diff --git a/include/wlr/types/wlr_xdg_shell.h b/include/wlr/types/wlr_xdg_shell.h index d813ad65..804b0083 100644 --- a/include/wlr/types/wlr_xdg_shell.h +++ b/include/wlr/types/wlr_xdg_shell.h @@ -105,6 +105,12 @@ struct wlr_xdg_toplevel_state { uint32_t width, height; uint32_t max_width, max_height; uint32_t min_width, min_height; + + // Since the fullscreen request may be made before the toplevel's surface + // is mapped, this is used to store the requested fullscreen output (if + // any) for wlr_xdg_toplevel::client_pending. + struct wlr_output *fullscreen_output; + struct wl_listener fullscreen_output_destroy; }; struct wlr_xdg_toplevel { diff --git a/types/xdg_shell/wlr_xdg_surface.c b/types/xdg_shell/wlr_xdg_surface.c index ada5b419..e3f13e0e 100644 --- a/types/xdg_shell/wlr_xdg_surface.c +++ b/types/xdg_shell/wlr_xdg_surface.c @@ -459,6 +459,11 @@ void reset_xdg_surface(struct wlr_xdg_surface *xdg_surface) { wl_resource_set_user_data(xdg_surface->toplevel->resource, NULL); xdg_surface->toplevel->resource = NULL; + if (xdg_surface->toplevel->client_pending.fullscreen_output) { + struct wlr_xdg_toplevel_state *client_pending = + &xdg_surface->toplevel->client_pending; + wl_list_remove(&client_pending->fullscreen_output_destroy.link); + } free(xdg_surface->toplevel); xdg_surface->toplevel = NULL; break; diff --git a/types/xdg_shell/wlr_xdg_toplevel.c b/types/xdg_shell/wlr_xdg_toplevel.c index d3ee0cb7..96bb0537 100644 --- a/types/xdg_shell/wlr_xdg_toplevel.c +++ b/types/xdg_shell/wlr_xdg_toplevel.c @@ -375,6 +375,30 @@ static void xdg_toplevel_handle_unset_maximized(struct wl_client *client, wlr_signal_emit_safe(&surface->toplevel->events.request_maximize, surface); } +static void handle_fullscreen_output_destroy(struct wl_listener *listener, + void *data) { + struct wlr_xdg_toplevel_state *state = + wl_container_of(listener, state, fullscreen_output_destroy); + state->fullscreen_output = NULL; + wl_list_remove(&state->fullscreen_output_destroy.link); +} + +static void store_fullscreen_pending(struct wlr_xdg_surface *surface, + bool fullscreen, struct wlr_output *output) { + struct wlr_xdg_toplevel_state *state = &surface->toplevel->client_pending; + state->fullscreen = fullscreen; + if (state->fullscreen_output) { + wl_list_remove(&state->fullscreen_output_destroy.link); + } + state->fullscreen_output = output; + if (state->fullscreen_output) { + state->fullscreen_output_destroy.notify = + handle_fullscreen_output_destroy; + wl_signal_add(&state->fullscreen_output->events.destroy, + &state->fullscreen_output_destroy); + } +} + static void xdg_toplevel_handle_set_fullscreen(struct wl_client *client, struct wl_resource *resource, struct wl_resource *output_resource) { struct wlr_xdg_surface *surface = @@ -385,7 +409,7 @@ static void xdg_toplevel_handle_set_fullscreen(struct wl_client *client, output = wlr_output_from_resource(output_resource); } - surface->toplevel->client_pending.fullscreen = true; + store_fullscreen_pending(surface, true, output); struct wlr_xdg_toplevel_set_fullscreen_event event = { .surface = surface, @@ -401,7 +425,7 @@ static void xdg_toplevel_handle_unset_fullscreen(struct wl_client *client, struct wlr_xdg_surface *surface = wlr_xdg_surface_from_toplevel_resource(resource); - surface->toplevel->client_pending.fullscreen = false; + store_fullscreen_pending(surface, false, NULL); struct wlr_xdg_toplevel_set_fullscreen_event event = { .surface = surface,