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 [enable_fullscreen_menu_text setTextColor:XQuartzRootlessDefault ? [NSColor disabledControlTextColor] : [NSColor controlTextColor]]; 616 617 DarwinSendDDXEvent(kXquartzSetRootless, 1, XQuartzRootlessDefault); 618 619 [NSApp prefs_set_boolean:@PREFS_ROOTLESS value:XQuartzRootlessDefault]; 620 [NSApp prefs_synchronize]; 621} 622 623- (IBAction) toggle_fullscreen:sender 624{ 625 DarwinSendDDXEvent(kXquartzToggleFullscreen, 0); 626} 627 628- (void) set_can_quit:(OSX_BOOL)state 629{ 630 can_quit = state; 631} 632 633- (IBAction)prefs_changed:sender 634{ 635 if(!sender) 636 return; 637 638 if(sender == fake_buttons) { 639 darwinFakeButtons = [fake_buttons intValue]; 640 [NSApp prefs_set_boolean:@PREFS_FAKEBUTTONS value:darwinFakeButtons]; 641 } else if(sender == enable_keyequivs) { 642 XQuartzEnableKeyEquivalents = [enable_keyequivs intValue]; 643 [NSApp prefs_set_boolean:@PREFS_KEYEQUIVS value:XQuartzEnableKeyEquivalents]; 644 } else if(sender == sync_keymap) { 645 darwinSyncKeymap = [sync_keymap intValue]; 646 [NSApp prefs_set_boolean:@PREFS_SYNC_KEYMAP value:darwinSyncKeymap]; 647 } else if(sender == enable_fullscreen_menu) { 648 XQuartzFullscreenMenu = [enable_fullscreen_menu intValue]; 649 [NSApp prefs_set_boolean:@PREFS_FULLSCREEN_MENU value:XQuartzFullscreenMenu]; 650 } else if(sender == option_sends_alt) { 651 BOOL prev_opt_sends_alt = XQuartzOptionSendsAlt; 652 653 XQuartzOptionSendsAlt = [option_sends_alt intValue]; 654 [NSApp prefs_set_boolean:@PREFS_OPTION_SENDS_ALT value:XQuartzOptionSendsAlt]; 655 656 if(prev_opt_sends_alt != XQuartzOptionSendsAlt) 657 QuartsResyncKeymap(TRUE); 658 } else if(sender == click_through) { 659 [NSApp prefs_set_boolean:@PREFS_CLICK_THROUGH value:[click_through intValue]]; 660 } else if(sender == focus_follows_mouse) { 661 [NSApp prefs_set_boolean:@PREFS_FFM value:[focus_follows_mouse intValue]]; 662 } else if(sender == focus_on_new_window) { 663 [NSApp prefs_set_boolean:@PREFS_FOCUS_ON_NEW_WINDOW value:[focus_on_new_window intValue]]; 664 } else if(sender == enable_auth) { 665 [NSApp prefs_set_boolean:@PREFS_NO_AUTH value:![enable_auth intValue]]; 666 } else if(sender == enable_tcp) { 667 [NSApp prefs_set_boolean:@PREFS_NO_TCP value:![enable_tcp intValue]]; 668 } else if(sender == depth) { 669 [NSApp prefs_set_integer:@PREFS_DEPTH value:[depth selectedTag]]; 670 } else if(sender == sync_pasteboard) { 671 BOOL pbproxy_active = [sync_pasteboard intValue]; 672 [NSApp prefs_set_boolean:@PREFS_SYNC_PB value:pbproxy_active]; 673 674 [sync_pasteboard_to_clipboard setEnabled:pbproxy_active]; 675 [sync_pasteboard_to_primary setEnabled:pbproxy_active]; 676 [sync_clipboard_to_pasteboard setEnabled:pbproxy_active]; 677 [sync_primary_immediately setEnabled:pbproxy_active]; 678 679 // setEnabled doesn't do this... 680 [sync_text1 setTextColor:pbproxy_active ? [NSColor controlTextColor] : [NSColor disabledControlTextColor]]; 681 [sync_text2 setTextColor:pbproxy_active ? [NSColor controlTextColor] : [NSColor disabledControlTextColor]]; 682 } else if(sender == sync_pasteboard_to_clipboard) { 683 [NSApp prefs_set_boolean:@PREFS_SYNC_PB_TO_CLIPBOARD value:[sync_pasteboard_to_clipboard intValue]]; 684 } else if(sender == sync_pasteboard_to_primary) { 685 [NSApp prefs_set_boolean:@PREFS_SYNC_PB_TO_PRIMARY value:[sync_pasteboard_to_primary intValue]]; 686 } else if(sender == sync_clipboard_to_pasteboard) { 687 [NSApp prefs_set_boolean:@PREFS_SYNC_CLIPBOARD_TO_PB value:[sync_clipboard_to_pasteboard intValue]]; 688 } else if(sender == sync_primary_immediately) { 689 [NSApp prefs_set_boolean:@PREFS_SYNC_PRIMARY_ON_SELECT value:[sync_primary_immediately intValue]]; 690 } else if(sender == scroll_in_device_direction) { 691 XQuartzScrollInDeviceDirection = [scroll_in_device_direction intValue]; 692 [NSApp prefs_set_boolean:@PREFS_SCROLL_IN_DEV_DIRECTION value:XQuartzScrollInDeviceDirection]; 693 } 694 695 [NSApp prefs_synchronize]; 696 697 DarwinSendDDXEvent(kXquartzReloadPreferences, 0); 698} 699 700- (IBAction) prefs_show:sender 701{ 702 BOOL pbproxy_active = [NSApp prefs_get_boolean:@PREFS_SYNC_PB default:YES]; 703 704 // Remove preferences from the GUI which are not supported 705 // TODO: Change 1117 to NSAppKitVersionNumber10_7 when it is defined 706 if(scroll_in_device_direction && NSAppKitVersionNumber < 1117) { 707 [scroll_in_device_direction removeFromSuperview]; 708 scroll_in_device_direction = nil; 709 } else { 710 [scroll_in_device_direction setIntValue:XQuartzScrollInDeviceDirection]; 711 } 712 713 [fake_buttons setIntValue:darwinFakeButtons]; 714 [enable_keyequivs setIntValue:XQuartzEnableKeyEquivalents]; 715 [sync_keymap setIntValue:darwinSyncKeymap]; 716 [option_sends_alt setIntValue:XQuartzOptionSendsAlt]; 717 [click_through setIntValue:[NSApp prefs_get_boolean:@PREFS_CLICK_THROUGH default:NO]]; 718 [focus_follows_mouse setIntValue:[NSApp prefs_get_boolean:@PREFS_FFM default:NO]]; 719 [focus_on_new_window setIntValue:[NSApp prefs_get_boolean:@PREFS_FOCUS_ON_NEW_WINDOW default:YES]]; 720 721 [enable_auth setIntValue:![NSApp prefs_get_boolean:@PREFS_NO_AUTH default:NO]]; 722 [enable_tcp setIntValue:![NSApp prefs_get_boolean:@PREFS_NO_TCP default:NO]]; 723 724 [depth selectItemAtIndex:[depth indexOfItemWithTag:[NSApp prefs_get_integer:@PREFS_DEPTH default:-1]]]; 725 726 [sync_pasteboard setIntValue:pbproxy_active]; 727 [sync_pasteboard_to_clipboard setIntValue:[NSApp prefs_get_boolean:@PREFS_SYNC_PB_TO_CLIPBOARD default:YES]]; 728 [sync_pasteboard_to_primary setIntValue:[NSApp prefs_get_boolean:@PREFS_SYNC_PB_TO_PRIMARY default:YES]]; 729 [sync_clipboard_to_pasteboard setIntValue:[NSApp prefs_get_boolean:@PREFS_SYNC_CLIPBOARD_TO_PB default:YES]]; 730 [sync_primary_immediately setIntValue:[NSApp prefs_get_boolean:@PREFS_SYNC_PRIMARY_ON_SELECT default:NO]]; 731 732 [sync_pasteboard_to_clipboard setEnabled:pbproxy_active]; 733 [sync_pasteboard_to_primary setEnabled:pbproxy_active]; 734 [sync_clipboard_to_pasteboard setEnabled:pbproxy_active]; 735 [sync_primary_immediately setEnabled:pbproxy_active]; 736 737 // setEnabled doesn't do this... 738 [sync_text1 setTextColor:pbproxy_active ? [NSColor controlTextColor] : [NSColor disabledControlTextColor]]; 739 [sync_text2 setTextColor:pbproxy_active ? [NSColor controlTextColor] : [NSColor disabledControlTextColor]]; 740 741 [enable_fullscreen setIntValue:!XQuartzRootlessDefault]; 742 [enable_fullscreen_menu setIntValue:XQuartzFullscreenMenu]; 743 [enable_fullscreen_menu setEnabled:!XQuartzRootlessDefault]; 744 [enable_fullscreen_menu_text setTextColor:XQuartzRootlessDefault ? [NSColor disabledControlTextColor] : [NSColor controlTextColor]]; 745 746 [prefs_panel makeKeyAndOrderFront:sender]; 747} 748 749- (IBAction) quit:sender { 750 DarwinSendDDXEvent(kXquartzQuit, 0); 751} 752 753- (IBAction) x11_help:sender { 754#if MAC_OS_X_VERSION_MIN_REQUIRED < 1060 755 AHLookupAnchor((CFStringRef)NSLocalizedString(@"Mac Help", no comment), CFSTR("mchlp2276")); 756#else 757 AHLookupAnchor(CFSTR("com.apple.machelp"), CFSTR("mchlp2276")); 758#endif 759} 760 761- (OSX_BOOL) validateMenuItem:(NSMenuItem *)item { 762 NSMenu *menu = [item menu]; 763 764 if (item == toggle_fullscreen_item) 765 return !XQuartzIsRootless; 766 else if (menu == [X11App windowsMenu] || menu == dock_menu 767 || (menu == [x11_about_item menu] && [item tag] == 42)) 768 return (AppleWMSelectedEvents () & AppleWMControllerNotifyMask) != 0; 769 else 770 return TRUE; 771} 772 773- (void) applicationDidHide:(NSNotification *)notify 774{ 775 DarwinSendDDXEvent(kXquartzControllerNotify, 1, AppleWMHideAll); 776} 777 778- (void) applicationDidUnhide:(NSNotification *)notify 779{ 780 DarwinSendDDXEvent(kXquartzControllerNotify, 1, AppleWMShowAll); 781} 782 783- (NSApplicationTerminateReply) applicationShouldTerminate:sender { 784 NSString *msg; 785 NSString *title; 786 787 if (can_quit || [X11App prefs_get_boolean:@PREFS_NO_QUIT_ALERT default:NO]) 788 return NSTerminateNow; 789 790 /* Make sure we're frontmost. */ 791 [NSApp activateIgnoringOtherApps:YES]; 792 793 title = NSLocalizedString(@"Do you really want to quit X11?", @"Dialog title when quitting"); 794 msg = NSLocalizedString(@"Any open X11 applications will stop immediately, and you will lose any unsaved changes.", @"Dialog when quitting"); 795 796 /* FIXME: safe to run the alert in here? Or should we return Later 797 * and then run the alert on a timer? It seems to work here, so.. 798 */ 799 800 return (NSRunAlertPanel (title, msg, NSLocalizedString (@"Quit", @""), 801 NSLocalizedString (@"Cancel", @""), nil) 802 == NSAlertDefaultReturn) ? NSTerminateNow : NSTerminateCancel; 803} 804 805- (void) applicationWillTerminate:(NSNotification *)aNotification 806{ 807 unsigned remain; 808 [X11App prefs_synchronize]; 809 810 /* shutdown the X server, it will exit () for us. */ 811 DarwinSendDDXEvent(kXquartzQuit, 0); 812 813 /* In case it doesn't, exit anyway after a while. */ 814 remain = 10000000; 815 while((remain = usleep(remain)) > 0); 816 817 exit (1); 818} 819 820- (void) server_ready 821{ 822 x_list *node; 823 824 finished_launching = YES; 825 826 for (node = pending_apps; node != NULL; node = node->next) 827 { 828 NSString *filename = node->data; 829 [self launch_client:filename]; 830 [filename release]; 831 } 832 833 x_list_free (pending_apps); 834 pending_apps = NULL; 835} 836 837- (OSX_BOOL) application:(NSApplication *)app openFile:(NSString *)filename 838{ 839 const char *name = [filename UTF8String]; 840 841 if (finished_launching) 842 [self launch_client:filename]; 843 else if (name[0] != ':') /* ignore display names */ 844 pending_apps = x_list_prepend (pending_apps, [filename retain]); 845 846 /* FIXME: report failures. */ 847 return YES; 848} 849 850@end 851 852void X11ControllerMain(int argc, char **argv, char **envp) { 853 X11ApplicationMain (argc, argv, envp); 854} 855