~ubuntu-branches/ubuntu/gutsy/vnc4/gutsy

« back to all changes in this revision

Viewing changes to unix/xc/programs/Xserver/hw/darwin/darwinEvents.c

  • Committer: Bazaar Package Importer
  • Author(s): Ola Lundqvist
  • Date: 2006-05-15 20:35:17 UTC
  • mfrom: (1.1.2 upstream)
  • Revision ID: james.westby@ubuntu.com-20060515203517-l4lre1ku942mn26k
Tags: 4.1.1+X4.3.0-10
* Correction of critical security issue. Thanks to Martin Kogler
  <e9925248@student.tuwien.ac.at> that informed me about the issue,
  and provided the patch.
  This flaw was originally found by Steve Wiseman of intelliadmin.com.
* Applied patch from Javier Kohen <jkohen@users.sourceforge.net> that
  inform the user that only 8 first characters of the password will
  actually be used when typing more than 8 characters, closes:
  #355619.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Darwin event queue and event handling
 
3
 */
 
4
/*
 
5
Copyright (c) 2002 Torrey T. Lyons. All Rights Reserved.
 
6
 
 
7
This file is based on mieq.c by Keith Packard,
 
8
which contains the following copyright:
 
9
Copyright 1990, 1998  The Open Group
 
10
 
 
11
Permission to use, copy, modify, distribute, and sell this software and its
 
12
documentation for any purpose is hereby granted without fee, provided that
 
13
the above copyright notice appear in all copies and that both that
 
14
copyright notice and this permission notice appear in supporting
 
15
documentation.
 
16
 
 
17
The above copyright notice and this permission notice shall be included in
 
18
all copies or substantial portions of the Software.
 
19
 
 
20
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 
21
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 
22
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
 
23
OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
 
24
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 
25
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 
26
 
 
27
Except as contained in this notice, the name of The Open Group shall not be
 
28
used in advertising or otherwise to promote the sale, use or other dealings
 
29
in this Software without prior written authorization from The Open Group.
 
30
 */
 
31
 
 
32
#define NEED_EVENTS
 
33
#include   "X.h"
 
34
#include   "Xmd.h"
 
35
#include   "Xproto.h"
 
36
#include   "misc.h"
 
37
#include   "windowstr.h"
 
38
#include   "pixmapstr.h"
 
39
#include   "inputstr.h"
 
40
#include   "mi.h"
 
41
#include   "scrnintstr.h"
 
42
#include   "mipointer.h"
 
43
 
 
44
#include "darwin.h"
 
45
#include "quartz/quartz.h"
 
46
 
 
47
#include <sys/types.h>
 
48
#include <sys/uio.h>
 
49
#include <unistd.h>
 
50
#include <IOKit/hidsystem/IOLLEvent.h>
 
51
 
 
52
/* Fake button press/release for scroll wheel move. */
 
53
#define SCROLLWHEELUPFAKE       4
 
54
#define SCROLLWHEELDOWNFAKE     5
 
55
 
 
56
#define QUEUE_SIZE 256
 
57
 
 
58
typedef struct _Event {
 
59
    xEvent      event;
 
60
    ScreenPtr   pScreen;
 
61
} EventRec, *EventPtr;
 
62
 
 
63
typedef struct _EventQueue {
 
64
    HWEventQueueType    head, tail; /* long for SetInputCheck */
 
65
    CARD32      lastEventTime;      /* to avoid time running backwards */
 
66
    Bool        lastMotion;
 
67
    EventRec    events[QUEUE_SIZE]; /* static allocation for signals */
 
68
    DevicePtr   pKbd, pPtr;         /* device pointer, to get funcs */
 
69
    ScreenPtr   pEnqueueScreen;     /* screen events are being delivered to */
 
70
    ScreenPtr   pDequeueScreen;     /* screen events are being dispatched to */
 
71
} EventQueueRec, *EventQueuePtr;
 
72
 
 
73
static EventQueueRec darwinEventQueue;
 
74
 
 
75
 
 
76
/*
 
77
 * DarwinPressModifierMask
 
78
 *  Press or release the given modifier key, specified by its mask.
 
79
 */
 
