⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 osxwin.m

📁 putty
💻 M
📖 第 1 页 / 共 3 页
字号:
/*
 * osxwin.m: code to manage a session window in Mac OS X PuTTY.
 */

#import <Cocoa/Cocoa.h>
#include "putty.h"
#include "terminal.h"
#include "osxclass.h"

/* Colours come in two flavours: configurable, and xterm-extended. */
#define NCFGCOLOURS (lenof(((Config *)0)->colours))
#define NEXTCOLOURS 240 /* 216 colour-cube plus 24 shades of grey */
#define NALLCOLOURS (NCFGCOLOURS + NEXTCOLOURS)

/*
 * The key component of the per-session data is the SessionWindow
 * class. A pointer to this is used as the frontend handle, to be
 * passed to all the platform-independent subsystems that require
 * one.
 */

@interface TerminalView : NSImageView
{
    NSFont *font;
    NSImage *image;
    Terminal *term;
    Config cfg;
    NSColor *colours[NALLCOLOURS];
    float fw, fasc, fdesc, fh;
}
- (void)drawStartFinish:(BOOL)start;
- (void)setColour:(int)n r:(float)r g:(float)g b:(float)b;
- (void)doText:(wchar_t *)text len:(int)len x:(int)x y:(int)y
    attr:(unsigned long)attr lattr:(int)lattr;
@end

@implementation TerminalView
- (BOOL)isFlipped
{
    return YES;
}
- (id)initWithTerminal:(Terminal *)aTerm config:(Config)aCfg
{
    float w, h;

    self = [self initWithFrame:NSMakeRect(0,0,100,100)];

    term = aTerm;
    cfg = aCfg;

    /*
     * Initialise the fonts we're going to use.
     * 
     * FIXME: for the moment I'm sticking with exactly one default font.
     */
    font = [NSFont userFixedPitchFontOfSize:0];

    /*
     * Now determine the size of the primary font.
     * 
     * FIXME: If we have multiple fonts, we may need to set fasc
     * and fdesc to the _maximum_ asc and desc out of all the
     * fonts, _before_ adding them together to get fh.
     */
    fw = [font widthOfString:@"A"];
    fasc = [font ascender];
    fdesc = -[font descender];
    fh = fasc + fdesc;
    fh = (int)fh + (fh > (int)fh);     /* round up, ickily */

    /*
     * Use this to figure out the size of the terminal view.
     */
    w = fw * term->cols;
    h = fh * term->rows;

    /*
     * And set our size and subimage.
     */
    image = [[NSImage alloc] initWithSize:NSMakeSize(w,h)];
    [image setFlipped:YES];
    [self setImage:image];
    [self setFrame:NSMakeRect(0,0,w,h)];

    term_invalidate(term);

    return self;
}
- (void)drawStartFinish:(BOOL)start
{
    if (start)
	[image lockFocus];
    else
	[image unlockFocus];
}
- (void)doText:(wchar_t *)text len:(int)len x:(int)x y:(int)y
    attr:(unsigned long)attr lattr:(int)lattr
{
    int nfg, nbg, rlen, widefactor;
    float ox, oy, tw, th;
    NSDictionary *attrdict;

    /* FIXME: TATTR_COMBINING */

    nfg = ((attr & ATTR_FGMASK) >> ATTR_FGSHIFT);
    nbg = ((attr & ATTR_BGMASK) >> ATTR_BGSHIFT);
    if (attr & ATTR_REVERSE) {
	int t = nfg;
	nfg = nbg;
	nbg = t;
    }
    if (cfg.bold_colour && (attr & ATTR_BOLD)) {
	if (nfg < 16) nfg |= 8;
	else if (nfg >= 256) nfg |= 1;
    }
    if (cfg.bold_colour && (attr & ATTR_BLINK)) {
	if (nbg < 16) nbg |= 8;
	else if (nbg >= 256) nbg |= 1;
    }
    if (attr & TATTR_ACTCURS) {
	nfg = 260;
	nbg = 261;
    }

    if (attr & ATTR_WIDE) {
	widefactor = 2;
	/* FIXME: what do we actually have to do about wide characters? */
    } else {
	widefactor = 1;
    }

    /* FIXME: ATTR_BOLD without cfg.bold_colour */

    if ((lattr & LATTR_MODE) != LATTR_NORM) {
	x *= 2;
	if (x >= term->cols)
	    return;
	if (x + len*2*widefactor > term->cols)
	    len = (term->cols-x)/2/widefactor;/* trim to LH half */
	rlen = len * 2;
    } else
	rlen = len;

    /* FIXME: how do we actually implement double-{width,height} lattrs? */

    ox = x * fw;
    oy = y * fh;
    tw = rlen * widefactor * fw;
    th = fh;

    /*
     * Set the clipping rectangle.
     */
    [[NSGraphicsContext currentContext] saveGraphicsState];
    [NSBezierPath clipRect:NSMakeRect(ox, oy, tw, th)];

    attrdict = [NSDictionary dictionaryWithObjectsAndKeys:
		colours[nfg], NSForegroundColorAttributeName,
		colours[nbg], NSBackgroundColorAttributeName,
		font, NSFontAttributeName, nil];

    /*
     * Create an NSString and draw it.
     * 
     * Annoyingly, although our input is wchar_t which is four
     * bytes wide on OS X and terminal.c supports 32-bit Unicode,
     * we must convert into the two-byte type `unichar' to store in
     * NSString, so we lose display capability for extra-BMP stuff
     * at this point.
     */
    {
	NSString *string;
	unichar *utext;
	int i;

	utext = snewn(len, unichar);
	for (i = 0; i < len; i++)
	    utext[i] = (text[i] >= 0x10000 ? 0xFFFD : text[i]);

	string = [NSString stringWithCharacters:utext length:len];
	[string drawAtPoint:NSMakePoint(ox, oy) withAttributes:attrdict];

	sfree(utext);
    }

    /*
     * Restore the graphics state from before the clipRect: call.
     */
    [[NSGraphicsContext currentContext] restoreGraphicsState];

    /*
     * And flag this area as needing display.
     */
    [self setNeedsDisplayInRect:NSMakeRect(ox, oy, tw, th)];
}

