Compare commits

...

4 Commits
col ... trans

Author SHA1 Message Date
Kovid Goyal
c10e421e9b Implement dynamic control of transparent background colors via escape code
Still have to implement it via remote control
2024-09-20 12:56:16 +05:30
Kovid Goyal
958cc6d98f Store transparent colors on ColorProfile
This will eventually allow them to be changed using remote control and
escape codes.
2024-09-20 10:02:28 +05:30
Kovid Goyal
f1f4a1a4a3 Replace the second_transparent_bg option
This is backwards incompatible, but only for a feature released 3 weeks
ago.
2024-09-20 09:11:39 +05:30
Kovid Goyal
55859f4b56 Prepare for allowing upto seven additional semi-transparent background colors 2024-09-20 09:11:39 +05:30
17 changed files with 249 additions and 84 deletions

View File

@@ -77,6 +77,8 @@ Detailed list of changes
0.36.3 [future] 0.36.3 [future]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- The option ``second_transparent_bg`` has been removed and replaced by :opt:`transparent_background_colors` which allows setting up to seven additional colors that will be transparent, with individual opacities per color (:iss:`7646`)
- Fix a regression in the previous release that broke use of the ``cd`` command in session files (:iss:`7829`) - Fix a regression in the previous release that broke use of the ``cd`` command in session files (:iss:`7829`)
- macOS: Fix shortcuts that become entries in the global menubar being reported as removed shortcuts in the debug output - macOS: Fix shortcuts that become entries in the global menubar being reported as removed shortcuts in the debug output
@@ -132,7 +134,7 @@ Detailed list of changes
- launch command: A new :option:`launch --bias` option to adjust the size of newly created windows declaratively (:iss:`7634`) - launch command: A new :option:`launch --bias` option to adjust the size of newly created windows declaratively (:iss:`7634`)
- A new option :opt:`second_transparent_bg` to make a second background color semi-transparent via :opt:`background_opacity`. Useful for things like cursor line highlight in editors (:iss:`7646`) - A new option :opt:`transparent_background_colors` to make a second background color semi-transparent via :opt:`background_opacity`. Useful for things like cursor line highlight in editors (:iss:`7646`)
- A new :doc:`notify </kittens/notify>` kitten to show desktop notifications - A new :doc:`notify </kittens/notify>` kitten to show desktop notifications
from the command line with support for icons, buttons and more. from the command line with support for icons, buttons and more.

View File

@@ -69,8 +69,11 @@ selection_foreground The foreground color of selections
cursor The color of the text cursor Foreground color cursor The color of the text cursor Foreground color
cursor_text The color of text under the cursor Background color cursor_text The color of text under the cursor Background color
visual_bell The color of a visual bell Automatic color selection based on current screen colors visual_bell The color of a visual bell Automatic color selection based on current screen colors
second_transparent_background A color that might be rendered semi-transparent No second color is made transparent transparent_background_color1..8 A background color that is rendered Unset
in addition to the default background color with the specified opacity in cells that have
the specified background color. An opacity
value less than zero means, use the
:opt:`background_opacity` value.
================================= =============================================== =============================== ================================= =============================================== ===============================
In this table the third column shows what effect setting the color to *dynamic* In this table the third column shows what effect setting the color to *dynamic*
@@ -160,8 +163,19 @@ RGB colors are encoded in one of three forms:
``rgbi:<red>/<green>/<blue>`` ``rgbi:<red>/<green>/<blue>``
red, green, and blue are floating-point values between 0.0 and 1.0, inclusive. The input format for these values is an optional red, green, and blue are floating-point values between 0.0 and 1.0, inclusive. The input format for these values is an optional
sign, a string of numbers possibly containing a decimal point, and an optional exponent field containing an E or e followed by a possibly sign, a string of numbers possibly containing a decimal point, and an optional exponent field containing an E or e followed by a possibly
signed integer string. signed integer string. Values outside the ``0 - 1`` range must be clipped to be within the range.
If a color should have an alpha component, it must be suffixed to the color
specification in the form :code:`@number between zero and one`. For example::
red@0.5 rgb:ff0000@0.1 #ff0000@0.3
The syntax for the floating point alpha component is the same as used for the
components of ``rgbi`` defined above. When not specified, the default alpha
value is ``1.0``. Values outside the range ``0 - 1`` must be clipped
to be within the range, negative values may have special context dependent
meaning.
In addition, the following color names are accepted (case-insensitively) corresponding to the In addition, the following color names are accepted (case-insensitively) corresponding to the
specified RGB values. specified RGB values.

