X11Application.m revision 9ace9065
14642e01fSmrg/* X11Application.m -- subclass of NSApplication to multiplex events
24642e01fSmrg 
34642e01fSmrg Copyright (c) 2002-2008 Apple Inc.
44642e01fSmrg 
54642e01fSmrg Permission is hereby granted, free of charge, to any person
64642e01fSmrg obtaining a copy of this software and associated documentation files
74642e01fSmrg (the "Software"), to deal in the Software without restriction,
84642e01fSmrg including without limitation the rights to use, copy, modify, merge,
94642e01fSmrg publish, distribute, sublicense, and/or sell copies of the Software,
104642e01fSmrg and to permit persons to whom the Software is furnished to do so,
114642e01fSmrg subject to the following conditions:
124642e01fSmrg 
134642e01fSmrg The above copyright notice and this permission notice shall be
144642e01fSmrg included in all copies or substantial portions of the Software.
154642e01fSmrg 
164642e01fSmrg THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
174642e01fSmrg EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
184642e01fSmrg MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
194642e01fSmrg NONINFRINGEMENT.  IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT
204642e01fSmrg HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
214642e01fSmrg WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
224642e01fSmrg OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
234642e01fSmrg DEALINGS IN THE SOFTWARE.
244642e01fSmrg 
254642e01fSmrg Except as contained in this notice, the name(s) of the above
264642e01fSmrg copyright holders shall not be used in advertising or otherwise to
274642e01fSmrg promote the sale, use or other dealings in this Software without
284642e01fSmrg prior written authorization. */
294642e01fSmrg
304642e01fSmrg#include "sanitizedCarbon.h"
314642e01fSmrg
324642e01fSmrg#ifdef HAVE_DIX_CONFIG_H
334642e01fSmrg#include <dix-config.h>
344642e01fSmrg#endif
354642e01fSmrg
364642e01fSmrg#include "quartzCommon.h"
374642e01fSmrg
384642e01fSmrg#import "X11Application.h"
394642e01fSmrg
404642e01fSmrg#include "darwin.h"
416747b715Smrg#include "quartz.h"
424642e01fSmrg#include "darwinEvents.h"
434642e01fSmrg#include "quartzKeyboard.h"
444642e01fSmrg#include "quartz.h"
456747b715Smrg#include <X11/extensions/applewmconst.h>
464642e01fSmrg#include "micmap.h"
476747b715Smrg#include "exglobals.h"
484642e01fSmrg
494642e01fSmrg#include <mach/mach.h>
504642e01fSmrg#include <unistd.h>
514642e01fSmrg#include <AvailabilityMacros.h>
524642e01fSmrg
539ace9065Smrg#include <pthread.h>
549ace9065Smrg
554642e01fSmrg#include <Xplugin.h>
564642e01fSmrg
574642e01fSmrg// pbproxy/pbproxy.h
586747b715Smrgextern int xpbproxy_run (void);
594642e01fSmrg
604642e01fSmrg#define DEFAULTS_FILE X11LIBDIR"/X11/xserver/Xquartz.plist"
614642e01fSmrg
624642e01fSmrg#ifndef XSERVER_VERSION
634642e01fSmrg#define XSERVER_VERSION "?"
644642e01fSmrg#endif
654642e01fSmrg
664642e01fSmrg/* Stuck modifier / button state... force release when we context switch */
674642e01fSmrgstatic NSEventType keyState[NUM_KEYCODES];
684642e01fSmrg
694642e01fSmrgextern Bool noTestExtensions;
704642e01fSmrg
714642e01fSmrg#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1050
724642e01fSmrgstatic TISInputSourceRef last_key_layout;
734642e01fSmrg#else
744642e01fSmrgstatic KeyboardLayoutRef last_key_layout;
754642e01fSmrg#endif
764642e01fSmrg
774642e01fSmrgextern int darwinFakeButtons;
784642e01fSmrg
796747b715Smrg/* Store the mouse location while in the background, and update X11's pointer
806747b715Smrg * location when we become the foreground application
816747b715Smrg */
826747b715Smrgstatic NSPoint bgMouseLocation;
836747b715Smrgstatic BOOL bgMouseLocationUpdated = FALSE;
846747b715Smrg
854642e01fSmrgX11Application *X11App;
864642e01fSmrg
874642e01fSmrgCFStringRef app_prefs_domain_cfstr = NULL;
884642e01fSmrg
894642e01fSmrg#define ALL_KEY_MASKS (NSShiftKeyMask | NSControlKeyMask | NSAlternateKeyMask | NSCommandKeyMask)
904642e01fSmrg
914642e01fSmrg@interface X11Application (Private)
924642e01fSmrg- (void) sendX11NSEvent:(NSEvent *)e;
934642e01fSmrg@end
944642e01fSmrg
954642e01fSmrg@implementation X11Application
964642e01fSmrg
974642e01fSmrgtypedef struct message_struct message;
984642e01fSmrgstruct message_struct {
994642e01fSmrg    mach_msg_header_t hdr;
1004642e01fSmrg    SEL selector;
1014642e01fSmrg    NSObject *arg;
1024642e01fSmrg};
1034642e01fSmrg
1044642e01fSmrgstatic mach_port_t _port;
1054642e01fSmrg
1064642e01fSmrg/* Quartz mode initialization routine. This is often dynamically loaded
1074642e01fSmrg   but is statically linked into this X server. */
1084642e01fSmrgBool QuartzModeBundleInit(void);
1094642e01fSmrg
1104642e01fSmrgstatic void init_ports (void) {
1114642e01fSmrg    kern_return_t r;
1124642e01fSmrg    NSPort *p;
1134642e01fSmrg	
1144642e01fSmrg    if (_port != MACH_PORT_NULL) return;
1154642e01fSmrg	
1164642e01fSmrg    r = mach_port_allocate (mach_task_self (), MACH_PORT_RIGHT_RECEIVE, &_port);
1174642e01fSmrg    if (r != KERN_SUCCESS) return;
1184642e01fSmrg	
1194642e01fSmrg    p = [NSMachPort portWithMachPort:_port];
1204642e01fSmrg    [p setDelegate:NSApp];
1214642e01fSmrg    [p scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
1224642e01fSmrg}
1234642e01fSmrg
1244642e01fSmrgstatic void message_kit_thread (SEL selector, NSObject *arg) {
1254642e01fSmrg    message msg;
1264642e01fSmrg    kern_return_t r;
1274642e01fSmrg	
1284642e01fSmrg    msg.hdr.msgh_bits = MACH_MSGH_BITS (MACH_MSG_TYPE_MAKE_SEND, 0);
1294642e01fSmrg    msg.hdr.msgh_size = sizeof (msg);
1304642e01fSmrg    msg.hdr.msgh_remote_port = _port;
1314642e01fSmrg    msg.hdr.msgh_local_port = MACH_PORT_NULL;
1324642e01fSmrg    msg.hdr.msgh_reserved = 0;
1334642e01fSmrg    msg.hdr.msgh_id = 0;
1344642e01fSmrg	
1354642e01fSmrg    msg.selector = selector;
1364642e01fSmrg    msg.arg = [arg retain];
1374642e01fSmrg	
1384642e01fSmrg    r = mach_msg (&msg.hdr, MACH_SEND_MSG, msg.hdr.msgh_size,
1394642e01fSmrg		  0, MACH_PORT_NULL, 0, MACH_PORT_NULL);
1404642e01fSmrg    if (r != KERN_SUCCESS)
1414642e01fSmrg		ErrorF("%s: mach_msg failed: %x\n", __FUNCTION__, r);
1424642e01fSmrg}
1434642e01fSmrg
1444642e01fSmrg- (void) handleMachMessage:(void *)_msg {
1454642e01fSmrg    message *msg = _msg;
1464642e01fSmrg	
1474642e01fSmrg    [self performSelector:msg->selector withObject:msg->arg];
1484642e01fSmrg    [msg->arg release];
1494642e01fSmrg}
1504642e01fSmrg
1514642e01fSmrg- (void) set_controller:obj {
1524642e01fSmrg    if (_controller == nil) _controller = [obj retain];
1534642e01fSmrg}
1544642e01fSmrg
1554642e01fSmrg- (void) dealloc {
1564642e01fSmrg    if (_controller != nil) [_controller release];
1574642e01fSmrg	
1584642e01fSmrg    if (_port != MACH_PORT_NULL)
1594642e01fSmrg		mach_port_deallocate (mach_task_self (), _port);
1604642e01fSmrg	
1614642e01fSmrg    [super dealloc];
1624642e01fSmrg}
1634642e01fSmrg
1644642e01fSmrg- (void) orderFrontStandardAboutPanel: (id) sender {
1654642e01fSmrg    NSMutableDictionary *dict;
1664642e01fSmrg    NSDictionary *infoDict;
1674642e01fSmrg    NSString *tem;
1684642e01fSmrg    
1694642e01fSmrg    dict = [NSMutableDictionary dictionaryWithCapacity:3];
1704642e01fSmrg    infoDict = [[NSBundle mainBundle] infoDictionary];
1714642e01fSmrg    
1724642e01fSmrg    [dict setObject: NSLocalizedString (@"The X Window System", @"About panel")
1734642e01fSmrg          forKey:@"ApplicationName"];
1744642e01fSmrg    
1754642e01fSmrg    tem = [infoDict objectForKey:@"CFBundleShortVersionString"];
1764642e01fSmrg    
1774642e01fSmrg    [dict setObject:[NSString stringWithFormat:@"XQuartz %@", tem]
1784642e01fSmrg          forKey:@"ApplicationVersion"];
1794642e01fSmrg
1804642e01fSmrg    [dict setObject:[NSString stringWithFormat:@"xorg-server %s", XSERVER_VERSION]
1814642e01fSmrg          forKey:@"Version"];
1824642e01fSmrg    
1834642e01fSmrg    [self orderFrontStandardAboutPanelWithOptions: dict];
1844642e01fSmrg}
1854642e01fSmrg
1864642e01fSmrg- (void) activateX:(OSX_BOOL)state {
1874642e01fSmrg    size_t i;
1884642e01fSmrg    DEBUG_LOG("state=%d, _x_active=%d, \n", state, _x_active)
1894642e01fSmrg    if (state) {
1906747b715Smrg        if(bgMouseLocationUpdated) {
1916747b715Smrg            DarwinSendPointerEvents(darwinPointer, MotionNotify, 0, bgMouseLocation.x, bgMouseLocation.y, 0.0, 0.0, 0.0);
1926747b715Smrg            bgMouseLocationUpdated = FALSE;
1934642e01fSmrg        }
1946747b715Smrg        DarwinSendDDXEvent(kXquartzActivate, 0);
1954642e01fSmrg    } else {
1964642e01fSmrg
1976747b715Smrg        if(darwin_all_modifier_flags)
1984642e01fSmrg            DarwinUpdateModKeys(0);
1994642e01fSmrg        for(i=0; i < NUM_KEYCODES; i++) {
2004642e01fSmrg            if(keyState[i] == NSKeyDown) {
2014642e01fSmrg                DarwinSendKeyboardEvents(KeyRelease, i);
2024642e01fSmrg                keyState[i] = NSKeyUp;
2034642e01fSmrg            }
2044642e01fSmrg        }
2054642e01fSmrg        
2064642e01fSmrg        DarwinSendDDXEvent(kXquartzDeactivate, 0);
2074642e01fSmrg    }
2084642e01fSmrg
2094642e01fSmrg    _x_active = state;
2104642e01fSmrg}
2114642e01fSmrg
2124642e01fSmrg- (void) became_key:(NSWindow *)win {
2134642e01fSmrg	[self activateX:NO];
2144642e01fSmrg}
2154642e01fSmrg
2164642e01fSmrg- (void) sendEvent:(NSEvent *)e {
2174642e01fSmrg    OSX_BOOL for_appkit, for_x;
2184642e01fSmrg    
2194642e01fSmrg    /* By default pass down the responder chain and to X. */
2204642e01fSmrg    for_appkit = YES;
2214642e01fSmrg    for_x = YES;
2224642e01fSmrg    
2234642e01fSmrg    switch ([e type]) {
2244642e01fSmrg        case NSLeftMouseDown: case NSRightMouseDown: case NSOtherMouseDown:
2254642e01fSmrg        case NSLeftMouseUp: case NSRightMouseUp: case NSOtherMouseUp:
2264642e01fSmrg            if ([e window] != nil) {
2274642e01fSmrg                /* Pointer event has an (AppKit) window. Probably something for the kit. */
2284642e01fSmrg                for_x = NO;
2294642e01fSmrg                if (_x_active) [self activateX:NO];
2304642e01fSmrg            } else if ([self modalWindow] == nil) {
2314642e01fSmrg                /* Must be an X window. Tell appkit it doesn't have focus. */
2324642e01fSmrg                for_appkit = NO;
2334642e01fSmrg                
2344642e01fSmrg                if ([self isActive]) {
2354642e01fSmrg                    [self deactivate];
2364642e01fSmrg                    if (!_x_active && quartzProcs->IsX11Window([e window],
2374642e01fSmrg                                                               [e windowNumber]))
2384642e01fSmrg                        [self activateX:YES];
2394642e01fSmrg                }
2404642e01fSmrg            }
2414642e01fSmrg
2424642e01fSmrg            /* We want to force sending to appkit if we're over the menu bar */
2434642e01fSmrg            if(!for_appkit) {
2444642e01fSmrg                NSPoint NSlocation = [e locationInWindow];
2454642e01fSmrg                NSWindow *window = [e window];
2466747b715Smrg                NSRect NSframe, NSvisibleFrame;
2476747b715Smrg                CGRect CGframe, CGvisibleFrame;
2486747b715Smrg                CGPoint CGlocation;
2496747b715Smrg
2504642e01fSmrg                if (window != nil)	{
2514642e01fSmrg                    NSRect frame = [window frame];
2524642e01fSmrg                    NSlocation.x += frame.origin.x;
2534642e01fSmrg                    NSlocation.y += frame.origin.y;
2544642e01fSmrg                }
2554642e01fSmrg
2566747b715Smrg                NSframe = [[NSScreen mainScreen] frame];
2576747b715Smrg                NSvisibleFrame = [[NSScreen mainScreen] visibleFrame];
2584642e01fSmrg                
2596747b715Smrg                CGframe = CGRectMake(NSframe.origin.x, NSframe.origin.y,
2604642e01fSmrg                                            NSframe.size.width, NSframe.size.height);
2616747b715Smrg                CGvisibleFrame = CGRectMake(NSvisibleFrame.origin.x,
2624642e01fSmrg                                                   NSvisibleFrame.origin.y,
2634642e01fSmrg                                                   NSvisibleFrame.size.width,
2644642e01fSmrg                                                   NSvisibleFrame.size.height);
2656747b715Smrg                CGlocation = CGPointMake(NSlocation.x, NSlocation.y);
2664642e01fSmrg                
2674642e01fSmrg                if(CGRectContainsPoint(CGframe, CGlocation) &&
2684642e01fSmrg                   !CGRectContainsPoint(CGvisibleFrame, CGlocation))
2694642e01fSmrg                    for_appkit = YES;
2704642e01fSmrg            }
2714642e01fSmrg            
2724642e01fSmrg            break;
2734642e01fSmrg            
2744642e01fSmrg        case NSKeyDown: case NSKeyUp:
2754642e01fSmrg            
2764642e01fSmrg            if(_x_active) {
2774642e01fSmrg                static BOOL do_swallow = NO;
2784642e01fSmrg                static int swallow_keycode;
2794642e01fSmrg                
2804642e01fSmrg                if([e type] == NSKeyDown) {
2814642e01fSmrg                    /* Before that though, see if there are any global
2824642e01fSmrg                     * shortcuts bound to it. */
2834642e01fSmrg
2844642e01fSmrg                    if(darwinAppKitModMask & [e modifierFlags]) {
2854642e01fSmrg                        /* Override to force sending to Appkit */
2864642e01fSmrg                        swallow_keycode = [e keyCode];
2874642e01fSmrg                        do_swallow = YES;
2884642e01fSmrg                        for_x = NO;
2894642e01fSmrg#if XPLUGIN_VERSION >= 1
2906747b715Smrg                    } else if(XQuartzEnableKeyEquivalents &&
2914642e01fSmrg                             xp_is_symbolic_hotkey_event([e eventRef])) {
2924642e01fSmrg                        swallow_keycode = [e keyCode];
2934642e01fSmrg                        do_swallow = YES;
2944642e01fSmrg                        for_x = NO;
2954642e01fSmrg#endif
2966747b715Smrg                    } else if(XQuartzEnableKeyEquivalents &&
2974642e01fSmrg                              [[self mainMenu] performKeyEquivalent:e]) {
2984642e01fSmrg                        swallow_keycode = [e keyCode];
2994642e01fSmrg                        do_swallow = YES;
3004642e01fSmrg                        for_appkit = NO;
3014642e01fSmrg                        for_x = NO;
3026747b715Smrg                    } else if(!XQuartzIsRootless
3034642e01fSmrg                              && ([e modifierFlags] & ALL_KEY_MASKS) == (NSCommandKeyMask | NSAlternateKeyMask)
3044642e01fSmrg                              && ([e keyCode] == 0 /*a*/ || [e keyCode] == 53 /*Esc*/)) {
3054642e01fSmrg                        /* We have this here to force processing fullscreen 
3066747b715Smrg                         * toggle even if XQuartzEnableKeyEquivalents is disabled */
3074642e01fSmrg                        swallow_keycode = [e keyCode];
3084642e01fSmrg                        do_swallow = YES;
3094642e01fSmrg                        for_x = NO;
3104642e01fSmrg                        for_appkit = NO;
3114642e01fSmrg                        DarwinSendDDXEvent(kXquartzToggleFullscreen, 0);
3124642e01fSmrg                    } else {
3134642e01fSmrg                        /* No kit window is focused, so send it to X. */
3144642e01fSmrg                        for_appkit = NO;
3154642e01fSmrg                    }
3164642e01fSmrg                } else { /* KeyUp */
3174642e01fSmrg                    /* If we saw a key equivalent on the down, don't pass
3184642e01fSmrg                     * the up through to X. */
3194642e01fSmrg                    if (do_swallow && [e keyCode] == swallow_keycode) {
3204642e01fSmrg                        do_swallow = NO;
3214642e01fSmrg                        for_x = NO;
3224642e01fSmrg                    }
3234642e01fSmrg                }
3244642e01fSmrg            } else { /* !_x_active */
3254642e01fSmrg                for_x = NO;
3264642e01fSmrg            }
3274642e01fSmrg            break;
3284642e01fSmrg            
3294642e01fSmrg        case NSFlagsChanged:
3304642e01fSmrg            /* Don't tell X11 about modifiers changing while it's not active */
3314642e01fSmrg            if (!_x_active)
3324642e01fSmrg                for_x = NO;
3334642e01fSmrg            break;
3344642e01fSmrg            
3354642e01fSmrg        case NSAppKitDefined:
3364642e01fSmrg            switch ([e subtype]) {
3379ace9065Smrg                static BOOL x_was_active = NO;
3389ace9065Smrg
3394642e01fSmrg                case NSApplicationActivatedEventType:
3404642e01fSmrg                    for_x = NO;
3419ace9065Smrg                    if ([e window] == nil && x_was_active) {
3426747b715Smrg                        BOOL order_all_windows = YES, workspaces, ok;
3434642e01fSmrg                        for_appkit = NO;
3449ace9065Smrg
3459ace9065Smrg                        /* FIXME: This is a hack to avoid passing the event to AppKit which
3469ace9065Smrg                         *        would result in it raising one of its windows.
3479ace9065Smrg                         */
3484642e01fSmrg                        _appFlags._active = YES;
3499ace9065Smrg
3509ace9065Smrg                        X11ApplicationSetFrontProcess();
3519ace9065Smrg
3524642e01fSmrg                        /* Get the Spaces preference for SwitchOnActivate */
3536747b715Smrg                        (void)CFPreferencesAppSynchronize(CFSTR("com.apple.dock"));
3546747b715Smrg                        workspaces = CFPreferencesGetAppBooleanValue(CFSTR("workspaces"), CFSTR("com.apple.dock"), &ok);
3556747b715Smrg                        if (!ok)
3566747b715Smrg                            workspaces = NO;
3576747b715Smrg
3586747b715Smrg                        if (workspaces) {
3596747b715Smrg                            (void)CFPreferencesAppSynchronize(CFSTR(".GlobalPreferences"));
3606747b715Smrg                            order_all_windows = CFPreferencesGetAppBooleanValue(CFSTR("AppleSpacesSwitchOnActivate"), CFSTR(".GlobalPreferences"), &ok);
3616747b715Smrg                            if (!ok)
3626747b715Smrg                                order_all_windows = YES;
3636747b715Smrg                        }
3644642e01fSmrg                        
3656747b715Smrg                        /* TODO: In the workspaces && !AppleSpacesSwitchOnActivate case, the windows are ordered
3666747b715Smrg                         *       correctly, but we need to activate the top window on this space if there is
3676747b715Smrg                         *       none active.
3686747b715Smrg                         *
3696747b715Smrg                         *       If there are no active windows, and there are minimized windows, we should
3706747b715Smrg                         *       be restoring one of them.
3716747b715Smrg                         */
3729ace9065Smrg                        if ([e data2] & 0x10) { // 0x10 (bfCPSOrderAllWindowsForward) is set when we use cmd-tab or the dock icon
3736747b715Smrg                            DarwinSendDDXEvent(kXquartzBringAllToFront, 1, order_all_windows);
3749ace9065Smrg                        }
3754642e01fSmrg                    }
3764642e01fSmrg                    break;
3774642e01fSmrg                    
3784642e01fSmrg                case 18: /* ApplicationDidReactivate */
3796747b715Smrg                    if (XQuartzFullscreenVisible) for_appkit = NO;
3804642e01fSmrg                    break;
3814642e01fSmrg                    
3824642e01fSmrg                case NSApplicationDeactivatedEventType:
3834642e01fSmrg                    for_x = NO;
3849ace9065Smrg
3859ace9065Smrg                    x_was_active = _x_active;
3869ace9065Smrg                    if(_x_active)
3879ace9065Smrg                        [self activateX:NO];
3884642e01fSmrg                    break;
3894642e01fSmrg            }
3904642e01fSmrg            break;
3914642e01fSmrg            
3924642e01fSmrg        default: break; /* for gcc */
3934642e01fSmrg    }
3944642e01fSmrg    
3954642e01fSmrg    if (for_appkit) [super sendEvent:e];
3964642e01fSmrg    
3974642e01fSmrg    if (for_x) [self sendX11NSEvent:e];
3984642e01fSmrg}
3994642e01fSmrg
4004642e01fSmrg- (void) set_window_menu:(NSArray *)list {
4014642e01fSmrg	[_controller set_window_menu:list];
4024642e01fSmrg}
4034642e01fSmrg
4044642e01fSmrg- (void) set_window_menu_check:(NSNumber *)n {
4054642e01fSmrg	[_controller set_window_menu_check:n];
4064642e01fSmrg}
4074642e01fSmrg
4084642e01fSmrg- (void) set_apps_menu:(NSArray *)list {
4094642e01fSmrg	[_controller set_apps_menu:list];
4104642e01fSmrg}
4114642e01fSmrg
4124642e01fSmrg- (void) set_front_process:unused {
4134642e01fSmrg	[NSApp activateIgnoringOtherApps:YES];
4144642e01fSmrg
4154642e01fSmrg	if ([self modalWindow] == nil)
4164642e01fSmrg		[self activateX:YES];
4174642e01fSmrg}
4184642e01fSmrg
4194642e01fSmrg- (void) set_can_quit:(NSNumber *)state {
4204642e01fSmrg	[_controller set_can_quit:[state boolValue]];
4214642e01fSmrg}
4224642e01fSmrg
4234642e01fSmrg- (void) server_ready:unused {
4244642e01fSmrg	[_controller server_ready];
4254642e01fSmrg}
4264642e01fSmrg
4274642e01fSmrg- (void) show_hide_menubar:(NSNumber *)state {
4284642e01fSmrg    /* Also shows/hides the dock */
4294642e01fSmrg    if ([state boolValue])
4304642e01fSmrg        SetSystemUIMode(kUIModeNormal, 0); 
4314642e01fSmrg    else
4326747b715Smrg        SetSystemUIMode(kUIModeAllHidden, XQuartzFullscreenMenu ? kUIOptionAutoShowMenuBar : 0); // kUIModeAllSuppressed or kUIOptionAutoShowMenuBar can be used to allow "mouse-activation"
4334642e01fSmrg}
4344642e01fSmrg
4356747b715Smrg- (void) launch_client:(NSString *)cmd {
4366747b715Smrg    (void)[_controller application:self openFile:cmd];
4376747b715Smrg}
4384642e01fSmrg
4394642e01fSmrg/* user preferences */
4404642e01fSmrg
4414642e01fSmrg/* Note that these functions only work for arrays whose elements
4424642e01fSmrg can be toll-free-bridged between NS and CF worlds. */
4434642e01fSmrg
4444642e01fSmrgstatic const void *cfretain (CFAllocatorRef a, const void *b) {
4454642e01fSmrg    return CFRetain (b);
4464642e01fSmrg}
4474642e01fSmrg
4484642e01fSmrgstatic void cfrelease (CFAllocatorRef a, const void *b) {
4494642e01fSmrg    CFRelease (b);
4504642e01fSmrg}
4514642e01fSmrg
4524642e01fSmrgstatic CFMutableArrayRef nsarray_to_cfarray (NSArray *in) {
4534642e01fSmrg	CFMutableArrayRef out;
4544642e01fSmrg	CFArrayCallBacks cb;
4554642e01fSmrg	NSObject *ns;
4564642e01fSmrg	const CFTypeRef *cf;
4574642e01fSmrg	int i, count;
4584642e01fSmrg
4594642e01fSmrg	memset (&cb, 0, sizeof (cb));
4604642e01fSmrg	cb.version = 0;
4614642e01fSmrg	cb.retain = cfretain;
4624642e01fSmrg	cb.release = cfrelease;
4634642e01fSmrg
4644642e01fSmrg	count = [in count];
4654642e01fSmrg	out = CFArrayCreateMutable (NULL, count, &cb);
4664642e01fSmrg
4674642e01fSmrg	for (i = 0; i < count; i++) {
4684642e01fSmrg		ns = [in objectAtIndex:i];
4694642e01fSmrg
4704642e01fSmrg		if ([ns isKindOfClass:[NSArray class]])
4714642e01fSmrg			cf = (CFTypeRef) nsarray_to_cfarray ((NSArray *) ns);
4724642e01fSmrg		else
4734642e01fSmrg			cf = CFRetain ((CFTypeRef) ns);
4744642e01fSmrg
4754642e01fSmrg		CFArrayAppendValue (out, cf);
4764642e01fSmrg		CFRelease (cf);
4774642e01fSmrg	}
4784642e01fSmrg
4794642e01fSmrg	return out;
4804642e01fSmrg}
4814642e01fSmrg
4824642e01fSmrgstatic NSMutableArray * cfarray_to_nsarray (CFArrayRef in) {
4834642e01fSmrg	NSMutableArray *out;
4844642e01fSmrg	const CFTypeRef *cf;
4854642e01fSmrg	NSObject *ns;
4864642e01fSmrg	int i, count;
4874642e01fSmrg
4884642e01fSmrg	count = CFArrayGetCount (in);
4894642e01fSmrg	out = [[NSMutableArray alloc] initWithCapacity:count];
4904642e01fSmrg
4914642e01fSmrg	for (i = 0; i < count; i++) {
4924642e01fSmrg		cf = CFArrayGetValueAtIndex (in, i);
4934642e01fSmrg
4944642e01fSmrg		if (CFGetTypeID (cf) == CFArrayGetTypeID ())
4954642e01fSmrg			ns = cfarray_to_nsarray ((CFArrayRef) cf);
4964642e01fSmrg		else
4974642e01fSmrg			ns = [(id)cf retain];
4984642e01fSmrg
4994642e01fSmrg		[out addObject:ns];
5004642e01fSmrg		[ns release];
5014642e01fSmrg	}
5024642e01fSmrg
5034642e01fSmrg	return out;
5044642e01fSmrg}
5054642e01fSmrg
5066747b715Smrg- (CFPropertyListRef) prefs_get_copy:(NSString *)key {
5074642e01fSmrg    CFPropertyListRef value;
5084642e01fSmrg	
5094642e01fSmrg    value = CFPreferencesCopyAppValue ((CFStringRef) key, app_prefs_domain_cfstr);
5104642e01fSmrg	
5114642e01fSmrg    if (value == NULL) {
5124642e01fSmrg      static CFDictionaryRef defaults;
5134642e01fSmrg      
5144642e01fSmrg      if (defaults == NULL) {
5154642e01fSmrg	CFStringRef error = NULL;
5164642e01fSmrg	CFDataRef data;
5174642e01fSmrg	CFURLRef url;
5184642e01fSmrg	SInt32 error_code;
5194642e01fSmrg	
5204642e01fSmrg	url = (CFURLCreateFromFileSystemRepresentation
5214642e01fSmrg	       (NULL, (unsigned char *)DEFAULTS_FILE, strlen (DEFAULTS_FILE), false));
5224642e01fSmrg	if (CFURLCreateDataAndPropertiesFromResource (NULL, url, &data,
5234642e01fSmrg						      NULL, NULL, &error_code)) {
5244642e01fSmrg	  defaults = (CFPropertyListCreateFromXMLData
5254642e01fSmrg		      (NULL, data, kCFPropertyListMutableContainersAndLeaves, &error));
5264642e01fSmrg	  if (error != NULL) CFRelease (error);
5274642e01fSmrg	  CFRelease (data);
5284642e01fSmrg	}
5294642e01fSmrg	CFRelease (url);
5304642e01fSmrg			
5314642e01fSmrg	if (defaults != NULL) {
5324642e01fSmrg	  NSMutableArray *apps, *elt;
5334642e01fSmrg	  int count, i;
5344642e01fSmrg	  NSString *name, *nname;
5354642e01fSmrg	  
5364642e01fSmrg	  /* Localize the names in the default apps menu. */
5374642e01fSmrg	  
5384642e01fSmrg	  apps = [(NSDictionary *)defaults objectForKey:@PREFS_APPSMENU];
5394642e01fSmrg	  if (apps != nil) {
5404642e01fSmrg	    count = [apps count];
5414642e01fSmrg	    for (i = 0; i < count; i++)	{
5424642e01fSmrg	      elt = [apps objectAtIndex:i];
5434642e01fSmrg	      if (elt != nil && [elt isKindOfClass:[NSArray class]]) {
5444642e01fSmrg		name = [elt objectAtIndex:0];
5454642e01fSmrg		if (name != nil) {
5464642e01fSmrg		  nname = NSLocalizedString (name, nil);
5474642e01fSmrg		  if (nname != nil && nname != name)
5484642e01fSmrg		    [elt replaceObjectAtIndex:0 withObject:nname];
5494642e01fSmrg		}
5504642e01fSmrg	      }
5514642e01fSmrg	    }
5524642e01fSmrg	  }
5534642e01fSmrg	}
5544642e01fSmrg      }
5554642e01fSmrg		
5564642e01fSmrg      if (defaults != NULL) value = CFDictionaryGetValue (defaults, key);
5574642e01fSmrg      if (value != NULL) CFRetain (value);
5584642e01fSmrg    }
5594642e01fSmrg	
5604642e01fSmrg    return value;
5614642e01fSmrg}
5624642e01fSmrg
5634642e01fSmrg- (int) prefs_get_integer:(NSString *)key default:(int)def {
5644642e01fSmrg  CFPropertyListRef value;
5654642e01fSmrg  int ret;
5664642e01fSmrg  
5676747b715Smrg  value = [self prefs_get_copy:key];
5684642e01fSmrg  
5694642e01fSmrg  if (value != NULL && CFGetTypeID (value) == CFNumberGetTypeID ())
5704642e01fSmrg    CFNumberGetValue (value, kCFNumberIntType, &ret);
5714642e01fSmrg  else if (value != NULL && CFGetTypeID (value) == CFStringGetTypeID ())
5724642e01fSmrg    ret = CFStringGetIntValue (value);
5734642e01fSmrg  else
5744642e01fSmrg    ret = def;
5754642e01fSmrg  
5764642e01fSmrg  if (value != NULL) CFRelease (value);
5774642e01fSmrg  
5784642e01fSmrg  return ret;
5794642e01fSmrg}
5804642e01fSmrg
5814642e01fSmrg- (const char *) prefs_get_string:(NSString *)key default:(const char *)def {
5824642e01fSmrg  CFPropertyListRef value;
5834642e01fSmrg  const char *ret = NULL;
5844642e01fSmrg  
5856747b715Smrg  value = [self prefs_get_copy:key];
5864642e01fSmrg  
5874642e01fSmrg  if (value != NULL && CFGetTypeID (value) == CFStringGetTypeID ()) {
5884642e01fSmrg    NSString *s = (NSString *) value;
5894642e01fSmrg    
5904642e01fSmrg    ret = [s UTF8String];
5914642e01fSmrg  }
5924642e01fSmrg  
5934642e01fSmrg  if (value != NULL) CFRelease (value);
5944642e01fSmrg  
5954642e01fSmrg  return ret != NULL ? ret : def;
5964642e01fSmrg}
5974642e01fSmrg
5986747b715Smrg- (NSURL *) prefs_copy_url:(NSString *)key default:(NSURL *)def {
5996747b715Smrg    CFPropertyListRef value;
6006747b715Smrg    NSURL *ret = NULL;
6016747b715Smrg    
6026747b715Smrg    value = [self prefs_get_copy:key];
6036747b715Smrg    
6046747b715Smrg    if (value != NULL && CFGetTypeID (value) == CFStringGetTypeID ()) {
6056747b715Smrg        NSString *s = (NSString *) value;
6066747b715Smrg
6076747b715Smrg        ret = [NSURL URLWithString:s];
6086747b715Smrg        [ret retain];
6096747b715Smrg    }
6106747b715Smrg    
6116747b715Smrg    if (value != NULL) CFRelease (value);
6126747b715Smrg    
6136747b715Smrg    return ret != NULL ? ret : def;
6146747b715Smrg}
6156747b715Smrg
6164642e01fSmrg- (float) prefs_get_float:(NSString *)key default:(float)def {
6174642e01fSmrg  CFPropertyListRef value;
6184642e01fSmrg  float ret = def;
6194642e01fSmrg  
6206747b715Smrg  value = [self prefs_get_copy:key];
6214642e01fSmrg  
6224642e01fSmrg  if (value != NULL
6234642e01fSmrg      && CFGetTypeID (value) == CFNumberGetTypeID ()
6244642e01fSmrg      && CFNumberIsFloatType (value))
6254642e01fSmrg    CFNumberGetValue (value, kCFNumberFloatType, &ret);
6264642e01fSmrg  else if (value != NULL && CFGetTypeID (value) == CFStringGetTypeID ())
6274642e01fSmrg    ret = CFStringGetDoubleValue (value);
6284642e01fSmrg	
6294642e01fSmrg  if (value != NULL) CFRelease (value);
6304642e01fSmrg  
6314642e01fSmrg  return ret;
6324642e01fSmrg}
6334642e01fSmrg
6344642e01fSmrg- (int) prefs_get_boolean:(NSString *)key default:(int)def {
6354642e01fSmrg  CFPropertyListRef value;
6364642e01fSmrg  int ret = def;
6374642e01fSmrg  
6386747b715Smrg  value = [self prefs_get_copy:key];
6394642e01fSmrg  
6404642e01fSmrg  if (value != NULL) {
6414642e01fSmrg    if (CFGetTypeID (value) == CFNumberGetTypeID ())
6424642e01fSmrg      CFNumberGetValue (value, kCFNumberIntType, &ret);
6434642e01fSmrg    else if (CFGetTypeID (value) == CFBooleanGetTypeID ())
6444642e01fSmrg      ret = CFBooleanGetValue (value);
6454642e01fSmrg    else if (CFGetTypeID (value) == CFStringGetTypeID ()) {
6464642e01fSmrg      const char *tem = [(NSString *) value UTF8String];
6474642e01fSmrg      if (strcasecmp (tem, "true") == 0 || strcasecmp (tem, "yes") == 0)
6484642e01fSmrg	ret = YES;
6494642e01fSmrg      else
6504642e01fSmrg	ret = NO;
6514642e01fSmrg    }
6524642e01fSmrg    
6534642e01fSmrg    CFRelease (value);
6544642e01fSmrg  }
6554642e01fSmrg  return ret;
6564642e01fSmrg}
6574642e01fSmrg
6584642e01fSmrg- (NSArray *) prefs_get_array:(NSString *)key {
6594642e01fSmrg  NSArray *ret = nil;
6604642e01fSmrg  CFPropertyListRef value;
6614642e01fSmrg  
6626747b715Smrg  value = [self prefs_get_copy:key];
6634642e01fSmrg  
6644642e01fSmrg  if (value != NULL) {
6654642e01fSmrg    if (CFGetTypeID (value) == CFArrayGetTypeID ())
6664642e01fSmrg      ret = [cfarray_to_nsarray (value) autorelease];
6674642e01fSmrg    
6684642e01fSmrg    CFRelease (value);
6694642e01fSmrg  }
6704642e01fSmrg  
6714642e01fSmrg  return ret;
6724642e01fSmrg}
6734642e01fSmrg
6744642e01fSmrg- (void) prefs_set_integer:(NSString *)key value:(int)value {
6754642e01fSmrg    CFNumberRef x;
6764642e01fSmrg	
6774642e01fSmrg    x = CFNumberCreate (NULL, kCFNumberIntType, &value);
6784642e01fSmrg	
6794642e01fSmrg    CFPreferencesSetValue ((CFStringRef) key, (CFTypeRef) x, app_prefs_domain_cfstr,
6804642e01fSmrg			   kCFPreferencesCurrentUser, kCFPreferencesAnyHost);
6814642e01fSmrg	
6824642e01fSmrg    CFRelease (x);
6834642e01fSmrg}
6844642e01fSmrg
6854642e01fSmrg- (void) prefs_set_float:(NSString *)key value:(float)value {
6864642e01fSmrg    CFNumberRef x;
6874642e01fSmrg	
6884642e01fSmrg    x = CFNumberCreate (NULL, kCFNumberFloatType, &value);
6894642e01fSmrg	
6904642e01fSmrg    CFPreferencesSetValue ((CFStringRef) key, (CFTypeRef) x, app_prefs_domain_cfstr,
6914642e01fSmrg			   kCFPreferencesCurrentUser, kCFPreferencesAnyHost);
6924642e01fSmrg	
6934642e01fSmrg    CFRelease (x);
6944642e01fSmrg}
6954642e01fSmrg
6964642e01fSmrg- (void) prefs_set_boolean:(NSString *)key value:(int)value {
6974642e01fSmrg  CFPreferencesSetValue ((CFStringRef) key,
6984642e01fSmrg			 (CFTypeRef) (value ? kCFBooleanTrue
6994642e01fSmrg			 : kCFBooleanFalse), app_prefs_domain_cfstr,
7004642e01fSmrg			 kCFPreferencesCurrentUser, kCFPreferencesAnyHost);
7014642e01fSmrg  
7024642e01fSmrg}
7034642e01fSmrg
7044642e01fSmrg- (void) prefs_set_array:(NSString *)key value:(NSArray *)value {
7054642e01fSmrg  CFArrayRef cfarray;
7064642e01fSmrg  
7074642e01fSmrg  cfarray = nsarray_to_cfarray (value);
7084642e01fSmrg  CFPreferencesSetValue ((CFStringRef) key,
7094642e01fSmrg			 (CFTypeRef) cfarray,
7104642e01fSmrg			 app_prefs_domain_cfstr,
7114642e01fSmrg			 kCFPreferencesCurrentUser, kCFPreferencesAnyHost);
7124642e01fSmrg  CFRelease (cfarray);
7134642e01fSmrg}
7144642e01fSmrg
7154642e01fSmrg- (void) prefs_set_string:(NSString *)key value:(NSString *)value {
7164642e01fSmrg  CFPreferencesSetValue ((CFStringRef) key, (CFTypeRef) value,
7174642e01fSmrg			 app_prefs_domain_cfstr, kCFPreferencesCurrentUser,
7184642e01fSmrg			 kCFPreferencesAnyHost);
7194642e01fSmrg}
7204642e01fSmrg
7214642e01fSmrg- (void) prefs_synchronize {
7224642e01fSmrg    CFPreferencesAppSynchronize (kCFPreferencesCurrentApplication);
7234642e01fSmrg}
7244642e01fSmrg
7254642e01fSmrg- (void) read_defaults
7264642e01fSmrg{
7274642e01fSmrg    NSString *nsstr;
7284642e01fSmrg    const char *tem;
7294642e01fSmrg	
7306747b715Smrg    XQuartzRootlessDefault = [self prefs_get_boolean:@PREFS_ROOTLESS
7316747b715Smrg                                           default:XQuartzRootlessDefault];
7326747b715Smrg    XQuartzFullscreenMenu = [self prefs_get_boolean:@PREFS_FULLSCREEN_MENU
7336747b715Smrg                                           default:XQuartzFullscreenMenu];
7346747b715Smrg    XQuartzFullscreenDisableHotkeys = ![self prefs_get_boolean:@PREFS_FULLSCREEN_HOTKEYS
7356747b715Smrg                                                      default:!XQuartzFullscreenDisableHotkeys];
7364642e01fSmrg    darwinFakeButtons = [self prefs_get_boolean:@PREFS_FAKEBUTTONS
7374642e01fSmrg                                        default:darwinFakeButtons];
7386747b715Smrg    XQuartzOptionSendsAlt = [self prefs_get_boolean:@PREFS_OPTION_SENDS_ALT
7396747b715Smrg                                           default:XQuartzOptionSendsAlt];
7406747b715Smrg
7414642e01fSmrg    if (darwinFakeButtons) {
7424642e01fSmrg        const char *fake2, *fake3;
7434642e01fSmrg
7444642e01fSmrg        fake2 = [self prefs_get_string:@PREFS_FAKE_BUTTON2 default:NULL];
7454642e01fSmrg        fake3 = [self prefs_get_string:@PREFS_FAKE_BUTTON3 default:NULL];
7464642e01fSmrg
7474642e01fSmrg        if (fake2 != NULL) darwinFakeMouse2Mask = DarwinParseModifierList(fake2, TRUE);
7484642e01fSmrg        if (fake3 != NULL) darwinFakeMouse3Mask = DarwinParseModifierList(fake3, TRUE);
7494642e01fSmrg    }
7504642e01fSmrg
7514642e01fSmrg    tem = [self prefs_get_string:@PREFS_APPKIT_MODIFIERS default:NULL];
7524642e01fSmrg    if (tem != NULL) darwinAppKitModMask = DarwinParseModifierList(tem, TRUE);
7534642e01fSmrg	
7544642e01fSmrg    tem = [self prefs_get_string:@PREFS_WINDOW_ITEM_MODIFIERS default:NULL];
7554642e01fSmrg    if (tem != NULL) {
7564642e01fSmrg        windowItemModMask = DarwinParseModifierList(tem, FALSE);
7574642e01fSmrg    } else {
7584642e01fSmrg        nsstr = NSLocalizedString (@"window item modifiers", @"window item modifiers");
7594642e01fSmrg        if(nsstr != NULL) {
7604642e01fSmrg            tem = [nsstr UTF8String];
7614642e01fSmrg            if((tem != NULL) && strcmp(tem, "window item modifiers")) {
7624642e01fSmrg                windowItemModMask = DarwinParseModifierList(tem, FALSE);
7634642e01fSmrg            }
7644642e01fSmrg        }
7654642e01fSmrg    }
7664642e01fSmrg
7676747b715Smrg    XQuartzEnableKeyEquivalents = [self prefs_get_boolean:@PREFS_KEYEQUIVS
7686747b715Smrg                                              default:XQuartzEnableKeyEquivalents];
7694642e01fSmrg	
7704642e01fSmrg    darwinSyncKeymap = [self prefs_get_boolean:@PREFS_SYNC_KEYMAP
7714642e01fSmrg                                       default:darwinSyncKeymap];
7724642e01fSmrg		
7734642e01fSmrg    darwinDesiredDepth = [self prefs_get_integer:@PREFS_DEPTH
7744642e01fSmrg                                         default:darwinDesiredDepth];
7754642e01fSmrg    
7764642e01fSmrg    noTestExtensions = ![self prefs_get_boolean:@PREFS_TEST_EXTENSIONS
7774642e01fSmrg                                        default:FALSE];
7786747b715Smrg
7796747b715Smrg#if XQUARTZ_SPARKLE
7806747b715Smrg    NSURL *url =  [self prefs_copy_url:@PREFS_UPDATE_FEED default:nil];
7816747b715Smrg    if(url) {
7826747b715Smrg        [[SUUpdater sharedUpdater] setFeedURL:url];
7836747b715Smrg        [url release];
7846747b715Smrg    }
7856747b715Smrg#endif
7864642e01fSmrg}
7874642e01fSmrg
7884642e01fSmrg/* This will end up at the end of the responder chain. */
7894642e01fSmrg- (void) copy:sender {
7904642e01fSmrg  DarwinSendDDXEvent(kXquartzPasteboardNotify, 1,
7914642e01fSmrg			     AppleWMCopyToPasteboard);
7924642e01fSmrg}
7934642e01fSmrg
7946747b715Smrg- (X11Controller *) controller {
7956747b715Smrg    return _controller;
7966747b715Smrg}
7976747b715Smrg
7984642e01fSmrg- (OSX_BOOL) x_active {
7994642e01fSmrg    return _x_active;
8004642e01fSmrg}
8014642e01fSmrg
8024642e01fSmrg@end
8034642e01fSmrg
8044642e01fSmrgstatic NSArray *
8054642e01fSmrgarray_with_strings_and_numbers (int nitems, const char **items,
8064642e01fSmrg				const char *numbers) {
8074642e01fSmrg  NSMutableArray *array, *subarray;
8084642e01fSmrg  NSString *string, *number;
8094642e01fSmrg  int i;
8104642e01fSmrg	
8114642e01fSmrg  /* (Can't autorelease on the X server thread) */
8124642e01fSmrg  
8134642e01fSmrg  array = [[NSMutableArray alloc] initWithCapacity:nitems];
8144642e01fSmrg  
8154642e01fSmrg  for (i = 0; i < nitems; i++) {
8164642e01fSmrg    subarray = [[NSMutableArray alloc] initWithCapacity:2];
8174642e01fSmrg    
8184642e01fSmrg    string = [[NSString alloc] initWithUTF8String:items[i]];
8194642e01fSmrg    [subarray addObject:string];
8204642e01fSmrg    [string release];
8214642e01fSmrg    
8224642e01fSmrg    if (numbers[i] != 0) {
8234642e01fSmrg      number = [[NSString alloc] initWithFormat:@"%d", numbers[i]];
8244642e01fSmrg      [subarray addObject:number];
8254642e01fSmrg      [number release];
8264642e01fSmrg    } else
8274642e01fSmrg      [subarray addObject:@""];
8284642e01fSmrg    
8294642e01fSmrg    [array addObject:subarray];
8304642e01fSmrg    [subarray release];
8314642e01fSmrg  }
8324642e01fSmrg  
8334642e01fSmrg  return array;
8344642e01fSmrg}
8354642e01fSmrg
8364642e01fSmrgvoid X11ApplicationSetWindowMenu (int nitems, const char **items,
8374642e01fSmrg				  const char *shortcuts) {
8384642e01fSmrg  NSArray *array;
8394642e01fSmrg  array = array_with_strings_and_numbers (nitems, items, shortcuts);
8404642e01fSmrg  
8414642e01fSmrg  /* Send the array of strings over to the appkit thread */
8424642e01fSmrg  
8434642e01fSmrg  message_kit_thread (@selector (set_window_menu:), array);
8444642e01fSmrg  [array release];
8454642e01fSmrg}
8464642e01fSmrg
8474642e01fSmrgvoid X11ApplicationSetWindowMenuCheck (int idx) {
8484642e01fSmrg  NSNumber *n;
8494642e01fSmrg  
8504642e01fSmrg  n = [[NSNumber alloc] initWithInt:idx];
8514642e01fSmrg  
8524642e01fSmrg  message_kit_thread (@selector (set_window_menu_check:), n);
8534642e01fSmrg  
8544642e01fSmrg  [n release];
8554642e01fSmrg}
8564642e01fSmrg
8574642e01fSmrgvoid X11ApplicationSetFrontProcess (void) {
8584642e01fSmrg    message_kit_thread (@selector (set_front_process:), nil);
8594642e01fSmrg}
8604642e01fSmrg
8614642e01fSmrgvoid X11ApplicationSetCanQuit (int state) {
8624642e01fSmrg    NSNumber *n;
8634642e01fSmrg	
8644642e01fSmrg    n = [[NSNumber alloc] initWithBool:state];
8654642e01fSmrg	
8664642e01fSmrg    message_kit_thread (@selector (set_can_quit:), n);
8674642e01fSmrg	
8684642e01fSmrg    [n release];
8694642e01fSmrg}
8704642e01fSmrg
8714642e01fSmrgvoid X11ApplicationServerReady (void) {
8724642e01fSmrg    message_kit_thread (@selector (server_ready:), nil);
8734642e01fSmrg}
8744642e01fSmrg
8754642e01fSmrgvoid X11ApplicationShowHideMenubar (int state) {
8764642e01fSmrg    NSNumber *n;
8774642e01fSmrg	
8784642e01fSmrg    n = [[NSNumber alloc] initWithBool:state];
8794642e01fSmrg	
8804642e01fSmrg    message_kit_thread (@selector (show_hide_menubar:), n);
8814642e01fSmrg	
8824642e01fSmrg    [n release];
8834642e01fSmrg}
8844642e01fSmrg
8856747b715Smrgvoid X11ApplicationLaunchClient (const char *cmd) {
8866747b715Smrg    NSString *string;
8876747b715Smrg    
8886747b715Smrg    string = [[NSString alloc] initWithUTF8String:cmd];
8896747b715Smrg	
8906747b715Smrg    message_kit_thread (@selector (launch_client:), string);
8916747b715Smrg	
8926747b715Smrg    [string release];
8936747b715Smrg}
8946747b715Smrg
8958223e2f2Smrg/* This is a special function in that it is run from the *SERVER* thread and
8968223e2f2Smrg * not the AppKit thread.  We want to block entering a screen-capturing RandR
8978223e2f2Smrg * mode until we notify the user about how to get out if the X11 client crashes.
8988223e2f2Smrg */
8998223e2f2SmrgBool X11ApplicationCanEnterRandR(void) {
9008223e2f2Smrg    NSString *title, *msg;
9018223e2f2Smrg    
9028223e2f2Smrg    if([X11App prefs_get_boolean:@PREFS_NO_RANDR_ALERT default:NO] || XQuartzShieldingWindowLevel != 0)
9038223e2f2Smrg        return TRUE;
9048223e2f2Smrg    
9058223e2f2Smrg    title = NSLocalizedString(@"Enter RandR mode?", @"Dialog title when switching to RandR");
9068223e2f2Smrg    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.",
9078223e2f2Smrg                            @"Dialog when switching to RandR");
9088223e2f2Smrg
9098223e2f2Smrg    if(!XQuartzIsRootless)
9108223e2f2Smrg        QuartzShowFullscreen(FALSE);
9118223e2f2Smrg    
9128223e2f2Smrg    switch(NSRunAlertPanel(title, msg, NSLocalizedString(@"Allow", @""), NSLocalizedString (@"Cancel", @""), NSLocalizedString (@"Always Allow", @""))) {
9138223e2f2Smrg        case NSAlertOtherReturn:
9148223e2f2Smrg            [X11App prefs_set_boolean:@PREFS_NO_RANDR_ALERT value:YES];
9158223e2f2Smrg            [X11App prefs_synchronize];
9168223e2f2Smrg        case NSAlertDefaultReturn:
9178223e2f2Smrg            return YES;
9188223e2f2Smrg
9198223e2f2Smrg        default:
9208223e2f2Smrg            return NO;
9218223e2f2Smrg    }
9228223e2f2Smrg}
9238223e2f2Smrg
9244642e01fSmrgstatic void check_xinitrc (void) {
9254642e01fSmrg    char *tem, buf[1024];
9264642e01fSmrg    NSString *msg;
9274642e01fSmrg	
9284642e01fSmrg    if ([X11App prefs_get_boolean:@PREFS_DONE_XINIT_CHECK default:NO])
9294642e01fSmrg		return;
9304642e01fSmrg	
9314642e01fSmrg    tem = getenv ("HOME");
9324642e01fSmrg    if (tem == NULL) goto done;
9334642e01fSmrg	
9344642e01fSmrg    snprintf (buf, sizeof (buf), "%s/.xinitrc", tem);
9354642e01fSmrg    if (access (buf, F_OK) != 0)
9364642e01fSmrg		goto done;
9374642e01fSmrg	
9384642e01fSmrg    msg = NSLocalizedString (@"You have an existing ~/.xinitrc file.\n\n\
9394642e01fSmrgWindows displayed by X11 applications may not have titlebars, or may look \
9404642e01fSmrgdifferent to windows displayed by native applications.\n\n\
9414642e01fSmrgWould you like to move aside the existing file and use the standard X11 \
9424642e01fSmrgenvironment the next time you start X11?", @"Startup xinitrc dialog");
9434642e01fSmrg
9444642e01fSmrg    if(NSAlertDefaultReturn == NSRunAlertPanel (nil, msg, NSLocalizedString (@"Yes", @""),
9454642e01fSmrg                                                NSLocalizedString (@"No", @""), nil)) {
9464642e01fSmrg        char buf2[1024];
9474642e01fSmrg        int i = -1;
9484642e01fSmrg      
9494642e01fSmrg        snprintf (buf2, sizeof (buf2), "%s.old", buf);
9504642e01fSmrg      
9514642e01fSmrg        for(i = 1; access (buf2, F_OK) == 0; i++)
9524642e01fSmrg            snprintf (buf2, sizeof (buf2), "%s.old.%d", buf, i);
9534642e01fSmrg
9544642e01fSmrg        rename (buf, buf2);
9554642e01fSmrg    }
9564642e01fSmrg    
9574642e01fSmrg done:
9584642e01fSmrg    [X11App prefs_set_boolean:@PREFS_DONE_XINIT_CHECK value:YES];
9594642e01fSmrg    [X11App prefs_synchronize];
9604642e01fSmrg}
9614642e01fSmrg
9629ace9065Smrgstatic inline pthread_t create_thread(void *(*func)(void *), void *arg) {
9636747b715Smrg    pthread_attr_t attr;
9646747b715Smrg    pthread_t tid;
9656747b715Smrg    
9666747b715Smrg    pthread_attr_init(&attr);
9676747b715Smrg    pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM);
9686747b715Smrg    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
9696747b715Smrg    pthread_create(&tid, &attr, func, arg);
9706747b715Smrg    pthread_attr_destroy(&attr);
9716747b715Smrg    
9726747b715Smrg    return tid;
9736747b715Smrg}
9746747b715Smrg
9756747b715Smrgstatic void *xpbproxy_x_thread(void *args) {
9766747b715Smrg    xpbproxy_run();
9776747b715Smrg
9786747b715Smrg    fprintf(stderr, "xpbproxy thread is terminating unexpectedly.\n");
9796747b715Smrg    return NULL;
9806747b715Smrg}
9816747b715Smrg
9824642e01fSmrgvoid X11ApplicationMain (int argc, char **argv, char **envp) {
9834642e01fSmrg    NSAutoreleasePool *pool;
9844642e01fSmrg
9854642e01fSmrg#ifdef DEBUG
9864642e01fSmrg    while (access ("/tmp/x11-block", F_OK) == 0) sleep (1);
9874642e01fSmrg#endif
9884642e01fSmrg  
9894642e01fSmrg    pool = [[NSAutoreleasePool alloc] init];
9904642e01fSmrg    X11App = (X11Application *) [X11Application sharedApplication];
9914642e01fSmrg    init_ports ();
9924642e01fSmrg    
9934642e01fSmrg    app_prefs_domain_cfstr = (CFStringRef)[[NSBundle mainBundle] bundleIdentifier];
9944642e01fSmrg
9954642e01fSmrg    [NSApp read_defaults];
9964642e01fSmrg    [NSBundle loadNibNamed:@"main" owner:NSApp];
9974642e01fSmrg    [[NSNotificationCenter defaultCenter] addObserver:NSApp
9984642e01fSmrg					selector:@selector (became_key:)
9994642e01fSmrg					name:NSWindowDidBecomeKeyNotification object:nil];
10004642e01fSmrg
10014642e01fSmrg    /*
10024642e01fSmrg     * The xpr Quartz mode is statically linked into this server.
10034642e01fSmrg     * Initialize all the Quartz functions.
10044642e01fSmrg     */
10054642e01fSmrg    QuartzModeBundleInit();
10064642e01fSmrg
10074642e01fSmrg    /* Calculate the height of the menubar so we can avoid it. */
10084642e01fSmrg    aquaMenuBarHeight = NSHeight([[NSScreen mainScreen] frame]) -
10094642e01fSmrg    NSMaxY([[NSScreen mainScreen] visibleFrame]);
10104642e01fSmrg
10114642e01fSmrg    /* Set the key layout seed before we start the server */
10124642e01fSmrg#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1050
10134642e01fSmrg    last_key_layout = TISCopyCurrentKeyboardLayoutInputSource();    
10144642e01fSmrg
10154642e01fSmrg    if(!last_key_layout)
10164642e01fSmrg        fprintf(stderr, "X11ApplicationMain: Unable to determine TISCopyCurrentKeyboardLayoutInputSource() at startup.\n");
10174642e01fSmrg#else
10184642e01fSmrg    KLGetCurrentKeyboardLayout(&last_key_layout);
10194642e01fSmrg    if(!last_key_layout)
10204642e01fSmrg        fprintf(stderr, "X11ApplicationMain: Unable to determine KLGetCurrentKeyboardLayout() at startup.\n");
10214642e01fSmrg#endif
10224642e01fSmrg
10236747b715Smrg    if (!QuartsResyncKeymap(FALSE)) {
10244642e01fSmrg        fprintf(stderr, "X11ApplicationMain: Could not build a valid keymap.\n");
10254642e01fSmrg    }
10264642e01fSmrg
10274642e01fSmrg    /* Tell the server thread that it can proceed */
10284642e01fSmrg    QuartzInitServer(argc, argv, envp);
10294642e01fSmrg    
10304642e01fSmrg    /* This must be done after QuartzInitServer because it can result in
10314642e01fSmrg     * an mieqEnqueue() - <rdar://problem/6300249>
10324642e01fSmrg     */
10334642e01fSmrg    check_xinitrc();
10344642e01fSmrg    
10356747b715Smrg    create_thread(xpbproxy_x_thread, NULL);
10366747b715Smrg
10376747b715Smrg#if XQUARTZ_SPARKLE
10386747b715Smrg    [[X11App controller] setup_sparkle];
10396747b715Smrg    [[SUUpdater sharedUpdater] resetUpdateCycle];
10406747b715Smrg//    [[SUUpdater sharedUpdater] checkForUpdates:X11App];
10416747b715Smrg#endif
10426747b715Smrg
10436747b715Smrg    [pool release];
10444642e01fSmrg    [NSApp run];
10454642e01fSmrg    /* not reached */
10464642e01fSmrg}
10474642e01fSmrg
10484642e01fSmrg@implementation X11Application (Private)
10494642e01fSmrg
10504642e01fSmrg#ifdef NX_DEVICELCMDKEYMASK
10514642e01fSmrg/* This is to workaround a bug in the VNC server where we sometimes see the L
10524642e01fSmrg * modifier and sometimes see no "side"
10534642e01fSmrg */
10544642e01fSmrgstatic inline int ensure_flag(int flags, int device_independent, int device_dependents, int device_dependent_default) {
10554642e01fSmrg    if( (flags & device_independent) &&
10564642e01fSmrg       !(flags & device_dependents))
10574642e01fSmrg        flags |= device_dependent_default;
10584642e01fSmrg    return flags;
10594642e01fSmrg}
10604642e01fSmrg#endif
10614642e01fSmrg
10629ace9065Smrg#ifdef DEBUG_UNTRUSTED_POINTER_DELTA
10639ace9065Smrgstatic const char *untrusted_str(NSEvent *e) {
10649ace9065Smrg    switch([e type]) {
10659ace9065Smrg        case NSScrollWheel:
10669ace9065Smrg            return "NSScrollWheel";
10679ace9065Smrg        case NSTabletPoint:
10689ace9065Smrg            return "NSTabletPoint";
10699ace9065Smrg        case NSOtherMouseDown:
10709ace9065Smrg            return "NSOtherMouseDown";
10719ace9065Smrg        case NSOtherMouseUp:
10729ace9065Smrg            return "NSOtherMouseUp";
10739ace9065Smrg        case NSLeftMouseDown:
10749ace9065Smrg            return "NSLeftMouseDown";
10759ace9065Smrg        case NSLeftMouseUp:
10769ace9065Smrg            return "NSLeftMouseUp";
10779ace9065Smrg        default:
10789ace9065Smrg            switch([e subtype]) {
10799ace9065Smrg                case NSTabletPointEventSubtype:
10809ace9065Smrg                    return "NSTabletPointEventSubtype";
10819ace9065Smrg                case NSTabletProximityEventSubtype:
10829ace9065Smrg                    return "NSTabletProximityEventSubtype";
10839ace9065Smrg                default:
10849ace9065Smrg                    return "Other";
10859ace9065Smrg            }
10869ace9065Smrg    }
10879ace9065Smrg}
10889ace9065Smrg#endif
10899ace9065Smrg
10904642e01fSmrg- (void) sendX11NSEvent:(NSEvent *)e {
10916747b715Smrg    NSPoint location = NSZeroPoint, tilt = NSZeroPoint;
10924642e01fSmrg    int ev_button, ev_type;
10936747b715Smrg    float pressure = 0.0;
10944642e01fSmrg    DeviceIntPtr pDev;
10954642e01fSmrg    int modifierFlags;
10966747b715Smrg    BOOL isMouseOrTabletEvent, isTabletEvent;
10974642e01fSmrg
10986747b715Smrg    isMouseOrTabletEvent =  [e type] == NSLeftMouseDown    ||  [e type] == NSOtherMouseDown    ||  [e type] == NSRightMouseDown    ||
10996747b715Smrg                            [e type] == NSLeftMouseUp      ||  [e type] == NSOtherMouseUp      ||  [e type] == NSRightMouseUp      ||
11006747b715Smrg                            [e type] == NSLeftMouseDragged ||  [e type] == NSOtherMouseDragged ||  [e type] == NSRightMouseDragged ||
11016747b715Smrg                            [e type] == NSMouseMoved       ||  [e type] == NSTabletPoint       ||  [e type] == NSScrollWheel;
11024642e01fSmrg
11036747b715Smrg    isTabletEvent = ([e type] == NSTabletPoint) ||
11046747b715Smrg                    (isMouseOrTabletEvent && ([e subtype] == NSTabletPointEventSubtype || [e subtype] == NSTabletProximityEventSubtype));
11054642e01fSmrg
11066747b715Smrg    if(isMouseOrTabletEvent) {
11076747b715Smrg        static NSPoint lastpt;
11086747b715Smrg        NSWindow *window = [e window];
11096747b715Smrg        NSRect screen = [[[NSScreen screens] objectAtIndex:0] frame];
11106747b715Smrg	    BOOL hasUntrustedPointerDelta;
11116747b715Smrg        
11126747b715Smrg        // NSEvents for tablets are not consistent wrt deltaXY between events, so we cannot rely on that
11136747b715Smrg        // Thus tablets will be subject to the warp-pointer bug worked around by the delta, but tablets
11146747b715Smrg        // are not normally used in cases where that bug would present itself, so this is a fair tradeoff
11156747b715Smrg        // <rdar://problem/7111003> deltaX and deltaY are incorrect for NSMouseMoved, NSTabletPointEventSubtype
11166747b715Smrg        // http://xquartz.macosforge.org/trac/ticket/288
11176747b715Smrg        hasUntrustedPointerDelta = isTabletEvent;
11186747b715Smrg        
11196747b715Smrg        // The deltaXY for middle click events also appear erroneous after fast user switching
11206747b715Smrg        // <rdar://problem/7979468> deltaX and deltaY are incorrect for NSOtherMouseDown and NSOtherMouseUp after FUS
11216747b715Smrg        // http://xquartz.macosforge.org/trac/ticket/389
11226747b715Smrg        hasUntrustedPointerDelta = hasUntrustedPointerDelta || [e type] == NSOtherMouseDown || [e type] == NSOtherMouseUp;
11236747b715Smrg
11246747b715Smrg        // The deltaXY for scroll events correspond to the scroll delta, not the pointer delta
11256747b715Smrg        // <rdar://problem/7989690> deltaXY for wheel events are being sent as mouse movement
11266747b715Smrg        hasUntrustedPointerDelta = hasUntrustedPointerDelta || [e type] == NSScrollWheel;
11279ace9065Smrg
11289ace9065Smrg#ifdef DEBUG_UNTRUSTED_POINTER_DELTA
11299ace9065Smrg        hasUntrustedPointerDelta = hasUntrustedPointerDelta || [e type] == NSLeftMouseDown || [e type] == NSLeftMouseUp;
11309ace9065Smrg#endif
11316747b715Smrg        
11326747b715Smrg        if (window != nil)	{
11336747b715Smrg            NSRect frame = [window frame];
11346747b715Smrg            location = [e locationInWindow];
11356747b715Smrg            location.x += frame.origin.x;
11366747b715Smrg            location.y += frame.origin.y;
11376747b715Smrg            lastpt = location;
11386747b715Smrg        } else if(hasUntrustedPointerDelta) {
11399ace9065Smrg#ifdef DEBUG_UNTRUSTED_POINTER_DELTA
11409ace9065Smrg            ErrorF("--- Begin Event Debug ---\n");
11419ace9065Smrg            ErrorF("Event type: %s\n", untrusted_str(e));
11429ace9065Smrg            ErrorF("old lastpt: (%0.2f, %0.2f)\n", lastpt.x, lastpt.y);
11439ace9065Smrg            ErrorF("     delta: (%0.2f, %0.2f)\n", [e deltaX], -[e deltaY]);
11449ace9065Smrg            ErrorF("  location: (%0.2f, %0.2f)\n", lastpt.x + [e deltaX], lastpt.y - [e deltaY]);
11459ace9065Smrg            ErrorF("workaround: (%0.2f, %0.2f)\n", [e locationInWindow].x, [e locationInWindow].y);
11469ace9065Smrg            ErrorF("--- End Event Debug ---\n");
11479ace9065Smrg
11489ace9065Smrg            location.x = lastpt.x + [e deltaX];
11499ace9065Smrg            location.y = lastpt.y - [e deltaY];
11509ace9065Smrg            lastpt = [e locationInWindow];
11519ace9065Smrg#else
11526747b715Smrg            location = [e locationInWindow];
11536747b715Smrg            lastpt = location;
11549ace9065Smrg#endif
11556747b715Smrg        } else {
11566747b715Smrg            location.x = lastpt.x + [e deltaX];
11576747b715Smrg            location.y = lastpt.y - [e deltaY];
11586747b715Smrg            lastpt = [e locationInWindow];
11596747b715Smrg        }
11606747b715Smrg        
11616747b715Smrg        /* Convert coordinate system */
11626747b715Smrg        location.y = (screen.origin.y + screen.size.height) - location.y;
11636747b715Smrg    }
11644642e01fSmrg    
11654642e01fSmrg    modifierFlags = [e modifierFlags];
11664642e01fSmrg    
11674642e01fSmrg#ifdef NX_DEVICELCMDKEYMASK
11684642e01fSmrg    /* This is to workaround a bug in the VNC server where we sometimes see the L
11694642e01fSmrg     * modifier and sometimes see no "side"
11704642e01fSmrg     */
11714642e01fSmrg    modifierFlags = ensure_flag(modifierFlags, NX_CONTROLMASK,   NX_DEVICELCTLKEYMASK   | NX_DEVICERCTLKEYMASK,     NX_DEVICELCTLKEYMASK);
11724642e01fSmrg    modifierFlags = ensure_flag(modifierFlags, NX_SHIFTMASK,     NX_DEVICELSHIFTKEYMASK | NX_DEVICERSHIFTKEYMASK,   NX_DEVICELSHIFTKEYMASK);
11734642e01fSmrg    modifierFlags = ensure_flag(modifierFlags, NX_COMMANDMASK,   NX_DEVICELCMDKEYMASK   | NX_DEVICERCMDKEYMASK,     NX_DEVICELCMDKEYMASK);
11744642e01fSmrg    modifierFlags = ensure_flag(modifierFlags, NX_ALTERNATEMASK, NX_DEVICELALTKEYMASK   | NX_DEVICERALTKEYMASK,     NX_DEVICELALTKEYMASK);
11754642e01fSmrg#endif
11764642e01fSmrg
11776747b715Smrg    modifierFlags &= darwin_all_modifier_mask;
11784642e01fSmrg
11794642e01fSmrg    /* We don't receive modifier key events while out of focus, and 3button
11804642e01fSmrg     * emulation mucks this up, so we need to check our modifier flag state
11814642e01fSmrg     * on every event... ugg
11824642e01fSmrg     */
11834642e01fSmrg    
11846747b715Smrg    if(darwin_all_modifier_flags != modifierFlags)
11854642e01fSmrg        DarwinUpdateModKeys(modifierFlags);
11864642e01fSmrg    
11874642e01fSmrg	switch ([e type]) {
11884642e01fSmrg		case NSLeftMouseDown:     ev_button=1; ev_type=ButtonPress;   goto handle_mouse;
11894642e01fSmrg		case NSOtherMouseDown:    ev_button=2; ev_type=ButtonPress;   goto handle_mouse;
11904642e01fSmrg		case NSRightMouseDown:    ev_button=3; ev_type=ButtonPress;   goto handle_mouse;
11914642e01fSmrg		case NSLeftMouseUp:       ev_button=1; ev_type=ButtonRelease; goto handle_mouse;
11924642e01fSmrg		case NSOtherMouseUp:      ev_button=2; ev_type=ButtonRelease; goto handle_mouse;
11934642e01fSmrg		case NSRightMouseUp:      ev_button=3; ev_type=ButtonRelease; goto handle_mouse;
11944642e01fSmrg		case NSLeftMouseDragged:  ev_button=1; ev_type=MotionNotify;  goto handle_mouse;
11954642e01fSmrg		case NSOtherMouseDragged: ev_button=2; ev_type=MotionNotify;  goto handle_mouse;
11964642e01fSmrg		case NSRightMouseDragged: ev_button=3; ev_type=MotionNotify;  goto handle_mouse;
11974642e01fSmrg		case NSMouseMoved:        ev_button=0; ev_type=MotionNotify;  goto handle_mouse;
11984642e01fSmrg        case NSTabletPoint:       ev_button=0; ev_type=MotionNotify;  goto handle_mouse;
11994642e01fSmrg            
12004642e01fSmrg        handle_mouse:
12014642e01fSmrg            pDev = darwinPointer;
12024642e01fSmrg
12034642e01fSmrg            /* NSTabletPoint can have no subtype */
12044642e01fSmrg            if([e type] != NSTabletPoint &&
12054642e01fSmrg               [e subtype] == NSTabletProximityEventSubtype) {
12064642e01fSmrg                switch([e pointingDeviceType]) {
12074642e01fSmrg                    case NSEraserPointingDevice:
12084642e01fSmrg                        darwinTabletCurrent=darwinTabletEraser;
12094642e01fSmrg                        break;
12104642e01fSmrg                    case NSPenPointingDevice:
12114642e01fSmrg                        darwinTabletCurrent=darwinTabletStylus;
12124642e01fSmrg                        break;
12134642e01fSmrg                    case NSCursorPointingDevice:
12144642e01fSmrg                    case NSUnknownPointingDevice:
12154642e01fSmrg                    default:
12164642e01fSmrg                        darwinTabletCurrent=darwinTabletCursor;
12174642e01fSmrg                        break;
12184642e01fSmrg                }
12194642e01fSmrg                
12204642e01fSmrg                /* NSTabletProximityEventSubtype doesn't encode pressure ant tilt
12214642e01fSmrg                 * So we just pretend the motion was caused by the mouse.  Hopefully
12224642e01fSmrg                 * we'll have a better solution for this in the future (like maybe
12234642e01fSmrg                 * NSTabletProximityEventSubtype will come from NSTabletPoint
12244642e01fSmrg                 * rather than NSMouseMoved.
12254642e01fSmrg                pressure = [e pressure];
12266747b715Smrg                tilt     = [e tilt];
12274642e01fSmrg                pDev = darwinTabletCurrent;                
12284642e01fSmrg                 */
12294642e01fSmrg
12306747b715Smrg                DarwinSendProximityEvents([e isEnteringProximity] ? ProximityIn : ProximityOut,
12316747b715Smrg                                          location.x, location.y);
12324642e01fSmrg            }
12334642e01fSmrg
12344642e01fSmrg			if ([e type] == NSTabletPoint || [e subtype] == NSTabletPointEventSubtype) {
12354642e01fSmrg                pressure = [e pressure];
12366747b715Smrg                tilt     = [e tilt];
12374642e01fSmrg                
12384642e01fSmrg                pDev = darwinTabletCurrent;
12394642e01fSmrg            }
12404642e01fSmrg
12416747b715Smrg            if(!XQuartzServerVisible && noTestExtensions) {
12426747b715Smrg#if defined(XPLUGIN_VERSION) && XPLUGIN_VERSION > 0
12434642e01fSmrg/* Older libXplugin (Tiger/"Stock" Leopard) aren't thread safe, so we can't call xp_find_window from the Appkit thread */
12446747b715Smrg                xp_window_id wid = 0;
12456747b715Smrg                xp_error e;
12464642e01fSmrg
12474642e01fSmrg                /* Sigh. Need to check that we're really over one of
12484642e01fSmrg                 * our windows. (We need to receive pointer events while
12494642e01fSmrg                 * not in the foreground, but we don't want to receive them
12504642e01fSmrg                 * when another window is over us or we might show a tooltip)
12514642e01fSmrg                 */
12526747b715Smrg
12536747b715Smrg                e = xp_find_window(location.x, location.y, 0, &wid);
12546747b715Smrg
12556747b715Smrg                if (e != XP_Success || (e == XP_Success && wid == 0))
12564642e01fSmrg#endif
12576747b715Smrg                {
12586747b715Smrg                    bgMouseLocation = location;
12596747b715Smrg                    bgMouseLocationUpdated = TRUE;
12606747b715Smrg                    return;
12616747b715Smrg                }
12626747b715Smrg            }
12634642e01fSmrg            
12646747b715Smrg            if(bgMouseLocationUpdated) {
12656747b715Smrg                if(!(ev_type == MotionNotify && ev_button == 0)) {
12666747b715Smrg                    DarwinSendPointerEvents(pDev, MotionNotify, 0, location.x,
12676747b715Smrg                                            location.y, pressure, tilt.x, tilt.y);
12686747b715Smrg                }
12696747b715Smrg                bgMouseLocationUpdated = FALSE;
12706747b715Smrg            }
12716747b715Smrg
12726747b715Smrg            DarwinSendPointerEvents(pDev, ev_type, ev_button, location.x, location.y,
12736747b715Smrg                                    pressure, tilt.x, tilt.y);
12744642e01fSmrg            
12754642e01fSmrg            break;
12764642e01fSmrg            
12774642e01fSmrg		case NSTabletProximity:
12784642e01fSmrg            switch([e pointingDeviceType]) {
12794642e01fSmrg                case NSEraserPointingDevice:
12804642e01fSmrg                    darwinTabletCurrent=darwinTabletEraser;
12814642e01fSmrg                    break;
12824642e01fSmrg                case NSPenPointingDevice:
12834642e01fSmrg                    darwinTabletCurrent=darwinTabletStylus;
12844642e01fSmrg                    break;
12854642e01fSmrg                case NSCursorPointingDevice:
12864642e01fSmrg                case NSUnknownPointingDevice:
12874642e01fSmrg                default:
12884642e01fSmrg                    darwinTabletCurrent=darwinTabletCursor;
12894642e01fSmrg                    break;
12904642e01fSmrg            }
12914642e01fSmrg            
12926747b715Smrg			DarwinSendProximityEvents([e isEnteringProximity] ? ProximityIn : ProximityOut,
12936747b715Smrg                                      location.x, location.y);
12944642e01fSmrg            break;
12954642e01fSmrg            
12964642e01fSmrg		case NSScrollWheel:
12976747b715Smrg#if !defined(XPLUGIN_VERSION) || XPLUGIN_VERSION == 0
12986747b715Smrg            /* If we're in the background, we need to send a MotionNotify event
12996747b715Smrg             * first, since we aren't getting them on background mouse motion
13006747b715Smrg             */
13016747b715Smrg            if(!XQuartzServerVisible && noTestExtensions) {
13026747b715Smrg                bgMouseLocationUpdated = FALSE;
13036747b715Smrg                DarwinSendPointerEvents(darwinPointer, MotionNotify, 0, location.x,
13046747b715Smrg                                        location.y, pressure, tilt.x, tilt.y);
13056747b715Smrg            }
13066747b715Smrg#endif
13076747b715Smrg			DarwinSendScrollEvents([e deltaX], [e deltaY], location.x, location.y,
13086747b715Smrg                                   pressure, tilt.x, tilt.y);
13094642e01fSmrg            break;
13104642e01fSmrg            
13114642e01fSmrg        case NSKeyDown: case NSKeyUp:
13126747b715Smrg            {
13136747b715Smrg                /* XKB clobbers our keymap at startup, so we need to force it on the first keypress.
13146747b715Smrg                 * TODO: Make this less of a kludge.
13156747b715Smrg                 */
13166747b715Smrg                static int force_resync_keymap = YES;
13176747b715Smrg                if(force_resync_keymap) {
13186747b715Smrg                    DarwinSendDDXEvent(kXquartzReloadKeymap, 0);
13196747b715Smrg                    force_resync_keymap = NO;
13206747b715Smrg                }
13216747b715Smrg            }
13226747b715Smrg
13234642e01fSmrg            if(darwinSyncKeymap) {
13244642e01fSmrg#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1050
13254642e01fSmrg                TISInputSourceRef key_layout = TISCopyCurrentKeyboardLayoutInputSource();
13264642e01fSmrg                TISInputSourceRef clear;
13274642e01fSmrg                if (CFEqual(key_layout, last_key_layout)) {
13284642e01fSmrg                    CFRelease(key_layout);
13294642e01fSmrg                } else {
13304642e01fSmrg                    /* Swap/free thread-safely */
13314642e01fSmrg                    clear = last_key_layout;
13324642e01fSmrg                    last_key_layout = key_layout;
13334642e01fSmrg                    CFRelease(clear);
13344642e01fSmrg#else
13354642e01fSmrg                KeyboardLayoutRef key_layout;
13364642e01fSmrg                KLGetCurrentKeyboardLayout(&key_layout);
13374642e01fSmrg                if(key_layout != last_key_layout) {
13384642e01fSmrg                    last_key_layout = key_layout;
13394642e01fSmrg#endif
13404642e01fSmrg                    /* Update keyInfo */
13416747b715Smrg                    if (!QuartsResyncKeymap(TRUE)) {
13424642e01fSmrg                        fprintf(stderr, "sendX11NSEvent: Could not build a valid keymap.\n");
13434642e01fSmrg                    }
13444642e01fSmrg                }
13454642e01fSmrg            }
13464642e01fSmrg
13474642e01fSmrg            /* Avoid stuck keys on context switch */
13484642e01fSmrg            if(keyState[[e keyCode]] == [e type])
13494642e01fSmrg                return;
13504642e01fSmrg            keyState[[e keyCode]] = [e type];
13514642e01fSmrg
13524642e01fSmrg            DarwinSendKeyboardEvents(([e type] == NSKeyDown) ? KeyPress : KeyRelease, [e keyCode]);
13534642e01fSmrg            break;
13544642e01fSmrg            
13554642e01fSmrg        default: break; /* for gcc */
13564642e01fSmrg	}	
13574642e01fSmrg}
13584642e01fSmrg@end
1359