From d7dc6e01b446bf18385efeff15005deb3d48fd4f Mon Sep 17 00:00:00 2001 From: Christopher Snowhill Date: Thu, 15 Jun 2023 02:35:43 -0700 Subject: [PATCH] Chase wlroots: Unified mapping Need to handle new unified mapping, where mapping is attached to the wlr_surface objects instead of their parents. Also, most of them require a new associate event for xsurface objects, their surface member will be NULL before this event is received. Refactored by jlindgren: - add struct mappable - unify map/unmap logic --- include/view.h | 16 ++++++++++-- include/xwayland.h | 8 ++++-- src/dnd.c | 4 +-- src/layers.c | 8 +++--- src/session-lock.c | 6 ++--- src/view.c | 55 ++++++++++++++++++++++++++++++++++++++-- src/xdg.c | 17 +------------ src/xwayland-unmanaged.c | 47 ++++++++++++++++++++++++++-------- src/xwayland.c | 31 ++++++++++++++-------- subprojects/wlroots.wrap | 2 +- 10 files changed, 142 insertions(+), 52 deletions(-) diff --git a/include/view.h b/include/view.h index f747252c..f7329fdc 100644 --- a/include/view.h +++ b/include/view.h @@ -70,6 +70,13 @@ enum view_wants_focus { struct view; struct wlr_surface; +/* Common to struct view and struct xwayland_unmanaged */ +struct mappable { + bool connected; + struct wl_listener map; + struct wl_listener unmap; +}; + /* Basic size hints (subset of XSizeHints from X11) */ struct view_size_hints { int min_width; @@ -194,8 +201,8 @@ struct view { struct wl_listener destroy; } toplevel; - struct wl_listener map; - struct wl_listener unmap; + struct mappable mappable; + struct wl_listener destroy; struct wl_listener surface_destroy; struct wl_listener commit; @@ -345,6 +352,10 @@ view_is_focusable(struct view *view) { return view_is_focusable_from(view, NULL); } +void mappable_connect(struct mappable *mappable, struct wlr_surface *surface, + wl_notify_func_t notify_map, wl_notify_func_t notify_unmap); +void mappable_disconnect(struct mappable *mappable); + void view_toggle_keybinds(struct view *view); void view_set_activated(struct view *view, bool activated); @@ -427,6 +438,7 @@ void view_adjust_size(struct view *view, int *w, int *h); void view_evacuate_region(struct view *view); void view_on_output_destroy(struct view *view); +void view_connect_map(struct view *view, struct wlr_surface *surface); void view_destroy(struct view *view); enum view_axis view_axis_parse(const char *direction); diff --git a/include/xwayland.h b/include/xwayland.h index 8bb475ba..76e48ca5 100644 --- a/include/xwayland.h +++ b/include/xwayland.h @@ -13,12 +13,14 @@ struct xwayland_unmanaged { struct wlr_scene_node *node; struct wl_list link; + struct mappable mappable; + + struct wl_listener associate; + struct wl_listener dissociate; struct wl_listener request_activate; struct wl_listener request_configure; /* struct wl_listener request_fullscreen; */ struct wl_listener set_geometry; - struct wl_listener map; - struct wl_listener unmap; struct wl_listener destroy; struct wl_listener set_override_redirect; }; @@ -28,6 +30,8 @@ struct xwayland_view { struct wlr_xwayland_surface *xwayland_surface; /* Events unique to XWayland views */ + struct wl_listener associate; + struct wl_listener dissociate; struct wl_listener request_activate; struct wl_listener request_configure; struct wl_listener set_class; diff --git a/src/dnd.c b/src/dnd.c index e69a8548..695096f4 100644 --- a/src/dnd.c +++ b/src/dnd.c @@ -89,9 +89,9 @@ drag_icon_create(struct seat *seat, struct wlr_drag_icon *wlr_icon) self->events.unmap.notify = handle_icon_unmap; self->events.destroy.notify = handle_icon_destroy; - wl_signal_add(&wlr_icon->events.map, &self->events.map); + wl_signal_add(&wlr_icon->surface->events.map, &self->events.map); wl_signal_add(&wlr_icon->surface->events.commit, &self->events.commit); - wl_signal_add(&wlr_icon->events.unmap, &self->events.unmap); + wl_signal_add(&wlr_icon->surface->events.unmap, &self->events.unmap); wl_signal_add(&wlr_icon->events.destroy, &self->events.destroy); } diff --git a/src/layers.c b/src/layers.c index 634e3727..16a4be58 100644 --- a/src/layers.c +++ b/src/layers.c @@ -175,8 +175,8 @@ handle_surface_commit(struct wl_listener *listener, void *data) process_keyboard_interactivity(layer); } - if (committed || layer->mapped != layer_surface->mapped) { - layer->mapped = layer_surface->mapped; + if (committed || layer->mapped != layer_surface->surface->mapped) { + layer->mapped = layer_surface->surface->mapped; output_update_usable_area(output); /* * Update cursor focus here to ensure we @@ -401,10 +401,10 @@ handle_new_layer_surface(struct wl_listener *listener, void *data) &surface->surface_commit); surface->map.notify = handle_map; - wl_signal_add(&layer_surface->events.map, &surface->map); + wl_signal_add(&layer_surface->surface->events.map, &surface->map); surface->unmap.notify = handle_unmap; - wl_signal_add(&layer_surface->events.unmap, &surface->unmap); + wl_signal_add(&layer_surface->surface->events.unmap, &surface->unmap); surface->new_popup.notify = handle_new_popup; wl_signal_add(&layer_surface->events.new_popup, &surface->new_popup); diff --git a/src/session-lock.c b/src/session-lock.c index 0f4f8ef6..00676577 100644 --- a/src/session-lock.c +++ b/src/session-lock.c @@ -42,10 +42,10 @@ refocus_output(struct session_lock_output *output) struct session_lock_output *iter; wl_list_for_each(iter, &output->lock->session_lock_outputs, link) { - if (iter == output || !iter->surface) { + if (iter == output || !iter->surface || !iter->surface->surface) { continue; } - if (iter->surface->mapped) { + if (iter->surface->surface->mapped) { focus_surface(output->lock, iter->surface->surface); return; } @@ -110,7 +110,7 @@ found_lock_output: wl_signal_add(&lock_surface->events.destroy, &lock_output->surface_destroy); lock_output->surface_map.notify = handle_surface_map; - wl_signal_add(&lock_surface->events.map, &lock_output->surface_map); + wl_signal_add(&lock_surface->surface->events.map, &lock_output->surface_map); lock_output_reconfigure(lock_output); } diff --git a/src/view.c b/src/view.c index 8c77dcda..4a2008df 100644 --- a/src/view.c +++ b/src/view.c @@ -1605,6 +1605,55 @@ view_toggle_keybinds(struct view *view) } } +void +mappable_connect(struct mappable *mappable, struct wlr_surface *surface, + wl_notify_func_t notify_map, wl_notify_func_t notify_unmap) +{ + assert(mappable); + assert(!mappable->connected); + mappable->map.notify = notify_map; + wl_signal_add(&surface->events.map, &mappable->map); + mappable->unmap.notify = notify_unmap; + wl_signal_add(&surface->events.unmap, &mappable->unmap); + mappable->connected = true; +} + +void +mappable_disconnect(struct mappable *mappable) +{ + assert(mappable); + assert(mappable->connected); + wl_list_remove(&mappable->map.link); + wl_list_remove(&mappable->unmap.link); + mappable->connected = false; +} + +static void +handle_map(struct wl_listener *listener, void *data) +{ + struct view *view = wl_container_of(listener, view, mappable.map); + view->impl->map(view); +} + +static void +handle_unmap(struct wl_listener *listener, void *data) +{ + struct view *view = wl_container_of(listener, view, mappable.unmap); + view->impl->unmap(view, /* client_request */ true); +} + +/* + * TODO: after the release of wlroots 0.17, consider incorporating this + * function into a more general view_set_surface() function, which could + * connect other surface event handlers (like commit) as well. + */ +void +view_connect_map(struct view *view, struct wlr_surface *surface) +{ + assert(view); + mappable_connect(&view->mappable, surface, handle_map, handle_unmap); +} + void view_destroy(struct view *view) { @@ -1612,8 +1661,10 @@ view_destroy(struct view *view) struct server *server = view->server; bool need_cursor_update = false; - wl_list_remove(&view->map.link); - wl_list_remove(&view->unmap.link); + if (view->mappable.connected) { + mappable_disconnect(&view->mappable); + } + wl_list_remove(&view->request_move.link); wl_list_remove(&view->request_resize.link); wl_list_remove(&view->request_minimize.link); diff --git a/src/xdg.c b/src/xdg.c index a02c8aaa..713eccd1 100644 --- a/src/xdg.c +++ b/src/xdg.c @@ -163,20 +163,6 @@ set_pending_configure_serial(struct view *view, uint32_t serial) CONFIGURE_TIMEOUT_MS); } -static void -handle_map(struct wl_listener *listener, void *data) -{ - struct view *view = wl_container_of(listener, view, map); - view->impl->map(view); -} - -static void -handle_unmap(struct wl_listener *listener, void *data) -{ - struct view *view = wl_container_of(listener, view, unmap); - view->impl->unmap(view, /* client_request */ true); -} - static void handle_destroy(struct wl_listener *listener, void *data) { @@ -688,8 +674,7 @@ xdg_surface_new(struct wl_listener *listener, void *data) /* In support of xdg popups */ xdg_surface->surface->data = tree; - CONNECT_SIGNAL(xdg_surface, view, map); - CONNECT_SIGNAL(xdg_surface, view, unmap); + view_connect_map(view, xdg_surface->surface); CONNECT_SIGNAL(xdg_surface, view, destroy); struct wlr_xdg_toplevel *toplevel = xdg_surface->toplevel; diff --git a/src/xwayland-unmanaged.c b/src/xwayland-unmanaged.c index 21df12ba..3910eb2a 100644 --- a/src/xwayland-unmanaged.c +++ b/src/xwayland-unmanaged.c @@ -37,7 +37,7 @@ static void handle_map(struct wl_listener *listener, void *data) { struct xwayland_unmanaged *unmanaged = - wl_container_of(listener, unmanaged, map); + wl_container_of(listener, unmanaged, mappable.map); struct wlr_xwayland_surface *xsurface = unmanaged->xwayland_surface; assert(!unmanaged->node); @@ -95,7 +95,7 @@ static void handle_unmap(struct wl_listener *listener, void *data) { struct xwayland_unmanaged *unmanaged = - wl_container_of(listener, unmanaged, unmap); + wl_container_of(listener, unmanaged, mappable.unmap); struct wlr_xwayland_surface *xsurface = unmanaged->xwayland_surface; struct seat *seat = &unmanaged->server->seat; assert(unmanaged->node); @@ -116,16 +116,43 @@ handle_unmap(struct wl_listener *listener, void *data) } } +static void +handle_associate(struct wl_listener *listener, void *data) +{ + struct xwayland_unmanaged *unmanaged = + wl_container_of(listener, unmanaged, associate); + assert(unmanaged->xwayland_surface && + unmanaged->xwayland_surface->surface); + + mappable_connect(&unmanaged->mappable, + unmanaged->xwayland_surface->surface, + handle_map, handle_unmap); +} + +static void +handle_dissociate(struct wl_listener *listener, void *data) +{ + struct xwayland_unmanaged *unmanaged = + wl_container_of(listener, unmanaged, dissociate); + + mappable_disconnect(&unmanaged->mappable); +} + static void handle_destroy(struct wl_listener *listener, void *data) { struct xwayland_unmanaged *unmanaged = wl_container_of(listener, unmanaged, destroy); + + if (unmanaged->mappable.connected) { + mappable_disconnect(&unmanaged->mappable); + } + + wl_list_remove(&unmanaged->associate.link); + wl_list_remove(&unmanaged->dissociate.link); wl_list_remove(&unmanaged->request_configure.link); wl_list_remove(&unmanaged->set_override_redirect.link); wl_list_remove(&unmanaged->request_activate.link); - wl_list_remove(&unmanaged->map.link); - wl_list_remove(&unmanaged->unmap.link); wl_list_remove(&unmanaged->destroy.link); free(unmanaged); } @@ -139,9 +166,9 @@ handle_set_override_redirect(struct wl_listener *listener, void *data) struct wlr_xwayland_surface *xsurface = unmanaged->xwayland_surface; struct server *server = unmanaged->server; - bool mapped = xsurface->mapped; + bool mapped = xsurface->surface && xsurface->surface->mapped; if (mapped) { - handle_unmap(&unmanaged->unmap, NULL); + handle_unmap(&unmanaged->mappable.unmap, NULL); } handle_destroy(&unmanaged->destroy, NULL); @@ -155,7 +182,7 @@ handle_request_activate(struct wl_listener *listener, void *data) struct xwayland_unmanaged *unmanaged = wl_container_of(listener, unmanaged, request_activate); struct wlr_xwayland_surface *xsurface = unmanaged->xwayland_surface; - if (!xsurface->mapped) { + if (!xsurface->surface || !xsurface->surface->mapped) { return; } struct server *server = unmanaged->server; @@ -191,14 +218,14 @@ xwayland_unmanaged_create(struct server *server, */ assert(!xsurface->data); - CONNECT_SIGNAL(xsurface, unmanaged, map); - CONNECT_SIGNAL(xsurface, unmanaged, unmap); + CONNECT_SIGNAL(xsurface, unmanaged, associate); + CONNECT_SIGNAL(xsurface, unmanaged, dissociate); CONNECT_SIGNAL(xsurface, unmanaged, destroy); CONNECT_SIGNAL(xsurface, unmanaged, request_activate); CONNECT_SIGNAL(xsurface, unmanaged, request_configure); CONNECT_SIGNAL(xsurface, unmanaged, set_override_redirect); if (mapped) { - handle_map(&unmanaged->map, xsurface); + handle_map(&unmanaged->mappable.map, NULL); } } diff --git a/src/xwayland.c b/src/xwayland.c index c0888236..0753f1de 100644 --- a/src/xwayland.c +++ b/src/xwayland.c @@ -15,6 +15,8 @@ #include "workspaces.h" #include "xwayland.h" +static void xwayland_view_unmap(struct view *view, bool client_request); + static struct view_size_hints xwayland_view_get_size_hints(struct view *view) { @@ -225,17 +227,24 @@ handle_request_resize(struct wl_listener *listener, void *data) } static void -handle_map(struct wl_listener *listener, void *data) +handle_associate(struct wl_listener *listener, void *data) { - struct view *view = wl_container_of(listener, view, map); - view->impl->map(view); + struct xwayland_view *xwayland_view = + wl_container_of(listener, xwayland_view, associate); + assert(xwayland_view->xwayland_surface && + xwayland_view->xwayland_surface->surface); + + view_connect_map(&xwayland_view->base, + xwayland_view->xwayland_surface->surface); } static void -handle_unmap(struct wl_listener *listener, void *data) +handle_dissociate(struct wl_listener *listener, void *data) { - struct view *view = wl_container_of(listener, view, unmap); - view->impl->unmap(view, /* client_request */ true); + struct xwayland_view *xwayland_view = + wl_container_of(listener, xwayland_view, dissociate); + + mappable_disconnect(&xwayland_view->base.mappable); } static void @@ -275,6 +284,8 @@ handle_destroy(struct wl_listener *listener, void *data) xwayland_view->xwayland_surface = NULL; /* Remove XWayland view specific listeners */ + wl_list_remove(&xwayland_view->associate.link); + wl_list_remove(&xwayland_view->dissociate.link); wl_list_remove(&xwayland_view->request_activate.link); wl_list_remove(&xwayland_view->request_configure.link); wl_list_remove(&xwayland_view->set_class.link); @@ -434,9 +445,9 @@ handle_set_override_redirect(struct wl_listener *listener, void *data) struct wlr_xwayland_surface *xsurface = xwayland_view->xwayland_surface; struct server *server = view->server; - bool mapped = xsurface->mapped; + bool mapped = xsurface->surface && xsurface->surface->mapped; if (mapped) { - handle_unmap(&view->unmap, xsurface); + xwayland_view_unmap(view, /* client_request */ true); } handle_destroy(&view->destroy, xsurface); /* view is invalid after this point */ @@ -770,8 +781,6 @@ xwayland_view_create(struct server *server, view->scene_tree = wlr_scene_tree_create(view->workspace->tree); node_descriptor_create(&view->scene_tree->node, LAB_NODE_DESC_VIEW, view); - CONNECT_SIGNAL(xsurface, view, map); - CONNECT_SIGNAL(xsurface, view, unmap); CONNECT_SIGNAL(xsurface, view, destroy); CONNECT_SIGNAL(xsurface, view, request_minimize); CONNECT_SIGNAL(xsurface, view, request_maximize); @@ -781,6 +790,8 @@ xwayland_view_create(struct server *server, CONNECT_SIGNAL(xsurface, view, set_title); /* Events specific to XWayland views */ + CONNECT_SIGNAL(xsurface, xwayland_view, associate); + CONNECT_SIGNAL(xsurface, xwayland_view, dissociate); CONNECT_SIGNAL(xsurface, xwayland_view, request_activate); CONNECT_SIGNAL(xsurface, xwayland_view, request_configure); CONNECT_SIGNAL(xsurface, xwayland_view, set_class); diff --git a/subprojects/wlroots.wrap b/subprojects/wlroots.wrap index 6003c8c1..91b514df 100644 --- a/subprojects/wlroots.wrap +++ b/subprojects/wlroots.wrap @@ -1,6 +1,6 @@ [wrap-git] url = https://gitlab.freedesktop.org/wlroots/wlroots.git -revision = 0bb574239d3b164596677bf4cec371ff0671dc4f +revision = 26676c8c072f813dc2d7e2b2dfe9e2701ce361a7 [provide] dependency_names = wlroots