cycle: clarify the lifecycle of window switcher

This commit clarifies the lifecycle of the window switcher (cycle) by:
- init_cycle(): initializes the window switcher (e.g. OSD).
- update_cycle(): updates the window switcher states including OSD,
  preview and outlines.
- destroy_cycle(): clears all the window switcher states.

This commit temporarily regresses by not trying to preserve the selected
view when a view is destroyed. This will be addressed in the next commit.
This commit is contained in:
tokyo4j 2025-11-30 22:10:58 +09:00 committed by Johan Malm
parent 1783b805e1
commit b6c1a9ea59
3 changed files with 65 additions and 64 deletions

View file

@ -56,8 +56,8 @@ void cycle_step(struct server *server, enum lab_cycle_dir direction);
/* Closes the OSD */ /* Closes the OSD */
void cycle_finish(struct server *server, bool switch_focus); void cycle_finish(struct server *server, bool switch_focus);
/* Notify OSD about a destroying view */ /* Re-initialize the window switcher */
void cycle_on_view_destroy(struct view *view); void cycle_reinitialize(struct server *server);
/* Focus the clicked window and close OSD */ /* Focus the clicked window and close OSD */
void cycle_on_cursor_release(struct server *server, struct wlr_scene_node *node); void cycle_on_cursor_release(struct server *server, struct wlr_scene_node *node);

View file

