Add a menu when a popup is present (mouse only for now).
authornicm <nicm@openbsd.org>
Fri, 13 Aug 2021 18:54:54 +0000 (18:54 +0000)
committernicm <nicm@openbsd.org>
Fri, 13 Aug 2021 18:54:54 +0000 (18:54 +0000)
usr.bin/tmux/cmd-display-panes.c
usr.bin/tmux/menu.c
usr.bin/tmux/popup.c
usr.bin/tmux/screen-redraw.c
usr.bin/tmux/server-client.c
usr.bin/tmux/tmux.1
usr.bin/tmux/tmux.h
usr.bin/tmux/tty.c

index fa44a80..70c2160 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: cmd-display-panes.c,v 1.39 2021/07/21 08:06:36 nicm Exp $ */
+/* $OpenBSD: cmd-display-panes.c,v 1.40 2021/08/13 18:54:54 nicm Exp $ */
 
 /*
  * Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -186,7 +186,8 @@ out:
 }
 
 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_pane      *wp;
@@ -200,9 +201,9 @@ cmd_display_panes_draw(struct client *c, struct screen_redraw_ctx *ctx)
 }
 
 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)
                cmdq_continue(cdata->item);
@@ -211,9 +212,9 @@ cmd_display_panes_free(struct client *c)
 }
 
 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;
        struct window                   *w = c->session->curw->window;
        struct window_pane              *wp;
index d102b29..f016d28 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: menu.c,v 1.34 2021/07/21 08:06:36 nicm Exp $ */
+/* $OpenBSD: menu.c,v 1.35 2021/08/13 18:54:54 nicm Exp $ */
 
 /*
  * Copyright (c) 2019 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -131,18 +131,33 @@ menu_free(struct menu *menu)
        free(menu);
 }
 
-static struct screen *
-menu_mode_cb(struct client *c, __unused u_int *cx, __unused u_int *cy)
+struct screen *
+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);
 }
 
-static void
-menu_draw_cb(struct client *c, __unused struct screen_redraw_ctx *ctx0)
+int
+menu_check_cb(__unused struct client *c, void *data, u_int px, u_int py)
+{
+       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 = c->overlay_data;
+       struct menu_data        *md = data;
        struct tty              *tty = &c->tty;
        struct screen           *s = &md->s;
        struct menu             *menu = md->menu;
@@ -163,10 +178,10 @@ menu_draw_cb(struct client *c, __unused struct screen_redraw_ctx *ctx0)
        }
 }
 
-static void
-menu_free_cb(struct client *c)
+void
+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)
                cmdq_continue(md->item);
@@ -179,10 +194,10 @@ menu_free_cb(struct client *c)
        free(md);
 }
 
-static int
-menu_key_cb(struct client *c, struct key_event *event)
+int
+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 mouse_event              *m = &event->m;
        u_int                            i;
@@ -342,8 +357,8 @@ chosen:
        return (1);
 }
 
-int
-menu_display(struct menu *menu, int flags, struct cmdq_item *item, u_int px,
+struct menu_data *
+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,
     void *data)
 {
@@ -352,7 +367,7 @@ menu_display(struct menu *menu, int flags, struct cmdq_item *item, u_int px,
        const char              *name;
 
        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)
                px = c->tty.sx - menu->width - 4;
        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->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,
            menu_key_cb, menu_free_cb, NULL, md);
        return (0);
index 40eb543..9f652a8 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: popup.c,v 1.26 2021/08/13 17:03:29 nicm Exp $ */
+/* $OpenBSD: popup.c,v 1.27 2021/08/13 18:54:54 nicm Exp $ */
 
 /*
  * Copyright (c) 2020 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -40,6 +40,10 @@ struct popup_data {
        popup_close_cb            cb;
        void                     *arg;
 
+       struct menu              *menu;
+       struct menu_data         *md;
+       int                       close;
+
        /* Current position and size. */
        u_int                     px;
        u_int                     py;
