X11Controller.m revision 35c4bbdf
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 NSInteger result = NSRunAlertPanel(title, @"%@", NSLocalizedString(@"Quit", @""), 933 NSLocalizedString(@"Cancel", @""), nil, msg); 934 return (result == NSAlertDefaultReturn) ? NSTerminateNow : NSTerminateCancel; 935} 936 937- (void) applicationWillTerminate:(NSNotification *)aNotification _X_NORETURN 938{ 939 [X11App prefs_synchronize]; 940 941 /* shutdown the X server, it will exit () for us. */ 942 DarwinSendDDXEvent(kXquartzQuit, 0); 943 944 /* In case it doesn't, exit anyway after 5s. */ 945 [NSThread sleepForTimeInterval:5.0]; 946 947 exit(1); 948} 949 950- (void) server_ready 951{ 952 x_list *node; 953 954 finished_launching = YES; 955 956 for (node = pending_apps; node != NULL; node = node->next) { 957 NSString *filename = node->data; 958 [self launch_client:filename]; 959 [filename release]; 960 } 961 962 x_list_free(pending_apps); 963 pending_apps = NULL; 964} 965 966- (OSX_BOOL) application:(NSApplication *)app openFile:(NSString *)filename 967{ 968 const char *name = [filename UTF8String]; 969 970 if (finished_launching) 971 [self launch_client:filename]; 972 else if (name[0] != ':') /* ignore display names */ 973 pending_apps = x_list_prepend(pending_apps, [filename retain]); 974 975 /* FIXME: report failures. */ 976 return YES; 977} 978 979@end 980 981void 982X11ControllerMain(int argc, char **argv, char **envp) 983{ 984 X11ApplicationMain(argc, argv, envp); 985} 986