Prepare for allowing upto seven additional semi-transparent background colors

This commit is contained in:
Kovid Goyal
2024-09-19 11:47:16 +05:30
parent d02b1c0b31
commit e78e86572e
10 changed files with 114 additions and 41 deletions

View File

@@ -187,7 +187,7 @@ void main() {
#ifdef TRANSPARENT
final_color = vec4_premul(background, bg_alpha);
#else
final_color = vec4(background, draw_bg);
final_color = vec4(background, draw_bg * bg_alpha);
#endif
#endif

View File

@@ -4,13 +4,16 @@
// Inputs {{{
layout(std140) uniform CellRenderData {
float xstart, ystart, dx, dy, sprite_dx, sprite_dy, background_opacity, use_cell_bg_for_selection_fg, use_cell_fg_for_selection_fg, use_cell_for_selection_bg;
float xstart, ystart, dx, dy, sprite_dx, sprite_dy, use_cell_bg_for_selection_fg, use_cell_fg_for_selection_fg, use_cell_for_selection_bg;
uint default_fg, default_bg, highlight_fg, highlight_bg, cursor_fg, cursor_bg, url_color, url_style, inverted, second_transparent_bg;
uint default_fg, highlight_fg, highlight_bg, cursor_fg, cursor_bg, url_color, url_style, inverted, second_transparent_bg;
uint xnum, ynum, cursor_fg_sprite_idx;
float cursor_x, cursor_y, cursor_w, cursor_opacity;
// must have unique entries with 0 being default_bg and unset being UINT32_MAX
uint bg_colors0, bg_colors1, bg_colors2, bg_colors3, bg_colors4, bg_colors5, bg_colors6, bg_colors7;
float bg_opacities0, bg_opacities1, bg_opacities2, bg_opacities3, bg_opacities4, bg_opacities5, bg_opacities6, bg_opacities7;
uint color_table[NUM_COLORS + MARK_MASK + MARK_MASK + 2];
};
#if (PHASE == PHASE_BACKGROUND)
@@ -145,12 +148,30 @@ CellData set_vertex_position() {
return CellData(has_cursor, has_cursor * is_block_cursor, pos);
}
float background_opacity_for(uint bg, uint colorval, float opacity_if_matched) { // opacity_if_matched if bg == colorval else 1
float not_matched = step(1.f, abs(float(colorval - bg))); // not_matched = 0 if bg == colorval else 1
return not_matched + opacity_if_matched * (1.f - not_matched);
}
float calc_background_opacity(uint bg) {
return (
background_opacity_for(bg, bg_colors0, bg_opacities0) *
background_opacity_for(bg, bg_colors1, bg_opacities1) *
background_opacity_for(bg, bg_colors2, bg_opacities2) *
background_opacity_for(bg, bg_colors3, bg_opacities3) *
background_opacity_for(bg, bg_colors4, bg_opacities4) *
background_opacity_for(bg, bg_colors5, bg_opacities5) *
background_opacity_for(bg, bg_colors6, bg_opacities6) *
background_opacity_for(bg, bg_colors7, bg_opacities7)
);
}
void main() {
CellData cell_data = set_vertex_position();
// set cell color indices {{{
uvec2 default_colors = uvec2(default_fg, default_bg);
uvec2 default_colors = uvec2(default_fg, bg_colors0);
uint text_attrs = sprite_coords[3];
uint is_reversed = ((text_attrs >> REVERSE_SHIFT) & ONE);
uint is_inverted = is_reversed + inverted;
@@ -194,42 +215,34 @@ void main() {
// }}}
// Background {{{
float bg_is_not_transparent = step(1, float(abs(
(bg_as_uint - default_colors[1]) * (bg_as_uint - second_transparent_bg)
))); // bg_is_not_transparent = 0 if bg_as_uint in (default_colors[1], second_transparent_bg) else 1
#if PHASE == PHASE_BOTH && !defined(TRANSPARENT) // fast case single pass opaque background
bg_alpha = 1;
draw_bg = 1;
#else
bg_alpha = calc_background_opacity(bg_as_uint);
#if (PHASE == PHASE_BACKGROUND)
// draw_bg_bitfield has bit 0 set to draw default bg cells and bit 1 set to draw non-default bg cells
uint draw_bg_mask = uint(2 * bg_is_not_transparent + (1 - bg_is_not_transparent));
draw_bg = step(1, float(draw_bg_bitfield & draw_bg_mask));
float cell_has_non_default_bg = step(1.f, abs(float(bg_as_uint - bg_colors0))); // 0 if has default bg else 1
uint draw_bg_mask = uint(2.f * cell_has_non_default_bg + (1.f - cell_has_non_default_bg)); // 1 if has default bg else 2
draw_bg = step(0.5, float(draw_bg_bitfield & draw_bg_mask));
#else
draw_bg = 1;
#endif
bg_alpha = 1.f;
#ifdef TRANSPARENT
// Set bg_alpha to background_opacity on cells that have the default background color
// Which means they must not have a block cursor or a selection or reverse video
// On other cells it should be 1. For the SPECIAL program it should be 1 on cells with
// selections/block cursor and 0 everywhere else.
float is_special_cell = cell_data.has_block_cursor + float(is_selected & ONE);
#if (PHASE != PHASE_SPECIAL)
is_special_cell += bg_is_not_transparent + float(is_reversed);
#endif
#if PHASE == PHASE_SPECIAL
// Only special cells must be drawn and they must have bg_alpha 1
bg_alpha = step(0.5, is_special_cell); // bg_alpha = 1 if is_special_cell else 0
#if (PHASE != PHASE_SPECIAL)
bg_alpha = bg_alpha + (1.0f - bg_alpha) * background_opacity; // bg_alpha = 1 if bg_alpha else background_opacity
bg_alpha *= draw_bg; // if not draw_bg: bg_alpha = 0
#endif
#else
is_special_cell += float(is_reversed); // bg_alpha should be 1 for reverse video cells as well
is_special_cell = step(0.5, is_special_cell); // is_special_cell = 1 if is_special_cell else 0
bg_alpha = bg_alpha * (1. - float(is_special_cell)) + is_special_cell; // bg_alpha = 1 if is_special_cell else bg_alpha
#endif
bg_alpha *= draw_bg;
#endif // ends fast case #if else
// Selection and cursor
bg = choose_color(float(is_selected & ONE), choose_color(use_cell_for_selection_bg, color_to_vec(fg_as_uint), color_to_vec(highlight_bg)), bg);
background = choose_color(cell_data.has_block_cursor, mix(bg, color_to_vec(cursor_bg), cursor_opacity), bg);
#if !defined(TRANSPARENT) && (PHASE == PHASE_SPECIAL)
float is_special_cell = cell_data.has_block_cursor + float(is_selected & ONE);
bg_alpha = step(0.5, is_special_cell);
#endif
// }}}
}

View File

@@ -1481,7 +1481,7 @@ theme with a background color in your editor, it will not be rendered as
transparent. Instead you should change the default background color in your
kitty config and not use a background color in the editor color scheme. Or use
the escape codes to set the terminals default colors in a shell script to
launch your editor. See also :opt:`second_transparent_bg`.
launch your editor. See also :opt:`transparent_background_colors`.
Be aware that using a value less than 1.0 is a (possibly
significant) performance hit. When using a low value for this setting, it is
desirable that you set the :opt:`background` color to a color the matches the
@@ -1527,6 +1527,8 @@ opt('background_image_linear', 'no',
long_text='When background image is scaled, whether linear interpolation should be used.'
)
opt('transparent_background_colors', '', option_type='transparent_background_colors', ctype='!transparent_background_colors')
opt('second_transparent_bg', 'none', option_type='to_color_or_none', long_text='''
When the background color matches this color, :opt:`background_opacity` is applied to it
to render it as semi-transparent, just as for colors matching the main :opt:`background` color.

View File

@@ -19,8 +19,9 @@ from kitty.options.utils import (
shell_integration, store_multiple, symbol_map, tab_activity_symbol, tab_bar_edge,
tab_bar_margin_height, tab_bar_min_tabs, tab_fade, tab_font_style, tab_separator,
tab_title_template, titlebar_color, to_cursor_shape, to_cursor_unfocused_shape, to_font_size,
to_layout_names, to_modifiers, url_prefixes, url_style, visual_bell_duration,
visual_window_select_characters, window_border_width, window_logo_scale, window_size
to_layout_names, to_modifiers, transparent_background_colors, url_prefixes, url_style,
visual_bell_duration, visual_window_select_characters, window_border_width, window_logo_scale,
window_size
)
@@ -1326,6 +1327,9 @@ class Parser:
def touch_scroll_multiplier(self, val: str, ans: typing.Dict[str, typing.Any]) -> None:
ans['touch_scroll_multiplier'] = float(val)
def transparent_background_colors(self, val: str, ans: typing.Dict[str, typing.Any]) -> None:
ans['transparent_background_colors'] = transparent_background_colors(val)
def undercurl_style(self, val: str, ans: typing.Dict[str, typing.Any]) -> None:
val = val.lower()
if val not in self.choices_for_undercurl_style:

View File

@@ -850,6 +850,19 @@ convert_from_opts_background_image_linear(PyObject *py_opts, Options *opts) {
Py_DECREF(ret);
}
static void
convert_from_python_transparent_background_colors(PyObject *val, Options *opts) {
transparent_background_colors(val, opts);
}
static void
convert_from_opts_transparent_background_colors(PyObject *py_opts, Options *opts) {
PyObject *ret = PyObject_GetAttrString(py_opts, "transparent_background_colors");
if (ret == NULL) return;
convert_from_python_transparent_background_colors(ret, opts);
Py_DECREF(ret);
}
static void
convert_from_python_dynamic_background_opacity(PyObject *val, Options *opts) {
opts->dynamic_background_opacity = PyObject_IsTrue(val);
@@ -1229,6 +1242,8 @@ convert_opts_from_python_opts(PyObject *py_opts, Options *opts) {
if (PyErr_Occurred()) return false;
convert_from_opts_background_image_linear(py_opts, opts);
if (PyErr_Occurred()) return false;
convert_from_opts_transparent_background_colors(py_opts, opts);
if (PyErr_Occurred()) return false;
convert_from_opts_dynamic_background_opacity(py_opts, opts);
if (PyErr_Occurred()) return false;
convert_from_opts_background_tint(py_opts, opts);

View File

@@ -441,6 +441,17 @@ window_logo_scale(PyObject *src, Options *opts) {
opts->window_logo_scale.height = PyFloat_AsFloat(PyTuple_GET_ITEM(src, 1));
}
static void
transparent_background_colors(PyObject *src, Options *opts) {
memset(opts->transparent_background_colors, 0, sizeof(opts->transparent_background_colors));
for (Py_ssize_t i = 0; i < MIN(PyTuple_GET_SIZE(src), (Py_ssize_t)arraysz(opts->transparent_background_colors)); i++) {
PyObject *e = PyTuple_GET_ITEM(src, i);
opts->transparent_background_colors[i].color = color_as_int(PyTuple_GET_ITEM(e, 0));
opts->transparent_background_colors[i].opacity = PyFloat_AsFloat(PyTuple_GET_ITEM(e, 1));
opts->transparent_background_colors[i].is_set = true;
}
}
static inline void
resize_debounce_time(PyObject *src, Options *opts) {
opts->resize_debounce_time.on_end = s_double_to_monotonic_t(PyFloat_AsDouble(PyTuple_GET_ITEM(src, 0)));

View File

@@ -443,6 +443,7 @@ option_names = ( # {{{
'text_composition_strategy',
'text_fg_override_threshold',
'touch_scroll_multiplier',
'transparent_background_colors',
'undercurl_style',
'underline_hyperlinks',
'update_check_interval',
@@ -607,6 +608,7 @@ class Options:
text_composition_strategy: str = 'platform'
text_fg_override_threshold: float = 0.0
touch_scroll_multiplier: float = 1.0
transparent_background_colors: typing.Tuple[typing.Tuple[kitty.fast_data_types.Color, float], ...] = ()
undercurl_style: choices_for_undercurl_style = 'thin-sparse'
underline_hyperlinks: choices_for_underline_hyperlinks = 'hover'
update_check_interval: float = 24.0

View File

@@ -1554,6 +1554,23 @@ def visual_bell_duration(spec: str) -> Tuple[float, EasingFunction, EasingFuncti
return parse_animation(spec, interval=0.)
def transparent_background_colors(spec: str) -> Tuple[Tuple[Color, float], ...]:
if not spec:
return ()
ans: list[tuple[Color, float]] = []
seen: dict[Color, int] = {}
for part in spec.split():
col, sep, alpha = part.partition('@')
c = to_color(col)
o = unit_float(alpha) if alpha else -1
if (idx := seen.get(c)) is not None:
ans[idx] = c, o
continue
seen[c] = len(ans)
ans.append((c, o))
return tuple(ans[:7])
def deprecated_hide_window_decorations_aliases(key: str, val: str, ans: Dict[str, Any]) -> None:
if not hasattr(deprecated_hide_window_decorations_aliases, key):
setattr(deprecated_hide_window_decorations_aliases, key, True)

View File

@@ -293,12 +293,14 @@ pick_cursor_color(Line *line, const ColorProfile *color_profile, color_type cell
static void
cell_update_uniform_block(ssize_t vao_idx, Screen *screen, int uniform_buffer, const CellRenderData *crd, CursorRenderInfo *cursor, OSWindow *os_window) {
struct GPUCellRenderData {
GLfloat xstart, ystart, dx, dy, sprite_dx, sprite_dy, background_opacity, use_cell_bg_for_selection_fg, use_cell_fg_for_selection_color, use_cell_for_selection_bg;
GLfloat xstart, ystart, dx, dy, sprite_dx, sprite_dy, use_cell_bg_for_selection_fg, use_cell_fg_for_selection_color, use_cell_for_selection_bg;
GLuint default_fg, default_bg, highlight_fg, highlight_bg, cursor_fg, cursor_bg, url_color, url_style, inverted, second_transparent_bg;
GLuint default_fg, highlight_fg, highlight_bg, cursor_fg, cursor_bg, url_color, url_style, inverted, second_transparent_bg;
GLuint xnum, ynum, cursor_fg_sprite_idx;
GLfloat cursor_x, cursor_y, cursor_w, cursor_opacity;
GLuint bg_colors0, bg_colors1, bg_colors2, bg_colors3, bg_colors4, bg_colors5, bg_colors6, bg_colors7;
GLfloat bg_opacities0, bg_opacities1, bg_opacities2, bg_opacities3, bg_opacities4, bg_opacities5, bg_opacities6, bg_opacities7;
};
// Send the uniform data
struct GPUCellRenderData *rd = (struct GPUCellRenderData*)map_vao_buffer(vao_idx, uniform_buffer, GL_WRITE_ONLY);
@@ -307,8 +309,16 @@ cell_update_uniform_block(ssize_t vao_idx, Screen *screen, int uniform_buffer, c
copy_color_table_to_buffer(cp, (GLuint*)rd, cell_program_layouts[CELL_PROGRAM].color_table.offset / sizeof(GLuint), cell_program_layouts[CELL_PROGRAM].color_table.stride / sizeof(GLuint));
}
#define COLOR(name) colorprofile_to_color(cp, cp->overridden.name, cp->configured.name).rgb
rd->default_fg = COLOR(default_fg); rd->default_bg = COLOR(default_bg);
rd->default_fg = COLOR(default_fg);
rd->highlight_fg = COLOR(highlight_fg); rd->highlight_bg = COLOR(highlight_bg);
rd->bg_colors0 = COLOR(default_bg);
rd->bg_opacities0 = os_window->is_semi_transparent ? os_window->background_opacity : 1.0f;
#define SETBG(which) if (OPT(transparent_background_colors)[which-1].is_set) { \
rd->bg_colors##which = OPT(transparent_background_colors)[which-1].color; \
rd->bg_opacities##which = OPT(transparent_background_colors)[which-1].opacity < 0 ? rd->bg_opacities0 : OPT(transparent_background_colors)[which-1].opacity; \
} else { rd->bg_colors##which = UINT32_MAX; }
SETBG(1); SETBG(2); SETBG(3); SETBG(4); SETBG(5); SETBG(6); SETBG(7);
#undef SETBG
// selection
if (IS_SPECIAL_COLOR(highlight_fg)) {
if (IS_SPECIAL_COLOR(highlight_bg)) {
@@ -320,7 +330,6 @@ cell_update_uniform_block(ssize_t vao_idx, Screen *screen, int uniform_buffer, c
rd->use_cell_bg_for_selection_fg = 0.f; rd->use_cell_fg_for_selection_color = 0.f;
}
rd->use_cell_for_selection_bg = IS_SPECIAL_COLOR(highlight_bg) ? 1. : 0.;
rd->second_transparent_bg = IS_SPECIAL_COLOR(second_transparent_bg) ? rd->default_bg : COLOR(second_transparent_bg);
// Cursor position
enum { BLOCK_IDX = 0, BEAM_IDX = NUM_UNDERLINE_STYLES + 3, UNDERLINE_IDX = NUM_UNDERLINE_STYLES + 4, UNFOCUSED_IDX = NUM_UNDERLINE_STYLES + 5 };
Line *line_for_cursor = NULL;
@@ -338,7 +347,7 @@ cell_update_uniform_block(ssize_t vao_idx, Screen *screen, int uniform_buffer, c
case CURSOR_HOLLOW:
rd->cursor_fg_sprite_idx = UNFOCUSED_IDX; break;
};
color_type cell_fg = rd->default_fg, cell_bg = rd->default_bg;
color_type cell_fg = rd->default_fg, cell_bg = rd->bg_colors0;
index_type cell_color_x = cursor->x;
bool reversed = false;
if (cursor->x < screen->columns && cursor->y < screen->lines) {
@@ -352,10 +361,10 @@ cell_update_uniform_block(ssize_t vao_idx, Screen *screen, int uniform_buffer, c
colors_for_cell(line_for_cursor, cp, &cell_color_x, &cell_fg, &cell_bg, &reversed);
}
if (IS_SPECIAL_COLOR(cursor_color)) {
if (line_for_cursor) pick_cursor_color(line_for_cursor, cp, cell_fg, cell_bg, cell_color_x, &rd->cursor_fg, &rd->cursor_bg, rd->default_fg, rd->default_bg);
else { rd->cursor_fg = rd->default_bg; rd->cursor_bg = rd->default_fg; }
if (line_for_cursor) pick_cursor_color(line_for_cursor, cp, cell_fg, cell_bg, cell_color_x, &rd->cursor_fg, &rd->cursor_bg, rd->default_fg, rd->bg_colors0);
else { rd->cursor_fg = rd->bg_colors0; rd->cursor_bg = rd->default_fg; }
if (cell_bg == cell_fg) {
rd->cursor_fg = rd->default_bg; rd->cursor_bg = rd->default_fg;
rd->cursor_fg = rd->bg_colors0; rd->cursor_bg = rd->default_fg;
} else { rd->cursor_fg = cell_bg; rd->cursor_bg = cell_fg; }
} else {
rd->cursor_bg = COLOR(cursor_color);
@@ -375,7 +384,6 @@ cell_update_uniform_block(ssize_t vao_idx, Screen *screen, int uniform_buffer, c
sprite_tracker_current_layout(os_window->fonts_data, &x, &y, &z);
rd->sprite_dx = 1.0f / (float)x; rd->sprite_dy = 1.0f / (float)y;
rd->inverted = screen_invert_colors(screen) ? 1 : 0;
rd->background_opacity = os_window->is_semi_transparent ? os_window->background_opacity : 1.0f;
#undef COLOR
rd->url_color = OPT(url_color); rd->url_style = OPT(url_style);

View File

@@ -119,6 +119,7 @@ typedef struct {
} *entries;
} font_features;
struct { Animation *cursor, *visual_bell; } animation;
struct { color_type color; float opacity; bool is_set; } transparent_background_colors[8];
} Options;
typedef struct WindowLogoRenderData {