From 90f4e149c1b8c2211727d5e9c3eecf8f4dd9b151 Mon Sep 17 00:00:00 2001
From: nicm <nicm>
Date: Thu, 2 Apr 2020 05:35:15 +0000
Subject: [PATCH] Add a W position to display-menu -y to use the line above (or
 below) the status line containing the window list. Leave S meaning above (or
 below) all status lines. GitHub issue 2145.

---
 cmd-display-menu.c | 52 +++++++++++++++++++++++++++++++++++++---------
 key-bindings.c     |  6 +++---
 tmux.1             |  2 +-
 3 files changed, 46 insertions(+), 14 deletions(-)

diff --git a/cmd-display-menu.c b/cmd-display-menu.c
index 3e756116..852c540e 100644
--- a/cmd-display-menu.c
+++ b/cmd-display-menu.c
@@ -65,12 +65,26 @@ static void
 cmd_display_menu_get_position(struct client *c, struct cmdq_item *item,
     struct args *args, u_int *px, u_int *py, u_int w, u_int h)
 {
+	struct session		*s = c->session;
 	struct winlink		*wl = item->target.wl;
 	struct window_pane	*wp = item->target.wp;
+	struct style_ranges	*ranges;
 	struct style_range	*sr;
 	const char		*xp, *yp;
-	int			 at = status_at_line(c);
-	u_int			 ox, oy, sx, sy;
+	u_int			 line, ox, oy, sx, sy, lines;
+
+	lines = status_line_size(c);
+	for (line = 0; line < lines; line++) {
+		ranges = &c->status.entries[line].ranges;
+		TAILQ_FOREACH(sr, ranges, entry) {
+			if (sr->type == STYLE_RANGE_WINDOW)
+				break;
+		}
+		if (sr != NULL)
+			break;
+	}
+	if (line == lines)
+		ranges = &c->status.entries[0].ranges;
 
 	xp = args_get(args, 'x');
 	if (xp == NULL || strcmp(xp, "C") == 0)
@@ -89,10 +103,10 @@ cmd_display_menu_get_position(struct client *c, struct cmdq_item *item,
 		else
 			*px = 0;
 	} else if (strcmp(xp, "W") == 0) {
-		if (at == -1)
+		if (status_at_line(c) == -1)
 			*px = 0;
 		else {
-			TAILQ_FOREACH(sr, &c->status.entries[0].ranges, entry) {
+			TAILQ_FOREACH(sr, ranges, entry) {
 				if (sr->type != STYLE_RANGE_WINDOW)
 					continue;
 				if (sr->argument == (u_int)wl->idx)
@@ -120,12 +134,30 @@ cmd_display_menu_get_position(struct client *c, struct cmdq_item *item,
 	} else if (strcmp(yp, "M") == 0 && item->shared->mouse.valid)
 		*py = item->shared->mouse.y + h;
 	else if (strcmp(yp, "S") == 0) {
-		if (at == -1)
-			*py = c->tty.sy;
-		else if (at == 0)
-			*py = status_line_size(c) + h;
-		else
-			*py = at;
+		if (options_get_number(s->options, "status-position") == 0) {
+			if (lines != 0)
+				*py = lines + h;
+			else
+				*py = 0;
+		} else {
+			if (lines != 0)
+				*py = c->tty.sy - lines;
+			else
+				*py = c->tty.sy;
+		}
+	}
+	else if (strcmp(yp, "W") == 0) {
+		if (options_get_number(s->options, "status-position") == 0) {
+			if (lines != 0)
+				*py = line + 1 + h;
+			else
+				*py = 0;
+		} else {
+			if (lines != 0)
+				*py = c->tty.sy - lines + line;
+			else
+				*py = c->tty.sy;
+		}
 	} else
 		*py = strtoul(yp, NULL, 10);
 	if (*py < h)
diff --git a/key-bindings.c b/key-bindings.c
index a528a6c0..e9f175d0 100644
--- a/key-bindings.c
+++ b/key-bindings.c
@@ -317,7 +317,7 @@ key_bindings_init(void)
 		"bind -N 'Resize the pane right' -r C-Right resize-pane -R",
 
 		/* Menu keys */
-		"bind < display-menu -xW -yS -T '#[align=centre]#{window_index}:#{window_name}' " DEFAULT_WINDOW_MENU,
+		"bind < display-menu -xW -yW -T '#[align=centre]#{window_index}:#{window_name}' " DEFAULT_WINDOW_MENU,
 		"bind > display-menu -xP -yP -T '#[align=centre]#{pane_index} (#{pane_id})' " DEFAULT_PANE_MENU,
 
 		/* Mouse button 1 down on pane. */
@@ -351,10 +351,10 @@ key_bindings_init(void)
 		"bind -n WheelUpStatus previous-window",
 
 		/* Mouse button 3 down on status left. */
-		"bind -n MouseDown3StatusLeft display-menu -t= -xM -yS -T '#[align=centre]#{session_name}' " DEFAULT_SESSION_MENU,
+		"bind -n MouseDown3StatusLeft display-menu -t= -xM -yW -T '#[align=centre]#{session_name}' " DEFAULT_SESSION_MENU,
 
 		/* Mouse button 3 down on status line. */
-		"bind -n MouseDown3Status display-menu -t= -xW -yS -T '#[align=centre]#{window_index}:#{window_name}' " DEFAULT_WINDOW_MENU,
+		"bind -n MouseDown3Status display-menu -t= -xW -yW -T '#[align=centre]#{window_index}:#{window_name}' " DEFAULT_WINDOW_MENU,
 
 		/* Mouse button 3 down on pane. */
 		"bind -n MouseDown3Pane if -Ft= '#{||:#{mouse_any_flag},#{&&:#{pane_in_mode},#{?#{m/r:(copy|view)-mode,#{pane_mode}},0,1}}}' { select-pane -t=; send -M } { display-menu -t= -xM -yM -T '#[align=centre]#{pane_index} (#{pane_id})' " DEFAULT_PANE_MENU " }",
diff --git a/tmux.1 b/tmux.1
index ab214fe8..9346c443 100644
--- a/tmux.1
+++ b/tmux.1
@@ -4985,7 +4985,7 @@ Both may be a row or column number, or one of the following special values:
 .It Li "R" Ta Fl x Ta "The right side of the terminal"
 .It Li "P" Ta "Both" Ta "The bottom left of the pane"
 .It Li "M" Ta "Both" Ta "The mouse position"
-.It Li "W" Ta Fl x Ta "The window position on the status line"
+.It Li "W" Ta "Both" Ta "The window position on the status line"
 .It Li "S" Ta Fl y Ta "The line above or below the status line"
 .El
 .Pp