From 811ca199c444525dc4d846d38f76554f1a9b48b0 Mon Sep 17 00:00:00 2001 From: Kirill Primak Date: Thu, 23 Nov 2023 16:10:39 +0300 Subject: xdg-shell: drop automatic surface configuration Compositors now are expected to wait for an initial commit by checking wlr_xdg_surface.initial_commit on every surface commit and send (schedule) configure events manually. --- tinywl/tinywl.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) (limited to 'tinywl') diff --git a/tinywl/tinywl.c b/tinywl/tinywl.c index bd21dd91..0342ec54 100644 --- a/tinywl/tinywl.c +++ b/tinywl/tinywl.c @@ -86,6 +86,7 @@ struct tinywl_toplevel { struct wlr_scene_tree *scene_tree; struct wl_listener map; struct wl_listener unmap; + struct wl_listener commit; struct wl_listener destroy; struct wl_listener request_move; struct wl_listener request_resize; @@ -93,6 +94,12 @@ struct tinywl_toplevel { struct wl_listener request_fullscreen; }; +struct tinywl_popup { + struct wlr_xdg_popup *xdg_popup; + struct wl_listener commit; + struct wl_listener destroy; +}; + struct tinywl_keyboard { struct wl_list link; struct tinywl_server *server; @@ -672,12 +679,26 @@ static void xdg_toplevel_unmap(struct wl_listener *listener, void *data) { wl_list_remove(&toplevel->link); } +static void xdg_toplevel_commit(struct wl_listener *listener, void *data) { + /* Called when a new surface state is committed. */ + struct tinywl_toplevel *toplevel = wl_container_of(listener, toplevel, commit); + + if (toplevel->xdg_toplevel->base->initial_commit) { + /* When an xdg_surface performs an initial commit, the compositor must + * reply with a configure so the client can map the surface. tinywl + * configures the xdg_toplevel with 0,0 size to let the client pick the + * dimensions itself. */ + wlr_xdg_toplevel_set_size(toplevel->xdg_toplevel, 0, 0); + } +} + static void xdg_toplevel_destroy(struct wl_listener *listener, void *data) { /* Called when the xdg_toplevel is destroyed. */ struct tinywl_toplevel *toplevel = wl_container_of(listener, toplevel, destroy); wl_list_remove(&toplevel->map.link); wl_list_remove(&toplevel->unmap.link); + wl_list_remove(&toplevel->commit.link); wl_list_remove(&toplevel->destroy.link); wl_list_remove(&toplevel->request_move.link); wl_list_remove(&toplevel->request_resize.link); @@ -793,6 +814,8 @@ static void server_new_xdg_toplevel(struct wl_listener *listener, void *data) { wl_signal_add(&xdg_toplevel->base->surface->events.map, &toplevel->map); toplevel->unmap.notify = xdg_toplevel_unmap; wl_signal_add(&xdg_toplevel->base->surface->events.unmap, &toplevel->unmap); + toplevel->commit.notify = xdg_toplevel_commit; + wl_signal_add(&xdg_toplevel->base->surface->events.commit, &toplevel->commit); toplevel->destroy.notify = xdg_toplevel_destroy; wl_signal_add(&xdg_toplevel->events.destroy, &toplevel->destroy); @@ -808,10 +831,37 @@ static void server_new_xdg_toplevel(struct wl_listener *listener, void *data) { wl_signal_add(&xdg_toplevel->events.request_fullscreen, &toplevel->request_fullscreen); } +static void xdg_popup_commit(struct wl_listener *listener, void *data) { + /* Called when a new surface state is committed. */ + struct tinywl_popup *popup = wl_container_of(listener, popup, commit); + + if (popup->xdg_popup->base->initial_commit) { + /* When an xdg_surface performs an initial commit, the compositor must + * reply with a configure so the client can map the surface. + * tinywl sends an empty configure. A more sophisticated compositor + * might change an xdg_popup's geometry to ensure it's not positioned + * off-screen, for example. */ + wlr_xdg_surface_schedule_configure(popup->xdg_popup->base); + } +} + +static void xdg_popup_destroy(struct wl_listener *listener, void *data) { + /* Called when the xdg_popup is destroyed. */ + struct tinywl_popup *popup = wl_container_of(listener, popup, destroy); + + wl_list_remove(&popup->commit.link); + wl_list_remove(&popup->destroy.link); + + free(popup); +} + static void server_new_xdg_popup(struct wl_listener *listener, void *data) { /* This event is raised when a client creates a new popup. */ struct wlr_xdg_popup *xdg_popup = data; + struct tinywl_popup *popup = calloc(1, sizeof(*popup)); + popup->xdg_popup = xdg_popup; + /* We must add xdg popups to the scene graph so they get rendered. The * wlroots scene graph provides a helper for this, but to use it we must * provide the proper parent scene node of the xdg popup. To enable this, @@ -821,6 +871,12 @@ static void server_new_xdg_popup(struct wl_listener *listener, void *data) { assert(parent != NULL); struct wlr_scene_tree *parent_tree = parent->data; xdg_popup->base->data = wlr_scene_xdg_surface_create(parent_tree, xdg_popup->base); + + popup->commit.notify = xdg_popup_commit; + wl_signal_add(&xdg_popup->base->surface->events.commit, &popup->commit); + + popup->destroy.notify = xdg_popup_destroy; + wl_signal_add(&xdg_popup->events.destroy, &popup->destroy); } int main(int argc, char *argv[]) { -- cgit v1.2.3