1 /*
2  *
3 Copyright 1990, 1998  The Open Group
4 
5 Permission to use, copy, modify, distribute, and sell this software and its
6 documentation for any purpose is hereby granted without fee, provided that
7 the above copyright notice appear in all copies and that both that
8 copyright notice and this permission notice appear in supporting
9 documentation.
10 
11 The above copyright notice and this permission notice shall be included in
12 all copies or substantial portions of the Software.
13 
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
17 OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20 
21 Except as contained in this notice, the name of The Open Group shall not be
22 used in advertising or otherwise to promote the sale, use or other dealings
23 in this Software without prior written authorization from The Open Group.
24  *
25  * Author:  Keith Packard, MIT X Consortium
26  */
27 
28 /*
29  * mieq.c
30  *
31  * Machine independent event queue
32  *
33  */
34 
35 #if HAVE_DIX_CONFIG_H
36 #include <dix-config.h>
37 #endif
38 
39 #include   <X11/X.h>
40 #include   <X11/Xmd.h>
41 #include   <X11/Xproto.h>
42 #include   "misc.h"
43 #include   "windowstr.h"
44 #include   "pixmapstr.h"
45 #include   "inputstr.h"
46 #include   "inpututils.h"
47 #include   "mi.h"
48 #include   "mipointer.h"
49 #include   "scrnintstr.h"
50 #include   <X11/extensions/XI.h>
51 #include   <X11/extensions/XIproto.h>
52 #include   <X11/extensions/geproto.h>
53 #include   "extinit.h"
54 #include   "exglobals.h"
55 #include   "eventstr.h"
56 
57 #ifdef DPMSExtension
58 #include "dpmsproc.h"
59 #include <X11/extensions/dpmsconst.h>
60 #endif
61 
62 /* Maximum size should be initial size multiplied by a power of 2 */
63 #define QUEUE_INITIAL_SIZE                 512
64 #define QUEUE_RESERVED_SIZE                 64
65 #define QUEUE_MAXIMUM_SIZE                4096
66 #define QUEUE_DROP_BACKTRACE_FREQUENCY     100
67 #define QUEUE_DROP_BACKTRACE_MAX            10
68 
69 #define EnqueueScreen(dev) dev->spriteInfo->sprite->pEnqueueScreen
70 #define DequeueScreen(dev) dev->spriteInfo->sprite->pDequeueScreen
71 
72 typedef struct _Event {
73     InternalEvent *events;
74     ScreenPtr pScreen;
75     DeviceIntPtr pDev;          /* device this event _originated_ from */
76 } EventRec, *EventPtr;
77 
78 typedef struct _EventQueue {
79     HWEventQueueType head, tail;        /* long for SetInputCheck */
80     CARD32 lastEventTime;       /* to avoid time running backwards */
81     int lastMotion;             /* device ID if last event motion? */
82     EventRec *events;           /* our queue as an array */
83     size_t nevents;             /* the number of buckets in our queue */
84     size_t dropped;             /* counter for number of consecutive dropped events */
85     mieqHandler handlers[128];  /* custom event handler */
86 } EventQueueRec, *EventQueuePtr;
87 
88 static EventQueueRec miEventQueue;
89 
90 static CallbackListPtr miCallbacksWhenDrained = NULL;
91 
92 static size_t
mieqNumEnqueued(EventQueuePtr eventQueue)93 mieqNumEnqueued(EventQueuePtr eventQueue)
94 {
95     size_t n_enqueued = 0;
96 
97     if (eventQueue->nevents) {
98         /* % is not well-defined with negative numbers... sigh */
99         n_enqueued = eventQueue->tail - eventQueue->head + eventQueue->nevents;
100         if (n_enqueued >= eventQueue->nevents)
101             n_enqueued -= eventQueue->nevents;
102     }
103     return n_enqueued;
104 }
105 
106 /* Pre-condition: Called with input_lock held */
107 static Bool
mieqGrowQueue(EventQueuePtr eventQueue,size_t new_nevents)108 mieqGrowQueue(EventQueuePtr eventQueue, size_t new_nevents)
109 {
110     size_t i, n_enqueued, first_hunk;
111     EventRec *new_events;
112 
113     if (!eventQueue) {
114         ErrorF("[mi] mieqGrowQueue called with a NULL eventQueue\n");
115         return FALSE;
116     }
117 
118     if (new_nevents <= eventQueue->nevents)
119         return FALSE;
120 
121     new_events = calloc(new_nevents, sizeof(EventRec));
122     if (new_events == NULL) {
123         ErrorF("[mi] mieqGrowQueue memory allocation error.\n");
124         return FALSE;
125     }
126 
127     n_enqueued = mieqNumEnqueued(eventQueue);
128 
129     /* First copy the existing events */
130     first_hunk = eventQueue->nevents - eventQueue->head;
131     if (eventQueue->events) {
132         memcpy(new_events,
133                &eventQueue->events[eventQueue->head],
134                first_hunk * sizeof(EventRec));
135         memcpy(&new_events[first_hunk],
136                eventQueue->events, eventQueue->head * sizeof(EventRec));
137     }
138 
139     /* Initialize the new portion */
140     for (i = eventQueue->nevents; i < new_nevents; i++) {
141         InternalEvent *evlist = InitEventList(1);
142 
143         if (!evlist) {
144             size_t j;
145 
146             for (j = 0; j < i; j++)
147                 FreeEventList(new_events[j].events, 1);
148             free(new_events);
149             return FALSE;
150         }
151         new_events[i].events = evlist;
152     }
153 
154     /* And update our record */
155     eventQueue->tail = n_enqueued;
156     eventQueue->head = 0;
157     eventQueue->nevents = new_nevents;
158     free(eventQueue->events);
159     eventQueue->events = new_events;
160 
161     return TRUE;
162 }
163 
164 Bool
mieqInit(void)165 mieqInit(void)
166 {
167     memset(&miEventQueue, 0, sizeof(miEventQueue));
168     miEventQueue.lastEventTime = GetTimeInMillis();
169 
170     input_lock();
171     if (!mieqGrowQueue(&miEventQueue, QUEUE_INITIAL_SIZE))
172         FatalError("Could not allocate event queue.\n");
173     input_unlock();
174 
175     SetInputCheck(&miEventQueue.head, &miEventQueue.tail);
176     return TRUE;
177 }
178 
179 void
mieqFini(void)180 mieqFini(void)
181 {
182     int i;
183 
184     for (i = 0; i < miEventQueue.nevents; i++) {
185         if (miEventQueue.events[i].events != NULL) {
186             FreeEventList(miEventQueue.events[i].events, 1);
187             miEventQueue.events[i].events = NULL;
188         }
189     }
190     free(miEventQueue.events);
191 }
192 
193 /*
194  * Must be reentrant with ProcessInputEvents.  Assumption: mieqEnqueue
195  * will never be interrupted. Must be called with input_lock held
196  */
197 
198 void
mieqEnqueue(DeviceIntPtr pDev,InternalEvent * e)199 mieqEnqueue(DeviceIntPtr pDev, InternalEvent *e)
200 {
201     unsigned int oldtail = miEventQueue.tail;
202     InternalEvent *evt;
203     int isMotion = 0;
204     int evlen;
205     Time time;
206     size_t n_enqueued;
207 
208     verify_internal_event(e);
209 
210     n_enqueued = mieqNumEnqueued(&miEventQueue);
211 
212     /* avoid merging events from different devices */
213     if (e->any.type == ET_Motion)
214         isMotion = pDev->id;
215 
216     if (isMotion && isMotion == miEventQueue.lastMotion &&
217         oldtail != miEventQueue.head) {
218         oldtail = (oldtail - 1) % miEventQueue.nevents;
219     }
220     else if (n_enqueued + 1 == miEventQueue.nevents) {
221         if (!mieqGrowQueue(&miEventQueue, miEventQueue.nevents << 1)) {
222             /* Toss events which come in late.  Usually this means your server's
223              * stuck in an infinite loop in the main thread.
224              */
225             miEventQueue.dropped++;
226             if (miEventQueue.dropped == 1) {
227                 ErrorFSigSafe("[mi] EQ overflowing.  Additional events will be "
228                               "discarded until existing events are processed.\n");
229                 xorg_backtrace();
230                 ErrorFSigSafe("[mi] These backtraces from mieqEnqueue may point to "
231                               "a culprit higher up the stack.\n");
232                 ErrorFSigSafe("[mi] mieq is *NOT* the cause.  It is a victim.\n");
233             }
234             else if (miEventQueue.dropped % QUEUE_DROP_BACKTRACE_FREQUENCY == 0 &&
235                      miEventQueue.dropped / QUEUE_DROP_BACKTRACE_FREQUENCY <=
236                      QUEUE_DROP_BACKTRACE_MAX) {
237                 ErrorFSigSafe("[mi] EQ overflow continuing.  %zu events have been "
238                               "dropped.\n", miEventQueue.dropped);
239                 if (miEventQueue.dropped / QUEUE_DROP_BACKTRACE_FREQUENCY ==
240                     QUEUE_DROP_BACKTRACE_MAX) {
241                     ErrorFSigSafe("[mi] No further overflow reports will be "
242                                   "reported until the clog is cleared.\n");
243                 }
244                 xorg_backtrace();
245             }
246             return;
247         }
248         oldtail = miEventQueue.tail;
249     }
250 
251     evlen = e->any.length;
252     evt = miEventQueue.events[oldtail].events;
253     memcpy(evt, e, evlen);
254 
255     time = e->any.time;
256     /* Make sure that event times don't go backwards - this
257      * is "unnecessary", but very useful. */
258     if (time < miEventQueue.lastEventTime &&
259         miEventQueue.lastEventTime - time < 10000)
260         e->any.time = miEventQueue.lastEventTime;
261 
262     miEventQueue.lastEventTime = evt->any.time;
263     miEventQueue.events[oldtail].pScreen = pDev ? EnqueueScreen(pDev) : NULL;
264     miEventQueue.events[oldtail].pDev = pDev;
265 
266     miEventQueue.lastMotion = isMotion;
267     miEventQueue.tail = (oldtail + 1) % miEventQueue.nevents;
268 }
269 
270 /**
271  * Changes the screen reference events are being enqueued from.
272  * Input events are enqueued with a screen reference and dequeued and
273  * processed with a (potentially different) screen reference.
274  * This function is called whenever a new event has changed screen but is
275  * still logically on the previous screen as seen by the client.
276  * This usually happens whenever the visible cursor moves across screen
277  * boundaries during event generation, before the same event is processed
278  * and sent down the wire.
279  *
280  * @param pDev The device that triggered a screen change.
281  * @param pScreen The new screen events are being enqueued for.
282  * @param set_dequeue_screen If TRUE, pScreen is set as both enqueue screen
283  * and dequeue screen.
284  */
285 void
mieqSwitchScreen(DeviceIntPtr pDev,ScreenPtr pScreen,Bool set_dequeue_screen)286 mieqSwitchScreen(DeviceIntPtr pDev, ScreenPtr pScreen, Bool set_dequeue_screen)
287 {
288     EnqueueScreen(pDev) = pScreen;
289     if (set_dequeue_screen)
290         DequeueScreen(pDev) = pScreen;
291 }
292 
293 void
mieqSetHandler(int event,mieqHandler handler)294 mieqSetHandler(int event, mieqHandler handler)
295 {
296     if (handler && miEventQueue.handlers[event] != handler)
297         ErrorF("[mi] mieq: warning: overriding existing handler %p with %p for "
298                "event %d\n", miEventQueue.handlers[event], handler, event);
299 
300     miEventQueue.handlers[event] = handler;
301 }
302 
303 /**
304  * Change the device id of the given event to the given device's id.
305  */
306 static void
ChangeDeviceID(DeviceIntPtr dev,InternalEvent * event)307 ChangeDeviceID(DeviceIntPtr dev, InternalEvent *event)
308 {
309     switch (event->any.type) {
310     case ET_Motion:
311     case ET_KeyPress:
312     case ET_KeyRelease:
313     case ET_ButtonPress:
314     case ET_ButtonRelease:
315     case ET_ProximityIn:
316     case ET_ProximityOut:
317     case ET_Hierarchy:
318     case ET_DeviceChanged:
319     case ET_TouchBegin:
320     case ET_TouchUpdate:
321     case ET_TouchEnd:
322         event->device_event.deviceid = dev->id;
323         break;
324     case ET_TouchOwnership:
325         event->touch_ownership_event.deviceid = dev->id;
326         break;
327 #ifdef XFreeXDGA
328     case ET_DGAEvent:
329         break;
330 #endif
331     case ET_RawKeyPress:
332     case ET_RawKeyRelease:
333     case ET_RawButtonPress:
334     case ET_RawButtonRelease:
335     case ET_RawMotion:
336     case ET_RawTouchBegin:
337     case ET_RawTouchEnd:
338     case ET_RawTouchUpdate:
339         event->raw_event.deviceid = dev->id;
340         break;
341     case ET_BarrierHit:
342     case ET_BarrierLeave:
343         event->barrier_event.deviceid = dev->id;
344         break;
345     default:
346         ErrorF("[mi] Unknown event type (%d), cannot change id.\n",
347                event->any.type);
348     }
349 }
350 
351 static void
FixUpEventForMaster(DeviceIntPtr mdev,DeviceIntPtr sdev,InternalEvent * original,InternalEvent * master)352 FixUpEventForMaster(DeviceIntPtr mdev, DeviceIntPtr sdev,
353                     InternalEvent *original, InternalEvent *master)
354 {
355     verify_internal_event(original);
356     verify_internal_event(master);
357     /* Ensure chained button mappings, i.e. that the detail field is the
358      * value of the mapped button on the SD, not the physical button */
359     if (original->any.type == ET_ButtonPress ||
360         original->any.type == ET_ButtonRelease) {
361         int btn = original->device_event.detail.button;
362 
363         if (!sdev->button)
364             return;             /* Should never happen */
365 
366         master->device_event.detail.button = sdev->button->map[btn];
367     }
368 }
369 
370 /**
371  * Copy the given event into master.
372  * @param sdev The slave device the original event comes from
373  * @param original The event as it came from the EQ
374  * @param copy The event after being copied
375  * @return The master device or NULL if the device is a floating slave.
376  */
377 DeviceIntPtr
CopyGetMasterEvent(DeviceIntPtr sdev,InternalEvent * original,InternalEvent * copy)378 CopyGetMasterEvent(DeviceIntPtr sdev,
379                    InternalEvent *original, InternalEvent *copy)
380 {
381     DeviceIntPtr mdev;
382     int len = original->any.length;
383     int type = original->any.type;
384     int mtype;                  /* which master type? */
385 
386     verify_internal_event(original);
387 
388     /* ET_XQuartz has sdev == NULL */
389     if (!sdev || IsMaster(sdev) || IsFloating(sdev))
390         return NULL;
391 
392 #ifdef XFreeXDGA
393     if (type == ET_DGAEvent)
394         type = original->dga_event.subtype;
395 #endif
396 
397     switch (type) {
398     case ET_KeyPress:
399     case ET_KeyRelease:
400         mtype = MASTER_KEYBOARD;
401         break;
402     case ET_ButtonPress:
403     case ET_ButtonRelease:
404     case ET_Motion:
405     case ET_ProximityIn:
406     case ET_ProximityOut:
407         mtype = MASTER_POINTER;
408         break;
409     default:
410         mtype = MASTER_ATTACHED;
411         break;
412     }
413 
414     mdev = GetMaster(sdev, mtype);
415     memcpy(copy, original, len);
416     ChangeDeviceID(mdev, copy);
417     FixUpEventForMaster(mdev, sdev, original, copy);
418 
419     return mdev;
420 }
421 
422 static void
mieqMoveToNewScreen(DeviceIntPtr dev,ScreenPtr screen,DeviceEvent * event)423 mieqMoveToNewScreen(DeviceIntPtr dev, ScreenPtr screen, DeviceEvent *event)
424 {
425     if (dev && screen && screen != DequeueScreen(dev)) {
426         int x = 0, y = 0;
427 
428         DequeueScreen(dev) = screen;
429         x = event->root_x;
430         y = event->root_y;
431         NewCurrentScreen(dev, DequeueScreen(dev), x, y);
432     }
433 }
434 
435 /**
436  * Post the given @event through the device hierarchy, as appropriate.
437  * Use this function if an event must be posted for a given device during the
438  * usual event processing cycle.
439  */
440 void
mieqProcessDeviceEvent(DeviceIntPtr dev,InternalEvent * event,ScreenPtr screen)441 mieqProcessDeviceEvent(DeviceIntPtr dev, InternalEvent *event, ScreenPtr screen)
442 {
443     mieqHandler handler;
444     DeviceIntPtr master;
445     InternalEvent mevent;       /* master event */
446 
447     verify_internal_event(event);
448 
449     /* refuse events from disabled devices */
450     if (dev && !dev->enabled)
451         return;
452 
453     /* Custom event handler */
454     handler = miEventQueue.handlers[event->any.type];
455 
456     switch (event->any.type) {
457         /* Catch events that include valuator information and check if they
458          * are changing the screen */
459     case ET_Motion:
460     case ET_KeyPress:
461     case ET_KeyRelease:
462     case ET_ButtonPress:
463     case ET_ButtonRelease:
464         if (!handler)
465             mieqMoveToNewScreen(dev, screen, &event->device_event);
466         break;
467     case ET_TouchBegin:
468     case ET_TouchUpdate:
469     case ET_TouchEnd:
470         if (!handler && (event->device_event.flags & TOUCH_POINTER_EMULATED))
471             mieqMoveToNewScreen(dev, screen, &event->device_event);
472         break;
473     default:
474         break;
475     }
476     master = CopyGetMasterEvent(dev, event, &mevent);
477 
478     if (master)
479         master->lastSlave = dev;
480 
481     /* If someone's registered a custom event handler, let them
482      * steal it. */
483     if (handler) {
484         int screenNum = dev &&
485             DequeueScreen(dev) ? DequeueScreen(dev)->myNum : (screen ? screen->
486                                                               myNum : 0);
487         handler(screenNum, event, dev);
488         /* Check for the SD's master in case the device got detached
489          * during event processing */
490         if (master && !IsFloating(dev))
491             handler(screenNum, &mevent, master);
492     }
493     else {
494         /* process slave first, then master */
495         dev->public.processInputProc(event, dev);
496 
497         /* Check for the SD's master in case the device got detached
498          * during event processing */
499         if (master && !IsFloating(dev))
500             master->public.processInputProc(&mevent, master);
501     }
502 }
503 
504 /* Call this from ProcessInputEvents(). */
505 void
mieqProcessInputEvents(void)506 mieqProcessInputEvents(void)
507 {
508     EventRec *e = NULL;
509     ScreenPtr screen;
510     InternalEvent event;
511     DeviceIntPtr dev = NULL, master = NULL;
512     static Bool inProcessInputEvents = FALSE;
513 
514     input_lock();
515 
516     /*
517      * report an error if mieqProcessInputEvents() is called recursively;
518      * this can happen, e.g., if something in the mieqProcessDeviceEvent()
519      * call chain calls UpdateCurrentTime() instead of UpdateCurrentTimeIf()
520      */
521     BUG_WARN_MSG(inProcessInputEvents, "[mi] mieqProcessInputEvents() called recursively.\n");
522     inProcessInputEvents = TRUE;
523 
524     if (miEventQueue.dropped) {
525         ErrorF("[mi] EQ processing has resumed after %lu dropped events.\n",
526                (unsigned long) miEventQueue.dropped);
527         ErrorF
528             ("[mi] This may be caused by a misbehaving driver monopolizing the server's resources.\n");
529         miEventQueue.dropped = 0;
530     }
531 
532     while (miEventQueue.head != miEventQueue.tail) {
533         e = &miEventQueue.events[miEventQueue.head];
534 
535         event = *e->events;
536         dev = e->pDev;
537         screen = e->pScreen;
538 
539         miEventQueue.head = (miEventQueue.head + 1) % miEventQueue.nevents;
540 
541         input_unlock();
542 
543         master = (dev) ? GetMaster(dev, MASTER_ATTACHED) : NULL;
544 
545         if (screenIsSaved == SCREEN_SAVER_ON)
546             dixSaveScreens(serverClient, SCREEN_SAVER_OFF, ScreenSaverReset);
547 #ifdef DPMSExtension
548         else if (DPMSPowerLevel != DPMSModeOn)
549             SetScreenSaverTimer();
550 
551         if (DPMSPowerLevel != DPMSModeOn)
552             DPMSSet(serverClient, DPMSModeOn);
553 #endif
554 
555         mieqProcessDeviceEvent(dev, &event, screen);
556 
557         /* Update the sprite now. Next event may be from different device. */
558         if (master &&
559             (event.any.type == ET_Motion ||
560              ((event.any.type == ET_TouchBegin ||
561                event.any.type == ET_TouchUpdate) &&
562               event.device_event.flags & TOUCH_POINTER_EMULATED)))
563             miPointerUpdateSprite(dev);
564 
565         input_lock();
566     }
567 
568     inProcessInputEvents = FALSE;
569 
570     CallCallbacks(&miCallbacksWhenDrained, NULL);
571 
572     input_unlock();
573 }
574 
mieqAddCallbackOnDrained(CallbackProcPtr callback,void * param)575 void mieqAddCallbackOnDrained(CallbackProcPtr callback, void *param)
576 {
577     input_lock();
578     AddCallback(&miCallbacksWhenDrained, callback, param);
579     input_unlock();
580 }
581 
mieqRemoveCallbackOnDrained(CallbackProcPtr callback,void * param)582 void mieqRemoveCallbackOnDrained(CallbackProcPtr callback, void *param)
583 {
584     input_lock();
585     DeleteCallback(&miCallbacksWhenDrained, callback, param);
586     input_unlock();
587 }
588