Nicholas Marriott | fa0f10d | 2011-06-23 19:21:26 +0000 | [diff] [blame] | 1 | /* $Id$ */ |
Nicholas Marriott | a41ece5 | 2007-07-09 19:04:12 +0000 | [diff] [blame] | 2 | |
| 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 Marriott | 4d9af27 | 2009-01-23 16:59:14 +0000 | [diff] [blame] | 22 | #include <errno.h> |
Nicholas Marriott | a41ece5 | 2007-07-09 19:04:12 +0000 | [diff] [blame] | 23 | #include <fcntl.h> |
Nicholas Marriott | f7a9eb4 | 2009-06-25 16:04:24 +0000 | [diff] [blame] | 24 | #include <fnmatch.h> |
Nicholas Marriott | 22d1b94 | 2009-07-01 19:42:55 +0000 | [diff] [blame] | 25 | #include <pwd.h> |
Nicholas Marriott | a41ece5 | 2007-07-09 19:04:12 +0000 | [diff] [blame] | 26 | #include <signal.h> |
| 27 | #include <stdlib.h> |
| 28 | #include <string.h> |
Nicholas Marriott | a41ece5 | 2007-07-09 19:04:12 +0000 | [diff] [blame] | 29 | #include <termios.h> |
| 30 | #include <unistd.h> |
Nicholas Marriott | cf77c80 | 2007-10-19 20:47:09 +0000 | [diff] [blame] | 31 | |
Nicholas Marriott | c8cf438 | 2009-05-13 23:27:00 +0000 | [diff] [blame] | 32 | #include "tmux.h" |
Nicholas Marriott | a41ece5 | 2007-07-09 19:04:12 +0000 | [diff] [blame] | 33 | |
| 34 | /* |
Tiago Cunha | 545893d | 2009-07-20 15:42:05 +0000 | [diff] [blame] | 35 | * Each window is attached to a number of panes, each of which is a pty. This |
Nicholas Marriott | 162bacd | 2009-01-11 23:31:46 +0000 | [diff] [blame] | 36 | * file contains code to handle them. |
Nicholas Marriott | a41ece5 | 2007-07-09 19:04:12 +0000 | [diff] [blame] | 37 | * |
Nicholas Marriott | 162bacd | 2009-01-11 23:31:46 +0000 | [diff] [blame] | 38 | * A pane has two buffers attached, these are filled and emptied by the main |
Nicholas Marriott | b9de906 | 2007-08-27 10:08:44 +0000 | [diff] [blame] | 39 | * server poll loop. Output data is received from pty's in screen format, |
Nicholas Marriott | 35591ec | 2007-11-07 19:41:17 +0000 | [diff] [blame] | 40 | * 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 Marriott | ccfeb31 | 2008-01-02 19:22:21 +0000 | [diff] [blame] | 42 | * directly via input_key. |
Nicholas Marriott | a41ece5 | 2007-07-09 19:04:12 +0000 | [diff] [blame] | 43 | * |
Nicholas Marriott | 162bacd | 2009-01-11 23:31:46 +0000 | [diff] [blame] | 44 | * 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 Marriott | a41ece5 | 2007-07-09 19:04:12 +0000 | [diff] [blame] | 46 | * |
Nicholas Marriott | 4ba3cf6 | 2007-10-26 12:29:07 +0000 | [diff] [blame] | 47 | * Windows are stored directly on a global array and wrapped in any number of |
Nicholas Marriott | 35591ec | 2007-11-07 19:41:17 +0000 | [diff] [blame] | 48 | * winlink structs to be linked onto local session RB trees. A reference count |
Nicholas Marriott | 4ba3cf6 | 2007-10-26 12:29:07 +0000 | [diff] [blame] | 49 | * is maintained and a window removed from the global list and destroyed when |
Nicholas Marriott | 35591ec | 2007-11-07 19:41:17 +0000 | [diff] [blame] | 50 | * it reaches zero. |
Nicholas Marriott | a41ece5 | 2007-07-09 19:04:12 +0000 | [diff] [blame] | 51 | */ |
| 52 | |
| 53 | /* Global window list. */ |
Nicholas Marriott | 4ba3cf6 | 2007-10-26 12:29:07 +0000 | [diff] [blame] | 54 | struct windows windows; |
Tiago Cunha | 2df0882 | 2009-11-08 23:02:56 +0000 | [diff] [blame] | 55 | |
Nicholas Marriott | 536fc24 | 2011-04-06 22:16:33 +0000 | [diff] [blame] | 56 | /* Global panes tree. */ |
| 57 | struct window_pane_tree all_window_panes; |
| 58 | u_int next_window_pane; |
| 59 | |
Tiago Cunha | 2df0882 | 2009-11-08 23:02:56 +0000 | [diff] [blame] | 60 | void window_pane_read_callback(struct bufferevent *, void *); |
| 61 | void window_pane_error_callback(struct bufferevent *, short, void *); |
Nicholas Marriott | 22d1b94 | 2009-07-01 19:42:55 +0000 | [diff] [blame] | 62 | |
Nicholas Marriott | 4ba3cf6 | 2007-10-26 12:29:07 +0000 | [diff] [blame] | 63 | RB_GENERATE(winlinks, winlink, entry, winlink_cmp); |
| 64 | |
| 65 | int |
| 66 | winlink_cmp(struct winlink *wl1, struct winlink *wl2) |
| 67 | { |
| 68 | return (wl1->idx - wl2->idx); |
Nicholas Marriott | 536fc24 | 2011-04-06 22:16:33 +0000 | [diff] [blame] | 69 | } |
| 70 | |
| 71 | RB_GENERATE(window_pane_tree, window_pane, tree_entry, window_pane_cmp); |
| 72 | |
| 73 | int |
| 74 | window_pane_cmp(struct window_pane *wp1, struct window_pane *wp2) |
| 75 | { |
| 76 | return (wp1->id - wp2->id); |
Nicholas Marriott | 4ba3cf6 | 2007-10-26 12:29:07 +0000 | [diff] [blame] | 77 | } |
| 78 | |
| 79 | struct winlink * |
Nicholas Marriott | 8bfbc8c | 2009-07-15 17:45:09 +0000 | [diff] [blame] | 80 | winlink_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 | |
| 92 | struct winlink * |
Nicholas Marriott | 4ba3cf6 | 2007-10-26 12:29:07 +0000 | [diff] [blame] | 93 | winlink_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 | |
| 104 | int |
Tiago Cunha | e61ee94 | 2009-08-16 19:16:27 +0000 | [diff] [blame] | 105 | winlink_next_index(struct winlinks *wwl, int idx) |
Nicholas Marriott | 4ba3cf6 | 2007-10-26 12:29:07 +0000 | [diff] [blame] | 106 | { |
Tiago Cunha | e61ee94 | 2009-08-16 19:16:27 +0000 | [diff] [blame] | 107 | int i; |
Nicholas Marriott | 4ba3cf6 | 2007-10-26 12:29:07 +0000 | [diff] [blame] | 108 | |
Tiago Cunha | e61ee94 | 2009-08-16 19:16:27 +0000 | [diff] [blame] | 109 | i = idx; |
| 110 | do { |
Nicholas Marriott | 4ba3cf6 | 2007-10-26 12:29:07 +0000 | [diff] [blame] | 111 | if (winlink_find_by_index(wwl, i) == NULL) |
| 112 | return (i); |
Tiago Cunha | e61ee94 | 2009-08-16 19:16:27 +0000 | [diff] [blame] | 113 | if (i == INT_MAX) |
| 114 | i = 0; |
| 115 | else |
| 116 | i++; |
| 117 | } while (i != idx); |
| 118 | return (-1); |
Nicholas Marriott | 4ba3cf6 | 2007-10-26 12:29:07 +0000 | [diff] [blame] | 119 | } |
| 120 | |
Nicholas Marriott | fd05d07 | 2009-01-10 14:43:43 +0000 | [diff] [blame] | 121 | u_int |
| 122 | winlink_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 Marriott | 4ba3cf6 | 2007-10-26 12:29:07 +0000 | [diff] [blame] | 134 | struct winlink * |
Tiago Cunha | 4e4568c | 2011-02-15 15:09:52 +0000 | [diff] [blame] | 135 | winlink_add(struct winlinks *wwl, int idx) |
Nicholas Marriott | 4ba3cf6 | 2007-10-26 12:29:07 +0000 | [diff] [blame] | 136 | { |
| 137 | struct winlink *wl; |
| 138 | |
Tiago Cunha | e61ee94 | 2009-08-16 19:16:27 +0000 | [diff] [blame] | 139 | 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 Marriott | 4ba3cf6 | 2007-10-26 12:29:07 +0000 | [diff] [blame] | 143 | return (NULL); |
Nicholas Marriott | 4ba3cf6 | 2007-10-26 12:29:07 +0000 | [diff] [blame] | 144 | |
| 145 | wl = xcalloc(1, sizeof *wl); |
| 146 | wl->idx = idx; |
Nicholas Marriott | 4ba3cf6 | 2007-10-26 12:29:07 +0000 | [diff] [blame] | 147 | RB_INSERT(winlinks, wwl, wl); |
| 148 | |
Nicholas Marriott | 4ba3cf6 | 2007-10-26 12:29:07 +0000 | [diff] [blame] | 149 | return (wl); |
Tiago Cunha | 4e4568c | 2011-02-15 15:09:52 +0000 | [diff] [blame] | 150 | } |
| 151 | |
| 152 | void |
| 153 | winlink_set_window(struct winlink *wl, struct window *w) |
| 154 | { |
| 155 | wl->window = w; |
| 156 | w->references++; |
Nicholas Marriott | 4ba3cf6 | 2007-10-26 12:29:07 +0000 | [diff] [blame] | 157 | } |
| 158 | |
| 159 | void |
| 160 | winlink_remove(struct winlinks *wwl, struct winlink *wl) |
| 161 | { |
| 162 | struct window *w = wl->window; |
| 163 | |
| 164 | RB_REMOVE(winlinks, wwl, wl); |
Tiago Cunha | 7a9bfab | 2009-11-19 22:37:04 +0000 | [diff] [blame] | 165 | if (wl->status_text != NULL) |
| 166 | xfree(wl->status_text); |
Nicholas Marriott | 4ba3cf6 | 2007-10-26 12:29:07 +0000 | [diff] [blame] | 167 | xfree(wl); |
| 168 | |
Tiago Cunha | 4e4568c | 2011-02-15 15:09:52 +0000 | [diff] [blame] | 169 | 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 Marriott | 4ba3cf6 | 2007-10-26 12:29:07 +0000 | [diff] [blame] | 176 | } |
| 177 | |
| 178 | struct winlink * |
Tiago Cunha | c12e0b0 | 2009-11-28 14:50:37 +0000 | [diff] [blame] | 179 | winlink_next(struct winlink *wl) |
Nicholas Marriott | 4ba3cf6 | 2007-10-26 12:29:07 +0000 | [diff] [blame] | 180 | { |
| 181 | return (RB_NEXT(winlinks, wwl, wl)); |
Nicholas Marriott | 103748d | 2007-12-06 09:46:23 +0000 | [diff] [blame] | 182 | } |
Nicholas Marriott | 4ba3cf6 | 2007-10-26 12:29:07 +0000 | [diff] [blame] | 183 | |
| 184 | struct winlink * |
Tiago Cunha | c12e0b0 | 2009-11-28 14:50:37 +0000 | [diff] [blame] | 185 | winlink_previous(struct winlink *wl) |
Nicholas Marriott | 4ba3cf6 | 2007-10-26 12:29:07 +0000 | [diff] [blame] | 186 | { |
Nicholas Marriott | 85d520c | 2008-06-03 18:38:51 +0000 | [diff] [blame] | 187 | return (RB_PREV(winlinks, wwl, wl)); |
Nicholas Marriott | 103748d | 2007-12-06 09:46:23 +0000 | [diff] [blame] | 188 | } |
Nicholas Marriott | 4ba3cf6 | 2007-10-26 12:29:07 +0000 | [diff] [blame] | 189 | |
Tiago Cunha | 8d3b726 | 2010-06-22 23:29:05 +0000 | [diff] [blame] | 190 | struct winlink * |
Tiago Cunha | 11f81e8 | 2010-07-17 14:38:13 +0000 | [diff] [blame] | 191 | winlink_next_by_number(struct winlink *wl, struct session *s, int n) |
Tiago Cunha | 8d3b726 | 2010-06-22 23:29:05 +0000 | [diff] [blame] | 192 | { |
| 193 | for (; n > 0; n--) { |
| 194 | if ((wl = RB_NEXT(winlinks, wwl, wl)) == NULL) |
Tiago Cunha | 11f81e8 | 2010-07-17 14:38:13 +0000 | [diff] [blame] | 195 | wl = RB_MIN(winlinks, &s->windows); |
Tiago Cunha | 8d3b726 | 2010-06-22 23:29:05 +0000 | [diff] [blame] | 196 | } |
| 197 | |
| 198 | return (wl); |
| 199 | } |
| 200 | |
| 201 | struct winlink * |
Tiago Cunha | 11f81e8 | 2010-07-17 14:38:13 +0000 | [diff] [blame] | 202 | winlink_previous_by_number(struct winlink *wl, struct session *s, int n) |
Tiago Cunha | 8d3b726 | 2010-06-22 23:29:05 +0000 | [diff] [blame] | 203 | { |
| 204 | for (; n > 0; n--) { |
| 205 | if ((wl = RB_PREV(winlinks, wwl, wl)) == NULL) |
Tiago Cunha | 11f81e8 | 2010-07-17 14:38:13 +0000 | [diff] [blame] | 206 | wl = RB_MAX(winlinks, &s->windows); |
Tiago Cunha | 8d3b726 | 2010-06-22 23:29:05 +0000 | [diff] [blame] | 207 | } |
| 208 | |
| 209 | return (wl); |
| 210 | } |
| 211 | |
Nicholas Marriott | 46f5e42 | 2008-11-16 10:10:26 +0000 | [diff] [blame] | 212 | void |
| 213 | winlink_stack_push(struct winlink_stack *stack, struct winlink *wl) |
| 214 | { |
| 215 | if (wl == NULL) |
| 216 | return; |
| 217 | |
| 218 | winlink_stack_remove(stack, wl); |
Tiago Cunha | 6a1ebb1 | 2009-10-11 23:38:16 +0000 | [diff] [blame] | 219 | TAILQ_INSERT_HEAD(stack, wl, sentry); |
Nicholas Marriott | 46f5e42 | 2008-11-16 10:10:26 +0000 | [diff] [blame] | 220 | } |
| 221 | |
| 222 | void |
| 223 | winlink_stack_remove(struct winlink_stack *stack, struct winlink *wl) |
| 224 | { |
| 225 | struct winlink *wl2; |
| 226 | |
| 227 | if (wl == NULL) |
| 228 | return; |
Tiago Cunha | cc094fd | 2009-12-04 22:14:47 +0000 | [diff] [blame] | 229 | |
Tiago Cunha | 6a1ebb1 | 2009-10-11 23:38:16 +0000 | [diff] [blame] | 230 | TAILQ_FOREACH(wl2, stack, sentry) { |
Nicholas Marriott | 46f5e42 | 2008-11-16 10:10:26 +0000 | [diff] [blame] | 231 | if (wl2 == wl) { |
Tiago Cunha | 6a1ebb1 | 2009-10-11 23:38:16 +0000 | [diff] [blame] | 232 | TAILQ_REMOVE(stack, wl, sentry); |
Nicholas Marriott | 46f5e42 | 2008-11-16 10:10:26 +0000 | [diff] [blame] | 233 | return; |
| 234 | } |
| 235 | } |
| 236 | } |
| 237 | |
Nicholas Marriott | b4ac8c1 | 2009-01-14 19:29:32 +0000 | [diff] [blame] | 238 | int |
| 239 | window_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 Marriott | a41ece5 | 2007-07-09 19:04:12 +0000 | [diff] [blame] | 248 | struct window * |
Nicholas Marriott | 56f80a5 | 2009-03-07 09:29:54 +0000 | [diff] [blame] | 249 | window_create1(u_int sx, u_int sy) |
Nicholas Marriott | a41ece5 | 2007-07-09 19:04:12 +0000 | [diff] [blame] | 250 | { |
| 251 | struct window *w; |
Nicholas Marriott | b4ac8c1 | 2009-01-14 19:29:32 +0000 | [diff] [blame] | 252 | u_int i; |
Nicholas Marriott | a41ece5 | 2007-07-09 19:04:12 +0000 | [diff] [blame] | 253 | |
Tiago Cunha | ab38d91 | 2009-11-08 23:22:24 +0000 | [diff] [blame] | 254 | w = xcalloc(1, sizeof *w); |
Nicholas Marriott | 4d9af27 | 2009-01-23 16:59:14 +0000 | [diff] [blame] | 255 | w->name = NULL; |
Nicholas Marriott | 0f95671 | 2008-06-04 17:54:27 +0000 | [diff] [blame] | 256 | w->flags = 0; |
Nicholas Marriott | b4ac8c1 | 2009-01-14 19:29:32 +0000 | [diff] [blame] | 257 | |
| 258 | TAILQ_INIT(&w->panes); |
| 259 | w->active = NULL; |
Nicholas Marriott | d90d646 | 2008-06-29 07:04:31 +0000 | [diff] [blame] | 260 | |
Tiago Cunha | d9dcc5e | 2009-07-28 23:04:29 +0000 | [diff] [blame] | 261 | w->lastlayout = -1; |
Tiago Cunha | 545893d | 2009-07-20 15:42:05 +0000 | [diff] [blame] | 262 | w->layout_root = NULL; |
Tiago Cunha | cc094fd | 2009-12-04 22:14:47 +0000 | [diff] [blame] | 263 | |
Nicholas Marriott | 162bacd | 2009-01-11 23:31:46 +0000 | [diff] [blame] | 264 | w->sx = sx; |
| 265 | w->sy = sy; |
Tiago Cunha | ab38d91 | 2009-11-08 23:22:24 +0000 | [diff] [blame] | 266 | |
| 267 | queue_window_name(w); |
Nicholas Marriott | 162bacd | 2009-01-11 23:31:46 +0000 | [diff] [blame] | 268 | |
Nicholas Marriott | 86504af | 2009-07-08 18:01:31 +0000 | [diff] [blame] | 269 | options_init(&w->options, &global_w_options); |
Nicholas Marriott | a41ece5 | 2007-07-09 19:04:12 +0000 | [diff] [blame] | 270 | |
Nicholas Marriott | b4ac8c1 | 2009-01-14 19:29:32 +0000 | [diff] [blame] | 271 | 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 Marriott | 4ba3cf6 | 2007-10-26 12:29:07 +0000 | [diff] [blame] | 279 | w->references = 0; |
Nicholas Marriott | a41ece5 | 2007-07-09 19:04:12 +0000 | [diff] [blame] | 280 | |
Nicholas Marriott | 56f80a5 | 2009-03-07 09:29:54 +0000 | [diff] [blame] | 281 | return (w); |
| 282 | } |
| 283 | |
| 284 | struct window * |
Tiago Cunha | a3a150f | 2009-09-02 01:02:44 +0000 | [diff] [blame] | 285 | window_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 Marriott | 56f80a5 | 2009-03-07 09:29:54 +0000 | [diff] [blame] | 288 | { |
Tiago Cunha | 545893d | 2009-07-20 15:42:05 +0000 | [diff] [blame] | 289 | struct window *w; |
| 290 | struct window_pane *wp; |
Nicholas Marriott | 56f80a5 | 2009-03-07 09:29:54 +0000 | [diff] [blame] | 291 | |
| 292 | w = window_create1(sx, sy); |
Tiago Cunha | 6708ad1 | 2009-07-23 13:10:38 +0000 | [diff] [blame] | 293 | wp = window_add_pane(w, hlimit); |
Tiago Cunha | 545893d | 2009-07-20 15:42:05 +0000 | [diff] [blame] | 294 | layout_init(w); |
Tiago Cunha | a3a150f | 2009-09-02 01:02:44 +0000 | [diff] [blame] | 295 | if (window_pane_spawn(wp, cmd, shell, cwd, env, tio, cause) != 0) { |
Nicholas Marriott | d90d646 | 2008-06-29 07:04:31 +0000 | [diff] [blame] | 296 | window_destroy(w); |
| 297 | return (NULL); |
| 298 | } |
Nicholas Marriott | b4ac8c1 | 2009-01-14 19:29:32 +0000 | [diff] [blame] | 299 | w->active = TAILQ_FIRST(&w->panes); |
Nicholas Marriott | 2d15f59 | 2009-01-20 19:35:03 +0000 | [diff] [blame] | 300 | 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 Marriott | a41ece5 | 2007-07-09 19:04:12 +0000 | [diff] [blame] | 305 | return (w); |
| 306 | } |
| 307 | |
Nicholas Marriott | a41ece5 | 2007-07-09 19:04:12 +0000 | [diff] [blame] | 308 | void |
| 309 | window_destroy(struct window *w) |
| 310 | { |
Nicholas Marriott | 4ba3cf6 | 2007-10-26 12:29:07 +0000 | [diff] [blame] | 311 | u_int i; |
| 312 | |
Nicholas Marriott | b4ac8c1 | 2009-01-14 19:29:32 +0000 | [diff] [blame] | 313 | 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 Cunha | 545893d | 2009-07-20 15:42:05 +0000 | [diff] [blame] | 318 | |
| 319 | if (w->layout_root != NULL) |
| 320 | layout_free(w); |
Tiago Cunha | ab38d91 | 2009-11-08 23:22:24 +0000 | [diff] [blame] | 321 | |
| 322 | evtimer_del(&w->name_timer); |
Nicholas Marriott | 103748d | 2007-12-06 09:46:23 +0000 | [diff] [blame] | 323 | |
Nicholas Marriott | 7a82e86 | 2008-12-08 16:19:51 +0000 | [diff] [blame] | 324 | options_free(&w->options); |
Nicholas Marriott | 9d563c3 | 2007-10-01 14:15:48 +0000 | [diff] [blame] | 325 | |
Nicholas Marriott | b4ac8c1 | 2009-01-14 19:29:32 +0000 | [diff] [blame] | 326 | window_destroy_panes(w); |
Nicholas Marriott | 4d9af27 | 2009-01-23 16:59:14 +0000 | [diff] [blame] | 327 | |
| 328 | if (w->name != NULL) |
| 329 | xfree(w->name); |
Nicholas Marriott | a41ece5 | 2007-07-09 19:04:12 +0000 | [diff] [blame] | 330 | xfree(w); |
| 331 | } |
| 332 | |
Tiago Cunha | d29b57f | 2009-07-22 17:46:53 +0000 | [diff] [blame] | 333 | void |
Nicholas Marriott | a41ece5 | 2007-07-09 19:04:12 +0000 | [diff] [blame] | 334 | window_resize(struct window *w, u_int sx, u_int sy) |
| 335 | { |
Nicholas Marriott | b4ac8c1 | 2009-01-14 19:29:32 +0000 | [diff] [blame] | 336 | w->sx = sx; |
| 337 | w->sy = sy; |
Nicholas Marriott | b4ac8c1 | 2009-01-14 19:29:32 +0000 | [diff] [blame] | 338 | } |
| 339 | |
| 340 | void |
| 341 | window_set_active_pane(struct window *w, struct window_pane *wp) |
| 342 | { |
Nicholas Marriott | 36e537b | 2010-12-06 21:53:50 +0000 | [diff] [blame] | 343 | if (wp == w->active) |
| 344 | return; |
Tiago Cunha | cd079e8 | 2010-10-24 01:34:30 +0000 | [diff] [blame] | 345 | w->last = w->active; |
Nicholas Marriott | b4ac8c1 | 2009-01-14 19:29:32 +0000 | [diff] [blame] | 346 | w->active = wp; |
Nicholas Marriott | 1e574bb | 2009-07-15 17:42:44 +0000 | [diff] [blame] | 347 | while (!window_pane_visible(w->active)) { |
Nicholas Marriott | b4ac8c1 | 2009-01-14 19:29:32 +0000 | [diff] [blame] | 348 | w->active = TAILQ_PREV(w->active, window_panes, entry); |
Nicholas Marriott | 1e574bb | 2009-07-15 17:42:44 +0000 | [diff] [blame] | 349 | if (w->active == NULL) |
| 350 | w->active = TAILQ_LAST(&w->panes, window_panes); |
| 351 | if (w->active == wp) |
| 352 | return; |
| 353 | } |
Nicholas Marriott | b4ac8c1 | 2009-01-14 19:29:32 +0000 | [diff] [blame] | 354 | } |
| 355 | |
Nicholas Marriott | fa0f10d | 2011-06-23 19:21:26 +0000 | [diff] [blame] | 356 | struct window_pane * |
| 357 | window_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 Cunha | ea1721b | 2009-10-11 23:46:02 +0000 | [diff] [blame] | 373 | void |
| 374 | window_set_active_at(struct window *w, u_int x, u_int y) |
| 375 | { |
| 376 | struct window_pane *wp; |
| 377 | |
Nicholas Marriott | fa0f10d | 2011-06-23 19:21:26 +0000 | [diff] [blame] | 378 | wp = window_get_active_at(w, x, y); |
| 379 | if (wp != NULL && wp != w->active) |
Tiago Cunha | ea1721b | 2009-10-11 23:46:02 +0000 | [diff] [blame] | 380 | window_set_active_pane(w, wp); |
Nicholas Marriott | fa0f10d | 2011-06-23 19:21:26 +0000 | [diff] [blame] | 381 | } |
| 382 | |
| 383 | struct window_pane * |
| 384 | window_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 Cunha | ea1721b | 2009-10-11 23:46:02 +0000 | [diff] [blame] | 415 | } |
| 416 | |
Nicholas Marriott | b4ac8c1 | 2009-01-14 19:29:32 +0000 | [diff] [blame] | 417 | struct window_pane * |
Tiago Cunha | 6708ad1 | 2009-07-23 13:10:38 +0000 | [diff] [blame] | 418 | window_add_pane(struct window *w, u_int hlimit) |
Nicholas Marriott | 7cd3cf0 | 2009-01-12 18:22:47 +0000 | [diff] [blame] | 419 | { |
| 420 | struct window_pane *wp; |
Nicholas Marriott | 7cd3cf0 | 2009-01-12 18:22:47 +0000 | [diff] [blame] | 421 | |
Tiago Cunha | 545893d | 2009-07-20 15:42:05 +0000 | [diff] [blame] | 422 | wp = window_pane_create(w, w->sx, w->sy, hlimit); |
Nicholas Marriott | b4ac8c1 | 2009-01-14 19:29:32 +0000 | [diff] [blame] | 423 | 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 Marriott | b4ac8c1 | 2009-01-14 19:29:32 +0000 | [diff] [blame] | 427 | return (wp); |
Nicholas Marriott | 162bacd | 2009-01-11 23:31:46 +0000 | [diff] [blame] | 428 | } |
| 429 | |
Nicholas Marriott | b4ac8c1 | 2009-01-14 19:29:32 +0000 | [diff] [blame] | 430 | void |
Nicholas Marriott | f855591 | 2009-01-13 06:50:10 +0000 | [diff] [blame] | 431 | window_remove_pane(struct window *w, struct window_pane *wp) |
Nicholas Marriott | 162bacd | 2009-01-11 23:31:46 +0000 | [diff] [blame] | 432 | { |
Tiago Cunha | 8703e9f | 2010-10-24 01:32:35 +0000 | [diff] [blame] | 433 | if (wp == w->active) { |
Tiago Cunha | cd079e8 | 2010-10-24 01:34:30 +0000 | [diff] [blame] | 434 | 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 Marriott | f855591 | 2009-01-13 06:50:10 +0000 | [diff] [blame] | 443 | |
Nicholas Marriott | b4ac8c1 | 2009-01-14 19:29:32 +0000 | [diff] [blame] | 444 | TAILQ_REMOVE(&w->panes, wp, entry); |
| 445 | window_pane_destroy(wp); |
Nicholas Marriott | b4ac8c1 | 2009-01-14 19:29:32 +0000 | [diff] [blame] | 446 | } |
| 447 | |
| 448 | struct window_pane * |
| 449 | window_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 Cunha | 11f81e8 | 2010-07-17 14:38:13 +0000 | [diff] [blame] | 463 | struct window_pane * |
| 464 | window_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 | |
| 474 | struct window_pane * |
| 475 | window_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 Marriott | b4ac8c1 | 2009-01-14 19:29:32 +0000 | [diff] [blame] | 486 | u_int |
Tiago Cunha | ae7dda1 | 2009-07-17 18:32:54 +0000 | [diff] [blame] | 487 | window_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 | |
| 501 | u_int |
Nicholas Marriott | b4ac8c1 | 2009-01-14 19:29:32 +0000 | [diff] [blame] | 502 | window_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 | |
| 513 | void |
| 514 | window_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 Marriott | 162bacd | 2009-01-11 23:31:46 +0000 | [diff] [blame] | 523 | } |
| 524 | |
Tiago Cunha | 30f6d9b | 2011-01-07 16:55:40 +0000 | [diff] [blame] | 525 | /* Return list of printable window flag symbols. No flags is just a space. */ |
| 526 | char * |
| 527 | window_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 Marriott | 536fc24 | 2011-04-06 22:16:33 +0000 | [diff] [blame] | 551 | /* Find pane in global tree by id. */ |
| 552 | struct window_pane * |
| 553 | window_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 Marriott | 162bacd | 2009-01-11 23:31:46 +0000 | [diff] [blame] | 561 | struct window_pane * |
| 562 | window_pane_create(struct window *w, u_int sx, u_int sy, u_int hlimit) |
| 563 | { |
| 564 | struct window_pane *wp; |
| 565 | |
Nicholas Marriott | b4ac8c1 | 2009-01-14 19:29:32 +0000 | [diff] [blame] | 566 | wp = xcalloc(1, sizeof *wp); |
Nicholas Marriott | 162bacd | 2009-01-11 23:31:46 +0000 | [diff] [blame] | 567 | wp->window = w; |
Nicholas Marriott | 536fc24 | 2011-04-06 22:16:33 +0000 | [diff] [blame] | 568 | |
| 569 | wp->id = next_window_pane++; |
| 570 | RB_INSERT(window_pane_tree, &all_window_panes, wp); |
Nicholas Marriott | 162bacd | 2009-01-11 23:31:46 +0000 | [diff] [blame] | 571 | |
| 572 | wp->cmd = NULL; |
Tiago Cunha | a3a150f | 2009-09-02 01:02:44 +0000 | [diff] [blame] | 573 | wp->shell = NULL; |
Nicholas Marriott | 162bacd | 2009-01-11 23:31:46 +0000 | [diff] [blame] | 574 | wp->cwd = NULL; |
| 575 | |
| 576 | wp->fd = -1; |
Tiago Cunha | 2df0882 | 2009-11-08 23:02:56 +0000 | [diff] [blame] | 577 | wp->event = NULL; |
Nicholas Marriott | 162bacd | 2009-01-11 23:31:46 +0000 | [diff] [blame] | 578 | |
| 579 | wp->mode = NULL; |
| 580 | |
Tiago Cunha | 545893d | 2009-07-20 15:42:05 +0000 | [diff] [blame] | 581 | wp->layout_cell = NULL; |
| 582 | |
Nicholas Marriott | b6450b1 | 2009-04-01 18:21:42 +0000 | [diff] [blame] | 583 | wp->xoff = 0; |
Tiago Cunha | cc094fd | 2009-12-04 22:14:47 +0000 | [diff] [blame] | 584 | wp->yoff = 0; |
Nicholas Marriott | b6450b1 | 2009-04-01 18:21:42 +0000 | [diff] [blame] | 585 | |
Nicholas Marriott | 7cd3cf0 | 2009-01-12 18:22:47 +0000 | [diff] [blame] | 586 | wp->sx = sx; |
| 587 | wp->sy = sy; |
Nicholas Marriott | 7cd3cf0 | 2009-01-12 18:22:47 +0000 | [diff] [blame] | 588 | |
Tiago Cunha | 6091b05 | 2009-10-12 00:35:08 +0000 | [diff] [blame] | 589 | wp->pipe_fd = -1; |
Tiago Cunha | 6091b05 | 2009-10-12 00:35:08 +0000 | [diff] [blame] | 590 | wp->pipe_off = 0; |
Tiago Cunha | cb0bf6a | 2009-11-08 22:59:53 +0000 | [diff] [blame] | 591 | wp->pipe_event = NULL; |
Tiago Cunha | 6091b05 | 2009-10-12 00:35:08 +0000 | [diff] [blame] | 592 | |
Nicholas Marriott | e63567d | 2009-07-14 06:40:33 +0000 | [diff] [blame] | 593 | wp->saved_grid = NULL; |
| 594 | |
Nicholas Marriott | 162bacd | 2009-01-11 23:31:46 +0000 | [diff] [blame] | 595 | screen_init(&wp->base, sx, sy, hlimit); |
| 596 | wp->screen = &wp->base; |
| 597 | |
| 598 | input_init(wp); |
Nicholas Marriott | 7cd3cf0 | 2009-01-12 18:22:47 +0000 | [diff] [blame] | 599 | |
Nicholas Marriott | 162bacd | 2009-01-11 23:31:46 +0000 | [diff] [blame] | 600 | return (wp); |
| 601 | } |
| 602 | |
| 603 | void |
| 604 | window_pane_destroy(struct window_pane *wp) |
| 605 | { |
Tiago Cunha | 01052ca | 2010-08-29 14:46:13 +0000 | [diff] [blame] | 606 | window_pane_reset_mode(wp); |
| 607 | |
Tiago Cunha | 2df0882 | 2009-11-08 23:02:56 +0000 | [diff] [blame] | 608 | if (wp->fd != -1) { |
Nicholas Marriott | 162bacd | 2009-01-11 23:31:46 +0000 | [diff] [blame] | 609 | close(wp->fd); |
Tiago Cunha | 2df0882 | 2009-11-08 23:02:56 +0000 | [diff] [blame] | 610 | bufferevent_free(wp->event); |
| 611 | } |
Nicholas Marriott | 162bacd | 2009-01-11 23:31:46 +0000 | [diff] [blame] | 612 | |
| 613 | input_free(wp); |
| 614 | |
Nicholas Marriott | 162bacd | 2009-01-11 23:31:46 +0000 | [diff] [blame] | 615 | screen_free(&wp->base); |
Nicholas Marriott | e63567d | 2009-07-14 06:40:33 +0000 | [diff] [blame] | 616 | if (wp->saved_grid != NULL) |
| 617 | grid_destroy(wp->saved_grid); |
Tiago Cunha | 6091b05 | 2009-10-12 00:35:08 +0000 | [diff] [blame] | 618 | |
| 619 | if (wp->pipe_fd != -1) { |
Tiago Cunha | 6091b05 | 2009-10-12 00:35:08 +0000 | [diff] [blame] | 620 | close(wp->pipe_fd); |
Tiago Cunha | cb0bf6a | 2009-11-08 22:59:53 +0000 | [diff] [blame] | 621 | bufferevent_free(wp->pipe_event); |
Tiago Cunha | 6091b05 | 2009-10-12 00:35:08 +0000 | [diff] [blame] | 622 | } |
Nicholas Marriott | 162bacd | 2009-01-11 23:31:46 +0000 | [diff] [blame] | 623 | |
Nicholas Marriott | 536fc24 | 2011-04-06 22:16:33 +0000 | [diff] [blame] | 624 | RB_REMOVE(window_pane_tree, &all_window_panes, wp); |
| 625 | |
Nicholas Marriott | 162bacd | 2009-01-11 23:31:46 +0000 | [diff] [blame] | 626 | if (wp->cwd != NULL) |
| 627 | xfree(wp->cwd); |
Tiago Cunha | a3a150f | 2009-09-02 01:02:44 +0000 | [diff] [blame] | 628 | if (wp->shell != NULL) |
| 629 | xfree(wp->shell); |
Nicholas Marriott | 162bacd | 2009-01-11 23:31:46 +0000 | [diff] [blame] | 630 | if (wp->cmd != NULL) |
| 631 | xfree(wp->cmd); |
| 632 | xfree(wp); |
| 633 | } |
| 634 | |
| 635 | int |
Tiago Cunha | a3a150f | 2009-09-02 01:02:44 +0000 | [diff] [blame] | 636 | window_pane_spawn(struct window_pane *wp, const char *cmd, const char *shell, |
Tiago Cunha | f415d43 | 2009-08-16 18:59:12 +0000 | [diff] [blame] | 637 | const char *cwd, struct environ *env, struct termios *tio, char **cause) |
Nicholas Marriott | 162bacd | 2009-01-11 23:31:46 +0000 | [diff] [blame] | 638 | { |
Nicholas Marriott | 0fc6553 | 2010-04-06 21:59:19 +0000 | [diff] [blame] | 639 | struct winsize ws; |
Nicholas Marriott | 536fc24 | 2011-04-06 22:16:33 +0000 | [diff] [blame] | 640 | char *argv0, paneid[16]; |
Nicholas Marriott | 0fc6553 | 2010-04-06 21:59:19 +0000 | [diff] [blame] | 641 | const char *ptr; |
| 642 | struct termios tio2; |
Nicholas Marriott | 162bacd | 2009-01-11 23:31:46 +0000 | [diff] [blame] | 643 | |
Tiago Cunha | 2df0882 | 2009-11-08 23:02:56 +0000 | [diff] [blame] | 644 | if (wp->fd != -1) { |
Nicholas Marriott | 162bacd | 2009-01-11 23:31:46 +0000 | [diff] [blame] | 645 | close(wp->fd); |
Tiago Cunha | 2df0882 | 2009-11-08 23:02:56 +0000 | [diff] [blame] | 646 | bufferevent_free(wp->event); |
| 647 | } |
Nicholas Marriott | 162bacd | 2009-01-11 23:31:46 +0000 | [diff] [blame] | 648 | if (cmd != NULL) { |
| 649 | if (wp->cmd != NULL) |
| 650 | xfree(wp->cmd); |
| 651 | wp->cmd = xstrdup(cmd); |
Tiago Cunha | a3a150f | 2009-09-02 01:02:44 +0000 | [diff] [blame] | 652 | } |
| 653 | if (shell != NULL) { |
| 654 | if (wp->shell != NULL) |
| 655 | xfree(wp->shell); |
| 656 | wp->shell = xstrdup(shell); |
Nicholas Marriott | 162bacd | 2009-01-11 23:31:46 +0000 | [diff] [blame] | 657 | } |
| 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 Marriott | 2d15f59 | 2009-01-20 19:35:03 +0000 | [diff] [blame] | 667 | |
Tiago Cunha | cc094fd | 2009-12-04 22:14:47 +0000 | [diff] [blame] | 668 | switch (wp->pid = forkpty(&wp->fd, wp->tty, NULL, &ws)) { |
Nicholas Marriott | 162bacd | 2009-01-11 23:31:46 +0000 | [diff] [blame] | 669 | case -1: |
Nicholas Marriott | 4d9af27 | 2009-01-23 16:59:14 +0000 | [diff] [blame] | 670 | wp->fd = -1; |
| 671 | xasprintf(cause, "%s: %s", cmd, strerror(errno)); |
| 672 | return (-1); |
Nicholas Marriott | 162bacd | 2009-01-11 23:31:46 +0000 | [diff] [blame] | 673 | case 0: |
| 674 | if (chdir(wp->cwd) != 0) |
| 675 | chdir("/"); |
Tiago Cunha | 29b1b2f | 2009-08-09 17:48:55 +0000 | [diff] [blame] | 676 | |
Nicholas Marriott | 15b643f | 2009-09-16 12:36:28 +0000 | [diff] [blame] | 677 | 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 Cunha | d4b58c7 | 2010-10-24 00:45:57 +0000 | [diff] [blame] | 685 | closefrom(STDERR_FILENO + 1); |
| 686 | |
Nicholas Marriott | 536fc24 | 2011-04-06 22:16:33 +0000 | [diff] [blame] | 687 | xsnprintf(paneid, sizeof paneid, "%%%u", wp->id); |
| 688 | environ_set(env, "TMUX_PANE", paneid); |
Nicholas Marriott | 0fc6553 | 2010-04-06 21:59:19 +0000 | [diff] [blame] | 689 | environ_push(env); |
Tiago Cunha | 29b1b2f | 2009-08-09 17:48:55 +0000 | [diff] [blame] | 690 | |
Tiago Cunha | 56040be | 2010-08-29 14:42:11 +0000 | [diff] [blame] | 691 | clear_signals(1); |
Nicholas Marriott | 162bacd | 2009-01-11 23:31:46 +0000 | [diff] [blame] | 692 | log_close(); |
| 693 | |
Nicholas Marriott | 22d1b94 | 2009-07-01 19:42:55 +0000 | [diff] [blame] | 694 | if (*wp->cmd != '\0') { |
Tiago Cunha | 5838ee1 | 2009-09-02 01:08:32 +0000 | [diff] [blame] | 695 | /* 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 Marriott | 22d1b94 | 2009-07-01 19:42:55 +0000 | [diff] [blame] | 700 | execl(_PATH_BSHELL, "sh", "-c", wp->cmd, (char *) NULL); |
| 701 | fatal("execl failed"); |
| 702 | } |
| 703 | |
| 704 | /* No command; fork a login shell. */ |
Tiago Cunha | a3a150f | 2009-09-02 01:02:44 +0000 | [diff] [blame] | 705 | ptr = strrchr(wp->shell, '/'); |
| 706 | if (ptr != NULL && *(ptr + 1) != '\0') |
Nicholas Marriott | 22d1b94 | 2009-07-01 19:42:55 +0000 | [diff] [blame] | 707 | xasprintf(&argv0, "-%s", ptr + 1); |
| 708 | else |
Tiago Cunha | a3a150f | 2009-09-02 01:02:44 +0000 | [diff] [blame] | 709 | xasprintf(&argv0, "-%s", wp->shell); |
Tiago Cunha | 5838ee1 | 2009-09-02 01:08:32 +0000 | [diff] [blame] | 710 | setenv("SHELL", wp->shell, 1); |
Tiago Cunha | a3a150f | 2009-09-02 01:02:44 +0000 | [diff] [blame] | 711 | execl(wp->shell, argv0, (char *) NULL); |
Nicholas Marriott | 162bacd | 2009-01-11 23:31:46 +0000 | [diff] [blame] | 712 | fatal("execl failed"); |
| 713 | } |
| 714 | |
Tiago Cunha | 492e3aa | 2011-01-21 23:44:13 +0000 | [diff] [blame] | 715 | setblocking(wp->fd, 0); |
| 716 | |
Tiago Cunha | 2df0882 | 2009-11-08 23:02:56 +0000 | [diff] [blame] | 717 | 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 Marriott | 162bacd | 2009-01-11 23:31:46 +0000 | [diff] [blame] | 720 | |
| 721 | return (0); |
Tiago Cunha | 2df0882 | 2009-11-08 23:02:56 +0000 | [diff] [blame] | 722 | } |
| 723 | |
Tiago Cunha | c12e0b0 | 2009-11-28 14:50:37 +0000 | [diff] [blame] | 724 | /* ARGSUSED */ |
Tiago Cunha | 2df0882 | 2009-11-08 23:02:56 +0000 | [diff] [blame] | 725 | void |
| 726 | window_pane_read_callback(unused struct bufferevent *bufev, void *data) |
| 727 | { |
Nicholas Marriott | 091db41 | 2010-04-06 21:58:33 +0000 | [diff] [blame] | 728 | struct window_pane *wp = data; |
| 729 | char *new_data; |
| 730 | size_t new_size; |
Tiago Cunha | 2df0882 | 2009-11-08 23:02:56 +0000 | [diff] [blame] | 731 | |
Nicholas Marriott | 091db41 | 2010-04-06 21:58:33 +0000 | [diff] [blame] | 732 | 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 Marriott | 3a4f765 | 2010-12-06 22:52:21 +0000 | [diff] [blame] | 741 | |
| 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 Cunha | 2df0882 | 2009-11-08 23:02:56 +0000 | [diff] [blame] | 749 | } |
| 750 | |
Tiago Cunha | c12e0b0 | 2009-11-28 14:50:37 +0000 | [diff] [blame] | 751 | /* ARGSUSED */ |
Tiago Cunha | 2df0882 | 2009-11-08 23:02:56 +0000 | [diff] [blame] | 752 | void |
| 753 | window_pane_error_callback( |
| 754 | unused struct bufferevent *bufev, unused short what, void *data) |
| 755 | { |
| 756 | struct window_pane *wp = data; |
| 757 | |
Tiago Cunha | 72bc03a | 2009-11-14 17:48:39 +0000 | [diff] [blame] | 758 | server_destroy_pane(wp); |
Nicholas Marriott | 162bacd | 2009-01-11 23:31:46 +0000 | [diff] [blame] | 759 | } |
| 760 | |
Tiago Cunha | d29b57f | 2009-07-22 17:46:53 +0000 | [diff] [blame] | 761 | void |
Nicholas Marriott | 162bacd | 2009-01-11 23:31:46 +0000 | [diff] [blame] | 762 | window_pane_resize(struct window_pane *wp, u_int sx, u_int sy) |
| 763 | { |
Nicholas Marriott | a41ece5 | 2007-07-09 19:04:12 +0000 | [diff] [blame] | 764 | struct winsize ws; |
| 765 | |
Nicholas Marriott | 7cd3cf0 | 2009-01-12 18:22:47 +0000 | [diff] [blame] | 766 | if (sx == wp->sx && sy == wp->sy) |
Tiago Cunha | d29b57f | 2009-07-22 17:46:53 +0000 | [diff] [blame] | 767 | return; |
Nicholas Marriott | 7cd3cf0 | 2009-01-12 18:22:47 +0000 | [diff] [blame] | 768 | wp->sx = sx; |
| 769 | wp->sy = sy; |
Nicholas Marriott | 103748d | 2007-12-06 09:46:23 +0000 | [diff] [blame] | 770 | |
Nicholas Marriott | a41ece5 | 2007-07-09 19:04:12 +0000 | [diff] [blame] | 771 | memset(&ws, 0, sizeof ws); |
| 772 | ws.ws_col = sx; |
| 773 | ws.ws_row = sy; |
| 774 | |
Nicholas Marriott | 162bacd | 2009-01-11 23:31:46 +0000 | [diff] [blame] | 775 | screen_resize(&wp->base, sx, sy); |
| 776 | if (wp->mode != NULL) |
| 777 | wp->mode->resize(wp, sx, sy); |
Nicholas Marriott | a41ece5 | 2007-07-09 19:04:12 +0000 | [diff] [blame] | 778 | |
Nicholas Marriott | 162bacd | 2009-01-11 23:31:46 +0000 | [diff] [blame] | 779 | if (wp->fd != -1 && ioctl(wp->fd, TIOCSWINSZ, &ws) == -1) |
Nicholas Marriott | d73516c | 2009-09-23 16:09:12 +0000 | [diff] [blame] | 780 | #ifdef __sun |
Nicholas Marriott | 94e2339 | 2009-07-22 12:42:57 +0000 | [diff] [blame] | 781 | /* |
| 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 Marriott | 4b62b1d | 2007-07-25 23:13:18 +0000 | [diff] [blame] | 789 | fatal("ioctl failed"); |
Nicholas Marriott | a41ece5 | 2007-07-09 19:04:12 +0000 | [diff] [blame] | 790 | } |
| 791 | |
Nicholas Marriott | 9f5b9ba | 2010-03-15 12:51:23 +0000 | [diff] [blame] | 792 | /* |
| 793 | * Enter alternative screen mode. A copy of the visible screen is saved and the |
| 794 | * history is not updated |
| 795 | */ |
| 796 | void |
| 797 | window_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. */ |
| 823 | void |
| 824 | window_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 Marriott | 7dc18f6 | 2007-12-06 10:04:43 +0000 | [diff] [blame] | 867 | int |
Nicholas Marriott | 162bacd | 2009-01-11 23:31:46 +0000 | [diff] [blame] | 868 | window_pane_set_mode(struct window_pane *wp, const struct window_mode *mode) |
Nicholas Marriott | 7dc18f6 | 2007-12-06 10:04:43 +0000 | [diff] [blame] | 869 | { |
| 870 | struct screen *s; |
| 871 | |
Tiago Cunha | d29b57f | 2009-07-22 17:46:53 +0000 | [diff] [blame] | 872 | if (wp->mode != NULL) |
Nicholas Marriott | 7dc18f6 | 2007-12-06 10:04:43 +0000 | [diff] [blame] | 873 | return (1); |
Nicholas Marriott | 162bacd | 2009-01-11 23:31:46 +0000 | [diff] [blame] | 874 | wp->mode = mode; |
Nicholas Marriott | 7dc18f6 | 2007-12-06 10:04:43 +0000 | [diff] [blame] | 875 | |
Nicholas Marriott | 162bacd | 2009-01-11 23:31:46 +0000 | [diff] [blame] | 876 | if ((s = wp->mode->init(wp)) != NULL) |
| 877 | wp->screen = s; |
Tiago Cunha | 9ad2347 | 2009-10-23 17:41:20 +0000 | [diff] [blame] | 878 | wp->flags |= PANE_REDRAW; |
Nicholas Marriott | 7dc18f6 | 2007-12-06 10:04:43 +0000 | [diff] [blame] | 879 | return (0); |
| 880 | } |
| 881 | |
| 882 | void |
Nicholas Marriott | 162bacd | 2009-01-11 23:31:46 +0000 | [diff] [blame] | 883 | window_pane_reset_mode(struct window_pane *wp) |
Nicholas Marriott | 7dc18f6 | 2007-12-06 10:04:43 +0000 | [diff] [blame] | 884 | { |
Nicholas Marriott | 162bacd | 2009-01-11 23:31:46 +0000 | [diff] [blame] | 885 | if (wp->mode == NULL) |
Nicholas Marriott | 7dc18f6 | 2007-12-06 10:04:43 +0000 | [diff] [blame] | 886 | return; |
| 887 | |
Nicholas Marriott | 162bacd | 2009-01-11 23:31:46 +0000 | [diff] [blame] | 888 | wp->mode->free(wp); |
| 889 | wp->mode = NULL; |
Nicholas Marriott | 7dc18f6 | 2007-12-06 10:04:43 +0000 | [diff] [blame] | 890 | |
Nicholas Marriott | 162bacd | 2009-01-11 23:31:46 +0000 | [diff] [blame] | 891 | wp->screen = &wp->base; |
Tiago Cunha | 9ad2347 | 2009-10-23 17:41:20 +0000 | [diff] [blame] | 892 | wp->flags |= PANE_REDRAW; |
Nicholas Marriott | 9a6e47c | 2007-11-21 13:11:41 +0000 | [diff] [blame] | 893 | } |
| 894 | |
| 895 | void |
Micah Cowan | f11f717 | 2010-05-22 21:56:04 +0000 | [diff] [blame] | 896 | window_pane_key(struct window_pane *wp, struct session *sess, int key) |
Nicholas Marriott | 9a6e47c | 2007-11-21 13:11:41 +0000 | [diff] [blame] | 897 | { |
Tiago Cunha | 9ac062a | 2009-10-09 13:07:04 +0000 | [diff] [blame] | 898 | struct window_pane *wp2; |
| 899 | |
Tiago Cunha | cf9804f | 2009-10-12 00:04:56 +0000 | [diff] [blame] | 900 | if (!window_pane_visible(wp)) |
Nicholas Marriott | 7eff7f7 | 2009-06-25 16:00:25 +0000 | [diff] [blame] | 901 | return; |
| 902 | |
Nicholas Marriott | 4428987 | 2009-01-28 19:52:21 +0000 | [diff] [blame] | 903 | if (wp->mode != NULL) { |
| 904 | if (wp->mode->key != NULL) |
Micah Cowan | f11f717 | 2010-05-22 21:56:04 +0000 | [diff] [blame] | 905 | wp->mode->key(wp, sess, key); |
Tiago Cunha | 9ac062a | 2009-10-09 13:07:04 +0000 | [diff] [blame] | 906 | return; |
Tiago Cunha | cf9804f | 2009-10-12 00:04:56 +0000 | [diff] [blame] | 907 | } |
Tiago Cunha | 9ac062a | 2009-10-09 13:07:04 +0000 | [diff] [blame] | 908 | |
Tiago Cunha | cf9804f | 2009-10-12 00:04:56 +0000 | [diff] [blame] | 909 | if (wp->fd == -1) |
| 910 | return; |
Tiago Cunha | 9ac062a | 2009-10-09 13:07:04 +0000 | [diff] [blame] | 911 | 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 Marriott | 9a6e47c | 2007-11-21 13:11:41 +0000 | [diff] [blame] | 920 | } |
Nicholas Marriott | 4428987 | 2009-01-28 19:52:21 +0000 | [diff] [blame] | 921 | |
| 922 | void |
| 923 | window_pane_mouse( |
Micah Cowan | f11f717 | 2010-05-22 21:56:04 +0000 | [diff] [blame] | 924 | struct window_pane *wp, struct session *sess, struct mouse_event *m) |
Nicholas Marriott | 4428987 | 2009-01-28 19:52:21 +0000 | [diff] [blame] | 925 | { |
Tiago Cunha | cf9804f | 2009-10-12 00:04:56 +0000 | [diff] [blame] | 926 | if (!window_pane_visible(wp)) |
Nicholas Marriott | 7eff7f7 | 2009-06-25 16:00:25 +0000 | [diff] [blame] | 927 | return; |
| 928 | |
Tiago Cunha | b26ea84 | 2009-10-12 00:18:19 +0000 | [diff] [blame] | 929 | if (m->x < wp->xoff || m->x >= wp->xoff + wp->sx) |
Nicholas Marriott | 673290d | 2009-04-01 18:46:03 +0000 | [diff] [blame] | 930 | return; |
Tiago Cunha | b26ea84 | 2009-10-12 00:18:19 +0000 | [diff] [blame] | 931 | if (m->y < wp->yoff || m->y >= wp->yoff + wp->sy) |
Nicholas Marriott | 4428987 | 2009-01-28 19:52:21 +0000 | [diff] [blame] | 932 | return; |
Tiago Cunha | b26ea84 | 2009-10-12 00:18:19 +0000 | [diff] [blame] | 933 | m->x -= wp->xoff; |
| 934 | m->y -= wp->yoff; |
Nicholas Marriott | 4428987 | 2009-01-28 19:52:21 +0000 | [diff] [blame] | 935 | |
| 936 | if (wp->mode != NULL) { |
Nicholas Marriott | 7aafee7 | 2011-04-18 22:03:55 +0000 | [diff] [blame] | 937 | if (wp->mode->mouse != NULL && |
| 938 | options_get_number(&wp->window->options, "mode-mouse")) |
Micah Cowan | f11f717 | 2010-05-22 21:56:04 +0000 | [diff] [blame] | 939 | wp->mode->mouse(wp, sess, m); |
Tiago Cunha | cf9804f | 2009-10-12 00:04:56 +0000 | [diff] [blame] | 940 | } else if (wp->fd != -1) |
Tiago Cunha | b26ea84 | 2009-10-12 00:18:19 +0000 | [diff] [blame] | 941 | input_mouse(wp, m); |
Nicholas Marriott | 4428987 | 2009-01-28 19:52:21 +0000 | [diff] [blame] | 942 | } |
Nicholas Marriott | a9e3d5c | 2009-06-25 16:47:00 +0000 | [diff] [blame] | 943 | |
Nicholas Marriott | 1e574bb | 2009-07-15 17:42:44 +0000 | [diff] [blame] | 944 | int |
| 945 | window_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 Cunha | 80af85a | 2009-05-19 13:32:55 +0000 | [diff] [blame] | 956 | char * |
Nicholas Marriott | f7a9eb4 | 2009-06-25 16:04:24 +0000 | [diff] [blame] | 957 | window_pane_search(struct window_pane *wp, const char *searchstr, u_int *lineno) |
Tiago Cunha | 80af85a | 2009-05-19 13:32:55 +0000 | [diff] [blame] | 958 | { |
Nicholas Marriott | 853ad68 | 2009-06-25 16:02:37 +0000 | [diff] [blame] | 959 | struct screen *s = &wp->base; |
Nicholas Marriott | f7a9eb4 | 2009-06-25 16:04:24 +0000 | [diff] [blame] | 960 | char *newsearchstr, *line, *msg; |
Nicholas Marriott | 853ad68 | 2009-06-25 16:02:37 +0000 | [diff] [blame] | 961 | u_int i; |
Tiago Cunha | 80af85a | 2009-05-19 13:32:55 +0000 | [diff] [blame] | 962 | |
Nicholas Marriott | f7a9eb4 | 2009-06-25 16:04:24 +0000 | [diff] [blame] | 963 | msg = NULL; |
| 964 | xasprintf(&newsearchstr, "*%s*", searchstr); |
| 965 | |
Nicholas Marriott | 853ad68 | 2009-06-25 16:02:37 +0000 | [diff] [blame] | 966 | for (i = 0; i < screen_size_y(s); i++) { |
| 967 | line = grid_view_string_cells(s->grid, 0, i, screen_size_x(s)); |
Nicholas Marriott | f7a9eb4 | 2009-06-25 16:04:24 +0000 | [diff] [blame] | 968 | if (fnmatch(newsearchstr, line, 0) == 0) { |
| 969 | msg = line; |
| 970 | if (lineno != NULL) |
| 971 | *lineno = i; |
| 972 | break; |
| 973 | } |
Nicholas Marriott | 853ad68 | 2009-06-25 16:02:37 +0000 | [diff] [blame] | 974 | xfree(line); |
Tiago Cunha | 80af85a | 2009-05-19 13:32:55 +0000 | [diff] [blame] | 975 | } |
Nicholas Marriott | f7a9eb4 | 2009-06-25 16:04:24 +0000 | [diff] [blame] | 976 | |
| 977 | xfree(newsearchstr); |
| 978 | return (msg); |
Tiago Cunha | 80af85a | 2009-05-19 13:32:55 +0000 | [diff] [blame] | 979 | } |
Nicholas Marriott | aa8f901 | 2010-03-15 22:03:38 +0000 | [diff] [blame] | 980 | |
| 981 | /* Find the pane directly above another. */ |
| 982 | struct window_pane * |
| 983 | window_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. */ |
| 1008 | struct window_pane * |
| 1009 | window_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 | */ |
| 1037 | struct window_pane * |
| 1038 | window_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 | */ |
| 1066 | struct window_pane * |
| 1067 | window_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 | } |