~ubuntu-branches/ubuntu/intrepid/xserver-xgl/intrepid

« back to all changes in this revision

Viewing changes to hw/dmx/input/dmxeq.c

  • Committer: Bazaar Package Importer
  • Author(s): Matthew Garrett
  • Date: 2006-02-13 14:21:43 UTC
  • Revision ID: james.westby@ubuntu.com-20060213142143-mad6z9xzem7hzxz9
Tags: upstream-7.0.0
ImportĀ upstreamĀ versionĀ 7.0.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* $XFree86$ */
 
2
/*
 
3
 * $Xorg: mieq.c,v 1.4 2001/02/09 02:05:20 xorgcvs Exp $
 
4
 *
 
5
 * Copyright 1990, 1998  The Open Group
 
6
 *
 
7
 * Permission to use, copy, modify, distribute, and sell this software and its
 
8
 * documentation for any purpose is hereby granted without fee, provided that
 
9
 * the above copyright notice appear in all copies and that both that
 
10
 * copyright notice and this permission notice appear in supporting
 
11
 * documentation.
 
12
 *
 
13
 * The above copyright notice and this permission notice shall be included in
 
14
 * all copies or substantial portions of the Software.
 
15
 *
 
16
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 
17
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 
18
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
 
19
 * OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
 
20
 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 
21
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 
22
 *
 
23
 * Except as contained in this notice, the name of The Open Group shall not be
 
24
 * used in advertising or otherwise to promote the sale, use or other dealings
 
25
 * in this Software without prior written authorization from The Open Group.
 
26
 *
 
27
 * Author:  Keith Packard, MIT X Consortium
 
28
 */
 
29
 
 
30
/*
 
31
 * dmxeq.c is derived from mi/mieq.c so that XInput events can be handled
 
32
 *
 
33
 * Modified by: Rickard E. (Rik) Faith <faith@redhat.com>
 
34
 *
 
35
 * Copyright 2002-2003 Red Hat Inc., Durham, North Carolina.
 
36
 *
 
37
 * All Rights Reserved.
 
38
 *
 
39
 * Permission is hereby granted, free of charge, to any person obtaining
 
40
 * a copy of this software and associated documentation files (the
 
41
 * "Software"), to deal in the Software without restriction, including
 
42
 * without limitation on the rights to use, copy, modify, merge,
 
43
 * publish, distribute, sublicense, and/or sell copies of the Software,
 
44
 * and to permit persons to whom the Software is furnished to do so,
 
45
 * subject to the following conditions:
 
46
 *
 
47
 * The above copyright notice and this permission notice (including the
 
48
 * next paragraph) shall be included in all copies or substantial
 
49
 * portions of the Software.
 
50
 *
 
51
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 
52
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 
53
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 
54
 * NON-INFRINGEMENT.  IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS
 
55
 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
 
56
 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 
57
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 
58
 * SOFTWARE.
 
59
 */
 
60
 
 
61
/** \file
 
62
 * This file provides an event queue that knows about XInput events.
 
63
 * All of the code is based on mi/mieq.c and was modified as little as
 
64
 * possible to provide XInput event support (the copyright and some of
 
65
 * the comments are from The Open Group, Keith Packard, MIT X
 
66
 * Consortium).  (Another example of similar code is provided in
 
67
 * hw/xfree86/common/xf86Xinput.c.) */
 
68
 
 
69
#ifdef HAVE_DMX_CONFIG_H
 
70
#include <dmx-config.h>
 
71
#endif
 
72
 
 
73
#define DMX_EQ_DEBUG 0
 
74
 
 
75
#include "dmx.h"
 
76
#include "dmxeq.h"
 
77
#include "dmxinput.h"
 
78
#include "dmxlog.h"
 
79
#include "dmxdpms.h"
 
80
 
 
81
#include "inputstr.h"
 
82
#include "scrnintstr.h"         /* For screenInfo */
 