@@ -67,6 +71,16 @@ struct popup_editor {
        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
 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 *
-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) {
                *cx = pd->px + pd->s.cx;
@@ -129,21 +146,23 @@ popup_mode_cb(struct client *c, u_int *cx, u_int *cy)
 }
 
 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)
                return (1);
        if (py < pd->py || py > pd->py + pd->sy - 1)
                return (1);
+       if (pd->md != NULL)
+               return (menu_check_cb(c, pd->md, px, py));
        return (0);
 }
 
 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 screen            s;
        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.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++)
                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_data = pd;
 }
 
 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;
 
+       if (pd->md != NULL)
+               menu_free_cb(c, pd->md);
+
        if (pd->cb != NULL)
                pd->cb(pd->status, pd->arg);
 
@@ -199,17 +233,20 @@ popup_free_cb(struct client *c)
 
        screen_free(&pd->s);
        colour_palette_free(&pd->palette);
+
        free(pd);
 }
 
 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;
 
        if (pd == NULL)
                return;
+       if (pd->md != NULL)
+               menu_free_cb(c, pd->md);
 
        /* Adjust position and size. */
        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
 popup_handle_drag(struct client *c, struct popup_data *pd,
     struct mouse_event *m)
@@ -300,13 +377,25 @@ popup_handle_drag(struct client *c, struct popup_data *pd,
 }
 
 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;
        const char              *buf;
        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 (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->y < pd->py ||
                    m->y > pd->py + pd->sy - 1) {
-                       if (MOUSE_BUTTONS (m->b) == 1)
-                               return (1);
+                       if (MOUSE_BUTTONS(m->b) == 2)
+                               goto menu;
                        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) ||
                    ((~pd->flags & POPUP_NOBORDER) &&
                    (m->x == pd->px ||
@@ -338,7 +435,6 @@ popup_key_cb(struct client *c, struct key_event *event)
                        goto out;
                }
        }
-
        if ((((pd->flags & (POPUP_CLOSEEXIT|POPUP_CLOSEEXITZERO)) == 0) ||
            pd->job == NULL) &&
            (event->key == '\033' || event->key == '\003'))
@@ -362,6 +458,17 @@ popup_key_cb(struct client *c, struct key_event *event)
        }
        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:
        pd->lx = m->x;
        pd->ly = m->y;
index 51c6955..2273edf 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: screen-redraw.c,v 1.87 2021/08/11 20:49:55 nicm Exp $ */
+/* $OpenBSD: screen-redraw.c,v 1.88 2021/08/13 18:54:54 nicm Exp $ */
 
 /*
  * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -624,7 +624,7 @@ screen_redraw_screen(struct client *c)
        }
        if (c->overlay_draw != NULL && (flags & CLIENT_REDRAWOVERLAY)) {
                log_debug("%s: redrawing overlay", c->name);
-               c->overlay_draw(c, &ctx);
+               c->overlay_draw(c, c->overlay_data, &ctx);
        }
 
        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;
        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;
 
        cell_type = screen_redraw_check_cell(c, x, y, pane_status, &wp);
index 8626d3b..73c1b21 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: server-client.c,v 1.379 2021/08/13 06:52:51 nicm Exp $ */
+/* $OpenBSD: server-client.c,v 1.380 2021/08/13 18:54:54 nicm Exp $ */
 
 /*
  * Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -134,7 +134,7 @@ server_client_clear_overlay(struct client *c)
                evtimer_del(&c->overlay_timer);
 
        if (c->overlay_free != NULL)
-               c->overlay_free(c);
+               c->overlay_free(c, c->overlay_data);
 
        c->overlay_check = NULL;
        c->overlay_mode = NULL;
@@ -1390,7 +1390,7 @@ server_client_handle_key(struct client *c, struct key_event *event)
                        status_message_clear(c);
                }
                if (c->overlay_key != NULL) {
-                       switch (c->overlay_key(c, event)) {
+                       switch (c->overlay_key(c, c->overlay_data, event)) {
                        case 0:
                                return (0);
                        case 1:
@@ -1673,7 +1673,7 @@ server_client_reset_state(struct client *c)
        /* Get mode from overlay if any, else from screen. */
        if (c->overlay_draw != NULL) {
                if (c->overlay_mode != NULL)
-                       s = c->overlay_mode(c, &cx, &cy);
+                       s = c->overlay_mode(c, c->overlay_data, &cx, &cy);
        } else
                s = wp->screen;
        if (s != NULL)
