3 Copyright 1990, 1998 The Open Group
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
11 The above copyright notice and this permission notice shall be included in
12 all copies or substantial portions of the Software.
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.
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.
25 * Author: Keith Packard, MIT X Consortium
31 * Machine independent event queue
36 #include <dix-config.h>
41 #include <X11/Xproto.h>
43 #include "windowstr.h"
44 #include "pixmapstr.h"
46 #include "inpututils.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>
54 #include "exglobals.h"
59 #include <X11/extensions/dpmsconst.h>
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
69 #define EnqueueScreen(dev) dev->spriteInfo->sprite->pEnqueueScreen
70 #define DequeueScreen(dev) dev->spriteInfo->sprite->pDequeueScreen
72 typedef struct _Event
{
73 InternalEvent
*events
;
75 DeviceIntPtr pDev
; /* device this event _originated_ from */
76 } EventRec
, *EventPtr
;
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
;
88 static EventQueueRec miEventQueue
;
92 static pthread_mutex_t miEventQueueMutex
= PTHREAD_MUTEX_INITIALIZER
;
94 extern BOOL serverRunning
;
95 extern pthread_mutex_t serverRunningMutex
;
96 extern pthread_cond_t serverRunningCond
;
99 wait_for_server_init(void)
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
);
112 mieqNumEnqueued(EventQueuePtr eventQueue
)
114 size_t n_enqueued
= 0;
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
;
125 /* Pre-condition: Called with miEventQueueMutex held */
127 mieqGrowQueue(EventQueuePtr eventQueue
, size_t new_nevents
)
129 size_t i
, n_enqueued
, first_hunk
;
130 EventRec
*new_events
;
133 ErrorF("[mi] mieqGrowQueue called with a NULL eventQueue\n");
137 if (new_nevents
<= eventQueue
->nevents
)
140 new_events
= calloc(new_nevents
, sizeof(EventRec
));
141 if (new_events
== NULL
) {
142 ErrorF("[mi] mieqGrowQueue memory allocation error.\n");
146 n_enqueued
= mieqNumEnqueued(eventQueue
);
148 /* We block signals, so an mieqEnqueue triggered by SIGIO does not
149 * write to our queue as we are modifying it.
153 /* First copy the existing events */
154 first_hunk
= eventQueue
->nevents
- eventQueue
->head
;
156 &eventQueue
->events
[eventQueue
->head
],
157 first_hunk
* sizeof(EventRec
));
158 memcpy(&new_events
[first_hunk
],
159 eventQueue
->events
, eventQueue
->head
* sizeof(EventRec
));
161 /* Initialize the new portion */
162 for (i
= eventQueue
->nevents
; i
< new_nevents
; i
++) {
163 InternalEvent
*evlist
= InitEventList(1);
168 for (j
= 0; j
< i
; j
++)
169 FreeEventList(new_events
[j
].events
, 1);
174 new_events
[i
].events
= evlist
;
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
;
191 memset(&miEventQueue
, 0, sizeof(miEventQueue
));
192 miEventQueue
.lastEventTime
= GetTimeInMillis();
194 if (!mieqGrowQueue(&miEventQueue
, QUEUE_INITIAL_SIZE
))
195 FatalError("Could not allocate event queue.\n");
197 SetInputCheck(&miEventQueue
.head
, &miEventQueue
.tail
);
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
;
212 free(miEventQueue
.events
);
215 /* This function will determine if the given event is allowed to used the reserved
219 mieqReservedCandidate(InternalEvent
*e
)
221 switch (e
->any
.type
) {
223 case ET_ButtonRelease
:
227 case ET_RawKeyRelease
:
228 case ET_RawButtonRelease
:
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.
244 mieqEnqueue(DeviceIntPtr pDev
, InternalEvent
*e
)
246 unsigned int oldtail
= miEventQueue
.tail
;
254 wait_for_server_init();
255 pthread_mutex_lock(&miEventQueueMutex
);
258 verify_internal_event(e
);
260 n_enqueued
= mieqNumEnqueued(&miEventQueue
);
262 /* avoid merging events from different devices */
263 if (e
->any
.type
== ET_Motion
)
266 if (isMotion
&& isMotion
== miEventQueue
.lastMotion
&&
267 oldtail
!= miEventQueue
.head
) {
268 oldtail
= (oldtail
- 1) % miEventQueue
.nevents
;
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
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");
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");
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");
300 pthread_mutex_unlock(&miEventQueueMutex
);
305 evlen
= e
->any
.length
;
306 evt
= miEventQueue
.events
[oldtail
].events
;
307 memcpy(evt
, e
, evlen
);
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
;
316 miEventQueue
.lastEventTime
= evt
->any
.time
;
317 miEventQueue
.events
[oldtail
].pScreen
= pDev
? EnqueueScreen(pDev
) : NULL
;
318 miEventQueue
.events
[oldtail
].pDev
= pDev
;
320 miEventQueue
.lastMotion
= isMotion
;
321 miEventQueue
.tail
= (oldtail
+ 1) % miEventQueue
.nevents
;
323 pthread_mutex_unlock(&miEventQueueMutex
);
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.
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.
343 mieqSwitchScreen(DeviceIntPtr pDev
, ScreenPtr pScreen
, Bool set_dequeue_screen
)
346 pthread_mutex_lock(&miEventQueueMutex
);
348 EnqueueScreen(pDev
) = pScreen
;
349 if (set_dequeue_screen
)
350 DequeueScreen(pDev
) = pScreen
;
352 pthread_mutex_unlock(&miEventQueueMutex
);
357 mieqSetHandler(int event
, mieqHandler handler
)
360 pthread_mutex_lock(&miEventQueueMutex
);
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
);
366 miEventQueue
.handlers
[event
] = handler
;
368 pthread_mutex_unlock(&miEventQueueMutex
);
373 * Change the device id of the given event to the given device's id.
376 ChangeDeviceID(DeviceIntPtr dev
, InternalEvent
*event
)
378 switch (event
->any
.type
) {
383 case ET_ButtonRelease
:
385 case ET_ProximityOut
:
387 case ET_DeviceChanged
:
391 event
->device_event
.deviceid
= dev
->id
;
393 case ET_TouchOwnership
:
394 event
->touch_ownership_event
.deviceid
= dev
->id
;
401 case ET_RawKeyRelease
:
402 case ET_RawButtonPress
:
403 case ET_RawButtonRelease
:
405 case ET_RawTouchBegin
:
407 case ET_RawTouchUpdate
:
408 event
->raw_event
.deviceid
= dev
->id
;
411 case ET_BarrierLeave
:
412 event
->barrier_event
.deviceid
= dev
->id
;
415 ErrorF("[mi] Unknown event type (%d), cannot change id.\n",
421 FixUpEventForMaster(DeviceIntPtr mdev
, DeviceIntPtr sdev
,
422 InternalEvent
*original
, InternalEvent
*master
)
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
;
433 return; /* Should never happen */
435 master
->device_event
.detail
.button
= sdev
->button
->map
[btn
];
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.
447 CopyGetMasterEvent(DeviceIntPtr sdev
,
448 InternalEvent
*original
, InternalEvent
*copy
)
451 int len
= original
->any
.length
;
452 int type
= original
->any
.type
;
453 int mtype
; /* which master type? */
455 verify_internal_event(original
);
457 /* ET_XQuartz has sdev == NULL */
458 if (!sdev
|| IsMaster(sdev
) || IsFloating(sdev
))
462 if (type
== ET_DGAEvent
)
463 type
= original
->dga_event
.subtype
;
469 mtype
= MASTER_KEYBOARD
;
472 case ET_ButtonRelease
:
475 case ET_ProximityOut
:
476 mtype
= MASTER_POINTER
;
479 mtype
= MASTER_ATTACHED
;
483 mdev
= GetMaster(sdev
, mtype
);
484 memcpy(copy
, original
, len
);
485 ChangeDeviceID(mdev
, copy
);
486 FixUpEventForMaster(mdev
, sdev
, original
, copy
);
492 mieqMoveToNewScreen(DeviceIntPtr dev
, ScreenPtr screen
, DeviceEvent
*event
)
494 if (dev
&& screen
&& screen
!= DequeueScreen(dev
)) {
497 DequeueScreen(dev
) = screen
;
500 NewCurrentScreen(dev
, DequeueScreen(dev
), x
, y
);
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.
510 mieqProcessDeviceEvent(DeviceIntPtr dev
, InternalEvent
*event
, ScreenPtr screen
)
514 InternalEvent mevent
; /* master event */
516 verify_internal_event(event
);
518 /* Custom event handler */
519 handler
= miEventQueue
.handlers
[event
->any
.type
];
521 switch (event
->any
.type
) {
522 /* Catch events that include valuator information and check if they
523 * are changing the screen */
528 case ET_ButtonRelease
:
530 mieqMoveToNewScreen(dev
, screen
, &event
->device_event
);
535 if (!handler
&& (event
->device_event
.flags
& TOUCH_POINTER_EMULATED
))
536 mieqMoveToNewScreen(dev
, screen
, &event
->device_event
);
541 master
= CopyGetMasterEvent(dev
, event
, &mevent
);
544 master
->lastSlave
= dev
;
546 /* If someone's registered a custom event handler, let them
549 int screenNum
= dev
&&
550 DequeueScreen(dev
) ? DequeueScreen(dev
)->myNum
: (screen
? screen
->
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
);
559 /* process slave first, then master */
560 dev
->public.processInputProc(event
, dev
);
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
);
569 /* Call this from ProcessInputEvents(). */
571 mieqProcessInputEvents(void)
575 static InternalEvent event
;
576 DeviceIntPtr dev
= NULL
, master
= NULL
;
580 pthread_mutex_lock(&miEventQueueMutex
);
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");
594 if (miEventQueue
.dropped
) {
595 ErrorF("[mi] EQ processing has resumed after %lu dropped events.\n",
596 miEventQueue
.dropped
);
598 ("[mi] This may be caused my a misbehaving driver monopolizing the server's resources.\n");
599 miEventQueue
.dropped
= 0;
602 while (miEventQueue
.head
!= miEventQueue
.tail
) {
603 e
= &miEventQueue
.events
[miEventQueue
.head
];
609 miEventQueue
.head
= (miEventQueue
.head
+ 1) % miEventQueue
.nevents
;
612 pthread_mutex_unlock(&miEventQueueMutex
);
615 master
= (dev
) ? GetMaster(dev
, MASTER_ATTACHED
) : NULL
;
617 if (screenIsSaved
== SCREEN_SAVER_ON
)
618 dixSaveScreens(serverClient
, SCREEN_SAVER_OFF
, ScreenSaverReset
);
620 else if (DPMSPowerLevel
!= DPMSModeOn
)
621 SetScreenSaverTimer();
623 if (DPMSPowerLevel
!= DPMSModeOn
)
624 DPMSSet(serverClient
, DPMSModeOn
);
627 mieqProcessDeviceEvent(dev
, &event
, screen
);
629 /* Update the sprite now. Next event may be from different device. */
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
);
638 pthread_mutex_lock(&miEventQueueMutex
);
642 pthread_mutex_unlock(&miEventQueueMutex
);