1706f2543Smrg/* X11Application.m -- subclass of NSApplication to multiplex events
2706f2543Smrg 
3706f2543Smrg Copyright (c) 2002-2008 Apple Inc.
4706f2543Smrg 
5706f2543Smrg Permission is hereby granted, free of charge, to any person
6706f2543Smrg obtaining a copy of this software and associated documentation files
7706f2543Smrg (the "Software"), to deal in the Software without restriction,
8706f2543Smrg including without limitation the rights to use, copy, modify, merge,
9706f2543Smrg publish, distribute, sublicense, and/or sell copies of the Software,
10706f2543Smrg and to permit persons to whom the Software is furnished to do so,
11706f2543Smrg subject to the following conditions:
12706f2543Smrg 
13706f2543Smrg The above copyright notice and this permission notice shall be
14706f2543Smrg included in all copies or substantial portions of the Software.
15706f2543Smrg 
16706f2543Smrg THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17706f2543Smrg EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18706f2543Smrg MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19706f2543Smrg NONINFRINGEMENT.  IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT
20706f2543Smrg HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
21706f2543Smrg WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22706f2543Smrg OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23706f2543Smrg DEALINGS IN THE SOFTWARE.
24706f2543Smrg 
25706f2543Smrg Except as contained in this notice, the name(s) of the above
26706f2543Smrg copyright holders shall not be used in advertising or otherwise to
27706f2543Smrg promote the sale, use or other dealings in this Software without
28706f2543Smrg prior written authorization. */
29706f2543Smrg
30706f2543Smrg#include "sanitizedCarbon.h"
31706f2543Smrg
32706f2543Smrg#ifdef HAVE_DIX_CONFIG_H
33706f2543Smrg#include <dix-config.h>
34706f2543Smrg#endif
35706f2543Smrg
36706f2543Smrg#include "quartzCommon.h"
37706f2543Smrg
38706f2543Smrg#import "X11Application.h"
39706f2543Smrg
40706f2543Smrg#include "darwin.h"
41706f2543Smrg#include "quartz.h"
42706f2543Smrg#include "darwinEvents.h"
43706f2543Smrg#include "quartzKeyboard.h"
44706f2543Smrg#include "quartz.h"
45706f2543Smrg#include <X11/extensions/applewmconst.h>
46706f2543Smrg#include "micmap.h"
47706f2543Smrg#include "exglobals.h"
48706f2543Smrg
49706f2543Smrg#include <mach/mach.h>
50706f2543Smrg#include <unistd.h>
51706f2543Smrg#include <AvailabilityMacros.h>
52706f2543Smrg
53706f2543Smrg#include <pthread.h>
54706f2543Smrg
55706f2543Smrg#include <Xplugin.h>
56706f2543Smrg
57706f2543Smrg// pbproxy/pbproxy.h
58706f2543Smrgextern int xpbproxy_run (void);
59706f2543Smrg
60706f2543Smrg#define DEFAULTS_FILE X11LIBDIR"/X11/xserver/Xquartz.plist"
61706f2543Smrg
62706f2543Smrg#ifndef XSERVER_VERSION
63706f2543Smrg#define XSERVER_VERSION "?"
64706f2543Smrg#endif
65706f2543Smrg
66706f2543Smrg/* Stuck modifier / button state... force release when we context switch */
67706f2543Smrgstatic NSEventType keyState[NUM_KEYCODES];
68706f2543Smrg
69706f2543Smrgextern Bool noTestExtensions;
70706f2543Smrg
71706f2543Smrg#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1050
72706f2543Smrgstatic TISInputSourceRef last_key_layout;
73706f2543Smrg#else
74706f2543Smrgstatic KeyboardLayoutRef last_key_layout;
75706f2543Smrg#endif
76706f2543Smrg
77706f2543Smrg/* This preference is only tested on Lion or later as it's not relevant to
78706f2543Smrg * earlier OS versions.
79706f2543Smrg */
80706f2543SmrgBool XQuartzScrollInDeviceDirection = FALSE;
81706f2543Smrg
82706f2543Smrgextern int darwinFakeButtons;
83706f2543Smrg
84706f2543Smrg/* Store the mouse location while in the background, and update X11's pointer
85706f2543Smrg * location when we become the foreground application
86706f2543Smrg */
87706f2543Smrgstatic NSPoint bgMouseLocation;
88706f2543Smrgstatic BOOL bgMouseLocationUpdated = FALSE;
89706f2543Smrg
90706f2543SmrgX11Application *X11App;
91706f2543Smrg
92706f2543SmrgCFStringRef app_prefs_domain_cfstr = NULL;
93706f2543Smrg
94706f2543Smrg#define ALL_KEY_MASKS (NSShiftKeyMask | NSControlKeyMask | NSAlternateKeyMask | NSCommandKeyMask)
95706f2543Smrg
96706f2543Smrg@interface X11Application (Private)
97706f2543Smrg- (void) sendX11NSEvent:(NSEvent *)e;
98706f2543Smrg@end
99706f2543Smrg
100706f2543Smrg@implementation X11Application
101706f2543Smrg
102706f2543Smrgtypedef struct message_struct message;
103706f2543Smrgstruct message_struct {
104706f2543Smrg    mach_msg_header_t hdr;
105706f2543Smrg    SEL selector;
106706f2543Smrg    NSObject *arg;
107706f2543Smrg};
108706f2543Smrg
109706f2543Smrgstatic mach_port_t _port;
110706f2543Smrg
111706f2543Smrg/* Quartz mode initialization routine. This is often dynamically loaded
112706f2543Smrg   but is statically linked into this X server. */
113706f2543SmrgBool QuartzModeBundleInit(void);
114706f2543Smrg
115706f2543Smrgstatic void init_ports (void) {
116706f2543Smrg    kern_return_t r;
117706f2543Smrg    NSPort *p;
118706f2543Smrg	
119706f2543Smrg    if (_port != MACH_PORT_NULL) return;
120706f2543Smrg	
121706f2543Smrg    r = mach_port_allocate (mach_task_self (), MACH_PORT_RIGHT_RECEIVE, &_port);
122706f2543Smrg    if (r != KERN_SUCCESS) return;
123706f2543Smrg	
124706f2543Smrg    p = [NSMachPort portWithMachPort:_port];
125706f2543Smrg    [p setDelegate:NSApp];
126706f2543Smrg    [p scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
127706f2543Smrg}
128706f2543Smrg
129706f2543Smrgstatic void message_kit_thread (SEL selector, NSObject *arg) {
130706f2543Smrg    message msg;
131706f2543Smrg    kern_return_t r;
132706f2543Smrg	
133706f2543Smrg    msg.hdr.msgh_bits = MACH_MSGH_BITS (MACH_MSG_TYPE_MAKE_SEND, 0);
134706f2543Smrg    msg.hdr.msgh_size = sizeof (msg);
135706f2543Smrg    msg.hdr.msgh_remote_port = _port;
136706f2543Smrg    msg.hdr.msgh_local_port = MACH_PORT_NULL;
137706f2543Smrg    msg.hdr.msgh_reserved = 0;
138706f2543Smrg    msg.hdr.msgh_id = 0;
139706f2543Smrg	
140706f2543Smrg    msg.selector = selector;
141706f2543Smrg    msg.arg = [arg retain];
142706f2543Smrg	
143706f2543Smrg    r = mach_msg (&msg.hdr, MACH_SEND_MSG, msg.hdr.msgh_size,
144706f2543Smrg		  0, MACH_PORT_NULL, 0, MACH_PORT_NULL);
145706f2543Smrg    if (r != KERN_SUCCESS)
146706f2543Smrg		ErrorF("%s: mach_msg failed: %x\n", __FUNCTION__, r);
147706f2543Smrg}
148706f2543Smrg
149706f2543Smrg- (void) handleMachMessage:(void *)_msg {
150706f2543Smrg    message *msg = _msg;
151706f2543Smrg	
152706f2543Smrg    [self performSelector:msg->selector withObject:msg->arg];
153706f2543Smrg    [msg->arg release];
154706f2543Smrg}
155706f2543Smrg
156706f2543Smrg- (void) set_controller:obj {
157706f2543Smrg    if (_controller == nil) _controller = [obj retain];
158706f2543Smrg}
159706f2543Smrg
160706f2543Smrg- (void) dealloc {
161706f2543Smrg    if (_controller != nil) [_controller release];
162706f2543Smrg	
163706f2543Smrg    if (_port != MACH_PORT_NULL)
164706f2543Smrg		mach_port_deallocate (mach_task_self (), _port);
165706f2543Smrg	
166706f2543Smrg    [super dealloc];
167706f2543Smrg}
168706f2543Smrg
169706f2543Smrg- (void) orderFrontStandardAboutPanel: (id) sender {
170706f2543Smrg    NSMutableDictionary *dict;
171706f2543Smrg    NSDictionary *infoDict;
172706f2543Smrg    NSString *tem;
173706f2543Smrg    
174706f2543Smrg    dict = [NSMutableDictionary dictionaryWithCapacity:3];
175706f2543Smrg    infoDict = [[NSBundle mainBundle] infoDictionary];
176706f2543Smrg    
177706f2543Smrg    [dict setObject: NSLocalizedString (@"The X Window System", @"About panel")
178706f2543Smrg          forKey:@"ApplicationName"];
179706f2543Smrg    
180706f2543Smrg    tem = [infoDict objectForKey:@"CFBundleShortVersionString"];
181706f2543Smrg    
182706f2543Smrg    [dict setObject:[NSString stringWithFormat:@"XQuartz %@", tem]
183706f2543Smrg          forKey:@"ApplicationVersion"];
184706f2543Smrg
185706f2543Smrg    [dict setObject:[NSString stringWithFormat:@"xorg-server %s", XSERVER_VERSION]
186706f2543Smrg          forKey:@"Version"];
187706f2543Smrg    
188706f2543Smrg    [self orderFrontStandardAboutPanelWithOptions: dict];
189706f2543Smrg}
190706f2543Smrg
191706f2543Smrg- (void) activateX:(OSX_BOOL)state {
192706f2543Smrg    size_t i;
193706f2543Smrg    DEBUG_LOG("state=%d, _x_active=%d, \n", state, _x_active)
194706f2543Smrg    if (state) {
195706f2543Smrg        if(bgMouseLocationUpdated) {
196706f2543Smrg            DarwinSendPointerEvents(darwinPointer, MotionNotify, 0, bgMouseLocation.x, bgMouseLocation.y, 0.0, 0.0, 0.0);
197706f2543Smrg            bgMouseLocationUpdated = FALSE;
198706f2543Smrg        }
199706f2543Smrg        DarwinSendDDXEvent(kXquartzActivate, 0);
200706f2543Smrg    } else {
201706f2543Smrg
202706f2543Smrg        if(darwin_all_modifier_flags)
203706f2543Smrg            DarwinUpdateModKeys(0);
204706f2543Smrg        for(i=0; i < NUM_KEYCODES; i++) {
205706f2543Smrg            if(keyState[i] == NSKeyDown) {
206706f2543Smrg                DarwinSendKeyboardEvents(KeyRelease, i);
207706f2543Smrg                keyState[i] = NSKeyUp;
208706f2543Smrg            }
209706f2543Smrg        }
210706f2543Smrg        
211706f2543Smrg        DarwinSendDDXEvent(kXquartzDeactivate, 0);
212706f2543Smrg    }
213706f2543Smrg
214706f2543Smrg    _x_active = state;
215706f2543Smrg}
216706f2543Smrg
217706f2543Smrg- (void) became_key:(NSWindow *)win {
218706f2543Smrg	[self activateX:NO];
219706f2543Smrg}
220706f2543Smrg
221706f2543Smrg- (void) sendEvent:(NSEvent *)e {
222706f2543Smrg    OSX_BOOL for_appkit, for_x;
223706f2543Smrg    
224706f2543Smrg    /* By default pass down the responder chain and to X. */
225706f2543Smrg    for_appkit = YES;
226706f2543Smrg    for_x = YES;
227706f2543Smrg    
228706f2543Smrg    switch ([e type]) {
229706f2543Smrg        case NSLeftMouseDown: case NSRightMouseDown: case NSOtherMouseDown:
230706f2543Smrg        case NSLeftMouseUp: case NSRightMouseUp: case NSOtherMouseUp:
231706f2543Smrg            if ([e window] != nil) {
232706f2543Smrg                /* Pointer event has an (AppKit) window. Probably something for the kit. */
233706f2543Smrg                for_x = NO;
234706f2543Smrg                if (_x_active) [self activateX:NO];
235706f2543Smrg            } else if ([self modalWindow] == nil) {
236706f2543Smrg                /* Must be an X window. Tell appkit it doesn't have focus. */
237706f2543Smrg                for_appkit = NO;
238706f2543Smrg                
239706f2543Smrg                if ([self isActive]) {
240706f2543Smrg                    [self deactivate];
241706f2543Smrg                    if (!_x_active && quartzProcs->IsX11Window([e window],
242706f2543Smrg                                                               [e windowNumber]))
243706f2543Smrg                        [self activateX:YES];
244706f2543Smrg                }
245706f2543Smrg            }
246706f2543Smrg
247706f2543Smrg            /* We want to force sending to appkit if we're over the menu bar */
248706f2543Smrg            if(!for_appkit) {
249706f2543Smrg                NSPoint NSlocation = [e locationInWindow];
250706f2543Smrg                NSWindow *window = [e window];
251706f2543Smrg                NSRect NSframe, NSvisibleFrame;
252706f2543Smrg                CGRect CGframe, CGvisibleFrame;
253706f2543Smrg                CGPoint CGlocation;
254706f2543Smrg
255706f2543Smrg                if (window != nil)	{
256706f2543Smrg                    NSRect frame = [window frame];
257706f2543Smrg                    NSlocation.x += frame.origin.x;
258706f2543Smrg                    NSlocation.y += frame.origin.y;
259706f2543Smrg                }
260706f2543Smrg
261706f2543Smrg                NSframe = [[NSScreen mainScreen] frame];
262706f2543Smrg                NSvisibleFrame = [[NSScreen mainScreen] visibleFrame];
263706f2543Smrg                
264706f2543Smrg                CGframe = CGRectMake(NSframe.origin.x, NSframe.origin.y,
265706f2543Smrg                                            NSframe.size.width, NSframe.size.height);
266706f2543Smrg                CGvisibleFrame = CGRectMake(NSvisibleFrame.origin.x,
267706f2543Smrg                                                   NSvisibleFrame.origin.y,
268706f2543Smrg                                                   NSvisibleFrame.size.width,
269706f2543Smrg                                                   NSvisibleFrame.size.height);
270706f2543Smrg                CGlocation = CGPointMake(NSlocation.x, NSlocation.y);
271706f2543Smrg                
272706f2543Smrg                if(CGRectContainsPoint(CGframe, CGlocation) &&
273706f2543Smrg                   !CGRectContainsPoint(CGvisibleFrame, CGlocation))
274706f2543Smrg                    for_appkit = YES;
275706f2543Smrg            }
276706f2543Smrg            
277706f2543Smrg            break;
278706f2543Smrg            
279706f2543Smrg        case NSKeyDown: case NSKeyUp:
280706f2543Smrg            
281706f2543Smrg            if(_x_active) {
282706f2543Smrg                static BOOL do_swallow = NO;
283706f2543Smrg                static int swallow_keycode;
284706f2543Smrg                
285706f2543Smrg                if([e type] == NSKeyDown) {
286706f2543Smrg                    /* Before that though, see if there are any global
287706f2543Smrg                     * shortcuts bound to it. */
288706f2543Smrg
289706f2543Smrg                    if(darwinAppKitModMask & [e modifierFlags]) {
290706f2543Smrg                        /* Override to force sending to Appkit */
291706f2543Smrg                        swallow_keycode = [e keyCode];
292706f2543Smrg                        do_swallow = YES;
293706f2543Smrg                        for_x = NO;
294706f2543Smrg#if XPLUGIN_VERSION >= 1
295706f2543Smrg                    } else if(XQuartzEnableKeyEquivalents &&
296706f2543Smrg                             xp_is_symbolic_hotkey_event([e eventRef])) {
297706f2543Smrg                        swallow_keycode = [e keyCode];
298706f2543Smrg                        do_swallow = YES;
299706f2543Smrg                        for_x = NO;
300706f2543Smrg#endif
301706f2543Smrg                    } else if(XQuartzEnableKeyEquivalents &&
302706f2543Smrg                              [[self mainMenu] performKeyEquivalent:e]) {
303706f2543Smrg                        swallow_keycode = [e keyCode];
304706f2543Smrg                        do_swallow = YES;
305706f2543Smrg                        for_appkit = NO;
306706f2543Smrg                        for_x = NO;
307706f2543Smrg                    } else if(!XQuartzIsRootless
308706f2543Smrg                              && ([e modifierFlags] & ALL_KEY_MASKS) == (NSCommandKeyMask | NSAlternateKeyMask)
309706f2543Smrg                              && ([e keyCode] == 0 /*a*/ || [e keyCode] == 53 /*Esc*/)) {
310706f2543Smrg                        /* We have this here to force processing fullscreen 
311706f2543Smrg                         * toggle even if XQuartzEnableKeyEquivalents is disabled */
312706f2543Smrg                        swallow_keycode = [e keyCode];
313706f2543Smrg                        do_swallow = YES;
314706f2543Smrg                        for_x = NO;
315706f2543Smrg                        for_appkit = NO;
316706f2543Smrg                        DarwinSendDDXEvent(kXquartzToggleFullscreen, 0);
317706f2543Smrg                    } else {
318706f2543Smrg                        /* No kit window is focused, so send it to X. */
319706f2543Smrg                        for_appkit = NO;
320706f2543Smrg                    }
321706f2543Smrg                } else { /* KeyUp */
322706f2543Smrg                    /* If we saw a key equivalent on the down, don't pass
323706f2543Smrg                     * the up through to X. */
324706f2543Smrg                    if (do_swallow && [e keyCode] == swallow_keycode) {
325706f2543Smrg                        do_swallow = NO;
326706f2543Smrg                        for_x = NO;
327706f2543Smrg                    }
328706f2543Smrg                }
329706f2543Smrg            } else { /* !_x_active */
330706f2543Smrg                for_x = NO;
331706f2543Smrg            }
332706f2543Smrg            break;
333706f2543Smrg            
334706f2543Smrg        case NSFlagsChanged:
335706f2543Smrg            /* Don't tell X11 about modifiers changing while it's not active */
336706f2543Smrg            if (!_x_active)
337706f2543Smrg                for_x = NO;
338706f2543Smrg            break;
339706f2543Smrg            
340706f2543Smrg        case NSAppKitDefined:
341706f2543Smrg            switch ([e subtype]) {
342706f2543Smrg                static BOOL x_was_active = NO;
343706f2543Smrg
344706f2543Smrg                case NSApplicationActivatedEventType:
345706f2543Smrg                    for_x = NO;
346706f2543Smrg                    if ([e window] == nil && x_was_active) {
347706f2543Smrg                        BOOL order_all_windows = YES, workspaces, ok;
348706f2543Smrg                        for_appkit = NO;
349706f2543Smrg
350706f2543Smrg                        /* FIXME: This is a hack to avoid passing the event to AppKit which
351706f2543Smrg                         *        would result in it raising one of its windows.
352706f2543Smrg                         */
353706f2543Smrg                        _appFlags._active = YES;
354706f2543Smrg
355706f2543Smrg                        [self set_front_process:nil];
356706f2543Smrg
357706f2543Smrg                        /* Get the Spaces preference for SwitchOnActivate */
358706f2543Smrg                        (void)CFPreferencesAppSynchronize(CFSTR("com.apple.dock"));
359706f2543Smrg                        workspaces = CFPreferencesGetAppBooleanValue(CFSTR("workspaces"), CFSTR("com.apple.dock"), &ok);
360706f2543Smrg                        if (!ok)
361706f2543Smrg                            workspaces = NO;
362706f2543Smrg
363706f2543Smrg                        if (workspaces) {
364706f2543Smrg                            (void)CFPreferencesAppSynchronize(CFSTR(".GlobalPreferences"));
365706f2543Smrg                            order_all_windows = CFPreferencesGetAppBooleanValue(CFSTR("AppleSpacesSwitchOnActivate"), CFSTR(".GlobalPreferences"), &ok);
366706f2543Smrg                            if (!ok)
367706f2543Smrg                                order_all_windows = YES;
368706f2543Smrg                        }
369706f2543Smrg                        
370706f2543Smrg                        /* TODO: In the workspaces && !AppleSpacesSwitchOnActivate case, the windows are ordered
371706f2543Smrg                         *       correctly, but we need to activate the top window on this space if there is
372706f2543Smrg                         *       none active.
373706f2543Smrg                         *
374706f2543Smrg                         *       If there are no active windows, and there are minimized windows, we should
375706f2543Smrg                         *       be restoring one of them.
376706f2543Smrg                         */
377706f2543Smrg                        if ([e data2] & 0x10) { // 0x10 (bfCPSOrderAllWindowsForward) is set when we use cmd-tab or the dock icon
378706f2543Smrg                            DarwinSendDDXEvent(kXquartzBringAllToFront, 1, order_all_windows);
379706f2543Smrg                        }
380706f2543Smrg                    }
381706f2543Smrg                    break;
382706f2543Smrg                    
383706f2543Smrg                case 18: /* ApplicationDidReactivate */
384706f2543Smrg                    if (XQuartzFullscreenVisible) for_appkit = NO;
385706f2543Smrg                    break;
386706f2543Smrg                    
387706f2543Smrg                case NSApplicationDeactivatedEventType:
388706f2543Smrg                    for_x = NO;
389706f2543Smrg
390706f2543Smrg                    x_was_active = _x_active;
391706f2543Smrg                    if(_x_active)
392706f2543Smrg                        [self activateX:NO];
393706f2543Smrg                    break;
394706f2543Smrg            }
395706f2543Smrg            break;
396706f2543Smrg            
397706f2543Smrg        default: break; /* for gcc */
398706f2543Smrg    }
399706f2543Smrg    
400706f2543Smrg    if (for_appkit) [super sendEvent:e];
401706f2543Smrg    
402706f2543Smrg    if (for_x) [self sendX11NSEvent:e];
403706f2543Smrg}
404706f2543Smrg
405706f2543Smrg- (void) set_window_menu:(NSArray *)list {
406706f2543Smrg	[_controller set_window_menu:list];
407706f2543Smrg}
408706f2543Smrg
409706f2543Smrg- (void) set_window_menu_check:(NSNumber *)n {
410706f2543Smrg	[_controller set_window_menu_check:n];
411706f2543Smrg}
412706f2543Smrg
413706f2543Smrg- (void) set_apps_menu:(NSArray *)list {
414706f2543Smrg	[_controller set_apps_menu:list];
415706f2543Smrg}
416706f2543Smrg
417706f2543Smrg- (void) set_front_process:unused {
418706f2543Smrg	[NSApp activateIgnoringOtherApps:YES];
419706f2543Smrg
420706f2543Smrg	if ([self modalWindow] == nil)
421706f2543Smrg		[self activateX:YES];
422706f2543Smrg}
423706f2543Smrg
424706f2543Smrg- (void) set_can_quit:(NSNumber *)state {
425706f2543Smrg	[_controller set_can_quit:[state boolValue]];
426706f2543Smrg}
427706f2543Smrg
428706f2543Smrg- (void) server_ready:unused {
429706f2543Smrg	[_controller server_ready];
430706f2543Smrg}
431706f2543Smrg
432706f2543Smrg- (void) show_hide_menubar:(NSNumber *)state {
433706f2543Smrg    /* Also shows/hides the dock */
434706f2543Smrg    if ([state boolValue])
435706f2543Smrg        SetSystemUIMode(kUIModeNormal, 0); 
436706f2543Smrg    else
437706f2543Smrg        SetSystemUIMode(kUIModeAllHidden, XQuartzFullscreenMenu ? kUIOptionAutoShowMenuBar : 0); // kUIModeAllSuppressed or kUIOptionAutoShowMenuBar can be used to allow "mouse-activation"
438706f2543Smrg}
439706f2543Smrg
440706f2543Smrg- (void) launch_client:(NSString *)cmd {
441706f2543Smrg    (void)[_controller application:self openFile:cmd];
442706f2543Smrg}
443706f2543Smrg
444706f2543Smrg/* user preferences */
445706f2543Smrg
446706f2543Smrg/* Note that these functions only work for arrays whose elements
447706f2543Smrg can be toll-free-bridged between NS and CF worlds. */
448706f2543Smrg
449706f2543Smrgstatic const void *cfretain (CFAllocatorRef a, const void *b) {
450706f2543Smrg    return CFRetain (b);
451706f2543Smrg}
452706f2543Smrg
453706f2543Smrgstatic void cfrelease (CFAllocatorRef a, const void *b) {
454706f2543Smrg    CFRelease (b);
455706f2543Smrg}
456706f2543Smrg
457706f2543Smrgstatic CFMutableArrayRef nsarray_to_cfarray (NSArray *in) {
458706f2543Smrg	CFMutableArrayRef out;
459706f2543Smrg	CFArrayCallBacks cb;
460706f2543Smrg	NSObject *ns;
461706f2543Smrg	const CFTypeRef *cf;
462706f2543Smrg	int i, count;
463706f2543Smrg
464706f2543Smrg	memset (&cb, 0, sizeof (cb));
465706f2543Smrg	cb.version = 0;
466706f2543Smrg	cb.retain = cfretain;
467706f2543Smrg	cb.release = cfrelease;
468706f2543Smrg
469706f2543Smrg	count = [in count];
470706f2543Smrg	out = CFArrayCreateMutable (NULL, count, &cb);
471706f2543Smrg
472706f2543Smrg	for (i = 0; i < count; i++) {
473706f2543Smrg		ns = [in objectAtIndex:i];
474706f2543Smrg
475706f2543Smrg		if ([ns isKindOfClass:[NSArray class]])
476706f2543Smrg			cf = (CFTypeRef) nsarray_to_cfarray ((NSArray *) ns);
477706f2543Smrg		else
478706f2543Smrg			cf = CFRetain ((CFTypeRef) ns);
479706f2543Smrg
480706f2543Smrg		CFArrayAppendValue (out, cf);
481706f2543Smrg		CFRelease (cf);
482706f2543Smrg	}
483706f2543Smrg
484706f2543Smrg	return out;
485706f2543Smrg}
486706f2543Smrg
487706f2543Smrgstatic NSMutableArray * cfarray_to_nsarray (CFArrayRef in) {
488706f2543Smrg	NSMutableArray *out;
489706f2543Smrg	const CFTypeRef *cf;
490706f2543Smrg	NSObject *ns;
491706f2543Smrg	int i, count;
492706f2543Smrg
493706f2543Smrg	count = CFArrayGetCount (in);
494706f2543Smrg	out = [[NSMutableArray alloc] initWithCapacity:count];
495706f2543Smrg
496706f2543Smrg	for (i = 0; i < count; i++) {
497706f2543Smrg		cf = CFArrayGetValueAtIndex (in, i);
498706f2543Smrg
499706f2543Smrg		if (CFGetTypeID (cf) == CFArrayGetTypeID ())
500706f2543Smrg			ns = cfarray_to_nsarray ((CFArrayRef) cf);
501706f2543Smrg		else
502706f2543Smrg			ns = [(id)cf retain];
503706f2543Smrg
504706f2543Smrg		[out addObject:ns];
505706f2543Smrg		[ns release];
506706f2543Smrg	}
507706f2543Smrg
508706f2543Smrg	return out;
509706f2543Smrg}
510706f2543Smrg
511706f2543Smrg- (CFPropertyListRef) prefs_get_copy:(NSString *)key {
512706f2543Smrg    CFPropertyListRef value;
513706f2543Smrg	
514706f2543Smrg    value = CFPreferencesCopyAppValue ((CFStringRef) key, app_prefs_domain_cfstr);
515706f2543Smrg	
516706f2543Smrg    if (value == NULL) {
517706f2543Smrg      static CFDictionaryRef defaults;
518706f2543Smrg      
519706f2543Smrg      if (defaults == NULL) {
520706f2543Smrg	CFStringRef error = NULL;
521706f2543Smrg	CFDataRef data;
522706f2543Smrg	CFURLRef url;
523706f2543Smrg	SInt32 error_code;
524706f2543Smrg	
525706f2543Smrg	url = (CFURLCreateFromFileSystemRepresentation
526706f2543Smrg	       (NULL, (unsigned char *)DEFAULTS_FILE, strlen (DEFAULTS_FILE), false));
527706f2543Smrg	if (CFURLCreateDataAndPropertiesFromResource (NULL, url, &data,
528706f2543Smrg						      NULL, NULL, &error_code)) {
529706f2543Smrg	  defaults = (CFPropertyListCreateFromXMLData
530706f2543Smrg		      (NULL, data, kCFPropertyListMutableContainersAndLeaves, &error));
531706f2543Smrg	  if (error != NULL) CFRelease (error);
532706f2543Smrg	  CFRelease (data);
533706f2543Smrg	}
534706f2543Smrg	CFRelease (url);
535706f2543Smrg			
536706f2543Smrg	if (defaults != NULL) {
537706f2543Smrg	  NSMutableArray *apps, *elt;
538706f2543Smrg	  int count, i;
539706f2543Smrg	  NSString *name, *nname;
540706f2543Smrg	  
541706f2543Smrg	  /* Localize the names in the default apps menu. */
542706f2543Smrg	  
543706f2543Smrg	  apps = [(NSDictionary *)defaults objectForKey:@PREFS_APPSMENU];
544706f2543Smrg	  if (apps != nil) {
545706f2543Smrg	    count = [apps count];
546706f2543Smrg	    for (i = 0; i < count; i++)	{
547706f2543Smrg	      elt = [apps objectAtIndex:i];
548706f2543Smrg	      if (elt != nil && [elt isKindOfClass:[NSArray class]]) {
549706f2543Smrg		name = [elt objectAtIndex:0];
550706f2543Smrg		if (name != nil) {
551706f2543Smrg		  nname = NSLocalizedString (name, nil);
552706f2543Smrg		  if (nname != nil && nname != name)
553706f2543Smrg		    [elt replaceObjectAtIndex:0 withObject:nname];
554706f2543Smrg		}
555706f2543Smrg	      }
556706f2543Smrg	    }
557706f2543Smrg	  }
558706f2543Smrg	}
559706f2543Smrg      }
560706f2543Smrg		
561706f2543Smrg      if (defaults != NULL) value = CFDictionaryGetValue (defaults, key);
562706f2543Smrg      if (value != NULL) CFRetain (value);
563706f2543Smrg    }
564706f2543Smrg	
565706f2543Smrg    return value;
566706f2543Smrg}
567706f2543Smrg
568706f2543Smrg- (int) prefs_get_integer:(NSString *)key default:(int)def {
569706f2543Smrg  CFPropertyListRef value;
570706f2543Smrg  int ret;
571706f2543Smrg  
572706f2543Smrg  value = [self prefs_get_copy:key];
573706f2543Smrg  
574706f2543Smrg  if (value != NULL && CFGetTypeID (value) == CFNumberGetTypeID ())
575706f2543Smrg    CFNumberGetValue (value, kCFNumberIntType, &ret);
576706f2543Smrg  else if (value != NULL && CFGetTypeID (value) == CFStringGetTypeID ())
577706f2543Smrg    ret = CFStringGetIntValue (value);
578706f2543Smrg  else
579706f2543Smrg    ret = def;
580706f2543Smrg  
581706f2543Smrg  if (value != NULL) CFRelease (value);
582706f2543Smrg  
583706f2543Smrg  return ret;
584706f2543Smrg}
585706f2543Smrg
586706f2543Smrg- (const char *) prefs_get_string:(NSString *)key default:(const char *)def {
587706f2543Smrg  CFPropertyListRef value;
588706f2543Smrg  const char *ret = NULL;
589706f2543Smrg  
590706f2543Smrg  value = [self prefs_get_copy:key];
591706f2543Smrg  
592706f2543Smrg  if (value != NULL && CFGetTypeID (value) == CFStringGetTypeID ()) {
593706f2543Smrg    NSString *s = (NSString *) value;
594706f2543Smrg    
595706f2543Smrg    ret = [s UTF8String];
596706f2543Smrg  }
597706f2543Smrg  
598706f2543Smrg  if (value != NULL) CFRelease (value);
599706f2543Smrg  
600706f2543Smrg  return ret != NULL ? ret : def;
601706f2543Smrg}
602706f2543Smrg
603706f2543Smrg- (NSURL *) prefs_copy_url:(NSString *)key default:(NSURL *)def {
604706f2543Smrg    CFPropertyListRef value;
605706f2543Smrg    NSURL *ret = NULL;
606706f2543Smrg    
607706f2543Smrg    value = [self prefs_get_copy:key];
608706f2543Smrg    
609706f2543Smrg    if (value != NULL && CFGetTypeID (value) == CFStringGetTypeID ()) {
610706f2543Smrg        NSString *s = (NSString *) value;
611706f2543Smrg
612706f2543Smrg        ret = [NSURL URLWithString:s];
613706f2543Smrg        [ret retain];
614706f2543Smrg    }
615706f2543Smrg    
616706f2543Smrg    if (value != NULL) CFRelease (value);
617706f2543Smrg    
618706f2543Smrg    return ret != NULL ? ret : def;
619706f2543Smrg}
620706f2543Smrg
621706f2543Smrg- (float) prefs_get_float:(NSString *)key default:(float)def {
622706f2543Smrg  CFPropertyListRef value;
623706f2543Smrg  float ret = def;
624706f2543Smrg  
625706f2543Smrg  value = [self prefs_get_copy:key];
626706f2543Smrg  
627706f2543Smrg  if (value != NULL
628706f2543Smrg      && CFGetTypeID (value) == CFNumberGetTypeID ()
629706f2543Smrg      && CFNumberIsFloatType (value))
630706f2543Smrg    CFNumberGetValue (value, kCFNumberFloatType, &ret);
631706f2543Smrg  else if (value != NULL && CFGetTypeID (value) == CFStringGetTypeID ())
632706f2543Smrg    ret = CFStringGetDoubleValue (value);
633706f2543Smrg	
634706f2543Smrg  if (value != NULL) CFRelease (value);
635706f2543Smrg  
636706f2543Smrg  return ret;
637706f2543Smrg}
638706f2543Smrg
639706f2543Smrg- (int) prefs_get_boolean:(NSString *)key default:(int)def {
640706f2543Smrg  CFPropertyListRef value;
641706f2543Smrg  int ret = def;
642706f2543Smrg  
643706f2543Smrg  value = [self prefs_get_copy:key];
644706f2543Smrg  
645706f2543Smrg  if (value != NULL) {
646706f2543Smrg    if (CFGetTypeID (value) == CFNumberGetTypeID ())
647706f2543Smrg      CFNumberGetValue (value, kCFNumberIntType, &ret);
648706f2543Smrg    else if (CFGetTypeID (value) == CFBooleanGetTypeID ())
649706f2543Smrg      ret = CFBooleanGetValue (value);
650706f2543Smrg    else if (CFGetTypeID (value) == CFStringGetTypeID ()) {
651706f2543Smrg      const char *tem = [(NSString *) value UTF8String];
652706f2543Smrg      if (strcasecmp (tem, "true") == 0 || strcasecmp (tem, "yes") == 0)
653706f2543Smrg	ret = YES;
654706f2543Smrg      else
655706f2543Smrg	ret = NO;
656706f2543Smrg    }
657706f2543Smrg    
658706f2543Smrg    CFRelease (value);
659706f2543Smrg  }
660706f2543Smrg  return ret;
661706f2543Smrg}
662706f2543Smrg
663706f2543Smrg- (NSArray *) prefs_get_array:(NSString *)key {
664706f2543Smrg  NSArray *ret = nil;
665706f2543Smrg  CFPropertyListRef value;
666706f2543Smrg  
667706f2543Smrg  value = [self prefs_get_copy:key];
668706f2543Smrg  
669706f2543Smrg  if (value != NULL) {
670706f2543Smrg    if (CFGetTypeID (value) == CFArrayGetTypeID ())
671706f2543Smrg      ret = [cfarray_to_nsarray (value) autorelease];
672706f2543Smrg    
673706f2543Smrg    CFRelease (value);
674706f2543Smrg  }
675706f2543Smrg  
676706f2543Smrg  return ret;
677706f2543Smrg}
678706f2543Smrg
679706f2543Smrg- (void) prefs_set_integer:(NSString *)key value:(int)value {
680706f2543Smrg    CFNumberRef x;
681706f2543Smrg	
682706f2543Smrg    x = CFNumberCreate (NULL, kCFNumberIntType, &value);
683706f2543Smrg	
684706f2543Smrg    CFPreferencesSetValue ((CFStringRef) key, (CFTypeRef) x, app_prefs_domain_cfstr,
685706f2543Smrg			   kCFPreferencesCurrentUser, kCFPreferencesAnyHost);
686706f2543Smrg	
687706f2543Smrg    CFRelease (x);
688706f2543Smrg}
689706f2543Smrg
690706f2543Smrg- (void) prefs_set_float:(NSString *)key value:(float)value {
691706f2543Smrg    CFNumberRef x;
692706f2543Smrg	
693706f2543Smrg    x = CFNumberCreate (NULL, kCFNumberFloatType, &value);
694706f2543Smrg	
695706f2543Smrg    CFPreferencesSetValue ((CFStringRef) key, (CFTypeRef) x, app_prefs_domain_cfstr,
696706f2543Smrg			   kCFPreferencesCurrentUser, kCFPreferencesAnyHost);
697706f2543Smrg	
698706f2543Smrg    CFRelease (x);
699706f2543Smrg}
700706f2543Smrg
701706f2543Smrg- (void) prefs_set_boolean:(NSString *)key value:(int)value {
702706f2543Smrg  CFPreferencesSetValue ((CFStringRef) key,
703706f2543Smrg			 (CFTypeRef) (value ? kCFBooleanTrue
704706f2543Smrg			 : kCFBooleanFalse), app_prefs_domain_cfstr,
705706f2543Smrg			 kCFPreferencesCurrentUser, kCFPreferencesAnyHost);
706706f2543Smrg  
707706f2543Smrg}
708706f2543Smrg
709706f2543Smrg- (void) prefs_set_array:(NSString *)key value:(NSArray *)value {
710706f2543Smrg  CFArrayRef cfarray;
711706f2543Smrg  
712706f2543Smrg  cfarray = nsarray_to_cfarray (value);
713706f2543Smrg  CFPreferencesSetValue ((CFStringRef) key,
714706f2543Smrg			 (CFTypeRef) cfarray,
715706f2543Smrg			 app_prefs_domain_cfstr,
716706f2543Smrg			 kCFPreferencesCurrentUser, kCFPreferencesAnyHost);
717706f2543Smrg  CFRelease (cfarray);
718706f2543Smrg}
719706f2543Smrg
720706f2543Smrg- (void) prefs_set_string:(NSString *)key value:(NSString *)value {
721706f2543Smrg  CFPreferencesSetValue ((CFStringRef) key, (CFTypeRef) value,
722706f2543Smrg			 app_prefs_domain_cfstr, kCFPreferencesCurrentUser,
723706f2543Smrg			 kCFPreferencesAnyHost);
724706f2543Smrg}
725706f2543Smrg
726706f2543Smrg- (void) prefs_synchronize {
727706f2543Smrg    CFPreferencesAppSynchronize (kCFPreferencesCurrentApplication);
728706f2543Smrg}
729706f2543Smrg
730706f2543Smrg- (void) read_defaults
731706f2543Smrg{
732706f2543Smrg    NSString *nsstr;
733706f2543Smrg    const char *tem;
734706f2543Smrg	
735706f2543Smrg    XQuartzRootlessDefault = [self prefs_get_boolean:@PREFS_ROOTLESS
736706f2543Smrg                                           default:XQuartzRootlessDefault];
737706f2543Smrg    XQuartzFullscreenMenu = [self prefs_get_boolean:@PREFS_FULLSCREEN_MENU
738706f2543Smrg                                           default:XQuartzFullscreenMenu];
739706f2543Smrg    XQuartzFullscreenDisableHotkeys = ![self prefs_get_boolean:@PREFS_FULLSCREEN_HOTKEYS
740706f2543Smrg                                                      default:!XQuartzFullscreenDisableHotkeys];
741706f2543Smrg    darwinFakeButtons = [self prefs_get_boolean:@PREFS_FAKEBUTTONS
742706f2543Smrg                                        default:darwinFakeButtons];
743706f2543Smrg    XQuartzOptionSendsAlt = [self prefs_get_boolean:@PREFS_OPTION_SENDS_ALT
744706f2543Smrg                                           default:XQuartzOptionSendsAlt];
745706f2543Smrg
746706f2543Smrg    if (darwinFakeButtons) {
747706f2543Smrg        const char *fake2, *fake3;
748706f2543Smrg
749706f2543Smrg        fake2 = [self prefs_get_string:@PREFS_FAKE_BUTTON2 default:NULL];
750706f2543Smrg        fake3 = [self prefs_get_string:@PREFS_FAKE_BUTTON3 default:NULL];
751706f2543Smrg
752706f2543Smrg        if (fake2 != NULL) darwinFakeMouse2Mask = DarwinParseModifierList(fake2, TRUE);
753706f2543Smrg        if (fake3 != NULL) darwinFakeMouse3Mask = DarwinParseModifierList(fake3, TRUE);
754706f2543Smrg    }
755706f2543Smrg
756706f2543Smrg    tem = [self prefs_get_string:@PREFS_APPKIT_MODIFIERS default:NULL];
757706f2543Smrg    if (tem != NULL) darwinAppKitModMask = DarwinParseModifierList(tem, TRUE);
758706f2543Smrg	
759706f2543Smrg    tem = [self prefs_get_string:@PREFS_WINDOW_ITEM_MODIFIERS default:NULL];
760706f2543Smrg    if (tem != NULL) {
761706f2543Smrg        windowItemModMask = DarwinParseModifierList(tem, FALSE);
762706f2543Smrg    } else {
763706f2543Smrg        nsstr = NSLocalizedString (@"window item modifiers", @"window item modifiers");
764706f2543Smrg        if(nsstr != NULL) {
765706f2543Smrg            tem = [nsstr UTF8String];
766706f2543Smrg            if((tem != NULL) && strcmp(tem, "window item modifiers")) {
767706f2543Smrg                windowItemModMask = DarwinParseModifierList(tem, FALSE);
768706f2543Smrg            }
769706f2543Smrg        }
770706f2543Smrg    }
771706f2543Smrg
772706f2543Smrg    XQuartzEnableKeyEquivalents = [self prefs_get_boolean:@PREFS_KEYEQUIVS
773706f2543Smrg                                              default:XQuartzEnableKeyEquivalents];
774706f2543Smrg	
775706f2543Smrg    darwinSyncKeymap = [self prefs_get_boolean:@PREFS_SYNC_KEYMAP
776706f2543Smrg                                       default:darwinSyncKeymap];
777706f2543Smrg		
778706f2543Smrg    darwinDesiredDepth = [self prefs_get_integer:@PREFS_DEPTH
779706f2543Smrg                                         default:darwinDesiredDepth];
780706f2543Smrg    
781706f2543Smrg    noTestExtensions = ![self prefs_get_boolean:@PREFS_TEST_EXTENSIONS
782706f2543Smrg                                        default:FALSE];
783706f2543Smrg    
784706f2543Smrg    XQuartzScrollInDeviceDirection = [self prefs_get_boolean:@PREFS_SCROLL_IN_DEV_DIRECTION
785706f2543Smrg                                                     default:XQuartzScrollInDeviceDirection];
786706f2543Smrg
787706f2543Smrg#if XQUARTZ_SPARKLE
788706f2543Smrg    NSURL *url =  [self prefs_copy_url:@PREFS_UPDATE_FEED default:nil];
789706f2543Smrg    if(url) {
790706f2543Smrg        [[SUUpdater sharedUpdater] setFeedURL:url];
791706f2543Smrg        [url release];
792706f2543Smrg    }
793706f2543Smrg#endif
794706f2543Smrg}
795706f2543Smrg
796706f2543Smrg/* This will end up at the end of the responder chain. */
797706f2543Smrg- (void) copy:sender {
798706f2543Smrg  DarwinSendDDXEvent(kXquartzPasteboardNotify, 1,
799706f2543Smrg			     AppleWMCopyToPasteboard);
800706f2543Smrg}
801706f2543Smrg
802706f2543Smrg- (X11Controller *) controller {
803706f2543Smrg    return _controller;
804706f2543Smrg}
805706f2543Smrg
806706f2543Smrg- (OSX_BOOL) x_active {
807706f2543Smrg    return _x_active;
808706f2543Smrg}
809706f2543Smrg
810706f2543Smrg@end
811706f2543Smrg
812706f2543Smrgstatic NSArray *
813706f2543Smrgarray_with_strings_and_numbers (int nitems, const char **items,
814706f2543Smrg				const char *numbers) {
815706f2543Smrg  NSMutableArray *array, *subarray;
816706f2543Smrg  NSString *string, *number;
817706f2543Smrg  int i;
818706f2543Smrg	
819706f2543Smrg  /* (Can't autorelease on the X server thread) */
820706f2543Smrg  
821706f2543Smrg  array = [[NSMutableArray alloc] initWithCapacity:nitems];
822706f2543Smrg  
823706f2543Smrg  for (i = 0; i < nitems; i++) {
824706f2543Smrg    subarray = [[NSMutableArray alloc] initWithCapacity:2];
825706f2543Smrg    
826706f2543Smrg    string = [[NSString alloc] initWithUTF8String:items[i]];
827706f2543Smrg    [subarray addObject:string];
828706f2543Smrg    [string release];
829706f2543Smrg    
830706f2543Smrg    if (numbers[i] != 0) {
831706f2543Smrg      number = [[NSString alloc] initWithFormat:@"%d", numbers[i]];
832706f2543Smrg      [subarray addObject:number];
833706f2543Smrg      [number release];
834706f2543Smrg    } else
835706f2543Smrg      [subarray addObject:@""];
836706f2543Smrg    
837706f2543Smrg    [array addObject:subarray];
838706f2543Smrg    [subarray release];
839706f2543Smrg  }
840706f2543Smrg  
841706f2543Smrg  return array;
842706f2543Smrg}
843706f2543Smrg
844706f2543Smrgvoid X11ApplicationSetWindowMenu (int nitems, const char **items,
845706f2543Smrg				  const char *shortcuts) {
846706f2543Smrg  NSArray *array;
847706f2543Smrg  array = array_with_strings_and_numbers (nitems, items, shortcuts);
848706f2543Smrg  
849706f2543Smrg  /* Send the array of strings over to the appkit thread */
850706f2543Smrg  
851706f2543Smrg  message_kit_thread (@selector (set_window_menu:), array);
852706f2543Smrg  [array release];
853706f2543Smrg}
854706f2543Smrg
855706f2543Smrgvoid X11ApplicationSetWindowMenuCheck (int idx) {
856706f2543Smrg  NSNumber *n;
857706f2543Smrg  
858706f2543Smrg  n = [[NSNumber alloc] initWithInt:idx];
859706f2543Smrg  
860706f2543Smrg  message_kit_thread (@selector (set_window_menu_check:), n);
861706f2543Smrg  
862706f2543Smrg  [n release];
863706f2543Smrg}
864706f2543Smrg
865706f2543Smrgvoid X11ApplicationSetFrontProcess (void) {
866706f2543Smrg    message_kit_thread (@selector (set_front_process:), nil);
867706f2543Smrg}
868706f2543Smrg
869706f2543Smrgvoid X11ApplicationSetCanQuit (int state) {
870706f2543Smrg    NSNumber *n;
871706f2543Smrg	
872706f2543Smrg    n = [[NSNumber alloc] initWithBool:state];
873706f2543Smrg	
874706f2543Smrg    message_kit_thread (@selector (set_can_quit:), n);
875706f2543Smrg	
876706f2543Smrg    [n release];
877706f2543Smrg}
878706f2543Smrg
879706f2543Smrgvoid X11ApplicationServerReady (void) {
880706f2543Smrg    message_kit_thread (@selector (server_ready:), nil);
881706f2543Smrg}
882706f2543Smrg
883706f2543Smrgvoid X11ApplicationShowHideMenubar (int state) {
884706f2543Smrg    NSNumber *n;
885706f2543Smrg	
886706f2543Smrg    n = [[NSNumber alloc] initWithBool:state];
887706f2543Smrg	
888706f2543Smrg    message_kit_thread (@selector (show_hide_menubar:), n);
889706f2543Smrg	
890706f2543Smrg    [n release];
891706f2543Smrg}
892706f2543Smrg
893706f2543Smrgvoid X11ApplicationLaunchClient (const char *cmd) {
894706f2543Smrg    NSString *string;
895706f2543Smrg    
896706f2543Smrg    string = [[NSString alloc] initWithUTF8String:cmd];
897706f2543Smrg	
898706f2543Smrg    message_kit_thread (@selector (launch_client:), string);
899706f2543Smrg	
900706f2543Smrg    [string release];
901706f2543Smrg}
902706f2543Smrg
903706f2543Smrg/* This is a special function in that it is run from the *SERVER* thread and
904706f2543Smrg * not the AppKit thread.  We want to block entering a screen-capturing RandR
905706f2543Smrg * mode until we notify the user about how to get out if the X11 client crashes.
906706f2543Smrg */
907706f2543SmrgBool X11ApplicationCanEnterRandR(void) {
908706f2543Smrg    NSString *title, *msg;
909706f2543Smrg    
910706f2543Smrg    if([X11App prefs_get_boolean:@PREFS_NO_RANDR_ALERT default:NO] || XQuartzShieldingWindowLevel != 0)
911706f2543Smrg        return TRUE;
912706f2543Smrg    
913706f2543Smrg    title = NSLocalizedString(@"Enter RandR mode?", @"Dialog title when switching to RandR");
914706f2543Smrg    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.",
915706f2543Smrg                            @"Dialog when switching to RandR");
916706f2543Smrg
917706f2543Smrg    if(!XQuartzIsRootless)
918706f2543Smrg        QuartzShowFullscreen(FALSE);
919706f2543Smrg    
920706f2543Smrg    switch(NSRunAlertPanel(title, msg, NSLocalizedString(@"Allow", @""), NSLocalizedString (@"Cancel", @""), NSLocalizedString (@"Always Allow", @""))) {
921706f2543Smrg        case NSAlertOtherReturn:
922706f2543Smrg            [X11App prefs_set_boolean:@PREFS_NO_RANDR_ALERT value:YES];
923706f2543Smrg            [X11App prefs_synchronize];
924706f2543Smrg        case NSAlertDefaultReturn:
925706f2543Smrg            return YES;
926706f2543Smrg
927706f2543Smrg        default:
928706f2543Smrg            return NO;
929706f2543Smrg    }
930706f2543Smrg}
931706f2543Smrg
932706f2543Smrgstatic void check_xinitrc (void) {
933706f2543Smrg    char *tem, buf[1024];
934706f2543Smrg    NSString *msg;
935706f2543Smrg	
936706f2543Smrg    if ([X11App prefs_get_boolean:@PREFS_DONE_XINIT_CHECK default:NO])
937706f2543Smrg		return;
938706f2543Smrg	
939706f2543Smrg    tem = getenv ("HOME");
940706f2543Smrg    if (tem == NULL) goto done;
941706f2543Smrg	
942706f2543Smrg    snprintf (buf, sizeof (buf), "%s/.xinitrc", tem);
943706f2543Smrg    if (access (buf, F_OK) != 0)
944706f2543Smrg		goto done;
945706f2543Smrg	
946706f2543Smrg    msg = NSLocalizedString (@"You have an existing ~/.xinitrc file.\n\n\
947706f2543SmrgWindows displayed by X11 applications may not have titlebars, or may look \
948706f2543Smrgdifferent to windows displayed by native applications.\n\n\
949706f2543SmrgWould you like to move aside the existing file and use the standard X11 \
950706f2543Smrgenvironment the next time you start X11?", @"Startup xinitrc dialog");
951706f2543Smrg
952706f2543Smrg    if(NSAlertDefaultReturn == NSRunAlertPanel (nil, msg, NSLocalizedString (@"Yes", @""),
953706f2543Smrg                                                NSLocalizedString (@"No", @""), nil)) {
954706f2543Smrg        char buf2[1024];
955706f2543Smrg        int i = -1;
956706f2543Smrg      
957706f2543Smrg        snprintf (buf2, sizeof (buf2), "%s.old", buf);
958706f2543Smrg      
959706f2543Smrg        for(i = 1; access (buf2, F_OK) == 0; i++)
960706f2543Smrg            snprintf (buf2, sizeof (buf2), "%s.old.%d", buf, i);
961706f2543Smrg
962706f2543Smrg        rename (buf, buf2);
963706f2543Smrg    }
964706f2543Smrg    
965706f2543Smrg done:
966706f2543Smrg    [X11App prefs_set_boolean:@PREFS_DONE_XINIT_CHECK value:YES];
967706f2543Smrg    [X11App prefs_synchronize];
968706f2543Smrg}
969706f2543Smrg
970706f2543Smrgstatic inline pthread_t create_thread(void *(*func)(void *), void *arg) {
971706f2543Smrg    pthread_attr_t attr;
972706f2543Smrg    pthread_t tid;
973706f2543Smrg    
974706f2543Smrg    pthread_attr_init(&attr);
975706f2543Smrg    pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM);
976706f2543Smrg    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
977706f2543Smrg    pthread_create(&tid, &attr, func, arg);
978706f2543Smrg    pthread_attr_destroy(&attr);
979706f2543Smrg    
980706f2543Smrg    return tid;
981706f2543Smrg}
982706f2543Smrg
983706f2543Smrgstatic void *xpbproxy_x_thread(void *args) {
984706f2543Smrg    xpbproxy_run();
985706f2543Smrg
986706f2543Smrg    fprintf(stderr, "xpbproxy thread is terminating unexpectedly.\n");
987706f2543Smrg    return NULL;
988706f2543Smrg}
989706f2543Smrg
990706f2543Smrgvoid X11ApplicationMain (int argc, char **argv, char **envp) {
991706f2543Smrg    NSAutoreleasePool *pool;
992706f2543Smrg
993706f2543Smrg#ifdef DEBUG
994706f2543Smrg    while (access ("/tmp/x11-block", F_OK) == 0) sleep (1);
995706f2543Smrg#endif
996706f2543Smrg  
997706f2543Smrg    pool = [[NSAutoreleasePool alloc] init];
998706f2543Smrg    X11App = (X11Application *) [X11Application sharedApplication];
999706f2543Smrg    init_ports ();
1000706f2543Smrg    
1001706f2543Smrg    app_prefs_domain_cfstr = (CFStringRef)[[NSBundle mainBundle] bundleIdentifier];
1002706f2543Smrg
1003706f2543Smrg    if (app_prefs_domain_cfstr == NULL) {
1004706f2543Smrg        ErrorF("X11ApplicationMain: Unable to determine bundle identifier.  Your installation of XQuartz may be broken.\n");
1005706f2543Smrg        app_prefs_domain_cfstr = CFSTR(LAUNCHD_ID_PREFIX".X11");
1006706f2543Smrg    }
1007706f2543Smrg
1008706f2543Smrg    [NSApp read_defaults];
1009706f2543Smrg    [NSBundle loadNibNamed:@"main" owner:NSApp];
1010706f2543Smrg    [[NSNotificationCenter defaultCenter] addObserver:NSApp
1011706f2543Smrg					selector:@selector (became_key:)
1012706f2543Smrg					name:NSWindowDidBecomeKeyNotification object:nil];
1013706f2543Smrg
1014706f2543Smrg    /*
1015706f2543Smrg     * The xpr Quartz mode is statically linked into this server.
1016706f2543Smrg     * Initialize all the Quartz functions.
1017706f2543Smrg     */
1018706f2543Smrg    QuartzModeBundleInit();
1019706f2543Smrg
1020706f2543Smrg    /* Calculate the height of the menubar so we can avoid it. */
1021706f2543Smrg    aquaMenuBarHeight = NSHeight([[NSScreen mainScreen] frame]) -
1022706f2543Smrg    NSMaxY([[NSScreen mainScreen] visibleFrame]);
1023706f2543Smrg
1024706f2543Smrg    /* Set the key layout seed before we start the server */
1025706f2543Smrg#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1050
1026706f2543Smrg    last_key_layout = TISCopyCurrentKeyboardLayoutInputSource();    
1027706f2543Smrg
1028706f2543Smrg    if(!last_key_layout)
1029706f2543Smrg        fprintf(stderr, "X11ApplicationMain: Unable to determine TISCopyCurrentKeyboardLayoutInputSource() at startup.\n");
1030706f2543Smrg#else
1031706f2543Smrg    KLGetCurrentKeyboardLayout(&last_key_layout);
1032706f2543Smrg    if(!last_key_layout)
1033706f2543Smrg        fprintf(stderr, "X11ApplicationMain: Unable to determine KLGetCurrentKeyboardLayout() at startup.\n");
1034706f2543Smrg#endif
1035706f2543Smrg
1036706f2543Smrg    if (!QuartsResyncKeymap(FALSE)) {
1037706f2543Smrg        fprintf(stderr, "X11ApplicationMain: Could not build a valid keymap.\n");
1038706f2543Smrg    }
1039706f2543Smrg
1040706f2543Smrg    /* Tell the server thread that it can proceed */
1041706f2543Smrg    QuartzInitServer(argc, argv, envp);
1042706f2543Smrg    
1043706f2543Smrg    /* This must be done after QuartzInitServer because it can result in
1044706f2543Smrg     * an mieqEnqueue() - <rdar://problem/6300249>
1045706f2543Smrg     */
1046706f2543Smrg    check_xinitrc();
1047706f2543Smrg    
1048706f2543Smrg    create_thread(xpbproxy_x_thread, NULL);
1049706f2543Smrg
1050706f2543Smrg#if XQUARTZ_SPARKLE
1051706f2543Smrg    [[X11App controller] setup_sparkle];
1052706f2543Smrg    [[SUUpdater sharedUpdater] resetUpdateCycle];
1053706f2543Smrg//    [[SUUpdater sharedUpdater] checkForUpdates:X11App];
1054706f2543Smrg#endif
1055706f2543Smrg
1056706f2543Smrg    [pool release];
1057706f2543Smrg    [NSApp run];
1058706f2543Smrg    /* not reached */
1059706f2543Smrg}
1060706f2543Smrg
1061706f2543Smrg@implementation X11Application (Private)
1062706f2543Smrg
1063706f2543Smrg#ifdef NX_DEVICELCMDKEYMASK
1064706f2543Smrg/* This is to workaround a bug in the VNC server where we sometimes see the L
1065706f2543Smrg * modifier and sometimes see no "side"
1066706f2543Smrg */
1067706f2543Smrgstatic inline int ensure_flag(int flags, int device_independent, int device_dependents, int device_dependent_default) {
1068706f2543Smrg    if( (flags & device_independent) &&
1069706f2543Smrg       !(flags & device_dependents))
1070706f2543Smrg        flags |= device_dependent_default;
1071706f2543Smrg    return flags;
1072706f2543Smrg}
1073706f2543Smrg#endif
1074706f2543Smrg
1075706f2543Smrg#ifdef DEBUG_UNTRUSTED_POINTER_DELTA
1076706f2543Smrgstatic const char *untrusted_str(NSEvent *e) {
1077706f2543Smrg    switch([e type]) {
1078706f2543Smrg        case NSScrollWheel:
1079706f2543Smrg            return "NSScrollWheel";
1080706f2543Smrg        case NSTabletPoint:
1081706f2543Smrg            return "NSTabletPoint";
1082706f2543Smrg        case NSOtherMouseDown:
1083706f2543Smrg            return "NSOtherMouseDown";
1084706f2543Smrg        case NSOtherMouseUp:
1085706f2543Smrg            return "NSOtherMouseUp";
1086706f2543Smrg        case NSLeftMouseDown:
1087706f2543Smrg            return "NSLeftMouseDown";
1088706f2543Smrg        case NSLeftMouseUp:
1089706f2543Smrg            return "NSLeftMouseUp";
1090706f2543Smrg        default:
1091706f2543Smrg            switch([e subtype]) {
1092706f2543Smrg                case NSTabletPointEventSubtype:
1093706f2543Smrg                    return "NSTabletPointEventSubtype";
1094706f2543Smrg                case NSTabletProximityEventSubtype:
1095706f2543Smrg                    return "NSTabletProximityEventSubtype";
1096706f2543Smrg                default:
1097706f2543Smrg                    return "Other";
1098706f2543Smrg            }
1099706f2543Smrg    }
1100706f2543Smrg}
1101706f2543Smrg#endif
1102706f2543Smrg
1103706f2543Smrg- (void) sendX11NSEvent:(NSEvent *)e {
1104706f2543Smrg    NSPoint location = NSZeroPoint, tilt = NSZeroPoint;
1105706f2543Smrg    int ev_button, ev_type;
1106706f2543Smrg    float pressure = 0.0;
1107706f2543Smrg    DeviceIntPtr pDev;
1108706f2543Smrg    int modifierFlags;
1109706f2543Smrg    BOOL isMouseOrTabletEvent, isTabletEvent;
1110706f2543Smrg
1111706f2543Smrg    isMouseOrTabletEvent =  [e type] == NSLeftMouseDown    ||  [e type] == NSOtherMouseDown    ||  [e type] == NSRightMouseDown    ||
1112706f2543Smrg                            [e type] == NSLeftMouseUp      ||  [e type] == NSOtherMouseUp      ||  [e type] == NSRightMouseUp      ||
1113706f2543Smrg                            [e type] == NSLeftMouseDragged ||  [e type] == NSOtherMouseDragged ||  [e type] == NSRightMouseDragged ||
1114706f2543Smrg                            [e type] == NSMouseMoved       ||  [e type] == NSTabletPoint       ||  [e type] == NSScrollWheel;
1115706f2543Smrg
1116706f2543Smrg    isTabletEvent = ([e type] == NSTabletPoint) ||
1117706f2543Smrg                    (isMouseOrTabletEvent && ([e subtype] == NSTabletPointEventSubtype || [e subtype] == NSTabletProximityEventSubtype));
1118706f2543Smrg
1119706f2543Smrg    if(isMouseOrTabletEvent) {
1120706f2543Smrg        static NSPoint lastpt;
1121706f2543Smrg        NSWindow *window = [e window];
1122706f2543Smrg        NSRect screen = [[[NSScreen screens] objectAtIndex:0] frame];
1123706f2543Smrg	    BOOL hasUntrustedPointerDelta;
1124706f2543Smrg        
1125706f2543Smrg        // NSEvents for tablets are not consistent wrt deltaXY between events, so we cannot rely on that
1126706f2543Smrg        // Thus tablets will be subject to the warp-pointer bug worked around by the delta, but tablets
1127706f2543Smrg        // are not normally used in cases where that bug would present itself, so this is a fair tradeoff
1128706f2543Smrg        // <rdar://problem/7111003> deltaX and deltaY are incorrect for NSMouseMoved, NSTabletPointEventSubtype
1129706f2543Smrg        // http://xquartz.macosforge.org/trac/ticket/288
1130706f2543Smrg        hasUntrustedPointerDelta = isTabletEvent;
1131706f2543Smrg        
1132706f2543Smrg        // The deltaXY for middle click events also appear erroneous after fast user switching
1133706f2543Smrg        // <rdar://problem/7979468> deltaX and deltaY are incorrect for NSOtherMouseDown and NSOtherMouseUp after FUS
1134706f2543Smrg        // http://xquartz.macosforge.org/trac/ticket/389
1135706f2543Smrg        hasUntrustedPointerDelta = hasUntrustedPointerDelta || [e type] == NSOtherMouseDown || [e type] == NSOtherMouseUp;
1136706f2543Smrg
1137706f2543Smrg        // The deltaXY for scroll events correspond to the scroll delta, not the pointer delta
1138706f2543Smrg        // <rdar://problem/7989690> deltaXY for wheel events are being sent as mouse movement
1139706f2543Smrg        hasUntrustedPointerDelta = hasUntrustedPointerDelta || [e type] == NSScrollWheel;
1140706f2543Smrg
1141706f2543Smrg#ifdef DEBUG_UNTRUSTED_POINTER_DELTA
1142706f2543Smrg        hasUntrustedPointerDelta = hasUntrustedPointerDelta || [e type] == NSLeftMouseDown || [e type] == NSLeftMouseUp;
1143706f2543Smrg#endif
1144706f2543Smrg        
1145706f2543Smrg        if (window != nil)	{
1146706f2543Smrg            NSRect frame = [window frame];
1147706f2543Smrg            location = [e locationInWindow];
1148706f2543Smrg            location.x += frame.origin.x;
1149706f2543Smrg            location.y += frame.origin.y;
1150706f2543Smrg            lastpt = location;
1151706f2543Smrg        } else if(hasUntrustedPointerDelta) {
1152706f2543Smrg#ifdef DEBUG_UNTRUSTED_POINTER_DELTA
1153706f2543Smrg            ErrorF("--- Begin Event Debug ---\n");
1154706f2543Smrg            ErrorF("Event type: %s\n", untrusted_str(e));
1155706f2543Smrg            ErrorF("old lastpt: (%0.2f, %0.2f)\n", lastpt.x, lastpt.y);
1156706f2543Smrg            ErrorF("     delta: (%0.2f, %0.2f)\n", [e deltaX], -[e deltaY]);
1157706f2543Smrg            ErrorF("  location: (%0.2f, %0.2f)\n", lastpt.x + [e deltaX], lastpt.y - [e deltaY]);
1158706f2543Smrg            ErrorF("workaround: (%0.2f, %0.2f)\n", [e locationInWindow].x, [e locationInWindow].y);
1159706f2543Smrg            ErrorF("--- End Event Debug ---\n");
1160706f2543Smrg
1161706f2543Smrg            location.x = lastpt.x + [e deltaX];
1162706f2543Smrg            location.y = lastpt.y - [e deltaY];
1163706f2543Smrg            lastpt = [e locationInWindow];
1164706f2543Smrg#else
1165706f2543Smrg            location = [e locationInWindow];
1166706f2543Smrg            lastpt = location;
1167706f2543Smrg#endif
1168706f2543Smrg        } else {
1169706f2543Smrg            location.x = lastpt.x + [e deltaX];
1170706f2543Smrg            location.y = lastpt.y - [e deltaY];
1171706f2543Smrg            lastpt = [e locationInWindow];
1172706f2543Smrg        }
1173706f2543Smrg        
1174706f2543Smrg        /* Convert coordinate system */
1175706f2543Smrg        location.y = (screen.origin.y + screen.size.height) - location.y;
1176706f2543Smrg    }
1177706f2543Smrg    
1178706f2543Smrg    modifierFlags = [e modifierFlags];
1179706f2543Smrg    
1180706f2543Smrg#ifdef NX_DEVICELCMDKEYMASK
1181706f2543Smrg    /* This is to workaround a bug in the VNC server where we sometimes see the L
1182706f2543Smrg     * modifier and sometimes see no "side"
1183706f2543Smrg     */
1184706f2543Smrg    modifierFlags = ensure_flag(modifierFlags, NX_CONTROLMASK,   NX_DEVICELCTLKEYMASK   | NX_DEVICERCTLKEYMASK,     NX_DEVICELCTLKEYMASK);
1185706f2543Smrg    modifierFlags = ensure_flag(modifierFlags, NX_SHIFTMASK,     NX_DEVICELSHIFTKEYMASK | NX_DEVICERSHIFTKEYMASK,   NX_DEVICELSHIFTKEYMASK);
1186706f2543Smrg    modifierFlags = ensure_flag(modifierFlags, NX_COMMANDMASK,   NX_DEVICELCMDKEYMASK   | NX_DEVICERCMDKEYMASK,     NX_DEVICELCMDKEYMASK);
1187706f2543Smrg    modifierFlags = ensure_flag(modifierFlags, NX_ALTERNATEMASK, NX_DEVICELALTKEYMASK   | NX_DEVICERALTKEYMASK,     NX_DEVICELALTKEYMASK);
1188706f2543Smrg#endif
1189706f2543Smrg
1190706f2543Smrg    modifierFlags &= darwin_all_modifier_mask;
1191706f2543Smrg
1192706f2543Smrg    /* We don't receive modifier key events while out of focus, and 3button
1193706f2543Smrg     * emulation mucks this up, so we need to check our modifier flag state
1194706f2543Smrg     * on every event... ugg
1195706f2543Smrg     */
1196706f2543Smrg    
1197706f2543Smrg    if(darwin_all_modifier_flags != modifierFlags)
1198706f2543Smrg        DarwinUpdateModKeys(modifierFlags);
1199706f2543Smrg    
1200706f2543Smrg	switch ([e type]) {
1201706f2543Smrg		case NSLeftMouseDown:     ev_button=1; ev_type=ButtonPress;   goto handle_mouse;
1202706f2543Smrg		case NSOtherMouseDown:    ev_button=2; ev_type=ButtonPress;   goto handle_mouse;
1203706f2543Smrg		case NSRightMouseDown:    ev_button=3; ev_type=ButtonPress;   goto handle_mouse;
1204706f2543Smrg		case NSLeftMouseUp:       ev_button=1; ev_type=ButtonRelease; goto handle_mouse;
1205706f2543Smrg		case NSOtherMouseUp:      ev_button=2; ev_type=ButtonRelease; goto handle_mouse;
1206706f2543Smrg		case NSRightMouseUp:      ev_button=3; ev_type=ButtonRelease; goto handle_mouse;
1207706f2543Smrg		case NSLeftMouseDragged:  ev_button=1; ev_type=MotionNotify;  goto handle_mouse;
1208706f2543Smrg		case NSOtherMouseDragged: ev_button=2; ev_type=MotionNotify;  goto handle_mouse;
1209706f2543Smrg		case NSRightMouseDragged: ev_button=3; ev_type=MotionNotify;  goto handle_mouse;
1210706f2543Smrg		case NSMouseMoved:        ev_button=0; ev_type=MotionNotify;  goto handle_mouse;
1211706f2543Smrg        case NSTabletPoint:       ev_button=0; ev_type=MotionNotify;  goto handle_mouse;
1212706f2543Smrg            
1213706f2543Smrg        handle_mouse:
1214706f2543Smrg            pDev = darwinPointer;
1215706f2543Smrg
1216706f2543Smrg            /* NSTabletPoint can have no subtype */
1217706f2543Smrg            if([e type] != NSTabletPoint &&
1218706f2543Smrg               [e subtype] == NSTabletProximityEventSubtype) {
1219706f2543Smrg                switch([e pointingDeviceType]) {
1220706f2543Smrg                    case NSEraserPointingDevice:
1221706f2543Smrg                        darwinTabletCurrent=darwinTabletEraser;
1222706f2543Smrg                        break;
1223706f2543Smrg                    case NSPenPointingDevice:
1224706f2543Smrg                        darwinTabletCurrent=darwinTabletStylus;
1225706f2543Smrg                        break;
1226706f2543Smrg                    case NSCursorPointingDevice:
1227706f2543Smrg                    case NSUnknownPointingDevice:
1228706f2543Smrg                    default:
1229706f2543Smrg                        darwinTabletCurrent=darwinTabletCursor;
1230706f2543Smrg                        break;
1231706f2543Smrg                }
1232706f2543Smrg                
1233706f2543Smrg                /* NSTabletProximityEventSubtype doesn't encode pressure ant tilt
1234706f2543Smrg                 * So we just pretend the motion was caused by the mouse.  Hopefully
1235706f2543Smrg                 * we'll have a better solution for this in the future (like maybe
1236706f2543Smrg                 * NSTabletProximityEventSubtype will come from NSTabletPoint
1237706f2543Smrg                 * rather than NSMouseMoved.
1238706f2543Smrg                pressure = [e pressure];
1239706f2543Smrg                tilt     = [e tilt];
1240706f2543Smrg                pDev = darwinTabletCurrent;                
1241706f2543Smrg                 */
1242706f2543Smrg
1243706f2543Smrg                DarwinSendProximityEvents([e isEnteringProximity] ? ProximityIn : ProximityOut,
1244706f2543Smrg                                          location.x, location.y);
1245706f2543Smrg            }
1246706f2543Smrg
1247706f2543Smrg			if ([e type] == NSTabletPoint || [e subtype] == NSTabletPointEventSubtype) {
1248706f2543Smrg                pressure = [e pressure];
1249706f2543Smrg                tilt     = [e tilt];
1250706f2543Smrg                
1251706f2543Smrg                pDev = darwinTabletCurrent;
1252706f2543Smrg            }
1253706f2543Smrg
1254706f2543Smrg            if(!XQuartzServerVisible && noTestExtensions) {
1255706f2543Smrg#if defined(XPLUGIN_VERSION) && XPLUGIN_VERSION > 0
1256706f2543Smrg/* Older libXplugin (Tiger/"Stock" Leopard) aren't thread safe, so we can't call xp_find_window from the Appkit thread */
1257706f2543Smrg                xp_window_id wid = 0;
1258706f2543Smrg                xp_error e;
1259706f2543Smrg
1260706f2543Smrg                /* Sigh. Need to check that we're really over one of
1261706f2543Smrg                 * our windows. (We need to receive pointer events while
1262706f2543Smrg                 * not in the foreground, but we don't want to receive them
1263706f2543Smrg                 * when another window is over us or we might show a tooltip)
1264706f2543Smrg                 */
1265706f2543Smrg
1266706f2543Smrg                e = xp_find_window(location.x, location.y, 0, &wid);
1267706f2543Smrg
1268706f2543Smrg                if (e != XP_Success || (e == XP_Success && wid == 0))
1269706f2543Smrg#endif
1270706f2543Smrg                {
1271706f2543Smrg                    bgMouseLocation = location;
1272706f2543Smrg                    bgMouseLocationUpdated = TRUE;
1273706f2543Smrg                    return;
1274706f2543Smrg                }
1275706f2543Smrg            }
1276706f2543Smrg            
1277706f2543Smrg            if(bgMouseLocationUpdated) {
1278706f2543Smrg                if(!(ev_type == MotionNotify && ev_button == 0)) {
1279706f2543Smrg                    DarwinSendPointerEvents(pDev, MotionNotify, 0, location.x,
1280706f2543Smrg                                            location.y, pressure, tilt.x, tilt.y);
1281706f2543Smrg                }
1282706f2543Smrg                bgMouseLocationUpdated = FALSE;
1283706f2543Smrg            }
1284706f2543Smrg
1285706f2543Smrg            DarwinSendPointerEvents(pDev, ev_type, ev_button, location.x, location.y,
1286706f2543Smrg                                    pressure, tilt.x, tilt.y);
1287706f2543Smrg            
1288706f2543Smrg            break;
1289706f2543Smrg            
1290706f2543Smrg		case NSTabletProximity:
1291706f2543Smrg            switch([e pointingDeviceType]) {
1292706f2543Smrg                case NSEraserPointingDevice:
1293706f2543Smrg                    darwinTabletCurrent=darwinTabletEraser;
1294706f2543Smrg                    break;
1295706f2543Smrg                case NSPenPointingDevice:
1296706f2543Smrg                    darwinTabletCurrent=darwinTabletStylus;
1297706f2543Smrg                    break;
1298706f2543Smrg                case NSCursorPointingDevice:
1299706f2543Smrg                case NSUnknownPointingDevice:
1300706f2543Smrg                default:
1301706f2543Smrg                    darwinTabletCurrent=darwinTabletCursor;
1302706f2543Smrg                    break;
1303706f2543Smrg            }
1304706f2543Smrg            
1305706f2543Smrg			DarwinSendProximityEvents([e isEnteringProximity] ? ProximityIn : ProximityOut,
1306706f2543Smrg                                      location.x, location.y);
1307706f2543Smrg            break;
1308706f2543Smrg            
1309706f2543Smrg		case NSScrollWheel:
1310706f2543Smrg            {
1311706f2543Smrg                float deltaX = [e deltaX];
1312706f2543Smrg                float deltaY = [e deltaY];
1313706f2543Smrg#if !defined(XPLUGIN_VERSION) || XPLUGIN_VERSION == 0
1314706f2543Smrg                /* If we're in the background, we need to send a MotionNotify event
1315706f2543Smrg                * first, since we aren't getting them on background mouse motion
1316706f2543Smrg                */
1317706f2543Smrg                if(!XQuartzServerVisible && noTestExtensions) {
1318706f2543Smrg                    bgMouseLocationUpdated = FALSE;
1319706f2543Smrg                    DarwinSendPointerEvents(darwinPointer, MotionNotify, 0, location.x,
1320706f2543Smrg                                            location.y, pressure, tilt.x, tilt.y);
1321706f2543Smrg                }
1322706f2543Smrg#endif
1323706f2543Smrg#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
1324706f2543Smrg                // TODO: Change 1117 to NSAppKitVersionNumber10_7 when it is defined
1325706f2543Smrg                if(NSAppKitVersionNumber >= 1117 && XQuartzScrollInDeviceDirection && [e isDirectionInvertedFromDevice]) {
1326706f2543Smrg                    deltaX *= -1;
1327706f2543Smrg                    deltaY *= -1;
1328706f2543Smrg                }
1329706f2543Smrg#endif
1330706f2543Smrg                DarwinSendScrollEvents(deltaX, deltaY, location.x, location.y,
1331706f2543Smrg                                       pressure, tilt.x, tilt.y);
1332706f2543Smrg                break;
1333706f2543Smrg            }
1334706f2543Smrg        case NSKeyDown: case NSKeyUp:
1335706f2543Smrg            {
1336706f2543Smrg                /* XKB clobbers our keymap at startup, so we need to force it on the first keypress.
1337706f2543Smrg                 * TODO: Make this less of a kludge.
1338706f2543Smrg                 */
1339706f2543Smrg                static int force_resync_keymap = YES;
1340706f2543Smrg                if(force_resync_keymap) {
1341706f2543Smrg                    DarwinSendDDXEvent(kXquartzReloadKeymap, 0);
1342706f2543Smrg                    force_resync_keymap = NO;
1343706f2543Smrg                }
1344706f2543Smrg            }
1345706f2543Smrg
1346706f2543Smrg            if(darwinSyncKeymap) {
1347706f2543Smrg#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1050
1348706f2543Smrg                TISInputSourceRef key_layout = TISCopyCurrentKeyboardLayoutInputSource();
1349706f2543Smrg                TISInputSourceRef clear;
1350706f2543Smrg                if (CFEqual(key_layout, last_key_layout)) {
1351706f2543Smrg                    CFRelease(key_layout);
1352706f2543Smrg                } else {
1353706f2543Smrg                    /* Swap/free thread-safely */
1354706f2543Smrg                    clear = last_key_layout;
1355706f2543Smrg                    last_key_layout = key_layout;
1356706f2543Smrg                    CFRelease(clear);
1357706f2543Smrg#else
1358706f2543Smrg                KeyboardLayoutRef key_layout;
1359706f2543Smrg                KLGetCurrentKeyboardLayout(&key_layout);
1360706f2543Smrg                if(key_layout != last_key_layout) {
1361706f2543Smrg                    last_key_layout = key_layout;
1362706f2543Smrg#endif
1363706f2543Smrg                    /* Update keyInfo */
1364706f2543Smrg                    if (!QuartsResyncKeymap(TRUE)) {
1365706f2543Smrg                        fprintf(stderr, "sendX11NSEvent: Could not build a valid keymap.\n");
1366706f2543Smrg                    }
1367706f2543Smrg                }
1368706f2543Smrg            }
1369706f2543Smrg
1370706f2543Smrg            /* Avoid stuck keys on context switch */
1371706f2543Smrg            if(keyState[[e keyCode]] == [e type])
1372706f2543Smrg                return;
1373706f2543Smrg            keyState[[e keyCode]] = [e type];
1374706f2543Smrg
1375706f2543Smrg            DarwinSendKeyboardEvents(([e type] == NSKeyDown) ? KeyPress : KeyRelease, [e keyCode]);
1376706f2543Smrg            break;
1377706f2543Smrg            
1378706f2543Smrg        default: break; /* for gcc */
1379706f2543Smrg	}	
1380706f2543Smrg}
1381706f2543Smrg@end
1382