diff --git a/cmd-break-pane.c b/cmd-break-pane.c index 4fe6397c9..dcd4e8188 100644 --- a/cmd-break-pane.c +++ b/cmd-break-pane.c @@ -1,4 +1,4 @@ -/* $OpenBSD: cmd-break-pane.c,v 1.74 2026/07/15 13:02:33 nicm Exp $ */ +/* $OpenBSD: cmd-break-pane.c,v 1.75 2026/07/23 09:38:27 nicm Exp $ */ /* * Copyright (c) 2009 Nicholas Marriott @@ -172,6 +172,7 @@ cmd_break_pane_exec(struct cmd *self, struct cmdq_item *item) w->name = clean_name(name, 0); options_set_number(w->options, "automatic-rename", 0); } + window_set_fill_cells(w); layout_init(w, wp); wp->flags |= PANE_CHANGED; diff --git a/options-table.c b/options-table.c index f73fae4d8..ebe1fd9ff 100644 --- a/options-table.c +++ b/options-table.c @@ -1,4 +1,4 @@ -/* $OpenBSD: options-table.c,v 1.240 2026/07/21 11:52:13 nicm Exp $ */ +/* $OpenBSD: options-table.c,v 1.241 2026/07/23 09:38:27 nicm Exp $ */ /* * Copyright (c) 2011 Nicholas Marriott @@ -1459,8 +1459,8 @@ const struct options_table_entry options_table[] = { { .name = "fill-character", .type = OPTIONS_TABLE_STRING, .scope = OPTIONS_TABLE_WINDOW, - .default_str = "", - .text = "Character used to fill unused parts of window." + .default_str = "#{?is_inside,#[bg=themedarkgrey] ,#[fg=themelightgrey]#[acs]~}", + .text = "Format used to fill unused parts of window." }, { .name = "main-pane-height", diff --git a/options.c b/options.c index b5238bc69..c3d948020 100644 --- a/options.c +++ b/options.c @@ -1,4 +1,4 @@ -/* $OpenBSD: options.c,v 1.90 2026/07/10 13:38:45 nicm Exp $ */ +/* $OpenBSD: options.c,v 1.91 2026/07/23 09:38:27 nicm Exp $ */ /* * Copyright (c) 2008 Nicholas Marriott @@ -1372,7 +1372,7 @@ options_push_changes(const char *name) } if (strcmp(name, "fill-character") == 0) { RB_FOREACH(w, windows, &windows) - window_set_fill_character(w); + window_set_fill_cells(w); } if (strcmp(name, "key-table") == 0) { TAILQ_FOREACH(loop, &clients, entry) diff --git a/screen-redraw.c b/screen-redraw.c index c58beb646..a09ea333e 100644 --- a/screen-redraw.c +++ b/screen-redraw.c @@ -1,4 +1,4 @@ -/* $OpenBSD: screen-redraw.c,v 1.155 2026/07/21 13:27:41 nicm Exp $ */ +/* $OpenBSD: screen-redraw.c,v 1.156 2026/07/23 09:38:27 nicm Exp $ */ /* * Copyright (c) 2026 Nicholas Marriott @@ -320,7 +320,7 @@ redraw_reset_cell(struct redraw_build_ctx *bctx, u_int x, u_int y) struct window *w = bctx->w; memset(bc, 0, sizeof *bc); - if (bctx->ox + x <= w->sx && bctx->oy + y <= w->sy) + if (bctx->ox + x < w->sx && bctx->oy + y < w->sy) bc->data.type = REDRAW_SPAN_EMPTY; else bc->data.type = REDRAW_SPAN_OUTSIDE; @@ -1232,9 +1232,15 @@ redraw_draw_border_span(struct redraw_draw_ctx *dctx, if (wp == NULL) { redraw_get_default_border_style(dctx, &gc, &pane_lines); - if (span->data.type != REDRAW_SPAN_BORDER) - pane_lines = PANE_LINES_SINGLE; - window_get_border_cell(w, NULL, pane_lines, cell_type, &gc); + if (span->data.type == REDRAW_SPAN_OUTSIDE) + window_get_fill_cell(w, 0, &gc); + else if (span->data.type == REDRAW_SPAN_EMPTY) + window_get_fill_cell(w, 1, &gc); + else { + if (span->data.type != REDRAW_SPAN_BORDER) + pane_lines = PANE_LINES_SINGLE; + window_get_border_cell(NULL, pane_lines, cell_type, &gc); + } } else { window_pane_get_border_style(wp, c, &gc); window_pane_get_border_cell(wp, cell_type, &gc); diff --git a/spawn.c b/spawn.c index 1b382202b..03553e70c 100644 --- a/spawn.c +++ b/spawn.c @@ -1,4 +1,4 @@ -/* $OpenBSD: spawn.c,v 1.49 2026/07/15 13:02:33 nicm Exp $ */ +/* $OpenBSD: spawn.c,v 1.50 2026/07/23 09:38:27 nicm Exp $ */ /* * Copyright (c) 2019 Nicholas Marriott @@ -222,6 +222,7 @@ spawn_window(struct spawn_context *sc, char **cause) w->name = xstrdup(sc->name); options_set_number(w->options, "automatic-rename", 0); } + window_set_fill_cells(w); } /* Switch to the new window if required. */ diff --git a/tmux.1 b/tmux.1 index 1a228db6a..2f543526c 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1,4 +1,4 @@ -.\" $OpenBSD: tmux.1,v 1.1148 2026/07/22 20:12:58 nicm Exp $ +.\" $OpenBSD: tmux.1,v 1.1149 2026/07/23 09:38:27 nicm Exp $ .\" .\" Copyright (c) 2007 Nicholas Marriott .\" @@ -14,7 +14,7 @@ .\" IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING .\" OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" -.Dd $Mdocdate: July 22 2026 $ +.Dd $Mdocdate: July 23 2026 $ .Dt TMUX 1 .Os .Sh NAME @@ -5714,8 +5714,13 @@ Set the time in milliseconds for which the indicators shown by the .Ic display\-panes command appear. .Pp -.It Ic fill\-character Ar character -Set the character used to fill areas of the terminal unused by a window. +.It Ic fill\-character Ar format +Set the format used to fill areas of the terminal unused by a pane. +The format is expanded once for areas inside the window with +.Ql is_inside +set, and once for areas outside the window with +.Ql is_outside +set. .Pp .It Ic main\-pane\-height Ar height .It Ic main\-pane\-width Ar width diff --git a/tmux.h b/tmux.h index 33b499bf2..444179b0a 100644 --- a/tmux.h +++ b/tmux.h @@ -1,4 +1,4 @@ -/* $OpenBSD: tmux.h,v 1.1414 2026/07/22 20:12:58 nicm Exp $ */ +/* $OpenBSD: tmux.h,v 1.1415 2026/07/23 09:38:27 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -1472,7 +1472,8 @@ struct window { int sb; int sb_pos; - struct utf8_data *fill_character; + struct grid_cell inside_cell; + struct grid_cell outside_cell; int flags; #define WINDOW_BELL 0x1 #define WINDOW_ACTIVITY 0x2 @@ -3782,7 +3783,6 @@ void *window_pane_get_new_data(struct window_pane *, struct window_pane_offset *, size_t *); void window_pane_update_used_data(struct window_pane *, struct window_pane_offset *, size_t); -void window_set_fill_character(struct window *); void window_pane_default_cursor(struct window_pane *); int window_pane_mode(struct window_pane *); int window_pane_show_scrollbar(struct window_pane *); @@ -3810,8 +3810,10 @@ struct style_range *window_pane_status_get_range(struct window_pane *, u_int, int window_pane_is_floating(struct window_pane *); /* window-border.c */ -void window_get_border_cell(struct window *, struct window_pane *, - enum pane_lines, int, struct grid_cell *); +void window_set_fill_cells(struct window *); +void window_get_border_cell(struct window_pane *, enum pane_lines, + int, struct grid_cell *); +void window_get_fill_cell(struct window *, int, struct grid_cell *); void window_pane_get_border_cell(struct window_pane *, int, struct grid_cell *); void window_pane_get_border_style(struct window_pane *, diff --git a/window-border.c b/window-border.c index 5cd88c2bb..8f2209d0e 100644 --- a/window-border.c +++ b/window-border.c @@ -1,4 +1,4 @@ -/* $OpenBSD: window-border.c,v 1.2 2026/07/17 12:42:51 nicm Exp $ */ +/* $OpenBSD: window-border.c,v 1.3 2026/07/23 09:38:27 nicm Exp $ */ /* * Copyright (c) 2026 Nicholas Marriott @@ -23,18 +23,82 @@ #include "tmux.h" +/* Set window fill cell. */ +static void +window_set_fill_cell(struct window *w, int inside, struct grid_cell *gc) +{ + struct format_tree *ft; + struct screen s; + struct screen_write_ctx ctx; + struct grid_cell new_gc; + const char *value; + char *expanded; + + memcpy(gc, &grid_default_cell, sizeof *gc); + gc->attr |= GRID_ATTR_CHARSET; + utf8_set(&gc->data, CELL_BORDERS[CELL_NONE]); + + ft = format_create(NULL, NULL, FORMAT_WINDOW|w->id, FORMAT_NOJOBS); + format_defaults(ft, NULL, NULL, NULL, w->active); + format_add(ft, "is_inside", "%d", inside); + format_add(ft, "is_outside", "%d", !inside); + + value = options_get_string(w->options, "fill-character"); + expanded = format_expand(ft, value); + format_free(ft); + + screen_init(&s, 1, 1, 0); + screen_write_start(&ctx, &s); + format_draw(&ctx, &grid_default_cell, 1, expanded, NULL, 0); + screen_write_stop(&ctx); + free(expanded); + + grid_view_get_cell(s.grid, 0, 0, &new_gc); + if (new_gc.data.width == 1) + memcpy(gc, &new_gc, sizeof *gc); + screen_free(&s); +} + +/* Set window fill cells. */ +void +window_set_fill_cells(struct window *w) +{ + window_set_fill_cell(w, 1, &w->inside_cell); + window_set_fill_cell(w, 0, &w->outside_cell); +} + +/* Merge a window fill cell over an existing style. */ +static void +window_copy_fill_cell(struct grid_cell *gc, const struct grid_cell *fill) +{ + utf8_copy(&gc->data, &fill->data); + gc->attr |= fill->attr; + gc->flags |= fill->flags; + if (fill->fg != 8) + gc->fg = fill->fg; + if (fill->bg != 8) + gc->bg = fill->bg; + if (fill->us != 8) + gc->us = fill->us; +} + +/* Get window fill cell. */ +void +window_get_fill_cell(struct window *w, int inside, struct grid_cell *gc) +{ + if (inside) + window_copy_fill_cell(gc, &w->inside_cell); + else + window_copy_fill_cell(gc, &w->outside_cell); +} + /* Get border cell. */ void -window_get_border_cell(struct window *w, struct window_pane *wp, - enum pane_lines pane_lines, int cell_type, struct grid_cell *gc) +window_get_border_cell(struct window_pane *wp, enum pane_lines pane_lines, + int cell_type, struct grid_cell *gc) { u_int idx; - if (cell_type == CELL_NONE && w->fill_character != NULL) { - utf8_copy(&gc->data, &w->fill_character[0]); - return; - } - switch (pane_lines) { case PANE_LINES_NUMBER: if (cell_type == CELL_NONE) { @@ -79,7 +143,7 @@ window_pane_get_border_cell(struct window_pane *wp, int cell_type, { enum pane_lines pane_lines = window_pane_get_pane_lines(wp); - window_get_border_cell(wp->window, wp, pane_lines, cell_type, gc); + window_get_border_cell(wp, pane_lines, cell_type, gc); } /* Get pane border style. */ @@ -147,7 +211,7 @@ window_make_pane_status(struct window_pane *wp, struct client *c, u_int width, pane_lines = window_pane_get_pane_lines(wp); for (i = 0; i < width; i++) { cell_type = redraw_get_status_border_cell_type(&span, i); - window_get_border_cell(wp->window, wp, pane_lines, cell_type, &gc); + window_get_border_cell(wp, pane_lines, cell_type, &gc); screen_write_cell(&ctx, &gc); } gc.attr &= ~GRID_ATTR_CHARSET; diff --git a/window.c b/window.c index 5f7866bdc..3a2e21ed7 100644 --- a/window.c +++ b/window.c @@ -1,4 +1,4 @@ -/* $OpenBSD: window.c,v 1.367 2026/07/21 13:04:01 nicm Exp $ */ +/* $OpenBSD: window.c,v 1.368 2026/07/23 09:38:27 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -437,8 +437,6 @@ window_create(u_int sx, u_int sy, u_int xpixel, u_int ypixel) w->id = next_window_id++; RB_INSERT(windows, &windows, w); - window_set_fill_character(w); - if (gettimeofday(&w->creation_time, NULL) != 0) fatal("gettimeofday failed"); window_update_activity(w); @@ -472,7 +470,6 @@ window_destroy(struct window *w) event_del(&w->offset_timer); options_free(w->options); - free(w->fill_character); free(w->name); free(w); @@ -2442,25 +2439,6 @@ window_pane_update_used_data(struct window_pane *wp, wpo->used += size; } -void -window_set_fill_character(struct window *w) -{ - const char *value; - struct utf8_data *ud; - - free(w->fill_character); - w->fill_character = NULL; - - value = options_get_string(w->options, "fill-character"); - if (*value != '\0' && utf8_isvalid(value)) { - ud = utf8_fromcstr(value); - if (ud != NULL && ud[0].width == 1) - w->fill_character = ud; - else - free(ud); - } -} - void window_pane_default_cursor(struct window_pane *wp) {