4 * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
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.
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.
19 #include <sys/types.h>
25 int screen_redraw_cell_border1(struct window_pane
*, u_int
, u_int
);
26 int screen_redraw_cell_border(struct client
*, u_int
, u_int
);
27 int screen_redraw_check_cell(struct client
*, u_int
, u_int
,
28 struct window_pane
**);
29 int screen_redraw_check_active(u_int
, u_int
, int, struct window
*,
30 struct window_pane
*);
32 void screen_redraw_draw_number(struct client
*, struct window_pane
*);
35 #define CELL_LEFTRIGHT 1
36 #define CELL_TOPBOTTOM 2
37 #define CELL_TOPLEFT 3
38 #define CELL_TOPRIGHT 4
39 #define CELL_BOTTOMLEFT 5
40 #define CELL_BOTTOMRIGHT 6
41 #define CELL_TOPJOIN 7
42 #define CELL_BOTTOMJOIN 8
43 #define CELL_LEFTJOIN 9
44 #define CELL_RIGHTJOIN 10
46 #define CELL_OUTSIDE 12
48 #define CELL_BORDERS " xqlkmjwvtun~"
50 /* Check if cell is on the border of a particular pane. */
52 screen_redraw_cell_border1(struct window_pane
*wp
, u_int px
, u_int py
)
55 if (px
>= wp
->xoff
&& px
< wp
->xoff
+ wp
->sx
&&
56 py
>= wp
->yoff
&& py
< wp
->yoff
+ wp
->sy
)
59 /* Left/right borders. */
60 if ((wp
->yoff
== 0 || py
>= wp
->yoff
- 1) && py
<= wp
->yoff
+ wp
->sy
) {
61 if (wp
->xoff
!= 0 && px
== wp
->xoff
- 1)
63 if (px
== wp
->xoff
+ wp
->sx
)
67 /* Top/bottom borders. */
68 if ((wp
->xoff
== 0 || px
>= wp
->xoff
- 1) && px
<= wp
->xoff
+ wp
->sx
) {
69 if (wp
->yoff
!= 0 && py
== wp
->yoff
- 1)
71 if (py
== wp
->yoff
+ wp
->sy
)
79 /* Check if a cell is on the pane border. */
81 screen_redraw_cell_border(struct client
*c
, u_int px
, u_int py
)
83 struct window
*w
= c
->session
->curw
->window
;
84 struct window_pane
*wp
;
87 /* Check all the panes. */
88 TAILQ_FOREACH(wp
, &w
->panes
, entry
) {
89 if (!window_pane_visible(wp
))
91 if ((retval
= screen_redraw_cell_border1(wp
, px
, py
)) != -1)
98 /* Check if cell inside a pane. */
100 screen_redraw_check_cell(struct client
*c
, u_int px
, u_int py
,
101 struct window_pane
**wpp
)
103 struct window
*w
= c
->session
->curw
->window
;
104 struct window_pane
*wp
;
107 if (px
> w
->sx
|| py
> w
->sy
)
108 return (CELL_OUTSIDE
);
110 TAILQ_FOREACH(wp
, &w
->panes
, entry
) {
111 if (!window_pane_visible(wp
))
115 /* If outside the pane and its border, skip it. */
116 if ((wp
->xoff
!= 0 && px
< wp
->xoff
- 1) ||
117 px
> wp
->xoff
+ wp
->sx
||
118 (wp
->yoff
!= 0 && py
< wp
->yoff
- 1) ||
119 py
> wp
->yoff
+ wp
->sy
)
122 /* If definitely inside, return so. */
123 if (!screen_redraw_cell_border(c
, px
, py
))
124 return (CELL_INSIDE
);
127 * Construct a bitmask of whether the cells to the left (bit
128 * 4), right, top, and bottom (bit 1) of this cell are borders.
131 if (px
== 0 || screen_redraw_cell_border(c
, px
- 1, py
))
133 if (px
<= w
->sx
&& screen_redraw_cell_border(c
, px
+ 1, py
))
135 if (py
== 0 || screen_redraw_cell_border(c
, px
, py
- 1))
137 if (py
<= w
->sy
&& screen_redraw_cell_border(c
, px
, py
+ 1))
141 * Figure out what kind of border this cell is. Only one bit
142 * set doesn't make sense (can't have a border cell with no
146 case 15: /* 1111, left right top bottom */
148 case 14: /* 1110, left right top */
149 return (CELL_BOTTOMJOIN
);
150 case 13: /* 1101, left right bottom */
151 return (CELL_TOPJOIN
);
152 case 12: /* 1100, left right */
153 return (CELL_TOPBOTTOM
);
154 case 11: /* 1011, left top bottom */
155 return (CELL_RIGHTJOIN
);
156 case 10: /* 1010, left top */
157 return (CELL_BOTTOMRIGHT
);
158 case 9: /* 1001, left bottom */
159 return (CELL_TOPRIGHT
);
160 case 7: /* 0111, right top bottom */
161 return (CELL_LEFTJOIN
);
162 case 6: /* 0110, right top */
163 return (CELL_BOTTOMLEFT
);
164 case 5: /* 0101, right bottom */
165 return (CELL_TOPLEFT
);
166 case 3: /* 0011, top bottom */
167 return (CELL_LEFTRIGHT
);
172 return (CELL_OUTSIDE
);
175 /* Check active pane indicator. */
177 screen_redraw_check_active(u_int px
, u_int py
, int type
, struct window
*w
,
178 struct window_pane
*wp
)
180 /* Is this off the active pane border? */
181 if (screen_redraw_cell_border1(w
->active
, px
, py
) != 1)
184 /* If there are more than two panes, that's enough. */
185 if (window_count_panes(w
) != 2)
188 /* Else if the cell is not a border cell, forget it. */
189 if (wp
== NULL
|| (type
== CELL_OUTSIDE
|| type
== CELL_INSIDE
))
192 /* Check if the pane covers the whole width. */
193 if (wp
->xoff
== 0 && wp
->sx
== w
->sx
) {
194 /* This can either be the top pane or the bottom pane. */
195 if (wp
->yoff
== 0) { /* top pane */
197 return (px
<= wp
->sx
/ 2);
198 return (px
> wp
->sx
/ 2);
203 /* Check if the pane covers the whole height. */
204 if (wp
->yoff
== 0 && wp
->sy
== w
->sy
) {
205 /* This can either be the left pane or the right pane. */
206 if (wp
->xoff
== 0) { /* left pane */
208 return (py
<= wp
->sy
/ 2);
209 return (py
> wp
->sy
/ 2);
217 /* Redraw entire screen. */
219 screen_redraw_screen(struct client
*c
, int status_only
, int borders_only
)
221 struct window
*w
= c
->session
->curw
->window
;
222 struct options
*oo
= &c
->session
->options
;
223 struct tty
*tty
= &c
->tty
;
224 struct window_pane
*wp
;
225 struct grid_cell active_gc
, other_gc
;
226 u_int i
, j
, type
, top
;
227 int status
, spos
, fg
, bg
;
229 /* Suspended clients should not be updated. */
230 if (c
->flags
& CLIENT_SUSPENDED
)
233 /* Get status line, er, status. */
234 spos
= options_get_number(oo
, "status-position");
235 if (c
->message_string
!= NULL
|| c
->prompt_string
!= NULL
)
238 status
= options_get_number(oo
, "status");
240 if (status
&& spos
== 0)
243 /* If only drawing status and it is present, don't need the rest. */
244 if (status_only
&& status
) {
246 tty_draw_line(tty
, &c
->status
, 0, 0, 0);
248 tty_draw_line(tty
, &c
->status
, 0, 0, tty
->sy
- 1);
253 /* Set up pane border attributes. */
254 memcpy(&other_gc
, &grid_marker_cell
, sizeof other_gc
);
255 memcpy(&active_gc
, &grid_marker_cell
, sizeof active_gc
);
256 active_gc
.attr
= other_gc
.attr
= GRID_ATTR_CHARSET
;
257 fg
= options_get_number(oo
, "pane-border-fg");
258 colour_set_fg(&other_gc
, fg
);
259 bg
= options_get_number(oo
, "pane-border-bg");
260 colour_set_bg(&other_gc
, bg
);
261 fg
= options_get_number(oo
, "pane-active-border-fg");
262 colour_set_fg(&active_gc
, fg
);
263 bg
= options_get_number(oo
, "pane-active-border-bg");
264 colour_set_bg(&active_gc
, bg
);
266 /* Draw background and borders. */
267 for (j
= 0; j
< tty
->sy
- status
; j
++) {
269 if (spos
== 1 && j
!= tty
->sy
- 1)
271 else if (spos
== 0 && j
!= 0)
274 for (i
= 0; i
< tty
->sx
; i
++) {
275 type
= screen_redraw_check_cell(c
, i
, j
, &wp
);
276 if (type
== CELL_INSIDE
)
278 if (screen_redraw_check_active(i
, j
, type
, w
, wp
))
279 tty_attributes(tty
, &active_gc
);
281 tty_attributes(tty
, &other_gc
);
282 tty_cursor(tty
, i
, top
+ j
);
283 tty_putc(tty
, CELL_BORDERS
[type
]);
287 /* If only drawing borders, that's it. */
291 /* Draw the panes, if necessary. */
292 TAILQ_FOREACH(wp
, &w
->panes
, entry
) {
293 if (!window_pane_visible(wp
))
295 for (i
= 0; i
< wp
->sy
; i
++) {
297 if (spos
== 1 && wp
->yoff
+ i
!= tty
->sy
- 1)
299 else if (spos
== 0 && wp
->yoff
+ i
!= 0)
303 tty
, wp
->screen
, i
, wp
->xoff
, top
+ wp
->yoff
);
305 if (c
->flags
& CLIENT_IDENTIFY
)
306 screen_redraw_draw_number(c
, wp
);
309 /* Draw the status line. */
312 tty_draw_line(tty
, &c
->status
, 0, 0, 0);
314 tty_draw_line(tty
, &c
->status
, 0, 0, tty
->sy
- 1);
319 /* Draw a single pane. */
321 screen_redraw_pane(struct client
*c
, struct window_pane
*wp
)
325 if (!window_pane_visible(wp
))
329 if (status_at_line(c
) == 0)
332 for (i
= 0; i
< wp
->sy
; i
++)
333 tty_draw_line(&c
->tty
, wp
->screen
, i
, wp
->xoff
, yoff
);
337 /* Draw number on a pane. */
339 screen_redraw_draw_number(struct client
*c
, struct window_pane
*wp
)
341 struct tty
*tty
= &c
->tty
;
342 struct session
*s
= c
->session
;
343 struct options
*oo
= &s
->options
;
344 struct window
*w
= wp
->window
;
346 u_int idx
, px
, py
, i
, j
, xoff
, yoff
;
347 int colour
, active_colour
;
351 if (window_pane_index(wp
, &idx
) != 0)
352 fatalx("index not found");
353 len
= xsnprintf(buf
, sizeof buf
, "%u", idx
);
357 colour
= options_get_number(oo
, "display-panes-colour");
358 active_colour
= options_get_number(oo
, "display-panes-active-colour");
360 px
= wp
->sx
/ 2; py
= wp
->sy
/ 2;
361 xoff
= wp
->xoff
; yoff
= wp
->yoff
;
363 if (wp
->sx
< len
* 6 || wp
->sy
< 5) {
364 tty_cursor(tty
, xoff
+ px
- len
/ 2, yoff
+ py
);
371 memcpy(&gc
, &grid_marker_cell
, sizeof gc
);
373 colour_set_bg(&gc
, active_colour
);
375 colour_set_bg(&gc
, colour
);
376 tty_attributes(tty
, &gc
);
377 for (ptr
= buf
; *ptr
!= '\0'; ptr
++) {
378 if (*ptr
< '0' || *ptr
> '9')
382 for (j
= 0; j
< 5; j
++) {
383 for (i
= px
; i
< px
+ 5; i
++) {
384 tty_cursor(tty
, xoff
+ i
, yoff
+ py
+ j
);
385 if (clock_table
[idx
][j
][i
- px
])
392 len
= xsnprintf(buf
, sizeof buf
, "%ux%u", wp
->sx
, wp
->sy
);
393 if (wp
->sx
< len
|| wp
->sy
< 6)
395 tty_cursor(tty
, xoff
+ wp
->sx
- len
, yoff
);
398 memcpy(&gc
, &grid_marker_cell
, sizeof gc
);
400 colour_set_fg(&gc
, active_colour
);
402 colour_set_fg(&gc
, colour
);
403 tty_attributes(tty
, &gc
);
406 tty_cursor(tty
, 0, 0);