xserver: Branch 'master' - 19 commits

GitLab Mirror gitlab-mirror at kemper.freedesktop.org
Wed Mar 20 08:13:55 UTC 2024


 hw/xwayland/man/Xwayland.man  |    5 
 hw/xwayland/meson.build       |    4 
 hw/xwayland/xwayland-cursor.c |   22 +-
 hw/xwayland/xwayland-input.c  |   74 ++++++-
 hw/xwayland/xwayland-output.c |   82 +++++++-
 hw/xwayland/xwayland-output.h |    8 
 hw/xwayland/xwayland-screen.c |   77 +++++++-
 hw/xwayland/xwayland-screen.h |   12 +
 hw/xwayland/xwayland-window.c |  400 ++++++++++++++++++++++++++++++++++++++----
 hw/xwayland/xwayland-window.h |   15 +
 hw/xwayland/xwayland.c        |    4 
 meson.build                   |    2 
 12 files changed, 644 insertions(+), 61 deletions(-)

New commits:
commit 821d3d5789b366f6749b72e74f1e2fe7d6a93d9b
Author: Olivier Fourdan <ofourdan at redhat.com>
Date:   Mon Nov 27 14:40:25 2023 +0100

    xwayland: Use fractional scale with rootful
    
    Implement fractional scale with Xwayland rootful by scaling the content
    to the desired fractional scale using a viewport.
    
    For now this applies to Xwayland rootful only.
    
    Signed-off-by: Olivier Fourdan <ofourdan at redhat.com>
    Reviewed-By: Kenny Levinsen <kl at kl.wtf>
    Acked-by: Peter Hutterer <peter.hutterer at who-t.net>
    Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1197>

diff --git a/hw/xwayland/xwayland-window.c b/hw/xwayland/xwayland-window.c
index 0ba432fb8..f4d8a0227 100644
--- a/hw/xwayland/xwayland-window.c
+++ b/hw/xwayland/xwayland-window.c
@@ -27,6 +27,7 @@
 #include <dix-config.h>
 #endif
 
+#include <float.h>
 #include <math.h>
 #include <sys/mman.h>
 
@@ -53,6 +54,7 @@
 #include "viewporter-client-protocol.h"
 #include "xdg-shell-client-protocol.h"
 #include "xwayland-shell-v1-client-protocol.h"
+#include "fractional-scale-v1-client-protocol.h"
 
 #define DELAYED_WL_SURFACE_DESTROY 1000 /* ms */
 
@@ -61,6 +63,8 @@
 #define MIN_ROOTFUL_WIDTH 320
 #define MIN_ROOTFUL_HEIGHT 200
 
+#define FRACTIONAL_SCALE_DENOMINATOR 120
+
 static DevPrivateKeyRec xwl_window_private_key;
 static DevPrivateKeyRec xwl_damage_private_key;
 static const char *xwl_surface_tag = "xwl-surface";
@@ -246,6 +250,24 @@ unregister_damage(WindowPtr window)
     dixSetPrivate(&window->devPrivates, &xwl_damage_private_key, NULL);
 }
 
+static Bool
+xwl_window_update_fractional_scale(struct xwl_window *xwl_window,
+                                   int fractional_scale_numerator)
+{
+    int old_scale_numerator = xwl_window->fractional_scale_numerator;
+
+    xwl_window->fractional_scale_numerator = fractional_scale_numerator;
+
+    return (old_scale_numerator != fractional_scale_numerator);
+}
+
+static double
+xwl_window_get_fractional_scale_factor(struct xwl_window *xwl_window)
+{
+    return (double) xwl_window->fractional_scale_numerator /
+           (double) FRACTIONAL_SCALE_DENOMINATOR;
+}
+
 static Bool
 xwl_window_has_viewport_enabled(struct xwl_window *xwl_window)
 {
@@ -264,6 +286,42 @@ xwl_window_disable_viewport(struct xwl_window *xwl_window)
     xwl_window->viewport_scale_y = 1.0;
 }
 
+/* Enable the viewport for fractional scale support with Xwayland rootful.
+ * Fractional scale support is not used with Xwayland rootful fullscreen (which
+ * sets its own XRandR resolution) so we can use the viewport for either
+ * fullscreen mode or fractional scale.
+ */
+static void
+xwl_window_enable_viewport_for_fractional_scale(struct xwl_window *xwl_window,
+                                                int width, int height)
+{
+    struct xwl_screen *xwl_screen = xwl_window->xwl_screen;
+    int buffer_width, buffer_height;
+    double scale;
+
+    scale = xwl_window_get_fractional_scale_factor(xwl_window);
+    buffer_width = round((double) width / scale);
+    buffer_height = round((double) height / scale);
+
+    if (!xwl_window_has_viewport_enabled(xwl_window))
+        xwl_window->viewport = wp_viewporter_get_viewport(xwl_screen->viewporter,
+                                                          xwl_window->surface);
+
+    DebugF("XWAYLAND: enabling viewport for fractional scale %dx%d -> %dx%d\n",
+           width, height, buffer_width, buffer_height);
+    wp_viewport_set_source(xwl_window->viewport,
+                           wl_fixed_from_int(0),
+                           wl_fixed_from_int(0),
+                           wl_fixed_from_int(width),
+                           wl_fixed_from_int(height));
+    wp_viewport_set_destination(xwl_window->viewport,
+                                buffer_width,
+                                buffer_height);
+
+    xwl_window->viewport_scale_x = scale;
+    xwl_window->viewport_scale_y = scale;
+}
+
 /* Enable the viewport for Xwayland rootful fullscreen, to match the XRandR
  * resolution with the actual output size.
  */
@@ -434,6 +492,35 @@ xwl_window_should_enable_viewport(struct xwl_window *xwl_window,
     return FALSE;
 }
 
+static Bool
+xwl_window_should_enable_fractional_scale_viewport(struct xwl_window *xwl_window)
+{
+    struct xwl_screen *xwl_screen = xwl_window->xwl_screen;
+    double scale;
+
+    if (!xwl_screen_should_use_fractional_scale(xwl_screen))
+        return FALSE;
+
+    scale = xwl_window_get_fractional_scale_factor(xwl_window);
+
+    return fabs(scale - 1.00) > FLT_EPSILON;
+}
+
+static void
+xwl_window_check_fractional_scale_viewport(struct xwl_window *xwl_window,
+                                           int width, int height)
+{
+    struct xwl_screen *xwl_screen = xwl_window->xwl_screen;
+
+    if (!xwl_screen_should_use_fractional_scale(xwl_screen))
+        return;
+
+    if (xwl_window_should_enable_fractional_scale_viewport(xwl_window))
+        xwl_window_enable_viewport_for_fractional_scale(xwl_window, width, height);
+    else if (xwl_window_has_viewport_enabled(xwl_window))
+        xwl_window_disable_viewport(xwl_window);
+}
+
 void
 xwl_window_check_resolution_change_emulation(struct xwl_window *xwl_window)
 {
@@ -442,6 +529,8 @@ xwl_window_check_resolution_change_emulation(struct xwl_window *xwl_window)
 
     if (xwl_window_should_enable_viewport(xwl_window, &xwl_output, &emulated_mode))
         xwl_window_enable_viewport_for_output(xwl_window, xwl_output, &emulated_mode);
+    else if (xwl_window_should_enable_fractional_scale_viewport(xwl_window))
+        return;
     else if (xwl_window_has_viewport_enabled(xwl_window))
         xwl_window_disable_viewport(xwl_window);
 }
