mieq.c revision 1b5d61b8
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
9035c4bbdfSmrgstatic size_t
9135c4bbdfSmrgmieqNumEnqueued(EventQueuePtr eventQueue)
9235c4bbdfSmrg{
9335c4bbdfSmrg    size_t n_enqueued = 0;
9435c4bbdfSmrg
9535c4bbdfSmrg    if (eventQueue->nevents) {
9635c4bbdfSmrg        /* % is not well-defined with negative numbers... sigh */
9735c4bbdfSmrg        n_enqueued = eventQueue->tail - eventQueue->head + eventQueue->nevents;
9835c4bbdfSmrg        if (n_enqueued >= eventQueue->nevents)
9935c4bbdfSmrg            n_enqueued -= eventQueue->nevents;
10035c4bbdfSmrg    }
10135c4bbdfSmrg    return n_enqueued;
10235c4bbdfSmrg}
10335c4bbdfSmrg
1041b5d61b8Smrg/* Pre-condition: Called with input_lock held */
10535c4bbdfSmrgstatic Bool
10635c4bbdfSmrgmieqGrowQueue(EventQueuePtr eventQueue, size_t new_nevents)
10735c4bbdfSmrg{
10835c4bbdfSmrg    size_t i, n_enqueued, first_hunk;
10935c4bbdfSmrg    EventRec *new_events;
11035c4bbdfSmrg
11135c4bbdfSmrg    if (!eventQueue) {
11235c4bbdfSmrg        ErrorF("[mi] mieqGrowQueue called with a NULL eventQueue\n");
11335c4bbdfSmrg        return FALSE;
11435c4bbdfSmrg    }
11535c4bbdfSmrg
11635c4bbdfSmrg    if (new_nevents <= eventQueue->nevents)
11735c4bbdfSmrg        return FALSE;
11835c4bbdfSmrg
11935c4bbdfSmrg    new_events = calloc(new_nevents, sizeof(EventRec));
12035c4bbdfSmrg    if (new_events == NULL) {
12135c4bbdfSmrg        ErrorF("[mi] mieqGrowQueue memory allocation error.\n");
12235c4bbdfSmrg        return FALSE;
12335c4bbdfSmrg    }
12435c4bbdfSmrg
12535c4bbdfSmrg    n_enqueued = mieqNumEnqueued(eventQueue);
12635c4bbdfSmrg
12735c4bbdfSmrg    /* First copy the existing events */
12835c4bbdfSmrg    first_hunk = eventQueue->nevents - eventQueue->head;
12935c4bbdfSmrg    memcpy(new_events,
13035c4bbdfSmrg           &eventQueue->events[eventQueue->head],
13135c4bbdfSmrg           first_hunk * sizeof(EventRec));
13235c4bbdfSmrg    memcpy(&new_events[first_hunk],
13335c4bbdfSmrg           eventQueue->events, eventQueue->head * sizeof(EventRec));
13435c4bbdfSmrg
13535c4bbdfSmrg    /* Initialize the new portion */
13635c4bbdfSmrg    for (i = eventQueue->nevents; i < new_nevents; i++) {
13735c4bbdfSmrg        InternalEvent *evlist = InitEventList(1);
13835c4bbdfSmrg
13935c4bbdfSmrg        if (!evlist) {
14035c4bbdfSmrg            size_t j;
14135c4bbdfSmrg
14235c4bbdfSmrg            for (j = 0; j < i; j++)
14335c4bbdfSmrg                FreeEventList(new_events[j].events, 1);
14435c4bbdfSmrg            free(new_events);
14535c4bbdfSmrg            return FALSE;
14635c4bbdfSmrg        }
14735c4bbdfSmrg        new_events[i].events = evlist;
14835c4bbdfSmrg    }
14935c4bbdfSmrg
15035c4bbdfSmrg    /* And update our record */
15135c4bbdfSmrg    eventQueue->tail = n_enqueued;
15235c4bbdfSmrg    eventQueue->head = 0;
15335c4bbdfSmrg    eventQueue->nevents = new_nevents;
15435c4bbdfSmrg    free(eventQueue->events);
15535c4bbdfSmrg    eventQueue->events = new_events;
15635c4bbdfSmrg
15735c4bbdfSmrg    return TRUE;
15835c4bbdfSmrg}
15935c4bbdfSmrg
16005b261ecSmrgBool
16105b261ecSmrgmieqInit(void)
16205b261ecSmrg{
16335c4bbdfSmrg    memset(&miEventQueue, 0, sizeof(miEventQueue));
16435c4bbdfSmrg    miEventQueue.lastEventTime = GetTimeInMillis();
16505b261ecSmrg
1661b5d61b8Smrg    input_lock();
16735c4bbdfSmrg    if (!mieqGrowQueue(&miEventQueue, QUEUE_INITIAL_SIZE))
16835c4bbdfSmrg        FatalError("Could not allocate event queue.\n");
1691b5d61b8Smrg    input_unlock();
1704642e01fSmrg
17105b261ecSmrg    SetInputCheck(&miEventQueue.head, &miEventQueue.tail);
17205b261ecSmrg    return TRUE;
17305b261ecSmrg}
17405b261ecSmrg
1754642e01fSmrgvoid
1766747b715SmrgmieqFini(void)
1774642e01fSmrg{
1784642e01fSmrg    int i;
17935c4bbdfSmrg
18035c4bbdfSmrg    for (i = 0; i < miEventQueue.nevents; i++) {
18135c4bbdfSmrg        if (miEventQueue.events[i].events != NULL) {
18235c4bbdfSmrg            FreeEventList(miEventQueue.events[i].events, 1);
18335c4bbdfSmrg            miEventQueue.events[i].events = NULL;
18435c4bbdfSmrg        }
18535c4bbdfSmrg    }
18635c4bbdfSmrg    free(miEventQueue.events);
18735c4bbdfSmrg}
18835c4bbdfSmrg
18905b261ecSmrg/*
19005b261ecSmrg * Must be reentrant with ProcessInputEvents.  Assumption: mieqEnqueue
1911b5d61b8Smrg * will never be interrupted. Must be called with input_lock held
19205b261ecSmrg */
19305b261ecSmrg
19405b261ecSmrgvoid
1956747b715SmrgmieqEnqueue(DeviceIntPtr pDev, InternalEvent *e)
19605b261ecSmrg{
19735c4bbdfSmrg    unsigned int oldtail = miEventQueue.tail;
19835c4bbdfSmrg    InternalEvent *evt;
19935c4bbdfSmrg    int isMotion = 0;
20035c4bbdfSmrg    int evlen;
20135c4bbdfSmrg    Time time;
20235c4bbdfSmrg    size_t n_enqueued;
20305b261ecSmrg
20435c4bbdfSmrg    verify_internal_event(e);
20535c4bbdfSmrg
20635c4bbdfSmrg    n_enqueued = mieqNumEnqueued(&miEventQueue);
2076747b715Smrg
2084642e01fSmrg    /* avoid merging events from different devices */
2096747b715Smrg    if (e->any.type == ET_Motion)
21005b261ecSmrg        isMotion = pDev->id;
21105b261ecSmrg
21205b261ecSmrg    if (isMotion && isMotion == miEventQueue.lastMotion &&
21305b261ecSmrg        oldtail != miEventQueue.head) {
21435c4bbdfSmrg        oldtail = (oldtail - 1) % miEventQueue.nevents;
21505b261ecSmrg    }
2161b5d61b8Smrg    else if (n_enqueued + 1 == miEventQueue.nevents) {
2171b5d61b8Smrg        if (!mieqGrowQueue(&miEventQueue, miEventQueue.nevents << 1)) {
2181b5d61b8Smrg            /* Toss events which come in late.  Usually this means your server's
2191b5d61b8Smrg             * stuck in an infinite loop in the main thread.
2201b5d61b8Smrg             */
2211b5d61b8Smrg            miEventQueue.dropped++;
2221b5d61b8Smrg            if (miEventQueue.dropped == 1) {
2231b5d61b8Smrg                ErrorFSigSafe("[mi] EQ overflowing.  Additional events will be "
2241b5d61b8Smrg                              "discarded until existing events are processed.\n");
2251b5d61b8Smrg                xorg_backtrace();
2261b5d61b8Smrg                ErrorFSigSafe("[mi] These backtraces from mieqEnqueue may point to "
2271b5d61b8Smrg                              "a culprit higher up the stack.\n");
2281b5d61b8Smrg                ErrorFSigSafe("[mi] mieq is *NOT* the cause.  It is a victim.\n");
2291b5d61b8Smrg            }
2301b5d61b8Smrg            else if (miEventQueue.dropped % QUEUE_DROP_BACKTRACE_FREQUENCY == 0 &&
2311b5d61b8Smrg                     miEventQueue.dropped / QUEUE_DROP_BACKTRACE_FREQUENCY <=
2321b5d61b8Smrg                     QUEUE_DROP_BACKTRACE_MAX) {
2331b5d61b8Smrg                ErrorFSigSafe("[mi] EQ overflow continuing.  %zu events have been "
2341b5d61b8Smrg                              "dropped.\n", miEventQueue.dropped);
2351b5d61b8Smrg                if (miEventQueue.dropped / QUEUE_DROP_BACKTRACE_FREQUENCY ==
2361b5d61b8Smrg                    QUEUE_DROP_BACKTRACE_MAX) {
2371b5d61b8Smrg                    ErrorFSigSafe("[mi] No further overflow reports will be "
2381b5d61b8Smrg                                  "reported until the clog is cleared.\n");
2391b5d61b8Smrg                }
2401b5d61b8Smrg                xorg_backtrace();
2416747b715Smrg            }
2421b5d61b8Smrg            return;
24305b261ecSmrg        }
2441b5d61b8Smrg        oldtail = miEventQueue.tail;
24505b261ecSmrg    }
24605b261ecSmrg
24735c4bbdfSmrg    evlen = e->any.length;
24835c4bbdfSmrg    evt = miEventQueue.events[oldtail].events;
24935c4bbdfSmrg    memcpy(evt, e, evlen);
25005b261ecSmrg
2516747b715Smrg    time = e->any.time;
25205b261ecSmrg    /* Make sure that event times don't go backwards - this
25305b261ecSmrg     * is "unnecessary", but very useful. */
2546747b715Smrg    if (time < miEventQueue.lastEventTime &&
2556747b715Smrg        miEventQueue.lastEventTime - time < 10000)
2566747b715Smrg        e->any.time = miEventQueue.lastEventTime;
2574642e01fSmrg
25835c4bbdfSmrg    miEventQueue.lastEventTime = evt->any.time;
2596747b715Smrg    miEventQueue.events[oldtail].pScreen = pDev ? EnqueueScreen(pDev) : NULL;
26005b261ecSmrg    miEventQueue.events[oldtail].pDev = pDev;
26105b261ecSmrg
26205b261ecSmrg    miEventQueue.lastMotion = isMotion;
26335c4bbdfSmrg    miEventQueue.tail = (oldtail + 1) % miEventQueue.nevents;
26405b261ecSmrg}
26505b261ecSmrg
26635c4bbdfSmrg/**
26735c4bbdfSmrg * Changes the screen reference events are being enqueued from.
26835c4bbdfSmrg * Input events are enqueued with a screen reference and dequeued and
26935c4bbdfSmrg * processed with a (potentially different) screen reference.
27035c4bbdfSmrg * This function is called whenever a new event has changed screen but is
27135c4bbdfSmrg * still logically on the previous screen as seen by the client.
27235c4bbdfSmrg * This usually happens whenever the visible cursor moves across screen
27335c4bbdfSmrg * boundaries during event generation, before the same event is processed
27435c4bbdfSmrg * and sent down the wire.
27535c4bbdfSmrg *
27635c4bbdfSmrg * @param pDev The device that triggered a screen change.
27735c4bbdfSmrg * @param pScreen The new screen events are being enqueued for.
27835c4bbdfSmrg * @param set_dequeue_screen If TRUE, pScreen is set as both enqueue screen
27935c4bbdfSmrg * and dequeue screen.
28035c4bbdfSmrg */
28105b261ecSmrgvoid
28235c4bbdfSmrgmieqSwitchScreen(DeviceIntPtr pDev, ScreenPtr pScreen, Bool set_dequeue_screen)
28305b261ecSmrg{
2844642e01fSmrg    EnqueueScreen(pDev) = pScreen;
28535c4bbdfSmrg    if (set_dequeue_screen)
2866747b715Smrg        DequeueScreen(pDev) = pScreen;
28705b261ecSmrg}
28805b261ecSmrg
28905b261ecSmrgvoid
29005b261ecSmrgmieqSetHandler(int event, mieqHandler handler)
29105b261ecSmrg{
29205b261ecSmrg    if (handler && miEventQueue.handlers[event])
2934642e01fSmrg        ErrorF("[mi] mieq: warning: overriding existing handler %p with %p for "
29405b261ecSmrg               "event %d\n", miEventQueue.handlers[event], handler, event);
29505b261ecSmrg
29605b261ecSmrg    miEventQueue.handlers[event] = handler;
2974642e01fSmrg}
2984642e01fSmrg
2994642e01fSmrg/**
3004642e01fSmrg * Change the device id of the given event to the given device's id.
3014642e01fSmrg */
3024642e01fSmrgstatic void
30335c4bbdfSmrgChangeDeviceID(DeviceIntPtr dev, InternalEvent *event)
3044642e01fSmrg{
30535c4bbdfSmrg    switch (event->any.type) {
30635c4bbdfSmrg    case ET_Motion:
30735c4bbdfSmrg    case ET_KeyPress:
30835c4bbdfSmrg    case ET_KeyRelease:
30935c4bbdfSmrg    case ET_ButtonPress:
31035c4bbdfSmrg    case ET_ButtonRelease:
31135c4bbdfSmrg    case ET_ProximityIn:
31235c4bbdfSmrg    case ET_ProximityOut:
31335c4bbdfSmrg    case ET_Hierarchy:
31435c4bbdfSmrg    case ET_DeviceChanged:
31535c4bbdfSmrg    case ET_TouchBegin:
31635c4bbdfSmrg    case ET_TouchUpdate:
31735c4bbdfSmrg    case ET_TouchEnd:
31835c4bbdfSmrg        event->device_event.deviceid = dev->id;
31935c4bbdfSmrg        break;
32035c4bbdfSmrg    case ET_TouchOwnership:
32135c4bbdfSmrg        event->touch_ownership_event.deviceid = dev->id;
32235c4bbdfSmrg        break;
3231b5d61b8Smrg#ifdef XFreeXDGA
32435c4bbdfSmrg    case ET_DGAEvent:
32535c4bbdfSmrg        break;
3266747b715Smrg#endif
32735c4bbdfSmrg    case ET_RawKeyPress:
32835c4bbdfSmrg    case ET_RawKeyRelease:
32935c4bbdfSmrg    case ET_RawButtonPress:
33035c4bbdfSmrg    case ET_RawButtonRelease:
33135c4bbdfSmrg    case ET_RawMotion:
33235c4bbdfSmrg    case ET_RawTouchBegin:
33335c4bbdfSmrg    case ET_RawTouchEnd:
33435c4bbdfSmrg    case ET_RawTouchUpdate:
33535c4bbdfSmrg        event->raw_event.deviceid = dev->id;
33635c4bbdfSmrg        break;
33735c4bbdfSmrg    case ET_BarrierHit:
33835c4bbdfSmrg    case ET_BarrierLeave:
33935c4bbdfSmrg        event->barrier_event.deviceid = dev->id;
34035c4bbdfSmrg        break;
34135c4bbdfSmrg    default:
34235c4bbdfSmrg        ErrorF("[mi] Unknown event type (%d), cannot change id.\n",
34335c4bbdfSmrg               event->any.type);
3446747b715Smrg    }
34505b261ecSmrg}
34605b261ecSmrg
3474642e01fSmrgstatic void
3486747b715SmrgFixUpEventForMaster(DeviceIntPtr mdev, DeviceIntPtr sdev,
34935c4bbdfSmrg                    InternalEvent *original, InternalEvent *master)
3504642e01fSmrg{
35135c4bbdfSmrg    verify_internal_event(original);
35235c4bbdfSmrg    verify_internal_event(master);
3534642e01fSmrg    /* Ensure chained button mappings, i.e. that the detail field is the
3544642e01fSmrg     * value of the mapped button on the SD, not the physical button */
3556747b715Smrg    if (original->any.type == ET_ButtonPress ||
35635c4bbdfSmrg        original->any.type == ET_ButtonRelease) {
3576747b715Smrg        int btn = original->device_event.detail.button;
35835c4bbdfSmrg
3594642e01fSmrg        if (!sdev->button)
36035c4bbdfSmrg            return;             /* Should never happen */
3614642e01fSmrg
3626747b715Smrg        master->device_event.detail.button = sdev->button->map[btn];
3634642e01fSmrg    }
3644642e01fSmrg}
3654642e01fSmrg
3664642e01fSmrg/**
3674642e01fSmrg * Copy the given event into master.
3684642e01fSmrg * @param sdev The slave device the original event comes from
3694642e01fSmrg * @param original The event as it came from the EQ
3706747b715Smrg * @param copy The event after being copied
3716747b715Smrg * @return The master device or NULL if the device is a floating slave.
3724642e01fSmrg */
3736747b715SmrgDeviceIntPtr
3746747b715SmrgCopyGetMasterEvent(DeviceIntPtr sdev,
37535c4bbdfSmrg                   InternalEvent *original, InternalEvent *copy)
3764642e01fSmrg{
3776747b715Smrg    DeviceIntPtr mdev;
3786747b715Smrg    int len = original->any.length;
3798223e2f2Smrg    int type = original->any.type;
38035c4bbdfSmrg    int mtype;                  /* which master type? */
3814642e01fSmrg
38235c4bbdfSmrg    verify_internal_event(original);
3834642e01fSmrg
3846747b715Smrg    /* ET_XQuartz has sdev == NULL */
38535c4bbdfSmrg    if (!sdev || IsMaster(sdev) || IsFloating(sdev))
3866747b715Smrg        return NULL;
3874642e01fSmrg
3881b5d61b8Smrg#ifdef XFreeXDGA
3898223e2f2Smrg    if (type == ET_DGAEvent)
3908223e2f2Smrg        type = original->dga_event.subtype;
3918223e2f2Smrg#endif
3928223e2f2Smrg
39335c4bbdfSmrg    switch (type) {
39435c4bbdfSmrg    case ET_KeyPress:
39535c4bbdfSmrg    case ET_KeyRelease:
39635c4bbdfSmrg        mtype = MASTER_KEYBOARD;
39735c4bbdfSmrg        break;
39835c4bbdfSmrg    case ET_ButtonPress:
39935c4bbdfSmrg    case ET_ButtonRelease:
40035c4bbdfSmrg    case ET_Motion:
40135c4bbdfSmrg    case ET_ProximityIn:
40235c4bbdfSmrg    case ET_ProximityOut:
40335c4bbdfSmrg        mtype = MASTER_POINTER;
40435c4bbdfSmrg        break;
40535c4bbdfSmrg    default:
40635c4bbdfSmrg        mtype = MASTER_ATTACHED;
40735c4bbdfSmrg        break;
4084642e01fSmrg    }
4096747b715Smrg
41035c4bbdfSmrg    mdev = GetMaster(sdev, mtype);
4116747b715Smrg    memcpy(copy, original, len);
4126747b715Smrg    ChangeDeviceID(mdev, copy);
4136747b715Smrg    FixUpEventForMaster(mdev, sdev, original, copy);
4146747b715Smrg
4156747b715Smrg    return mdev;
4164642e01fSmrg}
4174642e01fSmrg
41835c4bbdfSmrgstatic void
41935c4bbdfSmrgmieqMoveToNewScreen(DeviceIntPtr dev, ScreenPtr screen, DeviceEvent *event)
42035c4bbdfSmrg{
42135c4bbdfSmrg    if (dev && screen && screen != DequeueScreen(dev)) {
42235c4bbdfSmrg        int x = 0, y = 0;
42335c4bbdfSmrg
42435c4bbdfSmrg        DequeueScreen(dev) = screen;
42535c4bbdfSmrg        x = event->root_x;
42635c4bbdfSmrg        y = event->root_y;
42735c4bbdfSmrg        NewCurrentScreen(dev, DequeueScreen(dev), x, y);
42835c4bbdfSmrg    }
42935c4bbdfSmrg}
4304642e01fSmrg
4316747b715Smrg/**
4326747b715Smrg * Post the given @event through the device hierarchy, as appropriate.
4336747b715Smrg * Use this function if an event must be posted for a given device during the
4346747b715Smrg * usual event processing cycle.
4356747b715Smrg */
4366747b715Smrgvoid
43735c4bbdfSmrgmieqProcessDeviceEvent(DeviceIntPtr dev, InternalEvent *event, ScreenPtr screen)
4386747b715Smrg{
4396747b715Smrg    mieqHandler handler;
4406747b715Smrg    DeviceIntPtr master;
44135c4bbdfSmrg    InternalEvent mevent;       /* master event */
4426747b715Smrg
44335c4bbdfSmrg    verify_internal_event(event);
44435c4bbdfSmrg
44535c4bbdfSmrg    /* refuse events from disabled devices */
44635c4bbdfSmrg    if (dev && !dev->enabled)
44735c4bbdfSmrg        return;
4486747b715Smrg
4496747b715Smrg    /* Custom event handler */
4506747b715Smrg    handler = miEventQueue.handlers[event->any.type];
4516747b715Smrg
4526747b715Smrg    switch (event->any.type) {
4536747b715Smrg        /* Catch events that include valuator information and check if they
4546747b715Smrg         * are changing the screen */
45535c4bbdfSmrg    case ET_Motion:
45635c4bbdfSmrg    case ET_KeyPress:
45735c4bbdfSmrg    case ET_KeyRelease:
45835c4bbdfSmrg    case ET_ButtonPress:
45935c4bbdfSmrg    case ET_ButtonRelease:
46035c4bbdfSmrg        if (!handler)
46135c4bbdfSmrg            mieqMoveToNewScreen(dev, screen, &event->device_event);
46235c4bbdfSmrg        break;
46335c4bbdfSmrg    case ET_TouchBegin:
46435c4bbdfSmrg    case ET_TouchUpdate:
46535c4bbdfSmrg    case ET_TouchEnd:
46635c4bbdfSmrg        if (!handler && (event->device_event.flags & TOUCH_POINTER_EMULATED))
46735c4bbdfSmrg            mieqMoveToNewScreen(dev, screen, &event->device_event);
46835c4bbdfSmrg        break;
46935c4bbdfSmrg    default:
47035c4bbdfSmrg        break;
4716747b715Smrg    }
4726747b715Smrg    master = CopyGetMasterEvent(dev, event, &mevent);
4736747b715Smrg
4746747b715Smrg    if (master)
47535c4bbdfSmrg        master->lastSlave = dev;
4766747b715Smrg
4776747b715Smrg    /* If someone's registered a custom event handler, let them
4786747b715Smrg     * steal it. */
47935c4bbdfSmrg    if (handler) {
48035c4bbdfSmrg        int screenNum = dev &&
48135c4bbdfSmrg            DequeueScreen(dev) ? DequeueScreen(dev)->myNum : (screen ? screen->
48235c4bbdfSmrg                                                              myNum : 0);
4836747b715Smrg        handler(screenNum, event, dev);
4846747b715Smrg        /* Check for the SD's master in case the device got detached
4856747b715Smrg         * during event processing */
48635c4bbdfSmrg        if (master && !IsFloating(dev))
4876747b715Smrg            handler(screenNum, &mevent, master);
48835c4bbdfSmrg    }
48935c4bbdfSmrg    else {
4906747b715Smrg        /* process slave first, then master */
4916747b715Smrg        dev->public.processInputProc(event, dev);
4926747b715Smrg
4936747b715Smrg        /* Check for the SD's master in case the device got detached
4946747b715Smrg         * during event processing */
49535c4bbdfSmrg        if (master && !IsFloating(dev))
4966747b715Smrg            master->public.processInputProc(&mevent, master);
4976747b715Smrg    }
4986747b715Smrg}
4994642e01fSmrg
50005b261ecSmrg/* Call this from ProcessInputEvents(). */
50105b261ecSmrgvoid
50205b261ecSmrgmieqProcessInputEvents(void)
50305b261ecSmrg{
50405b261ecSmrg    EventRec *e = NULL;
5054642e01fSmrg    ScreenPtr screen;
50635c4bbdfSmrg    InternalEvent event;
50735c4bbdfSmrg    DeviceIntPtr dev = NULL, master = NULL;
50835c4bbdfSmrg    static Bool inProcessInputEvents = FALSE;
5094642e01fSmrg
5101b5d61b8Smrg    input_lock();
5114642e01fSmrg
51235c4bbdfSmrg    /*
51335c4bbdfSmrg     * report an error if mieqProcessInputEvents() is called recursively;
51435c4bbdfSmrg     * this can happen, e.g., if something in the mieqProcessDeviceEvent()
51535c4bbdfSmrg     * call chain calls UpdateCurrentTime() instead of UpdateCurrentTimeIf()
51635c4bbdfSmrg     */
51735c4bbdfSmrg    BUG_WARN_MSG(inProcessInputEvents, "[mi] mieqProcessInputEvents() called recursively.\n");
51835c4bbdfSmrg    inProcessInputEvents = TRUE;
51935c4bbdfSmrg
52035c4bbdfSmrg    if (miEventQueue.dropped) {
52135c4bbdfSmrg        ErrorF("[mi] EQ processing has resumed after %lu dropped events.\n",
52235c4bbdfSmrg               (unsigned long) miEventQueue.dropped);
52335c4bbdfSmrg        ErrorF
52435c4bbdfSmrg            ("[mi] This may be caused by a misbehaving driver monopolizing the server's resources.\n");
52535c4bbdfSmrg        miEventQueue.dropped = 0;
52635c4bbdfSmrg    }
5274642e01fSmrg
52835c4bbdfSmrg    while (miEventQueue.head != miEventQueue.tail) {
52935c4bbdfSmrg        e = &miEventQueue.events[miEventQueue.head];
5304642e01fSmrg
53135c4bbdfSmrg        event = *e->events;
53235c4bbdfSmrg        dev = e->pDev;
53335c4bbdfSmrg        screen = e->pScreen;
5344642e01fSmrg
53535c4bbdfSmrg        miEventQueue.head = (miEventQueue.head + 1) % miEventQueue.nevents;
5364642e01fSmrg
5371b5d61b8Smrg        input_unlock();
5386747b715Smrg
53935c4bbdfSmrg        master = (dev) ? GetMaster(dev, MASTER_ATTACHED) : NULL;
5404642e01fSmrg
54105b261ecSmrg        if (screenIsSaved == SCREEN_SAVER_ON)
54235c4bbdfSmrg            dixSaveScreens(serverClient, SCREEN_SAVER_OFF, ScreenSaverReset);
54305b261ecSmrg#ifdef DPMSExtension
54405b261ecSmrg        else if (DPMSPowerLevel != DPMSModeOn)
54505b261ecSmrg            SetScreenSaverTimer();
54605b261ecSmrg
54705b261ecSmrg        if (DPMSPowerLevel != DPMSModeOn)
5484642e01fSmrg            DPMSSet(serverClient, DPMSModeOn);
54905b261ecSmrg#endif
55005b261ecSmrg
55135c4bbdfSmrg        mieqProcessDeviceEvent(dev, &event, screen);
55205b261ecSmrg
5534642e01fSmrg        /* Update the sprite now. Next event may be from different device. */
55435c4bbdfSmrg        if (master &&
55535c4bbdfSmrg            (event.any.type == ET_Motion ||
55635c4bbdfSmrg             ((event.any.type == ET_TouchBegin ||
55735c4bbdfSmrg               event.any.type == ET_TouchUpdate) &&
55835c4bbdfSmrg              event.device_event.flags & TOUCH_POINTER_EMULATED)))
5594642e01fSmrg            miPointerUpdateSprite(dev);
56005b261ecSmrg
5611b5d61b8Smrg        input_lock();
56205b261ecSmrg    }
56335c4bbdfSmrg
56435c4bbdfSmrg    inProcessInputEvents = FALSE;
56535c4bbdfSmrg
5661b5d61b8Smrg    input_unlock();
56705b261ecSmrg}
568