diff --git a/.gitignore b/.gitignore index 25851bf6..bbb2cc09 100644 --- a/.gitignore +++ b/.gitignore @@ -95,12 +95,6 @@ /icons/*.icns /icons/*.xpm /icons/*.c -/macosx/Makefile -/macosx/*.app -/macosx/puttygen -/macosx/plink -/macosx/psftp -/macosx/pscp /testdata/bignum.txt /unix/Makefile.gtk /unix/Makefile.ux diff --git a/Recipe b/Recipe index e8801da5..52fe3f4e 100644 --- a/Recipe +++ b/Recipe @@ -20,7 +20,6 @@ !makefile gtk unix/Makefile.gtk !makefile unix unix/Makefile.ux !makefile am Makefile.am -!makefile osx macosx/Makefile !makefile devcppproj windows/DEVCPP !makefile vstudio10 windows/VS2010 !makefile vstudio12 windows/VS2012 @@ -28,7 +27,6 @@ !srcdir charset/ !srcdir windows/ !srcdir unix/ -!srcdir macosx/ # Help text added to the top of each Makefile, with /D converted # into -D as appropriate for the particular Makefile. @@ -173,9 +171,6 @@ install: install-strip: $(MAKE) install INSTALL_PROGRAM="$(INSTALL_PROGRAM) -s" !end -!begin osx vars -CFLAGS += -DMACOSX -!end # List the man pages for the automake makefile. !begin am @@ -231,7 +226,6 @@ GUITERM = TERMINAL window windlg winctrls sizetip winucs winprint UXTERM = TERMINAL uxcfg sercfg uxucs uxprint timing callback miscucs GTKTERM = UXTERM gtkwin gtkcfg gtkdlg gtkfont gtkcols gtkmisc xkeysym + x11misc gtkcomm -OSXTERM = UXTERM osxwin osxdlg osxctrls # Non-SSH back ends (putty, puttytel, plink). NONSSH = telnet raw rlogin ldisc pinger @@ -254,7 +248,6 @@ MISC = timing callback misc version settings tree234 proxy conf be_misc WINMISC = MISC winstore winnet winhandl cmdline windefs winmisc winproxy + wintime winhsock errsock winsecur UXMISC = MISC uxstore uxsel uxnet uxpeer cmdline uxmisc uxproxy time -OSXMISC = MISC uxstore uxsel osxsel uxnet uxpeer uxmisc uxproxy time # import.c and dependencies, for PuTTYgen-like utilities that have to # load foreign key files. @@ -331,9 +324,6 @@ pageant : [X] uxpgnt uxagentc pageant sshrsa sshpubk sshdes sshbn sshmd5 + conf uxsignal nocproxy nogss be_none x11fwd ux_x11 uxcons gtkask + gtkmisc UXMISC -PuTTY : [MX] osxmain OSXTERM OSXMISC CHARSET U_BE_ALL NONSSH UXSSH - + ux_x11 uxpty uxsignal testback putty.icns info.plist - ptermapp : [XT] GTKTERM uxmisc misc ldisc settings uxpty uxsel BE_NONE uxstore + uxsignal CHARSET cmdline uxpterm version time xpmpterm xpmptcfg + nogss gtkapp diff --git a/macosx/README.OSX b/macosx/README.OSX deleted file mode 100644 index 084671ad..00000000 --- a/macosx/README.OSX +++ /dev/null @@ -1,92 +0,0 @@ -This directory contains a Mac OS X port of PuTTY/pterm, running as a -native Aqua GUI application. - -THIS PORT IS CURRENTLY UNFINISHED AND EXPERIMENTAL. It is _not_ -considered to be of release quality, even if you've found it (and -are reading this) in a PuTTY release source archive. You are welcome -to try using it, but don't be surprised at unexpected behaviour. I'm -not kidding. - -In particular, I have not yet decided where OS X PuTTY should store -its configuration data. Options include storing it in ~/.putty to be -compatible with Unix PuTTY, storing it wherever is compatible with -Mac Classic PuTTY, storing it in a natively OS X location, or -sorting out the `config-locations' wishlist item and doing all -three. Therefore, if you start using this port and create a whole -load of saved sessions, you should not be surprised if a future -version of the port decides to look somewhere completely different -for the data and therefore loses them all. If that happens, don't -say you weren't warned! - -Other ways in which the port is currently unfinished include: - -Bit rot -------- - - - the conversion of the old fixed-size 'Config' structure to the - new dynamic 'Conf' was never applied to this directory - - - probably other things are out of date too; it would need some - work to make it compile again - -Missing terminal window features --------------------------------- - - - terminal display is horribly slow - - - fonts aren't configurable - - - several features are unimplemented in the terminal display: - underlining, non-solid-block cursors, double-width and - double-height line attributes, bold as font rather than as - colour, wide (CJK) characters, combining characters. - - - there's no scrollbar - - - terminal window resizing isn't implemented yet - - - proper window placement (cascading down and right from the - starting position, plus remembering previous window positions per - the Apple HIG) is not implemented - -Missing alert box features --------------------------- - - - warn-on-close isn't implemented - -Missing input features ----------------------- - - - use of Alt+numberpad to enter arbitrary numeric character codes - is not yet supported - - - there's no Meta key yet. (I'd like to at least have the - possibility of using Command rather than Option as the Meta key, - since the latter is necessary to send some characters, including - the rather important # on Apple UK keyboards; but trapping - Command- and sending it to the window rather than the - application menu requires me to make a positive effort of some - sort and I haven't got round to it yet. For those Mac users who - consider their Command key sacrosanct, don't worry, this option - _will_ be configurable and _will_ be off by default.) - - - there's no specials menu - - - mouse activity isn't supported (neither cut-and-paste nor xterm - mouse tracking) - -Missing terminal emulation features ------------------------------------ - - - currently no support for server-side window management requests - (i.e. escape sequences to minimise or maximise the window, - request or change its position and size, change its title etc) - - - window title is currently fixed - -Other missing features ----------------------- - - - no Event Log - - - no mid-session Change Settings diff --git a/macosx/info.plist b/macosx/info.plist deleted file mode 100644 index ce03a332..00000000 --- a/macosx/info.plist +++ /dev/null @@ -1,8 +0,0 @@ - - - - - CFBundleIconFile - PuTTY.icns - - diff --git a/macosx/osx.h b/macosx/osx.h deleted file mode 100644 index 165539fb..00000000 --- a/macosx/osx.h +++ /dev/null @@ -1,34 +0,0 @@ -#ifndef PUTTY_OSX_H -#define PUTTY_OSX_H - -/* - * Cocoa defines `FontSpec' itself, so we must change its name. - * (Arrgh.) - */ -#define FontSpec FontSpec_OSX_Proof - -/* - * Define the various compatibility symbols to make uxpty.c compile - * correctly on OS X. - */ -#define BSD_PTYS -#define OMIT_UTMP -#define HAVE_NO_SETRESUID -#define NOT_X_WINDOWS - -/* - * OS X is largely just Unix, so we can include most of this - * unchanged. - */ -#include "unix.h" - -/* - * Functions exported by osxsel.m. (Both of these functions are - * expected to be called in the _main_ thread: the select subthread - * is an implementation detail of osxsel.m and ideally should not - * be visible at all outside it.) - */ -void osxsel_init(void); /* call this to kick things off */ -void osxsel_process_results(void); /* call this on receipt of a netevent */ - -#endif diff --git a/macosx/osxclass.h b/macosx/osxclass.h deleted file mode 100644 index e79290df..00000000 --- a/macosx/osxclass.h +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Header file for the Objective-C parts of Mac OS X PuTTY. This - * file contains the class definitions, which would cause compile - * failures in the pure C modules if they appeared in osx.h. - */ - -#ifndef PUTTY_OSXCLASS_H -#define PUTTY_OSXCLASS_H - -#include "putty.h" - -/* - * The application controller class, defined in osxmain.m. - */ -@interface AppController : NSObject -{ - NSTimer *timer; -} -- (void)newSessionConfig:(id)sender; -- (void)newTerminal:(id)sender; -- (void)newSessionWithConfig:(id)cfg; -- (void)setTimer:(long)next; -@end -extern AppController *controller; - -/* - * The SessionWindow class, defined in osxwin.m. - */ - -struct alert_queue { - struct alert_queue *next; - NSAlert *alert; - void (*callback)(void *, int); - void *ctx; -}; - -@class SessionWindow; -@class TerminalView; - -@interface SessionWindow : NSWindow -{ - Terminal *term; - TerminalView *termview; - struct unicode_data ucsdata; - void *logctx; - Config cfg; - void *ldisc; - Backend *back; - void *backhandle; - int exited; - /* - * The following two members relate to the currently active - * alert sheet, if any. They are NULL if there isn't one. - */ - void (*alert_callback)(void *, int); - void *alert_ctx; - /* This queues future alerts that need to be shown. */ - struct alert_queue *alert_qhead, *alert_qtail; -} -- (id)initWithConfig:(Config)cfg; -- (void)drawStartFinish:(BOOL)start; -- (void)setColour:(int)n r:(float)r g:(float)g b:(float)b; -- (Config *)cfg; -- (void)doText:(wchar_t *)text len:(int)len x:(int)x y:(int)y - attr:(unsigned long)attr lattr:(int)lattr; -- (int)fromBackend:(const char *)data len:(int)len isStderr:(int)is_stderr; -- (int)fromBackendUntrusted:(const char *)data len:(int)len; -- (void)startAlert:(NSAlert *)alert - withCallback:(void (*)(void *, int))callback andCtx:(void *)ctx; -- (void)endSession:(int)clean; -- (void)notifyRemoteExit; -- (Terminal *)term; -@end - -/* - * The ConfigWindow class, defined in osxdlg.m. - */ - -@class ConfigWindow; - -@interface ConfigWindow : NSWindow -{ - NSOutlineView *treeview; - struct controlbox *ctrlbox; - void *dv; - Config cfg; -} -- (id)initWithConfig:(Config)cfg; -@end - -/* - * Functions exported by osxctrls.m. (They have to go in this - * header file and not osx.h, because some of them have Cocoa class - * types in their prototypes.) - */ -#define HSPACING 12 /* needed in osxdlg.m and osxctrls.m */ -#define VSPACING 8 - -void *fe_dlg_init(void *data, NSWindow *window, NSObject *target, SEL action); -void fe_dlg_free(void *dv); -void create_ctrls(void *dv, NSView *parent, struct controlset *s, - int *minw, int *minh); -int place_ctrls(void *dv, struct controlset *s, int leftx, int topy, - int width); /* returns height used */ -void select_panel(void *dv, struct controlbox *b, const char *name); - -#endif /* PUTTY_OSXCLASS_H */ diff --git a/macosx/osxctrls.m b/macosx/osxctrls.m deleted file mode 100644 index 27c2c52b..00000000 --- a/macosx/osxctrls.m +++ /dev/null @@ -1,1781 +0,0 @@ -/* - * osxctrls.m: OS X implementation of the dialog.h interface. - */ - -#import -#include "putty.h" -#include "dialog.h" -#include "osxclass.h" -#include "tree234.h" - -/* - * Still to be implemented: - * - * - file selectors (NSOpenPanel / NSSavePanel) - * - * - font selectors - * - colour selectors - * * both of these have a conceptual oddity in Cocoa that - * you're only supposed to have one per application. But I - * currently expect to be able to have multiple PuTTY config - * boxes on screen at once; what happens if you trigger the - * font selector in each one at the same time? - * * if it comes to that, the _font_ selector can probably be - * managed by other means: nobody is forcing me to implement - * a font selector using a `Change...' button. The portable - * dialog interface gives me the flexibility to do this how I - * want. - * * The colour selector interface, in its present form, is - * more interesting and _if_ a radical change of plan is - * required then it may stretch across the interface into the - * portable side. - * * Before I do anything rash I should start by looking at the - * Mac Classic port and see how it's done there, on the basis - * that Apple seem reasonably unlikely to have invented this - * crazy restriction specifically for OS X. - * - * - focus management - * * I tried using makeFirstResponder to give keyboard focus, - * but it appeared not to work. Try again, and work out how - * it should be done. - * * also look into tab order. Currently pressing Tab suggests - * that only edit boxes and list boxes can get the keyboard - * focus, and that buttons (in all their forms) are unable to - * be driven by the keyboard. Find out for sure. - * - * - dlg_error_msg - * * this may run into the usual aggro with modal dialog boxes. - */ - -/* - * For Cocoa control layout, I need a two-stage process. In stage - * one, I allocate all the controls and measure their natural - * sizes, which allows me to compute the _minimum_ width and height - * of a given section of dialog. Then, in stage two, I lay out the - * dialog box as a whole, decide how much each section of the box - * needs to receive, and assign it its final size. - */ - -/* - * As yet unsolved issues [FIXME]: - * - * - Sometimes the height returned from create_ctrls and the - * height returned from place_ctrls differ. Find out why. It may - * be harmless (e.g. results of NSTextView being odd), but I - * want to know. - * - * - NSTextViews are indented a bit. It'd be nice to put their - * left margin at the same place as everything else's. - * - * - I don't yet know whether we even _can_ support tab order or - * keyboard shortcuts. If we can't, then fair enough, we can't. - * But if we can, we should. - * - * - I would _really_ like to know of a better way to correct - * NSButton's stupid size estimates than by subclassing it and - * overriding sizeToFit with hard-wired sensible values! - * - * - Speaking of stupid size estimates, the amount by which I'm - * adjusting a titled NSBox (currently equal to the point size - * of its title font) looks as if it isn't _quite_ enough. - * Figure out what the real amount should be and use it. - * - * - I don't understand why there's always a scrollbar displayed - * in each list box. I thought I told it to autohide scrollers? - * - * - Why do I have to fudge list box heights by adding one? (Might - * it be to do with the missing header view?) - */ - -/* - * Subclass of NSButton which corrects the fact that the normal - * one's sizeToFit method persistently returns 32 as its height, - * which is simply a lie. I have yet to work out a better - * alternative than hard-coding the real heights. - */ -@interface MyButton : NSButton -{ - int minht; -} -@end -@implementation MyButton -- (id)initWithFrame:(NSRect)r -{ - self = [super initWithFrame:r]; - minht = 25; - return self; -} -- (void)setButtonType:(NSButtonType)t -{ - if (t == NSRadioButton || t == NSSwitchButton) - minht = 18; - else - minht = 25; - [super setButtonType:t]; -} -- (void)sizeToFit -{ - NSRect r; - [super sizeToFit]; - r = [self frame]; - r.size.height = minht; - [self setFrame:r]; -} -@end - -/* - * Class used as the data source for NSTableViews. - */ -@interface MyTableSource : NSObject -{ - tree234 *tree; -} -- (id)init; -- (void)add:(const char *)str withId:(int)id; -- (int)getid:(int)index; -- (void)swap:(int)index1 with:(int)index2; -- (void)removestr:(int)index; -- (void)clear; -@end -@implementation MyTableSource -- (id)init -{ - self = [super init]; - tree = newtree234(NULL); - return self; -} -- (void)dealloc -{ - char *p; - while ((p = delpos234(tree, 0)) != NULL) - sfree(p); - freetree234(tree); - [super dealloc]; -} -- (void)add:(const char *)str withId:(int)id -{ - addpos234(tree, dupprintf("%d\t%s", id, str), count234(tree)); -} -- (int)getid:(int)index -{ - char *p = index234(tree, index); - return atoi(p); -} -- (void)removestr:(int)index -{ - char *p = delpos234(tree, index); - sfree(p); -} -- (void)swap:(int)index1 with:(int)index2 -{ - char *p1, *p2; - - if (index1 > index2) { - int t = index1; index1 = index2; index2 = t; - } - - /* delete later one first so it doesn't affect index of earlier one */ - p2 = delpos234(tree, index2); - p1 = delpos234(tree, index1); - - /* now insert earlier one before later one for the inverse reason */ - addpos234(tree, p2, index1); - addpos234(tree, p1, index2); -} -- (void)clear -{ - char *p; - while ((p = delpos234(tree, 0)) != NULL) - sfree(p); -} -- (int)numberOfRowsInTableView:(NSTableView *)aTableView -{ - return count234(tree); -} -- (id)tableView:(NSTableView *)aTableView - objectValueForTableColumn:(NSTableColumn *)aTableColumn - row:(int)rowIndex -{ - int j = [[aTableColumn identifier] intValue]; - char *p = index234(tree, rowIndex); - - while (j >= 0) { - p += strcspn(p, "\t"); - if (*p) p++; - j--; - } - - return [NSString stringWithCString:p length:strcspn(p, "\t")]; -} -@end - -/* - * Object to receive messages from various control classes. - */ -@class Receiver; - -struct fe_dlg { - NSWindow *window; - NSObject *target; - SEL action; - tree234 *byctrl; - tree234 *bywidget; - tree234 *boxes; - void *data; /* passed to portable side */ - Receiver *rec; -}; - -@interface Receiver : NSObject -{ - struct fe_dlg *d; -} -- (id)initWithStruct:(struct fe_dlg *)aStruct; -@end - -struct fe_ctrl { - union control *ctrl; - NSButton *button, *button2; - NSTextField *label, *editbox; - NSComboBox *combobox; - NSButton **radiobuttons; - NSTextView *textview; - NSPopUpButton *popupbutton; - NSTableView *tableview; - NSScrollView *scrollview; - int nradiobuttons; -}; - -static int fe_ctrl_cmp_by_ctrl(void *av, void *bv) -{ - struct fe_ctrl *a = (struct fe_ctrl *)av; - struct fe_ctrl *b = (struct fe_ctrl *)bv; - - if (a->ctrl < b->ctrl) - return -1; - if (a->ctrl > b->ctrl) - return +1; - return 0; -} - -static int fe_ctrl_find_by_ctrl(void *av, void *bv) -{ - union control *a = (union control *)av; - struct fe_ctrl *b = (struct fe_ctrl *)bv; - - if (a < b->ctrl) - return -1; - if (a > b->ctrl) - return +1; - return 0; -} - -struct fe_box { - struct controlset *s; - id box; -}; - -static int fe_boxcmp(void *av, void *bv) -{ - struct fe_box *a = (struct fe_box *)av; - struct fe_box *b = (struct fe_box *)bv; - - if (a->s < b->s) - return -1; - if (a->s > b->s) - return +1; - return 0; -} - -static int fe_boxfind(void *av, void *bv) -{ - struct controlset *a = (struct controlset *)av; - struct fe_box *b = (struct fe_box *)bv; - - if (a < b->s) - return -1; - if (a > b->s) - return +1; - return 0; -} - -struct fe_backwards { /* map Cocoa widgets back to fe_ctrls */ - id widget; - struct fe_ctrl *c; -}; - -static int fe_backwards_cmp_by_widget(void *av, void *bv) -{ - struct fe_backwards *a = (struct fe_backwards *)av; - struct fe_backwards *b = (struct fe_backwards *)bv; - - if (a->widget < b->widget) - return -1; - if (a->widget > b->widget) - return +1; - return 0; -} - -static int fe_backwards_find_by_widget(void *av, void *bv) -{ - id a = (id)av; - struct fe_backwards *b = (struct fe_backwards *)bv; - - if (a < b->widget) - return -1; - if (a > b->widget) - return +1; - return 0; -} - -static struct fe_ctrl *fe_ctrl_new(union control *ctrl) -{ - struct fe_ctrl *c; - - c = snew(struct fe_ctrl); - c->ctrl = ctrl; - - c->button = c->button2 = nil; - c->label = nil; - c->editbox = nil; - c->combobox = nil; - c->textview = nil; - c->popupbutton = nil; - c->tableview = nil; - c->scrollview = nil; - c->radiobuttons = NULL; - c->nradiobuttons = 0; - - return c; -} - -static void fe_ctrl_free(struct fe_ctrl *c) -{ - sfree(c->radiobuttons); - sfree(c); -} - -static struct fe_ctrl *fe_ctrl_byctrl(struct fe_dlg *d, union control *ctrl) -{ - return find234(d->byctrl, ctrl, fe_ctrl_find_by_ctrl); -} - -static void add_box(struct fe_dlg *d, struct controlset *s, id box) -{ - struct fe_box *b = snew(struct fe_box); - b->box = box; - b->s = s; - add234(d->boxes, b); -} - -static id find_box(struct fe_dlg *d, struct controlset *s) -{ - struct fe_box *b = find234(d->boxes, s, fe_boxfind); - return b ? b->box : NULL; -} - -static void add_widget(struct fe_dlg *d, struct fe_ctrl *c, id widget) -{ - struct fe_backwards *b = snew(struct fe_backwards); - b->widget = widget; - b->c = c; - add234(d->bywidget, b); -} - -static struct fe_ctrl *find_widget(struct fe_dlg *d, id widget) -{ - struct fe_backwards *b = find234(d->bywidget, widget, - fe_backwards_find_by_widget); - return b ? b->c : NULL; -} - -void *fe_dlg_init(void *data, NSWindow *window, NSObject *target, SEL action) -{ - struct fe_dlg *d; - - d = snew(struct fe_dlg); - d->window = window; - d->target = target; - d->action = action; - d->byctrl = newtree234(fe_ctrl_cmp_by_ctrl); - d->bywidget = newtree234(fe_backwards_cmp_by_widget); - d->boxes = newtree234(fe_boxcmp); - d->data = data; - d->rec = [[Receiver alloc] initWithStruct:d]; - - return d; -} - -void fe_dlg_free(void *dv) -{ - struct fe_dlg *d = (struct fe_dlg *)dv; - struct fe_ctrl *c; - struct fe_box *b; - - while ( (c = delpos234(d->byctrl, 0)) != NULL ) - fe_ctrl_free(c); - freetree234(d->byctrl); - - while ( (c = delpos234(d->bywidget, 0)) != NULL ) - sfree(c); - freetree234(d->bywidget); - - while ( (b = delpos234(d->boxes, 0)) != NULL ) - sfree(b); - freetree234(d->boxes); - - [d->rec release]; - - sfree(d); -} - -@implementation Receiver -- (id)initWithStruct:(struct fe_dlg *)aStruct -{ - self = [super init]; - d = aStruct; - return self; -} -- (void)buttonPushed:(id)sender -{ - struct fe_ctrl *c = find_widget(d, sender); - - assert(c && c->ctrl->generic.type == CTRL_BUTTON); - c->ctrl->generic.handler(c->ctrl, d, d->data, EVENT_ACTION); -} -- (void)checkboxChanged:(id)sender -{ - struct fe_ctrl *c = find_widget(d, sender); - - assert(c && c->ctrl->generic.type == CTRL_CHECKBOX); - c->ctrl->generic.handler(c->ctrl, d, d->data, EVENT_VALCHANGE); -} -- (void)radioChanged:(id)sender -{ - struct fe_ctrl *c = find_widget(d, sender); - int j; - - assert(c && c->radiobuttons); - for (j = 0; j < c->nradiobuttons; j++) - if (sender != c->radiobuttons[j]) - [c->radiobuttons[j] setState:NSOffState]; - c->ctrl->generic.handler(c->ctrl, d, d->data, EVENT_VALCHANGE); -} -- (void)popupMenuSelected:(id)sender -{ - struct fe_ctrl *c = find_widget(d, sender); - c->ctrl->generic.handler(c->ctrl, d, d->data, EVENT_VALCHANGE); -} -- (void)controlTextDidChange:(NSNotification *)notification -{ - id widget = [notification object]; - struct fe_ctrl *c = find_widget(d, widget); - assert(c && c->ctrl->generic.type == CTRL_EDITBOX); - c->ctrl->generic.handler(c->ctrl, d, d->data, EVENT_VALCHANGE); -} -- (void)controlTextDidEndEditing:(NSNotification *)notification -{ - id widget = [notification object]; - struct fe_ctrl *c = find_widget(d, widget); - assert(c && c->ctrl->generic.type == CTRL_EDITBOX); - c->ctrl->generic.handler(c->ctrl, d, d->data, EVENT_REFRESH); -} -- (void)tableViewSelectionDidChange:(NSNotification *)notification -{ - id widget = [notification object]; - struct fe_ctrl *c = find_widget(d, widget); - assert(c && c->ctrl->generic.type == CTRL_LISTBOX); - c->ctrl->generic.handler(c->ctrl, d, d->data, EVENT_SELCHANGE); -} -- (BOOL)tableView:(NSTableView *)aTableView - shouldEditTableColumn:(NSTableColumn *)aTableColumn - row:(int)rowIndex -{ - return NO; /* no editing permitted */ -} -- (void)listDoubleClicked:(id)sender -{ - struct fe_ctrl *c = find_widget(d, sender); - assert(c && c->ctrl->generic.type == CTRL_LISTBOX); - c->ctrl->generic.handler(c->ctrl, d, d->data, EVENT_ACTION); -} -- (void)dragListButton:(id)sender -{ - struct fe_ctrl *c = find_widget(d, sender); - int direction, row, nrows; - assert(c && c->ctrl->generic.type == CTRL_LISTBOX && - c->ctrl->listbox.draglist); - - if (sender == c->button) - direction = -1; /* up */ - else - direction = +1; /* down */ - - row = [c->tableview selectedRow]; - nrows = [c->tableview numberOfRows]; - - if (row + direction < 0 || row + direction >= nrows) { - NSBeep(); - return; - } - - [[c->tableview dataSource] swap:row with:row+direction]; - [c->tableview reloadData]; - [c->tableview selectRow:row+direction byExtendingSelection:NO]; - - c->ctrl->generic.handler(c->ctrl, d, d->data, EVENT_VALCHANGE); -} -@end - -void create_ctrls(void *dv, NSView *parent, struct controlset *s, - int *minw, int *minh) -{ - struct fe_dlg *d = (struct fe_dlg *)dv; - int ccw[100]; /* cumulative column widths */ - int cypos[100]; - int ncols; - int wmin = 0, hmin = 0; - int i, j, cw, ch; - NSRect rect; - NSFont *textviewfont = nil; - int boxh = 0, boxw = 0; - - if (!s->boxname && s->boxtitle) { - /* This controlset is a panel title. */ - - NSTextField *tf; - - tf = [[NSTextField alloc] initWithFrame:NSMakeRect(0,0,1,1)]; - [tf setEditable:NO]; - [tf setSelectable:NO]; - [tf setBordered:NO]; - [tf setDrawsBackground:NO]; - [tf setStringValue:[NSString stringWithCString:s->boxtitle]]; - [tf sizeToFit]; - rect = [tf frame]; - [parent addSubview:tf]; - - /* - * I'm going to store this NSTextField in the boxes tree, - * because I really can't face having a special tree234 - * mapping controlsets to panel titles. - */ - add_box(d, s, tf); - - *minw = rect.size.width; - *minh = rect.size.height; - - return; - } - - if (*s->boxname) { - /* - * Create an NSBox to contain this subset of controls. - */ - NSBox *box; - NSRect tmprect; - - box = [[NSBox alloc] initWithFrame:NSMakeRect(0,0,1,1)]; - if (s->boxtitle) - [box setTitle:[NSString stringWithCString:s->boxtitle]]; - else - [box setTitlePosition:NSNoTitle]; - add_box(d, s, box); - tmprect = [box frame]; - [box setContentViewMargins:NSMakeSize(20,20)]; - [box setFrameFromContentFrame:NSMakeRect(100,100,100,100)]; - rect = [box frame]; - [box setFrame:tmprect]; - boxh = (int)(rect.size.height - 100); - boxw = (int)(rect.size.width - 100); - [parent addSubview:box]; - - if (s->boxtitle) - boxh += [[box titleFont] pointSize]; - - /* - * All subsequent controls will be placed within this box. - */ - parent = box; - } - - ncols = 1; - ccw[0] = 0; - ccw[1] = 100; - cypos[0] = 0; - - /* - * Now iterate through the controls themselves, create them, - * and add their width and height to the overall width/height - * calculation. - */ - for (i = 0; i < s->ncontrols; i++) { - union control *ctrl = s->ctrls[i]; - struct fe_ctrl *c; - int colstart = COLUMN_START(ctrl->generic.column); - int colspan = COLUMN_SPAN(ctrl->generic.column); - int colend = colstart + colspan; - int ytop, wthis; - - switch (ctrl->generic.type) { - case CTRL_COLUMNS: - for (j = 1; j < ncols; j++) - if (cypos[0] < cypos[j]) - cypos[0] = cypos[j]; - - assert(ctrl->columns.ncols < lenof(ccw)); - - ccw[0] = 0; - for (j = 0; j < ctrl->columns.ncols; j++) { - ccw[j+1] = ccw[j] + (ctrl->columns.percentages ? - ctrl->columns.percentages[j] : 100); - cypos[j] = cypos[0]; - } - - ncols = ctrl->columns.ncols; - - continue; /* no actual control created */ - case CTRL_TABDELAY: - /* - * I'm currently uncertain that we can implement tab - * order in OS X. - */ - continue; /* no actual control created */ - } - - c = fe_ctrl_new(ctrl); - add234(d->byctrl, c); - - cw = ch = 0; - - switch (ctrl->generic.type) { - case CTRL_BUTTON: - case CTRL_CHECKBOX: - { - NSButton *b; - - b = [[MyButton alloc] initWithFrame:NSMakeRect(0, 0, 1, 1)]; - [b setBezelStyle:NSRoundedBezelStyle]; - if (ctrl->generic.type == CTRL_CHECKBOX) - [b setButtonType:NSSwitchButton]; - [b setTitle:[NSString stringWithCString:ctrl->generic.label]]; - if (ctrl->button.isdefault) - [b setKeyEquivalent:@"\r"]; - else if (ctrl->button.iscancel) - [b setKeyEquivalent:@"\033"]; - [b sizeToFit]; - rect = [b frame]; - - [parent addSubview:b]; - - [b setTarget:d->rec]; - if (ctrl->generic.type == CTRL_CHECKBOX) - [b setAction:@selector(checkboxChanged:)]; - else - [b setAction:@selector(buttonPushed:)]; - add_widget(d, c, b); - - c->button = b; - - cw = rect.size.width; - ch = rect.size.height; - } - break; - case CTRL_EDITBOX: - { - int editp = ctrl->editbox.percentwidth; - int labelp = editp == 100 ? 100 : 100 - editp; - NSTextField *tf; - NSComboBox *cb; - - tf = [[NSTextField alloc] initWithFrame:NSMakeRect(0,0,1,1)]; - [tf setEditable:NO]; - [tf setSelectable:NO]; - [tf setBordered:NO]; - [tf setDrawsBackground:NO]; - [tf setStringValue:[NSString - stringWithCString:ctrl->generic.label]]; - [tf sizeToFit]; - rect = [tf frame]; - [parent addSubview:tf]; - c->label = tf; - - cw = rect.size.width * 100 / labelp; - ch = rect.size.height; - - if (ctrl->editbox.has_list) { - cb = [[NSComboBox alloc] - initWithFrame:NSMakeRect(0,0,1,1)]; - [cb setStringValue:@"x"]; - [cb sizeToFit]; - rect = [cb frame]; - [parent addSubview:cb]; - c->combobox = cb; - } else { - if (ctrl->editbox.password) - tf = [NSSecureTextField alloc]; - else - tf = [NSTextField alloc]; - - tf = [tf initWithFrame:NSMakeRect(0,0,1,1)]; - [tf setEditable:YES]; - [tf setSelectable:YES]; - [tf setBordered:YES]; - [tf setStringValue:@"x"]; - [tf sizeToFit]; - rect = [tf frame]; - [parent addSubview:tf]; - c->editbox = tf; - - [tf setDelegate:d->rec]; - add_widget(d, c, tf); - } - - if (editp == 100) { - /* the edit box and its label are vertically separated */ - ch += VSPACING + rect.size.height; - } else { - /* the edit box and its label are horizontally separated */ - if (ch < rect.size.height) - ch = rect.size.height; - } - - if (cw < rect.size.width * 100 / editp) - cw = rect.size.width * 100 / editp; - } - break; - case CTRL_TEXT: - { - NSTextView *tv; - int testwid; - - if (!textviewfont) { - NSTextField *tf; - tf = [[NSTextField alloc] init]; - textviewfont = [tf font]; - [tf release]; - } - - testwid = (ccw[colend] - ccw[colstart]) * 3; - - tv = [[NSTextView alloc] - initWithFrame:NSMakeRect(0,0,testwid,1)]; - [tv setEditable:NO]; - [tv setSelectable:NO]; - //[tv setBordered:NO]; - [tv setDrawsBackground:NO]; - [tv setFont:textviewfont]; - [tv setString: - [NSString stringWithCString:ctrl->generic.label]]; - rect = [tv frame]; - [tv sizeToFit]; - [parent addSubview:tv]; - c->textview = tv; - - cw = rect.size.width; - ch = rect.size.height; - } - break; - case CTRL_RADIO: - { - NSTextField *tf; - int j; - - if (ctrl->generic.label) { - tf = [[NSTextField alloc] - initWithFrame:NSMakeRect(0,0,1,1)]; - [tf setEditable:NO]; - [tf setSelectable:NO]; - [tf setBordered:NO]; - [tf setDrawsBackground:NO]; - [tf setStringValue: - [NSString stringWithCString:ctrl->generic.label]]; - [tf sizeToFit]; - rect = [tf frame]; - [parent addSubview:tf]; - c->label = tf; - - cw = rect.size.width; - ch = rect.size.height; - } else { - cw = 0; - ch = -VSPACING; /* compensate for next advance */ - } - - c->nradiobuttons = ctrl->radio.nbuttons; - c->radiobuttons = snewn(ctrl->radio.nbuttons, NSButton *); - - for (j = 0; j < ctrl->radio.nbuttons; j++) { - NSButton *b; - int ncols; - - b = [[MyButton alloc] initWithFrame:NSMakeRect(0,0,1,1)]; - [b setBezelStyle:NSRoundedBezelStyle]; - [b setButtonType:NSRadioButton]; - [b setTitle:[NSString - stringWithCString:ctrl->radio.buttons[j]]]; - [b sizeToFit]; - rect = [b frame]; - [parent addSubview:b]; - - c->radiobuttons[j] = b; - - [b setTarget:d->rec]; - [b setAction:@selector(radioChanged:)]; - add_widget(d, c, b); - - /* - * Add to the height every time we place a - * button in column 0. - */ - if (j % ctrl->radio.ncolumns == 0) { - ch += rect.size.height + VSPACING; - } - - /* - * Add to the width by working out how many - * columns this button spans. - */ - if (j == ctrl->radio.nbuttons - 1) - ncols = (ctrl->radio.ncolumns - - (j % ctrl->radio.ncolumns)); - else - ncols = 1; - - if (cw < rect.size.width * ctrl->radio.ncolumns / ncols) - cw = rect.size.width * ctrl->radio.ncolumns / ncols; - } - } - break; - case CTRL_FILESELECT: - case CTRL_FONTSELECT: - { - NSTextField *tf; - NSButton *b; - int kh; - - tf = [[NSTextField alloc] initWithFrame:NSMakeRect(0,0,1,1)]; - [tf setEditable:NO]; - [tf setSelectable:NO]; - [tf setBordered:NO]; - [tf setDrawsBackground:NO]; - [tf setStringValue:[NSString - stringWithCString:ctrl->generic.label]]; - [tf sizeToFit]; - rect = [tf frame]; - [parent addSubview:tf]; - c->label = tf; - - cw = rect.size.width; - ch = rect.size.height; - - tf = [NSTextField alloc]; - tf = [tf initWithFrame:NSMakeRect(0,0,1,1)]; - if (ctrl->generic.type == CTRL_FILESELECT) { - [tf setEditable:YES]; - [tf setSelectable:YES]; - [tf setBordered:YES]; - } else { - [tf setEditable:NO]; - [tf setSelectable:NO]; - [tf setBordered:NO]; - [tf setDrawsBackground:NO]; - } - [tf setStringValue:@"x"]; - [tf sizeToFit]; - rect = [tf frame]; - [parent addSubview:tf]; - c->editbox = tf; - - kh = rect.size.height; - if (cw < rect.size.width * 4 / 3) - cw = rect.size.width * 4 / 3; - - b = [[MyButton alloc] initWithFrame:NSMakeRect(0, 0, 1, 1)]; - [b setBezelStyle:NSRoundedBezelStyle]; - if (ctrl->generic.type == CTRL_FILESELECT) - [b setTitle:@"Browse..."]; - else - [b setTitle:@"Change..."]; - // [b setKeyEquivalent:somethingorother]; - // [b setTarget:somethingorother]; - // [b setAction:somethingorother]; - [b sizeToFit]; - rect = [b frame]; - [parent addSubview:b]; - - c->button = b; - - if (kh < rect.size.height) - kh = rect.size.height; - ch += VSPACING + kh; - if (cw < rect.size.width * 4) - cw = rect.size.width * 4; - } - break; - case CTRL_LISTBOX: - { - int listp = ctrl->listbox.percentwidth; - int labelp = listp == 100 ? 100 : 100 - listp; - NSTextField *tf; - NSPopUpButton *pb; - NSTableView *tv; - NSScrollView *sv; - - if (ctrl->generic.label) { - tf = [[NSTextField alloc] - initWithFrame:NSMakeRect(0,0,1,1)]; - [tf setEditable:NO]; - [tf setSelectable:NO]; - [tf setBordered:NO]; - [tf setDrawsBackground:NO]; - [tf setStringValue: - [NSString stringWithCString:ctrl->generic.label]]; - [tf sizeToFit]; - rect = [tf frame]; - [parent addSubview:tf]; - c->label = tf; - - cw = rect.size.width; - ch = rect.size.height; - } else { - cw = 0; - ch = -VSPACING; /* compensate for next advance */ - } - - if (ctrl->listbox.height == 0) { - pb = [[NSPopUpButton alloc] - initWithFrame:NSMakeRect(0,0,1,1)]; - [pb sizeToFit]; - rect = [pb frame]; - [parent addSubview:pb]; - c->popupbutton = pb; - - [pb setTarget:d->rec]; - [pb setAction:@selector(popupMenuSelected:)]; - add_widget(d, c, pb); - } else { - assert(listp == 100); - if (ctrl->listbox.draglist) { - int bi; - - listp = 75; - - for (bi = 0; bi < 2; bi++) { - NSButton *b; - b = [[MyButton alloc] - initWithFrame:NSMakeRect(0, 0, 1, 1)]; - [b setBezelStyle:NSRoundedBezelStyle]; - if (bi == 0) - [b setTitle:@"Up"]; - else - [b setTitle:@"Down"]; - [b sizeToFit]; - rect = [b frame]; - [parent addSubview:b]; - - if (bi == 0) - c->button = b; - else - c->button2 = b; - - [b setTarget:d->rec]; - [b setAction:@selector(dragListButton:)]; - add_widget(d, c, b); - - if (cw < rect.size.width * 4) - cw = rect.size.width * 4; - } - } - - sv = [[NSScrollView alloc] initWithFrame: - NSMakeRect(20,20,10,10)]; - [sv setBorderType:NSLineBorder]; - tv = [[NSTableView alloc] initWithFrame:[sv frame]]; - [[tv headerView] setFrame:NSMakeRect(0,0,0,0)]; - [sv setDocumentView:tv]; - [parent addSubview:sv]; - [sv setHasVerticalScroller:YES]; - [sv setAutohidesScrollers:YES]; - [tv setAllowsColumnReordering:NO]; - [tv setAllowsColumnResizing:NO]; - [tv setAllowsMultipleSelection:ctrl->listbox.multisel]; - [tv setAllowsEmptySelection:YES]; - [tv setAllowsColumnSelection:YES]; - [tv setDataSource:[[MyTableSource alloc] init]]; - rect = [tv frame]; - /* - * For some reason this consistently comes out - * one short. Add one. - */ - rect.size.height = (ctrl->listbox.height+1)*[tv rowHeight]; - [sv setFrame:rect]; - c->tableview = tv; - c->scrollview = sv; - - [tv setDelegate:d->rec]; - [tv setTarget:d->rec]; - [tv setDoubleAction:@selector(listDoubleClicked:)]; - add_widget(d, c, tv); - } - - if (c->tableview) { - int ncols, *percentages; - int hundred = 100; - - if (ctrl->listbox.ncols) { - ncols = ctrl->listbox.ncols; - percentages = ctrl->listbox.percentages; - } else { - ncols = 1; - percentages = &hundred; - } - - for (j = 0; j < ncols; j++) { - NSTableColumn *col; - - col = [[NSTableColumn alloc] initWithIdentifier: - [NSNumber numberWithInt:j]]; - [c->tableview addTableColumn:col]; - } - } - - if (labelp == 100) { - /* the list and its label are vertically separated */ - ch += VSPACING + rect.size.height; - } else { - /* the list and its label are horizontally separated */ - if (ch < rect.size.height) - ch = rect.size.height; - } - - if (cw < rect.size.width * 100 / listp) - cw = rect.size.width * 100 / listp; - } - break; - } - - /* - * Update the width and height data for the control we've - * just created. - */ - ytop = 0; - - for (j = colstart; j < colend; j++) { - if (ytop < cypos[j]) - ytop = cypos[j]; - } - - for (j = colstart; j < colend; j++) - cypos[j] = ytop + ch + VSPACING; - - if (hmin < ytop + ch) - hmin = ytop + ch; - - wthis = (cw + HSPACING) * 100 / (ccw[colend] - ccw[colstart]); - wthis -= HSPACING; - - if (wmin < wthis) - wmin = wthis; - } - - if (*s->boxname) { - /* - * Add a bit to the width and height for the box. - */ - wmin += boxw; - hmin += boxh; - } - - //printf("For controlset %s/%s, returning w=%d h=%d\n", - // s->pathname, s->boxname, wmin, hmin); - *minw = wmin; - *minh = hmin; -} - -int place_ctrls(void *dv, struct controlset *s, int leftx, int topy, - int width) -{ - struct fe_dlg *d = (struct fe_dlg *)dv; - int ccw[100]; /* cumulative column widths */ - int cypos[100]; - int ncols; - int i, j, ret; - int boxh = 0, boxw = 0; - - if (!s->boxname && s->boxtitle) { - /* Size and place the panel title. */ - - NSTextField *tf = find_box(d, s); - NSRect rect; - - rect = [tf frame]; - [tf setFrame:NSMakeRect(leftx, topy-rect.size.height, - width, rect.size.height)]; - return rect.size.height; - } - - if (*s->boxname) { - NSRect rect, tmprect; - NSBox *box = find_box(d, s); - - assert(box != NULL); - tmprect = [box frame]; - [box setFrameFromContentFrame:NSMakeRect(100,100,100,100)]; - rect = [box frame]; - [box setFrame:tmprect]; - boxw = rect.size.width - 100; - boxh = rect.size.height - 100; - if (s->boxtitle) - boxh += [[box titleFont] pointSize]; - topy -= boxh; - width -= boxw; - } - - ncols = 1; - ccw[0] = 0; - ccw[1] = 100; - cypos[0] = topy; - ret = 0; - - /* - * Now iterate through the controls themselves, placing them - * appropriately. - */ - for (i = 0; i < s->ncontrols; i++) { - union control *ctrl = s->ctrls[i]; - struct fe_ctrl *c; - int colstart = COLUMN_START(ctrl->generic.column); - int colspan = COLUMN_SPAN(ctrl->generic.column); - int colend = colstart + colspan; - int xthis, ythis, wthis, ch; - NSRect rect; - - switch (ctrl->generic.type) { - case CTRL_COLUMNS: - for (j = 1; j < ncols; j++) - if (cypos[0] > cypos[j]) - cypos[0] = cypos[j]; - - assert(ctrl->columns.ncols < lenof(ccw)); - - ccw[0] = 0; - for (j = 0; j < ctrl->columns.ncols; j++) { - ccw[j+1] = ccw[j] + (ctrl->columns.percentages ? - ctrl->columns.percentages[j] : 100); - cypos[j] = cypos[0]; - } - - ncols = ctrl->columns.ncols; - - continue; /* no actual control created */ - case CTRL_TABDELAY: - continue; /* nothing to do here, move along */ - } - - c = fe_ctrl_byctrl(d, ctrl); - - ch = 0; - ythis = topy; - - for (j = colstart; j < colend; j++) { - if (ythis > cypos[j]) - ythis = cypos[j]; - } - - xthis = (width + HSPACING) * ccw[colstart] / 100; - wthis = (width + HSPACING) * ccw[colend] / 100 - HSPACING - xthis; - xthis += leftx; - - switch (ctrl->generic.type) { - case CTRL_BUTTON: - case CTRL_CHECKBOX: - rect = [c->button frame]; - [c->button setFrame:NSMakeRect(xthis,ythis-rect.size.height,wthis, - rect.size.height)]; - ch = rect.size.height; - break; - case CTRL_EDITBOX: - { - int editp = ctrl->editbox.percentwidth; - int labelp = editp == 100 ? 100 : 100 - editp; - int lheight, theight, rheight, ynext, editw; - NSControl *edit = (c->editbox ? c->editbox : c->combobox); - - rect = [c->label frame]; - lheight = rect.size.height; - rect = [edit frame]; - theight = rect.size.height; - - if (editp == 100) - rheight = lheight; - else - rheight = (lheight < theight ? theight : lheight); - - [c->label setFrame: - NSMakeRect(xthis, ythis-(rheight+lheight)/2, - (wthis + HSPACING) * labelp / 100 - HSPACING, - lheight)]; - if (editp == 100) { - ynext = ythis - rheight - VSPACING; - rheight = theight; - } else { - ynext = ythis; - } - - editw = (wthis + HSPACING) * editp / 100 - HSPACING; - - [edit setFrame: - NSMakeRect(xthis+wthis-editw, ynext-(rheight+theight)/2, - editw, theight)]; - - ch = (ythis - ynext) + theight; - } - break; - case CTRL_TEXT: - [c->textview setFrame:NSMakeRect(xthis, 0, wthis, 1)]; - [c->textview sizeToFit]; - rect = [c->textview frame]; - [c->textview setFrame:NSMakeRect(xthis, ythis-rect.size.height, - wthis, rect.size.height)]; - ch = rect.size.height; - break; - case CTRL_RADIO: - { - int j, ynext; - - if (c->label) { - rect = [c->label frame]; - [c->label setFrame:NSMakeRect(xthis,ythis-rect.size.height, - wthis,rect.size.height)]; - ynext = ythis - rect.size.height - VSPACING; - } else - ynext = ythis; - - for (j = 0; j < ctrl->radio.nbuttons; j++) { - int col = j % ctrl->radio.ncolumns; - int ncols; - int lx,rx; - - if (j == ctrl->radio.nbuttons - 1) - ncols = ctrl->radio.ncolumns - col; - else - ncols = 1; - - lx = (wthis + HSPACING) * col / ctrl->radio.ncolumns; - rx = ((wthis + HSPACING) * - (col+ncols) / ctrl->radio.ncolumns) - HSPACING; - - /* - * Set the frame size. - */ - rect = [c->radiobuttons[j] frame]; - [c->radiobuttons[j] setFrame: - NSMakeRect(lx+xthis, ynext-rect.size.height, - rx-lx, rect.size.height)]; - - /* - * Advance to next line if we're in the last - * column. - */ - if (col + ncols == ctrl->radio.ncolumns) - ynext -= rect.size.height + VSPACING; - } - ch = (ythis - ynext) - VSPACING; - } - break; - case CTRL_FILESELECT: - case CTRL_FONTSELECT: - { - int ynext, eh, bh, th, mx; - - rect = [c->label frame]; - [c->label setFrame:NSMakeRect(xthis,ythis-rect.size.height, - wthis,rect.size.height)]; - ynext = ythis - rect.size.height - VSPACING; - - rect = [c->editbox frame]; - eh = rect.size.height; - rect = [c->button frame]; - bh = rect.size.height; - th = (eh > bh ? eh : bh); - - mx = (wthis + HSPACING) * 3 / 4 - HSPACING; - - [c->editbox setFrame: - NSMakeRect(xthis, ynext-(th+eh)/2, mx, eh)]; - [c->button setFrame: - NSMakeRect(xthis+mx+HSPACING, ynext-(th+bh)/2, - wthis-mx-HSPACING, bh)]; - - ch = (ythis - ynext) + th + VSPACING; - } - break; - case CTRL_LISTBOX: - { - int listp = ctrl->listbox.percentwidth; - int labelp = listp == 100 ? 100 : 100 - listp; - int lheight, theight, rheight, ynext, listw, xlist; - NSControl *list = (c->scrollview ? (id)c->scrollview : - (id)c->popupbutton); - - if (ctrl->listbox.draglist) { - assert(listp == 100); - listp = 75; - } - - rect = [list frame]; - theight = rect.size.height; - - if (c->label) { - rect = [c->label frame]; - lheight = rect.size.height; - - if (labelp == 100) - rheight = lheight; - else - rheight = (lheight < theight ? theight : lheight); - - [c->label setFrame: - NSMakeRect(xthis, ythis-(rheight+lheight)/2, - (wthis + HSPACING) * labelp / 100 - HSPACING, - lheight)]; - if (labelp == 100) { - ynext = ythis - rheight - VSPACING; - rheight = theight; - } else { - ynext = ythis; - } - } else { - ynext = ythis; - rheight = theight; - } - - listw = (wthis + HSPACING) * listp / 100 - HSPACING; - - if (labelp == 100) - xlist = xthis; - else - xlist = xthis+wthis-listw; - - [list setFrame: NSMakeRect(xlist, ynext-(rheight+theight)/2, - listw, theight)]; - - /* - * Size the columns for the table view. - */ - if (c->tableview) { - int ncols, *percentages; - int hundred = 100; - int cpercent = 0, cpixels = 0; - NSArray *cols; - - if (ctrl->listbox.ncols) { - ncols = ctrl->listbox.ncols; - percentages = ctrl->listbox.percentages; - } else { - ncols = 1; - percentages = &hundred; - } - - cols = [c->tableview tableColumns]; - - for (j = 0; j < ncols; j++) { - NSTableColumn *col = [cols objectAtIndex:j]; - int newcpixels; - - cpercent += percentages[j]; - newcpixels = listw * cpercent / 100; - [col setWidth:newcpixels-cpixels]; - cpixels = newcpixels; - } - } - - ch = (ythis - ynext) + theight; - - if (c->button) { - int b2height, centre; - int bx, bw; - - /* - * Place the Up and Down buttons for a drag list. - */ - assert(c->button2); - - rect = [c->button frame]; - b2height = VSPACING + 2 * rect.size.height; - - centre = ynext - rheight/2; - - bx = (wthis + HSPACING) * 3 / 4; - bw = wthis - bx; - bx += leftx; - - [c->button setFrame: - NSMakeRect(bx, centre+b2height/2-rect.size.height, - bw, rect.size.height)]; - [c->button2 setFrame: - NSMakeRect(bx, centre-b2height/2, - bw, rect.size.height)]; - } - } - break; - } - - for (j = colstart; j < colend; j++) - cypos[j] = ythis - ch - VSPACING; - if (ret < topy - (ythis - ch)) - ret = topy - (ythis - ch); - } - - if (*s->boxname) { - NSBox *box = find_box(d, s); - assert(box != NULL); - [box sizeToFit]; - - if (s->boxtitle) { - NSRect rect = [box frame]; - rect.size.height += [[box titleFont] pointSize]; - [box setFrame:rect]; - } - - ret += boxh; - } - - //printf("For controlset %s/%s, returning ret=%d\n", - // s->pathname, s->boxname, ret); - return ret; -} - -void select_panel(void *dv, struct controlbox *b, const char *name) -{ - struct fe_dlg *d = (struct fe_dlg *)dv; - int i, j, hidden; - struct controlset *s; - union control *ctrl; - struct fe_ctrl *c; - NSBox *box; - - for (i = 0; i < b->nctrlsets; i++) { - s = b->ctrlsets[i]; - - if (*s->pathname) { - hidden = !strcmp(s->pathname, name) ? NO : YES; - - if ((box = find_box(d, s)) != NULL) { - [box setHidden:hidden]; - } else { - for (j = 0; j < s->ncontrols; j++) { - ctrl = s->ctrls[j]; - c = fe_ctrl_byctrl(d, ctrl); - - if (!c) - continue; - - if (c->label) - [c->label setHidden:hidden]; - if (c->button) - [c->button setHidden:hidden]; - if (c->button2) - [c->button2 setHidden:hidden]; - if (c->editbox) - [c->editbox setHidden:hidden]; - if (c->combobox) - [c->combobox setHidden:hidden]; - if (c->textview) - [c->textview setHidden:hidden]; - if (c->tableview) - [c->tableview setHidden:hidden]; - if (c->scrollview) - [c->scrollview setHidden:hidden]; - if (c->popupbutton) - [c->popupbutton setHidden:hidden]; - if (c->radiobuttons) { - int j; - for (j = 0; j < c->nradiobuttons; j++) - [c->radiobuttons[j] setHidden:hidden]; - } - break; - } - } - } - } -} - -void dlg_radiobutton_set(union control *ctrl, void *dv, int whichbutton) -{ - struct fe_dlg *d = (struct fe_dlg *)dv; - struct fe_ctrl *c = fe_ctrl_byctrl(d, ctrl); - int j; - - assert(c->radiobuttons); - for (j = 0; j < c->nradiobuttons; j++) - [c->radiobuttons[j] setState: - (j == whichbutton ? NSOnState : NSOffState)]; -} - -int dlg_radiobutton_get(union control *ctrl, void *dv) -{ - struct fe_dlg *d = (struct fe_dlg *)dv; - struct fe_ctrl *c = fe_ctrl_byctrl(d, ctrl); - int j; - - assert(c->radiobuttons); - for (j = 0; j < c->nradiobuttons; j++) - if ([c->radiobuttons[j] state] == NSOnState) - return j; - - return 0; /* should never reach here */ -} - -void dlg_checkbox_set(union control *ctrl, void *dv, int checked) -{ - struct fe_dlg *d = (struct fe_dlg *)dv; - struct fe_ctrl *c = fe_ctrl_byctrl(d, ctrl); - - assert(c->button); - [c->button setState:(checked ? NSOnState : NSOffState)]; -} - -int dlg_checkbox_get(union control *ctrl, void *dv) -{ - struct fe_dlg *d = (struct fe_dlg *)dv; - struct fe_ctrl *c = fe_ctrl_byctrl(d, ctrl); - - assert(c->button); - return ([c->button state] == NSOnState); -} - -void dlg_editbox_set(union control *ctrl, void *dv, char const *text) -{ - struct fe_dlg *d = (struct fe_dlg *)dv; - struct fe_ctrl *c = fe_ctrl_byctrl(d, ctrl); - - if (c->editbox) { - [c->editbox setStringValue:[NSString stringWithCString:text]]; - } else { - assert(c->combobox); - [c->combobox setStringValue:[NSString stringWithCString:text]]; - } -} - -void dlg_editbox_get(union control *ctrl, void *dv, char *buffer, int length) -{ - struct fe_dlg *d = (struct fe_dlg *)dv; - struct fe_ctrl *c = fe_ctrl_byctrl(d, ctrl); - NSString *str; - - if (c->editbox) { - str = [c->editbox stringValue]; - } else { - assert(c->combobox); - str = [c->combobox stringValue]; - } - if (!str) - str = @""; - - /* The length parameter to this method doesn't include a trailing NUL */ - [str getCString:buffer maxLength:length-1]; -} - -void dlg_listbox_clear(union control *ctrl, void *dv) -{ - struct fe_dlg *d = (struct fe_dlg *)dv; - struct fe_ctrl *c = fe_ctrl_byctrl(d, ctrl); - - if (c->tableview) { - [[c->tableview dataSource] clear]; - [c->tableview reloadData]; - } else { - [c->popupbutton removeAllItems]; - } -} - -void dlg_listbox_del(union control *ctrl, void *dv, int index) -{ - struct fe_dlg *d = (struct fe_dlg *)dv; - struct fe_ctrl *c = fe_ctrl_byctrl(d, ctrl); - - if (c->tableview) { - [[c->tableview dataSource] removestr:index]; - [c->tableview reloadData]; - } else { - [c->popupbutton removeItemAtIndex:index]; - } -} - -void dlg_listbox_addwithid(union control *ctrl, void *dv, - char const *text, int id) -{ - struct fe_dlg *d = (struct fe_dlg *)dv; - struct fe_ctrl *c = fe_ctrl_byctrl(d, ctrl); - - if (c->tableview) { - [[c->tableview dataSource] add:text withId:id]; - [c->tableview reloadData]; - } else { - [c->popupbutton addItemWithTitle:[NSString stringWithCString:text]]; - [[c->popupbutton lastItem] setTag:id]; - } -} - -void dlg_listbox_add(union control *ctrl, void *dv, char const *text) -{ - dlg_listbox_addwithid(ctrl, dv, text, -1); -} - -int dlg_listbox_getid(union control *ctrl, void *dv, int index) -{ - struct fe_dlg *d = (struct fe_dlg *)dv; - struct fe_ctrl *c = fe_ctrl_byctrl(d, ctrl); - - if (c->tableview) { - return [[c->tableview dataSource] getid:index]; - } else { - return [[c->popupbutton itemAtIndex:index] tag]; - } -} - -int dlg_listbox_index(union control *ctrl, void *dv) -{ - struct fe_dlg *d = (struct fe_dlg *)dv; - struct fe_ctrl *c = fe_ctrl_byctrl(d, ctrl); - - if (c->tableview) { - return [c->tableview selectedRow]; - } else { - return [c->popupbutton indexOfSelectedItem]; - } -} - -int dlg_listbox_issel(union control *ctrl, void *dv, int index) -{ - struct fe_dlg *d = (struct fe_dlg *)dv; - struct fe_ctrl *c = fe_ctrl_byctrl(d, ctrl); - - if (c->tableview) { - return [c->tableview isRowSelected:index]; - } else { - return [c->popupbutton indexOfSelectedItem] == index; - } -} - -void dlg_listbox_select(union control *ctrl, void *dv, int index) -{ - struct fe_dlg *d = (struct fe_dlg *)dv; - struct fe_ctrl *c = fe_ctrl_byctrl(d, ctrl); - - if (c->tableview) { - [c->tableview selectRow:index byExtendingSelection:NO]; - } else { - [c->popupbutton selectItemAtIndex:index]; - } -} - -void dlg_text_set(union control *ctrl, void *dv, char const *text) -{ - struct fe_dlg *d = (struct fe_dlg *)dv; - struct fe_ctrl *c = fe_ctrl_byctrl(d, ctrl); - - assert(c->textview); - [c->textview setString:[NSString stringWithCString:text]]; -} - -void dlg_label_change(union control *ctrl, void *dlg, char const *text) -{ - /* - * This function is currently only used by the config box to - * switch the labels on the host and port boxes between serial - * and network modes. Since OS X does not (yet?) have a serial - * back end, this function can safely do nothing for the - * moment. - */ -} - -void dlg_filesel_set(union control *ctrl, void *dv, Filename fn) -{ - /* FIXME */ -} - -void dlg_filesel_get(union control *ctrl, void *dv, Filename *fn) -{ - /* FIXME */ -} - -void dlg_fontsel_set(union control *ctrl, void *dv, FontSpec fn) -{ - /* FIXME */ -} - -void dlg_fontsel_get(union control *ctrl, void *dv, FontSpec *fn) -{ - /* FIXME */ -} - -void dlg_update_start(union control *ctrl, void *dv) -{ - /* FIXME */ -} - -void dlg_update_done(union control *ctrl, void *dv) -{ - /* FIXME */ -} - -void dlg_set_focus(union control *ctrl, void *dv) -{ - /* FIXME */ -} - -union control *dlg_last_focused(union control *ctrl, void *dv) -{ - return NULL; /* FIXME */ -} - -void dlg_beep(void *dv) -{ - NSBeep(); -} - -void dlg_error_msg(void *dv, const char *msg) -{ - /* FIXME */ -} - -void dlg_end(void *dv, int value) -{ - struct fe_dlg *d = (struct fe_dlg *)dv; - [d->target performSelector:d->action - withObject:[NSNumber numberWithInt:value]]; -} - -void dlg_coloursel_start(union control *ctrl, void *dv, - int r, int g, int b) -{ - /* FIXME */ -} - -int dlg_coloursel_results(union control *ctrl, void *dv, - int *r, int *g, int *b) -{ - return 0; /* FIXME */ -} - -void dlg_refresh(union control *ctrl, void *dv) -{ - struct fe_dlg *d = (struct fe_dlg *)dv; - struct fe_ctrl *c; - - if (ctrl) { - if (ctrl->generic.handler != NULL) - ctrl->generic.handler(ctrl, d, d->data, EVENT_REFRESH); - } else { - int i; - - for (i = 0; (c = index234(d->byctrl, i)) != NULL; i++) { - assert(c->ctrl != NULL); - if (c->ctrl->generic.handler != NULL) - c->ctrl->generic.handler(c->ctrl, d, - d->data, EVENT_REFRESH); - } - } -} diff --git a/macosx/osxdlg.m b/macosx/osxdlg.m deleted file mode 100644 index 84a761fe..00000000 --- a/macosx/osxdlg.m +++ /dev/null @@ -1,509 +0,0 @@ -/* - * osxdlg.m: various PuTTY dialog boxes for OS X. - */ - -#import -#include "putty.h" -#include "storage.h" -#include "dialog.h" -#include "osxclass.h" - -/* - * The `ConfigWindow' class is used to start up a new PuTTY - * session. - */ - -@class ConfigTree; -@interface ConfigTree : NSObject -{ - NSString **paths; - int *levels; - int nitems, itemsize; -} -- (void)addPath:(char *)path; -@end - -@implementation ConfigTree -- (id)init -{ - self = [super init]; - paths = NULL; - levels = NULL; - nitems = itemsize = 0; - return self; -} -- (void)addPath:(char *)path -{ - if (nitems >= itemsize) { - itemsize += 32; - paths = sresize(paths, itemsize, NSString *); - levels = sresize(levels, itemsize, int); - } - paths[nitems] = [[NSString stringWithCString:path] retain]; - levels[nitems] = ctrl_path_elements(path) - 1; - nitems++; -} -- (void)dealloc -{ - int i; - - for (i = 0; i < nitems; i++) - [paths[i] release]; - - sfree(paths); - sfree(levels); - - [super dealloc]; -} -- (id)iterateChildren:(int)index ofItem:(id)item count:(int *)count -{ - int i, plevel; - - if (item) { - for (i = 0; i < nitems; i++) - if (paths[i] == item) - break; - assert(i < nitems); - plevel = levels[i]; - i++; - } else { - i = 0; - plevel = -1; - } - - if (count) - *count = 0; - - while (index > 0) { - if (i >= nitems || levels[i] != plevel+1) - return nil; - if (count) - (*count)++; - do { - i++; - } while (i < nitems && levels[i] > plevel+1); - index--; - } - - return paths[i]; -} -- (id)outlineView:(NSOutlineView *)outlineView child:(int)index ofItem:(id)item -{ - return [self iterateChildren:index ofItem:item count:NULL]; -} -- (int)outlineView:(NSOutlineView *)outlineView numberOfChildrenOfItem:(id)item -{ - int count = 0; - /* pass nitems+1 to ensure we run off the end */ - [self iterateChildren:nitems+1 ofItem:item count:&count]; - return count; -} -- (BOOL)outlineView:(NSOutlineView *)outlineView isItemExpandable:(id)item -{ - return [self outlineView:outlineView numberOfChildrenOfItem:item] > 0; -} -- (id)outlineView:(NSOutlineView *)outlineView objectValueForTableColumn:(NSTableColumn *)tableColumn byItem:(id)item -{ - /* - * Trim off all path elements except the last one. - */ - NSArray *components = [item componentsSeparatedByString:@"/"]; - return [components objectAtIndex:[components count]-1]; -} -@end - -@implementation ConfigWindow -- (id)initWithConfig:(Config)aCfg -{ - NSScrollView *scrollview; - NSTableColumn *col; - ConfigTree *treedata; - int by = 0, mby = 0; - int wmin = 0; - int hmin = 0; - int panelht = 0; - - ctrlbox = ctrl_new_box(); - setup_config_box(ctrlbox, FALSE /*midsession*/, aCfg.protocol, - 0 /* protcfginfo */); - unix_setup_config_box(ctrlbox, FALSE /*midsession*/, aCfg.protocol); - - cfg = aCfg; /* structure copy */ - - self = [super initWithContentRect:NSMakeRect(0,0,300,300) - styleMask:(NSTitledWindowMask | NSMiniaturizableWindowMask | - NSClosableWindowMask) - backing:NSBackingStoreBuffered - defer:YES]; - [self setTitle:@"PuTTY Configuration"]; - - [self setIgnoresMouseEvents:NO]; - - dv = fe_dlg_init(&cfg, self, self, @selector(configBoxFinished:)); - - scrollview = [[NSScrollView alloc] initWithFrame:NSMakeRect(20,20,10,10)]; - treeview = [[NSOutlineView alloc] initWithFrame:[scrollview frame]]; - [scrollview setBorderType:NSLineBorder]; - [scrollview setDocumentView:treeview]; - [[self contentView] addSubview:scrollview]; - [scrollview setHasVerticalScroller:YES]; - [scrollview setAutohidesScrollers:YES]; - /* FIXME: the below is untested. Test it then remove this notice. */ - [treeview setAllowsColumnReordering:NO]; - [treeview setAllowsColumnResizing:NO]; - [treeview setAllowsMultipleSelection:NO]; - [treeview setAllowsEmptySelection:NO]; - [treeview setAllowsColumnSelection:YES]; - - treedata = [[[ConfigTree alloc] init] retain]; - - col = [[NSTableColumn alloc] initWithIdentifier:nil]; - [treeview addTableColumn:col]; - [treeview setOutlineTableColumn:col]; - - [[treeview headerView] setFrame:NSMakeRect(0,0,0,0)]; - - /* - * Create the controls. - */ - { - int i; - char *path = NULL; - - for (i = 0; i < ctrlbox->nctrlsets; i++) { - struct controlset *s = ctrlbox->ctrlsets[i]; - int mw, mh; - - if (!*s->pathname) { - - create_ctrls(dv, [self contentView], s, &mw, &mh); - - by += 20 + mh; - - if (wmin < mw + 40) - wmin = mw + 40; - } else { - int j = path ? ctrl_path_compare(s->pathname, path) : 0; - - if (j != INT_MAX) { /* add to treeview, start new panel */ - char *c; - - /* - * We expect never to find an implicit path - * component. For example, we expect never to - * see A/B/C followed by A/D/E, because that - * would _implicitly_ create A/D. All our path - * prefixes are expected to contain actual - * controls and be selectable in the treeview; - * so we would expect to see A/D _explicitly_ - * before encountering A/D/E. - */ - assert(j == ctrl_path_elements(s->pathname) - 1); - - c = strrchr(s->pathname, '/'); - if (!c) - c = s->pathname; - else - c++; - - [treedata addPath:s->pathname]; - path = s->pathname; - - panelht = 0; - } - - create_ctrls(dv, [self contentView], s, &mw, &mh); - if (wmin < mw + 3*20+150) - wmin = mw + 3*20+150; - panelht += mh + 20; - if (hmin < panelht - 20) - hmin = panelht - 20; - } - } - } - - { - int i; - NSRect r; - - [treeview setDataSource:treedata]; - for (i = [treeview numberOfRows]; i-- ;) - [treeview expandItem:[treeview itemAtRow:i] expandChildren:YES]; - - [treeview sizeToFit]; - r = [treeview frame]; - if (hmin < r.size.height) - hmin = r.size.height; - } - - [self setContentSize:NSMakeSize(wmin, hmin+60+by)]; - [scrollview setFrame:NSMakeRect(20, 40+by, 150, hmin)]; - [treeview setDelegate:self]; - mby = by; - - /* - * Now place the controls. - */ - { - int i; - char *path = NULL; - panelht = 0; - - for (i = 0; i < ctrlbox->nctrlsets; i++) { - struct controlset *s = ctrlbox->ctrlsets[i]; - - if (!*s->pathname) { - by -= VSPACING + place_ctrls(dv, s, 20, by, wmin-40); - } else { - if (!path || strcmp(s->pathname, path)) - panelht = 0; - - panelht += VSPACING + place_ctrls(dv, s, 2*20+150, - 40+mby+hmin-panelht, - wmin - (3*20+150)); - - path = s->pathname; - } - } - } - - select_panel(dv, ctrlbox, [[treeview itemAtRow:0] cString]); - - [treeview reloadData]; - - dlg_refresh(NULL, dv); - - [self center]; /* :-) */ - - return self; -} -- (void)configBoxFinished:(id)object -{ - int ret = [object intValue]; /* it'll be an NSNumber */ - if (ret) { - [controller performSelectorOnMainThread: - @selector(newSessionWithConfig:) - withObject:[NSData dataWithBytes:&cfg length:sizeof(cfg)] - waitUntilDone:NO]; - } - [self close]; -} -- (void)outlineViewSelectionDidChange:(NSNotification *)notification -{ - const char *path = [[treeview itemAtRow:[treeview selectedRow]] cString]; - select_panel(dv, ctrlbox, path); -} -- (BOOL)outlineView:(NSOutlineView *)outlineView - shouldEditTableColumn:(NSTableColumn *)tableColumn item:(id)item -{ - return NO; /* no editing! */ -} -@end - -/* ---------------------------------------------------------------------- - * Various special-purpose dialog boxes. - */ - -struct appendstate { - void (*callback)(void *ctx, int result); - void *ctx; -}; - -static void askappend_callback(void *ctx, int result) -{ - struct appendstate *state = (struct appendstate *)ctx; - - state->callback(state->ctx, (result == NSAlertFirstButtonReturn ? 2 : - result == NSAlertSecondButtonReturn ? 1 : 0)); - sfree(state); -} - -int askappend(void *frontend, Filename filename, - void (*callback)(void *ctx, int result), void *ctx) -{ - static const char msgtemplate[] = - "The session log file \"%s\" already exists. " - "You can overwrite it with a new session log, " - "append your session log to the end of it, " - "or disable session logging for this session."; - - char *text; - SessionWindow *win = (SessionWindow *)frontend; - struct appendstate *state; - NSAlert *alert; - - text = dupprintf(msgtemplate, filename.path); - - state = snew(struct appendstate); - state->callback = callback; - state->ctx = ctx; - - alert = [[NSAlert alloc] init]; - [alert setInformativeText:[NSString stringWithCString:text]]; - [alert addButtonWithTitle:@"Overwrite"]; - [alert addButtonWithTitle:@"Append"]; - [alert addButtonWithTitle:@"Disable"]; - [win startAlert:alert withCallback:askappend_callback andCtx:state]; - - return -1; -} - -struct algstate { - void (*callback)(void *ctx, int result); - void *ctx; -}; - -static void askalg_callback(void *ctx, int result) -{ - struct algstate *state = (struct algstate *)ctx; - - state->callback(state->ctx, result == NSAlertFirstButtonReturn); - sfree(state); -} - -int askalg(void *frontend, const char *algtype, const char *algname, - void (*callback)(void *ctx, int result), void *ctx) -{ - static const char msg[] = - "The first %s supported by the server is " - "%s, which is below the configured warning threshold.\n" - "Continue with connection?"; - - char *text; - SessionWindow *win = (SessionWindow *)frontend; - struct algstate *state; - NSAlert *alert; - - text = dupprintf(msg, algtype, algname); - - state = snew(struct algstate); - state->callback = callback; - state->ctx = ctx; - - alert = [[NSAlert alloc] init]; - [alert setInformativeText:[NSString stringWithCString:text]]; - [alert addButtonWithTitle:@"Yes"]; - [alert addButtonWithTitle:@"No"]; - [win startAlert:alert withCallback:askalg_callback andCtx:state]; - - return -1; -} - -struct hostkeystate { - char *host, *keytype, *keystr; - int port; - void (*callback)(void *ctx, int result); - void *ctx; -}; - -static void verify_ssh_host_key_callback(void *ctx, int result) -{ - struct hostkeystate *state = (struct hostkeystate *)ctx; - - if (result == NSAlertThirdButtonReturn) /* `Accept' */ - store_host_key(state->host, state->port, - state->keytype, state->keystr); - state->callback(state->ctx, result != NSAlertFirstButtonReturn); - sfree(state->host); - sfree(state->keytype); - sfree(state->keystr); - sfree(state); -} - -int verify_ssh_host_key(void *frontend, char *host, int port, - const char *keytype, char *keystr, char *fingerprint, - void (*callback)(void *ctx, int result), void *ctx) -{ - static const char absenttxt[] = - "The server's host key is not cached. You have no guarantee " - "that the server is the computer you think it is.\n" - "The server's %s key fingerprint is:\n" - "%s\n" - "If you trust this host, press \"Accept\" to add the key to " - "PuTTY's cache and carry on connecting.\n" - "If you want to carry on connecting just once, without " - "adding the key to the cache, press \"Connect Once\".\n" - "If you do not trust this host, press \"Cancel\" to abandon the " - "connection."; - static const char wrongtxt[] = - "WARNING - POTENTIAL SECURITY BREACH!\n" - "The server's host key does not match the one PuTTY has " - "cached. This means that either the server administrator " - "has changed the host key, or you have actually connected " - "to another computer pretending to be the server.\n" - "The new %s key fingerprint is:\n" - "%s\n" - "If you were expecting this change and trust the new key, " - "press \"Accept\" to update PuTTY's cache and continue connecting.\n" - "If you want to carry on connecting but without updating " - "the cache, press \"Connect Once\".\n" - "If you want to abandon the connection completely, press " - "\"Cancel\" to cancel. Pressing \"Cancel\" is the ONLY guaranteed " - "safe choice."; - - int ret; - char *text; - SessionWindow *win = (SessionWindow *)frontend; - struct hostkeystate *state; - NSAlert *alert; - - /* - * Verify the key. - */ - ret = verify_host_key(host, port, keytype, keystr); - - if (ret == 0) - return 1; - - text = dupprintf((ret == 2 ? wrongtxt : absenttxt), keytype, fingerprint); - - state = snew(struct hostkeystate); - state->callback = callback; - state->ctx = ctx; - state->host = dupstr(host); - state->port = port; - state->keytype = dupstr(keytype); - state->keystr = dupstr(keystr); - - alert = [[NSAlert alloc] init]; - [alert setInformativeText:[NSString stringWithCString:text]]; - [alert addButtonWithTitle:@"Cancel"]; - [alert addButtonWithTitle:@"Connect Once"]; - [alert addButtonWithTitle:@"Accept"]; - [win startAlert:alert withCallback:verify_ssh_host_key_callback - andCtx:state]; - - return -1; -} - -void old_keyfile_warning(void) -{ - /* - * This should never happen on OS X. We hope. - */ -} - -static void connection_fatal_callback(void *ctx, int result) -{ - SessionWindow *win = (SessionWindow *)ctx; - - [win endSession:FALSE]; -} - -void connection_fatal(void *frontend, const char *p, ...) -{ - SessionWindow *win = (SessionWindow *)frontend; - va_list ap; - char *msg; - NSAlert *alert; - - va_start(ap, p); - msg = dupvprintf(p, ap); - va_end(ap); - - alert = [[NSAlert alloc] init]; - [alert setInformativeText:[NSString stringWithCString:msg]]; - [alert addButtonWithTitle:@"Proceed"]; - [win startAlert:alert withCallback:connection_fatal_callback - andCtx:win]; -} diff --git a/macosx/osxmain.m b/macosx/osxmain.m deleted file mode 100644 index 2ac772a8..00000000 --- a/macosx/osxmain.m +++ /dev/null @@ -1,426 +0,0 @@ -/* - * osxmain.m: main-program file of Mac OS X PuTTY. - */ - -#import - -#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(const 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, const 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(const char *p, ...) -{ - va_list ap; - va_start(ap, p); - commonfatalbox(p, ap); - va_end(ap); -} - -void modalfatalbox(const char *p, ...) -{ - va_list ap; - va_start(ap, p); - commonfatalbox(p, ap); - va_end(ap); -} - -void cmdline_error(const 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; -} diff --git a/macosx/osxsel.m b/macosx/osxsel.m deleted file mode 100644 index eac60282..00000000 --- a/macosx/osxsel.m +++ /dev/null @@ -1,308 +0,0 @@ -/* - * osxsel.m: OS X implementation of the front end interface to uxsel. - */ - -#import -#include -#include "putty.h" -#include "osxclass.h" - -/* - * The unofficial Cocoa FAQ at - * - * http://www.alastairs-place.net/cocoa/faq.txt - * - * says that Cocoa has the native ability to be given an fd and - * tell you when it becomes readable, but cannot tell you when it - * becomes _writable_. This is unacceptable to PuTTY, which depends - * for correct functioning on being told both. Therefore, I can't - * use the Cocoa native mechanism. - * - * Instead, I'm going to resort to threads. I start a second thread - * whose job is to do selects. At the termination of every select, - * it posts a Cocoa event into the main thread's event queue, so - * that the main thread gets select results interleaved with other - * GUI operations. Communication from the main thread _to_ the - * select thread is performed by writing to a pipe whose other end - * is one of the file descriptors being selected on. (This is the - * only sensible way, because we have to be able to interrupt a - * select in order to provide a new fd list.) - */ - -/* - * In more detail, the select thread must: - * - * - start off by listening to _just_ the pipe, waiting to be told - * to begin a select. - * - * - when it receives the `start' command, it should read the - * shared uxsel data (which is protected by a mutex), set up its - * select, and begin it. - * - * - when the select terminates, it should write the results - * (perhaps minus the inter-thread pipe if it's there) into - * shared memory and dispatch a GUI event to let the main thread - * know. - * - * - the main thread will then think about it, do some processing, - * and _then_ send a command saying `now restart select'. Before - * sending that command it might easily have tinkered with the - * uxsel structures, which is why it waited before sending it. - * - * - EOF on the inter-thread pipe, of course, means the process - * has finished completely, so the select thread terminates. - * - * - The main thread may wish to adjust the uxsel settings in the - * middle of a select. In this situation it first writes the new - * data to the shared memory area, then notifies the select - * thread by writing to the inter-thread pipe. - * - * So the upshot is that the sequence of operations performed in - * the select thread must be: - * - * - read a byte from the pipe (which may block) - * - * - read the shared uxsel data and perform a select - * - * - notify the main thread of interesting select results (if any) - * - * - loop round again from the top. - * - * This is sufficient. Notifying the select thread asynchronously - * by writing to the pipe will cause its select to terminate and - * another to begin immediately without blocking. If the select - * thread's select terminates due to network data, its subsequent - * pipe read will block until the main thread is ready to let it - * loose again. - */ - -static int osxsel_pipe[2]; - -static NSLock *osxsel_inlock; -static fd_set osxsel_rfds_in; -static fd_set osxsel_wfds_in; -static fd_set osxsel_xfds_in; -static int osxsel_inmax; - -static NSLock *osxsel_outlock; -static fd_set osxsel_rfds_out; -static fd_set osxsel_wfds_out; -static fd_set osxsel_xfds_out; -static int osxsel_outmax; - -static int inhibit_start_select; - -/* - * NSThread requires an object method as its thread procedure, so - * here I define a trivial holding class. - */ -@class OSXSel; -@interface OSXSel : NSObject -{ -} -- (void)runThread:(id)arg; -@end -@implementation OSXSel -- (void)runThread:(id)arg -{ - char c; - fd_set r, w, x; - int n, ret; - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - - while (1) { - /* - * Read one byte from the pipe. - */ - ret = read(osxsel_pipe[0], &c, 1); - - if (ret <= 0) - return; /* terminate the thread */ - - /* - * Now set up the select data. - */ - [osxsel_inlock lock]; - memcpy(&r, &osxsel_rfds_in, sizeof(fd_set)); - memcpy(&w, &osxsel_wfds_in, sizeof(fd_set)); - memcpy(&x, &osxsel_xfds_in, sizeof(fd_set)); - n = osxsel_inmax; - [osxsel_inlock unlock]; - FD_SET(osxsel_pipe[0], &r); - if (n < osxsel_pipe[0]+1) - n = osxsel_pipe[0]+1; - - /* - * Perform the select. - */ - ret = select(n, &r, &w, &x, NULL); - - /* - * Detect the one special case in which the only - * interesting fd was the inter-thread pipe. In that - * situation only we are interested - the main thread will - * not be! - */ - if (ret == 1 && FD_ISSET(osxsel_pipe[0], &r)) - continue; /* just loop round again */ - - /* - * Write the select results to shared data. - * - * I _think_ we don't need this data to be lock-protected: - * it won't be read by the main thread until after we send - * a message indicating that we've finished writing it, and - * we won't start another select (hence potentially writing - * it again) until the main thread notifies us in return. - * - * However, I'm scared of multithreading and not totally - * convinced of my reasoning, so I'm going to lock it - * anyway. - */ - [osxsel_outlock lock]; - memcpy(&osxsel_rfds_out, &r, sizeof(fd_set)); - memcpy(&osxsel_wfds_out, &w, sizeof(fd_set)); - memcpy(&osxsel_xfds_out, &x, sizeof(fd_set)); - osxsel_outmax = n; - [osxsel_outlock unlock]; - - /* - * Post a message to the main thread's message queue - * telling it that select data is available. - */ - [NSApp postEvent:[NSEvent otherEventWithType:NSApplicationDefined - location:NSMakePoint(0,0) - modifierFlags:0 - timestamp:0 - windowNumber:0 - context:nil - subtype:0 - data1:0 - data2:0] - atStart:NO]; - } - - [pool release]; -} -@end - -void osxsel_init(void) -{ - uxsel_init(); - - if (pipe(osxsel_pipe) < 0) { - fatalbox("Unable to set up inter-thread pipe for select"); - } - [NSThread detachNewThreadSelector:@selector(runThread:) - toTarget:[[[OSXSel alloc] init] retain] withObject:nil]; - /* - * Also initialise (i.e. clear) the input fd_sets. Need not - * start a select just yet - the select thread will block until - * we have at least one fd for it! - */ - FD_ZERO(&osxsel_rfds_in); - FD_ZERO(&osxsel_wfds_in); - FD_ZERO(&osxsel_xfds_in); - osxsel_inmax = 0; - /* - * Initialise the mutex locks used to protect the data passed - * between threads. - */ - osxsel_inlock = [[[NSLock alloc] init] retain]; - osxsel_outlock = [[[NSLock alloc] init] retain]; -} - -static void osxsel_start_select(void) -{ - char c = 'g'; /* for `Go!' :-) but it's never used */ - - if (!inhibit_start_select) - write(osxsel_pipe[1], &c, 1); -} - -int uxsel_input_add(int fd, int rwx) -{ - /* - * Add the new fd to the appropriate input fd_sets, then write - * to the inter-thread pipe. - */ - [osxsel_inlock lock]; - if (rwx & 1) - FD_SET(fd, &osxsel_rfds_in); - else - FD_CLR(fd, &osxsel_rfds_in); - if (rwx & 2) - FD_SET(fd, &osxsel_wfds_in); - else - FD_CLR(fd, &osxsel_wfds_in); - if (rwx & 4) - FD_SET(fd, &osxsel_xfds_in); - else - FD_CLR(fd, &osxsel_xfds_in); - if (osxsel_inmax < fd+1) - osxsel_inmax = fd+1; - [osxsel_inlock unlock]; - osxsel_start_select(); - - /* - * We must return an `id' which will be passed back to us at - * the time of uxsel_input_remove. Since we have no need to - * store ids in that sense, we might as well go with the fd - * itself. - */ - return fd; -} - -void uxsel_input_remove(int id) -{ - /* - * Remove the fd from all the input fd_sets. In this - * implementation, the simplest way to do that is to call - * uxsel_input_add with rwx==0! - */ - uxsel_input_add(id, 0); -} - -/* - * Function called in the main thread to process results. It will - * have to read the output fd_sets, go through them, call back to - * uxsel with the results, and then write to the inter-thread pipe. - * - * This function will have to be called from an event handler in - * osxmain.m, which will therefore necessarily contain a small part - * of this mechanism (along with calling osxsel_init). - */ -void osxsel_process_results(void) -{ - int i; - - /* - * We must write to the pipe to start a fresh select _even if_ - * there were no changes. So for efficiency, we set a flag here - * which inhibits uxsel_input_{add,remove} from writing to the - * pipe; then once we finish processing, we clear the flag - * again and write a single byte ourselves. It's cleaner, - * because it wakes up the select thread fewer times. - */ - inhibit_start_select = TRUE; - - [osxsel_outlock lock]; - - for (i = 0; i < osxsel_outmax; i++) { - if (FD_ISSET(i, &osxsel_xfds_out)) - select_result(i, 4); - } - for (i = 0; i < osxsel_outmax; i++) { - if (FD_ISSET(i, &osxsel_rfds_out)) - select_result(i, 1); - } - for (i = 0; i < osxsel_outmax; i++) { - if (FD_ISSET(i, &osxsel_wfds_out)) - select_result(i, 2); - } - - [osxsel_outlock unlock]; - - inhibit_start_select = FALSE; - osxsel_start_select(); -} diff --git a/macosx/osxwin.m b/macosx/osxwin.m deleted file mode 100644 index 06291369..00000000 --- a/macosx/osxwin.m +++ /dev/null @@ -1,1227 +0,0 @@ -/* - * osxwin.m: code to manage a session window in Mac OS X PuTTY. - */ - -#import -#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_style & 2) && (attr & ATTR_BOLD)) { - if (nfg < 16) nfg |= 8; - else if (nfg >= 256) nfg |= 1; - } - if ((cfg.bold_style & 2) && (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 if cfg.bold_style & 1 */ - - 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. - */ - back = backend_from_proto(cfg.protocol); - if (!back) - back = &pty_backend; - - { - 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'; - use_coutput = TRUE; - end = 2; - special = TRUE; - } - - /* Control-Shift-Space is 160 (ISO8859 nonbreaking space) */ - if (n == 1 && (m & NSControlKeyMask) && (m & NSShiftKeyMask) && - cm == ' ') { - output[1] = '\240'; - end = 2; - } - - /* Control-2, Control-Space and Control-@ are all NUL. */ - if ((m & NSControlKeyMask) && n == 1 && - (cm == '2' || cm == '@' || cm == ' ') && c == cm) { - output[1] = '\0'; - end = 2; - } - - /* We don't let MacOS tell us what Backspace is! We know better. */ - if (cm == 0x7F && !(m & NSShiftKeyMask)) { - coutput[1] = cfg.bksp_is_delete ? '\x7F' : '\x08'; - end = 2; - use_coutput = special = TRUE; - } - /* For Shift Backspace, do opposite of what is configured. */ - if (cm == 0x7F && (m & NSShiftKeyMask)) { - coutput[1] = cfg.bksp_is_delete ? '\x08' : '\x7F'; - end = 2; - use_coutput = special = TRUE; - } - - /* Shift-Tab is ESC [ Z. Oddly, this combination generates ^Y by - * default on MacOS! */ - if (cm == 0x19 && (m & NSShiftKeyMask) && !(m & NSControlKeyMask)) { - end = 1; - output[end++] = '\033'; - output[end++] = '['; - output[end++] = 'Z'; - } - - /* - * NetHack keypad mode. - */ - if (cfg.nethack_keypad && (m & NSNumericPadKeyMask)) { - wchar_t *keys = NULL; - switch (cm) { - case '1': keys = L"bB"; break; - case '2': keys = L"jJ"; break; - case '3': keys = L"nN"; break; - case '4': keys = L"hH"; break; - case '5': keys = L".."; break; - case '6': keys = L"lL"; break; - case '7': keys = L"yY"; break; - case '8': keys = L"kK"; break; - case '9': keys = L"uU"; break; - } - if (keys) { - end = 2; - if (m & NSShiftKeyMask) - output[1] = keys[1]; - else - output[1] = keys[0]; - goto done; - } - } - - /* - * Application keypad mode. - */ - if (term->app_keypad_keys && !cfg.no_applic_k && - (m & NSNumericPadKeyMask)) { - int xkey = 0; - switch (cm) { - case NSClearLineFunctionKey: xkey = 'P'; break; - case '=': xkey = 'Q'; break; - case '/': xkey = 'R'; break; - case '*': xkey = 'S'; break; - /* - * FIXME: keypad - and + need to be mapped to ESC O l - * and ESC O k, or ESC O l and ESC O m, depending on - * xterm function key mode, and I can't remember which - * goes where. - */ - case '\003': xkey = 'M'; break; - case '0': xkey = 'p'; break; - case '1': xkey = 'q'; break; - case '2': xkey = 'r'; break; - case '3': xkey = 's'; break; - case '4': xkey = 't'; break; - case '5': xkey = 'u'; break; - case '6': xkey = 'v'; break; - case '7': xkey = 'w'; break; - case '8': xkey = 'x'; break; - case '9': xkey = 'y'; break; - case '.': xkey = 'n'; break; - } - if (xkey) { - if (term->vt52_mode) { - if (xkey >= 'P' && xkey <= 'S') { - output[end++] = '\033'; - output[end++] = xkey; - } else { - output[end++] = '\033'; - output[end++] = '?'; - output[end++] = xkey; - } - } else { - output[end++] = '\033'; - output[end++] = 'O'; - output[end++] = xkey; - } - goto done; - } - } - - /* - * Next, all the keys that do tilde codes. (ESC '[' nn '~', - * for integer decimal nn.) - * - * We also deal with the weird ones here. Linux VCs replace F1 - * to F5 by ESC [ [ A to ESC [ [ E. rxvt doesn't do _that_, but - * does replace Home and End (1~ and 4~) by ESC [ H and ESC O w - * respectively. - */ - { - int code = 0; - switch (cm) { - case NSF1FunctionKey: - code = (m & NSShiftKeyMask ? 23 : 11); - break; - case NSF2FunctionKey: - code = (m & NSShiftKeyMask ? 24 : 12); - break; - case NSF3FunctionKey: - code = (m & NSShiftKeyMask ? 25 : 13); - break; - case NSF4FunctionKey: - code = (m & NSShiftKeyMask ? 26 : 14); - break; - case NSF5FunctionKey: - code = (m & NSShiftKeyMask ? 28 : 15); - break; - case NSF6FunctionKey: - code = (m & NSShiftKeyMask ? 29 : 17); - break; - case NSF7FunctionKey: - code = (m & NSShiftKeyMask ? 31 : 18); - break; - case NSF8FunctionKey: - code = (m & NSShiftKeyMask ? 32 : 19); - break; - case NSF9FunctionKey: - code = (m & NSShiftKeyMask ? 33 : 20); - break; - case NSF10FunctionKey: - code = (m & NSShiftKeyMask ? 34 : 21); - break; - case NSF11FunctionKey: - code = 23; - break; - case NSF12FunctionKey: - code = 24; - break; - case NSF13FunctionKey: - code = 25; - break; - case NSF14FunctionKey: - code = 26; - break; - case NSF15FunctionKey: - code = 28; - break; - case NSF16FunctionKey: - code = 29; - break; - case NSF17FunctionKey: - code = 31; - break; - case NSF18FunctionKey: - code = 32; - break; - case NSF19FunctionKey: - code = 33; - break; - case NSF20FunctionKey: - code = 34; - break; - } - if (!(m & NSControlKeyMask)) switch (cm) { - case NSHomeFunctionKey: - code = 1; - break; -#ifdef FIXME - case GDK_Insert: case GDK_KP_Insert: - code = 2; - break; -#endif - case NSDeleteFunctionKey: - code = 3; - break; - case NSEndFunctionKey: - code = 4; - break; - case NSPageUpFunctionKey: - code = 5; - break; - case NSPageDownFunctionKey: - code = 6; - break; - } - /* Reorder edit keys to physical order */ - if (cfg.funky_type == FUNKY_VT400 && code <= 6) - code = "\0\2\1\4\5\3\6"[code]; - - if (term->vt52_mode && code > 0 && code <= 6) { - output[end++] = '\033'; - output[end++] = " HLMEIG"[code]; - goto done; - } - - if (cfg.funky_type == FUNKY_SCO && /* SCO function keys */ - code >= 11 && code <= 34) { - char codes[] = "MNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz@[\\]^_`{"; - int index = 0; - switch (cm) { - case NSF1FunctionKey: index = 0; break; - case NSF2FunctionKey: index = 1; break; - case NSF3FunctionKey: index = 2; break; - case NSF4FunctionKey: index = 3; break; - case NSF5FunctionKey: index = 4; break; - case NSF6FunctionKey: index = 5; break; - case NSF7FunctionKey: index = 6; break; - case NSF8FunctionKey: index = 7; break; - case NSF9FunctionKey: index = 8; break; - case NSF10FunctionKey: index = 9; break; - case NSF11FunctionKey: index = 10; break; - case NSF12FunctionKey: index = 11; break; - } - if (m & NSShiftKeyMask) index += 12; - if (m & NSControlKeyMask) index += 24; - output[end++] = '\033'; - output[end++] = '['; - output[end++] = codes[index]; - goto done; - } - if (cfg.funky_type == FUNKY_SCO && /* SCO small keypad */ - code >= 1 && code <= 6) { - char codes[] = "HL.FIG"; - if (code == 3) { - output[1] = '\x7F'; - end = 2; - } else { - output[end++] = '\033'; - output[end++] = '['; - output[end++] = codes[code-1]; - } - goto done; - } - if ((term->vt52_mode || cfg.funky_type == FUNKY_VT100P) && - code >= 11 && code <= 24) { - int offt = 0; - if (code > 15) - offt++; - if (code > 21) - offt++; - if (term->vt52_mode) { - output[end++] = '\033'; - output[end++] = code + 'P' - 11 - offt; - } else { - output[end++] = '\033'; - output[end++] = 'O'; - output[end++] = code + 'P' - 11 - offt; - } - goto done; - } - if (cfg.funky_type == FUNKY_LINUX && code >= 11 && code <= 15) { - output[end++] = '\033'; - output[end++] = '['; - output[end++] = '['; - output[end++] = code + 'A' - 11; - goto done; - } - if (cfg.funky_type == FUNKY_XTERM && code >= 11 && code <= 14) { - if (term->vt52_mode) { - output[end++] = '\033'; - output[end++] = code + 'P' - 11; - } else { - output[end++] = '\033'; - output[end++] = 'O'; - output[end++] = code + 'P' - 11; - } - goto done; - } - if (cfg.rxvt_homeend && (code == 1 || code == 4)) { - if (code == 1) { - output[end++] = '\033'; - output[end++] = '['; - output[end++] = 'H'; - } else { - output[end++] = '\033'; - output[end++] = 'O'; - output[end++] = 'w'; - } - goto done; - } - if (code) { - char buf[20]; - sprintf(buf, "\x1B[%d~", code); - for (i = 0; buf[i]; i++) - output[end++] = buf[i]; - goto done; - } - } - - /* - * Cursor keys. (This includes the numberpad cursor keys, - * if we haven't already done them due to app keypad mode.) - */ - { - int xkey = 0; - switch (cm) { - case NSUpArrowFunctionKey: xkey = 'A'; break; - case NSDownArrowFunctionKey: xkey = 'B'; break; - case NSRightArrowFunctionKey: xkey = 'C'; break; - case NSLeftArrowFunctionKey: xkey = 'D'; break; - } - if (xkey) { - end += format_arrow_key(output+end, term, xkey, - m & NSControlKeyMask); - goto done; - } - } - - done: - - /* - * Failing everything else, send the exact Unicode we got from - * OS X. - */ - if (end == start) { - if (n > lenof(output)-start) - n = lenof(output)-start; /* _shouldn't_ happen! */ - for (i = 0; i < n; i++) { - output[i+start] = [s characterAtIndex:i]; - } - end = n+start; - } - - if (use_coutput) { - assert(special); - assert(end < lenof(coutput)); - coutput[end] = '\0'; - ldisc_send(ldisc, coutput+start, -2, TRUE); - } else { - luni_send(ldisc, output+start, end-start, TRUE); - } -} - -- (int)fromBackend:(const char *)data len:(int)len isStderr:(int)is_stderr -{ - return term_data(term, is_stderr, data, len); -} - -- (int)fromBackendUntrusted:(const char *)data len:(int)len -{ - return term_data_untrusted(term, data, len); -} - -- (void)startAlert:(NSAlert *)alert - withCallback:(void (*)(void *, int))callback andCtx:(void *)ctx -{ - if (alert_ctx || alert_qhead) { - /* - * Queue this alert to be shown later. - */ - struct alert_queue *qitem = snew(struct alert_queue); - qitem->next = NULL; - qitem->alert = alert; - qitem->callback = callback; - qitem->ctx = ctx; - if (alert_qtail) - alert_qtail->next = qitem; - else - alert_qhead = qitem; - alert_qtail = qitem; - } else { - alert_callback = callback; - alert_ctx = ctx; /* NB this is assumed to need freeing! */ - [alert beginSheetModalForWindow:self modalDelegate:self - didEndSelector:@selector(alertSheetDidEnd:returnCode:contextInfo:) - contextInfo:NULL]; - } -} - -- (void)alertSheetDidEnd:(NSAlert *)alert returnCode:(int)returnCode - contextInfo:(void *)contextInfo -{ - [self performSelectorOnMainThread: - @selector(alertSheetDidFinishEnding:) - withObject:[NSNumber numberWithInt:returnCode] - waitUntilDone:NO]; -} - -- (void)alertSheetDidFinishEnding:(id)object -{ - int returnCode = [object intValue]; - - alert_callback(alert_ctx, returnCode); /* transfers ownership of ctx */ - - /* - * If there's an alert in our queue (either already or because - * the callback just queued it), start it. - */ - if (alert_qhead) { - struct alert_queue *qnext; - - alert_callback = alert_qhead->callback; - alert_ctx = alert_qhead->ctx; - [alert_qhead->alert beginSheetModalForWindow:self modalDelegate:self - didEndSelector:@selector(alertSheetDidEnd:returnCode:contextInfo:) - contextInfo:NULL]; - - qnext = alert_qhead->next; - sfree(alert_qhead); - alert_qhead = qnext; - if (!qnext) - alert_qtail = NULL; - } else { - alert_ctx = NULL; - } -} - -- (void)notifyRemoteExit -{ - int exitcode; - - if (!exited && (exitcode = back->exitcode(backhandle)) >= 0) - [self endSession:(exitcode == 0)]; -} - -- (void)endSession:(int)clean -{ - exited = TRUE; - if (ldisc) { - ldisc_free(ldisc); - ldisc = NULL; - } - if (back) { - back->free(backhandle); - backhandle = NULL; - back = NULL; - //FIXME: update specials menu; - } - if (cfg.close_on_exit == FORCE_ON || - (cfg.close_on_exit == AUTO && clean)) - [self close]; - // FIXME: else show restart menu item -} - -- (Terminal *)term -{ - return term; -} - -@end - -int from_backend(void *frontend, int is_stderr, const char *data, int len) -{ - SessionWindow *win = (SessionWindow *)frontend; - return [win fromBackend:data len:len isStderr:is_stderr]; -} - -int from_backend_untrusted(void *frontend, const char *data, int len) -{ - SessionWindow *win = (SessionWindow *)frontend; - return [win fromBackendUntrusted:data len:len]; -} - -int get_userpass_input(prompts_t *p, const unsigned char *in, int inlen) -{ - SessionWindow *win = (SessionWindow *)p->frontend; - Terminal *term = [win term]; - return term_get_userpass_input(term, p, in, inlen); -} - -void frontend_keypress(void *handle) -{ - /* FIXME */ -} - -void notify_remote_exit(void *frontend) -{ - SessionWindow *win = (SessionWindow *)frontend; - - [win notifyRemoteExit]; -} - -void frontend_echoedit_update(void *frontend, int echo, int edit) -{ - //SessionWindow *win = (SessionWindow *)frontend; - /* - * In a GUI front end, this need do nothing. - */ -} - -char *get_ttymode(void *frontend, const char *mode) -{ - SessionWindow *win = (SessionWindow *)frontend; - Terminal *term = [win term]; - return term_get_ttymode(term, mode); -} - -void update_specials_menu(void *frontend) -{ - //SessionWindow *win = (SessionWindow *)frontend; - /* FIXME */ -} - -/* - * This is still called when mode==BELL_VISUAL, even though the - * visual bell is handled entirely within terminal.c, because we - * may want to perform additional actions on any kind of bell (for - * example, taskbar flashing in Windows). - */ -void do_beep(void *frontend, int mode) -{ - //SessionWindow *win = (SessionWindow *)frontend; - if (mode != BELL_VISUAL) - NSBeep(); -} - -int char_width(Context ctx, int uc) -{ - /* - * Under X, any fixed-width font really _is_ fixed-width. - * Double-width characters will be dealt with using a separate - * font. For the moment we can simply return 1. - */ - return 1; -} - -void palette_set(void *frontend, int n, int r, int g, int b) -{ - SessionWindow *win = (SessionWindow *)frontend; - - if (n >= 16) - n += 256 - 16; - if (n >= NALLCOLOURS) - return; - [win setColour:n r:r/255.0 g:g/255.0 b:b/255.0]; - - /* - * FIXME: do we need an OS X equivalent of set_window_background? - */ -} - -void palette_reset(void *frontend) -{ - SessionWindow *win = (SessionWindow *)frontend; - Config *cfg = [win cfg]; - - /* This maps colour indices in cfg to those used in colours[]. */ - static const int ww[] = { - 256, 257, 258, 259, 260, 261, - 0, 8, 1, 9, 2, 10, 3, 11, - 4, 12, 5, 13, 6, 14, 7, 15 - }; - - int i; - - for (i = 0; i < NCFGCOLOURS; i++) { - [win setColour:ww[i] r:cfg->colours[i][0]/255.0 - g:cfg->colours[i][1]/255.0 b:cfg->colours[i][2]/255.0]; - } - - for (i = 0; i < NEXTCOLOURS; i++) { - if (i < 216) { - int r = i / 36, g = (i / 6) % 6, b = i % 6; - r = r ? r*40+55 : 0; g = g ? b*40+55 : 0; b = b ? b*40+55 : 0; - [win setColour:i+16 r:r/255.0 g:g/255.0 b:b/255.0]; - } else { - int shade = i - 216; - float fshade = (shade * 10 + 8) / 255.0; - [win setColour:i+16 r:fshade g:fshade b:fshade]; - } - } - - /* - * FIXME: do we need an OS X equivalent of set_window_background? - */ -} - -Context get_ctx(void *frontend) -{ - SessionWindow *win = (SessionWindow *)frontend; - - /* - * Lock the drawing focus on the image inside the TerminalView. - */ - [win drawStartFinish:YES]; - - [[NSGraphicsContext currentContext] setShouldAntialias:YES]; - - /* - * Cocoa drawing functions don't take a graphics context: that - * parameter is implicit. Therefore, we'll use the frontend - * handle itself as the context, on the grounds that it's as - * good a thing to use as any. - */ - return frontend; -} - -void free_ctx(Context ctx) -{ - SessionWindow *win = (SessionWindow *)ctx; - - [win drawStartFinish:NO]; -} - -void do_text(Context ctx, int x, int y, wchar_t *text, int len, - unsigned long attr, int lattr) -{ - SessionWindow *win = (SessionWindow *)ctx; - - [win doText:text len:len x:x y:y attr:attr lattr:lattr]; -} - -void do_cursor(Context ctx, int x, int y, wchar_t *text, int len, - unsigned long attr, int lattr) -{ - SessionWindow *win = (SessionWindow *)ctx; - Config *cfg = [win cfg]; - int active, passive; - - if (attr & TATTR_PASCURS) { - attr &= ~TATTR_PASCURS; - passive = 1; - } else - passive = 0; - if ((attr & TATTR_ACTCURS) && cfg->cursor_type != 0) { - attr &= ~TATTR_ACTCURS; - active = 1; - } else - active = 0; - - [win doText:text len:len x:x y:y attr:attr lattr:lattr]; - - /* - * FIXME: now draw the various cursor types (both passive and - * active underlines and vertical lines, plus passive blocks). - */ -} - -/* - * Minimise or restore the window in response to a server-side - * request. - */ -void set_iconic(void *frontend, int iconic) -{ - //SessionWindow *win = (SessionWindow *)frontend; - /* FIXME */ -} - -/* - * Move the window in response to a server-side request. - */ -void move_window(void *frontend, int x, int y) -{ - //SessionWindow *win = (SessionWindow *)frontend; - /* FIXME */ -} - -/* - * Move the window to the top or bottom of the z-order in response - * to a server-side request. - */ -void set_zorder(void *frontend, int top) -{ - //SessionWindow *win = (SessionWindow *)frontend; - /* FIXME */ -} - -/* - * Refresh the window in response to a server-side request. - */ -void refresh_window(void *frontend) -{ - //SessionWindow *win = (SessionWindow *)frontend; - /* FIXME */ -} - -/* - * Maximise or restore the window in response to a server-side - * request. - */ -void set_zoomed(void *frontend, int zoomed) -{ - //SessionWindow *win = (SessionWindow *)frontend; - /* FIXME */ -} - -/* - * Report whether the window is iconic, for terminal reports. - */ -int is_iconic(void *frontend) -{ - //SessionWindow *win = (SessionWindow *)frontend; - return NO; /* FIXME */ -} - -/* - * Report the window's position, for terminal reports. - */ -void get_window_pos(void *frontend, int *x, int *y) -{ - //SessionWindow *win = (SessionWindow *)frontend; - /* FIXME */ -} - -/* - * Report the window's pixel size, for terminal reports. - */ -void get_window_pixels(void *frontend, int *x, int *y) -{ - //SessionWindow *win = (SessionWindow *)frontend; - /* FIXME */ -} - -/* - * Return the window or icon title. - */ -char *get_window_title(void *frontend, int icon) -{ - //SessionWindow *win = (SessionWindow *)frontend; - return NULL; /* FIXME */ -} - -void set_title(void *frontend, char *title) -{ - //SessionWindow *win = (SessionWindow *)frontend; - /* FIXME */ -} - -void set_icon(void *frontend, char *title) -{ - //SessionWindow *win = (SessionWindow *)frontend; - /* FIXME */ -} - -void set_sbar(void *frontend, int total, int start, int page) -{ - //SessionWindow *win = (SessionWindow *)frontend; - /* FIXME */ -} - -void get_clip(void *frontend, wchar_t ** p, int *len) -{ - //SessionWindow *win = (SessionWindow *)frontend; - /* FIXME */ -} - -void write_clip(void *frontend, wchar_t *data, int *attr, int len, int must_deselect) -{ - //SessionWindow *win = (SessionWindow *)frontend; - /* FIXME */ -} - -void request_paste(void *frontend) -{ - //SessionWindow *win = (SessionWindow *)frontend; - /* FIXME */ -} - -void set_raw_mouse_mode(void *frontend, int activate) -{ - //SessionWindow *win = (SessionWindow *)frontend; - /* FIXME */ -} - -void request_resize(void *frontend, int w, int h) -{ - //SessionWindow *win = (SessionWindow *)frontend; - /* FIXME */ -} - -void sys_cursor(void *frontend, int x, int y) -{ - //SessionWindow *win = (SessionWindow *)frontend; - /* - * This is probably meaningless under OS X. FIXME: find out for - * sure. - */ -} - -void logevent(void *frontend, const char *string) -{ - //SessionWindow *win = (SessionWindow *)frontend; - /* FIXME */ -printf("logevent: %s\n", string); -} - -int font_dimension(void *frontend, int which)/* 0 for width, 1 for height */ -{ - //SessionWindow *win = (SessionWindow *)frontend; - return 1; /* FIXME */ -} - -void set_busy_status(void *frontend, int status) -{ - /* - * We need do nothing here: the OS X `application is busy' - * beachball pointer appears _automatically_ when the - * application isn't responding to GUI messages. - */ -} diff --git a/puttyps.h b/puttyps.h index 724bf9b8..27916d27 100644 --- a/puttyps.h +++ b/puttyps.h @@ -9,10 +9,6 @@ #include "winstuff.h" -#elif defined(MACOSX) - -#include "osx.h" - #else #include "unix.h"