From a4a7a611f2219a4cdcb359ac828ea122906f158e Mon Sep 17 00:00:00 2001 From: "Owen W. Taylor" Date: Sat, 9 Oct 2010 22:38:54 -0400 Subject: [PATCH] GtkWindow: Allow setting size from geometry If you set a geometry widget via gtk_window_set_geometry_hints() it becomes very hard to compute appropriate toplevel sizes in pixels to make the window a particular size. Synthesizing strings and passing them to gtk_window_parse_geometry() is possible, but to avoid avoid such ugliness, add functions: gtk_window_set_default_geometry() gtk_window_resize_to_geometry() That act like gtk_window_set_default_size() and gtk_window_resize() but are in terms of the resize increments of the geometry widget. https://bugzilla.gnome.org/show_bug.cgi?id=631796 --- gtk/gtkwindow.c | 171 +++++++++++++++++++++++++++++++------------ gtk/gtkwindow.h | 8 ++ tests/testgeometry.c | 29 ++++++++ 3 files changed, 161 insertions(+), 47 deletions(-) diff --git a/gtk/gtkwindow.c b/gtk/gtkwindow.c index 0c6dbe1f25..7ef2d5f74b 100644 --- a/gtk/gtkwindow.c +++ b/gtk/gtkwindow.c @@ -281,11 +281,15 @@ struct _GtkWindowGeometryInfo */ guint position_constraints_changed : 1; - /* if true, default_width, height come from gtk_window_parse_geometry, - * and thus should be multiplied by the increments and affect the - * geometry widget only + /* if true, default_width, height should be multiplied by the + * increments and affect the geometry widget only */ guint default_is_geometry : 1; + + /* if true, resize_width, height should be multiplied by the + * increments and affect the geometry widget only + */ + guint resize_is_geometry : 1; GtkWindowLastGeometryInfo last; }; @@ -3928,6 +3932,30 @@ gtk_window_set_default_size (GtkWindow *window, gtk_window_set_default_size_internal (window, TRUE, width, TRUE, height, FALSE); } +/** + * gtk_window_set_default_geometry: + * @window: a #GtkWindow + * @width: width in resize increments, or -1 to unset the default width + * @height: height in resize increments, or -1 to unset the default height + * + * Like gtk_window_set_default_size(), but @width and @height are interpreted + * in terms of the base size and increment set with + * gtk_window_set_geometry_hints. + * + * Since: 3.0 + */ +void +gtk_window_set_default_geometry (GtkWindow *window, + gint width, + gint height) +{ + g_return_if_fail (GTK_IS_WINDOW (window)); + g_return_if_fail (width >= -1); + g_return_if_fail (height >= -1); + + gtk_window_set_default_size_internal (window, TRUE, width, TRUE, height, TRUE); +} + /** * gtk_window_get_default_size: * @window: a #GtkWindow @@ -3992,6 +4020,39 @@ gtk_window_resize (GtkWindow *window, info->resize_width = width; info->resize_height = height; + info->resize_is_geometry = FALSE; + + gtk_widget_queue_resize_no_redraw (GTK_WIDGET (window)); +} + +/** + * gtk_window_resize_to_geometry: + * @window: a #GtkWindow + * @width: width in resize increments to resize the window to + * @height: height in resize increments to resize the window to + * + * Like gtk_window_resize(), but @width and @height are interpreted + * in terms of the base size and increment set with + * gtk_window_set_geometry_hints. + * + * Since: 3.0 + */ +void +gtk_window_resize_to_geometry (GtkWindow *window, + gint width, + gint height) +{ + GtkWindowGeometryInfo *info; + + g_return_if_fail (GTK_IS_WINDOW (window)); + g_return_if_fail (width > 0); + g_return_if_fail (height > 0); + + info = gtk_window_get_geometry_info (window, TRUE); + + info->resize_width = width; + info->resize_height = height; + info->resize_is_geometry = TRUE; gtk_widget_queue_resize_no_redraw (GTK_WIDGET (window)); } @@ -6061,11 +6122,48 @@ _gtk_window_unset_focus_and_default (GtkWindow *window, * Functions related to resizing * *********************************/ +static void +geometry_size_to_pixels (GdkGeometry *geometry, + guint flags, + guint *width, + guint *height) +{ + gint base_width = 0; + gint base_height = 0; + gint min_width = 0; + gint min_height = 0; + gint width_inc = 1; + gint height_inc = 1; + + if (flags & GDK_HINT_BASE_SIZE) + { + base_width = geometry->base_width; + base_height = geometry->base_height; + } + if (flags & GDK_HINT_MIN_SIZE) + { + min_width = geometry->min_width; + min_height = geometry->min_height; + } + if (flags & GDK_HINT_RESIZE_INC) + { + width_inc = geometry->width_inc; + height_inc = geometry->height_inc; + } + + if (width) + *width = MAX (*width * width_inc + base_width, min_width); + if (height) + *height = MAX (*height * height_inc + base_height, min_height); +} + /* This function doesn't constrain to geometry hints */ static void -gtk_window_compute_configure_request_size (GtkWindow *window, - guint *width, - guint *height) +gtk_window_compute_configure_request_size (GtkWindow *window, + GdkGeometry *geometry, + guint flags, + guint *width, + guint *height) { GtkWindowPrivate *priv = window->priv; GtkRequisition requisition; @@ -6098,44 +6196,16 @@ gtk_window_compute_configure_request_size (GtkWindow *window, /* Override requisition with default size */ if (info) - { - gint base_width = 0; - gint base_height = 0; - gint min_width = 0; - gint min_height = 0; - gint width_inc = 1; - gint height_inc = 1; - - if (info->default_is_geometry && - (info->default_width > 0 || info->default_height > 0)) - { - GdkGeometry geometry; - guint flags; - - gtk_window_compute_hints (window, &geometry, &flags); - - if (flags & GDK_HINT_BASE_SIZE) - { - base_width = geometry.base_width; - base_height = geometry.base_height; - } - if (flags & GDK_HINT_MIN_SIZE) - { - min_width = geometry.min_width; - min_height = geometry.min_height; - } - if (flags & GDK_HINT_RESIZE_INC) - { - width_inc = geometry.width_inc; - height_inc = geometry.height_inc; - } - } - + { if (info->default_width > 0) - *width = MAX (info->default_width * width_inc + base_width, min_width); - + *width = info->default_width; if (info->default_height > 0) - *height = MAX (info->default_height * height_inc + base_height, min_height); + *height = info->default_height; + + if (info->default_is_geometry) + geometry_size_to_pixels (geometry, flags, + info->default_width > 0 ? width : NULL, + info->default_height > 0 ? height : NULL); } } else @@ -6153,10 +6223,14 @@ gtk_window_compute_configure_request_size (GtkWindow *window, if (info) { if (info->resize_width > 0) - *width = info->resize_width; - + *width = info->resize_width; if (info->resize_height > 0) - *height = info->resize_height; + *height = info->resize_height; + + if (info->resize_is_geometry) + geometry_size_to_pixels (geometry, flags, + info->resize_width > 0 ? width : NULL, + info->resize_height > 0 ? height : NULL); } /* Don't ever request zero width or height, its not supported by @@ -6308,9 +6382,11 @@ gtk_window_compute_configure_request (GtkWindow *window, screen = gtk_window_check_screen (window); - gtk_window_compute_configure_request_size (window, (guint *)&w, (guint *)&h); - gtk_window_compute_hints (window, &new_geometry, &new_flags); + gtk_window_compute_configure_request_size (window, + &new_geometry, new_flags, + (guint *)&w, (guint *)&h); + gtk_window_constrain_size (window, &new_geometry, new_flags, w, h, @@ -7084,6 +7160,7 @@ gtk_window_compute_hints (GtkWindow *window, { /* For simplicity, we always set the base hint, even when we * don't expect it to have any visible effect. + * (Note: geometry_size_to_pixels() depends on this.) */ *new_flags |= GDK_HINT_BASE_SIZE; diff --git a/gtk/gtkwindow.h b/gtk/gtkwindow.h index bb43bee24f..96008b8e1f 100644 --- a/gtk/gtkwindow.h +++ b/gtk/gtkwindow.h @@ -315,6 +315,14 @@ void gtk_window_get_position (GtkWindow *window, gint *root_y); gboolean gtk_window_parse_geometry (GtkWindow *window, const gchar *geometry); + +void gtk_window_set_default_geometry (GtkWindow *window, + gint width, + gint height); +void gtk_window_resize_to_geometry (GtkWindow *window, + gint width, + gint height); + GtkWindowGroup *gtk_window_get_group (GtkWindow *window); gboolean gtk_window_has_group (GtkWindow *window); diff --git a/tests/testgeometry.c b/tests/testgeometry.c index 9d3f714075..f7eb0fa9fe 100644 --- a/tests/testgeometry.c +++ b/tests/testgeometry.c @@ -73,6 +73,19 @@ on_drawing_area_draw (GtkWidget *drawing_area, return FALSE; } +static void +on_resize_clicked (GtkWidget *button, + gpointer data) +{ + GtkWidget *window = gtk_widget_get_toplevel (button); + GdkWindowHints mask = GPOINTER_TO_UINT(data); + + if ((mask & GDK_HINT_RESIZE_INC) != 0) + gtk_window_resize_to_geometry (GTK_WINDOW (window), 8, 8); + else + gtk_window_resize_to_geometry (GTK_WINDOW (window), 8 * GRID_SIZE, 8 * GRID_SIZE); +} + static void create_window (GdkWindowHints mask) { @@ -80,6 +93,7 @@ create_window (GdkWindowHints mask) GtkWidget *drawing_area; GtkWidget *table; GtkWidget *label; + GtkWidget *button; GdkGeometry geometry; GString *label_text = g_string_new (NULL); int border = 0; @@ -130,6 +144,15 @@ create_window (GdkWindowHints mask) GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0); + button = gtk_button_new_with_label ("Resize"); + g_signal_connect (button, "clicked", + G_CALLBACK (on_resize_clicked), + GUINT_TO_POINTER (mask)); + gtk_table_attach (GTK_TABLE (table), button, + 0, 2, 2, 3, + GTK_EXPAND, 0, + 0, 8); + gtk_container_add (GTK_CONTAINER (window), table); if ((mask & GDK_HINT_BASE_SIZE) != 0) @@ -169,6 +192,12 @@ create_window (GdkWindowHints mask) { if (geometry_string) gtk_window_parse_geometry (GTK_WINDOW (window), geometry_string); + else + gtk_window_set_default_geometry (GTK_WINDOW (window), 10, 10); + } + else + { + gtk_window_set_default_geometry (GTK_WINDOW (window), 10 * GRID_SIZE, 10 * GRID_SIZE); } gtk_widget_show (window);