diff options
Diffstat (limited to 'xorg-server/mi/mieq.c')
-rw-r--r-- | xorg-server/mi/mieq.c | 359 |
1 files changed, 296 insertions, 63 deletions
diff --git a/xorg-server/mi/mieq.c b/xorg-server/mi/mieq.c index 803724708..213ad5b40 100644 --- a/xorg-server/mi/mieq.c +++ b/xorg-server/mi/mieq.c @@ -49,6 +49,7 @@ in this Software without prior written authorization from The Open Group. # include "scrnintstr.h" # include <X11/extensions/XI.h> # include <X11/extensions/XIproto.h> +# include <X11/extensions/geproto.h> # include "extinit.h" # include "exglobals.h" @@ -60,8 +61,11 @@ in this Software without prior written authorization from The Open Group. #define QUEUE_SIZE 512 +#define EnqueueScreen(dev) dev->spriteInfo->sprite->pEnqueueScreen +#define DequeueScreen(dev) dev->spriteInfo->sprite->pDequeueScreen + typedef struct _Event { - xEvent event[7]; + EventListPtr events; int nevents; ScreenPtr pScreen; DeviceIntPtr pDev; /* device this event _originated_ from */ @@ -72,12 +76,30 @@ typedef struct _EventQueue { CARD32 lastEventTime; /* to avoid time running backwards */ int lastMotion; /* device ID if last event motion? */ EventRec events[QUEUE_SIZE]; /* static allocation for signals */ - ScreenPtr pEnqueueScreen; /* screen events are being delivered to */ - ScreenPtr pDequeueScreen; /* screen events are being dispatched to */ mieqHandler handlers[128]; /* custom event handler */ } EventQueueRec, *EventQueuePtr; static EventQueueRec miEventQueue; +static EventListPtr masterEvents; /* for use in mieqProcessInputEvents */ + +#ifdef XQUARTZ +#include <pthread.h> +static pthread_mutex_t miEventQueueMutex = PTHREAD_MUTEX_INITIALIZER; + +extern BOOL serverInitComplete; +extern pthread_mutex_t serverInitCompleteMutex; +extern pthread_cond_t serverInitCompleteCond; + +static inline void wait_for_server_init(void) { + /* If the server hasn't finished initializing, wait for it... */ + if(!serverInitComplete) { + pthread_mutex_lock(&serverInitCompleteMutex); + while(!serverInitComplete) + pthread_cond_wait(&serverInitCompleteCond, &serverInitCompleteMutex); + pthread_mutex_unlock(&serverInitCompleteMutex); + } +} +#endif Bool mieqInit(void) @@ -87,14 +109,40 @@ mieqInit(void) miEventQueue.head = miEventQueue.tail = 0; miEventQueue.lastEventTime = GetTimeInMillis (); miEventQueue.lastMotion = FALSE; - miEventQueue.pEnqueueScreen = screenInfo.screens[0]; - miEventQueue.pDequeueScreen = miEventQueue.pEnqueueScreen; for (i = 0; i < 128; i++) miEventQueue.handlers[i] = NULL; + for (i = 0; i < QUEUE_SIZE; i++) + { + EventListPtr evlist = InitEventList(1 + MAX_VALUATOR_EVENTS); + if (!evlist) + FatalError("Could not allocate event queue.\n"); + miEventQueue.events[i].events = evlist; + } + + /* XXX: mE is just 1 event long, if we have Motion + Valuator they are + * squashed into the first event to make passing it into the event + * processing handlers easier. This should be fixed when the processing + * handlers switch to EventListPtr instead of xEvent */ + masterEvents = InitEventList(1); + if (!masterEvents) + FatalError("Could not allocated MD event queue.\n"); + SetMinimumEventSize(masterEvents, 1, + (1 + MAX_VALUATOR_EVENTS) * sizeof(xEvent)); + SetInputCheck(&miEventQueue.head, &miEventQueue.tail); return TRUE; } +/* Ensure all events in the EQ are at least size bytes. */ +void +mieqResizeEvents(int min_size) +{ + int i; + + for (i = 0; i < QUEUE_SIZE; i++) + SetMinimumEventSize(miEventQueue.events[i].events, 7, min_size); +} + /* * Must be reentrant with ProcessInputEvents. Assumption: mieqEnqueue * will never be interrupted. If this is called from both signal @@ -105,23 +153,37 @@ mieqInit(void) void mieqEnqueue(DeviceIntPtr pDev, xEvent *e) { - unsigned int oldtail = miEventQueue.tail, newtail; + unsigned int oldtail = miEventQueue.tail; + EventListPtr evt; int isMotion = 0; - deviceValuator *v = (deviceValuator *) e; - EventPtr laste = &miEventQueue.events[(oldtail - 1) % - QUEUE_SIZE]; - deviceKeyButtonPointer *lastkbp = (deviceKeyButtonPointer *) - &laste->event[0]; + int evlen; +#ifdef XQUARTZ + wait_for_server_init(); + pthread_mutex_lock(&miEventQueueMutex); +#endif + + /* avoid merging events from different devices */ if (e->u.u.type == MotionNotify) - isMotion = inputInfo.pointer->id; - else if (e->u.u.type == DeviceMotionNotify) isMotion = pDev->id; + else if (e->u.u.type == DeviceMotionNotify) + isMotion = pDev->id | (1 << 8); /* flag to indicate DeviceMotion */ /* We silently steal valuator events: just tack them on to the last * motion event they need to be attached to. Sigh. */ if (e->u.u.type == DeviceValuator) { + deviceValuator *v = (deviceValuator *) e; + EventPtr laste; + deviceKeyButtonPointer *lastkbp; + + laste = &miEventQueue.events[(oldtail - 1) % QUEUE_SIZE]; + lastkbp = (deviceKeyButtonPointer *) laste->events->event; + if (laste->nevents > 6) { +#ifdef XQUARTZ + pthread_mutex_unlock(&miEventQueueMutex); +#endif + ErrorF("[mi] mieqEnqueue: more than six valuator events; dropping.\n"); return; } @@ -133,10 +195,17 @@ mieqEnqueue(DeviceIntPtr pDev, xEvent *e) lastkbp->type == ProximityOut) || ((lastkbp->deviceid & DEVICE_BITS) != (v->deviceid & DEVICE_BITS))) { +#ifdef XQUARTZ + pthread_mutex_unlock(&miEventQueueMutex); +#endif ErrorF("[mi] mieqEnequeue: out-of-order valuator event; dropping.\n"); return; } - memcpy(&(laste->event[laste->nevents++]), e, sizeof(xEvent)); + + memcpy((laste->events[laste->nevents++].event), e, sizeof(xEvent)); +#ifdef XQUARTZ + pthread_mutex_unlock(&miEventQueueMutex); +#endif return; } @@ -146,68 +215,216 @@ mieqEnqueue(DeviceIntPtr pDev, xEvent *e) } else { static int stuck = 0; - newtail = (oldtail + 1) % QUEUE_SIZE; /* Toss events which come in late. Usually this means your server's * stuck in an infinite loop somewhere, but SIGIO is still getting * handled. */ - if (newtail == miEventQueue.head) { + if (((oldtail + 1) % QUEUE_SIZE) == miEventQueue.head) { ErrorF("[mi] EQ overflowing. The server is probably stuck " "in an infinite loop.\n"); if (!stuck) { xorg_backtrace(); stuck = 1; } +#ifdef XQUARTZ + pthread_mutex_unlock(&miEventQueueMutex); +#endif return; } stuck = 0; - miEventQueue.tail = newtail; } - memcpy(&(miEventQueue.events[oldtail].event[0]), e, sizeof(xEvent)); + evlen = sizeof(xEvent); + if (e->u.u.type == GenericEvent) + evlen += ((xGenericEvent*)e)->length * 4; + + evt = miEventQueue.events[oldtail].events; + if (evt->evlen < evlen) + { + evt->evlen = evlen; + evt->event = xrealloc(evt->event, evt->evlen); + if (!evt->event) + { + ErrorF("[mi] Running out of memory. Tossing event.\n"); +#ifdef XQUARTZ + pthread_mutex_unlock(&miEventQueueMutex); +#endif + return; + } + } + + memcpy(evt->event, e, evlen); miEventQueue.events[oldtail].nevents = 1; /* Make sure that event times don't go backwards - this * is "unnecessary", but very useful. */ - if (e->u.keyButtonPointer.time < miEventQueue.lastEventTime && - miEventQueue.lastEventTime - e->u.keyButtonPointer.time < 10000) - miEventQueue.events[oldtail].event[0].u.keyButtonPointer.time = - miEventQueue.lastEventTime; - - miEventQueue.lastEventTime = - miEventQueue.events[oldtail].event[0].u.keyButtonPointer.time; - miEventQueue.events[oldtail].pScreen = miEventQueue.pEnqueueScreen; + if (e->u.u.type != GenericEvent && + e->u.keyButtonPointer.time < miEventQueue.lastEventTime && + miEventQueue.lastEventTime - e->u.keyButtonPointer.time < 10000) + evt->event->u.keyButtonPointer.time = miEventQueue.lastEventTime; + + miEventQueue.lastEventTime = evt->event->u.keyButtonPointer.time; + miEventQueue.events[oldtail].pScreen = EnqueueScreen(pDev); miEventQueue.events[oldtail].pDev = pDev; miEventQueue.lastMotion = isMotion; + miEventQueue.tail = (oldtail + 1) % QUEUE_SIZE; +#ifdef XQUARTZ + pthread_mutex_unlock(&miEventQueueMutex); +#endif } void -mieqSwitchScreen(ScreenPtr pScreen, Bool fromDIX) +mieqSwitchScreen(DeviceIntPtr pDev, ScreenPtr pScreen, Bool fromDIX) { - miEventQueue.pEnqueueScreen = pScreen; +#ifdef XQUARTZ + pthread_mutex_lock(&miEventQueueMutex); +#endif + EnqueueScreen(pDev) = pScreen; if (fromDIX) - miEventQueue.pDequeueScreen = pScreen; + DequeueScreen(pDev) = pScreen; +#ifdef XQUARTZ + pthread_mutex_unlock(&miEventQueueMutex); +#endif } void mieqSetHandler(int event, mieqHandler handler) { +#ifdef XQUARTZ + pthread_mutex_lock(&miEventQueueMutex); +#endif if (handler && miEventQueue.handlers[event]) - ErrorF("mieq: warning: overriding existing handler %p with %p for " + ErrorF("[mi] mieq: warning: overriding existing handler %p with %p for " "event %d\n", miEventQueue.handlers[event], handler, event); miEventQueue.handlers[event] = handler; +#ifdef XQUARTZ + pthread_mutex_unlock(&miEventQueueMutex); +#endif +} + +/** + * Change the device id of the given event to the given device's id. + */ +static void +ChangeDeviceID(DeviceIntPtr dev, xEvent* event) +{ + int type = event->u.u.type; + + if (type == DeviceKeyPress || type == DeviceKeyRelease || + type == DeviceButtonPress || type == DeviceButtonRelease || + type == DeviceMotionNotify || type == ProximityIn || + type == ProximityOut) + ((deviceKeyButtonPointer*)event)->deviceid = dev->id; + else if (type == DeviceValuator) + ((deviceValuator*)event)->deviceid = dev->id; + else if (type == GenericEvent) + { + DebugF("[mi] Unknown generic event (%d/%d), cannot change id.\n", + ((xGenericEvent*)event)->extension, + ((xGenericEvent*)event)->evtype); + } else + DebugF("[mi] Unknown event type (%d), cannot change id.\n", type); } +static void +FixUpEventForMaster(DeviceIntPtr mdev, DeviceIntPtr sdev, xEvent* original, + EventListPtr master, int count) +{ + /* Ensure chained button mappings, i.e. that the detail field is the + * value of the mapped button on the SD, not the physical button */ + if (original->u.u.type == DeviceButtonPress || original->u.u.type == DeviceButtonRelease) + { + int btn = original->u.u.detail; + if (!sdev->button) + return; /* Should never happen */ + + master->event->u.u.detail = sdev->button->map[btn]; + } +} + +/** + * Copy the given event into master. + * @param mdev The master device + * @param sdev The slave device the original event comes from + * @param original The event as it came from the EQ + * @param master The event after being copied + * @param count Number of events in original. + */ +void +CopyGetMasterEvent(DeviceIntPtr mdev, DeviceIntPtr sdev, xEvent* original, + EventListPtr master, int count) +{ + int len = count * sizeof(xEvent); + + /* Assumption: GenericEvents always have count 1 */ + + if (GEV(original)->type == GenericEvent) + len += GEV(original)->length * 4; + + if (master->evlen < len) + SetMinimumEventSize(master, 1, len); + + memcpy(master->event, original, len); + while (count--) + { + ChangeDeviceID(mdev, &master->event[count]); + FixUpEventForMaster(mdev, sdev, original, master, count); + } +} +extern void +CopyKeyClass(DeviceIntPtr device, DeviceIntPtr master); + + + /* Call this from ProcessInputEvents(). */ void mieqProcessInputEvents(void) { + mieqHandler handler; EventRec *e = NULL; int x = 0, y = 0; - DeviceIntPtr dev = NULL; - + int type, nevents, evlen, i; + ScreenPtr screen; + static xEvent *event = NULL; + static size_t event_size = 0; + DeviceIntPtr dev = NULL, + master = NULL; + +#ifdef XQUARTZ + pthread_mutex_lock(&miEventQueueMutex); +#endif + while (miEventQueue.head != miEventQueue.tail) { + e = &miEventQueue.events[miEventQueue.head]; + + /* GenericEvents always have nevents == 1 */ + nevents = e->nevents; + evlen = (nevents > 1) ? sizeof(xEvent) : e->events->evlen; + if((nevents * evlen) > event_size) { + event_size = nevents * evlen; + event = (xEvent *)xrealloc(event, event_size); + } + + if (!event) + FatalError("[mi] No memory left for event processing.\n"); + + for (i = 0; i < nevents; i++) + memcpy(&event[i], e->events[i].event, evlen); + + + dev = e->pDev; + screen = e->pScreen; + + miEventQueue.head = (miEventQueue.head + 1) % QUEUE_SIZE; + +#ifdef XQUARTZ + pthread_mutex_unlock(&miEventQueueMutex); +#endif + + type = event->u.u.type; + master = (!dev->isMaster && dev->u.master) ? dev->u.master : NULL; + if (screenIsSaved == SCREEN_SAVER_ON) dixSaveScreens (serverClient, SCREEN_SAVER_OFF, ScreenSaverReset); #ifdef DPMSExtension @@ -218,44 +435,60 @@ mieqProcessInputEvents(void) DPMSSet(serverClient, DPMSModeOn); #endif - e = &miEventQueue.events[miEventQueue.head]; - /* Assumption - screen switching can only occur on motion events. */ - miEventQueue.head = (miEventQueue.head + 1) % QUEUE_SIZE; + /* Custom event handler */ + handler = miEventQueue.handlers[type]; - if (e->pScreen != miEventQueue.pDequeueScreen) { - miEventQueue.pDequeueScreen = e->pScreen; - x = e->event[0].u.keyButtonPointer.rootX; - y = e->event[0].u.keyButtonPointer.rootY; - NewCurrentScreen (miEventQueue.pDequeueScreen, x, y); + if (screen != DequeueScreen(dev) && !handler) { + /* Assumption - screen switching can only occur on motion events. */ + DequeueScreen(dev) = screen; + x = event->u.keyButtonPointer.rootX; + y = event->u.keyButtonPointer.rootY; + NewCurrentScreen (dev, DequeueScreen(dev), x, y); } else { + if (master) { + /* Force a copy of the key class into the VCK so that the layout + is transferred. */ + if (event->u.u.type == DeviceKeyPress || + event->u.u.type == DeviceKeyRelease) + { + if (!master->key) + master = GetPairedDevice(master); + CopyKeyClass(dev, master); + } + + CopyGetMasterEvent(master, dev, event, masterEvents, nevents); + } + /* If someone's registered a custom event handler, let them * steal it. */ - if (miEventQueue.handlers[e->event->u.u.type]) { - miEventQueue.handlers[e->event->u.u.type](miEventQueue.pDequeueScreen->myNum, - e->event, dev, - e->nevents); - return; + if (handler) + { + handler(DequeueScreen(dev)->myNum, event, dev, nevents); + if (master) + handler(DequeueScreen(master)->myNum, + masterEvents->event, master, nevents); + } else + { + /* process slave first, then master */ + dev->public.processInputProc(event, dev, nevents); + + if (master) + master->public.processInputProc(masterEvents->event, master, + nevents); } + } - /* If this is a core event, make sure our keymap, et al, is - * changed to suit. */ - if (e->event[0].u.u.type == KeyPress || - e->event[0].u.u.type == KeyRelease) { - SwitchCoreKeyboard(e->pDev); - dev = inputInfo.keyboard; - } - else if (e->event[0].u.u.type == MotionNotify || - e->event[0].u.u.type == ButtonPress || - e->event[0].u.u.type == ButtonRelease) { - SwitchCorePointer(e->pDev); - dev = inputInfo.pointer; - } - else { - dev = e->pDev; - } + /* Update the sprite now. Next event may be from different device. */ + if (type == DeviceMotionNotify && dev->coreEvents) + miPointerUpdateSprite(dev); - dev->public.processInputProc(e->event, dev, e->nevents); - } +#ifdef XQUARTZ + pthread_mutex_lock(&miEventQueueMutex); +#endif } +#ifdef XQUARTZ + pthread_mutex_unlock(&miEventQueueMutex); +#endif } + |