@@ -2050,7 +2050,7 @@ server_client_dispatch(struct imsg *imsg, void *arg)
                if (c->overlay_resize == NULL)
                        server_client_clear_overlay(c);
                else
-                       c->overlay_resize(c);
+                       c->overlay_resize(c, c->overlay_data);
                server_redraw_client(c);
                if (c->session != NULL)
                        notify_client("client-resized", c);
index b4f93c7..dd1b755 100644 (file)
@@ -1,4 +1,4 @@
-.\" $OpenBSD: tmux.1,v 1.853 2021/08/13 17:03:29 nicm Exp $
+.\" $OpenBSD: tmux.1,v 1.854 2021/08/13 18:54:54 nicm Exp $
 .\"
 .\" Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
 .\"
@@ -5516,8 +5516,8 @@ option:
 .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 "Transpose characters" Ta "" Ta "C-t"
-.Pp
 .El
+.Pp
 With
 .Fl b ,
 the prompt is shown in the background and the invoking client does not exit
index 04cf34e..7099232 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: tmux.h,v 1.1119 2021/08/13 17:03:29 nicm Exp $ */
+/* $OpenBSD: tmux.h,v 1.1120 2021/08/13 18:54:54 nicm Exp $ */
 
 /*
  * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -51,6 +51,7 @@ struct format_job_tree;
 struct format_tree;
 struct input_ctx;
 struct job;
+struct menu_data;
 struct mode_tree_data;
 struct mouse_event;
 struct options;
@@ -1535,12 +1536,14 @@ RB_HEAD(client_windows, client_window);
 /* Client connection. */
 typedef int (*prompt_input_cb)(struct client *, void *, const char *, int);
 typedef void (*prompt_free_cb)(void *);
-typedef int (*overlay_check_cb)(struct client *, u_int, u_int);
-typedef struct screen *(*overlay_mode_cb)(struct client *, u_int *, u_int *);
-typedef void (*overlay_draw_cb)(struct client *, struct screen_redraw_ctx *);
-typedef int (*overlay_key_cb)(struct client *, struct key_event *);
-typedef void (*overlay_free_cb)(struct client *);
-typedef void (*overlay_resize_cb)(struct client *);
+typedef int (*overlay_check_cb)(struct client *, void *, u_int, u_int);
+typedef struct screen *(*overlay_mode_cb)(struct client *, void *, u_int *,
+           u_int *);
+typedef void (*overlay_draw_cb)(struct client *, void *,
+           struct screen_redraw_ctx *);
+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 {
        const char      *name;
        struct tmuxpeer *peer;
@@ -3018,9 +3021,18 @@ void              menu_add_item(struct menu *, const struct menu_item *,
                    struct cmdq_item *, struct client *,
                    struct cmd_find_state *);
 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,
                    u_int, struct client *, struct cmd_find_state *,
                    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 */
 #define POPUP_CLOSEEXIT 0x1
index f1cdc22..aa0c143 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: tty.c,v 1.400 2021/08/12 19:47:05 nicm Exp $ */
+/* $OpenBSD: tty.c,v 1.401 2021/08/13 18:54:54 nicm Exp $ */
 
 /*
  * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -1318,7 +1318,7 @@ tty_check_overlay(struct tty *tty, u_int px, u_int py)
 
        if (c->overlay_check == NULL)
                return (1);
-       return (c->overlay_check(c, px, py));
+       return (c->overlay_check(c, c->overlay_data, px, py));
 }
 
 void