]> asedeno.scripts.mit.edu Git - PuTTY.git/commitdiff
Rework window geometry to avoid using geometry_widget.
authorSimon Tatham <anakin@pobox.com>
Tue, 29 Mar 2016 12:42:54 +0000 (13:42 +0100)
committerSimon Tatham <anakin@pobox.com>
Tue, 29 Mar 2016 12:57:10 +0000 (13:57 +0100)
Partly this is because the geometry_widget functionality is going away
in a later version of GTK3, so sooner or later we'll need not to be
using it anyway. But also, it turns out that GTK 3's geometry
calculations have the unfortunate effect of setting the window's base
and min heights to values that are not congruent mod height_increment
(because the former is the value we gave, but the latter is based on
the minimum height of the scrollbar), which confuses at least one
window manager (xfwm4) and causes the window to be created one row too
small.

So I've redone all the geometry computations my own way, based on the
knowledge that the only widgets visible in the top-level window are
the drawing area and the scrollbar and I know how both of those
behave, and taking care to keep base_height and min_height congruent
to avoid that xfwm4 bug.

unix/gtkwin.c

index 49db1fe5c2f7be9ad39dc0d556b934385ddf0ec3..f10a96ec822de148eb0c5b550d1361eb2b010278 100644 (file)
@@ -56,6 +56,7 @@ struct clipboard_data_instance;
 
 struct gui_data {
     GtkWidget *window, *area, *sbar;
+    gboolean sbar_visible;
     GtkBox *hbox;
     GtkAdjustment *sbar_adjust;
     GtkWidget *menu, *specialsmenu, *specialsitem1, *specialsitem2,
@@ -2846,6 +2847,15 @@ void scrollbar_moved(GtkAdjustment *adj, gpointer data)
        term_scroll(inst->term, 1, (int)gtk_adjustment_get_value(adj));
 }
 
+static void show_scrollbar(struct gui_data *inst, gboolean visible)
+{
+    inst->sbar_visible = visible;
+    if (visible)
+        gtk_widget_show(inst->sbar);
+    else
+        gtk_widget_hide(inst->sbar);
+}
+
 void sys_cursor(void *frontend, int x, int y)
 {
     /*
@@ -3599,17 +3609,65 @@ char *setup_fonts_ucs(struct gui_data *inst)
 void set_geom_hints(struct gui_data *inst)
 {
     GdkGeometry geom;
+    gint flags;
+
+    /*
+     * Unused fields in geom.
+     */
+    geom.max_width = geom.max_height = -1;
+    geom.min_aspect = geom.max_aspect = 0;
+
+    /*
+     * Set up the geometry fields we care about, with reference to
+     * just the drawing area. We'll correct for the scrollbar in a
+     * moment.
+     */
+    flags = GDK_HINT_MIN_SIZE | GDK_HINT_BASE_SIZE | GDK_HINT_RESIZE_INC;
     geom.min_width = inst->font_width + 2*inst->window_border;
     geom.min_height = inst->font_height + 2*inst->window_border;
-    geom.max_width = geom.max_height = -1;
     geom.base_width = 2*inst->window_border;
     geom.base_height = 2*inst->window_border;
     geom.width_inc = inst->font_width;
     geom.height_inc = inst->font_height;
-    geom.min_aspect = geom.max_aspect = 0;
-    gtk_window_set_geometry_hints(GTK_WINDOW(inst->window), inst->area, &geom,
-                                  GDK_HINT_MIN_SIZE | GDK_HINT_BASE_SIZE |
-                                  GDK_HINT_RESIZE_INC);
+
+    /*
+     * If we've got a scrollbar visible, then we must include its
+     * width as part of the base and min width, and also ensure that
+     * our window's minimum height is at least the height required by
+     * the scrollbar.
+     *
+     * In the latter case, we must also take care to arrange that
+     * (geom.min_height - geom.base_height) is an integer multiple of
+     * geom.height_inc, because if it's not, then some window managers
+     * (we know of xfwm4) get confused, with the effect that they
+     * resize our window to a height based on min_height instead of
+     * base_height, which we then round down and the window ends up
+     * too short.
+     */
+    if (inst->sbar_visible) {
+        GtkRequisition req;
+        int min_sb_height;
+
+#if GTK_CHECK_VERSION(3,0,0)
+        gtk_widget_get_preferred_size(inst->sbar, &req, NULL);
+#else
+        gtk_widget_size_request(inst->sbar, &req);
+#endif
+
+        /* Compute rounded-up scrollbar height. */
+        min_sb_height = req.height;
+        min_sb_height += geom.height_inc - 1;
+        min_sb_height -= ((min_sb_height - geom.base_height % geom.height_inc)
+                          % geom.height_inc);
+
+        geom.min_width += req.width;
+        geom.base_width += req.width;
+        if (geom.min_height < min_sb_height)
+            geom.min_height = min_sb_height;
+    }
+
+    gtk_window_set_geometry_hints(GTK_WINDOW(inst->window),
+                                  NULL, &geom, flags);
 }
 
 void clear_scrollback_menuitem(GtkMenuItem *item, gpointer data)
