From 09373bf7ee4c6069a5825a363f11b7b0f229d04b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20Cobos=20=C3=81lvarez?= Date: Mon, 8 Jan 2024 14:44:57 +0100 Subject: [PATCH] [gtk3/wayland] Fix GdkMonitor sizes on Mutter without fractional scaling. This is the gtk3 version of !6722. This fixes a problem that is apparent in https://bugzilla.mozilla.org/show_bug.cgi?id=1869724, but that also reproduces on any GTK application as described in https://bugzilla.mozilla.org/show_bug.cgi?id=1869724#c16. xdg_output sizes might be physical if the compositor doesn't scale them, it seems. So to report the correct logical geometry in GDK pixels, we need to detect this case. We do this by checking whether the wl_output size matches the xdg_output size. --- gdk/wayland/gdkmonitor-wayland.h | 9 ++-- gdk/wayland/gdkscreen-wayland.c | 76 ++++++++++++++++++-------------- 2 files changed, 47 insertions(+), 38 deletions(-) diff --git a/gdk/wayland/gdkmonitor-wayland.h b/gdk/wayland/gdkmonitor-wayland.h index 8c65bbfc4a..b4a831e0fa 100644 --- a/gdk/wayland/gdkmonitor-wayland.h +++ b/gdk/wayland/gdkmonitor-wayland.h @@ -31,11 +31,10 @@ struct _GdkWaylandMonitor { struct wl_output *output; struct zxdg_output_v1 *xdg_output; - /* Size and position, can be either from wl_output or xdg_output */ - int32_t x; - int32_t y; - int32_t width; - int32_t height; + /* Raw wl_output data */ + GdkRectangle output_geometry; + /* Raw xdg_output data */ + GdkRectangle xdg_output_geometry; char *name; gboolean wl_output_done; gboolean xdg_output_done; diff --git a/gdk/wayland/gdkscreen-wayland.c b/gdk/wayland/gdkscreen-wayland.c index 9aec01b0b6..6ea16cef1b 100644 --- a/gdk/wayland/gdkscreen-wayland.c +++ b/gdk/wayland/gdkscreen-wayland.c @@ -1552,17 +1552,43 @@ should_expect_xdg_output_done (GdkWaylandMonitor *monitor) static void apply_monitor_change (GdkWaylandMonitor *monitor) { + GDK_NOTE (MISC, + g_message ("monitor %d changed position %d %d, size %d %d", + monitor->id, monitor->output_geometry.x, + monitor->output_geometry.y, + monitor->output_geometry.width, + monitor->output_geometry.height)); + GdkDisplay *display = GDK_MONITOR (monitor)->display; GdkWaylandScreen *screen_wayland = GDK_WAYLAND_SCREEN (gdk_display_get_default_screen (display)); - GDK_NOTE (MISC, - g_message ("monitor %d changed position %d %d, size %d %d", - monitor->id, - monitor->x, monitor->y, - monitor->width, monitor->height)); + GdkRectangle logical_geometry; + gboolean needs_scaling = FALSE; - gdk_monitor_set_position (GDK_MONITOR (monitor), monitor->x, monitor->y); - gdk_monitor_set_size (GDK_MONITOR (monitor), monitor->width, monitor->height); + if (monitor_has_xdg_output(monitor)) + { + logical_geometry = monitor->xdg_output_geometry; + needs_scaling = + logical_geometry.width == monitor->output_geometry.width || + logical_geometry.height == monitor->output_geometry.height; + } + else + { + logical_geometry = monitor->output_geometry; + needs_scaling = TRUE; + } + + if (needs_scaling) + { + int scale = gdk_monitor_get_scale_factor (GDK_MONITOR (monitor)); + logical_geometry.y /= scale; + logical_geometry.x /= scale; + logical_geometry.width /= scale; + logical_geometry.height /= scale; + } + + gdk_monitor_set_position (GDK_MONITOR (monitor), logical_geometry.x, logical_geometry.y); + gdk_monitor_set_size (GDK_MONITOR (monitor), logical_geometry.width, logical_geometry.height); gdk_monitor_set_connector (GDK_MONITOR (monitor), monitor->name); monitor->wl_output_done = FALSE; monitor->xdg_output_done = FALSE; @@ -1582,8 +1608,9 @@ xdg_output_handle_logical_position (void *data, GDK_NOTE (MISC, g_message ("handle logical position xdg-output %d, position %d %d", monitor->id, x, y)); - monitor->x = x; - monitor->y = y; + + monitor->xdg_output_geometry.x = x; + monitor->xdg_output_geometry.y = y; } static void @@ -1597,8 +1624,9 @@ xdg_output_handle_logical_size (void *data, GDK_NOTE (MISC, g_message ("handle logical size xdg-output %d, size %d %d", monitor->id, width, height)); - monitor->width = width; - monitor->height = height; + + monitor->xdg_output_geometry.width = width; + monitor->xdg_output_geometry.height = height; } static void @@ -1685,8 +1713,8 @@ output_handle_geometry (void *data, g_message ("handle geometry output %d, position %d %d, phys. size %d %d, subpixel layout %s, manufacturer %s, model %s, transform %s", monitor->id, x, y, physical_width, physical_height, subpixel_to_string (subpixel), make, model, transform_to_string (transform))); - monitor->x = x; - monitor->y = y; + monitor->output_geometry.x = x; + monitor->output_geometry.y = y; switch (transform) { @@ -1731,29 +1759,13 @@ output_handle_scale (void *data, int32_t scale) { GdkWaylandMonitor *monitor = (GdkWaylandMonitor *)data; - GdkRectangle previous_geometry; - int previous_scale; - int width; - int height; GDK_NOTE (MISC, g_message ("handle scale output %d, scale %d", monitor->id, scale)); - gdk_monitor_get_geometry (GDK_MONITOR (monitor), &previous_geometry); - previous_scale = gdk_monitor_get_scale_factor (GDK_MONITOR (monitor)); - /* Set the scale from wl_output protocol, regardless of xdg-output support */ gdk_monitor_set_scale_factor (GDK_MONITOR (monitor), scale); - if (monitor_has_xdg_output (monitor)) - return; - - width = previous_geometry.width * previous_scale; - height = previous_geometry.height * previous_scale; - - monitor->width = width / scale; - monitor->height = height / scale; - if (should_update_monitor (monitor)) apply_monitor_change (monitor); } @@ -1767,7 +1779,6 @@ output_handle_mode (void *data, int refresh) { GdkWaylandMonitor *monitor = (GdkWaylandMonitor *)data; - int scale; GDK_NOTE (MISC, g_message ("handle mode output %d, size %d %d, rate %d", @@ -1776,9 +1787,8 @@ output_handle_mode (void *data, if ((flags & WL_OUTPUT_MODE_CURRENT) == 0) return; - scale = gdk_monitor_get_scale_factor (GDK_MONITOR (monitor)); - monitor->width = width / scale; - monitor->height = height / scale; + monitor->output_geometry.width = width; + monitor->output_geometry.height = height; gdk_monitor_set_refresh_rate (GDK_MONITOR (monitor), refresh); if (should_update_monitor (monitor) || !monitor_has_xdg_output (monitor))