Generic_Window_Manager/wl_event.c

1512 lines
37 KiB
C

/* Copyright 1989 GROUPE BULL -- See license conditions in file COPYRIGHT
* Copyright 1989 Massachusetts Institute of Technology
*/
/***********************\
* *
* WOOL_OBJECT: Event *
* BODY *
* *
\***********************/
#include "EXTERN.h"
#include <stdio.h>
#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 <X11/Xatom.h>
#include <X11/Xutil.h>
#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 */