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