1
0
mirror of https://git.tartarus.org/simon/putty.git synced 2025-01-09 17:38:00 +00:00

The long-awaited config box revamp! I've taken the whole config box

to pieces, and put it back together in a new table-driven form.
config.c sets up a data structure describing most of the config box;
wincfg.c adds in the Windows-specific options (so that config.c can
also form the basis for Mac and Unix config boxes). Then winctrls.c
contains a shiny new layout engine which consumes that data
structure, and windlg.c passes all WM_COMMAND and similar messages
to a driver alongside that layout engine. In the process I've sorted
out nicer-looking panel titles and finally fixed the list-boxes-are-
never-the-right-size bug (turned out to be Windows's fault, of
course). I _believe_ it should do everything the old config box did,
including context help. Now everyone has to test it thoroughly...

[originally from svn r2908]
This commit is contained in:
Simon Tatham 2003-03-05 22:07:40 +00:00
parent a4e81c06c7
commit 616c837cf0
11 changed files with 5119 additions and 3863 deletions

4
Recipe
View File

@ -95,7 +95,7 @@
# 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
@ -146,7 +146,7 @@ pageant : [G] pageant sshrsa sshpubk sshdes sshbn sshmd5 version tree234
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

1526
config.c Normal file

File diff suppressed because it is too large Load Diff

587
dialog.c Normal file
View File

@ -0,0 +1,587 @@
/*
* 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));
}
}

665
dialog.h Normal file
View File

@ -0,0 +1,665 @@
/*
* 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);

View File

@ -1,4 +1,4 @@
\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
@ -622,10 +622,14 @@ on a terminal bell:
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
@ -634,10 +638,6 @@ beeps from any other beeps on the system. If you select this option,
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}
@ -883,32 +883,6 @@ offered a choice from all the fixed-width fonts installed on the
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}
@ -944,6 +918,32 @@ it to zero, or increase it further.
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}

View File

@ -48,20 +48,6 @@ STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
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 */

275
wincfg.c Normal file
View File

@ -0,0 +1,275 @@
/*
* 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)));
}

2060
winctrls.c

File diff suppressed because it is too large Load Diff

3584
windlg.c

File diff suppressed because it is too large Load Diff

109
winhelp.h Normal file
View File

@ -0,0 +1,109 @@
/*
* 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"

View File

@ -7,6 +7,10 @@
#include <stdio.h> /* for FILENAME_MAX */
#include "tree234.h"
#include "winhelp.h"
struct Filename {
char path[FILENAME_MAX];
};
@ -111,6 +115,16 @@ GLOBAL void *logctx;
*/
#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.
*/
@ -141,6 +155,24 @@ struct prefslist {
int dragging;
};
/*
* 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.
*/
@ -151,7 +183,7 @@ HWND doctl(struct ctlpos *cp, RECT r,
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, ...);
@ -183,8 +215,8 @@ void charclass(struct ctlpos *cp, char *stext, int sid, int listid,
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,
@ -196,6 +228,56 @@ void fwdsetter(struct ctlpos *cp, int listid, char *stext, int sid,
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.
*/