Skip to content

Instantly share code, notes, and snippets.

@foxyfocus
Created May 1, 2020 21:28
Show Gist options
  • Save foxyfocus/50f9c260821f11b8b0f2887290ea14ee to your computer and use it in GitHub Desktop.
Save foxyfocus/50f9c260821f11b8b0f2887290ea14ee to your computer and use it in GitHub Desktop.
PKGBUILD for modified wlroots for Xwayland HIDPI support
# Maintainer: Adrian Perez de Castro <aperez@igalia.com>
pkgname=wlroots-git
pkgver=0.10.0.r81.gf81aa6a1
pkgrel=1
license=(custom:MIT)
pkgdesc='Modular Wayland compositor library'
url=https://github.com/swaywm/wlroots
arch=(x86_64)
provides=("wlroots=${pkgver%%.r*}")
conflicts=(wlroots)
options=(debug)
depends=(libcap systemd wayland opengl-driver libxcb xcb-util-errors
xcb-util-wm pixman libinput libxkbcommon)
makedepends=(meson ninja git wayland-protocols xorgproto)
source=("${pkgname}::git+${url}")
sha512sums=('SKIP')
pkgver () {
cd "${pkgname}"
(
set -o pipefail
git describe --long 2>/dev/null | sed 's/\([^-]*-g\)/r\1/;s/-/./g' ||
printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
)
}
prepare() {
cd "${pkgname}"
patch -Np1 -i ../../scale.patch
}
build () {
cd "${pkgname}"
rm -rf build
meson build \
--prefix /usr \
--buildtype debug \
-Dlibcap=enabled \
-Dlogind=enabled \
-Dlogind-provider=systemd \
-Dxcb-errors=enabled \
-Dxcb-icccm=enabled \
-Dxwayland=enabled \
-Dx11-backend=enabled \
-Dexamples=true
ninja -C build
}
package () {
cd "${pkgname}"
DESTDIR="${pkgdir}" ninja -C build install
install -Dm644 LICENSE "${pkgdir}/usr/share/licenses/${pkgname}/LICENSE"
}
From 182d8c449bd38d66230717d8e8fef5abf80332aa Mon Sep 17 00:00:00 2001
From: Dario Nieuwenhuis <dirbaio@dirbaio.net>
Date: Fri, 31 Jan 2020 22:57:48 +0100
Subject: [PATCH 1/2] Xwayland HiDPI
This does the necessary changes to support HiDPI in xwayland
applications, with the following xwayland patch:
https://gitlab.freedesktop.org/xorg/xserver/merge_requests/111
---
include/wlr/xwayland.h | 4 ++++
xwayland/xwayland.c | 8 +++++++-
xwayland/xwm.c | 42 +++++++++++++++++++++++++++++++-----------
3 files changed, 42 insertions(+), 12 deletions(-)
diff --git a/include/wlr/xwayland.h b/include/wlr/xwayland.h
index 8646e7acb..d1b705f62 100644
--- a/include/wlr/xwayland.h
+++ b/include/wlr/xwayland.h
@@ -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;
@@ -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);
diff --git a/xwayland/xwayland.c b/xwayland/xwayland.c
index 77698f449..3c90aff27 100644
--- a/xwayland/xwayland.c
+++ b/xwayland/xwayland.c
@@ -66,7 +66,7 @@ _Noreturn static void exec_xwayland(struct wlr_xwayland *wlr_xwayland) {
char *argv[] = {
"Xwayland", NULL /* display, e.g. :1 */,
- "-rootless", "-terminate",
+ "-rootless", "-terminate", "-max-factor-rescale",
"-listen", NULL /* x_fd[0] */,
"-listen", NULL /* x_fd[1] */,
"-wm", NULL /* wm_fd[1] */,
@@ -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);
@@ -436,6 +438,10 @@ 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;
+}
+
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) {
diff --git a/xwayland/xwm.c b/xwayland/xwm.c
index b19efbcf1..8c8bc696d 100644
--- a/xwayland/xwm.c
+++ b/xwayland/xwm.c
@@ -16,6 +16,15 @@
#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;
+}
+
const char *atom_map[ATOM_LAST] = {
[WL_SURFACE_ID] = "WL_SURFACE_ID",
[WM_DELETE_WINDOW] = "WM_DELETE_WINDOW",
@@ -834,8 +843,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,
@@ -866,10 +880,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),
+ .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,
@@ -885,10 +899,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;
@@ -1431,7 +1445,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);
}
From 9fcf9dd38b9658ae029d2baa0fb42fcb65039b97 Mon Sep 17 00:00:00 2001
From: Dario Nieuwenhuis <dirbaio@dirbaio.net>
Date: Tue, 10 Mar 2020 23:21:11 +0100
Subject: [PATCH 2/2] Make xwayland scale factor configurable on the fly via X
extension and xsettings.
---
include/xwayland/xwm.h | 9 +++
xwayland/xwayland.c | 3 +
xwayland/xwm.c | 122 +++++++++++++++++++++++++++++++++++++++++
3 files changed, 134 insertions(+)
diff --git a/include/xwayland/xwm.h b/include/xwayland/xwm.h
index 351fce441..2c3ba1b68 100644
--- a/include/xwayland/xwm.h
+++ b/include/xwayland/xwm.h
@@ -80,6 +80,9 @@ enum atom_name {
DND_ACTION_ASK,
DND_ACTION_PRIVATE,
NET_CLIENT_LIST,
+ XSETTINGS_SETTINGS,
+ XSETTINGS_S0,
+ MANAGER,
ATOM_LAST // keep last
};
@@ -106,6 +109,9 @@ struct wlr_xwm {
xcb_render_pictformat_t render_format_id;
xcb_cursor_t cursor;
+ xcb_window_t xsettings_window;
+ int32_t xsettings_serial;
+
xcb_window_t selection_window;
struct wlr_xwm_selection clipboard_selection;
struct wlr_xwm_selection primary_selection;
@@ -122,6 +128,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 +162,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 3c90aff27..10c7c17f0 100644
--- a/xwayland/xwayland.c
+++ b/xwayland/xwayland.c
@@ -440,6 +440,9 @@ struct wlr_xwayland *wlr_xwayland_create(struct wl_display *wl_display,
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..3761ba83c 100644
--- a/xwayland/xwm.c
+++ b/xwayland/xwm.c
@@ -13,6 +13,7 @@
#include <xcb/composite.h>
#include <xcb/render.h>
#include <xcb/xfixes.h>
+#include <xcb/xcbext.h>
#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",
@@ -87,6 +92,9 @@ const char *atom_map[ATOM_LAST] = {
[DND_ACTION_ASK] = "XdndActionAsk",
[DND_ACTION_PRIVATE] = "XdndActionPrivate",
[NET_CLIENT_LIST] = "_NET_CLIENT_LIST",
+ [XSETTINGS_SETTINGS] = "_XSETTINGS_SETTINGS",
+ [XSETTINGS_S0] = "_XSETTINGS_S0",
+ [MANAGER] = "MANAGER",
};
static const struct wlr_surface_role xwayland_surface_role;
@@ -1517,6 +1525,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 +1557,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 =
@@ -1613,6 +1624,75 @@ static void xwm_create_wm_window(struct wlr_xwm *xwm) {
XCB_CURRENT_TIME);
}
+static void xwm_xsettings_set(struct wlr_xwm *xwm) {
+ uint8_t data[] = {
+ XCB_IMAGE_ORDER_LSB_FIRST,
+ 0, 0, 0,
+ xwm->xsettings_serial, 0, 0, 0, // serial
+ 1, 0, 0, 0, // setting count
+
+ 0, // type: XSettingsTypeInteger
+ 0, // unused
+ 23, 0, // name len
+ 71, 100, 107, 47, 87, 105, 110, 100, 111, 119, 83, 99, 97, 108, 105, 110, 103, 70, 97, 99, 116, 111, 114, // name
+ 0, // name padding (round up to multiple of 4)
+ xwm->xsettings_serial, 0, 0, 0, // serial
+ xwm->xwayland->scale, 0, 0, 0, // value
+ };
+
+ xcb_change_property(xwm->xcb_conn,
+ XCB_PROP_MODE_REPLACE,
+ xwm->xsettings_window,
+ xwm->atoms[XSETTINGS_SETTINGS],
+ xwm->atoms[XSETTINGS_SETTINGS],
+ 8,
+ sizeof(data),
+ data
+ );
+
+ wlr_log(WLR_ERROR, "xwm_xsettings_set window %x scale %d serial %d", xwm->window, xwm->xwayland->scale, xwm->xsettings_serial);
+}
+
+static void xwm_xsettings_init(struct wlr_xwm *xwm) {
+ wlr_log(WLR_ERROR, "xwm_xsettings_init");
+
+ xwm->xsettings_serial = 1;
+ xwm->xsettings_window = xcb_generate_id(xwm->xcb_conn);
+
+ xcb_create_window(xwm->xcb_conn,
+ XCB_COPY_FROM_PARENT,
+ xwm->xsettings_window,
+ xwm->screen->root,
+ 0, 0,
+ 10, 10,
+ 0,
+ XCB_WINDOW_CLASS_INPUT_OUTPUT,
+ xwm->screen->root_visual,
+ 0, NULL);
+
+ xwm_xsettings_set(xwm);
+ xcb_set_selection_owner(xwm->xcb_conn, xwm->xsettings_window, xwm->atoms[XSETTINGS_S0], XCB_CURRENT_TIME);
+
+ xcb_client_message_event_t event = {
+ .response_type = XCB_CLIENT_MESSAGE,
+ .format = 32,
+ .sequence = 0,
+ .window = xwm->screen->root,
+ .type = xwm->atoms[MANAGER],
+ .data = {
+ .data32 = {
+ 0, //timestamp
+ xwm->atoms[XSETTINGS_S0],
+ xwm->xsettings_window,
+ 0,
+ }
+ },
+ };
+
+ xcb_send_event(xwm->xcb_conn, false, xwm->screen->root, XCB_EVENT_MASK_STRUCTURE_NOTIFY, (char*)&event);
+ xcb_flush(xwm->xcb_conn);
+}
+
// TODO use me to support 32 bit color somehow
static void xwm_get_visual_and_colormap(struct wlr_xwm *xwm) {
xcb_depth_iterator_t d_iter;
@@ -1725,6 +1805,7 @@ struct wlr_xwm *xwm_create(struct wlr_xwayland *wlr_xwayland) {
wl_list_init(&xwm->surfaces);
wl_list_init(&xwm->unpaired_surfaces);
xwm->ping_timeout = 10000;
+ xwm->xsettings_serial = 1;
xwm->xcb_conn = xcb_connect_to_fd(wlr_xwayland->wm_fd[0], NULL);
@@ -1809,6 +1890,8 @@ struct wlr_xwm *xwm_create(struct wlr_xwayland *wlr_xwayland) {
xwm_create_wm_window(xwm);
+ xwm_xsettings_init(xwm);
+
xcb_flush(xwm->xcb_conn);
return xwm;
@@ -1878,3 +1961,42 @@ 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) {
+ xwm->xsettings_serial++;
+ xwm_xsettings_set(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);
+}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment