putty/macosx/osxmain.m

427 строки
9.6 KiB
Mathematica
Исходник Обычный вид История

/*
* osxmain.m: main-program file of Mac OS X PuTTY.
*/
#import <Cocoa/Cocoa.h>
#define PUTTY_DO_GLOBALS /* actually _define_ globals */
#include "putty.h"
#include "osxclass.h"
/* ----------------------------------------------------------------------
* Global variables.
*/
AppController *controller;
/* ----------------------------------------------------------------------
* Miscellaneous elements of the interface to the cross-platform
* and Unix PuTTY code.
*/
char *platform_get_x_display(void) {
return NULL;
}
FontSpec platform_default_fontspec(const char *name)
{
FontSpec ret;
/* FIXME */
return ret;
}
Filename platform_default_filename(const char *name)
{
Filename ret;
if (!strcmp(name, "LogFileName"))
strcpy(ret.path, "putty.log");
else
*ret.path = '\0';
return ret;
}
char *platform_default_s(const char *name)
{
return NULL;
}
int platform_default_i(const char *name, int def)
{
if (!strcmp(name, "CloseOnExit"))
return 2; /* maps to FORCE_ON after painful rearrangement :-( */
return def;
}
char *x_get_default(const char *key)
{
return NULL; /* this is a stub */
}
static void commonfatalbox(char *p, va_list ap)
{
char errorbuf[2048];
NSAlert *alert;
/*
* We may have come here because we ran out of memory, in which
* case it's entirely likely that that further memory
* allocations will fail. So (a) we use vsnprintf to format the
* error message rather than the usual dupvprintf; and (b) we
* have a fallback way to get the message out via stderr if
* even creating an NSAlert fails.
*/
vsnprintf(errorbuf, lenof(errorbuf), p, ap);
alert = [NSAlert alloc];
if (!alert) {
fprintf(stderr, "fatal error (and NSAlert failed): %s\n", errorbuf);
} else {
alert = [[alert init] autorelease];
[alert addButtonWithTitle:@"Terminate"];
[alert setInformativeText:[NSString stringWithCString:errorbuf]];
[alert runModal];
}
exit(1);
}
void nonfatal(void *frontend, char *p, ...)
{
char *errorbuf;
NSAlert *alert;
va_list ap;
va_start(ap, p);
errorbuf = dupvprintf(p, ap);
va_end(ap);
alert = [[[NSAlert alloc] init] autorelease];
[alert addButtonWithTitle:@"Error"];
[alert setInformativeText:[NSString stringWithCString:errorbuf]];
[alert runModal];
sfree(errorbuf);
}
void fatalbox(char *p, ...)
{
va_list ap;
va_start(ap, p);
commonfatalbox(p, ap);
va_end(ap);
}
void modalfatalbox(char *p, ...)
{
va_list ap;
va_start(ap, p);
commonfatalbox(p, ap);
va_end(ap);
}
void cmdline_error(char *p, ...)
{
va_list ap;
fprintf(stderr, "%s: ", appname);
va_start(ap, p);
vfprintf(stderr, p, ap);
va_end(ap);
fputc('\n', stderr);
exit(1);
}
/*
* Clean up and exit.
*/
void cleanup_exit(int code)
{
/*
* Clean up.
*/
sk_cleanup();
random_save_seed();
exit(code);
}
/* ----------------------------------------------------------------------
* Tiny extension to NSMenuItem which carries a payload of a `void
* *', allowing several menu items to invoke the same message but
* pass different data through it.
*/
@interface DataMenuItem : NSMenuItem
{
void *payload;
}
- (void)setPayload:(void *)d;
- (void *)getPayload;
@end
@implementation DataMenuItem
- (void)setPayload:(void *)d
{
payload = d;
}
- (void *)getPayload
{
return payload;
}
@end
/* ----------------------------------------------------------------------
* Utility routines for constructing OS X menus.
*/
NSMenu *newmenu(const char *title)
{
return [[[NSMenu allocWithZone:[NSMenu menuZone]]
initWithTitle:[NSString stringWithCString:title]]
autorelease];
}
NSMenu *newsubmenu(NSMenu *parent, const char *title)
{
NSMenuItem *item;
NSMenu *child;
item = [[[NSMenuItem allocWithZone:[NSMenu menuZone]]
initWithTitle:[NSString stringWithCString:title]
action:NULL
keyEquivalent:@""]
autorelease];
child = newmenu(title);
[item setEnabled:YES];
[item setSubmenu:child];
[parent addItem:item];
return child;
}
id initnewitem(NSMenuItem *item, NSMenu *parent, const char *title,
const char *key, id target, SEL action)
{
unsigned mask = NSCommandKeyMask;
if (key[strcspn(key, "-")]) {
while (*key && *key != '-') {
int c = tolower((unsigned char)*key);
if (c == 's') {
mask |= NSShiftKeyMask;
} else if (c == 'o' || c == 'a') {
mask |= NSAlternateKeyMask;
}
key++;
}
if (*key)
key++;
}
item = [[item initWithTitle:[NSString stringWithCString:title]
action:NULL
keyEquivalent:[NSString stringWithCString:key]]
autorelease];
if (*key)
[item setKeyEquivalentModifierMask: mask];
[item setEnabled:YES];
[item setTarget:target];
[item setAction:action];
[parent addItem:item];
return item;
}
NSMenuItem *newitem(NSMenu *parent, char *title, char *key,
id target, SEL action)
{
return initnewitem([NSMenuItem allocWithZone:[NSMenu menuZone]],
parent, title, key, target, action);
}
/* ----------------------------------------------------------------------
* AppController: the object which receives the messages from all
* menu selections that aren't standard OS X functions.
*/
@implementation AppController
- (id)init
{
self = [super init];
timer = NULL;
return self;
}
- (void)newTerminal:(id)sender
{
id win;
Config cfg;
do_defaults(NULL, &cfg);
cfg.protocol = -1; /* PROT_TERMINAL */
win = [[SessionWindow alloc] initWithConfig:cfg];
[win makeKeyAndOrderFront:self];
}
- (void)newSessionConfig:(id)sender
{
id win;
Config cfg;
do_defaults(NULL, &cfg);
win = [[ConfigWindow alloc] initWithConfig:cfg];
[win makeKeyAndOrderFront:self];
}
- (void)newSessionWithConfig:(id)vdata
{
id win;
Config cfg;
NSData *data = (NSData *)vdata;
assert([data length] == sizeof(cfg));
[data getBytes:&cfg];
win = [[SessionWindow alloc] initWithConfig:cfg];
[win makeKeyAndOrderFront:self];
}
- (NSMenu *)applicationDockMenu:(NSApplication *)sender
{
NSMenu *menu = newmenu("Dock Menu");
/*
* FIXME: Add some useful things to this, probably including
* the saved session list.
*/
return menu;
}
- (void)timerFired:(id)sender
{
long now, next;
assert(sender == timer);
/* `sender' is the timer itself, so its userInfo is an NSNumber. */
now = [(NSNumber *)[sender userInfo] longValue];
[sender invalidate];
timer = NULL;
if (run_timers(now, &next))
[self setTimer:next];
}
- (void)setTimer:(long)next
{
long interval = next - GETTICKCOUNT();
float finterval;
if (interval <= 0)
interval = 1; /* just in case */
finterval = interval / (float)TICKSPERSEC;
if (timer) {
[timer invalidate];
}
timer = [NSTimer scheduledTimerWithTimeInterval:finterval
target:self selector:@selector(timerFired:)
userInfo:[NSNumber numberWithLong:next] repeats:NO];
}
@end
void timer_change_notify(long next)
{
[controller setTimer:next];
}
/* ----------------------------------------------------------------------
* Annoyingly, it looks as if I have to actually subclass
* NSApplication if I want to catch NSApplicationDefined events. So
* here goes.
*/
@interface MyApplication : NSApplication
{
}
@end
@implementation MyApplication
- (void)sendEvent:(NSEvent *)ev
{
if ([ev type] == NSApplicationDefined)
osxsel_process_results();
[super sendEvent:ev];
}
@end
/* ----------------------------------------------------------------------
* Main program. Constructs the menus and runs the application.
*/
int main(int argc, char **argv)
{
NSAutoreleasePool *pool;
NSMenu *menu;
NSMenuItem *item;
NSImage *icon;
pool = [[NSAutoreleasePool alloc] init];
icon = [NSImage imageNamed:@"NSApplicationIcon"];
[MyApplication sharedApplication];
[NSApp setApplicationIconImage:icon];
controller = [[[AppController alloc] init] autorelease];
[NSApp setDelegate:controller];
[NSApp setMainMenu: newmenu("Main Menu")];
menu = newsubmenu([NSApp mainMenu], "Apple Menu");
[NSApp setServicesMenu:newsubmenu(menu, "Services")];
[menu addItem:[NSMenuItem separatorItem]];
item = newitem(menu, "Hide PuTTY", "h", NSApp, @selector(hide:));
item = newitem(menu, "Hide Others", "o-h", NSApp, @selector(hideOtherApplications:));
item = newitem(menu, "Show All", "", NSApp, @selector(unhideAllApplications:));
[menu addItem:[NSMenuItem separatorItem]];
item = newitem(menu, "Quit", "q", NSApp, @selector(terminate:));
[NSApp setAppleMenu: menu];
menu = newsubmenu([NSApp mainMenu], "File");
item = newitem(menu, "New", "n", NULL, @selector(newSessionConfig:));
item = newitem(menu, "New Terminal", "t", NULL, @selector(newTerminal:));
item = newitem(menu, "Close", "w", NULL, @selector(performClose:));
menu = newsubmenu([NSApp mainMenu], "Window");
[NSApp setWindowsMenu: menu];
item = newitem(menu, "Minimise Window", "m", NULL, @selector(performMiniaturize:));
// menu = newsubmenu([NSApp mainMenu], "Help");
// item = newitem(menu, "PuTTY Help", "?", NSApp, @selector(showHelp:));
/*
* Start up the sub-thread doing select().
*/
osxsel_init();
/*
* Start up networking.
*/
sk_init();
/*
* FIXME: To make initial debugging more convenient I'm going
* to start by opening a session window unconditionally. This
* will probably change later on.
*/
[controller newSessionConfig:nil];
[NSApp run];
[pool release];
return 0;
}