diff --git a/include/xwayland/xwm.h b/include/xwayland/xwm.h index 351fce441..25db63c1e 100644 --- a/include/xwayland/xwm.h +++ b/include/xwayland/xwm.h @@ -122,6 +122,7 @@ struct wlr_xwm { struct wlr_xwayland_surface *drag_focus; const xcb_query_extension_reply_t *xfixes; + const xcb_query_extension_reply_t *xwayland_ext; #if WLR_HAS_XCB_ERRORS xcb_errors_context_t *errors_context; #endif @@ -155,4 +156,6 @@ char *xwm_get_atom_name(struct wlr_xwm *xwm, xcb_atom_t atom); bool xwm_atoms_contains(struct wlr_xwm *xwm, xcb_atom_t *atoms, size_t num_atoms, enum atom_name needle); +void xwm_scale_changed(struct wlr_xwm *xwm); + #endif diff --git a/xwayland/xwayland.c b/xwayland/xwayland.c index 7ede1c1c5..062079902 100644 --- a/xwayland/xwayland.c +++ b/xwayland/xwayland.c @@ -440,6 +440,9 @@ error_alloc: void wlr_xwayland_set_scale(struct wlr_xwayland *wlr_xwayland, int32_t scale) { wlr_xwayland->scale = scale; + if (wlr_xwayland->xwm != NULL) { + xwm_scale_changed(wlr_xwayland->xwm); + } } void wlr_xwayland_set_cursor(struct wlr_xwayland *wlr_xwayland, diff --git a/xwayland/xwm.c b/xwayland/xwm.c index 8c8bc696d..020460f1a 100644 --- a/xwayland/xwm.c +++ b/xwayland/xwm.c @@ -13,6 +13,7 @@ #include #include #include +#include #include "util/signal.h" #include "xwayland/xwm.h" @@ -25,6 +26,10 @@ static int32_t unscale(struct wlr_xwm *xwm, int32_t val) { return (val + xwm->xwayland->scale/2) / xwm->xwayland->scale; } +static xcb_extension_t xwayland_ext_id = { + .name = "XWAYLAND", +}; + const char *atom_map[ATOM_LAST] = { [WL_SURFACE_ID] = "WL_SURFACE_ID", [WM_DELETE_WINDOW] = "WM_DELETE_WINDOW", @@ -1517,6 +1522,7 @@ void xwm_destroy(struct wlr_xwm *xwm) { static void xwm_get_resources(struct wlr_xwm *xwm) { xcb_prefetch_extension_data(xwm->xcb_conn, &xcb_xfixes_id); xcb_prefetch_extension_data(xwm->xcb_conn, &xcb_composite_id); + xcb_prefetch_extension_data(xwm->xcb_conn, &xwayland_ext_id); // TODO what if extension is not present?? size_t i; xcb_intern_atom_cookie_t cookies[ATOM_LAST]; @@ -1548,6 +1554,8 @@ static void xwm_get_resources(struct wlr_xwm *xwm) { wlr_log(WLR_DEBUG, "xfixes not available"); } + xwm->xwayland_ext = xcb_get_extension_data(xwm->xcb_conn, &xwayland_ext_id); + xcb_xfixes_query_version_cookie_t xfixes_cookie; xcb_xfixes_query_version_reply_t *xfixes_reply; xfixes_cookie = @@ -1878,3 +1886,39 @@ bool wlr_xwayland_or_surface_wants_focus( return ret; } + + +typedef struct { + uint8_t major_opcode; + uint8_t minor_opcode; + uint16_t length; + uint16_t screen; + uint16_t scale; +} xwayland_ext_set_scale_request_t; + +void xwm_scale_changed(struct wlr_xwm *xwm) { + xcb_protocol_request_t req = { + .count = 1, + .ext = &xwayland_ext_id, + .opcode = 1, + .isvoid = false, + }; + + xwayland_ext_set_scale_request_t xcb_out = { + .screen = 0, + .scale = xwm->xwayland->scale, + }; + + struct iovec xcb_parts[3]; + xcb_parts[2].iov_base = (char *) &xcb_out; + xcb_parts[2].iov_len = sizeof(xcb_out); + xcb_send_request(xwm->xcb_conn, 0, xcb_parts+2, &req); + + // Reconfigure all surfaces with the new scale. + struct wlr_xwayland_surface *surface; + wl_list_for_each(surface, &xwm->surfaces, link) { + wlr_xwayland_surface_configure(surface, surface->x, surface->y, surface->width, surface->height); + } + + xcb_flush(xwm->xcb_conn); +}