]> git.mdlowis.com Git - proto/labwc.git/commitdiff
menu: lazily generate menu scenes
authortokyo4j <hrak1529@gmail.com>
Sun, 9 Mar 2025 15:00:39 +0000 (00:00 +0900)
committerHiroaki Yamamoto <hrak1529@gmail.com>
Mon, 10 Mar 2025 07:16:20 +0000 (16:16 +0900)
This removes the need to call update_client_list_combined_menu()
and update_client_send_to_menu() every time a root menu is opened.

This commit also fixed the incorrect menu position with following
configuration:
  <menu id="foo" label="foo">
    <item label="aaaaaa"/>
    <item label="bbbbbb"/>
  </menu>
  <menu id="root-menu">
    <menu id="foo" />
    <menu id="foo" />
  </menu>

include/menu/menu.h
src/action.c
src/menu/menu.c

index ef336d294a263151b2b59a0d5b18ffbf75937551..f69e902ab2df3ff4f7109eb5a76d96a8b41df75a 100644 (file)
@@ -127,7 +127,4 @@ void menu_close_root(struct server *server);
 /* menu_reconfigure - reload theme and content */
 void menu_reconfigure(struct server *server);
 
-void update_client_list_combined_menu(struct server *server);
-void update_client_send_to_menu(struct server *server);
-
 #endif /* LABWC_MENU_H */
index 6f99cc4602e4426f7b609a3ef097ad22274fbb49..07b5c6a636f7a855c81005b1ac0737c8d509deb5 100644 (file)
@@ -664,16 +664,6 @@ show_menu(struct server *server, struct view *view, struct cursor_context *ctx,
                return;
        }
 
-       /*
-        * We always refresh client-list-combined-menu and client-send-to-menu
-        * so that they are up-to-date whether they are directly opened as a
-        * top-level menu or opened as a submenu which we don't know at this
-        * point. It is also needed to calculate the proper width for placement
-        * as it fluctuates depending on application/workspace titles.
-        */
-       update_client_list_combined_menu(menu->server);
-       update_client_send_to_menu(menu->server);
-
        int x = server->seat.cursor->x;
        int y = server->seat.cursor->y;
 
index 0605b1f6d7636cacfca3e21567b1ea2f460b40fb..ebf16419dcddd26042007798b52482dcbb1063be 100644 (file)
@@ -362,19 +362,30 @@ title_create_scene(struct menuitem *menuitem, int *item_y)
        *item_y += theme->menu_header_height;
 }
 
-/* (Re)creates the scene of the menu */
+static void item_destroy(struct menuitem *item);
+
 static void
-menu_update_scene(struct menu *menu)
+reset_menu(struct menu *menu)
 {
-       struct menuitem *item;
-       struct theme *theme = menu->server->theme;
-
+       struct menuitem *item, *next;
+       wl_list_for_each_safe(item, next, &menu->menuitems, link) {
+               item_destroy(item);
+       }
        if (menu->scene_tree) {
                wlr_scene_node_destroy(&menu->scene_tree->node);
-               wl_list_for_each(item, &menu->menuitems, link) {
-                       item->tree = NULL;
-               }
+               menu->scene_tree = NULL;
        }
+       /* TODO: also reset other fields? */
+}
+
+static void
+menu_create_scene(struct menu *menu)
+{
+       struct menuitem *item;
+       struct theme *theme = menu->server->theme;
+
+       assert(!menu->scene_tree);
+
        menu->scene_tree = wlr_scene_tree_create(menu->server->menu_tree);
        wlr_scene_node_set_enabled(&menu->scene_tree->node, false);
 
@@ -420,22 +431,6 @@ menu_update_scene(struct menu *menu)
        wlr_scene_node_lower_to_bottom(&bg_buffer->scene_buffer->node);
 }
 
-static void
-post_processing(struct server *server)
-{
-       /*
-        * Create menu scene after all of its contents is determined
-        * (e.g. when finished reading menu.xml or received output from
-        * pipemenu program).
-        */
-       struct menu *menu;
-       wl_list_for_each(menu, &server->menus, link) {
-               if (!menu->scene_tree) {
-                       menu_update_scene(menu);
-               }
-       }
-}
-
 /*
  * Handle the following:
  * <item label="">
@@ -916,8 +911,6 @@ get_item_anchor_rect(struct theme *theme, struct menuitem *item)
 static void
 menu_reposition(struct menu *menu, struct wlr_box anchor_rect)
 {
-       struct theme *theme = menu->server->theme;
-
        /* Get output usable area to place the menu within */
        struct output *output = output_nearest_to(menu->server,
                anchor_rect.x, anchor_rect.y);
@@ -962,15 +955,6 @@ menu_reposition(struct menu *menu, struct wlr_box anchor_rect)
        wlr_scene_node_set_position(&menu->scene_tree->node, box.x, box.y);
 
        menu->align_left = (box.x < anchor_rect.x);
-
-       struct menuitem *item;
-       wl_list_for_each(item, &menu->menuitems, link) {
-               if (!item->submenu) {
-                       continue;
-               }
-               anchor_rect = get_item_anchor_rect(theme, item);
-               menu_reposition(item->submenu, anchor_rect);
-       }
 }
 
 static void