80
static void DarwinPressModifierMask(
 
81
    xEvent *xe,      // must already have type, time and mouse location
 
82
    int mask)       // one of NX_*MASK constants
 
83
{
 
84
    int key = DarwinModifierNXMaskToNXKey(mask);
 
85
 
 
86
    if (key != -1) {
 
87
        int keycode = DarwinModifierNXKeyToNXKeycode(key, 0);
 
88
        if (keycode != 0) {
 
89
            xe->u.u.detail = keycode + MIN_KEYCODE;
 
90
            (*darwinEventQueue.pKbd->processInputProc)(xe,
 
91
                            (DeviceIntPtr)darwinEventQueue.pKbd, 1);
 
92
        }
 
93
    }
 
94
}
 
95
 
 
96
 
 
97
/*
 
98
 * DarwinUpdateModifiers
 
99
 *  Send events to update the modifier state.
 
100
 */
 
101
static void DarwinUpdateModifiers(
 
102
    xEvent *xe,         // event template with time and mouse position set
 
103
    int pressed,        // KeyPress or KeyRelease
 
104
    int flags )         // modifier flags that have changed
 
105
{
 
106
    xe->u.u.type = pressed;
 
107
    if (flags & NX_ALPHASHIFTMASK) {
 
108
        DarwinPressModifierMask(xe, NX_ALPHASHIFTMASK);
 
109
    }
 
110
    if (flags & NX_COMMANDMASK) {
 
111
        DarwinPressModifierMask(xe, NX_COMMANDMASK);
 
112
    }
 
113
    if (flags & NX_CONTROLMASK) {
 
114
        DarwinPressModifierMask(xe, NX_CONTROLMASK);
 
115
    }
 
116
    if (flags & NX_ALTERNATEMASK) {
 
117
        DarwinPressModifierMask(xe, NX_ALTERNATEMASK);
 
118
    }
 
119
    if (flags & NX_SHIFTMASK) {
 
120
        DarwinPressModifierMask(xe, NX_SHIFTMASK);
 
121
    }
 
122
    if (flags & NX_SECONDARYFNMASK) {
 
123
        DarwinPressModifierMask(xe, NX_SECONDARYFNMASK);
 
124
    }
 
125
}
 
126
 
 
127
 
 
128
/*
 
129
 * DarwinSimulateMouseClick
 
130
 *  Send a mouse click to X when multiple mouse buttons are simulated
 
131
 *  with modifier-clicks, such as command-click for button 2. The dix
 
132
 *  layer is told that the previously pressed modifier key(s) are
 
133
 *  released, the simulated click event is sent. After the mouse button
 
134
 *  is released, the modifier keys are reverted to their actual state,
 
135
 *  which may or may not be pressed at that point. This is usually
 
136
 *  closest to what the user wants. Ie. the user typically wants to
 
137
 *  simulate a button 2 press instead of Command-button 2.
 
138
 */
 
139
static void DarwinSimulateMouseClick(
 
140
    xEvent *xe,         // event template with time and
 
141
                        // mouse position filled in
 
142
    int whichButton,    // mouse button to be pressed
 
143
    int modifierMask)   // modifiers used for the fake click
 
144
{
 
145
    // first fool X into forgetting about the keys
 
146
    DarwinUpdateModifiers(xe, KeyRelease, modifierMask);
 
147
 
 
148
    // push the mouse button
 
149
    xe->u.u.type = ButtonPress;
 
150
    xe->u.u.detail = whichButton;
 
151
    (*darwinEventQueue.pPtr->processInputProc)
 
152
            (xe, (DeviceIntPtr)darwinEventQueue.pPtr, 1);
 
153
}
 
154
 
 
155
 
 
156
Bool
 
157
DarwinEQInit(
 
158
    DevicePtr pKbd,
 
159
    DevicePtr pPtr)
 
160
{
 
161
    darwinEventQueue.head = darwinEventQueue.tail = 0;
 
162
    darwinEventQueue.lastEventTime = GetTimeInMillis ();
 
163
    darwinEventQueue.pKbd = pKbd;
 
164
    darwinEventQueue.pPtr = pPtr;
 
165
    darwinEventQueue.pEnqueueScreen = screenInfo.screens[0];
 
166
    darwinEventQueue.pDequeueScreen = darwinEventQueue.pEnqueueScreen;
 
167
    SetInputCheck (&darwinEventQueue.head, &darwinEventQueue.tail);
 
168
    return TRUE;
 
169
}
 
