blob: 236d2436b9ddefe19af581f64ca17659f509643b [file] [log] [blame] [raw]
Nicholas Marriott747cab42014-11-08 12:27:43 +00001/* $OpenBSD$ */
Nicholas Marriotta41ece52007-07-09 19:04:12 +00002
3/*
nicm995af0e2016-01-19 15:59:12 +00004 * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
Nicholas Marriotta41ece52007-07-09 19:04:12 +00005 *
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>
Nicholas Marriotta41ece52007-07-09 19:04:12 +000020
Nicholas Marriott4d9af272009-01-23 16:59:14 +000021#include <errno.h>
Nicholas Marriotta41ece52007-07-09 19:04:12 +000022#include <fcntl.h>
Nicholas Marriottf7a9eb42009-06-25 16:04:24 +000023#include <fnmatch.h>
Nicholas Marriott782dd942016-02-17 23:21:58 +000024#include <signal.h>
Nicholas Marriott35876ea2009-06-01 22:58:49 +000025#include <stdint.h>
Nicholas Marriotta41ece52007-07-09 19:04:12 +000026#include <stdlib.h>
27#include <string.h>
Nicholas Marriotta41ece52007-07-09 19:04:12 +000028#include <termios.h>
29#include <unistd.h>
Nicholas Marriottcf77c802007-10-19 20:47:09 +000030
Nicholas Marriottc8cf4382009-05-13 23:27:00 +000031#include "tmux.h"
Nicholas Marriotta41ece52007-07-09 19:04:12 +000032
33/*
Tiago Cunha545893d2009-07-20 15:42:05 +000034 * Each window is attached to a number of panes, each of which is a pty. This
Nicholas Marriott162bacd2009-01-11 23:31:46 +000035 * file contains code to handle them.
Nicholas Marriotta41ece52007-07-09 19:04:12 +000036 *
Nicholas Marriott162bacd2009-01-11 23:31:46 +000037 * A pane has two buffers attached, these are filled and emptied by the main
Nicholas Marriottb9de9062007-08-27 10:08:44 +000038 * server poll loop. Output data is received from pty's in screen format,
Nicholas Marriott35591ec2007-11-07 19:41:17 +000039 * translated and returned as a series of escape sequences and strings via
40 * input_parse (in input.c). Input data is received as key codes and written
Nicholas Marriottccfeb312008-01-02 19:22:21 +000041 * directly via input_key.
Nicholas Marriotta41ece52007-07-09 19:04:12 +000042 *
Nicholas Marriott162bacd2009-01-11 23:31:46 +000043 * Each pane also has a "virtual" screen (screen.c) which contains the current
44 * state and is redisplayed when the window is reattached to a client.
Nicholas Marriotta41ece52007-07-09 19:04:12 +000045 *
Nicholas Marriott4ba3cf62007-10-26 12:29:07 +000046 * Windows are stored directly on a global array and wrapped in any number of
Nicholas Marriott35591ec2007-11-07 19:41:17 +000047 * winlink structs to be linked onto local session RB trees. A reference count
Nicholas Marriott4ba3cf62007-10-26 12:29:07 +000048 * is maintained and a window removed from the global list and destroyed when
Nicholas Marriott35591ec2007-11-07 19:41:17 +000049 * it reaches zero.
Nicholas Marriotta41ece52007-07-09 19:04:12 +000050 */
51
52/* Global window list. */
Nicholas Marriott4ba3cf62007-10-26 12:29:07 +000053struct windows windows;
Tiago Cunha2df08822009-11-08 23:02:56 +000054
Nicholas Marriott536fc242011-04-06 22:16:33 +000055/* Global panes tree. */
56struct window_pane_tree all_window_panes;
Tiago Cunha2ee0d852012-01-31 12:01:43 +000057u_int next_window_pane_id;
58u_int next_window_id;
nicm540f0b32014-05-08 06:03:30 +000059u_int next_active_point;
nicmc930fd52014-01-28 22:19:17 +000060
Tiago Cunhaf9f6eea2012-03-29 21:05:16 +000061void window_pane_timer_callback(int, short, void *);
Tiago Cunha2df08822009-11-08 23:02:56 +000062void window_pane_read_callback(struct bufferevent *, void *);
63void window_pane_error_callback(struct bufferevent *, short, void *);
nicm540f0b32014-05-08 06:03:30 +000064
nicm05e7fbd2015-04-25 18:56:05 +000065struct window_pane *window_pane_choose_best(struct window_pane **, u_int);
Nicholas Marriott22d1b942009-07-01 19:42:55 +000066
nicm8d66f4f2015-04-22 15:30:11 +000067RB_GENERATE(windows, window, entry, window_cmp);
68
69int
70window_cmp(struct window *w1, struct window *w2)
71{
72 return (w1->id - w2->id);
73}
74
Nicholas Marriott4ba3cf62007-10-26 12:29:07 +000075RB_GENERATE(winlinks, winlink, entry, winlink_cmp);
76
77int
78winlink_cmp(struct winlink *wl1, struct winlink *wl2)
79{
80 return (wl1->idx - wl2->idx);
Nicholas Marriott536fc242011-04-06 22:16:33 +000081}
82
83RB_GENERATE(window_pane_tree, window_pane, tree_entry, window_pane_cmp);
84
85int
86window_pane_cmp(struct window_pane *wp1, struct window_pane *wp2)
87{
88 return (wp1->id - wp2->id);
Nicholas Marriott4ba3cf62007-10-26 12:29:07 +000089}
90
91struct winlink *
Nicholas Marriott8bfbc8c2009-07-15 17:45:09 +000092winlink_find_by_window(struct winlinks *wwl, struct window *w)
93{
94 struct winlink *wl;
95
96 RB_FOREACH(wl, winlinks, wwl) {
97 if (wl->window == w)
98 return (wl);
99 }
100
101 return (NULL);
102}
103
104struct winlink *
Nicholas Marriott4ba3cf62007-10-26 12:29:07 +0000105winlink_find_by_index(struct winlinks *wwl, int idx)
106{
107 struct winlink wl;
108
109 if (idx < 0)
110 fatalx("bad index");
111
112 wl.idx = idx;
113 return (RB_FIND(winlinks, wwl, &wl));
Tiago Cunha2ee0d852012-01-31 12:01:43 +0000114}
115
116struct winlink *
117winlink_find_by_window_id(struct winlinks *wwl, u_int id)
118{
119 struct winlink *wl;
120
121 RB_FOREACH(wl, winlinks, wwl) {
122 if (wl->window->id == id)
123 return (wl);
124 }
Tiago Cunhae5b38582012-04-10 09:54:29 +0000125 return (NULL);
Nicholas Marriott4ba3cf62007-10-26 12:29:07 +0000126}
127
128int
Tiago Cunhae61ee942009-08-16 19:16:27 +0000129winlink_next_index(struct winlinks *wwl, int idx)
Nicholas Marriott4ba3cf62007-10-26 12:29:07 +0000130{
Tiago Cunhae61ee942009-08-16 19:16:27 +0000131 int i;
Nicholas Marriott4ba3cf62007-10-26 12:29:07 +0000132
Tiago Cunhae61ee942009-08-16 19:16:27 +0000133 i = idx;
134 do {
Nicholas Marriott4ba3cf62007-10-26 12:29:07 +0000135 if (winlink_find_by_index(wwl, i) == NULL)
136 return (i);
Tiago Cunhae61ee942009-08-16 19:16:27 +0000137 if (i == INT_MAX)
138 i = 0;
139 else
140 i++;
141 } while (i != idx);
142 return (-1);
Nicholas Marriott4ba3cf62007-10-26 12:29:07 +0000143}
144
Nicholas Marriottfd05d072009-01-10 14:43:43 +0000145u_int
146winlink_count(struct winlinks *wwl)
147{
148 struct winlink *wl;
149 u_int n;
150
151 n = 0;
152 RB_FOREACH(wl, winlinks, wwl)
153 n++;
154
155 return (n);
156}
157
Nicholas Marriott4ba3cf62007-10-26 12:29:07 +0000158struct winlink *
Tiago Cunha4e4568c2011-02-15 15:09:52 +0000159winlink_add(struct winlinks *wwl, int idx)
Nicholas Marriott4ba3cf62007-10-26 12:29:07 +0000160{
161 struct winlink *wl;
162
Tiago Cunhae61ee942009-08-16 19:16:27 +0000163 if (idx < 0) {
164 if ((idx = winlink_next_index(wwl, -idx - 1)) == -1)
165 return (NULL);
166 } else if (winlink_find_by_index(wwl, idx) != NULL)
Nicholas Marriott4ba3cf62007-10-26 12:29:07 +0000167 return (NULL);
Nicholas Marriott4ba3cf62007-10-26 12:29:07 +0000168
169 wl = xcalloc(1, sizeof *wl);
170 wl->idx = idx;
Nicholas Marriott4ba3cf62007-10-26 12:29:07 +0000171 RB_INSERT(winlinks, wwl, wl);
172
Nicholas Marriott4ba3cf62007-10-26 12:29:07 +0000173 return (wl);
Tiago Cunha4e4568c2011-02-15 15:09:52 +0000174}
175
176void
177winlink_set_window(struct winlink *wl, struct window *w)
178{
179 wl->window = w;
180 w->references++;
Nicholas Marriott4ba3cf62007-10-26 12:29:07 +0000181}
182
183void
184winlink_remove(struct winlinks *wwl, struct winlink *wl)
185{
186 struct window *w = wl->window;
187
188 RB_REMOVE(winlinks, wwl, wl);
Tiago Cunhaa432fcd2012-07-11 19:34:16 +0000189 free(wl->status_text);
190 free(wl);
Nicholas Marriott4ba3cf62007-10-26 12:29:07 +0000191
Tiago Cunha56e37482012-08-31 09:22:08 +0000192 if (w != NULL)
193 window_remove_ref(w);
Nicholas Marriott4ba3cf62007-10-26 12:29:07 +0000194}
195
196struct winlink *
Tiago Cunhac12e0b02009-11-28 14:50:37 +0000197winlink_next(struct winlink *wl)
Nicholas Marriott4ba3cf62007-10-26 12:29:07 +0000198{
199 return (RB_NEXT(winlinks, wwl, wl));
Nicholas Marriott103748d2007-12-06 09:46:23 +0000200}
Nicholas Marriott4ba3cf62007-10-26 12:29:07 +0000201
202struct winlink *
Tiago Cunhac12e0b02009-11-28 14:50:37 +0000203winlink_previous(struct winlink *wl)
Nicholas Marriott4ba3cf62007-10-26 12:29:07 +0000204{
Nicholas Marriott85d520c2008-06-03 18:38:51 +0000205 return (RB_PREV(winlinks, wwl, wl));
Nicholas Marriott103748d2007-12-06 09:46:23 +0000206}
Nicholas Marriott4ba3cf62007-10-26 12:29:07 +0000207
Tiago Cunha8d3b7262010-06-22 23:29:05 +0000208struct winlink *
Tiago Cunha11f81e82010-07-17 14:38:13 +0000209winlink_next_by_number(struct winlink *wl, struct session *s, int n)
Tiago Cunha8d3b7262010-06-22 23:29:05 +0000210{
211 for (; n > 0; n--) {
212 if ((wl = RB_NEXT(winlinks, wwl, wl)) == NULL)
Tiago Cunha11f81e82010-07-17 14:38:13 +0000213 wl = RB_MIN(winlinks, &s->windows);
Tiago Cunha8d3b7262010-06-22 23:29:05 +0000214 }
215
216 return (wl);
217}
218
219struct winlink *
Tiago Cunha11f81e82010-07-17 14:38:13 +0000220winlink_previous_by_number(struct winlink *wl, struct session *s, int n)
Tiago Cunha8d3b7262010-06-22 23:29:05 +0000221{
222 for (; n > 0; n--) {
223 if ((wl = RB_PREV(winlinks, wwl, wl)) == NULL)
Tiago Cunha11f81e82010-07-17 14:38:13 +0000224 wl = RB_MAX(winlinks, &s->windows);
Tiago Cunha8d3b7262010-06-22 23:29:05 +0000225 }
226
227 return (wl);
228}
229
Nicholas Marriott46f5e422008-11-16 10:10:26 +0000230void
231winlink_stack_push(struct winlink_stack *stack, struct winlink *wl)
232{
233 if (wl == NULL)
234 return;
235
236 winlink_stack_remove(stack, wl);
Tiago Cunha6a1ebb12009-10-11 23:38:16 +0000237 TAILQ_INSERT_HEAD(stack, wl, sentry);
Nicholas Marriott46f5e422008-11-16 10:10:26 +0000238}
239
240void
241winlink_stack_remove(struct winlink_stack *stack, struct winlink *wl)
242{
243 struct winlink *wl2;
244
245 if (wl == NULL)
246 return;
Tiago Cunhacc094fd2009-12-04 22:14:47 +0000247
Tiago Cunha6a1ebb12009-10-11 23:38:16 +0000248 TAILQ_FOREACH(wl2, stack, sentry) {
Nicholas Marriott46f5e422008-11-16 10:10:26 +0000249 if (wl2 == wl) {
Tiago Cunha6a1ebb12009-10-11 23:38:16 +0000250 TAILQ_REMOVE(stack, wl, sentry);
Nicholas Marriott46f5e422008-11-16 10:10:26 +0000251 return;
252 }
253 }
Nicholas Marriott35876ea2009-06-01 22:58:49 +0000254}
255
Nicholas Marriott35876ea2009-06-01 22:58:49 +0000256struct window *
nicm05e7fbd2015-04-25 18:56:05 +0000257window_find_by_id_str(const char *s)
nicm6dbd63b2015-04-25 18:09:28 +0000258{
259 const char *errstr;
260 u_int id;
261
262 if (*s != '@')
263 return (NULL);
264
265 id = strtonum(s + 1, 0, UINT_MAX, &errstr);
266 if (errstr != NULL)
267 return (NULL);
268 return (window_find_by_id(id));
Nicholas Marriott46f5e422008-11-16 10:10:26 +0000269}
270
Nicholas Marriotta41ece52007-07-09 19:04:12 +0000271struct window *
Tiago Cunha2ee0d852012-01-31 12:01:43 +0000272window_find_by_id(u_int id)
273{
nicm8d66f4f2015-04-22 15:30:11 +0000274 struct window w;
Tiago Cunha2ee0d852012-01-31 12:01:43 +0000275
nicm8d66f4f2015-04-22 15:30:11 +0000276 w.id = id;
277 return (RB_FIND(windows, &windows, &w));
Tiago Cunha2ee0d852012-01-31 12:01:43 +0000278}
279
nicmb5aaefc2015-08-29 08:30:54 +0000280void
281window_update_activity(struct window *w)
282{
283 gettimeofday(&w->activity_time, NULL);
284 alerts_queue(w, WINDOW_ACTIVITY);
285}
286
Tiago Cunha2ee0d852012-01-31 12:01:43 +0000287struct window *
Nicholas Marriott56f80a52009-03-07 09:29:54 +0000288window_create1(u_int sx, u_int sy)
Nicholas Marriotta41ece52007-07-09 19:04:12 +0000289{
290 struct window *w;
Nicholas Marriotta41ece52007-07-09 19:04:12 +0000291
Tiago Cunhaab38d912009-11-08 23:22:24 +0000292 w = xcalloc(1, sizeof *w);
Nicholas Marriott4d9af272009-01-23 16:59:14 +0000293 w->name = NULL;
Nicholas Marriott0f956712008-06-04 17:54:27 +0000294 w->flags = 0;
Nicholas Marriottb4ac8c12009-01-14 19:29:32 +0000295
296 TAILQ_INIT(&w->panes);
297 w->active = NULL;
Nicholas Marriottd90d6462008-06-29 07:04:31 +0000298
Tiago Cunhad9dcc5e2009-07-28 23:04:29 +0000299 w->lastlayout = -1;
Tiago Cunha545893d2009-07-20 15:42:05 +0000300 w->layout_root = NULL;
Tiago Cunhacc094fd2009-12-04 22:14:47 +0000301
Nicholas Marriott162bacd2009-01-11 23:31:46 +0000302 w->sx = sx;
303 w->sy = sy;
Tiago Cunhaab38d912009-11-08 23:22:24 +0000304
nicm44657bf2015-10-27 15:58:42 +0000305 w->options = options_create(global_w_options);
Nicholas Marriotta41ece52007-07-09 19:04:12 +0000306
Nicholas Marriott4ba3cf62007-10-26 12:29:07 +0000307 w->references = 0;
nicm8d66f4f2015-04-22 15:30:11 +0000308
309 w->id = next_window_id++;
nicm8e9b6e02015-05-07 11:42:56 +0000310 RB_INSERT(windows, &windows, w);
nicmb5aaefc2015-08-29 08:30:54 +0000311
312 window_update_activity(w);
Nicholas Marriotta41ece52007-07-09 19:04:12 +0000313
Nicholas Marriott56f80a52009-03-07 09:29:54 +0000314 return (w);
315}
316
317struct window *
nicmb3e8d442014-05-13 08:08:32 +0000318window_create(const char *name, int argc, char **argv, const char *path,
nicm01defc92015-10-31 08:13:58 +0000319 const char *shell, const char *cwd, struct environ *env,
320 struct termios *tio, u_int sx, u_int sy, u_int hlimit, char **cause)
Nicholas Marriott56f80a52009-03-07 09:29:54 +0000321{
Tiago Cunha545893d2009-07-20 15:42:05 +0000322 struct window *w;
323 struct window_pane *wp;
Nicholas Marriott56f80a52009-03-07 09:29:54 +0000324
325 w = window_create1(sx, sy);
Tiago Cunha6708ad12009-07-23 13:10:38 +0000326 wp = window_add_pane(w, hlimit);
Nicholas Marriottc5239c52013-02-24 00:25:03 +0000327 layout_init(w, wp);
Nicholas Marriott31407b72013-02-22 14:31:38 +0000328
nicmb3e8d442014-05-13 08:08:32 +0000329 if (window_pane_spawn(wp, argc, argv, path, shell, cwd, env, tio,
nicm3e27be32014-04-17 13:02:59 +0000330 cause) != 0) {
Nicholas Marriottd90d6462008-06-29 07:04:31 +0000331 window_destroy(w);
332 return (NULL);
333 }
Nicholas Marriott31407b72013-02-22 14:31:38 +0000334
Nicholas Marriottb4ac8c12009-01-14 19:29:32 +0000335 w->active = TAILQ_FIRST(&w->panes);
Nicholas Marriott2d15f592009-01-20 19:35:03 +0000336 if (name != NULL) {
337 w->name = xstrdup(name);
nicm44657bf2015-10-27 15:58:42 +0000338 options_set_number(w->options, "automatic-rename", 0);
Nicholas Marriott2d15f592009-01-20 19:35:03 +0000339 } else
340 w->name = default_window_name(w);
Nicholas Marriott31407b72013-02-22 14:31:38 +0000341
Nicholas Marriotta41ece52007-07-09 19:04:12 +0000342 return (w);
343}
344
Nicholas Marriotta41ece52007-07-09 19:04:12 +0000345void
346window_destroy(struct window *w)
347{
nicm8d66f4f2015-04-22 15:30:11 +0000348 RB_REMOVE(windows, &windows, w);
Tiago Cunha545893d2009-07-20 15:42:05 +0000349
350 if (w->layout_root != NULL)
nicmbad8d0f2015-07-17 13:09:07 +0000351 layout_free_cell(w->layout_root);
352 if (w->saved_layout_root != NULL)
353 layout_free_cell(w->saved_layout_root);
nicm77174442015-04-28 10:43:13 +0000354 free(w->old_layout);
Tiago Cunhaab38d912009-11-08 23:22:24 +0000355
nicmb7861f32015-08-29 00:29:15 +0000356 if (event_initialized(&w->name_event))
357 evtimer_del(&w->name_event);
nicmb5aaefc2015-08-29 08:30:54 +0000358
359 if (event_initialized(&w->alerts_timer))
360 evtimer_del(&w->alerts_timer);
Nicholas Marriott103748d2007-12-06 09:46:23 +0000361
nicm44657bf2015-10-27 15:58:42 +0000362 options_free(w->options);
Nicholas Marriott9d563c32007-10-01 14:15:48 +0000363
Nicholas Marriottb4ac8c12009-01-14 19:29:32 +0000364 window_destroy_panes(w);
Nicholas Marriott4d9af272009-01-23 16:59:14 +0000365
Tiago Cunhaa432fcd2012-07-11 19:34:16 +0000366 free(w->name);
367 free(w);
Nicholas Marriotta41ece52007-07-09 19:04:12 +0000368}
369
Tiago Cunhad29b57f2009-07-22 17:46:53 +0000370void
Tiago Cunha56e37482012-08-31 09:22:08 +0000371window_remove_ref(struct window *w)
372{
373 if (w->references == 0)
374 fatal("bad reference count");
375 w->references--;
376 if (w->references == 0)
377 window_destroy(w);
378}
379
380void
Tiago Cunhac82e0682012-02-02 02:00:12 +0000381window_set_name(struct window *w, const char *new_name)
382{
Tiago Cunhaa432fcd2012-07-11 19:34:16 +0000383 free(w->name);
Tiago Cunhac82e0682012-02-02 02:00:12 +0000384 w->name = xstrdup(new_name);
Tiago Cunhaf41efd92012-03-18 02:22:09 +0000385 notify_window_renamed(w);
Tiago Cunhac82e0682012-02-02 02:00:12 +0000386}
387
388void
Nicholas Marriotta41ece52007-07-09 19:04:12 +0000389window_resize(struct window *w, u_int sx, u_int sy)
390{
Nicholas Marriottb4ac8c12009-01-14 19:29:32 +0000391 w->sx = sx;
392 w->sy = sy;
Nicholas Marriottb4ac8c12009-01-14 19:29:32 +0000393}
394
nicma02c2e52014-10-21 22:22:04 +0000395int
nicmbf635e72015-04-19 21:34:21 +0000396window_has_pane(struct window *w, struct window_pane *wp)
397{
398 struct window_pane *wp1;
399
400 TAILQ_FOREACH(wp1, &w->panes, entry) {
401 if (wp1 == wp)
402 return (1);
403 }
404 return (0);
405}
406
407int
Nicholas Marriottb4ac8c12009-01-14 19:29:32 +0000408window_set_active_pane(struct window *w, struct window_pane *wp)
409{
Nicholas Marriott36e537b2010-12-06 21:53:50 +0000410 if (wp == w->active)
nicma02c2e52014-10-21 22:22:04 +0000411 return (0);
Tiago Cunhacd079e82010-10-24 01:34:30 +0000412 w->last = w->active;
Nicholas Marriottb4ac8c12009-01-14 19:29:32 +0000413 w->active = wp;
Nicholas Marriott1e574bb2009-07-15 17:42:44 +0000414 while (!window_pane_visible(w->active)) {
Nicholas Marriottb4ac8c12009-01-14 19:29:32 +0000415 w->active = TAILQ_PREV(w->active, window_panes, entry);
Nicholas Marriott1e574bb2009-07-15 17:42:44 +0000416 if (w->active == NULL)
417 w->active = TAILQ_LAST(&w->panes, window_panes);
418 if (w->active == wp)
nicma02c2e52014-10-21 22:22:04 +0000419 return (1);
Nicholas Marriott1e574bb2009-07-15 17:42:44 +0000420 }
nicm540f0b32014-05-08 06:03:30 +0000421 w->active->active_point = next_active_point++;
nicmfc58e442015-08-28 07:49:24 +0000422 w->active->flags |= PANE_CHANGED;
nicma02c2e52014-10-21 22:22:04 +0000423 return (1);
Nicholas Marriottb4ac8c12009-01-14 19:29:32 +0000424}
425
nicmaf16ce62015-09-14 11:34:50 +0000426void
427window_redraw_active_switch(struct window *w, struct window_pane *wp)
428{
429 const struct grid_cell *agc, *wgc;
430
431 if (wp == w->active)
432 return;
433
434 /*
435 * If window-style and window-active-style are the same, we don't need
436 * to redraw panes when switching active panes. Otherwise, if the
437 * active or inactive pane do not have a custom style, they will need
438 * to be redrawn.
439 */
nicm44657bf2015-10-27 15:58:42 +0000440 agc = options_get_style(w->options, "window-active-style");
441 wgc = options_get_style(w->options, "window-style");
nicmaf16ce62015-09-14 11:34:50 +0000442 if (style_equal(agc, wgc))
443 return;
444 if (style_equal(&grid_default_cell, &w->active->colgc))
445 w->active->flags |= PANE_REDRAW;
446 if (style_equal(&grid_default_cell, &wp->colgc))
447 wp->flags |= PANE_REDRAW;
448}
449
Nicholas Marriottfa0f10d2011-06-23 19:21:26 +0000450struct window_pane *
451window_get_active_at(struct window *w, u_int x, u_int y)
452{
453 struct window_pane *wp;
454
455 TAILQ_FOREACH(wp, &w->panes, entry) {
456 if (!window_pane_visible(wp))
457 continue;
458 if (x < wp->xoff || x > wp->xoff + wp->sx)
459 continue;
460 if (y < wp->yoff || y > wp->yoff + wp->sy)
461 continue;
462 return (wp);
463 }
464 return (NULL);
Nicholas Marriottfa0f10d2011-06-23 19:21:26 +0000465}
466
467struct window_pane *
468window_find_string(struct window *w, const char *s)
469{
470 u_int x, y;
471
472 x = w->sx / 2;
473 y = w->sy / 2;
474
475 if (strcasecmp(s, "top") == 0)
476 y = 0;
477 else if (strcasecmp(s, "bottom") == 0)
478 y = w->sy - 1;
479 else if (strcasecmp(s, "left") == 0)
480 x = 0;
481 else if (strcasecmp(s, "right") == 0)
482 x = w->sx - 1;
483 else if (strcasecmp(s, "top-left") == 0) {
484 x = 0;
485 y = 0;
486 } else if (strcasecmp(s, "top-right") == 0) {
487 x = w->sx - 1;
488 y = 0;
489 } else if (strcasecmp(s, "bottom-left") == 0) {
490 x = 0;
491 y = w->sy - 1;
492 } else if (strcasecmp(s, "bottom-right") == 0) {
493 x = w->sx - 1;
494 y = w->sy - 1;
495 } else
496 return (NULL);
497
498 return (window_get_active_at(w, x, y));
Nicholas Marriottc5239c52013-02-24 00:25:03 +0000499}
500
501int
502window_zoom(struct window_pane *wp)
503{
504 struct window *w = wp->window;
505 struct window_pane *wp1;
506
507 if (w->flags & WINDOW_ZOOMED)
508 return (-1);
509
510 if (!window_pane_visible(wp))
511 return (-1);
Nicholas Marriott8aa40ec2013-03-12 12:18:52 +0000512
513 if (window_count_panes(w) == 1)
514 return (-1);
515
Nicholas Marriottc5239c52013-02-24 00:25:03 +0000516 if (w->active != wp)
517 window_set_active_pane(w, wp);
518
519 TAILQ_FOREACH(wp1, &w->panes, entry) {
520 wp1->saved_layout_cell = wp1->layout_cell;
521 wp1->layout_cell = NULL;
522 }
523
524 w->saved_layout_root = w->layout_root;
525 layout_init(w, wp);
526 w->flags |= WINDOW_ZOOMED;
nicm160e3e22014-12-15 10:04:18 +0000527 notify_window_layout_changed(w);
Nicholas Marriottc5239c52013-02-24 00:25:03 +0000528
529 return (0);
530}
531
532int
533window_unzoom(struct window *w)
534{
Nicholas Marriott771d7db2013-03-26 10:54:48 +0000535 struct window_pane *wp;
Nicholas Marriottc5239c52013-02-24 00:25:03 +0000536
537 if (!(w->flags & WINDOW_ZOOMED))
538 return (-1);
Nicholas Marriottc5239c52013-02-24 00:25:03 +0000539
540 w->flags &= ~WINDOW_ZOOMED;
541 layout_free(w);
542 w->layout_root = w->saved_layout_root;
nicm69f292a2015-04-21 22:38:49 +0000543 w->saved_layout_root = NULL;
Nicholas Marriottc5239c52013-02-24 00:25:03 +0000544
Nicholas Marriott771d7db2013-03-26 10:54:48 +0000545 TAILQ_FOREACH(wp, &w->panes, entry) {
546 wp->layout_cell = wp->saved_layout_cell;
547 wp->saved_layout_cell = NULL;
Nicholas Marriottc5239c52013-02-24 00:25:03 +0000548 }
549 layout_fix_panes(w, w->sx, w->sy);
nicm160e3e22014-12-15 10:04:18 +0000550 notify_window_layout_changed(w);
Nicholas Marriottc5239c52013-02-24 00:25:03 +0000551
552 return (0);
Tiago Cunhaea1721b2009-10-11 23:46:02 +0000553}
554
Nicholas Marriottb4ac8c12009-01-14 19:29:32 +0000555struct window_pane *
Tiago Cunha6708ad12009-07-23 13:10:38 +0000556window_add_pane(struct window *w, u_int hlimit)
Nicholas Marriott7cd3cf02009-01-12 18:22:47 +0000557{
558 struct window_pane *wp;
Nicholas Marriott7cd3cf02009-01-12 18:22:47 +0000559
Tiago Cunha545893d2009-07-20 15:42:05 +0000560 wp = window_pane_create(w, w->sx, w->sy, hlimit);
Nicholas Marriottb4ac8c12009-01-14 19:29:32 +0000561 if (TAILQ_EMPTY(&w->panes))
562 TAILQ_INSERT_HEAD(&w->panes, wp, entry);
563 else
564 TAILQ_INSERT_AFTER(&w->panes, w->active, wp, entry);
Nicholas Marriottb4ac8c12009-01-14 19:29:32 +0000565 return (wp);
Nicholas Marriott162bacd2009-01-11 23:31:46 +0000566}
567
Nicholas Marriottb4ac8c12009-01-14 19:29:32 +0000568void
nicm2e98c902014-04-17 09:13:13 +0000569window_lost_pane(struct window *w, struct window_pane *wp)
Nicholas Marriott162bacd2009-01-11 23:31:46 +0000570{
nicm12da13c2015-12-15 00:00:01 +0000571 if (wp == marked_pane.wp)
nicma8638342015-06-04 11:43:51 +0000572 server_clear_marked();
573
Tiago Cunha8703e9f2010-10-24 01:32:35 +0000574 if (wp == w->active) {
Tiago Cunhacd079e82010-10-24 01:34:30 +0000575 w->active = w->last;
576 w->last = NULL;
577 if (w->active == NULL) {
578 w->active = TAILQ_PREV(wp, window_panes, entry);
579 if (w->active == NULL)
580 w->active = TAILQ_NEXT(wp, entry);
581 }
nicm72368382015-12-02 23:09:22 +0000582 if (w->active != NULL)
583 w->active->flags |= PANE_CHANGED;
Tiago Cunhacd079e82010-10-24 01:34:30 +0000584 } else if (wp == w->last)
585 w->last = NULL;
nicm2e98c902014-04-17 09:13:13 +0000586}
587
588void
589window_remove_pane(struct window *w, struct window_pane *wp)
590{
591 window_lost_pane(w, wp);
Nicholas Marriottf8555912009-01-13 06:50:10 +0000592
Nicholas Marriottb4ac8c12009-01-14 19:29:32 +0000593 TAILQ_REMOVE(&w->panes, wp, entry);
594 window_pane_destroy(wp);
Nicholas Marriottb4ac8c12009-01-14 19:29:32 +0000595}
596
597struct window_pane *
598window_pane_at_index(struct window *w, u_int idx)
599{
600 struct window_pane *wp;
601 u_int n;
602
nicm44657bf2015-10-27 15:58:42 +0000603 n = options_get_number(w->options, "pane-base-index");
Nicholas Marriottb4ac8c12009-01-14 19:29:32 +0000604 TAILQ_FOREACH(wp, &w->panes, entry) {
605 if (n == idx)
606 return (wp);
607 n++;
608 }
609 return (NULL);
610}
611
Tiago Cunha11f81e82010-07-17 14:38:13 +0000612struct window_pane *
613window_pane_next_by_number(struct window *w, struct window_pane *wp, u_int n)
614{
615 for (; n > 0; n--) {
616 if ((wp = TAILQ_NEXT(wp, entry)) == NULL)
617 wp = TAILQ_FIRST(&w->panes);
618 }
619
620 return (wp);
621}
622
623struct window_pane *
624window_pane_previous_by_number(struct window *w, struct window_pane *wp,
625 u_int n)
626{
627 for (; n > 0; n--) {
628 if ((wp = TAILQ_PREV(wp, window_panes, entry)) == NULL)
629 wp = TAILQ_LAST(&w->panes, window_panes);
630 }
631
632 return (wp);
633}
634
Tiago Cunha9ec45752011-11-25 13:30:45 +0000635int
636window_pane_index(struct window_pane *wp, u_int *i)
Tiago Cunhaae7dda12009-07-17 18:32:54 +0000637{
638 struct window_pane *wq;
Tiago Cunha9ec45752011-11-25 13:30:45 +0000639 struct window *w = wp->window;
Tiago Cunhaae7dda12009-07-17 18:32:54 +0000640
nicm44657bf2015-10-27 15:58:42 +0000641 *i = options_get_number(w->options, "pane-base-index");
Tiago Cunhaae7dda12009-07-17 18:32:54 +0000642 TAILQ_FOREACH(wq, &w->panes, entry) {
Tiago Cunha9ec45752011-11-25 13:30:45 +0000643 if (wp == wq) {
644 return (0);
645 }
646 (*i)++;
Tiago Cunhaae7dda12009-07-17 18:32:54 +0000647 }
Tiago Cunha9ec45752011-11-25 13:30:45 +0000648
649 return (-1);
Tiago Cunhaae7dda12009-07-17 18:32:54 +0000650}
651
652u_int
Nicholas Marriottb4ac8c12009-01-14 19:29:32 +0000653window_count_panes(struct window *w)
654{
655 struct window_pane *wp;
656 u_int n;
657
658 n = 0;
659 TAILQ_FOREACH(wp, &w->panes, entry)
660 n++;
661 return (n);
662}
663
664void
665window_destroy_panes(struct window *w)
666{
667 struct window_pane *wp;
668
669 while (!TAILQ_EMPTY(&w->panes)) {
670 wp = TAILQ_FIRST(&w->panes);
671 TAILQ_REMOVE(&w->panes, wp, entry);
672 window_pane_destroy(wp);
673 }
Nicholas Marriott162bacd2009-01-11 23:31:46 +0000674}
675
nicm31b1ab42015-05-06 08:35:39 +0000676/* Retuns the printable flags on a window, empty string if no flags set. */
Tiago Cunha30f6d9b2011-01-07 16:55:40 +0000677char *
678window_printable_flags(struct session *s, struct winlink *wl)
679{
nicm6f587572015-04-20 07:50:49 +0000680 char flags[32];
Tiago Cunha30f6d9b2011-01-07 16:55:40 +0000681 int pos;
682
683 pos = 0;
684 if (wl->flags & WINLINK_ACTIVITY)
685 flags[pos++] = '#';
686 if (wl->flags & WINLINK_BELL)
687 flags[pos++] = '!';
Tiago Cunha30f6d9b2011-01-07 16:55:40 +0000688 if (wl->flags & WINLINK_SILENCE)
689 flags[pos++] = '~';
690 if (wl == s->curw)
691 flags[pos++] = '*';
692 if (wl == TAILQ_FIRST(&s->lastw))
693 flags[pos++] = '-';
nicm12da13c2015-12-15 00:00:01 +0000694 if (server_check_marked() && wl == marked_pane.wl)
nicma8638342015-06-04 11:43:51 +0000695 flags[pos++] = 'M';
Nicholas Marriottc5239c52013-02-24 00:25:03 +0000696 if (wl->window->flags & WINDOW_ZOOMED)
697 flags[pos++] = 'Z';
Tiago Cunha30f6d9b2011-01-07 16:55:40 +0000698 flags[pos] = '\0';
699 return (xstrdup(flags));
700}
701
nicm6dbd63b2015-04-25 18:09:28 +0000702struct window_pane *
703window_pane_find_by_id_str(const char *s)
704{
705 const char *errstr;
706 u_int id;
707
708 if (*s != '%')
709 return (NULL);
710
711 id = strtonum(s + 1, 0, UINT_MAX, &errstr);
712 if (errstr != NULL)
713 return (NULL);
714 return (window_pane_find_by_id(id));
715}
716
Nicholas Marriott536fc242011-04-06 22:16:33 +0000717struct window_pane *
718window_pane_find_by_id(u_int id)
719{
720 struct window_pane wp;
721
722 wp.id = id;
723 return (RB_FIND(window_pane_tree, &all_window_panes, &wp));
724}
725
Nicholas Marriott162bacd2009-01-11 23:31:46 +0000726struct window_pane *
727window_pane_create(struct window *w, u_int sx, u_int sy, u_int hlimit)
728{
729 struct window_pane *wp;
nicmd9b31332015-08-28 17:11:12 +0000730 char host[HOST_NAME_MAX + 1];
Nicholas Marriott162bacd2009-01-11 23:31:46 +0000731
Nicholas Marriottb4ac8c12009-01-14 19:29:32 +0000732 wp = xcalloc(1, sizeof *wp);
Nicholas Marriott162bacd2009-01-11 23:31:46 +0000733 wp->window = w;
Nicholas Marriott536fc242011-04-06 22:16:33 +0000734
Tiago Cunha2ee0d852012-01-31 12:01:43 +0000735 wp->id = next_window_pane_id++;
Nicholas Marriott536fc242011-04-06 22:16:33 +0000736 RB_INSERT(window_pane_tree, &all_window_panes, wp);
Nicholas Marriott162bacd2009-01-11 23:31:46 +0000737
nicmb3e8d442014-05-13 08:08:32 +0000738 wp->argc = 0;
739 wp->argv = NULL;
Tiago Cunhaa3a150f2009-09-02 01:02:44 +0000740 wp->shell = NULL;
nicm01defc92015-10-31 08:13:58 +0000741 wp->cwd = NULL;
Nicholas Marriott162bacd2009-01-11 23:31:46 +0000742
743 wp->fd = -1;
Tiago Cunha2df08822009-11-08 23:02:56 +0000744 wp->event = NULL;
Nicholas Marriott162bacd2009-01-11 23:31:46 +0000745
746 wp->mode = NULL;
747
Tiago Cunha545893d2009-07-20 15:42:05 +0000748 wp->layout_cell = NULL;
749
Nicholas Marriottb6450b12009-04-01 18:21:42 +0000750 wp->xoff = 0;
Tiago Cunhacc094fd2009-12-04 22:14:47 +0000751 wp->yoff = 0;
Nicholas Marriottb6450b12009-04-01 18:21:42 +0000752
Nicholas Marriott7cd3cf02009-01-12 18:22:47 +0000753 wp->sx = sx;
754 wp->sy = sy;
Nicholas Marriott7cd3cf02009-01-12 18:22:47 +0000755
Tiago Cunha6091b052009-10-12 00:35:08 +0000756 wp->pipe_fd = -1;
Tiago Cunha6091b052009-10-12 00:35:08 +0000757 wp->pipe_off = 0;
Tiago Cunhacb0bf6a2009-11-08 22:59:53 +0000758 wp->pipe_event = NULL;
Tiago Cunha6091b052009-10-12 00:35:08 +0000759
Nicholas Marriotte63567d2009-07-14 06:40:33 +0000760 wp->saved_grid = NULL;
Nicholas Marriott35928592009-07-13 10:43:52 +0000761
nicmee123c22015-04-19 21:05:27 +0000762 memcpy(&wp->colgc, &grid_default_cell, sizeof wp->colgc);
Nicholas Marriotte63567d2009-07-14 06:40:33 +0000763
Nicholas Marriott162bacd2009-01-11 23:31:46 +0000764 screen_init(&wp->base, sx, sy, hlimit);
765 wp->screen = &wp->base;
Nicholas Marriott35876ea2009-06-01 22:58:49 +0000766
nicmd9b31332015-08-28 17:11:12 +0000767 if (gethostname(host, sizeof host) == 0)
768 screen_set_title(&wp->base, host);
Nicholas Marriott162bacd2009-01-11 23:31:46 +0000769
770 input_init(wp);
Nicholas Marriott7cd3cf02009-01-12 18:22:47 +0000771
Nicholas Marriott162bacd2009-01-11 23:31:46 +0000772 return (wp);
773}
774
775void
776window_pane_destroy(struct window_pane *wp)
777{
Tiago Cunha01052ca2010-08-29 14:46:13 +0000778 window_pane_reset_mode(wp);
779
nicm3f4ee982015-05-12 22:40:38 +0000780 if (event_initialized(&wp->timer))
781 evtimer_del(&wp->timer);
Tiago Cunhaf9f6eea2012-03-29 21:05:16 +0000782
Tiago Cunha2df08822009-11-08 23:02:56 +0000783 if (wp->fd != -1) {
Nicholas Marriott4273c1b2014-02-24 23:07:22 +0000784#ifdef HAVE_UTEMPTER
785 utempter_remove_record(wp->fd);
786#endif
Tiago Cunha2df08822009-11-08 23:02:56 +0000787 bufferevent_free(wp->event);
Tiago Cunhae23df3a2012-01-29 12:53:33 +0000788 close(wp->fd);
Tiago Cunha2df08822009-11-08 23:02:56 +0000789 }
Nicholas Marriott162bacd2009-01-11 23:31:46 +0000790
791 input_free(wp);
792
Nicholas Marriott162bacd2009-01-11 23:31:46 +0000793 screen_free(&wp->base);
Nicholas Marriotte63567d2009-07-14 06:40:33 +0000794 if (wp->saved_grid != NULL)
795 grid_destroy(wp->saved_grid);
Tiago Cunha6091b052009-10-12 00:35:08 +0000796
797 if (wp->pipe_fd != -1) {
Tiago Cunhacb0bf6a2009-11-08 22:59:53 +0000798 bufferevent_free(wp->pipe_event);
Tiago Cunhae23df3a2012-01-29 12:53:33 +0000799 close(wp->pipe_fd);
Tiago Cunha6091b052009-10-12 00:35:08 +0000800 }
Nicholas Marriott162bacd2009-01-11 23:31:46 +0000801
Nicholas Marriott536fc242011-04-06 22:16:33 +0000802 RB_REMOVE(window_pane_tree, &all_window_panes, wp);
803
nicm01defc92015-10-31 08:13:58 +0000804 free((void *)wp->cwd);
Tiago Cunhaa432fcd2012-07-11 19:34:16 +0000805 free(wp->shell);
nicmb3e8d442014-05-13 08:08:32 +0000806 cmd_free_argv(wp->argc, wp->argv);
Tiago Cunhaa432fcd2012-07-11 19:34:16 +0000807 free(wp);
Nicholas Marriott162bacd2009-01-11 23:31:46 +0000808}
809
810int
nicmb3e8d442014-05-13 08:08:32 +0000811window_pane_spawn(struct window_pane *wp, int argc, char **argv,
nicm01defc92015-10-31 08:13:58 +0000812 const char *path, const char *shell, const char *cwd, struct environ *env,
nicmb3e8d442014-05-13 08:08:32 +0000813 struct termios *tio, char **cause)
Nicholas Marriott162bacd2009-01-11 23:31:46 +0000814{
Nicholas Marriott0fc65532010-04-06 21:59:19 +0000815 struct winsize ws;
nicm62d3af12015-11-24 23:46:15 +0000816 char *argv0, *cmd, **argvp;
nicm01defc92015-10-31 08:13:58 +0000817 const char *ptr, *first, *home;
Nicholas Marriott0fc65532010-04-06 21:59:19 +0000818 struct termios tio2;
Nicholas Marriott4273c1b2014-02-24 23:07:22 +0000819#ifdef HAVE_UTEMPTER
820 char s[32];
821#endif
nicmb3e8d442014-05-13 08:08:32 +0000822 int i;
Nicholas Marriott162bacd2009-01-11 23:31:46 +0000823
Tiago Cunha2df08822009-11-08 23:02:56 +0000824 if (wp->fd != -1) {
Tiago Cunha2df08822009-11-08 23:02:56 +0000825 bufferevent_free(wp->event);
Tiago Cunhae23df3a2012-01-29 12:53:33 +0000826 close(wp->fd);
Tiago Cunha2df08822009-11-08 23:02:56 +0000827 }
nicmb3e8d442014-05-13 08:08:32 +0000828 if (argc > 0) {
829 cmd_free_argv(wp->argc, wp->argv);
830 wp->argc = argc;
831 wp->argv = cmd_copy_argv(argc, argv);
Tiago Cunhaa3a150f2009-09-02 01:02:44 +0000832 }
833 if (shell != NULL) {
Tiago Cunhaa432fcd2012-07-11 19:34:16 +0000834 free(wp->shell);
Tiago Cunhaa3a150f2009-09-02 01:02:44 +0000835 wp->shell = xstrdup(shell);
Nicholas Marriott162bacd2009-01-11 23:31:46 +0000836 }
nicm01defc92015-10-31 08:13:58 +0000837 if (cwd != NULL) {
838 free((void *)wp->cwd);
839 wp->cwd = xstrdup(cwd);
Nicholas Marriott162bacd2009-01-11 23:31:46 +0000840 }
841
nicmb3e8d442014-05-13 08:08:32 +0000842 cmd = cmd_stringify_argv(wp->argc, wp->argv);
843 log_debug("spawn: %s -- %s", wp->shell, cmd);
844 for (i = 0; i < wp->argc; i++)
845 log_debug("spawn: argv[%d] = %s", i, wp->argv[i]);
Nicholas Marriott31407b72013-02-22 14:31:38 +0000846
Nicholas Marriott162bacd2009-01-11 23:31:46 +0000847 memset(&ws, 0, sizeof ws);
848 ws.ws_col = screen_size_x(&wp->base);
849 ws.ws_row = screen_size_y(&wp->base);
Nicholas Marriott2d15f592009-01-20 19:35:03 +0000850
Tiago Cunhacc094fd2009-12-04 22:14:47 +0000851 switch (wp->pid = forkpty(&wp->fd, wp->tty, NULL, &ws)) {
Nicholas Marriott162bacd2009-01-11 23:31:46 +0000852 case -1:
Nicholas Marriott4d9af272009-01-23 16:59:14 +0000853 wp->fd = -1;
854 xasprintf(cause, "%s: %s", cmd, strerror(errno));
nicmb3e8d442014-05-13 08:08:32 +0000855 free(cmd);
Nicholas Marriott4d9af272009-01-23 16:59:14 +0000856 return (-1);
Nicholas Marriott162bacd2009-01-11 23:31:46 +0000857 case 0:
nicm01defc92015-10-31 08:13:58 +0000858 if (chdir(wp->cwd) != 0) {
859 if ((home = find_home()) == NULL || chdir(home) != 0)
860 chdir("/");
861 }
Tiago Cunha29b1b2f2009-08-09 17:48:55 +0000862
Nicholas Marriott15b643f2009-09-16 12:36:28 +0000863 if (tcgetattr(STDIN_FILENO, &tio2) != 0)
864 fatal("tcgetattr failed");
865 if (tio != NULL)
866 memcpy(tio2.c_cc, tio->c_cc, sizeof tio2.c_cc);
867 tio2.c_cc[VERASE] = '\177';
Nicholas Marriottdb7570d2012-01-20 20:18:20 +0000868#ifdef IUTF8
Nicholas Marriottb7397bf2015-11-13 16:05:58 +0000869 tio2.c_iflag |= IUTF8;
Nicholas Marriottdb7570d2012-01-20 20:18:20 +0000870#endif
Nicholas Marriott15b643f2009-09-16 12:36:28 +0000871 if (tcsetattr(STDIN_FILENO, TCSANOW, &tio2) != 0)
872 fatal("tcgetattr failed");
873
Tiago Cunhad4b58c72010-10-24 00:45:57 +0000874 closefrom(STDERR_FILENO + 1);
875
nicm3e27be32014-04-17 13:02:59 +0000876 if (path != NULL)
nicm62d3af12015-11-24 23:46:15 +0000877 environ_set(env, "PATH", "%s", path);
878 environ_set(env, "TMUX_PANE", "%%%u", wp->id);
Nicholas Marriott0fc65532010-04-06 21:59:19 +0000879 environ_push(env);
Tiago Cunha29b1b2f2009-08-09 17:48:55 +0000880
Tiago Cunha56040be2010-08-29 14:42:11 +0000881 clear_signals(1);
Nicholas Marriott162bacd2009-01-11 23:31:46 +0000882 log_close();
883
Tiago Cunha2e3a2602012-05-30 13:47:33 +0000884 setenv("SHELL", wp->shell, 1);
885 ptr = strrchr(wp->shell, '/');
Tiago Cunha5838ee12009-09-02 01:08:32 +0000886
nicmb3e8d442014-05-13 08:08:32 +0000887 /*
888 * If given one argument, assume it should be passed to sh -c;
889 * with more than one argument, use execvp(). If there is no
890 * arguments, create a login shell.
891 */
892 if (wp->argc > 0) {
893 if (wp->argc != 1) {
894 /* Copy to ensure argv ends in NULL. */
895 argvp = cmd_copy_argv(wp->argc, wp->argv);
896 execvp(argvp[0], argvp);
897 fatal("execvp failed");
898 }
899 first = wp->argv[0];
900
Tiago Cunha2e3a2602012-05-30 13:47:33 +0000901 if (ptr != NULL && *(ptr + 1) != '\0')
902 xasprintf(&argv0, "%s", ptr + 1);
903 else
904 xasprintf(&argv0, "%s", wp->shell);
nicmb3e8d442014-05-13 08:08:32 +0000905 execl(wp->shell, argv0, "-c", first, (char *)NULL);
Nicholas Marriott22d1b942009-07-01 19:42:55 +0000906 fatal("execl failed");
907 }
Tiago Cunhaa3a150f2009-09-02 01:02:44 +0000908 if (ptr != NULL && *(ptr + 1) != '\0')
Nicholas Marriott22d1b942009-07-01 19:42:55 +0000909 xasprintf(&argv0, "-%s", ptr + 1);
910 else
Tiago Cunhaa3a150f2009-09-02 01:02:44 +0000911 xasprintf(&argv0, "-%s", wp->shell);
nicmb3e8d442014-05-13 08:08:32 +0000912 execl(wp->shell, argv0, (char *)NULL);
Nicholas Marriott162bacd2009-01-11 23:31:46 +0000913 fatal("execl failed");
914 }
915
Nicholas Marriott4273c1b2014-02-24 23:07:22 +0000916#ifdef HAVE_UTEMPTER
Nicholas Marriottf3152072014-02-24 23:11:25 +0000917 xsnprintf(s, sizeof s, "tmux(%lu).%%%u", (long) getpid(), wp->id);
Nicholas Marriott4273c1b2014-02-24 23:07:22 +0000918 utempter_add_record(wp->fd, s);
Nicholas Marriott782dd942016-02-17 23:21:58 +0000919 kill(getpid(), SIGCHLD);
Nicholas Marriott4273c1b2014-02-24 23:07:22 +0000920#endif
921
Tiago Cunha492e3aa2011-01-21 23:44:13 +0000922 setblocking(wp->fd, 0);
923
nicmb3e8d442014-05-13 08:08:32 +0000924 wp->event = bufferevent_new(wp->fd, window_pane_read_callback, NULL,
925 window_pane_error_callback, wp);
nicm3f4ee982015-05-12 22:40:38 +0000926
927 bufferevent_setwatermark(wp->event, EV_READ, 0, READ_SIZE);
Tiago Cunha2df08822009-11-08 23:02:56 +0000928 bufferevent_enable(wp->event, EV_READ|EV_WRITE);
Nicholas Marriott162bacd2009-01-11 23:31:46 +0000929
nicmb3e8d442014-05-13 08:08:32 +0000930 free(cmd);
Nicholas Marriott162bacd2009-01-11 23:31:46 +0000931 return (0);
Tiago Cunha2df08822009-11-08 23:02:56 +0000932}
933
Tiago Cunhaf9f6eea2012-03-29 21:05:16 +0000934void
nicm577c0e32015-11-18 14:27:44 +0000935window_pane_timer_callback(__unused int fd, __unused short events, void *data)
Tiago Cunhaf9f6eea2012-03-29 21:05:16 +0000936{
nicm3f4ee982015-05-12 22:40:38 +0000937 window_pane_read_callback(NULL, data);
Tiago Cunhaf9f6eea2012-03-29 21:05:16 +0000938}
939
Tiago Cunha2df08822009-11-08 23:02:56 +0000940void
nicm577c0e32015-11-18 14:27:44 +0000941window_pane_read_callback(__unused struct bufferevent *bufev, void *data)
Tiago Cunha2df08822009-11-08 23:02:56 +0000942{
nicm3f4ee982015-05-12 22:40:38 +0000943 struct window_pane *wp = data;
944 struct evbuffer *evb = wp->event->input;
945 char *new_data;
946 size_t new_size, available;
947 struct client *c;
948 struct timeval tv;
Tiago Cunha2df08822009-11-08 23:02:56 +0000949
nicm3f4ee982015-05-12 22:40:38 +0000950 if (event_initialized(&wp->timer))
951 evtimer_del(&wp->timer);
952
953 log_debug("%%%u has %zu bytes", wp->id, EVBUFFER_LENGTH(evb));
954
955 TAILQ_FOREACH(c, &clients, entry) {
956 if (!tty_client_ready(c, wp))
957 continue;
958
959 available = EVBUFFER_LENGTH(c->tty.event->output);
960 if (available > READ_BACKOFF)
961 goto start_timer;
962 }
963
964 new_size = EVBUFFER_LENGTH(evb) - wp->pipe_off;
Nicholas Marriott091db412010-04-06 21:58:33 +0000965 if (wp->pipe_fd != -1 && new_size > 0) {
nicmf84d32c2015-12-31 18:14:13 +0000966 new_data = EVBUFFER_DATA(evb) + wp->pipe_off;
Nicholas Marriott091db412010-04-06 21:58:33 +0000967 bufferevent_write(wp->pipe_event, new_data, new_size);
968 }
969
970 input_parse(wp);
971
nicm3f4ee982015-05-12 22:40:38 +0000972 wp->pipe_off = EVBUFFER_LENGTH(evb);
nicm3f4ee982015-05-12 22:40:38 +0000973 return;
974
975start_timer:
976 log_debug("%%%u backing off (%s %zu > %d)", wp->id, c->ttyname,
977 available, READ_BACKOFF);
978
979 tv.tv_sec = 0;
980 tv.tv_usec = READ_TIME;
981
982 evtimer_set(&wp->timer, window_pane_timer_callback, wp);
983 evtimer_add(&wp->timer, &tv);
Tiago Cunha2df08822009-11-08 23:02:56 +0000984}
985
986void
nicm577c0e32015-11-18 14:27:44 +0000987window_pane_error_callback(__unused struct bufferevent *bufev,
988 __unused short what, void *data)
Tiago Cunha2df08822009-11-08 23:02:56 +0000989{
990 struct window_pane *wp = data;
991
nicm021c6432015-12-16 21:50:37 +0000992 server_destroy_pane(wp, 1);
Nicholas Marriott162bacd2009-01-11 23:31:46 +0000993}
994
Tiago Cunhad29b57f2009-07-22 17:46:53 +0000995void
Nicholas Marriott162bacd2009-01-11 23:31:46 +0000996window_pane_resize(struct window_pane *wp, u_int sx, u_int sy)
997{
Nicholas Marriott7cd3cf02009-01-12 18:22:47 +0000998 if (sx == wp->sx && sy == wp->sy)
Tiago Cunhad29b57f2009-07-22 17:46:53 +0000999 return;
Nicholas Marriott7cd3cf02009-01-12 18:22:47 +00001000 wp->sx = sx;
1001 wp->sy = sy;
Nicholas Marriott103748d2007-12-06 09:46:23 +00001002
Nicholas Marriott8903c1f2013-02-05 11:08:59 +00001003 screen_resize(&wp->base, sx, sy, wp->saved_grid == NULL);
Nicholas Marriott162bacd2009-01-11 23:31:46 +00001004 if (wp->mode != NULL)
1005 wp->mode->resize(wp, sx, sy);
Nicholas Marriotta41ece52007-07-09 19:04:12 +00001006
Nicholas Marriottdbd8e472013-02-22 21:35:29 +00001007 wp->flags |= PANE_RESIZE;
Nicholas Marriotta41ece52007-07-09 19:04:12 +00001008}
1009
Nicholas Marriott9f5b9ba2010-03-15 12:51:23 +00001010/*
1011 * Enter alternative screen mode. A copy of the visible screen is saved and the
1012 * history is not updated
1013 */
1014void
Nicholas Marriott24d7d072012-11-27 20:08:42 +00001015window_pane_alternate_on(struct window_pane *wp, struct grid_cell *gc,
1016 int cursor)
Nicholas Marriott9f5b9ba2010-03-15 12:51:23 +00001017{
1018 struct screen *s = &wp->base;
1019 u_int sx, sy;
1020
1021 if (wp->saved_grid != NULL)
1022 return;
nicm44657bf2015-10-27 15:58:42 +00001023 if (!options_get_number(wp->window->options, "alternate-screen"))
Nicholas Marriott9f5b9ba2010-03-15 12:51:23 +00001024 return;
1025 sx = screen_size_x(s);
1026 sy = screen_size_y(s);
1027
1028 wp->saved_grid = grid_create(sx, sy, 0);
1029 grid_duplicate_lines(wp->saved_grid, 0, s->grid, screen_hsize(s), sy);
Nicholas Marriott24d7d072012-11-27 20:08:42 +00001030 if (cursor) {
1031 wp->saved_cx = s->cx;
1032 wp->saved_cy = s->cy;
1033 }
Nicholas Marriott9f5b9ba2010-03-15 12:51:23 +00001034 memcpy(&wp->saved_cell, gc, sizeof wp->saved_cell);
1035
1036 grid_view_clear(s->grid, 0, 0, sx, sy);
1037
1038 wp->base.grid->flags &= ~GRID_HISTORY;
1039
1040 wp->flags |= PANE_REDRAW;
1041}
1042
1043/* Exit alternate screen mode and restore the copied grid. */
1044void
Nicholas Marriott24d7d072012-11-27 20:08:42 +00001045window_pane_alternate_off(struct window_pane *wp, struct grid_cell *gc,
1046 int cursor)
Nicholas Marriott9f5b9ba2010-03-15 12:51:23 +00001047{
1048 struct screen *s = &wp->base;
1049 u_int sx, sy;
1050
1051 if (wp->saved_grid == NULL)
1052 return;
nicm44657bf2015-10-27 15:58:42 +00001053 if (!options_get_number(wp->window->options, "alternate-screen"))
Nicholas Marriott9f5b9ba2010-03-15 12:51:23 +00001054 return;
1055 sx = screen_size_x(s);
1056 sy = screen_size_y(s);
1057
1058 /*
1059 * If the current size is bigger, temporarily resize to the old size
1060 * before copying back.
1061 */
1062 if (sy > wp->saved_grid->sy)
Nicholas Marriott8903c1f2013-02-05 11:08:59 +00001063 screen_resize(s, sx, wp->saved_grid->sy, 1);
Nicholas Marriott9f5b9ba2010-03-15 12:51:23 +00001064
1065 /* Restore the grid, cursor position and cell. */
1066 grid_duplicate_lines(s->grid, screen_hsize(s), wp->saved_grid, 0, sy);
Nicholas Marriott24d7d072012-11-27 20:08:42 +00001067 if (cursor)
1068 s->cx = wp->saved_cx;
Nicholas Marriott9f5b9ba2010-03-15 12:51:23 +00001069 if (s->cx > screen_size_x(s) - 1)
1070 s->cx = screen_size_x(s) - 1;
Nicholas Marriott24d7d072012-11-27 20:08:42 +00001071 if (cursor)
1072 s->cy = wp->saved_cy;
Nicholas Marriott9f5b9ba2010-03-15 12:51:23 +00001073 if (s->cy > screen_size_y(s) - 1)
1074 s->cy = screen_size_y(s) - 1;
1075 memcpy(gc, &wp->saved_cell, sizeof *gc);
1076
1077 /*
1078 * Turn history back on (so resize can use it) and then resize back to
1079 * the current size.
1080 */
1081 wp->base.grid->flags |= GRID_HISTORY;
Nicholas Marriott8903c1f2013-02-05 11:08:59 +00001082 if (sy > wp->saved_grid->sy || sx != wp->saved_grid->sx)
1083 screen_resize(s, sx, sy, 1);
Nicholas Marriott9f5b9ba2010-03-15 12:51:23 +00001084
1085 grid_destroy(wp->saved_grid);
1086 wp->saved_grid = NULL;
1087
1088 wp->flags |= PANE_REDRAW;
1089}
1090
Nicholas Marriott7dc18f62007-12-06 10:04:43 +00001091int
Nicholas Marriott162bacd2009-01-11 23:31:46 +00001092window_pane_set_mode(struct window_pane *wp, const struct window_mode *mode)
Nicholas Marriott7dc18f62007-12-06 10:04:43 +00001093{
1094 struct screen *s;
1095
Tiago Cunhad29b57f2009-07-22 17:46:53 +00001096 if (wp->mode != NULL)
Nicholas Marriott7dc18f62007-12-06 10:04:43 +00001097 return (1);
Nicholas Marriott162bacd2009-01-11 23:31:46 +00001098 wp->mode = mode;
Nicholas Marriott7dc18f62007-12-06 10:04:43 +00001099
Nicholas Marriott162bacd2009-01-11 23:31:46 +00001100 if ((s = wp->mode->init(wp)) != NULL)
1101 wp->screen = s;
nicm5267ce82015-08-29 00:39:18 +00001102 wp->flags |= (PANE_REDRAW|PANE_CHANGED);
nicm2e4503a2016-03-01 12:05:15 +00001103
1104 server_status_window(wp->window);
Nicholas Marriott7dc18f62007-12-06 10:04:43 +00001105 return (0);
1106}
1107
1108void
Nicholas Marriott162bacd2009-01-11 23:31:46 +00001109window_pane_reset_mode(struct window_pane *wp)
Nicholas Marriott7dc18f62007-12-06 10:04:43 +00001110{
Nicholas Marriott162bacd2009-01-11 23:31:46 +00001111 if (wp->mode == NULL)
Nicholas Marriott7dc18f62007-12-06 10:04:43 +00001112 return;
1113
Nicholas Marriott162bacd2009-01-11 23:31:46 +00001114 wp->mode->free(wp);
1115 wp->mode = NULL;
Nicholas Marriott7dc18f62007-12-06 10:04:43 +00001116
Nicholas Marriott162bacd2009-01-11 23:31:46 +00001117 wp->screen = &wp->base;
nicm5267ce82015-08-29 00:39:18 +00001118 wp->flags |= (PANE_REDRAW|PANE_CHANGED);
nicm2e4503a2016-03-01 12:05:15 +00001119
1120 server_status_window(wp->window);
Nicholas Marriott9a6e47c2007-11-21 13:11:41 +00001121}
1122
1123void
nicmbf635e72015-04-19 21:34:21 +00001124window_pane_key(struct window_pane *wp, struct client *c, struct session *s,
nicm69e0b832015-11-12 11:05:34 +00001125 key_code key, struct mouse_event *m)
Nicholas Marriott9a6e47c2007-11-21 13:11:41 +00001126{
Tiago Cunha9ac062a2009-10-09 13:07:04 +00001127 struct window_pane *wp2;
1128
nicmbf635e72015-04-19 21:34:21 +00001129 if (KEYC_IS_MOUSE(key) && m == NULL)
1130 return;
1131
Nicholas Marriott44289872009-01-28 19:52:21 +00001132 if (wp->mode != NULL) {
1133 if (wp->mode->key != NULL)
nicmbf635e72015-04-19 21:34:21 +00001134 wp->mode->key(wp, c, s, key, m);
Tiago Cunha9ac062a2009-10-09 13:07:04 +00001135 return;
Tiago Cunhacf9804f2009-10-12 00:04:56 +00001136 }
Tiago Cunha9ac062a2009-10-09 13:07:04 +00001137
nicmf518a072014-08-11 22:14:30 +00001138 if (wp->fd == -1 || wp->flags & PANE_INPUTOFF)
Tiago Cunhacf9804f2009-10-12 00:04:56 +00001139 return;
nicmf518a072014-08-11 22:14:30 +00001140
nicmbf635e72015-04-19 21:34:21 +00001141 input_key(wp, key, m);
1142
1143 if (KEYC_IS_MOUSE(key))
1144 return;
nicm44657bf2015-10-27 15:58:42 +00001145 if (options_get_number(wp->window->options, "synchronize-panes")) {
Tiago Cunha9ac062a2009-10-09 13:07:04 +00001146 TAILQ_FOREACH(wp2, &wp->window->panes, entry) {
1147 if (wp2 == wp || wp2->mode != NULL)
1148 continue;
nicmbdbec092015-12-19 08:43:04 +00001149 if (wp2->fd == -1 || wp2->flags & PANE_INPUTOFF)
1150 continue;
1151 if (window_pane_visible(wp2))
nicmbf635e72015-04-19 21:34:21 +00001152 input_key(wp2, key, NULL);
Tiago Cunha9ac062a2009-10-09 13:07:04 +00001153 }
1154 }
Nicholas Marriott44289872009-01-28 19:52:21 +00001155}
Nicholas Marriotta9e3d5c2009-06-25 16:47:00 +00001156
Nicholas Marriott1e574bb2009-07-15 17:42:44 +00001157int
1158window_pane_visible(struct window_pane *wp)
1159{
1160 struct window *w = wp->window;
1161
Nicholas Marriottc5239c52013-02-24 00:25:03 +00001162 if (wp->layout_cell == NULL)
1163 return (0);
Nicholas Marriott1e574bb2009-07-15 17:42:44 +00001164 if (wp->xoff >= w->sx || wp->yoff >= w->sy)
1165 return (0);
1166 if (wp->xoff + wp->sx > w->sx || wp->yoff + wp->sy > w->sy)
1167 return (0);
1168 return (1);
1169}
1170
Tiago Cunha80af85a2009-05-19 13:32:55 +00001171char *
nicma5d4b7f2014-04-17 14:45:49 +00001172window_pane_search(struct window_pane *wp, const char *searchstr,
1173 u_int *lineno)
Tiago Cunha80af85a2009-05-19 13:32:55 +00001174{
Nicholas Marriott853ad682009-06-25 16:02:37 +00001175 struct screen *s = &wp->base;
Nicholas Marriottf7a9eb42009-06-25 16:04:24 +00001176 char *newsearchstr, *line, *msg;
Nicholas Marriott853ad682009-06-25 16:02:37 +00001177 u_int i;
Tiago Cunha80af85a2009-05-19 13:32:55 +00001178
Nicholas Marriottf7a9eb42009-06-25 16:04:24 +00001179 msg = NULL;
1180 xasprintf(&newsearchstr, "*%s*", searchstr);
1181
Nicholas Marriott853ad682009-06-25 16:02:37 +00001182 for (i = 0; i < screen_size_y(s); i++) {
1183 line = grid_view_string_cells(s->grid, 0, i, screen_size_x(s));
Nicholas Marriottf7a9eb42009-06-25 16:04:24 +00001184 if (fnmatch(newsearchstr, line, 0) == 0) {
1185 msg = line;
1186 if (lineno != NULL)
1187 *lineno = i;
1188 break;
1189 }
Tiago Cunhaa432fcd2012-07-11 19:34:16 +00001190 free(line);
Tiago Cunha80af85a2009-05-19 13:32:55 +00001191 }
Nicholas Marriottf7a9eb42009-06-25 16:04:24 +00001192
Tiago Cunhaa432fcd2012-07-11 19:34:16 +00001193 free(newsearchstr);
Nicholas Marriottf7a9eb42009-06-25 16:04:24 +00001194 return (msg);
Tiago Cunha80af85a2009-05-19 13:32:55 +00001195}
Nicholas Marriottaa8f9012010-03-15 22:03:38 +00001196
nicm540f0b32014-05-08 06:03:30 +00001197/* Get MRU pane from a list. */
1198struct window_pane *
nicm05e7fbd2015-04-25 18:56:05 +00001199window_pane_choose_best(struct window_pane **list, u_int size)
nicm540f0b32014-05-08 06:03:30 +00001200{
1201 struct window_pane *next, *best;
1202 u_int i;
1203
nicm05e7fbd2015-04-25 18:56:05 +00001204 if (size == 0)
nicm540f0b32014-05-08 06:03:30 +00001205 return (NULL);
1206
nicm05e7fbd2015-04-25 18:56:05 +00001207 best = list[0];
1208 for (i = 1; i < size; i++) {
1209 next = list[i];
nicm540f0b32014-05-08 06:03:30 +00001210 if (next->active_point > best->active_point)
1211 best = next;
1212 }
1213 return (best);
1214}
1215
1216/*
1217 * Find the pane directly above another. We build a list of those adjacent to
1218 * top edge and then choose the best.
1219 */
Nicholas Marriottaa8f9012010-03-15 22:03:38 +00001220struct window_pane *
1221window_pane_find_up(struct window_pane *wp)
1222{
nicm05e7fbd2015-04-25 18:56:05 +00001223 struct window_pane *next, *best, **list;
1224 u_int edge, left, right, end, size;
nicm540f0b32014-05-08 06:03:30 +00001225 int found;
Nicholas Marriottaa8f9012010-03-15 22:03:38 +00001226
1227 if (wp == NULL || !window_pane_visible(wp))
1228 return (NULL);
nicm05e7fbd2015-04-25 18:56:05 +00001229
1230 list = NULL;
1231 size = 0;
Nicholas Marriottaa8f9012010-03-15 22:03:38 +00001232
nicm540f0b32014-05-08 06:03:30 +00001233 edge = wp->yoff;
1234 if (edge == 0)
1235 edge = wp->window->sy + 1;
1236
Nicholas Marriottaa8f9012010-03-15 22:03:38 +00001237 left = wp->xoff;
nicm540f0b32014-05-08 06:03:30 +00001238 right = wp->xoff + wp->sx;
Nicholas Marriottaa8f9012010-03-15 22:03:38 +00001239
nicm540f0b32014-05-08 06:03:30 +00001240 TAILQ_FOREACH(next, &wp->window->panes, entry) {
1241 if (next == wp || !window_pane_visible(next))
Nicholas Marriottaa8f9012010-03-15 22:03:38 +00001242 continue;
nicm540f0b32014-05-08 06:03:30 +00001243 if (next->yoff + next->sy + 1 != edge)
Nicholas Marriottaa8f9012010-03-15 22:03:38 +00001244 continue;
nicm540f0b32014-05-08 06:03:30 +00001245 end = next->xoff + next->sx - 1;
1246
1247 found = 0;
1248 if (next->xoff < left && end > right)
1249 found = 1;
1250 else if (next->xoff >= left && next->xoff <= right)
1251 found = 1;
1252 else if (end >= left && end <= right)
1253 found = 1;
nicm05e7fbd2015-04-25 18:56:05 +00001254 if (!found)
1255 continue;
1256 list = xreallocarray(list, size + 1, sizeof *list);
1257 list[size++] = next;
Nicholas Marriottaa8f9012010-03-15 22:03:38 +00001258 }
nicm540f0b32014-05-08 06:03:30 +00001259
nicm05e7fbd2015-04-25 18:56:05 +00001260 best = window_pane_choose_best(list, size);
1261 free(list);
nicm540f0b32014-05-08 06:03:30 +00001262 return (best);
Nicholas Marriottaa8f9012010-03-15 22:03:38 +00001263}
1264
1265/* Find the pane directly below another. */
1266struct window_pane *
1267window_pane_find_down(struct window_pane *wp)
1268{
nicm05e7fbd2015-04-25 18:56:05 +00001269 struct window_pane *next, *best, **list;
1270 u_int edge, left, right, end, size;
nicm540f0b32014-05-08 06:03:30 +00001271 int found;
Nicholas Marriottaa8f9012010-03-15 22:03:38 +00001272
1273 if (wp == NULL || !window_pane_visible(wp))
1274 return (NULL);
nicm05e7fbd2015-04-25 18:56:05 +00001275
1276 list = NULL;
1277 size = 0;
Nicholas Marriottaa8f9012010-03-15 22:03:38 +00001278
nicm540f0b32014-05-08 06:03:30 +00001279 edge = wp->yoff + wp->sy + 1;
1280 if (edge >= wp->window->sy)
1281 edge = 0;
1282
Nicholas Marriottaa8f9012010-03-15 22:03:38 +00001283 left = wp->xoff;
nicm540f0b32014-05-08 06:03:30 +00001284 right = wp->xoff + wp->sx;
Nicholas Marriottaa8f9012010-03-15 22:03:38 +00001285
nicm540f0b32014-05-08 06:03:30 +00001286 TAILQ_FOREACH(next, &wp->window->panes, entry) {
1287 if (next == wp || !window_pane_visible(next))
Nicholas Marriottaa8f9012010-03-15 22:03:38 +00001288 continue;
nicm540f0b32014-05-08 06:03:30 +00001289 if (next->yoff != edge)
Nicholas Marriottaa8f9012010-03-15 22:03:38 +00001290 continue;
nicm540f0b32014-05-08 06:03:30 +00001291 end = next->xoff + next->sx - 1;
1292
1293 found = 0;
1294 if (next->xoff < left && end > right)
1295 found = 1;
1296 else if (next->xoff >= left && next->xoff <= right)
1297 found = 1;
1298 else if (end >= left && end <= right)
1299 found = 1;
nicm05e7fbd2015-04-25 18:56:05 +00001300 if (!found)
1301 continue;
1302 list = xreallocarray(list, size + 1, sizeof *list);
1303 list[size++] = next;
Nicholas Marriottaa8f9012010-03-15 22:03:38 +00001304 }
nicm540f0b32014-05-08 06:03:30 +00001305
nicm05e7fbd2015-04-25 18:56:05 +00001306 best = window_pane_choose_best(list, size);
1307 free(list);
nicm540f0b32014-05-08 06:03:30 +00001308 return (best);
Nicholas Marriottaa8f9012010-03-15 22:03:38 +00001309}
1310
nicm540f0b32014-05-08 06:03:30 +00001311/* Find the pane directly to the left of another. */
Nicholas Marriottaa8f9012010-03-15 22:03:38 +00001312struct window_pane *
1313window_pane_find_left(struct window_pane *wp)
1314{
nicm05e7fbd2015-04-25 18:56:05 +00001315 struct window_pane *next, *best, **list;
1316 u_int edge, top, bottom, end, size;
nicm540f0b32014-05-08 06:03:30 +00001317 int found;
Nicholas Marriottaa8f9012010-03-15 22:03:38 +00001318
1319 if (wp == NULL || !window_pane_visible(wp))
1320 return (NULL);
nicm05e7fbd2015-04-25 18:56:05 +00001321
1322 list = NULL;
1323 size = 0;
Nicholas Marriottaa8f9012010-03-15 22:03:38 +00001324
nicm540f0b32014-05-08 06:03:30 +00001325 edge = wp->xoff;
1326 if (edge == 0)
1327 edge = wp->window->sx + 1;
1328
Nicholas Marriottaa8f9012010-03-15 22:03:38 +00001329 top = wp->yoff;
nicm540f0b32014-05-08 06:03:30 +00001330 bottom = wp->yoff + wp->sy;
Nicholas Marriottaa8f9012010-03-15 22:03:38 +00001331
nicm540f0b32014-05-08 06:03:30 +00001332 TAILQ_FOREACH(next, &wp->window->panes, entry) {
1333 if (next == wp || !window_pane_visible(next))
Nicholas Marriottaa8f9012010-03-15 22:03:38 +00001334 continue;
nicm540f0b32014-05-08 06:03:30 +00001335 if (next->xoff + next->sx + 1 != edge)
Nicholas Marriottaa8f9012010-03-15 22:03:38 +00001336 continue;
nicm540f0b32014-05-08 06:03:30 +00001337 end = next->yoff + next->sy - 1;
1338
1339 found = 0;
1340 if (next->yoff < top && end > bottom)
1341 found = 1;
1342 else if (next->yoff >= top && next->yoff <= bottom)
1343 found = 1;
1344 else if (end >= top && end <= bottom)
1345 found = 1;
nicm05e7fbd2015-04-25 18:56:05 +00001346 if (!found)
1347 continue;
1348 list = xreallocarray(list, size + 1, sizeof *list);
1349 list[size++] = next;
Nicholas Marriottaa8f9012010-03-15 22:03:38 +00001350 }
nicm540f0b32014-05-08 06:03:30 +00001351
nicm05e7fbd2015-04-25 18:56:05 +00001352 best = window_pane_choose_best(list, size);
1353 free(list);
nicm540f0b32014-05-08 06:03:30 +00001354 return (best);
Nicholas Marriottaa8f9012010-03-15 22:03:38 +00001355}
1356
nicm540f0b32014-05-08 06:03:30 +00001357/* Find the pane directly to the right of another. */
Nicholas Marriottaa8f9012010-03-15 22:03:38 +00001358struct window_pane *
1359window_pane_find_right(struct window_pane *wp)
1360{
nicm05e7fbd2015-04-25 18:56:05 +00001361 struct window_pane *next, *best, **list;
1362 u_int edge, top, bottom, end, size;
nicm540f0b32014-05-08 06:03:30 +00001363 int found;
Nicholas Marriottaa8f9012010-03-15 22:03:38 +00001364
1365 if (wp == NULL || !window_pane_visible(wp))
1366 return (NULL);
nicm05e7fbd2015-04-25 18:56:05 +00001367
1368 list = NULL;
1369 size = 0;
Nicholas Marriottaa8f9012010-03-15 22:03:38 +00001370
nicm540f0b32014-05-08 06:03:30 +00001371 edge = wp->xoff + wp->sx + 1;
1372 if (edge >= wp->window->sx)
1373 edge = 0;
1374
Nicholas Marriottaa8f9012010-03-15 22:03:38 +00001375 top = wp->yoff;
nicm540f0b32014-05-08 06:03:30 +00001376 bottom = wp->yoff + wp->sy;
Nicholas Marriottaa8f9012010-03-15 22:03:38 +00001377
nicm540f0b32014-05-08 06:03:30 +00001378 TAILQ_FOREACH(next, &wp->window->panes, entry) {
1379 if (next == wp || !window_pane_visible(next))
Nicholas Marriottaa8f9012010-03-15 22:03:38 +00001380 continue;
nicm540f0b32014-05-08 06:03:30 +00001381 if (next->xoff != edge)
Nicholas Marriottaa8f9012010-03-15 22:03:38 +00001382 continue;
nicm540f0b32014-05-08 06:03:30 +00001383 end = next->yoff + next->sy - 1;
1384
1385 found = 0;
1386 if (next->yoff < top && end > bottom)
1387 found = 1;
1388 else if (next->yoff >= top && next->yoff <= bottom)
1389 found = 1;
1390 else if (end >= top && end <= bottom)
1391 found = 1;
nicm05e7fbd2015-04-25 18:56:05 +00001392 if (!found)
1393 continue;
1394 list = xreallocarray(list, size + 1, sizeof *list);
1395 list[size++] = next;
Nicholas Marriottaa8f9012010-03-15 22:03:38 +00001396 }
nicm540f0b32014-05-08 06:03:30 +00001397
nicm05e7fbd2015-04-25 18:56:05 +00001398 best = window_pane_choose_best(list, size);
1399 free(list);
nicm540f0b32014-05-08 06:03:30 +00001400 return (best);
Nicholas Marriottaa8f9012010-03-15 22:03:38 +00001401}
Tiago Cunha38530de2012-07-11 17:06:11 +00001402
1403/* Clear alert flags for a winlink */
1404void
1405winlink_clear_flags(struct winlink *wl)
1406{
Tiago Cunha38530de2012-07-11 17:06:11 +00001407 struct session *s;
nicm8d66f4f2015-04-22 15:30:11 +00001408 struct winlink *wl_loop;
Tiago Cunha38530de2012-07-11 17:06:11 +00001409
nicm8d66f4f2015-04-22 15:30:11 +00001410 RB_FOREACH(s, sessions, &sessions) {
1411 RB_FOREACH(wl_loop, winlinks, &s->windows) {
1412 if (wl_loop->window != wl->window)
1413 continue;
1414 if ((wl_loop->flags & WINLINK_ALERTFLAGS) == 0)
Tiago Cunha38530de2012-07-11 17:06:11 +00001415 continue;
1416
nicm8d66f4f2015-04-22 15:30:11 +00001417 wl_loop->flags &= ~WINLINK_ALERTFLAGS;
1418 wl_loop->window->flags &= ~WINDOW_ALERTFLAGS;
Tiago Cunha38530de2012-07-11 17:06:11 +00001419 server_status_session(s);
1420 }
1421 }
Tiago Cunha200b0e52012-08-12 19:28:20 +00001422}
nicm0ff33592015-06-17 16:50:28 +00001423
1424int
1425winlink_shuffle_up(struct session *s, struct winlink *wl)
1426{
1427 int idx, last;
1428
1429 idx = wl->idx + 1;
1430
1431 /* Find the next free index. */
1432 for (last = idx; last < INT_MAX; last++) {
1433 if (winlink_find_by_index(&s->windows, last) == NULL)
1434 break;
1435 }
1436 if (last == INT_MAX)
1437 return (-1);
1438
1439 /* Move everything from last - 1 to idx up a bit. */
1440 for (; last > idx; last--) {
1441 wl = winlink_find_by_index(&s->windows, last - 1);
1442 server_link_window(s, wl, s, last, 0, 0, NULL);
1443 server_unlink_window(s, wl);
1444 }
1445
1446 return (idx);
1447}