2015-05-13 12:55:08 +00:00
|
|
|
/*
|
|
|
|
* GTK implementation of a GUI password/passphrase prompt.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <assert.h>
|
|
|
|
#include <time.h>
|
|
|
|
#include <stdlib.h>
|
2015-08-08 14:04:28 +00:00
|
|
|
|
|
|
|
#include <unistd.h>
|
|
|
|
|
2015-05-13 12:55:08 +00:00
|
|
|
#include <gtk/gtk.h>
|
2015-08-08 14:06:15 +00:00
|
|
|
#include <gdk/gdk.h>
|
|
|
|
#if !GTK_CHECK_VERSION(3,0,0)
|
2015-05-13 12:55:08 +00:00
|
|
|
#include <gdk/gdkkeysyms.h>
|
2015-08-08 14:06:15 +00:00
|
|
|
#endif
|
2015-05-13 12:55:08 +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
|
|
|
#include "defs.h"
|
2021-04-23 05:19:05 +00:00
|
|
|
#include "unifont.h"
|
2015-08-08 14:04:28 +00:00
|
|
|
#include "gtkcompat.h"
|
2015-08-31 14:45:18 +00:00
|
|
|
#include "gtkmisc.h"
|
2015-08-08 14:04:28 +00:00
|
|
|
|
2019-05-05 19:22:36 +00:00
|
|
|
#include "putty.h"
|
|
|
|
#include "ssh.h"
|
2015-05-13 12:55:08 +00:00
|
|
|
#include "misc.h"
|
|
|
|
|
|
|
|
#define N_DRAWING_AREAS 3
|
|
|
|
|
|
|
|
struct drawing_area_ctx {
|
|
|
|
GtkWidget *area;
|
Refactor the GTK drawing system to do both GDK and Cairo.
We're going to have to use Cairo in the GTK3 port, because that's all
GTK3 supports; but we still need old-style GDK for GTK1 support, and
also for performance reasons in GTK2 (see below). Hence, this change
completely restructures GTK PuTTY's drawing code so that there's a
central 'drawing context' structure which contains a type code
indicating GDK or Cairo, and then either some GDK gubbins or some
Cairo gubbins as appropriate; all actual drawing is abstracted through
a set of routines which test the type code in that structure and do
one thing or another. And because the type code is tested at run time,
both sets of drawing primitives can be compiled in at once, and where
possible, they will be.
X server-side bitmap fonts are still supported in the Cairo world, but
because Cairo drawing is entirely client-side, they have to work by
cheekily downloading each glyph bitmap from the server when it's first
needed, and building up a client-side cache of 'cairo_surface_t's
containing the bitmaps with which we then draw on the window. This
technique works, but it's rather slow; hence, even in GTK2, we keep
the GDK drawing back end compiled in, and switch over to it when the
main selected font is a bitmap one.
One visible effect of the new Cairo routines is in the double-width
and double-height text you can get by sending ESC # 3, ESC # 4 and
ESC # 6 escape sequences. In GDK, that's always been done by a really
horrible process of manually scaling the bitmap, server-side, column
by column and row by row, causing each pixel to be exactly doubled or
quadrupled. But in Cairo, we can just set a transformation matrix, and
then that takes effect _before_ the scalable fonts are rendered - so
the results are visibly nicer, and use all the available resolution.
(Sadly, if you're using a server-side bitmap font as your primary one,
then the GDK backend will be selected for all drawing in the terminal
as a whole - so in that situation, even fallback characters absent
from the primary font and rendered by Pango will get the old GDK
scaling treatment. It's only if your main font is scalable, so that
the Cairo backend is selected, that DW/DH characters will come out
looking nice.)
2015-08-15 20:05:56 +00:00
|
|
|
#ifndef DRAW_DEFAULT_CAIRO
|
2015-05-13 12:55:08 +00:00
|
|
|
GdkColor *cols;
|
Refactor the GTK drawing system to do both GDK and Cairo.
We're going to have to use Cairo in the GTK3 port, because that's all
GTK3 supports; but we still need old-style GDK for GTK1 support, and
also for performance reasons in GTK2 (see below). Hence, this change
completely restructures GTK PuTTY's drawing code so that there's a
central 'drawing context' structure which contains a type code
indicating GDK or Cairo, and then either some GDK gubbins or some
Cairo gubbins as appropriate; all actual drawing is abstracted through
a set of routines which test the type code in that structure and do
one thing or another. And because the type code is tested at run time,
both sets of drawing primitives can be compiled in at once, and where
possible, they will be.
X server-side bitmap fonts are still supported in the Cairo world, but
because Cairo drawing is entirely client-side, they have to work by
cheekily downloading each glyph bitmap from the server when it's first
needed, and building up a client-side cache of 'cairo_surface_t's
containing the bitmaps with which we then draw on the window. This
technique works, but it's rather slow; hence, even in GTK2, we keep
the GDK drawing back end compiled in, and switch over to it when the
main selected font is a bitmap one.
One visible effect of the new Cairo routines is in the double-width
and double-height text you can get by sending ESC # 3, ESC # 4 and
ESC # 6 escape sequences. In GDK, that's always been done by a really
horrible process of manually scaling the bitmap, server-side, column
by column and row by row, causing each pixel to be exactly doubled or
quadrupled. But in Cairo, we can just set a transformation matrix, and
then that takes effect _before_ the scalable fonts are rendered - so
the results are visibly nicer, and use all the available resolution.
(Sadly, if you're using a server-side bitmap font as your primary one,
then the GDK backend will be selected for all drawing in the terminal
as a whole - so in that situation, even fallback characters absent
from the primary font and rendered by Pango will get the old GDK
scaling treatment. It's only if your main font is scalable, so that
the Cairo backend is selected, that DW/DH characters will come out
looking nice.)
2015-08-15 20:05:56 +00:00
|
|
|
#endif
|
2018-05-13 21:56:52 +00:00
|
|
|
int width, height;
|
|
|
|
enum { NOT_CURRENT, CURRENT, GREYED_OUT } state;
|
2015-05-13 12:55:08 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
struct askpass_ctx {
|
|
|
|
GtkWidget *dialog, *promptlabel;
|
|
|
|
struct drawing_area_ctx drawingareas[N_DRAWING_AREAS];
|
|
|
|
int active_area;
|
2015-08-08 14:04:28 +00:00
|
|
|
#if GTK_CHECK_VERSION(2,0,0)
|
2015-05-13 12:55:08 +00:00
|
|
|
GtkIMContext *imc;
|
2015-08-08 14:04:28 +00:00
|
|
|
#endif
|
Refactor the GTK drawing system to do both GDK and Cairo.
We're going to have to use Cairo in the GTK3 port, because that's all
GTK3 supports; but we still need old-style GDK for GTK1 support, and
also for performance reasons in GTK2 (see below). Hence, this change
completely restructures GTK PuTTY's drawing code so that there's a
central 'drawing context' structure which contains a type code
indicating GDK or Cairo, and then either some GDK gubbins or some
Cairo gubbins as appropriate; all actual drawing is abstracted through
a set of routines which test the type code in that structure and do
one thing or another. And because the type code is tested at run time,
both sets of drawing primitives can be compiled in at once, and where
possible, they will be.
X server-side bitmap fonts are still supported in the Cairo world, but
because Cairo drawing is entirely client-side, they have to work by
cheekily downloading each glyph bitmap from the server when it's first
needed, and building up a client-side cache of 'cairo_surface_t's
containing the bitmaps with which we then draw on the window. This
technique works, but it's rather slow; hence, even in GTK2, we keep
the GDK drawing back end compiled in, and switch over to it when the
main selected font is a bitmap one.
One visible effect of the new Cairo routines is in the double-width
and double-height text you can get by sending ESC # 3, ESC # 4 and
ESC # 6 escape sequences. In GDK, that's always been done by a really
horrible process of manually scaling the bitmap, server-side, column
by column and row by row, causing each pixel to be exactly doubled or
quadrupled. But in Cairo, we can just set a transformation matrix, and
then that takes effect _before_ the scalable fonts are rendered - so
the results are visibly nicer, and use all the available resolution.
(Sadly, if you're using a server-side bitmap font as your primary one,
then the GDK backend will be selected for all drawing in the terminal
as a whole - so in that situation, even fallback characters absent
from the primary font and rendered by Pango will get the old GDK
scaling treatment. It's only if your main font is scalable, so that
the Cairo backend is selected, that DW/DH characters will come out
looking nice.)
2015-08-15 20:05:56 +00:00
|
|
|
#ifndef DRAW_DEFAULT_CAIRO
|
2015-05-13 12:55:08 +00:00
|
|
|
GdkColormap *colmap;
|
2018-05-13 21:56:52 +00:00
|
|
|
GdkColor cols[3];
|
Refactor the GTK drawing system to do both GDK and Cairo.
We're going to have to use Cairo in the GTK3 port, because that's all
GTK3 supports; but we still need old-style GDK for GTK1 support, and
also for performance reasons in GTK2 (see below). Hence, this change
completely restructures GTK PuTTY's drawing code so that there's a
central 'drawing context' structure which contains a type code
indicating GDK or Cairo, and then either some GDK gubbins or some
Cairo gubbins as appropriate; all actual drawing is abstracted through
a set of routines which test the type code in that structure and do
one thing or another. And because the type code is tested at run time,
both sets of drawing primitives can be compiled in at once, and where
possible, they will be.
X server-side bitmap fonts are still supported in the Cairo world, but
because Cairo drawing is entirely client-side, they have to work by
cheekily downloading each glyph bitmap from the server when it's first
needed, and building up a client-side cache of 'cairo_surface_t's
containing the bitmaps with which we then draw on the window. This
technique works, but it's rather slow; hence, even in GTK2, we keep
the GDK drawing back end compiled in, and switch over to it when the
main selected font is a bitmap one.
One visible effect of the new Cairo routines is in the double-width
and double-height text you can get by sending ESC # 3, ESC # 4 and
ESC # 6 escape sequences. In GDK, that's always been done by a really
horrible process of manually scaling the bitmap, server-side, column
by column and row by row, causing each pixel to be exactly doubled or
quadrupled. But in Cairo, we can just set a transformation matrix, and
then that takes effect _before_ the scalable fonts are rendered - so
the results are visibly nicer, and use all the available resolution.
(Sadly, if you're using a server-side bitmap font as your primary one,
then the GDK backend will be selected for all drawing in the terminal
as a whole - so in that situation, even fallback characters absent
from the primary font and rendered by Pango will get the old GDK
scaling treatment. It's only if your main font is scalable, so that
the Cairo backend is selected, that DW/DH characters will come out
looking nice.)
2015-08-15 20:05:56 +00:00
|
|
|
#endif
|
2018-05-13 21:56:52 +00:00
|
|
|
char *error_message; /* if we finish without a passphrase */
|
2022-09-13 14:00:26 +00:00
|
|
|
strbuf *passphrase; /* if we finish with one */
|
2016-04-04 10:21:54 +00:00
|
|
|
#if GTK_CHECK_VERSION(3,20,0)
|
|
|
|
GdkSeat *seat; /* for gdk_seat_grab */
|
|
|
|
#elif GTK_CHECK_VERSION(3,0,0)
|
2015-08-16 13:36:32 +00:00
|
|
|
GdkDevice *keyboard; /* for gdk_device_grab */
|
|
|
|
#endif
|
2018-05-13 21:56:52 +00:00
|
|
|
|
|
|
|
int nattempts;
|
2015-05-13 12:55:08 +00:00
|
|
|
};
|
|
|
|
|
2019-05-05 19:22:36 +00:00
|
|
|
static prng *keypress_prng = NULL;
|
|
|
|
static void feed_keypress_prng(void *data, int size)
|
|
|
|
{
|
|
|
|
put_data(keypress_prng, data, size);
|
|
|
|
}
|
|
|
|
void random_add_noise(NoiseSourceId source, const void *noise, int length)
|
|
|
|
{
|
|
|
|
if (keypress_prng)
|
|
|
|
prng_add_entropy(keypress_prng, source, make_ptrlen(noise, length));
|
|
|
|
}
|
|
|
|
static void setup_keypress_prng(void)
|
|
|
|
{
|
|
|
|
keypress_prng = prng_new(&ssh_sha256);
|
|
|
|
prng_seed_begin(keypress_prng);
|
|
|
|
noise_get_heavy(feed_keypress_prng);
|
|
|
|
prng_seed_finish(keypress_prng);
|
|
|
|
}
|
|
|
|
static void cleanup_keypress_prng(void)
|
|
|
|
{
|
|
|
|
prng_free(keypress_prng);
|
|
|
|
}
|
2019-07-23 17:40:09 +00:00
|
|
|
static uint64_t keypress_prng_value(void)
|
2019-05-05 19:22:36 +00:00
|
|
|
{
|
2019-05-05 19:43:16 +00:00
|
|
|
/*
|
|
|
|
* Don't actually put the passphrase keystrokes themselves into
|
|
|
|
* the PRNG; that doesn't seem like the course of wisdom when
|
|
|
|
* that's precisely what the information displayed on the screen
|
|
|
|
* is trying _not_ to be correlated to.
|
|
|
|
*/
|
|
|
|
noise_ultralight(NOISE_SOURCE_KEY, 0);
|
2019-05-05 19:22:36 +00:00
|
|
|
uint8_t data[8];
|
|
|
|
prng_read(keypress_prng, data, 8);
|
2019-07-23 17:40:09 +00:00
|
|
|
return GET_64BIT_MSB_FIRST(data);
|
|
|
|
}
|
|
|
|
static int choose_new_area(int prev_area)
|
|
|
|
{
|
|
|
|
int reduced = keypress_prng_value() % (N_DRAWING_AREAS - 1);
|
2019-05-05 19:22:36 +00:00
|
|
|
return (prev_area + 1 + reduced) % N_DRAWING_AREAS;
|
|
|
|
}
|
|
|
|
|
2015-05-13 12:55:08 +00:00
|
|
|
static void visually_acknowledge_keypress(struct askpass_ctx *ctx)
|
|
|
|
{
|
2019-05-05 19:22:36 +00:00
|
|
|
int new_active = choose_new_area(ctx->active_area);
|
2018-05-13 21:56:52 +00:00
|
|
|
ctx->drawingareas[ctx->active_area].state = NOT_CURRENT;
|
2015-05-13 12:55:08 +00:00
|
|
|
gtk_widget_queue_draw(ctx->drawingareas[ctx->active_area].area);
|
2018-05-13 21:56:52 +00:00
|
|
|
ctx->drawingareas[new_active].state = CURRENT;
|
2015-05-13 12:55:08 +00:00
|
|
|
gtk_widget_queue_draw(ctx->drawingareas[new_active].area);
|
|
|
|
ctx->active_area = new_active;
|
|
|
|
}
|
|
|
|
|
2022-09-13 14:00:26 +00:00
|
|
|
static size_t last_char_start(struct askpass_ctx *ctx)
|
2015-05-13 12:55:08 +00:00
|
|
|
{
|
|
|
|
/*
|
|
|
|
* GTK always encodes in UTF-8, so we can do this in a fixed way.
|
|
|
|
*/
|
2022-09-13 14:00:26 +00:00
|
|
|
assert(ctx->passphrase->len > 0);
|
|
|
|
size_t i = ctx->passphrase->len - 1;
|
|
|
|
while ((unsigned)(ctx->passphrase->u[i] - 0x80) < 0x40) {
|
2015-05-13 12:55:08 +00:00
|
|
|
if (i == 0)
|
|
|
|
break;
|
|
|
|
i--;
|
|
|
|
}
|
2022-09-13 14:00:26 +00:00
|
|
|
return i;
|
2015-05-13 12:55:08 +00:00
|
|
|
}
|
|
|
|
|
2015-08-08 14:04:28 +00:00
|
|
|
static void add_text_to_passphrase(struct askpass_ctx *ctx, gchar *str)
|
|
|
|
{
|
2022-09-13 14:00:26 +00:00
|
|
|
put_datapl(ctx->passphrase, ptrlen_from_asciz(str));
|
2015-08-08 14:04:28 +00:00
|
|
|
visually_acknowledge_keypress(ctx);
|
|
|
|
}
|
|
|
|
|
2021-04-05 16:48:30 +00:00
|
|
|
static void cancel_askpass(struct askpass_ctx *ctx, const char *msg)
|
|
|
|
{
|
2022-09-13 14:00:26 +00:00
|
|
|
strbuf_free(ctx->passphrase);
|
2021-04-05 16:48:30 +00:00
|
|
|
ctx->passphrase = NULL;
|
|
|
|
ctx->error_message = dupstr(msg);
|
|
|
|
gtk_main_quit();
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean askpass_dialog_closed(GtkWidget *widget, GdkEvent *event,
|
|
|
|
gpointer data)
|
|
|
|
{
|
|
|
|
struct askpass_ctx *ctx = (struct askpass_ctx *)data;
|
|
|
|
cancel_askpass(ctx, "passphrase input cancelled");
|
|
|
|
/* Don't destroy dialog yet, so gtk_askpass_cleanup() can do its work */
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2015-05-13 12:55:08 +00:00
|
|
|
static gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data)
|
|
|
|
{
|
|
|
|
struct askpass_ctx *ctx = (struct askpass_ctx *)data;
|
2015-08-08 14:04:28 +00:00
|
|
|
|
2015-08-08 15:23:54 +00:00
|
|
|
if (event->keyval == GDK_KEY_Return &&
|
|
|
|
event->type == GDK_KEY_PRESS) {
|
2015-05-13 12:55:08 +00:00
|
|
|
gtk_main_quit();
|
2015-08-08 15:23:54 +00:00
|
|
|
} else if (event->keyval == GDK_KEY_Escape &&
|
|
|
|
event->type == GDK_KEY_PRESS) {
|
2021-04-05 16:48:30 +00:00
|
|
|
cancel_askpass(ctx, "passphrase input cancelled");
|
2015-05-13 12:55:08 +00:00
|
|
|
} else {
|
2015-08-08 14:04:28 +00:00
|
|
|
#if GTK_CHECK_VERSION(2,0,0)
|
2015-05-13 12:55:08 +00:00
|
|
|
if (gtk_im_context_filter_keypress(ctx->imc, event))
|
2018-10-29 19:50:29 +00:00
|
|
|
return true;
|
2015-08-08 14:04:28 +00:00
|
|
|
#endif
|
2015-05-13 12:55:08 +00:00
|
|
|
|
|
|
|
if (event->type == GDK_KEY_PRESS) {
|
|
|
|
if (!strcmp(event->string, "\x15")) {
|
|
|
|
/* Ctrl-U. Wipe out the whole line */
|
2022-09-13 14:00:26 +00:00
|
|
|
strbuf_clear(ctx->passphrase);
|
2015-05-13 12:55:08 +00:00
|
|
|
visually_acknowledge_keypress(ctx);
|
|
|
|
} else if (!strcmp(event->string, "\x17")) {
|
|
|
|
/* Ctrl-W. Delete back to the last space->nonspace
|
|
|
|
* boundary. We interpret 'space' in a really simple
|
|
|
|
* way (mimicking terminal drivers), and don't attempt
|
|
|
|
* to second-guess exciting Unicode space
|
|
|
|
* characters. */
|
2022-09-13 14:00:26 +00:00
|
|
|
while (ctx->passphrase->len > 0) {
|
2015-05-13 12:55:08 +00:00
|
|
|
char deleted, prior;
|
2022-09-13 14:00:26 +00:00
|
|
|
size_t newlen = last_char_start(ctx);
|
|
|
|
deleted = ctx->passphrase->s[newlen];
|
|
|
|
strbuf_shrink_to(ctx->passphrase, newlen);
|
|
|
|
prior = (ctx->passphrase->len == 0 ? ' ' :
|
|
|
|
ctx->passphrase->s[ctx->passphrase->len-1]);
|
2015-05-13 12:55:08 +00:00
|
|
|
if (!g_ascii_isspace(deleted) && g_ascii_isspace(prior))
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
visually_acknowledge_keypress(ctx);
|
2015-08-08 15:23:54 +00:00
|
|
|
} else if (event->keyval == GDK_KEY_BackSpace) {
|
2015-05-13 12:55:08 +00:00
|
|
|
/* Backspace. Delete one character. */
|
2022-09-13 14:00:26 +00:00
|
|
|
if (ctx->passphrase->len > 0)
|
|
|
|
strbuf_shrink_to(ctx->passphrase, last_char_start(ctx));
|
2015-05-13 12:55:08 +00:00
|
|
|
visually_acknowledge_keypress(ctx);
|
2015-08-08 14:04:28 +00:00
|
|
|
#if !GTK_CHECK_VERSION(2,0,0)
|
|
|
|
} else if (event->string[0]) {
|
|
|
|
add_text_to_passphrase(ctx, event->string);
|
|
|
|
#endif
|
2015-05-13 12:55:08 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2018-10-29 19:50:29 +00:00
|
|
|
return true;
|
2015-05-13 12:55:08 +00:00
|
|
|
}
|
|
|
|
|
2015-08-08 14:04:28 +00:00
|
|
|
#if GTK_CHECK_VERSION(2,0,0)
|
2015-05-13 12:55:08 +00:00
|
|
|
static void input_method_commit_event(GtkIMContext *imc, gchar *str,
|
|
|
|
gpointer data)
|
|
|
|
{
|
|
|
|
struct askpass_ctx *ctx = (struct askpass_ctx *)data;
|
2015-08-08 14:04:28 +00:00
|
|
|
add_text_to_passphrase(ctx, str);
|
2015-05-13 12:55:08 +00:00
|
|
|
}
|
2015-08-08 14:04:28 +00:00
|
|
|
#endif
|
2015-05-13 12:55:08 +00:00
|
|
|
|
|
|
|
static gint configure_area(GtkWidget *widget, GdkEventConfigure *event,
|
|
|
|
gpointer data)
|
|
|
|
{
|
|
|
|
struct drawing_area_ctx *ctx = (struct drawing_area_ctx *)data;
|
|
|
|
ctx->width = event->width;
|
|
|
|
ctx->height = event->height;
|
|
|
|
gtk_widget_queue_draw(widget);
|
2018-10-29 19:50:29 +00:00
|
|
|
return true;
|
2015-05-13 12:55:08 +00:00
|
|
|
}
|
|
|
|
|
Refactor the GTK drawing system to do both GDK and Cairo.
We're going to have to use Cairo in the GTK3 port, because that's all
GTK3 supports; but we still need old-style GDK for GTK1 support, and
also for performance reasons in GTK2 (see below). Hence, this change
completely restructures GTK PuTTY's drawing code so that there's a
central 'drawing context' structure which contains a type code
indicating GDK or Cairo, and then either some GDK gubbins or some
Cairo gubbins as appropriate; all actual drawing is abstracted through
a set of routines which test the type code in that structure and do
one thing or another. And because the type code is tested at run time,
both sets of drawing primitives can be compiled in at once, and where
possible, they will be.
X server-side bitmap fonts are still supported in the Cairo world, but
because Cairo drawing is entirely client-side, they have to work by
cheekily downloading each glyph bitmap from the server when it's first
needed, and building up a client-side cache of 'cairo_surface_t's
containing the bitmaps with which we then draw on the window. This
technique works, but it's rather slow; hence, even in GTK2, we keep
the GDK drawing back end compiled in, and switch over to it when the
main selected font is a bitmap one.
One visible effect of the new Cairo routines is in the double-width
and double-height text you can get by sending ESC # 3, ESC # 4 and
ESC # 6 escape sequences. In GDK, that's always been done by a really
horrible process of manually scaling the bitmap, server-side, column
by column and row by row, causing each pixel to be exactly doubled or
quadrupled. But in Cairo, we can just set a transformation matrix, and
then that takes effect _before_ the scalable fonts are rendered - so
the results are visibly nicer, and use all the available resolution.
(Sadly, if you're using a server-side bitmap font as your primary one,
then the GDK backend will be selected for all drawing in the terminal
as a whole - so in that situation, even fallback characters absent
from the primary font and rendered by Pango will get the old GDK
scaling treatment. It's only if your main font is scalable, so that
the Cairo backend is selected, that DW/DH characters will come out
looking nice.)
2015-08-15 20:05:56 +00:00
|
|
|
#ifdef DRAW_DEFAULT_CAIRO
|
|
|
|
static void askpass_redraw_cairo(cairo_t *cr, struct drawing_area_ctx *ctx)
|
|
|
|
{
|
2018-05-13 21:56:52 +00:00
|
|
|
double rgbval = (ctx->state == CURRENT ? 0 :
|
|
|
|
ctx->state == NOT_CURRENT ? 1 : 0.5);
|
|
|
|
cairo_set_source_rgb(cr, rgbval, rgbval, rgbval);
|
Refactor the GTK drawing system to do both GDK and Cairo.
We're going to have to use Cairo in the GTK3 port, because that's all
GTK3 supports; but we still need old-style GDK for GTK1 support, and
also for performance reasons in GTK2 (see below). Hence, this change
completely restructures GTK PuTTY's drawing code so that there's a
central 'drawing context' structure which contains a type code
indicating GDK or Cairo, and then either some GDK gubbins or some
Cairo gubbins as appropriate; all actual drawing is abstracted through
a set of routines which test the type code in that structure and do
one thing or another. And because the type code is tested at run time,
both sets of drawing primitives can be compiled in at once, and where
possible, they will be.
X server-side bitmap fonts are still supported in the Cairo world, but
because Cairo drawing is entirely client-side, they have to work by
cheekily downloading each glyph bitmap from the server when it's first
needed, and building up a client-side cache of 'cairo_surface_t's
containing the bitmaps with which we then draw on the window. This
technique works, but it's rather slow; hence, even in GTK2, we keep
the GDK drawing back end compiled in, and switch over to it when the
main selected font is a bitmap one.
One visible effect of the new Cairo routines is in the double-width
and double-height text you can get by sending ESC # 3, ESC # 4 and
ESC # 6 escape sequences. In GDK, that's always been done by a really
horrible process of manually scaling the bitmap, server-side, column
by column and row by row, causing each pixel to be exactly doubled or
quadrupled. But in Cairo, we can just set a transformation matrix, and
then that takes effect _before_ the scalable fonts are rendered - so
the results are visibly nicer, and use all the available resolution.
(Sadly, if you're using a server-side bitmap font as your primary one,
then the GDK backend will be selected for all drawing in the terminal
as a whole - so in that situation, even fallback characters absent
from the primary font and rendered by Pango will get the old GDK
scaling treatment. It's only if your main font is scalable, so that
the Cairo backend is selected, that DW/DH characters will come out
looking nice.)
2015-08-15 20:05:56 +00:00
|
|
|
cairo_paint(cr);
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
static void askpass_redraw_gdk(GdkWindow *win, struct drawing_area_ctx *ctx)
|
|
|
|
{
|
|
|
|
GdkGC *gc = gdk_gc_new(win);
|
2018-05-13 21:56:52 +00:00
|
|
|
gdk_gc_set_foreground(gc, &ctx->cols[ctx->state]);
|
2018-10-29 19:50:29 +00:00
|
|
|
gdk_draw_rectangle(win, gc, true, 0, 0, ctx->width, ctx->height);
|
Refactor the GTK drawing system to do both GDK and Cairo.
We're going to have to use Cairo in the GTK3 port, because that's all
GTK3 supports; but we still need old-style GDK for GTK1 support, and
also for performance reasons in GTK2 (see below). Hence, this change
completely restructures GTK PuTTY's drawing code so that there's a
central 'drawing context' structure which contains a type code
indicating GDK or Cairo, and then either some GDK gubbins or some
Cairo gubbins as appropriate; all actual drawing is abstracted through
a set of routines which test the type code in that structure and do
one thing or another. And because the type code is tested at run time,
both sets of drawing primitives can be compiled in at once, and where
possible, they will be.
X server-side bitmap fonts are still supported in the Cairo world, but
because Cairo drawing is entirely client-side, they have to work by
cheekily downloading each glyph bitmap from the server when it's first
needed, and building up a client-side cache of 'cairo_surface_t's
containing the bitmaps with which we then draw on the window. This
technique works, but it's rather slow; hence, even in GTK2, we keep
the GDK drawing back end compiled in, and switch over to it when the
main selected font is a bitmap one.
One visible effect of the new Cairo routines is in the double-width
and double-height text you can get by sending ESC # 3, ESC # 4 and
ESC # 6 escape sequences. In GDK, that's always been done by a really
horrible process of manually scaling the bitmap, server-side, column
by column and row by row, causing each pixel to be exactly doubled or
quadrupled. But in Cairo, we can just set a transformation matrix, and
then that takes effect _before_ the scalable fonts are rendered - so
the results are visibly nicer, and use all the available resolution.
(Sadly, if you're using a server-side bitmap font as your primary one,
then the GDK backend will be selected for all drawing in the terminal
as a whole - so in that situation, even fallback characters absent
from the primary font and rendered by Pango will get the old GDK
scaling treatment. It's only if your main font is scalable, so that
the Cairo backend is selected, that DW/DH characters will come out
looking nice.)
2015-08-15 20:05:56 +00:00
|
|
|
gdk_gc_unref(gc);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2015-08-16 13:34:19 +00:00
|
|
|
#if GTK_CHECK_VERSION(3,0,0)
|
|
|
|
static gint draw_area(GtkWidget *widget, cairo_t *cr, gpointer data)
|
|
|
|
{
|
|
|
|
struct drawing_area_ctx *ctx = (struct drawing_area_ctx *)data;
|
|
|
|
askpass_redraw_cairo(cr, ctx);
|
2018-10-29 19:50:29 +00:00
|
|
|
return true;
|
2015-08-16 13:34:19 +00:00
|
|
|
}
|
|
|
|
#else
|
2015-05-13 12:55:08 +00:00
|
|
|
static gint expose_area(GtkWidget *widget, GdkEventExpose *event,
|
|
|
|
gpointer data)
|
|
|
|
{
|
|
|
|
struct drawing_area_ctx *ctx = (struct drawing_area_ctx *)data;
|
|
|
|
|
Refactor the GTK drawing system to do both GDK and Cairo.
We're going to have to use Cairo in the GTK3 port, because that's all
GTK3 supports; but we still need old-style GDK for GTK1 support, and
also for performance reasons in GTK2 (see below). Hence, this change
completely restructures GTK PuTTY's drawing code so that there's a
central 'drawing context' structure which contains a type code
indicating GDK or Cairo, and then either some GDK gubbins or some
Cairo gubbins as appropriate; all actual drawing is abstracted through
a set of routines which test the type code in that structure and do
one thing or another. And because the type code is tested at run time,
both sets of drawing primitives can be compiled in at once, and where
possible, they will be.
X server-side bitmap fonts are still supported in the Cairo world, but
because Cairo drawing is entirely client-side, they have to work by
cheekily downloading each glyph bitmap from the server when it's first
needed, and building up a client-side cache of 'cairo_surface_t's
containing the bitmaps with which we then draw on the window. This
technique works, but it's rather slow; hence, even in GTK2, we keep
the GDK drawing back end compiled in, and switch over to it when the
main selected font is a bitmap one.
One visible effect of the new Cairo routines is in the double-width
and double-height text you can get by sending ESC # 3, ESC # 4 and
ESC # 6 escape sequences. In GDK, that's always been done by a really
horrible process of manually scaling the bitmap, server-side, column
by column and row by row, causing each pixel to be exactly doubled or
quadrupled. But in Cairo, we can just set a transformation matrix, and
then that takes effect _before_ the scalable fonts are rendered - so
the results are visibly nicer, and use all the available resolution.
(Sadly, if you're using a server-side bitmap font as your primary one,
then the GDK backend will be selected for all drawing in the terminal
as a whole - so in that situation, even fallback characters absent
from the primary font and rendered by Pango will get the old GDK
scaling treatment. It's only if your main font is scalable, so that
the Cairo backend is selected, that DW/DH characters will come out
looking nice.)
2015-08-15 20:05:56 +00:00
|
|
|
#ifdef DRAW_DEFAULT_CAIRO
|
|
|
|
cairo_t *cr = gdk_cairo_create(gtk_widget_get_window(ctx->area));
|
|
|
|
askpass_redraw_cairo(cr, ctx);
|
|
|
|
cairo_destroy(cr);
|
|
|
|
#else
|
|
|
|
askpass_redraw_gdk(gtk_widget_get_window(ctx->area), ctx);
|
|
|
|
#endif
|
|
|
|
|
2018-10-29 19:50:29 +00:00
|
|
|
return true;
|
2015-05-13 12:55:08 +00:00
|
|
|
}
|
2015-08-16 13:34:19 +00:00
|
|
|
#endif
|
2015-05-13 12:55:08 +00:00
|
|
|
|
2018-05-13 21:56:52 +00:00
|
|
|
static gboolean try_grab_keyboard(gpointer vctx)
|
2015-05-13 12:55:08 +00:00
|
|
|
{
|
2018-05-13 21:56:52 +00:00
|
|
|
struct askpass_ctx *ctx = (struct askpass_ctx *)vctx;
|
|
|
|
int i, ret;
|
2015-08-16 13:36:32 +00:00
|
|
|
|
2016-04-04 10:21:54 +00:00
|
|
|
#if GTK_CHECK_VERSION(3,20,0)
|
2015-08-16 13:36:32 +00:00
|
|
|
/*
|
2016-04-04 10:21:54 +00:00
|
|
|
* Grabbing the keyboard in GTK 3.20 requires the new notion of
|
|
|
|
* GdkSeat.
|
|
|
|
*/
|
|
|
|
GdkSeat *seat;
|
2018-05-13 21:56:52 +00:00
|
|
|
GdkWindow *gdkw = gtk_widget_get_window(ctx->dialog);
|
|
|
|
if (!GDK_IS_WINDOW(gdkw) || !gdk_window_is_visible(gdkw))
|
|
|
|
goto fail;
|
2016-04-04 10:21:54 +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
|
|
|
seat = gdk_display_get_default_seat(
|
|
|
|
gtk_widget_get_display(ctx->dialog));
|
2016-04-04 10:21:54 +00:00
|
|
|
if (!seat)
|
2018-05-13 21:56:52 +00:00
|
|
|
goto fail;
|
2016-04-04 10:21:54 +00:00
|
|
|
|
|
|
|
ctx->seat = seat;
|
2018-05-13 21:56:52 +00:00
|
|
|
ret = gdk_seat_grab(seat, gdkw, GDK_SEAT_CAPABILITY_KEYBOARD,
|
2018-10-29 19:50:29 +00:00
|
|
|
true, NULL, NULL, NULL, NULL);
|
2018-05-13 21:56:52 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* For some reason GDK 3.22 hides the GDK window as a side effect
|
|
|
|
* of a failed grab. I've no idea why. But if we're going to retry
|
|
|
|
* the grab, then we need to unhide it again or else we'll just
|
|
|
|
* get GDK_GRAB_NOT_VIEWABLE on every subsequent attempt.
|
|
|
|
*/
|
|
|
|
if (ret != GDK_GRAB_SUCCESS)
|
|
|
|
gdk_window_show(gdkw);
|
|
|
|
|
2016-04-04 10:21:54 +00:00
|
|
|
#elif GTK_CHECK_VERSION(3,0,0)
|
|
|
|
/*
|
|
|
|
* And it has to be done differently again prior to GTK 3.20.
|
2015-08-16 13:36:32 +00:00
|
|
|
*/
|
|
|
|
GdkDeviceManager *dm;
|
|
|
|
GdkDevice *pointer, *keyboard;
|
|
|
|
|
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
|
|
|
dm = gdk_display_get_device_manager(
|
|
|
|
gtk_widget_get_display(ctx->dialog));
|
2015-08-16 13:36:32 +00:00
|
|
|
if (!dm)
|
2018-05-13 21:56:52 +00:00
|
|
|
goto fail;
|
2015-08-16 13:36:32 +00:00
|
|
|
|
|
|
|
pointer = gdk_device_manager_get_client_pointer(dm);
|
|
|
|
if (!pointer)
|
2018-05-13 21:56:52 +00:00
|
|
|
goto fail;
|
2015-08-16 13:36:32 +00:00
|
|
|
keyboard = gdk_device_get_associated_device(pointer);
|
|
|
|
if (!keyboard)
|
2018-05-13 21:56:52 +00:00
|
|
|
goto fail;
|
2015-08-16 13:36:32 +00:00
|
|
|
if (gdk_device_get_source(keyboard) != GDK_SOURCE_KEYBOARD)
|
2018-05-13 21:56:52 +00:00
|
|
|
goto fail;
|
2015-08-16 13:36:32 +00:00
|
|
|
|
|
|
|
ctx->keyboard = keyboard;
|
|
|
|
ret = gdk_device_grab(ctx->keyboard,
|
|
|
|
gtk_widget_get_window(ctx->dialog),
|
|
|
|
GDK_OWNERSHIP_NONE,
|
2018-10-29 19:50:29 +00:00
|
|
|
true,
|
2015-08-16 13:36:32 +00:00
|
|
|
GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK,
|
|
|
|
NULL,
|
|
|
|
GDK_CURRENT_TIME);
|
|
|
|
#else
|
|
|
|
/*
|
|
|
|
* It's much simpler in GTK 1 and 2!
|
|
|
|
*/
|
|
|
|
ret = gdk_keyboard_grab(gtk_widget_get_window(ctx->dialog),
|
2018-10-29 19:50:29 +00:00
|
|
|
false, GDK_CURRENT_TIME);
|
2015-08-16 13:36:32 +00:00
|
|
|
#endif
|
2018-05-13 21:56:52 +00:00
|
|
|
if (ret != GDK_GRAB_SUCCESS)
|
|
|
|
goto fail;
|
2015-08-16 13:36:32 +00:00
|
|
|
|
2018-05-13 21:56:52 +00:00
|
|
|
/*
|
|
|
|
* Now that we've got the keyboard grab, connect up our keyboard
|
|
|
|
* handlers.
|
|
|
|
*/
|
|
|
|
#if GTK_CHECK_VERSION(2,0,0)
|
|
|
|
g_signal_connect(G_OBJECT(ctx->imc), "commit",
|
|
|
|
G_CALLBACK(input_method_commit_event), ctx);
|
|
|
|
#endif
|
|
|
|
g_signal_connect(G_OBJECT(ctx->dialog), "key_press_event",
|
|
|
|
G_CALLBACK(key_event), ctx);
|
|
|
|
g_signal_connect(G_OBJECT(ctx->dialog), "key_release_event",
|
|
|
|
G_CALLBACK(key_event), ctx);
|
|
|
|
#if GTK_CHECK_VERSION(2,0,0)
|
|
|
|
gtk_im_context_set_client_window(ctx->imc,
|
|
|
|
gtk_widget_get_window(ctx->dialog));
|
|
|
|
#endif
|
2015-05-13 12:55:08 +00:00
|
|
|
|
|
|
|
/*
|
2018-05-13 21:56:52 +00:00
|
|
|
* And repaint the key-acknowledgment drawing areas as not greyed
|
|
|
|
* out.
|
2015-05-13 12:55:08 +00:00
|
|
|
*/
|
2019-07-23 17:40:09 +00:00
|
|
|
ctx->active_area = keypress_prng_value() % N_DRAWING_AREAS;
|
2018-05-13 21:56:52 +00:00
|
|
|
for (i = 0; i < N_DRAWING_AREAS; i++) {
|
|
|
|
ctx->drawingareas[i].state =
|
|
|
|
(i == ctx->active_area ? CURRENT : NOT_CURRENT);
|
|
|
|
gtk_widget_queue_draw(ctx->drawingareas[i].area);
|
|
|
|
}
|
2015-05-13 12:55:08 +00:00
|
|
|
|
2018-10-29 19:50:29 +00:00
|
|
|
return false;
|
2018-05-13 21:56:52 +00:00
|
|
|
|
|
|
|
fail:
|
|
|
|
/*
|
|
|
|
* If we didn't get the grab, reschedule ourself on a timer to try
|
|
|
|
* again later.
|
|
|
|
*
|
|
|
|
* We have to do this rather than just trying once, because there
|
|
|
|
* is at least one important situation in which the grab may fail
|
|
|
|
* the first time: any user who is launching an add-key operation
|
|
|
|
* off some kind of window manager hotkey will almost by
|
|
|
|
* definition be running this script with a keyboard grab already
|
|
|
|
* active, namely the one-key grab that the WM (or whatever) uses
|
|
|
|
* to detect presses of the hotkey. So at the very least we have
|
|
|
|
* to give the user time to release that key.
|
|
|
|
*/
|
|
|
|
if (++ctx->nattempts >= 4) {
|
2021-04-05 16:48:30 +00:00
|
|
|
cancel_askpass(ctx, "unable to grab keyboard after 5 seconds");
|
2018-05-13 21:56:52 +00:00
|
|
|
} else {
|
|
|
|
g_timeout_add(1000/8, try_grab_keyboard, ctx);
|
2015-05-13 12:55:08 +00:00
|
|
|
}
|
2018-10-29 19:50:29 +00:00
|
|
|
return false;
|
2015-05-13 12:55:08 +00:00
|
|
|
}
|
|
|
|
|
2018-05-13 21:56:52 +00:00
|
|
|
void realize(GtkWidget *widget, gpointer vctx)
|
|
|
|
{
|
|
|
|
struct askpass_ctx *ctx = (struct askpass_ctx *)vctx;
|
|
|
|
|
|
|
|
gtk_grab_add(ctx->dialog);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Schedule the first attempt at the keyboard grab.
|
|
|
|
*/
|
|
|
|
ctx->nattempts = 0;
|
|
|
|
#if GTK_CHECK_VERSION(3,20,0)
|
|
|
|
ctx->seat = NULL;
|
|
|
|
#elif GTK_CHECK_VERSION(3,0,0)
|
|
|
|
ctx->keyboard = NULL;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
g_idle_add(try_grab_keyboard, ctx);
|
|
|
|
}
|
|
|
|
|
2015-05-13 12:55:08 +00:00
|
|
|
static const char *gtk_askpass_setup(struct askpass_ctx *ctx,
|
|
|
|
const char *window_title,
|
|
|
|
const char *prompt_text)
|
|
|
|
{
|
|
|
|
int i;
|
2015-08-31 14:45:18 +00:00
|
|
|
GtkBox *action_area;
|
2015-05-13 12:55:08 +00:00
|
|
|
|
2022-09-13 14:00:26 +00:00
|
|
|
ctx->passphrase = strbuf_new_nm();
|
2015-05-13 12:55:08 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Create widgets.
|
|
|
|
*/
|
2015-08-31 14:45:18 +00:00
|
|
|
ctx->dialog = our_dialog_new();
|
2015-05-13 12:55:08 +00:00
|
|
|
gtk_window_set_title(GTK_WINDOW(ctx->dialog), window_title);
|
2015-08-31 14:45:18 +00:00
|
|
|
gtk_window_set_position(GTK_WINDOW(ctx->dialog), GTK_WIN_POS_CENTER);
|
2021-04-05 16:48:30 +00:00
|
|
|
g_signal_connect(G_OBJECT(ctx->dialog), "delete-event",
|
2022-08-03 19:48:46 +00:00
|
|
|
G_CALLBACK(askpass_dialog_closed), ctx);
|
2015-05-13 12:55:08 +00:00
|
|
|
ctx->promptlabel = gtk_label_new(prompt_text);
|
2015-08-31 14:45:27 +00:00
|
|
|
align_label_left(GTK_LABEL(ctx->promptlabel));
|
2015-09-26 10:09:20 +00:00
|
|
|
gtk_widget_show(ctx->promptlabel);
|
2018-10-29 19:50:29 +00:00
|
|
|
gtk_label_set_line_wrap(GTK_LABEL(ctx->promptlabel), true);
|
2015-08-31 14:45:27 +00:00
|
|
|
#if GTK_CHECK_VERSION(3,0,0)
|
|
|
|
gtk_label_set_width_chars(GTK_LABEL(ctx->promptlabel), 48);
|
2021-04-02 11:54:52 +00:00
|
|
|
#endif
|
|
|
|
int margin = string_width("MM");
|
|
|
|
#if GTK_CHECK_VERSION(3,12,0)
|
|
|
|
gtk_widget_set_margin_start(ctx->promptlabel, margin);
|
|
|
|
gtk_widget_set_margin_end(ctx->promptlabel, margin);
|
|
|
|
#else
|
|
|
|
gtk_misc_set_padding(GTK_MISC(ctx->promptlabel), margin, 0);
|
2015-08-31 14:45:27 +00:00
|
|
|
#endif
|
2015-08-31 14:45:18 +00:00
|
|
|
our_dialog_add_to_content_area(GTK_WINDOW(ctx->dialog),
|
2018-10-29 19:50:29 +00:00
|
|
|
ctx->promptlabel, true, true, 0);
|
2015-08-08 14:04:28 +00:00
|
|
|
#if GTK_CHECK_VERSION(2,0,0)
|
2015-05-13 12:55:08 +00:00
|
|
|
ctx->imc = gtk_im_multicontext_new();
|
2015-08-08 14:04:28 +00:00
|
|
|
#endif
|
Refactor the GTK drawing system to do both GDK and Cairo.
We're going to have to use Cairo in the GTK3 port, because that's all
GTK3 supports; but we still need old-style GDK for GTK1 support, and
also for performance reasons in GTK2 (see below). Hence, this change
completely restructures GTK PuTTY's drawing code so that there's a
central 'drawing context' structure which contains a type code
indicating GDK or Cairo, and then either some GDK gubbins or some
Cairo gubbins as appropriate; all actual drawing is abstracted through
a set of routines which test the type code in that structure and do
one thing or another. And because the type code is tested at run time,
both sets of drawing primitives can be compiled in at once, and where
possible, they will be.
X server-side bitmap fonts are still supported in the Cairo world, but
because Cairo drawing is entirely client-side, they have to work by
cheekily downloading each glyph bitmap from the server when it's first
needed, and building up a client-side cache of 'cairo_surface_t's
containing the bitmaps with which we then draw on the window. This
technique works, but it's rather slow; hence, even in GTK2, we keep
the GDK drawing back end compiled in, and switch over to it when the
main selected font is a bitmap one.
One visible effect of the new Cairo routines is in the double-width
and double-height text you can get by sending ESC # 3, ESC # 4 and
ESC # 6 escape sequences. In GDK, that's always been done by a really
horrible process of manually scaling the bitmap, server-side, column
by column and row by row, causing each pixel to be exactly doubled or
quadrupled. But in Cairo, we can just set a transformation matrix, and
then that takes effect _before_ the scalable fonts are rendered - so
the results are visibly nicer, and use all the available resolution.
(Sadly, if you're using a server-side bitmap font as your primary one,
then the GDK backend will be selected for all drawing in the terminal
as a whole - so in that situation, even fallback characters absent
from the primary font and rendered by Pango will get the old GDK
scaling treatment. It's only if your main font is scalable, so that
the Cairo backend is selected, that DW/DH characters will come out
looking nice.)
2015-08-15 20:05:56 +00:00
|
|
|
#ifndef DRAW_DEFAULT_CAIRO
|
|
|
|
{
|
|
|
|
gboolean success[2];
|
|
|
|
ctx->colmap = gdk_colormap_get_system();
|
|
|
|
ctx->cols[0].red = ctx->cols[0].green = ctx->cols[0].blue = 0xFFFF;
|
|
|
|
ctx->cols[1].red = ctx->cols[1].green = ctx->cols[1].blue = 0;
|
2018-05-13 21:56:52 +00:00
|
|
|
ctx->cols[2].red = ctx->cols[2].green = ctx->cols[2].blue = 0x8000;
|
Refactor the GTK drawing system to do both GDK and Cairo.
We're going to have to use Cairo in the GTK3 port, because that's all
GTK3 supports; but we still need old-style GDK for GTK1 support, and
also for performance reasons in GTK2 (see below). Hence, this change
completely restructures GTK PuTTY's drawing code so that there's a
central 'drawing context' structure which contains a type code
indicating GDK or Cairo, and then either some GDK gubbins or some
Cairo gubbins as appropriate; all actual drawing is abstracted through
a set of routines which test the type code in that structure and do
one thing or another. And because the type code is tested at run time,
both sets of drawing primitives can be compiled in at once, and where
possible, they will be.
X server-side bitmap fonts are still supported in the Cairo world, but
because Cairo drawing is entirely client-side, they have to work by
cheekily downloading each glyph bitmap from the server when it's first
needed, and building up a client-side cache of 'cairo_surface_t's
containing the bitmaps with which we then draw on the window. This
technique works, but it's rather slow; hence, even in GTK2, we keep
the GDK drawing back end compiled in, and switch over to it when the
main selected font is a bitmap one.
One visible effect of the new Cairo routines is in the double-width
and double-height text you can get by sending ESC # 3, ESC # 4 and
ESC # 6 escape sequences. In GDK, that's always been done by a really
horrible process of manually scaling the bitmap, server-side, column
by column and row by row, causing each pixel to be exactly doubled or
quadrupled. But in Cairo, we can just set a transformation matrix, and
then that takes effect _before_ the scalable fonts are rendered - so
the results are visibly nicer, and use all the available resolution.
(Sadly, if you're using a server-side bitmap font as your primary one,
then the GDK backend will be selected for all drawing in the terminal
as a whole - so in that situation, even fallback characters absent
from the primary font and rendered by Pango will get the old GDK
scaling treatment. It's only if your main font is scalable, so that
the Cairo backend is selected, that DW/DH characters will come out
looking nice.)
2015-08-15 20:05:56 +00:00
|
|
|
gdk_colormap_alloc_colors(ctx->colmap, ctx->cols, 2,
|
2018-10-29 19:50:29 +00:00
|
|
|
false, true, success);
|
2018-10-30 18:09:12 +00:00
|
|
|
if (!success[0] || !success[1])
|
Refactor the GTK drawing system to do both GDK and Cairo.
We're going to have to use Cairo in the GTK3 port, because that's all
GTK3 supports; but we still need old-style GDK for GTK1 support, and
also for performance reasons in GTK2 (see below). Hence, this change
completely restructures GTK PuTTY's drawing code so that there's a
central 'drawing context' structure which contains a type code
indicating GDK or Cairo, and then either some GDK gubbins or some
Cairo gubbins as appropriate; all actual drawing is abstracted through
a set of routines which test the type code in that structure and do
one thing or another. And because the type code is tested at run time,
both sets of drawing primitives can be compiled in at once, and where
possible, they will be.
X server-side bitmap fonts are still supported in the Cairo world, but
because Cairo drawing is entirely client-side, they have to work by
cheekily downloading each glyph bitmap from the server when it's first
needed, and building up a client-side cache of 'cairo_surface_t's
containing the bitmaps with which we then draw on the window. This
technique works, but it's rather slow; hence, even in GTK2, we keep
the GDK drawing back end compiled in, and switch over to it when the
main selected font is a bitmap one.
One visible effect of the new Cairo routines is in the double-width
and double-height text you can get by sending ESC # 3, ESC # 4 and
ESC # 6 escape sequences. In GDK, that's always been done by a really
horrible process of manually scaling the bitmap, server-side, column
by column and row by row, causing each pixel to be exactly doubled or
quadrupled. But in Cairo, we can just set a transformation matrix, and
then that takes effect _before_ the scalable fonts are rendered - so
the results are visibly nicer, and use all the available resolution.
(Sadly, if you're using a server-side bitmap font as your primary one,
then the GDK backend will be selected for all drawing in the terminal
as a whole - so in that situation, even fallback characters absent
from the primary font and rendered by Pango will get the old GDK
scaling treatment. It's only if your main font is scalable, so that
the Cairo backend is selected, that DW/DH characters will come out
looking nice.)
2015-08-15 20:05:56 +00:00
|
|
|
return "unable to allocate colours";
|
|
|
|
}
|
|
|
|
#endif
|
2015-08-31 14:45:18 +00:00
|
|
|
|
|
|
|
action_area = our_dialog_make_action_hbox(GTK_WINDOW(ctx->dialog));
|
|
|
|
|
2015-05-13 12:55:08 +00:00
|
|
|
for (i = 0; i < N_DRAWING_AREAS; i++) {
|
|
|
|
ctx->drawingareas[i].area = gtk_drawing_area_new();
|
Refactor the GTK drawing system to do both GDK and Cairo.
We're going to have to use Cairo in the GTK3 port, because that's all
GTK3 supports; but we still need old-style GDK for GTK1 support, and
also for performance reasons in GTK2 (see below). Hence, this change
completely restructures GTK PuTTY's drawing code so that there's a
central 'drawing context' structure which contains a type code
indicating GDK or Cairo, and then either some GDK gubbins or some
Cairo gubbins as appropriate; all actual drawing is abstracted through
a set of routines which test the type code in that structure and do
one thing or another. And because the type code is tested at run time,
both sets of drawing primitives can be compiled in at once, and where
possible, they will be.
X server-side bitmap fonts are still supported in the Cairo world, but
because Cairo drawing is entirely client-side, they have to work by
cheekily downloading each glyph bitmap from the server when it's first
needed, and building up a client-side cache of 'cairo_surface_t's
containing the bitmaps with which we then draw on the window. This
technique works, but it's rather slow; hence, even in GTK2, we keep
the GDK drawing back end compiled in, and switch over to it when the
main selected font is a bitmap one.
One visible effect of the new Cairo routines is in the double-width
and double-height text you can get by sending ESC # 3, ESC # 4 and
ESC # 6 escape sequences. In GDK, that's always been done by a really
horrible process of manually scaling the bitmap, server-side, column
by column and row by row, causing each pixel to be exactly doubled or
quadrupled. But in Cairo, we can just set a transformation matrix, and
then that takes effect _before_ the scalable fonts are rendered - so
the results are visibly nicer, and use all the available resolution.
(Sadly, if you're using a server-side bitmap font as your primary one,
then the GDK backend will be selected for all drawing in the terminal
as a whole - so in that situation, even fallback characters absent
from the primary font and rendered by Pango will get the old GDK
scaling treatment. It's only if your main font is scalable, so that
the Cairo backend is selected, that DW/DH characters will come out
looking nice.)
2015-08-15 20:05:56 +00:00
|
|
|
#ifndef DRAW_DEFAULT_CAIRO
|
2015-05-13 12:55:08 +00:00
|
|
|
ctx->drawingareas[i].cols = ctx->cols;
|
Refactor the GTK drawing system to do both GDK and Cairo.
We're going to have to use Cairo in the GTK3 port, because that's all
GTK3 supports; but we still need old-style GDK for GTK1 support, and
also for performance reasons in GTK2 (see below). Hence, this change
completely restructures GTK PuTTY's drawing code so that there's a
central 'drawing context' structure which contains a type code
indicating GDK or Cairo, and then either some GDK gubbins or some
Cairo gubbins as appropriate; all actual drawing is abstracted through
a set of routines which test the type code in that structure and do
one thing or another. And because the type code is tested at run time,
both sets of drawing primitives can be compiled in at once, and where
possible, they will be.
X server-side bitmap fonts are still supported in the Cairo world, but
because Cairo drawing is entirely client-side, they have to work by
cheekily downloading each glyph bitmap from the server when it's first
needed, and building up a client-side cache of 'cairo_surface_t's
containing the bitmaps with which we then draw on the window. This
technique works, but it's rather slow; hence, even in GTK2, we keep
the GDK drawing back end compiled in, and switch over to it when the
main selected font is a bitmap one.
One visible effect of the new Cairo routines is in the double-width
and double-height text you can get by sending ESC # 3, ESC # 4 and
ESC # 6 escape sequences. In GDK, that's always been done by a really
horrible process of manually scaling the bitmap, server-side, column
by column and row by row, causing each pixel to be exactly doubled or
quadrupled. But in Cairo, we can just set a transformation matrix, and
then that takes effect _before_ the scalable fonts are rendered - so
the results are visibly nicer, and use all the available resolution.
(Sadly, if you're using a server-side bitmap font as your primary one,
then the GDK backend will be selected for all drawing in the terminal
as a whole - so in that situation, even fallback characters absent
from the primary font and rendered by Pango will get the old GDK
scaling treatment. It's only if your main font is scalable, so that
the Cairo backend is selected, that DW/DH characters will come out
looking nice.)
2015-08-15 20:05:56 +00:00
|
|
|
#endif
|
2018-05-13 21:56:52 +00:00
|
|
|
ctx->drawingareas[i].state = GREYED_OUT;
|
2015-05-13 12:55:08 +00:00
|
|
|
ctx->drawingareas[i].width = ctx->drawingareas[i].height = 0;
|
|
|
|
/* It would be nice to choose this size in some more
|
|
|
|
* context-sensitive way, like measuring the size of some
|
|
|
|
* piece of template text. */
|
|
|
|
gtk_widget_set_size_request(ctx->drawingareas[i].area, 32, 32);
|
2015-08-31 14:45:18 +00:00
|
|
|
gtk_box_pack_end(action_area, ctx->drawingareas[i].area,
|
2018-10-29 19:50:29 +00:00
|
|
|
true, true, 5);
|
2015-08-08 16:29:02 +00:00
|
|
|
g_signal_connect(G_OBJECT(ctx->drawingareas[i].area),
|
|
|
|
"configure_event",
|
|
|
|
G_CALLBACK(configure_area),
|
|
|
|
&ctx->drawingareas[i]);
|
2015-08-16 13:34:19 +00:00
|
|
|
#if GTK_CHECK_VERSION(3,0,0)
|
|
|
|
g_signal_connect(G_OBJECT(ctx->drawingareas[i].area),
|
|
|
|
"draw",
|
|
|
|
G_CALLBACK(draw_area),
|
|
|
|
&ctx->drawingareas[i]);
|
|
|
|
#else
|
2015-08-08 16:29:02 +00:00
|
|
|
g_signal_connect(G_OBJECT(ctx->drawingareas[i].area),
|
|
|
|
"expose_event",
|
|
|
|
G_CALLBACK(expose_area),
|
|
|
|
&ctx->drawingareas[i]);
|
2015-08-16 13:34:19 +00:00
|
|
|
#endif
|
2016-04-04 10:49:05 +00:00
|
|
|
|
|
|
|
#if GTK_CHECK_VERSION(3,0,0)
|
|
|
|
g_object_set(G_OBJECT(ctx->drawingareas[i].area),
|
|
|
|
"margin-bottom", 8, (const char *)NULL);
|
|
|
|
#endif
|
|
|
|
|
2015-05-13 12:55:08 +00:00
|
|
|
gtk_widget_show(ctx->drawingareas[i].area);
|
|
|
|
}
|
2018-05-13 21:56:52 +00:00
|
|
|
ctx->active_area = -1;
|
2015-05-13 12:55:08 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Arrange to receive key events. We don't really need to worry
|
|
|
|
* from a UI perspective about which widget gets the events, as
|
|
|
|
* long as we know which it is so we can catch them. So we'll pick
|
|
|
|
* the prompt label at random, and we'll use gtk_grab_add to
|
|
|
|
* ensure key events go to it.
|
|
|
|
*/
|
2018-10-29 19:50:29 +00:00
|
|
|
gtk_widget_set_sensitive(ctx->dialog, true);
|
2015-08-08 14:04:28 +00:00
|
|
|
|
|
|
|
#if GTK_CHECK_VERSION(2,0,0)
|
2018-10-29 19:50:29 +00:00
|
|
|
gtk_window_set_keep_above(GTK_WINDOW(ctx->dialog), true);
|
2015-08-08 14:04:28 +00:00
|
|
|
#endif
|
2015-05-13 12:55:08 +00:00
|
|
|
|
|
|
|
/*
|
2018-05-13 21:56:52 +00:00
|
|
|
* Wait for the key-receiving widget to actually be created, in
|
|
|
|
* order to call gtk_grab_add on it.
|
2015-05-13 12:55:08 +00:00
|
|
|
*/
|
2018-05-13 21:56:52 +00:00
|
|
|
g_signal_connect(G_OBJECT(ctx->dialog), "realize",
|
|
|
|
G_CALLBACK(realize), ctx);
|
2015-05-13 12:55:08 +00:00
|
|
|
|
|
|
|
/*
|
2018-05-13 21:56:52 +00:00
|
|
|
* Show the window.
|
2015-05-13 12:55:08 +00:00
|
|
|
*/
|
2018-05-13 21:56:52 +00:00
|
|
|
gtk_widget_show(ctx->dialog);
|
2015-05-13 12:55:08 +00:00
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void gtk_askpass_cleanup(struct askpass_ctx *ctx)
|
|
|
|
{
|
2016-04-04 10:21:54 +00:00
|
|
|
#if GTK_CHECK_VERSION(3,20,0)
|
2018-05-13 21:56:52 +00:00
|
|
|
if (ctx->seat)
|
|
|
|
gdk_seat_ungrab(ctx->seat);
|
2016-04-04 10:21:54 +00:00
|
|
|
#elif GTK_CHECK_VERSION(3,0,0)
|
2018-05-13 21:56:52 +00:00
|
|
|
if (ctx->keyboard)
|
|
|
|
gdk_device_ungrab(ctx->keyboard, GDK_CURRENT_TIME);
|
2015-08-16 13:36:32 +00:00
|
|
|
#else
|
2015-05-13 12:55:08 +00:00
|
|
|
gdk_keyboard_ungrab(GDK_CURRENT_TIME);
|
2015-08-16 13:36:32 +00:00
|
|
|
#endif
|
2015-05-13 12:55:08 +00:00
|
|
|
gtk_grab_remove(ctx->promptlabel);
|
|
|
|
|
|
|
|
gtk_widget_destroy(ctx->dialog);
|
|
|
|
}
|
|
|
|
|
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 setup_gtk(const char *display)
|
2015-05-13 12:55:08 +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
|
|
|
static bool gtk_initialised = false;
|
2015-05-13 12:55:08 +00:00
|
|
|
int argc;
|
|
|
|
char *real_argv[3];
|
|
|
|
char **argv = real_argv;
|
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 ret;
|
2015-05-13 12:55:08 +00:00
|
|
|
|
|
|
|
if (gtk_initialised)
|
2018-10-29 19:50:29 +00:00
|
|
|
return true;
|
2015-05-13 12:55:08 +00:00
|
|
|
|
|
|
|
argc = 0;
|
|
|
|
argv[argc++] = dupstr("dummy");
|
|
|
|
argv[argc++] = dupprintf("--display=%s", display);
|
|
|
|
argv[argc] = NULL;
|
|
|
|
ret = gtk_init_check(&argc, &argv);
|
|
|
|
while (argc > 0)
|
|
|
|
sfree(argv[--argc]);
|
|
|
|
|
|
|
|
gtk_initialised = ret;
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
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
|
|
|
const bool buildinfo_gtk_relevant = true;
|
2017-02-22 22:10:05 +00:00
|
|
|
|
2015-05-13 12:55:08 +00:00
|
|
|
char *gtk_askpass_main(const char *display, const char *wintitle,
|
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
|
|
|
const char *prompt, bool *success)
|
2015-05-13 12:55:08 +00:00
|
|
|
{
|
2019-12-22 08:15:52 +00:00
|
|
|
struct askpass_ctx ctx[1];
|
2015-05-13 12:55:08 +00:00
|
|
|
const char *err;
|
|
|
|
|
2018-05-13 21:56:52 +00:00
|
|
|
ctx->passphrase = NULL;
|
|
|
|
ctx->error_message = NULL;
|
|
|
|
|
2015-05-13 12:55:08 +00:00
|
|
|
/* In case gtk_init hasn't been called yet by the program */
|
|
|
|
if (!setup_gtk(display)) {
|
2018-10-29 19:50:29 +00:00
|
|
|
*success = false;
|
2015-05-13 12:55:08 +00:00
|
|
|
return dupstr("unable to initialise GTK");
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((err = gtk_askpass_setup(ctx, wintitle, prompt)) != NULL) {
|
2018-10-29 19:50:29 +00:00
|
|
|
*success = false;
|
2015-05-13 12:55:08 +00:00
|
|
|
return dupprintf("%s", err);
|
|
|
|
}
|
2019-05-05 19:22:36 +00:00
|
|
|
setup_keypress_prng();
|
2015-05-13 12:55:08 +00:00
|
|
|
gtk_main();
|
2019-05-05 19:22:36 +00:00
|
|
|
cleanup_keypress_prng();
|
2015-05-13 12:55:08 +00:00
|
|
|
gtk_askpass_cleanup(ctx);
|
|
|
|
|
|
|
|
if (ctx->passphrase) {
|
2018-10-29 19:50:29 +00:00
|
|
|
*success = true;
|
2022-09-13 14:00:26 +00:00
|
|
|
return strbuf_to_str(ctx->passphrase);
|
2015-05-13 12:55:08 +00:00
|
|
|
} else {
|
2018-10-29 19:50:29 +00:00
|
|
|
*success = false;
|
2018-05-13 21:56:52 +00:00
|
|
|
return ctx->error_message;
|
2015-05-13 12:55:08 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef TEST_ASKPASS
|
2015-05-15 10:15:42 +00:00
|
|
|
void modalfatalbox(const char *p, ...)
|
2015-05-13 12:55:08 +00:00
|
|
|
{
|
|
|
|
va_list ap;
|
|
|
|
fprintf(stderr, "FATAL ERROR: ");
|
|
|
|
va_start(ap, p);
|
|
|
|
vfprintf(stderr, p, ap);
|
|
|
|
va_end(ap);
|
|
|
|
fputc('\n', stderr);
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
int main(int argc, char **argv)
|
|
|
|
{
|
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 success;
|
|
|
|
int exitcode;
|
2015-05-13 12:55:08 +00:00
|
|
|
char *ret;
|
|
|
|
|
|
|
|
gtk_init(&argc, &argv);
|
|
|
|
|
|
|
|
if (argc != 2) {
|
2018-10-29 19:50:29 +00:00
|
|
|
success = false;
|
2015-05-13 12:55:08 +00:00
|
|
|
ret = dupprintf("usage: %s <prompt text>", argv[0]);
|
|
|
|
} else {
|
2015-09-26 09:53:32 +00:00
|
|
|
ret = gtk_askpass_main(NULL, "Enter passphrase", argv[1], &success);
|
2015-05-13 12:55:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!success) {
|
|
|
|
fputs(ret, stderr);
|
|
|
|
fputc('\n', stderr);
|
|
|
|
exitcode = 1;
|
|
|
|
} else {
|
|
|
|
fputs(ret, stdout);
|
|
|
|
fputc('\n', stdout);
|
|
|
|
exitcode = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
smemclr(ret, strlen(ret));
|
|
|
|
return exitcode;
|
|
|
|
}
|
|
|
|
#endif
|