xref: /OK3568_Linux_fs/external/xserver/hw/xquartz/X11Application.m (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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