diff --git a/cmd-join-pane.c b/cmd-join-pane.c index 36805c46..d860eeb1 100644 --- a/cmd-join-pane.c +++ b/cmd-join-pane.c @@ -146,7 +146,7 @@ cmd_join_pane_exec(struct cmd *self, struct cmdq_item *item) TAILQ_INSERT_BEFORE(dst_wp, src_wp, entry); else TAILQ_INSERT_AFTER(&dst_w->panes, dst_wp, src_wp, entry); - layout_assign_pane(lc, src_wp); + layout_assign_pane(lc, src_wp, 0); recalculate_sizes(); diff --git a/cmd-rotate-window.c b/cmd-rotate-window.c index 55c1dde2..450ffc17 100644 --- a/cmd-rotate-window.c +++ b/cmd-rotate-window.c @@ -52,7 +52,7 @@ cmd_rotate_window_exec(struct cmd *self, struct cmdq_item *item) struct layout_cell *lc; u_int sx, sy, xoff, yoff; - window_push_zoom(w, args_has(args, 'Z')); + window_push_zoom(w, 0, args_has(args, 'Z')); if (args_has(args, 'D')) { wp = TAILQ_LAST(&w->panes, window_panes); diff --git a/cmd-select-pane.c b/cmd-select-pane.c index fa388548..7871fe05 100644 --- a/cmd-select-pane.c +++ b/cmd-select-pane.c @@ -117,7 +117,7 @@ cmd_select_pane_exec(struct cmd *self, struct cmdq_item *item) server_redraw_window_borders(lastwp->window); server_status_window(lastwp->window); } else { - if (window_push_zoom(w, args_has(args, 'Z'))) + if (window_push_zoom(w, 0, args_has(args, 'Z'))) server_redraw_window(w); window_redraw_active_switch(w, lastwp); if (window_set_active_pane(w, lastwp, 1)) { @@ -171,19 +171,19 @@ cmd_select_pane_exec(struct cmd *self, struct cmdq_item *item) } if (args_has(args, 'L')) { - window_push_zoom(w, 1); + window_push_zoom(w, 0, 1); wp = window_pane_find_left(wp); window_pop_zoom(w); } else if (args_has(args, 'R')) { - window_push_zoom(w, 1); + window_push_zoom(w, 0, 1); wp = window_pane_find_right(wp); window_pop_zoom(w); } else if (args_has(args, 'U')) { - window_push_zoom(w, 1); + window_push_zoom(w, 0, 1); wp = window_pane_find_up(wp); window_pop_zoom(w); } else if (args_has(args, 'D')) { - window_push_zoom(w, 1); + window_push_zoom(w, 0, 1); wp = window_pane_find_down(wp); window_pop_zoom(w); } @@ -220,7 +220,7 @@ cmd_select_pane_exec(struct cmd *self, struct cmdq_item *item) activewp = w->active; if (wp == activewp) return (CMD_RETURN_NORMAL); - if (window_push_zoom(w, args_has(args, 'Z'))) + if (window_push_zoom(w, 0, args_has(args, 'Z'))) server_redraw_window(w); window_redraw_active_switch(w, wp); if (c != NULL && c->session != NULL && (c->flags & CLIENT_ACTIVEPANE)) diff --git a/cmd-split-window.c b/cmd-split-window.c index e5b3ac49..77b1eac7 100644 --- a/cmd-split-window.c +++ b/cmd-split-window.c @@ -39,8 +39,8 @@ const struct cmd_entry cmd_split_window_entry = { .name = "split-window", .alias = "splitw", - .args = { "bc:de:fF:hIl:p:Pt:v", 0, -1 }, - .usage = "[-bdefhIPv] [-c start-directory] [-e environment] " + .args = { "bc:de:fF:hIl:p:Pt:vZ", 0, -1 }, + .usage = "[-bdefhIPvZ] [-c start-directory] [-e environment] " "[-F format] [-l size] " CMD_TARGET_PANE_USAGE " [command]", .target = { 't', CMD_FIND_PANE, 0 }, @@ -110,7 +110,7 @@ cmd_split_window_exec(struct cmd *self, struct cmdq_item *item) } else size = -1; - server_unzoom_window(wp->window); + window_push_zoom(wp->window, 1, args_has(args, 'Z')); input = (args_has(args, 'I') && args->argc == 0); flags = 0; @@ -152,6 +152,8 @@ cmd_split_window_exec(struct cmd *self, struct cmdq_item *item) sc.flags = flags; if (args_has(args, 'd')) sc.flags |= SPAWN_DETACHED; + if (args_has(args, 'Z')) + sc.flags |= SPAWN_ZOOM; if ((new_wp = spawn_pane(&sc, &cause)) == NULL) { cmdq_error(item, "create pane failed: %s", cause); @@ -168,6 +170,7 @@ cmd_split_window_exec(struct cmd *self, struct cmdq_item *item) } if (!args_has(args, 'd')) cmd_find_from_winlink_pane(current, wl, new_wp, 0); + window_pop_zoom(wp->window); server_redraw_window(wp->window); server_status_session(s); diff --git a/cmd-swap-pane.c b/cmd-swap-pane.c index dd981b9a..12bc20b4 100644 --- a/cmd-swap-pane.c +++ b/cmd-swap-pane.c @@ -58,7 +58,7 @@ cmd_swap_pane_exec(struct cmd *self, struct cmdq_item *item) src_w = source->wl->window; src_wp = source->wp; - if (window_push_zoom(dst_w, args_has(args, 'Z'))) + if (window_push_zoom(dst_w, 0, args_has(args, 'Z'))) server_redraw_window(dst_w); if (args_has(args, 'D')) { @@ -73,7 +73,7 @@ cmd_swap_pane_exec(struct cmd *self, struct cmdq_item *item) src_wp = TAILQ_LAST(&dst_w->panes, window_panes); } - if (src_w != dst_w && window_push_zoom(src_w, args_has(args, 'Z'))) + if (src_w != dst_w && window_push_zoom(src_w, 0, args_has(args, 'Z'))) server_redraw_window(src_w); if (src_wp == dst_wp) diff --git a/cmd-switch-client.c b/cmd-switch-client.c index fc7f9d75..b10496e3 100644 --- a/cmd-switch-client.c +++ b/cmd-switch-client.c @@ -118,7 +118,7 @@ cmd_switch_client_exec(struct cmd *self, struct cmdq_item *item) return (CMD_RETURN_NORMAL); if (wl != NULL && wp != NULL && wp != wl->window->active) { w = wl->window; - if (window_push_zoom(w, args_has(args, 'Z'))) + if (window_push_zoom(w, 0, args_has(args, 'Z'))) server_redraw_window(w); window_redraw_active_switch(w, wp); window_set_active_pane(w, wp, 1); diff --git a/format-draw.c b/format-draw.c index 67b961d9..cf0bdf5f 100644 --- a/format-draw.c +++ b/format-draw.c @@ -157,13 +157,14 @@ format_draw_put_list(struct screen_write_ctx *octx, static void format_draw_none(struct screen_write_ctx *octx, u_int available, u_int ocx, u_int ocy, struct screen *left, struct screen *centre, struct screen *right, - struct format_ranges *frs) + struct screen *abs_centre, struct format_ranges *frs) { - u_int width_left, width_centre, width_right; + u_int width_left, width_centre, width_right, width_abs_centre; width_left = left->cx; width_centre = centre->cx; width_right = right->cx; + width_abs_centre = abs_centre->cx; /* * Try to keep as much of the left and right as possible at the expense @@ -199,23 +200,34 @@ format_draw_none(struct screen_write_ctx *octx, u_int available, u_int ocx, - width_centre / 2, centre->cx / 2 - width_centre / 2, width_centre); + + /* + * Write abs_centre in the perfect centre of all horizontal space. + */ + if (width_abs_centre > available) + width_abs_centre = available; + format_draw_put(octx, ocx, ocy, abs_centre, frs, + (available - width_abs_centre) / 2, + 0, + width_abs_centre); } /* Draw format with list on the left. */ static void format_draw_left(struct screen_write_ctx *octx, u_int available, u_int ocx, u_int ocy, struct screen *left, struct screen *centre, struct screen *right, - struct screen *list, struct screen *list_left, struct screen *list_right, - struct screen *after, int focus_start, int focus_end, - struct format_ranges *frs) + struct screen *abs_centre, struct screen *list, struct screen *list_left, + struct screen *list_right, struct screen *after, int focus_start, + int focus_end, struct format_ranges *frs) { u_int width_left, width_centre, width_right; - u_int width_list, width_after; + u_int width_list, width_after, width_abs_centre; struct screen_write_ctx ctx; width_left = left->cx; width_centre = centre->cx; width_right = right->cx; + width_abs_centre = abs_centre->cx; width_list = list->cx; width_after = after->cx; @@ -247,7 +259,7 @@ format_draw_left(struct screen_write_ctx *octx, u_int available, u_int ocx, screen_write_stop(&ctx); format_draw_none(octx, available, ocx, ocy, left, centre, - right, frs); + right, abs_centre, frs); return; } @@ -291,23 +303,34 @@ format_draw_left(struct screen_write_ctx *octx, u_int available, u_int ocx, focus_start = focus_end = 0; format_draw_put_list(octx, ocx, ocy, width_left, width_list, list, list_left, list_right, focus_start, focus_end, frs); + + /* + * Write abs_centre in the perfect centre of all horizontal space. + */ + if (width_abs_centre > available) + width_abs_centre = available; + format_draw_put(octx, ocx, ocy, abs_centre, frs, + (available - width_abs_centre) / 2, + 0, + width_abs_centre); } /* Draw format with list in the centre. */ static void format_draw_centre(struct screen_write_ctx *octx, u_int available, u_int ocx, u_int ocy, struct screen *left, struct screen *centre, struct screen *right, - struct screen *list, struct screen *list_left, struct screen *list_right, - struct screen *after, int focus_start, int focus_end, - struct format_ranges *frs) + struct screen *abs_centre, struct screen *list, struct screen *list_left, + struct screen *list_right, struct screen *after, int focus_start, + int focus_end, struct format_ranges *frs) { - u_int width_left, width_centre, width_right; - u_int width_list, width_after, middle; + u_int width_left, width_centre, width_right, middle; + u_int width_list, width_after, width_abs_centre; struct screen_write_ctx ctx; width_left = left->cx; width_centre = centre->cx; width_right = right->cx; + width_abs_centre = abs_centre->cx; width_list = list->cx; width_after = after->cx; @@ -339,7 +362,7 @@ format_draw_centre(struct screen_write_ctx *octx, u_int available, u_int ocx, screen_write_stop(&ctx); format_draw_none(octx, available, ocx, ocy, left, centre, - right, frs); + right, abs_centre, frs); return; } @@ -388,23 +411,34 @@ format_draw_centre(struct screen_write_ctx *octx, u_int available, u_int ocx, format_draw_put_list(octx, ocx, ocy, middle - width_list / 2, width_list, list, list_left, list_right, focus_start, focus_end, frs); + + /* + * Write abs_centre in the perfect centre of all horizontal space. + */ + if (width_abs_centre > available) + width_abs_centre = available; + format_draw_put(octx, ocx, ocy, abs_centre, frs, + (available - width_abs_centre) / 2, + 0, + width_abs_centre); } /* Draw format with list on the right. */ static void format_draw_right(struct screen_write_ctx *octx, u_int available, u_int ocx, u_int ocy, struct screen *left, struct screen *centre, struct screen *right, - struct screen *list, struct screen *list_left, struct screen *list_right, - struct screen *after, int focus_start, int focus_end, - struct format_ranges *frs) + struct screen *abs_centre, struct screen *list, + struct screen *list_left, struct screen *list_right, struct screen *after, + int focus_start, int focus_end, struct format_ranges *frs) { u_int width_left, width_centre, width_right; - u_int width_list, width_after; + u_int width_list, width_after, width_abs_centre; struct screen_write_ctx ctx; width_left = left->cx; width_centre = centre->cx; width_right = right->cx; + width_abs_centre = abs_centre->cx; width_list = list->cx; width_after = after->cx; @@ -436,7 +470,7 @@ format_draw_right(struct screen_write_ctx *octx, u_int available, u_int ocx, screen_write_stop(&ctx); format_draw_none(octx, available, ocx, ocy, left, centre, - right, frs); + right, abs_centre, frs); return; } @@ -484,6 +518,118 @@ format_draw_right(struct screen_write_ctx *octx, u_int available, u_int ocx, format_draw_put_list(octx, ocx, ocy, available - width_list - width_after, width_list, list, list_left, list_right, focus_start, focus_end, frs); + + /* + * Write abs_centre in the perfect centre of all horizontal space. + */ + if (width_abs_centre > available) + width_abs_centre = available; + format_draw_put(octx, ocx, ocy, abs_centre, frs, + (available - width_abs_centre) / 2, + 0, + width_abs_centre); +} + +static void +format_draw_absolute_centre(struct screen_write_ctx *octx, u_int available, + u_int ocx, u_int ocy, struct screen *left, struct screen *centre, + struct screen *right, struct screen *abs_centre, struct screen *list, + struct screen *list_left, struct screen *list_right, struct screen *after, + int focus_start, int focus_end, struct format_ranges *frs) +{ + u_int width_left, width_centre, width_right, width_abs_centre; + u_int width_list, width_after, middle, abs_centre_offset; + + width_left = left->cx; + width_centre = centre->cx; + width_right = right->cx; + width_abs_centre = abs_centre->cx; + width_list = list->cx; + width_after = after->cx; + + /* + * Trim first centre, then the right, then the left. + */ + while (width_left + + width_centre + + width_right > available) { + if (width_centre > 0) + width_centre--; + else if (width_right > 0) + width_right--; + else + width_left--; + } + + /* + * We trim list after and abs_centre independently, as we are drawing + * them over the rest. Trim first the list, then after the list, then + * abs_centre. + */ + while (width_list + width_after + width_abs_centre > available) { + if (width_list > 0) + width_list--; + else if (width_after > 0) + width_after--; + else + width_abs_centre--; + } + + /* Write left at 0. */ + format_draw_put(octx, ocx, ocy, left, frs, 0, 0, width_left); + + /* Write right at available - width_right. */ + format_draw_put(octx, ocx, ocy, right, frs, + available - width_right, + right->cx - width_right, + width_right); + + /* + * Keep writing centre at the relative centre. Only the list is written + * in the absolute centre of the horizontal space. + */ + middle = (width_left + ((available - width_right) - width_left) / 2); + + /* + * Write centre at + * middle - width_centre. + */ + format_draw_put(octx, ocx, ocy, centre, frs, + middle - width_centre, + 0, + width_centre); + + /* + * If there is no focus given, keep the centre in focus. + */ + if (focus_start == -1 || focus_end == -1) + focus_start = focus_end = list->cx / 2; + + /* + * We centre abs_centre and the list together, so their shared centre is + * in the perfect centre of horizontal space. + */ + abs_centre_offset = (available - width_list - width_abs_centre) / 2; + + /* + * Write abs_centre before the list. + */ + format_draw_put(octx, ocx, ocy, abs_centre, frs, abs_centre_offset, + 0, width_abs_centre); + abs_centre_offset += width_abs_centre; + + /* + * Draw the list in the absolute centre + */ + format_draw_put_list(octx, ocx, ocy, abs_centre_offset, width_list, + list, list_left, list_right, focus_start, focus_end, frs); + abs_centre_offset += width_list; + + /* + * Write after at the end of the centre + */ + format_draw_put(octx, ocx, ocy, after, frs, abs_centre_offset, 0, + width_after); } /* Draw multiple characters. */ @@ -506,6 +652,7 @@ format_draw(struct screen_write_ctx *octx, const struct grid_cell *base, enum { LEFT, CENTRE, RIGHT, + ABSOLUTE_CENTRE, LIST, LIST_LEFT, LIST_RIGHT, @@ -514,6 +661,7 @@ format_draw(struct screen_write_ctx *octx, const struct grid_cell *base, const char *names[] = { "LEFT", "CENTRE", "RIGHT", + "ABSOLUTE_CENTRE", "LIST", "LIST_LEFT", "LIST_RIGHT", @@ -522,7 +670,11 @@ format_draw(struct screen_write_ctx *octx, const struct grid_cell *base, struct screen *os = octx->s, s[TOTAL]; struct screen_write_ctx ctx[TOTAL]; u_int ocx = os->cx, ocy = os->cy, n, i, width[TOTAL]; - u_int map[] = { LEFT, LEFT, CENTRE, RIGHT }; + u_int map[] = { LEFT, + LEFT, + CENTRE, + RIGHT, + ABSOLUTE_CENTRE }; int focus_start = -1, focus_end = -1; int list_state = -1, fill = -1, even; enum style_align list_align = STYLE_ALIGN_DEFAULT; @@ -789,25 +941,35 @@ format_draw(struct screen_write_ctx *octx, const struct grid_cell *base, case STYLE_ALIGN_DEFAULT: /* No list. */ format_draw_none(octx, available, ocx, ocy, &s[LEFT], - &s[CENTRE], &s[RIGHT], &frs); + &s[CENTRE], &s[RIGHT], &s[ABSOLUTE_CENTRE], &frs); break; case STYLE_ALIGN_LEFT: /* List is part of the left. */ format_draw_left(octx, available, ocx, ocy, &s[LEFT], - &s[CENTRE], &s[RIGHT], &s[LIST], &s[LIST_LEFT], - &s[LIST_RIGHT], &s[AFTER], focus_start, focus_end, &frs); + &s[CENTRE], &s[RIGHT], &s[ABSOLUTE_CENTRE], &s[LIST], + &s[LIST_LEFT], &s[LIST_RIGHT], &s[AFTER], + focus_start, focus_end, &frs); break; case STYLE_ALIGN_CENTRE: /* List is part of the centre. */ format_draw_centre(octx, available, ocx, ocy, &s[LEFT], - &s[CENTRE], &s[RIGHT], &s[LIST], &s[LIST_LEFT], - &s[LIST_RIGHT], &s[AFTER], focus_start, focus_end, &frs); + &s[CENTRE], &s[RIGHT], &s[ABSOLUTE_CENTRE], &s[LIST], + &s[LIST_LEFT], &s[LIST_RIGHT], &s[AFTER], + focus_start, focus_end, &frs); break; case STYLE_ALIGN_RIGHT: /* List is part of the right. */ format_draw_right(octx, available, ocx, ocy, &s[LEFT], - &s[CENTRE], &s[RIGHT], &s[LIST], &s[LIST_LEFT], - &s[LIST_RIGHT], &s[AFTER], focus_start, focus_end, &frs); + &s[CENTRE], &s[RIGHT], &s[ABSOLUTE_CENTRE], &s[LIST], + &s[LIST_LEFT], &s[LIST_RIGHT], &s[AFTER], + focus_start, focus_end, &frs); + break; + case STYLE_ALIGN_ABSOLUTE_CENTRE: + /* List is in the centre of the entire horizontal space. */ + format_draw_absolute_centre(octx, available, ocx, ocy, &s[LEFT], + &s[CENTRE], &s[RIGHT], &s[ABSOLUTE_CENTRE], &s[LIST], + &s[LIST_LEFT], &s[LIST_RIGHT], &s[AFTER], + focus_start, focus_end, &frs); break; } diff --git a/format.c b/format.c index d3c7508a..0e8ea8f3 100644 --- a/format.c +++ b/format.c @@ -41,7 +41,6 @@ struct format_expand_state; static char *format_job_get(struct format_expand_state *, const char *); -static void format_job_timer(int, short, void *); static char *format_expand1(struct format_expand_state *, const char *); static int format_replace(struct format_expand_state *, const char *, size_t, char **, size_t *, size_t *); @@ -69,7 +68,6 @@ struct format_job { }; /* Format job tree. */ -static struct event format_job_event; static int format_job_cmp(struct format_job *, struct format_job *); static RB_HEAD(format_job_tree, format_job) format_jobs = RB_INITIALIZER(); RB_GENERATE_STATIC(format_job_tree, format_job, entry, format_job_cmp); @@ -437,6 +435,19 @@ format_job_tidy(struct format_job_tree *jobs, int force) } } +/* Tidy old jobs for all clients. */ +void +format_tidy_jobs(void) +{ + struct client *c; + + format_job_tidy(&format_jobs, 0); + TAILQ_FOREACH(c, &clients, entry) { + if (c->jobs != NULL) + format_job_tidy(c->jobs, 0); + } +} + /* Remove old jobs for client. */ void format_lost_client(struct client *c) @@ -446,23 +457,6 @@ format_lost_client(struct client *c) free(c->jobs); } -/* Remove old jobs periodically. */ -static void -format_job_timer(__unused int fd, __unused short events, __unused void *arg) -{ - struct client *c; - struct timeval tv = { .tv_sec = 60 }; - - format_job_tidy(&format_jobs, 0); - TAILQ_FOREACH(c, &clients, entry) { - if (c->jobs != NULL) - format_job_tidy(c->jobs, 0); - } - - evtimer_del(&format_job_event); - evtimer_add(&format_job_event, &tv); -} - /* Wrapper for asprintf. */ static char * printflike(1, 2) format_printf(const char *fmt, ...) @@ -3048,11 +3042,6 @@ format_create(struct client *c, struct cmdq_item *item, int tag, int flags) { struct format_tree *ft; - if (!event_initialized(&format_job_event)) { - evtimer_set(&format_job_event, format_job_timer, NULL); - format_job_timer(-1, 0, NULL); - } - ft = xcalloc(1, sizeof *ft); RB_INIT(&ft->tree); diff --git a/grid-reader.c b/grid-reader.c index c011ea1d..ae2f4d2b 100644 --- a/grid-reader.c +++ b/grid-reader.c @@ -172,7 +172,7 @@ grid_reader_cursor_next_word(struct grid_reader *gr, const char *separators) /* Do not break up wrapped words. */ if (grid_get_line(gr->gd, gr->cy)->flags & GRID_LINE_WRAPPED) - xx = grid_reader_line_length(gr) - 1; + xx = gr->gd->sx - 1; else xx = grid_reader_line_length(gr); yy = gr->gd->hsize + gr->gd->sy - 1; @@ -197,7 +197,7 @@ grid_reader_cursor_next_word(struct grid_reader *gr, const char *separators) if (grid_get_line(gr->gd, gr->cy)->flags & GRID_LINE_WRAPPED) - xx = grid_reader_line_length(gr) - 1; + xx = gr->gd->sx - 1; else xx = grid_reader_line_length(gr); } else @@ -216,7 +216,7 @@ grid_reader_cursor_next_word_end(struct grid_reader *gr, const char *separators) /* Do not break up wrapped words. */ if (grid_get_line(gr->gd, gr->cy)->flags & GRID_LINE_WRAPPED) - xx = grid_reader_line_length(gr) - 1; + xx = gr->gd->sx - 1; else xx = grid_reader_line_length(gr); yy = gr->gd->hsize + gr->gd->sy - 1; @@ -241,7 +241,7 @@ grid_reader_cursor_next_word_end(struct grid_reader *gr, const char *separators) if (grid_get_line(gr->gd, gr->cy)->flags & GRID_LINE_WRAPPED) - xx = grid_reader_line_length(gr) - 1; + xx = gr->gd->sx - 1; else xx = grid_reader_line_length(gr); } else @@ -294,7 +294,7 @@ grid_reader_cursor_previous_word(struct grid_reader *gr, const char *separators, GRID_LINE_WRAPPED) break; grid_reader_cursor_up(gr); - grid_reader_cursor_end_of_line(gr, 0, 0); + grid_reader_cursor_end_of_line(gr, 0, 1); } if (gr->cx > 0) gr->cx--; diff --git a/grid.c b/grid.c index 1822f2b5..7744587a 100644 --- a/grid.c +++ b/grid.c @@ -265,9 +265,6 @@ grid_free_lines(struct grid *gd, u_int py, u_int ny) for (yy = py; yy < py + ny; yy++) grid_free_line(gd, yy); -#ifdef HAVE_MALLOC_TRIM - malloc_trim(0); -#endif } /* Create a new grid. */ diff --git a/layout-custom.c b/layout-custom.c index 097dabe6..e7fb4253 100644 --- a/layout-custom.c +++ b/layout-custom.c @@ -233,7 +233,7 @@ layout_parse(struct window *w, const char *layout) /* Update pane offsets and sizes. */ layout_fix_offsets(w); - layout_fix_panes(w); + layout_fix_panes(w, NULL); recalculate_sizes(); layout_print_cell(lc, __func__, 0); diff --git a/layout-set.c b/layout-set.c index 9ef28416..c702817d 100644 --- a/layout-set.c +++ b/layout-set.c @@ -160,7 +160,7 @@ layout_set_even(struct window *w, enum layout_type type) /* Fix cell offsets. */ layout_fix_offsets(w); - layout_fix_panes(w); + layout_fix_panes(w, NULL); layout_print_cell(w->layout_root, __func__, 1); @@ -270,7 +270,7 @@ layout_set_main_h(struct window *w) /* Fix cell offsets. */ layout_fix_offsets(w); - layout_fix_panes(w); + layout_fix_panes(w, NULL); layout_print_cell(w->layout_root, __func__, 1); @@ -368,7 +368,7 @@ layout_set_main_v(struct window *w) /* Fix cell offsets. */ layout_fix_offsets(w); - layout_fix_panes(w); + layout_fix_panes(w, NULL); layout_print_cell(w->layout_root, __func__, 1); @@ -477,7 +477,7 @@ layout_set_tiled(struct window *w) /* Fix cell offsets. */ layout_fix_offsets(w); - layout_fix_panes(w); + layout_fix_panes(w, NULL); layout_print_cell(w->layout_root, __func__, 1); diff --git a/layout.c b/layout.c index 37214d02..04a13b0c 100644 --- a/layout.c +++ b/layout.c @@ -286,7 +286,7 @@ layout_add_border(struct window *w, struct layout_cell *lc, int status) /* Update pane offsets and sizes based on their cells. */ void -layout_fix_panes(struct window *w) +layout_fix_panes(struct window *w, struct window_pane *skip) { struct window_pane *wp; struct layout_cell *lc; @@ -294,7 +294,7 @@ layout_fix_panes(struct window *w) status = options_get_number(w->options, "pane-border-status"); TAILQ_FOREACH(wp, &w->panes, entry) { - if ((lc = wp->layout_cell) == NULL) + if ((lc = wp->layout_cell) == NULL || wp == skip) continue; wp->xoff = lc->xoff; @@ -482,7 +482,7 @@ layout_init(struct window *w, struct window_pane *wp) lc = w->layout_root = layout_create_cell(NULL); layout_set_size(lc, w->sx, w->sy, 0, 0); layout_make_leaf(lc, wp); - layout_fix_panes(w); + layout_fix_panes(w, NULL); } void @@ -540,7 +540,7 @@ layout_resize(struct window *w, u_int sx, u_int sy) /* Fix cell offsets. */ layout_fix_offsets(w); - layout_fix_panes(w); + layout_fix_panes(w, NULL); } /* Resize a pane to an absolute size. */ @@ -600,7 +600,7 @@ layout_resize_layout(struct window *w, struct layout_cell *lc, /* Fix cell offsets. */ layout_fix_offsets(w); - layout_fix_panes(w); + layout_fix_panes(w, NULL); notify_window("window-layout-changed", w); } @@ -704,10 +704,14 @@ layout_resize_pane_shrink(struct window *w, struct layout_cell *lc, /* Assign window pane to newly split cell. */ void -layout_assign_pane(struct layout_cell *lc, struct window_pane *wp) +layout_assign_pane(struct layout_cell *lc, struct window_pane *wp, + int do_not_resize) { layout_make_leaf(lc, wp); - layout_fix_panes(wp->window); + if (do_not_resize) + layout_fix_panes(wp->window, wp); + else + layout_fix_panes(wp->window, NULL); } /* Calculate the new pane size for resized parent. */ @@ -1040,7 +1044,7 @@ layout_close_pane(struct window_pane *wp) /* Fix pane offsets and sizes. */ if (w->layout_root != NULL) { layout_fix_offsets(w); - layout_fix_panes(w); + layout_fix_panes(w, NULL); } notify_window("window-layout-changed", w); } @@ -1109,7 +1113,7 @@ layout_spread_out(struct window_pane *wp) do { if (layout_spread_cell(w, parent)) { layout_fix_offsets(w); - layout_fix_panes(w); + layout_fix_panes(w, NULL); break; } } while ((parent = parent->parent) != NULL); diff --git a/options-table.c b/options-table.c index a6f07cf9..b185969c 100644 --- a/options-table.c +++ b/options-table.c @@ -45,7 +45,7 @@ static const char *options_table_status_keys_list[] = { "emacs", "vi", NULL }; static const char *options_table_status_justify_list[] = { - "left", "centre", "right", NULL + "left", "centre", "right", "absolute-centre", NULL }; static const char *options_table_status_position_list[] = { "top", "bottom", NULL diff --git a/options.c b/options.c index 9bc89db3..52f4f67e 100644 --- a/options.c +++ b/options.c @@ -1115,7 +1115,7 @@ options_push_changes(const char *name) } if (strcmp(name, "pane-border-status") == 0) { RB_FOREACH(w, windows, &windows) - layout_fix_panes(w); + layout_fix_panes(w, NULL); } RB_FOREACH(s, sessions, &sessions) status_update_cache(s); diff --git a/server.c b/server.c index 0260898c..0b878d9e 100644 --- a/server.c +++ b/server.c @@ -46,6 +46,7 @@ static int server_fd = -1; static uint64_t server_client_flags; static int server_exit; static struct event server_ev_accept; +static struct event server_ev_tidy; struct cmd_find_state marked_pane; @@ -149,15 +150,33 @@ fail: return (-1); } +/* Tidy up every hour. */ +static void +server_tidy_event(__unused int fd, __unused short events, __unused void *data) +{ + struct timeval tv = { .tv_sec = 3600 }; + uint64_t t = get_timer(); + + format_tidy_jobs(); + +#ifdef HAVE_MALLOC_TRIM + malloc_trim(0); +#endif + + log_debug("%s: took %llu milliseconds", __func__, get_timer() - t); + evtimer_add(&server_ev_tidy, &tv); +} + /* Fork new server. */ int server_start(struct tmuxproc *client, int flags, struct event_base *base, int lockfd, char *lockfile) { - int fd; - sigset_t set, oldset; - struct client *c = NULL; - char *cause = NULL; + int fd; + sigset_t set, oldset; + struct client *c = NULL; + char *cause = NULL; + struct timeval tv = { .tv_sec = 3600 }; sigfillset(&set); sigprocmask(SIG_BLOCK, &set, &oldset); @@ -216,6 +235,9 @@ server_start(struct tmuxproc *client, int flags, struct event_base *base, free(cause); } + evtimer_set(&server_ev_tidy, server_tidy_event, NULL); + evtimer_add(&server_ev_tidy, &tv); + server_add_accept(0); proc_loop(server_proc, server_loop); diff --git a/spawn.c b/spawn.c index c47b11f4..565b7da5 100644 --- a/spawn.c +++ b/spawn.c @@ -259,7 +259,10 @@ spawn_pane(struct spawn_context *sc, char **cause) layout_init(w, new_wp); } else { new_wp = window_add_pane(w, sc->wp0, hlimit, sc->flags); - layout_assign_pane(sc->lc, new_wp); + if (sc->flags & SPAWN_ZOOM) + layout_assign_pane(sc->lc, new_wp, 1); + else + layout_assign_pane(sc->lc, new_wp, 0); } /* diff --git a/style.c b/style.c index 08614f9c..24b09882 100644 --- a/style.c +++ b/style.c @@ -139,6 +139,8 @@ style_parse(struct style *sy, const struct grid_cell *base, const char *in) sy->align = STYLE_ALIGN_CENTRE; else if (strcasecmp(tmp + 6, "right") == 0) sy->align = STYLE_ALIGN_RIGHT; + else if (strcasecmp(tmp + 6, "absolute-centre") == 0) + sy->align = STYLE_ALIGN_ABSOLUTE_CENTRE; else goto error; } else if (end > 5 && strncasecmp(tmp, "fill=", 5) == 0) { @@ -227,6 +229,8 @@ style_tostring(struct style *sy) tmp = "centre"; else if (sy->align == STYLE_ALIGN_RIGHT) tmp = "right"; + else if (sy->align == STYLE_ALIGN_ABSOLUTE_CENTRE) + tmp = "absolute-centre"; off += xsnprintf(s + off, sizeof s - off, "%salign=%s", comma, tmp); comma = ","; diff --git a/tmux.1 b/tmux.1 index 4611cc20..c79950ce 100644 --- a/tmux.1 +++ b/tmux.1 @@ -2804,7 +2804,7 @@ is given and the selected window is already the current window, the command behaves like .Ic last-window . .It Xo Ic split-window -.Op Fl bdfhIvP +.Op Fl bdfhIvPZ .Op Fl c Ar start-directory .Op Fl e Ar environment .Op Fl l Ar size @@ -2840,6 +2840,8 @@ option creates a new pane spanning the full window height (with or full window width (with .Fl v ) , instead of splitting the active pane. +.Fl Z +zooms if the window is not zoomed, or keeps it zoomed if already zoomed. .Pp An empty .Ar shell-command @@ -3813,10 +3815,11 @@ seconds. By default, updates will occur every 15 seconds. A setting of zero disables redrawing at interval. .It Xo Ic status-justify -.Op Ic left | centre | right +.Op Ic left | centre | right | absolute-centre .Xc -Set the position of the window list component of the status line: left, centre -or right justified. +Set the position of the window list in the status line: left, centre or right. +centre puts the window list in the relative centre of the available free space; +absolute-centre uses the centre of the entire horizontal space. .It Xo Ic status-keys .Op Ic vi | emacs .Xc diff --git a/tmux.h b/tmux.h index 69610940..ca71559f 100644 --- a/tmux.h +++ b/tmux.h @@ -741,7 +741,8 @@ enum style_align { STYLE_ALIGN_DEFAULT, STYLE_ALIGN_LEFT, STYLE_ALIGN_CENTRE, - STYLE_ALIGN_RIGHT + STYLE_ALIGN_RIGHT, + STYLE_ALIGN_ABSOLUTE_CENTRE }; /* Style list. */ @@ -1863,6 +1864,7 @@ struct spawn_context { #define SPAWN_NONOTIFY 0x10 #define SPAWN_FULLSIZE 0x20 #define SPAWN_EMPTY 0x40 +#define SPAWN_ZOOM 0x80 }; /* Mode tree sort order. */ @@ -1946,6 +1948,7 @@ char *paste_make_sample(struct paste_buffer *); struct format_tree; struct format_modifier; typedef void *(*format_cb)(struct format_tree *); +void format_tidy_jobs(void); const char *format_skip(const char *, const char *); int format_true(const char *); struct format_tree *format_create(struct client *, struct cmdq_item *, int, @@ -2753,7 +2756,7 @@ void window_resize(struct window *, u_int, u_int, int, int); void window_pane_send_resize(struct window_pane *, int); int window_zoom(struct window_pane *); int window_unzoom(struct window *); -int window_push_zoom(struct window *, int); +int window_push_zoom(struct window *, int, int); int window_pop_zoom(struct window *); void window_lost_pane(struct window *, struct window_pane *); void window_remove_pane(struct window *, struct window_pane *); @@ -2816,7 +2819,7 @@ void layout_set_size(struct layout_cell *, u_int, u_int, u_int, void layout_make_leaf(struct layout_cell *, struct window_pane *); void layout_make_node(struct layout_cell *, enum layout_type); void layout_fix_offsets(struct window *); -void layout_fix_panes(struct window *); +void layout_fix_panes(struct window *, struct window_pane *); void layout_resize_adjust(struct window *, struct layout_cell *, enum layout_type, int); void layout_init(struct window *, struct window_pane *); @@ -2826,7 +2829,8 @@ void layout_resize_pane(struct window_pane *, enum layout_type, int, int); void layout_resize_pane_to(struct window_pane *, enum layout_type, u_int); -void layout_assign_pane(struct layout_cell *, struct window_pane *); +void layout_assign_pane(struct layout_cell *, struct window_pane *, + int); struct layout_cell *layout_split_pane(struct window_pane *, enum layout_type, int, int); void layout_close_pane(struct window_pane *); diff --git a/window-copy.c b/window-copy.c index 4558ed48..3fc7ad3e 100644 --- a/window-copy.c +++ b/window-copy.c @@ -1759,12 +1759,15 @@ window_copy_cmd_select_line(struct window_copy_cmd_state *cs) window_copy_cursor_start_of_line(wme); data->selrx = data->cx; data->selry = screen_hsize(data->backing) + data->cy - data->oy; - data->endselrx = window_copy_find_length(wme, data->selry); data->endselry = data->selry; window_copy_start_selection(wme); - for (; np > 1; np--) - window_copy_cursor_down(wme, 0); window_copy_cursor_end_of_line(wme); + data->endselry = screen_hsize(data->backing) + data->cy - data->oy; + data->endselrx = window_copy_find_length(wme, data->endselry); + for (; np > 1; np--) { + window_copy_cursor_down(wme, 0); + window_copy_cursor_end_of_line(wme); + } return (WINDOW_COPY_CMD_REDRAW); } @@ -1775,7 +1778,7 @@ window_copy_cmd_select_word(struct window_copy_cmd_state *cs) struct window_mode_entry *wme = cs->wme; struct session *s = cs->s; struct window_copy_mode_data *data = wme->data; - u_int px, py; + u_int px, py, nextx, nexty; data->lineflag = LINE_SEL_LEFT_RIGHT; data->rectflag = 0; @@ -1791,8 +1794,16 @@ window_copy_cmd_select_word(struct window_copy_cmd_state *cs) data->selry = py; window_copy_start_selection(wme); + /* Handle single character words. */ + nextx = px + 1; + nexty = py; + if (grid_get_line(data->backing->grid, nexty)->flags & + GRID_LINE_WRAPPED && nextx > screen_size_x(data->backing) - 1) { + nextx = 0; + nexty++; + } if (px >= window_copy_find_length(wme, py) || - !window_copy_in_set(wme, px + 1, py, data->ws)) + !window_copy_in_set(wme, nextx, nexty, data->ws)) window_copy_cursor_next_word_end(wme, data->ws, 1); else { window_copy_update_cursor(wme, px, data->cy); @@ -1801,7 +1812,10 @@ window_copy_cmd_select_word(struct window_copy_cmd_state *cs) } data->endselrx = data->cx; data->endselry = screen_hsize(data->backing) + data->cy - data->oy; - if (data->dx > data->endselrx) + if (data->dy > data->endselry) { + data->dy = data->endselry; + data->dx = data->endselrx; + } else if (data->dx > data->endselrx) data->dx = data->endselrx; return (WINDOW_COPY_CMD_REDRAW); @@ -3352,8 +3366,11 @@ window_copy_match_at_cursor(struct window_copy_mode_data *data) cy = screen_hsize(data->backing) - data->oy + data->cy; if (window_copy_search_mark_at(data, data->cx, cy, &at) != 0) return (NULL); - if (data->searchmark[at] == 0) - return (NULL); + if (data->searchmark[at] == 0) { + /* Allow one position after the match. */ + if (at == 0 || data->searchmark[--at] == 0) + return (NULL); + } window_copy_match_start_end(data, at, &start, &end); /* @@ -3635,6 +3652,8 @@ window_copy_synchronize_cursor_end(struct window_mode_entry *wme, int begin, data->endsely = data->endselry; } else { /* Left to right selection. */ + if (yy < data->endselry) + yy = data->endselry; xx = window_copy_find_length(wme, yy); /* Reset the start. */ @@ -3929,8 +3948,12 @@ window_copy_get_selection(struct window_mode_entry *wme, size_t *len) *len = 0; return (NULL); } - if (keys == MODEKEY_EMACS || lastex <= ey_last) - off -= 1; /* remove final \n (unless at end in vi mode) */ + /* Remove final \n (unless at end in vi mode). */ + if (keys == MODEKEY_EMACS || lastex <= ey_last) { + if (~grid_get_line(data->backing->grid, ey)->flags & + GRID_LINE_WRAPPED || lastex != ey_last) + off -= 1; + } *len = off; return (buf); } @@ -4531,6 +4554,7 @@ window_copy_cursor_next_word(struct window_mode_entry *wme, data->oy, oldy, px, py, 0); } +/* Compute the next place where a word ends. */ static void window_copy_cursor_next_word_end_pos(struct window_mode_entry *wme, const char *separators, u_int *ppx, u_int *ppy) @@ -4539,47 +4563,27 @@ window_copy_cursor_next_word_end_pos(struct window_mode_entry *wme, struct window_copy_mode_data *data = wme->data; struct options *oo = wp->window->options; struct screen *back_s = data->backing; - u_int px, py, xx, yy; - int keys, expected = 1; + struct grid_reader gr; + u_int px, py, hsize; + int keys; px = data->cx; - py = screen_hsize(back_s) + data->cy - data->oy; - xx = window_copy_find_length(wme, py); - yy = screen_hsize(back_s) + screen_size_y(back_s) - 1; + hsize = screen_hsize(back_s); + py = hsize + data->cy - data->oy; + grid_reader_start(&gr, back_s->grid, px, py); keys = options_get_number(oo, "mode-keys"); - if (keys == MODEKEY_VI && !window_copy_in_set(wme, px, py, separators)) - px++; - - /* - * First skip past any word characters, then any non-word characters. - * - * expected is initially set to 1 for the former and then 0 for the - * latter. - */ - do { - while (px > xx || - window_copy_in_set(wme, px, py, separators) == expected) { - /* Move down if we're past the end of the line. */ - if (px > xx) { - if (py == yy) - return; - py++; - px = 0; - xx = window_copy_find_length(wme, py); - } else - px++; - } - expected = !expected; - } while (expected == 0); - - if (keys == MODEKEY_VI && px != 0) - px--; - + if (keys == MODEKEY_VI && !grid_reader_in_set(&gr, separators)) + grid_reader_cursor_right(&gr, 0, 0); + grid_reader_cursor_next_word_end(&gr, separators); + if (keys == MODEKEY_VI) + grid_reader_cursor_left(&gr); + grid_reader_get_cursor(&gr, &px, &py); *ppx = px; *ppy = py; } +/* Move to the next place where a word ends. */ static void window_copy_cursor_next_word_end(struct window_mode_entry *wme, const char *separators, int no_reset) @@ -4615,42 +4619,17 @@ window_copy_cursor_previous_word_pos(struct window_mode_entry *wme, const char *separators, int already, u_int *ppx, u_int *ppy) { struct window_copy_mode_data *data = wme->data; + struct screen *back_s = data->backing; + struct grid_reader gr; u_int px, py, hsize; - hsize = screen_hsize(data->backing); px = data->cx; + hsize = screen_hsize(back_s); py = hsize + data->cy - data->oy; - /* Move back to the previous word character. */ - if (already || window_copy_in_set(wme, px, py, separators)) { - for (;;) { - if (px > 0) { - px--; - if (!window_copy_in_set(wme, px, py, - separators)) - break; - } else { - if (py == 0 || - (data->cy == 0 && - (hsize == 0 || data->oy > hsize - 1))) - goto out; - - py--; - px = window_copy_find_length(wme, py); - - /* Stop if separator at EOL. */ - if (px > 0 && window_copy_in_set(wme, px - 1, - py, separators)) - break; - } - } - } - - /* Move back to the beginning of this word. */ - while (px > 0 && !window_copy_in_set(wme, px - 1, py, separators)) - px--; - -out: + grid_reader_start(&gr, back_s->grid, px, py); + grid_reader_cursor_previous_word(&gr, separators, already); + grid_reader_get_cursor(&gr, &px, &py); *ppx = px; *ppy = py; } diff --git a/window.c b/window.c index a41385ce..38c1913c 100644 --- a/window.c +++ b/window.c @@ -629,18 +629,18 @@ window_unzoom(struct window *w) wp->layout_cell = wp->saved_layout_cell; wp->saved_layout_cell = NULL; } - layout_fix_panes(w); + layout_fix_panes(w, NULL); notify_window("window-layout-changed", w); return (0); } int -window_push_zoom(struct window *w, int flag) +window_push_zoom(struct window *w, int always, int flag) { log_debug("%s: @%u %d", __func__, w->id, flag && (w->flags & WINDOW_ZOOMED)); - if (flag && (w->flags & WINDOW_ZOOMED)) + if (flag && (always || (w->flags & WINDOW_ZOOMED))) w->flags |= WINDOW_WASZOOMED; else w->flags &= ~WINDOW_WASZOOMED;