170
 
 
171
 
 
172
/*
 
173
 * DarwinEQEnqueue
 
174
 *  Must be thread safe with ProcessInputEvents.
 
175
 *    DarwinEQEnqueue    - called from event gathering thread
 
176
 *    ProcessInputEvents - called from X server thread
 
177
 *  DarwinEQEnqueue should never be called from more than one thread.
 
178
 */
 
179
void
 
180
DarwinEQEnqueue(
 
181
    const xEvent *e)
 
182
{
 
183
    HWEventQueueType oldtail, newtail;
 
184
 
 
185
    oldtail = darwinEventQueue.tail;
 
186
 
 
187
    // mieqEnqueue() collapses successive motion events into one event.
 
188
    // This is difficult to do in a thread-safe way and rarely useful.
 
189
 
 
190
    newtail = oldtail + 1;
 
191
    if (newtail == QUEUE_SIZE)
 
192
        newtail = 0;
 
193
    /* Toss events which come in late */
 
194
    if (newtail == darwinEventQueue.head)
 
195
        return;
 
196
 
 
197
    darwinEventQueue.events[oldtail].event = *e;
 
198
    /*
 
199
     * Make sure that event times don't go backwards - this
 
200
     * is "unnecessary", but very useful
 
201
     */
 
202
    if (e->u.keyButtonPointer.time < darwinEventQueue.lastEventTime &&
 
203
        darwinEventQueue.lastEventTime - e->u.keyButtonPointer.time < 10000)
 
204
    {
 
205
        darwinEventQueue.events[oldtail].event.u.keyButtonPointer.time =
 
206
            darwinEventQueue.lastEventTime;
 
207
    }
 
208
    darwinEventQueue.events[oldtail].pScreen = darwinEventQueue.pEnqueueScreen;
 
209
 
 
210
    // Update the tail after the event is prepared
 
211
    darwinEventQueue.tail = newtail;
 
212
}
 
213
 
 
214
 
 
215
/*
 
216
 * DarwinEQPointerPost
 
217
 *  Post a pointer event. Used by the mipointer.c routines.
 
218
 */
 
219
void
 
220
DarwinEQPointerPost(
 
221
    xEvent *e)
 
222
{
 
223
    (*darwinEventQueue.pPtr->processInputProc)
 
224
            (e, (DeviceIntPtr)darwinEventQueue.pPtr, 1);
 
225
}
 
226
 
 
227
 
 
228
void
 
229
DarwinEQSwitchScreen(
 
230
    ScreenPtr   pScreen,
 
231
    Bool        fromDIX)
 
232
{
 
233
    darwinEventQueue.pEnqueueScreen = pScreen;
 
234
    if (fromDIX)
 
235
        darwinEventQueue.pDequeueScreen = pScreen;
 
236
}
 
237
 
 
238
 
 
239
/*
 
240
 * ProcessInputEvents
 
241
 *  Read and process events from the event queue until it is empty.
 
242
 */
 
243
void ProcessInputEvents(void)
 
