diff --git a/hw/xwayland/xwayland-output.c b/hw/xwayland/xwayland-output.c index 8df8330eb..42b96e821 100644 --- a/hw/xwayland/xwayland-output.c +++ b/hw/xwayland/xwayland-output.c @@ -29,6 +29,7 @@ #include "xwayland.h" #include +#include #define DEFAULT_DPI 96 #define ALL_ROTATIONS (RR_Rotate_0 | \ @@ -428,6 +429,80 @@ xwl_output_find_mode(struct xwl_output *xwl_output, return NULL; } +struct xwl_output_randr_emu_prop { + Atom atom; + uint32_t rects[XWL_CLIENT_MAX_EMULATED_MODES][4]; + int rect_count; +}; + +static void +xwl_output_randr_emu_prop(struct xwl_screen *xwl_screen, ClientPtr client, + struct xwl_output_randr_emu_prop *prop) +{ + static const char atom_name[] = "_XWAYLAND_RANDR_EMU_MONITOR_RECTS"; + struct xwl_emulated_mode *emulated_mode; + struct xwl_output *xwl_output; + int index = 0; + + prop->atom = MakeAtom(atom_name, strlen(atom_name), TRUE); + + xorg_list_for_each_entry(xwl_output, &xwl_screen->output_list, link) { + emulated_mode = xwl_output_get_emulated_mode_for_client(xwl_output, client); + if (!emulated_mode) + continue; + + prop->rects[index][0] = xwl_output->x; + prop->rects[index][1] = xwl_output->y; + prop->rects[index][2] = emulated_mode->width; + prop->rects[index][3] = emulated_mode->height; + index++; + } + + prop->rect_count = index; +} + +static void +xwl_output_set_randr_emu_prop(WindowPtr window, + struct xwl_output_randr_emu_prop *prop) +{ + if (!xwl_window_is_toplevel(window)) + return; + + if (prop->rect_count) { + dixChangeWindowProperty(serverClient, window, prop->atom, + XA_CARDINAL, 32, PropModeReplace, + prop->rect_count * 4, prop->rects, TRUE); + } else { + DeleteProperty(serverClient, window, prop->atom); + } +} + +static void +xwl_output_set_randr_emu_prop_callback(void *resource, XID id, void *user_data) +{ + xwl_output_set_randr_emu_prop(resource, user_data); +} + +static void +xwl_output_set_randr_emu_props(struct xwl_screen *xwl_screen, ClientPtr client) +{ + struct xwl_output_randr_emu_prop prop = {}; + + xwl_output_randr_emu_prop(xwl_screen, client, &prop); + FindClientResourcesByType(client, RT_WINDOW, + xwl_output_set_randr_emu_prop_callback, &prop); +} + +void +xwl_output_set_window_randr_emu_props(struct xwl_screen *xwl_screen, + WindowPtr window) +{ + struct xwl_output_randr_emu_prop prop = {}; + + xwl_output_randr_emu_prop(xwl_screen, wClient(window), &prop); + xwl_output_set_randr_emu_prop(window, &prop); +} + void xwl_output_set_emulated_mode(struct xwl_output *xwl_output, ClientPtr client, RRModePtr mode, Bool from_vidmode) @@ -442,6 +517,8 @@ xwl_output_set_emulated_mode(struct xwl_output *xwl_output, ClientPtr client, xwl_output_add_emulated_mode_for_client(xwl_output, client, mode, from_vidmode); xwl_screen_check_resolution_change_emulation(xwl_output->xwl_screen); + + xwl_output_set_randr_emu_props(xwl_output->xwl_screen, client); } static void diff --git a/hw/xwayland/xwayland.c b/hw/xwayland/xwayland.c index 6c4bbb2c7..97afce0b8 100644 --- a/hw/xwayland/xwayland.c +++ b/hw/xwayland/xwayland.c @@ -720,6 +720,27 @@ xwl_screen_check_resolution_change_emulation(struct xwl_screen *xwl_screen) xwl_window_check_resolution_change_emulation(xwl_window); } +/* This checks if the passed in Window is a toplevel client window, note this + * returns false for window-manager decoration windows and returns true for + * the actual client top-level window even if it has been reparented to + * a window-manager decoration window. + */ +Bool +xwl_window_is_toplevel(WindowPtr window) +{ + struct xwl_screen *xwl_screen = xwl_screen_get(window->drawable.pScreen); + + if (xwl_screen_client_is_window_manager(xwl_screen, wClient(window))) + return FALSE; + + /* CSD and override-redirect toplevel windows */ + if (window_get_damage(window)) + return TRUE; + + /* Normal toplevel client windows, reparented to decoration window */ + return (window->parent && window_get_damage(window->parent)); +} + static void xwl_window_init_allow_commits(struct xwl_window *xwl_window) { @@ -881,6 +902,8 @@ xwl_realize_window(WindowPtr window) return FALSE; } + xwl_output_set_window_randr_emu_props(xwl_screen, window); + return ensure_surface_for_window(window); } diff --git a/hw/xwayland/xwayland.h b/hw/xwayland/xwayland.h index 6dbb108f1..74556bb34 100644 --- a/hw/xwayland/xwayland.h +++ b/hw/xwayland/xwayland.h @@ -414,6 +414,7 @@ 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); +Bool xwl_window_is_toplevel(WindowPtr window); void xwl_tablet_tool_set_cursor(struct xwl_tablet_tool *tool); void xwl_seat_set_cursor(struct xwl_seat *xwl_seat); @@ -452,6 +453,8 @@ RRModePtr xwl_output_find_mode(struct xwl_output *xwl_output, void xwl_output_set_emulated_mode(struct xwl_output *xwl_output, ClientPtr client, RRModePtr mode, Bool from_vidmode); +void xwl_output_set_window_randr_emu_props(struct xwl_screen *xwl_screen, + WindowPtr window); RRModePtr xwayland_cvt(int HDisplay, int VDisplay, float VRefresh, Bool Reduced, Bool Interlaced);