X-Git-Url: https://asedeno.scripts.mit.edu/gitweb/?a=blobdiff_plain;f=unix%2Fgtkdlg.c;h=573111aeede967676f5f2d6c4a86c87c43226046;hb=1bdeff715c9b8c79ec5dc021b5aca403f575f1ae;hp=c044c0623347d1435e641edcb45a28b358501514;hpb=856a0ecc4a89ee113b54612b51678baca7af5d97;p=PuTTY.git diff --git a/unix/gtkdlg.c b/unix/gtkdlg.c index c044c062..573111ae 100644 --- a/unix/gtkdlg.c +++ b/unix/gtkdlg.c @@ -6,26 +6,30 @@ #include #include #include + #include #if !GTK_CHECK_VERSION(3,0,0) #include #endif + +#define MAY_REFER_TO_GTK_IN_HEADERS + +#include "putty.h" +#include "gtkcompat.h" +#include "gtkcols.h" +#include "gtkfont.h" +#include "gtkmisc.h" + #ifndef NOT_X_WINDOWS #include #include #include #endif -#include "gtkcompat.h" - -#include "gtkcols.h" -#include "gtkfont.h" - #ifdef TESTMODE #define PUTTY_DO_GLOBALS /* actually _define_ globals */ #endif -#include "putty.h" #include "storage.h" #include "dialog.h" #include "tree234.h" @@ -1035,10 +1039,12 @@ void dlg_beep(void *dlg) gdk_beep(); } +#if !GTK_CHECK_VERSION(3,0,0) static void errmsg_button_clicked(GtkButton *button, gpointer data) { gtk_widget_destroy(GTK_WIDGET(data)); } +#endif static void set_transient_window_pos(GtkWidget *parent, GtkWidget *child) { @@ -1074,11 +1080,23 @@ static void set_transient_window_pos(GtkWidget *parent, GtkWidget *child) void dlg_error_msg(void *dlg, const char *msg) { struct dlgparam *dp = (struct dlgparam *)dlg; - GtkWidget *window, *hbox, *text, *ok; + GtkWidget *window; + +#if GTK_CHECK_VERSION(3,0,0) + window = gtk_message_dialog_new(GTK_WINDOW(dp->window), + (GTK_DIALOG_MODAL | + GTK_DIALOG_DESTROY_WITH_PARENT), + GTK_MESSAGE_ERROR, + GTK_BUTTONS_CLOSE, + "%s", msg); + gtk_dialog_run(GTK_DIALOG(window)); + gtk_widget_destroy(window); +#else + GtkWidget *hbox, *text, *ok; window = gtk_dialog_new(); text = gtk_label_new(msg); - gtk_misc_set_alignment(GTK_MISC(text), 0.0, 0.0); + align_label_left(GTK_LABEL(text)); hbox = gtk_hbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(hbox), text, FALSE, FALSE, 20); gtk_box_pack_start(GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(window))), @@ -1102,6 +1120,8 @@ void dlg_error_msg(void *dlg, const char *msg) set_transient_window_pos(dp->window, window); gtk_widget_show(window); gtk_main(); +#endif + post_main(); } @@ -2274,6 +2294,9 @@ GtkWidget *layout_ctrls(struct dlgparam *dp, struct Shortcuts *scs, */ g_signal_connect(G_OBJECT(w), "changed", G_CALLBACK(droplist_selchange), dp); + + g_signal_connect(G_OBJECT(w), "focus_in_event", + G_CALLBACK(widget_focus), dp); #endif } else { #if !GTK_CHECK_VERSION(2,0,0) @@ -2380,6 +2403,8 @@ GtkWidget *layout_ctrls(struct dlgparam *dp, struct Shortcuts *scs, uc->treeview = w; g_signal_connect(G_OBJECT(w), "row-activated", G_CALLBACK(listbox_doubleclick), dp); + g_signal_connect(G_OBJECT(w), "focus_in_event", + G_CALLBACK(widget_focus), dp); g_signal_connect(G_OBJECT(sel), "changed", G_CALLBACK(listbox_selchange), dp); @@ -2409,7 +2434,7 @@ GtkWidget *layout_ctrls(struct dlgparam *dp, struct Shortcuts *scs, g_object_set(G_OBJECT(cellrend), "ellipsize", PANGO_ELLIPSIZE_END, "ellipsize-set", TRUE, - NULL); + (const char *)NULL); } column = gtk_tree_view_column_new_with_attributes ("heading", cellrend, "text", i+1, (char *)NULL); @@ -2448,7 +2473,7 @@ GtkWidget *layout_ctrls(struct dlgparam *dp, struct Shortcuts *scs, #endif shortcut_add(scs, label, ctrl->listbox.shortcut, - SHORTCUT_FOCUS, w); + SHORTCUT_UCTRL, uc); container = columns_new(4); if (ctrl->listbox.percentwidth == 100) { @@ -2514,7 +2539,7 @@ GtkWidget *layout_ctrls(struct dlgparam *dp, struct Shortcuts *scs, */ uc->text = w = gtk_label_new(uc->ctrl->generic.label); #endif - gtk_misc_set_alignment(GTK_MISC(w), 0.0, 0.0); + align_label_left(GTK_LABEL(w)); gtk_label_set_line_wrap(GTK_LABEL(w), TRUE); break; } @@ -2860,7 +2885,7 @@ void shortcut_add(struct Shortcuts *scs, GtkWidget *labelw, scs->sc[chr].action = action; - if (action == SHORTCUT_FOCUS) { + if (action == SHORTCUT_FOCUS || action == SHORTCUT_TREE) { scs->sc[chr].uc = NULL; scs->sc[chr].widget = (GtkWidget *)ptr; } else { @@ -2904,78 +2929,6 @@ int get_listitemheight(GtkWidget *w) #endif } -void set_dialog_action_area(GtkDialog *dlg, GtkWidget *w) -{ -#if !GTK_CHECK_VERSION(2,0,0) - - /* - * In GTK 1, laying out the buttons at the bottom of the - * configuration box is nice and easy, because a GtkDialog's - * action_area is a GtkHBox which stretches to cover the full - * width of the dialog. So we just put our Columns widget - * straight into that hbox, and it ends up just where we want - * it. - */ - gtk_box_pack_start(GTK_BOX(dlg->action_area), w, TRUE, TRUE, 0); - -#else - /* - * In GTK 2, the action area is now a GtkHButtonBox and its - * layout behaviour seems to be different: it doesn't stretch - * to cover the full width of the window, but instead finds its - * own preferred width and right-aligns that within the window. - * This isn't what we want, because we have both left-aligned - * and right-aligned buttons coming out of the above call to - * layout_ctrls(), and right-aligning the whole thing will - * result in the former being centred and looking weird. - * - * So instead we abandon the dialog's action area completely: - * we gtk_widget_hide() it in the below code, and we also call - * gtk_dialog_set_has_separator() to remove the separator above - * it. We then insert our own action area into the end of the - * dialog's main vbox, and add our own separator above that. - * - * (Ideally, if we were a native GTK app, we would use the - * GtkHButtonBox's _own_ innate ability to support one set of - * buttons being right-aligned and one left-aligned. But to do - * that here, we would have to either (a) pick apart our cross- - * platform layout structures and treat them specially for this - * particular set of controls, which would be painful, or else - * (b) develop a special and simpler cross-platform - * representation for these particular controls, and introduce - * special-case code into all the _other_ platforms to handle - * it. Neither appeals. Therefore, I regretfully discard the - * GTKHButtonBox and go it alone.) - */ - - GtkWidget *align; - align = gtk_alignment_new(0, 0, 1, 1); - gtk_container_add(GTK_CONTAINER(align), w); - /* - * The purpose of this GtkAlignment is to provide padding - * around the buttons. The padding we use is twice the padding - * used in our GtkColumns, because we nest two GtkColumns most - * of the time (one separating the tree view from the main - * controls, and another for the main controls themselves). - */ -#if GTK_CHECK_VERSION(2,4,0) - gtk_alignment_set_padding(GTK_ALIGNMENT(align), 8, 8, 8, 8); -#endif - gtk_widget_show(align); - gtk_box_pack_end(GTK_BOX(gtk_dialog_get_content_area(dlg)), - align, FALSE, TRUE, 0); - w = gtk_hseparator_new(); - gtk_box_pack_end(GTK_BOX(gtk_dialog_get_content_area(dlg)), - w, FALSE, TRUE, 0); - gtk_widget_show(w); - gtk_widget_hide(gtk_dialog_get_action_area(dlg)); -#if !GTK_CHECK_VERSION(3,0,0) - /* This cosmetic property is withdrawn in GTK 3's GtkDialog */ - g_object_set(G_OBJECT(dlg), "has-separator", TRUE, (const char *)NULL); -#endif -#endif -} - #if GTK_CHECK_VERSION(2,0,0) void initial_treeview_collapse(struct dlgparam *dp, GtkWidget *tree) { @@ -3032,7 +2985,7 @@ int do_config_box(const char *title, Conf *conf, int midsession, scs.sc[index].action = SHORTCUT_EMPTY; } - window = gtk_dialog_new(); + window = our_dialog_new(); ctrlbox = ctrl_new_box(); protocol = conf_get_int(conf, CONF_protocol); @@ -3042,9 +2995,7 @@ int do_config_box(const char *title, Conf *conf, int midsession, gtk_window_set_title(GTK_WINDOW(window), title); hbox = gtk_hbox_new(FALSE, 4); - gtk_box_pack_start - (GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(window))), - hbox, TRUE, TRUE, 0); + our_dialog_add_to_content_area(GTK_WINDOW(window), hbox, TRUE, TRUE, 0); gtk_container_set_border_width(GTK_CONTAINER(hbox), 10); gtk_widget_show(hbox); vbox = gtk_vbox_new(FALSE, 4); @@ -3098,7 +3049,7 @@ int do_config_box(const char *title, Conf *conf, int midsession, if (!*s->pathname) { w = layout_ctrls(&dp, &scs, s, GTK_WINDOW(window)); - set_dialog_action_area(GTK_DIALOG(window), w); + our_dialog_set_action_area(GTK_WINDOW(window), w); } else { int j = path ? ctrl_path_compare(s->pathname, path) : 0; if (j != INT_MAX) { /* add to treeview, start new panel */ @@ -3369,7 +3320,7 @@ int messagebox(GtkWidget *parentwin, const char *title, const char *msg, union control *c; struct dlgparam dp; struct Shortcuts scs; - int index, ncols; + int index, ncols, min_type; va_list ap; dlg_init(&dp); @@ -3380,13 +3331,23 @@ int messagebox(GtkWidget *parentwin, const char *title, const char *msg, ctrlbox = ctrl_new_box(); + /* + * Preliminary pass over the va_list, to count up the number of + * buttons and find out what kinds there are. + */ ncols = 0; va_start(ap, minwid); + min_type = +1; while (va_arg(ap, char *) != NULL) { - ncols++; + int type; + (void) va_arg(ap, int); /* shortcut */ - (void) va_arg(ap, int); /* normal/default/cancel */ + type = va_arg(ap, int); /* normal/default/cancel */ (void) va_arg(ap, int); /* end value */ + + ncols++; + if (min_type > type) + min_type = type; } va_end(ap); @@ -3411,7 +3372,17 @@ int messagebox(GtkWidget *parentwin, const char *title, const char *msg, c->generic.column = index++; if (type > 0) c->button.isdefault = TRUE; - else if (type < 0) + + /* We always arrange that _some_ button is labelled as + * 'iscancel', so that pressing Escape will always cause + * win_key_press to do something. The button we choose is + * whichever has the smallest type value: this means that real + * cancel buttons (labelled -1) will be picked if one is + * there, or in cases where the options are yes/no (1,0) then + * no will be picked, and if there's only one option (a box + * that really is just showing a _message_ and not even asking + * a question) then that will be picked. */ + if (type == min_type) c->button.iscancel = TRUE; } va_end(ap); @@ -3419,17 +3390,15 @@ int messagebox(GtkWidget *parentwin, const char *title, const char *msg, s1 = ctrl_getset(ctrlbox, "x", "", ""); ctrl_text(s1, msg, HELPCTX(no_help)); - window = gtk_dialog_new(); + window = our_dialog_new(); gtk_window_set_title(GTK_WINDOW(window), title); w0 = layout_ctrls(&dp, &scs, s0, GTK_WINDOW(window)); - set_dialog_action_area(GTK_DIALOG(window), w0); + our_dialog_set_action_area(GTK_WINDOW(window), w0); gtk_widget_show(w0); w1 = layout_ctrls(&dp, &scs, s1, GTK_WINDOW(window)); gtk_container_set_border_width(GTK_CONTAINER(w1), 10); gtk_widget_set_size_request(w1, minwid+20, -1); - gtk_box_pack_start - (GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(window))), - w1, TRUE, TRUE, 0); + our_dialog_add_to_content_area(GTK_WINDOW(window), w1, TRUE, TRUE, 0); gtk_widget_show(w1); dp.shortcuts = &scs; @@ -3460,13 +3429,6 @@ int messagebox(GtkWidget *parentwin, const char *title, const char *msg, return dp.retval; } -int string_width(const char *text) -{ - int ret; - get_label_text_dimensions(text, &ret, NULL); - return ret; -} - int reallyclose(void *frontend) { char *title = dupcat(appname, " Exit Confirmation", NULL); @@ -3558,7 +3520,8 @@ int askalg(void *frontend, const char *algtype, const char *algname, text = dupprintf(msg, algtype, algname); ret = messagebox(GTK_WIDGET(get_window(frontend)), "PuTTY Security Alert", text, - string_width("Continue with connection?"), + string_width("Reasonably long line of text as a width" + " template"), "Yes", 'y', 0, 1, "No", 'n', 0, 0, NULL); @@ -3623,6 +3586,15 @@ static void about_close_clicked(GtkButton *button, gpointer data) aboutbox = NULL; } +static void about_key_press(GtkWidget *widget, GdkEventKey *event, + gpointer data) +{ + if (event->keyval == GDK_KEY_Escape && aboutbox) { + gtk_widget_destroy(aboutbox); + aboutbox = NULL; + } +} + static void licence_clicked(GtkButton *button, gpointer data) { char *title; @@ -3669,6 +3641,7 @@ static void licence_clicked(GtkButton *button, gpointer data) void about_box(void *window) { GtkWidget *w; + GtkBox *action_area; char *title; if (aboutbox) { @@ -3676,7 +3649,7 @@ void about_box(void *window) return; } - aboutbox = gtk_dialog_new(); + aboutbox = our_dialog_new(); gtk_container_set_border_width(GTK_CONTAINER(aboutbox), 10); title = dupcat("About ", appname, NULL); gtk_window_set_title(GTK_WINDOW(aboutbox), title); @@ -3685,38 +3658,34 @@ void about_box(void *window) w = gtk_button_new_with_label("Close"); gtk_widget_set_can_default(w, TRUE); gtk_window_set_default(GTK_WINDOW(aboutbox), w); - gtk_box_pack_end(GTK_BOX(gtk_dialog_get_action_area(GTK_DIALOG(aboutbox))), - w, FALSE, FALSE, 0); + action_area = our_dialog_make_action_hbox(GTK_WINDOW(aboutbox)); + gtk_box_pack_end(action_area, w, FALSE, FALSE, 0); g_signal_connect(G_OBJECT(w), "clicked", G_CALLBACK(about_close_clicked), NULL); gtk_widget_show(w); w = gtk_button_new_with_label("View Licence"); gtk_widget_set_can_default(w, TRUE); - gtk_box_pack_end(GTK_BOX(gtk_dialog_get_action_area(GTK_DIALOG(aboutbox))), - w, FALSE, FALSE, 0); + gtk_box_pack_end(action_area, w, FALSE, FALSE, 0); g_signal_connect(G_OBJECT(w), "clicked", G_CALLBACK(licence_clicked), NULL); gtk_widget_show(w); w = gtk_label_new(appname); - gtk_box_pack_start - (GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(aboutbox))), - w, FALSE, FALSE, 0); + our_dialog_add_to_content_area(GTK_WINDOW(aboutbox), w, FALSE, FALSE, 0); gtk_widget_show(w); w = gtk_label_new(ver); - gtk_box_pack_start - (GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(aboutbox))), - w, FALSE, FALSE, 5); + our_dialog_add_to_content_area(GTK_WINDOW(aboutbox), w, FALSE, FALSE, 5); gtk_widget_show(w); w = gtk_label_new("Copyright 1997-2015 Simon Tatham. All rights reserved"); - gtk_box_pack_start - (GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(aboutbox))), - w, FALSE, FALSE, 5); + our_dialog_add_to_content_area(GTK_WINDOW(aboutbox), w, FALSE, FALSE, 5); gtk_widget_show(w); + g_signal_connect(G_OBJECT(aboutbox), "key_press_event", + G_CALLBACK(about_key_press), NULL); + set_transient_window_pos(GTK_WIDGET(window), aboutbox); gtk_window_set_transient_for(GTK_WINDOW(aboutbox), GTK_WINDOW(window)); @@ -3890,12 +3859,12 @@ void showeventlog(void *estuff, void *parentwin) c->listbox.percentages[1] = 10; c->listbox.percentages[2] = 65; - es->window = window = gtk_dialog_new(); + es->window = window = our_dialog_new(); title = dupcat(appname, " Event Log", NULL); gtk_window_set_title(GTK_WINDOW(window), title); sfree(title); w0 = layout_ctrls(&es->dp, &es->scs, s0, GTK_WINDOW(window)); - set_dialog_action_area(GTK_DIALOG(window), w0); + our_dialog_set_action_area(GTK_WINDOW(window), w0); gtk_widget_show(w0); w1 = layout_ctrls(&es->dp, &es->scs, s1, GTK_WINDOW(window)); gtk_container_set_border_width(GTK_CONTAINER(w1), 10); @@ -3903,9 +3872,7 @@ void showeventlog(void *estuff, void *parentwin) ("LINE OF TEXT GIVING WIDTH OF EVENT LOG IS " "QUITE LONG 'COS SSH LOG ENTRIES ARE WIDE"), -1); - gtk_box_pack_start - (GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(window))), - w1, TRUE, TRUE, 0); + our_dialog_add_to_content_area(GTK_WINDOW(window), w1, TRUE, TRUE, 0); gtk_widget_show(w1); es->dp.data = es;