From a8e9fd7860a3b7137ef45be294d370e2537dd495 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sun, 26 Nov 2017 17:21:32 +0000 Subject: [PATCH] Reimplement 'really close session?' as a non-modal message box. I've also moved it out into gtkwin.c, because it seemed easier to do the 'find existing instance of this dialog and raise it' dance there than to split it across source files pointlessly. --- unix/gtkdlg.c | 11 --------- unix/gtkwin.c | 66 +++++++++++++++++++++++++++++++++++++++++---------- unix/unix.h | 2 +- 3 files changed, 55 insertions(+), 24 deletions(-) diff --git a/unix/gtkdlg.c b/unix/gtkdlg.c index 3b7d9ab5..23fe909c 100644 --- a/unix/gtkdlg.c +++ b/unix/gtkdlg.c @@ -3467,17 +3467,6 @@ int message_box( return retval; } -int reallyclose(void *frontend) -{ - char *title = dupcat(appname, " Exit Confirmation", NULL); - int ret = message_box(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, &buttons_yn); - sfree(title); - return ret; -} - struct verify_ssh_host_key_result_ctx { char *host; int port; diff --git a/unix/gtkwin.c b/unix/gtkwin.c index ffb4040d..e8bc2894 100644 --- a/unix/gtkwin.c +++ b/unix/gtkwin.c @@ -450,6 +450,25 @@ void get_window_pixels(void *frontend, int *x, int *y) #endif } +/* + * Find out whether a dialog box already exists for this window in a + * particular DialogSlot. If it does, uniconify it (if we can) and + * raise it, so that the user realises they've already been asked this + * question. + */ +static int find_and_raise_dialog(struct gui_data *inst, enum DialogSlot slot) +{ + GtkWidget *dialog = inst->dialogs[slot]; + if (!dialog) + return FALSE; + +#if GTK_CHECK_VERSION(2,0,0) + gtk_window_deiconify(GTK_WINDOW(dialog)); +#endif + gdk_window_raise(gtk_widget_get_window(dialog)); + return TRUE; +} + /* * Return the window or icon title. */ @@ -459,12 +478,44 @@ char *get_window_title(void *frontend, int icon) return icon ? inst->icontitle : inst->wintitle; } +static void warn_on_close_callback(void *vctx, int result) +{ + struct gui_data *inst = (struct gui_data *)vctx; + unregister_dialog(inst, DIALOG_SLOT_WARN_ON_CLOSE); + if (result) + gtk_widget_destroy(inst->window); +} + +/* + * Handle the 'delete window' event (e.g. user clicking the WM close + * button). The return value FALSE means the window should close, and + * TRUE means it shouldn't. + * + * (That's counterintuitive, but really, in GTK terms, TRUE means 'I + * have done everything necessary to handle this event, so the default + * handler need not do anything', i.e. 'suppress default handler', + * i.e. 'do not close the window'.) + */ gint delete_window(GtkWidget *widget, GdkEvent *event, gpointer data) { struct gui_data *inst = (struct gui_data *)data; if (!inst->exited && conf_get_int(inst->conf, CONF_warn_on_close)) { - if (!reallyclose(inst)) - return TRUE; + /* + * We're not going to exit right now. We must put up a + * warn-on-close dialog, unless one already exists, in which + * case we'll just re-emphasise that one. + */ + if (!find_and_raise_dialog(inst, DIALOG_SLOT_WARN_ON_CLOSE)) { + char *title = dupcat(appname, " Exit Confirmation", NULL); + GtkWidget *dialog = create_message_box( + inst->window, title, + "Are you sure you want to close this session?", + string_width("Most of the width of the above text"), + FALSE, &buttons_yn, warn_on_close_callback, inst); + register_dialog(inst, DIALOG_SLOT_WARN_ON_CLOSE, dialog); + sfree(title); + } + return TRUE; } return FALSE; } @@ -4008,17 +4059,8 @@ void change_settings_menuitem(GtkMenuItem *item, gpointer data) GtkWidget *dialog; char *title; - if ((dialog = inst->dialogs[DIALOG_SLOT_RECONFIGURE]) != NULL) { - /* - * If this window already had a Change Settings box open, just - * find it and try to make it more prominent. - */ -#if GTK_CHECK_VERSION(2,0,0) - gtk_window_deiconify(GTK_WINDOW(dialog)); -#endif - gdk_window_raise(gtk_widget_get_window(dialog)); + if (find_and_raise_dialog(inst, DIALOG_SLOT_RECONFIGURE)) return; - } title = dupcat(appname, " Reconfiguration", NULL); diff --git a/unix/unix.h b/unix/unix.h index 2d9600c4..893f084e 100644 --- a/unix/unix.h +++ b/unix/unix.h @@ -154,6 +154,7 @@ enum DialogSlot { DIALOG_SLOT_RECONFIGURE, DIALOG_SLOT_NETWORK_PROMPT, DIALOG_SLOT_LOGFILE_PROMPT, + DIALOG_SLOT_WARN_ON_CLOSE, DIALOG_SLOT_LIMIT /* must remain last */ }; void register_dialog(void *frontend, enum DialogSlot slot, GtkWidget *dialog); @@ -173,7 +174,6 @@ void about_box(void *window); void *eventlogstuff_new(void); void showeventlog(void *estuff, void *parentwin); void logevent_dlg(void *estuff, const char *string); -int reallyclose(void *frontend); #ifdef MAY_REFER_TO_GTK_IN_HEADERS struct message_box_button { const char *title;