mieq.c revision ed6184df
105b261ecSmrg/*
205b261ecSmrg *
305b261ecSmrgCopyright 1990, 1998  The Open Group
405b261ecSmrg
505b261ecSmrgPermission to use, copy, modify, distribute, and sell this software and its
605b261ecSmrgdocumentation for any purpose is hereby granted without fee, provided that
705b261ecSmrgthe above copyright notice appear in all copies and that both that
805b261ecSmrgcopyright notice and this permission notice appear in supporting
905b261ecSmrgdocumentation.
1005b261ecSmrg
1105b261ecSmrgThe above copyright notice and this permission notice shall be included in
1205b261ecSmrgall copies or substantial portions of the Software.
1305b261ecSmrg
1405b261ecSmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1505b261ecSmrgIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1605b261ecSmrgFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
1705b261ecSmrgOPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
1805b261ecSmrgAN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
1905b261ecSmrgCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
2005b261ecSmrg
2105b261ecSmrgExcept as contained in this notice, the name of The Open Group shall not be
2205b261ecSmrgused in advertising or otherwise to promote the sale, use or other dealings
2305b261ecSmrgin this Software without prior written authorization from The Open Group.
2405b261ecSmrg *
2505b261ecSmrg * Author:  Keith Packard, MIT X Consortium
2605b261ecSmrg */
2705b261ecSmrg
2805b261ecSmrg/*
2905b261ecSmrg * mieq.c
3005b261ecSmrg *
3105b261ecSmrg * Machine independent event queue
3205b261ecSmrg *
3305b261ecSmrg */
3405b261ecSmrg
3505b261ecSmrg#if HAVE_DIX_CONFIG_H
3605b261ecSmrg#include <dix-config.h>
3705b261ecSmrg#endif
3805b261ecSmrg
3935c4bbdfSmrg#include   <X11/X.h>
4035c4bbdfSmrg#include   <X11/Xmd.h>
4135c4bbdfSmrg#include   <X11/Xproto.h>
4235c4bbdfSmrg#include   "misc.h"
4335c4bbdfSmrg#include   "windowstr.h"
4435c4bbdfSmrg#include   "pixmapstr.h"
4535c4bbdfSmrg#include   "inputstr.h"
4635c4bbdfSmrg#include   "inpututils.h"
4735c4bbdfSmrg#include   "mi.h"
4835c4bbdfSmrg#include   "mipointer.h"
4935c4bbdfSmrg#include   "scrnintstr.h"
5035c4bbdfSmrg#include   <X11/extensions/XI.h>
5135c4bbdfSmrg#include   <X11/extensions/XIproto.h>
5235c4bbdfSmrg#include   <X11/extensions/geproto.h>
5335c4bbdfSmrg#include   "extinit.h"
5435c4bbdfSmrg#include   "exglobals.h"
5535c4bbdfSmrg#include   "eventstr.h"
5605b261ecSmrg
5705b261ecSmrg#ifdef DPMSExtension
5835c4bbdfSmrg#include "dpmsproc.h"
5935c4bbdfSmrg#include <X11/extensions/dpmsconst.h>
6005b261ecSmrg#endif
6105b261ecSmrg
6235c4bbdfSmrg/* Maximum size should be initial size multiplied by a power of 2 */
6335c4bbdfSmrg#define QUEUE_INITIAL_SIZE                 512
6435c4bbdfSmrg#define QUEUE_RESERVED_SIZE                 64
6535c4bbdfSmrg#define QUEUE_MAXIMUM_SIZE                4096
6635c4bbdfSmrg#define QUEUE_DROP_BACKTRACE_FREQUENCY     100
6735c4bbdfSmrg#define QUEUE_DROP_BACKTRACE_MAX            10
6805b261ecSmrg
694642e01fSmrg#define EnqueueScreen(dev) dev->spriteInfo->sprite->pEnqueueScreen
704642e01fSmrg#define DequeueScreen(dev) dev->spriteInfo->sprite->pDequeueScreen
714642e01fSmrg
7205b261ecSmrgtypedef struct _Event {
7335c4bbdfSmrg    InternalEvent *events;
7435c4bbdfSmrg    ScreenPtr pScreen;
7535c4bbdfSmrg    DeviceIntPtr pDev;          /* device this event _originated_ from */
7605b261ecSmrg} EventRec, *EventPtr;
7705b261ecSmrg
7805b261ecSmrgtypedef struct _EventQueue {
7935c4bbdfSmrg    HWEventQueueType head, tail;        /* long for SetInputCheck */
8035c4bbdfSmrg    CARD32 lastEventTime;       /* to avoid time running backwards */
8135c4bbdfSmrg    int lastMotion;             /* device ID if last event motion? */
8235c4bbdfSmrg    EventRec *events;           /* our queue as an array */
8335c4bbdfSmrg    size_t nevents;             /* the number of buckets in our queue */
8435c4bbdfSmrg    size_t dropped;             /* counter for number of consecutive dropped events */
8535c4bbdfSmrg    mieqHandler handlers[128];  /* custom event handler */
8605b261ecSmrg} EventQueueRec, *EventQueuePtr;
8705b261ecSmrg
8805b261ecSmrgstatic EventQueueRec miEventQueue;
894642e01fSmrg
90ed6184dfSmrgstatic CallbackListPtr miCallbacksWhenDrained = NULL;
91ed6184dfSmrg
9235c4bbdfSmrgstatic size_t
9335c4bbdfSmrgmieqNumEnqueued(EventQueuePtr eventQueue)
9435c4bbdfSmrg{
9535c4bbdfSmrg    size_t n_enqueued = 0;
9635c4bbdfSmrg
9735c4bbdfSmrg    if (eventQueue->nevents) {
9835c4bbdfSmrg        /* % is not well-defined with negative numbers... sigh */
9935c4bbdfSmrg        n_enqueued = eventQueue->tail - eventQueue->head + eventQueue->nevents;
10035c4bbdfSmrg        if (n_enqueued >= eventQueue->nevents)
10135c4bbdfSmrg            n_enqueued -= eventQueue->nevents;
10235c4bbdfSmrg    }
10335c4bbdfSmrg    return n_enqueued;
10435c4bbdfSmrg}
10535c4bbdfSmrg
1061b5d61b8Smrg/* Pre-condition: Called with input_lock held */
10735c4bbdfSmrgstatic Bool
10835c4bbdfSmrgmieqGrowQueue(EventQueuePtr eventQueue, size_t new_nevents)
10935c4bbdfSmrg{
11035c4bbdfSmrg    size_t i, n_enqueued, first_hunk;
11135c4bbdfSmrg    EventRec *new_events;
11235c4bbdfSmrg
11335c4bbdfSmrg    if (!eventQueue) {
11435c4bbdfSmrg        ErrorF("[mi] mieqGrowQueue called with a NULL eventQueue\n");
11535c4bbdfSmrg        return FALSE;
11635c4bbdfSmrg    }
11735c4bbdfSmrg
11835c4bbdfSmrg    if (new_nevents <= eventQueue->nevents)
11935c4bbdfSmrg        return FALSE;
12035c4bbdfSmrg
12135c4bbdfSmrg    new_events = calloc(new_nevents, sizeof(EventRec));
12235c4bbdfSmrg    if (new_events == NULL) {
12335c4bbdfSmrg        ErrorF("[mi] mieqGrowQueue memory allocation error.\n");
12435c4bbdfSmrg        return FALSE;
12535c4bbdfSmrg    }
12635c4bbdfSmrg
12735c4bbdfSmrg    n_enqueued = mieqNumEnqueued(eventQueue);
12835c4bbdfSmrg
12935c4bbdfSmrg    /* First copy the existing events */
13035c4bbdfSmrg    first_hunk = eventQueue->nevents - eventQueue->head;
131ed6184dfSmrg    if (eventQueue->events) {
132ed6184dfSmrg        memcpy(new_events,
133ed6184dfSmrg               &eventQueue->events[eventQueue->head],
134ed6184dfSmrg               first_hunk * sizeof(EventRec));
135ed6184dfSmrg        memcpy(&new_events[first_hunk],
136ed6184dfSmrg               eventQueue->events, eventQueue->head * sizeof(EventRec));
137ed6184dfSmrg    }
13835c4bbdfSmrg
13935c4bbdfSmrg    /* Initialize the new portion */
14035c4bbdfSmrg    for (i = eventQueue->nevents; i < new_nevents; i++) {
14135c4bbdfSmrg        InternalEvent *evlist = InitEventList(1);
14235c4bbdfSmrg
14335c4bbdfSmrg        if (!evlist) {
14435c4bbdfSmrg            size_t j;
14535c4bbdfSmrg
14635c4bbdfSmrg            for (j = 0; j < i; j++)
14735c4bbdfSmrg                FreeEventList(new_events[j].events, 1);
14835c4bbdfSmrg            free(new_events);
14935c4bbdfSmrg            return FALSE;
15035c4bbdfSmrg        }
15135c4bbdfSmrg        new_events[i].events = evlist;
15235c4bbdfSmrg    }
15335c4bbdfSmrg
15435c4bbdfSmrg    /* And update our record */
15535c4bbdfSmrg    eventQueue->tail = n_enqueued;
15635c4bbdfSmrg    eventQueue->head = 0;
15735c4bbdfSmrg    eventQueue->nevents = new_nevents;
15835c4bbdfSmrg    free(eventQueue->events);
15935c4bbdfSmrg    eventQueue->events = new_events;
16035c4bbdfSmrg
16135c4bbdfSmrg    return TRUE;
16235c4bbdfSmrg}
16335c4bbdfSmrg
16405b261ecSmrgBool
16505b261ecSmrgmieqInit(void)
16605b261ecSmrg{
16735c4bbdfSmrg    memset(&miEventQueue, 0, sizeof(miEventQueue));
16835c4bbdfSmrg    miEventQueue.lastEventTime = GetTimeInMillis();
16905b261ecSmrg
1701b5d61b8Smrg    input_lock();
17135c4bbdfSmrg    if (!mieqGrowQueue(&miEventQueue, QUEUE_INITIAL_SIZE))
17235c4bbdfSmrg        FatalError("Could not allocate event queue.\n");
1731b5d61b8Smrg    input_unlock();
1744642e01fSmrg
17505b261ecSmrg    SetInputCheck(&miEventQueue.head, &miEventQueue.tail);
17605b261ecSmrg    return TRUE;
17705b261ecSmrg}
17805b261ecSmrg
1794642e01fSmrgvoid
1806747b715SmrgmieqFini(void)
1814642e01fSmrg{
1824642e01fSmrg    int i;
18335c4bbdfSmrg
18435c4bbdfSmrg    for (i = 0; i < miEventQueue.nevents; i++) {
18535c4bbdfSmrg        if (miEventQueue.events[i].events != NULL) {
18635c4bbdfSmrg            FreeEventList(miEventQueue.events[i].events, 1);
18735c4bbdfSmrg            miEventQueue.events[i].events = NULL;
18835c4bbdfSmrg        }
18935c4bbdfSmrg    }
19035c4bbdfSmrg    free(miEventQueue.events);
19135c4bbdfSmrg}
19235c4bbdfSmrg
19305b261ecSmrg/*
19405b261ecSmrg * Must be reentrant with ProcessInputEvents.  Assumption: mieqEnqueue
1951b5d61b8Smrg * will never be interrupted. Must be called with input_lock held
19605b261ecSmrg */
19705b261ecSmrg
19805b261ecSmrgvoid
1996747b715SmrgmieqEnqueue(DeviceIntPtr pDev, InternalEvent *e)
20005b261ecSmrg{
20135c4bbdfSmrg    unsigned int oldtail = miEventQueue.tail;
20235c4bbdfSmrg    InternalEvent *evt;
20335c4bbdfSmrg    int isMotion = 0;
20435c4bbdfSmrg    int evlen;
20535c4bbdfSmrg    Time time;
20635c4bbdfSmrg    size_t n_enqueued;
20705b261ecSmrg
20835c4bbdfSmrg    verify_internal_event(e);
20935c4bbdfSmrg
21035c4bbdfSmrg    n_enqueued = mieqNumEnqueued(&miEventQueue);
2116747b715Smrg
2124642e01fSmrg    /* avoid merging events from different devices */
2136747b715Smrg    if (e->any.type == ET_Motion)
21405b261ecSmrg        isMotion = pDev->id;
21505b261ecSmrg
21605b261ecSmrg    if (isMotion && isMotion == miEventQueue.lastMotion &&
21705b261ecSmrg        oldtail != miEventQueue.head) {
21835c4bbdfSmrg        oldtail = (oldtail - 1) % miEventQueue.nevents;
21905b261ecSmrg    }
2201b5d61b8Smrg    else if (n_enqueued + 1 == miEventQueue.nevents) {
2211b5d61b8Smrg        if (!mieqGrowQueue(&miEventQueue, miEventQueue.nevents << 1)) {
2221b5d61b8Smrg            /* Toss events which come in late.  Usually this means your server's
2231b5d61b8Smrg             * stuck in an infinite loop in the main thread.
2241b5d61b8Smrg             */
2251b5d61b8Smrg            miEventQueue.dropped++;
2261b5d61b8Smrg            if (miEventQueue.dropped == 1) {
2271b5d61b8Smrg                ErrorFSigSafe("[mi] EQ overflowing.  Additional events will be "
2281b5d61b8Smrg                              "discarded until existing events are processed.\n");
2291b5d61b8Smrg                xorg_backtrace();
2301b5d61b8Smrg                ErrorFSigSafe("[mi] These backtraces from mieqEnqueue may point to "
2311b5d61b8Smrg                              "a culprit higher up the stack.\n");
2321b5d61b8Smrg                ErrorFSigSafe("[mi] mieq is *NOT* the cause.  It is a victim.\n");
2331b5d61b8Smrg            }
2341b5d61b8Smrg            else if (miEventQueue.dropped % QUEUE_DROP_BACKTRACE_FREQUENCY == 0 &&
2351b5d61b8Smrg                     miEventQueue.dropped / QUEUE_DROP_BACKTRACE_FREQUENCY <=
2361b5d61b8Smrg                     QUEUE_DROP_BACKTRACE_MAX) {
2371b5d61b8Smrg                ErrorFSigSafe("[mi] EQ overflow continuing.  %zu events have been "
2381b5d61b8Smrg                              "dropped.\n", miEventQueue.dropped);
2391b5d61b8Smrg                if (miEventQueue.dropped / QUEUE_DROP_BACKTRACE_FREQUENCY ==
2401b5d61b8Smrg                    QUEUE_DROP_BACKTRACE_MAX) {
2411b5d61b8Smrg                    ErrorFSigSafe("[mi] No further overflow reports will be "
2421b5d61b8Smrg                                  "reported until the clog is cleared.\n");
2431b5d61b8Smrg                }
2441b5d61b8Smrg                xorg_backtrace();
2456747b715Smrg            }
2461b5d61b8Smrg            return;
24705b261ecSmrg        }
2481b5d61b8Smrg        oldtail = miEventQueue.tail;
24905b261ecSmrg    }
25005b261ecSmrg
25135c4bbdfSmrg    evlen = e->any.length;
25235c4bbdfSmrg    evt = miEventQueue.events[oldtail].events;
25335c4bbdfSmrg    memcpy(evt, e, evlen);
25405b261ecSmrg
2556747b715Smrg    time = e->any.time;
25605b261ecSmrg    /* Make sure that event times don't go backwards - this
25705b261ecSmrg     * is "unnecessary", but very useful. */
2586747b715Smrg    if (time < miEventQueue.lastEventTime &&
2596747b715Smrg        miEventQueue.lastEventTime - time < 10000)
2606747b715Smrg        e->any.time = miEventQueue.lastEventTime;
2614642e01fSmrg
26235c4bbdfSmrg    miEventQueue.lastEventTime = evt->any.time;
2636747b715Smrg    miEventQueue.events[oldtail].pScreen = pDev ? EnqueueScreen(pDev) : NULL;
26405b261ecSmrg    miEventQueue.events[oldtail].pDev = pDev;
26505b261ecSmrg
26605b261ecSmrg    miEventQueue.lastMotion = isMotion;
26735c4bbdfSmrg    miEventQueue.tail = (oldtail + 1) % miEventQueue.nevents;
26805b261ecSmrg}
26905b261ecSmrg
27035c4bbdfSmrg/**
27135c4bbdfSmrg * Changes the screen reference events are being enqueued from.
27235c4bbdfSmrg * Input events are enqueued with a screen reference and dequeued and
27335c4bbdfSmrg * processed with a (potentially different) screen reference.
27435c4bbdfSmrg * This function is called whenever a new event has changed screen but is
27535c4bbdfSmrg * still logically on the previous screen as seen by the client.
27635c4bbdfSmrg * This usually happens whenever the visible cursor moves across screen
27735c4bbdfSmrg * boundaries during event generation, before the same event is processed
27835c4bbdfSmrg * and sent down the wire.
27935c4bbdfSmrg *
28035c4bbdfSmrg * @param pDev The device that triggered a screen change.
28135c4bbdfSmrg * @param pScreen The new screen events are being enqueued for.
28235c4bbdfSmrg * @param set_dequeue_screen If TRUE, pScreen is set as both enqueue screen
28335c4bbdfSmrg * and dequeue screen.
28435c4bbdfSmrg */
28505b261ecSmrgvoid
28635c4bbdfSmrgmieqSwitchScreen(DeviceIntPtr pDev, ScreenPtr pScreen, Bool set_dequeue_screen)
28705b261ecSmrg{
2884642e01fSmrg    EnqueueScreen(pDev) = pScreen;
28935c4bbdfSmrg    if (set_dequeue_screen)
2906747b715Smrg        DequeueScreen(pDev) = pScreen;
29105b261ecSmrg}
29205b261ecSmrg
29305b261ecSmrgvoid
29405b261ecSmrgmieqSetHandler(int event, mieqHandler handler)
29505b261ecSmrg{
296ed6184dfSmrg    if (handler && miEventQueue.handlers[event] != handler)
2974642e01fSmrg        ErrorF("[mi] mieq: warning: overriding existing handler %p with %p for "
29805b261ecSmrg               "event %d\n", miEventQueue.handlers[event], handler, event);
29905b261ecSmrg
30005b261ecSmrg    miEventQueue.handlers[event] = handler;
3014642e01fSmrg}
3024642e01fSmrg
3034642e01fSmrg/**
3044642e01fSmrg * Change the device id of the given event to the given device's id.
3054642e01fSmrg */
3064642e01fSmrgstatic void
30735c4bbdfSmrgChangeDeviceID(DeviceIntPtr dev, InternalEvent *event)
3084642e01fSmrg{
30935c4bbdfSmrg    switch (event->any.type) {
31035c4bbdfSmrg    case ET_Motion:
31135c4bbdfSmrg    case ET_KeyPress:
31235c4bbdfSmrg    case ET_KeyRelease:
31335c4bbdfSmrg    case ET_ButtonPress:
31435c4bbdfSmrg    case ET_ButtonRelease:
31535c4bbdfSmrg    case ET_ProximityIn:
31635c4bbdfSmrg    case ET_ProximityOut:
31735c4bbdfSmrg    case ET_Hierarchy:
31835c4bbdfSmrg    case ET_DeviceChanged:
31935c4bbdfSmrg    case ET_TouchBegin:
32035c4bbdfSmrg    case ET_TouchUpdate:
32135c4bbdfSmrg    case ET_TouchEnd:
32235c4bbdfSmrg        event->device_event.deviceid = dev->id;
32335c4bbdfSmrg        break;
32435c4bbdfSmrg    case ET_TouchOwnership:
32535c4bbdfSmrg        event->touch_ownership_event.deviceid = dev->id;
32635c4bbdfSmrg        break;
3271b5d61b8Smrg#ifdef XFreeXDGA
32835c4bbdfSmrg    case ET_DGAEvent:
32935c4bbdfSmrg        break;
3306747b715Smrg#endif
33135c4bbdfSmrg    case ET_RawKeyPress:
33235c4bbdfSmrg    case ET_RawKeyRelease:
33335c4bbdfSmrg    case ET_RawButtonPress:
33435c4bbdfSmrg    case ET_RawButtonRelease:
33535c4bbdfSmrg    case ET_RawMotion:
33635c4bbdfSmrg    case ET_RawTouchBegin:
33735c4bbdfSmrg    case ET_RawTouchEnd:
33835c4bbdfSmrg    case ET_RawTouchUpdate:
33935c4bbdfSmrg        event->raw_event.deviceid = dev->id;
34035c4bbdfSmrg        break;
34135c4bbdfSmrg    case ET_BarrierHit:
34235c4bbdfSmrg    case ET_BarrierLeave:
34335c4bbdfSmrg        event->barrier_event.deviceid = dev->id;
34435c4bbdfSmrg        break;
345ed6184dfSmrg    case ET_GesturePinchBegin:
346ed6184dfSmrg    case ET_GesturePinchUpdate:
347ed6184dfSmrg    case ET_GesturePinchEnd:
348ed6184dfSmrg    case ET_GestureSwipeBegin:
349ed6184dfSmrg    case ET_GestureSwipeUpdate:
350ed6184dfSmrg    case ET_GestureSwipeEnd:
351ed6184dfSmrg        event->gesture_event.deviceid = dev->id;
352ed6184dfSmrg        break;
35335c4bbdfSmrg    default:
35435c4bbdfSmrg        ErrorF("[mi] Unknown event type (%d), cannot change id.\n",
35535c4bbdfSmrg               event->any.type);
3566747b715Smrg    }
35705b261ecSmrg}
35805b261ecSmrg
3594642e01fSmrgstatic void
3606747b715SmrgFixUpEventForMaster(DeviceIntPtr mdev, DeviceIntPtr sdev,
36135c4bbdfSmrg                    InternalEvent *original, InternalEvent *master)
3624642e01fSmrg{
36335c4bbdfSmrg    verify_internal_event(original);
36435c4bbdfSmrg    verify_internal_event(master);
3654642e01fSmrg    /* Ensure chained button mappings, i.e. that the detail field is the
3664642e01fSmrg     * value of the mapped button on the SD, not the physical button */
3676747b715Smrg    if (original->any.type == ET_ButtonPress ||
36835c4bbdfSmrg        original->any.type == ET_ButtonRelease) {
3696747b715Smrg        int btn = original->device_event.detail.button;
37035c4bbdfSmrg
3714642e01fSmrg        if (!sdev->button)
37235c4bbdfSmrg            return;             /* Should never happen */
3734642e01fSmrg
3746747b715Smrg        master->device_event.detail.button = sdev->button->map[btn];
3754642e01fSmrg    }
3764642e01fSmrg}
3774642e01fSmrg
3784642e01fSmrg/**
3794642e01fSmrg * Copy the given event into master.
3804642e01fSmrg * @param sdev The slave device the original event comes from
3814642e01fSmrg * @param original The event as it came from the EQ
3826747b715Smrg * @param copy The event after being copied
3836747b715Smrg * @return The master device or NULL if the device is a floating slave.
3844642e01fSmrg */
3856747b715SmrgDeviceIntPtr
3866747b715SmrgCopyGetMasterEvent(DeviceIntPtr sdev,
38735c4bbdfSmrg                   InternalEvent *original, InternalEvent *copy)
3884642e01fSmrg{
3896747b715Smrg    DeviceIntPtr mdev;
3906747b715Smrg    int len = original->any.length;
3918223e2f2Smrg    int type = original->any.type;
39235c4bbdfSmrg    int mtype;                  /* which master type? */
3934642e01fSmrg
39435c4bbdfSmrg    verify_internal_event(original);
3954642e01fSmrg
3966747b715Smrg    /* ET_XQuartz has sdev == NULL */
39735c4bbdfSmrg    if (!sdev || IsMaster(sdev) || IsFloating(sdev))
3986747b715Smrg        return NULL;
3994642e01fSmrg
4001b5d61b8Smrg#ifdef XFreeXDGA
4018223e2f2Smrg    if (type == ET_DGAEvent)
4028223e2f2Smrg        type = original->dga_event.subtype;
4038223e2f2Smrg#endif
4048223e2f2Smrg
40535c4bbdfSmrg    switch (type) {
40635c4bbdfSmrg    case ET_KeyPress:
40735c4bbdfSmrg    case ET_KeyRelease:
40835c4bbdfSmrg        mtype = MASTER_KEYBOARD;
40935c4bbdfSmrg        break;
41035c4bbdfSmrg    case ET_ButtonPress:
41135c4bbdfSmrg    case ET_ButtonRelease:
41235c4bbdfSmrg    case ET_Motion:
41335c4bbdfSmrg    case ET_ProximityIn:
41435c4bbdfSmrg    case ET_ProximityOut:
41535c4bbdfSmrg        mtype = MASTER_POINTER;
41635c4bbdfSmrg        break;
41735c4bbdfSmrg    default:
41835c4bbdfSmrg        mtype = MASTER_ATTACHED;
41935c4bbdfSmrg        break;
4204642e01fSmrg    }
4216747b715Smrg
42235c4bbdfSmrg    mdev = GetMaster(sdev, mtype);
4236747b715Smrg    memcpy(copy, original, len);
4246747b715Smrg    ChangeDeviceID(mdev, copy);
4256747b715Smrg    FixUpEventForMaster(mdev, sdev, original, copy);
4266747b715Smrg
4276747b715Smrg    return mdev;
4284642e01fSmrg}
4294642e01fSmrg
43035c4bbdfSmrgstatic void
43135c4bbdfSmrgmieqMoveToNewScreen(DeviceIntPtr dev, ScreenPtr screen, DeviceEvent *event)
43235c4bbdfSmrg{
43335c4bbdfSmrg    if (dev && screen && screen != DequeueScreen(dev)) {
43435c4bbdfSmrg        int x = 0, y = 0;
43535c4bbdfSmrg
43635c4bbdfSmrg        DequeueScreen(dev) = screen;
43735c4bbdfSmrg        x = event->root_x;
43835c4bbdfSmrg        y = event->root_y;
43935c4bbdfSmrg        NewCurrentScreen(dev, DequeueScreen(dev), x, y);
44035c4bbdfSmrg    }
44135c4bbdfSmrg}
4424642e01fSmrg
4436747b715Smrg/**
4446747b715Smrg * Post the given @event through the device hierarchy, as appropriate.
4456747b715Smrg * Use this function if an event must be posted for a given device during the
4466747b715Smrg * usual event processing cycle.
4476747b715Smrg */
4486747b715Smrgvoid
44935c4bbdfSmrgmieqProcessDeviceEvent(DeviceIntPtr dev, InternalEvent *event, ScreenPtr screen)
4506747b715Smrg{
4516747b715Smrg    mieqHandler handler;
4526747b715Smrg    DeviceIntPtr master;
45335c4bbdfSmrg    InternalEvent mevent;       /* master event */
4546747b715Smrg
45535c4bbdfSmrg    verify_internal_event(event);
45635c4bbdfSmrg
45735c4bbdfSmrg    /* refuse events from disabled devices */
45835c4bbdfSmrg    if (dev && !dev->enabled)
45935c4bbdfSmrg        return;
4606747b715Smrg
4616747b715Smrg    /* Custom event handler */
4626747b715Smrg    handler = miEventQueue.handlers[event->any.type];
4636747b715Smrg
4646747b715Smrg    switch (event->any.type) {
4656747b715Smrg        /* Catch events that include valuator information and check if they
4666747b715Smrg         * are changing the screen */
46735c4bbdfSmrg    case ET_Motion:
46835c4bbdfSmrg    case ET_KeyPress:
46935c4bbdfSmrg    case ET_KeyRelease:
47035c4bbdfSmrg    case ET_ButtonPress:
47135c4bbdfSmrg    case ET_ButtonRelease:
47235c4bbdfSmrg        if (!handler)
47335c4bbdfSmrg            mieqMoveToNewScreen(dev, screen, &event->device_event);
47435c4bbdfSmrg        break;
47535c4bbdfSmrg    case ET_TouchBegin:
47635c4bbdfSmrg    case ET_TouchUpdate:
47735c4bbdfSmrg    case ET_TouchEnd:
47835c4bbdfSmrg        if (!handler && (event->device_event.flags & TOUCH_POINTER_EMULATED))
47935c4bbdfSmrg            mieqMoveToNewScreen(dev, screen, &event->device_event);
48035c4bbdfSmrg        break;
48135c4bbdfSmrg    default:
48235c4bbdfSmrg        break;
4836747b715Smrg    }
4846747b715Smrg    master = CopyGetMasterEvent(dev, event, &mevent);
4856747b715Smrg
4866747b715Smrg    if (master)
48735c4bbdfSmrg        master->lastSlave = dev;
4886747b715Smrg
4896747b715Smrg    /* If someone's registered a custom event handler, let them
4906747b715Smrg     * steal it. */
49135c4bbdfSmrg    if (handler) {
49235c4bbdfSmrg        int screenNum = dev &&
49335c4bbdfSmrg            DequeueScreen(dev) ? DequeueScreen(dev)->myNum : (screen ? screen->
49435c4bbdfSmrg                                                              myNum : 0);
4956747b715Smrg        handler(screenNum, event, dev);
4966747b715Smrg        /* Check for the SD's master in case the device got detached
4976747b715Smrg         * during event processing */
49835c4bbdfSmrg        if (master && !IsFloating(dev))
4996747b715Smrg            handler(screenNum, &mevent, master);
50035c4bbdfSmrg    }
50135c4bbdfSmrg    else {
5026747b715Smrg        /* process slave first, then master */
5036747b715Smrg        dev->public.processInputProc(event, dev);
5046747b715Smrg
5056747b715Smrg        /* Check for the SD's master in case the device got detached
5066747b715Smrg         * during event processing */
50735c4bbdfSmrg        if (master && !IsFloating(dev))
5086747b715Smrg            master->public.processInputProc(&mevent, master);
5096747b715Smrg    }
5106747b715Smrg}
5114642e01fSmrg
51205b261ecSmrg/* Call this from ProcessInputEvents(). */
51305b261ecSmrgvoid
51405b261ecSmrgmieqProcessInputEvents(void)
51505b261ecSmrg{
51605b261ecSmrg    EventRec *e = NULL;
5174642e01fSmrg    ScreenPtr screen;
51835c4bbdfSmrg    InternalEvent event;
51935c4bbdfSmrg    DeviceIntPtr dev = NULL, master = NULL;
52035c4bbdfSmrg    static Bool inProcessInputEvents = FALSE;
5214642e01fSmrg
5221b5d61b8Smrg    input_lock();
5234642e01fSmrg
52435c4bbdfSmrg    /*
52535c4bbdfSmrg     * report an error if mieqProcessInputEvents() is called recursively;
52635c4bbdfSmrg     * this can happen, e.g., if something in the mieqProcessDeviceEvent()
52735c4bbdfSmrg     * call chain calls UpdateCurrentTime() instead of UpdateCurrentTimeIf()
52835c4bbdfSmrg     */
52935c4bbdfSmrg    BUG_WARN_MSG(inProcessInputEvents, "[mi] mieqProcessInputEvents() called recursively.\n");
53035c4bbdfSmrg    inProcessInputEvents = TRUE;
53135c4bbdfSmrg
53235c4bbdfSmrg    if (miEventQueue.dropped) {
53335c4bbdfSmrg        ErrorF("[mi] EQ processing has resumed after %lu dropped events.\n",
53435c4bbdfSmrg               (unsigned long) miEventQueue.dropped);
53535c4bbdfSmrg        ErrorF
53635c4bbdfSmrg            ("[mi] This may be caused by a misbehaving driver monopolizing the server's resources.\n");
53735c4bbdfSmrg        miEventQueue.dropped = 0;
53835c4bbdfSmrg    }
5394642e01fSmrg
54035c4bbdfSmrg    while (miEventQueue.head != miEventQueue.tail) {
54135c4bbdfSmrg        e = &miEventQueue.events[miEventQueue.head];
5424642e01fSmrg
54335c4bbdfSmrg        event = *e->events;
54435c4bbdfSmrg        dev = e->pDev;
54535c4bbdfSmrg        screen = e->pScreen;
5464642e01fSmrg
54735c4bbdfSmrg        miEventQueue.head = (miEventQueue.head + 1) % miEventQueue.nevents;
5484642e01fSmrg
5491b5d61b8Smrg        input_unlock();
5506747b715Smrg
55135c4bbdfSmrg        master = (dev) ? GetMaster(dev, MASTER_ATTACHED) : NULL;
5524642e01fSmrg
55305b261ecSmrg        if (screenIsSaved == SCREEN_SAVER_ON)
55435c4bbdfSmrg            dixSaveScreens(serverClient, SCREEN_SAVER_OFF, ScreenSaverReset);
55505b261ecSmrg#ifdef DPMSExtension
55605b261ecSmrg        else if (DPMSPowerLevel != DPMSModeOn)
55705b261ecSmrg            SetScreenSaverTimer();
55805b261ecSmrg
55905b261ecSmrg        if (DPMSPowerLevel != DPMSModeOn)
5604642e01fSmrg            DPMSSet(serverClient, DPMSModeOn);
56105b261ecSmrg#endif
56205b261ecSmrg
56335c4bbdfSmrg        mieqProcessDeviceEvent(dev, &event, screen);
56405b261ecSmrg
5654642e01fSmrg        /* Update the sprite now. Next event may be from different device. */
56635c4bbdfSmrg        if (master &&
56735c4bbdfSmrg            (event.any.type == ET_Motion ||
56835c4bbdfSmrg             ((event.any.type == ET_TouchBegin ||
56935c4bbdfSmrg               event.any.type == ET_TouchUpdate) &&
57035c4bbdfSmrg              event.device_event.flags & TOUCH_POINTER_EMULATED)))
5714642e01fSmrg            miPointerUpdateSprite(dev);
57205b261ecSmrg
5731b5d61b8Smrg        input_lock();
57405b261ecSmrg    }
57535c4bbdfSmrg
57635c4bbdfSmrg    inProcessInputEvents = FALSE;
57735c4bbdfSmrg
578ed6184dfSmrg    CallCallbacks(&miCallbacksWhenDrained, NULL);
579ed6184dfSmrg
580ed6184dfSmrg    input_unlock();
581ed6184dfSmrg}
582ed6184dfSmrg
583ed6184dfSmrgvoid mieqAddCallbackOnDrained(CallbackProcPtr callback, void *param)
584ed6184dfSmrg{
585ed6184dfSmrg    input_lock();
586ed6184dfSmrg    AddCallback(&miCallbacksWhenDrained, callback, param);
587ed6184dfSmrg    input_unlock();
588ed6184dfSmrg}
589ed6184dfSmrg
590ed6184dfSmrgvoid mieqRemoveCallbackOnDrained(CallbackProcPtr callback, void *param)
591ed6184dfSmrg{
592ed6184dfSmrg    input_lock();
593ed6184dfSmrg    DeleteCallback(&miCallbacksWhenDrained, callback, param);
5941b5d61b8Smrg    input_unlock();
59505b261ecSmrg}
596