From 9e6a55a086cdb14914e1f5543bd83140d345dce9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Thu, 19 Nov 2020 10:40:42 +0100 Subject: [PATCH 01/87] wayland: Decouple mapped state from surface creation --- gdk/wayland/gdksurface-wayland.c | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/gdk/wayland/gdksurface-wayland.c b/gdk/wayland/gdksurface-wayland.c index 35378851c6..2f227dcd3f 100644 --- a/gdk/wayland/gdksurface-wayland.c +++ b/gdk/wayland/gdksurface-wayland.c @@ -4737,22 +4737,16 @@ gdk_wayland_toplevel_class_init (GdkWaylandToplevelClass *class) } static void -show_surface (GdkSurface *surface) +maybe_notify_mapped (GdkSurface *surface) { - gboolean was_mapped; - if (surface->destroyed) return; - was_mapped = GDK_SURFACE_IS_MAPPED (surface); - - if (!was_mapped) - gdk_synthesize_surface_state (surface, GDK_TOPLEVEL_STATE_WITHDRAWN, 0); - - gdk_wayland_surface_show (surface, FALSE); - - if (!was_mapped) - gdk_surface_invalidate_rect (surface, NULL); + if (!GDK_SURFACE_IS_MAPPED (surface)) + { + gdk_synthesize_surface_state (surface, GDK_TOPLEVEL_STATE_WITHDRAWN, 0); + gdk_surface_invalidate_rect (surface, NULL); + } } static void @@ -4806,7 +4800,8 @@ gdk_wayland_toplevel_present (GdkToplevel *toplevel, g_clear_pointer (&impl->toplevel.layout, gdk_toplevel_layout_unref); impl->toplevel.layout = gdk_toplevel_layout_copy (layout); - show_surface (surface); + gdk_wayland_surface_show (surface, FALSE); + maybe_notify_mapped (surface); display_wayland = GDK_WAYLAND_DISPLAY (gdk_surface_get_display (surface)); callback = wl_display_sync (display_wayland->wl_display); @@ -4962,7 +4957,8 @@ gdk_wayland_drag_surface_present (GdkDragSurface *drag_surface, GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface); gdk_wayland_surface_resize (surface, width, height, impl->scale); - show_surface (surface); + gdk_wayland_surface_show (surface, FALSE); + maybe_notify_mapped (surface); return TRUE; } From 366b946f5b8bbb26972a542e3505833753fc6fc5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Thu, 19 Nov 2020 10:43:22 +0100 Subject: [PATCH 02/87] wayland/popup: Use maybe_notify_mapped() helper --- gdk/wayland/gdksurface-wayland.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/gdk/wayland/gdksurface-wayland.c b/gdk/wayland/gdksurface-wayland.c index 2f227dcd3f..c992ff4214 100644 --- a/gdk/wayland/gdksurface-wayland.c +++ b/gdk/wayland/gdksurface-wayland.c @@ -2948,6 +2948,19 @@ is_relayout_finished (GdkSurface *surface) return TRUE; } +static void +maybe_notify_mapped (GdkSurface *surface) +{ + if (surface->destroyed) + return; + + if (!GDK_SURFACE_IS_MAPPED (surface)) + { + gdk_synthesize_surface_state (surface, GDK_TOPLEVEL_STATE_WITHDRAWN, 0); + gdk_surface_invalidate_rect (surface, NULL); + } +} + static void gdk_wayland_surface_map_popup (GdkSurface *surface, int width, @@ -2983,7 +2996,7 @@ gdk_wayland_surface_map_popup (GdkSurface *surface, impl->popup.unconstrained_height = height; impl->mapped = TRUE; - gdk_synthesize_surface_state (surface, GDK_TOPLEVEL_STATE_WITHDRAWN, 0); + maybe_notify_mapped (surface); } static void @@ -4736,19 +4749,6 @@ gdk_wayland_toplevel_class_init (GdkWaylandToplevelClass *class) gdk_toplevel_install_properties (object_class, 1); } -static void -maybe_notify_mapped (GdkSurface *surface) -{ - if (surface->destroyed) - return; - - if (!GDK_SURFACE_IS_MAPPED (surface)) - { - gdk_synthesize_surface_state (surface, GDK_TOPLEVEL_STATE_WITHDRAWN, 0); - gdk_surface_invalidate_rect (surface, NULL); - } -} - static void reconfigure_callback (void *data, struct wl_callback *callback, From 528ec4ddedbf7600c9456e684e5fa82752d8ecf4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Thu, 19 Nov 2020 10:54:20 +0100 Subject: [PATCH 03/87] wayland: Only set mapped state when mapped Mapping a surface under Wayland is an asynchronous process, where one creates a surface and commits an initial state without having drawn anything, then waiting for a configuration, which then is acknowledged and content is painted and committed. Not until having received this configuration is a surface actually mapped, so wait with setting the mappedness until this. --- gdk/wayland/gdkdevice-wayland.c | 2 +- gdk/wayland/gdkprivate-wayland.h | 1 + gdk/wayland/gdksurface-wayland.c | 38 ++++++++++++++++++-------------- 3 files changed, 24 insertions(+), 17 deletions(-) diff --git a/gdk/wayland/gdkdevice-wayland.c b/gdk/wayland/gdkdevice-wayland.c index 8671561175..c975c2069d 100644 --- a/gdk/wayland/gdkdevice-wayland.c +++ b/gdk/wayland/gdkdevice-wayland.c @@ -4502,7 +4502,7 @@ gdk_wayland_seat_grab (GdkSeat *seat, if (prepare_func) (prepare_func) (seat, surface, prepare_func_data); - if (!gdk_surface_get_mapped (surface)) + if (!gdk_wayland_surface_has_surface (surface)) { gdk_wayland_seat_set_grab_surface (wayland_seat, NULL); return GDK_GRAB_NOT_VIEWABLE; diff --git a/gdk/wayland/gdkprivate-wayland.h b/gdk/wayland/gdkprivate-wayland.h index 19a4e91c0b..eadacffbb9 100644 --- a/gdk/wayland/gdkprivate-wayland.h +++ b/gdk/wayland/gdkprivate-wayland.h @@ -96,6 +96,7 @@ void gdk_wayland_surface_sync (GdkSurface *surface); void gdk_wayland_surface_commit (GdkSurface *surface); void gdk_wayland_surface_notify_committed (GdkSurface *surface); void gdk_wayland_surface_request_frame (GdkSurface *surface); +gboolean gdk_wayland_surface_has_surface (GdkSurface *surface); void gdk_wayland_surface_attach_image (GdkSurface *surface, cairo_surface_t *cairo_surface, const cairo_region_t *damage); diff --git a/gdk/wayland/gdksurface-wayland.c b/gdk/wayland/gdksurface-wayland.c index c992ff4214..1c6c27c1c0 100644 --- a/gdk/wayland/gdksurface-wayland.c +++ b/gdk/wayland/gdksurface-wayland.c @@ -603,6 +603,14 @@ gdk_wayland_surface_request_frame (GdkSurface *surface) impl->awaiting_frame = TRUE; } +gboolean +gdk_wayland_surface_has_surface (GdkSurface *surface) +{ + GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface); + + return !!impl->display_server.wl_surface; +} + void gdk_wayland_surface_commit (GdkSurface *surface) { @@ -1448,6 +1456,19 @@ gdk_wayland_surface_configure_popup (GdkSurface *surface) gdk_surface_invalidate_rect (surface, NULL); } +static void +maybe_notify_mapped (GdkSurface *surface) +{ + if (surface->destroyed) + return; + + if (!GDK_SURFACE_IS_MAPPED (surface)) + { + gdk_synthesize_surface_state (surface, GDK_TOPLEVEL_STATE_WITHDRAWN, 0); + gdk_surface_invalidate_rect (surface, NULL); + } +} + static void gdk_wayland_surface_configure (GdkSurface *surface) { @@ -1458,6 +1479,7 @@ gdk_wayland_surface_configure (GdkSurface *surface) gdk_surface_thaw_updates (surface); impl->initial_configure_received = TRUE; impl->pending.is_initial_configure = TRUE; + maybe_notify_mapped (surface); } impl->has_uncommitted_ack_configure = TRUE; @@ -2948,19 +2970,6 @@ is_relayout_finished (GdkSurface *surface) return TRUE; } -static void -maybe_notify_mapped (GdkSurface *surface) -{ - if (surface->destroyed) - return; - - if (!GDK_SURFACE_IS_MAPPED (surface)) - { - gdk_synthesize_surface_state (surface, GDK_TOPLEVEL_STATE_WITHDRAWN, 0); - gdk_surface_invalidate_rect (surface, NULL); - } -} - static void gdk_wayland_surface_map_popup (GdkSurface *surface, int width, @@ -2995,8 +3004,6 @@ gdk_wayland_surface_map_popup (GdkSurface *surface, impl->popup.unconstrained_width = width; impl->popup.unconstrained_height = height; impl->mapped = TRUE; - - maybe_notify_mapped (surface); } static void @@ -4801,7 +4808,6 @@ gdk_wayland_toplevel_present (GdkToplevel *toplevel, impl->toplevel.layout = gdk_toplevel_layout_copy (layout); gdk_wayland_surface_show (surface, FALSE); - maybe_notify_mapped (surface); display_wayland = GDK_WAYLAND_DISPLAY (gdk_surface_get_display (surface)); callback = wl_display_sync (display_wayland->wl_display); From 641915974be5113ab3bb16e1b5aa0be274d66608 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Fri, 20 Nov 2020 16:56:36 +0100 Subject: [PATCH 04/87] gdk/toplevel: Make gdk_toplevel_present() async The plan is to concencrate size computations as part of the frame clock dispatch, meaning we shouldn't do it synchronously in the present() function. Still, in Wayland, and maybe elsewhere, it is done in the present() function, e.g. when no state change was made, but this will eventually be changed. --- gdk/broadway/gdksurface-broadway.c | 4 +- gdk/gdktoplevel.c | 16 ++--- gdk/gdktoplevel.h | 2 +- gdk/gdktoplevelprivate.h | 2 +- gdk/wayland/gdksurface-wayland.c | 112 +++++++++++++++-------------- gdk/x11/gdksurface-x11.c | 6 +- 6 files changed, 72 insertions(+), 70 deletions(-) diff --git a/gdk/broadway/gdksurface-broadway.c b/gdk/broadway/gdksurface-broadway.c index d9e45ad077..bc5f3eb6c9 100644 --- a/gdk/broadway/gdksurface-broadway.c +++ b/gdk/broadway/gdksurface-broadway.c @@ -1524,7 +1524,7 @@ show_surface (GdkSurface *surface) gdk_surface_invalidate_rect (surface, NULL); } -static gboolean +static void gdk_broadway_toplevel_present (GdkToplevel *toplevel, GdkToplevelLayout *layout) { @@ -1583,8 +1583,6 @@ gdk_broadway_toplevel_present (GdkToplevel *toplevel, gdk_broadway_surface_unmaximize (surface); show_surface (surface); - - return TRUE; } static gboolean diff --git a/gdk/gdktoplevel.c b/gdk/gdktoplevel.c index 34328db10d..4cff2bb3dd 100644 --- a/gdk/gdktoplevel.c +++ b/gdk/gdktoplevel.c @@ -51,11 +51,10 @@ enum static guint signals[N_SIGNALS] = { 0 }; -static gboolean +static void gdk_toplevel_default_present (GdkToplevel *toplevel, GdkToplevelLayout *layout) { - return FALSE; } static gboolean @@ -239,18 +238,17 @@ gdk_toplevel_install_properties (GObjectClass *object_class, * 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. + * Presenting is asynchronous and the specified layout parameters are not + * guaranteed to be respected. */ -gboolean +void gdk_toplevel_present (GdkToplevel *toplevel, GdkToplevelLayout *layout) { - g_return_val_if_fail (GDK_IS_TOPLEVEL (toplevel), FALSE); - g_return_val_if_fail (layout != NULL, FALSE); + g_return_if_fail (GDK_IS_TOPLEVEL (toplevel)); + g_return_if_fail (layout != NULL); - return GDK_TOPLEVEL_GET_IFACE (toplevel)->present (toplevel, layout); + GDK_TOPLEVEL_GET_IFACE (toplevel)->present (toplevel, layout); } /** diff --git a/gdk/gdktoplevel.h b/gdk/gdktoplevel.h index 05fafa4b5f..28402feb10 100644 --- a/gdk/gdktoplevel.h +++ b/gdk/gdktoplevel.h @@ -129,7 +129,7 @@ GDK_AVAILABLE_IN_ALL G_DECLARE_INTERFACE (GdkToplevel, gdk_toplevel, GDK, TOPLEVEL, GObject) GDK_AVAILABLE_IN_ALL -gboolean gdk_toplevel_present (GdkToplevel *toplevel, +void gdk_toplevel_present (GdkToplevel *toplevel, GdkToplevelLayout *layout); GDK_AVAILABLE_IN_ALL diff --git a/gdk/gdktoplevelprivate.h b/gdk/gdktoplevelprivate.h index 989ac29c46..52dcdca0ad 100644 --- a/gdk/gdktoplevelprivate.h +++ b/gdk/gdktoplevelprivate.h @@ -13,7 +13,7 @@ struct _GdkToplevelInterface { GTypeInterface g_iface; - gboolean (* present) (GdkToplevel *toplevel, + void (* present) (GdkToplevel *toplevel, GdkToplevelLayout *layout); gboolean (* minimize) (GdkToplevel *toplevel); gboolean (* lower) (GdkToplevel *toplevel); diff --git a/gdk/wayland/gdksurface-wayland.c b/gdk/wayland/gdksurface-wayland.c index 1c6c27c1c0..27eb433a58 100644 --- a/gdk/wayland/gdksurface-wayland.c +++ b/gdk/wayland/gdksurface-wayland.c @@ -4756,79 +4756,87 @@ gdk_wayland_toplevel_class_init (GdkWaylandToplevelClass *class) gdk_toplevel_install_properties (object_class, 1); } -static void -reconfigure_callback (void *data, - struct wl_callback *callback, - uint32_t time) +static gboolean +did_maximize_layout_change (GdkToplevel *toplevel, + GdkToplevelLayout *layout) { - gboolean *done = (gboolean *) data; + GdkSurface *surface = GDK_SURFACE (toplevel); + GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface); - *done = TRUE; + if (!impl->toplevel.layout) + return TRUE; + + if (gdk_toplevel_layout_get_maximized (impl->toplevel.layout) != + gdk_toplevel_layout_get_maximized (layout)) + return TRUE; + + return FALSE; } -static const struct wl_callback_listener reconfigure_listener = { - reconfigure_callback -}; - static gboolean +did_fullscreen_layout_change (GdkToplevel *toplevel, + GdkToplevelLayout *layout) +{ + GdkSurface *surface = GDK_SURFACE (toplevel); + GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface); + + if (!impl->toplevel.layout) + return TRUE; + + if (gdk_toplevel_layout_get_fullscreen (impl->toplevel.layout) != + gdk_toplevel_layout_get_fullscreen (layout)) + return TRUE; + + if (gdk_toplevel_layout_get_fullscreen_monitor (impl->toplevel.layout) != + gdk_toplevel_layout_get_fullscreen_monitor (layout)) + return TRUE; + + return FALSE; +} + +static void gdk_wayland_toplevel_present (GdkToplevel *toplevel, GdkToplevelLayout *layout) { GdkSurface *surface = GDK_SURFACE (toplevel); GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface); - GdkWaylandDisplay *display_wayland; - struct wl_callback *callback; - gboolean done = FALSE; - int last_configure_serial = impl->last_configure_serial; - gboolean needs_reconfigure = TRUE; + gboolean pending_configure = FALSE; - if (gdk_toplevel_layout_get_maximized (layout)) + if (did_maximize_layout_change (toplevel, layout)) { - gdk_wayland_surface_maximize (surface); - needs_reconfigure = FALSE; - } - else - { - gdk_wayland_surface_unmaximize (surface); - } - - if (gdk_toplevel_layout_get_fullscreen (layout)) - { - GdkMonitor *monitor = gdk_toplevel_layout_get_fullscreen_monitor (layout); - if (monitor) - gdk_wayland_surface_fullscreen_on_monitor (surface, monitor); + if (gdk_toplevel_layout_get_maximized (layout)) + gdk_wayland_surface_maximize (surface); else - gdk_wayland_surface_fullscreen (surface); - needs_reconfigure = FALSE; + gdk_wayland_surface_unmaximize (surface); + pending_configure = TRUE; + } + + if (did_fullscreen_layout_change (toplevel, layout)) + { + if (gdk_toplevel_layout_get_fullscreen (layout)) + { + GdkMonitor *monitor; + + monitor = gdk_toplevel_layout_get_fullscreen_monitor (layout); + if (monitor) + gdk_wayland_surface_fullscreen_on_monitor (surface, monitor); + else + gdk_wayland_surface_fullscreen (surface); + } + else + { + gdk_wayland_surface_unfullscreen (surface); + } + pending_configure = TRUE; } - else - gdk_wayland_surface_unfullscreen (surface); g_clear_pointer (&impl->toplevel.layout, gdk_toplevel_layout_unref); impl->toplevel.layout = gdk_toplevel_layout_copy (layout); gdk_wayland_surface_show (surface, FALSE); - 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 (impl) && - (!impl->initial_configure_received || !done)) - wl_display_dispatch_queue (display_wayland->wl_display, impl->event_queue); - - wl_callback_destroy (callback); - - if (needs_reconfigure && - last_configure_serial == impl->last_configure_serial && - !(surface->state & (GDK_TOPLEVEL_STATE_MAXIMIZED | - GDK_TOPLEVEL_STATE_FULLSCREEN | - GDK_TOPLEVEL_STATE_TILED))) + if (!pending_configure) configure_surface_geometry (surface); - - return TRUE; } static gboolean diff --git a/gdk/x11/gdksurface-x11.c b/gdk/x11/gdksurface-x11.c index 24b536cb96..c4b14e11e3 100644 --- a/gdk/x11/gdksurface-x11.c +++ b/gdk/x11/gdksurface-x11.c @@ -4849,7 +4849,7 @@ gdk_x11_toplevel_class_init (GdkX11ToplevelClass *class) gdk_toplevel_install_properties (object_class, LAST_PROP); } -static gboolean +static void gdk_x11_toplevel_present (GdkToplevel *toplevel, GdkToplevelLayout *layout) { @@ -4922,7 +4922,7 @@ gdk_x11_toplevel_present (GdkToplevel *toplevel, gdk_x11_surface_unfullscreen (surface); if (surface->destroyed) - return TRUE; + return; was_mapped = GDK_SURFACE_IS_MAPPED (surface); @@ -4933,8 +4933,6 @@ gdk_x11_toplevel_present (GdkToplevel *toplevel, if (!was_mapped) gdk_surface_invalidate_rect (surface, NULL); - - return TRUE; } static gboolean From 996eeec16cd3923a1f50c7aafbb68e81cd108c3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Fri, 20 Nov 2020 17:11:44 +0100 Subject: [PATCH 05/87] gtk/window: Don't gdk_toplevel_present() if not mapped That would map the window too early. --- gtk/gtkwindow.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/gtk/gtkwindow.c b/gtk/gtkwindow.c index 996e09c64b..e1d83addbd 100644 --- a/gtk/gtkwindow.c +++ b/gtk/gtkwindow.c @@ -3856,7 +3856,8 @@ gtk_window_update_toplevel (GtkWindow *window) g_clear_pointer (&priv->layout, gdk_toplevel_layout_unref); priv->layout = gtk_window_compute_layout (window); - gdk_toplevel_present (GDK_TOPLEVEL (priv->surface), priv->layout); + if (_gtk_widget_get_mapped (GTK_WIDGET (window))) + gdk_toplevel_present (GDK_TOPLEVEL (priv->surface), priv->layout); } } @@ -5660,7 +5661,8 @@ 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), priv->layout); + if (_gtk_widget_get_mapped (widget)) + gdk_toplevel_present (GDK_TOPLEVEL (priv->surface), priv->layout); } else { @@ -5869,8 +5871,6 @@ gtk_window_present_with_time (GtkWindow *window, g_assert (surface != NULL); - gtk_window_present_toplevel (window); - /* Translate a timestamp of GDK_CURRENT_TIME appropriately */ if (timestamp == GDK_CURRENT_TIME) { From 23d7392eb98148d3f2c7a239c97abe43881e064f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Mon, 23 Nov 2020 16:13:45 +0100 Subject: [PATCH 06/87] gdk/surface: Removed unused struct field The 'old_state' wasn't used anywhere, lets remove it. --- gdk/gdksurfaceprivate.h | 1 - 1 file changed, 1 deletion(-) diff --git a/gdk/gdksurfaceprivate.h b/gdk/gdksurfaceprivate.h index f655d6c97f..c3933e0437 100644 --- a/gdk/gdksurfaceprivate.h +++ b/gdk/gdksurfaceprivate.h @@ -59,7 +59,6 @@ struct _GdkSurface more than we have to, but it represents the "true" damage. */ cairo_region_t *active_update_area; - GdkToplevelState old_state; GdkToplevelState state; guint8 resize_count; From f4c36fe1ce8c75aee23f70ae7923c42ff49806e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Mon, 23 Nov 2020 16:39:11 +0100 Subject: [PATCH 07/87] gdk/surface: Add API to queue and apply state changes This will be used to compress state changes and apply as part of a frame clock dispatch. --- gdk/gdksurface.c | 33 ++++++++++++++++++++++++++++++++- gdk/gdksurfaceprivate.h | 9 +++++++++ 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/gdk/gdksurface.c b/gdk/gdksurface.c index 93e61d5c68..a64cbb0f94 100644 --- a/gdk/gdksurface.c +++ b/gdk/gdksurface.c @@ -1670,7 +1670,11 @@ gdk_surface_hide (GdkSurface *surface) was_mapped = GDK_SURFACE_IS_MAPPED (surface); if (GDK_SURFACE_IS_MAPPED (surface)) - gdk_synthesize_surface_state (surface, 0, GDK_TOPLEVEL_STATE_WITHDRAWN); + { + gdk_synthesize_surface_state (surface, 0, GDK_TOPLEVEL_STATE_WITHDRAWN); + surface->pending_unset_flags = 0; + surface->pending_set_flags = 0; + } if (was_mapped) { @@ -2659,6 +2663,33 @@ gdk_synthesize_surface_state (GdkSurface *surface, gdk_surface_set_state (surface, (surface->state | set_flags) & ~unset_flags); } +void +gdk_surface_queue_state_change (GdkSurface *surface, + GdkToplevelState unset_flags, + GdkToplevelState set_flags) +{ + surface->pending_unset_flags |= unset_flags; + surface->pending_set_flags &= ~unset_flags; + + surface->pending_set_flags |= set_flags; + surface->pending_unset_flags &= ~set_flags; +} + +void +gdk_surface_apply_state_change (GdkSurface *surface) +{ + if (!surface->pending_unset_flags && !surface->pending_set_flags) + return; + + gdk_synthesize_surface_state (surface, + surface->pending_unset_flags, + surface->pending_set_flags); + if (surface->pending_unset_flags & GDK_TOPLEVEL_STATE_WITHDRAWN) + gdk_surface_invalidate_rect (surface, NULL); + surface->pending_unset_flags = 0; + surface->pending_set_flags = 0; +} + static gboolean check_autohide (GdkEvent *event) { diff --git a/gdk/gdksurfaceprivate.h b/gdk/gdksurfaceprivate.h index c3933e0437..5bc290493f 100644 --- a/gdk/gdksurfaceprivate.h +++ b/gdk/gdksurfaceprivate.h @@ -59,6 +59,8 @@ struct _GdkSurface more than we have to, but it represents the "true" damage. */ cairo_region_t *active_update_area; + GdkToplevelState pending_set_flags; + GdkToplevelState pending_unset_flags; GdkToplevelState state; guint8 resize_count; @@ -325,9 +327,16 @@ void gdk_surface_constrain_size (GdkGeometry *geometry, int *new_width, int *new_height); +void gdk_surface_queue_state_change (GdkSurface *surface, + GdkToplevelState unset_flags, + GdkToplevelState set_flags); + +void gdk_surface_apply_state_change (GdkSurface *surface); + GDK_AVAILABLE_IN_ALL void gdk_surface_request_motion (GdkSurface *surface); + G_END_DECLS #endif /* __GDK_SURFACE_PRIVATE_H__ */ From 18d92c3f16633aff5f10a7e9d7fa814c40b835ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Mon, 23 Nov 2020 16:46:29 +0100 Subject: [PATCH 08/87] wayland: Keep pending initial state separate Queue it, and then wait for it to actually take effect, i.e. be confirmed via a configure event from the compositor, before setting the actual GdkSurface::state value. --- gdk/wayland/gdksurface-wayland.c | 41 +++++++++++++++++++++++--------- 1 file changed, 30 insertions(+), 11 deletions(-) diff --git a/gdk/wayland/gdksurface-wayland.c b/gdk/wayland/gdksurface-wayland.c index 27eb433a58..39e815a219 100644 --- a/gdk/wayland/gdksurface-wayland.c +++ b/gdk/wayland/gdksurface-wayland.c @@ -179,6 +179,11 @@ struct _GdkWaylandSurface gboolean is_dirty; } pending; + struct { + GdkToplevelState unset_flags; + GdkToplevelState set_flags; + } initial_state; + uint32_t last_configure_serial; int state_freeze_count; @@ -1307,6 +1312,20 @@ configure_surface_geometry (GdkSurface *surface) gdk_wayland_surface_resize (surface, width, height, impl->scale); } +static void +synthesize_initial_surface_state (GdkSurface *surface, + GdkToplevelState unset_flags, + GdkToplevelState set_flags) +{ + GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface); + + impl->initial_state.unset_flags |= unset_flags; + impl->initial_state.set_flags &= ~unset_flags; + + impl->initial_state.set_flags |= set_flags; + impl->initial_state.unset_flags &= ~set_flags; +} + static void gdk_wayland_surface_configure_toplevel (GdkSurface *surface) { @@ -1786,20 +1805,20 @@ gdk_wayland_surface_create_xdg_toplevel (GdkSurface *surface) switch (display_wayland->shell_variant) { case GDK_WAYLAND_SHELL_VARIANT_XDG_SHELL: - if (surface->state & GDK_TOPLEVEL_STATE_MAXIMIZED) + if (impl->initial_state.set_flags & GDK_TOPLEVEL_STATE_MAXIMIZED) xdg_toplevel_set_maximized (impl->display_server.xdg_toplevel); - if (surface->state & GDK_TOPLEVEL_STATE_MINIMIZED) + if (impl->initial_state.set_flags & GDK_TOPLEVEL_STATE_MINIMIZED) xdg_toplevel_set_minimized (impl->display_server.xdg_toplevel); - if (surface->state & GDK_TOPLEVEL_STATE_FULLSCREEN) + if (impl->initial_state.set_flags & GDK_TOPLEVEL_STATE_FULLSCREEN) xdg_toplevel_set_fullscreen (impl->display_server.xdg_toplevel, impl->initial_fullscreen_output); break; case GDK_WAYLAND_SHELL_VARIANT_ZXDG_SHELL_V6: - if (surface->state & GDK_TOPLEVEL_STATE_MAXIMIZED) + if (impl->initial_state.set_flags & GDK_TOPLEVEL_STATE_MAXIMIZED) zxdg_toplevel_v6_set_maximized (impl->display_server.zxdg_toplevel_v6); - if (surface->state & GDK_TOPLEVEL_STATE_MINIMIZED) + if (impl->initial_state.set_flags & GDK_TOPLEVEL_STATE_MINIMIZED) zxdg_toplevel_v6_set_minimized (impl->display_server.zxdg_toplevel_v6); - if (surface->state & GDK_TOPLEVEL_STATE_FULLSCREEN) + if (impl->initial_state.set_flags & GDK_TOPLEVEL_STATE_FULLSCREEN) zxdg_toplevel_v6_set_fullscreen (impl->display_server.zxdg_toplevel_v6, impl->initial_fullscreen_output); break; @@ -3628,7 +3647,7 @@ gdk_wayland_surface_maximize (GdkSurface *surface) } else { - gdk_synthesize_surface_state (surface, 0, GDK_TOPLEVEL_STATE_MAXIMIZED); + synthesize_initial_surface_state (surface, 0, GDK_TOPLEVEL_STATE_MAXIMIZED); } } @@ -3659,7 +3678,7 @@ gdk_wayland_surface_unmaximize (GdkSurface *surface) } else { - gdk_synthesize_surface_state (surface, GDK_TOPLEVEL_STATE_MAXIMIZED, 0); + synthesize_initial_surface_state (surface, GDK_TOPLEVEL_STATE_MAXIMIZED, 0); } } @@ -3696,7 +3715,7 @@ gdk_wayland_surface_fullscreen_on_monitor (GdkSurface *surface, } else { - gdk_synthesize_surface_state (surface, 0, GDK_TOPLEVEL_STATE_FULLSCREEN); + synthesize_initial_surface_state (surface, 0, GDK_TOPLEVEL_STATE_FULLSCREEN); impl->initial_fullscreen_output = output; } } @@ -3734,7 +3753,7 @@ gdk_wayland_surface_fullscreen (GdkSurface *surface) } else { - gdk_synthesize_surface_state (surface, 0, GDK_TOPLEVEL_STATE_FULLSCREEN); + synthesize_initial_surface_state (surface, 0, GDK_TOPLEVEL_STATE_FULLSCREEN); } } @@ -3767,7 +3786,7 @@ gdk_wayland_surface_unfullscreen (GdkSurface *surface) } else { - gdk_synthesize_surface_state (surface, GDK_TOPLEVEL_STATE_FULLSCREEN, 0); + synthesize_initial_surface_state (surface, GDK_TOPLEVEL_STATE_FULLSCREEN, 0); } } From dd738d27872706ec758a97bc481ad4e26b9c32b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Mon, 23 Nov 2020 17:23:44 +0100 Subject: [PATCH 09/87] surface: Only keep state 'withdrawn' after hiding A hidden surface should start from a clean slate when showing again, so clear any now out of date state. --- gdk/gdksurface.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/gdk/gdksurface.c b/gdk/gdksurface.c index a64cbb0f94..25e6f12b27 100644 --- a/gdk/gdksurface.c +++ b/gdk/gdksurface.c @@ -1671,7 +1671,9 @@ gdk_surface_hide (GdkSurface *surface) if (GDK_SURFACE_IS_MAPPED (surface)) { - gdk_synthesize_surface_state (surface, 0, GDK_TOPLEVEL_STATE_WITHDRAWN); + gdk_synthesize_surface_state (surface, + surface->state & ~GDK_TOPLEVEL_STATE_WITHDRAWN, + GDK_TOPLEVEL_STATE_WITHDRAWN); surface->pending_unset_flags = 0; surface->pending_set_flags = 0; } From 251bd15597a0d622546bd371f3aa52b8231f305f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Mon, 23 Nov 2020 17:26:06 +0100 Subject: [PATCH 10/87] wayland: Apply new surface state at the beginning of a frame Concentrate state application to the start of a frame; this is to avoid having GTK going back and forth between different state if so would happen between two frames. --- gdk/wayland/gdksurface-wayland.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/gdk/wayland/gdksurface-wayland.c b/gdk/wayland/gdksurface-wayland.c index 39e815a219..bcbc647a28 100644 --- a/gdk/wayland/gdksurface-wayland.c +++ b/gdk/wayland/gdksurface-wayland.c @@ -587,6 +587,8 @@ on_frame_clock_before_paint (GdkFrameClock *clock, */ timings->predicted_presentation_time = timings->frame_time + refresh_interval / 2 + refresh_interval; } + + gdk_surface_apply_state_change (surface); } void @@ -1401,7 +1403,7 @@ gdk_wayland_surface_configure_toplevel (GdkSurface *surface) (new_state & GDK_TOPLEVEL_STATE_FOCUSED) ? " focused" : "", (new_state & GDK_TOPLEVEL_STATE_TILED) ? " tiled" : "")); - gdk_surface_set_state (surface, new_state); + gdk_surface_queue_state_change (surface, ~0 & ~new_state, new_state); switch (display_wayland->shell_variant) { @@ -1482,10 +1484,7 @@ maybe_notify_mapped (GdkSurface *surface) return; if (!GDK_SURFACE_IS_MAPPED (surface)) - { - gdk_synthesize_surface_state (surface, GDK_TOPLEVEL_STATE_WITHDRAWN, 0); - gdk_surface_invalidate_rect (surface, NULL); - } + gdk_surface_queue_state_change (surface, GDK_TOPLEVEL_STATE_WITHDRAWN, 0); } static void From 8f27b3fcf6fade010510796193d965f525fbebce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Mon, 23 Nov 2020 21:08:40 +0100 Subject: [PATCH 11/87] gtk/window: Let the backend handle toplevel freezing --- gdk/gdk-private.h | 3 --- gdk/gdksurface.c | 20 -------------------- gtk/gtkwindow.c | 39 --------------------------------------- 3 files changed, 62 deletions(-) diff --git a/gdk/gdk-private.h b/gdk/gdk-private.h index d2d185d57e..3df7d3215c 100644 --- a/gdk/gdk-private.h +++ b/gdk/gdk-private.h @@ -15,9 +15,6 @@ gboolean gdk_device_grab_info (GdkDisplay *display, void gdk_pre_parse (void); -void gdk_surface_freeze_toplevel_updates (GdkSurface *surface); -void gdk_surface_thaw_toplevel_updates (GdkSurface *surface); - gboolean gdk_surface_supports_edge_constraints (GdkSurface *surface); void gdk_display_set_double_click_time (GdkDisplay *display, diff --git a/gdk/gdksurface.c b/gdk/gdksurface.c index 25e6f12b27..b0831bcc55 100644 --- a/gdk/gdksurface.c +++ b/gdk/gdksurface.c @@ -1523,26 +1523,6 @@ gdk_surface_thaw_updates (GdkSurface *surface) gdk_surface_schedule_update (surface); } } -} - -void -gdk_surface_freeze_toplevel_updates (GdkSurface *surface) -{ - g_return_if_fail (GDK_IS_SURFACE (surface)); - - surface->update_and_descendants_freeze_count++; - gdk_surface_freeze_updates (surface); -} - -void -gdk_surface_thaw_toplevel_updates (GdkSurface *surface) -{ - g_return_if_fail (GDK_IS_SURFACE (surface)); - g_return_if_fail (surface->update_and_descendants_freeze_count > 0); - - surface->update_and_descendants_freeze_count--; - gdk_surface_schedule_update (surface); - gdk_surface_thaw_updates (surface); } diff --git a/gtk/gtkwindow.c b/gtk/gtkwindow.c index e1d83addbd..fc2cd4a986 100644 --- a/gtk/gtkwindow.c +++ b/gtk/gtkwindow.c @@ -177,8 +177,6 @@ typedef struct guint32 initial_timestamp; - guint16 configure_request_count; - guint mnemonics_display_timeout_id; guint focus_visible_timeout; @@ -1467,7 +1465,6 @@ gtk_window_init (GtkWindow *window) priv->geometry_info = NULL; priv->focus_widget = NULL; priv->default_widget = NULL; - priv->configure_request_count = 0; priv->resizable = TRUE; priv->configure_notify_received = FALSE; priv->need_default_size = TRUE; @@ -3924,11 +3921,6 @@ gtk_window_unmap (GtkWidget *widget) GTK_WIDGET_CLASS (gtk_window_parent_class)->unmap (widget); gdk_surface_hide (priv->surface); - while (priv->configure_request_count > 0) - { - priv->configure_request_count--; - gdk_surface_thaw_toplevel_updates (priv->surface); - } priv->configure_notify_received = FALSE; state = gdk_toplevel_get_state (GDK_TOPLEVEL (priv->surface)); @@ -4770,25 +4762,6 @@ surface_size_changed (GtkWidget *widget, info->last.configure_request.height = height; } - /* priv->configure_request_count incremented for each - * configure request, and decremented to a min of 0 for - * each configure notify. - * - * All it means is that we know we will get at least - * priv->configure_request_count more configure notifies. - * We could get more configure notifies than that; some - * of the configure notifies we get may be unrelated to - * the configure requests. But we will get at least - * priv->configure_request_count notifies. - */ - - if (priv->configure_request_count > 0) - { - priv->configure_request_count -= 1; - - gdk_surface_thaw_toplevel_updates (priv->surface); - } - /* * If we do need to resize, we do that by: * - setting configure_notify_received to TRUE @@ -5498,7 +5471,6 @@ gtk_window_move_resize (GtkWindow *window) "resize: \t%d x %d\n" "size_changed: %d pos_changed: %d hints_changed: %d\n" "configure_notify_received: %d\n" - "configure_request_count: %d\n" "position_constraints_changed: %d", priv->title ? priv->title : "(no title)", info->last.configure_request.x, @@ -5519,7 +5491,6 @@ gtk_window_move_resize (GtkWindow *window) configure_request_pos_changed, hints_changed, priv->configure_notify_received, - priv->configure_request_count, info->position_constraints_changed); } #endif @@ -5631,16 +5602,6 @@ gtk_window_move_resize (GtkWindow *window) * we don't get the ConfigureNotify back, the resize queue will never be run. */ - /* Increment the number of have-not-yet-received-notify requests. - * This is done before gdk_surface[_move]_resize(), because - * that call might be synchronous (depending on which GDK backend - * is being used), so any preparations for its effects must - * be done beforehand. - */ - priv->configure_request_count += 1; - - gdk_surface_freeze_toplevel_updates (priv->surface); - /* for GTK_RESIZE_QUEUE toplevels, we are now awaiting a new * configure event in response to our resizing request. * the configure event will cause a new resize with From e07fde5c81d9421a2479e92fa41a81e49aaab31e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Tue, 24 Nov 2020 15:02:35 +0100 Subject: [PATCH 12/87] frame-clock: Add 'compute-size' phase This will be handled between 'update' (which may trigger animation ticks, CSS update, etc) and 'layout' which will allocate the widget tree. It's meant to perform surface size computation, and is done between these two phases in order to have an up to date state, and letting the layout phase have an up to date size to layout in. --- gdk/gdkframeclock.c | 28 ++++++++++++++++++++++++++++ gdk/gdkframeclock.h | 10 ++++++---- gdk/gdkframeclockidle.c | 12 ++++++++++++ gdk/gdkframeclockprivate.h | 1 + 4 files changed, 47 insertions(+), 4 deletions(-) diff --git a/gdk/gdkframeclock.c b/gdk/gdkframeclock.c index 5e4492744c..15efa30afe 100644 --- a/gdk/gdkframeclock.c +++ b/gdk/gdkframeclock.c @@ -78,6 +78,7 @@ enum { FLUSH_EVENTS, BEFORE_PAINT, UPDATE, + COMPUTE_SIZE, LAYOUT, PAINT, AFTER_PAINT, @@ -184,6 +185,21 @@ gdk_frame_clock_class_init (GdkFrameClockClass *klass) NULL, NULL, NULL, G_TYPE_NONE, 0); + /** + * GdkFrameClock::compute-size: + * @clock: the frame clock emitting the signal + * + * This signal is used for computing the size of the underlying + * #GdkSurface. Applications should generally not handle this signal. + */ + signals[COMPUTE_SIZE] = + g_signal_new (g_intern_static_string ("compute-size"), + GDK_TYPE_FRAME_CLOCK, + G_SIGNAL_RUN_LAST, + 0, + NULL, NULL, NULL, + G_TYPE_NONE, 0); + /** * GdkFrameClock::layout: * @clock: the frame clock emitting the signal @@ -682,6 +698,18 @@ _gdk_frame_clock_emit_update (GdkFrameClock *frame_clock) gdk_profiler_end_mark (before, "frameclock update", NULL); } +void +_gdk_frame_clock_emit_compute_size (GdkFrameClock *frame_clock) +{ + gint64 before G_GNUC_UNUSED; + + before = GDK_PROFILER_CURRENT_TIME; + + g_signal_emit (frame_clock, signals[COMPUTE_SIZE], 0); + + gdk_profiler_end_mark (before, "frameclock compute size", NULL); +} + void _gdk_frame_clock_emit_layout (GdkFrameClock *frame_clock) { diff --git a/gdk/gdkframeclock.h b/gdk/gdkframeclock.h index a2eba246ad..dfe0c23747 100644 --- a/gdk/gdkframeclock.h +++ b/gdk/gdkframeclock.h @@ -50,6 +50,7 @@ typedef struct _GdkFrameClockClass GdkFrameClockClass; * @GDK_FRAME_CLOCK_PHASE_FLUSH_EVENTS: corresponds to GdkFrameClock::flush-events. Should not be handled by applications. * @GDK_FRAME_CLOCK_PHASE_BEFORE_PAINT: corresponds to GdkFrameClock::before-paint. Should not be handled by applications. * @GDK_FRAME_CLOCK_PHASE_UPDATE: corresponds to GdkFrameClock::update. + * @GDK_FRAME_CLOCK_PHASE_COMPUTE_SIZE: corresponds to GdkFrameClock::compute-size. Should not be handled by applications. * @GDK_FRAME_CLOCK_PHASE_LAYOUT: corresponds to GdkFrameClock::layout. * @GDK_FRAME_CLOCK_PHASE_PAINT: corresponds to GdkFrameClock::paint. * @GDK_FRAME_CLOCK_PHASE_RESUME_EVENTS: corresponds to GdkFrameClock::resume-events. Should not be handled by applications. @@ -64,10 +65,11 @@ typedef enum { GDK_FRAME_CLOCK_PHASE_FLUSH_EVENTS = 1 << 0, GDK_FRAME_CLOCK_PHASE_BEFORE_PAINT = 1 << 1, GDK_FRAME_CLOCK_PHASE_UPDATE = 1 << 2, - GDK_FRAME_CLOCK_PHASE_LAYOUT = 1 << 3, - GDK_FRAME_CLOCK_PHASE_PAINT = 1 << 4, - GDK_FRAME_CLOCK_PHASE_RESUME_EVENTS = 1 << 5, - GDK_FRAME_CLOCK_PHASE_AFTER_PAINT = 1 << 6 + GDK_FRAME_CLOCK_PHASE_COMPUTE_SIZE = 1 << 3, + GDK_FRAME_CLOCK_PHASE_LAYOUT = 1 << 4, + GDK_FRAME_CLOCK_PHASE_PAINT = 1 << 5, + GDK_FRAME_CLOCK_PHASE_RESUME_EVENTS = 1 << 6, + GDK_FRAME_CLOCK_PHASE_AFTER_PAINT = 1 << 7 } GdkFrameClockPhase; GDK_AVAILABLE_IN_ALL diff --git a/gdk/gdkframeclockidle.c b/gdk/gdkframeclockidle.c index 4870a110a6..ac69aba627 100644 --- a/gdk/gdkframeclockidle.c +++ b/gdk/gdkframeclockidle.c @@ -552,6 +552,18 @@ gdk_frame_clock_paint_idle (void *data) } G_GNUC_FALLTHROUGH; + case GDK_FRAME_CLOCK_PHASE_COMPUTE_SIZE: + if (priv->freeze_count == 0) + { + priv->phase = GDK_FRAME_CLOCK_PHASE_COMPUTE_SIZE; + if ((priv->requested & GDK_FRAME_CLOCK_PHASE_COMPUTE_SIZE) != 0) + { + priv->requested &= ~GDK_FRAME_CLOCK_PHASE_COMPUTE_SIZE; + _gdk_frame_clock_emit_compute_size (clock); + } + } + G_GNUC_FALLTHROUGH; + case GDK_FRAME_CLOCK_PHASE_LAYOUT: if (priv->freeze_count == 0) { diff --git a/gdk/gdkframeclockprivate.h b/gdk/gdkframeclockprivate.h index 010aa4564f..a68bc85da8 100644 --- a/gdk/gdkframeclockprivate.h +++ b/gdk/gdkframeclockprivate.h @@ -122,6 +122,7 @@ gboolean _gdk_frame_timings_steal (GdkFrameTimings *timings, void _gdk_frame_clock_emit_flush_events (GdkFrameClock *frame_clock); void _gdk_frame_clock_emit_before_paint (GdkFrameClock *frame_clock); void _gdk_frame_clock_emit_update (GdkFrameClock *frame_clock); +void _gdk_frame_clock_emit_compute_size (GdkFrameClock *frame_clock); void _gdk_frame_clock_emit_layout (GdkFrameClock *frame_clock); void _gdk_frame_clock_emit_paint (GdkFrameClock *frame_clock); void _gdk_frame_clock_emit_after_paint (GdkFrameClock *frame_clock); From 13b4a4b24ccdeddd83a591a707cff67063d8f1d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Tue, 24 Nov 2020 15:51:56 +0100 Subject: [PATCH 13/87] gdk/toplevelsize: Add way to set margin Will be used to communicate the shadow margin, instead of using gdk_surface_set_shadow_width(). Also set these values in gtkwindow.c. --- gdk/gdktoplevelsize.c | 14 ++++++++++++++ gdk/gdktoplevelsize.h | 7 +++++++ gdk/gdktoplevelsizeprivate.h | 8 ++++++++ gtk/gtkwindow.c | 7 +++++++ 4 files changed, 36 insertions(+) diff --git a/gdk/gdktoplevelsize.c b/gdk/gdktoplevelsize.c index e5802782d4..7cd09ebd5e 100644 --- a/gdk/gdktoplevelsize.c +++ b/gdk/gdktoplevelsize.c @@ -118,6 +118,20 @@ gdk_toplevel_size_set_min_size (GdkToplevelSize *size, size->min_height = min_height; } +void +gdk_toplevel_size_set_margin (GdkToplevelSize *size, + int left, + int right, + int top, + int bottom) +{ + size->margin.is_valid = TRUE; + size->margin.left = left; + size->margin.right = right; + size->margin.top = top; + size->margin.bottom = bottom; +} + void gdk_toplevel_size_validate (GdkToplevelSize *size) { diff --git a/gdk/gdktoplevelsize.h b/gdk/gdktoplevelsize.h index 013a061ee9..41f8a4a604 100644 --- a/gdk/gdktoplevelsize.h +++ b/gdk/gdktoplevelsize.h @@ -54,6 +54,13 @@ void gdk_toplevel_size_set_min_size (GdkToplevelSize * int min_width, int min_height); +GDK_AVAILABLE_IN_ALL +void gdk_toplevel_size_set_margin (GdkToplevelSize *size, + int left, + int right, + int top, + int bottom); + G_END_DECLS #endif /* __GDK_TOPLEVEL_SIZE_H__ */ diff --git a/gdk/gdktoplevelsizeprivate.h b/gdk/gdktoplevelsizeprivate.h index 3576513888..f2c4461bf9 100644 --- a/gdk/gdktoplevelsizeprivate.h +++ b/gdk/gdktoplevelsizeprivate.h @@ -30,6 +30,14 @@ struct _GdkToplevelSize int height; int min_width; int min_height; + + struct { + gboolean is_valid; + int left; + int right; + int top; + int bottom; + } margin; }; void gdk_toplevel_size_init (GdkToplevelSize *size, diff --git a/gtk/gtkwindow.c b/gtk/gtkwindow.c index fc2cd4a986..67c9d721ba 100644 --- a/gtk/gtkwindow.c +++ b/gtk/gtkwindow.c @@ -4364,6 +4364,13 @@ toplevel_compute_size (GdkToplevel *toplevel, min_height = MIN (min_height + shadow.top + shadow.bottom, height); gdk_toplevel_size_set_min_size (size, min_width, min_height); + + if (priv->use_client_shadow) + { + gdk_toplevel_size_set_margin (size, + shadow.left, shadow.right, + shadow.top, shadow.bottom); + } } static void From 4af54fb410f47891d5a6b36db9d4e599c8b66a0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Tue, 24 Nov 2020 16:02:23 +0100 Subject: [PATCH 14/87] gdk/surface: Use helper to emit 'size-changed' signal --- gdk/gdksurface.c | 12 ++++++++++-- gdk/gdksurfaceprivate.h | 4 ++++ 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/gdk/gdksurface.c b/gdk/gdksurface.c index b0831bcc55..d1e6192e53 100644 --- a/gdk/gdksurface.c +++ b/gdk/gdksurface.c @@ -1277,6 +1277,14 @@ gdk_surface_schedule_update (GdkSurface *surface) GDK_FRAME_CLOCK_PHASE_PAINT); } +void +gdk_surface_emit_size_changed (GdkSurface *surface, + int width, + int height) +{ + g_signal_emit (surface, signals[SIZE_CHANGED], 0, width, height); +} + static void gdk_surface_process_updates_internal (GdkSurface *surface) { @@ -2839,8 +2847,8 @@ gdk_surface_handle_event (GdkEvent *event) int width, height; gdk_configure_event_get_size (event, &width, &height); - g_signal_emit (gdk_event_get_surface (event), signals[SIZE_CHANGED], 0, - width, height); + gdk_surface_emit_size_changed (gdk_event_get_surface (event), + width, height); handled = TRUE; } else diff --git a/gdk/gdksurfaceprivate.h b/gdk/gdksurfaceprivate.h index 5bc290493f..5f5c3c178d 100644 --- a/gdk/gdksurfaceprivate.h +++ b/gdk/gdksurfaceprivate.h @@ -333,6 +333,10 @@ void gdk_surface_queue_state_change (GdkSurface *surface, void gdk_surface_apply_state_change (GdkSurface *surface); +void gdk_surface_emit_size_changed (GdkSurface *surface, + int width, + int height); + GDK_AVAILABLE_IN_ALL void gdk_surface_request_motion (GdkSurface *surface); From 68c14242b2840a8d66dd07118c39d842086b3ca2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Tue, 24 Nov 2020 16:03:07 +0100 Subject: [PATCH 15/87] gdk/surface: Add API to request 'compute-size' clock phase --- gdk/gdksurface.c | 26 +++++++++++++++++++++++++- gdk/gdksurfaceprivate.h | 3 +++ 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/gdk/gdksurface.c b/gdk/gdksurface.c index d1e6192e53..0d36a58a03 100644 --- a/gdk/gdksurface.c +++ b/gdk/gdksurface.c @@ -1285,6 +1285,25 @@ gdk_surface_emit_size_changed (GdkSurface *surface, g_signal_emit (surface, signals[SIZE_CHANGED], 0, width, height); } +void +gdk_surface_request_compute_size (GdkSurface *surface) +{ + GdkFrameClock *frame_clock; + + if (surface->update_freeze_count || + gdk_surface_is_toplevel_frozen (surface)) + { + surface->pending_request_compute_size = TRUE; + return; + } + + frame_clock = gdk_surface_get_frame_clock (surface); + g_return_if_fail (frame_clock); + + gdk_frame_clock_request_phase (frame_clock, + GDK_FRAME_CLOCK_PHASE_COMPUTE_SIZE); +} + static void gdk_surface_process_updates_internal (GdkSurface *surface) { @@ -1530,8 +1549,13 @@ gdk_surface_thaw_updates (GdkSurface *surface) surface->pending_schedule_update = FALSE; gdk_surface_schedule_update (surface); } - } + if (surface->pending_request_compute_size) + { + surface->pending_request_compute_size = FALSE; + gdk_surface_request_compute_size (surface); + } + } } /* diff --git a/gdk/gdksurfaceprivate.h b/gdk/gdksurfaceprivate.h index 5f5c3c178d..a6a981dbb8 100644 --- a/gdk/gdksurfaceprivate.h +++ b/gdk/gdksurfaceprivate.h @@ -54,6 +54,7 @@ struct _GdkSurface cairo_region_t *update_area; guint update_freeze_count; gboolean pending_schedule_update; + gboolean pending_request_compute_size; /* This is the update_area that was in effect when the current expose started. It may be smaller than the expose area if we'e painting more than we have to, but it represents the "true" damage. */ @@ -337,6 +338,8 @@ void gdk_surface_emit_size_changed (GdkSurface *surface, int width, int height); +void gdk_surface_request_compute_size (GdkSurface *surface); + GDK_AVAILABLE_IN_ALL void gdk_surface_request_motion (GdkSurface *surface); From 289b50785b8be2a70ba4760ed627fa931cd085b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Tue, 24 Nov 2020 22:58:02 +0100 Subject: [PATCH 16/87] wayland/surface: Don't save uninitialized size GdkSurface's are initialized to have the size 1x1, as otherwise we'd receive an X11 error, would a corresponding X11 window be created. This confuses the "saved size" mechanisms in the Wayland backend, as treats 0 as uninitialized, and not 1. Fix this simply not saving size that if it's smaller or equal than 1. --- gdk/wayland/gdksurface-wayland.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/gdk/wayland/gdksurface-wayland.c b/gdk/wayland/gdksurface-wayland.c index bcbc647a28..16886f5770 100644 --- a/gdk/wayland/gdksurface-wayland.c +++ b/gdk/wayland/gdksurface-wayland.c @@ -341,6 +341,9 @@ _gdk_wayland_surface_save_size (GdkSurface *surface) GDK_TOPLEVEL_STATE_TILED)) return; + if (surface->width <= 1 || surface->height <= 1) + return; + impl->saved_width = surface->width - impl->margin_left - impl->margin_right; impl->saved_height = surface->height - impl->margin_top - impl->margin_bottom; } From 8d4f8f0cfcb79c668400d85834a6bbb0bdf6b2ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Tue, 24 Nov 2020 16:05:26 +0100 Subject: [PATCH 17/87] wayland: Concentrate size computation to 'compute-size' phase This includes computing the surface size, including shadow margin, setting the surface size, during the 'compute-size' clock phase. --- gdk/wayland/gdksurface-wayland.c | 137 ++++++++++++++++++++----------- 1 file changed, 87 insertions(+), 50 deletions(-) diff --git a/gdk/wayland/gdksurface-wayland.c b/gdk/wayland/gdksurface-wayland.c index 16886f5770..6a4ae89dad 100644 --- a/gdk/wayland/gdksurface-wayland.c +++ b/gdk/wayland/gdksurface-wayland.c @@ -184,6 +184,12 @@ struct _GdkWaylandSurface GdkToplevelState set_flags; } initial_state; + gboolean configured_size_should_constrain; + gboolean configured_size_is_fixed; + int configured_width; + int configured_height; + gboolean surface_geometry_dirty; + uint32_t last_configure_serial; int state_freeze_count; @@ -295,6 +301,8 @@ static void update_popup_layout_state (GdkSurface *surface, static gboolean gdk_wayland_surface_is_exported (GdkWaylandSurface *impl); +static void configure_surface_geometry (GdkSurface *surface); + static void gdk_wayland_surface_init (GdkWaylandSurface *impl) { @@ -594,6 +602,19 @@ on_frame_clock_before_paint (GdkFrameClock *clock, gdk_surface_apply_state_change (surface); } +static void +on_frame_clock_compute_size (GdkFrameClock *clock, + GdkSurface *surface) +{ + GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface); + + if (impl->surface_geometry_dirty) + { + configure_surface_geometry (surface); + impl->surface_geometry_dirty = FALSE; + } +} + void gdk_wayland_surface_request_frame (GdkSurface *surface) { @@ -773,6 +794,7 @@ _gdk_wayland_display_create_surface (GdkDisplay *display, gdk_wayland_surface_create_surface (surface); g_signal_connect (frame_clock, "before-paint", G_CALLBACK (on_frame_clock_before_paint), surface); + g_signal_connect (frame_clock, "compute-size", G_CALLBACK (on_frame_clock_compute_size), surface); g_signal_connect (frame_clock, "after-paint", G_CALLBACK (on_frame_clock_after_paint), surface); g_object_unref (frame_clock); @@ -930,14 +952,7 @@ gdk_wayland_surface_resize (GdkSurface *surface, _gdk_surface_update_size (surface); if (is_realized_shell_surface (GDK_WAYLAND_SURFACE (surface))) - { - GdkDisplay *display; - GdkEvent *event; - - event = gdk_configure_event_new (surface, width, height); - display = gdk_surface_get_display (surface); - _gdk_wayland_display_deliver_event (display, event); - } + gdk_surface_emit_size_changed (surface, width, height); } static void gdk_wayland_surface_show (GdkSurface *surface, @@ -1281,7 +1296,6 @@ configure_surface_geometry (GdkSurface *surface) GdkRectangle monitor_geometry; int bounds_width, bounds_height; GdkToplevelSize size; - int width, height; GdkToplevelLayout *layout; GdkGeometry geometry; GdkSurfaceHints mask; @@ -1294,10 +1308,8 @@ configure_surface_geometry (GdkSurface *surface) 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); + g_warn_if_fail (size.width > 0); + g_warn_if_fail (size.height > 0); layout = impl->toplevel.layout; if (gdk_toplevel_layout_get_resizable (layout)) @@ -1308,13 +1320,54 @@ configure_surface_geometry (GdkSurface *surface) } else { - geometry.max_width = geometry.min_width = width; - geometry.max_height = geometry.min_height = height; + geometry.max_width = geometry.min_width = size.width; + geometry.max_height = geometry.min_height = size.height; mask = GDK_HINT_MIN_SIZE | GDK_HINT_MAX_SIZE; } gdk_wayland_surface_set_geometry_hints (impl, &geometry, mask); - gdk_surface_constrain_size (&geometry, mask, width, height, &width, &height); - gdk_wayland_surface_resize (surface, width, height, impl->scale); + + if (size.margin.is_valid) + { + impl->margin_left = size.margin.left; + impl->margin_right = size.margin.right; + impl->margin_top = size.margin.top; + impl->margin_bottom = size.margin.bottom; + } + + if (impl->configured_width > 0 && impl->configured_height > 0) + { + int width, height; + + width = impl->configured_width + impl->margin_left + impl->margin_right; + height = impl->configured_height + impl->margin_top + impl->margin_bottom; + + if (impl->configured_size_should_constrain) + { + gdk_surface_constrain_size (&impl->geometry_hints, + impl->geometry_mask, + width, height, + &width, &height); + } + gdk_wayland_surface_resize (surface, width, height, impl->scale); + + if (!impl->configured_size_is_fixed) + { + impl->configured_size_should_constrain = FALSE; + impl->configured_width = 0; + impl->configured_height = 0; + } + } + else + { + int width, height; + + width = size.width; + height = size.height; + gdk_surface_constrain_size (&geometry, mask, + width, height, + &width, &height); + gdk_wayland_surface_resize (surface, width, height, impl->scale); + } } static void @@ -1370,34 +1423,33 @@ gdk_wayland_surface_configure_toplevel (GdkSurface *surface) if (width > 0 && height > 0) { - GdkSurfaceHints geometry_mask = impl->geometry_mask; - if (!saved_size) { - /* Do not reapply constrains if we are restoring original size */ - gdk_surface_constrain_size (&impl->geometry_hints, - geometry_mask, - width + impl->margin_left + impl->margin_right, - height + impl->margin_top + impl->margin_bottom, - &width, - &height); + impl->configured_size_should_constrain = TRUE; /* Save size for next time we get 0x0 */ _gdk_wayland_surface_save_size (surface); } else { - width += impl->margin_left + impl->margin_right; - height += impl->margin_top + impl->margin_bottom; + impl->configured_size_should_constrain = FALSE; } - gdk_wayland_surface_resize (surface, width, height, impl->scale); + impl->configured_size_is_fixed = fixed_size; + impl->configured_width = width; + impl->configured_height = height; } else { - configure_surface_geometry (surface); + impl->configured_size_should_constrain = FALSE; + impl->configured_size_is_fixed = FALSE; + impl->configured_width = 0; + impl->configured_height = 0; } + impl->surface_geometry_dirty = TRUE; + gdk_surface_request_compute_size (surface); + GDK_DISPLAY_NOTE (gdk_surface_get_display (surface), EVENTS, g_message ("configure, surface %p %dx%d,%s%s%s%s", surface, width, height, @@ -3262,6 +3314,7 @@ gdk_wayland_surface_destroy (GdkSurface *surface, frame_clock = gdk_surface_get_frame_clock (surface); g_signal_handlers_disconnect_by_func (frame_clock, on_frame_clock_before_paint, surface); + g_signal_handlers_disconnect_by_func (frame_clock, on_frame_clock_compute_size, surface); g_signal_handlers_disconnect_by_func (frame_clock, on_frame_clock_after_paint, surface); display = GDK_WAYLAND_DISPLAY (gdk_surface_get_display (surface)); @@ -3969,25 +4022,6 @@ gdk_wayland_surface_set_shadow_width (GdkSurface *surface, int top, int bottom) { - GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface); - int new_width, new_height; - - if (GDK_SURFACE_DESTROYED (surface)) - return; - - /* Reconfigure surface to keep the same surface geometry */ - new_width = surface->width - - (impl->margin_left + impl->margin_right) + (left + right); - new_height = surface->height - - (impl->margin_top + impl->margin_bottom) + (top + bottom); - gdk_wayland_surface_maybe_resize (surface, - new_width, new_height, - impl->scale); - - impl->margin_left = left; - impl->margin_right = right; - impl->margin_top = top; - impl->margin_bottom = bottom; } static gboolean @@ -4857,7 +4891,10 @@ gdk_wayland_toplevel_present (GdkToplevel *toplevel, gdk_wayland_surface_show (surface, FALSE); if (!pending_configure) - configure_surface_geometry (surface); + { + impl->surface_geometry_dirty = TRUE; + gdk_surface_request_compute_size (surface); + } } static gboolean From 0c8d97e3f7b73f02b0376d1a7723ef7aba732efb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Tue, 24 Nov 2020 18:33:05 +0100 Subject: [PATCH 18/87] gtk/root: Validate css node after update It should happen before layout, but after the animation tick, thus after the update. --- gdk/gdksurface.c | 26 +++++++++++++++++ gtk/gtkroot.c | 72 ++++++++++++++++++++++++++++++++++-------------- 2 files changed, 77 insertions(+), 21 deletions(-) diff --git a/gdk/gdksurface.c b/gdk/gdksurface.c index 0d36a58a03..6cd7686bb2 100644 --- a/gdk/gdksurface.c +++ b/gdk/gdksurface.c @@ -78,6 +78,7 @@ enum { POPUP_LAYOUT_CHANGED, SIZE_CHANGED, + LAYOUT, RENDER, EVENT, ENTER_MONITOR, @@ -571,6 +572,31 @@ gdk_surface_class_init (GdkSurfaceClass *klass) G_TYPE_INT, G_TYPE_INT); + /** + * GdkSurface::layout: + * @surface: the #GdkSurface + * @width: the current width + * @height: the current height + * + * Emitted when the size of @surface is changed, or when relayout should + * be performed. + * + * Surface size is reported in ”application pixels”, not + * ”device pixels” (see gdk_surface_get_scale_factor()). + */ + signals[LAYOUT] = + g_signal_new (g_intern_static_string ("layout"), + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + 0, + NULL, + NULL, + NULL, + G_TYPE_NONE, + 2, + G_TYPE_INT, + G_TYPE_INT); + /** * GdkSurface::render: * @surface: the #GdkSurface diff --git a/gtk/gtkroot.c b/gtk/gtkroot.c index 33000c28fc..a480173695 100644 --- a/gtk/gtkroot.c +++ b/gtk/gtkroot.c @@ -44,7 +44,8 @@ */ static GQuark quark_restyle_pending; -static GQuark quark_resize_handler; +static GQuark quark_layout_handler; +static GQuark quark_after_update_handler; G_DEFINE_INTERFACE_WITH_CODE (GtkRoot, gtk_root, GTK_TYPE_WIDGET, g_type_interface_add_prerequisite (g_define_type_id, GTK_TYPE_NATIVE)) @@ -83,7 +84,8 @@ gtk_root_default_init (GtkRootInterface *iface) iface->set_focus = gtk_root_default_set_focus; quark_restyle_pending = g_quark_from_static_string ("gtk-root-restyle-pending"); - quark_resize_handler = g_quark_from_static_string ("gtk-root-resize-handler"); + quark_layout_handler = g_quark_from_static_string ("gtk-root-layout-handler"); + quark_after_update_handler = g_quark_from_static_string ("gtk-root-after-update-handler"); } /** @@ -171,8 +173,8 @@ gtk_root_needs_layout (GtkRoot *self) } static void -gtk_root_layout_cb (GdkFrameClock *clock, - GtkRoot *self) +gtk_root_after_update_cb (GdkFrameClock *clock, + GtkRoot *self) { GtkWidget *widget = GTK_WIDGET (self); @@ -188,9 +190,17 @@ gtk_root_layout_cb (GdkFrameClock *clock, */ if (g_object_get_qdata (G_OBJECT (self), quark_restyle_pending)) { - g_object_set_qdata (G_OBJECT (self), quark_restyle_pending, NULL); gtk_css_node_validate (gtk_widget_get_css_node (widget)); } +} + +static void +gtk_root_layout_cb (GdkFrameClock *clock, + GtkRoot *self) +{ + GtkWidget *widget = GTK_WIDGET (self); + + g_object_set_qdata (G_OBJECT (self), quark_restyle_pending, NULL); /* we may be invoked with a container_resize_queue of NULL, because * queue_resize could have been adding an extra idle function while @@ -219,20 +229,17 @@ gtk_root_layout_cb (GdkFrameClock *clock, } } - if (!gtk_root_needs_layout (self)) - gtk_root_stop_layout (self); - else - gdk_frame_clock_request_phase (clock, GDK_FRAME_CLOCK_PHASE_LAYOUT); + if (gtk_root_needs_layout (self)) + { + gdk_frame_clock_request_phase (clock, GDK_FRAME_CLOCK_PHASE_UPDATE); + gdk_frame_clock_request_phase (clock, GDK_FRAME_CLOCK_PHASE_LAYOUT); + } } void gtk_root_start_layout (GtkRoot *self) { GdkFrameClock *clock; - guint resize_handler; - - if (g_object_get_qdata (G_OBJECT (self), quark_resize_handler)) - return; if (!gtk_root_needs_layout (self)) return; @@ -241,10 +248,25 @@ gtk_root_start_layout (GtkRoot *self) if (clock == NULL) return; - resize_handler = g_signal_connect (clock, "layout", - G_CALLBACK (gtk_root_layout_cb), self); - g_object_set_qdata (G_OBJECT (self), quark_resize_handler, GINT_TO_POINTER (resize_handler)); + if (!g_object_get_qdata (G_OBJECT (self), quark_layout_handler)) + { + guint layout_handler; + guint after_update_handler; + after_update_handler = + g_signal_connect_after (clock, "update", + G_CALLBACK (gtk_root_after_update_cb), self); + g_object_set_qdata (G_OBJECT (self), quark_after_update_handler, + GINT_TO_POINTER (after_update_handler)); + + layout_handler = + g_signal_connect (clock, "layout", + G_CALLBACK (gtk_root_layout_cb), self); + g_object_set_qdata (G_OBJECT (self), quark_layout_handler, + GINT_TO_POINTER (layout_handler)); + } + + gdk_frame_clock_request_phase (clock, GDK_FRAME_CLOCK_PHASE_UPDATE); gdk_frame_clock_request_phase (clock, GDK_FRAME_CLOCK_PHASE_LAYOUT); } @@ -252,16 +274,24 @@ void gtk_root_stop_layout (GtkRoot *self) { GdkFrameClock *clock; - guint resize_handler; + guint layout_handler; + guint after_update_handler; - resize_handler = GPOINTER_TO_INT (g_object_get_qdata (G_OBJECT (self), quark_resize_handler)); + layout_handler = + GPOINTER_TO_INT (g_object_get_qdata (G_OBJECT (self), + quark_layout_handler)); + after_update_handler = + GPOINTER_TO_INT (g_object_get_qdata (G_OBJECT (self), + quark_after_update_handler)); - if (resize_handler == 0) + if (layout_handler == 0) return; clock = gtk_widget_get_frame_clock (GTK_WIDGET (self)); - g_signal_handler_disconnect (clock, resize_handler); - g_object_set_qdata (G_OBJECT (self), quark_resize_handler, NULL); + g_signal_handler_disconnect (clock, layout_handler); + g_signal_handler_disconnect (clock, after_update_handler); + g_object_set_qdata (G_OBJECT (self), quark_layout_handler, NULL); + g_object_set_qdata (G_OBJECT (self), quark_after_update_handler, NULL); } void From 475c07e935b92c2cdef3a0ff24c74ebdeb694d82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Tue, 24 Nov 2020 22:00:38 +0100 Subject: [PATCH 19/87] gdk/surface: Make pending schedule a phase enum Scheduling an update when frozen would reschedule when unfrozen; change this to a generic pending phase enum, and use this for resrcheduling paint and compute-size. --- gdk/gdksurface.c | 18 +++++++----------- gdk/gdksurfaceprivate.h | 3 +-- 2 files changed, 8 insertions(+), 13 deletions(-) diff --git a/gdk/gdksurface.c b/gdk/gdksurface.c index 6cd7686bb2..f5f4a5790d 100644 --- a/gdk/gdksurface.c +++ b/gdk/gdksurface.c @@ -1290,7 +1290,7 @@ gdk_surface_schedule_update (GdkSurface *surface) if (surface->update_freeze_count || gdk_surface_is_toplevel_frozen (surface)) { - surface->pending_schedule_update = TRUE; + surface->pending_phases |= GDK_FRAME_CLOCK_PHASE_PAINT; return; } @@ -1319,7 +1319,7 @@ gdk_surface_request_compute_size (GdkSurface *surface) if (surface->update_freeze_count || gdk_surface_is_toplevel_frozen (surface)) { - surface->pending_request_compute_size = TRUE; + surface->pending_phases |= GDK_FRAME_CLOCK_PHASE_COMPUTE_SIZE; return; } @@ -1568,18 +1568,14 @@ gdk_surface_thaw_updates (GdkSurface *surface) if (--surface->update_freeze_count == 0) { - _gdk_frame_clock_inhibit_freeze (surface->frame_clock); + GdkFrameClock *frame_clock = surface->frame_clock; - if (surface->pending_schedule_update) - { - surface->pending_schedule_update = FALSE; - gdk_surface_schedule_update (surface); - } + _gdk_frame_clock_inhibit_freeze (frame_clock); - if (surface->pending_request_compute_size) + if (surface->pending_phases) { - surface->pending_request_compute_size = FALSE; - gdk_surface_request_compute_size (surface); + gdk_frame_clock_request_phase (frame_clock, surface->pending_phases); + surface->pending_phases = 0; } } } diff --git a/gdk/gdksurfaceprivate.h b/gdk/gdksurfaceprivate.h index a6a981dbb8..196e2b9aeb 100644 --- a/gdk/gdksurfaceprivate.h +++ b/gdk/gdksurfaceprivate.h @@ -53,8 +53,7 @@ struct _GdkSurface cairo_region_t *update_area; guint update_freeze_count; - gboolean pending_schedule_update; - gboolean pending_request_compute_size; + GdkFrameClockPhase pending_phases; /* This is the update_area that was in effect when the current expose started. It may be smaller than the expose area if we'e painting more than we have to, but it represents the "true" damage. */ From ecc861bf06e7e3f3f92c9b9f1ae7127a82bad2c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Tue, 24 Nov 2020 22:02:53 +0100 Subject: [PATCH 20/87] Pass the layout signal via GdkSurface to GtkRoot Don't have GtkRoot listen directly to the layout signal on the frame clock, but let it pass through GdkSurface. This will allow GdkSurface to be more involved in the layout phase. --- gdk/gdksurface.c | 46 ++++++++++++++++++++++++++++++++++++++++++ gdk/gdksurface.h | 3 +++ gtk/gtkroot.c | 21 ++++++++++++------- gtk/gtkwidget.c | 2 +- gtk/gtkwidgetprivate.h | 2 ++ 5 files changed, 66 insertions(+), 8 deletions(-) diff --git a/gdk/gdksurface.c b/gdk/gdksurface.c index f5f4a5790d..226a7c7e53 100644 --- a/gdk/gdksurface.c +++ b/gdk/gdksurface.c @@ -1370,6 +1370,45 @@ gdk_surface_process_updates_internal (GdkSurface *surface) g_object_unref (surface); } +static void +gdk_surface_layout_on_clock (GdkFrameClock *clock, + void *data) +{ + GdkSurface *surface = GDK_SURFACE (data); + + g_return_if_fail (GDK_IS_SURFACE (surface)); + + if (GDK_SURFACE_DESTROYED (surface)) + return; + + if (!GDK_SURFACE_IS_MAPPED (surface)) + return; + + if (surface->update_freeze_count) + return; + + g_signal_emit (surface, signals[LAYOUT], 0, surface->width, surface->height); +} + +void +gdk_surface_request_layout (GdkSurface *surface) +{ + GdkFrameClock *frame_clock; + + if (surface->update_freeze_count || + gdk_surface_is_toplevel_frozen (surface)) + { + surface->pending_phases |= GDK_FRAME_CLOCK_PHASE_LAYOUT; + return; + } + + frame_clock = gdk_surface_get_frame_clock (surface); + g_return_if_fail (frame_clock); + + gdk_frame_clock_request_phase (frame_clock, + GDK_FRAME_CLOCK_PHASE_LAYOUT); +} + static void gdk_surface_paint_on_clock (GdkFrameClock *clock, void *data) @@ -2451,6 +2490,10 @@ gdk_surface_set_frame_clock (GdkSurface *surface, "resume-events", G_CALLBACK (gdk_surface_resume_events), surface); + g_signal_connect (G_OBJECT (clock), + "layout", + G_CALLBACK (gdk_surface_layout_on_clock), + surface); g_signal_connect (G_OBJECT (clock), "paint", G_CALLBACK (gdk_surface_paint_on_clock), @@ -2471,6 +2514,9 @@ gdk_surface_set_frame_clock (GdkSurface *surface, g_signal_handlers_disconnect_by_func (G_OBJECT (surface->frame_clock), G_CALLBACK (gdk_surface_resume_events), surface); + g_signal_handlers_disconnect_by_func (G_OBJECT (surface->frame_clock), + G_CALLBACK (gdk_surface_layout_on_clock), + surface); g_signal_handlers_disconnect_by_func (G_OBJECT (surface->frame_clock), G_CALLBACK (gdk_surface_paint_on_clock), surface); diff --git a/gdk/gdksurface.h b/gdk/gdksurface.h index 6b2cfcd03b..4c47fe659b 100644 --- a/gdk/gdksurface.h +++ b/gdk/gdksurface.h @@ -118,6 +118,9 @@ void gdk_surface_beep (GdkSurface *surface); GDK_AVAILABLE_IN_ALL void gdk_surface_queue_render (GdkSurface *surface); +GDK_AVAILABLE_IN_ALL +void gdk_surface_request_layout (GdkSurface *surface); + GDK_AVAILABLE_IN_ALL GdkFrameClock* gdk_surface_get_frame_clock (GdkSurface *surface); diff --git a/gtk/gtkroot.c b/gtk/gtkroot.c index a480173695..6bdf1b74a1 100644 --- a/gtk/gtkroot.c +++ b/gtk/gtkroot.c @@ -195,8 +195,10 @@ gtk_root_after_update_cb (GdkFrameClock *clock, } static void -gtk_root_layout_cb (GdkFrameClock *clock, - GtkRoot *self) +gtk_root_layout_cb (GdkSurface *surface, + int width, + int height, + GtkRoot *self) { GtkWidget *widget = GTK_WIDGET (self); @@ -231,19 +233,22 @@ gtk_root_layout_cb (GdkFrameClock *clock, if (gtk_root_needs_layout (self)) { - gdk_frame_clock_request_phase (clock, GDK_FRAME_CLOCK_PHASE_UPDATE); - gdk_frame_clock_request_phase (clock, GDK_FRAME_CLOCK_PHASE_LAYOUT); + gdk_frame_clock_request_phase (gdk_surface_get_frame_clock (surface), + GDK_FRAME_CLOCK_PHASE_UPDATE); + gdk_surface_request_layout (surface); } } void gtk_root_start_layout (GtkRoot *self) { + GdkSurface *surface; GdkFrameClock *clock; if (!gtk_root_needs_layout (self)) return; + surface = gtk_widget_get_surface (GTK_WIDGET (self)); clock = gtk_widget_get_frame_clock (GTK_WIDGET (self)); if (clock == NULL) return; @@ -260,19 +265,20 @@ gtk_root_start_layout (GtkRoot *self) GINT_TO_POINTER (after_update_handler)); layout_handler = - g_signal_connect (clock, "layout", + g_signal_connect (surface, "layout", G_CALLBACK (gtk_root_layout_cb), self); g_object_set_qdata (G_OBJECT (self), quark_layout_handler, GINT_TO_POINTER (layout_handler)); } gdk_frame_clock_request_phase (clock, GDK_FRAME_CLOCK_PHASE_UPDATE); - gdk_frame_clock_request_phase (clock, GDK_FRAME_CLOCK_PHASE_LAYOUT); + gdk_surface_request_layout (surface); } void gtk_root_stop_layout (GtkRoot *self) { + GdkSurface *surface; GdkFrameClock *clock; guint layout_handler; guint after_update_handler; @@ -287,8 +293,9 @@ gtk_root_stop_layout (GtkRoot *self) if (layout_handler == 0) return; + surface = gtk_widget_get_surface (GTK_WIDGET (self)); clock = gtk_widget_get_frame_clock (GTK_WIDGET (self)); - g_signal_handler_disconnect (clock, layout_handler); + g_signal_handler_disconnect (surface, layout_handler); g_signal_handler_disconnect (clock, after_update_handler); g_object_set_qdata (G_OBJECT (self), quark_layout_handler, NULL); g_object_set_qdata (G_OBJECT (self), quark_after_update_handler, NULL); diff --git a/gtk/gtkwidget.c b/gtk/gtkwidget.c index ab9de00cd2..6d1e3c865d 100644 --- a/gtk/gtkwidget.c +++ b/gtk/gtkwidget.c @@ -3244,7 +3244,7 @@ gtk_widget_remove_surface_transform_changed_callback (GtkWidget *widget, } } -static GdkSurface * +GdkSurface * gtk_widget_get_surface (GtkWidget *widget) { GtkNative *native = gtk_widget_get_native (widget); diff --git a/gtk/gtkwidgetprivate.h b/gtk/gtkwidgetprivate.h index a79ee938da..667df882ce 100644 --- a/gtk/gtkwidgetprivate.h +++ b/gtk/gtkwidgetprivate.h @@ -228,6 +228,8 @@ void gtk_widget_ensure_resize (GtkWidget *widget); void gtk_widget_ensure_allocate (GtkWidget *widget); void _gtk_widget_scale_changed (GtkWidget *widget); +GdkSurface * gtk_widget_get_surface (GtkWidget *widget); + void gtk_widget_render (GtkWidget *widget, GdkSurface *surface, const cairo_region_t *region); From 13931463bd9696036786e251d01910faa3234be5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Tue, 24 Nov 2020 23:16:48 +0100 Subject: [PATCH 21/87] wayland/surface: Compute size on layout Stop using the 'compute-size' phase of the frame clock, use the layout phase instead, now that GTK isn't using the layout phase anymore. --- gdk/gdksurface.c | 5 +++++ gdk/gdksurfaceprivate.h | 1 + gdk/wayland/gdksurface-wayland.c | 10 ++++------ 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/gdk/gdksurface.c b/gdk/gdksurface.c index 226a7c7e53..ae3dc94b66 100644 --- a/gdk/gdksurface.c +++ b/gdk/gdksurface.c @@ -1375,6 +1375,7 @@ gdk_surface_layout_on_clock (GdkFrameClock *clock, void *data) { GdkSurface *surface = GDK_SURFACE (data); + GdkSurfaceClass *class; g_return_if_fail (GDK_IS_SURFACE (surface)); @@ -1387,6 +1388,10 @@ gdk_surface_layout_on_clock (GdkFrameClock *clock, if (surface->update_freeze_count) return; + class = GDK_SURFACE_GET_CLASS (surface); + if (class->compute_size) + class->compute_size (surface); + g_signal_emit (surface, signals[LAYOUT], 0, surface->width, surface->height); } diff --git a/gdk/gdksurfaceprivate.h b/gdk/gdksurfaceprivate.h index 196e2b9aeb..cc4e1a1a35 100644 --- a/gdk/gdksurfaceprivate.h +++ b/gdk/gdksurfaceprivate.h @@ -170,6 +170,7 @@ struct _GdkSurfaceClass gboolean attached, GdkGLContext *share, GError **error); + void (* compute_size) (GdkSurface *surface); }; #define GDK_SURFACE_DESTROYED(d) (((GdkSurface *)(d))->destroyed) diff --git a/gdk/wayland/gdksurface-wayland.c b/gdk/wayland/gdksurface-wayland.c index 6a4ae89dad..c387dd2736 100644 --- a/gdk/wayland/gdksurface-wayland.c +++ b/gdk/wayland/gdksurface-wayland.c @@ -603,8 +603,7 @@ on_frame_clock_before_paint (GdkFrameClock *clock, } static void -on_frame_clock_compute_size (GdkFrameClock *clock, - GdkSurface *surface) +gdk_wayland_surface_compute_size (GdkSurface *surface) { GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface); @@ -794,7 +793,6 @@ _gdk_wayland_display_create_surface (GdkDisplay *display, gdk_wayland_surface_create_surface (surface); g_signal_connect (frame_clock, "before-paint", G_CALLBACK (on_frame_clock_before_paint), surface); - g_signal_connect (frame_clock, "compute-size", G_CALLBACK (on_frame_clock_compute_size), surface); g_signal_connect (frame_clock, "after-paint", G_CALLBACK (on_frame_clock_after_paint), surface); g_object_unref (frame_clock); @@ -1448,7 +1446,7 @@ gdk_wayland_surface_configure_toplevel (GdkSurface *surface) } impl->surface_geometry_dirty = TRUE; - gdk_surface_request_compute_size (surface); + gdk_surface_request_layout (surface); GDK_DISPLAY_NOTE (gdk_surface_get_display (surface), EVENTS, g_message ("configure, surface %p %dx%d,%s%s%s%s", @@ -3314,7 +3312,6 @@ gdk_wayland_surface_destroy (GdkSurface *surface, frame_clock = gdk_surface_get_frame_clock (surface); g_signal_handlers_disconnect_by_func (frame_clock, on_frame_clock_before_paint, surface); - g_signal_handlers_disconnect_by_func (frame_clock, on_frame_clock_compute_size, surface); g_signal_handlers_disconnect_by_func (frame_clock, on_frame_clock_after_paint, surface); display = GDK_WAYLAND_DISPLAY (gdk_surface_get_display (surface)); @@ -4110,6 +4107,7 @@ gdk_wayland_surface_class_init (GdkWaylandSurfaceClass *klass) impl_class->set_opaque_region = gdk_wayland_surface_set_opaque_region; impl_class->set_shadow_width = gdk_wayland_surface_set_shadow_width; impl_class->create_gl_context = gdk_wayland_surface_create_gl_context; + impl_class->compute_size = gdk_wayland_surface_compute_size; } void @@ -4893,7 +4891,7 @@ gdk_wayland_toplevel_present (GdkToplevel *toplevel, if (!pending_configure) { impl->surface_geometry_dirty = TRUE; - gdk_surface_request_compute_size (surface); + gdk_surface_request_layout (surface); } } From 4779e4e488ef3b3d0ab0937e9da518ab8e7f45b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Tue, 24 Nov 2020 23:18:42 +0100 Subject: [PATCH 22/87] gdk/frame-clock: Remove the newly added 'compute-size' phase What was previously done in the layout phase is now done in response to a GdkSurface signal, which means size computation can happen on layout. --- gdk/gdkframeclock.c | 28 ---------------------------- gdk/gdkframeclock.h | 12 +++++------- gdk/gdkframeclockidle.c | 12 ------------ gdk/gdkframeclockprivate.h | 1 - gdk/gdksurface.c | 19 ------------------- 5 files changed, 5 insertions(+), 67 deletions(-) diff --git a/gdk/gdkframeclock.c b/gdk/gdkframeclock.c index 15efa30afe..5e4492744c 100644 --- a/gdk/gdkframeclock.c +++ b/gdk/gdkframeclock.c @@ -78,7 +78,6 @@ enum { FLUSH_EVENTS, BEFORE_PAINT, UPDATE, - COMPUTE_SIZE, LAYOUT, PAINT, AFTER_PAINT, @@ -185,21 +184,6 @@ gdk_frame_clock_class_init (GdkFrameClockClass *klass) NULL, NULL, NULL, G_TYPE_NONE, 0); - /** - * GdkFrameClock::compute-size: - * @clock: the frame clock emitting the signal - * - * This signal is used for computing the size of the underlying - * #GdkSurface. Applications should generally not handle this signal. - */ - signals[COMPUTE_SIZE] = - g_signal_new (g_intern_static_string ("compute-size"), - GDK_TYPE_FRAME_CLOCK, - G_SIGNAL_RUN_LAST, - 0, - NULL, NULL, NULL, - G_TYPE_NONE, 0); - /** * GdkFrameClock::layout: * @clock: the frame clock emitting the signal @@ -698,18 +682,6 @@ _gdk_frame_clock_emit_update (GdkFrameClock *frame_clock) gdk_profiler_end_mark (before, "frameclock update", NULL); } -void -_gdk_frame_clock_emit_compute_size (GdkFrameClock *frame_clock) -{ - gint64 before G_GNUC_UNUSED; - - before = GDK_PROFILER_CURRENT_TIME; - - g_signal_emit (frame_clock, signals[COMPUTE_SIZE], 0); - - gdk_profiler_end_mark (before, "frameclock compute size", NULL); -} - void _gdk_frame_clock_emit_layout (GdkFrameClock *frame_clock) { diff --git a/gdk/gdkframeclock.h b/gdk/gdkframeclock.h index dfe0c23747..f50512c150 100644 --- a/gdk/gdkframeclock.h +++ b/gdk/gdkframeclock.h @@ -50,8 +50,7 @@ typedef struct _GdkFrameClockClass GdkFrameClockClass; * @GDK_FRAME_CLOCK_PHASE_FLUSH_EVENTS: corresponds to GdkFrameClock::flush-events. Should not be handled by applications. * @GDK_FRAME_CLOCK_PHASE_BEFORE_PAINT: corresponds to GdkFrameClock::before-paint. Should not be handled by applications. * @GDK_FRAME_CLOCK_PHASE_UPDATE: corresponds to GdkFrameClock::update. - * @GDK_FRAME_CLOCK_PHASE_COMPUTE_SIZE: corresponds to GdkFrameClock::compute-size. Should not be handled by applications. - * @GDK_FRAME_CLOCK_PHASE_LAYOUT: corresponds to GdkFrameClock::layout. + * @GDK_FRAME_CLOCK_PHASE_LAYOUT: corresponds to GdkFrameClock::layout. Should not be handled by applicatiosn. * @GDK_FRAME_CLOCK_PHASE_PAINT: corresponds to GdkFrameClock::paint. * @GDK_FRAME_CLOCK_PHASE_RESUME_EVENTS: corresponds to GdkFrameClock::resume-events. Should not be handled by applications. * @GDK_FRAME_CLOCK_PHASE_AFTER_PAINT: corresponds to GdkFrameClock::after-paint. Should not be handled by applications. @@ -65,11 +64,10 @@ typedef enum { GDK_FRAME_CLOCK_PHASE_FLUSH_EVENTS = 1 << 0, GDK_FRAME_CLOCK_PHASE_BEFORE_PAINT = 1 << 1, GDK_FRAME_CLOCK_PHASE_UPDATE = 1 << 2, - GDK_FRAME_CLOCK_PHASE_COMPUTE_SIZE = 1 << 3, - GDK_FRAME_CLOCK_PHASE_LAYOUT = 1 << 4, - GDK_FRAME_CLOCK_PHASE_PAINT = 1 << 5, - GDK_FRAME_CLOCK_PHASE_RESUME_EVENTS = 1 << 6, - GDK_FRAME_CLOCK_PHASE_AFTER_PAINT = 1 << 7 + GDK_FRAME_CLOCK_PHASE_LAYOUT = 1 << 3, + GDK_FRAME_CLOCK_PHASE_PAINT = 1 << 4, + GDK_FRAME_CLOCK_PHASE_RESUME_EVENTS = 1 << 5, + GDK_FRAME_CLOCK_PHASE_AFTER_PAINT = 1 << 6 } GdkFrameClockPhase; GDK_AVAILABLE_IN_ALL diff --git a/gdk/gdkframeclockidle.c b/gdk/gdkframeclockidle.c index ac69aba627..4870a110a6 100644 --- a/gdk/gdkframeclockidle.c +++ b/gdk/gdkframeclockidle.c @@ -552,18 +552,6 @@ gdk_frame_clock_paint_idle (void *data) } G_GNUC_FALLTHROUGH; - case GDK_FRAME_CLOCK_PHASE_COMPUTE_SIZE: - if (priv->freeze_count == 0) - { - priv->phase = GDK_FRAME_CLOCK_PHASE_COMPUTE_SIZE; - if ((priv->requested & GDK_FRAME_CLOCK_PHASE_COMPUTE_SIZE) != 0) - { - priv->requested &= ~GDK_FRAME_CLOCK_PHASE_COMPUTE_SIZE; - _gdk_frame_clock_emit_compute_size (clock); - } - } - G_GNUC_FALLTHROUGH; - case GDK_FRAME_CLOCK_PHASE_LAYOUT: if (priv->freeze_count == 0) { diff --git a/gdk/gdkframeclockprivate.h b/gdk/gdkframeclockprivate.h index a68bc85da8..010aa4564f 100644 --- a/gdk/gdkframeclockprivate.h +++ b/gdk/gdkframeclockprivate.h @@ -122,7 +122,6 @@ gboolean _gdk_frame_timings_steal (GdkFrameTimings *timings, void _gdk_frame_clock_emit_flush_events (GdkFrameClock *frame_clock); void _gdk_frame_clock_emit_before_paint (GdkFrameClock *frame_clock); void _gdk_frame_clock_emit_update (GdkFrameClock *frame_clock); -void _gdk_frame_clock_emit_compute_size (GdkFrameClock *frame_clock); void _gdk_frame_clock_emit_layout (GdkFrameClock *frame_clock); void _gdk_frame_clock_emit_paint (GdkFrameClock *frame_clock); void _gdk_frame_clock_emit_after_paint (GdkFrameClock *frame_clock); diff --git a/gdk/gdksurface.c b/gdk/gdksurface.c index ae3dc94b66..05e52dbf7d 100644 --- a/gdk/gdksurface.c +++ b/gdk/gdksurface.c @@ -1311,25 +1311,6 @@ gdk_surface_emit_size_changed (GdkSurface *surface, g_signal_emit (surface, signals[SIZE_CHANGED], 0, width, height); } -void -gdk_surface_request_compute_size (GdkSurface *surface) -{ - GdkFrameClock *frame_clock; - - if (surface->update_freeze_count || - gdk_surface_is_toplevel_frozen (surface)) - { - surface->pending_phases |= GDK_FRAME_CLOCK_PHASE_COMPUTE_SIZE; - return; - } - - frame_clock = gdk_surface_get_frame_clock (surface); - g_return_if_fail (frame_clock); - - gdk_frame_clock_request_phase (frame_clock, - GDK_FRAME_CLOCK_PHASE_COMPUTE_SIZE); -} - static void gdk_surface_process_updates_internal (GdkSurface *surface) { From 70b83c9a70a8d7dbffb8bea63c02f0ffad6b667e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Wed, 25 Nov 2020 11:14:33 +0100 Subject: [PATCH 23/87] gdk/surface: Remove left-over signal enum value The popup-layout-change signal was moved to GdkPopup, but the enum was never removed from GdkSurface. --- gdk/gdksurface.c | 1 - 1 file changed, 1 deletion(-) diff --git a/gdk/gdksurface.c b/gdk/gdksurface.c index 05e52dbf7d..9f6bb03e24 100644 --- a/gdk/gdksurface.c +++ b/gdk/gdksurface.c @@ -76,7 +76,6 @@ */ enum { - POPUP_LAYOUT_CHANGED, SIZE_CHANGED, LAYOUT, RENDER, From efcfd2365279d70345de2bcc79a0c848a9f7c508 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Wed, 25 Nov 2020 11:28:45 +0100 Subject: [PATCH 24/87] wayland/surface: Restructure fields used for the next layout Put them in a anonymous struct, and separate the toplevel specific ones into another anonymous struct inside the first one. Later popup related fields will be added. --- gdk/wayland/gdksurface-wayland.c | 80 ++++++++++++++++++++------------ 1 file changed, 51 insertions(+), 29 deletions(-) diff --git a/gdk/wayland/gdksurface-wayland.c b/gdk/wayland/gdksurface-wayland.c index c387dd2736..e8b635fef0 100644 --- a/gdk/wayland/gdksurface-wayland.c +++ b/gdk/wayland/gdksurface-wayland.c @@ -184,11 +184,15 @@ struct _GdkWaylandSurface GdkToplevelState set_flags; } initial_state; - gboolean configured_size_should_constrain; - gboolean configured_size_is_fixed; - int configured_width; - int configured_height; - gboolean surface_geometry_dirty; + struct { + struct { + gboolean should_constrain; + gboolean size_is_fixed; + } toplevel; + int configured_width; + int configured_height; + gboolean surface_geometry_dirty; + } next_layout; uint32_t last_configure_serial; @@ -301,7 +305,7 @@ static void update_popup_layout_state (GdkSurface *surface, static gboolean gdk_wayland_surface_is_exported (GdkWaylandSurface *impl); -static void configure_surface_geometry (GdkSurface *surface); +static void configure_toplevel_geometry (GdkSurface *surface); static void gdk_wayland_surface_init (GdkWaylandSurface *impl) @@ -602,15 +606,30 @@ on_frame_clock_before_paint (GdkFrameClock *clock, gdk_surface_apply_state_change (surface); } +static void +configure_popup_geometry (GdkSurface *surface) +{ + GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface); + + gdk_wayland_surface_move_resize (surface, + impl->next_layout.popup.x, + impl->next_layout.popup.y, + impl->next_layout.configured_width, + impl->next_layout.configured_height); + g_signal_emit_by_name (surface, "popup-layout"); +} + static void gdk_wayland_surface_compute_size (GdkSurface *surface) { GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface); - if (impl->surface_geometry_dirty) + if (impl->next_layout.surface_geometry_dirty) { - configure_surface_geometry (surface); - impl->surface_geometry_dirty = FALSE; + g_warn_if_fail (GDK_IS_TOPLEVEL (impl)); + configure_toplevel_geometry (surface); + + impl->next_layout.surface_geometry_dirty = FALSE; } } @@ -1286,7 +1305,7 @@ gdk_wayland_surface_create_surface (GdkSurface *surface) } static void -configure_surface_geometry (GdkSurface *surface) +configure_toplevel_geometry (GdkSurface *surface) { GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface); GdkDisplay *display = gdk_surface_get_display (surface); @@ -1332,14 +1351,17 @@ configure_surface_geometry (GdkSurface *surface) impl->margin_bottom = size.margin.bottom; } - if (impl->configured_width > 0 && impl->configured_height > 0) + if (impl->next_layout.configured_width > 0 && + impl->next_layout.configured_height > 0) { int width, height; - width = impl->configured_width + impl->margin_left + impl->margin_right; - height = impl->configured_height + impl->margin_top + impl->margin_bottom; + width = impl->next_layout.configured_width + + impl->margin_left + impl->margin_right; + height = impl->next_layout.configured_height + + impl->margin_top + impl->margin_bottom; - if (impl->configured_size_should_constrain) + if (impl->next_layout.toplevel.should_constrain) { gdk_surface_constrain_size (&impl->geometry_hints, impl->geometry_mask, @@ -1348,11 +1370,11 @@ configure_surface_geometry (GdkSurface *surface) } gdk_wayland_surface_resize (surface, width, height, impl->scale); - if (!impl->configured_size_is_fixed) + if (!impl->next_layout.toplevel.size_is_fixed) { - impl->configured_size_should_constrain = FALSE; - impl->configured_width = 0; - impl->configured_height = 0; + impl->next_layout.toplevel.should_constrain = FALSE; + impl->next_layout.configured_width = 0; + impl->next_layout.configured_height = 0; } } else @@ -1423,29 +1445,29 @@ gdk_wayland_surface_configure_toplevel (GdkSurface *surface) { if (!saved_size) { - impl->configured_size_should_constrain = TRUE; + impl->next_layout.toplevel.should_constrain = TRUE; /* Save size for next time we get 0x0 */ _gdk_wayland_surface_save_size (surface); } else { - impl->configured_size_should_constrain = FALSE; + impl->next_layout.toplevel.should_constrain = FALSE; } - impl->configured_size_is_fixed = fixed_size; - impl->configured_width = width; - impl->configured_height = height; + impl->next_layout.toplevel.size_is_fixed = fixed_size; + impl->next_layout.configured_width = width; + impl->next_layout.configured_height = height; } else { - impl->configured_size_should_constrain = FALSE; - impl->configured_size_is_fixed = FALSE; - impl->configured_width = 0; - impl->configured_height = 0; + impl->next_layout.toplevel.should_constrain = FALSE; + impl->next_layout.toplevel.size_is_fixed = FALSE; + impl->next_layout.configured_width = 0; + impl->next_layout.configured_height = 0; } - impl->surface_geometry_dirty = TRUE; + impl->next_layout.surface_geometry_dirty = TRUE; gdk_surface_request_layout (surface); GDK_DISPLAY_NOTE (gdk_surface_get_display (surface), EVENTS, @@ -4890,7 +4912,7 @@ gdk_wayland_toplevel_present (GdkToplevel *toplevel, if (!pending_configure) { - impl->surface_geometry_dirty = TRUE; + impl->next_layout.surface_geometry_dirty = TRUE; gdk_surface_request_layout (surface); } } From d38f81999e2e277e29573a855120873803d26125 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Wed, 25 Nov 2020 11:48:08 +0100 Subject: [PATCH 25/87] wayland: Communicate popup layout changes via GdkSurface::layout By moving popup layout emission to the layout phase, the current GdkPopup::poup-layout-changed signal has no value on its own as it'd be ignored by GtkPopover. Make the Wayland backend communicate the popup layout changes via the common signal; but leave the rest intact until other backends catch up. --- gdk/gdkpopup.c | 17 ++++++++------ gdk/wayland/gdksurface-wayland.c | 39 +++++++++++++------------------- gtk/gtkpopover.c | 21 +++++++++++++---- 3 files changed, 42 insertions(+), 35 deletions(-) diff --git a/gdk/gdkpopup.c b/gdk/gdkpopup.c index 375a0fcb92..bcd8c8ed29 100644 --- a/gdk/gdkpopup.c +++ b/gdk/gdkpopup.c @@ -133,13 +133,16 @@ gdk_popup_default_init (GdkPopupInterface *iface) * If the popup was previously now showing, it will be showed, * otherwise it will change position according to @layout. * - * After calling this function, the result of the layout can be queried - * using gdk_popup_get_position_x(), gdk_popup_get_position_y(), - * gdk_surface_get_width(), gdk_surface_get_height(), - * gdk_popup_get_rect_anchor() and gdk_popup_get_surface_anchor(). + * After calling this function, the result should be handled in response + * to the GdkSurface::layout signal being emitted. The resulting popup + * position can be queried using gdk_popup_get_position_x(), + * gdk_popup_get_position_y(), and the resulting size will be sent as + * parameters in the layout signal. Use gdk_popup_get_rect_anchor() and + * gdk_popup_get_surface_anchor() to get the resulting anchors. * * Presenting may have fail, for example if it was immediately - * hidden if the @popup was set to autohide. + * hidden if the @popup was set to autohide. If presenting failed, + * GdkSurface::layout will not me emitted. * * Returns: %FALSE if it failed to be presented, otherwise %TRUE. */ @@ -164,7 +167,7 @@ gdk_popup_present (GdkPopup *popup, * Gets the current popup surface anchor. * * The value returned may change after calling gdk_popup_present(), - * or after the "popup-layout-changed" is emitted. + * or after the "GdkSurface::layout" signal is emitted. * * Returns: the current surface anchor value of @popup */ @@ -183,7 +186,7 @@ gdk_popup_get_surface_anchor (GdkPopup *popup) * Gets the current popup rectangle anchor. * * The value returned may change after calling gdk_popup_present(), - * or after the "popup-layout-changed" is emitted. + * or after the "GdkSurface::layout" signal is emitted. * * Returns: the current rectangle anchor value of @popup */ diff --git a/gdk/wayland/gdksurface-wayland.c b/gdk/wayland/gdksurface-wayland.c index e8b635fef0..04a7643b46 100644 --- a/gdk/wayland/gdksurface-wayland.c +++ b/gdk/wayland/gdksurface-wayland.c @@ -189,6 +189,10 @@ struct _GdkWaylandSurface gboolean should_constrain; gboolean size_is_fixed; } toplevel; + struct { + int x; + int y; + } popup; int configured_width; int configured_height; gboolean surface_geometry_dirty; @@ -616,7 +620,6 @@ configure_popup_geometry (GdkSurface *surface) impl->next_layout.popup.y, impl->next_layout.configured_width, impl->next_layout.configured_height); - g_signal_emit_by_name (surface, "popup-layout"); } static void @@ -626,8 +629,10 @@ gdk_wayland_surface_compute_size (GdkSurface *surface) if (impl->next_layout.surface_geometry_dirty) { - g_warn_if_fail (GDK_IS_TOPLEVEL (impl)); - configure_toplevel_geometry (surface); + if (GDK_IS_TOPLEVEL (impl)) + configure_toplevel_geometry (surface); + else if (GDK_IS_POPUP (impl)) + configure_popup_geometry (surface); impl->next_layout.surface_geometry_dirty = FALSE; } @@ -1538,18 +1543,20 @@ gdk_wayland_surface_configure_popup (GdkSurface *surface) width = impl->pending.popup.width; height = impl->pending.popup.height; - gdk_wayland_surface_resize (surface, width, height, impl->scale); + x += surface->parent->shadow_left; + y += surface->parent->shadow_top; update_popup_layout_state (surface, x, y, width, height, impl->popup.layout); - if (!impl->pending.popup.has_repositioned_token && - !impl->pending.is_initial_configure) - g_signal_emit_by_name (surface, "popup-layout-changed"); - - gdk_surface_invalidate_rect (surface, NULL); + impl->next_layout.popup.x = x; + impl->next_layout.popup.y = y; + impl->next_layout.configured_width = width; + impl->next_layout.configured_height = height; + impl->next_layout.surface_geometry_dirty = TRUE; + gdk_surface_request_layout (surface); } static void @@ -2316,26 +2323,12 @@ update_popup_layout_state (GdkSurface *surface, int height, GdkPopupLayout *layout) { - int surface_x, surface_y; - int surface_width, surface_height; GdkRectangle best_rect; GdkRectangle flipped_rect; GdkGravity rect_anchor; GdkGravity surface_anchor; GdkAnchorHints anchor_hints; - x += surface->parent->shadow_left; - y += surface->parent->shadow_top; - - surface_x = x; - surface_y = y; - surface_width = width + surface->shadow_left + surface->shadow_right; - surface_height = height + surface->shadow_top + surface->shadow_bottom; - - gdk_wayland_surface_move_resize (surface, - surface_x, surface_y, - surface_width, surface_height); - rect_anchor = gdk_popup_layout_get_rect_anchor (layout); surface_anchor = gdk_popup_layout_get_surface_anchor (layout); anchor_hints = gdk_popup_layout_get_anchor_hints (layout); diff --git a/gtk/gtkpopover.c b/gtk/gtkpopover.c index 504dcd6cc1..252797599c 100644 --- a/gtk/gtkpopover.c +++ b/gtk/gtkpopover.c @@ -419,11 +419,6 @@ update_popover_layout (GtkPopover *popover, g_clear_pointer (&priv->arrow_render_node, gsk_render_node_unref); } - gtk_widget_allocate (GTK_WIDGET (popover), - gdk_surface_get_width (priv->surface), - gdk_surface_get_height (priv->surface), - -1, NULL); - gtk_widget_queue_draw (GTK_WIDGET (popover)); } @@ -771,6 +766,20 @@ popup_layout_changed (GdkSurface *surface, update_popover_layout (popover, gdk_popup_layout_ref (priv->layout)); } +static void +surface_layout (GdkSurface *surface, + int width, + int height, + GtkWidget *widget) +{ + GtkPopover *popover = GTK_POPOVER (widget); + GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover); + + update_popover_layout (popover, gdk_popup_layout_ref (priv->layout)); + if (_gtk_widget_get_alloc_needed (widget)) + gtk_widget_allocate (widget, width, height, -1, NULL); +} + static void gtk_popover_activate_default (GtkPopover *popover) { @@ -891,6 +900,7 @@ gtk_popover_realize (GtkWidget *widget) g_signal_connect (priv->surface, "render", G_CALLBACK (surface_render), widget); g_signal_connect (priv->surface, "event", G_CALLBACK (surface_event), widget); g_signal_connect (priv->surface, "popup-layout-changed", G_CALLBACK (popup_layout_changed), widget); + g_signal_connect (priv->surface, "layout", G_CALLBACK (surface_layout), widget); GTK_WIDGET_CLASS (gtk_popover_parent_class)->realize (widget); @@ -913,6 +923,7 @@ gtk_popover_unrealize (GtkWidget *widget) g_signal_handlers_disconnect_by_func (priv->surface, surface_render, widget); g_signal_handlers_disconnect_by_func (priv->surface, surface_event, widget); g_signal_handlers_disconnect_by_func (priv->surface, popup_layout_changed, widget); + g_signal_handlers_disconnect_by_func (priv->surface, surface_layout, widget); gdk_surface_set_widget (priv->surface, NULL); gdk_surface_destroy (priv->surface); g_clear_object (&priv->surface); From 3b140a05a441d89482896fe88f381a2c5088e41d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Wed, 25 Nov 2020 15:02:26 +0100 Subject: [PATCH 26/87] gtk/dragicon: Don't show until child is set Showing before the child would result in bogus gdk_drag_surface_present() with an "empty" (1x1) size. This can easily be avoided by postponing showing until there is anything to show. --- gtk/gtkdragicon.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/gtk/gtkdragicon.c b/gtk/gtkdragicon.c index 2348674951..e239090011 100644 --- a/gtk/gtkdragicon.c +++ b/gtk/gtkdragicon.c @@ -414,7 +414,8 @@ gtk_drag_icon_get_for_drag (GdkDrag *drag) g_object_set_qdata_full (G_OBJECT (drag), drag_icon_quark, g_object_ref_sink (self), g_object_unref); - gtk_widget_show (self); + if (GTK_DRAG_ICON (self)->child != NULL) + gtk_widget_show (self); } return self; @@ -472,7 +473,10 @@ gtk_drag_icon_set_child (GtkDragIcon *self, self->child = child; if (self->child) - gtk_widget_set_parent (self->child, GTK_WIDGET (self)); + { + gtk_widget_set_parent (self->child, GTK_WIDGET (self)); + gtk_widget_show (GTK_WIDGET (self)); + } g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_CHILD]); } From ecd40fa2659f039fc979b4488bedf186f3290358 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Wed, 25 Nov 2020 15:06:09 +0100 Subject: [PATCH 27/87] wayland: Layout drag icon from GdkSurface::layout --- gdk/wayland/gdksurface-wayland.c | 25 ++++++++++++++++++++++++- gtk/gtkdragicon.c | 20 ++++++++++++-------- 2 files changed, 36 insertions(+), 9 deletions(-) diff --git a/gdk/wayland/gdksurface-wayland.c b/gdk/wayland/gdksurface-wayland.c index 04a7643b46..8b16669213 100644 --- a/gdk/wayland/gdksurface-wayland.c +++ b/gdk/wayland/gdksurface-wayland.c @@ -283,6 +283,11 @@ static void gdk_wayland_surface_maybe_resize (GdkSurface *surface, int height, int scale); +static void gdk_wayland_surface_resize (GdkSurface *surface, + int width, + int height, + int scale); + static void gdk_wayland_surface_configure (GdkSurface *surface); static void maybe_set_gtk_surface_dbus_properties (GdkWaylandSurface *impl); @@ -622,6 +627,17 @@ configure_popup_geometry (GdkSurface *surface) impl->next_layout.configured_height); } +static void +configure_drag_surface_geometry (GdkSurface *surface) +{ + GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface); + + gdk_wayland_surface_resize (surface, + impl->next_layout.configured_width, + impl->next_layout.configured_height, + impl->scale); +} + static void gdk_wayland_surface_compute_size (GdkSurface *surface) { @@ -633,6 +649,8 @@ gdk_wayland_surface_compute_size (GdkSurface *surface) configure_toplevel_geometry (surface); else if (GDK_IS_POPUP (impl)) configure_popup_geometry (surface); + else if (GDK_IS_DRAG_SURFACE (impl)) + configure_drag_surface_geometry (surface); impl->next_layout.surface_geometry_dirty = FALSE; } @@ -5041,8 +5059,13 @@ gdk_wayland_drag_surface_present (GdkDragSurface *drag_surface, GdkSurface *surface = GDK_SURFACE (drag_surface); GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface); - gdk_wayland_surface_resize (surface, width, height, impl->scale); gdk_wayland_surface_show (surface, FALSE); + + impl->next_layout.configured_width = width; + impl->next_layout.configured_height = height; + impl->next_layout.surface_geometry_dirty = TRUE; + gdk_surface_request_layout (surface); + maybe_notify_mapped (surface); return TRUE; diff --git a/gtk/gtkdragicon.c b/gtk/gtkdragicon.c index e239090011..dfcb029cc9 100644 --- a/gtk/gtkdragicon.c +++ b/gtk/gtkdragicon.c @@ -155,14 +155,7 @@ gtk_drag_icon_native_check_resize (GtkNative *native) if (!_gtk_widget_get_alloc_needed (widget)) gtk_widget_ensure_allocate (widget); else if (gtk_widget_get_visible (widget)) - { - gtk_drag_icon_move_resize (icon); - if (icon->surface) - gtk_widget_allocate (widget, - gdk_surface_get_width (icon->surface), - gdk_surface_get_height (icon->surface), - -1, NULL); - } + gtk_drag_icon_move_resize (icon); } static void @@ -174,6 +167,15 @@ gtk_drag_icon_native_init (GtkNativeInterface *iface) iface->check_resize = gtk_drag_icon_native_check_resize; } +static void +surface_layout (GdkSurface *surface, + int width, + int height, + GtkWidget *widget) +{ + gtk_widget_allocate (widget, width, height, -1, NULL); +} + static gboolean surface_render (GdkSurface *surface, cairo_region_t *region, @@ -192,6 +194,7 @@ gtk_drag_icon_realize (GtkWidget *widget) gdk_surface_set_widget (icon->surface, widget); + g_signal_connect (icon->surface, "layout", G_CALLBACK (surface_layout), widget); g_signal_connect (icon->surface, "render", G_CALLBACK (surface_render), widget); GTK_WIDGET_CLASS (gtk_drag_icon_parent_class)->realize (widget); @@ -211,6 +214,7 @@ gtk_drag_icon_unrealize (GtkWidget *widget) if (icon->surface) { + g_signal_handlers_disconnect_by_func (icon->surface, surface_layout, widget); g_signal_handlers_disconnect_by_func (icon->surface, surface_render, widget); gdk_surface_set_widget (icon->surface, NULL); } From 8c014e63af72b2dede62afc22bfd5c6951a7d42b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Tue, 1 Dec 2020 11:10:59 +0100 Subject: [PATCH 28/87] x11: Remove handling of 'substructure' events Reading the comment, it seems to be related being a window manager decoration utility; this is not something GTK4 aims to handle, just drop support for this. --- gdk/gdkdeviceprivate.h | 11 ++--- gdk/win32/gdkevents-win32.c | 1 - gdk/x11/gdkdisplay-x11.c | 94 +++++++++++++++---------------------- 3 files changed, 44 insertions(+), 62 deletions(-) diff --git a/gdk/gdkdeviceprivate.h b/gdk/gdkdeviceprivate.h index 79d24378a0..a4cfffc28b 100644 --- a/gdk/gdkdeviceprivate.h +++ b/gdk/gdkdeviceprivate.h @@ -54,12 +54,11 @@ typedef enum GDK_PROPERTY_CHANGE_MASK = 1 << 16, GDK_PROXIMITY_IN_MASK = 1 << 18, GDK_PROXIMITY_OUT_MASK = 1 << 19, - GDK_SUBSTRUCTURE_MASK = 1 << 20, - GDK_SCROLL_MASK = 1 << 21, - GDK_TOUCH_MASK = 1 << 22, - GDK_SMOOTH_SCROLL_MASK = 1 << 23, - GDK_TOUCHPAD_GESTURE_MASK = 1 << 24, - GDK_TABLET_PAD_MASK = 1 << 25, + GDK_SCROLL_MASK = 1 << 20, + GDK_TOUCH_MASK = 1 << 21, + GDK_SMOOTH_SCROLL_MASK = 1 << 22, + GDK_TOUCHPAD_GESTURE_MASK = 1 << 23, + GDK_TABLET_PAD_MASK = 1 << 24, GDK_ALL_EVENTS_MASK = 0x3FFFFFE } GdkEventMask; diff --git a/gdk/win32/gdkevents-win32.c b/gdk/win32/gdkevents-win32.c index b7488fbc1e..32e319f040 100644 --- a/gdk/win32/gdkevents-win32.c +++ b/gdk/win32/gdkevents-win32.c @@ -562,7 +562,6 @@ event_mask_string (GdkEventMask mask) BIT (VISIBILITY_NOTIFY); BIT (PROXIMITY_IN); BIT (PROXIMITY_OUT); - BIT (SUBSTRUCTURE); BIT (SCROLL); #undef BIT diff --git a/gdk/x11/gdkdisplay-x11.c b/gdk/x11/gdkdisplay-x11.c index b6a223d914..0df79d289b 100644 --- a/gdk/x11/gdkdisplay-x11.c +++ b/gdk/x11/gdkdisplay-x11.c @@ -620,7 +620,6 @@ gdk_x11_display_translate_event (GdkEventTranslator *translator, { Window xwindow; GdkSurface *surface; - gboolean is_substructure; GdkX11Surface *surface_impl = NULL; GdkX11Screen *x11_screen = NULL; GdkToplevelX11 *toplevel = NULL; @@ -629,18 +628,9 @@ gdk_x11_display_translate_event (GdkEventTranslator *translator, event = NULL; - /* Find the GdkSurface that this event relates to. If that's - * not the same as the surface that the event was sent to, - * we are getting an event from SubstructureNotifyMask. - * We ignore such events for internal operation, but we - * need to report them to the application because of - * GDK_SUBSTRUCTURE_MASK (which should be removed at next - * opportunity.) The most likely reason for getting these - * events is when we are used in the Metacity or Mutter - * window managers. - */ xwindow = get_event_xwindow (xevent); - is_substructure = xwindow != xevent->xany.window; + if (xwindow != xevent->xany.window) + return NULL; surface = gdk_x11_surface_lookup_for_display (display, xwindow); if (surface) @@ -664,7 +654,7 @@ gdk_x11_display_translate_event (GdkEventTranslator *translator, goto done; } - if (xevent->type == DestroyNotify && !is_substructure) + if (xevent->type == DestroyNotify) { x11_screen = GDK_X11_DISPLAY (display)->screen; @@ -793,14 +783,11 @@ gdk_x11_display_translate_event (GdkEventTranslator *translator, g_message ("destroy notify:\twindow: %ld", xevent->xdestroywindow.window)); - if (!is_substructure) - { - if (surface) - event = gdk_delete_event_new (surface); + if (surface) + event = gdk_delete_event_new (surface); - if (surface && GDK_SURFACE_XID (surface) != x11_screen->xroot_window) - gdk_surface_destroy_notify (surface); - } + if (surface && GDK_SURFACE_XID (surface) != x11_screen->xroot_window) + gdk_surface_destroy_notify (surface); break; @@ -809,7 +796,7 @@ gdk_x11_display_translate_event (GdkEventTranslator *translator, g_message ("unmap notify:\t\twindow: %ld", xevent->xmap.window)); - if (surface && !is_substructure) + if (surface) { /* If the WM supports the _NET_WM_STATE_HIDDEN hint, we do not want to * interpret UnmapNotify events as implying iconic state. @@ -852,7 +839,7 @@ gdk_x11_display_translate_event (GdkEventTranslator *translator, g_message ("map notify:\t\twindow: %ld", xevent->xmap.window)); - if (surface && !is_substructure) + if (surface) { /* Unset minimized if it was set */ if (surface->state & GDK_TOPLEVEL_STATE_MINIMIZED) @@ -902,7 +889,7 @@ gdk_x11_display_translate_event (GdkEventTranslator *translator, } #ifdef HAVE_XSYNC - if (!is_substructure && toplevel && display_x11->use_sync && toplevel->pending_counter_value != 0) + if (toplevel && display_x11->use_sync && toplevel->pending_counter_value != 0) { toplevel->configure_counter_value = toplevel->pending_counter_value; toplevel->configure_counter_value_is_extended = toplevel->pending_counter_value_is_extended; @@ -916,6 +903,7 @@ gdk_x11_display_translate_event (GdkEventTranslator *translator, int x, y; int c_w = (xevent->xconfigure.width + surface_impl->surface_scale - 1) / surface_impl->surface_scale; int c_h = (xevent->xconfigure.height + surface_impl->surface_scale - 1) / surface_impl->surface_scale; + int new_abs_x, new_abs_y; event = gdk_configure_event_new (surface, c_w, c_h); @@ -946,47 +934,43 @@ gdk_x11_display_translate_event (GdkEventTranslator *translator, x = xevent->xconfigure.x / surface_impl->surface_scale; y = xevent->xconfigure.y / surface_impl->surface_scale; } - if (!is_substructure) - { - int new_abs_x, new_abs_y; - new_abs_x = x; - new_abs_y = y; + new_abs_x = x; + new_abs_y = y; - surface_impl->abs_x = new_abs_x; - surface_impl->abs_y = new_abs_y; + surface_impl->abs_x = new_abs_x; + surface_impl->abs_y = new_abs_y; - if (surface->parent) - { - GdkX11Surface *parent_impl = - GDK_X11_SURFACE (surface->parent); + if (surface->parent) + { + GdkX11Surface *parent_impl = + GDK_X11_SURFACE (surface->parent); - surface->x = new_abs_x - parent_impl->abs_x; - surface->y = new_abs_y - parent_impl->abs_y; - } + surface->x = new_abs_x - parent_impl->abs_x; + surface->y = new_abs_y - parent_impl->abs_y; + } - if (surface_impl->unscaled_width != xevent->xconfigure.width || - surface_impl->unscaled_height != xevent->xconfigure.height) - { - surface_impl->unscaled_width = xevent->xconfigure.width; - surface_impl->unscaled_height = xevent->xconfigure.height; - gdk_configure_event_get_size (event, &surface->width, &surface->height); + if (surface_impl->unscaled_width != xevent->xconfigure.width || + surface_impl->unscaled_height != xevent->xconfigure.height) + { + surface_impl->unscaled_width = xevent->xconfigure.width; + surface_impl->unscaled_height = xevent->xconfigure.height; + gdk_configure_event_get_size (event, &surface->width, &surface->height); - _gdk_surface_update_size (surface); - _gdk_x11_surface_update_size (surface_impl); - } + _gdk_surface_update_size (surface); + _gdk_x11_surface_update_size (surface_impl); + } - if (surface->resize_count >= 1) - { - surface->resize_count -= 1; + if (surface->resize_count >= 1) + { + surface->resize_count -= 1; - if (surface->resize_count == 0) - _gdk_x11_moveresize_configure_done (display, surface); - } + if (surface->resize_count == 0) + _gdk_x11_moveresize_configure_done (display, surface); + } - gdk_x11_surface_update_popups (surface); - gdk_x11_surface_enter_leave_monitors (surface); - } + gdk_x11_surface_update_popups (surface); + gdk_x11_surface_enter_leave_monitors (surface); } break; From 880ceebae41c8b2be646b8a70f4ca680a262da63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Wed, 2 Dec 2020 09:12:01 +0100 Subject: [PATCH 29/87] gdk/surface: Make backends aware of when layout is requested --- gdk/gdksurface.c | 5 +++++ gdk/gdksurfaceprivate.h | 1 + 2 files changed, 6 insertions(+) diff --git a/gdk/gdksurface.c b/gdk/gdksurface.c index 9f6bb03e24..a8f93170ec 100644 --- a/gdk/gdksurface.c +++ b/gdk/gdksurface.c @@ -1378,8 +1378,13 @@ gdk_surface_layout_on_clock (GdkFrameClock *clock, void gdk_surface_request_layout (GdkSurface *surface) { + GdkSurfaceClass *class; GdkFrameClock *frame_clock; + class = GDK_SURFACE_GET_CLASS (surface); + if (class->request_layout) + class->request_layout (surface); + if (surface->update_freeze_count || gdk_surface_is_toplevel_frozen (surface)) { diff --git a/gdk/gdksurfaceprivate.h b/gdk/gdksurfaceprivate.h index cc4e1a1a35..6a4a820faa 100644 --- a/gdk/gdksurfaceprivate.h +++ b/gdk/gdksurfaceprivate.h @@ -170,6 +170,7 @@ struct _GdkSurfaceClass gboolean attached, GdkGLContext *share, GError **error); + void (* request_layout) (GdkSurface *surface); void (* compute_size) (GdkSurface *surface); }; From e0f13ecae7a9ed42880b9e87df532913612754d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Wed, 2 Dec 2020 09:39:48 +0100 Subject: [PATCH 30/87] gdk/surface: Try to reschedule pending phase until dispatched If a surface scheduled a relayout, got frozen, and a layout phase happened, then got unfrozen, it wouldn't see it's layout being requested; avoid this race by remembering the pending phases until they actually happened. --- gdk/gdksurface.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/gdk/gdksurface.c b/gdk/gdksurface.c index a8f93170ec..d0cdcc33f2 100644 --- a/gdk/gdksurface.c +++ b/gdk/gdksurface.c @@ -1368,6 +1368,8 @@ gdk_surface_layout_on_clock (GdkFrameClock *clock, if (surface->update_freeze_count) return; + surface->pending_phases &= ~GDK_FRAME_CLOCK_PHASE_LAYOUT; + class = GDK_SURFACE_GET_CLASS (surface); if (class->compute_size) class->compute_size (surface); @@ -1420,6 +1422,7 @@ gdk_surface_paint_on_clock (GdkFrameClock *clock, * do the update later when idle instead. */ !surface->in_update) { + surface->pending_phases &= ~GDK_FRAME_CLOCK_PHASE_PAINT; gdk_surface_process_updates_internal (surface); gdk_surface_remove_update_surface (surface); } @@ -1602,10 +1605,7 @@ gdk_surface_thaw_updates (GdkSurface *surface) _gdk_frame_clock_inhibit_freeze (frame_clock); if (surface->pending_phases) - { - gdk_frame_clock_request_phase (frame_clock, surface->pending_phases); - surface->pending_phases = 0; - } + gdk_frame_clock_request_phase (frame_clock, surface->pending_phases); } } From 65ad9d6d96710c60e23f858373d7fc17488d365e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Wed, 2 Dec 2020 09:45:31 +0100 Subject: [PATCH 31/87] gdk/x11: Flush layout changes to the frame clack dispatch This follows the trail of the Wayland backend in that GdkSurface changes happen during the layout phase, and that a GDK_CONFIGURE no longer being used to communicate the size changes of a surface; this now also uses the layout signal on the GdkSurface. --- gdk/x11/gdkdisplay-x11.c | 28 +++++-- gdk/x11/gdksurface-x11.c | 168 ++++++++++++++++++++++++++++++++------- gdk/x11/gdksurface-x11.h | 13 +++ 3 files changed, 175 insertions(+), 34 deletions(-) diff --git a/gdk/x11/gdkdisplay-x11.c b/gdk/x11/gdkdisplay-x11.c index 0df79d289b..692f85230c 100644 --- a/gdk/x11/gdkdisplay-x11.c +++ b/gdk/x11/gdkdisplay-x11.c @@ -901,11 +901,16 @@ gdk_x11_display_translate_event (GdkEventTranslator *translator, xevent->xconfigure.event == xevent->xconfigure.window) { int x, y; - int c_w = (xevent->xconfigure.width + surface_impl->surface_scale - 1) / surface_impl->surface_scale; - int c_h = (xevent->xconfigure.height + surface_impl->surface_scale - 1) / surface_impl->surface_scale; + int configured_width; + int configured_height; int new_abs_x, new_abs_y; - event = gdk_configure_event_new (surface, c_w, c_h); + configured_width = + (xevent->xconfigure.width + surface_impl->surface_scale - 1) / + surface_impl->surface_scale; + configured_height = + (xevent->xconfigure.height + surface_impl->surface_scale - 1) / + surface_impl->surface_scale; if (!xevent->xconfigure.send_event && !xevent->xconfigure.override_redirect && @@ -915,6 +920,16 @@ gdk_x11_display_translate_event (GdkEventTranslator *translator, int ty = 0; Window child_window = 0; + if (surface_impl->pending_configure_events == 1) + { + surface_impl->pending_configure_events = 0; + gdk_surface_thaw_updates (surface); + } + else if (surface_impl->pending_configure_events > 1) + { + surface_impl->pending_configure_events--; + } + x = y = 0; gdk_x11_display_error_trap_push (display); if (XTranslateCoordinates (GDK_SURFACE_XDISPLAY (surface), @@ -955,10 +970,11 @@ gdk_x11_display_translate_event (GdkEventTranslator *translator, { surface_impl->unscaled_width = xevent->xconfigure.width; surface_impl->unscaled_height = xevent->xconfigure.height; - gdk_configure_event_get_size (event, &surface->width, &surface->height); - _gdk_surface_update_size (surface); - _gdk_x11_surface_update_size (surface_impl); + surface_impl->next_layout.configured_width = configured_width; + surface_impl->next_layout.configured_height = configured_height; + surface_impl->next_layout.surface_geometry_dirty = TRUE; + gdk_surface_request_layout (surface); } if (surface->resize_count >= 1) diff --git a/gdk/x11/gdksurface-x11.c b/gdk/x11/gdksurface-x11.c index c4b14e11e3..a207c8964b 100644 --- a/gdk/x11/gdksurface-x11.c +++ b/gdk/x11/gdksurface-x11.c @@ -192,6 +192,112 @@ gdk_x11_surface_get_unscaled_size (GdkSurface *surface, *unscaled_height = impl->unscaled_height; } +static void +update_shadow_size (GdkSurface *surface, + int shadow_left, + int shadow_right, + int shadow_top, + int shadow_bottom) +{ + GdkX11Surface *impl = GDK_X11_SURFACE (surface); + Atom frame_extents; + gulong data[4]; + + if (impl->shadow_left == shadow_left && + impl->shadow_right == shadow_right && + impl->shadow_top == shadow_top && + impl->shadow_bottom == shadow_bottom) + return; + + impl->shadow_left = shadow_left; + impl->shadow_right = shadow_right; + impl->shadow_top = shadow_top; + impl->shadow_bottom = shadow_bottom; + + data[0] = shadow_left * impl->surface_scale; + data[1] = shadow_right * impl->surface_scale; + data[2] = shadow_top * impl->surface_scale; + data[3] = shadow_bottom * impl->surface_scale; + + frame_extents = gdk_x11_get_xatom_by_name_for_display (gdk_surface_get_display (surface), + "_GTK_FRAME_EXTENTS"); + XChangeProperty (GDK_SURFACE_XDISPLAY (surface), + GDK_SURFACE_XID (surface), + frame_extents, XA_CARDINAL, + 32, PropModeReplace, + (guchar *) &data, 4); +} + +static void +gdk_x11_surface_request_layout (GdkSurface *surface) +{ + GdkX11Surface *impl = GDK_X11_SURFACE (surface); + + impl->next_layout.surface_geometry_dirty = TRUE; +} + +static void +gdk_x11_surface_compute_size (GdkSurface *surface) +{ + GdkX11Surface *impl = GDK_X11_SURFACE (surface); + + if (GDK_IS_TOPLEVEL (surface)) + { + if (impl->next_layout.surface_geometry_dirty) + { + GdkDisplay *display = gdk_surface_get_display (surface); + GdkMonitor *monitor; + GdkToplevelSize size; + int bounds_width, bounds_height; + + 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 (GDK_TOPLEVEL (surface), &size); + + if (size.margin.is_valid) + { + update_shadow_size (surface, + size.margin.left, + size.margin.right, + size.margin.top, + size.margin.bottom); + } + + surface->width = impl->next_layout.configured_width; + surface->height = impl->next_layout.configured_height; + + _gdk_surface_update_size (surface); + _gdk_x11_surface_update_size (impl); + + impl->next_layout.surface_geometry_dirty = FALSE; + } + } + else + { + surface->width = impl->next_layout.configured_width; + surface->height = impl->next_layout.configured_height; + + _gdk_surface_update_size (surface); + _gdk_x11_surface_update_size (impl); + + impl->next_layout.surface_geometry_dirty = FALSE; + } +} + gboolean gdk_x11_surface_supports_edge_constraints (GdkSurface *surface) { @@ -1424,6 +1530,9 @@ x11_surface_move (GdkSurface *surface, surface->x = x; surface->y = y; } + + impl->next_layout.surface_geometry_dirty = TRUE; + gdk_surface_request_layout (surface); } } @@ -1450,10 +1559,10 @@ x11_surface_resize (GdkSurface *surface, { impl->unscaled_width = width * impl->surface_scale; impl->unscaled_height = height * impl->surface_scale; - surface->width = width; - surface->height = height; - _gdk_surface_update_size (surface); - _gdk_x11_surface_update_size (GDK_X11_SURFACE (surface)); + impl->next_layout.configured_width = width; + impl->next_layout.configured_height = height; + impl->next_layout.surface_geometry_dirty = TRUE; + gdk_surface_request_layout (surface); } else { @@ -1491,10 +1600,10 @@ x11_surface_move_resize (GdkSurface *surface, impl->unscaled_width = width * impl->surface_scale; impl->unscaled_height = height * impl->surface_scale; - surface->width = width; - surface->height = height; - - _gdk_x11_surface_update_size (GDK_X11_SURFACE (surface)); + impl->next_layout.configured_width = width; + impl->next_layout.configured_height = height; + impl->next_layout.surface_geometry_dirty = TRUE; + gdk_surface_request_layout (surface); if (surface->parent) { @@ -2822,22 +2931,6 @@ gdk_x11_surface_set_shadow_width (GdkSurface *surface, int top, int bottom) { - GdkX11Surface *impl = GDK_X11_SURFACE (surface); - Atom frame_extents; - gulong data[4] = { - left * impl->surface_scale, - right * impl->surface_scale, - top * impl->surface_scale, - bottom * impl->surface_scale - }; - - frame_extents = gdk_x11_get_xatom_by_name_for_display (gdk_surface_get_display (surface), - "_GTK_FRAME_EXTENTS"); - XChangeProperty (GDK_SURFACE_XDISPLAY (surface), - GDK_SURFACE_XID (surface), - frame_extents, XA_CARDINAL, - 32, PropModeReplace, - (guchar *) &data, 4); } /** @@ -4568,6 +4661,8 @@ gdk_x11_surface_class_init (GdkX11SurfaceClass *klass) impl_class->set_shadow_width = gdk_x11_surface_set_shadow_width; impl_class->create_gl_context = gdk_x11_surface_create_gl_context; impl_class->get_unscaled_size = gdk_x11_surface_get_unscaled_size; + impl_class->request_layout = gdk_x11_surface_request_layout; + impl_class->compute_size = gdk_x11_surface_compute_size; } #define LAST_PROP 1 @@ -4854,6 +4949,7 @@ gdk_x11_toplevel_present (GdkToplevel *toplevel, GdkToplevelLayout *layout) { GdkSurface *surface = GDK_SURFACE (toplevel); + GdkX11Surface *impl = GDK_X11_SURFACE (surface); GdkDisplay *display = gdk_surface_get_display (surface); GdkMonitor *monitor; GdkToplevelSize size; @@ -4863,6 +4959,11 @@ gdk_x11_toplevel_present (GdkToplevel *toplevel, GdkSurfaceHints mask; gboolean was_mapped; + if (surface->destroyed) + return; + + was_mapped = GDK_SURFACE_IS_MAPPED (surface); + gdk_x11_surface_unminimize (surface); monitor = gdk_display_get_monitor_at_surface (display, surface); @@ -4903,6 +5004,19 @@ gdk_x11_toplevel_present (GdkToplevel *toplevel, gdk_surface_constrain_size (&geometry, mask, width, height, &width, &height); gdk_x11_surface_toplevel_resize (surface, width, height); + if (size.margin.is_valid) + { + update_shadow_size (surface, + size.margin.left, + size.margin.right, + size.margin.top, + size.margin.bottom); + } + + impl->pending_configure_events++; + if (impl->pending_configure_events == 1) + gdk_surface_freeze_updates (surface); + if (gdk_toplevel_layout_get_maximized (layout)) gdk_x11_surface_maximize (surface); else @@ -4921,10 +5035,8 @@ gdk_x11_toplevel_present (GdkToplevel *toplevel, else gdk_x11_surface_unfullscreen (surface); - if (surface->destroyed) - return; - - was_mapped = GDK_SURFACE_IS_MAPPED (surface); + impl->next_layout.surface_geometry_dirty = TRUE; + gdk_surface_request_layout (surface); if (!was_mapped) gdk_synthesize_surface_state (surface, GDK_TOPLEVEL_STATE_WITHDRAWN, 0); diff --git a/gdk/x11/gdksurface-x11.h b/gdk/x11/gdksurface-x11.h index eb23474afd..f6ccfa2f21 100644 --- a/gdk/x11/gdksurface-x11.h +++ b/gdk/x11/gdksurface-x11.h @@ -59,6 +59,11 @@ struct _GdkX11Surface int surface_scale; + int shadow_left; + int shadow_right; + int shadow_top; + int shadow_bottom; + /* Width and height not divided by surface_scale - this matters in the * corner-case where the window manager assigns us a size that isn't * a multiple of surface_scale - for example for a maximized window @@ -67,6 +72,14 @@ struct _GdkX11Surface int unscaled_width; int unscaled_height; + int pending_configure_events; + + struct { + int configured_width; + int configured_height; + gboolean surface_geometry_dirty; + } next_layout; + cairo_surface_t *cairo_surface; int abs_x; From deb58339b955834b5d0c7dbd39e9706c3c22ad8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Wed, 2 Dec 2020 09:56:55 +0100 Subject: [PATCH 32/87] gtk/expander: Remove manual call to gtk_window_resize() It happens implicitly for a non-resizeable window. --- gtk/gtkexpander.c | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) diff --git a/gtk/gtkexpander.c b/gtk/gtkexpander.c index 9b60db04a4..443f4f48c5 100644 --- a/gtk/gtkexpander.c +++ b/gtk/gtkexpander.c @@ -725,23 +725,7 @@ gtk_expander_resize_toplevel (GtkExpander *expander) if (GTK_IS_WINDOW (toplevel) && gtk_widget_get_realized (toplevel)) - { - int toplevel_width, toplevel_height; - int child_height; - - gtk_widget_measure (child, GTK_ORIENTATION_VERTICAL, -1, - &child_height, NULL, NULL, NULL); - gtk_window_get_size (GTK_WINDOW (toplevel), &toplevel_width, &toplevel_height); - - if (expander->expanded) - toplevel_height += child_height; - else - toplevel_height -= child_height; - - gtk_window_resize (GTK_WINDOW (toplevel), - toplevel_width, - toplevel_height); - } + gtk_widget_queue_resize (GTK_WIDGET (expander)); } } From f083849ebbe0e716677bfa4887c2dc0fdd6c7712 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Wed, 2 Dec 2020 10:08:46 +0100 Subject: [PATCH 33/87] tests: Use gtk_window_set_default_size() when appropriate Replace the usage of gtk_window_resize() with gtk_window_set_default_size() where possible. --- tests/showrendernode.c | 6 +++--- tests/testmenubutton.c | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/showrendernode.c b/tests/showrendernode.c index 5fafd3c00e..43f99b5198 100644 --- a/tests/showrendernode.c +++ b/tests/showrendernode.c @@ -239,9 +239,9 @@ main (int argc, char **argv) } gsk_render_node_get_bounds (GTK_NODE_VIEW (nodeview)->node, &node_bounds); - gtk_window_resize (GTK_WINDOW (window), - MAX (600, node_bounds.size.width), - MAX (500, node_bounds.size.height)); + gtk_window_set_default_size (GTK_WINDOW (window), + MAX (600, node_bounds.size.width), + MAX (500, node_bounds.size.height)); g_signal_connect (window, "destroy", G_CALLBACK (quit_cb), &done); gtk_widget_show (window); diff --git a/tests/testmenubutton.c b/tests/testmenubutton.c index a1f1c78a9d..4752cce214 100644 --- a/tests/testmenubutton.c +++ b/tests/testmenubutton.c @@ -46,7 +46,7 @@ int main (int argc, char **argv) gtk_init (); window = gtk_window_new (); - gtk_window_resize (GTK_WINDOW (window), 400, 300); + gtk_window_set_default_size (GTK_WINDOW (window), 400, 300); grid = gtk_grid_new (); gtk_grid_set_row_spacing (GTK_GRID (grid), 12); From 98fffe6f23998deba31dd5da67d3b0f9b9482134 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Wed, 2 Dec 2020 10:18:04 +0100 Subject: [PATCH 34/87] tests/animated-resizing: Resize widget instead of window This means the window needs to be marked as non-resizable, otherwise it won't shrink. --- tests/animated-resizing.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/animated-resizing.c b/tests/animated-resizing.c index 9b5133a88d..0446b29b68 100644 --- a/tests/animated-resizing.c +++ b/tests/animated-resizing.c @@ -123,8 +123,8 @@ on_frame (double progress) window_height = HEIGHT + jitter; } - gtk_window_resize (GTK_WINDOW (window), - window_width, window_height); + gtk_widget_set_size_request (gtk_window_get_child (GTK_WINDOW (window)), + window_width, window_height); gtk_widget_queue_draw (window); } @@ -196,6 +196,7 @@ main(int argc, char **argv) cb_no_resize ? "no" : "yes"); window = gtk_window_new (); + gtk_window_set_resizable (GTK_WINDOW (window), FALSE); frame_stats_ensure (GTK_WINDOW (window)); da = gtk_drawing_area_new (); From 2854d0339caf53ed822036ee64f56878b50f243c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Wed, 2 Dec 2020 10:21:12 +0100 Subject: [PATCH 35/87] tests/testgtk: Remove 'Resize' button The gtk_window_resize() API is going away, so remove this test. --- tests/testgtk.c | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/tests/testgtk.c b/tests/testgtk.c index 188ecb0554..06a9f0f06a 100644 --- a/tests/testgtk.c +++ b/tests/testgtk.c @@ -4775,17 +4775,6 @@ get_ints (GtkWidget *window, *b = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (spin2)); } -static void -set_size_callback (GtkWidget *widget, - gpointer data) -{ - int w, h; - - get_ints (data, &w, &h); - - gtk_window_resize (GTK_WINDOW (g_object_get_data (data, "target")), w, h); -} - static void unset_default_size_callback (GtkWidget *widget, gpointer data) @@ -4891,13 +4880,6 @@ window_controls (GtkWidget *window) G_CONNECT_SWAPPED); gtk_box_append (GTK_BOX (vbox), button); - button = gtk_button_new_with_label ("Resize"); - g_signal_connect (button, - "clicked", - G_CALLBACK (set_size_callback), - control_window); - gtk_box_append (GTK_BOX (vbox), button); - button = gtk_button_new_with_label ("Set default size"); g_signal_connect (button, "clicked", From 4083f7e47fe22b887459e3b9c1c401a42483f5d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Wed, 2 Dec 2020 14:17:29 +0100 Subject: [PATCH 36/87] testsuite: Remove test for gtk_window_resize() And use gtk_window_set_default_size() in the other place. --- testsuite/gtk/window.c | 66 +----------------------------------------- 1 file changed, 1 insertion(+), 65 deletions(-) diff --git a/testsuite/gtk/window.c b/testsuite/gtk/window.c index 8ffc0645bf..c92c92e03f 100644 --- a/testsuite/gtk/window.c +++ b/testsuite/gtk/window.c @@ -147,69 +147,6 @@ test_default_size (void) gtk_window_destroy (GTK_WINDOW (window)); } -static void -test_resize (void) -{ - GtkWidget *window; - GtkWidget *da; - int w, h; - gboolean done; - - window = gtk_window_new (); - if (interactive) - { - GtkEventController *controller = gtk_event_controller_key_new (); - g_signal_connect (controller, "key-pressed", G_CALLBACK (on_keypress), window); - gtk_widget_add_controller (window, controller); - } - - da = gtk_drawing_area_new (); - gtk_drawing_area_set_draw_func (GTK_DRAWING_AREA (da), on_draw, NULL, NULL); - gtk_window_set_child (GTK_WINDOW (window), da); - - /* test that resize before show overrides default size */ - gtk_window_set_default_size (GTK_WINDOW (window), 500, 500); - - gtk_window_resize (GTK_WINDOW (window), 1, 1); - - gtk_window_get_size (GTK_WINDOW (window), &w, &h); - g_assert_cmpint (w, ==, 1); - g_assert_cmpint (h, ==, 1); - - gtk_window_resize (GTK_WINDOW (window), 400, 200); - - gtk_widget_show (window); - - done = FALSE; - if (!interactive) - g_timeout_add (200, stop_main, &done); - while (!done) - g_main_context_iteration (NULL, TRUE); - - /* test that resize before show works */ - gtk_window_get_size (GTK_WINDOW (window), &w, &h); - g_assert_cmpint (w, ==, 400); - g_assert_cmpint (h, ==, 200); - - /* test that resize after show works, both - * for making things bigger and for making things - * smaller - */ - gtk_window_resize (GTK_WINDOW (window), 200, 400); - - done = FALSE; - if (!interactive) - g_timeout_add (200, stop_main, &done); - while (!done) - g_main_context_iteration (NULL, TRUE); - - gtk_window_get_size (GTK_WINDOW (window), &w, &h); - g_assert_cmpint (w, ==, 200); - g_assert_cmpint (h, ==, 400); - - gtk_window_destroy (GTK_WINDOW (window)); -} - static void test_resize_popup (void) { @@ -220,7 +157,7 @@ test_resize_popup (void) /* testcase for the dnd window */ window = gtk_window_new (); gtk_window_set_decorated (GTK_WINDOW (window), FALSE); - gtk_window_resize (GTK_WINDOW (window), 1, 1); + gtk_window_set_default_size (GTK_WINDOW (window), 1, 1); gtk_window_get_size (GTK_WINDOW (window), &w, &h); g_assert_cmpint (w, ==, 1); g_assert_cmpint (h, ==, 1); @@ -304,7 +241,6 @@ main (int argc, char *argv[]) } g_test_add_func ("/window/default-size", test_default_size); - g_test_add_func ("/window/resize", test_resize); g_test_add_func ("/window/resize-popup", test_resize_popup); g_test_add_func ("/window/show-hide", test_show_hide); From 14b5a5a4c7aab45cc5ec496f138be0c02d9c0239 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Wed, 2 Dec 2020 10:25:22 +0100 Subject: [PATCH 37/87] gtk/window: Remove gtk_window_resize() Use gtk_window_set_default_size() or change the size of the widget inside the window to get the same effect. --- docs/reference/gtk/gtk4-sections.txt | 1 - docs/sizing-test.txt | 8 -- gtk/gtkwindow.c | 122 --------------------------- gtk/gtkwindow.h | 4 - 4 files changed, 135 deletions(-) diff --git a/docs/reference/gtk/gtk4-sections.txt b/docs/reference/gtk/gtk4-sections.txt index 77316a4fb6..f28400f795 100644 --- a/docs/reference/gtk/gtk4-sections.txt +++ b/docs/reference/gtk/gtk4-sections.txt @@ -4620,7 +4620,6 @@ gtk_window_get_title gtk_window_get_transient_for gtk_window_get_group gtk_window_has_group -gtk_window_resize gtk_window_set_default_icon_name gtk_window_set_icon_name gtk_window_set_auto_startup_notification diff --git a/docs/sizing-test.txt b/docs/sizing-test.txt index 86183a2e83..bd98b0a977 100644 --- a/docs/sizing-test.txt +++ b/docs/sizing-test.txt @@ -12,13 +12,6 @@ gtk_widget_set_size_request(): we use 1x1 for implementation convenience) - causes notifies on width_request, height_request properties -gtk_window_resize(): - - causes a configure request in all cases if the window is mapped, - unless the new size is the same as the old size - - overrides the default size on map if the window is unmapped - - allows size of 0, equivalent to 1 - - clamped to geometry hints - gtk_window_set_default_size(): - has no effect after the window has been mapped the first time, unless the window has been unrealized in which case it should @@ -26,7 +19,6 @@ gtk_window_set_default_size(): - allows size of 0, equivalent to 1 - allows size of -1 to unset the default size - clamped to geometry hints - - gtk_window_resize() overrides it - causes notifies on default_width, default_height properties gtk_window_get_default_size(): diff --git a/gtk/gtkwindow.c b/gtk/gtkwindow.c index 67c9d721ba..5f7e363c22 100644 --- a/gtk/gtkwindow.c +++ b/gtk/gtkwindow.c @@ -316,12 +316,6 @@ typedef struct { struct _GtkWindowGeometryInfo { - /* from last gtk_window_resize () - if > 0, indicates that - * we should resize to this size. - */ - int resize_width; - int resize_height; - /* Default size - used only the FIRST time we map a window, * only if > 0. */ @@ -2697,8 +2691,6 @@ gtk_window_get_geometry_info (GtkWindow *window, info->default_width = -1; info->default_height = -1; - info->resize_width = -1; - info->resize_height = -1; info->last.configure_request.x = 0; info->last.configure_request.y = 0; info->last.configure_request.width = -1; @@ -3409,11 +3401,6 @@ gtk_window_set_default_size_internal (GtkWindow *window, * again as they normally would. Setting a default size of -1 means to * use the “natural” default size (the size request of the window). * - * For some uses, gtk_window_resize() is a more appropriate function. - * gtk_window_resize() changes the current size of the window, rather - * than the size to be used on initial display. gtk_window_resize() always - * affects the window itself, not the geometry widget. - * * The default size of a window only affects the first time a window is * shown; if a window is hidden and re-shown, it will remember the size * it had prior to hiding, rather than using the default size. @@ -3468,61 +3455,6 @@ gtk_window_get_default_size (GtkWindow *window, *height = info ? info->default_height : -1; } -/** - * gtk_window_resize: - * @window: a #GtkWindow - * @width: width in pixels to resize the window to - * @height: height in pixels to resize the window to - * - * Resizes the window as if the user had done so, obeying geometry - * constraints. The default geometry constraint is that windows may - * not be smaller than their size request; to override this - * constraint, call gtk_widget_set_size_request() to set the window's - * request to a smaller value. - * - * If gtk_window_resize() is called before showing a window for the - * first time, it overrides any default size set with - * gtk_window_set_default_size(). - * - * Windows may not be resized smaller than 1 by 1 pixels. - * - * When using client side decorations, GTK will do its best to adjust - * the given size so that the resulting window size matches the - * requested size without the title bar, borders and shadows added for - * the client side decorations, but there is no guarantee that the - * result will be totally accurate because these widgets added for - * client side decorations depend on the theme and may not be realized - * or visible at the time gtk_window_resize() is issued. - * - * If the GtkWindow has a titlebar widget (see gtk_window_set_titlebar()), then - * typically, gtk_window_resize() will compensate for the height of the titlebar - * widget only if the height is known when the resulting GtkWindow configuration - * is issued. - * For example, if new widgets are added after the GtkWindow configuration - * and cause the titlebar widget to grow in height, this will result in a - * window content smaller that specified by gtk_window_resize() and not - * a larger window. - * - **/ -void -gtk_window_resize (GtkWindow *window, - int width, - int 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; - - gtk_widget_queue_resize (GTK_WIDGET (window)); -} - /** * gtk_window_get_size: * @window: a #GtkWindow @@ -3536,25 +3468,6 @@ gtk_window_resize (GtkWindow *window, * size (but this is not reliably the same as the size the window manager * will actually select). See: gtk_window_set_default_size(). * - * Depending on the windowing system and the window manager constraints, - * the size returned by this function may not match the size set using - * gtk_window_resize(); additionally, since gtk_window_resize() may be - * implemented as an asynchronous operation, GTK cannot guarantee in any - * way that this code: - * - * |[ - * GtkWindow *window = GTK_WINDOW (gtk_window_new ()); - * int width = 500; - * int height = 300; - * gtk_window_resize (window, width, height); - * - * int new_width, new_height; - * gtk_window_get_size (window, &new_width, &new_height); - * ]| - * - * will result in `new_width` and `new_height` matching `width` and - * `height`, respectively. - * * This function will return the logical size of the #GtkWindow, * excluding the widgets used in client side decorations; there is, * however, no guarantee that the result will be completely accurate @@ -4329,25 +4242,12 @@ toplevel_compute_size (GdkToplevel *toplevel, 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 @@ -4490,8 +4390,6 @@ gtk_window_unrealize (GtkWidget *widget) info = gtk_window_get_geometry_info (window, FALSE); if (info) { - info->resize_width = -1; - info->resize_height = -1; info->last.configure_request.x = 0; info->last.configure_request.y = 0; info->last.configure_request.width = -1; @@ -5312,25 +5210,11 @@ gtk_window_compute_configure_request_size (GtkWindow *window, 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 @@ -5475,7 +5359,6 @@ gtk_window_move_resize (GtkWindow *window) "last : %d,%d\t%d x %d\n" "this : %d,%d\t%d x %d\n" "alloc : %d,%d\t%d x %d\n" - "resize: \t%d x %d\n" "size_changed: %d pos_changed: %d hints_changed: %d\n" "configure_notify_received: %d\n" "position_constraints_changed: %d", @@ -5492,8 +5375,6 @@ gtk_window_move_resize (GtkWindow *window) alloc.y, alloc.width, alloc.height, - info->resize_width, - info->resize_height, configure_request_size_changed, configure_request_pos_changed, hints_changed, @@ -5661,9 +5542,6 @@ gtk_window_move_resize (GtkWindow *window) allocation.height = MAX (current_height - shadow.top - shadow.bottom, min_height); gtk_widget_size_allocate (widget, &allocation, -1); } - - info->resize_width = -1; - info->resize_height = -1; } /* Compare two sets of Geometry hints for equality. diff --git a/gtk/gtkwindow.h b/gtk/gtkwindow.h index 3a5638d1d3..a68937ba67 100644 --- a/gtk/gtkwindow.h +++ b/gtk/gtkwindow.h @@ -216,10 +216,6 @@ void gtk_window_get_default_size (GtkWindow *window, int *width, int *height); GDK_AVAILABLE_IN_ALL -void gtk_window_resize (GtkWindow *window, - int width, - int height); -GDK_AVAILABLE_IN_ALL void gtk_window_get_size (GtkWindow *window, int *width, int *height); From 64f6118af4e152621a84062712d947bf90609335 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Wed, 2 Dec 2020 10:57:32 +0100 Subject: [PATCH 38/87] gdk/toplevelsize: Don't complain if only shadow extends out of bounds --- gdk/gdktoplevelsize.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/gdk/gdktoplevelsize.c b/gdk/gdktoplevelsize.c index 7cd09ebd5e..a1c6ded32d 100644 --- a/gdk/gdktoplevelsize.c +++ b/gdk/gdktoplevelsize.c @@ -135,15 +135,24 @@ gdk_toplevel_size_set_margin (GdkToplevelSize *size, void gdk_toplevel_size_validate (GdkToplevelSize *size) { + int geometry_width, geometry_height; + if (size->min_width > size->bounds_width || size->min_height > size->bounds_height) g_warning ("GdkToplevelSize: min_size (%d, %d) exceeds bounds (%d, %d)", size->min_width, size->min_height, size->bounds_width, size->bounds_height); - if (size->width > size->bounds_width || - size->height > size->bounds_height) - g_warning ("GdkToplevelSize: size (%d, %d) exceeds bounds (%d, %d)", + geometry_width = size->width; + geometry_height = size->height; + if (size->margin.is_valid) + { + geometry_width -= size->margin.left + size->margin.right; + geometry_height -= size->margin.top + size->margin.bottom; + } + if (geometry_width > size->bounds_width || + geometry_height > size->bounds_height) + g_warning ("GdkToplevelSize: geometry size (%d, %d) exceeds bounds (%d, %d)", size->width, size->height, size->bounds_width, size->bounds_height); From 048a0172a067a109f133ed271a5f76d2e81c3e4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Wed, 2 Dec 2020 11:38:17 +0100 Subject: [PATCH 39/87] gdk/wayland: Always configured size when resizing GTK4 doesn't support arbitrary constraints when resizing a window (e.g. steps, or aspect ratio), so we don't need to care about the result from compute-size when doing interactive resizing. --- gdk/wayland/gdksurface-wayland.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/gdk/wayland/gdksurface-wayland.c b/gdk/wayland/gdksurface-wayland.c index 8b16669213..d01d7d4aa3 100644 --- a/gdk/wayland/gdksurface-wayland.c +++ b/gdk/wayland/gdksurface-wayland.c @@ -162,6 +162,7 @@ struct _GdkWaylandSurface int width; int height; GdkToplevelState state; + gboolean is_resizing; } toplevel; struct { @@ -1435,16 +1436,21 @@ gdk_wayland_surface_configure_toplevel (GdkSurface *surface) GDK_WAYLAND_DISPLAY (gdk_surface_get_display (surface)); GdkToplevelState new_state; int width, height; + gboolean is_resizing; gboolean fixed_size; gboolean saved_size; new_state = impl->pending.toplevel.state; impl->pending.toplevel.state = 0; + is_resizing = impl->pending.toplevel.is_resizing; + impl->pending.toplevel.is_resizing = FALSE; + fixed_size = new_state & (GDK_TOPLEVEL_STATE_MAXIMIZED | GDK_TOPLEVEL_STATE_FULLSCREEN | - GDK_TOPLEVEL_STATE_TILED); + GDK_TOPLEVEL_STATE_TILED) || + is_resizing; width = impl->pending.toplevel.width; height = impl->pending.toplevel.height; @@ -1473,6 +1479,10 @@ gdk_wayland_surface_configure_toplevel (GdkSurface *surface) /* Save size for next time we get 0x0 */ _gdk_wayland_surface_save_size (surface); } + else if (is_resizing) + { + impl->next_layout.toplevel.should_constrain = TRUE; + } else { impl->next_layout.toplevel.should_constrain = FALSE; @@ -1679,9 +1689,12 @@ xdg_toplevel_configure (void *data, struct wl_array *states) { GdkSurface *surface = GDK_SURFACE (data); + GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface); uint32_t *p; GdkToplevelState pending_state = 0; + impl->pending.toplevel.is_resizing = FALSE; + wl_array_for_each (p, states) { uint32_t state = *p; @@ -1698,6 +1711,7 @@ xdg_toplevel_configure (void *data, pending_state |= GDK_TOPLEVEL_STATE_FOCUSED; break; case XDG_TOPLEVEL_STATE_RESIZING: + impl->pending.toplevel.is_resizing = TRUE; break; default: /* Unknown state */ @@ -1768,9 +1782,12 @@ zxdg_toplevel_v6_configure (void *data, struct wl_array *states) { GdkSurface *surface = GDK_SURFACE (data); + GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface); uint32_t *p; GdkToplevelState pending_state = 0; + impl->pending.toplevel.is_resizing = FALSE; + wl_array_for_each (p, states) { uint32_t state = *p; @@ -1787,6 +1804,7 @@ zxdg_toplevel_v6_configure (void *data, pending_state |= GDK_TOPLEVEL_STATE_FOCUSED; break; case ZXDG_TOPLEVEL_V6_STATE_RESIZING: + impl->pending.toplevel.is_resizing = TRUE; break; default: /* Unknown state */ From e51c32b9c12d5fa197fd438edf404daefe21fad0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Wed, 2 Dec 2020 11:50:55 +0100 Subject: [PATCH 40/87] gdk/wayland: Always compute-size if GTK asked fer layout --- gdk/wayland/gdksurface-wayland.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/gdk/wayland/gdksurface-wayland.c b/gdk/wayland/gdksurface-wayland.c index d01d7d4aa3..140774a65a 100644 --- a/gdk/wayland/gdksurface-wayland.c +++ b/gdk/wayland/gdksurface-wayland.c @@ -657,6 +657,14 @@ gdk_wayland_surface_compute_size (GdkSurface *surface) } } +static void +gdk_wayland_surface_request_layout (GdkSurface *surface) +{ + GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface); + + impl->next_layout.surface_geometry_dirty = TRUE; +} + void gdk_wayland_surface_request_frame (GdkSurface *surface) { @@ -4158,6 +4166,7 @@ gdk_wayland_surface_class_init (GdkWaylandSurfaceClass *klass) impl_class->set_opaque_region = gdk_wayland_surface_set_opaque_region; impl_class->set_shadow_width = gdk_wayland_surface_set_shadow_width; impl_class->create_gl_context = gdk_wayland_surface_create_gl_context; + impl_class->request_layout = gdk_wayland_surface_request_layout; impl_class->compute_size = gdk_wayland_surface_compute_size; } From a798edc360bc49190034e9b2c0713996eaf16b38 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Wed, 2 Dec 2020 17:42:42 +0100 Subject: [PATCH 41/87] gtk/window: Only deal with shadow when (ex|in)cluding csd size The size should correspond what gtk_widget_measure() does, and it measures what's within the window excluding the shadow; so make this helper function correspond to this. --- gtk/gtkwindow.c | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/gtk/gtkwindow.c b/gtk/gtkwindow.c index 5f7e363c22..4660dd40ce 100644 --- a/gtk/gtkwindow.c +++ b/gtk/gtkwindow.c @@ -3307,19 +3307,6 @@ gtk_window_update_csd_size (GtkWindow *window, w = *width + apply * (window_border.left + window_border.right); h = *height + apply * (window_border.top + window_border.bottom); - if (priv->title_box != NULL && - gtk_widget_get_visible (priv->title_box) && - gtk_widget_get_child_visible (priv->title_box)) - { - int minimum_height; - int natural_height; - - gtk_widget_measure (priv->title_box, GTK_ORIENTATION_VERTICAL, -1, - &minimum_height, &natural_height, - NULL, NULL); - h += apply * natural_height; - } - /* Make sure the size remains acceptable */ if (w < 1) w = 1; From 8a599b2582422f0b6921d85a33466f560d3073a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Wed, 2 Dec 2020 11:59:23 +0100 Subject: [PATCH 42/87] gtk: Allocate everything from GtkNativeClass::layout This changes allocation of the widget trees to happen as a side effect to the GdkSurface::layout signal, which first passes the GtkNative instance where it is then forwarded to the implementations of the GtkNative interface. The implementations of GtkNative are the ones doing the actual gtk_widget_allocate(), and they do so in their GtkNativeClass::layout function. --- gtk/gtkdragicon.c | 24 +-- gtk/gtknative.c | 121 ++++++++++++ gtk/gtknative.h | 5 + gtk/gtknativeprivate.h | 6 + gtk/gtkpopover.c | 38 ++-- gtk/gtkroot.c | 144 +------------- gtk/gtktexthandle.c | 23 ++- gtk/gtktooltipwindow.c | 24 ++- gtk/gtkwidget.c | 5 +- gtk/gtkwindow.c | 417 +++++++++-------------------------------- 10 files changed, 302 insertions(+), 505 deletions(-) diff --git a/gtk/gtkdragicon.c b/gtk/gtkdragicon.c index dfcb029cc9..0a39c39ccf 100644 --- a/gtk/gtkdragicon.c +++ b/gtk/gtkdragicon.c @@ -158,6 +158,14 @@ gtk_drag_icon_native_check_resize (GtkNative *native) gtk_drag_icon_move_resize (icon); } +static void +gtk_drag_icon_native_layout (GtkNative *native, + int width, + int height) +{ + gtk_widget_allocate (GTK_WIDGET (native), width, height, -1, NULL); +} + static void gtk_drag_icon_native_init (GtkNativeInterface *iface) { @@ -165,15 +173,7 @@ gtk_drag_icon_native_init (GtkNativeInterface *iface) iface->get_renderer = gtk_drag_icon_native_get_renderer; iface->get_surface_transform = gtk_drag_icon_native_get_surface_transform; iface->check_resize = gtk_drag_icon_native_check_resize; -} - -static void -surface_layout (GdkSurface *surface, - int width, - int height, - GtkWidget *widget) -{ - gtk_widget_allocate (widget, width, height, -1, NULL); + iface->layout = gtk_drag_icon_native_layout; } static gboolean @@ -194,12 +194,13 @@ gtk_drag_icon_realize (GtkWidget *widget) gdk_surface_set_widget (icon->surface, widget); - g_signal_connect (icon->surface, "layout", G_CALLBACK (surface_layout), widget); g_signal_connect (icon->surface, "render", G_CALLBACK (surface_render), widget); GTK_WIDGET_CLASS (gtk_drag_icon_parent_class)->realize (widget); icon->renderer = gsk_renderer_new_for_surface (icon->surface); + + gtk_native_realize (GTK_NATIVE (icon)); } static void @@ -207,6 +208,8 @@ gtk_drag_icon_unrealize (GtkWidget *widget) { GtkDragIcon *icon = GTK_DRAG_ICON (widget); + gtk_native_unrealize (GTK_NATIVE (icon)); + GTK_WIDGET_CLASS (gtk_drag_icon_parent_class)->unrealize (widget); gsk_renderer_unrealize (icon->renderer); @@ -214,7 +217,6 @@ gtk_drag_icon_unrealize (GtkWidget *widget) if (icon->surface) { - g_signal_handlers_disconnect_by_func (icon->surface, surface_layout, widget); g_signal_handlers_disconnect_by_func (icon->surface, surface_render, widget); gdk_surface_set_widget (icon->surface, NULL); } diff --git a/gtk/gtknative.c b/gtk/gtknative.c index 328d0c61fd..45ad317cbf 100644 --- a/gtk/gtknative.c +++ b/gtk/gtknative.c @@ -24,6 +24,15 @@ #include "gdk/gdk-private.h" #include "gtkprivate.h" #include "gtkintl.h" +#include "gtkcssnodeprivate.h" + +typedef struct _GtkNativePrivate +{ + gulong update_handler_id; + gulong layout_handler_id; +} GtkNativePrivate; + +static GQuark quark_gtk_native_private; /** * SECTION:gtknative @@ -59,12 +68,108 @@ gtk_native_default_check_resize (GtkNative *self) { } +static void +gtk_native_default_layout (GtkNative *self, + int width, + int height) +{ +} + static void gtk_native_default_init (GtkNativeInterface *iface) { iface->get_renderer = gtk_native_default_get_renderer; iface->get_surface_transform = gtk_native_default_get_surface_transform; iface->check_resize = gtk_native_default_check_resize; + iface->layout = gtk_native_default_layout; + + quark_gtk_native_private = g_quark_from_static_string ("gtk-native-private"); +} + +static void +frame_clock_update_cb (GdkFrameClock *clock, + GtkNative *native) +{ + if (GTK_IS_ROOT (native)) + gtk_css_node_validate (gtk_widget_get_css_node (GTK_WIDGET (native))); +} + +static void +gtk_native_layout (GtkNative *self, + int width, + int height) +{ + return GTK_NATIVE_GET_IFACE (self)->layout (self, width, height); +} + +static void +surface_layout_cb (GdkSurface *surface, + int width, + int height, + GtkNative *native) +{ + gtk_native_layout (native, width, height); + + if (gtk_widget_needs_allocate (GTK_WIDGET (native))) + gtk_native_queue_relayout (native); +} + +static void +verify_priv_unrealized (gpointer user_data) +{ + GtkNativePrivate *priv = user_data; + + g_warn_if_fail (priv->update_handler_id == 0); + g_warn_if_fail (priv->layout_handler_id == 0); + + g_free (priv); +} + +void +gtk_native_realize (GtkNative *self) +{ + GdkSurface *surface; + GdkFrameClock *clock; + GtkNativePrivate *priv; + + g_return_if_fail (g_object_get_qdata (G_OBJECT (self), + quark_gtk_native_private) == NULL); + + surface = gtk_native_get_surface (self); + clock = gdk_surface_get_frame_clock (surface); + g_return_if_fail (clock != NULL); + + priv = g_new0 (GtkNativePrivate, 1); + priv->update_handler_id = g_signal_connect_after (clock, "update", + G_CALLBACK (frame_clock_update_cb), + self); + priv->layout_handler_id = g_signal_connect (surface, "layout", + G_CALLBACK (surface_layout_cb), + self); + g_object_set_qdata_full (G_OBJECT (self), + quark_gtk_native_private, + priv, + verify_priv_unrealized); +} + +void +gtk_native_unrealize (GtkNative *self) +{ + GtkNativePrivate *priv; + GdkSurface *surface; + GdkFrameClock *clock; + + priv = g_object_get_qdata (G_OBJECT (self), quark_gtk_native_private); + g_return_if_fail (priv != NULL); + + surface = gtk_native_get_surface (self); + clock = gdk_surface_get_frame_clock (surface); + g_return_if_fail (clock != NULL); + + g_clear_signal_handler (&priv->update_handler_id, clock); + g_clear_signal_handler (&priv->layout_handler_id, surface); + + g_object_set_qdata (G_OBJECT (self), quark_gtk_native_private, NULL); } /** @@ -157,3 +262,19 @@ gtk_native_get_for_surface (GdkSurface *surface) return NULL; } + +void +gtk_native_queue_relayout (GtkNative *self) +{ + GtkWidget *widget = GTK_WIDGET (self); + GdkSurface *surface; + GdkFrameClock *clock; + + surface = gtk_widget_get_surface (widget); + clock = gtk_widget_get_frame_clock (widget); + if (clock == NULL) + return; + + gdk_frame_clock_request_phase (clock, GDK_FRAME_CLOCK_PHASE_UPDATE); + gdk_surface_request_layout (surface); +} diff --git a/gtk/gtknative.h b/gtk/gtknative.h index c9372a60e9..ce2ffcb068 100644 --- a/gtk/gtknative.h +++ b/gtk/gtknative.h @@ -34,6 +34,11 @@ G_BEGIN_DECLS GDK_AVAILABLE_IN_ALL G_DECLARE_INTERFACE (GtkNative, gtk_native, GTK, NATIVE, GtkWidget) +GDK_AVAILABLE_IN_ALL +void gtk_native_realize (GtkNative *self); + +GDK_AVAILABLE_IN_ALL +void gtk_native_unrealize (GtkNative *self); GDK_AVAILABLE_IN_ALL GtkNative * gtk_native_get_for_surface (GdkSurface *surface); diff --git a/gtk/gtknativeprivate.h b/gtk/gtknativeprivate.h index 6b603361ff..1016631661 100644 --- a/gtk/gtknativeprivate.h +++ b/gtk/gtknativeprivate.h @@ -24,8 +24,14 @@ struct _GtkNativeInterface double *y); void (* check_resize) (GtkNative *self); + + void (* layout) (GtkNative *self, + int width, + int height); }; +void gtk_native_queue_relayout (GtkNative *native); + G_END_DECLS #endif /* __GTK_NATIVE_PRIVATE_H__ */ diff --git a/gtk/gtkpopover.c b/gtk/gtkpopover.c index 252797599c..bb2a171864 100644 --- a/gtk/gtkpopover.c +++ b/gtk/gtkpopover.c @@ -589,6 +589,23 @@ gtk_popover_native_check_resize (GtkNative *native) present_popup (popover); } +static void +gtk_popover_native_layout (GtkNative *native, + int width, + int height) +{ + GtkPopover *popover = GTK_POPOVER (native); + GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover); + GtkWidget *widget = GTK_WIDGET (popover); + + update_popover_layout (popover, gdk_popup_layout_ref (priv->layout)); + + if (gtk_widget_needs_allocate (widget)) + gtk_widget_allocate (widget, width, height, -1, NULL); + else + gtk_widget_ensure_allocate (widget); +} + static gboolean gtk_popover_has_mnemonic_modifier_pressed (GtkPopover *popover) { @@ -766,20 +783,6 @@ popup_layout_changed (GdkSurface *surface, update_popover_layout (popover, gdk_popup_layout_ref (priv->layout)); } -static void -surface_layout (GdkSurface *surface, - int width, - int height, - GtkWidget *widget) -{ - GtkPopover *popover = GTK_POPOVER (widget); - GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover); - - update_popover_layout (popover, gdk_popup_layout_ref (priv->layout)); - if (_gtk_widget_get_alloc_needed (widget)) - gtk_widget_allocate (widget, width, height, -1, NULL); -} - static void gtk_popover_activate_default (GtkPopover *popover) { @@ -900,11 +903,12 @@ gtk_popover_realize (GtkWidget *widget) g_signal_connect (priv->surface, "render", G_CALLBACK (surface_render), widget); g_signal_connect (priv->surface, "event", G_CALLBACK (surface_event), widget); g_signal_connect (priv->surface, "popup-layout-changed", G_CALLBACK (popup_layout_changed), widget); - g_signal_connect (priv->surface, "layout", G_CALLBACK (surface_layout), widget); GTK_WIDGET_CLASS (gtk_popover_parent_class)->realize (widget); priv->renderer = gsk_renderer_new_for_surface (priv->surface); + + gtk_native_realize (GTK_NATIVE (popover)); } static void @@ -913,6 +917,8 @@ gtk_popover_unrealize (GtkWidget *widget) GtkPopover *popover = GTK_POPOVER (widget); GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover); + gtk_native_unrealize (GTK_NATIVE (popover)); + GTK_WIDGET_CLASS (gtk_popover_parent_class)->unrealize (widget); gsk_renderer_unrealize (priv->renderer); @@ -923,7 +929,6 @@ gtk_popover_unrealize (GtkWidget *widget) g_signal_handlers_disconnect_by_func (priv->surface, surface_render, widget); g_signal_handlers_disconnect_by_func (priv->surface, surface_event, widget); g_signal_handlers_disconnect_by_func (priv->surface, popup_layout_changed, widget); - g_signal_handlers_disconnect_by_func (priv->surface, surface_layout, widget); gdk_surface_set_widget (priv->surface, NULL); gdk_surface_destroy (priv->surface); g_clear_object (&priv->surface); @@ -1859,6 +1864,7 @@ gtk_popover_native_interface_init (GtkNativeInterface *iface) iface->get_renderer = gtk_popover_native_get_renderer; iface->get_surface_transform = gtk_popover_native_get_surface_transform; iface->check_resize = gtk_popover_native_check_resize; + iface->layout = gtk_popover_native_layout; } static GtkBuildableIface *parent_buildable_iface; diff --git a/gtk/gtkroot.c b/gtk/gtkroot.c index 6bdf1b74a1..16e1bef28c 100644 --- a/gtk/gtkroot.c +++ b/gtk/gtkroot.c @@ -21,6 +21,7 @@ #include "gtkrootprivate.h" #include "gtknative.h" +#include "gtknativeprivate.h" #include "gtkcssnodeprivate.h" #include "gtkwidgetprivate.h" #include "gdk/gdk-private.h" @@ -43,10 +44,6 @@ * The obvious example of a #GtkRoot is #GtkWindow. */ -static GQuark quark_restyle_pending; -static GQuark quark_layout_handler; -static GQuark quark_after_update_handler; - G_DEFINE_INTERFACE_WITH_CODE (GtkRoot, gtk_root, GTK_TYPE_WIDGET, g_type_interface_add_prerequisite (g_define_type_id, GTK_TYPE_NATIVE)) @@ -82,10 +79,6 @@ gtk_root_default_init (GtkRootInterface *iface) iface->get_constraint_solver = gtk_root_default_get_constraint_solver; iface->get_focus = gtk_root_default_get_focus; iface->set_focus = gtk_root_default_set_focus; - - quark_restyle_pending = g_quark_from_static_string ("gtk-root-restyle-pending"); - quark_layout_handler = g_quark_from_static_string ("gtk-root-layout-handler"); - quark_after_update_handler = g_quark_from_static_string ("gtk-root-after-update-handler"); } /** @@ -163,152 +156,19 @@ gtk_root_get_focus (GtkRoot *self) return GTK_ROOT_GET_IFACE (self)->get_focus (self); } -static gboolean -gtk_root_needs_layout (GtkRoot *self) -{ - if (g_object_get_qdata (G_OBJECT (self), quark_restyle_pending)) - return TRUE; - - return gtk_widget_needs_allocate (GTK_WIDGET (self)); -} - -static void -gtk_root_after_update_cb (GdkFrameClock *clock, - GtkRoot *self) -{ - GtkWidget *widget = GTK_WIDGET (self); - - /* We validate the style contexts in a single loop before even trying - * to handle resizes instead of doing validations inline. - * This is mostly necessary for compatibility reasons with old code, - * because both css_changed and size_allocate functions often change - * styles and so could cause infinite loops in this function. - * - * It's important to note that even an invalid style context returns - * sane values. So the result of an invalid style context will never be - * a program crash, but only a wrong layout or rendering. - */ - if (g_object_get_qdata (G_OBJECT (self), quark_restyle_pending)) - { - gtk_css_node_validate (gtk_widget_get_css_node (widget)); - } -} - -static void -gtk_root_layout_cb (GdkSurface *surface, - int width, - int height, - GtkRoot *self) -{ - GtkWidget *widget = GTK_WIDGET (self); - - g_object_set_qdata (G_OBJECT (self), quark_restyle_pending, NULL); - - /* we may be invoked with a container_resize_queue of NULL, because - * queue_resize could have been adding an extra idle function while - * the queue still got processed. we better just ignore such case - * than trying to explicitly work around them with some extra flags, - * since it doesn't cause any actual harm. - */ - if (gtk_widget_needs_allocate (widget)) - { - gtk_native_check_resize (GTK_NATIVE (self)); - if (GTK_IS_WINDOW (widget)) - { - GdkSeat *seat; - - seat = gdk_display_get_default_seat (gtk_widget_get_display (widget)); - if (seat) - { - GdkDevice *device; - GtkWidget *focus; - - device = gdk_seat_get_pointer (seat); - focus = gtk_window_lookup_pointer_focus_widget (GTK_WINDOW (widget), device, NULL); - if (focus) - gdk_surface_request_motion (gtk_native_get_surface (gtk_widget_get_native (focus))); - } - } - } - - if (gtk_root_needs_layout (self)) - { - gdk_frame_clock_request_phase (gdk_surface_get_frame_clock (surface), - GDK_FRAME_CLOCK_PHASE_UPDATE); - gdk_surface_request_layout (surface); - } -} - void gtk_root_start_layout (GtkRoot *self) { - GdkSurface *surface; - GdkFrameClock *clock; - - if (!gtk_root_needs_layout (self)) - return; - - surface = gtk_widget_get_surface (GTK_WIDGET (self)); - clock = gtk_widget_get_frame_clock (GTK_WIDGET (self)); - if (clock == NULL) - return; - - if (!g_object_get_qdata (G_OBJECT (self), quark_layout_handler)) - { - guint layout_handler; - guint after_update_handler; - - after_update_handler = - g_signal_connect_after (clock, "update", - G_CALLBACK (gtk_root_after_update_cb), self); - g_object_set_qdata (G_OBJECT (self), quark_after_update_handler, - GINT_TO_POINTER (after_update_handler)); - - layout_handler = - g_signal_connect (surface, "layout", - G_CALLBACK (gtk_root_layout_cb), self); - g_object_set_qdata (G_OBJECT (self), quark_layout_handler, - GINT_TO_POINTER (layout_handler)); - } - - gdk_frame_clock_request_phase (clock, GDK_FRAME_CLOCK_PHASE_UPDATE); - gdk_surface_request_layout (surface); + gtk_native_queue_relayout (GTK_NATIVE (self)); } void gtk_root_stop_layout (GtkRoot *self) { - GdkSurface *surface; - GdkFrameClock *clock; - guint layout_handler; - guint after_update_handler; - - layout_handler = - GPOINTER_TO_INT (g_object_get_qdata (G_OBJECT (self), - quark_layout_handler)); - after_update_handler = - GPOINTER_TO_INT (g_object_get_qdata (G_OBJECT (self), - quark_after_update_handler)); - - if (layout_handler == 0) - return; - - surface = gtk_widget_get_surface (GTK_WIDGET (self)); - clock = gtk_widget_get_frame_clock (GTK_WIDGET (self)); - g_signal_handler_disconnect (surface, layout_handler); - g_signal_handler_disconnect (clock, after_update_handler); - g_object_set_qdata (G_OBJECT (self), quark_layout_handler, NULL); - g_object_set_qdata (G_OBJECT (self), quark_after_update_handler, NULL); } void gtk_root_queue_restyle (GtkRoot *self) { - if (g_object_get_qdata (G_OBJECT (self), quark_restyle_pending)) - return; - - g_object_set_qdata (G_OBJECT (self), quark_restyle_pending, GINT_TO_POINTER (1)); - gtk_root_start_layout (self); } - diff --git a/gtk/gtktexthandle.c b/gtk/gtktexthandle.c index 47cceafa0e..6d80068088 100644 --- a/gtk/gtktexthandle.c +++ b/gtk/gtktexthandle.c @@ -162,11 +162,6 @@ gtk_text_handle_present_surface (GtkTextHandle *handle) MAX (req.height, 1), layout); gdk_popup_layout_unref (layout); - - gtk_widget_allocate (widget, - gdk_surface_get_width (handle->surface), - gdk_surface_get_height (handle->surface), - -1, NULL); } static void @@ -181,6 +176,19 @@ gtk_text_handle_native_check_resize (GtkNative *native) gtk_text_handle_present_surface (handle); } +static void +gtk_text_handle_native_layout (GtkNative *native, + int width, + int height) +{ + GtkWidget *widget = GTK_WIDGET (native); + + if (_gtk_widget_get_alloc_needed (widget)) + gtk_widget_allocate (widget, width, height, -1, NULL); + else + gtk_widget_ensure_allocate (widget); +} + static void gtk_text_handle_native_interface_init (GtkNativeInterface *iface) { @@ -188,6 +196,7 @@ gtk_text_handle_native_interface_init (GtkNativeInterface *iface) iface->get_renderer = gtk_text_handle_native_get_renderer; iface->get_surface_transform = gtk_text_handle_native_get_surface_transform; iface->check_resize = gtk_text_handle_native_check_resize; + iface->layout = gtk_text_handle_native_layout; } static gboolean @@ -240,6 +249,8 @@ gtk_text_handle_realize (GtkWidget *widget) GTK_WIDGET_CLASS (gtk_text_handle_parent_class)->realize (widget); handle->renderer = gsk_renderer_new_for_surface (handle->surface); + + gtk_native_realize (GTK_NATIVE (handle)); } static void @@ -247,6 +258,8 @@ gtk_text_handle_unrealize (GtkWidget *widget) { GtkTextHandle *handle = GTK_TEXT_HANDLE (widget); + gtk_native_unrealize (GTK_NATIVE (handle)); + GTK_WIDGET_CLASS (gtk_text_handle_parent_class)->unrealize (widget); gsk_renderer_unrealize (handle->renderer); diff --git a/gtk/gtktooltipwindow.c b/gtk/gtktooltipwindow.c index 95b4333a9f..c4c5b64ecd 100644 --- a/gtk/gtktooltipwindow.c +++ b/gtk/gtktooltipwindow.c @@ -152,14 +152,23 @@ gtk_tooltip_window_native_check_resize (GtkNative *native) else if (gtk_widget_get_visible (widget)) { gtk_tooltip_window_relayout (window); - if (window->surface) - gtk_widget_allocate (GTK_WIDGET (window), - gdk_surface_get_width (window->surface), - gdk_surface_get_height (window->surface), - -1, NULL); } } +static void +gtk_tooltip_window_native_layout (GtkNative *native, + int width, + int height) +{ + GtkWidget *widget = GTK_WIDGET (native); + + if (gtk_widget_needs_allocate (widget)) + gtk_widget_allocate (widget, width, height, -1, NULL); + else + gtk_widget_ensure_allocate (widget); + +} + static void gtk_tooltip_window_native_init (GtkNativeInterface *iface) { @@ -167,6 +176,7 @@ gtk_tooltip_window_native_init (GtkNativeInterface *iface) iface->get_renderer = gtk_tooltip_window_native_get_renderer; iface->get_surface_transform = gtk_tooltip_window_native_get_surface_transform; iface->check_resize = gtk_tooltip_window_native_check_resize; + iface->layout = gtk_tooltip_window_native_layout; } static void @@ -223,6 +233,8 @@ gtk_tooltip_window_realize (GtkWidget *widget) GTK_WIDGET_CLASS (gtk_tooltip_window_parent_class)->realize (widget); window->renderer = gsk_renderer_new_for_surface (window->surface); + + gtk_native_realize (GTK_NATIVE (window)); } static void @@ -230,6 +242,8 @@ gtk_tooltip_window_unrealize (GtkWidget *widget) { GtkTooltipWindow *window = GTK_TOOLTIP_WINDOW (widget); + gtk_native_unrealize (GTK_NATIVE (window)); + GTK_WIDGET_CLASS (gtk_tooltip_window_parent_class)->unrealize (widget); gsk_renderer_unrealize (window->renderer); diff --git a/gtk/gtkwidget.c b/gtk/gtkwidget.c index 6d1e3c865d..56a9afb295 100644 --- a/gtk/gtkwidget.c +++ b/gtk/gtkwidget.c @@ -56,6 +56,7 @@ #include "gtkrenderbackgroundprivate.h" #include "gtkrenderborderprivate.h" #include "gtkrootprivate.h" +#include "gtknativeprivate.h" #include "gtkscrollable.h" #include "gtksettingsprivate.h" #include "gtkshortcut.h" @@ -10223,9 +10224,11 @@ gtk_widget_set_alloc_needed (GtkWidget *widget) if (!priv->visible) break; + if (GTK_IS_NATIVE (widget)) + gtk_native_queue_relayout (GTK_NATIVE (widget)); + if (!priv->parent && GTK_IS_ROOT (widget)) { - gtk_root_start_layout (GTK_ROOT (widget)); break; } diff --git a/gtk/gtkwindow.c b/gtk/gtkwindow.c index 4660dd40ce..90864cea57 100644 --- a/gtk/gtkwindow.c +++ b/gtk/gtkwindow.c @@ -202,7 +202,6 @@ typedef struct guint need_default_size : 1; guint builder_visible : 1; - guint configure_notify_received : 1; guint decorated : 1; guint deletable : 1; guint destroy_with_parent : 1; @@ -236,6 +235,9 @@ typedef struct GtkConstraintSolver *constraint_solver; GdkToplevelLayout *layout; + int surface_width; + int surface_height; + GdkCursor *resize_cursor; } GtkWindowPrivate; @@ -385,11 +387,6 @@ static void gtk_window_transient_parent_unrealized (GtkWidget *parent, static GtkWindowGeometryInfo* gtk_window_get_geometry_info (GtkWindow *window, gboolean create); -static void gtk_window_move_resize (GtkWindow *window); -static gboolean gtk_window_compare_hints (GdkGeometry *geometry_a, - guint flags_a, - GdkGeometry *geometry_b, - guint flags_b); static void gtk_window_update_fixed_size (GtkWindow *window, GdkGeometry *new_geometry, int new_width, @@ -487,6 +484,14 @@ static void gtk_window_native_interface_init (GtkNativeInterface * static void ensure_state_flag_backdrop (GtkWidget *widget); static void unset_titlebar (GtkWindow *window); +#define INCLUDE_CSD_SIZE 1 +#define EXCLUDE_CSD_SIZE -1 + +static void +gtk_window_update_csd_size (GtkWindow *window, + int *width, + int *height, + int apply); G_DEFINE_TYPE_WITH_CODE (GtkWindow, gtk_window, GTK_TYPE_WIDGET, G_ADD_PRIVATE (GtkWindow) @@ -1460,7 +1465,6 @@ gtk_window_init (GtkWindow *window) priv->focus_widget = NULL; priv->default_widget = NULL; priv->resizable = TRUE; - priv->configure_notify_received = FALSE; priv->need_default_size = TRUE; priv->modal = FALSE; priv->decorated = TRUE; @@ -1877,11 +1881,59 @@ gtk_window_native_check_resize (GtkNative *native) if (!_gtk_widget_get_alloc_needed (widget)) gtk_widget_ensure_allocate (widget); else if (gtk_widget_get_visible (widget)) - gtk_window_move_resize (GTK_WINDOW (native)); + gtk_window_present_toplevel (GTK_WINDOW (native)); gdk_profiler_end_mark (before, "size allocation", ""); } +static void +gtk_window_native_layout (GtkNative *native, + int width, + int height) +{ + GtkWindow *window = GTK_WINDOW (native); + GtkWindowPrivate *priv = gtk_window_get_instance_private (window); + GtkWidget *widget = GTK_WIDGET (native); + GdkSeat *seat; + + if (priv->surface_width != width || priv->surface_height != height) + { + surface_size_changed (widget, width, height); + priv->surface_width = width; + priv->surface_height = height; + } + + seat = gdk_display_get_default_seat (gtk_widget_get_display (widget)); + if (seat) + { + GdkDevice *device; + GtkWidget *focus; + + device = gdk_seat_get_pointer (seat); + focus = gtk_window_lookup_pointer_focus_widget (GTK_WINDOW (widget), + device, NULL); + if (focus) + { + GdkSurface *focus_surface = + gtk_native_get_surface (gtk_widget_get_native (focus)); + + gdk_surface_request_motion (focus_surface); + } + } + + if (gtk_widget_needs_allocate (widget)) + { + gtk_window_update_csd_size (window, + &width, &height, + EXCLUDE_CSD_SIZE); + gtk_widget_allocate (widget, width, height, -1, NULL); + } + else + { + gtk_widget_ensure_allocate (widget); + } +} + static void gtk_window_root_interface_init (GtkRootInterface *iface) { @@ -1898,6 +1950,7 @@ gtk_window_native_interface_init (GtkNativeInterface *iface) iface->get_renderer = gtk_window_native_get_renderer; iface->get_surface_transform = gtk_window_native_get_surface_transform; iface->check_resize = gtk_window_native_check_resize; + iface->layout = gtk_window_native_layout; } /** @@ -3286,9 +3339,6 @@ gtk_window_get_default_icon_name (void) return default_icon_name; } -#define INCLUDE_CSD_SIZE 1 -#define EXCLUDE_CSD_SIZE -1 - static void gtk_window_update_csd_size (GtkWindow *window, int *width, @@ -3821,8 +3871,6 @@ gtk_window_unmap (GtkWidget *widget) GTK_WIDGET_CLASS (gtk_window_parent_class)->unmap (widget); gdk_surface_hide (priv->surface); - priv->configure_notify_received = FALSE; - state = gdk_toplevel_get_state (GDK_TOPLEVEL (priv->surface)); priv->minimize_initially = (state & GDK_TOPLEVEL_STATE_MINIMIZED) != 0; priv->maximize_initially = (state & GDK_TOPLEVEL_STATE_MAXIMIZED) != 0; @@ -4205,6 +4253,10 @@ toplevel_compute_size (GdkToplevel *toplevel, width = MAX (nat_width, remembered_width); height = MAX (nat_height, remembered_height); + gtk_window_update_csd_size (window, + &width, &height, + INCLUDE_CSD_SIZE); + /* Override with default size */ if (info) { @@ -4222,6 +4274,19 @@ toplevel_compute_size (GdkToplevel *toplevel, if (info->default_height > 0) height = default_height_csd; } + + info = gtk_window_get_geometry_info (window, TRUE); + info->last.configure_request.width = width; + info->last.configure_request.height = height; + } + else if (!priv->resizable) + { + width = nat_width; + height = nat_height; + + gtk_window_update_csd_size (window, + &width, &height, + INCLUDE_CSD_SIZE); } else { @@ -4235,6 +4300,7 @@ toplevel_compute_size (GdkToplevel *toplevel, gtk_window_get_remembered_size (window, &width, &height); } + get_shadow_width (window, &shadow); /* 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 @@ -4243,21 +4309,25 @@ toplevel_compute_size (GdkToplevel *toplevel, width = MAX (width, 1); height = MAX (height, 1); - gdk_toplevel_size_set_size (size, width, height); - get_shadow_width (window, &shadow); - - min_width = MIN (min_width + shadow.left + shadow.right, width); - min_height = MIN (min_height + shadow.top + shadow.bottom, height); + gtk_window_update_csd_size (window, + &min_width, &min_height, + INCLUDE_CSD_SIZE); gdk_toplevel_size_set_min_size (size, min_width, min_height); + gdk_toplevel_size_set_size (size, + MAX (min_width, width), + MAX (min_height, height)); + if (priv->use_client_shadow) { gdk_toplevel_size_set_margin (size, shadow.left, shadow.right, shadow.top, shadow.bottom); } + + gtk_widget_ensure_resize (widget); } static void @@ -4357,6 +4427,8 @@ gtk_window_realize (GtkWidget *widget) gtk_window_realize_icon (window); check_scale_changed (window); + + gtk_native_realize (GTK_NATIVE (window)); } static void @@ -4367,6 +4439,8 @@ gtk_window_unrealize (GtkWidget *widget) GtkWindowGeometryInfo *info; GdkSurface *surface; + gtk_native_unrealize (GTK_NATIVE (window)); + /* On unrealize, we reset the size of the window such * that we will re-apply the default sizing stuff * next time we show the window. @@ -4654,16 +4728,6 @@ surface_size_changed (GtkWidget *widget, info->last.configure_request.height = height; } - /* - * If we do need to resize, we do that by: - * - setting configure_notify_received to TRUE - * for use in gtk_window_move_resize() - * - queueing a resize, leading to invocation of - * gtk_window_move_resize() in an idle handler - * - */ - priv->configure_notify_received = TRUE; - gtk_widget_queue_allocate (widget); } @@ -5258,303 +5322,6 @@ gtk_window_compute_configure_request (GtkWindow *window, *flags = new_flags; } -static void -gtk_window_move_resize (GtkWindow *window) -{ - /* Overview: - * - * First we determine whether any information has changed that would - * cause us to revise our last configure request. If we would send - * a different configure request from last time, then - * configure_request_size_changed = TRUE or - * configure_request_pos_changed = TRUE. configure_request_size_changed - * may be true due to new hints, a gtk_window_resize(), or whatever. - * configure_request_pos_changed may be true due to gtk_window_set_position() - * or gtk_window_move(). - * - * If the configure request has changed, we send off a new one. To - * ensure GTK invariants are maintained (resize queue does what it - * should), we go ahead and size_allocate the requested size in this - * function. - * - * If the configure request has not changed, we don't ever resend - * it, because it could mean fighting the user or window manager. - * - * To prepare the configure request, we come up with a base size/pos: - * - the one from gtk_window_move()/gtk_window_resize() - * - else default_width, default_height if we haven't ever - * been mapped - * - else the size request if we haven't ever been mapped, - * as a substitute default size - * - else the current size of the window, as received from - * configure notifies (i.e. the current allocation) - */ - GtkWindowPrivate *priv = gtk_window_get_instance_private (window); - GtkWidget *widget; - GtkWindowGeometryInfo *info; - GdkGeometry new_geometry; - guint new_flags; - GdkRectangle new_request; - gboolean configure_request_size_changed; - gboolean configure_request_pos_changed; - gboolean hints_changed; /* do we need to send these again */ - GtkWindowLastGeometryInfo saved_last_info; - int current_width, current_height; - - widget = GTK_WIDGET (window); - - info = gtk_window_get_geometry_info (window, TRUE); - - configure_request_size_changed = FALSE; - configure_request_pos_changed = FALSE; - hints_changed = FALSE; - - gtk_window_compute_configure_request (window, &new_request, - &new_geometry, &new_flags); - - if (!(new_flags & GDK_HINT_MIN_SIZE)) - 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); - - /* This check implies the invariant that we never set info->last - * without setting the hints and sending off a configure request. - * - * If we change info->last without sending the request, we may - * miss a request. - */ - if (info->last.configure_request.x != new_request.x || - info->last.configure_request.y != new_request.y) - configure_request_pos_changed = TRUE; - - if ((info->last.configure_request.width != new_request.width || - info->last.configure_request.height != new_request.height)) - configure_request_size_changed = TRUE; - - if (!gtk_window_compare_hints (&info->last.geometry, info->last.flags, - &new_geometry, new_flags)) - hints_changed = TRUE; - -#if 0 - { - GtkAllocation alloc; - - gtk_widget_get_allocation (widget, &alloc); - - g_message ("--- %s ---\n" - "last : %d,%d\t%d x %d\n" - "this : %d,%d\t%d x %d\n" - "alloc : %d,%d\t%d x %d\n" - "size_changed: %d pos_changed: %d hints_changed: %d\n" - "configure_notify_received: %d\n" - "position_constraints_changed: %d", - priv->title ? priv->title : "(no title)", - info->last.configure_request.x, - info->last.configure_request.y, - info->last.configure_request.width, - info->last.configure_request.height, - new_request.x, - new_request.y, - new_request.width, - new_request.height, - alloc.x, - alloc.y, - alloc.width, - alloc.height, - configure_request_size_changed, - configure_request_pos_changed, - hints_changed, - priv->configure_notify_received, - info->position_constraints_changed); - } -#endif - - saved_last_info = info->last; - info->last.geometry = new_geometry; - info->last.flags = new_flags; - info->last.configure_request = new_request; - /* need to set PPosition so the WM will look at our position, - * but we don't want to count PPosition coming and going as a hints - * change for future iterations. So we saved info->last prior to - * this. - */ - - current_width = gdk_surface_get_width (priv->surface); - current_height = gdk_surface_get_height (priv->surface); - - /* handle resizing/moving and widget tree allocation - */ - if (priv->configure_notify_received) - { - GtkAllocation allocation; - GtkBorder shadow; - int min; - - /* If we have received a configure event since - * the last time in this function, we need to - * accept our new size and size_allocate child widgets. - * (see gtk_window_configure_event() for more details). - * - * 1 or more configure notifies may have been received. - * Also, configure_notify_received will only be TRUE - * if all expected configure notifies have been received - * (one per configure request), as an optimization. - * - */ - priv->configure_notify_received = FALSE; - - get_shadow_width (window, &shadow); - - allocation.x = shadow.left; - allocation.y = shadow.top; - - gtk_widget_measure (widget, GTK_ORIENTATION_HORIZONTAL, -1, - &min, NULL, NULL, NULL); - allocation.width = MAX (min, current_width - shadow.left - shadow.right); - gtk_widget_measure (widget, GTK_ORIENTATION_VERTICAL, allocation.width, - &min, NULL, NULL, NULL); - allocation.height = MAX (min, current_height - shadow.top - shadow.bottom); - - gtk_widget_size_allocate (widget, &allocation, -1); - - /* If the configure request changed, it means that - * we either: - * 1) coincidentally changed hints or widget properties - * impacting the configure request before getting - * a configure notify, or - * 2) some broken widget is changing its size request - * during size allocation, resulting in - * a false appearance of changed configure request. - * - * For 1), we could just go ahead and ask for the - * new size right now, but doing that for 2) - * might well be fighting the user (and can even - * trigger a loop). Since we really don't want to - * do that, we requeue a resize in hopes that - * by the time it gets handled, the child has seen - * the light and is willing to go along with the - * new size. (this happens for the zvt widget, since - * the size_allocate() above will have stored the - * requisition corresponding to the new size in the - * zvt widget) - * - * This doesn't buy us anything for 1), but it shouldn't - * hurt us too badly, since it is what would have - * happened if we had gotten the configure event before - * the new size had been set. - */ - - if (configure_request_size_changed || - configure_request_pos_changed) - { - /* Don't change the recorded last info after all, because we - * haven't actually updated to the new info yet - we decided - * to postpone our configure request until later. - */ - info->last = saved_last_info; - g_clear_pointer (&priv->layout, gdk_toplevel_layout_unref); - gtk_widget_queue_resize (widget); - } - - return; /* Bail out, we didn't really process the move/resize */ - } - else if ((configure_request_size_changed || hints_changed || configure_request_pos_changed) && - (current_width != new_request.width || current_height != new_request.height)) - { - /* We are in one of the following situations: - * A. configure_request_size_changed - * our requisition has changed and we need a different window size, - * so we request it from the window manager. - * B. !configure_request_size_changed && hints_changed - * the window manager rejects our size, but we have just changed the - * window manager hints, so there's a chance our request will - * be honoured this time, so we try again. - * - * However, if the new requisition is the same as the current allocation, - * we don't request it again, since we won't get a ConfigureNotify back from - * the window manager unless it decides to change our requisition. If - * we don't get the ConfigureNotify back, the resize queue will never be run. - */ - - /* for GTK_RESIZE_QUEUE toplevels, we are now awaiting a new - * configure event in response to our resizing request. - * the configure event will cause a new resize with - * ->configure_notify_received=TRUE. - * until then, we want to - * - discard expose events - * - coalesce resizes for our children - * - defer any window resizes until the configure event arrived - * to achieve this, we queue a resize for the window, but remove its - * resizing handler, so resizing will not be handled from the next - * idle handler but when the configure event arrives. - * - * FIXME: we should also dequeue the pending redraws here, since - * we handle those ourselves upon ->configure_notify_received==TRUE. - */ - - /* Now send the configure request */ - if (configure_request_pos_changed) - g_warning ("configure request position changed. This should not happen. Ignoring the position"); - - if (_gtk_widget_get_mapped (widget)) - gdk_toplevel_present (GDK_TOPLEVEL (priv->surface), priv->layout); - } - else - { - GtkAllocation allocation; - GtkBorder shadow; - int min_width, min_height; - - get_shadow_width (window, &shadow); - - allocation.x = shadow.left; - allocation.y = shadow.top; - - /* Handle any position changes. - */ - if (configure_request_pos_changed) - g_warning ("configure request position changed. This should not happen. Ignoring the position"); - - /* Our configure request didn't change size, but maybe some of - * our child widgets have. Run a size allocate with our current - * size to make sure that we re-layout our child widgets. */ - - gtk_widget_measure (widget, GTK_ORIENTATION_HORIZONTAL, current_height - shadow.top - shadow.bottom, - &min_width, NULL, NULL, NULL); - allocation.width = MAX (current_width - shadow.left - shadow.right, min_width); - - gtk_widget_measure (widget, GTK_ORIENTATION_VERTICAL, allocation.width, - &min_height, NULL, NULL, NULL); - allocation.height = MAX (current_height - shadow.top - shadow.bottom, min_height); - gtk_widget_size_allocate (widget, &allocation, -1); - } -} - -/* Compare two sets of Geometry hints for equality. - */ -static gboolean -gtk_window_compare_hints (GdkGeometry *geometry_a, - guint flags_a, - GdkGeometry *geometry_b, - guint flags_b) -{ - if (flags_a != flags_b) - return FALSE; - - if ((flags_a & GDK_HINT_MIN_SIZE) && - (geometry_a->min_width != geometry_b->min_width || - geometry_a->min_height != geometry_b->min_height)) - return FALSE; - - if ((flags_a & GDK_HINT_MAX_SIZE) && - (geometry_a->max_width != geometry_b->max_width || - geometry_a->max_height != geometry_b->max_height)) - return FALSE; - - return TRUE; -} - /* For non-resizable windows, make sure the given width/height fits * in the geometry constrains and update the geometry hints to match * the given width/height if not. From 0dcd4a5bdb21af20fc829c7d0a2e9f11a9e92a57 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Wed, 2 Dec 2020 14:13:32 +0100 Subject: [PATCH 43/87] wayland: Stop emitting size-changed It's dealt with by GdkSurface::layout now. --- gdk/wayland/gdksurface-wayland.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/gdk/wayland/gdksurface-wayland.c b/gdk/wayland/gdksurface-wayland.c index 140774a65a..69d9776131 100644 --- a/gdk/wayland/gdksurface-wayland.c +++ b/gdk/wayland/gdksurface-wayland.c @@ -999,9 +999,6 @@ gdk_wayland_surface_resize (GdkSurface *surface, { gdk_wayland_surface_update_size (surface, width, height, scale); _gdk_surface_update_size (surface); - - if (is_realized_shell_surface (GDK_WAYLAND_SURFACE (surface))) - gdk_surface_emit_size_changed (surface, width, height); } static void gdk_wayland_surface_show (GdkSurface *surface, From 3f96d4b6dae56e5e3fc27a4d7b9a8bd90c9a802c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Wed, 2 Dec 2020 14:58:45 +0100 Subject: [PATCH 44/87] gdk: Always get shadow width via GdkToplevelSize This removes the gdk_surface_set_shadow_width() function and related vfuncs. The point here is that the shadow width and surface size can now be communicated to GDK atomically, meaning it's possible to avoid intermediate stages where the surface size includes the shadow, but without the shadow width set, or the other way around. --- docs/reference/gdk/gdk4-sections.txt | 1 - gdk/broadway/gdksurface-broadway.c | 14 +++++++ gdk/broadway/gdksurface-broadway.h | 5 +++ gdk/gdksurface.c | 63 +++++----------------------- gdk/gdksurface.h | 7 ---- gdk/gdksurfaceprivate.h | 13 ++---- gdk/macos/gdkmacospopupsurface.c | 4 ++ gdk/macos/gdkmacossurface-private.h | 5 +++ gdk/macos/gdkmacossurface.c | 3 +- gdk/macos/gdkmacostoplevelsurface.c | 9 ++++ gdk/wayland/gdksurface-wayland.c | 21 +++------- gdk/win32/gdksurface-win32.c | 16 ++++++- gdk/x11/gdksurface-x11.c | 15 +++---- gtk/gtkwindow.c | 4 -- 14 files changed, 77 insertions(+), 103 deletions(-) diff --git a/docs/reference/gdk/gdk4-sections.txt b/docs/reference/gdk/gdk4-sections.txt index 1680e9e3e5..f480652627 100644 --- a/docs/reference/gdk/gdk4-sections.txt +++ b/docs/reference/gdk/gdk4-sections.txt @@ -203,7 +203,6 @@ gdk_surface_get_cursor gdk_surface_set_input_region gdk_surface_get_width gdk_surface_get_height -gdk_surface_set_shadow_width gdk_surface_get_device_position GdkModifierType GDK_MODIFIER_MASK diff --git a/gdk/broadway/gdksurface-broadway.c b/gdk/broadway/gdksurface-broadway.c index bc5f3eb6c9..d8667d0028 100644 --- a/gdk/broadway/gdksurface-broadway.c +++ b/gdk/broadway/gdksurface-broadway.c @@ -558,6 +558,7 @@ gdk_broadway_surface_layout_popup (GdkSurface *surface, int height, GdkPopupLayout *layout) { + GdkBroadwaySurface *impl = GDK_BROADWAY_SURFACE (surface); GdkMonitor *monitor; GdkRectangle bounds; GdkRectangle final_rect; @@ -570,6 +571,10 @@ gdk_broadway_surface_layout_popup (GdkSurface *surface, gdk_surface_layout_popup_helper (surface, width, height, + impl->shadow_left, + impl->shadow_right, + impl->shadow_top, + impl->shadow_bottom, monitor, &bounds, layout, @@ -1529,6 +1534,7 @@ gdk_broadway_toplevel_present (GdkToplevel *toplevel, GdkToplevelLayout *layout) { GdkSurface *surface = GDK_SURFACE (toplevel); + GdkBroadwaySurface *impl = GDK_BROADWAY_SURFACE (surface); GdkDisplay *display = gdk_surface_get_display (surface); GdkMonitor *monitor; GdkToplevelSize size; @@ -1582,6 +1588,14 @@ gdk_broadway_toplevel_present (GdkToplevel *toplevel, else gdk_broadway_surface_unmaximize (surface); + if (size.margin.is_valid) + { + impl->shadow_left = size.margin.left; + impl->shadow_right = size.margin.right; + impl->shadow_top = size.margin.top; + impl->shadow_bottom = size.margin.bottom; + } + show_surface (surface); } diff --git a/gdk/broadway/gdksurface-broadway.h b/gdk/broadway/gdksurface-broadway.h index 0ca144fc80..95cb02ce6d 100644 --- a/gdk/broadway/gdksurface-broadway.h +++ b/gdk/broadway/gdksurface-broadway.h @@ -64,6 +64,11 @@ struct _GdkBroadwaySurface int root_x; int root_y; + + int shadow_left; + int shadow_right; + int shadow_top; + int shadow_bottom; }; struct _GdkBroadwaySurfaceClass diff --git a/gdk/gdksurface.c b/gdk/gdksurface.c index d0cdcc33f2..e4240a3706 100644 --- a/gdk/gdksurface.c +++ b/gdk/gdksurface.c @@ -285,6 +285,10 @@ void gdk_surface_layout_popup_helper (GdkSurface *surface, int width, int height, + int shadow_left, + int shadow_right, + int shadow_top, + int shadow_bottom, GdkMonitor *monitor, GdkRectangle *bounds, GdkPopupLayout *layout, @@ -315,8 +319,8 @@ gdk_surface_layout_popup_helper (GdkSurface *surface, gdk_popup_layout_get_offset (layout, &rect_anchor_dx, &rect_anchor_dy); anchor_hints = gdk_popup_layout_get_anchor_hints (layout); - final_rect.width = width - surface->shadow_left - surface->shadow_right; - final_rect.height = height - surface->shadow_top - surface->shadow_bottom; + final_rect.width = width - shadow_left - shadow_right; + final_rect.height = height - shadow_top - shadow_bottom; final_rect.x = maybe_flip_position (bounds->x, bounds->width, root_rect.x, @@ -380,10 +384,10 @@ gdk_surface_layout_popup_helper (GdkSurface *surface, final_rect.height = bounds->y + bounds->height - final_rect.y; } - final_rect.x -= surface->shadow_left; - final_rect.y -= surface->shadow_top; - final_rect.width += surface->shadow_left + surface->shadow_right; - final_rect.height += surface->shadow_top + surface->shadow_bottom; + final_rect.x -= shadow_left; + final_rect.y -= shadow_top; + final_rect.width += shadow_left + shadow_right; + final_rect.height += shadow_top + shadow_bottom; gdk_surface_get_origin (surface->parent, &x, &y); final_rect.x -= x; @@ -2646,53 +2650,6 @@ gdk_surface_set_opaque_region (GdkSurface *surface, class->set_opaque_region (surface, region); } -/** - * gdk_surface_set_shadow_width: - * @surface: a #GdkSurface - * @left: The left extent - * @right: The right extent - * @top: The top extent - * @bottom: The bottom extent - * - * Newer GTK windows using client-side decorations use extra geometry - * around their frames for effects like shadows and invisible borders. - * Window managers that want to maximize windows or snap to edges need - * to know where the extents of the actual frame lie, so that users - * don’t feel like windows are snapping against random invisible edges. - * - * Note that this property is automatically updated by GTK, so this - * function should only be used by applications which do not use GTK - * to create toplevel surfaces. - */ -void -gdk_surface_set_shadow_width (GdkSurface *surface, - int left, - int right, - int top, - int bottom) -{ - GdkSurfaceClass *class; - - g_return_if_fail (GDK_IS_SURFACE (surface)); - g_return_if_fail (!GDK_SURFACE_DESTROYED (surface)); - g_return_if_fail (left >= 0 && right >= 0 && top >= 0 && bottom >= 0); - - if (surface->shadow_left == left && - surface->shadow_right == right && - surface->shadow_top == top && - surface->shadow_bottom == bottom) - return; - - surface->shadow_top = top; - surface->shadow_left = left; - surface->shadow_right = right; - surface->shadow_bottom = bottom; - - class = GDK_SURFACE_GET_CLASS (surface); - if (class->set_shadow_width) - class->set_shadow_width (surface, left, right, top, bottom); -} - void gdk_surface_set_state (GdkSurface *surface, GdkToplevelState new_state) diff --git a/gdk/gdksurface.h b/gdk/gdksurface.h index 4c47fe659b..4e083ec07b 100644 --- a/gdk/gdksurface.h +++ b/gdk/gdksurface.h @@ -128,13 +128,6 @@ GDK_AVAILABLE_IN_ALL void gdk_surface_set_opaque_region (GdkSurface *surface, cairo_region_t *region); -GDK_AVAILABLE_IN_ALL -void gdk_surface_set_shadow_width (GdkSurface *surface, - int left, - int right, - int top, - int bottom); - GDK_AVAILABLE_IN_ALL GdkCairoContext *gdk_surface_create_cairo_context(GdkSurface *surface); GDK_AVAILABLE_IN_ALL diff --git a/gdk/gdksurfaceprivate.h b/gdk/gdksurfaceprivate.h index 6a4a820faa..4fb40a376b 100644 --- a/gdk/gdksurfaceprivate.h +++ b/gdk/gdksurfaceprivate.h @@ -84,10 +84,6 @@ struct _GdkSurface guint update_and_descendants_freeze_count; int width, height; - int shadow_top; - int shadow_left; - int shadow_right; - int shadow_bottom; GdkCursor *cursor; GHashTable *device_cursor; @@ -161,11 +157,6 @@ struct _GdkSurfaceClass void (* set_opaque_region) (GdkSurface *surface, cairo_region_t *region); - void (* set_shadow_width) (GdkSurface *surface, - int left, - int right, - int top, - int bottom); GdkGLContext *(*create_gl_context) (GdkSurface *surface, gboolean attached, GdkGLContext *share, @@ -190,6 +181,10 @@ GdkMonitor * gdk_surface_get_layout_monitor (GdkSurface *surface, void gdk_surface_layout_popup_helper (GdkSurface *surface, int width, int height, + int shadow_left, + int shadow_right, + int shadow_top, + int shadow_bottom, GdkMonitor *monitor, GdkRectangle *bounds, GdkPopupLayout *layout, diff --git a/gdk/macos/gdkmacospopupsurface.c b/gdk/macos/gdkmacospopupsurface.c index 48c2ca02b8..23c44a70a8 100644 --- a/gdk/macos/gdkmacospopupsurface.c +++ b/gdk/macos/gdkmacospopupsurface.c @@ -69,6 +69,10 @@ gdk_macos_popup_surface_layout (GdkMacosPopupSurface *self, gdk_surface_layout_popup_helper (GDK_SURFACE (self), width, height, + self->parent_instance.shadow_left, + self->parent_instance.shadow_right, + self->parent_instance.shadow_top, + self->parent_instance.shadow_bottom, monitor, &bounds, self->layout, diff --git a/gdk/macos/gdkmacossurface-private.h b/gdk/macos/gdkmacossurface-private.h index 074fd28854..9dd2a7ba52 100644 --- a/gdk/macos/gdkmacossurface-private.h +++ b/gdk/macos/gdkmacossurface-private.h @@ -125,6 +125,11 @@ void _gdk_macos_surface_set_opacity (GdkMacosSurface void _gdk_macos_surface_get_root_coords (GdkMacosSurface *self, int *x, int *y); +void _gdk_macos_surface_set_shadow_width (GdkSurface *surface, + int left, + int right, + int top, + int bottom); G_END_DECLS diff --git a/gdk/macos/gdkmacossurface.c b/gdk/macos/gdkmacossurface.c index 7c1c03f44d..4f0617e878 100644 --- a/gdk/macos/gdkmacossurface.c +++ b/gdk/macos/gdkmacossurface.c @@ -139,7 +139,7 @@ gdk_macos_surface_get_scale_factor (GdkSurface *surface) return [self->window backingScaleFactor]; } -static void +void gdk_macos_surface_set_shadow_width (GdkSurface *surface, int left, int right, @@ -491,7 +491,6 @@ gdk_macos_surface_class_init (GdkMacosSurfaceClass *klass) surface_class->hide = gdk_macos_surface_hide; surface_class->set_input_region = gdk_macos_surface_set_input_region; surface_class->set_opaque_region = gdk_macos_surface_set_opaque_region; - surface_class->set_shadow_width = gdk_macos_surface_set_shadow_width; properties [PROP_NATIVE] = g_param_spec_pointer ("native", diff --git a/gdk/macos/gdkmacostoplevelsurface.c b/gdk/macos/gdkmacostoplevelsurface.c index 7af4725b35..da6b7e6c18 100644 --- a/gdk/macos/gdkmacostoplevelsurface.c +++ b/gdk/macos/gdkmacostoplevelsurface.c @@ -155,6 +155,15 @@ _gdk_macos_toplevel_surface_present (GdkToplevel *toplevel, if (style_mask != [nswindow styleMask]) [nswindow setStyleMask:style_mask]; + if (size.margin.is_valid) + { + _gdk_macos_surface_set_shadow_width (surface, + size.margin.left, + size.margin.right, + size.margin.top, + size.margin.bottom); + } + _gdk_macos_surface_set_geometry_hints (GDK_MACOS_SURFACE (self), &geometry, mask); gdk_surface_constrain_size (&geometry, mask, width, height, &width, &height); _gdk_macos_surface_resize (GDK_MACOS_SURFACE (self), width, height); diff --git a/gdk/wayland/gdksurface-wayland.c b/gdk/wayland/gdksurface-wayland.c index 69d9776131..8282e25ea6 100644 --- a/gdk/wayland/gdksurface-wayland.c +++ b/gdk/wayland/gdksurface-wayland.c @@ -1537,6 +1537,7 @@ static void gdk_wayland_surface_configure_popup (GdkSurface *surface) { GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface); + GdkWaylandSurface *parent_impl = GDK_WAYLAND_SURFACE (surface->parent); int x, y, width, height; if (impl->display_server.xdg_popup) @@ -1576,8 +1577,8 @@ gdk_wayland_surface_configure_popup (GdkSurface *surface) width = impl->pending.popup.width; height = impl->pending.popup.height; - x += surface->parent->shadow_left; - y += surface->parent->shadow_top; + x += parent_impl->margin_left; + y += parent_impl->margin_top; update_popup_layout_state (surface, x, y, @@ -2449,6 +2450,7 @@ create_dynamic_positioner (GdkSurface *surface, { GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface); GdkSurface *parent = surface->parent; + GdkWaylandSurface *parent_impl = GDK_WAYLAND_SURFACE (parent); GdkWaylandDisplay *display = GDK_WAYLAND_DISPLAY (gdk_surface_get_display (surface)); GdkRectangle geometry; @@ -2470,8 +2472,8 @@ create_dynamic_positioner (GdkSurface *surface, }; anchor_rect = gdk_popup_layout_get_anchor_rect (layout); - real_anchor_rect_x = anchor_rect->x - parent->shadow_left; - real_anchor_rect_y = anchor_rect->y - parent->shadow_top; + real_anchor_rect_x = anchor_rect->x - parent_impl->margin_left; + real_anchor_rect_y = anchor_rect->y - parent_impl->margin_top; anchor_rect_width = MAX (anchor_rect->width, 1); anchor_rect_height = MAX (anchor_rect->height, 1); @@ -2530,7 +2532,6 @@ create_dynamic_positioner (GdkSurface *surface, xdg_positioner_get_version (positioner) >= XDG_POSITIONER_SET_PARENT_CONFIGURE_SINCE_VERSION) { - GdkWaylandSurface *parent_impl = GDK_WAYLAND_SURFACE (parent); int parent_width; int parent_height; @@ -4068,15 +4069,6 @@ gdk_wayland_surface_set_opaque_region (GdkSurface *surface, impl->opaque_region_dirty = TRUE; } -static void -gdk_wayland_surface_set_shadow_width (GdkSurface *surface, - int left, - int right, - int top, - int bottom) -{ -} - static gboolean gdk_wayland_surface_show_window_menu (GdkSurface *surface, GdkEvent *event) @@ -4161,7 +4153,6 @@ gdk_wayland_surface_class_init (GdkWaylandSurfaceClass *klass) impl_class->drag_begin = _gdk_wayland_surface_drag_begin; impl_class->get_scale_factor = gdk_wayland_surface_get_scale_factor; impl_class->set_opaque_region = gdk_wayland_surface_set_opaque_region; - impl_class->set_shadow_width = gdk_wayland_surface_set_shadow_width; impl_class->create_gl_context = gdk_wayland_surface_create_gl_context; impl_class->request_layout = gdk_wayland_surface_request_layout; impl_class->compute_size = gdk_wayland_surface_compute_size; diff --git a/gdk/win32/gdksurface-win32.c b/gdk/win32/gdksurface-win32.c index 1f76b5bbb3..238be977af 100644 --- a/gdk/win32/gdksurface-win32.c +++ b/gdk/win32/gdksurface-win32.c @@ -1217,6 +1217,7 @@ gdk_win32_surface_layout_popup (GdkSurface *surface, int height, GdkPopupLayout *layout) { + GdkWin32Surface *impl = GDK_WIN32_SURFACE (surface); GdkMonitor *monitor; GdkRectangle bounds; GdkRectangle final_rect; @@ -1229,6 +1230,10 @@ gdk_win32_surface_layout_popup (GdkSurface *surface, gdk_surface_layout_popup_helper (surface, width, height, + impl->margins.left, + impl->margins.right, + impl->margins.top, + impl->margins.bottom, monitor, &bounds, layout, @@ -4615,8 +4620,6 @@ gdk_win32_surface_class_init (GdkWin32SurfaceClass *klass) //impl_class->beep = gdk_x11_surface_beep; - - impl_class->set_shadow_width = gdk_win32_surface_set_shadow_width; impl_class->destroy_notify = gdk_win32_surface_destroy_notify; impl_class->drag_begin = _gdk_win32_surface_drag_begin; impl_class->create_gl_context = _gdk_win32_surface_create_gl_context; @@ -4992,6 +4995,15 @@ gdk_win32_toplevel_present (GdkToplevel *toplevel, show_surface (surface); + if (size.margin.is_valid) + { + gdk_win32_surface_set_shadow_width (surface, + size.margin.left, + size.margin.right, + size.margin.top, + size.margin.bottom); + } + return TRUE; } diff --git a/gdk/x11/gdksurface-x11.c b/gdk/x11/gdksurface-x11.c index a207c8964b..a531659267 100644 --- a/gdk/x11/gdksurface-x11.c +++ b/gdk/x11/gdksurface-x11.c @@ -1664,6 +1664,7 @@ gdk_x11_surface_layout_popup (GdkSurface *surface, int height, GdkPopupLayout *layout) { + GdkX11Surface *impl = GDK_X11_SURFACE (surface); GdkMonitor *monitor; GdkRectangle bounds; GdkRectangle final_rect; @@ -1676,6 +1677,10 @@ gdk_x11_surface_layout_popup (GdkSurface *surface, gdk_surface_layout_popup_helper (surface, width, height, + impl->shadow_left, + impl->shadow_right, + impl->shadow_top, + impl->shadow_bottom, monitor, &bounds, layout, @@ -2924,15 +2929,6 @@ gdk_x11_surface_set_utf8_property (GdkSurface *surface, } } -static void -gdk_x11_surface_set_shadow_width (GdkSurface *surface, - int left, - int right, - int top, - int bottom) -{ -} - /** * gdk_x11_surface_set_theme_variant: * @surface: (type GdkX11Surface): a #GdkSurface @@ -4658,7 +4654,6 @@ gdk_x11_surface_class_init (GdkX11SurfaceClass *klass) impl_class->drag_begin = _gdk_x11_surface_drag_begin; impl_class->get_scale_factor = gdk_x11_surface_get_scale_factor; impl_class->set_opaque_region = gdk_x11_surface_set_opaque_region; - impl_class->set_shadow_width = gdk_x11_surface_set_shadow_width; impl_class->create_gl_context = gdk_x11_surface_create_gl_context; impl_class->get_unscaled_size = gdk_x11_surface_get_unscaled_size; impl_class->request_layout = gdk_x11_surface_request_layout; diff --git a/gtk/gtkwindow.c b/gtk/gtkwindow.c index 90864cea57..b3f848f8e1 100644 --- a/gtk/gtkwindow.c +++ b/gtk/gtkwindow.c @@ -4139,10 +4139,6 @@ update_realized_window_properties (GtkWindow *window) if (!priv->client_decorated) return; - if (priv->surface && priv->use_client_shadow) - gdk_surface_set_shadow_width (priv->surface, - shadow.left, shadow.right, shadow.top, shadow.bottom); - gtk_native_get_surface_transform (GTK_NATIVE (window), &native_x, &native_y); /* update the input shape, which makes it so that clicks From 42679f2903aa79639d7b24cf6aab2f5396d87831 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Wed, 2 Dec 2020 15:29:54 +0100 Subject: [PATCH 45/87] gdk: Replace all GDK_CONFIGURE usage with GdkSurface::layout This removes the GDK_CONFIGURE event and all related functions and data types; it includes untested changes to the MacOSX, Win32 and Broadway backends. --- docs/reference/gdk/gdk4-sections.txt | 1 - gdk/broadway/gdkeventsource.c | 7 +-- gdk/gdkevents.c | 71 ---------------------------- gdk/gdkevents.h | 10 ---- gdk/gdkeventsprivate.h | 19 -------- gdk/gdksurface.c | 28 ++--------- gdk/macos/GdkMacosWindow.c | 8 +--- gdk/win32/gdkevents-win32.c | 31 +----------- gdk/win32/gdkprivate-win32.h | 1 - gdk/win32/gdksurface-win32.c | 6 +-- 10 files changed, 10 insertions(+), 172 deletions(-) diff --git a/docs/reference/gdk/gdk4-sections.txt b/docs/reference/gdk/gdk4-sections.txt index f480652627..f2e6fa3f3a 100644 --- a/docs/reference/gdk/gdk4-sections.txt +++ b/docs/reference/gdk/gdk4-sections.txt @@ -528,7 +528,6 @@ GDK_IS_EVENT gdk_event_get_type gdk_event_sequence_get_type gdk_button_event_get_type -gdk_configure_event_get_type gdk_crossing_event_get_type gdk_delete_event_get_type gdk_dnd_event_get_type diff --git a/gdk/broadway/gdkeventsource.c b/gdk/broadway/gdkeventsource.c index 3aab5583fa..bc332f9b79 100644 --- a/gdk/broadway/gdkeventsource.c +++ b/gdk/broadway/gdkeventsource.c @@ -280,12 +280,7 @@ _gdk_broadway_events_got_input (GdkDisplay *display, surface = g_hash_table_lookup (display_broadway->id_ht, GINT_TO_POINTER (message->configure_notify.id)); if (surface) { - event = gdk_configure_event_new (surface, - message->configure_notify.width, - message->configure_notify.height); - - node = _gdk_event_queue_append (display, event); - _gdk_windowing_got_event (display, node, event, message->base.serial); + gdk_surface_request_layout (surface); if (surface->resize_count >= 1) { diff --git a/gdk/gdkevents.c b/gdk/gdkevents.c index 9cfefd0d39..30dee67dcd 100644 --- a/gdk/gdkevents.c +++ b/gdk/gdkevents.c @@ -430,7 +430,6 @@ static void gdk_event_init_types_once (void) { g_type_ensure (GDK_TYPE_BUTTON_EVENT); - g_type_ensure (GDK_TYPE_CONFIGURE_EVENT); g_type_ensure (GDK_TYPE_CROSSING_EVENT); g_type_ensure (GDK_TYPE_DELETE_EVENT); g_type_ensure (GDK_TYPE_DND_EVENT); @@ -1818,76 +1817,6 @@ gdk_key_event_get_match (GdkEvent *event, /* }}} */ -/* {{{ GdkConfigureEvent */ - -static gboolean -gdk_configure_event_get_position (GdkEvent *event, - double *x, - double *y) -{ - GdkConfigureEvent *self = (GdkConfigureEvent *) event; - - *x = self->x; - *y = self->y; - - return TRUE; -} - -static const GdkEventTypeInfo gdk_configure_event_info = { - sizeof (GdkConfigureEvent), - NULL, - NULL, - NULL, - gdk_configure_event_get_position, - NULL, - NULL, - NULL, -}; - -GDK_DEFINE_EVENT_TYPE (GdkConfigureEvent, gdk_configure_event, - &gdk_configure_event_info, - GDK_EVENT_TYPE_SLOT (GDK_CONFIGURE)) - -GdkEvent * -gdk_configure_event_new (GdkSurface *surface, - int width, - int height) -{ - GdkConfigureEvent *self; - - g_return_val_if_fail (width >= 0 && height >= 0, NULL); - - self = gdk_event_alloc (GDK_CONFIGURE, surface, NULL, GDK_CURRENT_TIME); - self->width = width; - self->height = height; - - return (GdkEvent *) self; -} - -/** - * gdk_configure_event_get_size: - * @event: (type GdkConfigureEvent): a configure event - * @width: (out): return location for surface width - * @height: (out): return location for surface height - * - * Extracts the surface size from a configure event. - */ -void -gdk_configure_event_get_size (GdkEvent *event, - int *width, - int *height) -{ - GdkConfigureEvent *self = (GdkConfigureEvent *) event; - - g_return_if_fail (GDK_IS_EVENT (event)); - g_return_if_fail (GDK_IS_EVENT_TYPE (event, GDK_CONFIGURE)); - - *width = self->width; - *height = self->height; -} - -/* }}} */ - /* {{{ GdkTouchEvent */ static void diff --git a/gdk/gdkevents.h b/gdk/gdkevents.h index 0ecd5a80df..2b87754eec 100644 --- a/gdk/gdkevents.h +++ b/gdk/gdkevents.h @@ -106,7 +106,6 @@ typedef struct _GdkEventSequence GdkEventSequence; typedef struct _GdkEvent GdkEvent; #define GDK_TYPE_BUTTON_EVENT (gdk_button_event_get_type()) -#define GDK_TYPE_CONFIGURE_EVENT (gdk_configure_event_get_type()) #define GDK_TYPE_CROSSING_EVENT (gdk_crossing_event_get_type()) #define GDK_TYPE_DELETE_EVENT (gdk_delete_event_get_type()) #define GDK_TYPE_DND_EVENT (gdk_dnd_event_get_type()) @@ -121,7 +120,6 @@ typedef struct _GdkEvent GdkEvent; #define GDK_TYPE_TOUCHPAD_EVENT (gdk_touchpad_event_get_type()) typedef struct _GdkButtonEvent GdkButtonEvent; -typedef struct _GdkConfigureEvent GdkConfigureEvent; typedef struct _GdkCrossingEvent GdkCrossingEvent; typedef struct _GdkDeleteEvent GdkDeleteEvent; typedef struct _GdkDNDEvent GdkDNDEvent; @@ -148,7 +146,6 @@ typedef struct _GdkTouchpadEvent GdkTouchpadEvent; * @GDK_ENTER_NOTIFY: the pointer has entered the surface. * @GDK_LEAVE_NOTIFY: the pointer has left the surface. * @GDK_FOCUS_CHANGE: the keyboard focus has entered or left the surface. - * @GDK_CONFIGURE: the size of the surface has changed. * @GDK_PROXIMITY_IN: an input device has moved into contact with a sensing * surface (e.g. a touchscreen or graphics tablet). * @GDK_PROXIMITY_OUT: an input device has moved out of contact with a sensing @@ -188,7 +185,6 @@ typedef enum GDK_ENTER_NOTIFY, GDK_LEAVE_NOTIFY, GDK_FOCUS_CHANGE, - GDK_CONFIGURE, GDK_PROXIMITY_IN, GDK_PROXIMITY_OUT, GDK_DRAG_ENTER, @@ -429,12 +425,6 @@ GdkNotifyType gdk_crossing_event_get_detail (GdkEvent *event); GDK_AVAILABLE_IN_ALL gboolean gdk_crossing_event_get_focus (GdkEvent *event); GDK_AVAILABLE_IN_ALL -GType gdk_configure_event_get_type (void) G_GNUC_CONST; -GDK_AVAILABLE_IN_ALL -void gdk_configure_event_get_size (GdkEvent *event, - int *width, - int *height); -GDK_AVAILABLE_IN_ALL GType gdk_touchpad_event_get_type (void) G_GNUC_CONST; GDK_AVAILABLE_IN_ALL GdkTouchpadGesturePhase diff --git a/gdk/gdkeventsprivate.h b/gdk/gdkeventsprivate.h index a521ca5ab5..c64598572e 100644 --- a/gdk/gdkeventsprivate.h +++ b/gdk/gdkeventsprivate.h @@ -322,25 +322,6 @@ struct _GdkFocusEvent gboolean focus_in; }; -/* - * GdkConfigureEvent: - * @x: the new x coordinate of the surface, relative to its parent. - * @y: the new y coordinate of the surface, relative to its parent. - * @width: the new width of the surface. - * @height: the new height of the surface. - * - * Generated when a surface size or position has changed. - */ -struct _GdkConfigureEvent -{ - GdkEvent parent_instance; - - int x; - int y; - int width; - int height; -}; - /* * GdkProximityEvent: * @tool: the #GdkDeviceTool associated to the event diff --git a/gdk/gdksurface.c b/gdk/gdksurface.c index e4240a3706..0225397f5d 100644 --- a/gdk/gdksurface.c +++ b/gdk/gdksurface.c @@ -2830,14 +2830,6 @@ add_event_mark (GdkEvent *event, break; } - case GDK_CONFIGURE: - { - int width, height; - gdk_configure_event_get_size (event, &width, &height); - message = g_strdup_printf ("%s {width=%d, height=%d}", kind, width, height); - break; - } - case GDK_ENTER_NOTIFY: case GDK_LEAVE_NOTIFY: case GDK_TOUCHPAD_SWIPE: @@ -2875,30 +2867,18 @@ add_event_mark (GdkEvent *event, gboolean gdk_surface_handle_event (GdkEvent *event) { + GdkSurface *surface = gdk_event_get_surface (event); gint64 begin_time = GDK_PROFILER_CURRENT_TIME; gboolean handled = FALSE; if (check_autohide (event)) return TRUE; - if (gdk_event_get_event_type (event) == GDK_CONFIGURE) - { - int width, height; - gdk_configure_event_get_size (event, &width, &height); - gdk_surface_emit_size_changed (gdk_event_get_surface (event), - width, height); - handled = TRUE; - } - else - { - GdkSurface *surface = gdk_event_get_surface (event); + if (gdk_event_get_event_type (event) == GDK_MOTION_NOTIFY) + surface->request_motion = FALSE; - if (gdk_event_get_event_type (event) == GDK_MOTION_NOTIFY) - surface->request_motion = FALSE; - - g_signal_emit (surface, signals[EVENT], 0, event, &handled); - } + g_signal_emit (surface, signals[EVENT], 0, event, &handled); if (GDK_PROFILER_IS_RUNNING) add_event_mark (event, begin_time, GDK_PROFILER_CURRENT_TIME); diff --git a/gdk/macos/GdkMacosWindow.c b/gdk/macos/GdkMacosWindow.c index 46a97adcfc..dd762543d0 100644 --- a/gdk/macos/GdkMacosWindow.c +++ b/gdk/macos/GdkMacosWindow.c @@ -256,13 +256,7 @@ _gdk_surface_update_size (surface); - /* Synthesize a configure event */ - event = gdk_configure_event_new (surface, - content_rect.size.width, - content_rect.size.height); - node = _gdk_event_queue_append (display, event); - _gdk_windowing_got_event (display, node, event, - _gdk_display_get_next_serial (display)); + gdk_surface_request_layout (surface); _gdk_macos_surface_reposition_children (gdk_surface); diff --git a/gdk/win32/gdkevents-win32.c b/gdk/win32/gdkevents-win32.c index 32e319f040..1a50cdb5dd 100644 --- a/gdk/win32/gdkevents-win32.c +++ b/gdk/win32/gdkevents-win32.c @@ -1277,35 +1277,6 @@ _gdk_win32_get_window_rect (GdkSurface *window, return !impl->inhibit_configure; } -void -_gdk_win32_do_emit_configure_event (GdkSurface *surface, - RECT rect) -{ - GdkWin32Surface *impl = GDK_WIN32_SURFACE (surface); - - impl->unscaled_width = rect.right - rect.left; - impl->unscaled_height = rect.bottom - rect.top; - surface->width = (impl->unscaled_width + impl->surface_scale - 1) / impl->surface_scale; - surface->height = (impl->unscaled_height + impl->surface_scale - 1) / impl->surface_scale; - surface->x = rect.left / impl->surface_scale; - surface->y = rect.top / impl->surface_scale; - - _gdk_surface_update_size (surface); - - g_signal_emit_by_name (surface, "size-changed", surface->width, surface->height); -} - -void -_gdk_win32_emit_configure_event (GdkSurface *surface) -{ - RECT rect; - - if (!_gdk_win32_get_window_rect (surface, &rect)) - return; - - _gdk_win32_do_emit_configure_event (surface, rect); -} - cairo_region_t * _gdk_win32_hrgn_to_region (HRGN hrgn, guint scale) @@ -2889,7 +2860,7 @@ gdk_event_translate (MSG *msg, { if (!IsIconic (msg->hwnd) && !GDK_SURFACE_DESTROYED (window)) - _gdk_win32_emit_configure_event (window); + gdk_surface_request_layout (window); } if ((windowpos->flags & SWP_HIDEWINDOW) && diff --git a/gdk/win32/gdkprivate-win32.h b/gdk/win32/gdkprivate-win32.h index 6ed78b480b..d37866bcf3 100644 --- a/gdk/win32/gdkprivate-win32.h +++ b/gdk/win32/gdkprivate-win32.h @@ -407,7 +407,6 @@ GdkSurface *gdk_win32_display_get_root_window (GdkDisplay *display); /* Distributed display manager implementation */ GdkDisplay *_gdk_win32_display_open (const char *display_name); void _gdk_win32_append_event (GdkEvent *event); -void _gdk_win32_emit_configure_event (GdkSurface *window); guint32 _gdk_win32_keymap_get_decimal_mark (GdkWin32Keymap *keymap); diff --git a/gdk/win32/gdksurface-win32.c b/gdk/win32/gdksurface-win32.c index 238be977af..227c377532 100644 --- a/gdk/win32/gdksurface-win32.c +++ b/gdk/win32/gdksurface-win32.c @@ -1190,7 +1190,7 @@ gdk_win32_surface_move_resize_internal (GdkSurface *window, out: surface->inhibit_configure = FALSE; - _gdk_win32_emit_configure_event (window); + gdk_surface_request_layout (window); } void @@ -4018,7 +4018,7 @@ gdk_win32_surface_do_move_resize_drag (GdkSurface *window, rect.bottom != new_rect.bottom)) { context->native_move_resize_pending = TRUE; - _gdk_win32_do_emit_configure_event (window, new_rect); + gdk_surface_request_layout (window); } else if (context->op == GDK_WIN32_DRAGOP_MOVE && (rect.left != new_rect.left || @@ -4026,7 +4026,7 @@ gdk_win32_surface_do_move_resize_drag (GdkSurface *window, { context->native_move_resize_pending = FALSE; - _gdk_win32_do_emit_configure_event (window, new_rect); + gdk_surface_request_layout (window); if (impl->layered) { From 5eca548accbeaa93567dc721dcbc8228ae74ab02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Wed, 2 Dec 2020 16:44:25 +0100 Subject: [PATCH 46/87] gtk/window: Use default size if non-resizable if set --- gtk/gtkwindow.c | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/gtk/gtkwindow.c b/gtk/gtkwindow.c index b3f848f8e1..42f35da098 100644 --- a/gtk/gtkwindow.c +++ b/gtk/gtkwindow.c @@ -4277,12 +4277,22 @@ toplevel_compute_size (GdkToplevel *toplevel, } else if (!priv->resizable) { - width = nat_width; - height = nat_height; - - gtk_window_update_csd_size (window, - &width, &height, - INCLUDE_CSD_SIZE); + if (info && + info->default_width > 0 && + info->default_height > 0) + { + width = info->default_width; + height = info->default_height; + gtk_window_update_csd_size (window, &width, &height, + INCLUDE_CSD_SIZE); + } + else + { + width = nat_width; + height = nat_height; + gtk_window_update_csd_size (window, &width, &height, + INCLUDE_CSD_SIZE); + } } else { From ca65ee8d50e6cc10f20f63f918e41fab02ac9463 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Wed, 2 Dec 2020 16:44:49 +0100 Subject: [PATCH 47/87] gtk/window: Remove out-dated comment --- gtk/gtkwindow.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/gtk/gtkwindow.c b/gtk/gtkwindow.c index 42f35da098..75c12a945e 100644 --- a/gtk/gtkwindow.c +++ b/gtk/gtkwindow.c @@ -4256,9 +4256,6 @@ toplevel_compute_size (GdkToplevel *toplevel, /* 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, From b8fa892b70363ae0cb890fc607aa1784dc0b2a30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Wed, 2 Dec 2020 16:44:59 +0100 Subject: [PATCH 48/87] gtk/window: Minor cleanup --- gtk/gtkwindow.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/gtk/gtkwindow.c b/gtk/gtkwindow.c index 75c12a945e..aed818e9ce 100644 --- a/gtk/gtkwindow.c +++ b/gtk/gtkwindow.c @@ -4303,8 +4303,6 @@ toplevel_compute_size (GdkToplevel *toplevel, gtk_window_get_remembered_size (window, &width, &height); } - get_shadow_width (window, &shadow); - /* 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 @@ -4312,7 +4310,6 @@ toplevel_compute_size (GdkToplevel *toplevel, width = MAX (width, 1); height = MAX (height, 1); - gtk_window_update_csd_size (window, &min_width, &min_height, INCLUDE_CSD_SIZE); @@ -4325,6 +4322,7 @@ toplevel_compute_size (GdkToplevel *toplevel, if (priv->use_client_shadow) { + get_shadow_width (window, &shadow); gdk_toplevel_size_set_margin (size, shadow.left, shadow.right, shadow.top, shadow.bottom); From b7380543449ea679a2c912b66aab4855b2bb41f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Wed, 2 Dec 2020 17:08:07 +0100 Subject: [PATCH 49/87] gdk: Remove GdkSurface::size-changed It's not emitted, and everyone should use the GdkSurface::layout signal from now on. --- docs/reference/gtk/migrating-3to4.md | 2 +- gdk/gdksurface.c | 33 ---------------------------- gtk/gtkpopover.c | 9 -------- gtk/gtkwindow.c | 2 -- tests/testwindowsize.c | 23 ++++++++++++++----- 5 files changed, 19 insertions(+), 50 deletions(-) diff --git a/docs/reference/gtk/migrating-3to4.md b/docs/reference/gtk/migrating-3to4.md index 8a4fc9f32e..95847872f7 100644 --- a/docs/reference/gtk/migrating-3to4.md +++ b/docs/reference/gtk/migrating-3to4.md @@ -165,7 +165,7 @@ for this change. | ::key-release-event | #GtkEventControllerKey | | ::enter-notify-event | #GtkEventControllerMotion | | ::leave-notify-event | #GtkEventControllerMotion | -| ::configure-event | replaced by #GdkSurface::size-changed | +| ::configure-event | replaced by #GdkSurface::layout | | ::focus-in-event | #GtkEventControllerFocus | | ::focus-out-event | #GtkEventControllerFocus | | ::map-event | replaced by #GdkSurface:mapped | diff --git a/gdk/gdksurface.c b/gdk/gdksurface.c index 0225397f5d..2c52e551f3 100644 --- a/gdk/gdksurface.c +++ b/gdk/gdksurface.c @@ -76,7 +76,6 @@ */ enum { - SIZE_CHANGED, LAYOUT, RENDER, EVENT, @@ -551,30 +550,6 @@ gdk_surface_class_init (GdkSurfaceClass *klass) g_object_class_install_properties (object_class, LAST_PROP, properties); - /** - * GdkSurface::size-changed: - * @surface: the #GdkSurface - * @width: the new width - * @height: the new height - * - * Emitted when the size of @surface is changed. - * - * Surface size is reported in ”application pixels”, not - * ”device pixels” (see gdk_surface_get_scale_factor()). - */ - signals[SIZE_CHANGED] = - g_signal_new (g_intern_static_string ("size-changed"), - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_FIRST, - 0, - NULL, - NULL, - NULL, - G_TYPE_NONE, - 2, - G_TYPE_INT, - G_TYPE_INT); - /** * GdkSurface::layout: * @surface: the #GdkSurface @@ -1306,14 +1281,6 @@ gdk_surface_schedule_update (GdkSurface *surface) GDK_FRAME_CLOCK_PHASE_PAINT); } -void -gdk_surface_emit_size_changed (GdkSurface *surface, - int width, - int height) -{ - g_signal_emit (surface, signals[SIZE_CHANGED], 0, width, height); -} - static void gdk_surface_process_updates_internal (GdkSurface *surface) { diff --git a/gtk/gtkpopover.c b/gtk/gtkpopover.c index bb2a171864..7fcfac9b66 100644 --- a/gtk/gtkpopover.c +++ b/gtk/gtkpopover.c @@ -748,13 +748,6 @@ surface_mapped_changed (GtkWidget *widget) gtk_widget_set_visible (widget, gdk_surface_get_mapped (priv->surface)); } -static void -surface_size_changed (GtkWidget *widget, - guint width, - guint height) -{ -} - static gboolean surface_render (GdkSurface *surface, cairo_region_t *region, @@ -899,7 +892,6 @@ gtk_popover_realize (GtkWidget *widget) gdk_surface_set_widget (priv->surface, widget); g_signal_connect_swapped (priv->surface, "notify::mapped", G_CALLBACK (surface_mapped_changed), widget); - g_signal_connect_swapped (priv->surface, "size-changed", G_CALLBACK (surface_size_changed), widget); g_signal_connect (priv->surface, "render", G_CALLBACK (surface_render), widget); g_signal_connect (priv->surface, "event", G_CALLBACK (surface_event), widget); g_signal_connect (priv->surface, "popup-layout-changed", G_CALLBACK (popup_layout_changed), widget); @@ -925,7 +917,6 @@ gtk_popover_unrealize (GtkWidget *widget) g_clear_object (&priv->renderer); g_signal_handlers_disconnect_by_func (priv->surface, surface_mapped_changed, widget); - g_signal_handlers_disconnect_by_func (priv->surface, surface_size_changed, widget); g_signal_handlers_disconnect_by_func (priv->surface, surface_render, widget); g_signal_handlers_disconnect_by_func (priv->surface, surface_event, widget); g_signal_handlers_disconnect_by_func (priv->surface, popup_layout_changed, widget); diff --git a/gtk/gtkwindow.c b/gtk/gtkwindow.c index aed818e9ce..0b63ac5f57 100644 --- a/gtk/gtkwindow.c +++ b/gtk/gtkwindow.c @@ -4368,7 +4368,6 @@ gtk_window_realize (GtkWidget *widget) priv->renderer = gsk_renderer_new_for_surface (surface); g_signal_connect_swapped (surface, "notify::state", G_CALLBACK (surface_state_changed), 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); @@ -4476,7 +4475,6 @@ gtk_window_unrealize (GtkWidget *widget) surface = priv->surface; g_signal_handlers_disconnect_by_func (surface, surface_state_changed, widget); - g_signal_handlers_disconnect_by_func (surface, surface_size_changed, widget); g_signal_handlers_disconnect_by_func (surface, surface_render, widget); g_signal_handlers_disconnect_by_func (surface, surface_event, widget); diff --git a/tests/testwindowsize.c b/tests/testwindowsize.c index e6539c7ae0..f61669b204 100644 --- a/tests/testwindowsize.c +++ b/tests/testwindowsize.c @@ -8,14 +8,27 @@ static GtkWidget *default_width_spin; static GtkWidget *default_height_spin; static GtkWidget *resizable_check; -static void -size_changed_cb (GdkSurface *surface, int width, int height, GtkLabel *label) +static gboolean +set_label_idle (gpointer user_data) { + GtkLabel *label = user_data; + GtkNative *native = gtk_widget_get_native (GTK_WIDGET (label)); + GdkSurface *surface = gtk_native_get_surface (native); char *str; - str = g_strdup_printf ("%d x %d", width, height); + str = g_strdup_printf ("%d x %d", + gdk_surface_get_width (surface), + gdk_surface_get_height (surface)); gtk_label_set_label (label, str); g_free (str); + + return G_SOURCE_REMOVE; +} + +static void +layout_cb (GdkSurface *surface, int width, int height, GtkLabel *label) +{ + g_idle_add (set_label_idle, label); } static void @@ -63,8 +76,8 @@ show_dialog (void) gtk_dialog_add_action_widget (GTK_DIALOG (dialog), label, GTK_RESPONSE_HELP); gtk_widget_realize (dialog); - g_signal_connect (gtk_native_get_surface (GTK_NATIVE (dialog)), "size-changed", - G_CALLBACK (size_changed_cb), label); + g_signal_connect (gtk_native_get_surface (GTK_NATIVE (dialog)), "layout", + G_CALLBACK (layout_cb), label); g_signal_connect (dialog, "response", G_CALLBACK (gtk_window_destroy), NULL); From 6ee7535af07e14193436876eafed6297916d0ca2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Wed, 2 Dec 2020 17:08:43 +0100 Subject: [PATCH 50/87] gdk/toplevelsize: Rename 'margin' to 'shadow' and 'shadow_width' This makes it more consistent with everywhere else. --- gdk/broadway/gdksurface-broadway.c | 10 ++-- gdk/gdktoplevelsize.c | 38 +++++++++----- gdk/gdktoplevelsize.h | 10 ++-- gdk/gdktoplevelsizeprivate.h | 2 +- gdk/macos/gdkmacostoplevelsurface.c | 10 ++-- gdk/wayland/gdksurface-wayland.c | 78 ++++++++++++++--------------- gdk/win32/gdksurface-win32.c | 10 ++-- gdk/x11/gdksurface-x11.c | 20 ++++---- gtk/gtkwindow.c | 6 +-- 9 files changed, 98 insertions(+), 86 deletions(-) diff --git a/gdk/broadway/gdksurface-broadway.c b/gdk/broadway/gdksurface-broadway.c index d8667d0028..30ba9ff51b 100644 --- a/gdk/broadway/gdksurface-broadway.c +++ b/gdk/broadway/gdksurface-broadway.c @@ -1588,12 +1588,12 @@ gdk_broadway_toplevel_present (GdkToplevel *toplevel, else gdk_broadway_surface_unmaximize (surface); - if (size.margin.is_valid) + if (size.shadow.is_valid) { - impl->shadow_left = size.margin.left; - impl->shadow_right = size.margin.right; - impl->shadow_top = size.margin.top; - impl->shadow_bottom = size.margin.bottom; + impl->shadow_left = size.shadow.left; + impl->shadow_right = size.shadow.right; + impl->shadow_top = size.shadow.top; + impl->shadow_bottom = size.shadow.bottom; } show_surface (surface); diff --git a/gdk/gdktoplevelsize.c b/gdk/gdktoplevelsize.c index a1c6ded32d..6932f6435b 100644 --- a/gdk/gdktoplevelsize.c +++ b/gdk/gdktoplevelsize.c @@ -118,18 +118,30 @@ gdk_toplevel_size_set_min_size (GdkToplevelSize *size, size->min_height = min_height; } +/** + * gdk_toplevel_size_set_shadow_width: + * @size: a #GdkToplevelSize + * @left: width of the left part of the shadow + * @right: width of the right part of the shadow + * @top: height of the top part of the shadow + * @bottom: height of the bottom part of the shadow + * + * The shadow width corresponds to the part of the computed surface size + * that would consist of the shadow margin surrounding the window, would + * there be any. + */ void -gdk_toplevel_size_set_margin (GdkToplevelSize *size, - int left, - int right, - int top, - int bottom) +gdk_toplevel_size_set_shadow_width (GdkToplevelSize *size, + int left, + int right, + int top, + int bottom) { - size->margin.is_valid = TRUE; - size->margin.left = left; - size->margin.right = right; - size->margin.top = top; - size->margin.bottom = bottom; + size->shadow.is_valid = TRUE; + size->shadow.left = left; + size->shadow.right = right; + size->shadow.top = top; + size->shadow.bottom = bottom; } void @@ -145,10 +157,10 @@ gdk_toplevel_size_validate (GdkToplevelSize *size) geometry_width = size->width; geometry_height = size->height; - if (size->margin.is_valid) + if (size->shadow.is_valid) { - geometry_width -= size->margin.left + size->margin.right; - geometry_height -= size->margin.top + size->margin.bottom; + geometry_width -= size->shadow.left + size->shadow.right; + geometry_height -= size->shadow.top + size->shadow.bottom; } if (geometry_width > size->bounds_width || geometry_height > size->bounds_height) diff --git a/gdk/gdktoplevelsize.h b/gdk/gdktoplevelsize.h index 41f8a4a604..69306d9413 100644 --- a/gdk/gdktoplevelsize.h +++ b/gdk/gdktoplevelsize.h @@ -55,11 +55,11 @@ void gdk_toplevel_size_set_min_size (GdkToplevelSize * int min_height); GDK_AVAILABLE_IN_ALL -void gdk_toplevel_size_set_margin (GdkToplevelSize *size, - int left, - int right, - int top, - int bottom); +void gdk_toplevel_size_set_shadow_width (GdkToplevelSize *size, + int left, + int right, + int top, + int bottom); G_END_DECLS diff --git a/gdk/gdktoplevelsizeprivate.h b/gdk/gdktoplevelsizeprivate.h index f2c4461bf9..bba34cc7d7 100644 --- a/gdk/gdktoplevelsizeprivate.h +++ b/gdk/gdktoplevelsizeprivate.h @@ -37,7 +37,7 @@ struct _GdkToplevelSize int right; int top; int bottom; - } margin; + } shadow; }; void gdk_toplevel_size_init (GdkToplevelSize *size, diff --git a/gdk/macos/gdkmacostoplevelsurface.c b/gdk/macos/gdkmacostoplevelsurface.c index da6b7e6c18..63d924c3a2 100644 --- a/gdk/macos/gdkmacostoplevelsurface.c +++ b/gdk/macos/gdkmacostoplevelsurface.c @@ -155,13 +155,13 @@ _gdk_macos_toplevel_surface_present (GdkToplevel *toplevel, if (style_mask != [nswindow styleMask]) [nswindow setStyleMask:style_mask]; - if (size.margin.is_valid) + if (size.shadow.is_valid) { _gdk_macos_surface_set_shadow_width (surface, - size.margin.left, - size.margin.right, - size.margin.top, - size.margin.bottom); + size.shadow.left, + size.shadow.right, + size.shadow.top, + size.shadow.bottom); } _gdk_macos_surface_set_geometry_hints (GDK_MACOS_SURFACE (self), &geometry, mask); diff --git a/gdk/wayland/gdksurface-wayland.c b/gdk/wayland/gdksurface-wayland.c index 8282e25ea6..b8a1d79f81 100644 --- a/gdk/wayland/gdksurface-wayland.c +++ b/gdk/wayland/gdksurface-wayland.c @@ -122,11 +122,11 @@ struct _GdkWaylandSurface gint64 pending_frame_counter; guint32 scale; - int margin_left; - int margin_right; - int margin_top; - int margin_bottom; - gboolean margin_dirty; + int shadow_left; + int shadow_right; + int shadow_top; + int shadow_bottom; + gboolean shadow_dirty; struct wl_output *initial_fullscreen_output; @@ -294,7 +294,7 @@ static void gdk_wayland_surface_configure (GdkSurface *surface); static void maybe_set_gtk_surface_dbus_properties (GdkWaylandSurface *impl); static void maybe_set_gtk_surface_modal (GdkSurface *surface); -static void gdk_wayland_surface_sync_margin (GdkSurface *surface); +static void gdk_wayland_surface_sync_shadow (GdkSurface *surface); static void gdk_wayland_surface_sync_input_region (GdkSurface *surface); static void gdk_wayland_surface_sync_opaque_region (GdkSurface *surface); @@ -366,8 +366,8 @@ _gdk_wayland_surface_save_size (GdkSurface *surface) if (surface->width <= 1 || surface->height <= 1) return; - impl->saved_width = surface->width - impl->margin_left - impl->margin_right; - impl->saved_height = surface->height - impl->margin_top - impl->margin_bottom; + impl->saved_width = surface->width - impl->shadow_left - impl->shadow_right; + impl->saved_height = surface->height - impl->shadow_top - impl->shadow_bottom; } static void @@ -890,7 +890,7 @@ gdk_wayland_surface_attach_image (GdkSurface *surface, void gdk_wayland_surface_sync (GdkSurface *surface) { - gdk_wayland_surface_sync_margin (surface); + gdk_wayland_surface_sync_shadow (surface); gdk_wayland_surface_sync_opaque_region (surface); gdk_wayland_surface_sync_input_region (surface); } @@ -1148,10 +1148,10 @@ gdk_wayland_surface_get_window_geometry (GdkSurface *surface, GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface); *geometry = (GdkRectangle) { - .x = impl->margin_left, - .y = impl->margin_top, - .width = surface->width - (impl->margin_left + impl->margin_right), - .height = surface->height - (impl->margin_top + impl->margin_bottom) + .x = impl->shadow_left, + .y = impl->shadow_top, + .width = surface->width - (impl->shadow_left + impl->shadow_right), + .height = surface->height - (impl->shadow_top + impl->shadow_bottom) }; } @@ -1160,7 +1160,7 @@ static void gdk_wayland_surface_set_geometry_hints (GdkWaylandSurface *impl, GdkSurfaceHints geom_mask); static void -gdk_wayland_surface_sync_margin (GdkSurface *surface) +gdk_wayland_surface_sync_shadow (GdkSurface *surface) { GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface); GdkWaylandDisplay *display_wayland = @@ -1372,12 +1372,12 @@ configure_toplevel_geometry (GdkSurface *surface) } gdk_wayland_surface_set_geometry_hints (impl, &geometry, mask); - if (size.margin.is_valid) + if (size.shadow.is_valid) { - impl->margin_left = size.margin.left; - impl->margin_right = size.margin.right; - impl->margin_top = size.margin.top; - impl->margin_bottom = size.margin.bottom; + impl->shadow_left = size.shadow.left; + impl->shadow_right = size.shadow.right; + impl->shadow_top = size.shadow.top; + impl->shadow_bottom = size.shadow.bottom; } if (impl->next_layout.configured_width > 0 && @@ -1386,9 +1386,9 @@ configure_toplevel_geometry (GdkSurface *surface) int width, height; width = impl->next_layout.configured_width + - impl->margin_left + impl->margin_right; + impl->shadow_left + impl->shadow_right; height = impl->next_layout.configured_height + - impl->margin_top + impl->margin_bottom; + impl->shadow_top + impl->shadow_bottom; if (impl->next_layout.toplevel.should_constrain) { @@ -1577,8 +1577,8 @@ gdk_wayland_surface_configure_popup (GdkSurface *surface) width = impl->pending.popup.width; height = impl->pending.popup.height; - x += parent_impl->margin_left; - y += parent_impl->margin_top; + x += parent_impl->shadow_left; + y += parent_impl->shadow_top; update_popup_layout_state (surface, x, y, @@ -2262,9 +2262,9 @@ calculate_popup_rect (GdkSurface *surface, int x = 0, y = 0; width = (impl->popup.unconstrained_width - - (impl->margin_left + impl->margin_right)); + (impl->shadow_left + impl->shadow_right)); height = (impl->popup.unconstrained_height - - (impl->margin_top + impl->margin_bottom)); + (impl->shadow_top + impl->shadow_bottom)); anchor_rect = *gdk_popup_layout_get_anchor_rect (layout); gdk_popup_layout_get_offset (layout, &dx, &dy); @@ -2465,15 +2465,15 @@ create_dynamic_positioner (GdkSurface *surface, GdkAnchorHints anchor_hints; geometry = (GdkRectangle) { - .x = impl->margin_left, - .y = impl->margin_top, - .width = width - (impl->margin_left + impl->margin_right), - .height = height - (impl->margin_top + impl->margin_bottom), + .x = impl->shadow_left, + .y = impl->shadow_top, + .width = width - (impl->shadow_left + impl->shadow_right), + .height = height - (impl->shadow_top + impl->shadow_bottom), }; anchor_rect = gdk_popup_layout_get_anchor_rect (layout); - real_anchor_rect_x = anchor_rect->x - parent_impl->margin_left; - real_anchor_rect_y = anchor_rect->y - parent_impl->margin_top; + real_anchor_rect_x = anchor_rect->x - parent_impl->shadow_left; + real_anchor_rect_y = anchor_rect->y - parent_impl->shadow_top; anchor_rect_width = MAX (anchor_rect->width, 1); anchor_rect_height = MAX (anchor_rect->height, 1); @@ -2535,10 +2535,10 @@ create_dynamic_positioner (GdkSurface *surface, int parent_width; int parent_height; - parent_width = parent->width - (parent_impl->margin_left + - parent_impl->margin_right); - parent_height = parent->height - (parent_impl->margin_top + - parent_impl->margin_bottom); + parent_width = parent->width - (parent_impl->shadow_left + + parent_impl->shadow_right); + parent_height = parent->height - (parent_impl->shadow_top + + parent_impl->shadow_bottom); xdg_positioner_set_parent_size (positioner, parent_width, @@ -3558,9 +3558,9 @@ gdk_wayland_surface_set_geometry_hints (GdkWaylandSurface *impl, if (geom_mask & GDK_HINT_MIN_SIZE) { min_width = MAX (0, (geometry->min_width - - (impl->margin_left + impl->margin_right))); + (impl->shadow_left + impl->shadow_right))); min_height = MAX (0, (geometry->min_height - - (impl->margin_top + impl->margin_bottom))); + (impl->shadow_top + impl->shadow_bottom))); } else { @@ -3571,9 +3571,9 @@ gdk_wayland_surface_set_geometry_hints (GdkWaylandSurface *impl, if (geom_mask & GDK_HINT_MAX_SIZE) { max_width = MAX (0, (geometry->max_width - - (impl->margin_left + impl->margin_right))); + (impl->shadow_left + impl->shadow_right))); max_height = MAX (0, (geometry->max_height - - (impl->margin_top + impl->margin_bottom))); + (impl->shadow_top + impl->shadow_bottom))); } else { diff --git a/gdk/win32/gdksurface-win32.c b/gdk/win32/gdksurface-win32.c index 227c377532..a7b1bda775 100644 --- a/gdk/win32/gdksurface-win32.c +++ b/gdk/win32/gdksurface-win32.c @@ -4995,13 +4995,13 @@ gdk_win32_toplevel_present (GdkToplevel *toplevel, show_surface (surface); - if (size.margin.is_valid) + if (size.shadow.is_valid) { gdk_win32_surface_set_shadow_width (surface, - size.margin.left, - size.margin.right, - size.margin.top, - size.margin.bottom); + size.shadow.left, + size.shadow.right, + size.shadow.top, + size.shadow.bottom); } return TRUE; diff --git a/gdk/x11/gdksurface-x11.c b/gdk/x11/gdksurface-x11.c index a531659267..7a9d30224f 100644 --- a/gdk/x11/gdksurface-x11.c +++ b/gdk/x11/gdksurface-x11.c @@ -268,13 +268,13 @@ gdk_x11_surface_compute_size (GdkSurface *surface) gdk_toplevel_size_init (&size, bounds_width, bounds_height); gdk_toplevel_notify_compute_size (GDK_TOPLEVEL (surface), &size); - if (size.margin.is_valid) + if (size.shadow.is_valid) { update_shadow_size (surface, - size.margin.left, - size.margin.right, - size.margin.top, - size.margin.bottom); + size.shadow.left, + size.shadow.right, + size.shadow.top, + size.shadow.bottom); } surface->width = impl->next_layout.configured_width; @@ -4999,13 +4999,13 @@ gdk_x11_toplevel_present (GdkToplevel *toplevel, gdk_surface_constrain_size (&geometry, mask, width, height, &width, &height); gdk_x11_surface_toplevel_resize (surface, width, height); - if (size.margin.is_valid) + if (size.shadow.is_valid) { update_shadow_size (surface, - size.margin.left, - size.margin.right, - size.margin.top, - size.margin.bottom); + size.shadow.left, + size.shadow.right, + size.shadow.top, + size.shadow.bottom); } impl->pending_configure_events++; diff --git a/gtk/gtkwindow.c b/gtk/gtkwindow.c index 0b63ac5f57..2ffc166894 100644 --- a/gtk/gtkwindow.c +++ b/gtk/gtkwindow.c @@ -4323,9 +4323,9 @@ toplevel_compute_size (GdkToplevel *toplevel, if (priv->use_client_shadow) { get_shadow_width (window, &shadow); - gdk_toplevel_size_set_margin (size, - shadow.left, shadow.right, - shadow.top, shadow.bottom); + gdk_toplevel_size_set_shadow_width (size, + shadow.left, shadow.right, + shadow.top, shadow.bottom); } gtk_widget_ensure_resize (widget); From 19d2a4ab947f807b68a5d2cda5c68b6bfa0a5d17 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Thu, 3 Dec 2020 22:50:31 +0100 Subject: [PATCH 51/87] gtk/window: Only fake motion events on windows with pending allocations This fixes an issue where the focus of the window continuously received fake motion events even when a popover was open, making input events end up behind the popover. It also adds a comment describing why motion events are requested. Note that popovers won't work with this, and it's possible both in the past and now that sporadic missplaced motion events will appear, e.g. when a window changes allocation but a popover is open. --- gtk/gtkwindow.c | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/gtk/gtkwindow.c b/gtk/gtkwindow.c index 2ffc166894..07c23b0761 100644 --- a/gtk/gtkwindow.c +++ b/gtk/gtkwindow.c @@ -1894,7 +1894,6 @@ gtk_window_native_layout (GtkNative *native, GtkWindow *window = GTK_WINDOW (native); GtkWindowPrivate *priv = gtk_window_get_instance_private (window); GtkWidget *widget = GTK_WIDGET (native); - GdkSeat *seat; if (priv->surface_width != width || priv->surface_height != height) { @@ -1903,21 +1902,30 @@ gtk_window_native_layout (GtkNative *native, priv->surface_height = height; } - seat = gdk_display_get_default_seat (gtk_widget_get_display (widget)); - if (seat) + /* This fake motion event is needed for getting up to date pointer focus + * and coordinates when tho pointer didn't move but the layout changed + * within the window. + */ + if (gtk_widget_needs_allocate (widget)) { - GdkDevice *device; - GtkWidget *focus; + GdkSeat *seat; - device = gdk_seat_get_pointer (seat); - focus = gtk_window_lookup_pointer_focus_widget (GTK_WINDOW (widget), - device, NULL); - if (focus) + seat = gdk_display_get_default_seat (gtk_widget_get_display (widget)); + if (seat) { - GdkSurface *focus_surface = - gtk_native_get_surface (gtk_widget_get_native (focus)); + GdkDevice *device; + GtkWidget *focus; - gdk_surface_request_motion (focus_surface); + device = gdk_seat_get_pointer (seat); + focus = gtk_window_lookup_pointer_focus_widget (GTK_WINDOW (widget), + device, NULL); + if (focus) + { + GdkSurface *focus_surface = + gtk_native_get_surface (gtk_widget_get_native (focus)); + + gdk_surface_request_motion (focus_surface); + } } } From 5eee1dfcd1803d359de5039243ed6b9e2d98d94e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Thu, 3 Dec 2020 23:20:31 +0100 Subject: [PATCH 52/87] gdk/popup: Remove the popup-layout-changed signal It was replaced with GdkSurface::layout. --- gdk/gdkpopup.c | 28 ---------------------------- gdk/macos/gdkmacossurface.c | 2 +- gtk/gtkpopover.c | 12 ------------ 3 files changed, 1 insertion(+), 41 deletions(-) diff --git a/gdk/gdkpopup.c b/gdk/gdkpopup.c index bcd8c8ed29..6e45e9f93e 100644 --- a/gdk/gdkpopup.c +++ b/gdk/gdkpopup.c @@ -38,15 +38,6 @@ G_DEFINE_INTERFACE (GdkPopup, gdk_popup, GDK_TYPE_SURFACE) -enum -{ - POPUP_LAYOUT_CHANGED, - - N_SIGNALS -}; - -static guint signals[N_SIGNALS] = { 0 }; - static gboolean gdk_popup_default_present (GdkPopup *popup, int width, @@ -101,25 +92,6 @@ gdk_popup_default_init (GdkPopupInterface *iface) P_("Whether to hide on outside clicks"), FALSE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); - - /** - * GdkPopup::popup-layout-changed - * @popup: the #GdkSurface that was laid out - * - * Emitted when the layout of a popup surface has changed, e.g. if the popup - * layout was reactive and after the parent moved causing the popover to end - * up partially off-screen. - */ - signals[POPUP_LAYOUT_CHANGED] = - g_signal_new (g_intern_static_string ("popup-layout-changed"), - GDK_TYPE_POPUP, - G_SIGNAL_RUN_FIRST, - 0, - NULL, - NULL, - NULL, - G_TYPE_NONE, - 0); } /** diff --git a/gdk/macos/gdkmacossurface.c b/gdk/macos/gdkmacossurface.c index 4f0617e878..705ae1d5ce 100644 --- a/gdk/macos/gdkmacossurface.c +++ b/gdk/macos/gdkmacossurface.c @@ -85,7 +85,7 @@ _gdk_macos_surface_reposition_children (GdkMacosSurface *self) } if (GDK_IS_POPUP (self) && self->did_initial_present) - g_signal_emit_by_name (self, "popup-layout-changed"); + gdk_surface_request_layout (GDK_SURFACE (self)); } static void diff --git a/gtk/gtkpopover.c b/gtk/gtkpopover.c index 7fcfac9b66..21e7f2e716 100644 --- a/gtk/gtkpopover.c +++ b/gtk/gtkpopover.c @@ -766,16 +766,6 @@ surface_event (GdkSurface *surface, return TRUE; } -static void -popup_layout_changed (GdkSurface *surface, - GtkWidget *widget) -{ - GtkPopover *popover = GTK_POPOVER (widget); - GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover); - - update_popover_layout (popover, gdk_popup_layout_ref (priv->layout)); -} - static void gtk_popover_activate_default (GtkPopover *popover) { @@ -894,7 +884,6 @@ gtk_popover_realize (GtkWidget *widget) g_signal_connect_swapped (priv->surface, "notify::mapped", G_CALLBACK (surface_mapped_changed), widget); g_signal_connect (priv->surface, "render", G_CALLBACK (surface_render), widget); g_signal_connect (priv->surface, "event", G_CALLBACK (surface_event), widget); - g_signal_connect (priv->surface, "popup-layout-changed", G_CALLBACK (popup_layout_changed), widget); GTK_WIDGET_CLASS (gtk_popover_parent_class)->realize (widget); @@ -919,7 +908,6 @@ gtk_popover_unrealize (GtkWidget *widget) g_signal_handlers_disconnect_by_func (priv->surface, surface_mapped_changed, widget); g_signal_handlers_disconnect_by_func (priv->surface, surface_render, widget); g_signal_handlers_disconnect_by_func (priv->surface, surface_event, widget); - g_signal_handlers_disconnect_by_func (priv->surface, popup_layout_changed, widget); gdk_surface_set_widget (priv->surface, NULL); gdk_surface_destroy (priv->surface); g_clear_object (&priv->surface); From 96450ed9cc8b993b4d54bbc9e87eb078bc64ad21 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Fri, 4 Dec 2020 08:04:58 +0100 Subject: [PATCH 53/87] gdk/surface: Emit layout event while frozen The allocation of popups are part dependent of the allocation of the root, which means the root must still be allocated when updates are frozen, otherwise we'll try to allocate non-laid out popups. --- gdk/gdksurface.c | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/gdk/gdksurface.c b/gdk/gdksurface.c index 2c52e551f3..fd2d0772e8 100644 --- a/gdk/gdksurface.c +++ b/gdk/gdksurface.c @@ -1336,9 +1336,6 @@ gdk_surface_layout_on_clock (GdkFrameClock *clock, if (!GDK_SURFACE_IS_MAPPED (surface)) return; - if (surface->update_freeze_count) - return; - surface->pending_phases &= ~GDK_FRAME_CLOCK_PHASE_LAYOUT; class = GDK_SURFACE_GET_CLASS (surface); @@ -1358,13 +1355,6 @@ gdk_surface_request_layout (GdkSurface *surface) if (class->request_layout) class->request_layout (surface); - if (surface->update_freeze_count || - gdk_surface_is_toplevel_frozen (surface)) - { - surface->pending_phases |= GDK_FRAME_CLOCK_PHASE_LAYOUT; - return; - } - frame_clock = gdk_surface_get_frame_clock (surface); g_return_if_fail (frame_clock); From 3b66f635238f5f69a7cd96d60f2a832ac285ab5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Fri, 4 Dec 2020 09:12:22 +0100 Subject: [PATCH 54/87] gtk/popover: Request fake motion events for popovers too As with GtkWindow, we need to request fake motion events if allocation changes, to emulate motion events given the new layout. --- gtk/gtkpopover.c | 42 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 40 insertions(+), 2 deletions(-) diff --git a/gtk/gtkpopover.c b/gtk/gtkpopover.c index 21e7f2e716..0aff55995d 100644 --- a/gtk/gtkpopover.c +++ b/gtk/gtkpopover.c @@ -589,6 +589,34 @@ gtk_popover_native_check_resize (GtkNative *native) present_popup (popover); } +static void +maybe_request_motion_event (GtkPopover *popover) +{ + GtkWidget *widget = GTK_WIDGET (popover); + GtkRoot *root = gtk_widget_get_root (widget); + GdkSeat *seat; + GdkDevice *device; + GtkWidget *focus; + GdkSurface *focus_surface; + + seat = gdk_display_get_default_seat (gtk_widget_get_display (widget)); + if (!seat) + return; + + + device = gdk_seat_get_pointer (seat); + focus = gtk_window_lookup_pointer_focus_widget (GTK_WINDOW (root), + device, NULL); + if (!focus) + return; + + if (!gtk_widget_is_ancestor (focus, GTK_WIDGET (popover))) + return; + + focus_surface = gtk_native_get_surface (gtk_widget_get_native (focus)); + gdk_surface_request_motion (focus_surface); +} + static void gtk_popover_native_layout (GtkNative *native, int width, @@ -601,9 +629,19 @@ gtk_popover_native_layout (GtkNative *native, update_popover_layout (popover, gdk_popup_layout_ref (priv->layout)); if (gtk_widget_needs_allocate (widget)) - gtk_widget_allocate (widget, width, height, -1, NULL); + { + gtk_widget_allocate (widget, width, height, -1, NULL); + + /* This fake motion event is needed for getting up to date pointer focus + * and coordinates when tho pointer didn't move but the layout changed + * within the popover. + */ + maybe_request_motion_event (popover); + } else - gtk_widget_ensure_allocate (widget); + { + gtk_widget_ensure_allocate (widget); + } } static gboolean From f7fceab40b1d39fc7f8f2f1ac648a3ac3fad0cd1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Fri, 4 Dec 2020 09:15:53 +0100 Subject: [PATCH 55/87] gtk/entry: Remove emoji chooser field It wasn't ever set. --- gtk/gtkentry.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/gtk/gtkentry.c b/gtk/gtkentry.c index a4cf3b30f8..e96fe4506f 100644 --- a/gtk/gtkentry.c +++ b/gtk/gtkentry.c @@ -181,7 +181,6 @@ struct _GtkEntryPrivate GtkWidget *text; GtkWidget *progress_widget; - GtkWidget *emoji_chooser; guint show_emoji_icon : 1; guint editing_canceled : 1; /* Only used by GtkCellRendererText */ @@ -1452,8 +1451,6 @@ gtk_entry_dispose (GObject *object) } g_clear_pointer (&priv->text, gtk_widget_unparent); - g_clear_pointer (&priv->emoji_chooser, gtk_widget_unparent); - G_OBJECT_CLASS (gtk_entry_parent_class)->dispose (object); } @@ -1803,9 +1800,6 @@ gtk_entry_size_allocate (GtkWidget *widget, if (completion) _gtk_entry_completion_resize_popup (completion); } - - if (priv->emoji_chooser) - gtk_native_check_resize (GTK_NATIVE (priv->emoji_chooser)); } static void From 2cddec77983c02a711ad3920b0d3dba825be617b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Fri, 4 Dec 2020 09:20:50 +0100 Subject: [PATCH 56/87] gtk/popover: Use gtk_popover_present() instead of going via GtkNative This makes it more explicit that managers of popovers make it "present". --- demos/gtk-demo/demo3widget.c | 4 ++-- demos/gtk-demo/suggestionentry.c | 2 +- docs/reference/gtk/gtk4-sections.txt | 1 + gtk/gtkcolorswatch.c | 2 +- gtk/gtkcolumnviewtitle.c | 2 +- gtk/gtkcombobox.c | 2 +- gtk/gtkdropdown.c | 2 +- gtk/gtkemojichooser.c | 2 +- gtk/gtkentrycompletion.c | 3 ++- gtk/gtkfilechooserwidget.c | 5 +++-- gtk/gtklabel.c | 2 +- gtk/gtklayoutmanager.c | 5 ++++- gtk/gtkmenubutton.c | 2 +- gtk/gtkplacessidebar.c | 4 ++-- gtk/gtkplacesviewrow.c | 3 ++- gtk/gtkpopover.c | 10 +++++++--- gtk/gtkpopover.h | 3 +++ gtk/gtkpopovermenubar.c | 2 +- gtk/gtkscalebutton.c | 2 +- gtk/gtktext.c | 10 +++++----- gtk/gtktextview.c | 8 ++++---- gtk/gtktreeview.c | 2 +- 22 files changed, 46 insertions(+), 32 deletions(-) diff --git a/demos/gtk-demo/demo3widget.c b/demos/gtk-demo/demo3widget.c index 3a309927e8..7a13f698c4 100644 --- a/demos/gtk-demo/demo3widget.c +++ b/demos/gtk-demo/demo3widget.c @@ -97,9 +97,9 @@ demo3_widget_size_allocate (GtkWidget *widget, /* Since we are not using a layout manager (who would do this * for us), we need to allocate a size for our menu by calling - * gtk_native_check_resize(). + * gtk_popover_present(). */ - gtk_native_check_resize (GTK_NATIVE (self->menu)); + gtk_popover_present (GTK_POPOVER (self->menu)); } static void diff --git a/demos/gtk-demo/suggestionentry.c b/demos/gtk-demo/suggestionentry.c index a0a926979f..8a0b3aa082 100644 --- a/demos/gtk-demo/suggestionentry.c +++ b/demos/gtk-demo/suggestionentry.c @@ -474,7 +474,7 @@ suggestion_entry_size_allocate (GtkWidget *widget, gtk_widget_set_size_request (self->popup, gtk_widget_get_allocated_width (GTK_WIDGET (self)), -1); gtk_widget_queue_resize (self->popup); - gtk_native_check_resize (GTK_NATIVE (self->popup)); + gtk_popover_present (GTK_POPOVER (self->popup)); } static gboolean diff --git a/docs/reference/gtk/gtk4-sections.txt b/docs/reference/gtk/gtk4-sections.txt index f28400f795..8fea2b3c53 100644 --- a/docs/reference/gtk/gtk4-sections.txt +++ b/docs/reference/gtk/gtk4-sections.txt @@ -6112,6 +6112,7 @@ GtkPopover gtk_popover_new gtk_popover_popup gtk_popover_popdown +gtk_popover_present gtk_popover_set_child gtk_popover_get_child gtk_popover_set_pointing_to diff --git a/gtk/gtkcolorswatch.c b/gtk/gtkcolorswatch.c index 7addf913d3..a451fd827f 100644 --- a/gtk/gtkcolorswatch.c +++ b/gtk/gtkcolorswatch.c @@ -322,7 +322,7 @@ swatch_size_allocate (GtkWidget *widget, }, -1); if (swatch->popover) - gtk_native_check_resize (GTK_NATIVE (swatch->popover)); + gtk_popover_present (GTK_POPOVER (swatch->popover)); } static void diff --git a/gtk/gtkcolumnviewtitle.c b/gtk/gtkcolumnviewtitle.c index c76c8a9a8b..160b1b7604 100644 --- a/gtk/gtkcolumnviewtitle.c +++ b/gtk/gtkcolumnviewtitle.c @@ -144,7 +144,7 @@ gtk_column_view_title_size_allocate (GtkWidget *widget, } if (self->popup_menu) - gtk_native_check_resize (GTK_NATIVE (self->popup_menu)); + gtk_popover_present (GTK_POPOVER (self->popup_menu)); } static void diff --git a/gtk/gtkcombobox.c b/gtk/gtkcombobox.c index 30b4693078..0b2801e633 100644 --- a/gtk/gtkcombobox.c +++ b/gtk/gtkcombobox.c @@ -376,7 +376,7 @@ gtk_combo_box_size_allocate (GtkWidget *widget, gtk_widget_set_size_request (priv->popup_widget, MAX (width, menu_width), -1); - gtk_native_check_resize (GTK_NATIVE (priv->popup_widget)); + gtk_popover_present (GTK_POPOVER (priv->popup_widget)); } static void diff --git a/gtk/gtkdropdown.c b/gtk/gtkdropdown.c index 32e5c21c08..669305d539 100644 --- a/gtk/gtkdropdown.c +++ b/gtk/gtkdropdown.c @@ -383,7 +383,7 @@ gtk_drop_down_size_allocate (GtkWidget *widget, gtk_widget_set_size_request (self->popup, width, -1); gtk_widget_queue_resize (self->popup); - gtk_native_check_resize (GTK_NATIVE (self->popup)); + gtk_popover_present (GTK_POPOVER (self->popup)); } static gboolean diff --git a/gtk/gtkemojichooser.c b/gtk/gtkemojichooser.c index a41c4b49d5..11bf196e0a 100644 --- a/gtk/gtkemojichooser.c +++ b/gtk/gtkemojichooser.c @@ -113,7 +113,7 @@ gtk_emoji_chooser_child_size_allocate (GtkWidget *widget, GTK_WIDGET_CLASS (gtk_emoji_chooser_child_parent_class)->size_allocate (widget, width, height, baseline); if (child->variations) - gtk_native_check_resize (GTK_NATIVE (child->variations)); + gtk_popover_present (GTK_POPOVER (child->variations)); } static gboolean diff --git a/gtk/gtkentrycompletion.c b/gtk/gtkentrycompletion.c index 6c197a4572..6092e036c5 100644 --- a/gtk/gtkentrycompletion.c +++ b/gtk/gtkentrycompletion.c @@ -1150,7 +1150,8 @@ _gtk_entry_completion_resize_popup (GtkEntryCompletion *completion) NULL, FALSE, 0.0, 0.0); gtk_tree_path_free (path); } - gtk_native_check_resize (GTK_NATIVE (completion->popup_window)); + + gtk_popover_present (GTK_POPOVER (completion->popup_window)); } static void diff --git a/gtk/gtkfilechooserwidget.c b/gtk/gtkfilechooserwidget.c index dd1cb284cf..18d4033892 100644 --- a/gtk/gtkfilechooserwidget.c +++ b/gtk/gtkfilechooserwidget.c @@ -7225,10 +7225,11 @@ gtk_file_chooser_widget_size_allocate (GtkWidget *widget, GtkFileChooserWidget *impl = GTK_FILE_CHOOSER_WIDGET (widget); GTK_WIDGET_CLASS (gtk_file_chooser_widget_parent_class)->size_allocate (widget, width, height, baseline); + if (impl->browse_files_popover) - gtk_native_check_resize (GTK_NATIVE (impl->browse_files_popover)); + gtk_popover_present (GTK_POPOVER (impl->browse_files_popover)); if (impl->rename_file_popover) - gtk_native_check_resize (GTK_NATIVE (impl->rename_file_popover)); + gtk_popover_present (GTK_POPOVER (impl->rename_file_popover)); } static void diff --git a/gtk/gtklabel.c b/gtk/gtklabel.c index 58c7431814..61fd639a1f 100644 --- a/gtk/gtklabel.c +++ b/gtk/gtklabel.c @@ -3276,7 +3276,7 @@ gtk_label_size_allocate (GtkWidget *widget, } if (self->popup_menu) - gtk_native_check_resize (GTK_NATIVE (self->popup_menu)); + gtk_popover_present (GTK_POPOVER (self->popup_menu)); } static void diff --git a/gtk/gtklayoutmanager.c b/gtk/gtklayoutmanager.c index d0e4037b2f..483d92ce93 100644 --- a/gtk/gtklayoutmanager.c +++ b/gtk/gtklayoutmanager.c @@ -77,6 +77,7 @@ #include "gtklayoutchild.h" #include "gtkwidgetprivate.h" #include "gtknative.h" +#include "gtkpopover.h" #ifdef G_ENABLE_DEBUG #define LAYOUT_MANAGER_WARN_NOT_IMPLEMENTED(m,method) G_STMT_START { \ @@ -363,7 +364,9 @@ allocate_native_children (GtkWidget *widget) child != NULL; child = _gtk_widget_get_next_sibling (child)) { - if (GTK_IS_NATIVE (child)) + if (GTK_IS_POPOVER (child)) + gtk_popover_present (GTK_POPOVER (child)); + else if (GTK_IS_NATIVE (child)) gtk_native_check_resize (GTK_NATIVE (child)); } } diff --git a/gtk/gtkmenubutton.c b/gtk/gtkmenubutton.c index 93376641c0..d37ee47fc1 100644 --- a/gtk/gtkmenubutton.c +++ b/gtk/gtkmenubutton.c @@ -319,7 +319,7 @@ gtk_menu_button_size_allocate (GtkWidget *widget, &(GtkAllocation) { 0, 0, width, height }, baseline); if (self->popover) - gtk_native_check_resize (GTK_NATIVE (self->popover)); + gtk_popover_present (GTK_POPOVER (self->popover)); } static gboolean diff --git a/gtk/gtkplacessidebar.c b/gtk/gtkplacessidebar.c index b90b748b85..41df790cc6 100644 --- a/gtk/gtkplacessidebar.c +++ b/gtk/gtkplacessidebar.c @@ -4076,10 +4076,10 @@ gtk_places_sidebar_size_allocate (GtkWidget *widget, baseline); if (sidebar->popover) - gtk_native_check_resize (GTK_NATIVE (sidebar->popover)); + gtk_popover_present (GTK_POPOVER (sidebar->popover)); if (sidebar->rename_popover) - gtk_native_check_resize (GTK_NATIVE (sidebar->rename_popover)); + gtk_popover_present (GTK_POPOVER (sidebar->rename_popover)); } static void diff --git a/gtk/gtkplacesviewrow.c b/gtk/gtkplacesviewrow.c index 8d8611bc1c..51af16c465 100644 --- a/gtk/gtkplacesviewrow.c +++ b/gtk/gtkplacesviewrow.c @@ -36,6 +36,7 @@ #include "gtkstack.h" #include "gtktypebuiltins.h" #include "gtknative.h" +#include "gtkpopover.h" #else #include #endif @@ -319,7 +320,7 @@ gtk_places_view_row_size_allocate (GtkWidget *widget, GTK_WIDGET_CLASS (gtk_places_view_row_parent_class)->size_allocate (widget, width, height, baseline); if (menu) - gtk_native_check_resize (GTK_NATIVE (menu)); + gtk_popover_present (GTK_POPOVER (menu)); } static void diff --git a/gtk/gtkpopover.c b/gtk/gtkpopover.c index 0aff55995d..5d923645df 100644 --- a/gtk/gtkpopover.c +++ b/gtk/gtkpopover.c @@ -577,10 +577,9 @@ present_popup (GtkPopover *popover) return FALSE; } -static void -gtk_popover_native_check_resize (GtkNative *native) +void +gtk_popover_present (GtkPopover *popover) { - GtkPopover *popover = GTK_POPOVER (native); GtkWidget *widget = GTK_WIDGET (popover); if (!_gtk_widget_get_alloc_needed (widget)) @@ -589,6 +588,11 @@ gtk_popover_native_check_resize (GtkNative *native) present_popup (popover); } +static void +gtk_popover_native_check_resize (GtkNative *native) +{ +} + static void maybe_request_motion_event (GtkPopover *popover) { diff --git a/gtk/gtkpopover.h b/gtk/gtkpopover.h index 9cb1208761..1ecb8e57c3 100644 --- a/gtk/gtkpopover.h +++ b/gtk/gtkpopover.h @@ -121,6 +121,9 @@ GDK_AVAILABLE_IN_ALL void gtk_popover_set_default_widget (GtkPopover *popover, GtkWidget *widget); +GDK_AVAILABLE_IN_ALL +void gtk_popover_present (GtkPopover *popover); + G_END_DECLS diff --git a/gtk/gtkpopovermenubar.c b/gtk/gtkpopovermenubar.c index 447dc5fa65..b98489e8ce 100644 --- a/gtk/gtkpopovermenubar.c +++ b/gtk/gtkpopovermenubar.c @@ -320,7 +320,7 @@ gtk_popover_menu_bar_item_size_allocate (GtkWidget *widget, &(GtkAllocation) { 0, 0, width, height }, baseline); - gtk_native_check_resize (GTK_NATIVE (item->popover)); + gtk_popover_present (GTK_POPOVER (item->popover)); } static void diff --git a/gtk/gtkscalebutton.c b/gtk/gtkscalebutton.c index bb39e7f19b..67c6044fc2 100644 --- a/gtk/gtkscalebutton.c +++ b/gtk/gtkscalebutton.c @@ -1001,5 +1001,5 @@ gtk_scale_button_size_allocate (GtkWidget *widget, &(GtkAllocation) { 0, 0, width, height }, baseline); - gtk_native_check_resize (GTK_NATIVE (priv->dock)); + gtk_popover_present (GTK_POPOVER (priv->dock)); } diff --git a/gtk/gtktext.c b/gtk/gtktext.c index 8452344f60..427bb9a891 100644 --- a/gtk/gtktext.c +++ b/gtk/gtktext.c @@ -2448,21 +2448,21 @@ gtk_text_size_allocate (GtkWidget *widget, chooser = g_object_get_data (G_OBJECT (self), "gtk-emoji-chooser"); if (chooser) - gtk_native_check_resize (GTK_NATIVE (chooser)); + gtk_popover_present (GTK_POPOVER (chooser)); gtk_text_update_handles (self); if (priv->emoji_completion) - gtk_native_check_resize (GTK_NATIVE (priv->emoji_completion)); + gtk_popover_present (GTK_POPOVER (priv->emoji_completion)); if (priv->magnifier_popover) - gtk_native_check_resize (GTK_NATIVE (priv->magnifier_popover)); + gtk_popover_present (GTK_POPOVER (priv->magnifier_popover)); if (priv->popup_menu) - gtk_native_check_resize (GTK_NATIVE (priv->popup_menu)); + gtk_popover_present (GTK_POPOVER (priv->popup_menu)); if (priv->selection_bubble) - gtk_native_check_resize (GTK_NATIVE (priv->selection_bubble)); + gtk_popover_present (GTK_POPOVER (priv->selection_bubble)); if (priv->text_handles[TEXT_HANDLE_CURSOR]) gtk_native_check_resize (GTK_NATIVE (priv->text_handles[TEXT_HANDLE_CURSOR])); diff --git a/gtk/gtktextview.c b/gtk/gtktextview.c index 4816bef439..5e26378748 100644 --- a/gtk/gtktextview.c +++ b/gtk/gtktextview.c @@ -4528,13 +4528,13 @@ gtk_text_view_size_allocate (GtkWidget *widget, chooser = g_object_get_data (G_OBJECT (text_view), "gtk-emoji-chooser"); if (chooser) - gtk_native_check_resize (GTK_NATIVE (chooser)); + gtk_popover_present (GTK_POPOVER (chooser)); if (priv->magnifier_popover) - gtk_native_check_resize (GTK_NATIVE (priv->magnifier_popover)); + gtk_popover_present (GTK_POPOVER (priv->magnifier_popover)); if (priv->popup_menu) - gtk_native_check_resize (GTK_NATIVE (priv->popup_menu)); + gtk_popover_present (GTK_POPOVER (priv->popup_menu)); if (priv->text_handles[TEXT_HANDLE_CURSOR]) gtk_native_check_resize (GTK_NATIVE (priv->text_handles[TEXT_HANDLE_CURSOR])); @@ -4543,7 +4543,7 @@ gtk_text_view_size_allocate (GtkWidget *widget, gtk_native_check_resize (GTK_NATIVE (priv->text_handles[TEXT_HANDLE_SELECTION_BOUND])); if (priv->selection_bubble) - gtk_native_check_resize (GTK_NATIVE (priv->selection_bubble)); + gtk_popover_present (GTK_POPOVER (priv->selection_bubble)); } static void diff --git a/gtk/gtktreeview.c b/gtk/gtktreeview.c index def80e5776..dda21f82aa 100644 --- a/gtk/gtktreeview.c +++ b/gtk/gtktreeview.c @@ -2654,7 +2654,7 @@ gtk_tree_view_size_allocate (GtkWidget *widget, } if (priv->search_popover) - gtk_native_check_resize (GTK_NATIVE (priv->search_popover)); + gtk_popover_present (GTK_POPOVER (priv->search_popover)); } /* Grabs the focus and unsets the GTK_TREE_VIEW_DRAW_KEYFOCUS flag */ From 369b03a3d80760935d991828376c1dca7ac9a4a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Fri, 4 Dec 2020 09:23:46 +0100 Subject: [PATCH 57/87] gtk/window: Don't go via GtkNative when presenting It'll only call directly back into GtkWindow's toplevel present handling code. --- gtk/gtkwindow.c | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/gtk/gtkwindow.c b/gtk/gtkwindow.c index 07c23b0761..4940f9f217 100644 --- a/gtk/gtkwindow.c +++ b/gtk/gtkwindow.c @@ -1873,17 +1873,6 @@ gtk_window_native_get_surface_transform (GtkNative *native, static void gtk_window_native_check_resize (GtkNative *native) { - GtkWidget *widget = GTK_WIDGET (native); - gint64 before G_GNUC_UNUSED; - - before = GDK_PROFILER_CURRENT_TIME; - - if (!_gtk_widget_get_alloc_needed (widget)) - gtk_widget_ensure_allocate (widget); - else if (gtk_widget_get_visible (widget)) - gtk_window_present_toplevel (GTK_WINDOW (native)); - - gdk_profiler_end_mark (before, "size allocation", ""); } static void @@ -3749,7 +3738,7 @@ gtk_window_show (GtkWidget *widget) gtk_widget_realize (widget); - gtk_native_check_resize (GTK_NATIVE (window)); + gtk_window_present_toplevel (window); gtk_widget_map (widget); From 517bc0db843238455ef138bc9fc89f836833388c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Fri, 4 Dec 2020 10:53:16 +0100 Subject: [PATCH 58/87] gtk/texthandle: Use gtk_text_handle_present() instead of GtkNative --- gtk/gtklayoutmanager.c | 3 +++ gtk/gtktext.c | 4 ++-- gtk/gtktexthandle.c | 8 ++++++-- gtk/gtktexthandleprivate.h | 2 ++ gtk/gtktextview.c | 4 ++-- 5 files changed, 15 insertions(+), 6 deletions(-) diff --git a/gtk/gtklayoutmanager.c b/gtk/gtklayoutmanager.c index 483d92ce93..1a7b7afbf6 100644 --- a/gtk/gtklayoutmanager.c +++ b/gtk/gtklayoutmanager.c @@ -78,6 +78,7 @@ #include "gtkwidgetprivate.h" #include "gtknative.h" #include "gtkpopover.h" +#include "gtktexthandleprivate.h" #ifdef G_ENABLE_DEBUG #define LAYOUT_MANAGER_WARN_NOT_IMPLEMENTED(m,method) G_STMT_START { \ @@ -366,6 +367,8 @@ allocate_native_children (GtkWidget *widget) { if (GTK_IS_POPOVER (child)) gtk_popover_present (GTK_POPOVER (child)); + else if (GTK_IS_TEXT_HANDLE (child)) + gtk_text_handle_present (GTK_TEXT_HANDLE (child)); else if (GTK_IS_NATIVE (child)) gtk_native_check_resize (GTK_NATIVE (child)); } diff --git a/gtk/gtktext.c b/gtk/gtktext.c index 427bb9a891..c39e007d61 100644 --- a/gtk/gtktext.c +++ b/gtk/gtktext.c @@ -2465,10 +2465,10 @@ gtk_text_size_allocate (GtkWidget *widget, gtk_popover_present (GTK_POPOVER (priv->selection_bubble)); if (priv->text_handles[TEXT_HANDLE_CURSOR]) - gtk_native_check_resize (GTK_NATIVE (priv->text_handles[TEXT_HANDLE_CURSOR])); + gtk_text_handle_present (priv->text_handles[TEXT_HANDLE_CURSOR]); if (priv->text_handles[TEXT_HANDLE_SELECTION_BOUND]) - gtk_native_check_resize (GTK_NATIVE (priv->text_handles[TEXT_HANDLE_SELECTION_BOUND])); + gtk_text_handle_present (priv->text_handles[TEXT_HANDLE_SELECTION_BOUND]); } static void diff --git a/gtk/gtktexthandle.c b/gtk/gtktexthandle.c index 6d80068088..8d7deddb3e 100644 --- a/gtk/gtktexthandle.c +++ b/gtk/gtktexthandle.c @@ -167,8 +167,12 @@ gtk_text_handle_present_surface (GtkTextHandle *handle) static void gtk_text_handle_native_check_resize (GtkNative *native) { - GtkTextHandle *handle = GTK_TEXT_HANDLE (native); - GtkWidget *widget = GTK_WIDGET (native); +} + +void +gtk_text_handle_present (GtkTextHandle *handle) +{ + GtkWidget *widget = GTK_WIDGET (handle); if (!_gtk_widget_get_alloc_needed (widget)) gtk_widget_ensure_allocate (widget); diff --git a/gtk/gtktexthandleprivate.h b/gtk/gtktexthandleprivate.h index 0a02eac12e..c01fedcd50 100644 --- a/gtk/gtktexthandleprivate.h +++ b/gtk/gtktexthandleprivate.h @@ -35,6 +35,8 @@ typedef enum GtkTextHandle * gtk_text_handle_new (GtkWidget *parent); +void gtk_text_handle_present (GtkTextHandle *handle); + void gtk_text_handle_set_role (GtkTextHandle *handle, GtkTextHandleRole role); GtkTextHandleRole gtk_text_handle_get_role (GtkTextHandle *handle); diff --git a/gtk/gtktextview.c b/gtk/gtktextview.c index 5e26378748..ce097cb586 100644 --- a/gtk/gtktextview.c +++ b/gtk/gtktextview.c @@ -4537,10 +4537,10 @@ gtk_text_view_size_allocate (GtkWidget *widget, gtk_popover_present (GTK_POPOVER (priv->popup_menu)); if (priv->text_handles[TEXT_HANDLE_CURSOR]) - gtk_native_check_resize (GTK_NATIVE (priv->text_handles[TEXT_HANDLE_CURSOR])); + gtk_text_handle_present (priv->text_handles[TEXT_HANDLE_CURSOR]); if (priv->text_handles[TEXT_HANDLE_SELECTION_BOUND]) - gtk_native_check_resize (GTK_NATIVE (priv->text_handles[TEXT_HANDLE_SELECTION_BOUND])); + gtk_text_handle_present (priv->text_handles[TEXT_HANDLE_SELECTION_BOUND]); if (priv->selection_bubble) gtk_popover_present (GTK_POPOVER (priv->selection_bubble)); From 9d3f497a21b37b01ab80ba82b9e4444baaad7968 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Fri, 4 Dec 2020 11:06:25 +0100 Subject: [PATCH 59/87] gtk/tooltipwindow: Use gtk_tooltip_window_present() instead of GtkNative --- gtk/gtklayoutmanager.c | 3 +++ gtk/gtktooltip.c | 2 +- gtk/gtktooltipwindow.c | 8 ++++++-- gtk/gtktooltipwindowprivate.h | 2 ++ 4 files changed, 12 insertions(+), 3 deletions(-) diff --git a/gtk/gtklayoutmanager.c b/gtk/gtklayoutmanager.c index 1a7b7afbf6..5ba6d17021 100644 --- a/gtk/gtklayoutmanager.c +++ b/gtk/gtklayoutmanager.c @@ -79,6 +79,7 @@ #include "gtknative.h" #include "gtkpopover.h" #include "gtktexthandleprivate.h" +#include "gtktooltipwindowprivate.h" #ifdef G_ENABLE_DEBUG #define LAYOUT_MANAGER_WARN_NOT_IMPLEMENTED(m,method) G_STMT_START { \ @@ -369,6 +370,8 @@ allocate_native_children (GtkWidget *widget) gtk_popover_present (GTK_POPOVER (child)); else if (GTK_IS_TEXT_HANDLE (child)) gtk_text_handle_present (GTK_TEXT_HANDLE (child)); + else if (GTK_IS_TOOLTIP_WINDOW (child)) + gtk_tooltip_window_present (GTK_TOOLTIP_WINDOW (child)); else if (GTK_IS_NATIVE (child)) gtk_native_check_resize (GTK_NATIVE (child)); } diff --git a/gtk/gtktooltip.c b/gtk/gtktooltip.c index 392bd0620e..a192d1eb0d 100644 --- a/gtk/gtktooltip.c +++ b/gtk/gtktooltip.c @@ -1024,7 +1024,7 @@ gtk_tooltip_maybe_allocate (GtkNative *native) if (!tooltip || GTK_NATIVE (tooltip->native) != native) return; - gtk_native_check_resize (GTK_NATIVE (tooltip->window)); + gtk_tooltip_window_present (GTK_TOOLTIP_WINDOW (tooltip->window)); } void diff --git a/gtk/gtktooltipwindow.c b/gtk/gtktooltipwindow.c index c4c5b64ecd..a0651e4338 100644 --- a/gtk/gtktooltipwindow.c +++ b/gtk/gtktooltipwindow.c @@ -142,8 +142,12 @@ gtk_tooltip_window_relayout (GtkTooltipWindow *window) static void gtk_tooltip_window_native_check_resize (GtkNative *native) { - GtkTooltipWindow *window = GTK_TOOLTIP_WINDOW (native); - GtkWidget *widget = GTK_WIDGET (native); +} + +void +gtk_tooltip_window_present (GtkTooltipWindow *window) +{ + GtkWidget *widget = GTK_WIDGET (window); if (!_gtk_widget_get_alloc_needed (widget)) { diff --git a/gtk/gtktooltipwindowprivate.h b/gtk/gtktooltipwindowprivate.h index 61e6b91864..651a3cf7c7 100644 --- a/gtk/gtktooltipwindowprivate.h +++ b/gtk/gtktooltipwindowprivate.h @@ -37,6 +37,8 @@ G_DECLARE_FINAL_TYPE (GtkTooltipWindow, gtk_tooltip_window, GTK, TOOLTIP_WINDOW, GtkWidget * gtk_tooltip_window_new (void); +void gtk_tooltip_window_present (GtkTooltipWindow *window); + void gtk_tooltip_window_set_label_markup (GtkTooltipWindow *window, const char *markup); void gtk_tooltip_window_set_label_text (GtkTooltipWindow *window, From 4b2aae99506aec04b8177c205e4c519e5b8be87c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Fri, 4 Dec 2020 11:11:05 +0100 Subject: [PATCH 60/87] gtk/dragicon: Use private gtk_drag_icon_present() instead of GtkNative It didn't even use GtkNative, just the vfunc it set to the interface sturct. --- gtk/gtkdragicon.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/gtk/gtkdragicon.c b/gtk/gtkdragicon.c index 0a39c39ccf..79a8875d1c 100644 --- a/gtk/gtkdragicon.c +++ b/gtk/gtkdragicon.c @@ -149,8 +149,12 @@ gtk_drag_icon_move_resize (GtkDragIcon *icon) static void gtk_drag_icon_native_check_resize (GtkNative *native) { - GtkDragIcon *icon = GTK_DRAG_ICON (native); - GtkWidget *widget = GTK_WIDGET (native); +} + +static void +gtk_drag_icon_present (GtkDragIcon *icon) +{ + GtkWidget *widget = GTK_WIDGET (icon); if (!_gtk_widget_get_alloc_needed (widget)) gtk_widget_ensure_allocate (widget); @@ -285,7 +289,7 @@ gtk_drag_icon_show (GtkWidget *widget) _gtk_widget_set_visible_flag (widget, TRUE); gtk_css_node_validate (gtk_widget_get_css_node (widget)); gtk_widget_realize (widget); - gtk_drag_icon_native_check_resize (GTK_NATIVE (widget)); + gtk_drag_icon_present (GTK_DRAG_ICON (widget)); gtk_widget_map (widget); } From 40a9baa2dbe8344d58ed5c263a062b78dad7d6c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Fri, 4 Dec 2020 11:18:09 +0100 Subject: [PATCH 61/87] gtk/native: Remove gtk_native_check_resize() This is now handle by the corresponding implemenatations using per non-gobject-type API. --- docs/reference/gtk/gtk4-sections.txt | 1 - gtk/gtkdragicon.c | 6 ------ gtk/gtklayoutmanager.c | 3 ++- gtk/gtknative.c | 23 ----------------------- gtk/gtknative.h | 3 --- gtk/gtknativeprivate.h | 2 -- gtk/gtkpopover.c | 6 ------ gtk/gtktexthandle.c | 6 ------ gtk/gtktooltipwindow.c | 8 +------- gtk/gtkwindow.c | 6 ------ 10 files changed, 3 insertions(+), 61 deletions(-) diff --git a/docs/reference/gtk/gtk4-sections.txt b/docs/reference/gtk/gtk4-sections.txt index 8fea2b3c53..909bd1df92 100644 --- a/docs/reference/gtk/gtk4-sections.txt +++ b/docs/reference/gtk/gtk4-sections.txt @@ -6970,7 +6970,6 @@ GtkNative gtk_native_get_for_surface gtk_native_get_surface gtk_native_get_renderer -gtk_native_check_resize gtk_native_get_surface_transform diff --git a/gtk/gtkdragicon.c b/gtk/gtkdragicon.c index 79a8875d1c..6f31fd19cc 100644 --- a/gtk/gtkdragicon.c +++ b/gtk/gtkdragicon.c @@ -146,11 +146,6 @@ gtk_drag_icon_move_resize (GtkDragIcon *icon) } } -static void -gtk_drag_icon_native_check_resize (GtkNative *native) -{ -} - static void gtk_drag_icon_present (GtkDragIcon *icon) { @@ -176,7 +171,6 @@ gtk_drag_icon_native_init (GtkNativeInterface *iface) iface->get_surface = gtk_drag_icon_native_get_surface; iface->get_renderer = gtk_drag_icon_native_get_renderer; iface->get_surface_transform = gtk_drag_icon_native_get_surface_transform; - iface->check_resize = gtk_drag_icon_native_check_resize; iface->layout = gtk_drag_icon_native_layout; } diff --git a/gtk/gtklayoutmanager.c b/gtk/gtklayoutmanager.c index 5ba6d17021..31ce041959 100644 --- a/gtk/gtklayoutmanager.c +++ b/gtk/gtklayoutmanager.c @@ -373,7 +373,8 @@ allocate_native_children (GtkWidget *widget) else if (GTK_IS_TOOLTIP_WINDOW (child)) gtk_tooltip_window_present (GTK_TOOLTIP_WINDOW (child)); else if (GTK_IS_NATIVE (child)) - gtk_native_check_resize (GTK_NATIVE (child)); + g_warning ("Unable to present a to the layout manager unknown auxiliary child surface widget type %s", + G_OBJECT_TYPE_NAME (child)); } } diff --git a/gtk/gtknative.c b/gtk/gtknative.c index 45ad317cbf..00dfd35820 100644 --- a/gtk/gtknative.c +++ b/gtk/gtknative.c @@ -63,11 +63,6 @@ gtk_native_default_get_surface_transform (GtkNative *self, *y = 0; } -static void -gtk_native_default_check_resize (GtkNative *self) -{ -} - static void gtk_native_default_layout (GtkNative *self, int width, @@ -80,7 +75,6 @@ gtk_native_default_init (GtkNativeInterface *iface) { iface->get_renderer = gtk_native_default_get_renderer; iface->get_surface_transform = gtk_native_default_get_surface_transform; - iface->check_resize = gtk_native_default_check_resize; iface->layout = gtk_native_default_layout; quark_gtk_native_private = g_quark_from_static_string ("gtk-native-private"); @@ -225,23 +219,6 @@ gtk_native_get_surface_transform (GtkNative *self, return GTK_NATIVE_GET_IFACE (self)->get_surface_transform (self, x, y); } -/** - * gtk_native_check_resize: - * @self: a #GtkNative - * - * Reposition and resize a #GtkNative. - * - * Widgets need to call this function on their attached - * native widgets when they receive a new size allocation. - */ -void -gtk_native_check_resize (GtkNative *self) -{ - g_return_if_fail (GTK_IS_NATIVE (self)); - - GTK_NATIVE_GET_IFACE (self)->check_resize (self); -} - /** * gtk_native_get_for_surface: * @surface: a #GdkSurface diff --git a/gtk/gtknative.h b/gtk/gtknative.h index ce2ffcb068..18346f32fa 100644 --- a/gtk/gtknative.h +++ b/gtk/gtknative.h @@ -43,9 +43,6 @@ void gtk_native_unrealize (GtkNative *self); GDK_AVAILABLE_IN_ALL GtkNative * gtk_native_get_for_surface (GdkSurface *surface); -GDK_AVAILABLE_IN_ALL -void gtk_native_check_resize (GtkNative *self); - GDK_AVAILABLE_IN_ALL GdkSurface *gtk_native_get_surface (GtkNative *self); diff --git a/gtk/gtknativeprivate.h b/gtk/gtknativeprivate.h index 1016631661..df9b9ffaa6 100644 --- a/gtk/gtknativeprivate.h +++ b/gtk/gtknativeprivate.h @@ -23,8 +23,6 @@ struct _GtkNativeInterface double *x, double *y); - void (* check_resize) (GtkNative *self); - void (* layout) (GtkNative *self, int width, int height); diff --git a/gtk/gtkpopover.c b/gtk/gtkpopover.c index 5d923645df..5d8a01266d 100644 --- a/gtk/gtkpopover.c +++ b/gtk/gtkpopover.c @@ -588,11 +588,6 @@ gtk_popover_present (GtkPopover *popover) present_popup (popover); } -static void -gtk_popover_native_check_resize (GtkNative *native) -{ -} - static void maybe_request_motion_event (GtkPopover *popover) { @@ -1884,7 +1879,6 @@ gtk_popover_native_interface_init (GtkNativeInterface *iface) iface->get_surface = gtk_popover_native_get_surface; iface->get_renderer = gtk_popover_native_get_renderer; iface->get_surface_transform = gtk_popover_native_get_surface_transform; - iface->check_resize = gtk_popover_native_check_resize; iface->layout = gtk_popover_native_layout; } diff --git a/gtk/gtktexthandle.c b/gtk/gtktexthandle.c index 8d7deddb3e..73bd8d5bcc 100644 --- a/gtk/gtktexthandle.c +++ b/gtk/gtktexthandle.c @@ -164,11 +164,6 @@ gtk_text_handle_present_surface (GtkTextHandle *handle) gdk_popup_layout_unref (layout); } -static void -gtk_text_handle_native_check_resize (GtkNative *native) -{ -} - void gtk_text_handle_present (GtkTextHandle *handle) { @@ -199,7 +194,6 @@ gtk_text_handle_native_interface_init (GtkNativeInterface *iface) iface->get_surface = gtk_text_handle_native_get_surface; iface->get_renderer = gtk_text_handle_native_get_renderer; iface->get_surface_transform = gtk_text_handle_native_get_surface_transform; - iface->check_resize = gtk_text_handle_native_check_resize; iface->layout = gtk_text_handle_native_layout; } diff --git a/gtk/gtktooltipwindow.c b/gtk/gtktooltipwindow.c index a0651e4338..55c6a882d1 100644 --- a/gtk/gtktooltipwindow.c +++ b/gtk/gtktooltipwindow.c @@ -139,11 +139,6 @@ gtk_tooltip_window_relayout (GtkTooltipWindow *window) gdk_popup_layout_unref (layout); } -static void -gtk_tooltip_window_native_check_resize (GtkNative *native) -{ -} - void gtk_tooltip_window_present (GtkTooltipWindow *window) { @@ -179,7 +174,6 @@ gtk_tooltip_window_native_init (GtkNativeInterface *iface) iface->get_surface = gtk_tooltip_window_native_get_surface; iface->get_renderer = gtk_tooltip_window_native_get_renderer; iface->get_surface_transform = gtk_tooltip_window_native_get_surface_transform; - iface->check_resize = gtk_tooltip_window_native_check_resize; iface->layout = gtk_tooltip_window_native_layout; } @@ -358,7 +352,7 @@ gtk_tooltip_window_show (GtkWidget *widget) { _gtk_widget_set_visible_flag (widget, TRUE); gtk_widget_realize (widget); - gtk_tooltip_window_native_check_resize (GTK_NATIVE (widget)); + gtk_tooltip_window_present (GTK_TOOLTIP_WINDOW (widget)); gtk_widget_map (widget); } diff --git a/gtk/gtkwindow.c b/gtk/gtkwindow.c index 4940f9f217..70c94ff706 100644 --- a/gtk/gtkwindow.c +++ b/gtk/gtkwindow.c @@ -1870,11 +1870,6 @@ gtk_window_native_get_surface_transform (GtkNative *native, *y = shadow.top - margin_rect->origin.y; } -static void -gtk_window_native_check_resize (GtkNative *native) -{ -} - static void gtk_window_native_layout (GtkNative *native, int width, @@ -1946,7 +1941,6 @@ gtk_window_native_interface_init (GtkNativeInterface *iface) iface->get_surface = gtk_window_native_get_surface; iface->get_renderer = gtk_window_native_get_renderer; iface->get_surface_transform = gtk_window_native_get_surface_transform; - iface->check_resize = gtk_window_native_check_resize; iface->layout = gtk_window_native_layout; } From 8e3ee58e3fcee161d6d1c52f7370800fd48d2bff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Fri, 4 Dec 2020 15:02:59 +0100 Subject: [PATCH 62/87] tests/animated-resizing: Don't try to resize during frame dispatch This will not work on X11 because it's too late to resize, due to resizing being asynchronous i.e. it won't be complete before we need to draw. --- tests/animated-resizing.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/tests/animated-resizing.c b/tests/animated-resizing.c index 0446b29b68..c9a316a560 100644 --- a/tests/animated-resizing.c +++ b/tests/animated-resizing.c @@ -130,10 +130,9 @@ on_frame (double progress) } static gboolean -tick_callback (GtkWidget *widget, - GdkFrameClock *frame_clock, - gpointer user_data) +resize_idle (gpointer user_data) { + GdkFrameClock *frame_clock = user_data; gint64 frame_time = gdk_frame_clock_get_frame_time (frame_clock); double scaled_time; @@ -143,6 +142,16 @@ tick_callback (GtkWidget *widget, scaled_time = (frame_time - start_frame_time) / (CYCLE_TIME * 1000000); on_frame (scaled_time - floor (scaled_time)); + return G_SOURCE_REMOVE; +} + +static gboolean +tick_callback (GtkWidget *widget, + GdkFrameClock *frame_clock, + gpointer user_data) +{ + g_idle_add (resize_idle, frame_clock); + return G_SOURCE_CONTINUE; } @@ -196,7 +205,6 @@ main(int argc, char **argv) cb_no_resize ? "no" : "yes"); window = gtk_window_new (); - gtk_window_set_resizable (GTK_WINDOW (window), FALSE); frame_stats_ensure (GTK_WINDOW (window)); da = gtk_drawing_area_new (); From dfb7ab3352109f3a3313c0f6b20754b3d9eab2ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Fri, 4 Dec 2020 15:40:53 +0100 Subject: [PATCH 63/87] x11/surface: Compute toplevel size outside of frame dispatch We can't compute and resize a toplevel size during dispatch, as resizing on X11 is an asynhronous operation, requiring a configuration event. --- gdk/x11/gdksurface-x11.c | 140 ++++++++++++++++++++++++++++----------- gdk/x11/gdksurface-x11.h | 2 + 2 files changed, 102 insertions(+), 40 deletions(-) diff --git a/gdk/x11/gdksurface-x11.c b/gdk/x11/gdksurface-x11.c index 7a9d30224f..15c296ae45 100644 --- a/gdk/x11/gdksurface-x11.c +++ b/gdk/x11/gdksurface-x11.c @@ -111,6 +111,10 @@ static void gdk_x11_toplevel_state_callback (GdkSurface *surface); static gboolean gdk_x11_toplevel_event_callback (GdkSurface *surface, GdkEvent *gdk_event); +static void gdk_x11_surface_toplevel_resize (GdkSurface *surface, + int width, + int height); + /* Return whether time1 is considered later than time2 as far as xserver * time is concerned. Accounts for wraparound. */ @@ -228,12 +232,67 @@ update_shadow_size (GdkSurface *surface, (guchar *) &data, 4); } +static gboolean +compute_size_idle (gpointer user_data) +{ + GdkSurface *surface = user_data; + GdkX11Surface *impl = GDK_X11_SURFACE (surface); + GdkDisplay *display = gdk_surface_get_display (surface); + GdkMonitor *monitor; + GdkToplevelSize size; + int bounds_width, bounds_height; + int width, height; + + impl->compute_size_source_id = 0; + + if (impl->next_layout.surface_geometry_dirty) + return G_SOURCE_REMOVE; + + if (surface->state & (GDK_TOPLEVEL_STATE_MAXIMIZED & + GDK_TOPLEVEL_STATE_FULLSCREEN & + GDK_TOPLEVEL_STATE_TILED)) + return G_SOURCE_REMOVE; + + 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 (GDK_TOPLEVEL (surface), &size); + + width = size.width; + height = size.height; + if (width != impl->unscaled_width * impl->surface_scale || + height != impl->unscaled_height * impl->surface_scale) + gdk_x11_surface_toplevel_resize (surface, width, height); + + return G_SOURCE_REMOVE; +} + static void gdk_x11_surface_request_layout (GdkSurface *surface) { GdkX11Surface *impl = GDK_X11_SURFACE (surface); - impl->next_layout.surface_geometry_dirty = TRUE; + if (!impl->compute_size_source_id && + GDK_IS_TOPLEVEL (surface)) + { + impl->compute_size_source_id = g_idle_add_full (G_PRIORITY_HIGH - 10, + compute_size_idle, + surface, + NULL); + } } static void @@ -243,48 +302,45 @@ gdk_x11_surface_compute_size (GdkSurface *surface) if (GDK_IS_TOPLEVEL (surface)) { - if (impl->next_layout.surface_geometry_dirty) + GdkDisplay *display = gdk_surface_get_display (surface); + GdkMonitor *monitor; + GdkToplevelSize size; + int bounds_width, bounds_height; + + monitor = gdk_display_get_monitor_at_surface (display, surface); + if (monitor) { - GdkDisplay *display = gdk_surface_get_display (surface); - GdkMonitor *monitor; - GdkToplevelSize size; - int bounds_width, bounds_height; + GdkRectangle workarea; - 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 (GDK_TOPLEVEL (surface), &size); - - if (size.shadow.is_valid) - { - update_shadow_size (surface, - size.shadow.left, - size.shadow.right, - size.shadow.top, - size.shadow.bottom); - } - - surface->width = impl->next_layout.configured_width; - surface->height = impl->next_layout.configured_height; - - _gdk_surface_update_size (surface); - _gdk_x11_surface_update_size (impl); - - impl->next_layout.surface_geometry_dirty = FALSE; + 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 (GDK_TOPLEVEL (surface), &size); + + if (size.shadow.is_valid) + { + update_shadow_size (surface, + size.shadow.left, + size.shadow.right, + size.shadow.top, + size.shadow.bottom); + } + + surface->width = impl->next_layout.configured_width; + surface->height = impl->next_layout.configured_height; + + _gdk_surface_update_size (surface); + _gdk_x11_surface_update_size (impl); + + impl->next_layout.surface_geometry_dirty = FALSE; } else { @@ -1494,6 +1550,8 @@ gdk_x11_surface_withdraw (GdkSurface *surface) static void gdk_x11_surface_hide (GdkSurface *surface) { + GdkX11Surface *impl = GDK_X11_SURFACE (surface); + /* We'll get the unmap notify eventually, and handle it then, * but checking here makes things more consistent if we are * just doing stuff ourself. @@ -1501,6 +1559,8 @@ gdk_x11_surface_hide (GdkSurface *surface) _gdk_x11_surface_grab_check_unmap (surface, NextRequest (GDK_SURFACE_XDISPLAY (surface))); + g_clear_handle_id (&impl->compute_size_source_id, g_source_remove); + gdk_x11_surface_withdraw (surface); } diff --git a/gdk/x11/gdksurface-x11.h b/gdk/x11/gdksurface-x11.h index f6ccfa2f21..1e47827971 100644 --- a/gdk/x11/gdksurface-x11.h +++ b/gdk/x11/gdksurface-x11.h @@ -80,6 +80,8 @@ struct _GdkX11Surface gboolean surface_geometry_dirty; } next_layout; + guint compute_size_source_id; + cairo_surface_t *cairo_surface; int abs_x; From 351d88f7ae1492048988122b7f0d4a8fc2db9294 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Fri, 4 Dec 2020 18:35:01 +0100 Subject: [PATCH 64/87] wayland/surface: Clear shadow width when hiding Not doing this means the next time the same surface is shown, if the shadow size wasn't changed, it wouldn't be sent to the compositor, which then would result in compositor deriving its own window geometry which would include the shadow margin. This fixes an issue where the file chooser dialog would grow each time it opened. --- gdk/wayland/gdksurface-wayland.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/gdk/wayland/gdksurface-wayland.c b/gdk/wayland/gdksurface-wayland.c index b8a1d79f81..d5e777638c 100644 --- a/gdk/wayland/gdksurface-wayland.c +++ b/gdk/wayland/gdksurface-wayland.c @@ -2957,6 +2957,8 @@ gdk_wayland_surface_hide_surface (GdkSurface *surface) unset_transient_for_exported (surface); + impl->last_sent_window_geometry = (GdkRectangle) { 0 }; + _gdk_wayland_surface_clear_saved_size (surface); impl->mapped = FALSE; } From 8396bdb759543442c6bbb9e5b0f4ebd7c26a0fce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Fri, 4 Dec 2020 18:39:22 +0100 Subject: [PATCH 65/87] wayland/surface: Reset last sent min/max size when hiding As with the window geometry, the last sent min/max values must be reset so they are sent again next time the surface is shown. --- gdk/wayland/gdksurface-wayland.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/gdk/wayland/gdksurface-wayland.c b/gdk/wayland/gdksurface-wayland.c index d5e777638c..6ad40c39cd 100644 --- a/gdk/wayland/gdksurface-wayland.c +++ b/gdk/wayland/gdksurface-wayland.c @@ -2958,6 +2958,10 @@ gdk_wayland_surface_hide_surface (GdkSurface *surface) unset_transient_for_exported (surface); impl->last_sent_window_geometry = (GdkRectangle) { 0 }; + impl->last_sent_min_width = 0; + impl->last_sent_min_height = 0; + impl->last_sent_max_width = 0; + impl->last_sent_max_height = 0; _gdk_wayland_surface_clear_saved_size (surface); impl->mapped = FALSE; From ff23a2a58238b1b69142754254c6159b08f7fa4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Sat, 5 Dec 2020 00:07:21 +0100 Subject: [PATCH 66/87] x11: Use resize counting for freezing updates too It's already keep strack of when we're waiting for configure events, so lets reuse it. This fixes an issue where reshown dialogs wouldn't reappear. --- gdk/x11/gdkdisplay-x11.c | 10 ---------- gdk/x11/gdksurface-x11.c | 25 +++++++++++++++++-------- gdk/x11/gdksurface-x11.h | 2 -- 3 files changed, 17 insertions(+), 20 deletions(-) diff --git a/gdk/x11/gdkdisplay-x11.c b/gdk/x11/gdkdisplay-x11.c index 692f85230c..73529906c5 100644 --- a/gdk/x11/gdkdisplay-x11.c +++ b/gdk/x11/gdkdisplay-x11.c @@ -920,16 +920,6 @@ gdk_x11_display_translate_event (GdkEventTranslator *translator, int ty = 0; Window child_window = 0; - if (surface_impl->pending_configure_events == 1) - { - surface_impl->pending_configure_events = 0; - gdk_surface_thaw_updates (surface); - } - else if (surface_impl->pending_configure_events > 1) - { - surface_impl->pending_configure_events--; - } - x = y = 0; gdk_x11_display_error_trap_push (display); if (XTranslateCoordinates (GDK_SURFACE_XDISPLAY (surface), diff --git a/gdk/x11/gdksurface-x11.c b/gdk/x11/gdksurface-x11.c index 15c296ae45..a4b6e5f6ce 100644 --- a/gdk/x11/gdksurface-x11.c +++ b/gdk/x11/gdksurface-x11.c @@ -1626,8 +1626,13 @@ x11_surface_resize (GdkSurface *surface, } else { - if (width * impl->surface_scale != impl->unscaled_width || height * impl->surface_scale != impl->unscaled_height) - surface->resize_count += 1; + if (width * impl->surface_scale != impl->unscaled_width || + height * impl->surface_scale != impl->unscaled_height) + { + surface->resize_count++; + if (surface->resize_count == 1) + gdk_surface_freeze_updates (surface); + } } } @@ -1678,8 +1683,13 @@ x11_surface_move_resize (GdkSurface *surface, } else { - if (width * impl->surface_scale != impl->unscaled_width || height * impl->surface_scale != impl->unscaled_height) - surface->resize_count += 1; + if (width * impl->surface_scale != impl->unscaled_width || + height * impl->surface_scale != impl->unscaled_height) + { + surface->resize_count++; + if (surface->resize_count == 1) + gdk_surface_freeze_updates (surface); + } } } @@ -4244,6 +4254,9 @@ _gdk_x11_moveresize_configure_done (GdkDisplay *display, XEvent *tmp_event; MoveResizeData *mv_resize = get_move_resize_data (display, FALSE); + gdk_surface_thaw_updates (surface); + gdk_surface_request_layout (surface); + if (!mv_resize || surface != mv_resize->moveresize_surface) return FALSE; @@ -5068,10 +5081,6 @@ gdk_x11_toplevel_present (GdkToplevel *toplevel, size.shadow.bottom); } - impl->pending_configure_events++; - if (impl->pending_configure_events == 1) - gdk_surface_freeze_updates (surface); - if (gdk_toplevel_layout_get_maximized (layout)) gdk_x11_surface_maximize (surface); else diff --git a/gdk/x11/gdksurface-x11.h b/gdk/x11/gdksurface-x11.h index 1e47827971..6fd7122ba0 100644 --- a/gdk/x11/gdksurface-x11.h +++ b/gdk/x11/gdksurface-x11.h @@ -72,8 +72,6 @@ struct _GdkX11Surface int unscaled_width; int unscaled_height; - int pending_configure_events; - struct { int configured_width; int configured_height; From 3bbeb891c4cfbbeec86846633027350e87cbd1f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Sat, 5 Dec 2020 00:11:08 +0100 Subject: [PATCH 67/87] gdk/surface: Allow inhibit layout from backend If compute_size() returns TRUE, the layout will not be propagated to GTK. This will be used by the X11 backend to queue asynchronous resizes that shouldn't yet allocate in GTK. --- gdk/gdksurface.c | 5 ++++- gdk/gdksurfaceprivate.h | 2 +- gdk/wayland/gdksurface-wayland.c | 4 +++- gdk/x11/gdksurface-x11.c | 4 +++- 4 files changed, 11 insertions(+), 4 deletions(-) diff --git a/gdk/gdksurface.c b/gdk/gdksurface.c index fd2d0772e8..27b775982c 100644 --- a/gdk/gdksurface.c +++ b/gdk/gdksurface.c @@ -1340,7 +1340,10 @@ gdk_surface_layout_on_clock (GdkFrameClock *clock, class = GDK_SURFACE_GET_CLASS (surface); if (class->compute_size) - class->compute_size (surface); + { + if (class->compute_size (surface)) + return; + } g_signal_emit (surface, signals[LAYOUT], 0, surface->width, surface->height); } diff --git a/gdk/gdksurfaceprivate.h b/gdk/gdksurfaceprivate.h index 4fb40a376b..4c879fc2cb 100644 --- a/gdk/gdksurfaceprivate.h +++ b/gdk/gdksurfaceprivate.h @@ -162,7 +162,7 @@ struct _GdkSurfaceClass GdkGLContext *share, GError **error); void (* request_layout) (GdkSurface *surface); - void (* compute_size) (GdkSurface *surface); + gboolean (* compute_size) (GdkSurface *surface); }; #define GDK_SURFACE_DESTROYED(d) (((GdkSurface *)(d))->destroyed) diff --git a/gdk/wayland/gdksurface-wayland.c b/gdk/wayland/gdksurface-wayland.c index 6ad40c39cd..c152acf3e5 100644 --- a/gdk/wayland/gdksurface-wayland.c +++ b/gdk/wayland/gdksurface-wayland.c @@ -639,7 +639,7 @@ configure_drag_surface_geometry (GdkSurface *surface) impl->scale); } -static void +static gboolean gdk_wayland_surface_compute_size (GdkSurface *surface) { GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface); @@ -655,6 +655,8 @@ gdk_wayland_surface_compute_size (GdkSurface *surface) impl->next_layout.surface_geometry_dirty = FALSE; } + + return FALSE; } static void diff --git a/gdk/x11/gdksurface-x11.c b/gdk/x11/gdksurface-x11.c index a4b6e5f6ce..5e0fc557d8 100644 --- a/gdk/x11/gdksurface-x11.c +++ b/gdk/x11/gdksurface-x11.c @@ -295,7 +295,7 @@ gdk_x11_surface_request_layout (GdkSurface *surface) } } -static void +static gboolean gdk_x11_surface_compute_size (GdkSurface *surface) { GdkX11Surface *impl = GDK_X11_SURFACE (surface); @@ -352,6 +352,8 @@ gdk_x11_surface_compute_size (GdkSurface *surface) impl->next_layout.surface_geometry_dirty = FALSE; } + + return surface->resize_count > 0; } gboolean From 2217cf8ea26a5b1531be06be8d0e88afbc1dce78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Sat, 5 Dec 2020 11:02:58 +0100 Subject: [PATCH 68/87] x11/surface: Remember when there is a pending ConfigureNotify This will be used to decide whether to try to resize windows when . --- gdk/x11/gdkdisplay-x11.c | 1 + gdk/x11/gdksurface-x11.c | 1 + gdk/x11/gdksurface-x11.h | 1 + 3 files changed, 3 insertions(+) diff --git a/gdk/x11/gdkdisplay-x11.c b/gdk/x11/gdkdisplay-x11.c index 73529906c5..31b06ea53f 100644 --- a/gdk/x11/gdkdisplay-x11.c +++ b/gdk/x11/gdkdisplay-x11.c @@ -964,6 +964,7 @@ gdk_x11_display_translate_event (GdkEventTranslator *translator, surface_impl->next_layout.configured_width = configured_width; surface_impl->next_layout.configured_height = configured_height; surface_impl->next_layout.surface_geometry_dirty = TRUE; + surface_impl->next_layout.configure_pending = TRUE; gdk_surface_request_layout (surface); } diff --git a/gdk/x11/gdksurface-x11.c b/gdk/x11/gdksurface-x11.c index 5e0fc557d8..0348e9b85b 100644 --- a/gdk/x11/gdksurface-x11.c +++ b/gdk/x11/gdksurface-x11.c @@ -341,6 +341,7 @@ gdk_x11_surface_compute_size (GdkSurface *surface) _gdk_x11_surface_update_size (impl); impl->next_layout.surface_geometry_dirty = FALSE; + impl->next_layout.configure_pending = FALSE; } else { diff --git a/gdk/x11/gdksurface-x11.h b/gdk/x11/gdksurface-x11.h index 6fd7122ba0..994d125036 100644 --- a/gdk/x11/gdksurface-x11.h +++ b/gdk/x11/gdksurface-x11.h @@ -75,6 +75,7 @@ struct _GdkX11Surface struct { int configured_width; int configured_height; + gboolean configure_pending; gboolean surface_geometry_dirty; } next_layout; From e7ddaf5ed15ac324593879d0ff0ace339b06f6da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Sat, 5 Dec 2020 11:13:07 +0100 Subject: [PATCH 69/87] x11/surface: Compute size after update too This will sometimes mean a frame is skipped if a resize was requested during the update phase of the frame dispatch. Not doing so can cause trying to allocate a window smaller than the minimum size of the widget. --- gdk/x11/gdksurface-x11.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/gdk/x11/gdksurface-x11.c b/gdk/x11/gdksurface-x11.c index 0348e9b85b..8c65183f5d 100644 --- a/gdk/x11/gdksurface-x11.c +++ b/gdk/x11/gdksurface-x11.c @@ -1002,6 +1002,19 @@ on_frame_clock_before_paint (GdkFrameClock *clock, gdk_x11_surface_begin_frame (surface, FALSE); } +static void +on_frame_clock_after_update (GdkFrameClock *clock, + GdkSurface *surface) +{ + GdkX11Surface *impl = GDK_X11_SURFACE (surface); + + if (impl->compute_size_source_id) + { + g_clear_handle_id (&impl->compute_size_source_id, g_source_remove); + compute_size_idle (surface); + } +} + static void on_frame_clock_after_paint (GdkFrameClock *clock, GdkSurface *surface) @@ -1024,6 +1037,8 @@ connect_frame_clock (GdkSurface *surface) g_signal_connect (frame_clock, "before-paint", G_CALLBACK (on_frame_clock_before_paint), surface); + g_signal_connect_after (frame_clock, "update", + G_CALLBACK (on_frame_clock_after_update), surface); g_signal_connect (frame_clock, "after-paint", G_CALLBACK (on_frame_clock_after_paint), surface); @@ -1043,6 +1058,8 @@ disconnect_frame_clock (GdkSurface *surface) g_signal_handlers_disconnect_by_func (frame_clock, on_frame_clock_before_paint, surface); + g_signal_handlers_disconnect_by_func (frame_clock, + on_frame_clock_after_update, surface); g_signal_handlers_disconnect_by_func (frame_clock, on_frame_clock_after_paint, surface); From c791185c20c90d0bc3d2a7d329834bd4a81800a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Sat, 5 Dec 2020 11:30:45 +0100 Subject: [PATCH 70/87] x11/surface: Remember the toplevel layout --- gdk/x11/gdksurface-x11.c | 4 ++++ gdk/x11/gdksurface-x11.h | 2 ++ 2 files changed, 6 insertions(+) diff --git a/gdk/x11/gdksurface-x11.c b/gdk/x11/gdksurface-x11.c index 8c65183f5d..b5db385093 100644 --- a/gdk/x11/gdksurface-x11.c +++ b/gdk/x11/gdksurface-x11.c @@ -1580,6 +1580,7 @@ gdk_x11_surface_hide (GdkSurface *surface) NextRequest (GDK_SURFACE_XDISPLAY (surface))); g_clear_handle_id (&impl->compute_size_source_id, g_source_remove); + g_clear_pointer (&impl->toplevel_layout, gdk_toplevel_layout_unref); gdk_x11_surface_withdraw (surface); } @@ -5054,6 +5055,9 @@ gdk_x11_toplevel_present (GdkToplevel *toplevel, gdk_x11_surface_unminimize (surface); + g_clear_pointer (&impl->toplevel_layout, gdk_toplevel_layout_unref); + impl->toplevel_layout = gdk_toplevel_layout_copy (layout); + monitor = gdk_display_get_monitor_at_surface (display, surface); if (monitor) { diff --git a/gdk/x11/gdksurface-x11.h b/gdk/x11/gdksurface-x11.h index 994d125036..134ebdf617 100644 --- a/gdk/x11/gdksurface-x11.h +++ b/gdk/x11/gdksurface-x11.h @@ -72,6 +72,8 @@ struct _GdkX11Surface int unscaled_width; int unscaled_height; + GdkToplevelLayout *toplevel_layout; + struct { int configured_width; int configured_height; From 994aa41ccc5fd92ddb9014cf8cbffbd7f9f04056 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Sat, 5 Dec 2020 11:38:17 +0100 Subject: [PATCH 71/87] x11/surface: Move the scattered compute-size calls to helper This simplifies things, and fixes issue where we'd resize the wrong time, and miss resizing other times. --- gdk/x11/gdksurface-x11.c | 215 ++++++++++++++++++--------------------- 1 file changed, 100 insertions(+), 115 deletions(-) diff --git a/gdk/x11/gdksurface-x11.c b/gdk/x11/gdksurface-x11.c index b5db385093..e80e0beff4 100644 --- a/gdk/x11/gdksurface-x11.c +++ b/gdk/x11/gdksurface-x11.c @@ -98,6 +98,14 @@ const int _gdk_x11_event_mask_table[21] = ButtonPressMask /* SCROLL; on X mouse wheel events is treated as mouse button 4/5 */ }; +typedef struct { + GdkX11Surface parent_instance; +} GdkX11Toplevel; + +typedef struct { + GdkX11SurfaceClass parent_class; +} GdkX11ToplevelClass; + const int _gdk_x11_event_mask_table_size = G_N_ELEMENTS (_gdk_x11_event_mask_table); /* Forward declarations */ @@ -115,6 +123,10 @@ static void gdk_x11_surface_toplevel_resize (GdkSurface *surface, int width, int height); +static void gdk_x11_surface_set_geometry_hints (GdkSurface *surface, + const GdkGeometry *geometry, + GdkSurfaceHints geom_mask); + /* Return whether time1 is considered later than time2 as far as xserver * time is concerned. Accounts for wraparound. */ @@ -232,26 +244,20 @@ update_shadow_size (GdkSurface *surface, (guchar *) &data, 4); } +#define UPDATE_GEOMETRY TRUE +#define DONT_UPDATE_GEOMETRY FALSE + static gboolean -compute_size_idle (gpointer user_data) +compute_toplevel_size (GdkSurface *surface, + gboolean update_geometry, + int *width, + int *height) { - GdkSurface *surface = user_data; GdkX11Surface *impl = GDK_X11_SURFACE (surface); GdkDisplay *display = gdk_surface_get_display (surface); GdkMonitor *monitor; GdkToplevelSize size; int bounds_width, bounds_height; - int width, height; - - impl->compute_size_source_id = 0; - - if (impl->next_layout.surface_geometry_dirty) - return G_SOURCE_REMOVE; - - if (surface->state & (GDK_TOPLEVEL_STATE_MAXIMIZED & - GDK_TOPLEVEL_STATE_FULLSCREEN & - GDK_TOPLEVEL_STATE_TILED)) - return G_SOURCE_REMOVE; monitor = gdk_display_get_monitor_at_surface (display, surface); if (monitor) @@ -271,10 +277,76 @@ compute_size_idle (gpointer user_data) gdk_toplevel_size_init (&size, bounds_width, bounds_height); gdk_toplevel_notify_compute_size (GDK_TOPLEVEL (surface), &size); - width = size.width; - height = size.height; - if (width != impl->unscaled_width * impl->surface_scale || - height != impl->unscaled_height * impl->surface_scale) + if (size.shadow.is_valid && update_geometry) + { + update_shadow_size (surface, + size.shadow.left, + size.shadow.right, + size.shadow.top, + size.shadow.bottom); + } + + if (update_geometry) + { + GdkGeometry geometry; + GdkSurfaceHints mask; + + if (gdk_toplevel_layout_get_resizable (impl->toplevel_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 = size.width; + geometry.max_height = geometry.min_height = size.height; + mask = GDK_HINT_MIN_SIZE | GDK_HINT_MAX_SIZE; + } + gdk_x11_surface_set_geometry_hints (surface, &geometry, mask); + } + + if (!(surface->state & (GDK_TOPLEVEL_STATE_FULLSCREEN | + GDK_TOPLEVEL_STATE_MAXIMIZED | + GDK_TOPLEVEL_STATE_TILED | + GDK_TOPLEVEL_STATE_TOP_TILED | + GDK_TOPLEVEL_STATE_RIGHT_TILED | + GDK_TOPLEVEL_STATE_BOTTOM_TILED | + GDK_TOPLEVEL_STATE_LEFT_TILED | + GDK_TOPLEVEL_STATE_MINIMIZED)) && + (!impl->next_layout.configure_pending || surface->resize_count > 0)) + { + GdkToplevelX11 *toplevel = _gdk_x11_surface_get_toplevel (surface); + GdkGeometry geometry; + GdkSurfaceHints mask; + + geometry = toplevel->last_geometry_hints; + mask = toplevel->last_geometry_hints_mask; + gdk_surface_constrain_size (&geometry, mask, + size.width, size.height, + &size.width, &size.height); + if ((impl->next_layout.configured_width != size.width || + impl->next_layout.configured_height != size.height)) + { + *width = size.width; + *height = size.height; + + return TRUE; + } + } + + return FALSE; +} + +static gboolean +compute_size_idle (gpointer user_data) +{ + GdkSurface *surface = user_data; + GdkX11Surface *impl = GDK_X11_SURFACE (surface); + int width, height; + + impl->compute_size_source_id = 0; + if (compute_toplevel_size (surface, UPDATE_GEOMETRY, &width, &height)) gdk_x11_surface_toplevel_resize (surface, width, height); return G_SOURCE_REMOVE; @@ -302,43 +374,18 @@ gdk_x11_surface_compute_size (GdkSurface *surface) if (GDK_IS_TOPLEVEL (surface)) { - GdkDisplay *display = gdk_surface_get_display (surface); - GdkMonitor *monitor; - GdkToplevelSize size; - int bounds_width, bounds_height; + int width, height; - monitor = gdk_display_get_monitor_at_surface (display, surface); - if (monitor) + if (compute_toplevel_size (surface, UPDATE_GEOMETRY, &width, &height)) + gdk_x11_surface_toplevel_resize (surface, width, height); + + if (surface->resize_count == 0) { - GdkRectangle workarea; - - gdk_x11_monitor_get_workarea (monitor, &workarea); - bounds_width = workarea.width; - bounds_height = workarea.height; + surface->width = impl->next_layout.configured_width; + surface->height = impl->next_layout.configured_height; + _gdk_surface_update_size (surface); + _gdk_x11_surface_update_size (impl); } - else - { - bounds_width = G_MAXINT; - bounds_height = G_MAXINT; - } - - gdk_toplevel_size_init (&size, bounds_width, bounds_height); - gdk_toplevel_notify_compute_size (GDK_TOPLEVEL (surface), &size); - - if (size.shadow.is_valid) - { - update_shadow_size (surface, - size.shadow.left, - size.shadow.right, - size.shadow.top, - size.shadow.bottom); - } - - surface->width = impl->next_layout.configured_width; - surface->height = impl->next_layout.configured_height; - - _gdk_surface_update_size (surface); - _gdk_x11_surface_update_size (impl); impl->next_layout.surface_geometry_dirty = FALSE; impl->next_layout.configure_pending = FALSE; @@ -1926,10 +1973,6 @@ gdk_x11_surface_enter_leave_monitors (GdkSurface *surface) } } -static void gdk_x11_surface_set_geometry_hints (GdkSurface *surface, - const GdkGeometry *geometry, - GdkSurfaceHints geom_mask); - void _gdk_x11_surface_set_surface_scale (GdkSurface *surface, int scale) @@ -4880,14 +4923,6 @@ gdk_x11_popup_iface_init (GdkPopupInterface *iface) iface->get_position_y = gdk_x11_popup_get_position_y; } -typedef struct { - GdkX11Surface parent_instance; -} GdkX11Toplevel; - -typedef struct { - GdkX11SurfaceClass parent_class; -} GdkX11ToplevelClass; - static void gdk_x11_toplevel_iface_init (GdkToplevelInterface *iface); G_DEFINE_TYPE_WITH_CODE (GdkX11Toplevel, gdk_x11_toplevel, GDK_TYPE_X11_SURFACE, @@ -5039,13 +5074,7 @@ gdk_x11_toplevel_present (GdkToplevel *toplevel, { GdkSurface *surface = GDK_SURFACE (toplevel); GdkX11Surface *impl = GDK_X11_SURFACE (surface); - 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; if (surface->destroyed) @@ -5058,52 +5087,8 @@ gdk_x11_toplevel_present (GdkToplevel *toplevel, g_clear_pointer (&impl->toplevel_layout, gdk_toplevel_layout_unref); impl->toplevel_layout = gdk_toplevel_layout_copy (layout); - 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 = 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_x11_surface_set_geometry_hints (surface, &geometry, mask); - gdk_surface_constrain_size (&geometry, mask, width, height, &width, &height); - gdk_x11_surface_toplevel_resize (surface, width, height); - - if (size.shadow.is_valid) - { - update_shadow_size (surface, - size.shadow.left, - size.shadow.right, - size.shadow.top, - size.shadow.bottom); - } + if (compute_toplevel_size (surface, DONT_UPDATE_GEOMETRY, &width, &height)) + gdk_x11_surface_toplevel_resize (surface, width, height); if (gdk_toplevel_layout_get_maximized (layout)) gdk_x11_surface_maximize (surface); From fd01723470aa694f5f0b25929d2434846bbb1535 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Sat, 5 Dec 2020 11:40:47 +0100 Subject: [PATCH 72/87] x11/surface: Avoid resizing if computed size didn't change This fixes an issue where we'd resize to the previous window size during interactive resize. --- gdk/x11/gdksurface-x11.c | 6 +++++- gdk/x11/gdksurface-x11.h | 3 +++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/gdk/x11/gdksurface-x11.c b/gdk/x11/gdksurface-x11.c index e80e0beff4..6680312563 100644 --- a/gdk/x11/gdksurface-x11.c +++ b/gdk/x11/gdksurface-x11.c @@ -325,11 +325,15 @@ compute_toplevel_size (GdkSurface *surface, gdk_surface_constrain_size (&geometry, mask, size.width, size.height, &size.width, &size.height); - if ((impl->next_layout.configured_width != size.width || + if ((impl->last_computed_width != size.width || + impl->last_computed_height != size.height) && + (impl->next_layout.configured_width != size.width || impl->next_layout.configured_height != size.height)) { *width = size.width; *height = size.height; + impl->last_computed_width = size.width; + impl->last_computed_height = size.height; return TRUE; } diff --git a/gdk/x11/gdksurface-x11.h b/gdk/x11/gdksurface-x11.h index 134ebdf617..0830407dd0 100644 --- a/gdk/x11/gdksurface-x11.h +++ b/gdk/x11/gdksurface-x11.h @@ -72,6 +72,9 @@ struct _GdkX11Surface int unscaled_width; int unscaled_height; + int last_computed_width; + int last_computed_height; + GdkToplevelLayout *toplevel_layout; struct { From 27077d5be8b1040a1ff1a0bb94d60249514a436b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Sat, 5 Dec 2020 11:44:51 +0100 Subject: [PATCH 73/87] gtk/window: Make 'default-size' adapt to configured size This commit changes the behavior of window size computation and the default size properties to: * The default-width and default-height properties are updated to the current window size unless the size is fixed by e.g. being maxmized, tiled etc. * The compute-size semantics are to just pick the default size, or if not adequate, use the measured size, and consequently update the default size, unless unresizable. * gtk_window_get_size() is removed, what's more likely relevant is the gtk_window_get_default_size() which will now contain more sensible values. Various places that used gtk_window_get_size() were updated to use gtk_window_get_default_size() to remember and restore previous sizes. This also changes the default value of 'default-width' and 'default-height' from -1 to 0. The gtk builder simplify tool is taught how to omit when the default size is set to both -1 and 0. --- demos/gtk-demo/application.c | 2 +- gtk/gtkfilechooserdialog.c | 2 +- gtk/gtkwindow.c | 599 ++++---------------------- gtk/tools/gtk-builder-tool-simplify.c | 9 + 4 files changed, 83 insertions(+), 529 deletions(-) diff --git a/demos/gtk-demo/application.c b/demos/gtk-demo/application.c index a03e5c2c66..f1bca0523d 100644 --- a/demos/gtk-demo/application.c +++ b/demos/gtk-demo/application.c @@ -465,7 +465,7 @@ demo_application_window_size_allocate (GtkWidget *widget, baseline); if (!window->maximized && !window->fullscreen) - gtk_window_get_size (GTK_WINDOW (window), &window->width, &window->height); + gtk_window_get_default_size (GTK_WINDOW (window), &window->width, &window->height); } static void diff --git a/gtk/gtkfilechooserdialog.c b/gtk/gtkfilechooserdialog.c index 6cff44ec93..b571a46f1e 100644 --- a/gtk/gtkfilechooserdialog.c +++ b/gtk/gtkfilechooserdialog.c @@ -628,7 +628,7 @@ save_dialog_geometry (GtkFileChooserDialog *dialog) window = GTK_WINDOW (dialog); - gtk_window_get_size (window, &width, &height); + gtk_window_get_default_size (window, &width, &height); g_settings_get (settings, SETTINGS_KEY_WINDOW_SIZE, "(ii)", &old_width, &old_height); if (old_width != width || old_height != height) diff --git a/gtk/gtkwindow.c b/gtk/gtkwindow.c index 70c94ff706..b03d5a7bb2 100644 --- a/gtk/gtkwindow.c +++ b/gtk/gtkwindow.c @@ -170,6 +170,9 @@ typedef struct GdkDisplay *display; GtkApplication *application; + int default_width; + int default_height; + char *startup_id; char *title; @@ -318,12 +321,6 @@ typedef struct { struct _GtkWindowGeometryInfo { - /* Default size - used only the FIRST time we map a window, - * only if > 0. - */ - int default_width; - int default_height; - GtkWindowLastGeometryInfo last; }; @@ -373,6 +370,10 @@ static int gtk_window_focus (GtkWidget *widget, static void gtk_window_move_focus (GtkWidget *widget, GtkDirectionType dir); +static void gtk_window_get_remembered_size (GtkWindow *window, + int *width, + int *height); + static void gtk_window_real_activate_default (GtkWindow *window); static void gtk_window_real_activate_focus (GtkWindow *window); static void gtk_window_keys_changed (GtkWindow *window); @@ -387,18 +388,6 @@ static void gtk_window_transient_parent_unrealized (GtkWidget *parent, static GtkWindowGeometryInfo* gtk_window_get_geometry_info (GtkWindow *window, gboolean create); -static void gtk_window_update_fixed_size (GtkWindow *window, - GdkGeometry *new_geometry, - int new_width, - int new_height); -static void gtk_window_compute_hints (GtkWindow *window, - GdkGeometry *new_geometry, - guint *new_flags); -static void gtk_window_compute_configure_request (GtkWindow *window, - GdkRectangle *request, - GdkGeometry *geometry, - guint *flags); - static void gtk_window_set_default_size_internal (GtkWindow *window, gboolean change_width, int width, @@ -753,17 +742,17 @@ gtk_window_class_init (GtkWindowClass *klass) window_props[PROP_DEFAULT_WIDTH] = g_param_spec_int ("default-width", P_("Default Width"), - P_("The default width of the window, used when initially showing the window"), + P_("The default width of the window"), -1, G_MAXINT, - -1, + 0, GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY); window_props[PROP_DEFAULT_HEIGHT] = g_param_spec_int ("default-height", P_("Default Height"), - P_("The default height of the window, used when initially showing the window"), + P_("The default height of the window"), -1, G_MAXINT, - -1, + 0, GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY); window_props[PROP_DESTROY_WITH_PARENT] = @@ -1583,11 +1572,13 @@ gtk_window_set_property (GObject *object, gtk_window_set_default_size_internal (window, TRUE, g_value_get_int (value), FALSE, -1); + gtk_widget_queue_resize (GTK_WIDGET (window)); break; case PROP_DEFAULT_HEIGHT: gtk_window_set_default_size_internal (window, FALSE, -1, TRUE, g_value_get_int (value)); + gtk_widget_queue_resize (GTK_WIDGET (window)); break; case PROP_DESTROY_WITH_PARENT: gtk_window_set_destroy_with_parent (window, g_value_get_boolean (value)); @@ -1645,7 +1636,6 @@ gtk_window_get_property (GObject *object, switch (prop_id) { - GtkWindowGeometryInfo *info; case PROP_TITLE: g_value_set_string (value, priv->title); break; @@ -1656,18 +1646,10 @@ gtk_window_get_property (GObject *object, g_value_set_boolean (value, priv->modal); break; case PROP_DEFAULT_WIDTH: - info = gtk_window_get_geometry_info (window, FALSE); - if (!info) - g_value_set_int (value, -1); - else - g_value_set_int (value, info->default_width); + g_value_set_int (value, priv->default_width); break; case PROP_DEFAULT_HEIGHT: - info = gtk_window_get_geometry_info (window, FALSE); - if (!info) - g_value_set_int (value, -1); - else - g_value_set_int (value, info->default_height); + g_value_set_int (value, priv->default_height); break; case PROP_DESTROY_WITH_PARENT: g_value_set_boolean (value, priv->destroy_with_parent); @@ -2733,8 +2715,6 @@ gtk_window_get_geometry_info (GtkWindow *window, { info = g_new0 (GtkWindowGeometryInfo, 1); - info->default_width = -1; - info->default_height = -1; info->last.configure_request.x = 0; info->last.configure_request.y = 0; info->last.configure_request.width = -1; @@ -3368,48 +3348,32 @@ gtk_window_set_default_size_internal (GtkWindow *window, gboolean change_height, int height) { - GtkWindowGeometryInfo *info; + GtkWindowPrivate *priv = gtk_window_get_instance_private (window); g_return_if_fail (change_width == FALSE || width >= -1); g_return_if_fail (change_height == FALSE || height >= -1); - info = gtk_window_get_geometry_info (window, TRUE); - g_object_freeze_notify (G_OBJECT (window)); if (change_width) { - if (width == 0) - width = 1; - - if (width < 0) - width = -1; - - if (info->default_width != width) + if (priv->default_width != width) { - info->default_width = width; + priv->default_width = width; g_object_notify_by_pspec (G_OBJECT (window), window_props[PROP_DEFAULT_WIDTH]); } } if (change_height) { - if (height == 0) - height = 1; - - if (height < 0) - height = -1; - - if (info->default_height != height) + if (priv->default_height != height) { - info->default_height = height; + priv->default_height = height; g_object_notify_by_pspec (G_OBJECT (window), window_props[PROP_DEFAULT_HEIGHT]); } } g_object_thaw_notify (G_OBJECT (window)); - - gtk_widget_queue_resize (GTK_WIDGET (window)); } /** @@ -3451,6 +3415,7 @@ gtk_window_set_default_size (GtkWindow *window, g_return_if_fail (height >= -1); gtk_window_set_default_size_internal (window, TRUE, width, TRUE, height); + gtk_widget_queue_resize (GTK_WIDGET (window)); } /** @@ -3459,7 +3424,7 @@ gtk_window_set_default_size (GtkWindow *window, * @width: (out) (allow-none): location to store the default width, or %NULL * @height: (out) (allow-none): location to store the default height, or %NULL * - * Gets the default size of the window. A value of -1 for the width or + * Gets the default size of the window. A value of 0 for the width or * height indicates that a default size has not been explicitly set * for that dimension, so the “natural” size of the window will be * used. @@ -3470,93 +3435,9 @@ gtk_window_get_default_size (GtkWindow *window, int *width, int *height) { - GtkWindowGeometryInfo *info; - g_return_if_fail (GTK_IS_WINDOW (window)); - info = gtk_window_get_geometry_info (window, FALSE); - - if (width) - *width = info ? info->default_width : -1; - - if (height) - *height = info ? info->default_height : -1; -} - -/** - * gtk_window_get_size: - * @window: a #GtkWindow - * @width: (out) (optional): return location for width, or %NULL - * @height: (out) (optional): return location for height, or %NULL - * - * Obtains the current size of @window. - * - * If @window is not visible on screen, this function return the size GTK - * will suggest to the [window manager][gtk-X11-arch] for the initial window - * size (but this is not reliably the same as the size the window manager - * will actually select). See: gtk_window_set_default_size(). - * - * This function will return the logical size of the #GtkWindow, - * excluding the widgets used in client side decorations; there is, - * however, no guarantee that the result will be completely accurate - * because client side decoration may include widgets that depend on - * the user preferences and that may not be visible at the time you - * call this function. - * - * The dimensions returned by this function are suitable for being - * stored across sessions; use gtk_window_set_default_size() to - * restore them when before showing the window. - * - * |[ - * static void - * on_size_allocate (GtkWidget *widget, - * const GtkAllocation *allocation, - * int baseline) - * { - * int new_width, new_height; - * - * gtk_window_get_size (GTK_WINDOW (widget), &new_width, &new_height); - * - * // ... - * } - * ]| - */ -void -gtk_window_get_size (GtkWindow *window, - int *width, - int *height) -{ - GtkWindowPrivate *priv = gtk_window_get_instance_private (window); - int w, h; - - g_return_if_fail (GTK_IS_WINDOW (window)); - - if (width == NULL && height == NULL) - return; - - if (_gtk_widget_get_mapped (GTK_WIDGET (window))) - { - w = gdk_surface_get_width (priv->surface); - h = gdk_surface_get_height (priv->surface); - } - else - { - GdkRectangle configure_request; - - gtk_window_compute_configure_request (window, - &configure_request, - NULL, NULL); - - w = configure_request.width; - h = configure_request.height; - } - - gtk_window_update_csd_size (window, &w, &h, EXCLUDE_CSD_SIZE); - - if (width) - *width = w; - if (height) - *height = h; + gtk_window_get_remembered_size (window, width, height); } static gboolean @@ -3873,107 +3754,15 @@ gtk_window_unmap (GtkWidget *widget) gtk_widget_unmap (child); } -/* (Note: Replace "size" with "width" or "height". Also, the request - * mode is honoured.) - * For selecting the default window size, the following conditions - * should hold (in order of importance): - * - the size is not below the minimum size - * Windows cannot be resized below their minimum size, so we must - * ensure we don’t do that either. - * - the size is not above the natural size - * It seems weird to allocate more than this in an initial guess. - * - the size does not exceed that of a maximized window - * We want to see the whole window after all. - * (Note that this may not be possible to achieve due to imperfect - * information from the windowing system.) - */ - -static void -gtk_window_guess_default_size (GtkWindow *window, - int *width, - int *height) -{ - GtkWindowPrivate *priv = gtk_window_get_instance_private (window); - GtkWidget *widget; - GdkSurface *surface; - GdkDisplay *display; - GdkMonitor *monitor = NULL; - GdkRectangle geometry; - int minimum, natural; - - widget = GTK_WIDGET (window); - display = gtk_widget_get_display (widget); - surface = priv->surface; - - 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 - { - geometry.width = G_MAXINT; - geometry.height = G_MAXINT; - } - - *width = geometry.width; - *height = geometry.height; - - if (gtk_widget_get_request_mode (widget) == GTK_SIZE_REQUEST_WIDTH_FOR_HEIGHT) - { - 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 */ - { - 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)); - } -} - static void gtk_window_get_remembered_size (GtkWindow *window, int *width, int *height) { - GtkWindowGeometryInfo *info; + GtkWindowPrivate *priv = gtk_window_get_instance_private (window); - *width = 0; - *height = 0; - - info = gtk_window_get_geometry_info (window, FALSE); - if (info) - { - /* MAX() works even if the last request is unset with -1 */ - *width = MAX (*width, info->last.configure_request.width); - *height = MAX (*height, info->last.configure_request.height); - } + *width = priv->default_width; + *height = priv->default_height; } static void @@ -4204,6 +3993,24 @@ gtk_window_compute_default_size (GtkWindow *window, } } +static gboolean +should_remember_size (GtkWindow *window) +{ + GtkWindowPrivate *priv = gtk_window_get_instance_private (window); + + if (!priv->resizable) + return FALSE; + + return !(priv->state & (GDK_TOPLEVEL_STATE_FULLSCREEN | + GDK_TOPLEVEL_STATE_MAXIMIZED | + GDK_TOPLEVEL_STATE_TILED | + GDK_TOPLEVEL_STATE_TOP_TILED | + GDK_TOPLEVEL_STATE_RIGHT_TILED | + GDK_TOPLEVEL_STATE_BOTTOM_TILED | + GDK_TOPLEVEL_STATE_LEFT_TILED | + GDK_TOPLEVEL_STATE_MINIMIZED)); +} + static void toplevel_compute_size (GdkToplevel *toplevel, GdkToplevelSize *size, @@ -4211,15 +4018,12 @@ toplevel_compute_size (GdkToplevel *toplevel, { GtkWindow *window = GTK_WINDOW (widget); GtkWindowPrivate *priv = gtk_window_get_instance_private (window); - GtkWindowGeometryInfo *info; int width, height; GtkBorder shadow; int bounds_width, bounds_height; int min_width, min_height; int nat_width, nat_height; - info = gtk_window_get_geometry_info (window, FALSE); - gdk_toplevel_size_get_bounds (size, &bounds_width, &bounds_height); gtk_window_compute_default_size (window, @@ -4227,89 +4031,32 @@ toplevel_compute_size (GdkToplevel *toplevel, &min_width, &min_height, &nat_width, &nat_height); - if (priv->need_default_size) - { - int remembered_width; - int remembered_height; + width = priv->default_width; + height = priv->default_height; - /* No longer use the default settings */ - priv->need_default_size = FALSE; + if (width <= 0) + width = nat_width; + if (height <= 0) + height = nat_height; - gtk_window_get_remembered_size (window, - &remembered_width, &remembered_height); - width = MAX (nat_width, remembered_width); - height = MAX (nat_height, remembered_height); + if (width < min_width) + width = min_width; + if (height < min_height) + height = min_height; - gtk_window_update_csd_size (window, - &width, &height, - INCLUDE_CSD_SIZE); - - /* Override with default size */ - if (info) - { - 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; - } - - info = gtk_window_get_geometry_info (window, TRUE); - info->last.configure_request.width = width; - info->last.configure_request.height = height; - } - else if (!priv->resizable) - { - if (info && - info->default_width > 0 && - info->default_height > 0) - { - width = info->default_width; - height = info->default_height; - gtk_window_update_csd_size (window, &width, &height, - INCLUDE_CSD_SIZE); - } - else - { - width = nat_width; - height = nat_height; - gtk_window_update_csd_size (window, &width, &height, - INCLUDE_CSD_SIZE); - } - } - else - { - /* Default to keeping current size */ - gtk_window_get_remembered_size (window, &width, &height); - } - - if (priv->maximized || priv->fullscreen) - { - /* Unless we are maximized or fullscreen */ - gtk_window_get_remembered_size (window, &width, &height); - } - - /* 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); + if (should_remember_size (window)) + gtk_window_set_default_size_internal (window, TRUE, width, TRUE, height); + gtk_window_update_csd_size (window, + &width, &height, + INCLUDE_CSD_SIZE); gtk_window_update_csd_size (window, &min_width, &min_height, INCLUDE_CSD_SIZE); gdk_toplevel_size_set_min_size (size, min_width, min_height); - gdk_toplevel_size_set_size (size, - MAX (min_width, width), - MAX (min_height, height)); + gdk_toplevel_size_set_size (size, width, height); if (priv->use_client_shadow) { @@ -4698,24 +4445,23 @@ surface_size_changed (GtkWidget *widget, int width, int height) { - GtkWindowPrivate *priv = gtk_window_get_instance_private (GTK_WINDOW (widget)); + GtkWindow *window = GTK_WINDOW (widget); check_scale_changed (GTK_WINDOW (widget)); - if (!(priv->state & (GDK_TOPLEVEL_STATE_FULLSCREEN | - GDK_TOPLEVEL_STATE_MAXIMIZED | - GDK_TOPLEVEL_STATE_TILED | - GDK_TOPLEVEL_STATE_TOP_TILED | - GDK_TOPLEVEL_STATE_RIGHT_TILED | - GDK_TOPLEVEL_STATE_BOTTOM_TILED | - GDK_TOPLEVEL_STATE_LEFT_TILED | - GDK_TOPLEVEL_STATE_MINIMIZED))) + if (should_remember_size (window)) { - GtkWindowGeometryInfo *info; + int width_to_remember; + int height_to_remember; - info = gtk_window_get_geometry_info (GTK_WINDOW (widget), TRUE); - info->last.configure_request.width = width; - info->last.configure_request.height = height; + width_to_remember = width; + height_to_remember = height; + gtk_window_update_csd_size (window, + &width_to_remember, &height_to_remember, + EXCLUDE_CSD_SIZE); + gtk_window_set_default_size_internal (window, + TRUE, width_to_remember, + TRUE, height_to_remember); } gtk_widget_queue_allocate (widget); @@ -5200,207 +4946,6 @@ _gtk_window_unset_focus_and_default (GtkWindow *window, g_object_unref (window); } -/********************************* - * Functions related to resizing * - *********************************/ - -/* This function doesn't constrain to geometry hints */ -static void -gtk_window_compute_configure_request_size (GtkWindow *window, - guint flags, - int *width, - int *height) -{ - GtkWindowPrivate *priv = gtk_window_get_instance_private (window); - GtkWindowGeometryInfo *info; - int w, h; - - /* Preconditions: - * - we've done a size request - */ - info = gtk_window_get_geometry_info (window, FALSE); - - if (priv->need_default_size) - { - gtk_window_guess_default_size (window, width, height); - gtk_window_get_remembered_size (window, &w, &h); - *width = MAX (*width, w); - *height = MAX (*height, h); - - /* 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); - } - - if (priv->maximized || priv->fullscreen) - { - /* Unless we are maximized or fullscreen */ - gtk_window_get_remembered_size (window, width, height); - } - - /* 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); - -} - -static void -gtk_window_compute_configure_request (GtkWindow *window, - GdkRectangle *request, - GdkGeometry *geometry, - guint *flags) -{ - GdkGeometry new_geometry; - guint new_flags; - int w, h; - GtkWindowGeometryInfo *info; - int x, y; - - gtk_window_compute_hints (window, &new_geometry, &new_flags); - gtk_window_compute_configure_request_size (window, - new_flags, - &w, &h); - gtk_window_update_fixed_size (window, &new_geometry, w, h); - gdk_surface_constrain_size (&new_geometry, new_flags, - w, h, - &w, &h); - - info = gtk_window_get_geometry_info (window, FALSE); - - /* by default, don't change position requested */ - if (info) - { - x = info->last.configure_request.x; - y = info->last.configure_request.y; - } - else - { - x = 0; - y = 0; - } - - request->x = x; - request->y = y; - request->width = w; - request->height = h; - - if (geometry) - *geometry = new_geometry; - if (flags) - *flags = new_flags; -} - -/* For non-resizable windows, make sure the given width/height fits - * in the geometry constrains and update the geometry hints to match - * the given width/height if not. - * This is to make sure that non-resizable windows get the default - * width/height if set, but can still grow if their content requires. - * - * Note: Fixed size windows with a default size set will not shrink - * smaller than the default size when their content requires less size. - */ -static void -gtk_window_update_fixed_size (GtkWindow *window, - GdkGeometry *new_geometry, - int new_width, - int new_height) -{ - GtkWindowPrivate *priv = gtk_window_get_instance_private (window); - GtkWindowGeometryInfo *info; - gboolean has_size_request; - - /* Adjust the geometry hints for non-resizable windows only */ - has_size_request = gtk_widget_has_size_request (GTK_WIDGET (window)); - if (priv->resizable || has_size_request) - return; - - info = gtk_window_get_geometry_info (window, FALSE); - if (info) - { - 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 > -1) - { - int w = MAX (MAX (default_width_csd, new_width), new_geometry->min_width); - new_geometry->min_width = w; - new_geometry->max_width = w; - } - - if (info->default_height > -1) - { - int h = MAX (MAX (default_height_csd, new_height), new_geometry->min_height); - new_geometry->min_height = h; - new_geometry->max_height = h; - } - } -} - -/* Compute the set of geometry hints and flags for a window - * based on the application set geometry, and requisition - * of the window. gtk_widget_get_preferred_size() must have been - * called first. - */ -static void -gtk_window_compute_hints (GtkWindow *window, - GdkGeometry *new_geometry, - guint *new_flags) -{ - GtkWindowPrivate *priv = gtk_window_get_instance_private (window); - GtkWidget *widget; - GtkRequisition requisition; - GtkBorder shadow; - - widget = GTK_WIDGET (window); - - /* Use a good size for unresizable widgets, otherwise the minimum one. */ - if (priv->resizable) - gtk_widget_get_preferred_size (widget, &requisition, NULL); - else - gtk_window_guess_default_size (window, &requisition.width, &requisition.height); - - *new_flags = 0; - - get_shadow_width (window, &shadow); - *new_flags |= GDK_HINT_MIN_SIZE; - new_geometry->min_width = requisition.width + shadow.left + shadow.right; - new_geometry->min_height = requisition.height + shadow.top + shadow.bottom; - - if (!priv->resizable) - { - *new_flags |= GDK_HINT_MAX_SIZE; - - new_geometry->max_width = new_geometry->min_width; - new_geometry->max_height = new_geometry->min_height; - } -} - #undef INCLUDE_CSD_SIZE #undef EXCLUDE_CSD_SIZE diff --git a/gtk/tools/gtk-builder-tool-simplify.c b/gtk/tools/gtk-builder-tool-simplify.c index 868d0dc49a..add00fe833 100644 --- a/gtk/tools/gtk-builder-tool-simplify.c +++ b/gtk/tools/gtk-builder-tool-simplify.c @@ -455,6 +455,15 @@ value_is_default (Element *element, ret = g_value_get_boolean (&value) == default_value; } + else if (pspec->owner_type == GTK_TYPE_WINDOW && + (g_str_equal (pspec->name, "default-width") || + g_str_equal (pspec->name, "default-height"))) + { + int default_size; + + default_size = g_value_get_int (&value); + ret = default_size <= 0; + } else ret = g_param_value_defaults (pspec, &value); } From eb0eac0f0316b767dd834b423e89c2d7c0bf1c80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Sat, 5 Dec 2020 12:11:25 +0100 Subject: [PATCH 74/87] gtk/window: Make R/O is-maximized R/W maximized prop This makes it possible to set 'maximized' to true in .ui files, and the window will show up maximized. gtk_window_is_maximized() will return the intended maximized state until actually mapped, it will then show the actual maximized state. The same applies to reading the property. --- gtk/gtkwindow.c | 48 ++++++++++++++++++++++++++++++++--------- gtk/gtkwindowcontrols.c | 2 +- 2 files changed, 39 insertions(+), 11 deletions(-) diff --git a/gtk/gtkwindow.c b/gtk/gtkwindow.c index b03d5a7bb2..27c9067e37 100644 --- a/gtk/gtkwindow.c +++ b/gtk/gtkwindow.c @@ -284,7 +284,7 @@ enum { PROP_MNEMONICS_VISIBLE, PROP_FOCUS_VISIBLE, - PROP_IS_MAXIMIZED, + PROP_MAXIMIZED, LAST_ARG }; @@ -862,12 +862,12 @@ gtk_window_class_init (GtkWindowClass *klass) GTK_TYPE_WINDOW, GTK_PARAM_READWRITE|G_PARAM_CONSTRUCT|G_PARAM_EXPLICIT_NOTIFY); - window_props[PROP_IS_MAXIMIZED] = - g_param_spec_boolean ("is-maximized", + window_props[PROP_MAXIMIZED] = + g_param_spec_boolean ("maximized", P_("Is maximized"), P_("Whether the window is maximized"), FALSE, - GTK_PARAM_READABLE); + GTK_PARAM_READWRITE|G_PARAM_CONSTRUCT|G_PARAM_EXPLICIT_NOTIFY); /** * GtkWindow:application: @@ -1093,6 +1093,9 @@ gtk_window_class_init (GtkWindowClass *klass) * immediately (or at all), as an effect of calling * gtk_window_maximize() or gtk_window_unmaximize(). * + * If the window isn't yet mapped, the value returned will whether the + * initial requested state is maximized. + * * Returns: whether the window has a maximized state. */ gboolean @@ -1102,7 +1105,10 @@ gtk_window_is_maximized (GtkWindow *window) g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE); - return priv->maximized; + if (priv->surface && gdk_surface_get_mapped (priv->surface)) + return priv->maximized; + else + return priv->maximize_initially; } void @@ -1613,6 +1619,12 @@ gtk_window_set_property (GObject *object, case PROP_FOCUS_VISIBLE: gtk_window_set_focus_visible (window, g_value_get_boolean (value)); break; + case PROP_MAXIMIZED: + if (g_value_get_boolean (value)) + gtk_window_maximize (window); + else + gtk_window_unmaximize (window); + break; case PROP_FOCUS_WIDGET: gtk_window_set_focus (window, g_value_get_object (value)); break; @@ -1687,7 +1699,7 @@ gtk_window_get_property (GObject *object, case PROP_FOCUS_VISIBLE: g_value_set_boolean (value, priv->focus_visible); break; - case PROP_IS_MAXIMIZED: + case PROP_MAXIMIZED: g_value_set_boolean (value, gtk_window_is_maximized (window)); break; case PROP_FOCUS_WIDGET: @@ -4420,7 +4432,7 @@ surface_state_changed (GtkWidget *widget) priv->maximized = (new_surface_state & GDK_TOPLEVEL_STATE_MAXIMIZED) ? TRUE : FALSE; priv->maximize_initially = priv->maximized; - g_object_notify_by_pspec (G_OBJECT (widget), window_props[PROP_IS_MAXIMIZED]); + g_object_notify_by_pspec (G_OBJECT (widget), window_props[PROP_MAXIMIZED]); } update_edge_constraints (window, new_surface_state); @@ -5107,19 +5119,28 @@ gtk_window_unminimize (GtkWindow *window) * initially. * * You can track the result of this operation via the #GdkToplevel:state - * property, or by listening to notifications on the #GtkWindow:is-maximized + * property, or by listening to notifications on the #GtkWindow:maximized * property. */ void gtk_window_maximize (GtkWindow *window) { GtkWindowPrivate *priv = gtk_window_get_instance_private (window); + gboolean was_maximized_initially; g_return_if_fail (GTK_IS_WINDOW (window)); + was_maximized_initially = priv->maximize_initially; priv->maximize_initially = TRUE; - gtk_window_update_toplevel (window); + if (priv->surface && gdk_surface_get_mapped (priv->surface)) + { + gtk_window_update_toplevel (window); + } + else if (!was_maximized_initially) + { + g_object_notify_by_pspec (G_OBJECT (window), window_props[PROP_MAXIMIZED]); + } } /** @@ -5134,19 +5155,26 @@ gtk_window_maximize (GtkWindow *window) * end up unmaximized. Just don’t write code that crashes if not. * * You can track the result of this operation via the #GdkToplevel:state - * property, or by listening to notifications on the #GtkWindow:is-maximized + * property, or by listening to notifications on the #GtkWindow:maximized * property. */ void gtk_window_unmaximize (GtkWindow *window) { GtkWindowPrivate *priv = gtk_window_get_instance_private (window); + gboolean was_maximized_initially; g_return_if_fail (GTK_IS_WINDOW (window)); + was_maximized_initially = priv->maximize_initially; priv->maximize_initially = FALSE; gtk_window_update_toplevel (window); + + if (priv->surface && gdk_surface_get_mapped (priv->surface)) + gtk_window_update_toplevel (window); + else if (was_maximized_initially) + g_object_notify_by_pspec (G_OBJECT (window), window_props[PROP_MAXIMIZED]); } /** diff --git a/gtk/gtkwindowcontrols.c b/gtk/gtkwindowcontrols.c index 69dfe82534..c288c4ed75 100644 --- a/gtk/gtkwindowcontrols.c +++ b/gtk/gtkwindowcontrols.c @@ -377,7 +377,7 @@ window_notify_cb (GtkWindowControls *self, { if (pspec->name == I_("deletable") || pspec->name == I_("icon-name") || - pspec->name == I_("is-maximized") || + pspec->name == I_("maximized") || pspec->name == I_("modal") || pspec->name == I_("resizable") || pspec->name == I_("scale-factor") || From 2e5eeb6b925621486328b1410373ec8bd324d78c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Sat, 5 Dec 2020 12:22:25 +0100 Subject: [PATCH 75/87] gtk/window: Add 'fullscreen' prop and gtk_window_is_fullscreen() This makes it possible to set 'fullscreen' to 'true' in a .ui file to start an application in fullscreen mode. --- gtk/gtkwindow.c | 63 ++++++++++++++++++++++++++++++++++++++++++++++++- gtk/gtkwindow.h | 3 +++ 2 files changed, 65 insertions(+), 1 deletion(-) diff --git a/gtk/gtkwindow.c b/gtk/gtkwindow.c index 27c9067e37..176ae22bf5 100644 --- a/gtk/gtkwindow.c +++ b/gtk/gtkwindow.c @@ -285,6 +285,7 @@ enum { PROP_FOCUS_VISIBLE, PROP_MAXIMIZED, + PROP_FULLSCREEN, LAST_ARG }; @@ -869,6 +870,13 @@ gtk_window_class_init (GtkWindowClass *klass) FALSE, GTK_PARAM_READWRITE|G_PARAM_CONSTRUCT|G_PARAM_EXPLICIT_NOTIFY); + window_props[PROP_FULLSCREEN] = + g_param_spec_boolean ("fullscreen", + P_("Is fullscreen"), + P_("Whether the window is fullscreen"), + FALSE, + GTK_PARAM_READWRITE|G_PARAM_CONSTRUCT|G_PARAM_EXPLICIT_NOTIFY); + /** * GtkWindow:application: * @@ -1111,6 +1119,36 @@ gtk_window_is_maximized (GtkWindow *window) return priv->maximize_initially; } +/** + * gtk_window_is_fullscreen: + * @window: a #GtkWindow + * + * Retrieves the current fullscreen state of @window. + * + * Note that since fullscreening is ultimately handled by the window + * manager and happens asynchronously to an application request, you + * shouldn’t assume the return value of this function changing + * immediately (or at all), as an effect of calling + * gtk_window_fullscreen() or gtk_window_unfullscreen(). + * + * If the window isn't yet mapped, the value returned will whether the + * initial requested state is fullscreen. + * + * Returns: whether the window has a fullscreen state. + */ +gboolean +gtk_window_is_fullscreen (GtkWindow *window) +{ + GtkWindowPrivate *priv = gtk_window_get_instance_private (window); + + g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE); + + if (priv->surface && gdk_surface_get_mapped (priv->surface)) + return priv->fullscreen; + else + return priv->fullscreen_initially; +} + void _gtk_window_toggle_maximized (GtkWindow *window) { @@ -1625,6 +1663,12 @@ gtk_window_set_property (GObject *object, else gtk_window_unmaximize (window); break; + case PROP_FULLSCREEN: + if (g_value_get_boolean (value)) + gtk_window_fullscreen (window); + else + gtk_window_unfullscreen (window); + break; case PROP_FOCUS_WIDGET: gtk_window_set_focus (window, g_value_get_object (value)); break; @@ -1702,6 +1746,9 @@ gtk_window_get_property (GObject *object, case PROP_MAXIMIZED: g_value_set_boolean (value, gtk_window_is_maximized (window)); break; + case PROP_FULLSCREEN: + g_value_set_boolean (value, gtk_window_is_fullscreen (window)); + break; case PROP_FOCUS_WIDGET: g_value_set_object (value, gtk_window_get_focus (window)); break; @@ -4425,6 +4472,8 @@ surface_state_changed (GtkWidget *widget) { priv->fullscreen = (new_surface_state & GDK_TOPLEVEL_STATE_FULLSCREEN) ? TRUE : FALSE; priv->fullscreen_initially = priv->fullscreen; + + g_object_notify_by_pspec (G_OBJECT (widget), window_props[PROP_FULLSCREEN]); } if (changed_mask & GDK_TOPLEVEL_STATE_MAXIMIZED) @@ -5195,12 +5244,17 @@ void gtk_window_fullscreen (GtkWindow *window) { GtkWindowPrivate *priv = gtk_window_get_instance_private (window); + gboolean was_fullscreen_initially; g_return_if_fail (GTK_IS_WINDOW (window)); + was_fullscreen_initially = priv->fullscreen_initially; priv->fullscreen_initially = TRUE; - gtk_window_update_toplevel (window); + if (priv->surface && gdk_surface_get_mapped (priv->surface)) + gtk_window_update_toplevel (window); + else if (!was_fullscreen_initially) + g_object_notify_by_pspec (G_OBJECT (window), window_props[PROP_FULLSCREEN]); } static void @@ -5267,13 +5321,20 @@ void gtk_window_unfullscreen (GtkWindow *window) { GtkWindowPrivate *priv = gtk_window_get_instance_private (window); + gboolean was_fullscreen_initially; g_return_if_fail (GTK_IS_WINDOW (window)); + was_fullscreen_initially = priv->fullscreen_initially; unset_fullscreen_monitor (window); priv->fullscreen_initially = FALSE; gtk_window_update_toplevel (window); + + if (priv->surface && gdk_surface_get_mapped (priv->surface)) + gtk_window_update_toplevel (window); + else if (was_fullscreen_initially) + g_object_notify_by_pspec (G_OBJECT (window), window_props[PROP_FULLSCREEN]); } /** diff --git a/gtk/gtkwindow.h b/gtk/gtkwindow.h index a68937ba67..1c673b4201 100644 --- a/gtk/gtkwindow.h +++ b/gtk/gtkwindow.h @@ -247,6 +247,9 @@ GtkWidget *gtk_window_get_titlebar (GtkWindow *window); GDK_AVAILABLE_IN_ALL gboolean gtk_window_is_maximized (GtkWindow *window); +GDK_AVAILABLE_IN_ALL +gboolean gtk_window_is_fullscreen (GtkWindow *window); + GDK_AVAILABLE_IN_ALL void gtk_window_destroy (GtkWindow *window); From ac17217c69b3a439cc3039ee39e92801203b726f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Sat, 5 Dec 2020 15:57:45 +0100 Subject: [PATCH 76/87] wayland/toplevel: Don't alwyas skip changing xdg_toplevel state We only called xdg_toplevel.(un)set_maximize() if the toplevel layout changed, but this misses the case when the compositor had changed the maximized state. Change it to call the xdg_toplevel request if either the local layout changed, or if the layout differs from the current state. This fixes an issue where one couldn't unmaximize a window by double clicking the titlebar that, had previously been maximized e.g. using a keyboard binding. Do the same for fullscreen. --- gdk/wayland/gdksurface-wayland.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/gdk/wayland/gdksurface-wayland.c b/gdk/wayland/gdksurface-wayland.c index c152acf3e5..9ce5669bac 100644 --- a/gdk/wayland/gdksurface-wayland.c +++ b/gdk/wayland/gdksurface-wayland.c @@ -4876,6 +4876,8 @@ did_maximize_layout_change (GdkToplevel *toplevel, return TRUE; if (gdk_toplevel_layout_get_maximized (impl->toplevel.layout) != + gdk_toplevel_layout_get_maximized (layout) || + !!(surface->state & GDK_TOPLEVEL_STATE_MAXIMIZED) != gdk_toplevel_layout_get_maximized (layout)) return TRUE; @@ -4893,6 +4895,8 @@ did_fullscreen_layout_change (GdkToplevel *toplevel, return TRUE; if (gdk_toplevel_layout_get_fullscreen (impl->toplevel.layout) != + gdk_toplevel_layout_get_fullscreen (layout) || + !!(surface->state & GDK_TOPLEVEL_STATE_FULLSCREEN) != gdk_toplevel_layout_get_fullscreen (layout)) return TRUE; From d7d738d745c3a8b91bfb009b2ee9a9f67a3b0c5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Mon, 7 Dec 2020 09:41:54 +0100 Subject: [PATCH 77/87] tests/animated-resizing: Use gtk_window_default_size() instead This will actually make it resize on-demand, as the default size is the size used when computing the window size when the size is not fixed. --- tests/animated-resizing.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/animated-resizing.c b/tests/animated-resizing.c index c9a316a560..bf7a0b68c4 100644 --- a/tests/animated-resizing.c +++ b/tests/animated-resizing.c @@ -123,7 +123,7 @@ on_frame (double progress) window_height = HEIGHT + jitter; } - gtk_widget_set_size_request (gtk_window_get_child (GTK_WINDOW (window)), + gtk_window_set_default_size (GTK_WINDOW (window), window_width, window_height); gtk_widget_queue_draw (window); From 3db0d06901e8e6c052774000288e65ebe5ae6d07 Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Sat, 5 Dec 2020 12:15:24 -0500 Subject: [PATCH 78/87] Properly remove gtk_window_get_size It was still in the headers and the docs, but did not have an implementation anymore. --- docs/reference/gtk/gtk4-sections.txt | 1 - gtk/gtkwindow.h | 4 ---- 2 files changed, 5 deletions(-) diff --git a/docs/reference/gtk/gtk4-sections.txt b/docs/reference/gtk/gtk4-sections.txt index 909bd1df92..30f93aa872 100644 --- a/docs/reference/gtk/gtk4-sections.txt +++ b/docs/reference/gtk/gtk4-sections.txt @@ -4615,7 +4615,6 @@ gtk_window_get_default_size gtk_window_get_destroy_with_parent gtk_window_get_icon_name gtk_window_get_modal -gtk_window_get_size gtk_window_get_title gtk_window_get_transient_for gtk_window_get_group diff --git a/gtk/gtkwindow.h b/gtk/gtkwindow.h index 1c673b4201..06701f8313 100644 --- a/gtk/gtkwindow.h +++ b/gtk/gtkwindow.h @@ -215,10 +215,6 @@ GDK_AVAILABLE_IN_ALL void gtk_window_get_default_size (GtkWindow *window, int *width, int *height); -GDK_AVAILABLE_IN_ALL -void gtk_window_get_size (GtkWindow *window, - int *width, - int *height); GDK_AVAILABLE_IN_ALL GtkWindowGroup *gtk_window_get_group (GtkWindow *window); From 59fd17151533261c6334bd52d4164b30efbba1b2 Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Sat, 5 Dec 2020 12:28:50 -0500 Subject: [PATCH 79/87] popup: Documentation tweaks Use proper syntax for referring to signals. --- gdk/gdkpopup.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/gdk/gdkpopup.c b/gdk/gdkpopup.c index 6e45e9f93e..26b8fe55dd 100644 --- a/gdk/gdkpopup.c +++ b/gdk/gdkpopup.c @@ -106,15 +106,15 @@ gdk_popup_default_init (GdkPopupInterface *iface) * otherwise it will change position according to @layout. * * After calling this function, the result should be handled in response - * to the GdkSurface::layout signal being emitted. The resulting popup + * to the #GdkSurface::layout signal being emitted. The resulting popup * position can be queried using gdk_popup_get_position_x(), * gdk_popup_get_position_y(), and the resulting size will be sent as * parameters in the layout signal. Use gdk_popup_get_rect_anchor() and * gdk_popup_get_surface_anchor() to get the resulting anchors. * - * Presenting may have fail, for example if it was immediately - * hidden if the @popup was set to autohide. If presenting failed, - * GdkSurface::layout will not me emitted. + * Presenting may fail, for example if the @popup is set to autohide + * and is immediately hidden upon being presented. If presenting failed, + * the #GdkSurface::layout signal will not me emitted. * * Returns: %FALSE if it failed to be presented, otherwise %TRUE. */ @@ -139,7 +139,7 @@ gdk_popup_present (GdkPopup *popup, * Gets the current popup surface anchor. * * The value returned may change after calling gdk_popup_present(), - * or after the "GdkSurface::layout" signal is emitted. + * or after the #GdkSurface::layout signal is emitted. * * Returns: the current surface anchor value of @popup */ @@ -158,7 +158,7 @@ gdk_popup_get_surface_anchor (GdkPopup *popup) * Gets the current popup rectangle anchor. * * The value returned may change after calling gdk_popup_present(), - * or after the "GdkSurface::layout" signal is emitted. + * or after the #GdkSurface::layout signal is emitted. * * Returns: the current rectangle anchor value of @popup */ From a6bc4c95b1aec0ecb4bd151a4abd8bd281015207 Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Sat, 5 Dec 2020 12:29:17 -0500 Subject: [PATCH 80/87] docs: Add gtk_window_is_fullscreen --- docs/reference/gtk/gtk4-sections.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/reference/gtk/gtk4-sections.txt b/docs/reference/gtk/gtk4-sections.txt index 30f93aa872..d97a2ede6c 100644 --- a/docs/reference/gtk/gtk4-sections.txt +++ b/docs/reference/gtk/gtk4-sections.txt @@ -4589,6 +4589,7 @@ gtk_window_set_destroy_with_parent gtk_window_set_display gtk_window_is_active gtk_window_is_maximized +gtk_window_is_fullscreen gtk_window_get_toplevels gtk_window_list_toplevels gtk_window_get_focus From 3b69facf0bdfc1641a1b74bc9ec99c3669db32a0 Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Sat, 5 Dec 2020 12:41:52 -0500 Subject: [PATCH 81/87] Mention window sizes in the migration guide --- docs/reference/gtk/migrating-3to4.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/docs/reference/gtk/migrating-3to4.md b/docs/reference/gtk/migrating-3to4.md index 95847872f7..c4024c9c2f 100644 --- a/docs/reference/gtk/migrating-3to4.md +++ b/docs/reference/gtk/migrating-3to4.md @@ -510,9 +510,14 @@ gtk_window_set_gravity(), gtk_window_move(), gtk_window_parse_geometry(), gtk_window_set_keep_above(), gtk_window_set_keep_below(), gtk_window_begin_resize_drag(), gtk_window_begin_move_drag(). Most likely, you should just stop using them. In some cases, you can -fall back to using the underlying #GdkToplevel APIS (for example, +fall back to using the underlying #GdkToplevel APIs (for example, gdk_toplevel_begin_resize()). +The APIs for controlling GtkWindow size have changed to be better aligned +with the way size changes are integrated in the frame cycle. gtk_window_resize() +and gtk_window_get_size() have been removed. Instead, use +gtk_window_set_default_size() and gtk_window_get_default_size(). + ### Adapt to GtkHeaderBar and GtkActionBar API changes The gtk_header_bar_set_show_close_button() function has been renamed to From 8f8c5040dbfc9fe1bac0df7664c39f65c3110428 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Mon, 7 Dec 2020 16:04:01 +0100 Subject: [PATCH 82/87] gtk/headerbar: Remove unused 'state' field --- gtk/gtkheaderbar.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/gtk/gtkheaderbar.c b/gtk/gtkheaderbar.c index 5ed128c4c2..1cb9e8185a 100644 --- a/gtk/gtkheaderbar.c +++ b/gtk/gtkheaderbar.c @@ -130,8 +130,6 @@ struct _GtkHeaderBar guint show_title_buttons : 1; guint track_default_decoration : 1; - - GdkToplevelState state; }; typedef struct _GtkHeaderBarClass GtkHeaderBarClass; @@ -613,7 +611,6 @@ gtk_header_bar_init (GtkHeaderBar *bar) bar->title_widget = NULL; bar->decoration_layout = NULL; bar->show_title_buttons = TRUE; - bar->state = GDK_TOPLEVEL_STATE_WITHDRAWN; bar->handle = gtk_window_handle_new (); gtk_widget_set_parent (bar->handle, GTK_WIDGET (bar)); From d2c95a1b13ee710fcfc69a592be669bcea4b26e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Mon, 7 Dec 2020 18:18:38 +0100 Subject: [PATCH 83/87] gdk: Replace 'WITHDRAWN' state with async 'is-mapped' boolean It was used by all surfaces to track 'is-mapped', but still part of the GdkToplevelState, and is now replaced with a separate boolean in the GdkSurface structure. It also caused issues when a widget was unmapped, and due to that unmapped a popover which hid its corresponding surface. When this surface was hidden, it emitted a state change event, which would then go back into GTK and queue a resize on popover widget, which would travel back down to the widget that was originally unmapped, causing confusino when doing future allocations. To summarize, one should not hide widgets during allocation, and to avoid this, make this new is-mapped boolean asynchronous when hiding a surface, meaning the notification event for the changed mapped state will be emitted in an idle callback. This avoids the above described reentry issue. --- gdk/broadway/gdksurface-broadway.c | 4 +- gdk/gdksurface.c | 90 ++++++++++++++++++++++++------ gdk/gdksurfaceprivate.h | 10 +++- gdk/gdktoplevel.c | 2 +- gdk/gdktoplevel.h | 34 ++++++----- gdk/macos/gdkmacossurface.c | 2 +- gdk/wayland/gdksurface-wayland.c | 2 +- gdk/win32/gdkevents-win32.c | 6 +- gdk/win32/gdkmain-win32.c | 5 -- gdk/win32/gdksurface-win32.c | 8 +-- gdk/x11/gdkdisplay-x11.c | 2 +- gdk/x11/gdkdrag-x11.c | 2 +- gdk/x11/gdkglcontext-x11.c | 2 +- gdk/x11/gdksurface-x11.c | 12 ++-- gtk/gtktooltipwindow.c | 24 +++----- gtk/gtkwindow.c | 3 +- tests/testgtk.c | 2 - 17 files changed, 122 insertions(+), 88 deletions(-) diff --git a/gdk/broadway/gdksurface-broadway.c b/gdk/broadway/gdksurface-broadway.c index 30ba9ff51b..d44b2281f0 100644 --- a/gdk/broadway/gdksurface-broadway.c +++ b/gdk/broadway/gdksurface-broadway.c @@ -601,7 +601,7 @@ gdk_broadway_surface_layout_popup (GdkSurface *surface, static void show_popup (GdkSurface *surface) { - gdk_synthesize_surface_state (surface, GDK_TOPLEVEL_STATE_WITHDRAWN, 0); + gdk_surface_set_is_mapped (surface, TRUE); gdk_broadway_surface_show (surface, FALSE); gdk_surface_invalidate_rect (surface, NULL); } @@ -1521,7 +1521,7 @@ show_surface (GdkSurface *surface) was_mapped = GDK_SURFACE_IS_MAPPED (surface); if (!was_mapped) - gdk_synthesize_surface_state (surface, GDK_TOPLEVEL_STATE_WITHDRAWN, 0); + gdk_surface_set_is_mapped (surface, TRUE); gdk_broadway_surface_show (surface, FALSE); diff --git a/gdk/gdksurface.c b/gdk/gdksurface.c index 27b775982c..012864479a 100644 --- a/gdk/gdksurface.c +++ b/gdk/gdksurface.c @@ -114,6 +114,9 @@ static void update_cursor (GdkDisplay *display, static void gdk_surface_set_frame_clock (GdkSurface *surface, GdkFrameClock *clock); +static void gdk_surface_queue_set_is_mapped (GdkSurface *surface, + gboolean is_mapped); + static guint signals[LAST_SIGNAL] = { 0 }; static GParamSpec *properties[LAST_PROP] = { NULL, }; @@ -472,7 +475,7 @@ gdk_surface_init (GdkSurface *surface) { /* 0-initialization is good for all other fields. */ - surface->state = GDK_TOPLEVEL_STATE_WITHDRAWN; + surface->state = 0; surface->fullscreen_mode = GDK_FULLSCREEN_ON_CURRENT_MONITOR; surface->width = 1; surface->height = 1; @@ -923,7 +926,10 @@ _gdk_surface_destroy_hierarchy (GdkSurface *surface, _gdk_surface_clear_update_area (surface); - surface->state |= GDK_TOPLEVEL_STATE_WITHDRAWN; + g_clear_handle_id (&surface->set_is_mapped_source_id, g_source_remove); + surface->is_mapped = FALSE; + surface->pending_is_mapped = FALSE; + surface->destroyed = TRUE; surface_remove_from_pointer_info (surface, surface->display); @@ -1696,14 +1702,7 @@ gdk_surface_hide (GdkSurface *surface) was_mapped = GDK_SURFACE_IS_MAPPED (surface); - if (GDK_SURFACE_IS_MAPPED (surface)) - { - gdk_synthesize_surface_state (surface, - surface->state & ~GDK_TOPLEVEL_STATE_WITHDRAWN, - GDK_TOPLEVEL_STATE_WITHDRAWN); - surface->pending_unset_flags = 0; - surface->pending_set_flags = 0; - } + gdk_surface_queue_set_is_mapped (surface, FALSE); if (was_mapped) { @@ -2614,7 +2613,6 @@ void gdk_surface_set_state (GdkSurface *surface, GdkToplevelState new_state) { - gboolean was_mapped, mapped; gboolean was_sticky, sticky; g_return_if_fail (GDK_IS_SURFACE (surface)); @@ -2626,20 +2624,15 @@ gdk_surface_set_state (GdkSurface *surface, * inconsistent state to the user. */ - was_mapped = GDK_SURFACE_IS_MAPPED (surface); was_sticky = GDK_SURFACE_IS_STICKY (surface); surface->state = new_state; - mapped = GDK_SURFACE_IS_MAPPED (surface); sticky = GDK_SURFACE_IS_STICKY (surface); if (GDK_IS_TOPLEVEL (surface)) g_object_notify (G_OBJECT (surface), "state"); - if (was_mapped != mapped) - g_object_notify_by_pspec (G_OBJECT (surface), properties[PROP_MAPPED]); - if (was_sticky != sticky) g_object_notify (G_OBJECT (surface), "sticky"); } @@ -2673,12 +2666,73 @@ gdk_surface_apply_state_change (GdkSurface *surface) gdk_synthesize_surface_state (surface, surface->pending_unset_flags, surface->pending_set_flags); - if (surface->pending_unset_flags & GDK_TOPLEVEL_STATE_WITHDRAWN) - gdk_surface_invalidate_rect (surface, NULL); surface->pending_unset_flags = 0; surface->pending_set_flags = 0; } +static gboolean +set_is_mapped_idle (gpointer user_data) +{ + GdkSurface *surface = GDK_SURFACE (user_data); + + surface->set_is_mapped_source_id = 0; + + g_return_val_if_fail (surface->pending_is_mapped != surface->is_mapped, + G_SOURCE_REMOVE); + + surface->is_mapped = surface->pending_is_mapped; + if (surface->is_mapped) + gdk_surface_invalidate_rect (surface, NULL); + + g_object_notify (G_OBJECT (surface), "mapped"); + + return G_SOURCE_REMOVE; +} + +void +gdk_surface_set_is_mapped (GdkSurface *surface, + gboolean is_mapped) +{ + gboolean was_mapped; + + if (surface->pending_is_mapped != surface->is_mapped) + g_clear_handle_id (&surface->set_is_mapped_source_id, g_source_remove); + + surface->pending_is_mapped = is_mapped; + + was_mapped = surface->is_mapped; + surface->is_mapped = is_mapped; + if (surface->is_mapped) + gdk_surface_invalidate_rect (surface, NULL); + + if (was_mapped != is_mapped) + g_object_notify (G_OBJECT (surface), "mapped"); +} + +static void +gdk_surface_queue_set_is_mapped (GdkSurface *surface, + gboolean is_mapped) +{ + if (surface->pending_is_mapped == is_mapped) + return; + + surface->pending_is_mapped = is_mapped; + + if (surface->is_mapped == surface->pending_is_mapped) + { + g_clear_handle_id (&surface->set_is_mapped_source_id, g_source_remove); + } + else + { + g_return_if_fail (!surface->set_is_mapped_source_id); + + surface->set_is_mapped_source_id = + g_idle_add_full (G_PRIORITY_HIGH - 10, + set_is_mapped_idle, + surface, NULL); + } +} + static gboolean check_autohide (GdkEvent *event) { diff --git a/gdk/gdksurfaceprivate.h b/gdk/gdksurfaceprivate.h index 4c879fc2cb..27a3966fe7 100644 --- a/gdk/gdksurfaceprivate.h +++ b/gdk/gdksurfaceprivate.h @@ -44,6 +44,10 @@ struct _GdkSurface GdkSurface *parent; /* for popups */ GList *children; /* popups */ + guint set_is_mapped_source_id; + gboolean pending_is_mapped; + gboolean is_mapped; + gpointer widget; int x; @@ -167,12 +171,14 @@ struct _GdkSurfaceClass #define GDK_SURFACE_DESTROYED(d) (((GdkSurface *)(d))->destroyed) -#define GDK_SURFACE_IS_MAPPED(surface) (((surface)->state & GDK_TOPLEVEL_STATE_WITHDRAWN) == 0) - +#define GDK_SURFACE_IS_MAPPED(surface) ((surface)->pending_is_mapped) void gdk_surface_set_state (GdkSurface *surface, GdkToplevelState new_state); +void gdk_surface_set_is_mapped (GdkSurface *surface, + gboolean is_mapped); + GdkMonitor * gdk_surface_get_layout_monitor (GdkSurface *surface, GdkPopupLayout *layout, void (*get_bounds) (GdkMonitor *monitor, diff --git a/gdk/gdktoplevel.c b/gdk/gdktoplevel.c index 4cff2bb3dd..13eb38cda1 100644 --- a/gdk/gdktoplevel.c +++ b/gdk/gdktoplevel.c @@ -123,7 +123,7 @@ gdk_toplevel_default_init (GdkToplevelInterface *iface) g_param_spec_flags ("state", P_("State"), P_("State"), - GDK_TYPE_TOPLEVEL_STATE, GDK_TOPLEVEL_STATE_WITHDRAWN, + GDK_TYPE_TOPLEVEL_STATE, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); g_object_interface_install_property (iface, g_param_spec_string ("title", diff --git a/gdk/gdktoplevel.h b/gdk/gdktoplevel.h index 28402feb10..fb29315710 100644 --- a/gdk/gdktoplevel.h +++ b/gdk/gdktoplevel.h @@ -71,7 +71,6 @@ typedef enum /** * GdkToplevelState: - * @GDK_TOPLEVEL_STATE_WITHDRAWN: the surface is not shown * @GDK_TOPLEVEL_STATE_MINIMIZED: the surface is minimized * @GDK_TOPLEVEL_STATE_MAXIMIZED: the surface is maximized * @GDK_TOPLEVEL_STATE_STICKY: the surface is sticky @@ -98,23 +97,22 @@ typedef enum */ typedef enum { - GDK_TOPLEVEL_STATE_WITHDRAWN = 1 << 0, - GDK_TOPLEVEL_STATE_MINIMIZED = 1 << 1, - GDK_TOPLEVEL_STATE_MAXIMIZED = 1 << 2, - GDK_TOPLEVEL_STATE_STICKY = 1 << 3, - GDK_TOPLEVEL_STATE_FULLSCREEN = 1 << 4, - GDK_TOPLEVEL_STATE_ABOVE = 1 << 5, - GDK_TOPLEVEL_STATE_BELOW = 1 << 6, - GDK_TOPLEVEL_STATE_FOCUSED = 1 << 7, - GDK_TOPLEVEL_STATE_TILED = 1 << 8, - GDK_TOPLEVEL_STATE_TOP_TILED = 1 << 9, - GDK_TOPLEVEL_STATE_TOP_RESIZABLE = 1 << 10, - GDK_TOPLEVEL_STATE_RIGHT_TILED = 1 << 11, - GDK_TOPLEVEL_STATE_RIGHT_RESIZABLE = 1 << 12, - GDK_TOPLEVEL_STATE_BOTTOM_TILED = 1 << 13, - GDK_TOPLEVEL_STATE_BOTTOM_RESIZABLE = 1 << 14, - GDK_TOPLEVEL_STATE_LEFT_TILED = 1 << 15, - GDK_TOPLEVEL_STATE_LEFT_RESIZABLE = 1 << 16 + GDK_TOPLEVEL_STATE_MINIMIZED = 1 << 0, + GDK_TOPLEVEL_STATE_MAXIMIZED = 1 << 1, + GDK_TOPLEVEL_STATE_STICKY = 1 << 2, + GDK_TOPLEVEL_STATE_FULLSCREEN = 1 << 3, + GDK_TOPLEVEL_STATE_ABOVE = 1 << 4, + GDK_TOPLEVEL_STATE_BELOW = 1 << 5, + GDK_TOPLEVEL_STATE_FOCUSED = 1 << 6, + GDK_TOPLEVEL_STATE_TILED = 1 << 7, + GDK_TOPLEVEL_STATE_TOP_TILED = 1 << 8, + GDK_TOPLEVEL_STATE_TOP_RESIZABLE = 1 << 9, + GDK_TOPLEVEL_STATE_RIGHT_TILED = 1 << 10, + GDK_TOPLEVEL_STATE_RIGHT_RESIZABLE = 1 << 11, + GDK_TOPLEVEL_STATE_BOTTOM_TILED = 1 << 12, + GDK_TOPLEVEL_STATE_BOTTOM_RESIZABLE = 1 << 13, + GDK_TOPLEVEL_STATE_LEFT_TILED = 1 << 14, + GDK_TOPLEVEL_STATE_LEFT_RESIZABLE = 1 << 15 } GdkToplevelState; diff --git a/gdk/macos/gdkmacossurface.c b/gdk/macos/gdkmacossurface.c index 705ae1d5ce..5e528ca8e2 100644 --- a/gdk/macos/gdkmacossurface.c +++ b/gdk/macos/gdkmacossurface.c @@ -762,7 +762,7 @@ _gdk_macos_surface_show (GdkMacosSurface *self) was_mapped = GDK_SURFACE_IS_MAPPED (GDK_SURFACE (self)); if (!was_mapped) - gdk_synthesize_surface_state (GDK_SURFACE (self), GDK_TOPLEVEL_STATE_WITHDRAWN, 0); + gdk_surface_set_is_mapped (GDK_SURFACE (self), TRUE); _gdk_macos_display_clear_sorting (GDK_MACOS_DISPLAY (GDK_SURFACE (self)->display)); diff --git a/gdk/wayland/gdksurface-wayland.c b/gdk/wayland/gdksurface-wayland.c index 9ce5669bac..602d76b773 100644 --- a/gdk/wayland/gdksurface-wayland.c +++ b/gdk/wayland/gdksurface-wayland.c @@ -1602,7 +1602,7 @@ maybe_notify_mapped (GdkSurface *surface) return; if (!GDK_SURFACE_IS_MAPPED (surface)) - gdk_surface_queue_state_change (surface, GDK_TOPLEVEL_STATE_WITHDRAWN, 0); + gdk_surface_set_is_mapped (surface, TRUE); } static void diff --git a/gdk/win32/gdkevents-win32.c b/gdk/win32/gdkevents-win32.c index 1a50cdb5dd..dbdcab2c43 100644 --- a/gdk/win32/gdkevents-win32.c +++ b/gdk/win32/gdkevents-win32.c @@ -2825,11 +2825,6 @@ gdk_event_translate (MSG *msg, set_bits = 0; unset_bits = 0; - if (IsWindowVisible (msg->hwnd)) - unset_bits |= GDK_TOPLEVEL_STATE_WITHDRAWN; - else - set_bits |= GDK_TOPLEVEL_STATE_WITHDRAWN; - if (IsIconic (msg->hwnd)) set_bits |= GDK_TOPLEVEL_STATE_MINIMIZED; else @@ -2840,6 +2835,7 @@ gdk_event_translate (MSG *msg, else unset_bits |= GDK_TOPLEVEL_STATE_MAXIMIZED; + gdk_surface_set_is_mapped (window, !!IsWindowVisible (msg->hwnd)); gdk_synthesize_surface_state (window, unset_bits, set_bits); new_state = window->state; diff --git a/gdk/win32/gdkmain-win32.c b/gdk/win32/gdkmain-win32.c index 73d0420011..6d4e44cfc7 100644 --- a/gdk/win32/gdkmain-win32.c +++ b/gdk/win32/gdkmain-win32.c @@ -274,11 +274,6 @@ _gdk_win32_surface_state_to_string (GdkToplevelState state) if (state & GDK_TOPLEVEL_STATE_ ## x) \ (bufp += sprintf (bufp, "%s" #x, s), s = "|") - /* For clarity, also show the complement of WITHDRAWN, i.e. "MAPPED" */ - if (!(state & GDK_TOPLEVEL_STATE_WITHDRAWN)) - (bufp += sprintf (bufp, "MAPPED"), s = "|"); - - BIT (WITHDRAWN); BIT (MINIMIZED); BIT (MAXIMIZED); BIT (STICKY); diff --git a/gdk/win32/gdksurface-win32.c b/gdk/win32/gdksurface-win32.c index a7b1bda775..263fcc6c60 100644 --- a/gdk/win32/gdksurface-win32.c +++ b/gdk/win32/gdksurface-win32.c @@ -1006,9 +1006,7 @@ gdk_win32_surface_hide (GdkSurface *window) _gdk_win32_surface_state_to_string (window->state))); if (GDK_SURFACE_IS_MAPPED (window)) - gdk_synthesize_surface_state (window, - 0, - GDK_TOPLEVEL_STATE_WITHDRAWN); + gdk_surface_set_is_mapped (window, FALSE); _gdk_surface_clear_update_area (window); @@ -1262,7 +1260,7 @@ static void show_popup (GdkSurface *surface) { gdk_win32_surface_raise (surface); - gdk_synthesize_surface_state (surface, GDK_TOPLEVEL_STATE_WITHDRAWN, 0); + gdk_surface_set_is_mapped (surface, TRUE); show_window_internal (surface, FALSE, FALSE); gdk_surface_invalidate_rect (surface, NULL); } @@ -4924,7 +4922,7 @@ show_surface (GdkSurface *surface) was_mapped = GDK_SURFACE_IS_MAPPED (surface); if (!was_mapped) - gdk_synthesize_surface_state (surface, GDK_TOPLEVEL_STATE_WITHDRAWN, 0); + gdk_surface_set_is_mapped (surface, TRUE); gdk_win32_surface_show (surface, FALSE); diff --git a/gdk/x11/gdkdisplay-x11.c b/gdk/x11/gdkdisplay-x11.c index 31b06ea53f..4350f2eef8 100644 --- a/gdk/x11/gdkdisplay-x11.c +++ b/gdk/x11/gdkdisplay-x11.c @@ -566,7 +566,7 @@ gdk_check_edge_constraints_changed (GdkSurface *surface) * messing around with shifts, just make the passed value and GDK's * enum values match by shifting to the first tiled state. */ - toplevel->edge_constraints = constraints[0] << 9; + toplevel->edge_constraints = constraints[0] << 8; XFree (constraints); } diff --git a/gdk/x11/gdkdrag-x11.c b/gdk/x11/gdkdrag-x11.c index 8e40cab447..606cef0f0c 100644 --- a/gdk/x11/gdkdrag-x11.c +++ b/gdk/x11/gdkdrag-x11.c @@ -2036,7 +2036,7 @@ _gdk_x11_surface_drag_begin (GdkSurface *surface, if (gdk_x11_surface_get_group (surface)) gdk_x11_surface_set_group (x11_drag->ipc_surface, surface); - gdk_synthesize_surface_state (x11_drag->ipc_surface, GDK_TOPLEVEL_STATE_WITHDRAWN, 0); + gdk_surface_set_is_mapped (x11_drag->ipc_surface, TRUE); gdk_x11_surface_show (x11_drag->ipc_surface, FALSE); x11_drag->drag_surface = create_drag_surface (display); diff --git a/gdk/x11/gdkglcontext-x11.c b/gdk/x11/gdkglcontext-x11.c index a332773493..d83ef6aaad 100644 --- a/gdk/x11/gdkglcontext-x11.c +++ b/gdk/x11/gdkglcontext-x11.c @@ -463,7 +463,7 @@ on_surface_state_changed (GdkGLContext *context) { GdkSurface *surface = gdk_gl_context_get_surface (context); - if ((surface->state & GDK_TOPLEVEL_STATE_WITHDRAWN) == 0) + if (GDK_SURFACE_IS_MAPPED (surface)) return; /* If we're about to withdraw the surface, then we don't care if the frame is diff --git a/gdk/x11/gdksurface-x11.c b/gdk/x11/gdksurface-x11.c index 6680312563..293134371e 100644 --- a/gdk/x11/gdksurface-x11.c +++ b/gdk/x11/gdksurface-x11.c @@ -1401,7 +1401,7 @@ update_wm_hints (GdkSurface *surface, if (!force && !toplevel->is_leader && - surface->state & GDK_TOPLEVEL_STATE_WITHDRAWN) + !GDK_SURFACE_IS_MAPPED (surface)) return; wm_hints.flags = StateHint | InputHint; @@ -1608,9 +1608,7 @@ gdk_x11_surface_withdraw (GdkSurface *surface) if (!surface->destroyed) { if (GDK_SURFACE_IS_MAPPED (surface)) - gdk_synthesize_surface_state (surface, - 0, - GDK_TOPLEVEL_STATE_WITHDRAWN); + gdk_surface_set_is_mapped (surface, FALSE); g_assert (!GDK_SURFACE_IS_MAPPED (surface)); XWithdrawWindow (GDK_SURFACE_XDISPLAY (surface), @@ -1852,7 +1850,7 @@ static void show_popup (GdkSurface *surface) { gdk_x11_surface_raise (surface); - gdk_synthesize_surface_state (surface, GDK_TOPLEVEL_STATE_WITHDRAWN, 0); + gdk_surface_set_is_mapped (surface, TRUE); gdk_x11_surface_show (surface, FALSE); gdk_surface_invalidate_rect (surface, NULL); } @@ -5116,7 +5114,7 @@ gdk_x11_toplevel_present (GdkToplevel *toplevel, gdk_surface_request_layout (surface); if (!was_mapped) - gdk_synthesize_surface_state (surface, GDK_TOPLEVEL_STATE_WITHDRAWN, 0); + gdk_surface_set_is_mapped (surface, TRUE); gdk_x11_surface_show (surface, was_mapped); @@ -5287,7 +5285,7 @@ gdk_x11_drag_surface_present (GdkDragSurface *drag_surface, GdkSurface *surface = GDK_SURFACE (drag_surface); gdk_x11_surface_toplevel_resize (surface, width, height); - gdk_synthesize_surface_state (surface, GDK_TOPLEVEL_STATE_WITHDRAWN, 0); + gdk_surface_set_is_mapped (surface, TRUE); gdk_x11_surface_show (surface, FALSE); gdk_surface_invalidate_rect (surface, NULL); diff --git a/gtk/gtktooltipwindow.c b/gtk/gtktooltipwindow.c index 55c6a882d1..a3dbf83db4 100644 --- a/gtk/gtktooltipwindow.c +++ b/gtk/gtktooltipwindow.c @@ -47,7 +47,6 @@ struct _GtkTooltipWindow GdkSurface *surface; GskRenderer *renderer; - GdkToplevelState state; GtkWidget *relative_to; GdkRectangle rect; GdkGravity rect_anchor; @@ -178,21 +177,12 @@ gtk_tooltip_window_native_init (GtkNativeInterface *iface) } static void -surface_state_changed (GtkWidget *widget) +mapped_changed (GdkSurface *surface, + GParamSpec *pspec, + GtkWidget *widget) { - GtkTooltipWindow *window = GTK_TOOLTIP_WINDOW (widget); - GdkToplevelState new_surface_state; - GdkToplevelState changed_mask; - - new_surface_state = gdk_toplevel_get_state (GDK_TOPLEVEL (window->surface)); - changed_mask = new_surface_state ^ window->state; - window->state = new_surface_state; - - if (changed_mask & GDK_TOPLEVEL_STATE_WITHDRAWN) - { - if (window->state & GDK_TOPLEVEL_STATE_WITHDRAWN) - gtk_widget_hide (widget); - } + if (!gdk_surface_get_mapped (surface)) + gtk_widget_hide (widget); } static gboolean @@ -224,7 +214,7 @@ gtk_tooltip_window_realize (GtkWidget *widget) gdk_surface_set_widget (window->surface, widget); - g_signal_connect_swapped (window->surface, "notify::state", G_CALLBACK (surface_state_changed), widget); + g_signal_connect (window->surface, "notify::mapped", G_CALLBACK (mapped_changed), widget); g_signal_connect (window->surface, "render", G_CALLBACK (surface_render), widget); g_signal_connect (window->surface, "event", G_CALLBACK (surface_event), widget); @@ -247,7 +237,7 @@ gtk_tooltip_window_unrealize (GtkWidget *widget) gsk_renderer_unrealize (window->renderer); g_clear_object (&window->renderer); - g_signal_handlers_disconnect_by_func (window->surface, surface_state_changed, widget); + g_signal_handlers_disconnect_by_func (window->surface, mapped_changed, widget); g_signal_handlers_disconnect_by_func (window->surface, surface_render, widget); g_signal_handlers_disconnect_by_func (window->surface, surface_event, widget); gdk_surface_set_widget (window->surface, NULL); diff --git a/gtk/gtkwindow.c b/gtk/gtkwindow.c index 176ae22bf5..7e22e4bcbe 100644 --- a/gtk/gtkwindow.c +++ b/gtk/gtkwindow.c @@ -1503,7 +1503,7 @@ gtk_window_init (GtkWindow *window) priv->decorated = TRUE; priv->display = gdk_display_get_default (); - priv->state = GDK_TOPLEVEL_STATE_WITHDRAWN; + priv->state = 0; priv->deletable = TRUE; priv->startup_id = NULL; @@ -4165,6 +4165,7 @@ gtk_window_realize (GtkWidget *widget) priv->renderer = gsk_renderer_new_for_surface (surface); g_signal_connect_swapped (surface, "notify::state", G_CALLBACK (surface_state_changed), widget); + g_signal_connect_swapped (surface, "notify::mapped", G_CALLBACK (surface_state_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); diff --git a/tests/testgtk.c b/tests/testgtk.c index 06a9f0f06a..077d16136b 100644 --- a/tests/testgtk.c +++ b/tests/testgtk.c @@ -4531,8 +4531,6 @@ surface_state_callback (GdkSurface *window, new_state = gdk_toplevel_get_state (GDK_TOPLEVEL (window)); msg = g_strconcat ((const char *)g_object_get_data (G_OBJECT (label), "title"), ": ", - (new_state & GDK_TOPLEVEL_STATE_WITHDRAWN) ? - "withdrawn" : "not withdrawn", ", ", (new_state & GDK_TOPLEVEL_STATE_MINIMIZED) ? "minimized" : "not minimized", ", ", (new_state & GDK_TOPLEVEL_STATE_STICKY) ? From fea1b151e6b8c728acefc1e8b585be9b7e40cf75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Mon, 7 Dec 2020 22:29:51 +0100 Subject: [PATCH 84/87] testsuite/filtermodel: Remove calls to gtk_widget_realize() They don't do what they used to do. --- testsuite/gtk/filtermodel.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/testsuite/gtk/filtermodel.c b/testsuite/gtk/filtermodel.c index 51728532be..2bf39ab0f3 100644 --- a/testsuite/gtk/filtermodel.c +++ b/testsuite/gtk/filtermodel.c @@ -4691,7 +4691,6 @@ specific_append_after_collapse (void) window = gtk_window_new (); tree_view = gtk_tree_view_new_with_model (sort); gtk_window_set_child (GTK_WINDOW (window), tree_view); - gtk_widget_realize (tree_view); while (g_main_context_pending (NULL)) g_main_context_iteration (NULL, TRUE); @@ -4811,7 +4810,6 @@ specific_sort_filter_remove_node (void) window = gtk_window_new (); tree_view = gtk_tree_view_new_with_model (filter); gtk_window_set_child (GTK_WINDOW (window), tree_view); - gtk_widget_realize (tree_view); while (g_main_context_pending (NULL)) g_main_context_iteration (NULL, TRUE); From 130ff5f841f337c3cfd0bb4fcd4b2581d3d82235 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Mon, 7 Dec 2020 22:41:36 +0100 Subject: [PATCH 85/87] testsuite/notify: Don't fiddle with GtkWidget::visible It may map toplevel windows with arbitrary modes, which will effect other properties, such as GtkWindow::maximized and GtkWindow::fullscreen. --- testsuite/gtk/notify.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/testsuite/gtk/notify.c b/testsuite/gtk/notify.c index 12ae9edb89..7809d4e915 100644 --- a/testsuite/gtk/notify.c +++ b/testsuite/gtk/notify.c @@ -524,7 +524,8 @@ test_type (gconstpointer data) g_str_equal (pspec->name, "has-default") || g_str_equal (pspec->name, "is-focus") || g_str_equal (pspec->name, "hexpand") || - g_str_equal (pspec->name, "vexpand"))) + g_str_equal (pspec->name, "vexpand") || + g_str_equal (pspec->name, "visible"))) continue; if (g_type_is_a (type, GTK_TYPE_ACCESSIBLE) && From 7b7f3342d8320d1205ad5da68b4d7efa16f547ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Tue, 8 Dec 2020 12:03:18 +0100 Subject: [PATCH 86/87] reftests/textview-tags: Hide text view cursor Otherwise it'd sometimes show up, causing test flakyness. --- testsuite/reftests/textview-tags.ref.ui | 1 + testsuite/reftests/textview-tags.ui | 1 + 2 files changed, 2 insertions(+) diff --git a/testsuite/reftests/textview-tags.ref.ui b/testsuite/reftests/textview-tags.ref.ui index 35a68abf20..c55837f484 100644 --- a/testsuite/reftests/textview-tags.ref.ui +++ b/testsuite/reftests/textview-tags.ref.ui @@ -37,6 +37,7 @@ + false textbuffer1 diff --git a/testsuite/reftests/textview-tags.ui b/testsuite/reftests/textview-tags.ui index 88da7b5493..4119eb4d47 100644 --- a/testsuite/reftests/textview-tags.ui +++ b/testsuite/reftests/textview-tags.ui @@ -37,6 +37,7 @@ + false textbuffer1 From 074b933ae4e866d092edd734fd43524e39033b5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Tue, 8 Dec 2020 14:22:59 +0100 Subject: [PATCH 87/87] reftests: Remove window-show-contents-on-map.ui test It tested that a widget shown after the window was mapped deals with window resizing appropriately when doing the follow-up allocation. Now, doing this only allocates both at the same time, as allocation happens during the frame dispatch. To do the equivalent now, one would have to write code that shows the label after the first frame was drawn, and that's not possible via a reftest, so lets remove it. --- testsuite/reftests/meson.build | 2 -- .../reftests/window-show-contents-on-map.ref.ui | 16 ---------------- .../reftests/window-show-contents-on-map.ui | 15 --------------- 3 files changed, 33 deletions(-) delete mode 100644 testsuite/reftests/window-show-contents-on-map.ref.ui delete mode 100644 testsuite/reftests/window-show-contents-on-map.ui diff --git a/testsuite/reftests/meson.build b/testsuite/reftests/meson.build index 8df36fab93..a50b8f84df 100644 --- a/testsuite/reftests/meson.build +++ b/testsuite/reftests/meson.build @@ -439,8 +439,6 @@ testdata = [ 'window-default-size.ui', 'window-height-for-width.ref.ui', 'window-height-for-width.ui', - 'window-show-contents-on-map.ref.ui', - 'window-show-contents-on-map.ui', ] # These need to be fixed but the issue hasn't been tracked down. diff --git a/testsuite/reftests/window-show-contents-on-map.ref.ui b/testsuite/reftests/window-show-contents-on-map.ref.ui deleted file mode 100644 index f24540ed6b..0000000000 --- a/testsuite/reftests/window-show-contents-on-map.ref.ui +++ /dev/null @@ -1,16 +0,0 @@ - - - - 200 - 200 - 0 - - - This label is only shown when the window is mapped. So the window does its first size allocation without the label being visible and has to resize. - 1 - 20 - 20 - - - - diff --git a/testsuite/reftests/window-show-contents-on-map.ui b/testsuite/reftests/window-show-contents-on-map.ui deleted file mode 100644 index 88e00d8e51..0000000000 --- a/testsuite/reftests/window-show-contents-on-map.ui +++ /dev/null @@ -1,15 +0,0 @@ - - - - 0 - - - - 0 - This label is only shown when the window is mapped. So the window does its first size allocation without the label being visible and has to resize. - 20 - 1 - - - -