#include "xlib.h" #define MAX_ARGS 14 static s48_value Argl, Argv; static struct event_desc { char *name; int argc; } Event_Table[] = { { "event-0", 1 }, { "event-1", 1 }, { "key-press", 12 }, { "key-release", 12 }, { "button-press", 12 }, { "button-release", 12 }, { "motion-notify", 12 }, { "enter-notify", 14 }, { "leave-notify", 14 }, { "focus-in", 4 }, { "focus-out", 4 }, { "keymap-notify", 3 }, { "expose", 7 }, { "graphics-expose", 9 }, { "no-expose", 4 }, { "visibility-notify", 3 }, { "create-notify", 9 }, { "destroy-notify", 3 }, { "unmap-notify", 4 }, { "map-notify", 4 }, { "map-request", 3 }, { "reparent-notify", 7 }, { "configure-notify", 10 }, { "configure-request", 11 }, { "gravity-notify", 5 }, { "resize-request", 4 }, { "circulate-notify", 4 }, { "circulate-request", 4 }, { "property-notify", 5 }, { "selection-clear", 4 }, { "selection-request", 7 }, { "selection-notify", 6 }, { "colormap-notify", 5 }, { "client-message", 4 }, { "mapping-notify", 4 }, { 0, 0 } }; struct predicate_arg { s48_value *funcs; s48_value *ret; }; /*ARGSUSED*/ static Event_Predicate (dpy, ep, ptr) Display *dpy; XEvent *ep; #ifdef XLIB_RELEASE_5_OR_LATER XPointer ptr; { #else char *ptr; { #endif struct predicate_arg *ap = (struct predicate_arg *)ptr; register i; s48_value args; S48_DECLARE_GC_PROTECT(1); if ((i = ep->type) < LASTEvent && !S48_NULL_P (ap->funcs[i])) { args = Get_Event_Args (ep); S48_GC_PROTECT_1 (args); *ap->ret = Funcall (ap->funcs[i], args, 0); Destroy_Event_Args (args); S48_GC_UNPROTECT; } return S48_TRUE_P (*ap->ret); } /* (handle-events display discard? peek? clause...) * clause = (event function) or ((event...) function) or (else function) * loops/blocks until a function returns x != #f, then returns x. * discard?: discard unprocessed events. * peek?: don't discard processed events. */ static s48_value P_Handle_Events (argl) s48_value argl; { s48_value next, clause, func, ret, funcs[LASTEvent], args; register i, discard, peek; Display *dpy; char *errmsg = "event occurs more than once"; S48_DECLARE_GC_PROTECT(3); struct gcnode gcv; TC_Prolog; TC_Disable; clause = args = S48_NULL; S48_GC_PROTECT_3 (argl, clause, args); next = Eval (S48_CAR (argl)); Check_Type (next, T_Display); dpy = DISPLAY(next)->dpy; argl = S48_CDR (argl); next = Eval (S48_CAR (argl)); Check_Type (next, T_Boolean); discard = S48_TRUE_P (next); argl = S48_CDR (argl); next = Eval (S48_CAR (argl)); Check_Type (next, T_Boolean); peek = S48_TRUE_P (next); for (i = 0; i < LASTEvent; i++) funcs[i] = S48_NULL; gcv.gclen = 1+LASTEvent; gcv.gcobj = funcs; gcv.next = &gc3; GC_List = &gcv; for (argl = S48_CDR (argl); !S48_NULL_P (argl); argl = S48_CDR (argl)) { clause = S48_CAR (argl); Check_List (clause); if (Fast_Length (clause) != 2) Primitive_Error ("badly formed event clause"); func = Eval (S48_CAR (S48_CDR (clause))); Check_Procedure (func); clause = S48_CAR (clause); if (S48_EQ_P(clause, Sym_Else)) { for (i = 0; i < LASTEvent; i++) if (S48_NULL_P (funcs[i])) funcs[i] = func; } else { if (S48_PAIR_P(clause)) { for (; !S48_NULL_P (clause); clause = S48_CDR (clause)) { i = Encode_Event (S48_CAR (clause)); if (!S48_NULL_P (funcs[i])) Primitive_Error (errmsg); funcs[i] = func; } } else { i = Encode_Event (clause); if (!S48_NULL_P (funcs[i])) Primitive_Error (errmsg); funcs[i] = func; } } } ret = S48_FALSE; while (!S48_TRUE_P (ret)) { XEvent e; if (discard) { (peek ? XPeekEvent : XNextEvent) (dpy, &e); if ((i = e.type) < LASTEvent && !S48_NULL_P (funcs[i])) { args = Get_Event_Args (&e); ret = Funcall (funcs[i], args, 0); Destroy_Event_Args (args); } else { if (peek) XNextEvent (dpy, &e); /* discard it */ } } else { struct predicate_arg a; a.funcs = funcs; a.ret = &ret; (peek ? XPeekIfEvent : XIfEvent) (dpy, &e, Event_Predicate, #ifdef XLIB_RELEASE_5_OR_LATER (XPointer)&a); #else (char *)&a); #endif } } S48_GC_UNPROTECT; TC_Enable; return ret; } static s48_value Get_Time_Arg (t) Time t; { return t == CurrentTime ? Sym_Now : s48_enter_integer ((unsigned long)t); } s48_value Get_Event_Args (ep) XEvent *ep; { s48_value tmpargs[MAX_ARGS]; register e, i; register s48_value *a, *vp; struct gcnode gcv; s48_value dummy; S48_DECLARE_GC_PROTECT(1); e = ep->type; dummy = S48_NULL; a = tmpargs; for (i = 0; i < MAX_ARGS; i++) a[i] = S48_NULL; S48_GC_PROTECT_1 (dummy); gcv.gclen = 1 + MAX_ARGS; gcv.gcobj = a; gcv.next = &gc1; GC_List = &gcv; switch (e) { case KeyPress: case KeyRelease: case ButtonPress: case ButtonRelease: case MotionNotify: case EnterNotify: case LeaveNotify: { register XKeyEvent *p = (XKeyEvent *)ep; a[1] = Make_Window (0, p->display, p->window); a[2] = Make_Window (0, p->display, p->root); a[3] = Make_Window (0, p->display, p->subwindow); a[4] = Get_Time_Arg (p->time); a[5] = s48_enter_integer (p->x); a[6] = s48_enter_integer (p->y); a[7] = s48_enter_integer (p->x_root); a[8] = s48_enter_integer (p->y_root); if (e == KeyPress || e == KeyRelease) { a[9] = Bits_To_Symbols ((unsigned long)p->state, 1, State_Syms); a[10] = s48_enter_integer (p->keycode); a[11] = p->same_screen ? S48_TRUE : S48_FALSE; } else if (e == ButtonPress || e == ButtonRelease) { register XButtonEvent *q = (XButtonEvent *)ep; a[9] = Bits_To_Symbols ((unsigned long)q->state, 1, State_Syms); a[10] = Bits_To_Symbols ((unsigned long)q->button, 0, Button_Syms); a[11] = q->same_screen ? S48_TRUE : S48_FALSE; } else if (e == MotionNotify) { register XMotionEvent *q = (XMotionEvent *)ep; a[9] = Bits_To_Symbols ((unsigned long)q->state, 1, State_Syms); a[10] = q->is_hint ? S48_TRUE : S48_FALSE; a[11] = q->same_screen ? S48_TRUE : S48_FALSE; } else { register XCrossingEvent *q = (XCrossingEvent *)ep; a[9] = Bits_To_Symbols ((unsigned long)q->mode, 0, Cross_Mode_Syms); a[10] = Bits_To_Symbols ((unsigned long)q->detail, 0, Cross_Detail_Syms); a[11] = q->same_screen ? S48_TRUE : S48_FALSE; a[12] = q->focus ? S48_TRUE : S48_FALSE; a[13] = Bits_To_Symbols ((unsigned long)q->state, 1, Button_Syms); } } break; case FocusIn: case FocusOut: { register XFocusChangeEvent *p = (XFocusChangeEvent *)ep; a[1] = Make_Window (0, p->display, p->window); a[2] = Bits_To_Symbols ((unsigned long)p->mode, 0, Cross_Mode_Syms); a[3] = Bits_To_Symbols ((unsigned long)p->detail, 0, Focus_Detail_Syms); } break; case KeymapNotify: { register XKeymapEvent *p = (XKeymapEvent *)ep; a[1] = Make_Window (0, p->display, p->window); a[2] = Make_String (p->key_vector, 32); } break; case Expose: { register XExposeEvent *p = (XExposeEvent *)ep; a[1] = Make_Window (0, p->display, p->window); a[2] = s48_enter_integer (p->x); a[3] = s48_enter_integer (p->y); a[4] = s48_enter_integer (p->width); a[5] = s48_enter_integer (p->height); a[6] = s48_enter_integer (p->count); } break; case GraphicsExpose: { register XGraphicsExposeEvent *p = (XGraphicsExposeEvent *)ep; a[1] = Make_Window (0, p->display, p->drawable); a[2] = s48_enter_integer (p->x); a[3] = s48_enter_integer (p->y); a[4] = s48_enter_integer (p->width); a[5] = s48_enter_integer (p->height); a[6] = s48_enter_integer (p->count); a[7] = s48_enter_integer (p->major_code); a[8] = s48_enter_integer (p->minor_code); } break; case NoExpose: { register XNoExposeEvent *p = (XNoExposeEvent *)ep; a[1] = Make_Window (0, p->display, p->drawable); a[2] = s48_enter_integer (p->major_code); a[3] = s48_enter_integer (p->minor_code); } break; case VisibilityNotify: { register XVisibilityEvent *p = (XVisibilityEvent *)ep; a[1] = Make_Window (0, p->display, p->window); a[2] = Bits_To_Symbols ((unsigned long)p->state, 0, Visibility_Syms); } break; case CreateNotify: { register XCreateWindowEvent *p = (XCreateWindowEvent *)ep; a[1] = Make_Window (0, p->display, p->parent); a[2] = Make_Window (0, p->display, p->window); a[3] = s48_enter_integer (p->x); a[4] = s48_enter_integer (p->y); a[5] = s48_enter_integer (p->width); a[6] = s48_enter_integer (p->height); a[7] = s48_enter_integer (p->border_width); a[8] = p->override_redirect ? S48_TRUE : S48_FALSE; } break; case DestroyNotify: { register XDestroyWindowEvent *p = (XDestroyWindowEvent *)ep; a[1] = Make_Window (0, p->display, p->event); a[2] = Make_Window (0, p->display, p->window); } break; case UnmapNotify: { register XUnmapEvent *p = (XUnmapEvent *)ep; a[1] = Make_Window (0, p->display, p->event); a[2] = Make_Window (0, p->display, p->window); a[3] = p->from_configure ? S48_TRUE : S48_FALSE; } break; case MapNotify: { register XMapEvent *p = (XMapEvent *)ep; a[1] = Make_Window (0, p->display, p->event); a[2] = Make_Window (0, p->display, p->window); a[3] = p->override_redirect ? S48_TRUE : S48_FALSE; } break; case MapRequest: { register XMapRequestEvent *p = (XMapRequestEvent *)ep; a[1] = Make_Window (0, p->display, p->parent); a[2] = Make_Window (0, p->display, p->window); } break; case ReparentNotify: { register XReparentEvent *p = (XReparentEvent *)ep; a[1] = Make_Window (0, p->display, p->event); a[2] = Make_Window (0, p->display, p->window); a[3] = Make_Window (0, p->display, p->parent); a[4] = s48_enter_integer (p->x); a[5] = s48_enter_integer (p->y); a[6] = p->override_redirect ? S48_TRUE : S48_FALSE; } break; case ConfigureNotify: { register XConfigureEvent *p = (XConfigureEvent *)ep; a[1] = Make_Window (0, p->display, p->event); a[2] = Make_Window (0, p->display, p->window); a[3] = s48_enter_integer (p->x); a[4] = s48_enter_integer (p->y); a[5] = s48_enter_integer (p->width); a[6] = s48_enter_integer (p->height); a[7] = s48_enter_integer (p->border_width); a[8] = Make_Window (0, p->display, p->above); a[9] = p->override_redirect ? S48_TRUE : S48_FALSE; } break; case ConfigureRequest: { register XConfigureRequestEvent *p = (XConfigureRequestEvent *)ep; a[1] = Make_Window (0, p->display, p->parent); a[2] = Make_Window (0, p->display, p->window); a[3] = s48_enter_integer (p->x); a[4] = s48_enter_integer (p->y); a[5] = s48_enter_integer (p->width); a[6] = s48_enter_integer (p->height); a[7] = s48_enter_integer (p->border_width); a[8] = Make_Window (0, p->display, p->above); a[9] = Bits_To_Symbols ((unsigned long)p->detail, 0, Stack_Mode_Syms); a[10] = s48_enter_integer (p->value_mask); } break; case GravityNotify: { register XGravityEvent *p = (XGravityEvent *)ep; a[1] = Make_Window (0, p->display, p->event); a[2] = Make_Window (0, p->display, p->window); a[3] = s48_enter_integer (p->x); a[4] = s48_enter_integer (p->y); } break; case ResizeRequest: { register XResizeRequestEvent *p = (XResizeRequestEvent *)ep; a[1] = Make_Window (0, p->display, p->window); a[2] = s48_enter_integer (p->width); a[3] = s48_enter_integer (p->height); } break; case CirculateNotify: { register XCirculateEvent *p = (XCirculateEvent *)ep; a[1] = Make_Window (0, p->display, p->event); a[2] = Make_Window (0, p->display, p->window); a[3] = Bits_To_Symbols ((unsigned long)p->place, 0, Place_Syms); } break; case CirculateRequest: { register XCirculateRequestEvent *p = (XCirculateRequestEvent *)ep; a[1] = Make_Window (0, p->display, p->parent); a[2] = Make_Window (0, p->display, p->window); a[3] = Bits_To_Symbols ((unsigned long)p->place, 0, Place_Syms); } break; case PropertyNotify: { register XPropertyEvent *p = (XPropertyEvent *)ep; a[1] = Make_Window (0, p->display, p->window); a[2] = Make_Atom (p->atom); a[3] = Get_Time_Arg (p->time); a[4] = Bits_To_Symbols ((unsigned long)p->state, 0, Prop_Syms); } break; case SelectionClear: { register XSelectionClearEvent *p = (XSelectionClearEvent *)ep; a[1] = Make_Window (0, p->display, p->window); a[2] = Make_Atom (p->selection); a[3] = Get_Time_Arg (p->time); } break; case SelectionRequest: { register XSelectionRequestEvent *p = (XSelectionRequestEvent *)ep; a[1] = Make_Window (0, p->display, p->owner); a[2] = Make_Window (0, p->display, p->requestor); a[3] = Make_Atom (p->selection); a[4] = Make_Atom (p->target); a[5] = Make_Atom (p->property); a[6] = Get_Time_Arg (p->time); } break; case SelectionNotify: { register XSelectionEvent *p = (XSelectionEvent *)ep; a[1] = Make_Window (0, p->display, p->requestor); a[2] = Make_Atom (p->selection); a[3] = Make_Atom (p->target); a[4] = Make_Atom (p->property); a[5] = Get_Time_Arg (p->time); } break; case ColormapNotify: { register XColormapEvent *p = (XColormapEvent *)ep; a[1] = Make_Window (0, p->display, p->window); a[2] = Make_Colormap (0, p->display, p->colormap); a[3] = p->new ? S48_TRUE : S48_FALSE; a[4] = p->state == ColormapInstalled ? S48_TRUE : S48_FALSE; } break; case ClientMessage: { register XClientMessageEvent *p = (XClientMessageEvent *)ep; register i; a[1] = Make_Window (0, p->display, p->window); a[2] = Make_Atom (p->message_type); switch (p->format) { case 8: a[3] = Make_String (p->data.b, 20); break; case 16: a[3] = s48_make_vector (10, S48_NULL); for (i = 0; i < 10; i++) S48_VECTOR_SET(a[3], i, s48_enter_integer (p->data.s[i]);) break; case 32: a[3] = s48_make_vector (5, S48_NULL); for (i = 0; i < 5; i++) S48_VECTOR_SET(a[3], i, s48_enter_integer (p->data.l[i]);) break; default: a[3] = s48_enter_integer (p->format); /* ??? */ } } break; case MappingNotify: { register XMappingEvent *p = (XMappingEvent *)ep; a[1] = Make_Window (0, p->display, p->window); a[2] = Bits_To_Symbols ((unsigned long)p->request, 0, Mapping_Syms); a[3] = s48_enter_integer (p->first_keycode); a[4] = s48_enter_integer (p->count); } break; } a[0] = Intern (Event_Table[e].name); for (vp = VECTOR(Argv)->data, i = 0; i < Event_Table[e].argc; i++) { if (i) vp++; S48_CAR (*vp) = a[i]; S48_CDR (*vp) = vp[1]; } S48_CDR (*vp) = S48_NULL; S48_GC_UNPROTECT; return Argl; } void Destroy_Event_Args (args) s48_value args; { s48_value t; for (t = args; !S48_NULL_P (t); t = S48_CDR (t)) S48_CAR (t) = S48_NULL; } Encode_Event (e) s48_value e; { s48_value s; register char *p; register struct event_desc *ep; register n; Check_Type (e, T_Symbol); s = s48_extract_string(S48_SYMBOL_TO_STRING(e)); p = STRING(s)->data; n = STRING(s)->size; for (ep = Event_Table; ep->name; ep++) if (n && strncmp (ep->name, p, n) == 0) break; if (ep->name == 0) Primitive_Error ("no such event: ~s", e); return ep-Event_Table; } static s48_value P_Get_Motion_Events (w, from, to) s48_value w, from, to; { XTimeCoord *p; int n; register i; s48_value e, ret; S48_DECLARE_GC_PROTECT(2); Check_Type (w, T_Window); p = XGetMotionEvents (WINDOW(w)->dpy, WINDOW(w)->win, Get_Time (from), Get_Time (to), &n); e = ret = s48_make_vector (n, S48_NULL); S48_GC_PROTECT_2 (ret, e); for (i = 0; i < n; i++) { e = P_Make_List (s48_enter_integer (3), S48_NULL); S48_VECTOR_SET(ret, i, e;) S48_CAR (e) = Get_Time_Arg (p[i].time); e = S48_CDR (e); S48_CAR (e) = s48_enter_integer (p[i].x); e = S48_CDR (e); S48_CAR (e) = s48_enter_integer (p[i].y); } S48_GC_UNPROTECT; XFree ((char *)p); return ret; } static s48_value P_Event_Listen (d, wait_flag) s48_value d, wait_flag; { Display *dpy; register n; XEvent e; Check_Type (d, T_Display); Check_Type (wait_flag, T_Boolean); dpy = DISPLAY(d)->dpy; n = XPending (dpy); if (n == 0 && S48_EQ_P(wait_flag, S48_TRUE)) { XPeekEvent (dpy, &e); n = XPending (dpy); } return s48_enter_integer (n); } elk_init_xlib_event () { s48_value t; register i; Argl = P_Make_List (s48_enter_integer (MAX_ARGS), S48_NULL); Global_S48_GC_PROTECT_1 (Argl); Argv = s48_make_vector (MAX_ARGS, S48_NULL); Global_S48_GC_PROTECT_1 (Argv); for (i = 0, t = Argl; i < MAX_ARGS; i++, t = S48_CDR (t)) S48_VECTOR_SET(Argv, i, t;) Define_Primitive (P_Handle_Events, "handle-events", 3, MANY, NOEVAL); Define_Primitive (P_Get_Motion_Events, "get-motion-events", 3, 3, EVAL); Define_Primitive (P_Event_Listen, "event-listen", 2, 2, EVAL); }