diff options
Diffstat (limited to 'nx-X11/programs/Xserver/hw/darwin/darwinEvents.c')
-rw-r--r-- | nx-X11/programs/Xserver/hw/darwin/darwinEvents.c | 481 |
1 files changed, 481 insertions, 0 deletions
diff --git a/nx-X11/programs/Xserver/hw/darwin/darwinEvents.c b/nx-X11/programs/Xserver/hw/darwin/darwinEvents.c new file mode 100644 index 000000000..61100d9b3 --- /dev/null +++ b/nx-X11/programs/Xserver/hw/darwin/darwinEvents.c @@ -0,0 +1,481 @@ +/* + * Darwin event queue and event handling + */ +/* +Copyright (c) 2002-2004 Torrey T. Lyons. All Rights Reserved. +Copyright 2004 Kaleb S. KEITHLEY. All Rights Reserved. + +This file is based on mieq.c by Keith Packard, +which contains the following copyright: +Copyright 1990, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + */ +/* $XFree86: xc/programs/Xserver/hw/darwin/darwinEvents.c,v 1.6 2004/03/31 22:29:09 torrey Exp $ */ + +#define NEED_EVENTS +#include <X11/X.h> +#include <X11/Xmd.h> +#include <X11/Xproto.h> +#include "misc.h" +#include "windowstr.h" +#include "pixmapstr.h" +#include "inputstr.h" +#include "mi.h" +#include "scrnintstr.h" +#include "mipointer.h" + +#include "darwin.h" +#include "darwinKeyboard.h" + +#include <sys/types.h> +#include <sys/uio.h> +#include <unistd.h> +#include <IOKit/hidsystem/IOLLEvent.h> + +/* Fake button press/release for scroll wheel move. */ +#define SCROLLWHEELUPFAKE 4 +#define SCROLLWHEELDOWNFAKE 5 + +#define QUEUE_SIZE 256 + +typedef struct _Event { + xEvent event; + ScreenPtr pScreen; +} EventRec, *EventPtr; + +typedef struct _EventQueue { + HWEventQueueType head, tail; /* long for SetInputCheck */ + CARD32 lastEventTime; /* to avoid time running backwards */ + Bool lastMotion; + EventRec events[QUEUE_SIZE]; /* static allocation for signals */ + DevicePtr pKbd, pPtr; /* device pointer, to get funcs */ + ScreenPtr pEnqueueScreen; /* screen events are being delivered to */ + ScreenPtr pDequeueScreen; /* screen events are being dispatched to */ +} EventQueueRec, *EventQueuePtr; + +static EventQueueRec darwinEventQueue; + + +/* + * DarwinPressModifierMask + * Press or release the given modifier key, specified by its mask. + */ +static void DarwinPressModifierMask( + xEvent *xe, // must already have type, time and mouse location + int mask) // one of NX_*MASK constants +{ + int key = DarwinModifierNXMaskToNXKey(mask); + + if (key != -1) { + int keycode = DarwinModifierNXKeyToNXKeycode(key, 0); + if (keycode != 0) { + xe->u.u.detail = keycode + MIN_KEYCODE; + (*darwinEventQueue.pKbd->processInputProc)(xe, + (DeviceIntPtr)darwinEventQueue.pKbd, 1); + } + } +} + +#ifdef NX_DEVICELCTLKEYMASK +#define CONTROL_MASK(flags) (flags & (NX_DEVICELCTLKEYMASK|NX_DEVICERCTLKEYMASK)) +#else +#define CONTROL_MASK(flags) (NX_CONTROLMASK) +#endif /* NX_DEVICELCTLKEYMASK */ + +#ifdef NX_DEVICELSHIFTKEYMASK +#define SHIFT_MASK(flags) (flags & (NX_DEVICELSHIFTKEYMASK|NX_DEVICERSHIFTKEYMASK)) +#else +#define SHIFT_MASK(flags) (NX_SHIFTMASK) +#endif /* NX_DEVICELSHIFTKEYMASK */ + +#ifdef NX_DEVICELCMDKEYMASK +#define COMMAND_MASK(flags) (flags & (NX_DEVICELCMDKEYMASK|NX_DEVICERCMDKEYMASK)) +#else +#define COMMAND_MASK(flags) (NX_COMMANDMASK) +#endif /* NX_DEVICELCMDKEYMASK */ + +#ifdef NX_DEVICELALTKEYMASK +#define ALTERNATE_MASK(flags) (flags & (NX_DEVICELALTKEYMASK|NX_DEVICERALTKEYMASK)) +#else +#define ALTERNATE_MASK(flags) (NX_ALTERNATEMASK) +#endif /* NX_DEVICELALTKEYMASK */ + +/* + * DarwinUpdateModifiers + * Send events to update the modifier state. + */ +static void DarwinUpdateModifiers( + xEvent *xe, // event template with time and mouse position set + int pressed, // KeyPress or KeyRelease + int flags ) // modifier flags that have changed +{ + xe->u.u.type = pressed; + if (flags & NX_ALPHASHIFTMASK) { + DarwinPressModifierMask(xe, NX_ALPHASHIFTMASK); + } + if (flags & NX_COMMANDMASK) { + DarwinPressModifierMask(xe, COMMAND_MASK(flags)); + } + if (flags & NX_CONTROLMASK) { + DarwinPressModifierMask(xe, CONTROL_MASK(flags)); + } + if (flags & NX_ALTERNATEMASK) { + DarwinPressModifierMask(xe, ALTERNATE_MASK(flags)); + } + if (flags & NX_SHIFTMASK) { + DarwinPressModifierMask(xe, SHIFT_MASK(flags)); + } + if (flags & NX_SECONDARYFNMASK) { + DarwinPressModifierMask(xe, NX_SECONDARYFNMASK); + } +} + + +/* + * DarwinSimulateMouseClick + * Send a mouse click to X when multiple mouse buttons are simulated + * with modifier-clicks, such as command-click for button 2. The dix + * layer is told that the previously pressed modifier key(s) are + * released, the simulated click event is sent. After the mouse button + * is released, the modifier keys are reverted to their actual state, + * which may or may not be pressed at that point. This is usually + * closest to what the user wants. Ie. the user typically wants to + * simulate a button 2 press instead of Command-button 2. + */ +static void DarwinSimulateMouseClick( + xEvent *xe, // event template with time and + // mouse position filled in + int whichButton, // mouse button to be pressed + int modifierMask) // modifiers used for the fake click +{ + // first fool X into forgetting about the keys + DarwinUpdateModifiers(xe, KeyRelease, modifierMask); + + // push the mouse button + xe->u.u.type = ButtonPress; + xe->u.u.detail = whichButton; + (*darwinEventQueue.pPtr->processInputProc) + (xe, (DeviceIntPtr)darwinEventQueue.pPtr, 1); +} + + +Bool +DarwinEQInit( + DevicePtr pKbd, + DevicePtr pPtr) +{ + darwinEventQueue.head = darwinEventQueue.tail = 0; + darwinEventQueue.lastEventTime = GetTimeInMillis (); + darwinEventQueue.pKbd = pKbd; + darwinEventQueue.pPtr = pPtr; + darwinEventQueue.pEnqueueScreen = screenInfo.screens[0]; + darwinEventQueue.pDequeueScreen = darwinEventQueue.pEnqueueScreen; + SetInputCheck (&darwinEventQueue.head, &darwinEventQueue.tail); + return TRUE; +} + + +/* + * DarwinEQEnqueue + * Must be thread safe with ProcessInputEvents. + * DarwinEQEnqueue - called from event gathering thread + * ProcessInputEvents - called from X server thread + * DarwinEQEnqueue should never be called from more than one thread. + */ +void +DarwinEQEnqueue( + const xEvent *e) +{ + HWEventQueueType oldtail, newtail; + char byte = 0; + + oldtail = darwinEventQueue.tail; + + // mieqEnqueue() collapses successive motion events into one event. + // This is difficult to do in a thread-safe way and rarely useful. + + newtail = oldtail + 1; + if (newtail == QUEUE_SIZE) + newtail = 0; + /* Toss events which come in late */ + if (newtail == darwinEventQueue.head) + return; + + darwinEventQueue.events[oldtail].event = *e; + /* + * Make sure that event times don't go backwards - this + * is "unnecessary", but very useful + */ + if (e->u.keyButtonPointer.time < darwinEventQueue.lastEventTime && + darwinEventQueue.lastEventTime - e->u.keyButtonPointer.time < 10000) + { + darwinEventQueue.events[oldtail].event.u.keyButtonPointer.time = + darwinEventQueue.lastEventTime; + } + darwinEventQueue.events[oldtail].pScreen = darwinEventQueue.pEnqueueScreen; + + // Update the tail after the event is prepared + darwinEventQueue.tail = newtail; + + // Signal there is an event ready to handle + write(darwinEventWriteFD, &byte, 1); +} + + +/* + * DarwinEQPointerPost + * Post a pointer event. Used by the mipointer.c routines. + */ +void +DarwinEQPointerPost( + xEvent *e) +{ + (*darwinEventQueue.pPtr->processInputProc) + (e, (DeviceIntPtr)darwinEventQueue.pPtr, 1); +} + + +void +DarwinEQSwitchScreen( + ScreenPtr pScreen, + Bool fromDIX) +{ + darwinEventQueue.pEnqueueScreen = pScreen; + if (fromDIX) + darwinEventQueue.pDequeueScreen = pScreen; +} + + +/* + * ProcessInputEvents + * Read and process events from the event queue until it is empty. + */ +void ProcessInputEvents(void) +{ + EventRec *e; + int x, y; + xEvent xe; + static int old_flags = 0; // last known modifier state + // button number and modifier mask of currently pressed fake button + static int darwinFakeMouseButtonDown = 0; + static int darwinFakeMouseButtonMask = 0; + + // Empty the signaling pipe + x = sizeof(xe); + while (x == sizeof(xe)) { + x = read(darwinEventReadFD, &xe, sizeof(xe)); + } + + while (darwinEventQueue.head != darwinEventQueue.tail) + { + if (screenIsSaved == SCREEN_SAVER_ON) + SaveScreens (SCREEN_SAVER_OFF, ScreenSaverReset); + + e = &darwinEventQueue.events[darwinEventQueue.head]; + xe = e->event; + + // Shift from global screen coordinates to coordinates relative to + // the origin of the current screen. + xe.u.keyButtonPointer.rootX -= darwinMainScreenX + + dixScreenOrigins[miPointerCurrentScreen()->myNum].x; + xe.u.keyButtonPointer.rootY -= darwinMainScreenY + + dixScreenOrigins[miPointerCurrentScreen()->myNum].y; + + /* + * Assumption - screen switching can only occur on motion events + */ + if (e->pScreen != darwinEventQueue.pDequeueScreen) + { + darwinEventQueue.pDequeueScreen = e->pScreen; + x = xe.u.keyButtonPointer.rootX; + y = xe.u.keyButtonPointer.rootY; + if (darwinEventQueue.head == QUEUE_SIZE - 1) + darwinEventQueue.head = 0; + else + ++darwinEventQueue.head; + NewCurrentScreen (darwinEventQueue.pDequeueScreen, x, y); + } + else + { + if (darwinEventQueue.head == QUEUE_SIZE - 1) + darwinEventQueue.head = 0; + else + ++darwinEventQueue.head; + switch (xe.u.u.type) + { + case KeyPress: + if (old_flags == 0 + && darwinSyncKeymap && darwinKeymapFile == NULL) + { + /* See if keymap has changed. */ + + static unsigned int last_seed; + unsigned int this_seed; + + this_seed = DarwinModeSystemKeymapSeed(); + if (this_seed != last_seed) + { + last_seed = this_seed; + DarwinKeyboardReload(darwinKeyboard); + } + } + /* fall through */ + + case KeyRelease: + xe.u.u.detail += MIN_KEYCODE; + (*darwinEventQueue.pKbd->processInputProc) + (&xe, (DeviceIntPtr)darwinEventQueue.pKbd, 1); + break; + + case ButtonPress: + miPointerAbsoluteCursor(xe.u.keyButtonPointer.rootX, + xe.u.keyButtonPointer.rootY, + xe.u.keyButtonPointer.time); + if (darwinFakeButtons && xe.u.u.detail == 1) { + // Mimic multi-button mouse with modifier-clicks + // If both sets of modifiers are pressed, + // button 2 is clicked. + if ((old_flags & darwinFakeMouse2Mask) == + darwinFakeMouse2Mask) + { + DarwinSimulateMouseClick(&xe, 2, darwinFakeMouse2Mask); + darwinFakeMouseButtonDown = 2; + darwinFakeMouseButtonMask = darwinFakeMouse2Mask; + break; + } + else if ((old_flags & darwinFakeMouse3Mask) == + darwinFakeMouse3Mask) + { + DarwinSimulateMouseClick(&xe, 3, darwinFakeMouse3Mask); + darwinFakeMouseButtonDown = 3; + darwinFakeMouseButtonMask = darwinFakeMouse3Mask; + break; + } + } + (*darwinEventQueue.pPtr->processInputProc) + (&xe, (DeviceIntPtr)darwinEventQueue.pPtr, 1); + break; + + case ButtonRelease: + miPointerAbsoluteCursor(xe.u.keyButtonPointer.rootX, + xe.u.keyButtonPointer.rootY, + xe.u.keyButtonPointer.time); + if (darwinFakeButtons && xe.u.u.detail == 1 && + darwinFakeMouseButtonDown) + { + // If last mousedown was a fake click, don't check for + // mouse modifiers here. The user may have released the + // modifiers before the mouse button. + xe.u.u.detail = darwinFakeMouseButtonDown; + darwinFakeMouseButtonDown = 0; + (*darwinEventQueue.pPtr->processInputProc) + (&xe, (DeviceIntPtr)darwinEventQueue.pPtr, 1); + + // Bring modifiers back up to date + DarwinUpdateModifiers(&xe, KeyPress, + darwinFakeMouseButtonMask & old_flags); + darwinFakeMouseButtonMask = 0; + } else { + (*darwinEventQueue.pPtr->processInputProc) + (&xe, (DeviceIntPtr)darwinEventQueue.pPtr, 1); + } + break; + + case MotionNotify: + miPointerAbsoluteCursor(xe.u.keyButtonPointer.rootX, + xe.u.keyButtonPointer.rootY, + xe.u.keyButtonPointer.time); + break; + + case kXDarwinUpdateModifiers: + { + // Update modifier state. + // Any amount of modifiers may have changed. + int flags = xe.u.clientMessage.u.l.longs0; + DarwinUpdateModifiers(&xe, KeyRelease, + old_flags & ~flags); + DarwinUpdateModifiers(&xe, KeyPress, + ~old_flags & flags); + old_flags = flags; + break; + } + + case kXDarwinUpdateButtons: + { + long hwDelta = xe.u.clientMessage.u.l.longs0; + long hwButtons = xe.u.clientMessage.u.l.longs1; + int i; + + for (i = 1; i < 5; i++) { + if (hwDelta & (1 << i)) { + // IOKit and X have different numbering for the + // middle and right mouse buttons. + if (i == 1) { + xe.u.u.detail = 3; + } else if (i == 2) { + xe.u.u.detail = 2; + } else { + xe.u.u.detail = i + 1; + } + if (hwButtons & (1 << i)) { + xe.u.u.type = ButtonPress; + } else { + xe.u.u.type = ButtonRelease; + } + (*darwinEventQueue.pPtr->processInputProc) + (&xe, (DeviceIntPtr)darwinEventQueue.pPtr, 1); + } + } + break; + } + + case kXDarwinScrollWheel: + { + short count = xe.u.clientMessage.u.s.shorts0; + + if (count > 0) { + xe.u.u.detail = SCROLLWHEELUPFAKE; + } else { + xe.u.u.detail = SCROLLWHEELDOWNFAKE; + count = -count; + } + + for (; count; --count) { + xe.u.u.type = ButtonPress; + (*darwinEventQueue.pPtr->processInputProc) + (&xe, (DeviceIntPtr)darwinEventQueue.pPtr, 1); + xe.u.u.type = ButtonRelease; + (*darwinEventQueue.pPtr->processInputProc) + (&xe, (DeviceIntPtr)darwinEventQueue.pPtr, 1); + } + break; + } + + default: + // Check for mode specific event + DarwinModeProcessEvent(&xe); + } + } + } + + miPointerUpdate(); +} |