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