~profzoom/ubuntu/quantal/wmaker/bug-1079925

« back to all changes in this revision

Viewing changes to WINGs/wevent.c

  • Committer: Bazaar Package Importer
  • Author(s): Marcelo E. Magallon
  • Date: 2004-11-10 14:05:30 UTC
  • Revision ID: james.westby@ubuntu.com-20041110140530-qpd66b5lm38x7apk
Tags: upstream-0.91.0
ImportĀ upstreamĀ versionĀ 0.91.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
 
 
2
 
 
3
/*
 
4
 * This event handling stuff was inspired on Tk.
 
5
 */
 
6
 
 
7
#include "WINGsP.h"
 
8
 
 
9
 
 
10
/* table to map event types to event masks */
 
11
static unsigned long eventMasks[] = {
 
12
    0,
 
13
    0,
 
14
    KeyPressMask,                       /* KeyPress */
 
15
    KeyReleaseMask,                     /* KeyRelease */
 
16
    ButtonPressMask,                    /* ButtonPress */
 
17
    ButtonReleaseMask,                  /* ButtonRelease */
 
18
    PointerMotionMask|PointerMotionHintMask|ButtonMotionMask
 
19
    |Button1MotionMask|Button2MotionMask|Button3MotionMask
 
20
    |Button4MotionMask|Button5MotionMask,
 
21
    /* MotionNotify */
 
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 */
 
50
};
 
51
 
 
52
 
 
53
 
 
54
/* hook for other toolkits or wmaker process their events */
 
55
static WMEventHook *extraEventHandler=NULL;
 
56
 
 
57
 
 
58
 
 
59
 
 
60
 
 
61
/*
 
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.
 
66
 *
 
67
 */
 
68
void
 
69
WMCreateEventHandler(WMView *view, unsigned long mask, WMEventProc *eventProc,
 
70
                     void *clientData)
 
71
{
 
72
    W_EventHandler *hPtr;
 
73
    WMArrayIterator iter;
 
74
 
 
75
    WM_ITERATE_ARRAY(view->eventHandlers, hPtr, iter) {
 
76
        if (hPtr->clientData==clientData && hPtr->proc==eventProc) {
 
77
            hPtr->eventMask |= mask;
 
78
            return;
 
79
        }
 
80
    }
 
81
 
 
82
    hPtr = wmalloc(sizeof(W_EventHandler));
 
83
 
 
84
    /* select events for window */
 
85
    hPtr->eventMask = mask;
 
86
    hPtr->proc = eventProc;
 
87
    hPtr->clientData = clientData;
 
88
 
 
89
    WMAddToArray(view->eventHandlers, hPtr);
 
90
}
 
91
 
 
92
 
 
93
static int
 
94
matchHandler(void *item, void *cdata)
 
95
{
 
96
#define H1 ((W_EventHandler*)item)
 
97
#define H2 ((W_EventHandler*)cdata)
 
98
 
 
99
    return (H1->eventMask==H2->eventMask && H1->proc==H2->proc &&
 
100
            H1->clientData==H2->clientData);
 
101
}
 
102
 
 
103
 
 
104
/*
 
105
 * WMDeleteEventHandler--
 
106
 *      Delete event handler matching arguments from windows
 
107
 * event handler list.
 
108
 *
 
109
 */
 
110
void
 
111
WMDeleteEventHandler(WMView *view, unsigned long mask, WMEventProc *eventProc,
 
112
                     void *clientData)
 
113
{
 
114
    W_EventHandler tmp;
 
115
 
 
116
    tmp.eventMask = mask;
 
117
    tmp.proc = eventProc;
 
118
    tmp.clientData = clientData;
 
119
    WMRemoveFromArrayMatching(view->eventHandlers, matchHandler, (void*)&tmp);
 
120
}
 
121
 
 
122
 
 
123
static Time
 
124
getEventTime(WMScreen *screen, XEvent *event)
 
125
{
 
126
    switch (event->type) {
 
127
    case ButtonPress:
 
128
    case ButtonRelease:
 
129
        return event->xbutton.time;
 
130
    case KeyPress:
 
131
    case KeyRelease:
 
132
        return event->xkey.time;
 
133
    case MotionNotify:
 
134
        return event->xmotion.time;
 
135
    case EnterNotify:
 
136
    case LeaveNotify:
 
137
        return event->xcrossing.time;
 
138
    case PropertyNotify:
 
139
        return event->xproperty.time;
 
140
    case SelectionClear:
 
141
        return event->xselectionclear.time;
 
142
    case SelectionRequest:
 
143
        return event->xselectionrequest.time;
 
144
    case SelectionNotify:
 
145
        return event->xselection.time;
 
146
    default:
 
147
        return screen->lastEventTime;
 
148
    }
 
149
}
 
