Change to the linux kernel coding style
[wmaker-crm.git] / WINGs / wevent.c
Commit [+]AuthorDateLineData
9d2e6ef9 scottc1998-09-29 22:36:29 +00001
9d2e6ef9 scottc1998-09-29 22:36:29 +00002/*
9a89e6cc kojima2000-07-15 22:08:25 +00003 * This event handling stuff was inspired on Tk.
9d2e6ef9 scottc1998-09-29 22:36:29 +00004 */
5
6#include "WINGsP.h"
7
9d2e6ef9 scottc1998-09-29 22:36:29 +00008/* table to map event types to event masks */
9static unsigned long eventMasks[] = {
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +020010 0,
11 0,
12 KeyPressMask, /* KeyPress */
13 KeyReleaseMask, /* KeyRelease */
14 ButtonPressMask, /* ButtonPress */
15 ButtonReleaseMask, /* ButtonRelease */
16 PointerMotionMask | PointerMotionHintMask | ButtonMotionMask
17 | Button1MotionMask | Button2MotionMask | Button3MotionMask | Button4MotionMask | Button5MotionMask,
18 /* MotionNotify */
19 EnterWindowMask, /* EnterNotify */
20 LeaveWindowMask, /* LeaveNotify */
21 FocusChangeMask, /* FocusIn */
22 FocusChangeMask, /* FocusOut */
23 KeymapStateMask, /* KeymapNotify */
24 ExposureMask, /* Expose */
25 ExposureMask, /* GraphicsExpose */
26 ExposureMask, /* NoExpose */
27 VisibilityChangeMask, /* VisibilityNotify */
28 SubstructureNotifyMask, /* CreateNotify */
29 StructureNotifyMask, /* DestroyNotify */
30 StructureNotifyMask, /* UnmapNotify */
31 StructureNotifyMask, /* MapNotify */
32 SubstructureRedirectMask, /* MapRequest */
33 StructureNotifyMask, /* ReparentNotify */
34 StructureNotifyMask, /* ConfigureNotify */
35 SubstructureRedirectMask, /* ConfigureRequest */
36 StructureNotifyMask, /* GravityNotify */
37 ResizeRedirectMask, /* ResizeRequest */
38 StructureNotifyMask, /* CirculateNotify */
39 SubstructureRedirectMask, /* CirculateRequest */
40 PropertyChangeMask, /* PropertyNotify */
41 0, /* SelectionClear */
42 0, /* SelectionRequest */
43 0, /* SelectionNotify */
44 ColormapChangeMask, /* ColormapNotify */
45 ClientMessageMask, /* ClientMessage */
46 0, /* Mapping Notify */
9d2e6ef9 scottc1998-09-29 22:36:29 +000047};
48
9d2e6ef9 scottc1998-09-29 22:36:29 +000049/* hook for other toolkits or wmaker process their events */
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +020050static WMEventHook *extraEventHandler = NULL;
9d2e6ef9 scottc1998-09-29 22:36:29 +000051
9d2e6ef9 scottc1998-09-29 22:36:29 +000052/*
53 * WMCreateEventHandler--
54 * Create an event handler and put it in the event handler list for the
55 * view. If the same callback and clientdata are already used in another
064f79eb dan2002-12-20 17:47:31 +000056 * handler, the masks are OR'ed.
e7d0c5d9 dan2004-04-07 02:50:52 +000057 *
9d2e6ef9 scottc1998-09-29 22:36:29 +000058 */
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +020059void WMCreateEventHandler(WMView * view, unsigned long mask, WMEventProc * eventProc, void *clientData)
9d2e6ef9 scottc1998-09-29 22:36:29 +000060{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +020061 W_EventHandler *hPtr;
62 WMArrayIterator iter;
046403db dan2001-04-15 01:22:56 +000063
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +020064 WM_ITERATE_ARRAY(view->eventHandlers, hPtr, iter) {
65 if (hPtr->clientData == clientData && hPtr->proc == eventProc) {
66 hPtr->eventMask |= mask;
67 return;
68 }
69 }
9d2e6ef9 scottc1998-09-29 22:36:29 +000070
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +020071 hPtr = wmalloc(sizeof(W_EventHandler));
064f79eb dan2002-12-20 17:47:31 +000072
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +020073 /* select events for window */
74 hPtr->eventMask = mask;
75 hPtr->proc = eventProc;
76 hPtr->clientData = clientData;
064f79eb dan2002-12-20 17:47:31 +000077
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +020078 WMAddToArray(view->eventHandlers, hPtr);
9d2e6ef9 scottc1998-09-29 22:36:29 +000079}
80
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +020081static int matchHandler(void *item, void *cdata)
046403db dan2001-04-15 01:22:56 +000082{
83#define H1 ((W_EventHandler*)item)
84#define H2 ((W_EventHandler*)cdata)
85
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +020086 return (H1->eventMask == H2->eventMask && H1->proc == H2->proc && H1->clientData == H2->clientData);
046403db dan2001-04-15 01:22:56 +000087}
88
9d2e6ef9 scottc1998-09-29 22:36:29 +000089/*
90 * WMDeleteEventHandler--
91 * Delete event handler matching arguments from windows
92 * event handler list.
e7d0c5d9 dan2004-04-07 02:50:52 +000093 *
9d2e6ef9 scottc1998-09-29 22:36:29 +000094 */
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +020095void WMDeleteEventHandler(WMView * view, unsigned long mask, WMEventProc * eventProc, void *clientData)
9d2e6ef9 scottc1998-09-29 22:36:29 +000096{
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +020097 W_EventHandler tmp;
e29fce43 kojima2000-07-10 22:37:39 +000098
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +020099 tmp.eventMask = mask;
100 tmp.proc = eventProc;
101 tmp.clientData = clientData;
102 WMRemoveFromArrayMatching(view->eventHandlers, matchHandler, (void *)&tmp);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000103}
104
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200105static Time getEventTime(WMScreen * screen, XEvent * event)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000106{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200107 switch (event->type) {
108 case ButtonPress:
109 case ButtonRelease:
110 return event->xbutton.time;
111 case KeyPress:
112 case KeyRelease:
113 return event->xkey.time;
114 case MotionNotify:
115 return event->xmotion.time;
116 case EnterNotify:
117 case LeaveNotify:
118 return event->xcrossing.time;
119 case PropertyNotify:
120 return event->xproperty.time;
121 case SelectionClear:
122 return event->xselectionclear.time;
123 case SelectionRequest:
124 return event->xselectionrequest.time;
125 case SelectionNotify:
126 return event->xselection.time;
127 default:
128 return screen->lastEventTime;
129 }
9d2e6ef9 scottc1998-09-29 22:36:29 +0000130}
131
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200132void W_CallDestroyHandlers(W_View * view)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000133{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200134 XEvent event;
135 WMArrayIterator iter;
136 W_EventHandler *hPtr;
137
138 event.type = DestroyNotify;
139 event.xdestroywindow.window = view->window;
140 event.xdestroywindow.event = view->window;
141
142 WM_ITERATE_ARRAY(view->eventHandlers, hPtr, iter) {
143 if (hPtr->eventMask & StructureNotifyMask) {
144 (*hPtr->proc) (&event, hPtr->clientData);
145 }
146 }
9d2e6ef9 scottc1998-09-29 22:36:29 +0000147}
148
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200149void WMSetViewNextResponder(WMView * view, WMView * responder)
bb886be8 kojima2001-01-18 02:00:56 +0000150{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200151 /* set the widget to receive keyboard events that aren't handled
152 * by this widget */
e7d0c5d9 dan2004-04-07 02:50:52 +0000153
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200154 view->nextResponder = responder;
bb886be8 kojima2001-01-18 02:00:56 +0000155}
156
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200157void WMRelayToNextResponder(WMView * view, XEvent * event)
bb886be8 kojima2001-01-18 02:00:56 +0000158{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200159 unsigned long mask = eventMasks[event->xany.type];
160
161 if (view->nextResponder) {
162 WMView *next = view->nextResponder;
163 W_EventHandler *hPtr;
164 WMArrayIterator iter;
165
166 WM_ITERATE_ARRAY(next->eventHandlers, hPtr, iter) {
167 if ((hPtr->eventMask & mask)) {
168 (*hPtr->proc) (event, hPtr->clientData);
169 }
170 }
171 }
bb886be8 kojima2001-01-18 02:00:56 +0000172}
173
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200174int WMHandleEvent(XEvent * event)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000175{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200176 W_EventHandler *hPtr;
177 W_View *view, *toplevel;
178 unsigned long mask;
179 Window window;
180 WMArrayIterator iter;
181
182 if (event->type == MappingNotify) {
183 XRefreshKeyboardMapping(&event->xmapping);
184 return True;
185 }
186
187 if (XFilterEvent(event, None) == True) {
188 return False;
189 }
190
191 mask = eventMasks[event->xany.type];
192
193 window = event->xany.window;
194
195 /* diferentiate SubstructureNotify with StructureNotify */
196 if (mask == StructureNotifyMask) {
197 if (event->xmap.event != event->xmap.window) {
198 mask = SubstructureNotifyMask;
199 window = event->xmap.event;
200 }
201 }
202 view = W_GetViewForXWindow(event->xany.display, window);
203
204 if (!view) {
205 if (extraEventHandler)
206 (extraEventHandler) (event);
207
208 return False;
209 }
210
211 view->screen->lastEventTime = getEventTime(view->screen, event);
212
213 toplevel = W_TopLevelOfView(view);
214
215 if (event->type == SelectionNotify || event->type == SelectionClear || event->type == SelectionRequest) {
216 /* handle selection related events */
217 W_HandleSelectionEvent(event);
218
219 }
220
221 /* if it's a key event, redispatch it to the focused control */
222 if (mask & (KeyPressMask | KeyReleaseMask)) {
223 W_View *focused = W_FocusedViewOfToplevel(toplevel);
224
225 if (focused) {
226 view = focused;
227 }
228 }
229
230 /* compress Motion events */
231 if (event->type == MotionNotify && !view->flags.dontCompressMotion) {
232 while (XPending(event->xmotion.display)) {
233 XEvent ev;
234 XPeekEvent(event->xmotion.display, &ev);
235 if (ev.type == MotionNotify
236 && event->xmotion.window == ev.xmotion.window
237 && event->xmotion.subwindow == ev.xmotion.subwindow) {
238 /* replace events */
239 XNextEvent(event->xmotion.display, event);
240 } else
241 break;
242 }
243 }
244
245 /* compress expose events */
246 if (event->type == Expose && !view->flags.dontCompressExpose) {
247 while (XCheckTypedWindowEvent(event->xexpose.display, view->window, Expose, event)) ;
248 }
249
250 if (view->screen->modalLoop && toplevel != view->screen->modalView && !toplevel->flags.worksWhenModal) {
251 if (event->type == KeyPress || event->type == KeyRelease
252 || event->type == MotionNotify || event->type == ButtonPress
253 || event->type == ButtonRelease || event->type == FocusIn || event->type == FocusOut) {
254 return True;
255 }
256 }
257
258 /* do balloon stuffs */
259 if (event->type == EnterNotify)
260 W_BalloonHandleEnterView(view);
261 else if (event->type == LeaveNotify)
262 W_BalloonHandleLeaveView(view);
263
264 /* This is a hack. It will make the panel be secure while
265 * the event handlers are handled, as some event handler
266 * might destroy the widget. */
267 W_RetainView(toplevel);
268
269 WM_ITERATE_ARRAY(view->eventHandlers, hPtr, iter) {
270 if ((hPtr->eventMask & mask)) {
271 (*hPtr->proc) (event, hPtr->clientData);
272 }
273 }
bb886be8 kojima2001-01-18 02:00:56 +0000274#if 0
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200275 /* pass the event to the top level window of the widget */
276 /* TODO: change this to a responder chain */
277 if (view->parent != NULL) {
278 vPtr = view;
279 while (vPtr->parent != NULL)
280 vPtr = vPtr->parent;
281
282 WM_ITERATE_ARRAY(vPtr->eventHandlers, hPtr, iter) {
283 if (hPtr->eventMask & mask) {
284 (*hPtr->proc) (event, hPtr->clientData);
285 }
286 }
287 }
bb886be8 kojima2001-01-18 02:00:56 +0000288#endif
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200289 /* save button click info to track double-clicks */
290 if (view->screen->ignoreNextDoubleClick) {
291 view->screen->ignoreNextDoubleClick = 0;
292 } else {
293 if (event->type == ButtonPress) {
294 view->screen->lastClickWindow = event->xbutton.window;
295 view->screen->lastClickTime = event->xbutton.time;
296 }
297 }
298
299 if (event->type == ClientMessage) {
300 /* must be handled at the end, for such message can destroy the view */
301 W_HandleDNDClientMessage(toplevel, &event->xclient);
302 }
303
304 W_ReleaseView(toplevel);
305
306 return True;
9d2e6ef9 scottc1998-09-29 22:36:29 +0000307}
308
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200309int WMIsDoubleClick(XEvent * event)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000310{
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200311 W_View *view;
e7d0c5d9 dan2004-04-07 02:50:52 +0000312
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200313 if (event->type != ButtonPress)
314 return False;
e7d0c5d9 dan2004-04-07 02:50:52 +0000315
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200316 view = W_GetViewForXWindow(event->xany.display, event->xbutton.window);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000317
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200318 if (!view)
319 return False;
e7d0c5d9 dan2004-04-07 02:50:52 +0000320
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200321 if (view->screen->lastClickWindow != event->xbutton.window)
322 return False;
e7d0c5d9 dan2004-04-07 02:50:52 +0000323
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200324 if (event->xbutton.time - view->screen->lastClickTime < WINGsConfiguration.doubleClickDelay) {
325 view->screen->lastClickTime = 0;
326 view->screen->lastClickWindow = None;
327 view->screen->ignoreNextDoubleClick = 1;
328 return True;
329 } else
330 return False;
9d2e6ef9 scottc1998-09-29 22:36:29 +0000331}
332
bc3b44ac dan2001-03-21 01:29:22 +0000333/*
1a3fd2f7 dan2001-03-22 00:56:09 +0000334 * Check for X and input events. If X events are present input events will
335 * not be checked.
336 *
337 * Return value: True if a X event is available or any input event was
338 * processed, false otherwise (including return because of
339 * some timer handler expired).
340 *
341 * If waitForInput is False, it will just peek for available input and return
342 * without processing. Return vaue will be True if input is available.
343 *
344 * If waitForInput is True, it will wait until an input event arrives on the
345 * registered input handlers and ConnectionNumber(dpy), or will return when
346 * a timer handler expires if no input event arrived until then.
bc3b44ac dan2001-03-21 01:29:22 +0000347 */
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200348static Bool waitForEvent(Display * dpy, unsigned long xeventmask, Bool waitForInput)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000349{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200350 XSync(dpy, False);
351 if (xeventmask == 0) {
352 if (XPending(dpy))
353 return True;
354 } else {
355 XEvent ev;
356 if (XCheckMaskEvent(dpy, xeventmask, &ev)) {
357 XPutBackEvent(dpy, &ev);
358 return True;
359 }
360 }
361
362 return W_HandleInputEvents(waitForInput, ConnectionNumber(dpy));
9d2e6ef9 scottc1998-09-29 22:36:29 +0000363}
364
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200365void WMNextEvent(Display * dpy, XEvent * event)
1a3fd2f7 dan2001-03-22 00:56:09 +0000366{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200367 /* Check any expired timers */
368 W_CheckTimerHandlers();
369
370 while (XPending(dpy) == 0) {
371 /* Do idle and timer stuff while there are no input or X events */
372 while (!waitForEvent(dpy, 0, False) && W_CheckIdleHandlers()) {
373 /* dispatch timer events */
374 W_CheckTimerHandlers();
375 }
376
377 /*
378 * Make sure that new events did not arrive while we were doing
379 * timer/idle stuff. Or we might block forever waiting for
380 * an event that already arrived.
381 */
382 /* wait for something to happen or a timer to expire */
383 waitForEvent(dpy, 0, True);
384
385 /* Check any expired timers */
386 W_CheckTimerHandlers();
387 }
388
389 XNextEvent(dpy, event);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000390}
391
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200392void WMMaskEvent(Display * dpy, long mask, XEvent * event)
bc3b44ac dan2001-03-21 01:29:22 +0000393{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200394 /* Check any expired timers */
395 W_CheckTimerHandlers();
1a3fd2f7 dan2001-03-22 00:56:09 +0000396
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200397 while (!XCheckMaskEvent(dpy, mask, event)) {
398 /* Do idle and timer stuff while there are no input or X events */
399 while (!waitForEvent(dpy, mask, False) && W_CheckIdleHandlers()) {
400 W_CheckTimerHandlers();
401 }
9d2e6ef9 scottc1998-09-29 22:36:29 +0000402
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200403 if (XCheckMaskEvent(dpy, mask, event))
404 return;
1a3fd2f7 dan2001-03-22 00:56:09 +0000405
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200406 /* Wait for input on the X connection socket or another input handler */
407 waitForEvent(dpy, mask, True);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000408
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200409 /* Check any expired timers */
410 W_CheckTimerHandlers();
411 }
9d2e6ef9 scottc1998-09-29 22:36:29 +0000412}
9d2e6ef9 scottc1998-09-29 22:36:29 +0000413
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200414Bool WMScreenPending(WMScreen * scr)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000415{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200416 if (XPending(scr->display))
417 return True;
418 else
419 return False;
9d2e6ef9 scottc1998-09-29 22:36:29 +0000420}
421
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200422WMEventHook *WMHookEventHandler(WMEventHook * handler)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000423{
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200424 WMEventHook *oldHandler = extraEventHandler;
e7d0c5d9 dan2004-04-07 02:50:52 +0000425
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200426 extraEventHandler = handler;
e7d0c5d9 dan2004-04-07 02:50:52 +0000427
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200428 return oldHandler;
9d2e6ef9 scottc1998-09-29 22:36:29 +0000429}