- (void)setColour:(int)n r:(float)r g:(float)g b:(float)b
{
    assert(n >= 0 && n < lenof(colours));
    colours[n] = [[NSColor colorWithDeviceRed:r green:g blue:b alpha:1.0]
		  retain];
}
@end

@implementation SessionWindow
- (id)initWithConfig:(Config)aCfg
{
    NSRect rect = { {0,0}, {0,0} };

    alert_ctx = NULL;

    cfg = aCfg;			       /* structure copy */

    init_ucs(&ucsdata, cfg.line_codepage, cfg.utf8_override,
	     CS_UTF8, cfg.vtmode);
    term = term_init(&cfg, &ucsdata, self);
    logctx = log_init(self, &cfg);
    term_provide_logctx(term, logctx);
    term_size(term, cfg.height, cfg.width, cfg.savelines);

    termview = [[[TerminalView alloc] initWithTerminal:term config:cfg]
		autorelease];

    /*
     * Now work out the size of the window.
     */
    rect = [termview frame];
    rect.origin = NSMakePoint(0,0);
    rect.size.width += 2 * cfg.window_border;
    rect.size.height += 2 * cfg.window_border;

    /*
     * Set up a backend.
     */
    {
	int i;
	back = &pty_backend;
	for (i = 0; backends[i].backend != NULL; i++)
	    if (backends[i].protocol == cfg.protocol) {
		back = backends[i].backend;
		break;
	    }
    }

    {
	const char *error;
	char *realhost = NULL;
	error = back->init(self, &backhandle, &cfg, cfg.host, cfg.port,
			   &realhost, cfg.tcp_nodelay, cfg.tcp_keepalives);
	if (error) {
	    fatalbox("%s\n", error);   /* FIXME: connection_fatal at worst */
	}

	if (realhost)
	    sfree(realhost);	       /* FIXME: do something with this */
    }
    back->provide_logctx(backhandle, logctx);

    /*
     * Create a line discipline. (This must be done after creating
     * the terminal _and_ the backend, since it needs to be passed
     * pointers to both.)
     */
    ldisc = ldisc_create(&cfg, term, back, backhandle, self);

    /*
     * FIXME: Set up a scrollbar.
     */

    self = [super initWithContentRect:rect
	    styleMask:(NSTitledWindowMask | NSMiniaturizableWindowMask |
		       NSClosableWindowMask)
	    backing:NSBackingStoreBuffered
	    defer:YES];
    [self setTitle:@"PuTTY"];

    [self setIgnoresMouseEvents:NO];

    /*
     * Put the terminal view in the window.
     */
    rect = [termview frame];
    rect.origin = NSMakePoint(cfg.window_border, cfg.window_border);
    [termview setFrame:rect];
    [[self contentView] addSubview:termview];

    /*
     * Set up the colour palette.
     */
    palette_reset(self);

    /*
     * FIXME: Only the _first_ document window should be centred.
     * The subsequent ones should appear down and to the right of
     * it, probably using the cascade function provided by Cocoa.
     * Also we're apparently required by the HIG to remember and
     * reuse previous positions of windows, although I'm not sure
     * how that works if the user opens more than one of the same
     * session type.
     */
    [self center];		       /* :-) */

    exited = FALSE;

    return self;
}

