2000-10-18 15:36:32 +00:00
|
|
|
/*
|
|
|
|
* winctrls.c: routines to self-manage the controls in a dialog
|
|
|
|
* box.
|
|
|
|
*/
|
|
|
|
|
2003-03-05 22:07:40 +00:00
|
|
|
/*
|
|
|
|
* Possible TODO in new cross-platform config box stuff:
|
|
|
|
*
|
|
|
|
* - When lining up two controls alongside each other, I wonder if
|
|
|
|
* we could conveniently arrange to centre them vertically?
|
|
|
|
* Particularly ugly in the current setup is the `Add new
|
|
|
|
* forwarded port:' static next to the rather taller `Remove'
|
|
|
|
* button.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <assert.h>
|
2003-03-06 12:41:39 +00:00
|
|
|
#include <ctype.h>
|
2000-10-18 15:36:32 +00:00
|
|
|
|
2003-10-12 13:46:12 +00:00
|
|
|
#include "putty.h"
|
2003-03-05 22:07:40 +00:00
|
|
|
#include "misc.h"
|
|
|
|
#include "dialog.h"
|
2001-08-25 19:33:33 +00:00
|
|
|
|
2003-10-12 13:46:12 +00:00
|
|
|
#include <commctrl.h>
|
2000-10-18 15:36:32 +00:00
|
|
|
|
|
|
|
#define GAPBETWEEN 3
|
|
|
|
#define GAPWITHIN 1
|
|
|
|
#define GAPXBOX 7
|
|
|
|
#define GAPYBOX 4
|
|
|
|
#define DLGWIDTH 168
|
|
|
|
#define STATICHEIGHT 8
|
2003-03-05 22:07:40 +00:00
|
|
|
#define TITLEHEIGHT 12
|
2000-10-18 15:36:32 +00:00
|
|
|
#define CHECKBOXHEIGHT 8
|
|
|
|
#define RADIOHEIGHT 8
|
|
|
|
#define EDITHEIGHT 12
|
2003-03-05 22:07:40 +00:00
|
|
|
#define LISTHEIGHT 11
|
|
|
|
#define LISTINCREMENT 8
|
2000-10-18 15:36:32 +00:00
|
|
|
#define COMBOHEIGHT 12
|
|
|
|
#define PUSHBTNHEIGHT 14
|
2000-10-19 15:43:08 +00:00
|
|
|
#define PROGBARHEIGHT 14
|
2000-10-18 15:36:32 +00:00
|
|
|
|
2017-03-13 21:42:44 +00:00
|
|
|
DECL_WINDOWS_FUNCTION(static, void, InitCommonControls, (void));
|
|
|
|
DECL_WINDOWS_FUNCTION(static, BOOL, MakeDragList, (HWND));
|
|
|
|
DECL_WINDOWS_FUNCTION(static, int, LBItemFromPt, (HWND, POINT, BOOL));
|
2017-12-10 09:19:15 +00:00
|
|
|
DECL_WINDOWS_FUNCTION(static, void, DrawInsert, (HWND, HWND, int));
|
2017-03-13 21:42:44 +00:00
|
|
|
|
|
|
|
void init_common_controls(void)
|
|
|
|
{
|
|
|
|
HMODULE comctl32_module = load_system32_dll("comctl32.dll");
|
|
|
|
GET_WINDOWS_FUNCTION(comctl32_module, InitCommonControls);
|
|
|
|
GET_WINDOWS_FUNCTION(comctl32_module, MakeDragList);
|
|
|
|
GET_WINDOWS_FUNCTION(comctl32_module, LBItemFromPt);
|
|
|
|
GET_WINDOWS_FUNCTION(comctl32_module, DrawInsert);
|
|
|
|
p_InitCommonControls();
|
|
|
|
}
|
|
|
|
|
2000-10-18 15:36:32 +00:00
|
|
|
void ctlposinit(struct ctlpos *cp, HWND hwnd,
|
2019-09-08 19:29:00 +00:00
|
|
|
int leftborder, int rightborder, int topborder)
|
2001-05-06 14:35:20 +00:00
|
|
|
{
|
2000-10-18 15:36:32 +00:00
|
|
|
RECT r, r2;
|
|
|
|
cp->hwnd = hwnd;
|
|
|
|
cp->font = SendMessage(hwnd, WM_GETFONT, 0, 0);
|
|
|
|
cp->ypos = topborder;
|
|
|
|
GetClientRect(hwnd, &r);
|
|
|
|
r2.left = r2.top = 0;
|
|
|
|
r2.right = 4;
|
|
|
|
r2.bottom = 8;
|
|
|
|
MapDialogRect(hwnd, &r2);
|
|
|
|
cp->dlu4inpix = r2.right;
|
2001-05-06 14:35:20 +00:00
|
|
|
cp->width = (r.right * 4) / (r2.right) - 2 * GAPBETWEEN;
|
2000-10-18 15:36:32 +00:00
|
|
|
cp->xoff = leftborder;
|
|
|
|
cp->width -= leftborder + rightborder;
|
|
|
|
}
|
|
|
|
|
2001-08-25 19:33:33 +00:00
|
|
|
HWND doctl(struct ctlpos *cp, RECT r,
|
2019-09-08 19:29:00 +00:00
|
|
|
char *wclass, int wstyle, int exstyle, char *wtext, int wid)
|
2001-05-06 14:35:20 +00:00
|
|
|
{
|
2000-10-18 15:36:32 +00:00
|
|
|
HWND ctl;
|
|
|
|
/*
|
|
|
|
* Note nonstandard use of RECT. This is deliberate: by
|
|
|
|
* transforming the width and height directly we arrange to
|
|
|
|
* have all supposedly same-sized controls really same-sized.
|
|
|
|
*/
|
|
|
|
|
|
|
|
r.left += cp->xoff;
|
|
|
|
MapDialogRect(cp->hwnd, &r);
|
|
|
|
|
2003-03-05 22:07:40 +00:00
|
|
|
/*
|
|
|
|
* We can pass in cp->hwnd == NULL, to indicate a dry run
|
|
|
|
* without creating any actual controls.
|
|
|
|
*/
|
|
|
|
if (cp->hwnd) {
|
2019-09-08 19:29:00 +00:00
|
|
|
ctl = CreateWindowEx(exstyle, wclass, wtext, wstyle,
|
|
|
|
r.left, r.top, r.right, r.bottom,
|
|
|
|
cp->hwnd, (HMENU)(ULONG_PTR)wid, hinst, NULL);
|
|
|
|
SendMessage(ctl, WM_SETFONT, cp->font, MAKELPARAM(true, 0));
|
|
|
|
|
|
|
|
if (!strcmp(wclass, "LISTBOX")) {
|
|
|
|
/*
|
|
|
|
* Bizarre Windows bug: the list box calculates its
|
|
|
|
* number of lines based on the font it has at creation
|
|
|
|
* time, but sending it WM_SETFONT doesn't cause it to
|
|
|
|
* recalculate. So now, _after_ we've sent it
|
|
|
|
* WM_SETFONT, we explicitly resize it (to the same
|
|
|
|
* size it was already!) to force it to reconsider.
|
|
|
|
*/
|
|
|
|
SetWindowPos(ctl, NULL, 0, 0, r.right, r.bottom,
|
|
|
|
SWP_NOACTIVATE | SWP_NOCOPYBITS |
|
|
|
|
SWP_NOMOVE | SWP_NOZORDER);
|
|
|
|
}
|
2003-03-06 12:41:39 +00:00
|
|
|
} else
|
2019-09-08 19:29:00 +00:00
|
|
|
ctl = NULL;
|
2001-08-25 19:33:33 +00:00
|
|
|
return ctl;
|
2000-10-18 15:36:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* A title bar across the top of a sub-dialog.
|
|
|
|
*/
|
2001-05-06 14:35:20 +00:00
|
|
|
void bartitle(struct ctlpos *cp, char *name, int id)
|
|
|
|
{
|
2000-10-18 15:36:32 +00:00
|
|
|
RECT r;
|
|
|
|
|
2001-05-06 14:35:20 +00:00
|
|
|
r.left = GAPBETWEEN;
|
|
|
|
r.right = cp->width;
|
|
|
|
r.top = cp->ypos;
|
|
|
|
r.bottom = STATICHEIGHT;
|
2000-10-18 15:36:32 +00:00
|
|
|
cp->ypos += r.bottom + GAPBETWEEN;
|
|
|
|
doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0, name, id);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Begin a grouping box, with or without a group title.
|
|
|
|
*/
|
2001-05-06 14:35:20 +00:00
|
|
|
void beginbox(struct ctlpos *cp, char *name, int idbox)
|
|
|
|
{
|
2000-10-18 15:36:32 +00:00
|
|
|
cp->boxystart = cp->ypos;
|
2001-01-22 17:17:26 +00:00
|
|
|
if (!name)
|
2019-09-08 19:29:00 +00:00
|
|
|
cp->boxystart -= STATICHEIGHT / 2;
|
2000-10-18 15:36:32 +00:00
|
|
|
if (name)
|
2019-09-08 19:29:00 +00:00
|
|
|
cp->ypos += STATICHEIGHT;
|
2000-10-18 15:36:32 +00:00
|
|
|
cp->ypos += GAPYBOX;
|
2001-05-06 14:35:20 +00:00
|
|
|
cp->width -= 2 * GAPXBOX;
|
2000-10-18 15:36:32 +00:00
|
|
|
cp->xoff += GAPXBOX;
|
|
|
|
cp->boxid = idbox;
|
|
|
|
cp->boxtext = name;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* End a grouping box.
|
|
|
|
*/
|
2001-05-06 14:35:20 +00:00
|
|
|
void endbox(struct ctlpos *cp)
|
|
|
|
{
|
2000-10-18 15:36:32 +00:00
|
|
|
RECT r;
|
|
|
|
cp->xoff -= GAPXBOX;
|
2001-05-06 14:35:20 +00:00
|
|
|
cp->width += 2 * GAPXBOX;
|
2000-10-18 15:36:32 +00:00
|
|
|
cp->ypos += GAPYBOX - GAPBETWEEN;
|
2001-05-06 14:35:20 +00:00
|
|
|
r.left = GAPBETWEEN;
|
|
|
|
r.right = cp->width;
|
|
|
|
r.top = cp->boxystart;
|
|
|
|
r.bottom = cp->ypos - cp->boxystart;
|
2001-01-22 17:17:26 +00:00
|
|
|
doctl(cp, r, "BUTTON", BS_GROUPBOX | WS_CHILD | WS_VISIBLE, 0,
|
2019-09-08 19:29:00 +00:00
|
|
|
cp->boxtext ? cp->boxtext : "", cp->boxid);
|
2000-10-18 15:36:32 +00:00
|
|
|
cp->ypos += GAPYBOX;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2005-04-11 16:23:35 +00:00
|
|
|
* A static line, followed by a full-width edit box.
|
2000-10-18 15:36:32 +00:00
|
|
|
*/
|
Convert a lot of 'int' variables to 'bool'.
My normal habit these days, in new code, is to treat int and bool as
_almost_ completely separate types. I'm still willing to use C's
implicit test for zero on an integer (e.g. 'if (!blob.len)' is fine,
no need to spell it out as blob.len != 0), but generally, if a
variable is going to be conceptually a boolean, I like to declare it
bool and assign to it using 'true' or 'false' rather than 0 or 1.
PuTTY is an exception, because it predates the C99 bool, and I've
stuck to its existing coding style even when adding new code to it.
But it's been annoying me more and more, so now that I've decided C99
bool is an acceptable thing to require from our toolchain in the first
place, here's a quite thorough trawl through the source doing
'boolification'. Many variables and function parameters are now typed
as bool rather than int; many assignments of 0 or 1 to those variables
are now spelled 'true' or 'false'.
I managed this thorough conversion with the help of a custom clang
plugin that I wrote to trawl the AST and apply heuristics to point out
where things might want changing. So I've even managed to do a decent
job on parts of the code I haven't looked at in years!
To make the plugin's work easier, I pushed platform front ends
generally in the direction of using standard 'bool' in preference to
platform-specific boolean types like Windows BOOL or GTK's gboolean;
I've left the platform booleans in places they _have_ to be for the
platform APIs to work right, but variables only used by my own code
have been converted wherever I found them.
In a few places there are int values that look very like booleans in
_most_ of the places they're used, but have a rarely-used third value,
or a distinction between different nonzero values that most users
don't care about. In these cases, I've _removed_ uses of 'true' and
'false' for the return values, to emphasise that there's something
more subtle going on than a simple boolean answer:
- the 'multisel' field in dialog.h's list box structure, for which
the GTK front end in particular recognises a difference between 1
and 2 but nearly everything else treats as boolean
- the 'urgent' parameter to plug_receive, where 1 vs 2 tells you
something about the specific location of the urgent pointer, but
most clients only care about 0 vs 'something nonzero'
- the return value of wc_match, where -1 indicates a syntax error in
the wildcard.
- the return values from SSH-1 RSA-key loading functions, which use
-1 for 'wrong passphrase' and 0 for all other failures (so any
caller which already knows it's not loading an _encrypted private_
key can treat them as boolean)
- term->esc_query, and the 'query' parameter in toggle_mode in
terminal.c, which _usually_ hold 0 for ESC[123h or 1 for ESC[?123h,
but can also hold -1 for some other intervening character that we
don't support.
In a few places there's an integer that I haven't turned into a bool
even though it really _can_ only take values 0 or 1 (and, as above,
tried to make the call sites consistent in not calling those values
true and false), on the grounds that I thought it would make it more
confusing to imply that the 0 value was in some sense 'negative' or
bad and the 1 positive or good:
- the return value of plug_accepting uses the POSIXish convention of
0=success and nonzero=error; I think if I made it bool then I'd
also want to reverse its sense, and that's a job for a separate
piece of work.
- the 'screen' parameter to lineptr() in terminal.c, where 0 and 1
represent the default and alternate screens. There's no obvious
reason why one of those should be considered 'true' or 'positive'
or 'success' - they're just indices - so I've left it as int.
ssh_scp_recv had particularly confusing semantics for its previous int
return value: its call sites used '<= 0' to check for error, but it
never actually returned a negative number, just 0 or 1. Now the
function and its call sites agree that it's a bool.
In a couple of places I've renamed variables called 'ret', because I
don't like that name any more - it's unclear whether it means the
return value (in preparation) for the _containing_ function or the
return value received from a subroutine call, and occasionally I've
accidentally used the same variable for both and introduced a bug. So
where one of those got in my way, I've renamed it to 'toret' or 'retd'
(the latter short for 'returned') in line with my usual modern
practice, but I haven't done a thorough job of finding all of them.
Finally, one amusing side effect of doing this is that I've had to
separate quite a few chained assignments. It used to be perfectly fine
to write 'a = b = c = TRUE' when a,b,c were int and TRUE was just a
the 'true' defined by stdbool.h, that idiom provokes a warning from
gcc: 'suggest parentheses around assignment used as truth value'!
2018-11-02 19:23:19 +00:00
|
|
|
void editboxfw(struct ctlpos *cp, bool password, char *text,
|
2019-09-08 19:29:00 +00:00
|
|
|
int staticid, int editid)
|
2001-05-06 14:35:20 +00:00
|
|
|
{
|
2000-10-18 15:36:32 +00:00
|
|
|
RECT r;
|
2001-05-06 14:35:20 +00:00
|
|
|
|
2005-04-11 16:23:35 +00:00
|
|
|
r.left = GAPBETWEEN;
|
|
|
|
r.right = cp->width;
|
2001-05-06 14:35:20 +00:00
|
|
|
|
2005-04-11 16:23:35 +00:00
|
|
|
if (text) {
|
2019-09-08 19:29:00 +00:00
|
|
|
r.top = cp->ypos;
|
|
|
|
r.bottom = STATICHEIGHT;
|
|
|
|
doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0, text, staticid);
|
|
|
|
cp->ypos += STATICHEIGHT + GAPWITHIN;
|
2000-10-18 15:36:32 +00:00
|
|
|
}
|
2005-04-11 16:23:35 +00:00
|
|
|
r.top = cp->ypos;
|
|
|
|
r.bottom = EDITHEIGHT;
|
|
|
|
doctl(cp, r, "EDIT",
|
2019-09-08 19:29:00 +00:00
|
|
|
WS_CHILD | WS_VISIBLE | WS_TABSTOP | ES_AUTOHSCROLL |
|
|
|
|
(password ? ES_PASSWORD : 0),
|
|
|
|
WS_EX_CLIENTEDGE, "", editid);
|
2005-04-11 16:23:35 +00:00
|
|
|
cp->ypos += EDITHEIGHT + GAPBETWEEN;
|
2001-08-12 19:25:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2001-09-05 21:01:04 +00:00
|
|
|
* A static line, followed by a full-width combo box.
|
2001-08-12 19:25:21 +00:00
|
|
|
*/
|
2001-09-05 21:01:04 +00:00
|
|
|
void combobox(struct ctlpos *cp, char *text, int staticid, int listid)
|
2001-08-12 19:25:21 +00:00
|
|
|
{
|
|
|
|
RECT r;
|
|
|
|
|
|
|
|
r.left = GAPBETWEEN;
|
|
|
|
r.right = cp->width;
|
|
|
|
|
2005-04-11 16:23:35 +00:00
|
|
|
if (text) {
|
2019-09-08 19:29:00 +00:00
|
|
|
r.top = cp->ypos;
|
|
|
|
r.bottom = STATICHEIGHT;
|
|
|
|
doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0, text, staticid);
|
|
|
|
cp->ypos += STATICHEIGHT + GAPWITHIN;
|
2005-04-11 16:23:35 +00:00
|
|
|
}
|
2001-08-12 19:25:21 +00:00
|
|
|
r.top = cp->ypos;
|
|
|
|
r.bottom = COMBOHEIGHT * 10;
|
|
|
|
doctl(cp, r, "COMBOBOX",
|
2019-09-08 19:29:00 +00:00
|
|
|
WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_VSCROLL |
|
|
|
|
CBS_DROPDOWN | CBS_HASSTRINGS, WS_EX_CLIENTEDGE, "", listid);
|
2005-04-11 16:23:35 +00:00
|
|
|
cp->ypos += COMBOHEIGHT + GAPBETWEEN;
|
2000-10-18 15:36:32 +00:00
|
|
|
}
|
|
|
|
|
2003-03-05 22:07:40 +00:00
|
|
|
struct radio { char *text; int id; };
|
|
|
|
|
|
|
|
static void radioline_common(struct ctlpos *cp, char *text, int id,
|
2019-09-08 19:29:00 +00:00
|
|
|
int nacross, struct radio *buttons, int nbuttons)
|
2001-05-06 14:35:20 +00:00
|
|
|
{
|
2000-10-18 15:36:32 +00:00
|
|
|
RECT r;
|
|
|
|
int group;
|
|
|
|
int i;
|
2003-03-05 22:07:40 +00:00
|
|
|
int j;
|
|
|
|
|
|
|
|
if (text) {
|
2019-09-08 19:29:00 +00:00
|
|
|
r.left = GAPBETWEEN;
|
|
|
|
r.top = cp->ypos;
|
|
|
|
r.right = cp->width;
|
|
|
|
r.bottom = STATICHEIGHT;
|
|
|
|
cp->ypos += r.bottom + GAPWITHIN;
|
|
|
|
doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0, text, id);
|
2003-03-05 22:07:40 +00:00
|
|
|
}
|
2000-10-18 15:36:32 +00:00
|
|
|
|
|
|
|
group = WS_GROUP;
|
|
|
|
i = 0;
|
2003-03-05 22:07:40 +00:00
|
|
|
for (j = 0; j < nbuttons; j++) {
|
2019-09-08 19:29:00 +00:00
|
|
|
char *btext = buttons[j].text;
|
|
|
|
int bid = buttons[j].id;
|
|
|
|
|
|
|
|
if (i == nacross) {
|
|
|
|
cp->ypos += r.bottom + (nacross > 1 ? GAPBETWEEN : GAPWITHIN);
|
|
|
|
i = 0;
|
|
|
|
}
|
|
|
|
r.left = GAPBETWEEN + i * (cp->width + GAPBETWEEN) / nacross;
|
|
|
|
if (j < nbuttons-1)
|
|
|
|
r.right =
|
|
|
|
(i + 1) * (cp->width + GAPBETWEEN) / nacross - r.left;
|
|
|
|
else
|
|
|
|
r.right = cp->width - r.left;
|
|
|
|
r.top = cp->ypos;
|
|
|
|
r.bottom = RADIOHEIGHT;
|
|
|
|
doctl(cp, r, "BUTTON",
|
|
|
|
BS_NOTIFY | BS_AUTORADIOBUTTON | WS_CHILD |
|
|
|
|
WS_VISIBLE | WS_TABSTOP | group, 0, btext, bid);
|
|
|
|
group = 0;
|
|
|
|
i++;
|
2000-10-18 15:36:32 +00:00
|
|
|
}
|
|
|
|
cp->ypos += r.bottom + GAPBETWEEN;
|
|
|
|
}
|
|
|
|
|
2001-08-08 20:44:35 +00:00
|
|
|
/*
|
|
|
|
* A set of radio buttons on the same line, with a static above
|
|
|
|
* them. `nacross' dictates how many parts the line is divided into
|
|
|
|
* (you might want this not to equal the number of buttons if you
|
|
|
|
* needed to line up some 2s and some 3s to look good in the same
|
|
|
|
* panel).
|
2019-09-08 19:29:00 +00:00
|
|
|
*
|
2001-08-08 20:44:35 +00:00
|
|
|
* There's a bit of a hack in here to ensure that if nacross
|
|
|
|
* exceeds the actual number of buttons, the rightmost button
|
|
|
|
* really does get all the space right to the edge of the line, so
|
|
|
|
* you can do things like
|
2019-09-08 19:29:00 +00:00
|
|
|
*
|
2001-08-08 20:44:35 +00:00
|
|
|
* (*) Button1 (*) Button2 (*) ButtonWithReallyLongTitle
|
|
|
|
*/
|
|
|
|
void radioline(struct ctlpos *cp, char *text, int id, int nacross, ...)
|
|
|
|
{
|
|
|
|
va_list ap;
|
2003-03-05 22:07:40 +00:00
|
|
|
struct radio *buttons;
|
|
|
|
int i, nbuttons;
|
2001-08-08 20:44:35 +00:00
|
|
|
|
|
|
|
va_start(ap, nacross);
|
2003-03-05 22:07:40 +00:00
|
|
|
nbuttons = 0;
|
|
|
|
while (1) {
|
2019-09-08 19:29:00 +00:00
|
|
|
char *btext = va_arg(ap, char *);
|
|
|
|
if (!btext)
|
|
|
|
break;
|
|
|
|
(void) va_arg(ap, int); /* id */
|
|
|
|
nbuttons++;
|
2003-03-05 22:07:40 +00:00
|
|
|
}
|
|
|
|
va_end(ap);
|
2003-03-29 16:14:26 +00:00
|
|
|
buttons = snewn(nbuttons, struct radio);
|
2003-03-05 22:07:40 +00:00
|
|
|
va_start(ap, nacross);
|
|
|
|
for (i = 0; i < nbuttons; i++) {
|
2019-09-08 19:29:00 +00:00
|
|
|
buttons[i].text = va_arg(ap, char *);
|
|
|
|
buttons[i].id = va_arg(ap, int);
|
2003-03-05 22:07:40 +00:00
|
|
|
}
|
2001-08-08 20:44:35 +00:00
|
|
|
va_end(ap);
|
2003-03-05 22:07:40 +00:00
|
|
|
radioline_common(cp, text, id, nacross, buttons, nbuttons);
|
|
|
|
sfree(buttons);
|
2001-08-08 20:44:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* A set of radio buttons on the same line, without a static above
|
|
|
|
* them. Otherwise just like radioline.
|
|
|
|
*/
|
|
|
|
void bareradioline(struct ctlpos *cp, int nacross, ...)
|
|
|
|
{
|
|
|
|
va_list ap;
|
2003-03-05 22:07:40 +00:00
|
|
|
struct radio *buttons;
|
|
|
|
int i, nbuttons;
|
2001-08-08 20:44:35 +00:00
|
|
|
|
|
|
|
va_start(ap, nacross);
|
2003-03-05 22:07:40 +00:00
|
|
|
nbuttons = 0;
|
|
|
|
while (1) {
|
2019-09-08 19:29:00 +00:00
|
|
|
char *btext = va_arg(ap, char *);
|
|
|
|
if (!btext)
|
|
|
|
break;
|
|
|
|
(void) va_arg(ap, int); /* id */
|
2017-02-14 21:15:02 +00:00
|
|
|
nbuttons++;
|
2003-03-05 22:07:40 +00:00
|
|
|
}
|
|
|
|
va_end(ap);
|
2003-03-29 16:14:26 +00:00
|
|
|
buttons = snewn(nbuttons, struct radio);
|
2003-03-05 22:07:40 +00:00
|
|
|
va_start(ap, nacross);
|
|
|
|
for (i = 0; i < nbuttons; i++) {
|
2019-09-08 19:29:00 +00:00
|
|
|
buttons[i].text = va_arg(ap, char *);
|
|
|
|
buttons[i].id = va_arg(ap, int);
|
2003-03-05 22:07:40 +00:00
|
|
|
}
|
2001-08-08 20:44:35 +00:00
|
|
|
va_end(ap);
|
2003-03-05 22:07:40 +00:00
|
|
|
radioline_common(cp, NULL, 0, nacross, buttons, nbuttons);
|
|
|
|
sfree(buttons);
|
2001-08-08 20:44:35 +00:00
|
|
|
}
|
|
|
|
|
2000-10-18 15:36:32 +00:00
|
|
|
/*
|
|
|
|
* A set of radio buttons on multiple lines, with a static above
|
|
|
|
* them.
|
|
|
|
*/
|
2001-05-06 14:35:20 +00:00
|
|
|
void radiobig(struct ctlpos *cp, char *text, int id, ...)
|
|
|
|
{
|
2000-10-18 15:36:32 +00:00
|
|
|
va_list ap;
|
2003-03-05 22:07:40 +00:00
|
|
|
struct radio *buttons;
|
|
|
|
int i, nbuttons;
|
2000-10-18 15:36:32 +00:00
|
|
|
|
|
|
|
va_start(ap, id);
|
2003-03-05 22:07:40 +00:00
|
|
|
nbuttons = 0;
|
2000-10-18 15:36:32 +00:00
|
|
|
while (1) {
|
2019-09-08 19:29:00 +00:00
|
|
|
char *btext = va_arg(ap, char *);
|
|
|
|
if (!btext)
|
|
|
|
break;
|
|
|
|
(void) va_arg(ap, int); /* id */
|
2017-02-14 21:15:02 +00:00
|
|
|
nbuttons++;
|
2000-10-18 15:36:32 +00:00
|
|
|
}
|
|
|
|
va_end(ap);
|
2003-03-29 16:14:26 +00:00
|
|
|
buttons = snewn(nbuttons, struct radio);
|
2003-03-05 22:07:40 +00:00
|
|
|
va_start(ap, id);
|
|
|
|
for (i = 0; i < nbuttons; i++) {
|
2019-09-08 19:29:00 +00:00
|
|
|
buttons[i].text = va_arg(ap, char *);
|
|
|
|
buttons[i].id = va_arg(ap, int);
|
2003-03-05 22:07:40 +00:00
|
|
|
}
|
|
|
|
va_end(ap);
|
|
|
|
radioline_common(cp, text, id, 1, buttons, nbuttons);
|
|
|
|
sfree(buttons);
|
2000-10-18 15:36:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* A single standalone checkbox.
|
|
|
|
*/
|
2001-05-06 14:35:20 +00:00
|
|
|
void checkbox(struct ctlpos *cp, char *text, int id)
|
|
|
|
{
|
2000-10-18 15:36:32 +00:00
|
|
|
RECT r;
|
|
|
|
|
2001-05-06 14:35:20 +00:00
|
|
|
r.left = GAPBETWEEN;
|
|
|
|
r.top = cp->ypos;
|
|
|
|
r.right = cp->width;
|
|
|
|
r.bottom = CHECKBOXHEIGHT;
|
2000-10-18 15:36:32 +00:00
|
|
|
cp->ypos += r.bottom + GAPBETWEEN;
|
|
|
|
doctl(cp, r, "BUTTON",
|
2019-09-08 19:29:00 +00:00
|
|
|
BS_NOTIFY | BS_AUTOCHECKBOX | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 0,
|
|
|
|
text, id);
|
2000-10-18 15:36:32 +00:00
|
|
|
}
|
|
|
|
|
2003-03-05 22:07:40 +00:00
|
|
|
/*
|
|
|
|
* Wrap a piece of text for a static text control. Returns the
|
|
|
|
* wrapped text (a malloc'ed string containing \ns), and also
|
|
|
|
* returns the number of lines required.
|
|
|
|
*/
|
|
|
|
char *staticwrap(struct ctlpos *cp, HWND hwnd, char *text, int *lines)
|
|
|
|
{
|
|
|
|
HDC hdc = GetDC(hwnd);
|
|
|
|
int width, nlines, j;
|
|
|
|
INT *pwidths, nfit;
|
|
|
|
SIZE size;
|
|
|
|
char *ret, *p, *q;
|
|
|
|
RECT r;
|
2003-03-06 19:18:25 +00:00
|
|
|
HFONT oldfont, newfont;
|
2003-03-05 22:07:40 +00:00
|
|
|
|
2003-03-29 16:14:26 +00:00
|
|
|
ret = snewn(1+strlen(text), char);
|
2003-03-05 22:07:40 +00:00
|
|
|
p = text;
|
|
|
|
q = ret;
|
2003-03-29 16:14:26 +00:00
|
|
|
pwidths = snewn(1+strlen(text), INT);
|
2003-03-05 22:07:40 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Work out the width the text will need to fit in, by doing
|
|
|
|
* the same adjustment that the `statictext' function itself
|
|
|
|
* will perform.
|
|
|
|
*/
|
2019-09-08 19:29:00 +00:00
|
|
|
SetMapMode(hdc, MM_TEXT); /* ensure logical units == pixels */
|
2003-03-05 22:07:40 +00:00
|
|
|
r.left = r.top = r.bottom = 0;
|
|
|
|
r.right = cp->width;
|
|
|
|
MapDialogRect(hwnd, &r);
|
2003-03-06 19:18:25 +00:00
|
|
|
width = r.right;
|
2003-03-05 22:07:40 +00:00
|
|
|
|
|
|
|
nlines = 1;
|
|
|
|
|
2003-03-06 19:18:25 +00:00
|
|
|
/*
|
|
|
|
* We must select the correct font into the HDC before calling
|
|
|
|
* GetTextExtent*, or silly things will happen.
|
|
|
|
*/
|
|
|
|
newfont = (HFONT)SendMessage(hwnd, WM_GETFONT, 0, 0);
|
|
|
|
oldfont = SelectObject(hdc, newfont);
|
|
|
|
|
2003-03-05 22:07:40 +00:00
|
|
|
while (*p) {
|
2019-09-08 19:29:00 +00:00
|
|
|
if (!GetTextExtentExPoint(hdc, p, strlen(p), width,
|
|
|
|
&nfit, pwidths, &size) ||
|
|
|
|
(size_t)nfit >= strlen(p)) {
|
|
|
|
/*
|
|
|
|
* Either GetTextExtentExPoint returned failure, or the
|
|
|
|
* whole of the rest of the text fits on this line.
|
|
|
|
* Either way, we stop wrapping, copy the remainder of
|
|
|
|
* the input string unchanged to the output, and leave.
|
|
|
|
*/
|
|
|
|
strcpy(q, p);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Now we search backwards along the string from `nfit',
|
|
|
|
* looking for a space at which to break the line. If we
|
|
|
|
* don't find one at all, that's fine - we'll just break
|
|
|
|
* the line at `nfit'.
|
|
|
|
*/
|
|
|
|
for (j = nfit; j > 0; j--) {
|
|
|
|
if (isspace((unsigned char)p[j])) {
|
|
|
|
nfit = j;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
strncpy(q, p, nfit);
|
|
|
|
q[nfit] = '\n';
|
|
|
|
q += nfit+1;
|
|
|
|
|
|
|
|
p += nfit;
|
|
|
|
while (*p && isspace((unsigned char)*p))
|
|
|
|
p++;
|
|
|
|
|
|
|
|
nlines++;
|
2003-03-05 22:07:40 +00:00
|
|
|
}
|
|
|
|
|
2003-03-06 19:18:25 +00:00
|
|
|
SelectObject(hdc, oldfont);
|
2003-03-05 22:07:40 +00:00
|
|
|
ReleaseDC(cp->hwnd, hdc);
|
|
|
|
|
|
|
|
if (lines) *lines = nlines;
|
|
|
|
|
2013-07-22 07:11:54 +00:00
|
|
|
sfree(pwidths);
|
|
|
|
|
2003-03-05 22:07:40 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2000-10-19 15:43:08 +00:00
|
|
|
/*
|
|
|
|
* A single standalone static text control.
|
|
|
|
*/
|
2001-09-09 09:58:20 +00:00
|
|
|
void statictext(struct ctlpos *cp, char *text, int lines, int id)
|
2001-05-06 14:35:20 +00:00
|
|
|
{
|
2000-10-19 15:43:08 +00:00
|
|
|
RECT r;
|
|
|
|
|
2001-05-06 14:35:20 +00:00
|
|
|
r.left = GAPBETWEEN;
|
|
|
|
r.top = cp->ypos;
|
|
|
|
r.right = cp->width;
|
2001-09-09 09:58:20 +00:00
|
|
|
r.bottom = STATICHEIGHT * lines;
|
2000-10-19 15:43:08 +00:00
|
|
|
cp->ypos += r.bottom + GAPBETWEEN;
|
2003-03-05 22:07:40 +00:00
|
|
|
doctl(cp, r, "STATIC",
|
2019-09-08 19:29:00 +00:00
|
|
|
WS_CHILD | WS_VISIBLE | SS_LEFTNOWORDWRAP,
|
|
|
|
0, text, id);
|
2003-03-05 22:07:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* An owner-drawn static text control for a panel title.
|
|
|
|
*/
|
|
|
|
void paneltitle(struct ctlpos *cp, int id)
|
|
|
|
{
|
|
|
|
RECT r;
|
|
|
|
|
|
|
|
r.left = GAPBETWEEN;
|
|
|
|
r.top = cp->ypos;
|
|
|
|
r.right = cp->width;
|
|
|
|
r.bottom = TITLEHEIGHT;
|
|
|
|
cp->ypos += r.bottom + GAPBETWEEN;
|
|
|
|
doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE | SS_OWNERDRAW,
|
2019-09-08 19:29:00 +00:00
|
|
|
0, NULL, id);
|
2000-10-19 15:43:08 +00:00
|
|
|
}
|
|
|
|
|
2000-10-18 15:36:32 +00:00
|
|
|
/*
|
|
|
|
* A button on the right hand side, with a static to its left.
|
|
|
|
*/
|
|
|
|
void staticbtn(struct ctlpos *cp, char *stext, int sid,
|
2019-09-08 19:29:00 +00:00
|
|
|
char *btext, int bid)
|
2001-05-06 14:35:20 +00:00
|
|
|
{
|
2000-10-18 15:36:32 +00:00
|
|
|
const int height = (PUSHBTNHEIGHT > STATICHEIGHT ?
|
2019-09-08 19:29:00 +00:00
|
|
|
PUSHBTNHEIGHT : STATICHEIGHT);
|
2000-10-18 15:36:32 +00:00
|
|
|
RECT r;
|
|
|
|
int lwid, rwid, rpos;
|
|
|
|
|
|
|
|
rpos = GAPBETWEEN + 3 * (cp->width + GAPBETWEEN) / 4;
|
2001-05-06 14:35:20 +00:00
|
|
|
lwid = rpos - 2 * GAPBETWEEN;
|
2000-10-18 15:36:32 +00:00
|
|
|
rwid = cp->width + GAPBETWEEN - rpos;
|
|
|
|
|
2001-05-06 14:35:20 +00:00
|
|
|
r.left = GAPBETWEEN;
|
|
|
|
r.top = cp->ypos + (height - STATICHEIGHT) / 2;
|
|
|
|
r.right = lwid;
|
|
|
|
r.bottom = STATICHEIGHT;
|
2000-10-18 15:36:32 +00:00
|
|
|
doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0, stext, sid);
|
|
|
|
|
2001-05-06 14:35:20 +00:00
|
|
|
r.left = rpos;
|
|
|
|
r.top = cp->ypos + (height - PUSHBTNHEIGHT) / 2;
|
|
|
|
r.right = rwid;
|
|
|
|
r.bottom = PUSHBTNHEIGHT;
|
2000-10-18 15:36:32 +00:00
|
|
|
doctl(cp, r, "BUTTON",
|
2019-09-08 19:29:00 +00:00
|
|
|
BS_NOTIFY | WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_PUSHBUTTON,
|
|
|
|
0, btext, bid);
|
2000-10-18 15:36:32 +00:00
|
|
|
|
|
|
|
cp->ypos += height + GAPBETWEEN;
|
|
|
|
}
|
|
|
|
|
2003-03-05 22:07:40 +00:00
|
|
|
/*
|
|
|
|
* A simple push button.
|
|
|
|
*/
|
Convert a lot of 'int' variables to 'bool'.
My normal habit these days, in new code, is to treat int and bool as
_almost_ completely separate types. I'm still willing to use C's
implicit test for zero on an integer (e.g. 'if (!blob.len)' is fine,
no need to spell it out as blob.len != 0), but generally, if a
variable is going to be conceptually a boolean, I like to declare it
bool and assign to it using 'true' or 'false' rather than 0 or 1.
PuTTY is an exception, because it predates the C99 bool, and I've
stuck to its existing coding style even when adding new code to it.
But it's been annoying me more and more, so now that I've decided C99
bool is an acceptable thing to require from our toolchain in the first
place, here's a quite thorough trawl through the source doing
'boolification'. Many variables and function parameters are now typed
as bool rather than int; many assignments of 0 or 1 to those variables
are now spelled 'true' or 'false'.
I managed this thorough conversion with the help of a custom clang
plugin that I wrote to trawl the AST and apply heuristics to point out
where things might want changing. So I've even managed to do a decent
job on parts of the code I haven't looked at in years!
To make the plugin's work easier, I pushed platform front ends
generally in the direction of using standard 'bool' in preference to
platform-specific boolean types like Windows BOOL or GTK's gboolean;
I've left the platform booleans in places they _have_ to be for the
platform APIs to work right, but variables only used by my own code
have been converted wherever I found them.
In a few places there are int values that look very like booleans in
_most_ of the places they're used, but have a rarely-used third value,
or a distinction between different nonzero values that most users
don't care about. In these cases, I've _removed_ uses of 'true' and
'false' for the return values, to emphasise that there's something
more subtle going on than a simple boolean answer:
- the 'multisel' field in dialog.h's list box structure, for which
the GTK front end in particular recognises a difference between 1
and 2 but nearly everything else treats as boolean
- the 'urgent' parameter to plug_receive, where 1 vs 2 tells you
something about the specific location of the urgent pointer, but
most clients only care about 0 vs 'something nonzero'
- the return value of wc_match, where -1 indicates a syntax error in
the wildcard.
- the return values from SSH-1 RSA-key loading functions, which use
-1 for 'wrong passphrase' and 0 for all other failures (so any
caller which already knows it's not loading an _encrypted private_
key can treat them as boolean)
- term->esc_query, and the 'query' parameter in toggle_mode in
terminal.c, which _usually_ hold 0 for ESC[123h or 1 for ESC[?123h,
but can also hold -1 for some other intervening character that we
don't support.
In a few places there's an integer that I haven't turned into a bool
even though it really _can_ only take values 0 or 1 (and, as above,
tried to make the call sites consistent in not calling those values
true and false), on the grounds that I thought it would make it more
confusing to imply that the 0 value was in some sense 'negative' or
bad and the 1 positive or good:
- the return value of plug_accepting uses the POSIXish convention of
0=success and nonzero=error; I think if I made it bool then I'd
also want to reverse its sense, and that's a job for a separate
piece of work.
- the 'screen' parameter to lineptr() in terminal.c, where 0 and 1
represent the default and alternate screens. There's no obvious
reason why one of those should be considered 'true' or 'positive'
or 'success' - they're just indices - so I've left it as int.
ssh_scp_recv had particularly confusing semantics for its previous int
return value: its call sites used '<= 0' to check for error, but it
never actually returned a negative number, just 0 or 1. Now the
function and its call sites agree that it's a bool.
In a couple of places I've renamed variables called 'ret', because I
don't like that name any more - it's unclear whether it means the
return value (in preparation) for the _containing_ function or the
return value received from a subroutine call, and occasionally I've
accidentally used the same variable for both and introduced a bug. So
where one of those got in my way, I've renamed it to 'toret' or 'retd'
(the latter short for 'returned') in line with my usual modern
practice, but I haven't done a thorough job of finding all of them.
Finally, one amusing side effect of doing this is that I've had to
separate quite a few chained assignments. It used to be perfectly fine
to write 'a = b = c = TRUE' when a,b,c were int and TRUE was just a
the 'true' defined by stdbool.h, that idiom provokes a warning from
gcc: 'suggest parentheses around assignment used as truth value'!
2018-11-02 19:23:19 +00:00
|
|
|
void button(struct ctlpos *cp, char *btext, int bid, bool defbtn)
|
2003-03-05 22:07:40 +00:00
|
|
|
{
|
|
|
|
RECT r;
|
|
|
|
|
|
|
|
r.left = GAPBETWEEN;
|
|
|
|
r.top = cp->ypos;
|
|
|
|
r.right = cp->width;
|
|
|
|
r.bottom = PUSHBTNHEIGHT;
|
|
|
|
|
|
|
|
/* Q67655: the _dialog box_ must know which button is default
|
|
|
|
* as well as the button itself knowing */
|
|
|
|
if (defbtn && cp->hwnd)
|
2019-09-08 19:29:00 +00:00
|
|
|
SendMessage(cp->hwnd, DM_SETDEFID, bid, 0);
|
2003-03-05 22:07:40 +00:00
|
|
|
|
|
|
|
doctl(cp, r, "BUTTON",
|
2019-09-08 19:29:00 +00:00
|
|
|
BS_NOTIFY | WS_CHILD | WS_VISIBLE | WS_TABSTOP |
|
|
|
|
(defbtn ? BS_DEFPUSHBUTTON : 0) | BS_PUSHBUTTON,
|
|
|
|
0, btext, bid);
|
2003-03-05 22:07:40 +00:00
|
|
|
|
|
|
|
cp->ypos += PUSHBTNHEIGHT + GAPBETWEEN;
|
|
|
|
}
|
|
|
|
|
2001-08-27 17:40:03 +00:00
|
|
|
/*
|
|
|
|
* Like staticbtn, but two buttons.
|
|
|
|
*/
|
|
|
|
void static2btn(struct ctlpos *cp, char *stext, int sid,
|
2019-09-08 19:29:00 +00:00
|
|
|
char *btext1, int bid1, char *btext2, int bid2)
|
2001-08-27 17:40:03 +00:00
|
|
|
{
|
|
|
|
const int height = (PUSHBTNHEIGHT > STATICHEIGHT ?
|
2019-09-08 19:29:00 +00:00
|
|
|
PUSHBTNHEIGHT : STATICHEIGHT);
|
2001-08-27 17:40:03 +00:00
|
|
|
RECT r;
|
|
|
|
int lwid, rwid1, rwid2, rpos1, rpos2;
|
|
|
|
|
|
|
|
rpos1 = GAPBETWEEN + (cp->width + GAPBETWEEN) / 2;
|
|
|
|
rpos2 = GAPBETWEEN + 3 * (cp->width + GAPBETWEEN) / 4;
|
|
|
|
lwid = rpos1 - 2 * GAPBETWEEN;
|
|
|
|
rwid1 = rpos2 - rpos1 - GAPBETWEEN;
|
|
|
|
rwid2 = cp->width + GAPBETWEEN - rpos2;
|
|
|
|
|
|
|
|
r.left = GAPBETWEEN;
|
|
|
|
r.top = cp->ypos + (height - STATICHEIGHT) / 2;
|
|
|
|
r.right = lwid;
|
|
|
|
r.bottom = STATICHEIGHT;
|
|
|
|
doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0, stext, sid);
|
|
|
|
|
|
|
|
r.left = rpos1;
|
|
|
|
r.top = cp->ypos + (height - PUSHBTNHEIGHT) / 2;
|
|
|
|
r.right = rwid1;
|
|
|
|
r.bottom = PUSHBTNHEIGHT;
|
|
|
|
doctl(cp, r, "BUTTON",
|
2019-09-08 19:29:00 +00:00
|
|
|
BS_NOTIFY | WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_PUSHBUTTON,
|
|
|
|
0, btext1, bid1);
|
2001-08-27 17:40:03 +00:00
|
|
|
|
|
|
|
r.left = rpos2;
|
|
|
|
r.top = cp->ypos + (height - PUSHBTNHEIGHT) / 2;
|
|
|
|
r.right = rwid2;
|
|
|
|
r.bottom = PUSHBTNHEIGHT;
|
|
|
|
doctl(cp, r, "BUTTON",
|
2019-09-08 19:29:00 +00:00
|
|
|
BS_NOTIFY | WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_PUSHBUTTON,
|
|
|
|
0, btext2, bid2);
|
2001-08-27 17:40:03 +00:00
|
|
|
|
|
|
|
cp->ypos += height + GAPBETWEEN;
|
|
|
|
}
|
|
|
|
|
2000-10-18 15:36:32 +00:00
|
|
|
/*
|
|
|
|
* An edit control on the right hand side, with a static to its left.
|
|
|
|
*/
|
2000-10-19 15:43:08 +00:00
|
|
|
static void staticedit_internal(struct ctlpos *cp, char *stext,
|
2019-09-08 19:29:00 +00:00
|
|
|
int sid, int eid, int percentedit,
|
|
|
|
int style)
|
2001-05-06 14:35:20 +00:00
|
|
|
{
|
2000-10-18 15:36:32 +00:00
|
|
|
const int height = (EDITHEIGHT > STATICHEIGHT ?
|
2019-09-08 19:29:00 +00:00
|
|
|
EDITHEIGHT : STATICHEIGHT);
|
2000-10-18 15:36:32 +00:00
|
|
|
RECT r;
|
|
|
|
int lwid, rwid, rpos;
|
|
|
|
|
2001-05-06 14:35:20 +00:00
|
|
|
rpos =
|
2019-09-08 19:29:00 +00:00
|
|
|
GAPBETWEEN + (100 - percentedit) * (cp->width + GAPBETWEEN) / 100;
|
2001-05-06 14:35:20 +00:00
|
|
|
lwid = rpos - 2 * GAPBETWEEN;
|
2000-10-18 15:36:32 +00:00
|
|
|
rwid = cp->width + GAPBETWEEN - rpos;
|
|
|
|
|
2001-05-06 14:35:20 +00:00
|
|
|
r.left = GAPBETWEEN;
|
|
|
|
r.top = cp->ypos + (height - STATICHEIGHT) / 2;
|
|
|
|
r.right = lwid;
|
|
|
|
r.bottom = STATICHEIGHT;
|
2000-10-18 15:36:32 +00:00
|
|
|
doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0, stext, sid);
|
|
|
|
|
2001-05-06 14:35:20 +00:00
|
|
|
r.left = rpos;
|
|
|
|
r.top = cp->ypos + (height - EDITHEIGHT) / 2;
|
|
|
|
r.right = rwid;
|
|
|
|
r.bottom = EDITHEIGHT;
|
2000-10-18 15:36:32 +00:00
|
|
|
doctl(cp, r, "EDIT",
|
2019-09-08 19:29:00 +00:00
|
|
|
WS_CHILD | WS_VISIBLE | WS_TABSTOP | ES_AUTOHSCROLL | style,
|
|
|
|
WS_EX_CLIENTEDGE, "", eid);
|
2000-10-18 15:36:32 +00:00
|
|
|
|
|
|
|
cp->ypos += height + GAPBETWEEN;
|
|
|
|
}
|
|
|
|
|
2000-10-19 15:43:08 +00:00
|
|
|
void staticedit(struct ctlpos *cp, char *stext,
|
2019-09-08 19:29:00 +00:00
|
|
|
int sid, int eid, int percentedit)
|
2001-05-06 14:35:20 +00:00
|
|
|
{
|
2000-10-19 15:43:08 +00:00
|
|
|
staticedit_internal(cp, stext, sid, eid, percentedit, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
void staticpassedit(struct ctlpos *cp, char *stext,
|
2019-09-08 19:29:00 +00:00
|
|
|
int sid, int eid, int percentedit)
|
2001-05-06 14:35:20 +00:00
|
|
|
{
|
2000-10-19 15:43:08 +00:00
|
|
|
staticedit_internal(cp, stext, sid, eid, percentedit, ES_PASSWORD);
|
|
|
|
}
|
|
|
|
|
2002-09-08 13:28:38 +00:00
|
|
|
/*
|
|
|
|
* A drop-down list box on the right hand side, with a static to
|
|
|
|
* its left.
|
|
|
|
*/
|
|
|
|
void staticddl(struct ctlpos *cp, char *stext,
|
2019-09-08 19:29:00 +00:00
|
|
|
int sid, int lid, int percentlist)
|
2002-09-08 13:28:38 +00:00
|
|
|
{
|
|
|
|
const int height = (COMBOHEIGHT > STATICHEIGHT ?
|
2019-09-08 19:29:00 +00:00
|
|
|
COMBOHEIGHT : STATICHEIGHT);
|
2002-09-08 13:28:38 +00:00
|
|
|
RECT r;
|
|
|
|
int lwid, rwid, rpos;
|
|
|
|
|
|
|
|
rpos =
|
2019-09-08 19:29:00 +00:00
|
|
|
GAPBETWEEN + (100 - percentlist) * (cp->width + GAPBETWEEN) / 100;
|
2002-09-08 13:28:38 +00:00
|
|
|
lwid = rpos - 2 * GAPBETWEEN;
|
|
|
|
rwid = cp->width + GAPBETWEEN - rpos;
|
|
|
|
|
|
|
|
r.left = GAPBETWEEN;
|
|
|
|
r.top = cp->ypos + (height - STATICHEIGHT) / 2;
|
|
|
|
r.right = lwid;
|
|
|
|
r.bottom = STATICHEIGHT;
|
|
|
|
doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0, stext, sid);
|
|
|
|
|
|
|
|
r.left = rpos;
|
|
|
|
r.top = cp->ypos + (height - EDITHEIGHT) / 2;
|
|
|
|
r.right = rwid;
|
|
|
|
r.bottom = COMBOHEIGHT*4;
|
|
|
|
doctl(cp, r, "COMBOBOX",
|
2019-09-08 19:29:00 +00:00
|
|
|
WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_VSCROLL |
|
|
|
|
CBS_DROPDOWNLIST | CBS_HASSTRINGS, WS_EX_CLIENTEDGE, "", lid);
|
2002-09-08 13:28:38 +00:00
|
|
|
|
|
|
|
cp->ypos += height + GAPBETWEEN;
|
|
|
|
}
|
|
|
|
|
2003-03-05 22:07:40 +00:00
|
|
|
/*
|
|
|
|
* A combo box on the right hand side, with a static to its left.
|
|
|
|
*/
|
|
|
|
void staticcombo(struct ctlpos *cp, char *stext,
|
2019-09-08 19:29:00 +00:00
|
|
|
int sid, int lid, int percentlist)
|
2003-03-05 22:07:40 +00:00
|
|
|
{
|
|
|
|
const int height = (COMBOHEIGHT > STATICHEIGHT ?
|
2019-09-08 19:29:00 +00:00
|
|
|
COMBOHEIGHT : STATICHEIGHT);
|
2003-03-05 22:07:40 +00:00
|
|
|
RECT r;
|
|
|
|
int lwid, rwid, rpos;
|
|
|
|
|
|
|
|
rpos =
|
2019-09-08 19:29:00 +00:00
|
|
|
GAPBETWEEN + (100 - percentlist) * (cp->width + GAPBETWEEN) / 100;
|
2003-03-05 22:07:40 +00:00
|
|
|
lwid = rpos - 2 * GAPBETWEEN;
|
|
|
|
rwid = cp->width + GAPBETWEEN - rpos;
|
|
|
|
|
|
|
|
r.left = GAPBETWEEN;
|
|
|
|
r.top = cp->ypos + (height - STATICHEIGHT) / 2;
|
|
|
|
r.right = lwid;
|
|
|
|
r.bottom = STATICHEIGHT;
|
|
|
|
doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0, stext, sid);
|
|
|
|
|
|
|
|
r.left = rpos;
|
|
|
|
r.top = cp->ypos + (height - EDITHEIGHT) / 2;
|
|
|
|
r.right = rwid;
|
|
|
|
r.bottom = COMBOHEIGHT*10;
|
|
|
|
doctl(cp, r, "COMBOBOX",
|
2019-09-08 19:29:00 +00:00
|
|
|
WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_VSCROLL |
|
|
|
|
CBS_DROPDOWN | CBS_HASSTRINGS, WS_EX_CLIENTEDGE, "", lid);
|
2003-03-05 22:07:40 +00:00
|
|
|
|
|
|
|
cp->ypos += height + GAPBETWEEN;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* A static, with a full-width drop-down list box below it.
|
|
|
|
*/
|
|
|
|
void staticddlbig(struct ctlpos *cp, char *stext,
|
2019-09-08 19:29:00 +00:00
|
|
|
int sid, int lid)
|
2003-03-05 22:07:40 +00:00
|
|
|
{
|
|
|
|
RECT r;
|
|
|
|
|
2005-04-11 16:23:35 +00:00
|
|
|
if (stext) {
|
2019-09-08 19:29:00 +00:00
|
|
|
r.left = GAPBETWEEN;
|
|
|
|
r.top = cp->ypos;
|
|
|
|
r.right = cp->width;
|
|
|
|
r.bottom = STATICHEIGHT;
|
|
|
|
doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0, stext, sid);
|
|
|
|
cp->ypos += STATICHEIGHT;
|
2005-04-11 16:23:35 +00:00
|
|
|
}
|
2003-03-05 22:07:40 +00:00
|
|
|
|
|
|
|
r.left = GAPBETWEEN;
|
|
|
|
r.top = cp->ypos;
|
|
|
|
r.right = cp->width;
|
|
|
|
r.bottom = COMBOHEIGHT*4;
|
|
|
|
doctl(cp, r, "COMBOBOX",
|
2019-09-08 19:29:00 +00:00
|
|
|
WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_VSCROLL |
|
|
|
|
CBS_DROPDOWNLIST | CBS_HASSTRINGS, WS_EX_CLIENTEDGE, "", lid);
|
2003-03-05 22:07:40 +00:00
|
|
|
cp->ypos += COMBOHEIGHT + GAPBETWEEN;
|
|
|
|
}
|
|
|
|
|
2000-10-19 15:43:08 +00:00
|
|
|
/*
|
|
|
|
* A big multiline edit control with a static labelling it.
|
|
|
|
*/
|
|
|
|
void bigeditctrl(struct ctlpos *cp, char *stext,
|
2019-09-08 19:29:00 +00:00
|
|
|
int sid, int eid, int lines)
|
2001-05-06 14:35:20 +00:00
|
|
|
{
|
2000-10-19 15:43:08 +00:00
|
|
|
RECT r;
|
|
|
|
|
2005-04-11 16:23:35 +00:00
|
|
|
if (stext) {
|
2019-09-08 19:29:00 +00:00
|
|
|
r.left = GAPBETWEEN;
|
|
|
|
r.top = cp->ypos;
|
|
|
|
r.right = cp->width;
|
|
|
|
r.bottom = STATICHEIGHT;
|
|
|
|
cp->ypos += r.bottom + GAPWITHIN;
|
|
|
|
doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0, stext, sid);
|
2005-04-11 16:23:35 +00:00
|
|
|
}
|
2000-10-19 15:43:08 +00:00
|
|
|
|
2001-05-06 14:35:20 +00:00
|
|
|
r.left = GAPBETWEEN;
|
|
|
|
r.top = cp->ypos;
|
|
|
|
r.right = cp->width;
|
|
|
|
r.bottom = EDITHEIGHT + (lines - 1) * STATICHEIGHT;
|
2000-10-19 15:43:08 +00:00
|
|
|
cp->ypos += r.bottom + GAPBETWEEN;
|
|
|
|
doctl(cp, r, "EDIT",
|
2019-09-08 19:29:00 +00:00
|
|
|
WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_VSCROLL | ES_MULTILINE,
|
|
|
|
WS_EX_CLIENTEDGE, "", eid);
|
2000-10-19 15:43:08 +00:00
|
|
|
}
|
|
|
|
|
2003-03-05 22:07:40 +00:00
|
|
|
/*
|
|
|
|
* A list box with a static labelling it.
|
|
|
|
*/
|
|
|
|
void listbox(struct ctlpos *cp, char *stext,
|
2019-09-08 19:29:00 +00:00
|
|
|
int sid, int lid, int lines, bool multi)
|
2003-03-05 22:07:40 +00:00
|
|
|
{
|
|
|
|
RECT r;
|
|
|
|
|
|
|
|
if (stext != NULL) {
|
2019-09-08 19:29:00 +00:00
|
|
|
r.left = GAPBETWEEN;
|
|
|
|
r.top = cp->ypos;
|
|
|
|
r.right = cp->width;
|
|
|
|
r.bottom = STATICHEIGHT;
|
|
|
|
cp->ypos += r.bottom + GAPWITHIN;
|
|
|
|
doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0, stext, sid);
|
2003-03-05 22:07:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
r.left = GAPBETWEEN;
|
|
|
|
r.top = cp->ypos;
|
|
|
|
r.right = cp->width;
|
|
|
|
r.bottom = LISTHEIGHT + (lines - 1) * LISTINCREMENT;
|
|
|
|
cp->ypos += r.bottom + GAPBETWEEN;
|
|
|
|
doctl(cp, r, "LISTBOX",
|
2019-09-08 19:29:00 +00:00
|
|
|
WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_VSCROLL |
|
|
|
|
LBS_NOTIFY | LBS_HASSTRINGS | LBS_USETABSTOPS |
|
|
|
|
(multi ? LBS_MULTIPLESEL : 0),
|
|
|
|
WS_EX_CLIENTEDGE, "", lid);
|
2003-03-05 22:07:40 +00:00
|
|
|
}
|
|
|
|
|
2000-10-18 15:36:32 +00:00
|
|
|
/*
|
|
|
|
* A tab-control substitute when a real tab control is unavailable.
|
|
|
|
*/
|
2001-05-06 14:35:20 +00:00
|
|
|
void ersatztab(struct ctlpos *cp, char *stext, int sid, int lid, int s2id)
|
|
|
|
{
|
2000-10-18 15:36:32 +00:00
|
|
|
const int height = (COMBOHEIGHT > STATICHEIGHT ?
|
2019-09-08 19:29:00 +00:00
|
|
|
COMBOHEIGHT : STATICHEIGHT);
|
2000-10-18 15:36:32 +00:00
|
|
|
RECT r;
|
|
|
|
int bigwid, lwid, rwid, rpos;
|
|
|
|
static const int BIGGAP = 15;
|
|
|
|
static const int MEDGAP = 3;
|
|
|
|
|
2001-05-06 14:35:20 +00:00
|
|
|
bigwid = cp->width + 2 * GAPBETWEEN - 2 * BIGGAP;
|
2000-10-18 15:36:32 +00:00
|
|
|
cp->ypos += MEDGAP;
|
|
|
|
rpos = BIGGAP + (bigwid + BIGGAP) / 2;
|
2001-05-06 14:35:20 +00:00
|
|
|
lwid = rpos - 2 * BIGGAP;
|
2000-10-18 15:36:32 +00:00
|
|
|
rwid = bigwid + BIGGAP - rpos;
|
|
|
|
|
2001-05-06 14:35:20 +00:00
|
|
|
r.left = BIGGAP;
|
|
|
|
r.top = cp->ypos + (height - STATICHEIGHT) / 2;
|
|
|
|
r.right = lwid;
|
|
|
|
r.bottom = STATICHEIGHT;
|
2000-10-18 15:36:32 +00:00
|
|
|
doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0, stext, sid);
|
|
|
|
|
2001-05-06 14:35:20 +00:00
|
|
|
r.left = rpos;
|
|
|
|
r.top = cp->ypos + (height - COMBOHEIGHT) / 2;
|
|
|
|
r.right = rwid;
|
|
|
|
r.bottom = COMBOHEIGHT * 10;
|
2000-10-18 15:36:32 +00:00
|
|
|
doctl(cp, r, "COMBOBOX",
|
2019-09-08 19:29:00 +00:00
|
|
|
WS_CHILD | WS_VISIBLE | WS_TABSTOP |
|
|
|
|
CBS_DROPDOWNLIST | CBS_HASSTRINGS, WS_EX_CLIENTEDGE, "", lid);
|
2000-10-18 15:36:32 +00:00
|
|
|
|
|
|
|
cp->ypos += height + MEDGAP + GAPBETWEEN;
|
|
|
|
|
2001-05-06 14:35:20 +00:00
|
|
|
r.left = GAPBETWEEN;
|
|
|
|
r.top = cp->ypos;
|
|
|
|
r.right = cp->width;
|
|
|
|
r.bottom = 2;
|
2000-10-18 15:36:32 +00:00
|
|
|
doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE | SS_ETCHEDHORZ,
|
2019-09-08 19:29:00 +00:00
|
|
|
0, "", s2id);
|
2000-10-18 15:36:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* A static line, followed by an edit control on the left hand side
|
|
|
|
* and a button on the right.
|
|
|
|
*/
|
|
|
|
void editbutton(struct ctlpos *cp, char *stext, int sid,
|
2019-09-08 19:29:00 +00:00
|
|
|
int eid, char *btext, int bid)
|
2001-05-06 14:35:20 +00:00
|
|
|
{
|
2000-10-18 15:36:32 +00:00
|
|
|
const int height = (EDITHEIGHT > PUSHBTNHEIGHT ?
|
2019-09-08 19:29:00 +00:00
|
|
|
EDITHEIGHT : PUSHBTNHEIGHT);
|
2000-10-18 15:36:32 +00:00
|
|
|
RECT r;
|
|
|
|
int lwid, rwid, rpos;
|
|
|
|
|
2001-05-06 14:35:20 +00:00
|
|
|
r.left = GAPBETWEEN;
|
|
|
|
r.top = cp->ypos;
|
|
|
|
r.right = cp->width;
|
|
|
|
r.bottom = STATICHEIGHT;
|
2000-10-18 15:36:32 +00:00
|
|
|
cp->ypos += r.bottom + GAPWITHIN;
|
|
|
|
doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0, stext, sid);
|
|
|
|
|
|
|
|
rpos = GAPBETWEEN + 3 * (cp->width + GAPBETWEEN) / 4;
|
2001-05-06 14:35:20 +00:00
|
|
|
lwid = rpos - 2 * GAPBETWEEN;
|
2000-10-18 15:36:32 +00:00
|
|
|
rwid = cp->width + GAPBETWEEN - rpos;
|
|
|
|
|
2001-05-06 14:35:20 +00:00
|
|
|
r.left = GAPBETWEEN;
|
|
|
|
r.top = cp->ypos + (height - EDITHEIGHT) / 2;
|
|
|
|
r.right = lwid;
|
|
|
|
r.bottom = EDITHEIGHT;
|
2000-10-18 15:36:32 +00:00
|
|
|
doctl(cp, r, "EDIT",
|
2019-09-08 19:29:00 +00:00
|
|
|
WS_CHILD | WS_VISIBLE | WS_TABSTOP | ES_AUTOHSCROLL,
|
|
|
|
WS_EX_CLIENTEDGE, "", eid);
|
2000-10-18 15:36:32 +00:00
|
|
|
|
2001-05-06 14:35:20 +00:00
|
|
|
r.left = rpos;
|
|
|
|
r.top = cp->ypos + (height - PUSHBTNHEIGHT) / 2;
|
|
|
|
r.right = rwid;
|
|
|
|
r.bottom = PUSHBTNHEIGHT;
|
2000-10-18 15:36:32 +00:00
|
|
|
doctl(cp, r, "BUTTON",
|
2019-09-08 19:29:00 +00:00
|
|
|
BS_NOTIFY | WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_PUSHBUTTON,
|
|
|
|
0, btext, bid);
|
2000-10-18 15:36:32 +00:00
|
|
|
|
|
|
|
cp->ypos += height + GAPBETWEEN;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2003-03-05 22:07:40 +00:00
|
|
|
* A special control for manipulating an ordered preference list
|
|
|
|
* (eg. for cipher selection).
|
|
|
|
* XXX: this is a rough hack and could be improved.
|
2000-10-18 15:36:32 +00:00
|
|
|
*/
|
2003-03-05 22:07:40 +00:00
|
|
|
void prefslist(struct prefslist *hdl, struct ctlpos *cp, int lines,
|
2019-09-08 19:29:00 +00:00
|
|
|
char *stext, int sid, int listid, int upbid, int dnbid)
|
2001-05-06 14:35:20 +00:00
|
|
|
{
|
2003-03-05 22:07:40 +00:00
|
|
|
const static int percents[] = { 5, 75, 20 };
|
2000-10-18 15:36:32 +00:00
|
|
|
RECT r;
|
2003-03-05 22:07:40 +00:00
|
|
|
int xpos, percent = 0, i;
|
|
|
|
int listheight = LISTHEIGHT + (lines - 1) * LISTINCREMENT;
|
|
|
|
const int BTNSHEIGHT = 2*PUSHBTNHEIGHT + GAPBETWEEN;
|
|
|
|
int totalheight, buttonpos;
|
2000-10-18 15:36:32 +00:00
|
|
|
|
2003-03-05 22:07:40 +00:00
|
|
|
/* Squirrel away IDs. */
|
|
|
|
hdl->listid = listid;
|
|
|
|
hdl->upbid = upbid;
|
|
|
|
hdl->dnbid = dnbid;
|
2000-10-18 15:36:32 +00:00
|
|
|
|
2003-03-05 22:07:40 +00:00
|
|
|
/* The static label. */
|
|
|
|
if (stext != NULL) {
|
2019-09-08 19:29:00 +00:00
|
|
|
r.left = GAPBETWEEN;
|
|
|
|
r.top = cp->ypos;
|
|
|
|
r.right = cp->width;
|
|
|
|
r.bottom = STATICHEIGHT;
|
|
|
|
cp->ypos += r.bottom + GAPWITHIN;
|
|
|
|
doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0, stext, sid);
|
2000-10-18 15:36:32 +00:00
|
|
|
}
|
|
|
|
|
2003-03-05 22:07:40 +00:00
|
|
|
if (listheight > BTNSHEIGHT) {
|
|
|
|
totalheight = listheight;
|
2019-09-08 19:29:00 +00:00
|
|
|
buttonpos = (listheight - BTNSHEIGHT) / 2;
|
2003-03-05 22:07:40 +00:00
|
|
|
} else {
|
|
|
|
totalheight = BTNSHEIGHT;
|
2019-09-08 19:29:00 +00:00
|
|
|
buttonpos = 0;
|
2001-08-25 19:33:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
for (i=0; i<3; i++) {
|
|
|
|
int left, wid;
|
|
|
|
xpos = (cp->width + GAPBETWEEN) * percent / 100;
|
|
|
|
left = xpos + GAPBETWEEN;
|
|
|
|
percent += percents[i];
|
|
|
|
xpos = (cp->width + GAPBETWEEN) * percent / 100;
|
|
|
|
wid = xpos - left;
|
|
|
|
|
|
|
|
switch (i) {
|
Formatting change to braces around one case of a switch.
Sometimes, within a switch statement, you want to declare local
variables specific to the handler for one particular case. Until now
I've mostly been writing this in the form
switch (discriminant) {
case SIMPLE:
do stuff;
break;
case COMPLICATED:
{
declare variables;
do stuff;
}
break;
}
which is ugly because the two pieces of essentially similar code
appear at different indent levels, and also inconvenient because you
have less horizontal space available to write the complicated case
handler in - particuarly undesirable because _complicated_ case
handlers are the ones most likely to need all the space they can get!
After encountering a rather nicer idiom in the LLVM source code, and
after a bit of hackery this morning figuring out how to persuade
Emacs's auto-indent to do what I wanted with it, I've decided to move
to an idiom in which the open brace comes right after the case
statement, and the code within it is indented the same as it would
have been without the brace. Then the whole case handler (including
the break) lives inside those braces, and you get something that looks
more like this:
switch (discriminant) {
case SIMPLE:
do stuff;
break;
case COMPLICATED: {
declare variables;
do stuff;
break;
}
}
This commit is a big-bang change that reformats all the complicated
case handlers I could find into the new layout. This is particularly
nice in the Pageant main function, in which almost _every_ case
handler had a bundle of variables and was long and complicated. (In
fact that's what motivated me to get round to this.) Some of the
innermost parts of the terminal escape-sequence handling are also
breathing a bit easier now the horizontal pressure on them is
relieved.
(Also, in a few cases, I was able to remove the extra braces
completely, because the only variable local to the case handler was a
loop variable which our new C99 policy allows me to move into the
initialiser clause of its for statement.)
Viewed with whitespace ignored, this is not too disruptive a change.
Downstream patches that conflict with it may need to be reapplied
using --ignore-whitespace or similar.
2020-02-16 07:49:52 +00:00
|
|
|
case 1: {
|
2001-08-25 19:33:33 +00:00
|
|
|
/* The drag list box. */
|
|
|
|
r.left = left; r.right = wid;
|
2003-03-05 22:07:40 +00:00
|
|
|
r.top = cp->ypos; r.bottom = listheight;
|
Formatting change to braces around one case of a switch.
Sometimes, within a switch statement, you want to declare local
variables specific to the handler for one particular case. Until now
I've mostly been writing this in the form
switch (discriminant) {
case SIMPLE:
do stuff;
break;
case COMPLICATED:
{
declare variables;
do stuff;
}
break;
}
which is ugly because the two pieces of essentially similar code
appear at different indent levels, and also inconvenient because you
have less horizontal space available to write the complicated case
handler in - particuarly undesirable because _complicated_ case
handlers are the ones most likely to need all the space they can get!
After encountering a rather nicer idiom in the LLVM source code, and
after a bit of hackery this morning figuring out how to persuade
Emacs's auto-indent to do what I wanted with it, I've decided to move
to an idiom in which the open brace comes right after the case
statement, and the code within it is indented the same as it would
have been without the brace. Then the whole case handler (including
the break) lives inside those braces, and you get something that looks
more like this:
switch (discriminant) {
case SIMPLE:
do stuff;
break;
case COMPLICATED: {
declare variables;
do stuff;
break;
}
}
This commit is a big-bang change that reformats all the complicated
case handlers I could find into the new layout. This is particularly
nice in the Pageant main function, in which almost _every_ case
handler had a bundle of variables and was long and complicated. (In
fact that's what motivated me to get round to this.) Some of the
innermost parts of the terminal escape-sequence handling are also
breathing a bit easier now the horizontal pressure on them is
relieved.
(Also, in a few cases, I was able to remove the extra braces
completely, because the only variable local to the case handler was a
loop variable which our new C99 policy allows me to move into the
initialiser clause of its for statement.)
Viewed with whitespace ignored, this is not too disruptive a change.
Downstream patches that conflict with it may need to be reapplied
using --ignore-whitespace or similar.
2020-02-16 07:49:52 +00:00
|
|
|
HWND ctl = doctl(cp, r, "LISTBOX",
|
|
|
|
WS_CHILD | WS_VISIBLE | WS_TABSTOP |
|
|
|
|
WS_VSCROLL | LBS_HASSTRINGS | LBS_USETABSTOPS,
|
|
|
|
WS_EX_CLIENTEDGE,
|
|
|
|
"", listid);
|
|
|
|
p_MakeDragList(ctl);
|
2001-08-25 19:33:33 +00:00
|
|
|
break;
|
Formatting change to braces around one case of a switch.
Sometimes, within a switch statement, you want to declare local
variables specific to the handler for one particular case. Until now
I've mostly been writing this in the form
switch (discriminant) {
case SIMPLE:
do stuff;
break;
case COMPLICATED:
{
declare variables;
do stuff;
}
break;
}
which is ugly because the two pieces of essentially similar code
appear at different indent levels, and also inconvenient because you
have less horizontal space available to write the complicated case
handler in - particuarly undesirable because _complicated_ case
handlers are the ones most likely to need all the space they can get!
After encountering a rather nicer idiom in the LLVM source code, and
after a bit of hackery this morning figuring out how to persuade
Emacs's auto-indent to do what I wanted with it, I've decided to move
to an idiom in which the open brace comes right after the case
statement, and the code within it is indented the same as it would
have been without the brace. Then the whole case handler (including
the break) lives inside those braces, and you get something that looks
more like this:
switch (discriminant) {
case SIMPLE:
do stuff;
break;
case COMPLICATED: {
declare variables;
do stuff;
break;
}
}
This commit is a big-bang change that reformats all the complicated
case handlers I could find into the new layout. This is particularly
nice in the Pageant main function, in which almost _every_ case
handler had a bundle of variables and was long and complicated. (In
fact that's what motivated me to get round to this.) Some of the
innermost parts of the terminal escape-sequence handling are also
breathing a bit easier now the horizontal pressure on them is
relieved.
(Also, in a few cases, I was able to remove the extra braces
completely, because the only variable local to the case handler was a
loop variable which our new C99 policy allows me to move into the
initialiser clause of its for statement.)
Viewed with whitespace ignored, this is not too disruptive a change.
Downstream patches that conflict with it may need to be reapplied
using --ignore-whitespace or similar.
2020-02-16 07:49:52 +00:00
|
|
|
}
|
2001-08-25 19:33:33 +00:00
|
|
|
|
|
|
|
case 2:
|
|
|
|
/* The "Up" and "Down" buttons. */
|
2019-09-08 19:29:00 +00:00
|
|
|
/* XXX worry about accelerators if we have more than one
|
|
|
|
* prefslist on a panel */
|
2001-08-25 19:33:33 +00:00
|
|
|
r.left = left; r.right = wid;
|
2003-03-05 22:07:40 +00:00
|
|
|
r.top = cp->ypos + buttonpos; r.bottom = PUSHBTNHEIGHT;
|
2001-08-25 19:33:33 +00:00
|
|
|
doctl(cp, r, "BUTTON",
|
2003-03-05 22:07:40 +00:00
|
|
|
BS_NOTIFY | WS_CHILD | WS_VISIBLE |
|
2019-09-08 19:29:00 +00:00
|
|
|
WS_TABSTOP | BS_PUSHBUTTON,
|
2001-08-25 19:33:33 +00:00
|
|
|
0, "&Up", upbid);
|
|
|
|
|
|
|
|
r.left = left; r.right = wid;
|
2003-03-05 22:07:40 +00:00
|
|
|
r.top = cp->ypos + buttonpos + PUSHBTNHEIGHT + GAPBETWEEN;
|
2001-08-25 19:33:33 +00:00
|
|
|
r.bottom = PUSHBTNHEIGHT;
|
|
|
|
doctl(cp, r, "BUTTON",
|
2003-03-05 22:07:40 +00:00
|
|
|
BS_NOTIFY | WS_CHILD | WS_VISIBLE |
|
2019-09-08 19:29:00 +00:00
|
|
|
WS_TABSTOP | BS_PUSHBUTTON,
|
2001-08-25 19:33:33 +00:00
|
|
|
0, "&Down", dnbid);
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
cp->ypos += totalheight + GAPBETWEEN;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Helper function for prefslist: move item in list box.
|
|
|
|
*/
|
|
|
|
static void pl_moveitem(HWND hwnd, int listid, int src, int dst)
|
|
|
|
{
|
|
|
|
int tlen, val;
|
|
|
|
char *txt;
|
|
|
|
/* Get the item's data. */
|
|
|
|
tlen = SendDlgItemMessage (hwnd, listid, LB_GETTEXTLEN, src, 0);
|
2003-03-29 16:14:26 +00:00
|
|
|
txt = snewn(tlen+1, char);
|
2001-08-25 19:33:33 +00:00
|
|
|
SendDlgItemMessage (hwnd, listid, LB_GETTEXT, src, (LPARAM) txt);
|
|
|
|
val = SendDlgItemMessage (hwnd, listid, LB_GETITEMDATA, src, 0);
|
|
|
|
/* Deselect old location. */
|
2018-10-29 19:50:29 +00:00
|
|
|
SendDlgItemMessage (hwnd, listid, LB_SETSEL, false, src);
|
2001-08-25 19:33:33 +00:00
|
|
|
/* Delete it at the old location. */
|
|
|
|
SendDlgItemMessage (hwnd, listid, LB_DELETESTRING, src, 0);
|
|
|
|
/* Insert it at new location. */
|
|
|
|
SendDlgItemMessage (hwnd, listid, LB_INSERTSTRING, dst,
|
2019-09-08 19:29:00 +00:00
|
|
|
(LPARAM) txt);
|
2001-08-25 19:33:33 +00:00
|
|
|
SendDlgItemMessage (hwnd, listid, LB_SETITEMDATA, dst,
|
2019-09-08 19:29:00 +00:00
|
|
|
(LPARAM) val);
|
2001-08-25 19:33:33 +00:00
|
|
|
/* Set selection. */
|
|
|
|
SendDlgItemMessage (hwnd, listid, LB_SETCURSEL, dst, 0);
|
|
|
|
sfree (txt);
|
|
|
|
}
|
|
|
|
|
Convert a lot of 'int' variables to 'bool'.
My normal habit these days, in new code, is to treat int and bool as
_almost_ completely separate types. I'm still willing to use C's
implicit test for zero on an integer (e.g. 'if (!blob.len)' is fine,
no need to spell it out as blob.len != 0), but generally, if a
variable is going to be conceptually a boolean, I like to declare it
bool and assign to it using 'true' or 'false' rather than 0 or 1.
PuTTY is an exception, because it predates the C99 bool, and I've
stuck to its existing coding style even when adding new code to it.
But it's been annoying me more and more, so now that I've decided C99
bool is an acceptable thing to require from our toolchain in the first
place, here's a quite thorough trawl through the source doing
'boolification'. Many variables and function parameters are now typed
as bool rather than int; many assignments of 0 or 1 to those variables
are now spelled 'true' or 'false'.
I managed this thorough conversion with the help of a custom clang
plugin that I wrote to trawl the AST and apply heuristics to point out
where things might want changing. So I've even managed to do a decent
job on parts of the code I haven't looked at in years!
To make the plugin's work easier, I pushed platform front ends
generally in the direction of using standard 'bool' in preference to
platform-specific boolean types like Windows BOOL or GTK's gboolean;
I've left the platform booleans in places they _have_ to be for the
platform APIs to work right, but variables only used by my own code
have been converted wherever I found them.
In a few places there are int values that look very like booleans in
_most_ of the places they're used, but have a rarely-used third value,
or a distinction between different nonzero values that most users
don't care about. In these cases, I've _removed_ uses of 'true' and
'false' for the return values, to emphasise that there's something
more subtle going on than a simple boolean answer:
- the 'multisel' field in dialog.h's list box structure, for which
the GTK front end in particular recognises a difference between 1
and 2 but nearly everything else treats as boolean
- the 'urgent' parameter to plug_receive, where 1 vs 2 tells you
something about the specific location of the urgent pointer, but
most clients only care about 0 vs 'something nonzero'
- the return value of wc_match, where -1 indicates a syntax error in
the wildcard.
- the return values from SSH-1 RSA-key loading functions, which use
-1 for 'wrong passphrase' and 0 for all other failures (so any
caller which already knows it's not loading an _encrypted private_
key can treat them as boolean)
- term->esc_query, and the 'query' parameter in toggle_mode in
terminal.c, which _usually_ hold 0 for ESC[123h or 1 for ESC[?123h,
but can also hold -1 for some other intervening character that we
don't support.
In a few places there's an integer that I haven't turned into a bool
even though it really _can_ only take values 0 or 1 (and, as above,
tried to make the call sites consistent in not calling those values
true and false), on the grounds that I thought it would make it more
confusing to imply that the 0 value was in some sense 'negative' or
bad and the 1 positive or good:
- the return value of plug_accepting uses the POSIXish convention of
0=success and nonzero=error; I think if I made it bool then I'd
also want to reverse its sense, and that's a job for a separate
piece of work.
- the 'screen' parameter to lineptr() in terminal.c, where 0 and 1
represent the default and alternate screens. There's no obvious
reason why one of those should be considered 'true' or 'positive'
or 'success' - they're just indices - so I've left it as int.
ssh_scp_recv had particularly confusing semantics for its previous int
return value: its call sites used '<= 0' to check for error, but it
never actually returned a negative number, just 0 or 1. Now the
function and its call sites agree that it's a bool.
In a couple of places I've renamed variables called 'ret', because I
don't like that name any more - it's unclear whether it means the
return value (in preparation) for the _containing_ function or the
return value received from a subroutine call, and occasionally I've
accidentally used the same variable for both and introduced a bug. So
where one of those got in my way, I've renamed it to 'toret' or 'retd'
(the latter short for 'returned') in line with my usual modern
practice, but I haven't done a thorough job of finding all of them.
Finally, one amusing side effect of doing this is that I've had to
separate quite a few chained assignments. It used to be perfectly fine
to write 'a = b = c = TRUE' when a,b,c were int and TRUE was just a
the 'true' defined by stdbool.h, that idiom provokes a warning from
gcc: 'suggest parentheses around assignment used as truth value'!
2018-11-02 19:23:19 +00:00
|
|
|
int pl_itemfrompt(HWND hwnd, POINT cursor, bool scroll)
|
2001-08-25 19:33:33 +00:00
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
POINT uppoint, downpoint;
|
|
|
|
int updist, downdist, upitem, downitem, i;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Ghastly hackery to try to figure out not which
|
|
|
|
* _item_, but which _gap between items_, the user
|
|
|
|
* is pointing at. We do this by first working out
|
|
|
|
* which list item is under the cursor, and then
|
|
|
|
* working out how far the cursor would have to
|
|
|
|
* move up or down before the answer was different.
|
|
|
|
* Then we put the insertion point _above_ the
|
|
|
|
* current item if the upper edge is closer than
|
|
|
|
* the lower edge, or _below_ it if vice versa.
|
|
|
|
*/
|
2017-03-13 21:42:44 +00:00
|
|
|
ret = p_LBItemFromPt(hwnd, cursor, scroll);
|
2001-08-25 19:33:33 +00:00
|
|
|
if (ret == -1)
|
2019-09-08 19:29:00 +00:00
|
|
|
return ret;
|
2018-10-29 19:50:29 +00:00
|
|
|
ret = p_LBItemFromPt(hwnd, cursor, false);
|
2001-08-25 19:33:33 +00:00
|
|
|
updist = downdist = 0;
|
|
|
|
for (i = 1; i < 4096 && (!updist || !downdist); i++) {
|
2019-09-08 19:29:00 +00:00
|
|
|
uppoint = downpoint = cursor;
|
|
|
|
uppoint.y -= i;
|
|
|
|
downpoint.y += i;
|
|
|
|
upitem = p_LBItemFromPt(hwnd, uppoint, false);
|
|
|
|
downitem = p_LBItemFromPt(hwnd, downpoint, false);
|
|
|
|
if (!updist && upitem != ret)
|
|
|
|
updist = i;
|
|
|
|
if (!downdist && downitem != ret)
|
|
|
|
downdist = i;
|
2001-08-25 19:33:33 +00:00
|
|
|
}
|
|
|
|
if (downdist < updist)
|
2019-09-08 19:29:00 +00:00
|
|
|
ret++;
|
2001-08-25 19:33:33 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Handler for prefslist above.
|
2019-09-08 19:29:00 +00:00
|
|
|
*
|
2003-03-05 22:07:40 +00:00
|
|
|
* Return value has bit 0 set if the dialog box procedure needs to
|
2018-10-29 19:50:29 +00:00
|
|
|
* return true from handling this message; it has bit 1 set if a
|
2003-03-05 22:07:40 +00:00
|
|
|
* change may have been made in the contents of the list.
|
2001-08-25 19:33:33 +00:00
|
|
|
*/
|
|
|
|
int handle_prefslist(struct prefslist *hdl,
|
|
|
|
int *array, int maxmemb,
|
Convert a lot of 'int' variables to 'bool'.
My normal habit these days, in new code, is to treat int and bool as
_almost_ completely separate types. I'm still willing to use C's
implicit test for zero on an integer (e.g. 'if (!blob.len)' is fine,
no need to spell it out as blob.len != 0), but generally, if a
variable is going to be conceptually a boolean, I like to declare it
bool and assign to it using 'true' or 'false' rather than 0 or 1.
PuTTY is an exception, because it predates the C99 bool, and I've
stuck to its existing coding style even when adding new code to it.
But it's been annoying me more and more, so now that I've decided C99
bool is an acceptable thing to require from our toolchain in the first
place, here's a quite thorough trawl through the source doing
'boolification'. Many variables and function parameters are now typed
as bool rather than int; many assignments of 0 or 1 to those variables
are now spelled 'true' or 'false'.
I managed this thorough conversion with the help of a custom clang
plugin that I wrote to trawl the AST and apply heuristics to point out
where things might want changing. So I've even managed to do a decent
job on parts of the code I haven't looked at in years!
To make the plugin's work easier, I pushed platform front ends
generally in the direction of using standard 'bool' in preference to
platform-specific boolean types like Windows BOOL or GTK's gboolean;
I've left the platform booleans in places they _have_ to be for the
platform APIs to work right, but variables only used by my own code
have been converted wherever I found them.
In a few places there are int values that look very like booleans in
_most_ of the places they're used, but have a rarely-used third value,
or a distinction between different nonzero values that most users
don't care about. In these cases, I've _removed_ uses of 'true' and
'false' for the return values, to emphasise that there's something
more subtle going on than a simple boolean answer:
- the 'multisel' field in dialog.h's list box structure, for which
the GTK front end in particular recognises a difference between 1
and 2 but nearly everything else treats as boolean
- the 'urgent' parameter to plug_receive, where 1 vs 2 tells you
something about the specific location of the urgent pointer, but
most clients only care about 0 vs 'something nonzero'
- the return value of wc_match, where -1 indicates a syntax error in
the wildcard.
- the return values from SSH-1 RSA-key loading functions, which use
-1 for 'wrong passphrase' and 0 for all other failures (so any
caller which already knows it's not loading an _encrypted private_
key can treat them as boolean)
- term->esc_query, and the 'query' parameter in toggle_mode in
terminal.c, which _usually_ hold 0 for ESC[123h or 1 for ESC[?123h,
but can also hold -1 for some other intervening character that we
don't support.
In a few places there's an integer that I haven't turned into a bool
even though it really _can_ only take values 0 or 1 (and, as above,
tried to make the call sites consistent in not calling those values
true and false), on the grounds that I thought it would make it more
confusing to imply that the 0 value was in some sense 'negative' or
bad and the 1 positive or good:
- the return value of plug_accepting uses the POSIXish convention of
0=success and nonzero=error; I think if I made it bool then I'd
also want to reverse its sense, and that's a job for a separate
piece of work.
- the 'screen' parameter to lineptr() in terminal.c, where 0 and 1
represent the default and alternate screens. There's no obvious
reason why one of those should be considered 'true' or 'positive'
or 'success' - they're just indices - so I've left it as int.
ssh_scp_recv had particularly confusing semantics for its previous int
return value: its call sites used '<= 0' to check for error, but it
never actually returned a negative number, just 0 or 1. Now the
function and its call sites agree that it's a bool.
In a couple of places I've renamed variables called 'ret', because I
don't like that name any more - it's unclear whether it means the
return value (in preparation) for the _containing_ function or the
return value received from a subroutine call, and occasionally I've
accidentally used the same variable for both and introduced a bug. So
where one of those got in my way, I've renamed it to 'toret' or 'retd'
(the latter short for 'returned') in line with my usual modern
practice, but I haven't done a thorough job of finding all of them.
Finally, one amusing side effect of doing this is that I've had to
separate quite a few chained assignments. It used to be perfectly fine
to write 'a = b = c = TRUE' when a,b,c were int and TRUE was just a
the 'true' defined by stdbool.h, that idiom provokes a warning from
gcc: 'suggest parentheses around assignment used as truth value'!
2018-11-02 19:23:19 +00:00
|
|
|
bool is_dlmsg, HWND hwnd,
|
2019-09-08 19:29:00 +00:00
|
|
|
WPARAM wParam, LPARAM lParam)
|
2001-08-25 19:33:33 +00:00
|
|
|
{
|
|
|
|
int i;
|
2003-03-05 22:07:40 +00:00
|
|
|
int ret = 0;
|
2001-08-25 19:33:33 +00:00
|
|
|
|
|
|
|
if (is_dlmsg) {
|
|
|
|
|
2001-08-28 08:08:43 +00:00
|
|
|
if ((int)wParam == hdl->listid) {
|
2001-08-25 19:33:33 +00:00
|
|
|
DRAGLISTINFO *dlm = (DRAGLISTINFO *)lParam;
|
2019-09-08 19:29:00 +00:00
|
|
|
int dest = 0; /* initialise to placate gcc */
|
2001-08-25 19:33:33 +00:00
|
|
|
switch (dlm->uNotification) {
|
|
|
|
case DL_BEGINDRAG:
|
2019-09-08 19:29:00 +00:00
|
|
|
/* Add a dummy item to make pl_itemfrompt() work
|
|
|
|
* better.
|
|
|
|
* FIXME: this causes scrollbar glitches if the count of
|
|
|
|
* listbox contains >= its height. */
|
|
|
|
hdl->dummyitem =
|
|
|
|
SendDlgItemMessage(hwnd, hdl->listid,
|
|
|
|
LB_ADDSTRING, 0, (LPARAM) "");
|
2001-08-25 19:33:33 +00:00
|
|
|
|
2018-10-29 19:50:29 +00:00
|
|
|
hdl->srcitem = p_LBItemFromPt(dlm->hWnd, dlm->ptCursor, true);
|
2019-09-08 19:29:00 +00:00
|
|
|
hdl->dragging = false;
|
|
|
|
/* XXX hack Q183115 */
|
|
|
|
SetWindowLongPtr(hwnd, DWLP_MSGRESULT, true);
|
2003-03-05 22:07:40 +00:00
|
|
|
ret |= 1; break;
|
2001-08-25 19:33:33 +00:00
|
|
|
case DL_CANCELDRAG:
|
2019-09-08 19:29:00 +00:00
|
|
|
p_DrawInsert(hwnd, dlm->hWnd, -1); /* Clear arrow */
|
|
|
|
SendDlgItemMessage(hwnd, hdl->listid,
|
|
|
|
LB_DELETESTRING, hdl->dummyitem, 0);
|
|
|
|
hdl->dragging = false;
|
2003-03-05 22:07:40 +00:00
|
|
|
ret |= 1; break;
|
2001-08-25 19:33:33 +00:00
|
|
|
case DL_DRAGGING:
|
2019-09-08 19:29:00 +00:00
|
|
|
hdl->dragging = true;
|
|
|
|
dest = pl_itemfrompt(dlm->hWnd, dlm->ptCursor, true);
|
|
|
|
if (dest > hdl->dummyitem) dest = hdl->dummyitem;
|
|
|
|
p_DrawInsert (hwnd, dlm->hWnd, dest);
|
|
|
|
if (dest >= 0)
|
|
|
|
SetWindowLongPtr(hwnd, DWLP_MSGRESULT, DL_MOVECURSOR);
|
|
|
|
else
|
|
|
|
SetWindowLongPtr(hwnd, DWLP_MSGRESULT, DL_STOPCURSOR);
|
2003-03-05 22:07:40 +00:00
|
|
|
ret |= 1; break;
|
2001-08-25 19:33:33 +00:00
|
|
|
case DL_DROPPED:
|
2019-09-08 19:29:00 +00:00
|
|
|
if (hdl->dragging) {
|
|
|
|
dest = pl_itemfrompt(dlm->hWnd, dlm->ptCursor, true);
|
|
|
|
if (dest > hdl->dummyitem) dest = hdl->dummyitem;
|
|
|
|
p_DrawInsert (hwnd, dlm->hWnd, -1);
|
|
|
|
}
|
|
|
|
SendDlgItemMessage(hwnd, hdl->listid,
|
|
|
|
LB_DELETESTRING, hdl->dummyitem, 0);
|
|
|
|
if (hdl->dragging) {
|
|
|
|
hdl->dragging = false;
|
|
|
|
if (dest >= 0) {
|
|
|
|
/* Correct for "missing" item. */
|
|
|
|
if (dest > hdl->srcitem) dest--;
|
|
|
|
pl_moveitem(hwnd, hdl->listid, hdl->srcitem, dest);
|
|
|
|
}
|
|
|
|
ret |= 2;
|
|
|
|
}
|
2003-03-05 22:07:40 +00:00
|
|
|
ret |= 1; break;
|
2001-08-25 19:33:33 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
if (((LOWORD(wParam) == hdl->upbid) ||
|
|
|
|
(LOWORD(wParam) == hdl->dnbid)) &&
|
|
|
|
((HIWORD(wParam) == BN_CLICKED) ||
|
|
|
|
(HIWORD(wParam) == BN_DOUBLECLICKED))) {
|
|
|
|
/* Move an item up or down the list. */
|
|
|
|
/* Get the current selection, if any. */
|
|
|
|
int selection = SendDlgItemMessage (hwnd, hdl->listid, LB_GETCURSEL, 0, 0);
|
|
|
|
if (selection == LB_ERR) {
|
|
|
|
MessageBeep(0);
|
|
|
|
} else {
|
|
|
|
int nitems;
|
|
|
|
/* Get the total number of items. */
|
|
|
|
nitems = SendDlgItemMessage (hwnd, hdl->listid, LB_GETCOUNT, 0, 0);
|
|
|
|
/* Should we do anything? */
|
2019-09-08 19:29:00 +00:00
|
|
|
if (LOWORD(wParam) == hdl->upbid && (selection > 0))
|
|
|
|
pl_moveitem(hwnd, hdl->listid, selection, selection - 1);
|
|
|
|
else if (LOWORD(wParam) == hdl->dnbid && (selection < nitems - 1))
|
|
|
|
pl_moveitem(hwnd, hdl->listid, selection, selection + 1);
|
|
|
|
ret |= 2;
|
2001-08-25 19:33:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2003-03-05 22:07:40 +00:00
|
|
|
if (array) {
|
2019-09-08 19:29:00 +00:00
|
|
|
/* Update array to match the list box. */
|
|
|
|
for (i=0; i < maxmemb; i++)
|
|
|
|
array[i] = SendDlgItemMessage (hwnd, hdl->listid, LB_GETITEMDATA,
|
|
|
|
i, 0);
|
2003-03-05 22:07:40 +00:00
|
|
|
}
|
2001-08-25 19:33:33 +00:00
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2000-10-19 15:43:08 +00:00
|
|
|
/*
|
|
|
|
* A progress bar (from Common Controls). We like our progress bars
|
|
|
|
* to be smooth and unbroken, without those ugly divisions; some
|
|
|
|
* older compilers may not support that, but that's life.
|
|
|
|
*/
|
2001-05-06 14:35:20 +00:00
|
|
|
void progressbar(struct ctlpos *cp, int id)
|
|
|
|
{
|
2000-10-19 15:43:08 +00:00
|
|
|
RECT r;
|
|
|
|
|
2001-05-06 14:35:20 +00:00
|
|
|
r.left = GAPBETWEEN;
|
|
|
|
r.top = cp->ypos;
|
|
|
|
r.right = cp->width;
|
|
|
|
r.bottom = PROGBARHEIGHT;
|
2000-10-19 15:43:08 +00:00
|
|
|
cp->ypos += r.bottom + GAPBETWEEN;
|
|
|
|
|
2001-05-06 14:35:20 +00:00
|
|
|
doctl(cp, r, PROGRESS_CLASS, WS_CHILD | WS_VISIBLE
|
2000-10-19 15:43:08 +00:00
|
|
|
#ifdef PBS_SMOOTH
|
2019-09-08 19:29:00 +00:00
|
|
|
| PBS_SMOOTH
|
2000-10-19 15:43:08 +00:00
|
|
|
#endif
|
2019-09-08 19:29:00 +00:00
|
|
|
, WS_EX_CLIENTEDGE, "", id);
|
2000-10-19 15:43:08 +00:00
|
|
|
}
|
2001-08-08 20:44:35 +00:00
|
|
|
|
2003-03-05 22:07:40 +00:00
|
|
|
/* ----------------------------------------------------------------------
|
|
|
|
* Platform-specific side of portable dialog-box mechanism.
|
|
|
|
*/
|
|
|
|
|
2001-08-08 20:44:35 +00:00
|
|
|
/*
|
2003-03-05 22:07:40 +00:00
|
|
|
* This function takes a string, escapes all the ampersands, and
|
|
|
|
* places a single (unescaped) ampersand in front of the first
|
|
|
|
* occurrence of the given shortcut character (which may be
|
|
|
|
* NO_SHORTCUT).
|
2019-09-08 19:29:00 +00:00
|
|
|
*
|
2003-03-05 22:07:40 +00:00
|
|
|
* Return value is a malloc'ed copy of the processed version of the
|
|
|
|
* string.
|
2001-08-08 20:44:35 +00:00
|
|
|
*/
|
2006-08-28 10:35:12 +00:00
|
|
|
static char *shortcut_escape(const char *text, char shortcut)
|
2003-03-05 22:07:40 +00:00
|
|
|
{
|
|
|
|
char *ret;
|
2006-08-28 10:35:12 +00:00
|
|
|
char const *p;
|
|
|
|
char *q;
|
2003-03-05 22:07:40 +00:00
|
|
|
|
|
|
|
if (!text)
|
2019-09-08 19:29:00 +00:00
|
|
|
return NULL; /* sfree won't choke on this */
|
2003-03-05 22:07:40 +00:00
|
|
|
|
2003-03-29 16:14:26 +00:00
|
|
|
ret = snewn(2*strlen(text)+1, char); /* size potentially doubles! */
|
2003-03-05 22:07:40 +00:00
|
|
|
shortcut = tolower((unsigned char)shortcut);
|
|
|
|
|
|
|
|
p = text;
|
|
|
|
q = ret;
|
|
|
|
while (*p) {
|
2019-09-08 19:29:00 +00:00
|
|
|
if (shortcut != NO_SHORTCUT &&
|
|
|
|
tolower((unsigned char)*p) == shortcut) {
|
|
|
|
*q++ = '&';
|
|
|
|
shortcut = NO_SHORTCUT; /* stop it happening twice */
|
|
|
|
} else if (*p == '&') {
|
|
|
|
*q++ = '&';
|
|
|
|
}
|
|
|
|
*q++ = *p++;
|
2003-03-05 22:07:40 +00:00
|
|
|
}
|
|
|
|
*q = '\0';
|
|
|
|
return ret;
|
|
|
|
}
|
2001-08-08 20:44:35 +00:00
|
|
|
|
2003-03-05 22:07:40 +00:00
|
|
|
void winctrl_add_shortcuts(struct dlgparam *dp, struct winctrl *c)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
for (i = 0; i < lenof(c->shortcuts); i++)
|
2019-09-08 19:29:00 +00:00
|
|
|
if (c->shortcuts[i] != NO_SHORTCUT) {
|
|
|
|
unsigned char s = tolower((unsigned char)c->shortcuts[i]);
|
|
|
|
assert(!dp->shortcuts[s]);
|
|
|
|
dp->shortcuts[s] = true;
|
|
|
|
}
|
2003-03-05 22:07:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void winctrl_rem_shortcuts(struct dlgparam *dp, struct winctrl *c)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
for (i = 0; i < lenof(c->shortcuts); i++)
|
2019-09-08 19:29:00 +00:00
|
|
|
if (c->shortcuts[i] != NO_SHORTCUT) {
|
|
|
|
unsigned char s = tolower((unsigned char)c->shortcuts[i]);
|
|
|
|
assert(dp->shortcuts[s]);
|
|
|
|
dp->shortcuts[s] = false;
|
|
|
|
}
|
2003-03-05 22:07:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int winctrl_cmp_byctrl(void *av, void *bv)
|
|
|
|
{
|
|
|
|
struct winctrl *a = (struct winctrl *)av;
|
|
|
|
struct winctrl *b = (struct winctrl *)bv;
|
|
|
|
if (a->ctrl < b->ctrl)
|
2019-09-08 19:29:00 +00:00
|
|
|
return -1;
|
2003-03-05 22:07:40 +00:00
|
|
|
else if (a->ctrl > b->ctrl)
|
2019-09-08 19:29:00 +00:00
|
|
|
return +1;
|
2003-03-05 22:07:40 +00:00
|
|
|
else
|
2019-09-08 19:29:00 +00:00
|
|
|
return 0;
|
2003-03-05 22:07:40 +00:00
|
|
|
}
|
|
|
|
static int winctrl_cmp_byid(void *av, void *bv)
|
|
|
|
{
|
|
|
|
struct winctrl *a = (struct winctrl *)av;
|
|
|
|
struct winctrl *b = (struct winctrl *)bv;
|
|
|
|
if (a->base_id < b->base_id)
|
2019-09-08 19:29:00 +00:00
|
|
|
return -1;
|
2003-03-05 22:07:40 +00:00
|
|
|
else if (a->base_id > b->base_id)
|
2019-09-08 19:29:00 +00:00
|
|
|
return +1;
|
2003-03-05 22:07:40 +00:00
|
|
|
else
|
2019-09-08 19:29:00 +00:00
|
|
|
return 0;
|
2003-03-05 22:07:40 +00:00
|
|
|
}
|
|
|
|
static int winctrl_cmp_byctrl_find(void *av, void *bv)
|
|
|
|
{
|
|
|
|
union control *a = (union control *)av;
|
|
|
|
struct winctrl *b = (struct winctrl *)bv;
|
|
|
|
if (a < b->ctrl)
|
2019-09-08 19:29:00 +00:00
|
|
|
return -1;
|
2003-03-05 22:07:40 +00:00
|
|
|
else if (a > b->ctrl)
|
2019-09-08 19:29:00 +00:00
|
|
|
return +1;
|
2003-03-05 22:07:40 +00:00
|
|
|
else
|
2019-09-08 19:29:00 +00:00
|
|
|
return 0;
|
2003-03-05 22:07:40 +00:00
|
|
|
}
|
|
|
|
static int winctrl_cmp_byid_find(void *av, void *bv)
|
|
|
|
{
|
|
|
|
int *a = (int *)av;
|
|
|
|
struct winctrl *b = (struct winctrl *)bv;
|
|
|
|
if (*a < b->base_id)
|
2019-09-08 19:29:00 +00:00
|
|
|
return -1;
|
2003-03-05 22:07:40 +00:00
|
|
|
else if (*a >= b->base_id + b->num_ids)
|
2019-09-08 19:29:00 +00:00
|
|
|
return +1;
|
2003-03-05 22:07:40 +00:00
|
|
|
else
|
2019-09-08 19:29:00 +00:00
|
|
|
return 0;
|
2003-03-05 22:07:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void winctrl_init(struct winctrls *wc)
|
|
|
|
{
|
|
|
|
wc->byctrl = newtree234(winctrl_cmp_byctrl);
|
|
|
|
wc->byid = newtree234(winctrl_cmp_byid);
|
|
|
|
}
|
|
|
|
void winctrl_cleanup(struct winctrls *wc)
|
|
|
|
{
|
|
|
|
struct winctrl *c;
|
|
|
|
|
|
|
|
while ((c = index234(wc->byid, 0)) != NULL) {
|
2019-09-08 19:29:00 +00:00
|
|
|
winctrl_remove(wc, c);
|
|
|
|
sfree(c->data);
|
|
|
|
sfree(c);
|
2003-03-05 22:07:40 +00:00
|
|
|
}
|
2001-08-08 20:44:35 +00:00
|
|
|
|
2003-03-05 22:07:40 +00:00
|
|
|
freetree234(wc->byctrl);
|
|
|
|
freetree234(wc->byid);
|
|
|
|
wc->byctrl = wc->byid = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
void winctrl_add(struct winctrls *wc, struct winctrl *c)
|
|
|
|
{
|
|
|
|
struct winctrl *ret;
|
|
|
|
if (c->ctrl) {
|
2019-09-08 19:29:00 +00:00
|
|
|
ret = add234(wc->byctrl, c);
|
|
|
|
assert(ret == c);
|
2003-03-05 22:07:40 +00:00
|
|
|
}
|
|
|
|
ret = add234(wc->byid, c);
|
|
|
|
assert(ret == c);
|
|
|
|
}
|
|
|
|
|
|
|
|
void winctrl_remove(struct winctrls *wc, struct winctrl *c)
|
|
|
|
{
|
|
|
|
struct winctrl *ret;
|
|
|
|
ret = del234(wc->byctrl, c);
|
|
|
|
ret = del234(wc->byid, c);
|
|
|
|
assert(ret == c);
|
|
|
|
}
|
|
|
|
|
|
|
|
struct winctrl *winctrl_findbyctrl(struct winctrls *wc, union control *ctrl)
|
|
|
|
{
|
|
|
|
return find234(wc->byctrl, ctrl, winctrl_cmp_byctrl_find);
|
|
|
|
}
|
|
|
|
|
|
|
|
struct winctrl *winctrl_findbyid(struct winctrls *wc, int id)
|
|
|
|
{
|
|
|
|
return find234(wc->byid, &id, winctrl_cmp_byid_find);
|
|
|
|
}
|
|
|
|
|
|
|
|
struct winctrl *winctrl_findbyindex(struct winctrls *wc, int index)
|
|
|
|
{
|
|
|
|
return index234(wc->byid, index);
|
|
|
|
}
|
|
|
|
|
|
|
|
void winctrl_layout(struct dlgparam *dp, struct winctrls *wc,
|
2019-09-08 19:29:00 +00:00
|
|
|
struct ctlpos *cp, struct controlset *s, int *id)
|
2003-03-05 22:07:40 +00:00
|
|
|
{
|
|
|
|
struct ctlpos columns[16];
|
|
|
|
int ncols, colstart, colspan;
|
|
|
|
|
|
|
|
struct ctlpos tabdelays[16];
|
|
|
|
union control *tabdelayed[16];
|
|
|
|
int ntabdelays;
|
|
|
|
|
|
|
|
struct ctlpos pos;
|
|
|
|
|
2003-03-06 12:41:39 +00:00
|
|
|
char shortcuts[MAX_SHORTCUTS_PER_CTRL];
|
|
|
|
int nshortcuts;
|
2003-03-05 22:07:40 +00:00
|
|
|
char *escaped;
|
2003-03-18 19:06:51 +00:00
|
|
|
int i, actual_base_id, base_id, num_ids;
|
2003-03-05 22:07:40 +00:00
|
|
|
void *data;
|
|
|
|
|
|
|
|
base_id = *id;
|
|
|
|
|
|
|
|
/* Start a containing box, if we have a boxname. */
|
|
|
|
if (s->boxname && *s->boxname) {
|
2019-09-08 19:29:00 +00:00
|
|
|
struct winctrl *c = snew(struct winctrl);
|
|
|
|
c->ctrl = NULL;
|
|
|
|
c->base_id = base_id;
|
|
|
|
c->num_ids = 1;
|
|
|
|
c->data = NULL;
|
|
|
|
memset(c->shortcuts, NO_SHORTCUT, lenof(c->shortcuts));
|
|
|
|
winctrl_add(wc, c);
|
|
|
|
beginbox(cp, s->boxtitle, base_id);
|
|
|
|
base_id++;
|
2003-03-05 22:07:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Draw a title, if we have one. */
|
|
|
|
if (!s->boxname && s->boxtitle) {
|
2019-09-08 19:29:00 +00:00
|
|
|
struct winctrl *c = snew(struct winctrl);
|
|
|
|
c->ctrl = NULL;
|
|
|
|
c->base_id = base_id;
|
|
|
|
c->num_ids = 1;
|
|
|
|
c->data = dupstr(s->boxtitle);
|
|
|
|
memset(c->shortcuts, NO_SHORTCUT, lenof(c->shortcuts));
|
|
|
|
winctrl_add(wc, c);
|
|
|
|
paneltitle(cp, base_id);
|
|
|
|
base_id++;
|
2003-03-05 22:07:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Initially we have just one column. */
|
|
|
|
ncols = 1;
|
2019-09-08 19:29:00 +00:00
|
|
|
columns[0] = *cp; /* structure copy */
|
2003-03-05 22:07:40 +00:00
|
|
|
|
|
|
|
/* And initially, there are no pending tab-delayed controls. */
|
|
|
|
ntabdelays = 0;
|
|
|
|
|
|
|
|
/* Loop over each control in the controlset. */
|
|
|
|
for (i = 0; i < s->ncontrols; i++) {
|
2019-09-08 19:29:00 +00:00
|
|
|
union control *ctrl = s->ctrls[i];
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Generic processing that pertains to all control types.
|
|
|
|
* At the end of this if statement, we'll have produced
|
|
|
|
* `ctrl' (a pointer to the control we have to create, or
|
|
|
|
* think about creating, in this iteration of the loop),
|
|
|
|
* `pos' (a suitable ctlpos with which to position it), and
|
|
|
|
* `c' (a winctrl structure to receive details of the
|
|
|
|
* dialog IDs). Or we'll have done a `continue', if it was
|
|
|
|
* CTRL_COLUMNS and doesn't require any control creation at
|
|
|
|
* all.
|
|
|
|
*/
|
|
|
|
if (ctrl->generic.type == CTRL_COLUMNS) {
|
|
|
|
assert((ctrl->columns.ncols == 1) ^ (ncols == 1));
|
|
|
|
|
|
|
|
if (ncols == 1) {
|
|
|
|
/*
|
|
|
|
* We're splitting into multiple columns.
|
|
|
|
*/
|
|
|
|
int lpercent, rpercent, lx, rx, i;
|
|
|
|
|
|
|
|
ncols = ctrl->columns.ncols;
|
|
|
|
assert(ncols <= lenof(columns));
|
|
|
|
for (i = 1; i < ncols; i++)
|
|
|
|
columns[i] = columns[0]; /* structure copy */
|
|
|
|
|
|
|
|
lpercent = 0;
|
|
|
|
for (i = 0; i < ncols; i++) {
|
|
|
|
rpercent = lpercent + ctrl->columns.percentages[i];
|
|
|
|
lx = columns[i].xoff + lpercent *
|
|
|
|
(columns[i].width + GAPBETWEEN) / 100;
|
|
|
|
rx = columns[i].xoff + rpercent *
|
|
|
|
(columns[i].width + GAPBETWEEN) / 100;
|
|
|
|
columns[i].xoff = lx;
|
|
|
|
columns[i].width = rx - lx - GAPBETWEEN;
|
|
|
|
lpercent = rpercent;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
/*
|
|
|
|
* We're recombining the various columns into one.
|
|
|
|
*/
|
|
|
|
int maxy = columns[0].ypos;
|
|
|
|
int i;
|
|
|
|
for (i = 1; i < ncols; i++)
|
|
|
|
if (maxy < columns[i].ypos)
|
|
|
|
maxy = columns[i].ypos;
|
|
|
|
ncols = 1;
|
|
|
|
columns[0] = *cp; /* structure copy */
|
|
|
|
columns[0].ypos = maxy;
|
|
|
|
}
|
|
|
|
|
|
|
|
continue;
|
|
|
|
} else if (ctrl->generic.type == CTRL_TABDELAY) {
|
|
|
|
int i;
|
|
|
|
|
|
|
|
assert(!ctrl->generic.tabdelay);
|
|
|
|
ctrl = ctrl->tabdelay.ctrl;
|
|
|
|
|
|
|
|
for (i = 0; i < ntabdelays; i++)
|
|
|
|
if (tabdelayed[i] == ctrl)
|
|
|
|
break;
|
|
|
|
assert(i < ntabdelays); /* we have to have found it */
|
|
|
|
|
|
|
|
pos = tabdelays[i]; /* structure copy */
|
|
|
|
|
|
|
|
colstart = colspan = -1; /* indicate this was tab-delayed */
|
|
|
|
|
|
|
|
} else {
|
|
|
|
/*
|
|
|
|
* If it wasn't one of those, it's a genuine control;
|
|
|
|
* so we'll have to compute a position for it now, by
|
|
|
|
* checking its column span.
|
|
|
|
*/
|
|
|
|
int col;
|
|
|
|
|
|
|
|
colstart = COLUMN_START(ctrl->generic.column);
|
|
|
|
colspan = COLUMN_SPAN(ctrl->generic.column);
|
|
|
|
|
|
|
|
pos = columns[colstart]; /* structure copy */
|
|
|
|
pos.width = columns[colstart+colspan-1].width +
|
|
|
|
(columns[colstart+colspan-1].xoff - columns[colstart].xoff);
|
|
|
|
|
|
|
|
for (col = colstart; col < colstart+colspan; col++)
|
|
|
|
if (pos.ypos < columns[col].ypos)
|
|
|
|
pos.ypos = columns[col].ypos;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If this control is to be tabdelayed, add it to the
|
|
|
|
* tabdelay list, and unset pos.hwnd to inhibit actual
|
|
|
|
* control creation.
|
|
|
|
*/
|
|
|
|
if (ctrl->generic.tabdelay) {
|
|
|
|
assert(ntabdelays < lenof(tabdelays));
|
|
|
|
tabdelays[ntabdelays] = pos; /* structure copy */
|
|
|
|
tabdelayed[ntabdelays] = ctrl;
|
|
|
|
ntabdelays++;
|
|
|
|
pos.hwnd = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Most controls don't need anything in c->data. */
|
|
|
|
data = NULL;
|
|
|
|
|
|
|
|
/* And they all start off with no shortcuts registered. */
|
|
|
|
memset(shortcuts, NO_SHORTCUT, lenof(shortcuts));
|
|
|
|
nshortcuts = 0;
|
|
|
|
|
|
|
|
/* Almost all controls start at base_id. */
|
|
|
|
actual_base_id = base_id;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Now we're ready to actually create the control, by
|
|
|
|
* switching on its type.
|
|
|
|
*/
|
|
|
|
switch (ctrl->generic.type) {
|
Formatting change to braces around one case of a switch.
Sometimes, within a switch statement, you want to declare local
variables specific to the handler for one particular case. Until now
I've mostly been writing this in the form
switch (discriminant) {
case SIMPLE:
do stuff;
break;
case COMPLICATED:
{
declare variables;
do stuff;
}
break;
}
which is ugly because the two pieces of essentially similar code
appear at different indent levels, and also inconvenient because you
have less horizontal space available to write the complicated case
handler in - particuarly undesirable because _complicated_ case
handlers are the ones most likely to need all the space they can get!
After encountering a rather nicer idiom in the LLVM source code, and
after a bit of hackery this morning figuring out how to persuade
Emacs's auto-indent to do what I wanted with it, I've decided to move
to an idiom in which the open brace comes right after the case
statement, and the code within it is indented the same as it would
have been without the brace. Then the whole case handler (including
the break) lives inside those braces, and you get something that looks
more like this:
switch (discriminant) {
case SIMPLE:
do stuff;
break;
case COMPLICATED: {
declare variables;
do stuff;
break;
}
}
This commit is a big-bang change that reformats all the complicated
case handlers I could find into the new layout. This is particularly
nice in the Pageant main function, in which almost _every_ case
handler had a bundle of variables and was long and complicated. (In
fact that's what motivated me to get round to this.) Some of the
innermost parts of the terminal escape-sequence handling are also
breathing a bit easier now the horizontal pressure on them is
relieved.
(Also, in a few cases, I was able to remove the extra braces
completely, because the only variable local to the case handler was a
loop variable which our new C99 policy allows me to move into the
initialiser clause of its for statement.)
Viewed with whitespace ignored, this is not too disruptive a change.
Downstream patches that conflict with it may need to be reapplied
using --ignore-whitespace or similar.
2020-02-16 07:49:52 +00:00
|
|
|
case CTRL_TEXT: {
|
|
|
|
char *wrapped, *escaped;
|
|
|
|
int lines;
|
|
|
|
num_ids = 1;
|
|
|
|
wrapped = staticwrap(&pos, cp->hwnd,
|
|
|
|
ctrl->generic.label, &lines);
|
|
|
|
escaped = shortcut_escape(wrapped, NO_SHORTCUT);
|
|
|
|
statictext(&pos, escaped, lines, base_id);
|
|
|
|
sfree(escaped);
|
|
|
|
sfree(wrapped);
|
2019-09-08 19:29:00 +00:00
|
|
|
break;
|
Formatting change to braces around one case of a switch.
Sometimes, within a switch statement, you want to declare local
variables specific to the handler for one particular case. Until now
I've mostly been writing this in the form
switch (discriminant) {
case SIMPLE:
do stuff;
break;
case COMPLICATED:
{
declare variables;
do stuff;
}
break;
}
which is ugly because the two pieces of essentially similar code
appear at different indent levels, and also inconvenient because you
have less horizontal space available to write the complicated case
handler in - particuarly undesirable because _complicated_ case
handlers are the ones most likely to need all the space they can get!
After encountering a rather nicer idiom in the LLVM source code, and
after a bit of hackery this morning figuring out how to persuade
Emacs's auto-indent to do what I wanted with it, I've decided to move
to an idiom in which the open brace comes right after the case
statement, and the code within it is indented the same as it would
have been without the brace. Then the whole case handler (including
the break) lives inside those braces, and you get something that looks
more like this:
switch (discriminant) {
case SIMPLE:
do stuff;
break;
case COMPLICATED: {
declare variables;
do stuff;
break;
}
}
This commit is a big-bang change that reformats all the complicated
case handlers I could find into the new layout. This is particularly
nice in the Pageant main function, in which almost _every_ case
handler had a bundle of variables and was long and complicated. (In
fact that's what motivated me to get round to this.) Some of the
innermost parts of the terminal escape-sequence handling are also
breathing a bit easier now the horizontal pressure on them is
relieved.
(Also, in a few cases, I was able to remove the extra braces
completely, because the only variable local to the case handler was a
loop variable which our new C99 policy allows me to move into the
initialiser clause of its for statement.)
Viewed with whitespace ignored, this is not too disruptive a change.
Downstream patches that conflict with it may need to be reapplied
using --ignore-whitespace or similar.
2020-02-16 07:49:52 +00:00
|
|
|
}
|
2019-09-08 19:29:00 +00:00
|
|
|
case CTRL_EDITBOX:
|
|
|
|
num_ids = 2; /* static, edit */
|
|
|
|
escaped = shortcut_escape(ctrl->editbox.label,
|
|
|
|
ctrl->editbox.shortcut);
|
|
|
|
shortcuts[nshortcuts++] = ctrl->editbox.shortcut;
|
|
|
|
if (ctrl->editbox.percentwidth == 100) {
|
|
|
|
if (ctrl->editbox.has_list)
|
|
|
|
combobox(&pos, escaped,
|
|
|
|
base_id, base_id+1);
|
|
|
|
else
|
|
|
|
editboxfw(&pos, ctrl->editbox.password, escaped,
|
|
|
|
base_id, base_id+1);
|
|
|
|
} else {
|
|
|
|
if (ctrl->editbox.has_list) {
|
|
|
|
staticcombo(&pos, escaped, base_id, base_id+1,
|
|
|
|
ctrl->editbox.percentwidth);
|
|
|
|
} else {
|
|
|
|
(ctrl->editbox.password ? staticpassedit : staticedit)
|
|
|
|
(&pos, escaped, base_id, base_id+1,
|
|
|
|
ctrl->editbox.percentwidth);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
sfree(escaped);
|
|
|
|
break;
|
Formatting change to braces around one case of a switch.
Sometimes, within a switch statement, you want to declare local
variables specific to the handler for one particular case. Until now
I've mostly been writing this in the form
switch (discriminant) {
case SIMPLE:
do stuff;
break;
case COMPLICATED:
{
declare variables;
do stuff;
}
break;
}
which is ugly because the two pieces of essentially similar code
appear at different indent levels, and also inconvenient because you
have less horizontal space available to write the complicated case
handler in - particuarly undesirable because _complicated_ case
handlers are the ones most likely to need all the space they can get!
After encountering a rather nicer idiom in the LLVM source code, and
after a bit of hackery this morning figuring out how to persuade
Emacs's auto-indent to do what I wanted with it, I've decided to move
to an idiom in which the open brace comes right after the case
statement, and the code within it is indented the same as it would
have been without the brace. Then the whole case handler (including
the break) lives inside those braces, and you get something that looks
more like this:
switch (discriminant) {
case SIMPLE:
do stuff;
break;
case COMPLICATED: {
declare variables;
do stuff;
break;
}
}
This commit is a big-bang change that reformats all the complicated
case handlers I could find into the new layout. This is particularly
nice in the Pageant main function, in which almost _every_ case
handler had a bundle of variables and was long and complicated. (In
fact that's what motivated me to get round to this.) Some of the
innermost parts of the terminal escape-sequence handling are also
breathing a bit easier now the horizontal pressure on them is
relieved.
(Also, in a few cases, I was able to remove the extra braces
completely, because the only variable local to the case handler was a
loop variable which our new C99 policy allows me to move into the
initialiser clause of its for statement.)
Viewed with whitespace ignored, this is not too disruptive a change.
Downstream patches that conflict with it may need to be reapplied
using --ignore-whitespace or similar.
2020-02-16 07:49:52 +00:00
|
|
|
case CTRL_RADIO: {
|
2019-09-08 19:29:00 +00:00
|
|
|
num_ids = ctrl->radio.nbuttons + 1; /* label as well */
|
Formatting change to braces around one case of a switch.
Sometimes, within a switch statement, you want to declare local
variables specific to the handler for one particular case. Until now
I've mostly been writing this in the form
switch (discriminant) {
case SIMPLE:
do stuff;
break;
case COMPLICATED:
{
declare variables;
do stuff;
}
break;
}
which is ugly because the two pieces of essentially similar code
appear at different indent levels, and also inconvenient because you
have less horizontal space available to write the complicated case
handler in - particuarly undesirable because _complicated_ case
handlers are the ones most likely to need all the space they can get!
After encountering a rather nicer idiom in the LLVM source code, and
after a bit of hackery this morning figuring out how to persuade
Emacs's auto-indent to do what I wanted with it, I've decided to move
to an idiom in which the open brace comes right after the case
statement, and the code within it is indented the same as it would
have been without the brace. Then the whole case handler (including
the break) lives inside those braces, and you get something that looks
more like this:
switch (discriminant) {
case SIMPLE:
do stuff;
break;
case COMPLICATED: {
declare variables;
do stuff;
break;
}
}
This commit is a big-bang change that reformats all the complicated
case handlers I could find into the new layout. This is particularly
nice in the Pageant main function, in which almost _every_ case
handler had a bundle of variables and was long and complicated. (In
fact that's what motivated me to get round to this.) Some of the
innermost parts of the terminal escape-sequence handling are also
breathing a bit easier now the horizontal pressure on them is
relieved.
(Also, in a few cases, I was able to remove the extra braces
completely, because the only variable local to the case handler was a
loop variable which our new C99 policy allows me to move into the
initialiser clause of its for statement.)
Viewed with whitespace ignored, this is not too disruptive a change.
Downstream patches that conflict with it may need to be reapplied
using --ignore-whitespace or similar.
2020-02-16 07:49:52 +00:00
|
|
|
struct radio *buttons;
|
|
|
|
int i;
|
2019-09-08 19:29:00 +00:00
|
|
|
|
Formatting change to braces around one case of a switch.
Sometimes, within a switch statement, you want to declare local
variables specific to the handler for one particular case. Until now
I've mostly been writing this in the form
switch (discriminant) {
case SIMPLE:
do stuff;
break;
case COMPLICATED:
{
declare variables;
do stuff;
}
break;
}
which is ugly because the two pieces of essentially similar code
appear at different indent levels, and also inconvenient because you
have less horizontal space available to write the complicated case
handler in - particuarly undesirable because _complicated_ case
handlers are the ones most likely to need all the space they can get!
After encountering a rather nicer idiom in the LLVM source code, and
after a bit of hackery this morning figuring out how to persuade
Emacs's auto-indent to do what I wanted with it, I've decided to move
to an idiom in which the open brace comes right after the case
statement, and the code within it is indented the same as it would
have been without the brace. Then the whole case handler (including
the break) lives inside those braces, and you get something that looks
more like this:
switch (discriminant) {
case SIMPLE:
do stuff;
break;
case COMPLICATED: {
declare variables;
do stuff;
break;
}
}
This commit is a big-bang change that reformats all the complicated
case handlers I could find into the new layout. This is particularly
nice in the Pageant main function, in which almost _every_ case
handler had a bundle of variables and was long and complicated. (In
fact that's what motivated me to get round to this.) Some of the
innermost parts of the terminal escape-sequence handling are also
breathing a bit easier now the horizontal pressure on them is
relieved.
(Also, in a few cases, I was able to remove the extra braces
completely, because the only variable local to the case handler was a
loop variable which our new C99 policy allows me to move into the
initialiser clause of its for statement.)
Viewed with whitespace ignored, this is not too disruptive a change.
Downstream patches that conflict with it may need to be reapplied
using --ignore-whitespace or similar.
2020-02-16 07:49:52 +00:00
|
|
|
escaped = shortcut_escape(ctrl->radio.label,
|
|
|
|
ctrl->radio.shortcut);
|
|
|
|
shortcuts[nshortcuts++] = ctrl->radio.shortcut;
|
|
|
|
|
|
|
|
buttons = snewn(ctrl->radio.nbuttons, struct radio);
|
|
|
|
|
|
|
|
for (i = 0; i < ctrl->radio.nbuttons; i++) {
|
|
|
|
buttons[i].text =
|
|
|
|
shortcut_escape(ctrl->radio.buttons[i],
|
|
|
|
(char)(ctrl->radio.shortcuts ?
|
|
|
|
ctrl->radio.shortcuts[i] :
|
|
|
|
NO_SHORTCUT));
|
|
|
|
buttons[i].id = base_id + 1 + i;
|
|
|
|
if (ctrl->radio.shortcuts) {
|
|
|
|
assert(nshortcuts < MAX_SHORTCUTS_PER_CTRL);
|
|
|
|
shortcuts[nshortcuts++] = ctrl->radio.shortcuts[i];
|
|
|
|
}
|
|
|
|
}
|
2019-09-08 19:29:00 +00:00
|
|
|
|
Formatting change to braces around one case of a switch.
Sometimes, within a switch statement, you want to declare local
variables specific to the handler for one particular case. Until now
I've mostly been writing this in the form
switch (discriminant) {
case SIMPLE:
do stuff;
break;
case COMPLICATED:
{
declare variables;
do stuff;
}
break;
}
which is ugly because the two pieces of essentially similar code
appear at different indent levels, and also inconvenient because you
have less horizontal space available to write the complicated case
handler in - particuarly undesirable because _complicated_ case
handlers are the ones most likely to need all the space they can get!
After encountering a rather nicer idiom in the LLVM source code, and
after a bit of hackery this morning figuring out how to persuade
Emacs's auto-indent to do what I wanted with it, I've decided to move
to an idiom in which the open brace comes right after the case
statement, and the code within it is indented the same as it would
have been without the brace. Then the whole case handler (including
the break) lives inside those braces, and you get something that looks
more like this:
switch (discriminant) {
case SIMPLE:
do stuff;
break;
case COMPLICATED: {
declare variables;
do stuff;
break;
}
}
This commit is a big-bang change that reformats all the complicated
case handlers I could find into the new layout. This is particularly
nice in the Pageant main function, in which almost _every_ case
handler had a bundle of variables and was long and complicated. (In
fact that's what motivated me to get round to this.) Some of the
innermost parts of the terminal escape-sequence handling are also
breathing a bit easier now the horizontal pressure on them is
relieved.
(Also, in a few cases, I was able to remove the extra braces
completely, because the only variable local to the case handler was a
loop variable which our new C99 policy allows me to move into the
initialiser clause of its for statement.)
Viewed with whitespace ignored, this is not too disruptive a change.
Downstream patches that conflict with it may need to be reapplied
using --ignore-whitespace or similar.
2020-02-16 07:49:52 +00:00
|
|
|
radioline_common(&pos, escaped, base_id,
|
|
|
|
ctrl->radio.ncolumns,
|
|
|
|
buttons, ctrl->radio.nbuttons);
|
2019-09-08 19:29:00 +00:00
|
|
|
|
Formatting change to braces around one case of a switch.
Sometimes, within a switch statement, you want to declare local
variables specific to the handler for one particular case. Until now
I've mostly been writing this in the form
switch (discriminant) {
case SIMPLE:
do stuff;
break;
case COMPLICATED:
{
declare variables;
do stuff;
}
break;
}
which is ugly because the two pieces of essentially similar code
appear at different indent levels, and also inconvenient because you
have less horizontal space available to write the complicated case
handler in - particuarly undesirable because _complicated_ case
handlers are the ones most likely to need all the space they can get!
After encountering a rather nicer idiom in the LLVM source code, and
after a bit of hackery this morning figuring out how to persuade
Emacs's auto-indent to do what I wanted with it, I've decided to move
to an idiom in which the open brace comes right after the case
statement, and the code within it is indented the same as it would
have been without the brace. Then the whole case handler (including
the break) lives inside those braces, and you get something that looks
more like this:
switch (discriminant) {
case SIMPLE:
do stuff;
break;
case COMPLICATED: {
declare variables;
do stuff;
break;
}
}
This commit is a big-bang change that reformats all the complicated
case handlers I could find into the new layout. This is particularly
nice in the Pageant main function, in which almost _every_ case
handler had a bundle of variables and was long and complicated. (In
fact that's what motivated me to get round to this.) Some of the
innermost parts of the terminal escape-sequence handling are also
breathing a bit easier now the horizontal pressure on them is
relieved.
(Also, in a few cases, I was able to remove the extra braces
completely, because the only variable local to the case handler was a
loop variable which our new C99 policy allows me to move into the
initialiser clause of its for statement.)
Viewed with whitespace ignored, this is not too disruptive a change.
Downstream patches that conflict with it may need to be reapplied
using --ignore-whitespace or similar.
2020-02-16 07:49:52 +00:00
|
|
|
for (i = 0; i < ctrl->radio.nbuttons; i++) {
|
|
|
|
sfree(buttons[i].text);
|
2019-09-08 19:29:00 +00:00
|
|
|
}
|
Formatting change to braces around one case of a switch.
Sometimes, within a switch statement, you want to declare local
variables specific to the handler for one particular case. Until now
I've mostly been writing this in the form
switch (discriminant) {
case SIMPLE:
do stuff;
break;
case COMPLICATED:
{
declare variables;
do stuff;
}
break;
}
which is ugly because the two pieces of essentially similar code
appear at different indent levels, and also inconvenient because you
have less horizontal space available to write the complicated case
handler in - particuarly undesirable because _complicated_ case
handlers are the ones most likely to need all the space they can get!
After encountering a rather nicer idiom in the LLVM source code, and
after a bit of hackery this morning figuring out how to persuade
Emacs's auto-indent to do what I wanted with it, I've decided to move
to an idiom in which the open brace comes right after the case
statement, and the code within it is indented the same as it would
have been without the brace. Then the whole case handler (including
the break) lives inside those braces, and you get something that looks
more like this:
switch (discriminant) {
case SIMPLE:
do stuff;
break;
case COMPLICATED: {
declare variables;
do stuff;
break;
}
}
This commit is a big-bang change that reformats all the complicated
case handlers I could find into the new layout. This is particularly
nice in the Pageant main function, in which almost _every_ case
handler had a bundle of variables and was long and complicated. (In
fact that's what motivated me to get round to this.) Some of the
innermost parts of the terminal escape-sequence handling are also
breathing a bit easier now the horizontal pressure on them is
relieved.
(Also, in a few cases, I was able to remove the extra braces
completely, because the only variable local to the case handler was a
loop variable which our new C99 policy allows me to move into the
initialiser clause of its for statement.)
Viewed with whitespace ignored, this is not too disruptive a change.
Downstream patches that conflict with it may need to be reapplied
using --ignore-whitespace or similar.
2020-02-16 07:49:52 +00:00
|
|
|
sfree(buttons);
|
|
|
|
sfree(escaped);
|
2019-09-08 19:29:00 +00:00
|
|
|
break;
|
Formatting change to braces around one case of a switch.
Sometimes, within a switch statement, you want to declare local
variables specific to the handler for one particular case. Until now
I've mostly been writing this in the form
switch (discriminant) {
case SIMPLE:
do stuff;
break;
case COMPLICATED:
{
declare variables;
do stuff;
}
break;
}
which is ugly because the two pieces of essentially similar code
appear at different indent levels, and also inconvenient because you
have less horizontal space available to write the complicated case
handler in - particuarly undesirable because _complicated_ case
handlers are the ones most likely to need all the space they can get!
After encountering a rather nicer idiom in the LLVM source code, and
after a bit of hackery this morning figuring out how to persuade
Emacs's auto-indent to do what I wanted with it, I've decided to move
to an idiom in which the open brace comes right after the case
statement, and the code within it is indented the same as it would
have been without the brace. Then the whole case handler (including
the break) lives inside those braces, and you get something that looks
more like this:
switch (discriminant) {
case SIMPLE:
do stuff;
break;
case COMPLICATED: {
declare variables;
do stuff;
break;
}
}
This commit is a big-bang change that reformats all the complicated
case handlers I could find into the new layout. This is particularly
nice in the Pageant main function, in which almost _every_ case
handler had a bundle of variables and was long and complicated. (In
fact that's what motivated me to get round to this.) Some of the
innermost parts of the terminal escape-sequence handling are also
breathing a bit easier now the horizontal pressure on them is
relieved.
(Also, in a few cases, I was able to remove the extra braces
completely, because the only variable local to the case handler was a
loop variable which our new C99 policy allows me to move into the
initialiser clause of its for statement.)
Viewed with whitespace ignored, this is not too disruptive a change.
Downstream patches that conflict with it may need to be reapplied
using --ignore-whitespace or similar.
2020-02-16 07:49:52 +00:00
|
|
|
}
|
2019-09-08 19:29:00 +00:00
|
|
|
case CTRL_CHECKBOX:
|
|
|
|
num_ids = 1;
|
|
|
|
escaped = shortcut_escape(ctrl->checkbox.label,
|
|
|
|
ctrl->checkbox.shortcut);
|
|
|
|
shortcuts[nshortcuts++] = ctrl->checkbox.shortcut;
|
|
|
|
checkbox(&pos, escaped, base_id);
|
|
|
|
sfree(escaped);
|
|
|
|
break;
|
|
|
|
case CTRL_BUTTON:
|
|
|
|
escaped = shortcut_escape(ctrl->button.label,
|
|
|
|
ctrl->button.shortcut);
|
|
|
|
shortcuts[nshortcuts++] = ctrl->button.shortcut;
|
|
|
|
if (ctrl->button.iscancel)
|
|
|
|
actual_base_id = IDCANCEL;
|
|
|
|
num_ids = 1;
|
|
|
|
button(&pos, escaped, actual_base_id, ctrl->button.isdefault);
|
|
|
|
sfree(escaped);
|
|
|
|
break;
|
|
|
|
case CTRL_LISTBOX:
|
|
|
|
num_ids = 2;
|
|
|
|
escaped = shortcut_escape(ctrl->listbox.label,
|
|
|
|
ctrl->listbox.shortcut);
|
|
|
|
shortcuts[nshortcuts++] = ctrl->listbox.shortcut;
|
|
|
|
if (ctrl->listbox.draglist) {
|
|
|
|
data = snew(struct prefslist);
|
|
|
|
num_ids = 4;
|
|
|
|
prefslist(data, &pos, ctrl->listbox.height, escaped,
|
|
|
|
base_id, base_id+1, base_id+2, base_id+3);
|
|
|
|
shortcuts[nshortcuts++] = 'u'; /* Up */
|
|
|
|
shortcuts[nshortcuts++] = 'd'; /* Down */
|
|
|
|
} else if (ctrl->listbox.height == 0) {
|
|
|
|
/* Drop-down list. */
|
|
|
|
if (ctrl->listbox.percentwidth == 100) {
|
|
|
|
staticddlbig(&pos, escaped,
|
|
|
|
base_id, base_id+1);
|
|
|
|
} else {
|
|
|
|
staticddl(&pos, escaped, base_id,
|
|
|
|
base_id+1, ctrl->listbox.percentwidth);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
/* Ordinary list. */
|
|
|
|
listbox(&pos, escaped, base_id, base_id+1,
|
|
|
|
ctrl->listbox.height, ctrl->listbox.multisel);
|
|
|
|
}
|
|
|
|
if (ctrl->listbox.ncols) {
|
|
|
|
/*
|
|
|
|
* This method of getting the box width is a bit of
|
|
|
|
* a hack; we'd do better to try to retrieve the
|
|
|
|
* actual width in dialog units from doctl() just
|
|
|
|
* before MapDialogRect. But that's going to be no
|
|
|
|
* fun, and this should be good enough accuracy.
|
|
|
|
*/
|
|
|
|
int width = cp->width * ctrl->listbox.percentwidth;
|
|
|
|
int *tabarray;
|
|
|
|
int i, percent;
|
|
|
|
|
|
|
|
tabarray = snewn(ctrl->listbox.ncols-1, int);
|
|
|
|
percent = 0;
|
|
|
|
for (i = 0; i < ctrl->listbox.ncols-1; i++) {
|
|
|
|
percent += ctrl->listbox.percentages[i];
|
|
|
|
tabarray[i] = width * percent / 10000;
|
|
|
|
}
|
|
|
|
SendDlgItemMessage(cp->hwnd, base_id+1, LB_SETTABSTOPS,
|
|
|
|
ctrl->listbox.ncols-1, (LPARAM)tabarray);
|
|
|
|
sfree(tabarray);
|
|
|
|
}
|
|
|
|
sfree(escaped);
|
|
|
|
break;
|
|
|
|
case CTRL_FILESELECT:
|
|
|
|
num_ids = 3;
|
|
|
|
escaped = shortcut_escape(ctrl->fileselect.label,
|
|
|
|
ctrl->fileselect.shortcut);
|
|
|
|
shortcuts[nshortcuts++] = ctrl->fileselect.shortcut;
|
|
|
|
editbutton(&pos, escaped, base_id, base_id+1,
|
|
|
|
"Bro&wse...", base_id+2);
|
|
|
|
shortcuts[nshortcuts++] = 'w';
|
|
|
|
sfree(escaped);
|
|
|
|
break;
|
|
|
|
case CTRL_FONTSELECT:
|
|
|
|
num_ids = 3;
|
|
|
|
escaped = shortcut_escape(ctrl->fontselect.label,
|
|
|
|
ctrl->fontselect.shortcut);
|
|
|
|
shortcuts[nshortcuts++] = ctrl->fontselect.shortcut;
|
|
|
|
statictext(&pos, escaped, 1, base_id);
|
|
|
|
staticbtn(&pos, "", base_id+1, "Change...", base_id+2);
|
Convert a lot of 'int' variables to 'bool'.
My normal habit these days, in new code, is to treat int and bool as
_almost_ completely separate types. I'm still willing to use C's
implicit test for zero on an integer (e.g. 'if (!blob.len)' is fine,
no need to spell it out as blob.len != 0), but generally, if a
variable is going to be conceptually a boolean, I like to declare it
bool and assign to it using 'true' or 'false' rather than 0 or 1.
PuTTY is an exception, because it predates the C99 bool, and I've
stuck to its existing coding style even when adding new code to it.
But it's been annoying me more and more, so now that I've decided C99
bool is an acceptable thing to require from our toolchain in the first
place, here's a quite thorough trawl through the source doing
'boolification'. Many variables and function parameters are now typed
as bool rather than int; many assignments of 0 or 1 to those variables
are now spelled 'true' or 'false'.
I managed this thorough conversion with the help of a custom clang
plugin that I wrote to trawl the AST and apply heuristics to point out
where things might want changing. So I've even managed to do a decent
job on parts of the code I haven't looked at in years!
To make the plugin's work easier, I pushed platform front ends
generally in the direction of using standard 'bool' in preference to
platform-specific boolean types like Windows BOOL or GTK's gboolean;
I've left the platform booleans in places they _have_ to be for the
platform APIs to work right, but variables only used by my own code
have been converted wherever I found them.
In a few places there are int values that look very like booleans in
_most_ of the places they're used, but have a rarely-used third value,
or a distinction between different nonzero values that most users
don't care about. In these cases, I've _removed_ uses of 'true' and
'false' for the return values, to emphasise that there's something
more subtle going on than a simple boolean answer:
- the 'multisel' field in dialog.h's list box structure, for which
the GTK front end in particular recognises a difference between 1
and 2 but nearly everything else treats as boolean
- the 'urgent' parameter to plug_receive, where 1 vs 2 tells you
something about the specific location of the urgent pointer, but
most clients only care about 0 vs 'something nonzero'
- the return value of wc_match, where -1 indicates a syntax error in
the wildcard.
- the return values from SSH-1 RSA-key loading functions, which use
-1 for 'wrong passphrase' and 0 for all other failures (so any
caller which already knows it's not loading an _encrypted private_
key can treat them as boolean)
- term->esc_query, and the 'query' parameter in toggle_mode in
terminal.c, which _usually_ hold 0 for ESC[123h or 1 for ESC[?123h,
but can also hold -1 for some other intervening character that we
don't support.
In a few places there's an integer that I haven't turned into a bool
even though it really _can_ only take values 0 or 1 (and, as above,
tried to make the call sites consistent in not calling those values
true and false), on the grounds that I thought it would make it more
confusing to imply that the 0 value was in some sense 'negative' or
bad and the 1 positive or good:
- the return value of plug_accepting uses the POSIXish convention of
0=success and nonzero=error; I think if I made it bool then I'd
also want to reverse its sense, and that's a job for a separate
piece of work.
- the 'screen' parameter to lineptr() in terminal.c, where 0 and 1
represent the default and alternate screens. There's no obvious
reason why one of those should be considered 'true' or 'positive'
or 'success' - they're just indices - so I've left it as int.
ssh_scp_recv had particularly confusing semantics for its previous int
return value: its call sites used '<= 0' to check for error, but it
never actually returned a negative number, just 0 or 1. Now the
function and its call sites agree that it's a bool.
In a couple of places I've renamed variables called 'ret', because I
don't like that name any more - it's unclear whether it means the
return value (in preparation) for the _containing_ function or the
return value received from a subroutine call, and occasionally I've
accidentally used the same variable for both and introduced a bug. So
where one of those got in my way, I've renamed it to 'toret' or 'retd'
(the latter short for 'returned') in line with my usual modern
practice, but I haven't done a thorough job of finding all of them.
Finally, one amusing side effect of doing this is that I've had to
separate quite a few chained assignments. It used to be perfectly fine
to write 'a = b = c = TRUE' when a,b,c were int and TRUE was just a
the 'true' defined by stdbool.h, that idiom provokes a warning from
gcc: 'suggest parentheses around assignment used as truth value'!
2018-11-02 19:23:19 +00:00
|
|
|
data = fontspec_new("", false, 0, 0);
|
2019-09-08 19:29:00 +00:00
|
|
|
sfree(escaped);
|
|
|
|
break;
|
|
|
|
default:
|
2019-09-09 18:07:55 +00:00
|
|
|
unreachable("bad control type in winctrl_layout");
|
2019-09-08 19:29:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Create a `struct winctrl' for this control, and advance
|
|
|
|
* the dialog ID counter, if it's actually been created
|
|
|
|
* (and isn't tabdelayed).
|
|
|
|
*/
|
|
|
|
if (pos.hwnd) {
|
|
|
|
struct winctrl *c = snew(struct winctrl);
|
|
|
|
|
|
|
|
c->ctrl = ctrl;
|
|
|
|
c->base_id = actual_base_id;
|
|
|
|
c->num_ids = num_ids;
|
|
|
|
c->data = data;
|
|
|
|
memcpy(c->shortcuts, shortcuts, sizeof(shortcuts));
|
|
|
|
winctrl_add(wc, c);
|
|
|
|
winctrl_add_shortcuts(dp, c);
|
|
|
|
if (actual_base_id == base_id)
|
|
|
|
base_id += num_ids;
|
|
|
|
} else {
|
2013-07-22 07:11:54 +00:00
|
|
|
sfree(data);
|
|
|
|
}
|
2003-03-05 22:07:40 +00:00
|
|
|
|
2019-09-08 19:29:00 +00:00
|
|
|
if (colstart >= 0) {
|
|
|
|
/*
|
|
|
|
* Update the ypos in all columns crossed by this
|
|
|
|
* control.
|
|
|
|
*/
|
|
|
|
int i;
|
|
|
|
for (i = colstart; i < colstart+colspan; i++)
|
|
|
|
columns[i].ypos = pos.ypos;
|
|
|
|
}
|
2001-08-08 20:44:35 +00:00
|
|
|
}
|
2003-03-05 22:07:40 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* We've now finished laying out the controls; so now update
|
|
|
|
* the ctlpos and control ID that were passed in, terminate
|
|
|
|
* any containing box, and return.
|
|
|
|
*/
|
|
|
|
for (i = 0; i < ncols; i++)
|
2019-09-08 19:29:00 +00:00
|
|
|
if (cp->ypos < columns[i].ypos)
|
|
|
|
cp->ypos = columns[i].ypos;
|
2003-03-05 22:07:40 +00:00
|
|
|
*id = base_id;
|
|
|
|
|
|
|
|
if (s->boxname && *s->boxname)
|
2019-09-08 19:29:00 +00:00
|
|
|
endbox(cp);
|
2003-03-05 22:07:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void winctrl_set_focus(union control *ctrl, struct dlgparam *dp,
|
2019-09-08 19:29:00 +00:00
|
|
|
bool has_focus)
|
2003-03-05 22:07:40 +00:00
|
|
|
{
|
|
|
|
if (has_focus) {
|
2019-09-08 19:29:00 +00:00
|
|
|
if (dp->focused)
|
|
|
|
dp->lastfocused = dp->focused;
|
|
|
|
dp->focused = ctrl;
|
2003-03-05 22:07:40 +00:00
|
|
|
} else if (!has_focus && dp->focused == ctrl) {
|
2019-09-08 19:29:00 +00:00
|
|
|
dp->lastfocused = dp->focused;
|
|
|
|
dp->focused = NULL;
|
2003-03-05 22:07:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-09-13 11:58:44 +00:00
|
|
|
union control *dlg_last_focused(union control *ctrl, dlgparam *dp)
|
2003-03-05 22:07:40 +00:00
|
|
|
{
|
2003-03-18 19:06:51 +00:00
|
|
|
return dp->focused == ctrl ? dp->lastfocused : dp->focused;
|
2003-03-05 22:07:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The dialog-box procedure calls this function to handle Windows
|
|
|
|
* messages on a control we manage.
|
|
|
|
*/
|
Convert a lot of 'int' variables to 'bool'.
My normal habit these days, in new code, is to treat int and bool as
_almost_ completely separate types. I'm still willing to use C's
implicit test for zero on an integer (e.g. 'if (!blob.len)' is fine,
no need to spell it out as blob.len != 0), but generally, if a
variable is going to be conceptually a boolean, I like to declare it
bool and assign to it using 'true' or 'false' rather than 0 or 1.
PuTTY is an exception, because it predates the C99 bool, and I've
stuck to its existing coding style even when adding new code to it.
But it's been annoying me more and more, so now that I've decided C99
bool is an acceptable thing to require from our toolchain in the first
place, here's a quite thorough trawl through the source doing
'boolification'. Many variables and function parameters are now typed
as bool rather than int; many assignments of 0 or 1 to those variables
are now spelled 'true' or 'false'.
I managed this thorough conversion with the help of a custom clang
plugin that I wrote to trawl the AST and apply heuristics to point out
where things might want changing. So I've even managed to do a decent
job on parts of the code I haven't looked at in years!
To make the plugin's work easier, I pushed platform front ends
generally in the direction of using standard 'bool' in preference to
platform-specific boolean types like Windows BOOL or GTK's gboolean;
I've left the platform booleans in places they _have_ to be for the
platform APIs to work right, but variables only used by my own code
have been converted wherever I found them.
In a few places there are int values that look very like booleans in
_most_ of the places they're used, but have a rarely-used third value,
or a distinction between different nonzero values that most users
don't care about. In these cases, I've _removed_ uses of 'true' and
'false' for the return values, to emphasise that there's something
more subtle going on than a simple boolean answer:
- the 'multisel' field in dialog.h's list box structure, for which
the GTK front end in particular recognises a difference between 1
and 2 but nearly everything else treats as boolean
- the 'urgent' parameter to plug_receive, where 1 vs 2 tells you
something about the specific location of the urgent pointer, but
most clients only care about 0 vs 'something nonzero'
- the return value of wc_match, where -1 indicates a syntax error in
the wildcard.
- the return values from SSH-1 RSA-key loading functions, which use
-1 for 'wrong passphrase' and 0 for all other failures (so any
caller which already knows it's not loading an _encrypted private_
key can treat them as boolean)
- term->esc_query, and the 'query' parameter in toggle_mode in
terminal.c, which _usually_ hold 0 for ESC[123h or 1 for ESC[?123h,
but can also hold -1 for some other intervening character that we
don't support.
In a few places there's an integer that I haven't turned into a bool
even though it really _can_ only take values 0 or 1 (and, as above,
tried to make the call sites consistent in not calling those values
true and false), on the grounds that I thought it would make it more
confusing to imply that the 0 value was in some sense 'negative' or
bad and the 1 positive or good:
- the return value of plug_accepting uses the POSIXish convention of
0=success and nonzero=error; I think if I made it bool then I'd
also want to reverse its sense, and that's a job for a separate
piece of work.
- the 'screen' parameter to lineptr() in terminal.c, where 0 and 1
represent the default and alternate screens. There's no obvious
reason why one of those should be considered 'true' or 'positive'
or 'success' - they're just indices - so I've left it as int.
ssh_scp_recv had particularly confusing semantics for its previous int
return value: its call sites used '<= 0' to check for error, but it
never actually returned a negative number, just 0 or 1. Now the
function and its call sites agree that it's a bool.
In a couple of places I've renamed variables called 'ret', because I
don't like that name any more - it's unclear whether it means the
return value (in preparation) for the _containing_ function or the
return value received from a subroutine call, and occasionally I've
accidentally used the same variable for both and introduced a bug. So
where one of those got in my way, I've renamed it to 'toret' or 'retd'
(the latter short for 'returned') in line with my usual modern
practice, but I haven't done a thorough job of finding all of them.
Finally, one amusing side effect of doing this is that I've had to
separate quite a few chained assignments. It used to be perfectly fine
to write 'a = b = c = TRUE' when a,b,c were int and TRUE was just a
the 'true' defined by stdbool.h, that idiom provokes a warning from
gcc: 'suggest parentheses around assignment used as truth value'!
2018-11-02 19:23:19 +00:00
|
|
|
bool winctrl_handle_command(struct dlgparam *dp, UINT msg,
|
|
|
|
WPARAM wParam, LPARAM lParam)
|
2003-03-05 22:07:40 +00:00
|
|
|
{
|
|
|
|
struct winctrl *c;
|
|
|
|
union control *ctrl;
|
Convert a lot of 'int' variables to 'bool'.
My normal habit these days, in new code, is to treat int and bool as
_almost_ completely separate types. I'm still willing to use C's
implicit test for zero on an integer (e.g. 'if (!blob.len)' is fine,
no need to spell it out as blob.len != 0), but generally, if a
variable is going to be conceptually a boolean, I like to declare it
bool and assign to it using 'true' or 'false' rather than 0 or 1.
PuTTY is an exception, because it predates the C99 bool, and I've
stuck to its existing coding style even when adding new code to it.
But it's been annoying me more and more, so now that I've decided C99
bool is an acceptable thing to require from our toolchain in the first
place, here's a quite thorough trawl through the source doing
'boolification'. Many variables and function parameters are now typed
as bool rather than int; many assignments of 0 or 1 to those variables
are now spelled 'true' or 'false'.
I managed this thorough conversion with the help of a custom clang
plugin that I wrote to trawl the AST and apply heuristics to point out
where things might want changing. So I've even managed to do a decent
job on parts of the code I haven't looked at in years!
To make the plugin's work easier, I pushed platform front ends
generally in the direction of using standard 'bool' in preference to
platform-specific boolean types like Windows BOOL or GTK's gboolean;
I've left the platform booleans in places they _have_ to be for the
platform APIs to work right, but variables only used by my own code
have been converted wherever I found them.
In a few places there are int values that look very like booleans in
_most_ of the places they're used, but have a rarely-used third value,
or a distinction between different nonzero values that most users
don't care about. In these cases, I've _removed_ uses of 'true' and
'false' for the return values, to emphasise that there's something
more subtle going on than a simple boolean answer:
- the 'multisel' field in dialog.h's list box structure, for which
the GTK front end in particular recognises a difference between 1
and 2 but nearly everything else treats as boolean
- the 'urgent' parameter to plug_receive, where 1 vs 2 tells you
something about the specific location of the urgent pointer, but
most clients only care about 0 vs 'something nonzero'
- the return value of wc_match, where -1 indicates a syntax error in
the wildcard.
- the return values from SSH-1 RSA-key loading functions, which use
-1 for 'wrong passphrase' and 0 for all other failures (so any
caller which already knows it's not loading an _encrypted private_
key can treat them as boolean)
- term->esc_query, and the 'query' parameter in toggle_mode in
terminal.c, which _usually_ hold 0 for ESC[123h or 1 for ESC[?123h,
but can also hold -1 for some other intervening character that we
don't support.
In a few places there's an integer that I haven't turned into a bool
even though it really _can_ only take values 0 or 1 (and, as above,
tried to make the call sites consistent in not calling those values
true and false), on the grounds that I thought it would make it more
confusing to imply that the 0 value was in some sense 'negative' or
bad and the 1 positive or good:
- the return value of plug_accepting uses the POSIXish convention of
0=success and nonzero=error; I think if I made it bool then I'd
also want to reverse its sense, and that's a job for a separate
piece of work.
- the 'screen' parameter to lineptr() in terminal.c, where 0 and 1
represent the default and alternate screens. There's no obvious
reason why one of those should be considered 'true' or 'positive'
or 'success' - they're just indices - so I've left it as int.
ssh_scp_recv had particularly confusing semantics for its previous int
return value: its call sites used '<= 0' to check for error, but it
never actually returned a negative number, just 0 or 1. Now the
function and its call sites agree that it's a bool.
In a couple of places I've renamed variables called 'ret', because I
don't like that name any more - it's unclear whether it means the
return value (in preparation) for the _containing_ function or the
return value received from a subroutine call, and occasionally I've
accidentally used the same variable for both and introduced a bug. So
where one of those got in my way, I've renamed it to 'toret' or 'retd'
(the latter short for 'returned') in line with my usual modern
practice, but I haven't done a thorough job of finding all of them.
Finally, one amusing side effect of doing this is that I've had to
separate quite a few chained assignments. It used to be perfectly fine
to write 'a = b = c = TRUE' when a,b,c were int and TRUE was just a
the 'true' defined by stdbool.h, that idiom provokes a warning from
gcc: 'suggest parentheses around assignment used as truth value'!
2018-11-02 19:23:19 +00:00
|
|
|
int i, id;
|
|
|
|
bool ret;
|
2003-03-05 22:07:40 +00:00
|
|
|
static UINT draglistmsg = WM_NULL;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Filter out pointless window messages. Our interest is in
|
|
|
|
* WM_COMMAND and the drag list message, and nothing else.
|
|
|
|
*/
|
|
|
|
if (draglistmsg == WM_NULL)
|
2019-09-08 19:29:00 +00:00
|
|
|
draglistmsg = RegisterWindowMessage (DRAGLISTMSGSTRING);
|
2003-03-05 22:07:40 +00:00
|
|
|
|
|
|
|
if (msg != draglistmsg && msg != WM_COMMAND && msg != WM_DRAWITEM)
|
2019-09-08 19:29:00 +00:00
|
|
|
return false;
|
2003-03-05 22:07:40 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Look up the control ID in our data.
|
|
|
|
*/
|
2003-03-06 12:41:39 +00:00
|
|
|
c = NULL;
|
2003-03-05 22:07:40 +00:00
|
|
|
for (i = 0; i < dp->nctrltrees; i++) {
|
2019-09-08 19:29:00 +00:00
|
|
|
c = winctrl_findbyid(dp->controltrees[i], LOWORD(wParam));
|
|
|
|
if (c)
|
|
|
|
break;
|
2003-03-05 22:07:40 +00:00
|
|
|
}
|
|
|
|
if (!c)
|
2019-09-08 19:29:00 +00:00
|
|
|
return false; /* we have nothing to do */
|
2003-03-05 22:07:40 +00:00
|
|
|
|
|
|
|
if (msg == WM_DRAWITEM) {
|
2019-09-08 19:29:00 +00:00
|
|
|
/*
|
|
|
|
* Owner-draw request for a panel title.
|
|
|
|
*/
|
|
|
|
LPDRAWITEMSTRUCT di = (LPDRAWITEMSTRUCT) lParam;
|
|
|
|
HDC hdc = di->hDC;
|
|
|
|
RECT r = di->rcItem;
|
|
|
|
SIZE s;
|
|
|
|
|
|
|
|
SetMapMode(hdc, MM_TEXT); /* ensure logical units == pixels */
|
|
|
|
|
|
|
|
GetTextExtentPoint32(hdc, (char *)c->data,
|
|
|
|
strlen((char *)c->data), &s);
|
|
|
|
DrawEdge(hdc, &r, EDGE_ETCHED, BF_ADJUST | BF_RECT);
|
|
|
|
TextOut(hdc,
|
|
|
|
r.left + (r.right-r.left-s.cx)/2,
|
|
|
|
r.top + (r.bottom-r.top-s.cy)/2,
|
|
|
|
(char *)c->data, strlen((char *)c->data));
|
|
|
|
|
|
|
|
return true;
|
2003-03-05 22:07:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
ctrl = c->ctrl;
|
|
|
|
id = LOWORD(wParam) - c->base_id;
|
|
|
|
|
|
|
|
if (!ctrl || !ctrl->generic.handler)
|
2019-09-08 19:29:00 +00:00
|
|
|
return false; /* nothing we can do here */
|
2003-03-05 22:07:40 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* From here on we do not issue `return' statements until the
|
|
|
|
* very end of the dialog box: any event handler is entitled to
|
|
|
|
* ask for a colour selector, so we _must_ always allow control
|
|
|
|
* to reach the end of this switch statement so that the
|
|
|
|
* subsequent code can test dp->coloursel_wanted().
|
|
|
|
*/
|
Convert a lot of 'int' variables to 'bool'.
My normal habit these days, in new code, is to treat int and bool as
_almost_ completely separate types. I'm still willing to use C's
implicit test for zero on an integer (e.g. 'if (!blob.len)' is fine,
no need to spell it out as blob.len != 0), but generally, if a
variable is going to be conceptually a boolean, I like to declare it
bool and assign to it using 'true' or 'false' rather than 0 or 1.
PuTTY is an exception, because it predates the C99 bool, and I've
stuck to its existing coding style even when adding new code to it.
But it's been annoying me more and more, so now that I've decided C99
bool is an acceptable thing to require from our toolchain in the first
place, here's a quite thorough trawl through the source doing
'boolification'. Many variables and function parameters are now typed
as bool rather than int; many assignments of 0 or 1 to those variables
are now spelled 'true' or 'false'.
I managed this thorough conversion with the help of a custom clang
plugin that I wrote to trawl the AST and apply heuristics to point out
where things might want changing. So I've even managed to do a decent
job on parts of the code I haven't looked at in years!
To make the plugin's work easier, I pushed platform front ends
generally in the direction of using standard 'bool' in preference to
platform-specific boolean types like Windows BOOL or GTK's gboolean;
I've left the platform booleans in places they _have_ to be for the
platform APIs to work right, but variables only used by my own code
have been converted wherever I found them.
In a few places there are int values that look very like booleans in
_most_ of the places they're used, but have a rarely-used third value,
or a distinction between different nonzero values that most users
don't care about. In these cases, I've _removed_ uses of 'true' and
'false' for the return values, to emphasise that there's something
more subtle going on than a simple boolean answer:
- the 'multisel' field in dialog.h's list box structure, for which
the GTK front end in particular recognises a difference between 1
and 2 but nearly everything else treats as boolean
- the 'urgent' parameter to plug_receive, where 1 vs 2 tells you
something about the specific location of the urgent pointer, but
most clients only care about 0 vs 'something nonzero'
- the return value of wc_match, where -1 indicates a syntax error in
the wildcard.
- the return values from SSH-1 RSA-key loading functions, which use
-1 for 'wrong passphrase' and 0 for all other failures (so any
caller which already knows it's not loading an _encrypted private_
key can treat them as boolean)
- term->esc_query, and the 'query' parameter in toggle_mode in
terminal.c, which _usually_ hold 0 for ESC[123h or 1 for ESC[?123h,
but can also hold -1 for some other intervening character that we
don't support.
In a few places there's an integer that I haven't turned into a bool
even though it really _can_ only take values 0 or 1 (and, as above,
tried to make the call sites consistent in not calling those values
true and false), on the grounds that I thought it would make it more
confusing to imply that the 0 value was in some sense 'negative' or
bad and the 1 positive or good:
- the return value of plug_accepting uses the POSIXish convention of
0=success and nonzero=error; I think if I made it bool then I'd
also want to reverse its sense, and that's a job for a separate
piece of work.
- the 'screen' parameter to lineptr() in terminal.c, where 0 and 1
represent the default and alternate screens. There's no obvious
reason why one of those should be considered 'true' or 'positive'
or 'success' - they're just indices - so I've left it as int.
ssh_scp_recv had particularly confusing semantics for its previous int
return value: its call sites used '<= 0' to check for error, but it
never actually returned a negative number, just 0 or 1. Now the
function and its call sites agree that it's a bool.
In a couple of places I've renamed variables called 'ret', because I
don't like that name any more - it's unclear whether it means the
return value (in preparation) for the _containing_ function or the
return value received from a subroutine call, and occasionally I've
accidentally used the same variable for both and introduced a bug. So
where one of those got in my way, I've renamed it to 'toret' or 'retd'
(the latter short for 'returned') in line with my usual modern
practice, but I haven't done a thorough job of finding all of them.
Finally, one amusing side effect of doing this is that I've had to
separate quite a few chained assignments. It used to be perfectly fine
to write 'a = b = c = TRUE' when a,b,c were int and TRUE was just a
the 'true' defined by stdbool.h, that idiom provokes a warning from
gcc: 'suggest parentheses around assignment used as truth value'!
2018-11-02 19:23:19 +00:00
|
|
|
ret = false;
|
2018-10-29 19:50:29 +00:00
|
|
|
dp->coloursel_wanted = false;
|
2003-03-05 22:07:40 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Now switch on the control type and the message.
|
|
|
|
*/
|
|
|
|
switch (ctrl->generic.type) {
|
|
|
|
case CTRL_EDITBOX:
|
2019-09-08 19:29:00 +00:00
|
|
|
if (msg == WM_COMMAND && !ctrl->editbox.has_list &&
|
|
|
|
(HIWORD(wParam) == EN_SETFOCUS || HIWORD(wParam) == EN_KILLFOCUS))
|
|
|
|
winctrl_set_focus(ctrl, dp, HIWORD(wParam) == EN_SETFOCUS);
|
|
|
|
if (msg == WM_COMMAND && ctrl->editbox.has_list &&
|
|
|
|
(HIWORD(wParam)==CBN_SETFOCUS || HIWORD(wParam)==CBN_KILLFOCUS))
|
|
|
|
winctrl_set_focus(ctrl, dp, HIWORD(wParam) == CBN_SETFOCUS);
|
|
|
|
|
|
|
|
if (msg == WM_COMMAND && !ctrl->editbox.has_list &&
|
|
|
|
HIWORD(wParam) == EN_CHANGE)
|
|
|
|
ctrl->generic.handler(ctrl, dp, dp->data, EVENT_VALCHANGE);
|
|
|
|
if (msg == WM_COMMAND &&
|
|
|
|
ctrl->editbox.has_list) {
|
|
|
|
if (HIWORD(wParam) == CBN_SELCHANGE) {
|
|
|
|
int index, len;
|
|
|
|
char *text;
|
|
|
|
|
|
|
|
index = SendDlgItemMessage(dp->hwnd, c->base_id+1,
|
|
|
|
CB_GETCURSEL, 0, 0);
|
|
|
|
len = SendDlgItemMessage(dp->hwnd, c->base_id+1,
|
|
|
|
CB_GETLBTEXTLEN, index, 0);
|
|
|
|
text = snewn(len+1, char);
|
|
|
|
SendDlgItemMessage(dp->hwnd, c->base_id+1, CB_GETLBTEXT,
|
|
|
|
index, (LPARAM)text);
|
|
|
|
SetDlgItemText(dp->hwnd, c->base_id+1, text);
|
|
|
|
sfree(text);
|
|
|
|
ctrl->generic.handler(ctrl, dp, dp->data, EVENT_VALCHANGE);
|
|
|
|
} else if (HIWORD(wParam) == CBN_EDITCHANGE) {
|
|
|
|
ctrl->generic.handler(ctrl, dp, dp->data, EVENT_VALCHANGE);
|
|
|
|
} else if (HIWORD(wParam) == CBN_KILLFOCUS) {
|
|
|
|
ctrl->generic.handler(ctrl, dp, dp->data, EVENT_REFRESH);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
break;
|
2003-03-05 22:07:40 +00:00
|
|
|
case CTRL_RADIO:
|
2019-09-08 19:29:00 +00:00
|
|
|
if (msg == WM_COMMAND &&
|
|
|
|
(HIWORD(wParam) == BN_SETFOCUS || HIWORD(wParam) == BN_KILLFOCUS))
|
|
|
|
winctrl_set_focus(ctrl, dp, HIWORD(wParam) == BN_SETFOCUS);
|
|
|
|
/*
|
|
|
|
* We sometimes get spurious BN_CLICKED messages for the
|
|
|
|
* radio button that is just about to _lose_ selection, if
|
|
|
|
* we're switching using the arrow keys. Therefore we
|
|
|
|
* double-check that the button in wParam is actually
|
|
|
|
* checked before generating an event.
|
|
|
|
*/
|
|
|
|
if (msg == WM_COMMAND &&
|
|
|
|
(HIWORD(wParam) == BN_CLICKED ||
|
|
|
|
HIWORD(wParam) == BN_DOUBLECLICKED) &&
|
|
|
|
IsDlgButtonChecked(dp->hwnd, LOWORD(wParam))) {
|
|
|
|
ctrl->generic.handler(ctrl, dp, dp->data, EVENT_VALCHANGE);
|
|
|
|
}
|
|
|
|
break;
|
2003-03-05 22:07:40 +00:00
|
|
|
case CTRL_CHECKBOX:
|
2019-09-08 19:29:00 +00:00
|
|
|
if (msg == WM_COMMAND &&
|
|
|
|
(HIWORD(wParam) == BN_SETFOCUS || HIWORD(wParam) == BN_KILLFOCUS))
|
|
|
|
winctrl_set_focus(ctrl, dp, HIWORD(wParam) == BN_SETFOCUS);
|
|
|
|
if (msg == WM_COMMAND &&
|
|
|
|
(HIWORD(wParam) == BN_CLICKED ||
|
|
|
|
HIWORD(wParam) == BN_DOUBLECLICKED)) {
|
|
|
|
ctrl->generic.handler(ctrl, dp, dp->data, EVENT_VALCHANGE);
|
|
|
|
}
|
|
|
|
break;
|
2003-03-05 22:07:40 +00:00
|
|
|
case CTRL_BUTTON:
|
2019-09-08 19:29:00 +00:00
|
|
|
if (msg == WM_COMMAND &&
|
|
|
|
(HIWORD(wParam) == BN_SETFOCUS || HIWORD(wParam) == BN_KILLFOCUS))
|
|
|
|
winctrl_set_focus(ctrl, dp, HIWORD(wParam) == BN_SETFOCUS);
|
|
|
|
if (msg == WM_COMMAND &&
|
|
|
|
(HIWORD(wParam) == BN_CLICKED ||
|
|
|
|
HIWORD(wParam) == BN_DOUBLECLICKED)) {
|
|
|
|
ctrl->generic.handler(ctrl, dp, dp->data, EVENT_ACTION);
|
|
|
|
}
|
|
|
|
break;
|
2003-03-05 22:07:40 +00:00
|
|
|
case CTRL_LISTBOX:
|
2019-09-08 19:29:00 +00:00
|
|
|
if (msg == WM_COMMAND && ctrl->listbox.height != 0 &&
|
|
|
|
(HIWORD(wParam)==LBN_SETFOCUS || HIWORD(wParam)==LBN_KILLFOCUS))
|
|
|
|
winctrl_set_focus(ctrl, dp, HIWORD(wParam) == LBN_SETFOCUS);
|
|
|
|
if (msg == WM_COMMAND && ctrl->listbox.height == 0 &&
|
|
|
|
(HIWORD(wParam)==CBN_SETFOCUS || HIWORD(wParam)==CBN_KILLFOCUS))
|
|
|
|
winctrl_set_focus(ctrl, dp, HIWORD(wParam) == CBN_SETFOCUS);
|
|
|
|
if (msg == WM_COMMAND && id >= 2 &&
|
|
|
|
(HIWORD(wParam) == BN_SETFOCUS || HIWORD(wParam) == BN_KILLFOCUS))
|
|
|
|
winctrl_set_focus(ctrl, dp, HIWORD(wParam) == BN_SETFOCUS);
|
|
|
|
if (ctrl->listbox.draglist) {
|
|
|
|
int pret;
|
|
|
|
pret = handle_prefslist(c->data, NULL, 0, (msg != WM_COMMAND),
|
|
|
|
dp->hwnd, wParam, lParam);
|
|
|
|
if (pret & 2)
|
|
|
|
ctrl->generic.handler(ctrl, dp, dp->data, EVENT_VALCHANGE);
|
|
|
|
ret = pret & 1;
|
|
|
|
} else {
|
|
|
|
if (msg == WM_COMMAND && HIWORD(wParam) == LBN_DBLCLK) {
|
|
|
|
SetCapture(dp->hwnd);
|
|
|
|
ctrl->generic.handler(ctrl, dp, dp->data, EVENT_ACTION);
|
|
|
|
} else if (msg == WM_COMMAND && HIWORD(wParam) == LBN_SELCHANGE) {
|
|
|
|
ctrl->generic.handler(ctrl, dp, dp->data, EVENT_SELCHANGE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
2003-03-05 22:07:40 +00:00
|
|
|
case CTRL_FILESELECT:
|
2019-09-08 19:29:00 +00:00
|
|
|
if (msg == WM_COMMAND && id == 1 &&
|
|
|
|
(HIWORD(wParam) == EN_SETFOCUS || HIWORD(wParam) == EN_KILLFOCUS))
|
|
|
|
winctrl_set_focus(ctrl, dp, HIWORD(wParam) == EN_SETFOCUS);
|
|
|
|
if (msg == WM_COMMAND && id == 2 &&
|
|
|
|
(HIWORD(wParam) == BN_SETFOCUS || HIWORD(wParam) == BN_KILLFOCUS))
|
|
|
|
winctrl_set_focus(ctrl, dp, HIWORD(wParam) == BN_SETFOCUS);
|
|
|
|
if (msg == WM_COMMAND && id == 1 && HIWORD(wParam) == EN_CHANGE)
|
|
|
|
ctrl->generic.handler(ctrl, dp, dp->data, EVENT_VALCHANGE);
|
|
|
|
if (id == 2 &&
|
|
|
|
(msg == WM_COMMAND &&
|
|
|
|
(HIWORD(wParam) == BN_CLICKED ||
|
|
|
|
HIWORD(wParam) == BN_DOUBLECLICKED))) {
|
|
|
|
OPENFILENAME of;
|
|
|
|
char filename[FILENAME_MAX];
|
|
|
|
|
|
|
|
memset(&of, 0, sizeof(of));
|
|
|
|
of.hwndOwner = dp->hwnd;
|
|
|
|
if (ctrl->fileselect.filter)
|
|
|
|
of.lpstrFilter = ctrl->fileselect.filter;
|
|
|
|
else
|
|
|
|
of.lpstrFilter = "All Files (*.*)\0*\0\0\0";
|
|
|
|
of.lpstrCustomFilter = NULL;
|
|
|
|
of.nFilterIndex = 1;
|
|
|
|
of.lpstrFile = filename;
|
|
|
|
GetDlgItemText(dp->hwnd, c->base_id+1, filename, lenof(filename));
|
|
|
|
filename[lenof(filename)-1] = '\0';
|
|
|
|
of.nMaxFile = lenof(filename);
|
|
|
|
of.lpstrFileTitle = NULL;
|
|
|
|
of.lpstrTitle = ctrl->fileselect.title;
|
|
|
|
of.Flags = 0;
|
|
|
|
if (request_file(NULL, &of, false, ctrl->fileselect.for_writing)) {
|
|
|
|
SetDlgItemText(dp->hwnd, c->base_id + 1, filename);
|
|
|
|
ctrl->generic.handler(ctrl, dp, dp->data, EVENT_VALCHANGE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
2003-03-05 22:07:40 +00:00
|
|
|
case CTRL_FONTSELECT:
|
2019-09-08 19:29:00 +00:00
|
|
|
if (msg == WM_COMMAND && id == 2 &&
|
|
|
|
(HIWORD(wParam) == BN_SETFOCUS || HIWORD(wParam) == BN_KILLFOCUS))
|
|
|
|
winctrl_set_focus(ctrl, dp, HIWORD(wParam) == BN_SETFOCUS);
|
|
|
|
if (id == 2 &&
|
|
|
|
(msg == WM_COMMAND &&
|
|
|
|
(HIWORD(wParam) == BN_CLICKED ||
|
|
|
|
HIWORD(wParam) == BN_DOUBLECLICKED))) {
|
|
|
|
CHOOSEFONT cf;
|
|
|
|
LOGFONT lf;
|
|
|
|
HDC hdc;
|
|
|
|
FontSpec *fs = (FontSpec *)c->data;
|
|
|
|
|
|
|
|
hdc = GetDC(0);
|
|
|
|
lf.lfHeight = -MulDiv(fs->height,
|
|
|
|
GetDeviceCaps(hdc, LOGPIXELSY), 72);
|
|
|
|
ReleaseDC(0, hdc);
|
|
|
|
lf.lfWidth = lf.lfEscapement = lf.lfOrientation = 0;
|
|
|
|
lf.lfItalic = lf.lfUnderline = lf.lfStrikeOut = 0;
|
|
|
|
lf.lfWeight = (fs->isbold ? FW_BOLD : 0);
|
|
|
|
lf.lfCharSet = fs->charset;
|
|
|
|
lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
|
|
|
|
lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
|
|
|
|
lf.lfQuality = DEFAULT_QUALITY;
|
|
|
|
lf.lfPitchAndFamily = FIXED_PITCH | FF_DONTCARE;
|
|
|
|
strncpy(lf.lfFaceName, fs->name,
|
|
|
|
sizeof(lf.lfFaceName) - 1);
|
|
|
|
lf.lfFaceName[sizeof(lf.lfFaceName) - 1] = '\0';
|
|
|
|
|
|
|
|
cf.lStructSize = sizeof(cf);
|
|
|
|
cf.hwndOwner = dp->hwnd;
|
|
|
|
cf.lpLogFont = &lf;
|
|
|
|
cf.Flags = (dp->fixed_pitch_fonts ? CF_FIXEDPITCHONLY : 0) |
|
2010-12-29 14:11:25 +00:00
|
|
|
CF_FORCEFONTEXIST | CF_INITTOLOGFONTSTRUCT | CF_SCREENFONTS;
|
2003-03-05 22:07:40 +00:00
|
|
|
|
2019-09-08 19:29:00 +00:00
|
|
|
if (ChooseFont(&cf)) {
|
2011-10-01 17:38:59 +00:00
|
|
|
fs = fontspec_new(lf.lfFaceName, (lf.lfWeight == FW_BOLD),
|
|
|
|
cf.iPointSize / 10, lf.lfCharSet);
|
2019-09-08 19:29:00 +00:00
|
|
|
dlg_fontsel_set(ctrl, dp, fs);
|
2011-10-01 17:38:59 +00:00
|
|
|
fontspec_free(fs);
|
|
|
|
|
2019-09-08 19:29:00 +00:00
|
|
|
ctrl->generic.handler(ctrl, dp, dp->data, EVENT_VALCHANGE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
2003-03-05 22:07:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If the above event handler has asked for a colour selector,
|
|
|
|
* now is the time to generate one.
|
|
|
|
*/
|
|
|
|
if (dp->coloursel_wanted) {
|
2019-09-08 19:29:00 +00:00
|
|
|
static CHOOSECOLOR cc;
|
|
|
|
static DWORD custom[16] = { 0 }; /* zero initialisers */
|
|
|
|
cc.lStructSize = sizeof(cc);
|
|
|
|
cc.hwndOwner = dp->hwnd;
|
|
|
|
cc.hInstance = (HWND) hinst;
|
|
|
|
cc.lpCustColors = custom;
|
|
|
|
cc.rgbResult = RGB(dp->coloursel_result.r,
|
|
|
|
dp->coloursel_result.g,
|
|
|
|
dp->coloursel_result.b);
|
|
|
|
cc.Flags = CC_FULLOPEN | CC_RGBINIT;
|
|
|
|
if (ChooseColor(&cc)) {
|
|
|
|
dp->coloursel_result.r =
|
|
|
|
(unsigned char) (cc.rgbResult & 0xFF);
|
|
|
|
dp->coloursel_result.g =
|
|
|
|
(unsigned char) (cc.rgbResult >> 8) & 0xFF;
|
|
|
|
dp->coloursel_result.b =
|
|
|
|
(unsigned char) (cc.rgbResult >> 16) & 0xFF;
|
|
|
|
dp->coloursel_result.ok = true;
|
|
|
|
} else
|
|
|
|
dp->coloursel_result.ok = false;
|
|
|
|
ctrl->generic.handler(ctrl, dp, dp->data, EVENT_CALLBACK);
|
2003-03-05 22:07:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* This function can be called to produce context help on a
|
2018-10-29 19:50:29 +00:00
|
|
|
* control. Returns true if it has actually launched some help.
|
2003-03-05 22:07:40 +00:00
|
|
|
*/
|
Convert a lot of 'int' variables to 'bool'.
My normal habit these days, in new code, is to treat int and bool as
_almost_ completely separate types. I'm still willing to use C's
implicit test for zero on an integer (e.g. 'if (!blob.len)' is fine,
no need to spell it out as blob.len != 0), but generally, if a
variable is going to be conceptually a boolean, I like to declare it
bool and assign to it using 'true' or 'false' rather than 0 or 1.
PuTTY is an exception, because it predates the C99 bool, and I've
stuck to its existing coding style even when adding new code to it.
But it's been annoying me more and more, so now that I've decided C99
bool is an acceptable thing to require from our toolchain in the first
place, here's a quite thorough trawl through the source doing
'boolification'. Many variables and function parameters are now typed
as bool rather than int; many assignments of 0 or 1 to those variables
are now spelled 'true' or 'false'.
I managed this thorough conversion with the help of a custom clang
plugin that I wrote to trawl the AST and apply heuristics to point out
where things might want changing. So I've even managed to do a decent
job on parts of the code I haven't looked at in years!
To make the plugin's work easier, I pushed platform front ends
generally in the direction of using standard 'bool' in preference to
platform-specific boolean types like Windows BOOL or GTK's gboolean;
I've left the platform booleans in places they _have_ to be for the
platform APIs to work right, but variables only used by my own code
have been converted wherever I found them.
In a few places there are int values that look very like booleans in
_most_ of the places they're used, but have a rarely-used third value,
or a distinction between different nonzero values that most users
don't care about. In these cases, I've _removed_ uses of 'true' and
'false' for the return values, to emphasise that there's something
more subtle going on than a simple boolean answer:
- the 'multisel' field in dialog.h's list box structure, for which
the GTK front end in particular recognises a difference between 1
and 2 but nearly everything else treats as boolean
- the 'urgent' parameter to plug_receive, where 1 vs 2 tells you
something about the specific location of the urgent pointer, but
most clients only care about 0 vs 'something nonzero'
- the return value of wc_match, where -1 indicates a syntax error in
the wildcard.
- the return values from SSH-1 RSA-key loading functions, which use
-1 for 'wrong passphrase' and 0 for all other failures (so any
caller which already knows it's not loading an _encrypted private_
key can treat them as boolean)
- term->esc_query, and the 'query' parameter in toggle_mode in
terminal.c, which _usually_ hold 0 for ESC[123h or 1 for ESC[?123h,
but can also hold -1 for some other intervening character that we
don't support.
In a few places there's an integer that I haven't turned into a bool
even though it really _can_ only take values 0 or 1 (and, as above,
tried to make the call sites consistent in not calling those values
true and false), on the grounds that I thought it would make it more
confusing to imply that the 0 value was in some sense 'negative' or
bad and the 1 positive or good:
- the return value of plug_accepting uses the POSIXish convention of
0=success and nonzero=error; I think if I made it bool then I'd
also want to reverse its sense, and that's a job for a separate
piece of work.
- the 'screen' parameter to lineptr() in terminal.c, where 0 and 1
represent the default and alternate screens. There's no obvious
reason why one of those should be considered 'true' or 'positive'
or 'success' - they're just indices - so I've left it as int.
ssh_scp_recv had particularly confusing semantics for its previous int
return value: its call sites used '<= 0' to check for error, but it
never actually returned a negative number, just 0 or 1. Now the
function and its call sites agree that it's a bool.
In a couple of places I've renamed variables called 'ret', because I
don't like that name any more - it's unclear whether it means the
return value (in preparation) for the _containing_ function or the
return value received from a subroutine call, and occasionally I've
accidentally used the same variable for both and introduced a bug. So
where one of those got in my way, I've renamed it to 'toret' or 'retd'
(the latter short for 'returned') in line with my usual modern
practice, but I haven't done a thorough job of finding all of them.
Finally, one amusing side effect of doing this is that I've had to
separate quite a few chained assignments. It used to be perfectly fine
to write 'a = b = c = TRUE' when a,b,c were int and TRUE was just a
the 'true' defined by stdbool.h, that idiom provokes a warning from
gcc: 'suggest parentheses around assignment used as truth value'!
2018-11-02 19:23:19 +00:00
|
|
|
bool winctrl_context_help(struct dlgparam *dp, HWND hwnd, int id)
|
2003-03-05 22:07:40 +00:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
struct winctrl *c;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Look up the control ID in our data.
|
|
|
|
*/
|
2003-03-06 12:41:39 +00:00
|
|
|
c = NULL;
|
2003-03-05 22:07:40 +00:00
|
|
|
for (i = 0; i < dp->nctrltrees; i++) {
|
2019-09-08 19:29:00 +00:00
|
|
|
c = winctrl_findbyid(dp->controltrees[i], id);
|
|
|
|
if (c)
|
|
|
|
break;
|
2003-03-05 22:07:40 +00:00
|
|
|
}
|
|
|
|
if (!c)
|
2019-09-08 19:29:00 +00:00
|
|
|
return false; /* we have nothing to do */
|
2003-03-05 22:07:40 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* This is the Windows front end, so we're allowed to assume
|
|
|
|
* `helpctx.p' is a context string.
|
|
|
|
*/
|
|
|
|
if (!c->ctrl || !c->ctrl->generic.helpctx.p)
|
2019-09-08 19:29:00 +00:00
|
|
|
return false; /* no help available for this ctrl */
|
2003-03-05 22:07:40 +00:00
|
|
|
|
2006-12-17 11:16:07 +00:00
|
|
|
launch_help(hwnd, c->ctrl->generic.helpctx.p);
|
Convert a lot of 'int' variables to 'bool'.
My normal habit these days, in new code, is to treat int and bool as
_almost_ completely separate types. I'm still willing to use C's
implicit test for zero on an integer (e.g. 'if (!blob.len)' is fine,
no need to spell it out as blob.len != 0), but generally, if a
variable is going to be conceptually a boolean, I like to declare it
bool and assign to it using 'true' or 'false' rather than 0 or 1.
PuTTY is an exception, because it predates the C99 bool, and I've
stuck to its existing coding style even when adding new code to it.
But it's been annoying me more and more, so now that I've decided C99
bool is an acceptable thing to require from our toolchain in the first
place, here's a quite thorough trawl through the source doing
'boolification'. Many variables and function parameters are now typed
as bool rather than int; many assignments of 0 or 1 to those variables
are now spelled 'true' or 'false'.
I managed this thorough conversion with the help of a custom clang
plugin that I wrote to trawl the AST and apply heuristics to point out
where things might want changing. So I've even managed to do a decent
job on parts of the code I haven't looked at in years!
To make the plugin's work easier, I pushed platform front ends
generally in the direction of using standard 'bool' in preference to
platform-specific boolean types like Windows BOOL or GTK's gboolean;
I've left the platform booleans in places they _have_ to be for the
platform APIs to work right, but variables only used by my own code
have been converted wherever I found them.
In a few places there are int values that look very like booleans in
_most_ of the places they're used, but have a rarely-used third value,
or a distinction between different nonzero values that most users
don't care about. In these cases, I've _removed_ uses of 'true' and
'false' for the return values, to emphasise that there's something
more subtle going on than a simple boolean answer:
- the 'multisel' field in dialog.h's list box structure, for which
the GTK front end in particular recognises a difference between 1
and 2 but nearly everything else treats as boolean
- the 'urgent' parameter to plug_receive, where 1 vs 2 tells you
something about the specific location of the urgent pointer, but
most clients only care about 0 vs 'something nonzero'
- the return value of wc_match, where -1 indicates a syntax error in
the wildcard.
- the return values from SSH-1 RSA-key loading functions, which use
-1 for 'wrong passphrase' and 0 for all other failures (so any
caller which already knows it's not loading an _encrypted private_
key can treat them as boolean)
- term->esc_query, and the 'query' parameter in toggle_mode in
terminal.c, which _usually_ hold 0 for ESC[123h or 1 for ESC[?123h,
but can also hold -1 for some other intervening character that we
don't support.
In a few places there's an integer that I haven't turned into a bool
even though it really _can_ only take values 0 or 1 (and, as above,
tried to make the call sites consistent in not calling those values
true and false), on the grounds that I thought it would make it more
confusing to imply that the 0 value was in some sense 'negative' or
bad and the 1 positive or good:
- the return value of plug_accepting uses the POSIXish convention of
0=success and nonzero=error; I think if I made it bool then I'd
also want to reverse its sense, and that's a job for a separate
piece of work.
- the 'screen' parameter to lineptr() in terminal.c, where 0 and 1
represent the default and alternate screens. There's no obvious
reason why one of those should be considered 'true' or 'positive'
or 'success' - they're just indices - so I've left it as int.
ssh_scp_recv had particularly confusing semantics for its previous int
return value: its call sites used '<= 0' to check for error, but it
never actually returned a negative number, just 0 or 1. Now the
function and its call sites agree that it's a bool.
In a couple of places I've renamed variables called 'ret', because I
don't like that name any more - it's unclear whether it means the
return value (in preparation) for the _containing_ function or the
return value received from a subroutine call, and occasionally I've
accidentally used the same variable for both and introduced a bug. So
where one of those got in my way, I've renamed it to 'toret' or 'retd'
(the latter short for 'returned') in line with my usual modern
practice, but I haven't done a thorough job of finding all of them.
Finally, one amusing side effect of doing this is that I've had to
separate quite a few chained assignments. It used to be perfectly fine
to write 'a = b = c = TRUE' when a,b,c were int and TRUE was just a
the 'true' defined by stdbool.h, that idiom provokes a warning from
gcc: 'suggest parentheses around assignment used as truth value'!
2018-11-02 19:23:19 +00:00
|
|
|
return true;
|
2003-03-05 22:07:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Now the various functions that the platform-independent
|
|
|
|
* mechanism can call to access the dialog box entries.
|
|
|
|
*/
|
|
|
|
|
|
|
|
static struct winctrl *dlg_findbyctrl(struct dlgparam *dp, union control *ctrl)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < dp->nctrltrees; i++) {
|
2019-09-08 19:29:00 +00:00
|
|
|
struct winctrl *c = winctrl_findbyctrl(dp->controltrees[i], ctrl);
|
|
|
|
if (c)
|
|
|
|
return c;
|
2003-03-05 22:07:40 +00:00
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
Don't implicitly load a session if Session pane not active.
If you select an entry in the saved sessions list box, but without
double-clicking to actually load it, and then you hit OK, the config-
box code will automatically load it. That just saves one click in a
common situation.
But in order to load that session, the config-box system first has to
ask the list-box control _which_ session is selected. On Windows, this
causes an assertion failure if the user has switched away from the
Session panel to some other panel of the config box, because when the
list box isn't on screen, its Windows control object is actually
destroyed.
I think a sensible answer is that we shouldn't be doing that implicit
load behaviour in any case if the list box isn't _visible_: silently
loading and launching a session someone selected a lot of UI actions
ago wasn't really the point. So now I make that behaviour only happen
when the list box (i.e. the Session panel) _is_ visible. That should
prevent the assertion failure on Windows, but the UI effect is cross-
platform, applying even on GTK where the control objects for invisible
panels persist and so the assertion failure didn't happen. I think
it's a reasonable UI change to make globally.
In order to implement it, I've had to invent a new query function so
that config.c can tell whether a given control is visible. In order to
do that on GTK, I had to give each control a pointer to the 'selparam'
structure describing its config-box pane, so that query function could
check it against the current one - and in order to do _that_, I had to
first arrange that those 'selparam' structures have stable addresses
from the moment they're first created, which meant adding a layer of
indirection so that the array of them in the top-level dlgparam
structure is now an array of _pointers_ rather than of actual structs.
(That way, realloc half way through config box creation can't
invalidate the important pointer values.)
2019-06-29 16:12:47 +00:00
|
|
|
bool dlg_is_visible(union control *ctrl, dlgparam *dp)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* In this implementation of the dialog box, we physically
|
|
|
|
* uncreate controls that aren't in a visible panel of the config
|
|
|
|
* box. So we can tell if a control is visible just by checking if
|
|
|
|
* it _exists_.
|
|
|
|
*/
|
|
|
|
return dlg_findbyctrl(dp, ctrl) != NULL;
|
|
|
|
}
|
|
|
|
|
2018-09-13 11:58:44 +00:00
|
|
|
void dlg_radiobutton_set(union control *ctrl, dlgparam *dp, int whichbutton)
|
2003-03-05 22:07:40 +00:00
|
|
|
{
|
|
|
|
struct winctrl *c = dlg_findbyctrl(dp, ctrl);
|
|
|
|
assert(c && c->ctrl->generic.type == CTRL_RADIO);
|
|
|
|
CheckRadioButton(dp->hwnd,
|
2019-09-08 19:29:00 +00:00
|
|
|
c->base_id + 1,
|
|
|
|
c->base_id + c->ctrl->radio.nbuttons,
|
|
|
|
c->base_id + 1 + whichbutton);
|
2003-03-05 22:07:40 +00:00
|
|
|
}
|
|
|
|
|
2018-09-13 11:58:44 +00:00
|
|
|
int dlg_radiobutton_get(union control *ctrl, dlgparam *dp)
|
2003-03-05 22:07:40 +00:00
|
|
|
{
|
|
|
|
struct winctrl *c = dlg_findbyctrl(dp, ctrl);
|
|
|
|
int i;
|
|
|
|
assert(c && c->ctrl->generic.type == CTRL_RADIO);
|
|
|
|
for (i = 0; i < c->ctrl->radio.nbuttons; i++)
|
2019-09-08 19:29:00 +00:00
|
|
|
if (IsDlgButtonChecked(dp->hwnd, c->base_id + 1 + i))
|
|
|
|
return i;
|
2019-09-09 18:07:55 +00:00
|
|
|
unreachable("no radio button was checked");
|
2003-03-05 22:07:40 +00:00
|
|
|
}
|
|
|
|
|
Convert a lot of 'int' variables to 'bool'.
My normal habit these days, in new code, is to treat int and bool as
_almost_ completely separate types. I'm still willing to use C's
implicit test for zero on an integer (e.g. 'if (!blob.len)' is fine,
no need to spell it out as blob.len != 0), but generally, if a
variable is going to be conceptually a boolean, I like to declare it
bool and assign to it using 'true' or 'false' rather than 0 or 1.
PuTTY is an exception, because it predates the C99 bool, and I've
stuck to its existing coding style even when adding new code to it.
But it's been annoying me more and more, so now that I've decided C99
bool is an acceptable thing to require from our toolchain in the first
place, here's a quite thorough trawl through the source doing
'boolification'. Many variables and function parameters are now typed
as bool rather than int; many assignments of 0 or 1 to those variables
are now spelled 'true' or 'false'.
I managed this thorough conversion with the help of a custom clang
plugin that I wrote to trawl the AST and apply heuristics to point out
where things might want changing. So I've even managed to do a decent
job on parts of the code I haven't looked at in years!
To make the plugin's work easier, I pushed platform front ends
generally in the direction of using standard 'bool' in preference to
platform-specific boolean types like Windows BOOL or GTK's gboolean;
I've left the platform booleans in places they _have_ to be for the
platform APIs to work right, but variables only used by my own code
have been converted wherever I found them.
In a few places there are int values that look very like booleans in
_most_ of the places they're used, but have a rarely-used third value,
or a distinction between different nonzero values that most users
don't care about. In these cases, I've _removed_ uses of 'true' and
'false' for the return values, to emphasise that there's something
more subtle going on than a simple boolean answer:
- the 'multisel' field in dialog.h's list box structure, for which
the GTK front end in particular recognises a difference between 1
and 2 but nearly everything else treats as boolean
- the 'urgent' parameter to plug_receive, where 1 vs 2 tells you
something about the specific location of the urgent pointer, but
most clients only care about 0 vs 'something nonzero'
- the return value of wc_match, where -1 indicates a syntax error in
the wildcard.
- the return values from SSH-1 RSA-key loading functions, which use
-1 for 'wrong passphrase' and 0 for all other failures (so any
caller which already knows it's not loading an _encrypted private_
key can treat them as boolean)
- term->esc_query, and the 'query' parameter in toggle_mode in
terminal.c, which _usually_ hold 0 for ESC[123h or 1 for ESC[?123h,
but can also hold -1 for some other intervening character that we
don't support.
In a few places there's an integer that I haven't turned into a bool
even though it really _can_ only take values 0 or 1 (and, as above,
tried to make the call sites consistent in not calling those values
true and false), on the grounds that I thought it would make it more
confusing to imply that the 0 value was in some sense 'negative' or
bad and the 1 positive or good:
- the return value of plug_accepting uses the POSIXish convention of
0=success and nonzero=error; I think if I made it bool then I'd
also want to reverse its sense, and that's a job for a separate
piece of work.
- the 'screen' parameter to lineptr() in terminal.c, where 0 and 1
represent the default and alternate screens. There's no obvious
reason why one of those should be considered 'true' or 'positive'
or 'success' - they're just indices - so I've left it as int.
ssh_scp_recv had particularly confusing semantics for its previous int
return value: its call sites used '<= 0' to check for error, but it
never actually returned a negative number, just 0 or 1. Now the
function and its call sites agree that it's a bool.
In a couple of places I've renamed variables called 'ret', because I
don't like that name any more - it's unclear whether it means the
return value (in preparation) for the _containing_ function or the
return value received from a subroutine call, and occasionally I've
accidentally used the same variable for both and introduced a bug. So
where one of those got in my way, I've renamed it to 'toret' or 'retd'
(the latter short for 'returned') in line with my usual modern
practice, but I haven't done a thorough job of finding all of them.
Finally, one amusing side effect of doing this is that I've had to
separate quite a few chained assignments. It used to be perfectly fine
to write 'a = b = c = TRUE' when a,b,c were int and TRUE was just a
the 'true' defined by stdbool.h, that idiom provokes a warning from
gcc: 'suggest parentheses around assignment used as truth value'!
2018-11-02 19:23:19 +00:00
|
|
|
void dlg_checkbox_set(union control *ctrl, dlgparam *dp, bool checked)
|
2003-03-05 22:07:40 +00:00
|
|
|
{
|
|
|
|
struct winctrl *c = dlg_findbyctrl(dp, ctrl);
|
|
|
|
assert(c && c->ctrl->generic.type == CTRL_CHECKBOX);
|
Convert a lot of 'int' variables to 'bool'.
My normal habit these days, in new code, is to treat int and bool as
_almost_ completely separate types. I'm still willing to use C's
implicit test for zero on an integer (e.g. 'if (!blob.len)' is fine,
no need to spell it out as blob.len != 0), but generally, if a
variable is going to be conceptually a boolean, I like to declare it
bool and assign to it using 'true' or 'false' rather than 0 or 1.
PuTTY is an exception, because it predates the C99 bool, and I've
stuck to its existing coding style even when adding new code to it.
But it's been annoying me more and more, so now that I've decided C99
bool is an acceptable thing to require from our toolchain in the first
place, here's a quite thorough trawl through the source doing
'boolification'. Many variables and function parameters are now typed
as bool rather than int; many assignments of 0 or 1 to those variables
are now spelled 'true' or 'false'.
I managed this thorough conversion with the help of a custom clang
plugin that I wrote to trawl the AST and apply heuristics to point out
where things might want changing. So I've even managed to do a decent
job on parts of the code I haven't looked at in years!
To make the plugin's work easier, I pushed platform front ends
generally in the direction of using standard 'bool' in preference to
platform-specific boolean types like Windows BOOL or GTK's gboolean;
I've left the platform booleans in places they _have_ to be for the
platform APIs to work right, but variables only used by my own code
have been converted wherever I found them.
In a few places there are int values that look very like booleans in
_most_ of the places they're used, but have a rarely-used third value,
or a distinction between different nonzero values that most users
don't care about. In these cases, I've _removed_ uses of 'true' and
'false' for the return values, to emphasise that there's something
more subtle going on than a simple boolean answer:
- the 'multisel' field in dialog.h's list box structure, for which
the GTK front end in particular recognises a difference between 1
and 2 but nearly everything else treats as boolean
- the 'urgent' parameter to plug_receive, where 1 vs 2 tells you
something about the specific location of the urgent pointer, but
most clients only care about 0 vs 'something nonzero'
- the return value of wc_match, where -1 indicates a syntax error in
the wildcard.
- the return values from SSH-1 RSA-key loading functions, which use
-1 for 'wrong passphrase' and 0 for all other failures (so any
caller which already knows it's not loading an _encrypted private_
key can treat them as boolean)
- term->esc_query, and the 'query' parameter in toggle_mode in
terminal.c, which _usually_ hold 0 for ESC[123h or 1 for ESC[?123h,
but can also hold -1 for some other intervening character that we
don't support.
In a few places there's an integer that I haven't turned into a bool
even though it really _can_ only take values 0 or 1 (and, as above,
tried to make the call sites consistent in not calling those values
true and false), on the grounds that I thought it would make it more
confusing to imply that the 0 value was in some sense 'negative' or
bad and the 1 positive or good:
- the return value of plug_accepting uses the POSIXish convention of
0=success and nonzero=error; I think if I made it bool then I'd
also want to reverse its sense, and that's a job for a separate
piece of work.
- the 'screen' parameter to lineptr() in terminal.c, where 0 and 1
represent the default and alternate screens. There's no obvious
reason why one of those should be considered 'true' or 'positive'
or 'success' - they're just indices - so I've left it as int.
ssh_scp_recv had particularly confusing semantics for its previous int
return value: its call sites used '<= 0' to check for error, but it
never actually returned a negative number, just 0 or 1. Now the
function and its call sites agree that it's a bool.
In a couple of places I've renamed variables called 'ret', because I
don't like that name any more - it's unclear whether it means the
return value (in preparation) for the _containing_ function or the
return value received from a subroutine call, and occasionally I've
accidentally used the same variable for both and introduced a bug. So
where one of those got in my way, I've renamed it to 'toret' or 'retd'
(the latter short for 'returned') in line with my usual modern
practice, but I haven't done a thorough job of finding all of them.
Finally, one amusing side effect of doing this is that I've had to
separate quite a few chained assignments. It used to be perfectly fine
to write 'a = b = c = TRUE' when a,b,c were int and TRUE was just a
the 'true' defined by stdbool.h, that idiom provokes a warning from
gcc: 'suggest parentheses around assignment used as truth value'!
2018-11-02 19:23:19 +00:00
|
|
|
CheckDlgButton(dp->hwnd, c->base_id, checked);
|
2003-03-05 22:07:40 +00:00
|
|
|
}
|
|
|
|
|
Convert a lot of 'int' variables to 'bool'.
My normal habit these days, in new code, is to treat int and bool as
_almost_ completely separate types. I'm still willing to use C's
implicit test for zero on an integer (e.g. 'if (!blob.len)' is fine,
no need to spell it out as blob.len != 0), but generally, if a
variable is going to be conceptually a boolean, I like to declare it
bool and assign to it using 'true' or 'false' rather than 0 or 1.
PuTTY is an exception, because it predates the C99 bool, and I've
stuck to its existing coding style even when adding new code to it.
But it's been annoying me more and more, so now that I've decided C99
bool is an acceptable thing to require from our toolchain in the first
place, here's a quite thorough trawl through the source doing
'boolification'. Many variables and function parameters are now typed
as bool rather than int; many assignments of 0 or 1 to those variables
are now spelled 'true' or 'false'.
I managed this thorough conversion with the help of a custom clang
plugin that I wrote to trawl the AST and apply heuristics to point out
where things might want changing. So I've even managed to do a decent
job on parts of the code I haven't looked at in years!
To make the plugin's work easier, I pushed platform front ends
generally in the direction of using standard 'bool' in preference to
platform-specific boolean types like Windows BOOL or GTK's gboolean;
I've left the platform booleans in places they _have_ to be for the
platform APIs to work right, but variables only used by my own code
have been converted wherever I found them.
In a few places there are int values that look very like booleans in
_most_ of the places they're used, but have a rarely-used third value,
or a distinction between different nonzero values that most users
don't care about. In these cases, I've _removed_ uses of 'true' and
'false' for the return values, to emphasise that there's something
more subtle going on than a simple boolean answer:
- the 'multisel' field in dialog.h's list box structure, for which
the GTK front end in particular recognises a difference between 1
and 2 but nearly everything else treats as boolean
- the 'urgent' parameter to plug_receive, where 1 vs 2 tells you
something about the specific location of the urgent pointer, but
most clients only care about 0 vs 'something nonzero'
- the return value of wc_match, where -1 indicates a syntax error in
the wildcard.
- the return values from SSH-1 RSA-key loading functions, which use
-1 for 'wrong passphrase' and 0 for all other failures (so any
caller which already knows it's not loading an _encrypted private_
key can treat them as boolean)
- term->esc_query, and the 'query' parameter in toggle_mode in
terminal.c, which _usually_ hold 0 for ESC[123h or 1 for ESC[?123h,
but can also hold -1 for some other intervening character that we
don't support.
In a few places there's an integer that I haven't turned into a bool
even though it really _can_ only take values 0 or 1 (and, as above,
tried to make the call sites consistent in not calling those values
true and false), on the grounds that I thought it would make it more
confusing to imply that the 0 value was in some sense 'negative' or
bad and the 1 positive or good:
- the return value of plug_accepting uses the POSIXish convention of
0=success and nonzero=error; I think if I made it bool then I'd
also want to reverse its sense, and that's a job for a separate
piece of work.
- the 'screen' parameter to lineptr() in terminal.c, where 0 and 1
represent the default and alternate screens. There's no obvious
reason why one of those should be considered 'true' or 'positive'
or 'success' - they're just indices - so I've left it as int.
ssh_scp_recv had particularly confusing semantics for its previous int
return value: its call sites used '<= 0' to check for error, but it
never actually returned a negative number, just 0 or 1. Now the
function and its call sites agree that it's a bool.
In a couple of places I've renamed variables called 'ret', because I
don't like that name any more - it's unclear whether it means the
return value (in preparation) for the _containing_ function or the
return value received from a subroutine call, and occasionally I've
accidentally used the same variable for both and introduced a bug. So
where one of those got in my way, I've renamed it to 'toret' or 'retd'
(the latter short for 'returned') in line with my usual modern
practice, but I haven't done a thorough job of finding all of them.
Finally, one amusing side effect of doing this is that I've had to
separate quite a few chained assignments. It used to be perfectly fine
to write 'a = b = c = TRUE' when a,b,c were int and TRUE was just a
the 'true' defined by stdbool.h, that idiom provokes a warning from
gcc: 'suggest parentheses around assignment used as truth value'!
2018-11-02 19:23:19 +00:00
|
|
|
bool dlg_checkbox_get(union control *ctrl, dlgparam *dp)
|
2003-03-05 22:07:40 +00:00
|
|
|
{
|
|
|
|
struct winctrl *c = dlg_findbyctrl(dp, ctrl);
|
|
|
|
assert(c && c->ctrl->generic.type == CTRL_CHECKBOX);
|
|
|
|
return 0 != IsDlgButtonChecked(dp->hwnd, c->base_id);
|
|
|
|
}
|
|
|
|
|
2018-09-13 11:58:44 +00:00
|
|
|
void dlg_editbox_set(union control *ctrl, dlgparam *dp, char const *text)
|
2003-03-05 22:07:40 +00:00
|
|
|
{
|
|
|
|
struct winctrl *c = dlg_findbyctrl(dp, ctrl);
|
|
|
|
assert(c && c->ctrl->generic.type == CTRL_EDITBOX);
|
|
|
|
SetDlgItemText(dp->hwnd, c->base_id+1, text);
|
|
|
|
}
|
|
|
|
|
2018-09-13 11:58:44 +00:00
|
|
|
char *dlg_editbox_get(union control *ctrl, dlgparam *dp)
|
2011-10-02 11:01:57 +00:00
|
|
|
{
|
|
|
|
struct winctrl *c = dlg_findbyctrl(dp, ctrl);
|
|
|
|
assert(c && c->ctrl->generic.type == CTRL_EDITBOX);
|
2011-10-02 13:53:58 +00:00
|
|
|
return GetDlgItemText_alloc(dp->hwnd, c->base_id+1);
|
2011-10-02 11:01:57 +00:00
|
|
|
}
|
|
|
|
|
2003-03-05 22:07:40 +00:00
|
|
|
/* The `listbox' functions can also apply to combo boxes. */
|
2018-09-13 11:58:44 +00:00
|
|
|
void dlg_listbox_clear(union control *ctrl, dlgparam *dp)
|
2003-03-05 22:07:40 +00:00
|
|
|
{
|
|
|
|
struct winctrl *c = dlg_findbyctrl(dp, ctrl);
|
|
|
|
int msg;
|
|
|
|
assert(c &&
|
2019-09-08 19:29:00 +00:00
|
|
|
(c->ctrl->generic.type == CTRL_LISTBOX ||
|
|
|
|
(c->ctrl->generic.type == CTRL_EDITBOX &&
|
|
|
|
c->ctrl->editbox.has_list)));
|
2003-03-05 22:07:40 +00:00
|
|
|
msg = (c->ctrl->generic.type==CTRL_LISTBOX && c->ctrl->listbox.height!=0 ?
|
2019-09-08 19:29:00 +00:00
|
|
|
LB_RESETCONTENT : CB_RESETCONTENT);
|
2003-03-05 22:07:40 +00:00
|
|
|
SendDlgItemMessage(dp->hwnd, c->base_id+1, msg, 0, 0);
|
|
|
|
}
|
|
|
|
|
2018-09-13 11:58:44 +00:00
|
|
|
void dlg_listbox_del(union control *ctrl, dlgparam *dp, int index)
|
2003-03-05 22:07:40 +00:00
|
|
|
{
|
|
|
|
struct winctrl *c = dlg_findbyctrl(dp, ctrl);
|
|
|
|
int msg;
|
|
|
|
assert(c &&
|
2019-09-08 19:29:00 +00:00
|
|
|
(c->ctrl->generic.type == CTRL_LISTBOX ||
|
|
|
|
(c->ctrl->generic.type == CTRL_EDITBOX &&
|
|
|
|
c->ctrl->editbox.has_list)));
|
2003-03-05 22:07:40 +00:00
|
|
|
msg = (c->ctrl->generic.type==CTRL_LISTBOX && c->ctrl->listbox.height!=0 ?
|
2019-09-08 19:29:00 +00:00
|
|
|
LB_DELETESTRING : CB_DELETESTRING);
|
2003-03-05 22:07:40 +00:00
|
|
|
SendDlgItemMessage(dp->hwnd, c->base_id+1, msg, index, 0);
|
|
|
|
}
|
|
|
|
|
2018-09-13 11:58:44 +00:00
|
|
|
void dlg_listbox_add(union control *ctrl, dlgparam *dp, char const *text)
|
2003-03-05 22:07:40 +00:00
|
|
|
{
|
|
|
|
struct winctrl *c = dlg_findbyctrl(dp, ctrl);
|
|
|
|
int msg;
|
|
|
|
assert(c &&
|
2019-09-08 19:29:00 +00:00
|
|
|
(c->ctrl->generic.type == CTRL_LISTBOX ||
|
|
|
|
(c->ctrl->generic.type == CTRL_EDITBOX &&
|
|
|
|
c->ctrl->editbox.has_list)));
|
2003-03-05 22:07:40 +00:00
|
|
|
msg = (c->ctrl->generic.type==CTRL_LISTBOX && c->ctrl->listbox.height!=0 ?
|
2019-09-08 19:29:00 +00:00
|
|
|
LB_ADDSTRING : CB_ADDSTRING);
|
2003-03-05 22:07:40 +00:00
|
|
|
SendDlgItemMessage(dp->hwnd, c->base_id+1, msg, 0, (LPARAM)text);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Each listbox entry may have a numeric id associated with it.
|
|
|
|
* Note that some front ends only permit a string to be stored at
|
|
|
|
* each position, which means that _if_ you put two identical
|
|
|
|
* strings in any listbox then you MUST not assign them different
|
|
|
|
* IDs and expect to get meaningful results back.
|
|
|
|
*/
|
2018-09-13 11:58:44 +00:00
|
|
|
void dlg_listbox_addwithid(union control *ctrl, dlgparam *dp,
|
2019-09-08 19:29:00 +00:00
|
|
|
char const *text, int id)
|
2003-03-05 22:07:40 +00:00
|
|
|
{
|
|
|
|
struct winctrl *c = dlg_findbyctrl(dp, ctrl);
|
|
|
|
int msg, msg2, index;
|
|
|
|
assert(c &&
|
2019-09-08 19:29:00 +00:00
|
|
|
(c->ctrl->generic.type == CTRL_LISTBOX ||
|
|
|
|
(c->ctrl->generic.type == CTRL_EDITBOX &&
|
|
|
|
c->ctrl->editbox.has_list)));
|
2003-03-05 22:07:40 +00:00
|
|
|
msg = (c->ctrl->generic.type==CTRL_LISTBOX && c->ctrl->listbox.height!=0 ?
|
2019-09-08 19:29:00 +00:00
|
|
|
LB_ADDSTRING : CB_ADDSTRING);
|
2003-03-05 22:07:40 +00:00
|
|
|
msg2 = (c->ctrl->generic.type==CTRL_LISTBOX && c->ctrl->listbox.height!=0 ?
|
2019-09-08 19:29:00 +00:00
|
|
|
LB_SETITEMDATA : CB_SETITEMDATA);
|
2003-03-05 22:07:40 +00:00
|
|
|
index = SendDlgItemMessage(dp->hwnd, c->base_id+1, msg, 0, (LPARAM)text);
|
|
|
|
SendDlgItemMessage(dp->hwnd, c->base_id+1, msg2, index, (LPARAM)id);
|
|
|
|
}
|
|
|
|
|
2018-09-13 11:58:44 +00:00
|
|
|
int dlg_listbox_getid(union control *ctrl, dlgparam *dp, int index)
|
2003-03-05 22:07:40 +00:00
|
|
|
{
|
|
|
|
struct winctrl *c = dlg_findbyctrl(dp, ctrl);
|
|
|
|
int msg;
|
|
|
|
assert(c && c->ctrl->generic.type == CTRL_LISTBOX);
|
|
|
|
msg = (c->ctrl->listbox.height != 0 ? LB_GETITEMDATA : CB_GETITEMDATA);
|
|
|
|
return
|
2019-09-08 19:29:00 +00:00
|
|
|
SendDlgItemMessage(dp->hwnd, c->base_id+1, msg, index, 0);
|
2003-03-05 22:07:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* dlg_listbox_index returns <0 if no single element is selected. */
|
2018-09-13 11:58:44 +00:00
|
|
|
int dlg_listbox_index(union control *ctrl, dlgparam *dp)
|
2003-03-05 22:07:40 +00:00
|
|
|
{
|
|
|
|
struct winctrl *c = dlg_findbyctrl(dp, ctrl);
|
|
|
|
int msg, ret;
|
2007-02-18 19:50:41 +00:00
|
|
|
assert(c && c->ctrl->generic.type == CTRL_LISTBOX);
|
|
|
|
if (c->ctrl->listbox.multisel) {
|
2019-09-08 19:29:00 +00:00
|
|
|
assert(c->ctrl->listbox.height != 0); /* not combo box */
|
|
|
|
ret = SendDlgItemMessage(dp->hwnd, c->base_id+1, LB_GETSELCOUNT, 0, 0);
|
|
|
|
if (ret == LB_ERR || ret > 1)
|
|
|
|
return -1;
|
2007-02-18 19:50:41 +00:00
|
|
|
}
|
2003-03-05 22:07:40 +00:00
|
|
|
msg = (c->ctrl->listbox.height != 0 ? LB_GETCURSEL : CB_GETCURSEL);
|
|
|
|
ret = SendDlgItemMessage(dp->hwnd, c->base_id+1, msg, 0, 0);
|
|
|
|
if (ret == LB_ERR)
|
2019-09-08 19:29:00 +00:00
|
|
|
return -1;
|
2003-03-05 22:07:40 +00:00
|
|
|
else
|
2019-09-08 19:29:00 +00:00
|
|
|
return ret;
|
2003-03-05 22:07:40 +00:00
|
|
|
}
|
|
|
|
|
Convert a lot of 'int' variables to 'bool'.
My normal habit these days, in new code, is to treat int and bool as
_almost_ completely separate types. I'm still willing to use C's
implicit test for zero on an integer (e.g. 'if (!blob.len)' is fine,
no need to spell it out as blob.len != 0), but generally, if a
variable is going to be conceptually a boolean, I like to declare it
bool and assign to it using 'true' or 'false' rather than 0 or 1.
PuTTY is an exception, because it predates the C99 bool, and I've
stuck to its existing coding style even when adding new code to it.
But it's been annoying me more and more, so now that I've decided C99
bool is an acceptable thing to require from our toolchain in the first
place, here's a quite thorough trawl through the source doing
'boolification'. Many variables and function parameters are now typed
as bool rather than int; many assignments of 0 or 1 to those variables
are now spelled 'true' or 'false'.
I managed this thorough conversion with the help of a custom clang
plugin that I wrote to trawl the AST and apply heuristics to point out
where things might want changing. So I've even managed to do a decent
job on parts of the code I haven't looked at in years!
To make the plugin's work easier, I pushed platform front ends
generally in the direction of using standard 'bool' in preference to
platform-specific boolean types like Windows BOOL or GTK's gboolean;
I've left the platform booleans in places they _have_ to be for the
platform APIs to work right, but variables only used by my own code
have been converted wherever I found them.
In a few places there are int values that look very like booleans in
_most_ of the places they're used, but have a rarely-used third value,
or a distinction between different nonzero values that most users
don't care about. In these cases, I've _removed_ uses of 'true' and
'false' for the return values, to emphasise that there's something
more subtle going on than a simple boolean answer:
- the 'multisel' field in dialog.h's list box structure, for which
the GTK front end in particular recognises a difference between 1
and 2 but nearly everything else treats as boolean
- the 'urgent' parameter to plug_receive, where 1 vs 2 tells you
something about the specific location of the urgent pointer, but
most clients only care about 0 vs 'something nonzero'
- the return value of wc_match, where -1 indicates a syntax error in
the wildcard.
- the return values from SSH-1 RSA-key loading functions, which use
-1 for 'wrong passphrase' and 0 for all other failures (so any
caller which already knows it's not loading an _encrypted private_
key can treat them as boolean)
- term->esc_query, and the 'query' parameter in toggle_mode in
terminal.c, which _usually_ hold 0 for ESC[123h or 1 for ESC[?123h,
but can also hold -1 for some other intervening character that we
don't support.
In a few places there's an integer that I haven't turned into a bool
even though it really _can_ only take values 0 or 1 (and, as above,
tried to make the call sites consistent in not calling those values
true and false), on the grounds that I thought it would make it more
confusing to imply that the 0 value was in some sense 'negative' or
bad and the 1 positive or good:
- the return value of plug_accepting uses the POSIXish convention of
0=success and nonzero=error; I think if I made it bool then I'd
also want to reverse its sense, and that's a job for a separate
piece of work.
- the 'screen' parameter to lineptr() in terminal.c, where 0 and 1
represent the default and alternate screens. There's no obvious
reason why one of those should be considered 'true' or 'positive'
or 'success' - they're just indices - so I've left it as int.
ssh_scp_recv had particularly confusing semantics for its previous int
return value: its call sites used '<= 0' to check for error, but it
never actually returned a negative number, just 0 or 1. Now the
function and its call sites agree that it's a bool.
In a couple of places I've renamed variables called 'ret', because I
don't like that name any more - it's unclear whether it means the
return value (in preparation) for the _containing_ function or the
return value received from a subroutine call, and occasionally I've
accidentally used the same variable for both and introduced a bug. So
where one of those got in my way, I've renamed it to 'toret' or 'retd'
(the latter short for 'returned') in line with my usual modern
practice, but I haven't done a thorough job of finding all of them.
Finally, one amusing side effect of doing this is that I've had to
separate quite a few chained assignments. It used to be perfectly fine
to write 'a = b = c = TRUE' when a,b,c were int and TRUE was just a
the 'true' defined by stdbool.h, that idiom provokes a warning from
gcc: 'suggest parentheses around assignment used as truth value'!
2018-11-02 19:23:19 +00:00
|
|
|
bool dlg_listbox_issel(union control *ctrl, dlgparam *dp, int index)
|
2003-03-05 22:07:40 +00:00
|
|
|
{
|
|
|
|
struct winctrl *c = dlg_findbyctrl(dp, ctrl);
|
|
|
|
assert(c && c->ctrl->generic.type == CTRL_LISTBOX &&
|
2019-09-08 19:29:00 +00:00
|
|
|
c->ctrl->listbox.multisel &&
|
|
|
|
c->ctrl->listbox.height != 0);
|
2003-03-05 22:07:40 +00:00
|
|
|
return
|
2019-09-08 19:29:00 +00:00
|
|
|
SendDlgItemMessage(dp->hwnd, c->base_id+1, LB_GETSEL, index, 0);
|
2003-03-05 22:07:40 +00:00
|
|
|
}
|
|
|
|
|
2018-09-13 11:58:44 +00:00
|
|
|
void dlg_listbox_select(union control *ctrl, dlgparam *dp, int index)
|
2003-03-05 22:07:40 +00:00
|
|
|
{
|
|
|
|
struct winctrl *c = dlg_findbyctrl(dp, ctrl);
|
|
|
|
int msg;
|
|
|
|
assert(c && c->ctrl->generic.type == CTRL_LISTBOX &&
|
2019-09-08 19:29:00 +00:00
|
|
|
!c->ctrl->listbox.multisel);
|
2003-03-05 22:07:40 +00:00
|
|
|
msg = (c->ctrl->listbox.height != 0 ? LB_SETCURSEL : CB_SETCURSEL);
|
|
|
|
SendDlgItemMessage(dp->hwnd, c->base_id+1, msg, index, 0);
|
|
|
|
}
|
|
|
|
|
2018-09-13 11:58:44 +00:00
|
|
|
void dlg_text_set(union control *ctrl, dlgparam *dp, char const *text)
|
2003-03-05 22:07:40 +00:00
|
|
|
{
|
|
|
|
struct winctrl *c = dlg_findbyctrl(dp, ctrl);
|
|
|
|
assert(c && c->ctrl->generic.type == CTRL_TEXT);
|
|
|
|
SetDlgItemText(dp->hwnd, c->base_id, text);
|
|
|
|
}
|
|
|
|
|
2018-09-13 11:58:44 +00:00
|
|
|
void dlg_label_change(union control *ctrl, dlgparam *dp, char const *text)
|
2006-08-28 10:35:12 +00:00
|
|
|
{
|
|
|
|
struct winctrl *c = dlg_findbyctrl(dp, ctrl);
|
|
|
|
char *escaped = NULL;
|
|
|
|
int id = -1;
|
|
|
|
|
|
|
|
assert(c);
|
|
|
|
switch (c->ctrl->generic.type) {
|
|
|
|
case CTRL_EDITBOX:
|
2019-09-08 19:29:00 +00:00
|
|
|
escaped = shortcut_escape(text, c->ctrl->editbox.shortcut);
|
|
|
|
id = c->base_id;
|
|
|
|
break;
|
2006-08-28 10:35:12 +00:00
|
|
|
case CTRL_RADIO:
|
2019-09-08 19:29:00 +00:00
|
|
|
escaped = shortcut_escape(text, c->ctrl->radio.shortcut);
|
|
|
|
id = c->base_id;
|
|
|
|
break;
|
2006-08-28 10:35:12 +00:00
|
|
|
case CTRL_CHECKBOX:
|
2019-09-08 19:29:00 +00:00
|
|
|
escaped = shortcut_escape(text, ctrl->checkbox.shortcut);
|
|
|
|
id = c->base_id;
|
|
|
|
break;
|
2006-08-28 10:35:12 +00:00
|
|
|
case CTRL_BUTTON:
|
2019-09-08 19:29:00 +00:00
|
|
|
escaped = shortcut_escape(text, ctrl->button.shortcut);
|
|
|
|
id = c->base_id;
|
|
|
|
break;
|
2006-08-28 10:35:12 +00:00
|
|
|
case CTRL_LISTBOX:
|
2019-09-08 19:29:00 +00:00
|
|
|
escaped = shortcut_escape(text, ctrl->listbox.shortcut);
|
|
|
|
id = c->base_id;
|
|
|
|
break;
|
2006-08-28 10:35:12 +00:00
|
|
|
case CTRL_FILESELECT:
|
2019-09-08 19:29:00 +00:00
|
|
|
escaped = shortcut_escape(text, ctrl->fileselect.shortcut);
|
|
|
|
id = c->base_id;
|
|
|
|
break;
|
2006-08-28 10:35:12 +00:00
|
|
|
case CTRL_FONTSELECT:
|
2019-09-08 19:29:00 +00:00
|
|
|
escaped = shortcut_escape(text, ctrl->fontselect.shortcut);
|
|
|
|
id = c->base_id;
|
|
|
|
break;
|
2006-08-28 10:35:12 +00:00
|
|
|
default:
|
2019-09-09 18:07:55 +00:00
|
|
|
unreachable("bad control type in label_change");
|
2006-08-28 10:35:12 +00:00
|
|
|
}
|
|
|
|
if (escaped) {
|
2019-09-08 19:29:00 +00:00
|
|
|
SetDlgItemText(dp->hwnd, id, escaped);
|
|
|
|
sfree(escaped);
|
2006-08-28 10:35:12 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-09-13 11:58:44 +00:00
|
|
|
void dlg_filesel_set(union control *ctrl, dlgparam *dp, Filename *fn)
|
2003-03-05 22:07:40 +00:00
|
|
|
{
|
|
|
|
struct winctrl *c = dlg_findbyctrl(dp, ctrl);
|
|
|
|
assert(c && c->ctrl->generic.type == CTRL_FILESELECT);
|
2011-10-02 11:01:57 +00:00
|
|
|
SetDlgItemText(dp->hwnd, c->base_id+1, fn->path);
|
2003-03-05 22:07:40 +00:00
|
|
|
}
|
|
|
|
|
2018-09-13 11:58:44 +00:00
|
|
|
Filename *dlg_filesel_get(union control *ctrl, dlgparam *dp)
|
2003-03-05 22:07:40 +00:00
|
|
|
{
|
|
|
|
struct winctrl *c = dlg_findbyctrl(dp, ctrl);
|
2011-10-02 11:01:57 +00:00
|
|
|
char *tmp;
|
|
|
|
Filename *ret;
|
2003-03-05 22:07:40 +00:00
|
|
|
assert(c && c->ctrl->generic.type == CTRL_FILESELECT);
|
2011-10-02 13:53:58 +00:00
|
|
|
tmp = GetDlgItemText_alloc(dp->hwnd, c->base_id+1);
|
2011-10-02 11:01:57 +00:00
|
|
|
ret = filename_from_str(tmp);
|
|
|
|
sfree(tmp);
|
|
|
|
return ret;
|
2003-03-05 22:07:40 +00:00
|
|
|
}
|
|
|
|
|
2018-09-13 11:58:44 +00:00
|
|
|
void dlg_fontsel_set(union control *ctrl, dlgparam *dp, FontSpec *fs)
|
2003-03-05 22:07:40 +00:00
|
|
|
{
|
|
|
|
char *buf, *boldstr;
|
|
|
|
struct winctrl *c = dlg_findbyctrl(dp, ctrl);
|
|
|
|
assert(c && c->ctrl->generic.type == CTRL_FONTSELECT);
|
|
|
|
|
2011-10-01 17:38:59 +00:00
|
|
|
fontspec_free((FontSpec *)c->data);
|
|
|
|
c->data = fontspec_copy(fs);
|
2003-03-05 22:07:40 +00:00
|
|
|
|
2011-10-01 17:38:59 +00:00
|
|
|
boldstr = (fs->isbold ? "bold, " : "");
|
|
|
|
if (fs->height == 0)
|
2019-09-08 19:29:00 +00:00
|
|
|
buf = dupprintf("Font: %s, %sdefault height", fs->name, boldstr);
|
2003-03-05 22:07:40 +00:00
|
|
|
else
|
2019-09-08 19:29:00 +00:00
|
|
|
buf = dupprintf("Font: %s, %s%d-%s", fs->name, boldstr,
|
|
|
|
(fs->height < 0 ? -fs->height : fs->height),
|
|
|
|
(fs->height < 0 ? "pixel" : "point"));
|
2003-03-05 22:07:40 +00:00
|
|
|
SetDlgItemText(dp->hwnd, c->base_id+1, buf);
|
|
|
|
sfree(buf);
|
2010-12-29 14:11:25 +00:00
|
|
|
|
|
|
|
dlg_auto_set_fixed_pitch_flag(dp);
|
2003-03-05 22:07:40 +00:00
|
|
|
}
|
|
|
|
|
2018-09-13 11:58:44 +00:00
|
|
|
FontSpec *dlg_fontsel_get(union control *ctrl, dlgparam *dp)
|
2003-03-05 22:07:40 +00:00
|
|
|
{
|
|
|
|
struct winctrl *c = dlg_findbyctrl(dp, ctrl);
|
|
|
|
assert(c && c->ctrl->generic.type == CTRL_FONTSELECT);
|
2011-10-01 17:38:59 +00:00
|
|
|
return fontspec_copy((FontSpec *)c->data);
|
2003-03-05 22:07:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 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.
|
|
|
|
*/
|
2018-09-13 11:58:44 +00:00
|
|
|
void dlg_update_start(union control *ctrl, dlgparam *dp)
|
2003-03-05 22:07:40 +00:00
|
|
|
{
|
|
|
|
struct winctrl *c = dlg_findbyctrl(dp, ctrl);
|
|
|
|
if (c && c->ctrl->generic.type == CTRL_LISTBOX) {
|
2019-09-08 19:29:00 +00:00
|
|
|
SendDlgItemMessage(dp->hwnd, c->base_id+1, WM_SETREDRAW, false, 0);
|
2003-03-05 22:07:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-09-13 11:58:44 +00:00
|
|
|
void dlg_update_done(union control *ctrl, dlgparam *dp)
|
2003-03-05 22:07:40 +00:00
|
|
|
{
|
|
|
|
struct winctrl *c = dlg_findbyctrl(dp, ctrl);
|
|
|
|
if (c && c->ctrl->generic.type == CTRL_LISTBOX) {
|
2019-09-08 19:29:00 +00:00
|
|
|
HWND hw = GetDlgItem(dp->hwnd, c->base_id+1);
|
|
|
|
SendMessage(hw, WM_SETREDRAW, true, 0);
|
|
|
|
InvalidateRect(hw, NULL, true);
|
2003-03-05 22:07:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-09-13 11:58:44 +00:00
|
|
|
void dlg_set_focus(union control *ctrl, dlgparam *dp)
|
2003-03-05 22:07:40 +00:00
|
|
|
{
|
|
|
|
struct winctrl *c = dlg_findbyctrl(dp, ctrl);
|
|
|
|
int id;
|
|
|
|
HWND ctl;
|
2013-07-22 07:11:48 +00:00
|
|
|
if (!c)
|
|
|
|
return;
|
2003-03-05 22:07:40 +00:00
|
|
|
switch (ctrl->generic.type) {
|
|
|
|
case CTRL_EDITBOX: id = c->base_id + 1; break;
|
|
|
|
case CTRL_RADIO:
|
2019-09-08 19:29:00 +00:00
|
|
|
for (id = c->base_id + ctrl->radio.nbuttons; id > 1; id--)
|
|
|
|
if (IsDlgButtonChecked(dp->hwnd, id))
|
|
|
|
break;
|
|
|
|
/*
|
|
|
|
* In the theoretically-unlikely case that no button was
|
|
|
|
* selected, id should come out of this as 1, which is a
|
|
|
|
* reasonable enough choice.
|
|
|
|
*/
|
|
|
|
break;
|
2003-03-05 22:07:40 +00:00
|
|
|
case CTRL_CHECKBOX: id = c->base_id; break;
|
|
|
|
case CTRL_BUTTON: id = c->base_id; break;
|
|
|
|
case CTRL_LISTBOX: id = c->base_id + 1; break;
|
|
|
|
case CTRL_FILESELECT: id = c->base_id + 1; break;
|
|
|
|
case CTRL_FONTSELECT: id = c->base_id + 2; break;
|
|
|
|
default: id = c->base_id; break;
|
|
|
|
}
|
|
|
|
ctl = GetDlgItem(dp->hwnd, id);
|
|
|
|
SetFocus(ctl);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* During event processing, you might well want to give an error
|
|
|
|
* indication to the user. dlg_beep() is a quick and easy generic
|
|
|
|
* error; dlg_error() puts up a message-box or equivalent.
|
|
|
|
*/
|
2018-09-13 11:58:44 +00:00
|
|
|
void dlg_beep(dlgparam *dp)
|
2003-03-05 22:07:40 +00:00
|
|
|
{
|
|
|
|
MessageBeep(0);
|
|
|
|
}
|
|
|
|
|
2018-09-13 11:58:44 +00:00
|
|
|
void dlg_error_msg(dlgparam *dp, const char *msg)
|
2003-03-05 22:07:40 +00:00
|
|
|
{
|
|
|
|
MessageBox(dp->hwnd, msg,
|
2019-09-08 19:29:00 +00:00
|
|
|
dp->errtitle ? dp->errtitle : NULL,
|
|
|
|
MB_OK | MB_ICONERROR);
|
2003-03-05 22:07:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* This function signals to the front end that the dialog's
|
|
|
|
* processing is completed, and passes an integer value (typically
|
|
|
|
* a success status).
|
|
|
|
*/
|
2018-09-13 11:58:44 +00:00
|
|
|
void dlg_end(dlgparam *dp, int value)
|
2003-03-05 22:07:40 +00:00
|
|
|
{
|
2018-10-29 19:50:29 +00:00
|
|
|
dp->ended = true;
|
2003-03-05 22:07:40 +00:00
|
|
|
dp->endresult = value;
|
|
|
|
}
|
|
|
|
|
2018-09-13 11:58:44 +00:00
|
|
|
void dlg_refresh(union control *ctrl, dlgparam *dp)
|
2003-03-05 22:07:40 +00:00
|
|
|
{
|
|
|
|
int i, j;
|
|
|
|
struct winctrl *c;
|
|
|
|
|
|
|
|
if (!ctrl) {
|
2019-09-08 19:29:00 +00:00
|
|
|
/*
|
|
|
|
* Send EVENT_REFRESH to absolutely everything.
|
|
|
|
*/
|
|
|
|
for (j = 0; j < dp->nctrltrees; j++) {
|
|
|
|
for (i = 0;
|
|
|
|
(c = winctrl_findbyindex(dp->controltrees[j], i)) != NULL;
|
|
|
|
i++) {
|
|
|
|
if (c->ctrl && c->ctrl->generic.handler != NULL)
|
|
|
|
c->ctrl->generic.handler(c->ctrl, dp,
|
|
|
|
dp->data, EVENT_REFRESH);
|
|
|
|
}
|
|
|
|
}
|
2003-03-05 22:07:40 +00:00
|
|
|
} else {
|
2019-09-08 19:29:00 +00:00
|
|
|
/*
|
|
|
|
* Send EVENT_REFRESH to a specific control.
|
|
|
|
*/
|
|
|
|
if (ctrl->generic.handler != NULL)
|
|
|
|
ctrl->generic.handler(ctrl, dp, dp->data, EVENT_REFRESH);
|
2003-03-05 22:07:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-09-13 11:58:44 +00:00
|
|
|
void dlg_coloursel_start(union control *ctrl, dlgparam *dp, int r, int g, int b)
|
2003-03-05 22:07:40 +00:00
|
|
|
{
|
2018-10-29 19:50:29 +00:00
|
|
|
dp->coloursel_wanted = true;
|
2003-03-05 22:07:40 +00:00
|
|
|
dp->coloursel_result.r = r;
|
|
|
|
dp->coloursel_result.g = g;
|
|
|
|
dp->coloursel_result.b = b;
|
|
|
|
}
|
|
|
|
|
Convert a lot of 'int' variables to 'bool'.
My normal habit these days, in new code, is to treat int and bool as
_almost_ completely separate types. I'm still willing to use C's
implicit test for zero on an integer (e.g. 'if (!blob.len)' is fine,
no need to spell it out as blob.len != 0), but generally, if a
variable is going to be conceptually a boolean, I like to declare it
bool and assign to it using 'true' or 'false' rather than 0 or 1.
PuTTY is an exception, because it predates the C99 bool, and I've
stuck to its existing coding style even when adding new code to it.
But it's been annoying me more and more, so now that I've decided C99
bool is an acceptable thing to require from our toolchain in the first
place, here's a quite thorough trawl through the source doing
'boolification'. Many variables and function parameters are now typed
as bool rather than int; many assignments of 0 or 1 to those variables
are now spelled 'true' or 'false'.
I managed this thorough conversion with the help of a custom clang
plugin that I wrote to trawl the AST and apply heuristics to point out
where things might want changing. So I've even managed to do a decent
job on parts of the code I haven't looked at in years!
To make the plugin's work easier, I pushed platform front ends
generally in the direction of using standard 'bool' in preference to
platform-specific boolean types like Windows BOOL or GTK's gboolean;
I've left the platform booleans in places they _have_ to be for the
platform APIs to work right, but variables only used by my own code
have been converted wherever I found them.
In a few places there are int values that look very like booleans in
_most_ of the places they're used, but have a rarely-used third value,
or a distinction between different nonzero values that most users
don't care about. In these cases, I've _removed_ uses of 'true' and
'false' for the return values, to emphasise that there's something
more subtle going on than a simple boolean answer:
- the 'multisel' field in dialog.h's list box structure, for which
the GTK front end in particular recognises a difference between 1
and 2 but nearly everything else treats as boolean
- the 'urgent' parameter to plug_receive, where 1 vs 2 tells you
something about the specific location of the urgent pointer, but
most clients only care about 0 vs 'something nonzero'
- the return value of wc_match, where -1 indicates a syntax error in
the wildcard.
- the return values from SSH-1 RSA-key loading functions, which use
-1 for 'wrong passphrase' and 0 for all other failures (so any
caller which already knows it's not loading an _encrypted private_
key can treat them as boolean)
- term->esc_query, and the 'query' parameter in toggle_mode in
terminal.c, which _usually_ hold 0 for ESC[123h or 1 for ESC[?123h,
but can also hold -1 for some other intervening character that we
don't support.
In a few places there's an integer that I haven't turned into a bool
even though it really _can_ only take values 0 or 1 (and, as above,
tried to make the call sites consistent in not calling those values
true and false), on the grounds that I thought it would make it more
confusing to imply that the 0 value was in some sense 'negative' or
bad and the 1 positive or good:
- the return value of plug_accepting uses the POSIXish convention of
0=success and nonzero=error; I think if I made it bool then I'd
also want to reverse its sense, and that's a job for a separate
piece of work.
- the 'screen' parameter to lineptr() in terminal.c, where 0 and 1
represent the default and alternate screens. There's no obvious
reason why one of those should be considered 'true' or 'positive'
or 'success' - they're just indices - so I've left it as int.
ssh_scp_recv had particularly confusing semantics for its previous int
return value: its call sites used '<= 0' to check for error, but it
never actually returned a negative number, just 0 or 1. Now the
function and its call sites agree that it's a bool.
In a couple of places I've renamed variables called 'ret', because I
don't like that name any more - it's unclear whether it means the
return value (in preparation) for the _containing_ function or the
return value received from a subroutine call, and occasionally I've
accidentally used the same variable for both and introduced a bug. So
where one of those got in my way, I've renamed it to 'toret' or 'retd'
(the latter short for 'returned') in line with my usual modern
practice, but I haven't done a thorough job of finding all of them.
Finally, one amusing side effect of doing this is that I've had to
separate quite a few chained assignments. It used to be perfectly fine
to write 'a = b = c = TRUE' when a,b,c were int and TRUE was just a
the 'true' defined by stdbool.h, that idiom provokes a warning from
gcc: 'suggest parentheses around assignment used as truth value'!
2018-11-02 19:23:19 +00:00
|
|
|
bool dlg_coloursel_results(union control *ctrl, dlgparam *dp,
|
|
|
|
int *r, int *g, int *b)
|
2003-03-05 22:07:40 +00:00
|
|
|
{
|
|
|
|
if (dp->coloursel_result.ok) {
|
2019-09-08 19:29:00 +00:00
|
|
|
*r = dp->coloursel_result.r;
|
|
|
|
*g = dp->coloursel_result.g;
|
|
|
|
*b = dp->coloursel_result.b;
|
|
|
|
return true;
|
2003-03-05 22:07:40 +00:00
|
|
|
} else
|
2019-09-08 19:29:00 +00:00
|
|
|
return false;
|
2001-08-08 20:44:35 +00:00
|
|
|
}
|
2003-03-08 11:46:42 +00:00
|
|
|
|
2018-09-13 11:58:44 +00:00
|
|
|
void dlg_auto_set_fixed_pitch_flag(dlgparam *dp)
|
2010-12-29 14:11:25 +00:00
|
|
|
{
|
Post-release destabilisation! Completely remove the struct type
'Config' in putty.h, which stores all PuTTY's settings and includes an
arbitrary length limit on every single one of those settings which is
stored in string form. In place of it is 'Conf', an opaque data type
everywhere outside the new file conf.c, which stores a list of (key,
value) pairs in which every key contains an integer identifying a
configuration setting, and for some of those integers the key also
contains extra parts (so that, for instance, CONF_environmt is a
string-to-string mapping). Everywhere that a Config was previously
used, a Conf is now; everywhere there was a Config structure copy,
conf_copy() is called; every lookup, adjustment, load and save
operation on a Config has been rewritten; and there's a mechanism for
serialising a Conf into a binary blob and back for use with Duplicate
Session.
User-visible effects of this change _should_ be minimal, though I
don't doubt I've introduced one or two bugs here and there which will
eventually be found. The _intended_ visible effects of this change are
that all arbitrary limits on configuration strings and lists (e.g.
limit on number of port forwardings) should now disappear; that list
boxes in the configuration will now be displayed in a sorted order
rather than the arbitrary order in which they were added to the list
(since the underlying data structure is now a sorted tree234 rather
than an ad-hoc comma-separated string); and one more specific change,
which is that local and dynamic port forwardings on the same port
number are now mutually exclusive in the configuration (putting 'D' in
the key rather than the value was a mistake in the first place).
One other reorganisation as a result of this is that I've moved all
the dialog.c standard handlers (dlg_stdeditbox_handler and friends)
out into config.c, because I can't really justify calling them generic
any more. When they took a pointer to an arbitrary structure type and
the offset of a field within that structure, they were independent of
whether that structure was a Config or something completely different,
but now they really do expect to talk to a Conf, which can _only_ be
used for PuTTY configuration, so I've renamed them all things like
conf_editbox_handler and moved them out of the nominally independent
dialog-box management module into the PuTTY-specific config.c.
[originally from svn r9214]
2011-07-14 18:52:21 +00:00
|
|
|
Conf *conf = (Conf *)dp->data;
|
2011-10-01 17:38:59 +00:00
|
|
|
FontSpec *fs;
|
Post-release destabilisation! Completely remove the struct type
'Config' in putty.h, which stores all PuTTY's settings and includes an
arbitrary length limit on every single one of those settings which is
stored in string form. In place of it is 'Conf', an opaque data type
everywhere outside the new file conf.c, which stores a list of (key,
value) pairs in which every key contains an integer identifying a
configuration setting, and for some of those integers the key also
contains extra parts (so that, for instance, CONF_environmt is a
string-to-string mapping). Everywhere that a Config was previously
used, a Conf is now; everywhere there was a Config structure copy,
conf_copy() is called; every lookup, adjustment, load and save
operation on a Config has been rewritten; and there's a mechanism for
serialising a Conf into a binary blob and back for use with Duplicate
Session.
User-visible effects of this change _should_ be minimal, though I
don't doubt I've introduced one or two bugs here and there which will
eventually be found. The _intended_ visible effects of this change are
that all arbitrary limits on configuration strings and lists (e.g.
limit on number of port forwardings) should now disappear; that list
boxes in the configuration will now be displayed in a sorted order
rather than the arbitrary order in which they were added to the list
(since the underlying data structure is now a sorted tree234 rather
than an ad-hoc comma-separated string); and one more specific change,
which is that local and dynamic port forwardings on the same port
number are now mutually exclusive in the configuration (putting 'D' in
the key rather than the value was a mistake in the first place).
One other reorganisation as a result of this is that I've moved all
the dialog.c standard handlers (dlg_stdeditbox_handler and friends)
out into config.c, because I can't really justify calling them generic
any more. When they took a pointer to an arbitrary structure type and
the offset of a field within that structure, they were independent of
whether that structure was a Config or something completely different,
but now they really do expect to talk to a Conf, which can _only_ be
used for PuTTY configuration, so I've renamed them all things like
conf_editbox_handler and moved them out of the nominally independent
dialog-box management module into the PuTTY-specific config.c.
[originally from svn r9214]
2011-07-14 18:52:21 +00:00
|
|
|
int quality;
|
|
|
|
HFONT hfont;
|
2010-12-29 14:11:25 +00:00
|
|
|
HDC hdc;
|
|
|
|
TEXTMETRIC tm;
|
Convert a lot of 'int' variables to 'bool'.
My normal habit these days, in new code, is to treat int and bool as
_almost_ completely separate types. I'm still willing to use C's
implicit test for zero on an integer (e.g. 'if (!blob.len)' is fine,
no need to spell it out as blob.len != 0), but generally, if a
variable is going to be conceptually a boolean, I like to declare it
bool and assign to it using 'true' or 'false' rather than 0 or 1.
PuTTY is an exception, because it predates the C99 bool, and I've
stuck to its existing coding style even when adding new code to it.
But it's been annoying me more and more, so now that I've decided C99
bool is an acceptable thing to require from our toolchain in the first
place, here's a quite thorough trawl through the source doing
'boolification'. Many variables and function parameters are now typed
as bool rather than int; many assignments of 0 or 1 to those variables
are now spelled 'true' or 'false'.
I managed this thorough conversion with the help of a custom clang
plugin that I wrote to trawl the AST and apply heuristics to point out
where things might want changing. So I've even managed to do a decent
job on parts of the code I haven't looked at in years!
To make the plugin's work easier, I pushed platform front ends
generally in the direction of using standard 'bool' in preference to
platform-specific boolean types like Windows BOOL or GTK's gboolean;
I've left the platform booleans in places they _have_ to be for the
platform APIs to work right, but variables only used by my own code
have been converted wherever I found them.
In a few places there are int values that look very like booleans in
_most_ of the places they're used, but have a rarely-used third value,
or a distinction between different nonzero values that most users
don't care about. In these cases, I've _removed_ uses of 'true' and
'false' for the return values, to emphasise that there's something
more subtle going on than a simple boolean answer:
- the 'multisel' field in dialog.h's list box structure, for which
the GTK front end in particular recognises a difference between 1
and 2 but nearly everything else treats as boolean
- the 'urgent' parameter to plug_receive, where 1 vs 2 tells you
something about the specific location of the urgent pointer, but
most clients only care about 0 vs 'something nonzero'
- the return value of wc_match, where -1 indicates a syntax error in
the wildcard.
- the return values from SSH-1 RSA-key loading functions, which use
-1 for 'wrong passphrase' and 0 for all other failures (so any
caller which already knows it's not loading an _encrypted private_
key can treat them as boolean)
- term->esc_query, and the 'query' parameter in toggle_mode in
terminal.c, which _usually_ hold 0 for ESC[123h or 1 for ESC[?123h,
but can also hold -1 for some other intervening character that we
don't support.
In a few places there's an integer that I haven't turned into a bool
even though it really _can_ only take values 0 or 1 (and, as above,
tried to make the call sites consistent in not calling those values
true and false), on the grounds that I thought it would make it more
confusing to imply that the 0 value was in some sense 'negative' or
bad and the 1 positive or good:
- the return value of plug_accepting uses the POSIXish convention of
0=success and nonzero=error; I think if I made it bool then I'd
also want to reverse its sense, and that's a job for a separate
piece of work.
- the 'screen' parameter to lineptr() in terminal.c, where 0 and 1
represent the default and alternate screens. There's no obvious
reason why one of those should be considered 'true' or 'positive'
or 'success' - they're just indices - so I've left it as int.
ssh_scp_recv had particularly confusing semantics for its previous int
return value: its call sites used '<= 0' to check for error, but it
never actually returned a negative number, just 0 or 1. Now the
function and its call sites agree that it's a bool.
In a couple of places I've renamed variables called 'ret', because I
don't like that name any more - it's unclear whether it means the
return value (in preparation) for the _containing_ function or the
return value received from a subroutine call, and occasionally I've
accidentally used the same variable for both and introduced a bug. So
where one of those got in my way, I've renamed it to 'toret' or 'retd'
(the latter short for 'returned') in line with my usual modern
practice, but I haven't done a thorough job of finding all of them.
Finally, one amusing side effect of doing this is that I've had to
separate quite a few chained assignments. It used to be perfectly fine
to write 'a = b = c = TRUE' when a,b,c were int and TRUE was just a
the 'true' defined by stdbool.h, that idiom provokes a warning from
gcc: 'suggest parentheses around assignment used as truth value'!
2018-11-02 19:23:19 +00:00
|
|
|
bool is_var;
|
2010-12-29 14:11:25 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Attempt to load the current font, and see if it's
|
|
|
|
* variable-pitch. If so, start off the fixed-pitch flag for the
|
|
|
|
* dialog box as false.
|
|
|
|
*
|
|
|
|
* We assume here that any client of the dlg_* mechanism which is
|
Post-release destabilisation! Completely remove the struct type
'Config' in putty.h, which stores all PuTTY's settings and includes an
arbitrary length limit on every single one of those settings which is
stored in string form. In place of it is 'Conf', an opaque data type
everywhere outside the new file conf.c, which stores a list of (key,
value) pairs in which every key contains an integer identifying a
configuration setting, and for some of those integers the key also
contains extra parts (so that, for instance, CONF_environmt is a
string-to-string mapping). Everywhere that a Config was previously
used, a Conf is now; everywhere there was a Config structure copy,
conf_copy() is called; every lookup, adjustment, load and save
operation on a Config has been rewritten; and there's a mechanism for
serialising a Conf into a binary blob and back for use with Duplicate
Session.
User-visible effects of this change _should_ be minimal, though I
don't doubt I've introduced one or two bugs here and there which will
eventually be found. The _intended_ visible effects of this change are
that all arbitrary limits on configuration strings and lists (e.g.
limit on number of port forwardings) should now disappear; that list
boxes in the configuration will now be displayed in a sorted order
rather than the arbitrary order in which they were added to the list
(since the underlying data structure is now a sorted tree234 rather
than an ad-hoc comma-separated string); and one more specific change,
which is that local and dynamic port forwardings on the same port
number are now mutually exclusive in the configuration (putting 'D' in
the key rather than the value was a mistake in the first place).
One other reorganisation as a result of this is that I've moved all
the dialog.c standard handlers (dlg_stdeditbox_handler and friends)
out into config.c, because I can't really justify calling them generic
any more. When they took a pointer to an arbitrary structure type and
the offset of a field within that structure, they were independent of
whether that structure was a Config or something completely different,
but now they really do expect to talk to a Conf, which can _only_ be
used for PuTTY configuration, so I've renamed them all things like
conf_editbox_handler and moved them out of the nominally independent
dialog-box management module into the PuTTY-specific config.c.
[originally from svn r9214]
2011-07-14 18:52:21 +00:00
|
|
|
* using font selectors at all is also using a normal 'Conf *'
|
2010-12-29 14:11:25 +00:00
|
|
|
* as dp->data.
|
|
|
|
*/
|
|
|
|
|
Post-release destabilisation! Completely remove the struct type
'Config' in putty.h, which stores all PuTTY's settings and includes an
arbitrary length limit on every single one of those settings which is
stored in string form. In place of it is 'Conf', an opaque data type
everywhere outside the new file conf.c, which stores a list of (key,
value) pairs in which every key contains an integer identifying a
configuration setting, and for some of those integers the key also
contains extra parts (so that, for instance, CONF_environmt is a
string-to-string mapping). Everywhere that a Config was previously
used, a Conf is now; everywhere there was a Config structure copy,
conf_copy() is called; every lookup, adjustment, load and save
operation on a Config has been rewritten; and there's a mechanism for
serialising a Conf into a binary blob and back for use with Duplicate
Session.
User-visible effects of this change _should_ be minimal, though I
don't doubt I've introduced one or two bugs here and there which will
eventually be found. The _intended_ visible effects of this change are
that all arbitrary limits on configuration strings and lists (e.g.
limit on number of port forwardings) should now disappear; that list
boxes in the configuration will now be displayed in a sorted order
rather than the arbitrary order in which they were added to the list
(since the underlying data structure is now a sorted tree234 rather
than an ad-hoc comma-separated string); and one more specific change,
which is that local and dynamic port forwardings on the same port
number are now mutually exclusive in the configuration (putting 'D' in
the key rather than the value was a mistake in the first place).
One other reorganisation as a result of this is that I've moved all
the dialog.c standard handlers (dlg_stdeditbox_handler and friends)
out into config.c, because I can't really justify calling them generic
any more. When they took a pointer to an arbitrary structure type and
the offset of a field within that structure, they were independent of
whether that structure was a Config or something completely different,
but now they really do expect to talk to a Conf, which can _only_ be
used for PuTTY configuration, so I've renamed them all things like
conf_editbox_handler and moved them out of the nominally independent
dialog-box management module into the PuTTY-specific config.c.
[originally from svn r9214]
2011-07-14 18:52:21 +00:00
|
|
|
quality = conf_get_int(conf, CONF_font_quality);
|
2011-10-01 17:38:59 +00:00
|
|
|
fs = conf_get_fontspec(conf, CONF_font);
|
Post-release destabilisation! Completely remove the struct type
'Config' in putty.h, which stores all PuTTY's settings and includes an
arbitrary length limit on every single one of those settings which is
stored in string form. In place of it is 'Conf', an opaque data type
everywhere outside the new file conf.c, which stores a list of (key,
value) pairs in which every key contains an integer identifying a
configuration setting, and for some of those integers the key also
contains extra parts (so that, for instance, CONF_environmt is a
string-to-string mapping). Everywhere that a Config was previously
used, a Conf is now; everywhere there was a Config structure copy,
conf_copy() is called; every lookup, adjustment, load and save
operation on a Config has been rewritten; and there's a mechanism for
serialising a Conf into a binary blob and back for use with Duplicate
Session.
User-visible effects of this change _should_ be minimal, though I
don't doubt I've introduced one or two bugs here and there which will
eventually be found. The _intended_ visible effects of this change are
that all arbitrary limits on configuration strings and lists (e.g.
limit on number of port forwardings) should now disappear; that list
boxes in the configuration will now be displayed in a sorted order
rather than the arbitrary order in which they were added to the list
(since the underlying data structure is now a sorted tree234 rather
than an ad-hoc comma-separated string); and one more specific change,
which is that local and dynamic port forwardings on the same port
number are now mutually exclusive in the configuration (putting 'D' in
the key rather than the value was a mistake in the first place).
One other reorganisation as a result of this is that I've moved all
the dialog.c standard handlers (dlg_stdeditbox_handler and friends)
out into config.c, because I can't really justify calling them generic
any more. When they took a pointer to an arbitrary structure type and
the offset of a field within that structure, they were independent of
whether that structure was a Config or something completely different,
but now they really do expect to talk to a Conf, which can _only_ be
used for PuTTY configuration, so I've renamed them all things like
conf_editbox_handler and moved them out of the nominally independent
dialog-box management module into the PuTTY-specific config.c.
[originally from svn r9214]
2011-07-14 18:52:21 +00:00
|
|
|
|
2018-10-29 19:50:29 +00:00
|
|
|
hfont = CreateFont(0, 0, 0, 0, FW_DONTCARE, false, false, false,
|
Post-release destabilisation! Completely remove the struct type
'Config' in putty.h, which stores all PuTTY's settings and includes an
arbitrary length limit on every single one of those settings which is
stored in string form. In place of it is 'Conf', an opaque data type
everywhere outside the new file conf.c, which stores a list of (key,
value) pairs in which every key contains an integer identifying a
configuration setting, and for some of those integers the key also
contains extra parts (so that, for instance, CONF_environmt is a
string-to-string mapping). Everywhere that a Config was previously
used, a Conf is now; everywhere there was a Config structure copy,
conf_copy() is called; every lookup, adjustment, load and save
operation on a Config has been rewritten; and there's a mechanism for
serialising a Conf into a binary blob and back for use with Duplicate
Session.
User-visible effects of this change _should_ be minimal, though I
don't doubt I've introduced one or two bugs here and there which will
eventually be found. The _intended_ visible effects of this change are
that all arbitrary limits on configuration strings and lists (e.g.
limit on number of port forwardings) should now disappear; that list
boxes in the configuration will now be displayed in a sorted order
rather than the arbitrary order in which they were added to the list
(since the underlying data structure is now a sorted tree234 rather
than an ad-hoc comma-separated string); and one more specific change,
which is that local and dynamic port forwardings on the same port
number are now mutually exclusive in the configuration (putting 'D' in
the key rather than the value was a mistake in the first place).
One other reorganisation as a result of this is that I've moved all
the dialog.c standard handlers (dlg_stdeditbox_handler and friends)
out into config.c, because I can't really justify calling them generic
any more. When they took a pointer to an arbitrary structure type and
the offset of a field within that structure, they were independent of
whether that structure was a Config or something completely different,
but now they really do expect to talk to a Conf, which can _only_ be
used for PuTTY configuration, so I've renamed them all things like
conf_editbox_handler and moved them out of the nominally independent
dialog-box management module into the PuTTY-specific config.c.
[originally from svn r9214]
2011-07-14 18:52:21 +00:00
|
|
|
DEFAULT_CHARSET, OUT_DEFAULT_PRECIS,
|
|
|
|
CLIP_DEFAULT_PRECIS, FONT_QUALITY(quality),
|
2011-10-01 17:38:59 +00:00
|
|
|
FIXED_PITCH | FF_DONTCARE, fs->name);
|
2010-12-29 14:11:25 +00:00
|
|
|
hdc = GetDC(NULL);
|
2011-10-01 17:38:59 +00:00
|
|
|
if (hdc && SelectObject(hdc, hfont) && GetTextMetrics(hdc, &tm)) {
|
2010-12-29 14:11:25 +00:00
|
|
|
/* Note that the TMPF_FIXED_PITCH bit is defined upside down :-( */
|
|
|
|
is_var = (tm.tmPitchAndFamily & TMPF_FIXED_PITCH);
|
|
|
|
} else {
|
2018-10-29 19:50:29 +00:00
|
|
|
is_var = false; /* assume it's basically normal */
|
2010-12-29 14:11:25 +00:00
|
|
|
}
|
|
|
|
if (hdc)
|
|
|
|
ReleaseDC(NULL, hdc);
|
Post-release destabilisation! Completely remove the struct type
'Config' in putty.h, which stores all PuTTY's settings and includes an
arbitrary length limit on every single one of those settings which is
stored in string form. In place of it is 'Conf', an opaque data type
everywhere outside the new file conf.c, which stores a list of (key,
value) pairs in which every key contains an integer identifying a
configuration setting, and for some of those integers the key also
contains extra parts (so that, for instance, CONF_environmt is a
string-to-string mapping). Everywhere that a Config was previously
used, a Conf is now; everywhere there was a Config structure copy,
conf_copy() is called; every lookup, adjustment, load and save
operation on a Config has been rewritten; and there's a mechanism for
serialising a Conf into a binary blob and back for use with Duplicate
Session.
User-visible effects of this change _should_ be minimal, though I
don't doubt I've introduced one or two bugs here and there which will
eventually be found. The _intended_ visible effects of this change are
that all arbitrary limits on configuration strings and lists (e.g.
limit on number of port forwardings) should now disappear; that list
boxes in the configuration will now be displayed in a sorted order
rather than the arbitrary order in which they were added to the list
(since the underlying data structure is now a sorted tree234 rather
than an ad-hoc comma-separated string); and one more specific change,
which is that local and dynamic port forwardings on the same port
number are now mutually exclusive in the configuration (putting 'D' in
the key rather than the value was a mistake in the first place).
One other reorganisation as a result of this is that I've moved all
the dialog.c standard handlers (dlg_stdeditbox_handler and friends)
out into config.c, because I can't really justify calling them generic
any more. When they took a pointer to an arbitrary structure type and
the offset of a field within that structure, they were independent of
whether that structure was a Config or something completely different,
but now they really do expect to talk to a Conf, which can _only_ be
used for PuTTY configuration, so I've renamed them all things like
conf_editbox_handler and moved them out of the nominally independent
dialog-box management module into the PuTTY-specific config.c.
[originally from svn r9214]
2011-07-14 18:52:21 +00:00
|
|
|
if (hfont)
|
|
|
|
DeleteObject(hfont);
|
2010-12-29 14:11:25 +00:00
|
|
|
|
|
|
|
if (is_var)
|
2018-10-29 19:50:29 +00:00
|
|
|
dp->fixed_pitch_fonts = false;
|
2010-12-29 14:11:25 +00:00
|
|
|
}
|
|
|
|
|
Convert a lot of 'int' variables to 'bool'.
My normal habit these days, in new code, is to treat int and bool as
_almost_ completely separate types. I'm still willing to use C's
implicit test for zero on an integer (e.g. 'if (!blob.len)' is fine,
no need to spell it out as blob.len != 0), but generally, if a
variable is going to be conceptually a boolean, I like to declare it
bool and assign to it using 'true' or 'false' rather than 0 or 1.
PuTTY is an exception, because it predates the C99 bool, and I've
stuck to its existing coding style even when adding new code to it.
But it's been annoying me more and more, so now that I've decided C99
bool is an acceptable thing to require from our toolchain in the first
place, here's a quite thorough trawl through the source doing
'boolification'. Many variables and function parameters are now typed
as bool rather than int; many assignments of 0 or 1 to those variables
are now spelled 'true' or 'false'.
I managed this thorough conversion with the help of a custom clang
plugin that I wrote to trawl the AST and apply heuristics to point out
where things might want changing. So I've even managed to do a decent
job on parts of the code I haven't looked at in years!
To make the plugin's work easier, I pushed platform front ends
generally in the direction of using standard 'bool' in preference to
platform-specific boolean types like Windows BOOL or GTK's gboolean;
I've left the platform booleans in places they _have_ to be for the
platform APIs to work right, but variables only used by my own code
have been converted wherever I found them.
In a few places there are int values that look very like booleans in
_most_ of the places they're used, but have a rarely-used third value,
or a distinction between different nonzero values that most users
don't care about. In these cases, I've _removed_ uses of 'true' and
'false' for the return values, to emphasise that there's something
more subtle going on than a simple boolean answer:
- the 'multisel' field in dialog.h's list box structure, for which
the GTK front end in particular recognises a difference between 1
and 2 but nearly everything else treats as boolean
- the 'urgent' parameter to plug_receive, where 1 vs 2 tells you
something about the specific location of the urgent pointer, but
most clients only care about 0 vs 'something nonzero'
- the return value of wc_match, where -1 indicates a syntax error in
the wildcard.
- the return values from SSH-1 RSA-key loading functions, which use
-1 for 'wrong passphrase' and 0 for all other failures (so any
caller which already knows it's not loading an _encrypted private_
key can treat them as boolean)
- term->esc_query, and the 'query' parameter in toggle_mode in
terminal.c, which _usually_ hold 0 for ESC[123h or 1 for ESC[?123h,
but can also hold -1 for some other intervening character that we
don't support.
In a few places there's an integer that I haven't turned into a bool
even though it really _can_ only take values 0 or 1 (and, as above,
tried to make the call sites consistent in not calling those values
true and false), on the grounds that I thought it would make it more
confusing to imply that the 0 value was in some sense 'negative' or
bad and the 1 positive or good:
- the return value of plug_accepting uses the POSIXish convention of
0=success and nonzero=error; I think if I made it bool then I'd
also want to reverse its sense, and that's a job for a separate
piece of work.
- the 'screen' parameter to lineptr() in terminal.c, where 0 and 1
represent the default and alternate screens. There's no obvious
reason why one of those should be considered 'true' or 'positive'
or 'success' - they're just indices - so I've left it as int.
ssh_scp_recv had particularly confusing semantics for its previous int
return value: its call sites used '<= 0' to check for error, but it
never actually returned a negative number, just 0 or 1. Now the
function and its call sites agree that it's a bool.
In a couple of places I've renamed variables called 'ret', because I
don't like that name any more - it's unclear whether it means the
return value (in preparation) for the _containing_ function or the
return value received from a subroutine call, and occasionally I've
accidentally used the same variable for both and introduced a bug. So
where one of those got in my way, I've renamed it to 'toret' or 'retd'
(the latter short for 'returned') in line with my usual modern
practice, but I haven't done a thorough job of finding all of them.
Finally, one amusing side effect of doing this is that I've had to
separate quite a few chained assignments. It used to be perfectly fine
to write 'a = b = c = TRUE' when a,b,c were int and TRUE was just a
the 'true' defined by stdbool.h, that idiom provokes a warning from
gcc: 'suggest parentheses around assignment used as truth value'!
2018-11-02 19:23:19 +00:00
|
|
|
bool dlg_get_fixed_pitch_flag(dlgparam *dp)
|
2010-12-29 14:11:25 +00:00
|
|
|
{
|
|
|
|
return dp->fixed_pitch_fonts;
|
|
|
|
}
|
|
|
|
|
Convert a lot of 'int' variables to 'bool'.
My normal habit these days, in new code, is to treat int and bool as
_almost_ completely separate types. I'm still willing to use C's
implicit test for zero on an integer (e.g. 'if (!blob.len)' is fine,
no need to spell it out as blob.len != 0), but generally, if a
variable is going to be conceptually a boolean, I like to declare it
bool and assign to it using 'true' or 'false' rather than 0 or 1.
PuTTY is an exception, because it predates the C99 bool, and I've
stuck to its existing coding style even when adding new code to it.
But it's been annoying me more and more, so now that I've decided C99
bool is an acceptable thing to require from our toolchain in the first
place, here's a quite thorough trawl through the source doing
'boolification'. Many variables and function parameters are now typed
as bool rather than int; many assignments of 0 or 1 to those variables
are now spelled 'true' or 'false'.
I managed this thorough conversion with the help of a custom clang
plugin that I wrote to trawl the AST and apply heuristics to point out
where things might want changing. So I've even managed to do a decent
job on parts of the code I haven't looked at in years!
To make the plugin's work easier, I pushed platform front ends
generally in the direction of using standard 'bool' in preference to
platform-specific boolean types like Windows BOOL or GTK's gboolean;
I've left the platform booleans in places they _have_ to be for the
platform APIs to work right, but variables only used by my own code
have been converted wherever I found them.
In a few places there are int values that look very like booleans in
_most_ of the places they're used, but have a rarely-used third value,
or a distinction between different nonzero values that most users
don't care about. In these cases, I've _removed_ uses of 'true' and
'false' for the return values, to emphasise that there's something
more subtle going on than a simple boolean answer:
- the 'multisel' field in dialog.h's list box structure, for which
the GTK front end in particular recognises a difference between 1
and 2 but nearly everything else treats as boolean
- the 'urgent' parameter to plug_receive, where 1 vs 2 tells you
something about the specific location of the urgent pointer, but
most clients only care about 0 vs 'something nonzero'
- the return value of wc_match, where -1 indicates a syntax error in
the wildcard.
- the return values from SSH-1 RSA-key loading functions, which use
-1 for 'wrong passphrase' and 0 for all other failures (so any
caller which already knows it's not loading an _encrypted private_
key can treat them as boolean)
- term->esc_query, and the 'query' parameter in toggle_mode in
terminal.c, which _usually_ hold 0 for ESC[123h or 1 for ESC[?123h,
but can also hold -1 for some other intervening character that we
don't support.
In a few places there's an integer that I haven't turned into a bool
even though it really _can_ only take values 0 or 1 (and, as above,
tried to make the call sites consistent in not calling those values
true and false), on the grounds that I thought it would make it more
confusing to imply that the 0 value was in some sense 'negative' or
bad and the 1 positive or good:
- the return value of plug_accepting uses the POSIXish convention of
0=success and nonzero=error; I think if I made it bool then I'd
also want to reverse its sense, and that's a job for a separate
piece of work.
- the 'screen' parameter to lineptr() in terminal.c, where 0 and 1
represent the default and alternate screens. There's no obvious
reason why one of those should be considered 'true' or 'positive'
or 'success' - they're just indices - so I've left it as int.
ssh_scp_recv had particularly confusing semantics for its previous int
return value: its call sites used '<= 0' to check for error, but it
never actually returned a negative number, just 0 or 1. Now the
function and its call sites agree that it's a bool.
In a couple of places I've renamed variables called 'ret', because I
don't like that name any more - it's unclear whether it means the
return value (in preparation) for the _containing_ function or the
return value received from a subroutine call, and occasionally I've
accidentally used the same variable for both and introduced a bug. So
where one of those got in my way, I've renamed it to 'toret' or 'retd'
(the latter short for 'returned') in line with my usual modern
practice, but I haven't done a thorough job of finding all of them.
Finally, one amusing side effect of doing this is that I've had to
separate quite a few chained assignments. It used to be perfectly fine
to write 'a = b = c = TRUE' when a,b,c were int and TRUE was just a
the 'true' defined by stdbool.h, that idiom provokes a warning from
gcc: 'suggest parentheses around assignment used as truth value'!
2018-11-02 19:23:19 +00:00
|
|
|
void dlg_set_fixed_pitch_flag(dlgparam *dp, bool flag)
|
2010-12-29 14:11:25 +00:00
|
|
|
{
|
|
|
|
dp->fixed_pitch_fonts = flag;
|
|
|
|
}
|
|
|
|
|
2003-03-08 11:46:42 +00:00
|
|
|
void dp_init(struct dlgparam *dp)
|
|
|
|
{
|
|
|
|
dp->nctrltrees = 0;
|
|
|
|
dp->data = NULL;
|
2018-10-29 19:50:29 +00:00
|
|
|
dp->ended = false;
|
2003-03-08 11:46:42 +00:00
|
|
|
dp->focused = dp->lastfocused = NULL;
|
|
|
|
memset(dp->shortcuts, 0, sizeof(dp->shortcuts));
|
|
|
|
dp->hwnd = NULL;
|
2003-04-06 14:11:33 +00:00
|
|
|
dp->wintitle = dp->errtitle = NULL;
|
2018-10-29 19:50:29 +00:00
|
|
|
dp->fixed_pitch_fonts = true;
|
2003-03-08 11:46:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void dp_add_tree(struct dlgparam *dp, struct winctrls *wc)
|
|
|
|
{
|
|
|
|
assert(dp->nctrltrees < lenof(dp->controltrees));
|
|
|
|
dp->controltrees[dp->nctrltrees++] = wc;
|
|
|
|
}
|
|
|
|
|
|
|
|
void dp_cleanup(struct dlgparam *dp)
|
|
|
|
{
|
2003-04-06 14:11:33 +00:00
|
|
|
sfree(dp->wintitle);
|
|
|
|
sfree(dp->errtitle);
|
2003-03-08 11:46:42 +00:00
|
|
|
}
|