1/*
2 *
3Copyright 1990, 1998  The Open Group
4
5Permission to use, copy, modify, distribute, and sell this software and its
6documentation for any purpose is hereby granted without fee, provided that
7the above copyright notice appear in all copies and that both that
8copyright notice and this permission notice appear in supporting
9documentation.
10
11The above copyright notice and this permission notice shall be included in
12all copies or substantial portions of the Software.
13
14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
17OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20
21Except as contained in this notice, the name of The Open Group shall not be
22used in advertising or otherwise to promote the sale, use or other dealings
23in 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
72typedef struct _Event {
73    InternalEvent *events;
74    ScreenPtr pScreen;
75    DeviceIntPtr pDev;          /* device this event _originated_ from */
76} EventRec, *EventPtr;
77
78typedef 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
88static EventQueueRec miEventQueue;
89
90static CallbackListPtr miCallbacksWhenDrained = NULL;
91
92static size_t
93mieqNumEnqueued(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 */
107static Bool
108mieqGrowQueue(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
164Bool
165mieqInit(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
179void
180mieqFini(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
198void
199mieqEnqueue(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 */
285void
286mieqSwitchScreen(DeviceIntPtr pDev, ScreenPtr pScreen, Bool set_dequeue_screen)
287{
288    EnqueueScreen(pDev) = pScreen;
289    if (set_dequeue_screen)
290        DequeueScreen(pDev) = pScreen;
291}
292
293void
294mieqSetHandler(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 */
306static void
307ChangeDeviceID(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    case ET_GesturePinchBegin:
346    case ET_GesturePinchUpdate:
347    case ET_GesturePinchEnd:
348    case ET_GestureSwipeBegin:
349    case ET_GestureSwipeUpdate:
350    case ET_GestureSwipeEnd:
351        event->gesture_event.deviceid = dev->id;
352        break;
353    default:
354        ErrorF("[mi] Unknown event type (%d), cannot change id.\n",
355               event->any.type);
356    }
357}
358
359static void
360FixUpEventForMaster(DeviceIntPtr mdev, DeviceIntPtr sdev,
361                    InternalEvent *original, InternalEvent *master)
362{
363    verify_internal_event(original);
364    verify_internal_event(master);
365    /* Ensure chained button mappings, i.e. that the detail field is the
366     * value of the mapped button on the SD, not the physical button */
367    if (original->any.type == ET_ButtonPress ||
368        original->any.type == ET_ButtonRelease) {
369        int btn = original->device_event.detail.button;
370
371        if (!sdev->button)
372            return;             /* Should never happen */
373
374        master->device_event.detail.button = sdev->button->map[btn];
375    }
376}
377
378/**
379 * Copy the given event into master.
380 * @param sdev The slave device the original event comes from
381 * @param original The event as it came from the EQ
382 * @param copy The event after being copied
383 * @return The master device or NULL if the device is a floating slave.
384 */
385DeviceIntPtr
386CopyGetMasterEvent(DeviceIntPtr sdev,
387                   InternalEvent *original, InternalEvent *copy)
388{
389    DeviceIntPtr mdev;
390    int len = original->any.length;
391    int type = original->any.type;
392    int mtype;                  /* which master type? */
393
394    verify_internal_event(original);
395
396    /* ET_XQuartz has sdev == NULL */
397    if (!sdev || IsMaster(sdev) || IsFloating(sdev))
398        return NULL;
399
400#ifdef XFreeXDGA
401    if (type == ET_DGAEvent)
402        type = original->dga_event.subtype;
403#endif
404
405    switch (type) {
406    case ET_KeyPress:
407    case ET_KeyRelease:
408        mtype = MASTER_KEYBOARD;
409        break;
410    case ET_ButtonPress:
411    case ET_ButtonRelease:
412    case ET_Motion:
413    case ET_ProximityIn:
414    case ET_ProximityOut:
415        mtype = MASTER_POINTER;
416        break;
417    default:
418        mtype = MASTER_ATTACHED;
419        break;
420    }
421
422    mdev = GetMaster(sdev, mtype);
423    memcpy(copy, original, len);
424    ChangeDeviceID(mdev, copy);
425    FixUpEventForMaster(mdev, sdev, original, copy);
426
427    return mdev;
428}
429
430static void
431mieqMoveToNewScreen(DeviceIntPtr dev, ScreenPtr screen, DeviceEvent *event)
432{
433    if (dev && screen && screen != DequeueScreen(dev)) {
434        int x = 0, y = 0;
435
436        DequeueScreen(dev) = screen;
437        x = event->root_x;
438        y = event->root_y;
439        NewCurrentScreen(dev, DequeueScreen(dev), x, y);
440    }
441}
442
443/**
444 * Post the given @event through the device hierarchy, as appropriate.
445 * Use this function if an event must be posted for a given device during the
446 * usual event processing cycle.
447 */
448void
449mieqProcessDeviceEvent(DeviceIntPtr dev, InternalEvent *event, ScreenPtr screen)
450{
451    mieqHandler handler;
452    DeviceIntPtr master;
453    InternalEvent mevent;       /* master event */
454
455    verify_internal_event(event);
456
457    /* refuse events from disabled devices */
458    if (dev && !dev->enabled)
459        return;
460
461    /* Custom event handler */
462    handler = miEventQueue.handlers[event->any.type];
463
464    switch (event->any.type) {
465        /* Catch events that include valuator information and check if they
466         * are changing the screen */
467    case ET_Motion:
468    case ET_KeyPress:
469    case ET_KeyRelease:
470    case ET_ButtonPress:
471    case ET_ButtonRelease:
472        if (!handler)
473            mieqMoveToNewScreen(dev, screen, &event->device_event);
474        break;
475    case ET_TouchBegin:
476    case ET_TouchUpdate:
477    case ET_TouchEnd:
478        if (!handler && (event->device_event.flags & TOUCH_POINTER_EMULATED))
479            mieqMoveToNewScreen(dev, screen, &event->device_event);
480        break;
481    default:
482        break;
483    }
484    master = CopyGetMasterEvent(dev, event, &mevent);
485
486    if (master)
487        master->lastSlave = dev;
488
489    /* If someone's registered a custom event handler, let them
490     * steal it. */
491    if (handler) {
492        int screenNum = dev &&
493            DequeueScreen(dev) ? DequeueScreen(dev)->myNum : (screen ? screen->
494                                                              myNum : 0);
495        handler(screenNum, event, dev);
496        /* Check for the SD's master in case the device got detached
497         * during event processing */
498        if (master && !IsFloating(dev))
499            handler(screenNum, &mevent, master);
500    }
501    else {
502        /* process slave first, then master */
503        dev->public.processInputProc(event, dev);
504
505        /* Check for the SD's master in case the device got detached
506         * during event processing */
507        if (master && !IsFloating(dev))
508            master->public.processInputProc(&mevent, master);
509    }
510}
511
512/* Call this from ProcessInputEvents(). */
513void
514mieqProcessInputEvents(void)
515{
516    EventRec *e = NULL;
517    ScreenPtr screen;
518    InternalEvent event;
519    DeviceIntPtr dev = NULL, master = NULL;
520    static Bool inProcessInputEvents = FALSE;
521
522    input_lock();
523
524    /*
525     * report an error if mieqProcessInputEvents() is called recursively;
526     * this can happen, e.g., if something in the mieqProcessDeviceEvent()
527     * call chain calls UpdateCurrentTime() instead of UpdateCurrentTimeIf()
528     */
529    BUG_WARN_MSG(inProcessInputEvents, "[mi] mieqProcessInputEvents() called recursively.\n");
530    inProcessInputEvents = TRUE;
531
532    if (miEventQueue.dropped) {
533        ErrorF("[mi] EQ processing has resumed after %lu dropped events.\n",
534               (unsigned long) miEventQueue.dropped);
535        ErrorF
536            ("[mi] This may be caused by a misbehaving driver monopolizing the server's resources.\n");
537        miEventQueue.dropped = 0;
538    }
539
540    while (miEventQueue.head != miEventQueue.tail) {
541        e = &miEventQueue.events[miEventQueue.head];
542
543        event = *e->events;
544        dev = e->pDev;
545        screen = e->pScreen;
546
547        miEventQueue.head = (miEventQueue.head + 1) % miEventQueue.nevents;
548
549        input_unlock();
550
551        master = (dev) ? GetMaster(dev, MASTER_ATTACHED) : NULL;
552
553        if (screenIsSaved == SCREEN_SAVER_ON)
554            dixSaveScreens(serverClient, SCREEN_SAVER_OFF, ScreenSaverReset);
555#ifdef DPMSExtension
556        else if (DPMSPowerLevel != DPMSModeOn)
557            SetScreenSaverTimer();
558
559        if (DPMSPowerLevel != DPMSModeOn)
560            DPMSSet(serverClient, DPMSModeOn);
561#endif
562
563        mieqProcessDeviceEvent(dev, &event, screen);
564
565        /* Update the sprite now. Next event may be from different device. */
566        if (master &&
567            (event.any.type == ET_Motion ||
568             ((event.any.type == ET_TouchBegin ||
569               event.any.type == ET_TouchUpdate) &&
570              event.device_event.flags & TOUCH_POINTER_EMULATED)))
571            miPointerUpdateSprite(dev);
572
573        input_lock();
574    }
575
576    inProcessInputEvents = FALSE;
577
578    CallCallbacks(&miCallbacksWhenDrained, NULL);
579
580    input_unlock();
581}
582
583void mieqAddCallbackOnDrained(CallbackProcPtr callback, void *param)
584{
585    input_lock();
586    AddCallback(&miCallbacksWhenDrained, callback, param);
587    input_unlock();
588}
589
590void mieqRemoveCallbackOnDrained(CallbackProcPtr callback, void *param)
591{
592    input_lock();
593    DeleteCallback(&miCallbacksWhenDrained, callback, param);
594    input_unlock();
595}
596