83
 
 
84
#ifdef XINPUT
 
85
#include <X11/extensions/XIproto.h>
 
86
#define EXTENSION_PROC_ARGS void *
 
87
#include "extinit.h"            /* For LookupDeviceIntRec */
 
88
#endif
 
89
 
 
90
#if DMX_EQ_DEBUG
 
91
#define DMXDBG2(f,a,b)           dmxLog(dmxDebug,f,a,b)
 
92
#define DMXDBG5(f,a,b,c,d,e)     dmxLog(dmxDebug,f,a,b,c,d,e)
 
93
#else
 
94
#define DMXDBG2(f,a,b)
 
95
#define DMXDBG5(f,a,b,c,d,e)
 
96
#endif
 
97
 
 
98
/** The size of our queue.  (The queue provided by mi/mieq.c has a size
 
99
 * of 256.) */
 
100
#define QUEUE_SIZE  256
 
101
 
 
102
/** Information about the event. */
 
103
typedef struct _Event {
 
104
    xEvent         event;    /**< Event. */
 
105
    ScreenPtr      pScreen;  /**< Screen on which event occurred. */
 
106
#ifdef XINPUT
 
107
    deviceValuator valuator; /**< XInput device valuator information. */
 
108
#endif
 
109
} EventRec, *EventPtr;
 
110
 
 
111
/** Event queue. */
 
112
typedef struct _EventQueue {
 
113
    HWEventQueueType head; /**< Queue head; must be long for SetInputCheck. */ 
 
114
    HWEventQueueType tail; /**< Queue tail; must be long for SetInputCheck. */ 
 
115
    CARD32           lastEventTime; /**< To avoid time running backwards. */
 
116
    Bool             lastMotion;    /**< True if last event was motion.  */
 
117
    EventRec         events[QUEUE_SIZE]; /**< Static allocation for signals. */
 
118
    DevicePtr        pKbd, pPtr;    /**< Device pointers (to get funcs) */
 
119
    ScreenPtr        pEnqueueScreen;/**< Screen events are delivered to. */
 
120
    ScreenPtr        pDequeueScreen;/**< Screen events are dispatched to. */
 
121
} EventQueueRec, *EventQueuePtr;
 
122
 
 
123
static EventQueueRec dmxEventQueue;
 
124
static Bool          dmxeqInitializedFlag = FALSE;
 
125
 
 
126
Bool dmxeqInitialized(void)
 
127
{
 
128
    return dmxeqInitializedFlag;
 
129
}
 
130
 
 
131
Bool dmxeqInit(DevicePtr pKbd, DevicePtr pPtr)
 
132
{
 
133
    static unsigned long dmxGeneration = 0;
 
134
    
 
135
    if (dmxGeneration == serverGeneration && dmxeqInitializedFlag)
 
136
        return FALSE;
 
137
    dmxGeneration                = serverGeneration;
 
138
    dmxeqInitializedFlag         = TRUE;
 
139
    dmxEventQueue.head           = 0;
 
140
    dmxEventQueue.tail           = 0;
 
141
    dmxEventQueue.lastEventTime  = GetTimeInMillis();
 
142
    dmxEventQueue.pKbd           = pKbd;
 
143
    dmxEventQueue.pPtr           = pPtr;
 
144
    dmxEventQueue.lastMotion     = FALSE;
 
145
    dmxEventQueue.pEnqueueScreen = screenInfo.screens[0];
 
146
    dmxEventQueue.pDequeueScreen = dmxEventQueue.pEnqueueScreen;
 
147
    SetInputCheck(&dmxEventQueue.head, &dmxEventQueue.tail);
 
148
    return TRUE;
 
149
}
 
