Add a menu when a popup is present (mouse only for now).

pull/2824/head
nicm 2021-08-13 18:54:54 +00:00
parent 614611a8bd
commit 7789639b5d
8 changed files with 199 additions and 51 deletions

View File

@ -186,7 +186,8 @@ out:
} }
static void static void
cmd_display_panes_draw(struct client *c, struct screen_redraw_ctx *ctx) cmd_display_panes_draw(struct client *c, __unused void *data,
struct screen_redraw_ctx *ctx)
{ {
struct window *w = c->session->curw->window; struct window *w = c->session->curw->window;
struct window_pane *wp; struct window_pane *wp;
@ -200,9 +201,9 @@ cmd_display_panes_draw(struct client *c, struct screen_redraw_ctx *ctx)
} }
static void static void
cmd_display_panes_free(struct client *c) cmd_display_panes_free(__unused struct client *c, void *data)
{ {
struct cmd_display_panes_data *cdata = c->overlay_data; struct cmd_display_panes_data *cdata = data;
if (cdata->item != NULL) if (cdata->item != NULL)
cmdq_continue(cdata->item); cmdq_continue(cdata->item);
@ -211,9 +212,9 @@ cmd_display_panes_free(struct client *c)
} }
static int static int
cmd_display_panes_key(struct client *c, struct key_event *event) cmd_display_panes_key(struct client *c, void *data, struct key_event *event)
{ {
struct cmd_display_panes_data *cdata = c->overlay_data; struct cmd_display_panes_data *cdata = data;
char *cmd, *expanded, *error; char *cmd, *expanded, *error;
struct window *w = c->session->curw->window; struct window *w = c->session->curw->window;
struct window_pane *wp; struct window_pane *wp;

57
menu.c
View File

@ -131,18 +131,33 @@ menu_free(struct menu *menu)
free(menu); free(menu);
} }
static struct screen * struct screen *
menu_mode_cb(struct client *c, __unused u_int *cx, __unused u_int *cy) menu_mode_cb(__unused struct client *c, void *data, __unused u_int *cx,
__unused u_int *cy)
{ {
struct menu_data *md = c->overlay_data; struct menu_data *md = data;
return (&md->s); return (&md->s);
} }
static void int
menu_draw_cb(struct client *c, __unused struct screen_redraw_ctx *ctx0) menu_check_cb(__unused struct client *c, void *data, u_int px, u_int py)
{ {
struct menu_data *md = c->overlay_data; struct menu_data *md = data;
struct menu *menu = md->menu;
if (px < md->px || px > md->px + menu->width + 3)
return (1);
if (py < md->py || py > md->py + menu->count + 1)
return (1);
return (0);
}
void
menu_draw_cb(struct client *c, void *data,
__unused struct screen_redraw_ctx *rctx)
{
struct menu_data *md = data;
struct tty *tty = &c->tty; struct tty *tty = &c->tty;
struct screen *s = &md->s; struct screen *s = &md->s;
struct menu *menu = md->menu; struct menu *menu = md->menu;
@ -163,10 +178,10 @@ menu_draw_cb(struct client *c, __unused struct screen_redraw_ctx *ctx0)
} }
} }
static void void
menu_free_cb(struct client *c) menu_free_cb(__unused struct client *c, void *data)
{ {
struct menu_data *md = c->overlay_data; struct menu_data *md = data;
if (md->item != NULL) if (md->item != NULL)
cmdq_continue(md->item); cmdq_continue(md->item);
@ -179,10 +194,10 @@ menu_free_cb(struct client *c)
free(md); free(md);
} }
static int int
menu_key_cb(struct client *c, struct key_event *event) menu_key_cb(struct client *c, void *data, struct key_event *event)
{ {
struct menu_data *md = c->overlay_data; struct menu_data *md = data;
struct menu *menu = md->menu; struct menu *menu = md->menu;
struct mouse_event *m = &event->m; struct mouse_event *m = &event->m;
u_int i; u_int i;
@ -342,8 +357,8 @@ chosen:
return (1); return (1);
} }
int struct menu_data *
menu_display(struct menu *menu, int flags, struct cmdq_item *item, u_int px, menu_prepare(struct menu *menu, int flags, struct cmdq_item *item, u_int px,
u_int py, struct client *c, struct cmd_find_state *fs, menu_choice_cb cb, u_int py, struct client *c, struct cmd_find_state *fs, menu_choice_cb cb,
void *data) void *data)
{ {
@ -352,7 +367,7 @@ menu_display(struct menu *menu, int flags, struct cmdq_item *item, u_int px,
const char *name; const char *name;
if (c->tty.sx < menu->width + 4 || c->tty.sy < menu->count + 2) if (c->tty.sx < menu->width + 4 || c->tty.sy < menu->count + 2)
return (-1); return (NULL);
if (px + menu->width + 4 > c->tty.sx) if (px + menu->width + 4 > c->tty.sx)
px = c->tty.sx - menu->width - 4; px = c->tty.sx - menu->width - 4;
if (py + menu->count + 2 > c->tty.sy) if (py + menu->count + 2 > c->tty.sy)
@ -388,7 +403,19 @@ menu_display(struct menu *menu, int flags, struct cmdq_item *item, u_int px,
md->cb = cb; md->cb = cb;
md->data = data; md->data = data;
return (md);
}
int
menu_display(struct menu *menu, int flags, struct cmdq_item *item, u_int px,
u_int py, struct client *c, struct cmd_find_state *fs, menu_choice_cb cb,
void *data)
{
struct menu_data *md;
md = menu_prepare(menu, flags, item, px, py, c, fs, cb, data);
if (md == NULL)
return (-1);
server_client_set_overlay(c, 0, NULL, menu_mode_cb, menu_draw_cb, server_client_set_overlay(c, 0, NULL, menu_mode_cb, menu_draw_cb,
menu_key_cb, menu_free_cb, NULL, md); menu_key_cb, menu_free_cb, NULL, md);
return (0); return (0);

141
popup.c
View File

@ -40,6 +40,10 @@ struct popup_data {
popup_close_cb cb; popup_close_cb cb;
void *arg; void *arg;
struct menu *menu;
struct menu_data *md;
int close;
/* Current position and size. */ /* Current position and size. */
u_int px; u_int px;
u_int py; u_int py;
@ -67,6 +71,16 @@ struct popup_editor {
void *arg; void *arg;
}; };
static const struct menu_item popup_menu_items[] = {
{ "Close", 'q', NULL },
{ "#{?buffer_name,Paste #[underscore]#{buffer_name},}", 'p', NULL },
{ "", KEYC_NONE, NULL },
{ "Fill Space", 'F', NULL },
{ "Centre", 'C', NULL },
{ NULL, KEYC_NONE, NULL }
};
static void static void
popup_redraw_cb(const struct tty_ctx *ttyctx) popup_redraw_cb(const struct tty_ctx *ttyctx)
{ {
@ -114,9 +128,12 @@ popup_init_ctx_cb(struct screen_write_ctx *ctx, struct tty_ctx *ttyctx)
} }
static struct screen * static struct screen *
popup_mode_cb(struct client *c, u_int *cx, u_int *cy) popup_mode_cb(__unused struct client *c, void *data, u_int *cx, u_int *cy)
{ {
struct popup_data *pd = c->overlay_data; struct popup_data *pd = data;
if (pd->md != NULL)
return (menu_mode_cb(c, pd->md, cx, cy));
if (pd->flags & POPUP_NOBORDER) { if (pd->flags & POPUP_NOBORDER) {
*cx = pd->px + pd->s.cx; *cx = pd->px + pd->s.cx;
@ -129,21 +146,23 @@ popup_mode_cb(struct client *c, u_int *cx, u_int *cy)
} }
static int static int
popup_check_cb(struct client *c, u_int px, u_int py) popup_check_cb(struct client *c, void *data, u_int px, u_int py)
{ {
struct popup_data *pd = c->overlay_data; struct popup_data *pd = data;
if (px < pd->px || px > pd->px + pd->sx - 1) if (px < pd->px || px > pd->px + pd->sx - 1)
return (1); return (1);
if (py < pd->py || py > pd->py + pd->sy - 1) if (py < pd->py || py > pd->py + pd->sy - 1)
return (1); return (1);
if (pd->md != NULL)
return (menu_check_cb(c, pd->md, px, py));
return (0); return (0);
} }
static void static void
popup_draw_cb(struct client *c, __unused struct screen_redraw_ctx *ctx0) popup_draw_cb(struct client *c, void *data, struct screen_redraw_ctx *rctx)
{ {
struct popup_data *pd = c->overlay_data; struct popup_data *pd = data;
struct tty *tty = &c->tty; struct tty *tty = &c->tty;
struct screen s; struct screen s;
struct screen_write_ctx ctx; struct screen_write_ctx ctx;
@ -170,18 +189,33 @@ popup_draw_cb(struct client *c, __unused struct screen_redraw_ctx *ctx0)
gc.fg = pd->palette.fg; gc.fg = pd->palette.fg;
gc.bg = pd->palette.bg; gc.bg = pd->palette.bg;
c->overlay_check = NULL; if (pd->md != NULL) {
c->overlay_check = menu_check_cb;
c->overlay_data = pd->md;
} else {
c->overlay_check = NULL;
c->overlay_data = NULL;
}
for (i = 0; i < pd->sy; i++) for (i = 0; i < pd->sy; i++)
tty_draw_line(tty, &s, 0, i, pd->sx, px, py + i, &gc, palette); tty_draw_line(tty, &s, 0, i, pd->sx, px, py + i, &gc, palette);
if (pd->md != NULL) {
c->overlay_check = NULL;
c->overlay_data = NULL;
menu_draw_cb(c, pd->md, rctx);
}
c->overlay_check = popup_check_cb; c->overlay_check = popup_check_cb;
c->overlay_data = pd;
} }
static void static void
popup_free_cb(struct client *c) popup_free_cb(struct client *c, void *data)
{ {
struct popup_data *pd = c->overlay_data; struct popup_data *pd = data;
struct cmdq_item *item = pd->item; struct cmdq_item *item = pd->item;
if (pd->md != NULL)
menu_free_cb(c, pd->md);
if (pd->cb != NULL) if (pd->cb != NULL)
pd->cb(pd->status, pd->arg); pd->cb(pd->status, pd->arg);
@ -199,17 +233,20 @@ popup_free_cb(struct client *c)
screen_free(&pd->s); screen_free(&pd->s);
colour_palette_free(&pd->palette); colour_palette_free(&pd->palette);
free(pd); free(pd);
} }
static void static void
popup_resize_cb(struct client *c) popup_resize_cb(__unused struct client *c, void *data)
{ {
struct popup_data *pd = c->overlay_data; struct popup_data *pd = data;
struct tty *tty = &c->tty; struct tty *tty = &c->tty;
if (pd == NULL) if (pd == NULL)
return; return;
if (pd->md != NULL)
menu_free_cb(c, pd->md);
/* Adjust position and size. */ /* Adjust position and size. */
if (pd->psy > tty->sy) if (pd->psy > tty->sy)
@ -241,6 +278,46 @@ popup_resize_cb(struct client *c)
} }
} }
static void
popup_menu_done(__unused struct menu *menu, __unused u_int choice,
key_code key, void *data)
{
struct popup_data *pd = data;
struct client *c = pd->c;
struct paste_buffer *pb;
const char *buf;
size_t len;
pd->md = NULL;
pd->menu = NULL;
server_redraw_client(pd->c);
switch (key) {
case 'p':
pb = paste_get_top(NULL);
if (pb != NULL) {
buf = paste_buffer_data(pb, &len);
bufferevent_write(job_get_event(pd->job), buf, len);
}
break;
case 'F':
pd->sx = c->tty.sx;
pd->sy = c->tty.sy;
pd->px = 0;
pd->py = 0;
server_redraw_client(c);
break;
case 'C':
pd->px = c->tty.sx / 2 - pd->sx / 2;
pd->py = c->tty.sy / 2 - pd->sy / 2;
server_redraw_client(c);
break;
case 'q':
pd->close = 1;
break;
}
}
static void static void
popup_handle_drag(struct client *c, struct popup_data *pd, popup_handle_drag(struct client *c, struct popup_data *pd,
struct mouse_event *m) struct mouse_event *m)
@ -300,13 +377,25 @@ popup_handle_drag(struct client *c, struct popup_data *pd,
} }
static int static int
popup_key_cb(struct client *c, struct key_event *event) popup_key_cb(struct client *c, void *data, struct key_event *event)
{ {
struct popup_data *pd = c->overlay_data; struct popup_data *pd = data;
struct mouse_event *m = &event->m; struct mouse_event *m = &event->m;
const char *buf; const char *buf;
size_t len; size_t len;
u_int px, py; u_int px, py, x;
if (pd->md != NULL) {
if (menu_key_cb(c, pd->md, event) == 1) {
pd->md = NULL;
pd->menu = NULL;
if (pd->close)
server_client_clear_overlay(c);
else
server_redraw_client(c);
}
return (0);
}
if (KEYC_IS_MOUSE(event->key)) { if (KEYC_IS_MOUSE(event->key)) {
if (pd->dragging != OFF) { if (pd->dragging != OFF) {
@ -317,10 +406,18 @@ popup_key_cb(struct client *c, struct key_event *event)
m->x > pd->px + pd->sx - 1 || m->x > pd->px + pd->sx - 1 ||
m->y < pd->py || m->y < pd->py ||
m->y > pd->py + pd->sy - 1) { m->y > pd->py + pd->sy - 1) {
if (MOUSE_BUTTONS (m->b) == 1) if (MOUSE_BUTTONS(m->b) == 2)
return (1); goto menu;
return (0); return (0);
} }
if ((~pd->flags & POPUP_NOBORDER) &&
(~m->b & MOUSE_MASK_META) &&
MOUSE_BUTTONS(m->b) == 2 &&
(m->x == pd->px ||
m->x == pd->px + pd->sx - 1 ||
m->y == pd->py ||
m->y == pd->py + pd->sy - 1))
goto menu;
if ((m->b & MOUSE_MASK_META) || if ((m->b & MOUSE_MASK_META) ||
((~pd->flags & POPUP_NOBORDER) && ((~pd->flags & POPUP_NOBORDER) &&
(m->x == pd->px || (m->x == pd->px ||
@ -338,7 +435,6 @@ popup_key_cb(struct client *c, struct key_event *event)
goto out; goto out;
} }
} }
if ((((pd->flags & (POPUP_CLOSEEXIT|POPUP_CLOSEEXITZERO)) == 0) || if ((((pd->flags & (POPUP_CLOSEEXIT|POPUP_CLOSEEXITZERO)) == 0) ||
pd->job == NULL) && pd->job == NULL) &&
(event->key == '\033' || event->key == '\003')) (event->key == '\033' || event->key == '\003'))
@ -362,6 +458,17 @@ popup_key_cb(struct client *c, struct key_event *event)
} }
return (0); return (0);
menu:
pd->menu = menu_create("");
menu_add_items(pd->menu, popup_menu_items, NULL, NULL, NULL);
if (m->x >= (pd->menu->width + 4) / 2)
x = m->x - (pd->menu->width + 4) / 2;
else
x = 0;
pd->md = menu_prepare(pd->menu, 0, NULL, x, m->y, c, NULL,
popup_menu_done, pd);
c->flags |= CLIENT_REDRAWOVERLAY;
out: out:
pd->lx = m->x; pd->lx = m->x;
pd->ly = m->y; pd->ly = m->y;

View File

@ -624,7 +624,7 @@ screen_redraw_screen(struct client *c)
} }
if (c->overlay_draw != NULL && (flags & CLIENT_REDRAWOVERLAY)) { if (c->overlay_draw != NULL && (flags & CLIENT_REDRAWOVERLAY)) {
log_debug("%s: redrawing overlay", c->name); log_debug("%s: redrawing overlay", c->name);
c->overlay_draw(c, &ctx); c->overlay_draw(c, c->overlay_data, &ctx);
} }
tty_reset(&c->tty); tty_reset(&c->tty);
@ -690,7 +690,8 @@ screen_redraw_draw_borders_cell(struct screen_redraw_ctx *ctx, u_int i, u_int j)
struct grid_cell gc; struct grid_cell gc;
const struct grid_cell *tmp; const struct grid_cell *tmp;
if (c->overlay_check != NULL && !c->overlay_check(c, x, y)) if (c->overlay_check != NULL &&
!c->overlay_check(c, c->overlay_data, x, y))
return; return;
cell_type = screen_redraw_check_cell(c, x, y, pane_status, &wp); cell_type = screen_redraw_check_cell(c, x, y, pane_status, &wp);

View File

@ -134,7 +134,7 @@ server_client_clear_overlay(struct client *c)
evtimer_del(&c->overlay_timer); evtimer_del(&c->overlay_timer);
if (c->overlay_free != NULL) if (c->overlay_free != NULL)
c->overlay_free(c); c->overlay_free(c, c->overlay_data);
c->overlay_check = NULL; c->overlay_check = NULL;
c->overlay_mode = NULL; c->overlay_mode = NULL;
@ -1390,7 +1390,7 @@ server_client_handle_key(struct client *c, struct key_event *event)
status_message_clear(c); status_message_clear(c);
} }
if (c->overlay_key != NULL) { if (c->overlay_key != NULL) {
switch (c->overlay_key(c, event)) { switch (c->overlay_key(c, c->overlay_data, event)) {
case 0: case 0:
return (0); return (0);
case 1: case 1:
@ -1673,7 +1673,7 @@ server_client_reset_state(struct client *c)
/* Get mode from overlay if any, else from screen. */ /* Get mode from overlay if any, else from screen. */
if (c->overlay_draw != NULL) { if (c->overlay_draw != NULL) {
if (c->overlay_mode != NULL) if (c->overlay_mode != NULL)
s = c->overlay_mode(c, &cx, &cy); s = c->overlay_mode(c, c->overlay_data, &cx, &cy);
} else } else
s = wp->screen; s = wp->screen;
if (s != NULL) if (s != NULL)
@ -2050,7 +2050,7 @@ server_client_dispatch(struct imsg *imsg, void *arg)
if (c->overlay_resize == NULL) if (c->overlay_resize == NULL)
server_client_clear_overlay(c); server_client_clear_overlay(c);
else else
c->overlay_resize(c); c->overlay_resize(c, c->overlay_data);
server_redraw_client(c); server_redraw_client(c);
if (c->session != NULL) if (c->session != NULL)
notify_client("client-resized", c); notify_client("client-resized", c);

2
tmux.1
View File

@ -5516,8 +5516,8 @@ option:
.It Li "Move cursor to previous word" Ta "b" Ta "M-b" .It Li "Move cursor to previous word" Ta "b" Ta "M-b"
.It Li "Move cursor to start" Ta "0" Ta "C-a" .It Li "Move cursor to start" Ta "0" Ta "C-a"
.It Li "Transpose characters" Ta "" Ta "C-t" .It Li "Transpose characters" Ta "" Ta "C-t"
.Pp
.El .El
.Pp
With With
.Fl b , .Fl b ,
the prompt is shown in the background and the invoking client does not exit the prompt is shown in the background and the invoking client does not exit

24
tmux.h
View File

@ -51,6 +51,7 @@ struct format_job_tree;
struct format_tree; struct format_tree;
struct input_ctx; struct input_ctx;
struct job; struct job;
struct menu_data;
struct mode_tree_data; struct mode_tree_data;
struct mouse_event; struct mouse_event;
struct options; struct options;
@ -1535,12 +1536,14 @@ RB_HEAD(client_windows, client_window);
/* Client connection. */ /* Client connection. */
typedef int (*prompt_input_cb)(struct client *, void *, const char *, int); typedef int (*prompt_input_cb)(struct client *, void *, const char *, int);
typedef void (*prompt_free_cb)(void *); typedef void (*prompt_free_cb)(void *);
typedef int (*overlay_check_cb)(struct client *, u_int, u_int); typedef int (*overlay_check_cb)(struct client *, void *, u_int, u_int);
typedef struct screen *(*overlay_mode_cb)(struct client *, u_int *, u_int *); typedef struct screen *(*overlay_mode_cb)(struct client *, void *, u_int *,
typedef void (*overlay_draw_cb)(struct client *, struct screen_redraw_ctx *); u_int *);
typedef int (*overlay_key_cb)(struct client *, struct key_event *); typedef void (*overlay_draw_cb)(struct client *, void *,
typedef void (*overlay_free_cb)(struct client *); struct screen_redraw_ctx *);
typedef void (*overlay_resize_cb)(struct client *); typedef int (*overlay_key_cb)(struct client *, void *, struct key_event *);
typedef void (*overlay_free_cb)(struct client *, void *);
typedef void (*overlay_resize_cb)(struct client *, void *);
struct client { struct client {
const char *name; const char *name;
struct tmuxpeer *peer; struct tmuxpeer *peer;
@ -3018,9 +3021,18 @@ void menu_add_item(struct menu *, const struct menu_item *,
struct cmdq_item *, struct client *, struct cmdq_item *, struct client *,
struct cmd_find_state *); struct cmd_find_state *);
void menu_free(struct menu *); void menu_free(struct menu *);
struct menu_data *menu_prepare(struct menu *, int, struct cmdq_item *, u_int,
u_int, struct client *, struct cmd_find_state *,
menu_choice_cb, void *);
int menu_display(struct menu *, int, struct cmdq_item *, u_int, int menu_display(struct menu *, int, struct cmdq_item *, u_int,
u_int, struct client *, struct cmd_find_state *, u_int, struct client *, struct cmd_find_state *,
menu_choice_cb, void *); menu_choice_cb, void *);
struct screen *menu_mode_cb(struct client *, void *, u_int *, u_int *);
int menu_check_cb(struct client *, void *, u_int, u_int);
void menu_draw_cb(struct client *, void *,
struct screen_redraw_ctx *);
void menu_free_cb(struct client *, void *);
int menu_key_cb(struct client *, void *, struct key_event *);
/* popup.c */ /* popup.c */
#define POPUP_CLOSEEXIT 0x1 #define POPUP_CLOSEEXIT 0x1

2
tty.c
View File

@ -1318,7 +1318,7 @@ tty_check_overlay(struct tty *tty, u_int px, u_int py)
if (c->overlay_check == NULL) if (c->overlay_check == NULL)
return (1); return (1);
return (c->overlay_check(c, px, py)); return (c->overlay_check(c, c->overlay_data, px, py));
} }
void void