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