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