150
 
 
151
 
 
152
void
 
153
W_CallDestroyHandlers(W_View *view)
 
154
{
 
155
    XEvent event;
 
156
    WMArrayIterator iter;
 
157
    W_EventHandler *hPtr;
 
158
 
 
159
 
 
160
    event.type = DestroyNotify;
 
161
    event.xdestroywindow.window = view->window;
 
162
    event.xdestroywindow.event = view->window;
 
163
 
 
164
    WM_ITERATE_ARRAY(view->eventHandlers, hPtr, iter) {
 
165
        if (hPtr->eventMask & StructureNotifyMask) {
 
166
            (*hPtr->proc)(&event, hPtr->clientData);
 
167
        }
 
168
    }
 
169
}
 
170
 
 
171
 
 
172
 
 
173
void
 
174
WMSetViewNextResponder(WMView *view, WMView *responder)
 
175
{
 
176
    /* set the widget to receive keyboard events that aren't handled
 
177
     * by this widget */
 
178
 
 
179
    view->nextResponder = responder;
 
180
}
 
181
 
 
182
 
 
183
void
 
184
WMRelayToNextResponder(WMView *view, XEvent *event)
 
185
{
 
186
    unsigned long mask = eventMasks[event->xany.type];
 
187
 
 
188
    if (view->nextResponder) {
 
189
        WMView *next = view->nextResponder;
 
190
        W_EventHandler *hPtr;
 
191
        WMArrayIterator iter;
 
192
 
 
193
        WM_ITERATE_ARRAY(next->eventHandlers, hPtr, iter) {
 
194
            if ((hPtr->eventMask & mask)) {
 
195
                (*hPtr->proc)(event, hPtr->clientData);
 
196
            }
 
197
        }
 
198
    }
 
199
}
 
200
 
 
201
 
 
202
int
 
203
WMHandleEvent(XEvent *event)
 
204
{
 
205
    W_EventHandler *hPtr;
 
206
    W_View *view, *toplevel;
 
207
    unsigned long mask;
 
208
    Window window;
 
209
    WMArrayIterator iter;
 
210
 
 
211
    if (event->type == MappingNotify) {
 
212
        XRefreshKeyboardMapping(&event->xmapping);
 
213
        return True;
 
214
    }
 
215
 
 
216
    mask = eventMasks[event->xany.type];
 
217
 
 
218
    window = event->xany.window;
 
219
 
 
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;
 
225
        }
 
226
    }
 
227
    view = W_GetViewForXWindow(event->xany.display, window);
 
228
 
 
229
    if (!view) {
 
230
        if (extraEventHandler)
 
231
            (extraEventHandler)(event);
 
232
 
 
233
        return False;
 
234
    }
 
235
 
 
236
    view->screen->lastEventTime = getEventTime(view->screen, event);
 
237
 
 
238
    toplevel = W_TopLevelOfView(view);
 
239
 
 
240
    if (event->type == SelectionNotify || event->type == SelectionClear
 
241
        || event->type == SelectionRequest) {
 
242
        /* handle selection related events */
 
243
        W_HandleSelectionEvent(event);
 
244
 
 
245
    }
 
246
 
 
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);
 
250
 
 
251
        if (focused) {
 
252
            view = focused;
 
253
        }
 
254
    }
 
255
 
 
256
    /* compress Motion events */
 
257
    if (event->type == MotionNotify && !view->flags.dontCompressMotion) {
 
258
        while (XPending(event->xmotion.display)) {
 
259
            XEvent ev;
 
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) {
 
264
                /* replace events */
 
265
                XNextEvent(event->xmotion.display, event);
 
266
            } else break;
 
267
        }
 
268
    }
 
269
 
 
270
    /* compress expose events */
 
271
    if (event->type == Expose && !view->flags.dontCompressExpose) {
 
272
        while (XCheckTypedWindowEvent(event->xexpose.display, view->window,
 
273
                                      Expose, event));
 
274
    }
 
275
 
 
276
 
 
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) {
 
283
            return True;
 
284
        }
 
285
    }
 
286
 
 
287
    /* do balloon stuffs */
 
288
    if (event->type == EnterNotify)
 
289
        W_BalloonHandleEnterView(view);
 
290
    else if (event->type == LeaveNotify)
 
291
        W_BalloonHandleLeaveView(view);
 
292
 
 
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);
 
297
 
 
298
    WM_ITERATE_ARRAY(view->eventHandlers, hPtr, iter) {
 
299
        if ((hPtr->eventMask & mask)) {
 
300
            (*hPtr->proc)(event, hPtr->clientData);
 
301
        }
 
302
    }
 
