# GUI front end and terminal emulator (putty, puttytel).
GUITERM = window windlg winctrls terminal sizetip wcwidth unicode ldiscucs
- + logging printing winutils
+ + logging printing winutils dialog config wincfg tree234
# Non-SSH back ends (putty, puttytel, plink).
NONSSH = telnet raw rlogin ldisc
puttygen : [G] puttygen sshrsag sshdssg sshprime sshdes sshbn sshmd5 version
+ sshrand noise sshsha winstore misc winctrls sshrsa sshdss winmisc
- + sshpubk sshaes sshsh512 import winutils puttygen.res LIBS
+ + sshpubk sshaes sshsh512 import winutils puttygen.res tree234 LIBS
pterm : [X] pterm terminal wcwidth uxucs uxmisc tree234 misc ldisc ldiscucs
+ logging uxprint settings pty be_none uxstore signal CHARSET
--- /dev/null
+/*
+ * config.c - the platform-independent parts of the PuTTY
+ * configuration box.
+ */
+
+#include <assert.h>
+#include <stdlib.h>
+
+#include "putty.h"
+#include "dialog.h"
+#include "storage.h"
+
+#define PRINTER_DISABLED_STRING "None (printing disabled)"
+
+static void protocolbuttons_handler(union control *ctrl, void *dlg,
+ void *data, int event)
+{
+ int button, defport;
+ Config *cfg = (Config *)data;
+ /*
+ * This function works just like the standard radio-button
+ * handler, except that it also has to change the setting of
+ * the port box. We expect the context parameter to point at
+ * the `union control' structure for the port box.
+ */
+ if (event == EVENT_REFRESH) {
+ for (button = 0; button < ctrl->radio.nbuttons; button++)
+ if (cfg->protocol == ctrl->radio.buttondata[button].i)
+ break;
+ /* We expected that `break' to happen, in all circumstances. */
+ assert(button < ctrl->radio.nbuttons);
+ dlg_radiobutton_set(ctrl, dlg, button);
+ } else if (event == EVENT_VALCHANGE) {
+ int oldproto = cfg->protocol;
+ button = dlg_radiobutton_get(ctrl, dlg);
+ assert(button >= 0 && button < ctrl->radio.nbuttons);
+ cfg->protocol = ctrl->radio.buttondata[button].i;
+ if (oldproto != cfg->protocol) {
+ defport = -1;
+ switch (cfg->protocol) {
+ case PROT_SSH: defport = 22; break;
+ case PROT_TELNET: defport = 23; break;
+ case PROT_RLOGIN: defport = 513; break;
+ }
+ if (defport > 0 && cfg->port != defport) {
+ cfg->port = defport;
+ dlg_refresh((union control *)ctrl->radio.context.p, dlg);
+ }
+ }
+ }
+}
+
+static void numeric_keypad_handler(union control *ctrl, void *dlg,
+ void *data, int event)
+{
+ int button;
+ Config *cfg = (Config *)data;
+ /*
+ * This function works much like the standard radio button
+ * handler, but it has to handle two fields in Config.
+ */
+ if (event == EVENT_REFRESH) {
+ if (cfg->nethack_keypad)
+ button = 2;
+ else if (cfg->app_keypad)
+ button = 1;
+ else
+ button = 0;
+ assert(button < ctrl->radio.nbuttons);
+ dlg_radiobutton_set(ctrl, dlg, button);
+ } else if (event == EVENT_VALCHANGE) {
+ button = dlg_radiobutton_get(ctrl, dlg);
+ assert(button >= 0 && button < ctrl->radio.nbuttons);
+ if (button == 2) {
+ cfg->app_keypad = FALSE;
+ cfg->nethack_keypad = TRUE;
+ } else {
+ cfg->app_keypad = (button != 0);
+ cfg->nethack_keypad = FALSE;
+ }
+ }
+}
+
+static void cipherlist_handler(union control *ctrl, void *dlg,
+ void *data, int event)
+{
+ Config *cfg = (Config *)data;
+ if (event == EVENT_REFRESH) {
+ int i;
+
+ static const struct { char *s; int c; } ciphers[] = {
+ { "3DES", CIPHER_3DES },
+ { "Blowfish", CIPHER_BLOWFISH },
+ { "DES", CIPHER_DES },
+ { "AES (SSH 2 only)", CIPHER_AES },
+ { "-- warn below here --", CIPHER_WARN }
+ };
+
+ /* Set up the "selected ciphers" box. */
+ /* (cipherlist assumed to contain all ciphers) */
+ dlg_update_start(ctrl, dlg);
+ dlg_listbox_clear(ctrl, dlg);
+ for (i = 0; i < CIPHER_MAX; i++) {
+ int c = cfg->ssh_cipherlist[i];
+ int j;
+ char *cstr = NULL;
+ for (j = 0; j < (sizeof ciphers) / (sizeof ciphers[0]); j++) {
+ if (ciphers[j].c == c) {
+ cstr = ciphers[j].s;
+ break;
+ }
+ }
+ dlg_listbox_addwithindex(ctrl, dlg, cstr, c);
+ }
+ dlg_update_done(ctrl, dlg);
+
+ } else if (event == EVENT_VALCHANGE) {
+ int i;
+
+ /* Update array to match the list box. */
+ for (i=0; i < CIPHER_MAX; i++)
+ cfg->ssh_cipherlist[i] = dlg_listbox_getid(ctrl, dlg, i);
+
+ }
+}
+
+static void printerbox_handler(union control *ctrl, void *dlg,
+ void *data, int event)
+{
+ Config *cfg = (Config *)data;
+ if (event == EVENT_REFRESH) {
+ int nprinters, i;
+ printer_enum *pe;
+
+ dlg_update_start(ctrl, dlg);
+ dlg_listbox_clear(ctrl, dlg);
+ dlg_listbox_add(ctrl, dlg, PRINTER_DISABLED_STRING);
+ pe = printer_start_enum(&nprinters);
+ for (i = 0; i < nprinters; i++)
+ dlg_listbox_add(ctrl, dlg, printer_get_name(pe, i));
+ printer_finish_enum(pe);
+ dlg_editbox_set(ctrl, dlg,
+ (*cfg->printer ? cfg->printer :
+ PRINTER_DISABLED_STRING));
+ dlg_update_done(ctrl, dlg);
+ } else if (event == EVENT_VALCHANGE) {
+ dlg_editbox_get(ctrl, dlg, cfg->printer, sizeof(cfg->printer));
+ if (!strcmp(cfg->printer, PRINTER_DISABLED_STRING))
+ *cfg->printer = '\0';
+ }
+}
+
+static void codepage_handler(union control *ctrl, void *dlg,
+ void *data, int event)
+{
+ Config *cfg = (Config *)data;
+ if (event == EVENT_REFRESH) {
+ int i;
+ char *cp;
+ dlg_update_start(ctrl, dlg);
+ strcpy(cfg->line_codepage,
+ cp_name(decode_codepage(cfg->line_codepage)));
+ dlg_listbox_clear(ctrl, dlg);
+ for (i = 0; (cp = cp_enumerate(i)) != NULL; i++)
+ dlg_listbox_add(ctrl, dlg, cp);
+ dlg_editbox_set(ctrl, dlg, cfg->line_codepage);
+ dlg_update_done(ctrl, dlg);
+ } else if (event == EVENT_VALCHANGE) {
+ dlg_editbox_get(ctrl, dlg, cfg->line_codepage,
+ sizeof(cfg->line_codepage));
+ strcpy(cfg->line_codepage,
+ cp_name(decode_codepage(cfg->line_codepage)));
+ }
+}
+
+static void sshbug_handler(union control *ctrl, void *dlg,
+ void *data, int event)
+{
+ if (event == EVENT_REFRESH) {
+ dlg_update_start(ctrl, dlg);
+ dlg_listbox_clear(ctrl, dlg);
+ dlg_listbox_addwithindex(ctrl, dlg, "Auto", AUTO);
+ dlg_listbox_addwithindex(ctrl, dlg, "Off", FORCE_OFF);
+ dlg_listbox_addwithindex(ctrl, dlg, "On", FORCE_ON);
+ switch (*(int *)ATOFFSET(data, ctrl->listbox.context.i)) {
+ case AUTO: dlg_listbox_select(ctrl, dlg, 0); break;
+ case FORCE_OFF: dlg_listbox_select(ctrl, dlg, 1); break;
+ case FORCE_ON: dlg_listbox_select(ctrl, dlg, 2); break;
+ }
+ dlg_update_done(ctrl, dlg);
+ } else if (event == EVENT_SELCHANGE) {
+ int i = dlg_listbox_index(ctrl, dlg);
+ if (i < 0)
+ i = AUTO;
+ else
+ i = dlg_listbox_getid(ctrl, dlg, i);
+ *(int *)ATOFFSET(data, ctrl->listbox.context.i) = i;
+ }
+}
+
+struct sessionsaver_data {
+ union control *editbox, *listbox, *loadbutton, *savebutton, *delbutton;
+ union control *okbutton, *cancelbutton;
+ char savedsession[2048];
+ struct sesslist *sesslist;
+};
+
+/*
+ * Helper function to load the session selected in the list box, if
+ * any, as this is done in more than one place below. Returns 0 for
+ * failure.
+ */
+static int load_selected_session(struct sessionsaver_data *ssd,
+ void *dlg, Config *cfg)
+{
+ int i = dlg_listbox_index(ssd->listbox, dlg);
+ int isdef;
+ if (i < 0) {
+ dlg_beep(dlg);
+ return 0;
+ }
+ isdef = !strcmp(ssd->sesslist->sessions[i], "Default Settings");
+ load_settings(ssd->sesslist->sessions[i], !isdef, cfg);
+ if (!isdef) {
+ strncpy(ssd->savedsession, ssd->sesslist->sessions[i],
+ sizeof(ssd->savedsession));
+ ssd->savedsession[sizeof(ssd->savedsession)-1] = '\0';
+ } else {
+ ssd->savedsession[0] = '\0';
+ }
+ dlg_refresh(NULL, dlg);
+ /* Restore the selection, which might have been clobbered by
+ * changing the value of the edit box. */
+ dlg_listbox_select(ssd->listbox, dlg, i);
+ return 1;
+}
+
+static void sessionsaver_handler(union control *ctrl, void *dlg,
+ void *data, int event)
+{
+ Config *cfg = (Config *)data;
+ struct sessionsaver_data *ssd =
+ (struct sessionsaver_data *)ctrl->generic.context.p;
+
+ if (event == EVENT_REFRESH) {
+ if (ctrl == ssd->editbox) {
+ dlg_editbox_set(ctrl, dlg, ssd->savedsession);
+ } else if (ctrl == ssd->listbox) {
+ int i;
+ dlg_update_start(ctrl, dlg);
+ dlg_listbox_clear(ctrl, dlg);
+ for (i = 0; i < ssd->sesslist->nsessions; i++)
+ dlg_listbox_add(ctrl, dlg, ssd->sesslist->sessions[i]);
+ dlg_update_done(ctrl, dlg);
+ }
+ } else if (event == EVENT_VALCHANGE) {
+ if (ctrl == ssd->editbox) {
+ dlg_editbox_get(ctrl, dlg, ssd->savedsession,
+ sizeof(ssd->savedsession));
+ }
+ } else if (event == EVENT_ACTION) {
+ if (ctrl == ssd->listbox || ctrl == ssd->loadbutton) {
+ /*
+ * The user has double-clicked a session, or hit Load.
+ * We must load the selected session, and then
+ * terminate the configuration dialog _if_ there was a
+ * double-click on the list box _and_ that session
+ * contains a hostname.
+ */
+ if (load_selected_session(ssd, dlg, cfg) &&
+ (ctrl == ssd->listbox && cfg->host[0])) {
+ dlg_end(dlg, 1); /* it's all over, and succeeded */
+ }
+ } else if (ctrl == ssd->savebutton) {
+ int isdef = !strcmp(ssd->savedsession, "Default Settings");
+ if (!ssd->savedsession[0]) {
+ int i = dlg_listbox_index(ctrl, dlg);
+ if (i < 0) {
+ dlg_beep(dlg);
+ return;
+ }
+ isdef = !strcmp(ssd->sesslist->sessions[i], "Default Settings");
+ if (!isdef) {
+ strncpy(ssd->savedsession, ssd->sesslist->sessions[i],
+ sizeof(ssd->savedsession));
+ ssd->savedsession[sizeof(ssd->savedsession)-1] = '\0';
+ } else {
+ ssd->savedsession[0] = '\0';
+ }
+ }
+ save_settings(ssd->savedsession, isdef, cfg);
+ get_sesslist(ssd->sesslist, FALSE);
+ get_sesslist(ssd->sesslist, TRUE);
+ dlg_refresh(ssd->editbox, dlg);
+ dlg_refresh(ssd->listbox, dlg);
+ } else if (ctrl == ssd->delbutton) {
+ int i = dlg_listbox_index(ctrl, dlg);
+ if (i <= 0) {
+ dlg_beep(dlg);
+ } else {
+ del_settings(ssd->sesslist->sessions[i]);
+ get_sesslist(ssd->sesslist, FALSE);
+ get_sesslist(ssd->sesslist, TRUE);
+ dlg_refresh(ssd->listbox, dlg);
+ }
+ } else if (ctrl == ssd->okbutton) {
+ /*
+ * Annoying special case. If the `Open' button is
+ * pressed while no host name is currently set, _and_
+ * the session list previously had the focus, _and_
+ * there was a session selected in that which had a
+ * valid host name in it, then load it and go.
+ */
+ if (dlg_last_focused(dlg) == ssd->listbox && !*cfg->host) {
+ Config cfg2;
+ if (!load_selected_session(ssd, dlg, &cfg2)) {
+ dlg_beep(dlg);
+ return;
+ }
+ /* If at this point we have a valid session, go! */
+ if (*cfg2.host) {
+ *cfg = cfg2; /* structure copy */
+ dlg_end(dlg, 1);
+ } else
+ dlg_beep(dlg);
+ }
+
+ /*
+ * Otherwise, do the normal thing: if we have a valid
+ * session, get going.
+ */
+ if (*cfg->host) {
+ dlg_end(dlg, 1);
+ } else
+ dlg_beep(dlg);
+ } else if (ctrl == ssd->cancelbutton) {
+ dlg_end(dlg, 0);
+ }
+ }
+}
+
+struct charclass_data {
+ union control *listbox, *editbox, *button;
+};
+
+static void charclass_handler(union control *ctrl, void *dlg,
+ void *data, int event)
+{
+ Config *cfg = (Config *)data;
+ struct charclass_data *ccd =
+ (struct charclass_data *)ctrl->generic.context.p;
+
+ if (event == EVENT_REFRESH) {
+ if (ctrl == ccd->listbox) {
+ int i;
+ dlg_update_start(ctrl, dlg);
+ dlg_listbox_clear(ctrl, dlg);
+ for (i = 0; i < 128; i++) {
+ char str[100];
+ sprintf(str, "%d\t(0x%02X)\t%c\t%d", i, i,
+ (i >= 0x21 && i != 0x7F) ? i : ' ', cfg->wordness[i]);
+ dlg_listbox_add(ctrl, dlg, str);
+ }
+ dlg_update_done(ctrl, dlg);
+ }
+ } else if (event == EVENT_ACTION) {
+ if (ctrl == ccd->button) {
+ char str[100];
+ int i, n;
+ dlg_editbox_get(ccd->editbox, dlg, str, sizeof(str));
+ n = atoi(str);
+ for (i = 0; i < 128; i++) {
+ if (dlg_listbox_issel(ccd->listbox, dlg, i))
+ cfg->wordness[i] = n;
+ }
+ dlg_refresh(ccd->listbox, dlg);
+ }
+ }
+}
+
+struct colour_data {
+ union control *listbox, *rgbtext, *button;
+};
+
+static const char *const colours[] = {
+ "Default Foreground", "Default Bold Foreground",
+ "Default Background", "Default Bold Background",
+ "Cursor Text", "Cursor Colour",
+ "ANSI Black", "ANSI Black Bold",
+ "ANSI Red", "ANSI Red Bold",
+ "ANSI Green", "ANSI Green Bold",
+ "ANSI Yellow", "ANSI Yellow Bold",
+ "ANSI Blue", "ANSI Blue Bold",
+ "ANSI Magenta", "ANSI Magenta Bold",
+ "ANSI Cyan", "ANSI Cyan Bold",
+ "ANSI White", "ANSI White Bold"
+};
+
+static void colour_handler(union control *ctrl, void *dlg,
+ void *data, int event)
+{
+ Config *cfg = (Config *)data;
+ struct colour_data *cd =
+ (struct colour_data *)ctrl->generic.context.p;
+ int update = FALSE, r, g, b;
+
+ if (event == EVENT_REFRESH) {
+ if (ctrl == cd->listbox) {
+ int i;
+ dlg_update_start(ctrl, dlg);
+ dlg_listbox_clear(ctrl, dlg);
+ for (i = 0; i < lenof(colours); i++)
+ dlg_listbox_add(ctrl, dlg, colours[i]);
+ dlg_update_done(ctrl, dlg);
+ dlg_text_set(cd->rgbtext, dlg, "");
+ }
+ } else if (event == EVENT_SELCHANGE) {
+ if (ctrl == cd->listbox) {
+ /* The user has selected a colour. Update the RGB text. */
+ int i = dlg_listbox_index(ctrl, dlg);
+ if (i < 0) {
+ dlg_beep(dlg);
+ return;
+ }
+ r = cfg->colours[i][0];
+ g = cfg->colours[i][1];
+ b = cfg->colours[i][2];
+ update = TRUE;
+ }
+ } else if (event == EVENT_ACTION) {
+ if (ctrl == cd->button) {
+ int i = dlg_listbox_index(cd->listbox, dlg);
+ if (i < 0) {
+ dlg_beep(dlg);
+ return;
+ }
+ /*
+ * Start a colour selector, which will send us an
+ * EVENT_CALLBACK when it's finished and allow us to
+ * pick up the results.
+ */
+ dlg_coloursel_start(ctrl, dlg,
+ cfg->colours[i][0],
+ cfg->colours[i][1],
+ cfg->colours[i][2]);
+ }
+ } else if (event == EVENT_CALLBACK) {
+ if (ctrl == cd->button) {
+ int i = dlg_listbox_index(cd->listbox, dlg);
+ /*
+ * Collect the results of the colour selector. Will
+ * return nonzero on success, or zero if the colour
+ * selector did nothing (user hit Cancel, for example).
+ */
+ if (dlg_coloursel_results(ctrl, dlg, &r, &g, &b)) {
+ cfg->colours[i][0] = r;
+ cfg->colours[i][1] = g;
+ cfg->colours[i][2] = b;
+ update = TRUE;
+ }
+ }
+ }
+
+ if (update) {
+ char buf[40];
+ sprintf(buf, "%02x/%02x/%02x", r, g, b);
+ dlg_text_set(cd->rgbtext, dlg, buf);
+ }
+}
+
+struct environ_data {
+ union control *varbox, *valbox, *addbutton, *rembutton, *listbox;
+};
+
+static void environ_handler(union control *ctrl, void *dlg,
+ void *data, int event)
+{
+ Config *cfg = (Config *)data;
+ struct environ_data *ed =
+ (struct environ_data *)ctrl->generic.context.p;
+
+ if (event == EVENT_REFRESH) {
+ if (ctrl == ed->listbox) {
+ char *p = cfg->environmt;
+ dlg_update_start(ctrl, dlg);
+ dlg_listbox_clear(ctrl, dlg);
+ while (*p) {
+ dlg_listbox_add(ctrl, dlg, p);
+ p += strlen(p) + 1;
+ }
+ dlg_update_done(ctrl, dlg);
+ }
+ } else if (event == EVENT_ACTION) {
+ if (ctrl == ed->addbutton) {
+ char str[sizeof(cfg->environmt)];
+ char *p;
+ dlg_editbox_get(ed->varbox, dlg, str, sizeof(str)-1);
+ if (!*str) {
+ dlg_beep(dlg);
+ return;
+ }
+ p = str + strlen(str);
+ *p++ = '\t';
+ dlg_editbox_get(ed->valbox, dlg, p, sizeof(str)-1 - (p - str));
+ if (!*p) {
+ dlg_beep(dlg);
+ return;
+ }
+ p = cfg->environmt;
+ while (*p) {
+ while (*p)
+ p++;
+ p++;
+ }
+ if ((p - cfg->environmt) + strlen(str) + 2 <
+ sizeof(cfg->environmt)) {
+ strcpy(p, str);
+ p[strlen(str) + 1] = '\0';
+ dlg_listbox_add(ed->listbox, dlg, str);
+ dlg_editbox_set(ed->varbox, dlg, "");
+ dlg_editbox_set(ed->valbox, dlg, "");
+ } else {
+ dlg_error_msg(dlg, "Environment too big");
+ }
+ } else if (ctrl == ed->rembutton) {
+ int i = dlg_listbox_index(ed->listbox, dlg);
+ if (i < 0) {
+ dlg_beep(dlg);
+ } else {
+ char *p, *q;
+
+ dlg_listbox_del(ed->listbox, dlg, i);
+ p = cfg->environmt;
+ while (i > 0) {
+ if (!*p)
+ goto disaster;
+ while (*p)
+ p++;
+ p++;
+ i--;
+ }
+ q = p;
+ if (!*p)
+ goto disaster;
+ while (*p)
+ p++;
+ p++;
+ while (*p) {
+ while (*p)
+ *q++ = *p++;
+ *q++ = *p++;
+ }
+ *q = '\0';
+ disaster:;
+ }
+ }
+ }
+}
+
+struct portfwd_data {
+ union control *addbutton, *rembutton, *listbox;
+ union control *sourcebox, *destbox, *direction;
+};
+
+static void portfwd_handler(union control *ctrl, void *dlg,
+ void *data, int event)
+{
+ Config *cfg = (Config *)data;
+ struct portfwd_data *pfd =
+ (struct portfwd_data *)ctrl->generic.context.p;
+
+ if (event == EVENT_REFRESH) {
+ if (ctrl == pfd->listbox) {
+ char *p = cfg->portfwd;
+ dlg_update_start(ctrl, dlg);
+ dlg_listbox_clear(ctrl, dlg);
+ while (*p) {
+ dlg_listbox_add(ctrl, dlg, p);
+ p += strlen(p) + 1;
+ }
+ dlg_update_done(ctrl, dlg);
+ }
+ } else if (event == EVENT_ACTION) {
+ if (ctrl == pfd->addbutton) {
+ char str[sizeof(cfg->portfwd)];
+ char *p;
+ if (dlg_radiobutton_get(pfd->direction, dlg) == 0)
+ str[0] = 'L';
+ else
+ str[0] = 'R';
+ dlg_editbox_get(pfd->sourcebox, dlg, str+1, sizeof(str) - 2);
+ if (!str[1]) {
+ dlg_error_msg(dlg, "You need to specify a source port number");
+ return;
+ }
+ p = str + strlen(str);
+ *p++ = '\t';
+ dlg_editbox_get(pfd->destbox, dlg, p, sizeof(str)-1 - (p - str));
+ if (!*p || !strchr(p, ':')) {
+ dlg_error_msg(dlg,
+ "You need to specify a destination address\n"
+ "in the form \"host.name:port\"");
+ return;
+ }
+ p = cfg->portfwd;
+ while (*p) {
+ while (*p)
+ p++;
+ p++;
+ }
+ if ((p - cfg->portfwd) + strlen(str) + 2 <
+ sizeof(cfg->portfwd)) {
+ strcpy(p, str);
+ p[strlen(str) + 1] = '\0';
+ dlg_listbox_add(pfd->listbox, dlg, str);
+ dlg_editbox_set(pfd->sourcebox, dlg, "");
+ dlg_editbox_set(pfd->destbox, dlg, "");
+ } else {
+ dlg_error_msg(dlg, "Too many forwardings");
+ }
+ } else if (ctrl == pfd->rembutton) {
+ int i = dlg_listbox_index(pfd->listbox, dlg);
+ if (i < 0)
+ dlg_beep(dlg);
+ else {
+ char *p, *q;
+
+ dlg_listbox_del(pfd->listbox, dlg, i);
+ p = cfg->portfwd;
+ while (i > 0) {
+ if (!*p)
+ goto disaster2;
+ while (*p)
+ p++;
+ p++;
+ i--;
+ }
+ q = p;
+ if (!*p)
+ goto disaster2;
+ while (*p)
+ p++;
+ p++;
+ while (*p) {
+ while (*p)
+ *q++ = *p++;
+ *q++ = *p++;
+ }
+ *q = '\0';
+ disaster2:;
+ }
+ }
+ }
+}
+
+void setup_config_box(struct controlbox *b, struct sesslist *sesslist,
+ int midsession, int protocol)
+{
+ struct controlset *s;
+ struct sessionsaver_data *ssd;
+ struct charclass_data *ccd;
+ struct colour_data *cd;
+ struct environ_data *ed;
+ struct portfwd_data *pfd;
+ union control *c;
+
+ ssd = (struct sessionsaver_data *)
+ ctrl_alloc(b, sizeof(struct sessionsaver_data));
+ ssd->sesslist = (midsession ? NULL : sesslist);
+
+ /*
+ * The standard panel that appears at the bottom of all panels:
+ * Open, Cancel, Apply etc.
+ */
+ s = ctrl_getset(b, "", "", "");
+ ctrl_columns(s, 5, 20, 20, 20, 20, 20);
+ ssd->okbutton = ctrl_pushbutton(s,
+ (midsession ? "Apply" : "Open"),
+ (char)(midsession ? 'a' : 'o'),
+ HELPCTX(no_help),
+ sessionsaver_handler, P(ssd));
+ ssd->okbutton->button.isdefault = TRUE;
+ ssd->okbutton->generic.column = 3;
+ ssd->cancelbutton = ctrl_pushbutton(s, "Cancel", 'c', HELPCTX(no_help),
+ sessionsaver_handler, P(ssd));
+ ssd->cancelbutton->generic.column = 4;
+ /* We carefully don't close the 5-column part, so that platform-
+ * specific add-ons can put extra buttons alongside Open and Cancel. */
+
+ /*
+ * The Session panel.
+ */
+ ctrl_settitle(b, "Session", "Basic options for your PuTTY session");
+
+ if (!midsession) {
+ s = ctrl_getset(b, "Session", "hostport",
+ "Specify your connection by host name or IP address");
+ ctrl_columns(s, 2, 75, 25);
+ c = ctrl_editbox(s, "Host Name (or IP address)", 'n', 100,
+ HELPCTX(session_hostname),
+ dlg_stdeditbox_handler, I(offsetof(Config,host)),
+ I(sizeof(((Config *)0)->host)));
+ c->generic.column = 0;
+ c = ctrl_editbox(s, "Port", 'p', 100, HELPCTX(session_hostname),
+ dlg_stdeditbox_handler,
+ I(offsetof(Config,port)), I(-1));
+ c->generic.column = 1;
+ ctrl_columns(s, 1, 100);
+ if (backends[3].backend == NULL) {
+ ctrl_radiobuttons(s, "Protocol:", NO_SHORTCUT, 3,
+ HELPCTX(session_hostname),
+ protocolbuttons_handler, P(c),
+ "Raw", 'r', I(PROT_RAW),
+ "Telnet", 't', I(PROT_TELNET),
+ "Rlogin", 'i', I(PROT_RLOGIN),
+ NULL);
+ } else {
+ ctrl_radiobuttons(s, "Protocol:", NO_SHORTCUT, 4,
+ HELPCTX(session_hostname),
+ protocolbuttons_handler, P(c),
+ "Raw", 'r', I(PROT_RAW),
+ "Telnet", 't', I(PROT_TELNET),
+ "Rlogin", 'i', I(PROT_RLOGIN),
+ "SSH", 's', I(PROT_SSH),
+ NULL);
+ }
+
+ s = ctrl_getset(b, "Session", "savedsessions",
+ "Load, save or delete a stored session");
+ ctrl_columns(s, 2, 75, 25);
+ ssd->savedsession[0] = '\0';
+ ssd->sesslist = sesslist;
+ ssd->editbox = ctrl_editbox(s, "Saved Sessions", 'e', 100,
+ HELPCTX(session_saved),
+ sessionsaver_handler, P(ssd), P(NULL));
+ ssd->editbox->generic.column = 0;
+ /* Reset columns so that the buttons are alongside the list, rather
+ * than alongside that edit box. */
+ ctrl_columns(s, 1, 100);
+ ctrl_columns(s, 2, 75, 25);
+ ssd->loadbutton = ctrl_pushbutton(s, "Load", 'l',
+ HELPCTX(session_saved),
+ sessionsaver_handler, P(ssd));
+ ssd->loadbutton->generic.column = 1;
+ ssd->savebutton = ctrl_pushbutton(s, "Save", 'v',
+ HELPCTX(session_saved),
+ sessionsaver_handler, P(ssd));
+ ssd->savebutton->generic.column = 1;
+ ssd->delbutton = ctrl_pushbutton(s, "Delete", 'd',
+ HELPCTX(session_saved),
+ sessionsaver_handler, P(ssd));
+ ssd->delbutton->generic.column = 1;
+ ssd->listbox = ctrl_listbox(s, NULL, NO_SHORTCUT,
+ HELPCTX(session_saved),
+ sessionsaver_handler, P(ssd));
+ ssd->listbox->generic.column = 0;
+ ssd->listbox->listbox.height = 7;
+ ctrl_columns(s, 1, 100);
+ }
+
+ s = ctrl_getset(b, "Session", "otheropts", NULL);
+ c = ctrl_radiobuttons(s, "Close window on exit:", 'w', 4,
+ HELPCTX(session_coe),
+ dlg_stdradiobutton_handler,
+ I(offsetof(Config, close_on_exit)),
+ "Always", I(FORCE_ON),
+ "Never", I(FORCE_OFF),
+ "Only on clean exit", I(AUTO), NULL);
+
+ /*
+ * The Session/Logging panel.
+ */
+ ctrl_settitle(b, "Session/Logging", "Options controlling session logging");
+
+ s = ctrl_getset(b, "Session/Logging", "main", NULL);
+ ctrl_radiobuttons(s, "Session logging:", NO_SHORTCUT, 1,
+ HELPCTX(logging_main),
+ dlg_stdradiobutton_handler, I(offsetof(Config, logtype)),
+ "Logging turned off completely", 't', I(LGTYP_NONE),
+ "Log printable output only", 'p', I(LGTYP_ASCII),
+ "Log all session output", 'l', I(LGTYP_DEBUG),
+ "Log SSH packet data", 's', I(LGTYP_PACKETS),
+ NULL);
+ ctrl_filesel(s, "Log file name:", 'f',
+ NULL, TRUE, "Select session log file name",
+ HELPCTX(logging_filename),
+ dlg_stdfilesel_handler, I(offsetof(Config, logfilename)));
+ ctrl_text(s, "(Log file name can contain &Y, &M, &D for date,"
+ " &T for time, and &H for host name)",
+ HELPCTX(logging_filename));
+ ctrl_radiobuttons(s, "What to do if the log file already exists:", 'e', 1,
+ HELPCTX(logging_exists),
+ dlg_stdradiobutton_handler, I(offsetof(Config,logxfovr)),
+ "Always overwrite it", I(LGXF_OVR),
+ "Always append to the end of it", I(LGXF_APN),
+ "Ask the user every time", I(LGXF_ASK), NULL);
+
+ /*
+ * The Terminal panel.
+ */
+ ctrl_settitle(b, "Terminal", "Options controlling the terminal emulation");
+
+ s = ctrl_getset(b, "Terminal", "general", "Set various terminal options");
+ ctrl_checkbox(s, "Auto wrap mode initially on", 'w',
+ HELPCTX(terminal_autowrap),
+ dlg_stdcheckbox_handler, I(offsetof(Config,wrap_mode)));
+ ctrl_checkbox(s, "DEC Origin Mode initially on", 'd',
+ HELPCTX(terminal_decom),
+ dlg_stdcheckbox_handler, I(offsetof(Config,dec_om)));
+ ctrl_checkbox(s, "Implicit CR in every LF", 'r',
+ HELPCTX(terminal_lfhascr),
+ dlg_stdcheckbox_handler, I(offsetof(Config,lfhascr)));
+ ctrl_checkbox(s, "Use background colour to erase screen", 'e',
+ HELPCTX(terminal_bce),
+ dlg_stdcheckbox_handler, I(offsetof(Config,bce)));
+ ctrl_checkbox(s, "Enable blinking text", 'n',
+ HELPCTX(terminal_blink),
+ dlg_stdcheckbox_handler, I(offsetof(Config,blinktext)));
+ ctrl_editbox(s, "Answerback to ^E:", 's', 100,
+ HELPCTX(terminal_answerback),
+ dlg_stdeditbox_handler, I(offsetof(Config,answerback)),
+ I(sizeof(((Config *)0)->answerback)));
+
+ s = ctrl_getset(b, "Terminal", "ldisc", "Line discipline options");
+ ctrl_radiobuttons(s, "Local echo:", 'l', 3,
+ HELPCTX(terminal_localecho),
+ dlg_stdradiobutton_handler,I(offsetof(Config,localecho)),
+ "Auto", I(AUTO),
+ "Force on", I(FORCE_ON),
+ "Force off", I(FORCE_OFF), NULL);
+ ctrl_radiobuttons(s, "Local line editing:", 't', 3,
+ HELPCTX(terminal_localedit),
+ dlg_stdradiobutton_handler,I(offsetof(Config,localedit)),
+ "Auto", I(AUTO),
+ "Force on", I(FORCE_ON),
+ "Force off", I(FORCE_OFF), NULL);
+
+ s = ctrl_getset(b, "Terminal", "printing", "Remote-controlled printing");
+ ctrl_combobox(s, "Printer to send ANSI printer output to:", 'p', 100,
+ HELPCTX(terminal_printing),
+ printerbox_handler, P(NULL), P(NULL));
+
+ /*
+ * The Terminal/Keyboard panel.
+ */
+ ctrl_settitle(b, "Terminal/Keyboard",
+ "Options controlling the effects of keys");
+
+ s = ctrl_getset(b, "Terminal/Keyboard", "mappings",
+ "Change the sequences sent by:");
+ ctrl_radiobuttons(s, "The Backspace key", 'b', 2,
+ HELPCTX(keyboard_backspace),
+ dlg_stdradiobutton_handler,
+ I(offsetof(Config, bksp_is_delete)),
+ "Control-H", I(0), "Control-? (127)", I(1), NULL);
+ ctrl_radiobuttons(s, "The Home and End keys", 'e', 2,
+ HELPCTX(keyboard_homeend),
+ dlg_stdradiobutton_handler,
+ I(offsetof(Config, rxvt_homeend)),
+ "Standard", I(0), "rxvt", I(1), NULL);
+ ctrl_radiobuttons(s, "The Function keys and keypad", 'f', 3,
+ HELPCTX(keyboard_funkeys),
+ dlg_stdradiobutton_handler,
+ I(offsetof(Config, funky_type)),
+ "ESC[n~", I(0), "Linux", I(1), "Xterm R6", I(2),
+ "VT400", I(3), "VT100+", I(4), "SCO", I(5), NULL);
+
+ s = ctrl_getset(b, "Terminal/Keyboard", "appkeypad",
+ "Application keypad settings:");
+ ctrl_radiobuttons(s, "Initial state of cursor keys:", 'r', 3,
+ HELPCTX(keyboard_appcursor),
+ dlg_stdradiobutton_handler,
+ I(offsetof(Config, app_cursor)),
+ "Normal", I(0), "Application", I(1), NULL);
+ ctrl_radiobuttons(s, "Initial state of numeric keypad:", 'n', 3,
+ HELPCTX(keyboard_appkeypad),
+ numeric_keypad_handler, P(NULL),
+ "Normal", I(0), "Application", I(1), "NetHack", I(2),
+ NULL);
+
+ /*
+ * The Terminal/Bell panel.
+ */
+ ctrl_settitle(b, "Terminal/Bell",
+ "Options controlling the terminal bell");
+
+ s = ctrl_getset(b, "Terminal/Bell", "style", "Set the style of bell");
+ ctrl_radiobuttons(s, "Action to happen when a bell occurs:", 'b', 1,
+ HELPCTX(bell_style),
+ dlg_stdradiobutton_handler, I(offsetof(Config, beep)),
+ "None (bell disabled)", I(BELL_DISABLED),
+ "Make default system alert sound", I(BELL_DEFAULT),
+ "Visual bell (flash window)", I(BELL_VISUAL), NULL);
+
+ s = ctrl_getset(b, "Terminal/Bell", "overload",
+ "Control the bell overload behaviour");
+ ctrl_checkbox(s, "Bell is temporarily disabled when over-used", 'd',
+ HELPCTX(bell_overload),
+ dlg_stdcheckbox_handler, I(offsetof(Config,bellovl)));
+ ctrl_editbox(s, "Over-use means this many bells...", 'm', 20,
+ HELPCTX(bell_overload),
+ dlg_stdeditbox_handler, I(offsetof(Config,bellovl_n)), I(-1));
+ ctrl_editbox(s, "... in this many seconds", 't', 20,
+ HELPCTX(bell_overload),
+ dlg_stdeditbox_handler, I(offsetof(Config,bellovl_t)),
+ I(-1000));
+ ctrl_text(s, "The bell is re-enabled after a few seconds of silence.",
+ HELPCTX(bell_overload));
+ ctrl_editbox(s, "Seconds of silence required", 's', 20,
+ HELPCTX(bell_overload),
+ dlg_stdeditbox_handler, I(offsetof(Config,bellovl_s)),
+ I(-1000));
+
+ /*
+ * The Terminal/Features panel.
+ */
+ ctrl_settitle(b, "Terminal/Features",
+ "Enabling and disabling advanced terminal features");
+
+ s = ctrl_getset(b, "Terminal/Features", "main", NULL);
+ ctrl_checkbox(s, "Disable application cursor keys mode", 'u',
+ HELPCTX(features_application),
+ dlg_stdcheckbox_handler, I(offsetof(Config,no_applic_c)));
+ ctrl_checkbox(s, "Disable application keypad mode", 'k',
+ HELPCTX(features_application),
+ dlg_stdcheckbox_handler, I(offsetof(Config,no_applic_k)));
+ ctrl_checkbox(s, "Disable xterm-style mouse reporting", 'x',
+ HELPCTX(features_mouse),
+ dlg_stdcheckbox_handler, I(offsetof(Config,no_mouse_rep)));
+ ctrl_checkbox(s, "Disable remote-controlled terminal resizing", 's',
+ HELPCTX(features_resize),
+ dlg_stdcheckbox_handler,
+ I(offsetof(Config,no_remote_resize)));
+ ctrl_checkbox(s, "Disable switching to alternate terminal screen", 'w',
+ HELPCTX(features_altscreen),
+ dlg_stdcheckbox_handler, I(offsetof(Config,no_alt_screen)));
+ ctrl_checkbox(s, "Disable remote-controlled window title changing", 't',
+ HELPCTX(features_retitle),
+ dlg_stdcheckbox_handler,
+ I(offsetof(Config,no_remote_wintitle)));
+ ctrl_checkbox(s, "Disable destructive backspace on server sending ^?",'b',
+ HELPCTX(features_dbackspace),
+ dlg_stdcheckbox_handler, I(offsetof(Config,no_dbackspace)));
+ ctrl_checkbox(s, "Disable remote-controlled character set configuration",
+ 'r', HELPCTX(features_charset), dlg_stdcheckbox_handler,
+ I(offsetof(Config,no_remote_charset)));
+
+ /*
+ * The Window panel.
+ */
+ ctrl_settitle(b, "Window", "Options controlling PuTTY's window");
+
+ s = ctrl_getset(b, "Window", "size", "Set the size of the window");
+ ctrl_columns(s, 2, 50, 50);
+ c = ctrl_editbox(s, "Rows", 'r', 100,
+ HELPCTX(window_size),
+ dlg_stdeditbox_handler, I(offsetof(Config,height)),I(-1));
+ c->generic.column = 0;
+ c = ctrl_editbox(s, "Columns", 'm', 100,
+ HELPCTX(window_size),
+ dlg_stdeditbox_handler, I(offsetof(Config,width)), I(-1));
+ c->generic.column = 1;
+ ctrl_columns(s, 1, 100);
+
+ s = ctrl_getset(b, "Window", "scrollback",
+ "Control the scrollback in the window");
+ ctrl_editbox(s, "Lines of scrollback", 's', 50,
+ HELPCTX(window_scrollback),
+ dlg_stdeditbox_handler, I(offsetof(Config,savelines)), I(-1));
+ ctrl_checkbox(s, "Display scrollbar", 'd',
+ HELPCTX(window_scrollback),
+ dlg_stdcheckbox_handler, I(offsetof(Config,scrollbar)));
+ ctrl_checkbox(s, "Display scrollbar in full screen mode", 'i',
+ HELPCTX(window_scrollback),
+ dlg_stdcheckbox_handler,
+ I(offsetof(Config,scrollbar_in_fullscreen)));
+ ctrl_checkbox(s, "Reset scrollback on keypress", 'k',
+ HELPCTX(window_scrollback),
+ dlg_stdcheckbox_handler, I(offsetof(Config,scroll_on_key)));
+ ctrl_checkbox(s, "Reset scrollback on display activity", 'p',
+ HELPCTX(window_scrollback),
+ dlg_stdcheckbox_handler, I(offsetof(Config,scroll_on_disp)));
+
+ /*
+ * The Window/Appearance panel.
+ */
+ ctrl_settitle(b, "Window/Appearance",
+ "Configure the appearance of PuTTY's window");
+
+ s = ctrl_getset(b, "Window/Appearance", "cursor",
+ "Adjust the use of the cursor");
+ ctrl_radiobuttons(s, "Cursor appearance:", NO_SHORTCUT, 3,
+ HELPCTX(appearance_cursor),
+ dlg_stdradiobutton_handler,
+ I(offsetof(Config, cursor_type)),
+ "Block", 'l', I(0),
+ "Underline", 'u', I(1),
+ "Vertical line", 'v', I(2), NULL);
+ ctrl_checkbox(s, "Cursor blinks", 'b',
+ HELPCTX(appearance_cursor),
+ dlg_stdcheckbox_handler, I(offsetof(Config,blink_cur)));
+
+ s = ctrl_getset(b, "Window/Appearance", "font",
+ "Font settings");
+ ctrl_fontsel(s, "Font used in the terminal window", 'n',
+ HELPCTX(appearance_font),
+ dlg_stdfontsel_handler, I(offsetof(Config, font)));
+
+ s = ctrl_getset(b, "Window/Appearance", "mouse",
+ "Adjust the use of the mouse pointer");
+ ctrl_checkbox(s, "Hide mouse pointer when typing in window", 'p',
+ HELPCTX(appearance_hidemouse),
+ dlg_stdcheckbox_handler, I(offsetof(Config,hide_mouseptr)));
+
+ s = ctrl_getset(b, "Window/Appearance", "border",
+ "Adjust the window border");
+ ctrl_editbox(s, "Gap between text and window edge:", NO_SHORTCUT, 20,
+ HELPCTX(appearance_border),
+ dlg_stdeditbox_handler,
+ I(offsetof(Config,window_border)), I(-1));
+
+ /*
+ * The Window/Behaviour panel.
+ */
+ ctrl_settitle(b, "Window/Behaviour",
+ "Configure the behaviour of PuTTY's window");
+
+ s = ctrl_getset(b, "Window/Behaviour", "title",
+ "Adjust the behaviour of the window title");
+ ctrl_editbox(s, "Window title:", 't', 100,
+ HELPCTX(appearance_title),
+ dlg_stdeditbox_handler, I(offsetof(Config,wintitle)),
+ I(sizeof(((Config *)0)->wintitle)));
+ ctrl_checkbox(s, "Separate window and icon titles", 'i',
+ HELPCTX(appearance_title),
+ dlg_stdcheckbox_handler,
+ I(CHECKBOX_INVERT | offsetof(Config,win_name_always)));
+
+ s = ctrl_getset(b, "Window/Behaviour", "main", NULL);
+ ctrl_checkbox(s, "Warn before closing window", 'w',
+ HELPCTX(behaviour_closewarn),
+ dlg_stdcheckbox_handler, I(offsetof(Config,warn_on_close)));
+
+ /*
+ * The Window/Translation panel.
+ */
+ ctrl_settitle(b, "Window/Translation",
+ "Options controlling character set translation");
+
+ s = ctrl_getset(b, "Window/Translation", "trans",
+ "Character set translation on received data");
+ ctrl_combobox(s, "Received data assumed to be in which character set:",
+ 'r', 100, HELPCTX(translation_codepage),
+ codepage_handler, P(NULL), P(NULL));
+
+ s = ctrl_getset(b, "Window/Translation", "linedraw",
+ "Adjust how PuTTY displays line drawing characters");
+ ctrl_radiobuttons(s, "Handling of line drawing characters:", NO_SHORTCUT,1,
+ HELPCTX(translation_linedraw),
+ dlg_stdradiobutton_handler,
+ I(offsetof(Config, vtmode)),
+ "Font has XWindows encoding", 'x', I(VT_XWINDOWS),
+ "Poor man's line drawing (+, - and |)",'p',I(VT_POORMAN),
+ "Unicode mode", 'u', I(VT_UNICODE), NULL);
+
+ /*
+ * The Window/Selection panel.
+ */
+ ctrl_settitle(b, "Window/Selection", "Options controlling copy and paste");
+
+ s = ctrl_getset(b, "Window/Selection", "trans",
+ "Translation of pasted characters");
+ ctrl_checkbox(s, "Don't translate line drawing chars into +, - and |",'d',
+ HELPCTX(selection_linedraw),
+ dlg_stdcheckbox_handler, I(offsetof(Config,rawcnp)));
+
+ s = ctrl_getset(b, "Window/Selection", "mouse",
+ "Control use of mouse");
+ ctrl_checkbox(s, "Shift overrides application's use of mouse", 'p',
+ HELPCTX(selection_shiftdrag),
+ dlg_stdcheckbox_handler, I(offsetof(Config,mouse_override)));
+ ctrl_radiobuttons(s,
+ "Default selection mode (Alt+drag does the other one):",
+ NO_SHORTCUT, 2,
+ HELPCTX(selection_rect),
+ dlg_stdradiobutton_handler,
+ I(offsetof(Config, rect_select)),
+ "Normal", 'n', I(0),
+ "Rectangular block", 'r', I(1), NULL);
+
+ s = ctrl_getset(b, "Window/Selection", "charclass",
+ "Control the select-one-word-at-a-time mode");
+ ccd = (struct charclass_data *)
+ ctrl_alloc(b, sizeof(struct charclass_data));
+ ccd->listbox = ctrl_listbox(s, "Character classes:", 'e',
+ HELPCTX(selection_charclasses),
+ charclass_handler, P(ccd));
+ ccd->listbox->listbox.multisel = 1;
+ ccd->listbox->listbox.ncols = 4;
+ ccd->listbox->listbox.percentages = smalloc(4*sizeof(int));
+ ccd->listbox->listbox.percentages[0] = 15;
+ ccd->listbox->listbox.percentages[1] = 25;
+ ccd->listbox->listbox.percentages[2] = 20;
+ ccd->listbox->listbox.percentages[3] = 40;
+ ctrl_columns(s, 2, 67, 33);
+ ccd->editbox = ctrl_editbox(s, "Set to class", 't', 50,
+ HELPCTX(selection_charclasses),
+ charclass_handler, P(ccd), P(NULL));
+ ccd->editbox->generic.column = 0;
+ ccd->button = ctrl_pushbutton(s, "Set", 's',
+ HELPCTX(selection_charclasses),
+ charclass_handler, P(ccd));
+ ccd->button->generic.column = 1;
+ ctrl_columns(s, 1, 100);
+
+ /*
+ * The Window/Colours panel.
+ */
+ ctrl_settitle(b, "Window/Colours", "Options controlling use of colours");
+
+ s = ctrl_getset(b, "Window/Colours", "general",
+ "General options for colour usage");
+ ctrl_checkbox(s, "Bolded text is a different colour", 'b',
+ HELPCTX(colours_bold),
+ dlg_stdcheckbox_handler, I(offsetof(Config,bold_colour)));
+
+ s = ctrl_getset(b, "Window/Colours", "adjust",
+ "Adjust the precise colours PuTTY displays");
+ ctrl_text(s, "Select a colour from the list, and then click the"
+ " Modify button to change its appearance.",
+ HELPCTX(colours_config));
+ ctrl_columns(s, 2, 67, 33);
+ cd = (struct colour_data *)ctrl_alloc(b, sizeof(struct colour_data));
+ cd->listbox = ctrl_listbox(s, "Select a colour to adjust:", 'u',
+ HELPCTX(colours_config), colour_handler, P(cd));
+ cd->listbox->generic.column = 0;
+ c = ctrl_text(s, "RGB value:", HELPCTX(colours_config));
+ c->generic.column = 1;
+ cd->rgbtext = ctrl_text(s, "00/00/00", HELPCTX(colours_config));
+ cd->rgbtext->generic.column = 1;
+ cd->button = ctrl_pushbutton(s, "Modify", 'm', HELPCTX(colours_config),
+ colour_handler, P(cd));
+ cd->button->generic.column = 1;
+ ctrl_columns(s, 1, 100);
+
+ /*
+ * The Connection panel.
+ */
+ ctrl_settitle(b, "Connection", "Options controlling the connection");
+
+ if (!midsession) {
+ s = ctrl_getset(b, "Connection", "data", "Data to send to the server");
+ ctrl_editbox(s, "Terminal-type string", 't', 50,
+ HELPCTX(connection_termtype),
+ dlg_stdeditbox_handler, I(offsetof(Config,termtype)),
+ I(sizeof(((Config *)0)->termtype)));
+ ctrl_editbox(s, "Auto-login username", 'u', 50,
+ HELPCTX(connection_username),
+ dlg_stdeditbox_handler, I(offsetof(Config,username)),
+ I(sizeof(((Config *)0)->username)));
+ }
+
+ s = ctrl_getset(b, "Connection", "keepalive",
+ "Sending of null packets to keep session active");
+ ctrl_editbox(s, "Seconds between keepalives (0 to turn off)", 'k', 20,
+ HELPCTX(connection_keepalive),
+ dlg_stdeditbox_handler, I(offsetof(Config,ping_interval)),
+ I(-1));
+
+ if (!midsession) {
+ s = ctrl_getset(b, "Connection", "tcp",
+ "Low-level TCP connection options");
+ ctrl_checkbox(s, "Disable Nagle's algorithm (TCP_NODELAY option)", 'n',
+ HELPCTX(connection_nodelay),
+ dlg_stdcheckbox_handler,
+ I(offsetof(Config,tcp_nodelay)));
+ }
+
+ if (!midsession) {
+ /*
+ * The Connection/Proxy panel.
+ */
+ ctrl_settitle(b, "Connection/Proxy",
+ "Options controlling proxy usage");
+
+ s = ctrl_getset(b, "Connection/Proxy", "basics", "Proxy basics");
+ ctrl_radiobuttons(s, "Proxy type:", NO_SHORTCUT, 4,
+ HELPCTX(proxy_type),
+ dlg_stdradiobutton_handler,
+ I(offsetof(Config, proxy_type)),
+ "None", 'n', I(PROXY_NONE),
+ "HTTP", 't', I(PROXY_HTTP),
+ "SOCKS", 's', I(PROXY_SOCKS),
+ "Telnet", 'l', I(PROXY_TELNET),
+ NULL);
+ ctrl_columns(s, 2, 80, 20);
+ c = ctrl_editbox(s, "Proxy hostname", 'y', 100,
+ HELPCTX(proxy_main),
+ dlg_stdeditbox_handler,
+ I(offsetof(Config,proxy_host)),
+ I(sizeof(((Config *)0)->proxy_host)));
+ c->generic.column = 0;
+ c = ctrl_editbox(s, "Port", 'p', 100,
+ HELPCTX(proxy_main),
+ dlg_stdeditbox_handler,
+ I(offsetof(Config,proxy_port)),
+ I(-1));
+ c->generic.column = 1;
+ ctrl_columns(s, 1, 100);
+ ctrl_editbox(s, "Exclude Hosts/IPs", 'e', 100,
+ HELPCTX(proxy_exclude),
+ dlg_stdeditbox_handler,
+ I(offsetof(Config,proxy_exclude_list)),
+ I(sizeof(((Config *)0)->proxy_exclude_list)));
+ ctrl_checkbox(s, "Consider proxying local host connections", 'x',
+ HELPCTX(proxy_exclude),
+ dlg_stdcheckbox_handler,
+ I(offsetof(Config,even_proxy_localhost)));
+ ctrl_radiobuttons(s, "Do DNS name lookup at proxy end:", 'd', 3,
+ HELPCTX(proxy_dns),
+ dlg_stdradiobutton_handler,
+ I(offsetof(Config, proxy_dns)),
+ "No", I(FORCE_OFF),
+ "Auto", I(AUTO),
+ "Yes", I(FORCE_ON), NULL);
+ ctrl_editbox(s, "Username", 'u', 60,
+ HELPCTX(proxy_auth),
+ dlg_stdeditbox_handler,
+ I(offsetof(Config,proxy_username)),
+ I(sizeof(((Config *)0)->proxy_username)));
+ c = ctrl_editbox(s, "Password", 'w', 60,
+ HELPCTX(proxy_auth),
+ dlg_stdeditbox_handler,
+ I(offsetof(Config,proxy_password)),
+ I(sizeof(((Config *)0)->proxy_password)));
+ c->editbox.password = 1;
+
+ s = ctrl_getset(b, "Connection/Proxy", "misc",
+ "Miscellaneous proxy settings");
+ ctrl_editbox(s, "Telnet command", 'm', 100,
+ HELPCTX(proxy_command),
+ dlg_stdeditbox_handler,
+ I(offsetof(Config,proxy_telnet_command)),
+ I(sizeof(((Config *)0)->proxy_telnet_command)));
+ ctrl_radiobuttons(s, "SOCKS Version", 'v', 2,
+ HELPCTX(proxy_socksver),
+ dlg_stdradiobutton_handler,
+ I(offsetof(Config, proxy_socks_version)),
+ "Version 5", I(5), "Version 4", I(4), NULL);
+ }
+
+ /*
+ * The Telnet panel exists in the base config box, and in a
+ * mid-session reconfig box _if_ we're using Telnet.
+ */
+ if (!midsession || protocol == PROT_TELNET) {
+ /*
+ * The Connection/Telnet panel.
+ */
+ ctrl_settitle(b, "Connection/Telnet",
+ "Options controlling Telnet connections");
+
+ if (!midsession) {
+ s = ctrl_getset(b, "Connection/Telnet", "data",
+ "Data to send to the server");
+ ctrl_editbox(s, "Terminal-speed string", 's', 50,
+ HELPCTX(telnet_termspeed),
+ dlg_stdeditbox_handler, I(offsetof(Config,termspeed)),
+ I(sizeof(((Config *)0)->termspeed)));
+ ctrl_text(s, "Environment variables:", HELPCTX(telnet_environ));
+ ctrl_columns(s, 2, 80, 20);
+ ed = (struct environ_data *)
+ ctrl_alloc(b, sizeof(struct environ_data));
+ ed->varbox = ctrl_editbox(s, "Variable", 'v', 60,
+ HELPCTX(telnet_environ),
+ environ_handler, P(ed), P(NULL));
+ ed->varbox->generic.column = 0;
+ ed->valbox = ctrl_editbox(s, "Value", 'l', 60,
+ HELPCTX(telnet_environ),
+ environ_handler, P(ed), P(NULL));
+ ed->valbox->generic.column = 0;
+ ed->addbutton = ctrl_pushbutton(s, "Add", 'd',
+ HELPCTX(telnet_environ),
+ environ_handler, P(ed));
+ ed->addbutton->generic.column = 1;
+ ed->rembutton = ctrl_pushbutton(s, "Remove", 'r',
+ HELPCTX(telnet_environ),
+ environ_handler, P(ed));
+ ed->rembutton->generic.column = 1;
+ ctrl_columns(s, 1, 100);
+ ed->listbox = ctrl_listbox(s, NULL, NO_SHORTCUT,
+ HELPCTX(telnet_environ),
+ environ_handler, P(ed));
+ ed->listbox->listbox.height = 3;
+ }
+
+ s = ctrl_getset(b, "Connection/Telnet", "protocol",
+ "Telnet protocol adjustments");
+
+ if (!midsession) {
+ ctrl_radiobuttons(s, "Handling of OLD_ENVIRON ambiguity:",
+ NO_SHORTCUT, 2,
+ HELPCTX(telnet_oldenviron),
+ dlg_stdradiobutton_handler,
+ I(offsetof(Config, rfc_environ)),
+ "BSD (commonplace)", 'b', I(0),
+ "RFC 1408 (unusual)", 'f', I(1), NULL);
+ ctrl_radiobuttons(s, "Telnet negotiation mode:", 't', 2,
+ HELPCTX(telnet_passive),
+ dlg_stdradiobutton_handler,
+ I(offsetof(Config, passive_telnet)),
+ "Passive", I(1), "Active", I(0), NULL);
+ }
+ ctrl_checkbox(s, "Keyboard sends telnet Backspace and Interrupt", 'k',
+ HELPCTX(telnet_specialkeys),
+ dlg_stdcheckbox_handler,
+ I(offsetof(Config,telnet_keyboard)));
+ ctrl_checkbox(s, "Return key sends telnet New Line instead of ^M",
+ NO_SHORTCUT, HELPCTX(telnet_newline),
+ dlg_stdcheckbox_handler,
+ I(offsetof(Config,telnet_newline)));
+ }
+
+ if (!midsession) {
+
+ /*
+ * The Connection/Rlogin panel.
+ */
+ ctrl_settitle(b, "Connection/Rlogin",
+ "Options controlling Rlogin connections");
+
+ s = ctrl_getset(b, "Connection/Rlogin", "data",
+ "Data to send to the server");
+ ctrl_editbox(s, "Terminal-speed string", 's', 50,
+ HELPCTX(rlogin_termspeed),
+ dlg_stdeditbox_handler, I(offsetof(Config,termspeed)),
+ I(sizeof(((Config *)0)->termspeed)));
+ ctrl_editbox(s, "Local username:", 'l', 50,
+ HELPCTX(rlogin_localuser),
+ dlg_stdeditbox_handler, I(offsetof(Config,localusername)),
+ I(sizeof(((Config *)0)->localusername)));
+
+ }
+
+ /*
+ * All the SSH stuff is omitted in PuTTYtel.
+ */
+
+ if (!midsession && backends[3].backend != NULL) {
+
+ /*
+ * The Connection/SSH panel.
+ */
+ ctrl_settitle(b, "Connection/SSH",
+ "Options controlling SSH connections");
+
+ s = ctrl_getset(b, "Connection/SSH", "data",
+ "Data to send to the server");
+ ctrl_editbox(s, "Remote command:", 'r', 100,
+ HELPCTX(ssh_command),
+ dlg_stdeditbox_handler, I(offsetof(Config,remote_cmd)),
+ I(sizeof(((Config *)0)->remote_cmd)));
+
+ s = ctrl_getset(b, "Connection/SSH", "protocol", "Protocol options");
+ ctrl_checkbox(s, "Don't allocate a pseudo-terminal", 'p',
+ HELPCTX(ssh_nopty),
+ dlg_stdcheckbox_handler,
+ I(offsetof(Config,nopty)));
+ ctrl_checkbox(s, "Enable compression", 'e',
+ HELPCTX(ssh_compress),
+ dlg_stdcheckbox_handler,
+ I(offsetof(Config,compression)));
+ ctrl_radiobuttons(s, "Preferred SSH protocol version:", NO_SHORTCUT, 4,
+ HELPCTX(ssh_protocol),
+ dlg_stdradiobutton_handler,
+ I(offsetof(Config, sshprot)),
+ "1 only", 'l', I(0),
+ "1", '1', I(1),
+ "2", '2', I(2),
+ "2 only", 'n', I(3), NULL);
+
+ s = ctrl_getset(b, "Connection/SSH", "encryption", "Encryption options");
+ ctrl_draglist(s, "Encryption cipher selection policy:", 's',
+ HELPCTX(ssh_ciphers),
+ cipherlist_handler, P(NULL));
+ ctrl_checkbox(s, "Enable non-standard use of single-DES in SSH 2", 'i',
+ HELPCTX(ssh_ciphers),
+ dlg_stdcheckbox_handler,
+ I(offsetof(Config,ssh2_des_cbc)));
+
+ /*
+ * The Connection/SSH/Auth panel.
+ */
+ ctrl_settitle(b, "Connection/SSH/Auth",
+ "Options controlling SSH authentication");
+
+ s = ctrl_getset(b, "Connection/SSH/Auth", "methods",
+ "Authentication methods");
+ ctrl_checkbox(s, "Attempt TIS or CryptoCard auth (SSH1)", 'm',
+ HELPCTX(ssh_auth_tis),
+ dlg_stdcheckbox_handler,
+ I(offsetof(Config,try_tis_auth)));
+ ctrl_checkbox(s, "Attempt \"keyboard-interactive\" auth (SSH2)",
+ 'i', HELPCTX(ssh_auth_ki),
+ dlg_stdcheckbox_handler,
+ I(offsetof(Config,try_ki_auth)));
+
+ s = ctrl_getset(b, "Connection/SSH/Auth", "params",
+ "Authentication parameters");
+ ctrl_checkbox(s, "Allow agent forwarding", 'f',
+ HELPCTX(ssh_auth_agentfwd),
+ dlg_stdcheckbox_handler, I(offsetof(Config,agentfwd)));
+ ctrl_checkbox(s, "Allow attempted changes of username in SSH2", 'u',
+ HELPCTX(ssh_auth_changeuser),
+ dlg_stdcheckbox_handler,
+ I(offsetof(Config,change_username)));
+ ctrl_filesel(s, "Private key file for authentication:", 'k',
+ FILTER_KEY_FILES, FALSE, "Select private key file",
+ HELPCTX(ssh_auth_privkey),
+ dlg_stdfilesel_handler, I(offsetof(Config, keyfile)));
+
+ /*
+ * The Connection/SSH/Tunnels panel.
+ */
+ ctrl_settitle(b, "Connection/SSH/Tunnels",
+ "Options controlling SSH tunnelling");
+
+ s = ctrl_getset(b, "Connection/SSH/Tunnels", "x11", "X11 forwarding");
+ ctrl_checkbox(s, "Enable X11 forwarding", 'e',
+ HELPCTX(ssh_tunnels_x11),
+ dlg_stdcheckbox_handler,I(offsetof(Config,x11_forward)));
+ ctrl_editbox(s, "X display location", 'x', 50,
+ HELPCTX(ssh_tunnels_x11),
+ dlg_stdeditbox_handler, I(offsetof(Config,x11_display)),
+ I(sizeof(((Config *)0)->x11_display)));
+ ctrl_radiobuttons(s, "Remote X11 authentication protocol", 'u', 2,
+ HELPCTX(ssh_tunnels_x11auth),
+ dlg_stdradiobutton_handler,
+ I(offsetof(Config, x11_auth)),
+ "MIT-Magic-Cookie-1", I(X11_MIT),
+ "XDM-Authorization-1", I(X11_XDM), NULL);
+
+ s = ctrl_getset(b, "Connection/SSH/Tunnels", "portfwd",
+ "Port forwarding");
+ ctrl_checkbox(s, "Local ports accept connections from other hosts",'t',
+ HELPCTX(ssh_tunnels_portfwd_localhost),
+ dlg_stdcheckbox_handler,
+ I(offsetof(Config,lport_acceptall)));
+ ctrl_checkbox(s, "Remote ports do the same (SSH v2 only)", 'p',
+ HELPCTX(ssh_tunnels_portfwd_localhost),
+ dlg_stdcheckbox_handler,
+ I(offsetof(Config,rport_acceptall)));
+
+ ctrl_columns(s, 3, 55, 20, 25);
+ c = ctrl_text(s, "Forwarded ports:", HELPCTX(ssh_tunnels_portfwd));
+ c->generic.column = COLUMN_FIELD(0,2);
+ /* You want to select from the list, _then_ hit Remove. So tab order
+ * should be that way round. */
+ pfd = (struct portfwd_data *)ctrl_alloc(b,sizeof(struct portfwd_data));
+ pfd->rembutton = ctrl_pushbutton(s, "Remove", 'r',
+ HELPCTX(ssh_tunnels_portfwd),
+ portfwd_handler, P(pfd));
+ pfd->rembutton->generic.column = 2;
+ pfd->rembutton->generic.tabdelay = 1;
+ pfd->listbox = ctrl_listbox(s, NULL, NO_SHORTCUT,
+ HELPCTX(ssh_tunnels_portfwd),
+ portfwd_handler, P(pfd));
+ pfd->listbox->listbox.height = 3;
+ ctrl_tabdelay(s, pfd->rembutton);
+ ctrl_text(s, "Add new forwarded port:", HELPCTX(ssh_tunnels_portfwd));
+ /* You want to enter source, destination and type, _then_ hit Add.
+ * Again, we adjust the tab order to reflect this. */
+ pfd->addbutton = ctrl_pushbutton(s, "Add", 'd',
+ HELPCTX(ssh_tunnels_portfwd),
+ portfwd_handler, P(pfd));
+ pfd->addbutton->generic.column = 2;
+ pfd->addbutton->generic.tabdelay = 1;
+ pfd->sourcebox = ctrl_editbox(s, "Source port", 's', 40,
+ HELPCTX(ssh_tunnels_portfwd),
+ portfwd_handler, P(pfd), P(NULL));
+ pfd->sourcebox->generic.column = 0;
+ pfd->destbox = ctrl_editbox(s, "Destination", 'i', 67,
+ HELPCTX(ssh_tunnels_portfwd),
+ portfwd_handler, P(pfd), P(NULL));
+ pfd->direction = ctrl_radiobuttons(s, NULL, NO_SHORTCUT, 2,
+ HELPCTX(ssh_tunnels_portfwd),
+ portfwd_handler, P(pfd),
+ "Local", 'l', P(NULL),
+ "Remote", 'm', P(NULL), NULL);
+ ctrl_tabdelay(s, pfd->addbutton);
+ ctrl_columns(s, 1, 100);
+
+ /*
+ * The Connection/SSH/Bugs panel.
+ */
+ ctrl_settitle(b, "Connection/SSH/Bugs",
+ "Workarounds for SSH server bugs");
+
+ s = ctrl_getset(b, "Connection/SSH/Bugs", "main",
+ "Detection of known bugs in SSH servers");
+ ctrl_droplist(s, "Chokes on SSH1 ignore messages", 'i', 20,
+ HELPCTX(ssh_bugs_ignore1),
+ sshbug_handler, I(offsetof(Config,sshbug_ignore1)));
+ ctrl_droplist(s, "Refuses all SSH1 password camouflage", 's', 20,
+ HELPCTX(ssh_bugs_plainpw1),
+ sshbug_handler, I(offsetof(Config,sshbug_plainpw1)));
+ ctrl_droplist(s, "Chokes on SSH1 RSA authentication", 'r', 20,
+ HELPCTX(ssh_bugs_rsa1),
+ sshbug_handler, I(offsetof(Config,sshbug_rsa1)));
+ ctrl_droplist(s, "Miscomputes SSH2 HMAC keys", 'm', 20,
+ HELPCTX(ssh_bugs_hmac2),
+ sshbug_handler, I(offsetof(Config,sshbug_hmac2)));
+ ctrl_droplist(s, "Miscomputes SSH2 encryption keys", 'e', 20,
+ HELPCTX(ssh_bugs_derivekey2),
+ sshbug_handler, I(offsetof(Config,sshbug_derivekey2)));
+ ctrl_droplist(s, "Requires padding on SSH2 RSA signatures", 'p', 20,
+ HELPCTX(ssh_bugs_rsapad2),
+ sshbug_handler, I(offsetof(Config,sshbug_rsapad2)));
+ ctrl_droplist(s, "Chokes on Diffie-Hellman group exchange", 'd', 20,
+ HELPCTX(ssh_bugs_dhgex2),
+ sshbug_handler, I(offsetof(Config,sshbug_dhgex2)));
+ ctrl_droplist(s, "Misuses the session ID in PK auth", 'n', 20,
+ HELPCTX(ssh_bugs_pksessid2),
+ sshbug_handler, I(offsetof(Config,sshbug_pksessid2)));
+ }
+}
--- /dev/null
+/*
+ * dialog.c - a reasonably platform-independent mechanism for
+ * describing dialog boxes.
+ */
+
+#include <assert.h>
+#include <limits.h>
+#include <stdarg.h>
+
+#define DEFINE_INTORPTR_FNS
+
+#include "putty.h"
+#include "dialog.h"
+
+int ctrl_path_elements(char *path)
+{
+ int i = 1;
+ while (*path) {
+ if (*path == '/') i++;
+ path++;
+ }
+ return i;
+}
+
+/* Return the number of matching path elements at the starts of p1 and p2,
+ * or INT_MAX if the paths are identical. */
+int ctrl_path_compare(char *p1, char *p2)
+{
+ int i = 0;
+ while (*p1 || *p2) {
+ if ((*p1 == '/' || *p1 == '\0') &&
+ (*p2 == '/' || *p2 == '\0'))
+ i++; /* a whole element matches, ooh */
+ if (*p1 != *p2)
+ return i; /* mismatch */
+ p1++, p2++;
+ }
+ return INT_MAX; /* exact match */
+}
+
+struct controlbox *ctrl_new_box(void)
+{
+ struct controlbox *ret = smalloc(sizeof(struct controlbox));
+
+ ret->nctrlsets = ret->ctrlsetsize = 0;
+ ret->ctrlsets = NULL;
+ ret->nfrees = ret->freesize = 0;
+ ret->frees = NULL;
+
+ return ret;
+}
+
+void ctrl_free_box(struct controlbox *b)
+{
+ int i;
+
+ for (i = 0; i < b->nctrlsets; i++) {
+ ctrl_free_set(b->ctrlsets[i]);
+ }
+ for (i = 0; i < b->nfrees; i++)
+ sfree(b->frees[i]);
+ sfree(b->ctrlsets);
+ sfree(b->frees);
+ sfree(b);
+}
+
+void ctrl_free_set(struct controlset *s)
+{
+ int i;
+
+ sfree(s->pathname);
+ sfree(s->boxname);
+ sfree(s->boxtitle);
+ for (i = 0; i < s->ncontrols; i++) {
+ ctrl_free(s->ctrls[i]);
+ }
+ sfree(s->ctrls);
+ sfree(s);
+}
+
+/*
+ * Find the index of first controlset in a controlbox for a given
+ * path. If that path doesn't exist, return the index where it
+ * should be inserted.
+ */
+static int ctrl_find_set(struct controlbox *b, char *path, int start)
+{
+ int i, last, thisone;
+
+ last = 0;
+ for (i = 0; i < b->nctrlsets; i++) {
+ thisone = ctrl_path_compare(path, b->ctrlsets[i]->pathname);
+ /*
+ * If `start' is true and there exists a controlset with
+ * exactly the path we've been given, we should return the
+ * index of the first such controlset we find. Otherwise,
+ * we should return the index of the first entry in which
+ * _fewer_ path elements match than they did last time.
+ */
+ if ((start && thisone == INT_MAX) || thisone < last)
+ return i;
+ last = thisone;
+ }
+ return b->nctrlsets; /* insert at end */
+}
+
+/*
+ * Find the index of next controlset in a controlbox for a given
+ * path, or -1 if no such controlset exists. If -1 is passed as
+ * input, finds the first.
+ */
+int ctrl_find_path(struct controlbox *b, char *path, int index)
+{
+ if (index < 0)
+ index = ctrl_find_set(b, path, 1);
+ else
+ index++;
+
+ if (index < b->nctrlsets && !strcmp(path, b->ctrlsets[index]->pathname))
+ return index;
+ else
+ return -1;
+}
+
+/* Set up a panel title. */
+struct controlset *ctrl_settitle(struct controlbox *b,
+ char *path, char *title)
+{
+
+ struct controlset *s = smalloc(sizeof(struct controlset));
+ int index = ctrl_find_set(b, path, 1);
+ s->pathname = dupstr(path);
+ s->boxname = NULL;
+ s->boxtitle = dupstr(title);
+ s->ncontrols = s->ctrlsize = 0;
+ s->ncolumns = 0; /* this is a title! */
+ s->ctrls = NULL;
+ if (b->nctrlsets >= b->ctrlsetsize) {
+ b->ctrlsetsize = b->nctrlsets + 32;
+ b->ctrlsets = srealloc(b->ctrlsets,
+ b->ctrlsetsize*sizeof(*b->ctrlsets));
+ }
+ if (index < b->nctrlsets)
+ memmove(&b->ctrlsets[index+1], &b->ctrlsets[index],
+ (b->nctrlsets-index) * sizeof(*b->ctrlsets));
+ b->ctrlsets[index] = s;
+ b->nctrlsets++;
+ return s;
+}
+
+/* Retrieve a pointer to a controlset, creating it if absent. */
+struct controlset *ctrl_getset(struct controlbox *b,
+ char *path, char *name, char *boxtitle)
+{
+ struct controlset *s;
+ int index = ctrl_find_set(b, path, 1);
+ while (index < b->nctrlsets &&
+ !strcmp(b->ctrlsets[index]->pathname, path)) {
+ if (b->ctrlsets[index]->boxname &&
+ !strcmp(b->ctrlsets[index]->boxname, name))
+ return b->ctrlsets[index];
+ index++;
+ }
+ s = smalloc(sizeof(struct controlset));
+ s->pathname = dupstr(path);
+ s->boxname = dupstr(name);
+ s->boxtitle = boxtitle ? dupstr(boxtitle) : NULL;
+ s->ncolumns = 1;
+ s->ncontrols = s->ctrlsize = 0;
+ s->ctrls = NULL;
+ if (b->nctrlsets >= b->ctrlsetsize) {
+ b->ctrlsetsize = b->nctrlsets + 32;
+ b->ctrlsets = srealloc(b->ctrlsets,
+ b->ctrlsetsize*sizeof(*b->ctrlsets));
+ }
+ if (index < b->nctrlsets)
+ memmove(&b->ctrlsets[index+1], &b->ctrlsets[index],
+ (b->nctrlsets-index) * sizeof(*b->ctrlsets));
+ b->ctrlsets[index] = s;
+ b->nctrlsets++;
+ return s;
+}
+
+/* Allocate some private data in a controlbox. */
+void *ctrl_alloc(struct controlbox *b, size_t size)
+{
+ void *p;
+ p = smalloc(size);
+ if (b->nfrees >= b->freesize) {
+ b->freesize = b->nfrees + 32;
+ b->frees = srealloc(b->frees, b->freesize*sizeof(*b->frees));
+ }
+ b->frees[b->nfrees++] = p;
+ return p;
+}
+
+static union control *ctrl_new(struct controlset *s, int type,
+ intorptr helpctx, handler_fn handler,
+ intorptr context)
+{
+ union control *c = smalloc(sizeof(union control));
+ if (s->ncontrols >= s->ctrlsize) {
+ s->ctrlsize = s->ncontrols + 32;
+ s->ctrls = srealloc(s->ctrls, s->ctrlsize * sizeof(*s->ctrls));
+ }
+ s->ctrls[s->ncontrols++] = c;
+ /*
+ * Fill in the standard fields.
+ */
+ c->generic.type = type;
+ c->generic.tabdelay = 0;
+ c->generic.column = COLUMN_FIELD(0, s->ncolumns);
+ c->generic.helpctx = helpctx;
+ c->generic.handler = handler;
+ c->generic.context = context;
+ c->generic.label = NULL;
+ return c;
+}
+
+/* `ncolumns' is followed by that many percentages, as integers. */
+union control *ctrl_columns(struct controlset *s, int ncolumns, ...)
+{
+ union control *c = ctrl_new(s, CTRL_COLUMNS, P(NULL), NULL, P(NULL));
+ assert(s->ncolumns == 1 || ncolumns == 1);
+ c->columns.ncols = ncolumns;
+ s->ncolumns = ncolumns;
+ if (ncolumns == 1) {
+ c->columns.percentages = NULL;
+ } else {
+ va_list ap;
+ int i;
+ c->columns.percentages = smalloc(ncolumns * sizeof(int));
+ va_start(ap, ncolumns);
+ for (i = 0; i < ncolumns; i++)
+ c->columns.percentages[i] = va_arg(ap, int);
+ va_end(ap);
+ }
+ return c;
+}
+
+union control *ctrl_editbox(struct controlset *s, char *label, char shortcut,
+ int percentage,
+ intorptr helpctx, handler_fn handler,
+ intorptr context, intorptr context2)
+{
+ union control *c = ctrl_new(s, CTRL_EDITBOX, helpctx, handler, context);
+ c->editbox.label = label ? dupstr(label) : NULL;
+ c->editbox.shortcut = shortcut;
+ c->editbox.percentwidth = percentage;
+ c->editbox.password = 0;
+ c->editbox.has_list = 0;
+ c->editbox.context2 = context2;
+ return c;
+}
+
+union control *ctrl_combobox(struct controlset *s, char *label, char shortcut,
+ int percentage,
+ intorptr helpctx, handler_fn handler,
+ intorptr context, intorptr context2)
+{
+ union control *c = ctrl_new(s, CTRL_EDITBOX, helpctx, handler, context);
+ c->editbox.label = label ? dupstr(label) : NULL;
+ c->editbox.shortcut = shortcut;
+ c->editbox.percentwidth = percentage;
+ c->editbox.password = 0;
+ c->editbox.has_list = 1;
+ c->editbox.context2 = context2;
+ return c;
+}
+
+/*
+ * `ncolumns' is followed by (alternately) radio button titles and
+ * intorptrs, until a NULL in place of a title string is seen. Each
+ * title is expected to be followed by a shortcut _iff_ `shortcut'
+ * is NO_SHORTCUT.
+ */
+union control *ctrl_radiobuttons(struct controlset *s, char *label,
+ char shortcut, int ncolumns, intorptr helpctx,
+ handler_fn handler, intorptr context, ...)
+{
+ va_list ap;
+ int i;
+ union control *c = ctrl_new(s, CTRL_RADIO, helpctx, handler, context);
+ c->radio.label = label ? dupstr(label) : NULL;
+ c->radio.shortcut = shortcut;
+ c->radio.ncolumns = ncolumns;
+ /*
+ * Initial pass along variable argument list to count the
+ * buttons.
+ */
+ va_start(ap, context);
+ i = 0;
+ while (va_arg(ap, char *) != NULL) {
+ i++;
+ if (c->radio.shortcut == NO_SHORTCUT)
+ va_arg(ap, int); /* char promotes to int in arg lists */
+ va_arg(ap, intorptr);
+ }
+ va_end(ap);
+ c->radio.nbuttons = i;
+ if (c->radio.shortcut == NO_SHORTCUT)
+ c->radio.shortcuts = smalloc(c->radio.nbuttons * sizeof(char));
+ else
+ c->radio.shortcuts = NULL;
+ c->radio.buttons = smalloc(c->radio.nbuttons * sizeof(char *));
+ c->radio.buttondata = smalloc(c->radio.nbuttons * sizeof(intorptr));
+ /*
+ * Second pass along variable argument list to actually fill in
+ * the structure.
+ */
+ va_start(ap, context);
+ for (i = 0; i < c->radio.nbuttons; i++) {
+ c->radio.buttons[i] = dupstr(va_arg(ap, char *));
+ if (c->radio.shortcut == NO_SHORTCUT)
+ c->radio.shortcuts[i] = va_arg(ap, int);
+ /* char promotes to int in arg lists */
+ c->radio.buttondata[i] = va_arg(ap, intorptr);
+ }
+ va_end(ap);
+ return c;
+}
+
+union control *ctrl_pushbutton(struct controlset *s,char *label,char shortcut,
+ intorptr helpctx, handler_fn handler,
+ intorptr context)
+{
+ union control *c = ctrl_new(s, CTRL_BUTTON, helpctx, handler, context);
+ c->button.label = label ? dupstr(label) : NULL;
+ c->button.shortcut = shortcut;
+ c->button.isdefault = 0;
+ return c;
+}
+
+union control *ctrl_listbox(struct controlset *s,char *label,char shortcut,
+ intorptr helpctx, handler_fn handler,
+ intorptr context)
+{
+ union control *c = ctrl_new(s, CTRL_LISTBOX, helpctx, handler, context);
+ c->listbox.label = label ? dupstr(label) : NULL;
+ c->listbox.shortcut = shortcut;
+ c->listbox.height = 5; /* *shrug* a plausible default */
+ c->listbox.draglist = 0;
+ c->listbox.multisel = 0;
+ c->listbox.percentwidth = 100;
+ c->listbox.ncols = 0;
+ c->listbox.percentages = NULL;
+ return c;
+}
+
+union control *ctrl_droplist(struct controlset *s, char *label, char shortcut,
+ int percentage, intorptr helpctx,
+ handler_fn handler, intorptr context)
+{
+ union control *c = ctrl_new(s, CTRL_LISTBOX, helpctx, handler, context);
+ c->listbox.label = label ? dupstr(label) : NULL;
+ c->listbox.shortcut = shortcut;
+ c->listbox.height = 0; /* means it's a drop-down list */
+ c->listbox.draglist = 0;
+ c->listbox.multisel = 0;
+ c->listbox.percentwidth = percentage;
+ return c;
+}
+
+union control *ctrl_draglist(struct controlset *s,char *label,char shortcut,
+ intorptr helpctx, handler_fn handler,
+ intorptr context)
+{
+ union control *c = ctrl_new(s, CTRL_LISTBOX, helpctx, handler, context);
+ c->listbox.label = label ? dupstr(label) : NULL;
+ c->listbox.shortcut = shortcut;
+ c->listbox.height = 5; /* *shrug* a plausible default */
+ c->listbox.draglist = 1;
+ c->listbox.multisel = 0;
+ c->listbox.percentwidth = 100;
+ return c;
+}
+
+union control *ctrl_filesel(struct controlset *s,char *label,char shortcut,
+ char const *filter, int write, char *title,
+ intorptr helpctx, handler_fn handler,
+ intorptr context)
+{
+ union control *c = ctrl_new(s, CTRL_FILESELECT, helpctx, handler, context);
+ c->fileselect.label = label ? dupstr(label) : NULL;
+ c->fileselect.shortcut = shortcut;
+ c->fileselect.filter = filter;
+ c->fileselect.for_writing = write;
+ c->fileselect.title = dupstr(title);
+ return c;
+}
+
+union control *ctrl_fontsel(struct controlset *s,char *label,char shortcut,
+ intorptr helpctx, handler_fn handler,
+ intorptr context)
+{
+ union control *c = ctrl_new(s, CTRL_FONTSELECT, helpctx, handler, context);
+ c->fontselect.label = label ? dupstr(label) : NULL;
+ c->fontselect.shortcut = shortcut;
+ return c;
+}
+
+union control *ctrl_tabdelay(struct controlset *s, union control *ctrl)
+{
+ union control *c = ctrl_new(s, CTRL_TABDELAY, P(NULL), NULL, P(NULL));
+ c->tabdelay.ctrl = ctrl;
+ return c;
+}
+
+union control *ctrl_text(struct controlset *s, char *text, intorptr helpctx)
+{
+ union control *c = ctrl_new(s, CTRL_TEXT, helpctx, NULL, P(NULL));
+ c->text.label = dupstr(text);
+ return c;
+}
+
+union control *ctrl_checkbox(struct controlset *s, char *label, char shortcut,
+ intorptr helpctx, handler_fn handler,
+ intorptr context)
+{
+ union control *c = ctrl_new(s, CTRL_CHECKBOX, helpctx, handler, context);
+ c->checkbox.label = label ? dupstr(label) : NULL;
+ c->checkbox.shortcut = shortcut;
+ return c;
+}
+
+void ctrl_free(union control *ctrl)
+{
+ int i;
+
+ sfree(ctrl->generic.label);
+ switch (ctrl->generic.type) {
+ case CTRL_RADIO:
+ for (i = 0; i < ctrl->radio.nbuttons; i++)
+ sfree(ctrl->radio.buttons[i]);
+ sfree(ctrl->radio.buttons);
+ sfree(ctrl->radio.shortcuts);
+ sfree(ctrl->radio.buttondata);
+ break;
+ case CTRL_COLUMNS:
+ sfree(ctrl->columns.percentages);
+ break;
+ case CTRL_LISTBOX:
+ sfree(ctrl->listbox.percentages);
+ break;
+ case CTRL_FILESELECT:
+ sfree(ctrl->fileselect.title);
+ break;
+ }
+ sfree(ctrl);
+}
+
+void dlg_stdradiobutton_handler(union control *ctrl, void *dlg,
+ void *data, int event)
+{
+ int button;
+ /*
+ * For a standard radio button set, the context parameter gives
+ * offsetof(targetfield, Config), and the extra data per button
+ * gives the value the target field should take if that button
+ * is the one selected.
+ */
+ if (event == EVENT_REFRESH) {
+ for (button = 0; button < ctrl->radio.nbuttons; button++)
+ if (*(int *)ATOFFSET(data, ctrl->radio.context.i) ==
+ ctrl->radio.buttondata[button].i)
+ break;
+ /* We expected that `break' to happen, in all circumstances. */
+ assert(button < ctrl->radio.nbuttons);
+ dlg_radiobutton_set(ctrl, dlg, button);
+ } else if (event == EVENT_VALCHANGE) {
+ button = dlg_radiobutton_get(ctrl, dlg);
+ assert(button >= 0 && button < ctrl->radio.nbuttons);
+ *(int *)ATOFFSET(data, ctrl->radio.context.i) =
+ ctrl->radio.buttondata[button].i;
+ }
+}
+
+void dlg_stdcheckbox_handler(union control *ctrl, void *dlg,
+ void *data, int event)
+{
+ int offset, invert;
+
+ /*
+ * For a standard checkbox, the context parameter gives
+ * offsetof(targetfield, Config), optionally ORed with
+ * CHECKBOX_INVERT.
+ */
+ offset = ctrl->checkbox.context.i;
+ if (offset & CHECKBOX_INVERT) {
+ offset &= ~CHECKBOX_INVERT;
+ invert = 1;
+ } else
+ invert = 0;
+
+ /*
+ * C lacks a logical XOR, so the following code uses the idiom
+ * (!a ^ !b) to obtain the logical XOR of a and b. (That is, 1
+ * iff exactly one of a and b is nonzero, otherwise 0.)
+ */
+
+ if (event == EVENT_REFRESH) {
+ dlg_checkbox_set(ctrl,dlg, (!*(int *)ATOFFSET(data,offset) ^ !invert));
+ } else if (event == EVENT_VALCHANGE) {
+ *(int *)ATOFFSET(data, offset) = !dlg_checkbox_get(ctrl,dlg) ^ !invert;
+ }
+}
+
+void dlg_stdeditbox_handler(union control *ctrl, void *dlg,
+ void *data, int event)
+{
+ /*
+ * The standard edit-box handler expects the main `context'
+ * field to contain the `offsetof' a field in the structure
+ * pointed to by `data'. The secondary `context2' field
+ * indicates the type of this field:
+ *
+ * - if context2 > 0, the field is a char array and context2
+ * gives its size.
+ * - if context2 == -1, the field is an int and the edit box
+ * is numeric.
+ * - if context2 < -1, the field is an int and the edit box is
+ * _floating_, and (-context2) gives the scale. (E.g. if
+ * context2 == -1000, then typing 1.2 into the box will set
+ * the field to 1200.)
+ */
+ int offset = ctrl->editbox.context.i;
+ int length = ctrl->editbox.context2.i;
+
+ if (length > 0) {
+ char *field = (char *)ATOFFSET(data, offset);
+ if (event == EVENT_REFRESH) {
+ dlg_editbox_set(ctrl, dlg, field);
+ } else if (event == EVENT_VALCHANGE) {
+ dlg_editbox_get(ctrl, dlg, field, length);
+ }
+ } else if (length < 0) {
+ int *field = (int *)ATOFFSET(data, offset);
+ char data[80];
+ if (event == EVENT_REFRESH) {
+ if (length == -1)
+ sprintf(data, "%d", *field);
+ else
+ sprintf(data, "%g", (double)*field / (double)(-length));
+ dlg_editbox_set(ctrl, dlg, data);
+ } else if (event == EVENT_VALCHANGE) {
+ dlg_editbox_get(ctrl, dlg, data, lenof(data));
+ if (length == -1)
+ *field = atoi(data);
+ else
+ *field = (int)((-length) * atof(data));
+ }
+ }
+}
+
+void dlg_stdfilesel_handler(union control *ctrl, void *dlg,
+ void *data, int event)
+{
+ /*
+ * The standard file-selector handler expects the `context'
+ * field to contain the `offsetof' a Filename field in the
+ * structure pointed to by `data'.
+ */
+ int offset = ctrl->fileselect.context.i;
+
+ if (event == EVENT_REFRESH) {
+ dlg_filesel_set(ctrl, dlg, *(Filename *)ATOFFSET(data, offset));
+ } else if (event == EVENT_VALCHANGE) {
+ dlg_filesel_get(ctrl, dlg, (Filename *)ATOFFSET(data, offset));
+ }
+}
+
+void dlg_stdfontsel_handler(union control *ctrl, void *dlg,
+ void *data, int event)
+{
+ /*
+ * The standard file-selector handler expects the `context'
+ * field to contain the `offsetof' a FontSpec field in the
+ * structure pointed to by `data'.
+ */
+ int offset = ctrl->fontselect.context.i;
+
+ if (event == EVENT_REFRESH) {
+ dlg_fontsel_set(ctrl, dlg, *(FontSpec *)ATOFFSET(data, offset));
+ } else if (event == EVENT_VALCHANGE) {
+ dlg_fontsel_get(ctrl, dlg, (FontSpec *)ATOFFSET(data, offset));
+ }
+}
--- /dev/null
+/*
+ * Exports and types from dialog.c.
+ */
+
+/*
+ * This will come in handy for generic control handlers. Anyone
+ * knows how to make this more portable, let me know :-)
+ */
+#define ATOFFSET(data, offset) ( (void *) ( (char *)(data) + (offset) ) )
+
+/*
+ * This is the big union which defines a single control, of any
+ * type.
+ *
+ * General principles:
+ * - _All_ pointers in this structure are expected to point to
+ * dynamically allocated things, unless otherwise indicated.
+ * - `char' fields giving keyboard shortcuts are expected to be
+ * NO_SHORTCUT if no shortcut is desired for a particular control.
+ * - The `label' field can often be NULL, which will cause the
+ * control to not have a label at all. This doesn't apply to
+ * checkboxes and push buttons, in which the label is not
+ * separate from the control.
+ */
+
+#define NO_SHORTCUT '\0'
+
+enum {
+ CTRL_TEXT, /* just a static line of text */
+ CTRL_EDITBOX, /* label plus edit box */
+ CTRL_RADIO, /* label plus radio buttons */
+ CTRL_CHECKBOX, /* checkbox (contains own label) */
+ CTRL_BUTTON, /* simple push button (no label) */
+ CTRL_LISTBOX, /* label plus list box */
+ CTRL_COLUMNS, /* divide window into columns */
+ CTRL_FILESELECT, /* label plus filename selector */
+ CTRL_FONTSELECT, /* label plus font selector */
+ CTRL_TABDELAY /* see `tabdelay' below */
+};
+
+/*
+ * Many controls have `intorptr' unions for storing user data,
+ * since the user might reasonably want to store either an integer
+ * or a void * pointer. Here I define a union, and two convenience
+ * functions to create that union from actual integers or pointers.
+ *
+ * The convenience functions are declared as inline if possible.
+ * Otherwise, they're declared here and defined when this header is
+ * included with DEFINE_INTORPTR_FNS defined. This is a total pain,
+ * but such is life.
+ */
+typedef union { void *p; int i; } intorptr;
+
+#if defined DEFINE_INTORPTR_FNS || defined INLINE
+#ifdef INLINE
+#define PREFIX INLINE
+#else
+#define PREFIX
+#endif
+PREFIX intorptr I(int i) { intorptr ret; ret.i = i; return ret; }
+PREFIX intorptr P(void *p) { intorptr ret; ret.p = p; return ret; }
+#undef PREFIX
+#else
+intorptr I(int i);
+intorptr P(void *p);
+#endif
+
+/*
+ * Each control has an `int' field specifying which columns it
+ * occupies in a multi-column part of the dialog box. These macros
+ * pack and unpack that field.
+ *
+ * If a control belongs in exactly one column, just specifying the
+ * column number is perfectly adequate.
+ */
+#define COLUMN_FIELD(start, span) ( (((span)-1) << 16) + (start) )
+#define COLUMN_START(field) ( (field) & 0xFFFF )
+#define COLUMN_SPAN(field) ( (((field) >> 16) & 0xFFFF) + 1 )
+
+union control;
+
+/*
+ * The number of event types is being deliberately kept small, on
+ * the grounds that not all platforms might be able to report a
+ * large number of subtle events. We have:
+ * - the special REFRESH event, called when a control's value
+ * needs setting
+ * - the ACTION event, called when the user does something that
+ * positively requests action (double-clicking a list box item,
+ * or pushing a push-button)
+ * - the VALCHANGE event, called when the user alters the setting
+ * of the control in a way that is usually considered to alter
+ * the underlying data (toggling a checkbox or radio button,
+ * moving the items around in a drag-list, editing an edit
+ * control)
+ * - the SELCHANGE event, called when the user alters the setting
+ * of the control in a more minor way (changing the selected
+ * item in a list box).
+ * - the CALLBACK event, which happens after the handler routine
+ * has requested a subdialog (file selector, font selector,
+ * colour selector) and it has come back with information.
+ */
+enum {
+ EVENT_REFRESH,
+ EVENT_ACTION,
+ EVENT_VALCHANGE,
+ EVENT_SELCHANGE,
+ EVENT_CALLBACK
+};
+typedef void (*handler_fn)(union control *ctrl, void *dlg,
+ void *data, int event);
+
+#define STANDARD_PREFIX \
+ int type; \
+ char *label; \
+ int tabdelay; \
+ int column; \
+ handler_fn handler; \
+ intorptr context; \
+ intorptr helpctx
+
+union control {
+ /*
+ * The first possibility in this union is the generic header
+ * shared by all the structures, which we are therefore allowed
+ * to access through any one of them.
+ */
+ struct {
+ int type;
+ /*
+ * Every control except CTRL_COLUMNS has _some_ sort of
+ * label. By putting it in the `generic' union as well as
+ * everywhere else, we avoid having to have an irritating
+ * switch statement when we go through and deallocate all
+ * the memory in a config-box structure.
+ *
+ * Yes, this does mean that any non-NULL value in this
+ * field is expected to be dynamically allocated and
+ * freeable.
+ *
+ * For CTRL_COLUMNS, this field MUST be NULL.
+ */
+ char *label;
+ /*
+ * If `tabdelay' is non-zero, it indicates that this
+ * particular control should not yet appear in the tab
+ * order. A subsequent CTRL_TABDELAY entry will place it.
+ */
+ int tabdelay;
+ /*
+ * Indicate which column(s) this control occupies. This can
+ * be unpacked into starting column and column span by the
+ * COLUMN macros above.
+ */
+ int column;
+ /*
+ * Most controls need to provide a function which gets
+ * called when that control's setting is changed, or when
+ * the control's setting needs initialising.
+ *
+ * The `data' parameter points to the writable data being
+ * modified as a result of the configuration activity; for
+ * example, the PuTTY `Config' structure, although not
+ * necessarily.
+ *
+ * The `dlg' parameter is passed back to the platform-
+ * specific routines to read and write the actual control
+ * state.
+ */
+ handler_fn handler;
+ /*
+ * Almost all of the above functions will find it useful to
+ * be able to store a piece of `void *' or `int' data.
+ */
+ intorptr context;
+ /*
+ * For any control, we also allow the storage of a piece of
+ * data for use by context-sensitive help. For example, on
+ * Windows you can click the magic question mark and then
+ * click a control, and help for that control should spring
+ * up. Hence, here is a slot in which to store per-control
+ * data that a particular platform-specific driver can use
+ * to ensure it brings up the right piece of help text.
+ */
+ intorptr helpctx;
+ } generic;
+ struct {
+ STANDARD_PREFIX;
+ union control *ctrl;
+ } tabdelay;
+ struct {
+ STANDARD_PREFIX;
+ } text;
+ struct {
+ STANDARD_PREFIX;
+ char shortcut; /* keyboard shortcut */
+ /*
+ * Percentage of the dialog-box width used by the edit box.
+ * If this is set to 100, the label is on its own line;
+ * otherwise the label is on the same line as the box
+ * itself.
+ */
+ int percentwidth;
+ int password; /* details of input are hidden */
+ /*
+ * A special case of the edit box is the combo box, which
+ * has a drop-down list built in. (Note that a _non_-
+ * editable drop-down list is done as a special case of a
+ * list box.)
+ */
+ int has_list;
+ /*
+ * Edit boxes tend to need two items of context, so here's
+ * a spare.
+ */
+ intorptr context2;
+ } editbox;
+ struct {
+ STANDARD_PREFIX;
+ /*
+ * `shortcut' here is a single keyboard shortcut which is
+ * expected to select the whole group of radio buttons. It
+ * can be NO_SHORTCUT if required, and there is also a way
+ * to place individual shortcuts on each button; see below.
+ */
+ char shortcut;
+ /*
+ * There are separate fields for `ncolumns' and `nbuttons'
+ * for several reasons.
+ *
+ * Firstly, we sometimes want the last of a set of buttons
+ * to have a longer label than the rest; we achieve this by
+ * setting `ncolumns' higher than `nbuttons', and the
+ * layout code is expected to understand that the final
+ * button should be given all the remaining space on the
+ * line. This sounds like a ludicrously specific special
+ * case (if we're doing this sort of thing, why not have
+ * the general ability to have a particular button span
+ * more than one column whether it's the last one or not?)
+ * but actually it's reasonably common for the sort of
+ * three-way control you get a lot of in PuTTY: `yes'
+ * versus `no' versus `some more complex way to decide'.
+ *
+ * Secondly, setting `nbuttons' higher than `ncolumns' lets
+ * us have more than one line of radio buttons for a single
+ * setting. A very important special case of this is
+ * setting `ncolumns' to 1, so that each button is on its
+ * own line.
+ */
+ int ncolumns;
+ int nbuttons;
+ /*
+ * This points to a dynamically allocated array of `char *'
+ * pointers, each of which points to a dynamically
+ * allocated string.
+ */
+ char **buttons; /* `nbuttons' button labels */
+ /*
+ * This points to a dynamically allocated array of `char'
+ * giving the individual keyboard shortcuts for each radio
+ * button. The array may be NULL if none are required.
+ */
+ char *shortcuts; /* `nbuttons' shortcuts; may be NULL */
+ /*
+ * This points to a dynamically allocated array of
+ * intorptr, giving helpful data for each button.
+ */
+ intorptr *buttondata; /* `nbuttons' entries; may be NULL */
+ } radio;
+ struct {
+ STANDARD_PREFIX;
+ char shortcut;
+ } checkbox;
+ struct {
+ STANDARD_PREFIX;
+ char shortcut;
+ /*
+ * At least Windows has the concept of a `default push
+ * button', which gets implicitly pressed when you hit
+ * Return even if it doesn't have the input focus.
+ */
+ int isdefault;
+ } button;
+ struct {
+ STANDARD_PREFIX;
+ char shortcut; /* keyboard shortcut */
+ /*
+ * Height of the list box, in approximate number of lines.
+ * If this is zero, the list is a drop-down list.
+ */
+ int height; /* height in lines */
+ /*
+ * If this is set, the list elements can be reordered by
+ * the user (by drag-and-drop or by Up and Down buttons,
+ * whatever the per-platform implementation feels
+ * comfortable with). This is not guaranteed to work on a
+ * drop-down list, so don't try it!
+ */
+ int draglist;
+ /*
+ * If this is set, the list can have more than one element
+ * selected at a time. This is not guaranteed to work on a
+ * drop-down list, so don't try it!
+ */
+ int multisel;
+ /*
+ * Percentage of the dialog-box width used by the list box.
+ * If this is set to 100, the label is on its own line;
+ * otherwise the label is on the same line as the box
+ * itself. Setting this to anything other than 100 is not
+ * guaranteed to work on a _non_-drop-down list, so don't
+ * try it!
+ */
+ int percentwidth;
+ /*
+ * Some list boxes contain strings that contain tab
+ * characters. If `ncols' is greater than 0, then
+ * `percentages' is expected to be non-zero and to contain
+ * the respective widths of `ncols' columns, which together
+ * will exactly fit the width of the list box. Otherwise
+ * `percentages' must be NULL.
+ */
+ int ncols; /* number of columns */
+ int *percentages; /* % width of each column */
+ } listbox;
+ struct {
+ STANDARD_PREFIX;
+ char shortcut;
+ /*
+ * `filter' dictates what type of files will be selected by
+ * default; for example, when selecting private key files
+ * the file selector would do well to only show .PPK files
+ * (on those systems where this is the chosen extension).
+ *
+ * The precise contents of `filter' are platform-defined,
+ * unfortunately. The special value NULL means `all files'
+ * and is always a valid fallback.
+ *
+ * Unlike almost all strings in this structure, this value
+ * is NOT expected to require freeing (although of course
+ * you can always use ctrl_alloc if you do need to create
+ * one on the fly). This is because the likely mode of use
+ * is to define string constants in a platform-specific
+ * header file, and directly reference those. Or worse, a
+ * particular platform might choose to cast integers into
+ * this pointer type...
+ */
+ char const *filter;
+ /*
+ * Some systems like to know whether a file selector is
+ * choosing a file to read or one to write (and possibly
+ * create).
+ */
+ int for_writing;
+ /*
+ * On at least some platforms, the file selector is a
+ * separate dialog box, and contains a user-settable title.
+ *
+ * This value _is_ expected to require freeing.
+ */
+ char *title;
+ } fileselect;
+ struct {
+ /* In this variant, `label' MUST be NULL. */
+ STANDARD_PREFIX;
+ int ncols; /* number of columns */
+ int *percentages; /* % width of each column */
+ /*
+ * Every time this control type appears, exactly one of
+ * `ncols' and the previous number of columns MUST be one.
+ * Attempting to allow a seamless transition from a four-
+ * to a five-column layout, for example, would be way more
+ * trouble than it was worth. If you must lay things out
+ * like that, define eight unevenly sized columns and use
+ * column-spanning a lot. But better still, just don't.
+ *
+ * `percentages' may be NULL if ncols==1, to save space.
+ */
+ } columns;
+ struct {
+ STANDARD_PREFIX;
+ char shortcut;
+ } fontselect;
+};
+
+#undef STANDARD_PREFIX
+
+/*
+ * `controlset' is a container holding an array of `union control'
+ * structures, together with a panel name and a title for the whole
+ * set. In Windows and any similar-looking GUI, each `controlset'
+ * in the config will be a container box within a panel.
+ *
+ * Special case: if `boxname' is NULL, the control set gives an
+ * overall title for an entire panel of controls.
+ */
+struct controlset {
+ char *pathname; /* panel path, e.g. "SSH/Tunnels" */
+ char *boxname; /* internal short name of controlset */
+ char *boxtitle; /* title of container box */
+ int ncolumns; /* current no. of columns at bottom */
+ int ncontrols; /* number of `union control' in array */
+ int ctrlsize; /* allocated size of array */
+ union control **ctrls; /* actual array */
+};
+
+/*
+ * This is the container structure which holds a complete set of
+ * controls.
+ */
+struct controlbox {
+ int nctrlsets; /* number of ctrlsets */
+ int ctrlsetsize; /* ctrlset size */
+ struct controlset **ctrlsets; /* actual array of ctrlsets */
+ int nfrees;
+ int freesize;
+ void **frees; /* array of aux data areas to free */
+};
+
+struct controlbox *ctrl_new_box(void);
+void ctrl_free_box(struct controlbox *);
+
+/*
+ * Standard functions used for populating a controlbox structure.
+ */
+
+/* Set up a panel title. */
+struct controlset *ctrl_settitle(struct controlbox *,
+ char *path, char *title);
+/* Retrieve a pointer to a controlset, creating it if absent. */
+struct controlset *ctrl_getset(struct controlbox *,
+ char *path, char *name, char *boxtitle);
+void ctrl_free_set(struct controlset *);
+
+void ctrl_free(union control *);
+
+/*
+ * This function works like `malloc', but the memory it returns
+ * will be automatically freed when the controlbox is freed. Note
+ * that a controlbox is a dialog-box _template_, not an instance,
+ * and so data allocated through this function is better not used
+ * to hold modifiable per-instance things. It's mostly here for
+ * allocating structures to be passed as control handler params.
+ */
+void *ctrl_alloc(struct controlbox *b, size_t size);
+
+/*
+ * Individual routines to create `union control' structures in a controlset.
+ *
+ * Most of these routines allow the most common fields to be set
+ * directly, and put default values in the rest. Each one returns a
+ * pointer to the `union control' it created, so that final tweaks
+ * can be made.
+ */
+
+/* `ncolumns' is followed by that many percentages, as integers. */
+union control *ctrl_columns(struct controlset *, int ncolumns, ...);
+union control *ctrl_editbox(struct controlset *, char *label, char shortcut,
+ int percentage, intorptr helpctx,
+ handler_fn handler,
+ intorptr context, intorptr context2);
+union control *ctrl_combobox(struct controlset *, char *label, char shortcut,
+ int percentage, intorptr helpctx,
+ handler_fn handler,
+ intorptr context, intorptr context2);
+/*
+ * `ncolumns' is followed by (alternately) radio button titles and
+ * intorptrs, until a NULL in place of a title string is seen. Each
+ * title is expected to be followed by a shortcut _iff_ `shortcut'
+ * is NO_SHORTCUT.
+ */
+union control *ctrl_radiobuttons(struct controlset *, char *label,
+ char shortcut, int ncolumns,
+ intorptr helpctx,
+ handler_fn handler, intorptr context, ...);
+union control *ctrl_pushbutton(struct controlset *,char *label,char shortcut,
+ intorptr helpctx,
+ handler_fn handler, intorptr context);
+union control *ctrl_listbox(struct controlset *,char *label,char shortcut,
+ intorptr helpctx,
+ handler_fn handler, intorptr context);
+union control *ctrl_droplist(struct controlset *, char *label, char shortcut,
+ int percentage, intorptr helpctx,
+ handler_fn handler, intorptr context);
+union control *ctrl_draglist(struct controlset *,char *label,char shortcut,
+ intorptr helpctx,
+ handler_fn handler, intorptr context);
+union control *ctrl_filesel(struct controlset *,char *label,char shortcut,
+ char const *filter, int write, char *title,
+ intorptr helpctx,
+ handler_fn handler, intorptr context);
+union control *ctrl_fontsel(struct controlset *,char *label,char shortcut,
+ intorptr helpctx,
+ handler_fn handler, intorptr context);
+union control *ctrl_text(struct controlset *, char *text, intorptr helpctx);
+union control *ctrl_checkbox(struct controlset *, char *label, char shortcut,
+ intorptr helpctx,
+ handler_fn handler, intorptr context);
+union control *ctrl_tabdelay(struct controlset *, union control *);
+
+/*
+ * Standard handler routines to cover most of the common cases in
+ * the config box.
+ */
+/*
+ * The standard radio-button handler expects the main `context'
+ * field to contain the `offsetof' of an int field in the structure
+ * pointed to by `data', and expects each of the individual button
+ * data to give a value for that int field.
+ */
+void dlg_stdradiobutton_handler(union control *ctrl, void *dlg,
+ void *data, int event);
+/*
+ * The standard checkbox handler expects the main `context' field
+ * to contain the `offsetof' an int field in the structure pointed
+ * to by `data', optionally ORed with CHECKBOX_INVERT to indicate
+ * that the sense of the datum is opposite to the sense of the
+ * checkbox.
+ */
+#define CHECKBOX_INVERT (1<<30)
+void dlg_stdcheckbox_handler(union control *ctrl, void *dlg,
+ void *data, int event);
+/*
+ * The standard edit-box handler expects the main `context' field
+ * to contain the `offsetof' a field in the structure pointed to by
+ * `data'. The secondary `context2' field indicates the type of
+ * this field:
+ *
+ * - if context2 > 0, the field is a char array and context2 gives
+ * its size.
+ * - if context2 == -1, the field is an int and the edit box is
+ * numeric.
+ * - if context2 < -1, the field is an int and the edit box is
+ * _floating_, and (-context2) gives the scale. (E.g. if
+ * context2 == -1000, then typing 1.2 into the box will set the
+ * field to 1200.)
+ */
+void dlg_stdeditbox_handler(union control *ctrl, void *dlg,
+ void *data, int event);
+/*
+ * The standard file-selector handler expects the main `context'
+ * field to contain the `offsetof' a Filename field in the
+ * structure pointed to by `data'.
+ */
+void dlg_stdfilesel_handler(union control *ctrl, void *dlg,
+ void *data, int event);
+/*
+ * The standard font-selector handler expects the main `context'
+ * field to contain the `offsetof' a Font field in the structure
+ * pointed to by `data'.
+ */
+void dlg_stdfontsel_handler(union control *ctrl, void *dlg,
+ void *data, int event);
+
+/*
+ * Routines the platform-independent dialog code can call to read
+ * and write the values of controls.
+ */
+void dlg_radiobutton_set(union control *ctrl, void *dlg, int whichbutton);
+int dlg_radiobutton_get(union control *ctrl, void *dlg);
+void dlg_checkbox_set(union control *ctrl, void *dlg, int checked);
+int dlg_checkbox_get(union control *ctrl, void *dlg);
+void dlg_editbox_set(union control *ctrl, void *dlg, char const *text);
+void dlg_editbox_get(union control *ctrl, void *dlg, char *buffer, int length);
+/* The `listbox' functions can also apply to combo boxes. */
+void dlg_listbox_clear(union control *ctrl, void *dlg);
+void dlg_listbox_del(union control *ctrl, void *dlg, int index);
+void dlg_listbox_add(union control *ctrl, void *dlg, char const *text);
+/*
+ * Each listbox entry may have a numeric id associated with it.
+ * Note that some front ends only permit a string to be stored at
+ * each position, which means that _if_ you put two identical
+ * strings in any listbox then you MUST not assign them different
+ * IDs and expect to get meaningful results back.
+ */
+void dlg_listbox_addwithindex(union control *ctrl, void *dlg,
+ char const *text, int id);
+int dlg_listbox_getid(union control *ctrl, void *dlg, int index);
+/* dlg_listbox_index returns <0 if no single element is selected. */
+int dlg_listbox_index(union control *ctrl, void *dlg);
+int dlg_listbox_issel(union control *ctrl, void *dlg, int index);
+void dlg_listbox_select(union control *ctrl, void *dlg, int index);
+void dlg_text_set(union control *ctrl, void *dlg, char const *text);
+void dlg_filesel_set(union control *ctrl, void *dlg, Filename fn);
+void dlg_filesel_get(union control *ctrl, void *dlg, Filename *fn);
+void dlg_fontsel_set(union control *ctrl, void *dlg, FontSpec fn);
+void dlg_fontsel_get(union control *ctrl, void *dlg, FontSpec *fn);
+/*
+ * Bracketing a large set of updates in these two functions will
+ * cause the front end (if possible) to delay updating the screen
+ * until it's all complete, thus avoiding flicker.
+ */
+void dlg_update_start(union control *ctrl, void *dlg);
+void dlg_update_done(union control *ctrl, void *dlg);
+/*
+ * Set input focus into a particular control.
+ */
+void dlg_set_focus(union control *ctrl, void *dlg);
+/*
+ * Return the `ctrl' structure for the control that had the input
+ * focus before this one. This is NOT GUARANTEED to work on all
+ * platforms, so don't base any critical functionality on it!
+ */
+union control *dlg_last_focused(void *dlg);
+/*
+ * During event processing, you might well want to give an error
+ * indication to the user. dlg_beep() is a quick and easy generic
+ * error; dlg_error() puts up a message-box or equivalent.
+ */
+void dlg_beep(void *dlg);
+void dlg_error_msg(void *dlg, char *msg);
+/*
+ * This function signals to the front end that the dialog's
+ * processing is completed, and passes an integer value (typically
+ * a success status).
+ */
+void dlg_end(void *dlg, int value);
+
+/*
+ * Routines to manage a (per-platform) colour selector.
+ * dlg_coloursel_start() is called in an event handler, and
+ * schedules the running of a colour selector after the event
+ * handler returns. The colour selector will send EVENT_CALLBACK to
+ * the control that spawned it, when it's finished;
+ * dlg_coloursel_results() fetches the results, as integers from 0
+ * to 255; it returns nonzero on success, or zero if the colour
+ * selector was dismissed by hitting Cancel or similar.
+ *
+ * dlg_coloursel_start() accepts an RGB triple which is used to
+ * initialise the colour selector to its starting value.
+ */
+void dlg_coloursel_start(union control *ctrl, void *dlg,
+ int r, int g, int b);
+int dlg_coloursel_results(union control *ctrl, void *dlg,
+ int *r, int *g, int *b);
+
+/*
+ * This routine is used by the platform-independent code to
+ * indicate that the value of a particular control is likely to
+ * have changed. It triggers a call of the handler for that control
+ * with `event' set to EVENT_REFRESH.
+ *
+ * If `ctrl' is NULL, _all_ controls in the dialog get refreshed
+ * (for loading or saving entire sets of settings).
+ */
+void dlg_refresh(union control *ctrl, void *dlg);
+
+/*
+ * Standard helper functions for reading a controlbox structure.
+ */
+
+/*
+ * Find the index of next controlset in a controlbox for a given
+ * path, or -1 if no such controlset exists. If -1 is passed as
+ * input, finds the first. Intended usage is something like
+ *
+ * for (index=-1; (index=ctrl_find_path(ctrlbox, index, path)) >= 0 ;) {
+ * ... process this controlset ...
+ * }
+ */
+int ctrl_find_path(struct controlbox *b, char *path, int index);
+int ctrl_path_elements(char *path);
+/* Return the number of matching path elements at the starts of p1 and p2,
+ * or INT_MAX if the paths are identical. */
+int ctrl_path_compare(char *p1, char *p2);
-\versionid $Id: config.but,v 1.56 2003/02/19 09:54:45 jacob Exp $
+\versionid $Id: config.but,v 1.57 2003/03/05 22:07:40 simon Exp $
\C{config} Configuring PuTTY
the server can send as many Control-G characters as it likes and
nothing at all will happen.
-\b \q{Play Windows Default Sound} is the default setting. It causes
-the Windows \q{Default Beep} sound to be played. To change what this
-sound is, or to test it if nothing seems to be happening, use the
-Sound configurer in the Windows Control Panel.
+\b \q{Make default system alert sound} is the default setting. It
+causes the Windows \q{Default Beep} sound to be played. To change
+what this sound is, or to test it if nothing seems to be happening,
+use the Sound configurer in the Windows Control Panel.
+
+\b \q{Visual bell} is a silent alternative to a beeping computer. In
+this mode, when the server sends a Control-G, the whole PuTTY window
+will flash white for a fraction of a second.
\b \q{Play a custom sound file} allows you to specify a particular
sound file to be used by PuTTY alone, or even by a particular
you will also need to enter the name of your sound file in the edit
control \q{Custom sound file to play as a bell}.
-\b \q{Visual bell} is a silent alternative to a beeping computer. In
-this mode, when the server sends a Control-G, the whole PuTTY window
-will flash white for a fraction of a second.
-
\S{config-belltaskbar} \q{Taskbar/caption indication on bell}
\cfg{winhelp-topic}{bell.taskbar}
system. (VT100-style terminal handling can only deal with fixed-
width fonts.)
-\S{config-title} Controlling the window title
-
-\cfg{winhelp-topic}{appearance.title}
-
-The \q{Window title} edit box allows you to set the title of the
-PuTTY window. By default the window title will contain the host name
-followed by \q{PuTTY}, for example \c{server1.example.com - PuTTY}.
-If you want a different window title, this is where to set it.
-
-PuTTY allows the server to send \c{xterm} control sequences which
-modify the title of the window in mid-session. There is also an
-\c{xterm} sequence to modify the title of the window's \e{icon}.
-This makes sense in a windowing system where the window becomes an
-icon when minimised, such as Windows 3.1 or most X Window System
-setups; but in the Windows 95-like user interface it isn't as
-applicable.
-
-By default, PuTTY only uses the server-supplied \e{window} title, and
-ignores the icon title entirely. If for some reason you want to see
-both titles, check the box marked \q{Separate window and icon titles}.
-If you do this, PuTTY's window title and Taskbar caption will
-change into the server-supplied icon title if you minimise the PuTTY
-window, and change back to the server-supplied window title if you
-restore it. (If the server has not bothered to supply a window or
-icon title, none of this will happen.)
-
\S{config-mouseptr} \q{Hide mouse pointer when typing in window}
\cfg{winhelp-topic}{appearance.hidemouse}
The Behaviour configuration panel allows you to control aspects of
the behaviour of PuTTY's window.
+\S{config-title} Controlling the window title
+
+\cfg{winhelp-topic}{appearance.title}
+
+The \q{Window title} edit box allows you to set the title of the
+PuTTY window. By default the window title will contain the host name
+followed by \q{PuTTY}, for example \c{server1.example.com - PuTTY}.
+If you want a different window title, this is where to set it.
+
+PuTTY allows the server to send \c{xterm} control sequences which
+modify the title of the window in mid-session. There is also an
+\c{xterm} sequence to modify the title of the window's \e{icon}.
+This makes sense in a windowing system where the window becomes an
+icon when minimised, such as Windows 3.1 or most X Window System
+setups; but in the Windows 95-like user interface it isn't as
+applicable.
+
+By default, PuTTY only uses the server-supplied \e{window} title, and
+ignores the icon title entirely. If for some reason you want to see
+both titles, check the box marked \q{Separate window and icon titles}.
+If you do this, PuTTY's window title and Taskbar caption will
+change into the server-supplied icon title if you minimise the PuTTY
+window, and change back to the server-supplied window title if you
+restore it. (If the server has not bothered to supply a window or
+icon title, none of this will happen.)
+
\S{config-warnonclose} \q{Warn before closing window}
\cfg{winhelp-topic}{behaviour.closewarn}
CAPTION "PuTTY Configuration"
FONT 8, "MS Shell Dlg"
BEGIN
- DEFPUSHBUTTON "&Open", IDOK, 184, 235, 44, 14
- PUSHBUTTON "&Cancel", IDCANCEL, 231, 235, 44, 14
- PUSHBUTTON "&About", IDC_ABOUT, 3, 235, 44, 14, NOT WS_TABSTOP
- PUSHBUTTON "&Help", IDC_HELPBTN, 50, 235, 44, 14, NOT WS_TABSTOP
-END
-
-/* Accelerators used: ac */
-IDD_RECONF DIALOG DISCARDABLE 0, 0, 280, 252
-STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
-CAPTION "PuTTY Reconfiguration"
-FONT 8, "MS Shell Dlg"
-BEGIN
- DEFPUSHBUTTON "&Apply", IDOK, 184, 235, 44, 14
- PUSHBUTTON "&Cancel", IDCANCEL, 231, 235, 44, 14
END
/* Accelerators used: co */
--- /dev/null
+/*
+ * wincfg.c - the Windows-specific parts of the PuTTY configuration
+ * box.
+ */
+
+#include <windows.h>
+
+#include <assert.h>
+#include <stdlib.h>
+
+#include "putty.h"
+#include "dialog.h"
+#include "storage.h"
+
+static void about_handler(union control *ctrl, void *dlg,
+ void *data, int event)
+{
+ HWND *hwndp = (HWND *)ctrl->generic.context.p;
+
+ if (event == EVENT_ACTION) {
+ modal_about_box(*hwndp);
+ }
+}
+
+static void help_handler(union control *ctrl, void *dlg,
+ void *data, int event)
+{
+ HWND *hwndp = (HWND *)ctrl->generic.context.p;
+
+ if (event == EVENT_ACTION) {
+ show_help(*hwndp);
+ }
+}
+
+void win_setup_config_box(struct controlbox *b, HWND *hwndp, int has_help,
+ int midsession)
+{
+ struct controlset *s;
+ union control *c;
+
+ if (!midsession) {
+ /*
+ * Add the About and Help buttons to the standard panel.
+ */
+ s = ctrl_getset(b, "", "", "");
+ c = ctrl_pushbutton(s, "About", 'a', HELPCTX(no_help),
+ about_handler, P(hwndp));
+ c->generic.column = 0;
+ if (has_help) {
+ c = ctrl_pushbutton(s, "Help", 'h', HELPCTX(no_help),
+ help_handler, P(hwndp));
+ c->generic.column = 1;
+ }
+ }
+
+ /*
+ * Windows has the AltGr key, which has various Windows-
+ * specific options.
+ */
+ s = ctrl_getset(b, "Terminal/Keyboard", "features",
+ "Enable extra keyboard features:");
+ ctrl_checkbox(s, "AltGr acts as Compose key", 't',
+ HELPCTX(keyboard_compose),
+ dlg_stdcheckbox_handler, I(offsetof(Config,compose_key)));
+ ctrl_checkbox(s, "Control-Alt is different from AltGr", 'd',
+ HELPCTX(keyboard_ctrlalt),
+ dlg_stdcheckbox_handler, I(offsetof(Config,ctrlaltkeys)));
+
+ /*
+ * Windows allows an arbitrary .WAV to be played as a bell. For
+ * this we must search the existing controlset for the
+ * radio-button set controlling the `beep' option, and add an
+ * extra button to it.
+ *
+ * Note that although this _looks_ like a hideous hack, it's
+ * actually all above board. The well-defined interface to the
+ * per-platform dialog box code is the _data structures_ `union
+ * control', `struct controlset' and so on; so code like this
+ * that reaches into those data structures and changes bits of
+ * them is perfectly legitimate and crosses no boundaries. All
+ * the ctrl_* routines that create most of the controls are
+ * convenient shortcuts provided on the cross-platform side of
+ * the interface, and template creation code is under no actual
+ * obligation to use them.
+ */
+ s = ctrl_getset(b, "Terminal/Bell", "style", "Set the style of bell");
+ {
+ int i;
+ for (i = 0; i < s->ncontrols; i++) {
+ c = s->ctrls[i];
+ if (c->generic.type == CTRL_RADIO &&
+ c->generic.context.i == offsetof(Config, beep)) {
+ assert(c->generic.handler == dlg_stdradiobutton_handler);
+ c->radio.nbuttons++;
+ c->radio.buttons =
+ srealloc(c->radio.buttons,
+ c->radio.nbuttons * sizeof(*c->radio.buttons));
+ c->radio.buttons[c->radio.nbuttons-1] =
+ dupstr("Play a custom sound file");
+ c->radio.buttondata =
+ srealloc(c->radio.buttondata,
+ c->radio.nbuttons * sizeof(*c->radio.buttondata));
+ c->radio.buttondata[c->radio.nbuttons-1] = I(BELL_WAVEFILE);
+ if (c->radio.shortcuts) {
+ c->radio.shortcuts =
+ srealloc(c->radio.shortcuts,
+ (c->radio.nbuttons *
+ sizeof(*c->radio.shortcuts)));
+ c->radio.shortcuts[c->radio.nbuttons-1] = NO_SHORTCUT;
+ }
+ break;
+ }
+ }
+ }
+ ctrl_filesel(s, "Custom sound file to play as a bell:", NO_SHORTCUT,
+ FILTER_WAVE_FILES, FALSE, "Select bell sound file",
+ HELPCTX(bell_style),
+ dlg_stdfilesel_handler, I(offsetof(Config, bell_wavefile)));
+
+ /*
+ * While we've got this box open, taskbar flashing on a bell is
+ * also Windows-specific.
+ */
+ ctrl_radiobuttons(s, "Taskbar/caption indication on bell:", 'i', 3,
+ HELPCTX(bell_taskbar),
+ dlg_stdradiobutton_handler,
+ I(offsetof(Config, beep_ind)),
+ "Disabled", I(B_IND_DISABLED),
+ "Flashing", I(B_IND_FLASH),
+ "Steady", I(B_IND_STEADY), NULL);
+
+ /*
+ * The sunken-edge border is a Windows GUI feature.
+ */
+ s = ctrl_getset(b, "Window/Appearance", "border",
+ "Adjust the window border");
+ ctrl_checkbox(s, "Sunken-edge border (slightly thicker)", 's',
+ HELPCTX(appearance_border),
+ dlg_stdcheckbox_handler, I(offsetof(Config,sunken_edge)));
+
+ /*
+ * Cyrillic Lock is a horrid misfeature even on Windows, and
+ * the least we can do is ensure it never makes it to any other
+ * platform (at least unless someone fixes it!).
+ */
+ s = ctrl_getset(b, "Window/Translation", "input",
+ "Enable character set translation on input data");
+ ctrl_checkbox(s, "Caps Lock acts as Cyrillic switch", 's',
+ HELPCTX(translation_cyrillic),
+ dlg_stdcheckbox_handler,
+ I(offsetof(Config,xlat_capslockcyr)));
+
+ /*
+ * Windows has the weird OEM font mode, which gives us some
+ * additional options when working with line-drawing
+ * characters.
+ */
+ s = ctrl_getset(b, "Window/Translation", "linedraw",
+ "Adjust how PuTTY displays line drawing characters");
+ {
+ int i;
+ for (i = 0; i < s->ncontrols; i++) {
+ c = s->ctrls[i];
+ if (c->generic.type == CTRL_RADIO &&
+ c->generic.context.i == offsetof(Config, vtmode)) {
+ assert(c->generic.handler == dlg_stdradiobutton_handler);
+ c->radio.nbuttons += 2;
+ c->radio.buttons =
+ srealloc(c->radio.buttons,
+ c->radio.nbuttons * sizeof(*c->radio.buttons));
+ c->radio.buttons[c->radio.nbuttons-2] =
+ dupstr("Use font in both ANSI and OEM modes");
+ c->radio.buttons[c->radio.nbuttons-1] =
+ dupstr("Use font in OEM mode only");
+ c->radio.buttondata =
+ srealloc(c->radio.buttondata,
+ c->radio.nbuttons * sizeof(*c->radio.buttondata));
+ c->radio.buttondata[c->radio.nbuttons-2] = I(VT_OEMANSI);
+ c->radio.buttondata[c->radio.nbuttons-1] = I(VT_OEMONLY);
+ if (!c->radio.shortcuts) {
+ int j;
+ c->radio.shortcuts =
+ smalloc((c->radio.nbuttons *
+ sizeof(*c->radio.shortcuts)));
+ for (j = 0; j < c->radio.nbuttons; j++)
+ c->radio.shortcuts[j] = NO_SHORTCUT;
+ } else {
+ c->radio.shortcuts =
+ srealloc(c->radio.shortcuts,
+ (c->radio.nbuttons *
+ sizeof(*c->radio.shortcuts)));
+ }
+ c->radio.shortcuts[c->radio.nbuttons-2] = 'b';
+ c->radio.shortcuts[c->radio.nbuttons-1] = 'e';
+ break;
+ }
+ }
+ }
+
+ /*
+ * RTF paste is Windows-specific.
+ */
+ s = ctrl_getset(b, "Window/Selection", "trans",
+ "Translation of pasted characters");
+ ctrl_checkbox(s, "Paste to clipboard in RTF as well as plain text", 'f',
+ HELPCTX(selection_rtf),
+ dlg_stdcheckbox_handler, I(offsetof(Config,rtf_paste)));
+
+ /*
+ * Windows often has no middle button, so we supply a selection
+ * mode in which the more critical Paste action is available on
+ * the right button instead.
+ */
+ s = ctrl_getset(b, "Window/Selection", "mouse",
+ "Control use of mouse");
+ ctrl_radiobuttons(s, "Action of mouse buttons:", NO_SHORTCUT, 1,
+ HELPCTX(selection_buttons),
+ dlg_stdradiobutton_handler,
+ I(offsetof(Config, mouse_is_xterm)),
+ "Windows (Right pastes, Middle extends)", 'w', I(0),
+ "xterm (Right extends, Middle pastes)", 'x', I(1), NULL);
+ /*
+ * This really ought to go at the _top_ of its box, not the
+ * bottom, so we'll just do some shuffling now we've set it
+ * up...
+ */
+ c = s->ctrls[s->ncontrols-1]; /* this should be the new control */
+ memmove(s->ctrls+1, s->ctrls, (s->ncontrols-1)*sizeof(union control *));
+ s->ctrls[0] = c;
+
+ /*
+ * Logical palettes don't even make sense anywhere except Windows.
+ */
+ s = ctrl_getset(b, "Window/Colours", "general",
+ "General options for colour usage");
+ ctrl_checkbox(s, "Attempt to use logical palettes", 'l',
+ HELPCTX(colours_logpal),
+ dlg_stdcheckbox_handler, I(offsetof(Config,try_palette)));
+
+ /*
+ * Resize-by-changing-font is a Windows insanity.
+ */
+ s = ctrl_getset(b, "Window", "size", "Set the size of the window");
+ ctrl_radiobuttons(s, "When window is resized:", 'z', 1,
+ HELPCTX(window_resize),
+ dlg_stdradiobutton_handler,
+ I(offsetof(Config, resize_action)),
+ "Change the number of rows and columns", I(RESIZE_TERM),
+ "Change the size of the font", I(RESIZE_FONT),
+ "Change font size only when maximised", I(RESIZE_EITHER),
+ "Forbid resizing completely", I(RESIZE_DISABLED), NULL);
+
+ /*
+ * Most of the Window/Behaviour stuff is there to mimic Windows
+ * conventions which PuTTY can optionally disregard. Hence,
+ * most of these options are Windows-specific.
+ */
+ s = ctrl_getset(b, "Window/Behaviour", "main", NULL);
+ ctrl_checkbox(s, "Window closes on ALT-F4", '4',
+ HELPCTX(behaviour_altf4),
+ dlg_stdcheckbox_handler, I(offsetof(Config,alt_f4)));
+ ctrl_checkbox(s, "System menu appears on ALT-Space", 'y',
+ HELPCTX(behaviour_altspace),
+ dlg_stdcheckbox_handler, I(offsetof(Config,alt_space)));
+ ctrl_checkbox(s, "System menu appears on ALT alone", 'l',
+ HELPCTX(behaviour_altonly),
+ dlg_stdcheckbox_handler, I(offsetof(Config,alt_only)));
+ ctrl_checkbox(s, "Ensure window is always on top", 'e',
+ HELPCTX(behaviour_alwaysontop),
+ dlg_stdcheckbox_handler, I(offsetof(Config,alwaysontop)));
+ ctrl_checkbox(s, "Full screen on Alt-Enter", 'f',
+ HELPCTX(behaviour_altenter),
+ dlg_stdcheckbox_handler,
+ I(offsetof(Config,fullscreenonaltenter)));
+}
* box.
*/
+/*
+ * Possible TODO in new cross-platform config box stuff:
+ *
+ * - When lining up two controls alongside each other, I wonder if
+ * we could conveniently arrange to centre them vertically?
+ * Particularly ugly in the current setup is the `Add new
+ * forwarded port:' static next to the rather taller `Remove'
+ * button.
+ */
+
#include <windows.h>
#include <commctrl.h>
+#include <assert.h>
#include "winstuff.h"
+#include "misc.h"
+#include "dialog.h"
#include "puttymem.h"
#include "putty.h"
#define GAPYBOX 4
#define DLGWIDTH 168
#define STATICHEIGHT 8
+#define TITLEHEIGHT 12
#define CHECKBOXHEIGHT 8
#define RADIOHEIGHT 8
#define EDITHEIGHT 12
+#define LISTHEIGHT 11
+#define LISTINCREMENT 8
#define COMBOHEIGHT 12
#define PUSHBTNHEIGHT 14
#define PROGBARHEIGHT 14
r.left += cp->xoff;
MapDialogRect(cp->hwnd, &r);
- ctl = CreateWindowEx(exstyle, wclass, wtext, wstyle,
- r.left, r.top, r.right, r.bottom,
- cp->hwnd, (HMENU) wid, hinst, NULL);
- SendMessage(ctl, WM_SETFONT, cp->font, MAKELPARAM(TRUE, 0));
+ /*
+ * We can pass in cp->hwnd == NULL, to indicate a dry run
+ * without creating any actual controls.
+ */
+ if (cp->hwnd) {
+ ctl = CreateWindowEx(exstyle, wclass, wtext, wstyle,
+ r.left, r.top, r.right, r.bottom,
+ cp->hwnd, (HMENU) wid, hinst, NULL);
+ SendMessage(ctl, WM_SETFONT, cp->font, MAKELPARAM(TRUE, 0));
+
+ if (!strcmp(wclass, "LISTBOX")) {
+ /*
+ * Bizarre Windows bug: the list box calculates its
+ * number of lines based on the font it has at creation
+ * time, but sending it WM_SETFONT doesn't cause it to
+ * recalculate. So now, _after_ we've sent it
+ * WM_SETFONT, we explicitly resize it (to the same
+ * size it was already!) to force it to reconsider.
+ */
+ SetWindowPos(ctl, NULL, 0, 0, r.right, r.bottom,
+ SWP_NOACTIVATE | SWP_NOCOPYBITS |
+ SWP_NOMOVE | SWP_NOZORDER);
+ }
+ }
return ctl;
}
* Some edit boxes. Each one has a static above it. The percentages
* of the horizontal space are provided.
*/
-void multiedit(struct ctlpos *cp, ...)
+void multiedit(struct ctlpos *cp, int password, ...)
{
RECT r;
va_list ap;
int percent, xpos;
percent = xpos = 0;
- va_start(ap, cp);
+ va_start(ap, password);
while (1) {
char *text;
int staticid, editid, pcwidth;
r.top = cp->ypos + 8 + GAPWITHIN;
r.bottom = EDITHEIGHT;
doctl(cp, r, "EDIT",
- WS_CHILD | WS_VISIBLE | WS_TABSTOP | ES_AUTOHSCROLL,
+ WS_CHILD | WS_VISIBLE | WS_TABSTOP | ES_AUTOHSCROLL |
+ (password ? ES_PASSWORD : 0),
WS_EX_CLIENTEDGE, "", editid);
}
va_end(ap);
cp->ypos += STATICHEIGHT + GAPWITHIN + COMBOHEIGHT + GAPBETWEEN;
}
-static void radioline_common(struct ctlpos *cp, int nacross, va_list ap)
+struct radio { char *text; int id; };
+
+static void radioline_common(struct ctlpos *cp, char *text, int id,
+ int nacross, struct radio *buttons, int nbuttons)
{
RECT r;
int group;
int i;
- char *btext;
+ int j;
+
+ if (text) {
+ r.left = GAPBETWEEN;
+ r.top = cp->ypos;
+ r.right = cp->width;
+ r.bottom = STATICHEIGHT;
+ cp->ypos += r.bottom + GAPWITHIN;
+ doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0, text, id);
+ }
group = WS_GROUP;
i = 0;
- btext = va_arg(ap, char *);
- while (1) {
- char *nextbtext;
- int bid;
- if (!btext)
- break;
+ for (j = 0; j < nbuttons; j++) {
+ char *btext = buttons[j].text;
+ int bid = buttons[j].id;
+
if (i == nacross) {
- cp->ypos += r.bottom + GAPBETWEEN;
+ cp->ypos += r.bottom + (nacross > 1 ? GAPBETWEEN : GAPWITHIN);
i = 0;
}
- bid = va_arg(ap, int);
- nextbtext = va_arg(ap, char *);
r.left = GAPBETWEEN + i * (cp->width + GAPBETWEEN) / nacross;
- if (nextbtext)
+ if (j < nbuttons-1)
r.right =
(i + 1) * (cp->width + GAPBETWEEN) / nacross - r.left;
else
r.top = cp->ypos;
r.bottom = RADIOHEIGHT;
doctl(cp, r, "BUTTON",
- BS_AUTORADIOBUTTON | WS_CHILD | WS_VISIBLE | WS_TABSTOP |
- group, 0, btext, bid);
+ BS_NOTIFY | BS_AUTORADIOBUTTON | WS_CHILD |
+ WS_VISIBLE | WS_TABSTOP | group, 0, btext, bid);
group = 0;
i++;
- btext = nextbtext;
}
cp->ypos += r.bottom + GAPBETWEEN;
}
*/
void radioline(struct ctlpos *cp, char *text, int id, int nacross, ...)
{
- RECT r;
va_list ap;
+ struct radio *buttons;
+ int i, nbuttons;
- r.left = GAPBETWEEN;
- r.top = cp->ypos;
- r.right = cp->width;
- r.bottom = STATICHEIGHT;
- cp->ypos += r.bottom + GAPWITHIN;
- doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0, text, id);
va_start(ap, nacross);
- radioline_common(cp, nacross, ap);
+ nbuttons = 0;
+ while (1) {
+ char *btext = va_arg(ap, char *);
+ int bid;
+ if (!btext)
+ break;
+ bid = va_arg(ap, int);
+ }
+ va_end(ap);
+ buttons = smalloc(nbuttons * sizeof(struct radio));
+ va_start(ap, nacross);
+ for (i = 0; i < nbuttons; i++) {
+ buttons[i].text = va_arg(ap, char *);
+ buttons[i].id = va_arg(ap, int);
+ }
va_end(ap);
+ radioline_common(cp, text, id, nacross, buttons, nbuttons);
+ sfree(buttons);
}
/*
void bareradioline(struct ctlpos *cp, int nacross, ...)
{
va_list ap;
+ struct radio *buttons;
+ int i, nbuttons;
va_start(ap, nacross);
- radioline_common(cp, nacross, ap);
+ nbuttons = 0;
+ while (1) {
+ char *btext = va_arg(ap, char *);
+ int bid;
+ if (!btext)
+ break;
+ bid = va_arg(ap, int);
+ }
+ va_end(ap);
+ buttons = smalloc(nbuttons * sizeof(struct radio));
+ va_start(ap, nacross);
+ for (i = 0; i < nbuttons; i++) {
+ buttons[i].text = va_arg(ap, char *);
+ buttons[i].id = va_arg(ap, int);
+ }
va_end(ap);
+ radioline_common(cp, NULL, 0, nacross, buttons, nbuttons);
+ sfree(buttons);
}
/*
*/
void radiobig(struct ctlpos *cp, char *text, int id, ...)
{
- RECT r;
va_list ap;
- int group;
+ struct radio *buttons;
+ int i, nbuttons;
- r.left = GAPBETWEEN;
- r.top = cp->ypos;
- r.right = cp->width;
- r.bottom = STATICHEIGHT;
- cp->ypos += r.bottom + GAPWITHIN;
- doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0, text, id);
va_start(ap, id);
- group = WS_GROUP;
+ nbuttons = 0;
while (1) {
- char *btext;
+ char *btext = va_arg(ap, char *);
int bid;
- btext = va_arg(ap, char *);
if (!btext)
break;
bid = va_arg(ap, int);
- r.left = GAPBETWEEN;
- r.top = cp->ypos;
- r.right = cp->width;
- r.bottom = STATICHEIGHT;
- cp->ypos += r.bottom + GAPWITHIN;
- doctl(cp, r, "BUTTON",
- BS_AUTORADIOBUTTON | WS_CHILD | WS_VISIBLE | WS_TABSTOP |
- group, 0, btext, bid);
- group = 0;
}
va_end(ap);
- cp->ypos += GAPBETWEEN - GAPWITHIN;
+ buttons = smalloc(nbuttons * sizeof(struct radio));
+ va_start(ap, id);
+ for (i = 0; i < nbuttons; i++) {
+ buttons[i].text = va_arg(ap, char *);
+ buttons[i].id = va_arg(ap, int);
+ }
+ va_end(ap);
+ radioline_common(cp, text, id, 1, buttons, nbuttons);
+ sfree(buttons);
}
/*
r.bottom = CHECKBOXHEIGHT;
cp->ypos += r.bottom + GAPBETWEEN;
doctl(cp, r, "BUTTON",
- BS_AUTOCHECKBOX | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 0,
+ BS_NOTIFY | BS_AUTOCHECKBOX | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 0,
text, id);
}
/*
+ * Wrap a piece of text for a static text control. Returns the
+ * wrapped text (a malloc'ed string containing \ns), and also
+ * returns the number of lines required.
+ */
+char *staticwrap(struct ctlpos *cp, HWND hwnd, char *text, int *lines)
+{
+ HFONT font = (HFONT) cp->font;
+ HDC hdc = GetDC(hwnd);
+ int lpx = GetDeviceCaps(hdc, LOGPIXELSX);
+ int width, nlines, j;
+ INT *pwidths, nfit;
+ SIZE size;
+ char *ret, *p, *q;
+ RECT r;
+
+ ret = smalloc(1+strlen(text));
+ p = text;
+ q = ret;
+ pwidths = smalloc(sizeof(INT)*(1+strlen(text)));
+
+ /*
+ * Work out the width the text will need to fit in, by doing
+ * the same adjustment that the `statictext' function itself
+ * will perform.
+ *
+ * We must first convert from dialog-box units into pixels, and
+ * then from pixels into the `logical units' that Windows uses
+ * within GDI. You can't make this stuff up.
+ */
+ r.left = r.top = r.bottom = 0;
+ r.right = cp->width;
+ MapDialogRect(hwnd, &r);
+ width = MulDiv(r.right, lpx, 72);
+
+ nlines = 1;
+
+ while (*p) {
+ if (!GetTextExtentExPoint(hdc, p, strlen(p), width,
+ &nfit, pwidths, &size) ||
+ (size_t)nfit >= strlen(p)) {
+ /*
+ * Either GetTextExtentExPoint returned failure, or the
+ * whole of the rest of the text fits on this line.
+ * Either way, we stop wrapping, copy the remainder of
+ * the input string unchanged to the output, and leave.
+ */
+ strcpy(q, p);
+ break;
+ }
+
+ /*
+ * Now we search backwards along the string from `nfit',
+ * looking for a space at which to break the line. If we
+ * don't find one at all, that's fine - we'll just break
+ * the line at `nfit'.
+ */
+ for (j = nfit; j > 0; j--) {
+ if (isspace((unsigned char)p[j])) {
+ nfit = j;
+ break;
+ }
+ }
+
+ strncpy(q, p, nfit);
+ q[nfit] = '\n';
+ q += nfit+1;
+
+ p += nfit;
+ while (*p && isspace((unsigned char)*p))
+ p++;
+
+ nlines++;
+ }
+
+ ReleaseDC(cp->hwnd, hdc);
+
+ if (lines) *lines = nlines;
+
+ return ret;
+}
+
+/*
* A single standalone static text control.
*/
void statictext(struct ctlpos *cp, char *text, int lines, int id)
r.right = cp->width;
r.bottom = STATICHEIGHT * lines;
cp->ypos += r.bottom + GAPBETWEEN;
- doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0, text, id);
+ doctl(cp, r, "STATIC",
+ WS_CHILD | WS_VISIBLE | SS_LEFTNOWORDWRAP,
+ 0, text, id);
+}
+
+/*
+ * An owner-drawn static text control for a panel title.
+ */
+void paneltitle(struct ctlpos *cp, int id)
+{
+ RECT r;
+
+ r.left = GAPBETWEEN;
+ r.top = cp->ypos;
+ r.right = cp->width;
+ r.bottom = TITLEHEIGHT;
+ cp->ypos += r.bottom + GAPBETWEEN;
+ doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE | SS_OWNERDRAW,
+ 0, NULL, id);
}
/*
r.right = rwid;
r.bottom = PUSHBTNHEIGHT;
doctl(cp, r, "BUTTON",
- WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_PUSHBUTTON,
+ BS_NOTIFY | WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_PUSHBUTTON,
0, btext, bid);
cp->ypos += height + GAPBETWEEN;
}
/*
+ * A simple push button.
+ */
+void button(struct ctlpos *cp, char *btext, int bid, int defbtn)
+{
+ RECT r;
+
+ r.left = GAPBETWEEN;
+ r.top = cp->ypos;
+ r.right = cp->width;
+ r.bottom = PUSHBTNHEIGHT;
+
+ /* Q67655: the _dialog box_ must know which button is default
+ * as well as the button itself knowing */
+ if (defbtn && cp->hwnd)
+ SendMessage(cp->hwnd, DM_SETDEFID, bid, 0);
+
+ doctl(cp, r, "BUTTON",
+ BS_NOTIFY | WS_CHILD | WS_VISIBLE | WS_TABSTOP |
+ (defbtn ? BS_DEFPUSHBUTTON : 0) | BS_PUSHBUTTON,
+ 0, btext, bid);
+
+ cp->ypos += PUSHBTNHEIGHT + GAPBETWEEN;
+}
+
+/*
* Like staticbtn, but two buttons.
*/
void static2btn(struct ctlpos *cp, char *stext, int sid,
r.right = rwid1;
r.bottom = PUSHBTNHEIGHT;
doctl(cp, r, "BUTTON",
- WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_PUSHBUTTON,
+ BS_NOTIFY | WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_PUSHBUTTON,
0, btext1, bid1);
r.left = rpos2;
r.right = rwid2;
r.bottom = PUSHBTNHEIGHT;
doctl(cp, r, "BUTTON",
- WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_PUSHBUTTON,
+ BS_NOTIFY | WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_PUSHBUTTON,
0, btext2, bid2);
cp->ypos += height + GAPBETWEEN;
}
/*
+ * A combo box on the right hand side, with a static to its left.
+ */
+void staticcombo(struct ctlpos *cp, char *stext,
+ int sid, int lid, int percentlist)
+{
+ const int height = (COMBOHEIGHT > STATICHEIGHT ?
+ COMBOHEIGHT : STATICHEIGHT);
+ RECT r;
+ int lwid, rwid, rpos;
+
+ rpos =
+ GAPBETWEEN + (100 - percentlist) * (cp->width + GAPBETWEEN) / 100;
+ lwid = rpos - 2 * GAPBETWEEN;
+ rwid = cp->width + GAPBETWEEN - rpos;
+
+ r.left = GAPBETWEEN;
+ r.top = cp->ypos + (height - STATICHEIGHT) / 2;
+ r.right = lwid;
+ r.bottom = STATICHEIGHT;
+ doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0, stext, sid);
+
+ r.left = rpos;
+ r.top = cp->ypos + (height - EDITHEIGHT) / 2;
+ r.right = rwid;
+ r.bottom = COMBOHEIGHT*10;
+ doctl(cp, r, "COMBOBOX",
+ WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_VSCROLL |
+ CBS_DROPDOWN | CBS_HASSTRINGS, WS_EX_CLIENTEDGE, "", lid);
+
+ cp->ypos += height + GAPBETWEEN;
+}
+
+/*
+ * A static, with a full-width drop-down list box below it.
+ */
+void staticddlbig(struct ctlpos *cp, char *stext,
+ int sid, int lid)
+{
+ RECT r;
+
+ r.left = GAPBETWEEN;
+ r.top = cp->ypos;
+ r.right = cp->width;
+ r.bottom = STATICHEIGHT;
+ doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0, stext, sid);
+ cp->ypos += STATICHEIGHT;
+
+ r.left = GAPBETWEEN;
+ r.top = cp->ypos;
+ r.right = cp->width;
+ r.bottom = COMBOHEIGHT*4;
+ doctl(cp, r, "COMBOBOX",
+ WS_CHILD | WS_VISIBLE | WS_TABSTOP |
+ CBS_DROPDOWNLIST | CBS_HASSTRINGS, WS_EX_CLIENTEDGE, "", lid);
+ cp->ypos += COMBOHEIGHT + GAPBETWEEN;
+}
+
+/*
* A big multiline edit control with a static labelling it.
*/
void bigeditctrl(struct ctlpos *cp, char *stext,
}
/*
+ * A list box with a static labelling it.
+ */
+void listbox(struct ctlpos *cp, char *stext,
+ int sid, int lid, int lines, int multi)
+{
+ RECT r;
+
+ if (stext != NULL) {
+ r.left = GAPBETWEEN;
+ r.top = cp->ypos;
+ r.right = cp->width;
+ r.bottom = STATICHEIGHT;
+ cp->ypos += r.bottom + GAPWITHIN;
+ doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0, stext, sid);
+ }
+
+ r.left = GAPBETWEEN;
+ r.top = cp->ypos;
+ r.right = cp->width;
+ r.bottom = LISTHEIGHT + (lines - 1) * LISTINCREMENT;
+ cp->ypos += r.bottom + GAPBETWEEN;
+ doctl(cp, r, "LISTBOX",
+ WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_VSCROLL |
+ LBS_NOTIFY | LBS_HASSTRINGS | LBS_USETABSTOPS |
+ (multi ? LBS_MULTIPLESEL : 0),
+ WS_EX_CLIENTEDGE, "", lid);
+}
+
+/*
* A tab-control substitute when a real tab control is unavailable.
*/
void ersatztab(struct ctlpos *cp, char *stext, int sid, int lid, int s2id)
r.right = rwid;
r.bottom = PUSHBTNHEIGHT;
doctl(cp, r, "BUTTON",
- WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_PUSHBUTTON,
+ BS_NOTIFY | WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_PUSHBUTTON,
0, btext, bid);
cp->ypos += height + GAPBETWEEN;
}
/*
- * Special control which was hard to describe generically: the
- * session-saver assembly. A static; below that an edit box; below
- * that a list box. To the right of the list box, a column of
- * buttons.
+ * A special control for manipulating an ordered preference list
+ * (eg. for cipher selection).
+ * XXX: this is a rough hack and could be improved.
*/
-void sesssaver(struct ctlpos *cp, char *text,
- int staticid, int editid, int listid, ...)
+void prefslist(struct prefslist *hdl, struct ctlpos *cp, int lines,
+ char *stext, int sid, int listid, int upbid, int dnbid)
{
+ const static int percents[] = { 5, 75, 20 };
RECT r;
- va_list ap;
- int lwid, rwid, rpos;
- int y;
- const int LISTDEFHEIGHT = 66;
-
- rpos = GAPBETWEEN + 3 * (cp->width + GAPBETWEEN) / 4;
- lwid = rpos - 2 * GAPBETWEEN;
- rwid = cp->width + GAPBETWEEN - rpos;
-
- /* The static control. */
- r.left = GAPBETWEEN;
- r.top = cp->ypos;
- r.right = lwid;
- r.bottom = STATICHEIGHT;
- cp->ypos += r.bottom + GAPWITHIN;
- doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0, text, staticid);
+ int xpos, percent = 0, i;
+ int listheight = LISTHEIGHT + (lines - 1) * LISTINCREMENT;
+ const int BTNSHEIGHT = 2*PUSHBTNHEIGHT + GAPBETWEEN;
+ int totalheight, buttonpos;
- /* The edit control. */
- r.left = GAPBETWEEN;
- r.top = cp->ypos;
- r.right = lwid;
- r.bottom = EDITHEIGHT;
- cp->ypos += r.bottom + GAPWITHIN;
- doctl(cp, r, "EDIT",
- WS_CHILD | WS_VISIBLE | WS_TABSTOP | ES_AUTOHSCROLL,
- WS_EX_CLIENTEDGE, "", editid);
+ /* Squirrel away IDs. */
+ hdl->listid = listid;
+ hdl->upbid = upbid;
+ hdl->dnbid = dnbid;
- /*
- * The buttons (we should hold off on the list box until we
- * know how big the buttons are).
- */
- va_start(ap, listid);
- y = cp->ypos;
- while (1) {
- char *btext = va_arg(ap, char *);
- int bid;
- if (!btext)
- break;
- bid = va_arg(ap, int);
- r.left = rpos;
- r.top = y;
- r.right = rwid;
- r.bottom = PUSHBTNHEIGHT;
- y += r.bottom + GAPWITHIN;
- doctl(cp, r, "BUTTON",
- WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_PUSHBUTTON,
- 0, btext, bid);
+ /* The static label. */
+ if (stext != NULL) {
+ r.left = GAPBETWEEN;
+ r.top = cp->ypos;
+ r.right = cp->width;
+ r.bottom = STATICHEIGHT;
+ cp->ypos += r.bottom + GAPWITHIN;
+ doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0, stext, sid);
}
- /* Compute list box height. LISTDEFHEIGHT, or height of buttons. */
- y -= cp->ypos;
- y -= GAPWITHIN;
- if (y < LISTDEFHEIGHT)
- y = LISTDEFHEIGHT;
- r.left = GAPBETWEEN;
- r.top = cp->ypos;
- r.right = lwid;
- r.bottom = y;
- cp->ypos += y + GAPBETWEEN;
- doctl(cp, r, "LISTBOX",
- WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_VSCROLL |
- LBS_NOTIFY | LBS_HASSTRINGS, WS_EX_CLIENTEDGE, "", listid);
-}
-
-/*
- * Another special control: the environment-variable setter. A
- * static line first; then a pair of edit boxes with associated
- * statics, and two buttons; then a list box.
- */
-void envsetter(struct ctlpos *cp, char *stext, int sid,
- char *e1stext, int e1sid, int e1id,
- char *e2stext, int e2sid, int e2id,
- int listid, char *b1text, int b1id, char *b2text, int b2id)
-{
- RECT r;
- const int height = (STATICHEIGHT > EDITHEIGHT
- && STATICHEIGHT >
- PUSHBTNHEIGHT ? STATICHEIGHT : EDITHEIGHT >
- PUSHBTNHEIGHT ? EDITHEIGHT : PUSHBTNHEIGHT);
- const static int percents[] = { 20, 35, 10, 25 };
- int i, j, xpos, percent;
- const int LISTHEIGHT = 42;
-
- /* The static control. */
- r.left = GAPBETWEEN;
- r.top = cp->ypos;
- r.right = cp->width;
- r.bottom = STATICHEIGHT;
- cp->ypos += r.bottom + GAPWITHIN;
- doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0, stext, sid);
-
- /* The statics+edits+buttons. */
- for (j = 0; j < 2; j++) {
- percent = 10;
- for (i = 0; i < 4; i++) {
- xpos = (cp->width + GAPBETWEEN) * percent / 100;
- r.left = xpos + GAPBETWEEN;
- percent += percents[i];
- xpos = (cp->width + GAPBETWEEN) * percent / 100;
- r.right = xpos - r.left;
- r.top = cp->ypos;
- r.bottom = (i == 0 ? STATICHEIGHT :
- i == 1 ? EDITHEIGHT : PUSHBTNHEIGHT);
- r.top += (height - r.bottom) / 2;
- if (i == 0) {
- doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0,
- j == 0 ? e1stext : e2stext, j == 0 ? e1sid : e2sid);
- } else if (i == 1) {
- doctl(cp, r, "EDIT",
- WS_CHILD | WS_VISIBLE | WS_TABSTOP | ES_AUTOHSCROLL,
- WS_EX_CLIENTEDGE, "", j == 0 ? e1id : e2id);
- } else if (i == 3) {
- doctl(cp, r, "BUTTON",
- WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_PUSHBUTTON,
- 0, j == 0 ? b1text : b2text, j == 0 ? b1id : b2id);
- }
- }
- cp->ypos += height + GAPWITHIN;
- }
-
- /* The list box. */
- r.left = GAPBETWEEN;
- r.top = cp->ypos;
- r.right = cp->width;
- r.bottom = LISTHEIGHT;
- cp->ypos += r.bottom + GAPBETWEEN;
- doctl(cp, r, "LISTBOX",
- WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_VSCROLL | LBS_HASSTRINGS
- | LBS_USETABSTOPS, WS_EX_CLIENTEDGE, "", listid);
-}
-
-/*
- * Yet another special control: the character-class setter. A
- * static, then a list, then a line containing a
- * button-and-static-and-edit.
- */
-void charclass(struct ctlpos *cp, char *stext, int sid, int listid,
- char *btext, int bid, int eid, char *s2text, int s2id)
-{
- RECT r;
- const int height = (STATICHEIGHT > EDITHEIGHT
- && STATICHEIGHT >
- PUSHBTNHEIGHT ? STATICHEIGHT : EDITHEIGHT >
- PUSHBTNHEIGHT ? EDITHEIGHT : PUSHBTNHEIGHT);
- const static int percents[] = { 30, 40, 30 };
- int i, xpos, percent;
- const int LISTHEIGHT = 52;
-
- /* The static control. */
- r.left = GAPBETWEEN;
- r.top = cp->ypos;
- r.right = cp->width;
- r.bottom = STATICHEIGHT;
- cp->ypos += r.bottom + GAPWITHIN;
- doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0, stext, sid);
-
- /* The list box. */
- r.left = GAPBETWEEN;
- r.top = cp->ypos;
- r.right = cp->width;
- r.bottom = LISTHEIGHT;
- cp->ypos += r.bottom + GAPWITHIN;
- doctl(cp, r, "LISTBOX",
- WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_VSCROLL | LBS_HASSTRINGS
- | LBS_USETABSTOPS, WS_EX_CLIENTEDGE, "", listid);
-
- /* The button+static+edit. */
- percent = xpos = 0;
- for (i = 0; i < 3; i++) {
- r.left = xpos + GAPBETWEEN;
- percent += percents[i];
- xpos = (cp->width + GAPBETWEEN) * percent / 100;
- r.right = xpos - r.left;
- r.top = cp->ypos;
- r.bottom = (i == 0 ? PUSHBTNHEIGHT :
- i == 1 ? STATICHEIGHT : EDITHEIGHT);
- r.top += (height - r.bottom) / 2;
- if (i == 0) {
- doctl(cp, r, "BUTTON",
- WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_PUSHBUTTON,
- 0, btext, bid);
- } else if (i == 1) {
- doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE | SS_CENTER,
- 0, s2text, s2id);
- } else if (i == 2) {
- doctl(cp, r, "EDIT",
- WS_CHILD | WS_VISIBLE | WS_TABSTOP | ES_AUTOHSCROLL,
- WS_EX_CLIENTEDGE, "", eid);
- }
- }
- cp->ypos += height + GAPBETWEEN;
-}
-
-/*
- * A special control (horrors!). The colour editor. A static line;
- * then on the left, a list box, and on the right, a sequence of
- * two-part statics followed by a button.
- */
-void colouredit(struct ctlpos *cp, char *stext, int sid, int listid,
- char *btext, int bid, ...)
-{
- RECT r;
- int y;
- va_list ap;
- int lwid, rwid, rpos;
- const int LISTHEIGHT = 66;
-
- /* The static control. */
- r.left = GAPBETWEEN;
- r.top = cp->ypos;
- r.right = cp->width;
- r.bottom = STATICHEIGHT;
- cp->ypos += r.bottom + GAPWITHIN;
- doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0, stext, sid);
-
- rpos = GAPBETWEEN + 2 * (cp->width + GAPBETWEEN) / 3;
- lwid = rpos - 2 * GAPBETWEEN;
- rwid = cp->width + GAPBETWEEN - rpos;
-
- /* The list box. */
- r.left = GAPBETWEEN;
- r.top = cp->ypos;
- r.right = lwid;
- r.bottom = LISTHEIGHT;
- doctl(cp, r, "LISTBOX",
- WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_VSCROLL | LBS_HASSTRINGS
- | LBS_USETABSTOPS | LBS_NOTIFY, WS_EX_CLIENTEDGE, "", listid);
-
- /* The statics. */
- y = cp->ypos;
- va_start(ap, bid);
- while (1) {
- char *ltext;
- int lid, rid;
- ltext = va_arg(ap, char *);
- if (!ltext)
- break;
- lid = va_arg(ap, int);
- rid = va_arg(ap, int);
- r.top = y;
- r.bottom = STATICHEIGHT;
- y += r.bottom + GAPWITHIN;
- r.left = rpos;
- r.right = rwid / 2;
- doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0, ltext, lid);
- r.left = rpos + r.right;
- r.right = rwid - r.right;
- doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE | SS_RIGHT, 0, "",
- rid);
- }
- va_end(ap);
-
- /* The button. */
- r.top = y + 2 * GAPWITHIN;
- r.bottom = PUSHBTNHEIGHT;
- r.left = rpos;
- r.right = rwid;
- doctl(cp, r, "BUTTON",
- WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_PUSHBUTTON,
- 0, btext, bid);
-
- cp->ypos += LISTHEIGHT + GAPBETWEEN;
-}
-
-/*
- * A special control for manipulating an ordered preference list
- * (eg. for cipher selection).
- * XXX: this is a rough hack and could be improved.
- */
-void prefslist(struct prefslist *hdl, struct ctlpos *cp, char *stext,
- int sid, int listid, int upbid, int dnbid)
-{
- const static int percents[] = { 5, 75, 20 };
- RECT r;
- int xpos, percent = 0, i;
- const int DEFLISTHEIGHT = 52; /* XXX configurable? */
- const int BTNSHEIGHT = 2*PUSHBTNHEIGHT + GAPBETWEEN;
- int totalheight;
-
- /* Squirrel away IDs. */
- hdl->listid = listid;
- hdl->upbid = upbid;
- hdl->dnbid = dnbid;
-
- /* The static label. */
- r.left = GAPBETWEEN;
- r.top = cp->ypos;
- r.right = cp->width;
- r.bottom = STATICHEIGHT;
- cp->ypos += r.bottom + GAPWITHIN;
- doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0, stext, sid);
-
- /* XXX it'd be nice to centre the buttons wrt the listbox
- * but we'd have to find out how high the latter actually is. */
- if (DEFLISTHEIGHT > BTNSHEIGHT) {
- totalheight = DEFLISTHEIGHT;
- } else {
- totalheight = BTNSHEIGHT;
+ if (listheight > BTNSHEIGHT) {
+ totalheight = listheight;
+ buttonpos = (listheight - BTNSHEIGHT) / 2;
+ } else {
+ totalheight = BTNSHEIGHT;
+ buttonpos = 0;
}
for (i=0; i<3; i++) {
case 1:
/* The drag list box. */
r.left = left; r.right = wid;
- r.top = cp->ypos; r.bottom = totalheight;
+ r.top = cp->ypos; r.bottom = listheight;
{
HWND ctl;
ctl = doctl(cp, r, "LISTBOX",
WS_CHILD | WS_VISIBLE | WS_TABSTOP |
- WS_VSCROLL | LBS_HASSTRINGS,
+ WS_VSCROLL | LBS_HASSTRINGS | LBS_USETABSTOPS,
WS_EX_CLIENTEDGE,
"", listid);
MakeDragList(ctl);
/* XXX worry about accelerators if we have more than one
* prefslist on a panel */
r.left = left; r.right = wid;
- r.top = cp->ypos; r.bottom = PUSHBTNHEIGHT;
+ r.top = cp->ypos + buttonpos; r.bottom = PUSHBTNHEIGHT;
doctl(cp, r, "BUTTON",
- WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_PUSHBUTTON,
+ BS_NOTIFY | WS_CHILD | WS_VISIBLE |
+ WS_TABSTOP | BS_PUSHBUTTON,
0, "&Up", upbid);
r.left = left; r.right = wid;
- r.top = cp->ypos + PUSHBTNHEIGHT + GAPBETWEEN;
+ r.top = cp->ypos + buttonpos + PUSHBTNHEIGHT + GAPBETWEEN;
r.bottom = PUSHBTNHEIGHT;
doctl(cp, r, "BUTTON",
- WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_PUSHBUTTON,
+ BS_NOTIFY | WS_CHILD | WS_VISIBLE |
+ WS_TABSTOP | BS_PUSHBUTTON,
0, "&Down", dnbid);
break;
/*
* Handler for prefslist above.
+ *
+ * Return value has bit 0 set if the dialog box procedure needs to
+ * return TRUE from handling this message; it has bit 1 set if a
+ * change may have been made in the contents of the list.
*/
int handle_prefslist(struct prefslist *hdl,
int *array, int maxmemb,
WPARAM wParam, LPARAM lParam)
{
int i;
- int ret;
+ int ret = 0;
if (is_dlmsg) {
hdl->dragging = 0;
/* XXX hack Q183115 */
SetWindowLong(hwnd, DWL_MSGRESULT, TRUE);
- ret = 1; break;
+ ret |= 1; break;
case DL_CANCELDRAG:
DrawInsert(hwnd, dlm->hWnd, -1); /* Clear arrow */
SendDlgItemMessage(hwnd, hdl->listid,
LB_DELETESTRING, hdl->dummyitem, 0);
hdl->dragging = 0;
- ret = 1; break;
+ ret |= 1; break;
case DL_DRAGGING:
hdl->dragging = 1;
dest = pl_itemfrompt(dlm->hWnd, dlm->ptCursor, TRUE);
SetWindowLong(hwnd, DWL_MSGRESULT, DL_MOVECURSOR);
else
SetWindowLong(hwnd, DWL_MSGRESULT, DL_STOPCURSOR);
- ret = 1; break;
+ ret |= 1; break;
case DL_DROPPED:
if (hdl->dragging) {
dest = pl_itemfrompt(dlm->hWnd, dlm->ptCursor, TRUE);
if (dest > hdl->srcitem) dest--;
pl_moveitem(hwnd, hdl->listid, hdl->srcitem, dest);
}
+ ret |= 2;
}
- ret = 1; break;
+ ret |= 1; break;
}
}
} else {
- ret = 0;
if (((LOWORD(wParam) == hdl->upbid) ||
(LOWORD(wParam) == hdl->dnbid)) &&
((HIWORD(wParam) == BN_CLICKED) ||
pl_moveitem(hwnd, hdl->listid, selection, selection - 1);
else if (LOWORD(wParam) == hdl->dnbid && (selection < nitems - 1))
pl_moveitem(hwnd, hdl->listid, selection, selection + 1);
+ ret |= 2;
}
}
}
- /* Update array to match the list box. */
- for (i=0; i < maxmemb; i++)
- array[i] = SendDlgItemMessage (hwnd, hdl->listid, LB_GETITEMDATA,
- i, 0);
+ if (array) {
+ /* Update array to match the list box. */
+ for (i=0; i < maxmemb; i++)
+ array[i] = SendDlgItemMessage (hwnd, hdl->listid, LB_GETITEMDATA,
+ i, 0);
+ }
return ret;
-
}
/*
, WS_EX_CLIENTEDGE, "", id);
}
+/* ----------------------------------------------------------------------
+ * Platform-specific side of portable dialog-box mechanism.
+ */
+
/*
- * Another special control: the forwarding options setter. First a
- * list box; next a static header line, introducing a pair of edit
- * boxes with associated statics, another button, and a radio
- * button pair. Then we have a bareradioline, which is included in
- * this control group because it belongs before the `Add' button in
- * the tab order.
+ * This function takes a string, escapes all the ampersands, and
+ * places a single (unescaped) ampersand in front of the first
+ * occurrence of the given shortcut character (which may be
+ * NO_SHORTCUT).
+ *
+ * Return value is a malloc'ed copy of the processed version of the
+ * string.
*/
-void fwdsetter(struct ctlpos *cp, int listid, char *stext, int sid,
- char *e1stext, int e1sid, int e1id,
- char *e2stext, int e2sid, int e2id,
- char *btext, int bid,
- char *r1text, int r1id, char *r2text, int r2id)
-{
- RECT r, button_r;
- const int height = (STATICHEIGHT > EDITHEIGHT
- && STATICHEIGHT >
- PUSHBTNHEIGHT ? STATICHEIGHT : EDITHEIGHT >
- PUSHBTNHEIGHT ? EDITHEIGHT : PUSHBTNHEIGHT);
- const static int percents[] = { 25, 35, 15, 25 };
- int i, j, xpos, percent;
- const int LISTHEIGHT = 42;
-
- /* The list box. */
- r.left = GAPBETWEEN;
- r.top = cp->ypos;
- r.right = cp->width;
- r.bottom = LISTHEIGHT;
- cp->ypos += r.bottom + GAPBETWEEN;
- doctl(cp, r, "LISTBOX",
- WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_VSCROLL | LBS_HASSTRINGS
- | LBS_USETABSTOPS, WS_EX_CLIENTEDGE, "", listid);
+static char *shortcut_escape(char *text, char shortcut)
+{
+ char *ret;
+ char *p, *q;
+
+ if (!text)
+ return NULL; /* sfree won't choke on this */
+
+ ret = smalloc(2*strlen(text)+1); /* size potentially doubles! */
+ shortcut = tolower((unsigned char)shortcut);
+
+ p = text;
+ q = ret;
+ while (*p) {
+ if (shortcut != NO_SHORTCUT &&
+ tolower((unsigned char)*p) == shortcut) {
+ *q++ = '&';
+ shortcut = NO_SHORTCUT; /* stop it happening twice */
+ } else if (*p == '&') {
+ *q++ = '&';
+ }
+ *q++ = *p++;
+ }
+ *q = '\0';
+ return ret;
+}
- /* The static control. */
- r.left = GAPBETWEEN;
- r.top = cp->ypos;
- r.right = cp->width;
- r.bottom = STATICHEIGHT;
- cp->ypos += r.bottom + GAPWITHIN;
- doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0, stext, sid);
+void winctrl_add_shortcuts(struct dlgparam *dp, struct winctrl *c)
+{
+ int i;
+ for (i = 0; i < lenof(c->shortcuts); i++)
+ if (c->shortcuts[i] != NO_SHORTCUT) {
+ unsigned char s = tolower((unsigned char)c->shortcuts[i]);
+ assert(!dp->shortcuts[s]);
+ dp->shortcuts[s] = TRUE;
+ }
+}
+
+void winctrl_rem_shortcuts(struct dlgparam *dp, struct winctrl *c)
+{
+ int i;
+ for (i = 0; i < lenof(c->shortcuts); i++)
+ if (c->shortcuts[i] != NO_SHORTCUT) {
+ unsigned char s = tolower((unsigned char)c->shortcuts[i]);
+ assert(dp->shortcuts[s]);
+ dp->shortcuts[s] = FALSE;
+ }
+}
+
+static int winctrl_cmp_byctrl(void *av, void *bv)
+{
+ struct winctrl *a = (struct winctrl *)av;
+ struct winctrl *b = (struct winctrl *)bv;
+ if (a->ctrl < b->ctrl)
+ return -1;
+ else if (a->ctrl > b->ctrl)
+ return +1;
+ else
+ return 0;
+}
+static int winctrl_cmp_byid(void *av, void *bv)
+{
+ struct winctrl *a = (struct winctrl *)av;
+ struct winctrl *b = (struct winctrl *)bv;
+ if (a->base_id < b->base_id)
+ return -1;
+ else if (a->base_id > b->base_id)
+ return +1;
+ else
+ return 0;
+}
+static int winctrl_cmp_byctrl_find(void *av, void *bv)
+{
+ union control *a = (union control *)av;
+ struct winctrl *b = (struct winctrl *)bv;
+ if (a < b->ctrl)
+ return -1;
+ else if (a > b->ctrl)
+ return +1;
+ else
+ return 0;
+}
+static int winctrl_cmp_byid_find(void *av, void *bv)
+{
+ int *a = (int *)av;
+ struct winctrl *b = (struct winctrl *)bv;
+ if (*a < b->base_id)
+ return -1;
+ else if (*a >= b->base_id + b->num_ids)
+ return +1;
+ else
+ return 0;
+}
+
+void winctrl_init(struct winctrls *wc)
+{
+ wc->byctrl = newtree234(winctrl_cmp_byctrl);
+ wc->byid = newtree234(winctrl_cmp_byid);
+}
+void winctrl_cleanup(struct winctrls *wc)
+{
+ struct winctrl *c;
+
+ while ((c = index234(wc->byid, 0)) != NULL) {
+ winctrl_remove(wc, c);
+ sfree(c->data);
+ sfree(c);
+ }
- /* The statics+edits+buttons. */
- for (j = 0; j < 2; j++) {
- percent = 0;
- for (i = 0; i < (j ? 2 : 4); i++) {
- xpos = (cp->width + GAPBETWEEN) * percent / 100;
- r.left = xpos + GAPBETWEEN;
- percent += percents[i];
- if (j==1 && i==1) percent = 100;
- xpos = (cp->width + GAPBETWEEN) * percent / 100;
- r.right = xpos - r.left;
- r.top = cp->ypos;
- r.bottom = (i == 0 ? STATICHEIGHT :
- i == 1 ? EDITHEIGHT : PUSHBTNHEIGHT);
- r.top += (height - r.bottom) / 2;
- if (i == 0) {
- doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0,
- j == 0 ? e1stext : e2stext, j == 0 ? e1sid : e2sid);
- } else if (i == 1) {
- doctl(cp, r, "EDIT",
- WS_CHILD | WS_VISIBLE | WS_TABSTOP | ES_AUTOHSCROLL,
- WS_EX_CLIENTEDGE, "", j == 0 ? e1id : e2id);
- } else if (i == 3) {
+ freetree234(wc->byctrl);
+ freetree234(wc->byid);
+ wc->byctrl = wc->byid = NULL;
+}
+
+void winctrl_add(struct winctrls *wc, struct winctrl *c)
+{
+ struct winctrl *ret;
+ if (c->ctrl) {
+ ret = add234(wc->byctrl, c);
+ assert(ret == c);
+ }
+ ret = add234(wc->byid, c);
+ assert(ret == c);
+}
+
+void winctrl_remove(struct winctrls *wc, struct winctrl *c)
+{
+ struct winctrl *ret;
+ ret = del234(wc->byctrl, c);
+ ret = del234(wc->byid, c);
+ assert(ret == c);
+}
+
+struct winctrl *winctrl_findbyctrl(struct winctrls *wc, union control *ctrl)
+{
+ return find234(wc->byctrl, ctrl, winctrl_cmp_byctrl_find);
+}
+
+struct winctrl *winctrl_findbyid(struct winctrls *wc, int id)
+{
+ return find234(wc->byid, &id, winctrl_cmp_byid_find);
+}
+
+struct winctrl *winctrl_findbyindex(struct winctrls *wc, int index)
+{
+ return index234(wc->byid, index);
+}
+
+void winctrl_layout(struct dlgparam *dp, struct winctrls *wc,
+ struct ctlpos *cp, struct controlset *s, int *id)
+{
+ struct ctlpos columns[16];
+ int ncols, colstart, colspan;
+
+ struct ctlpos tabdelays[16];
+ union control *tabdelayed[16];
+ int ntabdelays;
+
+ struct ctlpos pos;
+
+ char shortcuts[MAX_SHORTCUTS_PER_CTRL], nshortcuts;
+ char *escaped;
+ int i, base_id, num_ids, orig_tabdelay;
+ void *data;
+
+ base_id = *id;
+
+ /* Start a containing box, if we have a boxname. */
+ if (s->boxname && *s->boxname) {
+ struct winctrl *c = smalloc(sizeof(struct winctrl));
+ c->ctrl = NULL;
+ c->base_id = base_id;
+ c->num_ids = 1;
+ c->data = NULL;
+ memset(c->shortcuts, NO_SHORTCUT, lenof(c->shortcuts));
+ winctrl_add(wc, c);
+ beginbox(cp, s->boxtitle, base_id);
+ base_id++;
+ }
+
+ /* Draw a title, if we have one. */
+ if (!s->boxname && s->boxtitle) {
+ struct winctrl *c = smalloc(sizeof(struct winctrl));
+ c->ctrl = NULL;
+ c->base_id = base_id;
+ c->num_ids = 1;
+ c->data = dupstr(s->boxtitle);
+ memset(c->shortcuts, NO_SHORTCUT, lenof(c->shortcuts));
+ winctrl_add(wc, c);
+ paneltitle(cp, base_id);
+ base_id++;
+ }
+
+ /* Initially we have just one column. */
+ ncols = 1;
+ columns[0] = *cp; /* structure copy */
+
+ /* And initially, there are no pending tab-delayed controls. */
+ ntabdelays = 0;
+
+ /* Loop over each control in the controlset. */
+ for (i = 0; i < s->ncontrols; i++) {
+ union control *ctrl = s->ctrls[i];
+
+ orig_tabdelay = FALSE;
+
+ /*
+ * Generic processing that pertains to all control types.
+ * At the end of this if statement, we'll have produced
+ * `ctrl' (a pointer to the control we have to create, or
+ * think about creating, in this iteration of the loop),
+ * `pos' (a suitable ctlpos with which to position it), and
+ * `c' (a winctrl structure to receive details of the
+ * dialog IDs). Or we'll have done a `continue', if it was
+ * CTRL_COLUMNS and doesn't require any control creation at
+ * all.
+ */
+ if (ctrl->generic.type == CTRL_COLUMNS) {
+ assert((ctrl->columns.ncols == 1) ^ (ncols == 1));
+
+ if (ncols == 1) {
+ /*
+ * We're splitting into multiple columns.
+ */
+ int lpercent, rpercent, lx, rx, i;
+
+ ncols = ctrl->columns.ncols;
+ assert(ncols <= lenof(columns));
+ for (i = 1; i < ncols; i++)
+ columns[i] = columns[0]; /* structure copy */
+
+ lpercent = 0;
+ for (i = 0; i < ncols; i++) {
+ rpercent = lpercent + ctrl->columns.percentages[i];
+ lx = columns[i].xoff + lpercent *
+ (columns[i].width + GAPBETWEEN) / 100;
+ rx = columns[i].xoff + rpercent *
+ (columns[i].width + GAPBETWEEN) / 100;
+ columns[i].xoff = lx;
+ columns[i].width = rx - lx - GAPBETWEEN;
+ lpercent = rpercent;
+ }
+ } else {
/*
- * We postpone creation of the button until we've
- * done everything else, since it belongs last in
- * the tab order.
+ * We're recombining the various columns into one.
*/
- button_r = r; /* structure copy */
+ int maxy = columns[0].ypos;
+ int i;
+ for (i = 1; i < ncols; i++)
+ if (maxy < columns[i].ypos)
+ maxy = columns[i].ypos;
+ ncols = 1;
+ columns[0] = *cp; /* structure copy */
+ columns[0].ypos = maxy;
+ }
+
+ continue;
+ } else if (ctrl->generic.type == CTRL_TABDELAY) {
+ int i;
+
+ assert(!ctrl->generic.tabdelay);
+ ctrl = ctrl->tabdelay.ctrl;
+ orig_tabdelay = TRUE;
+
+ for (i = 0; i < ntabdelays; i++)
+ if (tabdelayed[i] == ctrl)
+ break;
+ assert(i < ntabdelays); /* we have to have found it */
+
+ pos = tabdelays[i]; /* structure copy */
+
+ } else {
+ /*
+ * If it wasn't one of those, it's a genuine control;
+ * so we'll have to compute a position for it now, by
+ * checking its column span.
+ */
+ int col;
+
+ colstart = COLUMN_START(ctrl->generic.column);
+ colspan = COLUMN_SPAN(ctrl->generic.column);
+
+ pos = columns[colstart]; /* structure copy */
+ pos.width = columns[colstart+colspan-1].width +
+ (columns[colstart+colspan-1].xoff - columns[colstart].xoff);
+
+ for (col = colstart; col < colstart+colspan; col++)
+ if (pos.ypos < columns[col].ypos)
+ pos.ypos = columns[col].ypos;
+
+ /*
+ * If this control is to be tabdelayed, add it to the
+ * tabdelay list, and unset pos.hwnd to inhibit actual
+ * control creation.
+ */
+ if (ctrl->generic.tabdelay) {
+ assert(ntabdelays < lenof(tabdelays));
+ tabdelays[ntabdelays] = pos; /* structure copy */
+ tabdelayed[ntabdelays] = ctrl;
+ ntabdelays++;
+ pos.hwnd = NULL;
}
}
- cp->ypos += height + GAPWITHIN;
+
+ /* Most controls don't need anything in c->data. */
+ data = NULL;
+
+ /* And they all start off with no shortcuts registered. */
+ memset(shortcuts, NO_SHORTCUT, lenof(shortcuts));
+ nshortcuts = 0;
+
+ /*
+ * Now we're ready to actually create the control, by
+ * switching on its type.
+ */
+ switch (ctrl->generic.type) {
+ case CTRL_TEXT:
+ {
+ char *wrapped, *escaped;
+ int lines;
+ num_ids = 1;
+ wrapped = staticwrap(&pos, cp->hwnd,
+ ctrl->generic.label, &lines);
+ escaped = shortcut_escape(wrapped, NO_SHORTCUT);
+ statictext(&pos, escaped, lines, base_id);
+ sfree(escaped);
+ sfree(wrapped);
+ }
+ break;
+ case CTRL_EDITBOX:
+ num_ids = 2; /* static, edit */
+ escaped = shortcut_escape(ctrl->editbox.label,
+ ctrl->editbox.shortcut);
+ shortcuts[nshortcuts++] = ctrl->editbox.shortcut;
+ if (ctrl->editbox.percentwidth == 100) {
+ if (ctrl->editbox.has_list)
+ combobox(&pos, escaped,
+ base_id, base_id+1);
+ else
+ multiedit(&pos, ctrl->editbox.password, escaped,
+ base_id, base_id+1, 100, NULL);
+ } else {
+ if (ctrl->editbox.has_list) {
+ staticcombo(&pos, escaped, base_id, base_id+1,
+ ctrl->editbox.percentwidth);
+ } else {
+ (ctrl->editbox.password ? staticpassedit : staticedit)
+ (&pos, escaped, base_id, base_id+1,
+ ctrl->editbox.percentwidth);
+ }
+ }
+ sfree(escaped);
+ break;
+ case CTRL_RADIO:
+ num_ids = ctrl->radio.nbuttons + 1; /* label as well */
+ {
+ struct radio *buttons;
+ int i;
+
+ escaped = shortcut_escape(ctrl->radio.label,
+ ctrl->radio.shortcut);
+ shortcuts[nshortcuts++] = ctrl->radio.shortcut;
+
+ buttons = smalloc(ctrl->radio.nbuttons * sizeof(struct radio));
+
+ for (i = 0; i < ctrl->radio.nbuttons; i++) {
+ buttons[i].text =
+ shortcut_escape(ctrl->radio.buttons[i],
+ (char)(ctrl->radio.shortcuts ?
+ ctrl->radio.shortcuts[i] :
+ NO_SHORTCUT));
+ buttons[i].id = base_id + 1 + i;
+ if (ctrl->radio.shortcuts) {
+ assert(nshortcuts < MAX_SHORTCUTS_PER_CTRL);
+ shortcuts[nshortcuts++] = ctrl->radio.shortcuts[i];
+ }
+ }
+
+ radioline_common(&pos, escaped, base_id,
+ ctrl->radio.ncolumns,
+ buttons, ctrl->radio.nbuttons);
+
+ for (i = 0; i < ctrl->radio.nbuttons; i++) {
+ sfree(buttons[i].text);
+ }
+ sfree(buttons);
+ sfree(escaped);
+ }
+ break;
+ case CTRL_CHECKBOX:
+ num_ids = 1;
+ escaped = shortcut_escape(ctrl->checkbox.label,
+ ctrl->checkbox.shortcut);
+ shortcuts[nshortcuts++] = ctrl->checkbox.shortcut;
+ checkbox(&pos, escaped, base_id);
+ sfree(escaped);
+ break;
+ case CTRL_BUTTON:
+ escaped = shortcut_escape(ctrl->button.label,
+ ctrl->button.shortcut);
+ shortcuts[nshortcuts++] = ctrl->button.shortcut;
+ num_ids = 1;
+ button(&pos, escaped, base_id, ctrl->button.isdefault);
+ sfree(escaped);
+ break;
+ case CTRL_LISTBOX:
+ num_ids = 2;
+ escaped = shortcut_escape(ctrl->listbox.label,
+ ctrl->listbox.shortcut);
+ shortcuts[nshortcuts++] = ctrl->listbox.shortcut;
+ if (ctrl->listbox.draglist) {
+ data = smalloc(sizeof(struct prefslist));
+ num_ids = 4;
+ prefslist(data, &pos, ctrl->listbox.height, escaped,
+ base_id, base_id+1, base_id+2, base_id+3);
+ shortcuts[nshortcuts++] = 'u'; /* Up */
+ shortcuts[nshortcuts++] = 'd'; /* Down */
+ } else if (ctrl->listbox.height == 0) {
+ /* Drop-down list. */
+ if (ctrl->listbox.percentwidth == 100) {
+ staticddlbig(&pos, escaped,
+ base_id, base_id+1);
+ } else {
+ staticddl(&pos, escaped, base_id,
+ base_id+1, ctrl->listbox.percentwidth);
+ }
+ } else {
+ /* Ordinary list. */
+ listbox(&pos, escaped, base_id, base_id+1,
+ ctrl->listbox.height, ctrl->listbox.multisel);
+ }
+ if (ctrl->listbox.ncols) {
+ /*
+ * This method of getting the box width is a bit of
+ * a hack; we'd do better to try to retrieve the
+ * actual width in dialog units from doctl() just
+ * before MapDialogRect. But that's going to be no
+ * fun, and this should be good enough accuracy.
+ */
+ int width = cp->width * ctrl->listbox.percentwidth;
+ int *tabarray;
+ int i, percent;
+
+ tabarray = smalloc((ctrl->listbox.ncols-1) * sizeof(int));
+ percent = 0;
+ for (i = 0; i < ctrl->listbox.ncols-1; i++) {
+ percent += ctrl->listbox.percentages[i];
+ tabarray[i] = width * percent / 10000;
+ }
+ SendDlgItemMessage(cp->hwnd, base_id+1, LB_SETTABSTOPS,
+ ctrl->listbox.ncols-1, (LPARAM)tabarray);
+ sfree(tabarray);
+ }
+ sfree(escaped);
+ break;
+ case CTRL_FILESELECT:
+ num_ids = 3;
+ escaped = shortcut_escape(ctrl->fileselect.label,
+ ctrl->fileselect.shortcut);
+ shortcuts[nshortcuts++] = ctrl->fileselect.shortcut;
+ editbutton(&pos, escaped, base_id, base_id+1,
+ "Bro&wse...", base_id+2);
+ shortcuts[nshortcuts++] = 'w';
+ sfree(escaped);
+ break;
+ case CTRL_FONTSELECT:
+ num_ids = 3;
+ escaped = shortcut_escape(ctrl->fontselect.label,
+ ctrl->fontselect.shortcut);
+ shortcuts[nshortcuts++] = ctrl->fontselect.shortcut;
+ statictext(&pos, escaped, 1, base_id);
+ staticbtn(&pos, "", base_id+1, "Change...", base_id+2);
+ sfree(escaped);
+ data = smalloc(sizeof(FontSpec));
+ break;
+ default:
+ assert(!"Can't happen");
+ break;
+ }
+
+ /*
+ * Create a `struct winctrl' for this control, and advance
+ * the dialog ID counter, if it's actually been created
+ * (and isn't tabdelayed).
+ */
+ if (pos.hwnd) {
+ struct winctrl *c = smalloc(sizeof(struct winctrl));
+
+ c->ctrl = ctrl;
+ c->base_id = base_id;
+ c->num_ids = num_ids;
+ c->data = data;
+ memcpy(c->shortcuts, shortcuts, sizeof(shortcuts));
+ winctrl_add(wc, c);
+ winctrl_add_shortcuts(dp, c);
+ base_id += num_ids;
+ }
+
+ if (!orig_tabdelay) {
+ /*
+ * Update the ypos in all columns crossed by this
+ * control.
+ */
+ int i;
+ for (i = colstart; i < colstart+colspan; i++)
+ columns[i].ypos = pos.ypos;
+ }
}
- bareradioline(cp, 2, r1text, r1id, r2text, r2id, NULL);
- /* Create the postponed button. */
- doctl(cp, button_r, "BUTTON",
- WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_PUSHBUTTON,
- 0, btext, bid);
+
+ /*
+ * We've now finished laying out the controls; so now update
+ * the ctlpos and control ID that were passed in, terminate
+ * any containing box, and return.
+ */
+ for (i = 0; i < ncols; i++)
+ if (cp->ypos < columns[i].ypos)
+ cp->ypos = columns[i].ypos;
+ *id = base_id;
+
+ if (s->boxname && *s->boxname)
+ endbox(cp);
+}
+
+static void winctrl_set_focus(union control *ctrl, struct dlgparam *dp,
+ int has_focus)
+{
+ if (has_focus) {
+ if (dp->focused)
+ dp->lastfocused = dp->focused;
+ dp->focused = ctrl;
+ } else if (!has_focus && dp->focused == ctrl) {
+ dp->lastfocused = dp->focused;
+ dp->focused = NULL;
+ }
+}
+
+union control *dlg_last_focused(void *dlg)
+{
+ struct dlgparam *dp = (struct dlgparam *)dlg;
+ return dp->lastfocused;
+}
+
+/*
+ * The dialog-box procedure calls this function to handle Windows
+ * messages on a control we manage.
+ */
+int winctrl_handle_command(struct dlgparam *dp, UINT msg,
+ WPARAM wParam, LPARAM lParam)
+{
+ struct winctrl *c;
+ union control *ctrl;
+ int i, id, ret;
+ static UINT draglistmsg = WM_NULL;
+
+ /*
+ * Filter out pointless window messages. Our interest is in
+ * WM_COMMAND and the drag list message, and nothing else.
+ */
+ if (draglistmsg == WM_NULL)
+ draglistmsg = RegisterWindowMessage (DRAGLISTMSGSTRING);
+
+ if (msg != draglistmsg && msg != WM_COMMAND && msg != WM_DRAWITEM)
+ return 0;
+
+ /*
+ * Look up the control ID in our data.
+ */
+ for (i = 0; i < dp->nctrltrees; i++) {
+ c = winctrl_findbyid(dp->controltrees[i], LOWORD(wParam));
+ if (c)
+ break;
+ }
+ if (!c)
+ return 0; /* we have nothing to do */
+
+ if (msg == WM_DRAWITEM) {
+ /*
+ * Owner-draw request for a panel title.
+ */
+ LPDRAWITEMSTRUCT di = (LPDRAWITEMSTRUCT) lParam;
+ HDC hdc = di->hDC;
+ RECT r = di->rcItem;
+ SIZE s;
+
+ GetTextExtentPoint32(hdc, (char *)c->data,
+ strlen((char *)c->data), &s);
+ DrawEdge(hdc, &r, EDGE_ETCHED, BF_ADJUST | BF_RECT);
+ TextOut(hdc,
+ r.left + (r.right-r.left-s.cx)/2,
+ r.top + (r.bottom-r.top-s.cy)/2,
+ (char *)c->data, strlen((char *)c->data));
+
+ return TRUE;
+ }
+
+ ctrl = c->ctrl;
+ id = LOWORD(wParam) - c->base_id;
+
+ if (!ctrl || !ctrl->generic.handler)
+ return 0; /* nothing we can do here */
+
+ /*
+ * From here on we do not issue `return' statements until the
+ * very end of the dialog box: any event handler is entitled to
+ * ask for a colour selector, so we _must_ always allow control
+ * to reach the end of this switch statement so that the
+ * subsequent code can test dp->coloursel_wanted().
+ */
+ ret = 0;
+ dp->coloursel_wanted = FALSE;
+
+ /*
+ * Now switch on the control type and the message.
+ */
+ switch (ctrl->generic.type) {
+ case CTRL_EDITBOX:
+ if (msg == WM_COMMAND && !ctrl->editbox.has_list &&
+ (HIWORD(wParam) == EN_SETFOCUS || HIWORD(wParam) == EN_KILLFOCUS))
+ winctrl_set_focus(ctrl, dp, HIWORD(wParam) == EN_SETFOCUS);
+ if (msg == WM_COMMAND && ctrl->editbox.has_list &&
+ (HIWORD(wParam)==CBN_SETFOCUS || HIWORD(wParam)==CBN_KILLFOCUS))
+ winctrl_set_focus(ctrl, dp, HIWORD(wParam) == CBN_SETFOCUS);
+
+ if (msg == WM_COMMAND && !ctrl->editbox.has_list &&
+ HIWORD(wParam) == EN_CHANGE)
+ ctrl->generic.handler(ctrl, dp, dp->data, EVENT_VALCHANGE);
+ if (msg == WM_COMMAND &&
+ ctrl->editbox.has_list) {
+ if (HIWORD(wParam) == CBN_SELCHANGE) {
+ int index, len;
+ char *text;
+
+ index = SendDlgItemMessage(dp->hwnd, c->base_id+1,
+ CB_GETCURSEL, 0, 0);
+ len = SendDlgItemMessage(dp->hwnd, c->base_id+1,
+ CB_GETLBTEXTLEN, index, 0);
+ text = smalloc(len+1);
+ SendDlgItemMessage(dp->hwnd, c->base_id+1, CB_GETLBTEXT,
+ index, (LPARAM)text);
+ SetDlgItemText(dp->hwnd, c->base_id+1, text);
+ sfree(text);
+ ctrl->generic.handler(ctrl, dp, dp->data, EVENT_VALCHANGE);
+ } else if (HIWORD(wParam) == CBN_EDITCHANGE) {
+ ctrl->generic.handler(ctrl, dp, dp->data, EVENT_VALCHANGE);
+ } else if (HIWORD(wParam) == CBN_KILLFOCUS) {
+ ctrl->generic.handler(ctrl, dp, dp->data, EVENT_REFRESH);
+ }
+
+ }
+ break;
+ case CTRL_RADIO:
+ if (msg == WM_COMMAND &&
+ (HIWORD(wParam) == BN_SETFOCUS || HIWORD(wParam) == BN_KILLFOCUS))
+ winctrl_set_focus(ctrl, dp, HIWORD(wParam) == BN_SETFOCUS);
+ /*
+ * We sometimes get spurious BN_CLICKED messages for the
+ * radio button that is just about to _lose_ selection, if
+ * we're switching using the arrow keys. Therefore we
+ * double-check that the button in wParam is actually
+ * checked before generating an event.
+ */
+ if (msg == WM_COMMAND &&
+ HIWORD(wParam) == BN_CLICKED ||
+ HIWORD(wParam) == BN_DOUBLECLICKED &&
+ IsDlgButtonChecked(dp->hwnd, LOWORD(wParam))) {
+ ctrl->generic.handler(ctrl, dp, dp->data, EVENT_VALCHANGE);
+ }
+ break;
+ case CTRL_CHECKBOX:
+ if (msg == WM_COMMAND &&
+ (HIWORD(wParam) == BN_SETFOCUS || HIWORD(wParam) == BN_KILLFOCUS))
+ winctrl_set_focus(ctrl, dp, HIWORD(wParam) == BN_SETFOCUS);
+ if (msg == WM_COMMAND &&
+ (HIWORD(wParam) == BN_CLICKED ||
+ HIWORD(wParam) == BN_DOUBLECLICKED)) {
+ ctrl->generic.handler(ctrl, dp, dp->data, EVENT_VALCHANGE);
+ }
+ break;
+ case CTRL_BUTTON:
+ if (msg == WM_COMMAND &&
+ (HIWORD(wParam) == BN_SETFOCUS || HIWORD(wParam) == BN_KILLFOCUS))
+ winctrl_set_focus(ctrl, dp, HIWORD(wParam) == BN_SETFOCUS);
+ if (msg == WM_COMMAND &&
+ (HIWORD(wParam) == BN_CLICKED ||
+ HIWORD(wParam) == BN_DOUBLECLICKED)) {
+ ctrl->generic.handler(ctrl, dp, dp->data, EVENT_ACTION);
+ }
+ break;
+ case CTRL_LISTBOX:
+ if (msg == WM_COMMAND && ctrl->listbox.height != 0 &&
+ (HIWORD(wParam)==LBN_SETFOCUS || HIWORD(wParam)==LBN_KILLFOCUS))
+ winctrl_set_focus(ctrl, dp, HIWORD(wParam) == LBN_SETFOCUS);
+ if (msg == WM_COMMAND && ctrl->listbox.height == 0 &&
+ (HIWORD(wParam)==CBN_SETFOCUS || HIWORD(wParam)==CBN_KILLFOCUS))
+ winctrl_set_focus(ctrl, dp, HIWORD(wParam) == CBN_SETFOCUS);
+ if (msg == WM_COMMAND && id >= 2 &&
+ (HIWORD(wParam) == BN_SETFOCUS || HIWORD(wParam) == BN_KILLFOCUS))
+ winctrl_set_focus(ctrl, dp, HIWORD(wParam) == BN_SETFOCUS);
+ if (ctrl->listbox.draglist) {
+ int pret;
+ pret = handle_prefslist(c->data, NULL, 0, (msg != WM_COMMAND),
+ dp->hwnd, wParam, lParam);
+ if (pret & 2)
+ ctrl->generic.handler(ctrl, dp, dp->data, EVENT_VALCHANGE);
+ ret = pret & 1;
+ } else {
+ if (msg == WM_COMMAND && HIWORD(wParam) == LBN_DBLCLK) {
+ SetCapture(dp->hwnd);
+ ctrl->generic.handler(ctrl, dp, dp->data, EVENT_ACTION);
+ } else if (msg == WM_COMMAND && HIWORD(wParam) == LBN_SELCHANGE) {
+ ctrl->generic.handler(ctrl, dp, dp->data, EVENT_SELCHANGE);
+ }
+ }
+ break;
+ case CTRL_FILESELECT:
+ if (msg == WM_COMMAND && id == 1 &&
+ (HIWORD(wParam) == EN_SETFOCUS || HIWORD(wParam) == EN_KILLFOCUS))
+ winctrl_set_focus(ctrl, dp, HIWORD(wParam) == EN_SETFOCUS);
+ if (msg == WM_COMMAND && id == 2 &&
+ (HIWORD(wParam) == BN_SETFOCUS || HIWORD(wParam) == BN_KILLFOCUS))
+ winctrl_set_focus(ctrl, dp, HIWORD(wParam) == BN_SETFOCUS);
+ if (id == 2 &&
+ (msg == WM_COMMAND &&
+ (HIWORD(wParam) == BN_CLICKED ||
+ HIWORD(wParam) == BN_DOUBLECLICKED))) {
+ OPENFILENAME of;
+ char filename[FILENAME_MAX];
+ int ret;
+
+ memset(&of, 0, sizeof(of));
+#ifdef OPENFILENAME_SIZE_VERSION_400
+ of.lStructSize = OPENFILENAME_SIZE_VERSION_400;
+#else
+ of.lStructSize = sizeof(of);
+#endif
+ of.hwndOwner = dp->hwnd;
+ if (ctrl->fileselect.filter)
+ of.lpstrFilter = ctrl->fileselect.filter;
+ else
+ of.lpstrFilter = "All Files (*.*)\0*\0\0\0";
+ of.lpstrCustomFilter = NULL;
+ of.nFilterIndex = 1;
+ of.lpstrFile = filename;
+ GetDlgItemText(dp->hwnd, c->base_id+1, filename, lenof(filename));
+ filename[lenof(filename)-1] = '\0';
+ of.nMaxFile = lenof(filename);
+ of.lpstrFileTitle = NULL;
+ of.lpstrInitialDir = NULL;
+ of.lpstrTitle = ctrl->fileselect.title;
+ of.Flags = 0;
+ if (ctrl->fileselect.for_writing)
+ ret = GetSaveFileName(&of);
+ else
+ ret = GetOpenFileName(&of);
+ if (ret) {
+ SetDlgItemText(dp->hwnd, c->base_id + 1, filename);
+ ctrl->generic.handler(ctrl, dp, dp->data, EVENT_VALCHANGE);
+ }
+ }
+ break;
+ case CTRL_FONTSELECT:
+ if (msg == WM_COMMAND && id == 2 &&
+ (HIWORD(wParam) == BN_SETFOCUS || HIWORD(wParam) == BN_KILLFOCUS))
+ winctrl_set_focus(ctrl, dp, HIWORD(wParam) == BN_SETFOCUS);
+ if (id == 2 &&
+ (msg == WM_COMMAND &&
+ (HIWORD(wParam) == BN_CLICKED ||
+ HIWORD(wParam) == BN_DOUBLECLICKED))) {
+ CHOOSEFONT cf;
+ LOGFONT lf;
+ HDC hdc;
+ FontSpec fs = *(FontSpec *)c->data;
+
+ hdc = GetDC(0);
+ lf.lfHeight = -MulDiv(fs.height,
+ GetDeviceCaps(hdc, LOGPIXELSY), 72);
+ ReleaseDC(0, hdc);
+ lf.lfWidth = lf.lfEscapement = lf.lfOrientation = 0;
+ lf.lfItalic = lf.lfUnderline = lf.lfStrikeOut = 0;
+ lf.lfWeight = (fs.isbold ? FW_BOLD : 0);
+ lf.lfCharSet = fs.charset;
+ lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
+ lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
+ lf.lfQuality = DEFAULT_QUALITY;
+ lf.lfPitchAndFamily = FIXED_PITCH | FF_DONTCARE;
+ strncpy(lf.lfFaceName, fs.name,
+ sizeof(lf.lfFaceName) - 1);
+ lf.lfFaceName[sizeof(lf.lfFaceName) - 1] = '\0';
+
+ cf.lStructSize = sizeof(cf);
+ cf.hwndOwner = dp->hwnd;
+ cf.lpLogFont = &lf;
+ cf.Flags = CF_FIXEDPITCHONLY | CF_FORCEFONTEXIST |
+ CF_INITTOLOGFONTSTRUCT | CF_SCREENFONTS;
+
+ if (ChooseFont(&cf)) {
+ strncpy(fs.name, lf.lfFaceName,
+ sizeof(fs.name) - 1);
+ fs.name[sizeof(fs.name) - 1] = '\0';
+ fs.isbold = (lf.lfWeight == FW_BOLD);
+ fs.charset = lf.lfCharSet;
+ fs.height = cf.iPointSize / 10;
+ dlg_fontsel_set(ctrl, dp, fs);
+ ctrl->generic.handler(ctrl, dp, dp->data, EVENT_VALCHANGE);
+ }
+ }
+ break;
+ }
+
+ /*
+ * If the above event handler has asked for a colour selector,
+ * now is the time to generate one.
+ */
+ if (dp->coloursel_wanted) {
+ static CHOOSECOLOR cc;
+ static DWORD custom[16] = { 0 }; /* zero initialisers */
+ cc.lStructSize = sizeof(cc);
+ cc.hwndOwner = dp->hwnd;
+ cc.hInstance = (HWND) hinst;
+ cc.lpCustColors = custom;
+ cc.rgbResult = RGB(dp->coloursel_result.r,
+ dp->coloursel_result.g,
+ dp->coloursel_result.b);
+ cc.Flags = CC_FULLOPEN | CC_RGBINIT;
+ if (ChooseColor(&cc)) {
+ dp->coloursel_result.r =
+ (unsigned char) (cc.rgbResult & 0xFF);
+ dp->coloursel_result.g =
+ (unsigned char) (cc.rgbResult >> 8) & 0xFF;
+ dp->coloursel_result.b =
+ (unsigned char) (cc.rgbResult >> 16) & 0xFF;
+ dp->coloursel_result.ok = TRUE;
+ } else
+ dp->coloursel_result.ok = FALSE;
+ ctrl->generic.handler(ctrl, dp, dp->data, EVENT_CALLBACK);
+ }
+
+ return ret;
+}
+
+/*
+ * This function can be called to produce context help on a
+ * control. Returns TRUE if it has actually launched WinHelp.
+ */
+int winctrl_context_help(struct dlgparam *dp, HWND hwnd, int id)
+{
+ int i;
+ struct winctrl *c;
+ char *cmd;
+
+ /*
+ * Look up the control ID in our data.
+ */
+ for (i = 0; i < dp->nctrltrees; i++) {
+ c = winctrl_findbyid(dp->controltrees[i], id);
+ if (c)
+ break;
+ }
+ if (!c)
+ return 0; /* we have nothing to do */
+
+ /*
+ * This is the Windows front end, so we're allowed to assume
+ * `helpctx.p' is a context string.
+ */
+ if (!c->ctrl || !c->ctrl->generic.helpctx.p)
+ return 0; /* no help available for this ctrl */
+
+ cmd = dupprintf("JI(`',`%s')", c->ctrl->generic.helpctx.p);
+ WinHelp(hwnd, help_path, HELP_COMMAND, (DWORD)cmd);
+ sfree(cmd);
+ return 1;
+}
+
+/*
+ * Now the various functions that the platform-independent
+ * mechanism can call to access the dialog box entries.
+ */
+
+static struct winctrl *dlg_findbyctrl(struct dlgparam *dp, union control *ctrl)
+{
+ int i;
+
+ for (i = 0; i < dp->nctrltrees; i++) {
+ struct winctrl *c = winctrl_findbyctrl(dp->controltrees[i], ctrl);
+ if (c)
+ return c;
+ }
+ return NULL;
+}
+
+void dlg_radiobutton_set(union control *ctrl, void *dlg, int whichbutton)
+{
+ struct dlgparam *dp = (struct dlgparam *)dlg;
+ struct winctrl *c = dlg_findbyctrl(dp, ctrl);
+ assert(c && c->ctrl->generic.type == CTRL_RADIO);
+ CheckRadioButton(dp->hwnd,
+ c->base_id + 1,
+ c->base_id + c->ctrl->radio.nbuttons,
+ c->base_id + 1 + whichbutton);
+}
+
+int dlg_radiobutton_get(union control *ctrl, void *dlg)
+{
+ struct dlgparam *dp = (struct dlgparam *)dlg;
+ struct winctrl *c = dlg_findbyctrl(dp, ctrl);
+ int i;
+ assert(c && c->ctrl->generic.type == CTRL_RADIO);
+ for (i = 0; i < c->ctrl->radio.nbuttons; i++)
+ if (IsDlgButtonChecked(dp->hwnd, c->base_id + 1 + i))
+ return i;
+ assert(!"No radio button was checked?!");
+ return 0;
+}
+
+void dlg_checkbox_set(union control *ctrl, void *dlg, int checked)
+{
+ struct dlgparam *dp = (struct dlgparam *)dlg;
+ struct winctrl *c = dlg_findbyctrl(dp, ctrl);
+ assert(c && c->ctrl->generic.type == CTRL_CHECKBOX);
+ CheckDlgButton(dp->hwnd, c->base_id, (checked != 0));
+}
+
+int dlg_checkbox_get(union control *ctrl, void *dlg)
+{
+ struct dlgparam *dp = (struct dlgparam *)dlg;
+ struct winctrl *c = dlg_findbyctrl(dp, ctrl);
+ assert(c && c->ctrl->generic.type == CTRL_CHECKBOX);
+ return 0 != IsDlgButtonChecked(dp->hwnd, c->base_id);
+}
+
+void dlg_editbox_set(union control *ctrl, void *dlg, char const *text)
+{
+ struct dlgparam *dp = (struct dlgparam *)dlg;
+ struct winctrl *c = dlg_findbyctrl(dp, ctrl);
+ assert(c && c->ctrl->generic.type == CTRL_EDITBOX);
+ SetDlgItemText(dp->hwnd, c->base_id+1, text);
+}
+
+void dlg_editbox_get(union control *ctrl, void *dlg, char *buffer, int length)
+{
+ struct dlgparam *dp = (struct dlgparam *)dlg;
+ struct winctrl *c = dlg_findbyctrl(dp, ctrl);
+ assert(c && c->ctrl->generic.type == CTRL_EDITBOX);
+ GetDlgItemText(dp->hwnd, c->base_id+1, buffer, length);
+ buffer[length-1] = '\0';
+}
+
+/* The `listbox' functions can also apply to combo boxes. */
+void dlg_listbox_clear(union control *ctrl, void *dlg)
+{
+ struct dlgparam *dp = (struct dlgparam *)dlg;
+ struct winctrl *c = dlg_findbyctrl(dp, ctrl);
+ int msg;
+ assert(c &&
+ (c->ctrl->generic.type == CTRL_LISTBOX ||
+ c->ctrl->generic.type == CTRL_EDITBOX &&
+ c->ctrl->editbox.has_list));
+ msg = (c->ctrl->generic.type==CTRL_LISTBOX && c->ctrl->listbox.height!=0 ?
+ LB_RESETCONTENT : CB_RESETCONTENT);
+ SendDlgItemMessage(dp->hwnd, c->base_id+1, msg, 0, 0);
+}
+
+void dlg_listbox_del(union control *ctrl, void *dlg, int index)
+{
+ struct dlgparam *dp = (struct dlgparam *)dlg;
+ struct winctrl *c = dlg_findbyctrl(dp, ctrl);
+ int msg;
+ assert(c &&
+ (c->ctrl->generic.type == CTRL_LISTBOX ||
+ c->ctrl->generic.type == CTRL_EDITBOX &&
+ c->ctrl->editbox.has_list));
+ msg = (c->ctrl->generic.type==CTRL_LISTBOX && c->ctrl->listbox.height!=0 ?
+ LB_DELETESTRING : CB_DELETESTRING);
+ SendDlgItemMessage(dp->hwnd, c->base_id+1, msg, index, 0);
+}
+
+void dlg_listbox_add(union control *ctrl, void *dlg, char const *text)
+{
+ struct dlgparam *dp = (struct dlgparam *)dlg;
+ struct winctrl *c = dlg_findbyctrl(dp, ctrl);
+ int msg;
+ assert(c &&
+ (c->ctrl->generic.type == CTRL_LISTBOX ||
+ c->ctrl->generic.type == CTRL_EDITBOX &&
+ c->ctrl->editbox.has_list));
+ msg = (c->ctrl->generic.type==CTRL_LISTBOX && c->ctrl->listbox.height!=0 ?
+ LB_ADDSTRING : CB_ADDSTRING);
+ SendDlgItemMessage(dp->hwnd, c->base_id+1, msg, 0, (LPARAM)text);
+}
+
+/*
+ * Each listbox entry may have a numeric id associated with it.
+ * Note that some front ends only permit a string to be stored at
+ * each position, which means that _if_ you put two identical
+ * strings in any listbox then you MUST not assign them different
+ * IDs and expect to get meaningful results back.
+ */
+void dlg_listbox_addwithindex(union control *ctrl, void *dlg,
+ char const *text, int id)
+{
+ struct dlgparam *dp = (struct dlgparam *)dlg;
+ struct winctrl *c = dlg_findbyctrl(dp, ctrl);
+ int msg, msg2, index;
+ assert(c &&
+ (c->ctrl->generic.type == CTRL_LISTBOX ||
+ c->ctrl->generic.type == CTRL_EDITBOX &&
+ c->ctrl->editbox.has_list));
+ msg = (c->ctrl->generic.type==CTRL_LISTBOX && c->ctrl->listbox.height!=0 ?
+ LB_ADDSTRING : CB_ADDSTRING);
+ msg2 = (c->ctrl->generic.type==CTRL_LISTBOX && c->ctrl->listbox.height!=0 ?
+ LB_SETITEMDATA : CB_SETITEMDATA);
+ index = SendDlgItemMessage(dp->hwnd, c->base_id+1, msg, 0, (LPARAM)text);
+ SendDlgItemMessage(dp->hwnd, c->base_id+1, msg2, index, (LPARAM)id);
+}
+
+int dlg_listbox_getid(union control *ctrl, void *dlg, int index)
+{
+ struct dlgparam *dp = (struct dlgparam *)dlg;
+ struct winctrl *c = dlg_findbyctrl(dp, ctrl);
+ int msg;
+ assert(c && c->ctrl->generic.type == CTRL_LISTBOX);
+ msg = (c->ctrl->listbox.height != 0 ? LB_GETITEMDATA : CB_GETITEMDATA);
+ return
+ SendDlgItemMessage(dp->hwnd, c->base_id+1, msg, index, 0);
+}
+
+/* dlg_listbox_index returns <0 if no single element is selected. */
+int dlg_listbox_index(union control *ctrl, void *dlg)
+{
+ struct dlgparam *dp = (struct dlgparam *)dlg;
+ struct winctrl *c = dlg_findbyctrl(dp, ctrl);
+ int msg, ret;
+ assert(c && c->ctrl->generic.type == CTRL_LISTBOX &&
+ !c->ctrl->listbox.multisel);
+ msg = (c->ctrl->listbox.height != 0 ? LB_GETCURSEL : CB_GETCURSEL);
+ ret = SendDlgItemMessage(dp->hwnd, c->base_id+1, msg, 0, 0);
+ if (ret == LB_ERR)
+ return -1;
+ else
+ return ret;
+}
+
+int dlg_listbox_issel(union control *ctrl, void *dlg, int index)
+{
+ struct dlgparam *dp = (struct dlgparam *)dlg;
+ struct winctrl *c = dlg_findbyctrl(dp, ctrl);
+ assert(c && c->ctrl->generic.type == CTRL_LISTBOX &&
+ c->ctrl->listbox.multisel &&
+ c->ctrl->listbox.height != 0);
+ return
+ SendDlgItemMessage(dp->hwnd, c->base_id+1, LB_GETSEL, index, 0);
+}
+
+void dlg_listbox_select(union control *ctrl, void *dlg, int index)
+{
+ struct dlgparam *dp = (struct dlgparam *)dlg;
+ struct winctrl *c = dlg_findbyctrl(dp, ctrl);
+ int msg;
+ assert(c && c->ctrl->generic.type == CTRL_LISTBOX &&
+ !c->ctrl->listbox.multisel);
+ msg = (c->ctrl->listbox.height != 0 ? LB_SETCURSEL : CB_SETCURSEL);
+ SendDlgItemMessage(dp->hwnd, c->base_id+1, msg, index, 0);
+}
+
+void dlg_text_set(union control *ctrl, void *dlg, char const *text)
+{
+ struct dlgparam *dp = (struct dlgparam *)dlg;
+ struct winctrl *c = dlg_findbyctrl(dp, ctrl);
+ assert(c && c->ctrl->generic.type == CTRL_TEXT);
+ SetDlgItemText(dp->hwnd, c->base_id, text);
+}
+
+void dlg_filesel_set(union control *ctrl, void *dlg, Filename fn)
+{
+ struct dlgparam *dp = (struct dlgparam *)dlg;
+ struct winctrl *c = dlg_findbyctrl(dp, ctrl);
+ assert(c && c->ctrl->generic.type == CTRL_FILESELECT);
+ SetDlgItemText(dp->hwnd, c->base_id+1, fn.path);
+}
+
+void dlg_filesel_get(union control *ctrl, void *dlg, Filename *fn)
+{
+ struct dlgparam *dp = (struct dlgparam *)dlg;
+ struct winctrl *c = dlg_findbyctrl(dp, ctrl);
+ assert(c && c->ctrl->generic.type == CTRL_FILESELECT);
+ GetDlgItemText(dp->hwnd, c->base_id+1, fn->path, lenof(fn->path));
+ fn->path[lenof(fn->path)-1] = '\0';
+}
+
+void dlg_fontsel_set(union control *ctrl, void *dlg, FontSpec fs)
+{
+ char *buf, *boldstr;
+ struct dlgparam *dp = (struct dlgparam *)dlg;
+ struct winctrl *c = dlg_findbyctrl(dp, ctrl);
+ assert(c && c->ctrl->generic.type == CTRL_FONTSELECT);
+
+ *(FontSpec *)c->data = fs; /* structure copy */
+
+ boldstr = (fs.isbold ? "bold, " : "");
+ if (fs.height == 0)
+ buf = dupprintf("Font: %s, %sdefault height", fs.name, boldstr);
+ else
+ buf = dupprintf("Font: %s, %s%d-point", fs.name, boldstr,
+ (fs.height < 0 ? -fs.height : fs.height));
+ SetDlgItemText(dp->hwnd, c->base_id+1, buf);
+ sfree(buf);
+}
+
+void dlg_fontsel_get(union control *ctrl, void *dlg, FontSpec *fs)
+{
+ struct dlgparam *dp = (struct dlgparam *)dlg;
+ struct winctrl *c = dlg_findbyctrl(dp, ctrl);
+ assert(c && c->ctrl->generic.type == CTRL_FONTSELECT);
+ *fs = *(FontSpec *)c->data; /* structure copy */
+}
+
+/*
+ * Bracketing a large set of updates in these two functions will
+ * cause the front end (if possible) to delay updating the screen
+ * until it's all complete, thus avoiding flicker.
+ */
+void dlg_update_start(union control *ctrl, void *dlg)
+{
+ struct dlgparam *dp = (struct dlgparam *)dlg;
+ struct winctrl *c = dlg_findbyctrl(dp, ctrl);
+ if (c && c->ctrl->generic.type == CTRL_LISTBOX) {
+ SendDlgItemMessage(dp->hwnd, c->base_id+1, WM_SETREDRAW, FALSE, 0);
+ }
+}
+
+void dlg_update_done(union control *ctrl, void *dlg)
+{
+ struct dlgparam *dp = (struct dlgparam *)dlg;
+ struct winctrl *c = dlg_findbyctrl(dp, ctrl);
+ if (c && c->ctrl->generic.type == CTRL_LISTBOX) {
+ HWND hw = GetDlgItem(dp->hwnd, c->base_id+1);
+ SendMessage(hw, WM_SETREDRAW, TRUE, 0);
+ InvalidateRect(hw, NULL, TRUE);
+ }
+}
+
+void dlg_set_focus(union control *ctrl, void *dlg)
+{
+ struct dlgparam *dp = (struct dlgparam *)dlg;
+ struct winctrl *c = dlg_findbyctrl(dp, ctrl);
+ int id;
+ HWND ctl;
+ switch (ctrl->generic.type) {
+ case CTRL_EDITBOX: id = c->base_id + 1; break;
+ case CTRL_RADIO:
+ for (id = c->base_id + ctrl->radio.nbuttons; id > 1; id--)
+ if (IsDlgButtonChecked(dp->hwnd, id))
+ break;
+ /*
+ * In the theoretically-unlikely case that no button was
+ * selected, id should come out of this as 1, which is a
+ * reasonable enough choice.
+ */
+ break;
+ case CTRL_CHECKBOX: id = c->base_id; break;
+ case CTRL_BUTTON: id = c->base_id; break;
+ case CTRL_LISTBOX: id = c->base_id + 1; break;
+ case CTRL_FILESELECT: id = c->base_id + 1; break;
+ case CTRL_FONTSELECT: id = c->base_id + 2; break;
+ default: id = c->base_id; break;
+ }
+ ctl = GetDlgItem(dp->hwnd, id);
+ SetFocus(ctl);
+}
+
+/*
+ * During event processing, you might well want to give an error
+ * indication to the user. dlg_beep() is a quick and easy generic
+ * error; dlg_error() puts up a message-box or equivalent.
+ */
+void dlg_beep(void *dlg)
+{
+ /* struct dlgparam *dp = (struct dlgparam *)dlg; */
+ MessageBeep(0);
+}
+
+void dlg_error_msg(void *dlg, char *msg)
+{
+ struct dlgparam *dp = (struct dlgparam *)dlg;
+ MessageBox(dp->hwnd, msg,
+ dp->errtitle ? dp->errtitle : NULL,
+ MB_OK | MB_ICONERROR);
+}
+
+/*
+ * This function signals to the front end that the dialog's
+ * processing is completed, and passes an integer value (typically
+ * a success status).
+ */
+void dlg_end(void *dlg, int value)
+{
+ struct dlgparam *dp = (struct dlgparam *)dlg;
+ dp->ended = TRUE;
+ dp->endresult = value;
+}
+
+void dlg_refresh(union control *ctrl, void *dlg)
+{
+ struct dlgparam *dp = (struct dlgparam *)dlg;
+ int i, j;
+ struct winctrl *c;
+
+ if (!ctrl) {
+ /*
+ * Send EVENT_REFRESH to absolutely everything.
+ */
+ for (j = 0; j < dp->nctrltrees; j++) {
+ for (i = 0;
+ (c = winctrl_findbyindex(dp->controltrees[j], i)) != NULL;
+ i++) {
+ if (c->ctrl && c->ctrl->generic.handler != NULL)
+ c->ctrl->generic.handler(c->ctrl, dp,
+ dp->data, EVENT_REFRESH);
+ }
+ }
+ } else {
+ /*
+ * Send EVENT_REFRESH to a specific control.
+ */
+ if (ctrl->generic.handler != NULL)
+ ctrl->generic.handler(ctrl, dp, dp->data, EVENT_REFRESH);
+ }
+}
+
+void dlg_coloursel_start(union control *ctrl, void *dlg, int r, int g, int b)
+{
+ struct dlgparam *dp = (struct dlgparam *)dlg;
+ dp->coloursel_wanted = TRUE;
+ dp->coloursel_result.r = r;
+ dp->coloursel_result.g = g;
+ dp->coloursel_result.b = b;
+}
+
+int dlg_coloursel_results(union control *ctrl, void *dlg,
+ int *r, int *g, int *b)
+{
+ struct dlgparam *dp = (struct dlgparam *)dlg;
+ if (dp->coloursel_result.ok) {
+ *r = dp->coloursel_result.r;
+ *g = dp->coloursel_result.g;
+ *b = dp->coloursel_result.b;
+ return 1;
+ } else
+ return 0;
}
#include <commdlg.h>
#include <stdio.h>
#include <stdlib.h>
+#include <limits.h>
+#include <assert.h>
#include <ctype.h>
#include <time.h>
#include "winstuff.h"
#include "win_res.h"
#include "storage.h"
+#include "dialog.h"
#ifdef MSVC4
#define TVINSERTSTRUCT TV_INSERTSTRUCT
#define ICON_BIG 1
#endif
+/*
+ * These are the various bits of data required to handle the
+ * portable-dialog stuff in the config box. Having them at file
+ * scope in here isn't too bad a place to put them; if we were ever
+ * to need more than one config box per process we could always
+ * shift them to a per-config-box structure stored in GWL_USERDATA.
+ */
+static struct controlbox *ctrlbox;
+/*
+ * ctrls_base holds the OK and Cancel buttons: the controls which
+ * are present in all dialog panels. ctrls_panel holds the ones
+ * which change from panel to panel.
+ */
+static struct winctrls ctrls_base, ctrls_panel;
+static struct dlgparam dp;
+
static char **events = NULL;
static int nevents = 0, negsize = 0;
-static int readytogo;
-static int sesslist_has_focus;
static int requested_help;
-static struct prefslist cipherlist;
-
extern Config cfg; /* defined in window.c */
struct sesslist sesslist; /* exported to window.c */
recurse = 0;
}
-static void MyGetDlgItemInt(HWND hwnd, int id, int *result)
-{
- BOOL ok;
- int n;
- n = GetDlgItemInt(hwnd, id, &ok, FALSE);
- if (ok)
- *result = n;
-}
-
-static void MyGetDlgItemFlt(HWND hwnd, int id, int *result, int scale)
-{
- char text[80];
- BOOL ok;
- ok = GetDlgItemText(hwnd, id, text, sizeof(text) - 1);
- if (ok && text[0])
- *result = (int) (scale * atof(text));
-}
-
-static void MySetDlgItemFlt(HWND hwnd, int id, double value)
-{
- char text[80];
- sprintf(text, "%g", value);
- SetDlgItemText(hwnd, id, text);
-}
-
static int CALLBACK LogProc(HWND hwnd, UINT msg,
WPARAM wParam, LPARAM lParam)
{
return 0;
}
-static char savedsession[2048];
-
-enum { IDCX_ABOUT =
- IDC_ABOUT, IDCX_TVSTATIC, IDCX_TREEVIEW, controlstartvalue,
-
- sessionpanelstart,
- IDC_TITLE_SESSION,
- IDC_BOX_SESSION1,
- IDC_BOX_SESSION2,
- IDC_BOX_SESSION3,
- IDC_HOSTSTATIC,
- IDC_HOST,
- IDC_PORTSTATIC,
- IDC_PORT,
- IDC_PROTSTATIC,
- IDC_PROTRAW,
- IDC_PROTTELNET,
- IDC_PROTRLOGIN,
- IDC_PROTSSH,
- IDC_SESSSTATIC,
- IDC_SESSEDIT,
- IDC_SESSLIST,
- IDC_SESSLOAD,
- IDC_SESSSAVE,
- IDC_SESSDEL,
- IDC_CLOSEEXIT,
- IDC_COEALWAYS,
- IDC_COENEVER,
- IDC_COENORMAL,
- sessionpanelend,
-
- loggingpanelstart,
- IDC_TITLE_LOGGING,
- IDC_BOX_LOGGING1,
- IDC_LSTATSTATIC,
- IDC_LSTATOFF,
- IDC_LSTATASCII,
- IDC_LSTATRAW,
- IDC_LSTATPACKET,
- IDC_LGFSTATIC,
- IDC_LGFEDIT,
- IDC_LGFBUTTON,
- IDC_LGFEXPLAIN,
- IDC_LSTATXIST,
- IDC_LSTATXOVR,
- IDC_LSTATXAPN,
- IDC_LSTATXASK,
- loggingpanelend,
-
- keyboardpanelstart,
- IDC_TITLE_KEYBOARD,
- IDC_BOX_KEYBOARD1,
- IDC_BOX_KEYBOARD2,
- IDC_BOX_KEYBOARD3,
- IDC_DELSTATIC,
- IDC_DEL008,
- IDC_DEL127,
- IDC_HOMESTATIC,
- IDC_HOMETILDE,
- IDC_HOMERXVT,
- IDC_FUNCSTATIC,
- IDC_FUNCTILDE,
- IDC_FUNCLINUX,
- IDC_FUNCXTERM,
- IDC_FUNCVT400,
- IDC_FUNCVT100P,
- IDC_FUNCSCO,
- IDC_KPSTATIC,
- IDC_KPNORMAL,
- IDC_KPAPPLIC,
- IDC_KPNH,
- IDC_CURSTATIC,
- IDC_CURNORMAL,
- IDC_CURAPPLIC,
- IDC_COMPOSEKEY,
- IDC_CTRLALTKEYS,
- keyboardpanelend,
-
- terminalpanelstart,
- IDC_TITLE_TERMINAL,
- IDC_BOX_TERMINAL1,
- IDC_BOX_TERMINAL2,
- IDC_BOX_TERMINAL3,
- IDC_WRAPMODE,
- IDC_DECOM,
- IDC_LFHASCR,
- IDC_BCE,
- IDC_BLINKTEXT,
- IDC_ANSWERBACK,
- IDC_ANSWEREDIT,
- IDC_ECHOSTATIC,
- IDC_ECHOBACKEND,
- IDC_ECHOYES,
- IDC_ECHONO,
- IDC_EDITSTATIC,
- IDC_EDITBACKEND,
- IDC_EDITYES,
- IDC_EDITNO,
- IDC_PRINTERSTATIC,
- IDC_PRINTER,
- terminalpanelend,
-
- featurespanelstart,
- IDC_TITLE_FEATURES,
- IDC_BOX_FEATURES1,
- IDC_NOAPPLICK,
- IDC_NOAPPLICC,
- IDC_NOMOUSEREP,
- IDC_NORESIZE,
- IDC_NOALTSCREEN,
- IDC_NOWINTITLE,
- IDC_NODBACKSPACE,
- IDC_NOCHARSET,
- featurespanelend,
-
- bellpanelstart,
- IDC_TITLE_BELL,
- IDC_BOX_BELL1,
- IDC_BOX_BELL2,
- IDC_BELLSTATIC,
- IDC_BELL_DISABLED,
- IDC_BELL_DEFAULT,
- IDC_BELL_WAVEFILE,
- IDC_BELL_VISUAL,
- IDC_BELL_WAVESTATIC,
- IDC_BELL_WAVEEDIT,
- IDC_BELL_WAVEBROWSE,
- IDC_B_IND_STATIC,
- IDC_B_IND_DISABLED,
- IDC_B_IND_FLASH,
- IDC_B_IND_STEADY,
- IDC_BELLOVL,
- IDC_BELLOVLNSTATIC,
- IDC_BELLOVLN,
- IDC_BELLOVLTSTATIC,
- IDC_BELLOVLT,
- IDC_BELLOVLEXPLAIN,
- IDC_BELLOVLSSTATIC,
- IDC_BELLOVLS,
- bellpanelend,
-
- windowpanelstart,
- IDC_TITLE_WINDOW,
- IDC_BOX_WINDOW1,
- IDC_BOX_WINDOW2,
- IDC_BOX_WINDOW3,
- IDC_ROWSSTATIC,
- IDC_ROWSEDIT,
- IDC_COLSSTATIC,
- IDC_COLSEDIT,
- IDC_RESIZESTATIC,
- IDC_RESIZETERM,
- IDC_RESIZEFONT,
- IDC_RESIZENONE,
- IDC_RESIZEEITHER,
- IDC_SCROLLBAR,
- IDC_SCROLLBARFULLSCREEN,
- IDC_SAVESTATIC,
- IDC_SAVEEDIT,
- IDC_SCROLLKEY,
- IDC_SCROLLDISP,
- windowpanelend,
-
- behaviourpanelstart,
- IDC_TITLE_BEHAVIOUR,
- IDC_BOX_BEHAVIOUR1,
- IDC_CLOSEWARN,
- IDC_ALTF4,
- IDC_ALTSPACE,
- IDC_ALTONLY,
- IDC_ALWAYSONTOP,
- IDC_FULLSCREENONALTENTER,
- behaviourpanelend,
-
- appearancepanelstart,
- IDC_TITLE_APPEARANCE,
- IDC_BOX_APPEARANCE1,
- IDC_BOX_APPEARANCE2,
- IDC_BOX_APPEARANCE3,
- IDC_BOX_APPEARANCE4,
- IDC_BOX_APPEARANCE5,
- IDC_CURSORSTATIC,
- IDC_CURBLOCK,
- IDC_CURUNDER,
- IDC_CURVERT,
- IDC_BLINKCUR,
- IDC_FONTSTATIC,
- IDC_CHOOSEFONT,
- IDC_WINTITLE,
- IDC_WINEDIT,
- IDC_WINNAME,
- IDC_HIDEMOUSE,
- IDC_SUNKENEDGE,
- IDC_WINBSTATIC,
- IDC_WINBEDIT,
- appearancepanelend,
-
- connectionpanelstart,
- IDC_TITLE_CONNECTION,
- IDC_BOX_CONNECTION1,
- IDC_BOX_CONNECTION2,
- IDC_BOX_CONNECTION3,
- IDC_TTSTATIC,
- IDC_TTEDIT,
- IDC_LOGSTATIC,
- IDC_LOGEDIT,
- IDC_PINGSTATIC,
- IDC_PINGEDIT,
- IDC_NODELAY,
- connectionpanelend,
-
- proxypanelstart,
- IDC_TITLE_PROXY,
- IDC_BOX_PROXY1,
- IDC_PROXYTYPESTATIC,
- IDC_PROXYTYPENONE,
- IDC_PROXYTYPEHTTP,
- IDC_PROXYTYPESOCKS,
- IDC_PROXYTYPETELNET,
- IDC_PROXYHOSTSTATIC,
- IDC_PROXYHOSTEDIT,
- IDC_PROXYPORTSTATIC,
- IDC_PROXYPORTEDIT,
- IDC_PROXYEXCLUDESTATIC,
- IDC_PROXYEXCLUDEEDIT,
- IDC_PROXYLOCALHOST,
- IDC_PROXYDNSSTATIC,
- IDC_PROXYDNSNO,
- IDC_PROXYDNSAUTO,
- IDC_PROXYDNSYES,
- IDC_PROXYUSERSTATIC,
- IDC_PROXYUSEREDIT,
- IDC_PROXYPASSSTATIC,
- IDC_PROXYPASSEDIT,
- IDC_BOX_PROXY2,
- IDC_PROXYTELNETCMDSTATIC,
- IDC_PROXYTELNETCMDEDIT,
- IDC_PROXYSOCKSVERSTATIC,
- IDC_PROXYSOCKSVER5,
- IDC_PROXYSOCKSVER4,
- proxypanelend,
-
- telnetpanelstart,
- IDC_TITLE_TELNET,
- IDC_BOX_TELNET1,
- IDC_BOX_TELNET2,
- IDC_TSSTATIC,
- IDC_TSEDIT,
- IDC_ENVSTATIC,
- IDC_VARSTATIC,
- IDC_VAREDIT,
- IDC_VALSTATIC,
- IDC_VALEDIT,
- IDC_ENVLIST,
- IDC_ENVADD,
- IDC_ENVREMOVE,
- IDC_EMSTATIC,
- IDC_EMBSD,
- IDC_EMRFC,
- IDC_ACTSTATIC,
- IDC_TPASSIVE,
- IDC_TACTIVE,
- IDC_TELNETKEY,
- IDC_TELNETRET,
- telnetpanelend,
-
- rloginpanelstart,
- IDC_TITLE_RLOGIN,
- IDC_BOX_RLOGIN1,
- IDC_BOX_RLOGIN2,
- IDC_R_TSSTATIC,
- IDC_R_TSEDIT,
- IDC_RLLUSERSTATIC,
- IDC_RLLUSEREDIT,
- rloginpanelend,
-
- sshpanelstart,
- IDC_TITLE_SSH,
- IDC_BOX_SSH1,
- IDC_BOX_SSH2,
- IDC_BOX_SSH3,
- IDC_NOPTY,
- IDC_BOX_SSHCIPHER,
- IDC_CIPHERSTATIC2,
- IDC_CIPHERLIST,
- IDC_CIPHERUP,
- IDC_CIPHERDN,
- IDC_SSH2DES,
- IDC_SSHPROTSTATIC,
- IDC_SSHPROT1ONLY,
- IDC_SSHPROT1,
- IDC_SSHPROT2,
- IDC_SSHPROT2ONLY,
- IDC_CMDSTATIC,
- IDC_CMDEDIT,
- IDC_COMPRESS,
- sshpanelend,
-
- sshauthpanelstart,
- IDC_TITLE_SSHAUTH,
- IDC_BOX_SSHAUTH1,
- IDC_BOX_SSHAUTH2,
- IDC_PKSTATIC,
- IDC_PKEDIT,
- IDC_PKBUTTON,
- IDC_AGENTFWD,
- IDC_CHANGEUSER,
- IDC_AUTHTIS,
- IDC_AUTHKI,
- sshauthpanelend,
-
- sshbugspanelstart,
- IDC_TITLE_SSHBUGS,
- IDC_BOX_SSHBUGS1,
- IDC_BUGS_IGNORE1,
- IDC_BUGD_IGNORE1,
- IDC_BUGS_PLAINPW1,
- IDC_BUGD_PLAINPW1,
- IDC_BUGS_RSA1,
- IDC_BUGD_RSA1,
- IDC_BUGS_HMAC2,
- IDC_BUGD_HMAC2,
- IDC_BUGS_DERIVEKEY2,
- IDC_BUGD_DERIVEKEY2,
- IDC_BUGS_RSAPAD2,
- IDC_BUGD_RSAPAD2,
- IDC_BUGS_DHGEX2,
- IDC_BUGD_DHGEX2,
- IDC_BUGS_PKSESSID2,
- IDC_BUGD_PKSESSID2,
- sshbugspanelend,
-
- selectionpanelstart,
- IDC_TITLE_SELECTION,
- IDC_BOX_SELECTION1,
- IDC_BOX_SELECTION2,
- IDC_BOX_SELECTION3,
- IDC_MBSTATIC,
- IDC_MBWINDOWS,
- IDC_MBXTERM,
- IDC_MOUSEOVERRIDE,
- IDC_SELTYPESTATIC,
- IDC_SELTYPELEX,
- IDC_SELTYPERECT,
- IDC_CCSTATIC,
- IDC_CCLIST,
- IDC_CCSET,
- IDC_CCSTATIC2,
- IDC_CCEDIT,
- IDC_RAWCNP,
- IDC_RTFPASTE,
- selectionpanelend,
-
- colourspanelstart,
- IDC_TITLE_COLOURS,
- IDC_BOX_COLOURS1,
- IDC_BOX_COLOURS2,
- IDC_BOLDCOLOUR,
- IDC_PALETTE,
- IDC_COLOURSTATIC,
- IDC_COLOURLIST,
- IDC_RSTATIC,
- IDC_GSTATIC,
- IDC_BSTATIC,
- IDC_RVALUE,
- IDC_GVALUE,
- IDC_BVALUE,
- IDC_CHANGE,
- colourspanelend,
-
- translationpanelstart,
- IDC_TITLE_TRANSLATION,
- IDC_BOX_TRANSLATION1,
- IDC_BOX_TRANSLATION2,
- IDC_BOX_TRANSLATION3,
- IDC_CODEPAGESTATIC,
- IDC_CODEPAGE,
- IDC_CAPSLOCKCYR,
- IDC_VTSTATIC,
- IDC_VTXWINDOWS,
- IDC_VTOEMANSI,
- IDC_VTOEMONLY,
- IDC_VTPOORMAN,
- IDC_VTUNICODE,
- translationpanelend,
-
- tunnelspanelstart,
- IDC_TITLE_TUNNELS,
- IDC_BOX_TUNNELS1,
- IDC_BOX_TUNNELS2,
- IDC_X11_FORWARD,
- IDC_X11_DISPSTATIC,
- IDC_X11_DISPLAY,
- IDC_X11AUTHSTATIC,
- IDC_X11MIT,
- IDC_X11XDM,
- IDC_LPORT_ALL,
- IDC_RPORT_ALL,
- IDC_PFWDSTATIC,
- IDC_PFWDSTATIC2,
- IDC_PFWDREMOVE,
- IDC_PFWDLIST,
- IDC_PFWDADD,
- IDC_SPORTSTATIC,
- IDC_SPORTEDIT,
- IDC_DPORTSTATIC,
- IDC_DPORTEDIT,
- IDC_PFWDLOCAL,
- IDC_PFWDREMOTE,
-
- tunnelspanelend,
-
- controlendvalue
-};
-
-static const char *const colours[] = {
- "Default Foreground", "Default Bold Foreground",
- "Default Background", "Default Bold Background",
- "Cursor Text", "Cursor Colour",
- "ANSI Black", "ANSI Black Bold",
- "ANSI Red", "ANSI Red Bold",
- "ANSI Green", "ANSI Green Bold",
- "ANSI Yellow", "ANSI Yellow Bold",
- "ANSI Blue", "ANSI Blue Bold",
- "ANSI Magenta", "ANSI Magenta Bold",
- "ANSI Cyan", "ANSI Cyan Bold",
- "ANSI White", "ANSI White Bold"
+enum {
+ IDCX_ABOUT = IDC_ABOUT,
+ IDCX_TVSTATIC,
+ IDCX_TREEVIEW,
+ IDCX_STDBASE,
+ IDCX_PANELBASE = IDCX_STDBASE + 32
};
-static void fmtfont(char *buf)
-{
- sprintf(buf, "Font: %s, ", cfg.font.name);
- if (cfg.font.isbold)
- strcat(buf, "bold, ");
- if (cfg.font.height == 0)
- strcat(buf, "default height");
- else
- sprintf(buf + strlen(buf), "%d-point",
- (cfg.font.height < 0 ? -cfg.font.height : cfg.font.height));
-}
-
-char *help_context_cmd(int id)
-{
- switch (id) {
- case IDC_HOSTSTATIC:
- case IDC_HOST:
- case IDC_PORTSTATIC:
- case IDC_PORT:
- case IDC_PROTSTATIC:
- case IDC_PROTRAW:
- case IDC_PROTTELNET:
- case IDC_PROTRLOGIN:
- case IDC_PROTSSH:
- return "JI(`',`session.hostname')";
- case IDC_SESSSTATIC:
- case IDC_SESSEDIT:
- case IDC_SESSLIST:
- case IDC_SESSLOAD:
- case IDC_SESSSAVE:
- case IDC_SESSDEL:
- return "JI(`',`session.saved')";
- case IDC_CLOSEEXIT:
- case IDC_COEALWAYS:
- case IDC_COENEVER:
- case IDC_COENORMAL:
- return "JI(`',`session.coe')";
- case IDC_LSTATSTATIC:
- case IDC_LSTATOFF:
- case IDC_LSTATASCII:
- case IDC_LSTATRAW:
- case IDC_LSTATPACKET:
- return "JI(`',`logging.main')";
- case IDC_LGFSTATIC:
- case IDC_LGFEDIT:
- case IDC_LGFBUTTON:
- case IDC_LGFEXPLAIN:
- return "JI(`',`logging.filename')";
- case IDC_LSTATXIST:
- case IDC_LSTATXOVR:
- case IDC_LSTATXAPN:
- case IDC_LSTATXASK:
- return "JI(`',`logging.exists')";
-
- case IDC_DELSTATIC:
- case IDC_DEL008:
- case IDC_DEL127:
- return "JI(`',`keyboard.backspace')";
- case IDC_HOMESTATIC:
- case IDC_HOMETILDE:
- case IDC_HOMERXVT:
- return "JI(`',`keyboard.homeend')";
- case IDC_FUNCSTATIC:
- case IDC_FUNCTILDE:
- case IDC_FUNCLINUX:
- case IDC_FUNCXTERM:
- case IDC_FUNCVT400:
- case IDC_FUNCVT100P:
- case IDC_FUNCSCO:
- return "JI(`',`keyboard.funkeys')";
- case IDC_KPSTATIC:
- case IDC_KPNORMAL:
- case IDC_KPAPPLIC:
- return "JI(`',`keyboard.appkeypad')";
- case IDC_CURSTATIC:
- case IDC_CURNORMAL:
- case IDC_CURAPPLIC:
- return "JI(`',`keyboard.appcursor')";
- case IDC_KPNH:
- return "JI(`',`keyboard.nethack')";
- case IDC_COMPOSEKEY:
- return "JI(`',`keyboard.compose')";
- case IDC_CTRLALTKEYS:
- return "JI(`',`keyboard.ctrlalt')";
-
- case IDC_NOAPPLICK:
- case IDC_NOAPPLICC:
- return "JI(`',`features.application')";
- case IDC_NOMOUSEREP:
- return "JI(`',`features.mouse')";
- case IDC_NORESIZE:
- return "JI(`',`features.resize')";
- case IDC_NOALTSCREEN:
- return "JI(`',`features.altscreen')";
- case IDC_NOWINTITLE:
- return "JI(`',`features.retitle')";
- case IDC_NODBACKSPACE:
- return "JI(`',`features.dbackspace')";
- case IDC_NOCHARSET:
- return "JI(`',`features.charset')";
-
- case IDC_WRAPMODE:
- return "JI(`',`terminal.autowrap')";
- case IDC_DECOM:
- return "JI(`',`terminal.decom')";
- case IDC_LFHASCR:
- return "JI(`',`terminal.lfhascr')";
- case IDC_BCE:
- return "JI(`',`terminal.bce')";
- case IDC_BLINKTEXT:
- return "JI(`',`terminal.blink')";
- case IDC_ANSWERBACK:
- case IDC_ANSWEREDIT:
- return "JI(`',`terminal.answerback')";
- case IDC_ECHOSTATIC:
- case IDC_ECHOBACKEND:
- case IDC_ECHOYES:
- case IDC_ECHONO:
- return "JI(`',`terminal.localecho')";
- case IDC_EDITSTATIC:
- case IDC_EDITBACKEND:
- case IDC_EDITYES:
- case IDC_EDITNO:
- return "JI(`',`terminal.localedit')";
- case IDC_PRINTERSTATIC:
- case IDC_PRINTER:
- return "JI(`',`terminal.printing')";
-
- case IDC_BELLSTATIC:
- case IDC_BELL_DISABLED:
- case IDC_BELL_DEFAULT:
- case IDC_BELL_WAVEFILE:
- case IDC_BELL_VISUAL:
- case IDC_BELL_WAVESTATIC:
- case IDC_BELL_WAVEEDIT:
- case IDC_BELL_WAVEBROWSE:
- return "JI(`',`bell.style')";
- case IDC_B_IND_STATIC:
- case IDC_B_IND_DISABLED:
- case IDC_B_IND_FLASH:
- case IDC_B_IND_STEADY:
- return "JI(`',`bell.taskbar')";
- case IDC_BELLOVL:
- case IDC_BELLOVLNSTATIC:
- case IDC_BELLOVLN:
- case IDC_BELLOVLTSTATIC:
- case IDC_BELLOVLT:
- case IDC_BELLOVLEXPLAIN:
- case IDC_BELLOVLSSTATIC:
- case IDC_BELLOVLS:
- return "JI(`',`bell.overload')";
-
- case IDC_ROWSSTATIC:
- case IDC_ROWSEDIT:
- case IDC_COLSSTATIC:
- case IDC_COLSEDIT:
- return "JI(`',`window.size')";
- case IDC_RESIZESTATIC:
- case IDC_RESIZETERM:
- case IDC_RESIZEFONT:
- case IDC_RESIZENONE:
- case IDC_RESIZEEITHER:
- return "JI(`',`window.resize')";
- case IDC_SCROLLBAR:
- case IDC_SCROLLBARFULLSCREEN:
- case IDC_SAVESTATIC:
- case IDC_SAVEEDIT:
- case IDC_SCROLLKEY:
- case IDC_SCROLLDISP:
- return "JI(`',`window.scrollback')";
-
- case IDC_CLOSEWARN:
- return "JI(`',`behaviour.closewarn')";
- case IDC_ALTF4:
- return "JI(`',`behaviour.altf4')";
- case IDC_ALTSPACE:
- return "JI(`',`behaviour.altspace')";
- case IDC_ALTONLY:
- return "JI(`',`behaviour.altonly')";
- case IDC_ALWAYSONTOP:
- return "JI(`',`behaviour.alwaysontop')";
- case IDC_FULLSCREENONALTENTER:
- return "JI(`',`behaviour.altenter')";
-
- case IDC_CURSORSTATIC:
- case IDC_CURBLOCK:
- case IDC_CURUNDER:
- case IDC_CURVERT:
- case IDC_BLINKCUR:
- return "JI(`',`appearance.cursor')";
- case IDC_FONTSTATIC:
- case IDC_CHOOSEFONT:
- return "JI(`',`appearance.font')";
- case IDC_WINTITLE:
- case IDC_WINEDIT:
- case IDC_WINNAME:
- return "JI(`',`appearance.title')";
- case IDC_HIDEMOUSE:
- return "JI(`',`appearance.hidemouse')";
- case IDC_SUNKENEDGE:
- case IDC_WINBSTATIC:
- case IDC_WINBEDIT:
- return "JI(`',`appearance.border')";
-
- case IDC_TTSTATIC:
- case IDC_TTEDIT:
- return "JI(`',`connection.termtype')";
- case IDC_LOGSTATIC:
- case IDC_LOGEDIT:
- return "JI(`',`connection.username')";
- case IDC_PINGSTATIC:
- case IDC_PINGEDIT:
- return "JI(`',`connection.keepalive')";
- case IDC_NODELAY:
- return "JI(`',`connection.nodelay')";
-
- case IDC_PROXYTYPESTATIC:
- case IDC_PROXYTYPENONE:
- case IDC_PROXYTYPEHTTP:
- case IDC_PROXYTYPESOCKS:
- case IDC_PROXYTYPETELNET:
- return "JI(`',`proxy.type')";
- case IDC_PROXYHOSTSTATIC:
- case IDC_PROXYHOSTEDIT:
- case IDC_PROXYPORTSTATIC:
- case IDC_PROXYPORTEDIT:
- return "JI(`',`proxy.main')";
- case IDC_PROXYEXCLUDESTATIC:
- case IDC_PROXYEXCLUDEEDIT:
- case IDC_PROXYLOCALHOST:
- return "JI(`',`proxy.exclude')";
- case IDC_PROXYDNSSTATIC:
- case IDC_PROXYDNSNO:
- case IDC_PROXYDNSAUTO:
- case IDC_PROXYDNSYES:
- return "JI(`',`proxy.dns')";
- case IDC_PROXYUSERSTATIC:
- case IDC_PROXYUSEREDIT:
- case IDC_PROXYPASSSTATIC:
- case IDC_PROXYPASSEDIT:
- return "JI(`',`proxy.auth')";
- case IDC_PROXYTELNETCMDSTATIC:
- case IDC_PROXYTELNETCMDEDIT:
- return "JI(`',`proxy.command')";
- case IDC_PROXYSOCKSVERSTATIC:
- case IDC_PROXYSOCKSVER5:
- case IDC_PROXYSOCKSVER4:
- return "JI(`',`proxy.socksver')";
-
- case IDC_TSSTATIC:
- case IDC_TSEDIT:
- return "JI(`',`telnet.termspeed')";
- case IDC_ENVSTATIC:
- case IDC_VARSTATIC:
- case IDC_VAREDIT:
- case IDC_VALSTATIC:
- case IDC_VALEDIT:
- case IDC_ENVLIST:
- case IDC_ENVADD:
- case IDC_ENVREMOVE:
- return "JI(`',`telnet.environ')";
- case IDC_EMSTATIC:
- case IDC_EMBSD:
- case IDC_EMRFC:
- return "JI(`',`telnet.oldenviron')";
- case IDC_ACTSTATIC:
- case IDC_TPASSIVE:
- case IDC_TACTIVE:
- return "JI(`',`telnet.passive')";
- case IDC_TELNETKEY:
- return "JI(`',`telnet.specialkeys')";
- case IDC_TELNETRET:
- return "JI(`',`telnet.newline')";
-
- case IDC_R_TSSTATIC:
- case IDC_R_TSEDIT:
- return "JI(`',`rlogin.termspeed')";
- case IDC_RLLUSERSTATIC:
- case IDC_RLLUSEREDIT:
- return "JI(`',`rlogin.localuser')";
-
- case IDC_NOPTY:
- return "JI(`',`ssh.nopty')";
- case IDC_CIPHERSTATIC2:
- case IDC_CIPHERLIST:
- case IDC_CIPHERUP:
- case IDC_CIPHERDN:
- case IDC_SSH2DES:
- return "JI(`',`ssh.ciphers')";
- case IDC_SSHPROTSTATIC:
- case IDC_SSHPROT1ONLY:
- case IDC_SSHPROT1:
- case IDC_SSHPROT2:
- case IDC_SSHPROT2ONLY:
- return "JI(`',`ssh.protocol')";
- case IDC_CMDSTATIC:
- case IDC_CMDEDIT:
- return "JI(`',`ssh.command')";
- case IDC_COMPRESS:
- return "JI(`',`ssh.compress')";
-
- case IDC_PKSTATIC:
- case IDC_PKEDIT:
- case IDC_PKBUTTON:
- return "JI(`',`ssh.auth.privkey')";
- case IDC_AGENTFWD:
- return "JI(`',`ssh.auth.agentfwd')";
- case IDC_CHANGEUSER:
- return "JI(`',`ssh.auth.changeuser')";
- case IDC_AUTHTIS:
- return "JI(`',`ssh.auth.tis')";
- case IDC_AUTHKI:
- return "JI(`',`ssh.auth.ki')";
-
- case IDC_MBSTATIC:
- case IDC_MBWINDOWS:
- case IDC_MBXTERM:
- return "JI(`',`selection.buttons')";
- case IDC_MOUSEOVERRIDE:
- return "JI(`',`selection.shiftdrag')";
- case IDC_SELTYPESTATIC:
- case IDC_SELTYPELEX:
- case IDC_SELTYPERECT:
- return "JI(`',`selection.rect')";
- case IDC_CCSTATIC:
- case IDC_CCLIST:
- case IDC_CCSET:
- case IDC_CCSTATIC2:
- case IDC_CCEDIT:
- return "JI(`',`selection.charclasses')";
- case IDC_RAWCNP:
- return "JI(`',`selection.linedraw')";
- case IDC_RTFPASTE:
- return "JI(`',`selection.rtf')";
-
- case IDC_BOLDCOLOUR:
- return "JI(`',`colours.bold')";
- case IDC_PALETTE:
- return "JI(`',`colours.logpal')";
- case IDC_COLOURSTATIC:
- case IDC_COLOURLIST:
- case IDC_RSTATIC:
- case IDC_GSTATIC:
- case IDC_BSTATIC:
- case IDC_RVALUE:
- case IDC_GVALUE:
- case IDC_BVALUE:
- case IDC_CHANGE:
- return "JI(`',`colours.config')";
-
- case IDC_CODEPAGESTATIC:
- case IDC_CODEPAGE:
- return "JI(`',`translation.codepage')";
- case IDC_CAPSLOCKCYR:
- return "JI(`',`translation.cyrillic')";
- case IDC_VTSTATIC:
- case IDC_VTXWINDOWS:
- case IDC_VTOEMANSI:
- case IDC_VTOEMONLY:
- case IDC_VTPOORMAN:
- case IDC_VTUNICODE:
- return "JI(`',`translation.linedraw')";
-
- case IDC_X11_FORWARD:
- case IDC_X11_DISPSTATIC:
- case IDC_X11_DISPLAY:
- return "JI(`',`ssh.tunnels.x11')";
- case IDC_X11AUTHSTATIC:
- case IDC_X11MIT:
- case IDC_X11XDM:
- return "JI(`',`ssh.tunnels.x11auth')";
- case IDC_PFWDSTATIC:
- case IDC_PFWDSTATIC2:
- case IDC_PFWDREMOVE:
- case IDC_PFWDLIST:
- case IDC_PFWDADD:
- case IDC_SPORTSTATIC:
- case IDC_SPORTEDIT:
- case IDC_DPORTSTATIC:
- case IDC_DPORTEDIT:
- case IDC_PFWDLOCAL:
- case IDC_PFWDREMOTE:
- return "JI(`',`ssh.tunnels.portfwd')";
- case IDC_LPORT_ALL:
- case IDC_RPORT_ALL:
- return "JI(`',`ssh.tunnels.portfwd.localhost')";
-
- case IDC_BUGS_IGNORE1:
- case IDC_BUGD_IGNORE1:
- return "JI(`',`ssh.bugs.ignore1')";
- case IDC_BUGS_PLAINPW1:
- case IDC_BUGD_PLAINPW1:
- return "JI(`',`ssh.bugs.plainpw1')";
- case IDC_BUGS_RSA1:
- case IDC_BUGD_RSA1:
- return "JI(`',`ssh.bugs.rsa1')";
- case IDC_BUGS_HMAC2:
- case IDC_BUGD_HMAC2:
- return "JI(`',`ssh.bugs.hmac2')";
- case IDC_BUGS_DERIVEKEY2:
- case IDC_BUGD_DERIVEKEY2:
- return "JI(`',`ssh.bugs.derivekey2')";
- case IDC_BUGS_RSAPAD2:
- case IDC_BUGD_RSAPAD2:
- return "JI(`',`ssh.bugs.rsapad2')";
- case IDC_BUGS_DHGEX2:
- case IDC_BUGD_DHGEX2:
- return "JI(`',`ssh.bugs.dhgex2')";
- case IDC_BUGS_PKSESSID2:
- case IDC_BUGD_PKSESSID2:
- return "JI(`',`ssh.bugs.pksessid2')";
-
- default:
- return NULL;
- }
-}
-
-/* 2nd arg: NZ => don't redraw session list (use when loading
- * a new session) */
-static void init_dlg_ctrls(HWND hwnd, int keepsess)
-{
- int i;
- char fontstatic[256];
-
- SetDlgItemText(hwnd, IDC_HOST, cfg.host);
- SetDlgItemText(hwnd, IDC_SESSEDIT, savedsession);
- if (!keepsess) {
- int i, n;
- n = SendDlgItemMessage(hwnd, IDC_SESSLIST, LB_GETCOUNT, 0, 0);
- for (i = n; i-- > 0;)
- SendDlgItemMessage(hwnd, IDC_SESSLIST, LB_DELETESTRING, i, 0);
- for (i = 0; i < sesslist.nsessions; i++)
- SendDlgItemMessage(hwnd, IDC_SESSLIST, LB_ADDSTRING,
- 0, (LPARAM) (sesslist.sessions[i]));
- }
- SetDlgItemInt(hwnd, IDC_PORT, cfg.port, FALSE);
- CheckRadioButton(hwnd, IDC_PROTRAW, IDC_PROTSSH,
- cfg.protocol == PROT_SSH ? IDC_PROTSSH :
- cfg.protocol == PROT_TELNET ? IDC_PROTTELNET :
- cfg.protocol ==
- PROT_RLOGIN ? IDC_PROTRLOGIN : IDC_PROTRAW);
- SetDlgItemInt(hwnd, IDC_PINGEDIT, cfg.ping_interval, FALSE);
- CheckDlgButton(hwnd, IDC_NODELAY, cfg.tcp_nodelay);
-
- CheckRadioButton(hwnd, IDC_DEL008, IDC_DEL127,
- cfg.bksp_is_delete ? IDC_DEL127 : IDC_DEL008);
- CheckRadioButton(hwnd, IDC_HOMETILDE, IDC_HOMERXVT,
- cfg.rxvt_homeend ? IDC_HOMERXVT : IDC_HOMETILDE);
- CheckRadioButton(hwnd, IDC_FUNCTILDE, IDC_FUNCSCO,
- cfg.funky_type == 0 ? IDC_FUNCTILDE :
- cfg.funky_type == 1 ? IDC_FUNCLINUX :
- cfg.funky_type == 2 ? IDC_FUNCXTERM :
- cfg.funky_type == 3 ? IDC_FUNCVT400 :
- cfg.funky_type == 4 ? IDC_FUNCVT100P :
- cfg.funky_type == 5 ? IDC_FUNCSCO : IDC_FUNCTILDE);
- CheckDlgButton(hwnd, IDC_NOAPPLICC, cfg.no_applic_c);
- CheckDlgButton(hwnd, IDC_NOAPPLICK, cfg.no_applic_k);
- CheckDlgButton(hwnd, IDC_NOMOUSEREP, cfg.no_mouse_rep);
- CheckDlgButton(hwnd, IDC_NORESIZE, cfg.no_remote_resize);
- CheckDlgButton(hwnd, IDC_NOALTSCREEN, cfg.no_alt_screen);
- CheckDlgButton(hwnd, IDC_NOWINTITLE, cfg.no_remote_wintitle);
- CheckDlgButton(hwnd, IDC_NODBACKSPACE, cfg.no_dbackspace);
- CheckDlgButton(hwnd, IDC_NOCHARSET, cfg.no_remote_charset);
- CheckRadioButton(hwnd, IDC_CURNORMAL, IDC_CURAPPLIC,
- cfg.app_cursor ? IDC_CURAPPLIC : IDC_CURNORMAL);
- CheckRadioButton(hwnd, IDC_KPNORMAL, IDC_KPNH,
- cfg.nethack_keypad ? IDC_KPNH :
- cfg.app_keypad ? IDC_KPAPPLIC : IDC_KPNORMAL);
- CheckDlgButton(hwnd, IDC_ALTF4, cfg.alt_f4);
- CheckDlgButton(hwnd, IDC_ALTSPACE, cfg.alt_space);
- CheckDlgButton(hwnd, IDC_ALTONLY, cfg.alt_only);
- CheckDlgButton(hwnd, IDC_COMPOSEKEY, cfg.compose_key);
- CheckDlgButton(hwnd, IDC_CTRLALTKEYS, cfg.ctrlaltkeys);
- CheckDlgButton(hwnd, IDC_TELNETKEY, cfg.telnet_keyboard);
- CheckDlgButton(hwnd, IDC_TELNETRET, cfg.telnet_newline);
- CheckRadioButton(hwnd, IDC_ECHOBACKEND, IDC_ECHONO,
- cfg.localecho == AUTO ? IDC_ECHOBACKEND :
- cfg.localecho == FORCE_ON ? IDC_ECHOYES : IDC_ECHONO);
- CheckRadioButton(hwnd, IDC_EDITBACKEND, IDC_EDITNO,
- cfg.localedit == AUTO ? IDC_EDITBACKEND :
- cfg.localedit == FORCE_ON ? IDC_EDITYES : IDC_EDITNO);
- SetDlgItemText(hwnd, IDC_ANSWEREDIT, cfg.answerback);
- CheckDlgButton(hwnd, IDC_ALWAYSONTOP, cfg.alwaysontop);
- CheckDlgButton(hwnd, IDC_FULLSCREENONALTENTER, cfg.fullscreenonaltenter);
- CheckDlgButton(hwnd, IDC_SCROLLKEY, cfg.scroll_on_key);
- CheckDlgButton(hwnd, IDC_SCROLLDISP, cfg.scroll_on_disp);
-
- CheckDlgButton(hwnd, IDC_WRAPMODE, cfg.wrap_mode);
- CheckDlgButton(hwnd, IDC_DECOM, cfg.dec_om);
- CheckDlgButton(hwnd, IDC_LFHASCR, cfg.lfhascr);
- SetDlgItemInt(hwnd, IDC_ROWSEDIT, cfg.height, FALSE);
- SetDlgItemInt(hwnd, IDC_COLSEDIT, cfg.width, FALSE);
- SetDlgItemInt(hwnd, IDC_SAVEEDIT, cfg.savelines, FALSE);
- fmtfont(fontstatic);
- SetDlgItemText(hwnd, IDC_FONTSTATIC, fontstatic);
- CheckRadioButton(hwnd, IDC_BELL_DISABLED, IDC_BELL_VISUAL,
- cfg.beep == BELL_DISABLED ? IDC_BELL_DISABLED :
- cfg.beep == BELL_DEFAULT ? IDC_BELL_DEFAULT :
- cfg.beep == BELL_WAVEFILE ? IDC_BELL_WAVEFILE :
- cfg.beep ==
- BELL_VISUAL ? IDC_BELL_VISUAL : IDC_BELL_DEFAULT);
- CheckRadioButton(hwnd, IDC_B_IND_DISABLED, IDC_B_IND_STEADY,
- cfg.beep_ind ==
- B_IND_DISABLED ? IDC_B_IND_DISABLED : cfg.beep_ind ==
- B_IND_FLASH ? IDC_B_IND_FLASH : cfg.beep_ind ==
- B_IND_STEADY ? IDC_B_IND_STEADY : IDC_B_IND_DISABLED);
- SetDlgItemText(hwnd, IDC_BELL_WAVEEDIT, cfg.bell_wavefile.path);
- CheckDlgButton(hwnd, IDC_BELLOVL, cfg.bellovl);
- SetDlgItemInt(hwnd, IDC_BELLOVLN, cfg.bellovl_n, FALSE);
- MySetDlgItemFlt(hwnd, IDC_BELLOVLT, cfg.bellovl_t / 1000.0);
- MySetDlgItemFlt(hwnd, IDC_BELLOVLS, cfg.bellovl_s / 1000.0);
-
- CheckDlgButton(hwnd, IDC_BCE, cfg.bce);
- CheckDlgButton(hwnd, IDC_BLINKTEXT, cfg.blinktext);
-
- SetDlgItemText(hwnd, IDC_WINEDIT, cfg.wintitle);
- CheckDlgButton(hwnd, IDC_WINNAME, !cfg.win_name_always);
- CheckDlgButton(hwnd, IDC_HIDEMOUSE, cfg.hide_mouseptr);
- CheckDlgButton(hwnd, IDC_SUNKENEDGE, cfg.sunken_edge);
- SetDlgItemInt(hwnd, IDC_WINBEDIT, cfg.window_border, FALSE);
- CheckRadioButton(hwnd, IDC_CURBLOCK, IDC_CURVERT,
- cfg.cursor_type == 0 ? IDC_CURBLOCK :
- cfg.cursor_type == 1 ? IDC_CURUNDER : IDC_CURVERT);
- CheckDlgButton(hwnd, IDC_BLINKCUR, cfg.blink_cur);
- CheckDlgButton(hwnd, IDC_SCROLLBAR, cfg.scrollbar);
- CheckDlgButton(hwnd, IDC_SCROLLBARFULLSCREEN, cfg.scrollbar_in_fullscreen);
- CheckRadioButton(hwnd, IDC_RESIZETERM, IDC_RESIZEEITHER,
- cfg.resize_action == RESIZE_TERM ? IDC_RESIZETERM :
- cfg.resize_action == RESIZE_FONT ? IDC_RESIZEFONT :
- cfg.resize_action == RESIZE_EITHER ? IDC_RESIZEEITHER :
- IDC_RESIZENONE);
- CheckRadioButton(hwnd, IDC_COEALWAYS, IDC_COENORMAL,
- cfg.close_on_exit == AUTO ? IDC_COENORMAL :
- cfg.close_on_exit ==
- FORCE_OFF ? IDC_COENEVER : IDC_COEALWAYS);
- CheckDlgButton(hwnd, IDC_CLOSEWARN, cfg.warn_on_close);
-
- SetDlgItemText(hwnd, IDC_TTEDIT, cfg.termtype);
- SetDlgItemText(hwnd, IDC_TSEDIT, cfg.termspeed);
- SetDlgItemText(hwnd, IDC_R_TSEDIT, cfg.termspeed);
- SetDlgItemText(hwnd, IDC_RLLUSEREDIT, cfg.localusername);
- SetDlgItemText(hwnd, IDC_LOGEDIT, cfg.username);
- SetDlgItemText(hwnd, IDC_LGFEDIT, cfg.logfilename.path);
- CheckRadioButton(hwnd, IDC_LSTATOFF, IDC_LSTATPACKET,
- cfg.logtype == LGTYP_NONE ? IDC_LSTATOFF :
- cfg.logtype == LGTYP_ASCII ? IDC_LSTATASCII :
- cfg.logtype == LGTYP_DEBUG ? IDC_LSTATRAW :
- IDC_LSTATPACKET);
- CheckRadioButton(hwnd, IDC_LSTATXOVR, IDC_LSTATXASK,
- cfg.logxfovr == LGXF_OVR ? IDC_LSTATXOVR :
- cfg.logxfovr == LGXF_ASK ? IDC_LSTATXASK :
- IDC_LSTATXAPN);
- {
- char *p = cfg.environmt;
- SendDlgItemMessage(hwnd, IDC_ENVLIST, LB_RESETCONTENT, 0, 0);
- while (*p) {
- SendDlgItemMessage(hwnd, IDC_ENVLIST, LB_ADDSTRING, 0,
- (LPARAM) p);
- p += strlen(p) + 1;
- }
- p = cfg.portfwd;
- while (*p) {
- SendDlgItemMessage(hwnd, IDC_PFWDLIST, LB_ADDSTRING, 0,
- (LPARAM) p);
- p += strlen(p) + 1;
- }
- }
- CheckRadioButton(hwnd, IDC_EMBSD, IDC_EMRFC,
- cfg.rfc_environ ? IDC_EMRFC : IDC_EMBSD);
- CheckRadioButton(hwnd, IDC_TPASSIVE, IDC_TACTIVE,
- cfg.passive_telnet ? IDC_TPASSIVE : IDC_TACTIVE);
-
- SetDlgItemText(hwnd, IDC_TTEDIT, cfg.termtype);
- SetDlgItemText(hwnd, IDC_LOGEDIT, cfg.username);
- CheckDlgButton(hwnd, IDC_NOPTY, cfg.nopty);
- CheckDlgButton(hwnd, IDC_COMPRESS, cfg.compression);
- CheckDlgButton(hwnd, IDC_SSH2DES, cfg.ssh2_des_cbc);
- CheckDlgButton(hwnd, IDC_AGENTFWD, cfg.agentfwd);
- CheckDlgButton(hwnd, IDC_CHANGEUSER, cfg.change_username);
- CheckRadioButton(hwnd, IDC_SSHPROT1ONLY, IDC_SSHPROT2ONLY,
- cfg.sshprot == 1 ? IDC_SSHPROT1 :
- cfg.sshprot == 2 ? IDC_SSHPROT2 :
- cfg.sshprot == 3 ? IDC_SSHPROT2ONLY : IDC_SSHPROT1ONLY);
- CheckDlgButton(hwnd, IDC_AUTHTIS, cfg.try_tis_auth);
- CheckDlgButton(hwnd, IDC_AUTHKI, cfg.try_ki_auth);
- SetDlgItemText(hwnd, IDC_PKEDIT, cfg.keyfile.path);
- SetDlgItemText(hwnd, IDC_CMDEDIT, cfg.remote_cmd);
-
- {
- int i;
- static const struct { char *s; int c; } ciphers[] = {
- { "3DES", CIPHER_3DES },
- { "Blowfish", CIPHER_BLOWFISH },
- { "DES", CIPHER_DES },
- { "AES (SSH 2 only)", CIPHER_AES },
- { "-- warn below here --", CIPHER_WARN }
- };
-
- /* Set up the "selected ciphers" box. */
- /* (cipherlist assumed to contain all ciphers) */
- SendDlgItemMessage(hwnd, IDC_CIPHERLIST, LB_RESETCONTENT, 0, 0);
- for (i = 0; i < CIPHER_MAX; i++) {
- int c = cfg.ssh_cipherlist[i];
- int j, pos;
- char *cstr = NULL;
- for (j = 0; j < (sizeof ciphers) / (sizeof ciphers[0]); j++) {
- if (ciphers[j].c == c) {
- cstr = ciphers[j].s;
- break;
- }
- }
- pos = SendDlgItemMessage(hwnd, IDC_CIPHERLIST, LB_ADDSTRING,
- 0, (LPARAM) cstr);
- SendDlgItemMessage(hwnd, IDC_CIPHERLIST, LB_SETITEMDATA,
- pos, (LPARAM) c);
- }
-
- }
-
- CheckRadioButton(hwnd, IDC_MBWINDOWS, IDC_MBXTERM,
- cfg.mouse_is_xterm ? IDC_MBXTERM : IDC_MBWINDOWS);
- CheckRadioButton(hwnd, IDC_SELTYPELEX, IDC_SELTYPERECT,
- cfg.rect_select == 0 ? IDC_SELTYPELEX : IDC_SELTYPERECT);
- CheckDlgButton(hwnd, IDC_MOUSEOVERRIDE, cfg.mouse_override);
- CheckDlgButton(hwnd, IDC_RAWCNP, cfg.rawcnp);
- CheckDlgButton(hwnd, IDC_RTFPASTE, cfg.rtf_paste);
- {
- static int tabs[4] = { 25, 61, 96, 128 };
- SendDlgItemMessage(hwnd, IDC_CCLIST, LB_SETTABSTOPS, 4,
- (LPARAM) tabs);
- }
- for (i = 0; i < 128; i++) {
- char str[100];
- sprintf(str, "%d\t(0x%02X)\t%c\t%d", i, i,
- (i >= 0x21 && i != 0x7F) ? i : ' ', cfg.wordness[i]);
- SendDlgItemMessage(hwnd, IDC_CCLIST, LB_ADDSTRING, 0,
- (LPARAM) str);
- }
-
- CheckDlgButton(hwnd, IDC_BOLDCOLOUR, cfg.bold_colour);
- CheckDlgButton(hwnd, IDC_PALETTE, cfg.try_palette);
- {
- int i, n;
- n = SendDlgItemMessage(hwnd, IDC_COLOURLIST, LB_GETCOUNT, 0, 0);
- for (i = n; i-- > 0;)
- SendDlgItemMessage(hwnd, IDC_COLOURLIST,
- LB_DELETESTRING, i, 0);
- for (i = 0; i < 22; i++)
- SendDlgItemMessage(hwnd, IDC_COLOURLIST, LB_ADDSTRING, 0,
- (LPARAM) colours[i]);
- }
- SendDlgItemMessage(hwnd, IDC_COLOURLIST, LB_SETCURSEL, 0, 0);
- SetDlgItemInt(hwnd, IDC_RVALUE, cfg.colours[0][0], FALSE);
- SetDlgItemInt(hwnd, IDC_GVALUE, cfg.colours[0][1], FALSE);
- SetDlgItemInt(hwnd, IDC_BVALUE, cfg.colours[0][2], FALSE);
-
- {
- int i;
- char *cp;
- strcpy(cfg.line_codepage, cp_name(decode_codepage(cfg.line_codepage)));
- SendDlgItemMessage(hwnd, IDC_CODEPAGE, CB_RESETCONTENT, 0, 0);
- CheckDlgButton (hwnd, IDC_CAPSLOCKCYR, cfg.xlat_capslockcyr);
- for (i = 0; (cp = cp_enumerate(i)) != NULL; i++) {
- SendDlgItemMessage(hwnd, IDC_CODEPAGE, CB_ADDSTRING,
- 0, (LPARAM) cp);
- }
- SetDlgItemText(hwnd, IDC_CODEPAGE, cfg.line_codepage);
- }
-
- {
- int i, nprinters;
- printer_enum *pe;
- pe = printer_start_enum(&nprinters);
- SendDlgItemMessage(hwnd, IDC_PRINTER, CB_RESETCONTENT, 0, 0);
- SendDlgItemMessage(hwnd, IDC_PRINTER, CB_ADDSTRING,
- 0, (LPARAM) PRINTER_DISABLED_STRING);
- for (i = 0; i < nprinters; i++) {
- char *printer_name = printer_get_name(pe, i);
- SendDlgItemMessage(hwnd, IDC_PRINTER, CB_ADDSTRING,
- 0, (LPARAM) printer_name);
- }
- printer_finish_enum(pe);
- SetDlgItemText(hwnd, IDC_PRINTER,
- *cfg.printer ? cfg.printer : PRINTER_DISABLED_STRING);
- }
-
- CheckRadioButton(hwnd, IDC_VTXWINDOWS, IDC_VTUNICODE,
- cfg.vtmode == VT_XWINDOWS ? IDC_VTXWINDOWS :
- cfg.vtmode == VT_OEMANSI ? IDC_VTOEMANSI :
- cfg.vtmode == VT_OEMONLY ? IDC_VTOEMONLY :
- cfg.vtmode == VT_UNICODE ? IDC_VTUNICODE :
- IDC_VTPOORMAN);
-
- CheckDlgButton(hwnd, IDC_X11_FORWARD, cfg.x11_forward);
- SetDlgItemText(hwnd, IDC_X11_DISPLAY, cfg.x11_display);
- CheckRadioButton(hwnd, IDC_X11MIT, IDC_X11XDM,
- cfg.x11_auth == X11_MIT ? IDC_X11MIT : IDC_X11XDM);
-
- CheckDlgButton(hwnd, IDC_LPORT_ALL, cfg.lport_acceptall);
- CheckDlgButton(hwnd, IDC_RPORT_ALL, cfg.rport_acceptall);
- CheckRadioButton(hwnd, IDC_PFWDLOCAL, IDC_PFWDREMOTE, IDC_PFWDLOCAL);
-
- /* proxy config */
- CheckRadioButton(hwnd, IDC_PROXYTYPENONE, IDC_PROXYTYPETELNET,
- cfg.proxy_type == PROXY_HTTP ? IDC_PROXYTYPEHTTP :
- cfg.proxy_type == PROXY_SOCKS ? IDC_PROXYTYPESOCKS :
- cfg.proxy_type == PROXY_TELNET ? IDC_PROXYTYPETELNET : IDC_PROXYTYPENONE);
- SetDlgItemText(hwnd, IDC_PROXYHOSTEDIT, cfg.proxy_host);
- SetDlgItemInt(hwnd, IDC_PROXYPORTEDIT, cfg.proxy_port, FALSE);
- SetDlgItemText(hwnd, IDC_PROXYEXCLUDEEDIT, cfg.proxy_exclude_list);
- CheckDlgButton(hwnd, IDC_PROXYLOCALHOST, cfg.even_proxy_localhost);
- CheckRadioButton(hwnd, IDC_PROXYDNSNO, IDC_PROXYDNSYES,
- cfg.proxy_dns == FORCE_OFF ? IDC_PROXYDNSNO :
- cfg.proxy_dns == FORCE_ON ? IDC_PROXYDNSYES :
- IDC_PROXYDNSAUTO);
- SetDlgItemText(hwnd, IDC_PROXYTELNETCMDEDIT, cfg.proxy_telnet_command);
- SetDlgItemText(hwnd, IDC_PROXYUSEREDIT, cfg.proxy_username);
- SetDlgItemText(hwnd, IDC_PROXYPASSEDIT, cfg.proxy_password);
- CheckRadioButton(hwnd, IDC_PROXYSOCKSVER5, IDC_PROXYSOCKSVER4,
- cfg.proxy_socks_version == 4 ? IDC_PROXYSOCKSVER4 : IDC_PROXYSOCKSVER5);
-
- /* SSH bugs config */
- SendDlgItemMessage(hwnd, IDC_BUGD_IGNORE1, CB_RESETCONTENT, 0, 0);
- SendDlgItemMessage(hwnd, IDC_BUGD_IGNORE1, CB_ADDSTRING, 0, (LPARAM)"Auto");
- SendDlgItemMessage(hwnd, IDC_BUGD_IGNORE1, CB_ADDSTRING, 0, (LPARAM)"Off");
- SendDlgItemMessage(hwnd, IDC_BUGD_IGNORE1, CB_ADDSTRING, 0, (LPARAM)"On");
- SendDlgItemMessage(hwnd, IDC_BUGD_IGNORE1, CB_SETCURSEL,
- cfg.sshbug_ignore1 == FORCE_ON ? 2 :
- cfg.sshbug_ignore1 == FORCE_OFF ? 1 : 0, 0);
- SendDlgItemMessage(hwnd, IDC_BUGD_PLAINPW1, CB_RESETCONTENT, 0, 0);
- SendDlgItemMessage(hwnd, IDC_BUGD_PLAINPW1, CB_ADDSTRING, 0, (LPARAM)"Auto");
- SendDlgItemMessage(hwnd, IDC_BUGD_PLAINPW1, CB_ADDSTRING, 0, (LPARAM)"Off");
- SendDlgItemMessage(hwnd, IDC_BUGD_PLAINPW1, CB_ADDSTRING, 0, (LPARAM)"On");
- SendDlgItemMessage(hwnd, IDC_BUGD_PLAINPW1, CB_SETCURSEL,
- cfg.sshbug_plainpw1 == FORCE_ON ? 2 :
- cfg.sshbug_plainpw1 == FORCE_OFF ? 1 : 0, 0);
- SendDlgItemMessage(hwnd, IDC_BUGD_RSA1, CB_RESETCONTENT, 0, 0);
- SendDlgItemMessage(hwnd, IDC_BUGD_RSA1, CB_ADDSTRING, 0, (LPARAM)"Auto");
- SendDlgItemMessage(hwnd, IDC_BUGD_RSA1, CB_ADDSTRING, 0, (LPARAM)"Off");
- SendDlgItemMessage(hwnd, IDC_BUGD_RSA1, CB_ADDSTRING, 0, (LPARAM)"On");
- SendDlgItemMessage(hwnd, IDC_BUGD_RSA1, CB_SETCURSEL,
- cfg.sshbug_rsa1 == FORCE_ON ? 2 :
- cfg.sshbug_rsa1 == FORCE_OFF ? 1 : 0, 0);
- SendDlgItemMessage(hwnd, IDC_BUGD_HMAC2, CB_RESETCONTENT, 0, 0);
- SendDlgItemMessage(hwnd, IDC_BUGD_HMAC2, CB_ADDSTRING, 0, (LPARAM)"Auto");
- SendDlgItemMessage(hwnd, IDC_BUGD_HMAC2, CB_ADDSTRING, 0, (LPARAM)"Off");
- SendDlgItemMessage(hwnd, IDC_BUGD_HMAC2, CB_ADDSTRING, 0, (LPARAM)"On");
- SendDlgItemMessage(hwnd, IDC_BUGD_HMAC2, CB_SETCURSEL,
- cfg.sshbug_hmac2 == FORCE_ON ? 2 :
- cfg.sshbug_hmac2 == FORCE_OFF ? 1 : 0, 0);
- SendDlgItemMessage(hwnd, IDC_BUGD_DERIVEKEY2, CB_RESETCONTENT, 0, 0);
- SendDlgItemMessage(hwnd, IDC_BUGD_DERIVEKEY2, CB_ADDSTRING, 0, (LPARAM)"Auto");
- SendDlgItemMessage(hwnd, IDC_BUGD_DERIVEKEY2, CB_ADDSTRING, 0, (LPARAM)"Off");
- SendDlgItemMessage(hwnd, IDC_BUGD_DERIVEKEY2, CB_ADDSTRING, 0, (LPARAM)"On");
- SendDlgItemMessage(hwnd, IDC_BUGD_DERIVEKEY2, CB_SETCURSEL,
- cfg.sshbug_derivekey2 == FORCE_ON ? 2 :
- cfg.sshbug_derivekey2 == FORCE_OFF ? 1 : 0, 0);
- SendDlgItemMessage(hwnd, IDC_BUGD_RSAPAD2, CB_RESETCONTENT, 0, 0);
- SendDlgItemMessage(hwnd, IDC_BUGD_RSAPAD2, CB_ADDSTRING, 0, (LPARAM)"Auto");
- SendDlgItemMessage(hwnd, IDC_BUGD_RSAPAD2, CB_ADDSTRING, 0, (LPARAM)"Off");
- SendDlgItemMessage(hwnd, IDC_BUGD_RSAPAD2, CB_ADDSTRING, 0, (LPARAM)"On");
- SendDlgItemMessage(hwnd, IDC_BUGD_RSAPAD2, CB_SETCURSEL,
- cfg.sshbug_rsapad2 == FORCE_ON ? 2 :
- cfg.sshbug_rsapad2 == FORCE_OFF ? 1 : 0, 0);
- SendDlgItemMessage(hwnd, IDC_BUGD_DHGEX2, CB_RESETCONTENT, 0, 0);
- SendDlgItemMessage(hwnd, IDC_BUGD_DHGEX2, CB_ADDSTRING, 0, (LPARAM)"Auto");
- SendDlgItemMessage(hwnd, IDC_BUGD_DHGEX2, CB_ADDSTRING, 0, (LPARAM)"Off");
- SendDlgItemMessage(hwnd, IDC_BUGD_DHGEX2, CB_ADDSTRING, 0, (LPARAM)"On");
- SendDlgItemMessage(hwnd, IDC_BUGD_DHGEX2, CB_SETCURSEL,
- cfg.sshbug_dhgex2 == FORCE_ON ? 2 :
- cfg.sshbug_dhgex2 == FORCE_OFF ? 1 : 0, 0);
- SendDlgItemMessage(hwnd, IDC_BUGD_PKSESSID2, CB_RESETCONTENT, 0, 0);
- SendDlgItemMessage(hwnd, IDC_BUGD_PKSESSID2, CB_ADDSTRING, 0, (LPARAM)"Auto");
- SendDlgItemMessage(hwnd, IDC_BUGD_PKSESSID2, CB_ADDSTRING, 0, (LPARAM)"Off");
- SendDlgItemMessage(hwnd, IDC_BUGD_PKSESSID2, CB_ADDSTRING, 0, (LPARAM)"On");
- SendDlgItemMessage(hwnd, IDC_BUGD_PKSESSID2, CB_SETCURSEL,
- cfg.sshbug_pksessid2 == FORCE_ON ? 2 :
- cfg.sshbug_pksessid2 == FORCE_OFF ? 1 : 0, 0);
-}
-
struct treeview_faff {
HWND treeview;
HTREEITEM lastat[4];
};
static HTREEITEM treeview_insert(struct treeview_faff *faff,
- int level, char *text)
+ int level, char *text, char *path)
{
TVINSERTSTRUCT ins;
int i;
#else
#define INSITEM item
#endif
- ins.INSITEM.mask = TVIF_TEXT;
+ ins.INSITEM.mask = TVIF_TEXT | TVIF_PARAM;
ins.INSITEM.pszText = text;
+ ins.INSITEM.cchTextMax = strlen(text)+1;
+ ins.INSITEM.lParam = (LPARAM)path;
newitem = TreeView_InsertItem(faff->treeview, &ins);
if (level > 0)
TreeView_Expand(faff->treeview, faff->lastat[level - 1],
/*
* Create the panelfuls of controls in the configuration box.
*/
-static void create_controls(HWND hwnd, int dlgtype, int panel)
+static void create_controls(HWND hwnd, char *path)
{
- if (panel == sessionpanelstart) {
- /* The Session panel. Accelerators used: [acgoh] nprtis elvd w */
- struct ctlpos cp;
- ctlposinit(&cp, hwnd, 80, 3, 13);
- bartitle(&cp, "Basic options for your PuTTY session",
- IDC_TITLE_SESSION);
- if (dlgtype == 0) {
- beginbox(&cp, "Specify your connection by host name or IP address",
- IDC_BOX_SESSION1);
- multiedit(&cp,
- "Host &Name (or IP address)",
- IDC_HOSTSTATIC, IDC_HOST, 75,
- "&Port", IDC_PORTSTATIC, IDC_PORT, 25, NULL);
- if (backends[3].backend == NULL) {
- /* this is PuTTYtel, so only three protocols available */
- radioline(&cp, "Protocol:", IDC_PROTSTATIC, 3,
- "&Raw", IDC_PROTRAW,
- "&Telnet", IDC_PROTTELNET,
- "Rlog&in", IDC_PROTRLOGIN, NULL);
- } else {
- radioline(&cp, "Protocol:", IDC_PROTSTATIC, 4,
- "&Raw", IDC_PROTRAW,
- "&Telnet", IDC_PROTTELNET,
- "Rlog&in", IDC_PROTRLOGIN,
-#ifdef FWHACK
- "&SSH/hack",
-#else
- "&SSH",
-#endif
- IDC_PROTSSH, NULL);
- }
- endbox(&cp);
- beginbox(&cp, "Load, save or delete a stored session",
- IDC_BOX_SESSION2);
- sesssaver(&cp, "Sav&ed Sessions",
- IDC_SESSSTATIC, IDC_SESSEDIT, IDC_SESSLIST,
- "&Load", IDC_SESSLOAD,
- "Sa&ve", IDC_SESSSAVE, "&Delete", IDC_SESSDEL, NULL);
- endbox(&cp);
- }
- beginbox(&cp, NULL, IDC_BOX_SESSION3);
- radioline(&cp, "Close &window on exit:", IDC_CLOSEEXIT, 4,
- "Always", IDC_COEALWAYS,
- "Never", IDC_COENEVER,
- "Only on clean exit", IDC_COENORMAL, NULL);
- endbox(&cp);
- }
+ struct ctlpos cp;
+ int index;
+ int base_id;
+ struct winctrls *wc;
- if (panel == loggingpanelstart) {
- /* The Logging panel. Accelerators used: [acgoh] tplsfwe */
- struct ctlpos cp;
- ctlposinit(&cp, hwnd, 80, 3, 13);
- bartitle(&cp, "Options controlling session logging",
- IDC_TITLE_LOGGING);
- beginbox(&cp, NULL, IDC_BOX_LOGGING1);
- radiobig(&cp,
- "Session logging:", IDC_LSTATSTATIC,
- "Logging &turned off completely", IDC_LSTATOFF,
- "Log &printable output only", IDC_LSTATASCII,
- "&Log all session output", IDC_LSTATRAW,
- "Log &SSH packet data", IDC_LSTATPACKET,
- NULL);
- editbutton(&cp, "Log &file name:",
- IDC_LGFSTATIC, IDC_LGFEDIT, "Bro&wse...",
- IDC_LGFBUTTON);
- statictext(&cp, "(Log file name can contain &&Y, &&M, &&D for date,"
- " &&T for time, and &&H for host name)", 2, IDC_LGFEXPLAIN);
- radiobig(&cp,
- "What to do if the log file already &exists:",
- IDC_LSTATXIST, "Always overwrite it", IDC_LSTATXOVR,
- "Always append to the end of it", IDC_LSTATXAPN,
- "Ask the user every time", IDC_LSTATXASK, NULL);
- endbox(&cp);
- }
-
- if (panel == terminalpanelstart) {
- /* The Terminal panel. Accelerators used: [acgoh] wdren lts p */
- struct ctlpos cp;
- ctlposinit(&cp, hwnd, 80, 3, 13);
- bartitle(&cp, "Options controlling the terminal emulation",
- IDC_TITLE_TERMINAL);
- beginbox(&cp, "Set various terminal options", IDC_BOX_TERMINAL1);
- checkbox(&cp, "Auto &wrap mode initially on", IDC_WRAPMODE);
- checkbox(&cp, "&DEC Origin Mode initially on", IDC_DECOM);
- checkbox(&cp, "Implicit C&R in every LF", IDC_LFHASCR);
- checkbox(&cp, "Use background colour to &erase screen", IDC_BCE);
- checkbox(&cp, "Enable bli&nking text", IDC_BLINKTEXT);
- multiedit(&cp,
- "An&swerback to ^E:", IDC_ANSWERBACK,
- IDC_ANSWEREDIT, 100, NULL);
- endbox(&cp);
-
- beginbox(&cp, "Line discipline options", IDC_BOX_TERMINAL2);
- radioline(&cp, "&Local echo:", IDC_ECHOSTATIC, 3,
- "Auto", IDC_ECHOBACKEND,
- "Force on", IDC_ECHOYES, "Force off", IDC_ECHONO, NULL);
- radioline(&cp, "Local line edi&ting:", IDC_EDITSTATIC, 3,
- "Auto", IDC_EDITBACKEND,
- "Force on", IDC_EDITYES, "Force off", IDC_EDITNO, NULL);
- endbox(&cp);
-
- beginbox(&cp, "Remote-controlled printing", IDC_BOX_TERMINAL3);
- combobox(&cp, "&Printer to send ANSI printer output to:",
- IDC_PRINTERSTATIC, IDC_PRINTER);
- endbox(&cp);
- }
-
- if (panel == featurespanelstart) {
- /* The Features panel. Accelerators used: [acgoh] ukswtbrx */
- struct ctlpos cp;
- ctlposinit(&cp, hwnd, 80, 3, 13);
- bartitle(&cp, "Enabling and disabling advanced terminal features ",
- IDC_TITLE_FEATURES);
- beginbox(&cp, NULL, IDC_BOX_FEATURES1);
- checkbox(&cp, "Disable application c&ursor keys mode", IDC_NOAPPLICC);
- checkbox(&cp, "Disable application &keypad mode", IDC_NOAPPLICK);
- checkbox(&cp, "Disable &xterm-style mouse reporting", IDC_NOMOUSEREP);
- checkbox(&cp, "Disable remote-controlled terminal re&sizing",
- IDC_NORESIZE);
- checkbox(&cp, "Disable s&witching to alternate terminal screen",
- IDC_NOALTSCREEN);
- checkbox(&cp, "Disable remote-controlled window &title changing",
- IDC_NOWINTITLE);
- checkbox(&cp, "Disable destructive &backspace on server sending ^?",
- IDC_NODBACKSPACE);
- checkbox(&cp, "Disable remote-controlled cha&racter set configuration",
- IDC_NOCHARSET);
- endbox(&cp);
- }
-
- if (panel == bellpanelstart) {
- /* The Bell panel. Accelerators used: [acgoh] bdsm wit */
- struct ctlpos cp;
- ctlposinit(&cp, hwnd, 80, 3, 13);
- bartitle(&cp, "Options controlling the terminal bell",
- IDC_TITLE_BELL);
- beginbox(&cp, "Set the style of bell", IDC_BOX_BELL1);
- radiobig(&cp,
- "Action to happen when a &bell occurs:", IDC_BELLSTATIC,
- "None (bell disabled)", IDC_BELL_DISABLED,
- "Play Windows Default Sound", IDC_BELL_DEFAULT,
- "Play a custom sound file", IDC_BELL_WAVEFILE,
- "Visual bell (flash window)", IDC_BELL_VISUAL, NULL);
- editbutton(&cp, "Custom sound file to play as a bell:",
- IDC_BELL_WAVESTATIC, IDC_BELL_WAVEEDIT,
- "Bro&wse...", IDC_BELL_WAVEBROWSE);
- radioline(&cp, "Taskbar/caption &indication on bell:",
- IDC_B_IND_STATIC, 3, "Disabled", IDC_B_IND_DISABLED,
- "Flashing", IDC_B_IND_FLASH, "Steady", IDC_B_IND_STEADY,
- NULL);
- endbox(&cp);
- beginbox(&cp, "Control the bell overload behaviour",
- IDC_BOX_BELL2);
- checkbox(&cp, "Bell is temporarily &disabled when over-used",
- IDC_BELLOVL);
- staticedit(&cp, "Over-use means this &many bells...",
- IDC_BELLOVLNSTATIC, IDC_BELLOVLN, 20);
- staticedit(&cp, "... in &this many seconds",
- IDC_BELLOVLTSTATIC, IDC_BELLOVLT, 20);
- statictext(&cp,
- "The bell is re-enabled after a few seconds of silence.",
- 1, IDC_BELLOVLEXPLAIN);
- staticedit(&cp, "Seconds of &silence required", IDC_BELLOVLSSTATIC,
- IDC_BELLOVLS, 20);
- endbox(&cp);
- }
-
- if (panel == keyboardpanelstart) {
- /* The Keyboard panel. Accelerators used: [acgoh] bef rntd */
- struct ctlpos cp;
- ctlposinit(&cp, hwnd, 80, 3, 13);
- bartitle(&cp, "Options controlling the effects of keys",
- IDC_TITLE_KEYBOARD);
- beginbox(&cp, "Change the sequences sent by:", IDC_BOX_KEYBOARD1);
- radioline(&cp, "The &Backspace key", IDC_DELSTATIC, 2,
- "Control-H", IDC_DEL008,
- "Control-? (127)", IDC_DEL127, NULL);
- radioline(&cp, "The Home and &End keys", IDC_HOMESTATIC, 2,
- "Standard", IDC_HOMETILDE, "rxvt", IDC_HOMERXVT, NULL);
- radioline(&cp, "The &Function keys and keypad", IDC_FUNCSTATIC, 3,
- "ESC[n~", IDC_FUNCTILDE,
- "Linux", IDC_FUNCLINUX,
- "Xterm R6", IDC_FUNCXTERM,
- "VT400", IDC_FUNCVT400,
- "VT100+", IDC_FUNCVT100P, "SCO", IDC_FUNCSCO, NULL);
- endbox(&cp);
- beginbox(&cp, "Application keypad settings:", IDC_BOX_KEYBOARD2);
- radioline(&cp, "Initial state of cu&rsor keys:", IDC_CURSTATIC, 2,
- "Normal", IDC_CURNORMAL,
- "Application", IDC_CURAPPLIC, NULL);
- radioline(&cp, "Initial state of &numeric keypad:", IDC_KPSTATIC,
- 3, "Normal", IDC_KPNORMAL, "Application", IDC_KPAPPLIC,
- "NetHack", IDC_KPNH, NULL);
- endbox(&cp);
- beginbox(&cp, "Enable extra keyboard features:",
- IDC_BOX_KEYBOARD3);
- checkbox(&cp, "AltGr ac&ts as Compose key", IDC_COMPOSEKEY);
- checkbox(&cp, "Control-Alt is &different from AltGr",
- IDC_CTRLALTKEYS);
- endbox(&cp);
- }
-
- if (panel == windowpanelstart) {
- /* The Window panel. Accelerators used: [acgoh] rmz sdikp */
- struct ctlpos cp;
- ctlposinit(&cp, hwnd, 80, 3, 13);
- bartitle(&cp, "Options controlling PuTTY's window",
- IDC_TITLE_WINDOW);
- beginbox(&cp, "Set the size of the window", IDC_BOX_WINDOW1);
- multiedit(&cp,
- "&Rows", IDC_ROWSSTATIC, IDC_ROWSEDIT, 50,
- "Colu&mns", IDC_COLSSTATIC, IDC_COLSEDIT, 50, NULL);
- radiobig(&cp, "When window is resi&zed:", IDC_RESIZESTATIC,
- "Change the number of rows and columns", IDC_RESIZETERM,
- "Change the size of the font", IDC_RESIZEFONT,
- "Change font size only when maximised", IDC_RESIZEEITHER,
- "Forbid resizing completely", IDC_RESIZENONE, NULL);
- endbox(&cp);
- beginbox(&cp, "Control the scrollback in the window",
- IDC_BOX_WINDOW2);
- staticedit(&cp, "Lines of &scrollback",
- IDC_SAVESTATIC, IDC_SAVEEDIT, 50);
- checkbox(&cp, "&Display scrollbar", IDC_SCROLLBAR);
- checkbox(&cp, "D&isplay scrollbar in full screen mode", IDC_SCROLLBARFULLSCREEN);
- checkbox(&cp, "Reset scrollback on &keypress", IDC_SCROLLKEY);
- checkbox(&cp, "Reset scrollback on dis&play activity",
- IDC_SCROLLDISP);
- endbox(&cp);
- }
-
- if (panel == appearancepanelstart) {
- /* The Appearance panel. Accelerators used: [acgoh] luvb n ti p s */
- struct ctlpos cp;
- ctlposinit(&cp, hwnd, 80, 3, 13);
- bartitle(&cp, "Configure the appearance of PuTTY's window",
- IDC_TITLE_APPEARANCE);
- beginbox(&cp, "Adjust the use of the cursor", IDC_BOX_APPEARANCE1);
- radioline(&cp, "Cursor appearance:", IDC_CURSORSTATIC, 3,
- "B&lock", IDC_CURBLOCK,
- "&Underline", IDC_CURUNDER,
- "&Vertical line", IDC_CURVERT, NULL);
- checkbox(&cp, "Cursor &blinks", IDC_BLINKCUR);
- endbox(&cp);
- beginbox(&cp, "Set the font used in the terminal window",
- IDC_BOX_APPEARANCE2);
- staticbtn(&cp, "", IDC_FONTSTATIC, "Cha&nge...", IDC_CHOOSEFONT);
- endbox(&cp);
- beginbox(&cp, "Adjust the use of the window title",
- IDC_BOX_APPEARANCE3);
- multiedit(&cp,
- "Window &title:", IDC_WINTITLE, IDC_WINEDIT, 100, NULL);
- checkbox(&cp, "Separate window and &icon titles", IDC_WINNAME);
- endbox(&cp);
- beginbox(&cp, "Adjust the use of the mouse pointer",
- IDC_BOX_APPEARANCE4);
- checkbox(&cp, "Hide mouse &pointer when typing in window",
- IDC_HIDEMOUSE);
- endbox(&cp);
- beginbox(&cp, "Adjust the window border", IDC_BOX_APPEARANCE5);
- checkbox(&cp, "&Sunken-edge border (slightly thicker)",
- IDC_SUNKENEDGE);
- staticedit(&cp, "Gap between text and window edge",
- IDC_WINBSTATIC, IDC_WINBEDIT, 20);
- endbox(&cp);
- }
-
- if (panel == behaviourpanelstart) {
- /* The Behaviour panel. Accelerators used: [acgoh] w4yltf */
- struct ctlpos cp;
- ctlposinit(&cp, hwnd, 80, 3, 13);
- bartitle(&cp, "Configure the behaviour of PuTTY's window",
- IDC_TITLE_WINDOW);
- beginbox(&cp, NULL, IDC_BOX_BEHAVIOUR1);
- checkbox(&cp, "&Warn before closing window", IDC_CLOSEWARN);
- checkbox(&cp, "Window closes on ALT-F&4", IDC_ALTF4);
- checkbox(&cp, "S&ystem menu appears on ALT-Space", IDC_ALTSPACE);
- checkbox(&cp, "System menu appears on A< alone", IDC_ALTONLY);
- checkbox(&cp, "Ensure window is always on &top", IDC_ALWAYSONTOP);
- checkbox(&cp, "&Full screen on Alt-Enter", IDC_FULLSCREENONALTENTER);
- endbox(&cp);
- }
-
- if (panel == translationpanelstart) {
- /* The Translation panel. Accelerators used: [acgoh] rxbepus */
- struct ctlpos cp;
- ctlposinit(&cp, hwnd, 80, 3, 13);
- bartitle(&cp, "Options controlling character set translation",
- IDC_TITLE_TRANSLATION);
- beginbox(&cp, "Character set translation on received data",
- IDC_BOX_TRANSLATION1);
- combobox(&cp, "&Received data assumed to be in which character set:",
- IDC_CODEPAGESTATIC, IDC_CODEPAGE);
- endbox(&cp);
- beginbox(&cp, "Enable character set translation on input data",
- IDC_BOX_TRANSLATION2);
- checkbox(&cp, "Cap&s Lock acts as Cyrillic switch",
- IDC_CAPSLOCKCYR);
- endbox(&cp);
- beginbox(&cp, "Adjust how PuTTY displays line drawing characters",
- IDC_BOX_TRANSLATION3);
- radiobig(&cp,
- "Handling of line drawing characters:", IDC_VTSTATIC,
- "Font has &XWindows encoding", IDC_VTXWINDOWS,
- "Use font in &both ANSI and OEM modes", IDC_VTOEMANSI,
- "Use font in O&EM mode only", IDC_VTOEMONLY,
- "&Poor man's line drawing (" "+" ", " "-" " and " "|" ")",
- IDC_VTPOORMAN, "&Unicode mode", IDC_VTUNICODE, NULL);
- endbox(&cp);
- }
-
- if (panel == selectionpanelstart) {
- /* The Selection panel. Accelerators used: [acgoh] df wxp est nr */
- struct ctlpos cp;
- ctlposinit(&cp, hwnd, 80, 3, 13);
- bartitle(&cp, "Options controlling copy and paste",
- IDC_TITLE_SELECTION);
- beginbox(&cp, "Translation of pasted characters",
- IDC_BOX_SELECTION1);
- checkbox(&cp,
- "&Don't translate line drawing chars into +, - and |",
- IDC_RAWCNP);
- checkbox(&cp,
- "Paste to clipboard in RT&F as well as plain text",
- IDC_RTFPASTE);
- endbox(&cp);
- beginbox(&cp, "Control which mouse button does which thing",
- IDC_BOX_SELECTION2);
- radiobig(&cp, "Action of mouse buttons:", IDC_MBSTATIC,
- "&Windows (Right pastes, Middle extends)", IDC_MBWINDOWS,
- "&xterm (Right extends, Middle pastes)", IDC_MBXTERM,
- NULL);
- checkbox(&cp,
- "Shift overrides a&pplication's use of mouse",
- IDC_MOUSEOVERRIDE);
- radioline(&cp,
- "Default selection mode (Alt+drag does the other one):",
- IDC_SELTYPESTATIC, 2,
- "&Normal", IDC_SELTYPELEX,
- "&Rectangular block", IDC_SELTYPERECT, NULL);
- endbox(&cp);
- beginbox(&cp, "Control the select-one-word-at-a-time mode",
- IDC_BOX_SELECTION3);
- charclass(&cp, "Charact&er classes:", IDC_CCSTATIC, IDC_CCLIST,
- "&Set", IDC_CCSET, IDC_CCEDIT,
- "&to class", IDC_CCSTATIC2);
- endbox(&cp);
- }
-
- if (panel == colourspanelstart) {
- /* The Colours panel. Accelerators used: [acgoh] blum */
- struct ctlpos cp;
- ctlposinit(&cp, hwnd, 80, 3, 13);
- bartitle(&cp, "Options controlling use of colours",
- IDC_TITLE_COLOURS);
- beginbox(&cp, "General options for colour usage",
- IDC_BOX_COLOURS1);
- checkbox(&cp, "&Bolded text is a different colour",
- IDC_BOLDCOLOUR);
- checkbox(&cp, "Attempt to use &logical palettes", IDC_PALETTE);
- endbox(&cp);
- beginbox(&cp, "Adjust the precise colours PuTTY displays",
- IDC_BOX_COLOURS2);
- colouredit(&cp, "Select a colo&ur and then click to modify it:",
- IDC_COLOURSTATIC, IDC_COLOURLIST,
- "&Modify...", IDC_CHANGE,
- "Red:", IDC_RSTATIC, IDC_RVALUE,
- "Green:", IDC_GSTATIC, IDC_GVALUE,
- "Blue:", IDC_BSTATIC, IDC_BVALUE, NULL);
- endbox(&cp);
- }
-
- if (panel == connectionpanelstart) {
- /* The Connection panel. Accelerators used: [acgoh] tukn */
- struct ctlpos cp;
- ctlposinit(&cp, hwnd, 80, 3, 13);
- bartitle(&cp, "Options controlling the connection",
- IDC_TITLE_CONNECTION);
- if (dlgtype == 0) {
- beginbox(&cp, "Data to send to the server",
- IDC_BOX_CONNECTION1);
- staticedit(&cp, "Terminal-&type string", IDC_TTSTATIC,
- IDC_TTEDIT, 50);
- staticedit(&cp, "Auto-login &username", IDC_LOGSTATIC,
- IDC_LOGEDIT, 50);
- endbox(&cp);
- } else {
- beginbox(&cp, "Adjust telnet session.", IDC_BOX_CONNECTION1);
- checkbox(&cp, "Keyboard sends telnet Backspace and Interrupt",
- IDC_TELNETKEY);
- checkbox(&cp, "Return key sends telnet New Line instead of ^M",
- IDC_TELNETRET);
- endbox(&cp);
- }
- beginbox(&cp, "Sending of null packets to keep session active",
- IDC_BOX_CONNECTION2);
- staticedit(&cp, "Seconds between &keepalives (0 to turn off)",
- IDC_PINGSTATIC, IDC_PINGEDIT, 20);
- endbox(&cp);
- if (dlgtype == 0) {
- beginbox(&cp, "Low-level TCP connection options",
- IDC_BOX_CONNECTION3);
- checkbox(&cp, "Disable &Nagle's algorithm (TCP_NODELAY option)",
- IDC_NODELAY);
- endbox(&cp);
- }
- }
-
- if (panel == proxypanelstart) {
- /* The Proxy panel. Accelerators used: [acgoh] ntslypeuwmvxd */
- struct ctlpos cp;
- ctlposinit(&cp, hwnd, 80, 3, 13);
- if (dlgtype == 0) {
- bartitle(&cp, "Options controlling proxy usage",
- IDC_TITLE_PROXY);
- beginbox(&cp, "Proxy basics", IDC_BOX_PROXY1);
- radioline(&cp, "Proxy type:", IDC_PROXYTYPESTATIC, 4,
- "&None", IDC_PROXYTYPENONE,
- "H&TTP", IDC_PROXYTYPEHTTP,
- "&SOCKS", IDC_PROXYTYPESOCKS,
- "Te&lnet", IDC_PROXYTYPETELNET, NULL);
- multiedit(&cp,
- "Prox&y Host", IDC_PROXYHOSTSTATIC, IDC_PROXYHOSTEDIT, 80,
- "&Port", IDC_PROXYPORTSTATIC, IDC_PROXYPORTEDIT, 20, NULL);
- multiedit(&cp,
- "&Exclude Hosts/IPs", IDC_PROXYEXCLUDESTATIC,
- IDC_PROXYEXCLUDEEDIT, 100, NULL);
- checkbox(&cp, "Consider pro&xying local host connections",
- IDC_PROXYLOCALHOST);
- radioline(&cp, "Do &DNS name lookup at proxy end:",
- IDC_PROXYDNSSTATIC, 3,
- "No", IDC_PROXYDNSNO,
- "Auto", IDC_PROXYDNSAUTO,
- "Yes", IDC_PROXYDNSYES, NULL);
- staticedit(&cp, "&Username", IDC_PROXYUSERSTATIC,
- IDC_PROXYUSEREDIT, 60);
- staticpassedit(&cp, "Pass&word", IDC_PROXYPASSSTATIC,
- IDC_PROXYPASSEDIT, 60);
- endbox(&cp);
- beginbox(&cp, "Misc. proxy settings", IDC_BOX_PROXY2);
- multiedit(&cp,
- "Telnet co&mmand", IDC_PROXYTELNETCMDSTATIC,
- IDC_PROXYTELNETCMDEDIT, 100, NULL);
- radioline(&cp, "SOCKS &Version", IDC_PROXYSOCKSVERSTATIC,
- 2, "Version 5", IDC_PROXYSOCKSVER5, "Version 4",
- IDC_PROXYSOCKSVER4, NULL);
- endbox(&cp);
- }
- }
-
- if (panel == telnetpanelstart) {
- /* The Telnet panel. Accelerators used: [acgoh] svldr bftk */
- struct ctlpos cp;
- ctlposinit(&cp, hwnd, 80, 3, 13);
- if (dlgtype == 0) {
- bartitle(&cp, "Options controlling Telnet connections",
- IDC_TITLE_TELNET);
- beginbox(&cp, "Data to send to the server", IDC_BOX_TELNET1);
- staticedit(&cp, "Terminal-&speed string", IDC_TSSTATIC,
- IDC_TSEDIT, 50);
- envsetter(&cp, "Environment variables:", IDC_ENVSTATIC,
- "&Variable", IDC_VARSTATIC, IDC_VAREDIT, "Va&lue",
- IDC_VALSTATIC, IDC_VALEDIT, IDC_ENVLIST, "A&dd",
- IDC_ENVADD, "&Remove", IDC_ENVREMOVE);
- endbox(&cp);
- beginbox(&cp, "Telnet protocol adjustments", IDC_BOX_TELNET2);
- radioline(&cp, "Handling of OLD_ENVIRON ambiguity:",
- IDC_EMSTATIC, 2, "&BSD (commonplace)", IDC_EMBSD,
- "R&FC 1408 (unusual)", IDC_EMRFC, NULL);
- radioline(&cp, "&Telnet negotiation mode:", IDC_ACTSTATIC, 2,
- "Passive", IDC_TPASSIVE, "Active",
- IDC_TACTIVE, NULL);
- checkbox(&cp, "&Keyboard sends telnet Backspace and Interrupt",
- IDC_TELNETKEY);
- checkbox(&cp, "Return key sends telnet New Line instead of ^M",
- IDC_TELNETRET);
- endbox(&cp);
- }
- }
-
- if (panel == rloginpanelstart) {
- /* The Rlogin panel. Accelerators used: [acgoh] sl */
- struct ctlpos cp;
- ctlposinit(&cp, hwnd, 80, 3, 13);
- if (dlgtype == 0) {
- bartitle(&cp, "Options controlling Rlogin connections",
- IDC_TITLE_RLOGIN);
- beginbox(&cp, "Data to send to the server", IDC_BOX_RLOGIN1);
- staticedit(&cp, "Terminal-&speed string", IDC_R_TSSTATIC,
- IDC_R_TSEDIT, 50);
- staticedit(&cp, "&Local username:", IDC_RLLUSERSTATIC,
- IDC_RLLUSEREDIT, 50);
- endbox(&cp);
- }
- }
-
- if (panel == sshpanelstart) {
- /* The SSH panel. Accelerators used: [acgoh] r pel12n sud i */
- struct ctlpos cp;
- ctlposinit(&cp, hwnd, 80, 3, 13);
- if (dlgtype == 0) {
- bartitle(&cp, "Options controlling SSH connections",
- IDC_TITLE_SSH);
- beginbox(&cp, "Data to send to the server", IDC_BOX_SSH1);
- multiedit(&cp,
- "&Remote command:", IDC_CMDSTATIC, IDC_CMDEDIT, 100,
- NULL);
- endbox(&cp);
- beginbox(&cp, "Protocol options", IDC_BOX_SSH2);
- checkbox(&cp, "Don't allocate a &pseudo-terminal", IDC_NOPTY);
- checkbox(&cp, "Enable compr&ession", IDC_COMPRESS);
- radioline(&cp, "Preferred SSH protocol version:",
- IDC_SSHPROTSTATIC, 4,
- "1 on&ly", IDC_SSHPROT1ONLY,
- "&1", IDC_SSHPROT1, "&2", IDC_SSHPROT2,
- "2 o&nly", IDC_SSHPROT2ONLY, NULL);
- endbox(&cp);
- beginbox(&cp, "Encryption options", IDC_BOX_SSH3);
- /* Adds accelerators: ud */
- prefslist(&cipherlist, &cp, "Encryption cipher &selection policy:",
- IDC_CIPHERSTATIC2, IDC_CIPHERLIST, IDC_CIPHERUP,
- IDC_CIPHERDN);
- checkbox(&cp, "Enable non-standard use of s&ingle-DES in SSH 2",
- IDC_SSH2DES);
- endbox(&cp);
- }
- }
-
- if (panel == sshauthpanelstart) {
- /* The SSH authentication panel. Accelerators used: [acgoh] m fkiuw */
- struct ctlpos cp;
- ctlposinit(&cp, hwnd, 80, 3, 13);
- if (dlgtype == 0) {
- bartitle(&cp, "Options controlling SSH authentication",
- IDC_TITLE_SSHAUTH);
- beginbox(&cp, "Authentication methods",
- IDC_BOX_SSHAUTH1);
- checkbox(&cp, "Atte&mpt TIS or CryptoCard authentication (SSH1)",
- IDC_AUTHTIS);
- checkbox(&cp, "Attempt \"keyboard-&interactive\" authentication"
- " (SSH2)", IDC_AUTHKI);
- endbox(&cp);
- beginbox(&cp, "Authentication parameters",
- IDC_BOX_SSHAUTH2);
- checkbox(&cp, "Allow agent &forwarding", IDC_AGENTFWD);
- checkbox(&cp, "Allow attempted changes of &username in SSH2",
- IDC_CHANGEUSER);
- editbutton(&cp, "Private &key file for authentication:",
- IDC_PKSTATIC, IDC_PKEDIT, "Bro&wse...",
- IDC_PKBUTTON);
- endbox(&cp);
- }
- }
-
- if (panel == sshbugspanelstart) {
- /* The SSH bugs panel. Accelerators used: [acgoh] isrmepd */
- struct ctlpos cp;
+ if (!path[0]) {
+ /*
+ * Here we must create the basic standard controls.
+ */
+ ctlposinit(&cp, hwnd, 3, 3, 235);
+ wc = &ctrls_base;
+ base_id = IDCX_STDBASE;
+ } else {
+ /*
+ * Otherwise, we're creating the controls for a particular
+ * panel.
+ */
ctlposinit(&cp, hwnd, 80, 3, 13);
- if (dlgtype == 0) {
- bartitle(&cp, "Workarounds for SSH server bugs",
- IDC_TITLE_SSHBUGS);
- beginbox(&cp, "Detection of known bugs in SSH servers",
- IDC_BOX_SSHBUGS1);
- staticddl(&cp, "Chokes on SSH1 &ignore messages",
- IDC_BUGS_IGNORE1, IDC_BUGD_IGNORE1, 20);
- staticddl(&cp, "Refuses all SSH1 pa&ssword camouflage",
- IDC_BUGS_PLAINPW1, IDC_BUGD_PLAINPW1, 20);
- staticddl(&cp, "Chokes on SSH1 &RSA authentication",
- IDC_BUGS_RSA1, IDC_BUGD_RSA1, 20);
- staticddl(&cp, "Miscomputes SSH2 H&MAC keys",
- IDC_BUGS_HMAC2, IDC_BUGD_HMAC2, 20);
- staticddl(&cp, "Miscomputes SSH2 &encryption keys",
- IDC_BUGS_DERIVEKEY2, IDC_BUGD_DERIVEKEY2, 20);
- staticddl(&cp, "Requires &padding on SSH2 RSA signatures",
- IDC_BUGS_RSAPAD2, IDC_BUGD_RSAPAD2, 20);
- staticddl(&cp, "Chokes on &Diffie-Hellman group exchange",
- IDC_BUGS_DHGEX2, IDC_BUGD_DHGEX2, 20);
- staticddl(&cp, "Misuses the sessio&n ID in PK auth",
- IDC_BUGS_PKSESSID2, IDC_BUGD_PKSESSID2, 20);
- endbox(&cp);
- }
+ wc = &ctrls_panel;
+ base_id = IDCX_PANELBASE;
}
- if (panel == tunnelspanelstart) {
- /* The Tunnels panel. Accelerators used: [acgoh] exu tprsdilm */
- struct ctlpos cp;
- ctlposinit(&cp, hwnd, 80, 3, 13);
- if (dlgtype == 0) {
- bartitle(&cp, "Options controlling SSH tunnelling",
- IDC_TITLE_TUNNELS);
- beginbox(&cp, "X11 forwarding", IDC_BOX_TUNNELS1);
- checkbox(&cp, "&Enable X11 forwarding", IDC_X11_FORWARD);
- staticedit(&cp, "&X display location", IDC_X11_DISPSTATIC,
- IDC_X11_DISPLAY, 50);
- radioline(&cp, "Remote X11 a&uthentication protocol",
- IDC_X11AUTHSTATIC, 2,
- "MIT-Magic-Cookie-1", IDC_X11MIT,
- "XDM-Authorization-1", IDC_X11XDM, NULL);
- endbox(&cp);
- beginbox(&cp, "Port forwarding", IDC_BOX_TUNNELS2);
- checkbox(&cp, "Local ports accept connections from o&ther hosts",
- IDC_LPORT_ALL);
- checkbox(&cp, "Remote &ports do the same (SSH v2 only)",
- IDC_RPORT_ALL);
- staticbtn(&cp, "Forwarded ports:", IDC_PFWDSTATIC,
- "&Remove", IDC_PFWDREMOVE);
- fwdsetter(&cp, IDC_PFWDLIST,
- "Add new forwarded port:", IDC_PFWDSTATIC2,
- "&Source port", IDC_SPORTSTATIC, IDC_SPORTEDIT,
- "Dest&ination", IDC_DPORTSTATIC, IDC_DPORTEDIT,
- "A&dd", IDC_PFWDADD,
- "&Local", IDC_PFWDLOCAL,
- "Re&mote", IDC_PFWDREMOTE);
- endbox(&cp);
-
- }
+ for (index=-1; (index = ctrl_find_path(ctrlbox, path, index)) >= 0 ;) {
+ struct controlset *s = ctrlbox->ctrlsets[index];
+ winctrl_layout(&dp, wc, &cp, s, &base_id);
}
}
-/*
- * Helper function to load the session selected in SESSLIST
- * if any, as this is done in more than one place in
- * GenericMainDlgProc(). 0 => failure.
- */
-static int load_selected_session(HWND hwnd)
-{
- int n = SendDlgItemMessage(hwnd, IDC_SESSLIST,
- LB_GETCURSEL, 0, 0);
- int isdef;
- if (n == LB_ERR) {
- MessageBeep(0);
- return 0;
- }
- isdef = !strcmp(sesslist.sessions[n], "Default Settings");
- load_settings(sesslist.sessions[n], !isdef, &cfg);
- init_dlg_ctrls(hwnd, TRUE);
- if (!isdef)
- SetDlgItemText(hwnd, IDC_SESSEDIT, sesslist.sessions[n]);
- else
- SetDlgItemText(hwnd, IDC_SESSEDIT, "");
- /* Restore the selection, which will have been clobbered by
- * SESSEDIT handling. */
- SendDlgItemMessage(hwnd, IDC_SESSLIST, LB_SETCURSEL, n, 0);
- return 1;
-}
-
/*
* This function is the configuration box.
*/
-static int GenericMainDlgProc(HWND hwnd, UINT msg,
- WPARAM wParam, LPARAM lParam, int dlgtype)
+static int CALLBACK GenericMainDlgProc(HWND hwnd, UINT msg,
+ WPARAM wParam, LPARAM lParam)
{
HWND hw, treeview;
struct treeview_faff tvfaff;
- HTREEITEM hsession;
- OPENFILENAME of;
- char filename[sizeof(cfg.keyfile.path)];
- CHOOSEFONT cf;
- LOGFONT lf;
- char fontstatic[256];
- char portname[32];
- struct servent *service;
- int i;
- static UINT draglistmsg = WM_NULL;
+ int ret;
switch (msg) {
case WM_INITDIALOG:
- readytogo = 0;
+ dp.hwnd = hwnd;
+ create_controls(hwnd, ""); /* Open and Cancel buttons etc */
SetWindowLong(hwnd, GWL_USERDATA, 0);
if (help_path)
SetWindowLong(hwnd, GWL_EXSTYLE,
/*
* Set up the tree view contents.
*/
- hsession = treeview_insert(&tvfaff, 0, "Session");
- treeview_insert(&tvfaff, 1, "Logging");
- treeview_insert(&tvfaff, 0, "Terminal");
- treeview_insert(&tvfaff, 1, "Keyboard");
- treeview_insert(&tvfaff, 1, "Bell");
- treeview_insert(&tvfaff, 1, "Features");
- treeview_insert(&tvfaff, 0, "Window");
- treeview_insert(&tvfaff, 1, "Appearance");
- treeview_insert(&tvfaff, 1, "Behaviour");
- treeview_insert(&tvfaff, 1, "Translation");
- treeview_insert(&tvfaff, 1, "Selection");
- treeview_insert(&tvfaff, 1, "Colours");
- treeview_insert(&tvfaff, 0, "Connection");
- if (dlgtype == 0) {
- treeview_insert(&tvfaff, 1, "Proxy");
- treeview_insert(&tvfaff, 1, "Telnet");
- treeview_insert(&tvfaff, 1, "Rlogin");
- if (backends[3].backend != NULL) {
- treeview_insert(&tvfaff, 1, "SSH");
- /* XXX long name is ugly */
- /* XXX make it closed by default? */
- treeview_insert(&tvfaff, 2, "Auth");
- treeview_insert(&tvfaff, 2, "Tunnels");
- treeview_insert(&tvfaff, 2, "Bugs");
+ {
+ HTREEITEM hfirst = NULL;
+ int i;
+ char *path = NULL;
+
+ for (i = 0; i < ctrlbox->nctrlsets; i++) {
+ struct controlset *s = ctrlbox->ctrlsets[i];
+ HTREEITEM item;
+ int j;
+ char *c;
+
+ if (!s->pathname[0])
+ continue;
+ j = path ? ctrl_path_compare(s->pathname, path) : 0;
+ if (j == INT_MAX)
+ continue; /* same path, nothing to add to tree */
+
+ /*
+ * 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++;
+
+ item = treeview_insert(&tvfaff, j, c, s->pathname);
+ if (!hfirst)
+ hfirst = item;
+
+ path = s->pathname;
}
- }
- /*
- * Put the treeview selection on to the Session panel. This
- * should also cause creation of the relevant controls.
- */
- TreeView_SelectItem(treeview, hsession);
+ /*
+ * Put the treeview selection on to the Session panel.
+ * This should also cause creation of the relevant
+ * controls.
+ */
+ TreeView_SelectItem(treeview, hfirst);
+ }
/*
* Set focus into the first available control.
*/
{
- HWND ctl;
- ctl = GetDlgItem(hwnd, IDC_HOST);
- if (!ctl)
- ctl = GetDlgItem(hwnd, IDC_CLOSEEXIT);
- SetFocus(ctl);
+ int i;
+ struct winctrl *c;
+
+ for (i = 0; (c = winctrl_findbyindex(&ctrls_panel, i)) != NULL;
+ i++) {
+ if (c->ctrl) {
+ dlg_set_focus(c->ctrl, &dp);
+ break;
+ }
+ }
}
SetWindowLong(hwnd, GWL_USERDATA, 1);
- sesslist_has_focus = 0;
return 0;
case WM_LBUTTONUP:
/*
* previous double click on the session list.
*/
ReleaseCapture();
- if (readytogo)
- SendMessage(hwnd, WM_COMMAND, IDOK, 0);
+ if (dp.ended)
+ EndDialog(hwnd, dp.endresult ? 1 : 0);
break;
case WM_NOTIFY:
if (LOWORD(wParam) == IDCX_TREEVIEW &&
HTREEITEM i =
TreeView_GetSelection(((LPNMHDR) lParam)->hwndFrom);
TVITEM item;
- int j;
char buffer[64];
SendMessage (hwnd, WM_SETREDRAW, FALSE, 0);
item.hItem = i;
item.pszText = buffer;
item.cchTextMax = sizeof(buffer);
- item.mask = TVIF_TEXT;
+ item.mask = TVIF_TEXT | TVIF_PARAM;
TreeView_GetItem(((LPNMHDR) lParam)->hwndFrom, &item);
- for (j = controlstartvalue; j < controlendvalue; j++) {
- HWND item = GetDlgItem(hwnd, j);
- if (item)
- DestroyWindow(item);
+ {
+ /* Destroy all controls in the currently visible panel. */
+ int k;
+ HWND item;
+ struct winctrl *c;
+
+ while ((c = winctrl_findbyindex(&ctrls_panel, 0)) != NULL) {
+ for (k = 0; k < c->num_ids; k++) {
+ item = GetDlgItem(hwnd, c->base_id + k);
+ if (item)
+ DestroyWindow(item);
+ }
+ winctrl_rem_shortcuts(&dp, c);
+ winctrl_remove(&ctrls_panel, c);
+ sfree(c->data);
+ sfree(c);
+ }
}
- if (!strcmp(buffer, "Session"))
- create_controls(hwnd, dlgtype, sessionpanelstart);
- if (!strcmp(buffer, "Logging"))
- create_controls(hwnd, dlgtype, loggingpanelstart);
- if (!strcmp(buffer, "Keyboard"))
- create_controls(hwnd, dlgtype, keyboardpanelstart);
- if (!strcmp(buffer, "Terminal"))
- create_controls(hwnd, dlgtype, terminalpanelstart);
- if (!strcmp(buffer, "Bell"))
- create_controls(hwnd, dlgtype, bellpanelstart);
- if (!strcmp(buffer, "Features"))
- create_controls(hwnd, dlgtype, featurespanelstart);
- if (!strcmp(buffer, "Window"))
- create_controls(hwnd, dlgtype, windowpanelstart);
- if (!strcmp(buffer, "Appearance"))
- create_controls(hwnd, dlgtype, appearancepanelstart);
- if (!strcmp(buffer, "Behaviour"))
- create_controls(hwnd, dlgtype, behaviourpanelstart);
- if (!strcmp(buffer, "Tunnels"))
- create_controls(hwnd, dlgtype, tunnelspanelstart);
- if (!strcmp(buffer, "Connection"))
- create_controls(hwnd, dlgtype, connectionpanelstart);
- if (!strcmp(buffer, "Proxy"))
- create_controls(hwnd, dlgtype, proxypanelstart);
- if (!strcmp(buffer, "Telnet"))
- create_controls(hwnd, dlgtype, telnetpanelstart);
- if (!strcmp(buffer, "Rlogin"))
- create_controls(hwnd, dlgtype, rloginpanelstart);
- if (!strcmp(buffer, "SSH"))
- create_controls(hwnd, dlgtype, sshpanelstart);
- if (!strcmp(buffer, "Auth"))
- create_controls(hwnd, dlgtype, sshauthpanelstart);
- if (!strcmp(buffer, "Bugs"))
- create_controls(hwnd, dlgtype, sshbugspanelstart);
- if (!strcmp(buffer, "Selection"))
- create_controls(hwnd, dlgtype, selectionpanelstart);
- if (!strcmp(buffer, "Colours"))
- create_controls(hwnd, dlgtype, colourspanelstart);
- if (!strcmp(buffer, "Translation"))
- create_controls(hwnd, dlgtype, translationpanelstart);
-
- init_dlg_ctrls(hwnd, FALSE);
+ create_controls(hwnd, (char *)item.lParam);
+
+ dlg_refresh(NULL, &dp); /* set up control values */
SendMessage (hwnd, WM_SETREDRAW, TRUE, 0);
InvalidateRect (hwnd, NULL, TRUE);
}
break;
case WM_COMMAND:
+ case WM_DRAWITEM:
+ default: /* also handle drag list msg here */
/*
* Only process WM_COMMAND once the dialog is fully formed.
*/
- if (GetWindowLong(hwnd, GWL_USERDATA) == 1)
- switch (LOWORD(wParam)) {
- case IDOK:
- /* Behaviour of the "Open" button is different if the
- * session list has focus, *unless* the user just
- * double-clicked... */
- if (sesslist_has_focus && !readytogo) {
- if (!load_selected_session(hwnd)) {
- MessageBeep(0);
- return 0;
- }
- }
- /* If at this point we have a valid session, go! */
- if (*cfg.host) {
- if (requested_help) {
- WinHelp(hwnd, help_path, HELP_QUIT, 0);
- requested_help = FALSE;
- }
- EndDialog(hwnd, 1);
- } else
- MessageBeep(0);
- return 0;
- case IDC_HELPBTN:
- if (HIWORD(wParam) == BN_CLICKED ||
- HIWORD(wParam) == BN_DOUBLECLICKED) {
- if (help_path) {
- WinHelp(hwnd, help_path,
- help_has_contents ? HELP_FINDER : HELP_CONTENTS,
- 0);
- requested_help = TRUE;
- }
- }
- break;
- case IDCANCEL:
- if (requested_help) {
- WinHelp(hwnd, help_path, HELP_QUIT, 0);
- requested_help = FALSE;
- }
- EndDialog(hwnd, 0);
- return 0;
- case IDC_PROTTELNET:
- case IDC_PROTRLOGIN:
- case IDC_PROTSSH:
- case IDC_PROTRAW:
- if (HIWORD(wParam) == BN_CLICKED ||
- HIWORD(wParam) == BN_DOUBLECLICKED) {
- int i = IsDlgButtonChecked(hwnd, IDC_PROTSSH);
- int j = IsDlgButtonChecked(hwnd, IDC_PROTTELNET);
- int k = IsDlgButtonChecked(hwnd, IDC_PROTRLOGIN);
- cfg.protocol =
- i ? PROT_SSH : j ? PROT_TELNET : k ? PROT_RLOGIN :
- PROT_RAW;
- /*
- * When switching using the arrow keys, we
- * appear to get two of these messages, both
- * mentioning the target button in
- * LOWORD(wParam), but one of them called while
- * the previous button is still checked. This
- * causes an unnecessary reset of the port
- * number field, which we fix by ensuring here
- * that the button selected is indeed the one
- * checked.
- */
- if (IsDlgButtonChecked(hwnd, LOWORD(wParam)) &&
- ((cfg.protocol == PROT_SSH && cfg.port != 22)
- || (cfg.protocol == PROT_TELNET && cfg.port != 23)
- || (cfg.protocol == PROT_RLOGIN
- && cfg.port != 513))) {
- cfg.port = i ? 22 : j ? 23 : 513;
- SetDlgItemInt(hwnd, IDC_PORT, cfg.port, FALSE);
- }
- }
- break;
- case IDC_HOST:
- if (HIWORD(wParam) == EN_CHANGE)
- GetDlgItemText(hwnd, IDC_HOST, cfg.host,
- sizeof(cfg.host) - 1);
- break;
- case IDC_PORT:
- if (HIWORD(wParam) == EN_CHANGE) {
- GetDlgItemText(hwnd, IDC_PORT, portname, 31);
- if (isdigit(portname[0]))
- MyGetDlgItemInt(hwnd, IDC_PORT, &cfg.port);
- else {
- service = getservbyname(portname, NULL);
- if (service)
- cfg.port = ntohs(service->s_port);
- else
- cfg.port = 0;
- }
- }
- break;
- case IDC_SESSEDIT:
- if (HIWORD(wParam) == EN_CHANGE) {
- SendDlgItemMessage(hwnd, IDC_SESSLIST, LB_SETCURSEL,
- (WPARAM) - 1, 0);
- GetDlgItemText(hwnd, IDC_SESSEDIT,
- savedsession, sizeof(savedsession) - 1);
- savedsession[sizeof(savedsession) - 1] = '\0';
- }
- break;
- case IDC_SESSSAVE:
- if (HIWORD(wParam) == BN_CLICKED ||
- HIWORD(wParam) == BN_DOUBLECLICKED) {
- /*
- * Save a session
- */
- char str[2048];
- GetDlgItemText(hwnd, IDC_SESSEDIT, str,
- sizeof(str) - 1);
- if (!*str) {
- int n = SendDlgItemMessage(hwnd, IDC_SESSLIST,
- LB_GETCURSEL, 0, 0);
- if (n == LB_ERR) {
- MessageBeep(0);
- break;
- }
- strcpy(str, sesslist.sessions[n]);
- }
- save_settings(str, !!strcmp(str, "Default Settings"),
- &cfg);
- get_sesslist(&sesslist, FALSE);
- get_sesslist(&sesslist, TRUE);
- SendDlgItemMessage(hwnd, IDC_SESSLIST, WM_SETREDRAW,
- FALSE, 0);
- SendDlgItemMessage(hwnd, IDC_SESSLIST, LB_RESETCONTENT,
- 0, 0);
- for (i = 0; i < sesslist.nsessions; i++)
- SendDlgItemMessage(hwnd, IDC_SESSLIST,
- LB_ADDSTRING, 0,
- (LPARAM) (sesslist.sessions[i]));
- SendDlgItemMessage(hwnd, IDC_SESSLIST, LB_SETCURSEL,
- (WPARAM) - 1, 0);
- SendDlgItemMessage(hwnd, IDC_SESSLIST, WM_SETREDRAW,
- TRUE, 0);
- InvalidateRect(GetDlgItem(hwnd, IDC_SESSLIST), NULL,
- TRUE);
- }
- break;
- case IDC_SESSLIST:
- case IDC_SESSLOAD:
- if (LOWORD(wParam) == IDC_SESSLIST) {
- if (HIWORD(wParam) == LBN_SETFOCUS)
- sesslist_has_focus = 1;
- else if (HIWORD(wParam) == LBN_KILLFOCUS)
- sesslist_has_focus = 0;
- }
- if (LOWORD(wParam) == IDC_SESSLOAD &&
- HIWORD(wParam) != BN_CLICKED &&
- HIWORD(wParam) != BN_DOUBLECLICKED) break;
- if (LOWORD(wParam) == IDC_SESSLIST &&
- HIWORD(wParam) != LBN_DBLCLK) break;
- /* Load the session selected in SESSLIST. */
- if (load_selected_session(hwnd) &&
- LOWORD(wParam) == IDC_SESSLIST) {
- /*
- * A double-click on a saved session should
- * actually start the session, not just load it.
- * Unless it's Default Settings or some other
- * host-less set of saved settings.
- */
- if (*cfg.host) {
- readytogo = TRUE;
- SetCapture(hwnd);
- }
- }
- break;
- case IDC_SESSDEL:
- if (HIWORD(wParam) == BN_CLICKED ||
- HIWORD(wParam) == BN_DOUBLECLICKED) {
- int n = SendDlgItemMessage(hwnd, IDC_SESSLIST,
- LB_GETCURSEL, 0, 0);
- if (n == LB_ERR || n == 0) {
- MessageBeep(0);
- break;
- }
- del_settings(sesslist.sessions[n]);
- get_sesslist(&sesslist, FALSE);
- get_sesslist(&sesslist, TRUE);
- SendDlgItemMessage(hwnd, IDC_SESSLIST, WM_SETREDRAW,
- FALSE, 0);
- SendDlgItemMessage(hwnd, IDC_SESSLIST, LB_RESETCONTENT,
- 0, 0);
- for (i = 0; i < sesslist.nsessions; i++)
- SendDlgItemMessage(hwnd, IDC_SESSLIST,
- LB_ADDSTRING, 0,
- (LPARAM) (sesslist.sessions[i]));
- SendDlgItemMessage(hwnd, IDC_SESSLIST, LB_SETCURSEL,
- (WPARAM) - 1, 0);
- SendDlgItemMessage(hwnd, IDC_SESSLIST, WM_SETREDRAW,
- TRUE, 0);
- InvalidateRect(GetDlgItem(hwnd, IDC_SESSLIST), NULL,
- TRUE);
- }
- case IDC_PINGEDIT:
- if (HIWORD(wParam) == EN_CHANGE)
- MyGetDlgItemInt(hwnd, IDC_PINGEDIT,
- &cfg.ping_interval);
- break;
- case IDC_NODELAY:
- if (HIWORD(wParam) == BN_CLICKED ||
- HIWORD(wParam) == BN_DOUBLECLICKED)
- cfg.tcp_nodelay =
- IsDlgButtonChecked(hwnd, IDC_NODELAY);
- break;
- case IDC_DEL008:
- case IDC_DEL127:
- if (HIWORD(wParam) == BN_CLICKED ||
- HIWORD(wParam) == BN_DOUBLECLICKED)
- cfg.bksp_is_delete =
- IsDlgButtonChecked(hwnd, IDC_DEL127);
- break;
- case IDC_HOMETILDE:
- case IDC_HOMERXVT:
- if (HIWORD(wParam) == BN_CLICKED ||
- HIWORD(wParam) == BN_DOUBLECLICKED)
- cfg.rxvt_homeend =
- IsDlgButtonChecked(hwnd, IDC_HOMERXVT);
- break;
- case IDC_FUNCTILDE:
- case IDC_FUNCLINUX:
- case IDC_FUNCXTERM:
- case IDC_FUNCVT400:
- case IDC_FUNCVT100P:
- case IDC_FUNCSCO:
- if (HIWORD(wParam) == BN_CLICKED ||
- HIWORD(wParam) == BN_DOUBLECLICKED)
- switch (LOWORD(wParam)) {
- case IDC_FUNCTILDE:
- cfg.funky_type = 0;
- break;
- case IDC_FUNCLINUX:
- cfg.funky_type = 1;
- break;
- case IDC_FUNCXTERM:
- cfg.funky_type = 2;
- break;
- case IDC_FUNCVT400:
- cfg.funky_type = 3;
- break;
- case IDC_FUNCVT100P:
- cfg.funky_type = 4;
- break;
- case IDC_FUNCSCO:
- cfg.funky_type = 5;
- break;
- }
- break;
- case IDC_KPNORMAL:
- case IDC_KPAPPLIC:
- if (HIWORD(wParam) == BN_CLICKED ||
- HIWORD(wParam) == BN_DOUBLECLICKED) {
- cfg.app_keypad =
- IsDlgButtonChecked(hwnd, IDC_KPAPPLIC);
- cfg.nethack_keypad = FALSE;
- }
- break;
- case IDC_KPNH:
- if (HIWORD(wParam) == BN_CLICKED ||
- HIWORD(wParam) == BN_DOUBLECLICKED) {
- cfg.app_keypad = FALSE;
- cfg.nethack_keypad = TRUE;
- }
- break;
- case IDC_CURNORMAL:
- case IDC_CURAPPLIC:
- if (HIWORD(wParam) == BN_CLICKED ||
- HIWORD(wParam) == BN_DOUBLECLICKED)
- cfg.app_cursor =
- IsDlgButtonChecked(hwnd, IDC_CURAPPLIC);
- break;
- case IDC_NOAPPLICC:
- if (HIWORD(wParam) == BN_CLICKED ||
- HIWORD(wParam) == BN_DOUBLECLICKED)
- cfg.no_applic_c =
- IsDlgButtonChecked(hwnd, IDC_NOAPPLICC);
- break;
- case IDC_NOAPPLICK:
- if (HIWORD(wParam) == BN_CLICKED ||
- HIWORD(wParam) == BN_DOUBLECLICKED)
- cfg.no_applic_k =
- IsDlgButtonChecked(hwnd, IDC_NOAPPLICK);
- break;
- case IDC_NOMOUSEREP:
- if (HIWORD(wParam) == BN_CLICKED ||
- HIWORD(wParam) == BN_DOUBLECLICKED)
- cfg.no_mouse_rep =
- IsDlgButtonChecked(hwnd, IDC_NOMOUSEREP);
- break;
- case IDC_NORESIZE:
- if (HIWORD(wParam) == BN_CLICKED ||
- HIWORD(wParam) == BN_DOUBLECLICKED)
- cfg.no_remote_resize =
- IsDlgButtonChecked(hwnd, IDC_NORESIZE);
- break;
- case IDC_NOALTSCREEN:
- if (HIWORD(wParam) == BN_CLICKED ||
- HIWORD(wParam) == BN_DOUBLECLICKED)
- cfg.no_alt_screen =
- IsDlgButtonChecked(hwnd, IDC_NOALTSCREEN);
- break;
- case IDC_NOWINTITLE:
- if (HIWORD(wParam) == BN_CLICKED ||
- HIWORD(wParam) == BN_DOUBLECLICKED)
- cfg.no_remote_wintitle =
- IsDlgButtonChecked(hwnd, IDC_NOWINTITLE);
- break;
- case IDC_NODBACKSPACE:
- if (HIWORD(wParam) == BN_CLICKED ||
- HIWORD(wParam) == BN_DOUBLECLICKED)
- cfg.no_dbackspace =
- IsDlgButtonChecked(hwnd, IDC_NODBACKSPACE);
- break;
- case IDC_NOCHARSET:
- if (HIWORD(wParam) == BN_CLICKED ||
- HIWORD(wParam) == BN_DOUBLECLICKED)
- cfg.no_remote_charset =
- IsDlgButtonChecked(hwnd, IDC_NOCHARSET);
- break;
- case IDC_ALTF4:
- if (HIWORD(wParam) == BN_CLICKED ||
- HIWORD(wParam) == BN_DOUBLECLICKED)
- cfg.alt_f4 = IsDlgButtonChecked(hwnd, IDC_ALTF4);
- break;
- case IDC_ALTSPACE:
- if (HIWORD(wParam) == BN_CLICKED ||
- HIWORD(wParam) == BN_DOUBLECLICKED)
- cfg.alt_space =
- IsDlgButtonChecked(hwnd, IDC_ALTSPACE);
- break;
- case IDC_ALTONLY:
- if (HIWORD(wParam) == BN_CLICKED ||
- HIWORD(wParam) == BN_DOUBLECLICKED)
- cfg.alt_only =
- IsDlgButtonChecked(hwnd, IDC_ALTONLY);
- break;
- case IDC_ECHOBACKEND:
- case IDC_ECHOYES:
- case IDC_ECHONO:
- if (HIWORD(wParam) == BN_CLICKED ||
- HIWORD(wParam) == BN_DOUBLECLICKED) {
- if (LOWORD(wParam) == IDC_ECHOBACKEND)
- cfg.localecho = AUTO;
- if (LOWORD(wParam) == IDC_ECHOYES)
- cfg.localecho = FORCE_ON;
- if (LOWORD(wParam) == IDC_ECHONO)
- cfg.localecho = FORCE_OFF;
- }
- break;
- case IDC_EDITBACKEND:
- case IDC_EDITYES:
- case IDC_EDITNO:
- if (HIWORD(wParam) == BN_CLICKED ||
- HIWORD(wParam) == BN_DOUBLECLICKED) {
- if (LOWORD(wParam) == IDC_EDITBACKEND)
- cfg.localedit = AUTO;
- if (LOWORD(wParam) == IDC_EDITYES)
- cfg.localedit = FORCE_ON;
- if (LOWORD(wParam) == IDC_EDITNO)
- cfg.localedit = FORCE_OFF;
- }
- break;
- case IDC_ANSWEREDIT:
- if (HIWORD(wParam) == EN_CHANGE)
- GetDlgItemText(hwnd, IDC_ANSWEREDIT, cfg.answerback,
- sizeof(cfg.answerback) - 1);
- break;
- case IDC_ALWAYSONTOP:
- if (HIWORD(wParam) == BN_CLICKED ||
- HIWORD(wParam) == BN_DOUBLECLICKED)
- cfg.alwaysontop =
- IsDlgButtonChecked(hwnd, IDC_ALWAYSONTOP);
- break;
- case IDC_FULLSCREENONALTENTER:
- if (HIWORD(wParam) == BN_CLICKED ||
- HIWORD(wParam) == BN_DOUBLECLICKED)
- cfg.fullscreenonaltenter =
- IsDlgButtonChecked(hwnd, IDC_FULLSCREENONALTENTER);
- break;
- case IDC_SCROLLKEY:
- if (HIWORD(wParam) == BN_CLICKED ||
- HIWORD(wParam) == BN_DOUBLECLICKED)
- cfg.scroll_on_key =
- IsDlgButtonChecked(hwnd, IDC_SCROLLKEY);
- break;
- case IDC_SCROLLDISP:
- if (HIWORD(wParam) == BN_CLICKED ||
- HIWORD(wParam) == BN_DOUBLECLICKED)
- cfg.scroll_on_disp =
- IsDlgButtonChecked(hwnd, IDC_SCROLLDISP);
- break;
- case IDC_COMPOSEKEY:
- if (HIWORD(wParam) == BN_CLICKED ||
- HIWORD(wParam) == BN_DOUBLECLICKED)
- cfg.compose_key =
- IsDlgButtonChecked(hwnd, IDC_COMPOSEKEY);
- break;
- case IDC_CTRLALTKEYS:
- if (HIWORD(wParam) == BN_CLICKED ||
- HIWORD(wParam) == BN_DOUBLECLICKED)
- cfg.ctrlaltkeys =
- IsDlgButtonChecked(hwnd, IDC_CTRLALTKEYS);
- break;
- case IDC_TELNETKEY:
- if (HIWORD(wParam) == BN_CLICKED ||
- HIWORD(wParam) == BN_DOUBLECLICKED)
- cfg.telnet_keyboard =
- IsDlgButtonChecked(hwnd, IDC_TELNETKEY);
- break;
- case IDC_TELNETRET:
- if (HIWORD(wParam) == BN_CLICKED ||
- HIWORD(wParam) == BN_DOUBLECLICKED)
- cfg.telnet_newline =
- IsDlgButtonChecked(hwnd, IDC_TELNETRET);
- break;
- case IDC_WRAPMODE:
- if (HIWORD(wParam) == BN_CLICKED ||
- HIWORD(wParam) == BN_DOUBLECLICKED)
- cfg.wrap_mode =
- IsDlgButtonChecked(hwnd, IDC_WRAPMODE);
- break;
- case IDC_DECOM:
- if (HIWORD(wParam) == BN_CLICKED ||
- HIWORD(wParam) == BN_DOUBLECLICKED)
- cfg.dec_om = IsDlgButtonChecked(hwnd, IDC_DECOM);
- break;
- case IDC_LFHASCR:
- if (HIWORD(wParam) == BN_CLICKED ||
- HIWORD(wParam) == BN_DOUBLECLICKED)
- cfg.lfhascr =
- IsDlgButtonChecked(hwnd, IDC_LFHASCR);
- break;
- case IDC_ROWSEDIT:
- if (HIWORD(wParam) == EN_CHANGE)
- MyGetDlgItemInt(hwnd, IDC_ROWSEDIT, &cfg.height);
- break;
- case IDC_COLSEDIT:
- if (HIWORD(wParam) == EN_CHANGE)
- MyGetDlgItemInt(hwnd, IDC_COLSEDIT, &cfg.width);
- break;
- case IDC_SAVEEDIT:
- if (HIWORD(wParam) == EN_CHANGE)
- MyGetDlgItemInt(hwnd, IDC_SAVEEDIT, &cfg.savelines);
- break;
- case IDC_CHOOSEFONT:
- {
- HDC hdc = GetDC(0);
- lf.lfHeight = -MulDiv(cfg.font.height,
- GetDeviceCaps(hdc, LOGPIXELSY),
- 72);
- ReleaseDC(0, hdc);
- }
- lf.lfWidth = lf.lfEscapement = lf.lfOrientation = 0;
- lf.lfItalic = lf.lfUnderline = lf.lfStrikeOut = 0;
- lf.lfWeight = (cfg.font.isbold ? FW_BOLD : 0);
- lf.lfCharSet = cfg.font.charset;
- lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
- lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
- lf.lfQuality = DEFAULT_QUALITY;
- lf.lfPitchAndFamily = FIXED_PITCH | FF_DONTCARE;
- strncpy(lf.lfFaceName, cfg.font.name,
- sizeof(lf.lfFaceName) - 1);
- lf.lfFaceName[sizeof(lf.lfFaceName) - 1] = '\0';
-
- cf.lStructSize = sizeof(cf);
- cf.hwndOwner = hwnd;
- cf.lpLogFont = &lf;
- cf.Flags = CF_FIXEDPITCHONLY | CF_FORCEFONTEXIST |
- CF_INITTOLOGFONTSTRUCT | CF_SCREENFONTS;
-
- if (ChooseFont(&cf)) {
- strncpy(cfg.font.name, lf.lfFaceName,
- sizeof(cfg.font.name) - 1);
- cfg.font.name[sizeof(cfg.font.name) - 1] = '\0';
- cfg.font.isbold = (lf.lfWeight == FW_BOLD);
- cfg.font.charset = lf.lfCharSet;
- cfg.font.height = cf.iPointSize / 10;
- fmtfont(fontstatic);
- SetDlgItemText(hwnd, IDC_FONTSTATIC, fontstatic);
- }
- break;
- case IDC_BELL_DISABLED:
- case IDC_BELL_DEFAULT:
- case IDC_BELL_WAVEFILE:
- case IDC_BELL_VISUAL:
- if (HIWORD(wParam) == BN_CLICKED ||
- HIWORD(wParam) == BN_DOUBLECLICKED) {
- if (LOWORD(wParam) == IDC_BELL_DISABLED)
- cfg.beep = BELL_DISABLED;
- if (LOWORD(wParam) == IDC_BELL_DEFAULT)
- cfg.beep = BELL_DEFAULT;
- if (LOWORD(wParam) == IDC_BELL_WAVEFILE)
- cfg.beep = BELL_WAVEFILE;
- if (LOWORD(wParam) == IDC_BELL_VISUAL)
- cfg.beep = BELL_VISUAL;
- }
- break;
- case IDC_B_IND_DISABLED:
- case IDC_B_IND_FLASH:
- case IDC_B_IND_STEADY:
- if (HIWORD(wParam) == BN_CLICKED ||
- HIWORD(wParam) == BN_DOUBLECLICKED) {
- if (LOWORD(wParam) == IDC_B_IND_DISABLED)
- cfg.beep_ind = B_IND_DISABLED;
- if (LOWORD(wParam) == IDC_B_IND_FLASH)
- cfg.beep_ind = B_IND_FLASH;
- if (LOWORD(wParam) == IDC_B_IND_STEADY)
- cfg.beep_ind = B_IND_STEADY;
- }
- break;
- case IDC_BELL_WAVEBROWSE:
- memset(&of, 0, sizeof(of));
-#ifdef OPENFILENAME_SIZE_VERSION_400
- of.lStructSize = OPENFILENAME_SIZE_VERSION_400;
-#else
- of.lStructSize = sizeof(of);
-#endif
- of.hwndOwner = hwnd;
- of.lpstrFilter = "Wave Files (*.wav)\0*.WAV\0"
- "All Files (*.*)\0*\0\0\0";
- of.lpstrCustomFilter = NULL;
- of.nFilterIndex = 1;
- of.lpstrFile = filename;
- strcpy(filename, cfg.bell_wavefile.path);
- of.nMaxFile = sizeof(filename);
- of.lpstrFileTitle = NULL;
- of.lpstrInitialDir = NULL;
- of.lpstrTitle = "Select Bell Sound File";
- of.Flags = 0;
- if (GetOpenFileName(&of)) {
- strcpy(cfg.bell_wavefile.path, filename);
- SetDlgItemText(hwnd, IDC_BELL_WAVEEDIT,
- cfg.bell_wavefile.path);
- }
- break;
- case IDC_BELL_WAVEEDIT:
- if (HIWORD(wParam) == EN_CHANGE)
- GetDlgItemText(hwnd, IDC_BELL_WAVEEDIT,
- cfg.bell_wavefile.path,
- sizeof(cfg.bell_wavefile.path) - 1);
- break;
- case IDC_BELLOVL:
- if (HIWORD(wParam) == BN_CLICKED ||
- HIWORD(wParam) == BN_DOUBLECLICKED)
- cfg.bellovl =
- IsDlgButtonChecked(hwnd, IDC_BELLOVL);
- break;
- case IDC_BELLOVLN:
- if (HIWORD(wParam) == EN_CHANGE)
- MyGetDlgItemInt(hwnd, IDC_BELLOVLN, &cfg.bellovl_n);
- break;
- case IDC_BELLOVLT:
- if (HIWORD(wParam) == EN_CHANGE)
- MyGetDlgItemFlt(hwnd, IDC_BELLOVLT, &cfg.bellovl_t,
- 1000);
- break;
- case IDC_BELLOVLS:
- if (HIWORD(wParam) == EN_CHANGE)
- MyGetDlgItemFlt(hwnd, IDC_BELLOVLS, &cfg.bellovl_s,
- 1000);
- break;
- case IDC_BLINKTEXT:
- if (HIWORD(wParam) == BN_CLICKED ||
- HIWORD(wParam) == BN_DOUBLECLICKED)
- cfg.blinktext =
- IsDlgButtonChecked(hwnd, IDC_BLINKTEXT);
- break;
- case IDC_BCE:
- if (HIWORD(wParam) == BN_CLICKED ||
- HIWORD(wParam) == BN_DOUBLECLICKED)
- cfg.bce = IsDlgButtonChecked(hwnd, IDC_BCE);
- break;
- case IDC_WINNAME:
- if (HIWORD(wParam) == BN_CLICKED ||
- HIWORD(wParam) == BN_DOUBLECLICKED)
- cfg.win_name_always =
- !IsDlgButtonChecked(hwnd, IDC_WINNAME);
- break;
- case IDC_HIDEMOUSE:
- if (HIWORD(wParam) == BN_CLICKED ||
- HIWORD(wParam) == BN_DOUBLECLICKED)
- cfg.hide_mouseptr =
- IsDlgButtonChecked(hwnd, IDC_HIDEMOUSE);
- break;
- case IDC_SUNKENEDGE:
- if (HIWORD(wParam) == BN_CLICKED ||
- HIWORD(wParam) == BN_DOUBLECLICKED)
- cfg.sunken_edge =
- IsDlgButtonChecked(hwnd, IDC_SUNKENEDGE);
- break;
- case IDC_WINBEDIT:
- if (HIWORD(wParam) == EN_CHANGE)
- MyGetDlgItemInt(hwnd, IDC_WINBEDIT,
- &cfg.window_border);
- if (cfg.window_border > 32)
- cfg.window_border = 32;
- break;
- case IDC_CURBLOCK:
- if (HIWORD(wParam) == BN_CLICKED ||
- HIWORD(wParam) == BN_DOUBLECLICKED)
- cfg.cursor_type = 0;
- break;
- case IDC_CURUNDER:
- if (HIWORD(wParam) == BN_CLICKED ||
- HIWORD(wParam) == BN_DOUBLECLICKED)
- cfg.cursor_type = 1;
- break;
- case IDC_CURVERT:
- if (HIWORD(wParam) == BN_CLICKED ||
- HIWORD(wParam) == BN_DOUBLECLICKED)
- cfg.cursor_type = 2;
- break;
- case IDC_BLINKCUR:
- if (HIWORD(wParam) == BN_CLICKED ||
- HIWORD(wParam) == BN_DOUBLECLICKED)
- cfg.blink_cur =
- IsDlgButtonChecked(hwnd, IDC_BLINKCUR);
- break;
- case IDC_SCROLLBAR:
- if (HIWORD(wParam) == BN_CLICKED ||
- HIWORD(wParam) == BN_DOUBLECLICKED)
- cfg.scrollbar =
- IsDlgButtonChecked(hwnd, IDC_SCROLLBAR);
- break;
- case IDC_SCROLLBARFULLSCREEN:
- if (HIWORD(wParam) == BN_CLICKED ||
- HIWORD(wParam) == BN_DOUBLECLICKED)
- cfg.scrollbar_in_fullscreen =
- IsDlgButtonChecked(hwnd, IDC_SCROLLBARFULLSCREEN);
- break;
- case IDC_RESIZETERM:
- case IDC_RESIZEFONT:
- case IDC_RESIZENONE:
- case IDC_RESIZEEITHER:
- if (HIWORD(wParam) == BN_CLICKED ||
- HIWORD(wParam) == BN_DOUBLECLICKED) {
- cfg.resize_action =
- IsDlgButtonChecked(hwnd,
- IDC_RESIZETERM) ? RESIZE_TERM :
- IsDlgButtonChecked(hwnd,
- IDC_RESIZEFONT) ? RESIZE_FONT :
- IsDlgButtonChecked(hwnd,
- IDC_RESIZEEITHER) ? RESIZE_EITHER :
- RESIZE_DISABLED;
- }
- break;
- case IDC_WINEDIT:
- if (HIWORD(wParam) == EN_CHANGE)
- GetDlgItemText(hwnd, IDC_WINEDIT, cfg.wintitle,
- sizeof(cfg.wintitle) - 1);
- break;
- case IDC_COEALWAYS:
- case IDC_COENEVER:
- case IDC_COENORMAL:
- if (HIWORD(wParam) == BN_CLICKED ||
- HIWORD(wParam) == BN_DOUBLECLICKED) {
- cfg.close_on_exit =
- IsDlgButtonChecked(hwnd,
- IDC_COEALWAYS) ? FORCE_ON :
- IsDlgButtonChecked(hwnd,
- IDC_COENEVER) ? FORCE_OFF :
- AUTO;
- }
- break;
- case IDC_CLOSEWARN:
- if (HIWORD(wParam) == BN_CLICKED ||
- HIWORD(wParam) == BN_DOUBLECLICKED)
- cfg.warn_on_close =
- IsDlgButtonChecked(hwnd, IDC_CLOSEWARN);
- break;
- case IDC_TTEDIT:
- if (HIWORD(wParam) == EN_CHANGE)
- GetDlgItemText(hwnd, IDC_TTEDIT, cfg.termtype,
- sizeof(cfg.termtype) - 1);
- break;
-
- /* proxy config */
- case IDC_PROXYHOSTEDIT:
- if (HIWORD(wParam) == EN_CHANGE)
- GetDlgItemText(hwnd, IDC_PROXYHOSTEDIT, cfg.proxy_host,
- sizeof(cfg.proxy_host) - 1);
- break;
- case IDC_PROXYPORTEDIT:
- if (HIWORD(wParam) == EN_CHANGE) {
- GetDlgItemText(hwnd, IDC_PROXYPORTEDIT, portname, 31);
- if (isdigit(portname[0]))
- MyGetDlgItemInt(hwnd, IDC_PROXYPORTEDIT, &cfg.proxy_port);
- else {
- service = getservbyname(portname, NULL);
- if (service)
- cfg.proxy_port = ntohs(service->s_port);
- else
- cfg.proxy_port = 0;
- }
- }
- break;
- case IDC_PROXYEXCLUDEEDIT:
- if (HIWORD(wParam) == EN_CHANGE)
- GetDlgItemText(hwnd, IDC_PROXYEXCLUDEEDIT,
- cfg.proxy_exclude_list,
- sizeof(cfg.proxy_exclude_list) - 1);
- break;
- case IDC_PROXYUSEREDIT:
- if (HIWORD(wParam) == EN_CHANGE)
- GetDlgItemText(hwnd, IDC_PROXYUSEREDIT,
- cfg.proxy_username,
- sizeof(cfg.proxy_username) - 1);
- break;
- case IDC_PROXYPASSEDIT:
- if (HIWORD(wParam) == EN_CHANGE)
- GetDlgItemText(hwnd, IDC_PROXYPASSEDIT,
- cfg.proxy_password,
- sizeof(cfg.proxy_password) - 1);
- break;
- case IDC_PROXYTELNETCMDEDIT:
- if (HIWORD(wParam) == EN_CHANGE)
- GetDlgItemText(hwnd, IDC_PROXYTELNETCMDEDIT,
- cfg.proxy_telnet_command,
- sizeof(cfg.proxy_telnet_command) - 1);
- break;
- case IDC_PROXYSOCKSVER5:
- case IDC_PROXYSOCKSVER4:
- if (HIWORD(wParam) == BN_CLICKED ||
- HIWORD(wParam) == BN_DOUBLECLICKED) {
- cfg.proxy_socks_version =
- IsDlgButtonChecked(hwnd, IDC_PROXYSOCKSVER4) ? 4 : 5;
- }
- break;
- case IDC_PROXYLOCALHOST:
- if (HIWORD(wParam) == BN_CLICKED ||
- HIWORD(wParam) == BN_DOUBLECLICKED)
- cfg.even_proxy_localhost =
- IsDlgButtonChecked(hwnd, IDC_PROXYLOCALHOST);
- break;
- case IDC_PROXYDNSNO:
- case IDC_PROXYDNSAUTO:
- case IDC_PROXYDNSYES:
- if (HIWORD(wParam) == BN_CLICKED ||
- HIWORD(wParam) == BN_DOUBLECLICKED) {
- cfg.proxy_dns =
- IsDlgButtonChecked(hwnd, IDC_PROXYDNSNO) ? FORCE_OFF :
- IsDlgButtonChecked(hwnd, IDC_PROXYDNSYES) ? FORCE_ON :
- AUTO;
- }
- break;
- case IDC_PROXYTYPENONE:
- case IDC_PROXYTYPEHTTP:
- case IDC_PROXYTYPESOCKS:
- case IDC_PROXYTYPETELNET:
- if (HIWORD(wParam) == BN_CLICKED ||
- HIWORD(wParam) == BN_DOUBLECLICKED) {
- cfg.proxy_type =
- IsDlgButtonChecked(hwnd, IDC_PROXYTYPEHTTP) ? PROXY_HTTP :
- IsDlgButtonChecked(hwnd, IDC_PROXYTYPESOCKS) ? PROXY_SOCKS :
- IsDlgButtonChecked(hwnd, IDC_PROXYTYPETELNET) ? PROXY_TELNET :
- PROXY_NONE;
- }
- break;
-
- case IDC_LGFEDIT:
- if (HIWORD(wParam) == EN_CHANGE)
- GetDlgItemText(hwnd, IDC_LGFEDIT, cfg.logfilename.path,
- sizeof(cfg.logfilename.path) - 1);
- break;
- case IDC_LGFBUTTON:
- memset(&of, 0, sizeof(of));
-#ifdef OPENFILENAME_SIZE_VERSION_400
- of.lStructSize = OPENFILENAME_SIZE_VERSION_400;
-#else
- of.lStructSize = sizeof(of);
-#endif
- of.hwndOwner = hwnd;
- of.lpstrFilter = "All Files (*.*)\0*\0\0\0";
- of.lpstrCustomFilter = NULL;
- of.nFilterIndex = 1;
- of.lpstrFile = filename;
- strcpy(filename, cfg.logfilename.path);
- of.nMaxFile = sizeof(filename);
- of.lpstrFileTitle = NULL;
- of.lpstrInitialDir = NULL;
- of.lpstrTitle = "Select session log file";
- of.Flags = 0;
- if (GetSaveFileName(&of)) {
- strcpy(cfg.logfilename.path, filename);
- SetDlgItemText(hwnd, IDC_LGFEDIT, cfg.logfilename.path);
- }
- break;
- case IDC_LSTATOFF:
- case IDC_LSTATASCII:
- case IDC_LSTATRAW:
- case IDC_LSTATPACKET:
- if (HIWORD(wParam) == BN_CLICKED ||
- HIWORD(wParam) == BN_DOUBLECLICKED) {
- if (IsDlgButtonChecked(hwnd, IDC_LSTATOFF))
- cfg.logtype = LGTYP_NONE;
- if (IsDlgButtonChecked(hwnd, IDC_LSTATASCII))
- cfg.logtype = LGTYP_ASCII;
- if (IsDlgButtonChecked(hwnd, IDC_LSTATRAW))
- cfg.logtype = LGTYP_DEBUG;
- if (IsDlgButtonChecked(hwnd, IDC_LSTATPACKET))
- cfg.logtype = LGTYP_PACKETS;
- }
- break;
- case IDC_LSTATXASK:
- case IDC_LSTATXAPN:
- case IDC_LSTATXOVR:
- if (HIWORD(wParam) == BN_CLICKED ||
- HIWORD(wParam) == BN_DOUBLECLICKED) {
- if (IsDlgButtonChecked(hwnd, IDC_LSTATXASK))
- cfg.logxfovr = LGXF_ASK;
- if (IsDlgButtonChecked(hwnd, IDC_LSTATXAPN))
- cfg.logxfovr = LGXF_APN;
- if (IsDlgButtonChecked(hwnd, IDC_LSTATXOVR))
- cfg.logxfovr = LGXF_OVR;
- }
- break;
- case IDC_TSEDIT:
- case IDC_R_TSEDIT:
- if (HIWORD(wParam) == EN_CHANGE)
- GetDlgItemText(hwnd, LOWORD(wParam), cfg.termspeed,
- sizeof(cfg.termspeed) - 1);
- break;
- case IDC_LOGEDIT:
- if (HIWORD(wParam) == EN_CHANGE)
- GetDlgItemText(hwnd, IDC_LOGEDIT, cfg.username,
- sizeof(cfg.username) - 1);
- break;
- case IDC_RLLUSEREDIT:
- if (HIWORD(wParam) == EN_CHANGE)
- GetDlgItemText(hwnd, IDC_RLLUSEREDIT,
- cfg.localusername,
- sizeof(cfg.localusername) - 1);
- break;
- case IDC_EMBSD:
- case IDC_EMRFC:
- cfg.rfc_environ = IsDlgButtonChecked(hwnd, IDC_EMRFC);
- break;
- case IDC_TPASSIVE:
- case IDC_TACTIVE:
- cfg.passive_telnet =
- IsDlgButtonChecked(hwnd, IDC_TPASSIVE);
- break;
- case IDC_ENVADD:
- if (HIWORD(wParam) == BN_CLICKED ||
- HIWORD(wParam) == BN_DOUBLECLICKED) {
- char str[sizeof(cfg.environmt)];
- char *p;
- GetDlgItemText(hwnd, IDC_VAREDIT, str,
- sizeof(str) - 1);
- if (!*str) {
- MessageBeep(0);
- break;
- }
- p = str + strlen(str);
- *p++ = '\t';
- GetDlgItemText(hwnd, IDC_VALEDIT, p,
- sizeof(str) - 1 - (p - str));
- if (!*p) {
- MessageBeep(0);
- break;
- }
- p = cfg.environmt;
- while (*p) {
- while (*p)
- p++;
- p++;
- }
- if ((p - cfg.environmt) + strlen(str) + 2 <
- sizeof(cfg.environmt)) {
- strcpy(p, str);
- p[strlen(str) + 1] = '\0';
- SendDlgItemMessage(hwnd, IDC_ENVLIST, LB_ADDSTRING,
- 0, (LPARAM) str);
- SetDlgItemText(hwnd, IDC_VAREDIT, "");
- SetDlgItemText(hwnd, IDC_VALEDIT, "");
- } else {
- MessageBox(hwnd, "Environment too big",
- "PuTTY Error", MB_OK | MB_ICONERROR);
- }
- }
- break;
- case IDC_ENVREMOVE:
- if (HIWORD(wParam) != BN_CLICKED &&
- HIWORD(wParam) != BN_DOUBLECLICKED) break;
- i =
- SendDlgItemMessage(hwnd, IDC_ENVLIST, LB_GETCURSEL, 0,
- 0);
- if (i == LB_ERR)
- MessageBeep(0);
- else {
- char *p, *q;
-
- SendDlgItemMessage(hwnd, IDC_ENVLIST, LB_DELETESTRING,
- i, 0);
- p = cfg.environmt;
- while (i > 0) {
- if (!*p)
- goto disaster;
- while (*p)
- p++;
- p++;
- i--;
- }
- q = p;
- if (!*p)
- goto disaster;
- while (*p)
- p++;
- p++;
- while (*p) {
- while (*p)
- *q++ = *p++;
- *q++ = *p++;
- }
- *q = '\0';
- disaster:;
- }
- break;
- case IDC_NOPTY:
- if (HIWORD(wParam) == BN_CLICKED ||
- HIWORD(wParam) == BN_DOUBLECLICKED)
- cfg.nopty = IsDlgButtonChecked(hwnd, IDC_NOPTY);
- break;
- case IDC_COMPRESS:
- if (HIWORD(wParam) == BN_CLICKED ||
- HIWORD(wParam) == BN_DOUBLECLICKED)
- cfg.compression =
- IsDlgButtonChecked(hwnd, IDC_COMPRESS);
- break;
- case IDC_SSH2DES:
- if (HIWORD(wParam) == BN_CLICKED ||
- HIWORD(wParam) == BN_DOUBLECLICKED)
- cfg.ssh2_des_cbc =
- IsDlgButtonChecked(hwnd, IDC_SSH2DES);
- break;
- case IDC_AGENTFWD:
- if (HIWORD(wParam) == BN_CLICKED ||
- HIWORD(wParam) == BN_DOUBLECLICKED)
- cfg.agentfwd =
- IsDlgButtonChecked(hwnd, IDC_AGENTFWD);
- break;
- case IDC_CHANGEUSER:
- if (HIWORD(wParam) == BN_CLICKED ||
- HIWORD(wParam) == BN_DOUBLECLICKED)
- cfg.change_username =
- IsDlgButtonChecked(hwnd, IDC_CHANGEUSER);
- break;
- case IDC_CIPHERLIST:
- case IDC_CIPHERUP:
- case IDC_CIPHERDN:
- handle_prefslist(&cipherlist,
- cfg.ssh_cipherlist, CIPHER_MAX,
- 0, hwnd, wParam, lParam);
- break;
- case IDC_SSHPROT1ONLY:
- case IDC_SSHPROT1:
- case IDC_SSHPROT2:
- case IDC_SSHPROT2ONLY:
- if (HIWORD(wParam) == BN_CLICKED ||
- HIWORD(wParam) == BN_DOUBLECLICKED) {
- if (IsDlgButtonChecked(hwnd, IDC_SSHPROT1ONLY))
- cfg.sshprot = 0;
- if (IsDlgButtonChecked(hwnd, IDC_SSHPROT1))
- cfg.sshprot = 1;
- else if (IsDlgButtonChecked(hwnd, IDC_SSHPROT2))
- cfg.sshprot = 2;
- else if (IsDlgButtonChecked(hwnd, IDC_SSHPROT2ONLY))
- cfg.sshprot = 3;
- }
- break;
- case IDC_AUTHTIS:
- if (HIWORD(wParam) == BN_CLICKED ||
- HIWORD(wParam) == BN_DOUBLECLICKED)
- cfg.try_tis_auth =
- IsDlgButtonChecked(hwnd, IDC_AUTHTIS);
- break;
- case IDC_AUTHKI:
- if (HIWORD(wParam) == BN_CLICKED ||
- HIWORD(wParam) == BN_DOUBLECLICKED)
- cfg.try_ki_auth =
- IsDlgButtonChecked(hwnd, IDC_AUTHKI);
- break;
- case IDC_PKEDIT:
- if (HIWORD(wParam) == EN_CHANGE)
- GetDlgItemText(hwnd, IDC_PKEDIT, cfg.keyfile.path,
- sizeof(cfg.keyfile.path) - 1);
- break;
- case IDC_CMDEDIT:
- if (HIWORD(wParam) == EN_CHANGE)
- GetDlgItemText(hwnd, IDC_CMDEDIT, cfg.remote_cmd,
- sizeof(cfg.remote_cmd) - 1);
- break;
- case IDC_PKBUTTON:
- memset(&of, 0, sizeof(of));
-#ifdef OPENFILENAME_SIZE_VERSION_400
- of.lStructSize = OPENFILENAME_SIZE_VERSION_400;
-#else
- of.lStructSize = sizeof(of);
-#endif
- of.hwndOwner = hwnd;
- of.lpstrFilter = "PuTTY Private Key Files (*.ppk)\0*.ppk\0"
- "All Files (*.*)\0*\0\0\0";
- of.lpstrCustomFilter = NULL;
- of.nFilterIndex = 1;
- of.lpstrFile = filename;
- strcpy(filename, cfg.keyfile.path);
- of.nMaxFile = sizeof(filename);
- of.lpstrFileTitle = NULL;
- of.lpstrInitialDir = NULL;
- of.lpstrTitle = "Select Private Key File";
- of.Flags = 0;
- if (GetOpenFileName(&of)) {
- strcpy(cfg.keyfile.path, filename);
- SetDlgItemText(hwnd, IDC_PKEDIT, cfg.keyfile.path);
- }
- break;
- case IDC_RAWCNP:
- cfg.rawcnp = IsDlgButtonChecked(hwnd, IDC_RAWCNP);
- break;
- case IDC_RTFPASTE:
- cfg.rtf_paste = IsDlgButtonChecked(hwnd, IDC_RTFPASTE);
- break;
- case IDC_MBWINDOWS:
- case IDC_MBXTERM:
- cfg.mouse_is_xterm = IsDlgButtonChecked(hwnd, IDC_MBXTERM);
- break;
- case IDC_SELTYPELEX:
- case IDC_SELTYPERECT:
- cfg.rect_select = IsDlgButtonChecked(hwnd, IDC_SELTYPERECT);
- break;
- case IDC_MOUSEOVERRIDE:
- cfg.mouse_override = IsDlgButtonChecked(hwnd, IDC_MOUSEOVERRIDE);
- break;
- case IDC_CCSET:
- {
- BOOL ok;
- int i;
- int n = GetDlgItemInt(hwnd, IDC_CCEDIT, &ok, FALSE);
-
- if (!ok)
- MessageBeep(0);
- else {
- for (i = 0; i < 128; i++)
- if (SendDlgItemMessage
- (hwnd, IDC_CCLIST, LB_GETSEL, i, 0)) {
- char str[100];
- cfg.wordness[i] = n;
- SendDlgItemMessage(hwnd, IDC_CCLIST,
- LB_DELETESTRING, i, 0);
- sprintf(str, "%d\t(0x%02X)\t%c\t%d", i, i,
- (i >= 0x21 && i != 0x7F) ? i : ' ',
- cfg.wordness[i]);
- SendDlgItemMessage(hwnd, IDC_CCLIST,
- LB_INSERTSTRING, i,
- (LPARAM) str);
- }
- }
- }
- break;
- case IDC_BOLDCOLOUR:
- if (HIWORD(wParam) == BN_CLICKED ||
- HIWORD(wParam) == BN_DOUBLECLICKED) {
- int n, i;
- cfg.bold_colour =
- IsDlgButtonChecked(hwnd, IDC_BOLDCOLOUR);
- }
- break;
- case IDC_PALETTE:
- if (HIWORD(wParam) == BN_CLICKED ||
- HIWORD(wParam) == BN_DOUBLECLICKED)
- cfg.try_palette =
- IsDlgButtonChecked(hwnd, IDC_PALETTE);
- break;
- case IDC_COLOURLIST:
- if (HIWORD(wParam) == LBN_DBLCLK ||
- HIWORD(wParam) == LBN_SELCHANGE) {
- int i =
- SendDlgItemMessage(hwnd, IDC_COLOURLIST,
- LB_GETCURSEL,
- 0, 0);
- if (!cfg.bold_colour)
- i = (i < 3 ? i * 2 : i == 3 ? 5 : i * 2 - 2);
- SetDlgItemInt(hwnd, IDC_RVALUE, cfg.colours[i][0],
- FALSE);
- SetDlgItemInt(hwnd, IDC_GVALUE, cfg.colours[i][1],
- FALSE);
- SetDlgItemInt(hwnd, IDC_BVALUE, cfg.colours[i][2],
- FALSE);
- }
- break;
- case IDC_CHANGE:
- if (HIWORD(wParam) == BN_CLICKED ||
- HIWORD(wParam) == BN_DOUBLECLICKED) {
- static CHOOSECOLOR cc;
- static DWORD custom[16] = { 0 }; /* zero initialisers */
- int i =
- SendDlgItemMessage(hwnd, IDC_COLOURLIST,
- LB_GETCURSEL,
- 0, 0);
- if (!cfg.bold_colour)
- i = (i < 3 ? i * 2 : i == 3 ? 5 : i * 2 - 2);
- cc.lStructSize = sizeof(cc);
- cc.hwndOwner = hwnd;
- cc.hInstance = (HWND) hinst;
- cc.lpCustColors = custom;
- cc.rgbResult =
- RGB(cfg.colours[i][0], cfg.colours[i][1],
- cfg.colours[i][2]);
- cc.Flags = CC_FULLOPEN | CC_RGBINIT;
- if (ChooseColor(&cc)) {
- cfg.colours[i][0] =
- (unsigned char) (cc.rgbResult & 0xFF);
- cfg.colours[i][1] =
- (unsigned char) (cc.rgbResult >> 8) & 0xFF;
- cfg.colours[i][2] =
- (unsigned char) (cc.rgbResult >> 16) & 0xFF;
- SetDlgItemInt(hwnd, IDC_RVALUE, cfg.colours[i][0],
- FALSE);
- SetDlgItemInt(hwnd, IDC_GVALUE, cfg.colours[i][1],
- FALSE);
- SetDlgItemInt(hwnd, IDC_BVALUE, cfg.colours[i][2],
- FALSE);
- }
- }
- break;
- case IDC_CODEPAGE:
- if (HIWORD(wParam) == CBN_SELCHANGE) {
- int index = SendDlgItemMessage(hwnd, IDC_CODEPAGE,
- CB_GETCURSEL, 0, 0);
- SendDlgItemMessage(hwnd, IDC_CODEPAGE, CB_GETLBTEXT,
- index, (LPARAM)cfg.line_codepage);
- } else if (HIWORD(wParam) == CBN_EDITCHANGE) {
- GetDlgItemText(hwnd, IDC_CODEPAGE, cfg.line_codepage,
- sizeof(cfg.line_codepage) - 1);
- } else if (HIWORD(wParam) == CBN_KILLFOCUS) {
- strcpy(cfg.line_codepage,
- cp_name(decode_codepage(cfg.line_codepage)));
- SetDlgItemText(hwnd, IDC_CODEPAGE, cfg.line_codepage);
- }
- break;
- case IDC_PRINTER:
- if (HIWORD(wParam) == CBN_SELCHANGE) {
- int index = SendDlgItemMessage(hwnd, IDC_PRINTER,
- CB_GETCURSEL, 0, 0);
- SendDlgItemMessage(hwnd, IDC_PRINTER, CB_GETLBTEXT,
- index, (LPARAM)cfg.printer);
- } else if (HIWORD(wParam) == CBN_EDITCHANGE) {
- GetDlgItemText(hwnd, IDC_PRINTER, cfg.printer,
- sizeof(cfg.printer) - 1);
- }
- if (!strcmp(cfg.printer, PRINTER_DISABLED_STRING))
- *cfg.printer = '\0';
- break;
- case IDC_CAPSLOCKCYR:
- if (HIWORD(wParam) == BN_CLICKED ||
- HIWORD(wParam) == BN_DOUBLECLICKED) {
- cfg.xlat_capslockcyr =
- IsDlgButtonChecked (hwnd, IDC_CAPSLOCKCYR);
- }
- break;
- case IDC_VTXWINDOWS:
- case IDC_VTOEMANSI:
- case IDC_VTOEMONLY:
- case IDC_VTPOORMAN:
- case IDC_VTUNICODE:
- cfg.vtmode =
- (IsDlgButtonChecked(hwnd, IDC_VTXWINDOWS) ? VT_XWINDOWS
- : IsDlgButtonChecked(hwnd,
- IDC_VTOEMANSI) ? VT_OEMANSI :
- IsDlgButtonChecked(hwnd,
- IDC_VTOEMONLY) ? VT_OEMONLY :
- IsDlgButtonChecked(hwnd,
- IDC_VTUNICODE) ? VT_UNICODE :
- VT_POORMAN);
- break;
- case IDC_X11_FORWARD:
- if (HIWORD(wParam) == BN_CLICKED ||
- HIWORD(wParam) == BN_DOUBLECLICKED)
- cfg.x11_forward =
- IsDlgButtonChecked(hwnd, IDC_X11_FORWARD);
- break;
- case IDC_LPORT_ALL:
- if (HIWORD(wParam) == BN_CLICKED ||
- HIWORD(wParam) == BN_DOUBLECLICKED)
- cfg.lport_acceptall =
- IsDlgButtonChecked(hwnd, IDC_LPORT_ALL);
- break;
- case IDC_RPORT_ALL:
- if (HIWORD(wParam) == BN_CLICKED ||
- HIWORD(wParam) == BN_DOUBLECLICKED)
- cfg.rport_acceptall =
- IsDlgButtonChecked(hwnd, IDC_RPORT_ALL);
- break;
- case IDC_X11_DISPLAY:
- if (HIWORD(wParam) == EN_CHANGE)
- GetDlgItemText(hwnd, IDC_X11_DISPLAY, cfg.x11_display,
- sizeof(cfg.x11_display) - 1);
- break;
- case IDC_X11MIT:
- case IDC_X11XDM:
- if (HIWORD(wParam) == BN_CLICKED ||
- HIWORD(wParam) == BN_DOUBLECLICKED) {
- if (IsDlgButtonChecked(hwnd, IDC_X11MIT))
- cfg.x11_auth = X11_MIT;
- else if (IsDlgButtonChecked(hwnd, IDC_X11XDM))
- cfg.x11_auth = X11_XDM;
- }
- break;
- case IDC_PFWDADD:
- if (HIWORD(wParam) == BN_CLICKED ||
- HIWORD(wParam) == BN_DOUBLECLICKED) {
- char str[sizeof(cfg.portfwd)];
- char *p;
- if (IsDlgButtonChecked(hwnd, IDC_PFWDLOCAL))
- str[0] = 'L';
- else
- str[0] = 'R';
- GetDlgItemText(hwnd, IDC_SPORTEDIT, str+1,
- sizeof(str) - 2);
- if (!str[1]) {
- MessageBox(hwnd,
- "You need to specify a source port number",
- "PuTTY Error", MB_OK | MB_ICONERROR);
- break;
- }
- p = str + strlen(str);
- *p++ = '\t';
- GetDlgItemText(hwnd, IDC_DPORTEDIT, p,
- sizeof(str) - 1 - (p - str));
- if (!*p || !strchr(p, ':')) {
- MessageBox(hwnd,
- "You need to specify a destination address\n"
- "in the form \"host.name:port\"",
- "PuTTY Error", MB_OK | MB_ICONERROR);
- break;
- }
- p = cfg.portfwd;
- while (*p) {
- while (*p)
- p++;
- p++;
- }
- if ((p - cfg.portfwd) + strlen(str) + 2 <
- sizeof(cfg.portfwd)) {
- strcpy(p, str);
- p[strlen(str) + 1] = '\0';
- SendDlgItemMessage(hwnd, IDC_PFWDLIST, LB_ADDSTRING,
- 0, (LPARAM) str);
- SetDlgItemText(hwnd, IDC_SPORTEDIT, "");
- SetDlgItemText(hwnd, IDC_DPORTEDIT, "");
- } else {
- MessageBox(hwnd, "Too many forwardings",
- "PuTTY Error", MB_OK | MB_ICONERROR);
- }
- }
- break;
- case IDC_PFWDREMOVE:
- if (HIWORD(wParam) != BN_CLICKED &&
- HIWORD(wParam) != BN_DOUBLECLICKED) break;
- i = SendDlgItemMessage(hwnd, IDC_PFWDLIST,
- LB_GETCURSEL, 0, 0);
- if (i == LB_ERR)
- MessageBeep(0);
- else {
- char *p, *q;
-
- SendDlgItemMessage(hwnd, IDC_PFWDLIST, LB_DELETESTRING,
- i, 0);
- p = cfg.portfwd;
- while (i > 0) {
- if (!*p)
- goto disaster2;
- while (*p)
- p++;
- p++;
- i--;
- }
- q = p;
- if (!*p)
- goto disaster2;
- while (*p)
- p++;
- p++;
- while (*p) {
- while (*p)
- *q++ = *p++;
- *q++ = *p++;
- }
- *q = '\0';
- disaster2:;
- }
- break;
- case IDC_BUGD_IGNORE1:
- if (HIWORD(wParam) == CBN_SELCHANGE) {
- int index = SendDlgItemMessage(hwnd, IDC_BUGD_IGNORE1,
- CB_GETCURSEL, 0, 0);
- cfg.sshbug_ignore1 = (index == 0 ? AUTO :
- index == 1 ? FORCE_OFF : FORCE_ON);
- }
- break;
- case IDC_BUGD_PLAINPW1:
- if (HIWORD(wParam) == CBN_SELCHANGE) {
- int index = SendDlgItemMessage(hwnd, IDC_BUGD_PLAINPW1,
- CB_GETCURSEL, 0, 0);
- cfg.sshbug_plainpw1 = (index == 0 ? AUTO :
- index == 1 ? FORCE_OFF : FORCE_ON);
- }
- break;
- case IDC_BUGD_RSA1:
- if (HIWORD(wParam) == CBN_SELCHANGE) {
- int index = SendDlgItemMessage(hwnd, IDC_BUGD_RSA1,
- CB_GETCURSEL, 0, 0);
- cfg.sshbug_rsa1 = (index == 0 ? AUTO :
- index == 1 ? FORCE_OFF : FORCE_ON);
- }
- break;
- case IDC_BUGD_HMAC2:
- if (HIWORD(wParam) == CBN_SELCHANGE) {
- int index = SendDlgItemMessage(hwnd, IDC_BUGD_HMAC2,
- CB_GETCURSEL, 0, 0);
- cfg.sshbug_hmac2 = (index == 0 ? AUTO :
- index == 1 ? FORCE_OFF : FORCE_ON);
- }
- break;
- case IDC_BUGD_DERIVEKEY2:
- if (HIWORD(wParam) == CBN_SELCHANGE) {
- int index = SendDlgItemMessage(hwnd, IDC_BUGD_DERIVEKEY2,
- CB_GETCURSEL, 0, 0);
- cfg.sshbug_derivekey2 = (index == 0 ? AUTO :
- index == 1 ? FORCE_OFF:FORCE_ON);
- }
- break;
- case IDC_BUGD_RSAPAD2:
- if (HIWORD(wParam) == CBN_SELCHANGE) {
- int index = SendDlgItemMessage(hwnd, IDC_BUGD_RSAPAD2,
- CB_GETCURSEL, 0, 0);
- cfg.sshbug_rsapad2 = (index == 0 ? AUTO :
- index == 1 ? FORCE_OFF : FORCE_ON);
- }
- break;
- case IDC_BUGD_DHGEX2:
- if (HIWORD(wParam) == CBN_SELCHANGE) {
- int index = SendDlgItemMessage(hwnd, IDC_BUGD_DHGEX2,
- CB_GETCURSEL, 0, 0);
- cfg.sshbug_dhgex2 = (index == 0 ? AUTO :
- index == 1 ? FORCE_OFF : FORCE_ON);
- }
- break;
- case IDC_BUGD_PKSESSID2:
- if (HIWORD(wParam) == CBN_SELCHANGE) {
- int index = SendDlgItemMessage(hwnd, IDC_BUGD_PKSESSID2,
- CB_GETCURSEL, 0, 0);
- cfg.sshbug_pksessid2 = (index == 0 ? AUTO :
- index == 1 ? FORCE_OFF : FORCE_ON);
- }
- break;
- }
- return 0;
+ if (GetWindowLong(hwnd, GWL_USERDATA) == 1) {
+ ret = winctrl_handle_command(&dp, msg, wParam, lParam);
+ if (dp.ended && GetCapture() != hwnd)
+ EndDialog(hwnd, dp.endresult ? 1 : 0);
+ } else
+ ret = 0;
+ return ret;
case WM_HELP:
if (help_path) {
- int id = ((LPHELPINFO)lParam)->iCtrlId;
- char *cmd = help_context_cmd(id);
- if (cmd) {
- WinHelp(hwnd, help_path, HELP_COMMAND, (DWORD)cmd);
+ if (winctrl_context_help(&dp, hwnd,
+ ((LPHELPINFO)lParam)->iCtrlId))
requested_help = TRUE;
- } else {
+ else
MessageBeep(0);
- }
}
break;
case WM_CLOSE:
force_normal(hwnd);
return 0;
- default:
- /*
- * Handle application-defined messages eg. DragListBox
- */
- /* First find out what the number is (once). */
- if (draglistmsg == WM_NULL)
- draglistmsg = RegisterWindowMessage (DRAGLISTMSGSTRING);
-
- if (msg == draglistmsg) {
- /* Only process once dialog is fully formed. */
- if (GetWindowLong(hwnd, GWL_USERDATA) == 1) switch (LOWORD(wParam)) {
- case IDC_CIPHERLIST:
- return handle_prefslist(&cipherlist,
- cfg.ssh_cipherlist, CIPHER_MAX,
- 1, hwnd, wParam, lParam);
- }
- }
- return 0;
-
}
return 0;
}
-static int CALLBACK MainDlgProc(HWND hwnd, UINT msg,
- WPARAM wParam, LPARAM lParam)
+void modal_about_box(HWND hwnd)
{
- if (msg == WM_COMMAND && LOWORD(wParam) == IDOK) {
- }
- if (msg == WM_COMMAND && LOWORD(wParam) == IDCX_ABOUT) {
- EnableWindow(hwnd, 0);
- DialogBox(hinst, MAKEINTRESOURCE(IDD_ABOUTBOX), hwnd, AboutProc);
- EnableWindow(hwnd, 1);
- SetActiveWindow(hwnd);
- }
- return GenericMainDlgProc(hwnd, msg, wParam, lParam, 0);
+ EnableWindow(hwnd, 0);
+ DialogBox(hinst, MAKEINTRESOURCE(IDD_ABOUTBOX), hwnd, AboutProc);
+ EnableWindow(hwnd, 1);
+ SetActiveWindow(hwnd);
}
-static int CALLBACK ReconfDlgProc(HWND hwnd, UINT msg,
- WPARAM wParam, LPARAM lParam)
+void show_help(HWND hwnd)
{
- return GenericMainDlgProc(hwnd, msg, wParam, lParam, 1);
+ if (help_path) {
+ WinHelp(hwnd, help_path,
+ help_has_contents ? HELP_FINDER : HELP_CONTENTS,
+ 0);
+ requested_help = TRUE;
+ }
}
void defuse_showwindow(void)
{
int ret;
+ ctrlbox = ctrl_new_box();
+ setup_config_box(ctrlbox, &sesslist, FALSE, 0);
+ win_setup_config_box(ctrlbox, &dp.hwnd, (help_path != NULL), FALSE);
+ winctrl_init(&ctrls_base);
+ winctrl_init(&ctrls_panel);
+ dp.controltrees[0] = &ctrls_base;
+ dp.controltrees[1] = &ctrls_panel;
+ dp.nctrltrees = 2;
+ dp.errtitle = "PuTTY Error";
+ dp.data = &cfg;
+ dp.ended = FALSE;
+ dp.lastfocused = NULL;
+ memset(dp.shortcuts, 0, sizeof(dp.shortcuts));
+ dp.shortcuts['g'] = TRUE; /* the treeview: `Cate&gory' */
+
get_sesslist(&sesslist, TRUE);
- savedsession[0] = '\0';
ret =
- DialogBox(hinst, MAKEINTRESOURCE(IDD_MAINBOX), NULL, MainDlgProc);
+ DialogBox(hinst, MAKEINTRESOURCE(IDD_MAINBOX), NULL,
+ GenericMainDlgProc);
get_sesslist(&sesslist, FALSE);
+ ctrl_free_box(ctrlbox);
+ winctrl_cleanup(&ctrls_base);
+ winctrl_cleanup(&ctrls_panel);
+
return ret;
}
int ret;
backup_cfg = cfg; /* structure copy */
+
+ ctrlbox = ctrl_new_box();
+ setup_config_box(ctrlbox, NULL, TRUE, cfg.protocol);
+ win_setup_config_box(ctrlbox, &dp.hwnd, (help_path != NULL), TRUE);
+ winctrl_init(&ctrls_base);
+ winctrl_init(&ctrls_panel);
+ dp.controltrees[0] = &ctrls_base;
+ dp.controltrees[1] = &ctrls_panel;
+ dp.nctrltrees = 2;
+ dp.errtitle = "PuTTY Error";
+ dp.data = &cfg;
+ dp.ended = FALSE;
+ dp.lastfocused = NULL;
+ memset(dp.shortcuts, 0, sizeof(dp.shortcuts));
+ dp.shortcuts['g'] = TRUE; /* the treeview: `Cate&gory' */
+
ret =
- DialogBox(hinst, MAKEINTRESOURCE(IDD_RECONF), hwnd, ReconfDlgProc);
+ DialogBox(hinst, MAKEINTRESOURCE(IDD_MAINBOX), NULL,
+ GenericMainDlgProc);
+
+ ctrl_free_box(ctrlbox);
+ winctrl_cleanup(&ctrls_base);
+ winctrl_cleanup(&ctrls_panel);
+
if (!ret)
cfg = backup_cfg; /* structure copy */
--- /dev/null
+/*
+ * winhelp.h - define Windows Help context names for the controls
+ * in the PuTTY config box.
+ */
+
+#define HELPCTX(x) P(WINHELP_CTX_ ## x)
+
+#define WINHELP_CTX_no_help NULL
+
+#define WINHELP_CTX_session_hostname "session.hostname"
+#define WINHELP_CTX_session_saved "session.saved"
+#define WINHELP_CTX_session_coe "session.coe"
+#define WINHELP_CTX_logging_main "logging.main"
+#define WINHELP_CTX_logging_filename "logging.filename"
+#define WINHELP_CTX_logging_exists "logging.exists"
+#define WINHELP_CTX_keyboard_backspace "keyboard.backspace"
+#define WINHELP_CTX_keyboard_homeend "keyboard.homeend"
+#define WINHELP_CTX_keyboard_funkeys "keyboard.funkeys"
+#define WINHELP_CTX_keyboard_appkeypad "keyboard.appkeypad"
+#define WINHELP_CTX_keyboard_appcursor "keyboard.appcursor"
+#define WINHELP_CTX_keyboard_nethack "keyboard.nethack"
+#define WINHELP_CTX_keyboard_compose "keyboard.compose"
+#define WINHELP_CTX_keyboard_ctrlalt "keyboard.ctrlalt"
+#define WINHELP_CTX_features_application "features.application"
+#define WINHELP_CTX_features_mouse "features.mouse"
+#define WINHELP_CTX_features_resize "features.resize"
+#define WINHELP_CTX_features_altscreen "features.altscreen"
+#define WINHELP_CTX_features_retitle "features.retitle"
+#define WINHELP_CTX_features_dbackspace "features.dbackspace"
+#define WINHELP_CTX_features_charset "features.charset"
+#define WINHELP_CTX_terminal_autowrap "terminal.autowrap"
+#define WINHELP_CTX_terminal_decom "terminal.decom"
+#define WINHELP_CTX_terminal_lfhascr "terminal.lfhascr"
+#define WINHELP_CTX_terminal_bce "terminal.bce"
+#define WINHELP_CTX_terminal_blink "terminal.blink"
+#define WINHELP_CTX_terminal_answerback "terminal.answerback"
+#define WINHELP_CTX_terminal_localecho "terminal.localecho"
+#define WINHELP_CTX_terminal_localedit "terminal.localedit"
+#define WINHELP_CTX_terminal_printing "terminal.printing"
+#define WINHELP_CTX_bell_style "bell.style"
+#define WINHELP_CTX_bell_taskbar "bell.taskbar"
+#define WINHELP_CTX_bell_overload "bell.overload"
+#define WINHELP_CTX_window_size "window.size"
+#define WINHELP_CTX_window_resize "window.resize"
+#define WINHELP_CTX_window_scrollback "window.scrollback"
+#define WINHELP_CTX_behaviour_closewarn "behaviour.closewarn"
+#define WINHELP_CTX_behaviour_altf4 "behaviour.altf4"
+#define WINHELP_CTX_behaviour_altspace "behaviour.altspace"
+#define WINHELP_CTX_behaviour_altonly "behaviour.altonly"
+#define WINHELP_CTX_behaviour_alwaysontop "behaviour.alwaysontop"
+#define WINHELP_CTX_behaviour_altenter "behaviour.altenter"
+#define WINHELP_CTX_appearance_cursor "appearance.cursor"
+#define WINHELP_CTX_appearance_font "appearance.font"
+#define WINHELP_CTX_appearance_title "appearance.title"
+#define WINHELP_CTX_appearance_hidemouse "appearance.hidemouse"
+#define WINHELP_CTX_appearance_border "appearance.border"
+#define WINHELP_CTX_connection_termtype "connection.termtype"
+#define WINHELP_CTX_connection_username "connection.username"
+#define WINHELP_CTX_connection_keepalive "connection.keepalive"
+#define WINHELP_CTX_connection_nodelay "connection.nodelay"
+#define WINHELP_CTX_proxy_type "proxy.type"
+#define WINHELP_CTX_proxy_main "proxy.main"
+#define WINHELP_CTX_proxy_exclude "proxy.exclude"
+#define WINHELP_CTX_proxy_dns "proxy.dns"
+#define WINHELP_CTX_proxy_auth "proxy.auth"
+#define WINHELP_CTX_proxy_command "proxy.command"
+#define WINHELP_CTX_proxy_socksver "proxy.socksver"
+#define WINHELP_CTX_telnet_termspeed "telnet.termspeed"
+#define WINHELP_CTX_telnet_environ "telnet.environ"
+#define WINHELP_CTX_telnet_oldenviron "telnet.oldenviron"
+#define WINHELP_CTX_telnet_passive "telnet.passive"
+#define WINHELP_CTX_telnet_specialkeys "telnet.specialkeys"
+#define WINHELP_CTX_telnet_newline "telnet.newline"
+#define WINHELP_CTX_rlogin_termspeed "rlogin.termspeed"
+#define WINHELP_CTX_rlogin_localuser "rlogin.localuser"
+#define WINHELP_CTX_ssh_nopty "ssh.nopty"
+#define WINHELP_CTX_ssh_ciphers "ssh.ciphers"
+#define WINHELP_CTX_ssh_protocol "ssh.protocol"
+#define WINHELP_CTX_ssh_command "ssh.command"
+#define WINHELP_CTX_ssh_compress "ssh.compress"
+#define WINHELP_CTX_ssh_auth_privkey "ssh.auth.privkey"
+#define WINHELP_CTX_ssh_auth_agentfwd "ssh.auth.agentfwd"
+#define WINHELP_CTX_ssh_auth_changeuser "ssh.auth.changeuser"
+#define WINHELP_CTX_ssh_auth_tis "ssh.auth.tis"
+#define WINHELP_CTX_ssh_auth_ki "ssh.auth.ki"
+#define WINHELP_CTX_selection_buttons "selection.buttons"
+#define WINHELP_CTX_selection_shiftdrag "selection.shiftdrag"
+#define WINHELP_CTX_selection_rect "selection.rect"
+#define WINHELP_CTX_selection_charclasses "selection.charclasses"
+#define WINHELP_CTX_selection_linedraw "selection.linedraw"
+#define WINHELP_CTX_selection_rtf "selection.rtf"
+#define WINHELP_CTX_colours_bold "colours.bold"
+#define WINHELP_CTX_colours_logpal "colours.logpal"
+#define WINHELP_CTX_colours_config "colours.config"
+#define WINHELP_CTX_translation_codepage "translation.codepage"
+#define WINHELP_CTX_translation_cyrillic "translation.cyrillic"
+#define WINHELP_CTX_translation_linedraw "translation.linedraw"
+#define WINHELP_CTX_ssh_tunnels_x11 "ssh.tunnels.x11"
+#define WINHELP_CTX_ssh_tunnels_x11auth "ssh.tunnels.x11auth"
+#define WINHELP_CTX_ssh_tunnels_portfwd "ssh.tunnels.portfwd"
+#define WINHELP_CTX_ssh_tunnels_portfwd_localhost "ssh.tunnels.portfwd.localhost"
+#define WINHELP_CTX_ssh_bugs_ignore1 "ssh.bugs.ignore1"
+#define WINHELP_CTX_ssh_bugs_plainpw1 "ssh.bugs.plainpw1"
+#define WINHELP_CTX_ssh_bugs_rsa1 "ssh.bugs.rsa1"
+#define WINHELP_CTX_ssh_bugs_hmac2 "ssh.bugs.hmac2"
+#define WINHELP_CTX_ssh_bugs_derivekey2 "ssh.bugs.derivekey2"
+#define WINHELP_CTX_ssh_bugs_rsapad2 "ssh.bugs.rsapad2"
+#define WINHELP_CTX_ssh_bugs_dhgex2 "ssh.bugs.dhgex2"
+#define WINHELP_CTX_ssh_bugs_pksessid2 "ssh.bugs.pksessid2"
#include <stdio.h> /* for FILENAME_MAX */
+#include "tree234.h"
+
+#include "winhelp.h"
+
struct Filename {
char path[FILENAME_MAX];
};
#define sk_getxdmdata(socket, ip, port) (0)
/*
+ * File-selector filter strings used in the config box. On Windows,
+ * these strings are of exactly the type needed to go in
+ * `lpstrFilter' in an OPENFILENAME structure.
+ */
+#define FILTER_KEY_FILES ("PuTTY Private Key Files (*.ppk)\0*.ppk\0" \
+ "All Files (*.*)\0*\0\0\0")
+#define FILTER_WAVE_FILES ("Wave Files (*.wav)\0*.WAV\0" \
+ "All Files (*.*)\0*\0\0\0")
+
+/*
* Exports from winctrls.c.
*/
};
/*
+ * This structure is passed to event handler functions as the `dlg'
+ * parameter, and hence is passed back to winctrls access functions.
+ */
+struct dlgparam {
+ HWND hwnd; /* the hwnd of the dialog box */
+ struct winctrls *controltrees[8]; /* can have several of these */
+ int nctrltrees;
+ char *errtitle; /* title of error sub-messageboxes */
+ void *data; /* data to pass in refresh events */
+ union control *focused, *lastfocused; /* which ctrl has focus now/before */
+ int coloursel_wanted; /* has an event handler asked for
+ * a colour selector? */
+ char shortcuts[128]; /* track which shortcuts in use */
+ struct { unsigned char r, g, b, ok; } coloursel_result; /* 0-255 */
+ int ended, endresult; /* has the dialog been ended? */
+};
+
+/*
* Exports from winctrls.c.
*/
void ctlposinit(struct ctlpos *cp, HWND hwnd,
void bartitle(struct ctlpos *cp, char *name, int id);
void beginbox(struct ctlpos *cp, char *name, int idbox);
void endbox(struct ctlpos *cp);
-void multiedit(struct ctlpos *cp, ...);
+void multiedit(struct ctlpos *cp, int password, ...);
void radioline(struct ctlpos *cp, char *text, int id, int nacross, ...);
void bareradioline(struct ctlpos *cp, int nacross, ...);
void radiobig(struct ctlpos *cp, char *text, int id, ...);
char *btext, int bid, int eid, char *s2text, int s2id);
void colouredit(struct ctlpos *cp, char *stext, int sid, int listid,
char *btext, int bid, ...);
-void prefslist(struct prefslist *hdl, struct ctlpos *cp, char *stext,
- int sid, int listid, int upbid, int dnbid);
+void prefslist(struct prefslist *hdl, struct ctlpos *cp, int lines,
+ char *stext, int sid, int listid, int upbid, int dnbid);
int handle_prefslist(struct prefslist *hdl,
int *array, int maxmemb,
int is_dlmsg, HWND hwnd,
char *btext, int bid,
char *r1text, int r1id, char *r2text, int r2id);
+#define MAX_SHORTCUTS_PER_CTRL 16
+
+/*
+ * This structure is what's stored for each `union control' in the
+ * portable-dialog interface.
+ */
+struct winctrl {
+ union control *ctrl;
+ /*
+ * The control may have several components at the Windows
+ * level, with different dialog IDs. To avoid needing N
+ * separate platformsidectrl structures (which could be stored
+ * separately in a tree234 so that lookup by ID worked), we
+ * impose the constraint that those IDs must be in a contiguous
+ * block.
+ */
+ int base_id;
+ int num_ids;
+ /*
+ * Remember what keyboard shortcuts were used by this control,
+ * so that when we remove it again we can take them out of the
+ * list in the dlgparam.
+ */
+ char shortcuts[MAX_SHORTCUTS_PER_CTRL];
+ /*
+ * Some controls need a piece of allocated memory in which to
+ * store temporary data about the control.
+ */
+ void *data;
+};
+/*
+ * And this structure holds a set of the above, in two separate
+ * tree234s so that it can find an item by `union control' or by
+ * dialog ID.
+ */
+struct winctrls {
+ tree234 *byctrl, *byid;
+};
+void winctrl_init(struct winctrls *);
+void winctrl_cleanup(struct winctrls *);
+void winctrl_add(struct winctrls *, struct winctrl *);
+void winctrl_remove(struct winctrls *, struct winctrl *);
+struct winctrl *winctrl_findbyctrl(struct winctrls *, union control *);
+struct winctrl *winctrl_findbyid(struct winctrls *, int);
+struct winctrl *winctrl_findbyindex(struct winctrls *, int);
+void winctrl_layout(struct dlgparam *dp, struct winctrls *wc,
+ struct ctlpos *cp, struct controlset *s, int *id);
+int winctrl_handle_command(struct dlgparam *dp, UINT msg,
+ WPARAM wParam, LPARAM lParam);
+
/*
* Exports from windlg.c.
*/