+++ /dev/null
-/*\r
- * osxwin.m: code to manage a session window in Mac OS X PuTTY.\r
- */\r
-\r
-#import <Cocoa/Cocoa.h>\r
-#include "putty.h"\r
-#include "terminal.h"\r
-#include "osxclass.h"\r
-\r
-/* Colours come in two flavours: configurable, and xterm-extended. */\r
-#define NCFGCOLOURS (lenof(((Config *)0)->colours))\r
-#define NEXTCOLOURS 240 /* 216 colour-cube plus 24 shades of grey */\r
-#define NALLCOLOURS (NCFGCOLOURS + NEXTCOLOURS)\r
-\r
-/*\r
- * The key component of the per-session data is the SessionWindow\r
- * class. A pointer to this is used as the frontend handle, to be\r
- * passed to all the platform-independent subsystems that require\r
- * one.\r
- */\r
-\r
-@interface TerminalView : NSImageView\r
-{\r
- NSFont *font;\r
- NSImage *image;\r
- Terminal *term;\r
- Config cfg;\r
- NSColor *colours[NALLCOLOURS];\r
- float fw, fasc, fdesc, fh;\r
-}\r
-- (void)drawStartFinish:(BOOL)start;\r
-- (void)setColour:(int)n r:(float)r g:(float)g b:(float)b;\r
-- (void)doText:(wchar_t *)text len:(int)len x:(int)x y:(int)y\r
- attr:(unsigned long)attr lattr:(int)lattr;\r
-@end\r
-\r
-@implementation TerminalView\r
-- (BOOL)isFlipped\r
-{\r
- return YES;\r
-}\r
-- (id)initWithTerminal:(Terminal *)aTerm config:(Config)aCfg\r
-{\r
- float w, h;\r
-\r
- self = [self initWithFrame:NSMakeRect(0,0,100,100)];\r
-\r
- term = aTerm;\r
- cfg = aCfg;\r
-\r
- /*\r
- * Initialise the fonts we're going to use.\r
- * \r
- * FIXME: for the moment I'm sticking with exactly one default font.\r
- */\r
- font = [NSFont userFixedPitchFontOfSize:0];\r
-\r
- /*\r
- * Now determine the size of the primary font.\r
- * \r
- * FIXME: If we have multiple fonts, we may need to set fasc\r
- * and fdesc to the _maximum_ asc and desc out of all the\r
- * fonts, _before_ adding them together to get fh.\r
- */\r
- fw = [font widthOfString:@"A"];\r
- fasc = [font ascender];\r
- fdesc = -[font descender];\r
- fh = fasc + fdesc;\r
- fh = (int)fh + (fh > (int)fh); /* round up, ickily */\r
-\r
- /*\r
- * Use this to figure out the size of the terminal view.\r
- */\r
- w = fw * term->cols;\r
- h = fh * term->rows;\r
-\r
- /*\r
- * And set our size and subimage.\r
- */\r
- image = [[NSImage alloc] initWithSize:NSMakeSize(w,h)];\r
- [image setFlipped:YES];\r
- [self setImage:image];\r
- [self setFrame:NSMakeRect(0,0,w,h)];\r
-\r
- term_invalidate(term);\r
-\r
- return self;\r
-}\r
-- (void)drawStartFinish:(BOOL)start\r
-{\r
- if (start)\r
- [image lockFocus];\r
- else\r
- [image unlockFocus];\r
-}\r
-- (void)doText:(wchar_t *)text len:(int)len x:(int)x y:(int)y\r
- attr:(unsigned long)attr lattr:(int)lattr\r
-{\r
- int nfg, nbg, rlen, widefactor;\r
- float ox, oy, tw, th;\r
- NSDictionary *attrdict;\r
-\r
- /* FIXME: TATTR_COMBINING */\r
-\r
- nfg = ((attr & ATTR_FGMASK) >> ATTR_FGSHIFT);\r
- nbg = ((attr & ATTR_BGMASK) >> ATTR_BGSHIFT);\r
- if (attr & ATTR_REVERSE) {\r
- int t = nfg;\r
- nfg = nbg;\r
- nbg = t;\r
- }\r
- if (cfg.bold_colour && (attr & ATTR_BOLD)) {\r
- if (nfg < 16) nfg |= 8;\r
- else if (nfg >= 256) nfg |= 1;\r
- }\r
- if (cfg.bold_colour && (attr & ATTR_BLINK)) {\r
- if (nbg < 16) nbg |= 8;\r
- else if (nbg >= 256) nbg |= 1;\r
- }\r
- if (attr & TATTR_ACTCURS) {\r
- nfg = 260;\r
- nbg = 261;\r
- }\r
-\r
- if (attr & ATTR_WIDE) {\r
- widefactor = 2;\r
- /* FIXME: what do we actually have to do about wide characters? */\r
- } else {\r
- widefactor = 1;\r
- }\r
-\r
- /* FIXME: ATTR_BOLD without cfg.bold_colour */\r
-\r
- if ((lattr & LATTR_MODE) != LATTR_NORM) {\r
- x *= 2;\r
- if (x >= term->cols)\r
- return;\r
- if (x + len*2*widefactor > term->cols)\r
- len = (term->cols-x)/2/widefactor;/* trim to LH half */\r
- rlen = len * 2;\r
- } else\r
- rlen = len;\r
-\r
- /* FIXME: how do we actually implement double-{width,height} lattrs? */\r
-\r
- ox = x * fw;\r
- oy = y * fh;\r
- tw = rlen * widefactor * fw;\r
- th = fh;\r
-\r
- /*\r
- * Set the clipping rectangle.\r
- */\r
- [[NSGraphicsContext currentContext] saveGraphicsState];\r
- [NSBezierPath clipRect:NSMakeRect(ox, oy, tw, th)];\r
-\r
- attrdict = [NSDictionary dictionaryWithObjectsAndKeys:\r
- colours[nfg], NSForegroundColorAttributeName,\r
- colours[nbg], NSBackgroundColorAttributeName,\r
- font, NSFontAttributeName, nil];\r
-\r
- /*\r
- * Create an NSString and draw it.\r
- * \r
- * Annoyingly, although our input is wchar_t which is four\r
- * bytes wide on OS X and terminal.c supports 32-bit Unicode,\r
- * we must convert into the two-byte type `unichar' to store in\r
- * NSString, so we lose display capability for extra-BMP stuff\r
- * at this point.\r
- */\r
- {\r
- NSString *string;\r
- unichar *utext;\r
- int i;\r
-\r
- utext = snewn(len, unichar);\r
- for (i = 0; i < len; i++)\r
- utext[i] = (text[i] >= 0x10000 ? 0xFFFD : text[i]);\r
-\r
- string = [NSString stringWithCharacters:utext length:len];\r
- [string drawAtPoint:NSMakePoint(ox, oy) withAttributes:attrdict];\r
-\r
- sfree(utext);\r
- }\r
-\r
- /*\r
- * Restore the graphics state from before the clipRect: call.\r
- */\r
- [[NSGraphicsContext currentContext] restoreGraphicsState];\r
-\r
- /*\r
- * And flag this area as needing display.\r
- */\r
- [self setNeedsDisplayInRect:NSMakeRect(ox, oy, tw, th)];\r
-}\r
-\r
-- (void)setColour:(int)n r:(float)r g:(float)g b:(float)b\r
-{\r
- assert(n >= 0 && n < lenof(colours));\r
- colours[n] = [[NSColor colorWithDeviceRed:r green:g blue:b alpha:1.0]\r
- retain];\r
-}\r
-@end\r
-\r
-@implementation SessionWindow\r
-- (id)initWithConfig:(Config)aCfg\r
-{\r
- NSRect rect = { {0,0}, {0,0} };\r
-\r
- alert_ctx = NULL;\r
-\r
- cfg = aCfg; /* structure copy */\r
-\r
- init_ucs(&ucsdata, cfg.line_codepage, cfg.utf8_override,\r
- CS_UTF8, cfg.vtmode);\r
- term = term_init(&cfg, &ucsdata, self);\r
- logctx = log_init(self, &cfg);\r
- term_provide_logctx(term, logctx);\r
- term_size(term, cfg.height, cfg.width, cfg.savelines);\r
-\r
- termview = [[[TerminalView alloc] initWithTerminal:term config:cfg]\r
- autorelease];\r
-\r
- /*\r
- * Now work out the size of the window.\r
- */\r
- rect = [termview frame];\r
- rect.origin = NSMakePoint(0,0);\r
- rect.size.width += 2 * cfg.window_border;\r
- rect.size.height += 2 * cfg.window_border;\r
-\r
- /*\r
- * Set up a backend.\r
- */\r
- back = backend_from_proto(cfg.protocol);\r
- if (!back)\r
- back = &pty_backend;\r
-\r
- {\r
- const char *error;\r
- char *realhost = NULL;\r
- error = back->init(self, &backhandle, &cfg, cfg.host, cfg.port,\r
- &realhost, cfg.tcp_nodelay, cfg.tcp_keepalives);\r
- if (error) {\r
- fatalbox("%s\n", error); /* FIXME: connection_fatal at worst */\r
- }\r
-\r
- if (realhost)\r
- sfree(realhost); /* FIXME: do something with this */\r
- }\r
- back->provide_logctx(backhandle, logctx);\r
-\r
- /*\r
- * Create a line discipline. (This must be done after creating\r
- * the terminal _and_ the backend, since it needs to be passed\r
- * pointers to both.)\r
- */\r
- ldisc = ldisc_create(&cfg, term, back, backhandle, self);\r
-\r
- /*\r
- * FIXME: Set up a scrollbar.\r
- */\r
-\r
- self = [super initWithContentRect:rect\r
- styleMask:(NSTitledWindowMask | NSMiniaturizableWindowMask |\r
- NSClosableWindowMask)\r
- backing:NSBackingStoreBuffered\r
- defer:YES];\r
- [self setTitle:@"PuTTY"];\r
-\r
- [self setIgnoresMouseEvents:NO];\r
-\r
- /*\r
- * Put the terminal view in the window.\r
- */\r
- rect = [termview frame];\r
- rect.origin = NSMakePoint(cfg.window_border, cfg.window_border);\r
- [termview setFrame:rect];\r
- [[self contentView] addSubview:termview];\r
-\r
- /*\r
- * Set up the colour palette.\r
- */\r
- palette_reset(self);\r
-\r
- /*\r
- * FIXME: Only the _first_ document window should be centred.\r
- * The subsequent ones should appear down and to the right of\r
- * it, probably using the cascade function provided by Cocoa.\r
- * Also we're apparently required by the HIG to remember and\r
- * reuse previous positions of windows, although I'm not sure\r
- * how that works if the user opens more than one of the same\r
- * session type.\r
- */\r
- [self center]; /* :-) */\r
-\r
- exited = FALSE;\r
-\r
- return self;\r
-}\r
-\r
-- (void)dealloc\r
-{\r
- /*\r
- * FIXME: Here we must deallocate all sorts of stuff: the\r
- * terminal, the backend, the ldisc, the logctx, you name it.\r
- * Do so.\r
- */\r
- sfree(alert_ctx);\r
- if (back)\r
- back->free(backhandle);\r
- if (ldisc)\r
- ldisc_free(ldisc);\r
- /* ldisc must be freed before term, since ldisc_free expects term\r
- * still to be around. */\r
- if (logctx)\r
- log_free(logctx);\r
- if (term)\r
- term_free(term);\r
- [super dealloc];\r
-}\r
-\r
-- (void)drawStartFinish:(BOOL)start\r
-{\r
- [termview drawStartFinish:start];\r
-}\r
-\r
-- (void)setColour:(int)n r:(float)r g:(float)g b:(float)b\r
-{\r
- [termview setColour:n r:r g:g b:b];\r
-}\r
-\r
-- (void)doText:(wchar_t *)text len:(int)len x:(int)x y:(int)y\r
- attr:(unsigned long)attr lattr:(int)lattr\r
-{\r
- /* Pass this straight on to the TerminalView. */\r
- [termview doText:text len:len x:x y:y attr:attr lattr:lattr];\r
-}\r
-\r
-- (Config *)cfg\r
-{\r
- return &cfg;\r
-}\r
-\r
-- (void)keyDown:(NSEvent *)ev\r
-{\r
- NSString *s = [ev characters];\r
- int i;\r
- int n = [s length], c = [s characterAtIndex:0], m = [ev modifierFlags];\r
- int cm = [[ev charactersIgnoringModifiers] characterAtIndex:0];\r
- wchar_t output[32];\r
- char coutput[32];\r
- int use_coutput = FALSE, special = FALSE, start, end;\r
-\r
-//printf("n=%d c=U+%04x cm=U+%04x m=%08x\n", n, c, cm, m);\r
-\r
- /*\r
- * FIXME: Alt+numberpad codes.\r
- */\r
-\r
- /*\r
- * Shift and Ctrl with PageUp/PageDown for scrollback.\r
- */\r
- if (n == 1 && c == NSPageUpFunctionKey && (m & NSShiftKeyMask)) {\r
- term_scroll(term, 0, -term->rows/2);\r
- return;\r
- }\r
- if (n == 1 && c == NSPageUpFunctionKey && (m & NSControlKeyMask)) {\r
- term_scroll(term, 0, -1);\r
- return;\r
- }\r
- if (n == 1 && c == NSPageDownFunctionKey && (m & NSShiftKeyMask)) {\r
- term_scroll(term, 0, +term->rows/2);\r
- return;\r
- }\r
- if (n == 1 && c == NSPageDownFunctionKey && (m & NSControlKeyMask)) {\r
- term_scroll(term, 0, +1);\r
- return;\r
- }\r
-\r
- /*\r
- * FIXME: Shift-Ins for paste? Or is that not Maccy enough?\r
- */\r
-\r
- /*\r
- * FIXME: Alt (Option? Command?) prefix in general.\r
- * \r
- * (Note that Alt-Shift-thing will work just by looking at\r
- * charactersIgnoringModifiers; but Alt-Ctrl-thing will need\r
- * processing properly, and Alt-as-in-Option won't happen at\r
- * all. Hmmm.)\r
- * \r
- * (Note also that we need to be able to override menu key\r
- * equivalents before this is particularly useful.)\r
- */\r
- start = 1;\r
- end = start;\r
-\r
- /*\r
- * Ctrl-` is the same as Ctrl-\, unless we already have a\r
- * better idea.\r
- */\r
- if ((m & NSControlKeyMask) && n == 1 && cm == '`' && c == '`') {\r
- output[1] = '\x1c';\r
- end = 2;\r
- }\r
-\r
- /* We handle Return ourselves, because it needs to be flagged as\r
- * special to ldisc. */\r
- if (n == 1 && c == '\015') {\r
- coutput[1] = '\015';\r
- use_coutput = TRUE;\r
- end = 2;\r
- special = TRUE;\r
- }\r
-\r
- /* Control-Shift-Space is 160 (ISO8859 nonbreaking space) */\r
- if (n == 1 && (m & NSControlKeyMask) && (m & NSShiftKeyMask) &&\r
- cm == ' ') {\r
- output[1] = '\240';\r
- end = 2;\r
- }\r
-\r
- /* Control-2, Control-Space and Control-@ are all NUL. */\r
- if ((m & NSControlKeyMask) && n == 1 &&\r
- (cm == '2' || cm == '@' || cm == ' ') && c == cm) {\r
- output[1] = '\0';\r
- end = 2;\r
- }\r
-\r
- /* We don't let MacOS tell us what Backspace is! We know better. */\r
- if (cm == 0x7F && !(m & NSShiftKeyMask)) {\r
- coutput[1] = cfg.bksp_is_delete ? '\x7F' : '\x08';\r
- end = 2;\r
- use_coutput = special = TRUE;\r
- }\r
- /* For Shift Backspace, do opposite of what is configured. */\r
- if (cm == 0x7F && (m & NSShiftKeyMask)) {\r
- coutput[1] = cfg.bksp_is_delete ? '\x08' : '\x7F';\r
- end = 2;\r
- use_coutput = special = TRUE;\r
- }\r
-\r
- /* Shift-Tab is ESC [ Z. Oddly, this combination generates ^Y by\r
- * default on MacOS! */\r
- if (cm == 0x19 && (m & NSShiftKeyMask) && !(m & NSControlKeyMask)) {\r
- end = 1;\r
- output[end++] = '\033';\r
- output[end++] = '[';\r
- output[end++] = 'Z';\r
- }\r
-\r
- /*\r
- * NetHack keypad mode.\r
- */\r
- if (cfg.nethack_keypad && (m & NSNumericPadKeyMask)) {\r
- wchar_t *keys = NULL;\r
- switch (cm) {\r
- case '1': keys = L"bB"; break;\r
- case '2': keys = L"jJ"; break;\r
- case '3': keys = L"nN"; break;\r
- case '4': keys = L"hH"; break;\r
- case '5': keys = L".."; break;\r
- case '6': keys = L"lL"; break;\r
- case '7': keys = L"yY"; break;\r
- case '8': keys = L"kK"; break;\r
- case '9': keys = L"uU"; break;\r
- }\r
- if (keys) {\r
- end = 2;\r
- if (m & NSShiftKeyMask)\r
- output[1] = keys[1];\r
- else\r
- output[1] = keys[0];\r
- goto done;\r
- }\r
- }\r
-\r
- /*\r
- * Application keypad mode.\r
- */\r
- if (term->app_keypad_keys && !cfg.no_applic_k &&\r
- (m & NSNumericPadKeyMask)) {\r
- int xkey = 0;\r
- switch (cm) {\r
- case NSClearLineFunctionKey: xkey = 'P'; break;\r
- case '=': xkey = 'Q'; break;\r
- case '/': xkey = 'R'; break;\r
- case '*': xkey = 'S'; break;\r
- /*\r
- * FIXME: keypad - and + need to be mapped to ESC O l\r
- * and ESC O k, or ESC O l and ESC O m, depending on\r
- * xterm function key mode, and I can't remember which\r
- * goes where.\r
- */\r
- case '\003': xkey = 'M'; break;\r
- case '0': xkey = 'p'; break;\r
- case '1': xkey = 'q'; break;\r
- case '2': xkey = 'r'; break;\r
- case '3': xkey = 's'; break;\r
- case '4': xkey = 't'; break;\r
- case '5': xkey = 'u'; break;\r
- case '6': xkey = 'v'; break;\r
- case '7': xkey = 'w'; break;\r
- case '8': xkey = 'x'; break;\r
- case '9': xkey = 'y'; break;\r
- case '.': xkey = 'n'; break;\r
- }\r
- if (xkey) {\r
- if (term->vt52_mode) {\r
- if (xkey >= 'P' && xkey <= 'S') {\r
- output[end++] = '\033';\r
- output[end++] = xkey;\r
- } else {\r
- output[end++] = '\033';\r
- output[end++] = '?';\r
- output[end++] = xkey;\r
- }\r
- } else {\r
- output[end++] = '\033';\r
- output[end++] = 'O';\r
- output[end++] = xkey;\r
- }\r
- goto done;\r
- }\r
- }\r
-\r
- /*\r
- * Next, all the keys that do tilde codes. (ESC '[' nn '~',\r
- * for integer decimal nn.)\r
- *\r
- * We also deal with the weird ones here. Linux VCs replace F1\r
- * to F5 by ESC [ [ A to ESC [ [ E. rxvt doesn't do _that_, but\r
- * does replace Home and End (1~ and 4~) by ESC [ H and ESC O w\r
- * respectively.\r
- */\r
- {\r
- int code = 0;\r
- switch (cm) {\r
- case NSF1FunctionKey:\r
- code = (m & NSShiftKeyMask ? 23 : 11);\r
- break;\r
- case NSF2FunctionKey:\r
- code = (m & NSShiftKeyMask ? 24 : 12);\r
- break;\r
- case NSF3FunctionKey:\r
- code = (m & NSShiftKeyMask ? 25 : 13);\r
- break;\r
- case NSF4FunctionKey:\r
- code = (m & NSShiftKeyMask ? 26 : 14);\r
- break;\r
- case NSF5FunctionKey:\r
- code = (m & NSShiftKeyMask ? 28 : 15);\r
- break;\r
- case NSF6FunctionKey:\r
- code = (m & NSShiftKeyMask ? 29 : 17);\r
- break;\r
- case NSF7FunctionKey:\r
- code = (m & NSShiftKeyMask ? 31 : 18);\r
- break;\r
- case NSF8FunctionKey:\r
- code = (m & NSShiftKeyMask ? 32 : 19);\r
- break;\r
- case NSF9FunctionKey:\r
- code = (m & NSShiftKeyMask ? 33 : 20);\r
- break;\r
- case NSF10FunctionKey:\r
- code = (m & NSShiftKeyMask ? 34 : 21);\r
- break;\r
- case NSF11FunctionKey:\r
- code = 23;\r
- break;\r
- case NSF12FunctionKey:\r
- code = 24;\r
- break;\r
- case NSF13FunctionKey:\r
- code = 25;\r
- break;\r
- case NSF14FunctionKey:\r
- code = 26;\r
- break;\r
- case NSF15FunctionKey:\r
- code = 28;\r
- break;\r
- case NSF16FunctionKey:\r
- code = 29;\r
- break;\r
- case NSF17FunctionKey:\r
- code = 31;\r
- break;\r
- case NSF18FunctionKey:\r
- code = 32;\r
- break;\r
- case NSF19FunctionKey:\r
- code = 33;\r
- break;\r
- case NSF20FunctionKey:\r
- code = 34;\r
- break;\r
- }\r
- if (!(m & NSControlKeyMask)) switch (cm) {\r
- case NSHomeFunctionKey:\r
- code = 1;\r
- break;\r
-#ifdef FIXME\r
- case GDK_Insert: case GDK_KP_Insert:\r
- code = 2;\r
- break;\r
-#endif\r
- case NSDeleteFunctionKey:\r
- code = 3;\r
- break;\r
- case NSEndFunctionKey:\r
- code = 4;\r
- break;\r
- case NSPageUpFunctionKey:\r
- code = 5;\r
- break;\r
- case NSPageDownFunctionKey:\r
- code = 6;\r
- break;\r
- }\r
- /* Reorder edit keys to physical order */\r
- if (cfg.funky_type == FUNKY_VT400 && code <= 6)\r
- code = "\0\2\1\4\5\3\6"[code];\r
-\r
- if (term->vt52_mode && code > 0 && code <= 6) {\r
- output[end++] = '\033';\r
- output[end++] = " HLMEIG"[code];\r
- goto done;\r
- }\r
-\r
- if (cfg.funky_type == FUNKY_SCO && /* SCO function keys */\r
- code >= 11 && code <= 34) {\r
- char codes[] = "MNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz@[\\]^_`{";\r
- int index = 0;\r
- switch (cm) {\r
- case NSF1FunctionKey: index = 0; break;\r
- case NSF2FunctionKey: index = 1; break;\r
- case NSF3FunctionKey: index = 2; break;\r
- case NSF4FunctionKey: index = 3; break;\r
- case NSF5FunctionKey: index = 4; break;\r
- case NSF6FunctionKey: index = 5; break;\r
- case NSF7FunctionKey: index = 6; break;\r
- case NSF8FunctionKey: index = 7; break;\r
- case NSF9FunctionKey: index = 8; break;\r
- case NSF10FunctionKey: index = 9; break;\r
- case NSF11FunctionKey: index = 10; break;\r
- case NSF12FunctionKey: index = 11; break;\r
- }\r
- if (m & NSShiftKeyMask) index += 12;\r
- if (m & NSControlKeyMask) index += 24;\r
- output[end++] = '\033';\r
- output[end++] = '[';\r
- output[end++] = codes[index];\r
- goto done;\r
- }\r
- if (cfg.funky_type == FUNKY_SCO && /* SCO small keypad */\r
- code >= 1 && code <= 6) {\r
- char codes[] = "HL.FIG";\r
- if (code == 3) {\r
- output[1] = '\x7F';\r
- end = 2;\r
- } else {\r
- output[end++] = '\033';\r
- output[end++] = '[';\r
- output[end++] = codes[code-1];\r
- }\r
- goto done;\r
- }\r
- if ((term->vt52_mode || cfg.funky_type == FUNKY_VT100P) &&\r
- code >= 11 && code <= 24) {\r
- int offt = 0;\r
- if (code > 15)\r
- offt++;\r
- if (code > 21)\r
- offt++;\r
- if (term->vt52_mode) {\r
- output[end++] = '\033';\r
- output[end++] = code + 'P' - 11 - offt;\r
- } else {\r
- output[end++] = '\033';\r
- output[end++] = 'O';\r
- output[end++] = code + 'P' - 11 - offt;\r
- }\r
- goto done;\r
- }\r
- if (cfg.funky_type == FUNKY_LINUX && code >= 11 && code <= 15) {\r
- output[end++] = '\033';\r
- output[end++] = '[';\r
- output[end++] = '['; \r
- output[end++] = code + 'A' - 11;\r
- goto done;\r
- }\r
- if (cfg.funky_type == FUNKY_XTERM && code >= 11 && code <= 14) {\r
- if (term->vt52_mode) {\r
- output[end++] = '\033';\r
- output[end++] = code + 'P' - 11;\r
- } else {\r
- output[end++] = '\033';\r
- output[end++] = 'O';\r
- output[end++] = code + 'P' - 11;\r
- }\r
- goto done;\r
- }\r
- if (cfg.rxvt_homeend && (code == 1 || code == 4)) {\r
- if (code == 1) {\r
- output[end++] = '\033';\r
- output[end++] = '[';\r
- output[end++] = 'H';\r
- } else {\r
- output[end++] = '\033';\r
- output[end++] = 'O';\r
- output[end++] = 'w';\r
- }\r
- goto done;\r
- }\r
- if (code) {\r
- char buf[20];\r
- sprintf(buf, "\x1B[%d~", code);\r
- for (i = 0; buf[i]; i++)\r
- output[end++] = buf[i];\r
- goto done;\r
- }\r
- }\r
-\r
- /*\r
- * Cursor keys. (This includes the numberpad cursor keys,\r
- * if we haven't already done them due to app keypad mode.)\r
- */\r
- {\r
- int xkey = 0;\r
- switch (cm) {\r
- case NSUpArrowFunctionKey: xkey = 'A'; break;\r
- case NSDownArrowFunctionKey: xkey = 'B'; break;\r
- case NSRightArrowFunctionKey: xkey = 'C'; break;\r
- case NSLeftArrowFunctionKey: xkey = 'D'; break;\r
- }\r
- if (xkey) {\r
- end += format_arrow_key(output+end, term, xkey,\r
- m & NSControlKeyMask);\r
- goto done;\r
- }\r
- }\r
-\r
- done:\r
-\r
- /*\r
- * Failing everything else, send the exact Unicode we got from\r
- * OS X.\r
- */\r
- if (end == start) {\r
- if (n > lenof(output)-start)\r
- n = lenof(output)-start; /* _shouldn't_ happen! */\r
- for (i = 0; i < n; i++) {\r
- output[i+start] = [s characterAtIndex:i];\r
- }\r
- end = n+start;\r
- }\r
-\r
- if (use_coutput) {\r
- assert(special);\r
- assert(end < lenof(coutput));\r
- coutput[end] = '\0';\r
- ldisc_send(ldisc, coutput+start, -2, TRUE);\r
- } else {\r
- luni_send(ldisc, output+start, end-start, TRUE);\r
- }\r
-}\r
-\r
-- (int)fromBackend:(const char *)data len:(int)len isStderr:(int)is_stderr\r
-{\r
- return term_data(term, is_stderr, data, len);\r
-}\r
-\r
-- (int)fromBackendUntrusted:(const char *)data len:(int)len\r
-{\r
- return term_data_untrusted(term, data, len);\r
-}\r
-\r
-- (void)startAlert:(NSAlert *)alert\r
- withCallback:(void (*)(void *, int))callback andCtx:(void *)ctx\r
-{\r
- if (alert_ctx || alert_qhead) {\r
- /*\r
- * Queue this alert to be shown later.\r
- */\r
- struct alert_queue *qitem = snew(struct alert_queue);\r
- qitem->next = NULL;\r
- qitem->alert = alert;\r
- qitem->callback = callback;\r
- qitem->ctx = ctx;\r
- if (alert_qtail)\r
- alert_qtail->next = qitem;\r
- else\r
- alert_qhead = qitem;\r
- alert_qtail = qitem;\r
- } else {\r
- alert_callback = callback;\r
- alert_ctx = ctx; /* NB this is assumed to need freeing! */\r
- [alert beginSheetModalForWindow:self modalDelegate:self\r
- didEndSelector:@selector(alertSheetDidEnd:returnCode:contextInfo:)\r
- contextInfo:NULL];\r
- }\r
-}\r
-\r
-- (void)alertSheetDidEnd:(NSAlert *)alert returnCode:(int)returnCode\r
- contextInfo:(void *)contextInfo\r
-{\r
- [self performSelectorOnMainThread:\r
- @selector(alertSheetDidFinishEnding:)\r
- withObject:[NSNumber numberWithInt:returnCode]\r
- waitUntilDone:NO];\r
-}\r
-\r
-- (void)alertSheetDidFinishEnding:(id)object\r
-{\r
- int returnCode = [object intValue];\r
-\r
- alert_callback(alert_ctx, returnCode); /* transfers ownership of ctx */\r
-\r
- /*\r
- * If there's an alert in our queue (either already or because\r
- * the callback just queued it), start it.\r
- */\r
- if (alert_qhead) {\r
- struct alert_queue *qnext;\r
-\r
- alert_callback = alert_qhead->callback;\r
- alert_ctx = alert_qhead->ctx;\r
- [alert_qhead->alert beginSheetModalForWindow:self modalDelegate:self\r
- didEndSelector:@selector(alertSheetDidEnd:returnCode:contextInfo:)\r
- contextInfo:NULL];\r
-\r
- qnext = alert_qhead->next;\r
- sfree(alert_qhead);\r
- alert_qhead = qnext;\r
- if (!qnext)\r
- alert_qtail = NULL;\r
- } else {\r
- alert_ctx = NULL;\r
- }\r
-}\r
-\r
-- (void)notifyRemoteExit\r
-{\r
- int exitcode;\r
-\r
- if (!exited && (exitcode = back->exitcode(backhandle)) >= 0)\r
- [self endSession:(exitcode == 0)];\r
-}\r
-\r
-- (void)endSession:(int)clean\r
-{\r
- exited = TRUE;\r
- if (ldisc) {\r
- ldisc_free(ldisc);\r
- ldisc = NULL;\r
- }\r
- if (back) {\r
- back->free(backhandle);\r
- backhandle = NULL;\r
- back = NULL;\r
- //FIXME: update specials menu;\r
- }\r
- if (cfg.close_on_exit == FORCE_ON ||\r
- (cfg.close_on_exit == AUTO && clean))\r
- [self close];\r
- // FIXME: else show restart menu item\r
-}\r
-\r
-- (Terminal *)term\r
-{\r
- return term;\r
-}\r
-\r
-@end\r
-\r
-int from_backend(void *frontend, int is_stderr, const char *data, int len)\r
-{\r
- SessionWindow *win = (SessionWindow *)frontend;\r
- return [win fromBackend:data len:len isStderr:is_stderr];\r
-}\r
-\r
-int from_backend_untrusted(void *frontend, const char *data, int len)\r
-{\r
- SessionWindow *win = (SessionWindow *)frontend;\r
- return [win fromBackendUntrusted:data len:len];\r
-}\r
-\r
-int get_userpass_input(prompts_t *p, unsigned char *in, int inlen)\r
-{\r
- SessionWindow *win = (SessionWindow *)p->frontend;\r
- Terminal *term = [win term];\r
- return term_get_userpass_input(term, p, in, inlen);\r
-}\r
-\r
-void frontend_keypress(void *handle)\r
-{\r
- /* FIXME */\r
-}\r
-\r
-void notify_remote_exit(void *frontend)\r
-{\r
- SessionWindow *win = (SessionWindow *)frontend;\r
-\r
- [win notifyRemoteExit];\r
-}\r
-\r
-void ldisc_update(void *frontend, int echo, int edit)\r
-{\r
- //SessionWindow *win = (SessionWindow *)frontend;\r
- /*\r
- * In a GUI front end, this need do nothing.\r
- */\r
-}\r
-\r
-char *get_ttymode(void *frontend, const char *mode)\r
-{\r
- SessionWindow *win = (SessionWindow *)frontend;\r
- Terminal *term = [win term];\r
- return term_get_ttymode(term, mode);\r
-}\r
-\r
-void update_specials_menu(void *frontend)\r
-{\r
- //SessionWindow *win = (SessionWindow *)frontend;\r
- /* FIXME */\r
-}\r
-\r
-/*\r
- * This is still called when mode==BELL_VISUAL, even though the\r
- * visual bell is handled entirely within terminal.c, because we\r
- * may want to perform additional actions on any kind of bell (for\r
- * example, taskbar flashing in Windows).\r
- */\r
-void do_beep(void *frontend, int mode)\r
-{\r
- //SessionWindow *win = (SessionWindow *)frontend;\r
- if (mode != BELL_VISUAL)\r
- NSBeep();\r
-}\r
-\r
-int char_width(Context ctx, int uc)\r
-{\r
- /*\r
- * Under X, any fixed-width font really _is_ fixed-width.\r
- * Double-width characters will be dealt with using a separate\r
- * font. For the moment we can simply return 1.\r
- */\r
- return 1;\r
-}\r
-\r
-void palette_set(void *frontend, int n, int r, int g, int b)\r
-{\r
- SessionWindow *win = (SessionWindow *)frontend;\r
-\r
- if (n >= 16)\r
- n += 256 - 16;\r
- if (n > NALLCOLOURS)\r
- return;\r
- [win setColour:n r:r/255.0 g:g/255.0 b:b/255.0];\r
-\r
- /*\r
- * FIXME: do we need an OS X equivalent of set_window_background?\r
- */\r
-}\r
-\r
-void palette_reset(void *frontend)\r
-{\r
- SessionWindow *win = (SessionWindow *)frontend;\r
- Config *cfg = [win cfg];\r
-\r
- /* This maps colour indices in cfg to those used in colours[]. */\r
- static const int ww[] = {\r
- 256, 257, 258, 259, 260, 261,\r
- 0, 8, 1, 9, 2, 10, 3, 11,\r
- 4, 12, 5, 13, 6, 14, 7, 15\r
- };\r
-\r
- int i;\r
-\r
- for (i = 0; i < NCFGCOLOURS; i++) {\r
- [win setColour:ww[i] r:cfg->colours[i][0]/255.0\r
- g:cfg->colours[i][1]/255.0 b:cfg->colours[i][2]/255.0];\r
- }\r
-\r
- for (i = 0; i < NEXTCOLOURS; i++) {\r
- if (i < 216) {\r
- int r = i / 36, g = (i / 6) % 6, b = i % 6;\r
- r = r ? r*40+55 : 0; g = g ? b*40+55 : 0; b = b ? b*40+55 : 0;\r
- [win setColour:i+16 r:r/255.0 g:g/255.0 b:b/255.0];\r
- } else {\r
- int shade = i - 216;\r
- float fshade = (shade * 10 + 8) / 255.0;\r
- [win setColour:i+16 r:fshade g:fshade b:fshade];\r
- }\r
- }\r
-\r
- /*\r
- * FIXME: do we need an OS X equivalent of set_window_background?\r
- */\r
-}\r
-\r
-Context get_ctx(void *frontend)\r
-{\r
- SessionWindow *win = (SessionWindow *)frontend;\r
-\r
- /*\r
- * Lock the drawing focus on the image inside the TerminalView.\r
- */\r
- [win drawStartFinish:YES];\r
-\r
- [[NSGraphicsContext currentContext] setShouldAntialias:YES];\r
-\r
- /*\r
- * Cocoa drawing functions don't take a graphics context: that\r
- * parameter is implicit. Therefore, we'll use the frontend\r
- * handle itself as the context, on the grounds that it's as\r
- * good a thing to use as any.\r
- */\r
- return frontend;\r
-}\r
-\r
-void free_ctx(Context ctx)\r
-{\r
- SessionWindow *win = (SessionWindow *)ctx;\r
-\r
- [win drawStartFinish:NO];\r
-}\r
-\r
-void do_text(Context ctx, int x, int y, wchar_t *text, int len,\r
- unsigned long attr, int lattr)\r
-{\r
- SessionWindow *win = (SessionWindow *)ctx;\r
-\r
- [win doText:text len:len x:x y:y attr:attr lattr:lattr];\r
-}\r
-\r
-void do_cursor(Context ctx, int x, int y, wchar_t *text, int len,\r
- unsigned long attr, int lattr)\r
-{\r
- SessionWindow *win = (SessionWindow *)ctx;\r
- Config *cfg = [win cfg];\r
- int active, passive;\r
-\r
- if (attr & TATTR_PASCURS) {\r
- attr &= ~TATTR_PASCURS;\r
- passive = 1;\r
- } else\r
- passive = 0;\r
- if ((attr & TATTR_ACTCURS) && cfg->cursor_type != 0) {\r
- attr &= ~TATTR_ACTCURS;\r
- active = 1;\r
- } else\r
- active = 0;\r
-\r
- [win doText:text len:len x:x y:y attr:attr lattr:lattr];\r
-\r
- /*\r
- * FIXME: now draw the various cursor types (both passive and\r
- * active underlines and vertical lines, plus passive blocks).\r
- */\r
-}\r
-\r
-/*\r
- * Minimise or restore the window in response to a server-side\r
- * request.\r
- */\r
-void set_iconic(void *frontend, int iconic)\r
-{\r
- //SessionWindow *win = (SessionWindow *)frontend;\r
- /* FIXME */\r
-}\r
-\r
-/*\r
- * Move the window in response to a server-side request.\r
- */\r
-void move_window(void *frontend, int x, int y)\r
-{\r
- //SessionWindow *win = (SessionWindow *)frontend; \r
- /* FIXME */\r
-}\r
-\r
-/*\r
- * Move the window to the top or bottom of the z-order in response\r
- * to a server-side request.\r
- */\r
-void set_zorder(void *frontend, int top)\r
-{\r
- //SessionWindow *win = (SessionWindow *)frontend;\r
- /* FIXME */\r
-}\r
-\r
-/*\r
- * Refresh the window in response to a server-side request.\r
- */\r
-void refresh_window(void *frontend)\r
-{\r
- //SessionWindow *win = (SessionWindow *)frontend;\r
- /* FIXME */\r
-}\r
-\r
-/*\r
- * Maximise or restore the window in response to a server-side\r
- * request.\r
- */\r
-void set_zoomed(void *frontend, int zoomed)\r
-{\r
- //SessionWindow *win = (SessionWindow *)frontend;\r
- /* FIXME */\r
-}\r
-\r
-/*\r
- * Report whether the window is iconic, for terminal reports.\r
- */\r
-int is_iconic(void *frontend)\r
-{\r
- //SessionWindow *win = (SessionWindow *)frontend;\r
- return NO; /* FIXME */\r
-}\r
-\r
-/*\r
- * Report the window's position, for terminal reports.\r
- */\r
-void get_window_pos(void *frontend, int *x, int *y)\r
-{\r
- //SessionWindow *win = (SessionWindow *)frontend;\r
- /* FIXME */\r
-}\r
-\r
-/*\r
- * Report the window's pixel size, for terminal reports.\r
- */\r
-void get_window_pixels(void *frontend, int *x, int *y)\r
-{\r
- //SessionWindow *win = (SessionWindow *)frontend;\r
- /* FIXME */\r
-}\r
-\r
-/*\r
- * Return the window or icon title.\r
- */\r
-char *get_window_title(void *frontend, int icon)\r
-{\r
- //SessionWindow *win = (SessionWindow *)frontend;\r
- return NULL; /* FIXME */\r
-}\r
-\r
-void set_title(void *frontend, char *title)\r
-{\r
- //SessionWindow *win = (SessionWindow *)frontend;\r
- /* FIXME */\r
-}\r
-\r
-void set_icon(void *frontend, char *title)\r
-{\r
- //SessionWindow *win = (SessionWindow *)frontend;\r
- /* FIXME */\r
-}\r
-\r
-void set_sbar(void *frontend, int total, int start, int page)\r
-{\r
- //SessionWindow *win = (SessionWindow *)frontend;\r
- /* FIXME */\r
-}\r
-\r
-void get_clip(void *frontend, wchar_t ** p, int *len)\r
-{\r
- //SessionWindow *win = (SessionWindow *)frontend;\r
- /* FIXME */\r
-}\r
-\r
-void write_clip(void *frontend, wchar_t *data, int *attr, int len, int must_deselect)\r
-{\r
- //SessionWindow *win = (SessionWindow *)frontend;\r
- /* FIXME */\r
-}\r
-\r
-void request_paste(void *frontend)\r
-{\r
- //SessionWindow *win = (SessionWindow *)frontend;\r
- /* FIXME */\r
-}\r
-\r
-void set_raw_mouse_mode(void *frontend, int activate)\r
-{\r
- //SessionWindow *win = (SessionWindow *)frontend;\r
- /* FIXME */\r
-}\r
-\r
-void request_resize(void *frontend, int w, int h)\r
-{\r
- //SessionWindow *win = (SessionWindow *)frontend;\r
- /* FIXME */\r
-}\r
-\r
-void sys_cursor(void *frontend, int x, int y)\r
-{\r
- //SessionWindow *win = (SessionWindow *)frontend;\r
- /*\r
- * This is probably meaningless under OS X. FIXME: find out for\r
- * sure.\r
- */\r
-}\r
-\r
-void logevent(void *frontend, const char *string)\r
-{\r
- //SessionWindow *win = (SessionWindow *)frontend;\r
- /* FIXME */\r
-printf("logevent: %s\n", string);\r
-}\r
-\r
-int font_dimension(void *frontend, int which)/* 0 for width, 1 for height */\r
-{\r
- //SessionWindow *win = (SessionWindow *)frontend;\r
- return 1; /* FIXME */\r
-}\r
-\r
-void set_busy_status(void *frontend, int status)\r
-{\r
- /*\r
- * We need do nothing here: the OS X `application is busy'\r
- * beachball pointer appears _automatically_ when the\r
- * application isn't responding to GUI messages.\r
- */\r
-}\r