X-Git-Url: https://asedeno.scripts.mit.edu/gitweb/?a=blobdiff_plain;f=unix%2Fgtkask.c;h=c2b582e9c9afe29e29a2d0befaf5c6dd3453ecca;hb=095072fa46b2d7b8beafaddb2f873d2f500a1e10;hp=bc2457234e8a5aac7c09abff36faff5874a0ad1d;hpb=4eddcb4c564151d606aef8b3fc32172a6fac5573;p=PuTTY.git diff --git a/unix/gtkask.c b/unix/gtkask.c index bc245723..c2b582e9 100644 --- a/unix/gtkask.c +++ b/unix/gtkask.c @@ -5,8 +5,18 @@ #include #include #include + +#include + #include +#include +#if !GTK_CHECK_VERSION(3,0,0) #include +#endif + +#include "gtkfont.h" +#include "gtkcompat.h" +#include "gtkmisc.h" #include "misc.h" @@ -14,7 +24,9 @@ struct drawing_area_ctx { GtkWidget *area; +#ifndef DRAW_DEFAULT_CAIRO GdkColor *cols; +#endif int width, height, current; }; @@ -22,11 +34,20 @@ struct askpass_ctx { GtkWidget *dialog, *promptlabel; struct drawing_area_ctx drawingareas[N_DRAWING_AREAS]; int active_area; +#if GTK_CHECK_VERSION(2,0,0) GtkIMContext *imc; +#endif +#ifndef DRAW_DEFAULT_CAIRO GdkColormap *colmap; GdkColor cols[2]; +#endif char *passphrase; int passlen, passsize; +#if GTK_CHECK_VERSION(3,20,0) + GdkSeat *seat; /* for gdk_seat_grab */ +#elif GTK_CHECK_VERSION(3,0,0) + GdkDevice *keyboard; /* for gdk_device_grab */ +#endif }; static void visually_acknowledge_keypress(struct askpass_ctx *ctx) @@ -58,18 +79,46 @@ static int last_char_len(struct askpass_ctx *ctx) return ctx->passlen - i; } +static void add_text_to_passphrase(struct askpass_ctx *ctx, gchar *str) +{ + int len = strlen(str); + if (ctx->passlen + len >= ctx->passsize) { + /* Take some care with buffer expansion, because there are + * pieces of passphrase in the old buffer so we should ensure + * realloc doesn't leave a copy lying around in the address + * space. */ + int oldsize = ctx->passsize; + char *newbuf; + + ctx->passsize = (ctx->passlen + len) * 5 / 4 + 1024; + newbuf = snewn(ctx->passsize, char); + memcpy(newbuf, ctx->passphrase, oldsize); + smemclr(ctx->passphrase, oldsize); + sfree(ctx->passphrase); + ctx->passphrase = newbuf; + } + strcpy(ctx->passphrase + ctx->passlen, str); + ctx->passlen += len; + visually_acknowledge_keypress(ctx); +} + static gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data) { struct askpass_ctx *ctx = (struct askpass_ctx *)data; - if (event->keyval == GDK_Return && event->type == GDK_KEY_PRESS) { + + if (event->keyval == GDK_KEY_Return && + event->type == GDK_KEY_PRESS) { gtk_main_quit(); - } else if (event->keyval == GDK_Escape && event->type == GDK_KEY_PRESS) { + } else if (event->keyval == GDK_KEY_Escape && + event->type == GDK_KEY_PRESS) { smemclr(ctx->passphrase, ctx->passsize); ctx->passphrase = NULL; gtk_main_quit(); } else { +#if GTK_CHECK_VERSION(2,0,0) if (gtk_im_context_filter_keypress(ctx->imc, event)) return TRUE; +#endif if (event->type == GDK_KEY_PRESS) { if (!strcmp(event->string, "\x15")) { @@ -92,41 +141,29 @@ static gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data) break; } visually_acknowledge_keypress(ctx); - } else if (event->keyval == GDK_BackSpace) { + } else if (event->keyval == GDK_KEY_BackSpace) { /* Backspace. Delete one character. */ if (ctx->passlen > 0) ctx->passlen -= last_char_len(ctx); visually_acknowledge_keypress(ctx); +#if !GTK_CHECK_VERSION(2,0,0) + } else if (event->string[0]) { + add_text_to_passphrase(ctx, event->string); +#endif } } } return TRUE; } +#if GTK_CHECK_VERSION(2,0,0) static void input_method_commit_event(GtkIMContext *imc, gchar *str, gpointer data) { struct askpass_ctx *ctx = (struct askpass_ctx *)data; - int len = strlen(str); - if (ctx->passlen + len >= ctx->passsize) { - /* Take some care with buffer expansion, because there are - * pieces of passphrase in the old buffer so we should ensure - * realloc doesn't leave a copy lying around in the address - * space. */ - int oldsize = ctx->passsize; - char *newbuf; - - ctx->passsize = (ctx->passlen + len) * 5 / 4 + 1024; - newbuf = snewn(ctx->passsize, char); - memcpy(newbuf, ctx->passphrase, oldsize); - smemclr(ctx->passphrase, oldsize); - sfree(ctx->passphrase); - ctx->passphrase = newbuf; - } - strcpy(ctx->passphrase + ctx->passlen, str); - ctx->passlen += len; - visually_acknowledge_keypress(ctx); + add_text_to_passphrase(ctx, str); } +#endif static gint configure_area(GtkWidget *widget, GdkEventConfigure *event, gpointer data) @@ -138,22 +175,104 @@ static gint configure_area(GtkWidget *widget, GdkEventConfigure *event, return TRUE; } +#ifdef DRAW_DEFAULT_CAIRO +static void askpass_redraw_cairo(cairo_t *cr, struct drawing_area_ctx *ctx) +{ + cairo_set_source_rgb(cr, 1-ctx->current, 1-ctx->current, 1-ctx->current); + cairo_paint(cr); +} +#else +static void askpass_redraw_gdk(GdkWindow *win, struct drawing_area_ctx *ctx) +{ + GdkGC *gc = gdk_gc_new(win); + gdk_gc_set_foreground(gc, &ctx->cols[ctx->current]); + gdk_draw_rectangle(win, gc, TRUE, 0, 0, ctx->width, ctx->height); + gdk_gc_unref(gc); +} +#endif + +#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); + return TRUE; +} +#else static gint expose_area(GtkWidget *widget, GdkEventExpose *event, gpointer data) { struct drawing_area_ctx *ctx = (struct drawing_area_ctx *)data; - GdkGC *gc = gdk_gc_new(ctx->area->window); - gdk_gc_set_foreground(gc, &ctx->cols[ctx->current]); - gdk_draw_rectangle(widget->window, gc, TRUE, - 0, 0, ctx->width, ctx->height); - gdk_gc_unref(gc); +#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 + return TRUE; } +#endif static int try_grab_keyboard(struct askpass_ctx *ctx) { - int ret = gdk_keyboard_grab(ctx->dialog->window, FALSE, GDK_CURRENT_TIME); + int ret; + +#if GTK_CHECK_VERSION(3,20,0) + /* + * Grabbing the keyboard in GTK 3.20 requires the new notion of + * GdkSeat. + */ + GdkSeat *seat; + + seat = gdk_display_get_default_seat + (gtk_widget_get_display(ctx->dialog)); + if (!seat) + return FALSE; + + ctx->seat = seat; + ret = gdk_seat_grab(seat, gtk_widget_get_window(ctx->dialog), + GDK_SEAT_CAPABILITY_KEYBOARD, + TRUE, NULL, NULL, NULL, NULL); +#elif GTK_CHECK_VERSION(3,0,0) + /* + * And it has to be done differently again prior to GTK 3.20. + */ + GdkDeviceManager *dm; + GdkDevice *pointer, *keyboard; + + dm = gdk_display_get_device_manager + (gtk_widget_get_display(ctx->dialog)); + if (!dm) + return FALSE; + + pointer = gdk_device_manager_get_client_pointer(dm); + if (!pointer) + return FALSE; + keyboard = gdk_device_get_associated_device(pointer); + if (!keyboard) + return FALSE; + if (gdk_device_get_source(keyboard) != GDK_SOURCE_KEYBOARD) + return FALSE; + + ctx->keyboard = keyboard; + ret = gdk_device_grab(ctx->keyboard, + gtk_widget_get_window(ctx->dialog), + GDK_OWNERSHIP_NONE, + TRUE, + 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), + FALSE, GDK_CURRENT_TIME); +#endif + return ret == GDK_GRAB_SUCCESS; } @@ -189,7 +308,7 @@ static const char *gtk_askpass_setup(struct askpass_ctx *ctx, const char *prompt_text) { int i; - gboolean success[2]; + GtkBox *action_area; ctx->passlen = 0; ctx->passsize = 2048; @@ -198,41 +317,70 @@ static const char *gtk_askpass_setup(struct askpass_ctx *ctx, /* * Create widgets. */ - ctx->dialog = gtk_dialog_new(); + ctx->dialog = our_dialog_new(); gtk_window_set_title(GTK_WINDOW(ctx->dialog), window_title); + gtk_window_set_position(GTK_WINDOW(ctx->dialog), GTK_WIN_POS_CENTER); ctx->promptlabel = gtk_label_new(prompt_text); + align_label_left(GTK_LABEL(ctx->promptlabel)); + gtk_widget_show(ctx->promptlabel); gtk_label_set_line_wrap(GTK_LABEL(ctx->promptlabel), TRUE); - gtk_container_add(GTK_CONTAINER(gtk_dialog_get_content_area - (GTK_DIALOG(ctx->dialog))), - ctx->promptlabel); +#if GTK_CHECK_VERSION(3,0,0) + gtk_label_set_width_chars(GTK_LABEL(ctx->promptlabel), 48); +#endif + our_dialog_add_to_content_area(GTK_WINDOW(ctx->dialog), + ctx->promptlabel, TRUE, TRUE, 0); +#if GTK_CHECK_VERSION(2,0,0) ctx->imc = gtk_im_multicontext_new(); - 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; - gdk_colormap_alloc_colors(ctx->colmap, ctx->cols, 2, - FALSE, TRUE, success); - if (!success[0] | !success[1]) - return "unable to allocate colours"; +#endif +#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; + gdk_colormap_alloc_colors(ctx->colmap, ctx->cols, 2, + FALSE, TRUE, success); + if (!success[0] | !success[1]) + return "unable to allocate colours"; + } +#endif + + action_area = our_dialog_make_action_hbox(GTK_WINDOW(ctx->dialog)); + for (i = 0; i < N_DRAWING_AREAS; i++) { ctx->drawingareas[i].area = gtk_drawing_area_new(); +#ifndef DRAW_DEFAULT_CAIRO ctx->drawingareas[i].cols = ctx->cols; +#endif ctx->drawingareas[i].current = 0; 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); - gtk_container_add(GTK_CONTAINER(gtk_dialog_get_action_area - (GTK_DIALOG(ctx->dialog))), - ctx->drawingareas[i].area); - gtk_signal_connect(GTK_OBJECT(ctx->drawingareas[i].area), - "configure_event", - GTK_SIGNAL_FUNC(configure_area), - &ctx->drawingareas[i]); - gtk_signal_connect(GTK_OBJECT(ctx->drawingareas[i].area), - "expose_event", - GTK_SIGNAL_FUNC(expose_area), - &ctx->drawingareas[i]); + gtk_box_pack_end(action_area, ctx->drawingareas[i].area, + TRUE, TRUE, 5); + g_signal_connect(G_OBJECT(ctx->drawingareas[i].area), + "configure_event", + G_CALLBACK(configure_area), + &ctx->drawingareas[i]); +#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 + g_signal_connect(G_OBJECT(ctx->drawingareas[i].area), + "expose_event", + G_CALLBACK(expose_area), + &ctx->drawingareas[i]); +#endif + +#if GTK_CHECK_VERSION(3,0,0) + g_object_set(G_OBJECT(ctx->drawingareas[i].area), + "margin-bottom", 8, (const char *)NULL); +#endif + gtk_widget_show(ctx->drawingareas[i].area); } ctx->active_area = rand() % N_DRAWING_AREAS; @@ -246,7 +394,10 @@ static const char *gtk_askpass_setup(struct askpass_ctx *ctx, * ensure key events go to it. */ gtk_widget_set_sensitive(ctx->promptlabel, TRUE); + +#if GTK_CHECK_VERSION(2,0,0) gtk_window_set_keep_above(GTK_WINDOW(ctx->dialog), TRUE); +#endif /* * Actually show the window, and wait for it to be shown. @@ -262,23 +413,33 @@ static const char *gtk_askpass_setup(struct askpass_ctx *ctx, /* * And now that we've got the keyboard grab, connect up our - * keyboard handlers, and display the prompt. + * keyboard handlers. */ +#if GTK_CHECK_VERSION(2,0,0) g_signal_connect(G_OBJECT(ctx->imc), "commit", G_CALLBACK(input_method_commit_event), ctx); - gtk_signal_connect(GTK_OBJECT(ctx->promptlabel), "key_press_event", - GTK_SIGNAL_FUNC(key_event), ctx); - gtk_signal_connect(GTK_OBJECT(ctx->promptlabel), "key_release_event", - GTK_SIGNAL_FUNC(key_event), ctx); - gtk_im_context_set_client_window(ctx->imc, ctx->dialog->window); - gtk_widget_show(ctx->promptlabel); +#endif + g_signal_connect(G_OBJECT(ctx->promptlabel), "key_press_event", + G_CALLBACK(key_event), ctx); + g_signal_connect(G_OBJECT(ctx->promptlabel), "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 return NULL; } static void gtk_askpass_cleanup(struct askpass_ctx *ctx) { +#if GTK_CHECK_VERSION(3,20,0) + gdk_seat_ungrab(ctx->seat); +#elif GTK_CHECK_VERSION(3,0,0) + gdk_device_ungrab(ctx->keyboard, GDK_CURRENT_TIME); +#else gdk_keyboard_ungrab(GDK_CURRENT_TIME); +#endif gtk_grab_remove(ctx->promptlabel); if (ctx->passphrase) { @@ -364,7 +525,7 @@ int main(int argc, char **argv) ret = dupprintf("usage: %s ", argv[0]); } else { srand(time(NULL)); - ret = gtk_askpass_main(argv[1], &success); + ret = gtk_askpass_main(NULL, "Enter passphrase", argv[1], &success); } if (!success) {