@@ -673,6 +762,13 @@ xwl_window_maybe_resize(struct xwl_window *xwl_window, double width, double heig
     xwl_screen->width = width;
     xwl_screen->height = height;
 
+    /* When fractional scale is used, the global surface scale is 1, and vice
+     * versa, so we can multiply the two here, and have the resulting scale
+     * apply for both cases, the legacy wl_surface buffer scale and fractional
+     * scaling.
+     */
+    scale *= xwl_window_get_fractional_scale_factor(xwl_window);
+
     xwl_output = xwl_screen_get_fixed_or_first_output(xwl_screen);
     if (!xwl_randr_add_modes_fixed(xwl_output, round(width / scale), round(height / scale)))
         return;
@@ -707,9 +803,12 @@ xwl_window_update_libdecor_size(struct xwl_window *xwl_window,
                                 int width, int height)
 {
     struct libdecor_state *state;
+    double scale;
 
     if (xwl_window->libdecor_frame) {
-	state = libdecor_state_new(width, height);
+	scale = xwl_window_get_fractional_scale_factor(xwl_window);
+	state = libdecor_state_new(round((double) width / scale),
+	                           round((double) height / scale));
 	libdecor_frame_commit(xwl_window->libdecor_frame, state, configuration);
 	libdecor_state_free(state);
     }
@@ -724,6 +823,7 @@ handle_libdecor_configure(struct libdecor_frame *frame,
     struct xwl_screen *xwl_screen = xwl_window->xwl_screen;
     int width, height;
     double new_width, new_height;
+    double scale;
 
     if (libdecor_configuration_get_content_size(configuration, frame, &width, &height)) {
         new_width = (double) width;
@@ -737,6 +837,10 @@ handle_libdecor_configure(struct libdecor_frame *frame,
     new_width *= xwl_screen->global_surface_scale;
     new_height *= xwl_screen->global_surface_scale;
 
+    scale = xwl_window_get_fractional_scale_factor(xwl_window);
+    new_width *= scale;
+    new_height *= scale;
+
     xwl_window_maybe_resize(xwl_window, new_width, new_height);
 
     new_width = xwl_screen->width / xwl_screen->global_surface_scale;
@@ -941,15 +1045,20 @@ xdg_toplevel_handle_configure(void *data,
     struct xwl_screen *xwl_screen = xwl_window->xwl_screen;
     uint32_t *p;
     Bool old_active = xwl_screen->active;
-    int new_width, new_height;
+    double scale, new_width, new_height;
 
     /* Maintain our current size if no dimensions are requested */
     if (width == 0 && height == 0)
         return;
 
     if (!xwl_screen->fullscreen) {
-        new_width = width * xwl_screen->global_surface_scale;
-        new_height = height * xwl_screen->global_surface_scale;
+        new_width = (double) (width * xwl_screen->global_surface_scale);
+        new_height = (double) (height * xwl_screen->global_surface_scale);
+
+        scale = xwl_window_get_fractional_scale_factor(xwl_window);
+        new_width *= scale;
+        new_height *= scale;
+
         /* This will be committed by the xdg_surface.configure handler */
         xwl_window_maybe_resize(xwl_window, new_width, new_height);
     }
@@ -982,6 +1091,58 @@ static const struct xdg_toplevel_listener xdg_toplevel_listener = {
     xdg_toplevel_handle_close,
 };
 
+static void
+xwl_window_update_rootful_scale(struct xwl_window *xwl_window, double previous_scale)
+{
+    struct xwl_screen *xwl_screen = xwl_window->xwl_screen;
+    double new_scale, new_width, new_height;
+
+    new_scale = xwl_window_get_fractional_scale_factor(xwl_window);
+    new_width = xwl_screen->width / previous_scale * new_scale;
+    new_height = xwl_screen->height / previous_scale * new_scale;
+
+    DebugF("XWAYLAND: Fractional scale is now %.2f (was %.2f)\n",
+           new_scale, previous_scale);
+
+    xwl_output_set_xscale(xwl_screen->fixed_output, new_scale);
+    xwl_window_maybe_resize(xwl_window, new_width, new_height);
+    xwl_window_check_fractional_scale_viewport(xwl_window,
+                                               xwl_screen_get_width(xwl_screen),
+                                               xwl_screen_get_height(xwl_screen));
+
+#ifdef XWL_HAS_LIBDECOR
+    if (xwl_window->libdecor_frame) {
+        xwl_window_libdecor_set_size_limits(xwl_window);
+        xwl_window_update_libdecor_size(xwl_window,
+                                        NULL,
+                                        xwl_screen_get_width(xwl_screen),
+                                        xwl_screen_get_height(xwl_screen));
+    }
+    else
+#endif
+        wl_surface_commit(xwl_window->surface);
+}
+
+static void
+wp_fractional_scale_preferred_scale(void *data,
+                                    struct wp_fractional_scale_v1 *fractional_scale,
+                                    uint32_t scale_numerator)
+{
+    struct xwl_window *xwl_window = data;
+    struct xwl_screen *xwl_screen = xwl_window->xwl_screen;
+    double previous_scale = xwl_window_get_fractional_scale_factor(xwl_window);
+
+    if (xwl_window_update_fractional_scale(xwl_window, scale_numerator)) {
+        if (xwl_screen->fixed_output) { /* We're running rootful */
+            xwl_window_update_rootful_scale(xwl_window, previous_scale);
+        }
+    }
+}
+
+static const struct wp_fractional_scale_v1_listener fractional_scale_listener = {
+   wp_fractional_scale_preferred_scale,
+};
+
 static Bool
 xwl_create_root_surface(struct xwl_window *xwl_window)
 {
@@ -1028,6 +1189,14 @@ xwl_create_root_surface(struct xwl_window *xwl_window)
     wl_surface_add_listener(xwl_window->surface,
                             &surface_listener, xwl_window);
 
+    if (xwl_screen_should_use_fractional_scale(xwl_screen)) {
+        xwl_window->fractional_scale =
+            wp_fractional_scale_manager_v1_get_fractional_scale(xwl_screen->fractional_scale_manager,
+                                                                xwl_window->surface);
+        wp_fractional_scale_v1_add_listener(xwl_window->fractional_scale,
+                                            &fractional_scale_listener, xwl_window);
+    }
+
     xwl_window_rootful_update_title(xwl_window);
     xwl_window_rootful_set_app_id(xwl_window);
     wl_surface_commit(xwl_window->surface);
@@ -1083,8 +1252,10 @@ ensure_surface_for_window(WindowPtr window)
 
     xwl_window->xwl_screen = xwl_screen;
     xwl_window->window = window;
+    xwl_window->fractional_scale_numerator = FRACTIONAL_SCALE_DENOMINATOR;
     xwl_window->viewport_scale_x = 1.0;
     xwl_window->viewport_scale_y = 1.0;
+    xwl_window->surface_scale = 1;
     xorg_list_init(&xwl_window->xwl_output_list);
     xwl_window->surface = wl_compositor_create_surface(xwl_screen->compositor);
     if (xwl_window->surface == NULL) {
@@ -1322,6 +1493,9 @@ xwl_unrealize_window(WindowPtr window)
     if (xwl_window->tearing_control)
         wp_tearing_control_v1_destroy(xwl_window->tearing_control);
 
+    if (xwl_window->fractional_scale)
+        wp_fractional_scale_v1_destroy(xwl_window->fractional_scale);
+
     release_wl_surface_for_window(xwl_window);
     xorg_list_del(&xwl_window->link_damage);
     xorg_list_del(&xwl_window->link_window);
@@ -1419,16 +1593,17 @@ xwl_resize_window(WindowPtr window,
     if (xwl_window) {
         if (xwl_window_get(window) || xwl_window_is_toplevel(window))
             xwl_window_check_resolution_change_emulation(xwl_window);
-#ifdef XWL_HAS_LIBDECOR
         if (window == screen->root) {
+#ifdef XWL_HAS_LIBDECOR
             unsigned int decor_width, decor_height;
 
             decor_width = width / xwl_screen->global_surface_scale;
             decor_height = height / xwl_screen->global_surface_scale;
             xwl_window_update_libdecor_size(xwl_window, NULL,
                                             decor_width, decor_height);
-        }
 #endif
+            xwl_window_check_fractional_scale_viewport(xwl_window, width, height);
+        }
     }
 }
 
diff --git a/hw/xwayland/xwayland-window.h b/hw/xwayland/xwayland-window.h
index 03b4ad249..108c19e09 100644
--- a/hw/xwayland/xwayland-window.h
+++ b/hw/xwayland/xwayland-window.h
@@ -82,6 +82,8 @@ struct xwl_window {
     /* If TRUE, the window buffer format supports scanout with implicit modifier */
     Bool has_implicit_scanout_support;
     struct wp_tearing_control_v1 *tearing_control;
+    struct wp_fractional_scale_v1 *fractional_scale;
+    int fractional_scale_numerator;
 };
 
 struct xwl_window *xwl_window_get(WindowPtr window);
commit 3e77c1699a843c0512a347cf25938d1f93e715ae
Author: Olivier Fourdan <ofourdan at redhat.com>
Date:   Mon Nov 27 13:57:58 2023 +0100

    xwayland: Add helper function for fractional scaling
    
    Fractional scaling may not be available, or not suitable for the current
    configuration (e.g. if running rootless).
    
    Add a helper function to tell whether fractional scaling should be used.
    
    Signed-off-by: Olivier Fourdan <ofourdan at redhat.com>
    Reviewed-By: Kenny Levinsen <kl at kl.wtf>
    Acked-by: Peter Hutterer <peter.hutterer at who-t.net>
    Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1197>

diff --git a/hw/xwayland/xwayland-screen.c b/hw/xwayland/xwayland-screen.c
index 6a0f5a2ef..42c9a0e20 100644
--- a/hw/xwayland/xwayland-screen.c
+++ b/hw/xwayland/xwayland-screen.c
@@ -773,6 +773,26 @@ xwl_screen_lost_focus(struct xwl_screen *xwl_screen)
     }
 }
 
+Bool
+xwl_screen_should_use_fractional_scale(struct xwl_screen *xwl_screen)
+{
+    /* Fullscreen uses a viewport already */
+    if (xwl_screen->fullscreen)
+        return FALSE;
+
+    if (xwl_screen->rootless)
+        return FALSE;
+
+    /* We need both fractional scale and viewporter protocols */
+    if (!xwl_screen->fractional_scale_manager)
+        return FALSE;
+
+    if (!xwl_screen->viewporter)
+        return FALSE;
+
+    return xwl_screen->hidpi;
+}
+
 Bool
 xwl_screen_update_global_surface_scale(struct xwl_screen *xwl_screen)
 {
@@ -780,6 +800,9 @@ xwl_screen_update_global_surface_scale(struct xwl_screen *xwl_screen)
     struct xwl_window *xwl_window;
     int32_t old_scale;
 
+    if (xwl_screen_should_use_fractional_scale(xwl_screen))
+        return FALSE;
+
     if (xwl_screen->rootless)
         return FALSE;
 
diff --git a/hw/xwayland/xwayland-screen.h b/hw/xwayland/xwayland-screen.h
index d2c0865b8..477473eea 100644
--- a/hw/xwayland/xwayland-screen.h
+++ b/hw/xwayland/xwayland-screen.h
@@ -173,5 +173,6 @@ void xwl_surface_damage(struct xwl_screen *xwl_screen,
 int xwl_screen_get_next_output_serial(struct xwl_screen * xwl_screen);
 void xwl_screen_lost_focus(struct xwl_screen *xwl_screen);
 Bool xwl_screen_update_global_surface_scale(struct xwl_screen *xwl_screen);
+Bool xwl_screen_should_use_fractional_scale(struct xwl_screen *xwl_screen);
 
 #endif /* XWAYLAND_SCREEN_H */
commit 7a78756d0a4e7a2332e53940413b9e61b418345b
Author: Olivier Fourdan <ofourdan at redhat.com>
Date:   Wed Nov 22 08:59:21 2023 +0100

    xwayland: Add support for fractional scale protocol
    
    Add support for wp_fractional_scale_v1 protocol.
    
    Signed-off-by: Olivier Fourdan <ofourdan at redhat.com>
    Reviewed-By: Kenny Levinsen <kl at kl.wtf>
    Acked-by: Peter Hutterer <peter.hutterer at who-t.net>
    Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1197>

diff --git a/hw/xwayland/meson.build b/hw/xwayland/meson.build
index f27c3ea2b..7a9645c00 100644
--- a/hw/xwayland/meson.build
+++ b/hw/xwayland/meson.build
@@ -49,6 +49,7 @@ drm_lease_xml = join_paths(protodir, 'staging', 'drm-lease', 'drm-lease-v1.xml')
 shortcuts_inhibit_xml = join_paths(protodir, 'unstable', 'keyboard-shortcuts-inhibit', 'keyboard-shortcuts-inhibit-unstable-v1.xml')
 xwayland_shell_xml = join_paths(protodir, 'staging', 'xwayland-shell', 'xwayland-shell-v1.xml')
 tearing_xml = join_paths(protodir, 'staging', 'tearing-control', 'tearing-control-v1.xml')
+fractional_scale_xml = join_paths(protodir, 'staging', 'fractional-scale', 'fractional-scale-v1.xml')
 
 client_header = generator(scanner,
     output : '@BASENAME at -client-protocol.h',
@@ -78,6 +79,7 @@ srcs += client_header.process(drm_lease_xml)
 srcs += client_header.process(shortcuts_inhibit_xml)
 srcs += client_header.process(xwayland_shell_xml)
 srcs += client_header.process(tearing_xml)
+srcs += client_header.process(fractional_scale_xml)
 srcs += code.process(relative_xml)
 srcs += code.process(pointer_xml)
 srcs += code.process(gestures_xml)
@@ -91,6 +93,7 @@ srcs += code.process(drm_lease_xml)
 srcs += code.process(shortcuts_inhibit_xml)
 srcs += code.process(xwayland_shell_xml)
 srcs += code.process(tearing_xml)
+srcs += code.process(fractional_scale_xml)
 
 if build_ei
     xwayland_dep += libei_dep
diff --git a/hw/xwayland/xwayland-screen.c b/hw/xwayland/xwayland-screen.c
index 39e2439df..6a0f5a2ef 100644
--- a/hw/xwayland/xwayland-screen.c
+++ b/hw/xwayland/xwayland-screen.c
@@ -69,6 +69,7 @@
 #include "xdg-shell-client-protocol.h"
 #include "xwayland-shell-v1-client-protocol.h"
 #include "tearing-control-v1-client-protocol.h"
+#include "fractional-scale-v1-client-protocol.h"
 
 static DevPrivateKeyRec xwl_screen_private_key;
 static DevPrivateKeyRec xwl_client_private_key;
@@ -507,6 +508,10 @@ registry_global(void *data, struct wl_registry *registry, uint32_t id,
         xwl_screen->tearing_control_manager =
             wl_registry_bind(registry, id, &wp_tearing_control_manager_v1_interface, 1);
     }
+    else if (strcmp(interface, wp_fractional_scale_manager_v1_interface.name) == 0) {
+        xwl_screen->fractional_scale_manager =
+            wl_registry_bind(registry, id, &wp_fractional_scale_manager_v1_interface, 1);
+    }
 #ifdef XWL_HAS_GLAMOR
     else if (xwl_screen->glamor) {
         xwl_glamor_init_wl_registry(xwl_screen, registry, id, interface,
diff --git a/hw/xwayland/xwayland-screen.h b/hw/xwayland/xwayland-screen.h
index 1770053d6..d2c0865b8 100644
--- a/hw/xwayland/xwayland-screen.h
+++ b/hw/xwayland/xwayland-screen.h
@@ -111,6 +111,7 @@ struct xwl_screen {
     struct wp_viewporter *viewporter;
     struct xwayland_shell_v1 *xwayland_shell;
     struct wp_tearing_control_manager_v1 *tearing_control_manager;
+    struct wp_fractional_scale_manager_v1 *fractional_scale_manager;
     struct xorg_list drm_lease_devices;
     struct xorg_list queued_drm_lease_devices;
     struct xorg_list drm_leases;
commit 98692300f5de42f2cff874a17d4413107078ae4e
Author: Olivier Fourdan <ofourdan at redhat.com>
Date:   Tue Nov 21 17:11:19 2023 +0100

    build: Bump wayland-protocols requirement to 1.31
    
    This is needed to support the "wp-fractional-scale-v1" protocol.
    
    Signed-off-by: Olivier Fourdan <ofourdan at redhat.com>
    Reviewed-By: Kenny Levinsen <kl at kl.wtf>
    Acked-by: Peter Hutterer <peter.hutterer at who-t.net>
    Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1197>

diff --git a/meson.build b/meson.build
index 0cfa50ce1..935e3b8b1 100644
--- a/meson.build
+++ b/meson.build
@@ -64,7 +64,7 @@ libdrm_req = '>= 2.4.109'
 libselinux_req = '>= 2.0.86'
 xext_req = '>= 1.0.99.4'
 wayland_req = '>= 1.21.0'
-wayland_protocols_req = '>= 1.30'
+wayland_protocols_req = '>= 1.31'
 gbm_req = '>= 10.2'
 xf86dgaproto_req = '>= 2.0.99.1'
 xshmfence_req = '>= 1.1'
commit da84b470cb8f877a4a2e898bbd16cec575bf3143
Author: Olivier Fourdan <ofourdan at redhat.com>
Date:   Wed Nov 22 11:06:59 2023 +0100

    xwayland: Rename xwl_window_enable_viewport()
    
    To support the fractional scale protocol, we need a viewport.
    
    Rename the existing function xwl_window_enable_viewport() to avoid
    confusion with the viewport we use for fullscreen XRandR emulation in
    rootless mode.
    
    No functional change.
    
    Signed-off-by: Olivier Fourdan <ofourdan at redhat.com>
    Reviewed-By: Kenny Levinsen <kl at kl.wtf>
    Acked-by: Peter Hutterer <peter.hutterer at who-t.net>
    Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1197>

diff --git a/hw/xwayland/xwayland-window.c b/hw/xwayland/xwayland-window.c
index a10453e13..0ba432fb8 100644
--- a/hw/xwayland/xwayland-window.c
+++ b/hw/xwayland/xwayland-window.c
@@ -264,10 +264,13 @@ xwl_window_disable_viewport(struct xwl_window *xwl_window)
     xwl_window->viewport_scale_y = 1.0;
 }
 
+/* Enable the viewport for Xwayland rootful fullscreen, to match the XRandR
+ * resolution with the actual output size.
+ */
 static void
-xwl_window_enable_viewport(struct xwl_window *xwl_window,
-                           struct xwl_output *xwl_output,
-                           struct xwl_emulated_mode *emulated_mode)
+xwl_window_enable_viewport_for_output(struct xwl_window *xwl_window,
+                                      struct xwl_output *xwl_output,
+                                      struct xwl_emulated_mode *emulated_mode)
 {
     struct xwl_screen *xwl_screen = xwl_window->xwl_screen;
     int width, height;
@@ -438,7 +441,7 @@ xwl_window_check_resolution_change_emulation(struct xwl_window *xwl_window)
     struct xwl_output *xwl_output;
 
     if (xwl_window_should_enable_viewport(xwl_window, &xwl_output, &emulated_mode))
-        xwl_window_enable_viewport(xwl_window, xwl_output, &emulated_mode);
+        xwl_window_enable_viewport_for_output(xwl_window, xwl_output, &emulated_mode);
     else if (xwl_window_has_viewport_enabled(xwl_window))
         xwl_window_disable_viewport(xwl_window);
 }
commit 4003b1f9a28c4a333cab9ca7e64a7027ed1da58f
Author: Olivier Fourdan <ofourdan at redhat.com>
Date:   Thu Nov 2 11:04:18 2023 +0100

    xwayland: Update the global screen scale
    
    Recompute and update the global screen scale based on the different
    outputs the root window is placed on.
    
    For backward compatibility, this functionality is however disabled by
    default and can be enabled using a new command line option "-hidpi".
    
    That option has no effect if Xwayland is running rootless.
    
    Signed-off-by: Olivier Fourdan <ofourdan at redhat.com>
    Reviewed-By: Kenny Levinsen <kl at kl.wtf>
    Acked-by: Peter Hutterer <peter.hutterer at who-t.net>
    Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1197>

diff --git a/hw/xwayland/man/Xwayland.man b/hw/xwayland/man/Xwayland.man
index 46fd6c2d9..e30799e9a 100644
--- a/hw/xwayland/man/Xwayland.man
+++ b/hw/xwayland/man/Xwayland.man
@@ -82,6 +82,11 @@ and fallback to GL ES if GL version is less than 2.1.
 
 This option is not compatible with \fI-shm\fP option.
 .TP 8
+.B \-hidpi
+Adjust to the scale of the outputs when running rootful in windowing mode.
+
+This option is not compatible with rootless mode (\fI-rootless\fP).
+.TP 8
 .B \-host-grab
 Disable host keyboard shorcuts and confine the pointer when running rootful.
 
diff --git a/hw/xwayland/meson.build b/hw/xwayland/meson.build
index ee05749d7..f27c3ea2b 100644
--- a/hw/xwayland/meson.build
+++ b/hw/xwayland/meson.build
@@ -174,6 +174,7 @@ xwayland_vars = [
     'have_decorate=' + have_libdecor.to_string(),
     'have_enable_ei_portal=' + build_ei_portal.to_string(),
     'have_byteswappedclients=true',
+    'have_hidpi=true',
 ]
 
 pkgconfig = import('pkgconfig')
diff --git a/hw/xwayland/xwayland-screen.c b/hw/xwayland/xwayland-screen.c
index 11460a723..39e2439df 100644
--- a/hw/xwayland/xwayland-screen.c
+++ b/hw/xwayland/xwayland-screen.c
@@ -768,6 +768,35 @@ xwl_screen_lost_focus(struct xwl_screen *xwl_screen)
     }
 }
 
+Bool
+xwl_screen_update_global_surface_scale(struct xwl_screen *xwl_screen)
+{
+    ScreenPtr screen = xwl_screen->screen;
+    struct xwl_window *xwl_window;
+    int32_t old_scale;
+
+    if (xwl_screen->rootless)
+        return FALSE;
+
+    if (xwl_screen->fullscreen)
+        return FALSE;
+
+    if (!xwl_screen->hidpi)
+        return FALSE;
+
+    if (screen->root == NullWindow)
+        return FALSE;
+
+    xwl_window = xwl_window_get(screen->root);
+    if (!xwl_window)
+        return FALSE;
+
+    old_scale = xwl_screen->global_surface_scale;
+    xwl_screen->global_surface_scale = xwl_window_get_max_output_scale(xwl_window);
+
+    return (xwl_screen->global_surface_scale != old_scale);
+}
+
 Bool
 xwl_screen_init(ScreenPtr pScreen, int argc, char **argv)
 {
@@ -881,6 +910,9 @@ xwl_screen_init(ScreenPtr pScreen, int argc, char **argv)
         else if (strcmp(argv[i], "-nokeymap") == 0) {
             xwl_screen->nokeymap = 1;
         }
+        else if (strcmp(argv[i], "-hidpi") == 0) {
+            xwl_screen->hidpi = 1;
+        }
     }
 
     if (!xwl_screen->rootless) {
diff --git a/hw/xwayland/xwayland-screen.h b/hw/xwayland/xwayland-screen.h
index c8c093fbe..1770053d6 100644
--- a/hw/xwayland/xwayland-screen.h
+++ b/hw/xwayland/xwayland-screen.h
@@ -66,6 +66,7 @@ struct xwl_screen {
     int decorate;
     int enable_ei_portal;
     int nokeymap;
+    int hidpi;
 
     CreateScreenResourcesProcPtr CreateScreenResources;
     CloseScreenProcPtr CloseScreen;
@@ -170,5 +171,6 @@ void xwl_surface_damage(struct xwl_screen *xwl_screen,
                         int32_t x, int32_t y, int32_t width, int32_t height);
 int xwl_screen_get_next_output_serial(struct xwl_screen * xwl_screen);
 void xwl_screen_lost_focus(struct xwl_screen *xwl_screen);
+Bool xwl_screen_update_global_surface_scale(struct xwl_screen *xwl_screen);
 
 #endif /* XWAYLAND_SCREEN_H */
diff --git a/hw/xwayland/xwayland-window.c b/hw/xwayland/xwayland-window.c
index 626a5d22d..a10453e13 100644
--- a/hw/xwayland/xwayland-window.c
+++ b/hw/xwayland/xwayland-window.c
@@ -671,10 +671,10 @@ xwl_window_maybe_resize(struct xwl_window *xwl_window, double width, double heig
     xwl_screen->height = height;
 
     xwl_output = xwl_screen_get_fixed_or_first_output(xwl_screen);
-    if (!xwl_randr_add_modes_fixed(xwl_output, round(width), round(height)))
+    if (!xwl_randr_add_modes_fixed(xwl_output, round(width / scale), round(height / scale)))
         return;
 
-    mode = xwl_output_find_mode(xwl_output,  round(width), round(height));
+    mode = xwl_output_find_mode(xwl_output, round(width / scale), round(height / scale));
     xwl_output_set_mode_fixed(xwl_output, mode);
 
     xwl_window_attach_buffer(xwl_window);
@@ -797,7 +797,39 @@ static const struct xdg_surface_listener xdg_surface_listener = {
 static void
 xwl_window_update_surface_scale(struct xwl_window *xwl_window)
 {
+    struct xwl_screen *xwl_screen = xwl_window->xwl_screen;
+    int previous_scale, new_scale;
+    double new_width, new_height;
+
+    previous_scale = xwl_screen->global_surface_scale;
+    assert(previous_scale != 0);
     xwl_window->surface_scale = xwl_window_get_max_output_scale(xwl_window);
+
+    if (xwl_screen_update_global_surface_scale(xwl_screen)) {
+        new_scale = xwl_screen->global_surface_scale;
+
+        DebugF("XWAYLAND: Global scale is now %i (was %i)\n",
+               new_scale, previous_scale);
+
+        new_width = xwl_screen->width / previous_scale * new_scale;
+        new_height = xwl_screen->height / previous_scale * new_scale;
+
+        wl_surface_set_buffer_scale(xwl_window->surface, xwl_screen->global_surface_scale);
+        /* Reflect the scale factor using XRandR transform */
+        xwl_output_set_xscale(xwl_screen->fixed_output, new_scale);
+        xwl_window_maybe_resize(xwl_window, new_width, new_height);
+#ifdef XWL_HAS_LIBDECOR
+        if (xwl_window->libdecor_frame) {
+            xwl_window_libdecor_set_size_limits(xwl_window);
+            xwl_window_update_libdecor_size(xwl_window,
+                                            NULL,
+                                            round(new_width / new_scale),
+                                            round(new_height / new_scale));
+        }
+        else
+#endif
+            wl_surface_commit(xwl_window->surface);
+    }
 }
 
 static void
diff --git a/hw/xwayland/xwayland.c b/hw/xwayland/xwayland.c
index 7ef0056e8..81b8a7ec0 100644
--- a/hw/xwayland/xwayland.c
+++ b/hw/xwayland/xwayland.c
@@ -97,6 +97,7 @@ ddxUseMsg(void)
     ErrorF("-rootless              run rootless, requires wm support\n");
     ErrorF("-fullscreen            run fullscreen when rootful\n");
     ErrorF("-geometry WxH          set Xwayland window size when rootful\n");
+    ErrorF("-hidpi                 adjust to output scale when rootful\n");
     ErrorF("-host-grab             disable host keyboard shortcuts when rootful\n");
     ErrorF("-nokeymap              ignore keymap from the Wayland compositor\n");
     ErrorF("-output                specify which output to use for fullscreen when rootful\n");
@@ -269,6 +270,9 @@ ddxProcessArgument(int argc, char *argv[], int i)
     else if (strcmp(argv[i], "-nokeymap") == 0) {
         return 1;
     }
+    else if (strcmp(argv[i], "-hidpi") == 0) {
+        return 1;
+    }
 
     return 0;
 }
commit 290ae87c02abf5070422bb50af948402345ab4e1
Author: Olivier Fourdan <ofourdan at redhat.com>
Date:   Thu Nov 2 11:05:55 2023 +0100

    xwayland: Update the scale based on enter/leave events
    
    Recompute the window scale each time the window enters or leaves an
    output.
    
    Signed-off-by: Olivier Fourdan <ofourdan at redhat.com>
    Reviewed-By: Kenny Levinsen <kl at kl.wtf>
    Acked-by: Peter Hutterer <peter.hutterer at who-t.net>
    Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1197>

diff --git a/hw/xwayland/xwayland-window.c b/hw/xwayland/xwayland-window.c
index b439c3a47..626a5d22d 100644
--- a/hw/xwayland/xwayland-window.c
+++ b/hw/xwayland/xwayland-window.c
@@ -794,6 +794,12 @@ static const struct xdg_surface_listener xdg_surface_listener = {
     xdg_surface_handle_configure,
 };
 
+static void
+xwl_window_update_surface_scale(struct xwl_window *xwl_window)
+{
+    xwl_window->surface_scale = xwl_window_get_max_output_scale(xwl_window);
+}
+
 static void
 xwl_window_enter_output(struct xwl_window *xwl_window, struct xwl_output *xwl_output)
 {
@@ -828,6 +834,22 @@ xwl_window_free_outputs(struct xwl_window *xwl_window)
     }
 }
 
+int
+xwl_window_get_max_output_scale(struct xwl_window *xwl_window)
+{
+    struct xwl_window_output *window_output;
+    struct xwl_output *xwl_output;
+    int scale = 1;
+
+    xorg_list_for_each_entry(window_output, &xwl_window->xwl_output_list, link) {
+        xwl_output = window_output->xwl_output;
+        if (xwl_output->scale > scale)
+            scale = xwl_output->scale;
+    }
+
+    return scale;
+}
+
 static void
 xwl_window_surface_enter(void *data,
                          struct wl_surface *wl_surface,
@@ -837,8 +859,10 @@ xwl_window_surface_enter(void *data,
     struct xwl_screen *xwl_screen = xwl_window->xwl_screen;
     struct xwl_output *xwl_output = xwl_output_from_wl_output(xwl_screen, wl_output);
 
-    if (xwl_output)
+    if (xwl_output) {
         xwl_window_enter_output(xwl_window, xwl_output);
+        xwl_window_update_surface_scale(xwl_window);
+    }
 
     if (xwl_window->wl_output != wl_output) {
         xwl_window->wl_output = wl_output;
@@ -857,8 +881,10 @@ xwl_window_surface_leave(void *data,
     struct xwl_screen *xwl_screen = xwl_window->xwl_screen;
     struct xwl_output *xwl_output = xwl_output_from_wl_output(xwl_screen, wl_output);
 
-    if (xwl_output)
+    if (xwl_output) {
         xwl_window_leave_output(xwl_window, xwl_output);
+        xwl_window_update_surface_scale(xwl_window);
+    }
 
     if (xwl_window->wl_output == wl_output)
         xwl_window->wl_output = NULL;
diff --git a/hw/xwayland/xwayland-window.h b/hw/xwayland/xwayland-window.h
index 0e45f08d2..03b4ad249 100644
--- a/hw/xwayland/xwayland-window.h
+++ b/hw/xwayland/xwayland-window.h
@@ -59,6 +59,7 @@ struct xwl_window {
     struct wl_surface *surface;
     struct wp_viewport *viewport;
     float viewport_scale_x, viewport_scale_y;
+    int surface_scale;
     struct xdg_surface *xdg_surface;
     struct xdg_toplevel *xdg_toplevel;
     WindowPtr window;
@@ -100,6 +101,7 @@ void xwl_window_set_window_pixmap(WindowPtr window, PixmapPtr pixmap);
 
 void xwl_window_leave_output(struct xwl_window *xwl_window,
                              struct xwl_output *xwl_output);
+int xwl_window_get_max_output_scale(struct xwl_window *xwl_window);
 Bool xwl_realize_window(WindowPtr window);
 Bool xwl_unrealize_window(WindowPtr window);
 Bool xwl_change_window_attributes(WindowPtr window, unsigned long mask);
commit 4248bfb0da6e14c176acd0750393c66261d6f4c3
Author: Olivier Fourdan <ofourdan at redhat.com>
Date:   Thu Nov 2 10:37:15 2023 +0100

    xwayland: Keep track of outputs per window
    
    Add a list of outputs a window is placed on, adding an output whenever
    the surface enters the output and removing it once it leaves the output.
    
    Note that not all Wayland compositors actually send a leave surface
    event on output removal, so we need to make sure to remove the output
    from the list for each window, otherwise we might end up pointing to
    freed memory.
    
    Signed-off-by: Olivier Fourdan <ofourdan at redhat.com>
    Reviewed-By: Kenny Levinsen <kl at kl.wtf>
    Acked-by: Peter Hutterer <peter.hutterer at who-t.net>
    Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1197>

diff --git a/hw/xwayland/xwayland-output.c b/hw/xwayland/xwayland-output.c
index 2c987a39f..f77ba8278 100644
--- a/hw/xwayland/xwayland-output.c
+++ b/hw/xwayland/xwayland-output.c
@@ -962,8 +962,13 @@ xwl_output_remove(struct xwl_output *xwl_output)
 {
     struct xwl_output *it;
     struct xwl_screen *xwl_screen = xwl_output->xwl_screen;
+    struct xwl_window *xwl_window;
     int width = 0, height = 0;
 
+    /* Not all compositors send a "leave" event on output removal */
+    xorg_list_for_each_entry(xwl_window, &xwl_screen->window_list, link_window)
+        xwl_window_leave_output(xwl_window, xwl_output);
+
     xorg_list_del(&xwl_output->link);
 
     if (xwl_output->randr_output)
diff --git a/hw/xwayland/xwayland-window.c b/hw/xwayland/xwayland-window.c
index d419e3070..b439c3a47 100644
--- a/hw/xwayland/xwayland-window.c
+++ b/hw/xwayland/xwayland-window.c
@@ -794,6 +794,40 @@ static const struct xdg_surface_listener xdg_surface_listener = {
     xdg_surface_handle_configure,
 };
 
+static void
+xwl_window_enter_output(struct xwl_window *xwl_window, struct xwl_output *xwl_output)
+{
+    struct xwl_window_output *window_output;
+
+    window_output = xnfcalloc(1, sizeof(struct xwl_window_output));
+    window_output->xwl_output = xwl_output;
+    xorg_list_add(&window_output->link, &xwl_window->xwl_output_list);
+}
+
+void
+xwl_window_leave_output(struct xwl_window *xwl_window, struct xwl_output *xwl_output)
+{
+    struct xwl_window_output *window_output, *tmp;
+
+    xorg_list_for_each_entry_safe(window_output, tmp, &xwl_window->xwl_output_list, link) {
+        if (window_output->xwl_output == xwl_output) {
+            xorg_list_del(&window_output->link);
+            free(window_output);
+        }
+    }
+}
+
+static void
+xwl_window_free_outputs(struct xwl_window *xwl_window)
+{
+    struct xwl_window_output *window_output, *tmp;
+
+    xorg_list_for_each_entry_safe(window_output, tmp, &xwl_window->xwl_output_list, link) {
+        xorg_list_del(&window_output->link);
+        free(window_output);
+    }
+}
+
 static void
 xwl_window_surface_enter(void *data,
                          struct wl_surface *wl_surface,
@@ -801,6 +835,10 @@ xwl_window_surface_enter(void *data,
 {
     struct xwl_window *xwl_window = data;
     struct xwl_screen *xwl_screen = xwl_window->xwl_screen;
+    struct xwl_output *xwl_output = xwl_output_from_wl_output(xwl_screen, wl_output);
+
+    if (xwl_output)
+        xwl_window_enter_output(xwl_window, xwl_output);
 
     if (xwl_window->wl_output != wl_output) {
         xwl_window->wl_output = wl_output;
@@ -816,6 +854,11 @@ xwl_window_surface_leave(void *data,
                          struct wl_output *wl_output)
 {
     struct xwl_window *xwl_window = data;
+    struct xwl_screen *xwl_screen = xwl_window->xwl_screen;
+    struct xwl_output *xwl_output = xwl_output_from_wl_output(xwl_screen, wl_output);
+
+    if (xwl_output)
+        xwl_window_leave_output(xwl_window, xwl_output);
 
     if (xwl_window->wl_output == wl_output)
         xwl_window->wl_output = NULL;
@@ -913,9 +956,6 @@ xwl_create_root_surface(struct xwl_window *xwl_window)
             goto err_surf;
         }
 
-        wl_surface_add_listener(xwl_window->surface,
-                                &surface_listener, xwl_window);
-
         xdg_surface_add_listener(xwl_window->xdg_surface,
                                  &xdg_surface_listener, xwl_window);
 
@@ -924,6 +964,9 @@ xwl_create_root_surface(struct xwl_window *xwl_window)
                                   xwl_window);
     }
 
+    wl_surface_add_listener(xwl_window->surface,
+                            &surface_listener, xwl_window);
+
     xwl_window_rootful_update_title(xwl_window);
     xwl_window_rootful_set_app_id(xwl_window);
     wl_surface_commit(xwl_window->surface);
@@ -981,6 +1024,7 @@ ensure_surface_for_window(WindowPtr window)
     xwl_window->window = window;
     xwl_window->viewport_scale_x = 1.0;
     xwl_window->viewport_scale_y = 1.0;
+    xorg_list_init(&xwl_window->xwl_output_list);
     xwl_window->surface = wl_compositor_create_surface(xwl_screen->compositor);
     if (xwl_window->surface == NULL) {
         ErrorF("wl_display_create_surface failed\n");
@@ -1230,6 +1274,8 @@ xwl_unrealize_window(WindowPtr window)
     if (xwl_window->frame_callback)
         wl_callback_destroy(xwl_window->frame_callback);
 
+    xwl_window_free_outputs(xwl_window);
+
     free(xwl_window);
     dixSetPrivate(&window->devPrivates, &xwl_window_private_key, NULL);
 
diff --git a/hw/xwayland/xwayland-window.h b/hw/xwayland/xwayland-window.h
index 08629877f..0e45f08d2 100644
--- a/hw/xwayland/xwayland-window.h
+++ b/hw/xwayland/xwayland-window.h
@@ -49,6 +49,11 @@ struct xwl_wl_surface {
     struct xorg_list link;
 };
 
+struct xwl_window_output {
+    struct xorg_list link;
+    struct xwl_output *xwl_output;
+};
+
 struct xwl_window {
     struct xwl_screen *xwl_screen;
     struct wl_surface *surface;
@@ -66,6 +71,7 @@ struct xwl_window {
     OsTimerPtr window_buffers_timer;
     struct wl_output *wl_output;
     struct wl_output *wl_output_fullscreen;
+    struct xorg_list xwl_output_list;
     struct xorg_list frame_callback_list;
 #ifdef XWL_HAS_LIBDECOR
     struct libdecor_frame *libdecor_frame;
@@ -92,6 +98,8 @@ void xwl_window_rootful_update_fullscreen(struct xwl_window *xwl_window,
                                           struct xwl_output *xwl_output);
 void xwl_window_set_window_pixmap(WindowPtr window, PixmapPtr pixmap);
 
+void xwl_window_leave_output(struct xwl_window *xwl_window,
+                             struct xwl_output *xwl_output);
 Bool xwl_realize_window(WindowPtr window);
 Bool xwl_unrealize_window(WindowPtr window);
 Bool xwl_change_window_attributes(WindowPtr window, unsigned long mask);
commit cd0c43df13141cf100b16fea4ea0b93f6fff2325
Author: Olivier Fourdan <ofourdan at redhat.com>
Date:   Mon Nov 27 15:05:42 2023 +0100

    xwayland: Make has_viewport_enabled private
    
    By using a sensible scale factor for input even when there is no
    viewport enabled, no need to have xwl_window_has_viewport_enabled()
    public anymore.
    
    Small cleanup, no functional change.
    
    Signed-off-by: Olivier Fourdan <ofourdan at redhat.com>
    Reviewed-By: Kenny Levinsen <kl at kl.wtf>
    Acked-by: Peter Hutterer <peter.hutterer at who-t.net>
    Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1197>

diff --git a/hw/xwayland/xwayland-window.c b/hw/xwayland/xwayland-window.c
index 09d69df3c..d419e3070 100644
--- a/hw/xwayland/xwayland-window.c
+++ b/hw/xwayland/xwayland-window.c
@@ -246,7 +246,7 @@ unregister_damage(WindowPtr window)
     dixSetPrivate(&window->devPrivates, &xwl_damage_private_key, NULL);
 }
 
-Bool
+static Bool
 xwl_window_has_viewport_enabled(struct xwl_window *xwl_window)
 {
     return (xwl_window->viewport != NULL);
diff --git a/hw/xwayland/xwayland-window.h b/hw/xwayland/xwayland-window.h
index 2873ab707..08629877f 100644
--- a/hw/xwayland/xwayland-window.h
+++ b/hw/xwayland/xwayland-window.h
@@ -85,7 +85,6 @@ Bool is_surface_from_xwl_window(struct wl_surface *surface);
 
 void xwl_window_update_property(struct xwl_window *xwl_window,
                                 PropertyStateRec *propstate);
-Bool xwl_window_has_viewport_enabled(struct xwl_window *xwl_window);
 Bool xwl_window_is_toplevel(WindowPtr window);
 void xwl_window_check_resolution_change_emulation(struct xwl_window *xwl_window);
 void xwl_window_rootful_update_title(struct xwl_window *xwl_window);
commit d7f31fe8878676e4840f37627106085fd9397735
Author: Olivier Fourdan <ofourdan at redhat.com>
Date:   Tue Nov 28 14:26:31 2023 +0100

    xwayland: Apply the viewport's scale_x/y to all input
    
    The viewport's scale_x/y is currently applied to the motion event only.
    
    Apply the same viewport_scale_x/y to all relevant input coordinates.
    
    Signed-off-by: Olivier Fourdan <ofourdan at redhat.com>
    Reviewed-By: Kenny Levinsen <kl at kl.wtf>
    Acked-by: Peter Hutterer <peter.hutterer at who-t.net>
    Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1197>

diff --git a/hw/xwayland/xwayland-input.c b/hw/xwayland/xwayland-input.c
index fcf3ee91e..3c546057d 100644
--- a/hw/xwayland/xwayland-input.c
+++ b/hw/xwayland/xwayland-input.c
@@ -641,6 +641,11 @@ dispatch_relative_motion_with_warp(struct xwl_seat *xwl_seat)
     dx_unaccel *= xwl_screen->global_surface_scale;
     dy_unaccel *= xwl_screen->global_surface_scale;
 
+    dx *= xwl_seat->focus_window->viewport_scale_x;
+    dy *= xwl_seat->focus_window->viewport_scale_y;
+    dx_unaccel *= xwl_seat->focus_window->viewport_scale_x;
+    dy_unaccel *= xwl_seat->focus_window->viewport_scale_y;
+
     xwl_pointer_warp_emulator_handle_motion(xwl_seat->pointer_warp_emulator,
                                             dx, dy,
                                             dx_unaccel, dy_unaccel);
@@ -699,6 +704,11 @@ dispatch_relative_motion(struct xwl_seat *xwl_seat)
     event_dx_unaccel *= xwl_screen->global_surface_scale;
     event_dy_unaccel *= xwl_screen->global_surface_scale;
 
+    event_dx *= xwl_seat->focus_window->viewport_scale_x;
+    event_dy *= xwl_seat->focus_window->viewport_scale_y;
+    event_dx_unaccel *= xwl_seat->focus_window->viewport_scale_x;
+    event_dy_unaccel *= xwl_seat->focus_window->viewport_scale_y;
+
     valuator_mask_zero(&mask);
     valuator_mask_set_unaccelerated(&mask, 0, event_dx, event_dx_unaccel);
     valuator_mask_set_unaccelerated(&mask, 1, event_dy, event_dy_unaccel);
@@ -972,13 +982,9 @@ pointer_gesture_swipe_handle_update(void *data,
                                     wl_fixed_t dyf)
 {
     struct xwl_seat *xwl_seat = data;
-    struct xwl_screen *xwl_screen = xwl_seat->xwl_screen;
     double dx = wl_fixed_to_double(dxf);
     double dy = wl_fixed_to_double(dyf);
 
-    dx *= xwl_screen->global_surface_scale;
-    dy *= xwl_screen->global_surface_scale;
-
     QueueGestureSwipeEvents(xwl_seat->pointer_gestures,
                             XI_GestureSwipeUpdate,
                             xwl_seat->pointer_gesture_swipe_fingers,
@@ -1042,14 +1048,10 @@ pointer_gesture_pinch_handle_update(void *data,
                                     wl_fixed_t rotation)
 {
     struct xwl_seat *xwl_seat = data;
-    struct xwl_screen *xwl_screen = xwl_seat->xwl_screen;
     double dx = wl_fixed_to_double(dxf);
     double dy = wl_fixed_to_double(dyf);
     double scale = wl_fixed_to_double(scalef);
 
-    dx *= xwl_screen->global_surface_scale;
-    dy *= xwl_screen->global_surface_scale;
-
     xwl_seat->pointer_gesture_pinch_last_scale = scale;
     QueueGesturePinchEvents(xwl_seat->pointer_gestures,
                             XI_GesturePinchUpdate,
@@ -1452,6 +1454,9 @@ touch_handle_down(void *data, struct wl_touch *wl_touch,
     xwl_touch->x *= xwl_screen->global_surface_scale;
     xwl_touch->y *= xwl_screen->global_surface_scale;
 
+    xwl_touch->x *= xwl_touch->window->viewport_scale_x;
+    xwl_touch->y *= xwl_touch->window->viewport_scale_y;
+
     xwl_touch_send_event(xwl_touch, xwl_seat, XI_TouchBegin);
 }
 
@@ -1492,6 +1497,9 @@ touch_handle_motion(void *data, struct wl_touch *wl_touch,
     xwl_touch->x *= xwl_screen->global_surface_scale;
     xwl_touch->y *= xwl_screen->global_surface_scale;
 
+    xwl_touch->x *= xwl_touch->window->viewport_scale_x;
+    xwl_touch->y *= xwl_touch->window->viewport_scale_y;
+
     xwl_touch_send_event(xwl_touch, xwl_seat, XI_TouchUpdate);
 }
 
@@ -2191,6 +2199,9 @@ tablet_tool_motion(void *data, struct zwp_tablet_tool_v2 *tool,
     sx *= xwl_screen->global_surface_scale;
     sy *= xwl_screen->global_surface_scale;
 
+    sx *= xwl_seat->tablet_focus_window->viewport_scale_x;
+    sy *= xwl_seat->tablet_focus_window->viewport_scale_y;
+
     dx = xwl_seat->tablet_focus_window->window->drawable.x;
     dy = xwl_seat->tablet_focus_window->window->drawable.y;
 
@@ -2234,6 +2245,9 @@ tablet_tool_tilt(void *data, struct zwp_tablet_tool_v2 *tool,
 
     xwl_tablet_tool->tilt_x *= xwl_screen->global_surface_scale;
     xwl_tablet_tool->tilt_y *= xwl_screen->global_surface_scale;
+
+    xwl_tablet_tool->tilt_x *= xwl_seat->tablet_focus_window->viewport_scale_x;
+    xwl_tablet_tool->tilt_y *= xwl_seat->tablet_focus_window->viewport_scale_y;
 }
 
 static void
commit 3ea36e521426aaba37f3d00de3b57805cc71243e
Author: Olivier Fourdan <ofourdan at redhat.com>
Date:   Mon Nov 27 15:02:08 2023 +0100

    xwayland: Always set the viewport scale factor
    
    When the viewport is disabled, set the scale x/y back to 1.0 so that we
    can apply the scale factor regardless of the viewport being enabled.
    
    Signed-off-by: Olivier Fourdan <ofourdan at redhat.com>
    Reviewed-By: Kenny Levinsen <kl at kl.wtf>
    Acked-by: Peter Hutterer <peter.hutterer at who-t.net>
    Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1197>

diff --git a/hw/xwayland/xwayland-input.c b/hw/xwayland/xwayland-input.c
index 502581425..fcf3ee91e 100644
--- a/hw/xwayland/xwayland-input.c
+++ b/hw/xwayland/xwayland-input.c
@@ -663,10 +663,8 @@ dispatch_absolute_motion(struct xwl_seat *xwl_seat)
     event_x *= xwl_screen->global_surface_scale;
     event_y *= xwl_screen->global_surface_scale;
 
-    if (xwl_window_has_viewport_enabled(xwl_seat->focus_window)) {
-        event_x *= xwl_seat->focus_window->viewport_scale_x;
-        event_y *= xwl_seat->focus_window->viewport_scale_y;
-    }
+    event_x *= xwl_seat->focus_window->viewport_scale_x;
+    event_y *= xwl_seat->focus_window->viewport_scale_y;
 
     x = drawable_x + event_x;
     y = drawable_y + event_y;
diff --git a/hw/xwayland/xwayland-window.c b/hw/xwayland/xwayland-window.c
index 00cdbdd58..09d69df3c 100644
--- a/hw/xwayland/xwayland-window.c
+++ b/hw/xwayland/xwayland-window.c
@@ -260,6 +260,8 @@ xwl_window_disable_viewport(struct xwl_window *xwl_window)
     DebugF("XWAYLAND: disabling viewport\n");
     wp_viewport_destroy(xwl_window->viewport);
     xwl_window->viewport = NULL;
+    xwl_window->viewport_scale_x = 1.0;
+    xwl_window->viewport_scale_y = 1.0;
 }
 
 static void
@@ -977,6 +979,8 @@ ensure_surface_for_window(WindowPtr window)
 
     xwl_window->xwl_screen = xwl_screen;
     xwl_window->window = window;
+    xwl_window->viewport_scale_x = 1.0;
+    xwl_window->viewport_scale_y = 1.0;
     xwl_window->surface = wl_compositor_create_surface(xwl_screen->compositor);
     if (xwl_window->surface == NULL) {
         ErrorF("wl_display_create_surface failed\n");
commit 96fd7cc8c99b065dbbe7fc2ab0f2f93e841e01ae
Author: Olivier Fourdan <ofourdan at redhat.com>
Date:   Tue Nov 28 14:45:55 2023 +0100

    xwayland: Rename scale_x/y to viewport_scale_x/y
    
    The scale_x/y factor applies when a viewport is in use, rename the
    fields to reflect that and distinguish these from the other scale
    factors such as the core protocol surface scale and the fractional
    scaling.
    
    Signed-off-by: Olivier Fourdan <ofourdan at redhat.com>
    Reviewed-By: Kenny Levinsen <kl at kl.wtf>
    Acked-by: Peter Hutterer <peter.hutterer at who-t.net>
    Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1197>

diff --git a/hw/xwayland/xwayland-input.c b/hw/xwayland/xwayland-input.c
index cf0ca87b0..502581425 100644
--- a/hw/xwayland/xwayland-input.c
+++ b/hw/xwayland/xwayland-input.c
@@ -664,8 +664,8 @@ dispatch_absolute_motion(struct xwl_seat *xwl_seat)
     event_y *= xwl_screen->global_surface_scale;
 
     if (xwl_window_has_viewport_enabled(xwl_seat->focus_window)) {
-        event_x *= xwl_seat->focus_window->scale_x;
-        event_y *= xwl_seat->focus_window->scale_y;
+        event_x *= xwl_seat->focus_window->viewport_scale_x;
+        event_y *= xwl_seat->focus_window->viewport_scale_y;
     }
 
     x = drawable_x + event_x;
diff --git a/hw/xwayland/xwayland-window.c b/hw/xwayland/xwayland-window.c
index e83ca8a2c..00cdbdd58 100644
--- a/hw/xwayland/xwayland-window.c
+++ b/hw/xwayland/xwayland-window.c
@@ -290,8 +290,8 @@ xwl_window_enable_viewport(struct xwl_window *xwl_window,
                                 xwl_output->width,
                                 xwl_output->height);
 
-    xwl_window->scale_x = (float) width / xwl_output->width;
-    xwl_window->scale_y = (float) height / xwl_output->height;
+    xwl_window->viewport_scale_x = (float) width / xwl_output->width;
+    xwl_window->viewport_scale_y = (float) height / xwl_output->height;
 }
 
 static Bool
diff --git a/hw/xwayland/xwayland-window.h b/hw/xwayland/xwayland-window.h
index 7c70bb9ed..2873ab707 100644
--- a/hw/xwayland/xwayland-window.h
+++ b/hw/xwayland/xwayland-window.h
@@ -53,7 +53,7 @@ struct xwl_window {
     struct xwl_screen *xwl_screen;
     struct wl_surface *surface;
     struct wp_viewport *viewport;
-    float scale_x, scale_y;
+    float viewport_scale_x, viewport_scale_y;
     struct xdg_surface *xdg_surface;
     struct xdg_toplevel *xdg_toplevel;
     WindowPtr window;
commit 54f8fc409091ea3b3466cbf948a53194aaa26aad
Author: Olivier Fourdan <ofourdan at redhat.com>
Date:   Thu Nov 2 10:25:46 2023 +0100

    xwayland: Account for the scale factor
    
    Apply the scale factor to the root window and adjust the coordinates and
    hotspot location for cursors.
    
    Signed-off-by: Olivier Fourdan <ofourdan at redhat.com>
    Reviewed-By: Kenny Levinsen <kl at kl.wtf>
    Acked-by: Peter Hutterer <peter.hutterer at who-t.net>
    Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1197>

diff --git a/hw/xwayland/xwayland-cursor.c b/hw/xwayland/xwayland-cursor.c
index bd94b0cfb..9ee427063 100644
--- a/hw/xwayland/xwayland-cursor.c
+++ b/hw/xwayland/xwayland-cursor.c
@@ -156,6 +156,7 @@ xwl_cursor_attach_pixmap(struct xwl_seat *xwl_seat,
                          struct xwl_cursor *xwl_cursor, PixmapPtr pixmap)
 {
     struct wl_buffer *buffer;
+    struct xwl_screen *xwl_screen = xwl_seat->xwl_screen;
 
     buffer = xwl_shm_pixmap_get_wl_buffer(pixmap);
     if (!buffer) {
@@ -164,7 +165,8 @@ xwl_cursor_attach_pixmap(struct xwl_seat *xwl_seat,
     }
 
     wl_surface_attach(xwl_cursor->surface, buffer, 0, 0);
-    xwl_surface_damage(xwl_seat->xwl_screen, xwl_cursor->surface, 0, 0,
+    wl_surface_set_buffer_scale(xwl_cursor->surface, xwl_screen->global_surface_scale);
+    xwl_surface_damage(xwl_screen, xwl_cursor->surface, 0, 0,
                        xwl_seat->x_cursor->bits->width,
                        xwl_seat->x_cursor->bits->height);
 
@@ -196,8 +198,10 @@ void
 xwl_seat_set_cursor(struct xwl_seat *xwl_seat)
 {
     struct xwl_cursor *xwl_cursor = &xwl_seat->cursor;
+    struct xwl_screen *xwl_screen = xwl_seat->xwl_screen;
     PixmapPtr pixmap;
     CursorPtr cursor;
+    int xhot, yhot;
 
     if (!xwl_seat->wl_pointer)
         return;
@@ -222,11 +226,14 @@ xwl_seat_set_cursor(struct xwl_seat *xwl_seat)
 
     xwl_cursor_copy_bits_to_pixmap(cursor, pixmap);
 
+    xhot = xwl_seat->x_cursor->bits->xhot / xwl_screen->global_surface_scale;
+    yhot = xwl_seat->x_cursor->bits->yhot / xwl_screen->global_surface_scale;
+
     wl_pointer_set_cursor(xwl_seat->wl_pointer,
                           xwl_seat->pointer_enter_serial,
                           xwl_cursor->surface,
-                          xwl_seat->x_cursor->bits->xhot,
-                          xwl_seat->x_cursor->bits->yhot);
+                          xhot,
+                          yhot);
 
     xwl_cursor_attach_pixmap(xwl_seat, xwl_cursor, pixmap);
 }
@@ -235,9 +242,11 @@ void
 xwl_tablet_tool_set_cursor(struct xwl_tablet_tool *xwl_tablet_tool)
 {
     struct xwl_seat *xwl_seat = xwl_tablet_tool->seat;
+    struct xwl_screen *xwl_screen = xwl_seat->xwl_screen;
     struct xwl_cursor *xwl_cursor = &xwl_tablet_tool->cursor;
     PixmapPtr pixmap;
     CursorPtr cursor;
+    int xhot, yhot;
 
     if (!xwl_seat->x_cursor) {
         zwp_tablet_tool_v2_set_cursor(xwl_tablet_tool->tool,
@@ -260,11 +269,14 @@ xwl_tablet_tool_set_cursor(struct xwl_tablet_tool *xwl_tablet_tool)
 
     xwl_cursor_copy_bits_to_pixmap(cursor, pixmap);
 
+    xhot = xwl_seat->x_cursor->bits->xhot / xwl_screen->global_surface_scale;
+    yhot = xwl_seat->x_cursor->bits->yhot / xwl_screen->global_surface_scale;
+
     zwp_tablet_tool_v2_set_cursor(xwl_tablet_tool->tool,
                                   xwl_tablet_tool->proximity_in_serial,
                                   xwl_cursor->surface,
-                                  xwl_seat->x_cursor->bits->xhot,
-                                  xwl_seat->x_cursor->bits->yhot);
+                                  xhot,
+                                  yhot);
 
     xwl_cursor_attach_pixmap(xwl_seat, xwl_cursor, pixmap);
 }
diff --git a/hw/xwayland/xwayland-input.c b/hw/xwayland/xwayland-input.c
index abbf3b0e3..cf0ca87b0 100644
--- a/hw/xwayland/xwayland-input.c
+++ b/hw/xwayland/xwayland-input.c
@@ -515,13 +515,13 @@ pointer_handle_enter(void *data, struct wl_pointer *pointer,
                      wl_fixed_t sx_w, wl_fixed_t sy_w)
 {
     struct xwl_seat *xwl_seat = data;
+    struct xwl_screen *xwl_screen = xwl_seat->xwl_screen;
     DeviceIntPtr dev = get_pointer_device(xwl_seat);
     DeviceIntPtr master;
     int i;
-    int sx = wl_fixed_to_int(sx_w);
-    int sy = wl_fixed_to_int(sy_w);
+    int sx, sy;
     int dx, dy;
-    ScreenPtr pScreen = xwl_seat->xwl_screen->screen;
+    ScreenPtr pScreen = xwl_screen->screen;
     ValuatorMask mask;
 
     /* There's a race here where if we create and then immediately
@@ -536,6 +536,9 @@ pointer_handle_enter(void *data, struct wl_pointer *pointer,
     if (!is_surface_from_xwl_window(surface))
         return;
 
+    sx = wl_fixed_to_int(sx_w) * xwl_screen->global_surface_scale;
+    sy = wl_fixed_to_int(sy_w) * xwl_screen->global_surface_scale;
+
     xwl_seat->xwl_screen->serial = serial;
     xwl_seat->pointer_enter_serial = serial;
 
@@ -624,6 +627,7 @@ pointer_handle_leave(void *data, struct wl_pointer *pointer,
 static void
 dispatch_relative_motion_with_warp(struct xwl_seat *xwl_seat)
 {
+    struct xwl_screen *xwl_screen = xwl_seat->xwl_screen;
     double dx, dx_unaccel;
     double dy, dy_unaccel;
 
@@ -632,6 +636,11 @@ dispatch_relative_motion_with_warp(struct xwl_seat *xwl_seat)
     dx_unaccel = xwl_seat->pending_pointer_event.dx_unaccel;
     dy_unaccel = xwl_seat->pending_pointer_event.dy_unaccel;
 
+    dx *= xwl_screen->global_surface_scale;
+    dy *= xwl_screen->global_surface_scale;
+    dx_unaccel *= xwl_screen->global_surface_scale;
+    dy_unaccel *= xwl_screen->global_surface_scale;
+
     xwl_pointer_warp_emulator_handle_motion(xwl_seat->pointer_warp_emulator,
                                             dx, dy,
                                             dx_unaccel, dy_unaccel);
@@ -640,6 +649,7 @@ dispatch_relative_motion_with_warp(struct xwl_seat *xwl_seat)
 static void
 dispatch_absolute_motion(struct xwl_seat *xwl_seat)
 {
+    struct xwl_screen *xwl_screen = xwl_seat->xwl_screen;
     ValuatorMask mask;
     DeviceIntPtr device;
     int flags;
@@ -650,6 +660,9 @@ dispatch_absolute_motion(struct xwl_seat *xwl_seat)
     int x;
     int y;
 
+    event_x *= xwl_screen->global_surface_scale;
+    event_y *= xwl_screen->global_surface_scale;
+
     if (xwl_window_has_viewport_enabled(xwl_seat->focus_window)) {
         event_x *= xwl_seat->focus_window->scale_x;
         event_y *= xwl_seat->focus_window->scale_y;
@@ -676,12 +689,18 @@ dispatch_absolute_motion(struct xwl_seat *xwl_seat)
 static void
 dispatch_relative_motion(struct xwl_seat *xwl_seat)
 {
+    struct xwl_screen *xwl_screen = xwl_seat->xwl_screen;
     ValuatorMask mask;
     double event_dx = xwl_seat->pending_pointer_event.dx;
     double event_dy = xwl_seat->pending_pointer_event.dy;
     double event_dx_unaccel = xwl_seat->pending_pointer_event.dx_unaccel;
     double event_dy_unaccel = xwl_seat->pending_pointer_event.dy_unaccel;
 
+    event_dx *= xwl_screen->global_surface_scale;
+    event_dy *= xwl_screen->global_surface_scale;
+    event_dx_unaccel *= xwl_screen->global_surface_scale;
+    event_dy_unaccel *= xwl_screen->global_surface_scale;
+
     valuator_mask_zero(&mask);
     valuator_mask_set_unaccelerated(&mask, 0, event_dx, event_dx_unaccel);
     valuator_mask_set_unaccelerated(&mask, 1, event_dy, event_dy_unaccel);
@@ -955,9 +974,13 @@ pointer_gesture_swipe_handle_update(void *data,
                                     wl_fixed_t dyf)
 {
     struct xwl_seat *xwl_seat = data;
+    struct xwl_screen *xwl_screen = xwl_seat->xwl_screen;
     double dx = wl_fixed_to_double(dxf);
     double dy = wl_fixed_to_double(dyf);
 
+    dx *= xwl_screen->global_surface_scale;
+    dy *= xwl_screen->global_surface_scale;
+
     QueueGestureSwipeEvents(xwl_seat->pointer_gestures,
                             XI_GestureSwipeUpdate,
                             xwl_seat->pointer_gesture_swipe_fingers,
@@ -1021,10 +1044,14 @@ pointer_gesture_pinch_handle_update(void *data,
                                     wl_fixed_t rotation)
 {
     struct xwl_seat *xwl_seat = data;
+    struct xwl_screen *xwl_screen = xwl_seat->xwl_screen;
     double dx = wl_fixed_to_double(dxf);
     double dy = wl_fixed_to_double(dyf);
     double scale = wl_fixed_to_double(scalef);
 
+    dx *= xwl_screen->global_surface_scale;
+    dy *= xwl_screen->global_surface_scale;
+
     xwl_seat->pointer_gesture_pinch_last_scale = scale;
     QueueGesturePinchEvents(xwl_seat->pointer_gestures,
                             XI_GesturePinchUpdate,
@@ -1403,6 +1430,7 @@ touch_handle_down(void *data, struct wl_touch *wl_touch,
                   int32_t id, wl_fixed_t sx_w, wl_fixed_t sy_w)
 {
     struct xwl_seat *xwl_seat = data;
+    struct xwl_screen *xwl_screen = xwl_seat->xwl_screen;
     struct xwl_touch *xwl_touch;
 
     if (surface == NULL)
@@ -1423,6 +1451,9 @@ touch_handle_down(void *data, struct wl_touch *wl_touch,
     xwl_touch->y = wl_fixed_to_int(sy_w);
     xorg_list_add(&xwl_touch->link_touch, &xwl_seat->touches);
 
+    xwl_touch->x *= xwl_screen->global_surface_scale;
+    xwl_touch->y *= xwl_screen->global_surface_scale;
+
     xwl_touch_send_event(xwl_touch, xwl_seat, XI_TouchBegin);
 }
 
@@ -1449,6 +1480,7 @@ touch_handle_motion(void *data, struct wl_touch *wl_touch,
                     wl_fixed_t sx_w, wl_fixed_t sy_w)
 {
     struct xwl_seat *xwl_seat = data;
+    struct xwl_screen *xwl_screen = xwl_seat->xwl_screen;
     struct xwl_touch *xwl_touch;
 
     xwl_touch = xwl_seat_lookup_touch(xwl_seat, id);
@@ -1458,6 +1490,10 @@ touch_handle_motion(void *data, struct wl_touch *wl_touch,
 
     xwl_touch->x = wl_fixed_to_int(sx_w);
     xwl_touch->y = wl_fixed_to_int(sy_w);
+
+    xwl_touch->x *= xwl_screen->global_surface_scale;
+    xwl_touch->y *= xwl_screen->global_surface_scale;
+
     xwl_touch_send_event(xwl_touch, xwl_seat, XI_TouchUpdate);
 }
 
@@ -2146,6 +2182,7 @@ tablet_tool_motion(void *data, struct zwp_tablet_tool_v2 *tool,
 {
     struct xwl_tablet_tool *xwl_tablet_tool = data;
     struct xwl_seat *xwl_seat = xwl_tablet_tool->seat;
+    struct xwl_screen *xwl_screen = xwl_seat->xwl_screen;
     int32_t dx, dy;
     double sx = wl_fixed_to_double(x);
     double sy = wl_fixed_to_double(y);
@@ -2153,6 +2190,9 @@ tablet_tool_motion(void *data, struct zwp_tablet_tool_v2 *tool,
     if (!xwl_seat->tablet_focus_window)
         return;
 
+    sx *= xwl_screen->global_surface_scale;
+    sy *= xwl_screen->global_surface_scale;
+
     dx = xwl_seat->tablet_focus_window->window->drawable.x;
     dy = xwl_seat->tablet_focus_window->window->drawable.y;
 
@@ -2186,12 +2226,16 @@ tablet_tool_tilt(void *data, struct zwp_tablet_tool_v2 *tool,
 {
     struct xwl_tablet_tool *xwl_tablet_tool = data;
     struct xwl_seat *xwl_seat = xwl_tablet_tool->seat;
+    struct xwl_screen *xwl_screen = xwl_seat->xwl_screen;
 
     if (!xwl_seat->tablet_focus_window)
         return;
 
     xwl_tablet_tool->tilt_x = wl_fixed_to_double(tilt_x);
     xwl_tablet_tool->tilt_y = wl_fixed_to_double(tilt_y);
+
+    xwl_tablet_tool->tilt_x *= xwl_screen->global_surface_scale;
+    xwl_tablet_tool->tilt_y *= xwl_screen->global_surface_scale;
 }
 
 static void
diff --git a/hw/xwayland/xwayland-window.c b/hw/xwayland/xwayland-window.c
index 325ffdb13..e83ca8a2c 100644
--- a/hw/xwayland/xwayland-window.c
+++ b/hw/xwayland/xwayland-window.c
@@ -27,6 +27,7 @@
 #include <dix-config.h>
 #endif
 
+#include <math.h>
 #include <sys/mman.h>
 
 #include <X11/X.h>
@@ -266,6 +267,9 @@ xwl_window_enable_viewport(struct xwl_window *xwl_window,
                            struct xwl_output *xwl_output,
                            struct xwl_emulated_mode *emulated_mode)
 {
+    struct xwl_screen *xwl_screen = xwl_window->xwl_screen;
+    int width, height;
+
     if (!xwl_window_has_viewport_enabled(xwl_window)) {
         DebugF("XWAYLAND: enabling viewport %dx%d -> %dx%d\n",
                emulated_mode->width, emulated_mode->height,
@@ -274,17 +278,20 @@ xwl_window_enable_viewport(struct xwl_window *xwl_window,
                                                           xwl_window->surface);
     }
 
+    width = emulated_mode->width / xwl_screen->global_surface_scale;
+    height = emulated_mode->height / xwl_screen->global_surface_scale;
+
     wp_viewport_set_source(xwl_window->viewport,
                            wl_fixed_from_int(0),
                            wl_fixed_from_int(0),
-                           wl_fixed_from_int(emulated_mode->width),
-                           wl_fixed_from_int(emulated_mode->height));
+                           wl_fixed_from_int(width),
+                           wl_fixed_from_int(height));
     wp_viewport_set_destination(xwl_window->viewport,
                                 xwl_output->width,
                                 xwl_output->height);
 
-    xwl_window->scale_x = (float)emulated_mode->width  / xwl_output->width;
-    xwl_window->scale_y = (float)emulated_mode->height / xwl_output->height;
+    xwl_window->scale_x = (float) width / xwl_output->width;
+    xwl_window->scale_y = (float) height / xwl_output->height;
 }
 
 static Bool
@@ -641,12 +648,20 @@ xwl_window_maybe_resize(struct xwl_window *xwl_window, double width, double heig
 {
     struct xwl_screen *xwl_screen = xwl_window->xwl_screen;
     struct xwl_output *xwl_output;
+    double scale;
     RRModePtr mode;
 
     /* Clamp the size */
     width = min(max(width, MIN_ROOTFUL_WIDTH), MAX_ROOTFUL_WIDTH);
     height = min(max(height, MIN_ROOTFUL_HEIGHT), MAX_ROOTFUL_HEIGHT);
 
+    /* Make sure the size is a multiple of the scale, it's a protocol error otherwise. */
+    scale = xwl_screen->global_surface_scale;
+    if (scale > 1.0) {
+        width = round(width / scale) * scale;
+        height = round(height / scale) * scale;
+    }
+
     if (width == xwl_screen->width && height == xwl_screen->height)
         return;
 
@@ -667,10 +682,18 @@ xwl_window_maybe_resize(struct xwl_window *xwl_window, double width, double heig
 static void
 xwl_window_libdecor_set_size_limits(struct xwl_window *xwl_window)
 {
+    struct xwl_screen *xwl_screen = xwl_window->xwl_screen;
+
     libdecor_frame_set_min_content_size(xwl_window->libdecor_frame,
-                                        MIN_ROOTFUL_WIDTH, MIN_ROOTFUL_HEIGHT);
+                                        MIN_ROOTFUL_WIDTH /
+                                        xwl_screen->global_surface_scale,
+                                        MIN_ROOTFUL_HEIGHT /
+                                        xwl_screen->global_surface_scale);
     libdecor_frame_set_max_content_size(xwl_window->libdecor_frame,
-                                        MAX_ROOTFUL_WIDTH, MAX_ROOTFUL_HEIGHT);
+                                        MAX_ROOTFUL_WIDTH /
+                                        xwl_screen->global_surface_scale,
+                                        MAX_ROOTFUL_HEIGHT /
+                                        xwl_screen->global_surface_scale);
 }
 
 static void
@@ -701,11 +724,21 @@ handle_libdecor_configure(struct libdecor_frame *frame,
         new_width = (double) width;
         new_height = (double) height;
     }
+    else {
+        new_width = xwl_screen->width / xwl_screen->global_surface_scale;
+        new_height = xwl_screen->height / xwl_screen->global_surface_scale;
+    }
+
+    new_width *= xwl_screen->global_surface_scale;
+    new_height *= xwl_screen->global_surface_scale;
 
     xwl_window_maybe_resize(xwl_window, new_width, new_height);
+
+    new_width = xwl_screen->width / xwl_screen->global_surface_scale;
+    new_height = xwl_screen->height / xwl_screen->global_surface_scale;
+
     xwl_window_update_libdecor_size(xwl_window, configuration,
-                                     xwl_screen_get_width(xwl_screen),
-                                     xwl_screen_get_height(xwl_screen));
+                                    round(new_width), round(new_height));
     wl_surface_commit(xwl_window->surface);
 }
 
@@ -802,14 +835,17 @@ xdg_toplevel_handle_configure(void *data,
     struct xwl_screen *xwl_screen = xwl_window->xwl_screen;
     uint32_t *p;
     Bool old_active = xwl_screen->active;
+    int new_width, new_height;
 
     /* Maintain our current size if no dimensions are requested */
     if (width == 0 && height == 0)
         return;
 
     if (!xwl_screen->fullscreen) {
+        new_width = width * xwl_screen->global_surface_scale;
+        new_height = height * xwl_screen->global_surface_scale;
         /* This will be committed by the xdg_surface.configure handler */
-        xwl_window_maybe_resize(xwl_window, width, height);
+        xwl_window_maybe_resize(xwl_window, new_width, new_height);
     }
 
     xwl_screen->active = FALSE;
@@ -1273,8 +1309,14 @@ xwl_resize_window(WindowPtr window,
         if (xwl_window_get(window) || xwl_window_is_toplevel(window))
             xwl_window_check_resolution_change_emulation(xwl_window);
 #ifdef XWL_HAS_LIBDECOR
-        if (window == screen->root)
-            xwl_window_update_libdecor_size(xwl_window, NULL, width, height);
+        if (window == screen->root) {
+            unsigned int decor_width, decor_height;
+
+            decor_width = width / xwl_screen->global_surface_scale;
+            decor_height = height / xwl_screen->global_surface_scale;
+            xwl_window_update_libdecor_size(xwl_window, NULL,
+                                            decor_width, decor_height);
+        }
 #endif
     }
 }
commit b678297c53b081d42cb19fabc65d13202ad5494e
Author: Olivier Fourdan <ofourdan at redhat.com>
Date:   Thu Nov 2 10:23:54 2023 +0100

    xwayland: Add scale factor to the Xwayland screen
    
    For now, the global surface scale is always 1, no functional change.
    
    Signed-off-by: Olivier Fourdan <ofourdan at redhat.com>
    Reviewed-By: Kenny Levinsen <kl at kl.wtf>
    Acked-by: Peter Hutterer <peter.hutterer at who-t.net>
    Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1197>

diff --git a/hw/xwayland/xwayland-screen.c b/hw/xwayland/xwayland-screen.c
index e69196486..11460a723 100644
--- a/hw/xwayland/xwayland-screen.c
+++ b/hw/xwayland/xwayland-screen.c
@@ -915,6 +915,7 @@ xwl_screen_init(ScreenPtr pScreen, int argc, char **argv)
     xorg_list_init(&xwl_screen->drm_leases);
     xorg_list_init(&xwl_screen->pending_wl_surface_destroy);
     xwl_screen->depth = 24;
+    xwl_screen->global_surface_scale = 1;
 
     if (!monitorResolution)
         monitorResolution = DEFAULT_DPI;
diff --git a/hw/xwayland/xwayland-screen.h b/hw/xwayland/xwayland-screen.h
index bf42b5a69..c8c093fbe 100644
--- a/hw/xwayland/xwayland-screen.h
+++ b/hw/xwayland/xwayland-screen.h
@@ -48,6 +48,7 @@ struct xwl_screen {
     double width;
     double height;
     int depth;
+    int global_surface_scale;
     int output_name_serial;
     ScreenPtr screen;
     int wm_client_id;
commit 2bdf594ceaaa9e6788e9090de0f3713184ed2d59
Author: Olivier Fourdan <ofourdan at redhat.com>
Date:   Thu Nov 2 10:33:22 2023 +0100

    xwayland: Track output scales
    
    Keep track of the output scales as advertised by the wl_output protocol.
    
    Signed-off-by: Olivier Fourdan <ofourdan at redhat.com>
    Reviewed-By: Kenny Levinsen <kl at kl.wtf>
    Acked-by: Peter Hutterer <peter.hutterer at who-t.net>
    Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1197>

diff --git a/hw/xwayland/xwayland-output.c b/hw/xwayland/xwayland-output.c
index 8a4a55312..2c987a39f 100644
--- a/hw/xwayland/xwayland-output.c
+++ b/hw/xwayland/xwayland-output.c
@@ -725,6 +725,9 @@ output_handle_done(void *data, struct wl_output *wl_output)
 static void
 output_handle_scale(void *data, struct wl_output *wl_output, int32_t factor)
 {
+    struct xwl_output *xwl_output = data;
+
+    xwl_output->scale = factor;
 }
 
 static void
diff --git a/hw/xwayland/xwayland-output.h b/hw/xwayland/xwayland-output.h
index 5138d5e88..0e5ee6b55 100644
--- a/hw/xwayland/xwayland-output.h
+++ b/hw/xwayland/xwayland-output.h
@@ -54,7 +54,7 @@ struct xwl_output {
     struct wl_output *output;
     struct zxdg_output_v1 *xdg_output;
     uint32_t server_output_id;
-    int32_t x, y, width, height, refresh;
+    int32_t x, y, width, height, refresh, scale;
     int32_t mode_width, mode_height;
     double xscale; /* Effective scale, can be fractional */
     Rotation rotation;
commit 5b05a299126e621f11977c75318975c850b98c93
Author: Olivier Fourdan <ofourdan at redhat.com>
Date:   Mon Nov 27 13:42:13 2023 +0100

    xwayland: Use CRTC transforms
    
    Advertise the scaling factor applied to the Xwayland output using the
    mechanism of CRTC transforms.
    
    That allows for X11 clients to query the scale factor using XRandR.
    
    Signed-off-by: Olivier Fourdan <ofourdan at redhat.com>
    Reviewed-By: Kenny Levinsen <kl at kl.wtf>
    Acked-by: Peter Hutterer <peter.hutterer at who-t.net>
    Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1197>

diff --git a/hw/xwayland/xwayland-output.c b/hw/xwayland/xwayland-output.c
index 23c9733d2..8a4a55312 100644
--- a/hw/xwayland/xwayland-output.c
+++ b/hw/xwayland/xwayland-output.c
@@ -945,6 +945,8 @@ xwl_output_destroy(struct xwl_output *xwl_output)
 {
     if (xwl_output->lease_connector)
         wp_drm_lease_connector_v1_destroy(xwl_output->lease_connector);
+    if (xwl_output->transform)
+        free(xwl_output->transform);
     if (xwl_output->xdg_output)
         zxdg_output_v1_destroy(xwl_output->xdg_output);
     if (xwl_output->output)
@@ -1142,10 +1144,41 @@ mode_sort(const void *left, const void *right)
     return (*mode_b)->mode.width - (*mode_a)->mode.width;
 }
 
+static void
+xwl_output_set_transform(struct xwl_output *xwl_output)
+{
+    pixman_fixed_t transform_xscale;
+    RRModePtr mode;
+
+    mode = xwl_output_find_mode(xwl_output, xwl_output->mode_width, xwl_output->mode_height);
+    if (!mode) {
+        ErrorF("XWAYLAND: Failed to find mode for %ix%i\n",
+               xwl_output->mode_width, xwl_output->mode_height);
+        return;
+    }
+
+    if (xwl_output->transform == NULL) {
+        xwl_output->transform = xnfalloc(sizeof(RRTransformRec));
+        RRTransformInit(xwl_output->transform);
+    }
+
+    transform_xscale = pixman_double_to_fixed(xwl_output->xscale);
+    pixman_transform_init_scale(&xwl_output->transform->transform,
+                                transform_xscale, transform_xscale);
+    pixman_f_transform_init_scale(&xwl_output->transform->f_transform,
+                                  xwl_output->xscale, xwl_output->xscale);
+    pixman_f_transform_invert(&xwl_output->transform->f_inverse,
+                              &xwl_output->transform->f_transform);
+
+    RRCrtcNotify(xwl_output->randr_crtc, mode, 0, 0, RR_Rotate_0,
+                 xwl_output->transform, 1, &xwl_output->randr_output);
+}
+
 void
 xwl_output_set_xscale(struct xwl_output *xwl_output, double xscale)
 {
     xwl_output->xscale = xscale;
+    xwl_output_set_transform(xwl_output);
 }
 
 Bool
@@ -1209,8 +1242,7 @@ xwl_output_set_mode_fixed(struct xwl_output *xwl_output, RRModePtr mode)
                        round((double) mode->mode.width * xwl_output->xscale),
                        round((double) mode->mode.height * xwl_output->xscale));
 
-    RRCrtcNotify(xwl_output->randr_crtc, mode, 0, 0, RR_Rotate_0,
-                 NULL, 1, &xwl_output->randr_output);
+    xwl_output_set_transform(xwl_output);
 }
 
 static Bool
@@ -1264,6 +1296,7 @@ xwl_screen_init_randr_fixed(struct xwl_screen *xwl_screen)
     }
     RRCrtcSetRotations (xwl_output->randr_crtc, RR_Rotate_0);
     RRCrtcGammaSetSize(xwl_output->randr_crtc, 256);
+    RRCrtcSetTransformSupport(xwl_output->randr_crtc, TRUE);
     RROutputSetCrtcs(xwl_output->randr_output, &xwl_output->randr_crtc, 1);
 
     xwl_randr_add_modes_fixed(xwl_output,
diff --git a/hw/xwayland/xwayland-output.h b/hw/xwayland/xwayland-output.h
index 7923a7e1a..5138d5e88 100644
--- a/hw/xwayland/xwayland-output.h
+++ b/hw/xwayland/xwayland-output.h
@@ -48,6 +48,7 @@ struct xwl_output {
     struct xwl_screen *xwl_screen;
     RROutputPtr randr_output;
     RRCrtcPtr randr_crtc;
+    RRTransformPtr transform;
 
     /* only for regular outputs */
     struct wl_output *output;
commit 6a09cd2d20a6e6dfdb1efdbcbeb823ad99930a4d
Author: Olivier Fourdan <ofourdan at redhat.com>
Date:   Mon Nov 27 13:39:26 2023 +0100

    xwayland: Introduce output scale
    
    Add a scale factor to the Xwayland output and take the scale into
    account when computing the screen size.
    
    Signed-off-by: Olivier Fourdan <ofourdan at redhat.com>
    Reviewed-By: Kenny Levinsen <kl at kl.wtf>
    Acked-by: Peter Hutterer <peter.hutterer at who-t.net>
    Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1197>

diff --git a/hw/xwayland/xwayland-output.c b/hw/xwayland/xwayland-output.c
index 349af302b..23c9733d2 100644
--- a/hw/xwayland/xwayland-output.c
+++ b/hw/xwayland/xwayland-output.c
@@ -891,6 +891,7 @@ xwl_output_create(struct xwl_screen *xwl_screen, uint32_t id,
 
     xwl_output->server_output_id = id;
     wl_output_add_listener(xwl_output->output, &output_listener, xwl_output);
+    xwl_output->xscale = 1.0;
 
     xwl_output->xwl_screen = xwl_screen;
 
@@ -1141,6 +1142,12 @@ mode_sort(const void *left, const void *right)
     return (*mode_b)->mode.width - (*mode_a)->mode.width;
 }
 
+void
+xwl_output_set_xscale(struct xwl_output *xwl_output, double xscale)
+{
+    xwl_output->xscale = xscale;
+}
+
 Bool
 xwl_randr_add_modes_fixed(struct xwl_output *xwl_output,
                           int current_width, int current_height)
@@ -1198,7 +1205,9 @@ xwl_output_set_mode_fixed(struct xwl_output *xwl_output, RRModePtr mode)
     xwl_output->mode_width = mode->mode.width;
     xwl_output->mode_height = mode->mode.height;
 
-    update_screen_size(xwl_screen, mode->mode.width, mode->mode.height);
+    update_screen_size(xwl_screen,
+                       round((double) mode->mode.width * xwl_output->xscale),
+                       round((double) mode->mode.height * xwl_output->xscale));
 
     RRCrtcNotify(xwl_output->randr_crtc, mode, 0, 0, RR_Rotate_0,
                  NULL, 1, &xwl_output->randr_output);
@@ -1275,6 +1284,7 @@ xwl_screen_init_randr_fixed(struct xwl_screen *xwl_screen)
 
     xwl_output->xwl_screen = xwl_screen;
     xwl_screen->fixed_output = xwl_output;
+    xwl_output->xscale = 1.0;
 
     return TRUE;
 
diff --git a/hw/xwayland/xwayland-output.h b/hw/xwayland/xwayland-output.h
index 68889c59d..7923a7e1a 100644
--- a/hw/xwayland/xwayland-output.h
+++ b/hw/xwayland/xwayland-output.h
@@ -55,6 +55,7 @@ struct xwl_output {
     uint32_t server_output_id;
     int32_t x, y, width, height, refresh;
     int32_t mode_width, mode_height;
+    double xscale; /* Effective scale, can be fractional */
     Rotation rotation;
     Bool wl_output_done;
     Bool xdg_output_done;
@@ -78,6 +79,9 @@ Bool xwl_screen_init_output(struct xwl_screen *xwl_screen);
 
 Bool xwl_screen_init_randr_fixed(struct xwl_screen *xwl_screen);
 
+void
+xwl_output_set_xscale(struct xwl_output *xwl_output, double xscale);
+
 Bool
 xwl_randr_add_modes_fixed(struct xwl_output *xwl_output,
                           int current_width, int current_height);
commit 8c54f90673370b75b75207aaf7f5752a9cd123f9
Author: Olivier Fourdan <ofourdan at redhat.com>
Date:   Mon Nov 27 13:34:52 2023 +0100

    xwayland: Store the mode width/height
    
    The mode size can be different from the actual output size when a
    transformation is at play.
    
    Store the actual mode width/height as well in preparation for adding
    support for transforms.
    
    No functional change.
    
    Signed-off-by: Olivier Fourdan <ofourdan at redhat.com>
    Reviewed-By: Kenny Levinsen <kl at kl.wtf>
    Acked-by: Peter Hutterer <peter.hutterer at who-t.net>
    Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1197>

diff --git a/hw/xwayland/xwayland-output.c b/hw/xwayland/xwayland-output.c
index e947ca090..349af302b 100644
--- a/hw/xwayland/xwayland-output.c
+++ b/hw/xwayland/xwayland-output.c
@@ -1155,6 +1155,9 @@ xwl_randr_add_modes_fixed(struct xwl_output *xwl_output,
         return FALSE;
     }
 
+    xwl_output->mode_width = current_width;
+    xwl_output->mode_height = current_height;
+
     nmodes = 0;
     current = 0;
 
@@ -1192,6 +1195,9 @@ xwl_output_set_mode_fixed(struct xwl_output *xwl_output, RRModePtr mode)
 {
     struct xwl_screen *xwl_screen = xwl_output->xwl_screen;
 
+    xwl_output->mode_width = mode->mode.width;
+    xwl_output->mode_height = mode->mode.height;
+
     update_screen_size(xwl_screen, mode->mode.width, mode->mode.height);
 
     RRCrtcNotify(xwl_output->randr_crtc, mode, 0, 0, RR_Rotate_0,
diff --git a/hw/xwayland/xwayland-output.h b/hw/xwayland/xwayland-output.h
index 24b118dfd..68889c59d 100644
--- a/hw/xwayland/xwayland-output.h
+++ b/hw/xwayland/xwayland-output.h
@@ -54,6 +54,7 @@ struct xwl_output {
     struct zxdg_output_v1 *xdg_output;
     uint32_t server_output_id;
     int32_t x, y, width, height, refresh;
+    int32_t mode_width, mode_height;
     Rotation rotation;
     Bool wl_output_done;
     Bool xdg_output_done;
commit 32dad240832af1e2e1abb5f150cb35c8e1494656
Author: Olivier Fourdan <ofourdan at redhat.com>
Date:   Tue Feb 6 14:51:56 2024 +0100

    xwayland: Use double for screen size
    
    Use double precision floating point for the screen size to reduce the
    rounding issues when using fractional scaling.
    
    Introduce a couple of simple convenient functions that round the
    floating point value into an integer and use it in place of directly
    accessing the xwl_screen width/height for integer computation.
    
    This is preparation work for the introduction of fractional scaling,
    there should be no functional change at this point.
    
    Signed-off-by: Olivier Fourdan <ofourdan at redhat.com>
    Reviewed-By: Kenny Levinsen <kl at kl.wtf>
    Acked-by: Peter Hutterer <peter.hutterer at who-t.net>
    Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1197>

diff --git a/hw/xwayland/xwayland-input.c b/hw/xwayland/xwayland-input.c
index 9c14b3ff4..abbf3b0e3 100644
--- a/hw/xwayland/xwayland-input.c
+++ b/hw/xwayland/xwayland-input.c
@@ -1387,8 +1387,8 @@ xwl_touch_send_event(struct xwl_touch *xwl_touch,
     dx = xwl_touch->window->window->drawable.x;
     dy = xwl_touch->window->window->drawable.y;
 
-    x = (dx + xwl_touch->x) * 0xFFFF / xwl_seat->xwl_screen->width;
-    y = (dy + xwl_touch->y) * 0xFFFF / xwl_seat->xwl_screen->height;
+    x = (dx + xwl_touch->x) * 0xFFFF / xwl_screen_get_width(xwl_seat->xwl_screen);
+    y = (dy + xwl_touch->y) * 0xFFFF / xwl_screen_get_height(xwl_seat->xwl_screen);
 
     valuator_mask_zero(&mask);
     valuator_mask_set_double(&mask, 0, x);
diff --git a/hw/xwayland/xwayland-output.c b/hw/xwayland/xwayland-output.c
index 2788c64d5..e947ca090 100644
--- a/hw/xwayland/xwayland-output.c
+++ b/hw/xwayland/xwayland-output.c
@@ -25,6 +25,8 @@
 
 #include <xwayland-config.h>
 
+#include <math.h>
+
 #include <X11/Xatom.h>
 #include "randrstr_priv.h"
 
@@ -186,8 +188,11 @@ update_backing_pixmaps(struct xwl_screen *xwl_screen, int width, int height)
 static void
 update_screen_size(struct xwl_screen *xwl_screen, int width, int height)
 {
-    xwl_screen->width = width;
-    xwl_screen->height = height;
+    if (xwl_screen_get_width(xwl_screen) != width)
+        xwl_screen->width = width;
+
+    if (xwl_screen_get_height(xwl_screen) != height)
+        xwl_screen->height = height;
 
     if (xwl_screen->root_clip_mode == ROOT_CLIP_FULL)
         SetRootClip(xwl_screen->screen, ROOT_CLIP_NONE);
@@ -486,8 +491,8 @@ xwl_output_get_emulated_root_size(struct xwl_output *xwl_output,
     emulated_mode = xwl_output_get_emulated_mode_for_client(xwl_output, client);
     /* If not an emulated mode, just return the actual screen size */
     if (!emulated_mode) {
-        *width = xwl_screen->width;
-        *height = xwl_screen->height;
+        *width = xwl_screen_get_width(xwl_screen);
+        *height = xwl_screen_get_height(xwl_screen);
         return;
     }
 
@@ -1247,10 +1252,12 @@ xwl_screen_init_randr_fixed(struct xwl_screen *xwl_screen)
     RROutputSetCrtcs(xwl_output->randr_output, &xwl_output->randr_crtc, 1);
 
     xwl_randr_add_modes_fixed(xwl_output,
-                              xwl_screen->width, xwl_screen->height);
+                              xwl_screen_get_width(xwl_screen),
+                              xwl_screen_get_height(xwl_screen));
     /* Current mode */
     mode = xwl_output_find_mode(xwl_output,
-                                xwl_screen->width, xwl_screen->height);
+                                xwl_screen_get_width(xwl_screen),
+                                xwl_screen_get_height(xwl_screen));
     RRCrtcNotify(xwl_output->randr_crtc, mode, 0, 0, RR_Rotate_0,
                  NULL, 1, &xwl_output->randr_output);
 
diff --git a/hw/xwayland/xwayland-screen.c b/hw/xwayland/xwayland-screen.c
index 16e95f900..e69196486 100644
--- a/hw/xwayland/xwayland-screen.c
+++ b/hw/xwayland/xwayland-screen.c
@@ -25,6 +25,7 @@
 
 #include <xwayland-config.h>
 
+#include <math.h>
 #include <stdio.h>
 #include <unistd.h>
 #include <errno.h>
@@ -145,6 +146,18 @@ xwl_screen_get_fixed_or_first_output(struct xwl_screen *xwl_screen)
     return xwl_screen_get_first_output(xwl_screen);
 }
 
+int
+xwl_screen_get_width(struct xwl_screen *xwl_screen)
+{
+    return round(xwl_screen->width);
+}
+
+int
+xwl_screen_get_height(struct xwl_screen *xwl_screen)
+{
+    return round(xwl_screen->height);
+}
+
 static void
 xwl_property_callback(CallbackListPtr *pcbl, void *closure,
                       void *calldata)
@@ -966,7 +979,8 @@ xwl_screen_init(ScreenPtr pScreen, int argc, char **argv)
     miSetPixmapDepths();
 
     ret = fbScreenInit(pScreen, NULL,
-                       xwl_screen->width, xwl_screen->height,
+                       xwl_screen_get_width(xwl_screen),
+                       xwl_screen_get_height(xwl_screen),
                        monitorResolution, monitorResolution, 0,
                        BitsPerPixel(xwl_screen->depth));
     if (!ret)
diff --git a/hw/xwayland/xwayland-screen.h b/hw/xwayland/xwayland-screen.h
index 2c7a8cef9..bf42b5a69 100644
--- a/hw/xwayland/xwayland-screen.h
+++ b/hw/xwayland/xwayland-screen.h
@@ -45,8 +45,8 @@
 #endif
 
 struct xwl_screen {
-    int width;
-    int height;
+    double width;
+    double height;
     int depth;
     int output_name_serial;
     ScreenPtr screen;
@@ -157,6 +157,9 @@ Bool xwl_screen_has_resolution_change_emulation(struct xwl_screen *xwl_screen);
 void xwl_screen_check_resolution_change_emulation(struct xwl_screen *xwl_screen);
 struct xwl_output *xwl_screen_get_first_output(struct xwl_screen *xwl_screen);
 struct xwl_output *xwl_screen_get_fixed_or_first_output(struct xwl_screen *xwl_screen);
+int xwl_screen_get_width(struct xwl_screen *xwl_screen);
+int xwl_screen_get_height(struct xwl_screen *xwl_screen);
+
 Bool xwl_close_screen(ScreenPtr screen);
 Bool xwl_screen_init(ScreenPtr pScreen, int argc, char **argv);
 void xwl_sync_events (struct xwl_screen *xwl_screen);
diff --git a/hw/xwayland/xwayland-window.c b/hw/xwayland/xwayland-window.c
index 922b45ee9..325ffdb13 100644
--- a/hw/xwayland/xwayland-window.c
+++ b/hw/xwayland/xwayland-window.c
@@ -346,8 +346,8 @@ xwl_window_should_enable_viewport_fullscreen(struct xwl_window *xwl_window,
 
     *xwl_output_ret = xwl_output;
     emulated_mode_ret->server_output_id = 0;
-    emulated_mode_ret->width = xwl_screen->width;
-    emulated_mode_ret->height = xwl_screen->height;
+    emulated_mode_ret->width = xwl_screen_get_width(xwl_screen);
+    emulated_mode_ret->height = xwl_screen_get_height(xwl_screen);
     emulated_mode_ret->from_vidmode = FALSE;
 
     return TRUE;
@@ -411,8 +411,8 @@ xwl_window_should_enable_viewport(struct xwl_window *xwl_window,
     if (xwl_output && xwl_window->window->overrideRedirect &&
         emulated_mode && emulated_mode->from_vidmode &&
         drawable->x == 0 && drawable->y == 0 &&
-        drawable->width  == xwl_screen->width &&
-        drawable->height == xwl_screen->height) {
+        drawable->width  == xwl_screen_get_width(xwl_screen) &&
+        drawable->height == xwl_screen_get_height(xwl_screen)) {
 
         memcpy(emulated_mode_ret, emulated_mode, sizeof(struct xwl_emulated_mode));
         *xwl_output_ret = xwl_output;
@@ -637,7 +637,7 @@ xwl_window_rootful_set_app_id(struct xwl_window *xwl_window)
 }
 
 static void
-xwl_window_maybe_resize(struct xwl_window *xwl_window, int width, int height)
+xwl_window_maybe_resize(struct xwl_window *xwl_window, double width, double height)
 {
     struct xwl_screen *xwl_screen = xwl_window->xwl_screen;
     struct xwl_output *xwl_output;
@@ -650,11 +650,14 @@ xwl_window_maybe_resize(struct xwl_window *xwl_window, int width, int height)
     if (width == xwl_screen->width && height == xwl_screen->height)
         return;
 
+    xwl_screen->width = width;
+    xwl_screen->height = height;
+
     xwl_output = xwl_screen_get_fixed_or_first_output(xwl_screen);
-    if (!xwl_randr_add_modes_fixed(xwl_output, width, height))
+    if (!xwl_randr_add_modes_fixed(xwl_output, round(width), round(height)))
         return;
 
-    mode = xwl_output_find_mode(xwl_output, width, height);
+    mode = xwl_output_find_mode(xwl_output,  round(width), round(height));
     xwl_output_set_mode_fixed(xwl_output, mode);
 
     xwl_window_attach_buffer(xwl_window);
@@ -692,15 +695,17 @@ handle_libdecor_configure(struct libdecor_frame *frame,
     struct xwl_window *xwl_window = data;
     struct xwl_screen *xwl_screen = xwl_window->xwl_screen;
     int width, height;
+    double new_width, new_height;
 
-    if (!libdecor_configuration_get_content_size(configuration, frame, &width, &height)) {
-        width = xwl_screen->width;
-        height = xwl_screen->height;
+    if (libdecor_configuration_get_content_size(configuration, frame, &width, &height)) {
+        new_width = (double) width;
+        new_height = (double) height;
     }
 
-    xwl_window_maybe_resize(xwl_window, width, height);
+    xwl_window_maybe_resize(xwl_window, new_width, new_height);
     xwl_window_update_libdecor_size(xwl_window, configuration,
-                                    xwl_screen->width, xwl_screen->height);
+                                     xwl_screen_get_width(xwl_screen),
+                                     xwl_screen_get_height(xwl_screen));
     wl_surface_commit(xwl_window->surface);
 }
 
@@ -1023,7 +1028,12 @@ xwl_realize_window(WindowPtr window)
         }
 
         if (!window->parent) {
-            BoxRec box = { 0, 0, xwl_screen->width, xwl_screen->height };
+            BoxRec box = {
+                0,
+                0,
+                xwl_screen_get_width(xwl_screen),
+                xwl_screen_get_height(xwl_screen)
+            };
 
             RegionReset(&window->winSize, &box);
             RegionNull(&window->clipList);


More information about the xorg-commit mailing list