Imported Upstream version 1.15.1
[deb_xorg-server.git] / hw / xquartz / X11Controller.m
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
59 extern aslclient aslc;
60 extern 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
983 void
984 X11ControllerMain(int argc, char **argv, char **envp)
985 {
986 X11ApplicationMain(argc, argv, envp);
987 }