First import
[xorg_rtime.git] / xorg-server-1.4 / hw / dmx / input / dmxeq.c
blob3e98fb799cee14af023a635d2c116105d8b84fff
1 /*
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
9 * documentation.
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
56 * SOFTWARE.
59 /** \file
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>
69 #endif
71 #define DMX_EQ_DEBUG 0
73 #include "dmx.h"
74 #include "dmxeq.h"
75 #include "dmxinput.h"
76 #include "dmxlog.h"
77 #include "dmxdpms.h"
79 #include "inputstr.h"
80 #include "scrnintstr.h" /* For screenInfo */
82 #ifdef XINPUT
83 #include <X11/extensions/XIproto.h>
84 #define EXTENSION_PROC_ARGS void *
85 #include "extinit.h" /* For LookupDeviceIntRec */
86 #endif
88 #if DMX_EQ_DEBUG
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)
91 #else
92 #define DMXDBG2(f,a,b)
93 #define DMXDBG5(f,a,b,c,d,e)
94 #endif
96 /** The size of our queue. (The queue provided by mi/mieq.c has a size
97 * of 256.) */
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. */
104 #ifdef XINPUT
105 deviceValuator valuator; /**< XInput device valuator information. */
106 #endif
107 } EventRec, *EventPtr;
109 /** Event queue. */
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)
134 return FALSE;
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);
146 return TRUE;
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
154 * the new event.
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;
165 Bool isMotion;
167 oldtail = dmxEventQueue.tail;
168 isMotion = e->u.u.type == MotionNotify;
169 if (isMotion
170 && dmxEventQueue.lastMotion
171 && oldtail != dmxEventQueue.head) {
172 if (oldtail == 0) oldtail = QUEUE_SIZE;
173 oldtail = oldtail - 1;
174 } else {
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;
187 #ifdef XINPUT
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);
195 #endif
197 /* Make sure that event times don't go
198 * backwards - this is "unnecessary",
199 * but very useful */
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;
215 #ifdef XINPUT
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);
222 if (!pDevice) {
223 dmxLog(dmxError, "dmxeqProcessInputEvents: id %d not found\n", id);
224 return;
227 if (!pDevice->public.processInputProc) {
228 dmxLog(dmxError,
229 "dmxeqProcessInputEvents: no processInputProc for"
230 " device id %d (%s)\n", id, pDevice->name);
231 return;
234 if (ev->deviceid & MORE_EVENTS) {
235 xe[1] = *(xEvent *)(&e->valuator);
236 pDevice->public.processInputProc(xe, pDevice, 2);
237 } else {
238 pDevice->public.processInputProc(xe, pDevice, 1);
241 #endif
244 * This function is called from #ProcessInputEvents() to remove events
245 * from the queue and process them.
247 void dmxeqProcessInputEvents(void)
249 EventRec *e;
250 int x, y;
251 xEvent xe[2];
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",
257 e->event.u.u.type,
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);
272 } else {
273 xe[0] = e->event;
274 if (dmxEventQueue.head == QUEUE_SIZE - 1) dmxEventQueue.head = 0;
275 else ++dmxEventQueue.head;
276 switch (xe[0].u.u.type) {
277 case KeyPress:
278 case KeyRelease:
279 if (!dmxEventQueue.pKbd) {
280 dmxLog(dmxError, "dmxeqProcessInputEvents: No keyboard\n");
281 return;
283 dmxEventQueue.pKbd
284 ->processInputProc(xe,
285 (DeviceIntPtr)dmxEventQueue.pKbd, 1);
286 break;
287 default:
288 #ifdef XINPUT
289 dmxeqProcessXInputEvent(xe, e);
290 break;
291 #endif
292 /* ifndef XINPUT, fall through */
293 case ButtonPress:
294 case ButtonRelease:
295 case MotionNotify:
296 if (!dmxEventQueue.pPtr) {
297 dmxLog(dmxError, "dmxeqProcessInputEvents: No mouse\n");
298 return;
300 dmxEventQueue.pPtr
301 ->processInputProc(xe,
302 (DeviceIntPtr)dmxEventQueue.pPtr, 1);
303 break;