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
29 * dmxeq.c is derived from mi/mieq.c so that XInput events can be handled
31 * Modified by: Rickard E. (Rik) Faith <faith@redhat.com>
33 * Copyright 2002-2003 Red Hat Inc., Durham, North Carolina.
35 * All Rights Reserved.
37 * Permission is hereby granted, free of charge, to any person obtaining
38 * a copy of this software and associated documentation files (the
39 * "Software"), to deal in the Software without restriction, including
40 * without limitation on the rights to use, copy, modify, merge,
41 * publish, distribute, sublicense, and/or sell copies of the Software,
42 * and to permit persons to whom the Software is furnished to do so,
43 * subject to the following conditions:
45 * The above copyright notice and this permission notice (including the
46 * next paragraph) shall be included in all copies or substantial
47 * portions of the Software.
49 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
50 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
51 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
52 * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS
53 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
54 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
55 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
60 * This file provides an event queue that knows about XInput events.
61 * All of the code is based on mi/mieq.c and was modified as little as
62 * possible to provide XInput event support (the copyright and some of
63 * the comments are from The Open Group, Keith Packard, MIT X
64 * Consortium). (Another example of similar code is provided in
65 * hw/xfree86/common/xf86Xinput.c.) */
67 #ifdef HAVE_DMX_CONFIG_H
68 #include <dmx-config.h>
71 #define DMX_EQ_DEBUG 0
80 #include "scrnintstr.h" /* For screenInfo */
83 #include <X11/extensions/XIproto.h>
84 #define EXTENSION_PROC_ARGS void *
85 #include "extinit.h" /* For LookupDeviceIntRec */
89 #define DMXDBG2(f,a,b) dmxLog(dmxDebug,f,a,b)
90 #define DMXDBG5(f,a,b,c,d,e) dmxLog(dmxDebug,f,a,b,c,d,e)
92 #define DMXDBG2(f,a,b)
93 #define DMXDBG5(f,a,b,c,d,e)
96 /** The size of our queue. (The queue provided by mi/mieq.c has a size
98 #define QUEUE_SIZE 256
100 /** Information about the event. */
101 typedef struct _Event
{
102 xEvent event
; /**< Event. */
103 ScreenPtr pScreen
; /**< Screen on which event occurred. */
105 deviceValuator valuator
; /**< XInput device valuator information. */
107 } EventRec
, *EventPtr
;
110 typedef struct _EventQueue
{
111 HWEventQueueType head
; /**< Queue head; must be long for SetInputCheck. */
112 HWEventQueueType tail
; /**< Queue tail; must be long for SetInputCheck. */
113 CARD32 lastEventTime
; /**< To avoid time running backwards. */
114 Bool lastMotion
; /**< True if last event was motion. */
115 EventRec events
[QUEUE_SIZE
]; /**< Static allocation for signals. */
116 DevicePtr pKbd
, pPtr
; /**< Device pointers (to get funcs) */
117 ScreenPtr pEnqueueScreen
;/**< Screen events are delivered to. */
118 ScreenPtr pDequeueScreen
;/**< Screen events are dispatched to. */
119 } EventQueueRec
, *EventQueuePtr
;
121 static EventQueueRec dmxEventQueue
;
122 static Bool dmxeqInitializedFlag
= FALSE
;
124 Bool
dmxeqInitialized(void)
126 return dmxeqInitializedFlag
;
129 Bool
dmxeqInit(DevicePtr pKbd
, DevicePtr pPtr
)
131 static unsigned long dmxGeneration
= 0;
133 if (dmxGeneration
== serverGeneration
&& dmxeqInitializedFlag
)
135 dmxGeneration
= serverGeneration
;
136 dmxeqInitializedFlag
= TRUE
;
137 dmxEventQueue
.head
= 0;
138 dmxEventQueue
.tail
= 0;
139 dmxEventQueue
.lastEventTime
= GetTimeInMillis();
140 dmxEventQueue
.pKbd
= pKbd
;
141 dmxEventQueue
.pPtr
= pPtr
;
142 dmxEventQueue
.lastMotion
= FALSE
;
143 dmxEventQueue
.pEnqueueScreen
= screenInfo
.screens
[0];
144 dmxEventQueue
.pDequeueScreen
= dmxEventQueue
.pEnqueueScreen
;
145 SetInputCheck(&dmxEventQueue
.head
, &dmxEventQueue
.tail
);
150 * This function adds an event to the end of the queue. If the event is
151 * an XInput event, then the next event (the valuator event) is also
152 * stored in the queue. If the new event has a time before the time of
153 * the last event currently on the queue, then the time is updated for
156 * Must be reentrant with ProcessInputEvents. Assumption: dmxeqEnqueue
157 * will never be interrupted. If this is called from both signal
158 * handlers and regular code, make sure the signal is suspended when
159 * called from regular code.
162 void dmxeqEnqueue(xEvent
*e
)
164 HWEventQueueType oldtail
, newtail
;
167 oldtail
= dmxEventQueue
.tail
;
168 isMotion
= e
->u
.u
.type
== MotionNotify
;
170 && dmxEventQueue
.lastMotion
171 && oldtail
!= dmxEventQueue
.head
) {
172 if (oldtail
== 0) oldtail
= QUEUE_SIZE
;
173 oldtail
= oldtail
- 1;
175 newtail
= oldtail
+ 1;
176 if (newtail
== QUEUE_SIZE
) newtail
= 0;
177 /* Toss events which come in late */
178 if (newtail
== dmxEventQueue
.head
) return;
179 dmxEventQueue
.tail
= newtail
;
181 DMXDBG2("dmxeqEnqueue %d %d\n", dmxEventQueue
.head
, dmxEventQueue
.tail
);
182 dmxEventQueue
.lastMotion
= isMotion
;
183 dmxEventQueue
.events
[oldtail
].pScreen
= dmxEventQueue
.pEnqueueScreen
;
185 /* Store the event in the queue */
186 dmxEventQueue
.events
[oldtail
].event
= *e
;
189 /* If this is an XInput event, store the
190 * valuator event, too */
191 deviceKeyButtonPointer
*ev
= (deviceKeyButtonPointer
*)e
;
192 if (e
->u
.u
.type
>= LASTEvent
&& (ev
->deviceid
& MORE_EVENTS
))
193 dmxEventQueue
.events
[oldtail
].valuator
= *(deviceValuator
*)(ev
+1);
197 /* Make sure that event times don't go
198 * backwards - this is "unnecessary",
200 if (e
->u
.keyButtonPointer
.time
< dmxEventQueue
.lastEventTime
201 && dmxEventQueue
.lastEventTime
- e
->u
.keyButtonPointer
.time
< 10000) {
202 dmxEventQueue
.events
[oldtail
].event
.u
.keyButtonPointer
.time
=
203 dmxEventQueue
.lastEventTime
;
207 /** Make \a pScreen the new screen for enqueueing events. If \a fromDIX
208 * is TRUE, also make \a pScreen the new screen for dequeuing events. */
209 void dmxeqSwitchScreen(ScreenPtr pScreen
, Bool fromDIX
)
211 dmxEventQueue
.pEnqueueScreen
= pScreen
;
212 if (fromDIX
) dmxEventQueue
.pDequeueScreen
= pScreen
;
216 static void dmxeqProcessXInputEvent(xEvent
*xe
, EventRec
*e
)
218 deviceKeyButtonPointer
*ev
= (deviceKeyButtonPointer
*)xe
;
219 int id
= ev
->deviceid
& DEVICE_BITS
;
220 DeviceIntPtr pDevice
= LookupDeviceIntRec(id
);
223 dmxLog(dmxError
, "dmxeqProcessInputEvents: id %d not found\n", id
);
227 if (!pDevice
->public.processInputProc
) {
229 "dmxeqProcessInputEvents: no processInputProc for"
230 " device id %d (%s)\n", id
, pDevice
->name
);
234 if (ev
->deviceid
& MORE_EVENTS
) {
235 xe
[1] = *(xEvent
*)(&e
->valuator
);
236 pDevice
->public.processInputProc(xe
, pDevice
, 2);
238 pDevice
->public.processInputProc(xe
, pDevice
, 1);
244 * This function is called from #ProcessInputEvents() to remove events
245 * from the queue and process them.
247 void dmxeqProcessInputEvents(void)
253 while (dmxEventQueue
.head
!= dmxEventQueue
.tail
) {
254 dmxDPMSWakeup(); /* Handles screen saver and DPMS */
255 e
= &dmxEventQueue
.events
[dmxEventQueue
.head
];
256 DMXDBG5("dmxeqProcessInputEvents: type=%d screen=%p,%p root=%d,%d\n",
258 e
->pScreen
, dmxEventQueue
.pDequeueScreen
,
259 e
->event
.u
.keyButtonPointer
.rootX
,
260 e
->event
.u
.keyButtonPointer
.rootY
);
262 * Assumption - screen switching can only occur on core motion events
264 if (e
->event
.u
.u
.type
== MotionNotify
265 && e
->pScreen
!= dmxEventQueue
.pDequeueScreen
) {
266 dmxEventQueue
.pDequeueScreen
= e
->pScreen
;
267 x
= e
->event
.u
.keyButtonPointer
.rootX
;
268 y
= e
->event
.u
.keyButtonPointer
.rootY
;
269 if (dmxEventQueue
.head
== QUEUE_SIZE
- 1) dmxEventQueue
.head
= 0;
270 else ++dmxEventQueue
.head
;
271 NewCurrentScreen(dmxEventQueue
.pDequeueScreen
, x
, y
);
274 if (dmxEventQueue
.head
== QUEUE_SIZE
- 1) dmxEventQueue
.head
= 0;
275 else ++dmxEventQueue
.head
;
276 switch (xe
[0].u
.u
.type
) {
279 if (!dmxEventQueue
.pKbd
) {
280 dmxLog(dmxError
, "dmxeqProcessInputEvents: No keyboard\n");
284 ->processInputProc(xe
,
285 (DeviceIntPtr
)dmxEventQueue
.pKbd
, 1);
289 dmxeqProcessXInputEvent(xe
, e
);
292 /* ifndef XINPUT, fall through */
296 if (!dmxEventQueue
.pPtr
) {
297 dmxLog(dmxError
, "dmxeqProcessInputEvents: No mouse\n");
301 ->processInputProc(xe
,
302 (DeviceIntPtr
)dmxEventQueue
.pPtr
, 1);