- (void)dealloc
{
    /*
     * FIXME: Here we must deallocate all sorts of stuff: the
     * terminal, the backend, the ldisc, the logctx, you name it.
     * Do so.
     */
    sfree(alert_ctx);
    if (back)
	back->free(backhandle);
    if (ldisc)
	ldisc_free(ldisc);
    /* ldisc must be freed before term, since ldisc_free expects term
     * still to be around. */
    if (logctx)
	log_free(logctx);
    if (term)
	term_free(term);
    [super dealloc];
}

- (void)drawStartFinish:(BOOL)start
{
    [termview drawStartFinish:start];
}

- (void)setColour:(int)n r:(float)r g:(float)g b:(float)b
{
    [termview setColour:n r:r g:g b:b];
}

- (void)doText:(wchar_t *)text len:(int)len x:(int)x y:(int)y
    attr:(unsigned long)attr lattr:(int)lattr
{
    /* Pass this straight on to the TerminalView. */
    [termview doText:text len:len x:x y:y attr:attr lattr:lattr];
}

- (Config *)cfg
{
    return &cfg;
}

- (void)keyDown:(NSEvent *)ev
{
    NSString *s = [ev characters];
    int i;
    int n = [s length], c = [s characterAtIndex:0], m = [ev modifierFlags];
    int cm = [[ev charactersIgnoringModifiers] characterAtIndex:0];
    wchar_t output[32];
    char coutput[32];
    int use_coutput = FALSE, special = FALSE, start, end;

//printf("n=%d c=U+%04x cm=U+%04x m=%08x\n", n, c, cm, m);

    /*
     * FIXME: Alt+numberpad codes.
     */

    /*
     * Shift and Ctrl with PageUp/PageDown for scrollback.
     */
    if (n == 1 && c == NSPageUpFunctionKey && (m & NSShiftKeyMask)) {
	term_scroll(term, 0, -term->rows/2);
	return;
    }
    if (n == 1 && c == NSPageUpFunctionKey && (m & NSControlKeyMask)) {
	term_scroll(term, 0, -1);
	return;
    }
    if (n == 1 && c == NSPageDownFunctionKey && (m & NSShiftKeyMask)) {
	term_scroll(term, 0, +term->rows/2);
	return;
    }
    if (n == 1 && c == NSPageDownFunctionKey && (m & NSControlKeyMask)) {
	term_scroll(term, 0, +1);
	return;
    }

    /*
     * FIXME: Shift-Ins for paste? Or is that not Maccy enough?
     */

    /*
     * FIXME: Alt (Option? Command?) prefix in general.
     * 
     * (Note that Alt-Shift-thing will work just by looking at
     * charactersIgnoringModifiers; but Alt-Ctrl-thing will need
     * processing properly, and Alt-as-in-Option won't happen at
     * all. Hmmm.)
     * 
     * (Note also that we need to be able to override menu key
     * equivalents before this is particularly useful.)
     */
    start = 1;
    end = start;

    /*
     * Ctrl-` is the same as Ctrl-\, unless we already have a
     * better idea.
     */
    if ((m & NSControlKeyMask) && n == 1 && cm == '`' && c == '`') {
	output[1] = '\x1c';
	end = 2;
    }

    /* We handle Return ourselves, because it needs to be flagged as
     * special to ldisc. */
    if (n == 1 && c == '\015') {
	coutput[1] = '\015';

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -