Line | Count | Source |
1 | | /* $OpenBSD: window-panes.c,v 1.4 2026/07/29 14:06:32 nicm Exp $ */ |
2 | | |
3 | | /* |
4 | | * Copyright (c) 2026 Nicholas Marriott <nicholas.marriott@gmail.com> |
5 | | * |
6 | | * Permission to use, copy, modify, and distribute this software for any |
7 | | * purpose with or without fee is hereby granted, provided that the above |
8 | | * copyright notice and this permission notice appear in all copies. |
9 | | * |
10 | | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
11 | | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
12 | | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY |
13 | | * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
14 | | * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER IN AN |
15 | | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN |
16 | | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
17 | | */ |
18 | | |
19 | | #include <sys/types.h> |
20 | | |
21 | | #include <stdlib.h> |
22 | | #include <string.h> |
23 | | |
24 | | #include "tmux.h" |
25 | | |
26 | | static struct screen *window_panes_init(struct window_mode_entry *, |
27 | | struct cmdq_item *, struct cmd_find_state *, |
28 | | struct args *); |
29 | | static void window_panes_free(struct window_mode_entry *); |
30 | | static void window_panes_resize(struct window_mode_entry *, u_int, |
31 | | u_int); |
32 | | static void window_panes_key(struct window_mode_entry *, |
33 | | struct client *, struct session *, |
34 | | struct winlink *, key_code, struct mouse_event *); |
35 | | |
36 | | const struct window_mode window_panes_mode = { |
37 | | .name = "panes-mode", |
38 | | .flags = WINDOW_MODE_HIDE_PANE_STATUS|WINDOW_MODE_NO_STACK| |
39 | | WINDOW_MODE_FILL_WINDOW|WINDOW_MODE_HIDE_SCROLLBARS, |
40 | | |
41 | | .init = window_panes_init, |
42 | | .free = window_panes_free, |
43 | | .resize = window_panes_resize, |
44 | | .key = window_panes_key, |
45 | | }; |
46 | | |
47 | | struct window_panes_area { |
48 | | u_int id; |
49 | | u_int x; |
50 | | u_int y; |
51 | | u_int sx; |
52 | | u_int sy; |
53 | | }; |
54 | | |
55 | | struct window_panes_modedata { |
56 | | struct window_pane *wp; |
57 | | struct session *session; |
58 | | u_int source_session; |
59 | | u_int source_window; |
60 | | struct screen screen; |
61 | | struct screen *preview; |
62 | | |
63 | | struct event timer; |
64 | | |
65 | | struct args_command_state *state; |
66 | | u_int delay; |
67 | | int ignore_keys; |
68 | | int zoomed; |
69 | | |
70 | | struct window_panes_area *areas; |
71 | | u_int areas_size; |
72 | | }; |
73 | | |
74 | 0 | #define WINDOW_PANES_BORDER_L 0x1 |
75 | 0 | #define WINDOW_PANES_BORDER_R 0x2 |
76 | 0 | #define WINDOW_PANES_BORDER_U 0x4 |
77 | 0 | #define WINDOW_PANES_BORDER_D 0x8 |
78 | | |
79 | | static int |
80 | | window_panes_get_source(struct window_panes_modedata *data, struct session **sp, |
81 | | struct winlink **wlp, struct window **wp) |
82 | 0 | { |
83 | 0 | struct session *s; |
84 | 0 | struct window *w; |
85 | 0 | struct winlink *wl = NULL; |
86 | |
|
87 | 0 | w = window_find_by_id(data->source_window); |
88 | 0 | if (w == NULL) |
89 | 0 | return (0); |
90 | | |
91 | 0 | s = session_find_by_id(data->source_session); |
92 | 0 | if (s != NULL) |
93 | 0 | wl = winlink_find_by_window(&s->windows, w); |
94 | 0 | if (wl == NULL) |
95 | 0 | s = data->session; |
96 | 0 | if (s != NULL) |
97 | 0 | wl = winlink_find_by_window(&s->windows, w); |
98 | |
|
99 | 0 | if (sp != NULL) |
100 | 0 | *sp = s; |
101 | 0 | if (wlp != NULL) |
102 | 0 | *wlp = wl; |
103 | 0 | if (wp != NULL) |
104 | 0 | *wp = w; |
105 | 0 | return (1); |
106 | 0 | } |
107 | | |
108 | | static void |
109 | | window_panes_set_preview(struct window_panes_modedata *data) |
110 | 0 | { |
111 | 0 | struct window_pane *wp = data->wp; |
112 | 0 | struct screen *src = &wp->base, *dst; |
113 | 0 | struct screen_write_ctx ctx; |
114 | 0 | u_int sx = screen_size_x(src), sy = screen_size_y(src); |
115 | |
|
116 | 0 | data->preview = dst = xmalloc(sizeof *data->preview); |
117 | 0 | screen_init(dst, sx, sy, 0); |
118 | 0 | screen_write_start(&ctx, dst); |
119 | 0 | screen_write_fast_copy(&ctx, src, 0, src->grid->hsize, sx, sy); |
120 | 0 | screen_write_stop(&ctx); |
121 | 0 | dst->mode = src->mode; |
122 | 0 | dst->cx = src->cx; |
123 | 0 | dst->cy = src->cy; |
124 | 0 | } |
125 | | |
126 | | static void |
127 | | window_panes_free_areas(struct window_panes_modedata *data) |
128 | 0 | { |
129 | 0 | free(data->areas); |
130 | 0 | data->areas = NULL; |
131 | 0 | data->areas_size = 0; |
132 | 0 | } |
133 | | |
134 | | static void |
135 | | window_panes_add_area(struct window_panes_modedata *data, |
136 | | struct window_pane *wp, u_int x, u_int y, u_int sx, u_int sy) |
137 | 0 | { |
138 | 0 | struct window_panes_area *area; |
139 | |
|
140 | 0 | data->areas = xreallocarray(data->areas, data->areas_size + 1, |
141 | 0 | sizeof *data->areas); |
142 | 0 | area = &data->areas[data->areas_size++]; |
143 | 0 | area->id = wp->id; |
144 | 0 | area->x = x; |
145 | 0 | area->y = y; |
146 | 0 | area->sx = sx; |
147 | 0 | area->sy = sy; |
148 | 0 | } |
149 | | |
150 | | static int |
151 | | window_panes_pane_floating(struct window_pane *wp) |
152 | 0 | { |
153 | 0 | struct layout_cell *lc = wp->saved_layout_cell; |
154 | |
|
155 | 0 | if (lc == NULL) |
156 | 0 | lc = wp->layout_cell; |
157 | 0 | if (lc == NULL || (~lc->flags & LAYOUT_CELL_FLOATING)) |
158 | 0 | return (0); |
159 | 0 | return (1); |
160 | 0 | } |
161 | | |
162 | | static int |
163 | | window_panes_pane_visible(struct window_pane *wp) |
164 | 0 | { |
165 | 0 | if (wp->saved_layout_cell != NULL) |
166 | 0 | return (1); |
167 | 0 | return (window_pane_is_visible(wp)); |
168 | 0 | } |
169 | | |
170 | | static int |
171 | | window_panes_get_geometry(struct window_pane *wp, struct layout_cell *root, |
172 | | u_int osx, u_int osy, u_int dsx, u_int dsy, u_int *xp, u_int *yp, |
173 | | u_int *sxp, u_int *syp) |
174 | 0 | { |
175 | 0 | struct layout_cell *lc = wp->saved_layout_cell; |
176 | 0 | int status; |
177 | 0 | u_int x, y, sx, sy, x2, y2; |
178 | |
|
179 | 0 | if (lc == NULL) |
180 | 0 | lc = wp->layout_cell; |
181 | 0 | if (lc == NULL || osx == 0 || osy == 0 || dsx == 0 || dsy == 0) |
182 | 0 | return (0); |
183 | | |
184 | 0 | if (osx <= dsx && osy <= dsy) { |
185 | 0 | x = lc->g.xoff; |
186 | 0 | y = lc->g.yoff; |
187 | 0 | x2 = x + lc->g.sx; |
188 | 0 | y2 = y + lc->g.sy; |
189 | 0 | } else { |
190 | 0 | x = (u_int)lc->g.xoff * dsx / osx; |
191 | 0 | y = (u_int)lc->g.yoff * dsy / osy; |
192 | 0 | x2 = ((u_int)lc->g.xoff + lc->g.sx) * dsx / osx; |
193 | 0 | y2 = ((u_int)lc->g.yoff + lc->g.sy) * dsy / osy; |
194 | 0 | } |
195 | |
|
196 | 0 | if (x >= dsx || y >= dsy) |
197 | 0 | return (0); |
198 | 0 | if (x2 <= x) |
199 | 0 | x2 = x + 1; |
200 | 0 | if (y2 <= y) |
201 | 0 | y2 = y + 1; |
202 | 0 | if (x2 > dsx) |
203 | 0 | x2 = dsx; |
204 | 0 | if (y2 > dsy) |
205 | 0 | y2 = dsy; |
206 | |
|
207 | 0 | sx = x2 - x; |
208 | 0 | sy = y2 - y; |
209 | 0 | if (sx == 0 || sy == 0) |
210 | 0 | return (0); |
211 | | |
212 | 0 | status = window_get_pane_status(wp->window); |
213 | 0 | if (layout_add_horizontal_border(root, lc, status) && sy > 1) { |
214 | 0 | if (status == PANE_STATUS_TOP) |
215 | 0 | y++; |
216 | 0 | sy--; |
217 | 0 | } |
218 | |
|
219 | 0 | *xp = x; |
220 | 0 | *yp = y; |
221 | 0 | *sxp = sx; |
222 | 0 | *syp = sy; |
223 | 0 | return (1); |
224 | 0 | } |
225 | | |
226 | | static void |
227 | | window_panes_get_border_cell(struct window_panes_modedata *data, |
228 | | struct grid_cell *gc) |
229 | 0 | { |
230 | 0 | struct format_tree *ft; |
231 | 0 | struct window_pane *wp = data->wp; |
232 | 0 | struct session *s = data->session; |
233 | |
|
234 | 0 | memcpy(gc, &grid_default_cell, sizeof *gc); |
235 | 0 | ft = format_create_defaults(NULL, NULL, s, s->curw, wp); |
236 | 0 | style_apply(gc, wp->window->options, "display-panes-border-style", ft); |
237 | 0 | format_free(ft); |
238 | 0 | } |
239 | | |
240 | | static int |
241 | | window_panes_map_x(u_int x, u_int osx, u_int dsx) |
242 | 0 | { |
243 | 0 | if (osx <= dsx) |
244 | 0 | return (x); |
245 | 0 | return (x * dsx / osx); |
246 | 0 | } |
247 | | |
248 | | static int |
249 | | window_panes_map_y(u_int y, u_int osy, u_int dsy) |
250 | 0 | { |
251 | 0 | if (osy <= dsy) |
252 | 0 | return (y); |
253 | 0 | return (y * dsy / osy); |
254 | 0 | } |
255 | | |
256 | | static struct layout_cell * |
257 | | window_panes_next_tiled_cell(struct layout_cell *lc) |
258 | 0 | { |
259 | 0 | struct layout_cell *next; |
260 | |
|
261 | 0 | next = TAILQ_NEXT(lc, entry); |
262 | 0 | while (next != NULL) { |
263 | 0 | if (~next->flags & LAYOUT_CELL_FLOATING) |
264 | 0 | return (next); |
265 | 0 | next = TAILQ_NEXT(next, entry); |
266 | 0 | } |
267 | 0 | return (NULL); |
268 | 0 | } |
269 | | |
270 | | static void |
271 | | window_panes_mark_border(u_char *map, u_int dsx, u_int dsy, u_int x, u_int y, |
272 | | u_char mask) |
273 | 0 | { |
274 | 0 | if (x < dsx && y < dsy) |
275 | 0 | map[y * dsx + x] |= mask; |
276 | 0 | } |
277 | | |
278 | | static void |
279 | | window_panes_mark_vline(u_char *map, u_int dsx, u_int dsy, int x, int y, int y2) |
280 | 0 | { |
281 | 0 | u_char mask; |
282 | 0 | int yy; |
283 | |
|
284 | 0 | if (x < 0 || (u_int)x >= dsx || y2 <= y) |
285 | 0 | return; |
286 | 0 | if (y < 0) |
287 | 0 | y = 0; |
288 | 0 | if ((u_int)y2 > dsy) |
289 | 0 | y2 = dsy; |
290 | |
|
291 | 0 | for (yy = y; yy < y2; yy++) { |
292 | 0 | mask = 0; |
293 | 0 | if (yy > y) |
294 | 0 | mask |= WINDOW_PANES_BORDER_U; |
295 | 0 | if (yy + 1 < y2) |
296 | 0 | mask |= WINDOW_PANES_BORDER_D; |
297 | 0 | if (mask == 0) |
298 | 0 | mask = WINDOW_PANES_BORDER_U|WINDOW_PANES_BORDER_D; |
299 | 0 | window_panes_mark_border(map, dsx, dsy, x, yy, mask); |
300 | 0 | } |
301 | 0 | } |
302 | | |
303 | | static void |
304 | | window_panes_mark_hline(u_char *map, u_int dsx, u_int dsy, int x, int x2, int y) |
305 | 0 | { |
306 | 0 | u_char mask; |
307 | 0 | int xx; |
308 | |
|
309 | 0 | if (y < 0 || (u_int)y >= dsy || x2 <= x) |
310 | 0 | return; |
311 | 0 | if (x < 0) |
312 | 0 | x = 0; |
313 | 0 | if ((u_int)x2 > dsx) |
314 | 0 | x2 = dsx; |
315 | |
|
316 | 0 | for (xx = x; xx < x2; xx++) { |
317 | 0 | mask = 0; |
318 | 0 | if (xx > x) |
319 | 0 | mask |= WINDOW_PANES_BORDER_L; |
320 | 0 | if (xx + 1 < x2) |
321 | 0 | mask |= WINDOW_PANES_BORDER_R; |
322 | 0 | if (mask == 0) |
323 | 0 | mask = WINDOW_PANES_BORDER_L|WINDOW_PANES_BORDER_R; |
324 | 0 | window_panes_mark_border(map, dsx, dsy, xx, y, mask); |
325 | 0 | } |
326 | 0 | } |
327 | | |
328 | | static void |
329 | | window_panes_mark_borders_cell(u_char *map, struct layout_cell *lc, u_int osx, |
330 | | u_int osy, u_int dsx, u_int dsy) |
331 | 0 | { |
332 | 0 | struct layout_cell *lcchild, *lcnext; |
333 | 0 | int x, y, x2, y2; |
334 | |
|
335 | 0 | if (lc->type == LAYOUT_WINDOWPANE) |
336 | 0 | return; |
337 | | |
338 | 0 | TAILQ_FOREACH(lcchild, &lc->cells, entry) { |
339 | 0 | window_panes_mark_borders_cell(map, lcchild, osx, osy, dsx, |
340 | 0 | dsy); |
341 | 0 | if (lcchild->flags & LAYOUT_CELL_FLOATING) |
342 | 0 | continue; |
343 | 0 | lcnext = window_panes_next_tiled_cell(lcchild); |
344 | 0 | if (lcnext == NULL) |
345 | 0 | continue; |
346 | | |
347 | 0 | if (lc->type == LAYOUT_LEFTRIGHT) { |
348 | 0 | x = window_panes_map_x(lcchild->g.xoff + lcchild->g.sx, |
349 | 0 | osx, dsx); |
350 | 0 | y = window_panes_map_y(lc->g.yoff, osy, dsy); |
351 | 0 | y2 = window_panes_map_y(lc->g.yoff + lc->g.sy, osy, |
352 | 0 | dsy); |
353 | 0 | window_panes_mark_vline(map, dsx, dsy, x, y, y2); |
354 | 0 | } else { |
355 | 0 | x = window_panes_map_x(lc->g.xoff, osx, dsx); |
356 | 0 | x2 = window_panes_map_x(lc->g.xoff + lc->g.sx, osx, |
357 | 0 | dsx); |
358 | 0 | y = window_panes_map_y(lcchild->g.yoff + lcchild->g.sy, |
359 | 0 | osy, dsy); |
360 | 0 | window_panes_mark_hline(map, dsx, dsy, x, x2, y); |
361 | 0 | } |
362 | 0 | } |
363 | 0 | } |
364 | | |
365 | | static void |
366 | | window_panes_mark_pane_status_borders(u_char *map, struct window *w, |
367 | | struct layout_cell *root, u_int osx, u_int osy, u_int dsx, u_int dsy) |
368 | 0 | { |
369 | 0 | struct window_pane *wp; |
370 | 0 | struct layout_cell *lc; |
371 | 0 | int status, x, y, x2, y2; |
372 | |
|
373 | 0 | status = window_get_pane_status(w); |
374 | 0 | if (status != PANE_STATUS_TOP && status != PANE_STATUS_BOTTOM) |
375 | 0 | return; |
376 | | |
377 | 0 | TAILQ_FOREACH(wp, &w->panes, entry) { |
378 | 0 | if (!window_panes_pane_visible(wp)) |
379 | 0 | continue; |
380 | | |
381 | 0 | lc = wp->saved_layout_cell; |
382 | 0 | if (lc == NULL) |
383 | 0 | lc = wp->layout_cell; |
384 | 0 | if (lc == NULL || |
385 | 0 | !layout_add_horizontal_border(root, lc, status)) |
386 | 0 | continue; |
387 | | |
388 | 0 | x = window_panes_map_x(lc->g.xoff, osx, dsx); |
389 | 0 | x2 = window_panes_map_x(lc->g.xoff + lc->g.sx, osx, dsx); |
390 | 0 | if (status == PANE_STATUS_TOP) |
391 | 0 | y = window_panes_map_y(lc->g.yoff, osy, dsy); |
392 | 0 | else { |
393 | 0 | y2 = window_panes_map_y(lc->g.yoff + lc->g.sy, osy, |
394 | 0 | dsy); |
395 | 0 | y = y2 - 1; |
396 | 0 | } |
397 | 0 | window_panes_mark_hline(map, dsx, dsy, x, x2, y); |
398 | 0 | } |
399 | 0 | } |
400 | | |
401 | | static int |
402 | | window_panes_get_floating_borders(struct window_pane *wp, u_int osx, u_int osy, |
403 | | u_int dsx, u_int dsy, int *xp, int *yp, int *x2p, int *y2p) |
404 | 0 | { |
405 | 0 | struct layout_cell *lc; |
406 | |
|
407 | 0 | lc = wp->saved_layout_cell; |
408 | 0 | if (lc == NULL) |
409 | 0 | lc = wp->layout_cell; |
410 | 0 | if (lc == NULL || (~lc->flags & LAYOUT_CELL_FLOATING)) |
411 | 0 | return (0); |
412 | | |
413 | 0 | if (lc->g.xoff == 0) |
414 | 0 | *xp = -1; |
415 | 0 | else |
416 | 0 | *xp = window_panes_map_x(lc->g.xoff - 1, osx, dsx); |
417 | 0 | if (lc->g.yoff == 0) |
418 | 0 | *yp = -1; |
419 | 0 | else |
420 | 0 | *yp = window_panes_map_y(lc->g.yoff - 1, osy, dsy); |
421 | 0 | *x2p = window_panes_map_x(lc->g.xoff + lc->g.sx, osx, dsx); |
422 | 0 | *y2p = window_panes_map_y(lc->g.yoff + lc->g.sy, osy, dsy); |
423 | 0 | return (1); |
424 | 0 | } |
425 | | |
426 | | static int |
427 | | window_panes_clip_floating_pane(struct window_pane *wp, u_int osx, u_int osy, |
428 | | u_int dsx, u_int dsy, u_int *xp, u_int *yp, u_int *sxp, u_int *syp) |
429 | 0 | { |
430 | 0 | int x, y, x2, y2, bx, by, bx2, by2; |
431 | |
|
432 | 0 | if (!window_panes_get_floating_borders(wp, osx, osy, dsx, dsy, &x, &y, |
433 | 0 | &x2, &y2)) |
434 | 0 | return (1); |
435 | | |
436 | 0 | bx = *xp; |
437 | 0 | by = *yp; |
438 | 0 | bx2 = bx + *sxp - 1; |
439 | 0 | by2 = by + *syp - 1; |
440 | |
|
441 | 0 | if (x >= 0 && bx <= x) |
442 | 0 | bx = x + 1; |
443 | 0 | if (y >= 0 && by <= y) |
444 | 0 | by = y + 1; |
445 | 0 | if ((u_int)x2 < dsx && bx2 >= x2) |
446 | 0 | bx2 = x2 - 1; |
447 | 0 | if ((u_int)y2 < dsy && by2 >= y2) |
448 | 0 | by2 = y2 - 1; |
449 | 0 | if (bx2 < bx || by2 < by) |
450 | 0 | return (0); |
451 | | |
452 | 0 | *xp = bx; |
453 | 0 | *yp = by; |
454 | 0 | *sxp = bx2 - bx + 1; |
455 | 0 | *syp = by2 - by + 1; |
456 | 0 | return (1); |
457 | 0 | } |
458 | | |
459 | | static int |
460 | | window_panes_border_cell_type(u_char mask) |
461 | 0 | { |
462 | 0 | switch (mask) { |
463 | 0 | case WINDOW_PANES_BORDER_L|WINDOW_PANES_BORDER_R| |
464 | 0 | WINDOW_PANES_BORDER_U|WINDOW_PANES_BORDER_D: |
465 | 0 | return (CELL_LRUD); |
466 | 0 | case WINDOW_PANES_BORDER_L|WINDOW_PANES_BORDER_R|WINDOW_PANES_BORDER_U: |
467 | 0 | return (CELL_LRU); |
468 | 0 | case WINDOW_PANES_BORDER_L|WINDOW_PANES_BORDER_R|WINDOW_PANES_BORDER_D: |
469 | 0 | return (CELL_LRD); |
470 | 0 | case WINDOW_PANES_BORDER_L|WINDOW_PANES_BORDER_R: |
471 | 0 | case WINDOW_PANES_BORDER_L: |
472 | 0 | case WINDOW_PANES_BORDER_R: |
473 | 0 | return (CELL_LR); |
474 | 0 | case WINDOW_PANES_BORDER_L|WINDOW_PANES_BORDER_U|WINDOW_PANES_BORDER_D: |
475 | 0 | return (CELL_ULD); |
476 | 0 | case WINDOW_PANES_BORDER_L|WINDOW_PANES_BORDER_U: |
477 | 0 | return (CELL_LU); |
478 | 0 | case WINDOW_PANES_BORDER_L|WINDOW_PANES_BORDER_D: |
479 | 0 | return (CELL_LD); |
480 | 0 | case WINDOW_PANES_BORDER_R|WINDOW_PANES_BORDER_U|WINDOW_PANES_BORDER_D: |
481 | 0 | return (CELL_URD); |
482 | 0 | case WINDOW_PANES_BORDER_R|WINDOW_PANES_BORDER_U: |
483 | 0 | return (CELL_RU); |
484 | 0 | case WINDOW_PANES_BORDER_R|WINDOW_PANES_BORDER_D: |
485 | 0 | return (CELL_RD); |
486 | 0 | case WINDOW_PANES_BORDER_U|WINDOW_PANES_BORDER_D: |
487 | 0 | case WINDOW_PANES_BORDER_U: |
488 | 0 | case WINDOW_PANES_BORDER_D: |
489 | 0 | return (CELL_UD); |
490 | 0 | } |
491 | 0 | return (CELL_NONE); |
492 | 0 | } |
493 | | |
494 | | static int |
495 | | window_panes_border_has_horizontal(u_char mask) |
496 | 0 | { |
497 | 0 | return ((mask & (WINDOW_PANES_BORDER_L|WINDOW_PANES_BORDER_R)) != 0); |
498 | 0 | } |
499 | | |
500 | | static int |
501 | | window_panes_border_has_vertical(u_char mask) |
502 | 0 | { |
503 | 0 | return ((mask & (WINDOW_PANES_BORDER_U|WINDOW_PANES_BORDER_D)) != 0); |
504 | 0 | } |
505 | | |
506 | | static void |
507 | | window_panes_mark_border_joins_cell(u_char *map, struct layout_cell *lc, |
508 | | u_int osx, u_int osy, u_int dsx, u_int dsy) |
509 | 0 | { |
510 | 0 | struct layout_cell *lcchild, *lcnext; |
511 | 0 | int x, y, x2, y2; |
512 | |
|
513 | 0 | if (lc->type == LAYOUT_WINDOWPANE) |
514 | 0 | return; |
515 | | |
516 | 0 | TAILQ_FOREACH(lcchild, &lc->cells, entry) { |
517 | 0 | window_panes_mark_border_joins_cell(map, lcchild, osx, osy, |
518 | 0 | dsx, dsy); |
519 | 0 | if (lcchild->flags & LAYOUT_CELL_FLOATING) |
520 | 0 | continue; |
521 | 0 | lcnext = window_panes_next_tiled_cell(lcchild); |
522 | 0 | if (lcnext == NULL) |
523 | 0 | continue; |
524 | | |
525 | 0 | if (lc->type == LAYOUT_LEFTRIGHT) { |
526 | 0 | x = window_panes_map_x(lcchild->g.xoff + lcchild->g.sx, |
527 | 0 | osx, dsx); |
528 | 0 | y = window_panes_map_y(lc->g.yoff, osy, dsy); |
529 | 0 | y2 = window_panes_map_y(lc->g.yoff + lc->g.sy, osy, |
530 | 0 | dsy); |
531 | 0 | if (x < 0 || (u_int)x >= dsx) |
532 | 0 | continue; |
533 | 0 | if (y > 0 && |
534 | 0 | window_panes_border_has_horizontal( |
535 | 0 | map[(y - 1) * dsx + x])) { |
536 | 0 | window_panes_mark_border(map, dsx, dsy, x, |
537 | 0 | y - 1, WINDOW_PANES_BORDER_D); |
538 | 0 | window_panes_mark_border(map, dsx, dsy, x, y, |
539 | 0 | WINDOW_PANES_BORDER_U); |
540 | 0 | } |
541 | 0 | if ((u_int)y2 < dsy && |
542 | 0 | window_panes_border_has_horizontal( |
543 | 0 | map[y2 * dsx + x])) { |
544 | 0 | window_panes_mark_border(map, dsx, dsy, x, y2, |
545 | 0 | WINDOW_PANES_BORDER_U); |
546 | 0 | window_panes_mark_border(map, dsx, dsy, x, |
547 | 0 | y2 - 1, WINDOW_PANES_BORDER_D); |
548 | 0 | } |
549 | 0 | } else { |
550 | 0 | x = window_panes_map_x(lc->g.xoff, osx, dsx); |
551 | 0 | x2 = window_panes_map_x(lc->g.xoff + lc->g.sx, osx, |
552 | 0 | dsx); |
553 | 0 | y = window_panes_map_y(lcchild->g.yoff + lcchild->g.sy, |
554 | 0 | osy, dsy); |
555 | 0 | if (y < 0 || (u_int)y >= dsy) |
556 | 0 | continue; |
557 | 0 | if (x > 0 && |
558 | 0 | window_panes_border_has_vertical( |
559 | 0 | map[y * dsx + x - 1])) { |
560 | 0 | window_panes_mark_border(map, dsx, dsy, x - 1, |
561 | 0 | y, WINDOW_PANES_BORDER_R); |
562 | 0 | window_panes_mark_border(map, dsx, dsy, x, y, |
563 | 0 | WINDOW_PANES_BORDER_L); |
564 | 0 | } |
565 | 0 | if ((u_int)x2 < dsx && |
566 | 0 | window_panes_border_has_vertical( |
567 | 0 | map[y * dsx + x2])) { |
568 | 0 | window_panes_mark_border(map, dsx, dsy, x2, y, |
569 | 0 | WINDOW_PANES_BORDER_L); |
570 | 0 | window_panes_mark_border(map, dsx, dsy, x2 - 1, |
571 | 0 | y, WINDOW_PANES_BORDER_R); |
572 | 0 | } |
573 | 0 | } |
574 | 0 | } |
575 | 0 | } |
576 | | |
577 | | static void |
578 | | window_panes_draw_borders(struct screen_write_ctx *ctx, struct window *w, |
579 | | struct layout_cell *lc, const struct grid_cell *gc, u_int osx, u_int osy, |
580 | | u_int dsx, u_int dsy) |
581 | 0 | { |
582 | 0 | struct grid_cell border_gc; |
583 | 0 | u_char *map; |
584 | 0 | u_int xx, yy; |
585 | 0 | int cell_type; |
586 | |
|
587 | 0 | if (dsx == 0 || dsy == 0) |
588 | 0 | return; |
589 | | |
590 | 0 | map = xcalloc(dsx, dsy); |
591 | 0 | window_panes_mark_borders_cell(map, lc, osx, osy, dsx, dsy); |
592 | 0 | window_panes_mark_pane_status_borders(map, w, lc, osx, osy, dsx, |
593 | 0 | dsy); |
594 | 0 | window_panes_mark_border_joins_cell(map, lc, osx, osy, dsx, dsy); |
595 | |
|
596 | 0 | for (yy = 0; yy < dsy; yy++) { |
597 | 0 | for (xx = 0; xx < dsx; xx++) { |
598 | 0 | if (map[yy * dsx + xx] == 0) |
599 | 0 | continue; |
600 | 0 | cell_type = window_panes_border_cell_type( |
601 | 0 | map[yy * dsx + xx]); |
602 | 0 | memcpy(&border_gc, gc, sizeof border_gc); |
603 | 0 | border_gc.attr |= GRID_ATTR_CHARSET; |
604 | 0 | utf8_set(&border_gc.data, CELL_BORDERS[cell_type]); |
605 | 0 | screen_write_cursormove(ctx, xx, yy, 0); |
606 | 0 | screen_write_cell(ctx, &border_gc); |
607 | 0 | } |
608 | 0 | } |
609 | 0 | free(map); |
610 | 0 | } |
611 | | |
612 | | static void |
613 | | window_panes_draw_floating_border(struct screen_write_ctx *ctx, |
614 | | struct window_pane *wp, const struct grid_cell *gc, u_int osx, u_int osy, |
615 | | u_int dsx, u_int dsy) |
616 | 0 | { |
617 | 0 | struct grid_cell border_gc; |
618 | 0 | u_char *map; |
619 | 0 | u_int xx, yy; |
620 | 0 | int x, y, x2, y2, cell_type; |
621 | |
|
622 | 0 | if (dsx == 0 || dsy == 0) |
623 | 0 | return; |
624 | 0 | if (!window_panes_get_floating_borders(wp, osx, osy, dsx, dsy, &x, &y, |
625 | 0 | &x2, &y2)) |
626 | 0 | return; |
627 | | |
628 | 0 | map = xcalloc(dsx, dsy); |
629 | 0 | window_panes_mark_hline(map, dsx, dsy, x, x2 + 1, y); |
630 | 0 | window_panes_mark_hline(map, dsx, dsy, x, x2 + 1, y2); |
631 | 0 | window_panes_mark_vline(map, dsx, dsy, x, y, y2 + 1); |
632 | 0 | window_panes_mark_vline(map, dsx, dsy, x2, y, y2 + 1); |
633 | |
|
634 | 0 | for (yy = 0; yy < dsy; yy++) { |
635 | 0 | for (xx = 0; xx < dsx; xx++) { |
636 | 0 | if (map[yy * dsx + xx] == 0) |
637 | 0 | continue; |
638 | 0 | cell_type = window_panes_border_cell_type( |
639 | 0 | map[yy * dsx + xx]); |
640 | 0 | memcpy(&border_gc, gc, sizeof border_gc); |
641 | 0 | border_gc.attr |= GRID_ATTR_CHARSET; |
642 | 0 | utf8_set(&border_gc.data, CELL_BORDERS[cell_type]); |
643 | 0 | screen_write_cursormove(ctx, xx, yy, 0); |
644 | 0 | screen_write_cell(ctx, &border_gc); |
645 | 0 | } |
646 | 0 | } |
647 | 0 | free(map); |
648 | 0 | } |
649 | | |
650 | | static void |
651 | | window_panes_clear_floating_area(struct screen_write_ctx *ctx, |
652 | | struct window_pane *wp, u_int osx, u_int osy, u_int dsx, u_int dsy) |
653 | 0 | { |
654 | 0 | struct grid_cell gc; |
655 | 0 | int x, y, x2, y2, xx, yy; |
656 | |
|
657 | 0 | if (!window_panes_get_floating_borders(wp, osx, osy, dsx, dsy, &x, &y, |
658 | 0 | &x2, &y2)) |
659 | 0 | return; |
660 | | |
661 | 0 | memcpy(&gc, &grid_default_cell, sizeof gc); |
662 | 0 | if (x < 0) |
663 | 0 | x = 0; |
664 | 0 | if (y < 0) |
665 | 0 | y = 0; |
666 | 0 | if ((u_int)x2 >= dsx) |
667 | 0 | x2 = dsx - 1; |
668 | 0 | if ((u_int)y2 >= dsy) |
669 | 0 | y2 = dsy - 1; |
670 | 0 | if (x2 < x || y2 < y) |
671 | 0 | return; |
672 | | |
673 | 0 | for (yy = y; yy <= y2; yy++) { |
674 | 0 | screen_write_cursormove(ctx, x, yy, 0); |
675 | 0 | for (xx = x; xx <= x2; xx++) |
676 | 0 | screen_write_putc(ctx, &gc, ' '); |
677 | 0 | } |
678 | 0 | } |
679 | | |
680 | | static void |
681 | | window_panes_draw_format(struct window_panes_modedata *data, |
682 | | struct screen_write_ctx *ctx, struct window_pane *wp, u_int x, u_int y, |
683 | | u_int sx, const struct grid_cell *gc) |
684 | 0 | { |
685 | 0 | struct session *s = data->session; |
686 | 0 | struct winlink *wl = s->curw; |
687 | 0 | const char *format; |
688 | 0 | char *expanded; |
689 | |
|
690 | 0 | if (sx == 0) |
691 | 0 | return; |
692 | 0 | format = options_get_string(data->wp->window->options, |
693 | 0 | "display-panes-format"); |
694 | 0 | if (*format == '\0') |
695 | 0 | return; |
696 | | |
697 | 0 | window_panes_get_source(data, &s, &wl, NULL); |
698 | 0 | if (s == NULL) |
699 | 0 | return; |
700 | | |
701 | 0 | expanded = format_single(NULL, format, NULL, s, wl, wp); |
702 | 0 | if (*expanded != '\0') { |
703 | 0 | screen_write_cursormove(ctx, x, y, 0); |
704 | 0 | format_draw(ctx, gc, sx, expanded, NULL, 0); |
705 | 0 | } |
706 | 0 | free(expanded); |
707 | 0 | } |
708 | | |
709 | | static void |
710 | | window_panes_draw_number(struct window_panes_modedata *data, |
711 | | struct screen_write_ctx *ctx, struct window_pane *wp, u_int pane, u_int x, |
712 | | u_int y, u_int sx, u_int sy) |
713 | 0 | { |
714 | 0 | struct session *s = data->session; |
715 | 0 | struct window *w = wp->window; |
716 | 0 | struct winlink *wl = s->curw; |
717 | 0 | struct options *oo = data->wp->window->options; |
718 | 0 | struct grid_cell fgc, bgc; |
719 | 0 | struct format_tree *ft; |
720 | 0 | const char *name; |
721 | 0 | char buf[16], lbuf[16] = { 0 }, *ptr; |
722 | 0 | size_t len, llen = 0, width; |
723 | 0 | u_int cx, cy, px, py, idx, i, j, format; |
724 | |
|
725 | 0 | len = xsnprintf(buf, sizeof buf, "%u", pane); |
726 | 0 | if (pane > 9 && pane < 35) |
727 | 0 | llen = xsnprintf(lbuf, sizeof lbuf, "%c", 'a' + (pane - 10)); |
728 | 0 | if (sx < len) |
729 | 0 | return; |
730 | | |
731 | 0 | window_panes_get_source(data, &s, &wl, NULL); |
732 | 0 | if (s != NULL) { |
733 | 0 | if (wl == NULL) |
734 | 0 | wl = s->curw; |
735 | 0 | } |
736 | 0 | if (w->active == wp) |
737 | 0 | name = "display-panes-active-colour"; |
738 | 0 | else |
739 | 0 | name = "display-panes-colour"; |
740 | 0 | ft = format_create_defaults(NULL, NULL, s, wl, wp); |
741 | 0 | style_apply(&fgc, oo, name, ft); |
742 | 0 | format_free(ft); |
743 | |
|
744 | 0 | memcpy(&bgc, &grid_default_cell, sizeof bgc); |
745 | 0 | bgc.bg = fgc.fg; |
746 | |
|
747 | 0 | format = 0; |
748 | 0 | if (options_get_string(oo, "display-panes-format")[0] != '\0') |
749 | 0 | format = 1; |
750 | 0 | width = (len * 6) - 1; |
751 | 0 | if (sx < width || sy < (format ? 7 : 5)) { |
752 | 0 | width = len; |
753 | 0 | if (llen != 0 && sx >= len + llen + 1) |
754 | 0 | width += llen + 1; |
755 | 0 | cx = x + (sx - width) / 2; |
756 | 0 | cy = y + sy / 2; |
757 | 0 | screen_write_cursormove(ctx, cx, cy, 0); |
758 | 0 | screen_write_puts(ctx, &fgc, "%s", buf); |
759 | 0 | if (width > len) |
760 | 0 | screen_write_puts(ctx, &fgc, " %s", lbuf); |
761 | 0 | if (format && sy > 1) |
762 | 0 | window_panes_draw_format(data, ctx, wp, x, y, sx, &fgc); |
763 | 0 | return; |
764 | 0 | } |
765 | | |
766 | 0 | px = (sx - width) / 2; |
767 | 0 | py = (sy - 5) / 2; |
768 | 0 | for (ptr = buf; *ptr != '\0'; ptr++) { |
769 | 0 | if (*ptr < '0' || *ptr > '9') |
770 | 0 | continue; |
771 | 0 | idx = *ptr - '0'; |
772 | |
|
773 | 0 | for (j = 0; j < 5; j++) { |
774 | 0 | for (i = 0; i < 5; i++) { |
775 | 0 | if (!window_clock_table[idx][j][i]) |
776 | 0 | continue; |
777 | 0 | screen_write_cursormove(ctx, x + px + i, |
778 | 0 | y + py + j, 0); |
779 | 0 | screen_write_putc(ctx, &bgc, ' '); |
780 | 0 | } |
781 | 0 | } |
782 | 0 | px += 6; |
783 | 0 | } |
784 | |
|
785 | 0 | if (sy <= 6) |
786 | 0 | return; |
787 | 0 | window_panes_draw_format(data, ctx, wp, x, y, sx, &fgc); |
788 | 0 | if (llen != 0) { |
789 | 0 | cx = x + px - llen - 1; |
790 | 0 | cy = y + py + 5; |
791 | 0 | screen_write_cursormove(ctx, cx, cy, 0); |
792 | 0 | screen_write_puts(ctx, &fgc, "%s", lbuf); |
793 | 0 | } |
794 | 0 | } |
795 | | |
796 | | static void |
797 | | window_panes_draw_pane(struct window_panes_modedata *data, |
798 | | struct screen_write_ctx *ctx, struct window_pane *wp, |
799 | | struct layout_cell *root, u_int osx, u_int osy, u_int dsx, u_int dsy) |
800 | 0 | { |
801 | 0 | struct screen *s = &wp->base; |
802 | 0 | u_int pane, x, y, sx, sy; |
803 | |
|
804 | 0 | if (!window_panes_pane_visible(wp)) |
805 | 0 | return; |
806 | 0 | if (!window_panes_get_geometry(wp, root, osx, osy, dsx, dsy, &x, &y, |
807 | 0 | &sx, &sy)) |
808 | 0 | return; |
809 | 0 | if (!window_panes_clip_floating_pane(wp, osx, osy, dsx, dsy, &x, &y, |
810 | 0 | &sx, &sy)) |
811 | 0 | return; |
812 | 0 | if (window_pane_index(wp, &pane) != 0) |
813 | 0 | return; |
814 | 0 | window_panes_add_area(data, wp, x, y, sx, sy); |
815 | |
|
816 | 0 | screen_write_cursormove(ctx, x, y, 0); |
817 | 0 | if (data->preview != NULL && |
818 | 0 | wp == data->wp && |
819 | 0 | sx <= screen_size_x(data->preview) && |
820 | 0 | sy <= screen_size_y(data->preview)) |
821 | 0 | s = data->preview; |
822 | 0 | if (osx <= dsx && osy <= dsy) |
823 | 0 | screen_write_fast_copy(ctx, s, 0, s->grid->hsize, sx, sy); |
824 | 0 | else |
825 | 0 | screen_write_preview(ctx, s, sx, sy); |
826 | 0 | window_panes_draw_number(data, ctx, wp, pane, x, y, sx, sy); |
827 | 0 | } |
828 | | |
829 | | static void |
830 | | window_panes_draw_screen(struct window_mode_entry *wme) |
831 | 0 | { |
832 | 0 | struct window_panes_modedata *data = wme->data; |
833 | 0 | struct window *w; |
834 | 0 | struct window_pane *wp; |
835 | 0 | struct screen_write_ctx ctx; |
836 | 0 | struct layout_cell *root; |
837 | 0 | struct grid_cell border_gc; |
838 | 0 | u_int osx, osy, sx, sy; |
839 | |
|
840 | 0 | if (!window_panes_get_source(data, NULL, NULL, &w)) |
841 | 0 | return; |
842 | 0 | root = w->saved_layout_root; |
843 | 0 | if (root == NULL) |
844 | 0 | root = w->layout_root; |
845 | 0 | if (root == NULL) |
846 | 0 | return; |
847 | | |
848 | 0 | osx = root->g.sx; |
849 | 0 | osy = root->g.sy; |
850 | 0 | sx = screen_size_x(&data->screen); |
851 | 0 | sy = screen_size_y(&data->screen); |
852 | |
|
853 | 0 | window_panes_free_areas(data); |
854 | 0 | screen_write_start(&ctx, &data->screen); |
855 | 0 | screen_write_clearscreen(&ctx, 8); |
856 | 0 | TAILQ_FOREACH(wp, &w->panes, entry) { |
857 | 0 | if (window_panes_pane_floating(wp)) |
858 | 0 | continue; |
859 | 0 | window_panes_draw_pane(data, &ctx, wp, root, osx, osy, sx, sy); |
860 | 0 | } |
861 | 0 | window_panes_get_border_cell(data, &border_gc); |
862 | 0 | window_panes_draw_borders(&ctx, w, root, &border_gc, osx, osy, sx, sy); |
863 | 0 | TAILQ_FOREACH_REVERSE(wp, &w->z_index, window_panes_zindex, zentry) { |
864 | 0 | if (!window_panes_pane_floating(wp)) |
865 | 0 | continue; |
866 | 0 | window_panes_clear_floating_area(&ctx, wp, osx, osy, sx, sy); |
867 | 0 | window_panes_draw_pane(data, &ctx, wp, root, osx, osy, sx, sy); |
868 | 0 | window_panes_draw_floating_border(&ctx, wp, &border_gc, osx, |
869 | 0 | osy, sx, sy); |
870 | 0 | } |
871 | 0 | screen_write_stop(&ctx); |
872 | |
|
873 | 0 | data->wp->flags |= PANE_REDRAW; |
874 | 0 | } |
875 | | |
876 | | static void |
877 | | window_panes_timer_callback(__unused int fd, __unused short events, void *arg) |
878 | 0 | { |
879 | 0 | struct window_mode_entry *wme = arg; |
880 | |
|
881 | 0 | window_pane_reset_mode(wme->wp); |
882 | 0 | } |
883 | | |
884 | | static struct screen * |
885 | | window_panes_init(struct window_mode_entry *wme, struct cmdq_item *item, |
886 | | __unused struct cmd_find_state *fs, struct args *args) |
887 | 0 | { |
888 | 0 | struct window_pane *wp = wme->wp; |
889 | 0 | struct window *w = wp->window; |
890 | 0 | struct window_panes_modedata *data; |
891 | 0 | struct cmd *self; |
892 | 0 | struct cmd_find_state *source, *target; |
893 | 0 | struct session *s; |
894 | 0 | struct timeval tv; |
895 | 0 | char *cause; |
896 | 0 | u_int sx = screen_size_x(&wp->base); |
897 | 0 | u_int sy = screen_size_y(&wp->base); |
898 | 0 | u_int delay; |
899 | |
|
900 | 0 | if (item == NULL) |
901 | 0 | return (NULL); |
902 | 0 | self = cmdq_get_cmd(item); |
903 | 0 | if (self == NULL) |
904 | 0 | return (NULL); |
905 | | |
906 | 0 | source = cmdq_get_source(item); |
907 | 0 | target = cmdq_get_target(item); |
908 | 0 | s = target->s; |
909 | |
|
910 | 0 | if (!args_has(args, 'd')) |
911 | 0 | delay = options_get_number(w->options, "display-panes-time"); |
912 | 0 | else { |
913 | 0 | delay = args_strtonum(args, 'd', 0, UINT_MAX, &cause); |
914 | 0 | if (cause != NULL) { |
915 | 0 | cmdq_error(item, "delay %s", cause); |
916 | 0 | free(cause); |
917 | 0 | return (NULL); |
918 | 0 | } |
919 | 0 | } |
920 | | |
921 | 0 | wme->data = data = xcalloc(1, sizeof *data); |
922 | 0 | data->wp = wp; |
923 | 0 | data->session = s; |
924 | |
|
925 | 0 | screen_init(&data->screen, sx, sy, 0); |
926 | 0 | data->screen.mode &= ~MODE_CURSOR; |
927 | |
|
928 | 0 | data->state = args_make_commands_prepare(self, item, 0, |
929 | 0 | "select-pane -t \"%%%\"", 0, 0); |
930 | 0 | if (args_has(args, 's')) { |
931 | 0 | data->source_session = source->s->id; |
932 | 0 | data->source_window = source->w->id; |
933 | 0 | } else { |
934 | 0 | data->source_session = target->s->id; |
935 | 0 | data->source_window = target->w->id; |
936 | 0 | } |
937 | |
|
938 | 0 | data->delay = delay; |
939 | 0 | data->ignore_keys = args_has(args, 'N'); |
940 | |
|
941 | 0 | if (args_has(args, 'Z')) |
942 | 0 | data->zoomed = -1; |
943 | 0 | else { |
944 | 0 | data->zoomed = (w->flags & WINDOW_ZOOMED); |
945 | 0 | if (!data->zoomed) |
946 | 0 | window_panes_set_preview(data); |
947 | 0 | if (!data->zoomed && window_zoom(wp) == 0) |
948 | 0 | server_redraw_window(w); |
949 | 0 | } |
950 | |
|
951 | 0 | evtimer_set(&data->timer, window_panes_timer_callback, wme); |
952 | 0 | if (data->delay != 0) { |
953 | 0 | tv.tv_sec = data->delay / 1000; |
954 | 0 | tv.tv_usec = (data->delay % 1000) * 1000; |
955 | 0 | evtimer_add(&data->timer, &tv); |
956 | 0 | } |
957 | |
|
958 | 0 | window_panes_draw_screen(wme); |
959 | 0 | return (&data->screen); |
960 | 0 | } |
961 | | |
962 | | static void |
963 | | window_panes_free(struct window_mode_entry *wme) |
964 | 0 | { |
965 | 0 | struct window_panes_modedata *data = wme->data; |
966 | 0 | struct window *w = wme->wp->window; |
967 | |
|
968 | 0 | evtimer_del(&data->timer); |
969 | |
|
970 | 0 | if (data->zoomed == 0) |
971 | 0 | server_unzoom_window(w); |
972 | 0 | server_redraw_window(w); |
973 | 0 | server_redraw_window_borders(w); |
974 | 0 | server_status_window(w); |
975 | |
|
976 | 0 | if (data->state != NULL) |
977 | 0 | args_make_commands_free(data->state); |
978 | 0 | window_panes_free_areas(data); |
979 | 0 | if (data->preview != NULL) { |
980 | 0 | screen_free(data->preview); |
981 | 0 | free(data->preview); |
982 | 0 | } |
983 | 0 | screen_free(&data->screen); |
984 | 0 | free(data); |
985 | 0 | } |
986 | | |
987 | | static void |
988 | | window_panes_resize(struct window_mode_entry *wme, u_int sx, u_int sy) |
989 | 0 | { |
990 | 0 | struct window_panes_modedata *data = wme->data; |
991 | |
|
992 | 0 | screen_resize(&data->screen, sx, sy, 0); |
993 | 0 | window_panes_draw_screen(wme); |
994 | 0 | } |
995 | | |
996 | | static void |
997 | | window_panes_run_command(struct window_panes_modedata *data, struct client *c, |
998 | | struct window_pane *wp) |
999 | 0 | { |
1000 | 0 | struct cmdq_item *new_item; |
1001 | 0 | struct cmd_list *cmdlist; |
1002 | 0 | char *expanded, *error; |
1003 | |
|
1004 | 0 | xasprintf(&expanded, "%%%u", wp->id); |
1005 | 0 | cmdlist = args_make_commands(data->state, 1, &expanded, &error); |
1006 | 0 | if (cmdlist == NULL) { |
1007 | 0 | cmdq_append(c, cmdq_get_error(error)); |
1008 | 0 | free(error); |
1009 | 0 | } else { |
1010 | 0 | new_item = cmdq_get_command(cmdlist, NULL); |
1011 | 0 | cmdq_append(c, new_item); |
1012 | 0 | } |
1013 | 0 | free(expanded); |
1014 | 0 | } |
1015 | | |
1016 | | static struct window_pane * |
1017 | | window_panes_find_pane(struct window_panes_modedata *data, u_int x, u_int y) |
1018 | 0 | { |
1019 | 0 | struct window_panes_area *area; |
1020 | 0 | u_int i; |
1021 | |
|
1022 | 0 | for (i = data->areas_size; i > 0; i--) { |
1023 | 0 | area = &data->areas[i - 1]; |
1024 | 0 | if (x < area->x || x >= area->x + area->sx) |
1025 | 0 | continue; |
1026 | 0 | if (y < area->y || y >= area->y + area->sy) |
1027 | 0 | continue; |
1028 | 0 | return (window_pane_find_by_id(area->id)); |
1029 | 0 | } |
1030 | 0 | return (NULL); |
1031 | 0 | } |
1032 | | |
1033 | | static struct window_pane * |
1034 | | window_panes_key_pane(struct window_panes_modedata *data, key_code key) |
1035 | 0 | { |
1036 | 0 | struct window *w; |
1037 | 0 | u_int index; |
1038 | |
|
1039 | 0 | if (key >= '0' && key <= '9') |
1040 | 0 | index = key - '0'; |
1041 | 0 | else if ((key & KEYC_MASK_MODIFIERS) == 0) { |
1042 | 0 | key &= KEYC_MASK_KEY; |
1043 | 0 | if (key < 'a' || key > 'z') |
1044 | 0 | return (NULL); |
1045 | 0 | index = 10 + (key - 'a'); |
1046 | 0 | } else |
1047 | 0 | return (NULL); |
1048 | 0 | if (!window_panes_get_source(data, NULL, NULL, &w)) |
1049 | 0 | return (NULL); |
1050 | 0 | return (window_pane_at_index(w, index)); |
1051 | 0 | } |
1052 | | |
1053 | | static struct window_pane * |
1054 | | window_panes_get_target(struct window_mode_entry *wme, key_code key, |
1055 | | struct mouse_event *m) |
1056 | 0 | { |
1057 | 0 | struct window_panes_modedata *data = wme->data; |
1058 | 0 | u_int x, y; |
1059 | |
|
1060 | 0 | if (data->ignore_keys) |
1061 | 0 | return (NULL); |
1062 | | |
1063 | 0 | if (KEYC_IS_MOUSE(key)) { |
1064 | 0 | if (key != KEYC_MOUSEDOWN1_PANE || |
1065 | 0 | m == NULL || |
1066 | 0 | cmd_mouse_at(wme->wp, m, &x, &y, 0) != 0) |
1067 | 0 | return (NULL); |
1068 | 0 | return (window_panes_find_pane(data, x, y)); |
1069 | 0 | } |
1070 | | |
1071 | 0 | return (window_panes_key_pane(data, key)); |
1072 | 0 | } |
1073 | | |
1074 | | static void |
1075 | | window_panes_key(struct window_mode_entry *wme, struct client *c, |
1076 | | __unused struct session *s, __unused struct winlink *wl, key_code key, |
1077 | | struct mouse_event *m) |
1078 | 0 | { |
1079 | 0 | struct window_pane *wp = wme->wp, *target = NULL; |
1080 | 0 | struct window_panes_modedata *data = wme->data; |
1081 | |
|
1082 | 0 | if (key == '\033' || key == 'q') { |
1083 | 0 | window_pane_reset_mode(wp); |
1084 | 0 | return; |
1085 | 0 | } |
1086 | | |
1087 | 0 | target = window_panes_get_target(wme, key, m); |
1088 | 0 | if (target == NULL) { |
1089 | 0 | if (!data->ignore_keys && !KEYC_IS_MOUSE(key)) |
1090 | 0 | window_pane_reset_mode(wp); |
1091 | 0 | return; |
1092 | 0 | } |
1093 | | |
1094 | 0 | if (wp->window->flags & WINDOW_ZOOMED) |
1095 | 0 | window_unzoom(wp->window, 1); |
1096 | 0 | window_panes_run_command(data, c, target); |
1097 | 0 | window_pane_reset_mode(wp); |
1098 | 0 | } |