@@ -3732,16 +3790,16 @@ void change_settings_menuitem(GtkMenuItem *item, gpointer data)
            }
         }
 
+        need_size = FALSE;
+
         /*
          * If the scrollbar needs to be shown, hidden, or moved
          * from one end to the other of the window, do so now.
          */
         if (conf_get_int(oldconf, CONF_scrollbar) !=
            conf_get_int(newconf, CONF_scrollbar)) {
-            if (conf_get_int(newconf, CONF_scrollbar))
-                gtk_widget_show(inst->sbar);
-            else
-                gtk_widget_hide(inst->sbar);
+            show_scrollbar(inst, conf_get_int(newconf, CONF_scrollbar));
+            need_size = TRUE;
         }
         if (conf_get_int(oldconf, CONF_scrollbar_on_left) !=
            conf_get_int(newconf, CONF_scrollbar_on_left)) {
@@ -3762,7 +3820,6 @@ void change_settings_menuitem(GtkMenuItem *item, gpointer data)
          * Redo the whole tangled fonts and Unicode mess if
          * necessary.
          */
-        need_size = FALSE;
         if (strcmp(conf_get_fontspec(oldconf, CONF_font)->name,
                   conf_get_fontspec(newconf, CONF_font)->name) ||
            strcmp(conf_get_fontspec(oldconf, CONF_boldfont)->name,
@@ -4139,23 +4196,6 @@ struct gui_data *new_session_window(Conf *conf, const char *geometry_string)
 
     init_clipboard(inst);
 
-    set_geom_hints(inst);
-
-#if GTK_CHECK_VERSION(3,0,0)
-    gtk_window_set_default_geometry(GTK_WINDOW(inst->window),
-                                    inst->width, inst->height);
-#else
-    {
-        int w = inst->font_width * inst->width + 2*inst->window_border;
-        int h = inst->font_height * inst->height + 2*inst->window_border;
-#if GTK_CHECK_VERSION(2,0,0)
-        gtk_widget_set_size_request(inst->area, w, h);
-#else
-        gtk_drawing_area_size(GTK_DRAWING_AREA(inst->area), w, h);
-#endif
-    }
-#endif
-
     inst->sbar_adjust = GTK_ADJUSTMENT(gtk_adjustment_new(0,0,0,0,0,0));
     inst->sbar = gtk_vscrollbar_new(inst->sbar_adjust);
     inst->hbox = GTK_BOX(gtk_hbox_new(FALSE, 0));
@@ -4173,12 +4213,26 @@ struct gui_data *new_session_window(Conf *conf, const char *geometry_string)
     gtk_container_add(GTK_CONTAINER(inst->window), GTK_WIDGET(inst->hbox));
 
     gtk_widget_show(inst->area);
-    if (conf_get_int(inst->conf, CONF_scrollbar))
-       gtk_widget_show(inst->sbar);
-    else
-       gtk_widget_hide(inst->sbar);
+    show_scrollbar(inst, conf_get_int(inst->conf, CONF_scrollbar));
     gtk_widget_show(GTK_WIDGET(inst->hbox));
 
+    set_geom_hints(inst);
+
+#if GTK_CHECK_VERSION(3,0,0)
+    gtk_window_set_default_geometry(GTK_WINDOW(inst->window),
+                                    inst->width, inst->height);
+#else
+    {
+        int w = inst->font_width * inst->width + 2*inst->window_border;
+        int h = inst->font_height * inst->height + 2*inst->window_border;
+#if GTK_CHECK_VERSION(2,0,0)
+        gtk_widget_set_size_request(inst->area, w, h);
+#else
+        gtk_drawing_area_size(GTK_DRAWING_AREA(inst->area), w, h);
+#endif
+    }
+#endif
+
 #if GTK_CHECK_VERSION(2,0,0)
     if (inst->geometry) {
         gtk_window_parse_geometry(GTK_WINDOW(inst->window), inst->geometry);