Imported Upstream version 1.15.1
[deb_xorg-server.git] / hw / xquartz / X11Controller.m
CommitLineData
a09e091a
JB
1/* X11Controller.m -- connect the IB ui, also the NSApp delegate
2 *
3 * Copyright (c) 2002-2012 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
31#include "sanitizedCarbon.h"
32#include <AvailabilityMacros.h>
33
34#ifdef HAVE_DIX_CONFIG_H
35#include <dix-config.h>
36#endif
37
38#include "quartzCommon.h"
39
40#import "X11Controller.h"
41#import "X11Application.h"
42
43#include "opaque.h"
44#include "darwin.h"
45#include "darwinEvents.h"
46#include "quartz.h"
47#include "quartzKeyboard.h"
48#include <X11/extensions/applewmconst.h>
49#include "applewmExt.h"
50
51#include <stdio.h>
52#include <unistd.h>
53#include <fcntl.h>
54#include <sys/types.h>
55#include <sys/wait.h>
56#include <asl.h>
57#include <stdlib.h>
58
59extern aslclient aslc;
60extern char *bundle_id_prefix;
61
62@implementation X11Controller
63
64- (void) awakeFromNib
65{
66 X11Application *xapp = NSApp;
67 NSArray *array;
68
69 /* Point X11Application at ourself. */
70 [xapp set_controller:self];
71
72 array = [xapp prefs_get_array:@PREFS_APPSMENU];
73 if (array != nil) {
74 int count;
75
76 /* convert from [TITLE1 COMMAND1 TITLE2 COMMAND2 ...]
77 to [[TITLE1 COMMAND1] [TITLE2 COMMAND2] ...] format. */
78
79 count = [array count];
80 if (count > 0
81 && ![[array objectAtIndex:0] isKindOfClass:[NSArray class]]) {
82 int i;
83 NSMutableArray *copy, *sub;
84
85 copy = [NSMutableArray arrayWithCapacity:(count / 2)];
86
87 for (i = 0; i < count / 2; i++) {
88 sub = [[NSMutableArray alloc] initWithCapacity:3];
89 [sub addObject:[array objectAtIndex:i * 2]];
90 [sub addObject:[array objectAtIndex:i * 2 + 1]];
91 [sub addObject:@""];
92 [copy addObject:sub];
93 [sub release];
94 }
95
96 array = copy;
97 }
98
99 [self set_apps_menu:array];
100 }
101
102 [[NSNotificationCenter defaultCenter]
103 addObserver: self
104 selector: @selector(apps_table_done:)
105 name: NSWindowWillCloseNotification
106 object: [apps_table window]];
107
108 // Setup data about our Windows menu
109 if (window_separator) {
110 [[window_separator menu] removeItem:window_separator];
111 window_separator = nil;
112 }
113
114 windows_menu_start = [[X11App windowsMenu] numberOfItems];
115}
116
117- (void) item_selected:sender
118{
119 [NSApp activateIgnoringOtherApps:YES];
120
121 DarwinSendDDXEvent(kXquartzControllerNotify, 2,
122 AppleWMWindowMenuItem, [sender tag]);
123}
124
125- (void) remove_window_menu
126{
127 NSMenu *menu;
128 int count, i;
129
130 /* Work backwards so we don't mess up the indices */
131 menu = [X11App windowsMenu];
132 count = [menu numberOfItems];
133 for (i = count - 1; i >= windows_menu_start; i--)
134 [menu removeItemAtIndex:i];
135
136 count = [dock_menu indexOfItem:dock_window_separator];
137 for (i = 0; i < count; i++)
138 [dock_menu removeItemAtIndex:0];
139}
140
141- (void) install_window_menu:(NSArray *)list
142{
143 NSMenu *menu;
144 NSMenuItem *item;
145 int first, count, i;
146
147 menu = [X11App windowsMenu];
148 first = windows_menu_start + 1;
149 count = [list count];
150
151 // Push a Separator
152 if (count) {
153 [menu addItem:[NSMenuItem separatorItem]];
154 }
155
156 for (i = 0; i < count; i++) {
157 NSString *name, *shortcut;
158
159 name = [[list objectAtIndex:i] objectAtIndex:0];
160 shortcut = [[list objectAtIndex:i] objectAtIndex:1];
161
162 if (windowItemModMask == 0 || windowItemModMask == -1)
163 shortcut = @"";
164
165 item =
166 (NSMenuItem *)[menu addItemWithTitle:name action:
167 @selector
168 (item_selected:) keyEquivalent:shortcut];
169 [item setKeyEquivalentModifierMask:(NSUInteger)windowItemModMask];
170 [item setTarget:self];
171 [item setTag:i];
172 [item setEnabled:YES];
173
174 item = (NSMenuItem *)[dock_menu insertItemWithTitle:name
175 action:@selector
176 (item_selected:) keyEquivalent:shortcut
177 atIndex:i];
178 [item setKeyEquivalentModifierMask:(NSUInteger)windowItemModMask];
179 [item setTarget:self];
180 [item setTag:i];
181 [item setEnabled:YES];
182 }
183
184 if (checked_window_item >= 0 && checked_window_item < count) {
185 item = (NSMenuItem *)[menu itemAtIndex:first + checked_window_item];
186 [item setState:NSOnState];
187 item = (NSMenuItem *)[dock_menu itemAtIndex:checked_window_item];
188 [item setState:NSOnState];
189 }
190}
191
192- (void) remove_apps_menu
193{
194 NSMenu *menu;
195 NSMenuItem *item;
196 int i;
197
198 if (apps == nil || apps_separator == nil) return;
199
200 menu = [apps_separator menu];
201
202 if (menu != nil) {
203 for (i = [menu numberOfItems] - 1; i >= 0; i--) {
204 item = (NSMenuItem *)[menu itemAtIndex:i];
205 if ([item tag] != 0)
206 [menu removeItemAtIndex:i];
207 }
208 }
209
210 if (dock_apps_menu != nil) {
211 for (i = [dock_apps_menu numberOfItems] - 1; i >= 0; i--) {
212 item = (NSMenuItem *)[dock_apps_menu itemAtIndex:i];
213 if ([item tag] != 0)
214 [dock_apps_menu removeItemAtIndex:i];
215 }
216 }
217
218 [apps release];
219 apps = nil;
220}
221
222- (void) prepend_apps_item:(NSArray *)list index:(int)i menu:(NSMenu *)menu
223{
224 NSString *title, *shortcut = @"";
225 NSArray *group;
226 NSMenuItem *item;
227
228 group = [list objectAtIndex:i];
229 title = [group objectAtIndex:0];
230 if ([group count] >= 3)
231 shortcut = [group objectAtIndex:2];
232
233 if ([title length] != 0) {
234 item = (NSMenuItem *)[menu insertItemWithTitle:title
235 action:@selector (
236 app_selected:)
237 keyEquivalent:shortcut atIndex:0];
238 [item setTarget:self];
239 [item setEnabled:YES];
240 }
241 else {
242 item = (NSMenuItem *)[NSMenuItem separatorItem];
243 [menu insertItem:item atIndex:0];
244 }
245
246 [item setTag:i + 1]; /* can't be zero, so add one */
247}
248
249- (void) install_apps_menu:(NSArray *)list
250{
251 NSMenu *menu;
252 int i, count;
253
254 count = [list count];
255
256 if (count == 0 || apps_separator == nil) return;
257
258 menu = [apps_separator menu];
259
260 for (i = count - 1; i >= 0; i--) {
261 if (menu != nil)
262 [self prepend_apps_item:list index:i menu:menu];
263 if (dock_apps_menu != nil)
264 [self prepend_apps_item:list index:i menu:dock_apps_menu];
265 }
266
267 apps = [list retain];
268}
269
270- (void) set_window_menu:(NSArray *)list
271{
272 [self remove_window_menu];
273 [self install_window_menu:list];
274
275 DarwinSendDDXEvent(kXquartzControllerNotify, 1,
276 AppleWMWindowMenuNotify);
277}
278
279- (void) set_window_menu_check:(NSNumber *)nn
280{
281 NSMenu *menu;
282 NSMenuItem *item;
283 int first, count;
284 int n = [nn intValue];
285
286 menu = [X11App windowsMenu];
287 first = windows_menu_start + 1;
288 count = [menu numberOfItems] - first;
289
290 if (checked_window_item >= 0 && checked_window_item < count) {
291 item = (NSMenuItem *)[menu itemAtIndex:first + checked_window_item];
292 [item setState:NSOffState];
293 item = (NSMenuItem *)[dock_menu itemAtIndex:checked_window_item];
294 [item setState:NSOffState];
295 }
296 if (n >= 0 && n < count) {
297 item = (NSMenuItem *)[menu itemAtIndex:first + n];
298 [item setState:NSOnState];
299 item = (NSMenuItem *)[dock_menu itemAtIndex:n];
300 [item setState:NSOnState];
301 }
302 checked_window_item = n;
303}
304
305- (void) set_apps_menu:(NSArray *)list
306{
307 [self remove_apps_menu];
308 [self install_apps_menu:list];
309}
310
311#ifdef XQUARTZ_SPARKLE
312- (void) setup_sparkle
313{
314 if (check_for_updates_item)
315 return; // already did it...
316
317 NSMenu *menu = [x11_about_item menu];
318
319 check_for_updates_item =
320 [menu insertItemWithTitle:NSLocalizedString(
321 @"Check for X11 Updates...",
322 @"Check for X11 Updates...")
323 action:@selector (
324 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 *)
336 update
337{
338 //[self set_can_quit:YES];
339}
340
341#endif
342
343- (void) launch_client:(NSString *)filename
344{
345 int child1, child2 = 0;
346 int status;
347 const char *newargv[4];
348 char buf[128];
349 char *s;
350#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1080
351 int stdout_pipe[2];
352 int stderr_pipe[2];
353#endif
354
355 newargv[0] = [X11App prefs_get_string:@PREFS_LOGIN_SHELL default:"/bin/sh"];
356 newargv[1] = "-c";
357 newargv[2] = [filename UTF8String];
358 newargv[3] = NULL;
359
360 s = getenv("DISPLAY");
361 if (s == NULL || s[0] == 0) {
362 snprintf(buf, sizeof(buf), ":%s", display);
363 setenv("DISPLAY", buf, TRUE);
364 }
365
366#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1080
367 if (asl_log_descriptor) {
368 char *asl_sender;
369 aslmsg amsg = asl_new(ASL_TYPE_MSG);
370 assert(amsg);
371
372 asprintf(&asl_sender, "%s.%s", bundle_id_prefix, newargv[2]);
373 assert(asl_sender);
374 for(s = asl_sender + strlen(bundle_id_prefix) + 1; *s; s++) {
375 if(! ((*s >= 'a' && *s <= 'z') ||
376 (*s >= 'A' && *s <= 'Z') ||
377 (*s >= '0' && *s <= '9'))) {
378 *s = '_';
379 }
380 }
381
382 (void)asl_set(amsg, ASL_KEY_SENDER, asl_sender);
383 free(asl_sender);
384
385 assert(0 == pipe(stdout_pipe));
386 fcntl(stdout_pipe[0], F_SETFD, FD_CLOEXEC);
387 fcntl(stdout_pipe[0], F_SETFL, O_NONBLOCK);
388
389 assert(0 == pipe(stderr_pipe));
390 fcntl(stderr_pipe[0], F_SETFD, FD_CLOEXEC);
391 fcntl(stderr_pipe[0], F_SETFL, O_NONBLOCK);
392
393 asl_log_descriptor(aslc, amsg, ASL_LEVEL_INFO, stdout_pipe[0], ASL_LOG_DESCRIPTOR_READ);
394 asl_log_descriptor(aslc, amsg, ASL_LEVEL_NOTICE, stderr_pipe[0], ASL_LOG_DESCRIPTOR_READ);
395
396 asl_free(amsg);
397 }
398#endif
399
400 /* Do the fork-twice trick to avoid having to reap zombies */
401 child1 = fork();
402 switch (child1) {
403 case -1: /* error */
404 break;
405
406 case 0: /* child1 */
407 child2 = fork();
408
409 switch (child2) {
410 int max_files, i;
411
412 case -1: /* error */
413 _exit(1);
414
415 case 0: /* child2 */
416#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1080
417 if (asl_log_descriptor) {
418 /* Replace our stdout/stderr */
419 dup2(stdout_pipe[1], STDOUT_FILENO);
420 dup2(stderr_pipe[1], STDERR_FILENO);
421 }
422#endif
423
424 /* close all open files except for standard streams */
425 max_files = sysconf(_SC_OPEN_MAX);
426 for (i = 3; i < max_files; i++)
427 close(i);
428
429 /* ensure stdin is on /dev/null */
430 close(0);
431 open("/dev/null", O_RDONLY);
432
433 execvp(newargv[0], (char * *const)newargv);
434 _exit(2);
435
436 default: /* parent (child1) */
437 _exit(0);
438 }
439 break;
440
441 default: /* parent */
442 waitpid(child1, &status, 0);
443 }
444
445#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1080
446 if (asl_log_descriptor) {
447 /* Close the write ends of the pipe */
448 close(stdout_pipe[1]);
449 close(stderr_pipe[1]);
450 }
451#endif
452}
453
454- (void) app_selected:sender
455{
456 int tag;
457 NSString *item;
458
459 tag = [sender tag] - 1;
460 if (apps == nil || tag < 0 || tag >= [apps count])
461 return;
462
463 item = [[apps objectAtIndex:tag] objectAtIndex:1];
464
465 [self launch_client:item];
466}
467
468- (IBAction) apps_table_show:sender
469{
470 NSArray *columns;
471 NSMutableArray *oldapps = nil;
472
473 if (table_apps != nil)
474 oldapps = table_apps;
475
476 table_apps = [[NSMutableArray alloc] initWithCapacity:1];
477 if (apps != nil)
478 [table_apps addObjectsFromArray:apps];
479
480 columns = [apps_table tableColumns];
481 [[columns objectAtIndex:0] setIdentifier:@"0"];
482 [[columns objectAtIndex:1] setIdentifier:@"1"];
483 [[columns objectAtIndex:2] setIdentifier:@"2"];
484
485 [apps_table setDataSource:self];
486 [apps_table selectRowIndexes:[NSIndexSet indexSetWithIndex:0]
487 byExtendingSelection:NO];
488
489 [[apps_table window] makeKeyAndOrderFront:sender];
490 [apps_table reloadData];
491 if (oldapps != nil)
492 [oldapps release];
493}
494
495- (IBAction) apps_table_done:sender
496{
497 [apps_table deselectAll:sender]; /* flush edits? */
498
499 [self remove_apps_menu];
500 [self install_apps_menu:table_apps];
501
502 [NSApp prefs_set_array:@PREFS_APPSMENU value:table_apps];
503 [NSApp prefs_synchronize];
504
505 [[apps_table window] orderOut:sender];
506
507 [table_apps release];
508 table_apps = nil;
509}
510
511- (IBAction) apps_table_new:sender
512{
513 NSMutableArray *item;
514
515 int row = [apps_table selectedRow], i;
516
517 if (row < 0) row = 0;
518 else row = row + 1;
519
520 i = row;
521 if (i > [table_apps count])
522 return; /* avoid exceptions */
523
524 [apps_table deselectAll:sender];
525
526 item = [[NSMutableArray alloc] initWithCapacity:3];
527 [item addObject:@""];
528 [item addObject:@""];
529 [item addObject:@""];
530
531 [table_apps insertObject:item atIndex:i];
532 [item release];
533
534 [apps_table reloadData];
535 [apps_table selectRowIndexes:[NSIndexSet indexSetWithIndex:row]
536 byExtendingSelection:NO];
537}
538
539- (IBAction) apps_table_duplicate:sender
540{
541 int row = [apps_table selectedRow], i;
542 NSObject *item;
543
544 if (row < 0) {
545 [self apps_table_new:sender];
546 return;
547 }
548
549 i = row;
550 if (i > [table_apps count] - 1) return; /* avoid exceptions */
551
552 [apps_table deselectAll:sender];
553
554 item = [[table_apps objectAtIndex:i] mutableCopy];
555 [table_apps insertObject:item atIndex:i];
556 [item release];
557
558 [apps_table reloadData];
559 [apps_table selectRowIndexes:[NSIndexSet indexSetWithIndex:row +
560 1] byExtendingSelection:NO];
561}
562
563- (IBAction) apps_table_delete:sender
564{
565 int row = [apps_table selectedRow];
566
567 if (row >= 0) {
568 int i = row;
569
570 if (i > [table_apps count] - 1) return; /* avoid exceptions */
571
572 [apps_table deselectAll:sender];
573
574 [table_apps removeObjectAtIndex:i];
575 }
576
577 [apps_table reloadData];
578
579 row = MIN(row, [table_apps count] - 1);
580 if (row >= 0)
581 [apps_table selectRowIndexes:[NSIndexSet indexSetWithIndex:row]
582 byExtendingSelection:NO];
583}
584
585- (NSInteger) numberOfRowsInTableView:(NSTableView *)tableView
586{
587 if (table_apps == nil) return 0;
588
589 return [table_apps count];
590}
591
592- (id) tableView:(NSTableView *)tableView
593 objectValueForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row
594{
595 NSArray *item;
596 int col;
597
598 if (table_apps == nil) return nil;
599
600 col = [[tableColumn identifier] intValue];
601
602 item = [table_apps objectAtIndex:row];
603 if ([item count] > col)
604 return [item objectAtIndex:col];
605 else
606 return @"";
607}
608
609- (void) tableView:(NSTableView *)tableView setObjectValue:(id)object
610 forTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row
611{
612 NSMutableArray *item;
613 int col;
614
615 if (table_apps == nil) return;
616
617 col = [[tableColumn identifier] intValue];
618
619 item = [table_apps objectAtIndex:row];
620 [item replaceObjectAtIndex:col withObject:object];
621}
622
623- (void) hide_window:sender
624{
625 if ([X11App x_active])
626 DarwinSendDDXEvent(kXquartzControllerNotify, 1, AppleWMHideWindow);
627 else
628 NSBeep(); /* FIXME: something here */
629}
630
631- (IBAction)bring_to_front:sender
632{
633 DarwinSendDDXEvent(kXquartzControllerNotify, 1, AppleWMBringAllToFront);
634}
635
636- (IBAction)close_window:sender
637{
638 if ([X11App x_active])
639 DarwinSendDDXEvent(kXquartzControllerNotify, 1, AppleWMCloseWindow);
640 else
641 [[NSApp keyWindow] performClose:sender];
642}
643
644- (IBAction)minimize_window:sender
645{
646 if ([X11App x_active])
647 DarwinSendDDXEvent(kXquartzControllerNotify, 1, AppleWMMinimizeWindow);
648 else
649 [[NSApp keyWindow] performMiniaturize:sender];
650}
651
652- (IBAction)zoom_window:sender
653{
654 if ([X11App x_active])
655 DarwinSendDDXEvent(kXquartzControllerNotify, 1, AppleWMZoomWindow);
656 else
657 [[NSApp keyWindow] performZoom:sender];
658}
659
660- (IBAction) next_window:sender
661{
662 DarwinSendDDXEvent(kXquartzControllerNotify, 1, AppleWMNextWindow);
663}
664
665- (IBAction) previous_window:sender
666{
667 DarwinSendDDXEvent(kXquartzControllerNotify, 1, AppleWMPreviousWindow);
668}
669
670- (IBAction) enable_fullscreen_changed:sender
671{
672 XQuartzRootlessDefault = ![enable_fullscreen intValue];
673
674 [enable_fullscreen_menu setEnabled:!XQuartzRootlessDefault];
675 [enable_fullscreen_menu_text setTextColor:XQuartzRootlessDefault ?[
676 NSColor disabledControlTextColor] : [NSColor controlTextColor]];
677
678 DarwinSendDDXEvent(kXquartzSetRootless, 1, XQuartzRootlessDefault);
679
680 [NSApp prefs_set_boolean:@PREFS_ROOTLESS value:XQuartzRootlessDefault];
681 [NSApp prefs_synchronize];
682}
683
684- (IBAction) toggle_fullscreen:sender
685{
686 DarwinSendDDXEvent(kXquartzToggleFullscreen, 0);
687}
688
689- (void) set_can_quit:(OSX_BOOL)state
690{
691 can_quit = state;
692}
693
694- (IBAction)prefs_changed:sender
695{
696 if (!sender)
697 return;
698
699 if (sender == fake_buttons) {
700 darwinFakeButtons = [fake_buttons intValue];
701 [NSApp prefs_set_boolean:@PREFS_FAKEBUTTONS value:darwinFakeButtons];
702 }
703 else if (sender == enable_keyequivs) {
704 XQuartzEnableKeyEquivalents = [enable_keyequivs intValue];
705 [NSApp prefs_set_boolean:@PREFS_KEYEQUIVS value:
706 XQuartzEnableKeyEquivalents];
707 }
708 else if (sender == sync_keymap) {
709 darwinSyncKeymap = [sync_keymap intValue];
710 [NSApp prefs_set_boolean:@PREFS_SYNC_KEYMAP value:darwinSyncKeymap];
711 }
712 else if (sender == enable_fullscreen_menu) {
713 XQuartzFullscreenMenu = [enable_fullscreen_menu intValue];
714 [NSApp prefs_set_boolean:@PREFS_FULLSCREEN_MENU value:
715 XQuartzFullscreenMenu];
716 }
717 else if (sender == option_sends_alt) {
718 BOOL prev_opt_sends_alt = XQuartzOptionSendsAlt;
719
720 XQuartzOptionSendsAlt = [option_sends_alt intValue];
721 [NSApp prefs_set_boolean:@PREFS_OPTION_SENDS_ALT value:
722 XQuartzOptionSendsAlt];
723
724 if (prev_opt_sends_alt != XQuartzOptionSendsAlt)
725 QuartsResyncKeymap(TRUE);
726 }
727 else if (sender == click_through) {
728 [NSApp prefs_set_boolean:@PREFS_CLICK_THROUGH value:[click_through
729 intValue]];
730 }
731 else if (sender == focus_follows_mouse) {
732 [NSApp prefs_set_boolean:@PREFS_FFM value:[focus_follows_mouse
733 intValue]];
734 }
735 else if (sender == focus_on_new_window) {
736 [NSApp prefs_set_boolean:@PREFS_FOCUS_ON_NEW_WINDOW value:[
737 focus_on_new_window intValue]];
738 }
739 else if (sender == enable_auth) {
740 [NSApp prefs_set_boolean:@PREFS_NO_AUTH value:![enable_auth intValue]
741 ];
742 }
743 else if (sender == enable_tcp) {
744 [NSApp prefs_set_boolean:@PREFS_NO_TCP value:![enable_tcp intValue]];
745 }
746 else if (sender == depth) {
747 [NSApp prefs_set_integer:@PREFS_DEPTH value:[depth selectedTag]];
748 }
749 else if (sender == sync_pasteboard) {
750 BOOL pbproxy_active = [sync_pasteboard intValue];
751 [NSApp prefs_set_boolean:@PREFS_SYNC_PB value:pbproxy_active];
752
753 [sync_pasteboard_to_clipboard setEnabled:pbproxy_active];
754 [sync_pasteboard_to_primary setEnabled:pbproxy_active];
755 [sync_clipboard_to_pasteboard setEnabled:pbproxy_active];
756 [sync_primary_immediately setEnabled:pbproxy_active];
757
758 // setEnabled doesn't do this...
759 [sync_text1 setTextColor:pbproxy_active ?[NSColor controlTextColor] :
760 [NSColor disabledControlTextColor]];
761 [sync_text2 setTextColor:pbproxy_active ?[NSColor controlTextColor] :
762 [NSColor disabledControlTextColor]];
763 }
764 else if (sender == sync_pasteboard_to_clipboard) {
765 [NSApp prefs_set_boolean:@PREFS_SYNC_PB_TO_CLIPBOARD value:[
766 sync_pasteboard_to_clipboard intValue]];
767 }
768 else if (sender == sync_pasteboard_to_primary) {
769 [NSApp prefs_set_boolean:@PREFS_SYNC_PB_TO_PRIMARY value:[
770 sync_pasteboard_to_primary intValue]];
771 }
772 else if (sender == sync_clipboard_to_pasteboard) {
773 [NSApp prefs_set_boolean:@PREFS_SYNC_CLIPBOARD_TO_PB value:[
774 sync_clipboard_to_pasteboard intValue]];
775 }
776 else if (sender == sync_primary_immediately) {
777 [NSApp prefs_set_boolean:@PREFS_SYNC_PRIMARY_ON_SELECT value:[
778 sync_primary_immediately intValue]];
779 }
780 else if (sender == scroll_in_device_direction) {
781 XQuartzScrollInDeviceDirection =
782 [scroll_in_device_direction intValue];
783 [NSApp prefs_set_boolean:@PREFS_SCROLL_IN_DEV_DIRECTION value:
784 XQuartzScrollInDeviceDirection];
785 }
786
787 [NSApp prefs_synchronize];
788
789 DarwinSendDDXEvent(kXquartzReloadPreferences, 0);
790}
791
792- (IBAction) prefs_show:sender
793{
794 BOOL pbproxy_active =
795 [NSApp prefs_get_boolean:@PREFS_SYNC_PB default:YES];
796
797 // Remove preferences from the GUI which are not supported
798 // TODO: Change 1117 to NSAppKitVersionNumber10_7 when it is defined
799 if (scroll_in_device_direction && NSAppKitVersionNumber < 1117) {
800 [scroll_in_device_direction removeFromSuperview];
801 scroll_in_device_direction = nil;
802 }
803 else {
804 [scroll_in_device_direction setIntValue:
805 XQuartzScrollInDeviceDirection];
806 }
807
808 [fake_buttons setIntValue:darwinFakeButtons];
809 [enable_keyequivs setIntValue:XQuartzEnableKeyEquivalents];
810 [sync_keymap setIntValue:darwinSyncKeymap];
811 [option_sends_alt setIntValue:XQuartzOptionSendsAlt];
812 [click_through setIntValue:[NSApp prefs_get_boolean:@PREFS_CLICK_THROUGH
813 default:NO]];
814 [focus_follows_mouse setIntValue:[NSApp prefs_get_boolean:@PREFS_FFM
815 default:NO]];
816 [focus_on_new_window setIntValue:[NSApp prefs_get_boolean:
817 @PREFS_FOCUS_ON_NEW_WINDOW default:YES]
818 ];
819
820 [enable_auth setIntValue:![NSApp prefs_get_boolean:@PREFS_NO_AUTH default
821 :NO]];
822 [enable_tcp setIntValue:![NSApp prefs_get_boolean:@PREFS_NO_TCP default:
823 NO]];
824
825 [depth selectItemAtIndex:[depth indexOfItemWithTag:[NSApp
826 prefs_get_integer:
827 @PREFS_DEPTH default:
828 -1]]];
829
830 [sync_pasteboard setIntValue:pbproxy_active];
831 [sync_pasteboard_to_clipboard setIntValue:[NSApp prefs_get_boolean:
832 @PREFS_SYNC_PB_TO_CLIPBOARD
833 default:YES]];
834 [sync_pasteboard_to_primary setIntValue:[NSApp prefs_get_boolean:
835 @PREFS_SYNC_PB_TO_PRIMARY
836 default:YES]];
837 [sync_clipboard_to_pasteboard setIntValue:[NSApp prefs_get_boolean:
838 @PREFS_SYNC_CLIPBOARD_TO_PB
839 default:YES]];
840 [sync_primary_immediately setIntValue:[NSApp prefs_get_boolean:
841 @PREFS_SYNC_PRIMARY_ON_SELECT
842 default:NO]];
843
844 [sync_pasteboard_to_clipboard setEnabled:pbproxy_active];
845 [sync_pasteboard_to_primary setEnabled:pbproxy_active];
846 [sync_clipboard_to_pasteboard setEnabled:pbproxy_active];
847 [sync_primary_immediately setEnabled:pbproxy_active];
848
849 // setEnabled doesn't do this...
850 [sync_text1 setTextColor:pbproxy_active ?[NSColor controlTextColor] : [
851 NSColor disabledControlTextColor]];
852 [sync_text2 setTextColor:pbproxy_active ?[NSColor controlTextColor] : [
853 NSColor disabledControlTextColor]];
854
855 [enable_fullscreen setIntValue:!XQuartzRootlessDefault];
856 [enable_fullscreen_menu setIntValue:XQuartzFullscreenMenu];
857 [enable_fullscreen_menu setEnabled:!XQuartzRootlessDefault];
858 [enable_fullscreen_menu_text setTextColor:XQuartzRootlessDefault ?[
859 NSColor disabledControlTextColor] : [NSColor controlTextColor]];
860
861 [prefs_panel makeKeyAndOrderFront:sender];
862}
863
864- (IBAction) quit:sender
865{
866 DarwinSendDDXEvent(kXquartzQuit, 0);
867}
868
869- (IBAction) x11_help:sender
870{
871#if MAC_OS_X_VERSION_MIN_REQUIRED < 1060
872 AHLookupAnchor((CFStringRef)NSLocalizedString(@"Mac Help",
873 no comment),
874 CFSTR("mchlp2276"));
875#else
876 AHLookupAnchor(CFSTR("com.apple.machelp"), CFSTR("mchlp2276"));
877#endif
878}
879
880- (OSX_BOOL) validateMenuItem:(NSMenuItem *)item
881{
882 NSMenu *menu = [item menu];
883
884 if (item == toggle_fullscreen_item)
885 return !XQuartzIsRootless;
886 else if (menu == [X11App windowsMenu] || menu == dock_menu
887 || (menu == [x11_about_item menu] && [item tag] == 42))
888 return (AppleWMSelectedEvents() & AppleWMControllerNotifyMask) != 0;
889 else
890 return TRUE;
891}
892
893- (void) applicationDidHide:(NSNotification *)notify
894{
895 DarwinSendDDXEvent(kXquartzControllerNotify, 1, AppleWMHideAll);
896
897 /* Toggle off fullscreen mode to leave our non-default video
898 * mode and hide our guard window.
899 */
900 if (!XQuartzIsRootless && XQuartzFullscreenVisible) {
901 DarwinSendDDXEvent(kXquartzToggleFullscreen, 0);
902 }
903}
904
905- (void) applicationDidUnhide:(NSNotification *)notify
906{
907 DarwinSendDDXEvent(kXquartzControllerNotify, 1, AppleWMShowAll);
908}
909
910- (NSApplicationTerminateReply) applicationShouldTerminate:sender
911{
912 NSString *msg;
913 NSString *title;
914
915 if (can_quit ||
916 [X11App prefs_get_boolean:@PREFS_NO_QUIT_ALERT default:NO])
917 return NSTerminateNow;
918
919 /* Make sure we're frontmost. */
920 [NSApp activateIgnoringOtherApps:YES];
921
922 title = NSLocalizedString(@"Do you really want to quit X11?",
923 @"Dialog title when quitting");
924 msg = NSLocalizedString(
925 @"Any open X11 applications will stop immediately, and you will lose any unsaved changes.",
926 @"Dialog when quitting");
927
928 /* FIXME: safe to run the alert in here? Or should we return Later
929 * and then run the alert on a timer? It seems to work here, so..
930 */
931
932 return (NSRunAlertPanel(title, msg, NSLocalizedString(@"Quit", @""),
933 NSLocalizedString(@"Cancel", @""), nil)
934 == NSAlertDefaultReturn) ? NSTerminateNow : NSTerminateCancel;
935}
936
937- (void) applicationWillTerminate:(NSNotification *)aNotification _X_NORETURN
938{
939 int remain;
940 [X11App prefs_synchronize];
941
942 /* shutdown the X server, it will exit () for us. */
943 DarwinSendDDXEvent(kXquartzQuit, 0);
944
945 /* In case it doesn't, exit anyway after a while. */
946 remain = 10000000;
947 while ((remain = usleep(remain)) > 0) ;
948
949 exit(1);
950}
951
952- (void) server_ready
953{
954 x_list *node;
955
956 finished_launching = YES;
957
958 for (node = pending_apps; node != NULL; node = node->next) {
959 NSString *filename = node->data;
960 [self launch_client:filename];
961 [filename release];
962 }
963
964 x_list_free(pending_apps);
965 pending_apps = NULL;
966}
967
968- (OSX_BOOL) application:(NSApplication *)app openFile:(NSString *)filename
969{
970 const char *name = [filename UTF8String];
971
972 if (finished_launching)
973 [self launch_client:filename];
974 else if (name[0] != ':') /* ignore display names */
975 pending_apps = x_list_prepend(pending_apps, [filename retain]);
976
977 /* FIXME: report failures. */
978 return YES;
979}
980
981@end
982
983void
984X11ControllerMain(int argc, char **argv, char **envp)
985{
986 X11ApplicationMain(argc, argv, envp);
987}