Store transparent colors on ColorProfile

This will eventually allow them to be changed using remote control and
escape codes.
This commit is contained in:
Kovid Goyal
2024-09-20 10:02:28 +05:30
parent 6ca187c42c
commit dbfeb8d6a4
13 changed files with 58 additions and 64 deletions

View File

@@ -80,9 +80,18 @@ set_configured_colors(ColorProfile *self, PyObject *opts) {
n(default_fg, foreground); n(default_bg, background);
n(cursor_color, cursor); n(cursor_text_color, cursor_text_color);
n(highlight_fg, selection_foreground); n(highlight_bg, selection_background);
n(visual_bell_color, visual_bell_color); n(second_transparent_bg, second_transparent_bg);
n(visual_bell_color, visual_bell_color);
#undef n
return true;
memset(self->configured_transparent_colors, 0, sizeof(self->configured_transparent_colors));
RAII_PyObject(src, PyObject_GetAttrString(opts, "transparent_background_colors"));
if (!src) { PyErr_SetString(PyExc_TypeError, "No transparent_background_colors on opts object"); return false; }
for (Py_ssize_t i = 0; i < MIN(PyTuple_GET_SIZE(src), (Py_ssize_t)arraysz(self->configured_transparent_colors)); i++) {
PyObject *e = PyTuple_GET_ITEM(src, i);
self->configured_transparent_colors[i].color = ((Color*)(PyTuple_GET_ITEM(e, 0)))->color.val & 0xffffff;
self->configured_transparent_colors[i].opacity = (float)PyFloat_AsDouble(PyTuple_GET_ITEM(e, 1));
self->configured_transparent_colors[i].is_set = true;
}
return PyErr_Occurred() ? false : true;
}
static bool
@@ -162,6 +171,8 @@ copy_color_profile(ColorProfile *dest, ColorProfile *src) {
memcpy(dest->orig_color_table, src->orig_color_table, sizeof(dest->color_table));
memcpy(&dest->configured, &src->configured, sizeof(dest->configured));
memcpy(&dest->overridden, &src->overridden, sizeof(dest->overridden));
memcpy(dest->overriden_transparent_colors, src->overriden_transparent_colors, sizeof(dest->overriden_transparent_colors));
memcpy(dest->configured_transparent_colors, src->configured_transparent_colors, sizeof(dest->configured_transparent_colors));
dest->dirty = true;
}
@@ -226,12 +237,28 @@ patch_color_profiles(PyObject *module UNUSED, PyObject *args) {
S(foreground, default_fg); S(background, default_bg); S(cursor, cursor_color);
S(selection_foreground, highlight_fg); S(selection_background, highlight_bg);
S(cursor_text_color, cursor_text_color); S(visual_bell_color, visual_bell_color);
S(second_transparent_bg, second_transparent_bg);
#undef SI
#undef S
// TODO: Patch transparent_colors
Py_RETURN_NONE;
}
bool
colorprofile_to_transparent_color(const ColorProfile *self, unsigned index, color_type *color, float *opacity) {
*color = UINT32_MAX; *opacity = 1.0;
if (index < arraysz(self->configured_transparent_colors)) {
if (self->overriden_transparent_colors[index].is_set) {
*color = self->overriden_transparent_colors[index].color; *opacity = self->overriden_transparent_colors[index].opacity;
return true;
}
if (self->configured_transparent_colors[index].is_set) {
*color = self->configured_transparent_colors[index].color; *opacity = self->configured_transparent_colors[index].opacity;
return true;
}
}
return false;
}
DynamicColor
colorprofile_to_color(const ColorProfile *self, DynamicColor entry, DynamicColor defval) {
switch(entry.type) {
@@ -295,9 +322,10 @@ as_dict(ColorProfile *self, PyObject *args UNUSED) {
}}
D(default_fg, foreground); D(default_bg, background);
D(cursor_color, cursor); D(cursor_text_color, cursor_text); D(highlight_fg, selection_foreground);
D(highlight_bg, selection_background); D(visual_bell_color, visual_bell_color); D(second_transparent_bg, second_transparent_bg);
D(highlight_bg, selection_background); D(visual_bell_color, visual_bell_color);
#undef D
// TODO: Add transparent_colors
return ans;
}
@@ -373,6 +401,8 @@ copy_color_table_to_buffer(ColorProfile *self, color_type *buf, int offset, size
static void
push_onto_color_stack_at(ColorProfile *self, unsigned int i) {
self->color_stack[i].dynamic_colors = self->overridden;
memcpy(self->color_stack[i].transparent_colors, self->overriden_transparent_colors, sizeof(self->overriden_transparent_colors));
self->color_stack[i].dynamic_colors = self->overridden;
memcpy(self->color_stack[i].color_table, self->color_table, sizeof(self->color_stack->color_table));
}
@@ -381,6 +411,7 @@ static void
copy_from_color_stack_at(ColorProfile *self, unsigned int i) {
self->overridden = self->color_stack[i].dynamic_colors;
memcpy(self->color_table, self->color_stack[i].color_table, sizeof(self->color_table));
memcpy(self->overriden_transparent_colors, self->color_stack[i].transparent_colors, sizeof(self->overriden_transparent_colors));
}
bool
@@ -477,7 +508,6 @@ CGETSET(cursor_text_color, true)
CGETSET(highlight_fg, true)
CGETSET(highlight_bg, true)
CGETSET(visual_bell_color, true)
CGETSET(second_transparent_bg, true)
#undef CGETSET
static PyGetSetDef cp_getsetters[] = {
@@ -488,7 +518,6 @@ static PyGetSetDef cp_getsetters[] = {
GETSET(highlight_fg)
GETSET(highlight_bg)
GETSET(visual_bell_color)
GETSET(second_transparent_bg)
{NULL} /* Sentinel */
};
@@ -552,7 +581,7 @@ new_color(PyTypeObject *type UNUSED, PyObject *args, PyObject *kwds) {
}
static PyObject*
color_as_int(Color *self) {
Color_as_int(Color *self) {
return PyLong_FromUnsignedLong(self->color.val);
}
@@ -566,7 +595,7 @@ color_truediv(Color *self, PyObject *divisor) {
}
static PyNumberMethods color_number_methods = {
.nb_int = (unaryfunc)color_as_int,
.nb_int = (unaryfunc)Color_as_int,
.nb_true_divide = (binaryfunc)color_truediv,
};

View File

@@ -323,15 +323,21 @@ typedef union DynamicColor {
} DynamicColor;
typedef struct {
DynamicColor default_fg, default_bg, cursor_color, cursor_text_color, highlight_fg, highlight_bg, visual_bell_color, second_transparent_bg;
DynamicColor default_fg, default_bg, cursor_color, cursor_text_color, highlight_fg, highlight_bg, visual_bell_color;
} DynamicColors;
typedef struct TransparentDynamicColor {
color_type color; float opacity; bool is_set;
} TransparentDynamicColor;
typedef struct {
PyObject_HEAD
bool dirty;
uint32_t color_table[256], orig_color_table[256];
struct { DynamicColors dynamic_colors; uint32_t color_table[256]; } *color_stack;
TransparentDynamicColor configured_transparent_colors[8], overriden_transparent_colors[8];
struct { DynamicColors dynamic_colors; uint32_t color_table[256]; TransparentDynamicColor transparent_colors[8]; } *color_stack;
unsigned int color_stack_idx, color_stack_sz;
DynamicColors configured, overridden;
color_type mark_foregrounds[MARK_MASK+1], mark_backgrounds[MARK_MASK+1];
@@ -403,6 +409,7 @@ bool schedule_write_to_child_python(unsigned long id, const char *prefix, PyObje
bool set_iutf8(int, bool);
DynamicColor colorprofile_to_color(const ColorProfile *self, DynamicColor entry, DynamicColor defval);
bool colorprofile_to_transparent_color(const ColorProfile *self, unsigned index, color_type *color, float *opacity);
color_type
colorprofile_to_color_with_fallback(ColorProfile *self, DynamicColor entry, DynamicColor defval, DynamicColor fallback, DynamicColor falback_defval);
void copy_color_table_to_buffer(ColorProfile *self, color_type *address, int offset, size_t stride);

View File

@@ -809,11 +809,6 @@ class ColorProfile:
@visual_bell_color.setter
def visual_bell_color(self, val: Union[None|int|Color]) -> None: ...
@property
def second_transparent_bg(self) -> Optional[Color]: ...
@second_transparent_bg.setter
def second_transparent_bg(self, val: Union[None|int|Color]) -> None: ...
def __init__(self, opts: Optional[Options] = None): ...
def as_dict(self) -> Dict[str, Optional[int]]:

View File

@@ -1527,7 +1527,7 @@ 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', long_text='''
opt('transparent_background_colors', '', option_type='transparent_background_colors', long_text='''
A space separated list of upto 7 colors, with opacity. When the background color of a cell matches one of these colors,
it is rendered semi-transparent using the specified opacity.

View File

@@ -1194,9 +1194,6 @@ class Parser:
def scrollback_pager_history_size(self, val: str, ans: typing.Dict[str, typing.Any]) -> None:
ans['scrollback_pager_history_size'] = scrollback_pager_history_size(val)
def second_transparent_bg(self, val: str, ans: typing.Dict[str, typing.Any]) -> None:
ans['second_transparent_bg'] = to_color_or_none(val)
def select_by_word_characters(self, val: str, ans: typing.Dict[str, typing.Any]) -> None:
ans['select_by_word_characters'] = str(val)

View File

@@ -850,19 +850,6 @@ 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);
@@ -1242,8 +1229,6 @@ 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,17 +441,6 @@ 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

@@ -409,7 +409,6 @@ option_names = ( # {{{
'scrollback_lines',
'scrollback_pager',
'scrollback_pager_history_size',
'second_transparent_bg',
'select_by_word_characters',
'select_by_word_characters_forward',
'selection_background',
@@ -575,7 +574,6 @@ class Options:
scrollback_lines: int = 2000
scrollback_pager: typing.List[str] = ['less', '--chop-long-lines', '--RAW-CONTROL-CHARS', '+INPUT_LINE_NUMBER']
scrollback_pager_history_size: int = 0
second_transparent_bg: typing.Optional[kitty.fast_data_types.Color] = None
select_by_word_characters: str = '@-./_~?&=%+#'
select_by_word_characters_forward: str = ''
selection_background: typing.Optional[kitty.fast_data_types.Color] = Color(255, 250, 205)
@@ -1037,7 +1035,6 @@ nullable_colors = frozenset({
'active_border_color'
'tab_bar_background'
'tab_bar_margin_color'
'second_transparent_bg'
'selection_foreground'
'selection_background'
})

View File

@@ -313,10 +313,7 @@ cell_update_uniform_block(ssize_t vao_idx, Screen *screen, int uniform_buffer, c
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; }
#define SETBG(which) colorprofile_to_transparent_color(cp, which - 1, &rd->bg_colors##which, &rd->bg_opacities##which)
SETBG(1); SETBG(2); SETBG(3); SETBG(4); SETBG(5); SETBG(6); SETBG(7);
#undef SETBG
// selection

View File

@@ -119,7 +119,6 @@ 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 {

View File

@@ -453,11 +453,12 @@ def color_control(cp: ColorProfile, code: int, value: Union[str, bytes, memoryvi
responses = {}
for rec in value.split(';'):
key, sep, val = rec.partition('=')
# TODO: Add transparent_colors
attr = {
'foreground': 'default_fg', 'background': 'default_bg',
'selection_background': 'highlight_bg', 'selection_foreground': 'highlight_fg',
'cursor': 'cursor_color', 'cursor_text': 'cursor_text_color',
'visual_bell': 'visual_bell_color', 'second_transparent_background': 'second_transparent_bg',
'visual_bell': 'visual_bell_color',
}.get(key, '')
colnum = -1
with suppress(Exception):