14642e01fSmrg/*
235c4bbdfSmrg * Darwin event queue and event handling
335c4bbdfSmrg *
435c4bbdfSmrg * Copyright 2007-2008 Apple Inc.
535c4bbdfSmrg * Copyright 2004 Kaleb S. KEITHLEY. All Rights Reserved.
635c4bbdfSmrg * Copyright (c) 2002-2004 Torrey T. Lyons. All Rights Reserved.
735c4bbdfSmrg *
835c4bbdfSmrg * This file is based on mieq.c by Keith Packard,
935c4bbdfSmrg * which contains the following copyright:
1035c4bbdfSmrg * Copyright 1990, 1998  The Open Group
1135c4bbdfSmrg *
1235c4bbdfSmrg *
1335c4bbdfSmrg * Copyright (c) 2002-2012 Apple Inc. All rights reserved.
1435c4bbdfSmrg *
1535c4bbdfSmrg * Permission is hereby granted, free of charge, to any person
1635c4bbdfSmrg * obtaining a copy of this software and associated documentation files
1735c4bbdfSmrg * (the "Software"), to deal in the Software without restriction,
1835c4bbdfSmrg * including without limitation the rights to use, copy, modify, merge,
1935c4bbdfSmrg * publish, distribute, sublicense, and/or sell copies of the Software,
2035c4bbdfSmrg * and to permit persons to whom the Software is furnished to do so,
2135c4bbdfSmrg * subject to the following conditions:
2235c4bbdfSmrg *
2335c4bbdfSmrg * The above copyright notice and this permission notice shall be
2435c4bbdfSmrg * included in all copies or substantial portions of the Software.
2535c4bbdfSmrg *
2635c4bbdfSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
2735c4bbdfSmrg * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
2835c4bbdfSmrg * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
2935c4bbdfSmrg * NONINFRINGEMENT.  IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT
3035c4bbdfSmrg * HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
3135c4bbdfSmrg * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
3235c4bbdfSmrg * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
3335c4bbdfSmrg * DEALINGS IN THE SOFTWARE.
3435c4bbdfSmrg *
3535c4bbdfSmrg * Except as contained in this notice, the name(s) of the above
3635c4bbdfSmrg * copyright holders shall not be used in advertising or otherwise to
3735c4bbdfSmrg * promote the sale, use or other dealings in this Software without
3835c4bbdfSmrg * prior written authorization.
394642e01fSmrg */
404642e01fSmrg
414642e01fSmrg#include "sanitizedCarbon.h"
424642e01fSmrg
434642e01fSmrg#ifdef HAVE_DIX_CONFIG_H
444642e01fSmrg#include <dix-config.h>
454642e01fSmrg#endif
464642e01fSmrg
4735c4bbdfSmrg#include <X11/X.h>
4835c4bbdfSmrg#include <X11/Xmd.h>
4935c4bbdfSmrg#include <X11/Xproto.h>
5035c4bbdfSmrg#include "misc.h"
5135c4bbdfSmrg#include "windowstr.h"
5235c4bbdfSmrg#include "pixmapstr.h"
5335c4bbdfSmrg#include "inputstr.h"
5435c4bbdfSmrg#include "inpututils.h"
5535c4bbdfSmrg#include "eventstr.h"
5635c4bbdfSmrg#include "mi.h"
5735c4bbdfSmrg#include "scrnintstr.h"
5835c4bbdfSmrg#include "mipointer.h"
5935c4bbdfSmrg#include "os.h"
6035c4bbdfSmrg#include "exglobals.h"
614642e01fSmrg
624642e01fSmrg#include "darwin.h"
634642e01fSmrg#include "quartz.h"
644642e01fSmrg#include "quartzKeyboard.h"
656747b715Smrg#include "quartzRandR.h"
664642e01fSmrg#include "darwinEvents.h"
674642e01fSmrg
684642e01fSmrg#include <sys/types.h>
694642e01fSmrg#include <sys/uio.h>
704642e01fSmrg#include <unistd.h>
714642e01fSmrg#include <pthread.h>
724642e01fSmrg#include <errno.h>
739ace9065Smrg#include <time.h>
744642e01fSmrg
754642e01fSmrg#include <IOKit/hidsystem/IOLLEvent.h>
764642e01fSmrg
776747b715Smrg#include <X11/extensions/applewmconst.h>
784642e01fSmrg#include "applewmExt.h"
794642e01fSmrg
804642e01fSmrg/* FIXME: Abstract this better */
8135c4bbdfSmrgextern Bool
8235c4bbdfSmrgQuartzModeEventHandler(int screenNum, XQuartzEvent *e, DeviceIntPtr dev);
834642e01fSmrg
846747b715Smrgint darwin_all_modifier_flags = 0;  // last known modifier state
856747b715Smrgint darwin_all_modifier_mask = 0;
866747b715Smrgint darwin_x11_modifier_mask = 0;
874642e01fSmrg
884642e01fSmrg#define FD_ADD_MAX 128
894642e01fSmrgstatic int fd_add[FD_ADD_MAX];
904642e01fSmrgint fd_add_count = 0;
914642e01fSmrgstatic pthread_mutex_t fd_add_lock = PTHREAD_MUTEX_INITIALIZER;
924642e01fSmrgstatic pthread_cond_t fd_add_ready_cond = PTHREAD_COND_INITIALIZER;
934642e01fSmrgstatic pthread_t fd_add_tid = NULL;
944642e01fSmrg
951b5d61b8Smrgstatic BOOL mieqInitialized;
961b5d61b8Smrgstatic pthread_mutex_t mieqInitializedMutex = PTHREAD_MUTEX_INITIALIZER;
971b5d61b8Smrgstatic pthread_cond_t mieqInitializedCond = PTHREAD_COND_INITIALIZER;
984642e01fSmrg
991b5d61b8Smrg_X_NOTSAN
1001b5d61b8Smrgextern inline void
1011b5d61b8Smrgwait_for_mieq_init(void)
1021b5d61b8Smrg{
1031b5d61b8Smrg    if (!mieqInitialized) {
1041b5d61b8Smrg        pthread_mutex_lock(&mieqInitializedMutex);
1051b5d61b8Smrg        while (!mieqInitialized) {
1061b5d61b8Smrg            pthread_cond_wait(&mieqInitializedCond, &mieqInitializedMutex);
1071b5d61b8Smrg        }
1081b5d61b8Smrg        pthread_mutex_unlock(&mieqInitializedMutex);
1091b5d61b8Smrg    }
1101b5d61b8Smrg}
1111b5d61b8Smrg
1121b5d61b8Smrg_X_NOTSAN
1131b5d61b8Smrgstatic inline void
1141b5d61b8Smrgsignal_mieq_init(void)
1151b5d61b8Smrg{
1161b5d61b8Smrg    pthread_mutex_lock(&mieqInitializedMutex);
1171b5d61b8Smrg    mieqInitialized = TRUE;
1181b5d61b8Smrg    pthread_cond_broadcast(&mieqInitializedCond);
1191b5d61b8Smrg    pthread_mutex_unlock(&mieqInitializedMutex);
1201b5d61b8Smrg}
1214642e01fSmrg
1224642e01fSmrg/*** Pthread Magics ***/
12335c4bbdfSmrgstatic pthread_t
12435c4bbdfSmrgcreate_thread(void *(*func)(void *), void *arg)
12535c4bbdfSmrg{
1264642e01fSmrg    pthread_attr_t attr;
1274642e01fSmrg    pthread_t tid;
1284642e01fSmrg
12935c4bbdfSmrg    pthread_attr_init(&attr);
13035c4bbdfSmrg    pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM);
13135c4bbdfSmrg    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
13235c4bbdfSmrg    pthread_create(&tid, &attr, func, arg);
13335c4bbdfSmrg    pthread_attr_destroy(&attr);
1344642e01fSmrg
1354642e01fSmrg    return tid;
1364642e01fSmrg}
1374642e01fSmrg
1384642e01fSmrg/*
1394642e01fSmrg * DarwinPressModifierKey
1404642e01fSmrg * Press or release the given modifier key (one of NX_MODIFIERKEY_* constants)
1414642e01fSmrg */
14235c4bbdfSmrgstatic void
14335c4bbdfSmrgDarwinPressModifierKey(int pressed, int key)
14435c4bbdfSmrg{
1454642e01fSmrg    int keycode = DarwinModifierNXKeyToNXKeycode(key, 0);
1464642e01fSmrg
1474642e01fSmrg    if (keycode == 0) {
1484642e01fSmrg        ErrorF("DarwinPressModifierKey bad keycode: key=%d\n", key);
1494642e01fSmrg        return;
1504642e01fSmrg    }
1514642e01fSmrg
1524642e01fSmrg    DarwinSendKeyboardEvents(pressed, keycode);
1534642e01fSmrg}
1544642e01fSmrg
1554642e01fSmrg/*
1564642e01fSmrg * DarwinUpdateModifiers
1574642e01fSmrg *  Send events to update the modifier state.
1584642e01fSmrg */
1594642e01fSmrg
1606747b715Smrgstatic int darwin_x11_modifier_mask_list[] = {
1614642e01fSmrg#ifdef NX_DEVICELCMDKEYMASK
16235c4bbdfSmrg    NX_DEVICELCTLKEYMASK,   NX_DEVICERCTLKEYMASK,
1634642e01fSmrg    NX_DEVICELSHIFTKEYMASK, NX_DEVICERSHIFTKEYMASK,
16435c4bbdfSmrg    NX_DEVICELCMDKEYMASK,   NX_DEVICERCMDKEYMASK,
16535c4bbdfSmrg    NX_DEVICELALTKEYMASK,   NX_DEVICERALTKEYMASK,
1664642e01fSmrg#else
16735c4bbdfSmrg    NX_CONTROLMASK,         NX_SHIFTMASK,          NX_COMMANDMASK,
16835c4bbdfSmrg    NX_ALTERNATEMASK,
1694642e01fSmrg#endif
1704642e01fSmrg    NX_ALPHASHIFTMASK,
1714642e01fSmrg    0
1724642e01fSmrg};
1734642e01fSmrg
17435c4bbdfSmrgstatic int darwin_all_modifier_mask_additions[] = { NX_SECONDARYFNMASK, 0 };
1756747b715Smrg
17635c4bbdfSmrgstatic void
17735c4bbdfSmrgDarwinUpdateModifiers(int pressed,                    // KeyPress or KeyRelease
17835c4bbdfSmrg                      int flags)                      // modifier flags that have changed
1794642e01fSmrg{
1804642e01fSmrg    int *f;
1814642e01fSmrg    int key;
1824642e01fSmrg
1834642e01fSmrg    /* Capslock is special.  This mask is the state of capslock (on/off),
1844642e01fSmrg     * not the state of the button.  Hopefully we can find a better solution.
1854642e01fSmrg     */
18635c4bbdfSmrg    if (NX_ALPHASHIFTMASK & flags) {
1874642e01fSmrg        DarwinPressModifierKey(KeyPress, NX_MODIFIERKEY_ALPHALOCK);
1884642e01fSmrg        DarwinPressModifierKey(KeyRelease, NX_MODIFIERKEY_ALPHALOCK);
1894642e01fSmrg    }
19035c4bbdfSmrg
19135c4bbdfSmrg    for (f = darwin_x11_modifier_mask_list; *f; f++)
19235c4bbdfSmrg        if (*f & flags && *f != NX_ALPHASHIFTMASK) {
1934642e01fSmrg            key = DarwinModifierNXMaskToNXKey(*f);
19435c4bbdfSmrg            if (key == -1)
19535c4bbdfSmrg                ErrorF("DarwinUpdateModifiers: Unsupported NXMask: 0x%x\n",
19635c4bbdfSmrg                       *f);
1974642e01fSmrg            else
1984642e01fSmrg                DarwinPressModifierKey(pressed, key);
1994642e01fSmrg        }
2004642e01fSmrg}
2014642e01fSmrg
2024642e01fSmrg/* Generic handler for Xquartz-specifc events.  When possible, these should
2034642e01fSmrg   be moved into their own individual functions and set as handlers using
2044642e01fSmrg   mieqSetHandler. */
2054642e01fSmrg
20635c4bbdfSmrgstatic void
20735c4bbdfSmrgDarwinEventHandler(int screenNum, InternalEvent *ie, DeviceIntPtr dev)
20835c4bbdfSmrg{
2096747b715Smrg    XQuartzEvent *e = &(ie->xquartz_event);
2106747b715Smrg
21135c4bbdfSmrg    switch (e->subtype) {
21235c4bbdfSmrg    case kXquartzControllerNotify:
21335c4bbdfSmrg        DEBUG_LOG("kXquartzControllerNotify\n");
21435c4bbdfSmrg        AppleWMSendEvent(AppleWMControllerNotify,
21535c4bbdfSmrg                         AppleWMControllerNotifyMask,
21635c4bbdfSmrg                         e->data[0],
21735c4bbdfSmrg                         e->data[1]);
21835c4bbdfSmrg        break;
21935c4bbdfSmrg
22035c4bbdfSmrg    case kXquartzPasteboardNotify:
22135c4bbdfSmrg        DEBUG_LOG("kXquartzPasteboardNotify\n");
22235c4bbdfSmrg        AppleWMSendEvent(AppleWMPasteboardNotify,
22335c4bbdfSmrg                         AppleWMPasteboardNotifyMask,
22435c4bbdfSmrg                         e->data[0],
22535c4bbdfSmrg                         e->data[1]);
22635c4bbdfSmrg        break;
22735c4bbdfSmrg
22835c4bbdfSmrg    case kXquartzActivate:
22935c4bbdfSmrg        DEBUG_LOG("kXquartzActivate\n");
23035c4bbdfSmrg        QuartzShow();
23135c4bbdfSmrg        AppleWMSendEvent(AppleWMActivationNotify,
23235c4bbdfSmrg                         AppleWMActivationNotifyMask,
23335c4bbdfSmrg                         AppleWMIsActive, 0);
23435c4bbdfSmrg        break;
23535c4bbdfSmrg
23635c4bbdfSmrg    case kXquartzDeactivate:
23735c4bbdfSmrg        DEBUG_LOG("kXquartzDeactivate\n");
23835c4bbdfSmrg        AppleWMSendEvent(AppleWMActivationNotify,
23935c4bbdfSmrg                         AppleWMActivationNotifyMask,
24035c4bbdfSmrg                         AppleWMIsInactive, 0);
24135c4bbdfSmrg        QuartzHide();
24235c4bbdfSmrg        break;
24335c4bbdfSmrg
24435c4bbdfSmrg    case kXquartzReloadPreferences:
24535c4bbdfSmrg        DEBUG_LOG("kXquartzReloadPreferences\n");
24635c4bbdfSmrg        AppleWMSendEvent(AppleWMActivationNotify,
24735c4bbdfSmrg                         AppleWMActivationNotifyMask,
24835c4bbdfSmrg                         AppleWMReloadPreferences, 0);
24935c4bbdfSmrg        break;
25035c4bbdfSmrg
25135c4bbdfSmrg    case kXquartzToggleFullscreen:
25235c4bbdfSmrg        DEBUG_LOG("kXquartzToggleFullscreen\n");
25335c4bbdfSmrg        if (XQuartzIsRootless)
25435c4bbdfSmrg            ErrorF(
25535c4bbdfSmrg                "Ignoring kXquartzToggleFullscreen because of rootless mode.");
25635c4bbdfSmrg        else
25735c4bbdfSmrg            QuartzRandRToggleFullscreen();
25835c4bbdfSmrg        break;
25935c4bbdfSmrg
26035c4bbdfSmrg    case kXquartzSetRootless:
26135c4bbdfSmrg        DEBUG_LOG("kXquartzSetRootless\n");
26235c4bbdfSmrg        if (e->data[0]) {
26335c4bbdfSmrg            QuartzRandRSetFakeRootless();
26435c4bbdfSmrg        }
26535c4bbdfSmrg        else {
26635c4bbdfSmrg            QuartzRandRSetFakeFullscreen(FALSE);
26735c4bbdfSmrg        }
26835c4bbdfSmrg        break;
26935c4bbdfSmrg
27035c4bbdfSmrg    case kXquartzSetRootClip:
27135c4bbdfSmrg        QuartzSetRootClip(e->data[0]);
27235c4bbdfSmrg        break;
27335c4bbdfSmrg
27435c4bbdfSmrg    case kXquartzQuit:
27535c4bbdfSmrg        GiveUp(0);
27635c4bbdfSmrg        break;
27735c4bbdfSmrg
27835c4bbdfSmrg    case kXquartzSpaceChanged:
27935c4bbdfSmrg        DEBUG_LOG("kXquartzSpaceChanged\n");
28035c4bbdfSmrg        QuartzSpaceChanged(e->data[0]);
28135c4bbdfSmrg        break;
28235c4bbdfSmrg
28335c4bbdfSmrg    case kXquartzListenOnOpenFD:
28435c4bbdfSmrg        ErrorF("Calling ListenOnOpenFD() for new fd: %d\n", (int)e->data[0]);
28535c4bbdfSmrg        ListenOnOpenFD((int)e->data[0], 1);
28635c4bbdfSmrg        break;
28735c4bbdfSmrg
28835c4bbdfSmrg    case kXquartzReloadKeymap:
28935c4bbdfSmrg        DarwinKeyboardReloadHandler();
29035c4bbdfSmrg        break;
29135c4bbdfSmrg
29235c4bbdfSmrg    case kXquartzDisplayChanged:
29335c4bbdfSmrg        DEBUG_LOG("kXquartzDisplayChanged\n");
29435c4bbdfSmrg        QuartzUpdateScreens();
29535c4bbdfSmrg
29635c4bbdfSmrg        /* Update our RandR info */
29735c4bbdfSmrg        QuartzRandRUpdateFakeModes(TRUE);
29835c4bbdfSmrg        break;
29935c4bbdfSmrg
30035c4bbdfSmrg    default:
30135c4bbdfSmrg        if (!QuartzModeEventHandler(screenNum, e, dev))
30235c4bbdfSmrg            ErrorF("Unknown application defined event type %d.\n", e->subtype);
30335c4bbdfSmrg    }
3044642e01fSmrg}
3054642e01fSmrg
30635c4bbdfSmrgvoid
30735c4bbdfSmrgDarwinListenOnOpenFD(int fd)
30835c4bbdfSmrg{
3094642e01fSmrg    ErrorF("DarwinListenOnOpenFD: %d\n", fd);
31035c4bbdfSmrg
3114642e01fSmrg    pthread_mutex_lock(&fd_add_lock);
31235c4bbdfSmrg    if (fd_add_count < FD_ADD_MAX)
3134642e01fSmrg        fd_add[fd_add_count++] = fd;
3144642e01fSmrg    else
3154642e01fSmrg        ErrorF("FD Addition buffer at max.  Dropping fd addition request.\n");
3164642e01fSmrg
3174642e01fSmrg    pthread_cond_broadcast(&fd_add_ready_cond);
3184642e01fSmrg    pthread_mutex_unlock(&fd_add_lock);
3194642e01fSmrg}
3204642e01fSmrg
32135c4bbdfSmrgstatic void *
32235c4bbdfSmrgDarwinProcessFDAdditionQueue_thread(void *args)
32335c4bbdfSmrg{
3249ace9065Smrg    /* TODO: Possibly adjust this to no longer be a race... maybe trigger this
3259ace9065Smrg     *       once a client connects and claims to be the WM.
3269ace9065Smrg     *
3279ace9065Smrg     * From ajax:
3289ace9065Smrg     * There's already an internal callback chain for setting selection [in 1.5]
3299ace9065Smrg     * ownership.  See the CallSelectionCallback at the bottom of
3309ace9065Smrg     * ProcSetSelectionOwner, and xfixes/select.c for an example of how to hook
3319ace9065Smrg     * into it.
3329ace9065Smrg     */
3339ace9065Smrg
3349ace9065Smrg    struct timespec sleep_for;
3359ace9065Smrg    struct timespec sleep_remaining;
3369ace9065Smrg
3379ace9065Smrg    sleep_for.tv_sec = 3;
3389ace9065Smrg    sleep_for.tv_nsec = 0;
3399ace9065Smrg
34035c4bbdfSmrg    ErrorF(
34135c4bbdfSmrg        "X11.app: DarwinProcessFDAdditionQueue_thread: Sleeping to allow xinitrc to catchup.\n");
34235c4bbdfSmrg    while (nanosleep(&sleep_for, &sleep_remaining) != 0) {
3439ace9065Smrg        sleep_for = sleep_remaining;
3449ace9065Smrg    }
3459ace9065Smrg
3464642e01fSmrg    pthread_mutex_lock(&fd_add_lock);
34735c4bbdfSmrg    while (true) {
34835c4bbdfSmrg        while (fd_add_count) {
34935c4bbdfSmrg            DarwinSendDDXEvent(kXquartzListenOnOpenFD, 1,
35035c4bbdfSmrg                               fd_add[--fd_add_count]);
3514642e01fSmrg        }
3524642e01fSmrg        pthread_cond_wait(&fd_add_ready_cond, &fd_add_lock);
3534642e01fSmrg    }
3549ace9065Smrg
3559ace9065Smrg    return NULL;
3564642e01fSmrg}
3574642e01fSmrg
35835c4bbdfSmrgBool
35935c4bbdfSmrgDarwinEQInit(void)
36035c4bbdfSmrg{
3616747b715Smrg    int *p;
3626747b715Smrg
36335c4bbdfSmrg    for (p = darwin_x11_modifier_mask_list; *p; p++) {
3646747b715Smrg        darwin_x11_modifier_mask |= *p;
3656747b715Smrg    }
36635c4bbdfSmrg
36735c4bbdfSmrg    darwin_all_modifier_mask = darwin_x11_modifier_mask;
36835c4bbdfSmrg    for (p = darwin_all_modifier_mask_additions; *p; p++) {
3696747b715Smrg        darwin_all_modifier_mask |= *p;
3704642e01fSmrg    }
37135c4bbdfSmrg
3726747b715Smrg    mieqInit();
3736747b715Smrg    mieqSetHandler(ET_XQuartz, DarwinEventHandler);
3744642e01fSmrg
37535c4bbdfSmrg    if (!fd_add_tid)
3764642e01fSmrg        fd_add_tid = create_thread(DarwinProcessFDAdditionQueue_thread, NULL);
37735c4bbdfSmrg
3781b5d61b8Smrg    signal_mieq_init();
3791b5d61b8Smrg
3804642e01fSmrg    return TRUE;
3814642e01fSmrg}
3824642e01fSmrg
38335c4bbdfSmrgvoid
38435c4bbdfSmrgDarwinEQFini(void)
38535c4bbdfSmrg{
38635c4bbdfSmrg    mieqFini();
38735c4bbdfSmrg}
38835c4bbdfSmrg
3894642e01fSmrg/*
3904642e01fSmrg * ProcessInputEvents
3914642e01fSmrg *  Read and process events from the event queue until it is empty.
3924642e01fSmrg */
39335c4bbdfSmrgvoid
39435c4bbdfSmrgProcessInputEvents(void)
39535c4bbdfSmrg{
3966747b715Smrg    char nullbyte;
39735c4bbdfSmrg    int x = sizeof(nullbyte);
3984642e01fSmrg
3994642e01fSmrg    mieqProcessInputEvents();
4004642e01fSmrg
4014642e01fSmrg    // Empty the signaling pipe
4026747b715Smrg    while (x == sizeof(nullbyte)) {
40335c4bbdfSmrg        x = read(darwinEventReadFD, &nullbyte, sizeof(nullbyte));
4044642e01fSmrg    }
4054642e01fSmrg}
4064642e01fSmrg
4074642e01fSmrg/* Sends a null byte down darwinEventWriteFD, which will cause the
4084642e01fSmrg   Dispatch() event loop to check out event queue */
40935c4bbdfSmrgstatic void
41035c4bbdfSmrgDarwinPokeEQ(void)
41135c4bbdfSmrg{
41235c4bbdfSmrg    char nullbyte = 0;
41335c4bbdfSmrg    //  <daniels> oh, i ... er ... christ.
41435c4bbdfSmrg    write(darwinEventWriteFD, &nullbyte, sizeof(nullbyte));
4154642e01fSmrg}
4164642e01fSmrg
41735c4bbdfSmrgvoid
41835c4bbdfSmrgDarwinInputReleaseButtonsAndKeys(DeviceIntPtr pDev)
41935c4bbdfSmrg{
4201b5d61b8Smrg    input_lock();
42135c4bbdfSmrg    {
42235c4bbdfSmrg        int i;
42335c4bbdfSmrg        if (pDev->button) {
42435c4bbdfSmrg            for (i = 0; i < pDev->button->numButtons; i++) {
42535c4bbdfSmrg                if (BitIsOn(pDev->button->down, i)) {
42635c4bbdfSmrg                    QueuePointerEvents(pDev, ButtonRelease, i,
42735c4bbdfSmrg                                       POINTER_ABSOLUTE,
42835c4bbdfSmrg                                       NULL);
42935c4bbdfSmrg                }
43035c4bbdfSmrg            }
43135c4bbdfSmrg        }
43235c4bbdfSmrg
43335c4bbdfSmrg        if (pDev->key) {
43435c4bbdfSmrg            for (i = 0; i < NUM_KEYCODES; i++) {
43535c4bbdfSmrg                if (BitIsOn(pDev->key->down, i + MIN_KEYCODE)) {
43635c4bbdfSmrg                    QueueKeyboardEvents(pDev, KeyRelease, i + MIN_KEYCODE);
43735c4bbdfSmrg                }
43835c4bbdfSmrg            }
43935c4bbdfSmrg        }
44035c4bbdfSmrg        DarwinPokeEQ();
4411b5d61b8Smrg    } input_unlock();
44235c4bbdfSmrg}
44335c4bbdfSmrg
44435c4bbdfSmrgvoid
44535c4bbdfSmrgDarwinSendTabletEvents(DeviceIntPtr pDev, int ev_type, int ev_button,
44635c4bbdfSmrg                       double pointer_x, double pointer_y,
44735c4bbdfSmrg                       double pressure, double tilt_x,
44835c4bbdfSmrg                       double tilt_y)
44935c4bbdfSmrg{
45035c4bbdfSmrg    ScreenPtr screen;
45135c4bbdfSmrg    ValuatorMask valuators;
45235c4bbdfSmrg
45335c4bbdfSmrg    screen = miPointerGetScreen(pDev);
45435c4bbdfSmrg    if (!screen) {
45535c4bbdfSmrg        DEBUG_LOG("%s called before screen was initialized\n",
45635c4bbdfSmrg                  __FUNCTION__);
45735c4bbdfSmrg        return;
45835c4bbdfSmrg    }
45935c4bbdfSmrg
4604642e01fSmrg    /* Fix offset between darwin and X screens */
4616747b715Smrg    pointer_x -= darwinMainScreenX + screen->x;
4626747b715Smrg    pointer_y -= darwinMainScreenY + screen->y;
4634642e01fSmrg
46435c4bbdfSmrg    /* Adjust our pointer location to the [0,1] range */
46535c4bbdfSmrg    pointer_x = pointer_x / (double)screenInfo.width;
46635c4bbdfSmrg    pointer_y = pointer_y / (double)screenInfo.height;
46735c4bbdfSmrg
46835c4bbdfSmrg    valuator_mask_zero(&valuators);
46935c4bbdfSmrg    valuator_mask_set_double(&valuators, 0, XQUARTZ_VALUATOR_LIMIT * pointer_x);
47035c4bbdfSmrg    valuator_mask_set_double(&valuators, 1, XQUARTZ_VALUATOR_LIMIT * pointer_y);
47135c4bbdfSmrg    valuator_mask_set_double(&valuators, 2, XQUARTZ_VALUATOR_LIMIT * pressure);
47235c4bbdfSmrg    valuator_mask_set_double(&valuators, 3, XQUARTZ_VALUATOR_LIMIT * tilt_x);
47335c4bbdfSmrg    valuator_mask_set_double(&valuators, 4, XQUARTZ_VALUATOR_LIMIT * tilt_y);
47435c4bbdfSmrg
4751b5d61b8Smrg    input_lock();
47635c4bbdfSmrg    {
47735c4bbdfSmrg        if (ev_type == ProximityIn || ev_type == ProximityOut) {
47835c4bbdfSmrg            QueueProximityEvents(pDev, ev_type, &valuators);
47935c4bbdfSmrg        } else {
48035c4bbdfSmrg            QueuePointerEvents(pDev, ev_type, ev_button, POINTER_ABSOLUTE,
48135c4bbdfSmrg                               &valuators);
48235c4bbdfSmrg        }
48335c4bbdfSmrg        DarwinPokeEQ();
4841b5d61b8Smrg    } input_unlock();
4854642e01fSmrg}
4864642e01fSmrg
48735c4bbdfSmrgvoid
48835c4bbdfSmrgDarwinSendPointerEvents(DeviceIntPtr pDev, int ev_type, int ev_button,
48935c4bbdfSmrg                        double pointer_x, double pointer_y,
49035c4bbdfSmrg                        double pointer_dx, double pointer_dy)
49135c4bbdfSmrg{
49235c4bbdfSmrg    static int darwinFakeMouseButtonDown = 0;
4934642e01fSmrg    ScreenPtr screen;
49435c4bbdfSmrg    ValuatorMask valuators;
49535c4bbdfSmrg
4964642e01fSmrg    screen = miPointerGetScreen(pDev);
49735c4bbdfSmrg    if (!screen) {
49835c4bbdfSmrg        DEBUG_LOG("%s called before screen was initialized\n",
49935c4bbdfSmrg                  __FUNCTION__);
5004642e01fSmrg        return;
5014642e01fSmrg    }
5024642e01fSmrg
5034642e01fSmrg    /* Handle fake click */
50435c4bbdfSmrg    if (ev_type == ButtonPress && darwinFakeButtons && ev_button == 1) {
50535c4bbdfSmrg        if (darwinFakeMouseButtonDown != 0) {
5064642e01fSmrg            /* We're currently "down" with another button, so release it first */
50735c4bbdfSmrg            DarwinSendPointerEvents(pDev, ButtonRelease,
50835c4bbdfSmrg                                    darwinFakeMouseButtonDown,
50935c4bbdfSmrg                                    pointer_x, pointer_y, 0.0, 0.0);
51035c4bbdfSmrg            darwinFakeMouseButtonDown = 0;
5114642e01fSmrg        }
51235c4bbdfSmrg        if (darwin_all_modifier_flags & darwinFakeMouse2Mask) {
5134642e01fSmrg            ev_button = 2;
51435c4bbdfSmrg            darwinFakeMouseButtonDown = 2;
51535c4bbdfSmrg            DarwinUpdateModKeys(
51635c4bbdfSmrg                darwin_all_modifier_flags & ~darwinFakeMouse2Mask);
51735c4bbdfSmrg        }
51835c4bbdfSmrg        else if (darwin_all_modifier_flags & darwinFakeMouse3Mask) {
5194642e01fSmrg            ev_button = 3;
52035c4bbdfSmrg            darwinFakeMouseButtonDown = 3;
52135c4bbdfSmrg            DarwinUpdateModKeys(
52235c4bbdfSmrg                darwin_all_modifier_flags & ~darwinFakeMouse3Mask);
52335c4bbdfSmrg        }
52435c4bbdfSmrg    }
5254642e01fSmrg
52635c4bbdfSmrg    if (ev_type == ButtonRelease && ev_button == 1) {
52735c4bbdfSmrg        if (darwinFakeMouseButtonDown) {
5284642e01fSmrg            ev_button = darwinFakeMouseButtonDown;
5294642e01fSmrg        }
5304642e01fSmrg
53135c4bbdfSmrg        if (darwinFakeMouseButtonDown == 2) {
53235c4bbdfSmrg            DarwinUpdateModKeys(
53335c4bbdfSmrg                darwin_all_modifier_flags & ~darwinFakeMouse2Mask);
53435c4bbdfSmrg        }
53535c4bbdfSmrg        else if (darwinFakeMouseButtonDown == 3) {
53635c4bbdfSmrg            DarwinUpdateModKeys(
53735c4bbdfSmrg                darwin_all_modifier_flags & ~darwinFakeMouse3Mask);
5384642e01fSmrg        }
5394642e01fSmrg
5404642e01fSmrg        darwinFakeMouseButtonDown = 0;
54135c4bbdfSmrg    }
54235c4bbdfSmrg
54335c4bbdfSmrg    /* Fix offset between darwin and X screens */
54435c4bbdfSmrg    pointer_x -= darwinMainScreenX + screen->x;
54535c4bbdfSmrg    pointer_y -= darwinMainScreenY + screen->y;
54635c4bbdfSmrg
54735c4bbdfSmrg    valuator_mask_zero(&valuators);
54835c4bbdfSmrg    valuator_mask_set_double(&valuators, 0, pointer_x);
54935c4bbdfSmrg    valuator_mask_set_double(&valuators, 1, pointer_y);
55035c4bbdfSmrg
55135c4bbdfSmrg    if (ev_type == MotionNotify) {
55235c4bbdfSmrg        if (pointer_dx != 0.0)
55335c4bbdfSmrg            valuator_mask_set_double(&valuators, 2, pointer_dx);
55435c4bbdfSmrg        if (pointer_dy != 0.0)
55535c4bbdfSmrg            valuator_mask_set_double(&valuators, 3, pointer_dy);
55635c4bbdfSmrg    }
55735c4bbdfSmrg
5581b5d61b8Smrg    input_lock();
55935c4bbdfSmrg    {
56035c4bbdfSmrg        QueuePointerEvents(pDev, ev_type, ev_button, POINTER_ABSOLUTE,
56135c4bbdfSmrg                           &valuators);
56235c4bbdfSmrg        DarwinPokeEQ();
5631b5d61b8Smrg    } input_unlock();
5644642e01fSmrg}
5654642e01fSmrg
56635c4bbdfSmrgvoid
56735c4bbdfSmrgDarwinSendKeyboardEvents(int ev_type, int keycode)
56835c4bbdfSmrg{
5691b5d61b8Smrg    input_lock();
57035c4bbdfSmrg    {
57135c4bbdfSmrg        QueueKeyboardEvents(darwinKeyboard, ev_type, keycode + MIN_KEYCODE);
57235c4bbdfSmrg        DarwinPokeEQ();
5731b5d61b8Smrg    } input_unlock();
5744642e01fSmrg}
5754642e01fSmrg
57635c4bbdfSmrg/* Send the appropriate number of button clicks to emulate scroll wheel */
57735c4bbdfSmrgvoid
57835c4bbdfSmrgDarwinSendScrollEvents(double scroll_x, double scroll_y) {
5794642e01fSmrg    ScreenPtr screen;
58035c4bbdfSmrg    ValuatorMask valuators;
5814642e01fSmrg
58235c4bbdfSmrg    screen = miPointerGetScreen(darwinPointer);
58335c4bbdfSmrg    if (!screen) {
58435c4bbdfSmrg        DEBUG_LOG(
58535c4bbdfSmrg            "DarwinSendScrollEvents called before screen was initialized\n");
5864642e01fSmrg        return;
58735c4bbdfSmrg    }
5884642e01fSmrg
58935c4bbdfSmrg    valuator_mask_zero(&valuators);
59035c4bbdfSmrg    valuator_mask_set_double(&valuators, 4, scroll_y);
59135c4bbdfSmrg    valuator_mask_set_double(&valuators, 5, scroll_x);
5924642e01fSmrg
5931b5d61b8Smrg    input_lock();
59435c4bbdfSmrg    {
59535c4bbdfSmrg        QueuePointerEvents(darwinPointer, MotionNotify, 0,
59635c4bbdfSmrg                           POINTER_RELATIVE, &valuators);
59735c4bbdfSmrg        DarwinPokeEQ();
5981b5d61b8Smrg    } input_unlock();
5994642e01fSmrg}
6004642e01fSmrg
6014642e01fSmrg/* Send the appropriate KeyPress/KeyRelease events to GetKeyboardEvents to
6024642e01fSmrg   reflect changing modifier flags (alt, control, meta, etc) */
60335c4bbdfSmrgvoid
60435c4bbdfSmrgDarwinUpdateModKeys(int flags)
60535c4bbdfSmrg{
60635c4bbdfSmrg    DarwinUpdateModifiers(
60735c4bbdfSmrg        KeyRelease, darwin_all_modifier_flags & ~flags &
60835c4bbdfSmrg        darwin_x11_modifier_mask);
60935c4bbdfSmrg    DarwinUpdateModifiers(
61035c4bbdfSmrg        KeyPress, ~darwin_all_modifier_flags & flags &
61135c4bbdfSmrg        darwin_x11_modifier_mask);
61235c4bbdfSmrg    darwin_all_modifier_flags = flags;
6134642e01fSmrg}
6144642e01fSmrg
6154642e01fSmrg/*
6164642e01fSmrg * DarwinSendDDXEvent
6174642e01fSmrg *  Send the X server thread a message by placing it on the event queue.
6184642e01fSmrg */
61935c4bbdfSmrgvoid
62035c4bbdfSmrgDarwinSendDDXEvent(int type, int argc, ...)
62135c4bbdfSmrg{
6226747b715Smrg    XQuartzEvent e;
6236747b715Smrg    int i;
6244642e01fSmrg    va_list args;
6254642e01fSmrg
6266747b715Smrg    memset(&e, 0, sizeof(e));
6276747b715Smrg    e.header = ET_Internal;
6286747b715Smrg    e.type = ET_XQuartz;
6296747b715Smrg    e.length = sizeof(e);
6306747b715Smrg    e.time = GetTimeInMillis();
6316747b715Smrg    e.subtype = type;
6324642e01fSmrg
6336747b715Smrg    if (argc > 0 && argc < XQUARTZ_EVENT_MAXARGS) {
63435c4bbdfSmrg        va_start(args, argc);
6354642e01fSmrg        for (i = 0; i < argc; i++)
63635c4bbdfSmrg            e.data[i] = (uint32_t)va_arg(args, uint32_t);
63735c4bbdfSmrg        va_end(args);
6384642e01fSmrg    }
6394642e01fSmrg
6401b5d61b8Smrg    wait_for_mieq_init();
6411b5d61b8Smrg
6421b5d61b8Smrg    input_lock();
64335c4bbdfSmrg    {
64435c4bbdfSmrg        mieqEnqueue(NULL, (InternalEvent *)&e);
6454642e01fSmrg        DarwinPokeEQ();
6461b5d61b8Smrg    } input_unlock();
6474642e01fSmrg}
648