blob: 4b5f9016baba7ef6b8ad11e42b374a63f7f69d8a [file] [log] [blame] [raw]
Nicholas Marriottfa0f10d2011-06-23 19:21:26 +00001/* $Id$ */
Nicholas Marriotta41ece52007-07-09 19:04:12 +00002
3/*
4 * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
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#include <sys/ioctl.h>
21
Nicholas Marriott4d9af272009-01-23 16:59:14 +000022#include <errno.h>
Nicholas Marriotta41ece52007-07-09 19:04:12 +000023#include <fcntl.h>
Nicholas Marriottf7a9eb42009-06-25 16:04:24 +000024#include <fnmatch.h>
Nicholas Marriott22d1b942009-07-01 19:42:55 +000025#include <pwd.h>
Nicholas Marriotta41ece52007-07-09 19:04:12 +000026#include <signal.h>
27#include <stdlib.h>
28#include <string.h>
Nicholas Marriotta41ece52007-07-09 19:04:12 +000029#include <termios.h>
30#include <unistd.h>
Nicholas Marriottcf77c802007-10-19 20:47:09 +000031
Nicholas Marriottc8cf4382009-05-13 23:27:00 +000032#include "tmux.h"
Nicholas Marriotta41ece52007-07-09 19:04:12 +000033
34/*
Tiago Cunha545893d2009-07-20 15:42:05 +000035 * Each window is attached to a number of panes, each of which is a pty. This
Nicholas Marriott162bacd2009-01-11 23:31:46 +000036 * file contains code to handle them.
Nicholas Marriotta41ece52007-07-09 19:04:12 +000037 *
Nicholas Marriott162bacd2009-01-11 23:31:46 +000038 * A pane has two buffers attached, these are filled and emptied by the main
Nicholas Marriottb9de9062007-08-27 10:08:44 +000039 * server poll loop. Output data is received from pty's in screen format,
Nicholas Marriott35591ec2007-11-07 19:41:17 +000040 * translated and returned as a series of escape sequences and strings via
41 * input_parse (in input.c). Input data is received as key codes and written
Nicholas Marriottccfeb312008-01-02 19:22:21 +000042 * directly via input_key.
Nicholas Marriotta41ece52007-07-09 19:04:12 +000043 *
Nicholas Marriott162bacd2009-01-11 23:31:46 +000044 * Each pane also has a "virtual" screen (screen.c) which contains the current
45 * state and is redisplayed when the window is reattached to a client.
Nicholas Marriotta41ece52007-07-09 19:04:12 +000046 *
Nicholas Marriott4ba3cf62007-10-26 12:29:07 +000047 * Windows are stored directly on a global array and wrapped in any number of
Nicholas Marriott35591ec2007-11-07 19:41:17 +000048 * winlink structs to be linked onto local session RB trees. A reference count
Nicholas Marriott4ba3cf62007-10-26 12:29:07 +000049 * is maintained and a window removed from the global list and destroyed when
Nicholas Marriott35591ec2007-11-07 19:41:17 +000050 * it reaches zero.
Nicholas Marriotta41ece52007-07-09 19:04:12 +000051 */
52
53/* Global window list. */
Nicholas Marriott4ba3cf62007-10-26 12:29:07 +000054struct windows windows;
Tiago Cunha2df08822009-11-08 23:02:56 +000055
Nicholas Marriott536fc242011-04-06 22:16:33 +000056/* Global panes tree. */
57struct window_pane_tree all_window_panes;
58u_int next_window_pane;
59
Tiago Cunha2df08822009-11-08 23:02:56 +000060void window_pane_read_callback(struct bufferevent *, void *);
61void window_pane_error_callback(struct bufferevent *, short, void *);
Nicholas Marriott22d1b942009-07-01 19:42:55 +000062
Nicholas Marriott4ba3cf62007-10-26 12:29:07 +000063RB_GENERATE(winlinks, winlink, entry, winlink_cmp);
64
65int
66winlink_cmp(struct winlink *wl1, struct winlink *wl2)
67{
68 return (wl1->idx - wl2->idx);
Nicholas Marriott536fc242011-04-06 22:16:33 +000069}
70
71RB_GENERATE(window_pane_tree, window_pane, tree_entry, window_pane_cmp);
72
73int
74window_pane_cmp(struct window_pane *wp1, struct window_pane *wp2)
75{
76 return (wp1->id - wp2->id);
Nicholas Marriott4ba3cf62007-10-26 12:29:07 +000077}
78
79struct winlink *
Nicholas Marriott8bfbc8c2009-07-15 17:45:09 +000080winlink_find_by_window(struct winlinks *wwl, struct window *w)
81{
82 struct winlink *wl;
83
84 RB_FOREACH(wl, winlinks, wwl) {
85 if (wl->window == w)
86 return (wl);
87 }
88
89 return (NULL);
90}
91
92struct winlink *
Nicholas Marriott4ba3cf62007-10-26 12:29:07 +000093winlink_find_by_index(struct winlinks *wwl, int idx)
94{
95 struct winlink wl;
96
97 if (idx < 0)
98 fatalx("bad index");
99
100 wl.idx = idx;
101 return (RB_FIND(winlinks, wwl, &wl));
102}
103
104int
Tiago Cunhae61ee942009-08-16 19:16:27 +0000105winlink_next_index(struct winlinks *wwl, int idx)
Nicholas Marriott4ba3cf62007-10-26 12:29:07 +0000106{
Tiago Cunhae61ee942009-08-16 19:16:27 +0000107 int i;
Nicholas Marriott4ba3cf62007-10-26 12:29:07 +0000108
Tiago Cunhae61ee942009-08-16 19:16:27 +0000109 i = idx;
110 do {
Nicholas Marriott4ba3cf62007-10-26 12:29:07 +0000111 if (winlink_find_by_index(wwl, i) == NULL)
112 return (i);
Tiago Cunhae61ee942009-08-16 19:16:27 +0000113 if (i == INT_MAX)
114 i = 0;
115 else
116 i++;
117 } while (i != idx);
118 return (-1);
Nicholas Marriott4ba3cf62007-10-26 12:29:07 +0000119}
120
Nicholas Marriottfd05d072009-01-10 14:43:43 +0000121u_int
122winlink_count(struct winlinks *wwl)
123{
124 struct winlink *wl;
125 u_int n;
126
127 n = 0;
128 RB_FOREACH(wl, winlinks, wwl)
129 n++;
130
131 return (n);
132}
133
Nicholas Marriott4ba3cf62007-10-26 12:29:07 +0000134struct winlink *
Tiago Cunha4e4568c2011-02-15 15:09:52 +0000135winlink_add(struct winlinks *wwl, int idx)
Nicholas Marriott4ba3cf62007-10-26 12:29:07 +0000136{
137 struct winlink *wl;
138
Tiago Cunhae61ee942009-08-16 19:16:27 +0000139 if (idx < 0) {
140 if ((idx = winlink_next_index(wwl, -idx - 1)) == -1)
141 return (NULL);
142 } else if (winlink_find_by_index(wwl, idx) != NULL)
Nicholas Marriott4ba3cf62007-10-26 12:29:07 +0000143 return (NULL);
Nicholas Marriott4ba3cf62007-10-26 12:29:07 +0000144
145 wl = xcalloc(1, sizeof *wl);
146 wl->idx = idx;
Nicholas Marriott4ba3cf62007-10-26 12:29:07 +0000147 RB_INSERT(winlinks, wwl, wl);
148
Nicholas Marriott4ba3cf62007-10-26 12:29:07 +0000149 return (wl);
Tiago Cunha4e4568c2011-02-15 15:09:52 +0000150}
151
152void
153winlink_set_window(struct winlink *wl, struct window *w)
154{
155 wl->window = w;
156 w->references++;
Nicholas Marriott4ba3cf62007-10-26 12:29:07 +0000157}
158
159void
160winlink_remove(struct winlinks *wwl, struct winlink *wl)
161{
162 struct window *w = wl->window;
163
164 RB_REMOVE(winlinks, wwl, wl);
Tiago Cunha7a9bfab2009-11-19 22:37:04 +0000165 if (wl->status_text != NULL)
166 xfree(wl->status_text);
Nicholas Marriott4ba3cf62007-10-26 12:29:07 +0000167 xfree(wl);
168
Tiago Cunha4e4568c2011-02-15 15:09:52 +0000169 if (w != NULL) {
170 if (w->references == 0)
171 fatal("bad reference count");
172 w->references--;
173 if (w->references == 0)
174 window_destroy(w);
175 }
Nicholas Marriott4ba3cf62007-10-26 12:29:07 +0000176}
177
178struct winlink *
Tiago Cunhac12e0b02009-11-28 14:50:37 +0000179winlink_next(struct winlink *wl)
Nicholas Marriott4ba3cf62007-10-26 12:29:07 +0000180{
181 return (RB_NEXT(winlinks, wwl, wl));
Nicholas Marriott103748d2007-12-06 09:46:23 +0000182}
Nicholas Marriott4ba3cf62007-10-26 12:29:07 +0000183
184struct winlink *
Tiago Cunhac12e0b02009-11-28 14:50:37 +0000185winlink_previous(struct winlink *wl)
Nicholas Marriott4ba3cf62007-10-26 12:29:07 +0000186{
Nicholas Marriott85d520c2008-06-03 18:38:51 +0000187 return (RB_PREV(winlinks, wwl, wl));
Nicholas Marriott103748d2007-12-06 09:46:23 +0000188}
Nicholas Marriott4ba3cf62007-10-26 12:29:07 +0000189
Tiago Cunha8d3b7262010-06-22 23:29:05 +0000190struct winlink *
Tiago Cunha11f81e82010-07-17 14:38:13 +0000191winlink_next_by_number(struct winlink *wl, struct session *s, int n)
Tiago Cunha8d3b7262010-06-22 23:29:05 +0000192{
193 for (; n > 0; n--) {
194 if ((wl = RB_NEXT(winlinks, wwl, wl)) == NULL)
Tiago Cunha11f81e82010-07-17 14:38:13 +0000195 wl = RB_MIN(winlinks, &s->windows);
Tiago Cunha8d3b7262010-06-22 23:29:05 +0000196 }
197
198 return (wl);
199}
200
201struct winlink *
Tiago Cunha11f81e82010-07-17 14:38:13 +0000202winlink_previous_by_number(struct winlink *wl, struct session *s, int n)
Tiago Cunha8d3b7262010-06-22 23:29:05 +0000203{
204 for (; n > 0; n--) {
205 if ((wl = RB_PREV(winlinks, wwl, wl)) == NULL)
Tiago Cunha11f81e82010-07-17 14:38:13 +0000206 wl = RB_MAX(winlinks, &s->windows);
Tiago Cunha8d3b7262010-06-22 23:29:05 +0000207 }
208
209 return (wl);
210}
211
Nicholas Marriott46f5e422008-11-16 10:10:26 +0000212void
213winlink_stack_push(struct winlink_stack *stack, struct winlink *wl)
214{
215 if (wl == NULL)
216 return;
217
218 winlink_stack_remove(stack, wl);
Tiago Cunha6a1ebb12009-10-11 23:38:16 +0000219 TAILQ_INSERT_HEAD(stack, wl, sentry);
Nicholas Marriott46f5e422008-11-16 10:10:26 +0000220}
221
222void
223winlink_stack_remove(struct winlink_stack *stack, struct winlink *wl)
224{
225 struct winlink *wl2;
226
227 if (wl == NULL)
228 return;
Tiago Cunhacc094fd2009-12-04 22:14:47 +0000229
Tiago Cunha6a1ebb12009-10-11 23:38:16 +0000230 TAILQ_FOREACH(wl2, stack, sentry) {
Nicholas Marriott46f5e422008-11-16 10:10:26 +0000231 if (wl2 == wl) {
Tiago Cunha6a1ebb12009-10-11 23:38:16 +0000232 TAILQ_REMOVE(stack, wl, sentry);
Nicholas Marriott46f5e422008-11-16 10:10:26 +0000233 return;
234 }
235 }
236}
237
Nicholas Marriottb4ac8c12009-01-14 19:29:32 +0000238int
239window_index(struct window *s, u_int *i)
240{
241 for (*i = 0; *i < ARRAY_LENGTH(&windows); (*i)++) {
242 if (s == ARRAY_ITEM(&windows, *i))
243 return (0);
244 }
245 return (-1);
246}
247
Nicholas Marriotta41ece52007-07-09 19:04:12 +0000248struct window *
Nicholas Marriott56f80a52009-03-07 09:29:54 +0000249window_create1(u_int sx, u_int sy)
Nicholas Marriotta41ece52007-07-09 19:04:12 +0000250{
251 struct window *w;
Nicholas Marriottb4ac8c12009-01-14 19:29:32 +0000252 u_int i;
Nicholas Marriotta41ece52007-07-09 19:04:12 +0000253
Tiago Cunhaab38d912009-11-08 23:22:24 +0000254 w = xcalloc(1, sizeof *w);
Nicholas Marriott4d9af272009-01-23 16:59:14 +0000255 w->name = NULL;
Nicholas Marriott0f956712008-06-04 17:54:27 +0000256 w->flags = 0;
Nicholas Marriottb4ac8c12009-01-14 19:29:32 +0000257
258 TAILQ_INIT(&w->panes);
259 w->active = NULL;
Nicholas Marriottd90d6462008-06-29 07:04:31 +0000260
Tiago Cunhad9dcc5e2009-07-28 23:04:29 +0000261 w->lastlayout = -1;
Tiago Cunha545893d2009-07-20 15:42:05 +0000262 w->layout_root = NULL;
Tiago Cunhacc094fd2009-12-04 22:14:47 +0000263
Nicholas Marriott162bacd2009-01-11 23:31:46 +0000264 w->sx = sx;
265 w->sy = sy;
Tiago Cunhaab38d912009-11-08 23:22:24 +0000266
267 queue_window_name(w);
Nicholas Marriott162bacd2009-01-11 23:31:46 +0000268
Nicholas Marriott86504af2009-07-08 18:01:31 +0000269 options_init(&w->options, &global_w_options);
Nicholas Marriotta41ece52007-07-09 19:04:12 +0000270
Nicholas Marriottb4ac8c12009-01-14 19:29:32 +0000271 for (i = 0; i < ARRAY_LENGTH(&windows); i++) {
272 if (ARRAY_ITEM(&windows, i) == NULL) {
273 ARRAY_SET(&windows, i, w);
274 break;
275 }
276 }
277 if (i == ARRAY_LENGTH(&windows))
278 ARRAY_ADD(&windows, w);
Nicholas Marriott4ba3cf62007-10-26 12:29:07 +0000279 w->references = 0;
Nicholas Marriotta41ece52007-07-09 19:04:12 +0000280
Nicholas Marriott56f80a52009-03-07 09:29:54 +0000281 return (w);
282}
283
284struct window *
Tiago Cunhaa3a150f2009-09-02 01:02:44 +0000285window_create(const char *name, const char *cmd, const char *shell,
286 const char *cwd, struct environ *env, struct termios *tio,
287 u_int sx, u_int sy, u_int hlimit,char **cause)
Nicholas Marriott56f80a52009-03-07 09:29:54 +0000288{
Tiago Cunha545893d2009-07-20 15:42:05 +0000289 struct window *w;
290 struct window_pane *wp;
Nicholas Marriott56f80a52009-03-07 09:29:54 +0000291
292 w = window_create1(sx, sy);
Tiago Cunha6708ad12009-07-23 13:10:38 +0000293 wp = window_add_pane(w, hlimit);
Tiago Cunha545893d2009-07-20 15:42:05 +0000294 layout_init(w);
Tiago Cunhaa3a150f2009-09-02 01:02:44 +0000295 if (window_pane_spawn(wp, cmd, shell, cwd, env, tio, cause) != 0) {
Nicholas Marriottd90d6462008-06-29 07:04:31 +0000296 window_destroy(w);
297 return (NULL);
298 }
Nicholas Marriottb4ac8c12009-01-14 19:29:32 +0000299 w->active = TAILQ_FIRST(&w->panes);
Nicholas Marriott2d15f592009-01-20 19:35:03 +0000300 if (name != NULL) {
301 w->name = xstrdup(name);
302 options_set_number(&w->options, "automatic-rename", 0);
303 } else
304 w->name = default_window_name(w);
Nicholas Marriotta41ece52007-07-09 19:04:12 +0000305 return (w);
306}
307
Nicholas Marriotta41ece52007-07-09 19:04:12 +0000308void
309window_destroy(struct window *w)
310{
Nicholas Marriott4ba3cf62007-10-26 12:29:07 +0000311 u_int i;
312
Nicholas Marriottb4ac8c12009-01-14 19:29:32 +0000313 if (window_index(w, &i) != 0)
314 fatalx("index not found");
315 ARRAY_SET(&windows, i, NULL);
316 while (!ARRAY_EMPTY(&windows) && ARRAY_LAST(&windows) == NULL)
317 ARRAY_TRUNC(&windows, 1);
Tiago Cunha545893d2009-07-20 15:42:05 +0000318
319 if (w->layout_root != NULL)
320 layout_free(w);
Tiago Cunhaab38d912009-11-08 23:22:24 +0000321
322 evtimer_del(&w->name_timer);
Nicholas Marriott103748d2007-12-06 09:46:23 +0000323
Nicholas Marriott7a82e862008-12-08 16:19:51 +0000324 options_free(&w->options);
Nicholas Marriott9d563c32007-10-01 14:15:48 +0000325
Nicholas Marriottb4ac8c12009-01-14 19:29:32 +0000326 window_destroy_panes(w);
Nicholas Marriott4d9af272009-01-23 16:59:14 +0000327
328 if (w->name != NULL)
329 xfree(w->name);
Nicholas Marriotta41ece52007-07-09 19:04:12 +0000330 xfree(w);
331}
332
Tiago Cunhad29b57f2009-07-22 17:46:53 +0000333void
Nicholas Marriotta41ece52007-07-09 19:04:12 +0000334window_resize(struct window *w, u_int sx, u_int sy)
335{
Nicholas Marriottb4ac8c12009-01-14 19:29:32 +0000336 w->sx = sx;
337 w->sy = sy;
Nicholas Marriottb4ac8c12009-01-14 19:29:32 +0000338}
339
340void
341window_set_active_pane(struct window *w, struct window_pane *wp)
342{
Nicholas Marriott36e537b2010-12-06 21:53:50 +0000343 if (wp == w->active)
344 return;
Tiago Cunhacd079e82010-10-24 01:34:30 +0000345 w->last = w->active;
Nicholas Marriottb4ac8c12009-01-14 19:29:32 +0000346 w->active = wp;
Nicholas Marriott1e574bb2009-07-15 17:42:44 +0000347 while (!window_pane_visible(w->active)) {
Nicholas Marriottb4ac8c12009-01-14 19:29:32 +0000348 w->active = TAILQ_PREV(w->active, window_panes, entry);
Nicholas Marriott1e574bb2009-07-15 17:42:44 +0000349 if (w->active == NULL)
350 w->active = TAILQ_LAST(&w->panes, window_panes);
351 if (w->active == wp)
352 return;
353 }
Nicholas Marriottb4ac8c12009-01-14 19:29:32 +0000354}
355
Nicholas Marriottfa0f10d2011-06-23 19:21:26 +0000356struct window_pane *
357window_get_active_at(struct window *w, u_int x, u_int y)
358{
359 struct window_pane *wp;
360
361 TAILQ_FOREACH(wp, &w->panes, entry) {
362 if (!window_pane_visible(wp))
363 continue;
364 if (x < wp->xoff || x > wp->xoff + wp->sx)
365 continue;
366 if (y < wp->yoff || y > wp->yoff + wp->sy)
367 continue;
368 return (wp);
369 }
370 return (NULL);
371}
372
Tiago Cunhaea1721b2009-10-11 23:46:02 +0000373void
374window_set_active_at(struct window *w, u_int x, u_int y)
375{
376 struct window_pane *wp;
377
Nicholas Marriottfa0f10d2011-06-23 19:21:26 +0000378 wp = window_get_active_at(w, x, y);
379 if (wp != NULL && wp != w->active)
Tiago Cunhaea1721b2009-10-11 23:46:02 +0000380 window_set_active_pane(w, wp);
Nicholas Marriottfa0f10d2011-06-23 19:21:26 +0000381}
382
383struct window_pane *
384window_find_string(struct window *w, const char *s)
385{
386 u_int x, y;
387
388 x = w->sx / 2;
389 y = w->sy / 2;
390
391 if (strcasecmp(s, "top") == 0)
392 y = 0;
393 else if (strcasecmp(s, "bottom") == 0)
394 y = w->sy - 1;
395 else if (strcasecmp(s, "left") == 0)
396 x = 0;
397 else if (strcasecmp(s, "right") == 0)
398 x = w->sx - 1;
399 else if (strcasecmp(s, "top-left") == 0) {
400 x = 0;
401 y = 0;
402 } else if (strcasecmp(s, "top-right") == 0) {
403 x = w->sx - 1;
404 y = 0;
405 } else if (strcasecmp(s, "bottom-left") == 0) {
406 x = 0;
407 y = w->sy - 1;
408 } else if (strcasecmp(s, "bottom-right") == 0) {
409 x = w->sx - 1;
410 y = w->sy - 1;
411 } else
412 return (NULL);
413
414 return (window_get_active_at(w, x, y));
Tiago Cunhaea1721b2009-10-11 23:46:02 +0000415}
416
Nicholas Marriottb4ac8c12009-01-14 19:29:32 +0000417struct window_pane *
Tiago Cunha6708ad12009-07-23 13:10:38 +0000418window_add_pane(struct window *w, u_int hlimit)
Nicholas Marriott7cd3cf02009-01-12 18:22:47 +0000419{
420 struct window_pane *wp;
Nicholas Marriott7cd3cf02009-01-12 18:22:47 +0000421
Tiago Cunha545893d2009-07-20 15:42:05 +0000422 wp = window_pane_create(w, w->sx, w->sy, hlimit);
Nicholas Marriottb4ac8c12009-01-14 19:29:32 +0000423 if (TAILQ_EMPTY(&w->panes))
424 TAILQ_INSERT_HEAD(&w->panes, wp, entry);
425 else
426 TAILQ_INSERT_AFTER(&w->panes, w->active, wp, entry);
Nicholas Marriottb4ac8c12009-01-14 19:29:32 +0000427 return (wp);
Nicholas Marriott162bacd2009-01-11 23:31:46 +0000428}
429
Nicholas Marriottb4ac8c12009-01-14 19:29:32 +0000430void
Nicholas Marriottf8555912009-01-13 06:50:10 +0000431window_remove_pane(struct window *w, struct window_pane *wp)
Nicholas Marriott162bacd2009-01-11 23:31:46 +0000432{
Tiago Cunha8703e9f2010-10-24 01:32:35 +0000433 if (wp == w->active) {
Tiago Cunhacd079e82010-10-24 01:34:30 +0000434 w->active = w->last;
435 w->last = NULL;
436 if (w->active == NULL) {
437 w->active = TAILQ_PREV(wp, window_panes, entry);
438 if (w->active == NULL)
439 w->active = TAILQ_NEXT(wp, entry);
440 }
441 } else if (wp == w->last)
442 w->last = NULL;
Nicholas Marriottf8555912009-01-13 06:50:10 +0000443
Nicholas Marriottb4ac8c12009-01-14 19:29:32 +0000444 TAILQ_REMOVE(&w->panes, wp, entry);
445 window_pane_destroy(wp);
Nicholas Marriottb4ac8c12009-01-14 19:29:32 +0000446}
447
448struct window_pane *
449window_pane_at_index(struct window *w, u_int idx)
450{
451 struct window_pane *wp;
452 u_int n;
453
454 n = 0;
455 TAILQ_FOREACH(wp, &w->panes, entry) {
456 if (n == idx)
457 return (wp);
458 n++;
459 }
460 return (NULL);
461}
462
Tiago Cunha11f81e82010-07-17 14:38:13 +0000463struct window_pane *
464window_pane_next_by_number(struct window *w, struct window_pane *wp, u_int n)
465{
466 for (; n > 0; n--) {
467 if ((wp = TAILQ_NEXT(wp, entry)) == NULL)
468 wp = TAILQ_FIRST(&w->panes);
469 }
470
471 return (wp);
472}
473
474struct window_pane *
475window_pane_previous_by_number(struct window *w, struct window_pane *wp,
476 u_int n)
477{
478 for (; n > 0; n--) {
479 if ((wp = TAILQ_PREV(wp, window_panes, entry)) == NULL)
480 wp = TAILQ_LAST(&w->panes, window_panes);
481 }
482
483 return (wp);
484}
485
Nicholas Marriottb4ac8c12009-01-14 19:29:32 +0000486u_int
Tiago Cunhaae7dda12009-07-17 18:32:54 +0000487window_pane_index(struct window *w, struct window_pane *wp)
488{
489 struct window_pane *wq;
490 u_int n;
491
492 n = 0;
493 TAILQ_FOREACH(wq, &w->panes, entry) {
494 if (wp == wq)
495 break;
496 n++;
497 }
498 return (n);
499}
500
501u_int
Nicholas Marriottb4ac8c12009-01-14 19:29:32 +0000502window_count_panes(struct window *w)
503{
504 struct window_pane *wp;
505 u_int n;
506
507 n = 0;
508 TAILQ_FOREACH(wp, &w->panes, entry)
509 n++;
510 return (n);
511}
512
513void
514window_destroy_panes(struct window *w)
515{
516 struct window_pane *wp;
517
518 while (!TAILQ_EMPTY(&w->panes)) {
519 wp = TAILQ_FIRST(&w->panes);
520 TAILQ_REMOVE(&w->panes, wp, entry);
521 window_pane_destroy(wp);
522 }
Nicholas Marriott162bacd2009-01-11 23:31:46 +0000523}
524
Tiago Cunha30f6d9b2011-01-07 16:55:40 +0000525/* Return list of printable window flag symbols. No flags is just a space. */
526char *
527window_printable_flags(struct session *s, struct winlink *wl)
528{
529 char flags[BUFSIZ];
530 int pos;
531
532 pos = 0;
533 if (wl->flags & WINLINK_ACTIVITY)
534 flags[pos++] = '#';
535 if (wl->flags & WINLINK_BELL)
536 flags[pos++] = '!';
537 if (wl->flags & WINLINK_CONTENT)
538 flags[pos++] = '+';
539 if (wl->flags & WINLINK_SILENCE)
540 flags[pos++] = '~';
541 if (wl == s->curw)
542 flags[pos++] = '*';
543 if (wl == TAILQ_FIRST(&s->lastw))
544 flags[pos++] = '-';
545 if (pos == 0)
546 flags[pos++] = ' ';
547 flags[pos] = '\0';
548 return (xstrdup(flags));
549}
550
Nicholas Marriott536fc242011-04-06 22:16:33 +0000551/* Find pane in global tree by id. */
552struct window_pane *
553window_pane_find_by_id(u_int id)
554{
555 struct window_pane wp;
556
557 wp.id = id;
558 return (RB_FIND(window_pane_tree, &all_window_panes, &wp));
559}
560
Nicholas Marriott162bacd2009-01-11 23:31:46 +0000561struct window_pane *
562window_pane_create(struct window *w, u_int sx, u_int sy, u_int hlimit)
563{
564 struct window_pane *wp;
565
Nicholas Marriottb4ac8c12009-01-14 19:29:32 +0000566 wp = xcalloc(1, sizeof *wp);
Nicholas Marriott162bacd2009-01-11 23:31:46 +0000567 wp->window = w;
Nicholas Marriott536fc242011-04-06 22:16:33 +0000568
569 wp->id = next_window_pane++;
570 RB_INSERT(window_pane_tree, &all_window_panes, wp);
Nicholas Marriott162bacd2009-01-11 23:31:46 +0000571
572 wp->cmd = NULL;
Tiago Cunhaa3a150f2009-09-02 01:02:44 +0000573 wp->shell = NULL;
Nicholas Marriott162bacd2009-01-11 23:31:46 +0000574 wp->cwd = NULL;
575
576 wp->fd = -1;
Tiago Cunha2df08822009-11-08 23:02:56 +0000577 wp->event = NULL;
Nicholas Marriott162bacd2009-01-11 23:31:46 +0000578
579 wp->mode = NULL;
580
Tiago Cunha545893d2009-07-20 15:42:05 +0000581 wp->layout_cell = NULL;
582
Nicholas Marriottb6450b12009-04-01 18:21:42 +0000583 wp->xoff = 0;
Tiago Cunhacc094fd2009-12-04 22:14:47 +0000584 wp->yoff = 0;
Nicholas Marriottb6450b12009-04-01 18:21:42 +0000585
Nicholas Marriott7cd3cf02009-01-12 18:22:47 +0000586 wp->sx = sx;
587 wp->sy = sy;
Nicholas Marriott7cd3cf02009-01-12 18:22:47 +0000588
Tiago Cunha6091b052009-10-12 00:35:08 +0000589 wp->pipe_fd = -1;
Tiago Cunha6091b052009-10-12 00:35:08 +0000590 wp->pipe_off = 0;
Tiago Cunhacb0bf6a2009-11-08 22:59:53 +0000591 wp->pipe_event = NULL;
Tiago Cunha6091b052009-10-12 00:35:08 +0000592
Nicholas Marriotte63567d2009-07-14 06:40:33 +0000593 wp->saved_grid = NULL;
594
Nicholas Marriott162bacd2009-01-11 23:31:46 +0000595 screen_init(&wp->base, sx, sy, hlimit);
596 wp->screen = &wp->base;
597
598 input_init(wp);
Nicholas Marriott7cd3cf02009-01-12 18:22:47 +0000599
Nicholas Marriott162bacd2009-01-11 23:31:46 +0000600 return (wp);
601}
602
603void
604window_pane_destroy(struct window_pane *wp)
605{
Tiago Cunha01052ca2010-08-29 14:46:13 +0000606 window_pane_reset_mode(wp);
607
Tiago Cunha2df08822009-11-08 23:02:56 +0000608 if (wp->fd != -1) {
Nicholas Marriott162bacd2009-01-11 23:31:46 +0000609 close(wp->fd);
Tiago Cunha2df08822009-11-08 23:02:56 +0000610 bufferevent_free(wp->event);
611 }
Nicholas Marriott162bacd2009-01-11 23:31:46 +0000612
613 input_free(wp);
614
Nicholas Marriott162bacd2009-01-11 23:31:46 +0000615 screen_free(&wp->base);
Nicholas Marriotte63567d2009-07-14 06:40:33 +0000616 if (wp->saved_grid != NULL)
617 grid_destroy(wp->saved_grid);
Tiago Cunha6091b052009-10-12 00:35:08 +0000618
619 if (wp->pipe_fd != -1) {
Tiago Cunha6091b052009-10-12 00:35:08 +0000620 close(wp->pipe_fd);
Tiago Cunhacb0bf6a2009-11-08 22:59:53 +0000621 bufferevent_free(wp->pipe_event);
Tiago Cunha6091b052009-10-12 00:35:08 +0000622 }
Nicholas Marriott162bacd2009-01-11 23:31:46 +0000623
Nicholas Marriott536fc242011-04-06 22:16:33 +0000624 RB_REMOVE(window_pane_tree, &all_window_panes, wp);
625
Nicholas Marriott162bacd2009-01-11 23:31:46 +0000626 if (wp->cwd != NULL)
627 xfree(wp->cwd);
Tiago Cunhaa3a150f2009-09-02 01:02:44 +0000628 if (wp->shell != NULL)
629 xfree(wp->shell);
Nicholas Marriott162bacd2009-01-11 23:31:46 +0000630 if (wp->cmd != NULL)
631 xfree(wp->cmd);
632 xfree(wp);
633}
634
635int
Tiago Cunhaa3a150f2009-09-02 01:02:44 +0000636window_pane_spawn(struct window_pane *wp, const char *cmd, const char *shell,
Tiago Cunhaf415d432009-08-16 18:59:12 +0000637 const char *cwd, struct environ *env, struct termios *tio, char **cause)
Nicholas Marriott162bacd2009-01-11 23:31:46 +0000638{
Nicholas Marriott0fc65532010-04-06 21:59:19 +0000639 struct winsize ws;
Nicholas Marriott536fc242011-04-06 22:16:33 +0000640 char *argv0, paneid[16];
Nicholas Marriott0fc65532010-04-06 21:59:19 +0000641 const char *ptr;
642 struct termios tio2;
Nicholas Marriott162bacd2009-01-11 23:31:46 +0000643
Tiago Cunha2df08822009-11-08 23:02:56 +0000644 if (wp->fd != -1) {
Nicholas Marriott162bacd2009-01-11 23:31:46 +0000645 close(wp->fd);
Tiago Cunha2df08822009-11-08 23:02:56 +0000646 bufferevent_free(wp->event);
647 }
Nicholas Marriott162bacd2009-01-11 23:31:46 +0000648 if (cmd != NULL) {
649 if (wp->cmd != NULL)
650 xfree(wp->cmd);
651 wp->cmd = xstrdup(cmd);
Tiago Cunhaa3a150f2009-09-02 01:02:44 +0000652 }
653 if (shell != NULL) {
654 if (wp->shell != NULL)
655 xfree(wp->shell);
656 wp->shell = xstrdup(shell);
Nicholas Marriott162bacd2009-01-11 23:31:46 +0000657 }
658 if (cwd != NULL) {
659 if (wp->cwd != NULL)
660 xfree(wp->cwd);
661 wp->cwd = xstrdup(cwd);
662 }
663
664 memset(&ws, 0, sizeof ws);
665 ws.ws_col = screen_size_x(&wp->base);
666 ws.ws_row = screen_size_y(&wp->base);
Nicholas Marriott2d15f592009-01-20 19:35:03 +0000667
Tiago Cunhacc094fd2009-12-04 22:14:47 +0000668 switch (wp->pid = forkpty(&wp->fd, wp->tty, NULL, &ws)) {
Nicholas Marriott162bacd2009-01-11 23:31:46 +0000669 case -1:
Nicholas Marriott4d9af272009-01-23 16:59:14 +0000670 wp->fd = -1;
671 xasprintf(cause, "%s: %s", cmd, strerror(errno));
672 return (-1);
Nicholas Marriott162bacd2009-01-11 23:31:46 +0000673 case 0:
674 if (chdir(wp->cwd) != 0)
675 chdir("/");
Tiago Cunha29b1b2f2009-08-09 17:48:55 +0000676
Nicholas Marriott15b643f2009-09-16 12:36:28 +0000677 if (tcgetattr(STDIN_FILENO, &tio2) != 0)
678 fatal("tcgetattr failed");
679 if (tio != NULL)
680 memcpy(tio2.c_cc, tio->c_cc, sizeof tio2.c_cc);
681 tio2.c_cc[VERASE] = '\177';
682 if (tcsetattr(STDIN_FILENO, TCSANOW, &tio2) != 0)
683 fatal("tcgetattr failed");
684
Tiago Cunhad4b58c72010-10-24 00:45:57 +0000685 closefrom(STDERR_FILENO + 1);
686
Nicholas Marriott536fc242011-04-06 22:16:33 +0000687 xsnprintf(paneid, sizeof paneid, "%%%u", wp->id);
688 environ_set(env, "TMUX_PANE", paneid);
Nicholas Marriott0fc65532010-04-06 21:59:19 +0000689 environ_push(env);
Tiago Cunha29b1b2f2009-08-09 17:48:55 +0000690
Tiago Cunha56040be2010-08-29 14:42:11 +0000691 clear_signals(1);
Nicholas Marriott162bacd2009-01-11 23:31:46 +0000692 log_close();
693
Nicholas Marriott22d1b942009-07-01 19:42:55 +0000694 if (*wp->cmd != '\0') {
Tiago Cunha5838ee12009-09-02 01:08:32 +0000695 /* Set SHELL but only if it is currently not useful. */
696 shell = getenv("SHELL");
697 if (shell == NULL || *shell == '\0' || areshell(shell))
698 setenv("SHELL", wp->shell, 1);
699
Nicholas Marriott22d1b942009-07-01 19:42:55 +0000700 execl(_PATH_BSHELL, "sh", "-c", wp->cmd, (char *) NULL);
701 fatal("execl failed");
702 }
703
704 /* No command; fork a login shell. */
Tiago Cunhaa3a150f2009-09-02 01:02:44 +0000705 ptr = strrchr(wp->shell, '/');
706 if (ptr != NULL && *(ptr + 1) != '\0')
Nicholas Marriott22d1b942009-07-01 19:42:55 +0000707 xasprintf(&argv0, "-%s", ptr + 1);
708 else
Tiago Cunhaa3a150f2009-09-02 01:02:44 +0000709 xasprintf(&argv0, "-%s", wp->shell);
Tiago Cunha5838ee12009-09-02 01:08:32 +0000710 setenv("SHELL", wp->shell, 1);
Tiago Cunhaa3a150f2009-09-02 01:02:44 +0000711 execl(wp->shell, argv0, (char *) NULL);
Nicholas Marriott162bacd2009-01-11 23:31:46 +0000712 fatal("execl failed");
713 }
714
Tiago Cunha492e3aa2011-01-21 23:44:13 +0000715 setblocking(wp->fd, 0);
716
Tiago Cunha2df08822009-11-08 23:02:56 +0000717 wp->event = bufferevent_new(wp->fd,
718 window_pane_read_callback, NULL, window_pane_error_callback, wp);
719 bufferevent_enable(wp->event, EV_READ|EV_WRITE);
Nicholas Marriott162bacd2009-01-11 23:31:46 +0000720
721 return (0);
Tiago Cunha2df08822009-11-08 23:02:56 +0000722}
723
Tiago Cunhac12e0b02009-11-28 14:50:37 +0000724/* ARGSUSED */
Tiago Cunha2df08822009-11-08 23:02:56 +0000725void
726window_pane_read_callback(unused struct bufferevent *bufev, void *data)
727{
Nicholas Marriott091db412010-04-06 21:58:33 +0000728 struct window_pane *wp = data;
729 char *new_data;
730 size_t new_size;
Tiago Cunha2df08822009-11-08 23:02:56 +0000731
Nicholas Marriott091db412010-04-06 21:58:33 +0000732 new_size = EVBUFFER_LENGTH(wp->event->input) - wp->pipe_off;
733 if (wp->pipe_fd != -1 && new_size > 0) {
734 new_data = EVBUFFER_DATA(wp->event->input);
735 bufferevent_write(wp->pipe_event, new_data, new_size);
736 }
737
738 input_parse(wp);
739
740 wp->pipe_off = EVBUFFER_LENGTH(wp->event->input);
Nicholas Marriott3a4f7652010-12-06 22:52:21 +0000741
742 /*
743 * If we get here, we're not outputting anymore, so set the silence
744 * flag on the window.
745 */
746 wp->window->flags |= WINDOW_SILENCE;
747 if (gettimeofday(&wp->window->silence_timer, NULL) != 0)
748 fatal("gettimeofday failed.");
Tiago Cunha2df08822009-11-08 23:02:56 +0000749}
750
Tiago Cunhac12e0b02009-11-28 14:50:37 +0000751/* ARGSUSED */
Tiago Cunha2df08822009-11-08 23:02:56 +0000752void
753window_pane_error_callback(
754 unused struct bufferevent *bufev, unused short what, void *data)
755{
756 struct window_pane *wp = data;
757
Tiago Cunha72bc03a2009-11-14 17:48:39 +0000758 server_destroy_pane(wp);
Nicholas Marriott162bacd2009-01-11 23:31:46 +0000759}
760
Tiago Cunhad29b57f2009-07-22 17:46:53 +0000761void
Nicholas Marriott162bacd2009-01-11 23:31:46 +0000762window_pane_resize(struct window_pane *wp, u_int sx, u_int sy)
763{
Nicholas Marriotta41ece52007-07-09 19:04:12 +0000764 struct winsize ws;
765
Nicholas Marriott7cd3cf02009-01-12 18:22:47 +0000766 if (sx == wp->sx && sy == wp->sy)
Tiago Cunhad29b57f2009-07-22 17:46:53 +0000767 return;
Nicholas Marriott7cd3cf02009-01-12 18:22:47 +0000768 wp->sx = sx;
769 wp->sy = sy;
Nicholas Marriott103748d2007-12-06 09:46:23 +0000770
Nicholas Marriotta41ece52007-07-09 19:04:12 +0000771 memset(&ws, 0, sizeof ws);
772 ws.ws_col = sx;
773 ws.ws_row = sy;
774
Nicholas Marriott162bacd2009-01-11 23:31:46 +0000775 screen_resize(&wp->base, sx, sy);
776 if (wp->mode != NULL)
777 wp->mode->resize(wp, sx, sy);
Nicholas Marriotta41ece52007-07-09 19:04:12 +0000778
Nicholas Marriott162bacd2009-01-11 23:31:46 +0000779 if (wp->fd != -1 && ioctl(wp->fd, TIOCSWINSZ, &ws) == -1)
Nicholas Marriottd73516c2009-09-23 16:09:12 +0000780#ifdef __sun
Nicholas Marriott94e23392009-07-22 12:42:57 +0000781 /*
782 * Some versions of Solaris apparently can return an error when
783 * resizing; don't know why this happens, can't reproduce on
784 * other platforms and ignoring it doesn't seem to cause any
785 * issues.
786 */
787 if (errno != EINVAL)
788#endif
Nicholas Marriott4b62b1d2007-07-25 23:13:18 +0000789 fatal("ioctl failed");
Nicholas Marriotta41ece52007-07-09 19:04:12 +0000790}
791
Nicholas Marriott9f5b9ba2010-03-15 12:51:23 +0000792/*
793 * Enter alternative screen mode. A copy of the visible screen is saved and the
794 * history is not updated
795 */
796void
797window_pane_alternate_on(struct window_pane *wp, struct grid_cell *gc)
798{
799 struct screen *s = &wp->base;
800 u_int sx, sy;
801
802 if (wp->saved_grid != NULL)
803 return;
804 if (!options_get_number(&wp->window->options, "alternate-screen"))
805 return;
806 sx = screen_size_x(s);
807 sy = screen_size_y(s);
808
809 wp->saved_grid = grid_create(sx, sy, 0);
810 grid_duplicate_lines(wp->saved_grid, 0, s->grid, screen_hsize(s), sy);
811 wp->saved_cx = s->cx;
812 wp->saved_cy = s->cy;
813 memcpy(&wp->saved_cell, gc, sizeof wp->saved_cell);
814
815 grid_view_clear(s->grid, 0, 0, sx, sy);
816
817 wp->base.grid->flags &= ~GRID_HISTORY;
818
819 wp->flags |= PANE_REDRAW;
820}
821
822/* Exit alternate screen mode and restore the copied grid. */
823void
824window_pane_alternate_off(struct window_pane *wp, struct grid_cell *gc)
825{
826 struct screen *s = &wp->base;
827 u_int sx, sy;
828
829 if (wp->saved_grid == NULL)
830 return;
831 if (!options_get_number(&wp->window->options, "alternate-screen"))
832 return;
833 sx = screen_size_x(s);
834 sy = screen_size_y(s);
835
836 /*
837 * If the current size is bigger, temporarily resize to the old size
838 * before copying back.
839 */
840 if (sy > wp->saved_grid->sy)
841 screen_resize(s, sx, wp->saved_grid->sy);
842
843 /* Restore the grid, cursor position and cell. */
844 grid_duplicate_lines(s->grid, screen_hsize(s), wp->saved_grid, 0, sy);
845 s->cx = wp->saved_cx;
846 if (s->cx > screen_size_x(s) - 1)
847 s->cx = screen_size_x(s) - 1;
848 s->cy = wp->saved_cy;
849 if (s->cy > screen_size_y(s) - 1)
850 s->cy = screen_size_y(s) - 1;
851 memcpy(gc, &wp->saved_cell, sizeof *gc);
852
853 /*
854 * Turn history back on (so resize can use it) and then resize back to
855 * the current size.
856 */
857 wp->base.grid->flags |= GRID_HISTORY;
858 if (sy > wp->saved_grid->sy)
859 screen_resize(s, sx, sy);
860
861 grid_destroy(wp->saved_grid);
862 wp->saved_grid = NULL;
863
864 wp->flags |= PANE_REDRAW;
865}
866
Nicholas Marriott7dc18f62007-12-06 10:04:43 +0000867int
Nicholas Marriott162bacd2009-01-11 23:31:46 +0000868window_pane_set_mode(struct window_pane *wp, const struct window_mode *mode)
Nicholas Marriott7dc18f62007-12-06 10:04:43 +0000869{
870 struct screen *s;
871
Tiago Cunhad29b57f2009-07-22 17:46:53 +0000872 if (wp->mode != NULL)
Nicholas Marriott7dc18f62007-12-06 10:04:43 +0000873 return (1);
Nicholas Marriott162bacd2009-01-11 23:31:46 +0000874 wp->mode = mode;
Nicholas Marriott7dc18f62007-12-06 10:04:43 +0000875
Nicholas Marriott162bacd2009-01-11 23:31:46 +0000876 if ((s = wp->mode->init(wp)) != NULL)
877 wp->screen = s;
Tiago Cunha9ad23472009-10-23 17:41:20 +0000878 wp->flags |= PANE_REDRAW;
Nicholas Marriott7dc18f62007-12-06 10:04:43 +0000879 return (0);
880}
881
882void
Nicholas Marriott162bacd2009-01-11 23:31:46 +0000883window_pane_reset_mode(struct window_pane *wp)
Nicholas Marriott7dc18f62007-12-06 10:04:43 +0000884{
Nicholas Marriott162bacd2009-01-11 23:31:46 +0000885 if (wp->mode == NULL)
Nicholas Marriott7dc18f62007-12-06 10:04:43 +0000886 return;
887
Nicholas Marriott162bacd2009-01-11 23:31:46 +0000888 wp->mode->free(wp);
889 wp->mode = NULL;
Nicholas Marriott7dc18f62007-12-06 10:04:43 +0000890
Nicholas Marriott162bacd2009-01-11 23:31:46 +0000891 wp->screen = &wp->base;
Tiago Cunha9ad23472009-10-23 17:41:20 +0000892 wp->flags |= PANE_REDRAW;
Nicholas Marriott9a6e47c2007-11-21 13:11:41 +0000893}
894
895void
Micah Cowanf11f7172010-05-22 21:56:04 +0000896window_pane_key(struct window_pane *wp, struct session *sess, int key)
Nicholas Marriott9a6e47c2007-11-21 13:11:41 +0000897{
Tiago Cunha9ac062a2009-10-09 13:07:04 +0000898 struct window_pane *wp2;
899
Tiago Cunhacf9804f2009-10-12 00:04:56 +0000900 if (!window_pane_visible(wp))
Nicholas Marriott7eff7f72009-06-25 16:00:25 +0000901 return;
902
Nicholas Marriott44289872009-01-28 19:52:21 +0000903 if (wp->mode != NULL) {
904 if (wp->mode->key != NULL)
Micah Cowanf11f7172010-05-22 21:56:04 +0000905 wp->mode->key(wp, sess, key);
Tiago Cunha9ac062a2009-10-09 13:07:04 +0000906 return;
Tiago Cunhacf9804f2009-10-12 00:04:56 +0000907 }
Tiago Cunha9ac062a2009-10-09 13:07:04 +0000908
Tiago Cunhacf9804f2009-10-12 00:04:56 +0000909 if (wp->fd == -1)
910 return;
Tiago Cunha9ac062a2009-10-09 13:07:04 +0000911 input_key(wp, key);
912 if (options_get_number(&wp->window->options, "synchronize-panes")) {
913 TAILQ_FOREACH(wp2, &wp->window->panes, entry) {
914 if (wp2 == wp || wp2->mode != NULL)
915 continue;
916 if (wp2->fd != -1 && window_pane_visible(wp2))
917 input_key(wp2, key);
918 }
919 }
Nicholas Marriott9a6e47c2007-11-21 13:11:41 +0000920}
Nicholas Marriott44289872009-01-28 19:52:21 +0000921
922void
923window_pane_mouse(
Micah Cowanf11f7172010-05-22 21:56:04 +0000924 struct window_pane *wp, struct session *sess, struct mouse_event *m)
Nicholas Marriott44289872009-01-28 19:52:21 +0000925{
Tiago Cunhacf9804f2009-10-12 00:04:56 +0000926 if (!window_pane_visible(wp))
Nicholas Marriott7eff7f72009-06-25 16:00:25 +0000927 return;
928
Tiago Cunhab26ea842009-10-12 00:18:19 +0000929 if (m->x < wp->xoff || m->x >= wp->xoff + wp->sx)
Nicholas Marriott673290d2009-04-01 18:46:03 +0000930 return;
Tiago Cunhab26ea842009-10-12 00:18:19 +0000931 if (m->y < wp->yoff || m->y >= wp->yoff + wp->sy)
Nicholas Marriott44289872009-01-28 19:52:21 +0000932 return;
Tiago Cunhab26ea842009-10-12 00:18:19 +0000933 m->x -= wp->xoff;
934 m->y -= wp->yoff;
Nicholas Marriott44289872009-01-28 19:52:21 +0000935
936 if (wp->mode != NULL) {
Nicholas Marriott7aafee72011-04-18 22:03:55 +0000937 if (wp->mode->mouse != NULL &&
938 options_get_number(&wp->window->options, "mode-mouse"))
Micah Cowanf11f7172010-05-22 21:56:04 +0000939 wp->mode->mouse(wp, sess, m);
Tiago Cunhacf9804f2009-10-12 00:04:56 +0000940 } else if (wp->fd != -1)
Tiago Cunhab26ea842009-10-12 00:18:19 +0000941 input_mouse(wp, m);
Nicholas Marriott44289872009-01-28 19:52:21 +0000942}
Nicholas Marriotta9e3d5c2009-06-25 16:47:00 +0000943
Nicholas Marriott1e574bb2009-07-15 17:42:44 +0000944int
945window_pane_visible(struct window_pane *wp)
946{
947 struct window *w = wp->window;
948
949 if (wp->xoff >= w->sx || wp->yoff >= w->sy)
950 return (0);
951 if (wp->xoff + wp->sx > w->sx || wp->yoff + wp->sy > w->sy)
952 return (0);
953 return (1);
954}
955
Tiago Cunha80af85a2009-05-19 13:32:55 +0000956char *
Nicholas Marriottf7a9eb42009-06-25 16:04:24 +0000957window_pane_search(struct window_pane *wp, const char *searchstr, u_int *lineno)
Tiago Cunha80af85a2009-05-19 13:32:55 +0000958{
Nicholas Marriott853ad682009-06-25 16:02:37 +0000959 struct screen *s = &wp->base;
Nicholas Marriottf7a9eb42009-06-25 16:04:24 +0000960 char *newsearchstr, *line, *msg;
Nicholas Marriott853ad682009-06-25 16:02:37 +0000961 u_int i;
Tiago Cunha80af85a2009-05-19 13:32:55 +0000962
Nicholas Marriottf7a9eb42009-06-25 16:04:24 +0000963 msg = NULL;
964 xasprintf(&newsearchstr, "*%s*", searchstr);
965
Nicholas Marriott853ad682009-06-25 16:02:37 +0000966 for (i = 0; i < screen_size_y(s); i++) {
967 line = grid_view_string_cells(s->grid, 0, i, screen_size_x(s));
Nicholas Marriottf7a9eb42009-06-25 16:04:24 +0000968 if (fnmatch(newsearchstr, line, 0) == 0) {
969 msg = line;
970 if (lineno != NULL)
971 *lineno = i;
972 break;
973 }
Nicholas Marriott853ad682009-06-25 16:02:37 +0000974 xfree(line);
Tiago Cunha80af85a2009-05-19 13:32:55 +0000975 }
Nicholas Marriottf7a9eb42009-06-25 16:04:24 +0000976
977 xfree(newsearchstr);
978 return (msg);
Tiago Cunha80af85a2009-05-19 13:32:55 +0000979}
Nicholas Marriottaa8f9012010-03-15 22:03:38 +0000980
981/* Find the pane directly above another. */
982struct window_pane *
983window_pane_find_up(struct window_pane *wp)
984{
985 struct window_pane *wp2;
986 u_int left, top;
987
988 if (wp == NULL || !window_pane_visible(wp))
989 return (NULL);
990
991 top = wp->yoff;
992 if (top == 0)
993 top = wp->window->sy + 1;
994 left = wp->xoff;
995
996 TAILQ_FOREACH(wp2, &wp->window->panes, entry) {
997 if (!window_pane_visible(wp2))
998 continue;
999 if (wp2->yoff + wp2->sy + 1 != top)
1000 continue;
1001 if (left >= wp2->xoff && left <= wp2->xoff + wp2->sx)
1002 return (wp2);
1003 }
1004 return (NULL);
1005}
1006
1007/* Find the pane directly below another. */
1008struct window_pane *
1009window_pane_find_down(struct window_pane *wp)
1010{
1011 struct window_pane *wp2;
1012 u_int left, bottom;
1013
1014 if (wp == NULL || !window_pane_visible(wp))
1015 return (NULL);
1016
1017 bottom = wp->yoff + wp->sy + 1;
1018 if (bottom >= wp->window->sy)
1019 bottom = 0;
1020 left = wp->xoff;
1021
1022 TAILQ_FOREACH(wp2, &wp->window->panes, entry) {
1023 if (!window_pane_visible(wp2))
1024 continue;
1025 if (wp2->yoff != bottom)
1026 continue;
1027 if (left >= wp2->xoff && left <= wp2->xoff + wp2->sx)
1028 return (wp2);
1029 }
1030 return (NULL);
1031}
1032
1033/*
1034 * Find the pane directly to the left of another, adjacent to the left side and
1035 * containing the top edge.
1036 */
1037struct window_pane *
1038window_pane_find_left(struct window_pane *wp)
1039{
1040 struct window_pane *wp2;
1041 u_int left, top;
1042
1043 if (wp == NULL || !window_pane_visible(wp))
1044 return (NULL);
1045
1046 left = wp->xoff;
1047 if (left == 0)
1048 left = wp->window->sx + 1;
1049 top = wp->yoff;
1050
1051 TAILQ_FOREACH(wp2, &wp->window->panes, entry) {
1052 if (!window_pane_visible(wp2))
1053 continue;
1054 if (wp2->xoff + wp2->sx + 1 != left)
1055 continue;
1056 if (top >= wp2->yoff && top <= wp2->yoff + wp2->sy)
1057 return (wp2);
1058 }
1059 return (NULL);
1060}
1061
1062/*
1063 * Find the pane directly to the right of another, that is adjacent to the
1064 * right edge and including the top edge.
1065 */
1066struct window_pane *
1067window_pane_find_right(struct window_pane *wp)
1068{
1069 struct window_pane *wp2;
1070 u_int right, top;
1071
1072 if (wp == NULL || !window_pane_visible(wp))
1073 return (NULL);
1074
1075 right = wp->xoff + wp->sx + 1;
1076 if (right >= wp->window->sx)
1077 right = 0;
1078 top = wp->yoff;
1079
1080 TAILQ_FOREACH(wp2, &wp->window->panes, entry) {
1081 if (!window_pane_visible(wp2))
1082 continue;
1083 if (wp2->xoff != right)
1084 continue;
1085 if (top >= wp2->yoff && top <= wp2->yoff + wp2->sy)
1086 return (wp2);
1087 }
1088 return (NULL);
1089}