From 22c8637610e15d2c84509a484fee41bccd0ad0fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Wed, 3 Jul 2024 10:53:33 +0200 Subject: [PATCH] osc: extend damage-cells-by-color to default fg/bg as well When changing part of the color palette, through either OSC-4, or OSC-10 and OSC-11 (and the corresponding reset OSCs: 104, 110 and 111), only dirty affected cells. We've always done this, but only for OSC-4. This patch breaks out that logic, and extends it to handle default fg/bg too. It also fixes a bug where cells with colored underlines were not dirtied if the underline was the only part of the cell that was affected by a OSC-4 change. --- csi.c | 6 ++-- osc.c | 56 +++++---------------------------- terminal.c | 90 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ terminal.h | 1 + 4 files changed, 102 insertions(+), 51 deletions(-) diff --git a/csi.c b/csi.c index 86117c7e..1f61d3ce 100644 --- a/csi.c +++ b/csi.c @@ -2098,8 +2098,10 @@ csi_dispatch(struct terminal *term, uint8_t final) sizeof(term->colors)); term->color_stack.idx = slot - 1; - /* TODO: we _could_ iterate all cells and only dirty - those that are affected by the palette change... */ + /* Assume a full palette switch *will* affect almost + all cells. The alternative is to call + term_damage_color() for all 256 palette entries + *and* the default fg/bg (256 + 2 calls in total) */ term_damage_view(term); term_damage_margins(term); } else if (slot == 0) { diff --git a/osc.c b/osc.c index d9e952c0..a3dc1715 100644 --- a/osc.c +++ b/osc.c @@ -651,47 +651,7 @@ osc_dispatch(struct terminal *term) idx, term->colors.table[idx], color); term->colors.table[idx] = color; - - /* Dirty visible, affected cells */ - for (int r = 0; r < term->rows; r++) { - struct row *row = grid_row_in_view(term->grid, r); - struct cell *cell = &row->cells[0]; - - for (int c = 0; c < term->cols; c++, cell++) { - bool dirty = false; - - switch (cell->attrs.fg_src) { - case COLOR_BASE16: - case COLOR_BASE256: - if (cell->attrs.fg == idx) - dirty = true; - break; - - case COLOR_DEFAULT: - case COLOR_RGB: - /* Not affected */ - break; - } - - switch (cell->attrs.bg_src) { - case COLOR_BASE16: - case COLOR_BASE256: - if (cell->attrs.bg == idx) - dirty = true; - break; - - case COLOR_DEFAULT: - case COLOR_RGB: - /* Not affected */ - break; - } - - if (dirty) { - cell->attrs.clean = 0; - row->dirty = true; - } - } - } + term_damage_color(term, COLOR_BASE256, idx); } } @@ -772,7 +732,7 @@ osc_dispatch(struct terminal *term) switch (param) { case 10: term->colors.fg = color; - term_damage_view(term); + term_damage_color(term, COLOR_DEFAULT, 0); break; case 11: @@ -786,7 +746,7 @@ osc_dispatch(struct terminal *term) term_font_subpixel_changed(term); } } - term_damage_view(term); + term_damage_color(term, COLOR_DEFAULT, 0); term_damage_margins(term); break; @@ -798,13 +758,11 @@ osc_dispatch(struct terminal *term) case 17: term->colors.selection_bg = color; term->colors.use_custom_selection = true; - term_damage_view(term); break; case 19: term->colors.selection_fg = color; term->colors.use_custom_selection = true; - term_damage_view(term); break; } @@ -829,6 +787,7 @@ osc_dispatch(struct terminal *term) LOG_DBG("resetting all colors"); for (size_t i = 0; i < ALEN(term->colors.table); i++) term->colors.table[i] = term->conf->colors.table[i]; + term_damage_view(term); } else { @@ -850,11 +809,10 @@ osc_dispatch(struct terminal *term) LOG_DBG("resetting color #%u", idx); term->colors.table[idx] = term->conf->colors.table[idx]; + term_damage_color(term, COLOR_BASE256, idx); } } - - term_damage_view(term); break; } @@ -864,14 +822,14 @@ osc_dispatch(struct terminal *term) case 110: /* Reset default text foreground color */ LOG_DBG("resetting foreground color"); term->colors.fg = term->conf->colors.fg; - term_damage_view(term); + term_damage_color(term, COLOR_DEFAULT, 0); break; case 111: /* Reset default text background color */ LOG_DBG("resetting background color"); term->colors.bg = term->conf->colors.bg; term->colors.alpha = term->conf->colors.alpha; - term_damage_view(term); + term_damage_color(term, COLOR_DEFAULT, 0); term_damage_margins(term); break; diff --git a/terminal.c b/terminal.c index ca3d2bc1..d08bb74d 100644 --- a/terminal.c +++ b/terminal.c @@ -2386,6 +2386,96 @@ term_damage_margins(struct terminal *term) term->render.margins = true; } +void +term_damage_color(struct terminal *term, enum color_source src, int idx) +{ + xassert(src == COLOR_DEFAULT || src == COLOR_BASE256); + + for (int r = 0; r < term->rows; r++) { + struct row *row = grid_row_in_view(term->grid, r); + struct cell *cell = &row->cells[0]; + const struct cell *end = &row->cells[term->cols]; + + for (; cell < end; cell++) { + bool dirty = false; + + switch (cell->attrs.fg_src) { + case COLOR_BASE16: + case COLOR_BASE256: + if (src == COLOR_BASE256 && cell->attrs.fg == idx) + dirty = true; + break; + + case COLOR_DEFAULT: + if (src == COLOR_DEFAULT) { + /* Doesn't matter whether we've updated the + default foreground, or background, we still + want to dirty this cell, to be sure we handle + all cases of color inversion/reversal */ + dirty = true; + } + break; + + case COLOR_RGB: + /* Not affected */ + break; + } + + switch (cell->attrs.bg_src) { + case COLOR_BASE16: + case COLOR_BASE256: + if (src == COLOR_BASE256 && cell->attrs.bg == idx) + dirty = true; + break; + + case COLOR_DEFAULT: + if (src == COLOR_DEFAULT) { + /* Doesn't matter whether we've updated the + default foreground, or background, we still + want to dirty this cell, to be sure we handle + all cases of color inversion/reversal */ + dirty = true; + } + break; + + case COLOR_RGB: + /* Not affected */ + break; + } + + if (dirty) { + cell->attrs.clean = 0; + row->dirty = true; + } + } + + /* Colored underlines */ + if (row->extra != NULL) { + const struct row_ranges *underlines = &row->extra->underline_ranges; + + for (int i = 0; i < underlines->count; i++) { + const struct row_range *range = &underlines->v[i]; + + /* Underline colors are either default, or + BASE256/RGB, but never BASE16 */ + xassert(range->underline.color_src == COLOR_DEFAULT || + range->underline.color_src == COLOR_BASE256 || + range->underline.color_src == COLOR_RGB); + + if (range->underline.color_src == src) { + struct cell *c = &row->cells[range->start]; + const struct cell *e = &row->cells[range->end + 1]; + + for (; c < e; c++) + c->attrs.clean = 0; + + row->dirty = true; + } + } + } + } +} + void term_damage_scroll(struct terminal *term, enum damage_type damage_type, struct scroll_region region, int lines) diff --git a/terminal.h b/terminal.h index 4d628661..926870c1 100644 --- a/terminal.h +++ b/terminal.h @@ -845,6 +845,7 @@ void term_damage_view(struct terminal *term); void term_damage_cursor(struct terminal *term); void term_damage_margins(struct terminal *term); +void term_damage_color(struct terminal *term, enum color_source src, int idx); void term_reset_view(struct terminal *term);