From 4ff46e6cf9463e594605928feeb7c55cf323b5e7 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Tue, 18 Oct 2022 13:09:17 +0200 Subject: [PATCH] xwayland/xwm: add support for xwayland-shell-v1 --- include/wlr/xwayland/xwayland.h | 3 ++ include/xwayland/xwm.h | 2 ++ xwayland/xwayland.c | 19 ++++++++++++ xwayland/xwm.c | 54 ++++++++++++++++++++++++++++++++- 4 files changed, 77 insertions(+), 1 deletion(-) diff --git a/include/wlr/xwayland/xwayland.h b/include/wlr/xwayland/xwayland.h index 372ab9a88..2a68315c2 100644 --- a/include/wlr/xwayland/xwayland.h +++ b/include/wlr/xwayland/xwayland.h @@ -21,6 +21,7 @@ struct wlr_drag; struct wlr_xwayland { struct wlr_xwayland_server *server; struct wlr_xwm *xwm; + struct wlr_xwayland_shell_v1 *shell_v1; struct wlr_xwayland_cursor *cursor; const char *display_name; @@ -42,6 +43,7 @@ struct wlr_xwayland { */ int (*user_event_handler)(struct wlr_xwm *xwm, xcb_generic_event_t *event); + struct wl_listener server_start; struct wl_listener server_ready; struct wl_listener server_destroy; struct wl_listener seat_destroy; @@ -80,6 +82,7 @@ struct wlr_xwayland_surface { xcb_window_t window_id; struct wlr_xwm *xwm; uint32_t surface_id; + uint64_t serial; struct wl_list link; struct wl_list stack_link; diff --git a/include/xwayland/xwm.h b/include/xwayland/xwm.h index 41e35ef39..391e09ab1 100644 --- a/include/xwayland/xwm.h +++ b/include/xwayland/xwm.h @@ -17,6 +17,7 @@ enum atom_name { WL_SURFACE_ID, + WL_SURFACE_SERIAL, WM_DELETE_WINDOW, WM_PROTOCOLS, WM_HINTS, @@ -130,6 +131,7 @@ struct wlr_xwm { struct wl_listener compositor_new_surface; struct wl_listener compositor_destroy; + struct wl_listener shell_v1_new_surface; struct wl_listener seat_set_selection; struct wl_listener seat_set_primary_selection; struct wl_listener seat_start_drag; diff --git a/xwayland/xwayland.c b/xwayland/xwayland.c index 1fde77003..abaebd0de 100644 --- a/xwayland/xwayland.c +++ b/xwayland/xwayland.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include "sockets.h" #include "xwayland/xwm.h" @@ -33,6 +34,12 @@ static void handle_server_destroy(struct wl_listener *listener, void *data) { wlr_xwayland_destroy(xwayland); } +static void handle_server_start(struct wl_listener *listener, void *data) { + struct wlr_xwayland *xwayland = + wl_container_of(listener, xwayland, server_start); + wlr_xwayland_shell_v1_set_client(xwayland->shell_v1, xwayland->server->client); +} + static void handle_server_ready(struct wl_listener *listener, void *data) { struct wlr_xwayland *xwayland = wl_container_of(listener, xwayland, server_ready); @@ -62,11 +69,13 @@ void wlr_xwayland_destroy(struct wlr_xwayland *xwayland) { } wl_list_remove(&xwayland->server_destroy.link); + wl_list_remove(&xwayland->server_start.link); wl_list_remove(&xwayland->server_ready.link); free(xwayland->cursor); wlr_xwayland_set_seat(xwayland, NULL); wlr_xwayland_server_destroy(xwayland->server); + wlr_xwayland_shell_v1_destroy(xwayland->shell_v1); free(xwayland); } @@ -84,6 +93,12 @@ struct wlr_xwayland *wlr_xwayland_create(struct wl_display *wl_display, wl_signal_init(&xwayland->events.ready); wl_signal_init(&xwayland->events.remove_startup_info); + xwayland->shell_v1 = wlr_xwayland_shell_v1_create(wl_display, 1); + if (xwayland->shell_v1 == NULL) { + free(xwayland); + return NULL; + } + struct wlr_xwayland_server_options options = { .lazy = lazy, .enable_wm = true, @@ -93,6 +108,7 @@ struct wlr_xwayland *wlr_xwayland_create(struct wl_display *wl_display, }; xwayland->server = wlr_xwayland_server_create(wl_display, &options); if (xwayland->server == NULL) { + wlr_xwayland_shell_v1_destroy(xwayland->shell_v1); free(xwayland); return NULL; } @@ -102,6 +118,9 @@ struct wlr_xwayland *wlr_xwayland_create(struct wl_display *wl_display, xwayland->server_destroy.notify = handle_server_destroy; wl_signal_add(&xwayland->server->events.destroy, &xwayland->server_destroy); + xwayland->server_start.notify = handle_server_start; + wl_signal_add(&xwayland->server->events.start, &xwayland->server_start); + xwayland->server_ready.notify = handle_server_ready; wl_signal_add(&xwayland->server->events.ready, &xwayland->server_ready); diff --git a/xwayland/xwm.c b/xwayland/xwm.c index 3a3d35f22..cb8acd5d7 100644 --- a/xwayland/xwm.c +++ b/xwayland/xwm.c @@ -11,7 +11,8 @@ #include #include #include -#include +#include +#include #include #include #include @@ -20,6 +21,7 @@ const char *const atom_map[ATOM_LAST] = { [WL_SURFACE_ID] = "WL_SURFACE_ID", + [WL_SURFACE_SERIAL] = "WL_SURFACE_SERIAL", [WM_DELETE_WINDOW] = "WM_DELETE_WINDOW", [WM_PROTOCOLS] = "WM_PROTOCOLS", [WM_HINTS] = "WM_HINTS", @@ -1118,6 +1120,35 @@ static void xwm_handle_surface_id_message(struct wlr_xwm *xwm, } } +static void xwm_handle_surface_serial_message(struct wlr_xwm *xwm, + xcb_client_message_event_t *ev) { + struct wlr_xwayland_surface *xsurface = lookup_surface(xwm, ev->window); + if (xsurface == NULL) { + wlr_log(WLR_DEBUG, + "Received client message WL_SURFACE_SERIAL but no X11 window %u", + ev->window); + return; + } + if (xsurface->serial != 0) { + wlr_log(WLR_DEBUG, "Received multiple client messages WL_SURFACE_SERIAL " + "for the same X11 window %u", ev->window); + return; + } + + uint32_t serial_lo = ev->data.data32[0]; + uint32_t serial_hi = ev->data.data32[1]; + xsurface->serial = ((uint64_t)serial_hi << 32) | serial_lo; + + struct wlr_surface *surface = wlr_xwayland_shell_v1_surface_from_serial( + xwm->xwayland->shell_v1, xsurface->serial); + if (surface != NULL) { + xwm_map_shell_surface(xwm, xsurface, surface); + } else { + wl_list_remove(&xsurface->unpaired_link); + wl_list_insert(&xwm->unpaired_surfaces, &xsurface->unpaired_link); + } +} + #define _NET_WM_MOVERESIZE_SIZE_TOPLEFT 0 #define _NET_WM_MOVERESIZE_SIZE_TOP 1 #define _NET_WM_MOVERESIZE_SIZE_TOPRIGHT 2 @@ -1430,6 +1461,8 @@ static void xwm_handle_client_message(struct wlr_xwm *xwm, xcb_client_message_event_t *ev) { if (ev->type == xwm->atoms[WL_SURFACE_ID]) { xwm_handle_surface_id_message(xwm, ev); + } else if (ev->type == xwm->atoms[WL_SURFACE_SERIAL]) { + xwm_handle_surface_serial_message(xwm, ev); } else if (ev->type == xwm->atoms[NET_WM_STATE]) { xwm_handle_net_wm_state_message(xwm, ev); } else if (ev->type == xwm->atoms[NET_WM_MOVERESIZE]) { @@ -1656,6 +1689,20 @@ static void handle_compositor_destroy(struct wl_listener *listener, wl_list_init(&xwm->compositor_destroy.link); } +static void handle_shell_v1_new_surface(struct wl_listener *listener, + void *data) { + struct wlr_xwm *xwm = wl_container_of(listener, xwm, shell_v1_new_surface); + struct wlr_xwayland_surface_v1 *shell_surface = data; + + struct wlr_xwayland_surface *xsurface; + wl_list_for_each(xsurface, &xwm->unpaired_surfaces, unpaired_link) { + if (xsurface->serial == shell_surface->serial) { + xwm_map_shell_surface(xwm, xsurface, shell_surface->surface); + return; + } + } +} + void wlr_xwayland_surface_activate(struct wlr_xwayland_surface *xsurface, bool activated) { struct wlr_xwayland_surface *focused = xsurface->xwm->focus_surface; @@ -1756,6 +1803,7 @@ void xwm_destroy(struct wlr_xwm *xwm) { } wl_list_remove(&xwm->compositor_new_surface.link); wl_list_remove(&xwm->compositor_destroy.link); + wl_list_remove(&xwm->shell_v1_new_surface.link); xcb_disconnect(xwm->xcb_conn); struct pending_startup_id *pending, *next; @@ -2097,6 +2145,10 @@ struct wlr_xwm *xwm_create(struct wlr_xwayland *xwayland, int wm_fd) { wl_signal_add(&xwayland->compositor->events.destroy, &xwm->compositor_destroy); + xwm->shell_v1_new_surface.notify = handle_shell_v1_new_surface; + wl_signal_add(&xwayland->shell_v1->events.new_surface, + &xwm->shell_v1_new_surface); + xwm_create_wm_window(xwm); xcb_flush(xwm->xcb_conn);