Finer granularity of config box handling. SSH packet logging should
[u/mdw/putty] / unix / gtkdlg.c
index e699732..1b58d14 100644 (file)
@@ -307,15 +307,18 @@ void dlg_listbox_clear(union control *ctrl, void *dlg)
 {
     struct dlgparam *dp = (struct dlgparam *)dlg;
     struct uctrl *uc = dlg_find_byctrl(dp, ctrl);
-    GtkContainer *cont;
 
     assert(uc->ctrl->generic.type == CTRL_EDITBOX ||
           uc->ctrl->generic.type == CTRL_LISTBOX);
     assert(uc->menu != NULL || uc->list != NULL);
 
-    cont = (uc->menu ? GTK_CONTAINER(uc->menu) : GTK_CONTAINER(uc->list));
-
-    gtk_container_foreach(cont, container_remove_and_destroy, cont);
+    if (uc->menu) {
+       gtk_container_foreach(GTK_CONTAINER(uc->menu),
+                             container_remove_and_destroy,
+                             GTK_CONTAINER(uc->menu));
+    } else {
+       gtk_list_clear_items(GTK_LIST(uc->list), 0, -1);
+    }
 }
 
 void dlg_listbox_del(union control *ctrl, void *dlg, int index)
@@ -486,6 +489,8 @@ int dlg_listbox_index(union control *ctrl, void *dlg)
 
     if (uc->menu)
        activeitem = gtk_menu_get_active(GTK_MENU(uc->menu));
+    else
+       activeitem = NULL;             /* unnecessarily placate gcc */
 
     children = gtk_container_children(GTK_CONTAINER(uc->menu ? uc->menu :
                                                    uc->list));
@@ -677,6 +682,35 @@ static void errmsg_button_clicked(GtkButton *button, gpointer data)
     gtk_widget_destroy(GTK_WIDGET(data));
 }
 
+static void set_transient_window_pos(GtkWidget *parent, GtkWidget *child)
+{
+    gint x, y, w, h, dx, dy;
+    GtkRequisition req;
+    gtk_window_set_position(GTK_WINDOW(child), GTK_WIN_POS_NONE);
+    gtk_widget_size_request(GTK_WIDGET(child), &req);
+
+    gdk_window_get_origin(GTK_WIDGET(parent)->window, &x, &y);
+    gdk_window_get_size(GTK_WIDGET(parent)->window, &w, &h);
+
+    /*
+     * One corner of the transient will be offset inwards, by 1/4
+     * of the parent window's size, from the corresponding corner
+     * of the parent window. The corner will be chosen so as to
+     * place the transient closer to the centre of the screen; this
+     * should avoid transients going off the edge of the screen on
+     * a regular basis.
+     */
+    if (x + w/2 < gdk_screen_width() / 2)
+        dx = x + w/4;                  /* work from left edges */
+    else
+        dx = x + 3*w/4 - req.width;    /* work from right edges */
+    if (y + h/2 < gdk_screen_height() / 2)
+        dy = y + h/4;                  /* work from top edges */
+    else
+        dy = y + 3*h/4 - req.height;   /* work from bottom edges */
+    gtk_widget_set_uposition(GTK_WIDGET(child), dx, dy);
+}
+
 void dlg_error_msg(void *dlg, char *msg)
 {
     struct dlgparam *dp = (struct dlgparam *)dlg;
@@ -705,15 +739,7 @@ void dlg_error_msg(void *dlg, char *msg)
                        GTK_SIGNAL_FUNC(window_destroy), NULL);
     gtk_window_set_modal(GTK_WINDOW(window), TRUE);
     gtk_window_set_transient_for(GTK_WINDOW(window), GTK_WINDOW(dp->window));
-    {
-       gint x, y, w, h, dx, dy;
-       gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_NONE);
-       gdk_window_get_origin(GTK_WIDGET(dp->window)->window, &x, &y);
-       gdk_window_get_size(GTK_WIDGET(dp->window)->window, &w, &h);
-       dx = x + w/4;
-       dy = y + h/4;
-       gtk_widget_set_uposition(GTK_WIDGET(window), dx, dy);
-    }
+    set_transient_window_pos(dp->window, window);
     gtk_widget_show(window);
     gtk_main();
 }
@@ -1914,7 +1940,7 @@ int get_listitemheight(void)
     return req.height;
 }
 
