2003-03-13 19:52:28 +00:00
|
|
|
/*
|
2022-01-22 15:38:53 +00:00
|
|
|
* dialog.c - GTK implementation of the PuTTY configuration box.
|
2003-03-13 19:52:28 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include <assert.h>
|
2003-03-31 11:21:07 +00:00
|
|
|
#include <stdarg.h>
|
2003-03-16 12:37:48 +00:00
|
|
|
#include <ctype.h>
|
2003-04-09 18:46:45 +00:00
|
|
|
#include <time.h>
|
2015-08-31 12:05:51 +00:00
|
|
|
|
2003-03-13 19:52:28 +00:00
|
|
|
#include <gtk/gtk.h>
|
2015-08-08 14:06:15 +00:00
|
|
|
#if !GTK_CHECK_VERSION(3,0,0)
|
2003-03-16 12:37:48 +00:00
|
|
|
#include <gdk/gdkkeysyms.h>
|
2015-08-08 14:06:15 +00:00
|
|
|
#endif
|
2015-08-31 12:05:51 +00:00
|
|
|
|
2015-08-31 14:45:18 +00:00
|
|
|
#define MAY_REFER_TO_GTK_IN_HEADERS
|
|
|
|
|
2015-08-31 12:05:51 +00:00
|
|
|
#include "putty.h"
|
|
|
|
#include "gtkcompat.h"
|
2021-04-23 05:19:05 +00:00
|
|
|
#include "columns.h"
|
|
|
|
#include "unifont.h"
|
2015-08-31 14:45:18 +00:00
|
|
|
#include "gtkmisc.h"
|
2015-08-31 12:05:51 +00:00
|
|
|
|
2015-08-08 15:35:19 +00:00
|
|
|
#ifndef NOT_X_WINDOWS
|
2003-03-18 19:06:51 +00:00
|
|
|
#include <gdk/gdkx.h>
|
|
|
|
#include <X11/Xlib.h>
|
|
|
|
#include <X11/Xutil.h>
|
Basic support for running under GDK Wayland back end.
GTK 3 PuTTY/pterm has always assumed that if it was compiled with
_support_ for talking to the raw X11 layer underneath GTK and GDK,
then it was entitled to expect that raw X11 layer to exist at all
times, i.e. that GDK_DISPLAY_XDISPLAY would return a meaningful X
display that it could do useful things with. So if you ran it over the
GDK Wayland backend, it would immediately segfault.
Modern GTK applications need to cope with multiple GDK backends at run
time. It's fine for GTK PuTTY to _contain_ the code to find and use
underlying X11 primitives like the display and the X window id, but it
should be prepared to find that it's running on Wayland (or something
else again!) so those functions don't return anything useful - in
which case it should degrade gracefully to the subset of functionality
that can be accessed through backend-independent GTK calls.
Accordingly, I've centralised the use of GDK_DISPLAY_XDISPLAY into a
support function get_x_display() in gtkmisc.c, which starts by
checking that there actually is one first. All previous direct uses of
GDK_*_XDISPLAY now go via that function, and check the result for NULL
afterwards. (To save faffing about calling that function too many
times, I'm also caching the display pointer in more places, and
passing it as an extra argument to various subfunctions, mostly in
gtkfont.c.)
Similarly, the get_windowid() function that retrieves the window id to
put in the environment of pterm's child process has to be prepared for
there not to be a window id.
This isn't a complete fix for all Wayland-related problems. The other
one I'm currently aware of is that the default font is "server:fixed",
which is a bad default now that it won't be available on all backends.
And I expect that further problems will show up with more testing. But
it's a start.
2018-05-09 08:18:20 +00:00
|
|
|
#include "x11misc.h"
|
2015-08-08 15:35:19 +00:00
|
|
|
#endif
|
2003-03-13 19:52:28 +00:00
|
|
|
|
2003-03-31 11:21:07 +00:00
|
|
|
#include "storage.h"
|
2003-03-13 19:52:28 +00:00
|
|
|
#include "dialog.h"
|
2003-03-15 15:50:42 +00:00
|
|
|
#include "tree234.h"
|
2015-12-22 12:43:31 +00:00
|
|
|
#include "licence.h"
|
2021-03-13 10:59:47 +00:00
|
|
|
#include "ssh.h"
|
2003-03-15 15:50:42 +00:00
|
|
|
|
2015-08-08 16:34:25 +00:00
|
|
|
#if GTK_CHECK_VERSION(2,0,0)
|
|
|
|
/* Decide which of GtkFileChooserDialog and GtkFileSelection to use */
|
|
|
|
#define USE_GTK_FILE_CHOOSER_DIALOG
|
|
|
|
#endif
|
|
|
|
|
2003-03-16 12:37:48 +00:00
|
|
|
struct Shortcut {
|
|
|
|
GtkWidget *widget;
|
|
|
|
struct uctrl *uc;
|
|
|
|
int action;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct Shortcuts {
|
|
|
|
struct Shortcut sc[128];
|
|
|
|
};
|
|
|
|
|
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
|
|
|
struct selparam;
|
|
|
|
|
2003-03-15 15:50:42 +00:00
|
|
|
struct uctrl {
|
2022-05-01 08:48:38 +00:00
|
|
|
dlgcontrol *ctrl;
|
2003-03-15 15:50:42 +00:00
|
|
|
GtkWidget *toplevel;
|
|
|
|
GtkWidget **buttons; int nbuttons; /* for radio buttons */
|
2008-04-02 14:48:06 +00:00
|
|
|
GtkWidget *entry; /* for editbox, filesel, fontsel */
|
2008-04-04 10:16:24 +00:00
|
|
|
GtkWidget *button; /* for filesel, fontsel */
|
2008-05-31 19:23:45 +00:00
|
|
|
#if !GTK_CHECK_VERSION(2,4,0)
|
2019-09-08 19:29:00 +00:00
|
|
|
GtkWidget *list; /* for listbox (in GTK1), combobox (<=GTK2.3) */
|
|
|
|
GtkWidget *menu; /* for optionmenu (==droplist) */
|
|
|
|
GtkWidget *optmenu; /* also for optionmenu */
|
2008-04-04 10:56:26 +00:00
|
|
|
#else
|
2008-04-02 14:48:06 +00:00
|
|
|
GtkWidget *combo; /* for combo box (either editable or not) */
|
2008-05-31 19:23:45 +00:00
|
|
|
#endif
|
|
|
|
#if GTK_CHECK_VERSION(2,0,0)
|
|
|
|
GtkWidget *treeview; /* for listbox (GTK2), droplist+combo (>=2.4) */
|
2008-04-02 14:48:06 +00:00
|
|
|
GtkListStore *listmodel; /* for all types of list box */
|
2008-04-04 10:56:26 +00:00
|
|
|
#endif
|
2019-09-08 19:29:00 +00:00
|
|
|
GtkWidget *text; /* for text */
|
2006-08-28 14:29:02 +00:00
|
|
|
GtkWidget *label; /* for dlg_label_change */
|
2003-03-18 19:06:51 +00:00
|
|
|
GtkAdjustment *adj; /* for the scrollbar in a list box */
|
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
|
|
|
struct selparam *sp; /* which switchable pane of the box we're in */
|
2003-03-22 17:00:06 +00:00
|
|
|
guint textsig;
|
2007-03-27 18:16:36 +00:00
|
|
|
int nclicks;
|
2022-05-01 07:39:49 +00:00
|
|
|
const char *textvalue; /* temporary, for button-only file selectors */
|
2003-03-15 15:50:42 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
struct dlgparam {
|
|
|
|
tree234 *byctrl, *bywidget;
|
|
|
|
void *data;
|
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
|
|
|
struct {
|
|
|
|
unsigned char r, g, b; /* 0-255 */
|
|
|
|
bool ok;
|
|
|
|
} coloursel_result;
|
2003-03-15 15:50:42 +00:00
|
|
|
/* `flags' are set to indicate when a GTK signal handler is being called
|
|
|
|
* due to automatic processing and should not flag a user event. */
|
|
|
|
int flags;
|
2003-03-16 12:37:48 +00:00
|
|
|
struct Shortcuts *shortcuts;
|
2007-01-25 19:33:29 +00:00
|
|
|
GtkWidget *window, *cancelbutton;
|
2022-05-01 08:48:38 +00:00
|
|
|
dlgcontrol *currfocus, *lastfocus;
|
2007-01-25 19:33:29 +00:00
|
|
|
#if !GTK_CHECK_VERSION(2,0,0)
|
|
|
|
GtkWidget *currtreeitem, **treeitems;
|
2003-03-18 19:06:51 +00:00
|
|
|
int ntreeitems;
|
2015-08-25 18:44:44 +00:00
|
|
|
#else
|
New array-growing macros: sgrowarray and sgrowarrayn.
The idea of these is that they centralise the common idiom along the
lines of
if (logical_array_len >= physical_array_size) {
physical_array_size = logical_array_len * 5 / 4 + 256;
array = sresize(array, physical_array_size, ElementType);
}
which happens at a zillion call sites throughout this code base, with
different random choices of the geometric factor and additive
constant, sometimes forgetting them completely, and generally doing a
lot of repeated work.
The new macro sgrowarray(array,size,n) has the semantics: here are the
array pointer and its physical size for you to modify, now please
ensure that the nth element exists, so I can write into it. And
sgrowarrayn(array,size,n,m) is the same except that it ensures that
the array has size at least n+m (so sgrowarray is just the special
case where m=1).
Now that this is a single centralised implementation that will be used
everywhere, I've also gone to more effort in the implementation, with
careful overflow checks that would have been painful to put at all the
previous call sites.
This commit also switches over every use of sresize(), apart from a
few where I really didn't think it would gain anything. A consequence
of that is that a lot of array-size variables have to have their types
changed to size_t, because the macros require that (they address-take
the size to pass to the underlying function).
2019-02-28 20:07:30 +00:00
|
|
|
size_t nselparams;
|
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
|
|
|
struct selparam **selparams;
|
2007-01-25 19:33:29 +00:00
|
|
|
#endif
|
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
|
|
|
struct selparam *curr_panel;
|
Make the configuration dialog non-modal.
Now every call to do_config_box is replaced with a call to
create_config_box, which returns immediately having constructed the
new GTK window object, and is passed a callback function which it will
arrange to be called when the dialog terminates (whether by OK or by
Cancel). That callback is now what triggers the construction of a
session window after 'Open' is pressed in the initial config box, or
the actual mid-session reconfiguration action after 'Apply' is pressed
in a Change Settings box.
We were already prepared to ignore the re-selection of 'Change
Settings' from the context menu of a window that already had a Change
Settings box open (and not accidentally create a second config box for
the same window); but now we do slightly better, by finding the
existing config box and un-minimising and raising it, in case the user
had forgotten it was there.
That's a useful featurelet, but not the main purpose of this change.
The mani point, of course, is that now the multi-window GtkApplication
based front ends now don't do anything confusing to the nesting of
gtk_main() when config boxes are involved. Whether you're changing the
settings of one (or more than one) of your already-running sessions,
preparing to start up a new PuTTY connection, or both at once, we stay
in the same top-level instance of gtk_main() and all sessions' top-
level callbacks continue to run sensibly.
2017-11-26 11:58:02 +00:00
|
|
|
struct controlbox *ctrlbox;
|
2003-03-18 19:06:51 +00:00
|
|
|
int retval;
|
Make the configuration dialog non-modal.
Now every call to do_config_box is replaced with a call to
create_config_box, which returns immediately having constructed the
new GTK window object, and is passed a callback function which it will
arrange to be called when the dialog terminates (whether by OK or by
Cancel). That callback is now what triggers the construction of a
session window after 'Open' is pressed in the initial config box, or
the actual mid-session reconfiguration action after 'Apply' is pressed
in a Change Settings box.
We were already prepared to ignore the re-selection of 'Change
Settings' from the context menu of a window that already had a Change
Settings box open (and not accidentally create a second config box for
the same window); but now we do slightly better, by finding the
existing config box and un-minimising and raising it, in case the user
had forgotten it was there.
That's a useful featurelet, but not the main purpose of this change.
The mani point, of course, is that now the multi-window GtkApplication
based front ends now don't do anything confusing to the nesting of
gtk_main() when config boxes are involved. Whether you're changing the
settings of one (or more than one) of your already-running sessions,
preparing to start up a new PuTTY connection, or both at once, we stay
in the same top-level instance of gtk_main() and all sessions' top-
level callbacks continue to run sensibly.
2017-11-26 11:58:02 +00:00
|
|
|
post_dialog_fn_t after;
|
|
|
|
void *afterctx;
|
2003-03-15 15:50:42 +00:00
|
|
|
};
|
|
|
|
#define FLAG_UPDATING_COMBO_LIST 1
|
2008-04-02 14:48:06 +00:00
|
|
|
#define FLAG_UPDATING_LISTBOX 2
|
2003-03-15 15:50:42 +00:00
|
|
|
|
2019-09-08 19:29:00 +00:00
|
|
|
enum { /* values for Shortcut.action */
|
|
|
|
SHORTCUT_EMPTY, /* no shortcut on this key */
|
|
|
|
SHORTCUT_TREE, /* focus a tree item */
|
|
|
|
SHORTCUT_FOCUS, /* focus the supplied widget */
|
|
|
|
SHORTCUT_UCTRL, /* do something sane with uctrl */
|
|
|
|
SHORTCUT_UCTRL_UP, /* uctrl is a draglist, move Up */
|
|
|
|
SHORTCUT_UCTRL_DOWN, /* uctrl is a draglist, move Down */
|
2003-03-16 12:37:48 +00:00
|
|
|
};
|
|
|
|
|
2007-01-25 19:33:29 +00:00
|
|
|
#if GTK_CHECK_VERSION(2,0,0)
|
|
|
|
enum {
|
|
|
|
TREESTORE_PATH,
|
|
|
|
TREESTORE_PARAMS,
|
|
|
|
TREESTORE_NUM
|
|
|
|
};
|
|
|
|
#endif
|
|
|
|
|
2003-03-15 15:50:42 +00:00
|
|
|
/*
|
|
|
|
* Forward references.
|
|
|
|
*/
|
2003-03-18 19:06:51 +00:00
|
|
|
static gboolean widget_focus(GtkWidget *widget, GdkEventFocus *event,
|
|
|
|
gpointer data);
|
2003-03-16 12:37:48 +00:00
|
|
|
static void shortcut_add(struct Shortcuts *scs, GtkWidget *labelw,
|
2019-09-08 19:29:00 +00:00
|
|
|
int chr, int action, void *ptr);
|
2006-08-28 14:29:02 +00:00
|
|
|
static void shortcut_highlight(GtkWidget *label, int chr);
|
2008-04-04 10:56:26 +00:00
|
|
|
#if !GTK_CHECK_VERSION(2,0,0)
|
|
|
|
static gboolean listitem_single_key(GtkWidget *item, GdkEventKey *event,
|
2019-09-08 19:29:00 +00:00
|
|
|
gpointer data);
|
2008-04-04 10:56:26 +00:00
|
|
|
static gboolean listitem_multi_key(GtkWidget *item, GdkEventKey *event,
|
2019-09-08 19:29:00 +00:00
|
|
|
gpointer data);
|
2008-04-04 10:56:26 +00:00
|
|
|
static gboolean listitem_button_press(GtkWidget *item, GdkEventButton *event,
|
2019-09-08 19:29:00 +00:00
|
|
|
gpointer data);
|
2008-04-04 10:56:26 +00:00
|
|
|
static gboolean listitem_button_release(GtkWidget *item, GdkEventButton *event,
|
2019-09-08 19:29:00 +00:00
|
|
|
gpointer data);
|
2008-05-31 19:23:45 +00:00
|
|
|
#endif
|
|
|
|
#if !GTK_CHECK_VERSION(2,4,0)
|
2008-04-04 10:56:26 +00:00
|
|
|
static void menuitem_activate(GtkMenuItem *item, gpointer data);
|
|
|
|
#endif
|
2015-08-22 13:49:02 +00:00
|
|
|
#if GTK_CHECK_VERSION(3,0,0)
|
|
|
|
static void colourchoose_response(GtkDialog *dialog,
|
|
|
|
gint response_id, gpointer data);
|
|
|
|
#else
|
2003-03-15 15:50:42 +00:00
|
|
|
static void coloursel_ok(GtkButton *button, gpointer data);
|
|
|
|
static void coloursel_cancel(GtkButton *button, gpointer data);
|
2015-08-22 13:49:02 +00:00
|
|
|
#endif
|
Make the configuration dialog non-modal.
Now every call to do_config_box is replaced with a call to
create_config_box, which returns immediately having constructed the
new GTK window object, and is passed a callback function which it will
arrange to be called when the dialog terminates (whether by OK or by
Cancel). That callback is now what triggers the construction of a
session window after 'Open' is pressed in the initial config box, or
the actual mid-session reconfiguration action after 'Apply' is pressed
in a Change Settings box.
We were already prepared to ignore the re-selection of 'Change
Settings' from the context menu of a window that already had a Change
Settings box open (and not accidentally create a second config box for
the same window); but now we do slightly better, by finding the
existing config box and un-minimising and raising it, in case the user
had forgotten it was there.
That's a useful featurelet, but not the main purpose of this change.
The mani point, of course, is that now the multi-window GtkApplication
based front ends now don't do anything confusing to the nesting of
gtk_main() when config boxes are involved. Whether you're changing the
settings of one (or more than one) of your already-running sessions,
preparing to start up a new PuTTY connection, or both at once, we stay
in the same top-level instance of gtk_main() and all sessions' top-
level callbacks continue to run sensibly.
2017-11-26 11:58:02 +00:00
|
|
|
static void dlgparam_destroy(GtkWidget *widget, gpointer data);
|
2018-11-03 08:25:28 +00:00
|
|
|
static int get_listitemheight(GtkWidget *widget);
|
2003-03-15 15:50:42 +00:00
|
|
|
|
|
|
|
static int uctrl_cmp_byctrl(void *av, void *bv)
|
|
|
|
{
|
|
|
|
struct uctrl *a = (struct uctrl *)av;
|
|
|
|
struct uctrl *b = (struct uctrl *)bv;
|
|
|
|
if (a->ctrl < b->ctrl)
|
2019-09-08 19:29:00 +00:00
|
|
|
return -1;
|
2003-03-15 15:50:42 +00:00
|
|
|
else if (a->ctrl > b->ctrl)
|
2019-09-08 19:29:00 +00:00
|
|
|
return +1;
|
2003-03-15 15:50:42 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int uctrl_cmp_byctrl_find(void *av, void *bv)
|
|
|
|
{
|
2022-05-01 08:48:38 +00:00
|
|
|
dlgcontrol *a = (dlgcontrol *)av;
|
2003-03-15 15:50:42 +00:00
|
|
|
struct uctrl *b = (struct uctrl *)bv;
|
|
|
|
if (a < b->ctrl)
|
2019-09-08 19:29:00 +00:00
|
|
|
return -1;
|
2003-03-15 15:50:42 +00:00
|
|
|
else if (a > b->ctrl)
|
2019-09-08 19:29:00 +00:00
|
|
|
return +1;
|
2003-03-15 15:50:42 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int uctrl_cmp_bywidget(void *av, void *bv)
|
|
|
|
{
|
|
|
|
struct uctrl *a = (struct uctrl *)av;
|
|
|
|
struct uctrl *b = (struct uctrl *)bv;
|
|
|
|
if (a->toplevel < b->toplevel)
|
2019-09-08 19:29:00 +00:00
|
|
|
return -1;
|
2003-03-15 15:50:42 +00:00
|
|
|
else if (a->toplevel > b->toplevel)
|
2019-09-08 19:29:00 +00:00
|
|
|
return +1;
|
2003-03-15 15:50:42 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int uctrl_cmp_bywidget_find(void *av, void *bv)
|
|
|
|
{
|
|
|
|
GtkWidget *a = (GtkWidget *)av;
|
|
|
|
struct uctrl *b = (struct uctrl *)bv;
|
|
|
|
if (a < b->toplevel)
|
2019-09-08 19:29:00 +00:00
|
|
|
return -1;
|
2003-03-15 15:50:42 +00:00
|
|
|
else if (a > b->toplevel)
|
2019-09-08 19:29:00 +00:00
|
|
|
return +1;
|
2003-03-15 15:50:42 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void dlg_init(struct dlgparam *dp)
|
|
|
|
{
|
|
|
|
dp->byctrl = newtree234(uctrl_cmp_byctrl);
|
|
|
|
dp->bywidget = newtree234(uctrl_cmp_bywidget);
|
2018-10-29 19:50:29 +00:00
|
|
|
dp->coloursel_result.ok = false;
|
2007-01-25 19:33:29 +00:00
|
|
|
dp->window = dp->cancelbutton = NULL;
|
|
|
|
#if !GTK_CHECK_VERSION(2,0,0)
|
2003-03-31 11:21:07 +00:00
|
|
|
dp->treeitems = NULL;
|
2007-01-25 19:33:29 +00:00
|
|
|
dp->currtreeitem = NULL;
|
|
|
|
#endif
|
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
|
|
|
dp->curr_panel = NULL;
|
2004-01-17 14:25:36 +00:00
|
|
|
dp->flags = 0;
|
|
|
|
dp->currfocus = NULL;
|
2003-03-15 15:50:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void dlg_cleanup(struct dlgparam *dp)
|
|
|
|
{
|
|
|
|
struct uctrl *uc;
|
|
|
|
|
2019-09-08 19:29:00 +00:00
|
|
|
freetree234(dp->byctrl); /* doesn't free the uctrls inside */
|
2003-04-09 18:46:45 +00:00
|
|
|
dp->byctrl = NULL;
|
2003-03-15 15:50:42 +00:00
|
|
|
while ( (uc = index234(dp->bywidget, 0)) != NULL) {
|
2019-09-08 19:29:00 +00:00
|
|
|
del234(dp->bywidget, uc);
|
|
|
|
sfree(uc->buttons);
|
|
|
|
sfree(uc);
|
2003-03-15 15:50:42 +00:00
|
|
|
}
|
|
|
|
freetree234(dp->bywidget);
|
2003-04-09 18:46:45 +00:00
|
|
|
dp->bywidget = NULL;
|
2007-01-25 19:33:29 +00:00
|
|
|
#if !GTK_CHECK_VERSION(2,0,0)
|
2003-03-18 19:06:51 +00:00
|
|
|
sfree(dp->treeitems);
|
2007-01-25 19:33:29 +00:00
|
|
|
#endif
|
2003-03-15 15:50:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void dlg_add_uctrl(struct dlgparam *dp, struct uctrl *uc)
|
|
|
|
{
|
|
|
|
add234(dp->byctrl, uc);
|
|
|
|
add234(dp->bywidget, uc);
|
|
|
|
}
|
|
|
|
|
2022-05-01 08:48:38 +00:00
|
|
|
static struct uctrl *dlg_find_byctrl(struct dlgparam *dp, dlgcontrol *ctrl)
|
2003-03-15 15:50:42 +00:00
|
|
|
{
|
2003-04-09 18:46:45 +00:00
|
|
|
if (!dp->byctrl)
|
2019-09-08 19:29:00 +00:00
|
|
|
return NULL;
|
2003-03-15 15:50:42 +00:00
|
|
|
return find234(dp->byctrl, ctrl, uctrl_cmp_byctrl_find);
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct uctrl *dlg_find_bywidget(struct dlgparam *dp, GtkWidget *w)
|
|
|
|
{
|
|
|
|
struct uctrl *ret = NULL;
|
2003-04-09 18:46:45 +00:00
|
|
|
if (!dp->bywidget)
|
2019-09-08 19:29:00 +00:00
|
|
|
return NULL;
|
2003-03-15 15:50:42 +00:00
|
|
|
do {
|
2019-09-08 19:29:00 +00:00
|
|
|
ret = find234(dp->bywidget, w, uctrl_cmp_bywidget_find);
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
w = gtk_widget_get_parent(w);
|
2003-03-15 15:50:42 +00:00
|
|
|
} while (w);
|
|
|
|
return ret;
|
|
|
|
}
|
2003-03-13 19:52:28 +00:00
|
|
|
|
2022-05-01 08:48:38 +00:00
|
|
|
dlgcontrol *dlg_last_focused(dlgcontrol *ctrl, dlgparam *dp)
|
2003-03-13 19:52:28 +00:00
|
|
|
{
|
2003-03-18 19:06:51 +00:00
|
|
|
if (dp->currfocus != ctrl)
|
|
|
|
return dp->currfocus;
|
|
|
|
else
|
|
|
|
return dp->lastfocus;
|
2003-03-13 19:52:28 +00:00
|
|
|
}
|
|
|
|
|
2022-05-01 08:48:38 +00:00
|
|
|
void dlg_radiobutton_set(dlgcontrol *ctrl, dlgparam *dp, int which)
|
2003-03-13 19:52:28 +00:00
|
|
|
{
|
2003-03-15 15:50:42 +00:00
|
|
|
struct uctrl *uc = dlg_find_byctrl(dp, ctrl);
|
Restructure dlgcontrol as a struct with an anon union.
This gets rid of that awkward STANDARD_PREFIX system in which every
branch of the old 'union control' had to repeat all the generic
fields, and then call sites had to make an arbitrary decision about
which branch to access them through.
That was the best we could do before accepting C99 features in this
code base. But now we have anonymous unions, so we don't need to put
up with that nonsense any more!
'dlgcontrol' is now a struct rather than a union, and the generic
fields common to all control types are ordinary members of the struct,
so you don't have to refer to them as ctrl->generic.foo at all, just
ctrl->foo, which saves verbiage at the point of use.
The extra per-control fields are still held in structures named after
the control type, so you'll still say ctrl->listbox.height or
whatever. But now those structures are themselves members of an
anonymous union field following the generic fields, so those
sub-structures don't have to reiterate all the standard stuff too.
While I'm here, I've promoted 'context2' from an editbox-specific
field to a generic one (it just seems silly _not_ to allow any control
to have two context fields if it needs it). Also, I had to rename the
boolean field 'tabdelay' to avoid it clashing with the subsidiary
structure field 'tabdelay', now that the former isn't generic.tabdelay
any more.
2022-05-01 08:55:52 +00:00
|
|
|
assert(uc->ctrl->type == CTRL_RADIO);
|
2003-03-15 15:50:42 +00:00
|
|
|
assert(uc->buttons != NULL);
|
2018-10-29 19:50:29 +00:00
|
|
|
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(uc->buttons[which]), true);
|
2003-03-13 19:52:28 +00:00
|
|
|
}
|
|
|
|
|
2022-05-01 08:48:38 +00:00
|
|
|
int dlg_radiobutton_get(dlgcontrol *ctrl, dlgparam *dp)
|
2003-03-13 19:52:28 +00:00
|
|
|
{
|
2003-03-15 15:50:42 +00:00
|
|
|
struct uctrl *uc = dlg_find_byctrl(dp, ctrl);
|
|
|
|
int i;
|
|
|
|
|
Restructure dlgcontrol as a struct with an anon union.
This gets rid of that awkward STANDARD_PREFIX system in which every
branch of the old 'union control' had to repeat all the generic
fields, and then call sites had to make an arbitrary decision about
which branch to access them through.
That was the best we could do before accepting C99 features in this
code base. But now we have anonymous unions, so we don't need to put
up with that nonsense any more!
'dlgcontrol' is now a struct rather than a union, and the generic
fields common to all control types are ordinary members of the struct,
so you don't have to refer to them as ctrl->generic.foo at all, just
ctrl->foo, which saves verbiage at the point of use.
The extra per-control fields are still held in structures named after
the control type, so you'll still say ctrl->listbox.height or
whatever. But now those structures are themselves members of an
anonymous union field following the generic fields, so those
sub-structures don't have to reiterate all the standard stuff too.
While I'm here, I've promoted 'context2' from an editbox-specific
field to a generic one (it just seems silly _not_ to allow any control
to have two context fields if it needs it). Also, I had to rename the
boolean field 'tabdelay' to avoid it clashing with the subsidiary
structure field 'tabdelay', now that the former isn't generic.tabdelay
any more.
2022-05-01 08:55:52 +00:00
|
|
|
assert(uc->ctrl->type == CTRL_RADIO);
|
2003-03-15 15:50:42 +00:00
|
|
|
assert(uc->buttons != NULL);
|
|
|
|
for (i = 0; i < uc->nbuttons; i++)
|
2019-09-08 19:29:00 +00:00
|
|
|
if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(uc->buttons[i])))
|
|
|
|
return i;
|
|
|
|
return 0; /* got to return something */
|
2003-03-13 19:52:28 +00:00
|
|
|
}
|
|
|
|
|
2022-05-01 08:48:38 +00:00
|
|
|
void dlg_checkbox_set(dlgcontrol *ctrl, dlgparam *dp, bool checked)
|
2003-03-13 19:52:28 +00:00
|
|
|
{
|
2003-03-15 15:50:42 +00:00
|
|
|
struct uctrl *uc = dlg_find_byctrl(dp, ctrl);
|
Restructure dlgcontrol as a struct with an anon union.
This gets rid of that awkward STANDARD_PREFIX system in which every
branch of the old 'union control' had to repeat all the generic
fields, and then call sites had to make an arbitrary decision about
which branch to access them through.
That was the best we could do before accepting C99 features in this
code base. But now we have anonymous unions, so we don't need to put
up with that nonsense any more!
'dlgcontrol' is now a struct rather than a union, and the generic
fields common to all control types are ordinary members of the struct,
so you don't have to refer to them as ctrl->generic.foo at all, just
ctrl->foo, which saves verbiage at the point of use.
The extra per-control fields are still held in structures named after
the control type, so you'll still say ctrl->listbox.height or
whatever. But now those structures are themselves members of an
anonymous union field following the generic fields, so those
sub-structures don't have to reiterate all the standard stuff too.
While I'm here, I've promoted 'context2' from an editbox-specific
field to a generic one (it just seems silly _not_ to allow any control
to have two context fields if it needs it). Also, I had to rename the
boolean field 'tabdelay' to avoid it clashing with the subsidiary
structure field 'tabdelay', now that the former isn't generic.tabdelay
any more.
2022-05-01 08:55:52 +00:00
|
|
|
assert(uc->ctrl->type == CTRL_CHECKBOX);
|
2003-03-15 15:50:42 +00:00
|
|
|
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(uc->toplevel), checked);
|
2003-03-13 19:52:28 +00:00
|
|
|
}
|
|
|
|
|
2022-05-01 08:48:38 +00:00
|
|
|
bool dlg_checkbox_get(dlgcontrol *ctrl, dlgparam *dp)
|
2003-03-13 19:52:28 +00:00
|
|
|
{
|
2003-03-15 15:50:42 +00:00
|
|
|
struct uctrl *uc = dlg_find_byctrl(dp, ctrl);
|
Restructure dlgcontrol as a struct with an anon union.
This gets rid of that awkward STANDARD_PREFIX system in which every
branch of the old 'union control' had to repeat all the generic
fields, and then call sites had to make an arbitrary decision about
which branch to access them through.
That was the best we could do before accepting C99 features in this
code base. But now we have anonymous unions, so we don't need to put
up with that nonsense any more!
'dlgcontrol' is now a struct rather than a union, and the generic
fields common to all control types are ordinary members of the struct,
so you don't have to refer to them as ctrl->generic.foo at all, just
ctrl->foo, which saves verbiage at the point of use.
The extra per-control fields are still held in structures named after
the control type, so you'll still say ctrl->listbox.height or
whatever. But now those structures are themselves members of an
anonymous union field following the generic fields, so those
sub-structures don't have to reiterate all the standard stuff too.
While I'm here, I've promoted 'context2' from an editbox-specific
field to a generic one (it just seems silly _not_ to allow any control
to have two context fields if it needs it). Also, I had to rename the
boolean field 'tabdelay' to avoid it clashing with the subsidiary
structure field 'tabdelay', now that the former isn't generic.tabdelay
any more.
2022-05-01 08:55:52 +00:00
|
|
|
assert(uc->ctrl->type == CTRL_CHECKBOX);
|
2003-03-15 15:50:42 +00:00
|
|
|
return gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(uc->toplevel));
|
2003-03-13 19:52:28 +00:00
|
|
|
}
|
|
|
|
|
2024-09-23 13:20:44 +00:00
|
|
|
void dlg_editbox_set_utf8(dlgcontrol *ctrl, dlgparam *dp, char const *text)
|
2003-03-13 19:52:28 +00:00
|
|
|
{
|
2003-03-15 15:50:42 +00:00
|
|
|
struct uctrl *uc = dlg_find_byctrl(dp, ctrl);
|
2008-04-02 14:48:06 +00:00
|
|
|
GtkWidget *entry;
|
|
|
|
char *tmpstring;
|
Restructure dlgcontrol as a struct with an anon union.
This gets rid of that awkward STANDARD_PREFIX system in which every
branch of the old 'union control' had to repeat all the generic
fields, and then call sites had to make an arbitrary decision about
which branch to access them through.
That was the best we could do before accepting C99 features in this
code base. But now we have anonymous unions, so we don't need to put
up with that nonsense any more!
'dlgcontrol' is now a struct rather than a union, and the generic
fields common to all control types are ordinary members of the struct,
so you don't have to refer to them as ctrl->generic.foo at all, just
ctrl->foo, which saves verbiage at the point of use.
The extra per-control fields are still held in structures named after
the control type, so you'll still say ctrl->listbox.height or
whatever. But now those structures are themselves members of an
anonymous union field following the generic fields, so those
sub-structures don't have to reiterate all the standard stuff too.
While I'm here, I've promoted 'context2' from an editbox-specific
field to a generic one (it just seems silly _not_ to allow any control
to have two context fields if it needs it). Also, I had to rename the
boolean field 'tabdelay' to avoid it clashing with the subsidiary
structure field 'tabdelay', now that the former isn't generic.tabdelay
any more.
2022-05-01 08:55:52 +00:00
|
|
|
assert(uc->ctrl->type == CTRL_EDITBOX);
|
2008-04-02 14:48:06 +00:00
|
|
|
|
2008-05-31 19:23:45 +00:00
|
|
|
#if GTK_CHECK_VERSION(2,4,0)
|
|
|
|
if (uc->combo)
|
2019-09-08 19:29:00 +00:00
|
|
|
entry = gtk_bin_get_child(GTK_BIN(uc->combo));
|
2008-05-31 19:23:45 +00:00
|
|
|
else
|
2008-04-04 10:56:26 +00:00
|
|
|
#endif
|
2022-06-23 17:44:07 +00:00
|
|
|
entry = uc->entry;
|
2008-05-31 19:23:45 +00:00
|
|
|
|
|
|
|
assert(entry != NULL);
|
2008-04-02 14:48:06 +00:00
|
|
|
|
2007-01-25 19:47:36 +00:00
|
|
|
/*
|
|
|
|
* GTK 2 implements gtk_entry_set_text by means of two separate
|
|
|
|
* operations: first delete the previous text leaving the empty
|
|
|
|
* string, then insert the new text. This causes two calls to
|
|
|
|
* the "changed" signal.
|
2008-04-02 14:48:06 +00:00
|
|
|
*
|
2007-01-25 19:47:36 +00:00
|
|
|
* The first call to "changed", if allowed to proceed normally,
|
|
|
|
* will cause an EVENT_VALCHANGE event on the edit box, causing
|
|
|
|
* a call to dlg_editbox_get() which will read the empty string
|
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
|
|
|
* out of the GtkEntry - and promptly write it straight into the
|
|
|
|
* Conf structure, which is precisely where our `text' pointer
|
|
|
|
* is probably pointing, so the second editing operation will
|
|
|
|
* insert that instead of the string we originally asked for.
|
2008-04-02 14:48:06 +00:00
|
|
|
*
|
|
|
|
* Hence, we must take our own copy of the text before we do
|
|
|
|
* this.
|
2007-01-25 19:47:36 +00:00
|
|
|
*/
|
2008-04-02 14:48:06 +00:00
|
|
|
tmpstring = dupstr(text);
|
|
|
|
gtk_entry_set_text(GTK_ENTRY(entry), tmpstring);
|
|
|
|
sfree(tmpstring);
|
2003-03-13 19:52:28 +00:00
|
|
|
}
|
|
|
|
|
2024-09-23 13:20:44 +00:00
|
|
|
void dlg_editbox_set(dlgcontrol *ctrl, dlgparam *dp, char const *text)
|
|
|
|
{
|
|
|
|
/* GTK specifies that its edit boxes are always in UTF-8 anyway,
|
|
|
|
* so legacy behaviour is to use those strings unmodified */
|
|
|
|
dlg_editbox_set_utf8(ctrl, dp, text);
|
|
|
|
}
|
|
|
|
|
|
|
|
char *dlg_editbox_get_utf8(dlgcontrol *ctrl, dlgparam *dp)
|
2003-03-13 19:52:28 +00:00
|
|
|
{
|
2003-03-15 15:50:42 +00:00
|
|
|
struct uctrl *uc = dlg_find_byctrl(dp, ctrl);
|
Restructure dlgcontrol as a struct with an anon union.
This gets rid of that awkward STANDARD_PREFIX system in which every
branch of the old 'union control' had to repeat all the generic
fields, and then call sites had to make an arbitrary decision about
which branch to access them through.
That was the best we could do before accepting C99 features in this
code base. But now we have anonymous unions, so we don't need to put
up with that nonsense any more!
'dlgcontrol' is now a struct rather than a union, and the generic
fields common to all control types are ordinary members of the struct,
so you don't have to refer to them as ctrl->generic.foo at all, just
ctrl->foo, which saves verbiage at the point of use.
The extra per-control fields are still held in structures named after
the control type, so you'll still say ctrl->listbox.height or
whatever. But now those structures are themselves members of an
anonymous union field following the generic fields, so those
sub-structures don't have to reiterate all the standard stuff too.
While I'm here, I've promoted 'context2' from an editbox-specific
field to a generic one (it just seems silly _not_ to allow any control
to have two context fields if it needs it). Also, I had to rename the
boolean field 'tabdelay' to avoid it clashing with the subsidiary
structure field 'tabdelay', now that the former isn't generic.tabdelay
any more.
2022-05-01 08:55:52 +00:00
|
|
|
assert(uc->ctrl->type == CTRL_EDITBOX);
|
2003-03-15 15:50:42 +00:00
|
|
|
|
2008-05-31 19:23:45 +00:00
|
|
|
#if GTK_CHECK_VERSION(2,4,0)
|
|
|
|
if (uc->combo) {
|
Formatting: standardise on "func(\n", not "func\n(".
If the function name (or expression) in a function call or declaration
is itself so long that even the first argument doesn't fit after it on
the same line, or if that would leave so little space that it would be
silly to try to wrap all the run-on lines into a tall thin column,
then I used to do this
ludicrously_long_function_name
(arg1, arg2, arg3);
and now prefer this
ludicrously_long_function_name(
arg1, arg2, arg3);
I picked up the habit from Python, where the latter idiom is required
by Python's syntactic significance of newlines (you can write the
former if you use a backslash-continuation, but pretty much everyone
seems to agree that that's much uglier). But I've found it works well
in C as well: it makes it more obvious that the previous line is
incomplete, it gives you a tiny bit more space to wrap the following
lines into (the old idiom indents the _third_ line one space beyond
the second), and I generally turn out to agree with the knock-on
indentation decisions made by at least Emacs if you do it in the
middle of a complex expression. Plus, of course, using the _same_
idiom between C and Python means less state-switching.
So, while I'm making annoying indentation changes in general, this
seems like a good time to dig out all the cases of the old idiom in
this code, and switch them over to the new.
2022-08-03 19:48:46 +00:00
|
|
|
return dupstr(gtk_entry_get_text(
|
|
|
|
GTK_ENTRY(gtk_bin_get_child(GTK_BIN(uc->combo)))));
|
2008-04-02 14:48:06 +00:00
|
|
|
}
|
2008-04-04 10:56:26 +00:00
|
|
|
#endif
|
2008-05-31 19:23:45 +00:00
|
|
|
|
|
|
|
if (uc->entry) {
|
2019-09-08 19:29:00 +00:00
|
|
|
return dupstr(gtk_entry_get_text(GTK_ENTRY(uc->entry)));
|
2008-05-31 19:23:45 +00:00
|
|
|
}
|
|
|
|
|
2019-09-09 18:07:55 +00:00
|
|
|
unreachable("bad control type in editbox_get");
|
2003-03-13 19:52:28 +00:00
|
|
|
}
|
|
|
|
|
2024-09-23 13:20:44 +00:00
|
|
|
char *dlg_editbox_get(dlgcontrol *ctrl, dlgparam *dp)
|
|
|
|
{
|
|
|
|
/* GTK specifies that its edit boxes are always in UTF-8 anyway,
|
|
|
|
* so legacy behaviour is to use those strings unmodified */
|
|
|
|
return dlg_editbox_get_utf8(ctrl, dp);
|
|
|
|
}
|
|
|
|
|
2022-06-25 12:00:06 +00:00
|
|
|
void dlg_editbox_select_range(dlgcontrol *ctrl, dlgparam *dp,
|
|
|
|
size_t start, size_t len)
|
|
|
|
{
|
|
|
|
struct uctrl *uc = dlg_find_byctrl(dp, ctrl);
|
|
|
|
assert(uc->ctrl->type == CTRL_EDITBOX);
|
|
|
|
|
|
|
|
GtkWidget *entry = NULL;
|
|
|
|
|
|
|
|
#if GTK_CHECK_VERSION(2,4,0)
|
|
|
|
if (uc->combo)
|
|
|
|
entry = gtk_bin_get_child(GTK_BIN(uc->combo));
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (uc->entry)
|
|
|
|
entry = uc->entry;
|
|
|
|
|
|
|
|
assert(entry && "we should have a GtkEntry one way or another");
|
|
|
|
|
|
|
|
gtk_editable_select_region(GTK_EDITABLE(entry), start, start + len);
|
|
|
|
}
|
|
|
|
|
2008-05-31 19:23:45 +00:00
|
|
|
#if !GTK_CHECK_VERSION(2,4,0)
|
2008-04-04 10:56:26 +00:00
|
|
|
static void container_remove_and_destroy(GtkWidget *w, gpointer data)
|
|
|
|
{
|
|
|
|
GtkContainer *cont = GTK_CONTAINER(data);
|
|
|
|
/* gtk_container_remove will unref the widget for us; we need not. */
|
|
|
|
gtk_container_remove(cont, w);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2003-03-13 19:52:28 +00:00
|
|
|
/* The `listbox' functions can also apply to combo boxes. */
|
2022-05-01 08:48:38 +00:00
|
|
|
void dlg_listbox_clear(dlgcontrol *ctrl, dlgparam *dp)
|
2003-03-13 19:52:28 +00:00
|
|
|
{
|
2003-03-15 15:50:42 +00:00
|
|
|
struct uctrl *uc = dlg_find_byctrl(dp, ctrl);
|
|
|
|
|
Restructure dlgcontrol as a struct with an anon union.
This gets rid of that awkward STANDARD_PREFIX system in which every
branch of the old 'union control' had to repeat all the generic
fields, and then call sites had to make an arbitrary decision about
which branch to access them through.
That was the best we could do before accepting C99 features in this
code base. But now we have anonymous unions, so we don't need to put
up with that nonsense any more!
'dlgcontrol' is now a struct rather than a union, and the generic
fields common to all control types are ordinary members of the struct,
so you don't have to refer to them as ctrl->generic.foo at all, just
ctrl->foo, which saves verbiage at the point of use.
The extra per-control fields are still held in structures named after
the control type, so you'll still say ctrl->listbox.height or
whatever. But now those structures are themselves members of an
anonymous union field following the generic fields, so those
sub-structures don't have to reiterate all the standard stuff too.
While I'm here, I've promoted 'context2' from an editbox-specific
field to a generic one (it just seems silly _not_ to allow any control
to have two context fields if it needs it). Also, I had to rename the
boolean field 'tabdelay' to avoid it clashing with the subsidiary
structure field 'tabdelay', now that the former isn't generic.tabdelay
any more.
2022-05-01 08:55:52 +00:00
|
|
|
assert(uc->ctrl->type == CTRL_EDITBOX ||
|
|
|
|
uc->ctrl->type == CTRL_LISTBOX);
|
2003-03-15 15:50:42 +00:00
|
|
|
|
2008-05-31 19:23:45 +00:00
|
|
|
#if !GTK_CHECK_VERSION(2,4,0)
|
2008-04-04 10:56:26 +00:00
|
|
|
if (uc->menu) {
|
2019-09-08 19:29:00 +00:00
|
|
|
gtk_container_foreach(GTK_CONTAINER(uc->menu),
|
|
|
|
container_remove_and_destroy,
|
|
|
|
GTK_CONTAINER(uc->menu));
|
|
|
|
return;
|
2008-05-31 19:23:45 +00:00
|
|
|
}
|
|
|
|
if (uc->list) {
|
2019-09-08 19:29:00 +00:00
|
|
|
gtk_list_clear_items(GTK_LIST(uc->list), 0, -1);
|
|
|
|
return;
|
2008-04-04 10:56:26 +00:00
|
|
|
}
|
|
|
|
#endif
|
2008-05-31 19:23:45 +00:00
|
|
|
#if GTK_CHECK_VERSION(2,0,0)
|
|
|
|
if (uc->listmodel) {
|
2019-09-08 19:29:00 +00:00
|
|
|
gtk_list_store_clear(uc->listmodel);
|
|
|
|
return;
|
2008-05-31 19:23:45 +00:00
|
|
|
}
|
|
|
|
#endif
|
2019-09-09 18:07:55 +00:00
|
|
|
unreachable("bad control type in listbox_clear");
|
2003-03-13 19:52:28 +00:00
|
|
|
}
|
|
|
|
|
2022-05-01 08:48:38 +00:00
|
|
|
void dlg_listbox_del(dlgcontrol *ctrl, dlgparam *dp, int index)
|
2003-03-13 19:52:28 +00:00
|
|
|
{
|
2003-03-15 15:50:42 +00:00
|
|
|
struct uctrl *uc = dlg_find_byctrl(dp, ctrl);
|
|
|
|
|
Restructure dlgcontrol as a struct with an anon union.
This gets rid of that awkward STANDARD_PREFIX system in which every
branch of the old 'union control' had to repeat all the generic
fields, and then call sites had to make an arbitrary decision about
which branch to access them through.
That was the best we could do before accepting C99 features in this
code base. But now we have anonymous unions, so we don't need to put
up with that nonsense any more!
'dlgcontrol' is now a struct rather than a union, and the generic
fields common to all control types are ordinary members of the struct,
so you don't have to refer to them as ctrl->generic.foo at all, just
ctrl->foo, which saves verbiage at the point of use.
The extra per-control fields are still held in structures named after
the control type, so you'll still say ctrl->listbox.height or
whatever. But now those structures are themselves members of an
anonymous union field following the generic fields, so those
sub-structures don't have to reiterate all the standard stuff too.
While I'm here, I've promoted 'context2' from an editbox-specific
field to a generic one (it just seems silly _not_ to allow any control
to have two context fields if it needs it). Also, I had to rename the
boolean field 'tabdelay' to avoid it clashing with the subsidiary
structure field 'tabdelay', now that the former isn't generic.tabdelay
any more.
2022-05-01 08:55:52 +00:00
|
|
|
assert(uc->ctrl->type == CTRL_EDITBOX ||
|
|
|
|
uc->ctrl->type == CTRL_LISTBOX);
|
2003-03-15 15:50:42 +00:00
|
|
|
|
2008-05-31 19:23:45 +00:00
|
|
|
#if !GTK_CHECK_VERSION(2,4,0)
|
2008-04-04 10:56:26 +00:00
|
|
|
if (uc->menu) {
|
Formatting: standardise on "func(\n", not "func\n(".
If the function name (or expression) in a function call or declaration
is itself so long that even the first argument doesn't fit after it on
the same line, or if that would leave so little space that it would be
silly to try to wrap all the run-on lines into a tall thin column,
then I used to do this
ludicrously_long_function_name
(arg1, arg2, arg3);
and now prefer this
ludicrously_long_function_name(
arg1, arg2, arg3);
I picked up the habit from Python, where the latter idiom is required
by Python's syntactic significance of newlines (you can write the
former if you use a backslash-continuation, but pretty much everyone
seems to agree that that's much uglier). But I've found it works well
in C as well: it makes it more obvious that the previous line is
incomplete, it gives you a tiny bit more space to wrap the following
lines into (the old idiom indents the _third_ line one space beyond
the second), and I generally turn out to agree with the knock-on
indentation decisions made by at least Emacs if you do it in the
middle of a complex expression. Plus, of course, using the _same_
idiom between C and Python means less state-switching.
So, while I'm making annoying indentation changes in general, this
seems like a good time to dig out all the cases of the old idiom in
this code, and switch them over to the new.
2022-08-03 19:48:46 +00:00
|
|
|
gtk_container_remove(
|
|
|
|
GTK_CONTAINER(uc->menu),
|
|
|
|
g_list_nth_data(GTK_MENU_SHELL(uc->menu)->children, index));
|
2019-09-08 19:29:00 +00:00
|
|
|
return;
|
2008-05-31 19:23:45 +00:00
|
|
|
}
|
|
|
|
if (uc->list) {
|
2019-09-08 19:29:00 +00:00
|
|
|
gtk_list_clear_items(GTK_LIST(uc->list), index, index+1);
|
|
|
|
return;
|
2008-04-04 10:56:26 +00:00
|
|
|
}
|
2008-05-31 19:23:45 +00:00
|
|
|
#endif
|
|
|
|
#if GTK_CHECK_VERSION(2,0,0)
|
|
|
|
if (uc->listmodel) {
|
2019-09-08 19:29:00 +00:00
|
|
|
GtkTreePath *path;
|
|
|
|
GtkTreeIter iter;
|
|
|
|
assert(uc->listmodel != NULL);
|
|
|
|
path = gtk_tree_path_new_from_indices(index, -1);
|
|
|
|
gtk_tree_model_get_iter(GTK_TREE_MODEL(uc->listmodel), &iter, path);
|
|
|
|
gtk_list_store_remove(uc->listmodel, &iter);
|
|
|
|
gtk_tree_path_free(path);
|
|
|
|
return;
|
2008-04-04 10:56:26 +00:00
|
|
|
}
|
|
|
|
#endif
|
2019-09-09 18:07:55 +00:00
|
|
|
unreachable("bad control type in listbox_del");
|
2003-03-13 19:52:28 +00:00
|
|
|
}
|
|
|
|
|
2022-05-01 08:48:38 +00:00
|
|
|
void dlg_listbox_add(dlgcontrol *ctrl, dlgparam *dp, char const *text)
|
2003-03-13 19:52:28 +00:00
|
|
|
{
|
2018-09-13 11:58:44 +00:00
|
|
|
dlg_listbox_addwithid(ctrl, dp, text, 0);
|
2003-03-13 19:52:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 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.
|
|
|
|
*/
|
2022-05-01 08:48:38 +00:00
|
|
|
void dlg_listbox_addwithid(dlgcontrol *ctrl, dlgparam *dp,
|
2019-09-08 19:29:00 +00:00
|
|
|
char const *text, int id)
|
2003-03-13 19:52:28 +00:00
|
|
|
{
|
2003-03-15 15:50:42 +00:00
|
|
|
struct uctrl *uc = dlg_find_byctrl(dp, ctrl);
|
|
|
|
|
Restructure dlgcontrol as a struct with an anon union.
This gets rid of that awkward STANDARD_PREFIX system in which every
branch of the old 'union control' had to repeat all the generic
fields, and then call sites had to make an arbitrary decision about
which branch to access them through.
That was the best we could do before accepting C99 features in this
code base. But now we have anonymous unions, so we don't need to put
up with that nonsense any more!
'dlgcontrol' is now a struct rather than a union, and the generic
fields common to all control types are ordinary members of the struct,
so you don't have to refer to them as ctrl->generic.foo at all, just
ctrl->foo, which saves verbiage at the point of use.
The extra per-control fields are still held in structures named after
the control type, so you'll still say ctrl->listbox.height or
whatever. But now those structures are themselves members of an
anonymous union field following the generic fields, so those
sub-structures don't have to reiterate all the standard stuff too.
While I'm here, I've promoted 'context2' from an editbox-specific
field to a generic one (it just seems silly _not_ to allow any control
to have two context fields if it needs it). Also, I had to rename the
boolean field 'tabdelay' to avoid it clashing with the subsidiary
structure field 'tabdelay', now that the former isn't generic.tabdelay
any more.
2022-05-01 08:55:52 +00:00
|
|
|
assert(uc->ctrl->type == CTRL_EDITBOX ||
|
|
|
|
uc->ctrl->type == CTRL_LISTBOX);
|
2003-03-15 15:50:42 +00:00
|
|
|
|
2008-04-02 14:48:06 +00:00
|
|
|
/*
|
2008-04-04 10:56:26 +00:00
|
|
|
* This routine is long and complicated in both GTK 1 and 2,
|
|
|
|
* and completely different. Sigh.
|
2008-04-02 14:48:06 +00:00
|
|
|
*/
|
2008-04-04 10:56:26 +00:00
|
|
|
dp->flags |= FLAG_UPDATING_COMBO_LIST;
|
|
|
|
|
2008-05-31 19:23:45 +00:00
|
|
|
#if !GTK_CHECK_VERSION(2,4,0)
|
2008-04-04 10:56:26 +00:00
|
|
|
if (uc->menu) {
|
2019-09-08 19:29:00 +00:00
|
|
|
/*
|
|
|
|
* List item in a drop-down (but non-combo) list. Tabs are
|
|
|
|
* ignored; we just provide a standard menu item with the
|
|
|
|
* text.
|
|
|
|
*/
|
|
|
|
GtkWidget *menuitem = gtk_menu_item_new_with_label(text);
|
2008-04-04 10:56:26 +00:00
|
|
|
|
2019-09-08 19:29:00 +00:00
|
|
|
gtk_container_add(GTK_CONTAINER(uc->menu), menuitem);
|
|
|
|
gtk_widget_show(menuitem);
|
2008-04-04 10:56:26 +00:00
|
|
|
|
2015-08-08 16:29:02 +00:00
|
|
|
g_object_set_data(G_OBJECT(menuitem), "user-data",
|
|
|
|
GINT_TO_POINTER(id));
|
|
|
|
g_signal_connect(G_OBJECT(menuitem), "activate",
|
|
|
|
G_CALLBACK(menuitem_activate), dp);
|
2019-09-08 19:29:00 +00:00
|
|
|
goto done;
|
2008-05-31 19:23:45 +00:00
|
|
|
}
|
|
|
|
if (uc->list && uc->entry) {
|
2019-09-08 19:29:00 +00:00
|
|
|
/*
|
|
|
|
* List item in a combo-box list, which means the sensible
|
|
|
|
* thing to do is make it a perfectly normal label. Hence
|
|
|
|
* tabs are disregarded.
|
|
|
|
*/
|
|
|
|
GtkWidget *listitem = gtk_list_item_new_with_label(text);
|
2008-05-31 19:23:45 +00:00
|
|
|
|
2019-09-08 19:29:00 +00:00
|
|
|
gtk_container_add(GTK_CONTAINER(uc->list), listitem);
|
|
|
|
gtk_widget_show(listitem);
|
2008-05-31 19:23:45 +00:00
|
|
|
|
2015-08-08 16:29:02 +00:00
|
|
|
g_object_set_data(G_OBJECT(listitem), "user-data",
|
|
|
|
GINT_TO_POINTER(id));
|
2019-09-08 19:29:00 +00:00
|
|
|
goto done;
|
2008-05-31 19:23:45 +00:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
#if !GTK_CHECK_VERSION(2,0,0)
|
|
|
|
if (uc->list) {
|
2019-09-08 19:29:00 +00:00
|
|
|
/*
|
|
|
|
* List item in a non-combo-box list box. We make all of
|
|
|
|
* these Columns containing GtkLabels. This allows us to do
|
|
|
|
* the nasty force_left hack irrespective of whether there
|
|
|
|
* are tabs in the thing.
|
|
|
|
*/
|
|
|
|
GtkWidget *listitem = gtk_list_item_new();
|
|
|
|
GtkWidget *cols = columns_new(10);
|
|
|
|
gint *percents;
|
|
|
|
int i, ncols;
|
|
|
|
|
|
|
|
/* Count the tabs in the text, and hence determine # of columns. */
|
|
|
|
ncols = 1;
|
|
|
|
for (i = 0; text[i]; i++)
|
|
|
|
if (text[i] == '\t')
|
|
|
|
ncols++;
|
|
|
|
|
|
|
|
assert(ncols <=
|
|
|
|
(uc->ctrl->listbox.ncols ? uc->ctrl->listbox.ncols : 1));
|
|
|
|
percents = snewn(ncols, gint);
|
|
|
|
percents[ncols-1] = 100;
|
|
|
|
for (i = 0; i < ncols-1; i++) {
|
|
|
|
percents[i] = uc->ctrl->listbox.percentages[i];
|
|
|
|
percents[ncols-1] -= percents[i];
|
|
|
|
}
|
|
|
|
columns_set_cols(COLUMNS(cols), ncols, percents);
|
|
|
|
sfree(percents);
|
|
|
|
|
|
|
|
for (i = 0; i < ncols; i++) {
|
|
|
|
int len = strcspn(text, "\t");
|
|
|
|
char *dup = dupprintf("%.*s", len, text);
|
|
|
|
GtkWidget *label;
|
|
|
|
|
|
|
|
text += len;
|
|
|
|
if (*text) text++;
|
|
|
|
label = gtk_label_new(dup);
|
|
|
|
sfree(dup);
|
|
|
|
|
|
|
|
columns_add(COLUMNS(cols), label, i, 1);
|
|
|
|
columns_force_left_align(COLUMNS(cols), label);
|
|
|
|
gtk_widget_show(label);
|
|
|
|
}
|
|
|
|
gtk_container_add(GTK_CONTAINER(listitem), cols);
|
|
|
|
gtk_widget_show(cols);
|
|
|
|
gtk_container_add(GTK_CONTAINER(uc->list), listitem);
|
|
|
|
gtk_widget_show(listitem);
|
2008-04-04 10:56:26 +00:00
|
|
|
|
|
|
|
if (ctrl->listbox.multisel) {
|
2015-08-08 16:29:02 +00:00
|
|
|
g_signal_connect(G_OBJECT(listitem), "key_press_event",
|
|
|
|
G_CALLBACK(listitem_multi_key), uc->adj);
|
2008-04-04 10:56:26 +00:00
|
|
|
} else {
|
2015-08-08 16:29:02 +00:00
|
|
|
g_signal_connect(G_OBJECT(listitem), "key_press_event",
|
|
|
|
G_CALLBACK(listitem_single_key), uc->adj);
|
2008-04-04 10:56:26 +00:00
|
|
|
}
|
2015-08-08 16:29:02 +00:00
|
|
|
g_signal_connect(G_OBJECT(listitem), "focus_in_event",
|
|
|
|
G_CALLBACK(widget_focus), dp);
|
|
|
|
g_signal_connect(G_OBJECT(listitem), "button_press_event",
|
|
|
|
G_CALLBACK(listitem_button_press), dp);
|
|
|
|
g_signal_connect(G_OBJECT(listitem), "button_release_event",
|
|
|
|
G_CALLBACK(listitem_button_release), dp);
|
|
|
|
g_object_set_data(G_OBJECT(listitem), "user-data",
|
|
|
|
GINT_TO_POINTER(id));
|
2019-09-08 19:29:00 +00:00
|
|
|
goto done;
|
2003-03-15 15:50:42 +00:00
|
|
|
}
|
2008-04-04 10:56:26 +00:00
|
|
|
#else
|
2008-05-31 19:23:45 +00:00
|
|
|
if (uc->listmodel) {
|
2019-09-08 19:29:00 +00:00
|
|
|
GtkTreeIter iter;
|
|
|
|
int i, cols;
|
|
|
|
|
|
|
|
dp->flags |= FLAG_UPDATING_LISTBOX;/* inhibit drag-list update */
|
|
|
|
gtk_list_store_append(uc->listmodel, &iter);
|
|
|
|
dp->flags &= ~FLAG_UPDATING_LISTBOX;
|
|
|
|
gtk_list_store_set(uc->listmodel, &iter, 0, id, -1);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Now go through text and divide it into columns at the tabs,
|
|
|
|
* as necessary.
|
|
|
|
*/
|
Restructure dlgcontrol as a struct with an anon union.
This gets rid of that awkward STANDARD_PREFIX system in which every
branch of the old 'union control' had to repeat all the generic
fields, and then call sites had to make an arbitrary decision about
which branch to access them through.
That was the best we could do before accepting C99 features in this
code base. But now we have anonymous unions, so we don't need to put
up with that nonsense any more!
'dlgcontrol' is now a struct rather than a union, and the generic
fields common to all control types are ordinary members of the struct,
so you don't have to refer to them as ctrl->generic.foo at all, just
ctrl->foo, which saves verbiage at the point of use.
The extra per-control fields are still held in structures named after
the control type, so you'll still say ctrl->listbox.height or
whatever. But now those structures are themselves members of an
anonymous union field following the generic fields, so those
sub-structures don't have to reiterate all the standard stuff too.
While I'm here, I've promoted 'context2' from an editbox-specific
field to a generic one (it just seems silly _not_ to allow any control
to have two context fields if it needs it). Also, I had to rename the
boolean field 'tabdelay' to avoid it clashing with the subsidiary
structure field 'tabdelay', now that the former isn't generic.tabdelay
any more.
2022-05-01 08:55:52 +00:00
|
|
|
cols = (uc->ctrl->type == CTRL_LISTBOX ? ctrl->listbox.ncols : 1);
|
2019-09-08 19:29:00 +00:00
|
|
|
cols = cols ? cols : 1;
|
|
|
|
for (i = 0; i < cols; i++) {
|
|
|
|
int collen = strcspn(text, "\t");
|
2022-09-13 14:00:26 +00:00
|
|
|
char *tmpstr = mkstr(make_ptrlen(text, collen));
|
2019-09-08 19:29:00 +00:00
|
|
|
gtk_list_store_set(uc->listmodel, &iter, i+1, tmpstr, -1);
|
|
|
|
sfree(tmpstr);
|
|
|
|
text += collen;
|
|
|
|
if (*text) text++;
|
|
|
|
}
|
|
|
|
goto done;
|
2008-04-04 10:56:26 +00:00
|
|
|
}
|
|
|
|
#endif
|
2019-09-09 18:07:55 +00:00
|
|
|
unreachable("bad control type in listbox_addwithid");
|
2022-06-23 17:44:07 +00:00
|
|
|
done:
|
2008-05-31 19:23:45 +00:00
|
|
|
dp->flags &= ~FLAG_UPDATING_COMBO_LIST;
|
2003-03-13 19:52:28 +00:00
|
|
|
}
|
|
|
|
|
2022-05-01 08:48:38 +00:00
|
|
|
int dlg_listbox_getid(dlgcontrol *ctrl, dlgparam *dp, int index)
|
2003-03-13 19:52:28 +00:00
|
|
|
{
|
2003-03-15 15:50:42 +00:00
|
|
|
struct uctrl *uc = dlg_find_byctrl(dp, ctrl);
|
|
|
|
|
Restructure dlgcontrol as a struct with an anon union.
This gets rid of that awkward STANDARD_PREFIX system in which every
branch of the old 'union control' had to repeat all the generic
fields, and then call sites had to make an arbitrary decision about
which branch to access them through.
That was the best we could do before accepting C99 features in this
code base. But now we have anonymous unions, so we don't need to put
up with that nonsense any more!
'dlgcontrol' is now a struct rather than a union, and the generic
fields common to all control types are ordinary members of the struct,
so you don't have to refer to them as ctrl->generic.foo at all, just
ctrl->foo, which saves verbiage at the point of use.
The extra per-control fields are still held in structures named after
the control type, so you'll still say ctrl->listbox.height or
whatever. But now those structures are themselves members of an
anonymous union field following the generic fields, so those
sub-structures don't have to reiterate all the standard stuff too.
While I'm here, I've promoted 'context2' from an editbox-specific
field to a generic one (it just seems silly _not_ to allow any control
to have two context fields if it needs it). Also, I had to rename the
boolean field 'tabdelay' to avoid it clashing with the subsidiary
structure field 'tabdelay', now that the former isn't generic.tabdelay
any more.
2022-05-01 08:55:52 +00:00
|
|
|
assert(uc->ctrl->type == CTRL_EDITBOX ||
|
|
|
|
uc->ctrl->type == CTRL_LISTBOX);
|
2003-03-15 15:50:42 +00:00
|
|
|
|
2008-05-31 19:23:45 +00:00
|
|
|
#if !GTK_CHECK_VERSION(2,4,0)
|
|
|
|
if (uc->menu || uc->list) {
|
2019-09-08 19:29:00 +00:00
|
|
|
GList *children;
|
2015-08-08 16:29:02 +00:00
|
|
|
GObject *item;
|
2008-04-04 10:56:26 +00:00
|
|
|
|
2019-09-08 19:29:00 +00:00
|
|
|
children = gtk_container_children(GTK_CONTAINER(uc->menu ? uc->menu :
|
|
|
|
uc->list));
|
2015-08-08 16:29:02 +00:00
|
|
|
item = G_OBJECT(g_list_nth_data(children, index));
|
2019-09-08 19:29:00 +00:00
|
|
|
g_list_free(children);
|
2008-04-04 10:56:26 +00:00
|
|
|
|
2015-08-08 16:29:02 +00:00
|
|
|
return GPOINTER_TO_INT(g_object_get_data(G_OBJECT(item), "user-data"));
|
2008-04-04 10:56:26 +00:00
|
|
|
}
|
2008-05-31 19:23:45 +00:00
|
|
|
#endif
|
|
|
|
#if GTK_CHECK_VERSION(2,0,0)
|
|
|
|
if (uc->listmodel) {
|
2019-09-08 19:29:00 +00:00
|
|
|
GtkTreePath *path;
|
|
|
|
GtkTreeIter iter;
|
|
|
|
int ret;
|
2008-04-04 10:56:26 +00:00
|
|
|
|
2019-09-08 19:29:00 +00:00
|
|
|
path = gtk_tree_path_new_from_indices(index, -1);
|
|
|
|
gtk_tree_model_get_iter(GTK_TREE_MODEL(uc->listmodel), &iter, path);
|
|
|
|
gtk_tree_model_get(GTK_TREE_MODEL(uc->listmodel), &iter, 0, &ret, -1);
|
|
|
|
gtk_tree_path_free(path);
|
2008-04-04 10:56:26 +00:00
|
|
|
|
2019-09-08 19:29:00 +00:00
|
|
|
return ret;
|
2008-04-04 10:56:26 +00:00
|
|
|
}
|
|
|
|
#endif
|
2019-09-09 18:07:55 +00:00
|
|
|
unreachable("bad control type in listbox_getid");
|
2019-09-08 19:29:00 +00:00
|
|
|
return -1; /* placate dataflow analysis */
|
2003-03-13 19:52:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* dlg_listbox_index returns <0 if no single element is selected. */
|
2022-05-01 08:48:38 +00:00
|
|
|
int dlg_listbox_index(dlgcontrol *ctrl, dlgparam *dp)
|
2003-03-13 19:52:28 +00:00
|
|
|
{
|
2003-03-15 15:50:42 +00:00
|
|
|
struct uctrl *uc = dlg_find_byctrl(dp, ctrl);
|
|
|
|
|
Restructure dlgcontrol as a struct with an anon union.
This gets rid of that awkward STANDARD_PREFIX system in which every
branch of the old 'union control' had to repeat all the generic
fields, and then call sites had to make an arbitrary decision about
which branch to access them through.
That was the best we could do before accepting C99 features in this
code base. But now we have anonymous unions, so we don't need to put
up with that nonsense any more!
'dlgcontrol' is now a struct rather than a union, and the generic
fields common to all control types are ordinary members of the struct,
so you don't have to refer to them as ctrl->generic.foo at all, just
ctrl->foo, which saves verbiage at the point of use.
The extra per-control fields are still held in structures named after
the control type, so you'll still say ctrl->listbox.height or
whatever. But now those structures are themselves members of an
anonymous union field following the generic fields, so those
sub-structures don't have to reiterate all the standard stuff too.
While I'm here, I've promoted 'context2' from an editbox-specific
field to a generic one (it just seems silly _not_ to allow any control
to have two context fields if it needs it). Also, I had to rename the
boolean field 'tabdelay' to avoid it clashing with the subsidiary
structure field 'tabdelay', now that the former isn't generic.tabdelay
any more.
2022-05-01 08:55:52 +00:00
|
|
|
assert(uc->ctrl->type == CTRL_EDITBOX ||
|
|
|
|
uc->ctrl->type == CTRL_LISTBOX);
|
2003-03-15 15:50:42 +00:00
|
|
|
|
2008-05-31 19:23:45 +00:00
|
|
|
#if !GTK_CHECK_VERSION(2,4,0)
|
|
|
|
if (uc->menu || uc->list) {
|
2019-09-08 19:29:00 +00:00
|
|
|
GList *children;
|
|
|
|
GtkWidget *item, *activeitem;
|
|
|
|
int i;
|
|
|
|
int selected = -1;
|
|
|
|
|
|
|
|
if (uc->menu)
|
|
|
|
activeitem = gtk_menu_get_active(GTK_MENU(uc->menu));
|
|
|
|
else
|
|
|
|
activeitem = NULL; /* unnecessarily placate gcc */
|
|
|
|
|
|
|
|
children = gtk_container_children(GTK_CONTAINER(uc->menu ? uc->menu :
|
|
|
|
uc->list));
|
|
|
|
for (i = 0; children!=NULL && (item = GTK_WIDGET(children->data))!=NULL;
|
|
|
|
i++, children = children->next) {
|
|
|
|
if (uc->menu ? activeitem == item :
|
|
|
|
GTK_WIDGET_STATE(item) == GTK_STATE_SELECTED) {
|
|
|
|
if (selected == -1)
|
|
|
|
selected = i;
|
|
|
|
else
|
|
|
|
selected = -2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
g_list_free(children);
|
|
|
|
return selected < 0 ? -1 : selected;
|
2008-04-04 10:56:26 +00:00
|
|
|
}
|
|
|
|
#else
|
2008-04-02 14:48:06 +00:00
|
|
|
if (uc->combo) {
|
2019-09-08 19:29:00 +00:00
|
|
|
/*
|
|
|
|
* This API function already does the right thing in the
|
|
|
|
* case of no current selection.
|
|
|
|
*/
|
|
|
|
return gtk_combo_box_get_active(GTK_COMBO_BOX(uc->combo));
|
2008-05-31 19:23:45 +00:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
#if GTK_CHECK_VERSION(2,0,0)
|
|
|
|
if (uc->treeview) {
|
2019-09-08 19:29:00 +00:00
|
|
|
GtkTreeSelection *treesel;
|
|
|
|
GtkTreePath *path;
|
|
|
|
GtkTreeModel *model;
|
|
|
|
GList *sellist;
|
|
|
|
gint *indices;
|
|
|
|
int ret;
|
2008-04-02 14:48:06 +00:00
|
|
|
|
2019-09-08 19:29:00 +00:00
|
|
|
assert(uc->treeview != NULL);
|
|
|
|
treesel = gtk_tree_view_get_selection(GTK_TREE_VIEW(uc->treeview));
|
2008-04-02 14:48:06 +00:00
|
|
|
|
2019-09-08 19:29:00 +00:00
|
|
|
if (gtk_tree_selection_count_selected_rows(treesel) != 1)
|
|
|
|
return -1;
|
2008-04-02 14:48:06 +00:00
|
|
|
|
2019-09-08 19:29:00 +00:00
|
|
|
sellist = gtk_tree_selection_get_selected_rows(treesel, &model);
|
2008-04-02 14:48:06 +00:00
|
|
|
|
2019-09-08 19:29:00 +00:00
|
|
|
assert(sellist && sellist->data);
|
|
|
|
path = sellist->data;
|
2008-04-02 14:48:06 +00:00
|
|
|
|
2019-09-08 19:29:00 +00:00
|
|
|
if (gtk_tree_path_get_depth(path) != 1) {
|
|
|
|
ret = -1;
|
|
|
|
} else {
|
|
|
|
indices = gtk_tree_path_get_indices(path);
|
|
|
|
if (!indices) {
|
|
|
|
ret = -1;
|
|
|
|
} else {
|
|
|
|
ret = indices[0];
|
|
|
|
}
|
|
|
|
}
|
2008-04-02 14:48:06 +00:00
|
|
|
|
2019-09-08 19:29:00 +00:00
|
|
|
g_list_foreach(sellist, (GFunc)gtk_tree_path_free, NULL);
|
|
|
|
g_list_free(sellist);
|
2008-04-02 14:48:06 +00:00
|
|
|
|
2019-09-08 19:29:00 +00:00
|
|
|
return ret;
|
2003-03-15 15:50:42 +00:00
|
|
|
}
|
2008-04-04 10:56:26 +00:00
|
|
|
#endif
|
2019-09-09 18:07:55 +00:00
|
|
|
unreachable("bad control type in listbox_index");
|
2019-09-08 19:29:00 +00:00
|
|
|
return -1; /* placate dataflow analysis */
|
2003-03-13 19:52:28 +00:00
|
|
|
}
|
|
|
|
|
2022-05-01 08:48:38 +00:00
|
|
|
bool dlg_listbox_issel(dlgcontrol *ctrl, dlgparam *dp, int index)
|
2003-03-13 19:52:28 +00:00
|
|
|
{
|
2003-03-15 15:50:42 +00:00
|
|
|
struct uctrl *uc = dlg_find_byctrl(dp, ctrl);
|
|
|
|
|
Restructure dlgcontrol as a struct with an anon union.
This gets rid of that awkward STANDARD_PREFIX system in which every
branch of the old 'union control' had to repeat all the generic
fields, and then call sites had to make an arbitrary decision about
which branch to access them through.
That was the best we could do before accepting C99 features in this
code base. But now we have anonymous unions, so we don't need to put
up with that nonsense any more!
'dlgcontrol' is now a struct rather than a union, and the generic
fields common to all control types are ordinary members of the struct,
so you don't have to refer to them as ctrl->generic.foo at all, just
ctrl->foo, which saves verbiage at the point of use.
The extra per-control fields are still held in structures named after
the control type, so you'll still say ctrl->listbox.height or
whatever. But now those structures are themselves members of an
anonymous union field following the generic fields, so those
sub-structures don't have to reiterate all the standard stuff too.
While I'm here, I've promoted 'context2' from an editbox-specific
field to a generic one (it just seems silly _not_ to allow any control
to have two context fields if it needs it). Also, I had to rename the
boolean field 'tabdelay' to avoid it clashing with the subsidiary
structure field 'tabdelay', now that the former isn't generic.tabdelay
any more.
2022-05-01 08:55:52 +00:00
|
|
|
assert(uc->ctrl->type == CTRL_EDITBOX ||
|
|
|
|
uc->ctrl->type == CTRL_LISTBOX);
|
2003-03-15 15:50:42 +00:00
|
|
|
|
2008-05-31 19:23:45 +00:00
|
|
|
#if !GTK_CHECK_VERSION(2,4,0)
|
|
|
|
if (uc->menu || uc->list) {
|
2019-09-08 19:29:00 +00:00
|
|
|
GList *children;
|
|
|
|
GtkWidget *item, *activeitem;
|
2008-04-04 10:56:26 +00:00
|
|
|
|
Restructure dlgcontrol as a struct with an anon union.
This gets rid of that awkward STANDARD_PREFIX system in which every
branch of the old 'union control' had to repeat all the generic
fields, and then call sites had to make an arbitrary decision about
which branch to access them through.
That was the best we could do before accepting C99 features in this
code base. But now we have anonymous unions, so we don't need to put
up with that nonsense any more!
'dlgcontrol' is now a struct rather than a union, and the generic
fields common to all control types are ordinary members of the struct,
so you don't have to refer to them as ctrl->generic.foo at all, just
ctrl->foo, which saves verbiage at the point of use.
The extra per-control fields are still held in structures named after
the control type, so you'll still say ctrl->listbox.height or
whatever. But now those structures are themselves members of an
anonymous union field following the generic fields, so those
sub-structures don't have to reiterate all the standard stuff too.
While I'm here, I've promoted 'context2' from an editbox-specific
field to a generic one (it just seems silly _not_ to allow any control
to have two context fields if it needs it). Also, I had to rename the
boolean field 'tabdelay' to avoid it clashing with the subsidiary
structure field 'tabdelay', now that the former isn't generic.tabdelay
any more.
2022-05-01 08:55:52 +00:00
|
|
|
assert(uc->ctrl->type == CTRL_EDITBOX ||
|
|
|
|
uc->ctrl->type == CTRL_LISTBOX);
|
2019-09-08 19:29:00 +00:00
|
|
|
assert(uc->menu != NULL || uc->list != NULL);
|
2008-04-04 10:56:26 +00:00
|
|
|
|
2019-09-08 19:29:00 +00:00
|
|
|
children = gtk_container_children(GTK_CONTAINER(uc->menu ? uc->menu :
|
|
|
|
uc->list));
|
|
|
|
item = GTK_WIDGET(g_list_nth_data(children, index));
|
|
|
|
g_list_free(children);
|
2008-04-04 10:56:26 +00:00
|
|
|
|
2019-09-08 19:29:00 +00:00
|
|
|
if (uc->menu) {
|
|
|
|
activeitem = gtk_menu_get_active(GTK_MENU(uc->menu));
|
|
|
|
return item == activeitem;
|
|
|
|
} else {
|
|
|
|
return GTK_WIDGET_STATE(item) == GTK_STATE_SELECTED;
|
|
|
|
}
|
2008-04-04 10:56:26 +00:00
|
|
|
}
|
|
|
|
#else
|
2008-04-02 14:48:06 +00:00
|
|
|
if (uc->combo) {
|
2019-09-08 19:29:00 +00:00
|
|
|
/*
|
|
|
|
* This API function already does the right thing in the
|
|
|
|
* case of no current selection.
|
|
|
|
*/
|
|
|
|
return gtk_combo_box_get_active(GTK_COMBO_BOX(uc->combo)) == index;
|
2008-05-31 19:23:45 +00:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
#if GTK_CHECK_VERSION(2,0,0)
|
|
|
|
if (uc->treeview) {
|
2019-09-08 19:29:00 +00:00
|
|
|
GtkTreeSelection *treesel;
|
|
|
|
GtkTreePath *path;
|
|
|
|
bool ret;
|
2008-04-02 14:48:06 +00:00
|
|
|
|
2019-09-08 19:29:00 +00:00
|
|
|
assert(uc->treeview != NULL);
|
|
|
|
treesel = gtk_tree_view_get_selection(GTK_TREE_VIEW(uc->treeview));
|
2008-04-02 14:48:06 +00:00
|
|
|
|
2019-09-08 19:29:00 +00:00
|
|
|
path = gtk_tree_path_new_from_indices(index, -1);
|
|
|
|
ret = gtk_tree_selection_path_is_selected(treesel, path);
|
|
|
|
gtk_tree_path_free(path);
|
2008-04-02 14:48:06 +00:00
|
|
|
|
2019-09-08 19:29:00 +00:00
|
|
|
return ret;
|
2003-03-15 15:50:42 +00:00
|
|
|
}
|
2008-04-04 10:56:26 +00:00
|
|
|
#endif
|
2019-09-09 18:07:55 +00:00
|
|
|
unreachable("bad control type in listbox_issel");
|
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 false; /* placate dataflow analysis */
|
2003-03-13 19:52:28 +00:00
|
|
|
}
|
|
|
|
|
2022-05-01 08:48:38 +00:00
|
|
|
void dlg_listbox_select(dlgcontrol *ctrl, dlgparam *dp, int index)
|
2003-03-13 19:52:28 +00:00
|
|
|
{
|
2003-03-15 15:50:42 +00:00
|
|
|
struct uctrl *uc = dlg_find_byctrl(dp, ctrl);
|
|
|
|
|
Restructure dlgcontrol as a struct with an anon union.
This gets rid of that awkward STANDARD_PREFIX system in which every
branch of the old 'union control' had to repeat all the generic
fields, and then call sites had to make an arbitrary decision about
which branch to access them through.
That was the best we could do before accepting C99 features in this
code base. But now we have anonymous unions, so we don't need to put
up with that nonsense any more!
'dlgcontrol' is now a struct rather than a union, and the generic
fields common to all control types are ordinary members of the struct,
so you don't have to refer to them as ctrl->generic.foo at all, just
ctrl->foo, which saves verbiage at the point of use.
The extra per-control fields are still held in structures named after
the control type, so you'll still say ctrl->listbox.height or
whatever. But now those structures are themselves members of an
anonymous union field following the generic fields, so those
sub-structures don't have to reiterate all the standard stuff too.
While I'm here, I've promoted 'context2' from an editbox-specific
field to a generic one (it just seems silly _not_ to allow any control
to have two context fields if it needs it). Also, I had to rename the
boolean field 'tabdelay' to avoid it clashing with the subsidiary
structure field 'tabdelay', now that the former isn't generic.tabdelay
any more.
2022-05-01 08:55:52 +00:00
|
|
|
assert(uc->ctrl->type == CTRL_EDITBOX ||
|
|
|
|
uc->ctrl->type == CTRL_LISTBOX);
|
2003-03-15 15:50:42 +00:00
|
|
|
|
2008-05-31 19:23:45 +00:00
|
|
|
#if !GTK_CHECK_VERSION(2,4,0)
|
2008-04-04 10:56:26 +00:00
|
|
|
if (uc->optmenu) {
|
2019-09-08 19:29:00 +00:00
|
|
|
gtk_option_menu_set_history(GTK_OPTION_MENU(uc->optmenu), index);
|
|
|
|
return;
|
|
|
|
}
|
2008-05-31 19:23:45 +00:00
|
|
|
if (uc->list) {
|
2008-04-04 10:56:26 +00:00
|
|
|
int nitems;
|
|
|
|
GList *items;
|
|
|
|
gdouble newtop, newbot;
|
|
|
|
|
2019-09-08 19:29:00 +00:00
|
|
|
gtk_list_select_item(GTK_LIST(uc->list), index);
|
2008-04-04 10:56:26 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Scroll the list box if necessary to ensure the newly
|
|
|
|
* selected item is visible.
|
|
|
|
*/
|
|
|
|
items = gtk_container_children(GTK_CONTAINER(uc->list));
|
|
|
|
nitems = g_list_length(items);
|
|
|
|
if (nitems > 0) {
|
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 modified = false;
|
2008-04-04 10:56:26 +00:00
|
|
|
g_list_free(items);
|
|
|
|
newtop = uc->adj->lower +
|
|
|
|
(uc->adj->upper - uc->adj->lower) * index / nitems;
|
|
|
|
newbot = uc->adj->lower +
|
|
|
|
(uc->adj->upper - uc->adj->lower) * (index+1) / nitems;
|
|
|
|
if (uc->adj->value > newtop) {
|
2018-10-29 19:50:29 +00:00
|
|
|
modified = true;
|
2008-04-04 10:56:26 +00:00
|
|
|
uc->adj->value = newtop;
|
|
|
|
} else if (uc->adj->value < newbot - uc->adj->page_size) {
|
2018-10-29 19:50:29 +00:00
|
|
|
modified = true;
|
2008-04-04 10:56:26 +00:00
|
|
|
uc->adj->value = newbot - uc->adj->page_size;
|
|
|
|
}
|
|
|
|
if (modified)
|
|
|
|
gtk_adjustment_value_changed(uc->adj);
|
|
|
|
}
|
2019-09-08 19:29:00 +00:00
|
|
|
return;
|
2008-04-04 10:56:26 +00:00
|
|
|
}
|
|
|
|
#else
|
2008-04-02 14:48:06 +00:00
|
|
|
if (uc->combo) {
|
2019-09-08 19:29:00 +00:00
|
|
|
gtk_combo_box_set_active(GTK_COMBO_BOX(uc->combo), index);
|
|
|
|
return;
|
2008-05-31 19:23:45 +00:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
#if GTK_CHECK_VERSION(2,0,0)
|
|
|
|
if (uc->treeview) {
|
2019-09-08 19:29:00 +00:00
|
|
|
GtkTreeSelection *treesel;
|
|
|
|
GtkTreePath *path;
|
2005-09-21 17:09:07 +00:00
|
|
|
|
2019-09-08 19:29:00 +00:00
|
|
|
treesel = gtk_tree_view_get_selection(GTK_TREE_VIEW(uc->treeview));
|
2005-09-21 17:09:07 +00:00
|
|
|
|
2019-09-08 19:29:00 +00:00
|
|
|
path = gtk_tree_path_new_from_indices(index, -1);
|
|
|
|
gtk_tree_selection_select_path(treesel, path);
|
|
|
|
gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(uc->treeview),
|
|
|
|
path, NULL, false, 0.0, 0.0);
|
|
|
|
gtk_tree_path_free(path);
|
|
|
|
return;
|
2003-03-15 15:50:42 +00:00
|
|
|
}
|
2008-04-04 10:56:26 +00:00
|
|
|
#endif
|
2019-09-09 18:07:55 +00:00
|
|
|
unreachable("bad control type in listbox_select");
|
2003-03-13 19:52:28 +00:00
|
|
|
}
|
|
|
|
|
2022-05-01 08:48:38 +00:00
|
|
|
void dlg_text_set(dlgcontrol *ctrl, dlgparam *dp, char const *text)
|
2003-03-13 19:52:28 +00:00
|
|
|
{
|
2003-03-15 15:50:42 +00:00
|
|
|
struct uctrl *uc = dlg_find_byctrl(dp, ctrl);
|
|
|
|
|
Restructure dlgcontrol as a struct with an anon union.
This gets rid of that awkward STANDARD_PREFIX system in which every
branch of the old 'union control' had to repeat all the generic
fields, and then call sites had to make an arbitrary decision about
which branch to access them through.
That was the best we could do before accepting C99 features in this
code base. But now we have anonymous unions, so we don't need to put
up with that nonsense any more!
'dlgcontrol' is now a struct rather than a union, and the generic
fields common to all control types are ordinary members of the struct,
so you don't have to refer to them as ctrl->generic.foo at all, just
ctrl->foo, which saves verbiage at the point of use.
The extra per-control fields are still held in structures named after
the control type, so you'll still say ctrl->listbox.height or
whatever. But now those structures are themselves members of an
anonymous union field following the generic fields, so those
sub-structures don't have to reiterate all the standard stuff too.
While I'm here, I've promoted 'context2' from an editbox-specific
field to a generic one (it just seems silly _not_ to allow any control
to have two context fields if it needs it). Also, I had to rename the
boolean field 'tabdelay' to avoid it clashing with the subsidiary
structure field 'tabdelay', now that the former isn't generic.tabdelay
any more.
2022-05-01 08:55:52 +00:00
|
|
|
assert(uc->ctrl->type == CTRL_TEXT);
|
2003-03-15 15:50:42 +00:00
|
|
|
assert(uc->text != NULL);
|
|
|
|
|
|
|
|
gtk_label_set_text(GTK_LABEL(uc->text), text);
|
2003-03-13 19:52:28 +00:00
|
|
|
}
|
|
|
|
|
2022-05-01 08:48:38 +00:00
|
|
|
void dlg_label_change(dlgcontrol *ctrl, dlgparam *dp, char const *text)
|
2006-08-28 10:35:12 +00:00
|
|
|
{
|
2006-08-28 14:29:02 +00:00
|
|
|
struct uctrl *uc = dlg_find_byctrl(dp, ctrl);
|
|
|
|
|
Restructure dlgcontrol as a struct with an anon union.
This gets rid of that awkward STANDARD_PREFIX system in which every
branch of the old 'union control' had to repeat all the generic
fields, and then call sites had to make an arbitrary decision about
which branch to access them through.
That was the best we could do before accepting C99 features in this
code base. But now we have anonymous unions, so we don't need to put
up with that nonsense any more!
'dlgcontrol' is now a struct rather than a union, and the generic
fields common to all control types are ordinary members of the struct,
so you don't have to refer to them as ctrl->generic.foo at all, just
ctrl->foo, which saves verbiage at the point of use.
The extra per-control fields are still held in structures named after
the control type, so you'll still say ctrl->listbox.height or
whatever. But now those structures are themselves members of an
anonymous union field following the generic fields, so those
sub-structures don't have to reiterate all the standard stuff too.
While I'm here, I've promoted 'context2' from an editbox-specific
field to a generic one (it just seems silly _not_ to allow any control
to have two context fields if it needs it). Also, I had to rename the
boolean field 'tabdelay' to avoid it clashing with the subsidiary
structure field 'tabdelay', now that the former isn't generic.tabdelay
any more.
2022-05-01 08:55:52 +00:00
|
|
|
switch (uc->ctrl->type) {
|
2006-08-28 14:29:02 +00:00
|
|
|
case CTRL_BUTTON:
|
2019-09-08 19:29:00 +00:00
|
|
|
gtk_label_set_text(GTK_LABEL(uc->toplevel), text);
|
|
|
|
shortcut_highlight(uc->toplevel, ctrl->button.shortcut);
|
|
|
|
break;
|
2006-08-28 14:29:02 +00:00
|
|
|
case CTRL_CHECKBOX:
|
2019-09-08 19:29:00 +00:00
|
|
|
gtk_label_set_text(GTK_LABEL(uc->toplevel), text);
|
|
|
|
shortcut_highlight(uc->toplevel, ctrl->checkbox.shortcut);
|
|
|
|
break;
|
2006-08-28 14:29:02 +00:00
|
|
|
case CTRL_RADIO:
|
2019-09-08 19:29:00 +00:00
|
|
|
gtk_label_set_text(GTK_LABEL(uc->label), text);
|
|
|
|
shortcut_highlight(uc->label, ctrl->radio.shortcut);
|
|
|
|
break;
|
2006-08-28 14:29:02 +00:00
|
|
|
case CTRL_EDITBOX:
|
2019-09-08 19:29:00 +00:00
|
|
|
gtk_label_set_text(GTK_LABEL(uc->label), text);
|
|
|
|
shortcut_highlight(uc->label, ctrl->editbox.shortcut);
|
|
|
|
break;
|
2006-08-28 14:29:02 +00:00
|
|
|
case CTRL_FILESELECT:
|
2022-05-01 07:39:49 +00:00
|
|
|
if (uc->label) {
|
|
|
|
gtk_label_set_text(GTK_LABEL(uc->label), text);
|
|
|
|
shortcut_highlight(uc->label, ctrl->fileselect.shortcut);
|
|
|
|
}
|
2019-09-08 19:29:00 +00:00
|
|
|
break;
|
2006-08-28 14:29:02 +00:00
|
|
|
case CTRL_FONTSELECT:
|
2019-09-08 19:29:00 +00:00
|
|
|
gtk_label_set_text(GTK_LABEL(uc->label), text);
|
|
|
|
shortcut_highlight(uc->label, ctrl->fontselect.shortcut);
|
|
|
|
break;
|
2006-08-28 14:29:02 +00:00
|
|
|
case CTRL_LISTBOX:
|
2019-09-08 19:29:00 +00:00
|
|
|
gtk_label_set_text(GTK_LABEL(uc->label), text);
|
|
|
|
shortcut_highlight(uc->label, ctrl->listbox.shortcut);
|
|
|
|
break;
|
2006-08-28 14:29:02 +00:00
|
|
|
default:
|
2019-09-09 18:07:55 +00:00
|
|
|
unreachable("bad control type in label_change");
|
2006-08-28 14:29:02 +00:00
|
|
|
}
|
2006-08-28 10:35:12 +00:00
|
|
|
}
|
|
|
|
|
2022-05-01 08:48:38 +00:00
|
|
|
void dlg_filesel_set(dlgcontrol *ctrl, dlgparam *dp, Filename *fn)
|
2003-03-13 19:52:28 +00:00
|
|
|
{
|
2003-03-15 15:50:42 +00:00
|
|
|
struct uctrl *uc = dlg_find_byctrl(dp, ctrl);
|
2012-04-13 18:02:30 +00:00
|
|
|
/* We must copy fn->path before passing it to gtk_entry_set_text.
|
|
|
|
* See comment in dlg_editbox_set() for the reasons. */
|
|
|
|
char *duppath = dupstr(fn->path);
|
Restructure dlgcontrol as a struct with an anon union.
This gets rid of that awkward STANDARD_PREFIX system in which every
branch of the old 'union control' had to repeat all the generic
fields, and then call sites had to make an arbitrary decision about
which branch to access them through.
That was the best we could do before accepting C99 features in this
code base. But now we have anonymous unions, so we don't need to put
up with that nonsense any more!
'dlgcontrol' is now a struct rather than a union, and the generic
fields common to all control types are ordinary members of the struct,
so you don't have to refer to them as ctrl->generic.foo at all, just
ctrl->foo, which saves verbiage at the point of use.
The extra per-control fields are still held in structures named after
the control type, so you'll still say ctrl->listbox.height or
whatever. But now those structures are themselves members of an
anonymous union field following the generic fields, so those
sub-structures don't have to reiterate all the standard stuff too.
While I'm here, I've promoted 'context2' from an editbox-specific
field to a generic one (it just seems silly _not_ to allow any control
to have two context fields if it needs it). Also, I had to rename the
boolean field 'tabdelay' to avoid it clashing with the subsidiary
structure field 'tabdelay', now that the former isn't generic.tabdelay
any more.
2022-05-01 08:55:52 +00:00
|
|
|
assert(uc->ctrl->type == CTRL_FILESELECT);
|
2003-03-15 15:50:42 +00:00
|
|
|
assert(uc->entry != NULL);
|
2012-04-13 18:02:30 +00:00
|
|
|
gtk_entry_set_text(GTK_ENTRY(uc->entry), duppath);
|
|
|
|
sfree(duppath);
|
2003-03-13 19:52:28 +00:00
|
|
|
}
|
|
|
|
|
2022-05-01 08:48:38 +00:00
|
|
|
Filename *dlg_filesel_get(dlgcontrol *ctrl, dlgparam *dp)
|
2003-03-13 19:52:28 +00:00
|
|
|
{
|
2003-03-15 15:50:42 +00:00
|
|
|
struct uctrl *uc = dlg_find_byctrl(dp, ctrl);
|
Restructure dlgcontrol as a struct with an anon union.
This gets rid of that awkward STANDARD_PREFIX system in which every
branch of the old 'union control' had to repeat all the generic
fields, and then call sites had to make an arbitrary decision about
which branch to access them through.
That was the best we could do before accepting C99 features in this
code base. But now we have anonymous unions, so we don't need to put
up with that nonsense any more!
'dlgcontrol' is now a struct rather than a union, and the generic
fields common to all control types are ordinary members of the struct,
so you don't have to refer to them as ctrl->generic.foo at all, just
ctrl->foo, which saves verbiage at the point of use.
The extra per-control fields are still held in structures named after
the control type, so you'll still say ctrl->listbox.height or
whatever. But now those structures are themselves members of an
anonymous union field following the generic fields, so those
sub-structures don't have to reiterate all the standard stuff too.
While I'm here, I've promoted 'context2' from an editbox-specific
field to a generic one (it just seems silly _not_ to allow any control
to have two context fields if it needs it). Also, I had to rename the
boolean field 'tabdelay' to avoid it clashing with the subsidiary
structure field 'tabdelay', now that the former isn't generic.tabdelay
any more.
2022-05-01 08:55:52 +00:00
|
|
|
assert(uc->ctrl->type == CTRL_FILESELECT);
|
2022-05-01 07:39:49 +00:00
|
|
|
if (!uc->entry) {
|
|
|
|
assert(uc->textvalue);
|
|
|
|
return filename_from_str(uc->textvalue);
|
|
|
|
} else {
|
|
|
|
return filename_from_str(gtk_entry_get_text(GTK_ENTRY(uc->entry)));
|
|
|
|
}
|
2003-03-13 19:52:28 +00:00
|
|
|
}
|
|
|
|
|
2022-05-01 08:48:38 +00:00
|
|
|
void dlg_fontsel_set(dlgcontrol *ctrl, dlgparam *dp, FontSpec *fs)
|
2003-03-13 19:52:28 +00:00
|
|
|
{
|
2003-03-15 15:50:42 +00:00
|
|
|
struct uctrl *uc = dlg_find_byctrl(dp, ctrl);
|
2012-04-13 18:02:30 +00:00
|
|
|
/* We must copy fs->name before passing it to gtk_entry_set_text.
|
|
|
|
* See comment in dlg_editbox_set() for the reasons. */
|
|
|
|
char *dupname = dupstr(fs->name);
|
Restructure dlgcontrol as a struct with an anon union.
This gets rid of that awkward STANDARD_PREFIX system in which every
branch of the old 'union control' had to repeat all the generic
fields, and then call sites had to make an arbitrary decision about
which branch to access them through.
That was the best we could do before accepting C99 features in this
code base. But now we have anonymous unions, so we don't need to put
up with that nonsense any more!
'dlgcontrol' is now a struct rather than a union, and the generic
fields common to all control types are ordinary members of the struct,
so you don't have to refer to them as ctrl->generic.foo at all, just
ctrl->foo, which saves verbiage at the point of use.
The extra per-control fields are still held in structures named after
the control type, so you'll still say ctrl->listbox.height or
whatever. But now those structures are themselves members of an
anonymous union field following the generic fields, so those
sub-structures don't have to reiterate all the standard stuff too.
While I'm here, I've promoted 'context2' from an editbox-specific
field to a generic one (it just seems silly _not_ to allow any control
to have two context fields if it needs it). Also, I had to rename the
boolean field 'tabdelay' to avoid it clashing with the subsidiary
structure field 'tabdelay', now that the former isn't generic.tabdelay
any more.
2022-05-01 08:55:52 +00:00
|
|
|
assert(uc->ctrl->type == CTRL_FONTSELECT);
|
2003-03-15 15:50:42 +00:00
|
|
|
assert(uc->entry != NULL);
|
2012-04-13 18:02:30 +00:00
|
|
|
gtk_entry_set_text(GTK_ENTRY(uc->entry), dupname);
|
|
|
|
sfree(dupname);
|
2003-03-13 19:52:28 +00:00
|
|
|
}
|
|
|
|
|
2022-05-01 08:48:38 +00:00
|
|
|
FontSpec *dlg_fontsel_get(dlgcontrol *ctrl, dlgparam *dp)
|
2003-03-13 19:52:28 +00:00
|
|
|
{
|
2003-03-15 15:50:42 +00:00
|
|
|
struct uctrl *uc = dlg_find_byctrl(dp, ctrl);
|
Restructure dlgcontrol as a struct with an anon union.
This gets rid of that awkward STANDARD_PREFIX system in which every
branch of the old 'union control' had to repeat all the generic
fields, and then call sites had to make an arbitrary decision about
which branch to access them through.
That was the best we could do before accepting C99 features in this
code base. But now we have anonymous unions, so we don't need to put
up with that nonsense any more!
'dlgcontrol' is now a struct rather than a union, and the generic
fields common to all control types are ordinary members of the struct,
so you don't have to refer to them as ctrl->generic.foo at all, just
ctrl->foo, which saves verbiage at the point of use.
The extra per-control fields are still held in structures named after
the control type, so you'll still say ctrl->listbox.height or
whatever. But now those structures are themselves members of an
anonymous union field following the generic fields, so those
sub-structures don't have to reiterate all the standard stuff too.
While I'm here, I've promoted 'context2' from an editbox-specific
field to a generic one (it just seems silly _not_ to allow any control
to have two context fields if it needs it). Also, I had to rename the
boolean field 'tabdelay' to avoid it clashing with the subsidiary
structure field 'tabdelay', now that the former isn't generic.tabdelay
any more.
2022-05-01 08:55:52 +00:00
|
|
|
assert(uc->ctrl->type == CTRL_FONTSELECT);
|
2003-03-15 15:50:42 +00:00
|
|
|
assert(uc->entry != NULL);
|
2011-10-01 17:38:59 +00:00
|
|
|
return fontspec_new(gtk_entry_get_text(GTK_ENTRY(uc->entry)));
|
2003-03-13 19:52:28 +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.
|
|
|
|
*/
|
2022-05-01 08:48:38 +00:00
|
|
|
void dlg_update_start(dlgcontrol *ctrl, dlgparam *dp)
|
2003-03-13 19:52:28 +00:00
|
|
|
{
|
2003-03-15 15:50:42 +00:00
|
|
|
/*
|
|
|
|
* Apparently we can't do this at all in GTK. GtkCList supports
|
|
|
|
* freeze and thaw, but not GtkList. Bah.
|
|
|
|
*/
|
2003-03-13 19:52:28 +00:00
|
|
|
}
|
|
|
|
|
2022-05-01 08:48:38 +00:00
|
|
|
void dlg_update_done(dlgcontrol *ctrl, dlgparam *dp)
|
2003-03-13 19:52:28 +00:00
|
|
|
{
|
2003-03-15 15:50:42 +00:00
|
|
|
/*
|
|
|
|
* Apparently we can't do this at all in GTK. GtkCList supports
|
|
|
|
* freeze and thaw, but not GtkList. Bah.
|
|
|
|
*/
|
2003-03-13 19:52:28 +00:00
|
|
|
}
|
|
|
|
|
2022-05-01 08:48:38 +00:00
|
|
|
void dlg_set_focus(dlgcontrol *ctrl, dlgparam *dp)
|
2003-03-13 19:52:28 +00:00
|
|
|
{
|
2003-03-18 19:06:51 +00:00
|
|
|
struct uctrl *uc = dlg_find_byctrl(dp, ctrl);
|
|
|
|
|
Restructure dlgcontrol as a struct with an anon union.
This gets rid of that awkward STANDARD_PREFIX system in which every
branch of the old 'union control' had to repeat all the generic
fields, and then call sites had to make an arbitrary decision about
which branch to access them through.
That was the best we could do before accepting C99 features in this
code base. But now we have anonymous unions, so we don't need to put
up with that nonsense any more!
'dlgcontrol' is now a struct rather than a union, and the generic
fields common to all control types are ordinary members of the struct,
so you don't have to refer to them as ctrl->generic.foo at all, just
ctrl->foo, which saves verbiage at the point of use.
The extra per-control fields are still held in structures named after
the control type, so you'll still say ctrl->listbox.height or
whatever. But now those structures are themselves members of an
anonymous union field following the generic fields, so those
sub-structures don't have to reiterate all the standard stuff too.
While I'm here, I've promoted 'context2' from an editbox-specific
field to a generic one (it just seems silly _not_ to allow any control
to have two context fields if it needs it). Also, I had to rename the
boolean field 'tabdelay' to avoid it clashing with the subsidiary
structure field 'tabdelay', now that the former isn't generic.tabdelay
any more.
2022-05-01 08:55:52 +00:00
|
|
|
switch (ctrl->type) {
|
2003-03-18 19:06:51 +00:00
|
|
|
case CTRL_CHECKBOX:
|
|
|
|
case CTRL_BUTTON:
|
|
|
|
/* Check boxes and buttons get the focus _and_ get toggled. */
|
|
|
|
gtk_widget_grab_focus(uc->toplevel);
|
|
|
|
break;
|
|
|
|
case CTRL_FILESELECT:
|
|
|
|
case CTRL_FONTSELECT:
|
|
|
|
case CTRL_EDITBOX:
|
2019-09-08 19:29:00 +00:00
|
|
|
if (uc->entry) {
|
|
|
|
/* Anything containing an edit box gets that focused. */
|
|
|
|
gtk_widget_grab_focus(uc->entry);
|
|
|
|
}
|
2008-05-31 19:23:45 +00:00
|
|
|
#if GTK_CHECK_VERSION(2,4,0)
|
2019-09-08 19:29:00 +00:00
|
|
|
else if (uc->combo) {
|
|
|
|
/* Failing that, there'll be a combo box. */
|
|
|
|
gtk_widget_grab_focus(uc->combo);
|
|
|
|
}
|
2008-04-04 10:56:26 +00:00
|
|
|
#endif
|
2003-03-18 19:06:51 +00:00
|
|
|
break;
|
|
|
|
case CTRL_RADIO:
|
|
|
|
/*
|
|
|
|
* Radio buttons: we find the currently selected button and
|
|
|
|
* focus it.
|
|
|
|
*/
|
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 (int i = 0; i < ctrl->radio.nbuttons; i++)
|
Formatting: standardise on "func(\n", not "func\n(".
If the function name (or expression) in a function call or declaration
is itself so long that even the first argument doesn't fit after it on
the same line, or if that would leave so little space that it would be
silly to try to wrap all the run-on lines into a tall thin column,
then I used to do this
ludicrously_long_function_name
(arg1, arg2, arg3);
and now prefer this
ludicrously_long_function_name(
arg1, arg2, arg3);
I picked up the habit from Python, where the latter idiom is required
by Python's syntactic significance of newlines (you can write the
former if you use a backslash-continuation, but pretty much everyone
seems to agree that that's much uglier). But I've found it works well
in C as well: it makes it more obvious that the previous line is
incomplete, it gives you a tiny bit more space to wrap the following
lines into (the old idiom indents the _third_ line one space beyond
the second), and I generally turn out to agree with the knock-on
indentation decisions made by at least Emacs if you do it in the
middle of a complex expression. Plus, of course, using the _same_
idiom between C and Python means less state-switching.
So, while I'm making annoying indentation changes in general, this
seems like a good time to dig out all the cases of the old idiom in
this code, and switch them over to the new.
2022-08-03 19:48:46 +00:00
|
|
|
if (gtk_toggle_button_get_active(
|
|
|
|
GTK_TOGGLE_BUTTON(uc->buttons[i]))) {
|
2022-06-23 17:44:07 +00:00
|
|
|
gtk_widget_grab_focus(uc->buttons[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
|
|
|
}
|
2003-03-18 19:06:51 +00:00
|
|
|
break;
|
|
|
|
case CTRL_LISTBOX:
|
2008-05-31 19:23:45 +00:00
|
|
|
#if !GTK_CHECK_VERSION(2,4,0)
|
2008-04-04 10:56:26 +00:00
|
|
|
if (uc->optmenu) {
|
|
|
|
gtk_widget_grab_focus(uc->optmenu);
|
2019-09-08 19:29:00 +00:00
|
|
|
break;
|
2008-05-31 19:23:45 +00:00
|
|
|
}
|
|
|
|
#else
|
2019-09-08 19:29:00 +00:00
|
|
|
if (uc->combo) {
|
|
|
|
gtk_widget_grab_focus(uc->combo);
|
|
|
|
break;
|
|
|
|
}
|
2008-05-31 19:23:45 +00:00
|
|
|
#endif
|
|
|
|
#if !GTK_CHECK_VERSION(2,0,0)
|
2019-09-08 19:29:00 +00:00
|
|
|
if (uc->list) {
|
|
|
|
/*
|
|
|
|
* For GTK-1 style list boxes, we tell it to focus one
|
|
|
|
* of its children, which appears to do the Right
|
|
|
|
* Thing.
|
|
|
|
*/
|
2008-04-04 10:56:26 +00:00
|
|
|
gtk_container_focus(GTK_CONTAINER(uc->list), GTK_DIR_TAB_FORWARD);
|
2019-09-08 19:29:00 +00:00
|
|
|
break;
|
|
|
|
}
|
2008-04-04 10:56:26 +00:00
|
|
|
#else
|
2019-09-08 19:29:00 +00:00
|
|
|
if (uc->treeview) {
|
|
|
|
gtk_widget_grab_focus(uc->treeview);
|
|
|
|
break;
|
|
|
|
}
|
2008-04-04 10:56:26 +00:00
|
|
|
#endif
|
2019-09-09 18:07:55 +00:00
|
|
|
unreachable("bad control type in set_focus");
|
2003-03-18 19:06:51 +00:00
|
|
|
}
|
2003-03-13 19:52:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 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-13 19:52:28 +00:00
|
|
|
{
|
2018-03-03 18:20:04 +00:00
|
|
|
gdk_display_beep(gdk_display_get_default());
|
2003-03-13 19:52:28 +00:00
|
|
|
}
|
|
|
|
|
2003-04-10 08:53:43 +00:00
|
|
|
static void set_transient_window_pos(GtkWidget *parent, GtkWidget *child)
|
|
|
|
{
|
2015-08-08 17:02:01 +00:00
|
|
|
#if !GTK_CHECK_VERSION(2,0,0)
|
2003-04-10 08:53:43 +00:00
|
|
|
gint x, y, w, h, dx, dy;
|
|
|
|
GtkRequisition req;
|
|
|
|
gtk_window_set_position(GTK_WINDOW(child), GTK_WIN_POS_NONE);
|
|
|
|
gtk_widget_size_request(GTK_WIDGET(child), &req);
|
|
|
|
|
2015-08-08 14:53:43 +00:00
|
|
|
gdk_window_get_origin(gtk_widget_get_window(GTK_WIDGET(parent)), &x, &y);
|
|
|
|
gdk_window_get_size(gtk_widget_get_window(GTK_WIDGET(parent)), &w, &h);
|
2003-04-10 08:53:43 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* One corner of the transient will be offset inwards, by 1/4
|
|
|
|
* of the parent window's size, from the corresponding corner
|
|
|
|
* of the parent window. The corner will be chosen so as to
|
|
|
|
* place the transient closer to the centre of the screen; this
|
|
|
|
* should avoid transients going off the edge of the screen on
|
|
|
|
* a regular basis.
|
|
|
|
*/
|
|
|
|
if (x + w/2 < gdk_screen_width() / 2)
|
|
|
|
dx = x + w/4; /* work from left edges */
|
|
|
|
else
|
|
|
|
dx = x + 3*w/4 - req.width; /* work from right edges */
|
|
|
|
if (y + h/2 < gdk_screen_height() / 2)
|
|
|
|
dy = y + h/4; /* work from top edges */
|
|
|
|
else
|
|
|
|
dy = y + 3*h/4 - req.height; /* work from bottom edges */
|
|
|
|
gtk_widget_set_uposition(GTK_WIDGET(child), dx, dy);
|
2015-08-08 17:02:01 +00:00
|
|
|
#endif
|
2003-04-10 08:53:43 +00:00
|
|
|
}
|
|
|
|
|
2017-11-26 17:07:47 +00:00
|
|
|
void trivial_post_dialog_fn(void *vctx, int result)
|
2017-11-26 17:05:51 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2018-09-13 11:58:44 +00:00
|
|
|
void dlg_error_msg(dlgparam *dp, const char *msg)
|
2003-03-13 19:52:28 +00:00
|
|
|
{
|
2017-11-26 17:05:51 +00:00
|
|
|
create_message_box(
|
|
|
|
dp->window, "Error", msg,
|
|
|
|
string_width("Some sort of text about a config-box error message"),
|
2018-10-29 19:50:29 +00:00
|
|
|
false, &buttons_ok, trivial_post_dialog_fn, NULL);
|
2003-03-13 19:52:28 +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-13 19:52:28 +00:00
|
|
|
{
|
2003-03-18 19:06:51 +00:00
|
|
|
dp->retval = value;
|
2003-03-29 19:52:50 +00:00
|
|
|
gtk_widget_destroy(dp->window);
|
2003-03-13 19:52:28 +00:00
|
|
|
}
|
|
|
|
|
2022-05-01 08:48:38 +00:00
|
|
|
void dlg_refresh(dlgcontrol *ctrl, dlgparam *dp)
|
2003-03-13 19:52:28 +00:00
|
|
|
{
|
2003-03-15 15:50:42 +00:00
|
|
|
struct uctrl *uc;
|
|
|
|
|
|
|
|
if (ctrl) {
|
Restructure dlgcontrol as a struct with an anon union.
This gets rid of that awkward STANDARD_PREFIX system in which every
branch of the old 'union control' had to repeat all the generic
fields, and then call sites had to make an arbitrary decision about
which branch to access them through.
That was the best we could do before accepting C99 features in this
code base. But now we have anonymous unions, so we don't need to put
up with that nonsense any more!
'dlgcontrol' is now a struct rather than a union, and the generic
fields common to all control types are ordinary members of the struct,
so you don't have to refer to them as ctrl->generic.foo at all, just
ctrl->foo, which saves verbiage at the point of use.
The extra per-control fields are still held in structures named after
the control type, so you'll still say ctrl->listbox.height or
whatever. But now those structures are themselves members of an
anonymous union field following the generic fields, so those
sub-structures don't have to reiterate all the standard stuff too.
While I'm here, I've promoted 'context2' from an editbox-specific
field to a generic one (it just seems silly _not_ to allow any control
to have two context fields if it needs it). Also, I had to rename the
boolean field 'tabdelay' to avoid it clashing with the subsidiary
structure field 'tabdelay', now that the former isn't generic.tabdelay
any more.
2022-05-01 08:55:52 +00:00
|
|
|
if (ctrl->handler != NULL)
|
|
|
|
ctrl->handler(ctrl, dp, dp->data, EVENT_REFRESH);
|
2003-03-15 15:50:42 +00:00
|
|
|
} else {
|
2019-09-08 19:29:00 +00:00
|
|
|
int i;
|
2003-03-15 15:50:42 +00:00
|
|
|
|
2019-09-08 19:29:00 +00:00
|
|
|
for (i = 0; (uc = index234(dp->byctrl, i)) != NULL; i++) {
|
|
|
|
assert(uc->ctrl != NULL);
|
Restructure dlgcontrol as a struct with an anon union.
This gets rid of that awkward STANDARD_PREFIX system in which every
branch of the old 'union control' had to repeat all the generic
fields, and then call sites had to make an arbitrary decision about
which branch to access them through.
That was the best we could do before accepting C99 features in this
code base. But now we have anonymous unions, so we don't need to put
up with that nonsense any more!
'dlgcontrol' is now a struct rather than a union, and the generic
fields common to all control types are ordinary members of the struct,
so you don't have to refer to them as ctrl->generic.foo at all, just
ctrl->foo, which saves verbiage at the point of use.
The extra per-control fields are still held in structures named after
the control type, so you'll still say ctrl->listbox.height or
whatever. But now those structures are themselves members of an
anonymous union field following the generic fields, so those
sub-structures don't have to reiterate all the standard stuff too.
While I'm here, I've promoted 'context2' from an editbox-specific
field to a generic one (it just seems silly _not_ to allow any control
to have two context fields if it needs it). Also, I had to rename the
boolean field 'tabdelay' to avoid it clashing with the subsidiary
structure field 'tabdelay', now that the former isn't generic.tabdelay
any more.
2022-05-01 08:55:52 +00:00
|
|
|
if (uc->ctrl->handler != NULL)
|
|
|
|
uc->ctrl->handler(uc->ctrl, dp,
|
2022-06-23 17:44:07 +00:00
|
|
|
dp->data, EVENT_REFRESH);
|
2019-09-08 19:29:00 +00:00
|
|
|
}
|
2003-03-15 15:50:42 +00:00
|
|
|
}
|
2003-03-13 19:52:28 +00:00
|
|
|
}
|
|
|
|
|
2022-05-01 08:48:38 +00:00
|
|
|
void dlg_coloursel_start(dlgcontrol *ctrl, dlgparam *dp, int r, int g, int b)
|
2003-03-13 19:52:28 +00:00
|
|
|
{
|
2003-03-15 15:50:42 +00:00
|
|
|
struct uctrl *uc = dlg_find_byctrl(dp, ctrl);
|
|
|
|
|
2015-08-22 13:49:02 +00:00
|
|
|
#if GTK_CHECK_VERSION(3,0,0)
|
|
|
|
GtkWidget *coloursel =
|
2019-09-08 19:29:00 +00:00
|
|
|
gtk_color_chooser_dialog_new("Select a colour",
|
2015-08-22 13:49:02 +00:00
|
|
|
GTK_WINDOW(dp->window));
|
2018-10-29 19:50:29 +00:00
|
|
|
gtk_color_chooser_set_use_alpha(GTK_COLOR_CHOOSER(coloursel), false);
|
2015-08-22 13:49:02 +00:00
|
|
|
#else
|
|
|
|
GtkWidget *okbutton, *cancelbutton;
|
2003-03-15 15:50:42 +00:00
|
|
|
GtkWidget *coloursel =
|
2019-09-08 19:29:00 +00:00
|
|
|
gtk_color_selection_dialog_new("Select a colour");
|
2003-03-15 15:50:42 +00:00
|
|
|
GtkColorSelectionDialog *ccs = GTK_COLOR_SELECTION_DIALOG(coloursel);
|
Formatting: standardise on "func(\n", not "func\n(".
If the function name (or expression) in a function call or declaration
is itself so long that even the first argument doesn't fit after it on
the same line, or if that would leave so little space that it would be
silly to try to wrap all the run-on lines into a tall thin column,
then I used to do this
ludicrously_long_function_name
(arg1, arg2, arg3);
and now prefer this
ludicrously_long_function_name(
arg1, arg2, arg3);
I picked up the habit from Python, where the latter idiom is required
by Python's syntactic significance of newlines (you can write the
former if you use a backslash-continuation, but pretty much everyone
seems to agree that that's much uglier). But I've found it works well
in C as well: it makes it more obvious that the previous line is
incomplete, it gives you a tiny bit more space to wrap the following
lines into (the old idiom indents the _third_ line one space beyond
the second), and I generally turn out to agree with the knock-on
indentation decisions made by at least Emacs if you do it in the
middle of a complex expression. Plus, of course, using the _same_
idiom between C and Python means less state-switching.
So, while I'm making annoying indentation changes in general, this
seems like a good time to dig out all the cases of the old idiom in
this code, and switch them over to the new.
2022-08-03 19:48:46 +00:00
|
|
|
GtkColorSelection *cs = GTK_COLOR_SELECTION(
|
|
|
|
gtk_color_selection_dialog_get_color_selection(ccs));
|
2018-10-29 19:50:29 +00:00
|
|
|
gtk_color_selection_set_has_opacity_control(cs, false);
|
2015-08-22 13:49:02 +00:00
|
|
|
#endif
|
2003-03-15 15:50:42 +00:00
|
|
|
|
2018-10-29 19:50:29 +00:00
|
|
|
dp->coloursel_result.ok = false;
|
2003-03-15 15:50:42 +00:00
|
|
|
|
2018-10-29 19:50:29 +00:00
|
|
|
gtk_window_set_modal(GTK_WINDOW(coloursel), true);
|
2015-08-08 16:32:15 +00:00
|
|
|
|
2015-08-22 13:49:02 +00:00
|
|
|
#if GTK_CHECK_VERSION(3,0,0)
|
|
|
|
{
|
|
|
|
GdkRGBA rgba;
|
|
|
|
rgba.red = r / 255.0;
|
|
|
|
rgba.green = g / 255.0;
|
|
|
|
rgba.blue = b / 255.0;
|
|
|
|
rgba.alpha = 1.0; /* fully opaque! */
|
|
|
|
gtk_color_chooser_set_rgba(GTK_COLOR_CHOOSER(coloursel), &rgba);
|
|
|
|
}
|
|
|
|
#elif GTK_CHECK_VERSION(2,0,0)
|
2015-08-08 16:32:15 +00:00
|
|
|
{
|
|
|
|
GdkColor col;
|
|
|
|
col.red = r * 0x0101;
|
|
|
|
col.green = g * 0x0101;
|
|
|
|
col.blue = b * 0x0101;
|
|
|
|
gtk_color_selection_set_current_color(cs, &col);
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
{
|
|
|
|
gdouble cvals[4];
|
|
|
|
cvals[0] = r / 255.0;
|
|
|
|
cvals[1] = g / 255.0;
|
|
|
|
cvals[2] = b / 255.0;
|
2019-09-08 19:29:00 +00:00
|
|
|
cvals[3] = 1.0; /* fully opaque! */
|
2015-08-08 16:32:15 +00:00
|
|
|
gtk_color_selection_set_color(cs, cvals);
|
|
|
|
}
|
|
|
|
#endif
|
2003-03-15 15:50:42 +00:00
|
|
|
|
2015-08-22 13:49:02 +00:00
|
|
|
g_object_set_data(G_OBJECT(coloursel), "user-data", (gpointer)uc);
|
|
|
|
|
|
|
|
#if GTK_CHECK_VERSION(3,0,0)
|
|
|
|
g_signal_connect(G_OBJECT(coloursel), "response",
|
|
|
|
G_CALLBACK(colourchoose_response), (gpointer)dp);
|
|
|
|
#else
|
|
|
|
|
2015-08-08 14:53:43 +00:00
|
|
|
#if GTK_CHECK_VERSION(2,0,0)
|
|
|
|
g_object_get(G_OBJECT(ccs),
|
|
|
|
"ok-button", &okbutton,
|
|
|
|
"cancel-button", &cancelbutton,
|
|
|
|
(const char *)NULL);
|
|
|
|
#else
|
|
|
|
okbutton = ccs->ok_button;
|
|
|
|
cancelbutton = ccs->cancel_button;
|
|
|
|
#endif
|
|
|
|
g_object_set_data(G_OBJECT(okbutton), "user-data",
|
2022-06-23 17:44:07 +00:00
|
|
|
(gpointer)coloursel);
|
2015-08-08 14:53:43 +00:00
|
|
|
g_object_set_data(G_OBJECT(cancelbutton), "user-data",
|
2022-06-23 17:44:07 +00:00
|
|
|
(gpointer)coloursel);
|
2015-08-08 16:29:02 +00:00
|
|
|
g_signal_connect(G_OBJECT(okbutton), "clicked",
|
|
|
|
G_CALLBACK(coloursel_ok), (gpointer)dp);
|
|
|
|
g_signal_connect(G_OBJECT(cancelbutton), "clicked",
|
|
|
|
G_CALLBACK(coloursel_cancel), (gpointer)dp);
|
|
|
|
g_signal_connect_swapped(G_OBJECT(okbutton), "clicked",
|
|
|
|
G_CALLBACK(gtk_widget_destroy),
|
|
|
|
(gpointer)coloursel);
|
|
|
|
g_signal_connect_swapped(G_OBJECT(cancelbutton), "clicked",
|
|
|
|
G_CALLBACK(gtk_widget_destroy),
|
|
|
|
(gpointer)coloursel);
|
2015-08-22 13:49:02 +00:00
|
|
|
#endif
|
2003-03-15 15:50:42 +00:00
|
|
|
gtk_widget_show(coloursel);
|
2003-03-13 19:52:28 +00:00
|
|
|
}
|
|
|
|
|
2022-05-01 08:48:38 +00:00
|
|
|
bool dlg_coloursel_results(dlgcontrol *ctrl, dlgparam *dp,
|
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 *r, int *g, int *b)
|
2003-03-13 19:52:28 +00:00
|
|
|
{
|
2003-03-15 15:50:42 +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-15 15:50:42 +00:00
|
|
|
} else
|
2019-09-08 19:29:00 +00:00
|
|
|
return false;
|
2003-03-13 19:52:28 +00:00
|
|
|
}
|
|
|
|
|
2003-03-15 15:50:42 +00:00
|
|
|
/* ----------------------------------------------------------------------
|
|
|
|
* Signal handlers while the dialog box is active.
|
|
|
|
*/
|
|
|
|
|
2003-03-18 19:06:51 +00:00
|
|
|
static gboolean widget_focus(GtkWidget *widget, GdkEventFocus *event,
|
|
|
|
gpointer data)
|
|
|
|
{
|
|
|
|
struct dlgparam *dp = (struct dlgparam *)data;
|
|
|
|
struct uctrl *uc = dlg_find_bywidget(dp, widget);
|
2022-05-01 08:48:38 +00:00
|
|
|
dlgcontrol *focus;
|
2003-03-18 19:06:51 +00:00
|
|
|
|
|
|
|
if (uc && uc->ctrl)
|
|
|
|
focus = uc->ctrl;
|
|
|
|
else
|
|
|
|
focus = NULL;
|
|
|
|
|
|
|
|
if (focus != dp->currfocus) {
|
|
|
|
dp->lastfocus = dp->currfocus;
|
|
|
|
dp->currfocus = focus;
|
|
|
|
}
|
|
|
|
|
2018-10-29 19:50:29 +00:00
|
|
|
return false;
|
2003-03-18 19:06:51 +00:00
|
|
|
}
|
|
|
|
|
2003-03-15 15:50:42 +00:00
|
|
|
static void button_clicked(GtkButton *button, gpointer data)
|
|
|
|
{
|
|
|
|
struct dlgparam *dp = (struct dlgparam *)data;
|
|
|
|
struct uctrl *uc = dlg_find_bywidget(dp, GTK_WIDGET(button));
|
Restructure dlgcontrol as a struct with an anon union.
This gets rid of that awkward STANDARD_PREFIX system in which every
branch of the old 'union control' had to repeat all the generic
fields, and then call sites had to make an arbitrary decision about
which branch to access them through.
That was the best we could do before accepting C99 features in this
code base. But now we have anonymous unions, so we don't need to put
up with that nonsense any more!
'dlgcontrol' is now a struct rather than a union, and the generic
fields common to all control types are ordinary members of the struct,
so you don't have to refer to them as ctrl->generic.foo at all, just
ctrl->foo, which saves verbiage at the point of use.
The extra per-control fields are still held in structures named after
the control type, so you'll still say ctrl->listbox.height or
whatever. But now those structures are themselves members of an
anonymous union field following the generic fields, so those
sub-structures don't have to reiterate all the standard stuff too.
While I'm here, I've promoted 'context2' from an editbox-specific
field to a generic one (it just seems silly _not_ to allow any control
to have two context fields if it needs it). Also, I had to rename the
boolean field 'tabdelay' to avoid it clashing with the subsidiary
structure field 'tabdelay', now that the former isn't generic.tabdelay
any more.
2022-05-01 08:55:52 +00:00
|
|
|
uc->ctrl->handler(uc->ctrl, dp, dp->data, EVENT_ACTION);
|
2003-03-15 15:50:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void button_toggled(GtkToggleButton *tb, gpointer data)
|
|
|
|
{
|
|
|
|
struct dlgparam *dp = (struct dlgparam *)data;
|
|
|
|
struct uctrl *uc = dlg_find_bywidget(dp, GTK_WIDGET(tb));
|
Restructure dlgcontrol as a struct with an anon union.
This gets rid of that awkward STANDARD_PREFIX system in which every
branch of the old 'union control' had to repeat all the generic
fields, and then call sites had to make an arbitrary decision about
which branch to access them through.
That was the best we could do before accepting C99 features in this
code base. But now we have anonymous unions, so we don't need to put
up with that nonsense any more!
'dlgcontrol' is now a struct rather than a union, and the generic
fields common to all control types are ordinary members of the struct,
so you don't have to refer to them as ctrl->generic.foo at all, just
ctrl->foo, which saves verbiage at the point of use.
The extra per-control fields are still held in structures named after
the control type, so you'll still say ctrl->listbox.height or
whatever. But now those structures are themselves members of an
anonymous union field following the generic fields, so those
sub-structures don't have to reiterate all the standard stuff too.
While I'm here, I've promoted 'context2' from an editbox-specific
field to a generic one (it just seems silly _not_ to allow any control
to have two context fields if it needs it). Also, I had to rename the
boolean field 'tabdelay' to avoid it clashing with the subsidiary
structure field 'tabdelay', now that the former isn't generic.tabdelay
any more.
2022-05-01 08:55:52 +00:00
|
|
|
uc->ctrl->handler(uc->ctrl, dp, dp->data, EVENT_VALCHANGE);
|
2003-03-15 15:50:42 +00:00
|
|
|
}
|
|
|
|
|
2007-01-25 19:47:36 +00:00
|
|
|
static gboolean editbox_key(GtkWidget *widget, GdkEventKey *event,
|
2019-09-08 19:29:00 +00:00
|
|
|
gpointer data)
|
2003-03-16 12:37:48 +00:00
|
|
|
{
|
|
|
|
/*
|
|
|
|
* GtkEntry has a nasty habit of eating the Return key, which
|
|
|
|
* is unhelpful since it doesn't actually _do_ anything with it
|
|
|
|
* (it calls gtk_widget_activate, but our edit boxes never need
|
|
|
|
* activating). So I catch Return before GtkEntry sees it, and
|
|
|
|
* pass it straight on to the parent widget. Effect: hitting
|
|
|
|
* Return in an edit box will now activate the default button
|
|
|
|
* in the dialog just like it will everywhere else.
|
|
|
|
*/
|
2015-08-08 14:53:43 +00:00
|
|
|
GtkWidget *parent = gtk_widget_get_parent(widget);
|
2015-08-08 15:23:54 +00:00
|
|
|
if (event->keyval == GDK_KEY_Return && parent != NULL) {
|
2019-09-08 19:29:00 +00:00
|
|
|
gboolean return_val;
|
2015-08-08 16:29:02 +00:00
|
|
|
g_signal_stop_emission_by_name(G_OBJECT(widget), "key_press_event");
|
2019-09-08 19:29:00 +00:00
|
|
|
g_signal_emit_by_name(G_OBJECT(parent), "key_press_event",
|
2015-08-08 16:29:02 +00:00
|
|
|
event, &return_val);
|
2019-09-08 19:29:00 +00:00
|
|
|
return return_val;
|
2003-03-16 12:37:48 +00:00
|
|
|
}
|
2018-10-29 19:50:29 +00:00
|
|
|
return false;
|
2003-03-16 12:37:48 +00:00
|
|
|
}
|
|
|
|
|
2003-03-15 15:50:42 +00:00
|
|
|
static void editbox_changed(GtkEditable *ed, gpointer data)
|
|
|
|
{
|
|
|
|
struct dlgparam *dp = (struct dlgparam *)data;
|
|
|
|
if (!(dp->flags & FLAG_UPDATING_COMBO_LIST)) {
|
2019-09-08 19:29:00 +00:00
|
|
|
struct uctrl *uc = dlg_find_bywidget(dp, GTK_WIDGET(ed));
|
Restructure dlgcontrol as a struct with an anon union.
This gets rid of that awkward STANDARD_PREFIX system in which every
branch of the old 'union control' had to repeat all the generic
fields, and then call sites had to make an arbitrary decision about
which branch to access them through.
That was the best we could do before accepting C99 features in this
code base. But now we have anonymous unions, so we don't need to put
up with that nonsense any more!
'dlgcontrol' is now a struct rather than a union, and the generic
fields common to all control types are ordinary members of the struct,
so you don't have to refer to them as ctrl->generic.foo at all, just
ctrl->foo, which saves verbiage at the point of use.
The extra per-control fields are still held in structures named after
the control type, so you'll still say ctrl->listbox.height or
whatever. But now those structures are themselves members of an
anonymous union field following the generic fields, so those
sub-structures don't have to reiterate all the standard stuff too.
While I'm here, I've promoted 'context2' from an editbox-specific
field to a generic one (it just seems silly _not_ to allow any control
to have two context fields if it needs it). Also, I had to rename the
boolean field 'tabdelay' to avoid it clashing with the subsidiary
structure field 'tabdelay', now that the former isn't generic.tabdelay
any more.
2022-05-01 08:55:52 +00:00
|
|
|
uc->ctrl->handler(uc->ctrl, dp, dp->data, EVENT_VALCHANGE);
|
2003-03-15 15:50:42 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-01-25 19:47:36 +00:00
|
|
|
static gboolean editbox_lostfocus(GtkWidget *ed, GdkEventFocus *event,
|
2019-09-08 19:29:00 +00:00
|
|
|
gpointer data)
|
2003-03-15 15:50:42 +00:00
|
|
|
{
|
|
|
|
struct dlgparam *dp = (struct dlgparam *)data;
|
|
|
|
struct uctrl *uc = dlg_find_bywidget(dp, GTK_WIDGET(ed));
|
Restructure dlgcontrol as a struct with an anon union.
This gets rid of that awkward STANDARD_PREFIX system in which every
branch of the old 'union control' had to repeat all the generic
fields, and then call sites had to make an arbitrary decision about
which branch to access them through.
That was the best we could do before accepting C99 features in this
code base. But now we have anonymous unions, so we don't need to put
up with that nonsense any more!
'dlgcontrol' is now a struct rather than a union, and the generic
fields common to all control types are ordinary members of the struct,
so you don't have to refer to them as ctrl->generic.foo at all, just
ctrl->foo, which saves verbiage at the point of use.
The extra per-control fields are still held in structures named after
the control type, so you'll still say ctrl->listbox.height or
whatever. But now those structures are themselves members of an
anonymous union field following the generic fields, so those
sub-structures don't have to reiterate all the standard stuff too.
While I'm here, I've promoted 'context2' from an editbox-specific
field to a generic one (it just seems silly _not_ to allow any control
to have two context fields if it needs it). Also, I had to rename the
boolean field 'tabdelay' to avoid it clashing with the subsidiary
structure field 'tabdelay', now that the former isn't generic.tabdelay
any more.
2022-05-01 08:55:52 +00:00
|
|
|
uc->ctrl->handler(uc->ctrl, dp, dp->data, EVENT_REFRESH);
|
2018-10-29 19:50:29 +00:00
|
|
|
return false;
|
2003-03-15 15:50:42 +00:00
|
|
|
}
|
|
|
|
|
2008-04-04 10:56:26 +00:00
|
|
|
#if !GTK_CHECK_VERSION(2,0,0)
|
|
|
|
|
|
|
|
/*
|
|
|
|
* GTK 1 list box event handlers.
|
|
|
|
*/
|
|
|
|
|
|
|
|
static gboolean listitem_key(GtkWidget *item, GdkEventKey *event,
|
2019-09-08 19:29:00 +00:00
|
|
|
gpointer data, bool multiple)
|
2008-04-04 10:56:26 +00:00
|
|
|
{
|
|
|
|
GtkAdjustment *adj = GTK_ADJUSTMENT(data);
|
|
|
|
|
|
|
|
if (event->keyval == GDK_Up || event->keyval == GDK_KP_Up ||
|
|
|
|
event->keyval == GDK_Down || event->keyval == GDK_KP_Down ||
|
|
|
|
event->keyval == GDK_Page_Up || event->keyval == GDK_KP_Page_Up ||
|
|
|
|
event->keyval == GDK_Page_Down || event->keyval == GDK_KP_Page_Down) {
|
|
|
|
/*
|
|
|
|
* Up, Down, PgUp or PgDn have been pressed on a ListItem
|
|
|
|
* in a list box. So, if the list box is single-selection:
|
2019-09-08 19:29:00 +00:00
|
|
|
*
|
2008-04-04 10:56:26 +00:00
|
|
|
* - if the list item in question isn't already selected,
|
|
|
|
* we simply select it.
|
|
|
|
* - otherwise, we find the next one (or next
|
|
|
|
* however-far-away) in whichever direction we're going,
|
|
|
|
* and select that.
|
|
|
|
* + in this case, we must also fiddle with the
|
|
|
|
* scrollbar to ensure the newly selected item is
|
|
|
|
* actually visible.
|
2019-09-08 19:29:00 +00:00
|
|
|
*
|
2008-04-04 10:56:26 +00:00
|
|
|
* If it's multiple-selection, we do all of the above
|
|
|
|
* except actually selecting anything, so we move the focus
|
|
|
|
* and fiddle the scrollbar to follow it.
|
|
|
|
*/
|
|
|
|
GtkWidget *list = item->parent;
|
|
|
|
|
2015-08-08 16:29:02 +00:00
|
|
|
g_signal_stop_emission_by_name(G_OBJECT(item), "key_press_event");
|
2008-04-04 10:56:26 +00:00
|
|
|
|
|
|
|
if (!multiple &&
|
|
|
|
GTK_WIDGET_STATE(item) != GTK_STATE_SELECTED) {
|
2022-06-23 17:44:07 +00:00
|
|
|
gtk_list_select_child(GTK_LIST(list), item);
|
2008-04-04 10:56:26 +00:00
|
|
|
} else {
|
|
|
|
int direction =
|
|
|
|
(event->keyval==GDK_Up || event->keyval==GDK_KP_Up ||
|
|
|
|
event->keyval==GDK_Page_Up || event->keyval==GDK_KP_Page_Up)
|
|
|
|
? -1 : +1;
|
|
|
|
int step =
|
2019-09-08 19:29:00 +00:00
|
|
|
(event->keyval==GDK_Page_Down ||
|
2008-04-04 10:56:26 +00:00
|
|
|
event->keyval==GDK_KP_Page_Down ||
|
|
|
|
event->keyval==GDK_Page_Up || event->keyval==GDK_KP_Page_Up)
|
|
|
|
? 2 : 1;
|
|
|
|
int i, n;
|
|
|
|
GList *children, *chead;
|
|
|
|
|
|
|
|
chead = children = gtk_container_children(GTK_CONTAINER(list));
|
|
|
|
|
|
|
|
n = g_list_length(children);
|
|
|
|
|
|
|
|
if (step == 2) {
|
|
|
|
/*
|
|
|
|
* Figure out how many list items to a screenful,
|
|
|
|
* and adjust the step appropriately.
|
|
|
|
*/
|
|
|
|
step = 0.5 + adj->page_size * n / (adj->upper - adj->lower);
|
|
|
|
step--; /* go by one less than that */
|
|
|
|
}
|
|
|
|
|
|
|
|
i = 0;
|
|
|
|
while (children != NULL) {
|
|
|
|
if (item == children->data)
|
|
|
|
break;
|
|
|
|
children = children->next;
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (step > 0) {
|
|
|
|
if (direction < 0 && i > 0)
|
|
|
|
children = children->prev, i--;
|
|
|
|
else if (direction > 0 && i < n-1)
|
|
|
|
children = children->next, i++;
|
|
|
|
step--;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (children && children->data) {
|
|
|
|
if (!multiple)
|
|
|
|
gtk_list_select_child(GTK_LIST(list),
|
|
|
|
GTK_WIDGET(children->data));
|
|
|
|
gtk_widget_grab_focus(GTK_WIDGET(children->data));
|
Formatting: standardise on "func(\n", not "func\n(".
If the function name (or expression) in a function call or declaration
is itself so long that even the first argument doesn't fit after it on
the same line, or if that would leave so little space that it would be
silly to try to wrap all the run-on lines into a tall thin column,
then I used to do this
ludicrously_long_function_name
(arg1, arg2, arg3);
and now prefer this
ludicrously_long_function_name(
arg1, arg2, arg3);
I picked up the habit from Python, where the latter idiom is required
by Python's syntactic significance of newlines (you can write the
former if you use a backslash-continuation, but pretty much everyone
seems to agree that that's much uglier). But I've found it works well
in C as well: it makes it more obvious that the previous line is
incomplete, it gives you a tiny bit more space to wrap the following
lines into (the old idiom indents the _third_ line one space beyond
the second), and I generally turn out to agree with the knock-on
indentation decisions made by at least Emacs if you do it in the
middle of a complex expression. Plus, of course, using the _same_
idiom between C and Python means less state-switching.
So, while I'm making annoying indentation changes in general, this
seems like a good time to dig out all the cases of the old idiom in
this code, and switch them over to the new.
2022-08-03 19:48:46 +00:00
|
|
|
gtk_adjustment_clamp_page(
|
|
|
|
adj,
|
|
|
|
adj->lower + (adj->upper-adj->lower) * i / n,
|
|
|
|
adj->lower + (adj->upper-adj->lower) * (i+1) / n);
|
2008-04-04 10:56:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
g_list_free(chead);
|
|
|
|
}
|
2018-10-29 19:50:29 +00:00
|
|
|
return true;
|
2008-04-04 10:56:26 +00:00
|
|
|
}
|
|
|
|
|
2018-10-29 19:50:29 +00:00
|
|
|
return false;
|
2008-04-04 10:56:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean listitem_single_key(GtkWidget *item, GdkEventKey *event,
|
2019-09-08 19:29:00 +00:00
|
|
|
gpointer data)
|
2008-04-04 10:56:26 +00:00
|
|
|
{
|
2018-10-29 19:50:29 +00:00
|
|
|
return listitem_key(item, event, data, false);
|
2008-04-04 10:56:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean listitem_multi_key(GtkWidget *item, GdkEventKey *event,
|
2019-09-08 19:29:00 +00:00
|
|
|
gpointer data)
|
2008-04-04 10:56:26 +00:00
|
|
|
{
|
2018-10-29 19:50:29 +00:00
|
|
|
return listitem_key(item, event, data, true);
|
2008-04-04 10:56:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean listitem_button_press(GtkWidget *item, GdkEventButton *event,
|
2019-09-08 19:29:00 +00:00
|
|
|
gpointer data)
|
2008-04-04 10:56:26 +00:00
|
|
|
{
|
|
|
|
struct dlgparam *dp = (struct dlgparam *)data;
|
|
|
|
struct uctrl *uc = dlg_find_bywidget(dp, GTK_WIDGET(item));
|
|
|
|
switch (event->type) {
|
2022-06-23 17:44:07 +00:00
|
|
|
default:
|
|
|
|
case GDK_BUTTON_PRESS: uc->nclicks = 1; break;
|
|
|
|
case GDK_2BUTTON_PRESS: uc->nclicks = 2; break;
|
|
|
|
case GDK_3BUTTON_PRESS: uc->nclicks = 3; break;
|
2008-04-04 10:56:26 +00:00
|
|
|
}
|
2018-10-29 19:50:29 +00:00
|
|
|
return false;
|
2008-04-04 10:56:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean listitem_button_release(GtkWidget *item, GdkEventButton *event,
|
2019-09-08 19:29:00 +00:00
|
|
|
gpointer data)
|
2008-04-04 10:56:26 +00:00
|
|
|
{
|
|
|
|
struct dlgparam *dp = (struct dlgparam *)data;
|
|
|
|
struct uctrl *uc = dlg_find_bywidget(dp, GTK_WIDGET(item));
|
|
|
|
if (uc->nclicks>1) {
|
Restructure dlgcontrol as a struct with an anon union.
This gets rid of that awkward STANDARD_PREFIX system in which every
branch of the old 'union control' had to repeat all the generic
fields, and then call sites had to make an arbitrary decision about
which branch to access them through.
That was the best we could do before accepting C99 features in this
code base. But now we have anonymous unions, so we don't need to put
up with that nonsense any more!
'dlgcontrol' is now a struct rather than a union, and the generic
fields common to all control types are ordinary members of the struct,
so you don't have to refer to them as ctrl->generic.foo at all, just
ctrl->foo, which saves verbiage at the point of use.
The extra per-control fields are still held in structures named after
the control type, so you'll still say ctrl->listbox.height or
whatever. But now those structures are themselves members of an
anonymous union field following the generic fields, so those
sub-structures don't have to reiterate all the standard stuff too.
While I'm here, I've promoted 'context2' from an editbox-specific
field to a generic one (it just seems silly _not_ to allow any control
to have two context fields if it needs it). Also, I had to rename the
boolean field 'tabdelay' to avoid it clashing with the subsidiary
structure field 'tabdelay', now that the former isn't generic.tabdelay
any more.
2022-05-01 08:55:52 +00:00
|
|
|
uc->ctrl->handler(uc->ctrl, dp, dp->data, EVENT_ACTION);
|
2018-10-29 19:50:29 +00:00
|
|
|
return true;
|
2008-04-04 10:56:26 +00:00
|
|
|
}
|
2018-10-29 19:50:29 +00:00
|
|
|
return false;
|
2008-04-04 10:56:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void list_selchange(GtkList *list, gpointer data)
|
|
|
|
{
|
|
|
|
struct dlgparam *dp = (struct dlgparam *)data;
|
|
|
|
struct uctrl *uc = dlg_find_bywidget(dp, GTK_WIDGET(list));
|
|
|
|
if (!uc) return;
|
Restructure dlgcontrol as a struct with an anon union.
This gets rid of that awkward STANDARD_PREFIX system in which every
branch of the old 'union control' had to repeat all the generic
fields, and then call sites had to make an arbitrary decision about
which branch to access them through.
That was the best we could do before accepting C99 features in this
code base. But now we have anonymous unions, so we don't need to put
up with that nonsense any more!
'dlgcontrol' is now a struct rather than a union, and the generic
fields common to all control types are ordinary members of the struct,
so you don't have to refer to them as ctrl->generic.foo at all, just
ctrl->foo, which saves verbiage at the point of use.
The extra per-control fields are still held in structures named after
the control type, so you'll still say ctrl->listbox.height or
whatever. But now those structures are themselves members of an
anonymous union field following the generic fields, so those
sub-structures don't have to reiterate all the standard stuff too.
While I'm here, I've promoted 'context2' from an editbox-specific
field to a generic one (it just seems silly _not_ to allow any control
to have two context fields if it needs it). Also, I had to rename the
boolean field 'tabdelay' to avoid it clashing with the subsidiary
structure field 'tabdelay', now that the former isn't generic.tabdelay
any more.
2022-05-01 08:55:52 +00:00
|
|
|
uc->ctrl->handler(uc->ctrl, dp, dp->data, EVENT_SELCHANGE);
|
2008-04-04 10:56:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void draglist_move(struct dlgparam *dp, struct uctrl *uc, int direction)
|
|
|
|
{
|
|
|
|
int index = dlg_listbox_index(uc->ctrl, dp);
|
|
|
|
GList *children = gtk_container_children(GTK_CONTAINER(uc->list));
|
|
|
|
GtkWidget *child;
|
|
|
|
|
|
|
|
if ((index < 0) ||
|
2019-09-08 19:29:00 +00:00
|
|
|
(index == 0 && direction < 0) ||
|
|
|
|
(index == g_list_length(children)-1 && direction > 0)) {
|
|
|
|
gdk_display_beep(gdk_display_get_default());
|
|
|
|
return;
|
2008-04-04 10:56:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
child = g_list_nth_data(children, index);
|
|
|
|
gtk_widget_ref(child);
|
|
|
|
gtk_list_clear_items(GTK_LIST(uc->list), index, index+1);
|
|
|
|
g_list_free(children);
|
|
|
|
|
|
|
|
children = NULL;
|
|
|
|
children = g_list_append(children, child);
|
|
|
|
gtk_list_insert_items(GTK_LIST(uc->list), children, index + direction);
|
|
|
|
gtk_list_select_item(GTK_LIST(uc->list), index + direction);
|
Restructure dlgcontrol as a struct with an anon union.
This gets rid of that awkward STANDARD_PREFIX system in which every
branch of the old 'union control' had to repeat all the generic
fields, and then call sites had to make an arbitrary decision about
which branch to access them through.
That was the best we could do before accepting C99 features in this
code base. But now we have anonymous unions, so we don't need to put
up with that nonsense any more!
'dlgcontrol' is now a struct rather than a union, and the generic
fields common to all control types are ordinary members of the struct,
so you don't have to refer to them as ctrl->generic.foo at all, just
ctrl->foo, which saves verbiage at the point of use.
The extra per-control fields are still held in structures named after
the control type, so you'll still say ctrl->listbox.height or
whatever. But now those structures are themselves members of an
anonymous union field following the generic fields, so those
sub-structures don't have to reiterate all the standard stuff too.
While I'm here, I've promoted 'context2' from an editbox-specific
field to a generic one (it just seems silly _not_ to allow any control
to have two context fields if it needs it). Also, I had to rename the
boolean field 'tabdelay' to avoid it clashing with the subsidiary
structure field 'tabdelay', now that the former isn't generic.tabdelay
any more.
2022-05-01 08:55:52 +00:00
|
|
|
uc->ctrl->handler(uc->ctrl, dp, dp->data, EVENT_VALCHANGE);
|
2008-04-04 10:56:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void draglist_up(GtkButton *button, gpointer data)
|
|
|
|
{
|
|
|
|
struct dlgparam *dp = (struct dlgparam *)data;
|
|
|
|
struct uctrl *uc = dlg_find_bywidget(dp, GTK_WIDGET(button));
|
|
|
|
draglist_move(dp, uc, -1);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void draglist_down(GtkButton *button, gpointer data)
|
|
|
|
{
|
|
|
|
struct dlgparam *dp = (struct dlgparam *)data;
|
|
|
|
struct uctrl *uc = dlg_find_bywidget(dp, GTK_WIDGET(button));
|
|
|
|
draglist_move(dp, uc, +1);
|
|
|
|
}
|
|
|
|
|
|
|
|
#else /* !GTK_CHECK_VERSION(2,0,0) */
|
|
|
|
|
|
|
|
/*
|
|
|
|
* GTK 2 list box event handlers.
|
|
|
|
*/
|
|
|
|
|
2008-04-02 14:48:06 +00:00
|
|
|
static void listbox_doubleclick(GtkTreeView *treeview, GtkTreePath *path,
|
2019-09-08 19:29:00 +00:00
|
|
|
GtkTreeViewColumn *column, gpointer data)
|
2003-03-15 15:50:42 +00:00
|
|
|
{
|
|
|
|
struct dlgparam *dp = (struct dlgparam *)data;
|
2008-04-02 14:48:06 +00:00
|
|
|
struct uctrl *uc = dlg_find_bywidget(dp, GTK_WIDGET(treeview));
|
|
|
|
if (uc)
|
Restructure dlgcontrol as a struct with an anon union.
This gets rid of that awkward STANDARD_PREFIX system in which every
branch of the old 'union control' had to repeat all the generic
fields, and then call sites had to make an arbitrary decision about
which branch to access them through.
That was the best we could do before accepting C99 features in this
code base. But now we have anonymous unions, so we don't need to put
up with that nonsense any more!
'dlgcontrol' is now a struct rather than a union, and the generic
fields common to all control types are ordinary members of the struct,
so you don't have to refer to them as ctrl->generic.foo at all, just
ctrl->foo, which saves verbiage at the point of use.
The extra per-control fields are still held in structures named after
the control type, so you'll still say ctrl->listbox.height or
whatever. But now those structures are themselves members of an
anonymous union field following the generic fields, so those
sub-structures don't have to reiterate all the standard stuff too.
While I'm here, I've promoted 'context2' from an editbox-specific
field to a generic one (it just seems silly _not_ to allow any control
to have two context fields if it needs it). Also, I had to rename the
boolean field 'tabdelay' to avoid it clashing with the subsidiary
structure field 'tabdelay', now that the former isn't generic.tabdelay
any more.
2022-05-01 08:55:52 +00:00
|
|
|
uc->ctrl->handler(uc->ctrl, dp, dp->data, EVENT_ACTION);
|
2003-03-15 15:50:42 +00:00
|
|
|
}
|
|
|
|
|
2008-04-02 14:48:06 +00:00
|
|
|
static void listbox_selchange(GtkTreeSelection *treeselection,
|
2019-09-08 19:29:00 +00:00
|
|
|
gpointer data)
|
2003-03-15 15:50:42 +00:00
|
|
|
{
|
|
|
|
struct dlgparam *dp = (struct dlgparam *)data;
|
2008-04-02 14:48:06 +00:00
|
|
|
GtkTreeView *tree = gtk_tree_selection_get_tree_view(treeselection);
|
|
|
|
struct uctrl *uc = dlg_find_bywidget(dp, GTK_WIDGET(tree));
|
|
|
|
if (uc)
|
Restructure dlgcontrol as a struct with an anon union.
This gets rid of that awkward STANDARD_PREFIX system in which every
branch of the old 'union control' had to repeat all the generic
fields, and then call sites had to make an arbitrary decision about
which branch to access them through.
That was the best we could do before accepting C99 features in this
code base. But now we have anonymous unions, so we don't need to put
up with that nonsense any more!
'dlgcontrol' is now a struct rather than a union, and the generic
fields common to all control types are ordinary members of the struct,
so you don't have to refer to them as ctrl->generic.foo at all, just
ctrl->foo, which saves verbiage at the point of use.
The extra per-control fields are still held in structures named after
the control type, so you'll still say ctrl->listbox.height or
whatever. But now those structures are themselves members of an
anonymous union field following the generic fields, so those
sub-structures don't have to reiterate all the standard stuff too.
While I'm here, I've promoted 'context2' from an editbox-specific
field to a generic one (it just seems silly _not_ to allow any control
to have two context fields if it needs it). Also, I had to rename the
boolean field 'tabdelay' to avoid it clashing with the subsidiary
structure field 'tabdelay', now that the former isn't generic.tabdelay
any more.
2022-05-01 08:55:52 +00:00
|
|
|
uc->ctrl->handler(uc->ctrl, dp, dp->data, EVENT_SELCHANGE);
|
2003-03-15 15:50:42 +00:00
|
|
|
}
|
|
|
|
|
2008-04-02 14:48:06 +00:00
|
|
|
struct draglist_valchange_ctx {
|
|
|
|
struct uctrl *uc;
|
|
|
|
struct dlgparam *dp;
|
|
|
|
};
|
|
|
|
|
|
|
|
static gboolean draglist_valchange(gpointer data)
|
2003-03-15 15:50:42 +00:00
|
|
|
{
|
2008-04-02 14:48:06 +00:00
|
|
|
struct draglist_valchange_ctx *ctx =
|
2019-09-08 19:29:00 +00:00
|
|
|
(struct draglist_valchange_ctx *)data;
|
2003-03-15 15:50:42 +00:00
|
|
|
|
Restructure dlgcontrol as a struct with an anon union.
This gets rid of that awkward STANDARD_PREFIX system in which every
branch of the old 'union control' had to repeat all the generic
fields, and then call sites had to make an arbitrary decision about
which branch to access them through.
That was the best we could do before accepting C99 features in this
code base. But now we have anonymous unions, so we don't need to put
up with that nonsense any more!
'dlgcontrol' is now a struct rather than a union, and the generic
fields common to all control types are ordinary members of the struct,
so you don't have to refer to them as ctrl->generic.foo at all, just
ctrl->foo, which saves verbiage at the point of use.
The extra per-control fields are still held in structures named after
the control type, so you'll still say ctrl->listbox.height or
whatever. But now those structures are themselves members of an
anonymous union field following the generic fields, so those
sub-structures don't have to reiterate all the standard stuff too.
While I'm here, I've promoted 'context2' from an editbox-specific
field to a generic one (it just seems silly _not_ to allow any control
to have two context fields if it needs it). Also, I had to rename the
boolean field 'tabdelay' to avoid it clashing with the subsidiary
structure field 'tabdelay', now that the former isn't generic.tabdelay
any more.
2022-05-01 08:55:52 +00:00
|
|
|
ctx->uc->ctrl->handler(ctx->uc->ctrl, ctx->dp,
|
2022-06-23 17:44:07 +00:00
|
|
|
ctx->dp->data, EVENT_VALCHANGE);
|
2003-03-15 15:50:42 +00:00
|
|
|
|
2008-04-02 14:48:06 +00:00
|
|
|
sfree(ctx);
|
2003-03-18 19:06:51 +00:00
|
|
|
|
2018-10-29 19:50:29 +00:00
|
|
|
return false;
|
2003-03-15 15:50:42 +00:00
|
|
|
}
|
|
|
|
|
2008-04-02 14:48:06 +00:00
|
|
|
static void listbox_reorder(GtkTreeModel *treemodel, GtkTreePath *path,
|
2019-09-08 19:29:00 +00:00
|
|
|
GtkTreeIter *iter, gpointer data)
|
2003-03-15 15:50:42 +00:00
|
|
|
{
|
|
|
|
struct dlgparam *dp = (struct dlgparam *)data;
|
2008-04-02 14:48:06 +00:00
|
|
|
gpointer tree;
|
|
|
|
struct uctrl *uc;
|
2003-03-15 15:50:42 +00:00
|
|
|
|
2008-04-02 14:48:06 +00:00
|
|
|
if (dp->flags & FLAG_UPDATING_LISTBOX)
|
2019-09-08 19:29:00 +00:00
|
|
|
return; /* not a user drag operation */
|
2008-04-02 14:48:06 +00:00
|
|
|
|
|
|
|
tree = g_object_get_data(G_OBJECT(treemodel), "user-data");
|
|
|
|
uc = dlg_find_bywidget(dp, GTK_WIDGET(tree));
|
|
|
|
if (uc) {
|
2019-09-08 19:29:00 +00:00
|
|
|
/*
|
|
|
|
* We should cause EVENT_VALCHANGE on the list box, now
|
|
|
|
* that its rows have been reordered. However, the GTK 2
|
|
|
|
* docs say that at the point this signal is received the
|
|
|
|
* new row might not have actually been filled in yet.
|
|
|
|
*
|
|
|
|
* (So what smegging use is it then, eh? Don't suppose it
|
|
|
|
* occurred to you at any point that letting the
|
|
|
|
* application know _after_ the reordering was compelete
|
|
|
|
* might be helpful to someone?)
|
|
|
|
*
|
|
|
|
* To get round this, I schedule an idle function, which I
|
|
|
|
* hope won't be called until the main event loop is
|
|
|
|
* re-entered after the drag-and-drop handler has finished
|
|
|
|
* furtling with the list store.
|
|
|
|
*/
|
|
|
|
struct draglist_valchange_ctx *ctx =
|
|
|
|
snew(struct draglist_valchange_ctx);
|
|
|
|
ctx->uc = uc;
|
|
|
|
ctx->dp = dp;
|
|
|
|
g_idle_add(draglist_valchange, ctx);
|
2008-04-02 14:48:06 +00:00
|
|
|
}
|
2003-03-15 15:50:42 +00:00
|
|
|
}
|
|
|
|
|
2008-04-04 10:56:26 +00:00
|
|
|
#endif /* !GTK_CHECK_VERSION(2,0,0) */
|
|
|
|
|
2008-05-31 19:23:45 +00:00
|
|
|
#if !GTK_CHECK_VERSION(2,4,0)
|
|
|
|
|
|
|
|
static void menuitem_activate(GtkMenuItem *item, gpointer data)
|
|
|
|
{
|
|
|
|
struct dlgparam *dp = (struct dlgparam *)data;
|
|
|
|
GtkWidget *menushell = GTK_WIDGET(item)->parent;
|
2015-08-08 16:29:02 +00:00
|
|
|
gpointer optmenu = g_object_get_data(G_OBJECT(menushell), "user-data");
|
2008-05-31 19:23:45 +00:00
|
|
|
struct uctrl *uc = dlg_find_bywidget(dp, GTK_WIDGET(optmenu));
|
Restructure dlgcontrol as a struct with an anon union.
This gets rid of that awkward STANDARD_PREFIX system in which every
branch of the old 'union control' had to repeat all the generic
fields, and then call sites had to make an arbitrary decision about
which branch to access them through.
That was the best we could do before accepting C99 features in this
code base. But now we have anonymous unions, so we don't need to put
up with that nonsense any more!
'dlgcontrol' is now a struct rather than a union, and the generic
fields common to all control types are ordinary members of the struct,
so you don't have to refer to them as ctrl->generic.foo at all, just
ctrl->foo, which saves verbiage at the point of use.
The extra per-control fields are still held in structures named after
the control type, so you'll still say ctrl->listbox.height or
whatever. But now those structures are themselves members of an
anonymous union field following the generic fields, so those
sub-structures don't have to reiterate all the standard stuff too.
While I'm here, I've promoted 'context2' from an editbox-specific
field to a generic one (it just seems silly _not_ to allow any control
to have two context fields if it needs it). Also, I had to rename the
boolean field 'tabdelay' to avoid it clashing with the subsidiary
structure field 'tabdelay', now that the former isn't generic.tabdelay
any more.
2022-05-01 08:55:52 +00:00
|
|
|
uc->ctrl->handler(uc->ctrl, dp, dp->data, EVENT_SELCHANGE);
|
2008-05-31 19:23:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#else
|
|
|
|
|
|
|
|
static void droplist_selchange(GtkComboBox *combo, gpointer data)
|
|
|
|
{
|
|
|
|
struct dlgparam *dp = (struct dlgparam *)data;
|
|
|
|
struct uctrl *uc = dlg_find_bywidget(dp, GTK_WIDGET(combo));
|
|
|
|
if (uc)
|
Restructure dlgcontrol as a struct with an anon union.
This gets rid of that awkward STANDARD_PREFIX system in which every
branch of the old 'union control' had to repeat all the generic
fields, and then call sites had to make an arbitrary decision about
which branch to access them through.
That was the best we could do before accepting C99 features in this
code base. But now we have anonymous unions, so we don't need to put
up with that nonsense any more!
'dlgcontrol' is now a struct rather than a union, and the generic
fields common to all control types are ordinary members of the struct,
so you don't have to refer to them as ctrl->generic.foo at all, just
ctrl->foo, which saves verbiage at the point of use.
The extra per-control fields are still held in structures named after
the control type, so you'll still say ctrl->listbox.height or
whatever. But now those structures are themselves members of an
anonymous union field following the generic fields, so those
sub-structures don't have to reiterate all the standard stuff too.
While I'm here, I've promoted 'context2' from an editbox-specific
field to a generic one (it just seems silly _not_ to allow any control
to have two context fields if it needs it). Also, I had to rename the
boolean field 'tabdelay' to avoid it clashing with the subsidiary
structure field 'tabdelay', now that the former isn't generic.tabdelay
any more.
2022-05-01 08:55:52 +00:00
|
|
|
uc->ctrl->handler(uc->ctrl, dp, dp->data, EVENT_SELCHANGE);
|
2008-05-31 19:23:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#endif /* !GTK_CHECK_VERSION(2,4,0) */
|
|
|
|
|
2022-05-01 07:39:49 +00:00
|
|
|
static void filechoose_emit_value(struct dlgparam *dp, struct uctrl *uc,
|
|
|
|
const char *name)
|
|
|
|
{
|
|
|
|
if (uc->entry) {
|
|
|
|
gtk_entry_set_text(GTK_ENTRY(uc->entry), name);
|
|
|
|
} else {
|
|
|
|
uc->textvalue = name;
|
|
|
|
uc->ctrl->handler(uc->ctrl, dp, dp->data, EVENT_ACTION);
|
|
|
|
uc->textvalue = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-08-08 16:34:25 +00:00
|
|
|
#ifdef USE_GTK_FILE_CHOOSER_DIALOG
|
|
|
|
static void filechoose_response(GtkDialog *dialog, gint response,
|
|
|
|
gpointer data)
|
|
|
|
{
|
2022-05-01 07:39:49 +00:00
|
|
|
struct dlgparam *dp = (struct dlgparam *)data;
|
2015-08-08 16:34:25 +00:00
|
|
|
struct uctrl *uc = g_object_get_data(G_OBJECT(dialog), "user-data");
|
|
|
|
if (response == GTK_RESPONSE_ACCEPT) {
|
|
|
|
gchar *name = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
|
2022-05-01 07:39:49 +00:00
|
|
|
filechoose_emit_value(dp, uc, name);
|
2015-08-08 16:34:25 +00:00
|
|
|
g_free(name);
|
|
|
|
}
|
|
|
|
gtk_widget_destroy(GTK_WIDGET(dialog));
|
|
|
|
}
|
|
|
|
#else
|
2003-03-15 15:50:42 +00:00
|
|
|
static void filesel_ok(GtkButton *button, gpointer data)
|
|
|
|
{
|
2022-05-01 07:39:49 +00:00
|
|
|
struct dlgparam *dp = (struct dlgparam *)data;
|
2015-08-08 16:29:02 +00:00
|
|
|
gpointer filesel = g_object_get_data(G_OBJECT(button), "user-data");
|
|
|
|
struct uctrl *uc = g_object_get_data(G_OBJECT(filesel), "user-data");
|
Formatting: standardise on "func(\n", not "func\n(".
If the function name (or expression) in a function call or declaration
is itself so long that even the first argument doesn't fit after it on
the same line, or if that would leave so little space that it would be
silly to try to wrap all the run-on lines into a tall thin column,
then I used to do this
ludicrously_long_function_name
(arg1, arg2, arg3);
and now prefer this
ludicrously_long_function_name(
arg1, arg2, arg3);
I picked up the habit from Python, where the latter idiom is required
by Python's syntactic significance of newlines (you can write the
former if you use a backslash-continuation, but pretty much everyone
seems to agree that that's much uglier). But I've found it works well
in C as well: it makes it more obvious that the previous line is
incomplete, it gives you a tiny bit more space to wrap the following
lines into (the old idiom indents the _third_ line one space beyond
the second), and I generally turn out to agree with the knock-on
indentation decisions made by at least Emacs if you do it in the
middle of a complex expression. Plus, of course, using the _same_
idiom between C and Python means less state-switching.
So, while I'm making annoying indentation changes in general, this
seems like a good time to dig out all the cases of the old idiom in
this code, and switch them over to the new.
2022-08-03 19:48:46 +00:00
|
|
|
const char *name = gtk_file_selection_get_filename(
|
|
|
|
GTK_FILE_SELECTION(filesel));
|
2022-05-01 07:39:49 +00:00
|
|
|
filechoose_emit_value(dp, uc, name);
|
2003-03-15 15:50:42 +00:00
|
|
|
}
|
2015-08-08 16:34:25 +00:00
|
|
|
#endif
|
2003-03-15 15:50:42 +00:00
|
|
|
|
|
|
|
static void fontsel_ok(GtkButton *button, gpointer data)
|
|
|
|
{
|
2003-03-29 19:52:50 +00:00
|
|
|
/* struct dlgparam *dp = (struct dlgparam *)data; */
|
2008-04-04 10:56:26 +00:00
|
|
|
|
|
|
|
#if !GTK_CHECK_VERSION(2,0,0)
|
|
|
|
|
2015-08-08 16:29:02 +00:00
|
|
|
gpointer fontsel = g_object_get_data(G_OBJECT(button), "user-data");
|
|
|
|
struct uctrl *uc = g_object_get_data(G_OBJECT(fontsel), "user-data");
|
Formatting: standardise on "func(\n", not "func\n(".
If the function name (or expression) in a function call or declaration
is itself so long that even the first argument doesn't fit after it on
the same line, or if that would leave so little space that it would be
silly to try to wrap all the run-on lines into a tall thin column,
then I used to do this
ludicrously_long_function_name
(arg1, arg2, arg3);
and now prefer this
ludicrously_long_function_name(
arg1, arg2, arg3);
I picked up the habit from Python, where the latter idiom is required
by Python's syntactic significance of newlines (you can write the
former if you use a backslash-continuation, but pretty much everyone
seems to agree that that's much uglier). But I've found it works well
in C as well: it makes it more obvious that the previous line is
incomplete, it gives you a tiny bit more space to wrap the following
lines into (the old idiom indents the _third_ line one space beyond
the second), and I generally turn out to agree with the knock-on
indentation decisions made by at least Emacs if you do it in the
middle of a complex expression. Plus, of course, using the _same_
idiom between C and Python means less state-switching.
So, while I'm making annoying indentation changes in general, this
seems like a good time to dig out all the cases of the old idiom in
this code, and switch them over to the new.
2022-08-03 19:48:46 +00:00
|
|
|
const char *name = gtk_font_selection_dialog_get_font_name(
|
|
|
|
GTK_FONT_SELECTION_DIALOG(fontsel));
|
2008-04-04 10:56:26 +00:00
|
|
|
gtk_entry_set_text(GTK_ENTRY(uc->entry), name);
|
|
|
|
|
|
|
|
#else
|
|
|
|
|
Formatting: standardise on "func(\n", not "func\n(".
If the function name (or expression) in a function call or declaration
is itself so long that even the first argument doesn't fit after it on
the same line, or if that would leave so little space that it would be
silly to try to wrap all the run-on lines into a tall thin column,
then I used to do this
ludicrously_long_function_name
(arg1, arg2, arg3);
and now prefer this
ludicrously_long_function_name(
arg1, arg2, arg3);
I picked up the habit from Python, where the latter idiom is required
by Python's syntactic significance of newlines (you can write the
former if you use a backslash-continuation, but pretty much everyone
seems to agree that that's much uglier). But I've found it works well
in C as well: it makes it more obvious that the previous line is
incomplete, it gives you a tiny bit more space to wrap the following
lines into (the old idiom indents the _third_ line one space beyond
the second), and I generally turn out to agree with the knock-on
indentation decisions made by at least Emacs if you do it in the
middle of a complex expression. Plus, of course, using the _same_
idiom between C and Python means less state-switching.
So, while I'm making annoying indentation changes in general, this
seems like a good time to dig out all the cases of the old idiom in
this code, and switch them over to the new.
2022-08-03 19:48:46 +00:00
|
|
|
unifontsel *fontsel = (unifontsel *)g_object_get_data(
|
|
|
|
G_OBJECT(button), "user-data");
|
2008-03-25 21:49:14 +00:00
|
|
|
struct uctrl *uc = (struct uctrl *)fontsel->user_data;
|
|
|
|
char *name = unifontsel_get_name(fontsel);
|
2008-03-29 14:21:25 +00:00
|
|
|
assert(name); /* should always be ok after OK pressed */
|
2003-03-15 15:50:42 +00:00
|
|
|
gtk_entry_set_text(GTK_ENTRY(uc->entry), name);
|
2008-03-25 21:49:14 +00:00
|
|
|
sfree(name);
|
2008-04-04 10:56:26 +00:00
|
|
|
|
|
|
|
#endif
|
2003-03-15 15:50:42 +00:00
|
|
|
}
|
|
|
|
|
2015-08-22 13:49:02 +00:00
|
|
|
#if GTK_CHECK_VERSION(3,0,0)
|
|
|
|
|
|
|
|
static void colourchoose_response(GtkDialog *dialog,
|
|
|
|
gint response_id, gpointer data)
|
|
|
|
{
|
|
|
|
struct dlgparam *dp = (struct dlgparam *)data;
|
|
|
|
struct uctrl *uc = g_object_get_data(G_OBJECT(dialog), "user-data");
|
|
|
|
|
|
|
|
if (response_id == GTK_RESPONSE_OK) {
|
|
|
|
GdkRGBA rgba;
|
|
|
|
gtk_color_chooser_get_rgba(GTK_COLOR_CHOOSER(dialog), &rgba);
|
|
|
|
dp->coloursel_result.r = (int) (255 * rgba.red);
|
|
|
|
dp->coloursel_result.g = (int) (255 * rgba.green);
|
|
|
|
dp->coloursel_result.b = (int) (255 * rgba.blue);
|
2018-10-29 19:50:29 +00:00
|
|
|
dp->coloursel_result.ok = true;
|
2015-08-22 13:49:02 +00:00
|
|
|
} else {
|
2018-10-29 19:50:29 +00:00
|
|
|
dp->coloursel_result.ok = false;
|
2015-08-22 13:49:02 +00:00
|
|
|
}
|
|
|
|
|
Restructure dlgcontrol as a struct with an anon union.
This gets rid of that awkward STANDARD_PREFIX system in which every
branch of the old 'union control' had to repeat all the generic
fields, and then call sites had to make an arbitrary decision about
which branch to access them through.
That was the best we could do before accepting C99 features in this
code base. But now we have anonymous unions, so we don't need to put
up with that nonsense any more!
'dlgcontrol' is now a struct rather than a union, and the generic
fields common to all control types are ordinary members of the struct,
so you don't have to refer to them as ctrl->generic.foo at all, just
ctrl->foo, which saves verbiage at the point of use.
The extra per-control fields are still held in structures named after
the control type, so you'll still say ctrl->listbox.height or
whatever. But now those structures are themselves members of an
anonymous union field following the generic fields, so those
sub-structures don't have to reiterate all the standard stuff too.
While I'm here, I've promoted 'context2' from an editbox-specific
field to a generic one (it just seems silly _not_ to allow any control
to have two context fields if it needs it). Also, I had to rename the
boolean field 'tabdelay' to avoid it clashing with the subsidiary
structure field 'tabdelay', now that the former isn't generic.tabdelay
any more.
2022-05-01 08:55:52 +00:00
|
|
|
uc->ctrl->handler(uc->ctrl, dp, dp->data, EVENT_CALLBACK);
|
2015-08-22 13:49:02 +00:00
|
|
|
|
|
|
|
gtk_widget_destroy(GTK_WIDGET(dialog));
|
|
|
|
}
|
|
|
|
|
|
|
|
#else /* GTK 1/2 coloursel response handlers */
|
|
|
|
|
2003-03-15 15:50:42 +00:00
|
|
|
static void coloursel_ok(GtkButton *button, gpointer data)
|
|
|
|
{
|
|
|
|
struct dlgparam *dp = (struct dlgparam *)data;
|
2015-08-08 16:29:02 +00:00
|
|
|
gpointer coloursel = g_object_get_data(G_OBJECT(button), "user-data");
|
|
|
|
struct uctrl *uc = g_object_get_data(G_OBJECT(coloursel), "user-data");
|
2015-08-22 13:49:02 +00:00
|
|
|
|
2015-08-08 16:32:15 +00:00
|
|
|
#if GTK_CHECK_VERSION(2,0,0)
|
|
|
|
{
|
Formatting: standardise on "func(\n", not "func\n(".
If the function name (or expression) in a function call or declaration
is itself so long that even the first argument doesn't fit after it on
the same line, or if that would leave so little space that it would be
silly to try to wrap all the run-on lines into a tall thin column,
then I used to do this
ludicrously_long_function_name
(arg1, arg2, arg3);
and now prefer this
ludicrously_long_function_name(
arg1, arg2, arg3);
I picked up the habit from Python, where the latter idiom is required
by Python's syntactic significance of newlines (you can write the
former if you use a backslash-continuation, but pretty much everyone
seems to agree that that's much uglier). But I've found it works well
in C as well: it makes it more obvious that the previous line is
incomplete, it gives you a tiny bit more space to wrap the following
lines into (the old idiom indents the _third_ line one space beyond
the second), and I generally turn out to agree with the knock-on
indentation decisions made by at least Emacs if you do it in the
middle of a complex expression. Plus, of course, using the _same_
idiom between C and Python means less state-switching.
So, while I'm making annoying indentation changes in general, this
seems like a good time to dig out all the cases of the old idiom in
this code, and switch them over to the new.
2022-08-03 19:48:46 +00:00
|
|
|
GtkColorSelection *cs = GTK_COLOR_SELECTION(
|
|
|
|
gtk_color_selection_dialog_get_color_selection(
|
|
|
|
GTK_COLOR_SELECTION_DIALOG(coloursel)));
|
2015-08-08 16:32:15 +00:00
|
|
|
GdkColor col;
|
|
|
|
gtk_color_selection_get_current_color(cs, &col);
|
|
|
|
dp->coloursel_result.r = col.red / 0x0100;
|
|
|
|
dp->coloursel_result.g = col.green / 0x0100;
|
|
|
|
dp->coloursel_result.b = col.blue / 0x0100;
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
{
|
Formatting: standardise on "func(\n", not "func\n(".
If the function name (or expression) in a function call or declaration
is itself so long that even the first argument doesn't fit after it on
the same line, or if that would leave so little space that it would be
silly to try to wrap all the run-on lines into a tall thin column,
then I used to do this
ludicrously_long_function_name
(arg1, arg2, arg3);
and now prefer this
ludicrously_long_function_name(
arg1, arg2, arg3);
I picked up the habit from Python, where the latter idiom is required
by Python's syntactic significance of newlines (you can write the
former if you use a backslash-continuation, but pretty much everyone
seems to agree that that's much uglier). But I've found it works well
in C as well: it makes it more obvious that the previous line is
incomplete, it gives you a tiny bit more space to wrap the following
lines into (the old idiom indents the _third_ line one space beyond
the second), and I generally turn out to agree with the knock-on
indentation decisions made by at least Emacs if you do it in the
middle of a complex expression. Plus, of course, using the _same_
idiom between C and Python means less state-switching.
So, while I'm making annoying indentation changes in general, this
seems like a good time to dig out all the cases of the old idiom in
this code, and switch them over to the new.
2022-08-03 19:48:46 +00:00
|
|
|
GtkColorSelection *cs = GTK_COLOR_SELECTION(
|
|
|
|
gtk_color_selection_dialog_get_color_selection(
|
|
|
|
GTK_COLOR_SELECTION_DIALOG(coloursel)));
|
2015-08-08 16:32:15 +00:00
|
|
|
gdouble cvals[4];
|
|
|
|
gtk_color_selection_get_color(cs, cvals);
|
|
|
|
dp->coloursel_result.r = (int) (255 * cvals[0]);
|
|
|
|
dp->coloursel_result.g = (int) (255 * cvals[1]);
|
|
|
|
dp->coloursel_result.b = (int) (255 * cvals[2]);
|
|
|
|
}
|
|
|
|
#endif
|
2018-10-29 19:50:29 +00:00
|
|
|
dp->coloursel_result.ok = true;
|
Restructure dlgcontrol as a struct with an anon union.
This gets rid of that awkward STANDARD_PREFIX system in which every
branch of the old 'union control' had to repeat all the generic
fields, and then call sites had to make an arbitrary decision about
which branch to access them through.
That was the best we could do before accepting C99 features in this
code base. But now we have anonymous unions, so we don't need to put
up with that nonsense any more!
'dlgcontrol' is now a struct rather than a union, and the generic
fields common to all control types are ordinary members of the struct,
so you don't have to refer to them as ctrl->generic.foo at all, just
ctrl->foo, which saves verbiage at the point of use.
The extra per-control fields are still held in structures named after
the control type, so you'll still say ctrl->listbox.height or
whatever. But now those structures are themselves members of an
anonymous union field following the generic fields, so those
sub-structures don't have to reiterate all the standard stuff too.
While I'm here, I've promoted 'context2' from an editbox-specific
field to a generic one (it just seems silly _not_ to allow any control
to have two context fields if it needs it). Also, I had to rename the
boolean field 'tabdelay' to avoid it clashing with the subsidiary
structure field 'tabdelay', now that the former isn't generic.tabdelay
any more.
2022-05-01 08:55:52 +00:00
|
|
|
uc->ctrl->handler(uc->ctrl, dp, dp->data, EVENT_CALLBACK);
|
2003-03-15 15:50:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void coloursel_cancel(GtkButton *button, gpointer data)
|
|
|
|
{
|
|
|
|
struct dlgparam *dp = (struct dlgparam *)data;
|
2015-08-08 16:29:02 +00:00
|
|
|
gpointer coloursel = g_object_get_data(G_OBJECT(button), "user-data");
|
|
|
|
struct uctrl *uc = g_object_get_data(G_OBJECT(coloursel), "user-data");
|
2018-10-29 19:50:29 +00:00
|
|
|
dp->coloursel_result.ok = false;
|
Restructure dlgcontrol as a struct with an anon union.
This gets rid of that awkward STANDARD_PREFIX system in which every
branch of the old 'union control' had to repeat all the generic
fields, and then call sites had to make an arbitrary decision about
which branch to access them through.
That was the best we could do before accepting C99 features in this
code base. But now we have anonymous unions, so we don't need to put
up with that nonsense any more!
'dlgcontrol' is now a struct rather than a union, and the generic
fields common to all control types are ordinary members of the struct,
so you don't have to refer to them as ctrl->generic.foo at all, just
ctrl->foo, which saves verbiage at the point of use.
The extra per-control fields are still held in structures named after
the control type, so you'll still say ctrl->listbox.height or
whatever. But now those structures are themselves members of an
anonymous union field following the generic fields, so those
sub-structures don't have to reiterate all the standard stuff too.
While I'm here, I've promoted 'context2' from an editbox-specific
field to a generic one (it just seems silly _not_ to allow any control
to have two context fields if it needs it). Also, I had to rename the
boolean field 'tabdelay' to avoid it clashing with the subsidiary
structure field 'tabdelay', now that the former isn't generic.tabdelay
any more.
2022-05-01 08:55:52 +00:00
|
|
|
uc->ctrl->handler(uc->ctrl, dp, dp->data, EVENT_CALLBACK);
|
2003-03-15 15:50:42 +00:00
|
|
|
}
|
|
|
|
|
2015-08-22 13:49:02 +00:00
|
|
|
#endif /* end of coloursel response handlers */
|
|
|
|
|
2003-03-15 15:50:42 +00:00
|
|
|
static void filefont_clicked(GtkButton *button, gpointer data)
|
|
|
|
{
|
|
|
|
struct dlgparam *dp = (struct dlgparam *)data;
|
|
|
|
struct uctrl *uc = dlg_find_bywidget(dp, GTK_WIDGET(button));
|
|
|
|
|
Restructure dlgcontrol as a struct with an anon union.
This gets rid of that awkward STANDARD_PREFIX system in which every
branch of the old 'union control' had to repeat all the generic
fields, and then call sites had to make an arbitrary decision about
which branch to access them through.
That was the best we could do before accepting C99 features in this
code base. But now we have anonymous unions, so we don't need to put
up with that nonsense any more!
'dlgcontrol' is now a struct rather than a union, and the generic
fields common to all control types are ordinary members of the struct,
so you don't have to refer to them as ctrl->generic.foo at all, just
ctrl->foo, which saves verbiage at the point of use.
The extra per-control fields are still held in structures named after
the control type, so you'll still say ctrl->listbox.height or
whatever. But now those structures are themselves members of an
anonymous union field following the generic fields, so those
sub-structures don't have to reiterate all the standard stuff too.
While I'm here, I've promoted 'context2' from an editbox-specific
field to a generic one (it just seems silly _not_ to allow any control
to have two context fields if it needs it). Also, I had to rename the
boolean field 'tabdelay' to avoid it clashing with the subsidiary
structure field 'tabdelay', now that the former isn't generic.tabdelay
any more.
2022-05-01 08:55:52 +00:00
|
|
|
if (uc->ctrl->type == CTRL_FILESELECT) {
|
2015-08-08 16:34:25 +00:00
|
|
|
#ifdef USE_GTK_FILE_CHOOSER_DIALOG
|
Formatting: standardise on "func(\n", not "func\n(".
If the function name (or expression) in a function call or declaration
is itself so long that even the first argument doesn't fit after it on
the same line, or if that would leave so little space that it would be
silly to try to wrap all the run-on lines into a tall thin column,
then I used to do this
ludicrously_long_function_name
(arg1, arg2, arg3);
and now prefer this
ludicrously_long_function_name(
arg1, arg2, arg3);
I picked up the habit from Python, where the latter idiom is required
by Python's syntactic significance of newlines (you can write the
former if you use a backslash-continuation, but pretty much everyone
seems to agree that that's much uglier). But I've found it works well
in C as well: it makes it more obvious that the previous line is
incomplete, it gives you a tiny bit more space to wrap the following
lines into (the old idiom indents the _third_ line one space beyond
the second), and I generally turn out to agree with the knock-on
indentation decisions made by at least Emacs if you do it in the
middle of a complex expression. Plus, of course, using the _same_
idiom between C and Python means less state-switching.
So, while I'm making annoying indentation changes in general, this
seems like a good time to dig out all the cases of the old idiom in
this code, and switch them over to the new.
2022-08-03 19:48:46 +00:00
|
|
|
GtkWidget *filechoose = gtk_file_chooser_dialog_new(
|
|
|
|
uc->ctrl->fileselect.title, GTK_WINDOW(dp->window),
|
|
|
|
(uc->ctrl->fileselect.for_writing ?
|
|
|
|
GTK_FILE_CHOOSER_ACTION_SAVE :
|
|
|
|
GTK_FILE_CHOOSER_ACTION_OPEN),
|
|
|
|
STANDARD_CANCEL_LABEL, GTK_RESPONSE_CANCEL,
|
|
|
|
STANDARD_OPEN_LABEL, GTK_RESPONSE_ACCEPT,
|
|
|
|
(const gchar *)NULL);
|
2019-09-08 19:29:00 +00:00
|
|
|
gtk_window_set_modal(GTK_WINDOW(filechoose), true);
|
|
|
|
g_object_set_data(G_OBJECT(filechoose), "user-data", (gpointer)uc);
|
|
|
|
g_signal_connect(G_OBJECT(filechoose), "response",
|
2015-08-08 16:34:25 +00:00
|
|
|
G_CALLBACK(filechoose_response), (gpointer)dp);
|
2019-09-08 19:29:00 +00:00
|
|
|
gtk_widget_show(filechoose);
|
2015-08-08 16:34:25 +00:00
|
|
|
#else
|
2019-09-08 19:29:00 +00:00
|
|
|
GtkWidget *filesel =
|
|
|
|
gtk_file_selection_new(uc->ctrl->fileselect.title);
|
|
|
|
gtk_window_set_modal(GTK_WINDOW(filesel), true);
|
Formatting: standardise on "func(\n", not "func\n(".
If the function name (or expression) in a function call or declaration
is itself so long that even the first argument doesn't fit after it on
the same line, or if that would leave so little space that it would be
silly to try to wrap all the run-on lines into a tall thin column,
then I used to do this
ludicrously_long_function_name
(arg1, arg2, arg3);
and now prefer this
ludicrously_long_function_name(
arg1, arg2, arg3);
I picked up the habit from Python, where the latter idiom is required
by Python's syntactic significance of newlines (you can write the
former if you use a backslash-continuation, but pretty much everyone
seems to agree that that's much uglier). But I've found it works well
in C as well: it makes it more obvious that the previous line is
incomplete, it gives you a tiny bit more space to wrap the following
lines into (the old idiom indents the _third_ line one space beyond
the second), and I generally turn out to agree with the knock-on
indentation decisions made by at least Emacs if you do it in the
middle of a complex expression. Plus, of course, using the _same_
idiom between C and Python means less state-switching.
So, while I'm making annoying indentation changes in general, this
seems like a good time to dig out all the cases of the old idiom in
this code, and switch them over to the new.
2022-08-03 19:48:46 +00:00
|
|
|
g_object_set_data(
|
|
|
|
G_OBJECT(GTK_FILE_SELECTION(filesel)->ok_button), "user-data",
|
|
|
|
(gpointer)filesel);
|
2015-08-08 16:29:02 +00:00
|
|
|
g_object_set_data(G_OBJECT(filesel), "user-data", (gpointer)uc);
|
Formatting: standardise on "func(\n", not "func\n(".
If the function name (or expression) in a function call or declaration
is itself so long that even the first argument doesn't fit after it on
the same line, or if that would leave so little space that it would be
silly to try to wrap all the run-on lines into a tall thin column,
then I used to do this
ludicrously_long_function_name
(arg1, arg2, arg3);
and now prefer this
ludicrously_long_function_name(
arg1, arg2, arg3);
I picked up the habit from Python, where the latter idiom is required
by Python's syntactic significance of newlines (you can write the
former if you use a backslash-continuation, but pretty much everyone
seems to agree that that's much uglier). But I've found it works well
in C as well: it makes it more obvious that the previous line is
incomplete, it gives you a tiny bit more space to wrap the following
lines into (the old idiom indents the _third_ line one space beyond
the second), and I generally turn out to agree with the knock-on
indentation decisions made by at least Emacs if you do it in the
middle of a complex expression. Plus, of course, using the _same_
idiom between C and Python means less state-switching.
So, while I'm making annoying indentation changes in general, this
seems like a good time to dig out all the cases of the old idiom in
this code, and switch them over to the new.
2022-08-03 19:48:46 +00:00
|
|
|
g_signal_connect(
|
|
|
|
G_OBJECT(GTK_FILE_SELECTION(filesel)->ok_button), "clicked",
|
|
|
|
G_CALLBACK(filesel_ok), (gpointer)dp);
|
|
|
|
g_signal_connect_swapped(
|
|
|
|
G_OBJECT(GTK_FILE_SELECTION(filesel)->ok_button), "clicked",
|
|
|
|
G_CALLBACK(gtk_widget_destroy), (gpointer)filesel);
|
|
|
|
g_signal_connect_swapped(
|
|
|
|
G_OBJECT(GTK_FILE_SELECTION(filesel)->cancel_button), "clicked",
|
|
|
|
G_CALLBACK(gtk_widget_destroy), (gpointer)filesel);
|
2019-09-08 19:29:00 +00:00
|
|
|
gtk_widget_show(filesel);
|
2015-08-08 16:34:25 +00:00
|
|
|
#endif
|
2003-03-15 15:50:42 +00:00
|
|
|
}
|
|
|
|
|
Restructure dlgcontrol as a struct with an anon union.
This gets rid of that awkward STANDARD_PREFIX system in which every
branch of the old 'union control' had to repeat all the generic
fields, and then call sites had to make an arbitrary decision about
which branch to access them through.
That was the best we could do before accepting C99 features in this
code base. But now we have anonymous unions, so we don't need to put
up with that nonsense any more!
'dlgcontrol' is now a struct rather than a union, and the generic
fields common to all control types are ordinary members of the struct,
so you don't have to refer to them as ctrl->generic.foo at all, just
ctrl->foo, which saves verbiage at the point of use.
The extra per-control fields are still held in structures named after
the control type, so you'll still say ctrl->listbox.height or
whatever. But now those structures are themselves members of an
anonymous union field following the generic fields, so those
sub-structures don't have to reiterate all the standard stuff too.
While I'm here, I've promoted 'context2' from an editbox-specific
field to a generic one (it just seems silly _not_ to allow any control
to have two context fields if it needs it). Also, I had to rename the
boolean field 'tabdelay' to avoid it clashing with the subsidiary
structure field 'tabdelay', now that the former isn't generic.tabdelay
any more.
2022-05-01 08:55:52 +00:00
|
|
|
if (uc->ctrl->type == CTRL_FONTSELECT) {
|
2007-01-25 19:33:29 +00:00
|
|
|
const gchar *fontname = gtk_entry_get_text(GTK_ENTRY(uc->entry));
|
2008-04-04 10:56:26 +00:00
|
|
|
|
|
|
|
#if !GTK_CHECK_VERSION(2,0,0)
|
|
|
|
|
2019-09-08 19:29:00 +00:00
|
|
|
/*
|
|
|
|
* Use the GTK 1 standard font selector.
|
|
|
|
*/
|
|
|
|
|
|
|
|
gchar *spacings[] = { "c", "m", NULL };
|
|
|
|
GtkWidget *fontsel =
|
|
|
|
gtk_font_selection_dialog_new("Select a font");
|
|
|
|
gtk_window_set_modal(GTK_WINDOW(fontsel), true);
|
Formatting: standardise on "func(\n", not "func\n(".
If the function name (or expression) in a function call or declaration
is itself so long that even the first argument doesn't fit after it on
the same line, or if that would leave so little space that it would be
silly to try to wrap all the run-on lines into a tall thin column,
then I used to do this
ludicrously_long_function_name
(arg1, arg2, arg3);
and now prefer this
ludicrously_long_function_name(
arg1, arg2, arg3);
I picked up the habit from Python, where the latter idiom is required
by Python's syntactic significance of newlines (you can write the
former if you use a backslash-continuation, but pretty much everyone
seems to agree that that's much uglier). But I've found it works well
in C as well: it makes it more obvious that the previous line is
incomplete, it gives you a tiny bit more space to wrap the following
lines into (the old idiom indents the _third_ line one space beyond
the second), and I generally turn out to agree with the knock-on
indentation decisions made by at least Emacs if you do it in the
middle of a complex expression. Plus, of course, using the _same_
idiom between C and Python means less state-switching.
So, while I'm making annoying indentation changes in general, this
seems like a good time to dig out all the cases of the old idiom in
this code, and switch them over to the new.
2022-08-03 19:48:46 +00:00
|
|
|
gtk_font_selection_dialog_set_filter(
|
|
|
|
GTK_FONT_SELECTION_DIALOG(fontsel),
|
|
|
|
GTK_FONT_FILTER_BASE, GTK_FONT_ALL,
|
|
|
|
NULL, NULL, NULL, NULL, spacings, NULL);
|
|
|
|
if (!gtk_font_selection_dialog_set_font_name(
|
|
|
|
GTK_FONT_SELECTION_DIALOG(fontsel), fontname)) {
|
2008-04-04 10:56:26 +00:00
|
|
|
/*
|
|
|
|
* If the font name wasn't found as it was, try opening
|
|
|
|
* it and extracting its FONT property. This should
|
|
|
|
* have the effect of mapping short aliases into true
|
|
|
|
* XLFDs.
|
|
|
|
*/
|
|
|
|
GdkFont *font = gdk_font_load(fontname);
|
|
|
|
if (font) {
|
|
|
|
XFontStruct *xfs = GDK_FONT_XFONT(font);
|
Basic support for running under GDK Wayland back end.
GTK 3 PuTTY/pterm has always assumed that if it was compiled with
_support_ for talking to the raw X11 layer underneath GTK and GDK,
then it was entitled to expect that raw X11 layer to exist at all
times, i.e. that GDK_DISPLAY_XDISPLAY would return a meaningful X
display that it could do useful things with. So if you ran it over the
GDK Wayland backend, it would immediately segfault.
Modern GTK applications need to cope with multiple GDK backends at run
time. It's fine for GTK PuTTY to _contain_ the code to find and use
underlying X11 primitives like the display and the X window id, but it
should be prepared to find that it's running on Wayland (or something
else again!) so those functions don't return anything useful - in
which case it should degrade gracefully to the subset of functionality
that can be accessed through backend-independent GTK calls.
Accordingly, I've centralised the use of GDK_DISPLAY_XDISPLAY into a
support function get_x_display() in gtkmisc.c, which starts by
checking that there actually is one first. All previous direct uses of
GDK_*_XDISPLAY now go via that function, and check the result for NULL
afterwards. (To save faffing about calling that function too many
times, I'm also caching the display pointer in more places, and
passing it as an extra argument to various subfunctions, mostly in
gtkfont.c.)
Similarly, the get_windowid() function that retrieves the window id to
put in the environment of pterm's child process has to be prepared for
there not to be a window id.
This isn't a complete fix for all Wayland-related problems. The other
one I'm currently aware of is that the default font is "server:fixed",
which is a bad default now that it won't be available on all backends.
And I expect that further problems will show up with more testing. But
it's a start.
2018-05-09 08:18:20 +00:00
|
|
|
Display *disp = get_x11_display();
|
2008-04-04 10:56:26 +00:00
|
|
|
Atom fontprop = XInternAtom(disp, "FONT", False);
|
|
|
|
unsigned long ret;
|
Basic support for running under GDK Wayland back end.
GTK 3 PuTTY/pterm has always assumed that if it was compiled with
_support_ for talking to the raw X11 layer underneath GTK and GDK,
then it was entitled to expect that raw X11 layer to exist at all
times, i.e. that GDK_DISPLAY_XDISPLAY would return a meaningful X
display that it could do useful things with. So if you ran it over the
GDK Wayland backend, it would immediately segfault.
Modern GTK applications need to cope with multiple GDK backends at run
time. It's fine for GTK PuTTY to _contain_ the code to find and use
underlying X11 primitives like the display and the X window id, but it
should be prepared to find that it's running on Wayland (or something
else again!) so those functions don't return anything useful - in
which case it should degrade gracefully to the subset of functionality
that can be accessed through backend-independent GTK calls.
Accordingly, I've centralised the use of GDK_DISPLAY_XDISPLAY into a
support function get_x_display() in gtkmisc.c, which starts by
checking that there actually is one first. All previous direct uses of
GDK_*_XDISPLAY now go via that function, and check the result for NULL
afterwards. (To save faffing about calling that function too many
times, I'm also caching the display pointer in more places, and
passing it as an extra argument to various subfunctions, mostly in
gtkfont.c.)
Similarly, the get_windowid() function that retrieves the window id to
put in the environment of pterm's child process has to be prepared for
there not to be a window id.
This isn't a complete fix for all Wayland-related problems. The other
one I'm currently aware of is that the default font is "server:fixed",
which is a bad default now that it won't be available on all backends.
And I expect that further problems will show up with more testing. But
it's a start.
2018-05-09 08:18:20 +00:00
|
|
|
|
|
|
|
assert(disp); /* this is GTK1! */
|
|
|
|
|
2019-09-08 19:29:00 +00:00
|
|
|
gdk_font_ref(font);
|
2008-04-04 10:56:26 +00:00
|
|
|
if (XGetFontProperty(xfs, fontprop, &ret)) {
|
|
|
|
char *name = XGetAtomName(disp, (Atom)ret);
|
|
|
|
if (name)
|
Formatting: standardise on "func(\n", not "func\n(".
If the function name (or expression) in a function call or declaration
is itself so long that even the first argument doesn't fit after it on
the same line, or if that would leave so little space that it would be
silly to try to wrap all the run-on lines into a tall thin column,
then I used to do this
ludicrously_long_function_name
(arg1, arg2, arg3);
and now prefer this
ludicrously_long_function_name(
arg1, arg2, arg3);
I picked up the habit from Python, where the latter idiom is required
by Python's syntactic significance of newlines (you can write the
former if you use a backslash-continuation, but pretty much everyone
seems to agree that that's much uglier). But I've found it works well
in C as well: it makes it more obvious that the previous line is
incomplete, it gives you a tiny bit more space to wrap the following
lines into (the old idiom indents the _third_ line one space beyond
the second), and I generally turn out to agree with the knock-on
indentation decisions made by at least Emacs if you do it in the
middle of a complex expression. Plus, of course, using the _same_
idiom between C and Python means less state-switching.
So, while I'm making annoying indentation changes in general, this
seems like a good time to dig out all the cases of the old idiom in
this code, and switch them over to the new.
2022-08-03 19:48:46 +00:00
|
|
|
gtk_font_selection_dialog_set_font_name(
|
|
|
|
GTK_FONT_SELECTION_DIALOG(fontsel), name);
|
2008-04-04 10:56:26 +00:00
|
|
|
}
|
|
|
|
gdk_font_unref(font);
|
|
|
|
}
|
|
|
|
}
|
Formatting: standardise on "func(\n", not "func\n(".
If the function name (or expression) in a function call or declaration
is itself so long that even the first argument doesn't fit after it on
the same line, or if that would leave so little space that it would be
silly to try to wrap all the run-on lines into a tall thin column,
then I used to do this
ludicrously_long_function_name
(arg1, arg2, arg3);
and now prefer this
ludicrously_long_function_name(
arg1, arg2, arg3);
I picked up the habit from Python, where the latter idiom is required
by Python's syntactic significance of newlines (you can write the
former if you use a backslash-continuation, but pretty much everyone
seems to agree that that's much uglier). But I've found it works well
in C as well: it makes it more obvious that the previous line is
incomplete, it gives you a tiny bit more space to wrap the following
lines into (the old idiom indents the _third_ line one space beyond
the second), and I generally turn out to agree with the knock-on
indentation decisions made by at least Emacs if you do it in the
middle of a complex expression. Plus, of course, using the _same_
idiom between C and Python means less state-switching.
So, while I'm making annoying indentation changes in general, this
seems like a good time to dig out all the cases of the old idiom in
this code, and switch them over to the new.
2022-08-03 19:48:46 +00:00
|
|
|
g_object_set_data(
|
|
|
|
G_OBJECT(GTK_FONT_SELECTION_DIALOG(fontsel)->ok_button),
|
|
|
|
"user-data", (gpointer)fontsel);
|
2015-08-08 16:29:02 +00:00
|
|
|
g_object_set_data(G_OBJECT(fontsel), "user-data", (gpointer)uc);
|
Formatting: standardise on "func(\n", not "func\n(".
If the function name (or expression) in a function call or declaration
is itself so long that even the first argument doesn't fit after it on
the same line, or if that would leave so little space that it would be
silly to try to wrap all the run-on lines into a tall thin column,
then I used to do this
ludicrously_long_function_name
(arg1, arg2, arg3);
and now prefer this
ludicrously_long_function_name(
arg1, arg2, arg3);
I picked up the habit from Python, where the latter idiom is required
by Python's syntactic significance of newlines (you can write the
former if you use a backslash-continuation, but pretty much everyone
seems to agree that that's much uglier). But I've found it works well
in C as well: it makes it more obvious that the previous line is
incomplete, it gives you a tiny bit more space to wrap the following
lines into (the old idiom indents the _third_ line one space beyond
the second), and I generally turn out to agree with the knock-on
indentation decisions made by at least Emacs if you do it in the
middle of a complex expression. Plus, of course, using the _same_
idiom between C and Python means less state-switching.
So, while I'm making annoying indentation changes in general, this
seems like a good time to dig out all the cases of the old idiom in
this code, and switch them over to the new.
2022-08-03 19:48:46 +00:00
|
|
|
g_signal_connect(
|
|
|
|
G_OBJECT(GTK_FONT_SELECTION_DIALOG(fontsel)->ok_button),
|
|
|
|
"clicked", G_CALLBACK(fontsel_ok), (gpointer)dp);
|
|
|
|
g_signal_connect_swapped(
|
|
|
|
G_OBJECT(GTK_FONT_SELECTION_DIALOG(fontsel)->ok_button),
|
|
|
|
"clicked", G_CALLBACK(gtk_widget_destroy),
|
|
|
|
(gpointer)fontsel);
|
|
|
|
g_signal_connect_swapped(
|
|
|
|
G_OBJECT(GTK_FONT_SELECTION_DIALOG(fontsel)->cancel_button),
|
|
|
|
"clicked", G_CALLBACK(gtk_widget_destroy),
|
|
|
|
(gpointer)fontsel);
|
2019-09-08 19:29:00 +00:00
|
|
|
gtk_widget_show(fontsel);
|
2008-04-04 10:56:26 +00:00
|
|
|
|
|
|
|
#else /* !GTK_CHECK_VERSION(2,0,0) */
|
|
|
|
|
2019-09-08 19:29:00 +00:00
|
|
|
/*
|
2022-01-22 15:38:53 +00:00
|
|
|
* Use the unifontsel code provided in unifont.c.
|
2019-09-08 19:29:00 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
unifontsel *fontsel = unifontsel_new("Select a font");
|
2008-04-04 10:56:26 +00:00
|
|
|
|
2019-09-08 19:29:00 +00:00
|
|
|
gtk_window_set_modal(fontsel->window, true);
|
|
|
|
unifontsel_set_name(fontsel, fontname);
|
2008-03-25 21:49:14 +00:00
|
|
|
|
2015-08-08 16:29:02 +00:00
|
|
|
g_object_set_data(G_OBJECT(fontsel->ok_button),
|
|
|
|
"user-data", (gpointer)fontsel);
|
2019-09-08 19:29:00 +00:00
|
|
|
fontsel->user_data = uc;
|
2015-08-08 16:29:02 +00:00
|
|
|
g_signal_connect(G_OBJECT(fontsel->ok_button), "clicked",
|
|
|
|
G_CALLBACK(fontsel_ok), (gpointer)dp);
|
|
|
|
g_signal_connect_swapped(G_OBJECT(fontsel->ok_button), "clicked",
|
|
|
|
G_CALLBACK(unifontsel_destroy),
|
|
|
|
(gpointer)fontsel);
|
|
|
|
g_signal_connect_swapped(G_OBJECT(fontsel->cancel_button),"clicked",
|
|
|
|
G_CALLBACK(unifontsel_destroy),
|
|
|
|
(gpointer)fontsel);
|
2008-03-25 21:49:14 +00:00
|
|
|
|
2019-09-08 19:29:00 +00:00
|
|
|
gtk_widget_show(GTK_WIDGET(fontsel->window));
|
2008-04-04 10:56:26 +00:00
|
|
|
|
|
|
|
#endif /* !GTK_CHECK_VERSION(2,0,0) */
|
|
|
|
|
2003-03-15 15:50:42 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-08-23 14:01:07 +00:00
|
|
|
#if !GTK_CHECK_VERSION(3,0,0)
|
2003-03-22 17:00:06 +00:00
|
|
|
static void label_sizealloc(GtkWidget *widget, GtkAllocation *alloc,
|
2019-09-08 19:29:00 +00:00
|
|
|
gpointer data)
|
2003-03-22 17:00:06 +00:00
|
|
|
{
|
|
|
|
struct dlgparam *dp = (struct dlgparam *)data;
|
|
|
|
struct uctrl *uc = dlg_find_bywidget(dp, widget);
|
|
|
|
|
2015-08-08 17:02:01 +00:00
|
|
|
gtk_widget_set_size_request(uc->text, alloc->width, -1);
|
Restructure dlgcontrol as a struct with an anon union.
This gets rid of that awkward STANDARD_PREFIX system in which every
branch of the old 'union control' had to repeat all the generic
fields, and then call sites had to make an arbitrary decision about
which branch to access them through.
That was the best we could do before accepting C99 features in this
code base. But now we have anonymous unions, so we don't need to put
up with that nonsense any more!
'dlgcontrol' is now a struct rather than a union, and the generic
fields common to all control types are ordinary members of the struct,
so you don't have to refer to them as ctrl->generic.foo at all, just
ctrl->foo, which saves verbiage at the point of use.
The extra per-control fields are still held in structures named after
the control type, so you'll still say ctrl->listbox.height or
whatever. But now those structures are themselves members of an
anonymous union field following the generic fields, so those
sub-structures don't have to reiterate all the standard stuff too.
While I'm here, I've promoted 'context2' from an editbox-specific
field to a generic one (it just seems silly _not_ to allow any control
to have two context fields if it needs it). Also, I had to rename the
boolean field 'tabdelay' to avoid it clashing with the subsidiary
structure field 'tabdelay', now that the former isn't generic.tabdelay
any more.
2022-05-01 08:55:52 +00:00
|
|
|
gtk_label_set_text(GTK_LABEL(uc->text), uc->ctrl->label);
|
2015-08-08 16:29:02 +00:00
|
|
|
g_signal_handler_disconnect(G_OBJECT(uc->text), uc->textsig);
|
2003-03-22 17:00:06 +00:00
|
|
|
}
|
2015-08-23 14:01:07 +00:00
|
|
|
#endif
|
2003-03-22 17:00:06 +00:00
|
|
|
|
2003-03-15 15:50:42 +00:00
|
|
|
/* ----------------------------------------------------------------------
|
2003-03-13 19:52:28 +00:00
|
|
|
* This function does the main layout work: it reads a controlset,
|
|
|
|
* it creates the relevant GTK controls, and returns a GtkWidget
|
|
|
|
* containing the result. (This widget might be a title of some
|
|
|
|
* sort, it might be a Columns containing many controls, or it
|
|
|
|
* might be a GtkFrame containing a Columns; whatever it is, it's
|
|
|
|
* definitely a GtkWidget and should probably be added to a
|
|
|
|
* GtkVbox.)
|
2019-09-08 19:29:00 +00:00
|
|
|
*
|
2003-03-16 12:37:48 +00:00
|
|
|
* `win' is required for setting the default button. If it is
|
|
|
|
* non-NULL, all buttons created will be default-capable (so they
|
|
|
|
* have extra space round them for the default highlight).
|
2003-03-13 19:52:28 +00:00
|
|
|
*/
|
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
|
|
|
GtkWidget *layout_ctrls(
|
|
|
|
struct dlgparam *dp, struct selparam *sp, struct Shortcuts *scs,
|
|
|
|
struct controlset *s, GtkWindow *win)
|
2003-03-13 19:52:28 +00:00
|
|
|
{
|
|
|
|
Columns *cols;
|
|
|
|
GtkWidget *ret;
|
|
|
|
int i;
|
|
|
|
|
2018-12-01 14:13:37 +00:00
|
|
|
if (!s->boxname) {
|
2003-03-13 19:52:28 +00:00
|
|
|
/* This controlset is a panel title. */
|
2018-12-01 14:13:37 +00:00
|
|
|
assert(s->boxtitle);
|
2003-03-13 19:52:28 +00:00
|
|
|
return gtk_label_new(s->boxtitle);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Otherwise, we expect to be laying out actual controls, so
|
|
|
|
* we'll start by creating a Columns for the purpose.
|
|
|
|
*/
|
|
|
|
cols = COLUMNS(columns_new(4));
|
|
|
|
ret = GTK_WIDGET(cols);
|
|
|
|
gtk_widget_show(ret);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Create a containing frame if we have a box name.
|
|
|
|
*/
|
|
|
|
if (*s->boxname) {
|
|
|
|
ret = gtk_frame_new(s->boxtitle); /* NULL is valid here */
|
|
|
|
gtk_container_set_border_width(GTK_CONTAINER(cols), 4);
|
|
|
|
gtk_container_add(GTK_CONTAINER(ret), GTK_WIDGET(cols));
|
|
|
|
gtk_widget_show(ret);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Now iterate through the controls themselves, create them,
|
|
|
|
* and add them to the Columns.
|
|
|
|
*/
|
|
|
|
for (i = 0; i < s->ncontrols; i++) {
|
2022-05-01 08:48:38 +00:00
|
|
|
dlgcontrol *ctrl = s->ctrls[i];
|
2019-09-08 19:29:00 +00:00
|
|
|
struct uctrl *uc;
|
|
|
|
bool left = false;
|
2003-03-13 19:52:28 +00:00
|
|
|
GtkWidget *w = NULL;
|
|
|
|
|
Restructure dlgcontrol as a struct with an anon union.
This gets rid of that awkward STANDARD_PREFIX system in which every
branch of the old 'union control' had to repeat all the generic
fields, and then call sites had to make an arbitrary decision about
which branch to access them through.
That was the best we could do before accepting C99 features in this
code base. But now we have anonymous unions, so we don't need to put
up with that nonsense any more!
'dlgcontrol' is now a struct rather than a union, and the generic
fields common to all control types are ordinary members of the struct,
so you don't have to refer to them as ctrl->generic.foo at all, just
ctrl->foo, which saves verbiage at the point of use.
The extra per-control fields are still held in structures named after
the control type, so you'll still say ctrl->listbox.height or
whatever. But now those structures are themselves members of an
anonymous union field following the generic fields, so those
sub-structures don't have to reiterate all the standard stuff too.
While I'm here, I've promoted 'context2' from an editbox-specific
field to a generic one (it just seems silly _not_ to allow any control
to have two context fields if it needs it). Also, I had to rename the
boolean field 'tabdelay' to avoid it clashing with the subsidiary
structure field 'tabdelay', now that the former isn't generic.tabdelay
any more.
2022-05-01 08:55:52 +00:00
|
|
|
switch (ctrl->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_COLUMNS: {
|
|
|
|
static const int simplecols[1] = { 100 };
|
|
|
|
columns_set_cols(cols, ctrl->columns.ncols,
|
|
|
|
(ctrl->columns.percentages ?
|
|
|
|
ctrl->columns.percentages : simplecols));
|
2003-03-13 19:52:28 +00:00
|
|
|
continue; /* no actual control created */
|
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_TABDELAY: {
|
|
|
|
struct uctrl *uc = dlg_find_byctrl(dp, ctrl->tabdelay.ctrl);
|
|
|
|
if (uc)
|
|
|
|
columns_taborder_last(cols, uc->toplevel);
|
2003-03-13 19:52:28 +00:00
|
|
|
continue; /* no actual control created */
|
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
|
|
|
}
|
2003-03-16 12:37:48 +00:00
|
|
|
|
2019-09-08 19:29:00 +00:00
|
|
|
uc = snew(struct uctrl);
|
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
|
|
|
uc->sp = sp;
|
2019-09-08 19:29:00 +00:00
|
|
|
uc->ctrl = ctrl;
|
|
|
|
uc->buttons = NULL;
|
|
|
|
uc->entry = NULL;
|
2008-05-31 19:23:45 +00:00
|
|
|
#if !GTK_CHECK_VERSION(2,4,0)
|
2019-09-08 19:29:00 +00:00
|
|
|
uc->list = uc->menu = uc->optmenu = NULL;
|
2008-04-04 10:56:26 +00:00
|
|
|
#else
|
2019-09-08 19:29:00 +00:00
|
|
|
uc->combo = NULL;
|
2008-05-31 19:23:45 +00:00
|
|
|
#endif
|
|
|
|
#if GTK_CHECK_VERSION(2,0,0)
|
2019-09-08 19:29:00 +00:00
|
|
|
uc->treeview = NULL;
|
|
|
|
uc->listmodel = NULL;
|
2008-04-04 10:56:26 +00:00
|
|
|
#endif
|
2019-09-08 19:29:00 +00:00
|
|
|
uc->button = uc->text = NULL;
|
|
|
|
uc->label = NULL;
|
2007-03-27 18:16:36 +00:00
|
|
|
uc->nclicks = 0;
|
2003-03-16 12:37:48 +00:00
|
|
|
|
Restructure dlgcontrol as a struct with an anon union.
This gets rid of that awkward STANDARD_PREFIX system in which every
branch of the old 'union control' had to repeat all the generic
fields, and then call sites had to make an arbitrary decision about
which branch to access them through.
That was the best we could do before accepting C99 features in this
code base. But now we have anonymous unions, so we don't need to put
up with that nonsense any more!
'dlgcontrol' is now a struct rather than a union, and the generic
fields common to all control types are ordinary members of the struct,
so you don't have to refer to them as ctrl->generic.foo at all, just
ctrl->foo, which saves verbiage at the point of use.
The extra per-control fields are still held in structures named after
the control type, so you'll still say ctrl->listbox.height or
whatever. But now those structures are themselves members of an
anonymous union field following the generic fields, so those
sub-structures don't have to reiterate all the standard stuff too.
While I'm here, I've promoted 'context2' from an editbox-specific
field to a generic one (it just seems silly _not_ to allow any control
to have two context fields if it needs it). Also, I had to rename the
boolean field 'tabdelay' to avoid it clashing with the subsidiary
structure field 'tabdelay', now that the former isn't generic.tabdelay
any more.
2022-05-01 08:55:52 +00:00
|
|
|
switch (ctrl->type) {
|
2003-03-13 19:52:28 +00:00
|
|
|
case CTRL_BUTTON:
|
Restructure dlgcontrol as a struct with an anon union.
This gets rid of that awkward STANDARD_PREFIX system in which every
branch of the old 'union control' had to repeat all the generic
fields, and then call sites had to make an arbitrary decision about
which branch to access them through.
That was the best we could do before accepting C99 features in this
code base. But now we have anonymous unions, so we don't need to put
up with that nonsense any more!
'dlgcontrol' is now a struct rather than a union, and the generic
fields common to all control types are ordinary members of the struct,
so you don't have to refer to them as ctrl->generic.foo at all, just
ctrl->foo, which saves verbiage at the point of use.
The extra per-control fields are still held in structures named after
the control type, so you'll still say ctrl->listbox.height or
whatever. But now those structures are themselves members of an
anonymous union field following the generic fields, so those
sub-structures don't have to reiterate all the standard stuff too.
While I'm here, I've promoted 'context2' from an editbox-specific
field to a generic one (it just seems silly _not_ to allow any control
to have two context fields if it needs it). Also, I had to rename the
boolean field 'tabdelay' to avoid it clashing with the subsidiary
structure field 'tabdelay', now that the former isn't generic.tabdelay
any more.
2022-05-01 08:55:52 +00:00
|
|
|
w = gtk_button_new_with_label(ctrl->label);
|
2019-09-08 19:29:00 +00:00
|
|
|
if (win) {
|
|
|
|
gtk_widget_set_can_default(w, true);
|
|
|
|
if (ctrl->button.isdefault)
|
|
|
|
gtk_window_set_default(win, w);
|
|
|
|
if (ctrl->button.iscancel)
|
|
|
|
dp->cancelbutton = w;
|
|
|
|
}
|
2015-08-08 16:29:02 +00:00
|
|
|
g_signal_connect(G_OBJECT(w), "clicked",
|
|
|
|
G_CALLBACK(button_clicked), dp);
|
|
|
|
g_signal_connect(G_OBJECT(w), "focus_in_event",
|
|
|
|
G_CALLBACK(widget_focus), dp);
|
2015-08-08 14:53:43 +00:00
|
|
|
shortcut_add(scs, gtk_bin_get_child(GTK_BIN(w)),
|
|
|
|
ctrl->button.shortcut, SHORTCUT_UCTRL, uc);
|
2003-03-13 19:52:28 +00:00
|
|
|
break;
|
|
|
|
case CTRL_CHECKBOX:
|
Restructure dlgcontrol as a struct with an anon union.
This gets rid of that awkward STANDARD_PREFIX system in which every
branch of the old 'union control' had to repeat all the generic
fields, and then call sites had to make an arbitrary decision about
which branch to access them through.
That was the best we could do before accepting C99 features in this
code base. But now we have anonymous unions, so we don't need to put
up with that nonsense any more!
'dlgcontrol' is now a struct rather than a union, and the generic
fields common to all control types are ordinary members of the struct,
so you don't have to refer to them as ctrl->generic.foo at all, just
ctrl->foo, which saves verbiage at the point of use.
The extra per-control fields are still held in structures named after
the control type, so you'll still say ctrl->listbox.height or
whatever. But now those structures are themselves members of an
anonymous union field following the generic fields, so those
sub-structures don't have to reiterate all the standard stuff too.
While I'm here, I've promoted 'context2' from an editbox-specific
field to a generic one (it just seems silly _not_ to allow any control
to have two context fields if it needs it). Also, I had to rename the
boolean field 'tabdelay' to avoid it clashing with the subsidiary
structure field 'tabdelay', now that the former isn't generic.tabdelay
any more.
2022-05-01 08:55:52 +00:00
|
|
|
w = gtk_check_button_new_with_label(ctrl->label);
|
2015-08-08 16:29:02 +00:00
|
|
|
g_signal_connect(G_OBJECT(w), "toggled",
|
|
|
|
G_CALLBACK(button_toggled), dp);
|
|
|
|
g_signal_connect(G_OBJECT(w), "focus_in_event",
|
|
|
|
G_CALLBACK(widget_focus), dp);
|
2015-08-08 14:53:43 +00:00
|
|
|
shortcut_add(scs, gtk_bin_get_child(GTK_BIN(w)),
|
|
|
|
ctrl->checkbox.shortcut, SHORTCUT_UCTRL, uc);
|
2019-09-08 19:29:00 +00:00
|
|
|
left = true;
|
2003-03-13 19:52:28 +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
|
|
|
case CTRL_RADIO: {
|
2003-03-13 19:52:28 +00:00
|
|
|
/*
|
|
|
|
* Radio buttons get to go inside their own Columns, no
|
|
|
|
* matter what.
|
|
|
|
*/
|
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
|
|
|
gint i, *percentages;
|
|
|
|
GSList *group;
|
|
|
|
|
|
|
|
w = columns_new(0);
|
Restructure dlgcontrol as a struct with an anon union.
This gets rid of that awkward STANDARD_PREFIX system in which every
branch of the old 'union control' had to repeat all the generic
fields, and then call sites had to make an arbitrary decision about
which branch to access them through.
That was the best we could do before accepting C99 features in this
code base. But now we have anonymous unions, so we don't need to put
up with that nonsense any more!
'dlgcontrol' is now a struct rather than a union, and the generic
fields common to all control types are ordinary members of the struct,
so you don't have to refer to them as ctrl->generic.foo at all, just
ctrl->foo, which saves verbiage at the point of use.
The extra per-control fields are still held in structures named after
the control type, so you'll still say ctrl->listbox.height or
whatever. But now those structures are themselves members of an
anonymous union field following the generic fields, so those
sub-structures don't have to reiterate all the standard stuff too.
While I'm here, I've promoted 'context2' from an editbox-specific
field to a generic one (it just seems silly _not_ to allow any control
to have two context fields if it needs it). Also, I had to rename the
boolean field 'tabdelay' to avoid it clashing with the subsidiary
structure field 'tabdelay', now that the former isn't generic.tabdelay
any more.
2022-05-01 08:55:52 +00:00
|
|
|
if (ctrl->label) {
|
2022-06-23 17:44:07 +00:00
|
|
|
GtkWidget *label = gtk_label_new(ctrl->label);
|
|
|
|
columns_add(COLUMNS(w), label, 0, 1);
|
|
|
|
columns_force_left_align(COLUMNS(w), label);
|
|
|
|
gtk_widget_show(label);
|
|
|
|
shortcut_add(scs, label, ctrl->radio.shortcut,
|
|
|
|
SHORTCUT_UCTRL, uc);
|
|
|
|
uc->label = label;
|
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
|
|
|
}
|
|
|
|
percentages = g_new(gint, ctrl->radio.ncolumns);
|
|
|
|
for (i = 0; i < ctrl->radio.ncolumns; i++) {
|
2022-06-23 17:44:07 +00:00
|
|
|
percentages[i] =
|
|
|
|
((100 * (i+1) / ctrl->radio.ncolumns) -
|
|
|
|
100 * i / ctrl->radio.ncolumns);
|
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
|
|
|
}
|
|
|
|
columns_set_cols(COLUMNS(w), ctrl->radio.ncolumns,
|
|
|
|
percentages);
|
|
|
|
g_free(percentages);
|
|
|
|
group = NULL;
|
|
|
|
|
|
|
|
uc->nbuttons = ctrl->radio.nbuttons;
|
|
|
|
uc->buttons = snewn(uc->nbuttons, GtkWidget *);
|
|
|
|
|
|
|
|
for (i = 0; i < ctrl->radio.nbuttons; i++) {
|
2022-06-23 17:44:07 +00:00
|
|
|
GtkWidget *b;
|
|
|
|
gint colstart;
|
|
|
|
|
Formatting: standardise on "func(\n", not "func\n(".
If the function name (or expression) in a function call or declaration
is itself so long that even the first argument doesn't fit after it on
the same line, or if that would leave so little space that it would be
silly to try to wrap all the run-on lines into a tall thin column,
then I used to do this
ludicrously_long_function_name
(arg1, arg2, arg3);
and now prefer this
ludicrously_long_function_name(
arg1, arg2, arg3);
I picked up the habit from Python, where the latter idiom is required
by Python's syntactic significance of newlines (you can write the
former if you use a backslash-continuation, but pretty much everyone
seems to agree that that's much uglier). But I've found it works well
in C as well: it makes it more obvious that the previous line is
incomplete, it gives you a tiny bit more space to wrap the following
lines into (the old idiom indents the _third_ line one space beyond
the second), and I generally turn out to agree with the knock-on
indentation decisions made by at least Emacs if you do it in the
middle of a complex expression. Plus, of course, using the _same_
idiom between C and Python means less state-switching.
So, while I'm making annoying indentation changes in general, this
seems like a good time to dig out all the cases of the old idiom in
this code, and switch them over to the new.
2022-08-03 19:48:46 +00:00
|
|
|
b = gtk_radio_button_new_with_label(
|
|
|
|
group, ctrl->radio.buttons[i]);
|
2022-06-23 17:44:07 +00:00
|
|
|
uc->buttons[i] = b;
|
|
|
|
group = gtk_radio_button_get_group(GTK_RADIO_BUTTON(b));
|
|
|
|
colstart = i % ctrl->radio.ncolumns;
|
|
|
|
columns_add(COLUMNS(w), b, colstart,
|
|
|
|
(i == ctrl->radio.nbuttons-1 ?
|
|
|
|
ctrl->radio.ncolumns - colstart : 1));
|
|
|
|
columns_force_left_align(COLUMNS(w), b);
|
|
|
|
gtk_widget_show(b);
|
|
|
|
g_signal_connect(G_OBJECT(b), "toggled",
|
|
|
|
G_CALLBACK(button_toggled), dp);
|
|
|
|
g_signal_connect(G_OBJECT(b), "focus_in_event",
|
|
|
|
G_CALLBACK(widget_focus), dp);
|
|
|
|
if (ctrl->radio.shortcuts) {
|
|
|
|
shortcut_add(scs, gtk_bin_get_child(GTK_BIN(b)),
|
|
|
|
ctrl->radio.shortcuts[i],
|
|
|
|
SHORTCUT_UCTRL, uc);
|
|
|
|
}
|
2003-03-13 19:52:28 +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
|
|
|
}
|
|
|
|
case CTRL_EDITBOX: {
|
|
|
|
GtkWidget *signalobject;
|
2003-03-22 17:00:06 +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
|
|
|
if (ctrl->editbox.has_list) {
|
2008-05-31 19:23:45 +00:00
|
|
|
#if !GTK_CHECK_VERSION(2,4,0)
|
2022-06-23 17:44:07 +00:00
|
|
|
/*
|
|
|
|
* GTK 1 combo box.
|
|
|
|
*/
|
|
|
|
w = gtk_combo_new();
|
|
|
|
gtk_combo_set_value_in_list(GTK_COMBO(w), false, true);
|
|
|
|
uc->entry = GTK_COMBO(w)->entry;
|
|
|
|
uc->list = GTK_COMBO(w)->list;
|
|
|
|
signalobject = uc->entry;
|
2008-04-04 10:56:26 +00:00
|
|
|
#else
|
2022-06-23 17:44:07 +00:00
|
|
|
/*
|
|
|
|
* GTK 2 combo box.
|
|
|
|
*/
|
|
|
|
uc->listmodel = gtk_list_store_new(2, G_TYPE_INT,
|
|
|
|
G_TYPE_STRING);
|
Formatting: standardise on "func(\n", not "func\n(".
If the function name (or expression) in a function call or declaration
is itself so long that even the first argument doesn't fit after it on
the same line, or if that would leave so little space that it would be
silly to try to wrap all the run-on lines into a tall thin column,
then I used to do this
ludicrously_long_function_name
(arg1, arg2, arg3);
and now prefer this
ludicrously_long_function_name(
arg1, arg2, arg3);
I picked up the habit from Python, where the latter idiom is required
by Python's syntactic significance of newlines (you can write the
former if you use a backslash-continuation, but pretty much everyone
seems to agree that that's much uglier). But I've found it works well
in C as well: it makes it more obvious that the previous line is
incomplete, it gives you a tiny bit more space to wrap the following
lines into (the old idiom indents the _third_ line one space beyond
the second), and I generally turn out to agree with the knock-on
indentation decisions made by at least Emacs if you do it in the
middle of a complex expression. Plus, of course, using the _same_
idiom between C and Python means less state-switching.
So, while I'm making annoying indentation changes in general, this
seems like a good time to dig out all the cases of the old idiom in
this code, and switch them over to the new.
2022-08-03 19:48:46 +00:00
|
|
|
w = gtk_combo_box_new_with_model_and_entry(
|
|
|
|
GTK_TREE_MODEL(uc->listmodel));
|
2022-06-23 17:44:07 +00:00
|
|
|
g_object_set(G_OBJECT(w), "entry-text-column", 1,
|
|
|
|
(const char *)NULL);
|
|
|
|
/* We cannot support password combo boxes. */
|
|
|
|
assert(!ctrl->editbox.password);
|
|
|
|
uc->combo = w;
|
|
|
|
signalobject = uc->combo;
|
2019-09-08 19:29:00 +00:00
|
|
|
#endif
|
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
|
|
|
} else {
|
2022-06-23 17:44:07 +00:00
|
|
|
w = gtk_entry_new();
|
|
|
|
if (ctrl->editbox.password)
|
|
|
|
gtk_entry_set_visibility(GTK_ENTRY(w), false);
|
|
|
|
uc->entry = w;
|
|
|
|
signalobject = w;
|
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
|
|
|
}
|
2022-06-23 18:04:43 +00:00
|
|
|
g_signal_connect(G_OBJECT(signalobject), "changed",
|
|
|
|
G_CALLBACK(editbox_changed), dp);
|
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
|
|
|
g_signal_connect(G_OBJECT(signalobject), "key_press_event",
|
|
|
|
G_CALLBACK(editbox_key), dp);
|
|
|
|
g_signal_connect(G_OBJECT(signalobject), "focus_in_event",
|
|
|
|
G_CALLBACK(widget_focus), dp);
|
|
|
|
g_signal_connect(G_OBJECT(signalobject), "focus_out_event",
|
|
|
|
G_CALLBACK(editbox_lostfocus), dp);
|
|
|
|
g_signal_connect(G_OBJECT(signalobject), "focus_out_event",
|
|
|
|
G_CALLBACK(editbox_lostfocus), dp);
|
2015-08-22 09:37:48 +00:00
|
|
|
|
|
|
|
#if !GTK_CHECK_VERSION(3,0,0)
|
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
|
|
|
/*
|
|
|
|
* Edit boxes, for some strange reason, have a minimum
|
|
|
|
* width of 150 in GTK 1.2. We don't want this - we'd
|
|
|
|
* rather the edit boxes acquired their natural width
|
|
|
|
* from the column layout of the rest of the box.
|
|
|
|
*/
|
|
|
|
{
|
2022-06-23 17:44:07 +00:00
|
|
|
GtkRequisition req;
|
|
|
|
gtk_widget_size_request(w, &req);
|
|
|
|
gtk_widget_set_size_request(w, 10, req.height);
|
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
|
|
|
}
|
2015-08-22 09:37:48 +00:00
|
|
|
#else
|
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
|
|
|
/*
|
|
|
|
* In GTK 3, this is still true, but there's a special
|
|
|
|
* method for GtkEntry in particular to fix it.
|
|
|
|
*/
|
|
|
|
if (GTK_IS_ENTRY(w))
|
|
|
|
gtk_entry_set_width_chars(GTK_ENTRY(w), 1);
|
2015-08-22 09:37:48 +00:00
|
|
|
#endif
|
2003-03-13 19:52:28 +00:00
|
|
|
|
Restructure dlgcontrol as a struct with an anon union.
This gets rid of that awkward STANDARD_PREFIX system in which every
branch of the old 'union control' had to repeat all the generic
fields, and then call sites had to make an arbitrary decision about
which branch to access them through.
That was the best we could do before accepting C99 features in this
code base. But now we have anonymous unions, so we don't need to put
up with that nonsense any more!
'dlgcontrol' is now a struct rather than a union, and the generic
fields common to all control types are ordinary members of the struct,
so you don't have to refer to them as ctrl->generic.foo at all, just
ctrl->foo, which saves verbiage at the point of use.
The extra per-control fields are still held in structures named after
the control type, so you'll still say ctrl->listbox.height or
whatever. But now those structures are themselves members of an
anonymous union field following the generic fields, so those
sub-structures don't have to reiterate all the standard stuff too.
While I'm here, I've promoted 'context2' from an editbox-specific
field to a generic one (it just seems silly _not_ to allow any control
to have two context fields if it needs it). Also, I had to rename the
boolean field 'tabdelay' to avoid it clashing with the subsidiary
structure field 'tabdelay', now that the former isn't generic.tabdelay
any more.
2022-05-01 08:55:52 +00:00
|
|
|
if (ctrl->label) {
|
2022-06-23 17:44:07 +00:00
|
|
|
GtkWidget *label;
|
|
|
|
|
|
|
|
label = gtk_label_new(ctrl->label);
|
|
|
|
|
|
|
|
shortcut_add(scs, label, ctrl->editbox.shortcut,
|
|
|
|
SHORTCUT_FOCUS, uc->entry);
|
|
|
|
|
|
|
|
if (ctrl->editbox.percentwidth == 100) {
|
|
|
|
columns_add(cols, label,
|
|
|
|
COLUMN_START(ctrl->column),
|
|
|
|
COLUMN_SPAN(ctrl->column));
|
|
|
|
columns_force_left_align(cols, label);
|
|
|
|
} else {
|
|
|
|
GtkWidget *container = columns_new(4);
|
|
|
|
gint percentages[2];
|
|
|
|
percentages[1] = ctrl->editbox.percentwidth;
|
|
|
|
percentages[0] = 100 - ctrl->editbox.percentwidth;
|
|
|
|
columns_set_cols(COLUMNS(container), 2, percentages);
|
|
|
|
columns_add(COLUMNS(container), label, 0, 1);
|
|
|
|
columns_force_left_align(COLUMNS(container), label);
|
|
|
|
columns_add(COLUMNS(container), w, 1, 1);
|
|
|
|
columns_align_next_to(COLUMNS(container), label, w);
|
|
|
|
gtk_widget_show(w);
|
|
|
|
w = container;
|
|
|
|
}
|
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
|
|
|
|
2022-06-23 17:44:07 +00:00
|
|
|
gtk_widget_show(label);
|
|
|
|
uc->label = label;
|
2019-09-08 19:29:00 +00:00
|
|
|
}
|
2003-03-13 19:52:28 +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
|
|
|
}
|
2003-03-14 18:35:01 +00:00
|
|
|
case CTRL_FILESELECT:
|
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_FONTSELECT: {
|
|
|
|
GtkWidget *ww;
|
|
|
|
|
2022-10-28 16:49:59 +00:00
|
|
|
bool just_button = (ctrl->type == CTRL_FILESELECT &&
|
|
|
|
ctrl->fileselect.just_button);
|
|
|
|
|
|
|
|
if (!just_button) {
|
2022-05-01 07:39:49 +00:00
|
|
|
const char *browsebtn =
|
|
|
|
(ctrl->type == CTRL_FILESELECT ?
|
|
|
|
"Browse..." : "Change...");
|
|
|
|
|
|
|
|
gint percentages[] = { 75, 25 };
|
|
|
|
w = columns_new(4);
|
|
|
|
columns_set_cols(COLUMNS(w), 2, percentages);
|
|
|
|
|
|
|
|
if (ctrl->label) {
|
|
|
|
ww = gtk_label_new(ctrl->label);
|
|
|
|
columns_add(COLUMNS(w), ww, 0, 2);
|
|
|
|
columns_force_left_align(COLUMNS(w), ww);
|
|
|
|
gtk_widget_show(ww);
|
|
|
|
shortcut_add(scs, ww,
|
|
|
|
(ctrl->type == CTRL_FILESELECT ?
|
|
|
|
ctrl->fileselect.shortcut :
|
|
|
|
ctrl->fontselect.shortcut),
|
|
|
|
SHORTCUT_UCTRL, uc);
|
|
|
|
uc->label = ww;
|
|
|
|
}
|
2003-03-14 18:35:01 +00:00
|
|
|
|
2022-05-01 07:39:49 +00:00
|
|
|
uc->entry = ww = gtk_entry_new();
|
2015-08-24 18:04:37 +00:00
|
|
|
#if !GTK_CHECK_VERSION(3,0,0)
|
2022-05-01 07:39:49 +00:00
|
|
|
{
|
|
|
|
GtkRequisition req;
|
|
|
|
gtk_widget_size_request(ww, &req);
|
|
|
|
gtk_widget_set_size_request(ww, 10, req.height);
|
|
|
|
}
|
2015-08-24 18:04:37 +00:00
|
|
|
#else
|
2022-05-01 07:39:49 +00:00
|
|
|
gtk_entry_set_width_chars(GTK_ENTRY(ww), 1);
|
2015-08-24 18:04:37 +00:00
|
|
|
#endif
|
2022-05-01 07:39:49 +00:00
|
|
|
columns_add(COLUMNS(w), ww, 0, 1);
|
|
|
|
gtk_widget_show(ww);
|
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
|
|
|
|
2022-05-01 07:39:49 +00:00
|
|
|
uc->button = ww = gtk_button_new_with_label(browsebtn);
|
|
|
|
columns_add(COLUMNS(w), ww, 1, 1);
|
|
|
|
gtk_widget_show(ww);
|
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
|
|
|
|
Improve the align_next_to mechanism.
Various alignments I want to do in the host CA box have shown up
deficiencies in this system, so I've reworked it a bit.
Firstly, you can now specify more than two controls to be tied
together with an align_next_to (e.g. multiple checkboxes alongside
something else).
Secondly, as well as forcing the controls to be the same height as
each other, the layout algorithm will also move the later controls
further _downward_, so that their top y positions also line up. Until
now that hasn't been necessary, because they lined up already.
In the GTK implementation of this via the Columns class, I've renamed
'columns_force_same_height' to 'columns_align_next_to', and similarly
for some of the internal fields, since the latter change makes the
previous names a misnomer.
In the Windows implementation, I found it most convenient to set this
up by following a linked list of align_next_to fields backwards. But
it won't always be convenient to initialise them that way, so I've
also written a crude normaliser that will rewrite those links into a
canonical form. But I only call that on Windows; it's unnecessary in
GTK, where the Columns class provides plenty of per-widget extra
storage so I just keep each alignment class as a circular list.
2022-05-02 13:37:11 +00:00
|
|
|
columns_align_next_to(COLUMNS(w), uc->entry, uc->button);
|
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
|
|
|
|
2022-05-01 07:39:49 +00:00
|
|
|
g_signal_connect(G_OBJECT(uc->entry), "key_press_event",
|
|
|
|
G_CALLBACK(editbox_key), dp);
|
2022-06-23 18:04:43 +00:00
|
|
|
g_signal_connect(G_OBJECT(uc->entry), "changed",
|
|
|
|
G_CALLBACK(editbox_changed), dp);
|
2022-05-01 07:39:49 +00:00
|
|
|
g_signal_connect(G_OBJECT(uc->entry), "focus_in_event",
|
|
|
|
G_CALLBACK(widget_focus), dp);
|
|
|
|
} else {
|
|
|
|
uc->button = w = gtk_button_new_with_label(ctrl->label);
|
|
|
|
shortcut_add(scs, gtk_bin_get_child(GTK_BIN(w)),
|
|
|
|
ctrl->fileselect.shortcut, SHORTCUT_UCTRL, uc);
|
|
|
|
gtk_widget_show(w);
|
|
|
|
|
|
|
|
}
|
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
|
|
|
g_signal_connect(G_OBJECT(uc->button), "focus_in_event",
|
|
|
|
G_CALLBACK(widget_focus), dp);
|
2022-05-01 07:39:49 +00:00
|
|
|
g_signal_connect(G_OBJECT(uc->button), "clicked",
|
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
|
|
|
G_CALLBACK(filefont_clicked), dp);
|
2003-03-14 18:35:01 +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
|
|
|
}
|
2003-03-14 18:35:01 +00:00
|
|
|
case CTRL_LISTBOX:
|
2008-04-04 10:56:26 +00:00
|
|
|
|
2008-05-31 19:23:45 +00:00
|
|
|
#if GTK_CHECK_VERSION(2,0,0)
|
2019-09-08 19:29:00 +00:00
|
|
|
/*
|
|
|
|
* First construct the list data store, with the right
|
|
|
|
* number of columns.
|
|
|
|
*/
|
2008-05-31 19:23:45 +00:00
|
|
|
# if !GTK_CHECK_VERSION(2,4,0)
|
2019-09-08 19:29:00 +00:00
|
|
|
/* (For GTK 2.0 to 2.3, we do this for full listboxes only,
|
|
|
|
* because combo boxes are still done the old GTK1 way.) */
|
|
|
|
if (ctrl->listbox.height > 0)
|
2008-05-31 19:23:45 +00:00
|
|
|
# endif
|
2019-09-08 19:29:00 +00:00
|
|
|
{
|
|
|
|
GType *types;
|
|
|
|
int i;
|
|
|
|
int cols;
|
2008-05-31 19:23:45 +00:00
|
|
|
|
2019-09-08 19:29:00 +00:00
|
|
|
cols = ctrl->listbox.ncols;
|
|
|
|
cols = cols ? cols : 1;
|
|
|
|
types = snewn(1 + cols, GType);
|
2008-05-31 19:23:45 +00:00
|
|
|
|
2019-09-08 19:29:00 +00:00
|
|
|
types[0] = G_TYPE_INT;
|
|
|
|
for (i = 0; i < cols; i++)
|
|
|
|
types[i+1] = G_TYPE_STRING;
|
2008-05-31 19:23:45 +00:00
|
|
|
|
2019-09-08 19:29:00 +00:00
|
|
|
uc->listmodel = gtk_list_store_newv(1 + cols, types);
|
2008-05-31 19:23:45 +00:00
|
|
|
|
2019-09-08 19:29:00 +00:00
|
|
|
sfree(types);
|
|
|
|
}
|
2008-05-31 19:23:45 +00:00
|
|
|
#endif
|
2008-04-04 10:56:26 +00:00
|
|
|
|
2019-09-08 19:29:00 +00:00
|
|
|
/*
|
|
|
|
* See if it's a drop-down list (non-editable combo
|
|
|
|
* box).
|
|
|
|
*/
|
|
|
|
if (ctrl->listbox.height == 0) {
|
2008-05-31 19:23:45 +00:00
|
|
|
#if !GTK_CHECK_VERSION(2,4,0)
|
2019-09-08 19:29:00 +00:00
|
|
|
/*
|
|
|
|
* GTK1 and early-GTK2 option-menu style of
|
|
|
|
* drop-down list.
|
|
|
|
*/
|
2008-04-04 10:56:26 +00:00
|
|
|
uc->optmenu = w = gtk_option_menu_new();
|
2019-09-08 19:29:00 +00:00
|
|
|
uc->menu = gtk_menu_new();
|
|
|
|
gtk_option_menu_set_menu(GTK_OPTION_MENU(w), uc->menu);
|
2015-08-08 16:29:02 +00:00
|
|
|
g_object_set_data(G_OBJECT(uc->menu), "user-data",
|
|
|
|
(gpointer)uc->optmenu);
|
|
|
|
g_signal_connect(G_OBJECT(uc->optmenu), "focus_in_event",
|
|
|
|
G_CALLBACK(widget_focus), dp);
|
2008-05-31 19:23:45 +00:00
|
|
|
#else
|
2019-09-08 19:29:00 +00:00
|
|
|
/*
|
|
|
|
* Late-GTK2 style using a GtkComboBox.
|
|
|
|
*/
|
|
|
|
GtkCellRenderer *cr;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Create a non-editable GtkComboBox (that is, not
|
|
|
|
* its subclass GtkComboBoxEntry).
|
|
|
|
*/
|
Formatting: standardise on "func(\n", not "func\n(".
If the function name (or expression) in a function call or declaration
is itself so long that even the first argument doesn't fit after it on
the same line, or if that would leave so little space that it would be
silly to try to wrap all the run-on lines into a tall thin column,
then I used to do this
ludicrously_long_function_name
(arg1, arg2, arg3);
and now prefer this
ludicrously_long_function_name(
arg1, arg2, arg3);
I picked up the habit from Python, where the latter idiom is required
by Python's syntactic significance of newlines (you can write the
former if you use a backslash-continuation, but pretty much everyone
seems to agree that that's much uglier). But I've found it works well
in C as well: it makes it more obvious that the previous line is
incomplete, it gives you a tiny bit more space to wrap the following
lines into (the old idiom indents the _third_ line one space beyond
the second), and I generally turn out to agree with the knock-on
indentation decisions made by at least Emacs if you do it in the
middle of a complex expression. Plus, of course, using the _same_
idiom between C and Python means less state-switching.
So, while I'm making annoying indentation changes in general, this
seems like a good time to dig out all the cases of the old idiom in
this code, and switch them over to the new.
2022-08-03 19:48:46 +00:00
|
|
|
w = gtk_combo_box_new_with_model(
|
|
|
|
GTK_TREE_MODEL(uc->listmodel));
|
2019-09-08 19:29:00 +00:00
|
|
|
uc->combo = w;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Tell it how to render a list item (i.e. which
|
|
|
|
* column to look at in the list model).
|
|
|
|
*/
|
|
|
|
cr = gtk_cell_renderer_text_new();
|
|
|
|
gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(w), cr, true);
|
|
|
|
gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(w), cr,
|
|
|
|
"text", 1, NULL);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* And tell it to notify us when the selection
|
|
|
|
* changes.
|
|
|
|
*/
|
|
|
|
g_signal_connect(G_OBJECT(w), "changed",
|
|
|
|
G_CALLBACK(droplist_selchange), dp);
|
2015-09-26 10:48:21 +00:00
|
|
|
|
|
|
|
g_signal_connect(G_OBJECT(w), "focus_in_event",
|
|
|
|
G_CALLBACK(widget_focus), dp);
|
2008-05-31 19:23:45 +00:00
|
|
|
#endif
|
2008-04-04 10:56:26 +00:00
|
|
|
} else {
|
2008-05-31 19:23:45 +00:00
|
|
|
#if !GTK_CHECK_VERSION(2,0,0)
|
2019-09-08 19:29:00 +00:00
|
|
|
/*
|
|
|
|
* GTK1-style full list box.
|
|
|
|
*/
|
2008-04-04 10:56:26 +00:00
|
|
|
uc->list = gtk_list_new();
|
|
|
|
if (ctrl->listbox.multisel == 2) {
|
|
|
|
gtk_list_set_selection_mode(GTK_LIST(uc->list),
|
|
|
|
GTK_SELECTION_EXTENDED);
|
|
|
|
} else if (ctrl->listbox.multisel == 1) {
|
|
|
|
gtk_list_set_selection_mode(GTK_LIST(uc->list),
|
|
|
|
GTK_SELECTION_MULTIPLE);
|
|
|
|
} else {
|
|
|
|
gtk_list_set_selection_mode(GTK_LIST(uc->list),
|
|
|
|
GTK_SELECTION_SINGLE);
|
|
|
|
}
|
|
|
|
w = gtk_scrolled_window_new(NULL, NULL);
|
|
|
|
gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(w),
|
|
|
|
uc->list);
|
|
|
|
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(w),
|
|
|
|
GTK_POLICY_NEVER,
|
|
|
|
GTK_POLICY_AUTOMATIC);
|
Formatting: standardise on "func(\n", not "func\n(".
If the function name (or expression) in a function call or declaration
is itself so long that even the first argument doesn't fit after it on
the same line, or if that would leave so little space that it would be
silly to try to wrap all the run-on lines into a tall thin column,
then I used to do this
ludicrously_long_function_name
(arg1, arg2, arg3);
and now prefer this
ludicrously_long_function_name(
arg1, arg2, arg3);
I picked up the habit from Python, where the latter idiom is required
by Python's syntactic significance of newlines (you can write the
former if you use a backslash-continuation, but pretty much everyone
seems to agree that that's much uglier). But I've found it works well
in C as well: it makes it more obvious that the previous line is
incomplete, it gives you a tiny bit more space to wrap the following
lines into (the old idiom indents the _third_ line one space beyond
the second), and I generally turn out to agree with the knock-on
indentation decisions made by at least Emacs if you do it in the
middle of a complex expression. Plus, of course, using the _same_
idiom between C and Python means less state-switching.
So, while I'm making annoying indentation changes in general, this
seems like a good time to dig out all the cases of the old idiom in
this code, and switch them over to the new.
2022-08-03 19:48:46 +00:00
|
|
|
uc->adj = gtk_scrolled_window_get_vadjustment(
|
|
|
|
GTK_SCROLLED_WINDOW(w));
|
2008-04-04 10:56:26 +00:00
|
|
|
|
|
|
|
gtk_widget_show(uc->list);
|
2015-08-08 16:29:02 +00:00
|
|
|
g_signal_connect(G_OBJECT(uc->list), "selection-changed",
|
|
|
|
G_CALLBACK(list_selchange), dp);
|
|
|
|
g_signal_connect(G_OBJECT(uc->list), "focus_in_event",
|
|
|
|
G_CALLBACK(widget_focus), dp);
|
2008-04-04 10:56:26 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Adjust the height of the scrolled window to the
|
|
|
|
* minimum given by the height parameter.
|
2019-09-08 19:29:00 +00:00
|
|
|
*
|
2008-04-04 10:56:26 +00:00
|
|
|
* This piece of guesswork is a horrid hack based
|
|
|
|
* on looking inside the GTK 1.2 sources
|
|
|
|
* (specifically gtkviewport.c, which appears to be
|
|
|
|
* the widget which provides the border around the
|
|
|
|
* scrolling area). Anyone lets me know how I can
|
|
|
|
* do this in a way which isn't at risk from GTK
|
|
|
|
* upgrades, I'd be grateful.
|
|
|
|
*/
|
2019-09-08 19:29:00 +00:00
|
|
|
{
|
|
|
|
int edge;
|
|
|
|
edge = GTK_WIDGET(uc->list)->style->klass->ythickness;
|
2022-06-23 17:44:07 +00:00
|
|
|
gtk_widget_set_size_request(
|
|
|
|
w, 10, 2*edge + (ctrl->listbox.height *
|
|
|
|
get_listitemheight(w)));
|
2019-09-08 19:29:00 +00:00
|
|
|
}
|
2008-04-04 10:56:26 +00:00
|
|
|
|
|
|
|
if (ctrl->listbox.draglist) {
|
|
|
|
/*
|
|
|
|
* GTK doesn't appear to make it easy to
|
|
|
|
* implement a proper draggable list; so
|
|
|
|
* instead I'm just going to have to put an Up
|
|
|
|
* and a Down button to the right of the actual
|
|
|
|
* list box. Ah well.
|
|
|
|
*/
|
|
|
|
GtkWidget *cols, *button;
|
|
|
|
static const gint percentages[2] = { 80, 20 };
|
|
|
|
|
|
|
|
cols = columns_new(4);
|
|
|
|
columns_set_cols(COLUMNS(cols), 2, percentages);
|
|
|
|
columns_add(COLUMNS(cols), w, 0, 1);
|
|
|
|
gtk_widget_show(w);
|
|
|
|
button = gtk_button_new_with_label("Up");
|
|
|
|
columns_add(COLUMNS(cols), button, 1, 1);
|
|
|
|
gtk_widget_show(button);
|
2015-08-08 16:29:02 +00:00
|
|
|
g_signal_connect(G_OBJECT(button), "clicked",
|
|
|
|
G_CALLBACK(draglist_up), dp);
|
|
|
|
g_signal_connect(G_OBJECT(button), "focus_in_event",
|
|
|
|
G_CALLBACK(widget_focus), dp);
|
2008-04-04 10:56:26 +00:00
|
|
|
button = gtk_button_new_with_label("Down");
|
|
|
|
columns_add(COLUMNS(cols), button, 1, 1);
|
|
|
|
gtk_widget_show(button);
|
2015-08-08 16:29:02 +00:00
|
|
|
g_signal_connect(G_OBJECT(button), "clicked",
|
|
|
|
G_CALLBACK(draglist_down), dp);
|
|
|
|
g_signal_connect(G_OBJECT(button), "focus_in_event",
|
|
|
|
G_CALLBACK(widget_focus), dp);
|
2008-04-04 10:56:26 +00:00
|
|
|
|
|
|
|
w = cols;
|
|
|
|
}
|
2008-05-31 19:23:45 +00:00
|
|
|
#else
|
2019-09-08 19:29:00 +00:00
|
|
|
/*
|
|
|
|
* GTK2 treeview-based full list box.
|
|
|
|
*/
|
|
|
|
GtkTreeSelection *sel;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Create the list box itself, its columns, and
|
|
|
|
* its containing scrolled window.
|
|
|
|
*/
|
Formatting: standardise on "func(\n", not "func\n(".
If the function name (or expression) in a function call or declaration
is itself so long that even the first argument doesn't fit after it on
the same line, or if that would leave so little space that it would be
silly to try to wrap all the run-on lines into a tall thin column,
then I used to do this
ludicrously_long_function_name
(arg1, arg2, arg3);
and now prefer this
ludicrously_long_function_name(
arg1, arg2, arg3);
I picked up the habit from Python, where the latter idiom is required
by Python's syntactic significance of newlines (you can write the
former if you use a backslash-continuation, but pretty much everyone
seems to agree that that's much uglier). But I've found it works well
in C as well: it makes it more obvious that the previous line is
incomplete, it gives you a tiny bit more space to wrap the following
lines into (the old idiom indents the _third_ line one space beyond
the second), and I generally turn out to agree with the knock-on
indentation decisions made by at least Emacs if you do it in the
middle of a complex expression. Plus, of course, using the _same_
idiom between C and Python means less state-switching.
So, while I'm making annoying indentation changes in general, this
seems like a good time to dig out all the cases of the old idiom in
this code, and switch them over to the new.
2022-08-03 19:48:46 +00:00
|
|
|
w = gtk_tree_view_new_with_model(
|
|
|
|
GTK_TREE_MODEL(uc->listmodel));
|
2019-09-08 19:29:00 +00:00
|
|
|
g_object_set_data(G_OBJECT(uc->listmodel), "user-data",
|
|
|
|
(gpointer)w);
|
|
|
|
gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(w), false);
|
|
|
|
sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(w));
|
Formatting: standardise on "func(\n", not "func\n(".
If the function name (or expression) in a function call or declaration
is itself so long that even the first argument doesn't fit after it on
the same line, or if that would leave so little space that it would be
silly to try to wrap all the run-on lines into a tall thin column,
then I used to do this
ludicrously_long_function_name
(arg1, arg2, arg3);
and now prefer this
ludicrously_long_function_name(
arg1, arg2, arg3);
I picked up the habit from Python, where the latter idiom is required
by Python's syntactic significance of newlines (you can write the
former if you use a backslash-continuation, but pretty much everyone
seems to agree that that's much uglier). But I've found it works well
in C as well: it makes it more obvious that the previous line is
incomplete, it gives you a tiny bit more space to wrap the following
lines into (the old idiom indents the _third_ line one space beyond
the second), and I generally turn out to agree with the knock-on
indentation decisions made by at least Emacs if you do it in the
middle of a complex expression. Plus, of course, using the _same_
idiom between C and Python means less state-switching.
So, while I'm making annoying indentation changes in general, this
seems like a good time to dig out all the cases of the old idiom in
this code, and switch them over to the new.
2022-08-03 19:48:46 +00:00
|
|
|
gtk_tree_selection_set_mode(
|
|
|
|
sel, ctrl->listbox.multisel ? GTK_SELECTION_MULTIPLE :
|
|
|
|
GTK_SELECTION_SINGLE);
|
2019-09-08 19:29:00 +00:00
|
|
|
uc->treeview = w;
|
2015-08-08 16:29:02 +00:00
|
|
|
g_signal_connect(G_OBJECT(w), "row-activated",
|
|
|
|
G_CALLBACK(listbox_doubleclick), dp);
|
2015-09-26 10:48:21 +00:00
|
|
|
g_signal_connect(G_OBJECT(w), "focus_in_event",
|
|
|
|
G_CALLBACK(widget_focus), dp);
|
2019-09-08 19:29:00 +00:00
|
|
|
g_signal_connect(G_OBJECT(sel), "changed",
|
|
|
|
G_CALLBACK(listbox_selchange), dp);
|
|
|
|
|
|
|
|
if (ctrl->listbox.draglist) {
|
|
|
|
gtk_tree_view_set_reorderable(GTK_TREE_VIEW(w), true);
|
|
|
|
g_signal_connect(G_OBJECT(uc->listmodel), "row-inserted",
|
|
|
|
G_CALLBACK(listbox_reorder), dp);
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
int cols;
|
|
|
|
|
|
|
|
cols = ctrl->listbox.ncols;
|
|
|
|
cols = cols ? cols : 1;
|
|
|
|
for (i = 0; i < cols; i++) {
|
|
|
|
GtkTreeViewColumn *column;
|
2014-09-09 11:46:14 +00:00
|
|
|
GtkCellRenderer *cellrend;
|
2019-09-08 19:29:00 +00:00
|
|
|
/*
|
|
|
|
* It appears that GTK 2 doesn't leave us any
|
|
|
|
* particularly sensible way to honour the
|
|
|
|
* "percentages" specification in the ctrl
|
|
|
|
* structure.
|
|
|
|
*/
|
2014-09-09 11:46:14 +00:00
|
|
|
cellrend = gtk_cell_renderer_text_new();
|
|
|
|
if (!ctrl->listbox.hscroll) {
|
2015-08-08 16:29:02 +00:00
|
|
|
g_object_set(G_OBJECT(cellrend),
|
|
|
|
"ellipsize", PANGO_ELLIPSIZE_END,
|
2018-10-29 19:50:29 +00:00
|
|
|
"ellipsize-set", true,
|
2015-08-31 13:36:12 +00:00
|
|
|
(const char *)NULL);
|
2014-09-09 11:46:14 +00:00
|
|
|
}
|
Formatting: standardise on "func(\n", not "func\n(".
If the function name (or expression) in a function call or declaration
is itself so long that even the first argument doesn't fit after it on
the same line, or if that would leave so little space that it would be
silly to try to wrap all the run-on lines into a tall thin column,
then I used to do this
ludicrously_long_function_name
(arg1, arg2, arg3);
and now prefer this
ludicrously_long_function_name(
arg1, arg2, arg3);
I picked up the habit from Python, where the latter idiom is required
by Python's syntactic significance of newlines (you can write the
former if you use a backslash-continuation, but pretty much everyone
seems to agree that that's much uglier). But I've found it works well
in C as well: it makes it more obvious that the previous line is
incomplete, it gives you a tiny bit more space to wrap the following
lines into (the old idiom indents the _third_ line one space beyond
the second), and I generally turn out to agree with the knock-on
indentation decisions made by at least Emacs if you do it in the
middle of a complex expression. Plus, of course, using the _same_
idiom between C and Python means less state-switching.
So, while I'm making annoying indentation changes in general, this
seems like a good time to dig out all the cases of the old idiom in
this code, and switch them over to the new.
2022-08-03 19:48:46 +00:00
|
|
|
column = gtk_tree_view_column_new_with_attributes(
|
|
|
|
"heading", cellrend, "text", i+1, (char *)NULL);
|
|
|
|
gtk_tree_view_column_set_sizing(
|
|
|
|
column, GTK_TREE_VIEW_COLUMN_GROW_ONLY);
|
2019-09-08 19:29:00 +00:00
|
|
|
gtk_tree_view_append_column(GTK_TREE_VIEW(w), column);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
GtkWidget *scroll;
|
|
|
|
|
|
|
|
scroll = gtk_scrolled_window_new(NULL, NULL);
|
Formatting: standardise on "func(\n", not "func\n(".
If the function name (or expression) in a function call or declaration
is itself so long that even the first argument doesn't fit after it on
the same line, or if that would leave so little space that it would be
silly to try to wrap all the run-on lines into a tall thin column,
then I used to do this
ludicrously_long_function_name
(arg1, arg2, arg3);
and now prefer this
ludicrously_long_function_name(
arg1, arg2, arg3);
I picked up the habit from Python, where the latter idiom is required
by Python's syntactic significance of newlines (you can write the
former if you use a backslash-continuation, but pretty much everyone
seems to agree that that's much uglier). But I've found it works well
in C as well: it makes it more obvious that the previous line is
incomplete, it gives you a tiny bit more space to wrap the following
lines into (the old idiom indents the _third_ line one space beyond
the second), and I generally turn out to agree with the knock-on
indentation decisions made by at least Emacs if you do it in the
middle of a complex expression. Plus, of course, using the _same_
idiom between C and Python means less state-switching.
So, while I'm making annoying indentation changes in general, this
seems like a good time to dig out all the cases of the old idiom in
this code, and switch them over to the new.
2022-08-03 19:48:46 +00:00
|
|
|
gtk_scrolled_window_set_shadow_type(
|
|
|
|
GTK_SCROLLED_WINDOW(scroll), GTK_SHADOW_IN);
|
2019-09-08 19:29:00 +00:00
|
|
|
gtk_widget_show(w);
|
|
|
|
gtk_container_add(GTK_CONTAINER(scroll), w);
|
|
|
|
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll),
|
|
|
|
GTK_POLICY_AUTOMATIC,
|
|
|
|
GTK_POLICY_ALWAYS);
|
Formatting: standardise on "func(\n", not "func\n(".
If the function name (or expression) in a function call or declaration
is itself so long that even the first argument doesn't fit after it on
the same line, or if that would leave so little space that it would be
silly to try to wrap all the run-on lines into a tall thin column,
then I used to do this
ludicrously_long_function_name
(arg1, arg2, arg3);
and now prefer this
ludicrously_long_function_name(
arg1, arg2, arg3);
I picked up the habit from Python, where the latter idiom is required
by Python's syntactic significance of newlines (you can write the
former if you use a backslash-continuation, but pretty much everyone
seems to agree that that's much uglier). But I've found it works well
in C as well: it makes it more obvious that the previous line is
incomplete, it gives you a tiny bit more space to wrap the following
lines into (the old idiom indents the _third_ line one space beyond
the second), and I generally turn out to agree with the knock-on
indentation decisions made by at least Emacs if you do it in the
middle of a complex expression. Plus, of course, using the _same_
idiom between C and Python means less state-switching.
So, while I'm making annoying indentation changes in general, this
seems like a good time to dig out all the cases of the old idiom in
this code, and switch them over to the new.
2022-08-03 19:48:46 +00:00
|
|
|
gtk_widget_set_size_request(
|
|
|
|
scroll, -1,
|
|
|
|
ctrl->listbox.height * get_listitemheight(w));
|
2019-09-08 19:29:00 +00:00
|
|
|
|
|
|
|
w = scroll;
|
|
|
|
}
|
2008-05-31 19:23:45 +00:00
|
|
|
#endif
|
|
|
|
}
|
2003-03-14 18:35:01 +00:00
|
|
|
|
Restructure dlgcontrol as a struct with an anon union.
This gets rid of that awkward STANDARD_PREFIX system in which every
branch of the old 'union control' had to repeat all the generic
fields, and then call sites had to make an arbitrary decision about
which branch to access them through.
That was the best we could do before accepting C99 features in this
code base. But now we have anonymous unions, so we don't need to put
up with that nonsense any more!
'dlgcontrol' is now a struct rather than a union, and the generic
fields common to all control types are ordinary members of the struct,
so you don't have to refer to them as ctrl->generic.foo at all, just
ctrl->foo, which saves verbiage at the point of use.
The extra per-control fields are still held in structures named after
the control type, so you'll still say ctrl->listbox.height or
whatever. But now those structures are themselves members of an
anonymous union field following the generic fields, so those
sub-structures don't have to reiterate all the standard stuff too.
While I'm here, I've promoted 'context2' from an editbox-specific
field to a generic one (it just seems silly _not_ to allow any control
to have two context fields if it needs it). Also, I had to rename the
boolean field 'tabdelay' to avoid it clashing with the subsidiary
structure field 'tabdelay', now that the former isn't generic.tabdelay
any more.
2022-05-01 08:55:52 +00:00
|
|
|
if (ctrl->label) {
|
2019-09-08 19:29:00 +00:00
|
|
|
GtkWidget *label, *container;
|
2008-04-02 14:48:06 +00:00
|
|
|
|
Restructure dlgcontrol as a struct with an anon union.
This gets rid of that awkward STANDARD_PREFIX system in which every
branch of the old 'union control' had to repeat all the generic
fields, and then call sites had to make an arbitrary decision about
which branch to access them through.
That was the best we could do before accepting C99 features in this
code base. But now we have anonymous unions, so we don't need to put
up with that nonsense any more!
'dlgcontrol' is now a struct rather than a union, and the generic
fields common to all control types are ordinary members of the struct,
so you don't have to refer to them as ctrl->generic.foo at all, just
ctrl->foo, which saves verbiage at the point of use.
The extra per-control fields are still held in structures named after
the control type, so you'll still say ctrl->listbox.height or
whatever. But now those structures are themselves members of an
anonymous union field following the generic fields, so those
sub-structures don't have to reiterate all the standard stuff too.
While I'm here, I've promoted 'context2' from an editbox-specific
field to a generic one (it just seems silly _not_ to allow any control
to have two context fields if it needs it). Also, I had to rename the
boolean field 'tabdelay' to avoid it clashing with the subsidiary
structure field 'tabdelay', now that the former isn't generic.tabdelay
any more.
2022-05-01 08:55:52 +00:00
|
|
|
label = gtk_label_new(ctrl->label);
|
2015-08-25 18:50:23 +00:00
|
|
|
#if GTK_CHECK_VERSION(3,0,0)
|
2015-08-23 14:01:07 +00:00
|
|
|
gtk_label_set_width_chars(GTK_LABEL(label), 3);
|
2015-08-25 18:50:23 +00:00
|
|
|
#endif
|
2003-03-14 18:35:01 +00:00
|
|
|
|
2019-09-08 19:29:00 +00:00
|
|
|
shortcut_add(scs, label, ctrl->listbox.shortcut,
|
|
|
|
SHORTCUT_UCTRL, uc);
|
|
|
|
|
|
|
|
container = columns_new(4);
|
|
|
|
if (ctrl->listbox.percentwidth == 100) {
|
|
|
|
columns_add(COLUMNS(container), label, 0, 1);
|
|
|
|
columns_force_left_align(COLUMNS(container), label);
|
|
|
|
columns_add(COLUMNS(container), w, 0, 1);
|
|
|
|
} else {
|
|
|
|
gint percentages[2];
|
|
|
|
percentages[1] = ctrl->listbox.percentwidth;
|
|
|
|
percentages[0] = 100 - ctrl->listbox.percentwidth;
|
|
|
|
columns_set_cols(COLUMNS(container), 2, percentages);
|
|
|
|
columns_add(COLUMNS(container), label, 0, 1);
|
|
|
|
columns_force_left_align(COLUMNS(container), label);
|
|
|
|
columns_add(COLUMNS(container), w, 1, 1);
|
Improve the align_next_to mechanism.
Various alignments I want to do in the host CA box have shown up
deficiencies in this system, so I've reworked it a bit.
Firstly, you can now specify more than two controls to be tied
together with an align_next_to (e.g. multiple checkboxes alongside
something else).
Secondly, as well as forcing the controls to be the same height as
each other, the layout algorithm will also move the later controls
further _downward_, so that their top y positions also line up. Until
now that hasn't been necessary, because they lined up already.
In the GTK implementation of this via the Columns class, I've renamed
'columns_force_same_height' to 'columns_align_next_to', and similarly
for some of the internal fields, since the latter change makes the
previous names a misnomer.
In the Windows implementation, I found it most convenient to set this
up by following a linked list of align_next_to fields backwards. But
it won't always be convenient to initialise them that way, so I've
also written a crude normaliser that will rewrite those links into a
canonical form. But I only call that on Windows; it's unnecessary in
GTK, where the Columns class provides plenty of per-widget extra
storage so I just keep each alignment class as a circular list.
2022-05-02 13:37:11 +00:00
|
|
|
columns_align_next_to(COLUMNS(container), label, w);
|
2019-09-08 19:29:00 +00:00
|
|
|
}
|
|
|
|
gtk_widget_show(label);
|
|
|
|
gtk_widget_show(w);
|
2008-04-02 14:48:06 +00:00
|
|
|
|
2019-09-08 19:29:00 +00:00
|
|
|
w = container;
|
|
|
|
uc->label = label;
|
|
|
|
}
|
2008-04-02 14:48:06 +00:00
|
|
|
|
2019-09-08 19:29:00 +00:00
|
|
|
break;
|
2003-03-13 19:52:28 +00:00
|
|
|
case CTRL_TEXT:
|
2015-08-23 14:01:07 +00:00
|
|
|
#if !GTK_CHECK_VERSION(3,0,0)
|
2019-09-08 19:29:00 +00:00
|
|
|
/*
|
|
|
|
* Wrapping text widgets don't sit well with the GTK2
|
|
|
|
* layout model, in which widgets state a minimum size
|
|
|
|
* and the whole window then adjusts to the smallest
|
|
|
|
* size it can sensibly take given its contents. A
|
|
|
|
* wrapping text widget _has_ no clear minimum size;
|
|
|
|
* instead it has a range of possibilities. It can be
|
|
|
|
* one line deep but 2000 wide, or two lines deep and
|
|
|
|
* 1000 pixels, or three by 867, or four by 500 and so
|
|
|
|
* on. It can be as short as you like provided you
|
|
|
|
* don't mind it being wide, or as narrow as you like
|
|
|
|
* provided you don't mind it being tall.
|
|
|
|
*
|
|
|
|
* Therefore, it fits very badly into the layout model.
|
|
|
|
* Hence the only thing to do is pick a width and let
|
|
|
|
* it choose its own number of lines. To do this I'm
|
|
|
|
* going to cheat a little. All new wrapping text
|
|
|
|
* widgets will be created with a minimal text content
|
|
|
|
* "X"; then, after the rest of the dialog box is set
|
|
|
|
* up and its size calculated, the text widgets will be
|
|
|
|
* told their width and given their real text, which
|
|
|
|
* will cause the size to be recomputed in the y
|
|
|
|
* direction (because many of them will expand to more
|
|
|
|
* than one line).
|
|
|
|
*/
|
2003-03-22 17:00:06 +00:00
|
|
|
uc->text = w = gtk_label_new("X");
|
2019-09-08 19:29:00 +00:00
|
|
|
uc->textsig =
|
2015-08-08 16:29:02 +00:00
|
|
|
g_signal_connect(G_OBJECT(w), "size-allocate",
|
|
|
|
G_CALLBACK(label_sizealloc), dp);
|
2015-08-23 14:01:07 +00:00
|
|
|
#else
|
|
|
|
/*
|
|
|
|
* In GTK3, this is all fixed, because the main aim of the
|
|
|
|
* new 'height-for-width' geometry management is to make
|
|
|
|
* wrapping labels behave sensibly. So now we can just do
|
|
|
|
* the obvious thing.
|
|
|
|
*/
|
Restructure dlgcontrol as a struct with an anon union.
This gets rid of that awkward STANDARD_PREFIX system in which every
branch of the old 'union control' had to repeat all the generic
fields, and then call sites had to make an arbitrary decision about
which branch to access them through.
That was the best we could do before accepting C99 features in this
code base. But now we have anonymous unions, so we don't need to put
up with that nonsense any more!
'dlgcontrol' is now a struct rather than a union, and the generic
fields common to all control types are ordinary members of the struct,
so you don't have to refer to them as ctrl->generic.foo at all, just
ctrl->foo, which saves verbiage at the point of use.
The extra per-control fields are still held in structures named after
the control type, so you'll still say ctrl->listbox.height or
whatever. But now those structures are themselves members of an
anonymous union field following the generic fields, so those
sub-structures don't have to reiterate all the standard stuff too.
While I'm here, I've promoted 'context2' from an editbox-specific
field to a generic one (it just seems silly _not_ to allow any control
to have two context fields if it needs it). Also, I had to rename the
boolean field 'tabdelay' to avoid it clashing with the subsidiary
structure field 'tabdelay', now that the former isn't generic.tabdelay
any more.
2022-05-01 08:55:52 +00:00
|
|
|
uc->text = w = gtk_label_new(uc->ctrl->label);
|
2015-08-23 14:01:07 +00:00
|
|
|
#endif
|
2022-05-12 18:57:10 +00:00
|
|
|
#if GTK_CHECK_VERSION(2,0,0)
|
2022-05-07 10:00:19 +00:00
|
|
|
gtk_label_set_selectable(GTK_LABEL(w), true);
|
|
|
|
gtk_widget_set_can_focus(w, false);
|
2022-05-12 18:57:10 +00:00
|
|
|
#endif
|
2015-08-31 12:57:34 +00:00
|
|
|
align_label_left(GTK_LABEL(w));
|
2022-05-07 07:23:38 +00:00
|
|
|
gtk_label_set_line_wrap(GTK_LABEL(w), ctrl->text.wrap);
|
|
|
|
if (!ctrl->text.wrap) {
|
|
|
|
gtk_widget_show(uc->text);
|
|
|
|
w = gtk_scrolled_window_new(NULL, NULL);
|
|
|
|
gtk_container_set_border_width(GTK_CONTAINER(w), 0);
|
|
|
|
gtk_container_add(GTK_CONTAINER(w), uc->text);
|
|
|
|
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(w),
|
|
|
|
GTK_POLICY_AUTOMATIC,
|
|
|
|
GTK_POLICY_NEVER);
|
2022-05-12 18:57:10 +00:00
|
|
|
#if GTK_CHECK_VERSION(2,0,0)
|
2022-05-07 07:23:38 +00:00
|
|
|
gtk_widget_set_can_focus(w, false);
|
2022-05-12 18:57:10 +00:00
|
|
|
#endif
|
2022-05-07 07:23:38 +00:00
|
|
|
}
|
2003-03-13 19:52:28 +00:00
|
|
|
break;
|
|
|
|
}
|
2003-03-15 15:50:42 +00:00
|
|
|
|
2019-09-08 19:29:00 +00:00
|
|
|
assert(w != NULL);
|
2003-03-15 15:50:42 +00:00
|
|
|
|
2019-09-08 19:29:00 +00:00
|
|
|
columns_add(cols, w,
|
Restructure dlgcontrol as a struct with an anon union.
This gets rid of that awkward STANDARD_PREFIX system in which every
branch of the old 'union control' had to repeat all the generic
fields, and then call sites had to make an arbitrary decision about
which branch to access them through.
That was the best we could do before accepting C99 features in this
code base. But now we have anonymous unions, so we don't need to put
up with that nonsense any more!
'dlgcontrol' is now a struct rather than a union, and the generic
fields common to all control types are ordinary members of the struct,
so you don't have to refer to them as ctrl->generic.foo at all, just
ctrl->foo, which saves verbiage at the point of use.
The extra per-control fields are still held in structures named after
the control type, so you'll still say ctrl->listbox.height or
whatever. But now those structures are themselves members of an
anonymous union field following the generic fields, so those
sub-structures don't have to reiterate all the standard stuff too.
While I'm here, I've promoted 'context2' from an editbox-specific
field to a generic one (it just seems silly _not_ to allow any control
to have two context fields if it needs it). Also, I had to rename the
boolean field 'tabdelay' to avoid it clashing with the subsidiary
structure field 'tabdelay', now that the former isn't generic.tabdelay
any more.
2022-05-01 08:55:52 +00:00
|
|
|
COLUMN_START(ctrl->column),
|
|
|
|
COLUMN_SPAN(ctrl->column));
|
2019-09-08 19:29:00 +00:00
|
|
|
if (left)
|
|
|
|
columns_force_left_align(cols, w);
|
Restructure dlgcontrol as a struct with an anon union.
This gets rid of that awkward STANDARD_PREFIX system in which every
branch of the old 'union control' had to repeat all the generic
fields, and then call sites had to make an arbitrary decision about
which branch to access them through.
That was the best we could do before accepting C99 features in this
code base. But now we have anonymous unions, so we don't need to put
up with that nonsense any more!
'dlgcontrol' is now a struct rather than a union, and the generic
fields common to all control types are ordinary members of the struct,
so you don't have to refer to them as ctrl->generic.foo at all, just
ctrl->foo, which saves verbiage at the point of use.
The extra per-control fields are still held in structures named after
the control type, so you'll still say ctrl->listbox.height or
whatever. But now those structures are themselves members of an
anonymous union field following the generic fields, so those
sub-structures don't have to reiterate all the standard stuff too.
While I'm here, I've promoted 'context2' from an editbox-specific
field to a generic one (it just seems silly _not_ to allow any control
to have two context fields if it needs it). Also, I had to rename the
boolean field 'tabdelay' to avoid it clashing with the subsidiary
structure field 'tabdelay', now that the former isn't generic.tabdelay
any more.
2022-05-01 08:55:52 +00:00
|
|
|
if (ctrl->align_next_to) {
|
2021-04-03 16:45:31 +00:00
|
|
|
struct uctrl *uc2 = dlg_find_byctrl(
|
Restructure dlgcontrol as a struct with an anon union.
This gets rid of that awkward STANDARD_PREFIX system in which every
branch of the old 'union control' had to repeat all the generic
fields, and then call sites had to make an arbitrary decision about
which branch to access them through.
That was the best we could do before accepting C99 features in this
code base. But now we have anonymous unions, so we don't need to put
up with that nonsense any more!
'dlgcontrol' is now a struct rather than a union, and the generic
fields common to all control types are ordinary members of the struct,
so you don't have to refer to them as ctrl->generic.foo at all, just
ctrl->foo, which saves verbiage at the point of use.
The extra per-control fields are still held in structures named after
the control type, so you'll still say ctrl->listbox.height or
whatever. But now those structures are themselves members of an
anonymous union field following the generic fields, so those
sub-structures don't have to reiterate all the standard stuff too.
While I'm here, I've promoted 'context2' from an editbox-specific
field to a generic one (it just seems silly _not_ to allow any control
to have two context fields if it needs it). Also, I had to rename the
boolean field 'tabdelay' to avoid it clashing with the subsidiary
structure field 'tabdelay', now that the former isn't generic.tabdelay
any more.
2022-05-01 08:55:52 +00:00
|
|
|
dp, ctrl->align_next_to);
|
2021-04-03 16:45:31 +00:00
|
|
|
assert(uc2);
|
Improve the align_next_to mechanism.
Various alignments I want to do in the host CA box have shown up
deficiencies in this system, so I've reworked it a bit.
Firstly, you can now specify more than two controls to be tied
together with an align_next_to (e.g. multiple checkboxes alongside
something else).
Secondly, as well as forcing the controls to be the same height as
each other, the layout algorithm will also move the later controls
further _downward_, so that their top y positions also line up. Until
now that hasn't been necessary, because they lined up already.
In the GTK implementation of this via the Columns class, I've renamed
'columns_force_same_height' to 'columns_align_next_to', and similarly
for some of the internal fields, since the latter change makes the
previous names a misnomer.
In the Windows implementation, I found it most convenient to set this
up by following a linked list of align_next_to fields backwards. But
it won't always be convenient to initialise them that way, so I've
also written a crude normaliser that will rewrite those links into a
canonical form. But I only call that on Windows; it's unnecessary in
GTK, where the Columns class provides plenty of per-widget extra
storage so I just keep each alignment class as a circular list.
2022-05-02 13:37:11 +00:00
|
|
|
columns_align_next_to(cols, w, uc2->toplevel);
|
2021-04-03 16:45:31 +00:00
|
|
|
|
|
|
|
#if GTK_CHECK_VERSION(3, 10, 0)
|
|
|
|
/* Slightly nicer to align baselines than just vertically
|
|
|
|
* centring, where the option is available */
|
|
|
|
gtk_widget_set_valign(w, GTK_ALIGN_BASELINE);
|
|
|
|
gtk_widget_set_valign(uc2->toplevel, GTK_ALIGN_BASELINE);
|
|
|
|
#endif
|
|
|
|
}
|
2019-09-08 19:29:00 +00:00
|
|
|
gtk_widget_show(w);
|
2003-03-16 12:37:48 +00:00
|
|
|
|
2019-09-08 19:29:00 +00:00
|
|
|
uc->toplevel = w;
|
|
|
|
dlg_add_uctrl(dp, uc);
|
2003-03-13 19:52:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct selparam {
|
2003-03-16 12:37:48 +00:00
|
|
|
struct dlgparam *dp;
|
2006-12-29 14:35:34 +00:00
|
|
|
GtkNotebook *panels;
|
2007-01-25 19:33:29 +00:00
|
|
|
GtkWidget *panel;
|
|
|
|
#if !GTK_CHECK_VERSION(2,0,0)
|
|
|
|
GtkWidget *treeitem;
|
2008-04-04 11:37:06 +00:00
|
|
|
#else
|
|
|
|
int depth;
|
|
|
|
GtkTreePath *treepath;
|
2007-01-25 19:33:29 +00:00
|
|
|
#endif
|
2003-03-16 12:37:48 +00:00
|
|
|
struct Shortcuts shortcuts;
|
2003-03-13 19:52:28 +00:00
|
|
|
};
|
|
|
|
|
2007-01-25 19:33:29 +00:00
|
|
|
#if GTK_CHECK_VERSION(2,0,0)
|
|
|
|
static void treeselection_changed(GtkTreeSelection *treeselection,
|
2019-09-08 19:29:00 +00:00
|
|
|
gpointer data)
|
2007-01-25 19:33:29 +00:00
|
|
|
{
|
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
|
|
|
struct selparam **sps = (struct selparam **)data, *sp;
|
2007-01-25 19:33:29 +00:00
|
|
|
GtkTreeModel *treemodel;
|
|
|
|
GtkTreeIter treeiter;
|
|
|
|
gint spindex;
|
|
|
|
gint page_num;
|
|
|
|
|
|
|
|
if (!gtk_tree_selection_get_selected(treeselection, &treemodel, &treeiter))
|
2019-09-08 19:29:00 +00:00
|
|
|
return;
|
2007-01-25 19:33:29 +00:00
|
|
|
|
|
|
|
gtk_tree_model_get(treemodel, &treeiter, TREESTORE_PARAMS, &spindex, -1);
|
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
|
|
|
sp = sps[spindex];
|
2007-01-25 19:33:29 +00:00
|
|
|
|
|
|
|
page_num = gtk_notebook_page_num(sp->panels, sp->panel);
|
2015-08-08 17:02:01 +00:00
|
|
|
gtk_notebook_set_current_page(sp->panels, page_num);
|
2007-01-25 19:33:29 +00:00
|
|
|
|
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
|
|
|
sp->dp->curr_panel = sp;
|
2007-01-25 19:33:29 +00:00
|
|
|
dlg_refresh(NULL, sp->dp);
|
|
|
|
|
|
|
|
sp->dp->shortcuts = &sp->shortcuts;
|
|
|
|
}
|
|
|
|
#else
|
2003-03-13 19:52:28 +00:00
|
|
|
static void treeitem_sel(GtkItem *item, gpointer data)
|
|
|
|
{
|
|
|
|
struct selparam *sp = (struct selparam *)data;
|
2006-12-29 14:35:34 +00:00
|
|
|
gint page_num;
|
2003-03-13 19:52:28 +00:00
|
|
|
|
2006-12-29 14:35:34 +00:00
|
|
|
page_num = gtk_notebook_page_num(sp->panels, sp->panel);
|
|
|
|
gtk_notebook_set_page(sp->panels, page_num);
|
2003-03-16 12:37:48 +00:00
|
|
|
|
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
|
|
|
sp->dp->curr_panel = sp;
|
2006-08-28 14:29:02 +00:00
|
|
|
dlg_refresh(NULL, sp->dp);
|
|
|
|
|
2003-03-16 12:37:48 +00:00
|
|
|
sp->dp->shortcuts = &sp->shortcuts;
|
2003-03-18 19:06:51 +00:00
|
|
|
sp->dp->currtreeitem = sp->treeitem;
|
2003-03-13 19:52:28 +00:00
|
|
|
}
|
2007-01-25 19:33:29 +00:00
|
|
|
#endif
|
2003-03-13 19:52:28 +00:00
|
|
|
|
2022-05-01 08:48:38 +00:00
|
|
|
bool dlg_is_visible(dlgcontrol *ctrl, dlgparam *dp)
|
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
|
|
|
{
|
|
|
|
struct uctrl *uc = dlg_find_byctrl(dp, ctrl);
|
|
|
|
/*
|
|
|
|
* A control is visible if it belongs to _no_ notebook page (i.e.
|
|
|
|
* it's one of the config-box-global buttons like Load or About),
|
|
|
|
* or if it belongs to the currently selected page.
|
|
|
|
*/
|
|
|
|
return uc->sp == NULL || uc->sp == dp->curr_panel;
|
|
|
|
}
|
|
|
|
|
2007-01-25 19:33:29 +00:00
|
|
|
#if !GTK_CHECK_VERSION(2,0,0)
|
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
|
|
|
static bool tree_grab_focus(struct dlgparam *dp)
|
2003-03-22 17:00:06 +00:00
|
|
|
{
|
|
|
|
int i, f;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* See if any of the treeitems has the focus.
|
|
|
|
*/
|
|
|
|
f = -1;
|
|
|
|
for (i = 0; i < dp->ntreeitems; i++)
|
|
|
|
if (GTK_WIDGET_HAS_FOCUS(dp->treeitems[i])) {
|
|
|
|
f = i;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (f >= 0)
|
2018-10-29 19:50:29 +00:00
|
|
|
return false;
|
2003-03-22 17:00:06 +00:00
|
|
|
else {
|
|
|
|
gtk_widget_grab_focus(dp->currtreeitem);
|
2018-10-29 19:50:29 +00:00
|
|
|
return true;
|
2003-03-22 17:00:06 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
gint tree_focus(GtkContainer *container, GtkDirectionType direction,
|
|
|
|
gpointer data)
|
|
|
|
{
|
|
|
|
struct dlgparam *dp = (struct dlgparam *)data;
|
|
|
|
|
2015-08-08 16:29:02 +00:00
|
|
|
g_signal_stop_emission_by_name(G_OBJECT(container), "focus");
|
2003-03-22 17:00:06 +00:00
|
|
|
/*
|
2018-10-29 19:50:29 +00:00
|
|
|
* If there's a focused treeitem, we return false to cause the
|
2003-03-22 17:00:06 +00:00
|
|
|
* focus to move on to some totally other control. If not, we
|
|
|
|
* focus the selected one.
|
|
|
|
*/
|
|
|
|
return tree_grab_focus(dp);
|
|
|
|
}
|
2007-01-25 19:33:29 +00:00
|
|
|
#endif
|
2003-03-22 17:00:06 +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
|
|
|
gint win_key_press(GtkWidget *widget, GdkEventKey *event, gpointer data)
|
2003-03-16 12:37:48 +00:00
|
|
|
{
|
|
|
|
struct dlgparam *dp = (struct dlgparam *)data;
|
|
|
|
|
2015-08-08 15:23:54 +00:00
|
|
|
if (event->keyval == GDK_KEY_Escape && dp->cancelbutton) {
|
2015-08-08 16:29:02 +00:00
|
|
|
g_signal_emit_by_name(G_OBJECT(dp->cancelbutton), "clicked");
|
2019-09-08 19:29:00 +00:00
|
|
|
return true;
|
2003-03-16 12:37:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if ((event->state & GDK_MOD1_MASK) &&
|
2019-09-08 19:29:00 +00:00
|
|
|
(unsigned char)event->string[0] > 0 &&
|
|
|
|
(unsigned char)event->string[0] <= 127) {
|
|
|
|
int schr = (unsigned char)event->string[0];
|
|
|
|
struct Shortcut *sc = &dp->shortcuts->sc[schr];
|
2003-03-16 12:37:48 +00:00
|
|
|
|
2019-09-08 19:29:00 +00:00
|
|
|
switch (sc->action) {
|
|
|
|
case SHORTCUT_TREE:
|
2007-01-25 19:33:29 +00:00
|
|
|
#if GTK_CHECK_VERSION(2,0,0)
|
2019-09-08 19:29:00 +00:00
|
|
|
gtk_widget_grab_focus(sc->widget);
|
2007-01-25 19:33:29 +00:00
|
|
|
#else
|
2019-09-08 19:29:00 +00:00
|
|
|
tree_grab_focus(dp);
|
|
|
|
#endif
|
|
|
|
break;
|
|
|
|
case SHORTCUT_FOCUS:
|
|
|
|
gtk_widget_grab_focus(sc->widget);
|
|
|
|
break;
|
|
|
|
case SHORTCUT_UCTRL:
|
|
|
|
/*
|
|
|
|
* We must do something sensible with a uctrl.
|
|
|
|
* Precisely what this is depends on the type of
|
|
|
|
* control.
|
|
|
|
*/
|
Restructure dlgcontrol as a struct with an anon union.
This gets rid of that awkward STANDARD_PREFIX system in which every
branch of the old 'union control' had to repeat all the generic
fields, and then call sites had to make an arbitrary decision about
which branch to access them through.
That was the best we could do before accepting C99 features in this
code base. But now we have anonymous unions, so we don't need to put
up with that nonsense any more!
'dlgcontrol' is now a struct rather than a union, and the generic
fields common to all control types are ordinary members of the struct,
so you don't have to refer to them as ctrl->generic.foo at all, just
ctrl->foo, which saves verbiage at the point of use.
The extra per-control fields are still held in structures named after
the control type, so you'll still say ctrl->listbox.height or
whatever. But now those structures are themselves members of an
anonymous union field following the generic fields, so those
sub-structures don't have to reiterate all the standard stuff too.
While I'm here, I've promoted 'context2' from an editbox-specific
field to a generic one (it just seems silly _not_ to allow any control
to have two context fields if it needs it). Also, I had to rename the
boolean field 'tabdelay' to avoid it clashing with the subsidiary
structure field 'tabdelay', now that the former isn't generic.tabdelay
any more.
2022-05-01 08:55:52 +00:00
|
|
|
switch (sc->uc->ctrl->type) {
|
2019-09-08 19:29:00 +00:00
|
|
|
case CTRL_CHECKBOX:
|
|
|
|
case CTRL_BUTTON:
|
|
|
|
/* Check boxes and buttons get the focus _and_ get toggled. */
|
|
|
|
gtk_widget_grab_focus(sc->uc->toplevel);
|
|
|
|
g_signal_emit_by_name(G_OBJECT(sc->uc->toplevel), "clicked");
|
|
|
|
break;
|
|
|
|
case CTRL_FILESELECT:
|
|
|
|
case CTRL_FONTSELECT:
|
|
|
|
/* File/font selectors have their buttons pressed (ooer),
|
|
|
|
* and focus transferred to the edit box. */
|
|
|
|
g_signal_emit_by_name(G_OBJECT(sc->uc->button), "clicked");
|
2022-05-01 07:39:49 +00:00
|
|
|
if (sc->uc->entry)
|
|
|
|
gtk_widget_grab_focus(sc->uc->entry);
|
2019-09-08 19:29:00 +00:00
|
|
|
break;
|
|
|
|
case CTRL_RADIO:
|
|
|
|
/*
|
|
|
|
* Radio buttons are fun, because they have
|
|
|
|
* multiple shortcuts. We must find whether the
|
|
|
|
* activated shortcut is the shortcut for the whole
|
|
|
|
* group, or for a particular button. In the former
|
|
|
|
* case, we find the currently selected button and
|
|
|
|
* focus it; in the latter, we focus-and-click the
|
|
|
|
* button whose shortcut was pressed.
|
|
|
|
*/
|
|
|
|
if (schr == sc->uc->ctrl->radio.shortcut) {
|
|
|
|
int i;
|
|
|
|
for (i = 0; i < sc->uc->ctrl->radio.nbuttons; i++)
|
Formatting: standardise on "func(\n", not "func\n(".
If the function name (or expression) in a function call or declaration
is itself so long that even the first argument doesn't fit after it on
the same line, or if that would leave so little space that it would be
silly to try to wrap all the run-on lines into a tall thin column,
then I used to do this
ludicrously_long_function_name
(arg1, arg2, arg3);
and now prefer this
ludicrously_long_function_name(
arg1, arg2, arg3);
I picked up the habit from Python, where the latter idiom is required
by Python's syntactic significance of newlines (you can write the
former if you use a backslash-continuation, but pretty much everyone
seems to agree that that's much uglier). But I've found it works well
in C as well: it makes it more obvious that the previous line is
incomplete, it gives you a tiny bit more space to wrap the following
lines into (the old idiom indents the _third_ line one space beyond
the second), and I generally turn out to agree with the knock-on
indentation decisions made by at least Emacs if you do it in the
middle of a complex expression. Plus, of course, using the _same_
idiom between C and Python means less state-switching.
So, while I'm making annoying indentation changes in general, this
seems like a good time to dig out all the cases of the old idiom in
this code, and switch them over to the new.
2022-08-03 19:48:46 +00:00
|
|
|
if (gtk_toggle_button_get_active(
|
|
|
|
GTK_TOGGLE_BUTTON(sc->uc->buttons[i]))) {
|
2019-09-08 19:29:00 +00:00
|
|
|
gtk_widget_grab_focus(sc->uc->buttons[i]);
|
|
|
|
}
|
|
|
|
} else if (sc->uc->ctrl->radio.shortcuts) {
|
|
|
|
int i;
|
|
|
|
for (i = 0; i < sc->uc->ctrl->radio.nbuttons; i++)
|
|
|
|
if (schr == sc->uc->ctrl->radio.shortcuts[i]) {
|
|
|
|
gtk_widget_grab_focus(sc->uc->buttons[i]);
|
Formatting: standardise on "func(\n", not "func\n(".
If the function name (or expression) in a function call or declaration
is itself so long that even the first argument doesn't fit after it on
the same line, or if that would leave so little space that it would be
silly to try to wrap all the run-on lines into a tall thin column,
then I used to do this
ludicrously_long_function_name
(arg1, arg2, arg3);
and now prefer this
ludicrously_long_function_name(
arg1, arg2, arg3);
I picked up the habit from Python, where the latter idiom is required
by Python's syntactic significance of newlines (you can write the
former if you use a backslash-continuation, but pretty much everyone
seems to agree that that's much uglier). But I've found it works well
in C as well: it makes it more obvious that the previous line is
incomplete, it gives you a tiny bit more space to wrap the following
lines into (the old idiom indents the _third_ line one space beyond
the second), and I generally turn out to agree with the knock-on
indentation decisions made by at least Emacs if you do it in the
middle of a complex expression. Plus, of course, using the _same_
idiom between C and Python means less state-switching.
So, while I'm making annoying indentation changes in general, this
seems like a good time to dig out all the cases of the old idiom in
this code, and switch them over to the new.
2022-08-03 19:48:46 +00:00
|
|
|
g_signal_emit_by_name(
|
|
|
|
G_OBJECT(sc->uc->buttons[i]), "clicked");
|
2019-09-08 19:29:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case CTRL_LISTBOX:
|
2008-04-04 10:56:26 +00:00
|
|
|
|
2008-05-31 19:23:45 +00:00
|
|
|
#if !GTK_CHECK_VERSION(2,4,0)
|
2019-09-08 19:29:00 +00:00
|
|
|
if (sc->uc->optmenu) {
|
|
|
|
GdkEventButton bev;
|
|
|
|
gint returnval;
|
|
|
|
|
|
|
|
gtk_widget_grab_focus(sc->uc->optmenu);
|
|
|
|
/* Option menus don't work using the "clicked" signal.
|
|
|
|
* We need to manufacture a button press event :-/ */
|
|
|
|
bev.type = GDK_BUTTON_PRESS;
|
|
|
|
bev.button = 1;
|
2015-08-08 16:29:02 +00:00
|
|
|
g_signal_emit_by_name(G_OBJECT(sc->uc->optmenu),
|
|
|
|
"button_press_event",
|
|
|
|
&bev, &returnval);
|
2019-09-08 19:29:00 +00:00
|
|
|
break;
|
|
|
|
}
|
2008-05-31 19:23:45 +00:00
|
|
|
#else
|
2019-09-08 19:29:00 +00:00
|
|
|
if (sc->uc->combo) {
|
|
|
|
gtk_widget_grab_focus(sc->uc->combo);
|
|
|
|
gtk_combo_box_popup(GTK_COMBO_BOX(sc->uc->combo));
|
|
|
|
break;
|
|
|
|
}
|
2008-05-31 19:23:45 +00:00
|
|
|
#endif
|
|
|
|
#if !GTK_CHECK_VERSION(2,0,0)
|
2019-09-08 19:29:00 +00:00
|
|
|
if (sc->uc->list) {
|
|
|
|
/*
|
|
|
|
* For GTK-1 style list boxes, we tell it to
|
|
|
|
* focus one of its children, which appears to
|
|
|
|
* do the Right Thing.
|
|
|
|
*/
|
2008-04-04 10:56:26 +00:00
|
|
|
gtk_container_focus(GTK_CONTAINER(sc->uc->list),
|
|
|
|
GTK_DIR_TAB_FORWARD);
|
2019-09-08 19:29:00 +00:00
|
|
|
break;
|
|
|
|
}
|
2008-04-04 10:56:26 +00:00
|
|
|
#else
|
2019-09-08 19:29:00 +00:00
|
|
|
if (sc->uc->treeview) {
|
|
|
|
gtk_widget_grab_focus(sc->uc->treeview);
|
|
|
|
break;
|
|
|
|
}
|
2008-04-04 10:56:26 +00:00
|
|
|
#endif
|
2019-09-09 18:07:55 +00:00
|
|
|
unreachable("bad listbox type in win_key_press");
|
2019-09-08 19:29:00 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2003-03-16 12:37:48 +00:00
|
|
|
}
|
|
|
|
|
2018-10-29 19:50:29 +00:00
|
|
|
return false;
|
2003-03-16 12:37:48 +00:00
|
|
|
}
|
|
|
|
|
2007-01-25 19:33:29 +00:00
|
|
|
#if !GTK_CHECK_VERSION(2,0,0)
|
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
|
|
|
gint tree_key_press(GtkWidget *widget, GdkEventKey *event, gpointer data)
|
2003-03-18 19:06:51 +00:00
|
|
|
{
|
|
|
|
struct dlgparam *dp = (struct dlgparam *)data;
|
|
|
|
|
|
|
|
if (event->keyval == GDK_Up || event->keyval == GDK_KP_Up ||
|
|
|
|
event->keyval == GDK_Down || event->keyval == GDK_KP_Down) {
|
2003-03-22 17:00:06 +00:00
|
|
|
int dir, i, j = -1;
|
2003-03-18 19:06:51 +00:00
|
|
|
for (i = 0; i < dp->ntreeitems; i++)
|
2003-03-22 17:00:06 +00:00
|
|
|
if (widget == dp->treeitems[i])
|
2019-09-08 19:29:00 +00:00
|
|
|
break;
|
|
|
|
if (i < dp->ntreeitems) {
|
|
|
|
if (event->keyval == GDK_Up || event->keyval == GDK_KP_Up)
|
|
|
|
dir = -1;
|
|
|
|
else
|
|
|
|
dir = +1;
|
|
|
|
|
|
|
|
while (1) {
|
|
|
|
i += dir;
|
|
|
|
if (i < 0 || i >= dp->ntreeitems)
|
|
|
|
break; /* nothing in that dir to select */
|
|
|
|
/*
|
|
|
|
* Determine if this tree item is visible.
|
|
|
|
*/
|
|
|
|
{
|
|
|
|
GtkWidget *w = dp->treeitems[i];
|
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 vis = true;
|
2019-09-08 19:29:00 +00:00
|
|
|
while (w && (GTK_IS_TREE_ITEM(w) || GTK_IS_TREE(w))) {
|
|
|
|
if (!GTK_WIDGET_VISIBLE(w)) {
|
|
|
|
vis = false;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
w = w->parent;
|
|
|
|
}
|
|
|
|
if (vis) {
|
|
|
|
j = i; /* got one */
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2015-08-08 16:29:02 +00:00
|
|
|
g_signal_stop_emission_by_name(G_OBJECT(widget), "key_press_event");
|
2003-03-18 19:06:51 +00:00
|
|
|
if (j >= 0) {
|
2015-08-08 16:29:02 +00:00
|
|
|
g_signal_emit_by_name(G_OBJECT(dp->treeitems[j]), "toggle");
|
2003-03-18 19:06:51 +00:00
|
|
|
gtk_widget_grab_focus(dp->treeitems[j]);
|
|
|
|
}
|
2018-10-29 19:50:29 +00:00
|
|
|
return true;
|
2003-03-18 19:06:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2003-03-22 17:00:06 +00:00
|
|
|
* It's nice for Left and Right to expand and collapse tree
|
|
|
|
* branches.
|
2003-03-18 19:06:51 +00:00
|
|
|
*/
|
2003-03-22 17:00:06 +00:00
|
|
|
if (event->keyval == GDK_Left || event->keyval == GDK_KP_Left) {
|
2015-08-08 16:29:02 +00:00
|
|
|
g_signal_stop_emission_by_name(G_OBJECT(widget), "key_press_event");
|
2019-09-08 19:29:00 +00:00
|
|
|
gtk_tree_item_collapse(GTK_TREE_ITEM(widget));
|
|
|
|
return true;
|
2003-03-22 17:00:06 +00:00
|
|
|
}
|
|
|
|
if (event->keyval == GDK_Right || event->keyval == GDK_KP_Right) {
|
2015-08-08 16:29:02 +00:00
|
|
|
g_signal_stop_emission_by_name(G_OBJECT(widget), "key_press_event");
|
2019-09-08 19:29:00 +00:00
|
|
|
gtk_tree_item_expand(GTK_TREE_ITEM(widget));
|
|
|
|
return true;
|
2003-03-18 19:06:51 +00:00
|
|
|
}
|
2003-03-22 17:00:06 +00:00
|
|
|
|
2018-10-29 19:50:29 +00:00
|
|
|
return false;
|
2003-03-18 19:06:51 +00:00
|
|
|
}
|
2007-01-25 19:33:29 +00:00
|
|
|
#endif
|
2003-03-18 19:06:51 +00:00
|
|
|
|
2006-08-28 14:29:02 +00:00
|
|
|
static void shortcut_highlight(GtkWidget *labelw, int chr)
|
2003-03-16 12:37:48 +00:00
|
|
|
{
|
|
|
|
GtkLabel *label = GTK_LABEL(labelw);
|
2015-08-08 17:02:01 +00:00
|
|
|
const gchar *currstr;
|
|
|
|
gchar *pattern;
|
2003-03-16 12:37:48 +00:00
|
|
|
int i;
|
|
|
|
|
2015-08-08 17:02:01 +00:00
|
|
|
#if !GTK_CHECK_VERSION(2,0,0)
|
|
|
|
{
|
|
|
|
gchar *currstr_nonconst;
|
|
|
|
gtk_label_get(label, &currstr_nonconst);
|
|
|
|
currstr = currstr_nonconst;
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
currstr = gtk_label_get_text(label);
|
|
|
|
#endif
|
|
|
|
|
2006-08-28 14:29:02 +00:00
|
|
|
for (i = 0; currstr[i]; i++)
|
2019-09-08 19:29:00 +00:00
|
|
|
if (tolower((unsigned char)currstr[i]) == chr) {
|
|
|
|
pattern = dupprintf("%*s_", i, "");
|
|
|
|
gtk_label_set_pattern(label, pattern);
|
|
|
|
sfree(pattern);
|
|
|
|
break;
|
|
|
|
}
|
2006-08-28 14:29:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void shortcut_add(struct Shortcuts *scs, GtkWidget *labelw,
|
2019-09-08 19:29:00 +00:00
|
|
|
int chr, int action, void *ptr)
|
2006-08-28 14:29:02 +00:00
|
|
|
{
|
2003-03-16 12:37:48 +00:00
|
|
|
if (chr == NO_SHORTCUT)
|
2019-09-08 19:29:00 +00:00
|
|
|
return;
|
2003-03-16 12:37:48 +00:00
|
|
|
|
|
|
|
chr = tolower((unsigned char)chr);
|
|
|
|
|
|
|
|
assert(scs->sc[chr].action == SHORTCUT_EMPTY);
|
|
|
|
|
|
|
|
scs->sc[chr].action = action;
|
|
|
|
|
2015-09-26 12:12:25 +00:00
|
|
|
if (action == SHORTCUT_FOCUS || action == SHORTCUT_TREE) {
|
2019-09-08 19:29:00 +00:00
|
|
|
scs->sc[chr].uc = NULL;
|
|
|
|
scs->sc[chr].widget = (GtkWidget *)ptr;
|
2003-03-16 12:37:48 +00:00
|
|
|
} else {
|
2019-09-08 19:29:00 +00:00
|
|
|
scs->sc[chr].widget = NULL;
|
|
|
|
scs->sc[chr].uc = (struct uctrl *)ptr;
|
2003-03-16 12:37:48 +00:00
|
|
|
}
|
|
|
|
|
2006-08-28 14:29:02 +00:00
|
|
|
shortcut_highlight(labelw, chr);
|
2003-03-16 12:37:48 +00:00
|
|
|
}
|
|
|
|
|
2018-11-03 08:25:28 +00:00
|
|
|
static int get_listitemheight(GtkWidget *w)
|
2003-04-09 18:46:45 +00:00
|
|
|
{
|
2008-04-04 10:56:26 +00:00
|
|
|
#if !GTK_CHECK_VERSION(2,0,0)
|
|
|
|
GtkWidget *listitem = gtk_list_item_new_with_label("foo");
|
|
|
|
GtkRequisition req;
|
|
|
|
gtk_widget_size_request(listitem, &req);
|
2015-08-08 16:29:02 +00:00
|
|
|
g_object_ref_sink(G_OBJECT(listitem));
|
2008-04-04 10:56:26 +00:00
|
|
|
return req.height;
|
|
|
|
#else
|
2008-04-02 14:48:06 +00:00
|
|
|
int height;
|
|
|
|
GtkCellRenderer *cr = gtk_cell_renderer_text_new();
|
2015-08-22 12:53:29 +00:00
|
|
|
#if GTK_CHECK_VERSION(3,0,0)
|
|
|
|
{
|
|
|
|
GtkRequisition req;
|
|
|
|
/*
|
|
|
|
* Since none of my list items wraps in this GUI, no
|
|
|
|
* interesting width-for-height behaviour should be happening,
|
|
|
|
* so I don't think it should matter here whether I ask for
|
|
|
|
* the minimum or natural height.
|
|
|
|
*/
|
|
|
|
gtk_cell_renderer_get_preferred_size(cr, w, &req, NULL);
|
|
|
|
height = req.height;
|
|
|
|
}
|
|
|
|
#else
|
2008-04-02 14:48:06 +00:00
|
|
|
gtk_cell_renderer_get_size(cr, w, NULL, NULL, NULL, NULL, &height);
|
2015-08-22 12:53:29 +00:00
|
|
|
#endif
|
2008-04-02 14:48:06 +00:00
|
|
|
g_object_ref(G_OBJECT(cr));
|
2015-08-08 16:29:02 +00:00
|
|
|
g_object_ref_sink(G_OBJECT(cr));
|
2008-04-02 14:48:06 +00:00
|
|
|
g_object_unref(G_OBJECT(cr));
|
|
|
|
return height;
|
2008-04-04 10:56:26 +00:00
|
|
|
#endif
|
2003-04-09 18:46:45 +00:00
|
|
|
}
|
|
|
|
|
2015-08-25 18:44:44 +00:00
|
|
|
#if GTK_CHECK_VERSION(2,0,0)
|
|
|
|
void initial_treeview_collapse(struct dlgparam *dp, GtkWidget *tree)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Collapse the deeper branches of the treeview into the state we
|
|
|
|
* like them to start off in. See comment below in do_config_box.
|
|
|
|
*/
|
|
|
|
int i;
|
|
|
|
for (i = 0; i < dp->nselparams; i++)
|
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
|
|
|
if (dp->selparams[i]->depth >= 2)
|
2015-08-25 18:44:44 +00:00
|
|
|
gtk_tree_view_collapse_row(GTK_TREE_VIEW(tree),
|
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
|
|
|
dp->selparams[i]->treepath);
|
2015-08-25 18:44:44 +00:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if GTK_CHECK_VERSION(3,0,0)
|
|
|
|
void treeview_map_event(GtkWidget *tree, gpointer data)
|
|
|
|
{
|
|
|
|
struct dlgparam *dp = (struct dlgparam *)data;
|
|
|
|
GtkAllocation alloc;
|
|
|
|
gtk_widget_get_allocation(tree, &alloc);
|
|
|
|
gtk_widget_set_size_request(tree, alloc.width, -1);
|
|
|
|
initial_treeview_collapse(dp, tree);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
Make the configuration dialog non-modal.
Now every call to do_config_box is replaced with a call to
create_config_box, which returns immediately having constructed the
new GTK window object, and is passed a callback function which it will
arrange to be called when the dialog terminates (whether by OK or by
Cancel). That callback is now what triggers the construction of a
session window after 'Open' is pressed in the initial config box, or
the actual mid-session reconfiguration action after 'Apply' is pressed
in a Change Settings box.
We were already prepared to ignore the re-selection of 'Change
Settings' from the context menu of a window that already had a Change
Settings box open (and not accidentally create a second config box for
the same window); but now we do slightly better, by finding the
existing config box and un-minimising and raising it, in case the user
had forgotten it was there.
That's a useful featurelet, but not the main purpose of this change.
The mani point, of course, is that now the multi-window GtkApplication
based front ends now don't do anything confusing to the nesting of
gtk_main() when config boxes are involved. Whether you're changing the
settings of one (or more than one) of your already-running sessions,
preparing to start up a new PuTTY connection, or both at once, we stay
in the same top-level instance of gtk_main() and all sessions' top-
level callbacks continue to run sensibly.
2017-11-26 11:58:02 +00:00
|
|
|
GtkWidget *create_config_box(const char *title, Conf *conf,
|
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 midsession, int protcfginfo,
|
Make the configuration dialog non-modal.
Now every call to do_config_box is replaced with a call to
create_config_box, which returns immediately having constructed the
new GTK window object, and is passed a callback function which it will
arrange to be called when the dialog terminates (whether by OK or by
Cancel). That callback is now what triggers the construction of a
session window after 'Open' is pressed in the initial config box, or
the actual mid-session reconfiguration action after 'Apply' is pressed
in a Change Settings box.
We were already prepared to ignore the re-selection of 'Change
Settings' from the context menu of a window that already had a Change
Settings box open (and not accidentally create a second config box for
the same window); but now we do slightly better, by finding the
existing config box and un-minimising and raising it, in case the user
had forgotten it was there.
That's a useful featurelet, but not the main purpose of this change.
The mani point, of course, is that now the multi-window GtkApplication
based front ends now don't do anything confusing to the nesting of
gtk_main() when config boxes are involved. Whether you're changing the
settings of one (or more than one) of your already-running sessions,
preparing to start up a new PuTTY connection, or both at once, we stay
in the same top-level instance of gtk_main() and all sessions' top-
level callbacks continue to run sensibly.
2017-11-26 11:58:02 +00:00
|
|
|
post_dialog_fn_t after, void *afterctx)
|
2003-03-13 19:52:28 +00:00
|
|
|
{
|
|
|
|
GtkWidget *window, *hbox, *vbox, *cols, *label,
|
2019-09-08 19:29:00 +00:00
|
|
|
*tree, *treescroll, *panels, *panelvbox;
|
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 index, level, protocol;
|
2003-03-13 19:52:28 +00:00
|
|
|
char *path;
|
2007-01-25 19:33:29 +00:00
|
|
|
#if GTK_CHECK_VERSION(2,0,0)
|
|
|
|
GtkTreeStore *treestore;
|
|
|
|
GtkCellRenderer *treerenderer;
|
|
|
|
GtkTreeViewColumn *treecolumn;
|
|
|
|
GtkTreeSelection *treeselection;
|
|
|
|
GtkTreeIter treeiterlevels[8];
|
|
|
|
#else
|
2003-03-13 19:52:28 +00:00
|
|
|
GtkTreeItem *treeitemlevels[8];
|
|
|
|
GtkTree *treelevels[8];
|
2007-01-25 19:33:29 +00:00
|
|
|
#endif
|
Make the configuration dialog non-modal.
Now every call to do_config_box is replaced with a call to
create_config_box, which returns immediately having constructed the
new GTK window object, and is passed a callback function which it will
arrange to be called when the dialog terminates (whether by OK or by
Cancel). That callback is now what triggers the construction of a
session window after 'Open' is pressed in the initial config box, or
the actual mid-session reconfiguration action after 'Apply' is pressed
in a Change Settings box.
We were already prepared to ignore the re-selection of 'Change
Settings' from the context menu of a window that already had a Change
Settings box open (and not accidentally create a second config box for
the same window); but now we do slightly better, by finding the
existing config box and un-minimising and raising it, in case the user
had forgotten it was there.
That's a useful featurelet, but not the main purpose of this change.
The mani point, of course, is that now the multi-window GtkApplication
based front ends now don't do anything confusing to the nesting of
gtk_main() when config boxes are involved. Whether you're changing the
settings of one (or more than one) of your already-running sessions,
preparing to start up a new PuTTY connection, or both at once, we stay
in the same top-level instance of gtk_main() and all sessions' top-
level callbacks continue to run sensibly.
2017-11-26 11:58:02 +00:00
|
|
|
struct dlgparam *dp;
|
2003-03-16 12:37:48 +00:00
|
|
|
struct Shortcuts scs;
|
2003-03-13 19:52:28 +00:00
|
|
|
|
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
|
|
|
struct selparam **selparams = NULL;
|
New array-growing macros: sgrowarray and sgrowarrayn.
The idea of these is that they centralise the common idiom along the
lines of
if (logical_array_len >= physical_array_size) {
physical_array_size = logical_array_len * 5 / 4 + 256;
array = sresize(array, physical_array_size, ElementType);
}
which happens at a zillion call sites throughout this code base, with
different random choices of the geometric factor and additive
constant, sometimes forgetting them completely, and generally doing a
lot of repeated work.
The new macro sgrowarray(array,size,n) has the semantics: here are the
array pointer and its physical size for you to modify, now please
ensure that the nth element exists, so I can write into it. And
sgrowarrayn(array,size,n,m) is the same except that it ensures that
the array has size at least n+m (so sgrowarray is just the special
case where m=1).
Now that this is a single centralised implementation that will be used
everywhere, I've also gone to more effort in the implementation, with
careful overflow checks that would have been painful to put at all the
previous call sites.
This commit also switches over every use of sresize(), apart from a
few where I really didn't think it would gain anything. A consequence
of that is that a lot of array-size variables have to have their types
changed to size_t, because the macros require that (they address-take
the size to pass to the underlying function).
2019-02-28 20:07:30 +00:00
|
|
|
size_t nselparams = 0, selparamsize = 0;
|
2003-03-13 19:52:28 +00:00
|
|
|
|
Make the configuration dialog non-modal.
Now every call to do_config_box is replaced with a call to
create_config_box, which returns immediately having constructed the
new GTK window object, and is passed a callback function which it will
arrange to be called when the dialog terminates (whether by OK or by
Cancel). That callback is now what triggers the construction of a
session window after 'Open' is pressed in the initial config box, or
the actual mid-session reconfiguration action after 'Apply' is pressed
in a Change Settings box.
We were already prepared to ignore the re-selection of 'Change
Settings' from the context menu of a window that already had a Change
Settings box open (and not accidentally create a second config box for
the same window); but now we do slightly better, by finding the
existing config box and un-minimising and raising it, in case the user
had forgotten it was there.
That's a useful featurelet, but not the main purpose of this change.
The mani point, of course, is that now the multi-window GtkApplication
based front ends now don't do anything confusing to the nesting of
gtk_main() when config boxes are involved. Whether you're changing the
settings of one (or more than one) of your already-running sessions,
preparing to start up a new PuTTY connection, or both at once, we stay
in the same top-level instance of gtk_main() and all sessions' top-
level callbacks continue to run sensibly.
2017-11-26 11:58:02 +00:00
|
|
|
dp = snew(struct dlgparam);
|
|
|
|
dp->after = after;
|
|
|
|
dp->afterctx = afterctx;
|
|
|
|
|
|
|
|
dlg_init(dp);
|
2003-03-15 15:50:42 +00:00
|
|
|
|
2003-03-16 12:37:48 +00:00
|
|
|
for (index = 0; index < lenof(scs.sc); index++) {
|
2019-09-08 19:29:00 +00:00
|
|
|
scs.sc[index].action = SHORTCUT_EMPTY;
|
2003-03-16 12:37:48 +00:00
|
|
|
}
|
|
|
|
|
2015-08-31 14:45:18 +00:00
|
|
|
window = our_dialog_new();
|
2003-04-10 08:53:43 +00:00
|
|
|
|
Make the configuration dialog non-modal.
Now every call to do_config_box is replaced with a call to
create_config_box, which returns immediately having constructed the
new GTK window object, and is passed a callback function which it will
arrange to be called when the dialog terminates (whether by OK or by
Cancel). That callback is now what triggers the construction of a
session window after 'Open' is pressed in the initial config box, or
the actual mid-session reconfiguration action after 'Apply' is pressed
in a Change Settings box.
We were already prepared to ignore the re-selection of 'Change
Settings' from the context menu of a window that already had a Change
Settings box open (and not accidentally create a second config box for
the same window); but now we do slightly better, by finding the
existing config box and un-minimising and raising it, in case the user
had forgotten it was there.
That's a useful featurelet, but not the main purpose of this change.
The mani point, of course, is that now the multi-window GtkApplication
based front ends now don't do anything confusing to the nesting of
gtk_main() when config boxes are involved. Whether you're changing the
settings of one (or more than one) of your already-running sessions,
preparing to start up a new PuTTY connection, or both at once, we stay
in the same top-level instance of gtk_main() and all sessions' top-
level callbacks continue to run sensibly.
2017-11-26 11:58:02 +00:00
|
|
|
dp->ctrlbox = ctrl_new_box();
|
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
|
|
|
protocol = conf_get_int(conf, CONF_protocol);
|
Make the configuration dialog non-modal.
Now every call to do_config_box is replaced with a call to
create_config_box, which returns immediately having constructed the
new GTK window object, and is passed a callback function which it will
arrange to be called when the dialog terminates (whether by OK or by
Cancel). That callback is now what triggers the construction of a
session window after 'Open' is pressed in the initial config box, or
the actual mid-session reconfiguration action after 'Apply' is pressed
in a Change Settings box.
We were already prepared to ignore the re-selection of 'Change
Settings' from the context menu of a window that already had a Change
Settings box open (and not accidentally create a second config box for
the same window); but now we do slightly better, by finding the
existing config box and un-minimising and raising it, in case the user
had forgotten it was there.
That's a useful featurelet, but not the main purpose of this change.
The mani point, of course, is that now the multi-window GtkApplication
based front ends now don't do anything confusing to the nesting of
gtk_main() when config boxes are involved. Whether you're changing the
settings of one (or more than one) of your already-running sessions,
preparing to start up a new PuTTY connection, or both at once, we stay
in the same top-level instance of gtk_main() and all sessions' top-
level callbacks continue to run sensibly.
2017-11-26 11:58:02 +00:00
|
|
|
setup_config_box(dp->ctrlbox, midsession, protocol, protcfginfo);
|
|
|
|
unix_setup_config_box(dp->ctrlbox, midsession, protocol);
|
|
|
|
gtk_setup_config_box(dp->ctrlbox, midsession, window);
|
2003-03-13 19:52:28 +00:00
|
|
|
|
2003-03-22 17:00:06 +00:00
|
|
|
gtk_window_set_title(GTK_WINDOW(window), title);
|
2018-10-29 19:50:29 +00:00
|
|
|
hbox = gtk_hbox_new(false, 4);
|
|
|
|
our_dialog_add_to_content_area(GTK_WINDOW(window), hbox, true, true, 0);
|
2003-03-14 18:35:01 +00:00
|
|
|
gtk_container_set_border_width(GTK_CONTAINER(hbox), 10);
|
2003-03-13 19:52:28 +00:00
|
|
|
gtk_widget_show(hbox);
|
2018-10-29 19:50:29 +00:00
|
|
|
vbox = gtk_vbox_new(false, 4);
|
|
|
|
gtk_box_pack_start(GTK_BOX(hbox), vbox, false, false, 0);
|
2003-03-13 19:52:28 +00:00
|
|
|
gtk_widget_show(vbox);
|
|
|
|
cols = columns_new(4);
|
2018-10-29 19:50:29 +00:00
|
|
|
gtk_box_pack_start(GTK_BOX(vbox), cols, false, false, 0);
|
2003-03-13 19:52:28 +00:00
|
|
|
gtk_widget_show(cols);
|
|
|
|
label = gtk_label_new("Category:");
|
|
|
|
columns_add(COLUMNS(cols), label, 0, 1);
|
|
|
|
columns_force_left_align(COLUMNS(cols), label);
|
|
|
|
gtk_widget_show(label);
|
|
|
|
treescroll = gtk_scrolled_window_new(NULL, NULL);
|
2007-01-25 19:33:29 +00:00
|
|
|
#if GTK_CHECK_VERSION(2,0,0)
|
Formatting: standardise on "func(\n", not "func\n(".
If the function name (or expression) in a function call or declaration
is itself so long that even the first argument doesn't fit after it on
the same line, or if that would leave so little space that it would be
silly to try to wrap all the run-on lines into a tall thin column,
then I used to do this
ludicrously_long_function_name
(arg1, arg2, arg3);
and now prefer this
ludicrously_long_function_name(
arg1, arg2, arg3);
I picked up the habit from Python, where the latter idiom is required
by Python's syntactic significance of newlines (you can write the
former if you use a backslash-continuation, but pretty much everyone
seems to agree that that's much uglier). But I've found it works well
in C as well: it makes it more obvious that the previous line is
incomplete, it gives you a tiny bit more space to wrap the following
lines into (the old idiom indents the _third_ line one space beyond
the second), and I generally turn out to agree with the knock-on
indentation decisions made by at least Emacs if you do it in the
middle of a complex expression. Plus, of course, using the _same_
idiom between C and Python means less state-switching.
So, while I'm making annoying indentation changes in general, this
seems like a good time to dig out all the cases of the old idiom in
this code, and switch them over to the new.
2022-08-03 19:48:46 +00:00
|
|
|
treestore = gtk_tree_store_new(
|
|
|
|
TREESTORE_NUM, G_TYPE_STRING, G_TYPE_INT);
|
2007-01-25 19:33:29 +00:00
|
|
|
tree = gtk_tree_view_new_with_model(GTK_TREE_MODEL(treestore));
|
2018-10-29 19:50:29 +00:00
|
|
|
gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(tree), false);
|
2007-01-25 19:33:29 +00:00
|
|
|
treerenderer = gtk_cell_renderer_text_new();
|
Formatting: standardise on "func(\n", not "func\n(".
If the function name (or expression) in a function call or declaration
is itself so long that even the first argument doesn't fit after it on
the same line, or if that would leave so little space that it would be
silly to try to wrap all the run-on lines into a tall thin column,
then I used to do this
ludicrously_long_function_name
(arg1, arg2, arg3);
and now prefer this
ludicrously_long_function_name(
arg1, arg2, arg3);
I picked up the habit from Python, where the latter idiom is required
by Python's syntactic significance of newlines (you can write the
former if you use a backslash-continuation, but pretty much everyone
seems to agree that that's much uglier). But I've found it works well
in C as well: it makes it more obvious that the previous line is
incomplete, it gives you a tiny bit more space to wrap the following
lines into (the old idiom indents the _third_ line one space beyond
the second), and I generally turn out to agree with the knock-on
indentation decisions made by at least Emacs if you do it in the
middle of a complex expression. Plus, of course, using the _same_
idiom between C and Python means less state-switching.
So, while I'm making annoying indentation changes in general, this
seems like a good time to dig out all the cases of the old idiom in
this code, and switch them over to the new.
2022-08-03 19:48:46 +00:00
|
|
|
treecolumn = gtk_tree_view_column_new_with_attributes(
|
|
|
|
"Label", treerenderer, "text", 0, NULL);
|
2007-01-25 19:33:29 +00:00
|
|
|
gtk_tree_view_append_column(GTK_TREE_VIEW(tree), treecolumn);
|
|
|
|
treeselection = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree));
|
|
|
|
gtk_tree_selection_set_mode(treeselection, GTK_SELECTION_BROWSE);
|
|
|
|
gtk_container_add(GTK_CONTAINER(treescroll), tree);
|
|
|
|
#else
|
2003-03-13 19:52:28 +00:00
|
|
|
tree = gtk_tree_new();
|
|
|
|
gtk_tree_set_view_mode(GTK_TREE(tree), GTK_TREE_VIEW_ITEM);
|
2003-03-14 18:35:01 +00:00
|
|
|
gtk_tree_set_selection_mode(GTK_TREE(tree), GTK_SELECTION_BROWSE);
|
Make the configuration dialog non-modal.
Now every call to do_config_box is replaced with a call to
create_config_box, which returns immediately having constructed the
new GTK window object, and is passed a callback function which it will
arrange to be called when the dialog terminates (whether by OK or by
Cancel). That callback is now what triggers the construction of a
session window after 'Open' is pressed in the initial config box, or
the actual mid-session reconfiguration action after 'Apply' is pressed
in a Change Settings box.
We were already prepared to ignore the re-selection of 'Change
Settings' from the context menu of a window that already had a Change
Settings box open (and not accidentally create a second config box for
the same window); but now we do slightly better, by finding the
existing config box and un-minimising and raising it, in case the user
had forgotten it was there.
That's a useful featurelet, but not the main purpose of this change.
The mani point, of course, is that now the multi-window GtkApplication
based front ends now don't do anything confusing to the nesting of
gtk_main() when config boxes are involved. Whether you're changing the
settings of one (or more than one) of your already-running sessions,
preparing to start up a new PuTTY connection, or both at once, we stay
in the same top-level instance of gtk_main() and all sessions' top-
level callbacks continue to run sensibly.
2017-11-26 11:58:02 +00:00
|
|
|
g_signal_connect(G_OBJECT(tree), "focus", G_CALLBACK(tree_focus), dp);
|
2007-01-25 19:33:29 +00:00
|
|
|
#endif
|
2015-08-08 16:29:02 +00:00
|
|
|
g_signal_connect(G_OBJECT(tree), "focus_in_event",
|
Make the configuration dialog non-modal.
Now every call to do_config_box is replaced with a call to
create_config_box, which returns immediately having constructed the
new GTK window object, and is passed a callback function which it will
arrange to be called when the dialog terminates (whether by OK or by
Cancel). That callback is now what triggers the construction of a
session window after 'Open' is pressed in the initial config box, or
the actual mid-session reconfiguration action after 'Apply' is pressed
in a Change Settings box.
We were already prepared to ignore the re-selection of 'Change
Settings' from the context menu of a window that already had a Change
Settings box open (and not accidentally create a second config box for
the same window); but now we do slightly better, by finding the
existing config box and un-minimising and raising it, in case the user
had forgotten it was there.
That's a useful featurelet, but not the main purpose of this change.
The mani point, of course, is that now the multi-window GtkApplication
based front ends now don't do anything confusing to the nesting of
gtk_main() when config boxes are involved. Whether you're changing the
settings of one (or more than one) of your already-running sessions,
preparing to start up a new PuTTY connection, or both at once, we stay
in the same top-level instance of gtk_main() and all sessions' top-
level callbacks continue to run sensibly.
2017-11-26 11:58:02 +00:00
|
|
|
G_CALLBACK(widget_focus), dp);
|
2007-01-25 19:33:29 +00:00
|
|
|
shortcut_add(&scs, label, 'g', SHORTCUT_TREE, tree);
|
2003-03-13 19:52:28 +00:00
|
|
|
gtk_widget_show(treescroll);
|
2018-10-29 19:50:29 +00:00
|
|
|
gtk_box_pack_start(GTK_BOX(vbox), treescroll, true, true, 0);
|
2006-12-29 14:35:34 +00:00
|
|
|
panels = gtk_notebook_new();
|
2018-10-29 19:50:29 +00:00
|
|
|
gtk_notebook_set_show_tabs(GTK_NOTEBOOK(panels), false);
|
|
|
|
gtk_notebook_set_show_border(GTK_NOTEBOOK(panels), false);
|
|
|
|
gtk_box_pack_start(GTK_BOX(hbox), panels, true, true, 0);
|
2003-03-13 19:52:28 +00:00
|
|
|
gtk_widget_show(panels);
|
|
|
|
|
|
|
|
panelvbox = NULL;
|
|
|
|
path = NULL;
|
|
|
|
level = 0;
|
Make the configuration dialog non-modal.
Now every call to do_config_box is replaced with a call to
create_config_box, which returns immediately having constructed the
new GTK window object, and is passed a callback function which it will
arrange to be called when the dialog terminates (whether by OK or by
Cancel). That callback is now what triggers the construction of a
session window after 'Open' is pressed in the initial config box, or
the actual mid-session reconfiguration action after 'Apply' is pressed
in a Change Settings box.
We were already prepared to ignore the re-selection of 'Change
Settings' from the context menu of a window that already had a Change
Settings box open (and not accidentally create a second config box for
the same window); but now we do slightly better, by finding the
existing config box and un-minimising and raising it, in case the user
had forgotten it was there.
That's a useful featurelet, but not the main purpose of this change.
The mani point, of course, is that now the multi-window GtkApplication
based front ends now don't do anything confusing to the nesting of
gtk_main() when config boxes are involved. Whether you're changing the
settings of one (or more than one) of your already-running sessions,
preparing to start up a new PuTTY connection, or both at once, we stay
in the same top-level instance of gtk_main() and all sessions' top-
level callbacks continue to run sensibly.
2017-11-26 11:58:02 +00:00
|
|
|
for (index = 0; index < dp->ctrlbox->nctrlsets; index++) {
|
2019-09-08 19:29:00 +00:00
|
|
|
struct controlset *s = dp->ctrlbox->ctrlsets[index];
|
|
|
|
GtkWidget *w;
|
2003-03-13 19:52:28 +00:00
|
|
|
|
2019-09-08 19:29:00 +00:00
|
|
|
if (!*s->pathname) {
|
|
|
|
w = layout_ctrls(dp, NULL, &scs, s, GTK_WINDOW(window));
|
2007-01-25 19:45:50 +00:00
|
|
|
|
2019-09-08 19:29:00 +00:00
|
|
|
our_dialog_set_action_area(GTK_WINDOW(window), w);
|
|
|
|
} else {
|
|
|
|
int j = path ? ctrl_path_compare(s->pathname, path) : 0;
|
|
|
|
if (j != INT_MAX) { /* add to treeview, start new panel */
|
|
|
|
char *c;
|
2007-01-25 19:33:29 +00:00
|
|
|
#if GTK_CHECK_VERSION(2,0,0)
|
2019-09-08 19:29:00 +00:00
|
|
|
GtkTreeIter treeiter;
|
2007-01-25 19:33:29 +00:00
|
|
|
#else
|
2019-09-08 19:29:00 +00:00
|
|
|
GtkWidget *treeitem;
|
2007-01-25 19:33:29 +00:00
|
|
|
#endif
|
2019-09-08 19:29:00 +00:00
|
|
|
bool first;
|
2003-03-13 19:52:28 +00:00
|
|
|
|
2019-09-08 19:29:00 +00:00
|
|
|
/*
|
|
|
|
* We expect never to find an implicit path
|
|
|
|
* component. For example, we expect never to see
|
|
|
|
* A/B/C followed by A/D/E, because that would
|
|
|
|
* _implicitly_ create A/D. All our path prefixes
|
|
|
|
* are expected to contain actual controls and be
|
|
|
|
* selectable in the treeview; so we would expect
|
|
|
|
* to see A/D _explicitly_ before encountering
|
|
|
|
* A/D/E.
|
|
|
|
*/
|
|
|
|
assert(j == ctrl_path_elements(s->pathname) - 1);
|
2003-03-13 19:52:28 +00:00
|
|
|
|
2019-09-08 19:29:00 +00:00
|
|
|
c = strrchr(s->pathname, '/');
|
|
|
|
if (!c)
|
|
|
|
c = s->pathname;
|
|
|
|
else
|
|
|
|
c++;
|
2003-03-13 19:52:28 +00:00
|
|
|
|
2019-09-08 19:29:00 +00:00
|
|
|
path = s->pathname;
|
2007-01-25 19:33:29 +00:00
|
|
|
|
2019-09-08 19:29:00 +00:00
|
|
|
first = (panelvbox == NULL);
|
2007-01-25 19:33:29 +00:00
|
|
|
|
2019-09-08 19:29:00 +00:00
|
|
|
panelvbox = gtk_vbox_new(false, 4);
|
|
|
|
gtk_widget_show(panelvbox);
|
|
|
|
gtk_notebook_append_page(GTK_NOTEBOOK(panels), panelvbox,
|
|
|
|
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
|
|
|
|
|
|
|
struct selparam *sp = snew(struct selparam);
|
|
|
|
|
2019-09-08 19:29:00 +00:00
|
|
|
if (first) {
|
|
|
|
gint page_num;
|
2007-01-25 19:33:29 +00:00
|
|
|
|
2019-09-08 19:29:00 +00:00
|
|
|
page_num = gtk_notebook_page_num(GTK_NOTEBOOK(panels),
|
|
|
|
panelvbox);
|
|
|
|
gtk_notebook_set_current_page(GTK_NOTEBOOK(panels),
|
2015-08-08 17:02:01 +00:00
|
|
|
page_num);
|
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
|
|
|
|
|
|
|
dp->curr_panel = sp;
|
2019-09-08 19:29:00 +00:00
|
|
|
}
|
2007-01-25 19:33:29 +00:00
|
|
|
|
New array-growing macros: sgrowarray and sgrowarrayn.
The idea of these is that they centralise the common idiom along the
lines of
if (logical_array_len >= physical_array_size) {
physical_array_size = logical_array_len * 5 / 4 + 256;
array = sresize(array, physical_array_size, ElementType);
}
which happens at a zillion call sites throughout this code base, with
different random choices of the geometric factor and additive
constant, sometimes forgetting them completely, and generally doing a
lot of repeated work.
The new macro sgrowarray(array,size,n) has the semantics: here are the
array pointer and its physical size for you to modify, now please
ensure that the nth element exists, so I can write into it. And
sgrowarrayn(array,size,n,m) is the same except that it ensures that
the array has size at least n+m (so sgrowarray is just the special
case where m=1).
Now that this is a single centralised implementation that will be used
everywhere, I've also gone to more effort in the implementation, with
careful overflow checks that would have been painful to put at all the
previous call sites.
This commit also switches over every use of sresize(), apart from a
few where I really didn't think it would gain anything. A consequence
of that is that a lot of array-size variables have to have their types
changed to size_t, because the macros require that (they address-take
the size to pass to the underlying function).
2019-02-28 20:07:30 +00:00
|
|
|
sgrowarray(selparams, selparamsize, nselparams);
|
2019-09-08 19:29:00 +00:00
|
|
|
selparams[nselparams] = sp;
|
|
|
|
sp->dp = dp;
|
|
|
|
sp->panels = GTK_NOTEBOOK(panels);
|
|
|
|
sp->panel = panelvbox;
|
|
|
|
sp->shortcuts = scs; /* structure copy */
|
2007-01-25 19:33:29 +00:00
|
|
|
|
2019-09-08 19:29:00 +00:00
|
|
|
assert(j-1 < level);
|
2007-01-25 19:33:29 +00:00
|
|
|
|
|
|
|
#if GTK_CHECK_VERSION(2,0,0)
|
2019-09-08 19:29:00 +00:00
|
|
|
if (j > 0)
|
|
|
|
/* treeiterlevels[j-1] will always be valid because we
|
|
|
|
* don't allow implicit path components; see above.
|
|
|
|
*/
|
|
|
|
gtk_tree_store_append(treestore, &treeiter,
|
|
|
|
&treeiterlevels[j-1]);
|
|
|
|
else
|
|
|
|
gtk_tree_store_append(treestore, &treeiter, NULL);
|
|
|
|
gtk_tree_store_set(treestore, &treeiter,
|
|
|
|
TREESTORE_PATH, c,
|
|
|
|
TREESTORE_PARAMS, nselparams,
|
|
|
|
-1);
|
|
|
|
treeiterlevels[j] = treeiter;
|
|
|
|
|
|
|
|
sp->depth = j;
|
|
|
|
if (j > 0) {
|
|
|
|
sp->treepath = gtk_tree_model_get_path(
|
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
|
|
|
GTK_TREE_MODEL(treestore), &treeiterlevels[j-1]);
|
2019-09-08 19:29:00 +00:00
|
|
|
/*
|
|
|
|
* We are going to collapse all tree branches
|
|
|
|
* at depth greater than 2, but not _yet_; see
|
|
|
|
* the comment at the call to
|
|
|
|
* gtk_tree_view_collapse_row below.
|
|
|
|
*/
|
|
|
|
gtk_tree_view_expand_row(GTK_TREE_VIEW(tree),
|
|
|
|
sp->treepath, false);
|
|
|
|
} else {
|
|
|
|
sp->treepath = NULL;
|
|
|
|
}
|
2007-01-25 19:33:29 +00:00
|
|
|
#else
|
2019-09-08 19:29:00 +00:00
|
|
|
treeitem = gtk_tree_item_new_with_label(c);
|
|
|
|
if (j > 0) {
|
|
|
|
if (!treelevels[j-1]) {
|
|
|
|
treelevels[j-1] = GTK_TREE(gtk_tree_new());
|
Formatting: standardise on "func(\n", not "func\n(".
If the function name (or expression) in a function call or declaration
is itself so long that even the first argument doesn't fit after it on
the same line, or if that would leave so little space that it would be
silly to try to wrap all the run-on lines into a tall thin column,
then I used to do this
ludicrously_long_function_name
(arg1, arg2, arg3);
and now prefer this
ludicrously_long_function_name(
arg1, arg2, arg3);
I picked up the habit from Python, where the latter idiom is required
by Python's syntactic significance of newlines (you can write the
former if you use a backslash-continuation, but pretty much everyone
seems to agree that that's much uglier). But I've found it works well
in C as well: it makes it more obvious that the previous line is
incomplete, it gives you a tiny bit more space to wrap the following
lines into (the old idiom indents the _third_ line one space beyond
the second), and I generally turn out to agree with the knock-on
indentation decisions made by at least Emacs if you do it in the
middle of a complex expression. Plus, of course, using the _same_
idiom between C and Python means less state-switching.
So, while I'm making annoying indentation changes in general, this
seems like a good time to dig out all the cases of the old idiom in
this code, and switch them over to the new.
2022-08-03 19:48:46 +00:00
|
|
|
gtk_tree_item_set_subtree(
|
|
|
|
treeitemlevels[j-1], GTK_WIDGET(treelevels[j-1]));
|
2007-01-16 18:48:47 +00:00
|
|
|
if (j < 2)
|
|
|
|
gtk_tree_item_expand(treeitemlevels[j-1]);
|
|
|
|
else
|
|
|
|
gtk_tree_item_collapse(treeitemlevels[j-1]);
|
2019-09-08 19:29:00 +00:00
|
|
|
}
|
|
|
|
gtk_tree_append(treelevels[j-1], treeitem);
|
|
|
|
} else {
|
|
|
|
gtk_tree_append(GTK_TREE(tree), treeitem);
|
|
|
|
}
|
|
|
|
treeitemlevels[j] = GTK_TREE_ITEM(treeitem);
|
|
|
|
treelevels[j] = NULL;
|
2003-03-13 19:52:28 +00:00
|
|
|
|
2015-08-08 16:29:02 +00:00
|
|
|
g_signal_connect(G_OBJECT(treeitem), "key_press_event",
|
Make the configuration dialog non-modal.
Now every call to do_config_box is replaced with a call to
create_config_box, which returns immediately having constructed the
new GTK window object, and is passed a callback function which it will
arrange to be called when the dialog terminates (whether by OK or by
Cancel). That callback is now what triggers the construction of a
session window after 'Open' is pressed in the initial config box, or
the actual mid-session reconfiguration action after 'Apply' is pressed
in a Change Settings box.
We were already prepared to ignore the re-selection of 'Change
Settings' from the context menu of a window that already had a Change
Settings box open (and not accidentally create a second config box for
the same window); but now we do slightly better, by finding the
existing config box and un-minimising and raising it, in case the user
had forgotten it was there.
That's a useful featurelet, but not the main purpose of this change.
The mani point, of course, is that now the multi-window GtkApplication
based front ends now don't do anything confusing to the nesting of
gtk_main() when config boxes are involved. Whether you're changing the
settings of one (or more than one) of your already-running sessions,
preparing to start up a new PuTTY connection, or both at once, we stay
in the same top-level instance of gtk_main() and all sessions' top-
level callbacks continue to run sensibly.
2017-11-26 11:58:02 +00:00
|
|
|
G_CALLBACK(tree_key_press), dp);
|
2015-08-08 16:29:02 +00:00
|
|
|
g_signal_connect(G_OBJECT(treeitem), "focus_in_event",
|
Make the configuration dialog non-modal.
Now every call to do_config_box is replaced with a call to
create_config_box, which returns immediately having constructed the
new GTK window object, and is passed a callback function which it will
arrange to be called when the dialog terminates (whether by OK or by
Cancel). That callback is now what triggers the construction of a
session window after 'Open' is pressed in the initial config box, or
the actual mid-session reconfiguration action after 'Apply' is pressed
in a Change Settings box.
We were already prepared to ignore the re-selection of 'Change
Settings' from the context menu of a window that already had a Change
Settings box open (and not accidentally create a second config box for
the same window); but now we do slightly better, by finding the
existing config box and un-minimising and raising it, in case the user
had forgotten it was there.
That's a useful featurelet, but not the main purpose of this change.
The mani point, of course, is that now the multi-window GtkApplication
based front ends now don't do anything confusing to the nesting of
gtk_main() when config boxes are involved. Whether you're changing the
settings of one (or more than one) of your already-running sessions,
preparing to start up a new PuTTY connection, or both at once, we stay
in the same top-level instance of gtk_main() and all sessions' top-
level callbacks continue to run sensibly.
2017-11-26 11:58:02 +00:00
|
|
|
G_CALLBACK(widget_focus), dp);
|
2003-03-18 19:06:51 +00:00
|
|
|
|
2019-09-08 19:29:00 +00:00
|
|
|
gtk_widget_show(treeitem);
|
2003-03-13 19:52:28 +00:00
|
|
|
|
2019-09-08 19:29:00 +00:00
|
|
|
if (first)
|
|
|
|
gtk_tree_select_child(GTK_TREE(tree), treeitem);
|
|
|
|
sp->treeitem = treeitem;
|
2007-01-25 19:33:29 +00:00
|
|
|
#endif
|
2003-03-13 19:52:28 +00:00
|
|
|
|
2019-09-08 19:29:00 +00:00
|
|
|
level = j+1;
|
|
|
|
nselparams++;
|
|
|
|
}
|
2003-03-13 19:52:28 +00:00
|
|
|
|
2019-09-08 19:29:00 +00:00
|
|
|
w = layout_ctrls(dp, selparams[nselparams-1],
|
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
|
|
|
&selparams[nselparams-1]->shortcuts, s, NULL);
|
2019-09-08 19:29:00 +00:00
|
|
|
gtk_box_pack_start(GTK_BOX(panelvbox), w, false, false, 0);
|
2003-03-14 18:35:01 +00:00
|
|
|
gtk_widget_show(w);
|
2019-09-08 19:29:00 +00:00
|
|
|
}
|
2003-03-13 19:52:28 +00:00
|
|
|
}
|
|
|
|
|
2008-04-04 11:37:06 +00:00
|
|
|
#if GTK_CHECK_VERSION(2,0,0)
|
2015-08-25 18:44:44 +00:00
|
|
|
/*
|
|
|
|
* We want our tree view to come up with all branches at depth 2
|
|
|
|
* or more collapsed. However, if we start off with those branches
|
|
|
|
* collapsed, then the tree view's size request will be calculated
|
|
|
|
* based on the width of the collapsed tree, and then when the
|
|
|
|
* collapsed branches are expanded later, the tree view will
|
|
|
|
* jarringly change size.
|
|
|
|
*
|
|
|
|
* So instead we start with everything expanded; then, once the
|
|
|
|
* tree view has computed its resulting width requirement, we
|
|
|
|
* collapse the relevant rows, but force the width to be the value
|
|
|
|
* we just retrieved. This arranges that the tree view is wide
|
|
|
|
* enough to have all branches expanded without further resizing.
|
|
|
|
*/
|
2008-04-04 11:37:06 +00:00
|
|
|
|
Make the configuration dialog non-modal.
Now every call to do_config_box is replaced with a call to
create_config_box, which returns immediately having constructed the
new GTK window object, and is passed a callback function which it will
arrange to be called when the dialog terminates (whether by OK or by
Cancel). That callback is now what triggers the construction of a
session window after 'Open' is pressed in the initial config box, or
the actual mid-session reconfiguration action after 'Apply' is pressed
in a Change Settings box.
We were already prepared to ignore the re-selection of 'Change
Settings' from the context menu of a window that already had a Change
Settings box open (and not accidentally create a second config box for
the same window); but now we do slightly better, by finding the
existing config box and un-minimising and raising it, in case the user
had forgotten it was there.
That's a useful featurelet, but not the main purpose of this change.
The mani point, of course, is that now the multi-window GtkApplication
based front ends now don't do anything confusing to the nesting of
gtk_main() when config boxes are involved. Whether you're changing the
settings of one (or more than one) of your already-running sessions,
preparing to start up a new PuTTY connection, or both at once, we stay
in the same top-level instance of gtk_main() and all sessions' top-
level callbacks continue to run sensibly.
2017-11-26 11:58:02 +00:00
|
|
|
dp->nselparams = nselparams;
|
|
|
|
dp->selparams = selparams;
|
2008-04-04 11:37:06 +00:00
|
|
|
|
2015-08-25 18:44:44 +00:00
|
|
|
#if !GTK_CHECK_VERSION(3,0,0)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* In GTK2, we can just do the job right now.
|
|
|
|
*/
|
2019-09-08 19:29:00 +00:00
|
|
|
GtkRequisition req;
|
|
|
|
gtk_widget_size_request(tree, &req);
|
Make the configuration dialog non-modal.
Now every call to do_config_box is replaced with a call to
create_config_box, which returns immediately having constructed the
new GTK window object, and is passed a callback function which it will
arrange to be called when the dialog terminates (whether by OK or by
Cancel). That callback is now what triggers the construction of a
session window after 'Open' is pressed in the initial config box, or
the actual mid-session reconfiguration action after 'Apply' is pressed
in a Change Settings box.
We were already prepared to ignore the re-selection of 'Change
Settings' from the context menu of a window that already had a Change
Settings box open (and not accidentally create a second config box for
the same window); but now we do slightly better, by finding the
existing config box and un-minimising and raising it, in case the user
had forgotten it was there.
That's a useful featurelet, but not the main purpose of this change.
The mani point, of course, is that now the multi-window GtkApplication
based front ends now don't do anything confusing to the nesting of
gtk_main() when config boxes are involved. Whether you're changing the
settings of one (or more than one) of your already-running sessions,
preparing to start up a new PuTTY connection, or both at once, we stay
in the same top-level instance of gtk_main() and all sessions' top-
level callbacks continue to run sensibly.
2017-11-26 11:58:02 +00:00
|
|
|
initial_treeview_collapse(dp, tree);
|
2019-09-08 19:29:00 +00:00
|
|
|
gtk_widget_set_size_request(tree, req.width, -1);
|
2008-04-04 11:37:06 +00:00
|
|
|
}
|
2015-08-25 18:44:44 +00:00
|
|
|
#else
|
|
|
|
/*
|
|
|
|
* But in GTK3, we have to wait until the widget is about to be
|
|
|
|
* mapped, because the size computation won't have been done yet.
|
|
|
|
*/
|
|
|
|
g_signal_connect(G_OBJECT(tree), "map",
|
Make the configuration dialog non-modal.
Now every call to do_config_box is replaced with a call to
create_config_box, which returns immediately having constructed the
new GTK window object, and is passed a callback function which it will
arrange to be called when the dialog terminates (whether by OK or by
Cancel). That callback is now what triggers the construction of a
session window after 'Open' is pressed in the initial config box, or
the actual mid-session reconfiguration action after 'Apply' is pressed
in a Change Settings box.
We were already prepared to ignore the re-selection of 'Change
Settings' from the context menu of a window that already had a Change
Settings box open (and not accidentally create a second config box for
the same window); but now we do slightly better, by finding the
existing config box and un-minimising and raising it, in case the user
had forgotten it was there.
That's a useful featurelet, but not the main purpose of this change.
The mani point, of course, is that now the multi-window GtkApplication
based front ends now don't do anything confusing to the nesting of
gtk_main() when config boxes are involved. Whether you're changing the
settings of one (or more than one) of your already-running sessions,
preparing to start up a new PuTTY connection, or both at once, we stay
in the same top-level instance of gtk_main() and all sessions' top-
level callbacks continue to run sensibly.
2017-11-26 11:58:02 +00:00
|
|
|
G_CALLBACK(treeview_map_event), dp);
|
2015-08-25 18:44:44 +00:00
|
|
|
#endif /* GTK 2 vs 3 */
|
|
|
|
#endif /* GTK 2+ vs 1 */
|
2008-04-04 11:37:06 +00:00
|
|
|
|
2007-01-25 19:33:29 +00:00
|
|
|
#if GTK_CHECK_VERSION(2,0,0)
|
|
|
|
g_signal_connect(G_OBJECT(treeselection), "changed",
|
2019-09-08 19:29:00 +00:00
|
|
|
G_CALLBACK(treeselection_changed), selparams);
|
2007-01-25 19:33:29 +00:00
|
|
|
#else
|
Make the configuration dialog non-modal.
Now every call to do_config_box is replaced with a call to
create_config_box, which returns immediately having constructed the
new GTK window object, and is passed a callback function which it will
arrange to be called when the dialog terminates (whether by OK or by
Cancel). That callback is now what triggers the construction of a
session window after 'Open' is pressed in the initial config box, or
the actual mid-session reconfiguration action after 'Apply' is pressed
in a Change Settings box.
We were already prepared to ignore the re-selection of 'Change
Settings' from the context menu of a window that already had a Change
Settings box open (and not accidentally create a second config box for
the same window); but now we do slightly better, by finding the
existing config box and un-minimising and raising it, in case the user
had forgotten it was there.
That's a useful featurelet, but not the main purpose of this change.
The mani point, of course, is that now the multi-window GtkApplication
based front ends now don't do anything confusing to the nesting of
gtk_main() when config boxes are involved. Whether you're changing the
settings of one (or more than one) of your already-running sessions,
preparing to start up a new PuTTY connection, or both at once, we stay
in the same top-level instance of gtk_main() and all sessions' top-
level callbacks continue to run sensibly.
2017-11-26 11:58:02 +00:00
|
|
|
dp->ntreeitems = nselparams;
|
|
|
|
dp->treeitems = snewn(dp->ntreeitems, GtkWidget *);
|
2003-03-13 19:52:28 +00:00
|
|
|
for (index = 0; index < nselparams; index++) {
|
2019-10-15 19:11:30 +00:00
|
|
|
g_signal_connect(G_OBJECT(selparams[index]->treeitem), "select",
|
2015-08-08 16:29:02 +00:00
|
|
|
G_CALLBACK(treeitem_sel),
|
2019-11-02 08:37:30 +00:00
|
|
|
selparams[index]);
|
2019-10-15 19:11:30 +00:00
|
|
|
dp->treeitems[index] = selparams[index]->treeitem;
|
2003-03-13 19:52:28 +00:00
|
|
|
}
|
2007-01-25 19:33:29 +00:00
|
|
|
#endif
|
2003-03-13 19:52:28 +00:00
|
|
|
|
Make the configuration dialog non-modal.
Now every call to do_config_box is replaced with a call to
create_config_box, which returns immediately having constructed the
new GTK window object, and is passed a callback function which it will
arrange to be called when the dialog terminates (whether by OK or by
Cancel). That callback is now what triggers the construction of a
session window after 'Open' is pressed in the initial config box, or
the actual mid-session reconfiguration action after 'Apply' is pressed
in a Change Settings box.
We were already prepared to ignore the re-selection of 'Change
Settings' from the context menu of a window that already had a Change
Settings box open (and not accidentally create a second config box for
the same window); but now we do slightly better, by finding the
existing config box and un-minimising and raising it, in case the user
had forgotten it was there.
That's a useful featurelet, but not the main purpose of this change.
The mani point, of course, is that now the multi-window GtkApplication
based front ends now don't do anything confusing to the nesting of
gtk_main() when config boxes are involved. Whether you're changing the
settings of one (or more than one) of your already-running sessions,
preparing to start up a new PuTTY connection, or both at once, we stay
in the same top-level instance of gtk_main() and all sessions' top-
level callbacks continue to run sensibly.
2017-11-26 11:58:02 +00:00
|
|
|
dp->data = conf;
|
|
|
|
dlg_refresh(NULL, dp);
|
2003-03-15 15:50:42 +00:00
|
|
|
|
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
|
|
|
dp->shortcuts = &selparams[0]->shortcuts;
|
2007-01-25 19:33:29 +00:00
|
|
|
#if !GTK_CHECK_VERSION(2,0,0)
|
Make the configuration dialog non-modal.
Now every call to do_config_box is replaced with a call to
create_config_box, which returns immediately having constructed the
new GTK window object, and is passed a callback function which it will
arrange to be called when the dialog terminates (whether by OK or by
Cancel). That callback is now what triggers the construction of a
session window after 'Open' is pressed in the initial config box, or
the actual mid-session reconfiguration action after 'Apply' is pressed
in a Change Settings box.
We were already prepared to ignore the re-selection of 'Change
Settings' from the context menu of a window that already had a Change
Settings box open (and not accidentally create a second config box for
the same window); but now we do slightly better, by finding the
existing config box and un-minimising and raising it, in case the user
had forgotten it was there.
That's a useful featurelet, but not the main purpose of this change.
The mani point, of course, is that now the multi-window GtkApplication
based front ends now don't do anything confusing to the nesting of
gtk_main() when config boxes are involved. Whether you're changing the
settings of one (or more than one) of your already-running sessions,
preparing to start up a new PuTTY connection, or both at once, we stay
in the same top-level instance of gtk_main() and all sessions' top-
level callbacks continue to run sensibly.
2017-11-26 11:58:02 +00:00
|
|
|
dp->currtreeitem = dp->treeitems[0];
|
2007-01-25 19:33:29 +00:00
|
|
|
#endif
|
Make the configuration dialog non-modal.
Now every call to do_config_box is replaced with a call to
create_config_box, which returns immediately having constructed the
new GTK window object, and is passed a callback function which it will
arrange to be called when the dialog terminates (whether by OK or by
Cancel). That callback is now what triggers the construction of a
session window after 'Open' is pressed in the initial config box, or
the actual mid-session reconfiguration action after 'Apply' is pressed
in a Change Settings box.
We were already prepared to ignore the re-selection of 'Change
Settings' from the context menu of a window that already had a Change
Settings box open (and not accidentally create a second config box for
the same window); but now we do slightly better, by finding the
existing config box and un-minimising and raising it, in case the user
had forgotten it was there.
That's a useful featurelet, but not the main purpose of this change.
The mani point, of course, is that now the multi-window GtkApplication
based front ends now don't do anything confusing to the nesting of
gtk_main() when config boxes are involved. Whether you're changing the
settings of one (or more than one) of your already-running sessions,
preparing to start up a new PuTTY connection, or both at once, we stay
in the same top-level instance of gtk_main() and all sessions' top-
level callbacks continue to run sensibly.
2017-11-26 11:58:02 +00:00
|
|
|
dp->lastfocus = NULL;
|
|
|
|
dp->retval = -1;
|
|
|
|
dp->window = window;
|
2003-03-16 12:37:48 +00:00
|
|
|
|
2018-11-03 10:06:33 +00:00
|
|
|
set_window_icon(window, cfg_icon, n_cfg_icon);
|
2007-01-06 18:27:00 +00:00
|
|
|
|
2007-01-25 19:33:29 +00:00
|
|
|
#if !GTK_CHECK_VERSION(2,0,0)
|
2007-01-16 18:48:47 +00:00
|
|
|
gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(treescroll),
|
2019-09-08 19:29:00 +00:00
|
|
|
tree);
|
2007-01-25 19:33:29 +00:00
|
|
|
#endif
|
2007-01-16 18:48:47 +00:00
|
|
|
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(treescroll),
|
2019-09-08 19:29:00 +00:00
|
|
|
GTK_POLICY_NEVER,
|
|
|
|
GTK_POLICY_AUTOMATIC);
|
2007-01-16 18:48:47 +00:00
|
|
|
gtk_widget_show(tree);
|
|
|
|
|
2003-03-18 19:47:28 +00:00
|
|
|
gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
|
2003-03-13 19:52:28 +00:00
|
|
|
gtk_widget_show(window);
|
|
|
|
|
2003-03-18 19:06:51 +00:00
|
|
|
/*
|
|
|
|
* Set focus into the first available control.
|
|
|
|
*/
|
Make the configuration dialog non-modal.
Now every call to do_config_box is replaced with a call to
create_config_box, which returns immediately having constructed the
new GTK window object, and is passed a callback function which it will
arrange to be called when the dialog terminates (whether by OK or by
Cancel). That callback is now what triggers the construction of a
session window after 'Open' is pressed in the initial config box, or
the actual mid-session reconfiguration action after 'Apply' is pressed
in a Change Settings box.
We were already prepared to ignore the re-selection of 'Change
Settings' from the context menu of a window that already had a Change
Settings box open (and not accidentally create a second config box for
the same window); but now we do slightly better, by finding the
existing config box and un-minimising and raising it, in case the user
had forgotten it was there.
That's a useful featurelet, but not the main purpose of this change.
The mani point, of course, is that now the multi-window GtkApplication
based front ends now don't do anything confusing to the nesting of
gtk_main() when config boxes are involved. Whether you're changing the
settings of one (or more than one) of your already-running sessions,
preparing to start up a new PuTTY connection, or both at once, we stay
in the same top-level instance of gtk_main() and all sessions' top-
level callbacks continue to run sensibly.
2017-11-26 11:58:02 +00:00
|
|
|
for (index = 0; index < dp->ctrlbox->nctrlsets; index++) {
|
2019-09-08 19:29:00 +00:00
|
|
|
struct controlset *s = dp->ctrlbox->ctrlsets[index];
|
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 done = false;
|
2003-03-18 19:06:51 +00:00
|
|
|
int j;
|
|
|
|
|
2019-09-08 19:29:00 +00:00
|
|
|
if (*s->pathname) {
|
2003-03-18 19:06:51 +00:00
|
|
|
for (j = 0; j < s->ncontrols; j++)
|
Restructure dlgcontrol as a struct with an anon union.
This gets rid of that awkward STANDARD_PREFIX system in which every
branch of the old 'union control' had to repeat all the generic
fields, and then call sites had to make an arbitrary decision about
which branch to access them through.
That was the best we could do before accepting C99 features in this
code base. But now we have anonymous unions, so we don't need to put
up with that nonsense any more!
'dlgcontrol' is now a struct rather than a union, and the generic
fields common to all control types are ordinary members of the struct,
so you don't have to refer to them as ctrl->generic.foo at all, just
ctrl->foo, which saves verbiage at the point of use.
The extra per-control fields are still held in structures named after
the control type, so you'll still say ctrl->listbox.height or
whatever. But now those structures are themselves members of an
anonymous union field following the generic fields, so those
sub-structures don't have to reiterate all the standard stuff too.
While I'm here, I've promoted 'context2' from an editbox-specific
field to a generic one (it just seems silly _not_ to allow any control
to have two context fields if it needs it). Also, I had to rename the
boolean field 'tabdelay' to avoid it clashing with the subsidiary
structure field 'tabdelay', now that the former isn't generic.tabdelay
any more.
2022-05-01 08:55:52 +00:00
|
|
|
if (s->ctrls[j]->type != CTRL_TABDELAY &&
|
|
|
|
s->ctrls[j]->type != CTRL_COLUMNS &&
|
|
|
|
s->ctrls[j]->type != CTRL_TEXT) {
|
Make the configuration dialog non-modal.
Now every call to do_config_box is replaced with a call to
create_config_box, which returns immediately having constructed the
new GTK window object, and is passed a callback function which it will
arrange to be called when the dialog terminates (whether by OK or by
Cancel). That callback is now what triggers the construction of a
session window after 'Open' is pressed in the initial config box, or
the actual mid-session reconfiguration action after 'Apply' is pressed
in a Change Settings box.
We were already prepared to ignore the re-selection of 'Change
Settings' from the context menu of a window that already had a Change
Settings box open (and not accidentally create a second config box for
the same window); but now we do slightly better, by finding the
existing config box and un-minimising and raising it, in case the user
had forgotten it was there.
That's a useful featurelet, but not the main purpose of this change.
The mani point, of course, is that now the multi-window GtkApplication
based front ends now don't do anything confusing to the nesting of
gtk_main() when config boxes are involved. Whether you're changing the
settings of one (or more than one) of your already-running sessions,
preparing to start up a new PuTTY connection, or both at once, we stay
in the same top-level instance of gtk_main() and all sessions' top-
level callbacks continue to run sensibly.
2017-11-26 11:58:02 +00:00
|
|
|
dlg_set_focus(s->ctrls[j], dp);
|
|
|
|
dp->lastfocus = s->ctrls[j];
|
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
|
|
|
done = true;
|
2003-03-18 19:06:51 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (done)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2015-08-08 16:29:02 +00:00
|
|
|
g_signal_connect(G_OBJECT(window), "destroy",
|
Make the configuration dialog non-modal.
Now every call to do_config_box is replaced with a call to
create_config_box, which returns immediately having constructed the
new GTK window object, and is passed a callback function which it will
arrange to be called when the dialog terminates (whether by OK or by
Cancel). That callback is now what triggers the construction of a
session window after 'Open' is pressed in the initial config box, or
the actual mid-session reconfiguration action after 'Apply' is pressed
in a Change Settings box.
We were already prepared to ignore the re-selection of 'Change
Settings' from the context menu of a window that already had a Change
Settings box open (and not accidentally create a second config box for
the same window); but now we do slightly better, by finding the
existing config box and un-minimising and raising it, in case the user
had forgotten it was there.
That's a useful featurelet, but not the main purpose of this change.
The mani point, of course, is that now the multi-window GtkApplication
based front ends now don't do anything confusing to the nesting of
gtk_main() when config boxes are involved. Whether you're changing the
settings of one (or more than one) of your already-running sessions,
preparing to start up a new PuTTY connection, or both at once, we stay
in the same top-level instance of gtk_main() and all sessions' top-
level callbacks continue to run sensibly.
2017-11-26 11:58:02 +00:00
|
|
|
G_CALLBACK(dlgparam_destroy), dp);
|
2015-08-08 16:29:02 +00:00
|
|
|
g_signal_connect(G_OBJECT(window), "key_press_event",
|
Make the configuration dialog non-modal.
Now every call to do_config_box is replaced with a call to
create_config_box, which returns immediately having constructed the
new GTK window object, and is passed a callback function which it will
arrange to be called when the dialog terminates (whether by OK or by
Cancel). That callback is now what triggers the construction of a
session window after 'Open' is pressed in the initial config box, or
the actual mid-session reconfiguration action after 'Apply' is pressed
in a Change Settings box.
We were already prepared to ignore the re-selection of 'Change
Settings' from the context menu of a window that already had a Change
Settings box open (and not accidentally create a second config box for
the same window); but now we do slightly better, by finding the
existing config box and un-minimising and raising it, in case the user
had forgotten it was there.
That's a useful featurelet, but not the main purpose of this change.
The mani point, of course, is that now the multi-window GtkApplication
based front ends now don't do anything confusing to the nesting of
gtk_main() when config boxes are involved. Whether you're changing the
settings of one (or more than one) of your already-running sessions,
preparing to start up a new PuTTY connection, or both at once, we stay
in the same top-level instance of gtk_main() and all sessions' top-
level callbacks continue to run sensibly.
2017-11-26 11:58:02 +00:00
|
|
|
G_CALLBACK(win_key_press), dp);
|
2003-03-13 19:52:28 +00:00
|
|
|
|
Make the configuration dialog non-modal.
Now every call to do_config_box is replaced with a call to
create_config_box, which returns immediately having constructed the
new GTK window object, and is passed a callback function which it will
arrange to be called when the dialog terminates (whether by OK or by
Cancel). That callback is now what triggers the construction of a
session window after 'Open' is pressed in the initial config box, or
the actual mid-session reconfiguration action after 'Apply' is pressed
in a Change Settings box.
We were already prepared to ignore the re-selection of 'Change
Settings' from the context menu of a window that already had a Change
Settings box open (and not accidentally create a second config box for
the same window); but now we do slightly better, by finding the
existing config box and un-minimising and raising it, in case the user
had forgotten it was there.
That's a useful featurelet, but not the main purpose of this change.
The mani point, of course, is that now the multi-window GtkApplication
based front ends now don't do anything confusing to the nesting of
gtk_main() when config boxes are involved. Whether you're changing the
settings of one (or more than one) of your already-running sessions,
preparing to start up a new PuTTY connection, or both at once, we stay
in the same top-level instance of gtk_main() and all sessions' top-
level callbacks continue to run sensibly.
2017-11-26 11:58:02 +00:00
|
|
|
return window;
|
|
|
|
}
|
2003-03-18 19:06:51 +00:00
|
|
|
|
Make the configuration dialog non-modal.
Now every call to do_config_box is replaced with a call to
create_config_box, which returns immediately having constructed the
new GTK window object, and is passed a callback function which it will
arrange to be called when the dialog terminates (whether by OK or by
Cancel). That callback is now what triggers the construction of a
session window after 'Open' is pressed in the initial config box, or
the actual mid-session reconfiguration action after 'Apply' is pressed
in a Change Settings box.
We were already prepared to ignore the re-selection of 'Change
Settings' from the context menu of a window that already had a Change
Settings box open (and not accidentally create a second config box for
the same window); but now we do slightly better, by finding the
existing config box and un-minimising and raising it, in case the user
had forgotten it was there.
That's a useful featurelet, but not the main purpose of this change.
The mani point, of course, is that now the multi-window GtkApplication
based front ends now don't do anything confusing to the nesting of
gtk_main() when config boxes are involved. Whether you're changing the
settings of one (or more than one) of your already-running sessions,
preparing to start up a new PuTTY connection, or both at once, we stay
in the same top-level instance of gtk_main() and all sessions' top-
level callbacks continue to run sensibly.
2017-11-26 11:58:02 +00:00
|
|
|
static void dlgparam_destroy(GtkWidget *widget, gpointer data)
|
|
|
|
{
|
|
|
|
struct dlgparam *dp = (struct dlgparam *)data;
|
2017-11-26 14:37:38 +00:00
|
|
|
dp->after(dp->afterctx, dp->retval);
|
Make the configuration dialog non-modal.
Now every call to do_config_box is replaced with a call to
create_config_box, which returns immediately having constructed the
new GTK window object, and is passed a callback function which it will
arrange to be called when the dialog terminates (whether by OK or by
Cancel). That callback is now what triggers the construction of a
session window after 'Open' is pressed in the initial config box, or
the actual mid-session reconfiguration action after 'Apply' is pressed
in a Change Settings box.
We were already prepared to ignore the re-selection of 'Change
Settings' from the context menu of a window that already had a Change
Settings box open (and not accidentally create a second config box for
the same window); but now we do slightly better, by finding the
existing config box and un-minimising and raising it, in case the user
had forgotten it was there.
That's a useful featurelet, but not the main purpose of this change.
The mani point, of course, is that now the multi-window GtkApplication
based front ends now don't do anything confusing to the nesting of
gtk_main() when config boxes are involved. Whether you're changing the
settings of one (or more than one) of your already-running sessions,
preparing to start up a new PuTTY connection, or both at once, we stay
in the same top-level instance of gtk_main() and all sessions' top-
level callbacks continue to run sensibly.
2017-11-26 11:58:02 +00:00
|
|
|
dlg_cleanup(dp);
|
|
|
|
ctrl_free_box(dp->ctrlbox);
|
|
|
|
#if GTK_CHECK_VERSION(2,0,0)
|
2017-11-26 14:29:31 +00:00
|
|
|
if (dp->selparams) {
|
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
|
|
|
for (size_t i = 0; i < dp->nselparams; i++) {
|
|
|
|
if (dp->selparams[i]->treepath)
|
|
|
|
gtk_tree_path_free(dp->selparams[i]->treepath);
|
|
|
|
sfree(dp->selparams[i]);
|
|
|
|
}
|
2017-11-26 14:29:31 +00:00
|
|
|
sfree(dp->selparams);
|
Make the configuration dialog non-modal.
Now every call to do_config_box is replaced with a call to
create_config_box, which returns immediately having constructed the
new GTK window object, and is passed a callback function which it will
arrange to be called when the dialog terminates (whether by OK or by
Cancel). That callback is now what triggers the construction of a
session window after 'Open' is pressed in the initial config box, or
the actual mid-session reconfiguration action after 'Apply' is pressed
in a Change Settings box.
We were already prepared to ignore the re-selection of 'Change
Settings' from the context menu of a window that already had a Change
Settings box open (and not accidentally create a second config box for
the same window); but now we do slightly better, by finding the
existing config box and un-minimising and raising it, in case the user
had forgotten it was there.
That's a useful featurelet, but not the main purpose of this change.
The mani point, of course, is that now the multi-window GtkApplication
based front ends now don't do anything confusing to the nesting of
gtk_main() when config boxes are involved. Whether you're changing the
settings of one (or more than one) of your already-running sessions,
preparing to start up a new PuTTY connection, or both at once, we stay
in the same top-level instance of gtk_main() and all sessions' top-
level callbacks continue to run sensibly.
2017-11-26 11:58:02 +00:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
sfree(dp);
|
2003-03-13 19:52:28 +00:00
|
|
|
}
|
|
|
|
|
2022-05-01 08:48:38 +00:00
|
|
|
static void messagebox_handler(dlgcontrol *ctrl, dlgparam *dp,
|
2019-09-08 19:29:00 +00:00
|
|
|
void *data, int event)
|
2003-03-31 11:21:07 +00:00
|
|
|
{
|
|
|
|
if (event == EVENT_ACTION)
|
Restructure dlgcontrol as a struct with an anon union.
This gets rid of that awkward STANDARD_PREFIX system in which every
branch of the old 'union control' had to repeat all the generic
fields, and then call sites had to make an arbitrary decision about
which branch to access them through.
That was the best we could do before accepting C99 features in this
code base. But now we have anonymous unions, so we don't need to put
up with that nonsense any more!
'dlgcontrol' is now a struct rather than a union, and the generic
fields common to all control types are ordinary members of the struct,
so you don't have to refer to them as ctrl->generic.foo at all, just
ctrl->foo, which saves verbiage at the point of use.
The extra per-control fields are still held in structures named after
the control type, so you'll still say ctrl->listbox.height or
whatever. But now those structures are themselves members of an
anonymous union field following the generic fields, so those
sub-structures don't have to reiterate all the standard stuff too.
While I'm here, I've promoted 'context2' from an editbox-specific
field to a generic one (it just seems silly _not_ to allow any control
to have two context fields if it needs it). Also, I had to rename the
boolean field 'tabdelay' to avoid it clashing with the subsidiary
structure field 'tabdelay', now that the former isn't generic.tabdelay
any more.
2022-05-01 08:55:52 +00:00
|
|
|
dlg_end(dp, ctrl->context.i);
|
2003-03-31 11:21:07 +00:00
|
|
|
}
|
2017-11-26 14:05:02 +00:00
|
|
|
|
2020-01-29 06:22:01 +00:00
|
|
|
static const struct message_box_button button_array_yn[] = {
|
2017-11-26 14:05:02 +00:00
|
|
|
{"Yes", 'y', +1, 1},
|
|
|
|
{"No", 'n', -1, 0},
|
|
|
|
};
|
|
|
|
const struct message_box_buttons buttons_yn = {
|
|
|
|
button_array_yn, lenof(button_array_yn),
|
|
|
|
};
|
2020-01-29 06:22:01 +00:00
|
|
|
static const struct message_box_button button_array_ok[] = {
|
2017-11-26 14:05:02 +00:00
|
|
|
{"OK", 'o', 1, 1},
|
|
|
|
};
|
|
|
|
const struct message_box_buttons buttons_ok = {
|
|
|
|
button_array_ok, lenof(button_array_ok),
|
|
|
|
};
|
|
|
|
|
2021-03-13 11:05:39 +00:00
|
|
|
static GtkWidget *create_message_box_general(
|
2017-11-26 14:05:02 +00:00
|
|
|
GtkWidget *parentwin, const char *title, const char *msg, int minwid,
|
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 selectable, const struct message_box_buttons *buttons,
|
2021-03-13 11:05:39 +00:00
|
|
|
post_dialog_fn_t after, void *afterctx,
|
|
|
|
GtkWidget *(*action_postproc)(GtkWidget *, void *), void *postproc_ctx)
|
2003-03-31 11:21:07 +00:00
|
|
|
{
|
|
|
|
GtkWidget *window, *w0, *w1;
|
|
|
|
struct controlset *s0, *s1;
|
2022-05-01 08:48:38 +00:00
|
|
|
dlgcontrol *c, *textctrl;
|
2017-11-26 14:29:31 +00:00
|
|
|
struct dlgparam *dp;
|
2003-03-31 11:21:07 +00:00
|
|
|
struct Shortcuts scs;
|
2017-11-26 14:05:02 +00:00
|
|
|
int i, index, ncols, min_type;
|
2003-03-13 19:52:28 +00:00
|
|
|
|
2017-11-26 14:29:31 +00:00
|
|
|
dp = snew(struct dlgparam);
|
|
|
|
dp->after = after;
|
|
|
|
dp->afterctx = afterctx;
|
|
|
|
|
|
|
|
dlg_init(dp);
|
2003-03-13 19:52:28 +00:00
|
|
|
|
2003-03-31 11:21:07 +00:00
|
|
|
for (index = 0; index < lenof(scs.sc); index++) {
|
2019-09-08 19:29:00 +00:00
|
|
|
scs.sc[index].action = SHORTCUT_EMPTY;
|
2003-03-31 11:21:07 +00:00
|
|
|
}
|
2003-03-13 19:52:28 +00:00
|
|
|
|
2017-11-26 14:29:31 +00:00
|
|
|
dp->ctrlbox = ctrl_new_box();
|
2003-03-22 17:00:06 +00:00
|
|
|
|
2015-09-26 12:57:12 +00:00
|
|
|
/*
|
2017-11-26 14:05:02 +00:00
|
|
|
* Count up the number of buttons and find out what kinds there
|
|
|
|
* are.
|
2015-09-26 12:57:12 +00:00
|
|
|
*/
|
2003-03-31 11:21:07 +00:00
|
|
|
ncols = 0;
|
2015-09-26 12:57:12 +00:00
|
|
|
min_type = +1;
|
2017-11-26 14:05:02 +00:00
|
|
|
for (i = 0; i < buttons->nbuttons; i++) {
|
|
|
|
const struct message_box_button *button = &buttons->buttons[i];
|
2019-09-08 19:29:00 +00:00
|
|
|
ncols++;
|
2017-11-26 14:05:02 +00:00
|
|
|
if (min_type > button->type)
|
|
|
|
min_type = button->type;
|
2017-11-26 14:29:31 +00:00
|
|
|
assert(button->value >= 0); /* <0 means no return value available */
|
2003-03-31 11:21:07 +00:00
|
|
|
}
|
2003-03-13 19:52:28 +00:00
|
|
|
|
2017-11-26 14:29:31 +00:00
|
|
|
s0 = ctrl_getset(dp->ctrlbox, "", "", "");
|
2003-03-31 11:21:07 +00:00
|
|
|
c = ctrl_columns(s0, 2, 50, 50);
|
|
|
|
c->columns.ncols = s0->ncolumns = ncols;
|
|
|
|
c->columns.percentages = sresize(c->columns.percentages, ncols, int);
|
|
|
|
for (index = 0; index < ncols; index++)
|
2019-09-08 19:29:00 +00:00
|
|
|
c->columns.percentages[index] = (index+1)*100/ncols - index*100/ncols;
|
2003-03-31 11:21:07 +00:00
|
|
|
index = 0;
|
2017-11-26 14:05:02 +00:00
|
|
|
for (i = 0; i < buttons->nbuttons; i++) {
|
|
|
|
const struct message_box_button *button = &buttons->buttons[i];
|
2019-09-08 19:29:00 +00:00
|
|
|
c = ctrl_pushbutton(s0, button->title, button->shortcut,
|
2017-11-26 14:05:02 +00:00
|
|
|
HELPCTX(no_help), messagebox_handler,
|
|
|
|
I(button->value));
|
Restructure dlgcontrol as a struct with an anon union.
This gets rid of that awkward STANDARD_PREFIX system in which every
branch of the old 'union control' had to repeat all the generic
fields, and then call sites had to make an arbitrary decision about
which branch to access them through.
That was the best we could do before accepting C99 features in this
code base. But now we have anonymous unions, so we don't need to put
up with that nonsense any more!
'dlgcontrol' is now a struct rather than a union, and the generic
fields common to all control types are ordinary members of the struct,
so you don't have to refer to them as ctrl->generic.foo at all, just
ctrl->foo, which saves verbiage at the point of use.
The extra per-control fields are still held in structures named after
the control type, so you'll still say ctrl->listbox.height or
whatever. But now those structures are themselves members of an
anonymous union field following the generic fields, so those
sub-structures don't have to reiterate all the standard stuff too.
While I'm here, I've promoted 'context2' from an editbox-specific
field to a generic one (it just seems silly _not_ to allow any control
to have two context fields if it needs it). Also, I had to rename the
boolean field 'tabdelay' to avoid it clashing with the subsidiary
structure field 'tabdelay', now that the former isn't generic.tabdelay
any more.
2022-05-01 08:55:52 +00:00
|
|
|
c->column = index++;
|
2019-09-08 19:29:00 +00:00
|
|
|
if (button->type > 0)
|
|
|
|
c->button.isdefault = true;
|
2015-09-26 12:57:12 +00:00
|
|
|
|
|
|
|
/* We always arrange that _some_ button is labelled as
|
|
|
|
* 'iscancel', so that pressing Escape will always cause
|
|
|
|
* win_key_press to do something. The button we choose is
|
|
|
|
* whichever has the smallest type value: this means that real
|
|
|
|
* cancel buttons (labelled -1) will be picked if one is
|
|
|
|
* there, or in cases where the options are yes/no (1,0) then
|
|
|
|
* no will be picked, and if there's only one option (a box
|
|
|
|
* that really is just showing a _message_ and not even asking
|
|
|
|
* a question) then that will be picked. */
|
2019-09-08 19:29:00 +00:00
|
|
|
if (button->type == min_type)
|
|
|
|
c->button.iscancel = true;
|
2003-03-31 11:21:07 +00:00
|
|
|
}
|
2003-03-13 19:52:28 +00:00
|
|
|
|
2017-11-26 14:29:31 +00:00
|
|
|
s1 = ctrl_getset(dp->ctrlbox, "x", "", "");
|
2015-12-22 12:32:48 +00:00
|
|
|
textctrl = ctrl_text(s1, msg, HELPCTX(no_help));
|
2003-03-13 19:52:28 +00:00
|
|
|
|
2015-08-31 14:45:18 +00:00
|
|
|
window = our_dialog_new();
|
2003-03-31 11:21:07 +00:00
|
|
|
gtk_window_set_title(GTK_WINDOW(window), title);
|
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
|
|
|
w0 = layout_ctrls(dp, NULL, &scs, s0, GTK_WINDOW(window));
|
2021-03-13 11:05:39 +00:00
|
|
|
if (action_postproc)
|
|
|
|
w0 = action_postproc(w0, postproc_ctx);
|
2015-08-31 14:45:18 +00:00
|
|
|
our_dialog_set_action_area(GTK_WINDOW(window), w0);
|
2003-03-31 11:21:07 +00:00
|
|
|
gtk_widget_show(w0);
|
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
|
|
|
w1 = layout_ctrls(dp, NULL, &scs, s1, GTK_WINDOW(window));
|
2003-03-31 11:21:07 +00:00
|
|
|
gtk_container_set_border_width(GTK_CONTAINER(w1), 10);
|
2015-08-08 17:02:01 +00:00
|
|
|
gtk_widget_set_size_request(w1, minwid+20, -1);
|
2018-10-29 19:50:29 +00:00
|
|
|
our_dialog_add_to_content_area(GTK_WINDOW(window), w1, true, true, 0);
|
2003-03-31 11:21:07 +00:00
|
|
|
gtk_widget_show(w1);
|
2003-03-13 19:52:28 +00:00
|
|
|
|
2017-11-26 14:29:31 +00:00
|
|
|
dp->shortcuts = &scs;
|
|
|
|
dp->lastfocus = NULL;
|
|
|
|
dp->retval = 0;
|
|
|
|
dp->window = window;
|
2003-03-13 19:52:28 +00:00
|
|
|
|
2003-03-31 11:21:07 +00:00
|
|
|
if (parentwin) {
|
2003-04-10 08:53:43 +00:00
|
|
|
set_transient_window_pos(parentwin, window);
|
2019-09-08 19:29:00 +00:00
|
|
|
gtk_window_set_transient_for(GTK_WINDOW(window),
|
|
|
|
GTK_WINDOW(parentwin));
|
2003-03-31 11:21:07 +00:00
|
|
|
} else
|
2019-09-08 19:29:00 +00:00
|
|
|
gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
|
2015-12-22 12:32:48 +00:00
|
|
|
gtk_container_set_focus_child(GTK_CONTAINER(window), NULL);
|
2003-03-31 11:21:07 +00:00
|
|
|
gtk_widget_show(window);
|
2015-12-22 12:32:48 +00:00
|
|
|
gtk_window_set_focus(GTK_WINDOW(window), NULL);
|
2003-03-13 19:52:28 +00:00
|
|
|
|
2022-11-27 11:14:23 +00:00
|
|
|
#if GTK_CHECK_VERSION(2,0,0)
|
|
|
|
if (selectable) {
|
|
|
|
/*
|
|
|
|
* GTK selectable labels have a habit of selecting their
|
|
|
|
* entire contents when they gain focus. As far as I can see,
|
|
|
|
* an individual GtkLabel has no way to turn this off - source
|
|
|
|
* diving suggests that the only configurable option for it is
|
|
|
|
* "gtk-label-select-on-focus" in the cross-application
|
|
|
|
* GtkSettings, and there's no per-label or even
|
|
|
|
* per-application override.
|
|
|
|
*
|
|
|
|
* It's ugly to have text in a message box start up all
|
|
|
|
* selected, and also it interferes with any PRIMARY selection
|
|
|
|
* you might already have had. So for this purpose we'd prefer
|
|
|
|
* that the text doesn't _start off_ selected, but it should
|
|
|
|
* be selectable later.
|
|
|
|
*
|
|
|
|
* So we make the label selectable _now_, after the widget is
|
|
|
|
* shown and the focus has already gone wherever it's going.
|
|
|
|
*/
|
|
|
|
struct uctrl *uc = dlg_find_byctrl(dp, textctrl);
|
|
|
|
gtk_label_select_region(GTK_LABEL(uc->text), 0, 0);
|
|
|
|
gtk_label_set_selectable(GTK_LABEL(uc->text), true);
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
(void)textctrl; /* placate warning */
|
|
|
|
#endif
|
|
|
|
|
2018-03-03 18:18:54 +00:00
|
|
|
#if !GTK_CHECK_VERSION(2,0,0)
|
|
|
|
dp->currtreeitem = NULL;
|
|
|
|
dp->treeitems = NULL;
|
|
|
|
#else
|
2017-11-26 14:29:31 +00:00
|
|
|
dp->selparams = NULL;
|
2018-03-03 18:18:54 +00:00
|
|
|
#endif
|
2017-11-26 14:29:31 +00:00
|
|
|
|
2015-08-08 16:29:02 +00:00
|
|
|
g_signal_connect(G_OBJECT(window), "destroy",
|
2017-11-26 14:29:31 +00:00
|
|
|
G_CALLBACK(dlgparam_destroy), dp);
|
2015-08-08 16:29:02 +00:00
|
|
|
g_signal_connect(G_OBJECT(window), "key_press_event",
|
2017-11-26 14:29:31 +00:00
|
|
|
G_CALLBACK(win_key_press), dp);
|
|
|
|
|
|
|
|
return window;
|
|
|
|
}
|
|
|
|
|
2021-03-13 11:05:39 +00:00
|
|
|
GtkWidget *create_message_box(
|
|
|
|
GtkWidget *parentwin, const char *title, const char *msg, int minwid,
|
|
|
|
bool selectable, const struct message_box_buttons *buttons,
|
|
|
|
post_dialog_fn_t after, void *afterctx)
|
|
|
|
{
|
|
|
|
return create_message_box_general(
|
|
|
|
parentwin, title, msg, minwid, selectable, buttons, after, afterctx,
|
|
|
|
NULL /* action_postproc */, NULL /* postproc_ctx */);
|
|
|
|
}
|
|
|
|
|
Reorganise host key checking and confirmation.
Previously, checking the host key against the persistent cache managed
by the storage.h API was done as part of the seat_verify_ssh_host_key
method, i.e. separately by each Seat.
Now that check is done by verify_ssh_host_key(), which is a new
function in ssh/common.c that centralises all the parts of host key
checking that don't need an interactive prompt. It subsumes the
previous verify_ssh_manual_host_key() that checked against the Conf,
and it does the check against the storage API that each Seat was
previously doing separately. If it can't confirm or definitively
reject the host key by itself, _then_ it calls out to the Seat, once
an interactive prompt is definitely needed.
The main point of doing this is so that when SshProxy forwards a Seat
call from the proxy SSH connection to the primary Seat, it won't print
an announcement of which connection is involved unless it's actually
going to do something interactive. (Not that we're printing those
announcements _yet_ anyway, but this is a piece of groundwork that
works towards doing so.)
But while I'm at it, I've also taken the opportunity to clean things
up a bit by renaming functions sensibly. Previously we had three very
similarly named functions verify_ssh_manual_host_key(), SeatVtable's
'verify_ssh_host_key' method, and verify_host_key() in storage.h. Now
the Seat method is called 'confirm' rather than 'verify' (since its
job is now always to print an interactive prompt, so it looks more
like the other confirm_foo methods), and the storage.h function is
called check_stored_host_key(), which goes better with store_host_key
and avoids having too many functions with similar names. And the
'manual' function is subsumed into the new centralised code, so
there's now just *one* host key function with 'verify' in the name.
Several functions are reindented in this commit. Best viewed with
whitespace changes ignored.
2021-10-25 17:12:17 +00:00
|
|
|
struct confirm_ssh_host_key_dialog_ctx {
|
2017-11-26 14:29:42 +00:00
|
|
|
char *host;
|
|
|
|
int port;
|
|
|
|
char *keytype;
|
|
|
|
char *keystr;
|
2021-03-13 11:06:32 +00:00
|
|
|
char *more_info;
|
Richer data type for interactive prompt results.
All the seat functions that request an interactive prompt of some kind
to the user - both the main seat_get_userpass_input and the various
confirmation dialogs for things like host keys - were using a simple
int return value, with the general semantics of 0 = "fail", 1 =
"proceed" (and in the case of seat_get_userpass_input, answers to the
prompts were provided), and -1 = "request in progress, wait for a
callback".
In this commit I change all those functions' return types to a new
struct called SeatPromptResult, whose primary field is an enum
replacing those simple integer values.
The main purpose is that the enum has not three but _four_ values: the
"fail" result has been split into 'user abort' and 'software abort'.
The distinction is that a user abort occurs as a result of an
interactive UI action, such as the user clicking 'cancel' in a dialog
box or hitting ^D or ^C at a terminal password prompt - and therefore,
there's no need to display an error message telling the user that the
interactive operation has failed, because the user already knows,
because they _did_ it. 'Software abort' is from any other cause, where
PuTTY is the first to know there was a problem, and has to tell the
user.
We already had this 'user abort' vs 'software abort' distinction in
other parts of the code - the SSH backend has separate termination
functions which protocol layers can call. But we assumed that any
failure from an interactive prompt request fell into the 'user abort'
category, which is not true. A couple of examples: if you configure a
host key fingerprint in your saved session via the SSH > Host keys
pane, and the server presents a host key that doesn't match it, then
verify_ssh_host_key would report that the user had aborted the
connection, and feel no need to tell the user what had gone wrong!
Similarly, if a password provided on the command line was not
accepted, then (after I fixed the semantics of that in the previous
commit) the same wrong handling would occur.
So now, those Seat prompt functions too can communicate whether the
user or the software originated a connection abort. And in the latter
case, we also provide an error message to present to the user. Result:
in those two example cases (and others), error messages should no
longer go missing.
Implementation note: to avoid the hassle of having the error message
in a SeatPromptResult being a dynamically allocated string (and hence,
every recipient of one must always check whether it's non-NULL and
free it on every exit path, plus being careful about copying the
struct around), I've instead arranged that the structure contains a
function pointer and a couple of parameters, so that the string form
of the message can be constructed on demand. That way, the only users
who need to free it are the ones who actually _asked_ for it in the
first place, which is a much smaller set.
(This is one of the rare occasions that I regret not having C++'s
extra features available in this code base - a unique_ptr or
shared_ptr to a string would have been just the thing here, and the
compiler would have done all the hard work for me of remembering where
to insert the frees!)
2021-12-28 17:52:00 +00:00
|
|
|
void (*callback)(void *callback_ctx, SeatPromptResult result);
|
2017-11-26 14:29:42 +00:00
|
|
|
void *callback_ctx;
|
New abstraction 'Seat', to pass to backends.
This is a new vtable-based abstraction which is passed to a backend in
place of Frontend, and it implements only the subset of the Frontend
functions needed by a backend. (Many other Frontend functions still
exist, notably the wide range of things called by terminal.c providing
platform-independent operations on the GUI terminal window.)
The purpose of making it a vtable is that this opens up the
possibility of creating a backend as an internal implementation detail
of some other activity, by providing just that one backend with a
custom Seat that implements the methods differently.
For example, this refactoring should make it feasible to directly
implement an SSH proxy type, aka the 'jump host' feature supported by
OpenSSH, aka 'open a secondary SSH session in MAINCHAN_DIRECT_TCP
mode, and then expose the main channel of that as the Socket for the
primary connection'. (Which of course you can already do by spawning
'plink -nc' as a separate proxy process, but this would permit it in
the _same_ process without anything getting confused.)
I've centralised a full set of stub methods in misc.c for the new
abstraction, which allows me to get rid of several annoying stubs in
the previous code. Also, while I'm here, I've moved a lot of
duplicated modalfatalbox() type functions from application main
program files into wincons.c / uxcons.c, which I think saves
duplication overall. (A minor visible effect is that the prefixes on
those console-based fatal error messages will now be more consistent
between applications.)
2018-10-11 18:58:42 +00:00
|
|
|
Seat *seat;
|
2021-03-13 11:06:32 +00:00
|
|
|
|
|
|
|
GtkWidget *main_dialog;
|
|
|
|
GtkWidget *more_info_dialog;
|
2017-11-26 14:29:42 +00:00
|
|
|
};
|
|
|
|
|
Reorganise host key checking and confirmation.
Previously, checking the host key against the persistent cache managed
by the storage.h API was done as part of the seat_verify_ssh_host_key
method, i.e. separately by each Seat.
Now that check is done by verify_ssh_host_key(), which is a new
function in ssh/common.c that centralises all the parts of host key
checking that don't need an interactive prompt. It subsumes the
previous verify_ssh_manual_host_key() that checked against the Conf,
and it does the check against the storage API that each Seat was
previously doing separately. If it can't confirm or definitively
reject the host key by itself, _then_ it calls out to the Seat, once
an interactive prompt is definitely needed.
The main point of doing this is so that when SshProxy forwards a Seat
call from the proxy SSH connection to the primary Seat, it won't print
an announcement of which connection is involved unless it's actually
going to do something interactive. (Not that we're printing those
announcements _yet_ anyway, but this is a piece of groundwork that
works towards doing so.)
But while I'm at it, I've also taken the opportunity to clean things
up a bit by renaming functions sensibly. Previously we had three very
similarly named functions verify_ssh_manual_host_key(), SeatVtable's
'verify_ssh_host_key' method, and verify_host_key() in storage.h. Now
the Seat method is called 'confirm' rather than 'verify' (since its
job is now always to print an interactive prompt, so it looks more
like the other confirm_foo methods), and the storage.h function is
called check_stored_host_key(), which goes better with store_host_key
and avoids having too many functions with similar names. And the
'manual' function is subsumed into the new centralised code, so
there's now just *one* host key function with 'verify' in the name.
Several functions are reindented in this commit. Best viewed with
whitespace changes ignored.
2021-10-25 17:12:17 +00:00
|
|
|
static void confirm_ssh_host_key_result_callback(void *vctx, int result)
|
2017-11-26 14:29:42 +00:00
|
|
|
{
|
Reorganise host key checking and confirmation.
Previously, checking the host key against the persistent cache managed
by the storage.h API was done as part of the seat_verify_ssh_host_key
method, i.e. separately by each Seat.
Now that check is done by verify_ssh_host_key(), which is a new
function in ssh/common.c that centralises all the parts of host key
checking that don't need an interactive prompt. It subsumes the
previous verify_ssh_manual_host_key() that checked against the Conf,
and it does the check against the storage API that each Seat was
previously doing separately. If it can't confirm or definitively
reject the host key by itself, _then_ it calls out to the Seat, once
an interactive prompt is definitely needed.
The main point of doing this is so that when SshProxy forwards a Seat
call from the proxy SSH connection to the primary Seat, it won't print
an announcement of which connection is involved unless it's actually
going to do something interactive. (Not that we're printing those
announcements _yet_ anyway, but this is a piece of groundwork that
works towards doing so.)
But while I'm at it, I've also taken the opportunity to clean things
up a bit by renaming functions sensibly. Previously we had three very
similarly named functions verify_ssh_manual_host_key(), SeatVtable's
'verify_ssh_host_key' method, and verify_host_key() in storage.h. Now
the Seat method is called 'confirm' rather than 'verify' (since its
job is now always to print an interactive prompt, so it looks more
like the other confirm_foo methods), and the storage.h function is
called check_stored_host_key(), which goes better with store_host_key
and avoids having too many functions with similar names. And the
'manual' function is subsumed into the new centralised code, so
there's now just *one* host key function with 'verify' in the name.
Several functions are reindented in this commit. Best viewed with
whitespace changes ignored.
2021-10-25 17:12:17 +00:00
|
|
|
struct confirm_ssh_host_key_dialog_ctx *ctx =
|
|
|
|
(struct confirm_ssh_host_key_dialog_ctx *)vctx;
|
2017-11-26 14:29:42 +00:00
|
|
|
|
|
|
|
if (result >= 0) {
|
Richer data type for interactive prompt results.
All the seat functions that request an interactive prompt of some kind
to the user - both the main seat_get_userpass_input and the various
confirmation dialogs for things like host keys - were using a simple
int return value, with the general semantics of 0 = "fail", 1 =
"proceed" (and in the case of seat_get_userpass_input, answers to the
prompts were provided), and -1 = "request in progress, wait for a
callback".
In this commit I change all those functions' return types to a new
struct called SeatPromptResult, whose primary field is an enum
replacing those simple integer values.
The main purpose is that the enum has not three but _four_ values: the
"fail" result has been split into 'user abort' and 'software abort'.
The distinction is that a user abort occurs as a result of an
interactive UI action, such as the user clicking 'cancel' in a dialog
box or hitting ^D or ^C at a terminal password prompt - and therefore,
there's no need to display an error message telling the user that the
interactive operation has failed, because the user already knows,
because they _did_ it. 'Software abort' is from any other cause, where
PuTTY is the first to know there was a problem, and has to tell the
user.
We already had this 'user abort' vs 'software abort' distinction in
other parts of the code - the SSH backend has separate termination
functions which protocol layers can call. But we assumed that any
failure from an interactive prompt request fell into the 'user abort'
category, which is not true. A couple of examples: if you configure a
host key fingerprint in your saved session via the SSH > Host keys
pane, and the server presents a host key that doesn't match it, then
verify_ssh_host_key would report that the user had aborted the
connection, and feel no need to tell the user what had gone wrong!
Similarly, if a password provided on the command line was not
accepted, then (after I fixed the semantics of that in the previous
commit) the same wrong handling would occur.
So now, those Seat prompt functions too can communicate whether the
user or the software originated a connection abort. And in the latter
case, we also provide an error message to present to the user. Result:
in those two example cases (and others), error messages should no
longer go missing.
Implementation note: to avoid the hassle of having the error message
in a SeatPromptResult being a dynamically allocated string (and hence,
every recipient of one must always check whether it's non-NULL and
free it on every exit path, plus being careful about copying the
struct around), I've instead arranged that the structure contains a
function pointer and a couple of parameters, so that the string form
of the message can be constructed on demand. That way, the only users
who need to free it are the ones who actually _asked_ for it in the
first place, which is a much smaller set.
(This is one of the rare occasions that I regret not having C++'s
extra features available in this code base - a unique_ptr or
shared_ptr to a string would have been just the thing here, and the
compiler would have done all the hard work for me of remembering where
to insert the frees!)
2021-12-28 17:52:00 +00:00
|
|
|
SeatPromptResult logical_result;
|
2017-11-26 14:29:42 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Convert the dialog-box return value (one of three
|
|
|
|
* possibilities) into the return value we pass back to the SSH
|
|
|
|
* code (one of only two possibilities, because the SSH code
|
|
|
|
* doesn't care whether we saved the host key or not).
|
|
|
|
*/
|
|
|
|
if (result == 2) {
|
2022-09-13 07:49:38 +00:00
|
|
|
store_host_key(ctx->seat, ctx->host, ctx->port,
|
|
|
|
ctx->keytype, ctx->keystr);
|
Richer data type for interactive prompt results.
All the seat functions that request an interactive prompt of some kind
to the user - both the main seat_get_userpass_input and the various
confirmation dialogs for things like host keys - were using a simple
int return value, with the general semantics of 0 = "fail", 1 =
"proceed" (and in the case of seat_get_userpass_input, answers to the
prompts were provided), and -1 = "request in progress, wait for a
callback".
In this commit I change all those functions' return types to a new
struct called SeatPromptResult, whose primary field is an enum
replacing those simple integer values.
The main purpose is that the enum has not three but _four_ values: the
"fail" result has been split into 'user abort' and 'software abort'.
The distinction is that a user abort occurs as a result of an
interactive UI action, such as the user clicking 'cancel' in a dialog
box or hitting ^D or ^C at a terminal password prompt - and therefore,
there's no need to display an error message telling the user that the
interactive operation has failed, because the user already knows,
because they _did_ it. 'Software abort' is from any other cause, where
PuTTY is the first to know there was a problem, and has to tell the
user.
We already had this 'user abort' vs 'software abort' distinction in
other parts of the code - the SSH backend has separate termination
functions which protocol layers can call. But we assumed that any
failure from an interactive prompt request fell into the 'user abort'
category, which is not true. A couple of examples: if you configure a
host key fingerprint in your saved session via the SSH > Host keys
pane, and the server presents a host key that doesn't match it, then
verify_ssh_host_key would report that the user had aborted the
connection, and feel no need to tell the user what had gone wrong!
Similarly, if a password provided on the command line was not
accepted, then (after I fixed the semantics of that in the previous
commit) the same wrong handling would occur.
So now, those Seat prompt functions too can communicate whether the
user or the software originated a connection abort. And in the latter
case, we also provide an error message to present to the user. Result:
in those two example cases (and others), error messages should no
longer go missing.
Implementation note: to avoid the hassle of having the error message
in a SeatPromptResult being a dynamically allocated string (and hence,
every recipient of one must always check whether it's non-NULL and
free it on every exit path, plus being careful about copying the
struct around), I've instead arranged that the structure contains a
function pointer and a couple of parameters, so that the string form
of the message can be constructed on demand. That way, the only users
who need to free it are the ones who actually _asked_ for it in the
first place, which is a much smaller set.
(This is one of the rare occasions that I regret not having C++'s
extra features available in this code base - a unique_ptr or
shared_ptr to a string would have been just the thing here, and the
compiler would have done all the hard work for me of remembering where
to insert the frees!)
2021-12-28 17:52:00 +00:00
|
|
|
logical_result = SPR_OK;
|
2017-11-26 14:29:42 +00:00
|
|
|
} else if (result == 1) {
|
Richer data type for interactive prompt results.
All the seat functions that request an interactive prompt of some kind
to the user - both the main seat_get_userpass_input and the various
confirmation dialogs for things like host keys - were using a simple
int return value, with the general semantics of 0 = "fail", 1 =
"proceed" (and in the case of seat_get_userpass_input, answers to the
prompts were provided), and -1 = "request in progress, wait for a
callback".
In this commit I change all those functions' return types to a new
struct called SeatPromptResult, whose primary field is an enum
replacing those simple integer values.
The main purpose is that the enum has not three but _four_ values: the
"fail" result has been split into 'user abort' and 'software abort'.
The distinction is that a user abort occurs as a result of an
interactive UI action, such as the user clicking 'cancel' in a dialog
box or hitting ^D or ^C at a terminal password prompt - and therefore,
there's no need to display an error message telling the user that the
interactive operation has failed, because the user already knows,
because they _did_ it. 'Software abort' is from any other cause, where
PuTTY is the first to know there was a problem, and has to tell the
user.
We already had this 'user abort' vs 'software abort' distinction in
other parts of the code - the SSH backend has separate termination
functions which protocol layers can call. But we assumed that any
failure from an interactive prompt request fell into the 'user abort'
category, which is not true. A couple of examples: if you configure a
host key fingerprint in your saved session via the SSH > Host keys
pane, and the server presents a host key that doesn't match it, then
verify_ssh_host_key would report that the user had aborted the
connection, and feel no need to tell the user what had gone wrong!
Similarly, if a password provided on the command line was not
accepted, then (after I fixed the semantics of that in the previous
commit) the same wrong handling would occur.
So now, those Seat prompt functions too can communicate whether the
user or the software originated a connection abort. And in the latter
case, we also provide an error message to present to the user. Result:
in those two example cases (and others), error messages should no
longer go missing.
Implementation note: to avoid the hassle of having the error message
in a SeatPromptResult being a dynamically allocated string (and hence,
every recipient of one must always check whether it's non-NULL and
free it on every exit path, plus being careful about copying the
struct around), I've instead arranged that the structure contains a
function pointer and a couple of parameters, so that the string form
of the message can be constructed on demand. That way, the only users
who need to free it are the ones who actually _asked_ for it in the
first place, which is a much smaller set.
(This is one of the rare occasions that I regret not having C++'s
extra features available in this code base - a unique_ptr or
shared_ptr to a string would have been just the thing here, and the
compiler would have done all the hard work for me of remembering where
to insert the frees!)
2021-12-28 17:52:00 +00:00
|
|
|
logical_result = SPR_OK;
|
2017-11-26 14:29:42 +00:00
|
|
|
} else {
|
Richer data type for interactive prompt results.
All the seat functions that request an interactive prompt of some kind
to the user - both the main seat_get_userpass_input and the various
confirmation dialogs for things like host keys - were using a simple
int return value, with the general semantics of 0 = "fail", 1 =
"proceed" (and in the case of seat_get_userpass_input, answers to the
prompts were provided), and -1 = "request in progress, wait for a
callback".
In this commit I change all those functions' return types to a new
struct called SeatPromptResult, whose primary field is an enum
replacing those simple integer values.
The main purpose is that the enum has not three but _four_ values: the
"fail" result has been split into 'user abort' and 'software abort'.
The distinction is that a user abort occurs as a result of an
interactive UI action, such as the user clicking 'cancel' in a dialog
box or hitting ^D or ^C at a terminal password prompt - and therefore,
there's no need to display an error message telling the user that the
interactive operation has failed, because the user already knows,
because they _did_ it. 'Software abort' is from any other cause, where
PuTTY is the first to know there was a problem, and has to tell the
user.
We already had this 'user abort' vs 'software abort' distinction in
other parts of the code - the SSH backend has separate termination
functions which protocol layers can call. But we assumed that any
failure from an interactive prompt request fell into the 'user abort'
category, which is not true. A couple of examples: if you configure a
host key fingerprint in your saved session via the SSH > Host keys
pane, and the server presents a host key that doesn't match it, then
verify_ssh_host_key would report that the user had aborted the
connection, and feel no need to tell the user what had gone wrong!
Similarly, if a password provided on the command line was not
accepted, then (after I fixed the semantics of that in the previous
commit) the same wrong handling would occur.
So now, those Seat prompt functions too can communicate whether the
user or the software originated a connection abort. And in the latter
case, we also provide an error message to present to the user. Result:
in those two example cases (and others), error messages should no
longer go missing.
Implementation note: to avoid the hassle of having the error message
in a SeatPromptResult being a dynamically allocated string (and hence,
every recipient of one must always check whether it's non-NULL and
free it on every exit path, plus being careful about copying the
struct around), I've instead arranged that the structure contains a
function pointer and a couple of parameters, so that the string form
of the message can be constructed on demand. That way, the only users
who need to free it are the ones who actually _asked_ for it in the
first place, which is a much smaller set.
(This is one of the rare occasions that I regret not having C++'s
extra features available in this code base - a unique_ptr or
shared_ptr to a string would have been just the thing here, and the
compiler would have done all the hard work for me of remembering where
to insert the frees!)
2021-12-28 17:52:00 +00:00
|
|
|
logical_result = SPR_USER_ABORT;
|
2017-11-26 14:29:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
ctx->callback(ctx->callback_ctx, logical_result);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Clean up this context structure, whether or not a result was
|
|
|
|
* ever actually delivered from the dialog box.
|
|
|
|
*/
|
New abstraction 'Seat', to pass to backends.
This is a new vtable-based abstraction which is passed to a backend in
place of Frontend, and it implements only the subset of the Frontend
functions needed by a backend. (Many other Frontend functions still
exist, notably the wide range of things called by terminal.c providing
platform-independent operations on the GUI terminal window.)
The purpose of making it a vtable is that this opens up the
possibility of creating a backend as an internal implementation detail
of some other activity, by providing just that one backend with a
custom Seat that implements the methods differently.
For example, this refactoring should make it feasible to directly
implement an SSH proxy type, aka the 'jump host' feature supported by
OpenSSH, aka 'open a secondary SSH session in MAINCHAN_DIRECT_TCP
mode, and then expose the main channel of that as the Socket for the
primary connection'. (Which of course you can already do by spawning
'plink -nc' as a separate proxy process, but this would permit it in
the _same_ process without anything getting confused.)
I've centralised a full set of stub methods in misc.c for the new
abstraction, which allows me to get rid of several annoying stubs in
the previous code. Also, while I'm here, I've moved a lot of
duplicated modalfatalbox() type functions from application main
program files into wincons.c / uxcons.c, which I think saves
duplication overall. (A minor visible effect is that the prefixes on
those console-based fatal error messages will now be more consistent
between applications.)
2018-10-11 18:58:42 +00:00
|
|
|
unregister_dialog(ctx->seat, DIALOG_SLOT_NETWORK_PROMPT);
|
2017-11-26 14:29:42 +00:00
|
|
|
|
2021-03-13 11:06:32 +00:00
|
|
|
if (ctx->more_info_dialog)
|
|
|
|
gtk_widget_destroy(ctx->more_info_dialog);
|
|
|
|
|
2017-11-26 14:29:42 +00:00
|
|
|
sfree(ctx->host);
|
|
|
|
sfree(ctx->keytype);
|
|
|
|
sfree(ctx->keystr);
|
2021-03-13 11:06:32 +00:00
|
|
|
sfree(ctx->more_info);
|
2017-11-26 14:29:42 +00:00
|
|
|
sfree(ctx);
|
|
|
|
}
|
|
|
|
|
2021-03-13 11:06:32 +00:00
|
|
|
static GtkWidget *add_more_info_button(GtkWidget *w, void *vctx)
|
|
|
|
{
|
|
|
|
GtkWidget *box = gtk_hbox_new(false, 10);
|
|
|
|
gtk_widget_show(box);
|
|
|
|
gtk_box_pack_end(GTK_BOX(box), w, false, true, 0);
|
|
|
|
GtkWidget *button = gtk_button_new_with_label("More info...");
|
|
|
|
gtk_widget_show(button);
|
|
|
|
gtk_box_pack_start(GTK_BOX(box), button, false, true, 0);
|
|
|
|
*(GtkWidget **)vctx = button;
|
|
|
|
return box;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void more_info_closed(void *vctx, int result)
|
|
|
|
{
|
Reorganise host key checking and confirmation.
Previously, checking the host key against the persistent cache managed
by the storage.h API was done as part of the seat_verify_ssh_host_key
method, i.e. separately by each Seat.
Now that check is done by verify_ssh_host_key(), which is a new
function in ssh/common.c that centralises all the parts of host key
checking that don't need an interactive prompt. It subsumes the
previous verify_ssh_manual_host_key() that checked against the Conf,
and it does the check against the storage API that each Seat was
previously doing separately. If it can't confirm or definitively
reject the host key by itself, _then_ it calls out to the Seat, once
an interactive prompt is definitely needed.
The main point of doing this is so that when SshProxy forwards a Seat
call from the proxy SSH connection to the primary Seat, it won't print
an announcement of which connection is involved unless it's actually
going to do something interactive. (Not that we're printing those
announcements _yet_ anyway, but this is a piece of groundwork that
works towards doing so.)
But while I'm at it, I've also taken the opportunity to clean things
up a bit by renaming functions sensibly. Previously we had three very
similarly named functions verify_ssh_manual_host_key(), SeatVtable's
'verify_ssh_host_key' method, and verify_host_key() in storage.h. Now
the Seat method is called 'confirm' rather than 'verify' (since its
job is now always to print an interactive prompt, so it looks more
like the other confirm_foo methods), and the storage.h function is
called check_stored_host_key(), which goes better with store_host_key
and avoids having too many functions with similar names. And the
'manual' function is subsumed into the new centralised code, so
there's now just *one* host key function with 'verify' in the name.
Several functions are reindented in this commit. Best viewed with
whitespace changes ignored.
2021-10-25 17:12:17 +00:00
|
|
|
struct confirm_ssh_host_key_dialog_ctx *ctx =
|
|
|
|
(struct confirm_ssh_host_key_dialog_ctx *)vctx;
|
2021-03-13 11:06:32 +00:00
|
|
|
|
|
|
|
ctx->more_info_dialog = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void more_info_button_clicked(GtkButton *button, gpointer vctx)
|
|
|
|
{
|
Reorganise host key checking and confirmation.
Previously, checking the host key against the persistent cache managed
by the storage.h API was done as part of the seat_verify_ssh_host_key
method, i.e. separately by each Seat.
Now that check is done by verify_ssh_host_key(), which is a new
function in ssh/common.c that centralises all the parts of host key
checking that don't need an interactive prompt. It subsumes the
previous verify_ssh_manual_host_key() that checked against the Conf,
and it does the check against the storage API that each Seat was
previously doing separately. If it can't confirm or definitively
reject the host key by itself, _then_ it calls out to the Seat, once
an interactive prompt is definitely needed.
The main point of doing this is so that when SshProxy forwards a Seat
call from the proxy SSH connection to the primary Seat, it won't print
an announcement of which connection is involved unless it's actually
going to do something interactive. (Not that we're printing those
announcements _yet_ anyway, but this is a piece of groundwork that
works towards doing so.)
But while I'm at it, I've also taken the opportunity to clean things
up a bit by renaming functions sensibly. Previously we had three very
similarly named functions verify_ssh_manual_host_key(), SeatVtable's
'verify_ssh_host_key' method, and verify_host_key() in storage.h. Now
the Seat method is called 'confirm' rather than 'verify' (since its
job is now always to print an interactive prompt, so it looks more
like the other confirm_foo methods), and the storage.h function is
called check_stored_host_key(), which goes better with store_host_key
and avoids having too many functions with similar names. And the
'manual' function is subsumed into the new centralised code, so
there's now just *one* host key function with 'verify' in the name.
Several functions are reindented in this commit. Best viewed with
whitespace changes ignored.
2021-10-25 17:12:17 +00:00
|
|
|
struct confirm_ssh_host_key_dialog_ctx *ctx =
|
|
|
|
(struct confirm_ssh_host_key_dialog_ctx *)vctx;
|
2021-03-13 11:06:32 +00:00
|
|
|
|
|
|
|
if (ctx->more_info_dialog)
|
|
|
|
return;
|
|
|
|
|
|
|
|
ctx->more_info_dialog = create_message_box(
|
|
|
|
ctx->main_dialog, "Host key information", ctx->more_info,
|
|
|
|
string_width("SHA256 fingerprint: ecdsa-sha2-nistp521 521 "
|
|
|
|
"abcdefghkmnopqrsuvwxyzABCDEFGHJKLMNOPQRSTUW"), true,
|
|
|
|
&buttons_ok, more_info_closed, ctx);
|
|
|
|
}
|
|
|
|
|
Centralise most details of host-key prompting.
The text of the host key warnings was replicated in three places: the
Windows rc file, the GTK dialog setup function, and the console.c
shared between both platforms' CLI tools. Now it lives in just one
place, namely ssh/common.c where the rest of the centralised host-key
checking is done, so it'll be easier to adjust the wording in future.
This comes with some extra automation. Paragraph wrapping is no longer
done by hand in any version of these prompts. (Previously we let GTK
do the wrapping on GTK, but on Windows the resource file contained a
bunch of pre-wrapped LTEXT lines, and console.c had pre-wrapped
terminal messages.) And the dialog heights in Windows are determined
automatically based on the amount of stuff in the window.
The main idea of all this is that it'll be easier to set up more
elaborate kinds of host key prompt that deal with certificates (if,
e.g., a server sends us a certified host key which we don't trust the
CA for). But there are side benefits of this refactoring too: each
tool now reliably inserts its own appname in the prompts, and also, on
Windows the entire prompt text is copy-pastable.
Details of implementation: there's a new type SeatDialogText which
holds a set of (type, string) pairs describing the contents of a
prompt. Type codes distinguish ordinary text paragraphs, paragraphs to
be displayed prominently (like key fingerprints), the extra-bold scary
title at the top of the 'host key changed' version of the dialog, and
the various information that lives in the subsidiary 'more info' box.
ssh/common.c constructs this, and passes it to the Seat to present the
actual prompt.
In order to deal with the different UI for answering the prompt, I've
added an extra Seat method 'prompt_descriptions' which returns some
snippets of text to interpolate into the messages. ssh/common.c calls
that while it's still constructing the text, and incorporates the
resulting snippets into the SeatDialogText.
For the moment, this refactoring only affects the host key prompts.
The warnings about outmoded crypto are still done the old-fashioned
way; they probably ought to be similarly refactored to use this new
SeatDialogText system, but it's not immediately critical for the
purpose I have right now.
2022-07-07 16:25:15 +00:00
|
|
|
const SeatDialogPromptDescriptions *gtk_seat_prompt_descriptions(Seat *seat)
|
|
|
|
{
|
|
|
|
static const SeatDialogPromptDescriptions descs = {
|
|
|
|
.hk_accept_action = "press \"Accept\"",
|
|
|
|
.hk_connect_once_action = "press \"Connect Once\"",
|
|
|
|
.hk_cancel_action = "press \"Cancel\"",
|
|
|
|
.hk_cancel_action_Participle = "Pressing \"Cancel\"",
|
2023-11-22 08:57:54 +00:00
|
|
|
.weak_accept_action = "press \"Yes\"",
|
|
|
|
.weak_cancel_action = "press \"No\"",
|
Centralise most details of host-key prompting.
The text of the host key warnings was replicated in three places: the
Windows rc file, the GTK dialog setup function, and the console.c
shared between both platforms' CLI tools. Now it lives in just one
place, namely ssh/common.c where the rest of the centralised host-key
checking is done, so it'll be easier to adjust the wording in future.
This comes with some extra automation. Paragraph wrapping is no longer
done by hand in any version of these prompts. (Previously we let GTK
do the wrapping on GTK, but on Windows the resource file contained a
bunch of pre-wrapped LTEXT lines, and console.c had pre-wrapped
terminal messages.) And the dialog heights in Windows are determined
automatically based on the amount of stuff in the window.
The main idea of all this is that it'll be easier to set up more
elaborate kinds of host key prompt that deal with certificates (if,
e.g., a server sends us a certified host key which we don't trust the
CA for). But there are side benefits of this refactoring too: each
tool now reliably inserts its own appname in the prompts, and also, on
Windows the entire prompt text is copy-pastable.
Details of implementation: there's a new type SeatDialogText which
holds a set of (type, string) pairs describing the contents of a
prompt. Type codes distinguish ordinary text paragraphs, paragraphs to
be displayed prominently (like key fingerprints), the extra-bold scary
title at the top of the 'host key changed' version of the dialog, and
the various information that lives in the subsidiary 'more info' box.
ssh/common.c constructs this, and passes it to the Seat to present the
actual prompt.
In order to deal with the different UI for answering the prompt, I've
added an extra Seat method 'prompt_descriptions' which returns some
snippets of text to interpolate into the messages. ssh/common.c calls
that while it's still constructing the text, and incorporates the
resulting snippets into the SeatDialogText.
For the moment, this refactoring only affects the host key prompts.
The warnings about outmoded crypto are still done the old-fashioned
way; they probably ought to be similarly refactored to use this new
SeatDialogText system, but it's not immediately critical for the
purpose I have right now.
2022-07-07 16:25:15 +00:00
|
|
|
};
|
|
|
|
return &descs;
|
|
|
|
}
|
|
|
|
|
2023-11-22 08:57:54 +00:00
|
|
|
/*
|
|
|
|
* Format a SeatDialogText into a strbuf, also adjusting the box width
|
|
|
|
* to cope with displayed text. Returns the dialog box title.
|
|
|
|
*/
|
|
|
|
static const char *gtk_format_seatdialogtext(
|
|
|
|
SeatDialogText *text, strbuf *dlg_text, int *width)
|
2003-03-31 11:21:07 +00:00
|
|
|
{
|
Centralise most details of host-key prompting.
The text of the host key warnings was replicated in three places: the
Windows rc file, the GTK dialog setup function, and the console.c
shared between both platforms' CLI tools. Now it lives in just one
place, namely ssh/common.c where the rest of the centralised host-key
checking is done, so it'll be easier to adjust the wording in future.
This comes with some extra automation. Paragraph wrapping is no longer
done by hand in any version of these prompts. (Previously we let GTK
do the wrapping on GTK, but on Windows the resource file contained a
bunch of pre-wrapped LTEXT lines, and console.c had pre-wrapped
terminal messages.) And the dialog heights in Windows are determined
automatically based on the amount of stuff in the window.
The main idea of all this is that it'll be easier to set up more
elaborate kinds of host key prompt that deal with certificates (if,
e.g., a server sends us a certified host key which we don't trust the
CA for). But there are side benefits of this refactoring too: each
tool now reliably inserts its own appname in the prompts, and also, on
Windows the entire prompt text is copy-pastable.
Details of implementation: there's a new type SeatDialogText which
holds a set of (type, string) pairs describing the contents of a
prompt. Type codes distinguish ordinary text paragraphs, paragraphs to
be displayed prominently (like key fingerprints), the extra-bold scary
title at the top of the 'host key changed' version of the dialog, and
the various information that lives in the subsidiary 'more info' box.
ssh/common.c constructs this, and passes it to the Seat to present the
actual prompt.
In order to deal with the different UI for answering the prompt, I've
added an extra Seat method 'prompt_descriptions' which returns some
snippets of text to interpolate into the messages. ssh/common.c calls
that while it's still constructing the text, and incorporates the
resulting snippets into the SeatDialogText.
For the moment, this refactoring only affects the host key prompts.
The warnings about outmoded crypto are still done the old-fashioned
way; they probably ought to be similarly refactored to use this new
SeatDialogText system, but it's not immediately critical for the
purpose I have right now.
2022-07-07 16:25:15 +00:00
|
|
|
const char *dlg_title = NULL;
|
2003-03-31 11:21:07 +00:00
|
|
|
|
Centralise most details of host-key prompting.
The text of the host key warnings was replicated in three places: the
Windows rc file, the GTK dialog setup function, and the console.c
shared between both platforms' CLI tools. Now it lives in just one
place, namely ssh/common.c where the rest of the centralised host-key
checking is done, so it'll be easier to adjust the wording in future.
This comes with some extra automation. Paragraph wrapping is no longer
done by hand in any version of these prompts. (Previously we let GTK
do the wrapping on GTK, but on Windows the resource file contained a
bunch of pre-wrapped LTEXT lines, and console.c had pre-wrapped
terminal messages.) And the dialog heights in Windows are determined
automatically based on the amount of stuff in the window.
The main idea of all this is that it'll be easier to set up more
elaborate kinds of host key prompt that deal with certificates (if,
e.g., a server sends us a certified host key which we don't trust the
CA for). But there are side benefits of this refactoring too: each
tool now reliably inserts its own appname in the prompts, and also, on
Windows the entire prompt text is copy-pastable.
Details of implementation: there's a new type SeatDialogText which
holds a set of (type, string) pairs describing the contents of a
prompt. Type codes distinguish ordinary text paragraphs, paragraphs to
be displayed prominently (like key fingerprints), the extra-bold scary
title at the top of the 'host key changed' version of the dialog, and
the various information that lives in the subsidiary 'more info' box.
ssh/common.c constructs this, and passes it to the Seat to present the
actual prompt.
In order to deal with the different UI for answering the prompt, I've
added an extra Seat method 'prompt_descriptions' which returns some
snippets of text to interpolate into the messages. ssh/common.c calls
that while it's still constructing the text, and incorporates the
resulting snippets into the SeatDialogText.
For the moment, this refactoring only affects the host key prompts.
The warnings about outmoded crypto are still done the old-fashioned
way; they probably ought to be similarly refactored to use this new
SeatDialogText system, but it's not immediately critical for the
purpose I have right now.
2022-07-07 16:25:15 +00:00
|
|
|
for (SeatDialogTextItem *item = text->items,
|
|
|
|
*end = item + text->nitems; item < end; item++) {
|
|
|
|
switch (item->type) {
|
|
|
|
case SDT_PARA:
|
|
|
|
put_fmt(dlg_text, "%s\n\n", item->text);
|
|
|
|
break;
|
|
|
|
case SDT_DISPLAY: {
|
|
|
|
put_fmt(dlg_text, "%s\n\n", item->text);
|
|
|
|
int thiswidth = string_width(item->text);
|
2023-11-22 08:57:54 +00:00
|
|
|
if (*width < thiswidth)
|
|
|
|
*width = thiswidth;
|
Centralise most details of host-key prompting.
The text of the host key warnings was replicated in three places: the
Windows rc file, the GTK dialog setup function, and the console.c
shared between both platforms' CLI tools. Now it lives in just one
place, namely ssh/common.c where the rest of the centralised host-key
checking is done, so it'll be easier to adjust the wording in future.
This comes with some extra automation. Paragraph wrapping is no longer
done by hand in any version of these prompts. (Previously we let GTK
do the wrapping on GTK, but on Windows the resource file contained a
bunch of pre-wrapped LTEXT lines, and console.c had pre-wrapped
terminal messages.) And the dialog heights in Windows are determined
automatically based on the amount of stuff in the window.
The main idea of all this is that it'll be easier to set up more
elaborate kinds of host key prompt that deal with certificates (if,
e.g., a server sends us a certified host key which we don't trust the
CA for). But there are side benefits of this refactoring too: each
tool now reliably inserts its own appname in the prompts, and also, on
Windows the entire prompt text is copy-pastable.
Details of implementation: there's a new type SeatDialogText which
holds a set of (type, string) pairs describing the contents of a
prompt. Type codes distinguish ordinary text paragraphs, paragraphs to
be displayed prominently (like key fingerprints), the extra-bold scary
title at the top of the 'host key changed' version of the dialog, and
the various information that lives in the subsidiary 'more info' box.
ssh/common.c constructs this, and passes it to the Seat to present the
actual prompt.
In order to deal with the different UI for answering the prompt, I've
added an extra Seat method 'prompt_descriptions' which returns some
snippets of text to interpolate into the messages. ssh/common.c calls
that while it's still constructing the text, and incorporates the
resulting snippets into the SeatDialogText.
For the moment, this refactoring only affects the host key prompts.
The warnings about outmoded crypto are still done the old-fashioned
way; they probably ought to be similarly refactored to use this new
SeatDialogText system, but it's not immediately critical for the
purpose I have right now.
2022-07-07 16:25:15 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case SDT_SCARY_HEADING:
|
|
|
|
/* Can't change font size or weight in this context */
|
|
|
|
put_fmt(dlg_text, "%s\n\n", item->text);
|
|
|
|
break;
|
|
|
|
case SDT_TITLE:
|
|
|
|
dlg_title = item->text;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2023-11-22 08:57:54 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Trim trailing newlines.
|
|
|
|
*/
|
Centralise most details of host-key prompting.
The text of the host key warnings was replicated in three places: the
Windows rc file, the GTK dialog setup function, and the console.c
shared between both platforms' CLI tools. Now it lives in just one
place, namely ssh/common.c where the rest of the centralised host-key
checking is done, so it'll be easier to adjust the wording in future.
This comes with some extra automation. Paragraph wrapping is no longer
done by hand in any version of these prompts. (Previously we let GTK
do the wrapping on GTK, but on Windows the resource file contained a
bunch of pre-wrapped LTEXT lines, and console.c had pre-wrapped
terminal messages.) And the dialog heights in Windows are determined
automatically based on the amount of stuff in the window.
The main idea of all this is that it'll be easier to set up more
elaborate kinds of host key prompt that deal with certificates (if,
e.g., a server sends us a certified host key which we don't trust the
CA for). But there are side benefits of this refactoring too: each
tool now reliably inserts its own appname in the prompts, and also, on
Windows the entire prompt text is copy-pastable.
Details of implementation: there's a new type SeatDialogText which
holds a set of (type, string) pairs describing the contents of a
prompt. Type codes distinguish ordinary text paragraphs, paragraphs to
be displayed prominently (like key fingerprints), the extra-bold scary
title at the top of the 'host key changed' version of the dialog, and
the various information that lives in the subsidiary 'more info' box.
ssh/common.c constructs this, and passes it to the Seat to present the
actual prompt.
In order to deal with the different UI for answering the prompt, I've
added an extra Seat method 'prompt_descriptions' which returns some
snippets of text to interpolate into the messages. ssh/common.c calls
that while it's still constructing the text, and incorporates the
resulting snippets into the SeatDialogText.
For the moment, this refactoring only affects the host key prompts.
The warnings about outmoded crypto are still done the old-fashioned
way; they probably ought to be similarly refactored to use this new
SeatDialogText system, but it's not immediately critical for the
purpose I have right now.
2022-07-07 16:25:15 +00:00
|
|
|
while (strbuf_chomp(dlg_text, '\n'));
|
2021-03-13 10:59:47 +00:00
|
|
|
|
2023-11-22 08:57:54 +00:00
|
|
|
return dlg_title;
|
|
|
|
}
|
|
|
|
|
|
|
|
SeatPromptResult gtk_seat_confirm_ssh_host_key(
|
|
|
|
Seat *seat, const char *host, int port, const char *keytype,
|
|
|
|
char *keystr, SeatDialogText *text, HelpCtx helpctx,
|
|
|
|
void (*callback)(void *ctx, SeatPromptResult result), void *ctx)
|
|
|
|
{
|
|
|
|
static const struct message_box_button button_array_hostkey[] = {
|
|
|
|
{"Accept", 'a', 0, 2},
|
|
|
|
{"Connect Once", 'o', 0, 1},
|
|
|
|
{"Cancel", 'c', -1, 0},
|
|
|
|
};
|
|
|
|
static const struct message_box_buttons buttons_hostkey = {
|
|
|
|
button_array_hostkey, lenof(button_array_hostkey),
|
|
|
|
};
|
|
|
|
|
|
|
|
int width = string_width("default dialog width determination string");
|
|
|
|
strbuf *dlg_text = strbuf_new();
|
|
|
|
const char *dlg_title = gtk_format_seatdialogtext(text, dlg_text, &width);
|
|
|
|
|
Centralise most details of host-key prompting.
The text of the host key warnings was replicated in three places: the
Windows rc file, the GTK dialog setup function, and the console.c
shared between both platforms' CLI tools. Now it lives in just one
place, namely ssh/common.c where the rest of the centralised host-key
checking is done, so it'll be easier to adjust the wording in future.
This comes with some extra automation. Paragraph wrapping is no longer
done by hand in any version of these prompts. (Previously we let GTK
do the wrapping on GTK, but on Windows the resource file contained a
bunch of pre-wrapped LTEXT lines, and console.c had pre-wrapped
terminal messages.) And the dialog heights in Windows are determined
automatically based on the amount of stuff in the window.
The main idea of all this is that it'll be easier to set up more
elaborate kinds of host key prompt that deal with certificates (if,
e.g., a server sends us a certified host key which we don't trust the
CA for). But there are side benefits of this refactoring too: each
tool now reliably inserts its own appname in the prompts, and also, on
Windows the entire prompt text is copy-pastable.
Details of implementation: there's a new type SeatDialogText which
holds a set of (type, string) pairs describing the contents of a
prompt. Type codes distinguish ordinary text paragraphs, paragraphs to
be displayed prominently (like key fingerprints), the extra-bold scary
title at the top of the 'host key changed' version of the dialog, and
the various information that lives in the subsidiary 'more info' box.
ssh/common.c constructs this, and passes it to the Seat to present the
actual prompt.
In order to deal with the different UI for answering the prompt, I've
added an extra Seat method 'prompt_descriptions' which returns some
snippets of text to interpolate into the messages. ssh/common.c calls
that while it's still constructing the text, and incorporates the
resulting snippets into the SeatDialogText.
For the moment, this refactoring only affects the host key prompts.
The warnings about outmoded crypto are still done the old-fashioned
way; they probably ought to be similarly refactored to use this new
SeatDialogText system, but it's not immediately critical for the
purpose I have right now.
2022-07-07 16:25:15 +00:00
|
|
|
GtkWidget *mainwin, *msgbox;
|
2003-03-31 11:21:07 +00:00
|
|
|
|
Centralise most details of host-key prompting.
The text of the host key warnings was replicated in three places: the
Windows rc file, the GTK dialog setup function, and the console.c
shared between both platforms' CLI tools. Now it lives in just one
place, namely ssh/common.c where the rest of the centralised host-key
checking is done, so it'll be easier to adjust the wording in future.
This comes with some extra automation. Paragraph wrapping is no longer
done by hand in any version of these prompts. (Previously we let GTK
do the wrapping on GTK, but on Windows the resource file contained a
bunch of pre-wrapped LTEXT lines, and console.c had pre-wrapped
terminal messages.) And the dialog heights in Windows are determined
automatically based on the amount of stuff in the window.
The main idea of all this is that it'll be easier to set up more
elaborate kinds of host key prompt that deal with certificates (if,
e.g., a server sends us a certified host key which we don't trust the
CA for). But there are side benefits of this refactoring too: each
tool now reliably inserts its own appname in the prompts, and also, on
Windows the entire prompt text is copy-pastable.
Details of implementation: there's a new type SeatDialogText which
holds a set of (type, string) pairs describing the contents of a
prompt. Type codes distinguish ordinary text paragraphs, paragraphs to
be displayed prominently (like key fingerprints), the extra-bold scary
title at the top of the 'host key changed' version of the dialog, and
the various information that lives in the subsidiary 'more info' box.
ssh/common.c constructs this, and passes it to the Seat to present the
actual prompt.
In order to deal with the different UI for answering the prompt, I've
added an extra Seat method 'prompt_descriptions' which returns some
snippets of text to interpolate into the messages. ssh/common.c calls
that while it's still constructing the text, and incorporates the
resulting snippets into the SeatDialogText.
For the moment, this refactoring only affects the host key prompts.
The warnings about outmoded crypto are still done the old-fashioned
way; they probably ought to be similarly refactored to use this new
SeatDialogText system, but it's not immediately critical for the
purpose I have right now.
2022-07-07 16:25:15 +00:00
|
|
|
struct confirm_ssh_host_key_dialog_ctx *result_ctx =
|
|
|
|
snew(struct confirm_ssh_host_key_dialog_ctx);
|
2017-11-26 14:29:42 +00:00
|
|
|
result_ctx->callback = callback;
|
|
|
|
result_ctx->callback_ctx = ctx;
|
|
|
|
result_ctx->host = dupstr(host);
|
|
|
|
result_ctx->port = port;
|
|
|
|
result_ctx->keytype = dupstr(keytype);
|
|
|
|
result_ctx->keystr = dupstr(keystr);
|
New abstraction 'Seat', to pass to backends.
This is a new vtable-based abstraction which is passed to a backend in
place of Frontend, and it implements only the subset of the Frontend
functions needed by a backend. (Many other Frontend functions still
exist, notably the wide range of things called by terminal.c providing
platform-independent operations on the GUI terminal window.)
The purpose of making it a vtable is that this opens up the
possibility of creating a backend as an internal implementation detail
of some other activity, by providing just that one backend with a
custom Seat that implements the methods differently.
For example, this refactoring should make it feasible to directly
implement an SSH proxy type, aka the 'jump host' feature supported by
OpenSSH, aka 'open a secondary SSH session in MAINCHAN_DIRECT_TCP
mode, and then expose the main channel of that as the Socket for the
primary connection'. (Which of course you can already do by spawning
'plink -nc' as a separate proxy process, but this would permit it in
the _same_ process without anything getting confused.)
I've centralised a full set of stub methods in misc.c for the new
abstraction, which allows me to get rid of several annoying stubs in
the previous code. Also, while I'm here, I've moved a lot of
duplicated modalfatalbox() type functions from application main
program files into wincons.c / uxcons.c, which I think saves
duplication overall. (A minor visible effect is that the prefixes on
those console-based fatal error messages will now be more consistent
between applications.)
2018-10-11 18:58:42 +00:00
|
|
|
result_ctx->seat = seat;
|
2017-11-26 14:29:42 +00:00
|
|
|
|
New abstraction 'Seat', to pass to backends.
This is a new vtable-based abstraction which is passed to a backend in
place of Frontend, and it implements only the subset of the Frontend
functions needed by a backend. (Many other Frontend functions still
exist, notably the wide range of things called by terminal.c providing
platform-independent operations on the GUI terminal window.)
The purpose of making it a vtable is that this opens up the
possibility of creating a backend as an internal implementation detail
of some other activity, by providing just that one backend with a
custom Seat that implements the methods differently.
For example, this refactoring should make it feasible to directly
implement an SSH proxy type, aka the 'jump host' feature supported by
OpenSSH, aka 'open a secondary SSH session in MAINCHAN_DIRECT_TCP
mode, and then expose the main channel of that as the Socket for the
primary connection'. (Which of course you can already do by spawning
'plink -nc' as a separate proxy process, but this would permit it in
the _same_ process without anything getting confused.)
I've centralised a full set of stub methods in misc.c for the new
abstraction, which allows me to get rid of several annoying stubs in
the previous code. Also, while I'm here, I've moved a lot of
duplicated modalfatalbox() type functions from application main
program files into wincons.c / uxcons.c, which I think saves
duplication overall. (A minor visible effect is that the prefixes on
those console-based fatal error messages will now be more consistent
between applications.)
2018-10-11 18:58:42 +00:00
|
|
|
mainwin = GTK_WIDGET(gtk_seat_get_window(seat));
|
2021-03-13 11:06:32 +00:00
|
|
|
GtkWidget *more_info_button = NULL;
|
|
|
|
msgbox = create_message_box_general(
|
Centralise most details of host-key prompting.
The text of the host key warnings was replicated in three places: the
Windows rc file, the GTK dialog setup function, and the console.c
shared between both platforms' CLI tools. Now it lives in just one
place, namely ssh/common.c where the rest of the centralised host-key
checking is done, so it'll be easier to adjust the wording in future.
This comes with some extra automation. Paragraph wrapping is no longer
done by hand in any version of these prompts. (Previously we let GTK
do the wrapping on GTK, but on Windows the resource file contained a
bunch of pre-wrapped LTEXT lines, and console.c had pre-wrapped
terminal messages.) And the dialog heights in Windows are determined
automatically based on the amount of stuff in the window.
The main idea of all this is that it'll be easier to set up more
elaborate kinds of host key prompt that deal with certificates (if,
e.g., a server sends us a certified host key which we don't trust the
CA for). But there are side benefits of this refactoring too: each
tool now reliably inserts its own appname in the prompts, and also, on
Windows the entire prompt text is copy-pastable.
Details of implementation: there's a new type SeatDialogText which
holds a set of (type, string) pairs describing the contents of a
prompt. Type codes distinguish ordinary text paragraphs, paragraphs to
be displayed prominently (like key fingerprints), the extra-bold scary
title at the top of the 'host key changed' version of the dialog, and
the various information that lives in the subsidiary 'more info' box.
ssh/common.c constructs this, and passes it to the Seat to present the
actual prompt.
In order to deal with the different UI for answering the prompt, I've
added an extra Seat method 'prompt_descriptions' which returns some
snippets of text to interpolate into the messages. ssh/common.c calls
that while it's still constructing the text, and incorporates the
resulting snippets into the SeatDialogText.
For the moment, this refactoring only affects the host key prompts.
The warnings about outmoded crypto are still done the old-fashioned
way; they probably ought to be similarly refactored to use this new
SeatDialogText system, but it's not immediately critical for the
purpose I have right now.
2022-07-07 16:25:15 +00:00
|
|
|
mainwin, dlg_title, dlg_text->s, width, true,
|
Reorganise host key checking and confirmation.
Previously, checking the host key against the persistent cache managed
by the storage.h API was done as part of the seat_verify_ssh_host_key
method, i.e. separately by each Seat.
Now that check is done by verify_ssh_host_key(), which is a new
function in ssh/common.c that centralises all the parts of host key
checking that don't need an interactive prompt. It subsumes the
previous verify_ssh_manual_host_key() that checked against the Conf,
and it does the check against the storage API that each Seat was
previously doing separately. If it can't confirm or definitively
reject the host key by itself, _then_ it calls out to the Seat, once
an interactive prompt is definitely needed.
The main point of doing this is so that when SshProxy forwards a Seat
call from the proxy SSH connection to the primary Seat, it won't print
an announcement of which connection is involved unless it's actually
going to do something interactive. (Not that we're printing those
announcements _yet_ anyway, but this is a piece of groundwork that
works towards doing so.)
But while I'm at it, I've also taken the opportunity to clean things
up a bit by renaming functions sensibly. Previously we had three very
similarly named functions verify_ssh_manual_host_key(), SeatVtable's
'verify_ssh_host_key' method, and verify_host_key() in storage.h. Now
the Seat method is called 'confirm' rather than 'verify' (since its
job is now always to print an interactive prompt, so it looks more
like the other confirm_foo methods), and the storage.h function is
called check_stored_host_key(), which goes better with store_host_key
and avoids having too many functions with similar names. And the
'manual' function is subsumed into the new centralised code, so
there's now just *one* host key function with 'verify' in the name.
Several functions are reindented in this commit. Best viewed with
whitespace changes ignored.
2021-10-25 17:12:17 +00:00
|
|
|
&buttons_hostkey, confirm_ssh_host_key_result_callback, result_ctx,
|
2021-03-13 11:06:32 +00:00
|
|
|
add_more_info_button, &more_info_button);
|
|
|
|
|
|
|
|
result_ctx->main_dialog = msgbox;
|
|
|
|
result_ctx->more_info_dialog = NULL;
|
|
|
|
|
Centralise most details of host-key prompting.
The text of the host key warnings was replicated in three places: the
Windows rc file, the GTK dialog setup function, and the console.c
shared between both platforms' CLI tools. Now it lives in just one
place, namely ssh/common.c where the rest of the centralised host-key
checking is done, so it'll be easier to adjust the wording in future.
This comes with some extra automation. Paragraph wrapping is no longer
done by hand in any version of these prompts. (Previously we let GTK
do the wrapping on GTK, but on Windows the resource file contained a
bunch of pre-wrapped LTEXT lines, and console.c had pre-wrapped
terminal messages.) And the dialog heights in Windows are determined
automatically based on the amount of stuff in the window.
The main idea of all this is that it'll be easier to set up more
elaborate kinds of host key prompt that deal with certificates (if,
e.g., a server sends us a certified host key which we don't trust the
CA for). But there are side benefits of this refactoring too: each
tool now reliably inserts its own appname in the prompts, and also, on
Windows the entire prompt text is copy-pastable.
Details of implementation: there's a new type SeatDialogText which
holds a set of (type, string) pairs describing the contents of a
prompt. Type codes distinguish ordinary text paragraphs, paragraphs to
be displayed prominently (like key fingerprints), the extra-bold scary
title at the top of the 'host key changed' version of the dialog, and
the various information that lives in the subsidiary 'more info' box.
ssh/common.c constructs this, and passes it to the Seat to present the
actual prompt.
In order to deal with the different UI for answering the prompt, I've
added an extra Seat method 'prompt_descriptions' which returns some
snippets of text to interpolate into the messages. ssh/common.c calls
that while it's still constructing the text, and incorporates the
resulting snippets into the SeatDialogText.
For the moment, this refactoring only affects the host key prompts.
The warnings about outmoded crypto are still done the old-fashioned
way; they probably ought to be similarly refactored to use this new
SeatDialogText system, but it's not immediately critical for the
purpose I have right now.
2022-07-07 16:25:15 +00:00
|
|
|
strbuf *moreinfo = strbuf_new();
|
|
|
|
for (SeatDialogTextItem *item = text->items,
|
|
|
|
*end = item + text->nitems; item < end; item++) {
|
|
|
|
switch (item->type) {
|
|
|
|
case SDT_MORE_INFO_KEY:
|
|
|
|
put_fmt(moreinfo, "%s", item->text);
|
|
|
|
break;
|
|
|
|
case SDT_MORE_INFO_VALUE_SHORT:
|
|
|
|
put_fmt(moreinfo, ": %s\n", item->text);
|
|
|
|
break;
|
|
|
|
case SDT_MORE_INFO_VALUE_BLOB:
|
|
|
|
/* We have to manually wrap the public key, or else the GtkLabel
|
|
|
|
* will resize itself to accommodate the longest word, which will
|
|
|
|
* lead to a hilariously wide message box. */
|
2022-10-21 18:01:58 +00:00
|
|
|
put_byte(moreinfo, ':');
|
Centralise most details of host-key prompting.
The text of the host key warnings was replicated in three places: the
Windows rc file, the GTK dialog setup function, and the console.c
shared between both platforms' CLI tools. Now it lives in just one
place, namely ssh/common.c where the rest of the centralised host-key
checking is done, so it'll be easier to adjust the wording in future.
This comes with some extra automation. Paragraph wrapping is no longer
done by hand in any version of these prompts. (Previously we let GTK
do the wrapping on GTK, but on Windows the resource file contained a
bunch of pre-wrapped LTEXT lines, and console.c had pre-wrapped
terminal messages.) And the dialog heights in Windows are determined
automatically based on the amount of stuff in the window.
The main idea of all this is that it'll be easier to set up more
elaborate kinds of host key prompt that deal with certificates (if,
e.g., a server sends us a certified host key which we don't trust the
CA for). But there are side benefits of this refactoring too: each
tool now reliably inserts its own appname in the prompts, and also, on
Windows the entire prompt text is copy-pastable.
Details of implementation: there's a new type SeatDialogText which
holds a set of (type, string) pairs describing the contents of a
prompt. Type codes distinguish ordinary text paragraphs, paragraphs to
be displayed prominently (like key fingerprints), the extra-bold scary
title at the top of the 'host key changed' version of the dialog, and
the various information that lives in the subsidiary 'more info' box.
ssh/common.c constructs this, and passes it to the Seat to present the
actual prompt.
In order to deal with the different UI for answering the prompt, I've
added an extra Seat method 'prompt_descriptions' which returns some
snippets of text to interpolate into the messages. ssh/common.c calls
that while it's still constructing the text, and incorporates the
resulting snippets into the SeatDialogText.
For the moment, this refactoring only affects the host key prompts.
The warnings about outmoded crypto are still done the old-fashioned
way; they probably ought to be similarly refactored to use this new
SeatDialogText system, but it's not immediately critical for the
purpose I have right now.
2022-07-07 16:25:15 +00:00
|
|
|
for (const char *p = item->text, *q = p + strlen(p); p < q ;) {
|
|
|
|
size_t linelen = q-p;
|
|
|
|
if (linelen > 72)
|
|
|
|
linelen = 72;
|
|
|
|
put_byte(moreinfo, '\n');
|
|
|
|
put_data(moreinfo, p, linelen);
|
|
|
|
p += linelen;
|
|
|
|
}
|
2022-10-21 18:01:58 +00:00
|
|
|
put_byte(moreinfo, '\n');
|
Centralise most details of host-key prompting.
The text of the host key warnings was replicated in three places: the
Windows rc file, the GTK dialog setup function, and the console.c
shared between both platforms' CLI tools. Now it lives in just one
place, namely ssh/common.c where the rest of the centralised host-key
checking is done, so it'll be easier to adjust the wording in future.
This comes with some extra automation. Paragraph wrapping is no longer
done by hand in any version of these prompts. (Previously we let GTK
do the wrapping on GTK, but on Windows the resource file contained a
bunch of pre-wrapped LTEXT lines, and console.c had pre-wrapped
terminal messages.) And the dialog heights in Windows are determined
automatically based on the amount of stuff in the window.
The main idea of all this is that it'll be easier to set up more
elaborate kinds of host key prompt that deal with certificates (if,
e.g., a server sends us a certified host key which we don't trust the
CA for). But there are side benefits of this refactoring too: each
tool now reliably inserts its own appname in the prompts, and also, on
Windows the entire prompt text is copy-pastable.
Details of implementation: there's a new type SeatDialogText which
holds a set of (type, string) pairs describing the contents of a
prompt. Type codes distinguish ordinary text paragraphs, paragraphs to
be displayed prominently (like key fingerprints), the extra-bold scary
title at the top of the 'host key changed' version of the dialog, and
the various information that lives in the subsidiary 'more info' box.
ssh/common.c constructs this, and passes it to the Seat to present the
actual prompt.
In order to deal with the different UI for answering the prompt, I've
added an extra Seat method 'prompt_descriptions' which returns some
snippets of text to interpolate into the messages. ssh/common.c calls
that while it's still constructing the text, and incorporates the
resulting snippets into the SeatDialogText.
For the moment, this refactoring only affects the host key prompts.
The warnings about outmoded crypto are still done the old-fashioned
way; they probably ought to be similarly refactored to use this new
SeatDialogText system, but it's not immediately critical for the
purpose I have right now.
2022-07-07 16:25:15 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
result_ctx->more_info = strbuf_to_str(moreinfo);
|
2021-03-13 11:06:32 +00:00
|
|
|
|
|
|
|
g_signal_connect(G_OBJECT(more_info_button), "clicked",
|
|
|
|
G_CALLBACK(more_info_button_clicked), result_ctx);
|
|
|
|
|
New abstraction 'Seat', to pass to backends.
This is a new vtable-based abstraction which is passed to a backend in
place of Frontend, and it implements only the subset of the Frontend
functions needed by a backend. (Many other Frontend functions still
exist, notably the wide range of things called by terminal.c providing
platform-independent operations on the GUI terminal window.)
The purpose of making it a vtable is that this opens up the
possibility of creating a backend as an internal implementation detail
of some other activity, by providing just that one backend with a
custom Seat that implements the methods differently.
For example, this refactoring should make it feasible to directly
implement an SSH proxy type, aka the 'jump host' feature supported by
OpenSSH, aka 'open a secondary SSH session in MAINCHAN_DIRECT_TCP
mode, and then expose the main channel of that as the Socket for the
primary connection'. (Which of course you can already do by spawning
'plink -nc' as a separate proxy process, but this would permit it in
the _same_ process without anything getting confused.)
I've centralised a full set of stub methods in misc.c for the new
abstraction, which allows me to get rid of several annoying stubs in
the previous code. Also, while I'm here, I've moved a lot of
duplicated modalfatalbox() type functions from application main
program files into wincons.c / uxcons.c, which I think saves
duplication overall. (A minor visible effect is that the prefixes on
those console-based fatal error messages will now be more consistent
between applications.)
2018-10-11 18:58:42 +00:00
|
|
|
register_dialog(seat, DIALOG_SLOT_NETWORK_PROMPT, msgbox);
|
2003-03-31 11:21:07 +00:00
|
|
|
|
Centralise most details of host-key prompting.
The text of the host key warnings was replicated in three places: the
Windows rc file, the GTK dialog setup function, and the console.c
shared between both platforms' CLI tools. Now it lives in just one
place, namely ssh/common.c where the rest of the centralised host-key
checking is done, so it'll be easier to adjust the wording in future.
This comes with some extra automation. Paragraph wrapping is no longer
done by hand in any version of these prompts. (Previously we let GTK
do the wrapping on GTK, but on Windows the resource file contained a
bunch of pre-wrapped LTEXT lines, and console.c had pre-wrapped
terminal messages.) And the dialog heights in Windows are determined
automatically based on the amount of stuff in the window.
The main idea of all this is that it'll be easier to set up more
elaborate kinds of host key prompt that deal with certificates (if,
e.g., a server sends us a certified host key which we don't trust the
CA for). But there are side benefits of this refactoring too: each
tool now reliably inserts its own appname in the prompts, and also, on
Windows the entire prompt text is copy-pastable.
Details of implementation: there's a new type SeatDialogText which
holds a set of (type, string) pairs describing the contents of a
prompt. Type codes distinguish ordinary text paragraphs, paragraphs to
be displayed prominently (like key fingerprints), the extra-bold scary
title at the top of the 'host key changed' version of the dialog, and
the various information that lives in the subsidiary 'more info' box.
ssh/common.c constructs this, and passes it to the Seat to present the
actual prompt.
In order to deal with the different UI for answering the prompt, I've
added an extra Seat method 'prompt_descriptions' which returns some
snippets of text to interpolate into the messages. ssh/common.c calls
that while it's still constructing the text, and incorporates the
resulting snippets into the SeatDialogText.
For the moment, this refactoring only affects the host key prompts.
The warnings about outmoded crypto are still done the old-fashioned
way; they probably ought to be similarly refactored to use this new
SeatDialogText system, but it's not immediately critical for the
purpose I have right now.
2022-07-07 16:25:15 +00:00
|
|
|
strbuf_free(dlg_text);
|
2003-03-31 11:21:07 +00:00
|
|
|
|
Richer data type for interactive prompt results.
All the seat functions that request an interactive prompt of some kind
to the user - both the main seat_get_userpass_input and the various
confirmation dialogs for things like host keys - were using a simple
int return value, with the general semantics of 0 = "fail", 1 =
"proceed" (and in the case of seat_get_userpass_input, answers to the
prompts were provided), and -1 = "request in progress, wait for a
callback".
In this commit I change all those functions' return types to a new
struct called SeatPromptResult, whose primary field is an enum
replacing those simple integer values.
The main purpose is that the enum has not three but _four_ values: the
"fail" result has been split into 'user abort' and 'software abort'.
The distinction is that a user abort occurs as a result of an
interactive UI action, such as the user clicking 'cancel' in a dialog
box or hitting ^D or ^C at a terminal password prompt - and therefore,
there's no need to display an error message telling the user that the
interactive operation has failed, because the user already knows,
because they _did_ it. 'Software abort' is from any other cause, where
PuTTY is the first to know there was a problem, and has to tell the
user.
We already had this 'user abort' vs 'software abort' distinction in
other parts of the code - the SSH backend has separate termination
functions which protocol layers can call. But we assumed that any
failure from an interactive prompt request fell into the 'user abort'
category, which is not true. A couple of examples: if you configure a
host key fingerprint in your saved session via the SSH > Host keys
pane, and the server presents a host key that doesn't match it, then
verify_ssh_host_key would report that the user had aborted the
connection, and feel no need to tell the user what had gone wrong!
Similarly, if a password provided on the command line was not
accepted, then (after I fixed the semantics of that in the previous
commit) the same wrong handling would occur.
So now, those Seat prompt functions too can communicate whether the
user or the software originated a connection abort. And in the latter
case, we also provide an error message to present to the user. Result:
in those two example cases (and others), error messages should no
longer go missing.
Implementation note: to avoid the hassle of having the error message
in a SeatPromptResult being a dynamically allocated string (and hence,
every recipient of one must always check whether it's non-NULL and
free it on every exit path, plus being careful about copying the
struct around), I've instead arranged that the structure contains a
function pointer and a couple of parameters, so that the string form
of the message can be constructed on demand. That way, the only users
who need to free it are the ones who actually _asked_ for it in the
first place, which is a much smaller set.
(This is one of the rare occasions that I regret not having C++'s
extra features available in this code base - a unique_ptr or
shared_ptr to a string would have been just the thing here, and the
compiler would have done all the hard work for me of remembering where
to insert the frees!)
2021-12-28 17:52:00 +00:00
|
|
|
return SPR_INCOMPLETE; /* dialog still in progress */
|
2003-03-13 19:52:28 +00:00
|
|
|
}
|
|
|
|
|
Richer data type for interactive prompt results.
All the seat functions that request an interactive prompt of some kind
to the user - both the main seat_get_userpass_input and the various
confirmation dialogs for things like host keys - were using a simple
int return value, with the general semantics of 0 = "fail", 1 =
"proceed" (and in the case of seat_get_userpass_input, answers to the
prompts were provided), and -1 = "request in progress, wait for a
callback".
In this commit I change all those functions' return types to a new
struct called SeatPromptResult, whose primary field is an enum
replacing those simple integer values.
The main purpose is that the enum has not three but _four_ values: the
"fail" result has been split into 'user abort' and 'software abort'.
The distinction is that a user abort occurs as a result of an
interactive UI action, such as the user clicking 'cancel' in a dialog
box or hitting ^D or ^C at a terminal password prompt - and therefore,
there's no need to display an error message telling the user that the
interactive operation has failed, because the user already knows,
because they _did_ it. 'Software abort' is from any other cause, where
PuTTY is the first to know there was a problem, and has to tell the
user.
We already had this 'user abort' vs 'software abort' distinction in
other parts of the code - the SSH backend has separate termination
functions which protocol layers can call. But we assumed that any
failure from an interactive prompt request fell into the 'user abort'
category, which is not true. A couple of examples: if you configure a
host key fingerprint in your saved session via the SSH > Host keys
pane, and the server presents a host key that doesn't match it, then
verify_ssh_host_key would report that the user had aborted the
connection, and feel no need to tell the user what had gone wrong!
Similarly, if a password provided on the command line was not
accepted, then (after I fixed the semantics of that in the previous
commit) the same wrong handling would occur.
So now, those Seat prompt functions too can communicate whether the
user or the software originated a connection abort. And in the latter
case, we also provide an error message to present to the user. Result:
in those two example cases (and others), error messages should no
longer go missing.
Implementation note: to avoid the hassle of having the error message
in a SeatPromptResult being a dynamically allocated string (and hence,
every recipient of one must always check whether it's non-NULL and
free it on every exit path, plus being careful about copying the
struct around), I've instead arranged that the structure contains a
function pointer and a couple of parameters, so that the string form
of the message can be constructed on demand. That way, the only users
who need to free it are the ones who actually _asked_ for it in the
first place, which is a much smaller set.
(This is one of the rare occasions that I regret not having C++'s
extra features available in this code base - a unique_ptr or
shared_ptr to a string would have been just the thing here, and the
compiler would have done all the hard work for me of remembering where
to insert the frees!)
2021-12-28 17:52:00 +00:00
|
|
|
struct simple_prompt_result_spr_ctx {
|
|
|
|
void (*callback)(void *callback_ctx, SeatPromptResult spr);
|
2017-11-26 15:13:08 +00:00
|
|
|
void *callback_ctx;
|
New abstraction 'Seat', to pass to backends.
This is a new vtable-based abstraction which is passed to a backend in
place of Frontend, and it implements only the subset of the Frontend
functions needed by a backend. (Many other Frontend functions still
exist, notably the wide range of things called by terminal.c providing
platform-independent operations on the GUI terminal window.)
The purpose of making it a vtable is that this opens up the
possibility of creating a backend as an internal implementation detail
of some other activity, by providing just that one backend with a
custom Seat that implements the methods differently.
For example, this refactoring should make it feasible to directly
implement an SSH proxy type, aka the 'jump host' feature supported by
OpenSSH, aka 'open a secondary SSH session in MAINCHAN_DIRECT_TCP
mode, and then expose the main channel of that as the Socket for the
primary connection'. (Which of course you can already do by spawning
'plink -nc' as a separate proxy process, but this would permit it in
the _same_ process without anything getting confused.)
I've centralised a full set of stub methods in misc.c for the new
abstraction, which allows me to get rid of several annoying stubs in
the previous code. Also, while I'm here, I've moved a lot of
duplicated modalfatalbox() type functions from application main
program files into wincons.c / uxcons.c, which I think saves
duplication overall. (A minor visible effect is that the prefixes on
those console-based fatal error messages will now be more consistent
between applications.)
2018-10-11 18:58:42 +00:00
|
|
|
Seat *seat;
|
2017-11-26 16:56:03 +00:00
|
|
|
enum DialogSlot dialog_slot;
|
2017-11-26 15:13:08 +00:00
|
|
|
};
|
|
|
|
|
Richer data type for interactive prompt results.
All the seat functions that request an interactive prompt of some kind
to the user - both the main seat_get_userpass_input and the various
confirmation dialogs for things like host keys - were using a simple
int return value, with the general semantics of 0 = "fail", 1 =
"proceed" (and in the case of seat_get_userpass_input, answers to the
prompts were provided), and -1 = "request in progress, wait for a
callback".
In this commit I change all those functions' return types to a new
struct called SeatPromptResult, whose primary field is an enum
replacing those simple integer values.
The main purpose is that the enum has not three but _four_ values: the
"fail" result has been split into 'user abort' and 'software abort'.
The distinction is that a user abort occurs as a result of an
interactive UI action, such as the user clicking 'cancel' in a dialog
box or hitting ^D or ^C at a terminal password prompt - and therefore,
there's no need to display an error message telling the user that the
interactive operation has failed, because the user already knows,
because they _did_ it. 'Software abort' is from any other cause, where
PuTTY is the first to know there was a problem, and has to tell the
user.
We already had this 'user abort' vs 'software abort' distinction in
other parts of the code - the SSH backend has separate termination
functions which protocol layers can call. But we assumed that any
failure from an interactive prompt request fell into the 'user abort'
category, which is not true. A couple of examples: if you configure a
host key fingerprint in your saved session via the SSH > Host keys
pane, and the server presents a host key that doesn't match it, then
verify_ssh_host_key would report that the user had aborted the
connection, and feel no need to tell the user what had gone wrong!
Similarly, if a password provided on the command line was not
accepted, then (after I fixed the semantics of that in the previous
commit) the same wrong handling would occur.
So now, those Seat prompt functions too can communicate whether the
user or the software originated a connection abort. And in the latter
case, we also provide an error message to present to the user. Result:
in those two example cases (and others), error messages should no
longer go missing.
Implementation note: to avoid the hassle of having the error message
in a SeatPromptResult being a dynamically allocated string (and hence,
every recipient of one must always check whether it's non-NULL and
free it on every exit path, plus being careful about copying the
struct around), I've instead arranged that the structure contains a
function pointer and a couple of parameters, so that the string form
of the message can be constructed on demand. That way, the only users
who need to free it are the ones who actually _asked_ for it in the
first place, which is a much smaller set.
(This is one of the rare occasions that I regret not having C++'s
extra features available in this code base - a unique_ptr or
shared_ptr to a string would have been just the thing here, and the
compiler would have done all the hard work for me of remembering where
to insert the frees!)
2021-12-28 17:52:00 +00:00
|
|
|
static void simple_prompt_result_spr_callback(void *vctx, int result)
|
2017-11-26 15:13:08 +00:00
|
|
|
{
|
Richer data type for interactive prompt results.
All the seat functions that request an interactive prompt of some kind
to the user - both the main seat_get_userpass_input and the various
confirmation dialogs for things like host keys - were using a simple
int return value, with the general semantics of 0 = "fail", 1 =
"proceed" (and in the case of seat_get_userpass_input, answers to the
prompts were provided), and -1 = "request in progress, wait for a
callback".
In this commit I change all those functions' return types to a new
struct called SeatPromptResult, whose primary field is an enum
replacing those simple integer values.
The main purpose is that the enum has not three but _four_ values: the
"fail" result has been split into 'user abort' and 'software abort'.
The distinction is that a user abort occurs as a result of an
interactive UI action, such as the user clicking 'cancel' in a dialog
box or hitting ^D or ^C at a terminal password prompt - and therefore,
there's no need to display an error message telling the user that the
interactive operation has failed, because the user already knows,
because they _did_ it. 'Software abort' is from any other cause, where
PuTTY is the first to know there was a problem, and has to tell the
user.
We already had this 'user abort' vs 'software abort' distinction in
other parts of the code - the SSH backend has separate termination
functions which protocol layers can call. But we assumed that any
failure from an interactive prompt request fell into the 'user abort'
category, which is not true. A couple of examples: if you configure a
host key fingerprint in your saved session via the SSH > Host keys
pane, and the server presents a host key that doesn't match it, then
verify_ssh_host_key would report that the user had aborted the
connection, and feel no need to tell the user what had gone wrong!
Similarly, if a password provided on the command line was not
accepted, then (after I fixed the semantics of that in the previous
commit) the same wrong handling would occur.
So now, those Seat prompt functions too can communicate whether the
user or the software originated a connection abort. And in the latter
case, we also provide an error message to present to the user. Result:
in those two example cases (and others), error messages should no
longer go missing.
Implementation note: to avoid the hassle of having the error message
in a SeatPromptResult being a dynamically allocated string (and hence,
every recipient of one must always check whether it's non-NULL and
free it on every exit path, plus being careful about copying the
struct around), I've instead arranged that the structure contains a
function pointer and a couple of parameters, so that the string form
of the message can be constructed on demand. That way, the only users
who need to free it are the ones who actually _asked_ for it in the
first place, which is a much smaller set.
(This is one of the rare occasions that I regret not having C++'s
extra features available in this code base - a unique_ptr or
shared_ptr to a string would have been just the thing here, and the
compiler would have done all the hard work for me of remembering where
to insert the frees!)
2021-12-28 17:52:00 +00:00
|
|
|
struct simple_prompt_result_spr_ctx *ctx =
|
|
|
|
(struct simple_prompt_result_spr_ctx *)vctx;
|
2017-11-26 15:13:08 +00:00
|
|
|
|
2019-01-13 17:14:08 +00:00
|
|
|
unregister_dialog(ctx->seat, ctx->dialog_slot);
|
|
|
|
|
Richer data type for interactive prompt results.
All the seat functions that request an interactive prompt of some kind
to the user - both the main seat_get_userpass_input and the various
confirmation dialogs for things like host keys - were using a simple
int return value, with the general semantics of 0 = "fail", 1 =
"proceed" (and in the case of seat_get_userpass_input, answers to the
prompts were provided), and -1 = "request in progress, wait for a
callback".
In this commit I change all those functions' return types to a new
struct called SeatPromptResult, whose primary field is an enum
replacing those simple integer values.
The main purpose is that the enum has not three but _four_ values: the
"fail" result has been split into 'user abort' and 'software abort'.
The distinction is that a user abort occurs as a result of an
interactive UI action, such as the user clicking 'cancel' in a dialog
box or hitting ^D or ^C at a terminal password prompt - and therefore,
there's no need to display an error message telling the user that the
interactive operation has failed, because the user already knows,
because they _did_ it. 'Software abort' is from any other cause, where
PuTTY is the first to know there was a problem, and has to tell the
user.
We already had this 'user abort' vs 'software abort' distinction in
other parts of the code - the SSH backend has separate termination
functions which protocol layers can call. But we assumed that any
failure from an interactive prompt request fell into the 'user abort'
category, which is not true. A couple of examples: if you configure a
host key fingerprint in your saved session via the SSH > Host keys
pane, and the server presents a host key that doesn't match it, then
verify_ssh_host_key would report that the user had aborted the
connection, and feel no need to tell the user what had gone wrong!
Similarly, if a password provided on the command line was not
accepted, then (after I fixed the semantics of that in the previous
commit) the same wrong handling would occur.
So now, those Seat prompt functions too can communicate whether the
user or the software originated a connection abort. And in the latter
case, we also provide an error message to present to the user. Result:
in those two example cases (and others), error messages should no
longer go missing.
Implementation note: to avoid the hassle of having the error message
in a SeatPromptResult being a dynamically allocated string (and hence,
every recipient of one must always check whether it's non-NULL and
free it on every exit path, plus being careful about copying the
struct around), I've instead arranged that the structure contains a
function pointer and a couple of parameters, so that the string form
of the message can be constructed on demand. That way, the only users
who need to free it are the ones who actually _asked_ for it in the
first place, which is a much smaller set.
(This is one of the rare occasions that I regret not having C++'s
extra features available in this code base - a unique_ptr or
shared_ptr to a string would have been just the thing here, and the
compiler would have done all the hard work for me of remembering where
to insert the frees!)
2021-12-28 17:52:00 +00:00
|
|
|
if (result == 0)
|
|
|
|
ctx->callback(ctx->callback_ctx, SPR_USER_ABORT);
|
|
|
|
else if (result > 0)
|
|
|
|
ctx->callback(ctx->callback_ctx, SPR_OK);
|
|
|
|
/* if <0, we're cleaning up for some other reason */
|
2017-11-26 15:13:08 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Clean up this context structure, whether or not a result was
|
|
|
|
* ever actually delivered from the dialog box.
|
|
|
|
*/
|
|
|
|
sfree(ctx);
|
|
|
|
}
|
|
|
|
|
2003-03-31 11:21:07 +00:00
|
|
|
/*
|
2004-12-23 02:24:07 +00:00
|
|
|
* Ask whether the selected algorithm is acceptable (since it was
|
2003-03-31 11:21:07 +00:00
|
|
|
* below the configured 'warn' threshold).
|
|
|
|
*/
|
Richer data type for interactive prompt results.
All the seat functions that request an interactive prompt of some kind
to the user - both the main seat_get_userpass_input and the various
confirmation dialogs for things like host keys - were using a simple
int return value, with the general semantics of 0 = "fail", 1 =
"proceed" (and in the case of seat_get_userpass_input, answers to the
prompts were provided), and -1 = "request in progress, wait for a
callback".
In this commit I change all those functions' return types to a new
struct called SeatPromptResult, whose primary field is an enum
replacing those simple integer values.
The main purpose is that the enum has not three but _four_ values: the
"fail" result has been split into 'user abort' and 'software abort'.
The distinction is that a user abort occurs as a result of an
interactive UI action, such as the user clicking 'cancel' in a dialog
box or hitting ^D or ^C at a terminal password prompt - and therefore,
there's no need to display an error message telling the user that the
interactive operation has failed, because the user already knows,
because they _did_ it. 'Software abort' is from any other cause, where
PuTTY is the first to know there was a problem, and has to tell the
user.
We already had this 'user abort' vs 'software abort' distinction in
other parts of the code - the SSH backend has separate termination
functions which protocol layers can call. But we assumed that any
failure from an interactive prompt request fell into the 'user abort'
category, which is not true. A couple of examples: if you configure a
host key fingerprint in your saved session via the SSH > Host keys
pane, and the server presents a host key that doesn't match it, then
verify_ssh_host_key would report that the user had aborted the
connection, and feel no need to tell the user what had gone wrong!
Similarly, if a password provided on the command line was not
accepted, then (after I fixed the semantics of that in the previous
commit) the same wrong handling would occur.
So now, those Seat prompt functions too can communicate whether the
user or the software originated a connection abort. And in the latter
case, we also provide an error message to present to the user. Result:
in those two example cases (and others), error messages should no
longer go missing.
Implementation note: to avoid the hassle of having the error message
in a SeatPromptResult being a dynamically allocated string (and hence,
every recipient of one must always check whether it's non-NULL and
free it on every exit path, plus being careful about copying the
struct around), I've instead arranged that the structure contains a
function pointer and a couple of parameters, so that the string form
of the message can be constructed on demand. That way, the only users
who need to free it are the ones who actually _asked_ for it in the
first place, which is a much smaller set.
(This is one of the rare occasions that I regret not having C++'s
extra features available in this code base - a unique_ptr or
shared_ptr to a string would have been just the thing here, and the
compiler would have done all the hard work for me of remembering where
to insert the frees!)
2021-12-28 17:52:00 +00:00
|
|
|
SeatPromptResult gtk_seat_confirm_weak_crypto_primitive(
|
2023-11-22 08:57:54 +00:00
|
|
|
Seat *seat, SeatDialogText *text,
|
Richer data type for interactive prompt results.
All the seat functions that request an interactive prompt of some kind
to the user - both the main seat_get_userpass_input and the various
confirmation dialogs for things like host keys - were using a simple
int return value, with the general semantics of 0 = "fail", 1 =
"proceed" (and in the case of seat_get_userpass_input, answers to the
prompts were provided), and -1 = "request in progress, wait for a
callback".
In this commit I change all those functions' return types to a new
struct called SeatPromptResult, whose primary field is an enum
replacing those simple integer values.
The main purpose is that the enum has not three but _four_ values: the
"fail" result has been split into 'user abort' and 'software abort'.
The distinction is that a user abort occurs as a result of an
interactive UI action, such as the user clicking 'cancel' in a dialog
box or hitting ^D or ^C at a terminal password prompt - and therefore,
there's no need to display an error message telling the user that the
interactive operation has failed, because the user already knows,
because they _did_ it. 'Software abort' is from any other cause, where
PuTTY is the first to know there was a problem, and has to tell the
user.
We already had this 'user abort' vs 'software abort' distinction in
other parts of the code - the SSH backend has separate termination
functions which protocol layers can call. But we assumed that any
failure from an interactive prompt request fell into the 'user abort'
category, which is not true. A couple of examples: if you configure a
host key fingerprint in your saved session via the SSH > Host keys
pane, and the server presents a host key that doesn't match it, then
verify_ssh_host_key would report that the user had aborted the
connection, and feel no need to tell the user what had gone wrong!
Similarly, if a password provided on the command line was not
accepted, then (after I fixed the semantics of that in the previous
commit) the same wrong handling would occur.
So now, those Seat prompt functions too can communicate whether the
user or the software originated a connection abort. And in the latter
case, we also provide an error message to present to the user. Result:
in those two example cases (and others), error messages should no
longer go missing.
Implementation note: to avoid the hassle of having the error message
in a SeatPromptResult being a dynamically allocated string (and hence,
every recipient of one must always check whether it's non-NULL and
free it on every exit path, plus being careful about copying the
struct around), I've instead arranged that the structure contains a
function pointer and a couple of parameters, so that the string form
of the message can be constructed on demand. That way, the only users
who need to free it are the ones who actually _asked_ for it in the
first place, which is a much smaller set.
(This is one of the rare occasions that I regret not having C++'s
extra features available in this code base - a unique_ptr or
shared_ptr to a string would have been just the thing here, and the
compiler would have done all the hard work for me of remembering where
to insert the frees!)
2021-12-28 17:52:00 +00:00
|
|
|
void (*callback)(void *ctx, SeatPromptResult result), void *ctx)
|
2003-03-31 11:21:07 +00:00
|
|
|
{
|
Richer data type for interactive prompt results.
All the seat functions that request an interactive prompt of some kind
to the user - both the main seat_get_userpass_input and the various
confirmation dialogs for things like host keys - were using a simple
int return value, with the general semantics of 0 = "fail", 1 =
"proceed" (and in the case of seat_get_userpass_input, answers to the
prompts were provided), and -1 = "request in progress, wait for a
callback".
In this commit I change all those functions' return types to a new
struct called SeatPromptResult, whose primary field is an enum
replacing those simple integer values.
The main purpose is that the enum has not three but _four_ values: the
"fail" result has been split into 'user abort' and 'software abort'.
The distinction is that a user abort occurs as a result of an
interactive UI action, such as the user clicking 'cancel' in a dialog
box or hitting ^D or ^C at a terminal password prompt - and therefore,
there's no need to display an error message telling the user that the
interactive operation has failed, because the user already knows,
because they _did_ it. 'Software abort' is from any other cause, where
PuTTY is the first to know there was a problem, and has to tell the
user.
We already had this 'user abort' vs 'software abort' distinction in
other parts of the code - the SSH backend has separate termination
functions which protocol layers can call. But we assumed that any
failure from an interactive prompt request fell into the 'user abort'
category, which is not true. A couple of examples: if you configure a
host key fingerprint in your saved session via the SSH > Host keys
pane, and the server presents a host key that doesn't match it, then
verify_ssh_host_key would report that the user had aborted the
connection, and feel no need to tell the user what had gone wrong!
Similarly, if a password provided on the command line was not
accepted, then (after I fixed the semantics of that in the previous
commit) the same wrong handling would occur.
So now, those Seat prompt functions too can communicate whether the
user or the software originated a connection abort. And in the latter
case, we also provide an error message to present to the user. Result:
in those two example cases (and others), error messages should no
longer go missing.
Implementation note: to avoid the hassle of having the error message
in a SeatPromptResult being a dynamically allocated string (and hence,
every recipient of one must always check whether it's non-NULL and
free it on every exit path, plus being careful about copying the
struct around), I've instead arranged that the structure contains a
function pointer and a couple of parameters, so that the string form
of the message can be constructed on demand. That way, the only users
who need to free it are the ones who actually _asked_ for it in the
first place, which is a much smaller set.
(This is one of the rare occasions that I regret not having C++'s
extra features available in this code base - a unique_ptr or
shared_ptr to a string would have been just the thing here, and the
compiler would have done all the hard work for me of remembering where
to insert the frees!)
2021-12-28 17:52:00 +00:00
|
|
|
struct simple_prompt_result_spr_ctx *result_ctx;
|
2017-11-26 15:13:08 +00:00
|
|
|
GtkWidget *mainwin, *msgbox;
|
2003-03-31 11:21:07 +00:00
|
|
|
|
2023-11-22 08:57:54 +00:00
|
|
|
int width = string_width("Reasonably long line of text "
|
|
|
|
"as a width template");
|
|
|
|
strbuf *dlg_text = strbuf_new();
|
|
|
|
const char *dlg_title = gtk_format_seatdialogtext(text, dlg_text, &width);
|
2017-11-26 15:13:08 +00:00
|
|
|
|
Richer data type for interactive prompt results.
All the seat functions that request an interactive prompt of some kind
to the user - both the main seat_get_userpass_input and the various
confirmation dialogs for things like host keys - were using a simple
int return value, with the general semantics of 0 = "fail", 1 =
"proceed" (and in the case of seat_get_userpass_input, answers to the
prompts were provided), and -1 = "request in progress, wait for a
callback".
In this commit I change all those functions' return types to a new
struct called SeatPromptResult, whose primary field is an enum
replacing those simple integer values.
The main purpose is that the enum has not three but _four_ values: the
"fail" result has been split into 'user abort' and 'software abort'.
The distinction is that a user abort occurs as a result of an
interactive UI action, such as the user clicking 'cancel' in a dialog
box or hitting ^D or ^C at a terminal password prompt - and therefore,
there's no need to display an error message telling the user that the
interactive operation has failed, because the user already knows,
because they _did_ it. 'Software abort' is from any other cause, where
PuTTY is the first to know there was a problem, and has to tell the
user.
We already had this 'user abort' vs 'software abort' distinction in
other parts of the code - the SSH backend has separate termination
functions which protocol layers can call. But we assumed that any
failure from an interactive prompt request fell into the 'user abort'
category, which is not true. A couple of examples: if you configure a
host key fingerprint in your saved session via the SSH > Host keys
pane, and the server presents a host key that doesn't match it, then
verify_ssh_host_key would report that the user had aborted the
connection, and feel no need to tell the user what had gone wrong!
Similarly, if a password provided on the command line was not
accepted, then (after I fixed the semantics of that in the previous
commit) the same wrong handling would occur.
So now, those Seat prompt functions too can communicate whether the
user or the software originated a connection abort. And in the latter
case, we also provide an error message to present to the user. Result:
in those two example cases (and others), error messages should no
longer go missing.
Implementation note: to avoid the hassle of having the error message
in a SeatPromptResult being a dynamically allocated string (and hence,
every recipient of one must always check whether it's non-NULL and
free it on every exit path, plus being careful about copying the
struct around), I've instead arranged that the structure contains a
function pointer and a couple of parameters, so that the string form
of the message can be constructed on demand. That way, the only users
who need to free it are the ones who actually _asked_ for it in the
first place, which is a much smaller set.
(This is one of the rare occasions that I regret not having C++'s
extra features available in this code base - a unique_ptr or
shared_ptr to a string would have been just the thing here, and the
compiler would have done all the hard work for me of remembering where
to insert the frees!)
2021-12-28 17:52:00 +00:00
|
|
|
result_ctx = snew(struct simple_prompt_result_spr_ctx);
|
2017-11-26 15:13:08 +00:00
|
|
|
result_ctx->callback = callback;
|
|
|
|
result_ctx->callback_ctx = ctx;
|
New abstraction 'Seat', to pass to backends.
This is a new vtable-based abstraction which is passed to a backend in
place of Frontend, and it implements only the subset of the Frontend
functions needed by a backend. (Many other Frontend functions still
exist, notably the wide range of things called by terminal.c providing
platform-independent operations on the GUI terminal window.)
The purpose of making it a vtable is that this opens up the
possibility of creating a backend as an internal implementation detail
of some other activity, by providing just that one backend with a
custom Seat that implements the methods differently.
For example, this refactoring should make it feasible to directly
implement an SSH proxy type, aka the 'jump host' feature supported by
OpenSSH, aka 'open a secondary SSH session in MAINCHAN_DIRECT_TCP
mode, and then expose the main channel of that as the Socket for the
primary connection'. (Which of course you can already do by spawning
'plink -nc' as a separate proxy process, but this would permit it in
the _same_ process without anything getting confused.)
I've centralised a full set of stub methods in misc.c for the new
abstraction, which allows me to get rid of several annoying stubs in
the previous code. Also, while I'm here, I've moved a lot of
duplicated modalfatalbox() type functions from application main
program files into wincons.c / uxcons.c, which I think saves
duplication overall. (A minor visible effect is that the prefixes on
those console-based fatal error messages will now be more consistent
between applications.)
2018-10-11 18:58:42 +00:00
|
|
|
result_ctx->seat = seat;
|
2017-11-26 16:56:03 +00:00
|
|
|
result_ctx->dialog_slot = DIALOG_SLOT_NETWORK_PROMPT;
|
2017-11-26 15:13:08 +00:00
|
|
|
|
New abstraction 'Seat', to pass to backends.
This is a new vtable-based abstraction which is passed to a backend in
place of Frontend, and it implements only the subset of the Frontend
functions needed by a backend. (Many other Frontend functions still
exist, notably the wide range of things called by terminal.c providing
platform-independent operations on the GUI terminal window.)
The purpose of making it a vtable is that this opens up the
possibility of creating a backend as an internal implementation detail
of some other activity, by providing just that one backend with a
custom Seat that implements the methods differently.
For example, this refactoring should make it feasible to directly
implement an SSH proxy type, aka the 'jump host' feature supported by
OpenSSH, aka 'open a secondary SSH session in MAINCHAN_DIRECT_TCP
mode, and then expose the main channel of that as the Socket for the
primary connection'. (Which of course you can already do by spawning
'plink -nc' as a separate proxy process, but this would permit it in
the _same_ process without anything getting confused.)
I've centralised a full set of stub methods in misc.c for the new
abstraction, which allows me to get rid of several annoying stubs in
the previous code. Also, while I'm here, I've moved a lot of
duplicated modalfatalbox() type functions from application main
program files into wincons.c / uxcons.c, which I think saves
duplication overall. (A minor visible effect is that the prefixes on
those console-based fatal error messages will now be more consistent
between applications.)
2018-10-11 18:58:42 +00:00
|
|
|
mainwin = GTK_WIDGET(gtk_seat_get_window(seat));
|
2017-11-26 15:13:08 +00:00
|
|
|
msgbox = create_message_box(
|
2023-11-22 08:57:54 +00:00
|
|
|
mainwin, dlg_title, dlg_text->s, width, false,
|
|
|
|
&buttons_yn, simple_prompt_result_spr_callback, result_ctx);
|
New abstraction 'Seat', to pass to backends.
This is a new vtable-based abstraction which is passed to a backend in
place of Frontend, and it implements only the subset of the Frontend
functions needed by a backend. (Many other Frontend functions still
exist, notably the wide range of things called by terminal.c providing
platform-independent operations on the GUI terminal window.)
The purpose of making it a vtable is that this opens up the
possibility of creating a backend as an internal implementation detail
of some other activity, by providing just that one backend with a
custom Seat that implements the methods differently.
For example, this refactoring should make it feasible to directly
implement an SSH proxy type, aka the 'jump host' feature supported by
OpenSSH, aka 'open a secondary SSH session in MAINCHAN_DIRECT_TCP
mode, and then expose the main channel of that as the Socket for the
primary connection'. (Which of course you can already do by spawning
'plink -nc' as a separate proxy process, but this would permit it in
the _same_ process without anything getting confused.)
I've centralised a full set of stub methods in misc.c for the new
abstraction, which allows me to get rid of several annoying stubs in
the previous code. Also, while I'm here, I've moved a lot of
duplicated modalfatalbox() type functions from application main
program files into wincons.c / uxcons.c, which I think saves
duplication overall. (A minor visible effect is that the prefixes on
those console-based fatal error messages will now be more consistent
between applications.)
2018-10-11 18:58:42 +00:00
|
|
|
register_dialog(seat, result_ctx->dialog_slot, msgbox);
|
2017-11-26 15:13:08 +00:00
|
|
|
|
2023-11-22 08:57:54 +00:00
|
|
|
strbuf_free(dlg_text);
|
2016-03-27 17:08:49 +00:00
|
|
|
|
Richer data type for interactive prompt results.
All the seat functions that request an interactive prompt of some kind
to the user - both the main seat_get_userpass_input and the various
confirmation dialogs for things like host keys - were using a simple
int return value, with the general semantics of 0 = "fail", 1 =
"proceed" (and in the case of seat_get_userpass_input, answers to the
prompts were provided), and -1 = "request in progress, wait for a
callback".
In this commit I change all those functions' return types to a new
struct called SeatPromptResult, whose primary field is an enum
replacing those simple integer values.
The main purpose is that the enum has not three but _four_ values: the
"fail" result has been split into 'user abort' and 'software abort'.
The distinction is that a user abort occurs as a result of an
interactive UI action, such as the user clicking 'cancel' in a dialog
box or hitting ^D or ^C at a terminal password prompt - and therefore,
there's no need to display an error message telling the user that the
interactive operation has failed, because the user already knows,
because they _did_ it. 'Software abort' is from any other cause, where
PuTTY is the first to know there was a problem, and has to tell the
user.
We already had this 'user abort' vs 'software abort' distinction in
other parts of the code - the SSH backend has separate termination
functions which protocol layers can call. But we assumed that any
failure from an interactive prompt request fell into the 'user abort'
category, which is not true. A couple of examples: if you configure a
host key fingerprint in your saved session via the SSH > Host keys
pane, and the server presents a host key that doesn't match it, then
verify_ssh_host_key would report that the user had aborted the
connection, and feel no need to tell the user what had gone wrong!
Similarly, if a password provided on the command line was not
accepted, then (after I fixed the semantics of that in the previous
commit) the same wrong handling would occur.
So now, those Seat prompt functions too can communicate whether the
user or the software originated a connection abort. And in the latter
case, we also provide an error message to present to the user. Result:
in those two example cases (and others), error messages should no
longer go missing.
Implementation note: to avoid the hassle of having the error message
in a SeatPromptResult being a dynamically allocated string (and hence,
every recipient of one must always check whether it's non-NULL and
free it on every exit path, plus being careful about copying the
struct around), I've instead arranged that the structure contains a
function pointer and a couple of parameters, so that the string form
of the message can be constructed on demand. That way, the only users
who need to free it are the ones who actually _asked_ for it in the
first place, which is a much smaller set.
(This is one of the rare occasions that I regret not having C++'s
extra features available in this code base - a unique_ptr or
shared_ptr to a string would have been just the thing here, and the
compiler would have done all the hard work for me of remembering where
to insert the frees!)
2021-12-28 17:52:00 +00:00
|
|
|
return SPR_INCOMPLETE;
|
2016-03-27 17:08:49 +00:00
|
|
|
}
|
|
|
|
|
Richer data type for interactive prompt results.
All the seat functions that request an interactive prompt of some kind
to the user - both the main seat_get_userpass_input and the various
confirmation dialogs for things like host keys - were using a simple
int return value, with the general semantics of 0 = "fail", 1 =
"proceed" (and in the case of seat_get_userpass_input, answers to the
prompts were provided), and -1 = "request in progress, wait for a
callback".
In this commit I change all those functions' return types to a new
struct called SeatPromptResult, whose primary field is an enum
replacing those simple integer values.
The main purpose is that the enum has not three but _four_ values: the
"fail" result has been split into 'user abort' and 'software abort'.
The distinction is that a user abort occurs as a result of an
interactive UI action, such as the user clicking 'cancel' in a dialog
box or hitting ^D or ^C at a terminal password prompt - and therefore,
there's no need to display an error message telling the user that the
interactive operation has failed, because the user already knows,
because they _did_ it. 'Software abort' is from any other cause, where
PuTTY is the first to know there was a problem, and has to tell the
user.
We already had this 'user abort' vs 'software abort' distinction in
other parts of the code - the SSH backend has separate termination
functions which protocol layers can call. But we assumed that any
failure from an interactive prompt request fell into the 'user abort'
category, which is not true. A couple of examples: if you configure a
host key fingerprint in your saved session via the SSH > Host keys
pane, and the server presents a host key that doesn't match it, then
verify_ssh_host_key would report that the user had aborted the
connection, and feel no need to tell the user what had gone wrong!
Similarly, if a password provided on the command line was not
accepted, then (after I fixed the semantics of that in the previous
commit) the same wrong handling would occur.
So now, those Seat prompt functions too can communicate whether the
user or the software originated a connection abort. And in the latter
case, we also provide an error message to present to the user. Result:
in those two example cases (and others), error messages should no
longer go missing.
Implementation note: to avoid the hassle of having the error message
in a SeatPromptResult being a dynamically allocated string (and hence,
every recipient of one must always check whether it's non-NULL and
free it on every exit path, plus being careful about copying the
struct around), I've instead arranged that the structure contains a
function pointer and a couple of parameters, so that the string form
of the message can be constructed on demand. That way, the only users
who need to free it are the ones who actually _asked_ for it in the
first place, which is a much smaller set.
(This is one of the rare occasions that I regret not having C++'s
extra features available in this code base - a unique_ptr or
shared_ptr to a string would have been just the thing here, and the
compiler would have done all the hard work for me of remembering where
to insert the frees!)
2021-12-28 17:52:00 +00:00
|
|
|
SeatPromptResult gtk_seat_confirm_weak_cached_hostkey(
|
2023-11-22 08:57:54 +00:00
|
|
|
Seat *seat, SeatDialogText *text,
|
Richer data type for interactive prompt results.
All the seat functions that request an interactive prompt of some kind
to the user - both the main seat_get_userpass_input and the various
confirmation dialogs for things like host keys - were using a simple
int return value, with the general semantics of 0 = "fail", 1 =
"proceed" (and in the case of seat_get_userpass_input, answers to the
prompts were provided), and -1 = "request in progress, wait for a
callback".
In this commit I change all those functions' return types to a new
struct called SeatPromptResult, whose primary field is an enum
replacing those simple integer values.
The main purpose is that the enum has not three but _four_ values: the
"fail" result has been split into 'user abort' and 'software abort'.
The distinction is that a user abort occurs as a result of an
interactive UI action, such as the user clicking 'cancel' in a dialog
box or hitting ^D or ^C at a terminal password prompt - and therefore,
there's no need to display an error message telling the user that the
interactive operation has failed, because the user already knows,
because they _did_ it. 'Software abort' is from any other cause, where
PuTTY is the first to know there was a problem, and has to tell the
user.
We already had this 'user abort' vs 'software abort' distinction in
other parts of the code - the SSH backend has separate termination
functions which protocol layers can call. But we assumed that any
failure from an interactive prompt request fell into the 'user abort'
category, which is not true. A couple of examples: if you configure a
host key fingerprint in your saved session via the SSH > Host keys
pane, and the server presents a host key that doesn't match it, then
verify_ssh_host_key would report that the user had aborted the
connection, and feel no need to tell the user what had gone wrong!
Similarly, if a password provided on the command line was not
accepted, then (after I fixed the semantics of that in the previous
commit) the same wrong handling would occur.
So now, those Seat prompt functions too can communicate whether the
user or the software originated a connection abort. And in the latter
case, we also provide an error message to present to the user. Result:
in those two example cases (and others), error messages should no
longer go missing.
Implementation note: to avoid the hassle of having the error message
in a SeatPromptResult being a dynamically allocated string (and hence,
every recipient of one must always check whether it's non-NULL and
free it on every exit path, plus being careful about copying the
struct around), I've instead arranged that the structure contains a
function pointer and a couple of parameters, so that the string form
of the message can be constructed on demand. That way, the only users
who need to free it are the ones who actually _asked_ for it in the
first place, which is a much smaller set.
(This is one of the rare occasions that I regret not having C++'s
extra features available in this code base - a unique_ptr or
shared_ptr to a string would have been just the thing here, and the
compiler would have done all the hard work for me of remembering where
to insert the frees!)
2021-12-28 17:52:00 +00:00
|
|
|
void (*callback)(void *ctx, SeatPromptResult result), void *ctx)
|
2016-03-27 17:08:49 +00:00
|
|
|
{
|
Richer data type for interactive prompt results.
All the seat functions that request an interactive prompt of some kind
to the user - both the main seat_get_userpass_input and the various
confirmation dialogs for things like host keys - were using a simple
int return value, with the general semantics of 0 = "fail", 1 =
"proceed" (and in the case of seat_get_userpass_input, answers to the
prompts were provided), and -1 = "request in progress, wait for a
callback".
In this commit I change all those functions' return types to a new
struct called SeatPromptResult, whose primary field is an enum
replacing those simple integer values.
The main purpose is that the enum has not three but _four_ values: the
"fail" result has been split into 'user abort' and 'software abort'.
The distinction is that a user abort occurs as a result of an
interactive UI action, such as the user clicking 'cancel' in a dialog
box or hitting ^D or ^C at a terminal password prompt - and therefore,
there's no need to display an error message telling the user that the
interactive operation has failed, because the user already knows,
because they _did_ it. 'Software abort' is from any other cause, where
PuTTY is the first to know there was a problem, and has to tell the
user.
We already had this 'user abort' vs 'software abort' distinction in
other parts of the code - the SSH backend has separate termination
functions which protocol layers can call. But we assumed that any
failure from an interactive prompt request fell into the 'user abort'
category, which is not true. A couple of examples: if you configure a
host key fingerprint in your saved session via the SSH > Host keys
pane, and the server presents a host key that doesn't match it, then
verify_ssh_host_key would report that the user had aborted the
connection, and feel no need to tell the user what had gone wrong!
Similarly, if a password provided on the command line was not
accepted, then (after I fixed the semantics of that in the previous
commit) the same wrong handling would occur.
So now, those Seat prompt functions too can communicate whether the
user or the software originated a connection abort. And in the latter
case, we also provide an error message to present to the user. Result:
in those two example cases (and others), error messages should no
longer go missing.
Implementation note: to avoid the hassle of having the error message
in a SeatPromptResult being a dynamically allocated string (and hence,
every recipient of one must always check whether it's non-NULL and
free it on every exit path, plus being careful about copying the
struct around), I've instead arranged that the structure contains a
function pointer and a couple of parameters, so that the string form
of the message can be constructed on demand. That way, the only users
who need to free it are the ones who actually _asked_ for it in the
first place, which is a much smaller set.
(This is one of the rare occasions that I regret not having C++'s
extra features available in this code base - a unique_ptr or
shared_ptr to a string would have been just the thing here, and the
compiler would have done all the hard work for me of remembering where
to insert the frees!)
2021-12-28 17:52:00 +00:00
|
|
|
struct simple_prompt_result_spr_ctx *result_ctx;
|
2017-11-26 15:13:08 +00:00
|
|
|
GtkWidget *mainwin, *msgbox;
|
2016-03-27 17:08:49 +00:00
|
|
|
|
2023-11-22 08:57:54 +00:00
|
|
|
int width = string_width("is ecdsa-nistp521, which is below the configured"
|
|
|
|
" warning threshold.");
|
|
|
|
strbuf *dlg_text = strbuf_new();
|
|
|
|
const char *dlg_title = gtk_format_seatdialogtext(text, dlg_text, &width);
|
2017-11-26 15:13:08 +00:00
|
|
|
|
Richer data type for interactive prompt results.
All the seat functions that request an interactive prompt of some kind
to the user - both the main seat_get_userpass_input and the various
confirmation dialogs for things like host keys - were using a simple
int return value, with the general semantics of 0 = "fail", 1 =
"proceed" (and in the case of seat_get_userpass_input, answers to the
prompts were provided), and -1 = "request in progress, wait for a
callback".
In this commit I change all those functions' return types to a new
struct called SeatPromptResult, whose primary field is an enum
replacing those simple integer values.
The main purpose is that the enum has not three but _four_ values: the
"fail" result has been split into 'user abort' and 'software abort'.
The distinction is that a user abort occurs as a result of an
interactive UI action, such as the user clicking 'cancel' in a dialog
box or hitting ^D or ^C at a terminal password prompt - and therefore,
there's no need to display an error message telling the user that the
interactive operation has failed, because the user already knows,
because they _did_ it. 'Software abort' is from any other cause, where
PuTTY is the first to know there was a problem, and has to tell the
user.
We already had this 'user abort' vs 'software abort' distinction in
other parts of the code - the SSH backend has separate termination
functions which protocol layers can call. But we assumed that any
failure from an interactive prompt request fell into the 'user abort'
category, which is not true. A couple of examples: if you configure a
host key fingerprint in your saved session via the SSH > Host keys
pane, and the server presents a host key that doesn't match it, then
verify_ssh_host_key would report that the user had aborted the
connection, and feel no need to tell the user what had gone wrong!
Similarly, if a password provided on the command line was not
accepted, then (after I fixed the semantics of that in the previous
commit) the same wrong handling would occur.
So now, those Seat prompt functions too can communicate whether the
user or the software originated a connection abort. And in the latter
case, we also provide an error message to present to the user. Result:
in those two example cases (and others), error messages should no
longer go missing.
Implementation note: to avoid the hassle of having the error message
in a SeatPromptResult being a dynamically allocated string (and hence,
every recipient of one must always check whether it's non-NULL and
free it on every exit path, plus being careful about copying the
struct around), I've instead arranged that the structure contains a
function pointer and a couple of parameters, so that the string form
of the message can be constructed on demand. That way, the only users
who need to free it are the ones who actually _asked_ for it in the
first place, which is a much smaller set.
(This is one of the rare occasions that I regret not having C++'s
extra features available in this code base - a unique_ptr or
shared_ptr to a string would have been just the thing here, and the
compiler would have done all the hard work for me of remembering where
to insert the frees!)
2021-12-28 17:52:00 +00:00
|
|
|
result_ctx = snew(struct simple_prompt_result_spr_ctx);
|
2017-11-26 15:13:08 +00:00
|
|
|
result_ctx->callback = callback;
|
|
|
|
result_ctx->callback_ctx = ctx;
|
New abstraction 'Seat', to pass to backends.
This is a new vtable-based abstraction which is passed to a backend in
place of Frontend, and it implements only the subset of the Frontend
functions needed by a backend. (Many other Frontend functions still
exist, notably the wide range of things called by terminal.c providing
platform-independent operations on the GUI terminal window.)
The purpose of making it a vtable is that this opens up the
possibility of creating a backend as an internal implementation detail
of some other activity, by providing just that one backend with a
custom Seat that implements the methods differently.
For example, this refactoring should make it feasible to directly
implement an SSH proxy type, aka the 'jump host' feature supported by
OpenSSH, aka 'open a secondary SSH session in MAINCHAN_DIRECT_TCP
mode, and then expose the main channel of that as the Socket for the
primary connection'. (Which of course you can already do by spawning
'plink -nc' as a separate proxy process, but this would permit it in
the _same_ process without anything getting confused.)
I've centralised a full set of stub methods in misc.c for the new
abstraction, which allows me to get rid of several annoying stubs in
the previous code. Also, while I'm here, I've moved a lot of
duplicated modalfatalbox() type functions from application main
program files into wincons.c / uxcons.c, which I think saves
duplication overall. (A minor visible effect is that the prefixes on
those console-based fatal error messages will now be more consistent
between applications.)
2018-10-11 18:58:42 +00:00
|
|
|
result_ctx->seat = seat;
|
2017-11-26 16:56:03 +00:00
|
|
|
result_ctx->dialog_slot = DIALOG_SLOT_NETWORK_PROMPT;
|
2017-11-26 15:13:08 +00:00
|
|
|
|
New abstraction 'Seat', to pass to backends.
This is a new vtable-based abstraction which is passed to a backend in
place of Frontend, and it implements only the subset of the Frontend
functions needed by a backend. (Many other Frontend functions still
exist, notably the wide range of things called by terminal.c providing
platform-independent operations on the GUI terminal window.)
The purpose of making it a vtable is that this opens up the
possibility of creating a backend as an internal implementation detail
of some other activity, by providing just that one backend with a
custom Seat that implements the methods differently.
For example, this refactoring should make it feasible to directly
implement an SSH proxy type, aka the 'jump host' feature supported by
OpenSSH, aka 'open a secondary SSH session in MAINCHAN_DIRECT_TCP
mode, and then expose the main channel of that as the Socket for the
primary connection'. (Which of course you can already do by spawning
'plink -nc' as a separate proxy process, but this would permit it in
the _same_ process without anything getting confused.)
I've centralised a full set of stub methods in misc.c for the new
abstraction, which allows me to get rid of several annoying stubs in
the previous code. Also, while I'm here, I've moved a lot of
duplicated modalfatalbox() type functions from application main
program files into wincons.c / uxcons.c, which I think saves
duplication overall. (A minor visible effect is that the prefixes on
those console-based fatal error messages will now be more consistent
between applications.)
2018-10-11 18:58:42 +00:00
|
|
|
mainwin = GTK_WIDGET(gtk_seat_get_window(seat));
|
2017-11-26 15:13:08 +00:00
|
|
|
msgbox = create_message_box(
|
2023-11-22 08:57:54 +00:00
|
|
|
mainwin, dlg_title, dlg_text->s, width, false,
|
|
|
|
&buttons_yn, simple_prompt_result_spr_callback, result_ctx);
|
New abstraction 'Seat', to pass to backends.
This is a new vtable-based abstraction which is passed to a backend in
place of Frontend, and it implements only the subset of the Frontend
functions needed by a backend. (Many other Frontend functions still
exist, notably the wide range of things called by terminal.c providing
platform-independent operations on the GUI terminal window.)
The purpose of making it a vtable is that this opens up the
possibility of creating a backend as an internal implementation detail
of some other activity, by providing just that one backend with a
custom Seat that implements the methods differently.
For example, this refactoring should make it feasible to directly
implement an SSH proxy type, aka the 'jump host' feature supported by
OpenSSH, aka 'open a secondary SSH session in MAINCHAN_DIRECT_TCP
mode, and then expose the main channel of that as the Socket for the
primary connection'. (Which of course you can already do by spawning
'plink -nc' as a separate proxy process, but this would permit it in
the _same_ process without anything getting confused.)
I've centralised a full set of stub methods in misc.c for the new
abstraction, which allows me to get rid of several annoying stubs in
the previous code. Also, while I'm here, I've moved a lot of
duplicated modalfatalbox() type functions from application main
program files into wincons.c / uxcons.c, which I think saves
duplication overall. (A minor visible effect is that the prefixes on
those console-based fatal error messages will now be more consistent
between applications.)
2018-10-11 18:58:42 +00:00
|
|
|
register_dialog(seat, result_ctx->dialog_slot, msgbox);
|
2017-11-26 15:13:08 +00:00
|
|
|
|
2023-11-22 08:57:54 +00:00
|
|
|
strbuf_free(dlg_text);
|
2003-03-31 11:21:07 +00:00
|
|
|
|
Richer data type for interactive prompt results.
All the seat functions that request an interactive prompt of some kind
to the user - both the main seat_get_userpass_input and the various
confirmation dialogs for things like host keys - were using a simple
int return value, with the general semantics of 0 = "fail", 1 =
"proceed" (and in the case of seat_get_userpass_input, answers to the
prompts were provided), and -1 = "request in progress, wait for a
callback".
In this commit I change all those functions' return types to a new
struct called SeatPromptResult, whose primary field is an enum
replacing those simple integer values.
The main purpose is that the enum has not three but _four_ values: the
"fail" result has been split into 'user abort' and 'software abort'.
The distinction is that a user abort occurs as a result of an
interactive UI action, such as the user clicking 'cancel' in a dialog
box or hitting ^D or ^C at a terminal password prompt - and therefore,
there's no need to display an error message telling the user that the
interactive operation has failed, because the user already knows,
because they _did_ it. 'Software abort' is from any other cause, where
PuTTY is the first to know there was a problem, and has to tell the
user.
We already had this 'user abort' vs 'software abort' distinction in
other parts of the code - the SSH backend has separate termination
functions which protocol layers can call. But we assumed that any
failure from an interactive prompt request fell into the 'user abort'
category, which is not true. A couple of examples: if you configure a
host key fingerprint in your saved session via the SSH > Host keys
pane, and the server presents a host key that doesn't match it, then
verify_ssh_host_key would report that the user had aborted the
connection, and feel no need to tell the user what had gone wrong!
Similarly, if a password provided on the command line was not
accepted, then (after I fixed the semantics of that in the previous
commit) the same wrong handling would occur.
So now, those Seat prompt functions too can communicate whether the
user or the software originated a connection abort. And in the latter
case, we also provide an error message to present to the user. Result:
in those two example cases (and others), error messages should no
longer go missing.
Implementation note: to avoid the hassle of having the error message
in a SeatPromptResult being a dynamically allocated string (and hence,
every recipient of one must always check whether it's non-NULL and
free it on every exit path, plus being careful about copying the
struct around), I've instead arranged that the structure contains a
function pointer and a couple of parameters, so that the string form
of the message can be constructed on demand. That way, the only users
who need to free it are the ones who actually _asked_ for it in the
first place, which is a much smaller set.
(This is one of the rare occasions that I regret not having C++'s
extra features available in this code base - a unique_ptr or
shared_ptr to a string would have been just the thing here, and the
compiler would have done all the hard work for me of remembering where
to insert the frees!)
2021-12-28 17:52:00 +00:00
|
|
|
return SPR_INCOMPLETE;
|
2003-03-13 19:52:28 +00:00
|
|
|
}
|
|
|
|
|
2003-03-31 11:21:07 +00:00
|
|
|
void old_keyfile_warning(void)
|
2003-03-13 19:52:28 +00:00
|
|
|
{
|
2003-03-31 11:21:07 +00:00
|
|
|
/*
|
|
|
|
* This should never happen on Unix. We hope.
|
|
|
|
*/
|
2003-03-13 19:52:28 +00:00
|
|
|
}
|
|
|
|
|
2015-05-15 10:15:42 +00:00
|
|
|
void nonfatal_message_box(void *window, const char *msg)
|
2013-07-19 17:44:28 +00:00
|
|
|
{
|
Make dupcat() into a variadic macro.
Up until now, it's been a variadic _function_, whose argument list
consists of 'const char *' ASCIZ strings to concatenate, terminated by
one containing a null pointer. Now, that function is dupcat_fn(), and
it's wrapped by a C99 variadic _macro_ called dupcat(), which
automatically suffixes the null-pointer terminating argument.
This has three benefits. Firstly, it's just less effort at every call
site. Secondly, it protects against the risk of accidentally leaving
off the NULL, causing arbitrary words of stack memory to be
dereferenced as char pointers. And thirdly, it protects against the
more subtle risk of writing a bare 'NULL' as the terminating argument,
instead of casting it explicitly to a pointer. That last one is
necessary because C permits the macro NULL to expand to an integer
constant such as 0, so NULL by itself may not have pointer type, and
worse, it may not be marshalled in a variadic argument list in the
same way as a pointer. (For example, on a 64-bit machine it might only
occupy 32 bits. And yet, on another 64-bit platform, it might work
just fine, so that you don't notice the mistake!)
I was inspired to do this by happening to notice one of those bare
NULL terminators, and thinking I'd better check if there were any
more. Turned out there were quite a few. Now there are none.
2019-10-14 18:42:37 +00:00
|
|
|
char *title = dupcat(appname, " Error");
|
2017-11-26 17:55:00 +00:00
|
|
|
create_message_box(
|
|
|
|
window, title, msg,
|
|
|
|
string_width("REASONABLY LONG LINE OF TEXT FOR BASIC SANITY"),
|
2018-10-29 19:50:29 +00:00
|
|
|
false, &buttons_ok, trivial_post_dialog_fn, NULL);
|
2017-11-26 17:55:00 +00:00
|
|
|
sfree(title);
|
2013-07-19 17:44:28 +00:00
|
|
|
}
|
|
|
|
|
2015-05-15 10:15:42 +00:00
|
|
|
void nonfatal(const char *p, ...)
|
2013-07-19 17:44:28 +00:00
|
|
|
{
|
|
|
|
va_list ap;
|
|
|
|
char *msg;
|
|
|
|
va_start(ap, p);
|
|
|
|
msg = dupvprintf(p, ap);
|
|
|
|
va_end(ap);
|
2013-09-23 14:35:08 +00:00
|
|
|
nonfatal_message_box(NULL, msg);
|
2013-07-19 17:44:28 +00:00
|
|
|
sfree(msg);
|
|
|
|
}
|
|
|
|
|
2003-04-05 16:05:00 +00:00
|
|
|
static GtkWidget *aboutbox = NULL;
|
|
|
|
|
2021-04-05 16:50:02 +00:00
|
|
|
static void about_window_destroyed(GtkWidget *widget, gpointer data)
|
|
|
|
{
|
|
|
|
aboutbox = NULL;
|
|
|
|
}
|
|
|
|
|
2003-04-05 16:05:00 +00:00
|
|
|
static void about_close_clicked(GtkButton *button, gpointer data)
|
|
|
|
{
|
|
|
|
gtk_widget_destroy(aboutbox);
|
|
|
|
aboutbox = NULL;
|
|
|
|
}
|
|
|
|
|
2015-09-26 13:09:27 +00:00
|
|
|
static void about_key_press(GtkWidget *widget, GdkEventKey *event,
|
|
|
|
gpointer data)
|
|
|
|
{
|
|
|
|
if (event->keyval == GDK_KEY_Escape && aboutbox) {
|
|
|
|
gtk_widget_destroy(aboutbox);
|
|
|
|
aboutbox = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-04-05 16:05:00 +00:00
|
|
|
static void licence_clicked(GtkButton *button, gpointer data)
|
|
|
|
{
|
|
|
|
char *title;
|
|
|
|
|
Make dupcat() into a variadic macro.
Up until now, it's been a variadic _function_, whose argument list
consists of 'const char *' ASCIZ strings to concatenate, terminated by
one containing a null pointer. Now, that function is dupcat_fn(), and
it's wrapped by a C99 variadic _macro_ called dupcat(), which
automatically suffixes the null-pointer terminating argument.
This has three benefits. Firstly, it's just less effort at every call
site. Secondly, it protects against the risk of accidentally leaving
off the NULL, causing arbitrary words of stack memory to be
dereferenced as char pointers. And thirdly, it protects against the
more subtle risk of writing a bare 'NULL' as the terminating argument,
instead of casting it explicitly to a pointer. That last one is
necessary because C permits the macro NULL to expand to an integer
constant such as 0, so NULL by itself may not have pointer type, and
worse, it may not be marshalled in a variadic argument list in the
same way as a pointer. (For example, on a 64-bit machine it might only
occupy 32 bits. And yet, on another 64-bit platform, it might work
just fine, so that you don't notice the mistake!)
I was inspired to do this by happening to notice one of those bare
NULL terminators, and thinking I'd better check if there were any
more. Turned out there were quite a few. Now there are none.
2019-10-14 18:42:37 +00:00
|
|
|
title = dupcat(appname, " Licence");
|
2003-04-05 16:05:00 +00:00
|
|
|
assert(aboutbox != NULL);
|
2017-11-26 17:32:01 +00:00
|
|
|
create_message_box(aboutbox, title, LICENCE_TEXT("\n\n"),
|
|
|
|
string_width("LONGISH LINE OF TEXT SO THE LICENCE"
|
|
|
|
" BOX ISN'T EXCESSIVELY TALL AND THIN"),
|
2018-10-29 19:50:29 +00:00
|
|
|
true, &buttons_ok, trivial_post_dialog_fn, NULL);
|
2003-04-05 16:05:00 +00:00
|
|
|
sfree(title);
|
|
|
|
}
|
|
|
|
|
2003-04-10 08:53:43 +00:00
|
|
|
void about_box(void *window)
|
2003-04-05 16:05:00 +00:00
|
|
|
{
|
|
|
|
GtkWidget *w;
|
2015-08-31 14:45:18 +00:00
|
|
|
GtkBox *action_area;
|
2003-04-05 16:05:00 +00:00
|
|
|
char *title;
|
|
|
|
|
|
|
|
if (aboutbox) {
|
|
|
|
gtk_widget_grab_focus(aboutbox);
|
2019-09-08 19:29:00 +00:00
|
|
|
return;
|
2003-04-05 16:05:00 +00:00
|
|
|
}
|
|
|
|
|
2015-08-31 14:45:18 +00:00
|
|
|
aboutbox = our_dialog_new();
|
2003-04-05 16:05:00 +00:00
|
|
|
gtk_container_set_border_width(GTK_CONTAINER(aboutbox), 10);
|
Make dupcat() into a variadic macro.
Up until now, it's been a variadic _function_, whose argument list
consists of 'const char *' ASCIZ strings to concatenate, terminated by
one containing a null pointer. Now, that function is dupcat_fn(), and
it's wrapped by a C99 variadic _macro_ called dupcat(), which
automatically suffixes the null-pointer terminating argument.
This has three benefits. Firstly, it's just less effort at every call
site. Secondly, it protects against the risk of accidentally leaving
off the NULL, causing arbitrary words of stack memory to be
dereferenced as char pointers. And thirdly, it protects against the
more subtle risk of writing a bare 'NULL' as the terminating argument,
instead of casting it explicitly to a pointer. That last one is
necessary because C permits the macro NULL to expand to an integer
constant such as 0, so NULL by itself may not have pointer type, and
worse, it may not be marshalled in a variadic argument list in the
same way as a pointer. (For example, on a 64-bit machine it might only
occupy 32 bits. And yet, on another 64-bit platform, it might work
just fine, so that you don't notice the mistake!)
I was inspired to do this by happening to notice one of those bare
NULL terminators, and thinking I'd better check if there were any
more. Turned out there were quite a few. Now there are none.
2019-10-14 18:42:37 +00:00
|
|
|
title = dupcat("About ", appname);
|
2003-04-05 16:05:00 +00:00
|
|
|
gtk_window_set_title(GTK_WINDOW(aboutbox), title);
|
|
|
|
sfree(title);
|
|
|
|
|
2021-04-05 16:50:02 +00:00
|
|
|
g_signal_connect(G_OBJECT(aboutbox), "destroy",
|
|
|
|
G_CALLBACK(about_window_destroyed), NULL);
|
|
|
|
|
2003-04-05 16:05:00 +00:00
|
|
|
w = gtk_button_new_with_label("Close");
|
2018-10-29 19:50:29 +00:00
|
|
|
gtk_widget_set_can_default(w, true);
|
2003-04-05 16:05:00 +00:00
|
|
|
gtk_window_set_default(GTK_WINDOW(aboutbox), w);
|
2015-08-31 14:45:18 +00:00
|
|
|
action_area = our_dialog_make_action_hbox(GTK_WINDOW(aboutbox));
|
2018-10-29 19:50:29 +00:00
|
|
|
gtk_box_pack_end(action_area, w, false, false, 0);
|
2015-08-08 16:29:02 +00:00
|
|
|
g_signal_connect(G_OBJECT(w), "clicked",
|
|
|
|
G_CALLBACK(about_close_clicked), NULL);
|
2003-04-05 16:05:00 +00:00
|
|
|
gtk_widget_show(w);
|
|
|
|
|
|
|
|
w = gtk_button_new_with_label("View Licence");
|
2018-10-29 19:50:29 +00:00
|
|
|
gtk_widget_set_can_default(w, true);
|
|
|
|
gtk_box_pack_end(action_area, w, false, false, 0);
|
2015-08-08 16:29:02 +00:00
|
|
|
g_signal_connect(G_OBJECT(w), "clicked",
|
|
|
|
G_CALLBACK(licence_clicked), NULL);
|
2003-04-05 16:05:00 +00:00
|
|
|
gtk_widget_show(w);
|
|
|
|
|
2015-12-22 12:32:48 +00:00
|
|
|
{
|
2017-01-21 14:55:53 +00:00
|
|
|
char *buildinfo_text = buildinfo("\n");
|
Formatting: standardise on "func(\n", not "func\n(".
If the function name (or expression) in a function call or declaration
is itself so long that even the first argument doesn't fit after it on
the same line, or if that would leave so little space that it would be
silly to try to wrap all the run-on lines into a tall thin column,
then I used to do this
ludicrously_long_function_name
(arg1, arg2, arg3);
and now prefer this
ludicrously_long_function_name(
arg1, arg2, arg3);
I picked up the habit from Python, where the latter idiom is required
by Python's syntactic significance of newlines (you can write the
former if you use a backslash-continuation, but pretty much everyone
seems to agree that that's much uglier). But I've found it works well
in C as well: it makes it more obvious that the previous line is
incomplete, it gives you a tiny bit more space to wrap the following
lines into (the old idiom indents the _third_ line one space beyond
the second), and I generally turn out to agree with the knock-on
indentation decisions made by at least Emacs if you do it in the
middle of a complex expression. Plus, of course, using the _same_
idiom between C and Python means less state-switching.
So, while I'm making annoying indentation changes in general, this
seems like a good time to dig out all the cases of the old idiom in
this code, and switch them over to the new.
2022-08-03 19:48:46 +00:00
|
|
|
char *label_text = dupprintf(
|
|
|
|
"%s\n\n%s\n\n%s\n\n%s",
|
|
|
|
appname, ver, buildinfo_text,
|
|
|
|
"Copyright " SHORT_COPYRIGHT_DETAILS ". All rights reserved");
|
2015-12-22 12:32:48 +00:00
|
|
|
w = gtk_label_new(label_text);
|
|
|
|
gtk_label_set_justify(GTK_LABEL(w), GTK_JUSTIFY_CENTER);
|
|
|
|
#if GTK_CHECK_VERSION(2,0,0)
|
2018-10-29 19:50:29 +00:00
|
|
|
gtk_label_set_selectable(GTK_LABEL(w), true);
|
2015-12-22 12:32:48 +00:00
|
|
|
#endif
|
|
|
|
sfree(label_text);
|
|
|
|
}
|
2018-10-29 19:50:29 +00:00
|
|
|
our_dialog_add_to_content_area(GTK_WINDOW(aboutbox), w, false, false, 0);
|
2015-12-22 12:32:48 +00:00
|
|
|
#if GTK_CHECK_VERSION(2,0,0)
|
|
|
|
/*
|
2017-11-26 20:01:16 +00:00
|
|
|
* Same precautions against initial select-all as in
|
|
|
|
* create_message_box().
|
2015-12-22 12:32:48 +00:00
|
|
|
*/
|
|
|
|
gtk_widget_grab_focus(w);
|
|
|
|
gtk_label_select_region(GTK_LABEL(w), 0, 0);
|
|
|
|
#endif
|
2003-04-05 16:05:00 +00:00
|
|
|
gtk_widget_show(w);
|
|
|
|
|
2015-09-26 13:09:27 +00:00
|
|
|
g_signal_connect(G_OBJECT(aboutbox), "key_press_event",
|
|
|
|
G_CALLBACK(about_key_press), NULL);
|
|
|
|
|
2003-04-10 08:53:43 +00:00
|
|
|
set_transient_window_pos(GTK_WIDGET(window), aboutbox);
|
2017-12-18 11:46:48 +00:00
|
|
|
if (window)
|
|
|
|
gtk_window_set_transient_for(GTK_WINDOW(aboutbox),
|
|
|
|
GTK_WINDOW(window));
|
2015-12-22 12:32:48 +00:00
|
|
|
gtk_container_set_focus_child(GTK_CONTAINER(aboutbox), NULL);
|
2003-04-05 16:05:00 +00:00
|
|
|
gtk_widget_show(aboutbox);
|
2015-12-22 12:32:48 +00:00
|
|
|
gtk_window_set_focus(GTK_WINDOW(aboutbox), NULL);
|
2003-04-05 16:05:00 +00:00
|
|
|
}
|
2003-04-09 18:46:45 +00:00
|
|
|
|
Don't grow logevent buf indefinitely
The PuTTY GUIs (Unix and Windows) maintain an in-memory event log
for display to users as they request. This uses ints for tracking
eventlog size, which is subject to memory exhaustion and (given
enough heap space) overflow attacks by servers (via, e.g., constant
rekeying).
Also a bounded log is more user-friendly. It is rare to want more
than the initial logging and the logging from a few recent rekey
events.
The Windows fix has been tested using Dr. Memory as a valgrind
substitute. No errors corresponding to the affected code showed up.
The Dr. Memory results.txt was split into a file per-error and then
grep Error $(grep -l windlg *)|cut -d: -f3-|sort |uniq -c
was used to compare. Differences arose from different usage of the GUI,
but no error could be traced to the code modified in this commit.
The Unix fix has been tested using valgrind. We don't destroy the
eventlog_stuff eventlog arrays, so we can't be entirely sure that we
don't leak more than we did before, but from code inspection it looks
like we don't (and anyways, if we leaked as much as before, just without
the integer overflow, well, that's still an improvement).
2013-07-22 23:09:04 +00:00
|
|
|
#define LOGEVENT_INITIAL_MAX 128
|
|
|
|
#define LOGEVENT_CIRCULAR_MAX 128
|
|
|
|
|
2003-04-09 18:46:45 +00:00
|
|
|
struct eventlog_stuff {
|
|
|
|
GtkWidget *parentwin, *window;
|
|
|
|
struct controlbox *eventbox;
|
|
|
|
struct Shortcuts scs;
|
|
|
|
struct dlgparam dp;
|
2022-05-01 08:48:38 +00:00
|
|
|
dlgcontrol *listctrl;
|
Don't grow logevent buf indefinitely
The PuTTY GUIs (Unix and Windows) maintain an in-memory event log
for display to users as they request. This uses ints for tracking
eventlog size, which is subject to memory exhaustion and (given
enough heap space) overflow attacks by servers (via, e.g., constant
rekeying).
Also a bounded log is more user-friendly. It is rare to want more
than the initial logging and the logging from a few recent rekey
events.
The Windows fix has been tested using Dr. Memory as a valgrind
substitute. No errors corresponding to the affected code showed up.
The Dr. Memory results.txt was split into a file per-error and then
grep Error $(grep -l windlg *)|cut -d: -f3-|sort |uniq -c
was used to compare. Differences arose from different usage of the GUI,
but no error could be traced to the code modified in this commit.
The Unix fix has been tested using valgrind. We don't destroy the
eventlog_stuff eventlog arrays, so we can't be entirely sure that we
don't leak more than we did before, but from code inspection it looks
like we don't (and anyways, if we leaked as much as before, just without
the integer overflow, well, that's still an improvement).
2013-07-22 23:09:04 +00:00
|
|
|
char **events_initial;
|
|
|
|
char **events_circular;
|
|
|
|
int ninitial, ncircular, circular_first;
|
2018-12-01 09:35:52 +00:00
|
|
|
strbuf *seldata;
|
2003-04-11 17:40:52 +00:00
|
|
|
int sellen;
|
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 ignore_selchange;
|
2003-04-09 18:46:45 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static void eventlog_destroy(GtkWidget *widget, gpointer data)
|
|
|
|
{
|
2018-10-08 18:30:01 +00:00
|
|
|
eventlog_stuff *es = (eventlog_stuff *)data;
|
2003-04-09 18:46:45 +00:00
|
|
|
|
|
|
|
es->window = NULL;
|
|
|
|
dlg_cleanup(&es->dp);
|
|
|
|
ctrl_free_box(es->eventbox);
|
|
|
|
}
|
2022-05-01 08:48:38 +00:00
|
|
|
static void eventlog_ok_handler(dlgcontrol *ctrl, dlgparam *dp,
|
2019-09-08 19:29:00 +00:00
|
|
|
void *data, int event)
|
2003-04-09 18:46:45 +00:00
|
|
|
{
|
|
|
|
if (event == EVENT_ACTION)
|
2018-09-13 11:58:44 +00:00
|
|
|
dlg_end(dp, 0);
|
2003-04-09 18:46:45 +00:00
|
|
|
}
|
2022-05-01 08:48:38 +00:00
|
|
|
static void eventlog_list_handler(dlgcontrol *ctrl, dlgparam *dp,
|
2019-09-08 19:29:00 +00:00
|
|
|
void *data, int event)
|
2003-04-09 18:46:45 +00:00
|
|
|
{
|
2018-10-08 18:30:01 +00:00
|
|
|
eventlog_stuff *es = (eventlog_stuff *)data;
|
2003-04-09 18:46:45 +00:00
|
|
|
|
|
|
|
if (event == EVENT_REFRESH) {
|
2019-09-08 19:29:00 +00:00
|
|
|
int i;
|
2003-04-09 18:46:45 +00:00
|
|
|
|
2018-09-13 11:58:44 +00:00
|
|
|
dlg_update_start(ctrl, dp);
|
|
|
|
dlg_listbox_clear(ctrl, dp);
|
2019-09-08 19:29:00 +00:00
|
|
|
for (i = 0; i < es->ninitial; i++) {
|
2018-09-13 11:58:44 +00:00
|
|
|
dlg_listbox_add(ctrl, dp, es->events_initial[i]);
|
2019-09-08 19:29:00 +00:00
|
|
|
}
|
|
|
|
for (i = 0; i < es->ncircular; i++) {
|
2018-09-13 11:58:44 +00:00
|
|
|
dlg_listbox_add(ctrl, dp, es->events_circular[(es->circular_first + i) % LOGEVENT_CIRCULAR_MAX]);
|
2019-09-08 19:29:00 +00:00
|
|
|
}
|
2018-09-13 11:58:44 +00:00
|
|
|
dlg_update_done(ctrl, dp);
|
2003-04-11 17:40:52 +00:00
|
|
|
} else if (event == EVENT_SELCHANGE) {
|
|
|
|
int i;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If this SELCHANGE event is happening as a result of
|
|
|
|
* deliberate deselection because someone else has grabbed
|
|
|
|
* the selection, the last thing we want to do is pre-empt
|
|
|
|
* them.
|
|
|
|
*/
|
|
|
|
if (es->ignore_selchange)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Construct the data to use as the selection.
|
|
|
|
*/
|
2020-01-21 20:16:28 +00:00
|
|
|
strbuf_clear(es->seldata);
|
Don't grow logevent buf indefinitely
The PuTTY GUIs (Unix and Windows) maintain an in-memory event log
for display to users as they request. This uses ints for tracking
eventlog size, which is subject to memory exhaustion and (given
enough heap space) overflow attacks by servers (via, e.g., constant
rekeying).
Also a bounded log is more user-friendly. It is rare to want more
than the initial logging and the logging from a few recent rekey
events.
The Windows fix has been tested using Dr. Memory as a valgrind
substitute. No errors corresponding to the affected code showed up.
The Dr. Memory results.txt was split into a file per-error and then
grep Error $(grep -l windlg *)|cut -d: -f3-|sort |uniq -c
was used to compare. Differences arose from different usage of the GUI,
but no error could be traced to the code modified in this commit.
The Unix fix has been tested using valgrind. We don't destroy the
eventlog_stuff eventlog arrays, so we can't be entirely sure that we
don't leak more than we did before, but from code inspection it looks
like we don't (and anyways, if we leaked as much as before, just without
the integer overflow, well, that's still an improvement).
2013-07-22 23:09:04 +00:00
|
|
|
for (i = 0; i < es->ninitial; i++) {
|
2018-12-01 09:35:52 +00:00
|
|
|
if (dlg_listbox_issel(ctrl, dp, i))
|
2021-11-19 10:23:32 +00:00
|
|
|
put_fmt(es->seldata, "%s\n", es->events_initial[i]);
|
Don't grow logevent buf indefinitely
The PuTTY GUIs (Unix and Windows) maintain an in-memory event log
for display to users as they request. This uses ints for tracking
eventlog size, which is subject to memory exhaustion and (given
enough heap space) overflow attacks by servers (via, e.g., constant
rekeying).
Also a bounded log is more user-friendly. It is rare to want more
than the initial logging and the logging from a few recent rekey
events.
The Windows fix has been tested using Dr. Memory as a valgrind
substitute. No errors corresponding to the affected code showed up.
The Dr. Memory results.txt was split into a file per-error and then
grep Error $(grep -l windlg *)|cut -d: -f3-|sort |uniq -c
was used to compare. Differences arose from different usage of the GUI,
but no error could be traced to the code modified in this commit.
The Unix fix has been tested using valgrind. We don't destroy the
eventlog_stuff eventlog arrays, so we can't be entirely sure that we
don't leak more than we did before, but from code inspection it looks
like we don't (and anyways, if we leaked as much as before, just without
the integer overflow, well, that's still an improvement).
2013-07-22 23:09:04 +00:00
|
|
|
}
|
|
|
|
for (i = 0; i < es->ncircular; i++) {
|
2018-09-13 11:58:44 +00:00
|
|
|
if (dlg_listbox_issel(ctrl, dp, es->ninitial + i)) {
|
Don't grow logevent buf indefinitely
The PuTTY GUIs (Unix and Windows) maintain an in-memory event log
for display to users as they request. This uses ints for tracking
eventlog size, which is subject to memory exhaustion and (given
enough heap space) overflow attacks by servers (via, e.g., constant
rekeying).
Also a bounded log is more user-friendly. It is rare to want more
than the initial logging and the logging from a few recent rekey
events.
The Windows fix has been tested using Dr. Memory as a valgrind
substitute. No errors corresponding to the affected code showed up.
The Dr. Memory results.txt was split into a file per-error and then
grep Error $(grep -l windlg *)|cut -d: -f3-|sort |uniq -c
was used to compare. Differences arose from different usage of the GUI,
but no error could be traced to the code modified in this commit.
The Unix fix has been tested using valgrind. We don't destroy the
eventlog_stuff eventlog arrays, so we can't be entirely sure that we
don't leak more than we did before, but from code inspection it looks
like we don't (and anyways, if we leaked as much as before, just without
the integer overflow, well, that's still an improvement).
2013-07-22 23:09:04 +00:00
|
|
|
int j = (es->circular_first + i) % LOGEVENT_CIRCULAR_MAX;
|
2021-11-19 10:23:32 +00:00
|
|
|
put_fmt(es->seldata, "%s\n", es->events_circular[j]);
|
2003-04-11 17:40:52 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (gtk_selection_owner_set(es->window, GDK_SELECTION_PRIMARY,
|
|
|
|
GDK_CURRENT_TIME)) {
|
|
|
|
gtk_selection_add_target(es->window, GDK_SELECTION_PRIMARY,
|
|
|
|
GDK_SELECTION_TYPE_STRING, 1);
|
|
|
|
gtk_selection_add_target(es->window, GDK_SELECTION_PRIMARY,
|
|
|
|
compound_text_atom, 1);
|
|
|
|
}
|
|
|
|
|
2003-04-09 18:46:45 +00:00
|
|
|
}
|
|
|
|
}
|
2003-04-11 17:40:52 +00:00
|
|
|
|
|
|
|
void eventlog_selection_get(GtkWidget *widget, GtkSelectionData *seldata,
|
|
|
|
guint info, guint time_stamp, gpointer data)
|
|
|
|
{
|
2018-10-08 18:30:01 +00:00
|
|
|
eventlog_stuff *es = (eventlog_stuff *)data;
|
2003-04-11 17:40:52 +00:00
|
|
|
|
2015-08-08 14:53:43 +00:00
|
|
|
gtk_selection_data_set(seldata, gtk_selection_data_get_target(seldata), 8,
|
2018-12-01 09:35:52 +00:00
|
|
|
es->seldata->u, es->seldata->len);
|
2003-04-11 17:40:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
gint eventlog_selection_clear(GtkWidget *widget, GdkEventSelection *seldata,
|
|
|
|
gpointer data)
|
|
|
|
{
|
2018-10-08 18:30:01 +00:00
|
|
|
eventlog_stuff *es = (eventlog_stuff *)data;
|
2003-04-11 17:40:52 +00:00
|
|
|
struct uctrl *uc;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Deselect everything in the list box.
|
|
|
|
*/
|
|
|
|
uc = dlg_find_byctrl(&es->dp, es->listctrl);
|
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
|
|
|
es->ignore_selchange = true;
|
2008-04-04 10:56:26 +00:00
|
|
|
#if !GTK_CHECK_VERSION(2,0,0)
|
|
|
|
assert(uc->list);
|
|
|
|
gtk_list_unselect_all(GTK_LIST(uc->list));
|
|
|
|
#else
|
2008-04-04 10:16:24 +00:00
|
|
|
assert(uc->treeview);
|
Formatting: standardise on "func(\n", not "func\n(".
If the function name (or expression) in a function call or declaration
is itself so long that even the first argument doesn't fit after it on
the same line, or if that would leave so little space that it would be
silly to try to wrap all the run-on lines into a tall thin column,
then I used to do this
ludicrously_long_function_name
(arg1, arg2, arg3);
and now prefer this
ludicrously_long_function_name(
arg1, arg2, arg3);
I picked up the habit from Python, where the latter idiom is required
by Python's syntactic significance of newlines (you can write the
former if you use a backslash-continuation, but pretty much everyone
seems to agree that that's much uglier). But I've found it works well
in C as well: it makes it more obvious that the previous line is
incomplete, it gives you a tiny bit more space to wrap the following
lines into (the old idiom indents the _third_ line one space beyond
the second), and I generally turn out to agree with the knock-on
indentation decisions made by at least Emacs if you do it in the
middle of a complex expression. Plus, of course, using the _same_
idiom between C and Python means less state-switching.
So, while I'm making annoying indentation changes in general, this
seems like a good time to dig out all the cases of the old idiom in
this code, and switch them over to the new.
2022-08-03 19:48:46 +00:00
|
|
|
gtk_tree_selection_unselect_all(
|
|
|
|
gtk_tree_view_get_selection(GTK_TREE_VIEW(uc->treeview)));
|
2008-04-04 10:56:26 +00:00
|
|
|
#endif
|
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
|
|
|
es->ignore_selchange = false;
|
2003-04-11 17:40:52 +00:00
|
|
|
|
2018-10-29 19:50:29 +00:00
|
|
|
return true;
|
2003-04-11 17:40:52 +00:00
|
|
|
}
|
|
|
|
|
2018-10-08 18:30:01 +00:00
|
|
|
void showeventlog(eventlog_stuff *es, void *parentwin)
|
2003-04-09 18:46:45 +00:00
|
|
|
{
|
|
|
|
GtkWidget *window, *w0, *w1;
|
|
|
|
GtkWidget *parent = GTK_WIDGET(parentwin);
|
|
|
|
struct controlset *s0, *s1;
|
2022-05-01 08:48:38 +00:00
|
|
|
dlgcontrol *c;
|
2008-04-02 14:48:06 +00:00
|
|
|
int index;
|
2003-04-09 18:46:45 +00:00
|
|
|
char *title;
|
|
|
|
|
|
|
|
if (es->window) {
|
|
|
|
gtk_widget_grab_focus(es->window);
|
2019-09-08 19:29:00 +00:00
|
|
|
return;
|
2003-04-09 18:46:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
dlg_init(&es->dp);
|
|
|
|
|
|
|
|
for (index = 0; index < lenof(es->scs.sc); index++) {
|
2019-09-08 19:29:00 +00:00
|
|
|
es->scs.sc[index].action = SHORTCUT_EMPTY;
|
2003-04-09 18:46:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
es->eventbox = ctrl_new_box();
|
|
|
|
|
|
|
|
s0 = ctrl_getset(es->eventbox, "", "", "");
|
|
|
|
ctrl_columns(s0, 3, 33, 34, 33);
|
|
|
|
c = ctrl_pushbutton(s0, "Close", 'c', HELPCTX(no_help),
|
2019-09-08 19:29:00 +00:00
|
|
|
eventlog_ok_handler, P(NULL));
|
Restructure dlgcontrol as a struct with an anon union.
This gets rid of that awkward STANDARD_PREFIX system in which every
branch of the old 'union control' had to repeat all the generic
fields, and then call sites had to make an arbitrary decision about
which branch to access them through.
That was the best we could do before accepting C99 features in this
code base. But now we have anonymous unions, so we don't need to put
up with that nonsense any more!
'dlgcontrol' is now a struct rather than a union, and the generic
fields common to all control types are ordinary members of the struct,
so you don't have to refer to them as ctrl->generic.foo at all, just
ctrl->foo, which saves verbiage at the point of use.
The extra per-control fields are still held in structures named after
the control type, so you'll still say ctrl->listbox.height or
whatever. But now those structures are themselves members of an
anonymous union field following the generic fields, so those
sub-structures don't have to reiterate all the standard stuff too.
While I'm here, I've promoted 'context2' from an editbox-specific
field to a generic one (it just seems silly _not_ to allow any control
to have two context fields if it needs it). Also, I had to rename the
boolean field 'tabdelay' to avoid it clashing with the subsidiary
structure field 'tabdelay', now that the former isn't generic.tabdelay
any more.
2022-05-01 08:55:52 +00:00
|
|
|
c->column = 1;
|
2018-10-29 19:50:29 +00:00
|
|
|
c->button.isdefault = true;
|
2003-04-09 18:46:45 +00:00
|
|
|
|
|
|
|
s1 = ctrl_getset(es->eventbox, "x", "", "");
|
|
|
|
es->listctrl = c = ctrl_listbox(s1, NULL, NO_SHORTCUT, HELPCTX(no_help),
|
2019-09-08 19:29:00 +00:00
|
|
|
eventlog_list_handler, P(es));
|
2003-04-09 18:46:45 +00:00
|
|
|
c->listbox.height = 10;
|
|
|
|
c->listbox.multisel = 2;
|
|
|
|
c->listbox.ncols = 3;
|
|
|
|
c->listbox.percentages = snewn(3, int);
|
|
|
|
c->listbox.percentages[0] = 25;
|
|
|
|
c->listbox.percentages[1] = 10;
|
|
|
|
c->listbox.percentages[2] = 65;
|
|
|
|
|
2015-08-31 14:45:18 +00:00
|
|
|
es->window = window = our_dialog_new();
|
Make dupcat() into a variadic macro.
Up until now, it's been a variadic _function_, whose argument list
consists of 'const char *' ASCIZ strings to concatenate, terminated by
one containing a null pointer. Now, that function is dupcat_fn(), and
it's wrapped by a C99 variadic _macro_ called dupcat(), which
automatically suffixes the null-pointer terminating argument.
This has three benefits. Firstly, it's just less effort at every call
site. Secondly, it protects against the risk of accidentally leaving
off the NULL, causing arbitrary words of stack memory to be
dereferenced as char pointers. And thirdly, it protects against the
more subtle risk of writing a bare 'NULL' as the terminating argument,
instead of casting it explicitly to a pointer. That last one is
necessary because C permits the macro NULL to expand to an integer
constant such as 0, so NULL by itself may not have pointer type, and
worse, it may not be marshalled in a variadic argument list in the
same way as a pointer. (For example, on a 64-bit machine it might only
occupy 32 bits. And yet, on another 64-bit platform, it might work
just fine, so that you don't notice the mistake!)
I was inspired to do this by happening to notice one of those bare
NULL terminators, and thinking I'd better check if there were any
more. Turned out there were quite a few. Now there are none.
2019-10-14 18:42:37 +00:00
|
|
|
title = dupcat(appname, " Event Log");
|
2003-04-09 18:46:45 +00:00
|
|
|
gtk_window_set_title(GTK_WINDOW(window), title);
|
|
|
|
sfree(title);
|
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
|
|
|
w0 = layout_ctrls(&es->dp, NULL, &es->scs, s0, GTK_WINDOW(window));
|
2015-08-31 14:45:18 +00:00
|
|
|
our_dialog_set_action_area(GTK_WINDOW(window), w0);
|
2003-04-09 18:46:45 +00:00
|
|
|
gtk_widget_show(w0);
|
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
|
|
|
w1 = layout_ctrls(&es->dp, NULL, &es->scs, s1, GTK_WINDOW(window));
|
2003-04-09 18:46:45 +00:00
|
|
|
gtk_container_set_border_width(GTK_CONTAINER(w1), 10);
|
Formatting: standardise on "func(\n", not "func\n(".
If the function name (or expression) in a function call or declaration
is itself so long that even the first argument doesn't fit after it on
the same line, or if that would leave so little space that it would be
silly to try to wrap all the run-on lines into a tall thin column,
then I used to do this
ludicrously_long_function_name
(arg1, arg2, arg3);
and now prefer this
ludicrously_long_function_name(
arg1, arg2, arg3);
I picked up the habit from Python, where the latter idiom is required
by Python's syntactic significance of newlines (you can write the
former if you use a backslash-continuation, but pretty much everyone
seems to agree that that's much uglier). But I've found it works well
in C as well: it makes it more obvious that the previous line is
incomplete, it gives you a tiny bit more space to wrap the following
lines into (the old idiom indents the _third_ line one space beyond
the second), and I generally turn out to agree with the knock-on
indentation decisions made by at least Emacs if you do it in the
middle of a complex expression. Plus, of course, using the _same_
idiom between C and Python means less state-switching.
So, while I'm making annoying indentation changes in general, this
seems like a good time to dig out all the cases of the old idiom in
this code, and switch them over to the new.
2022-08-03 19:48:46 +00:00
|
|
|
gtk_widget_set_size_request(
|
|
|
|
w1, 20 + string_width("LINE OF TEXT GIVING WIDTH OF EVENT LOG IS "
|
|
|
|
"QUITE LONG 'COS SSH LOG ENTRIES ARE WIDE"),
|
|
|
|
-1);
|
2018-10-29 19:50:29 +00:00
|
|
|
our_dialog_add_to_content_area(GTK_WINDOW(window), w1, true, true, 0);
|
GTK: allow Event Log list box to grow vertically.
Now, when you resize the Event Log window, the list box grows in both
directions. Previously, as a side effect of the Columns-based layout,
it grew only horizontally.
I've arranged this by adding an extra wrinkle to the Columns layout
system, which allows you to tag _exactly one_ widget in the whole
container as the 'vexpand' widget. When the Columns is size-allocated
taller than its minimum height, the vexpand widget is given all the
extra space.
This technique ports naturally across all versions of GTK (since the
hard part is done in my own code). But it's limited: you can't set
more than one widget to be vexpand (which saves having to figure out
whether they're side by side and can expand in parallel, or vertically
separated and each have to get half the available extra space, etc).
And in complex layouts where the widget you really want to expand is
in a sub-Columns, there's no system for recursively searching down to
find it.
In other words, this is a one-shot bodge for the Event Log, and it
will want more work if we ever plan to extend it to list boxes in the
main config dialog.
2021-12-21 10:53:41 +00:00
|
|
|
{
|
|
|
|
struct uctrl *uc = dlg_find_byctrl(&es->dp, es->listctrl);
|
|
|
|
columns_vexpand(COLUMNS(w1), uc->toplevel);
|
|
|
|
}
|
2003-04-09 18:46:45 +00:00
|
|
|
gtk_widget_show(w1);
|
|
|
|
|
|
|
|
es->dp.data = es;
|
|
|
|
es->dp.shortcuts = &es->scs;
|
|
|
|
es->dp.lastfocus = NULL;
|
|
|
|
es->dp.retval = 0;
|
|
|
|
es->dp.window = window;
|
|
|
|
|
|
|
|
dlg_refresh(NULL, &es->dp);
|
|
|
|
|
|
|
|
if (parent) {
|
2003-04-10 08:53:43 +00:00
|
|
|
set_transient_window_pos(parent, window);
|
2019-09-08 19:29:00 +00:00
|
|
|
gtk_window_set_transient_for(GTK_WINDOW(window),
|
|
|
|
GTK_WINDOW(parent));
|
2003-04-09 18:46:45 +00:00
|
|
|
} else
|
2019-09-08 19:29:00 +00:00
|
|
|
gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
|
2003-04-09 18:46:45 +00:00
|
|
|
gtk_widget_show(window);
|
|
|
|
|
2015-08-08 16:29:02 +00:00
|
|
|
g_signal_connect(G_OBJECT(window), "destroy",
|
|
|
|
G_CALLBACK(eventlog_destroy), es);
|
|
|
|
g_signal_connect(G_OBJECT(window), "key_press_event",
|
|
|
|
G_CALLBACK(win_key_press), &es->dp);
|
|
|
|
g_signal_connect(G_OBJECT(window), "selection_get",
|
|
|
|
G_CALLBACK(eventlog_selection_get), es);
|
|
|
|
g_signal_connect(G_OBJECT(window), "selection_clear_event",
|
|
|
|
G_CALLBACK(eventlog_selection_clear), es);
|
2003-04-09 18:46:45 +00:00
|
|
|
}
|
|
|
|
|
2018-10-08 18:30:01 +00:00
|
|
|
eventlog_stuff *eventlogstuff_new(void)
|
2003-04-09 18:46:45 +00:00
|
|
|
{
|
2018-10-08 18:30:01 +00:00
|
|
|
eventlog_stuff *es = snew(eventlog_stuff);
|
2003-04-09 18:46:45 +00:00
|
|
|
memset(es, 0, sizeof(*es));
|
2018-12-01 09:35:52 +00:00
|
|
|
es->seldata = strbuf_new();
|
2003-04-09 18:46:45 +00:00
|
|
|
return es;
|
|
|
|
}
|
|
|
|
|
2018-10-08 18:30:01 +00:00
|
|
|
void eventlogstuff_free(eventlog_stuff *es)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (es->events_initial) {
|
|
|
|
for (i = 0; i < LOGEVENT_INITIAL_MAX; i++)
|
|
|
|
sfree(es->events_initial[i]);
|
|
|
|
sfree(es->events_initial);
|
|
|
|
}
|
|
|
|
if (es->events_circular) {
|
|
|
|
for (i = 0; i < LOGEVENT_CIRCULAR_MAX; i++)
|
|
|
|
sfree(es->events_circular[i]);
|
|
|
|
sfree(es->events_circular);
|
|
|
|
}
|
2018-12-01 09:35:52 +00:00
|
|
|
strbuf_free(es->seldata);
|
2018-10-08 18:30:01 +00:00
|
|
|
|
|
|
|
sfree(es);
|
|
|
|
}
|
|
|
|
|
|
|
|
void logevent_dlg(eventlog_stuff *es, const char *string)
|
2003-04-09 18:46:45 +00:00
|
|
|
{
|
|
|
|
char timebuf[40];
|
2005-01-09 14:27:48 +00:00
|
|
|
struct tm tm;
|
Don't grow logevent buf indefinitely
The PuTTY GUIs (Unix and Windows) maintain an in-memory event log
for display to users as they request. This uses ints for tracking
eventlog size, which is subject to memory exhaustion and (given
enough heap space) overflow attacks by servers (via, e.g., constant
rekeying).
Also a bounded log is more user-friendly. It is rare to want more
than the initial logging and the logging from a few recent rekey
events.
The Windows fix has been tested using Dr. Memory as a valgrind
substitute. No errors corresponding to the affected code showed up.
The Dr. Memory results.txt was split into a file per-error and then
grep Error $(grep -l windlg *)|cut -d: -f3-|sort |uniq -c
was used to compare. Differences arose from different usage of the GUI,
but no error could be traced to the code modified in this commit.
The Unix fix has been tested using valgrind. We don't destroy the
eventlog_stuff eventlog arrays, so we can't be entirely sure that we
don't leak more than we did before, but from code inspection it looks
like we don't (and anyways, if we leaked as much as before, just without
the integer overflow, well, that's still an improvement).
2013-07-22 23:09:04 +00:00
|
|
|
char **location;
|
|
|
|
size_t i;
|
2003-04-09 18:46:45 +00:00
|
|
|
|
Don't grow logevent buf indefinitely
The PuTTY GUIs (Unix and Windows) maintain an in-memory event log
for display to users as they request. This uses ints for tracking
eventlog size, which is subject to memory exhaustion and (given
enough heap space) overflow attacks by servers (via, e.g., constant
rekeying).
Also a bounded log is more user-friendly. It is rare to want more
than the initial logging and the logging from a few recent rekey
events.
The Windows fix has been tested using Dr. Memory as a valgrind
substitute. No errors corresponding to the affected code showed up.
The Dr. Memory results.txt was split into a file per-error and then
grep Error $(grep -l windlg *)|cut -d: -f3-|sort |uniq -c
was used to compare. Differences arose from different usage of the GUI,
but no error could be traced to the code modified in this commit.
The Unix fix has been tested using valgrind. We don't destroy the
eventlog_stuff eventlog arrays, so we can't be entirely sure that we
don't leak more than we did before, but from code inspection it looks
like we don't (and anyways, if we leaked as much as before, just without
the integer overflow, well, that's still an improvement).
2013-07-22 23:09:04 +00:00
|
|
|
if (es->ninitial == 0) {
|
|
|
|
es->events_initial = sresize(es->events_initial, LOGEVENT_INITIAL_MAX, char *);
|
|
|
|
for (i = 0; i < LOGEVENT_INITIAL_MAX; i++)
|
|
|
|
es->events_initial[i] = NULL;
|
|
|
|
es->events_circular = sresize(es->events_circular, LOGEVENT_CIRCULAR_MAX, char *);
|
|
|
|
for (i = 0; i < LOGEVENT_CIRCULAR_MAX; i++)
|
|
|
|
es->events_circular[i] = NULL;
|
2003-04-09 18:46:45 +00:00
|
|
|
}
|
|
|
|
|
Don't grow logevent buf indefinitely
The PuTTY GUIs (Unix and Windows) maintain an in-memory event log
for display to users as they request. This uses ints for tracking
eventlog size, which is subject to memory exhaustion and (given
enough heap space) overflow attacks by servers (via, e.g., constant
rekeying).
Also a bounded log is more user-friendly. It is rare to want more
than the initial logging and the logging from a few recent rekey
events.
The Windows fix has been tested using Dr. Memory as a valgrind
substitute. No errors corresponding to the affected code showed up.
The Dr. Memory results.txt was split into a file per-error and then
grep Error $(grep -l windlg *)|cut -d: -f3-|sort |uniq -c
was used to compare. Differences arose from different usage of the GUI,
but no error could be traced to the code modified in this commit.
The Unix fix has been tested using valgrind. We don't destroy the
eventlog_stuff eventlog arrays, so we can't be entirely sure that we
don't leak more than we did before, but from code inspection it looks
like we don't (and anyways, if we leaked as much as before, just without
the integer overflow, well, that's still an improvement).
2013-07-22 23:09:04 +00:00
|
|
|
if (es->ninitial < LOGEVENT_INITIAL_MAX)
|
|
|
|
location = &es->events_initial[es->ninitial];
|
|
|
|
else
|
|
|
|
location = &es->events_circular[(es->circular_first + es->ncircular) % LOGEVENT_CIRCULAR_MAX];
|
|
|
|
|
2005-01-09 14:27:48 +00:00
|
|
|
tm=ltime();
|
|
|
|
strftime(timebuf, sizeof(timebuf), "%Y-%m-%d %H:%M:%S\t", &tm);
|
2003-04-09 18:46:45 +00:00
|
|
|
|
Don't grow logevent buf indefinitely
The PuTTY GUIs (Unix and Windows) maintain an in-memory event log
for display to users as they request. This uses ints for tracking
eventlog size, which is subject to memory exhaustion and (given
enough heap space) overflow attacks by servers (via, e.g., constant
rekeying).
Also a bounded log is more user-friendly. It is rare to want more
than the initial logging and the logging from a few recent rekey
events.
The Windows fix has been tested using Dr. Memory as a valgrind
substitute. No errors corresponding to the affected code showed up.
The Dr. Memory results.txt was split into a file per-error and then
grep Error $(grep -l windlg *)|cut -d: -f3-|sort |uniq -c
was used to compare. Differences arose from different usage of the GUI,
but no error could be traced to the code modified in this commit.
The Unix fix has been tested using valgrind. We don't destroy the
eventlog_stuff eventlog arrays, so we can't be entirely sure that we
don't leak more than we did before, but from code inspection it looks
like we don't (and anyways, if we leaked as much as before, just without
the integer overflow, well, that's still an improvement).
2013-07-22 23:09:04 +00:00
|
|
|
sfree(*location);
|
Make dupcat() into a variadic macro.
Up until now, it's been a variadic _function_, whose argument list
consists of 'const char *' ASCIZ strings to concatenate, terminated by
one containing a null pointer. Now, that function is dupcat_fn(), and
it's wrapped by a C99 variadic _macro_ called dupcat(), which
automatically suffixes the null-pointer terminating argument.
This has three benefits. Firstly, it's just less effort at every call
site. Secondly, it protects against the risk of accidentally leaving
off the NULL, causing arbitrary words of stack memory to be
dereferenced as char pointers. And thirdly, it protects against the
more subtle risk of writing a bare 'NULL' as the terminating argument,
instead of casting it explicitly to a pointer. That last one is
necessary because C permits the macro NULL to expand to an integer
constant such as 0, so NULL by itself may not have pointer type, and
worse, it may not be marshalled in a variadic argument list in the
same way as a pointer. (For example, on a 64-bit machine it might only
occupy 32 bits. And yet, on another 64-bit platform, it might work
just fine, so that you don't notice the mistake!)
I was inspired to do this by happening to notice one of those bare
NULL terminators, and thinking I'd better check if there were any
more. Turned out there were quite a few. Now there are none.
2019-10-14 18:42:37 +00:00
|
|
|
*location = dupcat(timebuf, string);
|
2003-04-09 18:46:45 +00:00
|
|
|
if (es->window) {
|
2019-09-08 19:29:00 +00:00
|
|
|
dlg_listbox_add(es->listctrl, &es->dp, *location);
|
Don't grow logevent buf indefinitely
The PuTTY GUIs (Unix and Windows) maintain an in-memory event log
for display to users as they request. This uses ints for tracking
eventlog size, which is subject to memory exhaustion and (given
enough heap space) overflow attacks by servers (via, e.g., constant
rekeying).
Also a bounded log is more user-friendly. It is rare to want more
than the initial logging and the logging from a few recent rekey
events.
The Windows fix has been tested using Dr. Memory as a valgrind
substitute. No errors corresponding to the affected code showed up.
The Dr. Memory results.txt was split into a file per-error and then
grep Error $(grep -l windlg *)|cut -d: -f3-|sort |uniq -c
was used to compare. Differences arose from different usage of the GUI,
but no error could be traced to the code modified in this commit.
The Unix fix has been tested using valgrind. We don't destroy the
eventlog_stuff eventlog arrays, so we can't be entirely sure that we
don't leak more than we did before, but from code inspection it looks
like we don't (and anyways, if we leaked as much as before, just without
the integer overflow, well, that's still an improvement).
2013-07-22 23:09:04 +00:00
|
|
|
}
|
|
|
|
if (es->ninitial < LOGEVENT_INITIAL_MAX) {
|
|
|
|
es->ninitial++;
|
|
|
|
} else if (es->ncircular < LOGEVENT_CIRCULAR_MAX) {
|
|
|
|
es->ncircular++;
|
|
|
|
} else if (es->ncircular == LOGEVENT_CIRCULAR_MAX) {
|
|
|
|
es->circular_first = (es->circular_first + 1) % LOGEVENT_CIRCULAR_MAX;
|
|
|
|
sfree(es->events_circular[es->circular_first]);
|
|
|
|
es->events_circular[es->circular_first] = dupstr("..");
|
2003-04-09 18:46:45 +00:00
|
|
|
}
|
|
|
|
}
|
2003-04-11 18:44:05 +00:00
|
|
|
|
Richer data type for interactive prompt results.
All the seat functions that request an interactive prompt of some kind
to the user - both the main seat_get_userpass_input and the various
confirmation dialogs for things like host keys - were using a simple
int return value, with the general semantics of 0 = "fail", 1 =
"proceed" (and in the case of seat_get_userpass_input, answers to the
prompts were provided), and -1 = "request in progress, wait for a
callback".
In this commit I change all those functions' return types to a new
struct called SeatPromptResult, whose primary field is an enum
replacing those simple integer values.
The main purpose is that the enum has not three but _four_ values: the
"fail" result has been split into 'user abort' and 'software abort'.
The distinction is that a user abort occurs as a result of an
interactive UI action, such as the user clicking 'cancel' in a dialog
box or hitting ^D or ^C at a terminal password prompt - and therefore,
there's no need to display an error message telling the user that the
interactive operation has failed, because the user already knows,
because they _did_ it. 'Software abort' is from any other cause, where
PuTTY is the first to know there was a problem, and has to tell the
user.
We already had this 'user abort' vs 'software abort' distinction in
other parts of the code - the SSH backend has separate termination
functions which protocol layers can call. But we assumed that any
failure from an interactive prompt request fell into the 'user abort'
category, which is not true. A couple of examples: if you configure a
host key fingerprint in your saved session via the SSH > Host keys
pane, and the server presents a host key that doesn't match it, then
verify_ssh_host_key would report that the user had aborted the
connection, and feel no need to tell the user what had gone wrong!
Similarly, if a password provided on the command line was not
accepted, then (after I fixed the semantics of that in the previous
commit) the same wrong handling would occur.
So now, those Seat prompt functions too can communicate whether the
user or the software originated a connection abort. And in the latter
case, we also provide an error message to present to the user. Result:
in those two example cases (and others), error messages should no
longer go missing.
Implementation note: to avoid the hassle of having the error message
in a SeatPromptResult being a dynamically allocated string (and hence,
every recipient of one must always check whether it's non-NULL and
free it on every exit path, plus being careful about copying the
struct around), I've instead arranged that the structure contains a
function pointer and a couple of parameters, so that the string form
of the message can be constructed on demand. That way, the only users
who need to free it are the ones who actually _asked_ for it in the
first place, which is a much smaller set.
(This is one of the rare occasions that I regret not having C++'s
extra features available in this code base - a unique_ptr or
shared_ptr to a string would have been just the thing here, and the
compiler would have done all the hard work for me of remembering where
to insert the frees!)
2021-12-28 17:52:00 +00:00
|
|
|
struct simple_prompt_result_int_ctx {
|
|
|
|
void (*callback)(void *callback_ctx, int result);
|
|
|
|
void *callback_ctx;
|
|
|
|
Seat *seat;
|
|
|
|
enum DialogSlot dialog_slot;
|
|
|
|
};
|
|
|
|
|
|
|
|
static void simple_prompt_result_int_callback(void *vctx, int result)
|
|
|
|
{
|
|
|
|
struct simple_prompt_result_int_ctx *ctx =
|
|
|
|
(struct simple_prompt_result_int_ctx *)vctx;
|
|
|
|
|
|
|
|
unregister_dialog(ctx->seat, ctx->dialog_slot);
|
|
|
|
|
|
|
|
if (result >= 0)
|
|
|
|
ctx->callback(ctx->callback_ctx, result);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Clean up this context structure, whether or not a result was
|
|
|
|
* ever actually delivered from the dialog box.
|
|
|
|
*/
|
|
|
|
sfree(ctx);
|
|
|
|
}
|
|
|
|
|
New abstraction 'Seat', to pass to backends.
This is a new vtable-based abstraction which is passed to a backend in
place of Frontend, and it implements only the subset of the Frontend
functions needed by a backend. (Many other Frontend functions still
exist, notably the wide range of things called by terminal.c providing
platform-independent operations on the GUI terminal window.)
The purpose of making it a vtable is that this opens up the
possibility of creating a backend as an internal implementation detail
of some other activity, by providing just that one backend with a
custom Seat that implements the methods differently.
For example, this refactoring should make it feasible to directly
implement an SSH proxy type, aka the 'jump host' feature supported by
OpenSSH, aka 'open a secondary SSH session in MAINCHAN_DIRECT_TCP
mode, and then expose the main channel of that as the Socket for the
primary connection'. (Which of course you can already do by spawning
'plink -nc' as a separate proxy process, but this would permit it in
the _same_ process without anything getting confused.)
I've centralised a full set of stub methods in misc.c for the new
abstraction, which allows me to get rid of several annoying stubs in
the previous code. Also, while I'm here, I've moved a lot of
duplicated modalfatalbox() type functions from application main
program files into wincons.c / uxcons.c, which I think saves
duplication overall. (A minor visible effect is that the prefixes on
those console-based fatal error messages will now be more consistent
between applications.)
2018-10-11 18:58:42 +00:00
|
|
|
int gtkdlg_askappend(Seat *seat, Filename *filename,
|
Refactor the LogContext type.
LogContext is now the owner of the logevent() function that back ends
and so forth are constantly calling. Previously, logevent was owned by
the Frontend, which would store the message into its list for the GUI
Event Log dialog (or print it to standard error, or whatever) and then
pass it _back_ to LogContext to write to the currently open log file.
Now it's the other way round: LogContext gets the message from the
back end first, writes it to its log file if it feels so inclined, and
communicates it back to the front end.
This means that lots of parts of the back end system no longer need to
have a pointer to a full-on Frontend; the only thing they needed it
for was logging, so now they just have a LogContext (which many of
them had to have anyway, e.g. for logging SSH packets or session
traffic).
LogContext itself also doesn't get a full Frontend pointer any more:
it now talks back to the front end via a little vtable of its own
called LogPolicy, which contains the method that passes Event Log
entries through, the old askappend() function that decides whether to
truncate a pre-existing log file, and an emergency function for
printing an especially prominent message if the log file can't be
created. One minor nice effect of this is that console and GUI apps
can implement that last function subtly differently, so that Unix
console apps can write it with a plain \n instead of the \r\n
(harmless but inelegant) that the old centralised implementation
generated.
One other consequence of this is that the LogContext has to be
provided to backend_init() so that it's available to backends from the
instant of creation, rather than being provided via a separate API
call a couple of function calls later, because backends have typically
started doing things that need logging (like making network
connections) before the call to backend_provide_logctx. Fortunately,
there's no case in the whole code base where we don't already have
logctx by the time we make a backend (so I don't actually remember why
I ever delayed providing one). So that shortens the backend API by one
function, which is always nice.
While I'm tidying up, I've also moved the printf-style logeventf() and
the handy logevent_and_free() into logging.c, instead of having copies
of them scattered around other places. This has also let me remove
some stub functions from a couple of outlying applications like
Pageant. Finally, I've removed the pointless "_tag" at the end of
LogContext's official struct name.
2018-10-10 18:26:18 +00:00
|
|
|
void (*callback)(void *ctx, int result), void *ctx)
|
2003-04-11 18:44:05 +00:00
|
|
|
{
|
|
|
|
static const char msgtemplate[] =
|
2019-09-08 19:29:00 +00:00
|
|
|
"The session log file \"%.*s\" already exists. "
|
|
|
|
"You can overwrite it with a new session log, "
|
|
|
|
"append your session log to the end of it, "
|
|
|
|
"or disable session logging for this session.";
|
2017-11-26 14:05:02 +00:00
|
|
|
static const struct message_box_button button_array_append[] = {
|
|
|
|
{"Overwrite", 'o', 1, 2},
|
|
|
|
{"Append", 'a', 0, 1},
|
|
|
|
{"Disable", 'd', -1, 0},
|
|
|
|
};
|
|
|
|
static const struct message_box_buttons buttons_append = {
|
|
|
|
button_array_append, lenof(button_array_append),
|
|
|
|
};
|
|
|
|
|
2003-04-11 18:44:05 +00:00
|
|
|
char *message;
|
|
|
|
char *mbtitle;
|
Richer data type for interactive prompt results.
All the seat functions that request an interactive prompt of some kind
to the user - both the main seat_get_userpass_input and the various
confirmation dialogs for things like host keys - were using a simple
int return value, with the general semantics of 0 = "fail", 1 =
"proceed" (and in the case of seat_get_userpass_input, answers to the
prompts were provided), and -1 = "request in progress, wait for a
callback".
In this commit I change all those functions' return types to a new
struct called SeatPromptResult, whose primary field is an enum
replacing those simple integer values.
The main purpose is that the enum has not three but _four_ values: the
"fail" result has been split into 'user abort' and 'software abort'.
The distinction is that a user abort occurs as a result of an
interactive UI action, such as the user clicking 'cancel' in a dialog
box or hitting ^D or ^C at a terminal password prompt - and therefore,
there's no need to display an error message telling the user that the
interactive operation has failed, because the user already knows,
because they _did_ it. 'Software abort' is from any other cause, where
PuTTY is the first to know there was a problem, and has to tell the
user.
We already had this 'user abort' vs 'software abort' distinction in
other parts of the code - the SSH backend has separate termination
functions which protocol layers can call. But we assumed that any
failure from an interactive prompt request fell into the 'user abort'
category, which is not true. A couple of examples: if you configure a
host key fingerprint in your saved session via the SSH > Host keys
pane, and the server presents a host key that doesn't match it, then
verify_ssh_host_key would report that the user had aborted the
connection, and feel no need to tell the user what had gone wrong!
Similarly, if a password provided on the command line was not
accepted, then (after I fixed the semantics of that in the previous
commit) the same wrong handling would occur.
So now, those Seat prompt functions too can communicate whether the
user or the software originated a connection abort. And in the latter
case, we also provide an error message to present to the user. Result:
in those two example cases (and others), error messages should no
longer go missing.
Implementation note: to avoid the hassle of having the error message
in a SeatPromptResult being a dynamically allocated string (and hence,
every recipient of one must always check whether it's non-NULL and
free it on every exit path, plus being careful about copying the
struct around), I've instead arranged that the structure contains a
function pointer and a couple of parameters, so that the string form
of the message can be constructed on demand. That way, the only users
who need to free it are the ones who actually _asked_ for it in the
first place, which is a much smaller set.
(This is one of the rare occasions that I regret not having C++'s
extra features available in this code base - a unique_ptr or
shared_ptr to a string would have been just the thing here, and the
compiler would have done all the hard work for me of remembering where
to insert the frees!)
2021-12-28 17:52:00 +00:00
|
|
|
struct simple_prompt_result_int_ctx *result_ctx;
|
2017-11-26 16:56:03 +00:00
|
|
|
GtkWidget *mainwin, *msgbox;
|
2003-04-11 18:44:05 +00:00
|
|
|
|
2011-10-02 11:01:57 +00:00
|
|
|
message = dupprintf(msgtemplate, FILENAME_MAX, filename->path);
|
2003-04-11 18:44:05 +00:00
|
|
|
mbtitle = dupprintf("%s Log to File", appname);
|
|
|
|
|
Richer data type for interactive prompt results.
All the seat functions that request an interactive prompt of some kind
to the user - both the main seat_get_userpass_input and the various
confirmation dialogs for things like host keys - were using a simple
int return value, with the general semantics of 0 = "fail", 1 =
"proceed" (and in the case of seat_get_userpass_input, answers to the
prompts were provided), and -1 = "request in progress, wait for a
callback".
In this commit I change all those functions' return types to a new
struct called SeatPromptResult, whose primary field is an enum
replacing those simple integer values.
The main purpose is that the enum has not three but _four_ values: the
"fail" result has been split into 'user abort' and 'software abort'.
The distinction is that a user abort occurs as a result of an
interactive UI action, such as the user clicking 'cancel' in a dialog
box or hitting ^D or ^C at a terminal password prompt - and therefore,
there's no need to display an error message telling the user that the
interactive operation has failed, because the user already knows,
because they _did_ it. 'Software abort' is from any other cause, where
PuTTY is the first to know there was a problem, and has to tell the
user.
We already had this 'user abort' vs 'software abort' distinction in
other parts of the code - the SSH backend has separate termination
functions which protocol layers can call. But we assumed that any
failure from an interactive prompt request fell into the 'user abort'
category, which is not true. A couple of examples: if you configure a
host key fingerprint in your saved session via the SSH > Host keys
pane, and the server presents a host key that doesn't match it, then
verify_ssh_host_key would report that the user had aborted the
connection, and feel no need to tell the user what had gone wrong!
Similarly, if a password provided on the command line was not
accepted, then (after I fixed the semantics of that in the previous
commit) the same wrong handling would occur.
So now, those Seat prompt functions too can communicate whether the
user or the software originated a connection abort. And in the latter
case, we also provide an error message to present to the user. Result:
in those two example cases (and others), error messages should no
longer go missing.
Implementation note: to avoid the hassle of having the error message
in a SeatPromptResult being a dynamically allocated string (and hence,
every recipient of one must always check whether it's non-NULL and
free it on every exit path, plus being careful about copying the
struct around), I've instead arranged that the structure contains a
function pointer and a couple of parameters, so that the string form
of the message can be constructed on demand. That way, the only users
who need to free it are the ones who actually _asked_ for it in the
first place, which is a much smaller set.
(This is one of the rare occasions that I regret not having C++'s
extra features available in this code base - a unique_ptr or
shared_ptr to a string would have been just the thing here, and the
compiler would have done all the hard work for me of remembering where
to insert the frees!)
2021-12-28 17:52:00 +00:00
|
|
|
result_ctx = snew(struct simple_prompt_result_int_ctx);
|
2017-11-26 16:56:03 +00:00
|
|
|
result_ctx->callback = callback;
|
|
|
|
result_ctx->callback_ctx = ctx;
|
New abstraction 'Seat', to pass to backends.
This is a new vtable-based abstraction which is passed to a backend in
place of Frontend, and it implements only the subset of the Frontend
functions needed by a backend. (Many other Frontend functions still
exist, notably the wide range of things called by terminal.c providing
platform-independent operations on the GUI terminal window.)
The purpose of making it a vtable is that this opens up the
possibility of creating a backend as an internal implementation detail
of some other activity, by providing just that one backend with a
custom Seat that implements the methods differently.
For example, this refactoring should make it feasible to directly
implement an SSH proxy type, aka the 'jump host' feature supported by
OpenSSH, aka 'open a secondary SSH session in MAINCHAN_DIRECT_TCP
mode, and then expose the main channel of that as the Socket for the
primary connection'. (Which of course you can already do by spawning
'plink -nc' as a separate proxy process, but this would permit it in
the _same_ process without anything getting confused.)
I've centralised a full set of stub methods in misc.c for the new
abstraction, which allows me to get rid of several annoying stubs in
the previous code. Also, while I'm here, I've moved a lot of
duplicated modalfatalbox() type functions from application main
program files into wincons.c / uxcons.c, which I think saves
duplication overall. (A minor visible effect is that the prefixes on
those console-based fatal error messages will now be more consistent
between applications.)
2018-10-11 18:58:42 +00:00
|
|
|
result_ctx->seat = seat;
|
2017-11-26 16:56:03 +00:00
|
|
|
result_ctx->dialog_slot = DIALOG_SLOT_LOGFILE_PROMPT;
|
|
|
|
|
New abstraction 'Seat', to pass to backends.
This is a new vtable-based abstraction which is passed to a backend in
place of Frontend, and it implements only the subset of the Frontend
functions needed by a backend. (Many other Frontend functions still
exist, notably the wide range of things called by terminal.c providing
platform-independent operations on the GUI terminal window.)
The purpose of making it a vtable is that this opens up the
possibility of creating a backend as an internal implementation detail
of some other activity, by providing just that one backend with a
custom Seat that implements the methods differently.
For example, this refactoring should make it feasible to directly
implement an SSH proxy type, aka the 'jump host' feature supported by
OpenSSH, aka 'open a secondary SSH session in MAINCHAN_DIRECT_TCP
mode, and then expose the main channel of that as the Socket for the
primary connection'. (Which of course you can already do by spawning
'plink -nc' as a separate proxy process, but this would permit it in
the _same_ process without anything getting confused.)
I've centralised a full set of stub methods in misc.c for the new
abstraction, which allows me to get rid of several annoying stubs in
the previous code. Also, while I'm here, I've moved a lot of
duplicated modalfatalbox() type functions from application main
program files into wincons.c / uxcons.c, which I think saves
duplication overall. (A minor visible effect is that the prefixes on
those console-based fatal error messages will now be more consistent
between applications.)
2018-10-11 18:58:42 +00:00
|
|
|
mainwin = GTK_WIDGET(gtk_seat_get_window(seat));
|
2017-11-26 16:56:03 +00:00
|
|
|
msgbox = create_message_box(
|
|
|
|
mainwin, mbtitle, message,
|
|
|
|
string_width("LINE OF TEXT SUITABLE FOR THE ASKAPPEND WIDTH"),
|
Richer data type for interactive prompt results.
All the seat functions that request an interactive prompt of some kind
to the user - both the main seat_get_userpass_input and the various
confirmation dialogs for things like host keys - were using a simple
int return value, with the general semantics of 0 = "fail", 1 =
"proceed" (and in the case of seat_get_userpass_input, answers to the
prompts were provided), and -1 = "request in progress, wait for a
callback".
In this commit I change all those functions' return types to a new
struct called SeatPromptResult, whose primary field is an enum
replacing those simple integer values.
The main purpose is that the enum has not three but _four_ values: the
"fail" result has been split into 'user abort' and 'software abort'.
The distinction is that a user abort occurs as a result of an
interactive UI action, such as the user clicking 'cancel' in a dialog
box or hitting ^D or ^C at a terminal password prompt - and therefore,
there's no need to display an error message telling the user that the
interactive operation has failed, because the user already knows,
because they _did_ it. 'Software abort' is from any other cause, where
PuTTY is the first to know there was a problem, and has to tell the
user.
We already had this 'user abort' vs 'software abort' distinction in
other parts of the code - the SSH backend has separate termination
functions which protocol layers can call. But we assumed that any
failure from an interactive prompt request fell into the 'user abort'
category, which is not true. A couple of examples: if you configure a
host key fingerprint in your saved session via the SSH > Host keys
pane, and the server presents a host key that doesn't match it, then
verify_ssh_host_key would report that the user had aborted the
connection, and feel no need to tell the user what had gone wrong!
Similarly, if a password provided on the command line was not
accepted, then (after I fixed the semantics of that in the previous
commit) the same wrong handling would occur.
So now, those Seat prompt functions too can communicate whether the
user or the software originated a connection abort. And in the latter
case, we also provide an error message to present to the user. Result:
in those two example cases (and others), error messages should no
longer go missing.
Implementation note: to avoid the hassle of having the error message
in a SeatPromptResult being a dynamically allocated string (and hence,
every recipient of one must always check whether it's non-NULL and
free it on every exit path, plus being careful about copying the
struct around), I've instead arranged that the structure contains a
function pointer and a couple of parameters, so that the string form
of the message can be constructed on demand. That way, the only users
who need to free it are the ones who actually _asked_ for it in the
first place, which is a much smaller set.
(This is one of the rare occasions that I regret not having C++'s
extra features available in this code base - a unique_ptr or
shared_ptr to a string would have been just the thing here, and the
compiler would have done all the hard work for me of remembering where
to insert the frees!)
2021-12-28 17:52:00 +00:00
|
|
|
false, &buttons_append, simple_prompt_result_int_callback, result_ctx);
|
New abstraction 'Seat', to pass to backends.
This is a new vtable-based abstraction which is passed to a backend in
place of Frontend, and it implements only the subset of the Frontend
functions needed by a backend. (Many other Frontend functions still
exist, notably the wide range of things called by terminal.c providing
platform-independent operations on the GUI terminal window.)
The purpose of making it a vtable is that this opens up the
possibility of creating a backend as an internal implementation detail
of some other activity, by providing just that one backend with a
custom Seat that implements the methods differently.
For example, this refactoring should make it feasible to directly
implement an SSH proxy type, aka the 'jump host' feature supported by
OpenSSH, aka 'open a secondary SSH session in MAINCHAN_DIRECT_TCP
mode, and then expose the main channel of that as the Socket for the
primary connection'. (Which of course you can already do by spawning
'plink -nc' as a separate proxy process, but this would permit it in
the _same_ process without anything getting confused.)
I've centralised a full set of stub methods in misc.c for the new
abstraction, which allows me to get rid of several annoying stubs in
the previous code. Also, while I'm here, I've moved a lot of
duplicated modalfatalbox() type functions from application main
program files into wincons.c / uxcons.c, which I think saves
duplication overall. (A minor visible effect is that the prefixes on
those console-based fatal error messages will now be more consistent
between applications.)
2018-10-11 18:58:42 +00:00
|
|
|
register_dialog(seat, result_ctx->dialog_slot, msgbox);
|
2003-04-11 18:44:05 +00:00
|
|
|
|
|
|
|
sfree(message);
|
|
|
|
sfree(mbtitle);
|
|
|
|
|
2017-11-26 16:56:03 +00:00
|
|
|
return -1; /* dialog still in progress */
|
2003-04-11 18:44:05 +00:00
|
|
|
}
|
Initial support for host certificates.
Now we offer the OpenSSH certificate key types in our KEXINIT host key
algorithm list, so that if the server has a certificate, they can send
it to us.
There's a new storage.h abstraction for representing a list of trusted
host CAs, and which ones are trusted to certify hosts for what
domains. This is stored outside the normal saved session data, because
the whole point of host certificates is to avoid per-host faffing.
Configuring this set of trusted CAs is done via a new GUI dialog box,
separate from the main PuTTY config box (because it modifies a single
set of settings across all saved sessions), which you can launch by
clicking a button in the 'Host keys' pane. The GUI is pretty crude for
the moment, and very much at a 'just about usable' stage right now. It
will want some polishing.
If we have no CA configured that matches the hostname, we don't offer
to receive certified host keys in the first place. So for existing
users who haven't set any of this up yet, nothing will immediately
change.
Currently, if we do offer to receive certified host keys and the
server presents one signed by a CA we don't trust, PuTTY will bomb out
unconditionally with an error, instead of offering a confirmation box.
That's an unfinished part which I plan to fix before this goes into a
release.
2022-04-22 11:07:24 +00:00
|
|
|
|
|
|
|
struct ca_config_box {
|
|
|
|
GtkWidget *window;
|
|
|
|
struct controlbox *cb;
|
|
|
|
struct Shortcuts scs;
|
2022-05-01 07:22:44 +00:00
|
|
|
bool quit_main;
|
Initial support for host certificates.
Now we offer the OpenSSH certificate key types in our KEXINIT host key
algorithm list, so that if the server has a certificate, they can send
it to us.
There's a new storage.h abstraction for representing a list of trusted
host CAs, and which ones are trusted to certify hosts for what
domains. This is stored outside the normal saved session data, because
the whole point of host certificates is to avoid per-host faffing.
Configuring this set of trusted CAs is done via a new GUI dialog box,
separate from the main PuTTY config box (because it modifies a single
set of settings across all saved sessions), which you can launch by
clicking a button in the 'Host keys' pane. The GUI is pretty crude for
the moment, and very much at a 'just about usable' stage right now. It
will want some polishing.
If we have no CA configured that matches the hostname, we don't offer
to receive certified host keys in the first place. So for existing
users who haven't set any of this up yet, nothing will immediately
change.
Currently, if we do offer to receive certified host keys and the
server presents one signed by a CA we don't trust, PuTTY will bomb out
unconditionally with an error, instead of offering a confirmation box.
That's an unfinished part which I plan to fix before this goes into a
release.
2022-04-22 11:07:24 +00:00
|
|
|
dlgparam dp;
|
|
|
|
};
|
|
|
|
static struct ca_config_box *cacfg; /* one of these, cross-instance */
|
|
|
|
|
|
|
|
static void cacfg_destroy(GtkWidget *widget, gpointer data)
|
|
|
|
{
|
|
|
|
cacfg->window = NULL;
|
|
|
|
dlg_cleanup(&cacfg->dp);
|
|
|
|
ctrl_free_box(cacfg->cb);
|
|
|
|
cacfg->cb = NULL;
|
2022-05-01 07:22:44 +00:00
|
|
|
if (cacfg->quit_main)
|
|
|
|
gtk_main_quit();
|
Initial support for host certificates.
Now we offer the OpenSSH certificate key types in our KEXINIT host key
algorithm list, so that if the server has a certificate, they can send
it to us.
There's a new storage.h abstraction for representing a list of trusted
host CAs, and which ones are trusted to certify hosts for what
domains. This is stored outside the normal saved session data, because
the whole point of host certificates is to avoid per-host faffing.
Configuring this set of trusted CAs is done via a new GUI dialog box,
separate from the main PuTTY config box (because it modifies a single
set of settings across all saved sessions), which you can launch by
clicking a button in the 'Host keys' pane. The GUI is pretty crude for
the moment, and very much at a 'just about usable' stage right now. It
will want some polishing.
If we have no CA configured that matches the hostname, we don't offer
to receive certified host keys in the first place. So for existing
users who haven't set any of this up yet, nothing will immediately
change.
Currently, if we do offer to receive certified host keys and the
server presents one signed by a CA we don't trust, PuTTY will bomb out
unconditionally with an error, instead of offering a confirmation box.
That's an unfinished part which I plan to fix before this goes into a
release.
2022-04-22 11:07:24 +00:00
|
|
|
}
|
2022-05-01 07:22:44 +00:00
|
|
|
static void make_ca_config_box(GtkWidget *spawning_window)
|
Initial support for host certificates.
Now we offer the OpenSSH certificate key types in our KEXINIT host key
algorithm list, so that if the server has a certificate, they can send
it to us.
There's a new storage.h abstraction for representing a list of trusted
host CAs, and which ones are trusted to certify hosts for what
domains. This is stored outside the normal saved session data, because
the whole point of host certificates is to avoid per-host faffing.
Configuring this set of trusted CAs is done via a new GUI dialog box,
separate from the main PuTTY config box (because it modifies a single
set of settings across all saved sessions), which you can launch by
clicking a button in the 'Host keys' pane. The GUI is pretty crude for
the moment, and very much at a 'just about usable' stage right now. It
will want some polishing.
If we have no CA configured that matches the hostname, we don't offer
to receive certified host keys in the first place. So for existing
users who haven't set any of this up yet, nothing will immediately
change.
Currently, if we do offer to receive certified host keys and the
server presents one signed by a CA we don't trust, PuTTY will bomb out
unconditionally with an error, instead of offering a confirmation box.
That's an unfinished part which I plan to fix before this goes into a
release.
2022-04-22 11:07:24 +00:00
|
|
|
{
|
|
|
|
if (!cacfg) {
|
|
|
|
cacfg = snew(struct ca_config_box);
|
|
|
|
memset(cacfg, 0, sizeof(*cacfg));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (cacfg->window) {
|
|
|
|
/* This dialog box is already displayed; re-focus it */
|
|
|
|
gtk_widget_grab_focus(cacfg->window);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
dlg_init(&cacfg->dp);
|
|
|
|
for (size_t i = 0; i < lenof(cacfg->scs.sc); i++) {
|
|
|
|
cacfg->scs.sc[i].action = SHORTCUT_EMPTY;
|
|
|
|
}
|
|
|
|
|
|
|
|
cacfg->cb = ctrl_new_box();
|
|
|
|
setup_ca_config_box(cacfg->cb);
|
|
|
|
|
|
|
|
cacfg->window = our_dialog_new();
|
|
|
|
gtk_window_set_title(GTK_WINDOW(cacfg->window),
|
|
|
|
"PuTTY trusted host certification authorities");
|
|
|
|
gtk_widget_set_size_request(
|
|
|
|
cacfg->window, string_width(
|
|
|
|
"ecdsa-sha2-nistp256 256 SHA256:hsO5a8MYGzBoa2gW5"
|
|
|
|
"dLV2vl7bTnCPjw64x3kLkz6BY8"), -1);
|
|
|
|
|
|
|
|
/* Set up everything else */
|
|
|
|
for (int i = 0; i < cacfg->cb->nctrlsets; i++) {
|
|
|
|
struct controlset *s = cacfg->cb->ctrlsets[i];
|
|
|
|
GtkWidget *w = layout_ctrls(&cacfg->dp, NULL, &cacfg->scs, s,
|
|
|
|
GTK_WINDOW(cacfg->window));
|
|
|
|
gtk_container_set_border_width(GTK_CONTAINER(w), 10);
|
|
|
|
gtk_widget_show(w);
|
|
|
|
|
|
|
|
if (!*s->pathname) {
|
|
|
|
our_dialog_set_action_area(GTK_WINDOW(cacfg->window), w);
|
|
|
|
} else {
|
|
|
|
our_dialog_add_to_content_area(GTK_WINDOW(cacfg->window), w,
|
|
|
|
true, true, 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
cacfg->dp.data = cacfg;
|
|
|
|
cacfg->dp.shortcuts = &cacfg->scs;
|
|
|
|
cacfg->dp.lastfocus = NULL;
|
|
|
|
cacfg->dp.retval = 0;
|
|
|
|
cacfg->dp.window = cacfg->window;
|
|
|
|
|
|
|
|
dlg_refresh(NULL, &cacfg->dp);
|
|
|
|
|
2022-05-01 07:22:44 +00:00
|
|
|
if (spawning_window) {
|
|
|
|
set_transient_window_pos(spawning_window, cacfg->window);
|
Initial support for host certificates.
Now we offer the OpenSSH certificate key types in our KEXINIT host key
algorithm list, so that if the server has a certificate, they can send
it to us.
There's a new storage.h abstraction for representing a list of trusted
host CAs, and which ones are trusted to certify hosts for what
domains. This is stored outside the normal saved session data, because
the whole point of host certificates is to avoid per-host faffing.
Configuring this set of trusted CAs is done via a new GUI dialog box,
separate from the main PuTTY config box (because it modifies a single
set of settings across all saved sessions), which you can launch by
clicking a button in the 'Host keys' pane. The GUI is pretty crude for
the moment, and very much at a 'just about usable' stage right now. It
will want some polishing.
If we have no CA configured that matches the hostname, we don't offer
to receive certified host keys in the first place. So for existing
users who haven't set any of this up yet, nothing will immediately
change.
Currently, if we do offer to receive certified host keys and the
server presents one signed by a CA we don't trust, PuTTY will bomb out
unconditionally with an error, instead of offering a confirmation box.
That's an unfinished part which I plan to fix before this goes into a
release.
2022-04-22 11:07:24 +00:00
|
|
|
} else {
|
|
|
|
gtk_window_set_position(GTK_WINDOW(cacfg->window), GTK_WIN_POS_CENTER);
|
|
|
|
}
|
|
|
|
gtk_widget_show(cacfg->window);
|
|
|
|
|
|
|
|
g_signal_connect(G_OBJECT(cacfg->window), "destroy",
|
|
|
|
G_CALLBACK(cacfg_destroy), NULL);
|
|
|
|
g_signal_connect(G_OBJECT(cacfg->window), "key_press_event",
|
|
|
|
G_CALLBACK(win_key_press), &cacfg->dp);
|
|
|
|
}
|
2022-05-01 07:22:44 +00:00
|
|
|
|
|
|
|
void show_ca_config_box(dlgparam *dp)
|
|
|
|
{
|
|
|
|
make_ca_config_box(dp ? dp->window : NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
void show_ca_config_box_synchronously(void)
|
|
|
|
{
|
|
|
|
make_ca_config_box(NULL);
|
|
|
|
cacfg->quit_main = true;
|
|
|
|
gtk_main();
|
|
|
|
}
|