/* Copyright 1989 GROUPE BULL -- See license conditions in file COPYRIGHT * Copyright 1989 Massachusetts Institute of Technology */ /***********************\ * * * WOOL_OBJECT: Event * * BODY * * * \***********************/ #include "EXTERN.h" #include #include "wool.h" #include "wl_atom.h" #include "wl_pointer.h" #include "wl_string.h" #include "wl_number.h" #include "wl_list.h" #include "wl_func.h" #include "gwm.h" #include #include #include "INTERN.h" #include "wl_event.h" #include "EXTERN.h" #include "wl_cursor.h" #include "wl_fsm.h" extern WOB_METHOD MenuClass[], PlugClass[]; /* table of events getting redirected to grabbing wob during a GWM grab */ Card32 EventProperties[] = { /* zero */ 0, /* one */ 0, /* KeyPress */ EPGrabRedirected|EPKeyOrButton|EPXY|EPXYRoot|EPTime, /* KeyRelease */ EPGrabRedirected|EPKeyOrButton|EPXY|EPXYRoot|EPTime, /* ButtonPress */ EPGrabRedirected|EPKeyOrButton|EPXY|EPXYRoot|EPTime, /* ButtonRelease */ EPGrabRedirected|EPKeyOrButton|EPXY|EPXYRoot|EPTime, /* MotionNotify */ EPGrabRedirected|EPKeyOrButton|EPXY|EPXYRoot|EPTime, /* EnterNotify */ EPRedirectable|EPCrossing|EPXY|EPXYRoot|EPTime, /* LeaveNotify */ EPRedirectable|EPCrossing|EPXY|EPXYRoot|EPTime, /* FocusIn */ EPRedirectable|EPFocus, /* FocusOut */ EPRedirectable|EPFocus, /* KeymapNotify */ 0, /* Expose */ 0, /* GraphicsExpose */ 0, /* NoExpose */ 0, /* VisibilityNotify */ 0, /* CreateNotify */ 0, /* DestroyNotify */ 0, /* UnmapNotify */ 0, /* MapNotify */ 0, /* MapRequest */ 0, /* ReparentNotify */ 0, /* ConfigureNotify */ 0, /* ConfigureRequest */ 0, /* GravityNotify */ 0, /* ResizeRequest */ 0, /* CirculateNotify */ 0, /* CirculateRequest */ 0, /* PropertyNotify */ EPTime, /* SelectionClear */ EPTime, /* SelectionRequest */ EPTime, /* SelectionNotify */ EPTime, /* ColormapNotify */ 0, /* ClientMessage */ 0, /* MappingNotify */ 0, /* LASTEvent */ 0, /* GWMUserEvent */ 0 }; /* offset of the Time field of events possessing it */ /* IF THIS GIVES COMPILES ERROR, USE THE FLAG -DNO_STRUCTURE_OFFSETS */ XEvent dummy_evt_ptr; #define XEventFieldOffset(evt_type, field) \ ((char *)(&(dummy_evt_ptr.evt_type.field))) - \ ((char *)(&(dummy_evt_ptr.type))) int EventTimeFieldOffset #ifndef NO_STRUCTURE_OFFSETS [] = { /* zero */ 0, /* one */ 0, /* KeyPress */ XEventFieldOffset(xkey, time), /* KeyRelease */ XEventFieldOffset(xkey, time), /* ButtonPress */ XEventFieldOffset(xbutton, time), /* ButtonRelease */ XEventFieldOffset(xbutton, time), /* MotionNotify */ XEventFieldOffset(xmotion, time), /* EnterNotify */ XEventFieldOffset(xcrossing, time), /* LeaveNotify */ XEventFieldOffset(xcrossing, time), /* FocusIn */ 0, /* FocusOut */ 0, /* KeymapNotify */ 0, /* Expose */ 0, /* GraphicsExpose */ 0, /* NoExpose */ 0, /* VisibilityNotify */ 0, /* CreateNotify */ 0, /* DestroyNotify */ 0, /* UnmapNotify */ 0, /* MapNotify */ 0, /* MapRequest */ 0, /* ReparentNotify */ 0, /* ConfigureNotify */ 0, /* ConfigureRequest */ 0, /* GravityNotify */ 0, /* ResizeRequest */ 0, /* CirculateNotify */ 0, /* CirculateRequest */ 0, /* PropertyNotify */ XEventFieldOffset(xproperty, time), /* SelectionClear */ XEventFieldOffset(xselectionclear, time), /* SelectionRequest */ XEventFieldOffset(xselectionrequest, time), /* SelectionNotify */ XEventFieldOffset(xselection, time), /* ColormapNotify */ 0, /* ClientMessage */ 0, /* MappingNotify */ 0, /* LASTEvent */ 0, /* GWMUserEvent */ 0 } #else [GWMUserEvent] #endif /* NO_STRUCTURE_OFFSETS */ ; /* to filter button releases events from the fact that they get the same button * pressed as a modifier... */ unsigned int ButtonMasks[] = { ~0, ~Button1Mask, ~Button2Mask, ~Button3Mask, ~Button4Mask, ~Button5Mask }; /* * to built a Event from C */ WOOL_Event wool_event_make(name, x_type, match, release, mask, state, detail) char * name; int x_type; int (*match)(); int (*release)(); unsigned int mask, state, detail; { WOOL_Event object = (WOOL_Event) WLEvent_make(state, detail); object -> x_type = x_type; object -> match = match; object -> release = release; object -> mask = mask; return (WOOL_Event) WLAtom_set(wool_atom(name), object); } WOOL_Event WLEvent_make(state, detail) unsigned int state, detail; { WOOL_Event object = (WOOL_Event) Malloc( sizeof(struct _WOOL_Event)); zrt_put(object); object -> type = WLEvent; object -> state = state; object -> detail = detail; object -> user_mask = 0; object -> flags = 0; return object; } WOOL_OBJECT WLEvent_print(obj) WOOL_Event obj; { wool_printf("{EVENT %s", eventtype[obj->x_type]); wool_printf(" d=%d", obj->detail); wool_printf(" s=%d", obj->state); /*print_atom_pointing_to(obj); */ wool_puts("}"); return (WOOL_OBJECT) obj; } /* * List of matching procedures for each event */ int WLEvent_user(wl_event, evt) WOOL_Event wl_event; Event evt; { if ((wl_event -> detail == (int) evt -> xany.display) || (wl_event -> detail == (unsigned int) ANY)) return TRUE; else return FALSE; } int WLEvent_propertychange(wl_event, evt) WOOL_Event wl_event; Event evt; { if (evt -> xproperty.atom == (Atom) wl_event -> detail || (wl_event -> detail == (unsigned int) ANY)) { return TRUE; } else return FALSE; } int WLEvent_clientmessage(wl_event, evt) WOOL_Event wl_event; Event evt; { if (evt -> xclient.message_type == (Atom) wl_event -> detail || (wl_event -> detail == (unsigned int) ANY)) { return TRUE; } else return FALSE; } int WLEvent_property_icon_pixmap_change(wl_event, evt) WOOL_Event wl_event; Event evt; { if ((evt -> xproperty.atom == (Atom) XA_WM_HINTS) && (SetTarget(TargetWob), TargetWindow -> cached_props -> wm_hints.flags & IconPixmapHint) && (!(GWM_backup_of_old_property.wm_hints.flags & IconPixmapHint) || TargetWindow -> cached_props -> wm_hints.icon_pixmap != GWM_backup_of_old_property.wm_hints.icon_pixmap)) return TRUE; else return FALSE; } int WLEvent_configurenotify(wl_event, evt) WOOL_Event wl_event; Event evt; { return TRUE; } int WLEvent_buttonpress(wl_event, evt) WOOL_Event wl_event; Event evt; { if (((wl_event -> detail == (unsigned int) ANY) || (wl_event -> detail == evt -> xbutton.button)) && ((wl_event -> state == (unsigned int) ANY) || (wl_event -> state == evt -> xbutton.state))) return TRUE; else return FALSE; } int WLEvent_double_buttonpress(wl_event, evt) WOOL_Event wl_event; Event evt; { if (((wl_event -> detail == (unsigned int) ANY) || (wl_event -> detail == evt -> xbutton.button)) && ((wl_event -> state == (unsigned int) ANY) || (wl_event -> state == evt -> xbutton.state)) && evt -> xbutton.button == GWM_LastEvent.xbutton.button && evt -> xbutton.window == GWM_LastEvent.xbutton.window && evt -> xbutton.time < (GWM_LastEvent.xbutton.time + GWM_DoubleClickDelay)) return TRUE; else return FALSE; } int WLEvent_buttonrelease(wl_event, evt) WOOL_Event wl_event; Event evt; { unsigned int butmask = ButtonMasks[evt -> xbutton.button]; if (((wl_event -> detail == (unsigned int) ANY) || (wl_event -> detail == evt -> xbutton.button)) && ((wl_event -> state == (unsigned int) ANY) || ((wl_event -> state & butmask) == (evt -> xbutton.state & butmask) ))) return TRUE; else return FALSE; } int WLEvent_keypress(wl_event, evt) WOOL_Event wl_event; Event evt; { if (((wl_event -> detail == (unsigned int) ANY) || (wl_event -> detail == XKeycodeToKeysym(dpy, evt -> xkey.keycode, 0))) && ((wl_event -> state == (unsigned int) ANY) || (wl_event -> state == evt -> xkey.state))) { return TRUE; } else return FALSE; } int WLEvent_keyrelease(wl_event, evt) WOOL_Event wl_event; Event evt; { if (((wl_event -> detail == (unsigned int) ANY) || (wl_event -> detail == XKeycodeToKeysym(dpy, evt -> xkey.keycode, 0))) && ((wl_event -> state == (unsigned int) ANY) || (wl_event -> state == evt -> xkey.state))) { return TRUE; } else return FALSE; } /* * enter & leave in the subtree of the window */ int WLEvent_enterwindow(wl_event, evt) WOOL_Event wl_event; Event evt; { XEvent report; if (evt -> xcrossing.detail != NotifyInferior) { /* XSync(dpy, 0); */ if (!XCheckTypedWindowEvent(dpy, evt -> xcrossing.window, LeaveNotify, &report) || report.xcrossing.detail == NotifyInferior) return TRUE; else return FALSE; } else return FALSE; } int WLEvent_leavewindow(wl_event, evt) WOOL_Event wl_event; Event evt; { XEvent report; if (evt -> xcrossing.detail != NotifyInferior) { /* XSync(dpy, 0); */ if (!XCheckTypedWindowEvent(dpy, evt -> xcrossing.window, EnterNotify, &report) || report.xcrossing.detail == NotifyInferior) return TRUE; else return FALSE; } else return FALSE; } int WLEvent_enterwindow_nograb(wl_event, evt) WOOL_Event wl_event; Event evt; { XEvent report; if (evt -> xcrossing.detail != NotifyInferior) { /* XSync(dpy, 0); */ if ((!XCheckTypedWindowEvent(dpy, evt -> xcrossing.window, LeaveNotify, &report) || report.xcrossing.detail == NotifyInferior) && evt -> xcrossing.mode != NotifyGrab && evt -> xcrossing.mode != NotifyUngrab) return TRUE; else return FALSE; } else return FALSE; } int WLEvent_leavewindow_nograb(wl_event, evt) WOOL_Event wl_event; Event evt; { XEvent report; if (evt -> xcrossing.detail != NotifyInferior) { /* XSync(dpy, 0); */ if ((!XCheckTypedWindowEvent(dpy, evt -> xcrossing.window, EnterNotify, &report) || report.xcrossing.detail == NotifyInferior) && evt -> xcrossing.mode != NotifyGrab && evt -> xcrossing.mode != NotifyUngrab) return TRUE; else return FALSE; } else return FALSE; } /* Focus management */ int WLEvent_focusin(wl_event, evt) WOOL_Event wl_event; Event evt; { if (evt -> xfocus.detail == NotifyNonlinearVirtual || TargetWob -> type == PlugClass) { return TRUE; } else return FALSE; } int WLEvent_focusout(wl_event, evt) WOOL_Event wl_event; Event evt; { if (evt -> xfocus.detail == NotifyNonlinearVirtual || TargetWob -> type == PlugClass) { return TRUE; } else return FALSE; } /* visibility management */ int WLEvent_visibility_partially_obscured(wl_event, evt) WOOL_Event wl_event; Event evt; { return (evt -> xvisibility.state == VisibilityPartiallyObscured); } int WLEvent_visibility_fully_obscured(wl_event, evt) WOOL_Event wl_event; Event evt; { return (evt -> xvisibility.state == VisibilityFullyObscured); } int WLEvent_visibility_unobscured(wl_event, evt) WOOL_Event wl_event; Event evt; { return (evt -> xvisibility.state == VisibilityUnobscured); } /* * list of release procedures */ int WLEvent_button_release(wl_event, evt) WOOL_Event wl_event; Event evt; { wait_for_button_release(evt -> xbutton.button); return 0; } int WLEvent_key_release(wl_event, evt) WOOL_Event wl_event; Event evt; { wait_for_key_release(evt -> xkey.keycode); return 0; } /* mapping of window */ int WLEvent_map_notify(wl_event, evt) WOOL_Event wl_event; Event evt; { return TRUE; } /* * functions to make the different events */ WOOL_Event WLEvent_user_make(data) WOOL_Atom data; { WOOL_Event event; if (data -> type == WLNumber && (((WOOL_Number) data) -> number == ANY)) event = WLEvent_make(0, ANY); else event = WLEvent_make(0, (unsigned int)data); event -> x_type = GWMUserEvent; event -> match = WLEvent_user; event -> release = NULL; event -> mask = 0; event -> user_mask = 1; return event; } WOOL_Event WLEvent_propertychange_make(name) WOOL_String name; { WOOL_Event event = WLEvent_make(0, 0); WOOL_Pointer x_atom; Atom property_name; event -> x_type = PropertyNotify; event -> match = WLEvent_propertychange; event -> release = NULL; event -> mask = PropertyChangeMask; if (is_a_string(name)) { if (wool_self_pointer_make(name -> string, '\030', &x_atom)) { property_name = *(x_atom -> ptr); } else { property_name = XInternAtom(dpy, name -> string, False); *(x_atom -> ptr) = property_name; } } else { property_name = (Atom) ANY; } event -> detail = (unsigned int) property_name; return event; } WOOL_Event WLEvent_clientmessage_make(name) WOOL_String name; { WOOL_Event event = WLEvent_make(0, 0); WOOL_Pointer x_atom; Atom property_name; event -> x_type = ClientMessage; event -> match = WLEvent_clientmessage; event -> release = NULL; event -> mask = 0; must_be_string(name, 0); if (wool_self_pointer_make(name -> string, '\030', &x_atom)) { property_name = *(x_atom -> ptr); } else { property_name = XInternAtom(dpy, name -> string, False); *(x_atom -> ptr) = property_name; } event -> detail = (unsigned int) property_name; return event; } WOOL_Event WLEvent_button_make(button, modifier) WOOL_Number modifier; WOOL_Number button; { WOOL_Event event = WLEvent_make(modifier -> number, (button -> number == AnyButton ? ANY : button -> number)); event -> x_type = ButtonPress; event -> match = WLEvent_buttonpress; event -> release = WLEvent_button_release; event -> mask = ButtonPressMask | ButtonReleaseMask; return event; } WOOL_Event WLEvent_buttonpress_make(button, modifier) WOOL_Number modifier; WOOL_Number button; { WOOL_Event event = WLEvent_button_make(button, modifier); event -> release = NULL; return event; } WOOL_Event WLEvent_double_button_make(button, modifier) WOOL_Number modifier; WOOL_Number button; { WOOL_Event event = WLEvent_make(modifier -> number, (button -> number == AnyButton ? ANY : button -> number)); event -> x_type = ButtonPress; event -> match = WLEvent_double_buttonpress; event -> release = WLEvent_button_release; event -> mask = ButtonPressMask | ButtonReleaseMask; return event; } WOOL_Event WLEvent_double_buttonpress_make(button, modifier) WOOL_Number modifier; WOOL_Number button; { WOOL_Event event = WLEvent_double_button_make(button, modifier); event -> release = NULL; return event; } WOOL_Event WLEvent_buttonrelease_make(button, modifier) WOOL_Number modifier; WOOL_Number button; { WOOL_Event event = WLEvent_button_make(button, WLNumber_make(((unsigned long) modifier -> number) | (((unsigned long) Button1Mask) << (button -> number - Button1)))); event -> x_type = ButtonRelease; event -> match = WLEvent_buttonrelease; event -> release = NULL; return event; } WOOL_Event WLEvent_key_make(key, modifier) WOOL_Number modifier; WOOL_Number key; { WOOL_Event event; KeySym keysym; must_be_number(modifier, 1); if (key -> type == WLNumber) keysym = key -> number; else { if ((keysym = XStringToKeysym(((WOOL_String) key) -> string)) == NoSymbol) { wool_printf("unknown key name: \"%s\"\n", ((WOOL_String) key) -> string); keysym = (KeySym) UNDEFINED_KEYCODE; } } event = WLEvent_make(modifier -> number, keysym); event -> x_type = KeyPress; event -> match = WLEvent_keypress; event -> release = WLEvent_key_release; event -> mask = KeyPressMask | KeyReleaseMask; return event; } WOOL_Event WLEvent_keypress_make(key, modifier) WOOL_Number modifier; WOOL_Number key; { WOOL_Event event = WLEvent_key_make(key, modifier); event -> release = NULL; return event; } WOOL_Event WLEvent_keyrelease_make(key, modifier) WOOL_Number modifier; WOOL_Number key; { WOOL_Event event = WLEvent_key_make(key, modifier); event -> x_type = KeyRelease; event -> match = WLEvent_keyrelease; event -> release = NULL; return event; } /* * Initialize all the events */ void wool_all_events_make() { grab_queue_init(); wool_atom_with_numeric_value_make("any", ANY); wool_atom_with_numeric_value_make("alone", 0); wool_atom_with_numeric_value_make("with-button-1", Button1Mask); wool_atom_with_numeric_value_make("with-button-2", Button2Mask); wool_atom_with_numeric_value_make("with-button-3", Button3Mask); wool_atom_with_numeric_value_make("with-button-4", Button4Mask); wool_atom_with_numeric_value_make("with-button-5", Button5Mask); wool_atom_with_numeric_value_make("with-shift", ShiftMask); wool_atom_with_numeric_value_make("with-lock", LockMask); wool_atom_with_numeric_value_make("with-control", ControlMask); wool_atom_with_numeric_value_make("with-alt", Mod1Mask); wool_atom_with_numeric_value_make("with-modifier-1", Mod1Mask); wool_atom_with_numeric_value_make("with-modifier-2", Mod2Mask); wool_atom_with_numeric_value_make("with-modifier-3", Mod3Mask); wool_atom_with_numeric_value_make("with-modifier-4", Mod4Mask); wool_atom_with_numeric_value_make("with-modifier-5", Mod5Mask); wool_subr_make(WLSubr, WLEvent_buttonpress_make, "buttonpress", 2); wool_subr_make(WLSubr, WLEvent_keypress_make, "keypress", 2); wool_subr_make(WLSubr, WLEvent_button_make, "button", 2); wool_subr_make(WLSubr, WLEvent_key_make, "key", 2); wool_subr_make(WLSubr, WLEvent_buttonrelease_make, "buttonrelease", 2); wool_subr_make(WLSubr, WLEvent_keyrelease_make, "keyrelease", 2); wool_subr_make(WLSubr, WLEvent_user_make, "user-event", 1); wool_subr_make(WLSubr, WLEvent_propertychange_make, "property-change", 1); wool_subr_make(WLSubr, WLEvent_clientmessage_make, "client-message", 1); wool_subr_make(WLSubr, WLEvent_double_buttonpress_make, "double-buttonpress", 2); wool_subr_make(WLSubr, WLEvent_double_button_make, "double-button", 2); wool_event_make("name-change", PropertyNotify, WLEvent_propertychange, NULL, PropertyChangeMask, 0, XA_WM_NAME); wool_event_make("window-icon-pixmap-change", PropertyNotify, WLEvent_property_icon_pixmap_change, NULL, PropertyChangeMask, 0, XA_WM_HINTS); wool_event_make("geometry-change", ConfigureNotify, WLEvent_configurenotify, NULL, SubstructureNotifyMask, 0, 0); wool_event_make("enter-window", EnterNotify, WLEvent_enterwindow, NULL, EnterWindowMask, 0, 0); wool_event_make("leave-window", LeaveNotify, WLEvent_leavewindow, NULL, LeaveWindowMask, 0, 0); wool_event_make("enter-window-not-from-grab", EnterNotify, WLEvent_enterwindow_nograb, NULL, EnterWindowMask, 0, 0); wool_event_make("leave-window-not-from-grab", LeaveNotify, WLEvent_leavewindow_nograb, NULL, LeaveWindowMask, 0, 0); wool_event_make("focus-in", FocusIn, WLEvent_focusin, NULL, FocusChangeMask, 0, 0); wool_event_make("focus-out", FocusOut, WLEvent_focusout, NULL, FocusChangeMask, 0, 0); wool_event_make("map-notify", MapNotify, WLEvent_map_notify, NULL, StructureNotifyMask, 0, 0); wool_event_make("visibility-unobscured", VisibilityNotify, WLEvent_visibility_unobscured, NULL, VisibilityChangeMask, 0, 0); wool_event_make("visibility-partially-obscured", VisibilityNotify, WLEvent_visibility_partially_obscured, NULL, VisibilityChangeMask, 0, 0); wool_event_make("visibility-fully-obscured", VisibilityNotify, WLEvent_visibility_fully_obscured, NULL, VisibilityChangeMask, 0, 0); } /* * wait for release of button n */ int LookForButtonRelease(display, evt, arg) Display *display; XEvent *evt; char *arg; { int n = (int)arg; if ((evt -> type == ButtonRelease) && (evt -> xbutton.button == n)) return True; else return False; } wait_for_button_release(n) int n; { XEvent button_event; XIfEvent(dpy, &button_event, LookForButtonRelease, (char *)n); } /* * wait for release of key of code n */ int LookForKeyRelease(display, evt, arg) Display *display; XEvent *evt; char *arg; { if ((evt -> type == KeyRelease) && (evt -> xkey.keycode == (int)arg)) return True; else return False; } wait_for_key_release(n) int n; { XEvent button_event; XIfEvent(dpy, &button_event, LookForKeyRelease, (char *)n); } /* grab management */ WOOL_OBJECT set_grab(wob) Wob wob; { WOOL_Cursor cursor; int status; if (wob -> type == MenuClass) cursor = (WOOL_Cursor) wob -> cursor; else cursor = (WOOL_Cursor) WOOL_send(WOOL_eval, WA_cursor, (WA_cursor)); if ((status = XGrabPointer(dpy, wob -> hook, True, LegalPointerEventMask(((WOOL_Fsm) wob -> fsm) -> mask), GrabModeAsync, GrabModeAsync, (GWM_confine_grabs ? wob -> hook : None), (cursor == (WOOL_Cursor) NIL ? None : cursor -> cursor), CurrentTime)) != GrabSuccess) return (WOOL_OBJECT) WLNumber_make(status); if (GWM_grab_keyboard_also) if ((status = XGrabKeyboard(dpy, wob -> hook, True, GrabModeAsync, GrabModeAsync, CurrentTime)) != GrabSuccess) { XUngrabPointer(dpy, CurrentTime); return (WOOL_OBJECT) WLNumber_make(status); } else { GWM_KeyboardGrabbed = wob; } if (GWM_GrabServer) XGrabServer(dpy); GWM_ServerGrabbed = wob; return NIL; } WOOL_OBJECT remove_grab(wob) Wob wob; { if (!wob || wob == GWM_ServerGrabbed) { if (GWM_ServerGrabbed) XUngrabPointer(dpy, CurrentTime); if (GWM_KeyboardGrabbed) XUngrabKeyboard(dpy, CurrentTime); if (GWM_GrabServer) XUngrabServer(dpy); XSync(dpy, 0); GWM_ServerGrabbed = GWM_KeyboardGrabbed = NULL; FlushQueuedGrabEvents(); } return NIL; } WOOL_OBJECT wool_set_grab(argc, argv) int argc; WOOL_Number argv[]; { GWM_GrabChildEvents = 0; switch (argc) { case 0: return set_grab(TargetWob); case 2: GWM_GrabChildEvents = 1; } must_be_number(argv[0], 0); return set_grab(argv[0] -> number); } WOOL_OBJECT wool_remove_grab(argc, argv) int argc; WOOL_Number argv[]; { if (!argc) return remove_grab(0); must_be_number(argv[0], 0); return remove_grab(argv[0] -> number); } /* replay back event in a grab * if arg != NIL, replay key event */ WOOL_OBJECT wool_ungrab_and_replay_event(key) WOOL_OBJECT key; { if (key == NIL) XAllowEvents(dpy, ReplayPointer, CurrentTime); else XAllowEvents(dpy, ReplayKeyboard, CurrentTime); return NIL; } /* makes a button event replayable */ WOOL_OBJECT wool_makes_replayable(event) WOOL_Event event; { must_be_event(event, 0); event -> flags |= FREEZE_ON_GRABS; return (WOOL_OBJECT) event; } /* allows event processing after a freeze due to a replayable event */ WOOL_OBJECT wool_allow_events() { XAllowEvents(dpy, AsyncPointer, CurrentTime); XAllowEvents(dpy, AsyncKeyboard, CurrentTime); return NIL; } /* last events of some type */ WOOL_OBJECT wool_last_key_struck() { char s[81]; int l; if ((TriggeringEvent -> type == KeyPress || TriggeringEvent -> type == KeyRelease) && (l = XLookupString(&TriggeringEvent->xkey, s, 80, 0, 0))) { s[l] = '\0'; return (WOOL_OBJECT) WLString_make(s); } else return NIL; } WOOL_OBJECT wool_last_user_event() { if (TriggeringEvent -> type == GWMUserEvent) return (WOOL_OBJECT) TriggeringEvent -> xany.display; else return wool_error("last event%s was not an user event", ""); } Event last_key_or_button_event(evt) Event evt; { if (event_is_key_or_button(*TriggeringEvent)) return TriggeringEvent; else return &GWM_LastEvent; } /* * returns the coords of the click relative to the client as a list * (logical-x logical-y x y) for the current window's client */ #ifdef NOBASEDIMS #ifdef PBaseSize #undef PBaseSize #endif #define PBaseSize PMinSize #define base_width min_width #define base_height min_height #endif /* NOBASEDIMS */ WOOL_OBJECT wool_logical_coords() { int x=0 , y=0; Window child; WOOL_List wl_list = wool_list_make(6); Event evt = last_key_or_button_event(TriggeringEvent); XSizeHints *normal_hints = &(TargetWindow -> cached_props -> normal_hints); if (TargetWindow -> client) XTranslateCoordinates(dpy, evt -> xbutton.root, TargetWindow -> client, evt -> xbutton.x_root, evt -> xbutton.y_root, &x, &y, &child); increase_reference(wl_list -> list[0] = (WOOL_OBJECT) WLNumber_make( (x - (normal_hints -> flags & PBaseSize ? normal_hints -> base_width : 0)) / (normal_hints -> flags & PResizeInc ? normal_hints -> width_inc : 1))); increase_reference(wl_list -> list[1] = (WOOL_OBJECT) WLNumber_make( (y - (normal_hints -> flags & PBaseSize ? normal_hints -> base_height : 0)) / (normal_hints -> flags & PResizeInc ? normal_hints -> height_inc : 1))); increase_reference(wl_list -> list[2] = (WOOL_OBJECT) WLNumber_make(x)); increase_reference(wl_list -> list[3] = (WOOL_OBJECT) WLNumber_make(y)); XTranslateCoordinates(dpy, evt -> xbutton.root, TargetWindow -> hook, evt -> xbutton.x_root, evt -> xbutton.y_root, &x, &y, &child); increase_reference(wl_list -> list[4] = (WOOL_OBJECT) WLNumber_make(x)); increase_reference(wl_list -> list[5] = (WOOL_OBJECT) WLNumber_make(y)); return (WOOL_OBJECT) wl_list; } int EventMasks[]={0,0, KeyPressMask, KeyReleaseMask, ButtonPressMask, ButtonReleaseMask}; WOOL_OBJECT wool_resend_event(wob) WOOL_Number wob; { Window window; Event evt = last_key_or_button_event(TriggeringEvent); if (wob = (WOOL_Number) NIL) window = TargetWindow -> client; else window = ((Wob) wob) -> hook; if (window) { evt -> xany.window = window; XSendEvent(dpy, TargetWindow -> client, False, EventMasks[evt->type], evt); XFlush(dpy); } return (WOOL_OBJECT) NIL; } WOOL_OBJECT wool_send_keycode_to_client(keycode, mod) WOOL_Number keycode, mod; { XEvent event; fill_x_key_event(&event, keycode -> number, mod -> number); XSendEvent(dpy, TargetWindow -> client, False, KeyPressMask, &event); fill_x_key_event(&event, keycode -> number, mod -> number); event.type = KeyRelease; XSendEvent(dpy, TargetWindow -> client, False, KeyReleaseMask, &event); return (WOOL_OBJECT) keycode; } WOOL_OBJECT wool_send_key_to_client(key, mod) WOOL_Number key, mod; { XEvent event; char *p = 0; int keysym, keycode; int modifier; must_be_number(mod, 1); if (key -> type != WLNumber) { must_be_string(key, 0); p = ((WOOL_String) key) -> string; if (!(*p)) return NIL; } do { /* we MUST re-init event each time */ modifier = mod -> number; if (key -> type == WLNumber) keysym = key -> number; else { keysym = *p++; } if (!(keycode = XKeysymToKeycode(dpy, keysym))) return wool_error("unknown keysym for this server: 0x%x", keysym); /* add shift automatically for shifted chars */ /* We should do same thing for control chars & meta... */ if (keysym != XKeycodeToKeysym(dpy, keycode, 0)) { if (keysym == XKeycodeToKeysym(dpy, keycode, 1)) { modifier |= ShiftMask; } } fill_x_key_event(&event, keycode, modifier); XSendEvent(dpy, TargetWindow -> client, False, KeyPressMask, &event); fill_x_key_event(&event, keycode, modifier); event.type = KeyRelease; XSendEvent(dpy, TargetWindow -> client, False, KeyReleaseMask, &event); } while (p && *p); return (WOOL_OBJECT) key; } fill_x_key_event(evt, keycode, modifier) XKeyPressedEvent *evt; int keycode, modifier; { evt -> type = KeyPress; evt -> display = dpy; evt -> window = evt -> subwindow = TargetWindow -> client; evt -> root = Context->root; evt -> time = CurrentTime; evt -> x = evt -> y = evt -> x_root = evt -> y_root = 0; evt -> same_screen = 1; evt -> keycode = keycode; evt -> state = modifier; } /* same with button: button modifier x y */ fill_x_button_event(evt, button, modifier, x, y, x_root, y_root, child) XButtonEvent *evt; int button, modifier, x, y, x_root, y_root; Window child; { evt -> type = ButtonPress; evt -> display = dpy; evt -> window = child; evt -> subwindow = 0; evt -> root = Context->root; evt -> time = CurrentTime; evt -> x = x; evt -> y = y; evt -> x_root = x_root; evt -> y_root = y_root; evt -> same_screen = 1; evt -> button = button; evt -> state = modifier; } /* look which window would receive button event */ Window WindowGettingButtonEvent(w, x, y) Window w; int x,y; { int x2, y2; Window child, w2 = w; XWindowAttributes wa; find_window: XTranslateCoordinates(dpy, w, w2, x, y, &x2, &y2, &child); if (child) { x = x2; y = y2; w = w2; w2 = child; goto find_window; } x = x2; y = y2; w = w2; find_listener: XGetWindowAttributes(dpy, w, &wa); if (!(wa.all_event_masks & (ButtonPressMask | ButtonReleaseMask))) { Window d1, d2, *d3, parent; unsigned int d4; XQueryTree(dpy, w, &d1, &parent, &d3, &d4); XFreeN(d3); if (parent) { w = parent; goto find_listener; } } return w; } WOOL_OBJECT wool_send_button_to_client(argc, argv) int argc; WOOL_Number argv[]; { XEvent event; int button, modifier, x, y, x2, y2, x_root, y_root, i; Window child, dummy; if (argc != 4) return wool_error(BAD_NUMBER_OF_ARGS, argc); for (i = 0; i < argc; i++) must_be_number(argv[i], i); button = argv[0] -> number; modifier = argv[1] -> number; x = argv[2] -> number; y = argv[3] -> number; XTranslateCoordinates(dpy, TargetWindow -> client, Context -> root, x, y, &x_root, &y_root, &child); child = WindowGettingButtonEvent(TargetWindow -> client, x, y); x2 =x, y2 =y; XTranslateCoordinates(dpy, TargetWindow -> client, child, x2, y2, &x, &y, &dummy); fill_x_button_event(&event, button, modifier, x, y, x_root, y_root, child); XSendEvent(dpy, child, False, ButtonPressMask, &event); fill_x_button_event(&event, button, modifier, x, y, x_root, y_root, child); event.type = ButtonRelease; XSendEvent(dpy, child, False, ButtonReleaseMask, &event); return (WOOL_OBJECT) argv[0]; } /* management of the enter/leave on grabs for menus * these functions are used * - just before sending event in GWM_ProcessEvents (gwm.c) * if (IsNotGrabDiscarded(&evt)) { * send-event... * } * - in remove_grab (at the end) for FlushQueuedGrabEvents * * - in wool_all_events_make for grab_queue_init */ static XEvent *grab_queue; static int grab_queue_start; static int grab_queue_size; static int grab_queue_limit; grab_queue_init() { grab_queue_size = 0; grab_queue_limit = 1; grab_queue = (XEvent *) Malloc(grab_queue_limit * sizeof(XEvent)); } int IsNotGrabDiscarded(evt) Event evt; { if (((evt -> type == LeaveNotify) && (evt -> xcrossing.mode == NotifyGrab)) || ((evt -> type == FocusOut) && (evt -> xfocus.mode == NotifyGrab))) { if (grab_queue_size == grab_queue_limit) { grab_queue_limit *= 2; grab_queue = (XEvent *) Realloc(grab_queue, grab_queue_limit * sizeof(XEvent)); } bcopy(evt, &grab_queue[grab_queue_size++], sizeof(XEvent)); return FALSE; } else { if (((evt -> type == EnterNotify) && (evt -> xcrossing.mode == NotifyUngrab)) || ((evt -> type == FocusIn) && (evt -> xfocus.mode == NotifyUngrab))) { return TRUE; } else { return FALSE; } } } FlushQueuedGrabEvents() { Wob wob; SAVE_EVENT_CONTEXT; while (grab_queue_start < grab_queue_size) { if (wob = (Wob) LookUpWob(grab_queue[grab_queue_start].xany.window)) { WOOL_send(WOOL_process_event, wob, (wob, &grab_queue[grab_queue_start])); } grab_queue_start++; } RESTORE_EVENT_CONTEXT; grab_queue_size = 0; grab_queue_start = 0; } /* * recuperates parameters of the triggering event */ #define field_of_event(evt, event_property, etype, field) \ if(TriggeringEvent->type > 1 && TriggeringEvent->type < LASTEvent && \ EventProperties[TriggeringEvent->type] & event_property) \ return (WOOL_OBJECT) WLNumber_make(((etype *) evt) -> field); \ else return (WOOL_OBJECT) WLNumber_make(0); WOOL_OBJECT wool_get_triggering_event_data() { if (TriggeringEvent->type == ClientMessage) { switch (((XClientMessageEvent *) TriggeringEvent)->format) { case 8: return ((WOOL_OBJECT) WLString_make( ((XClientMessageEvent *) TriggeringEvent)->data.b)); case 16: { WOOL_Number ListArgv[10]; int i; for (i=0;i<10;i++) { ListArgv[i] = WLNumber_make( ((XClientMessageEvent *) TriggeringEvent)->data.s[i]); } return ((WOOL_OBJECT) wool_list_make_from_evaluated_array(10, (WOOL_OBJECT *) ListArgv)); } case 32: { WOOL_Number ListArgv[5]; int i; for (i=0;i<5;i++) { ListArgv[i] = WLNumber_make( ((XClientMessageEvent *) TriggeringEvent)->data.l[i]); } return ((WOOL_OBJECT) wool_list_make_from_evaluated_array(5, (WOOL_OBJECT *) ListArgv)); } } } return wool_error("internal error, event was not of good type%s", ""); } WOOL_OBJECT wool_get_triggering_event_state() { field_of_event(TriggeringEvent, EPKeyOrButton, XButtonEvent, state); } WOOL_OBJECT wool_get_triggering_event_code() { field_of_event(TriggeringEvent, EPKeyOrButton, XButtonEvent, button); } WOOL_OBJECT wool_get_triggering_event_x() { field_of_event(TriggeringEvent, EPXYRoot, XButtonEvent, x_root); } WOOL_OBJECT wool_get_triggering_event_y() { field_of_event(TriggeringEvent, EPXYRoot, XButtonEvent, y_root); } WOOL_OBJECT wool_get_triggering_event_x_relative() { field_of_event(TriggeringEvent, EPXY, XButtonEvent, x); } WOOL_OBJECT wool_get_triggering_event_y_relative() { field_of_event(TriggeringEvent, EPXY, XButtonEvent, y); } WOOL_OBJECT wool_get_triggering_event_time() { field_of_event(TriggeringEvent, EPXY, XButtonEvent, time); } /* used to know if current event was due to a grab */ WOOL_OBJECT wool_event_was_due_to_a_grab() { WOOL_Atom result = (WOOL_Atom) NIL; if (event_is_crossing(*TriggeringEvent)) { if (TriggeringEvent -> xcrossing.mode == NotifyGrab) result = WA_grab; else if (TriggeringEvent -> xcrossing.mode == NotifyUngrab) result = WA_ungrab; } else if (event_is_focus(*TriggeringEvent)) { if (TriggeringEvent -> xfocus.mode == NotifyGrab) result = WA_grab; else if (TriggeringEvent -> xfocus.mode == NotifyUngrab) result = WA_ungrab; } return (WOOL_OBJECT) result; } /********************\ * * * Tracing of events * * * \********************/ #ifdef DEBUG char *FocusDetailText[] = { "NotifyAncestor", /* 0 */ "NotifyVirtual", /* 1 */ "NotifyInferior", /* 2 */ "NotifyNonlinear", /* 3 */ "NotifyNonlinearVirtual", /* 4 */ "NotifyPointer", /* 5 */ "NotifyPointerRoot", /* 6 */ "NotifyDetailNone" /* 7 */ }; char *FocusModeText[] = { "NotifyNormal", /* 0 */ "NotifyGrab", /* 1 */ "NotifyUngrab", /* 2 */ "NotifyWhileGrabbed" /* 3 */ }; GWM_prettyprint_fsm_event(wob, evt, text, state, newstate) Wob wob; Event evt; char *text; int state, newstate; { fprintf(stderr, "%s %s (0x%lx/0x%lx): ", text, ((WOOL_Atom) wob -> type[0])-> p_name, wob, wob -> hook); if (state || newstate) { fprintf(stderr, " (s%d", state); if (state != newstate) { fprintf(stderr, "->%d", newstate); } fprintf(stderr, ")"); } GWM_prettyprint_event(" ", evt, "\n"); } GWM_prettyprint_event(tag, evt, end) char *tag; Event evt; char *end; { fputs(tag, stderr); fprintf(stderr, "%s ", eventtype[evt -> type]); switch (evt->type) { case GWMUserEvent: fprintf(stderr, "%s", ((WOOL_String) (evt->xany.display))->string); break; case FocusIn: case FocusOut: fprintf(stderr, "w 0x%x, detail %s, mode %s", evt->xfocus.window, FocusDetailText[evt->xfocus.detail], FocusModeText[evt->xfocus.mode]); break; case EnterNotify: case LeaveNotify: fprintf(stderr, "w 0x%x, detail %s, mode %s", evt->xcrossing.window, FocusDetailText[evt->xcrossing.detail], FocusModeText[evt->xcrossing.mode]); break; case PropertyNotify: fprintf(stderr, "w 0x%x, %s", evt->xproperty.window, XGetAtomName(dpy, evt->xproperty.atom)); break; case ReparentNotify: fprintf(stderr, "w 0x%x to 0x%x %s", evt->xreparent.window, evt->xreparent.parent, (evt->xreparent.override_redirect ? "(Override)":"")); break; case ConfigureNotify: fprintf(stderr, "event 0x%x window 0x%x x %d y %d w %d h %d bw %d above 0x%x\n", evt->xconfigure.event, evt->xconfigure.window, evt->xconfigure.x, evt->xconfigure.y, evt->xconfigure.width, evt->xconfigure.height, evt->xconfigure.border_width, evt->xconfigure.above); break; case ConfigureRequest: fprintf(stderr, "parent 0x%x window 0x%x x %d y %d w %d h %d bw %d above 0x%x detail %d mask %d\n", evt->xconfigurerequest.parent, evt->xconfigurerequest.window, evt->xconfigurerequest.x, evt->xconfigurerequest.y, evt->xconfigurerequest.width, evt->xconfigurerequest.height, evt->xconfigurerequest.border_width, evt->xconfigurerequest.above, evt->xconfigurerequest.detail, evt->xconfigurerequest.value_mask); break; default: fprintf(stderr, "w 0x%x", evt->xany.window); } fputs(end, stderr); } #endif /* DEBUG */