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