1 /* $OpenBSD$ */
2 
3 /*
4  * Copyright (c) 2009 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 #include <string.h>
23 
24 #include "tmux.h"
25 
26 /*
27  * Select pane.
28  */
29 
30 static enum cmd_retval        cmd_select_pane_exec(struct cmd *, struct cmdq_item *);
31 
32 const struct cmd_entry cmd_select_pane_entry = {
33           .name = "select-pane",
34           .alias = "selectp",
35 
36           .args = { "DdegLlMmP:RT:t:UZ", 0, 0, NULL }, /* -P and -g deprecated */
37           .usage = "[-DdeLlMmRUZ] [-T title] " CMD_TARGET_PANE_USAGE,
38 
39           .target = { 't', CMD_FIND_PANE, 0 },
40 
41           .flags = 0,
42           .exec = cmd_select_pane_exec
43 };
44 
45 const struct cmd_entry cmd_last_pane_entry = {
46           .name = "last-pane",
47           .alias = "lastp",
48 
49           .args = { "det:Z", 0, 0, NULL },
50           .usage = "[-deZ] " CMD_TARGET_WINDOW_USAGE,
51 
52           .target = { 't', CMD_FIND_WINDOW, 0 },
53 
54           .flags = 0,
55           .exec = cmd_select_pane_exec
56 };
57 
58 static void
cmd_select_pane_redraw(struct window * w)59 cmd_select_pane_redraw(struct window *w)
60 {
61           struct client       *c;
62 
63           /*
64            * Redraw entire window if it is bigger than the client (the
65            * offset may change), otherwise just draw borders.
66            */
67 
68           TAILQ_FOREACH(c, &clients, entry) {
69                     if (c->session == NULL || (c->flags & CLIENT_CONTROL))
70                               continue;
71                     if (c->session->curw->window == w && tty_window_bigger(&c->tty))
72                               server_redraw_client(c);
73                     else {
74                               if (c->session->curw->window == w)
75                                         c->flags |= CLIENT_REDRAWBORDERS;
76                               if (session_has(c->session, w))
77                                         c->flags |= CLIENT_REDRAWSTATUS;
78                     }
79 
80           }
81 }
82 
83 static enum cmd_retval
cmd_select_pane_exec(struct cmd * self,struct cmdq_item * item)84 cmd_select_pane_exec(struct cmd *self, struct cmdq_item *item)
85 {
86           struct args                   *args = cmd_get_args(self);
87           const struct cmd_entry        *entry = cmd_get_entry(self);
88           struct cmd_find_state         *current = cmdq_get_current(item);
89           struct cmd_find_state         *target = cmdq_get_target(item);
90           struct client                 *c = cmdq_get_client(item);
91           struct winlink                *wl = target->wl;
92           struct window                 *w = wl->window;
93           struct session                *s = target->s;
94           struct window_pane  *wp = target->wp, *activewp, *lastwp, *markedwp;
95           struct options                *oo = wp->options;
96           char                          *title;
97           const char                    *style;
98           struct options_entry          *o;
99 
100           if (entry == &cmd_last_pane_entry || args_has(args, 'l')) {
101                     /*
102                      * Check for no last pane found in case the other pane was
103                      * spawned without being visited (for example split-window -d).
104                      */
105                     lastwp = TAILQ_FIRST(&w->last_panes);
106                     if (lastwp == NULL && window_count_panes(w) == 2) {
107                               lastwp = TAILQ_PREV(w->active, window_panes, entry);
108                               if (lastwp == NULL)
109                                         lastwp = TAILQ_NEXT(w->active, entry);
110                     }
111                     if (lastwp == NULL) {
112                               cmdq_error(item, "no last pane");
113                               return (CMD_RETURN_ERROR);
114                     }
115                     if (args_has(args, 'e')) {
116                               lastwp->flags &= ~PANE_INPUTOFF;
117                               server_redraw_window_borders(lastwp->window);
118                               server_status_window(lastwp->window);
119                     } else if (args_has(args, 'd')) {
120                               lastwp->flags |= PANE_INPUTOFF;
121                               server_redraw_window_borders(lastwp->window);
122                               server_status_window(lastwp->window);
123                     } else {
124                               if (window_push_zoom(w, 0, args_has(args, 'Z')))
125                                         server_redraw_window(w);
126                               window_redraw_active_switch(w, lastwp);
127                               if (window_set_active_pane(w, lastwp, 1)) {
128                                         cmd_find_from_winlink(current, wl, 0);
129                                         cmd_select_pane_redraw(w);
130                               }
131                               if (window_pop_zoom(w))
132                                         server_redraw_window(w);
133                     }
134                     return (CMD_RETURN_NORMAL);
135           }
136 
137           if (args_has(args, 'm') || args_has(args, 'M')) {
138                     if (args_has(args, 'm') && !window_pane_visible(wp))
139                               return (CMD_RETURN_NORMAL);
140                     if (server_check_marked())
141                               lastwp = marked_pane.wp;
142                     else
143                               lastwp = NULL;
144 
145                     if (args_has(args, 'M') || server_is_marked(s, wl, wp))
146                               server_clear_marked();
147                     else
148                               server_set_marked(s, wl, wp);
149                     markedwp = marked_pane.wp;
150 
151                     if (lastwp != NULL) {
152                               lastwp->flags |= (PANE_REDRAW|PANE_STYLECHANGED);
153                               server_redraw_window_borders(lastwp->window);
154                               server_status_window(lastwp->window);
155                     }
156                     if (markedwp != NULL) {
157                               markedwp->flags |= (PANE_REDRAW|PANE_STYLECHANGED);
158                               server_redraw_window_borders(markedwp->window);
159                               server_status_window(markedwp->window);
160                     }
161                     return (CMD_RETURN_NORMAL);
162           }
163 
164           style = args_get(args, 'P');
165           if (style != NULL) {
166                     o = options_set_string(oo, "window-style", 0, "%s", style);
167                     if (o == NULL) {
168                               cmdq_error(item, "bad style: %s", style);
169                               return (CMD_RETURN_ERROR);
170                     }
171                     options_set_string(oo, "window-active-style", 0, "%s", style);
172                     wp->flags |= (PANE_REDRAW|PANE_STYLECHANGED);
173           }
174           if (args_has(args, 'g')) {
175                     cmdq_print(item, "%s", options_get_string(oo, "window-style"));
176                     return (CMD_RETURN_NORMAL);
177           }
178 
179           if (args_has(args, 'L')) {
180                     window_push_zoom(w, 0, 1);
181                     wp = window_pane_find_left(wp);
182                     window_pop_zoom(w);
183           } else if (args_has(args, 'R')) {
184                     window_push_zoom(w, 0, 1);
185                     wp = window_pane_find_right(wp);
186                     window_pop_zoom(w);
187           } else if (args_has(args, 'U')) {
188                     window_push_zoom(w, 0, 1);
189                     wp = window_pane_find_up(wp);
190                     window_pop_zoom(w);
191           } else if (args_has(args, 'D')) {
192                     window_push_zoom(w, 0, 1);
193                     wp = window_pane_find_down(wp);
194                     window_pop_zoom(w);
195           }
196           if (wp == NULL)
197                     return (CMD_RETURN_NORMAL);
198 
199           if (args_has(args, 'e')) {
200                     wp->flags &= ~PANE_INPUTOFF;
201                     server_redraw_window_borders(wp->window);
202                     server_status_window(wp->window);
203                     return (CMD_RETURN_NORMAL);
204           }
205           if (args_has(args, 'd')) {
206                     wp->flags |= PANE_INPUTOFF;
207                     server_redraw_window_borders(wp->window);
208                     server_status_window(wp->window);
209                     return (CMD_RETURN_NORMAL);
210           }
211 
212           if (args_has(args, 'T')) {
213                     title = format_single_from_target(item, args_get(args, 'T'));
214                     if (screen_set_title(&wp->base, title)) {
215                               notify_pane("pane-title-changed", wp);
216                               server_redraw_window_borders(wp->window);
217                               server_status_window(wp->window);
218                     }
219                     free(title);
220                     return (CMD_RETURN_NORMAL);
221           }
222 
223           if (c != NULL && c->session != NULL && (c->flags & CLIENT_ACTIVEPANE))
224                     activewp = server_client_get_pane(c);
225           else
226                     activewp = w->active;
227           if (wp == activewp)
228                     return (CMD_RETURN_NORMAL);
229           if (window_push_zoom(w, 0, args_has(args, 'Z')))
230                     server_redraw_window(w);
231           window_redraw_active_switch(w, wp);
232           if (c != NULL && c->session != NULL && (c->flags & CLIENT_ACTIVEPANE))
233                     server_client_set_pane(c, wp);
234           else if (window_set_active_pane(w, wp, 1))
235                     cmd_find_from_winlink_pane(current, wl, wp, 0);
236           cmdq_insert_hook(s, item, current, "after-select-pane");
237           cmd_select_pane_redraw(w);
238           if (window_pop_zoom(w))
239                     server_redraw_window(w);
240 
241           return (CMD_RETURN_NORMAL);
242 }
243