1 /* X11Controller.m -- connect the IB ui, also the NSApp delegate
2 $Id: X11Controller.m,v 1.36 2003/07/24 17:52:29 jharper Exp $
4 Copyright (c) 2002 Apple Computer, Inc. All rights reserved.
6 Permission is hereby granted, free of charge, to any person
7 obtaining a copy of this software and associated documentation files
8 (the "Software"), to deal in the Software without restriction,
9 including without limitation the rights to use, copy, modify, merge,
10 publish, distribute, sublicense, and/or sell copies of the Software,
11 and to permit persons to whom the Software is furnished to do so,
12 subject to the following conditions:
14 The above copyright notice and this permission notice shall be
15 included in all copies or substantial portions of the Software.
17 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20 NONINFRINGEMENT. IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT
21 HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
22 WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
24 DEALINGS IN THE SOFTWARE.
26 Except as contained in this notice, the name(s) of the above
27 copyright holders shall not be used in advertising or otherwise to
28 promote the sale, use or other dealings in this Software without
29 prior written authorization. */
32 #import "X11Controller.h"
33 #import "X11Application.h"
34 #import <Carbon/Carbon.h>
40 #define WindowPtr X_WindowPtr
41 #define Cursor X_Cursor
43 # define _APPLEWM_SERVER_
53 #define TRACE() fprintf (stderr, "%s\n", __FUNCTION__)
55 @implementation X11Controller
59 X11Application *xapp = NSApp;
62 /* Point X11Application at ourself. */
63 [xapp set_controller:self];
65 array = [xapp prefs_get_array:@PREFS_APPSMENU];
70 /* convert from [TITLE1 COMMAND1 TITLE2 COMMAND2 ...]
71 to [[TITLE1 COMMAND1] [TITLE2 COMMAND2] ...] format. */
73 count = [array count];
75 && ![[array objectAtIndex:0] isKindOfClass:[NSArray class]])
78 NSMutableArray *copy, *sub;
80 copy = [NSMutableArray arrayWithCapacity:(count / 2)];
82 for (i = 0; i < count / 2; i++)
84 sub = [[NSMutableArray alloc] initWithCapacity:3];
85 [sub addObject:[array objectAtIndex:i*2]];
86 [sub addObject:[array objectAtIndex:i*2+1]];
95 [self set_apps_menu:array];
100 - (void) item_selected:sender
102 [NSApp activateIgnoringOtherApps:YES];
104 QuartzMessageMainThread (kXquartzControllerNotify, 2,
105 AppleWMWindowMenuItem, [sender tag]);
108 - (void) remove_window_menu
113 /* Work backwards so we don't mess up the indices */
114 menu = [window_separator menu];
115 first = [menu indexOfItem:window_separator] + 1;
116 count = [menu numberOfItems];
117 for (i = count - 1; i >= first; i--)
118 [menu removeItemAtIndex:i];
120 menu = [dock_window_separator menu];
121 count = [menu indexOfItem:dock_window_separator];
122 for (i = 0; i < count; i++)
123 [dock_menu removeItemAtIndex:0];
126 - (void) install_window_menu:(NSArray *)list
132 menu = [window_separator menu];
133 first = [menu indexOfItem:window_separator] + 1;
134 count = [list count];
136 for (i = 0; i < count; i++)
138 NSString *name, *shortcut;
140 name = [[list objectAtIndex:i] objectAtIndex:0];
141 shortcut = [[list objectAtIndex:i] objectAtIndex:1];
143 item = (NSMenuItem *) [menu addItemWithTitle:name action:@selector
144 (item_selected:) keyEquivalent:shortcut];
145 [item setTarget:self];
147 [item setEnabled:YES];
149 item = (NSMenuItem *) [dock_menu insertItemWithTitle:name
151 (item_selected:) keyEquivalent:shortcut
153 [item setTarget:self];
155 [item setEnabled:YES];
158 if (checked_window_item >= 0 && checked_window_item < count)
160 item = (NSMenuItem *) [menu itemAtIndex:first + checked_window_item];
161 [item setState:NSOnState];
162 item = (NSMenuItem *) [dock_menu itemAtIndex:checked_window_item];
163 [item setState:NSOnState];
167 - (void) remove_apps_menu
173 if (apps == nil || apps_separator == nil)
176 menu = [apps_separator menu];
180 for (i = [menu numberOfItems] - 1; i >= 0; i--)
182 item = (NSMenuItem *) [menu itemAtIndex:i];
184 [menu removeItemAtIndex:i];
188 if (dock_apps_menu != nil)
190 for (i = [dock_apps_menu numberOfItems] - 1; i >= 0; i--)
192 item = (NSMenuItem *) [dock_apps_menu itemAtIndex:i];
194 [dock_apps_menu removeItemAtIndex:i];
202 - (void) prepend_apps_item:(NSArray *)list index:(int)i menu:(NSMenu *)menu
204 NSString *title, *shortcut = @"";
208 group = [list objectAtIndex:i];
209 title = [group objectAtIndex:0];
210 if ([group count] >= 3)
211 shortcut = [group objectAtIndex:2];
213 if ([title length] != 0)
215 item = (NSMenuItem *) [menu insertItemWithTitle:title
216 action:@selector (app_selected:)
217 keyEquivalent:shortcut atIndex:0];
218 [item setTarget:self];
219 [item setEnabled:YES];
223 item = (NSMenuItem *) [NSMenuItem separatorItem];
224 [menu insertItem:item atIndex:0];
227 [item setTag:i+1]; /* can't be zero, so add one */
230 - (void) install_apps_menu:(NSArray *)list
235 count = [list count];
237 if (count == 0 || apps_separator == nil)
240 menu = [apps_separator menu];
242 for (i = count - 1; i >= 0; i--)
245 [self prepend_apps_item:list index:i menu:menu];
246 if (dock_apps_menu != nil)
247 [self prepend_apps_item:list index:i menu:dock_apps_menu];
250 apps = [list retain];
253 - (void) set_window_menu:(NSArray *)list
255 [self remove_window_menu];
256 [self install_window_menu:list];
258 QuartzMessageMainThread (kXquartzControllerNotify, 1,
259 AppleWMWindowMenuNotify);
262 - (void) set_window_menu_check:(NSNumber *)nn
267 int n = [nn intValue];
269 menu = [window_separator menu];
270 first = [menu indexOfItem:window_separator] + 1;
271 count = [menu numberOfItems] - first;
273 if (checked_window_item >= 0 && checked_window_item < count)
275 item = (NSMenuItem *) [menu itemAtIndex:first + checked_window_item];
276 [item setState:NSOffState];
277 item = (NSMenuItem *) [dock_menu itemAtIndex:checked_window_item];
278 [item setState:NSOffState];
280 if (n >= 0 && n < count)
282 item = (NSMenuItem *) [menu itemAtIndex:first + n];
283 [item setState:NSOnState];
284 item = (NSMenuItem *) [dock_menu itemAtIndex:n];
285 [item setState:NSOnState];
287 checked_window_item = n;
290 - (void) set_apps_menu:(NSArray *)list
292 [self remove_apps_menu];
293 [self install_apps_menu:list];
296 - (void) launch_client:(NSString *)command
298 QuartzRunClient ([command cString]);
301 - (void) app_selected:sender
306 tag = [sender tag] - 1;
307 if (apps == nil || tag < 0 || tag >= [apps count])
310 item = [[apps objectAtIndex:tag] objectAtIndex:1];
312 [self launch_client:item];
315 - (IBAction) apps_table_show:sender
319 if (table_apps == nil)
321 table_apps = [[NSMutableArray alloc] initWithCapacity:1];
324 [table_apps addObjectsFromArray:apps];
327 columns = [apps_table tableColumns];
328 [[columns objectAtIndex:0] setIdentifier:@"0"];
329 [[columns objectAtIndex:1] setIdentifier:@"1"];
330 [[columns objectAtIndex:2] setIdentifier:@"2"];
332 [apps_table setDataSource:self];
333 [apps_table selectRow:0 byExtendingSelection:NO];
335 [[apps_table window] makeKeyAndOrderFront:sender];
338 - (IBAction) apps_table_cancel:sender
340 [[apps_table window] orderOut:sender];
342 [table_apps release];
346 - (IBAction) apps_table_done:sender
348 [apps_table deselectAll:sender]; /* flush edits? */
350 [self remove_apps_menu];
351 [self install_apps_menu:table_apps];
353 [NSApp prefs_set_array:@PREFS_APPSMENU value:table_apps];
354 [NSApp prefs_synchronize];
356 [[apps_table window] orderOut:sender];
358 [table_apps release];
362 - (IBAction) apps_table_new:sender
364 NSMutableArray *item;
366 int row = [apps_table selectedRow], i;
374 if (i > [table_apps count])
375 return; /* avoid exceptions */
377 item = [[NSMutableArray alloc] initWithCapacity:3];
378 [item addObject:@""];
379 [item addObject:@""];
380 [item addObject:@""];
382 [table_apps insertObject:item atIndex:i];
385 [apps_table noteNumberOfRowsChanged];
386 [apps_table selectRow:row byExtendingSelection:NO];
389 - (IBAction) apps_table_duplicate:sender
391 int row = [apps_table selectedRow], i;
396 [self apps_table_new:sender];
401 if (i > [table_apps count] - 1)
402 return; /* avoid exceptions */
404 a = [table_apps objectAtIndex:i];
405 [table_apps insertObject:[a copy] atIndex:i];
407 [apps_table noteNumberOfRowsChanged];
408 [apps_table selectRow:row+1 byExtendingSelection:NO];
411 - (IBAction) apps_table_delete:sender
413 int row = [apps_table selectedRow];
419 if (i > [table_apps count] - 1)
420 return; /* avoid exceptions */
422 [table_apps removeObjectAtIndex:i];
425 [apps_table noteNumberOfRowsChanged];
428 - (int) numberOfRowsInTableView:(NSTableView *)tableView
430 if (table_apps == nil)
433 return [table_apps count];
436 - (id) tableView:(NSTableView *)tableView
437 objectValueForTableColumn:(NSTableColumn *)tableColumn row:(int)row
442 if (table_apps == nil)
445 col = [[tableColumn identifier] intValue];
447 item = [table_apps objectAtIndex:row];
448 if ([item count] > col)
449 return [item objectAtIndex:col];
454 - (void) tableView:(NSTableView *)tableView setObjectValue:(id)object
455 forTableColumn:(NSTableColumn *)tableColumn row:(int)row
457 NSMutableArray *item;
460 if (table_apps == nil)
463 col = [[tableColumn identifier] intValue];
465 item = [table_apps objectAtIndex:row];
466 [item replaceObjectAtIndex:col withObject:object];
469 - (void) hide_window:sender
471 if ([X11App x_active])
472 QuartzMessageMainThread (kXquartzControllerNotify, 1, AppleWMHideWindow);
474 NSBeep (); /* FIXME: something here */
477 - (IBAction)bring_to_front:sender
479 QuartzMessageMainThread (kXquartzControllerNotify, 1,
480 AppleWMBringAllToFront);
483 - (IBAction)close_window:sender
485 if ([X11App x_active])
486 QuartzMessageMainThread (kXquartzControllerNotify, 1, AppleWMCloseWindow);
488 [[NSApp keyWindow] performClose:sender];
491 - (IBAction)minimize_window:sender
493 if ([X11App x_active])
494 QuartzMessageMainThread (kXquartzControllerNotify, 1, AppleWMMinimizeWindow);
496 [[NSApp keyWindow] performMiniaturize:sender];
499 - (IBAction)zoom_window:sender
501 if ([X11App x_active])
502 QuartzMessageMainThread (kXquartzControllerNotify, 1, AppleWMZoomWindow);
504 [[NSApp keyWindow] performZoom:sender];
507 - (IBAction) next_window:sender
509 QuartzMessageMainThread (kXquartzControllerNotify, 1, AppleWMNextWindow);
512 - (IBAction) previous_window:sender
514 QuartzMessageMainThread (kXquartzControllerNotify,
515 1, AppleWMPreviousWindow);
518 - (IBAction) enable_fullscreen_changed:sender
520 int value = ![enable_fullscreen intValue];
522 QuartzMessageMainThread (kXquartzSetRootless, 1, value);
524 [NSApp prefs_set_boolean:@PREFS_ROOTLESS value:value];
525 [NSApp prefs_synchronize];
528 - (IBAction) toggle_fullscreen:sender
530 QuartzMessageMainThread (kXquartzToggleFullscreen, 0);
533 - (void) set_can_quit:(BOOL)state
538 - (IBAction)prefs_changed:sender
540 darwinFakeButtons = [fake_buttons intValue];
541 quartzUseSysBeep = [use_sysbeep intValue];
542 X11EnableKeyEquivalents = [enable_keyequivs intValue];
543 darwinSyncKeymap = [sync_keymap intValue];
545 /* after adding prefs here, also add to [X11Application read_defaults]
548 [NSApp prefs_set_boolean:@PREFS_FAKEBUTTONS value:darwinFakeButtons];
549 [NSApp prefs_set_boolean:@PREFS_SYSBEEP value:quartzUseSysBeep];
550 [NSApp prefs_set_boolean:@PREFS_KEYEQUIVS value:X11EnableKeyEquivalents];
551 [NSApp prefs_set_boolean:@PREFS_SYNC_KEYMAP value:darwinSyncKeymap];
552 [NSApp prefs_set_boolean:@PREFS_NO_AUTH value:![enable_auth intValue]];
553 [NSApp prefs_set_boolean:@PREFS_NO_TCP value:![enable_tcp intValue]];
554 [NSApp prefs_set_integer:@PREFS_DEPTH value:[depth selectedTag]];
556 [NSApp prefs_synchronize];
559 - (IBAction) prefs_show:sender
561 [fake_buttons setIntValue:darwinFakeButtons];
562 [use_sysbeep setIntValue:quartzUseSysBeep];
563 [enable_keyequivs setIntValue:X11EnableKeyEquivalents];
564 [sync_keymap setIntValue:darwinSyncKeymap];
565 [sync_keymap setEnabled:darwinKeymapFile == NULL];
567 [enable_auth setIntValue:![NSApp prefs_get_boolean:@PREFS_NO_AUTH default:NO]];
568 [enable_tcp setIntValue:![NSApp prefs_get_boolean:@PREFS_NO_TCP default:NO]];
569 [depth selectItemAtIndex:[depth indexOfItemWithTag:[NSApp prefs_get_integer:@PREFS_DEPTH default:-1]]];
571 [enable_fullscreen setIntValue:!quartzEnableRootless];
573 [prefs_panel makeKeyAndOrderFront:sender];
576 - (IBAction) quit:sender
578 QuartzMessageMainThread (kXdarwinQuit, 0);
581 - (IBAction) x11_help:sender
583 AHLookupAnchor (CFSTR ("Mac Help"), CFSTR ("mchlp2276"));
586 - (BOOL) validateMenuItem:(NSMenuItem *)item
588 NSMenu *menu = [item menu];
590 if (item == toggle_fullscreen_item)
592 return !quartzEnableRootless;
594 else if (menu == [window_separator menu] || menu == dock_menu
595 || (menu == [x11_about_item menu] && [item tag] == 42))
597 return (AppleWMSelectedEvents () & AppleWMControllerNotifyMask) != 0;
605 - (void) applicationDidHide:(NSNotification *)notify
607 QuartzMessageMainThread (kXquartzControllerNotify, 1, AppleWMHideAll);
610 - (void) applicationDidUnhide:(NSNotification *)notify
612 QuartzMessageMainThread (kXquartzControllerNotify, 1, AppleWMShowAll);
615 - (NSApplicationTerminateReply) applicationShouldTerminate:sender
619 if (can_quit || [X11App prefs_get_boolean:@PREFS_NO_QUIT_ALERT default:NO])
621 return NSTerminateNow;
624 /* Make sure we're frontmost. */
625 [NSApp activateIgnoringOtherApps:YES];
627 msg = NSLocalizedString (@"Are you sure you want to quit X11?\n\n\
628 If you quit X11, any X11 applications you are running will stop immediately \
629 and you will lose any changes you have not saved.", @"");
631 /* FIXME: safe to run the alert in here? Or should we return Later
632 and then run the alert on a timer? It seems to work here, so.. */
634 return (NSRunAlertPanel (nil, msg, NSLocalizedString (@"Quit", @""),
635 NSLocalizedString (@"Cancel", @""), nil)
636 == NSAlertDefaultReturn) ? NSTerminateNow : NSTerminateCancel;
639 - (void) applicationWillTerminate:(NSNotification *)aNotification
641 [X11App prefs_synchronize];
643 /* shutdown the X server, it will exit () for us. */
644 QuartzMessageMainThread (kXdarwinQuit, 0);
646 /* In case it doesn't, exit anyway after a while. */
647 while (sleep (10) != 0) ;
651 - (void) server_ready
655 finished_launching = YES;
657 for (node = pending_apps; node != NULL; node = node->next)
659 NSString *filename = node->data;
660 QuartzRunClient ([filename UTF8String]);
664 x_list_free (pending_apps);
668 - (BOOL) application:(NSApplication *)app openFile:(NSString *)filename
671 const char *name = [filename UTF8String];
673 if (finished_launching)
674 QuartzRunClient (name);
675 else if (name[0] != ':') /* ignore display names */
676 pending_apps = x_list_prepend (pending_apps, [filename retain]);
678 /* FIXME: report failures. */
686 void X11ControllerMain (int argc, const char *argv[],
687 void (*server_thread) (void *), void *server_arg)
689 X11ApplicationMain (argc, argv, server_thread, server_arg);