@ -17,6 +17,7 @@
#include "theme.h" #include "theme.h"
#include "view.h" #include "view.h"
static bool init_cycle(struct server *server);
static void update_cycle(struct server *server); static void update_cycle(struct server *server);
static void destroy_cycle(struct server *server); static void destroy_cycle(struct server *server);
@ -80,10 +81,8 @@ get_next_selected_view(struct server *server, struct view *start_view,
} }
void void
cycle_on_view_destroy(struct view *view) cycle_reinitialize(struct server *server)
{ {
assert(view);
struct server *server = view->server;
struct cycle_state *cycle = &server->cycle; struct cycle_state *cycle = &server->cycle;
if (server->input_mode != LAB_INPUT_STATE_CYCLE) { if (server->input_mode != LAB_INPUT_STATE_CYCLE) {
@ -91,31 +90,15 @@ cycle_on_view_destroy(struct view *view)
return; return;
} }
if (cycle->selected_view == view) { destroy_cycle(server);
/* if (init_cycle(server)) {
* If we are the current OSD selected view, cycle /* TODO: try to select the same view */
* to the next because we are dying. cycle->selected_view = get_next_selected_view(server, NULL,
*/ LAB_CYCLE_DIR_FORWARD);
/* Also resets preview node */
cycle->selected_view = get_next_selected_view(server,
cycle->selected_view, LAB_CYCLE_DIR_BACKWARD);
/*
* If we cycled back to ourselves, then we have no more windows.
* Just close the OSD for good.
*/
if (cycle->selected_view == view
|| !cycle->selected_view) {
/* cycle_finish() additionally resets selected_view to NULL */
cycle_finish(server, /*switch_focus*/ false);
}
}
if (cycle->selected_view) {
/* Recreate the OSD to reflect the view has now gone. */
destroy_cycle(server);
update_cycle(server); update_cycle(server);
} else {
/* Failed to re-init window switcher, exit */
cycle_finish(server, /*switch_focus*/ false);
} }
} }
@ -149,6 +132,7 @@ restore_preview_node(struct server *server)
} }
server->cycle.preview_node = NULL; server->cycle.preview_node = NULL;
server->cycle.preview_dummy = NULL; server->cycle.preview_dummy = NULL;
server->cycle.preview_was_enabled = false;
server->cycle.preview_was_shaded = false; server->cycle.preview_was_shaded = false;
} }
} }
@ -160,6 +144,10 @@ cycle_begin(struct server *server, enum lab_cycle_dir direction)
return; return;
} }
if (!init_cycle(server)) {
return;
}
server->cycle.selected_view = get_next_selected_view(server, server->cycle.selected_view = get_next_selected_view(server,
server->cycle.selected_view, direction); server->cycle.selected_view, direction);
@ -188,23 +176,11 @@ cycle_finish(struct server *server, bool switch_focus)
return; return;
} }
restore_preview_node(server);
/* FIXME: this sets focus to the old surface even with switch_focus=true */
seat_focus_override_end(&server->seat);
struct view *selected_view = server->cycle.selected_view; struct view *selected_view = server->cycle.selected_view;
server->cycle.preview_node = NULL;
server->cycle.preview_dummy = NULL;
server->cycle.selected_view = NULL;
server->cycle.preview_was_shaded = false;
destroy_cycle(server); destroy_cycle(server);
if (server->cycle.preview_outline) { /* FIXME: this sets focus to the old surface even with switch_focus=true */
/* Destroy the whole multi_rect so we can easily react to new themes */ seat_focus_override_end(&server->seat);
wlr_scene_node_destroy(&server->cycle.preview_outline->tree->node);
server->cycle.preview_outline = NULL;
}
/* Hiding OSD may need a cursor change */ /* Hiding OSD may need a cursor change */
cursor_update_focus(server); cursor_update_focus(server);
@ -270,42 +246,40 @@ get_osd_impl(void)
} }
static void static void
update_osd_on_output(struct output *output, struct wl_array *views) create_osd_on_output(struct output *output, struct wl_array *views)
{ {
if (!output_is_usable(output)) { if (!output_is_usable(output)) {
return; return;
} }
if (!output->cycle_osd.tree) { get_osd_impl()->create(output, views);
get_osd_impl()->create(output, views); assert(output->cycle_osd.tree);
assert(output->cycle_osd.tree);
}
get_osd_impl()->update(output);
} }
static void /* Return false on failure */
update_cycle(struct server *server) static bool
init_cycle(struct server *server)
{ {
struct wl_array views; struct wl_array views;
wl_array_init(&views); wl_array_init(&views);
view_array_append(server, &views, rc.window_switcher.criteria); view_array_append(server, &views, rc.window_switcher.criteria);
if (wl_array_len(&views) <= 0) {
if (!wl_array_len(&views) || !server->cycle.selected_view) { wlr_log(WLR_DEBUG, "no views to switch between");
cycle_finish(server, /*switch_focus*/ false); wl_array_release(&views);
goto out; return false;
} }
if (rc.window_switcher.show) { if (rc.window_switcher.show) {
/* Display the actual OSD */ /* Create OSD */
switch (rc.window_switcher.output_criteria) { switch (rc.window_switcher.output_criteria) {
case CYCLE_OSD_OUTPUT_ALL: { case CYCLE_OSD_OUTPUT_ALL: {
struct output *output; struct output *output;
wl_list_for_each(output, &server->outputs, link) { wl_list_for_each(output, &server->outputs, link) {
update_osd_on_output(output, &views); create_osd_on_output(output, &views);
} }
break; break;
} }
case CYCLE_OSD_OUTPUT_POINTER: case CYCLE_OSD_OUTPUT_POINTER:
update_osd_on_output(output_nearest_to_cursor(server), &views); create_osd_on_output(output_nearest_to_cursor(server), &views);
break; break;
case CYCLE_OSD_OUTPUT_KEYBOARD: { case CYCLE_OSD_OUTPUT_KEYBOARD: {
struct output *output; struct output *output;
@ -315,14 +289,32 @@ update_cycle(struct server *server)
/* Fallback to pointer, if there is no active_view */ /* Fallback to pointer, if there is no active_view */
output = output_nearest_to_cursor(server); output = output_nearest_to_cursor(server);
} }
update_osd_on_output(output, &views); create_osd_on_output(output, &views);
break; break;
} }
} }
} }
wl_array_release(&views);
return true;
}
static void
update_cycle(struct server *server)
{
struct cycle_state *cycle = &server->cycle;
if (rc.window_switcher.show) {
struct output *output;
wl_list_for_each(output, &server->outputs, link) {
if (output->cycle_osd.tree) {
get_osd_impl()->update(output);
}
}
}
if (rc.window_switcher.preview) { if (rc.window_switcher.preview) {
preview_selected_view(server->cycle.selected_view); preview_selected_view(cycle->selected_view);
} }
/* Outline current window */ /* Outline current window */
@ -331,11 +323,9 @@ update_cycle(struct server *server)
update_preview_outlines(server->cycle.selected_view); update_preview_outlines(server->cycle.selected_view);
} }
} }
out:
wl_array_release(&views);
} }
/* Resets all the states in server->cycle */
static void static void
destroy_cycle(struct server *server) destroy_cycle(struct server *server)
{ {
@ -351,4 +341,13 @@ destroy_cycle(struct server *server)
output->cycle_osd.tree = NULL; output->cycle_osd.tree = NULL;
} }
} }
restore_preview_node(server);
if (server->cycle.preview_outline) {
wlr_scene_node_destroy(&server->cycle.preview_outline->tree->node);
server->cycle.preview_outline = NULL;
}
server->cycle.selected_view = NULL;
} }

View file

@ -2616,7 +2616,9 @@ view_destroy(struct view *view)
zfree(view->tiled_region_evacuate); zfree(view->tiled_region_evacuate);
} }
cycle_on_view_destroy(view); /* TODO: call this on map/unmap instead */
cycle_reinitialize(server);
undecorate(view); undecorate(view);
view_set_icon(view, NULL, NULL); view_set_icon(view, NULL, NULL);