From 16b0dfb78f119bd33083bb0755847fa0df2a0d03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= Date: Mon, 6 Oct 2025 16:58:59 +0200 Subject: [PATCH 01/10] xwayland: Use separate comment for each xwl_output_fake_modes line Preparation for next commit. --- hw/xwayland/xwayland-output.c | 79 +++++++++++++++++------------------ 1 file changed, 38 insertions(+), 41 deletions(-) diff --git a/hw/xwayland/xwayland-output.c b/hw/xwayland/xwayland-output.c index 715eff3ea..e1f0fca33 100644 --- a/hw/xwayland/xwayland-output.c +++ b/hw/xwayland/xwayland-output.c @@ -299,49 +299,46 @@ xwl_output_remove_emulated_mode_for_client(struct xwl_output *xwl_output, /* From hw/xfree86/common/xf86DefModeSet.c with some obscure modes dropped */ const int32_t xwl_output_fake_modes[][2] = { - /* 4:3 (1.33) */ - { 2048, 1536 }, - { 1920, 1440 }, - { 1600, 1200 }, - { 1440, 1080 }, - { 1400, 1050 }, + { 2048, 1536 }, /* 4:3 (1.33) */ + { 1920, 1440 }, /* 4:3 (1.33) */ + { 1600, 1200 }, /* 4:3 (1.33) */ + { 1440, 1080 }, /* 4:3 (1.33) */ + { 1400, 1050 }, /* 4:3 (1.33) */ { 1280, 1024 }, /* 5:4 (1.25) */ - { 1280, 960 }, - { 1152, 864 }, - { 1024, 768 }, - { 800, 600 }, - { 640, 480 }, - { 320, 240 }, - /* 16:10 (1.6) */ - { 2560, 1600 }, - { 1920, 1200 }, - { 1680, 1050 }, - { 1440, 900 }, - { 1280, 800 }, - { 1152, 720 }, - { 960, 600 }, - { 928, 580 }, - { 800, 500 }, - { 768, 480 }, + { 1280, 960 }, /* 4:3 (1.33) */ + { 1152, 864 }, /* 4:3 (1.33) */ + { 1024, 768 }, /* 4:3 (1.33) */ + { 800, 600 }, /* 4:3 (1.33) */ + { 640, 480 }, /* 4:3 (1.33) */ + { 320, 240 }, /* 4:3 (1.33) */ + { 2560, 1600 }, /* 16:10 (1.6) */ + { 1920, 1200 }, /* 16:10 (1.6) */ + { 1680, 1050 }, /* 16:10 (1.6) */ + { 1440, 900 }, /* 16:10 (1.6) */ + { 1280, 800 }, /* 16:10 (1.6) */ + { 1152, 720 }, /* 16:10 (1.6) */ + { 960, 600 }, /* 16:10 (1.6) */ + { 928, 580 }, /* 16:10 (1.6) */ + { 800, 500 }, /* 16:10 (1.6) */ + { 768, 480 }, /* 16:10 (1.6) */ { 720, 480 }, /* 3:2 (1.5) */ - { 640, 400 }, - { 320, 200 }, - /* 16:9 (1.77) */ - { 5120, 2880 }, - { 4096, 2304 }, - { 3840, 2160 }, - { 3200, 1800 }, - { 2880, 1620 }, - { 2560, 1440 }, - { 2048, 1152 }, - { 1920, 1080 }, - { 1600, 900 }, - { 1368, 768 }, - { 1280, 720 }, - { 1024, 576 }, - { 864, 486 }, - { 720, 400 }, - { 640, 350 }, + { 640, 400 }, /* 16:10 (1.6) */ + { 320, 200 }, /* 16:10 (1.6) */ + { 5120, 2880 }, /* 16:9 (1.77) */ + { 4096, 2304 }, /* 16:9 (1.77) */ + { 3840, 2160 }, /* 16:9 (1.77) */ + { 3200, 1800 }, /* 16:9 (1.77) */ + { 2880, 1620 }, /* 16:9 (1.77) */ + { 2560, 1440 }, /* 16:9 (1.77) */ + { 2048, 1152 }, /* 16:9 (1.77) */ + { 1920, 1080 }, /* 16:9 (1.77) */ + { 1600, 900 }, /* 16:9 (1.77) */ + { 1368, 768 }, /* 16:9 (1.77) */ + { 1280, 720 }, /* 16:9 (1.77) */ + { 1024, 576 }, /* 16:9 (1.77) */ + { 864, 486 }, /* 16:9 (1.77) */ + { 720, 400 }, /* 16:9 (1.77) */ + { 640, 350 }, /* 16:9 (1.77) */ }; /* Build an array with RRModes the first mode is the actual output mode, the From 586c3768a2a43cb2eb7410fab08633b0c1ecbce9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= Date: Mon, 6 Oct 2025 17:03:21 +0200 Subject: [PATCH 02/10] xwayland: Sort xwl_output_fake_modes entries Makes the list of modes tidier e.g. in xrandr output. --- hw/xwayland/xwayland-output.c | 50 +++++++++++++++++------------------ 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/hw/xwayland/xwayland-output.c b/hw/xwayland/xwayland-output.c index e1f0fca33..d41b19e58 100644 --- a/hw/xwayland/xwayland-output.c +++ b/hw/xwayland/xwayland-output.c @@ -299,46 +299,46 @@ xwl_output_remove_emulated_mode_for_client(struct xwl_output *xwl_output, /* From hw/xfree86/common/xf86DefModeSet.c with some obscure modes dropped */ const int32_t xwl_output_fake_modes[][2] = { - { 2048, 1536 }, /* 4:3 (1.33) */ - { 1920, 1440 }, /* 4:3 (1.33) */ - { 1600, 1200 }, /* 4:3 (1.33) */ - { 1440, 1080 }, /* 4:3 (1.33) */ - { 1400, 1050 }, /* 4:3 (1.33) */ - { 1280, 1024 }, /* 5:4 (1.25) */ - { 1280, 960 }, /* 4:3 (1.33) */ - { 1152, 864 }, /* 4:3 (1.33) */ - { 1024, 768 }, /* 4:3 (1.33) */ - { 800, 600 }, /* 4:3 (1.33) */ - { 640, 480 }, /* 4:3 (1.33) */ - { 320, 240 }, /* 4:3 (1.33) */ - { 2560, 1600 }, /* 16:10 (1.6) */ - { 1920, 1200 }, /* 16:10 (1.6) */ - { 1680, 1050 }, /* 16:10 (1.6) */ - { 1440, 900 }, /* 16:10 (1.6) */ - { 1280, 800 }, /* 16:10 (1.6) */ - { 1152, 720 }, /* 16:10 (1.6) */ - { 960, 600 }, /* 16:10 (1.6) */ - { 928, 580 }, /* 16:10 (1.6) */ - { 800, 500 }, /* 16:10 (1.6) */ - { 768, 480 }, /* 16:10 (1.6) */ - { 720, 480 }, /* 3:2 (1.5) */ - { 640, 400 }, /* 16:10 (1.6) */ - { 320, 200 }, /* 16:10 (1.6) */ { 5120, 2880 }, /* 16:9 (1.77) */ { 4096, 2304 }, /* 16:9 (1.77) */ { 3840, 2160 }, /* 16:9 (1.77) */ { 3200, 1800 }, /* 16:9 (1.77) */ { 2880, 1620 }, /* 16:9 (1.77) */ + { 2560, 1600 }, /* 16:10 (1.6) */ { 2560, 1440 }, /* 16:9 (1.77) */ + { 2048, 1536 }, /* 4:3 (1.33) */ { 2048, 1152 }, /* 16:9 (1.77) */ + { 1920, 1440 }, /* 4:3 (1.33) */ + { 1920, 1200 }, /* 16:10 (1.6) */ { 1920, 1080 }, /* 16:9 (1.77) */ + { 1680, 1050 }, /* 16:10 (1.6) */ + { 1600, 1200 }, /* 4:3 (1.33) */ { 1600, 900 }, /* 16:9 (1.77) */ + { 1440, 1080 }, /* 4:3 (1.33) */ + { 1440, 900 }, /* 16:10 (1.6) */ + { 1400, 1050 }, /* 4:3 (1.33) */ { 1368, 768 }, /* 16:9 (1.77) */ + { 1280, 1024 }, /* 5:4 (1.25) */ + { 1280, 960 }, /* 4:3 (1.33) */ + { 1280, 800 }, /* 16:10 (1.6) */ { 1280, 720 }, /* 16:9 (1.77) */ + { 1152, 864 }, /* 4:3 (1.33) */ + { 1152, 720 }, /* 16:10 (1.6) */ + { 1024, 768 }, /* 4:3 (1.33) */ { 1024, 576 }, /* 16:9 (1.77) */ + { 960, 600 }, /* 16:10 (1.6) */ + { 928, 580 }, /* 16:10 (1.6) */ { 864, 486 }, /* 16:9 (1.77) */ + { 800, 600 }, /* 4:3 (1.33) */ + { 800, 500 }, /* 16:10 (1.6) */ + { 768, 480 }, /* 16:10 (1.6) */ + { 720, 480 }, /* 3:2 (1.5) */ { 720, 400 }, /* 16:9 (1.77) */ + { 640, 480 }, /* 4:3 (1.33) */ + { 640, 400 }, /* 16:10 (1.6) */ { 640, 350 }, /* 16:9 (1.77) */ + { 320, 240 }, /* 4:3 (1.33) */ + { 320, 200 }, /* 16:10 (1.6) */ }; /* Build an array with RRModes the first mode is the actual output mode, the From 3ac8cab9a9ad365f343826c8f10b1fcaba6a14f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= Date: Thu, 16 Oct 2025 12:01:17 +0200 Subject: [PATCH 03/10] xwayland: Use logical_ prefix for logical coordinate system values Inspired by https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/878 . --- hw/xwayland/xwayland-output.c | 60 +++++++++++++++++----------------- hw/xwayland/xwayland-output.h | 4 +-- hw/xwayland/xwayland-screen.c | 2 +- hw/xwayland/xwayland-vidmode.c | 6 ++-- hw/xwayland/xwayland-window.c | 14 ++++---- 5 files changed, 43 insertions(+), 43 deletions(-) diff --git a/hw/xwayland/xwayland-output.c b/hw/xwayland/xwayland-output.c index d41b19e58..0b7bfa97f 100644 --- a/hw/xwayland/xwayland-output.c +++ b/hw/xwayland/xwayland-output.c @@ -102,8 +102,8 @@ output_handle_geometry(void *data, struct wl_output *wl_output, int x, int y, /* Apply the change from wl_output only if xdg-output is not supported */ if (!xwl_output->xdg_output) { - xwl_output->x = x; - xwl_output->y = y; + xwl_output->logical_x = x; + xwl_output->logical_y = y; } xwl_output->rotation = wl_transform_to_xrandr(transform); } @@ -119,8 +119,8 @@ output_handle_mode(void *data, struct wl_output *wl_output, uint32_t flags, /* Apply the change from wl_output only if xdg-output is not supported */ if (!xwl_output->xdg_output) { - xwl_output->width = width; - xwl_output->height = height; + xwl_output->logical_w = width; + xwl_output->logical_h = height; } xwl_output->refresh = refresh; } @@ -133,23 +133,23 @@ output_handle_mode(void *data, struct wl_output *wl_output, uint32_t flags, static inline void output_get_new_size(struct xwl_output *xwl_output, int *width, int *height) { - int output_width, output_height; + int logical_width, logical_height; /* When we have xdg-output support the stored size is already rotated. */ if (xwl_output->xdg_output || (xwl_output->rotation & (RR_Rotate_0 | RR_Rotate_180))) { - output_width = xwl_output->width; - output_height = xwl_output->height; + logical_width = xwl_output->logical_w; + logical_height = xwl_output->logical_h; } else { - output_width = xwl_output->height; - output_height = xwl_output->width; + logical_width = xwl_output->logical_h; + logical_height = xwl_output->logical_w; } - if (*width < xwl_output->x + output_width) - *width = xwl_output->x + output_width; + if (*width < xwl_output->logical_x + logical_width) + *width = xwl_output->logical_x + logical_width; - if (*height < xwl_output->y + output_height) - *height = xwl_output->y + output_height; + if (*height < xwl_output->logical_y + logical_height) + *height = xwl_output->logical_y + logical_height; } static int @@ -446,8 +446,8 @@ xwl_output_randr_emu_prop(struct xwl_screen *xwl_screen, ClientPtr client, if (!emulated_mode) continue; - prop->rects[index][0] = xwl_output->x; - prop->rects[index][1] = xwl_output->y; + prop->rects[index][0] = xwl_output->logical_x; + prop->rects[index][1] = xwl_output->logical_y; prop->rects[index][2] = emulated_mode->width; prop->rects[index][3] = emulated_mode->height; index++; @@ -629,8 +629,7 @@ apply_output_change(struct xwl_output *xwl_output) { struct xwl_screen *xwl_screen = xwl_output->xwl_screen; struct xwl_output *it; - int mode_width, mode_height, count; - int width = 0, height = 0, has_this_output = 0; + int logical_width, logical_height, count, has_this_output = 0; RRModePtr *randr_modes; /* Clear out the "done" received flags */ @@ -642,18 +641,18 @@ apply_output_change(struct xwl_output *xwl_output) */ if (xwl_output->xdg_output == NULL || xwl_output->rotation & (RR_Rotate_0 | RR_Rotate_180)) { - mode_width = xwl_output->width; - mode_height = xwl_output->height; + logical_width = xwl_output->logical_w; + logical_height = xwl_output->logical_h; } else { - mode_width = xwl_output->height; - mode_height = xwl_output->width; + logical_width = xwl_output->logical_h; + logical_height = xwl_output->logical_w; } if (xwl_output->randr_output) { /* Build a fresh modes array using the current refresh rate */ - randr_modes = output_get_rr_modes(xwl_output, mode_width, mode_height, &count); + randr_modes = output_get_rr_modes(xwl_output, logical_width, logical_height, &count); RROutputSetModes(xwl_output->randr_output, randr_modes, count, 1); RRCrtcNotify(xwl_output->randr_crtc, randr_modes[0], - xwl_output->x, xwl_output->y, + xwl_output->logical_x, xwl_output->logical_y, xwl_output->rotation, NULL, 1, &xwl_output->randr_output); /* RROutputSetModes takes ownership of the passed in modes, so we only * have to free the pointer array. @@ -661,6 +660,7 @@ apply_output_change(struct xwl_output *xwl_output) free(randr_modes); } + logical_width = logical_height = 0; xorg_list_for_each_entry(it, &xwl_screen->output_list, link) { /* output done event is sent even when some property * of output is changed. That means that we may already @@ -669,20 +669,20 @@ apply_output_change(struct xwl_output *xwl_output) if (it == xwl_output) has_this_output = 1; - output_get_new_size(it, &width, &height); + output_get_new_size(it, &logical_width, &logical_height); } if (!has_this_output) { xorg_list_append(&xwl_output->link, &xwl_screen->output_list); /* we did not check this output for new screen size, do it now */ - output_get_new_size(xwl_output, &width, &height); + output_get_new_size(xwl_output, &logical_width, &logical_height); --xwl_screen->expecting_event; } if (xwl_screen->fixed_output == NULL) - update_screen_size(xwl_screen, width, height); + update_screen_size(xwl_screen, logical_width, logical_height); else RRTellChanged(xwl_screen->screen); @@ -788,8 +788,8 @@ xdg_output_handle_logical_position(void *data, struct zxdg_output_v1 *xdg_output { struct xwl_output *xwl_output = data; - xwl_output->x = x; - xwl_output->y = y; + xwl_output->logical_x = x; + xwl_output->logical_y = y; } static void @@ -798,8 +798,8 @@ xdg_output_handle_logical_size(void *data, struct zxdg_output_v1 *xdg_output, { struct xwl_output *xwl_output = data; - xwl_output->width = width; - xwl_output->height = height; + xwl_output->logical_w = width; + xwl_output->logical_h = height; } static void diff --git a/hw/xwayland/xwayland-output.h b/hw/xwayland/xwayland-output.h index 0d36f459a..17bdf94d9 100644 --- a/hw/xwayland/xwayland-output.h +++ b/hw/xwayland/xwayland-output.h @@ -56,8 +56,8 @@ 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, scale; - int32_t mode_width, mode_height; + int32_t logical_x, logical_y, logical_w, logical_h; + int32_t mode_width, mode_height, refresh, scale; double xscale; /* Effective scale, can be fractional */ Rotation rotation; Bool wl_output_done; diff --git a/hw/xwayland/xwayland-screen.c b/hw/xwayland/xwayland-screen.c index 22c500801..44d798609 100644 --- a/hw/xwayland/xwayland-screen.c +++ b/hw/xwayland/xwayland-screen.c @@ -134,7 +134,7 @@ xwl_screen_get_first_output(struct xwl_screen *xwl_screen) struct xwl_output *xwl_output; xorg_list_for_each_entry(xwl_output, &xwl_screen->output_list, link) { - if (xwl_output->x == 0 && xwl_output->y == 0) + if (xwl_output->logical_x == 0 && xwl_output->logical_y == 0) return xwl_output; } diff --git a/hw/xwayland/xwayland-vidmode.c b/hw/xwayland/xwayland-vidmode.c index a4ca0eaf1..cabe1963c 100644 --- a/hw/xwayland/xwayland-vidmode.c +++ b/hw/xwayland/xwayland-vidmode.c @@ -308,7 +308,7 @@ xwlVidModeSetViewPort(ScreenPtr pScreen, int x, int y) return FALSE; /* Support only default viewport */ - return (x == xwl_output->x && y == xwl_output->y); + return (x == xwl_output->logical_x && y == xwl_output->logical_y); } static Bool @@ -321,8 +321,8 @@ xwlVidModeGetViewPort(ScreenPtr pScreen, int *x, int *y) if (xwl_output == NULL) return FALSE; - *x = xwl_output->x; - *y = xwl_output->y; + *x = xwl_output->logical_x; + *y = xwl_output->logical_y; return TRUE; } diff --git a/hw/xwayland/xwayland-window.c b/hw/xwayland/xwayland-window.c index db611d247..e70179b8b 100644 --- a/hw/xwayland/xwayland-window.c +++ b/hw/xwayland/xwayland-window.c @@ -463,11 +463,11 @@ xwl_window_enable_viewport_for_output(struct xwl_window *xwl_window, wl_fixed_from_int(width), wl_fixed_from_int(height)); wp_viewport_set_destination(xwl_window->viewport, - xwl_output->width, - xwl_output->height); + xwl_output->logical_w, + xwl_output->logical_h); - xwl_window->viewport_scale_x = (float) width / xwl_output->width; - xwl_window->viewport_scale_y = (float) height / xwl_output->height; + xwl_window->viewport_scale_x = (float) width / xwl_output->logical_w; + xwl_window->viewport_scale_y = (float) height / xwl_output->logical_h; xwl_window_set_input_region(xwl_window, wInputShape(xwl_window->toplevel)); } @@ -525,7 +525,7 @@ is_output_suitable_for_fullscreen(struct xwl_output *xwl_output) if (xwl_output == NULL) return FALSE; - if (xwl_output->width == 0 || xwl_output->height == 0) + if (xwl_output->logical_w == 0 || xwl_output->logical_h == 0) return FALSE; return TRUE; @@ -607,8 +607,8 @@ xwl_window_should_enable_viewport(struct xwl_window *xwl_window, if (!emulated_mode) continue; - if (drawable->x == xwl_output->x && - drawable->y == xwl_output->y && + if (drawable->x == xwl_output->logical_x && + drawable->y == xwl_output->logical_y && drawable->width == emulated_mode->width && drawable->height == emulated_mode->height) { From b36f59132370d256bbad310d3853c667313bca5f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= Date: Fri, 31 Oct 2025 18:53:03 +0100 Subject: [PATCH 04/10] xwayland: Refactor output_get_logical_mode/extents helpers Preparation for later changes. --- hw/xwayland/xwayland-output.c | 51 +++++++++++++++++++++-------------- 1 file changed, 31 insertions(+), 20 deletions(-) diff --git a/hw/xwayland/xwayland-output.c b/hw/xwayland/xwayland-output.c index 0b7bfa97f..fba660930 100644 --- a/hw/xwayland/xwayland-output.c +++ b/hw/xwayland/xwayland-output.c @@ -125,6 +125,34 @@ output_handle_mode(void *data, struct wl_output *wl_output, uint32_t flags, xwl_output->refresh = refresh; } +static void +output_get_logical_mode(struct xwl_output *xwl_output, int *width, int *height) +{ + /* When we have xdg-output support the stored size is already rotated. */ + if (xwl_output->xdg_output == NULL || + (xwl_output->rotation & (RR_Rotate_0 | RR_Rotate_180))) { + *width = xwl_output->logical_w; + *height = xwl_output->logical_h; + } else { + *width = xwl_output->logical_h; + *height = xwl_output->logical_w; + } +} + +static void +output_get_logical_extents(struct xwl_output *xwl_output, int *width, int *height) +{ + /* When we have xdg-output support the stored size is already rotated. */ + if (xwl_output->xdg_output || + (xwl_output->rotation & (RR_Rotate_0 | RR_Rotate_180))) { + *width = xwl_output->logical_w; + *height = xwl_output->logical_h; + } else { + *width = xwl_output->logical_h; + *height = xwl_output->logical_w; + } +} + /** * Decides on the maximum expanse of an output in logical space (i.e. in the * Wayland compositor plane) respective to some fix width and height values. The @@ -135,15 +163,7 @@ output_get_new_size(struct xwl_output *xwl_output, int *width, int *height) { int logical_width, logical_height; - /* When we have xdg-output support the stored size is already rotated. */ - if (xwl_output->xdg_output - || (xwl_output->rotation & (RR_Rotate_0 | RR_Rotate_180))) { - logical_width = xwl_output->logical_w; - logical_height = xwl_output->logical_h; - } else { - logical_width = xwl_output->logical_h; - logical_height = xwl_output->logical_w; - } + output_get_logical_extents(xwl_output, &logical_width, &logical_height); if (*width < xwl_output->logical_x + logical_width) *width = xwl_output->logical_x + logical_width; @@ -636,17 +656,8 @@ apply_output_change(struct xwl_output *xwl_output) xwl_output->wl_output_done = FALSE; xwl_output->xdg_output_done = FALSE; - /* When we have received an xdg-output for the mode size we might need to - * rotate back the stored logical size it provided. - */ - if (xwl_output->xdg_output == NULL - || xwl_output->rotation & (RR_Rotate_0 | RR_Rotate_180)) { - logical_width = xwl_output->logical_w; - logical_height = xwl_output->logical_h; - } else { - logical_width = xwl_output->logical_h; - logical_height = xwl_output->logical_w; - } + output_get_logical_mode(xwl_output, &logical_width, &logical_height); + if (xwl_output->randr_output) { /* Build a fresh modes array using the current refresh rate */ randr_modes = output_get_rr_modes(xwl_output, logical_width, logical_height, &count); From a136452f410339717ed4520410a80e5d6506abf3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= Date: Thu, 16 Oct 2025 12:31:20 +0200 Subject: [PATCH 05/10] xwayland: Set output mode size as reported by the wl_output protocol This means xwl_output->mode_width/height can be non-0 also with rootless, so need to check for rootful explicitly in xwl_output_find_mode. --- hw/xwayland/xwayland-output.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/hw/xwayland/xwayland-output.c b/hw/xwayland/xwayland-output.c index fba660930..09aac9655 100644 --- a/hw/xwayland/xwayland-output.c +++ b/hw/xwayland/xwayland-output.c @@ -122,6 +122,9 @@ output_handle_mode(void *data, struct wl_output *wl_output, uint32_t flags, xwl_output->logical_w = width; xwl_output->logical_h = height; } + + xwl_output->mode_width = width; + xwl_output->mode_height = height; xwl_output->refresh = refresh; } @@ -424,8 +427,9 @@ xwl_output_find_mode(struct xwl_output *xwl_output, /* width & height -1 means we want the actual output mode */ if (width == -1 && height == -1) { - if (xwl_output->mode_width > 0 && xwl_output->mode_height > 0) { - /* If running rootful, use the current mode size to search for the mode */ + if (xwl_output == xwl_output->xwl_screen->fixed_output && + xwl_output->mode_width > 0 && xwl_output->mode_height > 0) { + /* If running rootful, use the current fixed size to search for the mode */ width = xwl_output->mode_width; height = xwl_output->mode_height; } From 7f3ad3f5da17cbf928b8e7ab0a3fae211e72fcd7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= Date: Fri, 25 Feb 2022 18:23:03 +0100 Subject: [PATCH 06/10] xwayland: Do not assume the first RandR mode is the logical mode It currently always is, it won't be with the next commit though. --- hw/xwayland/xwayland-output.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/hw/xwayland/xwayland-output.c b/hw/xwayland/xwayland-output.c index 09aac9655..338c98f29 100644 --- a/hw/xwayland/xwayland-output.c +++ b/hw/xwayland/xwayland-output.c @@ -433,9 +433,12 @@ xwl_output_find_mode(struct xwl_output *xwl_output, width = xwl_output->mode_width; height = xwl_output->mode_height; } - else if (output->modes) { - /* else return the mode at first idx 0 */ - return output->modes[0]; + else { + output_get_logical_mode(xwl_output, &width, &height); + + if (output->numModes && + (width <= 0 || height <= 0)) + return output->modes[0]; } } @@ -604,6 +607,7 @@ xwl_output_set_emulated_mode(struct xwl_output *xwl_output, ClientPtr client, RRModePtr mode, Bool from_vidmode) { int old_emulated_width, old_emulated_height; + int logical_width, logical_height; int new_emulated_width, new_emulated_height; DebugF("XWAYLAND: xwl_output_set_emulated_mode from %s: %dx%d\n", @@ -613,8 +617,9 @@ xwl_output_set_emulated_mode(struct xwl_output *xwl_output, ClientPtr client, xwl_output_get_emulated_root_size(xwl_output, client, &old_emulated_width, &old_emulated_height); - /* modes[0] is the actual (not-emulated) output mode */ - if (mode == xwl_output->randr_output->modes[0]) + /* Skip the logical (not-emulated) output mode */ + output_get_logical_mode(xwl_output, &logical_width, &logical_height); + if (mode->mode.width == logical_width && mode->mode.height == logical_height) xwl_output_remove_emulated_mode_for_client(xwl_output, client); else xwl_output_add_emulated_mode_for_client(xwl_output, client, mode, from_vidmode); From cd8464218b2ca82323fd3312270c2dfafc8716ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= Date: Mon, 28 Feb 2022 18:08:23 +0100 Subject: [PATCH 07/10] xwayland: Add RandR mode for the native resolution if it fits in logical Always add it as the first mode, which makes it considered the preferred mode per the RandR protocol. Mark the logical mode as currently set. v2: * Drop change in xwl_window_should_enable_viewport which seems unnecessary and coult result in a crash. (Olivier Fourdan) * Use 'native' instead of 'actual'. --- hw/xwayland/xwayland-output.c | 41 +++++++++++++++++++++++++++++------ 1 file changed, 34 insertions(+), 7 deletions(-) diff --git a/hw/xwayland/xwayland-output.c b/hw/xwayland/xwayland-output.c index 338c98f29..85c2b7059 100644 --- a/hw/xwayland/xwayland-output.c +++ b/hw/xwayland/xwayland-output.c @@ -378,27 +378,46 @@ output_get_rr_modes(struct xwl_output *xwl_output, RRModePtr *rr_modes; int i; - rr_modes = xallocarray(ARRAY_SIZE(xwl_output_fake_modes) + 1, sizeof(RRModePtr)); + rr_modes = xallocarray(ARRAY_SIZE(xwl_output_fake_modes) + 2, sizeof(RRModePtr)); if (!rr_modes) goto err; - /* Add actual output mode */ - rr_modes[0] = xwayland_cvt(width, height, xwl_output->refresh / 1000.0, 0, 0); - if (!rr_modes[0]) + *count = 0; + + if (xwl_screen_has_resolution_change_emulation(xwl_screen) && + (width > xwl_output->mode_width || + (width == xwl_output->mode_width && height > xwl_output->mode_height))) { + /* Add native output mode as preferred */ + rr_modes[0] = xwayland_cvt(xwl_output->mode_width, xwl_output->mode_height, + xwl_output->refresh / 1000.0, 0, 0); + if (!rr_modes[0]) + goto err; + + *count = 1; + } + + /* Add logical output mode */ + rr_modes[*count] = xwayland_cvt(width, height, xwl_output->refresh / 1000.0, 0, 0); + if (!rr_modes[*count]) goto err; - *count = 1; + (*count)++; if (!xwl_screen_has_resolution_change_emulation(xwl_screen) && !xwl_screen->force_xrandr_emulation) return rr_modes; /* Add fake modes */ for (i = 0; i < ARRAY_SIZE(xwl_output_fake_modes); i++) { - /* Skip actual output mode, already added */ + /* Skip logical output mode, already added */ if (xwl_output_fake_modes[i][0] == width && xwl_output_fake_modes[i][1] == height) continue; + /* Skip native output mode, already added */ + if (xwl_output_fake_modes[i][0] == xwl_output->mode_width && + xwl_output_fake_modes[i][1] == xwl_output->mode_height) + continue; + /* Skip modes which are too big, avoid downscaling */ if (xwl_output_fake_modes[i][0] > width || xwl_output_fake_modes[i][1] > height) @@ -660,6 +679,7 @@ apply_output_change(struct xwl_output *xwl_output) struct xwl_output *it; int logical_width, logical_height, count, has_this_output = 0; RRModePtr *randr_modes; + RRModePtr default_mode; /* Clear out the "done" received flags */ xwl_output->wl_output_done = FALSE; @@ -670,8 +690,15 @@ apply_output_change(struct xwl_output *xwl_output) if (xwl_output->randr_output) { /* Build a fresh modes array using the current refresh rate */ randr_modes = output_get_rr_modes(xwl_output, logical_width, logical_height, &count); + + if (randr_modes[0]->mode.width == logical_width && + randr_modes[0]->mode.height == logical_height) + default_mode = randr_modes[0]; + else + default_mode = randr_modes[1]; + RROutputSetModes(xwl_output->randr_output, randr_modes, count, 1); - RRCrtcNotify(xwl_output->randr_crtc, randr_modes[0], + RRCrtcNotify(xwl_output->randr_crtc, default_mode, xwl_output->logical_x, xwl_output->logical_y, xwl_output->rotation, NULL, 1, &xwl_output->randr_output); /* RROutputSetModes takes ownership of the passed in modes, so we only From 52ea534bffd2cae40f5c4c74cabd314bae9988d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= Date: Mon, 6 Oct 2025 16:48:20 +0200 Subject: [PATCH 08/10] xwayland: Clear ConstrainCursorHarder in xwl_screen_init_output In the rootless case, Xwayland receives pointer motion events only while the pointer is over one of its Wayland surfaces, so there's no need for constraining them to RandR boundaries. This also avoids them getting spuriously constrained when using RandR emulation for modes larger than the default one. --- hw/xwayland/xwayland-output.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/hw/xwayland/xwayland-output.c b/hw/xwayland/xwayland-output.c index 85c2b7059..a43126678 100644 --- a/hw/xwayland/xwayland-output.c +++ b/hw/xwayland/xwayland-output.c @@ -1189,6 +1189,8 @@ xwl_screen_init_output(struct xwl_screen *xwl_screen) if (!RRScreenInit(xwl_screen->screen)) return FALSE; + xwl_screen->screen->ConstrainCursorHarder = NULL; + RRScreenSetSizeRange(xwl_screen->screen, 16, 16, 32767, 32767); rp = rrGetScrPriv(xwl_screen->screen); From 90d2a1dc295c886352d8dea4863c7e5bfee73579 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= Date: Mon, 3 Nov 2025 18:59:03 +0100 Subject: [PATCH 09/10] xwayland: Add emulated modes larger than the logical mode Up to the native mode, as reported by the wl_output protocol. This ensures that fullscreen apps can always use the native mode. Also ensure the root window is large enough for the output at its current position with the native mode. --- hw/xwayland/xwayland-output.c | 66 +++++++++++++++++++++++------------ 1 file changed, 44 insertions(+), 22 deletions(-) diff --git a/hw/xwayland/xwayland-output.c b/hw/xwayland/xwayland-output.c index a43126678..335ec43eb 100644 --- a/hw/xwayland/xwayland-output.c +++ b/hw/xwayland/xwayland-output.c @@ -164,15 +164,23 @@ output_get_logical_extents(struct xwl_output *xwl_output, int *width, int *heigh static inline void output_get_new_size(struct xwl_output *xwl_output, int *width, int *height) { - int logical_width, logical_height; + int logical_width, logical_height, max_width, max_height; output_get_logical_extents(xwl_output, &logical_width, &logical_height); - if (*width < xwl_output->logical_x + logical_width) - *width = xwl_output->logical_x + logical_width; + if (xwl_output->rotation & (RR_Rotate_0 | RR_Rotate_180)) { + max_width = max(logical_width, xwl_output->mode_width); + max_height = max(logical_height, xwl_output->mode_height); + } else { + max_width = max(logical_width, xwl_output->mode_height); + max_height = max(logical_height, xwl_output->mode_width); + } - if (*height < xwl_output->logical_y + logical_height) - *height = xwl_output->logical_y + logical_height; + if (*width < xwl_output->logical_x + max_width) + *width = xwl_output->logical_x + max_width; + + if (*height < xwl_output->logical_y + max_height) + *height = xwl_output->logical_y + max_height; } static int @@ -372,11 +380,11 @@ const int32_t xwl_output_fake_modes[][2] = { static RRModePtr * output_get_rr_modes(struct xwl_output *xwl_output, int32_t width, int32_t height, - int *count) + int *count, int *logical_mode) { struct xwl_screen *xwl_screen = xwl_output->xwl_screen; RRModePtr *rr_modes; - int i; + int i = 0; rr_modes = xallocarray(ARRAY_SIZE(xwl_output_fake_modes) + 2, sizeof(RRModePtr)); if (!rr_modes) @@ -385,8 +393,7 @@ output_get_rr_modes(struct xwl_output *xwl_output, *count = 0; if (xwl_screen_has_resolution_change_emulation(xwl_screen) && - (width > xwl_output->mode_width || - (width == xwl_output->mode_width && height > xwl_output->mode_height))) { + (width != xwl_output->mode_width || height != xwl_output->mode_height)) { /* Add native output mode as preferred */ rr_modes[0] = xwayland_cvt(xwl_output->mode_width, xwl_output->mode_height, xwl_output->refresh / 1000.0, 0, 0); @@ -394,6 +401,26 @@ output_get_rr_modes(struct xwl_output *xwl_output, goto err; *count = 1; + + /* Add fake modes larger than logical mode */ + for (; i < ARRAY_SIZE(xwl_output_fake_modes); i++) { + if (xwl_output_fake_modes[i][0] <= width && + xwl_output_fake_modes[i][1] <= height) + break; + + /* Skip modes which are too big, avoid downscaling */ + if (xwl_output_fake_modes[i][0] >= xwl_output->mode_width && + xwl_output_fake_modes[i][1] >= xwl_output->mode_height) + continue; + + rr_modes[*count] = xwayland_cvt(xwl_output_fake_modes[i][0], + xwl_output_fake_modes[i][1], + xwl_output->refresh / 1000.0, 0, 0); + if (!rr_modes[*count]) + goto err; + + (*count)++; + } } /* Add logical output mode */ @@ -401,13 +428,13 @@ output_get_rr_modes(struct xwl_output *xwl_output, if (!rr_modes[*count]) goto err; - (*count)++; + *logical_mode = (*count)++; if (!xwl_screen_has_resolution_change_emulation(xwl_screen) && !xwl_screen->force_xrandr_emulation) return rr_modes; /* Add fake modes */ - for (i = 0; i < ARRAY_SIZE(xwl_output_fake_modes); i++) { + for (; i < ARRAY_SIZE(xwl_output_fake_modes); i++) { /* Skip logical output mode, already added */ if (xwl_output_fake_modes[i][0] == width && xwl_output_fake_modes[i][1] == height) @@ -419,8 +446,8 @@ output_get_rr_modes(struct xwl_output *xwl_output, continue; /* Skip modes which are too big, avoid downscaling */ - if (xwl_output_fake_modes[i][0] > width || - xwl_output_fake_modes[i][1] > height) + if (xwl_output_fake_modes[i][0] > max(width, xwl_output->mode_width) || + xwl_output_fake_modes[i][1] > max(height, xwl_output->mode_height)) continue; rr_modes[*count] = xwayland_cvt(xwl_output_fake_modes[i][0], @@ -679,7 +706,7 @@ apply_output_change(struct xwl_output *xwl_output) struct xwl_output *it; int logical_width, logical_height, count, has_this_output = 0; RRModePtr *randr_modes; - RRModePtr default_mode; + int logical_mode; /* Clear out the "done" received flags */ xwl_output->wl_output_done = FALSE; @@ -689,16 +716,11 @@ apply_output_change(struct xwl_output *xwl_output) if (xwl_output->randr_output) { /* Build a fresh modes array using the current refresh rate */ - randr_modes = output_get_rr_modes(xwl_output, logical_width, logical_height, &count); - - if (randr_modes[0]->mode.width == logical_width && - randr_modes[0]->mode.height == logical_height) - default_mode = randr_modes[0]; - else - default_mode = randr_modes[1]; + randr_modes = output_get_rr_modes(xwl_output, logical_width, logical_height, + &count, &logical_mode); RROutputSetModes(xwl_output->randr_output, randr_modes, count, 1); - RRCrtcNotify(xwl_output->randr_crtc, default_mode, + RRCrtcNotify(xwl_output->randr_crtc, randr_modes[logical_mode], xwl_output->logical_x, xwl_output->logical_y, xwl_output->rotation, NULL, 1, &xwl_output->randr_output); /* RROutputSetModes takes ownership of the passed in modes, so we only From 6f81956b2df69f3889ad56c5dd4838157c9060b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= Date: Wed, 5 Nov 2025 16:31:21 +0100 Subject: [PATCH 10/10] xwayland: Adjust RandR emulation for rotation Need to use the extents of the output in screen cordinates, instead of the canonical mode size. --- hw/xwayland/xwayland-output.c | 13 +++++++++--- hw/xwayland/xwayland-output.h | 2 ++ hw/xwayland/xwayland-window.c | 39 ++++++++++++++++++++++++----------- 3 files changed, 39 insertions(+), 15 deletions(-) diff --git a/hw/xwayland/xwayland-output.c b/hw/xwayland/xwayland-output.c index 335ec43eb..fd8bb5630 100644 --- a/hw/xwayland/xwayland-output.c +++ b/hw/xwayland/xwayland-output.c @@ -142,7 +142,7 @@ output_get_logical_mode(struct xwl_output *xwl_output, int *width, int *height) } } -static void +void output_get_logical_extents(struct xwl_output *xwl_output, int *width, int *height) { /* When we have xdg-output support the stored size is already rotated. */ @@ -521,8 +521,15 @@ xwl_output_randr_emu_prop(struct xwl_screen *xwl_screen, ClientPtr client, prop->rects[index][0] = xwl_output->logical_x; prop->rects[index][1] = xwl_output->logical_y; - prop->rects[index][2] = emulated_mode->width; - prop->rects[index][3] = emulated_mode->height; + + if (xwl_output->rotation & (RR_Rotate_0 | RR_Rotate_180)) { + prop->rects[index][2] = emulated_mode->width; + prop->rects[index][3] = emulated_mode->height; + } else { + prop->rects[index][2] = emulated_mode->height; + prop->rects[index][3] = emulated_mode->width; + } + index++; } diff --git a/hw/xwayland/xwayland-output.h b/hw/xwayland/xwayland-output.h index 17bdf94d9..8bce0ba63 100644 --- a/hw/xwayland/xwayland-output.h +++ b/hw/xwayland/xwayland-output.h @@ -111,6 +111,8 @@ void xwl_output_remove(struct xwl_output *xwl_output); struct xwl_emulated_mode *xwl_output_get_emulated_mode_for_client( struct xwl_output *xwl_output, ClientPtr client); +void output_get_logical_extents(struct xwl_output *xwl_output, int *width, int *height); + RRModePtr xwl_output_find_mode(struct xwl_output *xwl_output, int32_t width, int32_t height); void xwl_output_set_emulated_mode(struct xwl_output *xwl_output, diff --git a/hw/xwayland/xwayland-window.c b/hw/xwayland/xwayland-window.c index e70179b8b..d4b7207e0 100644 --- a/hw/xwayland/xwayland-window.c +++ b/hw/xwayland/xwayland-window.c @@ -444,30 +444,35 @@ xwl_window_enable_viewport_for_output(struct xwl_window *xwl_window, struct xwl_emulated_mode *emulated_mode) { struct xwl_screen *xwl_screen = xwl_window->xwl_screen; - int width, height; + int width, height, logical_width, logical_height; + + if (xwl_output->rotation & (RR_Rotate_0 | RR_Rotate_180)) { + width = emulated_mode->width / xwl_screen->global_surface_scale; + height = emulated_mode->height / xwl_screen->global_surface_scale; + } else { + width = emulated_mode->height / xwl_screen->global_surface_scale; + height = emulated_mode->width / xwl_screen->global_surface_scale; + } + + output_get_logical_extents(xwl_output, &logical_width, &logical_height); if (!xwl_window_has_viewport_enabled(xwl_window)) { DebugF("XWAYLAND: enabling viewport %dx%d -> %dx%d\n", - emulated_mode->width, emulated_mode->height, - xwl_output->width, xwl_output->height); + width, height, logical_width, logical_height); xwl_window->viewport = wp_viewporter_get_viewport(xwl_window->xwl_screen->viewporter, 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(width), wl_fixed_from_int(height)); wp_viewport_set_destination(xwl_window->viewport, - xwl_output->logical_w, - xwl_output->logical_h); + logical_width, logical_height); - xwl_window->viewport_scale_x = (float) width / xwl_output->logical_w; - xwl_window->viewport_scale_y = (float) height / xwl_output->logical_h; + xwl_window->viewport_scale_x = (float) width / logical_width; + xwl_window->viewport_scale_y = (float) height / logical_height; xwl_window_set_input_region(xwl_window, wInputShape(xwl_window->toplevel)); } @@ -603,14 +608,24 @@ xwl_window_should_enable_viewport(struct xwl_window *xwl_window, * This path gets hit by most games / libs (e.g. SDL, SFML, OGRE) */ xorg_list_for_each_entry(xwl_output, &xwl_screen->output_list, link) { + int emulated_width, emulated_height; + emulated_mode = xwl_output_get_emulated_mode_for_client(xwl_output, owner); if (!emulated_mode) continue; + if (xwl_output->rotation & (RR_Rotate_0 | RR_Rotate_180)) { + emulated_width = emulated_mode->width; + emulated_height = emulated_mode->height; + } else { + emulated_width = emulated_mode->height; + emulated_height = emulated_mode->width; + } + if (drawable->x == xwl_output->logical_x && drawable->y == xwl_output->logical_y && - drawable->width == emulated_mode->width && - drawable->height == emulated_mode->height) { + drawable->width == emulated_width && + drawable->height == emulated_height) { memcpy(emulated_mode_ret, emulated_mode, sizeof(struct xwl_emulated_mode)); *xwl_output_ret = xwl_output;