elk/lib/xt/callback.c

130 lines
3.8 KiB
C
Raw Normal View History

#include "xt.h"
typedef struct {
PFX2S converter;
int num;
} CLIENT_DATA;
Object Get_Callbackfun (c) XtPointer c; {
register CLIENT_DATA *cd = (CLIENT_DATA *)c;
return cd ? Get_Function (cd->num) : False;
}
static void Callback_Proc (w, client_data, call_data) Widget w;
XtPointer client_data, call_data; {
register CLIENT_DATA *cd = (CLIENT_DATA *)client_data;
Object args;
GC_Node;
args = Null;
GC_Link (args);
if (cd->converter)
args = Cons ((cd->converter)((XtArgVal)call_data), args);
args = Cons (Make_Widget_Foreign (w), args);
GC_Unlink;
(void)Funcall (Get_Callbackfun (client_data), args, 0);
}
/*ARGSUSED*/
void Destroy_Callback_Proc (w, client_data, call_data) Widget w;
XtPointer client_data, call_data; {
Object x;
x = Find_Object (T_Widget, (GENERIC)0, Match_Xt_Obj, w);
if (Nullp (x) || WIDGET(x)->free)
return;
WIDGET(x)->free = 1;
Remove_All_Callbacks (w);
Deregister_Object (x);
}
/* The code assumes that callbacks are called in the order they
* have been added. The Destroy_Callback_Proc() must always be
* the last callback in the destroy callback list of each widget.
*
* When the destroy callback list of a widget is modified
* (via P_Add_Callbacks or P_Set_Values), Fiddle_Destroy_Callback()
* must be called to remove the Destroy_Callback_Proc() and put
* it back to the end of the callback list.
*/
void Fiddle_Destroy_Callback (w) Widget w; {
XtRemoveCallback (w, XtNdestroyCallback, Destroy_Callback_Proc,
(XtPointer)0);
XtAddCallback (w, XtNdestroyCallback, Destroy_Callback_Proc, (XtPointer)0);
}
void Check_Callback_List (x) Object x; {
Object tail;
Check_List (x);
for (tail = x; !Nullp (tail); tail = Cdr (tail))
Check_Procedure (Car (tail));
}
static Object P_Add_Callbacks (w, name, cbl) Object w, name, cbl; {
register char *s;
register n;
XtCallbackList callbacks;
Alloca_Begin;
Check_Widget (w);
Check_Callback_List (cbl);
s = Get_Strsym (name);
Make_Resource_Name (s);
n = Fast_Length (cbl);
Alloca (callbacks, XtCallbackRec*, (n+1) * sizeof (XtCallbackRec));
callbacks[n].callback = 0;
callbacks[n].closure = 0;
Fill_Callbacks (cbl, callbacks, n,
Find_Callback_Converter (XtClass (WIDGET(w)->widget), s, name));
XtAddCallbacks (WIDGET(w)->widget, s, callbacks);
if (streq (s, XtNdestroyCallback))
Fiddle_Destroy_Callback (WIDGET(w)->widget);
Alloca_End;
return Void;
}
void Fill_Callbacks (src, dst, n, conv) Object src; XtCallbackList dst;
register n; PFX2S conv; {
register CLIENT_DATA *cd;
register i, j;
Object tail;
for (i = 0, tail = src; i < n; i++, tail = Cdr (tail)) {
j = Register_Function (Car (tail));
cd = (CLIENT_DATA *)XtMalloc (sizeof (CLIENT_DATA));
cd->converter = conv;
cd->num = j;
dst[i].callback = (XtCallbackProc)Callback_Proc;
dst[i].closure = (XtPointer)cd;
}
}
Remove_All_Callbacks (w) Widget w; {
Arg a[1];
XtCallbackList c;
XtResource *r;
int nr, nc;
register i, j;
Get_All_Resources (0, w, XtClass (w), &r, &nr, &nc);
for (j = 0; j < nr; j++) {
if (streq (r[j].resource_type, XtRCallback)) {
XtSetArg (a[0], r[j].resource_name, &c);
XtGetValues (w, a, 1);
for (i = 0; c[i].callback; i++) {
register CLIENT_DATA *cd = (CLIENT_DATA *)c[i].closure;
if (c[i].callback == (XtCallbackProc)Callback_Proc && cd) {
Deregister_Function (cd->num);
XtFree ((char *)cd);
}
}
}
}
XtFree ((char *)r);
}
elk_init_xt_callback () {
Define_Primitive (P_Add_Callbacks, "add-callbacks", 3, 3, EVAL);
}