View File

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

View File

@@ -4,13 +4,16 @@
// Inputs {{{ // Inputs {{{
layout(std140) uniform CellRenderData { 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;
uint xnum, ynum, cursor_fg_sprite_idx; uint xnum, ynum, cursor_fg_sprite_idx;
float cursor_x, cursor_y, cursor_w, cursor_opacity; 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]; uint color_table[NUM_COLORS + MARK_MASK + MARK_MASK + 2];
}; };
#if (PHASE == PHASE_BACKGROUND) #if (PHASE == PHASE_BACKGROUND)
@@ -145,12 +148,30 @@ CellData set_vertex_position() {
return CellData(has_cursor, has_cursor * is_block_cursor, pos); 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() { void main() {
CellData cell_data = set_vertex_position(); CellData cell_data = set_vertex_position();
// set cell color indices {{{ // 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 text_attrs = sprite_coords[3];
uint is_reversed = ((text_attrs >> REVERSE_SHIFT) & ONE); uint is_reversed = ((text_attrs >> REVERSE_SHIFT) & ONE);
uint is_inverted = is_reversed + inverted; uint is_inverted = is_reversed + inverted;
@@ -194,42 +215,34 @@ void main() {
// }}} // }}}
// Background {{{ // Background {{{
float bg_is_not_transparent = step(1, float(abs( #if PHASE == PHASE_BOTH && !defined(TRANSPARENT) // fast case single pass opaque background
(bg_as_uint - default_colors[1]) * (bg_as_uint - second_transparent_bg) bg_alpha = 1;
))); // bg_is_not_transparent = 0 if bg_as_uint in (default_colors[1], second_transparent_bg) else 1
draw_bg = 1; draw_bg = 1;
#else
bg_alpha = calc_background_opacity(bg_as_uint);
#if (PHASE == PHASE_BACKGROUND) #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 // 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)); float cell_has_non_default_bg = step(1.f, abs(float(bg_as_uint - bg_colors0))); // 0 if has default bg else 1
draw_bg = step(1, float(draw_bg_bitfield & draw_bg_mask)); 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 #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); float is_special_cell = cell_data.has_block_cursor + float(is_selected & ONE);
#if (PHASE != PHASE_SPECIAL) #if PHASE == PHASE_SPECIAL
is_special_cell += bg_is_not_transparent + float(is_reversed); // Only special cells must be drawn and they must have bg_alpha 1
#endif
bg_alpha = step(0.5, is_special_cell); // bg_alpha = 1 if is_special_cell else 0 bg_alpha = step(0.5, is_special_cell); // bg_alpha = 1 if is_special_cell else 0
#if (PHASE != PHASE_SPECIAL) #else
bg_alpha = bg_alpha + (1.0f - bg_alpha) * background_opacity; // bg_alpha = 1 if bg_alpha else background_opacity is_special_cell += float(is_reversed); // bg_alpha should be 1 for reverse video cells as well
bg_alpha *= draw_bg; // if not draw_bg: bg_alpha = 0 is_special_cell = step(0.5, is_special_cell); // is_special_cell = 1 if is_special_cell else 0
#endif bg_alpha = bg_alpha * (1. - float(is_special_cell)) + is_special_cell; // bg_alpha = 1 if is_special_cell else bg_alpha
#endif #endif
bg_alpha *= draw_bg;
#endif // ends fast case #if else
// Selection and cursor // 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); 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); 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

@@ -80,9 +80,18 @@ set_configured_colors(ColorProfile *self, PyObject *opts) {
n(default_fg, foreground); n(default_bg, background); n(default_fg, foreground); n(default_bg, background);
n(cursor_color, cursor); n(cursor_text_color, cursor_text_color); n(cursor_color, cursor); n(cursor_text_color, cursor_text_color);
n(highlight_fg, selection_foreground); n(highlight_bg, selection_background); 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 #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 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->orig_color_table, src->orig_color_table, sizeof(dest->color_table));
memcpy(&dest->configured, &src->configured, sizeof(dest->configured)); memcpy(&dest->configured, &src->configured, sizeof(dest->configured));
memcpy(&dest->overridden, &src->overridden, sizeof(dest->overridden)); 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; dest->dirty = true;
} }
@@ -226,12 +237,30 @@ patch_color_profiles(PyObject *module UNUSED, PyObject *args) {
S(foreground, default_fg); S(background, default_bg); S(cursor, cursor_color); S(foreground, default_fg); S(background, default_bg); S(cursor, cursor_color);
S(selection_foreground, highlight_fg); S(selection_background, highlight_bg); 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(cursor_text_color, cursor_text_color); S(visual_bell_color, visual_bell_color);
S(second_transparent_bg, second_transparent_bg);
#undef SI #undef SI
#undef S #undef S
// TODO: Patch transparent_colors
Py_RETURN_NONE; 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;
if (*opacity < 0) *opacity = OPT(background_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;
if (*opacity < 0) *opacity = OPT(background_opacity);
return true;
}
}
return false;
}
DynamicColor DynamicColor
colorprofile_to_color(const ColorProfile *self, DynamicColor entry, DynamicColor defval) { colorprofile_to_color(const ColorProfile *self, DynamicColor entry, DynamicColor defval) {
switch(entry.type) { switch(entry.type) {
@@ -295,9 +324,10 @@ as_dict(ColorProfile *self, PyObject *args UNUSED) {
}} }}
D(default_fg, foreground); D(default_bg, background); D(default_fg, foreground); D(default_bg, background);
D(cursor_color, cursor); D(cursor_text_color, cursor_text); D(highlight_fg, selection_foreground); 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 #undef D
// TODO: Add transparent_colors
return ans; return ans;
} }
@@ -373,6 +403,8 @@ copy_color_table_to_buffer(ColorProfile *self, color_type *buf, int offset, size
static void static void
push_onto_color_stack_at(ColorProfile *self, unsigned int i) { 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; self->color_stack[i].dynamic_colors = self->overridden;
memcpy(self->color_stack[i].color_table, self->color_table, sizeof(self->color_stack->color_table)); memcpy(self->color_stack[i].color_table, self->color_table, sizeof(self->color_stack->color_table));
} }
@@ -381,6 +413,7 @@ static void
copy_from_color_stack_at(ColorProfile *self, unsigned int i) { copy_from_color_stack_at(ColorProfile *self, unsigned int i) {
self->overridden = self->color_stack[i].dynamic_colors; self->overridden = self->color_stack[i].dynamic_colors;
memcpy(self->color_table, self->color_stack[i].color_table, sizeof(self->color_table)); 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 bool
@@ -477,7 +510,6 @@ CGETSET(cursor_text_color, true)
CGETSET(highlight_fg, true) CGETSET(highlight_fg, true)
CGETSET(highlight_bg, true) CGETSET(highlight_bg, true)
CGETSET(visual_bell_color, true) CGETSET(visual_bell_color, true)
CGETSET(second_transparent_bg, true)
#undef CGETSET #undef CGETSET
static PyGetSetDef cp_getsetters[] = { static PyGetSetDef cp_getsetters[] = {
@@ -488,7 +520,6 @@ static PyGetSetDef cp_getsetters[] = {
GETSET(highlight_fg) GETSET(highlight_fg)
GETSET(highlight_bg) GETSET(highlight_bg)
GETSET(visual_bell_color) GETSET(visual_bell_color)
GETSET(second_transparent_bg)
{NULL} /* Sentinel */ {NULL} /* Sentinel */
}; };
@@ -508,6 +539,36 @@ reload_from_opts(ColorProfile *self, PyObject *args UNUSED) {
Py_RETURN_NONE; Py_RETURN_NONE;
} }
static PyObject*
get_transparent_background_color(ColorProfile *self, PyObject *index) {
if (!PyLong_Check(index)) { PyErr_SetString(PyExc_TypeError, "index must be an int"); return NULL; }
unsigned long idx = PyLong_AsUnsignedLong(index);
if (PyErr_Occurred()) return NULL;
if (idx >= arraysz(self->configured_transparent_colors)) Py_RETURN_NONE;
TransparentDynamicColor *c = self->overriden_transparent_colors[idx].is_set ? self->overriden_transparent_colors + idx : self->configured_transparent_colors + idx;
if (!c->is_set) Py_RETURN_NONE;
float opacity = c->opacity >= 0 ? c->opacity : OPT(background_opacity);
return (PyObject*)alloc_color((c->color >> 16) & 0xff, (c->color >> 8) & 0xff, c->color & 0xff, (unsigned)(255.f * opacity));
}
static PyObject*
set_transparent_background_color(ColorProfile *self, PyObject *const *args, Py_ssize_t nargs) {
if (nargs < 1) { PyErr_SetString(PyExc_TypeError, "must specify index"); return NULL; }
if (!PyLong_Check(args[0])) { PyErr_SetString(PyExc_TypeError, "index must be an int"); return NULL; }
unsigned long idx = PyLong_AsUnsignedLong(args[0]);
if (PyErr_Occurred()) return NULL;
if (idx >= arraysz(self->configured_transparent_colors)) Py_RETURN_NONE;
if (nargs < 2) { self->overriden_transparent_colors[idx].is_set = false; Py_RETURN_NONE; }
if (!PyObject_TypeCheck(args[1], &Color_Type)) { PyErr_SetString(PyExc_TypeError, "color must be Color object"); return NULL; }
Color *c = (Color*)args[1];
float opacity = (float)(c->color.alpha) / 255.f;
if (nargs > 2 && PyFloat_Check(args[2])) opacity = (float)PyFloat_AsDouble(args[2]);
self->overriden_transparent_colors[idx].is_set = true;
self->overriden_transparent_colors[idx].color = c->color.rgb;
self->overriden_transparent_colors[idx].opacity = MAX(-1.f, MIN(opacity, 1.f));
Py_RETURN_NONE;
}
static PyMethodDef cp_methods[] = { static PyMethodDef cp_methods[] = {
METHOD(reset_color_table, METH_NOARGS) METHOD(reset_color_table, METH_NOARGS)
METHOD(as_dict, METH_NOARGS) METHOD(as_dict, METH_NOARGS)
@@ -515,7 +576,9 @@ static PyMethodDef cp_methods[] = {
METHOD(as_color, METH_O) METHOD(as_color, METH_O)
METHOD(reset_color, METH_O) METHOD(reset_color, METH_O)
METHOD(set_color, METH_VARARGS) METHOD(set_color, METH_VARARGS)
METHODB(get_transparent_background_color, METH_O),
METHODB(reload_from_opts, METH_VARARGS), METHODB(reload_from_opts, METH_VARARGS),
{"set_transparent_background_color", (PyCFunction)(void(*)(void))set_transparent_background_color, METH_FASTCALL, ""},
{NULL} /* Sentinel */ {NULL} /* Sentinel */
}; };
@@ -552,7 +615,7 @@ new_color(PyTypeObject *type UNUSED, PyObject *args, PyObject *kwds) {
} }
static PyObject* static PyObject*
color_as_int(Color *self) { Color_as_int(Color *self) {
return PyLong_FromUnsignedLong(self->color.val); return PyLong_FromUnsignedLong(self->color.val);
} }
@@ -566,7 +629,7 @@ color_truediv(Color *self, PyObject *divisor) {
} }
static PyNumberMethods color_number_methods = { static PyNumberMethods color_number_methods = {
.nb_int = (unaryfunc)color_as_int, .nb_int = (unaryfunc)Color_as_int,
.nb_true_divide = (binaryfunc)color_truediv, .nb_true_divide = (binaryfunc)color_truediv,
}; };

View File

@@ -323,15 +323,21 @@ typedef union DynamicColor {
} DynamicColor; } DynamicColor;
typedef struct { 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; } DynamicColors;
typedef struct TransparentDynamicColor {
color_type color; float opacity; bool is_set;
} TransparentDynamicColor;
typedef struct { typedef struct {
PyObject_HEAD PyObject_HEAD
bool dirty; bool dirty;
uint32_t color_table[256], orig_color_table[256]; 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; unsigned int color_stack_idx, color_stack_sz;
DynamicColors configured, overridden; DynamicColors configured, overridden;
color_type mark_foregrounds[MARK_MASK+1], mark_backgrounds[MARK_MASK+1]; 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); bool set_iutf8(int, bool);
DynamicColor colorprofile_to_color(const ColorProfile *self, DynamicColor entry, DynamicColor defval); 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 color_type
colorprofile_to_color_with_fallback(ColorProfile *self, DynamicColor entry, DynamicColor defval, DynamicColor fallback, DynamicColor falback_defval); 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); 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 @visual_bell_color.setter
def visual_bell_color(self, val: Union[None|int|Color]) -> None: ... 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 __init__(self, opts: Optional[Options] = None): ...
def as_dict(self) -> Dict[str, Optional[int]]: def as_dict(self) -> Dict[str, Optional[int]]:
@@ -833,6 +828,9 @@ class ColorProfile:
def reload_from_opts(self, opts: Optional[Options] = None) -> None: ... def reload_from_opts(self, opts: Optional[Options] = None) -> None: ...
def get_transparent_background_color(self, index: int) -> Color | None: ...
def set_transparent_background_color(self, index: int, color: Color | None = None, opacity: float | None = None) -> None: ...
def patch_color_profiles( def patch_color_profiles(
spec: Dict[str, Optional[int]], profiles: Tuple[ColorProfile, ...], change_configured: bool spec: Dict[str, Optional[int]], profiles: Tuple[ColorProfile, ...], change_configured: bool

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 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 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 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 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 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 desirable that you set the :opt:`background` color to a color the matches the
@@ -1527,14 +1527,22 @@ opt('background_image_linear', 'no',
long_text='When background image is scaled, whether linear interpolation should be used.' long_text='When background image is scaled, whether linear interpolation should be used.'
) )
opt('second_transparent_bg', 'none', option_type='to_color_or_none', long_text=''' opt('transparent_background_colors', '', option_type='transparent_background_colors', long_text='''
When the background color matches this color, :opt:`background_opacity` is applied to it A space separated list of upto 7 colors, with opacity. When the background color of a cell matches one of these colors,
to render it as semi-transparent, just as for colors matching the main :opt:`background` color. it is rendered semi-transparent using the specified opacity.
Useful in more complex UIs like editors where you could want more than a single background color Useful in more complex UIs like editors where you could want more than a single background color
to be rendered as transparent, for instance, for a cursor highlight line background. to be rendered as transparent, for instance, for a cursor highlight line background or a highlighted block.
Terminal applications can set this color using :ref:`The kitty color control <color_control>` Terminal applications can set this color using :ref:`The kitty color control <color_control>`
escape code. escape code.
''')
The syntax for specifiying colors is: :code:`color@opacity`, where the :code:`@opacity`
part is optional. When unspecified, the value of :opt:`background_opacity` is used. For example::
transparent_background_colors red@0.5 #00ff00@0.3
'''
)
opt('dynamic_background_opacity', 'no', opt('dynamic_background_opacity', 'no',
option_type='to_bool', ctype='bool', option_type='to_bool', ctype='bool',

11
kitty/options/parse.py generated
View File

@@ -19,8 +19,9 @@ from kitty.options.utils import (
shell_integration, store_multiple, symbol_map, tab_activity_symbol, tab_bar_edge, 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_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, 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, to_layout_names, to_modifiers, transparent_background_colors, url_prefixes, url_style,
visual_window_select_characters, window_border_width, window_logo_scale, window_size visual_bell_duration, visual_window_select_characters, window_border_width, window_logo_scale,
window_size
) )
@@ -1193,9 +1194,6 @@ class Parser:
def scrollback_pager_history_size(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: 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) 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: def select_by_word_characters(self, val: str, ans: typing.Dict[str, typing.Any]) -> None:
ans['select_by_word_characters'] = str(val) ans['select_by_word_characters'] = str(val)
@@ -1326,6 +1324,9 @@ class Parser:
def touch_scroll_multiplier(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: def touch_scroll_multiplier(self, val: str, ans: typing.Dict[str, typing.Any]) -> None:
ans['touch_scroll_multiplier'] = float(val) 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: def undercurl_style(self, val: str, ans: typing.Dict[str, typing.Any]) -> None:
val = val.lower() val = val.lower()
if val not in self.choices_for_undercurl_style: if val not in self.choices_for_undercurl_style:

View File

@@ -409,7 +409,6 @@ option_names = ( # {{{
'scrollback_lines', 'scrollback_lines',
'scrollback_pager', 'scrollback_pager',
'scrollback_pager_history_size', 'scrollback_pager_history_size',
'second_transparent_bg',
'select_by_word_characters', 'select_by_word_characters',
'select_by_word_characters_forward', 'select_by_word_characters_forward',
'selection_background', 'selection_background',
@@ -443,6 +442,7 @@ option_names = ( # {{{
'text_composition_strategy', 'text_composition_strategy',
'text_fg_override_threshold', 'text_fg_override_threshold',
'touch_scroll_multiplier', 'touch_scroll_multiplier',
'transparent_background_colors',
'undercurl_style', 'undercurl_style',
'underline_hyperlinks', 'underline_hyperlinks',
'update_check_interval', 'update_check_interval',
@@ -574,7 +574,6 @@ class Options:
scrollback_lines: int = 2000 scrollback_lines: int = 2000
scrollback_pager: typing.List[str] = ['less', '--chop-long-lines', '--RAW-CONTROL-CHARS', '+INPUT_LINE_NUMBER'] scrollback_pager: typing.List[str] = ['less', '--chop-long-lines', '--RAW-CONTROL-CHARS', '+INPUT_LINE_NUMBER']
scrollback_pager_history_size: int = 0 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: str = '@-./_~?&=%+#'
select_by_word_characters_forward: str = '' select_by_word_characters_forward: str = ''
selection_background: typing.Optional[kitty.fast_data_types.Color] = Color(255, 250, 205) selection_background: typing.Optional[kitty.fast_data_types.Color] = Color(255, 250, 205)
@@ -607,6 +606,7 @@ class Options:
text_composition_strategy: str = 'platform' text_composition_strategy: str = 'platform'
text_fg_override_threshold: float = 0.0 text_fg_override_threshold: float = 0.0
touch_scroll_multiplier: float = 1.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' undercurl_style: choices_for_undercurl_style = 'thin-sparse'
underline_hyperlinks: choices_for_underline_hyperlinks = 'hover' underline_hyperlinks: choices_for_underline_hyperlinks = 'hover'
update_check_interval: float = 24.0 update_check_interval: float = 24.0
@@ -1035,7 +1035,6 @@ nullable_colors = frozenset({
'active_border_color' 'active_border_color'
'tab_bar_background' 'tab_bar_background'
'tab_bar_margin_color' 'tab_bar_margin_color'
'second_transparent_bg'
'selection_foreground' 'selection_foreground'
'selection_background' 'selection_background'
}) })

View File

@@ -1554,6 +1554,23 @@ def visual_bell_duration(spec: str) -> Tuple[float, EasingFunction, EasingFuncti
return parse_animation(spec, interval=0.) 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: def deprecated_hide_window_decorations_aliases(key: str, val: str, ans: Dict[str, Any]) -> None:
if not hasattr(deprecated_hide_window_decorations_aliases, key): if not hasattr(deprecated_hide_window_decorations_aliases, key):
setattr(deprecated_hide_window_decorations_aliases, key, True) 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 static void
cell_update_uniform_block(ssize_t vao_idx, Screen *screen, int uniform_buffer, const CellRenderData *crd, CursorRenderInfo *cursor, OSWindow *os_window) { cell_update_uniform_block(ssize_t vao_idx, Screen *screen, int uniform_buffer, const CellRenderData *crd, CursorRenderInfo *cursor, OSWindow *os_window) {
struct GPUCellRenderData { 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;
GLuint xnum, ynum, cursor_fg_sprite_idx; GLuint xnum, ynum, cursor_fg_sprite_idx;
GLfloat cursor_x, cursor_y, cursor_w, cursor_opacity; 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 // Send the uniform data
struct GPUCellRenderData *rd = (struct GPUCellRenderData*)map_vao_buffer(vao_idx, uniform_buffer, GL_WRITE_ONLY); struct GPUCellRenderData *rd = (struct GPUCellRenderData*)map_vao_buffer(vao_idx, uniform_buffer, GL_WRITE_ONLY);
@@ -307,8 +309,13 @@ 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)); 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 #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->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) 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 // selection
if (IS_SPECIAL_COLOR(highlight_fg)) { if (IS_SPECIAL_COLOR(highlight_fg)) {
if (IS_SPECIAL_COLOR(highlight_bg)) { if (IS_SPECIAL_COLOR(highlight_bg)) {
@@ -320,7 +327,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_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->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 // Cursor position
enum { BLOCK_IDX = 0, BEAM_IDX = NUM_UNDERLINE_STYLES + 3, UNDERLINE_IDX = NUM_UNDERLINE_STYLES + 4, UNFOCUSED_IDX = NUM_UNDERLINE_STYLES + 5 }; 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; Line *line_for_cursor = NULL;
@@ -338,7 +344,7 @@ cell_update_uniform_block(ssize_t vao_idx, Screen *screen, int uniform_buffer, c
case CURSOR_HOLLOW: case CURSOR_HOLLOW:
rd->cursor_fg_sprite_idx = UNFOCUSED_IDX; break; 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; index_type cell_color_x = cursor->x;
bool reversed = false; bool reversed = false;
if (cursor->x < screen->columns && cursor->y < screen->lines) { if (cursor->x < screen->columns && cursor->y < screen->lines) {
@@ -352,10 +358,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); colors_for_cell(line_for_cursor, cp, &cell_color_x, &cell_fg, &cell_bg, &reversed);
} }
if (IS_SPECIAL_COLOR(cursor_color)) { 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); 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->default_bg; rd->cursor_bg = rd->default_fg; } else { rd->cursor_fg = rd->bg_colors0; rd->cursor_bg = rd->default_fg; }
if (cell_bg == cell_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_fg = cell_bg; rd->cursor_bg = cell_fg; }
} else { } else {
rd->cursor_bg = COLOR(cursor_color); rd->cursor_bg = COLOR(cursor_color);
@@ -375,7 +381,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); 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->sprite_dx = 1.0f / (float)x; rd->sprite_dy = 1.0f / (float)y;
rd->inverted = screen_invert_colors(screen) ? 1 : 0; rd->inverted = screen_invert_colors(screen) ? 1 : 0;
rd->background_opacity = os_window->is_semi_transparent ? os_window->background_opacity : 1.0f;
#undef COLOR #undef COLOR
rd->url_color = OPT(url_color); rd->url_style = OPT(url_style); rd->url_color = OPT(url_color); rd->url_style = OPT(url_style);

View File

@@ -447,17 +447,46 @@ def process_remote_print(msg: memoryview) -> str:
return replace_c0_codes_except_nl_space_tab(base64_decode(msg)).decode('utf-8', 'replace') return replace_c0_codes_except_nl_space_tab(base64_decode(msg)).decode('utf-8', 'replace')
def transparent_background_color_control(cp: ColorProfile, responses: dict[str, str], index: int, key: str, sep: str, val: str) -> None:
if sep == '=':
if val == '?':
if index > 8:
responses[key] = '?'
else:
c = cp.get_transparent_background_color(index - 1)
if c is None:
responses[key] = ''
else:
opacity = max(0, min(c.alpha / 255.0, 1))
responses[key] = f'rgb:{c.red:02x}/{c.green:02x}/{c.blue:02x}@{opacity:.4f}'
elif index <= 8:
col, _, o = val.partition('@')
try:
opacity = float(o)
except Exception:
opacity = -1.0
c = to_color(col)
if c is not None:
cp.set_transparent_background_color(index - 1, c, opacity)
elif index <= 8:
cp.set_transparent_background_color(index - 1)
def color_control(cp: ColorProfile, code: int, value: Union[str, bytes, memoryview] = '') -> str: def color_control(cp: ColorProfile, code: int, value: Union[str, bytes, memoryview] = '') -> str:
if isinstance(value, (bytes, memoryview)): if isinstance(value, (bytes, memoryview)):
value = str(value, 'utf-8', 'replace') value = str(value, 'utf-8', 'replace')
responses = {} responses: dict[str, str] = {}
for rec in value.split(';'): for rec in value.split(';'):
key, sep, val = rec.partition('=') key, sep, val = rec.partition('=')
if key.startswith('transparent_background_color'):
index = int(key[len('transparent_background_color'):])
transparent_background_color_control(cp, responses, index, key, sep, val)
continue
attr = { attr = {
'foreground': 'default_fg', 'background': 'default_bg', 'foreground': 'default_fg', 'background': 'default_bg',
'selection_background': 'highlight_bg', 'selection_foreground': 'highlight_fg', 'selection_background': 'highlight_bg', 'selection_foreground': 'highlight_fg',
'cursor': 'cursor_color', 'cursor_text': 'cursor_text_color', '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, '') }.get(key, '')
colnum = -1 colnum = -1
with suppress(Exception): with suppress(Exception):
@@ -480,6 +509,7 @@ def color_control(cp: ColorProfile, code: int, value: Union[str, bytes, memoryvi
else: else:
if attr: if attr:
if val: if val:
val = val.partition('@')[0]
col = to_color(val) col = to_color(val)
if col is not None: if col is not None:
setattr(cp, attr, col) setattr(cp, attr, col)
@@ -488,6 +518,7 @@ def color_control(cp: ColorProfile, code: int, value: Union[str, bytes, memoryvi
setattr(cp, attr, None) setattr(cp, attr, None)
else: else:
if 0 <= colnum <= 255: if 0 <= colnum <= 255:
val = val.partition('@')[0]
col = to_color(val) col = to_color(val)
if col is not None: if col is not None:
cp.set_color(colnum, color_as_int(col)) cp.set_color(colnum, color_as_int(col))

View File

@@ -59,6 +59,8 @@ class Callbacks:
response = color_control(self.color_profile, code, data) response = color_control(self.color_profile, code, data)
if response: if response:
def p(x): def p(x):
if '@' in x:
return (to_color(x.partition('@')[0]), int(255 * float(x.partition('@')[2])))
ans = to_color(x) ans = to_color(x)
if ans is None: if ans is None:
ans = x ans = x

View File

@@ -1280,3 +1280,10 @@ class TestScreen(BaseTest):
q({'selection_background': ''}) q({'selection_background': ''})
self.assertIsNone(s.color_profile.highlight_bg) self.assertIsNone(s.color_profile.highlight_bg)
q({'selection_background': '?'}, {'selection_background': ''}) q({'selection_background': '?'}, {'selection_background': ''})
s.color_profile.reload_from_opts(defaults)
q({'transparent_background_color9': '?'}, {'transparent_background_color9': '?'})
q({'transparent_background_color2': '?'}, {'transparent_background_color2': ''})
q({'transparent_background_color2': 'red@0.5'})
q({'transparent_background_color2': '?'}, {'transparent_background_color2': (Color(255, 0, 0), 126)})
q({'transparent_background_color2': '#ffffff@-1'})
q({'transparent_background_color2': '?'}, {'transparent_background_color2': (Color(255, 255, 255), 255)})

View File

@@ -15,15 +15,14 @@ import (
var nullable_colors = map[string]bool{ var nullable_colors = map[string]bool{
// generated by gen-config.py do not edit // generated by gen-config.py do not edit
// NULLABLE_COLORS_START // NULLABLE_COLORS_START
"active_border_color": true, "active_border_color": true,
"cursor": true, "cursor": true,
"cursor_text_color": true, "cursor_text_color": true,
"second_transparent_bg": true, "selection_background": true,
"selection_background": true, "selection_foreground": true,
"selection_foreground": true, "tab_bar_background": true,
"tab_bar_background": true, "tab_bar_margin_color": true,
"tab_bar_margin_color": true, "visual_bell_color": true,
"visual_bell_color": true,
// NULLABLE_COLORS_END // NULLABLE_COLORS_END
} }

View File

@@ -309,7 +309,6 @@ var AllColorSettingNames = map[string]bool{ // {{{
"mark2_foreground": true, "mark2_foreground": true,
"mark3_background": true, "mark3_background": true,
"mark3_foreground": true, "mark3_foreground": true,
"second_transparent_bg": true,
"selection_background": true, "selection_background": true,
"selection_foreground": true, "selection_foreground": true,
"tab_bar_background": true, "tab_bar_background": true,