150
 
 
151
/**
 
152
 * This function adds an event to the end of the queue.  If the event is
 
153
 * an XInput event, then the next event (the valuator event) is also
 
154
 * stored in the queue.  If the new event has a time before the time of
 
155
 * the last event currently on the queue, then the time is updated for
 
156
 * the new event.
 
157
 *
 
158
 * Must be reentrant with ProcessInputEvents.  Assumption: dmxeqEnqueue
 
159
 * will never be interrupted.  If this is called from both signal
 
160
 * handlers and regular code, make sure the signal is suspended when
 
161
 * called from regular code.
 
162
 */
 
163
 
 
164
void dmxeqEnqueue(xEvent *e)
 
165
{
 
166
    HWEventQueueType oldtail, newtail;
 
167
    Bool             isMotion;
 
168
 
 
169
    oldtail                               = dmxEventQueue.tail;
 
170
    isMotion                              = e->u.u.type == MotionNotify;
 
171
    if (isMotion
 
172
        && dmxEventQueue.lastMotion
 
173
        && oldtail != dmxEventQueue.head) {
 
174
        if (oldtail == 0) oldtail = QUEUE_SIZE;
 
175
        oldtail = oldtail - 1;
 
176
    } else {
 
177
        newtail = oldtail + 1;
 
178
        if (newtail == QUEUE_SIZE) newtail = 0;
 
179
        /* Toss events which come in late */
 
180
        if (newtail == dmxEventQueue.head) return;
 
181
        dmxEventQueue.tail = newtail;
 
182
    }
 
183
    DMXDBG2("dmxeqEnqueue %d %d\n", dmxEventQueue.head, dmxEventQueue.tail);
 
184
    dmxEventQueue.lastMotion              = isMotion;
 
185
    dmxEventQueue.events[oldtail].pScreen = dmxEventQueue.pEnqueueScreen;
 
186
 
 
187
                                /* Store the event in the queue */
 
188
    dmxEventQueue.events[oldtail].event   = *e;
 
189
#ifdef XINPUT
 
190
    {
 
191
                                /* If this is an XInput event, store the
 
192
                                 * valuator event, too */
 
193
        deviceKeyButtonPointer *ev = (deviceKeyButtonPointer *)e;
 
194
        if (e->u.u.type >= LASTEvent && (ev->deviceid & MORE_EVENTS))
 
195
            dmxEventQueue.events[oldtail].valuator = *(deviceValuator *)(ev+1);
 
196
    }
 
197
#endif
 
198
 
 
199
                                /* Make sure that event times don't go
 
200
                                 * backwards - this is "unnecessary",
 
201
                                 * but very useful */
 
202
    if (e->u.keyButtonPointer.time < dmxEventQueue.lastEventTime
 
203
        && dmxEventQueue.lastEventTime - e->u.keyButtonPointer.time < 10000) {
 
204
        dmxEventQueue.events[oldtail].event.u.keyButtonPointer.time =
 
205
            dmxEventQueue.lastEventTime;
 
206
    }
 
207
}
 
208
 
 
209
/** Make \a pScreen the new screen for enqueueing events.  If \a fromDIX
 
210
 * is TRUE, also make \a pScreen the new screen for dequeuing events. */
 
211
void dmxeqSwitchScreen(ScreenPtr pScreen, Bool fromDIX)
 
212
{
 
213
    dmxEventQueue.pEnqueueScreen = pScreen;
 
214
    if (fromDIX) dmxEventQueue.pDequeueScreen = pScreen;
 
215
}
 
216
 
 
217
#ifdef XINPUT
 
218
static void dmxeqProcessXInputEvent(xEvent *xe, EventRec *e)
 
