diff --git a/layout.c b/layout.c index f4e05e70..eada12a8 100644 --- a/layout.c +++ b/layout.c @@ -502,14 +502,14 @@ layout_resize_pane_mouse(struct client *c, struct mouse_event *mouse) wp->yoff <= 1 + c->last_mouse.y && wp->yoff + wp->sy >= c->last_mouse.y) { layout_resize_pane(wp, LAYOUT_LEFTRIGHT, - mouse->x - c->last_mouse.x); + mouse->x - c->last_mouse.x); pane_border = 1; } if (wp->yoff + wp->sy == c->last_mouse.y && wp->xoff <= 1 + c->last_mouse.x && wp->xoff + wp->sx >= c->last_mouse.x) { layout_resize_pane(wp, LAYOUT_TOPBOTTOM, - mouse->y - c->last_mouse.y); + mouse->y - c->last_mouse.y); pane_border = 1; } } diff --git a/options-table.c b/options-table.c index 36544707..d5b8d216 100644 --- a/options-table.c +++ b/options-table.c @@ -47,6 +47,9 @@ const char *options_table_status_keys_list[] = { const char *options_table_status_justify_list[] = { "left", "centre", "right", NULL }; +const char *options_table_status_position_list[] = { + "top", "bottom", NULL +}; const char *options_table_bell_action_list[] = { "none", "any", "current", NULL }; @@ -358,6 +361,12 @@ const struct options_table_entry session_options_table[] = { .default_num = 10 }, + { .name = "status-position", + .type = OPTIONS_TABLE_CHOICE, + .choices = options_table_status_position_list, + .default_num = 1 + }, + { .name = "status-right", .type = OPTIONS_TABLE_STRING, .default_str = "\"#22T\" %H:%M %d-%b-%y" diff --git a/screen-redraw.c b/screen-redraw.c index af02c73b..3ad0e03a 100644 --- a/screen-redraw.c +++ b/screen-redraw.c @@ -170,25 +170,33 @@ void screen_redraw_screen(struct client *c, int status_only, int borders_only) { struct window *w = c->session->curw->window; + struct options *oo = &c->session->options; struct tty *tty = &c->tty; struct window_pane *wp; struct grid_cell active_gc, other_gc; - u_int i, j, type; - int status, fg, bg; + u_int i, j, type, top; + int status, spos, fg, bg; /* Suspended clients should not be updated. */ if (c->flags & CLIENT_SUSPENDED) return; /* Get status line, er, status. */ + spos = options_get_number(oo, "status-position"); if (c->message_string != NULL || c->prompt_string != NULL) status = 1; else - status = options_get_number(&c->session->options, "status"); + status = options_get_number(oo, "status"); + top = 0; + if (status && spos == 0) + top = 1; /* If only drawing status and it is present, don't need the rest. */ if (status_only && status) { - tty_draw_line(tty, &c->status, 0, 0, tty->sy - 1); + if (top) + tty_draw_line(tty, &c->status, 0, 0, 0); + else + tty_draw_line(tty, &c->status, 0, 0, tty->sy - 1); tty_reset(tty); return; } @@ -198,19 +206,23 @@ screen_redraw_screen(struct client *c, int status_only, int borders_only) memcpy(&active_gc, &grid_default_cell, sizeof active_gc); active_gc.data = other_gc.data = 'x'; /* not space */ active_gc.attr = other_gc.attr = GRID_ATTR_CHARSET; - fg = options_get_number(&c->session->options, "pane-border-fg"); + fg = options_get_number(oo, "pane-border-fg"); colour_set_fg(&other_gc, fg); - bg = options_get_number(&c->session->options, "pane-border-bg"); + bg = options_get_number(oo, "pane-border-bg"); colour_set_bg(&other_gc, bg); - fg = options_get_number(&c->session->options, "pane-active-border-fg"); + fg = options_get_number(oo, "pane-active-border-fg"); colour_set_fg(&active_gc, fg); - bg = options_get_number(&c->session->options, "pane-active-border-bg"); + bg = options_get_number(oo, "pane-active-border-bg"); colour_set_bg(&active_gc, bg); /* Draw background and borders. */ for (j = 0; j < tty->sy - status; j++) { - if (status_only && j != tty->sy - 1) - continue; + if (status_only) { + if (spos == 1 && j != tty->sy - 1) + continue; + else if (spos == 0 && j != 0) + break; + } for (i = 0; i < tty->sx; i++) { type = screen_redraw_check_cell(c, i, j); if (type == CELL_INSIDE) @@ -219,7 +231,7 @@ screen_redraw_screen(struct client *c, int status_only, int borders_only) tty_attributes(tty, &active_gc); else tty_attributes(tty, &other_gc); - tty_cursor(tty, i, j); + tty_cursor(tty, i, top + j); tty_putc(tty, CELL_BORDERS[type]); } } @@ -233,17 +245,26 @@ screen_redraw_screen(struct client *c, int status_only, int borders_only) if (!window_pane_visible(wp)) continue; for (i = 0; i < wp->sy; i++) { - if (status_only && wp->yoff + i != tty->sy - 1) - continue; - tty_draw_line(tty, wp->screen, i, wp->xoff, wp->yoff); + if (status_only) { + if (spos == 1 && wp->yoff + i != tty->sy - 1) + continue; + else if (spos == 0 && wp->yoff + i != 0) + break; + } + tty_draw_line( + tty, wp->screen, i, wp->xoff, top + wp->yoff); } if (c->flags & CLIENT_IDENTIFY) screen_redraw_draw_number(c, wp); } /* Draw the status line. */ - if (status) - tty_draw_line(tty, &c->status, 0, 0, tty->sy - 1); + if (status) { + if (top) + tty_draw_line(tty, &c->status, 0, 0, 0); + else + tty_draw_line(tty, &c->status, 0, 0, tty->sy - 1); + } tty_reset(tty); } @@ -251,10 +272,14 @@ screen_redraw_screen(struct client *c, int status_only, int borders_only) void screen_redraw_pane(struct client *c, struct window_pane *wp) { - u_int i; + u_int i, yoff; + + yoff = wp->yoff; + if (status_at_line(c) == 0) + yoff++; for (i = 0; i < wp->sy; i++) - tty_draw_line(&c->tty, wp->screen, i, wp->xoff, wp->yoff); + tty_draw_line(&c->tty, wp->screen, i, wp->xoff, yoff); tty_reset(&c->tty); } diff --git a/server-client.c b/server-client.c index 6d485ae1..8865865b 100644 --- a/server-client.c +++ b/server-client.c @@ -26,6 +26,8 @@ #include "tmux.h" +void server_client_check_mouse(struct client *c, + struct window_pane *wp, struct mouse_event *mouse); void server_client_handle_key(int, struct mouse_event *, void *); void server_client_repeat_timer(int, short, void *); void server_client_check_exit(struct client *); @@ -261,6 +263,65 @@ server_client_status_timer(void) } } +/* Check for mouse keys. */ +void +server_client_check_mouse( + struct client *c, struct window_pane *wp, struct mouse_event *mouse) +{ + struct session *s = c->session; + struct options *oo = &s->options; + int statusat; + + statusat = status_at_line(c); + + /* Is this a window selection click on the status line? */ + if (statusat != -1 && mouse->y == (u_int)statusat && + options_get_number(oo, "mouse-select-window")) { + if (mouse->b == MOUSE_UP && c->last_mouse.b != MOUSE_UP) { + status_set_window_at(c, mouse->x); + return; + } + if (mouse->b & MOUSE_45) { + if ((mouse->b & MOUSE_BUTTON) == MOUSE_1) { + session_previous(c->session, 0); + server_redraw_session(s); + } + if ((mouse->b & MOUSE_BUTTON) == MOUSE_2) { + session_next(c->session, 0); + server_redraw_session(s); + } + return; + } + } + + /* + * Not on status line - adjust mouse position if status line is at the + * top and limit if at the bottom. From here on a struct mouse + * represents the offset onto the window itself. + */ + if (statusat == 0 &&mouse->y > 0) + mouse->y--; + else if (statusat > 0 && mouse->y >= (u_int)statusat) + mouse->y = statusat - 1; + + /* Is this a pane selection? Allow down only in copy mode. */ + if (options_get_number(oo, "mouse-select-pane") && + ((!(mouse->b & MOUSE_DRAG) && mouse->b != MOUSE_UP) || + wp->mode != &window_copy_mode)) { + window_set_active_at(wp->window, mouse->x, mouse->y); + server_redraw_window_borders(wp->window); + wp = wp->window->active; /* may have changed */ + } + + /* Check if trying to resize pane. */ + if (options_get_number(oo, "mouse-resize-pane")) + layout_resize_pane_mouse(c, mouse); + + /* Update last and pass through to client. */ + memcpy(&c->last_mouse, mouse, sizeof c->last_mouse); + window_pane_mouse(wp, c->session, mouse); +} + /* Handle data key input from client. */ void server_client_handle_key(int key, struct mouse_event *mouse, void *data) @@ -316,43 +377,7 @@ server_client_handle_key(int key, struct mouse_event *mouse, void *data) if (key == KEYC_MOUSE) { if (c->flags & CLIENT_READONLY) return; - if (options_get_number(oo, "mouse-select-pane") && - (!(options_get_number(oo, "status") && - mouse->y + 1 == c->tty.sy)) && - ((!(mouse->b & MOUSE_DRAG) && mouse->b != MOUSE_UP) || - wp->mode != &window_copy_mode)) { - /* - * Allow pane switching in copy mode only by mouse down - * (click). - */ - window_set_active_at(w, mouse->x, mouse->y); - server_redraw_window_borders(w); - wp = w->active; - } - if (mouse->y + 1 == c->tty.sy && - options_get_number(oo, "mouse-select-window") && - options_get_number(oo, "status")) { - if (mouse->b == MOUSE_UP && - c->last_mouse.b != MOUSE_UP) { - status_set_window_at(c, mouse->x); - return; - } - if (mouse->b & MOUSE_45) { - if ((mouse->b & MOUSE_BUTTON) == MOUSE_1) { - session_previous(c->session, 0); - server_redraw_session(s); - } - if ((mouse->b & MOUSE_BUTTON) == MOUSE_2) { - session_next(c->session, 0); - server_redraw_session(s); - } - return; - } - } - if (options_get_number(oo, "mouse-resize-pane")) - layout_resize_pane_mouse(c, mouse); - memcpy(&c->last_mouse, mouse, sizeof c->last_mouse); - window_pane_mouse(wp, c->session, mouse); + server_client_check_mouse(c, wp, mouse); return; } @@ -471,7 +496,7 @@ server_client_reset_state(struct client *c) struct screen *s = wp->screen; struct options *oo = &c->session->options; struct options *wo = &w->options; - int status, mode; + int status, mode, o; if (c->flags & CLIENT_SUSPENDED) return; @@ -481,8 +506,10 @@ server_client_reset_state(struct client *c) status = options_get_number(oo, "status"); if (!window_pane_visible(wp) || wp->yoff + s->cy >= c->tty.sy - status) tty_cursor(&c->tty, 0, 0); - else - tty_cursor(&c->tty, wp->xoff + s->cx, wp->yoff + s->cy); + else { + o = status && options_get_number (oo, "status-position") == 0; + tty_cursor(&c->tty, wp->xoff + s->cx, o + wp->yoff + s->cy); + } /* * Resizing panes with the mouse requires at least button mode to give diff --git a/status.c b/status.c index 34d8f471..4df6745d 100644 --- a/status.c +++ b/status.c @@ -60,6 +60,20 @@ status_out_cmp(struct status_out *so1, struct status_out *so2) return (strcmp(so1->cmd, so2->cmd)); } +/* Get screen line of status line. -1 means off. */ +int +status_at_line(struct client *c) +{ + struct session *s = c->session; + + if (!options_get_number(&s->options, "status")) + return (-1); + + if (options_get_number(&s->options, "status-position") == 0) + return (0); + return (c->tty.sy - 1); +} + /* Retrieve options for left string. */ char * status_redraw_get_left(struct client *c, diff --git a/tmux.1 b/tmux.1 index a4a26631..c84d5039 100644 --- a/tmux.1 +++ b/tmux.1 @@ -2203,6 +2203,10 @@ Set the maximum .Ar length of the left component of the status bar. The default is 10. +.It Xo Ic status-position +.Op Ic top | bottom +.Xc +Set the position of the status line. .It Ic status-right Ar string Display .Ar string diff --git a/tmux.h b/tmux.h index 162bee00..069c53ef 100644 --- a/tmux.h +++ b/tmux.h @@ -1074,6 +1074,9 @@ struct tty_ctx { u_int orupper; u_int orlower; + u_int xoff; + u_int yoff; + /* Saved last cell on line. */ struct grid_cell last_cell; struct grid_utf8 last_utf8; @@ -1459,8 +1462,8 @@ void tty_draw_line(struct tty *, struct screen *, u_int, u_int, u_int); int tty_open(struct tty *, const char *, char **); void tty_close(struct tty *); void tty_free(struct tty *); -void tty_write(void (*)( - struct tty *, const struct tty_ctx *), const struct tty_ctx *); +void tty_write( + void (*)(struct tty *, const struct tty_ctx *), struct tty_ctx *); void tty_cmd_alignmenttest(struct tty *, const struct tty_ctx *); void tty_cmd_cell(struct tty *, const struct tty_ctx *); void tty_cmd_clearendofline(struct tty *, const struct tty_ctx *); @@ -1718,6 +1721,7 @@ void server_update_event(struct client *); /* status.c */ int status_out_cmp(struct status_out *, struct status_out *); RB_PROTOTYPE(status_out_tree, status_out, entry, status_out_cmp); +int status_at_line(struct client *); void status_free_jobs(struct status_out_tree *); void status_update_jobs(struct client *); void status_set_window_at(struct client *, u_int); diff --git a/tty.c b/tty.c index d248a889..7febed33 100644 --- a/tty.c +++ b/tty.c @@ -513,10 +513,10 @@ tty_redraw_region(struct tty *tty, const struct tty_ctx *ctx) if (ctx->ocy < ctx->orupper || ctx->ocy > ctx->orlower) { for (i = ctx->ocy; i < screen_size_y(s); i++) - tty_draw_line(tty, s, i, wp->xoff, wp->yoff); + tty_draw_line(tty, s, i, ctx->xoff, ctx->yoff); } else { for (i = ctx->orupper; i <= ctx->orlower; i++) - tty_draw_line(tty, s, i, wp->xoff, wp->yoff); + tty_draw_line(tty, s, i, ctx->xoff, ctx->yoff); } } @@ -585,11 +585,13 @@ tty_draw_line(struct tty *tty, struct screen *s, u_int py, u_int ox, u_int oy) } void -tty_write(void (*cmdfn)( - struct tty *, const struct tty_ctx *), const struct tty_ctx *ctx) +tty_write( + void (*cmdfn)(struct tty *, const struct tty_ctx *), struct tty_ctx *ctx) { struct window_pane *wp = ctx->wp; struct client *c; + struct session *s; + struct options *oo; u_int i; /* wp can be NULL if updating the screen but not the terminal. */ @@ -607,12 +609,20 @@ tty_write(void (*cmdfn)( continue; if (c->flags & CLIENT_SUSPENDED) continue; + s = c->session; - if (c->session->curw->window == wp->window) { + if (s->curw->window == wp->window) { if (c->tty.term == NULL) continue; if (c->tty.flags & (TTY_FREEZE|TTY_BACKOFF)) continue; + oo = &s->options; + + ctx->xoff = wp->xoff; + ctx->yoff = wp->yoff; + if (status_at_line(c) == 0) + ctx->yoff++; + cmdfn(&c->tty, ctx); } } @@ -625,8 +635,8 @@ tty_cmd_insertcharacter(struct tty *tty, const struct tty_ctx *ctx) struct screen *s = wp->screen; u_int i; - if (wp->xoff != 0 || screen_size_x(s) < tty->sx) { - tty_draw_line(tty, wp->screen, ctx->ocy, wp->xoff, wp->yoff); + if (ctx->xoff != 0 || screen_size_x(s) < tty->sx) { + tty_draw_line(tty, wp->screen, ctx->ocy, ctx->xoff, ctx->yoff); return; } @@ -644,7 +654,7 @@ tty_cmd_insertcharacter(struct tty *tty, const struct tty_ctx *ctx) tty_putc(tty, ' '); tty_putcode(tty, TTYC_RMIR); } else - tty_draw_line(tty, wp->screen, ctx->ocy, wp->xoff, wp->yoff); + tty_draw_line(tty, wp->screen, ctx->ocy, ctx->xoff, ctx->yoff); } void @@ -653,10 +663,10 @@ tty_cmd_deletecharacter(struct tty *tty, const struct tty_ctx *ctx) struct window_pane *wp = ctx->wp; struct screen *s = wp->screen; - if (wp->xoff != 0 || screen_size_x(s) < tty->sx || + if (ctx->xoff != 0 || screen_size_x(s) < tty->sx || (!tty_term_has(tty->term, TTYC_DCH) && !tty_term_has(tty->term, TTYC_DCH1))) { - tty_draw_line(tty, wp->screen, ctx->ocy, wp->xoff, wp->yoff); + tty_draw_line(tty, wp->screen, ctx->ocy, ctx->xoff, ctx->yoff); return; } @@ -675,7 +685,7 @@ tty_cmd_insertline(struct tty *tty, const struct tty_ctx *ctx) struct window_pane *wp = ctx->wp; struct screen *s = wp->screen; - if (wp->xoff != 0 || screen_size_x(s) < tty->sx || + if (ctx->xoff != 0 || screen_size_x(s) < tty->sx || !tty_term_has(tty->term, TTYC_CSR) || !tty_term_has(tty->term, TTYC_IL1)) { tty_redraw_region(tty, ctx); @@ -696,7 +706,7 @@ tty_cmd_deleteline(struct tty *tty, const struct tty_ctx *ctx) struct window_pane *wp = ctx->wp; struct screen *s = wp->screen; - if (wp->xoff != 0 || screen_size_x(s) < tty->sx || + if (ctx->xoff != 0 || screen_size_x(s) < tty->sx || !tty_term_has(tty->term, TTYC_CSR) || !tty_term_has(tty->term, TTYC_DL1)) { tty_redraw_region(tty, ctx); @@ -722,7 +732,7 @@ tty_cmd_clearline(struct tty *tty, const struct tty_ctx *ctx) tty_cursor_pane(tty, ctx, 0, ctx->ocy); - if (wp->xoff == 0 && screen_size_x(s) >= tty->sx && + if (ctx->xoff == 0 && screen_size_x(s) >= tty->sx && tty_term_has(tty->term, TTYC_EL)) { tty_putcode(tty, TTYC_EL); } else { @@ -742,7 +752,7 @@ tty_cmd_clearendofline(struct tty *tty, const struct tty_ctx *ctx) tty_cursor_pane(tty, ctx, ctx->ocx, ctx->ocy); - if (wp->xoff == 0 && screen_size_x(s) >= tty->sx && + if (ctx->xoff == 0 && screen_size_x(s) >= tty->sx && tty_term_has(tty->term, TTYC_EL)) tty_putcode(tty, TTYC_EL); else { @@ -754,12 +764,11 @@ tty_cmd_clearendofline(struct tty *tty, const struct tty_ctx *ctx) void tty_cmd_clearstartofline(struct tty *tty, const struct tty_ctx *ctx) { - struct window_pane *wp = ctx->wp; - u_int i; + u_int i; tty_reset(tty); - if (wp->xoff == 0 && tty_term_has(tty->term, TTYC_EL1)) { + if (ctx->xoff == 0 && tty_term_has(tty->term, TTYC_EL1)) { tty_cursor_pane(tty, ctx, ctx->ocx, ctx->ocy); tty_putcode(tty, TTYC_EL1); } else { @@ -778,7 +787,7 @@ tty_cmd_reverseindex(struct tty *tty, const struct tty_ctx *ctx) if (ctx->ocy != ctx->orupper) return; - if (wp->xoff != 0 || screen_size_x(s) < tty->sx || + if (ctx->xoff != 0 || screen_size_x(s) < tty->sx || !tty_term_has(tty->term, TTYC_CSR) || !tty_term_has(tty->term, TTYC_RI)) { tty_redraw_region(tty, ctx); @@ -802,7 +811,7 @@ tty_cmd_linefeed(struct tty *tty, const struct tty_ctx *ctx) if (ctx->ocy != ctx->orlower) return; - if (wp->xoff != 0 || screen_size_x(s) < tty->sx || + if (ctx->xoff != 0 || screen_size_x(s) < tty->sx || !tty_term_has(tty->term, TTYC_CSR)) { tty_redraw_region(tty, ctx); return; @@ -836,7 +845,7 @@ tty_cmd_clearendofscreen(struct tty *tty, const struct tty_ctx *ctx) tty_region_pane(tty, ctx, 0, screen_size_y(s) - 1); tty_cursor_pane(tty, ctx, ctx->ocx, ctx->ocy); - if (wp->xoff == 0 && screen_size_x(s) >= tty->sx && + if (ctx->xoff == 0 && screen_size_x(s) >= tty->sx && tty_term_has(tty->term, TTYC_EL)) { tty_putcode(tty, TTYC_EL); if (ctx->ocy != screen_size_y(s) - 1) { @@ -872,7 +881,7 @@ tty_cmd_clearstartofscreen(struct tty *tty, const struct tty_ctx *ctx) tty_region_pane(tty, ctx, 0, screen_size_y(s) - 1); tty_cursor_pane(tty, ctx, 0, 0); - if (wp->xoff == 0 && screen_size_x(s) >= tty->sx && + if (ctx->xoff == 0 && screen_size_x(s) >= tty->sx && tty_term_has(tty->term, TTYC_EL)) { for (i = 0; i < ctx->ocy; i++) { tty_putcode(tty, TTYC_EL); @@ -902,7 +911,7 @@ tty_cmd_clearscreen(struct tty *tty, const struct tty_ctx *ctx) tty_region_pane(tty, ctx, 0, screen_size_y(s) - 1); tty_cursor_pane(tty, ctx, 0, 0); - if (wp->xoff == 0 && screen_size_x(s) >= tty->sx && + if (ctx->xoff == 0 && screen_size_x(s) >= tty->sx && tty_term_has(tty->term, TTYC_EL)) { for (i = 0; i < screen_size_y(s); i++) { tty_putcode(tty, TTYC_EL); @@ -957,7 +966,7 @@ tty_cmd_cell(struct tty *tty, const struct tty_ctx *ctx) /* Is the cursor in the very last position? */ if (ctx->ocx > wp->sx - width) { - if (wp->xoff != 0 || wp->sx != tty->sx) { + if (ctx->xoff != 0 || wp->sx != tty->sx) { /* * The pane doesn't fill the entire line, the linefeed * will already have happened, so just move the cursor. @@ -991,7 +1000,7 @@ tty_cmd_utf8character(struct tty *tty, const struct tty_ctx *ctx) * Cannot rely on not being a partial character, so just redraw the * whole line. */ - tty_draw_line(tty, wp->screen, ctx->ocy, wp->xoff, wp->yoff); + tty_draw_line(tty, wp->screen, ctx->ocy, ctx->xoff, ctx->yoff); } void @@ -1078,9 +1087,7 @@ void tty_region_pane( struct tty *tty, const struct tty_ctx *ctx, u_int rupper, u_int rlower) { - struct window_pane *wp = ctx->wp; - - tty_region(tty, wp->yoff + rupper, wp->yoff + rlower); + tty_region(tty, ctx->yoff + rupper, ctx->yoff + rlower); } /* Set region at absolute position. */ @@ -1112,9 +1119,7 @@ tty_region(struct tty *tty, u_int rupper, u_int rlower) void tty_cursor_pane(struct tty *tty, const struct tty_ctx *ctx, u_int cx, u_int cy) { - struct window_pane *wp = ctx->wp; - - tty_cursor(tty, wp->xoff + cx, wp->yoff + cy); + tty_cursor(tty, ctx->xoff + cx, ctx->yoff + cy); } /* Move cursor to absolute position. */