From cebe469898f82ce7d688e94ab1e4727283a2d014 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Thu, 30 Jul 2020 17:01:54 +0200 Subject: [PATCH 1/3] gtk/window: Don't remember size from GdkSurface If we're maximized, and try to remember the non-maximized size, we'd still get the maximized size. --- gtk/gtkwindow.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/gtk/gtkwindow.c b/gtk/gtkwindow.c index 984e766be0..58041745d3 100644 --- a/gtk/gtkwindow.c +++ b/gtk/gtkwindow.c @@ -4078,19 +4078,11 @@ gtk_window_get_remembered_size (GtkWindow *window, int *width, int *height) { - GtkWindowPrivate *priv = gtk_window_get_instance_private (window); GtkWindowGeometryInfo *info; *width = 0; *height = 0; - if (priv->surface) - { - *width = gdk_surface_get_width (priv->surface); - *height = gdk_surface_get_height (priv->surface); - return; - } - info = gtk_window_get_geometry_info (window, FALSE); if (info) { From 4ee82e8175d1d1ed21d3ef8133f0d76267bde75c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Tue, 4 Aug 2020 08:21:38 +0200 Subject: [PATCH 2/3] gdk/toplevel: Fix typo in documentation --- gdk/gdktoplevel.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gdk/gdktoplevel.c b/gdk/gdktoplevel.c index a69f13fa62..d3b1d7fad7 100644 --- a/gdk/gdktoplevel.c +++ b/gdk/gdktoplevel.c @@ -186,7 +186,7 @@ gdk_toplevel_install_properties (GObjectClass *object_class, * @layout: the #GdkToplevelLayout object used to layout * * Present @toplevel after having processed the #GdkToplevelLayout rules. - * If the toplevel was previously now showing, it will be showed, + * If the toplevel was previously not showing, it will be showed, * otherwise it will change layout according to @layout. * * Presenting may fail. From 2ff74eb667c2cbe293c7309d5661fa438e8431c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Thu, 30 Jul 2020 23:06:59 +0200 Subject: [PATCH 3/3] gdk/toplevel: Negotiate surface size via a compute-size signal GTK will not up front know how to correctly calculate a size, since it will not be able to reliably predict the constraints that may exist where it will be mapped. Thus, to handle this, calculate the size of the toplevel by having GDK emitting a signal called 'compute-size' that will contain information needed for computing a toplevel window size. This signal may be emitted at any time, e.g. during gdk_toplevel_present(), or spontaneously if constraints change. This also drops the max size from the toplevel layout, while moving the min size from the toplevel layout struct to the struct passed via the signal, This needs changes to a test case where we make sure we process GDK_CONFIGURE etc, which means we also needs to show the window and process all pending events in the test-focus-chain test case. --- docs/reference/gdk/gdk4-sections.txt | 14 +- gdk/broadway/gdksurface-broadway.c | 34 +++- gdk/gdk.h | 1 + gdk/gdksurface.c | 8 +- gdk/gdksurface.h | 4 +- gdk/gdktoplevel.c | 62 ++++++- gdk/gdktoplevel.h | 2 - gdk/gdktoplevellayout.c | 43 +---- gdk/gdktoplevellayout.h | 8 +- gdk/gdktoplevelprivate.h | 8 +- gdk/gdktoplevelsize.c | 119 +++++++++++++ gdk/gdktoplevelsize.h | 62 +++++++ gdk/gdktoplevelsizeprivate.h | 39 +++++ gdk/macos/gdkmacostoplevelsurface.c | 33 +++- gdk/meson.build | 3 + gdk/wayland/gdksurface-wayland.c | 145 +++++++++++++--- gdk/win32/gdksurface-win32.c | 35 +++- gdk/x11/gdksurface-x11.c | 45 ++++- gtk/gtkwindow.c | 244 ++++++++++++++++++--------- gtk/inspector/general.c | 4 +- tests/rendernode.c | 2 +- tests/showrendernode.c | 4 +- tests/testfullscreen.c | 14 +- testsuite/gsk/compare-render.c | 2 +- testsuite/gtk/defaultvalue.c | 2 +- testsuite/gtk/notify.c | 2 +- testsuite/gtk/shortcuts.c | 2 +- testsuite/gtk/test-focus-chain.c | 25 +++ 28 files changed, 750 insertions(+), 216 deletions(-) create mode 100644 gdk/gdktoplevelsize.c create mode 100644 gdk/gdktoplevelsize.h create mode 100644 gdk/gdktoplevelsizeprivate.h diff --git a/docs/reference/gdk/gdk4-sections.txt b/docs/reference/gdk/gdk4-sections.txt index a7c942a4e5..5cff88eb65 100644 --- a/docs/reference/gdk/gdk4-sections.txt +++ b/docs/reference/gdk/gdk4-sections.txt @@ -633,8 +633,6 @@ gdk_toplevel_layout_get_maximized gdk_toplevel_layout_set_fullscreen gdk_toplevel_layout_get_fullscreen gdk_toplevel_layout_get_fullscreen_monitor -gdk_toplevel_layout_get_min_width -gdk_toplevel_layout_get_min_height gdk_toplevel_layout_set_resizable gdk_toplevel_layout_get_resizable @@ -642,6 +640,18 @@ GDK_TYPE_TOPLEVEL_LAYOUT gdk_toplevel_layout_get_type +
+gdktoplevelsize +GdkToplevelSize +GdkToplevelSize +gdk_toplevel_size_get_bounds +gdk_toplevel_size_set_size +gdk_toplevel_size_set_min_size + +GDK_TYPE_TOPLEVEL_SIZE +gdk_toplevel_size_get_type +
+
gdktoplevel GdkToplevel diff --git a/gdk/broadway/gdksurface-broadway.c b/gdk/broadway/gdksurface-broadway.c index fb03675ece..7f5f9a79e4 100644 --- a/gdk/broadway/gdksurface-broadway.c +++ b/gdk/broadway/gdksurface-broadway.c @@ -41,6 +41,7 @@ #include "gdktextureprivate.h" #include "gdktoplevelprivate.h" +#include #include #include #include @@ -1524,20 +1525,45 @@ show_surface (GdkSurface *surface) static gboolean gdk_broadway_toplevel_present (GdkToplevel *toplevel, - int width, - int height, GdkToplevelLayout *layout) { GdkSurface *surface = GDK_SURFACE (toplevel); + GdkDisplay *display = gdk_surface_get_display (surface); + GdkMonitor *monitor; + GdkToplevelSize size; + int bounds_width, bounds_height; + int width, height; GdkGeometry geometry; GdkSurfaceHints mask; gdk_broadway_surface_unminimize (surface); + monitor = gdk_display_get_monitor_at_surface (display, surface); + if (monitor) + { + GdkRectangle monitor_geometry; + + gdk_monitor_get_geometry (monitor, &monitor_geometry); + bounds_width = monitor_geometry.width; + bounds_height = monitor_geometry.height; + } + else + { + bounds_width = G_MAXINT; + bounds_height = G_MAXINT; + } + + gdk_toplevel_size_init (&size, bounds_width, bounds_height); + gdk_toplevel_notify_compute_size (toplevel, &size); + g_warn_if_fail (size.width > 0); + g_warn_if_fail (size.height > 0); + width = size.width; + height = size.height; + if (gdk_toplevel_layout_get_resizable (layout)) { - geometry.min_width = gdk_toplevel_layout_get_min_width (layout); - geometry.min_height = gdk_toplevel_layout_get_min_height (layout); + geometry.min_width = size.min_width; + geometry.min_height = size.min_height; mask = GDK_HINT_MIN_SIZE; } else diff --git a/gdk/gdk.h b/gdk/gdk.h index d15dd7d922..8b6489cbf0 100644 --- a/gdk/gdk.h +++ b/gdk/gdk.h @@ -70,6 +70,7 @@ #include #include #include +#include #include #include #include diff --git a/gdk/gdksurface.c b/gdk/gdksurface.c index 6d8b84ee34..75c35d6d50 100644 --- a/gdk/gdksurface.c +++ b/gdk/gdksurface.c @@ -795,22 +795,18 @@ gdk_surface_new (GdkDisplay *display, /** * gdk_surface_new_toplevel: (constructor) * @display: the display to create the surface on - * @width: width of new surface - * @height: height of new surface * * Creates a new toplevel surface. * * Returns: (transfer full): the new #GdkSurface **/ GdkSurface * -gdk_surface_new_toplevel (GdkDisplay *display, - int width, - int height) +gdk_surface_new_toplevel (GdkDisplay *display) { g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL); return gdk_surface_new (display, GDK_SURFACE_TOPLEVEL, - NULL, 0, 0, width, height); + NULL, 0, 0, 0, 0); } /** diff --git a/gdk/gdksurface.h b/gdk/gdksurface.h index 077c012a3f..9b1613147f 100644 --- a/gdk/gdksurface.h +++ b/gdk/gdksurface.h @@ -139,9 +139,7 @@ typedef struct _GdkSurfaceClass GdkSurfaceClass; GDK_AVAILABLE_IN_ALL GType gdk_surface_get_type (void) G_GNUC_CONST; GDK_AVAILABLE_IN_ALL -GdkSurface * gdk_surface_new_toplevel (GdkDisplay *display, - int width, - int height); +GdkSurface * gdk_surface_new_toplevel (GdkDisplay *display); GDK_AVAILABLE_IN_ALL GdkSurface * gdk_surface_new_popup (GdkSurface *parent, gboolean autohide); diff --git a/gdk/gdktoplevel.c b/gdk/gdktoplevel.c index d3b1d7fad7..3b8a22a611 100644 --- a/gdk/gdktoplevel.c +++ b/gdk/gdktoplevel.c @@ -23,6 +23,7 @@ #include "gdk-private.h" #include "gdktoplevelprivate.h" +#include #include /** @@ -35,10 +36,17 @@ G_DEFINE_INTERFACE (GdkToplevel, gdk_toplevel, GDK_TYPE_SURFACE) +enum +{ + COMPUTE_SIZE, + + N_SIGNALS +}; + +static guint signals[N_SIGNALS] = { 0 }; + static gboolean gdk_toplevel_default_present (GdkToplevel *toplevel, - int width, - int height, GdkToplevelLayout *layout) { return FALSE; @@ -86,6 +94,13 @@ gdk_toplevel_default_restore_system_shortcuts (GdkToplevel *toplevel) { } +void +gdk_toplevel_notify_compute_size (GdkToplevel *toplevel, + GdkToplevelSize *size) +{ + g_signal_emit (toplevel, signals[COMPUTE_SIZE], 0, size); +} + static void gdk_toplevel_default_init (GdkToplevelInterface *iface) { @@ -158,6 +173,37 @@ gdk_toplevel_default_init (GdkToplevelInterface *iface) "Whether keyboard shortcuts are inhibited", FALSE, G_PARAM_READABLE | G_PARAM_EXPLICIT_NOTIFY)); + + /** + * GdkToplevel::compute-size: + * @toplevel: a #GdkToplevel + * @size: (type Gdk.ToplevelSize) (out caller-allocates): a #GdkToplevelSize + * + * Compute the desired size of the toplevel, given the information passed via + * the #GdkToplevelSize object. + * + * It will normally be emitted during or after gdk_toplevel_present(), + * depending on the configuration received by the windowing system. It may + * also be emitted at any other point in time, in response to the windowing + * system spontaneously changing the configuration. + * + * It is the responsibility of the GdkToplevel user to handle this signal; + * failing to do so will result in an arbitrary fixed size being used as a + * result. The signal may be emitted with the pointer to the @size being + * %NULL, in which case only the minimum and maximum size needs to be + * computed. This could happen for example if the toplevel configuration is in + * a state where the size is decided by the windowing system, such as + * maximized or fullscreen. + */ + signals[COMPUTE_SIZE] = + g_signal_new ("compute-size", + GDK_TYPE_TOPLEVEL, + G_SIGNAL_RUN_LAST, + 0, + NULL, NULL, + NULL, + G_TYPE_NONE, 1, + GDK_TYPE_TOPLEVEL_SIZE | G_SIGNAL_TYPE_STATIC_SCOPE); } guint @@ -181,30 +227,28 @@ gdk_toplevel_install_properties (GObjectClass *object_class, /** * gdk_toplevel_present: * @toplevel: the #GdkToplevel to show - * @width: the unconstrained toplevel width to layout - * @height: the unconstrained toplevel height to layout * @layout: the #GdkToplevelLayout object used to layout * * Present @toplevel after having processed the #GdkToplevelLayout rules. * If the toplevel was previously not showing, it will be showed, * otherwise it will change layout according to @layout. * + * GDK may emit the 'compute-size' signal to let the user of this toplevel + * compute the preferred size of the toplevel surface. See + * #GdkToplevel::compute-size for details. + * * Presenting may fail. * * Returns: %FALSE if @toplevel failed to be presented, otherwise %TRUE. */ gboolean gdk_toplevel_present (GdkToplevel *toplevel, - int width, - int height, GdkToplevelLayout *layout) { g_return_val_if_fail (GDK_IS_TOPLEVEL (toplevel), FALSE); - g_return_val_if_fail (width > 0, FALSE); - g_return_val_if_fail (height > 0, FALSE); g_return_val_if_fail (layout != NULL, FALSE); - return GDK_TOPLEVEL_GET_IFACE (toplevel)->present (toplevel, width, height, layout); + return GDK_TOPLEVEL_GET_IFACE (toplevel)->present (toplevel, layout); } /** diff --git a/gdk/gdktoplevel.h b/gdk/gdktoplevel.h index 20b3fc5d4b..cd1bb74241 100644 --- a/gdk/gdktoplevel.h +++ b/gdk/gdktoplevel.h @@ -37,8 +37,6 @@ G_DECLARE_INTERFACE (GdkToplevel, gdk_toplevel, GDK, TOPLEVEL, GObject) GDK_AVAILABLE_IN_ALL gboolean gdk_toplevel_present (GdkToplevel *toplevel, - int width, - int height, GdkToplevelLayout *layout); GDK_AVAILABLE_IN_ALL diff --git a/gdk/gdktoplevellayout.c b/gdk/gdktoplevellayout.c index 8f4a6b56aa..577b03be41 100644 --- a/gdk/gdktoplevellayout.c +++ b/gdk/gdktoplevellayout.c @@ -39,8 +39,6 @@ struct _GdkToplevelLayout /* < private >*/ grefcount ref_count; - int min_width; - int min_height; guint resizable : 1; guint maximized : 1; guint fullscreen : 1; @@ -53,8 +51,6 @@ G_DEFINE_BOXED_TYPE (GdkToplevelLayout, gdk_toplevel_layout, /** * gdk_toplevel_layout_new: (constructor) - * @min_width: the minimum width for the layout - * @min_height: the minimum height for the layout * * Create a toplevel layout description. * @@ -67,15 +63,12 @@ G_DEFINE_BOXED_TYPE (GdkToplevelLayout, gdk_toplevel_layout, * Returns: (transfer full): newly created instance of #GdkToplevelLayout */ GdkToplevelLayout * -gdk_toplevel_layout_new (int min_width, - int min_height) +gdk_toplevel_layout_new (void) { GdkToplevelLayout *layout; layout = g_new0 (GdkToplevelLayout, 1); g_ref_count_init (&layout->ref_count); - layout->min_width = min_width; - layout->min_height = min_height; layout->resizable = TRUE; layout->maximized = FALSE; layout->fullscreen = FALSE; @@ -131,8 +124,6 @@ gdk_toplevel_layout_copy (GdkToplevelLayout *layout) new_layout = g_new0 (GdkToplevelLayout, 1); g_ref_count_init (&new_layout->ref_count); - new_layout->min_width = layout->min_width; - new_layout->min_height = layout->min_height; new_layout->resizable = layout->resizable; new_layout->maximized = layout->maximized; new_layout->fullscreen = layout->fullscreen; @@ -159,42 +150,12 @@ gdk_toplevel_layout_equal (GdkToplevelLayout *layout, g_return_val_if_fail (layout, FALSE); g_return_val_if_fail (other, FALSE); - return layout->min_width == other->min_width && - layout->min_height == other->min_height && - layout->resizable == other->resizable && + return layout->resizable == other->resizable && layout->maximized == other->maximized && layout->fullscreen == other->fullscreen && layout->fullscreen_monitor == other->fullscreen_monitor; } -/** - * gdk_toplevel_layout_get_min_width: - * @layout: a #GdkToplevelLayout - * - * Returns the minimum width of the given layout. - * - * Returns: the minimum width of @layout - */ -int -gdk_toplevel_layout_get_min_width (GdkToplevelLayout *layout) -{ - return layout->min_width; -} - -/** - * gdk_toplevel_layout_get_min_height: - * @layout: a #GdkToplevelLayout - * - * Returns the minimum height of the given layout. - * - * Returns: the minimum height of @layout - */ -int -gdk_toplevel_layout_get_min_height (GdkToplevelLayout *layout) -{ - return layout->min_height; -} - /** * gdk_toplevel_layout_set_resizable: * @layout: a #GdkToplevelLayout diff --git a/gdk/gdktoplevellayout.h b/gdk/gdktoplevellayout.h index 5be9aee83c..23b2660414 100644 --- a/gdk/gdktoplevellayout.h +++ b/gdk/gdktoplevellayout.h @@ -42,8 +42,7 @@ GDK_AVAILABLE_IN_ALL GType gdk_toplevel_layout_get_type (void); GDK_AVAILABLE_IN_ALL -GdkToplevelLayout * gdk_toplevel_layout_new (int min_width, - int min_height); +GdkToplevelLayout * gdk_toplevel_layout_new (void); GDK_AVAILABLE_IN_ALL GdkToplevelLayout * gdk_toplevel_layout_ref (GdkToplevelLayout *layout); @@ -66,11 +65,6 @@ void gdk_toplevel_layout_set_fullscreen (GdkToplevelLayout *l gboolean fullscreen, GdkMonitor *monitor); -GDK_AVAILABLE_IN_ALL -int gdk_toplevel_layout_get_min_width (GdkToplevelLayout *layout); -GDK_AVAILABLE_IN_ALL -int gdk_toplevel_layout_get_min_height (GdkToplevelLayout *layout); - GDK_AVAILABLE_IN_ALL gboolean gdk_toplevel_layout_get_maximized (GdkToplevelLayout *layout); diff --git a/gdk/gdktoplevelprivate.h b/gdk/gdktoplevelprivate.h index 6cdccca8b7..989ac29c46 100644 --- a/gdk/gdktoplevelprivate.h +++ b/gdk/gdktoplevelprivate.h @@ -2,6 +2,9 @@ #define __GDK_TOPLEVEL_PRIVATE_H__ #include "gdktoplevel.h" +#include "gdktoplevelsizeprivate.h" + +#include G_BEGIN_DECLS @@ -11,8 +14,6 @@ struct _GdkToplevelInterface GTypeInterface g_iface; gboolean (* present) (GdkToplevel *toplevel, - int width, - int height, GdkToplevelLayout *layout); gboolean (* minimize) (GdkToplevel *toplevel); gboolean (* lower) (GdkToplevel *toplevel); @@ -57,6 +58,9 @@ typedef enum guint gdk_toplevel_install_properties (GObjectClass *object_class, guint first_prop); +void gdk_toplevel_notify_compute_size (GdkToplevel *toplevel, + GdkToplevelSize *size); + G_END_DECLS #endif /* __GDK_TOPLEVEL_PRIVATE_H__ */ diff --git a/gdk/gdktoplevelsize.c b/gdk/gdktoplevelsize.c new file mode 100644 index 0000000000..18933523ff --- /dev/null +++ b/gdk/gdktoplevelsize.c @@ -0,0 +1,119 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 2020 Red Hat + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + * + */ + +#include "config.h" + +#include "gdktoplevelsizeprivate.h" + +/** + * SECTION:gdktoplevelsize + * @Title: GdkToplevelSize + * @Short_description: Information for computing toplevel size + * + * The GdkToplevelSIze struct contains information that may be useful + * for users of GdkToplevel to compute a surface size. It also carries + * information back with the computational result. + */ + +G_DEFINE_POINTER_TYPE (GdkToplevelSize, gdk_toplevel_size) + +#define UNCONFIGURED_WIDTH 400 +#define UNCONFIGURED_HEIGHT 300 + +void +gdk_toplevel_size_init (GdkToplevelSize *size, + int bounds_width, + int bounds_height) +{ + *size = (GdkToplevelSize) { 0 }; + + size->bounds_width = bounds_width; + size->bounds_height = bounds_height; + + size->width = UNCONFIGURED_WIDTH; + size->height = UNCONFIGURED_HEIGHT; +} + +/** + * gdk_toplevel_size_get_bounds: + * @size: a #GdkToplevelSize + * @bounds_width: (out): return location for width + * @bounds_height: (out): return location for height + * + * Retrieves the bounds the toplevel is placed within. + * + * The bounds represent the largest size a toplevel may have while still being + * able to fit within some type of boundery. Depending on the backend, this may + * be equivalent to the dimensions of the work area or the monitor on which the + * window is being presented on, or something else that limits the way a + * toplevel can be presented. + */ +void +gdk_toplevel_size_get_bounds (GdkToplevelSize *size, + int *bounds_width, + int *bounds_height) +{ + g_return_if_fail (bounds_width); + g_return_if_fail (bounds_height); + + *bounds_width = size->bounds_width; + *bounds_height = size->bounds_height; +} + +/** + * gdk_toplevel_size_set_size: + * @size: a #GdkToplevelSize + * @width: the width + * @height: the height + * + * Sets the size the toplevel prefers to be resized to. The size should be + * within the bounds (see gdk_toplevel_size_get_bounds()). The set size should + * be considered as a hint, and should not be assumed to be respected by the + * windowing system, or backend. + */ +void +gdk_toplevel_size_set_size (GdkToplevelSize *size, + int width, + int height) +{ + size->width = width; + size->height = height; +} + +/** + * gdk_toplevel_size_set_min_size: + * @size: a #GdkToplevelSize + * @min_width: the minimum width + * @min_height: the minimum height + * + * The minimum size corresponds to the limitations the toplevel can be shrunk + * to, without resulting in incorrect painting. A user of a #GdkToplevel should + * calculate these given both the existing size, and the bounds retrieved from + * the #GdkToplevelSize object. + * + * The minimum size should be within the bounds (see + * gdk_toplevel_size_get_bounds()). + */ +void +gdk_toplevel_size_set_min_size (GdkToplevelSize *size, + int min_width, + int min_height) +{ + size->min_width = min_width; + size->min_height = min_height; +} diff --git a/gdk/gdktoplevelsize.h b/gdk/gdktoplevelsize.h new file mode 100644 index 0000000000..731ea6379a --- /dev/null +++ b/gdk/gdktoplevelsize.h @@ -0,0 +1,62 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 2020 Red Hat + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + * + */ + +#ifndef __GDK_TOPLEVEL_SIZE_H__ +#define __GDK_TOPLEVEL_SIZE_H__ + +#if !defined(__GDK_H_INSIDE__) && !defined(GTK_COMPILATION) +#error "Only can be included directly." +#endif + +#include +#include + +G_BEGIN_DECLS + +/** + * GdkTopLevelSize: + * + * Struct containing information for computing the size of a #GdkToplevel. + */ +typedef struct _GdkToplevelSize GdkToplevelSize; + +#define GDK_TYPE_TOPLEVEL_SIZE (gdk_toplevel_size_get_type ()) + +GDK_AVAILABLE_IN_ALL +GType gdk_toplevel_size_get_type (void); + +void gdk_toplevel_size_get_bounds (GdkToplevelSize *size, + int *bounds_width, + int *bounds_height); + +GDK_AVAILABLE_IN_ALL +void gdk_toplevel_size_set_size (GdkToplevelSize *size, + int width, + int height); +GDK_AVAILABLE_IN_ALL +void gdk_toplevel_size_set_min_size (GdkToplevelSize *size, + int min_width, + int min_height); +GDK_AVAILABLE_IN_ALL +void gdk_toplevel_size_set_max_size (GdkToplevelSize *size, + int max_width, + int max_height); + +G_END_DECLS + +#endif /* __GDK_TOPLEVEL_SIZE_H__ */ diff --git a/gdk/gdktoplevelsizeprivate.h b/gdk/gdktoplevelsizeprivate.h new file mode 100644 index 0000000000..eaddefba0b --- /dev/null +++ b/gdk/gdktoplevelsizeprivate.h @@ -0,0 +1,39 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 2020 Red Hat + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + * + */ + +#ifndef __GDK_TOPLEVEL_SIZE_PRIVATE_H__ +#define __GDK_TOPLEVEL_SIZE_PRIVATE_H__ + +#include "gdktoplevelsize.h" + +struct _GdkToplevelSize +{ + int bounds_width; + int bounds_height; + + int width; + int height; + int min_width; + int min_height; +}; + +void gdk_toplevel_size_init (GdkToplevelSize *size, + int bounds_width, + int bounds_height); + +#endif /* __GDK_TOPLEVEL_SIZE_PRIVATE_H__ */ diff --git a/gdk/macos/gdkmacostoplevelsurface.c b/gdk/macos/gdkmacostoplevelsurface.c index a399150fe0..0e5a2a0ae7 100644 --- a/gdk/macos/gdkmacostoplevelsurface.c +++ b/gdk/macos/gdkmacostoplevelsurface.c @@ -93,12 +93,15 @@ _gdk_macos_toplevel_surface_unmaximize (GdkMacosToplevelSurface *self) static gboolean _gdk_macos_toplevel_surface_present (GdkToplevel *toplevel, - int width, - int height, GdkToplevelLayout *layout) { GdkMacosToplevelSurface *self = (GdkMacosToplevelSurface *)toplevel; NSWindow *nswindow = _gdk_macos_surface_get_native (GDK_MACOS_SURFACE (self)); + GdkDisplay *display = gdk_surface_get_display (surface); + GdkMonitor *monitor; + GdkToplevelSize size; + int bounds_width, bounds_height; + int width, height; GdkGeometry geometry; GdkSurfaceHints mask; NSWindowStyleMask style_mask; @@ -108,10 +111,32 @@ _gdk_macos_toplevel_surface_present (GdkToplevel *toplevel, style_mask = [nswindow styleMask]; + monitor = gdk_display_get_monitor_at_surface (display, surface); + if (monitor) + { + GdkRectangle workarea; + + gdk_macos_monitor_get_workarea (monitor, &workarea); + bounds_width = workarea.width; + bounds_height = workarea.height; + } + else + { + bounds_width = G_MAXINT; + bounds_height = G_MAXINT; + } + + gdk_toplevel_size_init (&size, bounds_width, bounds_height); + gdk_toplevel_notify_compute_size (toplevel, &size); + g_warn_if_fail (size.width > 0); + g_warn_if_fail (size.height > 0); + width = size.width; + height = size.height; + if (gdk_toplevel_layout_get_resizable (layout)) { - geometry.min_width = gdk_toplevel_layout_get_min_width (layout); - geometry.min_height = gdk_toplevel_layout_get_min_height (layout); + geometry.min_width = size.min_width; + geometry.min_height = size.min_height; mask = GDK_HINT_MIN_SIZE; /* Only set 'Resizable' mask to get native resize zones if the window is diff --git a/gdk/meson.build b/gdk/meson.build index eebc9b2a97..76d60dd2e6 100644 --- a/gdk/meson.build +++ b/gdk/meson.build @@ -47,6 +47,7 @@ gdk_public_sources = files([ 'gdkprofiler.c', 'gdkpopup.c', 'gdktoplevellayout.c', + 'gdktoplevelsize.c', 'gdktoplevel.c', 'gdkdragsurface.c', ]) @@ -95,6 +96,7 @@ gdk_public_headers = files([ 'gdkpopuplayout.h', 'gdkpopup.h', 'gdktoplevellayout.h', + 'gdktoplevelsize.h', 'gdktoplevel.h', 'gdkdragsurface.h', ]) @@ -107,6 +109,7 @@ gdk_private_h_sources = files([ 'gdkdevicetoolprivate.h', 'gdkmonitorprivate.h', 'gdkseatdefaultprivate.h', + 'gdktoplevelsizeprivate.h', ]) gdk_gresource_xml = configure_file(output : 'gdk.gresource.xml', diff --git a/gdk/wayland/gdksurface-wayland.c b/gdk/wayland/gdksurface-wayland.c index d30d7a8a12..2d6cafd187 100644 --- a/gdk/wayland/gdksurface-wayland.c +++ b/gdk/wayland/gdksurface-wayland.c @@ -146,11 +146,21 @@ struct _GdkWaylandSurface cairo_region_t *input_region; gboolean input_region_dirty; + GdkRectangle last_sent_window_geometry; + int last_sent_min_width; + int last_sent_min_height; + int last_sent_max_width; + int last_sent_max_height; + int saved_width; int saved_height; gulong parent_surface_committed_handler; + struct { + GdkToplevelLayout *layout; + } toplevel; + struct { GdkPopupLayout *layout; int unconstrained_width; @@ -1112,6 +1122,9 @@ gdk_wayland_surface_sync_margin (GdkSurface *surface) &impl->geometry_hints, impl->geometry_mask); + if (gdk_rectangle_equal (&geometry, &impl->last_sent_window_geometry)) + return; + switch (display_wayland->shell_variant) { case GDK_WAYLAND_SHELL_VARIANT_XDG_SHELL: @@ -1131,6 +1144,8 @@ gdk_wayland_surface_sync_margin (GdkSurface *surface) default: g_assert_not_reached (); } + + impl->last_sent_window_geometry = geometry; } static struct wl_region * @@ -1265,6 +1280,50 @@ gdk_wayland_surface_create_surface (GdkSurface *surface) impl->display_server.wl_surface = wl_surface; } +static void +configure_surface_geometry (GdkSurface *surface) +{ + GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface); + GdkDisplay *display = gdk_surface_get_display (surface); + GdkMonitor *monitor; + GdkRectangle monitor_geometry; + int bounds_width, bounds_height; + GdkToplevelSize size; + int width, height; + GdkToplevelLayout *layout; + GdkGeometry geometry; + GdkSurfaceHints mask; + + monitor = g_list_model_get_item (gdk_display_get_monitors (display), 0); + gdk_monitor_get_geometry (monitor, &monitor_geometry); + bounds_width = monitor_geometry.width; + bounds_height = monitor_geometry.height; + + gdk_toplevel_size_init (&size, bounds_width, bounds_height); + gdk_toplevel_notify_compute_size (GDK_TOPLEVEL (surface), &size); + width = size.width; + height = size.height; + g_warn_if_fail (width > 0); + g_warn_if_fail (height > 0); + + layout = impl->toplevel.layout; + if (gdk_toplevel_layout_get_resizable (layout)) + { + geometry.min_width = size.min_width; + geometry.min_height = size.min_height; + mask = GDK_HINT_MIN_SIZE; + } + else + { + geometry.max_width = geometry.min_width = width; + geometry.max_height = geometry.min_height = height; + mask = GDK_HINT_MIN_SIZE | GDK_HINT_MAX_SIZE; + } + gdk_wayland_surface_set_geometry_hints (surface, &geometry, mask); + gdk_surface_constrain_size (&geometry, mask, width, height, &width, &height); + gdk_wayland_surface_resize (surface, width, height, impl->scale); +} + static void gdk_wayland_surface_configure_toplevel (GdkSurface *surface) { @@ -1322,6 +1381,10 @@ gdk_wayland_surface_configure_toplevel (GdkSurface *surface) gdk_wayland_surface_resize (surface, width, height, impl->scale); } + else + { + configure_surface_geometry (surface); + } GDK_DISPLAY_NOTE (gdk_surface_get_display (surface), EVENTS, g_message ("configure, surface %p %dx%d,%s%s%s%s", @@ -2729,6 +2792,7 @@ gdk_wayland_surface_hide_surface (GdkSurface *surface) g_slist_free (impl->display_server.outputs); impl->display_server.outputs = NULL; + g_clear_pointer (&impl->toplevel.layout, gdk_toplevel_layout_unref); g_clear_pointer (&impl->popup.layout, gdk_popup_layout_unref); } @@ -3369,6 +3433,12 @@ gdk_wayland_surface_set_geometry_hints (GdkSurface *surface, max_height = 0; } + if (impl->last_sent_min_width == min_width && + impl->last_sent_min_height == min_height && + impl->last_sent_max_width == max_width && + impl->last_sent_max_height == max_height) + return; + switch (display_wayland->shell_variant) { case GDK_WAYLAND_SHELL_VARIANT_XDG_SHELL: @@ -3386,6 +3456,11 @@ gdk_wayland_surface_set_geometry_hints (GdkSurface *surface, default: g_assert_not_reached (); } + + impl->last_sent_min_width = min_width; + impl->last_sent_min_height = min_height; + impl->last_sent_max_width = max_width; + impl->last_sent_max_height = max_height; } static void @@ -4676,37 +4751,41 @@ show_surface (GdkSurface *surface) gdk_surface_invalidate_rect (surface, NULL); } +static void +reconfigure_callback (void *data, + struct wl_callback *callback, + uint32_t time) +{ + gboolean *done = (gboolean *) data; + + *done = TRUE; +} + +static const struct wl_callback_listener reconfigure_listener = { + reconfigure_callback +}; + static gboolean gdk_wayland_toplevel_present (GdkToplevel *toplevel, - int width, - int height, GdkToplevelLayout *layout) { GdkSurface *surface = GDK_SURFACE (toplevel); GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface); - GdkGeometry geometry; - GdkSurfaceHints mask; - - if (gdk_toplevel_layout_get_resizable (layout)) - { - geometry.min_width = gdk_toplevel_layout_get_min_width (layout); - geometry.min_height = gdk_toplevel_layout_get_min_height (layout); - mask = GDK_HINT_MIN_SIZE; - } - else - { - geometry.max_width = geometry.min_width = width; - geometry.max_height = geometry.min_height = height; - mask = GDK_HINT_MIN_SIZE | GDK_HINT_MAX_SIZE; - } - gdk_wayland_surface_set_geometry_hints (surface, &geometry, mask); - gdk_surface_constrain_size (&geometry, mask, width, height, &width, &height); - gdk_wayland_surface_resize (surface, width, height, impl->scale); + GdkWaylandDisplay *display_wayland; + struct wl_callback *callback; + gboolean done = FALSE; + int last_configure_serial = impl->last_configure_serial; + gboolean needs_reconfigure = TRUE; if (gdk_toplevel_layout_get_maximized (layout)) - gdk_wayland_surface_maximize (surface); + { + gdk_wayland_surface_maximize (surface); + needs_reconfigure = FALSE; + } else - gdk_wayland_surface_unmaximize (surface); + { + gdk_wayland_surface_unmaximize (surface); + } if (gdk_toplevel_layout_get_fullscreen (layout)) { @@ -4715,12 +4794,34 @@ gdk_wayland_toplevel_present (GdkToplevel *toplevel, gdk_wayland_surface_fullscreen_on_monitor (surface, monitor); else gdk_wayland_surface_fullscreen (surface); + needs_reconfigure = FALSE; } else gdk_wayland_surface_unfullscreen (surface); + g_clear_pointer (&impl->toplevel.layout, gdk_toplevel_layout_unref); + impl->toplevel.layout = gdk_toplevel_layout_copy (layout); + show_surface (surface); + display_wayland = GDK_WAYLAND_DISPLAY (gdk_surface_get_display (surface)); + callback = wl_display_sync (display_wayland->wl_display); + wl_proxy_set_queue ((struct wl_proxy *) callback, impl->event_queue); + wl_callback_add_listener (callback, + &reconfigure_listener, + &done); + while (is_realized_toplevel (surface) && + !impl->initial_configure_received && + !done) + wl_display_dispatch_queue (display_wayland->wl_display, impl->event_queue); + + if (needs_reconfigure && + last_configure_serial == impl->last_configure_serial && + !(surface->state & (GDK_SURFACE_STATE_MAXIMIZED | + GDK_SURFACE_STATE_FULLSCREEN | + GDK_SURFACE_STATE_TILED))) + configure_surface_geometry (surface); + return TRUE; } diff --git a/gdk/win32/gdksurface-win32.c b/gdk/win32/gdksurface-win32.c index fc52a82a5a..a8e2e125a0 100644 --- a/gdk/win32/gdksurface-win32.c +++ b/gdk/win32/gdksurface-win32.c @@ -4941,18 +4941,43 @@ show_surface (GdkSurface *surface) static gboolean gdk_win32_toplevel_present (GdkToplevel *toplevel, - int width, - int height, - GdkToplevelLayout *layout) + GdkToplevelLayout *layout) { GdkSurface *surface = GDK_SURFACE (toplevel); + GdkDisplay *display = gdk_surface_get_display (surface); + GdkMonitor *monitor; + GdkToplevelSize size; + int bounds_width, bounds_height; + int width, height; GdkGeometry geometry; GdkSurfaceHints mask; + monitor = gdk_display_get_monitor_at_surface (display, surface); + if (monitor) + { + GdkRectangle workarea; + + gdk_win32_monitor_get_workarea (monitor, &workarea); + bounds_width = workarea.width; + bounds_height = workarea.height; + } + else + { + bounds_width = G_MAXINT; + bounds_height = G_MAXINT; + } + + gdk_toplevel_size_init (&size, bounds_width, bounds_height); + gdk_toplevel_notify_compute_size (toplevel, &size); + g_warn_if_fail (size.width > 0); + g_warn_if_fail (size.height > 0); + width = size.width; + height = size.height; + if (gdk_toplevel_layout_get_resizable (layout)) { - geometry.min_width = gdk_toplevel_layout_get_min_width (layout); - geometry.min_height = gdk_toplevel_layout_get_min_height (layout); + geometry.min_width = size.min_width; + geometry.min_height = size.min_height; mask = GDK_HINT_MIN_SIZE; } else diff --git a/gdk/x11/gdksurface-x11.c b/gdk/x11/gdksurface-x11.c index d797368d79..b0a49cc737 100644 --- a/gdk/x11/gdksurface-x11.c +++ b/gdk/x11/gdksurface-x11.c @@ -43,6 +43,7 @@ #include "gdktextureprivate.h" #include "gdk-private.h" +#include #include #include #include @@ -1017,7 +1018,8 @@ _gdk_x11_display_create_surface (GdkDisplay *display, impl->xid = XCreateWindow (xdisplay, xparent, (surface->x + abs_x) * impl->surface_scale, (surface->y + abs_y) * impl->surface_scale, - surface->width * impl->surface_scale, surface->height * impl->surface_scale, + MAX (1, surface->width * impl->surface_scale), + MAX (1, surface->height * impl->surface_scale), 0, depth, class, xvisual, xattributes_mask, &xattributes); @@ -4830,21 +4832,46 @@ gdk_x11_toplevel_class_init (GdkX11ToplevelClass *class) static gboolean gdk_x11_toplevel_present (GdkToplevel *toplevel, - int width, - int height, GdkToplevelLayout *layout) { GdkSurface *surface = GDK_SURFACE (toplevel); + GdkDisplay *display = gdk_surface_get_display (surface); + GdkMonitor *monitor; + GdkToplevelSize size; + int bounds_width, bounds_height; + int width, height; GdkGeometry geometry; GdkSurfaceHints mask; gboolean was_mapped; gdk_x11_surface_unminimize (surface); + monitor = gdk_display_get_monitor_at_surface (display, surface); + if (monitor) + { + GdkRectangle workarea; + + gdk_x11_monitor_get_workarea (monitor, &workarea); + bounds_width = workarea.width; + bounds_height = workarea.height; + } + else + { + bounds_width = G_MAXINT; + bounds_height = G_MAXINT; + } + + gdk_toplevel_size_init (&size, bounds_width, bounds_height); + gdk_toplevel_notify_compute_size (toplevel, &size); + g_warn_if_fail (size.width > 0); + g_warn_if_fail (size.height > 0); + width = size.width; + height = size.height; + if (gdk_toplevel_layout_get_resizable (layout)) { - geometry.min_width = gdk_toplevel_layout_get_min_width (layout); - geometry.min_height = gdk_toplevel_layout_get_min_height (layout); + geometry.min_width = size.min_width; + geometry.min_height = size.min_height; mask = GDK_HINT_MIN_SIZE; } else @@ -4864,9 +4891,11 @@ gdk_x11_toplevel_present (GdkToplevel *toplevel, if (gdk_toplevel_layout_get_fullscreen (layout)) { - GdkMonitor *monitor = gdk_toplevel_layout_get_fullscreen_monitor (layout); - if (monitor) - gdk_x11_surface_fullscreen_on_monitor (surface, monitor); + GdkMonitor *fullscreen_monitor = + gdk_toplevel_layout_get_fullscreen_monitor (layout); + + if (fullscreen_monitor) + gdk_x11_surface_fullscreen_on_monitor (surface, fullscreen_monitor); else gdk_x11_surface_fullscreen (surface); } diff --git a/gtk/gtkwindow.c b/gtk/gtkwindow.c index 58041745d3..e0f419f88c 100644 --- a/gtk/gtkwindow.c +++ b/gtk/gtkwindow.c @@ -471,9 +471,7 @@ static void _gtk_window_set_is_active (GtkWindow *window, gboolean is_active); static void gtk_window_present_toplevel (GtkWindow *window); static void gtk_window_update_toplevel (GtkWindow *window); -static GdkToplevelLayout * gtk_window_compute_layout (GtkWindow *window, - int min_width, - int min_height); +static GdkToplevelLayout * gtk_window_compute_layout (GtkWindow *window); static void gtk_window_release_application (GtkWindow *window); @@ -3839,14 +3837,12 @@ gtk_window_hide (GtkWidget *widget) } static GdkToplevelLayout * -gtk_window_compute_layout (GtkWindow *window, - int min_width, - int min_height) +gtk_window_compute_layout (GtkWindow *window) { GtkWindowPrivate *priv = gtk_window_get_instance_private (window); GdkToplevelLayout *layout; - layout = gdk_toplevel_layout_new (min_width, min_height); + layout = gdk_toplevel_layout_new (); gdk_toplevel_layout_set_resizable (layout, priv->resizable); gdk_toplevel_layout_set_maximized (layout, priv->maximize_initially); @@ -3861,23 +3857,11 @@ static void gtk_window_present_toplevel (GtkWindow *window) { GtkWindowPrivate *priv = gtk_window_get_instance_private (window); - GdkRectangle request; - GdkGeometry geometry; - GdkSurfaceHints flags; - - gtk_window_compute_configure_request (window, &request, - &geometry, &flags); - - if (!(flags & GDK_HINT_MIN_SIZE)) - geometry.min_width = geometry.min_height = 1; if (!priv->layout) - priv->layout = gtk_window_compute_layout (window, geometry.min_width, geometry.min_height); + priv->layout = gtk_window_compute_layout (window); - gdk_toplevel_present (GDK_TOPLEVEL (priv->surface), - request.width, - request.height, - priv->layout); + gdk_toplevel_present (GDK_TOPLEVEL (priv->surface), priv->layout); } static void @@ -3887,22 +3871,10 @@ gtk_window_update_toplevel (GtkWindow *window) if (priv->surface && gdk_surface_get_mapped (priv->surface)) { - int min_width = 1; - int min_height = 1; - - if (priv->layout) - { - min_width = gdk_toplevel_layout_get_min_width (priv->layout); - min_height = gdk_toplevel_layout_get_min_height (priv->layout); - } - g_clear_pointer (&priv->layout, gdk_toplevel_layout_unref); - priv->layout = gtk_window_compute_layout (window, min_width, min_height); + priv->layout = gtk_window_compute_layout (window); - gdk_toplevel_present (GDK_TOPLEVEL (priv->surface), - gdk_surface_get_width (priv->surface), - gdk_surface_get_height (priv->surface), - priv->layout); + gdk_toplevel_present (GDK_TOPLEVEL (priv->surface), priv->layout); } } @@ -3930,9 +3902,6 @@ gtk_window_map (GtkWidget *widget) gtk_window_set_theme_variant (window); - /* No longer use the default settings */ - priv->need_default_size = FALSE; - if (!disable_startup_notification) { /* Do we have a custom startup-notification id? */ @@ -4014,7 +3983,7 @@ gtk_window_guess_default_size (GtkWindow *window, GtkWidget *widget; GdkSurface *surface; GdkDisplay *display; - GdkMonitor *monitor; + GdkMonitor *monitor = NULL; GdkRectangle geometry; int minimum, natural; @@ -4025,21 +3994,22 @@ gtk_window_guess_default_size (GtkWindow *window, if (surface) { monitor = gdk_display_get_monitor_at_surface (display, surface); + if (monitor) + g_object_ref (monitor); + } + + if (!monitor) + monitor = g_list_model_get_item (gdk_display_get_monitors (display), 0); + + if (monitor) + { gdk_monitor_get_geometry (monitor, &geometry); + g_object_unref (monitor); } else { - monitor = g_list_model_get_item (gdk_display_get_monitors (display), 0); - if (monitor) - { - gdk_monitor_get_geometry (monitor, &geometry); - g_object_unref (monitor); - } - else - { - geometry.width = G_MAXINT; - geometry.height = G_MAXINT; - } + geometry.width = G_MAXINT; + geometry.height = G_MAXINT; } *width = geometry.width; @@ -4277,14 +4247,150 @@ update_realized_window_properties (GtkWindow *window) } } +static void +gtk_window_compute_default_size (GtkWindow *window, + int max_width, + int max_height, + int *width, + int *height) +{ + GtkWindowPrivate *priv = gtk_window_get_instance_private (window); + GtkWidget *widget = GTK_WIDGET (window); + + *width = max_width; + *height = max_height; + if (gtk_widget_get_request_mode (widget) == GTK_SIZE_REQUEST_WIDTH_FOR_HEIGHT) + { + int minimum, natural; + + gtk_widget_measure (widget, GTK_ORIENTATION_VERTICAL, -1, + &minimum, &natural, + NULL, NULL); + *height = MAX (minimum, MIN (*height, natural)); + + gtk_widget_measure (widget, GTK_ORIENTATION_HORIZONTAL, + *height, + &minimum, &natural, + NULL, NULL); + *width = MAX (minimum, MIN (*width, natural)); + } + else /* GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH or CONSTANT_SIZE */ + { + int minimum, natural; + + gtk_widget_measure (widget, GTK_ORIENTATION_HORIZONTAL, -1, + &minimum, &natural, + NULL, NULL); + *width = MAX (minimum, MIN (*width, natural)); + + gtk_widget_measure (widget, GTK_ORIENTATION_VERTICAL, + *width, + &minimum, &natural, + NULL, NULL); + *height = MAX (minimum, MIN (*height, natural)); + } + + /* No longer use the default settings */ + priv->need_default_size = FALSE; +} + +static void +toplevel_compute_size (GdkToplevel *toplevel, + GdkToplevelSize *size, + GtkWidget *widget) +{ + GtkWindow *window = GTK_WINDOW (widget); + GtkWindowPrivate *priv = gtk_window_get_instance_private (window); + GtkWindowGeometryInfo *info; + int width, height; + GtkBorder shadow; + int min_width, min_height; + + info = gtk_window_get_geometry_info (window, FALSE); + + if (priv->need_default_size) + { + int remembered_width; + int remembered_height; + int bounds_width; + int bounds_height; + + gdk_toplevel_size_get_bounds (size, &bounds_width, &bounds_height); + + gtk_window_compute_default_size (window, + bounds_width, bounds_height, + &width, &height); + gtk_window_get_remembered_size (window, + &remembered_width, &remembered_height); + width = MAX (width, remembered_width); + height = MAX (height, remembered_height); + + /* Override with default size */ + if (info) + { + /* Take width of shadows/headerbar into account. We want to set the + * default size of the content area and not the window area. + */ + int default_width_csd = info->default_width; + int default_height_csd = info->default_height; + gtk_window_update_csd_size (window, + &default_width_csd, &default_height_csd, + INCLUDE_CSD_SIZE); + + if (info->default_width > 0) + width = default_width_csd; + if (info->default_height > 0) + height = default_height_csd; + } + } + else + { + /* Default to keeping current size */ + gtk_window_get_remembered_size (window, &width, &height); + } + + /* Override any size with gtk_window_resize() values */ + if (priv->maximized || priv->fullscreen) + { + /* Unless we are maximized or fullscreen */ + gtk_window_get_remembered_size (window, &width, &height); + } + else if (info) + { + int resize_width_csd = info->resize_width; + int resize_height_csd = info->resize_height; + gtk_window_update_csd_size (window, + &resize_width_csd, &resize_height_csd, + INCLUDE_CSD_SIZE); + + if (info->resize_width > 0) + width = resize_width_csd; + if (info->resize_height > 0) + height = resize_height_csd; + } + + /* Don't ever request zero width or height, it's not supported by + gdk. The size allocation code will round it to 1 anyway but if + we do it then the value returned from this function will is + not comparable to the size allocation read from the GtkWindow. */ + width = MAX (width, 1); + height = MAX (height, 1); + + gdk_toplevel_size_set_size (size, width, height); + + get_shadow_width (window, &shadow); + + min_width = width + shadow.left + shadow.right; + min_height = height + shadow.top + shadow.bottom; + gdk_toplevel_size_set_min_size (size, min_width, min_height); +} + static void gtk_window_realize (GtkWidget *widget) { GtkWindow *window = GTK_WINDOW (widget); GtkWindowPrivate *priv = gtk_window_get_instance_private (window); - GtkAllocation allocation; GdkSurface *surface; - GtkBorder shadow; /* Create default title bar */ if (!priv->client_decorated && gtk_window_should_use_csd (window)) @@ -4308,32 +4414,7 @@ gtk_window_realize (GtkWidget *widget) } } - get_shadow_width (window, &shadow); - - /* ensure widget tree is properly size allocated */ - if (_gtk_widget_get_alloc_needed (widget)) - { - GdkRectangle request; - - gtk_window_compute_configure_request (window, &request, NULL, NULL); - - allocation.x = shadow.left; - allocation.y = shadow.top; - allocation.width = request.width - shadow.left - shadow.right; - allocation.height = request.height - shadow.top - shadow.bottom; - - gtk_widget_size_allocate (widget, &allocation, -1); - - gtk_widget_queue_resize (widget); - - g_return_if_fail (!_gtk_widget_get_realized (widget)); - } - - gtk_widget_get_allocation (widget, &allocation); - - surface = gdk_surface_new_toplevel (gtk_widget_get_display (widget), - MAX (1, allocation.width + shadow.left + shadow.right), - MAX (1, allocation.height + shadow.top + shadow.bottom)); + surface = gdk_surface_new_toplevel (gtk_widget_get_display (widget)); priv->surface = surface; gdk_surface_set_widget (surface, widget); @@ -4341,6 +4422,7 @@ gtk_window_realize (GtkWidget *widget) g_signal_connect_swapped (surface, "size-changed", G_CALLBACK (surface_size_changed), widget); g_signal_connect (surface, "render", G_CALLBACK (surface_render), widget); g_signal_connect (surface, "event", G_CALLBACK (surface_event), widget); + g_signal_connect (surface, "compute-size", G_CALLBACK (toplevel_compute_size), widget); GTK_WIDGET_CLASS (gtk_window_parent_class)->realize (widget); @@ -5376,7 +5458,7 @@ gtk_window_move_resize (GtkWindow *window) new_geometry.min_width = new_geometry.min_height = 1; g_clear_pointer (&priv->layout, gdk_toplevel_layout_unref); - priv->layout = gtk_window_compute_layout (window, new_geometry.min_width, new_geometry.min_height); + priv->layout = gtk_window_compute_layout (window); /* This check implies the invariant that we never set info->last * without setting the hints and sending off a configure request. @@ -5573,9 +5655,7 @@ gtk_window_move_resize (GtkWindow *window) if (configure_request_pos_changed) g_warning ("configure request position changed. This should not happen. Ignoring the position"); - gdk_toplevel_present (GDK_TOPLEVEL (priv->surface), - new_request.width, new_request.height, - priv->layout); + gdk_toplevel_present (GDK_TOPLEVEL (priv->surface), priv->layout); } else { diff --git a/gtk/inspector/general.c b/gtk/inspector/general.c index 2e610a6672..76bd0011e2 100644 --- a/gtk/inspector/general.c +++ b/gtk/inspector/general.c @@ -141,7 +141,7 @@ init_version (GtkInspectorGeneral *gen) #endif backend = "Unknown"; - surface = gdk_surface_new_toplevel (gen->display, 10, 10); + surface = gdk_surface_new_toplevel (gen->display); gsk_renderer = gsk_renderer_new_for_surface (surface); if (strcmp (G_OBJECT_TYPE_NAME (gsk_renderer), "GskVulkanRenderer") == 0) renderer = "Vulkan"; @@ -402,7 +402,7 @@ init_vulkan (GtkInspectorGeneral *gen) GdkSurface *surface; GdkVulkanContext *context; - surface = gdk_surface_new_toplevel (gen->display, 10, 10); + surface = gdk_surface_new_toplevel (gen->display); context = gdk_surface_create_vulkan_context (surface, NULL); gdk_surface_destroy (surface); diff --git a/tests/rendernode.c b/tests/rendernode.c index 49a6c8601c..786cc6d050 100644 --- a/tests/rendernode.c +++ b/tests/rendernode.c @@ -128,7 +128,7 @@ main(int argc, char **argv) GdkSurface *window; GdkTexture *texture = NULL; - window = gdk_surface_new_toplevel (gdk_display_get_default(), 10 , 10); + window = gdk_surface_new_toplevel (gdk_display_get_default()); renderer = gsk_renderer_new_for_surface (window); for (run = 0; run < runs; run++) diff --git a/tests/showrendernode.c b/tests/showrendernode.c index 670e776e1d..25e9960251 100644 --- a/tests/showrendernode.c +++ b/tests/showrendernode.c @@ -181,7 +181,7 @@ main (int argc, char **argv) if (write_to_filename != NULL) { - GdkSurface *surface = gdk_surface_new_toplevel (gdk_display_get_default(), 10 , 10); + GdkSurface *surface = gdk_surface_new_toplevel (gdk_display_get_default()); GskRenderer *renderer = gsk_renderer_new_for_surface (surface); GdkTexture *texture = gsk_renderer_render_texture (renderer, GTK_NODE_VIEW (nodeview)->node, NULL); @@ -201,7 +201,7 @@ main (int argc, char **argv) if (compare_node) { GtkWidget *box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12); - GdkSurface *gdk_surface = gdk_surface_new_toplevel (gdk_display_get_default(), 10 , 10); + GdkSurface *gdk_surface = gdk_surface_new_toplevel (gdk_display_get_default()); GskRenderer *renderer = gsk_renderer_new_for_surface (gdk_surface); GdkTexture *texture = gsk_renderer_render_texture (renderer, GTK_NODE_VIEW (nodeview)->node, NULL); GtkWidget *image = gtk_image_new_from_paintable (GDK_PAINTABLE (texture)); diff --git a/tests/testfullscreen.c b/tests/testfullscreen.c index c7deda5e92..3adc82310f 100644 --- a/tests/testfullscreen.c +++ b/tests/testfullscreen.c @@ -34,13 +34,10 @@ set_fullscreen_monitor_cb (GtkWidget *widget, gpointer user_data) monitor = gdk_display_get_monitor_at_surface (display, surface); else monitor = NULL; - layout = gdk_toplevel_layout_new (0, 0); + layout = gdk_toplevel_layout_new (); gdk_toplevel_layout_set_resizable (layout, TRUE); gdk_toplevel_layout_set_fullscreen (layout, TRUE, monitor); - gdk_toplevel_present (GDK_TOPLEVEL (surface), - gdk_surface_get_width (surface), - gdk_surface_get_height (surface), - layout); + gdk_toplevel_present (GDK_TOPLEVEL (surface), layout); gdk_toplevel_layout_unref (layout); } @@ -51,13 +48,10 @@ remove_fullscreen_cb (GtkWidget *widget, gpointer user_data) GdkToplevelLayout *layout; surface = gtk_native_get_surface (gtk_widget_get_native (widget)); - layout = gdk_toplevel_layout_new (0, 0); + layout = gdk_toplevel_layout_new (); gdk_toplevel_layout_set_resizable (layout, TRUE); gdk_toplevel_layout_set_fullscreen (layout, FALSE, NULL); - gdk_toplevel_present (GDK_TOPLEVEL (surface), - gdk_surface_get_width (surface), - gdk_surface_get_height (surface), - layout); + gdk_toplevel_present (GDK_TOPLEVEL (surface), layout); gdk_toplevel_layout_unref (layout); } diff --git a/testsuite/gsk/compare-render.c b/testsuite/gsk/compare-render.c index c3d1c570b8..c71ee55b7c 100644 --- a/testsuite/gsk/compare-render.c +++ b/testsuite/gsk/compare-render.c @@ -173,7 +173,7 @@ main (int argc, char **argv) node_file = argv[1]; png_file = argv[2]; - window = gdk_surface_new_toplevel (gdk_display_get_default(), 10 , 10); + window = gdk_surface_new_toplevel (gdk_display_get_default()); renderer = gsk_renderer_new_for_surface (window); g_print ("Node file: '%s'\n", node_file); diff --git a/testsuite/gtk/defaultvalue.c b/testsuite/gtk/defaultvalue.c index 4947dac52f..f1b4d1f7fc 100644 --- a/testsuite/gtk/defaultvalue.c +++ b/testsuite/gtk/defaultvalue.c @@ -110,7 +110,7 @@ test_type (gconstpointer data) instance = G_OBJECT (g_object_ref (gtk_settings_get_default ())); else if (g_type_is_a (type, GDK_TYPE_SURFACE)) { - instance = G_OBJECT (g_object_ref (gdk_surface_new_toplevel (display, 100, 100))); + instance = G_OBJECT (g_object_ref (gdk_surface_new_toplevel (display))); } else if (g_type_is_a (type, GTK_TYPE_FILTER_LIST_MODEL) || g_type_is_a (type, GTK_TYPE_NO_SELECTION) || diff --git a/testsuite/gtk/notify.c b/testsuite/gtk/notify.c index 5dd4499577..797d05d594 100644 --- a/testsuite/gtk/notify.c +++ b/testsuite/gtk/notify.c @@ -430,7 +430,7 @@ test_type (gconstpointer data) instance = G_OBJECT (g_object_ref (gtk_settings_get_default ())); else if (g_type_is_a (type, GDK_TYPE_SURFACE)) { - instance = G_OBJECT (g_object_ref (gdk_surface_new_toplevel (display, 100, 100))); + instance = G_OBJECT (g_object_ref (gdk_surface_new_toplevel (display))); } else if (g_str_equal (g_type_name (type), "GdkX11Cursor")) instance = g_object_new (type, "display", display, NULL); diff --git a/testsuite/gtk/shortcuts.c b/testsuite/gtk/shortcuts.c index e0ce9c6509..ad5e9c798b 100644 --- a/testsuite/gtk/shortcuts.c +++ b/testsuite/gtk/shortcuts.c @@ -322,7 +322,7 @@ test_trigger_trigger (void) g_object_ref (trigger[2])); device = gdk_seat_get_keyboard (seat); - surface = gdk_surface_new_toplevel (display, 100, 100); + surface = gdk_surface_new_toplevel (display); for (i = 0; i < G_N_ELEMENTS (tests); i++) { diff --git a/testsuite/gtk/test-focus-chain.c b/testsuite/gtk/test-focus-chain.c index 2e52388f63..033cec98b5 100644 --- a/testsuite/gtk/test-focus-chain.c +++ b/testsuite/gtk/test-focus-chain.c @@ -217,6 +217,16 @@ get_dir_for_file (const char *path) return 0; } +static gboolean +quit_iteration_loop (gpointer user_data) +{ + gboolean *keep_running = user_data; + + *keep_running = FALSE; + + return G_SOURCE_REMOVE; +} + static gboolean load_ui_file (GFile *ui_file, GFile *ref_file, @@ -230,6 +240,8 @@ load_ui_file (GFile *ui_file, GError *error = NULL; GtkDirectionType dir; gboolean success = FALSE; + gboolean keep_running = TRUE; + guint timeout_handle_id; ui_path = g_file_get_path (ui_file); @@ -238,6 +250,19 @@ load_ui_file (GFile *ui_file, g_assert (window != NULL); + gtk_widget_show (window); + + timeout_handle_id = g_timeout_add (2000, + quit_iteration_loop, + &keep_running); + while (keep_running) + { + if (!g_main_context_iteration (NULL, FALSE)) + break; + } + if (keep_running) + g_source_remove (timeout_handle_id); + if (ext) { int i;