4
* This event handling stuff was inspired on Tk.
10
/* table to map event types to event masks */
11
static unsigned long eventMasks[] = {
14
KeyPressMask, /* KeyPress */
15
KeyReleaseMask, /* KeyRelease */
16
ButtonPressMask, /* ButtonPress */
17
ButtonReleaseMask, /* ButtonRelease */
18
PointerMotionMask|PointerMotionHintMask|ButtonMotionMask
19
|Button1MotionMask|Button2MotionMask|Button3MotionMask
20
|Button4MotionMask|Button5MotionMask,
22
EnterWindowMask, /* EnterNotify */
23
LeaveWindowMask, /* LeaveNotify */
24
FocusChangeMask, /* FocusIn */
25
FocusChangeMask, /* FocusOut */
26
KeymapStateMask, /* KeymapNotify */
27
ExposureMask, /* Expose */
28
ExposureMask, /* GraphicsExpose */
29
ExposureMask, /* NoExpose */
30
VisibilityChangeMask, /* VisibilityNotify */
31
SubstructureNotifyMask, /* CreateNotify */
32
StructureNotifyMask, /* DestroyNotify */
33
StructureNotifyMask, /* UnmapNotify */
34
StructureNotifyMask, /* MapNotify */
35
SubstructureRedirectMask, /* MapRequest */
36
StructureNotifyMask, /* ReparentNotify */
37
StructureNotifyMask, /* ConfigureNotify */
38
SubstructureRedirectMask, /* ConfigureRequest */
39
StructureNotifyMask, /* GravityNotify */
40
ResizeRedirectMask, /* ResizeRequest */
41
StructureNotifyMask, /* CirculateNotify */
42
SubstructureRedirectMask, /* CirculateRequest */
43
PropertyChangeMask, /* PropertyNotify */
44
0, /* SelectionClear */
45
0, /* SelectionRequest */
46
0, /* SelectionNotify */
47
ColormapChangeMask, /* ColormapNotify */
48
ClientMessageMask, /* ClientMessage */
49
0, /* Mapping Notify */
54
/* hook for other toolkits or wmaker process their events */
55
static WMEventHook *extraEventHandler=NULL;
62
* WMCreateEventHandler--
63
* Create an event handler and put it in the event handler list for the
64
* view. If the same callback and clientdata are already used in another
65
* handler, the masks are OR'ed.
69
WMCreateEventHandler(WMView *view, unsigned long mask, WMEventProc *eventProc,
75
WM_ITERATE_ARRAY(view->eventHandlers, hPtr, iter) {
76
if (hPtr->clientData==clientData && hPtr->proc==eventProc) {
77
hPtr->eventMask |= mask;
82
hPtr = wmalloc(sizeof(W_EventHandler));
84
/* select events for window */
85
hPtr->eventMask = mask;
86
hPtr->proc = eventProc;
87
hPtr->clientData = clientData;
89
WMAddToArray(view->eventHandlers, hPtr);
94
matchHandler(void *item, void *cdata)
96
#define H1 ((W_EventHandler*)item)
97
#define H2 ((W_EventHandler*)cdata)
99
return (H1->eventMask==H2->eventMask && H1->proc==H2->proc &&
100
H1->clientData==H2->clientData);
105
* WMDeleteEventHandler--
106
* Delete event handler matching arguments from windows
107
* event handler list.
111
WMDeleteEventHandler(WMView *view, unsigned long mask, WMEventProc *eventProc,
116
tmp.eventMask = mask;
117
tmp.proc = eventProc;
118
tmp.clientData = clientData;
119
WMRemoveFromArrayMatching(view->eventHandlers, matchHandler, (void*)&tmp);
124
getEventTime(WMScreen *screen, XEvent *event)
126
switch (event->type) {
129
return event->xbutton.time;
132
return event->xkey.time;
134
return event->xmotion.time;
137
return event->xcrossing.time;
139
return event->xproperty.time;
141
return event->xselectionclear.time;
142
case SelectionRequest:
143
return event->xselectionrequest.time;
144
case SelectionNotify:
145
return event->xselection.time;
147
return screen->lastEventTime;
153
W_CallDestroyHandlers(W_View *view)
156
WMArrayIterator iter;
157
W_EventHandler *hPtr;
160
event.type = DestroyNotify;
161
event.xdestroywindow.window = view->window;
162
event.xdestroywindow.event = view->window;
164
WM_ITERATE_ARRAY(view->eventHandlers, hPtr, iter) {
165
if (hPtr->eventMask & StructureNotifyMask) {
166
(*hPtr->proc)(&event, hPtr->clientData);
174
WMSetViewNextResponder(WMView *view, WMView *responder)
176
/* set the widget to receive keyboard events that aren't handled
179
view->nextResponder = responder;
184
WMRelayToNextResponder(WMView *view, XEvent *event)
186
unsigned long mask = eventMasks[event->xany.type];
188
if (view->nextResponder) {
189
WMView *next = view->nextResponder;
190
W_EventHandler *hPtr;
191
WMArrayIterator iter;
193
WM_ITERATE_ARRAY(next->eventHandlers, hPtr, iter) {
194
if ((hPtr->eventMask & mask)) {
195
(*hPtr->proc)(event, hPtr->clientData);
203
WMHandleEvent(XEvent *event)
205
W_EventHandler *hPtr;
206
W_View *view, *toplevel;
209
WMArrayIterator iter;
211
if (event->type == MappingNotify) {
212
XRefreshKeyboardMapping(&event->xmapping);
216
mask = eventMasks[event->xany.type];
218
window = event->xany.window;
220
/* diferentiate SubstructureNotify with StructureNotify */
221
if (mask == StructureNotifyMask) {
222
if (event->xmap.event != event->xmap.window) {
223
mask = SubstructureNotifyMask;
224
window = event->xmap.event;
227
view = W_GetViewForXWindow(event->xany.display, window);
230
if (extraEventHandler)
231
(extraEventHandler)(event);
236
view->screen->lastEventTime = getEventTime(view->screen, event);
238
toplevel = W_TopLevelOfView(view);
240
if (event->type == SelectionNotify || event->type == SelectionClear
241
|| event->type == SelectionRequest) {
242
/* handle selection related events */
243
W_HandleSelectionEvent(event);
247
/* if it's a key event, redispatch it to the focused control */
248
if (mask & (KeyPressMask|KeyReleaseMask)) {
249
W_View *focused = W_FocusedViewOfToplevel(toplevel);
256
/* compress Motion events */
257
if (event->type == MotionNotify && !view->flags.dontCompressMotion) {
258
while (XPending(event->xmotion.display)) {
260
XPeekEvent(event->xmotion.display, &ev);
261
if (ev.type == MotionNotify
262
&& event->xmotion.window == ev.xmotion.window
263
&& event->xmotion.subwindow == ev.xmotion.subwindow) {
265
XNextEvent(event->xmotion.display, event);
270
/* compress expose events */
271
if (event->type == Expose && !view->flags.dontCompressExpose) {
272
while (XCheckTypedWindowEvent(event->xexpose.display, view->window,
277
if (view->screen->modalLoop && toplevel!=view->screen->modalView
278
&& !toplevel->flags.worksWhenModal) {
279
if (event->type == KeyPress || event->type == KeyRelease
280
|| event->type == MotionNotify || event->type == ButtonPress
281
|| event->type == ButtonRelease
282
|| event->type == FocusIn || event->type == FocusOut) {
287
/* do balloon stuffs */
288
if (event->type == EnterNotify)
289
W_BalloonHandleEnterView(view);
290
else if (event->type == LeaveNotify)
291
W_BalloonHandleLeaveView(view);
293
/* This is a hack. It will make the panel be secure while
294
* the event handlers are handled, as some event handler
295
* might destroy the widget. */
296
W_RetainView(toplevel);
298
WM_ITERATE_ARRAY(view->eventHandlers, hPtr, iter) {
299
if ((hPtr->eventMask & mask)) {
300
(*hPtr->proc)(event, hPtr->clientData);
304
/* pass the event to the top level window of the widget */
305
/* TODO: change this to a responder chain */
306
if (view->parent != NULL) {
308
while (vPtr->parent != NULL)
311
WM_ITERATE_ARRAY(vPtr->eventHandlers, hPtr, iter) {
312
if (hPtr->eventMask & mask) {
313
(*hPtr->proc)(event, hPtr->clientData);
318
/* save button click info to track double-clicks */
319
if (view->screen->ignoreNextDoubleClick) {
320
view->screen->ignoreNextDoubleClick = 0;
322
if (event->type == ButtonPress) {
323
view->screen->lastClickWindow = event->xbutton.window;
324
view->screen->lastClickTime = event->xbutton.time;
328
if (event->type == ClientMessage) {
329
/* must be handled at the end, for such message can destroy the view */
330
W_HandleDNDClientMessage(toplevel, &event->xclient);
333
W_ReleaseView(toplevel);
340
WMIsDoubleClick(XEvent *event)
344
if (event->type != ButtonPress)
347
view = W_GetViewForXWindow(event->xany.display, event->xbutton.window);
352
if (view->screen->lastClickWindow != event->xbutton.window)
355
if (event->xbutton.time - view->screen->lastClickTime
356
< WINGsConfiguration.doubleClickDelay) {
357
view->screen->lastClickTime = 0;
358
view->screen->lastClickWindow = None;
359
view->screen->ignoreNextDoubleClick = 1;
367
* Check for X and input events. If X events are present input events will
370
* Return value: True if a X event is available or any input event was
371
* processed, false otherwise (including return because of
372
* some timer handler expired).
374
* If waitForInput is False, it will just peek for available input and return
375
* without processing. Return vaue will be True if input is available.
377
* If waitForInput is True, it will wait until an input event arrives on the
378
* registered input handlers and ConnectionNumber(dpy), or will return when
379
* a timer handler expires if no input event arrived until then.
382
waitForEvent(Display *dpy, unsigned long xeventmask, Bool waitForInput)
390
if (XCheckMaskEvent(dpy, xeventmask, &ev)) {
391
XPutBackEvent(dpy, &ev);
396
return W_HandleInputEvents(waitForInput, ConnectionNumber(dpy));
401
WMNextEvent(Display *dpy, XEvent *event)
403
/* Check any expired timers */
404
W_CheckTimerHandlers();
406
while (XPending(dpy) == 0) {
407
/* Do idle and timer stuff while there are no input or X events */
408
while (!waitForEvent(dpy, 0, False) && W_CheckIdleHandlers()) {
409
/* dispatch timer events */
410
W_CheckTimerHandlers();
414
* Make sure that new events did not arrive while we were doing
415
* timer/idle stuff. Or we might block forever waiting for
416
* an event that already arrived.
418
/* wait for something to happen or a timer to expire */
419
waitForEvent(dpy, 0, True);
421
/* Check any expired timers */
422
W_CheckTimerHandlers();
425
XNextEvent(dpy, event);
430
WMMaskEvent(Display *dpy, long mask, XEvent *event)
432
/* Check any expired timers */
433
W_CheckTimerHandlers();
435
while (!XCheckMaskEvent(dpy, mask, event)) {
436
/* Do idle and timer stuff while there are no input or X events */
437
while (!waitForEvent(dpy, mask, False) && W_CheckIdleHandlers()) {
438
W_CheckTimerHandlers();
441
if (XCheckMaskEvent(dpy, mask, event))
444
/* Wait for input on the X connection socket or another input handler */
445
waitForEvent(dpy, mask, True);
447
/* Check any expired timers */
448
W_CheckTimerHandlers();
454
WMScreenPending(WMScreen *scr)
456
if (XPending(scr->display))
464
WMHookEventHandler(WMEventHook *handler)
466
WMEventHook *oldHandler = extraEventHandler;
468
extraEventHandler = handler;