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:
parent
a4e81c06c7
commit
616c837cf0
4
Recipe
4
Recipe
@ -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
|
||||
|
587
dialog.c
Normal file
587
dialog.c
Normal 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
665
dialog.h
Normal 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);
|
@ -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}
|
||||
|
14
win_res.rc
14
win_res.rc
@ -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
275
wincfg.c
Normal 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
2060
winctrls.c
File diff suppressed because it is too large
Load Diff
109
winhelp.h
Normal file
109
winhelp.h
Normal 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"
|
88
winstuff.h
88
winstuff.h
@ -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.
|
||||
*/
|
||||
|
Loading…
Reference in New Issue
Block a user