-int do_config_box(const char *title, Config *cfg)
+int do_config_box(const char *title, Config *cfg, int midsession)
 {
     GtkWidget *window, *hbox, *vbox, *cols, *label,
        *tree, *treescroll, *panels, *panelvbox;
@@ -1940,11 +1966,12 @@ int do_config_box(const char *title, Config *cfg)
        scs.sc[index].action = SHORTCUT_EMPTY;
     }
 
+    window = gtk_dialog_new();
+
     ctrlbox = ctrl_new_box();
-    setup_config_box(ctrlbox, &sl, FALSE, 0);
-    unix_setup_config_box(ctrlbox, FALSE);
+    setup_config_box(ctrlbox, &sl, midsession, cfg->protocol);
+    unix_setup_config_box(ctrlbox, midsession, window);
 
-    window = gtk_dialog_new();
     gtk_window_set_title(GTK_WINDOW(window), title);
     hbox = gtk_hbox_new(FALSE, 4);
     gtk_box_pack_start(GTK_BOX(GTK_DIALOG(window)->vbox), hbox, TRUE, TRUE, 0);
@@ -2218,13 +2245,7 @@ int messagebox(GtkWidget *parentwin, char *title, char *msg, int minwid, ...)
 
     gtk_window_set_modal(GTK_WINDOW(window), TRUE);
     if (parentwin) {
-       gint x, y, w, h, dx, dy;
-       gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_NONE);
-       gdk_window_get_origin(parentwin->window, &x, &y);
-       gdk_window_get_size(parentwin->window, &w, &h);
-       dx = x + w/4;
-       dy = y + h/4;
-       gtk_widget_set_uposition(GTK_WIDGET(window), dx, dy);
+        set_transient_window_pos(parentwin, window);
        gtk_window_set_transient_for(GTK_WINDOW(window),
                                     GTK_WINDOW(parentwin));
     } else
@@ -2253,6 +2274,19 @@ static int string_width(char *text)
     return req.width;
 }
 
+int reallyclose(void *frontend)
+{
+    char *title = dupcat(appname, " Exit Confirmation", NULL);
+    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"),
+                        "Yes", 'y', +1, 1,
+                        "No", 'n', -1, 0,
+                        NULL);
+    sfree(title);
+    return ret;
+}
+
 void verify_ssh_host_key(void *frontend, char *host, int port, char *keytype,
                         char *keystr, char *fingerprint)
 {
@@ -2419,7 +2453,7 @@ static void licence_clicked(GtkButton *button, gpointer data)
     sfree(title);
 }
 
-void about_box(void)
+void about_box(void *window)
 {
     GtkWidget *w;
     char *title;
@@ -2467,6 +2501,7 @@ void about_box(void)
                       w, FALSE, FALSE, 5);
     gtk_widget_show(w);
 
+    set_transient_window_pos(GTK_WIDGET(window), aboutbox);
     gtk_widget_show(aboutbox);
 }
 
@@ -2478,6 +2513,9 @@ struct eventlog_stuff {
     union control *listctrl;
     char **events;
     int nevents, negsize;
+    char *seldata;
+    int sellen;
+    int ignore_selchange;
 };
 
 static void eventlog_destroy(GtkWidget *widget, gpointer data)
@@ -2485,6 +2523,7 @@ static void eventlog_destroy(GtkWidget *widget, gpointer data)
     struct eventlog_stuff *es = (struct eventlog_stuff *)data;
 
     es->window = NULL;
+    sfree(es->seldata);
     dlg_cleanup(&es->dp);
     ctrl_free_box(es->eventbox);
 }
@@ -2508,8 +2547,82 @@ static void eventlog_list_handler(union control *ctrl, void *dlg,
            dlg_listbox_add(ctrl, dlg, es->events[i]);
        }
        dlg_update_done(ctrl, dlg);
