diff --git a/cmd-send-keys.c b/cmd-send-keys.c index 814755f3..fd1c1ab9 100644 --- a/cmd-send-keys.c +++ b/cmd-send-keys.c @@ -67,7 +67,7 @@ cmd_send_keys_inject(struct client *c, struct cmd_find_state *fs, if (wme == NULL || wme->mode->key_table == NULL) { if (options_get_number(fs->wp->window->options, "xterm-keys")) key |= KEYC_XTERM; - window_pane_key(fs->wp, NULL, fs->s, fs->wl, key, NULL); + window_pane_key(fs->wp, item->client, fs->s, fs->wl, key, NULL); return (item); } table = key_bindings_get_table(wme->mode->key_table(wme), 1); @@ -132,7 +132,7 @@ cmd_send_keys_exec(struct cmd *self, struct cmdq_item *item) cmdq_error(item, "no mouse target"); return (CMD_RETURN_ERROR); } - window_pane_key(wp, NULL, s, wl, m->key, m); + window_pane_key(wp, item->client, s, wl, m->key, m); return (CMD_RETURN_NORMAL); } diff --git a/key-bindings.c b/key-bindings.c index ca4fdc52..c4874b50 100644 --- a/key-bindings.c +++ b/key-bindings.c @@ -278,8 +278,8 @@ key_bindings_init(void) "bind -n WheelDownStatus next-window", "bind -n WheelUpStatus previous-window", "bind -n MouseDrag1Pane if -Ft= '#{mouse_any_flag}' 'if -Ft= \"#{pane_in_mode}\" \"copy-mode -M\" \"send-keys -M\"' 'copy-mode -M'", - "bind -n MouseDown3Pane if-shell -Ft= '#{mouse_any_flag}' 'select-pane -t=; send-keys -M' 'select-pane -mt='", - "bind -n WheelUpPane if-shell -Ft= '#{mouse_any_flag}' 'send-keys -M' 'if -Ft= \"#{pane_in_mode}\" \"send-keys -M\" \"copy-mode -et=\"'", + "bind -n MouseDown3Pane if -Ft= '#{||:mouse_any_flag,pane_in_mode}' 'select-pane -t=; send-keys -M' 'select-pane -mt='", + "bind -n WheelUpPane if -Ft= '#{mouse_any_flag}' 'send-keys -M' 'if -Ft= \"#{pane_in_mode}\" \"send-keys -M\" \"copy-mode -et=\"'", "bind -n MouseDown3StatusRight display-menu -t= -xM -yS -F -M \"#{client_menu}\" -T \"#[align=centre]#{client_name}\"", "bind -n MouseDown3StatusLeft display-menu -t= -xM -yS -F -M \"#{session_menu}\" -T \"#[align=centre]#{session_name}\"", "bind -n MouseDown3Status display-menu -t= -xW -yS -F -M \"#{window_menu}\" -T \"#[align=centre]#{window_index}:#{window_name}\"", diff --git a/menu.c b/menu.c index bd5996da..945b62c4 100644 --- a/menu.c +++ b/menu.c @@ -56,7 +56,11 @@ menu_add_item(struct menu *menu, struct menu_item *item, struct client *c, if (item == NULL || *item->name == '\0') /* horizontal line */ return; - name = format_single(NULL, item->name, c, fs->s, fs->wl, fs->wp); + if (fs != NULL) { + name = format_single(NULL, item->name, c, fs->s, fs->wl, + fs->wp); + } else + name = xstrdup(item->name); if (*name == '\0') { /* no item if empty after format expanded */ menu->count--; return; @@ -118,7 +122,6 @@ menu_create(const char *s, struct client *c, struct cmd_find_state *fs, copy = string = xstrdup(s); do { next = (char *)format_skip(string, "|"); - log_debug("XXX %s -- %s", next, string); if (next != NULL) *next++ = '\0'; if (*string == '\0') @@ -180,6 +183,9 @@ menu_free_cb(struct client *c) if (md->item != NULL) md->item->flags &= ~CMDQ_WAITING; + if (md->cb != NULL) + md->cb(md->menu, UINT_MAX, KEYC_NONE, md->data); + screen_free(&md->s); menu_free(md->menu); free(md); @@ -274,6 +280,7 @@ chosen: return (1); if (md->cb != NULL) { md->cb(md->menu, md->choice, item->key, md->data); + md->cb = NULL; return (1); } cmdlist = cmd_string_parse(item->command, NULL, 0, &cause); @@ -308,7 +315,8 @@ menu_display(struct menu *menu, int flags, struct cmdq_item *item, u_int px, md->item = item; md->flags = flags; - cmd_find_copy_state(&md->fs, fs); + if (fs != NULL) + cmd_find_copy_state(&md->fs, fs); screen_init(&md->s, menu->width + 4, menu->count + 2, 0); md->px = px; diff --git a/mode-tree.c b/mode-tree.c index 60e23534..eb642826 100644 --- a/mode-tree.c +++ b/mode-tree.c @@ -35,6 +35,7 @@ struct mode_tree_data { struct window_pane *wp; void *modedata; + const char *menu; const char **sort_list; u_int sort_size; @@ -43,6 +44,7 @@ struct mode_tree_data { mode_tree_build_cb buildcb; mode_tree_draw_cb drawcb; mode_tree_search_cb searchcb; + mode_tree_menu_cb menucb; struct mode_tree_list children; struct mode_tree_list saved; @@ -89,8 +91,21 @@ struct mode_tree_line { int flat; }; +struct mode_tree_menu { + struct mode_tree_data *data; + struct client *c; + u_int line; + void *itemdata; +}; + static void mode_tree_free_items(struct mode_tree_list *); +#define MODE_TREE_MENU \ + "Scroll Left,<,|" \ + "Scroll Right,>,|" \ + "|" \ + "Cancel,q," + static struct mode_tree_item * mode_tree_find_item(struct mode_tree_list *mtl, uint64_t tag) { @@ -299,8 +314,9 @@ mode_tree_each_tagged(struct mode_tree_data *mtd, mode_tree_each_cb cb, struct mode_tree_data * mode_tree_start(struct window_pane *wp, struct args *args, mode_tree_build_cb buildcb, mode_tree_draw_cb drawcb, - mode_tree_search_cb searchcb, void *modedata, const char **sort_list, - u_int sort_size, struct screen **s) + mode_tree_search_cb searchcb, mode_tree_menu_cb menucb, void *modedata, + const char *menu, const char **sort_list, u_int sort_size, + struct screen **s) { struct mode_tree_data *mtd; const char *sort; @@ -311,6 +327,7 @@ mode_tree_start(struct window_pane *wp, struct args *args, mtd->wp = wp; mtd->modedata = modedata; + mtd->menu = menu; mtd->sort_list = sort_list; mtd->sort_size = sort_size; @@ -334,6 +351,7 @@ mode_tree_start(struct window_pane *wp, struct args *args, mtd->buildcb = buildcb; mtd->drawcb = drawcb; mtd->searchcb = searchcb; + mtd->menucb = menucb; TAILQ_INIT(&mtd->children); @@ -762,6 +780,71 @@ mode_tree_filter_free(void *data) mode_tree_remove_ref(data); } +static void +mode_tree_menu_callback(__unused struct menu *menu, __unused u_int idx, + key_code key, void *data) +{ + struct mode_tree_menu *mtm = data; + struct mode_tree_data *mtd = mtm->data; + struct mode_tree_item *mti; + + if (mtd->dead || key == KEYC_NONE) + goto out; + + if (mtm->line >= mtd->line_size) + goto out; + mti = mtd->line_list[mtm->line].item; + if (mti->itemdata != mtm->itemdata) + goto out; + mtd->current = mtm->line; + mtd->menucb (mtd->modedata, mtm->c, key); + +out: + mode_tree_remove_ref(mtd); + free(mtm); +} + +static void +mode_tree_display_menu(struct mode_tree_data *mtd, struct client *c, u_int x, + u_int y, int outside) +{ + struct mode_tree_item *mti; + struct menu *menu; + struct mode_tree_menu *mtm; + const char *s; + char *title; + u_int line; + + if (mtd->offset + y > mtd->line_size - 1) + line = mtd->current; + else + line = mtd->offset + y; + mti = mtd->line_list[line].item; + + if (!outside) { + s = mtd->menu; + xasprintf(&title, "#[align=centre]%s", mti->name); + } else { + s = MODE_TREE_MENU; + title = xstrdup(""); + } + menu = menu_create(s, c, NULL, title); + free(title); + if (menu == NULL) + return; + + mtm = xmalloc(sizeof *mtm); + mtm->data = mtd; + mtm->c = c; + mtm->line = line; + mtm->itemdata = mti->itemdata; + mtd->references++; + + if (menu_display(menu, 0, NULL, x, y, c, NULL, mode_tree_menu_callback, + mtm) != 0) + menu_free(menu); +} + int mode_tree_key(struct mode_tree_data *mtd, struct client *c, key_code *key, struct mouse_event *m, u_int *xp, u_int *yp) @@ -772,7 +855,7 @@ mode_tree_key(struct mode_tree_data *mtd, struct client *c, key_code *key, int choice; key_code tmp; - if (KEYC_IS_MOUSE(*key)) { + if (KEYC_IS_MOUSE(*key) && m != NULL) { if (cmd_mouse_at(mtd->wp, m, &x, &y, 0) != 0) { *key = KEYC_NONE; return (0); @@ -782,20 +865,29 @@ mode_tree_key(struct mode_tree_data *mtd, struct client *c, key_code *key, if (yp != NULL) *yp = y; if (x > mtd->width || y > mtd->height) { + if (*key == KEYC_MOUSEDOWN3_PANE) + mode_tree_display_menu(mtd, c, x, y, 1); if (!mtd->preview) *key = KEYC_NONE; return (0); } if (mtd->offset + y < mtd->line_size) { if (*key == KEYC_MOUSEDOWN1_PANE || + *key == KEYC_MOUSEDOWN3_PANE || *key == KEYC_DOUBLECLICK1_PANE) mtd->current = mtd->offset + y; if (*key == KEYC_DOUBLECLICK1_PANE) *key = '\r'; - else + else { + if (*key == KEYC_MOUSEDOWN3_PANE) + mode_tree_display_menu(mtd, c, x, y, 0); *key = KEYC_NONE; - } else + } + } else { + if (*key == KEYC_MOUSEDOWN3_PANE) + mode_tree_display_menu(mtd, c, x, y, 0); *key = KEYC_NONE; + } return (0); } @@ -879,7 +971,8 @@ mode_tree_key(struct mode_tree_data *mtd, struct client *c, key_code *key, current->tagged = 1; } else current->tagged = 0; - mode_tree_down(mtd, 0); + if (m != NULL) + mode_tree_down(mtd, 0); break; case 'T': for (i = 0; i < mtd->line_size; i++) diff --git a/tmux.h b/tmux.h index c00a468c..09e7ec9c 100644 --- a/tmux.h +++ b/tmux.h @@ -2408,8 +2408,9 @@ u_int layout_set_previous(struct window *); /* mode-tree.c */ typedef void (*mode_tree_build_cb)(void *, u_int, uint64_t *, const char *); typedef void (*mode_tree_draw_cb)(void *, void *, struct screen_write_ctx *, - u_int, u_int); + u_int, u_int); typedef int (*mode_tree_search_cb)(void *, void *, const char *); +typedef void (*mode_tree_menu_cb)(void *, struct client *, key_code); typedef void (*mode_tree_each_cb)(void *, void *, struct client *, key_code); u_int mode_tree_count_tagged(struct mode_tree_data *); void *mode_tree_get_current(struct mode_tree_data *); @@ -2420,7 +2421,8 @@ void mode_tree_each_tagged(struct mode_tree_data *, mode_tree_each_cb, void mode_tree_down(struct mode_tree_data *, int); struct mode_tree_data *mode_tree_start(struct window_pane *, struct args *, mode_tree_build_cb, mode_tree_draw_cb, mode_tree_search_cb, - void *, const char **, u_int, struct screen **); + mode_tree_menu_cb, void *, const char *, const char **, u_int, + struct screen **); void mode_tree_zoom(struct mode_tree_data *, struct args *); void mode_tree_build(struct mode_tree_data *); void mode_tree_free(struct mode_tree_data *); diff --git a/window-buffer.c b/window-buffer.c index c7e345c0..3597fbf2 100644 --- a/window-buffer.c +++ b/window-buffer.c @@ -39,6 +39,19 @@ static void window_buffer_key(struct window_mode_entry *, #define WINDOW_BUFFER_DEFAULT_FORMAT \ "#{buffer_size} bytes (#{t:buffer_created})" +#define WINDOW_BUFFER_MENU \ + "Paste,p,|" \ + "Paste Tagged,P,|" \ + "|" \ + "Tag,t,|" \ + "Tag All,C-t,|" \ + "Tag None,T,|" \ + "|" \ + "Delete,d,|" \ + "Delete Tagged,D,|" \ + "|" \ + "Cancel,q," + const struct window_mode window_buffer_mode = { .name = "buffer-mode", .default_format = WINDOW_BUFFER_DEFAULT_FORMAT, @@ -67,7 +80,9 @@ struct window_buffer_itemdata { }; struct window_buffer_modedata { + struct window_pane *wp; struct cmd_find_state fs; + struct mode_tree_data *data; char *command; char *format; @@ -264,6 +279,19 @@ window_buffer_search(__unused void *modedata, void *itemdata, const char *ss) return (memmem(bufdata, bufsize, ss, strlen(ss)) != NULL); } +static void +window_buffer_menu(void *modedata, struct client *c, key_code key) +{ + struct window_buffer_modedata *data = modedata; + struct window_pane *wp = data->wp; + struct window_mode_entry *wme; + + wme = TAILQ_FIRST(&wp->modes); + if (wme == NULL || wme->data != modedata) + return; + window_buffer_key(wme, c, NULL, NULL, key, NULL); +} + static struct screen * window_buffer_init(struct window_mode_entry *wme, struct cmd_find_state *fs, struct args *args) @@ -273,6 +301,7 @@ window_buffer_init(struct window_mode_entry *wme, struct cmd_find_state *fs, struct screen *s; wme->data = data = xcalloc(1, sizeof *data); + data->wp = wp; cmd_find_copy_state(&data->fs, fs); if (args == NULL || !args_has(args, 'F')) @@ -285,8 +314,9 @@ window_buffer_init(struct window_mode_entry *wme, struct cmd_find_state *fs, data->command = xstrdup(args->argv[0]); data->data = mode_tree_start(wp, args, window_buffer_build, - window_buffer_draw, window_buffer_search, data, - window_buffer_sort_list, nitems(window_buffer_sort_list), &s); + window_buffer_draw, window_buffer_search, window_buffer_menu, data, + WINDOW_BUFFER_MENU, window_buffer_sort_list, + nitems(window_buffer_sort_list), &s); mode_tree_zoom(data->data, args); mode_tree_build(data->data); diff --git a/window-client.c b/window-client.c index e0637a06..e172b584 100644 --- a/window-client.c +++ b/window-client.c @@ -40,6 +40,16 @@ static void window_client_key(struct window_mode_entry *, "session #{session_name} " \ "(#{client_width}x#{client_height}, #{t:client_activity})" +#define WINDOW_CLIENT_MENU \ + "Detach,d,|" \ + "Detach Tagged,D,|" \ + "|" \ + "Tag,t,|" \ + "Tag All,C-t,|" \ + "Tag None,T,|" \ + "|" \ + "Cancel,q," + const struct window_mode window_client_mode = { .name = "client-mode", .default_format = WINDOW_CLIENT_DEFAULT_FORMAT, @@ -68,6 +78,8 @@ struct window_client_itemdata { }; struct window_client_modedata { + struct window_pane *wp; + struct mode_tree_data *data; char *format; char *command; @@ -249,6 +261,19 @@ window_client_draw(__unused void *modedata, void *itemdata, screen_write_fast_copy(ctx, &c->status.screen, 0, 0, sx, lines); } +static void +window_client_menu(void *modedata, struct client *c, key_code key) +{ + struct window_client_modedata *data = modedata; + struct window_pane *wp = data->wp; + struct window_mode_entry *wme; + + wme = TAILQ_FIRST(&wp->modes); + if (wme == NULL || wme->data != modedata) + return; + window_client_key(wme, c, NULL, NULL, key, NULL); +} + static struct screen * window_client_init(struct window_mode_entry *wme, __unused struct cmd_find_state *fs, struct args *args) @@ -258,6 +283,7 @@ window_client_init(struct window_mode_entry *wme, struct screen *s; wme->data = data = xcalloc(1, sizeof *data); + data->wp = wp; if (args == NULL || !args_has(args, 'F')) data->format = xstrdup(WINDOW_CLIENT_DEFAULT_FORMAT); @@ -269,7 +295,8 @@ window_client_init(struct window_mode_entry *wme, data->command = xstrdup(args->argv[0]); data->data = mode_tree_start(wp, args, window_client_build, - window_client_draw, NULL, data, window_client_sort_list, + window_client_draw, NULL, window_client_menu, data, + WINDOW_CLIENT_MENU, window_client_sort_list, nitems(window_client_sort_list), &s); mode_tree_zoom(data->data, args); diff --git a/window-tree.c b/window-tree.c index 32dc0251..ce740ceb 100644 --- a/window-tree.c +++ b/window-tree.c @@ -53,6 +53,19 @@ static void window_tree_key(struct window_mode_entry *, "}" \ "}" +#define WINDOW_TREE_MENU \ + "Select,Enter,|" \ + "Expand,Right,|" \ + "|" \ + "Tag,t,|" \ + "Tag All,C-t,|" \ + "Tag None,T,|" \ + "|" \ + "Kill,x,|" \ + "Kill Tagged,X,|" \ + "|" \ + "Cancel,q," + const struct window_mode window_tree_mode = { .name = "tree-mode", .default_format = WINDOW_TREE_DEFAULT_FORMAT, @@ -814,6 +827,19 @@ window_tree_search(__unused void *modedata, void *itemdata, const char *ss) return (0); } +static void +window_tree_menu(void *modedata, struct client *c, key_code key) +{ + struct window_tree_modedata *data = modedata; + struct window_pane *wp = data->wp; + struct window_mode_entry *wme; + + wme = TAILQ_FIRST(&wp->modes); + if (wme == NULL || wme->data != modedata) + return; + window_tree_key(wme, c, NULL, NULL, key, NULL); +} + static struct screen * window_tree_init(struct window_mode_entry *wme, struct cmd_find_state *fs, struct args *args) @@ -823,6 +849,8 @@ window_tree_init(struct window_mode_entry *wme, struct cmd_find_state *fs, struct screen *s; wme->data = data = xcalloc(1, sizeof *data); + data->wp = wp; + data->references = 1; if (args_has(args, 's')) data->type = WINDOW_TREE_SESSION; @@ -832,9 +860,6 @@ window_tree_init(struct window_mode_entry *wme, struct cmd_find_state *fs, data->type = WINDOW_TREE_PANE; memcpy(&data->fs, fs, sizeof data->fs); - data->wp = wp; - data->references = 1; - if (args == NULL || !args_has(args, 'F')) data->format = xstrdup(WINDOW_TREE_DEFAULT_FORMAT); else @@ -846,7 +871,8 @@ window_tree_init(struct window_mode_entry *wme, struct cmd_find_state *fs, data->squash_groups = !args_has(args, 'G'); data->data = mode_tree_start(wp, args, window_tree_build, - window_tree_draw, window_tree_search, data, window_tree_sort_list, + window_tree_draw, window_tree_search, window_tree_menu, data, + WINDOW_TREE_MENU, window_tree_sort_list, nitems(window_tree_sort_list), &s); mode_tree_zoom(data->data, args); @@ -1146,7 +1172,7 @@ window_tree_key(struct window_mode_entry *wme, struct client *c, item = new_item; data->offset = 0; } - if (KEYC_IS_MOUSE(key)) + if (KEYC_IS_MOUSE(key) && m != NULL) key = window_tree_mouse(data, key, x, item); switch (key) { case '<': @@ -1207,7 +1233,6 @@ window_tree_key(struct window_mode_entry *wme, struct client *c, free(prompt); break; case '\r': - item = mode_tree_get_current(data->data); name = window_tree_get_target(item, &fs); if (name != NULL) mode_tree_run_command(c, NULL, data->command, name);