/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
!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
!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.
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
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
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.
+ 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
+++ /dev/null
-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-<key> 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
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-<dict>
- <key>CFBundleIconFile</key>
- <string>PuTTY.icns</string>
-</dict>
-</plist>
+++ /dev/null
-#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
+++ /dev/null
-/*
- * 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 */
+++ /dev/null
-/*
- * osxctrls.m: OS X implementation of the dialog.h interface.
- */
-
-#import <Cocoa/Cocoa.h>
-#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);
- }
- }
-}
+++ /dev/null
-/*
- * osxdlg.m: various PuTTY dialog boxes for OS X.
- */
-
-#import <Cocoa/Cocoa.h>
-#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];
-}
+++ /dev/null
-/*
- * osxmain.m: main-program file of Mac OS X PuTTY.
- */
-
-#import <Cocoa/Cocoa.h>
-
-#define PUTTY_DO_GLOBALS /* actually _define_ globals */
-
-#include "putty.h"
-#include "osxclass.h"
-
-/* ----------------------------------------------------------------------
- * Global variables.
- */
-
-AppController *controller;
-
-/* ----------------------------------------------------------------------
- * Miscellaneous elements of the interface to the cross-platform
- * and Unix PuTTY code.
- */
-
-char *platform_get_x_display(void) {
- return NULL;
-}
-
-FontSpec platform_default_fontspec(const char *name)
-{
- FontSpec ret;
- /* FIXME */
- return ret;
-}
-
-Filename platform_default_filename(const char *name)
-{
- Filename ret;
- if (!strcmp(name, "LogFileName"))
- strcpy(ret.path, "putty.log");
- else
- *ret.path = '\0';
- return ret;
-}
-
-char *platform_default_s(const char *name)
-{
- return NULL;
-}
-
-int platform_default_i(const char *name, int def)
-{
- if (!strcmp(name, "CloseOnExit"))
- return 2; /* maps to FORCE_ON after painful rearrangement :-( */
- return def;
-}
-
-char *x_get_default(const char *key)
-{
- return NULL; /* this is a stub */
-}
-
-static void commonfatalbox(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;
-}
+++ /dev/null
-/*
- * osxsel.m: OS X implementation of the front end interface to uxsel.
- */
-
-#import <Cocoa/Cocoa.h>
-#include <unistd.h>
-#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();
-}
+++ /dev/null
-/*
- * osxwin.m: code to manage a session window in Mac OS X PuTTY.
- */
-
-#import <Cocoa/Cocoa.h>
-#include "putty.h"
-#include "terminal.h"
-#include "osxclass.h"
-
-/* Colours come in two flavours: configurable, and xterm-extended. */
-#define NCFGCOLOURS (lenof(((Config *)0)->colours))
-#define NEXTCOLOURS 240 /* 216 colour-cube plus 24 shades of grey */
-#define NALLCOLOURS (NCFGCOLOURS + NEXTCOLOURS)
-
-/*
- * The key component of the per-session data is the SessionWindow
- * class. A pointer to this is used as the frontend handle, to be
- * passed to all the platform-independent subsystems that require
- * one.
- */
-
-@interface TerminalView : NSImageView
-{
- NSFont *font;
- NSImage *image;
- Terminal *term;
- Config cfg;
- NSColor *colours[NALLCOLOURS];
- float fw, fasc, fdesc, fh;
-}
-- (void)drawStartFinish:(BOOL)start;
-- (void)setColour:(int)n r:(float)r g:(float)g b:(float)b;
-- (void)doText:(wchar_t *)text len:(int)len x:(int)x y:(int)y
- attr:(unsigned long)attr lattr:(int)lattr;
-@end
-
-@implementation TerminalView
-- (BOOL)isFlipped
-{
- return YES;
-}
-- (id)initWithTerminal:(Terminal *)aTerm config:(Config)aCfg
-{
- float w, h;
-
- self = [self initWithFrame:NSMakeRect(0,0,100,100)];
-
- term = aTerm;
- cfg = aCfg;
-
- /*
- * Initialise the fonts we're going to use.
- *
- * FIXME: for the moment I'm sticking with exactly one default font.
- */
- font = [NSFont userFixedPitchFontOfSize:0];
-
- /*
- * Now determine the size of the primary font.
- *
- * FIXME: If we have multiple fonts, we may need to set fasc
- * and fdesc to the _maximum_ asc and desc out of all the
- * fonts, _before_ adding them together to get fh.
- */
- fw = [font widthOfString:@"A"];
- fasc = [font ascender];
- fdesc = -[font descender];
- fh = fasc + fdesc;
- fh = (int)fh + (fh > (int)fh); /* round up, ickily */
-
- /*
- * Use this to figure out the size of the terminal view.
- */
- w = fw * term->cols;
- h = fh * term->rows;
-
- /*
- * And set our size and subimage.
- */
- image = [[NSImage alloc] initWithSize:NSMakeSize(w,h)];
- [image setFlipped:YES];
- [self setImage:image];
- [self setFrame:NSMakeRect(0,0,w,h)];
-
- term_invalidate(term);
-
- return self;
-}
-- (void)drawStartFinish:(BOOL)start
-{
- if (start)
- [image lockFocus];
- else
- [image unlockFocus];
-}
-- (void)doText:(wchar_t *)text len:(int)len x:(int)x y:(int)y
- attr:(unsigned long)attr lattr:(int)lattr
-{
- int nfg, nbg, rlen, widefactor;
- float ox, oy, tw, th;
- NSDictionary *attrdict;
-
- /* FIXME: TATTR_COMBINING */
-
- nfg = ((attr & ATTR_FGMASK) >> ATTR_FGSHIFT);
- nbg = ((attr & ATTR_BGMASK) >> ATTR_BGSHIFT);
- if (attr & ATTR_REVERSE) {
- int t = nfg;
- nfg = nbg;
- nbg = t;
- }
- if ((cfg.bold_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.
- */
-}
#include "winstuff.h"
-#elif defined(MACOSX)
-
-#include "osx.h"
-
#else
#include "unix.h"