244
{
 
245
    EventRec    *e;
 
246
    int         x, y;
 
247
    xEvent      xe;
 
248
    static int  old_flags = 0;  // last known modifier state
 
249
    // button number and modifier mask of currently pressed fake button
 
250
    static int darwinFakeMouseButtonDown = 0;
 
251
    static int darwinFakeMouseButtonMask = 0;
 
252
 
 
253
    // Empty the signaling pipe
 
254
    x = sizeof(xe);
 
255
    while (x == sizeof(xe)) {
 
256
        x = read(darwinEventFD, &xe, sizeof(xe));
 
257
    }
 
258
 
 
259
    while (darwinEventQueue.head != darwinEventQueue.tail)
 
260
    {
 
261
        if (screenIsSaved == SCREEN_SAVER_ON)
 
262
            SaveScreens (SCREEN_SAVER_OFF, ScreenSaverReset);
 
263
 
 
264
        e = &darwinEventQueue.events[darwinEventQueue.head];
 
265
        xe = e->event;
 
266
 
 
267
        // Shift from global screen coordinates to coordinates relative to
 
268
        // the origin of the current screen.
 
269
        xe.u.keyButtonPointer.rootX -= darwinMainScreenX +
 
270
                dixScreenOrigins[miPointerCurrentScreen()->myNum].x;
 
271
        xe.u.keyButtonPointer.rootY -= darwinMainScreenY +
 
272
                dixScreenOrigins[miPointerCurrentScreen()->myNum].y;
 
273
 
 
274
        /*
 
275
         * Assumption - screen switching can only occur on motion events
 
276
         */
 
277
        if (e->pScreen != darwinEventQueue.pDequeueScreen)
 
278
        {
 
279
            darwinEventQueue.pDequeueScreen = e->pScreen;
 
280
            x = xe.u.keyButtonPointer.rootX;
 
281
            y = xe.u.keyButtonPointer.rootY;
 
282
            if (darwinEventQueue.head == QUEUE_SIZE - 1)
 
283
                darwinEventQueue.head = 0;
 
284
            else
 
285
                ++darwinEventQueue.head;
 
286
            NewCurrentScreen (darwinEventQueue.pDequeueScreen, x, y);
 
287
        }
 
288
        else
 
289
        {
 
290
            if (darwinEventQueue.head == QUEUE_SIZE - 1)
 
291
                darwinEventQueue.head = 0;
 
292
            else
 
293
                ++darwinEventQueue.head;
 
294
            switch (xe.u.u.type) 
 
295
            {
 
296
            case KeyPress:
 
297
            case KeyRelease:
 
298
                xe.u.u.detail += MIN_KEYCODE;
 
299
                (*darwinEventQueue.pKbd->processInputProc)
 
300
                                (&xe, (DeviceIntPtr)darwinEventQueue.pKbd, 1);
 
301
                break;
 
302
 
 
303
            case ButtonPress:
 
304
                miPointerAbsoluteCursor(xe.u.keyButtonPointer.rootX,
 
305
                                        xe.u.keyButtonPointer.rootY,
 
306
                                        xe.u.keyButtonPointer.time);
 
307
                if (darwinFakeButtons && xe.u.u.detail == 1) {
 
308
                    // Mimic multi-button mouse with modifier-clicks
 
309
                    // If both sets of modifiers are pressed,
 
310
                    // button 2 is clicked.
 
311
                    if ((old_flags & darwinFakeMouse2Mask) ==
 
312
                        darwinFakeMouse2Mask)
 
313
                    {
 
314
                        DarwinSimulateMouseClick(&xe, 2, darwinFakeMouse2Mask);
 
315
                        darwinFakeMouseButtonDown = 2;
 
316
                        darwinFakeMouseButtonMask = darwinFakeMouse2Mask;
 
317
                        break;
 
318
                    }
 
319
                    else if ((old_flags & darwinFakeMouse3Mask) ==
 
320
                             darwinFakeMouse3Mask)
 
321
                    {
 
322
                        DarwinSimulateMouseClick(&xe, 3, darwinFakeMouse3Mask);
 
323
                        darwinFakeMouseButtonDown = 3;
 
324
                        darwinFakeMouseButtonMask = darwinFakeMouse3Mask;
 
325
                        break;
 
326
                    }
 
327
                }
 
328
                (*darwinEventQueue.pPtr->processInputProc)
 
329
                        (&xe, (DeviceIntPtr)darwinEventQueue.pPtr, 1);
 
330
                break;
 
331
 
 
332
            case ButtonRelease:
 
333
                miPointerAbsoluteCursor(xe.u.keyButtonPointer.rootX,
 
334
                                        xe.u.keyButtonPointer.rootY,
 
335
                                        xe.u.keyButtonPointer.time);
 
336
                if (darwinFakeButtons && xe.u.u.detail == 1 &&
 
337
                    darwinFakeMouseButtonDown)
 
338
                {
 
339
                    // If last mousedown was a fake click, don't check for
 
340
                    // mouse modifiers here. The user may have released the
 
341
                    // modifiers before the mouse button.
 
342
                    xe.u.u.detail = darwinFakeMouseButtonDown;
 
343
                    darwinFakeMouseButtonDown = 0;
 
344
                    (*darwinEventQueue.pPtr->processInputProc)
 
345
                            (&xe, (DeviceIntPtr)darwinEventQueue.pPtr, 1);
 
346
 
 
347
                    // Bring modifiers back up to date
 
348
                    DarwinUpdateModifiers(&xe, KeyPress,
 
349
                            darwinFakeMouseButtonMask & old_flags);
 
350
                    darwinFakeMouseButtonMask = 0;
 
351
                } else {
 
352
                    (*darwinEventQueue.pPtr->processInputProc)
 
353
                            (&xe, (DeviceIntPtr)darwinEventQueue.pPtr, 1);
 
354
                }
 
355
                break;
 
356
 
 
357
            case MotionNotify:
 
358
                miPointerAbsoluteCursor(xe.u.keyButtonPointer.rootX,
 
359
                                        xe.u.keyButtonPointer.rootY,
 
360
                                        xe.u.keyButtonPointer.time);
 
361
                break;
 
362
 
 
363
            case kXDarwinUpdateModifiers:
 
364
            {
 
365
                // Update modifier state.
 
366
                // Any amount of modifiers may have changed.
 
367
                int flags = xe.u.clientMessage.u.l.longs0;
 
368
                DarwinUpdateModifiers(&xe, KeyRelease,
 
369
                                      old_flags & ~flags);
 
370
                DarwinUpdateModifiers(&xe, KeyPress,
 
371
                                      ~old_flags & flags);
 
372
                old_flags = flags;
 
373
                break;
 
374
            }
 
375
 
 
376
            case kXDarwinUpdateButtons:
 
377
            {
 
378
                long hwDelta = xe.u.clientMessage.u.l.longs0;
 
379
                long hwButtons = xe.u.clientMessage.u.l.longs1;
 
380
                int i;
 
381
 
 
382
                for (i = 1; i < 5; i++) {
 
383
                    if (hwDelta & (1 << i)) {
 
384
                        // IOKit and X have different numbering for the
 
385
                        // middle and right mouse buttons.
 
386
                        if (i == 1) {
 
387
                            xe.u.u.detail = 3;
 
388
                        } else if (i == 2) {
 
389
                            xe.u.u.detail = 2;
 
390
                        } else {
 
391
                            xe.u.u.detail = i + 1;
 
392
                        }
 
393
                        if (hwButtons & (1 << i)) {
 
394
                            xe.u.u.type = ButtonPress;
 
395
                        } else {
 
396
                            xe.u.u.type = ButtonRelease;
 
397
                        }
 
398
                        (*darwinEventQueue.pPtr->processInputProc)
 
399
                                (&xe, (DeviceIntPtr)darwinEventQueue.pPtr, 1);
 
400
                    }
 
401
                }
 
402
                break;
 
403
            }
 
404
 
 
405
            case kXDarwinScrollWheel:
 
406
            {
 
407
                short count = xe.u.clientMessage.u.s.shorts0;
 
408
 
 
409
                if (count > 0) {
 
410
                    xe.u.u.detail = SCROLLWHEELUPFAKE;
 
411
                } else {
 
412
                    xe.u.u.detail = SCROLLWHEELDOWNFAKE;
 
413
                    count = -count;
 
414
                }
 
415
 
 
416
                for (; count; --count) {
 
417
                    xe.u.u.type = ButtonPress;
 
418
                    (*darwinEventQueue.pPtr->processInputProc)
 
419
                            (&xe, (DeviceIntPtr)darwinEventQueue.pPtr, 1);
 
420
                    xe.u.u.type = ButtonRelease;
 
421
                    (*darwinEventQueue.pPtr->processInputProc)
 
422
                            (&xe, (DeviceIntPtr)darwinEventQueue.pPtr, 1);
 
423
                }
 
424
                break;
 
425
            }
 
426
 
 
427
            default:
 
428
                if (quartz) {
 
429
                    QuartzProcessEvent(&xe);
 
430
                } else {
 
431
                    ErrorF("Unknown X event caught: %d\n", xe.u.u.type);
 
432
                }
 
433
            }
 
434
        }
 
435
    }
 
436
 
 
437
    miPointerUpdate();
 
438
}