| 1 | /* |
| 2 | * Darwin event queue and event handling |
| 3 | * |
| 4 | * Copyright 2007-2008 Apple Inc. |
| 5 | * Copyright 2004 Kaleb S. KEITHLEY. All Rights Reserved. |
| 6 | * Copyright (c) 2002-2004 Torrey T. Lyons. All Rights Reserved. |
| 7 | * |
| 8 | * This file is based on mieq.c by Keith Packard, |
| 9 | * which contains the following copyright: |
| 10 | * Copyright 1990, 1998 The Open Group |
| 11 | * |
| 12 | * |
| 13 | * Copyright (c) 2002-2012 Apple Inc. All rights reserved. |
| 14 | * |
| 15 | * Permission is hereby granted, free of charge, to any person |
| 16 | * obtaining a copy of this software and associated documentation files |
| 17 | * (the "Software"), to deal in the Software without restriction, |
| 18 | * including without limitation the rights to use, copy, modify, merge, |
| 19 | * publish, distribute, sublicense, and/or sell copies of the Software, |
| 20 | * and to permit persons to whom the Software is furnished to do so, |
| 21 | * subject to the following conditions: |
| 22 | * |
| 23 | * The above copyright notice and this permission notice shall be |
| 24 | * included in all copies or substantial portions of the Software. |
| 25 | * |
| 26 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
| 27 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
| 28 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
| 29 | * NONINFRINGEMENT. IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT |
| 30 | * HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, |
| 31 | * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
| 32 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
| 33 | * DEALINGS IN THE SOFTWARE. |
| 34 | * |
| 35 | * Except as contained in this notice, the name(s) of the above |
| 36 | * copyright holders shall not be used in advertising or otherwise to |
| 37 | * promote the sale, use or other dealings in this Software without |
| 38 | * prior written authorization. |
| 39 | */ |
| 40 | |
| 41 | #include "sanitizedCarbon.h" |
| 42 | |
| 43 | #ifdef HAVE_DIX_CONFIG_H |
| 44 | #include <dix-config.h> |
| 45 | #endif |
| 46 | |
| 47 | #include <X11/X.h> |
| 48 | #include <X11/Xmd.h> |
| 49 | #include <X11/Xproto.h> |
| 50 | #include "misc.h" |
| 51 | #include "windowstr.h" |
| 52 | #include "pixmapstr.h" |
| 53 | #include "inputstr.h" |
| 54 | #include "inpututils.h" |
| 55 | #include "eventstr.h" |
| 56 | #include "mi.h" |
| 57 | #include "scrnintstr.h" |
| 58 | #include "mipointer.h" |
| 59 | #include "os.h" |
| 60 | #include "exglobals.h" |
| 61 | |
| 62 | #include "darwin.h" |
| 63 | #include "quartz.h" |
| 64 | #include "quartzKeyboard.h" |
| 65 | #include "quartzRandR.h" |
| 66 | #include "darwinEvents.h" |
| 67 | |
| 68 | #include <sys/types.h> |
| 69 | #include <sys/uio.h> |
| 70 | #include <unistd.h> |
| 71 | #include <pthread.h> |
| 72 | #include <errno.h> |
| 73 | #include <time.h> |
| 74 | |
| 75 | #include <IOKit/hidsystem/IOLLEvent.h> |
| 76 | |
| 77 | #include <X11/extensions/applewmconst.h> |
| 78 | #include "applewmExt.h" |
| 79 | |
| 80 | /* FIXME: Abstract this better */ |
| 81 | extern Bool |
| 82 | QuartzModeEventHandler(int screenNum, XQuartzEvent *e, DeviceIntPtr dev); |
| 83 | |
| 84 | int darwin_all_modifier_flags = 0; // last known modifier state |
| 85 | int darwin_all_modifier_mask = 0; |
| 86 | int darwin_x11_modifier_mask = 0; |
| 87 | |
| 88 | #define FD_ADD_MAX 128 |
| 89 | static int fd_add[FD_ADD_MAX]; |
| 90 | int fd_add_count = 0; |
| 91 | static pthread_mutex_t fd_add_lock = PTHREAD_MUTEX_INITIALIZER; |
| 92 | static pthread_cond_t fd_add_ready_cond = PTHREAD_COND_INITIALIZER; |
| 93 | static pthread_t fd_add_tid = NULL; |
| 94 | |
| 95 | static InternalEvent* darwinEvents = NULL; |
| 96 | |
| 97 | static pthread_mutex_t mieq_lock = PTHREAD_MUTEX_INITIALIZER; |
| 98 | static pthread_cond_t mieq_ready_cond = PTHREAD_COND_INITIALIZER; |
| 99 | |
| 100 | /*** Pthread Magics ***/ |
| 101 | static pthread_t |
| 102 | create_thread(void *(*func)(void *), void *arg) |
| 103 | { |
| 104 | pthread_attr_t attr; |
| 105 | pthread_t tid; |
| 106 | |
| 107 | pthread_attr_init(&attr); |
| 108 | pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM); |
| 109 | pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); |
| 110 | pthread_create(&tid, &attr, func, arg); |
| 111 | pthread_attr_destroy(&attr); |
| 112 | |
| 113 | return tid; |
| 114 | } |
| 115 | |
| 116 | void |
| 117 | darwinEvents_lock(void); |
| 118 | void |
| 119 | darwinEvents_lock(void) |
| 120 | { |
| 121 | int err; |
| 122 | if ((err = pthread_mutex_lock(&mieq_lock))) { |
| 123 | ErrorF("%s:%s:%d: Failed to lock mieq_lock: %d\n", |
| 124 | __FILE__, __FUNCTION__, __LINE__, err); |
| 125 | xorg_backtrace(); |
| 126 | } |
| 127 | if (darwinEvents == NULL) { |
| 128 | pthread_cond_wait(&mieq_ready_cond, &mieq_lock); |
| 129 | } |
| 130 | } |
| 131 | |
| 132 | void |
| 133 | darwinEvents_unlock(void); |
| 134 | void |
| 135 | darwinEvents_unlock(void) |
| 136 | { |
| 137 | int err; |
| 138 | if ((err = pthread_mutex_unlock(&mieq_lock))) { |
| 139 | ErrorF("%s:%s:%d: Failed to unlock mieq_lock: %d\n", |
| 140 | __FILE__, __FUNCTION__, __LINE__, err); |
| 141 | xorg_backtrace(); |
| 142 | } |
| 143 | } |
| 144 | |
| 145 | /* |
| 146 | * DarwinPressModifierKey |
| 147 | * Press or release the given modifier key (one of NX_MODIFIERKEY_* constants) |
| 148 | */ |
| 149 | static void |
| 150 | DarwinPressModifierKey(int pressed, int key) |
| 151 | { |
| 152 | int keycode = DarwinModifierNXKeyToNXKeycode(key, 0); |
| 153 | |
| 154 | if (keycode == 0) { |
| 155 | ErrorF("DarwinPressModifierKey bad keycode: key=%d\n", key); |
| 156 | return; |
| 157 | } |
| 158 | |
| 159 | DarwinSendKeyboardEvents(pressed, keycode); |
| 160 | } |
| 161 | |
| 162 | /* |
| 163 | * DarwinUpdateModifiers |
| 164 | * Send events to update the modifier state. |
| 165 | */ |
| 166 | |
| 167 | static int darwin_x11_modifier_mask_list[] = { |
| 168 | #ifdef NX_DEVICELCMDKEYMASK |
| 169 | NX_DEVICELCTLKEYMASK, NX_DEVICERCTLKEYMASK, |
| 170 | NX_DEVICELSHIFTKEYMASK, NX_DEVICERSHIFTKEYMASK, |
| 171 | NX_DEVICELCMDKEYMASK, NX_DEVICERCMDKEYMASK, |
| 172 | NX_DEVICELALTKEYMASK, NX_DEVICERALTKEYMASK, |
| 173 | #else |
| 174 | NX_CONTROLMASK, NX_SHIFTMASK, NX_COMMANDMASK, |
| 175 | NX_ALTERNATEMASK, |
| 176 | #endif |
| 177 | NX_ALPHASHIFTMASK, |
| 178 | 0 |
| 179 | }; |
| 180 | |
| 181 | static int darwin_all_modifier_mask_additions[] = { NX_SECONDARYFNMASK, }; |
| 182 | |
| 183 | static void |
| 184 | DarwinUpdateModifiers(int pressed, // KeyPress or KeyRelease |
| 185 | int flags) // modifier flags that have changed |
| 186 | { |
| 187 | int *f; |
| 188 | int key; |
| 189 | |
| 190 | /* Capslock is special. This mask is the state of capslock (on/off), |
| 191 | * not the state of the button. Hopefully we can find a better solution. |
| 192 | */ |
| 193 | if (NX_ALPHASHIFTMASK & flags) { |
| 194 | DarwinPressModifierKey(KeyPress, NX_MODIFIERKEY_ALPHALOCK); |
| 195 | DarwinPressModifierKey(KeyRelease, NX_MODIFIERKEY_ALPHALOCK); |
| 196 | } |
| 197 | |
| 198 | for (f = darwin_x11_modifier_mask_list; *f; f++) |
| 199 | if (*f & flags && *f != NX_ALPHASHIFTMASK) { |
| 200 | key = DarwinModifierNXMaskToNXKey(*f); |
| 201 | if (key == -1) |
| 202 | ErrorF("DarwinUpdateModifiers: Unsupported NXMask: 0x%x\n", |
| 203 | *f); |
| 204 | else |
| 205 | DarwinPressModifierKey(pressed, key); |
| 206 | } |
| 207 | } |
| 208 | |
| 209 | /* Generic handler for Xquartz-specifc events. When possible, these should |
| 210 | be moved into their own individual functions and set as handlers using |
| 211 | mieqSetHandler. */ |
| 212 | |
| 213 | static void |
| 214 | DarwinEventHandler(int screenNum, InternalEvent *ie, DeviceIntPtr dev) |
| 215 | { |
| 216 | XQuartzEvent *e = &(ie->xquartz_event); |
| 217 | |
| 218 | switch (e->subtype) { |
| 219 | case kXquartzControllerNotify: |
| 220 | DEBUG_LOG("kXquartzControllerNotify\n"); |
| 221 | AppleWMSendEvent(AppleWMControllerNotify, |
| 222 | AppleWMControllerNotifyMask, |
| 223 | e->data[0], |
| 224 | e->data[1]); |
| 225 | break; |
| 226 | |
| 227 | case kXquartzPasteboardNotify: |
| 228 | DEBUG_LOG("kXquartzPasteboardNotify\n"); |
| 229 | AppleWMSendEvent(AppleWMPasteboardNotify, |
| 230 | AppleWMPasteboardNotifyMask, |
| 231 | e->data[0], |
| 232 | e->data[1]); |
| 233 | break; |
| 234 | |
| 235 | case kXquartzActivate: |
| 236 | DEBUG_LOG("kXquartzActivate\n"); |
| 237 | QuartzShow(); |
| 238 | AppleWMSendEvent(AppleWMActivationNotify, |
| 239 | AppleWMActivationNotifyMask, |
| 240 | AppleWMIsActive, 0); |
| 241 | break; |
| 242 | |
| 243 | case kXquartzDeactivate: |
| 244 | DEBUG_LOG("kXquartzDeactivate\n"); |
| 245 | AppleWMSendEvent(AppleWMActivationNotify, |
| 246 | AppleWMActivationNotifyMask, |
| 247 | AppleWMIsInactive, 0); |
| 248 | QuartzHide(); |
| 249 | break; |
| 250 | |
| 251 | case kXquartzReloadPreferences: |
| 252 | DEBUG_LOG("kXquartzReloadPreferences\n"); |
| 253 | AppleWMSendEvent(AppleWMActivationNotify, |
| 254 | AppleWMActivationNotifyMask, |
| 255 | AppleWMReloadPreferences, 0); |
| 256 | break; |
| 257 | |
| 258 | case kXquartzToggleFullscreen: |
| 259 | DEBUG_LOG("kXquartzToggleFullscreen\n"); |
| 260 | if (XQuartzIsRootless) |
| 261 | ErrorF( |
| 262 | "Ignoring kXquartzToggleFullscreen because of rootless mode."); |
| 263 | else |
| 264 | QuartzRandRToggleFullscreen(); |
| 265 | break; |
| 266 | |
| 267 | case kXquartzSetRootless: |
| 268 | DEBUG_LOG("kXquartzSetRootless\n"); |
| 269 | if (e->data[0]) { |
| 270 | QuartzRandRSetFakeRootless(); |
| 271 | } |
| 272 | else { |
| 273 | QuartzRandRSetFakeFullscreen(FALSE); |
| 274 | } |
| 275 | break; |
| 276 | |
| 277 | case kXquartzSetRootClip: |
| 278 | QuartzSetRootClip((Bool)e->data[0]); |
| 279 | break; |
| 280 | |
| 281 | case kXquartzQuit: |
| 282 | GiveUp(0); |
| 283 | break; |
| 284 | |
| 285 | case kXquartzSpaceChanged: |
| 286 | DEBUG_LOG("kXquartzSpaceChanged\n"); |
| 287 | QuartzSpaceChanged(e->data[0]); |
| 288 | break; |
| 289 | |
| 290 | case kXquartzListenOnOpenFD: |
| 291 | ErrorF("Calling ListenOnOpenFD() for new fd: %d\n", (int)e->data[0]); |
| 292 | ListenOnOpenFD((int)e->data[0], 1); |
| 293 | break; |
| 294 | |
| 295 | case kXquartzReloadKeymap: |
| 296 | DarwinKeyboardReloadHandler(); |
| 297 | break; |
| 298 | |
| 299 | case kXquartzDisplayChanged: |
| 300 | DEBUG_LOG("kXquartzDisplayChanged\n"); |
| 301 | QuartzUpdateScreens(); |
| 302 | |
| 303 | /* Update our RandR info */ |
| 304 | QuartzRandRUpdateFakeModes(TRUE); |
| 305 | break; |
| 306 | |
| 307 | default: |
| 308 | if (!QuartzModeEventHandler(screenNum, e, dev)) |
| 309 | ErrorF("Unknown application defined event type %d.\n", e->subtype); |
| 310 | } |
| 311 | } |
| 312 | |
| 313 | void |
| 314 | DarwinListenOnOpenFD(int fd) |
| 315 | { |
| 316 | ErrorF("DarwinListenOnOpenFD: %d\n", fd); |
| 317 | |
| 318 | pthread_mutex_lock(&fd_add_lock); |
| 319 | if (fd_add_count < FD_ADD_MAX) |
| 320 | fd_add[fd_add_count++] = fd; |
| 321 | else |
| 322 | ErrorF("FD Addition buffer at max. Dropping fd addition request.\n"); |
| 323 | |
| 324 | pthread_cond_broadcast(&fd_add_ready_cond); |
| 325 | pthread_mutex_unlock(&fd_add_lock); |
| 326 | } |
| 327 | |
| 328 | static void * |
| 329 | DarwinProcessFDAdditionQueue_thread(void *args) |
| 330 | { |
| 331 | /* TODO: Possibly adjust this to no longer be a race... maybe trigger this |
| 332 | * once a client connects and claims to be the WM. |
| 333 | * |
| 334 | * From ajax: |
| 335 | * There's already an internal callback chain for setting selection [in 1.5] |
| 336 | * ownership. See the CallSelectionCallback at the bottom of |
| 337 | * ProcSetSelectionOwner, and xfixes/select.c for an example of how to hook |
| 338 | * into it. |
| 339 | */ |
| 340 | |
| 341 | struct timespec sleep_for; |
| 342 | struct timespec sleep_remaining; |
| 343 | |
| 344 | sleep_for.tv_sec = 3; |
| 345 | sleep_for.tv_nsec = 0; |
| 346 | |
| 347 | ErrorF( |
| 348 | "X11.app: DarwinProcessFDAdditionQueue_thread: Sleeping to allow xinitrc to catchup.\n"); |
| 349 | while (nanosleep(&sleep_for, &sleep_remaining) != 0) { |
| 350 | sleep_for = sleep_remaining; |
| 351 | } |
| 352 | |
| 353 | pthread_mutex_lock(&fd_add_lock); |
| 354 | while (true) { |
| 355 | while (fd_add_count) { |
| 356 | DarwinSendDDXEvent(kXquartzListenOnOpenFD, 1, |
| 357 | fd_add[--fd_add_count]); |
| 358 | } |
| 359 | pthread_cond_wait(&fd_add_ready_cond, &fd_add_lock); |
| 360 | } |
| 361 | |
| 362 | return NULL; |
| 363 | } |
| 364 | |
| 365 | Bool |
| 366 | DarwinEQInit(void) |
| 367 | { |
| 368 | int *p; |
| 369 | |
| 370 | for (p = darwin_x11_modifier_mask_list, darwin_all_modifier_mask = 0; *p; |
| 371 | p++) { |
| 372 | darwin_x11_modifier_mask |= *p; |
| 373 | } |
| 374 | |
| 375 | for (p = darwin_all_modifier_mask_additions, |
| 376 | darwin_all_modifier_mask = darwin_x11_modifier_mask; |
| 377 | *p; p++) { |
| 378 | darwin_all_modifier_mask |= *p; |
| 379 | } |
| 380 | |
| 381 | mieqInit(); |
| 382 | mieqSetHandler(ET_XQuartz, DarwinEventHandler); |
| 383 | |
| 384 | /* Note that this *could* cause a potential async issue, since we're checking |
| 385 | * darwinEvents without holding the lock, but darwinEvents is only ever set |
| 386 | * here, so I don't bother. |
| 387 | */ |
| 388 | if (!darwinEvents) { |
| 389 | darwinEvents = InitEventList(GetMaximumEventsNum()); |
| 390 | ; |
| 391 | |
| 392 | if (!darwinEvents) |
| 393 | FatalError("Couldn't allocate event buffer\n"); |
| 394 | |
| 395 | darwinEvents_lock(); |
| 396 | pthread_cond_broadcast(&mieq_ready_cond); |
| 397 | darwinEvents_unlock(); |
| 398 | } |
| 399 | |
| 400 | if (!fd_add_tid) |
| 401 | fd_add_tid = create_thread(DarwinProcessFDAdditionQueue_thread, NULL); |
| 402 | |
| 403 | return TRUE; |
| 404 | } |
| 405 | |
| 406 | void |
| 407 | DarwinEQFini(void) |
| 408 | { |
| 409 | mieqFini(); |
| 410 | } |
| 411 | |
| 412 | /* |
| 413 | * ProcessInputEvents |
| 414 | * Read and process events from the event queue until it is empty. |
| 415 | */ |
| 416 | void |
| 417 | ProcessInputEvents(void) |
| 418 | { |
| 419 | char nullbyte; |
| 420 | int x = sizeof(nullbyte); |
| 421 | |
| 422 | mieqProcessInputEvents(); |
| 423 | |
| 424 | // Empty the signaling pipe |
| 425 | while (x == sizeof(nullbyte)) { |
| 426 | x = read(darwinEventReadFD, &nullbyte, sizeof(nullbyte)); |
| 427 | } |
| 428 | } |
| 429 | |
| 430 | /* Sends a null byte down darwinEventWriteFD, which will cause the |
| 431 | Dispatch() event loop to check out event queue */ |
| 432 | static void |
| 433 | DarwinPokeEQ(void) |
| 434 | { |
| 435 | char nullbyte = 0; |
| 436 | // <daniels> oh, i ... er ... christ. |
| 437 | write(darwinEventWriteFD, &nullbyte, sizeof(nullbyte)); |
| 438 | } |
| 439 | |
| 440 | void |
| 441 | DarwinInputReleaseButtonsAndKeys(DeviceIntPtr pDev) |
| 442 | { |
| 443 | darwinEvents_lock(); |
| 444 | { |
| 445 | int i; |
| 446 | if (pDev->button) { |
| 447 | for (i = 0; i < pDev->button->numButtons; i++) { |
| 448 | if (BitIsOn(pDev->button->down, i)) { |
| 449 | QueuePointerEvents(pDev, ButtonRelease, i, |
| 450 | POINTER_ABSOLUTE, |
| 451 | NULL); |
| 452 | } |
| 453 | } |
| 454 | } |
| 455 | |
| 456 | if (pDev->key) { |
| 457 | for (i = 0; i < NUM_KEYCODES; i++) { |
| 458 | if (BitIsOn(pDev->key->down, i + MIN_KEYCODE)) { |
| 459 | QueueKeyboardEvents(pDev, KeyRelease, i + MIN_KEYCODE, |
| 460 | NULL); |
| 461 | } |
| 462 | } |
| 463 | } |
| 464 | DarwinPokeEQ(); |
| 465 | } darwinEvents_unlock(); |
| 466 | } |
| 467 | |
| 468 | void |
| 469 | DarwinSendTabletEvents(DeviceIntPtr pDev, int ev_type, int ev_button, |
| 470 | double pointer_x, double pointer_y, |
| 471 | double pressure, double tilt_x, |
| 472 | double tilt_y) |
| 473 | { |
| 474 | ScreenPtr screen; |
| 475 | ValuatorMask valuators; |
| 476 | |
| 477 | if (!darwinEvents) { |
| 478 | DEBUG_LOG("%s called before darwinEvents was initialized\n", |
| 479 | __FUNCTION__); |
| 480 | return; |
| 481 | } |
| 482 | |
| 483 | screen = miPointerGetScreen(pDev); |
| 484 | if (!screen) { |
| 485 | DEBUG_LOG("%s called before screen was initialized\n", |
| 486 | __FUNCTION__); |
| 487 | return; |
| 488 | } |
| 489 | |
| 490 | /* Fix offset between darwin and X screens */ |
| 491 | pointer_x -= darwinMainScreenX + screen->x; |
| 492 | pointer_y -= darwinMainScreenY + screen->y; |
| 493 | |
| 494 | /* Adjust our pointer location to the [0,1] range */ |
| 495 | pointer_x = pointer_x / (double)screenInfo.width; |
| 496 | pointer_y = pointer_y / (double)screenInfo.height; |
| 497 | |
| 498 | valuator_mask_zero(&valuators); |
| 499 | valuator_mask_set_double(&valuators, 0, XQUARTZ_VALUATOR_LIMIT * pointer_x); |
| 500 | valuator_mask_set_double(&valuators, 1, XQUARTZ_VALUATOR_LIMIT * pointer_y); |
| 501 | valuator_mask_set_double(&valuators, 2, XQUARTZ_VALUATOR_LIMIT * pressure); |
| 502 | valuator_mask_set_double(&valuators, 3, XQUARTZ_VALUATOR_LIMIT * tilt_x); |
| 503 | valuator_mask_set_double(&valuators, 4, XQUARTZ_VALUATOR_LIMIT * tilt_y); |
| 504 | |
| 505 | darwinEvents_lock(); |
| 506 | { |
| 507 | if (ev_type == ProximityIn || ev_type == ProximityOut) { |
| 508 | QueueProximityEvents(pDev, ev_type, &valuators); |
| 509 | } else { |
| 510 | QueuePointerEvents(pDev, ev_type, ev_button, POINTER_ABSOLUTE, |
| 511 | &valuators); |
| 512 | } |
| 513 | DarwinPokeEQ(); |
| 514 | } darwinEvents_unlock(); |
| 515 | } |
| 516 | |
| 517 | void |
| 518 | DarwinSendPointerEvents(DeviceIntPtr pDev, int ev_type, int ev_button, |
| 519 | double pointer_x, double pointer_y, |
| 520 | double pointer_dx, double pointer_dy) |
| 521 | { |
| 522 | static int darwinFakeMouseButtonDown = 0; |
| 523 | ScreenPtr screen; |
| 524 | ValuatorMask valuators; |
| 525 | |
| 526 | if (!darwinEvents) { |
| 527 | DEBUG_LOG("%s called before darwinEvents was initialized\n", |
| 528 | __FUNCTION__); |
| 529 | return; |
| 530 | } |
| 531 | |
| 532 | screen = miPointerGetScreen(pDev); |
| 533 | if (!screen) { |
| 534 | DEBUG_LOG("%s called before screen was initialized\n", |
| 535 | __FUNCTION__); |
| 536 | return; |
| 537 | } |
| 538 | |
| 539 | /* Handle fake click */ |
| 540 | if (ev_type == ButtonPress && darwinFakeButtons && ev_button == 1) { |
| 541 | if (darwinFakeMouseButtonDown != 0) { |
| 542 | /* We're currently "down" with another button, so release it first */ |
| 543 | DarwinSendPointerEvents(pDev, ButtonRelease, |
| 544 | darwinFakeMouseButtonDown, |
| 545 | pointer_x, pointer_y, 0.0, 0.0); |
| 546 | darwinFakeMouseButtonDown = 0; |
| 547 | } |
| 548 | if (darwin_all_modifier_flags & darwinFakeMouse2Mask) { |
| 549 | ev_button = 2; |
| 550 | darwinFakeMouseButtonDown = 2; |
| 551 | DarwinUpdateModKeys( |
| 552 | darwin_all_modifier_flags & ~darwinFakeMouse2Mask); |
| 553 | } |
| 554 | else if (darwin_all_modifier_flags & darwinFakeMouse3Mask) { |
| 555 | ev_button = 3; |
| 556 | darwinFakeMouseButtonDown = 3; |
| 557 | DarwinUpdateModKeys( |
| 558 | darwin_all_modifier_flags & ~darwinFakeMouse3Mask); |
| 559 | } |
| 560 | } |
| 561 | |
| 562 | if (ev_type == ButtonRelease && ev_button == 1) { |
| 563 | if (darwinFakeMouseButtonDown) { |
| 564 | ev_button = darwinFakeMouseButtonDown; |
| 565 | } |
| 566 | |
| 567 | if (darwinFakeMouseButtonDown == 2) { |
| 568 | DarwinUpdateModKeys( |
| 569 | darwin_all_modifier_flags & ~darwinFakeMouse2Mask); |
| 570 | } |
| 571 | else if (darwinFakeMouseButtonDown == 3) { |
| 572 | DarwinUpdateModKeys( |
| 573 | darwin_all_modifier_flags & ~darwinFakeMouse3Mask); |
| 574 | } |
| 575 | |
| 576 | darwinFakeMouseButtonDown = 0; |
| 577 | } |
| 578 | |
| 579 | /* Fix offset between darwin and X screens */ |
| 580 | pointer_x -= darwinMainScreenX + screen->x; |
| 581 | pointer_y -= darwinMainScreenY + screen->y; |
| 582 | |
| 583 | valuator_mask_zero(&valuators); |
| 584 | valuator_mask_set_double(&valuators, 0, pointer_x); |
| 585 | valuator_mask_set_double(&valuators, 1, pointer_y); |
| 586 | |
| 587 | if (ev_type == MotionNotify) { |
| 588 | if (pointer_dx != 0.0) |
| 589 | valuator_mask_set_double(&valuators, 2, pointer_dx); |
| 590 | if (pointer_dy != 0.0) |
| 591 | valuator_mask_set_double(&valuators, 3, pointer_dy); |
| 592 | } |
| 593 | |
| 594 | darwinEvents_lock(); |
| 595 | { |
| 596 | QueuePointerEvents(pDev, ev_type, ev_button, POINTER_ABSOLUTE, |
| 597 | &valuators); |
| 598 | DarwinPokeEQ(); |
| 599 | } darwinEvents_unlock(); |
| 600 | } |
| 601 | |
| 602 | void |
| 603 | DarwinSendKeyboardEvents(int ev_type, int keycode) |
| 604 | { |
| 605 | |
| 606 | if (!darwinEvents) { |
| 607 | DEBUG_LOG( |
| 608 | "DarwinSendKeyboardEvents called before darwinEvents was initialized\n"); |
| 609 | return; |
| 610 | } |
| 611 | |
| 612 | darwinEvents_lock(); |
| 613 | { |
| 614 | QueueKeyboardEvents(darwinKeyboard, ev_type, keycode + MIN_KEYCODE, |
| 615 | NULL); |
| 616 | DarwinPokeEQ(); |
| 617 | } darwinEvents_unlock(); |
| 618 | } |
| 619 | |
| 620 | /* Send the appropriate number of button clicks to emulate scroll wheel */ |
| 621 | void |
| 622 | DarwinSendScrollEvents(double scroll_x, double scroll_y) { |
| 623 | ScreenPtr screen; |
| 624 | ValuatorMask valuators; |
| 625 | |
| 626 | if (!darwinEvents) { |
| 627 | DEBUG_LOG( |
| 628 | "DarwinSendScrollEvents called before darwinEvents was initialized\n"); |
| 629 | return; |
| 630 | } |
| 631 | |
| 632 | screen = miPointerGetScreen(darwinPointer); |
| 633 | if (!screen) { |
| 634 | DEBUG_LOG( |
| 635 | "DarwinSendScrollEvents called before screen was initialized\n"); |
| 636 | return; |
| 637 | } |
| 638 | |
| 639 | valuator_mask_zero(&valuators); |
| 640 | valuator_mask_set_double(&valuators, 4, scroll_y); |
| 641 | valuator_mask_set_double(&valuators, 5, scroll_x); |
| 642 | |
| 643 | darwinEvents_lock(); |
| 644 | { |
| 645 | QueuePointerEvents(darwinPointer, MotionNotify, 0, |
| 646 | POINTER_RELATIVE, &valuators); |
| 647 | DarwinPokeEQ(); |
| 648 | } darwinEvents_unlock(); |
| 649 | } |
| 650 | |
| 651 | /* Send the appropriate KeyPress/KeyRelease events to GetKeyboardEvents to |
| 652 | reflect changing modifier flags (alt, control, meta, etc) */ |
| 653 | void |
| 654 | DarwinUpdateModKeys(int flags) |
| 655 | { |
| 656 | DarwinUpdateModifiers( |
| 657 | KeyRelease, darwin_all_modifier_flags & ~flags & |
| 658 | darwin_x11_modifier_mask); |
| 659 | DarwinUpdateModifiers( |
| 660 | KeyPress, ~darwin_all_modifier_flags & flags & |
| 661 | darwin_x11_modifier_mask); |
| 662 | darwin_all_modifier_flags = flags; |
| 663 | } |
| 664 | |
| 665 | /* |
| 666 | * DarwinSendDDXEvent |
| 667 | * Send the X server thread a message by placing it on the event queue. |
| 668 | */ |
| 669 | void |
| 670 | DarwinSendDDXEvent(int type, int argc, ...) |
| 671 | { |
| 672 | XQuartzEvent e; |
| 673 | int i; |
| 674 | va_list args; |
| 675 | |
| 676 | memset(&e, 0, sizeof(e)); |
| 677 | e.header = ET_Internal; |
| 678 | e.type = ET_XQuartz; |
| 679 | e.length = sizeof(e); |
| 680 | e.time = GetTimeInMillis(); |
| 681 | e.subtype = type; |
| 682 | |
| 683 | if (argc > 0 && argc < XQUARTZ_EVENT_MAXARGS) { |
| 684 | va_start(args, argc); |
| 685 | for (i = 0; i < argc; i++) |
| 686 | e.data[i] = (uint32_t)va_arg(args, uint32_t); |
| 687 | va_end(args); |
| 688 | } |
| 689 | |
| 690 | darwinEvents_lock(); |
| 691 | { |
| 692 | mieqEnqueue(NULL, (InternalEvent *)&e); |
| 693 | DarwinPokeEQ(); |
| 694 | } darwinEvents_unlock(); |
| 695 | } |