X11Application.m revision 35c4bbdf
14642e01fSmrg/* X11Application.m -- subclass of NSApplication to multiplex events
235c4bbdfSmrg *
335c4bbdfSmrg * Copyright (c) 2002-2012 Apple Inc. All rights reserved.
435c4bbdfSmrg *
535c4bbdfSmrg * Permission is hereby granted, free of charge, to any person
635c4bbdfSmrg * obtaining a copy of this software and associated documentation files
735c4bbdfSmrg * (the "Software"), to deal in the Software without restriction,
835c4bbdfSmrg * including without limitation the rights to use, copy, modify, merge,
935c4bbdfSmrg * publish, distribute, sublicense, and/or sell copies of the Software,
1035c4bbdfSmrg * and to permit persons to whom the Software is furnished to do so,
1135c4bbdfSmrg * subject to the following conditions:
1235c4bbdfSmrg *
1335c4bbdfSmrg * The above copyright notice and this permission notice shall be
1435c4bbdfSmrg * included in all copies or substantial portions of the Software.
1535c4bbdfSmrg *
1635c4bbdfSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
1735c4bbdfSmrg * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
1835c4bbdfSmrg * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
1935c4bbdfSmrg * NONINFRINGEMENT.  IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT
2035c4bbdfSmrg * HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
2135c4bbdfSmrg * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
2235c4bbdfSmrg * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
2335c4bbdfSmrg * DEALINGS IN THE SOFTWARE.
2435c4bbdfSmrg *
2535c4bbdfSmrg * Except as contained in this notice, the name(s) of the above
2635c4bbdfSmrg * copyright holders shall not be used in advertising or otherwise to
2735c4bbdfSmrg * promote the sale, use or other dealings in this Software without
2835c4bbdfSmrg * prior written authorization.
2935c4bbdfSmrg */
304642e01fSmrg
314642e01fSmrg#include "sanitizedCarbon.h"
324642e01fSmrg
334642e01fSmrg#ifdef HAVE_DIX_CONFIG_H
344642e01fSmrg#include <dix-config.h>
354642e01fSmrg#endif
364642e01fSmrg
374642e01fSmrg#include "quartzCommon.h"
384642e01fSmrg
394642e01fSmrg#import "X11Application.h"
404642e01fSmrg
414642e01fSmrg#include "darwin.h"
426747b715Smrg#include "quartz.h"
434642e01fSmrg#include "darwinEvents.h"
444642e01fSmrg#include "quartzKeyboard.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
5835c4bbdfSmrgextern int
5935c4bbdfSmrgxpbproxy_run(void);
604642e01fSmrg
6135c4bbdfSmrg#define DEFAULTS_FILE X11LIBDIR "/X11/xserver/Xquartz.plist"
624642e01fSmrg
634642e01fSmrg#ifndef XSERVER_VERSION
644642e01fSmrg#define XSERVER_VERSION "?"
654642e01fSmrg#endif
664642e01fSmrg
6735c4bbdfSmrg#ifdef HAVE_LIBDISPATCH
6835c4bbdfSmrg#include <dispatch/dispatch.h>
6935c4bbdfSmrg
7035c4bbdfSmrgstatic dispatch_queue_t eventTranslationQueue;
7135c4bbdfSmrg#endif
7235c4bbdfSmrg
7335c4bbdfSmrg#ifndef __has_feature
7435c4bbdfSmrg#define __has_feature(x) 0
7535c4bbdfSmrg#endif
7635c4bbdfSmrg
7735c4bbdfSmrg#ifndef CF_RETURNS_RETAINED
7835c4bbdfSmrg#if __has_feature(attribute_cf_returns_retained)
7935c4bbdfSmrg#define CF_RETURNS_RETAINED __attribute__((cf_returns_retained))
8035c4bbdfSmrg#else
8135c4bbdfSmrg#define CF_RETURNS_RETAINED
8235c4bbdfSmrg#endif
8335c4bbdfSmrg#endif
844642e01fSmrg
854642e01fSmrgextern Bool noTestExtensions;
8635c4bbdfSmrgextern Bool noRenderExtension;
8735c4bbdfSmrgextern BOOL serverRunning;
884642e01fSmrg
894642e01fSmrg#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1050
904642e01fSmrgstatic TISInputSourceRef last_key_layout;
914642e01fSmrg#else
924642e01fSmrgstatic KeyboardLayoutRef last_key_layout;
934642e01fSmrg#endif
944642e01fSmrg
95475c125cSmrg/* This preference is only tested on Lion or later as it's not relevant to
96475c125cSmrg * earlier OS versions.
97475c125cSmrg */
98475c125cSmrgBool XQuartzScrollInDeviceDirection = FALSE;
99475c125cSmrg
1004642e01fSmrgextern int darwinFakeButtons;
1014642e01fSmrg
1026747b715Smrg/* Store the mouse location while in the background, and update X11's pointer
1036747b715Smrg * location when we become the foreground application
1046747b715Smrg */
1056747b715Smrgstatic NSPoint bgMouseLocation;
1066747b715Smrgstatic BOOL bgMouseLocationUpdated = FALSE;
1076747b715Smrg
1084642e01fSmrgX11Application *X11App;
1094642e01fSmrg
1104642e01fSmrgCFStringRef app_prefs_domain_cfstr = NULL;
1114642e01fSmrg
11235c4bbdfSmrg#define ALL_KEY_MASKS (NSShiftKeyMask | NSControlKeyMask | \
11335c4bbdfSmrg                       NSAlternateKeyMask | NSCommandKeyMask)
1144642e01fSmrg
1154642e01fSmrg@interface X11Application (Private)
1164642e01fSmrg- (void) sendX11NSEvent:(NSEvent *)e;
1174642e01fSmrg@end
1184642e01fSmrg
1194642e01fSmrg@implementation X11Application
1204642e01fSmrg
1214642e01fSmrgtypedef struct message_struct message;
1224642e01fSmrgstruct message_struct {
1234642e01fSmrg    mach_msg_header_t hdr;
1244642e01fSmrg    SEL selector;
1254642e01fSmrg    NSObject *arg;
1264642e01fSmrg};
1274642e01fSmrg
1284642e01fSmrgstatic mach_port_t _port;
1294642e01fSmrg
1304642e01fSmrg/* Quartz mode initialization routine. This is often dynamically loaded
1314642e01fSmrg   but is statically linked into this X server. */
13235c4bbdfSmrgBool
13335c4bbdfSmrgQuartzModeBundleInit(void);
1344642e01fSmrg
13535c4bbdfSmrgstatic void
13635c4bbdfSmrginit_ports(void)
13735c4bbdfSmrg{
1384642e01fSmrg    kern_return_t r;
1394642e01fSmrg    NSPort *p;
14035c4bbdfSmrg
1414642e01fSmrg    if (_port != MACH_PORT_NULL) return;
14235c4bbdfSmrg
14335c4bbdfSmrg    r = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &_port);
1444642e01fSmrg    if (r != KERN_SUCCESS) return;
14535c4bbdfSmrg
1464642e01fSmrg    p = [NSMachPort portWithMachPort:_port];
1474642e01fSmrg    [p setDelegate:NSApp];
14835c4bbdfSmrg    [p scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:
14935c4bbdfSmrg     NSDefaultRunLoopMode];
1504642e01fSmrg}
1514642e01fSmrg
15235c4bbdfSmrgstatic void
15335c4bbdfSmrgmessage_kit_thread(SEL selector, NSObject *arg)
15435c4bbdfSmrg{
1554642e01fSmrg    message msg;
1564642e01fSmrg    kern_return_t r;
15735c4bbdfSmrg
15835c4bbdfSmrg    msg.hdr.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_MAKE_SEND, 0);
15935c4bbdfSmrg    msg.hdr.msgh_size = sizeof(msg);
1604642e01fSmrg    msg.hdr.msgh_remote_port = _port;
1614642e01fSmrg    msg.hdr.msgh_local_port = MACH_PORT_NULL;
1624642e01fSmrg    msg.hdr.msgh_reserved = 0;
1634642e01fSmrg    msg.hdr.msgh_id = 0;
16435c4bbdfSmrg
1654642e01fSmrg    msg.selector = selector;
1664642e01fSmrg    msg.arg = [arg retain];
16735c4bbdfSmrg
16835c4bbdfSmrg    r = mach_msg(&msg.hdr, MACH_SEND_MSG, msg.hdr.msgh_size,
16935c4bbdfSmrg                 0, MACH_PORT_NULL, 0, MACH_PORT_NULL);
1704642e01fSmrg    if (r != KERN_SUCCESS)
17135c4bbdfSmrg        ErrorF("%s: mach_msg failed: %x\n", __FUNCTION__, r);
1724642e01fSmrg}
1734642e01fSmrg
17435c4bbdfSmrg- (void) handleMachMessage:(void *)_msg
17535c4bbdfSmrg{
1764642e01fSmrg    message *msg = _msg;
17735c4bbdfSmrg
1784642e01fSmrg    [self performSelector:msg->selector withObject:msg->arg];
1794642e01fSmrg    [msg->arg release];
1804642e01fSmrg}
1814642e01fSmrg
18235c4bbdfSmrg- (void) set_controller:obj
18335c4bbdfSmrg{
1844642e01fSmrg    if (_controller == nil) _controller = [obj retain];
1854642e01fSmrg}
1864642e01fSmrg
18735c4bbdfSmrg- (void) dealloc
18835c4bbdfSmrg{
1894642e01fSmrg    if (_controller != nil) [_controller release];
19035c4bbdfSmrg
1914642e01fSmrg    if (_port != MACH_PORT_NULL)
19235c4bbdfSmrg        mach_port_deallocate(mach_task_self(), _port);
19335c4bbdfSmrg
1944642e01fSmrg    [super dealloc];
1954642e01fSmrg}
1964642e01fSmrg
19735c4bbdfSmrg- (void) orderFrontStandardAboutPanel: (id) sender
19835c4bbdfSmrg{
1994642e01fSmrg    NSMutableDictionary *dict;
2004642e01fSmrg    NSDictionary *infoDict;
2014642e01fSmrg    NSString *tem;
20235c4bbdfSmrg
2034642e01fSmrg    dict = [NSMutableDictionary dictionaryWithCapacity:3];
2044642e01fSmrg    infoDict = [[NSBundle mainBundle] infoDictionary];
20535c4bbdfSmrg
20635c4bbdfSmrg    [dict setObject: NSLocalizedString(@"The X Window System", @"About panel")
20735c4bbdfSmrg             forKey:@"ApplicationName"];
20835c4bbdfSmrg
2094642e01fSmrg    tem = [infoDict objectForKey:@"CFBundleShortVersionString"];
21035c4bbdfSmrg
2114642e01fSmrg    [dict setObject:[NSString stringWithFormat:@"XQuartz %@", tem]
21235c4bbdfSmrg             forKey:@"ApplicationVersion"];
21335c4bbdfSmrg
21435c4bbdfSmrg    [dict setObject:[NSString stringWithFormat:@"xorg-server %s",
21535c4bbdfSmrg                     XSERVER_VERSION]
21635c4bbdfSmrg     forKey:@"Version"];
2174642e01fSmrg
2184642e01fSmrg    [self orderFrontStandardAboutPanelWithOptions: dict];
2194642e01fSmrg}
2204642e01fSmrg
22135c4bbdfSmrg- (void) activateX:(OSX_BOOL)state
22235c4bbdfSmrg{
22335c4bbdfSmrg    if (_x_active == state)
22435c4bbdfSmrg        return;
22535c4bbdfSmrg
22635c4bbdfSmrg    DEBUG_LOG("state=%d, _x_active=%d, \n", state, _x_active);
2274642e01fSmrg    if (state) {
22835c4bbdfSmrg        if (bgMouseLocationUpdated) {
22935c4bbdfSmrg            DarwinSendPointerEvents(darwinPointer, MotionNotify, 0,
23035c4bbdfSmrg                                    bgMouseLocation.x, bgMouseLocation.y,
23135c4bbdfSmrg                                    0.0, 0.0);
2326747b715Smrg            bgMouseLocationUpdated = FALSE;
2334642e01fSmrg        }
2346747b715Smrg        DarwinSendDDXEvent(kXquartzActivate, 0);
23535c4bbdfSmrg    }
23635c4bbdfSmrg    else {
2374642e01fSmrg
23835c4bbdfSmrg        if (darwin_all_modifier_flags)
2394642e01fSmrg            DarwinUpdateModKeys(0);
24035c4bbdfSmrg
24135c4bbdfSmrg        DarwinInputReleaseButtonsAndKeys(darwinKeyboard);
24235c4bbdfSmrg        DarwinInputReleaseButtonsAndKeys(darwinPointer);
24335c4bbdfSmrg        DarwinInputReleaseButtonsAndKeys(darwinTabletCursor);
24435c4bbdfSmrg        DarwinInputReleaseButtonsAndKeys(darwinTabletStylus);
24535c4bbdfSmrg        DarwinInputReleaseButtonsAndKeys(darwinTabletEraser);
24635c4bbdfSmrg
2474642e01fSmrg        DarwinSendDDXEvent(kXquartzDeactivate, 0);
2484642e01fSmrg    }
2494642e01fSmrg
2504642e01fSmrg    _x_active = state;
2514642e01fSmrg}
2524642e01fSmrg
25335c4bbdfSmrg- (void) became_key:(NSWindow *)win
25435c4bbdfSmrg{
25535c4bbdfSmrg    [self activateX:NO];
2564642e01fSmrg}
2574642e01fSmrg
25835c4bbdfSmrg- (void) sendEvent:(NSEvent *)e
25935c4bbdfSmrg{
2604642e01fSmrg    OSX_BOOL for_appkit, for_x;
26135c4bbdfSmrg
2624642e01fSmrg    /* By default pass down the responder chain and to X. */
2634642e01fSmrg    for_appkit = YES;
2644642e01fSmrg    for_x = YES;
26535c4bbdfSmrg
2664642e01fSmrg    switch ([e type]) {
26735c4bbdfSmrg    case NSLeftMouseDown:
26835c4bbdfSmrg    case NSRightMouseDown:
26935c4bbdfSmrg    case NSOtherMouseDown:
27035c4bbdfSmrg    case NSLeftMouseUp:
27135c4bbdfSmrg    case NSRightMouseUp:
27235c4bbdfSmrg    case NSOtherMouseUp:
27335c4bbdfSmrg        if ([e window] != nil) {
27435c4bbdfSmrg            /* Pointer event has an (AppKit) window. Probably something for the kit. */
27535c4bbdfSmrg            for_x = NO;
27635c4bbdfSmrg            if (_x_active) [self activateX:NO];
27735c4bbdfSmrg        }
27835c4bbdfSmrg        else if ([self modalWindow] == nil) {
27935c4bbdfSmrg            /* Must be an X window. Tell appkit it doesn't have focus. */
28035c4bbdfSmrg            for_appkit = NO;
28135c4bbdfSmrg
28235c4bbdfSmrg            if ([self isActive]) {
28335c4bbdfSmrg                [self deactivate];
28435c4bbdfSmrg                if (!_x_active && quartzProcs->IsX11Window([e windowNumber]))
28535c4bbdfSmrg                    [self activateX:YES];
2864642e01fSmrg            }
28735c4bbdfSmrg        }
2884642e01fSmrg
28935c4bbdfSmrg        /* We want to force sending to appkit if we're over the menu bar */
29035c4bbdfSmrg        if (!for_appkit) {
29135c4bbdfSmrg            NSPoint NSlocation = [e locationInWindow];
29235c4bbdfSmrg            NSWindow *window = [e window];
29335c4bbdfSmrg            NSRect NSframe, NSvisibleFrame;
29435c4bbdfSmrg            CGRect CGframe, CGvisibleFrame;
29535c4bbdfSmrg            CGPoint CGlocation;
29635c4bbdfSmrg
29735c4bbdfSmrg            if (window != nil) {
29835c4bbdfSmrg                NSRect frame = [window frame];
29935c4bbdfSmrg                NSlocation.x += frame.origin.x;
30035c4bbdfSmrg                NSlocation.y += frame.origin.y;
3014642e01fSmrg            }
30235c4bbdfSmrg
30335c4bbdfSmrg            NSframe = [[NSScreen mainScreen] frame];
30435c4bbdfSmrg            NSvisibleFrame = [[NSScreen mainScreen] visibleFrame];
30535c4bbdfSmrg
30635c4bbdfSmrg            CGframe = CGRectMake(NSframe.origin.x, NSframe.origin.y,
30735c4bbdfSmrg                                 NSframe.size.width, NSframe.size.height);
30835c4bbdfSmrg            CGvisibleFrame = CGRectMake(NSvisibleFrame.origin.x,
30935c4bbdfSmrg                                        NSvisibleFrame.origin.y,
31035c4bbdfSmrg                                        NSvisibleFrame.size.width,
31135c4bbdfSmrg                                        NSvisibleFrame.size.height);
31235c4bbdfSmrg            CGlocation = CGPointMake(NSlocation.x, NSlocation.y);
31335c4bbdfSmrg
31435c4bbdfSmrg            if (CGRectContainsPoint(CGframe, CGlocation) &&
31535c4bbdfSmrg                !CGRectContainsPoint(CGvisibleFrame, CGlocation))
31635c4bbdfSmrg                for_appkit = YES;
31735c4bbdfSmrg        }
31835c4bbdfSmrg
31935c4bbdfSmrg        break;
32035c4bbdfSmrg
32135c4bbdfSmrg    case NSKeyDown:
32235c4bbdfSmrg    case NSKeyUp:
32335c4bbdfSmrg
32435c4bbdfSmrg        if (_x_active) {
32535c4bbdfSmrg            static BOOL do_swallow = NO;
32635c4bbdfSmrg            static int swallow_keycode;
32735c4bbdfSmrg
32835c4bbdfSmrg            if ([e type] == NSKeyDown) {
32935c4bbdfSmrg                /* Before that though, see if there are any global
33035c4bbdfSmrg                 * shortcuts bound to it. */
33135c4bbdfSmrg
33235c4bbdfSmrg                if (darwinAppKitModMask &[e modifierFlags]) {
33335c4bbdfSmrg                    /* Override to force sending to Appkit */
33435c4bbdfSmrg                    swallow_keycode = [e keyCode];
33535c4bbdfSmrg                    do_swallow = YES;
33635c4bbdfSmrg                    for_x = NO;
3374642e01fSmrg#if XPLUGIN_VERSION >= 1
33835c4bbdfSmrg                }
33935c4bbdfSmrg                else if (XQuartzEnableKeyEquivalents &&
34035c4bbdfSmrg                         xp_is_symbolic_hotkey_event([e eventRef])) {
34135c4bbdfSmrg                    swallow_keycode = [e keyCode];
34235c4bbdfSmrg                    do_swallow = YES;
34335c4bbdfSmrg                    for_x = NO;
3444642e01fSmrg#endif
3454642e01fSmrg                }
34635c4bbdfSmrg                else if (XQuartzEnableKeyEquivalents &&
34735c4bbdfSmrg                         [[self mainMenu] performKeyEquivalent:e]) {
34835c4bbdfSmrg                    swallow_keycode = [e keyCode];
34935c4bbdfSmrg                    do_swallow = YES;
35035c4bbdfSmrg                    for_appkit = NO;
35135c4bbdfSmrg                    for_x = NO;
35235c4bbdfSmrg                }
35335c4bbdfSmrg                else if (!XQuartzIsRootless
35435c4bbdfSmrg                         && ([e modifierFlags] & ALL_KEY_MASKS) ==
35535c4bbdfSmrg                         (NSCommandKeyMask | NSAlternateKeyMask)
35635c4bbdfSmrg                         && ([e keyCode] == 0 /*a*/ || [e keyCode] ==
35735c4bbdfSmrg                             53 /*Esc*/)) {
35835c4bbdfSmrg                    /* We have this here to force processing fullscreen
35935c4bbdfSmrg                     * toggle even if XQuartzEnableKeyEquivalents is disabled */
36035c4bbdfSmrg                    swallow_keycode = [e keyCode];
36135c4bbdfSmrg                    do_swallow = YES;
36235c4bbdfSmrg                    for_x = NO;
36335c4bbdfSmrg                    for_appkit = NO;
36435c4bbdfSmrg                    DarwinSendDDXEvent(kXquartzToggleFullscreen, 0);
36535c4bbdfSmrg                }
36635c4bbdfSmrg                else {
36735c4bbdfSmrg                    /* No kit window is focused, so send it to X. */
36835c4bbdfSmrg                    for_appkit = NO;
36935c4bbdfSmrg                }
37035c4bbdfSmrg            }
37135c4bbdfSmrg            else {       /* KeyUp */
37235c4bbdfSmrg                /* If we saw a key equivalent on the down, don't pass
37335c4bbdfSmrg                 * the up through to X. */
37435c4bbdfSmrg                if (do_swallow && [e keyCode] == swallow_keycode) {
37535c4bbdfSmrg                    do_swallow = NO;
37635c4bbdfSmrg                    for_x = NO;
37735c4bbdfSmrg                }
37835c4bbdfSmrg            }
37935c4bbdfSmrg        }
38035c4bbdfSmrg        else {       /* !_x_active */
38135c4bbdfSmrg            for_x = NO;
38235c4bbdfSmrg        }
38335c4bbdfSmrg        break;
38435c4bbdfSmrg
38535c4bbdfSmrg    case NSFlagsChanged:
38635c4bbdfSmrg        /* Don't tell X11 about modifiers changing while it's not active */
38735c4bbdfSmrg        if (!_x_active)
38835c4bbdfSmrg            for_x = NO;
38935c4bbdfSmrg        break;
39035c4bbdfSmrg
39135c4bbdfSmrg    case NSAppKitDefined:
39235c4bbdfSmrg        switch ([e subtype]) {
39335c4bbdfSmrg            static BOOL x_was_active = NO;
39435c4bbdfSmrg
39535c4bbdfSmrg        case NSApplicationActivatedEventType:
39635c4bbdfSmrg            for_x = NO;
39735c4bbdfSmrg            if ([e window] == nil && x_was_active) {
39835c4bbdfSmrg                BOOL order_all_windows = YES, workspaces, ok;
39935c4bbdfSmrg                for_appkit = NO;
40035c4bbdfSmrg
40135c4bbdfSmrg                /* FIXME: This is a hack to avoid passing the event to AppKit which
40235c4bbdfSmrg                 *        would result in it raising one of its windows.
40335c4bbdfSmrg                 */
40435c4bbdfSmrg                _appFlags._active = YES;
40535c4bbdfSmrg
40635c4bbdfSmrg                [self set_front_process:nil];
40735c4bbdfSmrg
40835c4bbdfSmrg                /* Get the Spaces preference for SwitchOnActivate */
40935c4bbdfSmrg                (void)CFPreferencesAppSynchronize(CFSTR("com.apple.dock"));
41035c4bbdfSmrg                workspaces =
41135c4bbdfSmrg                    CFPreferencesGetAppBooleanValue(CFSTR("workspaces"),
41235c4bbdfSmrg                                                    CFSTR(
41335c4bbdfSmrg                                                        "com.apple.dock"),
41435c4bbdfSmrg                                                    &ok);
41535c4bbdfSmrg                if (!ok)
41635c4bbdfSmrg                    workspaces = NO;
41735c4bbdfSmrg
41835c4bbdfSmrg                if (workspaces) {
41935c4bbdfSmrg                    (void)CFPreferencesAppSynchronize(CFSTR(
42035c4bbdfSmrg                                                          ".GlobalPreferences"));
42135c4bbdfSmrg                    order_all_windows =
42235c4bbdfSmrg                        CFPreferencesGetAppBooleanValue(CFSTR(
42335c4bbdfSmrg                                                            "AppleSpacesSwitchOnActivate"),
42435c4bbdfSmrg                                                        CFSTR(
42535c4bbdfSmrg                                                            ".GlobalPreferences"),
42635c4bbdfSmrg                                                        &ok);
42735c4bbdfSmrg                    if (!ok)
42835c4bbdfSmrg                        order_all_windows = YES;
42935c4bbdfSmrg                }
43035c4bbdfSmrg
43135c4bbdfSmrg                /* TODO: In the workspaces && !AppleSpacesSwitchOnActivate case, the windows are ordered
43235c4bbdfSmrg                 *       correctly, but we need to activate the top window on this space if there is
43335c4bbdfSmrg                 *       none active.
43435c4bbdfSmrg                 *
43535c4bbdfSmrg                 *       If there are no active windows, and there are minimized windows, we should
43635c4bbdfSmrg                 *       be restoring one of them.
43735c4bbdfSmrg                 */
43835c4bbdfSmrg                if ([e data2] & 0x10) {         // 0x10 (bfCPSOrderAllWindowsForward) is set when we use cmd-tab or the dock icon
43935c4bbdfSmrg                    DarwinSendDDXEvent(kXquartzBringAllToFront, 1,
44035c4bbdfSmrg                                       order_all_windows);
44135c4bbdfSmrg                }
4424642e01fSmrg            }
4434642e01fSmrg            break;
44435c4bbdfSmrg
44535c4bbdfSmrg        case 18:         /* ApplicationDidReactivate */
44635c4bbdfSmrg            if (XQuartzFullscreenVisible) for_appkit = NO;
4474642e01fSmrg            break;
4489ace9065Smrg
44935c4bbdfSmrg        case NSApplicationDeactivatedEventType:
45035c4bbdfSmrg            for_x = NO;
4519ace9065Smrg
45235c4bbdfSmrg            x_was_active = _x_active;
45335c4bbdfSmrg            if (_x_active)
45435c4bbdfSmrg                [self activateX:NO];
4554642e01fSmrg            break;
45635c4bbdfSmrg        }
45735c4bbdfSmrg        break;
45835c4bbdfSmrg
45935c4bbdfSmrg    default:
46035c4bbdfSmrg        break;          /* for gcc */
4614642e01fSmrg    }
46235c4bbdfSmrg
4634642e01fSmrg    if (for_appkit) [super sendEvent:e];
46435c4bbdfSmrg
46535c4bbdfSmrg    if (for_x) {
46635c4bbdfSmrg#ifdef HAVE_LIBDISPATCH
46735c4bbdfSmrg        dispatch_async(eventTranslationQueue, ^{
46835c4bbdfSmrg                           [self sendX11NSEvent:e];
46935c4bbdfSmrg                       });
47035c4bbdfSmrg#else
47135c4bbdfSmrg        [self sendX11NSEvent:e];
47235c4bbdfSmrg#endif
47335c4bbdfSmrg    }
4744642e01fSmrg}
4754642e01fSmrg
47635c4bbdfSmrg- (void) set_window_menu:(NSArray *)list
47735c4bbdfSmrg{
47835c4bbdfSmrg    [_controller set_window_menu:list];
4794642e01fSmrg}
4804642e01fSmrg
48135c4bbdfSmrg- (void) set_window_menu_check:(NSNumber *)n
48235c4bbdfSmrg{
48335c4bbdfSmrg    [_controller set_window_menu_check:n];
4844642e01fSmrg}
4854642e01fSmrg
48635c4bbdfSmrg- (void) set_apps_menu:(NSArray *)list
48735c4bbdfSmrg{
48835c4bbdfSmrg    [_controller set_apps_menu:list];
4894642e01fSmrg}
4904642e01fSmrg
49135c4bbdfSmrg- (void) set_front_process:unused
49235c4bbdfSmrg{
49335c4bbdfSmrg    [NSApp activateIgnoringOtherApps:YES];
4944642e01fSmrg
49535c4bbdfSmrg    if ([self modalWindow] == nil)
49635c4bbdfSmrg        [self activateX:YES];
4974642e01fSmrg}
4984642e01fSmrg
49935c4bbdfSmrg- (void) set_can_quit:(NSNumber *)state
50035c4bbdfSmrg{
50135c4bbdfSmrg    [_controller set_can_quit:[state boolValue]];
5024642e01fSmrg}
5034642e01fSmrg
50435c4bbdfSmrg- (void) server_ready:unused
50535c4bbdfSmrg{
50635c4bbdfSmrg    [_controller server_ready];
5074642e01fSmrg}
5084642e01fSmrg
50935c4bbdfSmrg- (void) show_hide_menubar:(NSNumber *)state
51035c4bbdfSmrg{
5114642e01fSmrg    /* Also shows/hides the dock */
5124642e01fSmrg    if ([state boolValue])
51335c4bbdfSmrg        SetSystemUIMode(kUIModeNormal, 0);
5144642e01fSmrg    else
51535c4bbdfSmrg        SetSystemUIMode(kUIModeAllHidden,
51635c4bbdfSmrg                        XQuartzFullscreenMenu ? kUIOptionAutoShowMenuBar : 0);                   // kUIModeAllSuppressed or kUIOptionAutoShowMenuBar can be used to allow "mouse-activation"
5174642e01fSmrg}
5184642e01fSmrg
51935c4bbdfSmrg- (void) launch_client:(NSString *)cmd
52035c4bbdfSmrg{
5216747b715Smrg    (void)[_controller application:self openFile:cmd];
5226747b715Smrg}
5234642e01fSmrg
5244642e01fSmrg/* user preferences */
5254642e01fSmrg
5264642e01fSmrg/* Note that these functions only work for arrays whose elements
52735c4bbdfSmrg   can be toll-free-bridged between NS and CF worlds. */
5284642e01fSmrg
52935c4bbdfSmrgstatic const void *
53035c4bbdfSmrgcfretain(CFAllocatorRef a, const void *b)
53135c4bbdfSmrg{
53235c4bbdfSmrg    return CFRetain(b);
5334642e01fSmrg}
5344642e01fSmrg
53535c4bbdfSmrgstatic void
53635c4bbdfSmrgcfrelease(CFAllocatorRef a, const void *b)
53735c4bbdfSmrg{
53835c4bbdfSmrg    CFRelease(b);
5394642e01fSmrg}
5404642e01fSmrg
54135c4bbdfSmrgCF_RETURNS_RETAINED
54235c4bbdfSmrgstatic CFMutableArrayRef
54335c4bbdfSmrgnsarray_to_cfarray(NSArray *in)
54435c4bbdfSmrg{
54535c4bbdfSmrg    CFMutableArrayRef out;
54635c4bbdfSmrg    CFArrayCallBacks cb;
54735c4bbdfSmrg    NSObject *ns;
54835c4bbdfSmrg    const CFTypeRef *cf;
54935c4bbdfSmrg    int i, count;
55035c4bbdfSmrg
55135c4bbdfSmrg    memset(&cb, 0, sizeof(cb));
55235c4bbdfSmrg    cb.version = 0;
55335c4bbdfSmrg    cb.retain = cfretain;
55435c4bbdfSmrg    cb.release = cfrelease;
55535c4bbdfSmrg
55635c4bbdfSmrg    count = [in count];
55735c4bbdfSmrg    out = CFArrayCreateMutable(NULL, count, &cb);
55835c4bbdfSmrg
55935c4bbdfSmrg    for (i = 0; i < count; i++) {
56035c4bbdfSmrg        ns = [in objectAtIndex:i];
56135c4bbdfSmrg
56235c4bbdfSmrg        if ([ns isKindOfClass:[NSArray class]])
56335c4bbdfSmrg            cf = (CFTypeRef)nsarray_to_cfarray((NSArray *)ns);
56435c4bbdfSmrg        else
56535c4bbdfSmrg            cf = CFRetain((CFTypeRef)ns);
56635c4bbdfSmrg
56735c4bbdfSmrg        CFArrayAppendValue(out, cf);
56835c4bbdfSmrg        CFRelease(cf);
56935c4bbdfSmrg    }
57035c4bbdfSmrg
57135c4bbdfSmrg    return out;
57235c4bbdfSmrg}
5734642e01fSmrg
57435c4bbdfSmrgstatic NSMutableArray *
57535c4bbdfSmrgcfarray_to_nsarray(CFArrayRef in)
57635c4bbdfSmrg{
57735c4bbdfSmrg    NSMutableArray *out;
57835c4bbdfSmrg    const CFTypeRef *cf;
57935c4bbdfSmrg    NSObject *ns;
58035c4bbdfSmrg    int i, count;
5814642e01fSmrg
58235c4bbdfSmrg    count = CFArrayGetCount(in);
58335c4bbdfSmrg    out = [[NSMutableArray alloc] initWithCapacity:count];
5844642e01fSmrg
58535c4bbdfSmrg    for (i = 0; i < count; i++) {
58635c4bbdfSmrg        cf = CFArrayGetValueAtIndex(in, i);
5874642e01fSmrg
58835c4bbdfSmrg        if (CFGetTypeID(cf) == CFArrayGetTypeID())
58935c4bbdfSmrg            ns = cfarray_to_nsarray((CFArrayRef)cf);
59035c4bbdfSmrg        else
59135c4bbdfSmrg            ns = [(id) cf retain];
5924642e01fSmrg
59335c4bbdfSmrg        [out addObject:ns];
59435c4bbdfSmrg        [ns release];
59535c4bbdfSmrg    }
5964642e01fSmrg
59735c4bbdfSmrg    return out;
5984642e01fSmrg}
5994642e01fSmrg
60035c4bbdfSmrg- (CFPropertyListRef) prefs_get_copy:(NSString *)key
60135c4bbdfSmrg{
60235c4bbdfSmrg    CFPropertyListRef value;
60335c4bbdfSmrg
60435c4bbdfSmrg    value = CFPreferencesCopyAppValue((CFStringRef)key,
60535c4bbdfSmrg                                      app_prefs_domain_cfstr);
60635c4bbdfSmrg
60735c4bbdfSmrg    if (value == NULL) {
60835c4bbdfSmrg        static CFDictionaryRef defaults;
60935c4bbdfSmrg
61035c4bbdfSmrg        if (defaults == NULL) {
61135c4bbdfSmrg            CFStringRef error = NULL;
61235c4bbdfSmrg            CFDataRef data;
61335c4bbdfSmrg            CFURLRef url;
61435c4bbdfSmrg            SInt32 error_code;
61535c4bbdfSmrg
61635c4bbdfSmrg            url = (CFURLCreateFromFileSystemRepresentation
61735c4bbdfSmrg                       (NULL, (unsigned char *)DEFAULTS_FILE,
61835c4bbdfSmrg                       strlen(DEFAULTS_FILE), false));
61935c4bbdfSmrg            if (CFURLCreateDataAndPropertiesFromResource(NULL, url, &data,
62035c4bbdfSmrg                                                         NULL, NULL,
62135c4bbdfSmrg                                                         &error_code)) {
62235c4bbdfSmrg                defaults = (CFPropertyListCreateFromXMLData
62335c4bbdfSmrg                                (NULL, data,
62435c4bbdfSmrg                                kCFPropertyListMutableContainersAndLeaves,
62535c4bbdfSmrg                                &error));
62635c4bbdfSmrg                if (error != NULL) CFRelease(error);
62735c4bbdfSmrg                CFRelease(data);
62835c4bbdfSmrg            }
62935c4bbdfSmrg            CFRelease(url);
63035c4bbdfSmrg
63135c4bbdfSmrg            if (defaults != NULL) {
63235c4bbdfSmrg                NSMutableArray *apps, *elt;
63335c4bbdfSmrg                int count, i;
63435c4bbdfSmrg                NSString *name, *nname;
63535c4bbdfSmrg
63635c4bbdfSmrg                /* Localize the names in the default apps menu. */
63735c4bbdfSmrg
63835c4bbdfSmrg                apps =
63935c4bbdfSmrg                    [(NSDictionary *) defaults objectForKey:@PREFS_APPSMENU];
64035c4bbdfSmrg                if (apps != nil) {
64135c4bbdfSmrg                    count = [apps count];
64235c4bbdfSmrg                    for (i = 0; i < count; i++) {
64335c4bbdfSmrg                        elt = [apps objectAtIndex:i];
64435c4bbdfSmrg                        if (elt != nil &&
64535c4bbdfSmrg                            [elt isKindOfClass:[NSArray class]]) {
64635c4bbdfSmrg                            name = [elt objectAtIndex:0];
64735c4bbdfSmrg                            if (name != nil) {
64835c4bbdfSmrg                                nname = NSLocalizedString(name, nil);
64935c4bbdfSmrg                                if (nname != nil && nname != name)
65035c4bbdfSmrg                                    [elt replaceObjectAtIndex:0 withObject:
65135c4bbdfSmrg                                     nname];
65235c4bbdfSmrg                            }
65335c4bbdfSmrg                        }
65435c4bbdfSmrg                    }
65535c4bbdfSmrg                }
65635c4bbdfSmrg            }
65735c4bbdfSmrg        }
65835c4bbdfSmrg
65935c4bbdfSmrg        if (defaults != NULL) value = CFDictionaryGetValue(defaults, key);
66035c4bbdfSmrg        if (value != NULL) CFRetain(value);
66135c4bbdfSmrg    }
6624642e01fSmrg
66335c4bbdfSmrg    return value;
66435c4bbdfSmrg}
6654642e01fSmrg
66635c4bbdfSmrg- (int) prefs_get_integer:(NSString *)key default:(int)def
66735c4bbdfSmrg{
66835c4bbdfSmrg    CFPropertyListRef value;
66935c4bbdfSmrg    int ret;
6704642e01fSmrg
67135c4bbdfSmrg    value = [self prefs_get_copy:key];
6724642e01fSmrg
67335c4bbdfSmrg    if (value != NULL && CFGetTypeID(value) == CFNumberGetTypeID())
67435c4bbdfSmrg        CFNumberGetValue(value, kCFNumberIntType, &ret);
67535c4bbdfSmrg    else if (value != NULL && CFGetTypeID(value) == CFStringGetTypeID())
67635c4bbdfSmrg        ret = CFStringGetIntValue(value);
67735c4bbdfSmrg    else
67835c4bbdfSmrg        ret = def;
6794642e01fSmrg
68035c4bbdfSmrg    if (value != NULL) CFRelease(value);
68135c4bbdfSmrg
68235c4bbdfSmrg    return ret;
6834642e01fSmrg}
6844642e01fSmrg
68535c4bbdfSmrg- (const char *) prefs_get_string:(NSString *)key default:(const char *)def
68635c4bbdfSmrg{
6874642e01fSmrg    CFPropertyListRef value;
68835c4bbdfSmrg    const char *ret = NULL;
68935c4bbdfSmrg
69035c4bbdfSmrg    value = [self prefs_get_copy:key];
69135c4bbdfSmrg
69235c4bbdfSmrg    if (value != NULL && CFGetTypeID(value) == CFStringGetTypeID()) {
69335c4bbdfSmrg        NSString *s = (NSString *)value;
69435c4bbdfSmrg
69535c4bbdfSmrg        ret = [s UTF8String];
6964642e01fSmrg    }
6974642e01fSmrg
69835c4bbdfSmrg    if (value != NULL) CFRelease(value);
6994642e01fSmrg
70035c4bbdfSmrg    return ret != NULL ? ret : def;
7014642e01fSmrg}
7024642e01fSmrg
70335c4bbdfSmrg- (NSURL *) prefs_copy_url:(NSString *)key default:(NSURL *)def
70435c4bbdfSmrg{
7056747b715Smrg    CFPropertyListRef value;
7066747b715Smrg    NSURL *ret = NULL;
70735c4bbdfSmrg
7086747b715Smrg    value = [self prefs_get_copy:key];
70935c4bbdfSmrg
71035c4bbdfSmrg    if (value != NULL && CFGetTypeID(value) == CFStringGetTypeID()) {
71135c4bbdfSmrg        NSString *s = (NSString *)value;
7126747b715Smrg
7136747b715Smrg        ret = [NSURL URLWithString:s];
7146747b715Smrg        [ret retain];
7156747b715Smrg    }
71635c4bbdfSmrg
71735c4bbdfSmrg    if (value != NULL) CFRelease(value);
71835c4bbdfSmrg
7196747b715Smrg    return ret != NULL ? ret : def;
7206747b715Smrg}
7216747b715Smrg
72235c4bbdfSmrg- (float) prefs_get_float:(NSString *)key default:(float)def
72335c4bbdfSmrg{
72435c4bbdfSmrg    CFPropertyListRef value;
72535c4bbdfSmrg    float ret = def;
72635c4bbdfSmrg
72735c4bbdfSmrg    value = [self prefs_get_copy:key];
72835c4bbdfSmrg
72935c4bbdfSmrg    if (value != NULL
73035c4bbdfSmrg        && CFGetTypeID(value) == CFNumberGetTypeID()
73135c4bbdfSmrg        && CFNumberIsFloatType(value))
73235c4bbdfSmrg        CFNumberGetValue(value, kCFNumberFloatType, &ret);
73335c4bbdfSmrg    else if (value != NULL && CFGetTypeID(value) == CFStringGetTypeID())
73435c4bbdfSmrg        ret = CFStringGetDoubleValue(value);
73535c4bbdfSmrg
73635c4bbdfSmrg    if (value != NULL) CFRelease(value);
73735c4bbdfSmrg
73835c4bbdfSmrg    return ret;
7394642e01fSmrg}
7404642e01fSmrg
74135c4bbdfSmrg- (int) prefs_get_boolean:(NSString *)key default:(int)def
74235c4bbdfSmrg{
74335c4bbdfSmrg    CFPropertyListRef value;
74435c4bbdfSmrg    int ret = def;
74535c4bbdfSmrg
74635c4bbdfSmrg    value = [self prefs_get_copy:key];
74735c4bbdfSmrg
74835c4bbdfSmrg    if (value != NULL) {
74935c4bbdfSmrg        if (CFGetTypeID(value) == CFNumberGetTypeID())
75035c4bbdfSmrg            CFNumberGetValue(value, kCFNumberIntType, &ret);
75135c4bbdfSmrg        else if (CFGetTypeID(value) == CFBooleanGetTypeID())
75235c4bbdfSmrg            ret = CFBooleanGetValue(value);
75335c4bbdfSmrg        else if (CFGetTypeID(value) == CFStringGetTypeID()) {
75435c4bbdfSmrg            const char *tem = [(NSString *) value UTF8String];
75535c4bbdfSmrg            if (strcasecmp(tem, "true") == 0 || strcasecmp(tem, "yes") == 0)
75635c4bbdfSmrg                ret = YES;
75735c4bbdfSmrg            else
75835c4bbdfSmrg                ret = NO;
75935c4bbdfSmrg        }
76035c4bbdfSmrg
76135c4bbdfSmrg        CFRelease(value);
7624642e01fSmrg    }
76335c4bbdfSmrg    return ret;
7644642e01fSmrg}
7654642e01fSmrg
76635c4bbdfSmrg- (NSArray *) prefs_get_array:(NSString *)key
76735c4bbdfSmrg{
76835c4bbdfSmrg    NSArray *ret = nil;
76935c4bbdfSmrg    CFPropertyListRef value;
77035c4bbdfSmrg
77135c4bbdfSmrg    value = [self prefs_get_copy:key];
77235c4bbdfSmrg
77335c4bbdfSmrg    if (value != NULL) {
77435c4bbdfSmrg        if (CFGetTypeID(value) == CFArrayGetTypeID())
77535c4bbdfSmrg            ret = [cfarray_to_nsarray (value)autorelease];
77635c4bbdfSmrg
77735c4bbdfSmrg        CFRelease(value);
77835c4bbdfSmrg    }
77935c4bbdfSmrg
78035c4bbdfSmrg    return ret;
7814642e01fSmrg}
7824642e01fSmrg
78335c4bbdfSmrg- (void) prefs_set_integer:(NSString *)key value:(int)value
78435c4bbdfSmrg{
7854642e01fSmrg    CFNumberRef x;
78635c4bbdfSmrg
78735c4bbdfSmrg    x = CFNumberCreate(NULL, kCFNumberIntType, &value);
78835c4bbdfSmrg
78935c4bbdfSmrg    CFPreferencesSetValue((CFStringRef)key, (CFTypeRef)x,
79035c4bbdfSmrg                          app_prefs_domain_cfstr,
79135c4bbdfSmrg                          kCFPreferencesCurrentUser,
79235c4bbdfSmrg                          kCFPreferencesAnyHost);
79335c4bbdfSmrg
79435c4bbdfSmrg    CFRelease(x);
7954642e01fSmrg}
7964642e01fSmrg
79735c4bbdfSmrg- (void) prefs_set_float:(NSString *)key value:(float)value
79835c4bbdfSmrg{
7994642e01fSmrg    CFNumberRef x;
80035c4bbdfSmrg
80135c4bbdfSmrg    x = CFNumberCreate(NULL, kCFNumberFloatType, &value);
80235c4bbdfSmrg
80335c4bbdfSmrg    CFPreferencesSetValue((CFStringRef)key, (CFTypeRef)x,
80435c4bbdfSmrg                          app_prefs_domain_cfstr,
80535c4bbdfSmrg                          kCFPreferencesCurrentUser,
80635c4bbdfSmrg                          kCFPreferencesAnyHost);
80735c4bbdfSmrg
80835c4bbdfSmrg    CFRelease(x);
8094642e01fSmrg}
8104642e01fSmrg
81135c4bbdfSmrg- (void) prefs_set_boolean:(NSString *)key value:(int)value
81235c4bbdfSmrg{
81335c4bbdfSmrg    CFPreferencesSetValue(
81435c4bbdfSmrg        (CFStringRef)key,
81535c4bbdfSmrg        (CFTypeRef)(value ? kCFBooleanTrue
81635c4bbdfSmrg                    : kCFBooleanFalse),
81735c4bbdfSmrg        app_prefs_domain_cfstr,
81835c4bbdfSmrg        kCFPreferencesCurrentUser, kCFPreferencesAnyHost);
81935c4bbdfSmrg
8204642e01fSmrg}
8214642e01fSmrg
82235c4bbdfSmrg- (void) prefs_set_array:(NSString *)key value:(NSArray *)value
82335c4bbdfSmrg{
82435c4bbdfSmrg    CFArrayRef cfarray;
82535c4bbdfSmrg
82635c4bbdfSmrg    cfarray = nsarray_to_cfarray(value);
82735c4bbdfSmrg    CFPreferencesSetValue((CFStringRef)key,
82835c4bbdfSmrg                          (CFTypeRef)cfarray,
82935c4bbdfSmrg                          app_prefs_domain_cfstr,
83035c4bbdfSmrg                          kCFPreferencesCurrentUser, kCFPreferencesAnyHost);
83135c4bbdfSmrg    CFRelease(cfarray);
8324642e01fSmrg}
8334642e01fSmrg
83435c4bbdfSmrg- (void) prefs_set_string:(NSString *)key value:(NSString *)value
83535c4bbdfSmrg{
83635c4bbdfSmrg    CFPreferencesSetValue((CFStringRef)key, (CFTypeRef)value,
83735c4bbdfSmrg                          app_prefs_domain_cfstr, kCFPreferencesCurrentUser,
83835c4bbdfSmrg                          kCFPreferencesAnyHost);
8394642e01fSmrg}
8404642e01fSmrg
84135c4bbdfSmrg- (void) prefs_synchronize
84235c4bbdfSmrg{
84335c4bbdfSmrg    CFPreferencesAppSynchronize(kCFPreferencesCurrentApplication);
8444642e01fSmrg}
8454642e01fSmrg
8464642e01fSmrg- (void) read_defaults
8474642e01fSmrg{
8484642e01fSmrg    NSString *nsstr;
8494642e01fSmrg    const char *tem;
85035c4bbdfSmrg
8516747b715Smrg    XQuartzRootlessDefault = [self prefs_get_boolean:@PREFS_ROOTLESS
85235c4bbdfSmrg                              default               :XQuartzRootlessDefault];
8536747b715Smrg    XQuartzFullscreenMenu = [self prefs_get_boolean:@PREFS_FULLSCREEN_MENU
85435c4bbdfSmrg                             default               :XQuartzFullscreenMenu];
85535c4bbdfSmrg    XQuartzFullscreenDisableHotkeys =
85635c4bbdfSmrg        ![self prefs_get_boolean:@PREFS_FULLSCREEN_HOTKEYS
85735c4bbdfSmrg          default               :!
85835c4bbdfSmrg          XQuartzFullscreenDisableHotkeys];
8594642e01fSmrg    darwinFakeButtons = [self prefs_get_boolean:@PREFS_FAKEBUTTONS
86035c4bbdfSmrg                         default               :darwinFakeButtons];
8616747b715Smrg    XQuartzOptionSendsAlt = [self prefs_get_boolean:@PREFS_OPTION_SENDS_ALT
86235c4bbdfSmrg                             default               :XQuartzOptionSendsAlt];
8636747b715Smrg
8644642e01fSmrg    if (darwinFakeButtons) {
8654642e01fSmrg        const char *fake2, *fake3;
8664642e01fSmrg
8674642e01fSmrg        fake2 = [self prefs_get_string:@PREFS_FAKE_BUTTON2 default:NULL];
8684642e01fSmrg        fake3 = [self prefs_get_string:@PREFS_FAKE_BUTTON3 default:NULL];
8694642e01fSmrg
87035c4bbdfSmrg        if (fake2 != NULL) darwinFakeMouse2Mask = DarwinParseModifierList(
87135c4bbdfSmrg                fake2, TRUE);
87235c4bbdfSmrg        if (fake3 != NULL) darwinFakeMouse3Mask = DarwinParseModifierList(
87335c4bbdfSmrg                fake3, TRUE);
8744642e01fSmrg    }
8754642e01fSmrg
8764642e01fSmrg    tem = [self prefs_get_string:@PREFS_APPKIT_MODIFIERS default:NULL];
8774642e01fSmrg    if (tem != NULL) darwinAppKitModMask = DarwinParseModifierList(tem, TRUE);
87835c4bbdfSmrg
8794642e01fSmrg    tem = [self prefs_get_string:@PREFS_WINDOW_ITEM_MODIFIERS default:NULL];
8804642e01fSmrg    if (tem != NULL) {
8814642e01fSmrg        windowItemModMask = DarwinParseModifierList(tem, FALSE);
88235c4bbdfSmrg    }
88335c4bbdfSmrg    else {
88435c4bbdfSmrg        nsstr = NSLocalizedString(@"window item modifiers",
88535c4bbdfSmrg                                  @"window item modifiers");
88635c4bbdfSmrg        if (nsstr != NULL) {
8874642e01fSmrg            tem = [nsstr UTF8String];
88835c4bbdfSmrg            if ((tem != NULL) && strcmp(tem, "window item modifiers")) {
8894642e01fSmrg                windowItemModMask = DarwinParseModifierList(tem, FALSE);
8904642e01fSmrg            }
8914642e01fSmrg        }
8924642e01fSmrg    }
8934642e01fSmrg
8946747b715Smrg    XQuartzEnableKeyEquivalents = [self prefs_get_boolean:@PREFS_KEYEQUIVS
89535c4bbdfSmrg                                   default               :
89635c4bbdfSmrg                                   XQuartzEnableKeyEquivalents];
89735c4bbdfSmrg
8984642e01fSmrg    darwinSyncKeymap = [self prefs_get_boolean:@PREFS_SYNC_KEYMAP
89935c4bbdfSmrg                        default               :darwinSyncKeymap];
90035c4bbdfSmrg
9014642e01fSmrg    darwinDesiredDepth = [self prefs_get_integer:@PREFS_DEPTH
90235c4bbdfSmrg                          default               :darwinDesiredDepth];
90335c4bbdfSmrg
9044642e01fSmrg    noTestExtensions = ![self prefs_get_boolean:@PREFS_TEST_EXTENSIONS
90535c4bbdfSmrg                         default               :FALSE];
90635c4bbdfSmrg
90735c4bbdfSmrg    noRenderExtension = ![self prefs_get_boolean:@PREFS_RENDER_EXTENSION
90835c4bbdfSmrg                          default               :TRUE];
90935c4bbdfSmrg
91035c4bbdfSmrg    XQuartzScrollInDeviceDirection =
91135c4bbdfSmrg        [self prefs_get_boolean:@PREFS_SCROLL_IN_DEV_DIRECTION
91235c4bbdfSmrg         default               :
91335c4bbdfSmrg         XQuartzScrollInDeviceDirection];
9146747b715Smrg
9156747b715Smrg#if XQUARTZ_SPARKLE
91635c4bbdfSmrg    NSURL *url = [self prefs_copy_url:@PREFS_UPDATE_FEED default:nil];
91735c4bbdfSmrg    if (url) {
9186747b715Smrg        [[SUUpdater sharedUpdater] setFeedURL:url];
9196747b715Smrg        [url release];
9206747b715Smrg    }
9216747b715Smrg#endif
9224642e01fSmrg}
9234642e01fSmrg
9244642e01fSmrg/* This will end up at the end of the responder chain. */
92535c4bbdfSmrg- (void) copy:sender
92635c4bbdfSmrg{
92735c4bbdfSmrg    DarwinSendDDXEvent(kXquartzPasteboardNotify, 1,
92835c4bbdfSmrg                       AppleWMCopyToPasteboard);
9294642e01fSmrg}
9304642e01fSmrg
93135c4bbdfSmrg- (X11Controller *) controller
93235c4bbdfSmrg{
9336747b715Smrg    return _controller;
9346747b715Smrg}
9356747b715Smrg
93635c4bbdfSmrg- (OSX_BOOL) x_active
93735c4bbdfSmrg{
9384642e01fSmrg    return _x_active;
9394642e01fSmrg}
9404642e01fSmrg
9414642e01fSmrg@end
9424642e01fSmrg
9434642e01fSmrgstatic NSArray *
94435c4bbdfSmrgarray_with_strings_and_numbers(int nitems, const char **items,
94535c4bbdfSmrg                               const char *numbers)
94635c4bbdfSmrg{
94735c4bbdfSmrg    NSMutableArray *array, *subarray;
94835c4bbdfSmrg    NSString *string, *number;
94935c4bbdfSmrg    int i;
95035c4bbdfSmrg
95135c4bbdfSmrg    /* (Can't autorelease on the X server thread) */
95235c4bbdfSmrg
95335c4bbdfSmrg    array = [[NSMutableArray alloc] initWithCapacity:nitems];
95435c4bbdfSmrg
95535c4bbdfSmrg    for (i = 0; i < nitems; i++) {
95635c4bbdfSmrg        subarray = [[NSMutableArray alloc] initWithCapacity:2];
95735c4bbdfSmrg
95835c4bbdfSmrg        string = [[NSString alloc] initWithUTF8String:items[i]];
95935c4bbdfSmrg        [subarray addObject:string];
96035c4bbdfSmrg        [string release];
96135c4bbdfSmrg
96235c4bbdfSmrg        if (numbers[i] != 0) {
96335c4bbdfSmrg            number = [[NSString alloc] initWithFormat:@"%d", numbers[i]];
96435c4bbdfSmrg            [subarray addObject:number];
96535c4bbdfSmrg            [number release];
96635c4bbdfSmrg        }
96735c4bbdfSmrg        else
96835c4bbdfSmrg            [subarray addObject:@""];
96935c4bbdfSmrg
97035c4bbdfSmrg        [array addObject:subarray];
97135c4bbdfSmrg        [subarray release];
97235c4bbdfSmrg    }
97335c4bbdfSmrg
97435c4bbdfSmrg    return array;
9754642e01fSmrg}
9764642e01fSmrg
97735c4bbdfSmrgvoid
97835c4bbdfSmrgX11ApplicationSetWindowMenu(int nitems, const char **items,
97935c4bbdfSmrg                            const char *shortcuts)
98035c4bbdfSmrg{
98135c4bbdfSmrg    NSArray *array;
98235c4bbdfSmrg    array = array_with_strings_and_numbers(nitems, items, shortcuts);
98335c4bbdfSmrg
98435c4bbdfSmrg    /* Send the array of strings over to the appkit thread */
98535c4bbdfSmrg
98635c4bbdfSmrg    message_kit_thread(@selector (set_window_menu:), array);
98735c4bbdfSmrg    [array release];
9884642e01fSmrg}
9894642e01fSmrg
99035c4bbdfSmrgvoid
99135c4bbdfSmrgX11ApplicationSetWindowMenuCheck(int idx)
99235c4bbdfSmrg{
99335c4bbdfSmrg    NSNumber *n;
99435c4bbdfSmrg
99535c4bbdfSmrg    n = [[NSNumber alloc] initWithInt:idx];
99635c4bbdfSmrg
99735c4bbdfSmrg    message_kit_thread(@selector (set_window_menu_check:), n);
99835c4bbdfSmrg
99935c4bbdfSmrg    [n release];
10004642e01fSmrg}
10014642e01fSmrg
100235c4bbdfSmrgvoid
100335c4bbdfSmrgX11ApplicationSetFrontProcess(void)
100435c4bbdfSmrg{
100535c4bbdfSmrg    message_kit_thread(@selector (set_front_process:), nil);
10064642e01fSmrg}
10074642e01fSmrg
100835c4bbdfSmrgvoid
100935c4bbdfSmrgX11ApplicationSetCanQuit(int state)
101035c4bbdfSmrg{
10114642e01fSmrg    NSNumber *n;
101235c4bbdfSmrg
10134642e01fSmrg    n = [[NSNumber alloc] initWithBool:state];
101435c4bbdfSmrg
101535c4bbdfSmrg    message_kit_thread(@selector (set_can_quit:), n);
101635c4bbdfSmrg
10174642e01fSmrg    [n release];
10184642e01fSmrg}
10194642e01fSmrg
102035c4bbdfSmrgvoid
102135c4bbdfSmrgX11ApplicationServerReady(void)
102235c4bbdfSmrg{
102335c4bbdfSmrg    message_kit_thread(@selector (server_ready:), nil);
10244642e01fSmrg}
10254642e01fSmrg
102635c4bbdfSmrgvoid
102735c4bbdfSmrgX11ApplicationShowHideMenubar(int state)
102835c4bbdfSmrg{
10294642e01fSmrg    NSNumber *n;
103035c4bbdfSmrg
10314642e01fSmrg    n = [[NSNumber alloc] initWithBool:state];
103235c4bbdfSmrg
103335c4bbdfSmrg    message_kit_thread(@selector (show_hide_menubar:), n);
103435c4bbdfSmrg
10354642e01fSmrg    [n release];
10364642e01fSmrg}
10374642e01fSmrg
103835c4bbdfSmrgvoid
103935c4bbdfSmrgX11ApplicationLaunchClient(const char *cmd)
104035c4bbdfSmrg{
10416747b715Smrg    NSString *string;
104235c4bbdfSmrg
10436747b715Smrg    string = [[NSString alloc] initWithUTF8String:cmd];
104435c4bbdfSmrg
104535c4bbdfSmrg    message_kit_thread(@selector (launch_client:), string);
104635c4bbdfSmrg
10476747b715Smrg    [string release];
10486747b715Smrg}
10496747b715Smrg
10508223e2f2Smrg/* This is a special function in that it is run from the *SERVER* thread and
10518223e2f2Smrg * not the AppKit thread.  We want to block entering a screen-capturing RandR
10528223e2f2Smrg * mode until we notify the user about how to get out if the X11 client crashes.
10538223e2f2Smrg */
105435c4bbdfSmrgBool
105535c4bbdfSmrgX11ApplicationCanEnterRandR(void)
105635c4bbdfSmrg{
10578223e2f2Smrg    NSString *title, *msg;
105835c4bbdfSmrg
105935c4bbdfSmrg    if ([X11App prefs_get_boolean:@PREFS_NO_RANDR_ALERT default:NO] ||
106035c4bbdfSmrg        XQuartzShieldingWindowLevel != 0)
10618223e2f2Smrg        return TRUE;
10628223e2f2Smrg
106335c4bbdfSmrg    title = NSLocalizedString(@"Enter RandR mode?",
106435c4bbdfSmrg                              @"Dialog title when switching to RandR");
106535c4bbdfSmrg    msg = NSLocalizedString(
106635c4bbdfSmrg        @"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.",
106735c4bbdfSmrg        @"Dialog when switching to RandR");
106835c4bbdfSmrg
106935c4bbdfSmrg    if (!XQuartzIsRootless)
10708223e2f2Smrg        QuartzShowFullscreen(FALSE);
10718223e2f2Smrg
107235c4bbdfSmrg    switch (NSRunAlertPanel(title, @"%@",
107335c4bbdfSmrg                            NSLocalizedString(@"Allow",
107435c4bbdfSmrg                                              @""),
107535c4bbdfSmrg                            NSLocalizedString(@"Cancel",
107635c4bbdfSmrg                                              @""),
107735c4bbdfSmrg                            NSLocalizedString(@"Always Allow", @""), msg)) {
107835c4bbdfSmrg    case NSAlertOtherReturn:
107935c4bbdfSmrg        [X11App prefs_set_boolean:@PREFS_NO_RANDR_ALERT value:YES];
108035c4bbdfSmrg        [X11App prefs_synchronize];
108135c4bbdfSmrg
108235c4bbdfSmrg    case NSAlertDefaultReturn:
108335c4bbdfSmrg        return YES;
108435c4bbdfSmrg
108535c4bbdfSmrg    default:
108635c4bbdfSmrg        return NO;
10878223e2f2Smrg    }
10888223e2f2Smrg}
10898223e2f2Smrg
109035c4bbdfSmrgvoid
109135c4bbdfSmrgX11ApplicationFatalError(const char *f, va_list args)
109235c4bbdfSmrg{
109335c4bbdfSmrg#ifdef HAVE_LIBDISPATCH
109435c4bbdfSmrg    NSString *title, *msg;
109535c4bbdfSmrg    char *error_msg;
109635c4bbdfSmrg
109735c4bbdfSmrg    /* This is called by FatalError() in the server thread just before
109835c4bbdfSmrg     * we would abort.  If the server never got off the ground, We should
109935c4bbdfSmrg     * inform the user of the error rather than letting the ever-so-friendly
110035c4bbdfSmrg     * CrashReporter do it for us.
110135c4bbdfSmrg     *
110235c4bbdfSmrg     * This also has the benefit of forcing user interaction rather than
110335c4bbdfSmrg     * allowing an infinite throttled-restart if the crash occurs before
110435c4bbdfSmrg     * we can drain the launchd socket.
110535c4bbdfSmrg     */
110635c4bbdfSmrg
110735c4bbdfSmrg    if (serverRunning) {
110835c4bbdfSmrg        return;
110935c4bbdfSmrg    }
111035c4bbdfSmrg
111135c4bbdfSmrg    title = NSLocalizedString(@"The application X11 could not be opened.",
111235c4bbdfSmrg                              @"Dialog title when encountering a fatal error");
111335c4bbdfSmrg    msg = NSLocalizedString(
111435c4bbdfSmrg        @"An error occurred while starting the X11 server: \"%s\"\n\nClick Quit to quit X11. Click Report to see more details or send a report to Apple.",
111535c4bbdfSmrg        @"Dialog when encountering a fatal error");
111635c4bbdfSmrg
111735c4bbdfSmrg    vasprintf(&error_msg, f, args);
111835c4bbdfSmrg    msg = [NSString stringWithFormat:msg, error_msg];
111935c4bbdfSmrg
112035c4bbdfSmrg    /* We want the AppKit thread to actually service the alert or we will race [NSApp run] and create an
112135c4bbdfSmrg     * 'NSInternalInconsistencyException', reason: 'NSApp with wrong _running count'
112235c4bbdfSmrg     */
112335c4bbdfSmrg    dispatch_sync(dispatch_get_main_queue(), ^{
112435c4bbdfSmrg                      if (NSAlertDefaultReturn ==
112535c4bbdfSmrg                          NSRunAlertPanel (title, @"%@",
112635c4bbdfSmrg                                           NSLocalizedString (@"Quit", @""),
112735c4bbdfSmrg                                           NSLocalizedString (@"Report...", @""),
112835c4bbdfSmrg                                           nil, msg)) {
112935c4bbdfSmrg                          exit (EXIT_FAILURE);
113035c4bbdfSmrg                      }
113135c4bbdfSmrg                  });
113235c4bbdfSmrg
113335c4bbdfSmrg    /* fall back to caller to do the abort() in the DIX */
113435c4bbdfSmrg#endif
113535c4bbdfSmrg}
113635c4bbdfSmrg
113735c4bbdfSmrgstatic void
113835c4bbdfSmrgcheck_xinitrc(void)
113935c4bbdfSmrg{
11404642e01fSmrg    char *tem, buf[1024];
11414642e01fSmrg    NSString *msg;
114235c4bbdfSmrg
11434642e01fSmrg    if ([X11App prefs_get_boolean:@PREFS_DONE_XINIT_CHECK default:NO])
114435c4bbdfSmrg        return;
114535c4bbdfSmrg
114635c4bbdfSmrg    tem = getenv("HOME");
11474642e01fSmrg    if (tem == NULL) goto done;
114835c4bbdfSmrg
114935c4bbdfSmrg    snprintf(buf, sizeof(buf), "%s/.xinitrc", tem);
115035c4bbdfSmrg    if (access(buf, F_OK) != 0)
115135c4bbdfSmrg        goto done;
115235c4bbdfSmrg
115335c4bbdfSmrg    msg =
115435c4bbdfSmrg        NSLocalizedString(
115535c4bbdfSmrg            @"You have an existing ~/.xinitrc file.\n\n\
115635c4bbdfSmrg                             Windows displayed by X11 applications may not have titlebars, or may look \
115735c4bbdfSmrg                             different to windows displayed by native applications.\n\n\
115835c4bbdfSmrg                             Would you like to move aside the existing file and use the standard X11 \
115935c4bbdfSmrg                             environment the next time you start X11?"                                                                                                                                                                                                                                                                                                                                                                  ,
116035c4bbdfSmrg            @"Startup xinitrc dialog");
116135c4bbdfSmrg
116235c4bbdfSmrg    if (NSAlertDefaultReturn ==
116335c4bbdfSmrg        NSRunAlertPanel(nil, @"%@", NSLocalizedString(@"Yes", @""),
116435c4bbdfSmrg                        NSLocalizedString(@"No", @""), nil, msg)) {
11654642e01fSmrg        char buf2[1024];
11664642e01fSmrg        int i = -1;
11674642e01fSmrg
116835c4bbdfSmrg        snprintf(buf2, sizeof(buf2), "%s.old", buf);
116935c4bbdfSmrg
117035c4bbdfSmrg        for (i = 1; access(buf2, F_OK) == 0; i++)
117135c4bbdfSmrg            snprintf(buf2, sizeof(buf2), "%s.old.%d", buf, i);
117235c4bbdfSmrg
117335c4bbdfSmrg        rename(buf, buf2);
11744642e01fSmrg    }
117535c4bbdfSmrg
117635c4bbdfSmrgdone:
11774642e01fSmrg    [X11App prefs_set_boolean:@PREFS_DONE_XINIT_CHECK value:YES];
11784642e01fSmrg    [X11App prefs_synchronize];
11794642e01fSmrg}
11804642e01fSmrg
118135c4bbdfSmrgstatic inline pthread_t
118235c4bbdfSmrgcreate_thread(void *(*func)(void *), void *arg)
118335c4bbdfSmrg{
11846747b715Smrg    pthread_attr_t attr;
11856747b715Smrg    pthread_t tid;
118635c4bbdfSmrg
11876747b715Smrg    pthread_attr_init(&attr);
11886747b715Smrg    pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM);
11896747b715Smrg    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
11906747b715Smrg    pthread_create(&tid, &attr, func, arg);
11916747b715Smrg    pthread_attr_destroy(&attr);
119235c4bbdfSmrg
11936747b715Smrg    return tid;
11946747b715Smrg}
11956747b715Smrg
119635c4bbdfSmrgstatic void *
119735c4bbdfSmrgxpbproxy_x_thread(void *args)
119835c4bbdfSmrg{
11996747b715Smrg    xpbproxy_run();
12006747b715Smrg
120135c4bbdfSmrg    ErrorF("xpbproxy thread is terminating unexpectedly.\n");
12026747b715Smrg    return NULL;
12036747b715Smrg}
12046747b715Smrg
120535c4bbdfSmrgvoid
120635c4bbdfSmrgX11ApplicationMain(int argc, char **argv, char **envp)
120735c4bbdfSmrg{
12084642e01fSmrg    NSAutoreleasePool *pool;
12094642e01fSmrg
12104642e01fSmrg#ifdef DEBUG
121135c4bbdfSmrg    while (access("/tmp/x11-block", F_OK) == 0) sleep(1);
12124642e01fSmrg#endif
121335c4bbdfSmrg
12144642e01fSmrg    pool = [[NSAutoreleasePool alloc] init];
121535c4bbdfSmrg    X11App = (X11Application *)[X11Application sharedApplication];
121635c4bbdfSmrg    init_ports();
121735c4bbdfSmrg
121835c4bbdfSmrg    app_prefs_domain_cfstr =
121935c4bbdfSmrg        (CFStringRef)[[NSBundle mainBundle] bundleIdentifier];
12204642e01fSmrg
1221475c125cSmrg    if (app_prefs_domain_cfstr == NULL) {
122235c4bbdfSmrg        ErrorF(
122335c4bbdfSmrg            "X11ApplicationMain: Unable to determine bundle identifier.  Your installation of XQuartz may be broken.\n");
122435c4bbdfSmrg        app_prefs_domain_cfstr = CFSTR(BUNDLE_ID_PREFIX ".X11");
1225475c125cSmrg    }
1226475c125cSmrg
12274642e01fSmrg    [NSApp read_defaults];
12284642e01fSmrg    [NSBundle loadNibNamed:@"main" owner:NSApp];
12294642e01fSmrg    [[NSNotificationCenter defaultCenter] addObserver:NSApp
123035c4bbdfSmrg                                             selector:@selector (became_key:)
123135c4bbdfSmrg                                                 name:
123235c4bbdfSmrg     NSWindowDidBecomeKeyNotification object:nil];
12334642e01fSmrg
12344642e01fSmrg    /*
12354642e01fSmrg     * The xpr Quartz mode is statically linked into this server.
12364642e01fSmrg     * Initialize all the Quartz functions.
12374642e01fSmrg     */
12384642e01fSmrg    QuartzModeBundleInit();
12394642e01fSmrg
12404642e01fSmrg    /* Calculate the height of the menubar so we can avoid it. */
124135c4bbdfSmrg    aquaMenuBarHeight = [[NSApp mainMenu] menuBarHeight];
124235c4bbdfSmrg#if ! __LP64__
124335c4bbdfSmrg    if (!aquaMenuBarHeight) {
124435c4bbdfSmrg        aquaMenuBarHeight = [NSMenuView menuBarHeight];
124535c4bbdfSmrg    }
124635c4bbdfSmrg#endif
124735c4bbdfSmrg    if (!aquaMenuBarHeight) {
124835c4bbdfSmrg        NSScreen* primaryScreen = [[NSScreen screens] objectAtIndex:0];
124935c4bbdfSmrg        aquaMenuBarHeight = NSHeight([primaryScreen frame]) - NSMaxY([primaryScreen visibleFrame]);
125035c4bbdfSmrg    }
125135c4bbdfSmrg
125235c4bbdfSmrg#ifdef HAVE_LIBDISPATCH
125335c4bbdfSmrg    eventTranslationQueue = dispatch_queue_create(
125435c4bbdfSmrg        BUNDLE_ID_PREFIX ".X11.NSEventsToX11EventsQueue", NULL);
125535c4bbdfSmrg    assert(eventTranslationQueue != NULL);
125635c4bbdfSmrg#endif
12574642e01fSmrg
12584642e01fSmrg    /* Set the key layout seed before we start the server */
12594642e01fSmrg#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1050
126035c4bbdfSmrg    last_key_layout = TISCopyCurrentKeyboardLayoutInputSource();
12614642e01fSmrg
126235c4bbdfSmrg    if (!last_key_layout)
126335c4bbdfSmrg        ErrorF(
126435c4bbdfSmrg            "X11ApplicationMain: Unable to determine TISCopyCurrentKeyboardLayoutInputSource() at startup.\n");
12654642e01fSmrg#else
12664642e01fSmrg    KLGetCurrentKeyboardLayout(&last_key_layout);
126735c4bbdfSmrg    if (!last_key_layout)
126835c4bbdfSmrg        ErrorF(
126935c4bbdfSmrg            "X11ApplicationMain: Unable to determine KLGetCurrentKeyboardLayout() at startup.\n");
12704642e01fSmrg#endif
12714642e01fSmrg
12726747b715Smrg    if (!QuartsResyncKeymap(FALSE)) {
127335c4bbdfSmrg        ErrorF("X11ApplicationMain: Could not build a valid keymap.\n");
12744642e01fSmrg    }
12754642e01fSmrg
12764642e01fSmrg    /* Tell the server thread that it can proceed */
12774642e01fSmrg    QuartzInitServer(argc, argv, envp);
127835c4bbdfSmrg
12794642e01fSmrg    /* This must be done after QuartzInitServer because it can result in
12804642e01fSmrg     * an mieqEnqueue() - <rdar://problem/6300249>
12814642e01fSmrg     */
12824642e01fSmrg    check_xinitrc();
128335c4bbdfSmrg
12846747b715Smrg    create_thread(xpbproxy_x_thread, NULL);
12856747b715Smrg
12866747b715Smrg#if XQUARTZ_SPARKLE
12876747b715Smrg    [[X11App controller] setup_sparkle];
12886747b715Smrg    [[SUUpdater sharedUpdater] resetUpdateCycle];
128935c4bbdfSmrg    //    [[SUUpdater sharedUpdater] checkForUpdates:X11App];
12906747b715Smrg#endif
12916747b715Smrg
12926747b715Smrg    [pool release];
12934642e01fSmrg    [NSApp run];
12944642e01fSmrg    /* not reached */
12954642e01fSmrg}
12964642e01fSmrg
12974642e01fSmrg@implementation X11Application (Private)
12984642e01fSmrg
12994642e01fSmrg#ifdef NX_DEVICELCMDKEYMASK
13004642e01fSmrg/* This is to workaround a bug in the VNC server where we sometimes see the L
13014642e01fSmrg * modifier and sometimes see no "side"
13024642e01fSmrg */
130335c4bbdfSmrgstatic inline int
130435c4bbdfSmrgensure_flag(int flags, int device_independent, int device_dependents,
130535c4bbdfSmrg            int device_dependent_default)
130635c4bbdfSmrg{
130735c4bbdfSmrg    if ((flags & device_independent) &&
130835c4bbdfSmrg        !(flags & device_dependents))
13094642e01fSmrg        flags |= device_dependent_default;
13104642e01fSmrg    return flags;
13114642e01fSmrg}
13124642e01fSmrg#endif
13134642e01fSmrg
13149ace9065Smrg#ifdef DEBUG_UNTRUSTED_POINTER_DELTA
131535c4bbdfSmrgstatic const char *
131635c4bbdfSmrguntrusted_str(NSEvent *e)
131735c4bbdfSmrg{
131835c4bbdfSmrg    switch ([e type]) {
131935c4bbdfSmrg    case NSScrollWheel:
132035c4bbdfSmrg        return "NSScrollWheel";
132135c4bbdfSmrg
132235c4bbdfSmrg    case NSTabletPoint:
132335c4bbdfSmrg        return "NSTabletPoint";
132435c4bbdfSmrg
132535c4bbdfSmrg    case NSOtherMouseDown:
132635c4bbdfSmrg        return "NSOtherMouseDown";
132735c4bbdfSmrg
132835c4bbdfSmrg    case NSOtherMouseUp:
132935c4bbdfSmrg        return "NSOtherMouseUp";
133035c4bbdfSmrg
133135c4bbdfSmrg    case NSLeftMouseDown:
133235c4bbdfSmrg        return "NSLeftMouseDown";
133335c4bbdfSmrg
133435c4bbdfSmrg    case NSLeftMouseUp:
133535c4bbdfSmrg        return "NSLeftMouseUp";
133635c4bbdfSmrg
133735c4bbdfSmrg    default:
133835c4bbdfSmrg        switch ([e subtype]) {
133935c4bbdfSmrg        case NSTabletPointEventSubtype:
134035c4bbdfSmrg            return "NSTabletPointEventSubtype";
134135c4bbdfSmrg
134235c4bbdfSmrg        case NSTabletProximityEventSubtype:
134335c4bbdfSmrg            return "NSTabletProximityEventSubtype";
134435c4bbdfSmrg
13459ace9065Smrg        default:
134635c4bbdfSmrg            return "Other";
134735c4bbdfSmrg        }
13489ace9065Smrg    }
13499ace9065Smrg}
13509ace9065Smrg#endif
13519ace9065Smrg
135235c4bbdfSmrgextern void
135335c4bbdfSmrgdarwinEvents_lock(void);
135435c4bbdfSmrgextern void
135535c4bbdfSmrgdarwinEvents_unlock(void);
135635c4bbdfSmrg
135735c4bbdfSmrg- (void) sendX11NSEvent:(NSEvent *)e
135835c4bbdfSmrg{
135935c4bbdfSmrg    NSPoint location = NSZeroPoint;
13604642e01fSmrg    int ev_button, ev_type;
136135c4bbdfSmrg    static float pressure = 0.0;       // static so ProximityOut will have the value from the previous tablet event
136235c4bbdfSmrg    static NSPoint tilt;               // static so ProximityOut will have the value from the previous tablet event
136335c4bbdfSmrg    static DeviceIntPtr darwinTabletCurrent = NULL;
136435c4bbdfSmrg    static BOOL needsProximityIn = NO; // Do we do need to handle a pending ProximityIn once we have pressure/tilt?
13654642e01fSmrg    DeviceIntPtr pDev;
13664642e01fSmrg    int modifierFlags;
13676747b715Smrg    BOOL isMouseOrTabletEvent, isTabletEvent;
13684642e01fSmrg
136935c4bbdfSmrg    if (!darwinTabletCurrent) {
137035c4bbdfSmrg        /* Ensure that the event system is initialized */
137135c4bbdfSmrg        darwinEvents_lock();
137235c4bbdfSmrg        darwinEvents_unlock();
137335c4bbdfSmrg        assert(darwinTabletStylus);
137435c4bbdfSmrg
137535c4bbdfSmrg        tilt = NSZeroPoint;
137635c4bbdfSmrg        darwinTabletCurrent = darwinTabletStylus;
137735c4bbdfSmrg    }
137835c4bbdfSmrg
137935c4bbdfSmrg    isMouseOrTabletEvent = [e type] == NSLeftMouseDown ||
138035c4bbdfSmrg                           [e type] == NSOtherMouseDown ||
138135c4bbdfSmrg                           [e type] == NSRightMouseDown ||
138235c4bbdfSmrg                           [e type] == NSLeftMouseUp ||
138335c4bbdfSmrg                           [e type] == NSOtherMouseUp ||
138435c4bbdfSmrg                           [e type] == NSRightMouseUp ||
138535c4bbdfSmrg                           [e type] == NSLeftMouseDragged ||
138635c4bbdfSmrg                           [e type] == NSOtherMouseDragged ||
138735c4bbdfSmrg                           [e type] == NSRightMouseDragged ||
138835c4bbdfSmrg                           [e type] == NSMouseMoved ||
138935c4bbdfSmrg                           [e type] == NSTabletPoint || 
139035c4bbdfSmrg                           [e type] == NSScrollWheel;
13914642e01fSmrg
13926747b715Smrg    isTabletEvent = ([e type] == NSTabletPoint) ||
139335c4bbdfSmrg                    (isMouseOrTabletEvent &&
139435c4bbdfSmrg                     ([e subtype] == NSTabletPointEventSubtype ||
139535c4bbdfSmrg                      [e subtype] == NSTabletProximityEventSubtype));
13964642e01fSmrg
139735c4bbdfSmrg    if (isMouseOrTabletEvent) {
13986747b715Smrg        static NSPoint lastpt;
13996747b715Smrg        NSWindow *window = [e window];
14006747b715Smrg        NSRect screen = [[[NSScreen screens] objectAtIndex:0] frame];
140135c4bbdfSmrg        BOOL hasUntrustedPointerDelta;
140235c4bbdfSmrg
14036747b715Smrg        // NSEvents for tablets are not consistent wrt deltaXY between events, so we cannot rely on that
14046747b715Smrg        // Thus tablets will be subject to the warp-pointer bug worked around by the delta, but tablets
14056747b715Smrg        // are not normally used in cases where that bug would present itself, so this is a fair tradeoff
14066747b715Smrg        // <rdar://problem/7111003> deltaX and deltaY are incorrect for NSMouseMoved, NSTabletPointEventSubtype
14076747b715Smrg        // http://xquartz.macosforge.org/trac/ticket/288
14086747b715Smrg        hasUntrustedPointerDelta = isTabletEvent;
140935c4bbdfSmrg
14106747b715Smrg        // The deltaXY for middle click events also appear erroneous after fast user switching
14116747b715Smrg        // <rdar://problem/7979468> deltaX and deltaY are incorrect for NSOtherMouseDown and NSOtherMouseUp after FUS
14126747b715Smrg        // http://xquartz.macosforge.org/trac/ticket/389
141335c4bbdfSmrg        hasUntrustedPointerDelta |= [e type] == NSOtherMouseDown ||
141435c4bbdfSmrg                                    [e type] == NSOtherMouseUp;
14156747b715Smrg
14166747b715Smrg        // The deltaXY for scroll events correspond to the scroll delta, not the pointer delta
14176747b715Smrg        // <rdar://problem/7989690> deltaXY for wheel events are being sent as mouse movement
141835c4bbdfSmrg        hasUntrustedPointerDelta |= [e type] == NSScrollWheel;
14199ace9065Smrg
14209ace9065Smrg#ifdef DEBUG_UNTRUSTED_POINTER_DELTA
142135c4bbdfSmrg        hasUntrustedPointerDelta |= [e type] == NSLeftMouseDown ||
142235c4bbdfSmrg                                    [e type] == NSLeftMouseUp;
14239ace9065Smrg#endif
142435c4bbdfSmrg
142535c4bbdfSmrg        if (window != nil) {
14266747b715Smrg            NSRect frame = [window frame];
14276747b715Smrg            location = [e locationInWindow];
14286747b715Smrg            location.x += frame.origin.x;
14296747b715Smrg            location.y += frame.origin.y;
14306747b715Smrg            lastpt = location;
143135c4bbdfSmrg        }
143235c4bbdfSmrg        else if (hasUntrustedPointerDelta) {
14339ace9065Smrg#ifdef DEBUG_UNTRUSTED_POINTER_DELTA
14349ace9065Smrg            ErrorF("--- Begin Event Debug ---\n");
14359ace9065Smrg            ErrorF("Event type: %s\n", untrusted_str(e));
14369ace9065Smrg            ErrorF("old lastpt: (%0.2f, %0.2f)\n", lastpt.x, lastpt.y);
14379ace9065Smrg            ErrorF("     delta: (%0.2f, %0.2f)\n", [e deltaX], -[e deltaY]);
143835c4bbdfSmrg            ErrorF("  location: (%0.2f, %0.2f)\n", lastpt.x + [e deltaX],
143935c4bbdfSmrg                   lastpt.y - [e deltaY]);
144035c4bbdfSmrg            ErrorF("workaround: (%0.2f, %0.2f)\n", [e locationInWindow].x,
144135c4bbdfSmrg                   [e locationInWindow].y);
14429ace9065Smrg            ErrorF("--- End Event Debug ---\n");
14439ace9065Smrg
14449ace9065Smrg            location.x = lastpt.x + [e deltaX];
14459ace9065Smrg            location.y = lastpt.y - [e deltaY];
14469ace9065Smrg            lastpt = [e locationInWindow];
14479ace9065Smrg#else
14486747b715Smrg            location = [e locationInWindow];
14496747b715Smrg            lastpt = location;
14509ace9065Smrg#endif
145135c4bbdfSmrg        }
145235c4bbdfSmrg        else {
14536747b715Smrg            location.x = lastpt.x + [e deltaX];
14546747b715Smrg            location.y = lastpt.y - [e deltaY];
14556747b715Smrg            lastpt = [e locationInWindow];
14566747b715Smrg        }
145735c4bbdfSmrg
14586747b715Smrg        /* Convert coordinate system */
14596747b715Smrg        location.y = (screen.origin.y + screen.size.height) - location.y;
14606747b715Smrg    }
146135c4bbdfSmrg
14624642e01fSmrg    modifierFlags = [e modifierFlags];
146335c4bbdfSmrg
14644642e01fSmrg#ifdef NX_DEVICELCMDKEYMASK
14654642e01fSmrg    /* This is to workaround a bug in the VNC server where we sometimes see the L
14664642e01fSmrg     * modifier and sometimes see no "side"
14674642e01fSmrg     */
146835c4bbdfSmrg    modifierFlags = ensure_flag(modifierFlags, NX_CONTROLMASK,
146935c4bbdfSmrg                                NX_DEVICELCTLKEYMASK | NX_DEVICERCTLKEYMASK,
147035c4bbdfSmrg                                NX_DEVICELCTLKEYMASK);
147135c4bbdfSmrg    modifierFlags = ensure_flag(modifierFlags, NX_SHIFTMASK,
147235c4bbdfSmrg                                NX_DEVICELSHIFTKEYMASK | NX_DEVICERSHIFTKEYMASK, 
147335c4bbdfSmrg                                NX_DEVICELSHIFTKEYMASK);
147435c4bbdfSmrg    modifierFlags = ensure_flag(modifierFlags, NX_COMMANDMASK,
147535c4bbdfSmrg                                NX_DEVICELCMDKEYMASK | NX_DEVICERCMDKEYMASK,
147635c4bbdfSmrg                                NX_DEVICELCMDKEYMASK);
147735c4bbdfSmrg    modifierFlags = ensure_flag(modifierFlags, NX_ALTERNATEMASK,
147835c4bbdfSmrg                                NX_DEVICELALTKEYMASK | NX_DEVICERALTKEYMASK,
147935c4bbdfSmrg                                NX_DEVICELALTKEYMASK);
14804642e01fSmrg#endif
14814642e01fSmrg
14826747b715Smrg    modifierFlags &= darwin_all_modifier_mask;
14834642e01fSmrg
14844642e01fSmrg    /* We don't receive modifier key events while out of focus, and 3button
14854642e01fSmrg     * emulation mucks this up, so we need to check our modifier flag state
14864642e01fSmrg     * on every event... ugg
14874642e01fSmrg     */
148835c4bbdfSmrg
148935c4bbdfSmrg    if (darwin_all_modifier_flags != modifierFlags)
14904642e01fSmrg        DarwinUpdateModKeys(modifierFlags);
14914642e01fSmrg
149235c4bbdfSmrg    switch ([e type]) {
149335c4bbdfSmrg    case NSLeftMouseDown:
149435c4bbdfSmrg        ev_button = 1;
149535c4bbdfSmrg        ev_type = ButtonPress;
149635c4bbdfSmrg        goto handle_mouse;
149735c4bbdfSmrg
149835c4bbdfSmrg    case NSOtherMouseDown:
149935c4bbdfSmrg        ev_button = 2;
150035c4bbdfSmrg        ev_type = ButtonPress;
150135c4bbdfSmrg        goto handle_mouse;
150235c4bbdfSmrg
150335c4bbdfSmrg    case NSRightMouseDown:
150435c4bbdfSmrg        ev_button = 3;
150535c4bbdfSmrg        ev_type = ButtonPress;
150635c4bbdfSmrg        goto handle_mouse;
150735c4bbdfSmrg
150835c4bbdfSmrg    case NSLeftMouseUp:
150935c4bbdfSmrg        ev_button = 1;
151035c4bbdfSmrg        ev_type = ButtonRelease;
151135c4bbdfSmrg        goto handle_mouse;
151235c4bbdfSmrg
151335c4bbdfSmrg    case NSOtherMouseUp:
151435c4bbdfSmrg        ev_button = 2;
151535c4bbdfSmrg        ev_type = ButtonRelease;
151635c4bbdfSmrg        goto handle_mouse;
151735c4bbdfSmrg
151835c4bbdfSmrg    case NSRightMouseUp:
151935c4bbdfSmrg        ev_button = 3;
152035c4bbdfSmrg        ev_type = ButtonRelease;
152135c4bbdfSmrg        goto handle_mouse;
152235c4bbdfSmrg
152335c4bbdfSmrg    case NSLeftMouseDragged:
152435c4bbdfSmrg        ev_button = 1;
152535c4bbdfSmrg        ev_type = MotionNotify;
152635c4bbdfSmrg        goto handle_mouse;
152735c4bbdfSmrg
152835c4bbdfSmrg    case NSOtherMouseDragged:
152935c4bbdfSmrg        ev_button = 2;
153035c4bbdfSmrg        ev_type = MotionNotify;
153135c4bbdfSmrg        goto handle_mouse;
153235c4bbdfSmrg
153335c4bbdfSmrg    case NSRightMouseDragged:
153435c4bbdfSmrg        ev_button = 3;
153535c4bbdfSmrg        ev_type = MotionNotify;
153635c4bbdfSmrg        goto handle_mouse;
153735c4bbdfSmrg
153835c4bbdfSmrg    case NSMouseMoved:
153935c4bbdfSmrg        ev_button = 0;
154035c4bbdfSmrg        ev_type = MotionNotify;
154135c4bbdfSmrg        goto handle_mouse;
154235c4bbdfSmrg
154335c4bbdfSmrg    case NSTabletPoint:
154435c4bbdfSmrg        ev_button = 0;
154535c4bbdfSmrg        ev_type = MotionNotify;
154635c4bbdfSmrg        goto handle_mouse;
154735c4bbdfSmrg
154835c4bbdfSmrghandle_mouse:
154935c4bbdfSmrg        pDev = darwinPointer;
155035c4bbdfSmrg
155135c4bbdfSmrg        /* NSTabletPoint can have no subtype */
155235c4bbdfSmrg        if ([e type] != NSTabletPoint &&
155335c4bbdfSmrg            [e subtype] == NSTabletProximityEventSubtype) {
155435c4bbdfSmrg            switch ([e pointingDeviceType]) {
155535c4bbdfSmrg            case NSEraserPointingDevice:
155635c4bbdfSmrg                darwinTabletCurrent = darwinTabletEraser;
155735c4bbdfSmrg                break;
155835c4bbdfSmrg
155935c4bbdfSmrg            case NSPenPointingDevice:
156035c4bbdfSmrg                darwinTabletCurrent = darwinTabletStylus;
156135c4bbdfSmrg                break;
156235c4bbdfSmrg
156335c4bbdfSmrg            case NSCursorPointingDevice:
156435c4bbdfSmrg            case NSUnknownPointingDevice:
156535c4bbdfSmrg            default:
156635c4bbdfSmrg                darwinTabletCurrent = darwinTabletCursor;
156735c4bbdfSmrg                break;
15684642e01fSmrg            }
15694642e01fSmrg
157035c4bbdfSmrg            if ([e isEnteringProximity])
157135c4bbdfSmrg                needsProximityIn = YES;
157235c4bbdfSmrg            else
157335c4bbdfSmrg                DarwinSendTabletEvents(darwinTabletCurrent, ProximityOut, 0,
157435c4bbdfSmrg                                       location.x, location.y, pressure,
157535c4bbdfSmrg                                       tilt.x, tilt.y);
157635c4bbdfSmrg            return;
157735c4bbdfSmrg        }
157835c4bbdfSmrg
157935c4bbdfSmrg        if ([e type] == NSTabletPoint ||
158035c4bbdfSmrg            [e subtype] == NSTabletPointEventSubtype) {
158135c4bbdfSmrg            pressure = [e pressure];
158235c4bbdfSmrg            tilt = [e tilt];
158335c4bbdfSmrg
158435c4bbdfSmrg            pDev = darwinTabletCurrent;
158535c4bbdfSmrg
158635c4bbdfSmrg            if (needsProximityIn) {
158735c4bbdfSmrg                DarwinSendTabletEvents(darwinTabletCurrent, ProximityIn, 0,
158835c4bbdfSmrg                                       location.x, location.y, pressure,
158935c4bbdfSmrg                                       tilt.x, tilt.y);
159035c4bbdfSmrg
159135c4bbdfSmrg                needsProximityIn = NO;
15924642e01fSmrg            }
159335c4bbdfSmrg        }
15944642e01fSmrg
159535c4bbdfSmrg        if (!XQuartzServerVisible && noTestExtensions) {
15966747b715Smrg#if defined(XPLUGIN_VERSION) && XPLUGIN_VERSION > 0
159735c4bbdfSmrg            /* Older libXplugin (Tiger/"Stock" Leopard) aren't thread safe, so we can't call xp_find_window from the Appkit thread */
159835c4bbdfSmrg            xp_window_id wid = 0;
159935c4bbdfSmrg            xp_error err;
160035c4bbdfSmrg
160135c4bbdfSmrg            /* Sigh. Need to check that we're really over one of
160235c4bbdfSmrg             * our windows. (We need to receive pointer events while
160335c4bbdfSmrg             * not in the foreground, but we don't want to receive them
160435c4bbdfSmrg             * when another window is over us or we might show a tooltip)
160535c4bbdfSmrg             */
16066747b715Smrg
160735c4bbdfSmrg            err = xp_find_window(location.x, location.y, 0, &wid);
16086747b715Smrg
160935c4bbdfSmrg            if (err != XP_Success || (err == XP_Success && wid == 0))
16104642e01fSmrg#endif
161135c4bbdfSmrg            {
161235c4bbdfSmrg                bgMouseLocation = location;
161335c4bbdfSmrg                bgMouseLocationUpdated = TRUE;
161435c4bbdfSmrg                return;
16156747b715Smrg            }
161635c4bbdfSmrg        }
161735c4bbdfSmrg
161835c4bbdfSmrg        if (bgMouseLocationUpdated) {
161935c4bbdfSmrg            if (!(ev_type == MotionNotify && ev_button == 0)) {
162035c4bbdfSmrg                DarwinSendPointerEvents(darwinPointer, MotionNotify, 0,
162135c4bbdfSmrg                                        location.x, location.y,
162235c4bbdfSmrg                                        0.0, 0.0);
16236747b715Smrg            }
162435c4bbdfSmrg            bgMouseLocationUpdated = FALSE;
162535c4bbdfSmrg        }
16266747b715Smrg
162735c4bbdfSmrg        if (pDev == darwinPointer) {
162835c4bbdfSmrg            DarwinSendPointerEvents(pDev, ev_type, ev_button,
162935c4bbdfSmrg                                    location.x, location.y,
163035c4bbdfSmrg                                    [e deltaX], [e deltaY]);
163135c4bbdfSmrg        } else {
163235c4bbdfSmrg            DarwinSendTabletEvents(pDev, ev_type, ev_button,
163335c4bbdfSmrg                                   location.x, location.y, pressure,
163435c4bbdfSmrg                                   tilt.x, tilt.y);
163535c4bbdfSmrg        }
163635c4bbdfSmrg
163735c4bbdfSmrg        break;
163835c4bbdfSmrg
163935c4bbdfSmrg    case NSTabletProximity:
164035c4bbdfSmrg        switch ([e pointingDeviceType]) {
164135c4bbdfSmrg        case NSEraserPointingDevice:
164235c4bbdfSmrg            darwinTabletCurrent = darwinTabletEraser;
16434642e01fSmrg            break;
164435c4bbdfSmrg
164535c4bbdfSmrg        case NSPenPointingDevice:
164635c4bbdfSmrg            darwinTabletCurrent = darwinTabletStylus;
164735c4bbdfSmrg            break;
164835c4bbdfSmrg
164935c4bbdfSmrg        case NSCursorPointingDevice:
165035c4bbdfSmrg        case NSUnknownPointingDevice:
165135c4bbdfSmrg        default:
165235c4bbdfSmrg            darwinTabletCurrent = darwinTabletCursor;
16534642e01fSmrg            break;
165435c4bbdfSmrg        }
165535c4bbdfSmrg
165635c4bbdfSmrg        if ([e isEnteringProximity])
165735c4bbdfSmrg            needsProximityIn = YES;
165835c4bbdfSmrg        else
165935c4bbdfSmrg            DarwinSendTabletEvents(darwinTabletCurrent, ProximityOut, 0,
166035c4bbdfSmrg                                   location.x, location.y, pressure,
166135c4bbdfSmrg                                   tilt.x, tilt.y);
166235c4bbdfSmrg        break;
166335c4bbdfSmrg
166435c4bbdfSmrg    case NSScrollWheel:
166535c4bbdfSmrg    {
166635c4bbdfSmrg#if MAC_OS_X_VERSION_MAX_ALLOWED < 1050
166735c4bbdfSmrg        float deltaX = [e deltaX];
166835c4bbdfSmrg        float deltaY = [e deltaY];
166935c4bbdfSmrg        BOOL isContinuous = NO;
167035c4bbdfSmrg#else
167135c4bbdfSmrg        CGFloat deltaX = [e deltaX];
167235c4bbdfSmrg        CGFloat deltaY = [e deltaY];
167335c4bbdfSmrg        CGEventRef cge = [e CGEvent];
167435c4bbdfSmrg        BOOL isContinuous =
167535c4bbdfSmrg            CGEventGetIntegerValueField(cge, kCGScrollWheelEventIsContinuous);
167635c4bbdfSmrg
167735c4bbdfSmrg#if 0
167835c4bbdfSmrg        /* Scale the scroll value by line height */
167935c4bbdfSmrg        CGEventSourceRef source = CGEventCreateSourceFromEvent(cge);
168035c4bbdfSmrg        if (source) {
168135c4bbdfSmrg            double lineHeight = CGEventSourceGetPixelsPerLine(source);
168235c4bbdfSmrg            CFRelease(source);
16834642e01fSmrg            
168435c4bbdfSmrg            /* There's no real reason for the 1/5 ratio here other than that
168535c4bbdfSmrg             * it feels like a good ratio after some testing.
168635c4bbdfSmrg             */
168735c4bbdfSmrg            
168835c4bbdfSmrg            deltaX *= lineHeight / 5.0;
168935c4bbdfSmrg            deltaY *= lineHeight / 5.0;
169035c4bbdfSmrg        }
169135c4bbdfSmrg#endif
169235c4bbdfSmrg#endif
169335c4bbdfSmrg        
16946747b715Smrg#if !defined(XPLUGIN_VERSION) || XPLUGIN_VERSION == 0
169535c4bbdfSmrg        /* If we're in the background, we need to send a MotionNotify event
169635c4bbdfSmrg         * first, since we aren't getting them on background mouse motion
169735c4bbdfSmrg         */
169835c4bbdfSmrg        if (!XQuartzServerVisible && noTestExtensions) {
169935c4bbdfSmrg            bgMouseLocationUpdated = FALSE;
170035c4bbdfSmrg            DarwinSendPointerEvents(darwinPointer, MotionNotify, 0,
170135c4bbdfSmrg                                    location.x, location.y,
170235c4bbdfSmrg                                    0.0, 0.0);
170335c4bbdfSmrg        }
17046747b715Smrg#endif
1705475c125cSmrg#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
170635c4bbdfSmrg        // TODO: Change 1117 to NSAppKitVersionNumber10_7 when it is defined
170735c4bbdfSmrg        if (NSAppKitVersionNumber >= 1117 &&
170835c4bbdfSmrg            XQuartzScrollInDeviceDirection &&
170935c4bbdfSmrg            [e isDirectionInvertedFromDevice]) {
171035c4bbdfSmrg            deltaX *= -1;
171135c4bbdfSmrg            deltaY *= -1;
171235c4bbdfSmrg        }
1713475c125cSmrg#endif
171435c4bbdfSmrg        /* This hack is in place to better deal with "clicky" scroll wheels:
171535c4bbdfSmrg         * http://xquartz.macosforge.org/trac/ticket/562
171635c4bbdfSmrg         */
171735c4bbdfSmrg        if (!isContinuous) {
171835c4bbdfSmrg            static NSTimeInterval lastScrollTime = 0.0;
171935c4bbdfSmrg
172035c4bbdfSmrg            /* These store how much extra we have already scrolled.
172135c4bbdfSmrg             * ie, this is how much we ignore on the next event.
172235c4bbdfSmrg             */
172335c4bbdfSmrg            static double deficit_x = 0.0;
172435c4bbdfSmrg            static double deficit_y = 0.0;
172535c4bbdfSmrg
172635c4bbdfSmrg            /* If we have past a second since the last scroll, wipe the slate
172735c4bbdfSmrg             * clean
172835c4bbdfSmrg             */
172935c4bbdfSmrg            if ([e timestamp] - lastScrollTime > 1.0) {
173035c4bbdfSmrg                deficit_x = deficit_y = 0.0;
1731475c125cSmrg            }
173235c4bbdfSmrg            lastScrollTime = [e timestamp];
173335c4bbdfSmrg
173435c4bbdfSmrg            if (deltaX != 0.0) {
173535c4bbdfSmrg                /* If we changed directions, wipe the slate clean */
173635c4bbdfSmrg                if ((deficit_x < 0.0 && deltaX > 0.0) ||
173735c4bbdfSmrg                    (deficit_x > 0.0 && deltaX < 0.0)) {
173835c4bbdfSmrg                    deficit_x = 0.0;
173935c4bbdfSmrg                }
174035c4bbdfSmrg
174135c4bbdfSmrg                /* Eat up the deficit, but ensure that something is
174235c4bbdfSmrg                 * always sent 
17436747b715Smrg                 */
174435c4bbdfSmrg                if (fabs(deltaX) > fabs(deficit_x)) {
174535c4bbdfSmrg                    deltaX -= deficit_x;
174635c4bbdfSmrg
174735c4bbdfSmrg                    if (deltaX > 0.0) {
174835c4bbdfSmrg                        deficit_x = ceil(deltaX) - deltaX;
174935c4bbdfSmrg                        deltaX = ceil(deltaX);
175035c4bbdfSmrg                    } else {
175135c4bbdfSmrg                        deficit_x = floor(deltaX) - deltaX;
175235c4bbdfSmrg                        deltaX = floor(deltaX);
175335c4bbdfSmrg                    }
175435c4bbdfSmrg                } else {
175535c4bbdfSmrg                    deficit_x -= deltaX;
175635c4bbdfSmrg
175735c4bbdfSmrg                    if (deltaX > 0.0) {
175835c4bbdfSmrg                        deltaX = 1.0;
175935c4bbdfSmrg                    } else {
176035c4bbdfSmrg                        deltaX = -1.0;
176135c4bbdfSmrg                    }
176235c4bbdfSmrg
176335c4bbdfSmrg                    deficit_x += deltaX;
17646747b715Smrg                }
17656747b715Smrg            }
17666747b715Smrg
176735c4bbdfSmrg            if (deltaY != 0.0) {
176835c4bbdfSmrg                /* If we changed directions, wipe the slate clean */
176935c4bbdfSmrg                if ((deficit_y < 0.0 && deltaY > 0.0) ||
177035c4bbdfSmrg                    (deficit_y > 0.0 && deltaY < 0.0)) {
177135c4bbdfSmrg                    deficit_y = 0.0;
177235c4bbdfSmrg                }
177335c4bbdfSmrg
177435c4bbdfSmrg                /* Eat up the deficit, but ensure that something is
177535c4bbdfSmrg                 * always sent 
177635c4bbdfSmrg                 */
177735c4bbdfSmrg                if (fabs(deltaY) > fabs(deficit_y)) {
177835c4bbdfSmrg                    deltaY -= deficit_y;
177935c4bbdfSmrg
178035c4bbdfSmrg                    if (deltaY > 0.0) {
178135c4bbdfSmrg                        deficit_y = ceil(deltaY) - deltaY;
178235c4bbdfSmrg                        deltaY = ceil(deltaY);
178335c4bbdfSmrg                    } else {
178435c4bbdfSmrg                        deficit_y = floor(deltaY) - deltaY;
178535c4bbdfSmrg                        deltaY = floor(deltaY);
178635c4bbdfSmrg                    }
17874642e01fSmrg                } else {
178835c4bbdfSmrg                    deficit_y -= deltaY;
178935c4bbdfSmrg
179035c4bbdfSmrg                    if (deltaY > 0.0) {
179135c4bbdfSmrg                        deltaY = 1.0;
179235c4bbdfSmrg                    } else {
179335c4bbdfSmrg                        deltaY = -1.0;
179435c4bbdfSmrg                    }
179535c4bbdfSmrg
179635c4bbdfSmrg                    deficit_y += deltaY;
179735c4bbdfSmrg                }
179835c4bbdfSmrg            }
179935c4bbdfSmrg        }
180035c4bbdfSmrg
180135c4bbdfSmrg        DarwinSendScrollEvents(deltaX, deltaY);
180235c4bbdfSmrg        break;
180335c4bbdfSmrg    }
180435c4bbdfSmrg
180535c4bbdfSmrg    case NSKeyDown:
180635c4bbdfSmrg    case NSKeyUp:
180735c4bbdfSmrg    {
180835c4bbdfSmrg        /* XKB clobbers our keymap at startup, so we need to force it on the first keypress.
180935c4bbdfSmrg         * TODO: Make this less of a kludge.
181035c4bbdfSmrg         */
181135c4bbdfSmrg        static int force_resync_keymap = YES;
181235c4bbdfSmrg        if (force_resync_keymap) {
181335c4bbdfSmrg            DarwinSendDDXEvent(kXquartzReloadKeymap, 0);
181435c4bbdfSmrg            force_resync_keymap = NO;
181535c4bbdfSmrg        }
181635c4bbdfSmrg    }
181735c4bbdfSmrg
181835c4bbdfSmrg        if (darwinSyncKeymap) {
181935c4bbdfSmrg#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1050
182035c4bbdfSmrg            TISInputSourceRef key_layout = 
182135c4bbdfSmrg                TISCopyCurrentKeyboardLayoutInputSource();
182235c4bbdfSmrg            TISInputSourceRef clear;
182335c4bbdfSmrg            if (CFEqual(key_layout, last_key_layout)) {
182435c4bbdfSmrg                CFRelease(key_layout);
182535c4bbdfSmrg            }
182635c4bbdfSmrg            else {
182735c4bbdfSmrg                /* Swap/free thread-safely */
182835c4bbdfSmrg                clear = last_key_layout;
182935c4bbdfSmrg                last_key_layout = key_layout;
183035c4bbdfSmrg                CFRelease(clear);
18314642e01fSmrg#else
183235c4bbdfSmrg            KeyboardLayoutRef key_layout;
183335c4bbdfSmrg            KLGetCurrentKeyboardLayout(&key_layout);
183435c4bbdfSmrg            if (key_layout != last_key_layout) {
183535c4bbdfSmrg                last_key_layout = key_layout;
18364642e01fSmrg#endif
183735c4bbdfSmrg                /* Update keyInfo */
183835c4bbdfSmrg                if (!QuartsResyncKeymap(TRUE)) {
183935c4bbdfSmrg                    ErrorF(
184035c4bbdfSmrg                        "sendX11NSEvent: Could not build a valid keymap.\n");
18414642e01fSmrg                }
18424642e01fSmrg            }
184335c4bbdfSmrg        }
18444642e01fSmrg
184535c4bbdfSmrg        ev_type = ([e type] == NSKeyDown) ? KeyPress : KeyRelease;
184635c4bbdfSmrg        DarwinSendKeyboardEvents(ev_type, [e keyCode]);
184735c4bbdfSmrg        break;
18484642e01fSmrg
184935c4bbdfSmrg    default:
185035c4bbdfSmrg        break;              /* for gcc */
185135c4bbdfSmrg    }
18524642e01fSmrg}
18534642e01fSmrg@end
1854