1/* 2 * 3Copyright 1990, 1998 The Open Group 4 5Permission to use, copy, modify, distribute, and sell this software and its 6documentation for any purpose is hereby granted without fee, provided that 7the above copyright notice appear in all copies and that both that 8copyright notice and this permission notice appear in supporting 9documentation. 10 11The above copyright notice and this permission notice shall be included in 12all copies or substantial portions of the Software. 13 14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 18AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 19CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 21Except as contained in this notice, the name of The Open Group shall not be 22used in advertising or otherwise to promote the sale, use or other dealings 23in 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 "mi.h" 47# include "mipointer.h" 48# include "scrnintstr.h" 49# include <X11/extensions/XI.h> 50# include <X11/extensions/XIproto.h> 51# include <X11/extensions/geproto.h> 52# include "extinit.h" 53# include "exglobals.h" 54# include "eventstr.h" 55 56#ifdef DPMSExtension 57# include "dpmsproc.h" 58# include <X11/extensions/dpmsconst.h> 59#endif 60 61#define QUEUE_SIZE 512 62 63#define EnqueueScreen(dev) dev->spriteInfo->sprite->pEnqueueScreen 64#define DequeueScreen(dev) dev->spriteInfo->sprite->pDequeueScreen 65 66typedef struct _Event { 67 EventListPtr events; 68 ScreenPtr pScreen; 69 DeviceIntPtr pDev; /* device this event _originated_ from */ 70} EventRec, *EventPtr; 71 72typedef struct _EventQueue { 73 HWEventQueueType head, tail; /* long for SetInputCheck */ 74 CARD32 lastEventTime; /* to avoid time running backwards */ 75 int lastMotion; /* device ID if last event motion? */ 76 EventRec events[QUEUE_SIZE]; /* static allocation for signals */ 77 mieqHandler handlers[128]; /* custom event handler */ 78} EventQueueRec, *EventQueuePtr; 79 80static EventQueueRec miEventQueue; 81 82#ifdef XQUARTZ 83#include <pthread.h> 84static pthread_mutex_t miEventQueueMutex = PTHREAD_MUTEX_INITIALIZER; 85 86extern BOOL serverRunning; 87extern pthread_mutex_t serverRunningMutex; 88extern pthread_cond_t serverRunningCond; 89 90static inline void wait_for_server_init(void) { 91 /* If the server hasn't finished initializing, wait for it... */ 92 if(!serverRunning) { 93 pthread_mutex_lock(&serverRunningMutex); 94 while(!serverRunning) 95 pthread_cond_wait(&serverRunningCond, &serverRunningMutex); 96 pthread_mutex_unlock(&serverRunningMutex); 97 } 98} 99#endif 100 101Bool 102mieqInit(void) 103{ 104 int i; 105 106 miEventQueue.head = miEventQueue.tail = 0; 107 miEventQueue.lastEventTime = GetTimeInMillis (); 108 miEventQueue.lastMotion = FALSE; 109 for (i = 0; i < 128; i++) 110 miEventQueue.handlers[i] = NULL; 111 for (i = 0; i < QUEUE_SIZE; i++) 112 { 113 if (miEventQueue.events[i].events == NULL) { 114 EventListPtr evlist = InitEventList(1); 115 if (!evlist) 116 FatalError("Could not allocate event queue.\n"); 117 miEventQueue.events[i].events = evlist; 118 } 119 } 120 121 SetInputCheck(&miEventQueue.head, &miEventQueue.tail); 122 return TRUE; 123} 124 125void 126mieqFini(void) 127{ 128 int i; 129 for (i = 0; i < QUEUE_SIZE; i++) 130 { 131 if (miEventQueue.events[i].events != NULL) { 132 FreeEventList(miEventQueue.events[i].events, 1); 133 miEventQueue.events[i].events = NULL; 134 } 135 } 136} 137 138/* 139 * Must be reentrant with ProcessInputEvents. Assumption: mieqEnqueue 140 * will never be interrupted. If this is called from both signal 141 * handlers and regular code, make sure the signal is suspended when 142 * called from regular code. 143 */ 144 145void 146mieqEnqueue(DeviceIntPtr pDev, InternalEvent *e) 147{ 148 unsigned int oldtail = miEventQueue.tail; 149 EventListPtr evt; 150 int isMotion = 0; 151 int evlen; 152 Time time; 153 154#ifdef XQUARTZ 155 wait_for_server_init(); 156 pthread_mutex_lock(&miEventQueueMutex); 157#endif 158 159 CHECKEVENT(e); 160 161 /* avoid merging events from different devices */ 162 if (e->any.type == ET_Motion) 163 isMotion = pDev->id; 164 165 if (isMotion && isMotion == miEventQueue.lastMotion && 166 oldtail != miEventQueue.head) { 167 oldtail = (oldtail - 1) % QUEUE_SIZE; 168 } 169 else { 170 static int stuck = 0; 171 /* Toss events which come in late. Usually this means your server's 172 * stuck in an infinite loop somewhere, but SIGIO is still getting 173 * handled. */ 174 if (((oldtail + 1) % QUEUE_SIZE) == miEventQueue.head) { 175 if (!stuck) { 176 ErrorF("[mi] EQ overflowing. The server is probably stuck " 177 "in an infinite loop.\n"); 178 xorg_backtrace(); 179 stuck = 1; 180 } 181#ifdef XQUARTZ 182 pthread_mutex_unlock(&miEventQueueMutex); 183#endif 184 return; 185 } 186 stuck = 0; 187 } 188 189 evlen = e->any.length; 190 evt = miEventQueue.events[oldtail].events; 191 if (evt->evlen < evlen) 192 { 193 evt->evlen = evlen; 194 evt->event = realloc(evt->event, evt->evlen); 195 if (!evt->event) 196 { 197 ErrorF("[mi] Running out of memory. Tossing event.\n"); 198#ifdef XQUARTZ 199 pthread_mutex_unlock(&miEventQueueMutex); 200#endif 201 return; 202 } 203 } 204 205 memcpy(evt->event, e, evlen); 206 207 time = e->any.time; 208 /* Make sure that event times don't go backwards - this 209 * is "unnecessary", but very useful. */ 210 if (time < miEventQueue.lastEventTime && 211 miEventQueue.lastEventTime - time < 10000) 212 e->any.time = miEventQueue.lastEventTime; 213 214 miEventQueue.lastEventTime = ((InternalEvent*)evt->event)->any.time; 215 miEventQueue.events[oldtail].pScreen = pDev ? EnqueueScreen(pDev) : NULL; 216 miEventQueue.events[oldtail].pDev = pDev; 217 218 miEventQueue.lastMotion = isMotion; 219 miEventQueue.tail = (oldtail + 1) % QUEUE_SIZE; 220#ifdef XQUARTZ 221 pthread_mutex_unlock(&miEventQueueMutex); 222#endif 223} 224 225void 226mieqSwitchScreen(DeviceIntPtr pDev, ScreenPtr pScreen, Bool fromDIX) 227{ 228#ifdef XQUARTZ 229 pthread_mutex_lock(&miEventQueueMutex); 230#endif 231 EnqueueScreen(pDev) = pScreen; 232 if (fromDIX) 233 DequeueScreen(pDev) = pScreen; 234#ifdef XQUARTZ 235 pthread_mutex_unlock(&miEventQueueMutex); 236#endif 237} 238 239void 240mieqSetHandler(int event, mieqHandler handler) 241{ 242#ifdef XQUARTZ 243 pthread_mutex_lock(&miEventQueueMutex); 244#endif 245 if (handler && miEventQueue.handlers[event]) 246 ErrorF("[mi] mieq: warning: overriding existing handler %p with %p for " 247 "event %d\n", miEventQueue.handlers[event], handler, event); 248 249 miEventQueue.handlers[event] = handler; 250#ifdef XQUARTZ 251 pthread_mutex_unlock(&miEventQueueMutex); 252#endif 253} 254 255/** 256 * Change the device id of the given event to the given device's id. 257 */ 258static void 259ChangeDeviceID(DeviceIntPtr dev, InternalEvent* event) 260{ 261 switch(event->any.type) 262 { 263 case ET_Motion: 264 case ET_KeyPress: 265 case ET_KeyRelease: 266 case ET_ButtonPress: 267 case ET_ButtonRelease: 268 case ET_ProximityIn: 269 case ET_ProximityOut: 270 case ET_Hierarchy: 271 case ET_DeviceChanged: 272 event->device_event.deviceid = dev->id; 273 break; 274#if XFreeXDGA 275 case ET_DGAEvent: 276 break; 277#endif 278 case ET_RawKeyPress: 279 case ET_RawKeyRelease: 280 case ET_RawButtonPress: 281 case ET_RawButtonRelease: 282 case ET_RawMotion: 283 event->raw_event.deviceid = dev->id; 284 break; 285 default: 286 ErrorF("[mi] Unknown event type (%d), cannot change id.\n", 287 event->any.type); 288 } 289} 290 291static void 292FixUpEventForMaster(DeviceIntPtr mdev, DeviceIntPtr sdev, 293 InternalEvent* original, InternalEvent *master) 294{ 295 CHECKEVENT(original); 296 CHECKEVENT(master); 297 /* Ensure chained button mappings, i.e. that the detail field is the 298 * value of the mapped button on the SD, not the physical button */ 299 if (original->any.type == ET_ButtonPress || 300 original->any.type == ET_ButtonRelease) 301 { 302 int btn = original->device_event.detail.button; 303 if (!sdev->button) 304 return; /* Should never happen */ 305 306 master->device_event.detail.button = sdev->button->map[btn]; 307 } 308} 309 310/** 311 * Copy the given event into master. 312 * @param sdev The slave device the original event comes from 313 * @param original The event as it came from the EQ 314 * @param copy The event after being copied 315 * @return The master device or NULL if the device is a floating slave. 316 */ 317DeviceIntPtr 318CopyGetMasterEvent(DeviceIntPtr sdev, 319 InternalEvent* original, InternalEvent *copy) 320{ 321 DeviceIntPtr mdev; 322 int len = original->any.length; 323 int type = original->any.type; 324 325 CHECKEVENT(original); 326 327 /* ET_XQuartz has sdev == NULL */ 328 if (!sdev || !sdev->u.master) 329 return NULL; 330 331#if XFreeXDGA 332 if (type == ET_DGAEvent) 333 type = original->dga_event.subtype; 334#endif 335 336 switch(type) 337 { 338 case ET_KeyPress: 339 case ET_KeyRelease: 340 mdev = GetMaster(sdev, MASTER_KEYBOARD); 341 break; 342 case ET_ButtonPress: 343 case ET_ButtonRelease: 344 case ET_Motion: 345 case ET_ProximityIn: 346 case ET_ProximityOut: 347 mdev = GetMaster(sdev, MASTER_POINTER); 348 break; 349 default: 350 mdev = sdev->u.master; 351 break; 352 } 353 354 memcpy(copy, original, len); 355 ChangeDeviceID(mdev, copy); 356 FixUpEventForMaster(mdev, sdev, original, copy); 357 358 return mdev; 359} 360 361 362/** 363 * Post the given @event through the device hierarchy, as appropriate. 364 * Use this function if an event must be posted for a given device during the 365 * usual event processing cycle. 366 */ 367void 368mieqProcessDeviceEvent(DeviceIntPtr dev, 369 InternalEvent *event, 370 ScreenPtr screen) 371{ 372 mieqHandler handler; 373 int x = 0, y = 0; 374 DeviceIntPtr master; 375 InternalEvent mevent; /* master event */ 376 377 CHECKEVENT(event); 378 379 /* Custom event handler */ 380 handler = miEventQueue.handlers[event->any.type]; 381 382 switch (event->any.type) { 383 /* Catch events that include valuator information and check if they 384 * are changing the screen */ 385 case ET_Motion: 386 case ET_KeyPress: 387 case ET_KeyRelease: 388 case ET_ButtonPress: 389 case ET_ButtonRelease: 390 if (dev && screen && screen != DequeueScreen(dev) && !handler) { 391 DequeueScreen(dev) = screen; 392 x = event->device_event.root_x; 393 y = event->device_event.root_y; 394 NewCurrentScreen (dev, DequeueScreen(dev), x, y); 395 } 396 break; 397 default: 398 break; 399 } 400 master = CopyGetMasterEvent(dev, event, &mevent); 401 402 if (master) 403 master->u.lastSlave = dev; 404 405 /* If someone's registered a custom event handler, let them 406 * steal it. */ 407 if (handler) 408 { 409 int screenNum = dev && DequeueScreen(dev) ? DequeueScreen(dev)->myNum : (screen ? screen->myNum : 0); 410 handler(screenNum, event, dev); 411 /* Check for the SD's master in case the device got detached 412 * during event processing */ 413 if (master && dev->u.master) 414 handler(screenNum, &mevent, master); 415 } else 416 { 417 /* process slave first, then master */ 418 dev->public.processInputProc(event, dev); 419 420 /* Check for the SD's master in case the device got detached 421 * during event processing */ 422 if (master && dev->u.master) 423 master->public.processInputProc(&mevent, master); 424 } 425} 426 427/* Call this from ProcessInputEvents(). */ 428void 429mieqProcessInputEvents(void) 430{ 431 EventRec *e = NULL; 432 int evlen; 433 ScreenPtr screen; 434 static InternalEvent *event = NULL; 435 static size_t event_size = 0; 436 DeviceIntPtr dev = NULL, 437 master = NULL; 438 439#ifdef XQUARTZ 440 pthread_mutex_lock(&miEventQueueMutex); 441#endif 442 443 while (miEventQueue.head != miEventQueue.tail) { 444 e = &miEventQueue.events[miEventQueue.head]; 445 446 evlen = e->events->evlen; 447 if(evlen > event_size) 448 { 449 event = realloc(event, evlen); 450 event_size = evlen; 451 } 452 453 454 if (!event) 455 FatalError("[mi] No memory left for event processing.\n"); 456 457 memcpy(event, e->events->event, evlen); 458 459 460 dev = e->pDev; 461 screen = e->pScreen; 462 463 miEventQueue.head = (miEventQueue.head + 1) % QUEUE_SIZE; 464 465#ifdef XQUARTZ 466 pthread_mutex_unlock(&miEventQueueMutex); 467#endif 468 469 master = (dev && !IsMaster(dev) && dev->u.master) ? dev->u.master : NULL; 470 471 if (screenIsSaved == SCREEN_SAVER_ON) 472 dixSaveScreens (serverClient, SCREEN_SAVER_OFF, ScreenSaverReset); 473#ifdef DPMSExtension 474 else if (DPMSPowerLevel != DPMSModeOn) 475 SetScreenSaverTimer(); 476 477 if (DPMSPowerLevel != DPMSModeOn) 478 DPMSSet(serverClient, DPMSModeOn); 479#endif 480 481 mieqProcessDeviceEvent(dev, event, screen); 482 483 /* Update the sprite now. Next event may be from different device. */ 484 if (event->any.type == ET_Motion && master) 485 miPointerUpdateSprite(dev); 486 487#ifdef XQUARTZ 488 pthread_mutex_lock(&miEventQueueMutex); 489#endif 490 } 491#ifdef XQUARTZ 492 pthread_mutex_unlock(&miEventQueueMutex); 493#endif 494} 495 496