219
{
 
220
    deviceKeyButtonPointer *ev     = (deviceKeyButtonPointer *)xe;
 
221
    int                    id      = ev->deviceid & DEVICE_BITS;
 
222
    DeviceIntPtr           pDevice = LookupDeviceIntRec(id);
 
223
    
 
224
    if (!pDevice) {
 
225
        dmxLog(dmxError, "dmxeqProcessInputEvents: id %d not found\n", id);
 
226
        return;
 
227
    }
 
228
 
 
229
    if (!pDevice->public.processInputProc) {
 
230
        dmxLog(dmxError,
 
231
               "dmxeqProcessInputEvents: no processInputProc for"
 
232
               " device id %d (%s)\n", id, pDevice->name);
 
233
        return;
 
234
    }
 
235
    
 
236
    if (ev->deviceid & MORE_EVENTS) {
 
237
        xe[1] = *(xEvent *)(&e->valuator);
 
238
        pDevice->public.processInputProc(xe, pDevice, 2);
 
239
    } else {
 
240
        pDevice->public.processInputProc(xe, pDevice, 1);
 
241
    }
 
242
}
 
243
#endif
 
244
 
 
245
/**
 
246
 * This function is called from #ProcessInputEvents() to remove events
 
247
 * from the queue and process them.
 
248
 */
 
249
void dmxeqProcessInputEvents(void)
 
250
{
 
251
    EventRec    *e;
 
252
    int         x, y;
 
253
    xEvent      xe[2];
 
254
 
 
255
    while (dmxEventQueue.head != dmxEventQueue.tail) {
 
256
        dmxDPMSWakeup();        /* Handles screen saver and DPMS */
 
257
        e = &dmxEventQueue.events[dmxEventQueue.head];
 
258
        DMXDBG5("dmxeqProcessInputEvents: type=%d screen=%p,%p root=%d,%d\n",
 
259
                e->event.u.u.type,
 
260
                e->pScreen, dmxEventQueue.pDequeueScreen,
 
261
                e->event.u.keyButtonPointer.rootX,
 
262
                e->event.u.keyButtonPointer.rootY);
 
263
        /*
 
264
         * Assumption - screen switching can only occur on core motion events
 
265
         */
 
266
        if (e->event.u.u.type == MotionNotify
 
267
            && e->pScreen != dmxEventQueue.pDequeueScreen) {
 
268
            dmxEventQueue.pDequeueScreen = e->pScreen;
 
269
            x = e->event.u.keyButtonPointer.rootX;
 
270
            y = e->event.u.keyButtonPointer.rootY;
 
271
            if (dmxEventQueue.head == QUEUE_SIZE - 1) dmxEventQueue.head = 0;
 
272
            else                                      ++dmxEventQueue.head;
 
273
            NewCurrentScreen(dmxEventQueue.pDequeueScreen, x, y);
 
274
        } else {
 
275
            xe[0] = e->event;
 
276
            if (dmxEventQueue.head == QUEUE_SIZE - 1) dmxEventQueue.head = 0;
 
277
            else                                      ++dmxEventQueue.head;
 
278
            switch (xe[0].u.u.type) {
 
279
            case KeyPress:
 
280
            case KeyRelease:
 
281
                if (!dmxEventQueue.pKbd) {
 
282
                    dmxLog(dmxError, "dmxeqProcessInputEvents: No keyboard\n");
 
283
                    return;
 
284
                }
 
285
                dmxEventQueue.pKbd
 
286
                    ->processInputProc(xe,
 
287
                                       (DeviceIntPtr)dmxEventQueue.pKbd, 1);
 
288
                break;
 
289
            default:
 
290
#ifdef XINPUT
 
291
                dmxeqProcessXInputEvent(xe, e);
 
292
                break;
 
293
#endif
 
294
                /* ifndef XINPUT, fall through */
 
295
            case ButtonPress:
 
296
            case ButtonRelease:
 
297
            case MotionNotify:
 
298
                if (!dmxEventQueue.pPtr) {
 
299
                    dmxLog(dmxError, "dmxeqProcessInputEvents: No mouse\n");
 
300
                    return;
 
301
                }
 
302
                dmxEventQueue.pPtr
 
303
                    ->processInputProc(xe,
 
304
                                       (DeviceIntPtr)dmxEventQueue.pPtr, 1);
 
305
                break;
 
306
            }
 
307
        }
 
308
    }
 
309
}