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] 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;