view: Tidy up view->output/view->fullscreen redundancy

A fullscreen view currently has its output specified twice by:
  - struct output *output
  - struct wlr_output *fullscreen

view->fullscreen may also become a dangling pointer if the output is
disconnected, because view_on_output_destroy() clears view->output but
not view->fullscreen.

To eliminate the redundancy and the dangling pointer, let's change
view->fullscreen to a Boolean and rely on view->output to specify the
output.

Along the way, change a few related usages of struct wlr_output to
struct output as well.

No functional change intended.

v2: Don't allow entering fullscreen on disabled output (makes
    conditions for entering/leaving fullscreen symmetric)
v3: Use output_is_usable() helper
This commit is contained in:
John Lindgren 2023-02-15 02:12:22 -05:00
parent 6efc6a9db4
commit 49c9466039
3 changed files with 44 additions and 47 deletions

View file

@ -48,6 +48,7 @@ struct view {
bool ssd_enabled; bool ssd_enabled;
bool minimized; bool minimized;
bool maximized; bool maximized;
bool fullscreen;
uint32_t tiled; /* private, enum view_edge in src/view.c */ uint32_t tiled; /* private, enum view_edge in src/view.c */
/* Pointer to an output owned struct region, may be NULL */ /* Pointer to an output owned struct region, may be NULL */
@ -55,8 +56,6 @@ struct view {
/* Set to region->name when tiled_region is free'd by a destroying output */ /* Set to region->name when tiled_region is free'd by a destroying output */
char *tiled_region_evacuate; char *tiled_region_evacuate;
struct wlr_output *fullscreen;
/* /*
* Geometry of the wlr_surface contained within the view, as * Geometry of the wlr_surface contained within the view, as
* currently displayed. Should be kept in sync with the * currently displayed. Should be kept in sync with the
@ -137,7 +136,7 @@ void view_set_untiled(struct view *view);
void view_maximize(struct view *view, bool maximize, void view_maximize(struct view *view, bool maximize,
bool store_natural_geometry); bool store_natural_geometry);
void view_set_fullscreen(struct view *view, bool fullscreen, void view_set_fullscreen(struct view *view, bool fullscreen,
struct wlr_output *wlr_output); struct output *output);
void view_toggle_maximize(struct view *view); void view_toggle_maximize(struct view *view);
void view_toggle_decorations(struct view *view); void view_toggle_decorations(struct view *view);
void view_toggle_always_on_top(struct view *view); void view_toggle_always_on_top(struct view *view);

View file

@ -221,9 +221,9 @@ view_minimize(struct view *view, bool minimized)
} }
} }
/* view_wlr_output - return the output that a view is mostly on */ /* view_output - return the output that a view is mostly on */
static struct wlr_output * static struct output *
view_wlr_output(struct view *view) view_output(struct view *view)
{ {
assert(view); assert(view);
double closest_x, closest_y; double closest_x, closest_y;
@ -234,13 +234,6 @@ view_wlr_output(struct view *view)
&closest_x, &closest_y); &closest_x, &closest_y);
wlr_output = wlr_output_layout_output_at(view->server->output_layout, wlr_output = wlr_output_layout_output_at(view->server->output_layout,
closest_x, closest_y); closest_x, closest_y);
return wlr_output;
}
static struct output *
view_output(struct view *view)
{
struct wlr_output *wlr_output = view_wlr_output(view);
return output_from_wlr_output(view->server, wlr_output); return output_from_wlr_output(view->server, wlr_output);
} }
@ -442,16 +435,17 @@ view_apply_tiled_geometry(struct view *view, struct output *output)
} }
static void static void
view_apply_fullscreen_geometry(struct view *view, struct wlr_output *wlr_output) view_apply_fullscreen_geometry(struct view *view)
{ {
assert(wlr_output); assert(view->fullscreen);
struct output *output = assert(output_is_usable(view->output));
output_from_wlr_output(view->server, wlr_output);
struct wlr_box box = { 0 }; struct wlr_box box = { 0 };
wlr_output_effective_resolution(wlr_output, &box.width, &box.height); wlr_output_effective_resolution(view->output->wlr_output,
&box.width, &box.height);
double ox = 0, oy = 0; double ox = 0, oy = 0;
wlr_output_layout_output_coords(output->server->output_layout, wlr_output_layout_output_coords(view->server->output_layout,
output->wlr_output, &ox, &oy); view->output->wlr_output, &ox, &oy);
box.x -= ox; box.x -= ox;
box.y -= oy; box.y -= oy;
view_move_resize(view, box); view_move_resize(view, box);
@ -679,16 +673,15 @@ view_toggle_fullscreen(struct view *view)
} }
void void
view_set_fullscreen(struct view *view, bool fullscreen, view_set_fullscreen(struct view *view, bool fullscreen, struct output *output)
struct wlr_output *wlr_output)
{ {
assert(view); assert(view);
if (fullscreen != !view->fullscreen) { if (fullscreen == view->fullscreen) {
return; return;
} }
if (!wlr_output) { if (fullscreen && !output_is_usable(output)) {
wlr_output = view_wlr_output(view); output = view_output(view);
if (!wlr_output && fullscreen) { if (!output_is_usable(output)) {
/* Prevent fullscreen with no available outputs */ /* Prevent fullscreen with no available outputs */
return; return;
} }
@ -713,8 +706,9 @@ view_set_fullscreen(struct view *view, bool fullscreen,
if (view->ssd_enabled) { if (view->ssd_enabled) {
undecorate(view); undecorate(view);
} }
view->fullscreen = wlr_output; view->fullscreen = true;
view_apply_fullscreen_geometry(view, view->fullscreen); view->output = output;
view_apply_fullscreen_geometry(view);
} else { } else {
view->fullscreen = false; view->fullscreen = false;
/* Re-show decorations when no longer fullscreen */ /* Re-show decorations when no longer fullscreen */
@ -728,32 +722,29 @@ view_set_fullscreen(struct view *view, bool fullscreen,
} }
/* Show fullscreen views above top-layer */ /* Show fullscreen views above top-layer */
struct output *output = if (view->output) {
output_from_wlr_output(view->server, wlr_output); uint32_t top = ZWLR_LAYER_SHELL_V1_LAYER_TOP;
if (!output) { wlr_scene_node_set_enabled(&view->output->layer_tree[top]->node,
return; !fullscreen);
} }
uint32_t top = ZWLR_LAYER_SHELL_V1_LAYER_TOP;
wlr_scene_node_set_enabled(&output->layer_tree[top]->node, !fullscreen);
} }
void void
view_adjust_for_layout_change(struct view *view) view_adjust_for_layout_change(struct view *view)
{ {
assert(view); assert(view);
struct wlr_output_layout *layout = view->server->output_layout;
if (view->fullscreen) { if (view->fullscreen) {
if (wlr_output_layout_get(layout, view->fullscreen)) { if (output_is_usable(view->output)) {
/* recompute fullscreen geometry */ /* recompute fullscreen geometry */
view_apply_fullscreen_geometry(view, view->fullscreen); view_apply_fullscreen_geometry(view);
} else { } else {
/* output is gone, exit fullscreen */ /* output is gone, exit fullscreen */
view_set_fullscreen(view, false, NULL); view_set_fullscreen(view, false, NULL);
} }
} else if (!view_apply_special_geometry(view)) { } else if (!view_apply_special_geometry(view)) {
/* reposition view if it's offscreen */ /* reposition view if it's offscreen */
if (!wlr_output_layout_intersects(layout, NULL, if (!wlr_output_layout_intersects(view->server->output_layout,
&view->pending)) { NULL, &view->pending)) {
view_center(view); view_center(view);
} }
} }
@ -771,7 +762,13 @@ void
view_discover_output(struct view *view) view_discover_output(struct view *view)
{ {
assert(view); assert(view);
view->output = view_output(view); /*
* Fullscreen views are tied to a particular output so don't
* auto-discover output for them.
*/
if (!view->fullscreen) {
view->output = view_output(view);
}
} }
void void
@ -1052,11 +1049,10 @@ view_destroy(struct view *view)
* in fullscreen mode, so if that's the case, we have to re-enable it * in fullscreen mode, so if that's the case, we have to re-enable it
* here. * here.
*/ */
if (view->fullscreen) { if (view->fullscreen && view->output) {
struct output *output =
output_from_wlr_output(server, view->fullscreen);
uint32_t top = ZWLR_LAYER_SHELL_V1_LAYER_TOP; uint32_t top = ZWLR_LAYER_SHELL_V1_LAYER_TOP;
wlr_scene_node_set_enabled(&output->layer_tree[top]->node, true); wlr_scene_node_set_enabled(&view->output->layer_tree[top]->node,
true);
} }
/* If we spawned a window menu, close it */ /* If we spawned a window menu, close it */

View file

@ -178,8 +178,9 @@ handle_request_fullscreen(struct wl_listener *listener, void *data)
{ {
struct view *view = wl_container_of(listener, view, request_fullscreen); struct view *view = wl_container_of(listener, view, request_fullscreen);
struct wlr_xdg_toplevel *xdg_toplevel = xdg_toplevel_from_view(view); struct wlr_xdg_toplevel *xdg_toplevel = xdg_toplevel_from_view(view);
view_set_fullscreen(view, xdg_toplevel->requested.fullscreen, struct output *output = output_from_wlr_output(view->server,
xdg_toplevel->requested.fullscreen_output); xdg_toplevel->requested.fullscreen_output);
view_set_fullscreen(view, xdg_toplevel->requested.fullscreen, output);
} }
static void static void
@ -345,8 +346,9 @@ xdg_toplevel_view_map(struct view *view)
} }
if (!view->fullscreen && requested->fullscreen) { if (!view->fullscreen && requested->fullscreen) {
view_set_fullscreen(view, true, struct output *output = output_from_wlr_output(
requested->fullscreen_output); view->server, requested->fullscreen_output);
view_set_fullscreen(view, true, output);
} else if (!view->maximized && requested->maximized) { } else if (!view->maximized && requested->maximized) {
view_maximize(view, true, view_maximize(view, true,
/*store_natural_geometry*/ true); /*store_natural_geometry*/ true);