Projects
Mega:24.03:SP1:Everything
xorg-x11-server
_service:tar_scm:0008-xwayland-Add-support-for-...
Sign Up
Log In
Username
Password
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File _service:tar_scm:0008-xwayland-Add-support-for-randr-resolution-change-emu.patch of Package xorg-x11-server
From 2f2a6b8556bd104740d76126640abcfe4705047c Mon Sep 17 00:00:00 2001 From: Hans de Goede <hdegoede@redhat.com> Date: Tue, 2 Jul 2019 11:55:26 +0200 Subject: [PATCH xserver 08/25] xwayland: Add support for randr-resolution change emulation using viewport MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add support for per client randr-resolution change emulation using viewport, for apps which want to change the resolution when going fullscreen. Partly based on earlier work on this by Robert Mader <robert.mader@posteo.de> Note SDL2 and SFML do not restore randr resolution when going from fullscreen -> windowed, I believe this is caused by us still reporting the desktop resolution when they query the resolution. This is not a problem because when windowed the toplevel window size includes the window-decorations so it never matches the emulated resolution. One exception would be the window being resizable in Windowed mode and the user resizing the window so that including decorations it matches the emulated resolution *and* the window being at pos 0x0. But this is an extreme corner case. Still I will submit patches upstream to SDL2 and SFML to always restore the desktop resolution under Xwayland, disabling resolution emulation all together when going windowed. Reviewed-by: Olivier Fourdan <ofourdan@redhat.com> Acked-by: Michel Dänzer <mdaenzer@redhat.com> Signed-off-by: Hans de Goede <hdegoede@redhat.com> (cherry picked from commit d99b9ff0f237d15e7eb507484493c73b393d5dba) --- hw/xwayland/xwayland-input.c | 5 + hw/xwayland/xwayland-output.c | 63 ++++++++++- hw/xwayland/xwayland.c | 199 ++++++++++++++++++++++++++++++++++ hw/xwayland/xwayland.h | 15 +++ 4 files changed, 276 insertions(+), 6 deletions(-) diff --git a/hw/xwayland/xwayland-input.c b/hw/xwayland/xwayland-input.c index a05d178ff..7d75a8f54 100644 --- a/hw/xwayland/xwayland-input.c +++ b/hw/xwayland/xwayland-input.c @@ -488,6 +488,11 @@ dispatch_pointer_motion_event(struct xwl_seat *xwl_seat) int dx = xwl_seat->focus_window->window->drawable.x; int dy = xwl_seat->focus_window->window->drawable.y; + if (xwl_window_has_viewport_enabled(xwl_seat->focus_window)) { + sx *= xwl_seat->focus_window->scale_x; + sy *= xwl_seat->focus_window->scale_y; + } + x = dx + sx; y = dy + sy; } else { diff --git a/hw/xwayland/xwayland-output.c b/hw/xwayland/xwayland-output.c index 64794dee7..e09d00108 100644 --- a/hw/xwayland/xwayland-output.c +++ b/hw/xwayland/xwayland-output.c @@ -371,6 +371,42 @@ err: FatalError("Failed to allocate memory for list of RR modes"); } +RRModePtr +xwl_output_find_mode(struct xwl_output *xwl_output, + int32_t width, int32_t height) +{ + RROutputPtr output = xwl_output->randr_output; + int i; + + /* width & height -1 means we want the actual output mode, which is idx 0 */ + if (width == -1 && height == -1 && output->modes) + return output->modes[0]; + + for (i = 0; i < output->numModes; i++) { + if (output->modes[i]->mode.width == width && output->modes[i]->mode.height == height) + return output->modes[i]; + } + + ErrorF("XWAYLAND: mode %dx%d is not available\n", width, height); + return NULL; +} + +void +xwl_output_set_emulated_mode(struct xwl_output *xwl_output, ClientPtr client, + RRModePtr mode, Bool from_vidmode) +{ + DebugF("XWAYLAND: xwl_output_set_emulated_mode from %s: %dx%d\n", + from_vidmode ? "vidmode" : "randr", + mode->mode.width, mode->mode.height); + + if (mode->mode.width == xwl_output->width && mode->mode.height == xwl_output->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); + + xwl_screen_check_resolution_change_emulation(xwl_output->xwl_screen); +} + static void apply_output_change(struct xwl_output *xwl_output) { @@ -613,21 +649,36 @@ xwl_randr_screen_set_size(ScreenPtr pScreen, static Bool xwl_randr_crtc_set(ScreenPtr pScreen, RRCrtcPtr crtc, - RRModePtr mode, + RRModePtr new_mode, int x, int y, Rotation rotation, int numOutputs, RROutputPtr * outputs) { struct xwl_output *xwl_output = crtc->devPrivate; + RRModePtr mode; - if (!mode || (mode->mode.width == xwl_output->width && - mode->mode.height == xwl_output->height)) { - RRCrtcChanged(crtc, TRUE); - return TRUE; + if (new_mode) { + mode = xwl_output_find_mode(xwl_output, + new_mode->mode.width, + new_mode->mode.height); + } else { + mode = xwl_output_find_mode(xwl_output, -1, -1); } + if (!mode) + return FALSE; - return FALSE; + xwl_output_set_emulated_mode(xwl_output, GetCurrentClient(), mode, FALSE); + + /* A real randr implementation would call: + * RRCrtcNotify(xwl_output->randr_crtc, mode, xwl_output->x, xwl_output->y, + * xwl_output->rotation, NULL, 1, &xwl_output->randr_output); + * here to update the mode reported to clients querying the randr settings + * but that influences *all* clients and we do randr mode change emulation + * on a per client basis. So we just return success here. + */ + + return TRUE; } static Bool diff --git a/hw/xwayland/xwayland.c b/hw/xwayland/xwayland.c index f422cfc29..87870a5f1 100644 --- a/hw/xwayland/xwayland.c +++ b/hw/xwayland/xwayland.c @@ -178,6 +178,23 @@ xwl_screen_has_resolution_change_emulation(struct xwl_screen *xwl_screen) return xwl_screen->rootless && xwl_screen_has_viewport_support(xwl_screen); } +/* Return the output @ 0x0, falling back to the first output in the list */ +struct xwl_output * +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) + return xwl_output; + } + + if (xorg_list_is_empty(&xwl_screen->output_list)) + return NULL; + + return xorg_list_first_entry(&xwl_screen->output_list, struct xwl_output, link); +} + static void xwl_window_set_allow_commits(struct xwl_window *xwl_window, Bool allow, const char *debug_msg) @@ -501,6 +518,150 @@ xwl_pixmap_get(PixmapPtr pixmap) return dixLookupPrivate(&pixmap->devPrivates, &xwl_pixmap_private_key); } +Bool +xwl_window_has_viewport_enabled(struct xwl_window *xwl_window) +{ + return (xwl_window->viewport != NULL); +} + +static void +xwl_window_disable_viewport(struct xwl_window *xwl_window) +{ + assert (xwl_window->viewport); + + DebugF("XWAYLAND: disabling viewport\n"); + wp_viewport_destroy(xwl_window->viewport); + xwl_window->viewport = NULL; +} + +static void +xwl_window_enable_viewport(struct xwl_window *xwl_window, + struct xwl_output *xwl_output, + struct xwl_emulated_mode *emulated_mode) +{ + /* If necessary disable old viewport to apply new settings */ + if (xwl_window_has_viewport_enabled(xwl_window)) + xwl_window_disable_viewport(xwl_window); + + DebugF("XWAYLAND: enabling viewport %dx%d -> %dx%d\n", + emulated_mode->width, emulated_mode->height, + xwl_output->width, xwl_output->height); + + xwl_window->viewport = + wp_viewporter_get_viewport(xwl_window->xwl_screen->viewporter, + xwl_window->surface); + + 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)); + 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; +} + +static Bool +xwl_screen_client_is_window_manager(struct xwl_screen *xwl_screen, + ClientPtr client) +{ + WindowPtr root = xwl_screen->screen->root; + OtherClients *others; + + for (others = wOtherClients(root); others; others = others->next) { + if (SameClient(others, client)) { + if (others->mask & (SubstructureRedirectMask | ResizeRedirectMask)) + return TRUE; + } + } + + return FALSE; +} + +static ClientPtr +xwl_window_get_owner(struct xwl_window *xwl_window) +{ + WindowPtr window = xwl_window->window; + ClientPtr client = wClient(window); + + /* If the toplevel window is owned by the window-manager, then the + * actual client toplevel window has been reparented to a window-manager + * decoration window. In that case return the client of the + * first *and only* child of the toplevel (decoration) window. + */ + if (xwl_screen_client_is_window_manager(xwl_window->xwl_screen, client)) { + if (window->firstChild && window->firstChild == window->lastChild) + return wClient(window->firstChild); + else + return NULL; /* Should never happen, skip resolution emulation */ + } + + return client; +} + +static Bool +xwl_window_should_enable_viewport(struct xwl_window *xwl_window, + struct xwl_output **xwl_output_ret, + struct xwl_emulated_mode **emulated_mode_ret) +{ + struct xwl_screen *xwl_screen = xwl_window->xwl_screen; + struct xwl_emulated_mode *emulated_mode; + struct xwl_output *xwl_output; + ClientPtr owner; + + if (!xwl_screen_has_resolution_change_emulation(xwl_screen)) + return FALSE; + + owner = xwl_window_get_owner(xwl_window); + if (!owner) + return FALSE; + + /* 1. Test if the window matches the emulated mode on one of the outputs + * 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) { + emulated_mode = xwl_output_get_emulated_mode_for_client(xwl_output, owner); + if (!emulated_mode) + continue; + + if (xwl_window->x == xwl_output->x && + xwl_window->y == xwl_output->y && + xwl_window->width == emulated_mode->width && + xwl_window->height == emulated_mode->height) { + + *emulated_mode_ret = emulated_mode; + *xwl_output_ret = xwl_output; + return TRUE; + } + } + + return FALSE; +} + +static void +xwl_window_check_resolution_change_emulation(struct xwl_window *xwl_window) +{ + struct xwl_emulated_mode *emulated_mode; + 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); + else if (xwl_window_has_viewport_enabled(xwl_window)) + xwl_window_disable_viewport(xwl_window); +} + +void +xwl_screen_check_resolution_change_emulation(struct xwl_screen *xwl_screen) +{ + struct xwl_window *xwl_window; + + xorg_list_for_each_entry(xwl_window, &xwl_screen->window_list, link_window) + xwl_window_check_resolution_change_emulation(xwl_window); +} + static void xwl_window_init_allow_commits(struct xwl_window *xwl_window) { @@ -571,6 +732,8 @@ ensure_surface_for_window(WindowPtr window) xwl_window->xwl_screen = xwl_screen; xwl_window->window = window; + xwl_window->width = window->drawable.width; + xwl_window->height = window->drawable.height; xwl_window->surface = wl_compositor_create_surface(xwl_screen->compositor); if (xwl_window->surface == NULL) { ErrorF("wl_display_create_surface failed\n"); @@ -612,6 +775,7 @@ ensure_surface_for_window(WindowPtr window) dixSetPrivate(&window->devPrivates, &xwl_window_private_key, xwl_window); xorg_list_init(&xwl_window->link_damage); + xorg_list_add(&xwl_window->link_window, &xwl_screen->window_list); #ifdef GLAMOR_HAS_GBM xorg_list_init(&xwl_window->frame_callback_list); @@ -705,8 +869,12 @@ xwl_unrealize_window(WindowPtr window) if (!xwl_window) return ret; + if (xwl_window_has_viewport_enabled(xwl_window)) + xwl_window_disable_viewport(xwl_window); + wl_surface_destroy(xwl_window->surface); xorg_list_del(&xwl_window->link_damage); + xorg_list_del(&xwl_window->link_window); unregister_damage(window); if (xwl_window->frame_callback) @@ -756,6 +924,33 @@ xwl_set_window_pixmap(WindowPtr window, ensure_surface_for_window(window); } +static void +xwl_resize_window(WindowPtr window, + int x, int y, + unsigned int width, unsigned int height, + WindowPtr sib) +{ + ScreenPtr screen = window->drawable.pScreen; + struct xwl_screen *xwl_screen; + struct xwl_window *xwl_window; + + xwl_screen = xwl_screen_get(screen); + xwl_window = xwl_window_get(window); + + screen->ResizeWindow = xwl_screen->ResizeWindow; + (*screen->ResizeWindow) (window, x, y, width, height, sib); + xwl_screen->ResizeWindow = screen->ResizeWindow; + screen->ResizeWindow = xwl_resize_window; + + if (xwl_window) { + xwl_window->x = x; + xwl_window->y = y; + xwl_window->width = width; + xwl_window->height = height; + xwl_window_check_resolution_change_emulation(xwl_window); + } +} + static void frame_callback(void *data, struct wl_callback *callback, @@ -1233,6 +1428,7 @@ xwl_screen_init(ScreenPtr pScreen, int argc, char **argv) xorg_list_init(&xwl_screen->output_list); xorg_list_init(&xwl_screen->seat_list); xorg_list_init(&xwl_screen->damage_window_list); + xorg_list_init(&xwl_screen->window_list); xwl_screen->depth = 24; if (!monitorResolution) @@ -1332,6 +1528,9 @@ xwl_screen_init(ScreenPtr pScreen, int argc, char **argv) xwl_screen->CloseScreen = pScreen->CloseScreen; pScreen->CloseScreen = xwl_close_screen; + xwl_screen->ResizeWindow = pScreen->ResizeWindow; + pScreen->ResizeWindow = xwl_resize_window; + if (xwl_screen->rootless) { xwl_screen->SetWindowPixmap = pScreen->SetWindowPixmap; pScreen->SetWindowPixmap = xwl_set_window_pixmap; diff --git a/hw/xwayland/xwayland.h b/hw/xwayland/xwayland.h index c886d77e9..36c4c4c8b 100644 --- a/hw/xwayland/xwayland.h +++ b/hw/xwayland/xwayland.h @@ -135,10 +135,12 @@ struct xwl_screen { DestroyWindowProcPtr DestroyWindow; XYToWindowProcPtr XYToWindow; SetWindowPixmapProcPtr SetWindowPixmap; + ResizeWindowProcPtr ResizeWindow; struct xorg_list output_list; struct xorg_list seat_list; struct xorg_list damage_window_list; + struct xorg_list window_list; int wayland_fd; struct wl_display *display; @@ -179,9 +181,13 @@ struct xwl_screen { struct xwl_window { struct xwl_screen *xwl_screen; struct wl_surface *surface; + struct wp_viewport *viewport; + int32_t x, y, width, height; + float scale_x, scale_y; struct wl_shell_surface *shell_surface; WindowPtr window; struct xorg_list link_damage; + struct xorg_list link_window; struct wl_callback *frame_callback; Bool allow_commits; #ifdef GLAMOR_HAS_GBM @@ -411,6 +417,9 @@ Bool xwl_screen_init_cursor(struct xwl_screen *xwl_screen); struct xwl_screen *xwl_screen_get(ScreenPtr screen); Bool xwl_screen_has_resolution_change_emulation(struct xwl_screen *xwl_screen); +struct xwl_output *xwl_screen_get_first_output(struct xwl_screen *xwl_screen); +void xwl_screen_check_resolution_change_emulation(struct xwl_screen *xwl_screen); +Bool xwl_window_has_viewport_enabled(struct xwl_window *xwl_window); void xwl_tablet_tool_set_cursor(struct xwl_tablet_tool *tool); void xwl_seat_set_cursor(struct xwl_seat *xwl_seat); @@ -444,6 +453,12 @@ 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); +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, + ClientPtr client, RRModePtr mode, + Bool from_vidmode); + RRModePtr xwayland_cvt(int HDisplay, int VDisplay, float VRefresh, Bool Reduced, Bool Interlaced); -- 2.28.0
Locations
Projects
Search
Status Monitor
Help
Open Build Service
OBS Manuals
API Documentation
OBS Portal
Reporting a Bug
Contact
Mailing List
Forums
Chat (IRC)
Twitter
Open Build Service (OBS)
is an
openSUSE project
.
浙ICP备2022010568号-2