2 * osxmain.m: main-program file of Mac OS X PuTTY.
5 #import <Cocoa/Cocoa.h>
7 #define PUTTY_DO_GLOBALS /* actually _define_ globals */
12 /* ----------------------------------------------------------------------
16 AppController *controller;
18 /* ----------------------------------------------------------------------
19 * Miscellaneous elements of the interface to the cross-platform
20 * and Unix PuTTY code.
23 const char platform_x11_best_transport[] = "unix";
25 char *platform_get_x_display(void) {
29 FontSpec platform_default_fontspec(const char *name)
36 Filename platform_default_filename(const char *name)
39 if (!strcmp(name, "LogFileName"))
40 strcpy(ret.path, "putty.log");
46 char *platform_default_s(const char *name)
51 int platform_default_i(const char *name, int def)
53 if (!strcmp(name, "CloseOnExit"))
54 return 2; /* maps to FORCE_ON after painful rearrangement :-( */
58 char *x_get_default(const char *key)
60 return NULL; /* this is a stub */
63 void modalfatalbox(char *p, ...)
65 /* FIXME: proper OS X GUI stuff */
67 fprintf(stderr, "FATAL ERROR: ");
69 vfprintf(stderr, p, ap);
75 void fatalbox(char *p, ...)
77 /* FIXME: proper OS X GUI stuff */
79 fprintf(stderr, "FATAL ERROR: ");
81 vfprintf(stderr, p, ap);
87 void cmdline_error(char *p, ...)
90 fprintf(stderr, "%s: ", appname);
92 vfprintf(stderr, p, ap);
101 void cleanup_exit(int code)
111 /* ----------------------------------------------------------------------
112 * Tiny extension to NSMenuItem which carries a payload of a `void
113 * *', allowing several menu items to invoke the same message but
114 * pass different data through it.
116 @interface DataMenuItem : NSMenuItem
120 - (void)setPayload:(void *)d;
121 - (void *)getPayload;
123 @implementation DataMenuItem
124 - (void)setPayload:(void *)d
134 /* ----------------------------------------------------------------------
135 * Utility routines for constructing OS X menus.
138 NSMenu *newmenu(const char *title)
140 return [[[NSMenu allocWithZone:[NSMenu menuZone]]
141 initWithTitle:[NSString stringWithCString:title]]
145 NSMenu *newsubmenu(NSMenu *parent, const char *title)
150 item = [[[NSMenuItem allocWithZone:[NSMenu menuZone]]
151 initWithTitle:[NSString stringWithCString:title]
155 child = newmenu(title);
156 [item setEnabled:YES];
157 [item setSubmenu:child];
158 [parent addItem:item];
162 id initnewitem(NSMenuItem *item, NSMenu *parent, const char *title,
163 const char *key, id target, SEL action)
165 unsigned mask = NSCommandKeyMask;
167 if (key[strcspn(key, "-")]) {
168 while (*key && *key != '-') {
169 int c = tolower((unsigned char)*key);
171 mask |= NSShiftKeyMask;
172 } else if (c == 'o' || c == 'a') {
173 mask |= NSAlternateKeyMask;
181 item = [[item initWithTitle:[NSString stringWithCString:title]
183 keyEquivalent:[NSString stringWithCString:key]]
187 [item setKeyEquivalentModifierMask: mask];
189 [item setEnabled:YES];
190 [item setTarget:target];
191 [item setAction:action];
193 [parent addItem:item];
198 NSMenuItem *newitem(NSMenu *parent, char *title, char *key,
199 id target, SEL action)
201 return initnewitem([NSMenuItem allocWithZone:[NSMenu menuZone]],
202 parent, title, key, target, action);
205 /* ----------------------------------------------------------------------
206 * AppController: the object which receives the messages from all
207 * menu selections that aren't standard OS X functions.
209 @implementation AppController
218 - (void)newTerminal:(id)sender
223 do_defaults(NULL, &cfg);
225 cfg.protocol = -1; /* PROT_TERMINAL */
227 win = [[SessionWindow alloc] initWithConfig:cfg];
228 [win makeKeyAndOrderFront:self];
231 - (void)newSessionConfig:(id)sender
236 do_defaults(NULL, &cfg);
238 win = [[ConfigWindow alloc] initWithConfig:cfg];
239 [win makeKeyAndOrderFront:self];
242 - (void)newSessionWithConfig:(id)vdata
246 NSData *data = (NSData *)vdata;
248 assert([data length] == sizeof(cfg));
249 [data getBytes:&cfg];
251 win = [[SessionWindow alloc] initWithConfig:cfg];
252 [win makeKeyAndOrderFront:self];
255 - (NSMenu *)applicationDockMenu:(NSApplication *)sender
257 NSMenu *menu = newmenu("Dock Menu");
259 * FIXME: Add some useful things to this, probably including
260 * the saved session list.
265 - (void)timerFired:(id)sender
269 assert(sender == timer);
271 /* `sender' is the timer itself, so its userInfo is an NSNumber. */
272 now = [(NSNumber *)[sender userInfo] longValue];
278 if (run_timers(now, &next))
279 [self setTimer:next];
282 - (void)setTimer:(long)next
284 long interval = next - GETTICKCOUNT();
288 interval = 1; /* just in case */
290 finterval = interval / (float)TICKSPERSEC;
296 timer = [NSTimer scheduledTimerWithTimeInterval:finterval
297 target:self selector:@selector(timerFired:)
298 userInfo:[NSNumber numberWithLong:next] repeats:NO];
303 void timer_change_notify(long next)
305 [controller setTimer:next];
308 /* ----------------------------------------------------------------------
309 * Annoyingly, it looks as if I have to actually subclass
310 * NSApplication if I want to catch NSApplicationDefined events. So
313 @interface MyApplication : NSApplication
317 @implementation MyApplication
318 - (void)sendEvent:(NSEvent *)ev
320 if ([ev type] == NSApplicationDefined)
321 osxsel_process_results();
323 [super sendEvent:ev];
327 /* ----------------------------------------------------------------------
328 * Main program. Constructs the menus and runs the application.
330 int main(int argc, char **argv)
332 NSAutoreleasePool *pool;
337 pool = [[NSAutoreleasePool alloc] init];
339 icon = [NSImage imageNamed:@"NSApplicationIcon"];
340 [MyApplication sharedApplication];
341 [NSApp setApplicationIconImage:icon];
343 controller = [[[AppController alloc] init] autorelease];
344 [NSApp setDelegate:controller];
346 [NSApp setMainMenu: newmenu("Main Menu")];
348 menu = newsubmenu([NSApp mainMenu], "Apple Menu");
349 [NSApp setServicesMenu:newsubmenu(menu, "Services")];
350 [menu addItem:[NSMenuItem separatorItem]];
351 item = newitem(menu, "Hide PuTTY", "h", NSApp, @selector(hide:));
352 item = newitem(menu, "Hide Others", "o-h", NSApp, @selector(hideOtherApplications:));
353 item = newitem(menu, "Show All", "", NSApp, @selector(unhideAllApplications:));
354 [menu addItem:[NSMenuItem separatorItem]];
355 item = newitem(menu, "Quit", "q", NSApp, @selector(terminate:));
356 [NSApp setAppleMenu: menu];
358 menu = newsubmenu([NSApp mainMenu], "File");
359 item = newitem(menu, "New", "n", NULL, @selector(newSessionConfig:));
360 item = newitem(menu, "New Terminal", "t", NULL, @selector(newTerminal:));
361 item = newitem(menu, "Close", "w", NULL, @selector(performClose:));
363 menu = newsubmenu([NSApp mainMenu], "Window");
364 [NSApp setWindowsMenu: menu];
365 item = newitem(menu, "Minimise Window", "m", NULL, @selector(performMiniaturize:));
367 // menu = newsubmenu([NSApp mainMenu], "Help");
368 // item = newitem(menu, "PuTTY Help", "?", NSApp, @selector(showHelp:));
371 * Start up the sub-thread doing select().
376 * Start up networking.
381 * FIXME: To make initial debugging more convenient I'm going
382 * to start by opening a session window unconditionally. This
383 * will probably change later on.
385 [controller newSessionConfig:nil];