diff options
Diffstat (limited to 'xorg-server/hw/xquartz/X11Application.m')
-rw-r--r-- | xorg-server/hw/xquartz/X11Application.m | 953 |
1 files changed, 593 insertions, 360 deletions
diff --git a/xorg-server/hw/xquartz/X11Application.m b/xorg-server/hw/xquartz/X11Application.m index be5511d30..9f4738c47 100644 --- a/xorg-server/hw/xquartz/X11Application.m +++ b/xorg-server/hw/xquartz/X11Application.m @@ -1,6 +1,6 @@ /* X11Application.m -- subclass of NSApplication to multiplex events - Copyright (c) 2002-2007 Apple Inc. + Copyright (c) 2002-2008 Apple Inc. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files @@ -27,48 +27,69 @@ promote the sale, use or other dealings in this Software without prior written authorization. */ +#include "sanitizedCarbon.h" + #ifdef HAVE_DIX_CONFIG_H #include <dix-config.h> #endif #include "quartzCommon.h" -#include "quartzForeground.h" #import "X11Application.h" -#include <Carbon/Carbon.h> - -/* ouch! */ -#define BOOL X_BOOL -# include "darwin.h" -# include "darwinEvents.h" -# include "quartz.h" -# define _APPLEWM_SERVER_ -# include "X11/extensions/applewm.h" -# include "micmap.h" -#undef BOOL + +#include "darwin.h" +#include "darwinEvents.h" +#include "quartzKeyboard.h" +#include "quartz.h" +#define _APPLEWM_SERVER_ +#include "X11/extensions/applewm.h" +#include "micmap.h" #include <mach/mach.h> #include <unistd.h> -#include <pthread.h> +#include <AvailabilityMacros.h> + +#include <Xplugin.h> -#include "rootlessCommon.h" +// pbproxy/pbproxy.h +extern BOOL xpbproxy_init (void); -WindowPtr xprGetXWindowFromAppKit(int windowNumber); // xpr/xprFrame.c +#define DEFAULTS_FILE X11LIBDIR"/X11/xserver/Xquartz.plist" + +#ifndef XSERVER_VERSION +#define XSERVER_VERSION "?" +#endif -#define DEFAULTS_FILE "/usr/X11/lib/X11/xserver/Xquartz.plist" +#define ProximityIn 0 +#define ProximityOut 1 -int X11EnableKeyEquivalents = TRUE; +/* Stuck modifier / button state... force release when we context switch */ +static NSEventType keyState[NUM_KEYCODES]; +static int modifierFlagsMask; + +int X11EnableKeyEquivalents = TRUE, quartzFullscreenMenu = FALSE; int quartzHasRoot = FALSE, quartzEnableRootless = TRUE; -extern int darwinFakeButtons, input_check_flag; -extern Bool enable_stereo; +extern Bool noTestExtensions; + +#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1050 +static TISInputSourceRef last_key_layout; +#else +static KeyboardLayoutRef last_key_layout; +#endif -extern xEvent *darwinEvents; +extern int darwinFakeButtons; X11Application *X11App; +CFStringRef app_prefs_domain_cfstr = NULL; + #define ALL_KEY_MASKS (NSShiftKeyMask | NSControlKeyMask | NSAlternateKeyMask | NSCommandKeyMask) +@interface X11Application (Private) +- (void) sendX11NSEvent:(NSEvent *)e; +@end + @implementation X11Application typedef struct message_struct message; @@ -80,8 +101,6 @@ struct message_struct { static mach_port_t _port; -static void send_nsevent (NSEventType type, NSEvent *e); - /* Quartz mode initialization routine. This is often dynamically loaded but is statically linked into this X server. */ Bool QuartzModeBundleInit(void); @@ -144,195 +163,259 @@ static void message_kit_thread (SEL selector, NSObject *arg) { NSMutableDictionary *dict; NSDictionary *infoDict; NSString *tem; - - dict = [NSMutableDictionary dictionaryWithCapacity:2]; + + dict = [NSMutableDictionary dictionaryWithCapacity:3]; infoDict = [[NSBundle mainBundle] infoDictionary]; - + [dict setObject: NSLocalizedString (@"The X Window System", @"About panel") - forKey:@"ApplicationName"]; - + forKey:@"ApplicationName"]; + tem = [infoDict objectForKey:@"CFBundleShortVersionString"]; - - [dict setObject:[NSString stringWithFormat:@"XQuartz %@ - (xorg-server %s)", tem, XSERVER_VERSION] - forKey:@"ApplicationVersion"]; - + + [dict setObject:[NSString stringWithFormat:@"XQuartz %@", tem] + forKey:@"ApplicationVersion"]; + + [dict setObject:[NSString stringWithFormat:@"xorg-server %s", XSERVER_VERSION] + forKey:@"Version"]; + [self orderFrontStandardAboutPanelWithOptions: dict]; } -- (void) activateX:(BOOL)state { +- (void) activateX:(OSX_BOOL)state { /* Create a TSM document that supports full Unicode input, and - have it activated while X is active (unless using the old - keymapping files) */ + have it activated while X is active */ static TSMDocumentID x11_document; - DEBUG_LOG("state=%d, _x_active=%d, \n", state, _x_active) + size_t i; + DEBUG_LOG("state=%d, _x_active=%d, \n", state, _x_active) if (state) { - QuartzMessageServerThread (kXDarwinActivate, 0); - - if (!_x_active) { - if (x11_document == 0 && darwinKeymapFile == NULL) { - OSType types[1]; - types[0] = kUnicodeDocument; - NewTSMDocument (1, types, &x11_document, 0); - } - - if (x11_document != 0) ActivateTSMDocument (x11_document); - } + DarwinSendDDXEvent(kXquartzActivate, 0); + + if (!_x_active) { + if (x11_document == 0) { + OSType types[1]; + types[0] = kUnicodeDocument; + NewTSMDocument (1, types, &x11_document, 0); + } + + if (x11_document != 0) ActivateTSMDocument (x11_document); + } } else { - QuartzMessageServerThread (kXDarwinDeactivate, 0); - - if (_x_active && x11_document != 0) - DeactivateTSMDocument (x11_document); + + if(darwin_modifier_flags) + DarwinUpdateModKeys(0); + for(i=0; i < NUM_KEYCODES; i++) { + if(keyState[i] == NSKeyDown) { + DarwinSendKeyboardEvents(KeyRelease, i); + keyState[i] = NSKeyUp; + } + } + + DarwinSendDDXEvent(kXquartzDeactivate, 0); + + if (_x_active && x11_document != 0) + DeactivateTSMDocument (x11_document); } - + _x_active = state; } - (void) became_key:(NSWindow *)win { - [self activateX:NO]; + [self activateX:NO]; } - (void) sendEvent:(NSEvent *)e { - NSEventType type; - BOOL for_appkit, for_x; - - type = [e type]; - - /* By default pass down the responder chain and to X. */ - for_appkit = YES; - for_x = YES; - - switch (type) { - case NSLeftMouseDown: case NSRightMouseDown: case NSOtherMouseDown: - case NSLeftMouseUp: case NSRightMouseUp: case NSOtherMouseUp: - if ([e window] != nil) { - /* Pointer event has an (AppKit) window. Probably something for the kit. */ - for_x = NO; - if (_x_active) [self activateX:NO]; - } else if ([self modalWindow] == nil) { - /* Must be an X window. Tell appkit it doesn't have focus. */ - WindowPtr pWin = xprGetXWindowFromAppKit([e windowNumber]); - if (pWin) RootlessReorderWindow(pWin); - for_appkit = NO; - - if ([self isActive]) { - [self deactivate]; - - if (!_x_active && quartzProcs->IsX11Window([e window], - [e windowNumber])) - [self activateX:YES]; - } - } - break; - - case NSKeyDown: case NSKeyUp: - if (_x_active) { - static int swallow_up; - - /* No kit window is focused, so send it to X. */ - for_appkit = NO; - if (type == NSKeyDown) { - /* Before that though, see if there are any global - shortcuts bound to it. */ - - if (X11EnableKeyEquivalents - && [[self mainMenu] performKeyEquivalent:e]) { - swallow_up = [e keyCode]; - for_x = NO; - } else if (!quartzEnableRootless - && ([e modifierFlags] & ALL_KEY_MASKS) - == (NSCommandKeyMask | NSAlternateKeyMask) - && ([e keyCode] == 0 /*a*/ - || [e keyCode] == 53 /*Esc*/)) { - swallow_up = 0; - for_x = NO; -#ifdef DARWIN_DDX_MISSING - QuartzMessageServerThread (kXDarwinToggleFullscreen, 0); -#endif - } - } else { - /* If we saw a key equivalent on the down, don't pass - the up through to X. */ - - if (swallow_up != 0 && [e keyCode] == swallow_up) { - swallow_up = 0; - for_x = NO; - } - } - } else for_x = NO; - break; + OSX_BOOL for_appkit, for_x; - case NSFlagsChanged: - /* For the l33t X users who remap modifier keys to normal keysyms. */ - if (!_x_active) for_x = NO; - break; + /* By default pass down the responder chain and to X. */ + for_appkit = YES; + for_x = YES; - case NSAppKitDefined: - switch ([e subtype]) { - case NSApplicationActivatedEventType: - for_x = NO; - if ([self modalWindow] == nil) { - for_appkit = NO; - - /* FIXME: hack to avoid having to pass the event to appkit, - which would cause it to raise one of its windows. */ - _appFlags._active = YES; - - [self activateX:YES]; - if ([e data2] & 0x10) X11ApplicationSetFrontProcess(); - } - break; - - case 18: /* ApplicationDidReactivate */ - if (quartzHasRoot) for_appkit = NO; - break; - - case NSApplicationDeactivatedEventType: - for_x = NO; - [self activateX:NO]; - break; + switch ([e type]) { + case NSLeftMouseDown: case NSRightMouseDown: case NSOtherMouseDown: + case NSLeftMouseUp: case NSRightMouseUp: case NSOtherMouseUp: + if ([e window] != nil) { + /* Pointer event has an (AppKit) window. Probably something for the kit. */ + for_x = NO; + if (_x_active) [self activateX:NO]; + } else if ([self modalWindow] == nil) { + /* Must be an X window. Tell appkit it doesn't have focus. */ + for_appkit = NO; + + if ([self isActive]) { + [self deactivate]; + if (!_x_active && quartzProcs->IsX11Window([e window], + [e windowNumber])) + [self activateX:YES]; + } + } + + /* We want to force sending to appkit if we're over the menu bar */ + if(!for_appkit) { + NSPoint NSlocation = [e locationInWindow]; + NSWindow *window = [e window]; + + if (window != nil) { + NSRect frame = [window frame]; + NSlocation.x += frame.origin.x; + NSlocation.y += frame.origin.y; + } + + NSRect NSframe = [[NSScreen mainScreen] frame]; + NSRect NSvisibleFrame = [[NSScreen mainScreen] visibleFrame]; + + CGRect CGframe = CGRectMake(NSframe.origin.x, NSframe.origin.y, + NSframe.size.width, NSframe.size.height); + CGRect CGvisibleFrame = CGRectMake(NSvisibleFrame.origin.x, + NSvisibleFrame.origin.y, + NSvisibleFrame.size.width, + NSvisibleFrame.size.height); + CGPoint CGlocation = CGPointMake(NSlocation.x, NSlocation.y); + + if(CGRectContainsPoint(CGframe, CGlocation) && + !CGRectContainsPoint(CGvisibleFrame, CGlocation)) + for_appkit = YES; + } + + break; + + case NSKeyDown: case NSKeyUp: + + if(_x_active) { + static BOOL do_swallow = NO; + static int swallow_keycode; + + if([e type] == NSKeyDown) { + /* Before that though, see if there are any global + * shortcuts bound to it. */ + + if(darwinAppKitModMask & [e modifierFlags]) { + /* Override to force sending to Appkit */ + swallow_keycode = [e keyCode]; + do_swallow = YES; + for_x = NO; +#if XPLUGIN_VERSION >= 1 + } else if(X11EnableKeyEquivalents && + xp_is_symbolic_hotkey_event([e eventRef])) { + swallow_keycode = [e keyCode]; + do_swallow = YES; + for_x = NO; +#endif + } else if(X11EnableKeyEquivalents && + [[self mainMenu] performKeyEquivalent:e]) { + swallow_keycode = [e keyCode]; + do_swallow = YES; + for_appkit = NO; + for_x = NO; + } else if(!quartzEnableRootless + && ([e modifierFlags] & ALL_KEY_MASKS) == (NSCommandKeyMask | NSAlternateKeyMask) + && ([e keyCode] == 0 /*a*/ || [e keyCode] == 53 /*Esc*/)) { + /* We have this here to force processing fullscreen + * toggle even if X11EnableKeyEquivalents is disabled */ + swallow_keycode = [e keyCode]; + do_swallow = YES; + for_x = NO; + for_appkit = NO; + DarwinSendDDXEvent(kXquartzToggleFullscreen, 0); + } else { + /* No kit window is focused, so send it to X. */ + for_appkit = NO; + } + } else { /* KeyUp */ + /* If we saw a key equivalent on the down, don't pass + * the up through to X. */ + if (do_swallow && [e keyCode] == swallow_keycode) { + do_swallow = NO; + for_x = NO; + } + } + } else { /* !_x_active */ + for_x = NO; + } + break; + + case NSFlagsChanged: + /* Don't tell X11 about modifiers changing while it's not active */ + if (!_x_active) + for_x = NO; + break; + + case NSAppKitDefined: + switch ([e subtype]) { + case NSApplicationActivatedEventType: + for_x = NO; + if ([self modalWindow] == nil) { + for_appkit = NO; + + /* FIXME: hack to avoid having to pass the event to appkit, + which would cause it to raise one of its windows. */ + _appFlags._active = YES; + + [self activateX:YES]; + + /* Get the Spaces preference for SwitchOnActivate */ + (void)CFPreferencesAppSynchronize(CFSTR(".GlobalPreferences")); + BOOL switch_on_activate, ok; + switch_on_activate = CFPreferencesGetAppBooleanValue(CFSTR("AppleSpacesSwitchOnActivate"), CFSTR(".GlobalPreferences"), &ok); + if(!ok) + switch_on_activate = YES; + + if ([e data2] & 0x10 && switch_on_activate) + DarwinSendDDXEvent(kXquartzBringAllToFront, 0); + } + break; + + case 18: /* ApplicationDidReactivate */ + if (quartzHasRoot) for_appkit = NO; + break; + + case NSApplicationDeactivatedEventType: + for_x = NO; + [self activateX:NO]; + break; + } + break; + + default: break; /* for gcc */ } - break; - default: break; /* for gcc */ - } - - if (for_appkit) [super sendEvent:e]; - - if (for_x) send_nsevent (type, e); + if (for_appkit) [super sendEvent:e]; + + if (for_x) [self sendX11NSEvent:e]; } - (void) set_window_menu:(NSArray *)list { - [_controller set_window_menu:list]; + [_controller set_window_menu:list]; } - (void) set_window_menu_check:(NSNumber *)n { - [_controller set_window_menu_check:n]; + [_controller set_window_menu_check:n]; } - (void) set_apps_menu:(NSArray *)list { - [_controller set_apps_menu:list]; + [_controller set_apps_menu:list]; } - (void) set_front_process:unused { - /* Hackery needed due to argv[0] hackery */ - // [self activateX:YES]; - ProcessSerialNumber psn = { 0, kCurrentProcess }; - SetFrontProcess(&psn); + [NSApp activateIgnoringOtherApps:YES]; - QuartzMessageServerThread(kXDarwinBringAllToFront, 0); + if ([self modalWindow] == nil) + [self activateX:YES]; } - (void) set_can_quit:(NSNumber *)state { - [_controller set_can_quit:[state boolValue]]; + [_controller set_can_quit:[state boolValue]]; } - (void) server_ready:unused { - [_controller server_ready]; + [_controller server_ready]; } - (void) show_hide_menubar:(NSNumber *)state { - if ([state boolValue]) ShowMenuBar (); - else HideMenuBar (); + /* Also shows/hides the dock */ + if ([state boolValue]) + SetSystemUIMode(kUIModeNormal, 0); + else + SetSystemUIMode(kUIModeAllHidden, quartzFullscreenMenu ? kUIOptionAutoShowMenuBar : 0); // kUIModeAllSuppressed or kUIOptionAutoShowMenuBar can be used to allow "mouse-activation" } @@ -350,63 +433,63 @@ static void cfrelease (CFAllocatorRef a, const void *b) { } static CFMutableArrayRef nsarray_to_cfarray (NSArray *in) { - CFMutableArrayRef out; - CFArrayCallBacks cb; - NSObject *ns; - const CFTypeRef *cf; - int i, count; - - memset (&cb, 0, sizeof (cb)); - cb.version = 0; - cb.retain = cfretain; - cb.release = cfrelease; - - count = [in count]; - out = CFArrayCreateMutable (NULL, count, &cb); - - for (i = 0; i < count; i++) { - ns = [in objectAtIndex:i]; - - if ([ns isKindOfClass:[NSArray class]]) - cf = (CFTypeRef) nsarray_to_cfarray ((NSArray *) ns); - else - cf = CFRetain ((CFTypeRef) ns); - - CFArrayAppendValue (out, cf); - CFRelease (cf); - } - - return out; + CFMutableArrayRef out; + CFArrayCallBacks cb; + NSObject *ns; + const CFTypeRef *cf; + int i, count; + + memset (&cb, 0, sizeof (cb)); + cb.version = 0; + cb.retain = cfretain; + cb.release = cfrelease; + + count = [in count]; + out = CFArrayCreateMutable (NULL, count, &cb); + + for (i = 0; i < count; i++) { + ns = [in objectAtIndex:i]; + + if ([ns isKindOfClass:[NSArray class]]) + cf = (CFTypeRef) nsarray_to_cfarray ((NSArray *) ns); + else + cf = CFRetain ((CFTypeRef) ns); + + CFArrayAppendValue (out, cf); + CFRelease (cf); + } + + return out; } static NSMutableArray * cfarray_to_nsarray (CFArrayRef in) { - NSMutableArray *out; - const CFTypeRef *cf; - NSObject *ns; - int i, count; - - count = CFArrayGetCount (in); - out = [[NSMutableArray alloc] initWithCapacity:count]; - - for (i = 0; i < count; i++) { - cf = CFArrayGetValueAtIndex (in, i); - - if (CFGetTypeID (cf) == CFArrayGetTypeID ()) - ns = cfarray_to_nsarray ((CFArrayRef) cf); - else - ns = [(id)cf retain]; - - [out addObject:ns]; - [ns release]; - } - - return out; + NSMutableArray *out; + const CFTypeRef *cf; + NSObject *ns; + int i, count; + + count = CFArrayGetCount (in); + out = [[NSMutableArray alloc] initWithCapacity:count]; + + for (i = 0; i < count; i++) { + cf = CFArrayGetValueAtIndex (in, i); + + if (CFGetTypeID (cf) == CFArrayGetTypeID ()) + ns = cfarray_to_nsarray ((CFArrayRef) cf); + else + ns = [(id)cf retain]; + + [out addObject:ns]; + [ns release]; + } + + return out; } - (CFPropertyListRef) prefs_get:(NSString *)key { CFPropertyListRef value; - value = CFPreferencesCopyAppValue ((CFStringRef) key, CFSTR (APP_PREFS)); + value = CFPreferencesCopyAppValue ((CFStringRef) key, app_prefs_domain_cfstr); if (value == NULL) { static CFDictionaryRef defaults; @@ -503,7 +586,7 @@ static NSMutableArray * cfarray_to_nsarray (CFArrayRef in) { if (value != NULL && CFGetTypeID (value) == CFNumberGetTypeID () - && CFNumberIsFloatType (value)) + && CFNumberIsFloatType (value)) CFNumberGetValue (value, kCFNumberFloatType, &ret); else if (value != NULL && CFGetTypeID (value) == CFStringGetTypeID ()) ret = CFStringGetDoubleValue (value); @@ -558,7 +641,7 @@ static NSMutableArray * cfarray_to_nsarray (CFArrayRef in) { x = CFNumberCreate (NULL, kCFNumberIntType, &value); - CFPreferencesSetValue ((CFStringRef) key, (CFTypeRef) x, CFSTR (APP_PREFS), + CFPreferencesSetValue ((CFStringRef) key, (CFTypeRef) x, app_prefs_domain_cfstr, kCFPreferencesCurrentUser, kCFPreferencesAnyHost); CFRelease (x); @@ -569,7 +652,7 @@ static NSMutableArray * cfarray_to_nsarray (CFArrayRef in) { x = CFNumberCreate (NULL, kCFNumberFloatType, &value); - CFPreferencesSetValue ((CFStringRef) key, (CFTypeRef) x, CFSTR (APP_PREFS), + CFPreferencesSetValue ((CFStringRef) key, (CFTypeRef) x, app_prefs_domain_cfstr, kCFPreferencesCurrentUser, kCFPreferencesAnyHost); CFRelease (x); @@ -577,8 +660,8 @@ static NSMutableArray * cfarray_to_nsarray (CFArrayRef in) { - (void) prefs_set_boolean:(NSString *)key value:(int)value { CFPreferencesSetValue ((CFStringRef) key, - (CFTypeRef) value ? kCFBooleanTrue - : kCFBooleanFalse, CFSTR (APP_PREFS), + (CFTypeRef) (value ? kCFBooleanTrue + : kCFBooleanFalse), app_prefs_domain_cfstr, kCFPreferencesCurrentUser, kCFPreferencesAnyHost); } @@ -589,14 +672,14 @@ static NSMutableArray * cfarray_to_nsarray (CFArrayRef in) { cfarray = nsarray_to_cfarray (value); CFPreferencesSetValue ((CFStringRef) key, (CFTypeRef) cfarray, - CFSTR (APP_PREFS), + app_prefs_domain_cfstr, kCFPreferencesCurrentUser, kCFPreferencesAnyHost); CFRelease (cfarray); } - (void) prefs_set_string:(NSString *)key value:(NSString *)value { CFPreferencesSetValue ((CFStringRef) key, (CFTypeRef) value, - CFSTR (APP_PREFS), kCFPreferencesCurrentUser, + app_prefs_domain_cfstr, kCFPreferencesCurrentUser, kCFPreferencesAnyHost); } @@ -606,55 +689,65 @@ static NSMutableArray * cfarray_to_nsarray (CFArrayRef in) { - (void) read_defaults { + NSString *nsstr; const char *tem; quartzUseSysBeep = [self prefs_get_boolean:@PREFS_SYSBEEP - default:quartzUseSysBeep]; + default:quartzUseSysBeep]; quartzEnableRootless = [self prefs_get_boolean:@PREFS_ROOTLESS - default:quartzEnableRootless]; -#ifdef DARWIN_DDX_MISSING + default:quartzEnableRootless]; + quartzFullscreenMenu = [self prefs_get_boolean:@PREFS_FULLSCREEN_MENU + default:quartzFullscreenMenu]; quartzFullscreenDisableHotkeys = ![self prefs_get_boolean: - @PREFS_FULLSCREEN_HOTKEYS default: - !quartzFullscreenDisableHotkeys]; - quartzXpluginOptions = [self prefs_get_integer:@PREFS_XP_OPTIONS - default:quartzXpluginOptions]; -#endif + @PREFS_FULLSCREEN_HOTKEYS default:!quartzFullscreenDisableHotkeys]; darwinFakeButtons = [self prefs_get_boolean:@PREFS_FAKEBUTTONS - default:darwinFakeButtons]; + default:darwinFakeButtons]; if (darwinFakeButtons) { - const char *fake2, *fake3; - - fake2 = [self prefs_get_string:@PREFS_FAKE_BUTTON2 default:NULL]; - fake3 = [self prefs_get_string:@PREFS_FAKE_BUTTON3 default:NULL]; - - if (fake2 != NULL) darwinFakeMouse2Mask = DarwinParseModifierList(fake2); - if (fake3 != NULL) darwinFakeMouse3Mask = DarwinParseModifierList(fake3); + const char *fake2, *fake3; + + fake2 = [self prefs_get_string:@PREFS_FAKE_BUTTON2 default:NULL]; + fake3 = [self prefs_get_string:@PREFS_FAKE_BUTTON3 default:NULL]; + + if (fake2 != NULL) darwinFakeMouse2Mask = DarwinParseModifierList(fake2, TRUE); + if (fake3 != NULL) darwinFakeMouse3Mask = DarwinParseModifierList(fake3, TRUE); } + + tem = [self prefs_get_string:@PREFS_APPKIT_MODIFIERS default:NULL]; + if (tem != NULL) darwinAppKitModMask = DarwinParseModifierList(tem, TRUE); + tem = [self prefs_get_string:@PREFS_WINDOW_ITEM_MODIFIERS default:NULL]; + if (tem != NULL) { + windowItemModMask = DarwinParseModifierList(tem, FALSE); + } else { + nsstr = NSLocalizedString (@"window item modifiers", @"window item modifiers"); + if(nsstr != NULL) { + tem = [nsstr UTF8String]; + if((tem != NULL) && strcmp(tem, "window item modifiers")) { + windowItemModMask = DarwinParseModifierList(tem, FALSE); + } + } + } + X11EnableKeyEquivalents = [self prefs_get_boolean:@PREFS_KEYEQUIVS - default:X11EnableKeyEquivalents]; + default:X11EnableKeyEquivalents]; darwinSyncKeymap = [self prefs_get_boolean:@PREFS_SYNC_KEYMAP - default:darwinSyncKeymap]; - - tem = [self prefs_get_string:@PREFS_KEYMAP_FILE default:NULL]; - if (tem != NULL) darwinKeymapFile = strdup (tem); - else darwinKeymapFile = NULL; - + default:darwinSyncKeymap]; + darwinDesiredDepth = [self prefs_get_integer:@PREFS_DEPTH - default:darwinDesiredDepth]; - - enable_stereo = [self prefs_get_boolean:@PREFS_ENABLE_STEREO - default:false]; + default:darwinDesiredDepth]; + + noTestExtensions = ![self prefs_get_boolean:@PREFS_TEST_EXTENSIONS + default:FALSE]; } /* This will end up at the end of the responder chain. */ - (void) copy:sender { - QuartzMessageServerThread (kXDarwinPasteboardNotify, 1, + DarwinSendDDXEvent(kXquartzPasteboardNotify, 1, AppleWMCopyToPasteboard); } -- (BOOL) x_active { +- (OSX_BOOL) x_active { return _x_active; } @@ -741,19 +834,6 @@ void X11ApplicationShowHideMenubar (int state) { [n release]; } -static void * create_thread (void *func, void *arg) { - pthread_attr_t attr; - pthread_t tid; - - pthread_attr_init (&attr); - pthread_attr_setscope (&attr, PTHREAD_SCOPE_SYSTEM); - pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED); - pthread_create (&tid, &attr, func, arg); - pthread_attr_destroy (&attr); - - return (void *) tid; -} - static void check_xinitrc (void) { char *tem, buf[1024]; NSString *msg; @@ -768,26 +848,23 @@ static void check_xinitrc (void) { if (access (buf, F_OK) != 0) goto done; - /* FIXME: put localized strings into Resources/English.lproj */ - msg = NSLocalizedString (@"You have an existing ~/.xinitrc file.\n\n\ Windows displayed by X11 applications may not have titlebars, or may look \ different to windows displayed by native applications.\n\n\ Would you like to move aside the existing file and use the standard X11 \ -environment?", @"Startup xinitrc dialog"); - - if (NSRunAlertPanel (nil, msg, NSLocalizedString (@"Yes", @""), - NSLocalizedString (@"No", @""), nil) - == NSAlertDefaultReturn) { - char buf2[1024]; - int i = -1; - - snprintf (buf2, sizeof (buf2), "%s.old", buf); +environment the next time you start X11?", @"Startup xinitrc dialog"); + + if(NSAlertDefaultReturn == NSRunAlertPanel (nil, msg, NSLocalizedString (@"Yes", @""), + NSLocalizedString (@"No", @""), nil)) { + char buf2[1024]; + int i = -1; - for (i = 1; access (buf2, F_OK) == 0; i++) - snprintf (buf2, sizeof (buf2), "%s.old.%d", buf, i); + snprintf (buf2, sizeof (buf2), "%s.old", buf); - rename (buf, buf2); + for(i = 1; access (buf2, F_OK) == 0; i++) + snprintf (buf2, sizeof (buf2), "%s.old.%d", buf, i); + + rename (buf, buf2); } done: @@ -795,8 +872,9 @@ environment?", @"Startup xinitrc dialog"); [X11App prefs_synchronize]; } -void X11ApplicationMain (int argc, const char **argv, void (*server_thread) (void *), void *server_arg) { +void X11ApplicationMain (int argc, char **argv, char **envp) { NSAutoreleasePool *pool; + int *p; #ifdef DEBUG while (access ("/tmp/x11-block", F_OK) == 0) sleep (1); @@ -805,12 +883,14 @@ void X11ApplicationMain (int argc, const char **argv, void (*server_thread) (voi pool = [[NSAutoreleasePool alloc] init]; X11App = (X11Application *) [X11Application sharedApplication]; init_ports (); + + app_prefs_domain_cfstr = (CFStringRef)[[NSBundle mainBundle] bundleIdentifier]; + [NSApp read_defaults]; [NSBundle loadNibNamed:@"main" owner:NSApp]; [[NSNotificationCenter defaultCenter] addObserver:NSApp selector:@selector (became_key:) name:NSWindowDidBecomeKeyNotification object:nil]; - check_xinitrc (); /* * The xpr Quartz mode is statically linked into this server. @@ -821,102 +901,255 @@ void X11ApplicationMain (int argc, const char **argv, void (*server_thread) (voi /* Calculate the height of the menubar so we can avoid it. */ aquaMenuBarHeight = NSHeight([[NSScreen mainScreen] frame]) - NSMaxY([[NSScreen mainScreen] visibleFrame]); - - if (!create_thread (server_thread, server_arg)) { - ErrorF("can't create secondary thread\n"); - exit (1); - } - QuartzMoveToForeground(); + /* Set the key layout seed before we start the server */ +#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1050 + last_key_layout = TISCopyCurrentKeyboardLayoutInputSource(); + if(!last_key_layout) + fprintf(stderr, "X11ApplicationMain: Unable to determine TISCopyCurrentKeyboardLayoutInputSource() at startup.\n"); +#else + KLGetCurrentKeyboardLayout(&last_key_layout); + if(!last_key_layout) + fprintf(stderr, "X11ApplicationMain: Unable to determine KLGetCurrentKeyboardLayout() at startup.\n"); +#endif + + memset(keyInfo.keyMap, 0, sizeof(keyInfo.keyMap)); + if (!QuartzReadSystemKeymap(&keyInfo)) { + fprintf(stderr, "X11ApplicationMain: Could not build a valid keymap.\n"); + } + + for(p=darwin_modifier_mask_list, modifierFlagsMask=0; *p; p++) { + modifierFlagsMask |= *p; + } + + /* Tell the server thread that it can proceed */ + QuartzInitServer(argc, argv, envp); + + /* This must be done after QuartzInitServer because it can result in + * an mieqEnqueue() - <rdar://problem/6300249> + */ + check_xinitrc(); + + if(!xpbproxy_init()) + fprintf(stderr, "Error initializing xpbproxy\n"); + [NSApp run]; /* not reached */ } -/* event conversion */ - -static inline unsigned short -convert_flags (unsigned int nsflags) { - unsigned int xflags = 0; - - if (nsflags == ~0) return 0xffff; - - if (nsflags & NSAlphaShiftKeyMask) xflags |= LockMask; - if (nsflags & NSShiftKeyMask) xflags |= ShiftMask; - if (nsflags & NSControlKeyMask) xflags |= ControlMask; - if (nsflags & NSAlternateKeyMask) xflags |= Mod1Mask; - if (nsflags & NSCommandKeyMask) xflags |= Mod2Mask; - /* FIXME: secondaryfn? */ - - return xflags; +@implementation X11Application (Private) + +#ifdef NX_DEVICELCMDKEYMASK +/* This is to workaround a bug in the VNC server where we sometimes see the L + * modifier and sometimes see no "side" + */ +static inline int ensure_flag(int flags, int device_independent, int device_dependents, int device_dependent_default) { + if( (flags & device_independent) && + !(flags & device_dependents)) + flags |= device_dependent_default; + return flags; } +#endif - -// This code should probably be merged with that in XDarwin's XServer.m - BB -static void send_nsevent (NSEventType type, NSEvent *e) { - // static unsigned int button_state = 0; +- (void) sendX11NSEvent:(NSEvent *)e { NSRect screen; NSPoint location; NSWindow *window; - int pointer_x, pointer_y, ev_button, ev_type; - // int num_events=0, i=0, state; - // xEvent xe; - - /* convert location to global top-left coordinates */ + int ev_button, ev_type; + float pointer_x, pointer_y, pressure, tilt_x, tilt_y; + DeviceIntPtr pDev; + int modifierFlags; + + /* convert location to be relative to top-left of primary display */ location = [e locationInWindow]; window = [e window]; screen = [[[NSScreen screens] objectAtIndex:0] frame]; - + if (window != nil) { - NSRect frame = [window frame]; - pointer_x = location.x + frame.origin.x; - pointer_y = (((screen.origin.y + screen.size.height) - - location.y) - frame.origin.y); + NSRect frame = [window frame]; + pointer_x = location.x + frame.origin.x; + pointer_y = (screen.origin.y + screen.size.height) + - (location.y + frame.origin.y); } else { - pointer_x = location.x; - pointer_y = (screen.origin.y + screen.size.height) - location.y; + pointer_x = location.x; + pointer_y = (screen.origin.y + screen.size.height) - location.y; } + + /* Setup our valuators. These will range from 0 to 1 */ + pressure = 0; + tilt_x = 0; + tilt_y = 0; - pointer_y -= aquaMenuBarHeight; - // state = convert_flags ([e modifierFlags]); + modifierFlags = [e modifierFlags]; - switch (type) { - case NSLeftMouseDown: ev_button=1; ev_type=ButtonPress; goto handle_mouse; - case NSOtherMouseDown: ev_button=2; ev_type=ButtonPress; goto handle_mouse; - case NSRightMouseDown: ev_button=3; ev_type=ButtonPress; goto handle_mouse; - case NSLeftMouseUp: ev_button=1; ev_type=ButtonRelease; goto handle_mouse; - case NSOtherMouseUp: ev_button=2; ev_type=ButtonRelease; goto handle_mouse; - case NSRightMouseUp: ev_button=3; ev_type=ButtonRelease; goto handle_mouse; - case NSLeftMouseDragged: ev_button=1; ev_type=MotionNotify; goto handle_mouse; - case NSOtherMouseDragged: ev_button=2; ev_type=MotionNotify; goto handle_mouse; - case NSRightMouseDragged: ev_button=3; ev_type=MotionNotify; goto handle_mouse; - case NSMouseMoved: ev_button=0; ev_type=MotionNotify; goto handle_mouse; - handle_mouse: - - /* I'm not sure the below code is necessary or useful (-bb) - if(ev_type==ButtonPress) { - if (!quartzProcs->IsX11Window([e window], [e windowNumber])) { - fprintf(stderr, "Dropping event because it's not a window\n"); - break; - } - button_state |= (1 << ev_button); - DarwinSendPointerEvents(ev_type, ev_button, pointer_x, pointer_y); - } else if (ev_type==ButtonRelease && (button_state & (1 << ev_button)) == 0) break; - */ - DarwinSendPointerEvents(ev_type, ev_button, pointer_x, pointer_y); - break; - case NSScrollWheel: - DarwinSendScrollEvents([e deltaY], pointer_x, pointer_y); - break; - - case NSKeyDown: // do we need to translate these keyCodes? - case NSKeyUp: - DarwinSendKeyboardEvents((type == NSKeyDown)?KeyPress:KeyRelease, [e keyCode]); - break; +#ifdef NX_DEVICELCMDKEYMASK + /* This is to workaround a bug in the VNC server where we sometimes see the L + * modifier and sometimes see no "side" + */ + modifierFlags = ensure_flag(modifierFlags, NX_CONTROLMASK, NX_DEVICELCTLKEYMASK | NX_DEVICERCTLKEYMASK, NX_DEVICELCTLKEYMASK); + modifierFlags = ensure_flag(modifierFlags, NX_SHIFTMASK, NX_DEVICELSHIFTKEYMASK | NX_DEVICERSHIFTKEYMASK, NX_DEVICELSHIFTKEYMASK); + modifierFlags = ensure_flag(modifierFlags, NX_COMMANDMASK, NX_DEVICELCMDKEYMASK | NX_DEVICERCMDKEYMASK, NX_DEVICELCMDKEYMASK); + modifierFlags = ensure_flag(modifierFlags, NX_ALTERNATEMASK, NX_DEVICELALTKEYMASK | NX_DEVICERALTKEYMASK, NX_DEVICELALTKEYMASK); +#endif + + modifierFlags &= modifierFlagsMask; - case NSFlagsChanged: - DarwinUpdateModKeys([e modifierFlags]); - break; - default: break; /* for gcc */ - } + /* We don't receive modifier key events while out of focus, and 3button + * emulation mucks this up, so we need to check our modifier flag state + * on every event... ugg + */ + + if(darwin_modifier_flags != modifierFlags) + DarwinUpdateModKeys(modifierFlags); + + switch ([e type]) { + case NSLeftMouseDown: ev_button=1; ev_type=ButtonPress; goto handle_mouse; + case NSOtherMouseDown: ev_button=2; ev_type=ButtonPress; goto handle_mouse; + case NSRightMouseDown: ev_button=3; ev_type=ButtonPress; goto handle_mouse; + case NSLeftMouseUp: ev_button=1; ev_type=ButtonRelease; goto handle_mouse; + case NSOtherMouseUp: ev_button=2; ev_type=ButtonRelease; goto handle_mouse; + case NSRightMouseUp: ev_button=3; ev_type=ButtonRelease; goto handle_mouse; + case NSLeftMouseDragged: ev_button=1; ev_type=MotionNotify; goto handle_mouse; + case NSOtherMouseDragged: ev_button=2; ev_type=MotionNotify; goto handle_mouse; + case NSRightMouseDragged: ev_button=3; ev_type=MotionNotify; goto handle_mouse; + case NSMouseMoved: ev_button=0; ev_type=MotionNotify; goto handle_mouse; + case NSTabletPoint: ev_button=0; ev_type=MotionNotify; goto handle_mouse; + + handle_mouse: + pDev = darwinPointer; + + /* NSTabletPoint can have no subtype */ + if([e type] != NSTabletPoint && + [e subtype] == NSTabletProximityEventSubtype) { + switch([e pointingDeviceType]) { + case NSEraserPointingDevice: + darwinTabletCurrent=darwinTabletEraser; + break; + case NSPenPointingDevice: + darwinTabletCurrent=darwinTabletStylus; + break; + case NSCursorPointingDevice: + case NSUnknownPointingDevice: + default: + darwinTabletCurrent=darwinTabletCursor; + break; + } + + /* NSTabletProximityEventSubtype doesn't encode pressure ant tilt + * So we just pretend the motion was caused by the mouse. Hopefully + * we'll have a better solution for this in the future (like maybe + * NSTabletProximityEventSubtype will come from NSTabletPoint + * rather than NSMouseMoved. + pressure = [e pressure]; + tilt_x = [e tilt].x; + tilt_y = [e tilt].y; + pDev = darwinTabletCurrent; + */ + + DarwinSendProximityEvents([e isEnteringProximity]?ProximityIn:ProximityOut, + pointer_x, pointer_y); + } + + if ([e type] == NSTabletPoint || [e subtype] == NSTabletPointEventSubtype) { + pressure = [e pressure]; + tilt_x = [e tilt].x; + tilt_y = [e tilt].y; + + pDev = darwinTabletCurrent; + } + +/* Older libXplugin (Tiger/"Stock" Leopard) aren't thread safe, so we can't call xp_find_window from the Appkit thread */ +#ifdef XPLUGIN_VERSION +#if XPLUGIN_VERSION > 0 + if(!quartzServerVisible) { + xp_window_id wid; + + /* Sigh. Need to check that we're really over one of + * our windows. (We need to receive pointer events while + * not in the foreground, but we don't want to receive them + * when another window is over us or we might show a tooltip) + */ + + wid = 0; + + if (xp_find_window(pointer_x, pointer_y, 0, &wid) == XP_Success && + wid == 0) + return; + } +#endif +#endif + + DarwinSendPointerEvents(pDev, ev_type, ev_button, pointer_x, pointer_y, + pressure, tilt_x, tilt_y); + + break; + + case NSTabletProximity: + switch([e pointingDeviceType]) { + case NSEraserPointingDevice: + darwinTabletCurrent=darwinTabletEraser; + break; + case NSPenPointingDevice: + darwinTabletCurrent=darwinTabletStylus; + break; + case NSCursorPointingDevice: + case NSUnknownPointingDevice: + default: + darwinTabletCurrent=darwinTabletCursor; + break; + } + + DarwinSendProximityEvents([e isEnteringProximity]?ProximityIn:ProximityOut, + pointer_x, pointer_y); + break; + + case NSScrollWheel: + DarwinSendScrollEvents([e deltaX], [e deltaY], pointer_x, pointer_y, + pressure, tilt_x, tilt_y); + break; + + case NSKeyDown: case NSKeyUp: + if(darwinSyncKeymap) { +#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1050 + TISInputSourceRef key_layout = TISCopyCurrentKeyboardLayoutInputSource(); + TISInputSourceRef clear; + if (CFEqual(key_layout, last_key_layout)) { + CFRelease(key_layout); + } else { + /* Swap/free thread-safely */ + clear = last_key_layout; + last_key_layout = key_layout; + CFRelease(clear); +#else + KeyboardLayoutRef key_layout; + KLGetCurrentKeyboardLayout(&key_layout); + if(key_layout != last_key_layout) { + last_key_layout = key_layout; +#endif + + /* Update keyInfo */ + pthread_mutex_lock(&keyInfo_mutex); + memset(keyInfo.keyMap, 0, sizeof(keyInfo.keyMap)); + if (!QuartzReadSystemKeymap(&keyInfo)) { + fprintf(stderr, "sendX11NSEvent: Could not build a valid keymap.\n"); + } + pthread_mutex_unlock(&keyInfo_mutex); + + /* Tell server thread to deal with new keyInfo */ + DarwinSendDDXEvent(kXquartzReloadKeymap, 0); + } + } + + /* Avoid stuck keys on context switch */ + if(keyState[[e keyCode]] == [e type]) + return; + keyState[[e keyCode]] = [e type]; + + DarwinSendKeyboardEvents(([e type] == NSKeyDown) ? KeyPress : KeyRelease, [e keyCode]); + break; + + default: break; /* for gcc */ + } } +@end |