From 97f9edd5702e92362fc19659a56bdbf7721603c9 Mon Sep 17 00:00:00 2001 From: nicm Date: Wed, 17 Jun 2026 07:52:21 +0000 Subject: [PATCH] Add -M to move-pane and default bindings for M-drag. From Michael Grant. --- usr.bin/tmux/cmd-join-pane.c | 76 ++++++++++++++++++++++++++++++++-- usr.bin/tmux/cmd-resize-pane.c | 28 ++++++++----- usr.bin/tmux/key-bindings.c | 4 +- usr.bin/tmux/tmux.1 | 10 +++-- 4 files changed, 101 insertions(+), 17 deletions(-) diff --git a/usr.bin/tmux/cmd-join-pane.c b/usr.bin/tmux/cmd-join-pane.c index ff0b0e8b629..2b2bf1153b6 100644 --- a/usr.bin/tmux/cmd-join-pane.c +++ b/usr.bin/tmux/cmd-join-pane.c @@ -1,4 +1,4 @@ -/* $OpenBSD: cmd-join-pane.c,v 1.63 2026/06/15 17:34:25 nicm Exp $ */ +/* $OpenBSD: cmd-join-pane.c,v 1.64 2026/06/17 07:52:21 nicm Exp $ */ /* * Copyright (c) 2011 George Nachman @@ -31,6 +31,9 @@ */ static enum cmd_retval cmd_join_pane_exec(struct cmd *, struct cmdq_item *); +static enum cmd_retval cmd_join_pane_mouse_update(struct cmdq_item *); +static void cmd_join_pane_mouse_move(struct client *, + struct mouse_event *); const struct cmd_entry cmd_join_pane_entry = { .name = "join-pane", @@ -50,8 +53,8 @@ const struct cmd_entry cmd_move_pane_entry = { .name = "move-pane", .alias = "movep", - .args = { "bdfhvl:L::P:R::s:t:U::X:Y:z:", 0, 0, NULL }, - .usage = "[-bdfhv] [-D lines] [-l size] [-L columns] [-P position] " + .args = { "bdfhMvl:L::P:R::s:t:U::X:Y:z:", 0, 0, NULL }, + .usage = "[-bdfhMv] [-D lines] [-l size] [-L columns] [-P position] " "[-R columns] " CMD_SRCDST_PANE_USAGE " [-U lines] " "[-X x-position] [-Y y-position] [-z z-index]", @@ -255,6 +258,71 @@ cmd_join_pane_move(struct cmdq_item *item, struct args *args, return (CMD_RETURN_NORMAL); } +static enum cmd_retval +cmd_join_pane_mouse_update(struct cmdq_item *item) +{ + struct cmd_find_state *target = cmdq_get_target(item); + struct key_event *event = cmdq_get_event(item); + struct client *c = cmdq_get_client(item); + struct session *s = target->s; + struct winlink *wl; + struct window *w; + struct window_pane *wp; + + if (!event->m.valid) + return (CMD_RETURN_NORMAL); + wp = cmd_mouse_pane(&event->m, &s, &wl); + if (wp == NULL || c == NULL || c->session != s) + return (CMD_RETURN_NORMAL); + if (!window_pane_is_floating(wp)) + return (CMD_RETURN_NORMAL); + + w = wl->window; + window_redraw_active_switch(w, wp); + window_set_active_pane(w, wp, 1); + + c->tty.mouse_drag_update = cmd_join_pane_mouse_move; + cmd_join_pane_mouse_move(c, &event->m); + return (CMD_RETURN_NORMAL); +} + +static void +cmd_join_pane_mouse_move(struct client *c, struct mouse_event *m) +{ + struct winlink *wl; + struct window *w; + struct window_pane *wp; + struct layout_cell *lc; + int y, ly, x, lx; + + wp = cmd_mouse_pane(m, NULL, &wl); + if (wp == NULL) { + c->tty.mouse_drag_update = NULL; + return; + } + w = wl->window; + lc = wp->layout_cell; + + y = m->y + m->oy; x = m->x + m->ox; + if (m->statusat == 0 && y >= (int)m->statuslines) + y -= m->statuslines; + else if (m->statusat > 0 && y >= m->statusat) + y = m->statusat - 1; + ly = m->ly + m->oy; lx = m->lx + m->ox; + if (m->statusat == 0 && ly >= (int)m->statuslines) + ly -= m->statuslines; + else if (m->statusat > 0 && ly >= m->statusat) + ly = m->statusat - 1; + + if (x != lx || y != ly) { + lc->xoff += x - lx; + lc->yoff += y - ly; + layout_fix_panes(w, NULL); + server_redraw_window(w); + server_redraw_window_borders(w); + } +} + static enum cmd_retval cmd_join_pane_zindex(struct cmdq_item *item, struct winlink *wl, struct window_pane *wp, const char *s) @@ -315,6 +383,8 @@ cmd_join_pane_exec(struct cmd *self, struct cmdq_item *item) server_unzoom_window(dst_w); if (cmd_get_entry(self) == &cmd_move_pane_entry) { + if (args_has(args, 'M')) + return (cmd_join_pane_mouse_update(item)); if (!window_pane_is_floating(dst_wp)) { cmdq_error(item, "pane is not floating"); return (CMD_RETURN_ERROR); diff --git a/usr.bin/tmux/cmd-resize-pane.c b/usr.bin/tmux/cmd-resize-pane.c index cbce09285b7..2c1ae4d1035 100644 --- a/usr.bin/tmux/cmd-resize-pane.c +++ b/usr.bin/tmux/cmd-resize-pane.c @@ -1,4 +1,4 @@ -/* $OpenBSD: cmd-resize-pane.c,v 1.59 2026/06/16 08:57:07 nicm Exp $ */ +/* $OpenBSD: cmd-resize-pane.c,v 1.60 2026/06/17 07:52:21 nicm Exp $ */ /* * Copyright (c) 2009 Nicholas Marriott @@ -31,9 +31,9 @@ static enum cmd_retval cmd_resize_pane_exec(struct cmd *, struct cmdq_item *); static enum cmd_retval cmd_resize_pane_mouse_update(struct cmd *, struct cmdq_item *); -static void cmd_resize_pane_mouse_update_floating(struct client *, - struct mouse_event *); -static void cmd_resize_pane_mouse_update_tiled(struct client *, +static void cmd_resize_pane_mouse_resize_move_floating( + struct client *, struct mouse_event *); +static void cmd_resize_pane_mouse_resize_tiled(struct client *, struct mouse_event *); const struct cmd_entry cmd_resize_pane_entry = { @@ -205,21 +205,29 @@ cmd_resize_pane_mouse_update(__unused struct cmd *self, struct cmdq_item *item) return (CMD_RETURN_NORMAL); if (!window_pane_is_floating(wp)) { - c->tty.mouse_drag_update = cmd_resize_pane_mouse_update_tiled; - cmd_resize_pane_mouse_update_tiled(c, &event->m); + c->tty.mouse_drag_update = cmd_resize_pane_mouse_resize_tiled; + cmd_resize_pane_mouse_resize_tiled(c, &event->m); return (CMD_RETURN_NORMAL); } window_redraw_active_switch(w, wp); window_set_active_pane(w, wp, 1); - c->tty.mouse_drag_update = cmd_resize_pane_mouse_update_floating; - cmd_resize_pane_mouse_update_floating(c, &event->m); + c->tty.mouse_drag_update = cmd_resize_pane_mouse_resize_move_floating; + cmd_resize_pane_mouse_resize_move_floating(c, &event->m); return (CMD_RETURN_NORMAL); } +/* + * Resizes or moves the pane by dragging. Resize a floating pane by dragging + * the borders or corners. Grabbing an edge only resizes that axis (special + * case). Moves the pane if dragging the top border. Since characters are + * generally rectangular, to make it easier to grab the corner, the character + * next to the corner is also considered the corner. + */ static void -cmd_resize_pane_mouse_update_floating(struct client *c, struct mouse_event *m) +cmd_resize_pane_mouse_resize_move_floating(struct client *c, + struct mouse_event *m) { struct winlink *wl; struct window *w; @@ -345,7 +353,7 @@ cmd_resize_pane_mouse_update_floating(struct client *c, struct mouse_event *m) } static void -cmd_resize_pane_mouse_update_tiled(struct client *c, struct mouse_event *m) +cmd_resize_pane_mouse_resize_tiled(struct client *c, struct mouse_event *m) { struct winlink *wl; struct window *w; diff --git a/usr.bin/tmux/key-bindings.c b/usr.bin/tmux/key-bindings.c index 1ea7795152e..2bc971ded4a 100644 --- a/usr.bin/tmux/key-bindings.c +++ b/usr.bin/tmux/key-bindings.c @@ -1,4 +1,4 @@ -/* $OpenBSD: key-bindings.c,v 1.176 2026/06/13 19:57:44 nicm Exp $ */ +/* $OpenBSD: key-bindings.c,v 1.177 2026/06/17 07:52:21 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -450,6 +450,7 @@ key_bindings_init(void) /* Mouse button 1 drag on pane. */ "bind -n MouseDrag1Pane { if -F '#{||:#{pane_in_mode},#{mouse_any_flag}}' { send -M } { copy-mode -M } }", + "bind -n M-MouseDrag1Pane { move-pane -M }", /* Mouse wheel up on pane. */ "bind -n WheelUpPane { if -F '#{||:#{alternate_on},#{pane_in_mode},#{mouse_any_flag}}' { send -M } { copy-mode -e } }", @@ -468,6 +469,7 @@ key_bindings_init(void) /* Mouse button 1 drag on border. */ "bind -n MouseDrag1Border { resize-pane -M }", + "bind -n M-MouseDrag1Border { move-pane -M }", /* Mouse button 1 down on status line. */ "bind -n MouseDown1Status { switch-client -t= }", diff --git a/usr.bin/tmux/tmux.1 b/usr.bin/tmux/tmux.1 index 5767dd82bc7..71922e6419a 100644 --- a/usr.bin/tmux/tmux.1 +++ b/usr.bin/tmux/tmux.1 @@ -1,4 +1,4 @@ -.\" $OpenBSD: tmux.1,v 1.1092 2026/06/16 05:01:56 jsg Exp $ +.\" $OpenBSD: tmux.1,v 1.1093 2026/06/17 07:52:21 nicm Exp $ .\" .\" Copyright (c) 2007 Nicholas Marriott .\" @@ -14,7 +14,7 @@ .\" IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING .\" OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" -.Dd $Mdocdate: June 16 2026 $ +.Dd $Mdocdate: June 17 2026 $ .Dt TMUX 1 .Os .Sh NAME @@ -3313,7 +3313,7 @@ or reverses the sort order. .Tg movep .It Xo Ic move\-pane -.Op Fl bdfhv +.Op Fl bdfhMv .Op Fl D Op Ar lines .Op Fl l Ar size .Op Fl L Op Ar columns @@ -3385,6 +3385,10 @@ move it to an absolute position. moves the pane to the given .Ar z-index , where zero is the front. +.Pp +.Fl M +begins a mouse drag (only valid if bound to a mouse key binding, see +.Sx MOUSE SUPPORT ) . .Tg movew .It Xo Ic move\-window .Op Fl abrdk