Skip to content
This repository has been archived by the owner on Nov 1, 2021. It is now read-only.

xwayland: hidpi support #2064

Draft
wants to merge 2 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions include/wlr/xwayland.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ struct wlr_xwayland {

time_t server_start;

int32_t scale;

/* Anything above display is reset on Xwayland restart, rest is conserved */

int display;
Expand Down Expand Up @@ -205,6 +207,8 @@ struct wlr_xwayland *wlr_xwayland_create(struct wl_display *wl_display,

void wlr_xwayland_destroy(struct wlr_xwayland *wlr_xwayland);

void wlr_xwayland_set_scale(struct wlr_xwayland *wlr_xwayland, int32_t scale);

void wlr_xwayland_set_cursor(struct wlr_xwayland *wlr_xwayland,
uint8_t *pixels, uint32_t stride, uint32_t width, uint32_t height,
int32_t hotspot_x, int32_t hotspot_y);
Expand Down
3 changes: 3 additions & 0 deletions include/xwayland/xwm.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
9 changes: 9 additions & 0 deletions xwayland/xwayland.c
Original file line number Diff line number Diff line change
Expand Up @@ -409,6 +409,8 @@ struct wlr_xwayland *wlr_xwayland_create(struct wl_display *wl_display,
wlr_xwayland->wl_fd[0] = wlr_xwayland->wl_fd[1] = -1;
wlr_xwayland->wm_fd[0] = wlr_xwayland->wm_fd[1] = -1;

wlr_xwayland->scale = 1;

wl_signal_init(&wlr_xwayland->events.new_surface);
wl_signal_init(&wlr_xwayland->events.ready);

Expand Down Expand Up @@ -436,6 +438,13 @@ struct wlr_xwayland *wlr_xwayland_create(struct wl_display *wl_display,
return NULL;
}

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,
uint8_t *pixels, uint32_t stride, uint32_t width, uint32_t height,
int32_t hotspot_x, int32_t hotspot_y) {
Expand Down
86 changes: 75 additions & 11 deletions xwayland/xwm.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,23 @@
#include <xcb/composite.h>
#include <xcb/render.h>
#include <xcb/xfixes.h>
#include <xcb/xcbext.h>
#include "util/signal.h"
#include "xwayland/xwm.h"


static int32_t scale(struct wlr_xwm *xwm, int32_t val) {
return val * xwm->xwayland->scale;
}

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",
Expand Down Expand Up @@ -834,8 +848,13 @@ static void xwm_handle_create_notify(struct wlr_xwm *xwm,
return;
}

xwayland_surface_create(xwm, ev->window, ev->x, ev->y,
ev->width, ev->height, ev->override_redirect);
xwayland_surface_create(xwm, ev->window,
unscale(xwm, ev->x),
unscale(xwm, ev->y),
unscale(xwm, ev->width),
unscale(xwm, ev->height),
ev->override_redirect
);
}

static void xwm_handle_destroy_notify(struct wlr_xwm *xwm,
Expand Down Expand Up @@ -866,10 +885,10 @@ static void xwm_handle_configure_request(struct wlr_xwm *xwm,

struct wlr_xwayland_surface_configure_event wlr_event = {
.surface = surface,
.x = mask & XCB_CONFIG_WINDOW_X ? ev->x : surface->x,
.y = mask & XCB_CONFIG_WINDOW_Y ? ev->y : surface->y,
.width = mask & XCB_CONFIG_WINDOW_WIDTH ? ev->width : surface->width,
.height = mask & XCB_CONFIG_WINDOW_HEIGHT ? ev->height : surface->height,
.x = unscale(xwm, mask & XCB_CONFIG_WINDOW_X ? ev->x : surface->x),
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have you verified whether surface->whatever are in the scaled units here? I'm not sure about this, but it's probably correct.

.y = unscale(xwm, mask & XCB_CONFIG_WINDOW_Y ? ev->y : surface->y),
.width = unscale(xwm, mask & XCB_CONFIG_WINDOW_WIDTH ? ev->width : surface->width),
.height = unscale(xwm, mask & XCB_CONFIG_WINDOW_HEIGHT ? ev->height : surface->height),
.mask = mask,
};
wlr_log(WLR_DEBUG, "XCB_CONFIGURE_REQUEST (%u) [%ux%u+%d,%d]", ev->window,
Expand All @@ -885,10 +904,10 @@ static void xwm_handle_configure_notify(struct wlr_xwm *xwm,
return;
}

xsurface->x = ev->x;
xsurface->y = ev->y;
xsurface->width = ev->width;
xsurface->height = ev->height;
xsurface->x = unscale(xwm, ev->x);
xsurface->y = unscale(xwm, ev->y);
xsurface->width = unscale(xwm, ev->width);
xsurface->height = unscale(xwm, ev->height);

if (xsurface->override_redirect != ev->override_redirect) {
xsurface->override_redirect = ev->override_redirect;
Expand Down Expand Up @@ -1431,7 +1450,13 @@ void wlr_xwayland_surface_configure(struct wlr_xwayland_surface *xsurface,
uint32_t mask = XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y |
XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT |
XCB_CONFIG_WINDOW_BORDER_WIDTH;
uint32_t values[] = {x, y, width, height, 0};
uint32_t values[] = {
scale(xsurface->xwm, x),
scale(xsurface->xwm, y),
scale(xsurface->xwm, width),
scale(xsurface->xwm, height),
0,
};
xcb_configure_window(xwm->xcb_conn, xsurface->window_id, mask, values);
xcb_flush(xwm->xcb_conn);
}
Expand Down Expand Up @@ -1497,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];
Expand Down Expand Up @@ -1528,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 =
Expand Down Expand Up @@ -1858,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);
}