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 size_t
mieqNumEnqueued(EventQueuePtr eventQueue)91 mieqNumEnqueued(EventQueuePtr eventQueue)
92 {
93 size_t n_enqueued = 0;
94
95 if (eventQueue->nevents) {
96 /* % is not well-defined with negative numbers... sigh */
97 n_enqueued = eventQueue->tail - eventQueue->head + eventQueue->nevents;
98 if (n_enqueued >= eventQueue->nevents)
99 n_enqueued -= eventQueue->nevents;
100 }
101 return n_enqueued;
102 }
103
104 /* Pre-condition: Called with input_lock held */
105 static Bool
mieqGrowQueue(EventQueuePtr eventQueue,size_t new_nevents)106 mieqGrowQueue(EventQueuePtr eventQueue, size_t new_nevents)
107 {
108 size_t i, n_enqueued, first_hunk;
109 EventRec *new_events;
110
111 if (!eventQueue) {
112 ErrorF("[mi] mieqGrowQueue called with a NULL eventQueue\n");
113 return FALSE;
114 }
115
116 if (new_nevents <= eventQueue->nevents)
117 return FALSE;
118
119 new_events = calloc(new_nevents, sizeof(EventRec));
120 if (new_events == NULL) {
121 ErrorF("[mi] mieqGrowQueue memory allocation error.\n");
122 return FALSE;
123 }
124
125 n_enqueued = mieqNumEnqueued(eventQueue);
126
127 /* First copy the existing events */
128 first_hunk = eventQueue->nevents - eventQueue->head;
129 memcpy(new_events,
130 &eventQueue->events[eventQueue->head],
131 first_hunk * sizeof(EventRec));
132 memcpy(&new_events[first_hunk],
133 eventQueue->events, eventQueue->head * sizeof(EventRec));
134
135 /* Initialize the new portion */
136 for (i = eventQueue->nevents; i < new_nevents; i++) {
137 InternalEvent *evlist = InitEventList(1);
138
139 if (!evlist) {
140 size_t j;
141
142 for (j = 0; j < i; j++)
143 FreeEventList(new_events[j].events, 1);
144 free(new_events);
145 return FALSE;
146 }
147 new_events[i].events = evlist;
148 }
149
150 /* And update our record */
151 eventQueue->tail = n_enqueued;
152 eventQueue->head = 0;
153 eventQueue->nevents = new_nevents;
154 free(eventQueue->events);
155 eventQueue->events = new_events;
156
157 return TRUE;
158 }
159
160 Bool
mieqInit(void)161 mieqInit(void)
162 {
163 memset(&miEventQueue, 0, sizeof(miEventQueue));
164 miEventQueue.lastEventTime = GetTimeInMillis();
165
166 input_lock();
167 if (!mieqGrowQueue(&miEventQueue, QUEUE_INITIAL_SIZE))
168 FatalError("Could not allocate event queue.\n");
169 input_unlock();
170
171 SetInputCheck(&miEventQueue.head, &miEventQueue.tail);
172 return TRUE;
173 }
174
175 void
mieqFini(void)176 mieqFini(void)
177 {
178 int i;
179
180 for (i = 0; i < miEventQueue.nevents; i++) {
181 if (miEventQueue.events[i].events != NULL) {
182 FreeEventList(miEventQueue.events[i].events, 1);
183 miEventQueue.events[i].events = NULL;
184 }
185 }
186 free(miEventQueue.events);
187 }
188
189 /*
190 * Must be reentrant with ProcessInputEvents. Assumption: mieqEnqueue
191 * will never be interrupted. Must be called with input_lock held
192 */
193
194 void
mieqEnqueue(DeviceIntPtr pDev,InternalEvent * e)195 mieqEnqueue(DeviceIntPtr pDev, InternalEvent *e)
196 {
197 unsigned int oldtail = miEventQueue.tail;
198 InternalEvent *evt;
199 int isMotion = 0;
200 int evlen;
201 Time time;
202 size_t n_enqueued;
203
204 verify_internal_event(e);
205
206 n_enqueued = mieqNumEnqueued(&miEventQueue);
207
208 /* avoid merging events from different devices */
209 if (e->any.type == ET_Motion)
210 isMotion = pDev->id;
211
212 if (isMotion && isMotion == miEventQueue.lastMotion &&
213 oldtail != miEventQueue.head) {
214 oldtail = (oldtail - 1) % miEventQueue.nevents;
215 }
216 else if (n_enqueued + 1 == miEventQueue.nevents) {
217 if (!mieqGrowQueue(&miEventQueue, miEventQueue.nevents << 1)) {
218 /* Toss events which come in late. Usually this means your server's
219 * stuck in an infinite loop in the main thread.
220 */
221 miEventQueue.dropped++;
222 if (miEventQueue.dropped == 1) {
223 ErrorFSigSafe("[mi] EQ overflowing. Additional events will be "
224 "discarded until existing events are processed.\n");
225 xorg_backtrace();
226 ErrorFSigSafe("[mi] These backtraces from mieqEnqueue may point to "
227 "a culprit higher up the stack.\n");
228 ErrorFSigSafe("[mi] mieq is *NOT* the cause. It is a victim.\n");
229 }
230 else if (miEventQueue.dropped % QUEUE_DROP_BACKTRACE_FREQUENCY == 0 &&
231 miEventQueue.dropped / QUEUE_DROP_BACKTRACE_FREQUENCY <=
232 QUEUE_DROP_BACKTRACE_MAX) {
233 ErrorFSigSafe("[mi] EQ overflow continuing. %zu events have been "
234 "dropped.\n", miEventQueue.dropped);
235 if (miEventQueue.dropped / QUEUE_DROP_BACKTRACE_FREQUENCY ==
236 QUEUE_DROP_BACKTRACE_MAX) {
237 ErrorFSigSafe("[mi] No further overflow reports will be "
238 "reported until the clog is cleared.\n");
239 }
240 xorg_backtrace();
241 }
242 return;
243 }
244 oldtail = miEventQueue.tail;
245 }
246
247 evlen = e->any.length;
248 evt = miEventQueue.events[oldtail].events;
249 memcpy(evt, e, evlen);
250
251 time = e->any.time;
252 /* Make sure that event times don't go backwards - this
253 * is "unnecessary", but very useful. */
254 if (time < miEventQueue.lastEventTime &&
255 miEventQueue.lastEventTime - time < 10000)
256 e->any.time = miEventQueue.lastEventTime;
257
258 miEventQueue.lastEventTime = evt->any.time;
259 miEventQueue.events[oldtail].pScreen = pDev ? EnqueueScreen(pDev) : NULL;
260 miEventQueue.events[oldtail].pDev = pDev;
261
262 miEventQueue.lastMotion = isMotion;
263 miEventQueue.tail = (oldtail + 1) % miEventQueue.nevents;
264 }
265
266 /**
267 * Changes the screen reference events are being enqueued from.
268 * Input events are enqueued with a screen reference and dequeued and
269 * processed with a (potentially different) screen reference.
270 * This function is called whenever a new event has changed screen but is
271 * still logically on the previous screen as seen by the client.
272 * This usually happens whenever the visible cursor moves across screen
273 * boundaries during event generation, before the same event is processed
274 * and sent down the wire.
275 *
276 * @param pDev The device that triggered a screen change.
277 * @param pScreen The new screen events are being enqueued for.
278 * @param set_dequeue_screen If TRUE, pScreen is set as both enqueue screen
279 * and dequeue screen.
280 */
281 void
mieqSwitchScreen(DeviceIntPtr pDev,ScreenPtr pScreen,Bool set_dequeue_screen)282 mieqSwitchScreen(DeviceIntPtr pDev, ScreenPtr pScreen, Bool set_dequeue_screen)
283 {
284 EnqueueScreen(pDev) = pScreen;
285 if (set_dequeue_screen)
286 DequeueScreen(pDev) = pScreen;
287 }
288
289 void
mieqSetHandler(int event,mieqHandler handler)290 mieqSetHandler(int event, mieqHandler handler)
291 {
292 if (handler && miEventQueue.handlers[event])
293 ErrorF("[mi] mieq: warning: overriding existing handler %p with %p for "
294 "event %d\n", miEventQueue.handlers[event], handler, event);
295
296 miEventQueue.handlers[event] = handler;
297 }
298
299 /**
300 * Change the device id of the given event to the given device's id.
301 */
302 static void
ChangeDeviceID(DeviceIntPtr dev,InternalEvent * event)303 ChangeDeviceID(DeviceIntPtr dev, InternalEvent *event)
304 {
305 switch (event->any.type) {
306 case ET_Motion:
307 case ET_KeyPress:
308 case ET_KeyRelease:
309 case ET_ButtonPress:
310 case ET_ButtonRelease:
311 case ET_ProximityIn:
312 case ET_ProximityOut:
313 case ET_Hierarchy:
314 case ET_DeviceChanged:
315 case ET_TouchBegin:
316 case ET_TouchUpdate:
317 case ET_TouchEnd:
318 event->device_event.deviceid = dev->id;
319 break;
320 case ET_TouchOwnership:
321 event->touch_ownership_event.deviceid = dev->id;
322 break;
323 #ifdef XFreeXDGA
324 case ET_DGAEvent:
325 break;
326 #endif
327 case ET_RawKeyPress:
328 case ET_RawKeyRelease:
329 case ET_RawButtonPress:
330 case ET_RawButtonRelease:
331 case ET_RawMotion:
332 case ET_RawTouchBegin:
333 case ET_RawTouchEnd:
334 case ET_RawTouchUpdate:
335 event->raw_event.deviceid = dev->id;
336 break;
337 case ET_BarrierHit:
338 case ET_BarrierLeave:
339 event->barrier_event.deviceid = dev->id;
340 break;
341 default:
342 ErrorF("[mi] Unknown event type (%d), cannot change id.\n",
343 event->any.type);
344 }
345 }
346
347 static void
FixUpEventForMaster(DeviceIntPtr mdev,DeviceIntPtr sdev,InternalEvent * original,InternalEvent * master)348 FixUpEventForMaster(DeviceIntPtr mdev, DeviceIntPtr sdev,
349 InternalEvent *original, InternalEvent *master)
350 {
351 verify_internal_event(original);
352 verify_internal_event(master);
353 /* Ensure chained button mappings, i.e. that the detail field is the
354 * value of the mapped button on the SD, not the physical button */
355 if (original->any.type == ET_ButtonPress ||
356 original->any.type == ET_ButtonRelease) {
357 int btn = original->device_event.detail.button;
358
359 if (!sdev->button)
360 return; /* Should never happen */
361
362 master->device_event.detail.button = sdev->button->map[btn];
363 }
364 }
365
366 /**
367 * Copy the given event into master.
368 * @param sdev The slave device the original event comes from
369 * @param original The event as it came from the EQ
370 * @param copy The event after being copied
371 * @return The master device or NULL if the device is a floating slave.
372 */
373 DeviceIntPtr
CopyGetMasterEvent(DeviceIntPtr sdev,InternalEvent * original,InternalEvent * copy)374 CopyGetMasterEvent(DeviceIntPtr sdev,
375 InternalEvent *original, InternalEvent *copy)
376 {
377 DeviceIntPtr mdev;
378 int len = original->any.length;
379 int type = original->any.type;
380 int mtype; /* which master type? */
381
382 verify_internal_event(original);
383
384 /* ET_XQuartz has sdev == NULL */
385 if (!sdev || IsMaster(sdev) || IsFloating(sdev))
386 return NULL;
387
388 #ifdef XFreeXDGA
389 if (type == ET_DGAEvent)
390 type = original->dga_event.subtype;
391 #endif
392
393 switch (type) {
394 case ET_KeyPress:
395 case ET_KeyRelease:
396 mtype = MASTER_KEYBOARD;
397 break;
398 case ET_ButtonPress:
399 case ET_ButtonRelease:
400 case ET_Motion:
401 case ET_ProximityIn:
402 case ET_ProximityOut:
403 mtype = MASTER_POINTER;
404 break;
405 default:
406 mtype = MASTER_ATTACHED;
407 break;
408 }
409
410 mdev = GetMaster(sdev, mtype);
411 memcpy(copy, original, len);
412 ChangeDeviceID(mdev, copy);
413 FixUpEventForMaster(mdev, sdev, original, copy);
414
415 return mdev;
416 }
417
418 static void
mieqMoveToNewScreen(DeviceIntPtr dev,ScreenPtr screen,DeviceEvent * event)419 mieqMoveToNewScreen(DeviceIntPtr dev, ScreenPtr screen, DeviceEvent *event)
420 {
421 if (dev && screen && screen != DequeueScreen(dev)) {
422 int x = 0, y = 0;
423
424 DequeueScreen(dev) = screen;
425 x = event->root_x;
426 y = event->root_y;
427 NewCurrentScreen(dev, DequeueScreen(dev), x, y);
428 }
429 }
430
431 /**
432 * Post the given @event through the device hierarchy, as appropriate.
433 * Use this function if an event must be posted for a given device during the
434 * usual event processing cycle.
435 */
436 void
mieqProcessDeviceEvent(DeviceIntPtr dev,InternalEvent * event,ScreenPtr screen)437 mieqProcessDeviceEvent(DeviceIntPtr dev, InternalEvent *event, ScreenPtr screen)
438 {
439 mieqHandler handler;
440 DeviceIntPtr master;
441 InternalEvent mevent; /* master event */
442
443 verify_internal_event(event);
444
445 /* refuse events from disabled devices */
446 if (dev && !dev->enabled)
447 return;
448
449 /* Custom event handler */
450 handler = miEventQueue.handlers[event->any.type];
451
452 switch (event->any.type) {
453 /* Catch events that include valuator information and check if they
454 * are changing the screen */
455 case ET_Motion:
456 case ET_KeyPress:
457 case ET_KeyRelease:
458 case ET_ButtonPress:
459 case ET_ButtonRelease:
460 if (!handler)
461 mieqMoveToNewScreen(dev, screen, &event->device_event);
462 break;
463 case ET_TouchBegin:
464 case ET_TouchUpdate:
465 case ET_TouchEnd:
466 if (!handler && (event->device_event.flags & TOUCH_POINTER_EMULATED))
467 mieqMoveToNewScreen(dev, screen, &event->device_event);
468 break;
469 default:
470 break;
471 }
472 master = CopyGetMasterEvent(dev, event, &mevent);
473
474 if (master)
475 master->lastSlave = dev;
476
477 /* If someone's registered a custom event handler, let them
478 * steal it. */
479 if (handler) {
480 int screenNum = dev &&
481 DequeueScreen(dev) ? DequeueScreen(dev)->myNum : (screen ? screen->
482 myNum : 0);
483 handler(screenNum, event, dev);
484 /* Check for the SD's master in case the device got detached
485 * during event processing */
486 if (master && !IsFloating(dev))
487 handler(screenNum, &mevent, master);
488 }
489 else {
490 /* process slave first, then master */
491 dev->public.processInputProc(event, dev);
492
493 /* Check for the SD's master in case the device got detached
494 * during event processing */
495 if (master && !IsFloating(dev))
496 master->public.processInputProc(&mevent, master);
497 }
498 }
499
500 /* Call this from ProcessInputEvents(). */
501 void
mieqProcessInputEvents(void)502 mieqProcessInputEvents(void)
503 {
504 EventRec *e = NULL;
505 ScreenPtr screen;
506 InternalEvent event;
507 DeviceIntPtr dev = NULL, master = NULL;
508 static Bool inProcessInputEvents = FALSE;
509
510 input_lock();
511
512 /*
513 * report an error if mieqProcessInputEvents() is called recursively;
514 * this can happen, e.g., if something in the mieqProcessDeviceEvent()
515 * call chain calls UpdateCurrentTime() instead of UpdateCurrentTimeIf()
516 */
517 BUG_WARN_MSG(inProcessInputEvents, "[mi] mieqProcessInputEvents() called recursively.\n");
518 inProcessInputEvents = TRUE;
519
520 if (miEventQueue.dropped) {
521 ErrorF("[mi] EQ processing has resumed after %lu dropped events.\n",
522 (unsigned long) miEventQueue.dropped);
523 ErrorF
524 ("[mi] This may be caused by a misbehaving driver monopolizing the server's resources.\n");
525 miEventQueue.dropped = 0;
526 }
527
528 while (miEventQueue.head != miEventQueue.tail) {
529 e = &miEventQueue.events[miEventQueue.head];
530
531 event = *e->events;
532 dev = e->pDev;
533 screen = e->pScreen;
534
535 miEventQueue.head = (miEventQueue.head + 1) % miEventQueue.nevents;
536
537 input_unlock();
538
539 master = (dev) ? GetMaster(dev, MASTER_ATTACHED) : NULL;
540
541 if (screenIsSaved == SCREEN_SAVER_ON)
542 dixSaveScreens(serverClient, SCREEN_SAVER_OFF, ScreenSaverReset);
543 #ifdef DPMSExtension
544 else if (DPMSPowerLevel != DPMSModeOn)
545 SetScreenSaverTimer();
546
547 if (DPMSPowerLevel != DPMSModeOn)
548 DPMSSet(serverClient, DPMSModeOn);
549 #endif
550
551 mieqProcessDeviceEvent(dev, &event, screen);
552
553 /* Update the sprite now. Next event may be from different device. */
554 if (master &&
555 (event.any.type == ET_Motion ||
556 ((event.any.type == ET_TouchBegin ||
557 event.any.type == ET_TouchUpdate) &&
558 event.device_event.flags & TOUCH_POINTER_EMULATED)))
559 miPointerUpdateSprite(dev);
560
561 input_lock();
562 }
563
564 inProcessInputEvents = FALSE;
565
566 input_unlock();
567 }
568