diff options
author | Jonas Ã…dahl <jadahl@gmail.com> | 2020-07-30 23:06:59 +0200 |
---|---|---|
committer | Jonas Ã…dahl <jadahl@gmail.com> | 2020-08-05 15:49:00 +0200 |
commit | 2ff74eb667c2cbe293c7309d5661fa438e8431c4 (patch) | |
tree | 67d4f4087f45decc59014e07fb643e169cb2a10f /gdk | |
parent | 4ee82e8175d1d1ed21d3ef8133f0d76267bde75c (diff) | |
download | gtk+-2ff74eb667c2cbe293c7309d5661fa438e8431c4.tar.gz |
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.
Diffstat (limited to 'gdk')
-rw-r--r-- | gdk/broadway/gdksurface-broadway.c | 34 | ||||
-rw-r--r-- | gdk/gdk.h | 1 | ||||
-rw-r--r-- | gdk/gdksurface.c | 8 | ||||
-rw-r--r-- | gdk/gdksurface.h | 4 | ||||
-rw-r--r-- | gdk/gdktoplevel.c | 62 | ||||
-rw-r--r-- | gdk/gdktoplevel.h | 2 | ||||
-rw-r--r-- | gdk/gdktoplevellayout.c | 43 | ||||
-rw-r--r-- | gdk/gdktoplevellayout.h | 8 | ||||
-rw-r--r-- | gdk/gdktoplevelprivate.h | 8 | ||||
-rw-r--r-- | gdk/gdktoplevelsize.c | 119 | ||||
-rw-r--r-- | gdk/gdktoplevelsize.h | 62 | ||||
-rw-r--r-- | gdk/gdktoplevelsizeprivate.h | 39 | ||||
-rw-r--r-- | gdk/macos/gdkmacostoplevelsurface.c | 33 | ||||
-rw-r--r-- | gdk/meson.build | 3 | ||||
-rw-r--r-- | gdk/wayland/gdksurface-wayland.c | 139 | ||||
-rw-r--r-- | gdk/win32/gdksurface-win32.c | 35 | ||||
-rw-r--r-- | gdk/x11/gdksurface-x11.c | 45 |
17 files changed, 535 insertions, 110 deletions
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 <graphene.h> #include <stdlib.h> #include <stdio.h> #include <string.h> @@ -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 @@ -70,6 +70,7 @@ #include <gdk/gdktexture.h> #include <gdk/gdktoplevel.h> #include <gdk/gdktoplevellayout.h> +#include <gdk/gdktoplevelsize.h> #include <gdk/gdktypes.h> #include <gdk/gdkversionmacros.h> #include <gdk/gdkvulkancontext.h> 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 <graphene-gobject.h> #include <math.h> /** @@ -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,43 +150,13 @@ 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 * @resizable: %TRUE to allow resizing 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); @@ -67,11 +66,6 @@ void gdk_toplevel_layout_set_fullscreen (GdkToplevelLayout *l 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); GDK_AVAILABLE_IN_ALL 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 <graphene.h> 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 <http://www.gnu.org/licenses/>. + * + */ + +#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 <http://www.gnu.org/licenses/>. + * + */ + +#ifndef __GDK_TOPLEVEL_SIZE_H__ +#define __GDK_TOPLEVEL_SIZE_H__ + +#if !defined(__GDK_H_INSIDE__) && !defined(GTK_COMPILATION) +#error "Only <gdk/gdk.h> can be included directly." +#endif + +#include <gdk/gdktypes.h> +#include <gdk/gdkversionmacros.h> + +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 <http://www.gnu.org/licenses/>. + * + */ + +#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,12 +146,22 @@ 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; int unconstrained_height; @@ -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 * @@ -1266,6 +1281,50 @@ gdk_wayland_surface_create_surface (GdkSurface *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) { GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (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; + 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_resizable (layout)) + if (gdk_toplevel_layout_get_maximized (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; + gdk_wayland_surface_maximize (surface); + needs_reconfigure = FALSE; } 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_unmaximize (surface); } - 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); - - if (gdk_toplevel_layout_get_maximized (layout)) - gdk_wayland_surface_maximize (surface); - else - 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 <graphene.h> #include <stdlib.h> #include <stdio.h> #include <string.h> @@ -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); } |