+    } else if (event == EVENT_SELCHANGE) {
+        int i;
+        int selsize = 0;
+
+        /*
+         * If this SELCHANGE event is happening as a result of
+         * deliberate deselection because someone else has grabbed
+         * the selection, the last thing we want to do is pre-empt
+         * them.
+         */
+        if (es->ignore_selchange)
+            return;
+
+        /*
+         * Construct the data to use as the selection.
+         */
+        sfree(es->seldata);
+        es->seldata = NULL;
+        es->sellen = 0;
+        for (i = 0; i < es->nevents; i++) {
+            if (dlg_listbox_issel(ctrl, dlg, i)) {
+                int extralen = strlen(es->events[i]);
+
+                if (es->sellen + extralen + 2 > selsize) {
+                    selsize = es->sellen + extralen + 512;
+                    es->seldata = sresize(es->seldata, selsize, char);
+                }
+
+                strcpy(es->seldata + es->sellen, es->events[i]);
+                es->sellen += extralen;
+                es->seldata[es->sellen++] = '\n';
+            }
+        }
+
+        if (gtk_selection_owner_set(es->window, GDK_SELECTION_PRIMARY,
+                                    GDK_CURRENT_TIME)) {
+            extern GdkAtom compound_text_atom;
+
+            gtk_selection_add_target(es->window, GDK_SELECTION_PRIMARY,
+                                     GDK_SELECTION_TYPE_STRING, 1);
+            gtk_selection_add_target(es->window, GDK_SELECTION_PRIMARY,
+                                     compound_text_atom, 1);
+        }
+
     }
 }
+
+void eventlog_selection_get(GtkWidget *widget, GtkSelectionData *seldata,
+                            guint info, guint time_stamp, gpointer data)
+{
+    struct eventlog_stuff *es = (struct eventlog_stuff *)data;
+
+    gtk_selection_data_set(seldata, seldata->target, 8,
+                           es->seldata, es->sellen);
+}
+
+gint eventlog_selection_clear(GtkWidget *widget, GdkEventSelection *seldata,
+                              gpointer data)
+{
+    struct eventlog_stuff *es = (struct eventlog_stuff *)data;
+    struct uctrl *uc;
+
+    /*
+     * Deselect everything in the list box.
+     */
+    uc = dlg_find_byctrl(&es->dp, es->listctrl);
+    es->ignore_selchange = 1;
+    gtk_list_unselect_all(GTK_LIST(uc->list));
+    es->ignore_selchange = 0;
+
+    sfree(es->seldata);
+    es->sellen = 0;
+    es->seldata = NULL;
+    return TRUE;
+}
+
 void showeventlog(void *estuff, void *parentwin)
 {
     struct eventlog_stuff *es = (struct eventlog_stuff *)estuff;
@@ -2582,13 +2695,7 @@ void showeventlog(void *estuff, void *parentwin)
     dlg_refresh(NULL, &es->dp);
 
     if (parent) {
-       gint x, y, w, h, dx, dy;
-       gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_NONE);
-       gdk_window_get_origin(parent->window, &x, &y);
-       gdk_window_get_size(parent->window, &w, &h);
-       dx = x + w/4;
-       dy = y + h/4;
-       gtk_widget_set_uposition(GTK_WIDGET(window), dx, dy);
+        set_transient_window_pos(parent, window);
        gtk_window_set_transient_for(GTK_WINDOW(window),
                                     GTK_WINDOW(parent));
     } else
@@ -2599,6 +2706,10 @@ void showeventlog(void *estuff, void *parentwin)
                       GTK_SIGNAL_FUNC(eventlog_destroy), es);
     gtk_signal_connect(GTK_OBJECT(window), "key_press_event",
                       GTK_SIGNAL_FUNC(win_key_press), &es->dp);
+    gtk_signal_connect(GTK_OBJECT(window), "selection_get",
+                      GTK_SIGNAL_FUNC(eventlog_selection_get), es);
+    gtk_signal_connect(GTK_OBJECT(window), "selection_clear_event",
+                      GTK_SIGNAL_FUNC(eventlog_selection_clear), es);
 }
 
 void *eventlogstuff_new(void)
@@ -2633,3 +2744,31 @@ void logevent_dlg(void *estuff, char *string)
     }
     es->nevents++;
 }
+
+int askappend(void *frontend, Filename filename)
+{
+    static const char msgtemplate[] =
+       "The session log file \"%.*s\" already exists. "
+       "You can overwrite it with a new session log, "
+       "append your session log to the end of it, "
+       "or disable session logging for this session.";
+    char *message;
+    char *mbtitle;
+    int mbret;
+
+    message = dupprintf(msgtemplate, FILENAME_MAX, filename.path);
+    mbtitle = dupprintf("%s Log to File", appname);
+
+    mbret = messagebox(get_window(frontend), mbtitle, message,
+                      string_width("LINE OF TEXT SUITABLE FOR THE"
+                                   " ASKAPPEND WIDTH"),
+                      "Overwrite", 'o', 1, 2,
+                      "Append", 'a', 0, 1,
+                      "Disable", 'd', -1, 0,
+                      NULL);
+
+    sfree(message);
+    sfree(mbtitle);
+
+    return mbret;
+}