From 16d7e09d996f7fd211e3a6ff8960a15217ca3710 Mon Sep 17 00:00:00 2001 From: emersion Date: Mon, 9 Jul 2018 23:02:03 +0100 Subject: [PATCH] surface: add wlr_surface_role.precommit This allows to emit the unmap event before the surface becomes actually unmapped for most shells. --- include/types/wlr_xdg_shell.h | 3 ++- include/types/wlr_xdg_shell_v6.h | 3 ++- include/wlr/types/wlr_surface.h | 1 + types/wlr_surface.c | 8 ++++++-- types/xdg_shell/wlr_xdg_popup.c | 3 ++- types/xdg_shell/wlr_xdg_surface.c | 18 +++++++++++++++++- types/xdg_shell/wlr_xdg_toplevel.c | 3 ++- types/xdg_shell_v6/wlr_xdg_popup_v6.c | 3 ++- types/xdg_shell_v6/wlr_xdg_surface_v6.c | 20 ++++++++++++++++---- types/xdg_shell_v6/wlr_xdg_toplevel_v6.c | 3 ++- xwayland/xwm.c | 18 ++++++++++++++++++ 11 files changed, 70 insertions(+), 13 deletions(-) diff --git a/include/types/wlr_xdg_shell.h b/include/types/wlr_xdg_shell.h index 7a17d2864..93fdc6708 100644 --- a/include/types/wlr_xdg_shell.h +++ b/include/types/wlr_xdg_shell.h @@ -19,7 +19,8 @@ struct wlr_xdg_surface *create_xdg_surface( uint32_t id); void unmap_xdg_surface(struct wlr_xdg_surface *surface); void destroy_xdg_surface(struct wlr_xdg_surface *surface); -void handle_xdg_surface_committed(struct wlr_surface *wlr_surface); +void handle_xdg_surface_commit(struct wlr_surface *wlr_surface); +void handle_xdg_surface_precommit(struct wlr_surface *wlr_surface); void create_xdg_positioner(struct wlr_xdg_client *client, uint32_t id); struct wlr_xdg_positioner_resource *get_xdg_positioner_from_resource( diff --git a/include/types/wlr_xdg_shell_v6.h b/include/types/wlr_xdg_shell_v6.h index 030c10e42..59fca6670 100644 --- a/include/types/wlr_xdg_shell_v6.h +++ b/include/types/wlr_xdg_shell_v6.h @@ -19,7 +19,8 @@ struct wlr_xdg_surface_v6 *create_xdg_surface_v6( uint32_t id); void unmap_xdg_surface_v6(struct wlr_xdg_surface_v6 *surface); void destroy_xdg_surface_v6(struct wlr_xdg_surface_v6 *surface); -void handle_xdg_surface_v6_committed(struct wlr_surface *wlr_surface); +void handle_xdg_surface_v6_commit(struct wlr_surface *wlr_surface); +void handle_xdg_surface_v6_precommit(struct wlr_surface *wlr_surface); void create_xdg_positioner_v6(struct wlr_xdg_client_v6 *client, uint32_t id); struct wlr_xdg_positioner_v6_resource *get_xdg_positioner_v6_from_resource( diff --git a/include/wlr/types/wlr_surface.h b/include/wlr/types/wlr_surface.h index 0e3b5ff40..ee9afa860 100644 --- a/include/wlr/types/wlr_surface.h +++ b/include/wlr/types/wlr_surface.h @@ -39,6 +39,7 @@ struct wlr_surface_state { struct wlr_surface_role { const char *name; void (*commit)(struct wlr_surface *surface); + void (*precommit)(struct wlr_surface *surface); }; struct wlr_surface { diff --git a/types/wlr_surface.c b/types/wlr_surface.c index f2b248ca4..ab1dfc2d2 100644 --- a/types/wlr_surface.c +++ b/types/wlr_surface.c @@ -360,10 +360,14 @@ static void surface_update_opaque_region(struct wlr_surface *surface) { } static void surface_commit_pending(struct wlr_surface *surface) { - bool invalid_buffer = surface->pending.committed & WLR_SURFACE_STATE_BUFFER; - surface_state_finalize(surface, &surface->pending); + if (surface->role && surface->role->precommit) { + surface->role->precommit(surface); + } + + bool invalid_buffer = surface->pending.committed & WLR_SURFACE_STATE_BUFFER; + surface->sx += surface->pending.dx; surface->sy += surface->pending.dy; surface_update_damage(&surface->buffer_damage, diff --git a/types/xdg_shell/wlr_xdg_popup.c b/types/xdg_shell/wlr_xdg_popup.c index 26d248e18..b34092619 100644 --- a/types/xdg_shell/wlr_xdg_popup.c +++ b/types/xdg_shell/wlr_xdg_popup.c @@ -214,7 +214,8 @@ static void xdg_popup_handle_resource_destroy(struct wl_resource *resource) { const struct wlr_surface_role xdg_popup_surface_role = { .name = "xdg_popup", - .commit = handle_xdg_surface_committed, + .commit = handle_xdg_surface_commit, + .precommit = handle_xdg_surface_precommit, }; void create_xdg_popup(struct wlr_xdg_surface *xdg_surface, diff --git a/types/xdg_shell/wlr_xdg_surface.c b/types/xdg_shell/wlr_xdg_surface.c index dc98a3a51..0ff47a045 100644 --- a/types/xdg_shell/wlr_xdg_surface.c +++ b/types/xdg_shell/wlr_xdg_surface.c @@ -313,7 +313,7 @@ static void xdg_surface_handle_surface_commit(struct wl_listener *listener, } } -void handle_xdg_surface_committed(struct wlr_surface *wlr_surface) { +void handle_xdg_surface_commit(struct wlr_surface *wlr_surface) { struct wlr_xdg_surface *surface = wlr_xdg_surface_from_wlr_surface(wlr_surface); if (surface == NULL) { @@ -355,6 +355,22 @@ void handle_xdg_surface_committed(struct wlr_surface *wlr_surface) { } } +void handle_xdg_surface_precommit(struct wlr_surface *wlr_surface) { + struct wlr_xdg_surface *surface = + wlr_xdg_surface_from_wlr_surface(wlr_surface); + if (surface == NULL) { + return; + } + + if (wlr_surface->pending.committed & WLR_SURFACE_STATE_BUFFER && + wlr_surface->pending.buffer_resource == NULL) { + // This is a NULL commit + if (surface->configured && surface->mapped) { + unmap_xdg_surface(surface); + } + } +} + static void xdg_surface_handle_surface_destroy(struct wl_listener *listener, void *data) { struct wlr_xdg_surface *xdg_surface = diff --git a/types/xdg_shell/wlr_xdg_toplevel.c b/types/xdg_shell/wlr_xdg_toplevel.c index f04aa654a..67f180253 100644 --- a/types/xdg_shell/wlr_xdg_toplevel.c +++ b/types/xdg_shell/wlr_xdg_toplevel.c @@ -449,7 +449,8 @@ static void xdg_toplevel_handle_resource_destroy(struct wl_resource *resource) { const struct wlr_surface_role xdg_toplevel_surface_role = { .name = "xdg_toplevel", - .commit = handle_xdg_surface_committed, + .commit = handle_xdg_surface_commit, + .precommit = handle_xdg_surface_precommit, }; void create_xdg_toplevel(struct wlr_xdg_surface *xdg_surface, diff --git a/types/xdg_shell_v6/wlr_xdg_popup_v6.c b/types/xdg_shell_v6/wlr_xdg_popup_v6.c index 59af020f2..097e02531 100644 --- a/types/xdg_shell_v6/wlr_xdg_popup_v6.c +++ b/types/xdg_shell_v6/wlr_xdg_popup_v6.c @@ -251,7 +251,8 @@ void handle_xdg_surface_v6_popup_committed(struct wlr_xdg_surface_v6 *surface) { const struct wlr_surface_role xdg_popup_v6_surface_role = { .name = "xdg_popup_v6", - .commit = handle_xdg_surface_v6_committed, + .commit = handle_xdg_surface_v6_commit, + .precommit = handle_xdg_surface_v6_precommit, }; void create_xdg_popup_v6(struct wlr_xdg_surface_v6 *xdg_surface, diff --git a/types/xdg_shell_v6/wlr_xdg_surface_v6.c b/types/xdg_shell_v6/wlr_xdg_surface_v6.c index ca729c48b..c4007c718 100644 --- a/types/xdg_shell_v6/wlr_xdg_surface_v6.c +++ b/types/xdg_shell_v6/wlr_xdg_surface_v6.c @@ -371,7 +371,7 @@ static void xdg_surface_handle_surface_commit(struct wl_listener *listener, } } -void handle_xdg_surface_v6_committed(struct wlr_surface *wlr_surface) { +void handle_xdg_surface_v6_commit(struct wlr_surface *wlr_surface) { struct wlr_xdg_surface_v6 *surface = wlr_xdg_surface_v6_from_wlr_surface(wlr_surface); if (surface == NULL) { @@ -407,9 +407,21 @@ void handle_xdg_surface_v6_committed(struct wlr_surface *wlr_surface) { surface->mapped = true; wlr_signal_emit_safe(&surface->events.map, surface); } - if (surface->configured && !wlr_surface_has_buffer(surface->surface) && - surface->mapped) { - unmap_xdg_surface_v6(surface); +} + +void handle_xdg_surface_v6_precommit(struct wlr_surface *wlr_surface) { + struct wlr_xdg_surface_v6 *surface = + wlr_xdg_surface_v6_from_wlr_surface(wlr_surface); + if (surface == NULL) { + return; + } + + if (wlr_surface->pending.committed & WLR_SURFACE_STATE_BUFFER && + wlr_surface->pending.buffer_resource == NULL) { + // This is a NULL commit + if (surface->configured && surface->mapped) { + unmap_xdg_surface_v6(surface); + } } } diff --git a/types/xdg_shell_v6/wlr_xdg_toplevel_v6.c b/types/xdg_shell_v6/wlr_xdg_toplevel_v6.c index 43ca99f0c..edde8b624 100644 --- a/types/xdg_shell_v6/wlr_xdg_toplevel_v6.c +++ b/types/xdg_shell_v6/wlr_xdg_toplevel_v6.c @@ -419,7 +419,8 @@ static void xdg_toplevel_handle_resource_destroy(struct wl_resource *resource) { const struct wlr_surface_role xdg_toplevel_v6_surface_role = { .name = "xdg_toplevel_v6", - .commit = handle_xdg_surface_v6_committed, + .commit = handle_xdg_surface_v6_commit, + .precommit = handle_xdg_surface_v6_precommit, }; void create_xdg_toplevel_v6(struct wlr_xdg_surface_v6 *xdg_surface, diff --git a/xwayland/xwm.c b/xwayland/xwm.c index bee3a005a..54cb88d08 100644 --- a/xwayland/xwm.c +++ b/xwayland/xwm.c @@ -652,9 +652,27 @@ static void xwayland_surface_role_commit(struct wlr_surface *wlr_surface) { } } +static void xwayland_surface_role_precommit(struct wlr_surface *wlr_surface) { + assert(wlr_surface->role == &xwayland_surface_role); + struct wlr_xwayland_surface *surface = wlr_surface->role_data; + if (surface == NULL) { + return; + } + + if (wlr_surface->pending.committed & WLR_SURFACE_STATE_BUFFER && + wlr_surface->pending.buffer_resource == NULL) { + // This is a NULL commit + if (surface->mapped) { + wlr_signal_emit_safe(&surface->events.unmap, surface); + surface->mapped = false; + } + } +} + static const struct wlr_surface_role xwayland_surface_role = { .name = "wlr_xwayland_surface", .commit = xwayland_surface_role_commit, + .precommit = xwayland_surface_role_precommit, }; static void handle_surface_destroy(struct wl_listener *listener, void *data) {