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 "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 72typedef struct _Event { 73 InternalEvent *events; 74 ScreenPtr pScreen; 75 DeviceIntPtr pDev; /* device this event _originated_ from */ 76} EventRec, *EventPtr; 77 78typedef 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 88static EventQueueRec miEventQueue; 89 90static CallbackListPtr miCallbacksWhenDrained = NULL; 91 92static size_t 93mieqNumEnqueued(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 */ 107static Bool 108mieqGrowQueue(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 164Bool 165mieqInit(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 179void 180mieqFini(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 198void 199mieqEnqueue(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 */ 285void 286mieqSwitchScreen(DeviceIntPtr pDev, ScreenPtr pScreen, Bool set_dequeue_screen) 287{ 288 EnqueueScreen(pDev) = pScreen; 289 if (set_dequeue_screen) 290 DequeueScreen(pDev) = pScreen; 291} 292 293void 294mieqSetHandler(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 */ 306static void 307ChangeDeviceID(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 359static void 360FixUpEventForMaster(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 */ 385DeviceIntPtr 386CopyGetMasterEvent(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 430static void 431mieqMoveToNewScreen(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 */ 448void 449mieqProcessDeviceEvent(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(). */ 513void 514mieqProcessInputEvents(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 583void mieqAddCallbackOnDrained(CallbackProcPtr callback, void *param) 584{ 585 input_lock(); 586 AddCallback(&miCallbacksWhenDrained, callback, param); 587 input_unlock(); 588} 589 590void mieqRemoveCallbackOnDrained(CallbackProcPtr callback, void *param) 591{ 592 input_lock(); 593 DeleteCallback(&miCallbacksWhenDrained, callback, param); 594 input_unlock(); 595} 596