@@ -1006,20 +990,13 @@ init_client_send_to_menu(struct server *server)
  * with the workspace names that can be used with
  * SendToDesktop, left/right options are included.
  */
-void
+static void
 update_client_send_to_menu(struct server *server)
 {
-       struct menu *menu = menu_get_by_id(server,
-                       "client-send-to-menu");
-
-       if (menu) {
-               struct menuitem *item, *next;
-               wl_list_for_each_safe(item, next, &menu->menuitems, link) {
-                       item_destroy(item);
-               }
-       }
+       struct menu *menu = menu_get_by_id(server, "client-send-to-menu");
+       assert(menu);
 
-       menu->size.height = 0;
+       reset_menu(menu);
 
        struct workspace *workspace;
 
@@ -1036,7 +1013,7 @@ update_client_send_to_menu(struct server *server)
                fill_item("to.action", workspace->name);
        }
 
-       menu_update_scene(menu);
+       menu_create_scene(menu);
 }
 
 static void
@@ -1054,23 +1031,13 @@ init_client_list_combined_menu(struct server *server)
  * separator label and the titles of the view, if any, below each workspace
  * name. Active view is indicated by "*" preceding title.
  */
-void
+static void
 update_client_list_combined_menu(struct server *server)
 {
        struct menu *menu = menu_get_by_id(server, "client-list-combined-menu");
+       assert(menu);
 
-       if (!menu) {
-               /* Menu is created on compositor startup/reconfigure */
-               wlr_log(WLR_ERROR, "client-list-combined-menu does not exist");
-               return;
-       }
-
-       struct menuitem *item, *next;
-       wl_list_for_each_safe(item, next, &menu->menuitems, link) {
-               item_destroy(item);
-       }
-
-       menu->size.height = 0;
+       reset_menu(menu);
 
        struct workspace *workspace;
        struct view *view;
@@ -1108,7 +1075,7 @@ update_client_list_combined_menu(struct server *server)
                fill_item("to.action", workspace->name);
        }
        buf_reset(&buffer);
-       menu_update_scene(menu);
+       menu_create_scene(menu);
 }
 
 static void
@@ -1191,7 +1158,6 @@ menu_init(struct server *server)
        init_windowmenu(server);
        init_client_list_combined_menu(server);
        init_client_send_to_menu(server);
-       post_processing(server);
        validate(server);
 }
 
@@ -1358,6 +1324,23 @@ menu_close(struct menu *menu)
        _close(menu);
 }
 
+static void
+open_menu(struct menu *menu, struct wlr_box anchor_rect)
+{
+       if (!strcmp(menu->id, "client-list-combined-menu")) {
+               update_client_list_combined_menu(menu->server);
+       } else if (!strcmp(menu->id, "client-send-to-menu")) {
+               update_client_send_to_menu(menu->server);
+       }
+
+       if (!menu->scene_tree) {
+               menu_create_scene(menu);
+               assert(menu->scene_tree);
+       }
+       menu_reposition(menu, anchor_rect);
+       wlr_scene_node_set_enabled(&menu->scene_tree->node, true);
+}
+
 void
 menu_open_root(struct menu *menu, int x, int y)
 {
@@ -1369,8 +1352,7 @@ menu_open_root(struct menu *menu, int x, int y)
 
        assert(!menu->server->menu_current);
 
-       menu_reposition(menu, (struct wlr_box){.x = x, .y = y});
-       wlr_scene_node_set_enabled(&menu->scene_tree->node, true);
+       open_menu(menu, (struct wlr_box){.x = x, .y = y});
        menu->server->menu_current = menu;
        selected_item = NULL;
        seat_focus_override_begin(&menu->server->seat,
@@ -1402,9 +1384,7 @@ create_pipe_menu(struct menu_pipe_context *ctx)
                                ctx->top_level_menu->id);
                }
                menu_level--;
-               post_processing(ctx->server);
                validate(ctx->server);
-               menu_update_scene(current_menu);
                return;
        }
 
@@ -1445,12 +1425,9 @@ create_pipe_menu(struct menu_pipe_context *ctx)
         * operate from current point onwards
         */
 
-       /* Set menu-widths before configuring */
-       post_processing(ctx->server);
-
        struct wlr_box anchor_rect =
                get_item_anchor_rect(ctx->server->theme, ctx->item);
-       menu_reposition(pipe_menu, anchor_rect);
+       open_menu(pipe_menu, anchor_rect);
 
        validate(ctx->server);
 
@@ -1625,8 +1602,9 @@ menu_process_item_selection(struct menuitem *item)
                /* Ensure the submenu has its parent set correctly */
                item->submenu->parent = item->parent;
                /* And open the new submenu tree */
-               wlr_scene_node_set_enabled(
-                       &item->submenu->scene_tree->node, true);
+               struct wlr_box anchor_rect =
+                       get_item_anchor_rect(item->submenu->server->theme, item);
+               open_menu(item->submenu, anchor_rect);
        }
 
        item->parent->selection.menu = item->submenu;