OSDN Git Service

Change OpenSSL context mode flags.
[ffftp/ffftp.git] / contrib / putty / MACOSX / OSXMAIN.M
1 /*\r
2  * osxmain.m: main-program file of Mac OS X PuTTY.\r
3  */\r
4 \r
5 #import <Cocoa/Cocoa.h>\r
6 \r
7 #define PUTTY_DO_GLOBALS               /* actually _define_ globals */\r
8 \r
9 #include "putty.h"\r
10 #include "osxclass.h"\r
11 \r
12 /* ----------------------------------------------------------------------\r
13  * Global variables.\r
14  */\r
15 \r
16 AppController *controller;\r
17 \r
18 /* ----------------------------------------------------------------------\r
19  * Miscellaneous elements of the interface to the cross-platform\r
20  * and Unix PuTTY code.\r
21  */\r
22 \r
23 char *platform_get_x_display(void) {\r
24     return NULL;\r
25 }\r
26 \r
27 FontSpec platform_default_fontspec(const char *name)\r
28 {\r
29     FontSpec ret;\r
30     /* FIXME */\r
31     return ret;\r
32 }\r
33 \r
34 Filename platform_default_filename(const char *name)\r
35 {\r
36     Filename ret;\r
37     if (!strcmp(name, "LogFileName"))\r
38         strcpy(ret.path, "putty.log");\r
39     else\r
40         *ret.path = '\0';\r
41     return ret;\r
42 }\r
43 \r
44 char *platform_default_s(const char *name)\r
45 {\r
46     return NULL;\r
47 }\r
48 \r
49 int platform_default_i(const char *name, int def)\r
50 {\r
51     if (!strcmp(name, "CloseOnExit"))\r
52         return 2;  /* maps to FORCE_ON after painful rearrangement :-( */\r
53     return def;\r
54 }\r
55 \r
56 char *x_get_default(const char *key)\r
57 {\r
58     return NULL;                       /* this is a stub */\r
59 }\r
60 \r
61 static void commonfatalbox(char *p, va_list ap)\r
62 {\r
63     char errorbuf[2048];\r
64     NSAlert *alert;\r
65 \r
66     /*\r
67      * We may have come here because we ran out of memory, in which\r
68      * case it's entirely likely that that further memory\r
69      * allocations will fail. So (a) we use vsnprintf to format the\r
70      * error message rather than the usual dupvprintf; and (b) we\r
71      * have a fallback way to get the message out via stderr if\r
72      * even creating an NSAlert fails.\r
73      */\r
74     vsnprintf(errorbuf, lenof(errorbuf), p, ap);\r
75 \r
76     alert = [NSAlert alloc];\r
77     if (!alert) {\r
78         fprintf(stderr, "fatal error (and NSAlert failed): %s\n", errorbuf);\r
79     } else {\r
80         alert = [[alert init] autorelease];\r
81         [alert addButtonWithTitle:@"Terminate"];\r
82         [alert setInformativeText:[NSString stringWithCString:errorbuf]];\r
83         [alert runModal];\r
84     }\r
85     exit(1);\r
86 }\r
87 \r
88 void fatalbox(char *p, ...)\r
89 {\r
90     va_list ap;\r
91     va_start(ap, p);\r
92     commonfatalbox(p, ap);\r
93     va_end(ap);\r
94 }\r
95 \r
96 void modalfatalbox(char *p, ...)\r
97 {\r
98     va_list ap;\r
99     va_start(ap, p);\r
100     commonfatalbox(p, ap);\r
101     va_end(ap);\r
102 }\r
103 \r
104 void cmdline_error(char *p, ...)\r
105 {\r
106     va_list ap;\r
107     fprintf(stderr, "%s: ", appname);\r
108     va_start(ap, p);\r
109     vfprintf(stderr, p, ap);\r
110     va_end(ap);\r
111     fputc('\n', stderr);\r
112     exit(1);\r
113 }\r
114 \r
115 /*\r
116  * Clean up and exit.\r
117  */\r
118 void cleanup_exit(int code)\r
119 {\r
120     /*\r
121      * Clean up.\r
122      */\r
123     sk_cleanup();\r
124     random_save_seed();\r
125     exit(code);\r
126 }\r
127 \r
128 /* ----------------------------------------------------------------------\r
129  * Tiny extension to NSMenuItem which carries a payload of a `void\r
130  * *', allowing several menu items to invoke the same message but\r
131  * pass different data through it.\r
132  */\r
133 @interface DataMenuItem : NSMenuItem\r
134 {\r
135     void *payload;\r
136 }\r
137 - (void)setPayload:(void *)d;\r
138 - (void *)getPayload;\r
139 @end\r
140 @implementation DataMenuItem\r
141 - (void)setPayload:(void *)d\r
142 {\r
143     payload = d;\r
144 }\r
145 - (void *)getPayload\r
146 {\r
147     return payload;\r
148 }\r
149 @end\r
150 \r
151 /* ----------------------------------------------------------------------\r
152  * Utility routines for constructing OS X menus.\r
153  */\r
154 \r
155 NSMenu *newmenu(const char *title)\r
156 {\r
157     return [[[NSMenu allocWithZone:[NSMenu menuZone]]\r
158              initWithTitle:[NSString stringWithCString:title]]\r
159             autorelease];\r
160 }\r
161 \r
162 NSMenu *newsubmenu(NSMenu *parent, const char *title)\r
163 {\r
164     NSMenuItem *item;\r
165     NSMenu *child;\r
166 \r
167     item = [[[NSMenuItem allocWithZone:[NSMenu menuZone]]\r
168              initWithTitle:[NSString stringWithCString:title]\r
169              action:NULL\r
170              keyEquivalent:@""]\r
171             autorelease];\r
172     child = newmenu(title);\r
173     [item setEnabled:YES];\r
174     [item setSubmenu:child];\r
175     [parent addItem:item];\r
176     return child;\r
177 }\r
178 \r
179 id initnewitem(NSMenuItem *item, NSMenu *parent, const char *title,\r
180                const char *key, id target, SEL action)\r
181 {\r
182     unsigned mask = NSCommandKeyMask;\r
183 \r
184     if (key[strcspn(key, "-")]) {\r
185         while (*key && *key != '-') {\r
186             int c = tolower((unsigned char)*key);\r
187             if (c == 's') {\r
188                 mask |= NSShiftKeyMask;\r
189             } else if (c == 'o' || c == 'a') {\r
190                 mask |= NSAlternateKeyMask;\r
191             }\r
192             key++;\r
193         }\r
194         if (*key)\r
195             key++;\r
196     }\r
197 \r
198     item = [[item initWithTitle:[NSString stringWithCString:title]\r
199              action:NULL\r
200              keyEquivalent:[NSString stringWithCString:key]]\r
201             autorelease];\r
202 \r
203     if (*key)\r
204         [item setKeyEquivalentModifierMask: mask];\r
205 \r
206     [item setEnabled:YES];\r
207     [item setTarget:target];\r
208     [item setAction:action];\r
209 \r
210     [parent addItem:item];\r
211 \r
212     return item;\r
213 }\r
214 \r
215 NSMenuItem *newitem(NSMenu *parent, char *title, char *key,\r
216                     id target, SEL action)\r
217 {\r
218     return initnewitem([NSMenuItem allocWithZone:[NSMenu menuZone]],\r
219                        parent, title, key, target, action);\r
220 }\r
221 \r
222 /* ----------------------------------------------------------------------\r
223  * AppController: the object which receives the messages from all\r
224  * menu selections that aren't standard OS X functions.\r
225  */\r
226 @implementation AppController\r
227 \r
228 - (id)init\r
229 {\r
230     self = [super init];\r
231     timer = NULL;\r
232     return self;\r
233 }\r
234 \r
235 - (void)newTerminal:(id)sender\r
236 {\r
237     id win;\r
238     Config cfg;\r
239 \r
240     do_defaults(NULL, &cfg);\r
241 \r
242     cfg.protocol = -1;                 /* PROT_TERMINAL */\r
243 \r
244     win = [[SessionWindow alloc] initWithConfig:cfg];\r
245     [win makeKeyAndOrderFront:self];\r
246 }\r
247 \r
248 - (void)newSessionConfig:(id)sender\r
249 {\r
250     id win;\r
251     Config cfg;\r
252 \r
253     do_defaults(NULL, &cfg);\r
254 \r
255     win = [[ConfigWindow alloc] initWithConfig:cfg];\r
256     [win makeKeyAndOrderFront:self];\r
257 }\r
258 \r
259 - (void)newSessionWithConfig:(id)vdata\r
260 {\r
261     id win;\r
262     Config cfg;\r
263     NSData *data = (NSData *)vdata;\r
264 \r
265     assert([data length] == sizeof(cfg));\r
266     [data getBytes:&cfg];\r
267 \r
268     win = [[SessionWindow alloc] initWithConfig:cfg];\r
269     [win makeKeyAndOrderFront:self];\r
270 }\r
271 \r
272 - (NSMenu *)applicationDockMenu:(NSApplication *)sender\r
273 {\r
274     NSMenu *menu = newmenu("Dock Menu");\r
275     /*\r
276      * FIXME: Add some useful things to this, probably including\r
277      * the saved session list.\r
278      */\r
279     return menu;\r
280 }\r
281 \r
282 - (void)timerFired:(id)sender\r
283 {\r
284     long now, next;\r
285 \r
286     assert(sender == timer);\r
287 \r
288     /* `sender' is the timer itself, so its userInfo is an NSNumber. */\r
289     now = [(NSNumber *)[sender userInfo] longValue];\r
290 \r
291     [sender invalidate];\r
292 \r
293     timer = NULL;\r
294 \r
295     if (run_timers(now, &next))\r
296         [self setTimer:next];\r
297 }\r
298 \r
299 - (void)setTimer:(long)next\r
300 {\r
301     long interval = next - GETTICKCOUNT();\r
302     float finterval;\r
303 \r
304     if (interval <= 0)\r
305         interval = 1;                  /* just in case */\r
306 \r
307     finterval = interval / (float)TICKSPERSEC;\r
308 \r
309     if (timer) {\r
310         [timer invalidate];\r
311     }\r
312 \r
313     timer = [NSTimer scheduledTimerWithTimeInterval:finterval\r
314              target:self selector:@selector(timerFired:)\r
315              userInfo:[NSNumber numberWithLong:next] repeats:NO];\r
316 }\r
317 \r
318 @end\r
319 \r
320 void timer_change_notify(long next)\r
321 {\r
322     [controller setTimer:next];\r
323 }\r
324 \r
325 /* ----------------------------------------------------------------------\r
326  * Annoyingly, it looks as if I have to actually subclass\r
327  * NSApplication if I want to catch NSApplicationDefined events. So\r
328  * here goes.\r
329  */\r
330 @interface MyApplication : NSApplication\r
331 {\r
332 }\r
333 @end\r
334 @implementation MyApplication\r
335 - (void)sendEvent:(NSEvent *)ev\r
336 {\r
337     if ([ev type] == NSApplicationDefined)\r
338         osxsel_process_results();\r
339 \r
340     [super sendEvent:ev];\r
341 }    \r
342 @end\r
343 \r
344 /* ----------------------------------------------------------------------\r
345  * Main program. Constructs the menus and runs the application.\r
346  */\r
347 int main(int argc, char **argv)\r
348 {\r
349     NSAutoreleasePool *pool;\r
350     NSMenu *menu;\r
351     NSMenuItem *item;\r
352     NSImage *icon;\r
353 \r
354     pool = [[NSAutoreleasePool alloc] init];\r
355 \r
356     icon = [NSImage imageNamed:@"NSApplicationIcon"];\r
357     [MyApplication sharedApplication];\r
358     [NSApp setApplicationIconImage:icon];\r
359 \r
360     controller = [[[AppController alloc] init] autorelease];\r
361     [NSApp setDelegate:controller];\r
362 \r
363     [NSApp setMainMenu: newmenu("Main Menu")];\r
364 \r
365     menu = newsubmenu([NSApp mainMenu], "Apple Menu");\r
366     [NSApp setServicesMenu:newsubmenu(menu, "Services")];\r
367     [menu addItem:[NSMenuItem separatorItem]];\r
368     item = newitem(menu, "Hide PuTTY", "h", NSApp, @selector(hide:));\r
369     item = newitem(menu, "Hide Others", "o-h", NSApp, @selector(hideOtherApplications:));\r
370     item = newitem(menu, "Show All", "", NSApp, @selector(unhideAllApplications:));\r
371     [menu addItem:[NSMenuItem separatorItem]];\r
372     item = newitem(menu, "Quit", "q", NSApp, @selector(terminate:));\r
373     [NSApp setAppleMenu: menu];\r
374 \r
375     menu = newsubmenu([NSApp mainMenu], "File");\r
376     item = newitem(menu, "New", "n", NULL, @selector(newSessionConfig:));\r
377     item = newitem(menu, "New Terminal", "t", NULL, @selector(newTerminal:));\r
378     item = newitem(menu, "Close", "w", NULL, @selector(performClose:));\r
379 \r
380     menu = newsubmenu([NSApp mainMenu], "Window");\r
381     [NSApp setWindowsMenu: menu];\r
382     item = newitem(menu, "Minimise Window", "m", NULL, @selector(performMiniaturize:));\r
383 \r
384 //    menu = newsubmenu([NSApp mainMenu], "Help");\r
385 //    item = newitem(menu, "PuTTY Help", "?", NSApp, @selector(showHelp:));\r
386 \r
387     /*\r
388      * Start up the sub-thread doing select().\r
389      */\r
390     osxsel_init();\r
391 \r
392     /*\r
393      * Start up networking.\r
394      */\r
395     sk_init();\r
396 \r
397     /*\r
398      * FIXME: To make initial debugging more convenient I'm going\r
399      * to start by opening a session window unconditionally. This\r
400      * will probably change later on.\r
401      */\r
402     [controller newSessionConfig:nil];\r
403 \r
404     [NSApp run];\r
405     [pool release];\r
406 \r
407     return 0;\r
408 }\r