mirror of
https://github.com/labwc/labwc.git
synced 2026-03-20 05:34:12 -04:00
src/menu: prevent delayed pipe menu response on item destroy (#2094)
Without this patch we would happily access `pipe_ctx->item` members even if the item had been destroyed in the meantime.
This commit is contained in:
parent
c4b8b53198
commit
5ae9eed1ac
2 changed files with 41 additions and 18 deletions
|
|
@ -39,6 +39,7 @@ struct menuitem {
|
||||||
struct wlr_scene_tree *tree;
|
struct wlr_scene_tree *tree;
|
||||||
struct menu_scene normal;
|
struct menu_scene normal;
|
||||||
struct menu_scene selected;
|
struct menu_scene selected;
|
||||||
|
struct menu_pipe_context *pipe_ctx;
|
||||||
struct wl_list link; /* menu.menuitems */
|
struct wl_list link; /* menu.menuitems */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -40,6 +40,16 @@ static struct menu *current_menu;
|
||||||
static bool waiting_for_pipe_menu;
|
static bool waiting_for_pipe_menu;
|
||||||
static struct menuitem *selected_item;
|
static struct menuitem *selected_item;
|
||||||
|
|
||||||
|
struct menu_pipe_context {
|
||||||
|
struct server *server;
|
||||||
|
struct menuitem *item;
|
||||||
|
struct buf buf;
|
||||||
|
struct wl_event_source *event_read;
|
||||||
|
struct wl_event_source *event_timeout;
|
||||||
|
pid_t pid;
|
||||||
|
int pipe_fd;
|
||||||
|
};
|
||||||
|
|
||||||
/* TODO: split this whole file into parser.c and actions.c*/
|
/* TODO: split this whole file into parser.c and actions.c*/
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
|
|
@ -347,6 +357,9 @@ fill_item(char *nodename, char *content)
|
||||||
static void
|
static void
|
||||||
item_destroy(struct menuitem *item)
|
item_destroy(struct menuitem *item)
|
||||||
{
|
{
|
||||||
|
if (item->pipe_ctx) {
|
||||||
|
item->pipe_ctx->item = NULL;
|
||||||
|
}
|
||||||
wl_list_remove(&item->link);
|
wl_list_remove(&item->link);
|
||||||
action_list_free(&item->actions);
|
action_list_free(&item->actions);
|
||||||
wlr_scene_node_destroy(&item->tree->node);
|
wlr_scene_node_destroy(&item->tree->node);
|
||||||
|
|
@ -1086,27 +1099,19 @@ menu_open_root(struct menu *menu, int x, int y)
|
||||||
selected_item = NULL;
|
selected_item = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct pipe_context {
|
|
||||||
struct server *server;
|
|
||||||
struct menuitem *item;
|
|
||||||
struct buf buf;
|
|
||||||
struct wl_event_source *event_read;
|
|
||||||
struct wl_event_source *event_timeout;
|
|
||||||
pid_t pid;
|
|
||||||
int pipe_fd;
|
|
||||||
};
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
create_pipe_menu(struct pipe_context *ctx)
|
create_pipe_menu(struct menu_pipe_context *ctx)
|
||||||
{
|
{
|
||||||
|
assert(ctx->item);
|
||||||
|
|
||||||
struct menu *pipe_parent = ctx->item->parent;
|
struct menu *pipe_parent = ctx->item->parent;
|
||||||
if (!pipe_parent) {
|
if (!pipe_parent) {
|
||||||
wlr_log(WLR_ERROR, "[pipemenu %ld] invalid parent",
|
wlr_log(WLR_INFO, "[pipemenu %ld] invalid parent",
|
||||||
(long)ctx->pid);
|
(long)ctx->pid);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!pipe_parent->scene_tree->node.enabled) {
|
if (!pipe_parent->scene_tree->node.enabled) {
|
||||||
wlr_log(WLR_ERROR, "[pipemenu %ld] parent menu already closed",
|
wlr_log(WLR_INFO, "[pipemenu %ld] parent menu already closed",
|
||||||
(long)ctx->pid);
|
(long)ctx->pid);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -1153,12 +1158,15 @@ restore_menus:
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
pipemenu_ctx_destroy(struct pipe_context *ctx)
|
pipemenu_ctx_destroy(struct menu_pipe_context *ctx)
|
||||||
{
|
{
|
||||||
wl_event_source_remove(ctx->event_read);
|
wl_event_source_remove(ctx->event_read);
|
||||||
wl_event_source_remove(ctx->event_timeout);
|
wl_event_source_remove(ctx->event_timeout);
|
||||||
spawn_piped_close(ctx->pid, ctx->pipe_fd);
|
spawn_piped_close(ctx->pid, ctx->pipe_fd);
|
||||||
buf_reset(&ctx->buf);
|
buf_reset(&ctx->buf);
|
||||||
|
if (ctx->item) {
|
||||||
|
ctx->item->pipe_ctx = NULL;
|
||||||
|
}
|
||||||
free(ctx);
|
free(ctx);
|
||||||
waiting_for_pipe_menu = false;
|
waiting_for_pipe_menu = false;
|
||||||
}
|
}
|
||||||
|
|
@ -1166,9 +1174,9 @@ pipemenu_ctx_destroy(struct pipe_context *ctx)
|
||||||
static int
|
static int
|
||||||
handle_pipemenu_timeout(void *_ctx)
|
handle_pipemenu_timeout(void *_ctx)
|
||||||
{
|
{
|
||||||
struct pipe_context *ctx = _ctx;
|
struct menu_pipe_context *ctx = _ctx;
|
||||||
wlr_log(WLR_ERROR, "[pipemenu %ld] timeout reached, killing %s",
|
wlr_log(WLR_ERROR, "[pipemenu %ld] timeout reached, killing %s",
|
||||||
(long)ctx->pid, ctx->item->execute);
|
(long)ctx->pid, ctx->item ? ctx->item->execute : "n/a");
|
||||||
kill(ctx->pid, SIGTERM);
|
kill(ctx->pid, SIGTERM);
|
||||||
pipemenu_ctx_destroy(ctx);
|
pipemenu_ctx_destroy(ctx);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
@ -1183,11 +1191,19 @@ starts_with_less_than(const char *s)
|
||||||
static int
|
static int
|
||||||
handle_pipemenu_readable(int fd, uint32_t mask, void *_ctx)
|
handle_pipemenu_readable(int fd, uint32_t mask, void *_ctx)
|
||||||
{
|
{
|
||||||
struct pipe_context *ctx = _ctx;
|
struct menu_pipe_context *ctx = _ctx;
|
||||||
/* two 4k pages + 1 NULL byte */
|
/* two 4k pages + 1 NULL byte */
|
||||||
char data[8193];
|
char data[8193];
|
||||||
ssize_t size;
|
ssize_t size;
|
||||||
|
|
||||||
|
if (!ctx->item) {
|
||||||
|
/* parent menu item got destroyed in the meantime */
|
||||||
|
wlr_log(WLR_INFO, "[pipemenu %ld] parent menu item destroyed",
|
||||||
|
(long)ctx->pid);
|
||||||
|
kill(ctx->pid, SIGTERM);
|
||||||
|
goto clean_up;
|
||||||
|
}
|
||||||
|
|
||||||
do {
|
do {
|
||||||
/* leave space for terminating NULL byte */
|
/* leave space for terminating NULL byte */
|
||||||
size = read(fd, data, sizeof(data) - 1);
|
size = read(fd, data, sizeof(data) - 1);
|
||||||
|
|
@ -1235,6 +1251,11 @@ parse_pipemenu(struct menuitem *item)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (item->pipe_ctx) {
|
||||||
|
wlr_log(WLR_ERROR, "item already has a pipe context attached");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
int pipe_fd = 0;
|
int pipe_fd = 0;
|
||||||
pid_t pid = spawn_piped(item->execute, &pipe_fd);
|
pid_t pid = spawn_piped(item->execute, &pipe_fd);
|
||||||
if (pid <= 0) {
|
if (pid <= 0) {
|
||||||
|
|
@ -1243,12 +1264,13 @@ parse_pipemenu(struct menuitem *item)
|
||||||
}
|
}
|
||||||
|
|
||||||
waiting_for_pipe_menu = true;
|
waiting_for_pipe_menu = true;
|
||||||
struct pipe_context *ctx = znew(*ctx);
|
struct menu_pipe_context *ctx = znew(*ctx);
|
||||||
ctx->server = item->parent->server;
|
ctx->server = item->parent->server;
|
||||||
ctx->item = item;
|
ctx->item = item;
|
||||||
ctx->pid = pid;
|
ctx->pid = pid;
|
||||||
ctx->pipe_fd = pipe_fd;
|
ctx->pipe_fd = pipe_fd;
|
||||||
ctx->buf = BUF_INIT;
|
ctx->buf = BUF_INIT;
|
||||||
|
item->pipe_ctx = ctx;
|
||||||
|
|
||||||
ctx->event_read = wl_event_loop_add_fd(ctx->server->wl_event_loop,
|
ctx->event_read = wl_event_loop_add_fd(ctx->server->wl_event_loop,
|
||||||
pipe_fd, WL_EVENT_READABLE, handle_pipemenu_readable, ctx);
|
pipe_fd, WL_EVENT_READABLE, handle_pipemenu_readable, ctx);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue