diff --git a/include/types/wlr_xdg_shell.h b/include/types/wlr_xdg_shell.h index 7a17d286..93fdc670 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 030c10e4..59fca667 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 0e3b5ff4..ee9afa86 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 f2b248ca..ab1dfc2d 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 26d248e1..b3409261 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 dc98a3a5..0ff47a04 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 0a1b9bfd..3bf7fd67 100644 --- a/types/xdg_shell/wlr_xdg_toplevel.c +++ b/types/xdg_shell/wlr_xdg_toplevel.c @@ -451,7 +451,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 59af020f..097e0253 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 ca729c48..c4007c71 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 3490f337..297f49f5 100644 --- a/types/xdg_shell_v6/wlr_xdg_toplevel_v6.c +++ b/types/xdg_shell_v6/wlr_xdg_toplevel_v6.c @@ -421,7 +421,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 6632b5fc..7999480a 100644 --- a/xwayland/xwm.c +++ b/xwayland/xwm.c @@ -654,9 +654,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) {