xserver

xserver with xephyr scale patch
git clone https://git.neptards.moe/u3shit/xserver.git
Log | Files | Refs | README | LICENSE

mieq.c (18434B)


      1 /*
      2  *
      3 Copyright 1990, 1998  The Open Group
      4 
      5 Permission to use, copy, modify, distribute, and sell this software and its
      6 documentation for any purpose is hereby granted without fee, provided that
      7 the above copyright notice appear in all copies and that both that
      8 copyright notice and this permission notice appear in supporting
      9 documentation.
     10 
     11 The above copyright notice and this permission notice shall be included in
     12 all copies or substantial portions of the Software.
     13 
     14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
     17 OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
     18 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
     19 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
     20 
     21 Except as contained in this notice, the name of The Open Group shall not be
     22 used in advertising or otherwise to promote the sale, use or other dealings
     23 in 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 
     72 typedef struct _Event {
     73     InternalEvent *events;
     74     ScreenPtr pScreen;
     75     DeviceIntPtr pDev;          /* device this event _originated_ from */
     76 } EventRec, *EventPtr;
     77 
     78 typedef 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 
     88 static EventQueueRec miEventQueue;
     89 
     90 static CallbackListPtr miCallbacksWhenDrained = NULL;
     91 
     92 static size_t
     93 mieqNumEnqueued(EventQueuePtr eventQueue)
     94 {
     95     size_t n_enqueued = 0;
     96 
     97     if (eventQueue->nevents) {
     98         /* % is not well-defined with negative numbers... sigh */
     99         n_enqueued = eventQueue->tail - eventQueue->head + eventQueue->nevents;
    100         if (n_enqueued >= eventQueue->nevents)
    101             n_enqueued -= eventQueue->nevents;
    102     }
    103     return n_enqueued;
    104 }
    105 
    106 /* Pre-condition: Called with input_lock held */
    107 static Bool
    108 mieqGrowQueue(EventQueuePtr eventQueue, size_t new_nevents)
    109 {
    110     size_t i, n_enqueued, first_hunk;
    111     EventRec *new_events;
    112 
    113     if (!eventQueue) {
    114         ErrorF("[mi] mieqGrowQueue called with a NULL eventQueue\n");
    115         return FALSE;
    116     }
    117 
    118     if (new_nevents <= eventQueue->nevents)
    119         return FALSE;
    120 
    121     new_events = calloc(new_nevents, sizeof(EventRec));
    122     if (new_events == NULL) {
    123         ErrorF("[mi] mieqGrowQueue memory allocation error.\n");
    124         return FALSE;
    125     }
    126 
    127     n_enqueued = mieqNumEnqueued(eventQueue);
    128 
    129     /* First copy the existing events */
    130     first_hunk = eventQueue->nevents - eventQueue->head;
    131     if (eventQueue->events) {
    132         memcpy(new_events,
    133                &eventQueue->events[eventQueue->head],
    134                first_hunk * sizeof(EventRec));
    135         memcpy(&new_events[first_hunk],
    136                eventQueue->events, eventQueue->head * sizeof(EventRec));
    137     }
    138 
    139     /* Initialize the new portion */
    140     for (i = eventQueue->nevents; i < new_nevents; i++) {
    141         InternalEvent *evlist = InitEventList(1);
    142 
    143         if (!evlist) {
    144             size_t j;
    145 
    146             for (j = 0; j < i; j++)
    147                 FreeEventList(new_events[j].events, 1);
    148             free(new_events);
    149             return FALSE;
    150         }
    151         new_events[i].events = evlist;
    152     }
    153 
    154     /* And update our record */
    155     eventQueue->tail = n_enqueued;
    156     eventQueue->head = 0;
    157     eventQueue->nevents = new_nevents;
    158     free(eventQueue->events);
    159     eventQueue->events = new_events;
    160 
    161     return TRUE;
    162 }
    163 
    164 Bool
    165 mieqInit(void)
    166 {
    167     memset(&miEventQueue, 0, sizeof(miEventQueue));
    168     miEventQueue.lastEventTime = GetTimeInMillis();
    169 
    170     input_lock();
    171     if (!mieqGrowQueue(&miEventQueue, QUEUE_INITIAL_SIZE))
    172         FatalError("Could not allocate event queue.\n");
    173     input_unlock();
    174 
    175     SetInputCheck(&miEventQueue.head, &miEventQueue.tail);
    176     return TRUE;
    177 }
    178 
    179 void
    180 mieqFini(void)
    181 {
    182     int i;
    183 
    184     for (i = 0; i < miEventQueue.nevents; i++) {
    185         if (miEventQueue.events[i].events != NULL) {
    186             FreeEventList(miEventQueue.events[i].events, 1);
    187             miEventQueue.events[i].events = NULL;
    188         }
    189     }
    190     free(miEventQueue.events);
    191 }
    192 
    193 /*
    194  * Must be reentrant with ProcessInputEvents.  Assumption: mieqEnqueue
    195  * will never be interrupted. Must be called with input_lock held
    196  */
    197 
    198 void
    199 mieqEnqueue(DeviceIntPtr pDev, InternalEvent *e)
    200 {
    201     unsigned int oldtail = miEventQueue.tail;
    202     InternalEvent *evt;
    203     int isMotion = 0;
    204     int evlen;
    205     Time time;
    206     size_t n_enqueued;
    207 
    208     verify_internal_event(e);
    209 
    210     n_enqueued = mieqNumEnqueued(&miEventQueue);
    211 
    212     /* avoid merging events from different devices */
    213     if (e->any.type == ET_Motion)
    214         isMotion = pDev->id;
    215 
    216     if (isMotion && isMotion == miEventQueue.lastMotion &&
    217         oldtail != miEventQueue.head) {
    218         oldtail = (oldtail - 1) % miEventQueue.nevents;
    219     }
    220     else if (n_enqueued + 1 == miEventQueue.nevents) {
    221         if (!mieqGrowQueue(&miEventQueue, miEventQueue.nevents << 1)) {
    222             /* Toss events which come in late.  Usually this means your server's
    223              * stuck in an infinite loop in the main thread.
    224              */
    225             miEventQueue.dropped++;
    226             if (miEventQueue.dropped == 1) {
    227                 ErrorFSigSafe("[mi] EQ overflowing.  Additional events will be "
    228                               "discarded until existing events are processed.\n");
    229                 xorg_backtrace();
    230                 ErrorFSigSafe("[mi] These backtraces from mieqEnqueue may point to "
    231                               "a culprit higher up the stack.\n");
    232                 ErrorFSigSafe("[mi] mieq is *NOT* the cause.  It is a victim.\n");
    233             }
    234             else if (miEventQueue.dropped % QUEUE_DROP_BACKTRACE_FREQUENCY == 0 &&
    235                      miEventQueue.dropped / QUEUE_DROP_BACKTRACE_FREQUENCY <=
    236                      QUEUE_DROP_BACKTRACE_MAX) {
    237                 ErrorFSigSafe("[mi] EQ overflow continuing.  %zu events have been "
    238                               "dropped.\n", miEventQueue.dropped);
    239                 if (miEventQueue.dropped / QUEUE_DROP_BACKTRACE_FREQUENCY ==
    240                     QUEUE_DROP_BACKTRACE_MAX) {
    241                     ErrorFSigSafe("[mi] No further overflow reports will be "
    242                                   "reported until the clog is cleared.\n");
    243                 }
    244                 xorg_backtrace();
    245             }
    246             return;
    247         }
    248         oldtail = miEventQueue.tail;
    249     }
    250 
    251     evlen = e->any.length;
    252     evt = miEventQueue.events[oldtail].events;
    253     memcpy(evt, e, evlen);
    254 
    255     time = e->any.time;
    256     /* Make sure that event times don't go backwards - this
    257      * is "unnecessary", but very useful. */
    258     if (time < miEventQueue.lastEventTime &&
    259         miEventQueue.lastEventTime - time < 10000)
    260         e->any.time = miEventQueue.lastEventTime;
    261 
    262     miEventQueue.lastEventTime = evt->any.time;
    263     miEventQueue.events[oldtail].pScreen = pDev ? EnqueueScreen(pDev) : NULL;
    264     miEventQueue.events[oldtail].pDev = pDev;
    265 
    266     miEventQueue.lastMotion = isMotion;
    267     miEventQueue.tail = (oldtail + 1) % miEventQueue.nevents;
    268 }
    269 
    270 /**
    271  * Changes the screen reference events are being enqueued from.
    272  * Input events are enqueued with a screen reference and dequeued and
    273  * processed with a (potentially different) screen reference.
    274  * This function is called whenever a new event has changed screen but is
    275  * still logically on the previous screen as seen by the client.
    276  * This usually happens whenever the visible cursor moves across screen
    277  * boundaries during event generation, before the same event is processed
    278  * and sent down the wire.
    279  *
    280  * @param pDev The device that triggered a screen change.
    281  * @param pScreen The new screen events are being enqueued for.
    282  * @param set_dequeue_screen If TRUE, pScreen is set as both enqueue screen
    283  * and dequeue screen.
    284  */
    285 void
    286 mieqSwitchScreen(DeviceIntPtr pDev, ScreenPtr pScreen, Bool set_dequeue_screen)
    287 {
    288     EnqueueScreen(pDev) = pScreen;
    289     if (set_dequeue_screen)
    290         DequeueScreen(pDev) = pScreen;
    291 }
    292 
    293 void
    294 mieqSetHandler(int event, mieqHandler handler)
    295 {
    296     if (handler && miEventQueue.handlers[event] != handler)
    297         ErrorF("[mi] mieq: warning: overriding existing handler %p with %p for "
    298                "event %d\n", miEventQueue.handlers[event], handler, event);
    299 
    300     miEventQueue.handlers[event] = handler;
    301 }
    302 
    303 /**
    304  * Change the device id of the given event to the given device's id.
    305  */
    306 static void
    307 ChangeDeviceID(DeviceIntPtr dev, InternalEvent *event)
    308 {
    309     switch (event->any.type) {
    310     case ET_Motion:
    311     case ET_KeyPress:
    312     case ET_KeyRelease:
    313     case ET_ButtonPress:
    314     case ET_ButtonRelease:
    315     case ET_ProximityIn:
    316     case ET_ProximityOut:
    317     case ET_Hierarchy:
    318     case ET_DeviceChanged:
    319     case ET_TouchBegin:
    320     case ET_TouchUpdate:
    321     case ET_TouchEnd:
    322         event->device_event.deviceid = dev->id;
    323         break;
    324     case ET_TouchOwnership:
    325         event->touch_ownership_event.deviceid = dev->id;
    326         break;
    327 #ifdef XFreeXDGA
    328     case ET_DGAEvent:
    329         break;
    330 #endif
    331     case ET_RawKeyPress:
    332     case ET_RawKeyRelease:
    333     case ET_RawButtonPress:
    334     case ET_RawButtonRelease:
    335     case ET_RawMotion:
    336     case ET_RawTouchBegin:
    337     case ET_RawTouchEnd:
    338     case ET_RawTouchUpdate:
    339         event->raw_event.deviceid = dev->id;
    340         break;
    341     case ET_BarrierHit:
    342     case ET_BarrierLeave:
    343         event->barrier_event.deviceid = dev->id;
    344         break;
    345     case ET_GesturePinchBegin:
    346     case ET_GesturePinchUpdate:
    347     case ET_GesturePinchEnd:
    348     case ET_GestureSwipeBegin:
    349     case ET_GestureSwipeUpdate:
    350     case ET_GestureSwipeEnd:
    351         event->gesture_event.deviceid = dev->id;
    352         break;
    353     default:
    354         ErrorF("[mi] Unknown event type (%d), cannot change id.\n",
    355                event->any.type);
    356     }
    357 }
    358 
    359 static void
    360 FixUpEventForMaster(DeviceIntPtr mdev, DeviceIntPtr sdev,
    361                     InternalEvent *original, InternalEvent *master)
    362 {
    363     verify_internal_event(original);
    364     verify_internal_event(master);
    365     /* Ensure chained button mappings, i.e. that the detail field is the
    366      * value of the mapped button on the SD, not the physical button */
    367     if (original->any.type == ET_ButtonPress ||
    368         original->any.type == ET_ButtonRelease) {
    369         int btn = original->device_event.detail.button;
    370 
    371         if (!sdev->button)
    372             return;             /* Should never happen */
    373 
    374         master->device_event.detail.button = sdev->button->map[btn];
    375     }
    376 }
    377 
    378 /**
    379  * Copy the given event into master.
    380  * @param sdev The slave device the original event comes from
    381  * @param original The event as it came from the EQ
    382  * @param copy The event after being copied
    383  * @return The master device or NULL if the device is a floating slave.
    384  */
    385 DeviceIntPtr
    386 CopyGetMasterEvent(DeviceIntPtr sdev,
    387                    InternalEvent *original, InternalEvent *copy)
    388 {
    389     DeviceIntPtr mdev;
    390     int len = original->any.length;
    391     int type = original->any.type;
    392     int mtype;                  /* which master type? */
    393 
    394     verify_internal_event(original);
    395 
    396     /* ET_XQuartz has sdev == NULL */
    397     if (!sdev || IsMaster(sdev) || IsFloating(sdev))
    398         return NULL;
    399 
    400 #ifdef XFreeXDGA
    401     if (type == ET_DGAEvent)
    402         type = original->dga_event.subtype;
    403 #endif
    404 
    405     switch (type) {
    406     case ET_KeyPress:
    407     case ET_KeyRelease:
    408         mtype = MASTER_KEYBOARD;
    409         break;
    410     case ET_ButtonPress:
    411     case ET_ButtonRelease:
    412     case ET_Motion:
    413     case ET_ProximityIn:
    414     case ET_ProximityOut:
    415         mtype = MASTER_POINTER;
    416         break;
    417     default:
    418         mtype = MASTER_ATTACHED;
    419         break;
    420     }
    421 
    422     mdev = GetMaster(sdev, mtype);
    423     memcpy(copy, original, len);
    424     ChangeDeviceID(mdev, copy);
    425     FixUpEventForMaster(mdev, sdev, original, copy);
    426 
    427     return mdev;
    428 }
    429 
    430 static void
    431 mieqMoveToNewScreen(DeviceIntPtr dev, ScreenPtr screen, DeviceEvent *event)
    432 {
    433     if (dev && screen && screen != DequeueScreen(dev)) {
    434         int x = 0, y = 0;
    435 
    436         DequeueScreen(dev) = screen;
    437         x = event->root_x;
    438         y = event->root_y;
    439         NewCurrentScreen(dev, DequeueScreen(dev), x, y);
    440     }
    441 }
    442 
    443 /**
    444  * Post the given @event through the device hierarchy, as appropriate.
    445  * Use this function if an event must be posted for a given device during the
    446  * usual event processing cycle.
    447  */
    448 void
    449 mieqProcessDeviceEvent(DeviceIntPtr dev, InternalEvent *event, ScreenPtr screen)
    450 {
    451     mieqHandler handler;
    452     DeviceIntPtr master;
    453     InternalEvent mevent;       /* master event */
    454 
    455     verify_internal_event(event);
    456 
    457     /* refuse events from disabled devices */
    458     if (dev && !dev->enabled)
    459         return;
    460 
    461     /* Custom event handler */
    462     handler = miEventQueue.handlers[event->any.type];
    463 
    464     switch (event->any.type) {
    465         /* Catch events that include valuator information and check if they
    466          * are changing the screen */
    467     case ET_Motion:
    468     case ET_KeyPress:
    469     case ET_KeyRelease:
    470     case ET_ButtonPress:
    471     case ET_ButtonRelease:
    472         if (!handler)
    473             mieqMoveToNewScreen(dev, screen, &event->device_event);
    474         break;
    475     case ET_TouchBegin:
    476     case ET_TouchUpdate:
    477     case ET_TouchEnd:
    478         if (!handler && (event->device_event.flags & TOUCH_POINTER_EMULATED))
    479             mieqMoveToNewScreen(dev, screen, &event->device_event);
    480         break;
    481     default:
    482         break;
    483     }
    484     master = CopyGetMasterEvent(dev, event, &mevent);
    485 
    486     if (master)
    487         master->lastSlave = dev;
    488 
    489     /* If someone's registered a custom event handler, let them
    490      * steal it. */
    491     if (handler) {
    492         int screenNum = dev &&
    493             DequeueScreen(dev) ? DequeueScreen(dev)->myNum : (screen ? screen->
    494                                                               myNum : 0);
    495         handler(screenNum, event, dev);
    496         /* Check for the SD's master in case the device got detached
    497          * during event processing */
    498         if (master && !IsFloating(dev))
    499             handler(screenNum, &mevent, master);
    500     }
    501     else {
    502         /* process slave first, then master */
    503         dev->public.processInputProc(event, dev);
    504 
    505         /* Check for the SD's master in case the device got detached
    506          * during event processing */
    507         if (master && !IsFloating(dev))
    508             master->public.processInputProc(&mevent, master);
    509     }
    510 }
    511 
    512 /* Call this from ProcessInputEvents(). */
    513 void
    514 mieqProcessInputEvents(void)
    515 {
    516     EventRec *e = NULL;
    517     ScreenPtr screen;
    518     InternalEvent event;
    519     DeviceIntPtr dev = NULL, master = NULL;
    520     static Bool inProcessInputEvents = FALSE;
    521 
    522     input_lock();
    523 
    524     /*
    525      * report an error if mieqProcessInputEvents() is called recursively;
    526      * this can happen, e.g., if something in the mieqProcessDeviceEvent()
    527      * call chain calls UpdateCurrentTime() instead of UpdateCurrentTimeIf()
    528      */
    529     BUG_WARN_MSG(inProcessInputEvents, "[mi] mieqProcessInputEvents() called recursively.\n");
    530     inProcessInputEvents = TRUE;
    531 
    532     if (miEventQueue.dropped) {
    533         ErrorF("[mi] EQ processing has resumed after %lu dropped events.\n",
    534                (unsigned long) miEventQueue.dropped);
    535         ErrorF
    536             ("[mi] This may be caused by a misbehaving driver monopolizing the server's resources.\n");
    537         miEventQueue.dropped = 0;
    538     }
    539 
    540     while (miEventQueue.head != miEventQueue.tail) {
    541         e = &miEventQueue.events[miEventQueue.head];
    542 
    543         event = *e->events;
    544         dev = e->pDev;
    545         screen = e->pScreen;
    546 
    547         miEventQueue.head = (miEventQueue.head + 1) % miEventQueue.nevents;
    548 
    549         input_unlock();
    550 
    551         master = (dev) ? GetMaster(dev, MASTER_ATTACHED) : NULL;
    552 
    553         if (screenIsSaved == SCREEN_SAVER_ON)
    554             dixSaveScreens(serverClient, SCREEN_SAVER_OFF, ScreenSaverReset);
    555 #ifdef DPMSExtension
    556         else if (DPMSPowerLevel != DPMSModeOn)
    557             SetScreenSaverTimer();
    558 
    559         if (DPMSPowerLevel != DPMSModeOn)
    560             DPMSSet(serverClient, DPMSModeOn);
    561 #endif
    562 
    563         mieqProcessDeviceEvent(dev, &event, screen);
    564 
    565         /* Update the sprite now. Next event may be from different device. */
    566         if (master &&
    567             (event.any.type == ET_Motion ||
    568              ((event.any.type == ET_TouchBegin ||
    569                event.any.type == ET_TouchUpdate) &&
    570               event.device_event.flags & TOUCH_POINTER_EMULATED)))
    571             miPointerUpdateSprite(dev);
    572 
    573         input_lock();
    574     }
    575 
    576     inProcessInputEvents = FALSE;
    577 
    578     CallCallbacks(&miCallbacksWhenDrained, NULL);
    579 
    580     input_unlock();
    581 }
    582 
    583 void mieqAddCallbackOnDrained(CallbackProcPtr callback, void *param)
    584 {
    585     input_lock();
    586     AddCallback(&miCallbacksWhenDrained, callback, param);
    587     input_unlock();
    588 }
    589 
    590 void mieqRemoveCallbackOnDrained(CallbackProcPtr callback, void *param)
    591 {
    592     input_lock();
    593     DeleteCallback(&miCallbacksWhenDrained, callback, param);
    594     input_unlock();
    595 }