mirror of
https://github.com/kovidgoyal/kitty
synced 2026-07-25 17:52:02 +02:00
Prepare for allowing upto seven additional semi-transparent background colors
This commit is contained in:
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
// }}}
|
||||
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
8
kitty/options/parse.py
generated
8
kitty/options/parse.py
generated
@@ -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:
|
||||
|
||||
15
kitty/options/to-c-generated.h
generated
15
kitty/options/to-c-generated.h
generated
@@ -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);
|
||||
|
||||
@@ -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)));
|
||||
|
||||
2
kitty/options/types.py
generated
2
kitty/options/types.py
generated
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user