303
#if 0
 
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) {
 
307
        vPtr = view;
 
308
        while (vPtr->parent != NULL)
 
309
            vPtr = vPtr->parent;
 
310
 
 
311
        WM_ITERATE_ARRAY(vPtr->eventHandlers, hPtr, iter) {
 
312
            if (hPtr->eventMask & mask) {
 
313
                (*hPtr->proc)(event, hPtr->clientData);
 
314
            }
 
315
        }
 
316
    }
 
317
#endif
 
318
    /* save button click info to track double-clicks */
 
319
    if (view->screen->ignoreNextDoubleClick) {
 
320
        view->screen->ignoreNextDoubleClick = 0;
 
321
    } else {
 
322
        if (event->type == ButtonPress) {
 
323
            view->screen->lastClickWindow = event->xbutton.window;
 
324
            view->screen->lastClickTime = event->xbutton.time;
 
325
        }
 
326
    }
 
327
 
 
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);
 
331
    }
 
332
 
 
333
    W_ReleaseView(toplevel);
 
334
 
 
335
    return True;
 
336
}
 
337
 
 
338
 
 
339
int
 
340
WMIsDoubleClick(XEvent *event)
 
341
{
 
342
    W_View *view;
 
343
 
 
344
    if (event->type != ButtonPress)
 
345
        return False;
 
346
 
 
347
    view = W_GetViewForXWindow(event->xany.display, event->xbutton.window);
 
348
 
 
349
    if (!view)
 
350
        return False;
 
351
 
 
352
    if (view->screen->lastClickWindow != event->xbutton.window)
 
353
        return False;
 
354
 
 
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;
 
360
        return True;
 
361
    } else
 
362
        return False;
 
363
}
 
364
 
 
365
 
 
366
/*
 
367
 * Check for X and input events. If X events are present input events will
 
368
 * not be checked.
 
369
 *
 
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).
 
373
 *
 
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.
 
376
 *
 
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.
 
380
 */
 
381
static Bool
 
382
waitForEvent(Display *dpy, unsigned long xeventmask, Bool waitForInput)
 
383
{
 
384
    XSync(dpy, False);
 
385
    if (xeventmask==0) {
 
386
        if (XPending(dpy))
 
387
            return True;
 
388
    } else {
 
389
        XEvent ev;
 
390
        if (XCheckMaskEvent(dpy, xeventmask, &ev)) {
 
391
            XPutBackEvent(dpy, &ev);
 
392
            return True;
 
393
        }
 
394
    }
 
395
 
 
396
    return W_HandleInputEvents(waitForInput, ConnectionNumber(dpy));
 
397
}
 
398
 
 
399
 
 
400
void
 
401
WMNextEvent(Display *dpy, XEvent *event)
 
402
{
 
403
    /* Check any expired timers */
 
404
    W_CheckTimerHandlers();
 
405
 
 
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();
 
411
        }
 
412
 
 
413
        /*
 
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.
 
417
         */
 
418
        /* wait for something to happen or a timer to expire */
 
419
        waitForEvent(dpy, 0, True);
 
420
 
 
421
        /* Check any expired timers */
 
422
        W_CheckTimerHandlers();
 
423
    }
 
424
 
 
425
    XNextEvent(dpy, event);
 
426
}
 
427
 
 
428
 
 
429
void
 
430
WMMaskEvent(Display *dpy, long mask, XEvent *event)
 
431
{
 
432
    /* Check any expired timers */
 
433
    W_CheckTimerHandlers();
 
434
 
 
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();
 
439
        }
 
440
 
 
441
        if (XCheckMaskEvent(dpy, mask, event))
 
442
            return;
 
443
 
 
444
        /* Wait for input on the X connection socket or another input handler */
 
445
        waitForEvent(dpy, mask, True);
 
446
 
 
447
        /* Check any expired timers */
 
448
        W_CheckTimerHandlers();
 
449
    }
 
450
}
 
451
 
 
452
 
 
453
Bool
 
454
WMScreenPending(WMScreen *scr)
 
455
{
 
456
    if (XPending(scr->display))
 
457
        return True;
 
458
    else
 
459
        return False;
 
460
}
 
461
 
 
462
 
 
463
WMEventHook*
 
464
WMHookEventHandler(WMEventHook *handler)
 
465
{
 
466
    WMEventHook *oldHandler = extraEventHandler;
 
467
 
 
468
    extraEventHandler = handler;
 
469
 
 
470
    return oldHandler;
 
471
}
 
472
 
 
473