Wikia

Sawfish

Librep Internals

773pages on
this wiki
Talk0
Development quick access

This page describes how to write lisp codes in C within Librep. It's far from complete.

Functions and data types are registered on modules load. The dealing with registered data types is handled by call-backs. Librep uses a mark and sweep garbage collector. For each data type registered, appropriate mark and sweep functions are registered.

Most of macros in this page are defined in librep/src/rep_lisp.h and sawfish/src/sawfish.h.

Value types Edit

repv is the type which represents lisp value. Qt and Qnil are repv for lisp `t' and `nil'.

Comparison like v == Qnil is possible.

Return value rep_NULL is equal to Qnil.

Conversion from / to native Edit

integer 
rep_MAKE_INT(x) is native -> lisp, rep_INT(v) is lisp -> native.
string 
rep_string_dup(char * str) / rep_string_dupn(char * str, int length) copies the native to repv, rep_STR(v) makes the char * from repv.
window 
The C struct for windows is Lisp_Window. VWIN(v) from lisp to C, rep_VAL(w) for C struct to lisp.

Type check macros Edit

These macros check the lisp type of a repv object. They can be used within if like if(rep_INTP(v)), and also in rep_DECLARE* described below.

rep_INTP, rep_NUMERICP (any number type), rep_CONSP, rep_STRINGP, rep_LISTP, rep_VECTORP and so on.

WINDOWP is in sawfish, too.

Car and cdr Edit

If the value is a cons, then you can access the car and cdr with macros rep_CAR and rep_CDR. Changing car and cdr can be done with them, too, so

rep_CAR(v) = Qt;

works.

Registering new symbols Edit

DEFSYM Macro Edit

DEFSYM(add_window_hook, "add-window-hook");

This creates a C variable Qadd_window_hook with the lisp name "add-window-hook". This should go somewhat near the top of the file (and not in a function).

rep_INTERN Edit

rep_INTERN(x)

Registers the symbol with the lisp environment. Usually placed inside the init code. For dynamical scope symbol, use rep_INTERN_SPECIAL.

Registering new functions Edit

DEFUN Macro Edit

#define DEFUN(name,fsym,ssym,args,type) Let's see an example:

DEFUN("call-window-hook", Fcall_window_hook, Scall_window_hook,
      (repv hook, repv win, repv args, repv type), rep_Subr4) /*
::doc:sawfish.wm.windows.subrs#call-window-hook::
call-window-hook HOOK WINDOW &optional ARGS HOOK-TYPE

Call HOOK for WINDOW with extra arguments ARGS. See `call-hook' for a
description of HOOK-TYPE.
::end:: */
{
/* code goes here */
}
name 
The string name of the function, this is how it will appear inside the rep environment.
fsym 
The actual C function that gets created, it will have the signature of repv fsym args. It can be called by the C code directly.
ssym 
The SUBR. This is passed to rep_ADD_SUBR to register the function.
args 
The arguments to the function. (repv arg1) for one argument, (repv arg1,repv arg2) for 2, and so on up to 5 arguments. For N arguments (repv args).
type 
The symbols rep_Subr0 -> rep_Subr5 and rep_SubrN corresponding to how many args defined in "args"

Then comes the doc-string. The return value is a repv. For functions that do not return a value (only there for side-effects) return Qt.

Don't forget to include the function in the header file, librep/src/rep_subrs.h or sawfish/src/sawfish_subrs.h.

rep_DECLARE* Edit

In the above example, these two lines are there at the beginnig of the function body:

rep_DECLARE1(hook, rep_SYMBOLP);
rep_DECLARE2(win, XWINDOWP);

This forces the type for each argument. If the type is wrong, an error is signaled.

Value `nil' is not allowed. To include `nil', use rep_DECLARE1_OPT(x,t) instead, for argument 1 for example.

rep_ADD_SUBR Edit

The DEFUN macro only defines C function. To make it available in lisp, use this kind of expression:

repv tem;
tem = rep_push_structure ("sawfish.wm.windows.subrs");
rep_ADD_SUBR(Scall_window_hook);
rep_pop_structure (tem);

Accessing lisp values Edit

Lisp variables values Edit

In most cases, this suffices:

DEFSYM(global_keymap, "global_keymap");
...
repv v = Fsymbol_value(Qglobal_keymap, Qt); // never mind Qt
...
rep_INTERN(global_keymap);

Sometimes you have to specify the module which defines the symbol:

repv tem = rep_push_structure_name ("foo.bar.baz");
value = Fsymbol_value (sym, Qt);
rep_pop_structure (tem);

Calling lisp functions Edit

First, read the previous section on variable.

If the function is defined with DEFUN macro, then you can simply call it like this:

repv win2 = Fwindow_get (win, Qplaced, Qt);

It's possible to access functions defined in lisp: (define (foo-func a b) ....)

DEFSYM(foo_func, "foo_func");
...
repv a = Qt, b = Qnil;
repv v = rep_call_lisp2(Fsymbol_value(Qfoo_func, Qt),
                        a, b);
...
rep_INTERN(foo_func);

If the function takes only one argument, then use rep_call_lisp1 instead.

Registering new types Edit

u_int rep_register_new_type(char *name,
                                   int (*compare)(repv, repv),
                                   void (*princ)(repv, repv),
                                   void (*print)(repv, repv),
                                   void (*sweep)(void),
                                   void (*mark)(repv),
                                   void (*mark_type)(void),
                                   int (*getc)(repv),
                                   int (*ungetc)(repv, int),
                                   int (*putc)(repv, int),
                                   int (*puts)(repv, void *, int, rep_bool),
                                   repv (*bind)(repv),
                                   void (*unbind)(repv))

"Required" arguments are "name","princ","print","sweep", and "mark." All others can be passed 0 (aka NULL?) if no implementation is given. "compare" is common (need to find out when it is used). "sweep" isn't used for "datum".... and neither "sweep" or "mark" is used for "weak-ref"...

compare Edit

I have yet to find an example that doesn't compare one object to another by pointer:

static int
x_window_cmp (repv w1, repv w2)
{
    return w1 != w2;
}

princ Edit

how to print the object: not sure on difference between print and princ yet

static void
x_window_prin (repv stream, repv obj)
{
    char buf[256];
    sprintf (buf, "#<x-drawable 0x%lx>", VX_DRAWABLE (obj)->id);
    rep_stream_puts (stream, buf, -1, FALSE);
}

print Edit

Like princ but formats output to be acceptable for reading in.

For example:

(print "hi") prints out "hi"
(princ "hi") prints out hi (no quotes)

sweep Edit

static void some_name (void)

Walk the list of objects (you should keep track of all self managed object you create) freeing those that are not marked (rep_GC_CELL_MARKEDP(rep_VAL(w))). Cleanup the object (if it holds and open connection, close it. malloced data, free it etc) then free the cell with rep_FREE_CELL(w). If it is marked (i.e. it does need to be collected) clear the GC bit with rep_GC_CLR_CELL(rep_VAL(w)).

To make it easier to manage, use the pattern:

Lisp_Struct *w = object_list;
while (w != 0) {
   Lisp_Struct *next = w->next;
   if (!rep_GC_CELL_MARKEDP (rep_VAL (w))) {
   } else {
      rep_GC_CLR_CELL (rep_VAL (w));
      w->next = object_list;
      object_list = w;
   }
   w = next;
}

This is reversing the list of objects as it traverses it, omitting any objects that need to be Collected.

mark Edit

static void some_name (repv obj)

This should call rep_MARKVAL on any repvs that are stored inside the struct. This allows the mark phase to find any other objects that are found through your object.

mark_type Edit

static void mark_all (void)

Mark all the objects of this type? Not entirely sure when this is needed. unix_processes uses it to keep around any process that is still active (even if no reference is held, still want it to run....).

getc Edit

putc Edit

static int some_name (repv stream, int c)

The return value is the number of bytes actually written? int c is the char to send, cast/save to char?

puts Edit

static int some_name (repv stream, void *data, int len, rep_bool is_lisp)

The return value is the number of bytes actually written? is_lisp signals that data is a rep_STR?

bind Edit

unbind Edit

load/unload Edit

These functions are called on load and unload respectively.

rep_dl_init Edit

This is where all initial registration and setup is done. Symbols, functions, datatypes and documentation registered.

rep_dl_kill Edit

Any closing or registering that needs to be on dl unloading.

Around Wikia's network

Random Wiki