1*4882a593Smuzhiyun/* X11Application.m -- subclass of NSApplication to multiplex events 2*4882a593Smuzhiyun * 3*4882a593Smuzhiyun * Copyright (c) 2002-2012 Apple Inc. All rights reserved. 4*4882a593Smuzhiyun * 5*4882a593Smuzhiyun * Permission is hereby granted, free of charge, to any person 6*4882a593Smuzhiyun * obtaining a copy of this software and associated documentation files 7*4882a593Smuzhiyun * (the "Software"), to deal in the Software without restriction, 8*4882a593Smuzhiyun * including without limitation the rights to use, copy, modify, merge, 9*4882a593Smuzhiyun * publish, distribute, sublicense, and/or sell copies of the Software, 10*4882a593Smuzhiyun * and to permit persons to whom the Software is furnished to do so, 11*4882a593Smuzhiyun * subject to the following conditions: 12*4882a593Smuzhiyun * 13*4882a593Smuzhiyun * The above copyright notice and this permission notice shall be 14*4882a593Smuzhiyun * included in all copies or substantial portions of the Software. 15*4882a593Smuzhiyun * 16*4882a593Smuzhiyun * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17*4882a593Smuzhiyun * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18*4882a593Smuzhiyun * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19*4882a593Smuzhiyun * NONINFRINGEMENT. IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT 20*4882a593Smuzhiyun * HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 21*4882a593Smuzhiyun * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22*4882a593Smuzhiyun * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23*4882a593Smuzhiyun * DEALINGS IN THE SOFTWARE. 24*4882a593Smuzhiyun * 25*4882a593Smuzhiyun * Except as contained in this notice, the name(s) of the above 26*4882a593Smuzhiyun * copyright holders shall not be used in advertising or otherwise to 27*4882a593Smuzhiyun * promote the sale, use or other dealings in this Software without 28*4882a593Smuzhiyun * prior written authorization. 29*4882a593Smuzhiyun */ 30*4882a593Smuzhiyun 31*4882a593Smuzhiyun#include "sanitizedCarbon.h" 32*4882a593Smuzhiyun 33*4882a593Smuzhiyun#ifdef HAVE_DIX_CONFIG_H 34*4882a593Smuzhiyun#include <dix-config.h> 35*4882a593Smuzhiyun#endif 36*4882a593Smuzhiyun 37*4882a593Smuzhiyun#import "X11Application.h" 38*4882a593Smuzhiyun 39*4882a593Smuzhiyun#include "darwin.h" 40*4882a593Smuzhiyun#include "quartz.h" 41*4882a593Smuzhiyun#include "darwinEvents.h" 42*4882a593Smuzhiyun#include "quartzKeyboard.h" 43*4882a593Smuzhiyun#include <X11/extensions/applewmconst.h> 44*4882a593Smuzhiyun#include "micmap.h" 45*4882a593Smuzhiyun#include "exglobals.h" 46*4882a593Smuzhiyun 47*4882a593Smuzhiyun#include <mach/mach.h> 48*4882a593Smuzhiyun#include <unistd.h> 49*4882a593Smuzhiyun 50*4882a593Smuzhiyun#include <pthread.h> 51*4882a593Smuzhiyun 52*4882a593Smuzhiyun#include <Xplugin.h> 53*4882a593Smuzhiyun 54*4882a593Smuzhiyun// pbproxy/pbproxy.h 55*4882a593Smuzhiyunextern int 56*4882a593Smuzhiyunxpbproxy_run(void); 57*4882a593Smuzhiyun 58*4882a593Smuzhiyun#define DEFAULTS_FILE X11LIBDIR "/X11/xserver/Xquartz.plist" 59*4882a593Smuzhiyun 60*4882a593Smuzhiyun#ifndef XSERVER_VERSION 61*4882a593Smuzhiyun#define XSERVER_VERSION "?" 62*4882a593Smuzhiyun#endif 63*4882a593Smuzhiyun 64*4882a593Smuzhiyun#include <dispatch/dispatch.h> 65*4882a593Smuzhiyun 66*4882a593Smuzhiyunstatic dispatch_queue_t eventTranslationQueue; 67*4882a593Smuzhiyun 68*4882a593Smuzhiyun#ifndef __has_feature 69*4882a593Smuzhiyun#define __has_feature(x) 0 70*4882a593Smuzhiyun#endif 71*4882a593Smuzhiyun 72*4882a593Smuzhiyun#ifndef CF_RETURNS_RETAINED 73*4882a593Smuzhiyun#if __has_feature(attribute_cf_returns_retained) 74*4882a593Smuzhiyun#define CF_RETURNS_RETAINED __attribute__((cf_returns_retained)) 75*4882a593Smuzhiyun#else 76*4882a593Smuzhiyun#define CF_RETURNS_RETAINED 77*4882a593Smuzhiyun#endif 78*4882a593Smuzhiyun#endif 79*4882a593Smuzhiyun 80*4882a593Smuzhiyunextern Bool noTestExtensions; 81*4882a593Smuzhiyunextern Bool noRenderExtension; 82*4882a593Smuzhiyun 83*4882a593Smuzhiyunstatic TISInputSourceRef last_key_layout; 84*4882a593Smuzhiyun 85*4882a593Smuzhiyun/* This preference is only tested on Lion or later as it's not relevant to 86*4882a593Smuzhiyun * earlier OS versions. 87*4882a593Smuzhiyun */ 88*4882a593SmuzhiyunBool XQuartzScrollInDeviceDirection = FALSE; 89*4882a593Smuzhiyun 90*4882a593Smuzhiyunextern int darwinFakeButtons; 91*4882a593Smuzhiyun 92*4882a593Smuzhiyun/* Store the mouse location while in the background, and update X11's pointer 93*4882a593Smuzhiyun * location when we become the foreground application 94*4882a593Smuzhiyun */ 95*4882a593Smuzhiyunstatic NSPoint bgMouseLocation; 96*4882a593Smuzhiyunstatic BOOL bgMouseLocationUpdated = FALSE; 97*4882a593Smuzhiyun 98*4882a593SmuzhiyunX11Application *X11App; 99*4882a593Smuzhiyun 100*4882a593SmuzhiyunCFStringRef app_prefs_domain_cfstr = NULL; 101*4882a593Smuzhiyun 102*4882a593Smuzhiyun#define ALL_KEY_MASKS (NSShiftKeyMask | NSControlKeyMask | \ 103*4882a593Smuzhiyun NSAlternateKeyMask | NSCommandKeyMask) 104*4882a593Smuzhiyun 105*4882a593Smuzhiyun@interface NSApplication (Internal) 106*4882a593Smuzhiyun- (void)_setKeyWindow:(id)window; 107*4882a593Smuzhiyun- (void)_setMainWindow:(id)window; 108*4882a593Smuzhiyun@end 109*4882a593Smuzhiyun 110*4882a593Smuzhiyun@interface X11Application (Private) 111*4882a593Smuzhiyun- (void) sendX11NSEvent:(NSEvent *)e; 112*4882a593Smuzhiyun@end 113*4882a593Smuzhiyun 114*4882a593Smuzhiyun@interface X11Application () 115*4882a593Smuzhiyun@property (nonatomic, readwrite, assign) OSX_BOOL x_active; 116*4882a593Smuzhiyun@end 117*4882a593Smuzhiyun 118*4882a593Smuzhiyun@implementation X11Application 119*4882a593Smuzhiyun 120*4882a593Smuzhiyuntypedef struct message_struct message; 121*4882a593Smuzhiyunstruct message_struct { 122*4882a593Smuzhiyun mach_msg_header_t hdr; 123*4882a593Smuzhiyun SEL selector; 124*4882a593Smuzhiyun NSObject *arg; 125*4882a593Smuzhiyun}; 126*4882a593Smuzhiyun 127*4882a593Smuzhiyun/* Quartz mode initialization routine. This is often dynamically loaded 128*4882a593Smuzhiyun but is statically linked into this X server. */ 129*4882a593SmuzhiyunBool 130*4882a593SmuzhiyunQuartzModeBundleInit(void); 131*4882a593Smuzhiyun 132*4882a593Smuzhiyun- (void) dealloc 133*4882a593Smuzhiyun{ 134*4882a593Smuzhiyun self.controller = nil; 135*4882a593Smuzhiyun [super dealloc]; 136*4882a593Smuzhiyun} 137*4882a593Smuzhiyun 138*4882a593Smuzhiyun- (void) orderFrontStandardAboutPanel: (id) sender 139*4882a593Smuzhiyun{ 140*4882a593Smuzhiyun NSMutableDictionary *dict; 141*4882a593Smuzhiyun NSDictionary *infoDict; 142*4882a593Smuzhiyun NSString *tem; 143*4882a593Smuzhiyun 144*4882a593Smuzhiyun dict = [NSMutableDictionary dictionaryWithCapacity:3]; 145*4882a593Smuzhiyun infoDict = [[NSBundle mainBundle] infoDictionary]; 146*4882a593Smuzhiyun 147*4882a593Smuzhiyun [dict setObject: NSLocalizedString(@"The X Window System", @"About panel") 148*4882a593Smuzhiyun forKey:@"ApplicationName"]; 149*4882a593Smuzhiyun 150*4882a593Smuzhiyun tem = [infoDict objectForKey:@"CFBundleShortVersionString"]; 151*4882a593Smuzhiyun 152*4882a593Smuzhiyun [dict setObject:[NSString stringWithFormat:@"XQuartz %@", tem] 153*4882a593Smuzhiyun forKey:@"ApplicationVersion"]; 154*4882a593Smuzhiyun 155*4882a593Smuzhiyun [dict setObject:[NSString stringWithFormat:@"xorg-server %s", 156*4882a593Smuzhiyun XSERVER_VERSION] 157*4882a593Smuzhiyun forKey:@"Version"]; 158*4882a593Smuzhiyun 159*4882a593Smuzhiyun [self orderFrontStandardAboutPanelWithOptions: dict]; 160*4882a593Smuzhiyun} 161*4882a593Smuzhiyun 162*4882a593Smuzhiyun- (void) activateX:(OSX_BOOL)state 163*4882a593Smuzhiyun{ 164*4882a593Smuzhiyun OSX_BOOL const x_active = self.x_active; 165*4882a593Smuzhiyun 166*4882a593Smuzhiyun if (x_active == state) 167*4882a593Smuzhiyun return; 168*4882a593Smuzhiyun 169*4882a593Smuzhiyun DEBUG_LOG("state=%d, x_active=%d, \n", state, x_active); 170*4882a593Smuzhiyun if (state) { 171*4882a593Smuzhiyun if (bgMouseLocationUpdated) { 172*4882a593Smuzhiyun DarwinSendPointerEvents(darwinPointer, MotionNotify, 0, 173*4882a593Smuzhiyun bgMouseLocation.x, bgMouseLocation.y, 174*4882a593Smuzhiyun 0.0, 0.0); 175*4882a593Smuzhiyun bgMouseLocationUpdated = FALSE; 176*4882a593Smuzhiyun } 177*4882a593Smuzhiyun DarwinSendDDXEvent(kXquartzActivate, 0); 178*4882a593Smuzhiyun } 179*4882a593Smuzhiyun else { 180*4882a593Smuzhiyun 181*4882a593Smuzhiyun if (darwin_all_modifier_flags) 182*4882a593Smuzhiyun DarwinUpdateModKeys(0); 183*4882a593Smuzhiyun 184*4882a593Smuzhiyun DarwinInputReleaseButtonsAndKeys(darwinKeyboard); 185*4882a593Smuzhiyun DarwinInputReleaseButtonsAndKeys(darwinPointer); 186*4882a593Smuzhiyun DarwinInputReleaseButtonsAndKeys(darwinTabletCursor); 187*4882a593Smuzhiyun DarwinInputReleaseButtonsAndKeys(darwinTabletStylus); 188*4882a593Smuzhiyun DarwinInputReleaseButtonsAndKeys(darwinTabletEraser); 189*4882a593Smuzhiyun 190*4882a593Smuzhiyun DarwinSendDDXEvent(kXquartzDeactivate, 0); 191*4882a593Smuzhiyun } 192*4882a593Smuzhiyun 193*4882a593Smuzhiyun self.x_active = state; 194*4882a593Smuzhiyun} 195*4882a593Smuzhiyun 196*4882a593Smuzhiyun- (void) became_key:(NSWindow *)win 197*4882a593Smuzhiyun{ 198*4882a593Smuzhiyun [self activateX:NO]; 199*4882a593Smuzhiyun} 200*4882a593Smuzhiyun 201*4882a593Smuzhiyun- (void) sendEvent:(NSEvent *)e 202*4882a593Smuzhiyun{ 203*4882a593Smuzhiyun /* Don't try sending to X if we haven't initialized. This can happen if AppKit takes over 204*4882a593Smuzhiyun * (eg: uncaught exception) early in launch. 205*4882a593Smuzhiyun */ 206*4882a593Smuzhiyun if (!eventTranslationQueue) { 207*4882a593Smuzhiyun [super sendEvent:e]; 208*4882a593Smuzhiyun return; 209*4882a593Smuzhiyun } 210*4882a593Smuzhiyun 211*4882a593Smuzhiyun OSX_BOOL for_appkit, for_x; 212*4882a593Smuzhiyun OSX_BOOL const x_active = self.x_active; 213*4882a593Smuzhiyun 214*4882a593Smuzhiyun /* By default pass down the responder chain and to X. */ 215*4882a593Smuzhiyun for_appkit = YES; 216*4882a593Smuzhiyun for_x = YES; 217*4882a593Smuzhiyun 218*4882a593Smuzhiyun switch ([e type]) { 219*4882a593Smuzhiyun case NSLeftMouseDown: 220*4882a593Smuzhiyun case NSRightMouseDown: 221*4882a593Smuzhiyun case NSOtherMouseDown: 222*4882a593Smuzhiyun case NSLeftMouseUp: 223*4882a593Smuzhiyun case NSRightMouseUp: 224*4882a593Smuzhiyun case NSOtherMouseUp: 225*4882a593Smuzhiyun if ([e window] != nil) { 226*4882a593Smuzhiyun /* Pointer event has an (AppKit) window. Probably something for the kit. */ 227*4882a593Smuzhiyun for_x = NO; 228*4882a593Smuzhiyun if (x_active) [self activateX:NO]; 229*4882a593Smuzhiyun } 230*4882a593Smuzhiyun else if ([self modalWindow] == nil) { 231*4882a593Smuzhiyun /* Must be an X window. Tell appkit windows to resign main/key */ 232*4882a593Smuzhiyun for_appkit = NO; 233*4882a593Smuzhiyun 234*4882a593Smuzhiyun if (!x_active && quartzProcs->IsX11Window([e windowNumber])) { 235*4882a593Smuzhiyun if ([self respondsToSelector:@selector(_setKeyWindow:)] && [self respondsToSelector:@selector(_setMainWindow:)]) { 236*4882a593Smuzhiyun NSWindow *keyWindow = [self keyWindow]; 237*4882a593Smuzhiyun if (keyWindow) { 238*4882a593Smuzhiyun [self _setKeyWindow:nil]; 239*4882a593Smuzhiyun [keyWindow resignKeyWindow]; 240*4882a593Smuzhiyun } 241*4882a593Smuzhiyun 242*4882a593Smuzhiyun NSWindow *mainWindow = [self mainWindow]; 243*4882a593Smuzhiyun if (mainWindow) { 244*4882a593Smuzhiyun [self _setMainWindow:nil]; 245*4882a593Smuzhiyun [mainWindow resignMainWindow]; 246*4882a593Smuzhiyun } 247*4882a593Smuzhiyun } else { 248*4882a593Smuzhiyun /* This has a side effect of causing background apps to steal focus from XQuartz. 249*4882a593Smuzhiyun * Unfortunately, there is no public and stable API to do what we want, but this 250*4882a593Smuzhiyun * is a decent fallback in the off chance that the above selectors get dropped 251*4882a593Smuzhiyun * in the future. 252*4882a593Smuzhiyun */ 253*4882a593Smuzhiyun [self deactivate]; 254*4882a593Smuzhiyun } 255*4882a593Smuzhiyun 256*4882a593Smuzhiyun [self activateX:YES]; 257*4882a593Smuzhiyun } 258*4882a593Smuzhiyun } 259*4882a593Smuzhiyun 260*4882a593Smuzhiyun /* We want to force sending to appkit if we're over the menu bar */ 261*4882a593Smuzhiyun if (!for_appkit) { 262*4882a593Smuzhiyun NSPoint NSlocation = [e locationInWindow]; 263*4882a593Smuzhiyun NSWindow *window = [e window]; 264*4882a593Smuzhiyun NSRect NSframe, NSvisibleFrame; 265*4882a593Smuzhiyun CGRect CGframe, CGvisibleFrame; 266*4882a593Smuzhiyun CGPoint CGlocation; 267*4882a593Smuzhiyun 268*4882a593Smuzhiyun if (window != nil) { 269*4882a593Smuzhiyun NSRect frame = [window frame]; 270*4882a593Smuzhiyun NSlocation.x += frame.origin.x; 271*4882a593Smuzhiyun NSlocation.y += frame.origin.y; 272*4882a593Smuzhiyun } 273*4882a593Smuzhiyun 274*4882a593Smuzhiyun NSframe = [[NSScreen mainScreen] frame]; 275*4882a593Smuzhiyun NSvisibleFrame = [[NSScreen mainScreen] visibleFrame]; 276*4882a593Smuzhiyun 277*4882a593Smuzhiyun CGframe = CGRectMake(NSframe.origin.x, NSframe.origin.y, 278*4882a593Smuzhiyun NSframe.size.width, NSframe.size.height); 279*4882a593Smuzhiyun CGvisibleFrame = CGRectMake(NSvisibleFrame.origin.x, 280*4882a593Smuzhiyun NSvisibleFrame.origin.y, 281*4882a593Smuzhiyun NSvisibleFrame.size.width, 282*4882a593Smuzhiyun NSvisibleFrame.size.height); 283*4882a593Smuzhiyun CGlocation = CGPointMake(NSlocation.x, NSlocation.y); 284*4882a593Smuzhiyun 285*4882a593Smuzhiyun if (CGRectContainsPoint(CGframe, CGlocation) && 286*4882a593Smuzhiyun !CGRectContainsPoint(CGvisibleFrame, CGlocation)) 287*4882a593Smuzhiyun for_appkit = YES; 288*4882a593Smuzhiyun } 289*4882a593Smuzhiyun 290*4882a593Smuzhiyun break; 291*4882a593Smuzhiyun 292*4882a593Smuzhiyun case NSKeyDown: 293*4882a593Smuzhiyun case NSKeyUp: 294*4882a593Smuzhiyun 295*4882a593Smuzhiyun if (_x_active) { 296*4882a593Smuzhiyun static BOOL do_swallow = NO; 297*4882a593Smuzhiyun static int swallow_keycode; 298*4882a593Smuzhiyun 299*4882a593Smuzhiyun if ([e type] == NSKeyDown) { 300*4882a593Smuzhiyun /* Before that though, see if there are any global 301*4882a593Smuzhiyun * shortcuts bound to it. */ 302*4882a593Smuzhiyun 303*4882a593Smuzhiyun if (darwinAppKitModMask &[e modifierFlags]) { 304*4882a593Smuzhiyun /* Override to force sending to Appkit */ 305*4882a593Smuzhiyun swallow_keycode = [e keyCode]; 306*4882a593Smuzhiyun do_swallow = YES; 307*4882a593Smuzhiyun for_x = NO; 308*4882a593Smuzhiyun } else if (XQuartzEnableKeyEquivalents && 309*4882a593Smuzhiyun xp_is_symbolic_hotkey_event([e eventRef])) { 310*4882a593Smuzhiyun swallow_keycode = [e keyCode]; 311*4882a593Smuzhiyun do_swallow = YES; 312*4882a593Smuzhiyun for_x = NO; 313*4882a593Smuzhiyun } 314*4882a593Smuzhiyun else if (XQuartzEnableKeyEquivalents && 315*4882a593Smuzhiyun [[self mainMenu] performKeyEquivalent:e]) { 316*4882a593Smuzhiyun swallow_keycode = [e keyCode]; 317*4882a593Smuzhiyun do_swallow = YES; 318*4882a593Smuzhiyun for_appkit = NO; 319*4882a593Smuzhiyun for_x = NO; 320*4882a593Smuzhiyun } 321*4882a593Smuzhiyun else if (!XQuartzIsRootless 322*4882a593Smuzhiyun && ([e modifierFlags] & ALL_KEY_MASKS) == 323*4882a593Smuzhiyun (NSCommandKeyMask | NSAlternateKeyMask) 324*4882a593Smuzhiyun && ([e keyCode] == 0 /*a*/ || [e keyCode] == 325*4882a593Smuzhiyun 53 /*Esc*/)) { 326*4882a593Smuzhiyun /* We have this here to force processing fullscreen 327*4882a593Smuzhiyun * toggle even if XQuartzEnableKeyEquivalents is disabled */ 328*4882a593Smuzhiyun swallow_keycode = [e keyCode]; 329*4882a593Smuzhiyun do_swallow = YES; 330*4882a593Smuzhiyun for_x = NO; 331*4882a593Smuzhiyun for_appkit = NO; 332*4882a593Smuzhiyun DarwinSendDDXEvent(kXquartzToggleFullscreen, 0); 333*4882a593Smuzhiyun } 334*4882a593Smuzhiyun else { 335*4882a593Smuzhiyun /* No kit window is focused, so send it to X. */ 336*4882a593Smuzhiyun for_appkit = NO; 337*4882a593Smuzhiyun 338*4882a593Smuzhiyun /* Reset our swallow state if we're seeing the same keyCode again. 339*4882a593Smuzhiyun * This can happen if we become !_x_active when the keyCode we 340*4882a593Smuzhiyun * intended to swallow is delivered. See: 341*4882a593Smuzhiyun * https://bugs.freedesktop.org/show_bug.cgi?id=92648 342*4882a593Smuzhiyun */ 343*4882a593Smuzhiyun if ([e keyCode] == swallow_keycode) { 344*4882a593Smuzhiyun do_swallow = NO; 345*4882a593Smuzhiyun } 346*4882a593Smuzhiyun } 347*4882a593Smuzhiyun } 348*4882a593Smuzhiyun else { /* KeyUp */ 349*4882a593Smuzhiyun /* If we saw a key equivalent on the down, don't pass 350*4882a593Smuzhiyun * the up through to X. */ 351*4882a593Smuzhiyun if (do_swallow && [e keyCode] == swallow_keycode) { 352*4882a593Smuzhiyun do_swallow = NO; 353*4882a593Smuzhiyun for_x = NO; 354*4882a593Smuzhiyun } 355*4882a593Smuzhiyun } 356*4882a593Smuzhiyun } 357*4882a593Smuzhiyun else { /* !_x_active */ 358*4882a593Smuzhiyun for_x = NO; 359*4882a593Smuzhiyun } 360*4882a593Smuzhiyun break; 361*4882a593Smuzhiyun 362*4882a593Smuzhiyun case NSFlagsChanged: 363*4882a593Smuzhiyun /* Don't tell X11 about modifiers changing while it's not active */ 364*4882a593Smuzhiyun if (!_x_active) 365*4882a593Smuzhiyun for_x = NO; 366*4882a593Smuzhiyun break; 367*4882a593Smuzhiyun 368*4882a593Smuzhiyun case NSAppKitDefined: 369*4882a593Smuzhiyun switch ([e subtype]) { 370*4882a593Smuzhiyun static BOOL x_was_active = NO; 371*4882a593Smuzhiyun 372*4882a593Smuzhiyun case NSApplicationActivatedEventType: 373*4882a593Smuzhiyun for_x = NO; 374*4882a593Smuzhiyun if ([e window] == nil && x_was_active) { 375*4882a593Smuzhiyun BOOL order_all_windows = YES, workspaces, ok; 376*4882a593Smuzhiyun for_appkit = NO; 377*4882a593Smuzhiyun 378*4882a593Smuzhiyun /* FIXME: This is a hack to avoid passing the event to AppKit which 379*4882a593Smuzhiyun * would result in it raising one of its windows. 380*4882a593Smuzhiyun */ 381*4882a593Smuzhiyun _appFlags._active = YES; 382*4882a593Smuzhiyun 383*4882a593Smuzhiyun [self set_front_process:nil]; 384*4882a593Smuzhiyun 385*4882a593Smuzhiyun /* Get the Spaces preference for SwitchOnActivate */ 386*4882a593Smuzhiyun (void)CFPreferencesAppSynchronize(CFSTR("com.apple.dock")); 387*4882a593Smuzhiyun workspaces = 388*4882a593Smuzhiyun CFPreferencesGetAppBooleanValue(CFSTR("workspaces"), 389*4882a593Smuzhiyun CFSTR( 390*4882a593Smuzhiyun "com.apple.dock"), 391*4882a593Smuzhiyun &ok); 392*4882a593Smuzhiyun if (!ok) 393*4882a593Smuzhiyun workspaces = NO; 394*4882a593Smuzhiyun 395*4882a593Smuzhiyun if (workspaces) { 396*4882a593Smuzhiyun (void)CFPreferencesAppSynchronize(CFSTR( 397*4882a593Smuzhiyun ".GlobalPreferences")); 398*4882a593Smuzhiyun order_all_windows = 399*4882a593Smuzhiyun CFPreferencesGetAppBooleanValue(CFSTR( 400*4882a593Smuzhiyun "AppleSpacesSwitchOnActivate"), 401*4882a593Smuzhiyun CFSTR( 402*4882a593Smuzhiyun ".GlobalPreferences"), 403*4882a593Smuzhiyun &ok); 404*4882a593Smuzhiyun if (!ok) 405*4882a593Smuzhiyun order_all_windows = YES; 406*4882a593Smuzhiyun } 407*4882a593Smuzhiyun 408*4882a593Smuzhiyun /* TODO: In the workspaces && !AppleSpacesSwitchOnActivate case, the windows are ordered 409*4882a593Smuzhiyun * correctly, but we need to activate the top window on this space if there is 410*4882a593Smuzhiyun * none active. 411*4882a593Smuzhiyun * 412*4882a593Smuzhiyun * If there are no active windows, and there are minimized windows, we should 413*4882a593Smuzhiyun * be restoring one of them. 414*4882a593Smuzhiyun */ 415*4882a593Smuzhiyun if ([e data2] & 0x10) { // 0x10 (bfCPSOrderAllWindowsForward) is set when we use cmd-tab or the dock icon 416*4882a593Smuzhiyun DarwinSendDDXEvent(kXquartzBringAllToFront, 1, 417*4882a593Smuzhiyun order_all_windows); 418*4882a593Smuzhiyun } 419*4882a593Smuzhiyun } 420*4882a593Smuzhiyun break; 421*4882a593Smuzhiyun 422*4882a593Smuzhiyun case 18: /* ApplicationDidReactivate */ 423*4882a593Smuzhiyun if (XQuartzFullscreenVisible) for_appkit = NO; 424*4882a593Smuzhiyun break; 425*4882a593Smuzhiyun 426*4882a593Smuzhiyun case NSApplicationDeactivatedEventType: 427*4882a593Smuzhiyun for_x = NO; 428*4882a593Smuzhiyun 429*4882a593Smuzhiyun x_was_active = _x_active; 430*4882a593Smuzhiyun if (_x_active) 431*4882a593Smuzhiyun [self activateX:NO]; 432*4882a593Smuzhiyun break; 433*4882a593Smuzhiyun } 434*4882a593Smuzhiyun break; 435*4882a593Smuzhiyun 436*4882a593Smuzhiyun default: 437*4882a593Smuzhiyun break; /* for gcc */ 438*4882a593Smuzhiyun } 439*4882a593Smuzhiyun 440*4882a593Smuzhiyun if (for_appkit) [super sendEvent:e]; 441*4882a593Smuzhiyun 442*4882a593Smuzhiyun if (for_x) { 443*4882a593Smuzhiyun dispatch_async(eventTranslationQueue, ^{ 444*4882a593Smuzhiyun [self sendX11NSEvent:e]; 445*4882a593Smuzhiyun }); 446*4882a593Smuzhiyun } 447*4882a593Smuzhiyun} 448*4882a593Smuzhiyun 449*4882a593Smuzhiyun- (void) set_apps_menu:(NSArray *)list 450*4882a593Smuzhiyun{ 451*4882a593Smuzhiyun [self.controller set_apps_menu:list]; 452*4882a593Smuzhiyun} 453*4882a593Smuzhiyun 454*4882a593Smuzhiyun- (void) set_front_process:unused 455*4882a593Smuzhiyun{ 456*4882a593Smuzhiyun [NSApp activateIgnoringOtherApps:YES]; 457*4882a593Smuzhiyun 458*4882a593Smuzhiyun if ([self modalWindow] == nil) 459*4882a593Smuzhiyun [self activateX:YES]; 460*4882a593Smuzhiyun} 461*4882a593Smuzhiyun 462*4882a593Smuzhiyun- (void) show_hide_menubar:(NSNumber *)state 463*4882a593Smuzhiyun{ 464*4882a593Smuzhiyun /* Also shows/hides the dock */ 465*4882a593Smuzhiyun if ([state boolValue]) 466*4882a593Smuzhiyun SetSystemUIMode(kUIModeNormal, 0); 467*4882a593Smuzhiyun else 468*4882a593Smuzhiyun SetSystemUIMode(kUIModeAllHidden, 469*4882a593Smuzhiyun XQuartzFullscreenMenu ? kUIOptionAutoShowMenuBar : 0); // kUIModeAllSuppressed or kUIOptionAutoShowMenuBar can be used to allow "mouse-activation" 470*4882a593Smuzhiyun} 471*4882a593Smuzhiyun 472*4882a593Smuzhiyun- (void) launch_client:(NSString *)cmd 473*4882a593Smuzhiyun{ 474*4882a593Smuzhiyun (void)[self.controller application:self openFile:cmd]; 475*4882a593Smuzhiyun} 476*4882a593Smuzhiyun 477*4882a593Smuzhiyun/* user preferences */ 478*4882a593Smuzhiyun 479*4882a593Smuzhiyun/* Note that these functions only work for arrays whose elements 480*4882a593Smuzhiyun can be toll-free-bridged between NS and CF worlds. */ 481*4882a593Smuzhiyun 482*4882a593Smuzhiyunstatic const void * 483*4882a593Smuzhiyuncfretain(CFAllocatorRef a, const void *b) 484*4882a593Smuzhiyun{ 485*4882a593Smuzhiyun return CFRetain(b); 486*4882a593Smuzhiyun} 487*4882a593Smuzhiyun 488*4882a593Smuzhiyunstatic void 489*4882a593Smuzhiyuncfrelease(CFAllocatorRef a, const void *b) 490*4882a593Smuzhiyun{ 491*4882a593Smuzhiyun CFRelease(b); 492*4882a593Smuzhiyun} 493*4882a593Smuzhiyun 494*4882a593SmuzhiyunCF_RETURNS_RETAINED 495*4882a593Smuzhiyunstatic CFMutableArrayRef 496*4882a593Smuzhiyunnsarray_to_cfarray(NSArray *in) 497*4882a593Smuzhiyun{ 498*4882a593Smuzhiyun CFMutableArrayRef out; 499*4882a593Smuzhiyun CFArrayCallBacks cb; 500*4882a593Smuzhiyun NSObject *ns; 501*4882a593Smuzhiyun const CFTypeRef *cf; 502*4882a593Smuzhiyun int i, count; 503*4882a593Smuzhiyun 504*4882a593Smuzhiyun memset(&cb, 0, sizeof(cb)); 505*4882a593Smuzhiyun cb.version = 0; 506*4882a593Smuzhiyun cb.retain = cfretain; 507*4882a593Smuzhiyun cb.release = cfrelease; 508*4882a593Smuzhiyun 509*4882a593Smuzhiyun count = [in count]; 510*4882a593Smuzhiyun out = CFArrayCreateMutable(NULL, count, &cb); 511*4882a593Smuzhiyun 512*4882a593Smuzhiyun for (i = 0; i < count; i++) { 513*4882a593Smuzhiyun ns = [in objectAtIndex:i]; 514*4882a593Smuzhiyun 515*4882a593Smuzhiyun if ([ns isKindOfClass:[NSArray class]]) 516*4882a593Smuzhiyun cf = (CFTypeRef)nsarray_to_cfarray((NSArray *)ns); 517*4882a593Smuzhiyun else 518*4882a593Smuzhiyun cf = CFRetain((CFTypeRef)ns); 519*4882a593Smuzhiyun 520*4882a593Smuzhiyun CFArrayAppendValue(out, cf); 521*4882a593Smuzhiyun CFRelease(cf); 522*4882a593Smuzhiyun } 523*4882a593Smuzhiyun 524*4882a593Smuzhiyun return out; 525*4882a593Smuzhiyun} 526*4882a593Smuzhiyun 527*4882a593Smuzhiyunstatic NSMutableArray * 528*4882a593Smuzhiyuncfarray_to_nsarray(CFArrayRef in) 529*4882a593Smuzhiyun{ 530*4882a593Smuzhiyun NSMutableArray *out; 531*4882a593Smuzhiyun const CFTypeRef *cf; 532*4882a593Smuzhiyun NSObject *ns; 533*4882a593Smuzhiyun int i, count; 534*4882a593Smuzhiyun 535*4882a593Smuzhiyun count = CFArrayGetCount(in); 536*4882a593Smuzhiyun out = [[NSMutableArray alloc] initWithCapacity:count]; 537*4882a593Smuzhiyun 538*4882a593Smuzhiyun for (i = 0; i < count; i++) { 539*4882a593Smuzhiyun cf = CFArrayGetValueAtIndex(in, i); 540*4882a593Smuzhiyun 541*4882a593Smuzhiyun if (CFGetTypeID(cf) == CFArrayGetTypeID()) 542*4882a593Smuzhiyun ns = cfarray_to_nsarray((CFArrayRef)cf); 543*4882a593Smuzhiyun else 544*4882a593Smuzhiyun ns = [(id) cf retain]; 545*4882a593Smuzhiyun 546*4882a593Smuzhiyun [out addObject:ns]; 547*4882a593Smuzhiyun [ns release]; 548*4882a593Smuzhiyun } 549*4882a593Smuzhiyun 550*4882a593Smuzhiyun return out; 551*4882a593Smuzhiyun} 552*4882a593Smuzhiyun 553*4882a593Smuzhiyun- (CFPropertyListRef) prefs_get_copy:(NSString *)key 554*4882a593Smuzhiyun{ 555*4882a593Smuzhiyun CFPropertyListRef value; 556*4882a593Smuzhiyun 557*4882a593Smuzhiyun value = CFPreferencesCopyAppValue((CFStringRef)key, 558*4882a593Smuzhiyun app_prefs_domain_cfstr); 559*4882a593Smuzhiyun 560*4882a593Smuzhiyun if (value == NULL) { 561*4882a593Smuzhiyun static CFDictionaryRef defaults; 562*4882a593Smuzhiyun 563*4882a593Smuzhiyun if (defaults == NULL) { 564*4882a593Smuzhiyun CFStringRef error = NULL; 565*4882a593Smuzhiyun CFDataRef data; 566*4882a593Smuzhiyun CFURLRef url; 567*4882a593Smuzhiyun SInt32 error_code; 568*4882a593Smuzhiyun 569*4882a593Smuzhiyun url = (CFURLCreateFromFileSystemRepresentation 570*4882a593Smuzhiyun (NULL, (unsigned char *)DEFAULTS_FILE, 571*4882a593Smuzhiyun strlen(DEFAULTS_FILE), false)); 572*4882a593Smuzhiyun if (CFURLCreateDataAndPropertiesFromResource(NULL, url, &data, 573*4882a593Smuzhiyun NULL, NULL, 574*4882a593Smuzhiyun &error_code)) { 575*4882a593Smuzhiyun defaults = (CFPropertyListCreateFromXMLData 576*4882a593Smuzhiyun (NULL, data, 577*4882a593Smuzhiyun kCFPropertyListMutableContainersAndLeaves, 578*4882a593Smuzhiyun &error)); 579*4882a593Smuzhiyun if (error != NULL) CFRelease(error); 580*4882a593Smuzhiyun CFRelease(data); 581*4882a593Smuzhiyun } 582*4882a593Smuzhiyun CFRelease(url); 583*4882a593Smuzhiyun 584*4882a593Smuzhiyun if (defaults != NULL) { 585*4882a593Smuzhiyun NSMutableArray *apps, *elt; 586*4882a593Smuzhiyun int count, i; 587*4882a593Smuzhiyun NSString *name, *nname; 588*4882a593Smuzhiyun 589*4882a593Smuzhiyun /* Localize the names in the default apps menu. */ 590*4882a593Smuzhiyun 591*4882a593Smuzhiyun apps = 592*4882a593Smuzhiyun [(NSDictionary *) defaults objectForKey:@PREFS_APPSMENU]; 593*4882a593Smuzhiyun if (apps != nil) { 594*4882a593Smuzhiyun count = [apps count]; 595*4882a593Smuzhiyun for (i = 0; i < count; i++) { 596*4882a593Smuzhiyun elt = [apps objectAtIndex:i]; 597*4882a593Smuzhiyun if (elt != nil && 598*4882a593Smuzhiyun [elt isKindOfClass:[NSArray class]]) { 599*4882a593Smuzhiyun name = [elt objectAtIndex:0]; 600*4882a593Smuzhiyun if (name != nil) { 601*4882a593Smuzhiyun nname = NSLocalizedString(name, nil); 602*4882a593Smuzhiyun if (nname != nil && nname != name) 603*4882a593Smuzhiyun [elt replaceObjectAtIndex:0 withObject: 604*4882a593Smuzhiyun nname]; 605*4882a593Smuzhiyun } 606*4882a593Smuzhiyun } 607*4882a593Smuzhiyun } 608*4882a593Smuzhiyun } 609*4882a593Smuzhiyun } 610*4882a593Smuzhiyun } 611*4882a593Smuzhiyun 612*4882a593Smuzhiyun if (defaults != NULL) value = CFDictionaryGetValue(defaults, key); 613*4882a593Smuzhiyun if (value != NULL) CFRetain(value); 614*4882a593Smuzhiyun } 615*4882a593Smuzhiyun 616*4882a593Smuzhiyun return value; 617*4882a593Smuzhiyun} 618*4882a593Smuzhiyun 619*4882a593Smuzhiyun- (int) prefs_get_integer:(NSString *)key default:(int)def 620*4882a593Smuzhiyun{ 621*4882a593Smuzhiyun CFPropertyListRef value; 622*4882a593Smuzhiyun int ret; 623*4882a593Smuzhiyun 624*4882a593Smuzhiyun value = [self prefs_get_copy:key]; 625*4882a593Smuzhiyun 626*4882a593Smuzhiyun if (value != NULL && CFGetTypeID(value) == CFNumberGetTypeID()) 627*4882a593Smuzhiyun CFNumberGetValue(value, kCFNumberIntType, &ret); 628*4882a593Smuzhiyun else if (value != NULL && CFGetTypeID(value) == CFStringGetTypeID()) 629*4882a593Smuzhiyun ret = CFStringGetIntValue(value); 630*4882a593Smuzhiyun else 631*4882a593Smuzhiyun ret = def; 632*4882a593Smuzhiyun 633*4882a593Smuzhiyun if (value != NULL) CFRelease(value); 634*4882a593Smuzhiyun 635*4882a593Smuzhiyun return ret; 636*4882a593Smuzhiyun} 637*4882a593Smuzhiyun 638*4882a593Smuzhiyun- (const char *) prefs_get_string:(NSString *)key default:(const char *)def 639*4882a593Smuzhiyun{ 640*4882a593Smuzhiyun CFPropertyListRef value; 641*4882a593Smuzhiyun const char *ret = NULL; 642*4882a593Smuzhiyun 643*4882a593Smuzhiyun value = [self prefs_get_copy:key]; 644*4882a593Smuzhiyun 645*4882a593Smuzhiyun if (value != NULL && CFGetTypeID(value) == CFStringGetTypeID()) { 646*4882a593Smuzhiyun NSString *s = (NSString *)value; 647*4882a593Smuzhiyun 648*4882a593Smuzhiyun ret = [s UTF8String]; 649*4882a593Smuzhiyun } 650*4882a593Smuzhiyun 651*4882a593Smuzhiyun if (value != NULL) CFRelease(value); 652*4882a593Smuzhiyun 653*4882a593Smuzhiyun return ret != NULL ? ret : def; 654*4882a593Smuzhiyun} 655*4882a593Smuzhiyun 656*4882a593Smuzhiyun- (NSURL *) prefs_copy_url:(NSString *)key default:(NSURL *)def 657*4882a593Smuzhiyun{ 658*4882a593Smuzhiyun CFPropertyListRef value; 659*4882a593Smuzhiyun NSURL *ret = NULL; 660*4882a593Smuzhiyun 661*4882a593Smuzhiyun value = [self prefs_get_copy:key]; 662*4882a593Smuzhiyun 663*4882a593Smuzhiyun if (value != NULL && CFGetTypeID(value) == CFStringGetTypeID()) { 664*4882a593Smuzhiyun NSString *s = (NSString *)value; 665*4882a593Smuzhiyun 666*4882a593Smuzhiyun ret = [NSURL URLWithString:s]; 667*4882a593Smuzhiyun [ret retain]; 668*4882a593Smuzhiyun } 669*4882a593Smuzhiyun 670*4882a593Smuzhiyun if (value != NULL) CFRelease(value); 671*4882a593Smuzhiyun 672*4882a593Smuzhiyun return ret != NULL ? ret : def; 673*4882a593Smuzhiyun} 674*4882a593Smuzhiyun 675*4882a593Smuzhiyun- (float) prefs_get_float:(NSString *)key default:(float)def 676*4882a593Smuzhiyun{ 677*4882a593Smuzhiyun CFPropertyListRef value; 678*4882a593Smuzhiyun float ret = def; 679*4882a593Smuzhiyun 680*4882a593Smuzhiyun value = [self prefs_get_copy:key]; 681*4882a593Smuzhiyun 682*4882a593Smuzhiyun if (value != NULL 683*4882a593Smuzhiyun && CFGetTypeID(value) == CFNumberGetTypeID() 684*4882a593Smuzhiyun && CFNumberIsFloatType(value)) 685*4882a593Smuzhiyun CFNumberGetValue(value, kCFNumberFloatType, &ret); 686*4882a593Smuzhiyun else if (value != NULL && CFGetTypeID(value) == CFStringGetTypeID()) 687*4882a593Smuzhiyun ret = CFStringGetDoubleValue(value); 688*4882a593Smuzhiyun 689*4882a593Smuzhiyun if (value != NULL) CFRelease(value); 690*4882a593Smuzhiyun 691*4882a593Smuzhiyun return ret; 692*4882a593Smuzhiyun} 693*4882a593Smuzhiyun 694*4882a593Smuzhiyun- (int) prefs_get_boolean:(NSString *)key default:(int)def 695*4882a593Smuzhiyun{ 696*4882a593Smuzhiyun CFPropertyListRef value; 697*4882a593Smuzhiyun int ret = def; 698*4882a593Smuzhiyun 699*4882a593Smuzhiyun value = [self prefs_get_copy:key]; 700*4882a593Smuzhiyun 701*4882a593Smuzhiyun if (value != NULL) { 702*4882a593Smuzhiyun if (CFGetTypeID(value) == CFNumberGetTypeID()) 703*4882a593Smuzhiyun CFNumberGetValue(value, kCFNumberIntType, &ret); 704*4882a593Smuzhiyun else if (CFGetTypeID(value) == CFBooleanGetTypeID()) 705*4882a593Smuzhiyun ret = CFBooleanGetValue(value); 706*4882a593Smuzhiyun else if (CFGetTypeID(value) == CFStringGetTypeID()) { 707*4882a593Smuzhiyun const char *tem = [(NSString *) value UTF8String]; 708*4882a593Smuzhiyun if (strcasecmp(tem, "true") == 0 || strcasecmp(tem, "yes") == 0) 709*4882a593Smuzhiyun ret = YES; 710*4882a593Smuzhiyun else 711*4882a593Smuzhiyun ret = NO; 712*4882a593Smuzhiyun } 713*4882a593Smuzhiyun 714*4882a593Smuzhiyun CFRelease(value); 715*4882a593Smuzhiyun } 716*4882a593Smuzhiyun return ret; 717*4882a593Smuzhiyun} 718*4882a593Smuzhiyun 719*4882a593Smuzhiyun- (NSArray *) prefs_get_array:(NSString *)key 720*4882a593Smuzhiyun{ 721*4882a593Smuzhiyun NSArray *ret = nil; 722*4882a593Smuzhiyun CFPropertyListRef value; 723*4882a593Smuzhiyun 724*4882a593Smuzhiyun value = [self prefs_get_copy:key]; 725*4882a593Smuzhiyun 726*4882a593Smuzhiyun if (value != NULL) { 727*4882a593Smuzhiyun if (CFGetTypeID(value) == CFArrayGetTypeID()) 728*4882a593Smuzhiyun ret = [cfarray_to_nsarray (value)autorelease]; 729*4882a593Smuzhiyun 730*4882a593Smuzhiyun CFRelease(value); 731*4882a593Smuzhiyun } 732*4882a593Smuzhiyun 733*4882a593Smuzhiyun return ret; 734*4882a593Smuzhiyun} 735*4882a593Smuzhiyun 736*4882a593Smuzhiyun- (void) prefs_set_integer:(NSString *)key value:(int)value 737*4882a593Smuzhiyun{ 738*4882a593Smuzhiyun CFNumberRef x; 739*4882a593Smuzhiyun 740*4882a593Smuzhiyun x = CFNumberCreate(NULL, kCFNumberIntType, &value); 741*4882a593Smuzhiyun 742*4882a593Smuzhiyun CFPreferencesSetValue((CFStringRef)key, (CFTypeRef)x, 743*4882a593Smuzhiyun app_prefs_domain_cfstr, 744*4882a593Smuzhiyun kCFPreferencesCurrentUser, 745*4882a593Smuzhiyun kCFPreferencesAnyHost); 746*4882a593Smuzhiyun 747*4882a593Smuzhiyun CFRelease(x); 748*4882a593Smuzhiyun} 749*4882a593Smuzhiyun 750*4882a593Smuzhiyun- (void) prefs_set_float:(NSString *)key value:(float)value 751*4882a593Smuzhiyun{ 752*4882a593Smuzhiyun CFNumberRef x; 753*4882a593Smuzhiyun 754*4882a593Smuzhiyun x = CFNumberCreate(NULL, kCFNumberFloatType, &value); 755*4882a593Smuzhiyun 756*4882a593Smuzhiyun CFPreferencesSetValue((CFStringRef)key, (CFTypeRef)x, 757*4882a593Smuzhiyun app_prefs_domain_cfstr, 758*4882a593Smuzhiyun kCFPreferencesCurrentUser, 759*4882a593Smuzhiyun kCFPreferencesAnyHost); 760*4882a593Smuzhiyun 761*4882a593Smuzhiyun CFRelease(x); 762*4882a593Smuzhiyun} 763*4882a593Smuzhiyun 764*4882a593Smuzhiyun- (void) prefs_set_boolean:(NSString *)key value:(int)value 765*4882a593Smuzhiyun{ 766*4882a593Smuzhiyun CFPreferencesSetValue( 767*4882a593Smuzhiyun (CFStringRef)key, 768*4882a593Smuzhiyun (CFTypeRef)(value ? kCFBooleanTrue 769*4882a593Smuzhiyun : kCFBooleanFalse), 770*4882a593Smuzhiyun app_prefs_domain_cfstr, 771*4882a593Smuzhiyun kCFPreferencesCurrentUser, kCFPreferencesAnyHost); 772*4882a593Smuzhiyun 773*4882a593Smuzhiyun} 774*4882a593Smuzhiyun 775*4882a593Smuzhiyun- (void) prefs_set_array:(NSString *)key value:(NSArray *)value 776*4882a593Smuzhiyun{ 777*4882a593Smuzhiyun CFArrayRef cfarray; 778*4882a593Smuzhiyun 779*4882a593Smuzhiyun cfarray = nsarray_to_cfarray(value); 780*4882a593Smuzhiyun CFPreferencesSetValue((CFStringRef)key, 781*4882a593Smuzhiyun (CFTypeRef)cfarray, 782*4882a593Smuzhiyun app_prefs_domain_cfstr, 783*4882a593Smuzhiyun kCFPreferencesCurrentUser, kCFPreferencesAnyHost); 784*4882a593Smuzhiyun CFRelease(cfarray); 785*4882a593Smuzhiyun} 786*4882a593Smuzhiyun 787*4882a593Smuzhiyun- (void) prefs_set_string:(NSString *)key value:(NSString *)value 788*4882a593Smuzhiyun{ 789*4882a593Smuzhiyun CFPreferencesSetValue((CFStringRef)key, (CFTypeRef)value, 790*4882a593Smuzhiyun app_prefs_domain_cfstr, kCFPreferencesCurrentUser, 791*4882a593Smuzhiyun kCFPreferencesAnyHost); 792*4882a593Smuzhiyun} 793*4882a593Smuzhiyun 794*4882a593Smuzhiyun- (void) prefs_synchronize 795*4882a593Smuzhiyun{ 796*4882a593Smuzhiyun CFPreferencesAppSynchronize(kCFPreferencesCurrentApplication); 797*4882a593Smuzhiyun} 798*4882a593Smuzhiyun 799*4882a593Smuzhiyun- (void) read_defaults 800*4882a593Smuzhiyun{ 801*4882a593Smuzhiyun NSString *nsstr; 802*4882a593Smuzhiyun const char *tem; 803*4882a593Smuzhiyun 804*4882a593Smuzhiyun XQuartzRootlessDefault = [self prefs_get_boolean:@PREFS_ROOTLESS 805*4882a593Smuzhiyun default :XQuartzRootlessDefault]; 806*4882a593Smuzhiyun XQuartzFullscreenMenu = [self prefs_get_boolean:@PREFS_FULLSCREEN_MENU 807*4882a593Smuzhiyun default :XQuartzFullscreenMenu]; 808*4882a593Smuzhiyun XQuartzFullscreenDisableHotkeys = 809*4882a593Smuzhiyun ![self prefs_get_boolean:@PREFS_FULLSCREEN_HOTKEYS 810*4882a593Smuzhiyun default :! 811*4882a593Smuzhiyun XQuartzFullscreenDisableHotkeys]; 812*4882a593Smuzhiyun darwinFakeButtons = [self prefs_get_boolean:@PREFS_FAKEBUTTONS 813*4882a593Smuzhiyun default :darwinFakeButtons]; 814*4882a593Smuzhiyun XQuartzOptionSendsAlt = [self prefs_get_boolean:@PREFS_OPTION_SENDS_ALT 815*4882a593Smuzhiyun default :XQuartzOptionSendsAlt]; 816*4882a593Smuzhiyun 817*4882a593Smuzhiyun if (darwinFakeButtons) { 818*4882a593Smuzhiyun const char *fake2, *fake3; 819*4882a593Smuzhiyun 820*4882a593Smuzhiyun fake2 = [self prefs_get_string:@PREFS_FAKE_BUTTON2 default:NULL]; 821*4882a593Smuzhiyun fake3 = [self prefs_get_string:@PREFS_FAKE_BUTTON3 default:NULL]; 822*4882a593Smuzhiyun 823*4882a593Smuzhiyun if (fake2 != NULL) darwinFakeMouse2Mask = DarwinParseModifierList( 824*4882a593Smuzhiyun fake2, TRUE); 825*4882a593Smuzhiyun if (fake3 != NULL) darwinFakeMouse3Mask = DarwinParseModifierList( 826*4882a593Smuzhiyun fake3, TRUE); 827*4882a593Smuzhiyun } 828*4882a593Smuzhiyun 829*4882a593Smuzhiyun tem = [self prefs_get_string:@PREFS_APPKIT_MODIFIERS default:NULL]; 830*4882a593Smuzhiyun if (tem != NULL) darwinAppKitModMask = DarwinParseModifierList(tem, TRUE); 831*4882a593Smuzhiyun 832*4882a593Smuzhiyun tem = [self prefs_get_string:@PREFS_WINDOW_ITEM_MODIFIERS default:NULL]; 833*4882a593Smuzhiyun if (tem != NULL) { 834*4882a593Smuzhiyun windowItemModMask = DarwinParseModifierList(tem, FALSE); 835*4882a593Smuzhiyun } 836*4882a593Smuzhiyun else { 837*4882a593Smuzhiyun nsstr = NSLocalizedString(@"window item modifiers", 838*4882a593Smuzhiyun @"window item modifiers"); 839*4882a593Smuzhiyun if (nsstr != NULL) { 840*4882a593Smuzhiyun tem = [nsstr UTF8String]; 841*4882a593Smuzhiyun if ((tem != NULL) && strcmp(tem, "window item modifiers")) { 842*4882a593Smuzhiyun windowItemModMask = DarwinParseModifierList(tem, FALSE); 843*4882a593Smuzhiyun } 844*4882a593Smuzhiyun } 845*4882a593Smuzhiyun } 846*4882a593Smuzhiyun 847*4882a593Smuzhiyun XQuartzEnableKeyEquivalents = [self prefs_get_boolean:@PREFS_KEYEQUIVS 848*4882a593Smuzhiyun default : 849*4882a593Smuzhiyun XQuartzEnableKeyEquivalents]; 850*4882a593Smuzhiyun 851*4882a593Smuzhiyun darwinSyncKeymap = [self prefs_get_boolean:@PREFS_SYNC_KEYMAP 852*4882a593Smuzhiyun default :darwinSyncKeymap]; 853*4882a593Smuzhiyun 854*4882a593Smuzhiyun darwinDesiredDepth = [self prefs_get_integer:@PREFS_DEPTH 855*4882a593Smuzhiyun default :darwinDesiredDepth]; 856*4882a593Smuzhiyun 857*4882a593Smuzhiyun noTestExtensions = ![self prefs_get_boolean:@PREFS_TEST_EXTENSIONS 858*4882a593Smuzhiyun default :FALSE]; 859*4882a593Smuzhiyun 860*4882a593Smuzhiyun noRenderExtension = ![self prefs_get_boolean:@PREFS_RENDER_EXTENSION 861*4882a593Smuzhiyun default :TRUE]; 862*4882a593Smuzhiyun 863*4882a593Smuzhiyun XQuartzScrollInDeviceDirection = 864*4882a593Smuzhiyun [self prefs_get_boolean:@PREFS_SCROLL_IN_DEV_DIRECTION 865*4882a593Smuzhiyun default : 866*4882a593Smuzhiyun XQuartzScrollInDeviceDirection]; 867*4882a593Smuzhiyun 868*4882a593Smuzhiyun#if XQUARTZ_SPARKLE 869*4882a593Smuzhiyun NSURL *url = [self prefs_copy_url:@PREFS_UPDATE_FEED default:nil]; 870*4882a593Smuzhiyun if (url) { 871*4882a593Smuzhiyun [[SUUpdater sharedUpdater] setFeedURL:url]; 872*4882a593Smuzhiyun [url release]; 873*4882a593Smuzhiyun } 874*4882a593Smuzhiyun#endif 875*4882a593Smuzhiyun} 876*4882a593Smuzhiyun 877*4882a593Smuzhiyun/* This will end up at the end of the responder chain. */ 878*4882a593Smuzhiyun- (void) copy:sender 879*4882a593Smuzhiyun{ 880*4882a593Smuzhiyun DarwinSendDDXEvent(kXquartzPasteboardNotify, 1, 881*4882a593Smuzhiyun AppleWMCopyToPasteboard); 882*4882a593Smuzhiyun} 883*4882a593Smuzhiyun 884*4882a593Smuzhiyun@end 885*4882a593Smuzhiyun 886*4882a593Smuzhiyunvoid 887*4882a593SmuzhiyunX11ApplicationSetWindowMenu(int nitems, const char **items, 888*4882a593Smuzhiyun const char *shortcuts) 889*4882a593Smuzhiyun{ 890*4882a593Smuzhiyun @autoreleasepool { 891*4882a593Smuzhiyun NSMutableArray <NSArray <NSString *> *> * const allMenuItems = [NSMutableArray array]; 892*4882a593Smuzhiyun 893*4882a593Smuzhiyun for (int i = 0; i < nitems; i++) { 894*4882a593Smuzhiyun NSMutableArray <NSString *> * const menuItem = [NSMutableArray array]; 895*4882a593Smuzhiyun [menuItem addObject:@(items[i])]; 896*4882a593Smuzhiyun 897*4882a593Smuzhiyun if (shortcuts[i] == 0) { 898*4882a593Smuzhiyun [menuItem addObject:@""]; 899*4882a593Smuzhiyun } else { 900*4882a593Smuzhiyun [menuItem addObject:[NSString stringWithFormat:@"%d", shortcuts[i]]]; 901*4882a593Smuzhiyun } 902*4882a593Smuzhiyun 903*4882a593Smuzhiyun [allMenuItems addObject:menuItem]; 904*4882a593Smuzhiyun } 905*4882a593Smuzhiyun 906*4882a593Smuzhiyun dispatch_async(dispatch_get_main_queue(), ^{ 907*4882a593Smuzhiyun [X11App.controller set_window_menu:allMenuItems]; 908*4882a593Smuzhiyun }); 909*4882a593Smuzhiyun } 910*4882a593Smuzhiyun} 911*4882a593Smuzhiyun 912*4882a593Smuzhiyunvoid 913*4882a593SmuzhiyunX11ApplicationSetWindowMenuCheck(int idx) 914*4882a593Smuzhiyun{ 915*4882a593Smuzhiyun dispatch_async(dispatch_get_main_queue(), ^{ 916*4882a593Smuzhiyun [X11App.controller set_window_menu_check:@(idx)]; 917*4882a593Smuzhiyun }); 918*4882a593Smuzhiyun} 919*4882a593Smuzhiyun 920*4882a593Smuzhiyunvoid 921*4882a593SmuzhiyunX11ApplicationSetFrontProcess(void) 922*4882a593Smuzhiyun{ 923*4882a593Smuzhiyun dispatch_async(dispatch_get_main_queue(), ^{ 924*4882a593Smuzhiyun [X11App set_front_process:nil]; 925*4882a593Smuzhiyun }); 926*4882a593Smuzhiyun} 927*4882a593Smuzhiyun 928*4882a593Smuzhiyunvoid 929*4882a593SmuzhiyunX11ApplicationSetCanQuit(int state) 930*4882a593Smuzhiyun{ 931*4882a593Smuzhiyun dispatch_async(dispatch_get_main_queue(), ^{ 932*4882a593Smuzhiyun X11App.controller.can_quit = !!state; 933*4882a593Smuzhiyun }); 934*4882a593Smuzhiyun} 935*4882a593Smuzhiyun 936*4882a593Smuzhiyunvoid 937*4882a593SmuzhiyunX11ApplicationServerReady(void) 938*4882a593Smuzhiyun{ 939*4882a593Smuzhiyun dispatch_async(dispatch_get_main_queue(), ^{ 940*4882a593Smuzhiyun [X11App.controller server_ready]; 941*4882a593Smuzhiyun }); 942*4882a593Smuzhiyun} 943*4882a593Smuzhiyun 944*4882a593Smuzhiyunvoid 945*4882a593SmuzhiyunX11ApplicationShowHideMenubar(int state) 946*4882a593Smuzhiyun{ 947*4882a593Smuzhiyun dispatch_async(dispatch_get_main_queue(), ^{ 948*4882a593Smuzhiyun [X11App show_hide_menubar:@(state)]; 949*4882a593Smuzhiyun }); 950*4882a593Smuzhiyun} 951*4882a593Smuzhiyun 952*4882a593Smuzhiyunvoid 953*4882a593SmuzhiyunX11ApplicationLaunchClient(const char *cmd) 954*4882a593Smuzhiyun{ 955*4882a593Smuzhiyun @autoreleasepool { 956*4882a593Smuzhiyun NSString *string = @(cmd); 957*4882a593Smuzhiyun dispatch_async(dispatch_get_main_queue(), ^{ 958*4882a593Smuzhiyun [X11App launch_client:string]; 959*4882a593Smuzhiyun }); 960*4882a593Smuzhiyun } 961*4882a593Smuzhiyun} 962*4882a593Smuzhiyun 963*4882a593Smuzhiyun/* This is a special function in that it is run from the *SERVER* thread and 964*4882a593Smuzhiyun * not the AppKit thread. We want to block entering a screen-capturing RandR 965*4882a593Smuzhiyun * mode until we notify the user about how to get out if the X11 client crashes. 966*4882a593Smuzhiyun */ 967*4882a593SmuzhiyunBool 968*4882a593SmuzhiyunX11ApplicationCanEnterRandR(void) 969*4882a593Smuzhiyun{ 970*4882a593Smuzhiyun NSString *title, *msg; 971*4882a593Smuzhiyun 972*4882a593Smuzhiyun if ([X11App prefs_get_boolean:@PREFS_NO_RANDR_ALERT default:NO] || 973*4882a593Smuzhiyun XQuartzShieldingWindowLevel != 0) 974*4882a593Smuzhiyun return TRUE; 975*4882a593Smuzhiyun 976*4882a593Smuzhiyun title = NSLocalizedString(@"Enter RandR mode?", 977*4882a593Smuzhiyun @"Dialog title when switching to RandR"); 978*4882a593Smuzhiyun msg = NSLocalizedString( 979*4882a593Smuzhiyun @"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.", 980*4882a593Smuzhiyun @"Dialog when switching to RandR"); 981*4882a593Smuzhiyun 982*4882a593Smuzhiyun if (!XQuartzIsRootless) 983*4882a593Smuzhiyun QuartzShowFullscreen(FALSE); 984*4882a593Smuzhiyun 985*4882a593Smuzhiyun NSInteger __block alert_result; 986*4882a593Smuzhiyun dispatch_sync(dispatch_get_main_queue(), ^{ 987*4882a593Smuzhiyun alert_result = NSRunAlertPanel(title, @"%@", 988*4882a593Smuzhiyun NSLocalizedString(@"Allow", @""), 989*4882a593Smuzhiyun NSLocalizedString(@"Cancel", @""), 990*4882a593Smuzhiyun NSLocalizedString(@"Always Allow", @""), msg); 991*4882a593Smuzhiyun }); 992*4882a593Smuzhiyun 993*4882a593Smuzhiyun switch (alert_result) { 994*4882a593Smuzhiyun case NSAlertOtherReturn: 995*4882a593Smuzhiyun [X11App prefs_set_boolean:@PREFS_NO_RANDR_ALERT value:YES]; 996*4882a593Smuzhiyun [X11App prefs_synchronize]; 997*4882a593Smuzhiyun 998*4882a593Smuzhiyun case NSAlertDefaultReturn: 999*4882a593Smuzhiyun return YES; 1000*4882a593Smuzhiyun 1001*4882a593Smuzhiyun default: 1002*4882a593Smuzhiyun return NO; 1003*4882a593Smuzhiyun } 1004*4882a593Smuzhiyun} 1005*4882a593Smuzhiyun 1006*4882a593Smuzhiyunstatic void 1007*4882a593Smuzhiyuncheck_xinitrc(void) 1008*4882a593Smuzhiyun{ 1009*4882a593Smuzhiyun char *tem, buf[1024]; 1010*4882a593Smuzhiyun NSString *msg; 1011*4882a593Smuzhiyun 1012*4882a593Smuzhiyun if ([X11App prefs_get_boolean:@PREFS_DONE_XINIT_CHECK default:NO]) 1013*4882a593Smuzhiyun return; 1014*4882a593Smuzhiyun 1015*4882a593Smuzhiyun tem = getenv("HOME"); 1016*4882a593Smuzhiyun if (tem == NULL) goto done; 1017*4882a593Smuzhiyun 1018*4882a593Smuzhiyun snprintf(buf, sizeof(buf), "%s/.xinitrc", tem); 1019*4882a593Smuzhiyun if (access(buf, F_OK) != 0) 1020*4882a593Smuzhiyun goto done; 1021*4882a593Smuzhiyun 1022*4882a593Smuzhiyun msg = 1023*4882a593Smuzhiyun NSLocalizedString( 1024*4882a593Smuzhiyun @"You have an existing ~/.xinitrc file.\n\n\ 1025*4882a593Smuzhiyun Windows displayed by X11 applications may not have titlebars, or may look \ 1026*4882a593Smuzhiyun different to windows displayed by native applications.\n\n\ 1027*4882a593Smuzhiyun Would you like to move aside the existing file and use the standard X11 \ 1028*4882a593Smuzhiyun environment the next time you start X11?" , 1029*4882a593Smuzhiyun @"Startup xinitrc dialog"); 1030*4882a593Smuzhiyun 1031*4882a593Smuzhiyun if (NSAlertDefaultReturn == 1032*4882a593Smuzhiyun NSRunAlertPanel(nil, @"%@", NSLocalizedString(@"Yes", @""), 1033*4882a593Smuzhiyun NSLocalizedString(@"No", @""), nil, msg)) { 1034*4882a593Smuzhiyun char buf2[1024]; 1035*4882a593Smuzhiyun int i = -1; 1036*4882a593Smuzhiyun 1037*4882a593Smuzhiyun snprintf(buf2, sizeof(buf2), "%s.old", buf); 1038*4882a593Smuzhiyun 1039*4882a593Smuzhiyun for (i = 1; access(buf2, F_OK) == 0; i++) 1040*4882a593Smuzhiyun snprintf(buf2, sizeof(buf2), "%s.old.%d", buf, i); 1041*4882a593Smuzhiyun 1042*4882a593Smuzhiyun rename(buf, buf2); 1043*4882a593Smuzhiyun } 1044*4882a593Smuzhiyun 1045*4882a593Smuzhiyundone: 1046*4882a593Smuzhiyun [X11App prefs_set_boolean:@PREFS_DONE_XINIT_CHECK value:YES]; 1047*4882a593Smuzhiyun [X11App prefs_synchronize]; 1048*4882a593Smuzhiyun} 1049*4882a593Smuzhiyun 1050*4882a593Smuzhiyunstatic inline pthread_t 1051*4882a593Smuzhiyuncreate_thread(void *(*func)(void *), void *arg) 1052*4882a593Smuzhiyun{ 1053*4882a593Smuzhiyun pthread_attr_t attr; 1054*4882a593Smuzhiyun pthread_t tid; 1055*4882a593Smuzhiyun 1056*4882a593Smuzhiyun pthread_attr_init(&attr); 1057*4882a593Smuzhiyun pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM); 1058*4882a593Smuzhiyun pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); 1059*4882a593Smuzhiyun pthread_create(&tid, &attr, func, arg); 1060*4882a593Smuzhiyun pthread_attr_destroy(&attr); 1061*4882a593Smuzhiyun 1062*4882a593Smuzhiyun return tid; 1063*4882a593Smuzhiyun} 1064*4882a593Smuzhiyun 1065*4882a593Smuzhiyunstatic void * 1066*4882a593Smuzhiyunxpbproxy_x_thread(void *args) 1067*4882a593Smuzhiyun{ 1068*4882a593Smuzhiyun xpbproxy_run(); 1069*4882a593Smuzhiyun 1070*4882a593Smuzhiyun ErrorF("xpbproxy thread is terminating unexpectedly.\n"); 1071*4882a593Smuzhiyun return NULL; 1072*4882a593Smuzhiyun} 1073*4882a593Smuzhiyun 1074*4882a593Smuzhiyunvoid 1075*4882a593SmuzhiyunX11ApplicationMain(int argc, char **argv, char **envp) 1076*4882a593Smuzhiyun{ 1077*4882a593Smuzhiyun#ifdef DEBUG 1078*4882a593Smuzhiyun while (access("/tmp/x11-block", F_OK) == 0) sleep(1); 1079*4882a593Smuzhiyun#endif 1080*4882a593Smuzhiyun 1081*4882a593Smuzhiyun @autoreleasepool { 1082*4882a593Smuzhiyun X11App = (X11Application *)[X11Application sharedApplication]; 1083*4882a593Smuzhiyun 1084*4882a593Smuzhiyun app_prefs_domain_cfstr = (CFStringRef)[[NSBundle mainBundle] bundleIdentifier]; 1085*4882a593Smuzhiyun 1086*4882a593Smuzhiyun if (app_prefs_domain_cfstr == NULL) { 1087*4882a593Smuzhiyun ErrorF("X11ApplicationMain: Unable to determine bundle identifier. Your installation of XQuartz may be broken.\n"); 1088*4882a593Smuzhiyun app_prefs_domain_cfstr = CFSTR(BUNDLE_ID_PREFIX ".X11"); 1089*4882a593Smuzhiyun } 1090*4882a593Smuzhiyun 1091*4882a593Smuzhiyun [NSApp read_defaults]; 1092*4882a593Smuzhiyun [NSBundle loadNibNamed:@"main" owner:NSApp]; 1093*4882a593Smuzhiyun [NSNotificationCenter.defaultCenter addObserver:NSApp 1094*4882a593Smuzhiyun selector:@selector (became_key:) 1095*4882a593Smuzhiyun name:NSWindowDidBecomeKeyNotification 1096*4882a593Smuzhiyun object:nil]; 1097*4882a593Smuzhiyun 1098*4882a593Smuzhiyun /* 1099*4882a593Smuzhiyun * The xpr Quartz mode is statically linked into this server. 1100*4882a593Smuzhiyun * Initialize all the Quartz functions. 1101*4882a593Smuzhiyun */ 1102*4882a593Smuzhiyun QuartzModeBundleInit(); 1103*4882a593Smuzhiyun 1104*4882a593Smuzhiyun /* Calculate the height of the menubar so we can avoid it. */ 1105*4882a593Smuzhiyun aquaMenuBarHeight = NSApp.mainMenu.menuBarHeight; 1106*4882a593Smuzhiyun if (!aquaMenuBarHeight) { 1107*4882a593Smuzhiyun NSScreen* primaryScreen = NSScreen.screens[0]; 1108*4882a593Smuzhiyun aquaMenuBarHeight = NSHeight(primaryScreen.frame) - NSMaxY(primaryScreen.visibleFrame); 1109*4882a593Smuzhiyun } 1110*4882a593Smuzhiyun 1111*4882a593Smuzhiyun eventTranslationQueue = dispatch_queue_create(BUNDLE_ID_PREFIX ".X11.NSEventsToX11EventsQueue", NULL); 1112*4882a593Smuzhiyun assert(eventTranslationQueue != NULL); 1113*4882a593Smuzhiyun 1114*4882a593Smuzhiyun /* Set the key layout seed before we start the server */ 1115*4882a593Smuzhiyun last_key_layout = TISCopyCurrentKeyboardLayoutInputSource(); 1116*4882a593Smuzhiyun 1117*4882a593Smuzhiyun if (!last_key_layout) { 1118*4882a593Smuzhiyun ErrorF("X11ApplicationMain: Unable to determine TISCopyCurrentKeyboardLayoutInputSource() at startup.\n"); 1119*4882a593Smuzhiyun } 1120*4882a593Smuzhiyun 1121*4882a593Smuzhiyun if (!QuartsResyncKeymap(FALSE)) { 1122*4882a593Smuzhiyun ErrorF("X11ApplicationMain: Could not build a valid keymap.\n"); 1123*4882a593Smuzhiyun } 1124*4882a593Smuzhiyun 1125*4882a593Smuzhiyun /* Tell the server thread that it can proceed */ 1126*4882a593Smuzhiyun QuartzInitServer(argc, argv, envp); 1127*4882a593Smuzhiyun 1128*4882a593Smuzhiyun /* This must be done after QuartzInitServer because it can result in 1129*4882a593Smuzhiyun * an mieqEnqueue() - <rdar://problem/6300249> 1130*4882a593Smuzhiyun */ 1131*4882a593Smuzhiyun check_xinitrc(); 1132*4882a593Smuzhiyun 1133*4882a593Smuzhiyun create_thread(xpbproxy_x_thread, NULL); 1134*4882a593Smuzhiyun 1135*4882a593Smuzhiyun#if XQUARTZ_SPARKLE 1136*4882a593Smuzhiyun [[X11App controller] setup_sparkle]; 1137*4882a593Smuzhiyun [[SUUpdater sharedUpdater] resetUpdateCycle]; 1138*4882a593Smuzhiyun // [[SUUpdater sharedUpdater] checkForUpdates:X11App]; 1139*4882a593Smuzhiyun#endif 1140*4882a593Smuzhiyun } 1141*4882a593Smuzhiyun 1142*4882a593Smuzhiyun [NSApp run]; 1143*4882a593Smuzhiyun /* not reached */ 1144*4882a593Smuzhiyun} 1145*4882a593Smuzhiyun 1146*4882a593Smuzhiyun@implementation X11Application (Private) 1147*4882a593Smuzhiyun 1148*4882a593Smuzhiyun#ifdef NX_DEVICELCMDKEYMASK 1149*4882a593Smuzhiyun/* This is to workaround a bug in the VNC server where we sometimes see the L 1150*4882a593Smuzhiyun * modifier and sometimes see no "side" 1151*4882a593Smuzhiyun */ 1152*4882a593Smuzhiyunstatic inline int 1153*4882a593Smuzhiyunensure_flag(int flags, int device_independent, int device_dependents, 1154*4882a593Smuzhiyun int device_dependent_default) 1155*4882a593Smuzhiyun{ 1156*4882a593Smuzhiyun if ((flags & device_independent) && 1157*4882a593Smuzhiyun !(flags & device_dependents)) 1158*4882a593Smuzhiyun flags |= device_dependent_default; 1159*4882a593Smuzhiyun return flags; 1160*4882a593Smuzhiyun} 1161*4882a593Smuzhiyun#endif 1162*4882a593Smuzhiyun 1163*4882a593Smuzhiyun#ifdef DEBUG_UNTRUSTED_POINTER_DELTA 1164*4882a593Smuzhiyunstatic const char * 1165*4882a593Smuzhiyununtrusted_str(NSEvent *e) 1166*4882a593Smuzhiyun{ 1167*4882a593Smuzhiyun switch ([e type]) { 1168*4882a593Smuzhiyun case NSScrollWheel: 1169*4882a593Smuzhiyun return "NSScrollWheel"; 1170*4882a593Smuzhiyun 1171*4882a593Smuzhiyun case NSTabletPoint: 1172*4882a593Smuzhiyun return "NSTabletPoint"; 1173*4882a593Smuzhiyun 1174*4882a593Smuzhiyun case NSOtherMouseDown: 1175*4882a593Smuzhiyun return "NSOtherMouseDown"; 1176*4882a593Smuzhiyun 1177*4882a593Smuzhiyun case NSOtherMouseUp: 1178*4882a593Smuzhiyun return "NSOtherMouseUp"; 1179*4882a593Smuzhiyun 1180*4882a593Smuzhiyun case NSLeftMouseDown: 1181*4882a593Smuzhiyun return "NSLeftMouseDown"; 1182*4882a593Smuzhiyun 1183*4882a593Smuzhiyun case NSLeftMouseUp: 1184*4882a593Smuzhiyun return "NSLeftMouseUp"; 1185*4882a593Smuzhiyun 1186*4882a593Smuzhiyun default: 1187*4882a593Smuzhiyun switch ([e subtype]) { 1188*4882a593Smuzhiyun case NSTabletPointEventSubtype: 1189*4882a593Smuzhiyun return "NSTabletPointEventSubtype"; 1190*4882a593Smuzhiyun 1191*4882a593Smuzhiyun case NSTabletProximityEventSubtype: 1192*4882a593Smuzhiyun return "NSTabletProximityEventSubtype"; 1193*4882a593Smuzhiyun 1194*4882a593Smuzhiyun default: 1195*4882a593Smuzhiyun return "Other"; 1196*4882a593Smuzhiyun } 1197*4882a593Smuzhiyun } 1198*4882a593Smuzhiyun} 1199*4882a593Smuzhiyun#endif 1200*4882a593Smuzhiyun 1201*4882a593Smuzhiyunextern void 1202*4882a593Smuzhiyunwait_for_mieq_init(void); 1203*4882a593Smuzhiyun 1204*4882a593Smuzhiyun- (void) sendX11NSEvent:(NSEvent *)e 1205*4882a593Smuzhiyun{ 1206*4882a593Smuzhiyun NSPoint location = NSZeroPoint; 1207*4882a593Smuzhiyun int ev_button, ev_type; 1208*4882a593Smuzhiyun static float pressure = 0.0; // static so ProximityOut will have the value from the previous tablet event 1209*4882a593Smuzhiyun static NSPoint tilt; // static so ProximityOut will have the value from the previous tablet event 1210*4882a593Smuzhiyun static DeviceIntPtr darwinTabletCurrent = NULL; 1211*4882a593Smuzhiyun static BOOL needsProximityIn = NO; // Do we do need to handle a pending ProximityIn once we have pressure/tilt? 1212*4882a593Smuzhiyun DeviceIntPtr pDev; 1213*4882a593Smuzhiyun int modifierFlags; 1214*4882a593Smuzhiyun BOOL isMouseOrTabletEvent, isTabletEvent; 1215*4882a593Smuzhiyun 1216*4882a593Smuzhiyun if (!darwinTabletCurrent) { 1217*4882a593Smuzhiyun /* Ensure that the event system is initialized */ 1218*4882a593Smuzhiyun wait_for_mieq_init(); 1219*4882a593Smuzhiyun assert(darwinTabletStylus); 1220*4882a593Smuzhiyun 1221*4882a593Smuzhiyun tilt = NSZeroPoint; 1222*4882a593Smuzhiyun darwinTabletCurrent = darwinTabletStylus; 1223*4882a593Smuzhiyun } 1224*4882a593Smuzhiyun 1225*4882a593Smuzhiyun isMouseOrTabletEvent = [e type] == NSLeftMouseDown || 1226*4882a593Smuzhiyun [e type] == NSOtherMouseDown || 1227*4882a593Smuzhiyun [e type] == NSRightMouseDown || 1228*4882a593Smuzhiyun [e type] == NSLeftMouseUp || 1229*4882a593Smuzhiyun [e type] == NSOtherMouseUp || 1230*4882a593Smuzhiyun [e type] == NSRightMouseUp || 1231*4882a593Smuzhiyun [e type] == NSLeftMouseDragged || 1232*4882a593Smuzhiyun [e type] == NSOtherMouseDragged || 1233*4882a593Smuzhiyun [e type] == NSRightMouseDragged || 1234*4882a593Smuzhiyun [e type] == NSMouseMoved || 1235*4882a593Smuzhiyun [e type] == NSTabletPoint || 1236*4882a593Smuzhiyun [e type] == NSScrollWheel; 1237*4882a593Smuzhiyun 1238*4882a593Smuzhiyun isTabletEvent = ([e type] == NSTabletPoint) || 1239*4882a593Smuzhiyun (isMouseOrTabletEvent && 1240*4882a593Smuzhiyun ([e subtype] == NSTabletPointEventSubtype || 1241*4882a593Smuzhiyun [e subtype] == NSTabletProximityEventSubtype)); 1242*4882a593Smuzhiyun 1243*4882a593Smuzhiyun if (isMouseOrTabletEvent) { 1244*4882a593Smuzhiyun static NSPoint lastpt; 1245*4882a593Smuzhiyun NSWindow *window = [e window]; 1246*4882a593Smuzhiyun NSRect screen = [[[NSScreen screens] objectAtIndex:0] frame]; 1247*4882a593Smuzhiyun BOOL hasUntrustedPointerDelta; 1248*4882a593Smuzhiyun 1249*4882a593Smuzhiyun // NSEvents for tablets are not consistent wrt deltaXY between events, so we cannot rely on that 1250*4882a593Smuzhiyun // Thus tablets will be subject to the warp-pointer bug worked around by the delta, but tablets 1251*4882a593Smuzhiyun // are not normally used in cases where that bug would present itself, so this is a fair tradeoff 1252*4882a593Smuzhiyun // <rdar://problem/7111003> deltaX and deltaY are incorrect for NSMouseMoved, NSTabletPointEventSubtype 1253*4882a593Smuzhiyun // http://xquartz.macosforge.org/trac/ticket/288 1254*4882a593Smuzhiyun hasUntrustedPointerDelta = isTabletEvent; 1255*4882a593Smuzhiyun 1256*4882a593Smuzhiyun // The deltaXY for middle click events also appear erroneous after fast user switching 1257*4882a593Smuzhiyun // <rdar://problem/7979468> deltaX and deltaY are incorrect for NSOtherMouseDown and NSOtherMouseUp after FUS 1258*4882a593Smuzhiyun // http://xquartz.macosforge.org/trac/ticket/389 1259*4882a593Smuzhiyun hasUntrustedPointerDelta |= [e type] == NSOtherMouseDown || 1260*4882a593Smuzhiyun [e type] == NSOtherMouseUp; 1261*4882a593Smuzhiyun 1262*4882a593Smuzhiyun // The deltaXY for scroll events correspond to the scroll delta, not the pointer delta 1263*4882a593Smuzhiyun // <rdar://problem/7989690> deltaXY for wheel events are being sent as mouse movement 1264*4882a593Smuzhiyun hasUntrustedPointerDelta |= [e type] == NSScrollWheel; 1265*4882a593Smuzhiyun 1266*4882a593Smuzhiyun#ifdef DEBUG_UNTRUSTED_POINTER_DELTA 1267*4882a593Smuzhiyun hasUntrustedPointerDelta |= [e type] == NSLeftMouseDown || 1268*4882a593Smuzhiyun [e type] == NSLeftMouseUp; 1269*4882a593Smuzhiyun#endif 1270*4882a593Smuzhiyun 1271*4882a593Smuzhiyun if (window != nil) { 1272*4882a593Smuzhiyun NSRect frame = [window frame]; 1273*4882a593Smuzhiyun location = [e locationInWindow]; 1274*4882a593Smuzhiyun location.x += frame.origin.x; 1275*4882a593Smuzhiyun location.y += frame.origin.y; 1276*4882a593Smuzhiyun lastpt = location; 1277*4882a593Smuzhiyun } 1278*4882a593Smuzhiyun else if (hasUntrustedPointerDelta) { 1279*4882a593Smuzhiyun#ifdef DEBUG_UNTRUSTED_POINTER_DELTA 1280*4882a593Smuzhiyun ErrorF("--- Begin Event Debug ---\n"); 1281*4882a593Smuzhiyun ErrorF("Event type: %s\n", untrusted_str(e)); 1282*4882a593Smuzhiyun ErrorF("old lastpt: (%0.2f, %0.2f)\n", lastpt.x, lastpt.y); 1283*4882a593Smuzhiyun ErrorF(" delta: (%0.2f, %0.2f)\n", [e deltaX], -[e deltaY]); 1284*4882a593Smuzhiyun ErrorF(" location: (%0.2f, %0.2f)\n", lastpt.x + [e deltaX], 1285*4882a593Smuzhiyun lastpt.y - [e deltaY]); 1286*4882a593Smuzhiyun ErrorF("workaround: (%0.2f, %0.2f)\n", [e locationInWindow].x, 1287*4882a593Smuzhiyun [e locationInWindow].y); 1288*4882a593Smuzhiyun ErrorF("--- End Event Debug ---\n"); 1289*4882a593Smuzhiyun 1290*4882a593Smuzhiyun location.x = lastpt.x + [e deltaX]; 1291*4882a593Smuzhiyun location.y = lastpt.y - [e deltaY]; 1292*4882a593Smuzhiyun lastpt = [e locationInWindow]; 1293*4882a593Smuzhiyun#else 1294*4882a593Smuzhiyun location = [e locationInWindow]; 1295*4882a593Smuzhiyun lastpt = location; 1296*4882a593Smuzhiyun#endif 1297*4882a593Smuzhiyun } 1298*4882a593Smuzhiyun else { 1299*4882a593Smuzhiyun location.x = lastpt.x + [e deltaX]; 1300*4882a593Smuzhiyun location.y = lastpt.y - [e deltaY]; 1301*4882a593Smuzhiyun lastpt = [e locationInWindow]; 1302*4882a593Smuzhiyun } 1303*4882a593Smuzhiyun 1304*4882a593Smuzhiyun /* Convert coordinate system */ 1305*4882a593Smuzhiyun location.y = (screen.origin.y + screen.size.height) - location.y; 1306*4882a593Smuzhiyun } 1307*4882a593Smuzhiyun 1308*4882a593Smuzhiyun modifierFlags = [e modifierFlags]; 1309*4882a593Smuzhiyun 1310*4882a593Smuzhiyun#ifdef NX_DEVICELCMDKEYMASK 1311*4882a593Smuzhiyun /* This is to workaround a bug in the VNC server where we sometimes see the L 1312*4882a593Smuzhiyun * modifier and sometimes see no "side" 1313*4882a593Smuzhiyun */ 1314*4882a593Smuzhiyun modifierFlags = ensure_flag(modifierFlags, NX_CONTROLMASK, 1315*4882a593Smuzhiyun NX_DEVICELCTLKEYMASK | NX_DEVICERCTLKEYMASK, 1316*4882a593Smuzhiyun NX_DEVICELCTLKEYMASK); 1317*4882a593Smuzhiyun modifierFlags = ensure_flag(modifierFlags, NX_SHIFTMASK, 1318*4882a593Smuzhiyun NX_DEVICELSHIFTKEYMASK | NX_DEVICERSHIFTKEYMASK, 1319*4882a593Smuzhiyun NX_DEVICELSHIFTKEYMASK); 1320*4882a593Smuzhiyun modifierFlags = ensure_flag(modifierFlags, NX_COMMANDMASK, 1321*4882a593Smuzhiyun NX_DEVICELCMDKEYMASK | NX_DEVICERCMDKEYMASK, 1322*4882a593Smuzhiyun NX_DEVICELCMDKEYMASK); 1323*4882a593Smuzhiyun modifierFlags = ensure_flag(modifierFlags, NX_ALTERNATEMASK, 1324*4882a593Smuzhiyun NX_DEVICELALTKEYMASK | NX_DEVICERALTKEYMASK, 1325*4882a593Smuzhiyun NX_DEVICELALTKEYMASK); 1326*4882a593Smuzhiyun#endif 1327*4882a593Smuzhiyun 1328*4882a593Smuzhiyun modifierFlags &= darwin_all_modifier_mask; 1329*4882a593Smuzhiyun 1330*4882a593Smuzhiyun /* We don't receive modifier key events while out of focus, and 3button 1331*4882a593Smuzhiyun * emulation mucks this up, so we need to check our modifier flag state 1332*4882a593Smuzhiyun * on every event... ugg 1333*4882a593Smuzhiyun */ 1334*4882a593Smuzhiyun 1335*4882a593Smuzhiyun if (darwin_all_modifier_flags != modifierFlags) 1336*4882a593Smuzhiyun DarwinUpdateModKeys(modifierFlags); 1337*4882a593Smuzhiyun 1338*4882a593Smuzhiyun switch ([e type]) { 1339*4882a593Smuzhiyun case NSLeftMouseDown: 1340*4882a593Smuzhiyun ev_button = 1; 1341*4882a593Smuzhiyun ev_type = ButtonPress; 1342*4882a593Smuzhiyun goto handle_mouse; 1343*4882a593Smuzhiyun 1344*4882a593Smuzhiyun case NSOtherMouseDown: 1345*4882a593Smuzhiyun ev_button = 2; 1346*4882a593Smuzhiyun ev_type = ButtonPress; 1347*4882a593Smuzhiyun goto handle_mouse; 1348*4882a593Smuzhiyun 1349*4882a593Smuzhiyun case NSRightMouseDown: 1350*4882a593Smuzhiyun ev_button = 3; 1351*4882a593Smuzhiyun ev_type = ButtonPress; 1352*4882a593Smuzhiyun goto handle_mouse; 1353*4882a593Smuzhiyun 1354*4882a593Smuzhiyun case NSLeftMouseUp: 1355*4882a593Smuzhiyun ev_button = 1; 1356*4882a593Smuzhiyun ev_type = ButtonRelease; 1357*4882a593Smuzhiyun goto handle_mouse; 1358*4882a593Smuzhiyun 1359*4882a593Smuzhiyun case NSOtherMouseUp: 1360*4882a593Smuzhiyun ev_button = 2; 1361*4882a593Smuzhiyun ev_type = ButtonRelease; 1362*4882a593Smuzhiyun goto handle_mouse; 1363*4882a593Smuzhiyun 1364*4882a593Smuzhiyun case NSRightMouseUp: 1365*4882a593Smuzhiyun ev_button = 3; 1366*4882a593Smuzhiyun ev_type = ButtonRelease; 1367*4882a593Smuzhiyun goto handle_mouse; 1368*4882a593Smuzhiyun 1369*4882a593Smuzhiyun case NSLeftMouseDragged: 1370*4882a593Smuzhiyun ev_button = 1; 1371*4882a593Smuzhiyun ev_type = MotionNotify; 1372*4882a593Smuzhiyun goto handle_mouse; 1373*4882a593Smuzhiyun 1374*4882a593Smuzhiyun case NSOtherMouseDragged: 1375*4882a593Smuzhiyun ev_button = 2; 1376*4882a593Smuzhiyun ev_type = MotionNotify; 1377*4882a593Smuzhiyun goto handle_mouse; 1378*4882a593Smuzhiyun 1379*4882a593Smuzhiyun case NSRightMouseDragged: 1380*4882a593Smuzhiyun ev_button = 3; 1381*4882a593Smuzhiyun ev_type = MotionNotify; 1382*4882a593Smuzhiyun goto handle_mouse; 1383*4882a593Smuzhiyun 1384*4882a593Smuzhiyun case NSMouseMoved: 1385*4882a593Smuzhiyun ev_button = 0; 1386*4882a593Smuzhiyun ev_type = MotionNotify; 1387*4882a593Smuzhiyun goto handle_mouse; 1388*4882a593Smuzhiyun 1389*4882a593Smuzhiyun case NSTabletPoint: 1390*4882a593Smuzhiyun ev_button = 0; 1391*4882a593Smuzhiyun ev_type = MotionNotify; 1392*4882a593Smuzhiyun goto handle_mouse; 1393*4882a593Smuzhiyun 1394*4882a593Smuzhiyunhandle_mouse: 1395*4882a593Smuzhiyun pDev = darwinPointer; 1396*4882a593Smuzhiyun 1397*4882a593Smuzhiyun /* NSTabletPoint can have no subtype */ 1398*4882a593Smuzhiyun if ([e type] != NSTabletPoint && 1399*4882a593Smuzhiyun [e subtype] == NSTabletProximityEventSubtype) { 1400*4882a593Smuzhiyun switch ([e pointingDeviceType]) { 1401*4882a593Smuzhiyun case NSEraserPointingDevice: 1402*4882a593Smuzhiyun darwinTabletCurrent = darwinTabletEraser; 1403*4882a593Smuzhiyun break; 1404*4882a593Smuzhiyun 1405*4882a593Smuzhiyun case NSPenPointingDevice: 1406*4882a593Smuzhiyun darwinTabletCurrent = darwinTabletStylus; 1407*4882a593Smuzhiyun break; 1408*4882a593Smuzhiyun 1409*4882a593Smuzhiyun case NSCursorPointingDevice: 1410*4882a593Smuzhiyun case NSUnknownPointingDevice: 1411*4882a593Smuzhiyun default: 1412*4882a593Smuzhiyun darwinTabletCurrent = darwinTabletCursor; 1413*4882a593Smuzhiyun break; 1414*4882a593Smuzhiyun } 1415*4882a593Smuzhiyun 1416*4882a593Smuzhiyun if ([e isEnteringProximity]) 1417*4882a593Smuzhiyun needsProximityIn = YES; 1418*4882a593Smuzhiyun else 1419*4882a593Smuzhiyun DarwinSendTabletEvents(darwinTabletCurrent, ProximityOut, 0, 1420*4882a593Smuzhiyun location.x, location.y, pressure, 1421*4882a593Smuzhiyun tilt.x, tilt.y); 1422*4882a593Smuzhiyun return; 1423*4882a593Smuzhiyun } 1424*4882a593Smuzhiyun 1425*4882a593Smuzhiyun if ([e type] == NSTabletPoint || 1426*4882a593Smuzhiyun [e subtype] == NSTabletPointEventSubtype) { 1427*4882a593Smuzhiyun pressure = [e pressure]; 1428*4882a593Smuzhiyun tilt = [e tilt]; 1429*4882a593Smuzhiyun 1430*4882a593Smuzhiyun pDev = darwinTabletCurrent; 1431*4882a593Smuzhiyun 1432*4882a593Smuzhiyun if (needsProximityIn) { 1433*4882a593Smuzhiyun DarwinSendTabletEvents(darwinTabletCurrent, ProximityIn, 0, 1434*4882a593Smuzhiyun location.x, location.y, pressure, 1435*4882a593Smuzhiyun tilt.x, tilt.y); 1436*4882a593Smuzhiyun 1437*4882a593Smuzhiyun needsProximityIn = NO; 1438*4882a593Smuzhiyun } 1439*4882a593Smuzhiyun } 1440*4882a593Smuzhiyun 1441*4882a593Smuzhiyun if (!XQuartzServerVisible && noTestExtensions) { 1442*4882a593Smuzhiyun xp_window_id wid = 0; 1443*4882a593Smuzhiyun xp_error err; 1444*4882a593Smuzhiyun 1445*4882a593Smuzhiyun /* Sigh. Need to check that we're really over one of 1446*4882a593Smuzhiyun * our windows. (We need to receive pointer events while 1447*4882a593Smuzhiyun * not in the foreground, but we don't want to receive them 1448*4882a593Smuzhiyun * when another window is over us or we might show a tooltip) 1449*4882a593Smuzhiyun */ 1450*4882a593Smuzhiyun 1451*4882a593Smuzhiyun err = xp_find_window(location.x, location.y, 0, &wid); 1452*4882a593Smuzhiyun 1453*4882a593Smuzhiyun if (err != XP_Success || (err == XP_Success && wid == 0)) 1454*4882a593Smuzhiyun { 1455*4882a593Smuzhiyun bgMouseLocation = location; 1456*4882a593Smuzhiyun bgMouseLocationUpdated = TRUE; 1457*4882a593Smuzhiyun return; 1458*4882a593Smuzhiyun } 1459*4882a593Smuzhiyun } 1460*4882a593Smuzhiyun 1461*4882a593Smuzhiyun if (bgMouseLocationUpdated) { 1462*4882a593Smuzhiyun if (!(ev_type == MotionNotify && ev_button == 0)) { 1463*4882a593Smuzhiyun DarwinSendPointerEvents(darwinPointer, MotionNotify, 0, 1464*4882a593Smuzhiyun location.x, location.y, 1465*4882a593Smuzhiyun 0.0, 0.0); 1466*4882a593Smuzhiyun } 1467*4882a593Smuzhiyun bgMouseLocationUpdated = FALSE; 1468*4882a593Smuzhiyun } 1469*4882a593Smuzhiyun 1470*4882a593Smuzhiyun if (pDev == darwinPointer) { 1471*4882a593Smuzhiyun DarwinSendPointerEvents(pDev, ev_type, ev_button, 1472*4882a593Smuzhiyun location.x, location.y, 1473*4882a593Smuzhiyun [e deltaX], [e deltaY]); 1474*4882a593Smuzhiyun } else { 1475*4882a593Smuzhiyun DarwinSendTabletEvents(pDev, ev_type, ev_button, 1476*4882a593Smuzhiyun location.x, location.y, pressure, 1477*4882a593Smuzhiyun tilt.x, tilt.y); 1478*4882a593Smuzhiyun } 1479*4882a593Smuzhiyun 1480*4882a593Smuzhiyun break; 1481*4882a593Smuzhiyun 1482*4882a593Smuzhiyun case NSTabletProximity: 1483*4882a593Smuzhiyun switch ([e pointingDeviceType]) { 1484*4882a593Smuzhiyun case NSEraserPointingDevice: 1485*4882a593Smuzhiyun darwinTabletCurrent = darwinTabletEraser; 1486*4882a593Smuzhiyun break; 1487*4882a593Smuzhiyun 1488*4882a593Smuzhiyun case NSPenPointingDevice: 1489*4882a593Smuzhiyun darwinTabletCurrent = darwinTabletStylus; 1490*4882a593Smuzhiyun break; 1491*4882a593Smuzhiyun 1492*4882a593Smuzhiyun case NSCursorPointingDevice: 1493*4882a593Smuzhiyun case NSUnknownPointingDevice: 1494*4882a593Smuzhiyun default: 1495*4882a593Smuzhiyun darwinTabletCurrent = darwinTabletCursor; 1496*4882a593Smuzhiyun break; 1497*4882a593Smuzhiyun } 1498*4882a593Smuzhiyun 1499*4882a593Smuzhiyun if ([e isEnteringProximity]) 1500*4882a593Smuzhiyun needsProximityIn = YES; 1501*4882a593Smuzhiyun else 1502*4882a593Smuzhiyun DarwinSendTabletEvents(darwinTabletCurrent, ProximityOut, 0, 1503*4882a593Smuzhiyun location.x, location.y, pressure, 1504*4882a593Smuzhiyun tilt.x, tilt.y); 1505*4882a593Smuzhiyun break; 1506*4882a593Smuzhiyun 1507*4882a593Smuzhiyun case NSScrollWheel: 1508*4882a593Smuzhiyun { 1509*4882a593Smuzhiyun CGFloat deltaX = [e deltaX]; 1510*4882a593Smuzhiyun CGFloat deltaY = [e deltaY]; 1511*4882a593Smuzhiyun CGEventRef cge = [e CGEvent]; 1512*4882a593Smuzhiyun BOOL isContinuous = 1513*4882a593Smuzhiyun CGEventGetIntegerValueField(cge, kCGScrollWheelEventIsContinuous); 1514*4882a593Smuzhiyun 1515*4882a593Smuzhiyun#if 0 1516*4882a593Smuzhiyun /* Scale the scroll value by line height */ 1517*4882a593Smuzhiyun CGEventSourceRef source = CGEventCreateSourceFromEvent(cge); 1518*4882a593Smuzhiyun if (source) { 1519*4882a593Smuzhiyun double lineHeight = CGEventSourceGetPixelsPerLine(source); 1520*4882a593Smuzhiyun CFRelease(source); 1521*4882a593Smuzhiyun 1522*4882a593Smuzhiyun /* There's no real reason for the 1/5 ratio here other than that 1523*4882a593Smuzhiyun * it feels like a good ratio after some testing. 1524*4882a593Smuzhiyun */ 1525*4882a593Smuzhiyun 1526*4882a593Smuzhiyun deltaX *= lineHeight / 5.0; 1527*4882a593Smuzhiyun deltaY *= lineHeight / 5.0; 1528*4882a593Smuzhiyun } 1529*4882a593Smuzhiyun#endif 1530*4882a593Smuzhiyun 1531*4882a593Smuzhiyun if (XQuartzScrollInDeviceDirection && 1532*4882a593Smuzhiyun [e isDirectionInvertedFromDevice]) { 1533*4882a593Smuzhiyun deltaX *= -1; 1534*4882a593Smuzhiyun deltaY *= -1; 1535*4882a593Smuzhiyun } 1536*4882a593Smuzhiyun /* This hack is in place to better deal with "clicky" scroll wheels: 1537*4882a593Smuzhiyun * http://xquartz.macosforge.org/trac/ticket/562 1538*4882a593Smuzhiyun */ 1539*4882a593Smuzhiyun if (!isContinuous) { 1540*4882a593Smuzhiyun static NSTimeInterval lastScrollTime = 0.0; 1541*4882a593Smuzhiyun 1542*4882a593Smuzhiyun /* These store how much extra we have already scrolled. 1543*4882a593Smuzhiyun * ie, this is how much we ignore on the next event. 1544*4882a593Smuzhiyun */ 1545*4882a593Smuzhiyun static double deficit_x = 0.0; 1546*4882a593Smuzhiyun static double deficit_y = 0.0; 1547*4882a593Smuzhiyun 1548*4882a593Smuzhiyun /* If we have past a second since the last scroll, wipe the slate 1549*4882a593Smuzhiyun * clean 1550*4882a593Smuzhiyun */ 1551*4882a593Smuzhiyun if ([e timestamp] - lastScrollTime > 1.0) { 1552*4882a593Smuzhiyun deficit_x = deficit_y = 0.0; 1553*4882a593Smuzhiyun } 1554*4882a593Smuzhiyun lastScrollTime = [e timestamp]; 1555*4882a593Smuzhiyun 1556*4882a593Smuzhiyun if (deltaX != 0.0) { 1557*4882a593Smuzhiyun /* If we changed directions, wipe the slate clean */ 1558*4882a593Smuzhiyun if ((deficit_x < 0.0 && deltaX > 0.0) || 1559*4882a593Smuzhiyun (deficit_x > 0.0 && deltaX < 0.0)) { 1560*4882a593Smuzhiyun deficit_x = 0.0; 1561*4882a593Smuzhiyun } 1562*4882a593Smuzhiyun 1563*4882a593Smuzhiyun /* Eat up the deficit, but ensure that something is 1564*4882a593Smuzhiyun * always sent 1565*4882a593Smuzhiyun */ 1566*4882a593Smuzhiyun if (fabs(deltaX) > fabs(deficit_x)) { 1567*4882a593Smuzhiyun deltaX -= deficit_x; 1568*4882a593Smuzhiyun 1569*4882a593Smuzhiyun if (deltaX > 0.0) { 1570*4882a593Smuzhiyun deficit_x = ceil(deltaX) - deltaX; 1571*4882a593Smuzhiyun deltaX = ceil(deltaX); 1572*4882a593Smuzhiyun } else { 1573*4882a593Smuzhiyun deficit_x = floor(deltaX) - deltaX; 1574*4882a593Smuzhiyun deltaX = floor(deltaX); 1575*4882a593Smuzhiyun } 1576*4882a593Smuzhiyun } else { 1577*4882a593Smuzhiyun deficit_x -= deltaX; 1578*4882a593Smuzhiyun 1579*4882a593Smuzhiyun if (deltaX > 0.0) { 1580*4882a593Smuzhiyun deltaX = 1.0; 1581*4882a593Smuzhiyun } else { 1582*4882a593Smuzhiyun deltaX = -1.0; 1583*4882a593Smuzhiyun } 1584*4882a593Smuzhiyun 1585*4882a593Smuzhiyun deficit_x += deltaX; 1586*4882a593Smuzhiyun } 1587*4882a593Smuzhiyun } 1588*4882a593Smuzhiyun 1589*4882a593Smuzhiyun if (deltaY != 0.0) { 1590*4882a593Smuzhiyun /* If we changed directions, wipe the slate clean */ 1591*4882a593Smuzhiyun if ((deficit_y < 0.0 && deltaY > 0.0) || 1592*4882a593Smuzhiyun (deficit_y > 0.0 && deltaY < 0.0)) { 1593*4882a593Smuzhiyun deficit_y = 0.0; 1594*4882a593Smuzhiyun } 1595*4882a593Smuzhiyun 1596*4882a593Smuzhiyun /* Eat up the deficit, but ensure that something is 1597*4882a593Smuzhiyun * always sent 1598*4882a593Smuzhiyun */ 1599*4882a593Smuzhiyun if (fabs(deltaY) > fabs(deficit_y)) { 1600*4882a593Smuzhiyun deltaY -= deficit_y; 1601*4882a593Smuzhiyun 1602*4882a593Smuzhiyun if (deltaY > 0.0) { 1603*4882a593Smuzhiyun deficit_y = ceil(deltaY) - deltaY; 1604*4882a593Smuzhiyun deltaY = ceil(deltaY); 1605*4882a593Smuzhiyun } else { 1606*4882a593Smuzhiyun deficit_y = floor(deltaY) - deltaY; 1607*4882a593Smuzhiyun deltaY = floor(deltaY); 1608*4882a593Smuzhiyun } 1609*4882a593Smuzhiyun } else { 1610*4882a593Smuzhiyun deficit_y -= deltaY; 1611*4882a593Smuzhiyun 1612*4882a593Smuzhiyun if (deltaY > 0.0) { 1613*4882a593Smuzhiyun deltaY = 1.0; 1614*4882a593Smuzhiyun } else { 1615*4882a593Smuzhiyun deltaY = -1.0; 1616*4882a593Smuzhiyun } 1617*4882a593Smuzhiyun 1618*4882a593Smuzhiyun deficit_y += deltaY; 1619*4882a593Smuzhiyun } 1620*4882a593Smuzhiyun } 1621*4882a593Smuzhiyun } 1622*4882a593Smuzhiyun 1623*4882a593Smuzhiyun DarwinSendScrollEvents(deltaX, deltaY); 1624*4882a593Smuzhiyun break; 1625*4882a593Smuzhiyun } 1626*4882a593Smuzhiyun 1627*4882a593Smuzhiyun case NSKeyDown: 1628*4882a593Smuzhiyun case NSKeyUp: 1629*4882a593Smuzhiyun { 1630*4882a593Smuzhiyun /* XKB clobbers our keymap at startup, so we need to force it on the first keypress. 1631*4882a593Smuzhiyun * TODO: Make this less of a kludge. 1632*4882a593Smuzhiyun */ 1633*4882a593Smuzhiyun static int force_resync_keymap = YES; 1634*4882a593Smuzhiyun if (force_resync_keymap) { 1635*4882a593Smuzhiyun DarwinSendDDXEvent(kXquartzReloadKeymap, 0); 1636*4882a593Smuzhiyun force_resync_keymap = NO; 1637*4882a593Smuzhiyun } 1638*4882a593Smuzhiyun } 1639*4882a593Smuzhiyun 1640*4882a593Smuzhiyun if (darwinSyncKeymap) { 1641*4882a593Smuzhiyun TISInputSourceRef key_layout = 1642*4882a593Smuzhiyun TISCopyCurrentKeyboardLayoutInputSource(); 1643*4882a593Smuzhiyun TISInputSourceRef clear; 1644*4882a593Smuzhiyun if (CFEqual(key_layout, last_key_layout)) { 1645*4882a593Smuzhiyun CFRelease(key_layout); 1646*4882a593Smuzhiyun } 1647*4882a593Smuzhiyun else { 1648*4882a593Smuzhiyun /* Swap/free thread-safely */ 1649*4882a593Smuzhiyun clear = last_key_layout; 1650*4882a593Smuzhiyun last_key_layout = key_layout; 1651*4882a593Smuzhiyun CFRelease(clear); 1652*4882a593Smuzhiyun 1653*4882a593Smuzhiyun /* Update keyInfo */ 1654*4882a593Smuzhiyun if (!QuartsResyncKeymap(TRUE)) { 1655*4882a593Smuzhiyun ErrorF( 1656*4882a593Smuzhiyun "sendX11NSEvent: Could not build a valid keymap.\n"); 1657*4882a593Smuzhiyun } 1658*4882a593Smuzhiyun } 1659*4882a593Smuzhiyun } 1660*4882a593Smuzhiyun 1661*4882a593Smuzhiyun ev_type = ([e type] == NSKeyDown) ? KeyPress : KeyRelease; 1662*4882a593Smuzhiyun DarwinSendKeyboardEvents(ev_type, [e keyCode]); 1663*4882a593Smuzhiyun break; 1664*4882a593Smuzhiyun 1665*4882a593Smuzhiyun default: 1666*4882a593Smuzhiyun break; /* for gcc */ 1667*4882a593Smuzhiyun } 1668*4882a593Smuzhiyun} 1669*4882a593Smuzhiyun@end 1670