src/menu: Attach view to menu and use it when executing actions

This fixes #380
This commit is contained in:
Consolatis 2022-06-09 17:10:36 +02:00 committed by Johan Malm
parent ca9226a7a6
commit 5a4c5de332
5 changed files with 63 additions and 30 deletions

View file

@ -4,7 +4,12 @@
#include <wayland-server.h> #include <wayland-server.h>
/* forward declare arguments */
struct view;
struct server;
struct wl_list;
struct lab_data_buffer; struct lab_data_buffer;
struct wlr_scene_tree;
struct wlr_scene_node; struct wlr_scene_node;
enum menu_align { enum menu_align {
@ -49,6 +54,9 @@ struct menu {
struct menuitem *item; struct menuitem *item;
} selection; } selection;
struct wlr_scene_tree *scene_tree; struct wlr_scene_tree *scene_tree;
/* Used to match a window-menu to the view that triggered it. */
struct view *triggered_by_view; /* may be NULL */
}; };
void menu_init_rootmenu(struct server *server); void menu_init_rootmenu(struct server *server);
@ -92,8 +100,15 @@ void menu_process_cursor_motion(struct wlr_scene_node *node);
*/ */
bool menu_call_actions(struct wlr_scene_node *node); bool menu_call_actions(struct wlr_scene_node *node);
/* menu_close - close menu */ /**
void menu_close(struct menu *menu); * menu_close_root- close root menu
*
* This function will close server->menu_current and set it to NULL.
* Asserts that server->input_mode is set to LAB_INPUT_STATE_MENU.
*
* Additionally, server->input_mode wil be set to LAB_INPUT_STATE_PASSTHROUGH.
*/
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);

View file

@ -121,6 +121,8 @@ show_menu(struct server *server, struct view *view, const char *menu_name)
x = server->seat.cursor->x; x = server->seat.cursor->x;
y = server->seat.cursor->y; y = server->seat.cursor->y;
} }
/* Replaced by next show_menu() or cleaned on view_destroy() */
menu->triggered_by_view = view;
menu_open(menu, x, y); menu_open(menu, x, y);
} }

View file

@ -718,13 +718,8 @@ cursor_button(struct wl_listener *listener, void *data)
seat->pressed.surface = NULL; seat->pressed.surface = NULL;
if (server->input_mode == LAB_INPUT_STATE_MENU) { if (server->input_mode == LAB_INPUT_STATE_MENU) {
if (close_menu) { if (close_menu) {
if (server->menu_current) { menu_close_root(server);
menu_close(server->menu_current); cursor_rebase(&server->seat, event->time_msec, false);
server->menu_current = NULL;
}
server->input_mode = LAB_INPUT_STATE_PASSTHROUGH;
cursor_rebase(&server->seat,
event->time_msec, false);
close_menu = false; close_menu = false;
} }
return; return;
@ -755,17 +750,11 @@ cursor_button(struct wl_listener *listener, void *data)
} }
if (server->input_mode == LAB_INPUT_STATE_MENU) { if (server->input_mode == LAB_INPUT_STATE_MENU) {
/* We are closing the menu on RELEASE to not leak a stray release */
if (view_area != LAB_SSD_MENU) { if (view_area != LAB_SSD_MENU) {
/*
* We close the menu on release so we don't leak a stray
* release
*/
close_menu = true; close_menu = true;
} else if (menu_call_actions(node)) { } else if (menu_call_actions(node)) {
/* /* Action was successfull, may fail if item just opens a submenu */
* Action was successfull, may fail if item just opens a
* submenu
*/
close_menu = true; close_menu = true;
} }
return; return;

View file

@ -548,6 +548,21 @@ close_all_submenus(struct menu *menu)
menu->selection.menu = NULL; menu->selection.menu = NULL;
} }
static void
menu_close(struct menu *menu)
{
if (!menu) {
wlr_log(WLR_ERROR, "Trying to close non exiting menu");
return;
}
wlr_scene_node_set_enabled(&menu->scene_tree->node, false);
menu_set_selection(menu, NULL);
if (menu->selection.menu) {
menu_close(menu->selection.menu);
menu->selection.menu = NULL;
}
}
void void
menu_open(struct menu *menu, int x, int y) menu_open(struct menu *menu, int x, int y)
{ {
@ -582,7 +597,9 @@ menu_process_cursor_motion(struct wlr_scene_node *node)
} }
if (item->submenu) { if (item->submenu) {
/* And open the new one */ /* Sync the triggering view */
item->submenu->triggered_by_view = item->parent->triggered_by_view;
/* And open the new submenu tree */
wlr_scene_node_set_enabled( wlr_scene_node_set_enabled(
&item->submenu->scene_tree->node, true); &item->submenu->scene_tree->node, true);
} }
@ -600,26 +617,29 @@ menu_call_actions(struct wlr_scene_node *node)
return false; return false;
} }
actions_run(NULL, item->parent->server, &item->actions, 0); actions_run(item->parent->triggered_by_view,
item->parent->server, &item->actions, 0);
/**
* We close the menu here to provide a faster feedback to the user.
* We do that without resetting the input state so src/cursor.c
* can do its own clean up on the following RELEASE event.
*/
menu_close(item->parent->server->menu_current); menu_close(item->parent->server->menu_current);
item->parent->server->menu_current = NULL; item->parent->server->menu_current = NULL;
return true; return true;
} }
void void
menu_close(struct menu *menu) menu_close_root(struct server *server)
{ {
if (!menu) { assert(server->input_mode == LAB_INPUT_STATE_MENU);
wlr_log(WLR_ERROR, "Trying to close non exiting menu"); if (server->menu_current) {
return; menu_close(server->menu_current);
} server->menu_current = NULL;
/* TODO: Maybe reset input state here instead of in cursor.c ? */
wlr_scene_node_set_enabled(&menu->scene_tree->node, false);
menu_set_selection(menu, NULL);
if (menu->selection.menu) {
menu_close(menu->selection.menu);
menu->selection.menu = NULL;
} }
server->input_mode = LAB_INPUT_STATE_PASSTHROUGH;
} }
void void

View file

@ -5,6 +5,7 @@
#include <xcb/xcb_icccm.h> #include <xcb/xcb_icccm.h>
#include "labwc.h" #include "labwc.h"
#include "ssd.h" #include "ssd.h"
#include "menu/menu.h"
#define MAX(a, b) (((a) > (b)) ? (a) : (b)) #define MAX(a, b) (((a) > (b)) ? (a) : (b))
@ -756,6 +757,12 @@ view_destroy(struct view *view)
wlr_scene_node_set_enabled(&output->layer_tree[top]->node, true); wlr_scene_node_set_enabled(&output->layer_tree[top]->node, true);
} }
/* If we spawned a window menu, close it */
if (server->menu_current
&& server->menu_current->triggered_by_view == view) {
menu_close_root(server);
}
/* Remove view from server->views */ /* Remove view from server->views */
wl_list_remove(&view->link); wl_list_remove(&view->link);
free(view); free(view);