xref: /OK3568_Linux_fs/external/xserver/mi/mieq.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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 size_t
mieqNumEnqueued(EventQueuePtr eventQueue)91 mieqNumEnqueued(EventQueuePtr eventQueue)
92 {
93     size_t n_enqueued = 0;
94 
95     if (eventQueue->nevents) {
96         /* % is not well-defined with negative numbers... sigh */
97         n_enqueued = eventQueue->tail - eventQueue->head + eventQueue->nevents;
98         if (n_enqueued >= eventQueue->nevents)
99             n_enqueued -= eventQueue->nevents;
100     }
101     return n_enqueued;
102 }
103 
104 /* Pre-condition: Called with input_lock held */
105 static Bool
mieqGrowQueue(EventQueuePtr eventQueue,size_t new_nevents)106 mieqGrowQueue(EventQueuePtr eventQueue, size_t new_nevents)
107 {
108     size_t i, n_enqueued, first_hunk;
109     EventRec *new_events;
110 
111     if (!eventQueue) {
112         ErrorF("[mi] mieqGrowQueue called with a NULL eventQueue\n");
113         return FALSE;
114     }
115 
116     if (new_nevents <= eventQueue->nevents)
117         return FALSE;
118 
119     new_events = calloc(new_nevents, sizeof(EventRec));
120     if (new_events == NULL) {
121         ErrorF("[mi] mieqGrowQueue memory allocation error.\n");
122         return FALSE;
123     }
124 
125     n_enqueued = mieqNumEnqueued(eventQueue);
126 
127     /* First copy the existing events */
128     first_hunk = eventQueue->nevents - eventQueue->head;
129     memcpy(new_events,
130            &eventQueue->events[eventQueue->head],
131            first_hunk * sizeof(EventRec));
132     memcpy(&new_events[first_hunk],
133            eventQueue->events, eventQueue->head * sizeof(EventRec));
134 
135     /* Initialize the new portion */
136     for (i = eventQueue->nevents; i < new_nevents; i++) {
137         InternalEvent *evlist = InitEventList(1);
138 
139         if (!evlist) {
140             size_t j;
141 
142             for (j = 0; j < i; j++)
143                 FreeEventList(new_events[j].events, 1);
144             free(new_events);
145             return FALSE;
146         }
147         new_events[i].events = evlist;
148     }
149 
150     /* And update our record */
151     eventQueue->tail = n_enqueued;
152     eventQueue->head = 0;
153     eventQueue->nevents = new_nevents;
154     free(eventQueue->events);
155     eventQueue->events = new_events;
156 
157     return TRUE;
158 }
159 
160 Bool
mieqInit(void)161 mieqInit(void)
162 {
163     memset(&miEventQueue, 0, sizeof(miEventQueue));
164     miEventQueue.lastEventTime = GetTimeInMillis();
165 
166     input_lock();
167     if (!mieqGrowQueue(&miEventQueue, QUEUE_INITIAL_SIZE))
168         FatalError("Could not allocate event queue.\n");
169     input_unlock();
170 
171     SetInputCheck(&miEventQueue.head, &miEventQueue.tail);
172     return TRUE;
173 }
174 
175 void
mieqFini(void)176 mieqFini(void)
177 {
178     int i;
179 
180     for (i = 0; i < miEventQueue.nevents; i++) {
181         if (miEventQueue.events[i].events != NULL) {
182             FreeEventList(miEventQueue.events[i].events, 1);
183             miEventQueue.events[i].events = NULL;
184         }
185     }
186     free(miEventQueue.events);
187 }
188 
189 /*
190  * Must be reentrant with ProcessInputEvents.  Assumption: mieqEnqueue
191  * will never be interrupted. Must be called with input_lock held
192  */
193 
194 void
mieqEnqueue(DeviceIntPtr pDev,InternalEvent * e)195 mieqEnqueue(DeviceIntPtr pDev, InternalEvent *e)
196 {
197     unsigned int oldtail = miEventQueue.tail;
198     InternalEvent *evt;
199     int isMotion = 0;
200     int evlen;
201     Time time;
202     size_t n_enqueued;
203 
204     verify_internal_event(e);
205 
206     n_enqueued = mieqNumEnqueued(&miEventQueue);
207 
208     /* avoid merging events from different devices */
209     if (e->any.type == ET_Motion)
210         isMotion = pDev->id;
211 
212     if (isMotion && isMotion == miEventQueue.lastMotion &&
213         oldtail != miEventQueue.head) {
214         oldtail = (oldtail - 1) % miEventQueue.nevents;
215     }
216     else if (n_enqueued + 1 == miEventQueue.nevents) {
217         if (!mieqGrowQueue(&miEventQueue, miEventQueue.nevents << 1)) {
218             /* Toss events which come in late.  Usually this means your server's
219              * stuck in an infinite loop in the main thread.
220              */
221             miEventQueue.dropped++;
222             if (miEventQueue.dropped == 1) {
223                 ErrorFSigSafe("[mi] EQ overflowing.  Additional events will be "
224                               "discarded until existing events are processed.\n");
225                 xorg_backtrace();
226                 ErrorFSigSafe("[mi] These backtraces from mieqEnqueue may point to "
227                               "a culprit higher up the stack.\n");
228                 ErrorFSigSafe("[mi] mieq is *NOT* the cause.  It is a victim.\n");
229             }
230             else if (miEventQueue.dropped % QUEUE_DROP_BACKTRACE_FREQUENCY == 0 &&
231                      miEventQueue.dropped / QUEUE_DROP_BACKTRACE_FREQUENCY <=
232                      QUEUE_DROP_BACKTRACE_MAX) {
233                 ErrorFSigSafe("[mi] EQ overflow continuing.  %zu events have been "
234                               "dropped.\n", miEventQueue.dropped);
235                 if (miEventQueue.dropped / QUEUE_DROP_BACKTRACE_FREQUENCY ==
236                     QUEUE_DROP_BACKTRACE_MAX) {
237                     ErrorFSigSafe("[mi] No further overflow reports will be "
238                                   "reported until the clog is cleared.\n");
239                 }
240                 xorg_backtrace();
241             }
242             return;
243         }
244         oldtail = miEventQueue.tail;
245     }
246 
247     evlen = e->any.length;
248     evt = miEventQueue.events[oldtail].events;
249     memcpy(evt, e, evlen);
250 
251     time = e->any.time;
252     /* Make sure that event times don't go backwards - this
253      * is "unnecessary", but very useful. */
254     if (time < miEventQueue.lastEventTime &&
255         miEventQueue.lastEventTime - time < 10000)
256         e->any.time = miEventQueue.lastEventTime;
257 
258     miEventQueue.lastEventTime = evt->any.time;
259     miEventQueue.events[oldtail].pScreen = pDev ? EnqueueScreen(pDev) : NULL;
260     miEventQueue.events[oldtail].pDev = pDev;
261 
262     miEventQueue.lastMotion = isMotion;
263     miEventQueue.tail = (oldtail + 1) % miEventQueue.nevents;
264 }
265 
266 /**
267  * Changes the screen reference events are being enqueued from.
268  * Input events are enqueued with a screen reference and dequeued and
269  * processed with a (potentially different) screen reference.
270  * This function is called whenever a new event has changed screen but is
271  * still logically on the previous screen as seen by the client.
272  * This usually happens whenever the visible cursor moves across screen
273  * boundaries during event generation, before the same event is processed
274  * and sent down the wire.
275  *
276  * @param pDev The device that triggered a screen change.
277  * @param pScreen The new screen events are being enqueued for.
278  * @param set_dequeue_screen If TRUE, pScreen is set as both enqueue screen
279  * and dequeue screen.
280  */
281 void
mieqSwitchScreen(DeviceIntPtr pDev,ScreenPtr pScreen,Bool set_dequeue_screen)282 mieqSwitchScreen(DeviceIntPtr pDev, ScreenPtr pScreen, Bool set_dequeue_screen)
283 {
284     EnqueueScreen(pDev) = pScreen;
285     if (set_dequeue_screen)
286         DequeueScreen(pDev) = pScreen;
287 }
288 
289 void
mieqSetHandler(int event,mieqHandler handler)290 mieqSetHandler(int event, mieqHandler handler)
291 {
292     if (handler && miEventQueue.handlers[event])
293         ErrorF("[mi] mieq: warning: overriding existing handler %p with %p for "
294                "event %d\n", miEventQueue.handlers[event], handler, event);
295 
296     miEventQueue.handlers[event] = handler;
297 }
298 
299 /**
300  * Change the device id of the given event to the given device's id.
301  */
302 static void
ChangeDeviceID(DeviceIntPtr dev,InternalEvent * event)303 ChangeDeviceID(DeviceIntPtr dev, InternalEvent *event)
304 {
305     switch (event->any.type) {
306     case ET_Motion:
307     case ET_KeyPress:
308     case ET_KeyRelease:
309     case ET_ButtonPress:
310     case ET_ButtonRelease:
311     case ET_ProximityIn:
312     case ET_ProximityOut:
313     case ET_Hierarchy:
314     case ET_DeviceChanged:
315     case ET_TouchBegin:
316     case ET_TouchUpdate:
317     case ET_TouchEnd:
318         event->device_event.deviceid = dev->id;
319         break;
320     case ET_TouchOwnership:
321         event->touch_ownership_event.deviceid = dev->id;
322         break;
323 #ifdef XFreeXDGA
324     case ET_DGAEvent:
325         break;
326 #endif
327     case ET_RawKeyPress:
328     case ET_RawKeyRelease:
329     case ET_RawButtonPress:
330     case ET_RawButtonRelease:
331     case ET_RawMotion:
332     case ET_RawTouchBegin:
333     case ET_RawTouchEnd:
334     case ET_RawTouchUpdate:
335         event->raw_event.deviceid = dev->id;
336         break;
337     case ET_BarrierHit:
338     case ET_BarrierLeave:
339         event->barrier_event.deviceid = dev->id;
340         break;
341     default:
342         ErrorF("[mi] Unknown event type (%d), cannot change id.\n",
343                event->any.type);
344     }
345 }
346 
347 static void
FixUpEventForMaster(DeviceIntPtr mdev,DeviceIntPtr sdev,InternalEvent * original,InternalEvent * master)348 FixUpEventForMaster(DeviceIntPtr mdev, DeviceIntPtr sdev,
349                     InternalEvent *original, InternalEvent *master)
350 {
351     verify_internal_event(original);
352     verify_internal_event(master);
353     /* Ensure chained button mappings, i.e. that the detail field is the
354      * value of the mapped button on the SD, not the physical button */
355     if (original->any.type == ET_ButtonPress ||
356         original->any.type == ET_ButtonRelease) {
357         int btn = original->device_event.detail.button;
358 
359         if (!sdev->button)
360             return;             /* Should never happen */
361 
362         master->device_event.detail.button = sdev->button->map[btn];
363     }
364 }
365 
366 /**
367  * Copy the given event into master.
368  * @param sdev The slave device the original event comes from
369  * @param original The event as it came from the EQ
370  * @param copy The event after being copied
371  * @return The master device or NULL if the device is a floating slave.
372  */
373 DeviceIntPtr
CopyGetMasterEvent(DeviceIntPtr sdev,InternalEvent * original,InternalEvent * copy)374 CopyGetMasterEvent(DeviceIntPtr sdev,
375                    InternalEvent *original, InternalEvent *copy)
376 {
377     DeviceIntPtr mdev;
378     int len = original->any.length;
379     int type = original->any.type;
380     int mtype;                  /* which master type? */
381 
382     verify_internal_event(original);
383 
384     /* ET_XQuartz has sdev == NULL */
385     if (!sdev || IsMaster(sdev) || IsFloating(sdev))
386         return NULL;
387 
388 #ifdef XFreeXDGA
389     if (type == ET_DGAEvent)
390         type = original->dga_event.subtype;
391 #endif
392 
393     switch (type) {
394     case ET_KeyPress:
395     case ET_KeyRelease:
396         mtype = MASTER_KEYBOARD;
397         break;
398     case ET_ButtonPress:
399     case ET_ButtonRelease:
400     case ET_Motion:
401     case ET_ProximityIn:
402     case ET_ProximityOut:
403         mtype = MASTER_POINTER;
404         break;
405     default:
406         mtype = MASTER_ATTACHED;
407         break;
408     }
409 
410     mdev = GetMaster(sdev, mtype);
411     memcpy(copy, original, len);
412     ChangeDeviceID(mdev, copy);
413     FixUpEventForMaster(mdev, sdev, original, copy);
414 
415     return mdev;
416 }
417 
418 static void
mieqMoveToNewScreen(DeviceIntPtr dev,ScreenPtr screen,DeviceEvent * event)419 mieqMoveToNewScreen(DeviceIntPtr dev, ScreenPtr screen, DeviceEvent *event)
420 {
421     if (dev && screen && screen != DequeueScreen(dev)) {
422         int x = 0, y = 0;
423 
424         DequeueScreen(dev) = screen;
425         x = event->root_x;
426         y = event->root_y;
427         NewCurrentScreen(dev, DequeueScreen(dev), x, y);
428     }
429 }
430 
431 /**
432  * Post the given @event through the device hierarchy, as appropriate.
433  * Use this function if an event must be posted for a given device during the
434  * usual event processing cycle.
435  */
436 void
mieqProcessDeviceEvent(DeviceIntPtr dev,InternalEvent * event,ScreenPtr screen)437 mieqProcessDeviceEvent(DeviceIntPtr dev, InternalEvent *event, ScreenPtr screen)
438 {
439     mieqHandler handler;
440     DeviceIntPtr master;
441     InternalEvent mevent;       /* master event */
442 
443     verify_internal_event(event);
444 
445     /* refuse events from disabled devices */
446     if (dev && !dev->enabled)
447         return;
448 
449     /* Custom event handler */
450     handler = miEventQueue.handlers[event->any.type];
451 
452     switch (event->any.type) {
453         /* Catch events that include valuator information and check if they
454          * are changing the screen */
455     case ET_Motion:
456     case ET_KeyPress:
457     case ET_KeyRelease:
458     case ET_ButtonPress:
459     case ET_ButtonRelease:
460         if (!handler)
461             mieqMoveToNewScreen(dev, screen, &event->device_event);
462         break;
463     case ET_TouchBegin:
464     case ET_TouchUpdate:
465     case ET_TouchEnd:
466         if (!handler && (event->device_event.flags & TOUCH_POINTER_EMULATED))
467             mieqMoveToNewScreen(dev, screen, &event->device_event);
468         break;
469     default:
470         break;
471     }
472     master = CopyGetMasterEvent(dev, event, &mevent);
473 
474     if (master)
475         master->lastSlave = dev;
476 
477     /* If someone's registered a custom event handler, let them
478      * steal it. */
479     if (handler) {
480         int screenNum = dev &&
481             DequeueScreen(dev) ? DequeueScreen(dev)->myNum : (screen ? screen->
482                                                               myNum : 0);
483         handler(screenNum, event, dev);
484         /* Check for the SD's master in case the device got detached
485          * during event processing */
486         if (master && !IsFloating(dev))
487             handler(screenNum, &mevent, master);
488     }
489     else {
490         /* process slave first, then master */
491         dev->public.processInputProc(event, dev);
492 
493         /* Check for the SD's master in case the device got detached
494          * during event processing */
495         if (master && !IsFloating(dev))
496             master->public.processInputProc(&mevent, master);
497     }
498 }
499 
500 /* Call this from ProcessInputEvents(). */
501 void
mieqProcessInputEvents(void)502 mieqProcessInputEvents(void)
503 {
504     EventRec *e = NULL;
505     ScreenPtr screen;
506     InternalEvent event;
507     DeviceIntPtr dev = NULL, master = NULL;
508     static Bool inProcessInputEvents = FALSE;
509 
510     input_lock();
511 
512     /*
513      * report an error if mieqProcessInputEvents() is called recursively;
514      * this can happen, e.g., if something in the mieqProcessDeviceEvent()
515      * call chain calls UpdateCurrentTime() instead of UpdateCurrentTimeIf()
516      */
517     BUG_WARN_MSG(inProcessInputEvents, "[mi] mieqProcessInputEvents() called recursively.\n");
518     inProcessInputEvents = TRUE;
519 
520     if (miEventQueue.dropped) {
521         ErrorF("[mi] EQ processing has resumed after %lu dropped events.\n",
522                (unsigned long) miEventQueue.dropped);
523         ErrorF
524             ("[mi] This may be caused by a misbehaving driver monopolizing the server's resources.\n");
525         miEventQueue.dropped = 0;
526     }
527 
528     while (miEventQueue.head != miEventQueue.tail) {
529         e = &miEventQueue.events[miEventQueue.head];
530 
531         event = *e->events;
532         dev = e->pDev;
533         screen = e->pScreen;
534 
535         miEventQueue.head = (miEventQueue.head + 1) % miEventQueue.nevents;
536 
537         input_unlock();
538 
539         master = (dev) ? GetMaster(dev, MASTER_ATTACHED) : NULL;
540 
541         if (screenIsSaved == SCREEN_SAVER_ON)
542             dixSaveScreens(serverClient, SCREEN_SAVER_OFF, ScreenSaverReset);
543 #ifdef DPMSExtension
544         else if (DPMSPowerLevel != DPMSModeOn)
545             SetScreenSaverTimer();
546 
547         if (DPMSPowerLevel != DPMSModeOn)
548             DPMSSet(serverClient, DPMSModeOn);
549 #endif
550 
551         mieqProcessDeviceEvent(dev, &event, screen);
552 
553         /* Update the sprite now. Next event may be from different device. */
554         if (master &&
555             (event.any.type == ET_Motion ||
556              ((event.any.type == ET_TouchBegin ||
557                event.any.type == ET_TouchUpdate) &&
558               event.device_event.flags & TOUCH_POINTER_EMULATED)))
559             miPointerUpdateSprite(dev);
560 
561         input_lock();
562     }
563 
564     inProcessInputEvents = FALSE;
565 
566     input_unlock();
567 }
568