menu: support client-list-combined-menu

...showing windows across all workspaces.

<action name="ShowMenu" menu="client-list-combined-menu"/>
This commit is contained in:
Droc 2024-09-17 06:52:10 -05:00 committed by Johan Malm
parent fc4bbca6f2
commit 71b2b5a4bc
5 changed files with 91 additions and 4 deletions

View file

@ -114,9 +114,10 @@ Actions are used in menus and keyboard/mouse bindings.
*<action name="ShowMenu" menu="value" atCursor="yes" />* *<action name="ShowMenu" menu="value" atCursor="yes" />*
Show a menu. Show a menu.
*menu* The name of the menu to show. The menus "root-menu" and *menu* The name of the menu to show. The menus "root-menu",
"client-menu" are guaranteed to exist, but others may be defined "client-menu", and "client-list-combined-menu" are guaranteed to exist,
explicitly. See labwc-menu(5) for more information. but others may be defined explicitly. See labwc-menu(5) for more
information.
*atCursor* [yes|no] When opening a menu, open the menu at the location *atCursor* [yes|no] When opening a menu, open the menu at the location
of the mouse cursor. When set to no, the menu will appear at the of the mouse cursor. When set to no, the menu will appear at the

View file

@ -48,6 +48,8 @@ The menu file must be entirely enclosed within <openbox_menu> and
ShowMenu action. Default identifiers are ShowMenu action. Default identifiers are
- "root-menu" for the root window context menu - "root-menu" for the root window context menu
- "client-menu" for a window's titlebar context menu - "client-menu" for a window's titlebar context menu
- "client-list-combined-menu" for a list of all windows across
all workspaces
*menu.id* (when nested under other *<menu>* element) *menu.id* (when nested under other *<menu>* element)
Link to a submenu defined elsewhere (by a *<menu id="">* at toplevel) Link to a submenu defined elsewhere (by a *<menu id="">* at toplevel)

View file

@ -47,6 +47,7 @@ struct menuitem {
struct menu_scene normal; struct menu_scene normal;
struct menu_scene selected; struct menu_scene selected;
struct menu_pipe_context *pipe_ctx; struct menu_pipe_context *pipe_ctx;
struct view *client_list_view; /* used by internal client-list */
struct wl_list link; /* menu.menuitems */ struct wl_list link; /* menu.menuitems */
}; };
@ -135,4 +136,6 @@ void menu_close_root(struct server *server);
/* menu_reconfigure - reload theme and content */ /* menu_reconfigure - reload theme and content */
void menu_reconfigure(struct server *server); void menu_reconfigure(struct server *server);
void update_client_list_combined_menu(struct server *server);
#endif /* LABWC_MENU_H */ #endif /* LABWC_MENU_H */

View file

@ -665,6 +665,11 @@ show_menu(struct server *server, struct view *view,
return; return;
} }
/* Need to refresh to show current windows and recalculate width */
if (!strcasecmp(menu_name, "client-list-combined-menu")) {
update_client_list_combined_menu(menu->server);
}
int x = server->seat.cursor->x; int x = server->seat.cursor->x;
int y = server->seat.cursor->y; int y = server->seat.cursor->y;

View file

@ -23,6 +23,8 @@
#include "common/string-helpers.h" #include "common/string-helpers.h"
#include "labwc.h" #include "labwc.h"
#include "menu/menu.h" #include "menu/menu.h"
#include "workspaces.h"
#include "view.h"
#include "node.h" #include "node.h"
#include "theme.h" #include "theme.h"
@ -908,6 +910,73 @@ menu_hide_submenu(struct server *server, const char *id)
} }
} }
static void
init_client_list_combined_menu(struct server *server)
{
/* Just create placeholder. Contents will be created when launched */
menu_create(server, "client-list-combined-menu", "");
}
/*
* This is client-list-combined-menu an internal menu similar to root-menu and
* client-menu.
*
* This will look at workspaces and produce a menu with the workspace name as a
* separator label and the titles of the view, if any, below each workspace
* name. Active view is indicated by "*" preceeding title.
*/
void
update_client_list_combined_menu(struct server *server)
{
struct menu *menu = menu_get_by_id(server, "client-list-combined-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;
struct workspace *workspace;
struct view *view;
struct buf buffer = BUF_INIT;
wl_list_for_each(workspace, &server->workspaces, link) {
buf_add_fmt(&buffer, workspace == server->workspace_current ? ">%s<" : "%s",
workspace->name);
current_item = separator_create(menu, buffer.data);
buf_clear(&buffer);
wl_list_for_each(view, &server->views, link) {
if (view->workspace == workspace) {
if (view == server->active_view) {
buf_add(&buffer, "*");
}
buf_add(&buffer, view_get_string_prop(view, "title"));
current_item = item_create(menu, buffer.data, /*show arrow*/ false);
current_item->id = xstrdup(menu->id);
current_item->client_list_view = view;
fill_item("name.action", "Focus");
fill_item("name.action", "Raise");
buf_clear(&buffer);
}
}
current_item = item_create(menu, _("Go there..."), /*show arrow*/ false);
current_item->id = xstrdup(menu->id);
fill_item("name.action", "GoToDesktop");
fill_item("to.action", workspace->name);
}
buf_reset(&buffer);
menu_update_width(menu);
}
static void static void
init_rootmenu(struct server *server) init_rootmenu(struct server *server)
{ {
@ -986,6 +1055,7 @@ menu_init(struct server *server)
parse_xml("menu.xml", server); parse_xml("menu.xml", server);
init_rootmenu(server); init_rootmenu(server);
init_windowmenu(server); init_windowmenu(server);
init_client_list_combined_menu(server);
post_processing(server); post_processing(server);
validate(server); validate(server);
} }
@ -1467,7 +1537,13 @@ menu_execute_item(struct menuitem *item)
* menu_close() and destroy_pipemenus() which we have to handle * menu_close() and destroy_pipemenus() which we have to handle
* before/after action_run() respectively. * before/after action_run() respectively.
*/ */
actions_run(item->parent->triggered_by_view, server, &item->actions, 0); if (item->id && !strcmp(item->id, "client-list-combined-menu")
&& item->client_list_view) {
actions_run(item->client_list_view, server, &item->actions, 0);
} else {
actions_run(item->parent->triggered_by_view, server,
&item->actions, 0);
}
server->menu_current = NULL; server->menu_current = NULL;
destroy_pipemenus(server); destroy_pipemenus(server);