]> git.mdlowis.com Git - proto/labwc.git/commitdiff
cycle: clarify the lifecycle of window switcher
authortokyo4j <hrak1529@gmail.com>
Sun, 30 Nov 2025 13:10:58 +0000 (22:10 +0900)
committerJohan Malm <johanmalm@users.noreply.github.com>
Sun, 30 Nov 2025 21:33:46 +0000 (21:33 +0000)
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.

include/cycle.h
src/cycle/cycle.c
src/view.c

index d7d20991ef7b4aa4cf919c35813bbbb7a4a6f8a0..d4ac72fca982d75a5fd050058afedc498fc3b1e5 100644 (file)
@@ -56,8 +56,8 @@ void cycle_step(struct server *server, enum lab_cycle_dir direction);
 /* Closes the OSD */
 void cycle_finish(struct server *server, bool switch_focus);
 
-/* Notify OSD about a destroying view */
-void cycle_on_view_destroy(struct view *view);
+/* Re-initialize the window switcher */
+void cycle_reinitialize(struct server *server);
 
 /* Focus the clicked window and close OSD */
 void cycle_on_cursor_release(struct server *server, struct wlr_scene_node *node);
index 9d5750d450cd265805308dc2bc915da5f4870f38..85d37faafadee29f1b4c680c87a389c76bbcfcdb 100644 (file)
@@ -17,6 +17,7 @@
 #include "theme.h"
 #include "view.h"
 
+static bool init_cycle(struct server *server);
 static void update_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
-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;
 
        if (server->input_mode != LAB_INPUT_STATE_CYCLE) {
@@ -91,31 +90,15 @@ cycle_on_view_destroy(struct view *view)
                return;
        }
 
-       if (cycle->selected_view == view) {
-               /*
-                * If we are the current OSD selected view, cycle
-                * to the next because we are dying.
-                */
-
-               /* 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);
+       destroy_cycle(server);
+       if (init_cycle(server)) {
+               /* TODO: try to select the same view */
+               cycle->selected_view = get_next_selected_view(server, NULL,
+                       LAB_CYCLE_DIR_FORWARD);
                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_dummy = NULL;
+               server->cycle.preview_was_enabled = false;
                server->cycle.preview_was_shaded = false;
        }
 }
@@ -160,6 +144,10 @@ cycle_begin(struct server *server, enum lab_cycle_dir direction)
                return;
        }
 
+       if (!init_cycle(server)) {
+               return;
+       }
+
        server->cycle.selected_view = get_next_selected_view(server,
                server->cycle.selected_view, direction);
 
@@ -188,23 +176,11 @@ cycle_finish(struct server *server, bool switch_focus)
                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;
-       server->cycle.preview_node = NULL;
-       server->cycle.preview_dummy = NULL;
-       server->cycle.selected_view = NULL;
-       server->cycle.preview_was_shaded = false;
-
        destroy_cycle(server);
 
-       if (server->cycle.preview_outline) {
-               /* Destroy the whole multi_rect so we can easily react to new themes */
-               wlr_scene_node_destroy(&server->cycle.preview_outline->tree->node);
-               server->cycle.preview_outline = NULL;
-       }
+       /* FIXME: this sets focus to the old surface even with switch_focus=true */
+       seat_focus_override_end(&server->seat);
 
        /* Hiding OSD may need a cursor change */
        cursor_update_focus(server);
@@ -270,42 +246,40 @@ get_osd_impl(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)) {
                return;
        }
-       if (!output->cycle_osd.tree) {
-               get_osd_impl()->create(output, views);
-               assert(output->cycle_osd.tree);
-       }
-       get_osd_impl()->update(output);
+       get_osd_impl()->create(output, views);
+       assert(output->cycle_osd.tree);
 }
 
-static void
-update_cycle(struct server *server)
+/* Return false on failure */
+static bool
+init_cycle(struct server *server)
 {
        struct wl_array views;
        wl_array_init(&views);
        view_array_append(server, &views, rc.window_switcher.criteria);
-
-       if (!wl_array_len(&views) || !server->cycle.selected_view) {
-               cycle_finish(server, /*switch_focus*/ false);
-               goto out;
+       if (wl_array_len(&views) <= 0) {
+               wlr_log(WLR_DEBUG, "no views to switch between");
+               wl_array_release(&views);
+               return false;
        }
 
        if (rc.window_switcher.show) {
-               /* Display the actual OSD */
+               /* Create OSD */
                switch (rc.window_switcher.output_criteria) {
                case CYCLE_OSD_OUTPUT_ALL: {
                        struct output *output;
                        wl_list_for_each(output, &server->outputs, link) {
-                               update_osd_on_output(output, &views);
+                               create_osd_on_output(output, &views);
                        }
                        break;
                }
                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;
                case CYCLE_OSD_OUTPUT_KEYBOARD: {
                        struct output *output;
@@ -315,14 +289,32 @@ update_cycle(struct server *server)
                                /* Fallback to pointer, if there is no active_view */
                                output = output_nearest_to_cursor(server);
                        }
-                       update_osd_on_output(output, &views);
+                       create_osd_on_output(output, &views);
                        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) {
-               preview_selected_view(server->cycle.selected_view);
+               preview_selected_view(cycle->selected_view);
        }
 
        /* Outline current window */
@@ -331,11 +323,9 @@ update_cycle(struct server *server)
                        update_preview_outlines(server->cycle.selected_view);
                }
        }
-
-out:
-       wl_array_release(&views);
 }
 
+/* Resets all the states in server->cycle */
 static void
 destroy_cycle(struct server *server)
 {
@@ -351,4 +341,13 @@ destroy_cycle(struct server *server)
                        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;
 }
index 473a1b376519fbfc9faec0f7e2ac1814603d6620..d56c3fea6917a8aa57f95b51aee0a6103b1aea74 100644 (file)
@@ -2616,7 +2616,9 @@ view_destroy(struct view *view)
                zfree(view->tiled_region_evacuate);
        }
 
-       cycle_on_view_destroy(view);
+       /* TODO: call this on map/unmap instead */
+       cycle_reinitialize(server);
+
        undecorate(view);
 
        view_set_icon(view, NULL, NULL);