1/* $OpenBSD: cmd-select-window.c,v 1.30 2021/08/21 10:22:39 nicm Exp $ */
2
3/*
4 * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
15 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
16 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19#include <sys/types.h>
20
21#include <stdlib.h>
22
23#include "tmux.h"
24
25/*
26 * Select window by index.
27 */
28
29static enum cmd_retval	cmd_select_window_exec(struct cmd *,
30			    struct cmdq_item *);
31
32const struct cmd_entry cmd_select_window_entry = {
33	.name = "select-window",
34	.alias = "selectw",
35
36	.args = { "lnpTt:", 0, 0, NULL },
37	.usage = "[-lnpT] " CMD_TARGET_WINDOW_USAGE,
38
39	.target = { 't', CMD_FIND_WINDOW, 0 },
40
41	.flags = 0,
42	.exec = cmd_select_window_exec
43};
44
45const struct cmd_entry cmd_next_window_entry = {
46	.name = "next-window",
47	.alias = "next",
48
49	.args = { "at:", 0, 0, NULL },
50	.usage = "[-a] " CMD_TARGET_SESSION_USAGE,
51
52	.target = { 't', CMD_FIND_SESSION, 0 },
53
54	.flags = 0,
55	.exec = cmd_select_window_exec
56};
57
58const struct cmd_entry cmd_previous_window_entry = {
59	.name = "previous-window",
60	.alias = "prev",
61
62	.args = { "at:", 0, 0, NULL },
63	.usage = "[-a] " CMD_TARGET_SESSION_USAGE,
64
65	.target = { 't', CMD_FIND_SESSION, 0 },
66
67	.flags = 0,
68	.exec = cmd_select_window_exec
69};
70
71const struct cmd_entry cmd_last_window_entry = {
72	.name = "last-window",
73	.alias = "last",
74
75	.args = { "t:", 0, 0, NULL },
76	.usage = CMD_TARGET_SESSION_USAGE,
77
78	.target = { 't', CMD_FIND_SESSION, 0 },
79
80	.flags = 0,
81	.exec = cmd_select_window_exec
82};
83
84static enum cmd_retval
85cmd_select_window_exec(struct cmd *self, struct cmdq_item *item)
86{
87	struct args		*args = cmd_get_args(self);
88	struct client		*c = cmdq_get_client(item);
89	struct cmd_find_state	*current = cmdq_get_current(item);
90	struct cmd_find_state	*target = cmdq_get_target(item);
91	struct winlink		*wl = target->wl;
92	struct session		*s = target->s;
93	int			 next, previous, last, activity;
94
95	next = (cmd_get_entry(self) == &cmd_next_window_entry);
96	if (args_has(args, 'n'))
97		next = 1;
98	previous = (cmd_get_entry(self) == &cmd_previous_window_entry);
99	if (args_has(args, 'p'))
100		previous = 1;
101	last = (cmd_get_entry(self) == &cmd_last_window_entry);
102	if (args_has(args, 'l'))
103		last = 1;
104
105	if (next || previous || last) {
106		activity = args_has(args, 'a');
107		if (next) {
108			if (session_next(s, activity) != 0) {
109				cmdq_error(item, "no next window");
110				return (CMD_RETURN_ERROR);
111			}
112		} else if (previous) {
113			if (session_previous(s, activity) != 0) {
114				cmdq_error(item, "no previous window");
115				return (CMD_RETURN_ERROR);
116			}
117		} else {
118			if (session_last(s) != 0) {
119				cmdq_error(item, "no last window");
120				return (CMD_RETURN_ERROR);
121			}
122		}
123		cmd_find_from_session(current, s, 0);
124		server_redraw_session(s);
125		cmdq_insert_hook(s, item, current, "after-select-window");
126	} else {
127		/*
128		 * If -T and select-window is invoked on same window as
129		 * current, switch to previous window.
130		 */
131		if (args_has(args, 'T') && wl == s->curw) {
132			if (session_last(s) != 0) {
133				cmdq_error(item, "no last window");
134				return (-1);
135			}
136			if (current->s == s)
137				cmd_find_from_session(current, s, 0);
138			server_redraw_session(s);
139		} else if (session_select(s, wl->idx) == 0) {
140			cmd_find_from_session(current, s, 0);
141			server_redraw_session(s);
142		}
143		cmdq_insert_hook(s, item, current, "after-select-window");
144	}
145	if (c != NULL && c->session != NULL)
146		s->curw->window->latest = c;
147	recalculate_sizes();
148
149	return (CMD_RETURN_NORMAL);
150}
151