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
mieqNumEnqueued(EventQueuePtr eventQueue)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
mieqGrowQueue(EventQueuePtr eventQueue,size_t new_nevents)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
mieqInit(void)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
mieqFini(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
mieqEnqueue(DeviceIntPtr pDev,InternalEvent * e)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
mieqSwitchScreen(DeviceIntPtr pDev,ScreenPtr pScreen,Bool set_dequeue_screen)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
mieqSetHandler(int event,mieqHandler handler)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
ChangeDeviceID(DeviceIntPtr dev,InternalEvent * event)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 default:
346 ErrorF("[mi] Unknown event type (%d), cannot change id.\n",
347 event->any.type);
348 }
349 }
350
351 static void
FixUpEventForMaster(DeviceIntPtr mdev,DeviceIntPtr sdev,InternalEvent * original,InternalEvent * master)352 FixUpEventForMaster(DeviceIntPtr mdev, DeviceIntPtr sdev,
353 InternalEvent *original, InternalEvent *master)
354 {
355 verify_internal_event(original);
356 verify_internal_event(master);
357 /* Ensure chained button mappings, i.e. that the detail field is the
358 * value of the mapped button on the SD, not the physical button */
359 if (original->any.type == ET_ButtonPress ||
360 original->any.type == ET_ButtonRelease) {
361 int btn = original->device_event.detail.button;
362
363 if (!sdev->button)
364 return; /* Should never happen */
365
366 master->device_event.detail.button = sdev->button->map[btn];
367 }
368 }
369
370 /**
371 * Copy the given event into master.
372 * @param sdev The slave device the original event comes from
373 * @param original The event as it came from the EQ
374 * @param copy The event after being copied
375 * @return The master device or NULL if the device is a floating slave.
376 */
377 DeviceIntPtr
CopyGetMasterEvent(DeviceIntPtr sdev,InternalEvent * original,InternalEvent * copy)378 CopyGetMasterEvent(DeviceIntPtr sdev,
379 InternalEvent *original, InternalEvent *copy)
380 {
381 DeviceIntPtr mdev;
382 int len = original->any.length;
383 int type = original->any.type;
384 int mtype; /* which master type? */
385
386 verify_internal_event(original);
387
388 /* ET_XQuartz has sdev == NULL */
389 if (!sdev || IsMaster(sdev) || IsFloating(sdev))
390 return NULL;
391
392 #ifdef XFreeXDGA
393 if (type == ET_DGAEvent)
394 type = original->dga_event.subtype;
395 #endif
396
397 switch (type) {
398 case ET_KeyPress:
399 case ET_KeyRelease:
400 mtype = MASTER_KEYBOARD;
401 break;
402 case ET_ButtonPress:
403 case ET_ButtonRelease:
404 case ET_Motion:
405 case ET_ProximityIn:
406 case ET_ProximityOut:
407 mtype = MASTER_POINTER;
408 break;
409 default:
410 mtype = MASTER_ATTACHED;
411 break;
412 }
413
414 mdev = GetMaster(sdev, mtype);
415 memcpy(copy, original, len);
416 ChangeDeviceID(mdev, copy);
417 FixUpEventForMaster(mdev, sdev, original, copy);
418
419 return mdev;
420 }
421
422 static void
mieqMoveToNewScreen(DeviceIntPtr dev,ScreenPtr screen,DeviceEvent * event)423 mieqMoveToNewScreen(DeviceIntPtr dev, ScreenPtr screen, DeviceEvent *event)
424 {
425 if (dev && screen && screen != DequeueScreen(dev)) {
426 int x = 0, y = 0;
427
428 DequeueScreen(dev) = screen;
429 x = event->root_x;
430 y = event->root_y;
431 NewCurrentScreen(dev, DequeueScreen(dev), x, y);
432 }
433 }
434
435 /**
436 * Post the given @event through the device hierarchy, as appropriate.
437 * Use this function if an event must be posted for a given device during the
438 * usual event processing cycle.
439 */
440 void
mieqProcessDeviceEvent(DeviceIntPtr dev,InternalEvent * event,ScreenPtr screen)441 mieqProcessDeviceEvent(DeviceIntPtr dev, InternalEvent *event, ScreenPtr screen)
442 {
443 mieqHandler handler;
444 DeviceIntPtr master;
445 InternalEvent mevent; /* master event */
446
447 verify_internal_event(event);
448
449 /* refuse events from disabled devices */
450 if (dev && !dev->enabled)
451 return;
452
453 /* Custom event handler */
454 handler = miEventQueue.handlers[event->any.type];
455
456 switch (event->any.type) {
457 /* Catch events that include valuator information and check if they
458 * are changing the screen */
459 case ET_Motion:
460 case ET_KeyPress:
461 case ET_KeyRelease:
462 case ET_ButtonPress:
463 case ET_ButtonRelease:
464 if (!handler)
465 mieqMoveToNewScreen(dev, screen, &event->device_event);
466 break;
467 case ET_TouchBegin:
468 case ET_TouchUpdate:
469 case ET_TouchEnd:
470 if (!handler && (event->device_event.flags & TOUCH_POINTER_EMULATED))
471 mieqMoveToNewScreen(dev, screen, &event->device_event);
472 break;
473 default:
474 break;
475 }
476 master = CopyGetMasterEvent(dev, event, &mevent);
477
478 if (master)
479 master->lastSlave = dev;
480
481 /* If someone's registered a custom event handler, let them
482 * steal it. */
483 if (handler) {
484 int screenNum = dev &&
485 DequeueScreen(dev) ? DequeueScreen(dev)->myNum : (screen ? screen->
486 myNum : 0);
487 handler(screenNum, event, dev);
488 /* Check for the SD's master in case the device got detached
489 * during event processing */
490 if (master && !IsFloating(dev))
491 handler(screenNum, &mevent, master);
492 }
493 else {
494 /* process slave first, then master */
495 dev->public.processInputProc(event, dev);
496
497 /* Check for the SD's master in case the device got detached
498 * during event processing */
499 if (master && !IsFloating(dev))
500 master->public.processInputProc(&mevent, master);
501 }
502 }
503
504 /* Call this from ProcessInputEvents(). */
505 void
mieqProcessInputEvents(void)506 mieqProcessInputEvents(void)
507 {
508 EventRec *e = NULL;
509 ScreenPtr screen;
510 InternalEvent event;
511 DeviceIntPtr dev = NULL, master = NULL;
512 static Bool inProcessInputEvents = FALSE;
513
514 input_lock();
515
516 /*
517 * report an error if mieqProcessInputEvents() is called recursively;
518 * this can happen, e.g., if something in the mieqProcessDeviceEvent()
519 * call chain calls UpdateCurrentTime() instead of UpdateCurrentTimeIf()
520 */
521 BUG_WARN_MSG(inProcessInputEvents, "[mi] mieqProcessInputEvents() called recursively.\n");
522 inProcessInputEvents = TRUE;
523
524 if (miEventQueue.dropped) {
525 ErrorF("[mi] EQ processing has resumed after %lu dropped events.\n",
526 (unsigned long) miEventQueue.dropped);
527 ErrorF
528 ("[mi] This may be caused by a misbehaving driver monopolizing the server's resources.\n");
529 miEventQueue.dropped = 0;
530 }
531
532 while (miEventQueue.head != miEventQueue.tail) {
533 e = &miEventQueue.events[miEventQueue.head];
534
535 event = *e->events;
536 dev = e->pDev;
537 screen = e->pScreen;
538
539 miEventQueue.head = (miEventQueue.head + 1) % miEventQueue.nevents;
540
541 input_unlock();
542
543 master = (dev) ? GetMaster(dev, MASTER_ATTACHED) : NULL;
544
545 if (screenIsSaved == SCREEN_SAVER_ON)
546 dixSaveScreens(serverClient, SCREEN_SAVER_OFF, ScreenSaverReset);
547 #ifdef DPMSExtension
548 else if (DPMSPowerLevel != DPMSModeOn)
549 SetScreenSaverTimer();
550
551 if (DPMSPowerLevel != DPMSModeOn)
552 DPMSSet(serverClient, DPMSModeOn);
553 #endif
554
555 mieqProcessDeviceEvent(dev, &event, screen);
556
557 /* Update the sprite now. Next event may be from different device. */
558 if (master &&
559 (event.any.type == ET_Motion ||
560 ((event.any.type == ET_TouchBegin ||
561 event.any.type == ET_TouchUpdate) &&
562 event.device_event.flags & TOUCH_POINTER_EMULATED)))
563 miPointerUpdateSprite(dev);
564
565 input_lock();
566 }
567
568 inProcessInputEvents = FALSE;
569
570 CallCallbacks(&miCallbacksWhenDrained, NULL);
571
572 input_unlock();
573 }
574
mieqAddCallbackOnDrained(CallbackProcPtr callback,void * param)575 void mieqAddCallbackOnDrained(CallbackProcPtr callback, void *param)
576 {
577 input_lock();
578 AddCallback(&miCallbacksWhenDrained, callback, param);
579 input_unlock();
580 }
581
mieqRemoveCallbackOnDrained(CallbackProcPtr callback,void * param)582 void mieqRemoveCallbackOnDrained(CallbackProcPtr callback, void *param)
583 {
584 input_lock();
585 DeleteCallback(&miCallbacksWhenDrained, callback, param);
586 input_unlock();
587 }
588