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.
This commit is contained in:
Jonas Ådahl
2020-12-04 15:40:53 +01:00
parent 8e3ee58e3f
commit dfb7ab3352
2 changed files with 102 additions and 40 deletions

View File

@@ -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);
}

View File

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