version 1.47, 2009/11/19 16:22:10 |
version 1.48, 2009/11/19 19:47:28 |
|
|
|
|
#include "tmux.h" |
#include "tmux.h" |
|
|
|
char *status_redraw_get_left( |
|
struct client *, time_t, int, struct grid_cell *, size_t *); |
|
char *status_redraw_get_right( |
|
struct client *, time_t, int, struct grid_cell *, size_t *); |
char *status_job(struct client *, char **); |
char *status_job(struct client *, char **); |
void status_job_callback(struct job *); |
void status_job_callback(struct job *); |
size_t status_width(struct client *, struct winlink *, time_t); |
size_t status_width(struct client *, struct winlink *, time_t); |
|
|
void status_prompt_add_history(struct client *); |
void status_prompt_add_history(struct client *); |
char *status_prompt_complete(const char *); |
char *status_prompt_complete(const char *); |
|
|
|
/* Retrieve options for left string. */ |
|
char * |
|
status_redraw_get_left(struct client *c, |
|
time_t t, int utf8flag, struct grid_cell *gc, size_t *size) |
|
{ |
|
struct session *s = c->session; |
|
char *left; |
|
u_char fg, bg, attr; |
|
size_t leftlen; |
|
|
|
fg = options_get_number(&s->options, "status-left-fg"); |
|
if (fg != 8) |
|
colour_set_fg(gc, fg); |
|
bg = options_get_number(&s->options, "status-left-bg"); |
|
if (bg != 8) |
|
colour_set_bg(gc, bg); |
|
attr = options_get_number(&s->options, "status-left-attr"); |
|
if (attr != 0) |
|
gc->attr = attr; |
|
|
|
left = status_replace( |
|
c, NULL, options_get_string(&s->options, "status-left"), t, 1); |
|
|
|
*size = options_get_number(&s->options, "status-left-length"); |
|
leftlen = screen_write_cstrlen(utf8flag, "%s", left); |
|
if (leftlen < *size) |
|
*size = leftlen; |
|
return (left); |
|
} |
|
|
|
/* Retrieve options for right string. */ |
|
char * |
|
status_redraw_get_right(struct client *c, |
|
time_t t, int utf8flag, struct grid_cell *gc, size_t *size) |
|
{ |
|
struct session *s = c->session; |
|
char *right; |
|
u_char fg, bg, attr; |
|
size_t rightlen; |
|
|
|
fg = options_get_number(&s->options, "status-right-fg"); |
|
if (fg != 8) |
|
colour_set_fg(gc, fg); |
|
bg = options_get_number(&s->options, "status-right-bg"); |
|
if (bg != 8) |
|
colour_set_bg(gc, bg); |
|
attr = options_get_number(&s->options, "status-right-attr"); |
|
if (attr != 0) |
|
gc->attr = attr; |
|
|
|
right = status_replace( |
|
c, NULL, options_get_string(&s->options, "status-right"), t, 1); |
|
|
|
*size = options_get_number(&s->options, "status-right-length"); |
|
rightlen = screen_write_cstrlen(utf8flag, "%s", right); |
|
if (rightlen < *size) |
|
*size = rightlen; |
|
return (right); |
|
} |
|
|
/* Draw status for client on the last lines of given context. */ |
/* Draw status for client on the last lines of given context. */ |
int |
int |
status_redraw(struct client *c) |
status_redraw(struct client *c) |
{ |
{ |
struct screen_write_ctx ctx; |
struct screen_write_ctx ctx; |
struct session *s = c->session; |
struct session *s = c->session; |
struct winlink *wl; |
struct winlink *wl; |
struct screen old_status; |
struct screen old_status, window_list; |
char *left, *right, *text, *ptr; |
struct grid_cell stdgc, lgc, rgc, gc; |
size_t llen, llen2, rlen, rlen2, offset; |
time_t t; |
size_t ox, xx, yy, size, start, width; |
char *left, *right; |
struct grid_cell stdgc, sl_stdgc, sr_stdgc, gc; |
u_int offset, needed; |
int larrow, rarrow, utf8flag; |
u_int wlstart, wlwidth, wlavailable, wloffset, wlsize; |
int sl_fg, sl_bg, sr_fg, sr_bg; |
size_t llen, rlen; |
int sl_attr, sr_attr; |
int larrow, rarrow, utf8flag; |
|
|
left = right = NULL; |
|
|
|
/* No status line?*/ |
/* No status line?*/ |
if (c->tty.sy == 0 || !options_get_number(&s->options, "status")) |
if (c->tty.sy == 0 || !options_get_number(&s->options, "status")) |
return (1); |
return (1); |
|
left = right = NULL; |
larrow = rarrow = 0; |
larrow = rarrow = 0; |
|
|
/* Create the target screen. */ |
/* Update status timer. */ |
memcpy(&old_status, &c->status, sizeof old_status); |
|
screen_init(&c->status, c->tty.sx, 1, 0); |
|
|
|
if (gettimeofday(&c->status_timer, NULL) != 0) |
if (gettimeofday(&c->status_timer, NULL) != 0) |
fatal("gettimeofday failed"); |
fatal("gettimeofday failed"); |
|
t = c->status_timer.tv_sec; |
|
|
|
/* Set up default colour. */ |
memcpy(&stdgc, &grid_default_cell, sizeof gc); |
memcpy(&stdgc, &grid_default_cell, sizeof gc); |
colour_set_fg(&stdgc, options_get_number(&s->options, "status-fg")); |
colour_set_fg(&stdgc, options_get_number(&s->options, "status-fg")); |
colour_set_bg(&stdgc, options_get_number(&s->options, "status-bg")); |
colour_set_bg(&stdgc, options_get_number(&s->options, "status-bg")); |
stdgc.attr |= options_get_number(&s->options, "status-attr"); |
stdgc.attr |= options_get_number(&s->options, "status-attr"); |
|
|
/* |
/* Create the target screen. */ |
* Set the status-left and status-right parts to the default status |
memcpy(&old_status, &c->status, sizeof old_status); |
* line options and only change them where they differ from the |
screen_init(&c->status, c->tty.sx, 1, 0); |
* defaults. |
screen_write_start(&ctx, NULL, &c->status); |
*/ |
for (offset = 0; offset < c->tty.sx; offset++) |
memcpy(&sl_stdgc, &stdgc, sizeof sl_stdgc); |
screen_write_putc(&ctx, &stdgc, ' '); |
memcpy(&sr_stdgc, &stdgc, sizeof sr_stdgc); |
screen_write_stop(&ctx); |
sl_fg = options_get_number(&s->options, "status-left-fg"); |
|
if (sl_fg != 8) |
|
colour_set_fg(&sl_stdgc, sl_fg); |
|
sl_bg = options_get_number(&s->options, "status-left-bg"); |
|
if (sl_bg != 8) |
|
colour_set_bg(&sl_stdgc, sl_bg); |
|
sl_attr = options_get_number(&s->options, "status-left-attr"); |
|
if (sl_attr != 0) |
|
sl_stdgc.attr = sl_attr; |
|
sr_fg = options_get_number(&s->options, "status-right-fg"); |
|
if (sr_fg != 8) |
|
colour_set_fg(&sr_stdgc, sr_fg); |
|
sr_bg = options_get_number(&s->options, "status-right-bg"); |
|
if (sr_bg != 8) |
|
colour_set_bg(&sr_stdgc, sr_bg); |
|
sr_attr = options_get_number(&s->options, "status-right-attr"); |
|
if (sr_attr != 0) |
|
sr_stdgc.attr = sr_attr; |
|
|
|
yy = c->tty.sy - 1; |
/* If the height is one line, blank status line. */ |
if (yy == 0) |
if (c->tty.sy <= 1) |
goto blank; |
goto out; |
|
|
/* Caring about UTF-8 in status line? */ |
/* Get UTF-8 flag. */ |
utf8flag = options_get_number(&s->options, "status-utf8"); |
utf8flag = options_get_number(&s->options, "status-utf8"); |
|
|
/* Work out the left and right strings. */ |
/* Work out left and right strings. */ |
left = status_replace(c, NULL, options_get_string( |
memcpy(&lgc, &stdgc, sizeof lgc); |
&s->options, "status-left"), c->status_timer.tv_sec, 1); |
left = status_redraw_get_left(c, t, utf8flag, &lgc, &llen); |
llen = options_get_number(&s->options, "status-left-length"); |
memcpy(&rgc, &stdgc, sizeof rgc); |
llen2 = screen_write_cstrlen(utf8flag, "%s", left); |
right = status_redraw_get_right(c, t, utf8flag, &rgc, &rlen); |
if (llen2 < llen) |
|
llen = llen2; |
|
|
|
right = status_replace(c, NULL, options_get_string( |
|
&s->options, "status-right"), c->status_timer.tv_sec, 1); |
|
rlen = options_get_number(&s->options, "status-right-length"); |
|
rlen2 = screen_write_cstrlen(utf8flag, "%s", right); |
|
if (rlen2 < rlen) |
|
rlen = rlen2; |
|
|
|
/* |
/* |
* Figure out how much space we have for the window list. If there isn't |
* Figure out how much space we have for the window list. If there |
* enough space, just wimp out. |
* isn't enough space, just show a blank status line. |
*/ |
*/ |
xx = 0; |
needed = 0; |
if (llen != 0) |
if (llen != 0) |
xx += llen + 1; |
needed += llen + 1; |
if (rlen != 0) |
if (rlen != 0) |
xx += rlen + 1; |
needed += rlen + 1; |
if (c->tty.sx == 0 || c->tty.sx <= xx) |
if (c->tty.sx == 0 || c->tty.sx <= needed) |
goto blank; |
goto out; |
xx = c->tty.sx - xx; |
wlavailable = c->tty.sx - needed; |
|
|
/* |
/* Calculate the total size needed for the window list. */ |
* Right. We have xx characters to fill. Find out how much is to go in |
wlstart = wloffset = wlwidth = 0; |
* them and the offset of the current window (it must be on screen). |
|
*/ |
|
width = offset = 0; |
|
RB_FOREACH(wl, winlinks, &s->windows) { |
RB_FOREACH(wl, winlinks, &s->windows) { |
size = status_width(c, wl, c->status_timer.tv_sec) + 1; |
if (wl->status_text != NULL) |
|
xfree(wl->status_text); |
|
memcpy(&wl->status_cell, &stdgc, sizeof wl->status_cell); |
|
wl->status_text = status_print(c, wl, t, &wl->status_cell); |
|
wl->status_width = |
|
screen_write_cstrlen(utf8flag, "%s", wl->status_text); |
|
|
if (wl == s->curw) |
if (wl == s->curw) |
offset = width; |
wloffset = wlwidth; |
width += size; |
wlwidth += wl->status_width + 1; |
} |
} |
start = 0; |
|
|
|
/* If there is enough space for the total width, all is gravy. */ |
/* Create a new screen for the window list. */ |
if (width <= xx) |
screen_init(&window_list, wlwidth, 1, 0); |
|
|
|
/* And draw the window list into it. */ |
|
screen_write_start(&ctx, NULL, &window_list); |
|
RB_FOREACH(wl, winlinks, &s->windows) { |
|
screen_write_cnputs(&ctx, |
|
-1, &wl->status_cell, utf8flag, "%s", wl->status_text); |
|
screen_write_putc(&ctx, &stdgc, ' '); |
|
} |
|
screen_write_stop(&ctx); |
|
|
|
/* If there is enough space for the total width, skip to draw now. */ |
|
if (wlwidth <= wlavailable) |
goto draw; |
goto draw; |
|
|
/* Find size of current window text. */ |
/* Find size of current window text. */ |
size = status_width(c, s->curw, c->status_timer.tv_sec); |
wlsize = s->curw->status_width; |
|
|
/* |
/* |
* If the offset is already on screen, we're good to draw from the |
* If the current window is already on screen, good to draw from the |
* start and just leave off the end. |
* start and just leave off the end. |
*/ |
*/ |
if (offset + size < xx) { |
if (wloffset + wlsize < wlavailable) { |
if (xx > 0) { |
if (wlavailable > 0) { |
rarrow = 1; |
rarrow = 1; |
xx--; |
wlavailable--; |
} |
} |
|
wlwidth = wlavailable; |
width = xx; |
|
goto draw; |
|
} |
|
|
|
/* |
|
* Work out how many characters we need to omit from the start. There |
|
* are xx characters to fill, and offset + size must be the last. So, |
|
* the start character is offset + size - xx. |
|
*/ |
|
if (xx > 0) { |
|
larrow = 1; |
|
xx--; |
|
} |
|
|
|
start = offset + size - xx; |
|
if (xx > 0 && width > start + xx + 1) { /* + 1, eh? */ |
|
rarrow = 1; |
|
start++; |
|
xx--; |
|
} |
|
width = xx; |
|
|
|
draw: |
|
/* Bail here if anything is too small too. XXX. */ |
|
if (width == 0 || xx == 0) |
|
goto blank; |
|
|
|
/* Begin drawing and move to the starting position. */ |
|
screen_write_start(&ctx, NULL, &c->status); |
|
if (llen != 0) { |
|
screen_write_cursormove(&ctx, 0, yy); |
|
screen_write_cnputs(&ctx, llen, &sl_stdgc, utf8flag, "%s", left); |
|
screen_write_putc(&ctx, &stdgc, ' '); |
|
if (larrow) |
|
screen_write_putc(&ctx, &stdgc, ' '); |
|
} else { |
} else { |
if (larrow) |
/* |
screen_write_cursormove(&ctx, 1, yy); |
* Work out how many characters we need to omit from the |
else |
* start. There are wlavailable characters to fill, and |
screen_write_cursormove(&ctx, 0, yy); |
* wloffset + wlsize must be the last. So, the start character |
|
* is wloffset + wlsize - wlavailable. |
|
*/ |
|
if (wlavailable > 0) { |
|
larrow = 1; |
|
wlavailable--; |
|
} |
|
|
|
wlstart = wloffset + wlsize - wlavailable; |
|
if (wlavailable > 0 && wlwidth > wlstart + wlavailable + 1) { |
|
rarrow = 1; |
|
wlstart++; |
|
wlavailable--; |
|
} |
|
wlwidth = wlavailable; |
} |
} |
|
|
ox = 0; |
/* Bail if anything is now too small too. */ |
if (width < xx) { |
if (wlwidth == 0 || wlavailable == 0) { |
switch (options_get_number(&s->options, "status-justify")) { |
screen_free(&window_list); |
case 1: /* centered */ |
goto out; |
ox = 1 + (xx - width) / 2; |
|
break; |
|
case 2: /* right */ |
|
ox = 1 + (xx - width); |
|
break; |
|
} |
|
xx -= ox; |
|
while (ox-- > 0) |
|
screen_write_putc(&ctx, &stdgc, ' '); |
|
} |
} |
|
|
/* Draw each character in succession. */ |
/* |
|
* Now the start position is known, work out the state of the left and |
|
* right arrows. |
|
*/ |
offset = 0; |
offset = 0; |
RB_FOREACH(wl, winlinks, &s->windows) { |
RB_FOREACH(wl, winlinks, &s->windows) { |
memcpy(&gc, &stdgc, sizeof gc); |
if (larrow == 1 && offset < wlstart) { |
text = status_print(c, wl, c->status_timer.tv_sec, &gc); |
|
|
|
if (larrow == 1 && offset < start) { |
|
if (session_alert_has(s, wl, WINDOW_ACTIVITY)) |
if (session_alert_has(s, wl, WINDOW_ACTIVITY)) |
larrow = -1; |
larrow = -1; |
else if (session_alert_has(s, wl, WINDOW_BELL)) |
else if (session_alert_has(s, wl, WINDOW_BELL)) |
|
|
larrow = -1; |
larrow = -1; |
} |
} |
|
|
ptr = text; |
offset += wl->status_width; |
for (; offset < start; offset++) |
|
ptr++; /* XXX should skip UTF-8 characters */ |
|
if (offset < start + width) { |
|
screen_write_cnputs(&ctx, |
|
start + width - offset, &gc, utf8flag, "%s", text); |
|
offset += screen_write_cstrlen(utf8flag, "%s", text); |
|
} |
|
|
|
if (rarrow == 1 && offset > start + width) { |
if (rarrow == 1 && offset > wlstart + wlwidth) { |
if (session_alert_has(s, wl, WINDOW_ACTIVITY)) |
if (session_alert_has(s, wl, WINDOW_ACTIVITY)) |
rarrow = -1; |
rarrow = -1; |
else if (session_alert_has(s, wl, WINDOW_BELL)) |
else if (session_alert_has(s, wl, WINDOW_BELL)) |
|
|
else if (session_alert_has(s, wl, WINDOW_CONTENT)) |
else if (session_alert_has(s, wl, WINDOW_CONTENT)) |
rarrow = -1; |
rarrow = -1; |
} |
} |
|
|
if (offset < start + width) { |
|
if (offset >= start) { |
|
screen_write_putc(&ctx, &stdgc, ' '); |
|
} |
|
offset++; |
|
} |
|
|
|
xfree(text); |
|
} |
} |
|
|
/* Fill the remaining space if any. */ |
draw: |
while (offset++ < xx) |
/* Begin drawing. */ |
screen_write_putc(&ctx, &stdgc, ' '); |
screen_write_start(&ctx, NULL, &c->status); |
|
|
/* Draw the last item. */ |
/* Draw the left string and arrow. */ |
if (rlen != 0) { |
screen_write_cursormove(&ctx, 0, 0); |
screen_write_cursormove(&ctx, c->tty.sx - rlen - 1, yy); |
if (llen != 0) { |
|
screen_write_cnputs(&ctx, llen, &lgc, utf8flag, "%s", left); |
screen_write_putc(&ctx, &stdgc, ' '); |
screen_write_putc(&ctx, &stdgc, ' '); |
screen_write_cnputs(&ctx, rlen, &sr_stdgc, utf8flag, "%s", right); |
|
} |
} |
|
|
/* Draw the arrows. */ |
|
if (larrow != 0) { |
if (larrow != 0) { |
memcpy(&gc, &stdgc, sizeof gc); |
memcpy(&gc, &stdgc, sizeof gc); |
if (larrow == -1) |
if (larrow == -1) |
gc.attr ^= GRID_ATTR_REVERSE; |
gc.attr ^= GRID_ATTR_REVERSE; |
if (llen != 0) |
|
screen_write_cursormove(&ctx, llen + 1, yy); |
|
else |
|
screen_write_cursormove(&ctx, 0, yy); |
|
screen_write_putc(&ctx, &gc, '<'); |
screen_write_putc(&ctx, &gc, '<'); |
} |
} |
|
|
|
/* Draw the right string and arrow. */ |
if (rarrow != 0) { |
if (rarrow != 0) { |
|
screen_write_cursormove(&ctx, c->tty.sx - rlen - 2, 0); |
memcpy(&gc, &stdgc, sizeof gc); |
memcpy(&gc, &stdgc, sizeof gc); |
if (rarrow == -1) |
if (rarrow == -1) |
gc.attr ^= GRID_ATTR_REVERSE; |
gc.attr ^= GRID_ATTR_REVERSE; |
if (rlen != 0) |
|
screen_write_cursormove(&ctx, c->tty.sx - rlen - 2, yy); |
|
else |
|
screen_write_cursormove(&ctx, c->tty.sx - 1, yy); |
|
screen_write_putc(&ctx, &gc, '>'); |
screen_write_putc(&ctx, &gc, '>'); |
|
} else |
|
screen_write_cursormove(&ctx, c->tty.sx - rlen - 1, 0); |
|
if (rlen != 0) { |
|
screen_write_putc(&ctx, &stdgc, ' '); |
|
screen_write_cnputs(&ctx, rlen, &rgc, utf8flag, "%s", right); |
} |
} |
|
|
goto out; |
/* Figure out the offset for the window list. */ |
|
wloffset = 1; |
|
if (wlwidth < wlavailable) { |
|
switch (options_get_number(&s->options, "status-justify")) { |
|
case 1: /* centered */ |
|
wloffset = 1 + (wlavailable - wlwidth) / 2; |
|
break; |
|
case 2: /* right */ |
|
wloffset = 1 + (wlavailable - wlwidth); |
|
break; |
|
} |
|
} |
|
wloffset += llen; |
|
if (larrow != 0) |
|
wloffset++; |
|
|
blank: |
/* Copy the window list. */ |
/* Just draw the whole line as blank. */ |
screen_write_cursormove(&ctx, wloffset, 0); |
screen_write_start(&ctx, NULL, &c->status); |
screen_write_copy(&ctx, &window_list, wlstart, 0, wlwidth, 1); |
screen_write_cursormove(&ctx, 0, yy); |
screen_free(&window_list); |
for (offset = 0; offset < c->tty.sx; offset++) |
|
screen_write_putc(&ctx, &stdgc, ' '); |
|
|
|
out: |
|
screen_write_stop(&ctx); |
screen_write_stop(&ctx); |
|
|
|
out: |
if (left != NULL) |
if (left != NULL) |
xfree(left); |
xfree(left); |
if (right != NULL) |
if (right != NULL) |