1/* X11Application.m -- subclass of NSApplication to multiplex events 2 3 Copyright (c) 2002-2008 Apple Inc. 4 5 Permission is hereby granted, free of charge, to any person 6 obtaining a copy of this software and associated documentation files 7 (the "Software"), to deal in the Software without restriction, 8 including without limitation the rights to use, copy, modify, merge, 9 publish, distribute, sublicense, and/or sell copies of the Software, 10 and to permit persons to whom the Software is furnished to do so, 11 subject to the following conditions: 12 13 The above copyright notice and this permission notice shall be 14 included in all copies or substantial portions of the Software. 15 16 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 NONINFRINGEMENT. IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT 20 HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 21 WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 DEALINGS IN THE SOFTWARE. 24 25 Except as contained in this notice, the name(s) of the above 26 copyright holders shall not be used in advertising or otherwise to 27 promote the sale, use or other dealings in this Software without 28 prior written authorization. */ 29 30#include "sanitizedCarbon.h" 31 32#ifdef HAVE_DIX_CONFIG_H 33#include <dix-config.h> 34#endif 35 36#include "quartzCommon.h" 37 38#import "X11Application.h" 39 40#include "darwin.h" 41#include "quartz.h" 42#include "darwinEvents.h" 43#include "quartzKeyboard.h" 44#include "quartz.h" 45#include <X11/extensions/applewmconst.h> 46#include "micmap.h" 47#include "exglobals.h" 48 49#include <mach/mach.h> 50#include <unistd.h> 51#include <AvailabilityMacros.h> 52 53#include <pthread.h> 54 55#include <Xplugin.h> 56 57// pbproxy/pbproxy.h 58extern int xpbproxy_run (void); 59 60#define DEFAULTS_FILE X11LIBDIR"/X11/xserver/Xquartz.plist" 61 62#ifndef XSERVER_VERSION 63#define XSERVER_VERSION "?" 64#endif 65 66/* Stuck modifier / button state... force release when we context switch */ 67static NSEventType keyState[NUM_KEYCODES]; 68 69extern Bool noTestExtensions; 70 71#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1050 72static TISInputSourceRef last_key_layout; 73#else 74static KeyboardLayoutRef last_key_layout; 75#endif 76 77/* This preference is only tested on Lion or later as it's not relevant to 78 * earlier OS versions. 79 */ 80Bool XQuartzScrollInDeviceDirection = FALSE; 81 82extern int darwinFakeButtons; 83 84/* Store the mouse location while in the background, and update X11's pointer 85 * location when we become the foreground application 86 */ 87static NSPoint bgMouseLocation; 88static BOOL bgMouseLocationUpdated = FALSE; 89 90X11Application *X11App; 91 92CFStringRef app_prefs_domain_cfstr = NULL; 93 94#define ALL_KEY_MASKS (NSShiftKeyMask | NSControlKeyMask | NSAlternateKeyMask | NSCommandKeyMask) 95 96@interface X11Application (Private) 97- (void) sendX11NSEvent:(NSEvent *)e; 98@end 99 100@implementation X11Application 101 102typedef struct message_struct message; 103struct message_struct { 104 mach_msg_header_t hdr; 105 SEL selector; 106 NSObject *arg; 107}; 108 109static mach_port_t _port; 110 111/* Quartz mode initialization routine. This is often dynamically loaded 112 but is statically linked into this X server. */ 113Bool QuartzModeBundleInit(void); 114 115static void init_ports (void) { 116 kern_return_t r; 117 NSPort *p; 118 119 if (_port != MACH_PORT_NULL) return; 120 121 r = mach_port_allocate (mach_task_self (), MACH_PORT_RIGHT_RECEIVE, &_port); 122 if (r != KERN_SUCCESS) return; 123 124 p = [NSMachPort portWithMachPort:_port]; 125 [p setDelegate:NSApp]; 126 [p scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; 127} 128 129static void message_kit_thread (SEL selector, NSObject *arg) { 130 message msg; 131 kern_return_t r; 132 133 msg.hdr.msgh_bits = MACH_MSGH_BITS (MACH_MSG_TYPE_MAKE_SEND, 0); 134 msg.hdr.msgh_size = sizeof (msg); 135 msg.hdr.msgh_remote_port = _port; 136 msg.hdr.msgh_local_port = MACH_PORT_NULL; 137 msg.hdr.msgh_reserved = 0; 138 msg.hdr.msgh_id = 0; 139 140 msg.selector = selector; 141 msg.arg = [arg retain]; 142 143 r = mach_msg (&msg.hdr, MACH_SEND_MSG, msg.hdr.msgh_size, 144 0, MACH_PORT_NULL, 0, MACH_PORT_NULL); 145 if (r != KERN_SUCCESS) 146 ErrorF("%s: mach_msg failed: %x\n", __FUNCTION__, r); 147} 148 149- (void) handleMachMessage:(void *)_msg { 150 message *msg = _msg; 151 152 [self performSelector:msg->selector withObject:msg->arg]; 153 [msg->arg release]; 154} 155 156- (void) set_controller:obj { 157 if (_controller == nil) _controller = [obj retain]; 158} 159 160- (void) dealloc { 161 if (_controller != nil) [_controller release]; 162 163 if (_port != MACH_PORT_NULL) 164 mach_port_deallocate (mach_task_self (), _port); 165 166 [super dealloc]; 167} 168 169- (void) orderFrontStandardAboutPanel: (id) sender { 170 NSMutableDictionary *dict; 171 NSDictionary *infoDict; 172 NSString *tem; 173 174 dict = [NSMutableDictionary dictionaryWithCapacity:3]; 175 infoDict = [[NSBundle mainBundle] infoDictionary]; 176 177 [dict setObject: NSLocalizedString (@"The X Window System", @"About panel") 178 forKey:@"ApplicationName"]; 179 180 tem = [infoDict objectForKey:@"CFBundleShortVersionString"]; 181 182 [dict setObject:[NSString stringWithFormat:@"XQuartz %@", tem] 183 forKey:@"ApplicationVersion"]; 184 185 [dict setObject:[NSString stringWithFormat:@"xorg-server %s", XSERVER_VERSION] 186 forKey:@"Version"]; 187 188 [self orderFrontStandardAboutPanelWithOptions: dict]; 189} 190 191- (void) activateX:(OSX_BOOL)state { 192 size_t i; 193 DEBUG_LOG("state=%d, _x_active=%d, \n", state, _x_active) 194 if (state) { 195 if(bgMouseLocationUpdated) { 196 DarwinSendPointerEvents(darwinPointer, MotionNotify, 0, bgMouseLocation.x, bgMouseLocation.y, 0.0, 0.0, 0.0); 197 bgMouseLocationUpdated = FALSE; 198 } 199 DarwinSendDDXEvent(kXquartzActivate, 0); 200 } else { 201 202 if(darwin_all_modifier_flags) 203 DarwinUpdateModKeys(0); 204 for(i=0; i < NUM_KEYCODES; i++) { 205 if(keyState[i] == NSKeyDown) { 206 DarwinSendKeyboardEvents(KeyRelease, i); 207 keyState[i] = NSKeyUp; 208 } 209 } 210 211 DarwinSendDDXEvent(kXquartzDeactivate, 0); 212 } 213 214 _x_active = state; 215} 216 217- (void) became_key:(NSWindow *)win { 218 [self activateX:NO]; 219} 220 221- (void) sendEvent:(NSEvent *)e { 222 OSX_BOOL for_appkit, for_x; 223 224 /* By default pass down the responder chain and to X. */ 225 for_appkit = YES; 226 for_x = YES; 227 228 switch ([e type]) { 229 case NSLeftMouseDown: case NSRightMouseDown: case NSOtherMouseDown: 230 case NSLeftMouseUp: case NSRightMouseUp: case NSOtherMouseUp: 231 if ([e window] != nil) { 232 /* Pointer event has an (AppKit) window. Probably something for the kit. */ 233 for_x = NO; 234 if (_x_active) [self activateX:NO]; 235 } else if ([self modalWindow] == nil) { 236 /* Must be an X window. Tell appkit it doesn't have focus. */ 237 for_appkit = NO; 238 239 if ([self isActive]) { 240 [self deactivate]; 241 if (!_x_active && quartzProcs->IsX11Window([e window], 242 [e windowNumber])) 243 [self activateX:YES]; 244 } 245 } 246 247 /* We want to force sending to appkit if we're over the menu bar */ 248 if(!for_appkit) { 249 NSPoint NSlocation = [e locationInWindow]; 250 NSWindow *window = [e window]; 251 NSRect NSframe, NSvisibleFrame; 252 CGRect CGframe, CGvisibleFrame; 253 CGPoint CGlocation; 254 255 if (window != nil) { 256 NSRect frame = [window frame]; 257 NSlocation.x += frame.origin.x; 258 NSlocation.y += frame.origin.y; 259 } 260 261 NSframe = [[NSScreen mainScreen] frame]; 262 NSvisibleFrame = [[NSScreen mainScreen] visibleFrame]; 263 264 CGframe = CGRectMake(NSframe.origin.x, NSframe.origin.y, 265 NSframe.size.width, NSframe.size.height); 266 CGvisibleFrame = CGRectMake(NSvisibleFrame.origin.x, 267 NSvisibleFrame.origin.y, 268 NSvisibleFrame.size.width, 269 NSvisibleFrame.size.height); 270 CGlocation = CGPointMake(NSlocation.x, NSlocation.y); 271 272 if(CGRectContainsPoint(CGframe, CGlocation) && 273 !CGRectContainsPoint(CGvisibleFrame, CGlocation)) 274 for_appkit = YES; 275 } 276 277 break; 278 279 case NSKeyDown: case NSKeyUp: 280 281 if(_x_active) { 282 static BOOL do_swallow = NO; 283 static int swallow_keycode; 284 285 if([e type] == NSKeyDown) { 286 /* Before that though, see if there are any global 287 * shortcuts bound to it. */ 288 289 if(darwinAppKitModMask & [e modifierFlags]) { 290 /* Override to force sending to Appkit */ 291 swallow_keycode = [e keyCode]; 292 do_swallow = YES; 293 for_x = NO; 294#if XPLUGIN_VERSION >= 1 295 } else if(XQuartzEnableKeyEquivalents && 296 xp_is_symbolic_hotkey_event([e eventRef])) { 297 swallow_keycode = [e keyCode]; 298 do_swallow = YES; 299 for_x = NO; 300#endif 301 } else if(XQuartzEnableKeyEquivalents && 302 [[self mainMenu] performKeyEquivalent:e]) { 303 swallow_keycode = [e keyCode]; 304 do_swallow = YES; 305 for_appkit = NO; 306 for_x = NO; 307 } else if(!XQuartzIsRootless 308 && ([e modifierFlags] & ALL_KEY_MASKS) == (NSCommandKeyMask | NSAlternateKeyMask) 309 && ([e keyCode] == 0 /*a*/ || [e keyCode] == 53 /*Esc*/)) { 310 /* We have this here to force processing fullscreen 311 * toggle even if XQuartzEnableKeyEquivalents is disabled */ 312 swallow_keycode = [e keyCode]; 313 do_swallow = YES; 314 for_x = NO; 315 for_appkit = NO; 316 DarwinSendDDXEvent(kXquartzToggleFullscreen, 0); 317 } else { 318 /* No kit window is focused, so send it to X. */ 319 for_appkit = NO; 320 } 321 } else { /* KeyUp */ 322 /* If we saw a key equivalent on the down, don't pass 323 * the up through to X. */ 324 if (do_swallow && [e keyCode] == swallow_keycode) { 325 do_swallow = NO; 326 for_x = NO; 327 } 328 } 329 } else { /* !_x_active */ 330 for_x = NO; 331 } 332 break; 333 334 case NSFlagsChanged: 335 /* Don't tell X11 about modifiers changing while it's not active */ 336 if (!_x_active) 337 for_x = NO; 338 break; 339 340 case NSAppKitDefined: 341 switch ([e subtype]) { 342 static BOOL x_was_active = NO; 343 344 case NSApplicationActivatedEventType: 345 for_x = NO; 346 if ([e window] == nil && x_was_active) { 347 BOOL order_all_windows = YES, workspaces, ok; 348 for_appkit = NO; 349 350 /* FIXME: This is a hack to avoid passing the event to AppKit which 351 * would result in it raising one of its windows. 352 */ 353 _appFlags._active = YES; 354 355 [self set_front_process:nil]; 356 357 /* Get the Spaces preference for SwitchOnActivate */ 358 (void)CFPreferencesAppSynchronize(CFSTR("com.apple.dock")); 359 workspaces = CFPreferencesGetAppBooleanValue(CFSTR("workspaces"), CFSTR("com.apple.dock"), &ok); 360 if (!ok) 361 workspaces = NO; 362 363 if (workspaces) { 364 (void)CFPreferencesAppSynchronize(CFSTR(".GlobalPreferences")); 365 order_all_windows = CFPreferencesGetAppBooleanValue(CFSTR("AppleSpacesSwitchOnActivate"), CFSTR(".GlobalPreferences"), &ok); 366 if (!ok) 367 order_all_windows = YES; 368 } 369 370 /* TODO: In the workspaces && !AppleSpacesSwitchOnActivate case, the windows are ordered 371 * correctly, but we need to activate the top window on this space if there is 372 * none active. 373 * 374 * If there are no active windows, and there are minimized windows, we should 375 * be restoring one of them. 376 */ 377 if ([e data2] & 0x10) { // 0x10 (bfCPSOrderAllWindowsForward) is set when we use cmd-tab or the dock icon 378 DarwinSendDDXEvent(kXquartzBringAllToFront, 1, order_all_windows); 379 } 380 } 381 break; 382 383 case 18: /* ApplicationDidReactivate */ 384 if (XQuartzFullscreenVisible) for_appkit = NO; 385 break; 386 387 case NSApplicationDeactivatedEventType: 388 for_x = NO; 389 390 x_was_active = _x_active; 391 if(_x_active) 392 [self activateX:NO]; 393 break; 394 } 395 break; 396 397 default: break; /* for gcc */ 398 } 399 400 if (for_appkit) [super sendEvent:e]; 401 402 if (for_x) [self sendX11NSEvent:e]; 403} 404 405- (void) set_window_menu:(NSArray *)list { 406 [_controller set_window_menu:list]; 407} 408 409- (void) set_window_menu_check:(NSNumber *)n { 410 [_controller set_window_menu_check:n]; 411} 412 413- (void) set_apps_menu:(NSArray *)list { 414 [_controller set_apps_menu:list]; 415} 416 417- (void) set_front_process:unused { 418 [NSApp activateIgnoringOtherApps:YES]; 419 420 if ([self modalWindow] == nil) 421 [self activateX:YES]; 422} 423 424- (void) set_can_quit:(NSNumber *)state { 425 [_controller set_can_quit:[state boolValue]]; 426} 427 428- (void) server_ready:unused { 429 [_controller server_ready]; 430} 431 432- (void) show_hide_menubar:(NSNumber *)state { 433 /* Also shows/hides the dock */ 434 if ([state boolValue]) 435 SetSystemUIMode(kUIModeNormal, 0); 436 else 437 SetSystemUIMode(kUIModeAllHidden, XQuartzFullscreenMenu ? kUIOptionAutoShowMenuBar : 0); // kUIModeAllSuppressed or kUIOptionAutoShowMenuBar can be used to allow "mouse-activation" 438} 439 440- (void) launch_client:(NSString *)cmd { 441 (void)[_controller application:self openFile:cmd]; 442} 443 444/* user preferences */ 445 446/* Note that these functions only work for arrays whose elements 447 can be toll-free-bridged between NS and CF worlds. */ 448 449static const void *cfretain (CFAllocatorRef a, const void *b) { 450 return CFRetain (b); 451} 452 453static void cfrelease (CFAllocatorRef a, const void *b) { 454 CFRelease (b); 455} 456 457static CFMutableArrayRef nsarray_to_cfarray (NSArray *in) { 458 CFMutableArrayRef out; 459 CFArrayCallBacks cb; 460 NSObject *ns; 461 const CFTypeRef *cf; 462 int i, count; 463 464 memset (&cb, 0, sizeof (cb)); 465 cb.version = 0; 466 cb.retain = cfretain; 467 cb.release = cfrelease; 468 469 count = [in count]; 470 out = CFArrayCreateMutable (NULL, count, &cb); 471 472 for (i = 0; i < count; i++) { 473 ns = [in objectAtIndex:i]; 474 475 if ([ns isKindOfClass:[NSArray class]]) 476 cf = (CFTypeRef) nsarray_to_cfarray ((NSArray *) ns); 477 else 478 cf = CFRetain ((CFTypeRef) ns); 479 480 CFArrayAppendValue (out, cf); 481 CFRelease (cf); 482 } 483 484 return out; 485} 486 487static NSMutableArray * cfarray_to_nsarray (CFArrayRef in) { 488 NSMutableArray *out; 489 const CFTypeRef *cf; 490 NSObject *ns; 491 int i, count; 492 493 count = CFArrayGetCount (in); 494 out = [[NSMutableArray alloc] initWithCapacity:count]; 495 496 for (i = 0; i < count; i++) { 497 cf = CFArrayGetValueAtIndex (in, i); 498 499 if (CFGetTypeID (cf) == CFArrayGetTypeID ()) 500 ns = cfarray_to_nsarray ((CFArrayRef) cf); 501 else 502 ns = [(id)cf retain]; 503 504 [out addObject:ns]; 505 [ns release]; 506 } 507 508 return out; 509} 510 511- (CFPropertyListRef) prefs_get_copy:(NSString *)key { 512 CFPropertyListRef value; 513 514 value = CFPreferencesCopyAppValue ((CFStringRef) key, app_prefs_domain_cfstr); 515 516 if (value == NULL) { 517 static CFDictionaryRef defaults; 518 519 if (defaults == NULL) { 520 CFStringRef error = NULL; 521 CFDataRef data; 522 CFURLRef url; 523 SInt32 error_code; 524 525 url = (CFURLCreateFromFileSystemRepresentation 526 (NULL, (unsigned char *)DEFAULTS_FILE, strlen (DEFAULTS_FILE), false)); 527 if (CFURLCreateDataAndPropertiesFromResource (NULL, url, &data, 528 NULL, NULL, &error_code)) { 529 defaults = (CFPropertyListCreateFromXMLData 530 (NULL, data, kCFPropertyListMutableContainersAndLeaves, &error)); 531 if (error != NULL) CFRelease (error); 532 CFRelease (data); 533 } 534 CFRelease (url); 535 536 if (defaults != NULL) { 537 NSMutableArray *apps, *elt; 538 int count, i; 539 NSString *name, *nname; 540 541 /* Localize the names in the default apps menu. */ 542 543 apps = [(NSDictionary *)defaults objectForKey:@PREFS_APPSMENU]; 544 if (apps != nil) { 545 count = [apps count]; 546 for (i = 0; i < count; i++) { 547 elt = [apps objectAtIndex:i]; 548 if (elt != nil && [elt isKindOfClass:[NSArray class]]) { 549 name = [elt objectAtIndex:0]; 550 if (name != nil) { 551 nname = NSLocalizedString (name, nil); 552 if (nname != nil && nname != name) 553 [elt replaceObjectAtIndex:0 withObject:nname]; 554 } 555 } 556 } 557 } 558 } 559 } 560 561 if (defaults != NULL) value = CFDictionaryGetValue (defaults, key); 562 if (value != NULL) CFRetain (value); 563 } 564 565 return value; 566} 567 568- (int) prefs_get_integer:(NSString *)key default:(int)def { 569 CFPropertyListRef value; 570 int ret; 571 572 value = [self prefs_get_copy:key]; 573 574 if (value != NULL && CFGetTypeID (value) == CFNumberGetTypeID ()) 575 CFNumberGetValue (value, kCFNumberIntType, &ret); 576 else if (value != NULL && CFGetTypeID (value) == CFStringGetTypeID ()) 577 ret = CFStringGetIntValue (value); 578 else 579 ret = def; 580 581 if (value != NULL) CFRelease (value); 582 583 return ret; 584} 585 586- (const char *) prefs_get_string:(NSString *)key default:(const char *)def { 587 CFPropertyListRef value; 588 const char *ret = NULL; 589 590 value = [self prefs_get_copy:key]; 591 592 if (value != NULL && CFGetTypeID (value) == CFStringGetTypeID ()) { 593 NSString *s = (NSString *) value; 594 595 ret = [s UTF8String]; 596 } 597 598 if (value != NULL) CFRelease (value); 599 600 return ret != NULL ? ret : def; 601} 602 603- (NSURL *) prefs_copy_url:(NSString *)key default:(NSURL *)def { 604 CFPropertyListRef value; 605 NSURL *ret = NULL; 606 607 value = [self prefs_get_copy:key]; 608 609 if (value != NULL && CFGetTypeID (value) == CFStringGetTypeID ()) { 610 NSString *s = (NSString *) value; 611 612 ret = [NSURL URLWithString:s]; 613 [ret retain]; 614 } 615 616 if (value != NULL) CFRelease (value); 617 618 return ret != NULL ? ret : def; 619} 620 621- (float) prefs_get_float:(NSString *)key default:(float)def { 622 CFPropertyListRef value; 623 float ret = def; 624 625 value = [self prefs_get_copy:key]; 626 627 if (value != NULL 628 && CFGetTypeID (value) == CFNumberGetTypeID () 629 && CFNumberIsFloatType (value)) 630 CFNumberGetValue (value, kCFNumberFloatType, &ret); 631 else if (value != NULL && CFGetTypeID (value) == CFStringGetTypeID ()) 632 ret = CFStringGetDoubleValue (value); 633 634 if (value != NULL) CFRelease (value); 635 636 return ret; 637} 638 639- (int) prefs_get_boolean:(NSString *)key default:(int)def { 640 CFPropertyListRef value; 641 int ret = def; 642 643 value = [self prefs_get_copy:key]; 644 645 if (value != NULL) { 646 if (CFGetTypeID (value) == CFNumberGetTypeID ()) 647 CFNumberGetValue (value, kCFNumberIntType, &ret); 648 else if (CFGetTypeID (value) == CFBooleanGetTypeID ()) 649 ret = CFBooleanGetValue (value); 650 else if (CFGetTypeID (value) == CFStringGetTypeID ()) { 651 const char *tem = [(NSString *) value UTF8String]; 652 if (strcasecmp (tem, "true") == 0 || strcasecmp (tem, "yes") == 0) 653 ret = YES; 654 else 655 ret = NO; 656 } 657 658 CFRelease (value); 659 } 660 return ret; 661} 662 663- (NSArray *) prefs_get_array:(NSString *)key { 664 NSArray *ret = nil; 665 CFPropertyListRef value; 666 667 value = [self prefs_get_copy:key]; 668 669 if (value != NULL) { 670 if (CFGetTypeID (value) == CFArrayGetTypeID ()) 671 ret = [cfarray_to_nsarray (value) autorelease]; 672 673 CFRelease (value); 674 } 675 676 return ret; 677} 678 679- (void) prefs_set_integer:(NSString *)key value:(int)value { 680 CFNumberRef x; 681 682 x = CFNumberCreate (NULL, kCFNumberIntType, &value); 683 684 CFPreferencesSetValue ((CFStringRef) key, (CFTypeRef) x, app_prefs_domain_cfstr, 685 kCFPreferencesCurrentUser, kCFPreferencesAnyHost); 686 687 CFRelease (x); 688} 689 690- (void) prefs_set_float:(NSString *)key value:(float)value { 691 CFNumberRef x; 692 693 x = CFNumberCreate (NULL, kCFNumberFloatType, &value); 694 695 CFPreferencesSetValue ((CFStringRef) key, (CFTypeRef) x, app_prefs_domain_cfstr, 696 kCFPreferencesCurrentUser, kCFPreferencesAnyHost); 697 698 CFRelease (x); 699} 700 701- (void) prefs_set_boolean:(NSString *)key value:(int)value { 702 CFPreferencesSetValue ((CFStringRef) key, 703 (CFTypeRef) (value ? kCFBooleanTrue 704 : kCFBooleanFalse), app_prefs_domain_cfstr, 705 kCFPreferencesCurrentUser, kCFPreferencesAnyHost); 706 707} 708 709- (void) prefs_set_array:(NSString *)key value:(NSArray *)value { 710 CFArrayRef cfarray; 711 712 cfarray = nsarray_to_cfarray (value); 713 CFPreferencesSetValue ((CFStringRef) key, 714 (CFTypeRef) cfarray, 715 app_prefs_domain_cfstr, 716 kCFPreferencesCurrentUser, kCFPreferencesAnyHost); 717 CFRelease (cfarray); 718} 719 720- (void) prefs_set_string:(NSString *)key value:(NSString *)value { 721 CFPreferencesSetValue ((CFStringRef) key, (CFTypeRef) value, 722 app_prefs_domain_cfstr, kCFPreferencesCurrentUser, 723 kCFPreferencesAnyHost); 724} 725 726- (void) prefs_synchronize { 727 CFPreferencesAppSynchronize (kCFPreferencesCurrentApplication); 728} 729 730- (void) read_defaults 731{ 732 NSString *nsstr; 733 const char *tem; 734 735 XQuartzRootlessDefault = [self prefs_get_boolean:@PREFS_ROOTLESS 736 default:XQuartzRootlessDefault]; 737 XQuartzFullscreenMenu = [self prefs_get_boolean:@PREFS_FULLSCREEN_MENU 738 default:XQuartzFullscreenMenu]; 739 XQuartzFullscreenDisableHotkeys = ![self prefs_get_boolean:@PREFS_FULLSCREEN_HOTKEYS 740 default:!XQuartzFullscreenDisableHotkeys]; 741 darwinFakeButtons = [self prefs_get_boolean:@PREFS_FAKEBUTTONS 742 default:darwinFakeButtons]; 743 XQuartzOptionSendsAlt = [self prefs_get_boolean:@PREFS_OPTION_SENDS_ALT 744 default:XQuartzOptionSendsAlt]; 745 746 if (darwinFakeButtons) { 747 const char *fake2, *fake3; 748 749 fake2 = [self prefs_get_string:@PREFS_FAKE_BUTTON2 default:NULL]; 750 fake3 = [self prefs_get_string:@PREFS_FAKE_BUTTON3 default:NULL]; 751 752 if (fake2 != NULL) darwinFakeMouse2Mask = DarwinParseModifierList(fake2, TRUE); 753 if (fake3 != NULL) darwinFakeMouse3Mask = DarwinParseModifierList(fake3, TRUE); 754 } 755 756 tem = [self prefs_get_string:@PREFS_APPKIT_MODIFIERS default:NULL]; 757 if (tem != NULL) darwinAppKitModMask = DarwinParseModifierList(tem, TRUE); 758 759 tem = [self prefs_get_string:@PREFS_WINDOW_ITEM_MODIFIERS default:NULL]; 760 if (tem != NULL) { 761 windowItemModMask = DarwinParseModifierList(tem, FALSE); 762 } else { 763 nsstr = NSLocalizedString (@"window item modifiers", @"window item modifiers"); 764 if(nsstr != NULL) { 765 tem = [nsstr UTF8String]; 766 if((tem != NULL) && strcmp(tem, "window item modifiers")) { 767 windowItemModMask = DarwinParseModifierList(tem, FALSE); 768 } 769 } 770 } 771 772 XQuartzEnableKeyEquivalents = [self prefs_get_boolean:@PREFS_KEYEQUIVS 773 default:XQuartzEnableKeyEquivalents]; 774 775 darwinSyncKeymap = [self prefs_get_boolean:@PREFS_SYNC_KEYMAP 776 default:darwinSyncKeymap]; 777 778 darwinDesiredDepth = [self prefs_get_integer:@PREFS_DEPTH 779 default:darwinDesiredDepth]; 780 781 noTestExtensions = ![self prefs_get_boolean:@PREFS_TEST_EXTENSIONS 782 default:FALSE]; 783 784 XQuartzScrollInDeviceDirection = [self prefs_get_boolean:@PREFS_SCROLL_IN_DEV_DIRECTION 785 default:XQuartzScrollInDeviceDirection]; 786 787#if XQUARTZ_SPARKLE 788 NSURL *url = [self prefs_copy_url:@PREFS_UPDATE_FEED default:nil]; 789 if(url) { 790 [[SUUpdater sharedUpdater] setFeedURL:url]; 791 [url release]; 792 } 793#endif 794} 795 796/* This will end up at the end of the responder chain. */ 797- (void) copy:sender { 798 DarwinSendDDXEvent(kXquartzPasteboardNotify, 1, 799 AppleWMCopyToPasteboard); 800} 801 802- (X11Controller *) controller { 803 return _controller; 804} 805 806- (OSX_BOOL) x_active { 807 return _x_active; 808} 809 810@end 811 812static NSArray * 813array_with_strings_and_numbers (int nitems, const char **items, 814 const char *numbers) { 815 NSMutableArray *array, *subarray; 816 NSString *string, *number; 817 int i; 818 819 /* (Can't autorelease on the X server thread) */ 820 821 array = [[NSMutableArray alloc] initWithCapacity:nitems]; 822 823 for (i = 0; i < nitems; i++) { 824 subarray = [[NSMutableArray alloc] initWithCapacity:2]; 825 826 string = [[NSString alloc] initWithUTF8String:items[i]]; 827 [subarray addObject:string]; 828 [string release]; 829 830 if (numbers[i] != 0) { 831 number = [[NSString alloc] initWithFormat:@"%d", numbers[i]]; 832 [subarray addObject:number]; 833 [number release]; 834 } else 835 [subarray addObject:@""]; 836 837 [array addObject:subarray]; 838 [subarray release]; 839 } 840 841 return array; 842} 843 844void X11ApplicationSetWindowMenu (int nitems, const char **items, 845 const char *shortcuts) { 846 NSArray *array; 847 array = array_with_strings_and_numbers (nitems, items, shortcuts); 848 849 /* Send the array of strings over to the appkit thread */ 850 851 message_kit_thread (@selector (set_window_menu:), array); 852 [array release]; 853} 854 855void X11ApplicationSetWindowMenuCheck (int idx) { 856 NSNumber *n; 857 858 n = [[NSNumber alloc] initWithInt:idx]; 859 860 message_kit_thread (@selector (set_window_menu_check:), n); 861 862 [n release]; 863} 864 865void X11ApplicationSetFrontProcess (void) { 866 message_kit_thread (@selector (set_front_process:), nil); 867} 868 869void X11ApplicationSetCanQuit (int state) { 870 NSNumber *n; 871 872 n = [[NSNumber alloc] initWithBool:state]; 873 874 message_kit_thread (@selector (set_can_quit:), n); 875 876 [n release]; 877} 878 879void X11ApplicationServerReady (void) { 880 message_kit_thread (@selector (server_ready:), nil); 881} 882 883void X11ApplicationShowHideMenubar (int state) { 884 NSNumber *n; 885 886 n = [[NSNumber alloc] initWithBool:state]; 887 888 message_kit_thread (@selector (show_hide_menubar:), n); 889 890 [n release]; 891} 892 893void X11ApplicationLaunchClient (const char *cmd) { 894 NSString *string; 895 896 string = [[NSString alloc] initWithUTF8String:cmd]; 897 898 message_kit_thread (@selector (launch_client:), string); 899 900 [string release]; 901} 902 903/* This is a special function in that it is run from the *SERVER* thread and 904 * not the AppKit thread. We want to block entering a screen-capturing RandR 905 * mode until we notify the user about how to get out if the X11 client crashes. 906 */ 907Bool X11ApplicationCanEnterRandR(void) { 908 NSString *title, *msg; 909 910 if([X11App prefs_get_boolean:@PREFS_NO_RANDR_ALERT default:NO] || XQuartzShieldingWindowLevel != 0) 911 return TRUE; 912 913 title = NSLocalizedString(@"Enter RandR mode?", @"Dialog title when switching to RandR"); 914 msg = NSLocalizedString(@"An application has requested X11 to change the resolution of your display. X11 will restore the display to its previous state when the requesting application requests to return to the previous state. Alternatively, you can use the ⌥⌘A key sequence to force X11 to return to the previous state.", 915 @"Dialog when switching to RandR"); 916 917 if(!XQuartzIsRootless) 918 QuartzShowFullscreen(FALSE); 919 920 switch(NSRunAlertPanel(title, msg, NSLocalizedString(@"Allow", @""), NSLocalizedString (@"Cancel", @""), NSLocalizedString (@"Always Allow", @""))) { 921 case NSAlertOtherReturn: 922 [X11App prefs_set_boolean:@PREFS_NO_RANDR_ALERT value:YES]; 923 [X11App prefs_synchronize]; 924 case NSAlertDefaultReturn: 925 return YES; 926 927 default: 928 return NO; 929 } 930} 931 932static void check_xinitrc (void) { 933 char *tem, buf[1024]; 934 NSString *msg; 935 936 if ([X11App prefs_get_boolean:@PREFS_DONE_XINIT_CHECK default:NO]) 937 return; 938 939 tem = getenv ("HOME"); 940 if (tem == NULL) goto done; 941 942 snprintf (buf, sizeof (buf), "%s/.xinitrc", tem); 943 if (access (buf, F_OK) != 0) 944 goto done; 945 946 msg = NSLocalizedString (@"You have an existing ~/.xinitrc file.\n\n\ 947Windows displayed by X11 applications may not have titlebars, or may look \ 948different to windows displayed by native applications.\n\n\ 949Would you like to move aside the existing file and use the standard X11 \ 950environment the next time you start X11?", @"Startup xinitrc dialog"); 951 952 if(NSAlertDefaultReturn == NSRunAlertPanel (nil, msg, NSLocalizedString (@"Yes", @""), 953 NSLocalizedString (@"No", @""), nil)) { 954 char buf2[1024]; 955 int i = -1; 956 957 snprintf (buf2, sizeof (buf2), "%s.old", buf); 958 959 for(i = 1; access (buf2, F_OK) == 0; i++) 960 snprintf (buf2, sizeof (buf2), "%s.old.%d", buf, i); 961 962 rename (buf, buf2); 963 } 964 965 done: 966 [X11App prefs_set_boolean:@PREFS_DONE_XINIT_CHECK value:YES]; 967 [X11App prefs_synchronize]; 968} 969 970static inline pthread_t create_thread(void *(*func)(void *), void *arg) { 971 pthread_attr_t attr; 972 pthread_t tid; 973 974 pthread_attr_init(&attr); 975 pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM); 976 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); 977 pthread_create(&tid, &attr, func, arg); 978 pthread_attr_destroy(&attr); 979 980 return tid; 981} 982 983static void *xpbproxy_x_thread(void *args) { 984 xpbproxy_run(); 985 986 fprintf(stderr, "xpbproxy thread is terminating unexpectedly.\n"); 987 return NULL; 988} 989 990void X11ApplicationMain (int argc, char **argv, char **envp) { 991 NSAutoreleasePool *pool; 992 993#ifdef DEBUG 994 while (access ("/tmp/x11-block", F_OK) == 0) sleep (1); 995#endif 996 997 pool = [[NSAutoreleasePool alloc] init]; 998 X11App = (X11Application *) [X11Application sharedApplication]; 999 init_ports (); 1000 1001 app_prefs_domain_cfstr = (CFStringRef)[[NSBundle mainBundle] bundleIdentifier]; 1002 1003 if (app_prefs_domain_cfstr == NULL) { 1004 ErrorF("X11ApplicationMain: Unable to determine bundle identifier. Your installation of XQuartz may be broken.\n"); 1005 app_prefs_domain_cfstr = CFSTR(LAUNCHD_ID_PREFIX".X11"); 1006 } 1007 1008 [NSApp read_defaults]; 1009 [NSBundle loadNibNamed:@"main" owner:NSApp]; 1010 [[NSNotificationCenter defaultCenter] addObserver:NSApp 1011 selector:@selector (became_key:) 1012 name:NSWindowDidBecomeKeyNotification object:nil]; 1013 1014 /* 1015 * The xpr Quartz mode is statically linked into this server. 1016 * Initialize all the Quartz functions. 1017 */ 1018 QuartzModeBundleInit(); 1019 1020 /* Calculate the height of the menubar so we can avoid it. */ 1021 aquaMenuBarHeight = NSHeight([[NSScreen mainScreen] frame]) - 1022 NSMaxY([[NSScreen mainScreen] visibleFrame]); 1023 1024 /* Set the key layout seed before we start the server */ 1025#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1050 1026 last_key_layout = TISCopyCurrentKeyboardLayoutInputSource(); 1027 1028 if(!last_key_layout) 1029 fprintf(stderr, "X11ApplicationMain: Unable to determine TISCopyCurrentKeyboardLayoutInputSource() at startup.\n"); 1030#else 1031 KLGetCurrentKeyboardLayout(&last_key_layout); 1032 if(!last_key_layout) 1033 fprintf(stderr, "X11ApplicationMain: Unable to determine KLGetCurrentKeyboardLayout() at startup.\n"); 1034#endif 1035 1036 if (!QuartsResyncKeymap(FALSE)) { 1037 fprintf(stderr, "X11ApplicationMain: Could not build a valid keymap.\n"); 1038 } 1039 1040 /* Tell the server thread that it can proceed */ 1041 QuartzInitServer(argc, argv, envp); 1042 1043 /* This must be done after QuartzInitServer because it can result in 1044 * an mieqEnqueue() - <rdar://problem/6300249> 1045 */ 1046 check_xinitrc(); 1047 1048 create_thread(xpbproxy_x_thread, NULL); 1049 1050#if XQUARTZ_SPARKLE 1051 [[X11App controller] setup_sparkle]; 1052 [[SUUpdater sharedUpdater] resetUpdateCycle]; 1053// [[SUUpdater sharedUpdater] checkForUpdates:X11App]; 1054#endif 1055 1056 [pool release]; 1057 [NSApp run]; 1058 /* not reached */ 1059} 1060 1061@implementation X11Application (Private) 1062 1063#ifdef NX_DEVICELCMDKEYMASK 1064/* This is to workaround a bug in the VNC server where we sometimes see the L 1065 * modifier and sometimes see no "side" 1066 */ 1067static inline int ensure_flag(int flags, int device_independent, int device_dependents, int device_dependent_default) { 1068 if( (flags & device_independent) && 1069 !(flags & device_dependents)) 1070 flags |= device_dependent_default; 1071 return flags; 1072} 1073#endif 1074 1075#ifdef DEBUG_UNTRUSTED_POINTER_DELTA 1076static const char *untrusted_str(NSEvent *e) { 1077 switch([e type]) { 1078 case NSScrollWheel: 1079 return "NSScrollWheel"; 1080 case NSTabletPoint: 1081 return "NSTabletPoint"; 1082 case NSOtherMouseDown: 1083 return "NSOtherMouseDown"; 1084 case NSOtherMouseUp: 1085 return "NSOtherMouseUp"; 1086 case NSLeftMouseDown: 1087 return "NSLeftMouseDown"; 1088 case NSLeftMouseUp: 1089 return "NSLeftMouseUp"; 1090 default: 1091 switch([e subtype]) { 1092 case NSTabletPointEventSubtype: 1093 return "NSTabletPointEventSubtype"; 1094 case NSTabletProximityEventSubtype: 1095 return "NSTabletProximityEventSubtype"; 1096 default: 1097 return "Other"; 1098 } 1099 } 1100} 1101#endif 1102 1103- (void) sendX11NSEvent:(NSEvent *)e { 1104 NSPoint location = NSZeroPoint, tilt = NSZeroPoint; 1105 int ev_button, ev_type; 1106 float pressure = 0.0; 1107 DeviceIntPtr pDev; 1108 int modifierFlags; 1109 BOOL isMouseOrTabletEvent, isTabletEvent; 1110 1111 isMouseOrTabletEvent = [e type] == NSLeftMouseDown || [e type] == NSOtherMouseDown || [e type] == NSRightMouseDown || 1112 [e type] == NSLeftMouseUp || [e type] == NSOtherMouseUp || [e type] == NSRightMouseUp || 1113 [e type] == NSLeftMouseDragged || [e type] == NSOtherMouseDragged || [e type] == NSRightMouseDragged || 1114 [e type] == NSMouseMoved || [e type] == NSTabletPoint || [e type] == NSScrollWheel; 1115 1116 isTabletEvent = ([e type] == NSTabletPoint) || 1117 (isMouseOrTabletEvent && ([e subtype] == NSTabletPointEventSubtype || [e subtype] == NSTabletProximityEventSubtype)); 1118 1119 if(isMouseOrTabletEvent) { 1120 static NSPoint lastpt; 1121 NSWindow *window = [e window]; 1122 NSRect screen = [[[NSScreen screens] objectAtIndex:0] frame]; 1123 BOOL hasUntrustedPointerDelta; 1124 1125 // NSEvents for tablets are not consistent wrt deltaXY between events, so we cannot rely on that 1126 // Thus tablets will be subject to the warp-pointer bug worked around by the delta, but tablets 1127 // are not normally used in cases where that bug would present itself, so this is a fair tradeoff 1128 // <rdar://problem/7111003> deltaX and deltaY are incorrect for NSMouseMoved, NSTabletPointEventSubtype 1129 // http://xquartz.macosforge.org/trac/ticket/288 1130 hasUntrustedPointerDelta = isTabletEvent; 1131 1132 // The deltaXY for middle click events also appear erroneous after fast user switching 1133 // <rdar://problem/7979468> deltaX and deltaY are incorrect for NSOtherMouseDown and NSOtherMouseUp after FUS 1134 // http://xquartz.macosforge.org/trac/ticket/389 1135 hasUntrustedPointerDelta = hasUntrustedPointerDelta || [e type] == NSOtherMouseDown || [e type] == NSOtherMouseUp; 1136 1137 // The deltaXY for scroll events correspond to the scroll delta, not the pointer delta 1138 // <rdar://problem/7989690> deltaXY for wheel events are being sent as mouse movement 1139 hasUntrustedPointerDelta = hasUntrustedPointerDelta || [e type] == NSScrollWheel; 1140 1141#ifdef DEBUG_UNTRUSTED_POINTER_DELTA 1142 hasUntrustedPointerDelta = hasUntrustedPointerDelta || [e type] == NSLeftMouseDown || [e type] == NSLeftMouseUp; 1143#endif 1144 1145 if (window != nil) { 1146 NSRect frame = [window frame]; 1147 location = [e locationInWindow]; 1148 location.x += frame.origin.x; 1149 location.y += frame.origin.y; 1150 lastpt = location; 1151 } else if(hasUntrustedPointerDelta) { 1152#ifdef DEBUG_UNTRUSTED_POINTER_DELTA 1153 ErrorF("--- Begin Event Debug ---\n"); 1154 ErrorF("Event type: %s\n", untrusted_str(e)); 1155 ErrorF("old lastpt: (%0.2f, %0.2f)\n", lastpt.x, lastpt.y); 1156 ErrorF(" delta: (%0.2f, %0.2f)\n", [e deltaX], -[e deltaY]); 1157 ErrorF(" location: (%0.2f, %0.2f)\n", lastpt.x + [e deltaX], lastpt.y - [e deltaY]); 1158 ErrorF("workaround: (%0.2f, %0.2f)\n", [e locationInWindow].x, [e locationInWindow].y); 1159 ErrorF("--- End Event Debug ---\n"); 1160 1161 location.x = lastpt.x + [e deltaX]; 1162 location.y = lastpt.y - [e deltaY]; 1163 lastpt = [e locationInWindow]; 1164#else 1165 location = [e locationInWindow]; 1166 lastpt = location; 1167#endif 1168 } else { 1169 location.x = lastpt.x + [e deltaX]; 1170 location.y = lastpt.y - [e deltaY]; 1171 lastpt = [e locationInWindow]; 1172 } 1173 1174 /* Convert coordinate system */ 1175 location.y = (screen.origin.y + screen.size.height) - location.y; 1176 } 1177 1178 modifierFlags = [e modifierFlags]; 1179 1180#ifdef NX_DEVICELCMDKEYMASK 1181 /* This is to workaround a bug in the VNC server where we sometimes see the L 1182 * modifier and sometimes see no "side" 1183 */ 1184 modifierFlags = ensure_flag(modifierFlags, NX_CONTROLMASK, NX_DEVICELCTLKEYMASK | NX_DEVICERCTLKEYMASK, NX_DEVICELCTLKEYMASK); 1185 modifierFlags = ensure_flag(modifierFlags, NX_SHIFTMASK, NX_DEVICELSHIFTKEYMASK | NX_DEVICERSHIFTKEYMASK, NX_DEVICELSHIFTKEYMASK); 1186 modifierFlags = ensure_flag(modifierFlags, NX_COMMANDMASK, NX_DEVICELCMDKEYMASK | NX_DEVICERCMDKEYMASK, NX_DEVICELCMDKEYMASK); 1187 modifierFlags = ensure_flag(modifierFlags, NX_ALTERNATEMASK, NX_DEVICELALTKEYMASK | NX_DEVICERALTKEYMASK, NX_DEVICELALTKEYMASK); 1188#endif 1189 1190 modifierFlags &= darwin_all_modifier_mask; 1191 1192 /* We don't receive modifier key events while out of focus, and 3button 1193 * emulation mucks this up, so we need to check our modifier flag state 1194 * on every event... ugg 1195 */ 1196 1197 if(darwin_all_modifier_flags != modifierFlags) 1198 DarwinUpdateModKeys(modifierFlags); 1199 1200 switch ([e type]) { 1201 case NSLeftMouseDown: ev_button=1; ev_type=ButtonPress; goto handle_mouse; 1202 case NSOtherMouseDown: ev_button=2; ev_type=ButtonPress; goto handle_mouse; 1203 case NSRightMouseDown: ev_button=3; ev_type=ButtonPress; goto handle_mouse; 1204 case NSLeftMouseUp: ev_button=1; ev_type=ButtonRelease; goto handle_mouse; 1205 case NSOtherMouseUp: ev_button=2; ev_type=ButtonRelease; goto handle_mouse; 1206 case NSRightMouseUp: ev_button=3; ev_type=ButtonRelease; goto handle_mouse; 1207 case NSLeftMouseDragged: ev_button=1; ev_type=MotionNotify; goto handle_mouse; 1208 case NSOtherMouseDragged: ev_button=2; ev_type=MotionNotify; goto handle_mouse; 1209 case NSRightMouseDragged: ev_button=3; ev_type=MotionNotify; goto handle_mouse; 1210 case NSMouseMoved: ev_button=0; ev_type=MotionNotify; goto handle_mouse; 1211 case NSTabletPoint: ev_button=0; ev_type=MotionNotify; goto handle_mouse; 1212 1213 handle_mouse: 1214 pDev = darwinPointer; 1215 1216 /* NSTabletPoint can have no subtype */ 1217 if([e type] != NSTabletPoint && 1218 [e subtype] == NSTabletProximityEventSubtype) { 1219 switch([e pointingDeviceType]) { 1220 case NSEraserPointingDevice: 1221 darwinTabletCurrent=darwinTabletEraser; 1222 break; 1223 case NSPenPointingDevice: 1224 darwinTabletCurrent=darwinTabletStylus; 1225 break; 1226 case NSCursorPointingDevice: 1227 case NSUnknownPointingDevice: 1228 default: 1229 darwinTabletCurrent=darwinTabletCursor; 1230 break; 1231 } 1232 1233 /* NSTabletProximityEventSubtype doesn't encode pressure ant tilt 1234 * So we just pretend the motion was caused by the mouse. Hopefully 1235 * we'll have a better solution for this in the future (like maybe 1236 * NSTabletProximityEventSubtype will come from NSTabletPoint 1237 * rather than NSMouseMoved. 1238 pressure = [e pressure]; 1239 tilt = [e tilt]; 1240 pDev = darwinTabletCurrent; 1241 */ 1242 1243 DarwinSendProximityEvents([e isEnteringProximity] ? ProximityIn : ProximityOut, 1244 location.x, location.y); 1245 } 1246 1247 if ([e type] == NSTabletPoint || [e subtype] == NSTabletPointEventSubtype) { 1248 pressure = [e pressure]; 1249 tilt = [e tilt]; 1250 1251 pDev = darwinTabletCurrent; 1252 } 1253 1254 if(!XQuartzServerVisible && noTestExtensions) { 1255#if defined(XPLUGIN_VERSION) && XPLUGIN_VERSION > 0 1256/* Older libXplugin (Tiger/"Stock" Leopard) aren't thread safe, so we can't call xp_find_window from the Appkit thread */ 1257 xp_window_id wid = 0; 1258 xp_error e; 1259 1260 /* Sigh. Need to check that we're really over one of 1261 * our windows. (We need to receive pointer events while 1262 * not in the foreground, but we don't want to receive them 1263 * when another window is over us or we might show a tooltip) 1264 */ 1265 1266 e = xp_find_window(location.x, location.y, 0, &wid); 1267 1268 if (e != XP_Success || (e == XP_Success && wid == 0)) 1269#endif 1270 { 1271 bgMouseLocation = location; 1272 bgMouseLocationUpdated = TRUE; 1273 return; 1274 } 1275 } 1276 1277 if(bgMouseLocationUpdated) { 1278 if(!(ev_type == MotionNotify && ev_button == 0)) { 1279 DarwinSendPointerEvents(pDev, MotionNotify, 0, location.x, 1280 location.y, pressure, tilt.x, tilt.y); 1281 } 1282 bgMouseLocationUpdated = FALSE; 1283 } 1284 1285 DarwinSendPointerEvents(pDev, ev_type, ev_button, location.x, location.y, 1286 pressure, tilt.x, tilt.y); 1287 1288 break; 1289 1290 case NSTabletProximity: 1291 switch([e pointingDeviceType]) { 1292 case NSEraserPointingDevice: 1293 darwinTabletCurrent=darwinTabletEraser; 1294 break; 1295 case NSPenPointingDevice: 1296 darwinTabletCurrent=darwinTabletStylus; 1297 break; 1298 case NSCursorPointingDevice: 1299 case NSUnknownPointingDevice: 1300 default: 1301 darwinTabletCurrent=darwinTabletCursor; 1302 break; 1303 } 1304 1305 DarwinSendProximityEvents([e isEnteringProximity] ? ProximityIn : ProximityOut, 1306 location.x, location.y); 1307 break; 1308 1309 case NSScrollWheel: 1310 { 1311 float deltaX = [e deltaX]; 1312 float deltaY = [e deltaY]; 1313#if !defined(XPLUGIN_VERSION) || XPLUGIN_VERSION == 0 1314 /* If we're in the background, we need to send a MotionNotify event 1315 * first, since we aren't getting them on background mouse motion 1316 */ 1317 if(!XQuartzServerVisible && noTestExtensions) { 1318 bgMouseLocationUpdated = FALSE; 1319 DarwinSendPointerEvents(darwinPointer, MotionNotify, 0, location.x, 1320 location.y, pressure, tilt.x, tilt.y); 1321 } 1322#endif 1323#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 1324 // TODO: Change 1117 to NSAppKitVersionNumber10_7 when it is defined 1325 if(NSAppKitVersionNumber >= 1117 && XQuartzScrollInDeviceDirection && [e isDirectionInvertedFromDevice]) { 1326 deltaX *= -1; 1327 deltaY *= -1; 1328 } 1329#endif 1330 DarwinSendScrollEvents(deltaX, deltaY, location.x, location.y, 1331 pressure, tilt.x, tilt.y); 1332 break; 1333 } 1334 case NSKeyDown: case NSKeyUp: 1335 { 1336 /* XKB clobbers our keymap at startup, so we need to force it on the first keypress. 1337 * TODO: Make this less of a kludge. 1338 */ 1339 static int force_resync_keymap = YES; 1340 if(force_resync_keymap) { 1341 DarwinSendDDXEvent(kXquartzReloadKeymap, 0); 1342 force_resync_keymap = NO; 1343 } 1344 } 1345 1346 if(darwinSyncKeymap) { 1347#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1050 1348 TISInputSourceRef key_layout = TISCopyCurrentKeyboardLayoutInputSource(); 1349 TISInputSourceRef clear; 1350 if (CFEqual(key_layout, last_key_layout)) { 1351 CFRelease(key_layout); 1352 } else { 1353 /* Swap/free thread-safely */ 1354 clear = last_key_layout; 1355 last_key_layout = key_layout; 1356 CFRelease(clear); 1357#else 1358 KeyboardLayoutRef key_layout; 1359 KLGetCurrentKeyboardLayout(&key_layout); 1360 if(key_layout != last_key_layout) { 1361 last_key_layout = key_layout; 1362#endif 1363 /* Update keyInfo */ 1364 if (!QuartsResyncKeymap(TRUE)) { 1365 fprintf(stderr, "sendX11NSEvent: Could not build a valid keymap.\n"); 1366 } 1367 } 1368 } 1369 1370 /* Avoid stuck keys on context switch */ 1371 if(keyState[[e keyCode]] == [e type]) 1372 return; 1373 keyState[[e keyCode]] = [e type]; 1374 1375 DarwinSendKeyboardEvents(([e type] == NSKeyDown) ? KeyPress : KeyRelease, [e keyCode]); 1376 break; 1377 1378 default: break; /* for gcc */ 1379 } 1380} 1381@end 1382