mieq.c revision 1b5d61b8
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 size_t
91mieqNumEnqueued(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 */
105static Bool
106mieqGrowQueue(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
160Bool
161mieqInit(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
175void
176mieqFini(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
194void
195mieqEnqueue(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 */
281void
282mieqSwitchScreen(DeviceIntPtr pDev, ScreenPtr pScreen, Bool set_dequeue_screen)
283{
284    EnqueueScreen(pDev) = pScreen;
285    if (set_dequeue_screen)
286        DequeueScreen(pDev) = pScreen;
287}
288
289void
290mieqSetHandler(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 */
302static void
303ChangeDeviceID(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
347static void
348FixUpEventForMaster(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 */
373DeviceIntPtr
374CopyGetMasterEvent(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
418static void
419mieqMoveToNewScreen(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 */
436void
437mieqProcessDeviceEvent(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(). */
501void
502mieqProcessInputEvents(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