X-Git-Url: https://asedeno.scripts.mit.edu/gitweb/?a=blobdiff_plain;f=unix%2Fgtkdlg.c;h=4eb4b010a4341781b3f4a5fd59bed27e39a3614d;hb=095072fa46b2d7b8beafaddb2f873d2f500a1e10;hp=8a696ec1646d753bc61c5992c29d85dad2b20316;hpb=46b7cb6edb9e8218d65b33ddca8db45fca13535e;p=PuTTY.git diff --git a/unix/gtkdlg.c b/unix/gtkdlg.c index 8a696ec1..4eb4b010 100644 --- a/unix/gtkdlg.c +++ b/unix/gtkdlg.c @@ -33,6 +33,7 @@ #include "storage.h" #include "dialog.h" #include "tree234.h" +#include "licence.h" #if GTK_CHECK_VERSION(2,0,0) /* Decide which of GtkFileChooserDialog and GtkFileSelection to use */ @@ -2083,6 +2084,8 @@ GtkWidget *layout_ctrls(struct dlgparam *dp, struct Shortcuts *scs, G_TYPE_STRING); w = gtk_combo_box_new_with_model_and_entry (GTK_TREE_MODEL(uc->listmodel)); + g_object_set(G_OBJECT(w), "entry-text-column", 1, + (const char *)NULL); /* We cannot support password combo boxes. */ assert(!ctrl->editbox.password); uc->combo = w; @@ -2473,7 +2476,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) { @@ -3312,15 +3315,15 @@ static void messagebox_handler(union control *ctrl, void *dlg, dlg_end(dlg, ctrl->generic.context.i); } int messagebox(GtkWidget *parentwin, const char *title, const char *msg, - int minwid, ...) + int minwid, int selectable, ...) { GtkWidget *window, *w0, *w1; struct controlbox *ctrlbox; struct controlset *s0, *s1; - union control *c; + union control *c, *textctrl; struct dlgparam dp; struct Shortcuts scs; - int index, ncols; + int index, ncols, min_type; va_list ap; dlg_init(&dp); @@ -3331,13 +3334,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); + va_start(ap, selectable); + 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); @@ -3347,7 +3360,7 @@ int messagebox(GtkWidget *parentwin, const char *title, const char *msg, c->columns.percentages = sresize(c->columns.percentages, ncols, int); for (index = 0; index < ncols; index++) c->columns.percentages[index] = (index+1)*100/ncols - index*100/ncols; - va_start(ap, minwid); + va_start(ap, selectable); index = 0; while (1) { char *title = va_arg(ap, char *); @@ -3362,13 +3375,23 @@ 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); s1 = ctrl_getset(ctrlbox, "x", "", ""); - ctrl_text(s1, msg, HELPCTX(no_help)); + textctrl = ctrl_text(s1, msg, HELPCTX(no_help)); window = our_dialog_new(); gtk_window_set_title(GTK_WINDOW(window), title); @@ -3386,6 +3409,26 @@ int messagebox(GtkWidget *parentwin, const char *title, const char *msg, dp.retval = 0; dp.window = window; + if (selectable) { +#if GTK_CHECK_VERSION(2,0,0) + struct uctrl *uc = dlg_find_byctrl(&dp, textctrl); + gtk_label_set_selectable(GTK_LABEL(uc->text), TRUE); + + /* + * GTK selectable labels have a habit of selecting their + * entire contents when they gain focus. It's ugly to have + * text in a message box start up all selected, so we suppress + * this by manually selecting none of it - but we must do this + * when the widget _already has_ focus, otherwise our work + * will be undone when it gains it shortly. + */ + gtk_widget_grab_focus(uc->text); + gtk_label_select_region(GTK_LABEL(uc->text), 0, 0); +#else + (void)textctrl; /* placate warning */ +#endif + } + gtk_window_set_modal(GTK_WINDOW(window), TRUE); if (parentwin) { set_transient_window_pos(parentwin, window); @@ -3393,7 +3436,9 @@ int messagebox(GtkWidget *parentwin, const char *title, const char *msg, GTK_WINDOW(parentwin)); } else gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER); + gtk_container_set_focus_child(GTK_CONTAINER(window), NULL); gtk_widget_show(window); + gtk_window_set_focus(GTK_WINDOW(window), NULL); g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(window_destroy), NULL); @@ -3415,6 +3460,7 @@ int reallyclose(void *frontend) int ret = messagebox(GTK_WIDGET(get_window(frontend)), title, "Are you sure you want to close this session?", string_width("Most of the width of the above text"), + FALSE, "Yes", 'y', +1, 1, "No", 'n', -1, 0, NULL); @@ -3468,6 +3514,7 @@ int verify_ssh_host_key(void *frontend, char *host, int port, ret = messagebox(GTK_WIDGET(get_window(frontend)), "PuTTY Security Alert", text, string_width(fingerprint), + TRUE, "Accept", 'a', 0, 2, "Connect Once", 'o', 0, 1, "Cancel", 'c', -1, 0, @@ -3500,7 +3547,40 @@ 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"), + FALSE, + "Yes", 'y', 0, 1, + "No", 'n', 0, 0, + NULL); + sfree(text); + + if (ret) { + return 1; + } else { + return 0; + } +} + +int askhk(void *frontend, const char *algname, const char *betteralgs, + void (*callback)(void *ctx, int result), void *ctx) +{ + static const char msg[] = + "The first host key type we have stored for this server\n" + "is %s, which is below the configured warning threshold.\n" + "The server also provides the following types of host key\n" + "above the threshold, which we do not have stored:\n" + "%s\n" + "Continue with connection?"; + char *text; + int ret; + + text = dupprintf(msg, algname, betteralgs); + ret = messagebox(GTK_WIDGET(get_window(frontend)), + "PuTTY Security Alert", text, + string_width("is ecdsa-nistp521, which is" + " below the configured warning threshold."), + FALSE, "Yes", 'y', 0, 1, "No", 'n', 0, 0, NULL); @@ -3524,14 +3604,14 @@ void fatal_message_box(void *window, const char *msg) { messagebox(window, "PuTTY Fatal Error", msg, string_width("REASONABLY LONG LINE OF TEXT FOR BASIC SANITY"), - "OK", 'o', 1, 1, NULL); + FALSE, "OK", 'o', 1, 1, NULL); } void nonfatal_message_box(void *window, const char *msg) { messagebox(window, "PuTTY Error", msg, string_width("REASONABLY LONG LINE OF TEXT FOR BASIC SANITY"), - "OK", 'o', 1, 1, NULL); + FALSE, "OK", 'o', 1, 1, NULL); } void fatalbox(const char *p, ...) @@ -3565,46 +3645,25 @@ 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; - const char *licence = - "Copyright 1997-2015 Simon Tatham.\n\n" - - "Portions copyright Robert de Bath, Joris van Rantwijk, Delian " - "Delchev, Andreas Schultz, Jeroen Massar, Wez Furlong, Nicolas " - "Barry, Justin Bradford, Ben Harris, Malcolm Smith, Ahmad Khalifa, " - "Markus Kuhn, Colin Watson, Christopher Staite, and CORE SDI S.A.\n\n" - - "Permission is hereby granted, free of charge, to any person " - "obtaining a copy of this software and associated documentation " - "files (the ""Software""), to deal in the Software without restriction, " - "including without limitation the rights to use, copy, modify, merge, " - "publish, distribute, sublicense, and/or sell copies of the Software, " - "and to permit persons to whom the Software is furnished to do so, " - "subject to the following conditions:\n\n" - - "The above copyright notice and this permission notice shall be " - "included in all copies or substantial portions of the Software.\n\n" - - "THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT " - "WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, " - "INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF " - "MERCHANTABILITY, FITNESS FOR A PARTICULAR " - "PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE " - "COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES " - "OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, " - "TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN " - "CONNECTION WITH THE SOFTWARE OR THE USE OR " - "OTHER DEALINGS IN THE SOFTWARE."; - title = dupcat(appname, " Licence", NULL); assert(aboutbox != NULL); - messagebox(aboutbox, title, licence, + messagebox(aboutbox, title, LICENCE_TEXT("\n\n"), string_width("LONGISH LINE OF TEXT SO THE LICENCE" " BOX ISN'T EXCESSIVELY TALL AND THIN"), - "OK", 'o', 1, 1, NULL); + TRUE, "OK", 'o', 1, 1, NULL); sfree(title); } @@ -3641,22 +3700,38 @@ void about_box(void *window) G_CALLBACK(licence_clicked), NULL); gtk_widget_show(w); - w = gtk_label_new(appname); + { + char *buildinfo_text = buildinfo("\n"); + char *label_text = dupprintf + ("%s\n\n%s\n\n%s\n\n%s", + appname, ver, buildinfo_text, + "Copyright " SHORT_COPYRIGHT_DETAILS ". All rights reserved"); + w = gtk_label_new(label_text); + gtk_label_set_justify(GTK_LABEL(w), GTK_JUSTIFY_CENTER); +#if GTK_CHECK_VERSION(2,0,0) + gtk_label_set_selectable(GTK_LABEL(w), TRUE); +#endif + sfree(label_text); + } our_dialog_add_to_content_area(GTK_WINDOW(aboutbox), w, FALSE, FALSE, 0); +#if GTK_CHECK_VERSION(2,0,0) + /* + * Same precautions against initial select-all as in messagebox(). + */ + gtk_widget_grab_focus(w); + gtk_label_select_region(GTK_LABEL(w), 0, 0); +#endif gtk_widget_show(w); - w = gtk_label_new(ver); - 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"); - 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)); + gtk_container_set_focus_child(GTK_CONTAINER(aboutbox), NULL); gtk_widget_show(aboutbox); + gtk_window_set_focus(GTK_WINDOW(aboutbox), NULL); } struct eventlog_stuff { @@ -3918,6 +3993,7 @@ int askappend(void *frontend, Filename *filename, mbret = messagebox(get_window(frontend), mbtitle, message, string_width("LINE OF TEXT SUITABLE FOR THE" " ASKAPPEND WIDTH"), + FALSE, "Overwrite", 'o', 1, 2, "Append", 'a', 0, 1, "Disable", 'd', -1, 0,