X11Controller.m revision 8223e2f2
1/* X11Controller.m -- connect the IB ui, also the NSApp delegate
2 
3   Copyright (c) 2002-2008 Apple Inc. All rights reserved.
4 
5   Permission is hereby granted, free of charge, to any person
6   obtaining a copy of this software and associated documentation files
7   (the "Software"), to deal in the Software without restriction,
8   including without limitation the rights to use, copy, modify, merge,
9   publish, distribute, sublicense, and/or sell copies of the Software,
10   and to permit persons to whom the Software is furnished to do so,
11   subject to the following conditions:
12 
13   The above copyright notice and this permission notice shall be
14   included in all copies or substantial portions of the Software.
15 
16   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19   NONINFRINGEMENT.  IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT
20   HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
21   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23   DEALINGS IN THE SOFTWARE.
24 
25   Except as contained in this notice, the name(s) of the above
26   copyright holders shall not be used in advertising or otherwise to
27   promote the sale, use or other dealings in this Software without
28   prior written authorization. */
29
30#include "sanitizedCarbon.h"
31#include <AvailabilityMacros.h>
32
33#ifdef HAVE_DIX_CONFIG_H
34#include <dix-config.h>
35#endif
36
37#include "quartzCommon.h"
38
39#import "X11Controller.h"
40#import "X11Application.h"
41
42#include "opaque.h"
43#include "darwin.h"
44#include "darwinEvents.h"
45#include "quartz.h"
46#include "quartzKeyboard.h"
47#include <X11/extensions/applewmconst.h>
48#include "applewmExt.h"
49
50#include <stdio.h>
51#include <unistd.h>
52#include <fcntl.h>
53#include <sys/types.h>
54#include <sys/wait.h>
55
56@implementation X11Controller
57
58- (void) awakeFromNib
59{
60  X11Application *xapp = NSApp;
61  NSArray *array;
62	
63  /* Point X11Application at ourself. */
64  [xapp set_controller:self];
65	
66  array = [xapp prefs_get_array:@PREFS_APPSMENU];
67  if (array != nil)
68    {
69      int count;
70		
71      /* convert from [TITLE1 COMMAND1 TITLE2 COMMAND2 ...]
72	 to [[TITLE1 COMMAND1] [TITLE2 COMMAND2] ...] format. */
73		
74      count = [array count];
75      if (count > 0
76	  && ![[array objectAtIndex:0] isKindOfClass:[NSArray class]])
77	{
78	  int i;
79	  NSMutableArray *copy, *sub;
80			
81	  copy = [NSMutableArray arrayWithCapacity:(count / 2)];
82			
83	  for (i = 0; i < count / 2; i++)
84	    {
85	      sub = [[NSMutableArray alloc] initWithCapacity:3];
86	      [sub addObject:[array objectAtIndex:i*2]];
87	      [sub addObject:[array objectAtIndex:i*2+1]];
88	      [sub addObject:@""];
89	      [copy addObject:sub];
90	      [sub release];
91	    }
92			
93	  array = copy;
94	}
95		
96      [self set_apps_menu:array];
97    }
98    
99    [[NSNotificationCenter defaultCenter]
100     addObserver: self
101     selector: @selector(apps_table_done:)
102     name: NSWindowWillCloseNotification
103     object: [apps_table window]];
104
105    // Setup data about our Windows menu
106    if(window_separator) {
107        [[window_separator menu] removeItem:window_separator];
108        window_separator = nil;
109    }
110    
111    windows_menu_start = [[X11App windowsMenu] numberOfItems];
112}
113
114- (void) item_selected:sender
115{
116  [NSApp activateIgnoringOtherApps:YES];
117	
118  DarwinSendDDXEvent(kXquartzControllerNotify, 2,
119			     AppleWMWindowMenuItem, [sender tag]);
120}
121
122- (void) remove_window_menu
123{
124  NSMenu *menu;
125  int count, i;
126
127  /* Work backwards so we don't mess up the indices */
128  menu = [X11App windowsMenu];
129  count = [menu numberOfItems];
130  for (i = count - 1; i >= windows_menu_start; i--)
131    [menu removeItemAtIndex:i];
132	
133  count = [dock_menu indexOfItem:dock_window_separator];
134  for (i = 0; i < count; i++)
135    [dock_menu removeItemAtIndex:0];
136}
137
138- (void) install_window_menu:(NSArray *)list
139{
140  NSMenu *menu;
141  NSMenuItem *item;
142  int first, count, i;
143
144  menu = [X11App windowsMenu];
145  first = windows_menu_start + 1;
146  count = [list count];
147  
148  // Push a Separator
149  if(count) {
150      [menu addItem:[NSMenuItem separatorItem]];
151  }
152
153  for (i = 0; i < count; i++)
154    {
155      NSString *name, *shortcut;
156		
157      name = [[list objectAtIndex:i] objectAtIndex:0];
158      shortcut = [[list objectAtIndex:i] objectAtIndex:1];
159        
160      if(windowItemModMask == 0 || windowItemModMask == -1)
161          shortcut = @"";
162
163      item = (NSMenuItem *) [menu addItemWithTitle:name action:@selector
164				  (item_selected:) keyEquivalent:shortcut];
165      [item setKeyEquivalentModifierMask:(NSUInteger) windowItemModMask];
166      [item setTarget:self];
167      [item setTag:i];
168      [item setEnabled:YES];
169
170      item = (NSMenuItem *) [dock_menu insertItemWithTitle:name
171				       action:@selector
172				       (item_selected:) keyEquivalent:shortcut
173				       atIndex:i];
174      [item setKeyEquivalentModifierMask:(NSUInteger) windowItemModMask];
175      [item setTarget:self];
176      [item setTag:i];
177      [item setEnabled:YES];
178    }
179	
180  if (checked_window_item >= 0 && checked_window_item < count)
181    {
182      item = (NSMenuItem *) [menu itemAtIndex:first + checked_window_item];
183      [item setState:NSOnState];
184      item = (NSMenuItem *) [dock_menu itemAtIndex:checked_window_item];
185      [item setState:NSOnState];
186    }
187}
188
189- (void) remove_apps_menu
190{
191  NSMenu *menu;
192  NSMenuItem *item;
193  int i;
194	
195  if (apps == nil || apps_separator == nil) return;
196	
197  menu = [apps_separator menu];
198	
199  if (menu != nil)
200    {
201      for (i = [menu numberOfItems] - 1; i >= 0; i--)
202	{
203	  item = (NSMenuItem *) [menu itemAtIndex:i];
204	  if ([item tag] != 0)
205	    [menu removeItemAtIndex:i];
206	}
207    }
208    
209  if (dock_apps_menu != nil)
210    {
211      for (i = [dock_apps_menu numberOfItems] - 1; i >= 0; i--)
212	{
213	  item = (NSMenuItem *) [dock_apps_menu itemAtIndex:i];
214	  if ([item tag] != 0)
215	    [dock_apps_menu removeItemAtIndex:i];
216	}
217    }
218    
219  [apps release];
220  apps = nil;
221}
222
223- (void) prepend_apps_item:(NSArray *)list index:(int)i menu:(NSMenu *)menu
224{
225  NSString *title, *shortcut = @"";
226  NSArray *group;
227  NSMenuItem *item;
228	
229  group = [list objectAtIndex:i];
230  title = [group objectAtIndex:0];
231  if ([group count] >= 3)
232    shortcut = [group objectAtIndex:2];
233	
234  if ([title length] != 0)
235    {
236      item = (NSMenuItem *) [menu insertItemWithTitle:title
237				  action:@selector (app_selected:)
238				  keyEquivalent:shortcut atIndex:0];
239      [item setTarget:self];
240      [item setEnabled:YES];
241    }
242  else
243    {
244      item = (NSMenuItem *) [NSMenuItem separatorItem];
245      [menu insertItem:item atIndex:0];
246    }
247	
248  [item setTag:i+1];			/* can't be zero, so add one */
249}
250
251- (void) install_apps_menu:(NSArray *)list
252{
253  NSMenu *menu;
254  int i, count;
255	
256  count = [list count];
257	
258  if (count == 0 || apps_separator == nil) return;
259	
260  menu = [apps_separator menu];
261	
262  for (i = count - 1; i >= 0; i--)
263    {
264      if (menu != nil)
265	[self prepend_apps_item:list index:i menu:menu];
266      if (dock_apps_menu != nil)
267	[self prepend_apps_item:list index:i menu:dock_apps_menu];
268    }
269	
270  apps = [list retain];
271}
272
273- (void) set_window_menu:(NSArray *)list
274{
275  [self remove_window_menu];
276  [self install_window_menu:list];
277	
278  DarwinSendDDXEvent(kXquartzControllerNotify, 1,
279			     AppleWMWindowMenuNotify);
280}
281
282- (void) set_window_menu_check:(NSNumber *)nn
283{
284  NSMenu *menu;
285  NSMenuItem *item;
286  int first, count;
287  int n = [nn intValue];
288
289  menu = [X11App windowsMenu];
290  first = windows_menu_start + 1;
291  count = [menu numberOfItems] - first;
292	
293  if (checked_window_item >= 0 && checked_window_item < count)
294    {
295      item = (NSMenuItem *) [menu itemAtIndex:first + checked_window_item];
296      [item setState:NSOffState];
297      item = (NSMenuItem *) [dock_menu itemAtIndex:checked_window_item];
298      [item setState:NSOffState];
299    }
300  if (n >= 0 && n < count)
301    {
302      item = (NSMenuItem *) [menu itemAtIndex:first + n];
303      [item setState:NSOnState];
304      item = (NSMenuItem *) [dock_menu itemAtIndex:n];
305      [item setState:NSOnState];
306    }
307  checked_window_item = n;
308}
309
310- (void) set_apps_menu:(NSArray *)list
311{
312  [self remove_apps_menu];
313  [self install_apps_menu:list];
314}
315
316#ifdef XQUARTZ_SPARKLE
317- (void) setup_sparkle {
318    if(check_for_updates_item)
319        return; // already did it...
320
321    NSMenu *menu = [x11_about_item menu];
322
323    check_for_updates_item = [menu insertItemWithTitle:NSLocalizedString(@"Check for X11 Updates...", @"Check for X11 Updates...")
324                                               action:@selector (checkForUpdates:)
325                                        keyEquivalent:@""
326                                              atIndex:1];
327    [check_for_updates_item setTarget:[SUUpdater sharedUpdater]];
328    [check_for_updates_item setEnabled:YES];
329
330    // Set X11Controller as the delegate for the updater.
331    [[SUUpdater sharedUpdater] setDelegate:self];
332}
333
334// Sent immediately before installing the specified update.
335- (void)updater:(SUUpdater *)updater willInstallUpdate:(SUAppcastItem *)update {
336    //[self set_can_quit:YES];
337}
338
339#endif
340
341- (void) launch_client:(NSString *)filename
342{
343    int child1, child2 = 0;
344    int status;
345    const char *newargv[4];
346    char buf[128];
347    char *s;
348    
349    newargv[0] = [X11App prefs_get_string:@PREFS_LOGIN_SHELL default:"/bin/sh"];
350    newargv[1] = "-c";
351    newargv[2] = [filename UTF8String];
352    newargv[3] = NULL;
353    
354    s = getenv("DISPLAY");
355    if (s == NULL || s[0] == 0) {
356        snprintf(buf, sizeof(buf), ":%s", display);
357        setenv("DISPLAY", buf, TRUE);
358    }
359
360    /* Do the fork-twice trick to avoid having to reap zombies */
361    child1 = fork();
362    switch (child1) {
363        case -1:                                /* error */
364            break;
365      
366        case 0:                                 /* child1 */
367            child2 = fork();
368      
369            switch (child2) {
370                int max_files, i;
371	
372                case -1:                            /* error */
373                    _exit(1);
374	 
375                case 0:                             /* child2 */
376                /* close all open files except for standard streams */
377                max_files = sysconf(_SC_OPEN_MAX);
378                for(i = 3; i < max_files; i++)
379                    close(i);
380	
381                /* ensure stdin is on /dev/null */
382                close(0);
383                open("/dev/null", O_RDONLY);
384	
385                execvp(newargv[0], (char **const) newargv);
386                _exit(2);
387	
388                default:                            /* parent (child1) */
389                _exit(0);
390            }
391            break;
392      
393        default:                                /* parent */
394            waitpid(child1, &status, 0);
395    }
396}
397
398- (void) app_selected:sender
399{
400  int tag;
401  NSString *item;
402  
403  tag = [sender tag] - 1;
404  if (apps == nil || tag < 0 || tag >= [apps count])
405    return;
406  
407  item = [[apps objectAtIndex:tag] objectAtIndex:1];
408  
409  [self launch_client:item];
410}
411
412- (IBAction) apps_table_show:sender
413{
414  NSArray *columns;
415  NSMutableArray *oldapps = nil;
416	
417  if (table_apps != nil)
418    oldapps = table_apps;
419
420  table_apps = [[NSMutableArray alloc] initWithCapacity:1];
421  if(apps != nil)
422      [table_apps addObjectsFromArray:apps];
423	
424  columns = [apps_table tableColumns];
425  [[columns objectAtIndex:0] setIdentifier:@"0"];
426  [[columns objectAtIndex:1] setIdentifier:@"1"];
427  [[columns objectAtIndex:2] setIdentifier:@"2"];
428	
429  [apps_table setDataSource:self];
430  [apps_table selectRowIndexes:[NSIndexSet indexSetWithIndex:0] byExtendingSelection:NO];
431
432  [[apps_table window] makeKeyAndOrderFront:sender];
433  [apps_table reloadData];
434  if(oldapps != nil)
435    [oldapps release];
436}
437
438- (IBAction) apps_table_done:sender
439{
440  [apps_table deselectAll:sender];	/* flush edits? */
441	
442  [self remove_apps_menu];
443  [self install_apps_menu:table_apps];
444	
445  [NSApp prefs_set_array:@PREFS_APPSMENU value:table_apps];
446  [NSApp prefs_synchronize];
447	
448  [[apps_table window] orderOut:sender];
449	
450  [table_apps release];
451  table_apps = nil;
452}
453
454- (IBAction) apps_table_new:sender
455{
456  NSMutableArray *item;
457	
458  int row = [apps_table selectedRow], i;
459	
460  if (row < 0) row = 0;
461  else row = row + 1;
462	
463  i = row;
464  if (i > [table_apps count])
465    return;				/* avoid exceptions */
466	
467  [apps_table deselectAll:sender];
468	
469  item = [[NSMutableArray alloc] initWithCapacity:3];
470  [item addObject:@""];
471  [item addObject:@""];
472  [item addObject:@""];
473	
474  [table_apps insertObject:item atIndex:i];
475  [item release];
476	
477  [apps_table reloadData];
478  [apps_table selectRowIndexes:[NSIndexSet indexSetWithIndex:row] byExtendingSelection:NO];
479}
480
481- (IBAction) apps_table_duplicate:sender
482{
483  int row = [apps_table selectedRow], i;
484  NSObject *item;
485	
486  if (row < 0) {
487    [self apps_table_new:sender];
488    return;
489  }
490	
491  i = row;
492  if (i > [table_apps count] - 1) return;				/* avoid exceptions */
493    
494  [apps_table deselectAll:sender];
495	
496  item = [[table_apps objectAtIndex:i] mutableCopy];
497  [table_apps insertObject:item atIndex:i];
498  [item release];
499	
500  [apps_table reloadData];
501  [apps_table selectRowIndexes:[NSIndexSet indexSetWithIndex:row+1] byExtendingSelection:NO];
502}
503
504- (IBAction) apps_table_delete:sender
505{
506  int row = [apps_table selectedRow];
507	
508  if (row >= 0)
509    {
510      int i = row;
511      
512      if (i > [table_apps count] - 1) return;			/* avoid exceptions */
513      
514      [apps_table deselectAll:sender];
515      
516      [table_apps removeObjectAtIndex:i];
517    }
518	
519  [apps_table reloadData];
520	
521  row = MIN (row, [table_apps count] - 1);
522  if (row >= 0)
523    [apps_table selectRowIndexes:[NSIndexSet indexSetWithIndex:row] byExtendingSelection:NO];
524}
525
526- (NSInteger) numberOfRowsInTableView:(NSTableView *)tableView
527{
528  if (table_apps == nil) return 0;
529  
530  return [table_apps count];
531}
532
533- (id) tableView:(NSTableView *)tableView
534objectValueForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row
535{
536  NSArray *item;
537  int col;
538	
539  if (table_apps == nil) return nil;
540	
541  col = [[tableColumn identifier] intValue];
542	
543  item = [table_apps objectAtIndex:row];
544  if ([item count] > col)
545    return [item objectAtIndex:col];
546  else
547    return @"";
548}
549
550- (void) tableView:(NSTableView *)tableView setObjectValue:(id)object
551    forTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row
552{
553  NSMutableArray *item;
554  int col;
555	
556  if (table_apps == nil) return;
557	
558  col = [[tableColumn identifier] intValue];
559	
560  item = [table_apps objectAtIndex:row];
561  [item replaceObjectAtIndex:col withObject:object];
562}
563
564- (void) hide_window:sender
565{
566  if ([X11App x_active])
567    DarwinSendDDXEvent(kXquartzControllerNotify, 1, AppleWMHideWindow);
568  else
569    NSBeep ();			/* FIXME: something here */
570}
571
572- (IBAction)bring_to_front:sender
573{
574  DarwinSendDDXEvent(kXquartzControllerNotify, 1, AppleWMBringAllToFront);
575}
576
577- (IBAction)close_window:sender
578{
579  if ([X11App x_active])
580    DarwinSendDDXEvent(kXquartzControllerNotify, 1, AppleWMCloseWindow);
581  else
582    [[NSApp keyWindow] performClose:sender];
583}
584
585- (IBAction)minimize_window:sender
586{
587  if ([X11App x_active])
588    DarwinSendDDXEvent(kXquartzControllerNotify, 1, AppleWMMinimizeWindow);
589  else
590    [[NSApp keyWindow] performMiniaturize:sender];
591}
592
593- (IBAction)zoom_window:sender
594{
595  if ([X11App x_active])
596    DarwinSendDDXEvent(kXquartzControllerNotify, 1, AppleWMZoomWindow);
597  else
598    [[NSApp keyWindow] performZoom:sender];
599}
600
601- (IBAction) next_window:sender
602{
603  DarwinSendDDXEvent(kXquartzControllerNotify, 1, AppleWMNextWindow);
604}
605
606- (IBAction) previous_window:sender
607{
608  DarwinSendDDXEvent(kXquartzControllerNotify, 1, AppleWMPreviousWindow);
609}
610
611- (IBAction) enable_fullscreen_changed:sender {
612    XQuartzRootlessDefault = ![enable_fullscreen intValue];
613
614    [enable_fullscreen_menu setEnabled:!XQuartzRootlessDefault];
615
616    DarwinSendDDXEvent(kXquartzSetRootless, 1, XQuartzRootlessDefault);
617
618    [NSApp prefs_set_boolean:@PREFS_ROOTLESS value:XQuartzRootlessDefault];
619    [NSApp prefs_synchronize];
620}
621
622- (IBAction) toggle_fullscreen:sender
623{
624  DarwinSendDDXEvent(kXquartzToggleFullscreen, 0);
625}
626
627- (void) set_can_quit:(OSX_BOOL)state
628{
629  can_quit = state;
630}
631
632- (IBAction)prefs_changed:sender
633{
634    if(!sender)
635        return;
636    
637    if(sender == fake_buttons) {
638        darwinFakeButtons = [fake_buttons intValue];
639        [NSApp prefs_set_boolean:@PREFS_FAKEBUTTONS value:darwinFakeButtons];
640    } else if(sender == enable_keyequivs) {
641        XQuartzEnableKeyEquivalents =  [enable_keyequivs intValue];
642        [NSApp prefs_set_boolean:@PREFS_KEYEQUIVS value:XQuartzEnableKeyEquivalents];
643    } else if(sender == sync_keymap) {
644        darwinSyncKeymap = [sync_keymap intValue];
645        [NSApp prefs_set_boolean:@PREFS_SYNC_KEYMAP value:darwinSyncKeymap];
646    } else if(sender == enable_fullscreen_menu) {
647        XQuartzFullscreenMenu = [enable_fullscreen_menu intValue];
648        [NSApp prefs_set_boolean:@PREFS_FULLSCREEN_MENU value:XQuartzFullscreenMenu];
649    } else if(sender == option_sends_alt) {
650        BOOL prev_opt_sends_alt = XQuartzOptionSendsAlt;
651        
652        XQuartzOptionSendsAlt = [option_sends_alt intValue];
653        [NSApp prefs_set_boolean:@PREFS_OPTION_SENDS_ALT value:XQuartzOptionSendsAlt];
654
655        if(prev_opt_sends_alt != XQuartzOptionSendsAlt)
656            QuartsResyncKeymap(TRUE);
657    } else if(sender == click_through) {
658        [NSApp prefs_set_boolean:@PREFS_CLICK_THROUGH value:[click_through intValue]];
659    } else if(sender == focus_follows_mouse) {
660        [NSApp prefs_set_boolean:@PREFS_FFM value:[focus_follows_mouse intValue]];
661    } else if(sender == focus_on_new_window) {
662        [NSApp prefs_set_boolean:@PREFS_FOCUS_ON_NEW_WINDOW value:[focus_on_new_window intValue]];
663    } else if(sender == enable_auth) {
664        [NSApp prefs_set_boolean:@PREFS_NO_AUTH value:![enable_auth intValue]];
665    } else if(sender == enable_tcp) {
666        [NSApp prefs_set_boolean:@PREFS_NO_TCP value:![enable_tcp intValue]];
667    } else if(sender == depth) {
668        [NSApp prefs_set_integer:@PREFS_DEPTH value:[depth selectedTag]];
669    } else if(sender == sync_pasteboard) {
670        BOOL pbproxy_active = [sync_pasteboard intValue];
671        [NSApp prefs_set_boolean:@PREFS_SYNC_PB value:pbproxy_active];
672
673        [sync_pasteboard_to_clipboard setEnabled:pbproxy_active];
674        [sync_pasteboard_to_primary setEnabled:pbproxy_active];
675        [sync_clipboard_to_pasteboard setEnabled:pbproxy_active];
676        [sync_primary_immediately setEnabled:pbproxy_active];
677
678        // setEnabled doesn't do this...
679        [sync_text1 setTextColor:pbproxy_active ? [NSColor controlTextColor] : [NSColor disabledControlTextColor]];
680        [sync_text2 setTextColor:pbproxy_active ? [NSColor controlTextColor] : [NSColor disabledControlTextColor]];
681    } else if(sender == sync_pasteboard_to_clipboard) {
682        [NSApp prefs_set_boolean:@PREFS_SYNC_PB_TO_CLIPBOARD value:[sync_pasteboard_to_clipboard intValue]];
683    } else if(sender == sync_pasteboard_to_primary) {
684        [NSApp prefs_set_boolean:@PREFS_SYNC_PB_TO_PRIMARY value:[sync_pasteboard_to_primary intValue]];
685    } else if(sender == sync_clipboard_to_pasteboard) {
686        [NSApp prefs_set_boolean:@PREFS_SYNC_CLIPBOARD_TO_PB value:[sync_clipboard_to_pasteboard intValue]];
687    } else if(sender == sync_primary_immediately) {
688        [NSApp prefs_set_boolean:@PREFS_SYNC_PRIMARY_ON_SELECT value:[sync_primary_immediately intValue]];
689    }
690
691    [NSApp prefs_synchronize];
692    
693    DarwinSendDDXEvent(kXquartzReloadPreferences, 0);
694}
695
696- (IBAction) prefs_show:sender
697{
698    BOOL pbproxy_active = [NSApp prefs_get_boolean:@PREFS_SYNC_PB default:YES];
699    
700    [fake_buttons setIntValue:darwinFakeButtons];
701    [enable_keyequivs setIntValue:XQuartzEnableKeyEquivalents];
702    [sync_keymap setIntValue:darwinSyncKeymap];
703    [option_sends_alt setIntValue:XQuartzOptionSendsAlt];
704    [click_through setIntValue:[NSApp prefs_get_boolean:@PREFS_CLICK_THROUGH default:NO]];
705    [focus_follows_mouse setIntValue:[NSApp prefs_get_boolean:@PREFS_FFM default:NO]];
706    [focus_on_new_window setIntValue:[NSApp prefs_get_boolean:@PREFS_FOCUS_ON_NEW_WINDOW default:YES]];
707    
708    [enable_auth setIntValue:![NSApp prefs_get_boolean:@PREFS_NO_AUTH default:NO]];
709    [enable_tcp setIntValue:![NSApp prefs_get_boolean:@PREFS_NO_TCP default:NO]];
710
711    [depth selectItemAtIndex:[depth indexOfItemWithTag:[NSApp prefs_get_integer:@PREFS_DEPTH default:-1]]];
712
713    [sync_pasteboard setIntValue:pbproxy_active];
714    [sync_pasteboard_to_clipboard setIntValue:[NSApp prefs_get_boolean:@PREFS_SYNC_PB_TO_CLIPBOARD default:YES]];
715    [sync_pasteboard_to_primary setIntValue:[NSApp prefs_get_boolean:@PREFS_SYNC_PB_TO_PRIMARY default:YES]];
716    [sync_clipboard_to_pasteboard setIntValue:[NSApp prefs_get_boolean:@PREFS_SYNC_CLIPBOARD_TO_PB default:YES]];
717    [sync_primary_immediately setIntValue:[NSApp prefs_get_boolean:@PREFS_SYNC_PRIMARY_ON_SELECT default:NO]];
718
719    [sync_pasteboard_to_clipboard setEnabled:pbproxy_active];
720    [sync_pasteboard_to_primary setEnabled:pbproxy_active];
721    [sync_clipboard_to_pasteboard setEnabled:pbproxy_active];
722    [sync_primary_immediately setEnabled:pbproxy_active];
723
724    // setEnabled doesn't do this...
725    [sync_text1 setTextColor:pbproxy_active ? [NSColor controlTextColor] : [NSColor disabledControlTextColor]];
726    [sync_text2 setTextColor:pbproxy_active ? [NSColor controlTextColor] : [NSColor disabledControlTextColor]];
727	
728    [enable_fullscreen setIntValue:!XQuartzRootlessDefault];
729    [enable_fullscreen_menu setEnabled:!XQuartzRootlessDefault];
730    [enable_fullscreen_menu setIntValue:XQuartzFullscreenMenu];
731    
732    [prefs_panel makeKeyAndOrderFront:sender];
733}
734
735- (IBAction) quit:sender {
736    DarwinSendDDXEvent(kXquartzQuit, 0);
737}
738
739- (IBAction) x11_help:sender {
740#if MAC_OS_X_VERSION_MIN_REQUIRED < 1060
741    AHLookupAnchor((CFStringRef)NSLocalizedString(@"Mac Help", no comment), CFSTR("mchlp2276"));
742#else
743    AHLookupAnchor(CFSTR("com.apple.machelp"), CFSTR("mchlp2276"));
744#endif
745}
746
747- (OSX_BOOL) validateMenuItem:(NSMenuItem *)item {
748  NSMenu *menu = [item menu];
749    
750  if (item == toggle_fullscreen_item)
751    return !XQuartzIsRootless;
752  else if (menu == [X11App windowsMenu] || menu == dock_menu
753	   || (menu == [x11_about_item menu] && [item tag] == 42))
754    return (AppleWMSelectedEvents () & AppleWMControllerNotifyMask) != 0;
755  else
756    return TRUE;
757}
758
759- (void) applicationDidHide:(NSNotification *)notify
760{
761  DarwinSendDDXEvent(kXquartzControllerNotify, 1, AppleWMHideAll);
762}
763
764- (void) applicationDidUnhide:(NSNotification *)notify
765{
766  DarwinSendDDXEvent(kXquartzControllerNotify, 1, AppleWMShowAll);
767}
768
769- (NSApplicationTerminateReply) applicationShouldTerminate:sender {
770    NSString *msg;
771    NSString *title;
772	
773    if (can_quit || [X11App prefs_get_boolean:@PREFS_NO_QUIT_ALERT default:NO])
774        return NSTerminateNow;
775	
776    /* Make sure we're frontmost. */
777    [NSApp activateIgnoringOtherApps:YES];
778	
779    title = NSLocalizedString(@"Do you really want to quit X11?", @"Dialog title when quitting");
780    msg = NSLocalizedString(@"Any open X11 applications will stop immediately, and you will lose any unsaved changes.", @"Dialog when quitting");
781
782    /* FIXME: safe to run the alert in here? Or should we return Later
783     *        and then run the alert on a timer? It seems to work here, so..
784     */
785	
786    return (NSRunAlertPanel (title, msg, NSLocalizedString (@"Quit", @""),
787                             NSLocalizedString (@"Cancel", @""), nil)
788            == NSAlertDefaultReturn) ? NSTerminateNow : NSTerminateCancel;
789}
790
791- (void) applicationWillTerminate:(NSNotification *)aNotification
792{
793  unsigned remain;
794  [X11App prefs_synchronize];
795	
796  /* shutdown the X server, it will exit () for us. */
797  DarwinSendDDXEvent(kXquartzQuit, 0);
798	
799  /* In case it doesn't, exit anyway after a while. */
800  remain = 10000000;
801  while((remain = usleep(remain)) > 0);
802
803  exit (1);
804}
805
806- (void) server_ready
807{
808  x_list *node;
809	
810  finished_launching = YES;
811	
812  for (node = pending_apps; node != NULL; node = node->next)
813    {
814      NSString *filename = node->data;
815      [self launch_client:filename];
816      [filename release];
817    }
818	
819  x_list_free (pending_apps);
820  pending_apps = NULL;
821}
822
823- (OSX_BOOL) application:(NSApplication *)app openFile:(NSString *)filename
824{
825    const char *name = [filename UTF8String];
826    
827    if (finished_launching)
828        [self launch_client:filename];
829    else if (name[0] != ':')		/* ignore display names */
830        pending_apps = x_list_prepend (pending_apps, [filename retain]);
831    
832    /* FIXME: report failures. */
833    return YES;
834}
835
836@end
837
838void X11ControllerMain(int argc, char **argv, char **envp) {
839    X11ApplicationMain (argc, argv, envp);
840}
841