summaryrefslogtreecommitdiff
path: root/usr.bin/tmux
diff options
context:
space:
mode:
authorNicholas Marriott <nicm@cvs.openbsd.org>2015-06-04 11:43:52 +0000
committerNicholas Marriott <nicm@cvs.openbsd.org>2015-06-04 11:43:52 +0000
commit484368b54332b70c1fa2134c6b39939e86b8afeb (patch)
tree945855293c66b90b8696e405cdab19b7b12d136a /usr.bin/tmux
parent4d710c395c58bda9fbd62bb57cabf8c2587503ab (diff)
Add support for a single "marked pane". There is one marked pane in the
server at a time; it may be toggled or cleared with select-pane -m and -M (the border is highlighted). A new target '~' or '{marked}' specifies the marked pane to commands and it is the default target for the swap-pane and join-pane -s flag (this makes them much simpler to use - mark the source pane and then change to the target pane to run swapp or joinp).
Diffstat (limited to 'usr.bin/tmux')
-rw-r--r--usr.bin/tmux/cmd-find.c67
-rw-r--r--usr.bin/tmux/cmd-join-pane.c4
-rw-r--r--usr.bin/tmux/cmd-select-pane.c33
-rw-r--r--usr.bin/tmux/cmd-swap-pane.c10
-rw-r--r--usr.bin/tmux/cmd-swap-window.c4
-rw-r--r--usr.bin/tmux/key-bindings.c5
-rw-r--r--usr.bin/tmux/screen-redraw.c46
-rw-r--r--usr.bin/tmux/server.c94
-rw-r--r--usr.bin/tmux/tmux.175
-rw-r--r--usr.bin/tmux/tmux.h15
-rw-r--r--usr.bin/tmux/window.c7
11 files changed, 308 insertions, 52 deletions
diff --git a/usr.bin/tmux/cmd-find.c b/usr.bin/tmux/cmd-find.c
index 28c97585c39..dcfda1cf8f4 100644
--- a/usr.bin/tmux/cmd-find.c
+++ b/usr.bin/tmux/cmd-find.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: cmd-find.c,v 1.7 2015/05/07 11:42:56 nicm Exp $ */
+/* $OpenBSD: cmd-find.c,v 1.8 2015/06/04 11:43:51 nicm Exp $ */
/*
* Copyright (c) 2015 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -29,6 +29,7 @@
#define CMD_FIND_PREFER_UNATTACHED 0x1
#define CMD_FIND_QUIET 0x2
#define CMD_FIND_WINDOW_INDEX 0x4
+#define CMD_FIND_DEFAULT_MARKED 0x8
enum cmd_find_type {
CMD_FIND_PANE,
@@ -759,7 +760,14 @@ cmd_find_target(struct cmd_q *cmdq, const char *target, enum cmd_find_type type,
/* Find current state. */
cmd_find_clear_state(&current, cmdq, flags);
- if (cmd_find_current_session(&current) != 0) {
+ if (server_check_marked() && (flags & CMD_FIND_DEFAULT_MARKED)) {
+ current.s = marked_session;
+ current.wl = marked_winlink;
+ current.idx = current.wl->idx;
+ current.w = current.wl->window;
+ current.wp = marked_window_pane;
+ }
+ if (current.s == NULL && cmd_find_current_session(&current) != 0) {
if (~flags & CMD_FIND_QUIET)
cmdq_error(cmdq, "no current session");
goto error;
@@ -798,9 +806,24 @@ cmd_find_target(struct cmd_q *cmdq, const char *target, enum cmd_find_type type,
}
return (&fs);
}
- copy = xstrdup(target);
+
+ /* Marked target is a plain ~ or {marked}. */
+ if (strcmp(target, "~") == 0 || strcmp(target, "{marked}") == 0) {
+ if (!server_check_marked()) {
+ if (~flags & CMD_FIND_QUIET)
+ cmdq_error(cmdq, "no marked target");
+ goto error;
+ }
+ fs.s = marked_session;
+ fs.wl = marked_winlink;
+ fs.idx = fs.wl->idx;
+ fs.w = fs.wl->window;
+ fs.wp = marked_window_pane;
+ return (&fs);
+ }
/* Find separators if they exist. */
+ copy = xstrdup(target);
colon = strchr(copy, ':');
if (colon != NULL)
*colon++ = '\0';
@@ -1053,6 +1076,24 @@ cmd_find_window(struct cmd_q *cmdq, const char *target, struct session **sp)
return (fs->wl);
}
+/* Find the target window, defaulting to marked rather than current. */
+struct winlink *
+cmd_find_window_marked(struct cmd_q *cmdq, const char *target,
+ struct session **sp)
+{
+ struct cmd_find_state *fs;
+ int flags = CMD_FIND_DEFAULT_MARKED;
+
+ fs = cmd_find_target(cmdq, target, CMD_FIND_WINDOW, flags);
+ cmd_find_log_state(__func__, target, fs);
+ if (fs == NULL)
+ return (NULL);
+
+ if (sp != NULL)
+ *sp = fs->s;
+ return (fs->wl);
+}
+
/* Find the target pane and report an error and return NULL. */
struct winlink *
cmd_find_pane(struct cmd_q *cmdq, const char *target, struct session **sp,
@@ -1072,6 +1113,26 @@ cmd_find_pane(struct cmd_q *cmdq, const char *target, struct session **sp,
return (fs->wl);
}
+/* Find the target pane, defaulting to marked rather than current. */
+struct winlink *
+cmd_find_pane_marked(struct cmd_q *cmdq, const char *target,
+ struct session **sp, struct window_pane **wpp)
+{
+ struct cmd_find_state *fs;
+ int flags = CMD_FIND_DEFAULT_MARKED;
+
+ fs = cmd_find_target(cmdq, target, CMD_FIND_PANE, flags);
+ cmd_find_log_state(__func__, target, fs);
+ if (fs == NULL)
+ return (NULL);
+
+ if (sp != NULL)
+ *sp = fs->s;
+ if (wpp != NULL)
+ *wpp = fs->wp;
+ return (fs->wl);
+}
+
/* Find the target client or report an error and return NULL. */
struct client *
cmd_find_client(struct cmd_q *cmdq, const char *target, int quiet)
diff --git a/usr.bin/tmux/cmd-join-pane.c b/usr.bin/tmux/cmd-join-pane.c
index f8fa8a6cc4e..d9971e31eaa 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.17 2014/10/20 22:29:25 nicm Exp $ */
+/* $OpenBSD: cmd-join-pane.c,v 1.18 2015/06/04 11:43:51 nicm Exp $ */
/*
* Copyright (c) 2011 George Nachman <tmux@georgester.com>
@@ -75,7 +75,7 @@ join_pane(struct cmd *self, struct cmd_q *cmdq, int not_same_window)
dst_idx = dst_wl->idx;
server_unzoom_window(dst_w);
- src_wl = cmd_find_pane(cmdq, args_get(args, 's'), NULL, &src_wp);
+ src_wl = cmd_find_pane_marked(cmdq, args_get(args, 's'), NULL, &src_wp);
if (src_wl == NULL)
return (CMD_RETURN_ERROR);
src_w = src_wl->window;
diff --git a/usr.bin/tmux/cmd-select-pane.c b/usr.bin/tmux/cmd-select-pane.c
index 85cfc4044f9..248e5ace8e4 100644
--- a/usr.bin/tmux/cmd-select-pane.c
+++ b/usr.bin/tmux/cmd-select-pane.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: cmd-select-pane.c,v 1.23 2015/04/29 16:26:17 nicm Exp $ */
+/* $OpenBSD: cmd-select-pane.c,v 1.24 2015/06/04 11:43:51 nicm Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -28,8 +28,8 @@ enum cmd_retval cmd_select_pane_exec(struct cmd *, struct cmd_q *);
const struct cmd_entry cmd_select_pane_entry = {
"select-pane", "selectp",
- "DdegLlP:Rt:U", 0, 0,
- "[-DdegLlRU] [-P style] " CMD_TARGET_PANE_USAGE,
+ "DdegLlMmP:Rt:U", 0, 0,
+ "[-DdegLlMmRU] [-P style] " CMD_TARGET_PANE_USAGE,
0,
cmd_select_pane_exec
};
@@ -47,7 +47,8 @@ cmd_select_pane_exec(struct cmd *self, struct cmd_q *cmdq)
{
struct args *args = self->args;
struct winlink *wl;
- struct window_pane *wp;
+ struct session *s;
+ struct window_pane *wp, *lastwp, *markedwp;
const char *style;
if (self->entry == &cmd_last_pane_entry || args_has(args, 'l')) {
@@ -74,9 +75,31 @@ cmd_select_pane_exec(struct cmd *self, struct cmd_q *cmdq)
return (CMD_RETURN_NORMAL);
}
- if ((wl = cmd_find_pane(cmdq, args_get(args, 't'), NULL, &wp)) == NULL)
+ if ((wl = cmd_find_pane(cmdq, args_get(args, 't'), &s, &wp)) == NULL)
return (CMD_RETURN_ERROR);
+ if (args_has(args, 'm') || args_has(args, 'M')) {
+ if (args_has(args, 'm') && !window_pane_visible(wp))
+ return (CMD_RETURN_NORMAL);
+ lastwp = marked_window_pane;
+
+ if (args_has(args, 'M') || server_is_marked(s, wl, wp))
+ server_clear_marked();
+ else
+ server_set_marked(s, wl, wp);
+ markedwp = marked_window_pane;
+
+ if (lastwp != NULL) {
+ server_redraw_window_borders(lastwp->window);
+ server_status_window(lastwp->window);
+ }
+ if (markedwp != NULL) {
+ server_redraw_window_borders(markedwp->window);
+ server_status_window(markedwp->window);
+ }
+ return (CMD_RETURN_NORMAL);
+ }
+
if (args_has(self->args, 'P') || args_has(self->args, 'g')) {
if (args_has(args, 'P')) {
style = args_get(args, 'P');
diff --git a/usr.bin/tmux/cmd-swap-pane.c b/usr.bin/tmux/cmd-swap-pane.c
index 59554c1087c..100d18c7c17 100644
--- a/usr.bin/tmux/cmd-swap-pane.c
+++ b/usr.bin/tmux/cmd-swap-pane.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: cmd-swap-pane.c,v 1.19 2014/10/20 22:29:25 nicm Exp $ */
+/* $OpenBSD: cmd-swap-pane.c,v 1.20 2015/06/04 11:43:51 nicm Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -58,18 +58,22 @@ cmd_swap_pane_exec(struct cmd *self, struct cmd_q *cmdq)
src_wp = TAILQ_NEXT(dst_wp, entry);
if (src_wp == NULL)
src_wp = TAILQ_FIRST(&dst_w->panes);
+ src_wl = dst_wl;
} else if (args_has(self->args, 'U')) {
src_wp = TAILQ_PREV(dst_wp, window_panes, entry);
if (src_wp == NULL)
src_wp = TAILQ_LAST(&dst_w->panes, window_panes);
+ src_wl = dst_wl;
} else {
- src_wl = cmd_find_pane(cmdq, NULL, NULL, &src_wp);
+ src_wl = cmd_find_pane_marked(cmdq, NULL, NULL,
+ &src_wp);
if (src_wl == NULL)
return (CMD_RETURN_ERROR);
src_w = src_wl->window;
}
} else {
- src_wl = cmd_find_pane(cmdq, args_get(args, 's'), NULL, &src_wp);
+ src_wl = cmd_find_pane_marked(cmdq, args_get(args, 's'), NULL,
+ &src_wp);
if (src_wl == NULL)
return (CMD_RETURN_ERROR);
src_w = src_wl->window;
diff --git a/usr.bin/tmux/cmd-swap-window.c b/usr.bin/tmux/cmd-swap-window.c
index a8cd845fc7f..bae3ec56875 100644
--- a/usr.bin/tmux/cmd-swap-window.c
+++ b/usr.bin/tmux/cmd-swap-window.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: cmd-swap-window.c,v 1.11 2014/10/20 22:29:25 nicm Exp $ */
+/* $OpenBSD: cmd-swap-window.c,v 1.12 2015/06/04 11:43:51 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -47,7 +47,7 @@ cmd_swap_window_exec(struct cmd *self, struct cmd_q *cmdq)
struct window *w;
target_src = args_get(args, 's');
- if ((wl_src = cmd_find_window(cmdq, target_src, &src)) == NULL)
+ if ((wl_src = cmd_find_window_marked(cmdq, target_src, &src)) == NULL)
return (CMD_RETURN_ERROR);
target_dst = args_get(args, 't');
if ((wl_dst = cmd_find_window(cmdq, target_dst, &dst)) == NULL)
diff --git a/usr.bin/tmux/key-bindings.c b/usr.bin/tmux/key-bindings.c
index af436d3af05..bcee036815b 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.48 2015/05/07 11:42:56 nicm Exp $ */
+/* $OpenBSD: key-bindings.c,v 1.49 2015/06/04 11:43:51 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -177,6 +177,7 @@ key_bindings_init(void)
"bind ? list-keys",
"bind D choose-client",
"bind L switch-client -l",
+ "bind M select-pane -M",
"bind [ copy-mode",
"bind ] paste-buffer",
"bind c new-window",
@@ -184,6 +185,7 @@ key_bindings_init(void)
"bind f command-prompt \"find-window '%%'\"",
"bind i display-message",
"bind l last-window",
+ "bind m select-pane -m",
"bind n next-window",
"bind o select-pane -t:.+",
"bind p previous-window",
@@ -222,6 +224,7 @@ key_bindings_init(void)
"bind -n MouseDrag1Border resize-pane -M",
"bind -n MouseDown1Status select-window -t=",
"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 select-pane -mt=",
};
u_int i;
struct cmd_list *cmdlist;
diff --git a/usr.bin/tmux/screen-redraw.c b/usr.bin/tmux/screen-redraw.c
index 396500cf4a8..1f86a2da8f9 100644
--- a/usr.bin/tmux/screen-redraw.c
+++ b/usr.bin/tmux/screen-redraw.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: screen-redraw.c,v 1.31 2015/05/07 07:16:14 nicm Exp $ */
+/* $OpenBSD: screen-redraw.c,v 1.32 2015/06/04 11:43:51 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -26,8 +26,8 @@ int screen_redraw_cell_border1(struct window_pane *, u_int, u_int);
int screen_redraw_cell_border(struct client *, u_int, u_int);
int screen_redraw_check_cell(struct client *, u_int, u_int,
struct window_pane **);
-int screen_redraw_check_active(u_int, u_int, int, struct window *,
- struct window_pane *);
+int screen_redraw_check_is(u_int, u_int, int, struct window *,
+ struct window_pane *, struct window_pane *);
void screen_redraw_draw_borders(struct client *, int, u_int);
void screen_redraw_draw_panes(struct client *, u_int);
@@ -175,13 +175,13 @@ screen_redraw_check_cell(struct client *c, u_int px, u_int py,
return (CELL_OUTSIDE);
}
-/* Check active pane indicator. */
+/* Check if the border of a particular pane. */
int
-screen_redraw_check_active(u_int px, u_int py, int type, struct window *w,
- struct window_pane *wp)
+screen_redraw_check_is(u_int px, u_int py, int type, struct window *w,
+ struct window_pane *wantwp, struct window_pane *wp)
{
/* Is this off the active pane border? */
- if (screen_redraw_cell_border1(w->active, px, py) != 1)
+ if (screen_redraw_cell_border1(wantwp, px, py) != 1)
return (0);
/* If there are more than two panes, that's enough. */
@@ -196,7 +196,7 @@ screen_redraw_check_active(u_int px, u_int py, int type, struct window *w,
if (wp->xoff == 0 && wp->sx == w->sx) {
/* This can either be the top pane or the bottom pane. */
if (wp->yoff == 0) { /* top pane */
- if (wp == w->active)
+ if (wp == wantwp)
return (px <= wp->sx / 2);
return (px > wp->sx / 2);
}
@@ -207,7 +207,7 @@ screen_redraw_check_active(u_int px, u_int py, int type, struct window *w,
if (wp->yoff == 0 && wp->sy == w->sy) {
/* This can either be the left pane or the right pane. */
if (wp->xoff == 0) { /* left pane */
- if (wp == w->active)
+ if (wp == wantwp)
return (py <= wp->sy / 2);
return (py > wp->sy / 2);
}
@@ -274,13 +274,15 @@ screen_redraw_pane(struct client *c, struct window_pane *wp)
void
screen_redraw_draw_borders(struct client *c, int status, u_int top)
{
- struct window *w = c->session->curw->window;
+ struct session *s = c->session;
+ struct window *w = s->curw->window;
struct options *oo = &w->options;
struct tty *tty = &c->tty;
struct window_pane *wp;
- struct grid_cell active_gc, other_gc, msg_gc;
+ struct grid_cell m_active_gc, active_gc, m_other_gc, other_gc;
+ struct grid_cell msg_gc;
u_int i, j, type, msgx = 0, msgy = 0;
- int small, flags;
+ int active, small, flags;
char msg[256];
const char *tmp;
size_t msglen = 0;
@@ -314,15 +316,29 @@ screen_redraw_draw_borders(struct client *c, int status, u_int top)
style_apply(&active_gc, oo, "pane-active-border-style");
active_gc.attr = other_gc.attr = GRID_ATTR_CHARSET;
+ memcpy(&m_other_gc, &other_gc, sizeof m_other_gc);
+ m_other_gc.attr ^= GRID_ATTR_REVERSE;
+ memcpy(&m_active_gc, &active_gc, sizeof m_active_gc);
+ m_active_gc.attr ^= GRID_ATTR_REVERSE;
+
for (j = 0; j < tty->sy - status; j++) {
for (i = 0; i < tty->sx; i++) {
type = screen_redraw_check_cell(c, i, j, &wp);
if (type == CELL_INSIDE)
continue;
- if (type == CELL_OUTSIDE &&
- small && i > msgx && j == msgy)
+ if (type == CELL_OUTSIDE && small &&
+ i > msgx && j == msgy)
continue;
- if (screen_redraw_check_active(i, j, type, w, wp))
+ active = screen_redraw_check_is(i, j, type, w,
+ w->active, wp);
+ if (server_is_marked(s, s->curw, marked_window_pane) &&
+ screen_redraw_check_is(i, j, type, w,
+ marked_window_pane, wp)) {
+ if (active)
+ tty_attributes(tty, &m_active_gc, NULL);
+ else
+ tty_attributes(tty, &m_other_gc, NULL);
+ } else if (active)
tty_attributes(tty, &active_gc, NULL);
else
tty_attributes(tty, &other_gc, NULL);
diff --git a/usr.bin/tmux/server.c b/usr.bin/tmux/server.c
index 53d65d55a91..98cecda9379 100644
--- a/usr.bin/tmux/server.c
+++ b/usr.bin/tmux/server.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: server.c,v 1.125 2015/06/01 09:20:19 nicm Exp $ */
+/* $OpenBSD: server.c,v 1.126 2015/06/04 11:43:51 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -50,19 +50,85 @@ int server_shutdown;
struct event server_ev_accept;
struct event server_ev_second;
-int server_create_socket(void);
-void server_loop(void);
-int server_should_shutdown(void);
-void server_send_shutdown(void);
-void server_clean_dead(void);
-void server_accept_callback(int, short, void *);
-void server_signal_callback(int, short, void *);
-void server_child_signal(void);
-void server_child_exited(pid_t, int);
-void server_child_stopped(pid_t, int);
-void server_second_callback(int, short, void *);
-void server_lock_server(void);
-void server_lock_sessions(void);
+struct session *marked_session;
+struct winlink *marked_winlink;
+struct window *marked_window;
+struct window_pane *marked_window_pane;
+struct layout_cell *marked_layout_cell;
+
+int server_create_socket(void);
+void server_loop(void);
+int server_should_shutdown(void);
+void server_send_shutdown(void);
+void server_clean_dead(void);
+void server_accept_callback(int, short, void *);
+void server_signal_callback(int, short, void *);
+void server_child_signal(void);
+void server_child_exited(pid_t, int);
+void server_child_stopped(pid_t, int);
+void server_second_callback(int, short, void *);
+void server_lock_server(void);
+void server_lock_sessions(void);
+
+/* Set marked pane. */
+void
+server_set_marked(struct session *s, struct winlink *wl, struct window_pane *wp)
+{
+ marked_session = s;
+ marked_winlink = wl;
+ marked_window = wl->window;
+ marked_window_pane = wp;
+ marked_layout_cell = wp->layout_cell;
+}
+
+/* Clear marked pane. */
+void
+server_clear_marked(void)
+{
+ marked_session = NULL;
+ marked_winlink = NULL;
+ marked_window = NULL;
+ marked_window_pane = NULL;
+ marked_layout_cell = NULL;
+}
+
+/* Is this the marked pane? */
+int
+server_is_marked(struct session *s, struct winlink *wl, struct window_pane *wp)
+{
+ if (s == NULL || wl == NULL || wp == NULL)
+ return (0);
+ if (marked_session != s || marked_winlink != wl)
+ return (0);
+ if (marked_window_pane != wp)
+ return (0);
+ return (server_check_marked());
+}
+
+/* Check if the marked pane is still valid. */
+int
+server_check_marked(void)
+{
+ struct winlink *wl;
+
+ if (marked_window_pane == NULL)
+ return (0);
+ if (marked_layout_cell != marked_window_pane->layout_cell)
+ return (0);
+
+ if (!session_alive(marked_session))
+ return (0);
+ RB_FOREACH(wl, winlinks, &marked_session->windows) {
+ if (wl->window == marked_window && wl == marked_winlink)
+ break;
+ }
+ if (wl == NULL)
+ return (0);
+
+ if (!window_has_pane(marked_window, marked_window_pane))
+ return (0);
+ return (window_pane_visible(marked_window_pane));
+}
/* Create server socket. */
int
diff --git a/usr.bin/tmux/tmux.1 b/usr.bin/tmux/tmux.1
index 6d0fd14deca..bd5a4c17bab 100644
--- a/usr.bin/tmux/tmux.1
+++ b/usr.bin/tmux/tmux.1
@@ -1,4 +1,4 @@
-.\" $OpenBSD: tmux.1,v 1.431 2015/05/27 13:28:04 nicm Exp $
+.\" $OpenBSD: tmux.1,v 1.432 2015/06/04 11:43:51 nicm Exp $
.\"
.\" Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
.\"
@@ -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: May 27 2015 $
+.Dd $Mdocdate: June 4 2015 $
.Dt TMUX 1
.Os
.Sh NAME
@@ -298,6 +298,12 @@ Change to the previous window.
Briefly display pane indexes.
.It r
Force redraw of the attached client.
+.It m
+Mark the current pane (see
+.Ic select-pane
+.Fl m ) .
+.It M
+Clear the marked pane.
.It s
Select a new session for the attached client interactively.
.It t
@@ -351,6 +357,8 @@ This section contains a list of the commands supported by
.Nm .
Most commands accept the optional
.Fl t
+(and sometimes
+.Fl s )
argument with one of
.Ar target-client ,
.Ar target-session
@@ -451,7 +459,6 @@ Each has a single-character alternative form.
.It Li "{last}" Ta "!" Ta "The last (previously current) window"
.It Li "{next}" Ta "+" Ta "The next window by number"
.It Li "{previous}" Ta "-" Ta "The previous window by number"
-.It Li "{mouse}" Ta "=" Ta "The window where the mouse event happened"
.El
.Pp
.Ar target-pane
@@ -481,7 +488,6 @@ The following special tokens are available for the pane index:
.It Li "{down}" Ta "" Ta "The pane below the active pane"
.It Li "{left}" Ta "" Ta "The pane to the left of the active pane"
.It Li "{right}" Ta "" Ta "The pane to the right of the active pane"
-.It Li "{mouse}" Ta "=" Ta "The pane where the mouse event happened"
.El
.Pp
The tokens
@@ -493,6 +499,27 @@ may be followed by an offset, for example:
select-window -t:+2
.Ed
.Pp
+In addition,
+.Em target-session ,
+.Em target-window
+or
+.Em target-pane
+may consist entirely of the token
+.Ql {mouse}
+(alternative form
+.Ql = )
+to specify the most recent mouse event
+(see the
+.Sx MOUSE SUPPORT
+section)
+or
+.Ql {marked}
+(alternative form
+.Ql ~ )
+to specify the marked pane (see
+.Ic select-pane
+.Fl m ) .
+.Pp
Sessions, window and panes are each numbered with a unique ID; session IDs are
prefixed with a
.Ql $ ,
@@ -1440,6 +1467,13 @@ option causes
.Ar src-pane
to be joined to left of or above
.Ar dst-pane .
+.Pp
+If
+.Fl s
+is omitted and a marked pane is present (see
+.Ic select-pane
+.Fl m ) ,
+the marked pane is used rather than the current pane.
.It Xo Ic kill-pane
.Op Fl a
.Op Fl t Ar target-pane
@@ -1795,7 +1829,7 @@ commands.
.Fl o
applies the last set layout if possible (undoes the most recent layout change).
.It Xo Ic select-pane
-.Op Fl DdegLlRU
+.Op Fl DdegLlMmRU
.Op Fl P Ar style
.Op Fl t Ar target-pane
.Xc
@@ -1823,6 +1857,20 @@ enables or
.Fl d
disables input to the pane.
.Pp
+.Fl m
+and
+.Fl M
+are used to set and clear the
+.Em marked pane .
+There is one marked pane at a time, setting a new marked pane clears the last.
+The marked pane is the default target for
+.Fl s
+to
+.Ic join-pane ,
+.Ic swap-pane
+and
+.Ic swap-window .
+.Pp
Each pane has a style: by default the
.Ic window-style
and
@@ -1911,6 +1959,13 @@ swaps with the next pane (after it numerically).
instructs
.Nm
not to change the active pane.
+.Pp
+If
+.Fl s
+is omitted and a marked pane is present (see
+.Ic select-pane
+.Fl m ) ,
+the marked pane is used rather than the current pane.
.It Xo Ic swap-window
.Op Fl d
.Op Fl s Ar src-window
@@ -1922,6 +1977,15 @@ This is similar to
except the source and destination windows are swapped.
It is an error if no window exists at
.Ar src-window .
+.Pp
+Like
+.Ic swap-pane ,
+if
+.Fl s
+is omitted and a marked pane is present (see
+.Ic select-pane
+.Fl m ) ,
+the window containing the marked pane is used rather than the current window.
.It Xo Ic unlink-window
.Op Fl k
.Op Fl t Ar target-window
@@ -3488,6 +3552,7 @@ The flag is one of the following symbols appended to the window name:
.It Li "#" Ta "Window is monitored and activity has been detected."
.It Li "!" Ta "A bell has occurred in the window."
.It Li "~" Ta "The window has been silent for the monitor-silence interval."
+.It Li "M" Ta "The window contains the marked pane."
.It Li "Z" Ta "The window's active pane is zoomed."
.El
.Pp
diff --git a/usr.bin/tmux/tmux.h b/usr.bin/tmux/tmux.h
index a79ac4a887d..d3e835a5bf5 100644
--- a/usr.bin/tmux/tmux.h
+++ b/usr.bin/tmux/tmux.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: tmux.h,v 1.515 2015/05/27 13:28:04 nicm Exp $ */
+/* $OpenBSD: tmux.h,v 1.516 2015/06/04 11:43:51 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -1688,8 +1688,12 @@ struct session *cmd_find_current(struct cmd_q *);
struct session *cmd_find_session(struct cmd_q *, const char *, int);
struct winlink *cmd_find_window(struct cmd_q *, const char *,
struct session **);
+struct winlink *cmd_find_window_marked(struct cmd_q *, const char *,
+ struct session **);
struct winlink *cmd_find_pane(struct cmd_q *, const char *, struct session **,
struct window_pane **);
+struct winlink *cmd_find_pane_marked(struct cmd_q *, const char *,
+ struct session **, struct window_pane **);
struct client *cmd_find_client(struct cmd_q *, const char *, int);
int cmd_find_index(struct cmd_q *, const char *,
struct session **);
@@ -1850,6 +1854,15 @@ const char *key_string_lookup_key(int);
/* server.c */
extern struct clients clients;
extern struct clients dead_clients;
+extern struct session *marked_session;
+extern struct winlink *marked_winlink;
+extern struct window_pane *marked_window_pane;
+void server_set_marked(struct session *, struct winlink *,
+ struct window_pane *);
+void server_clear_marked(void);
+int server_is_marked(struct session *, struct winlink *,
+ struct window_pane *);
+int server_check_marked(void);
int server_start(int, char *);
void server_update_socket(void);
void server_add_accept(int);
diff --git a/usr.bin/tmux/window.c b/usr.bin/tmux/window.c
index e7e49eec5b8..94489e1772c 100644
--- a/usr.bin/tmux/window.c
+++ b/usr.bin/tmux/window.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: window.c,v 1.131 2015/05/12 22:40:38 nicm Exp $ */
+/* $OpenBSD: window.c,v 1.132 2015/06/04 11:43:51 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -543,6 +543,9 @@ window_add_pane(struct window *w, u_int hlimit)
void
window_lost_pane(struct window *w, struct window_pane *wp)
{
+ if (wp == marked_window_pane)
+ server_clear_marked();
+
if (wp == w->active) {
w->active = w->last;
w->last = NULL;
@@ -661,6 +664,8 @@ window_printable_flags(struct session *s, struct winlink *wl)
flags[pos++] = '*';
if (wl == TAILQ_FIRST(&s->lastw))
flags[pos++] = '-';
+ if (server_check_marked() && wl == marked_winlink)
+ flags[pos++] = 'M';
if (wl->window->flags & WINDOW_ZOOMED)
flags[pos++] = 'Z';
flags[pos] = '\0';