mieq.c revision 35c4bbdf
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
904642e01fSmrg#ifdef XQUARTZ
914642e01fSmrg#include  <pthread.h>
924642e01fSmrgstatic pthread_mutex_t miEventQueueMutex = PTHREAD_MUTEX_INITIALIZER;
934642e01fSmrg
949ace9065Smrgextern BOOL serverRunning;
959ace9065Smrgextern pthread_mutex_t serverRunningMutex;
969ace9065Smrgextern pthread_cond_t serverRunningCond;
974642e01fSmrg
9835c4bbdfSmrgstatic inline void
9935c4bbdfSmrgwait_for_server_init(void)
10035c4bbdfSmrg{
1014642e01fSmrg    /* If the server hasn't finished initializing, wait for it... */
10235c4bbdfSmrg    if (!serverRunning) {
1039ace9065Smrg        pthread_mutex_lock(&serverRunningMutex);
10435c4bbdfSmrg        while (!serverRunning)
1059ace9065Smrg            pthread_cond_wait(&serverRunningCond, &serverRunningMutex);
1069ace9065Smrg        pthread_mutex_unlock(&serverRunningMutex);
1074642e01fSmrg    }
1084642e01fSmrg}
1094642e01fSmrg#endif
11005b261ecSmrg
11135c4bbdfSmrgstatic size_t
11235c4bbdfSmrgmieqNumEnqueued(EventQueuePtr eventQueue)
11335c4bbdfSmrg{
11435c4bbdfSmrg    size_t n_enqueued = 0;
11535c4bbdfSmrg
11635c4bbdfSmrg    if (eventQueue->nevents) {
11735c4bbdfSmrg        /* % is not well-defined with negative numbers... sigh */
11835c4bbdfSmrg        n_enqueued = eventQueue->tail - eventQueue->head + eventQueue->nevents;
11935c4bbdfSmrg        if (n_enqueued >= eventQueue->nevents)
12035c4bbdfSmrg            n_enqueued -= eventQueue->nevents;
12135c4bbdfSmrg    }
12235c4bbdfSmrg    return n_enqueued;
12335c4bbdfSmrg}
12435c4bbdfSmrg
12535c4bbdfSmrg/* Pre-condition: Called with miEventQueueMutex held */
12635c4bbdfSmrgstatic Bool
12735c4bbdfSmrgmieqGrowQueue(EventQueuePtr eventQueue, size_t new_nevents)
12835c4bbdfSmrg{
12935c4bbdfSmrg    size_t i, n_enqueued, first_hunk;
13035c4bbdfSmrg    EventRec *new_events;
13135c4bbdfSmrg
13235c4bbdfSmrg    if (!eventQueue) {
13335c4bbdfSmrg        ErrorF("[mi] mieqGrowQueue called with a NULL eventQueue\n");
13435c4bbdfSmrg        return FALSE;
13535c4bbdfSmrg    }
13635c4bbdfSmrg
13735c4bbdfSmrg    if (new_nevents <= eventQueue->nevents)
13835c4bbdfSmrg        return FALSE;
13935c4bbdfSmrg
14035c4bbdfSmrg    new_events = calloc(new_nevents, sizeof(EventRec));
14135c4bbdfSmrg    if (new_events == NULL) {
14235c4bbdfSmrg        ErrorF("[mi] mieqGrowQueue memory allocation error.\n");
14335c4bbdfSmrg        return FALSE;
14435c4bbdfSmrg    }
14535c4bbdfSmrg
14635c4bbdfSmrg    n_enqueued = mieqNumEnqueued(eventQueue);
14735c4bbdfSmrg
14835c4bbdfSmrg    /* We block signals, so an mieqEnqueue triggered by SIGIO does not
14935c4bbdfSmrg     * write to our queue as we are modifying it.
15035c4bbdfSmrg     */
15135c4bbdfSmrg    OsBlockSignals();
15235c4bbdfSmrg
15335c4bbdfSmrg    /* First copy the existing events */
15435c4bbdfSmrg    first_hunk = eventQueue->nevents - eventQueue->head;
15535c4bbdfSmrg    memcpy(new_events,
15635c4bbdfSmrg           &eventQueue->events[eventQueue->head],
15735c4bbdfSmrg           first_hunk * sizeof(EventRec));
15835c4bbdfSmrg    memcpy(&new_events[first_hunk],
15935c4bbdfSmrg           eventQueue->events, eventQueue->head * sizeof(EventRec));
16035c4bbdfSmrg
16135c4bbdfSmrg    /* Initialize the new portion */
16235c4bbdfSmrg    for (i = eventQueue->nevents; i < new_nevents; i++) {
16335c4bbdfSmrg        InternalEvent *evlist = InitEventList(1);
16435c4bbdfSmrg
16535c4bbdfSmrg        if (!evlist) {
16635c4bbdfSmrg            size_t j;
16735c4bbdfSmrg
16835c4bbdfSmrg            for (j = 0; j < i; j++)
16935c4bbdfSmrg                FreeEventList(new_events[j].events, 1);
17035c4bbdfSmrg            free(new_events);
17135c4bbdfSmrg            OsReleaseSignals();
17235c4bbdfSmrg            return FALSE;
17335c4bbdfSmrg        }
17435c4bbdfSmrg        new_events[i].events = evlist;
17535c4bbdfSmrg    }
17635c4bbdfSmrg
17735c4bbdfSmrg    /* And update our record */
17835c4bbdfSmrg    eventQueue->tail = n_enqueued;
17935c4bbdfSmrg    eventQueue->head = 0;
18035c4bbdfSmrg    eventQueue->nevents = new_nevents;
18135c4bbdfSmrg    free(eventQueue->events);
18235c4bbdfSmrg    eventQueue->events = new_events;
18335c4bbdfSmrg
18435c4bbdfSmrg    OsReleaseSignals();
18535c4bbdfSmrg    return TRUE;
18635c4bbdfSmrg}
18735c4bbdfSmrg
18805b261ecSmrgBool
18905b261ecSmrgmieqInit(void)
19005b261ecSmrg{
19135c4bbdfSmrg    memset(&miEventQueue, 0, sizeof(miEventQueue));
19235c4bbdfSmrg    miEventQueue.lastEventTime = GetTimeInMillis();
19305b261ecSmrg
19435c4bbdfSmrg    if (!mieqGrowQueue(&miEventQueue, QUEUE_INITIAL_SIZE))
19535c4bbdfSmrg        FatalError("Could not allocate event queue.\n");
1964642e01fSmrg
19705b261ecSmrg    SetInputCheck(&miEventQueue.head, &miEventQueue.tail);
19805b261ecSmrg    return TRUE;
19905b261ecSmrg}
20005b261ecSmrg
2014642e01fSmrgvoid
2026747b715SmrgmieqFini(void)
2034642e01fSmrg{
2044642e01fSmrg    int i;
20535c4bbdfSmrg
20635c4bbdfSmrg    for (i = 0; i < miEventQueue.nevents; i++) {
20735c4bbdfSmrg        if (miEventQueue.events[i].events != NULL) {
20835c4bbdfSmrg            FreeEventList(miEventQueue.events[i].events, 1);
20935c4bbdfSmrg            miEventQueue.events[i].events = NULL;
21035c4bbdfSmrg        }
21135c4bbdfSmrg    }
21235c4bbdfSmrg    free(miEventQueue.events);
21335c4bbdfSmrg}
21435c4bbdfSmrg
21535c4bbdfSmrg/* This function will determine if the given event is allowed to used the reserved
21635c4bbdfSmrg * queue space.
21735c4bbdfSmrg */
21835c4bbdfSmrgstatic Bool
21935c4bbdfSmrgmieqReservedCandidate(InternalEvent *e)
22035c4bbdfSmrg{
22135c4bbdfSmrg    switch (e->any.type) {
22235c4bbdfSmrg    case ET_KeyRelease:
22335c4bbdfSmrg    case ET_ButtonRelease:
22435c4bbdfSmrg#if XFreeXDGA
22535c4bbdfSmrg    case ET_DGAEvent:
22635c4bbdfSmrg#endif
22735c4bbdfSmrg    case ET_RawKeyRelease:
22835c4bbdfSmrg    case ET_RawButtonRelease:
22935c4bbdfSmrg    case ET_XQuartz:
23035c4bbdfSmrg        return TRUE;
23135c4bbdfSmrg    default:
23235c4bbdfSmrg        return FALSE;
2336747b715Smrg    }
2344642e01fSmrg}
2354642e01fSmrg
23605b261ecSmrg/*
23705b261ecSmrg * Must be reentrant with ProcessInputEvents.  Assumption: mieqEnqueue
23805b261ecSmrg * will never be interrupted.  If this is called from both signal
23905b261ecSmrg * handlers and regular code, make sure the signal is suspended when
24005b261ecSmrg * called from regular code.
24105b261ecSmrg */
24205b261ecSmrg
24305b261ecSmrgvoid
2446747b715SmrgmieqEnqueue(DeviceIntPtr pDev, InternalEvent *e)
24505b261ecSmrg{
24635c4bbdfSmrg    unsigned int oldtail = miEventQueue.tail;
24735c4bbdfSmrg    InternalEvent *evt;
24835c4bbdfSmrg    int isMotion = 0;
24935c4bbdfSmrg    int evlen;
25035c4bbdfSmrg    Time time;
25135c4bbdfSmrg    size_t n_enqueued;
25205b261ecSmrg
2534642e01fSmrg#ifdef XQUARTZ
2544642e01fSmrg    wait_for_server_init();
2554642e01fSmrg    pthread_mutex_lock(&miEventQueueMutex);
2564642e01fSmrg#endif
2574642e01fSmrg
25835c4bbdfSmrg    verify_internal_event(e);
25935c4bbdfSmrg
26035c4bbdfSmrg    n_enqueued = mieqNumEnqueued(&miEventQueue);
2616747b715Smrg
2624642e01fSmrg    /* avoid merging events from different devices */
2636747b715Smrg    if (e->any.type == ET_Motion)
26405b261ecSmrg        isMotion = pDev->id;
26505b261ecSmrg
26605b261ecSmrg    if (isMotion && isMotion == miEventQueue.lastMotion &&
26705b261ecSmrg        oldtail != miEventQueue.head) {
26835c4bbdfSmrg        oldtail = (oldtail - 1) % miEventQueue.nevents;
26905b261ecSmrg    }
27035c4bbdfSmrg    else if ((n_enqueued + 1 == miEventQueue.nevents) ||
27135c4bbdfSmrg             ((n_enqueued + 1 >= miEventQueue.nevents - QUEUE_RESERVED_SIZE) &&
27235c4bbdfSmrg              !mieqReservedCandidate(e))) {
2736747b715Smrg        /* Toss events which come in late.  Usually this means your server's
27405b261ecSmrg         * stuck in an infinite loop somewhere, but SIGIO is still getting
27535c4bbdfSmrg         * handled.
27635c4bbdfSmrg         */
27735c4bbdfSmrg        miEventQueue.dropped++;
27835c4bbdfSmrg        if (miEventQueue.dropped == 1) {
27935c4bbdfSmrg            ErrorFSigSafe("[mi] EQ overflowing.  Additional events will be "
28035c4bbdfSmrg                         "discarded until existing events are processed.\n");
28135c4bbdfSmrg            xorg_backtrace();
28235c4bbdfSmrg            ErrorFSigSafe("[mi] These backtraces from mieqEnqueue may point to "
28335c4bbdfSmrg                         "a culprit higher up the stack.\n");
28435c4bbdfSmrg            ErrorFSigSafe("[mi] mieq is *NOT* the cause.  It is a victim.\n");
28535c4bbdfSmrg        }
28635c4bbdfSmrg        else if (miEventQueue.dropped % QUEUE_DROP_BACKTRACE_FREQUENCY == 0 &&
28735c4bbdfSmrg                 miEventQueue.dropped / QUEUE_DROP_BACKTRACE_FREQUENCY <=
28835c4bbdfSmrg                 QUEUE_DROP_BACKTRACE_MAX) {
28935c4bbdfSmrg            ErrorFSigSafe("[mi] EQ overflow continuing.  %zu events have been "
29035c4bbdfSmrg                         "dropped.\n", miEventQueue.dropped);
29135c4bbdfSmrg            if (miEventQueue.dropped / QUEUE_DROP_BACKTRACE_FREQUENCY ==
29235c4bbdfSmrg                QUEUE_DROP_BACKTRACE_MAX) {
29335c4bbdfSmrg                ErrorFSigSafe("[mi] No further overflow reports will be "
29435c4bbdfSmrg                             "reported until the clog is cleared.\n");
2956747b715Smrg            }
29635c4bbdfSmrg            xorg_backtrace();
29705b261ecSmrg        }
2984642e01fSmrg
2994642e01fSmrg#ifdef XQUARTZ
30035c4bbdfSmrg        pthread_mutex_unlock(&miEventQueueMutex);
3014642e01fSmrg#endif
30235c4bbdfSmrg        return;
30305b261ecSmrg    }
30405b261ecSmrg
30535c4bbdfSmrg    evlen = e->any.length;
30635c4bbdfSmrg    evt = miEventQueue.events[oldtail].events;
30735c4bbdfSmrg    memcpy(evt, e, evlen);
30805b261ecSmrg
3096747b715Smrg    time = e->any.time;
31005b261ecSmrg    /* Make sure that event times don't go backwards - this
31105b261ecSmrg     * is "unnecessary", but very useful. */
3126747b715Smrg    if (time < miEventQueue.lastEventTime &&
3136747b715Smrg        miEventQueue.lastEventTime - time < 10000)
3146747b715Smrg        e->any.time = miEventQueue.lastEventTime;
3154642e01fSmrg
31635c4bbdfSmrg    miEventQueue.lastEventTime = evt->any.time;
3176747b715Smrg    miEventQueue.events[oldtail].pScreen = pDev ? EnqueueScreen(pDev) : NULL;
31805b261ecSmrg    miEventQueue.events[oldtail].pDev = pDev;
31905b261ecSmrg
32005b261ecSmrg    miEventQueue.lastMotion = isMotion;
32135c4bbdfSmrg    miEventQueue.tail = (oldtail + 1) % miEventQueue.nevents;
3224642e01fSmrg#ifdef XQUARTZ
3234642e01fSmrg    pthread_mutex_unlock(&miEventQueueMutex);
3244642e01fSmrg#endif
32505b261ecSmrg}
32605b261ecSmrg
32735c4bbdfSmrg/**
32835c4bbdfSmrg * Changes the screen reference events are being enqueued from.
32935c4bbdfSmrg * Input events are enqueued with a screen reference and dequeued and
33035c4bbdfSmrg * processed with a (potentially different) screen reference.
33135c4bbdfSmrg * This function is called whenever a new event has changed screen but is
33235c4bbdfSmrg * still logically on the previous screen as seen by the client.
33335c4bbdfSmrg * This usually happens whenever the visible cursor moves across screen
33435c4bbdfSmrg * boundaries during event generation, before the same event is processed
33535c4bbdfSmrg * and sent down the wire.
33635c4bbdfSmrg *
33735c4bbdfSmrg * @param pDev The device that triggered a screen change.
33835c4bbdfSmrg * @param pScreen The new screen events are being enqueued for.
33935c4bbdfSmrg * @param set_dequeue_screen If TRUE, pScreen is set as both enqueue screen
34035c4bbdfSmrg * and dequeue screen.
34135c4bbdfSmrg */
34205b261ecSmrgvoid
34335c4bbdfSmrgmieqSwitchScreen(DeviceIntPtr pDev, ScreenPtr pScreen, Bool set_dequeue_screen)
34405b261ecSmrg{
3454642e01fSmrg#ifdef XQUARTZ
3464642e01fSmrg    pthread_mutex_lock(&miEventQueueMutex);
3474642e01fSmrg#endif
3484642e01fSmrg    EnqueueScreen(pDev) = pScreen;
34935c4bbdfSmrg    if (set_dequeue_screen)
3506747b715Smrg        DequeueScreen(pDev) = pScreen;
3514642e01fSmrg#ifdef XQUARTZ
3524642e01fSmrg    pthread_mutex_unlock(&miEventQueueMutex);
3534642e01fSmrg#endif
35405b261ecSmrg}
35505b261ecSmrg
35605b261ecSmrgvoid
35705b261ecSmrgmieqSetHandler(int event, mieqHandler handler)
35805b261ecSmrg{
3594642e01fSmrg#ifdef XQUARTZ
3604642e01fSmrg    pthread_mutex_lock(&miEventQueueMutex);
3614642e01fSmrg#endif
36205b261ecSmrg    if (handler && miEventQueue.handlers[event])
3634642e01fSmrg        ErrorF("[mi] mieq: warning: overriding existing handler %p with %p for "
36405b261ecSmrg               "event %d\n", miEventQueue.handlers[event], handler, event);
36505b261ecSmrg
36605b261ecSmrg    miEventQueue.handlers[event] = handler;
3674642e01fSmrg#ifdef XQUARTZ
3684642e01fSmrg    pthread_mutex_unlock(&miEventQueueMutex);
3694642e01fSmrg#endif
3704642e01fSmrg}
3714642e01fSmrg
3724642e01fSmrg/**
3734642e01fSmrg * Change the device id of the given event to the given device's id.
3744642e01fSmrg */
3754642e01fSmrgstatic void
37635c4bbdfSmrgChangeDeviceID(DeviceIntPtr dev, InternalEvent *event)
3774642e01fSmrg{
37835c4bbdfSmrg    switch (event->any.type) {
37935c4bbdfSmrg    case ET_Motion:
38035c4bbdfSmrg    case ET_KeyPress:
38135c4bbdfSmrg    case ET_KeyRelease:
38235c4bbdfSmrg    case ET_ButtonPress:
38335c4bbdfSmrg    case ET_ButtonRelease:
38435c4bbdfSmrg    case ET_ProximityIn:
38535c4bbdfSmrg    case ET_ProximityOut:
38635c4bbdfSmrg    case ET_Hierarchy:
38735c4bbdfSmrg    case ET_DeviceChanged:
38835c4bbdfSmrg    case ET_TouchBegin:
38935c4bbdfSmrg    case ET_TouchUpdate:
39035c4bbdfSmrg    case ET_TouchEnd:
39135c4bbdfSmrg        event->device_event.deviceid = dev->id;
39235c4bbdfSmrg        break;
39335c4bbdfSmrg    case ET_TouchOwnership:
39435c4bbdfSmrg        event->touch_ownership_event.deviceid = dev->id;
39535c4bbdfSmrg        break;
3966747b715Smrg#if XFreeXDGA
39735c4bbdfSmrg    case ET_DGAEvent:
39835c4bbdfSmrg        break;
3996747b715Smrg#endif
40035c4bbdfSmrg    case ET_RawKeyPress:
40135c4bbdfSmrg    case ET_RawKeyRelease:
40235c4bbdfSmrg    case ET_RawButtonPress:
40335c4bbdfSmrg    case ET_RawButtonRelease:
40435c4bbdfSmrg    case ET_RawMotion:
40535c4bbdfSmrg    case ET_RawTouchBegin:
40635c4bbdfSmrg    case ET_RawTouchEnd:
40735c4bbdfSmrg    case ET_RawTouchUpdate:
40835c4bbdfSmrg        event->raw_event.deviceid = dev->id;
40935c4bbdfSmrg        break;
41035c4bbdfSmrg    case ET_BarrierHit:
41135c4bbdfSmrg    case ET_BarrierLeave:
41235c4bbdfSmrg        event->barrier_event.deviceid = dev->id;
41335c4bbdfSmrg        break;
41435c4bbdfSmrg    default:
41535c4bbdfSmrg        ErrorF("[mi] Unknown event type (%d), cannot change id.\n",
41635c4bbdfSmrg               event->any.type);
4176747b715Smrg    }
41805b261ecSmrg}
41905b261ecSmrg
4204642e01fSmrgstatic void
4216747b715SmrgFixUpEventForMaster(DeviceIntPtr mdev, DeviceIntPtr sdev,
42235c4bbdfSmrg                    InternalEvent *original, InternalEvent *master)
4234642e01fSmrg{
42435c4bbdfSmrg    verify_internal_event(original);
42535c4bbdfSmrg    verify_internal_event(master);
4264642e01fSmrg    /* Ensure chained button mappings, i.e. that the detail field is the
4274642e01fSmrg     * value of the mapped button on the SD, not the physical button */
4286747b715Smrg    if (original->any.type == ET_ButtonPress ||
42935c4bbdfSmrg        original->any.type == ET_ButtonRelease) {
4306747b715Smrg        int btn = original->device_event.detail.button;
43135c4bbdfSmrg
4324642e01fSmrg        if (!sdev->button)
43335c4bbdfSmrg            return;             /* Should never happen */
4344642e01fSmrg
4356747b715Smrg        master->device_event.detail.button = sdev->button->map[btn];
4364642e01fSmrg    }
4374642e01fSmrg}
4384642e01fSmrg
4394642e01fSmrg/**
4404642e01fSmrg * Copy the given event into master.
4414642e01fSmrg * @param sdev The slave device the original event comes from
4424642e01fSmrg * @param original The event as it came from the EQ
4436747b715Smrg * @param copy The event after being copied
4446747b715Smrg * @return The master device or NULL if the device is a floating slave.
4454642e01fSmrg */
4466747b715SmrgDeviceIntPtr
4476747b715SmrgCopyGetMasterEvent(DeviceIntPtr sdev,
44835c4bbdfSmrg                   InternalEvent *original, InternalEvent *copy)
4494642e01fSmrg{
4506747b715Smrg    DeviceIntPtr mdev;
4516747b715Smrg    int len = original->any.length;
4528223e2f2Smrg    int type = original->any.type;
45335c4bbdfSmrg    int mtype;                  /* which master type? */
4544642e01fSmrg
45535c4bbdfSmrg    verify_internal_event(original);
4564642e01fSmrg
4576747b715Smrg    /* ET_XQuartz has sdev == NULL */
45835c4bbdfSmrg    if (!sdev || IsMaster(sdev) || IsFloating(sdev))
4596747b715Smrg        return NULL;
4604642e01fSmrg
4618223e2f2Smrg#if XFreeXDGA
4628223e2f2Smrg    if (type == ET_DGAEvent)
4638223e2f2Smrg        type = original->dga_event.subtype;
4648223e2f2Smrg#endif
4658223e2f2Smrg
46635c4bbdfSmrg    switch (type) {
46735c4bbdfSmrg    case ET_KeyPress:
46835c4bbdfSmrg    case ET_KeyRelease:
46935c4bbdfSmrg        mtype = MASTER_KEYBOARD;
47035c4bbdfSmrg        break;
47135c4bbdfSmrg    case ET_ButtonPress:
47235c4bbdfSmrg    case ET_ButtonRelease:
47335c4bbdfSmrg    case ET_Motion:
47435c4bbdfSmrg    case ET_ProximityIn:
47535c4bbdfSmrg    case ET_ProximityOut:
47635c4bbdfSmrg        mtype = MASTER_POINTER;
47735c4bbdfSmrg        break;
47835c4bbdfSmrg    default:
47935c4bbdfSmrg        mtype = MASTER_ATTACHED;
48035c4bbdfSmrg        break;
4814642e01fSmrg    }
4826747b715Smrg
48335c4bbdfSmrg    mdev = GetMaster(sdev, mtype);
4846747b715Smrg    memcpy(copy, original, len);
4856747b715Smrg    ChangeDeviceID(mdev, copy);
4866747b715Smrg    FixUpEventForMaster(mdev, sdev, original, copy);
4876747b715Smrg
4886747b715Smrg    return mdev;
4894642e01fSmrg}
4904642e01fSmrg
49135c4bbdfSmrgstatic void
49235c4bbdfSmrgmieqMoveToNewScreen(DeviceIntPtr dev, ScreenPtr screen, DeviceEvent *event)
49335c4bbdfSmrg{
49435c4bbdfSmrg    if (dev && screen && screen != DequeueScreen(dev)) {
49535c4bbdfSmrg        int x = 0, y = 0;
49635c4bbdfSmrg
49735c4bbdfSmrg        DequeueScreen(dev) = screen;
49835c4bbdfSmrg        x = event->root_x;
49935c4bbdfSmrg        y = event->root_y;
50035c4bbdfSmrg        NewCurrentScreen(dev, DequeueScreen(dev), x, y);
50135c4bbdfSmrg    }
50235c4bbdfSmrg}
5034642e01fSmrg
5046747b715Smrg/**
5056747b715Smrg * Post the given @event through the device hierarchy, as appropriate.
5066747b715Smrg * Use this function if an event must be posted for a given device during the
5076747b715Smrg * usual event processing cycle.
5086747b715Smrg */
5096747b715Smrgvoid
51035c4bbdfSmrgmieqProcessDeviceEvent(DeviceIntPtr dev, InternalEvent *event, ScreenPtr screen)
5116747b715Smrg{
5126747b715Smrg    mieqHandler handler;
5136747b715Smrg    DeviceIntPtr master;
51435c4bbdfSmrg    InternalEvent mevent;       /* master event */
5156747b715Smrg
51635c4bbdfSmrg    verify_internal_event(event);
51735c4bbdfSmrg
51835c4bbdfSmrg    /* refuse events from disabled devices */
51935c4bbdfSmrg    if (dev && !dev->enabled)
52035c4bbdfSmrg        return;
5216747b715Smrg
5226747b715Smrg    /* Custom event handler */
5236747b715Smrg    handler = miEventQueue.handlers[event->any.type];
5246747b715Smrg
5256747b715Smrg    switch (event->any.type) {
5266747b715Smrg        /* Catch events that include valuator information and check if they
5276747b715Smrg         * are changing the screen */
52835c4bbdfSmrg    case ET_Motion:
52935c4bbdfSmrg    case ET_KeyPress:
53035c4bbdfSmrg    case ET_KeyRelease:
53135c4bbdfSmrg    case ET_ButtonPress:
53235c4bbdfSmrg    case ET_ButtonRelease:
53335c4bbdfSmrg        if (!handler)
53435c4bbdfSmrg            mieqMoveToNewScreen(dev, screen, &event->device_event);
53535c4bbdfSmrg        break;
53635c4bbdfSmrg    case ET_TouchBegin:
53735c4bbdfSmrg    case ET_TouchUpdate:
53835c4bbdfSmrg    case ET_TouchEnd:
53935c4bbdfSmrg        if (!handler && (event->device_event.flags & TOUCH_POINTER_EMULATED))
54035c4bbdfSmrg            mieqMoveToNewScreen(dev, screen, &event->device_event);
54135c4bbdfSmrg        break;
54235c4bbdfSmrg    default:
54335c4bbdfSmrg        break;
5446747b715Smrg    }
5456747b715Smrg    master = CopyGetMasterEvent(dev, event, &mevent);
5466747b715Smrg
5476747b715Smrg    if (master)
54835c4bbdfSmrg        master->lastSlave = dev;
5496747b715Smrg
5506747b715Smrg    /* If someone's registered a custom event handler, let them
5516747b715Smrg     * steal it. */
55235c4bbdfSmrg    if (handler) {
55335c4bbdfSmrg        int screenNum = dev &&
55435c4bbdfSmrg            DequeueScreen(dev) ? DequeueScreen(dev)->myNum : (screen ? screen->
55535c4bbdfSmrg                                                              myNum : 0);
5566747b715Smrg        handler(screenNum, event, dev);
5576747b715Smrg        /* Check for the SD's master in case the device got detached
5586747b715Smrg         * during event processing */
55935c4bbdfSmrg        if (master && !IsFloating(dev))
5606747b715Smrg            handler(screenNum, &mevent, master);
56135c4bbdfSmrg    }
56235c4bbdfSmrg    else {
5636747b715Smrg        /* process slave first, then master */
5646747b715Smrg        dev->public.processInputProc(event, dev);
5656747b715Smrg
5666747b715Smrg        /* Check for the SD's master in case the device got detached
5676747b715Smrg         * during event processing */
56835c4bbdfSmrg        if (master && !IsFloating(dev))
5696747b715Smrg            master->public.processInputProc(&mevent, master);
5706747b715Smrg    }
5716747b715Smrg}
5724642e01fSmrg
57305b261ecSmrg/* Call this from ProcessInputEvents(). */
57405b261ecSmrgvoid
57505b261ecSmrgmieqProcessInputEvents(void)
57605b261ecSmrg{
57705b261ecSmrg    EventRec *e = NULL;
5784642e01fSmrg    ScreenPtr screen;
57935c4bbdfSmrg    InternalEvent event;
58035c4bbdfSmrg    DeviceIntPtr dev = NULL, master = NULL;
58135c4bbdfSmrg    size_t n_enqueued;
58235c4bbdfSmrg    static Bool inProcessInputEvents = FALSE;
5834642e01fSmrg
5844642e01fSmrg#ifdef XQUARTZ
5854642e01fSmrg    pthread_mutex_lock(&miEventQueueMutex);
5864642e01fSmrg#endif
5874642e01fSmrg
58835c4bbdfSmrg    /*
58935c4bbdfSmrg     * report an error if mieqProcessInputEvents() is called recursively;
59035c4bbdfSmrg     * this can happen, e.g., if something in the mieqProcessDeviceEvent()
59135c4bbdfSmrg     * call chain calls UpdateCurrentTime() instead of UpdateCurrentTimeIf()
59235c4bbdfSmrg     */
59335c4bbdfSmrg    BUG_WARN_MSG(inProcessInputEvents, "[mi] mieqProcessInputEvents() called recursively.\n");
59435c4bbdfSmrg    inProcessInputEvents = TRUE;
59535c4bbdfSmrg
59635c4bbdfSmrg    /* Grow our queue if we are reaching capacity: < 2 * QUEUE_RESERVED_SIZE remaining */
59735c4bbdfSmrg    n_enqueued = mieqNumEnqueued(&miEventQueue);
59835c4bbdfSmrg    if (n_enqueued >= (miEventQueue.nevents - (2 * QUEUE_RESERVED_SIZE)) &&
59935c4bbdfSmrg        miEventQueue.nevents < QUEUE_MAXIMUM_SIZE) {
60035c4bbdfSmrg        ErrorF("[mi] Increasing EQ size to %lu to prevent dropped events.\n",
60135c4bbdfSmrg               (unsigned long) (miEventQueue.nevents << 1));
60235c4bbdfSmrg        if (!mieqGrowQueue(&miEventQueue, miEventQueue.nevents << 1)) {
60335c4bbdfSmrg            ErrorF("[mi] Increasing the size of EQ failed.\n");
60435c4bbdfSmrg        }
60535c4bbdfSmrg    }
6064642e01fSmrg
60735c4bbdfSmrg    if (miEventQueue.dropped) {
60835c4bbdfSmrg        ErrorF("[mi] EQ processing has resumed after %lu dropped events.\n",
60935c4bbdfSmrg               (unsigned long) miEventQueue.dropped);
61035c4bbdfSmrg        ErrorF
61135c4bbdfSmrg            ("[mi] This may be caused by a misbehaving driver monopolizing the server's resources.\n");
61235c4bbdfSmrg        miEventQueue.dropped = 0;
61335c4bbdfSmrg    }
6144642e01fSmrg
61535c4bbdfSmrg    while (miEventQueue.head != miEventQueue.tail) {
61635c4bbdfSmrg        e = &miEventQueue.events[miEventQueue.head];
6174642e01fSmrg
61835c4bbdfSmrg        event = *e->events;
61935c4bbdfSmrg        dev = e->pDev;
62035c4bbdfSmrg        screen = e->pScreen;
6214642e01fSmrg
62235c4bbdfSmrg        miEventQueue.head = (miEventQueue.head + 1) % miEventQueue.nevents;
6234642e01fSmrg
6244642e01fSmrg#ifdef XQUARTZ
6254642e01fSmrg        pthread_mutex_unlock(&miEventQueueMutex);
6264642e01fSmrg#endif
6276747b715Smrg
62835c4bbdfSmrg        master = (dev) ? GetMaster(dev, MASTER_ATTACHED) : NULL;
6294642e01fSmrg
63005b261ecSmrg        if (screenIsSaved == SCREEN_SAVER_ON)
63135c4bbdfSmrg            dixSaveScreens(serverClient, SCREEN_SAVER_OFF, ScreenSaverReset);
63205b261ecSmrg#ifdef DPMSExtension
63305b261ecSmrg        else if (DPMSPowerLevel != DPMSModeOn)
63405b261ecSmrg            SetScreenSaverTimer();
63505b261ecSmrg
63605b261ecSmrg        if (DPMSPowerLevel != DPMSModeOn)
6374642e01fSmrg            DPMSSet(serverClient, DPMSModeOn);
63805b261ecSmrg#endif
63905b261ecSmrg
64035c4bbdfSmrg        mieqProcessDeviceEvent(dev, &event, screen);
64105b261ecSmrg
6424642e01fSmrg        /* Update the sprite now. Next event may be from different device. */
64335c4bbdfSmrg        if (master &&
64435c4bbdfSmrg            (event.any.type == ET_Motion ||
64535c4bbdfSmrg             ((event.any.type == ET_TouchBegin ||
64635c4bbdfSmrg               event.any.type == ET_TouchUpdate) &&
64735c4bbdfSmrg              event.device_event.flags & TOUCH_POINTER_EMULATED)))
6484642e01fSmrg            miPointerUpdateSprite(dev);
64905b261ecSmrg
6504642e01fSmrg#ifdef XQUARTZ
6514642e01fSmrg        pthread_mutex_lock(&miEventQueueMutex);
6524642e01fSmrg#endif
65305b261ecSmrg    }
65435c4bbdfSmrg
65535c4bbdfSmrg    inProcessInputEvents = FALSE;
65635c4bbdfSmrg
6574642e01fSmrg#ifdef XQUARTZ
6584642e01fSmrg    pthread_mutex_unlock(&miEventQueueMutex);
6594642e01fSmrg#endif
66005b261ecSmrg}
661