Allow rendering the cursor with reverse video

Also clean up handling of dynamic global colors.
TODO: Implement none for selection_fg
TODO: Add some tests
TODO: Check that changing colors via remote control works

Fixes #126
This commit is contained in:
Kovid Goyal 2021-10-28 00:19:36 +05:30
parent 3ca3c67828
commit 0fdafd8398
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
16 changed files with 167 additions and 101 deletions

View File

@ -16,6 +16,9 @@ To update |kitty|, :doc:`follow the instructions <binary>`.
the keyboard. Pressing it causes numbers to appear over each visible window
and you can press the number to focus the corresponding window (:iss:`4110`)
- Allow rendering the cursor with a *reverse video* effect. See :opt:`cursor`
for details (:iss:`126`)
- A new option :opt:`tab_bar_align` to draw the tab bar centered or right
aligned (:iss:`3946`)

View File

@ -12,9 +12,9 @@
// Inputs {{{
layout(std140) uniform CellRenderData {
float xstart, ystart, dx, dy, sprite_dx, sprite_dy, background_opacity, cursor_text_uses_bg;
float xstart, ystart, dx, dy, sprite_dx, sprite_dy, background_opacity;
uint default_fg, default_bg, highlight_fg, highlight_bg, cursor_color, cursor_text_color, url_color, url_style, inverted;
uint default_fg, default_bg, highlight_fg, highlight_bg, cursor_fg, cursor_bg, url_color, url_style, inverted;
uint xnum, ynum, cursor_fg_sprite_idx;
float cursor_x, cursor_y, cursor_w;
@ -198,8 +198,8 @@ void main() {
strike_pos = to_sprite_pos(pos, ((text_attrs >> STRIKE_SHIFT) & ONE) * FOUR, ZERO, ZERO);
// Cursor
cursor_color_vec = vec4(color_to_vec(cursor_color), 1.0);
vec3 final_cursor_text_color = mix(color_to_vec(cursor_text_color), bg, cursor_text_uses_bg);
cursor_color_vec = vec4(color_to_vec(cursor_bg), 1.0);
vec3 final_cursor_text_color = color_to_vec(cursor_fg);
foreground = choose_color(cell_has_block_cursor, final_cursor_text_color, foreground);
decoration_fg = choose_color(cell_has_block_cursor, final_cursor_text_color, decoration_fg);
cursor_pos = to_sprite_pos(pos, cursor_fg_sprite_idx * uint(cell_has_cursor), ZERO, ZERO);
@ -237,7 +237,7 @@ void main() {
#if defined(SPECIAL) || defined(SIMPLE)
// Selection and cursor
bg = choose_color(float(is_selected & ONE), color_to_vec(highlight_bg), bg);
background = choose_color(cell_has_block_cursor, color_to_vec(cursor_color), bg);
background = choose_color(cell_has_block_cursor, color_to_vec(cursor_bg), bg);
#if !defined(TRANSPARENT) && defined(SPECIAL)
float is_special_cell = cell_has_block_cursor + float(is_selected & ONE);
bg_alpha = step(0.5, is_special_cell);

View File

@ -574,9 +574,7 @@ collect_cursor_info(CursorRenderInfo *ans, Window *w, monotonic_t now, OSWindow
}
if (!do_draw_cursor) { ans->is_visible = false; return; }
ans->is_visible = true;
ColorProfile *cp = rd->screen->color_profile;
ans->shape = cursor->shape ? cursor->shape : OPT(cursor_shape);
ans->color = colorprofile_to_color(cp, cp->overridden.cursor_color, cp->configured.cursor_color);
ans->is_focused = os_window->is_focused;
}
@ -617,7 +615,7 @@ prepare_to_render_os_window(OSWindow *os_window, monotonic_t now, unsigned int *
#define WD w->render_data
if (w->visible && WD.screen) {
*num_visible_windows += 1;
color_type window_bg = colorprofile_to_color(WD.screen->color_profile, WD.screen->color_profile->overridden.default_bg, WD.screen->color_profile->configured.default_bg);
color_type window_bg = colorprofile_to_color(WD.screen->color_profile, WD.screen->color_profile->overridden.default_bg, WD.screen->color_profile->configured.default_bg).rgb;
if (*num_visible_windows == 1) first_window_bg = window_bg;
if (first_window_bg != window_bg) *all_windows_have_same_bg = false;
if (w->last_drag_scroll_at > 0) {

View File

@ -151,65 +151,65 @@ patch_color_profiles(PyObject *module UNUSED, PyObject *args) {
S(background, i); S(foreground, i);
#undef S
}
#define SI(profile_name) \
DynamicColor color; \
if (PyLong_Check(v)) { \
color.rgb = PyLong_AsUnsignedLong(v); color.type = COLOR_IS_RGB; \
} else { color.rgb = 0; color.type = COLOR_IS_SPECIAL; }\
self->overridden.profile_name = color; \
if (change_configured) self->configured.profile_name = color; \
self->dirty = true;
#define S(config_name, profile_name) { \
v = PyDict_GetItemString(spec, #config_name); \
if (v && PyLong_Check(v)) { \
color_type color = PyLong_AsUnsignedLong(v); \
if (v) { \
for (Py_ssize_t i = 0; i < PyTuple_GET_SIZE(profiles); i++) { \
self = (ColorProfile*)PyTuple_GET_ITEM(profiles, i); \
self->overridden.profile_name = (color << 8) | 2; \
if (change_configured) self->configured.profile_name = color; \
self->dirty = true; \
SI(profile_name); \
} \
} \
}
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);
#undef SI
#undef S
PyObject *cursor_text_color = PyDict_GetItemString(spec, "cursor_text_color");
if (cursor_text_color) {
for (Py_ssize_t i = 0; i < PyTuple_GET_SIZE(profiles); i++) {
self = (ColorProfile*)PyTuple_GET_ITEM(profiles, i);
self->overridden.cursor_text_color = 0x111111;
self->overridden.cursor_text_uses_bg = 3;
if (PyLong_Check(cursor_text_color)) {
self->overridden.cursor_text_color = (PyLong_AsUnsignedLong(cursor_text_color) << 8) | 2;
self->overridden.cursor_text_uses_bg = 1;
}
if (change_configured) {
self->configured.cursor_text_color = self->overridden.cursor_text_color;
self->configured.cursor_text_uses_bg = self->overridden.cursor_text_uses_bg;
}
self->dirty = true;
}
}
Py_RETURN_NONE;
}
color_type
colorprofile_to_color(ColorProfile *self, color_type entry, color_type defval) {
color_type t = entry & 0xFF, r;
switch(t) {
case 1:
r = (entry >> 8) & 0xff;
return self->color_table[r];
case 2:
return entry >> 8;
default:
DynamicColor
colorprofile_to_color(ColorProfile *self, DynamicColor entry, DynamicColor defval) {
switch(entry.type) {
case COLOR_NOT_SET:
return defval;
case COLOR_IS_INDEX: {
DynamicColor ans;
ans.rgb = self->color_table[entry.rgb & 0xff] & 0xffffff;
ans.type = COLOR_IS_RGB;
return ans;
}
case COLOR_IS_RGB:
case COLOR_IS_SPECIAL:
return entry;
}
return entry;
}
float
cursor_text_as_bg(ColorProfile *self) {
if (self->overridden.cursor_text_uses_bg & 1) {
return self->overridden.cursor_text_uses_bg & 2 ? 1.f : 0.f;
color_type
colorprofile_to_color_with_fallback(ColorProfile *self, DynamicColor entry, DynamicColor defval, DynamicColor fallback, DynamicColor falback_defval) {
switch(entry.type) {
case COLOR_NOT_SET:
case COLOR_IS_SPECIAL:
if (defval.type == COLOR_IS_SPECIAL) return colorprofile_to_color(self, fallback, falback_defval).rgb;
return defval.rgb;
case COLOR_IS_RGB:
return entry.rgb;
case COLOR_IS_INDEX:
return self->color_table[entry.rgb & 0xff] & 0xffffff;
}
return self->configured.cursor_text_uses_bg & 2 ? 1.f : 0.f;
return entry.rgb;
}
static PyObject*
as_dict(ColorProfile *self, PyObject *args UNUSED) {
#define as_dict_doc "Return all colors as a dictionary of color_name to integer (names are the same as used in kitty.conf)"
@ -225,8 +225,8 @@ as_dict(ColorProfile *self, PyObject *args UNUSED) {
if (ret != 0) { Py_CLEAR(ans); return NULL; }
}
#define D(attr, name) { \
color_type c = colorprofile_to_color(self, self->overridden.attr, 0xffffffff); \
if (c != 0xffffffff) { \
if (self->overridden.attr.type != COLOR_NOT_SET) { \
color_type c = colorprofile_to_color(self, self->overridden.attr, self->configured.attr).rgb; \
PyObject *val = PyLong_FromUnsignedLong(c); \
if (!val) { Py_CLEAR(ans); return PyErr_NoMemory(); } \
int ret = PyDict_SetItemString(ans, #name, val); \
@ -296,11 +296,14 @@ set_color(ColorProfile *self, PyObject *args) {
static PyObject*
set_configured_colors(ColorProfile *self, PyObject *args) {
#define set_configured_colors_doc "Set the configured colors"
if (!PyArg_ParseTuple(
args, "II|IIIII",
&(self->configured.default_fg), &(self->configured.default_bg),
&(self->configured.cursor_color), &(self->configured.cursor_text_color), &(self->configured.cursor_text_uses_bg),
&(self->configured.highlight_fg), &(self->configured.highlight_bg))) return NULL;
unsigned int default_fg, default_bg, cursor_color, cursor_text_color, highlight_fg, highlight_bg;
if (!PyArg_ParseTuple(args, "II|IIII", &default_fg, &default_bg,
&cursor_color, &cursor_text_color, &highlight_fg, &highlight_bg)) return NULL;
#define S(which) \
self->configured.which.rgb = which & 0xffffff; \
self->configured.which.type = (which & 0xff000000) ? COLOR_IS_RGB : COLOR_IS_SPECIAL;
S(default_fg); S(default_bg); S(cursor_color); S(cursor_text_color); S(highlight_fg); S(highlight_bg);
#undef S
self->dirty = true;
Py_RETURN_NONE;
}
@ -395,8 +398,14 @@ default_color_table(PyObject *self UNUSED, PyObject *args UNUSED) {
// Boilerplate {{{
#define CGETSET(name) \
static PyObject* name##_get(ColorProfile *self, void UNUSED *closure) { return PyLong_FromUnsignedLong(colorprofile_to_color(self, self->overridden.name, self->configured.name)); } \
static int name##_set(ColorProfile *self, PyObject *val, void UNUSED *closure) { if (val == NULL) { PyErr_SetString(PyExc_TypeError, "Cannot delete attribute"); return -1; } self->overridden.name = (color_type) PyLong_AsUnsignedLong(val); self->dirty = true; return 0; }
static PyObject* name##_get(ColorProfile *self, void UNUSED *closure) { return PyLong_FromUnsignedLong(colorprofile_to_color(self, self->overridden.name, self->configured.name).rgb); } \
static int name##_set(ColorProfile *self, PyObject *v, void UNUSED *closure) { \
if (v == NULL) { PyErr_SetString(PyExc_TypeError, "Cannot delete attribute: " #name); return -1; } \
unsigned long val = PyLong_AsUnsignedLong(v); \
self->overridden.name.rgb = val & 0xffffff; \
self->overridden.name.type = (val & 0xff000000) ? COLOR_IS_RGB : COLOR_NOT_SET; \
self->dirty = true; return 0; \
}
CGETSET(default_fg)
CGETSET(default_bg)

View File

@ -239,16 +239,27 @@ typedef struct {
bool is_visible, is_focused;
CursorShape shape;
unsigned int x, y;
color_type color;
} CursorRenderInfo;
typedef struct {
color_type default_fg, default_bg, cursor_color, cursor_text_color, cursor_text_uses_bg, highlight_fg, highlight_bg;
typedef enum DynamicColorType {
COLOR_NOT_SET, COLOR_IS_SPECIAL, COLOR_IS_INDEX, COLOR_IS_RGB
} DynamicColorType;
typedef union DynamicColor {
struct {
color_type rgb: 24;
DynamicColorType type: 8;
};
color_type val;
} DynamicColor;
typedef struct {
DynamicColor default_fg, default_bg, cursor_color, cursor_text_color, highlight_fg, highlight_bg;
} DynamicColors;
typedef struct {
DynamicColor dynamic_colors;
DynamicColors dynamic_colors;
uint32_t color_table[256];
} ColorStackEntry;
@ -260,7 +271,7 @@ typedef struct {
uint32_t orig_color_table[256];
ColorStackEntry *color_stack;
unsigned int color_stack_idx, color_stack_sz;
DynamicColor configured, overridden;
DynamicColors configured, overridden;
color_type mark_foregrounds[MARK_MASK+1], mark_backgrounds[MARK_MASK+1];
} ColorProfile;
@ -332,8 +343,9 @@ bool schedule_write_to_child(unsigned long id, unsigned int num, ...);
bool schedule_write_to_child_python(unsigned long id, const char *prefix, PyObject* tuple_of_str_or_bytes, const char *suffix);
bool set_iutf8(int, bool);
color_type colorprofile_to_color(ColorProfile *self, color_type entry, color_type defval);
float cursor_text_as_bg(ColorProfile *self);
DynamicColor colorprofile_to_color(ColorProfile *self, DynamicColor entry, DynamicColor defval);
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);
bool colorprofile_push_colors(ColorProfile*, unsigned int);
bool colorprofile_pop_colors(ColorProfile*, unsigned int);

View File

@ -642,7 +642,7 @@ class ColorProfile:
pass
def set_configured_colors(
self, fg: int, bg: int, cursor: int = 0, cursor_text: int = 0, cursor_text_uses_bg: int = 0, highlight_fg: int = 0, highlight_bg: int = 0
self, fg: int, bg: int, cursor: int = 0, cursor_text: int = 0, highlight_fg: int = 0, highlight_bg: int = 0
) -> None:
pass

View File

@ -162,7 +162,7 @@ blank_os_window(OSWindow *w) {
Window *w = t->windows + t->active_window;
Screen *s = w->render_data.screen;
if (s) {
color = colorprofile_to_color(s->color_profile, s->color_profile->overridden.default_bg, s->color_profile->configured.default_bg);
color = colorprofile_to_color(s->color_profile, s->color_profile->overridden.default_bg, s->color_profile->configured.default_bg).rgb;
}
}
}

View File

@ -213,8 +213,14 @@ egr() # }}}
agr('cursor', 'Cursor customization')
opt('cursor', '#cccccc',
option_type='to_color',
long_text='Default cursor color'
option_type='to_color_or_none', long_text='''
Default cursor color. If set to the special value :code:`none` the cursor will be
rendered with a "reverse video" effect. It's color will be the color of the text in
the cell it is over and the text will be rendered with the background color of the cell.
Note that if the program running in the terminal sets a cursor color, this takes precedence.
Also, the reverse video effect is not applied if the cell's foreground and background colors
are the same.
'''
)
opt('cursor_text_color', '#111111',
@ -222,7 +228,7 @@ opt('cursor_text_color', '#111111',
long_text='''
Choose the color of text under the cursor. If you want it rendered with the
background color of the cell underneath instead, use the special keyword:
background
background.
'''
)

View File

@ -888,7 +888,7 @@ class Parser:
ans['copy_on_select'] = copy_on_select(val)
def cursor(self, val: str, ans: typing.Dict[str, typing.Any]) -> None:
ans['cursor'] = to_color(val)
ans['cursor'] = to_color_or_none(val)
def cursor_beam_thickness(self, val: str, ans: typing.Dict[str, typing.Any]) -> None:
ans['cursor_beam_thickness'] = positive_float(val)

View File

@ -27,7 +27,6 @@ color_or_none_as_int(PyObject *color) {
return color_as_int(color);
}
static inline color_type
active_border_color(PyObject *color) {
if (color == Py_None) return 0x00ff00;

View File

@ -472,7 +472,7 @@ class Options:
command_on_bell: typing.List[str] = ['none']
confirm_os_window_close: int = 0
copy_on_select: str = ''
cursor: Color = Color(red=204, green=204, blue=204)
cursor: typing.Optional[kitty.rgb.Color] = Color(red=204, green=204, blue=204)
cursor_beam_thickness: float = 1.5
cursor_blink_interval: float = -1.0
cursor_shape: int = 1

View File

@ -18,7 +18,7 @@ if TYPE_CHECKING:
from kitty.cli_stub import SetColorsRCOptions as CLIOptions
nullable_colors = ('cursor_text_color', 'tab_bar_background', 'tab_bar_margin_color')
nullable_colors = ('cursor', 'cursor_text_color', 'tab_bar_background', 'tab_bar_margin_color', 'selection_foreground')
def parse_colors(args: Iterable[str]) -> Dict[str, Optional[int]]:

View File

@ -168,7 +168,7 @@ screen_reset(Screen *self) {
self->modes = empty_modes;
self->saved_modes = empty_modes;
self->active_hyperlink_id = 0;
#define R(name) self->color_profile->overridden.name = 0
#define R(name) self->color_profile->overridden.name.val = 0
R(default_fg); R(default_bg); R(cursor_color); R(highlight_fg); R(highlight_bg);
#undef R
RESET_CHARSETS;
@ -1509,6 +1509,28 @@ screen_fake_move_cursor_to_position(Screen *self, index_type x, index_type y) {
return count > 0;
}
static color_type
resolve_color(ColorProfile *cp, color_type val, color_type defval) {
switch(val & 0xff) {
case 1:
return cp->color_table[(val >> 8) & 0xff];
case 2:
return val >> 8;
default:
return defval;
}
}
bool
resolve_cell_colors(Screen *self, index_type x, index_type y, color_type *fg, color_type *bg, color_type default_fg, color_type default_bg) {
if (x < self->columns && y < self->lines) {
linebuf_init_line(self->linebuf, y);
GPUCell *g = self->linebuf->line->gpu_cells + x;
*fg = resolve_color(self->color_profile, g->fg, default_fg);
*bg = resolve_color(self->color_profile, g->bg, default_bg);
return true;
} else { *fg = 0; *bg = 0; return false; }
}
// }}}
// Editing {{{

View File

@ -249,6 +249,7 @@ void screen_report_key_encoding_flags(Screen *self);
bool screen_detect_url(Screen *screen, unsigned int x, unsigned int y);
int screen_cursor_at_a_shell_prompt(const Screen *);
bool screen_fake_move_cursor_to_position(Screen *, index_type x, index_type y);
bool resolve_cell_colors(Screen *self, index_type x, index_type y, color_type *fg, color_type *bg, color_type default_fg, color_type default_bg);
#define DECLARE_CH_SCREEN_HANDLER(name) void screen_##name(Screen *screen);
DECLARE_CH_SCREEN_HANDLER(bell)
DECLARE_CH_SCREEN_HANDLER(backspace)

View File

@ -260,9 +260,9 @@ send_graphics_data_to_gpu(size_t image_count, ssize_t gvao_idx, const ImageRende
static void
cell_update_uniform_block(ssize_t vao_idx, Screen *screen, int uniform_buffer, GLfloat xstart, GLfloat ystart, GLfloat dx, GLfloat dy, CursorRenderInfo *cursor, bool inverted, OSWindow *os_window) {
struct CellRenderData {
GLfloat xstart, ystart, dx, dy, sprite_dx, sprite_dy, background_opacity, cursor_text_uses_bg;
GLfloat xstart, ystart, dx, dy, sprite_dx, sprite_dy, background_opacity;
GLuint default_fg, default_bg, highlight_fg, highlight_bg, cursor_color, cursor_text_color, url_color, url_style, inverted;
GLuint default_fg, default_bg, highlight_fg, highlight_bg, cursor_fg, cursor_bg, url_color, url_style, inverted;
GLuint xnum, ynum, cursor_fg_sprite_idx;
GLfloat cursor_x, cursor_y, cursor_w;
@ -274,6 +274,9 @@ cell_update_uniform_block(ssize_t vao_idx, Screen *screen, int uniform_buffer, G
if (UNLIKELY(screen->color_profile->dirty || screen->reload_all_gpu_data)) {
copy_color_table_to_buffer(screen->color_profile, (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(screen->color_profile, screen->color_profile->overridden.name, screen->color_profile->configured.name).rgb
#define IS_SPECIAL_COLOR(name) (screen->color_profile->overridden.name.type == COLOR_IS_SPECIAL || (screen->color_profile->overridden.name.type == COLOR_NOT_SET && screen->color_profile->configured.name.type == COLOR_IS_SPECIAL))
rd->default_fg = COLOR(default_fg); rd->default_bg = COLOR(default_bg); rd->highlight_fg = COLOR(highlight_fg); rd->highlight_bg = COLOR(highlight_bg);
// Cursor position
enum { BLOCK_IDX = 0, BEAM_IDX = 6, UNDERLINE_IDX = 7, UNFOCUSED_IDX = 8 };
if (cursor->is_visible) {
@ -288,6 +291,21 @@ cell_update_uniform_block(ssize_t vao_idx, Screen *screen, int uniform_buffer, G
rd->cursor_fg_sprite_idx = UNDERLINE_IDX; break;
}
} else rd->cursor_fg_sprite_idx = UNFOCUSED_IDX;
color_type cell_fg, cell_bg;
resolve_cell_colors(screen, screen->cursor->x, screen->cursor->y, &cell_fg, &cell_bg, rd->default_fg, rd->default_bg);
if (screen->color_profile->overridden.cursor_color.type == COLOR_IS_INDEX || screen->color_profile->overridden.cursor_color.type == COLOR_IS_RGB) {
// since the program is controlling the cursor color we hope it has chosen one
// that has good contrast with the text color of the cell
rd->cursor_fg = cell_fg; rd->cursor_bg = COLOR(cursor_color);
} else if (IS_SPECIAL_COLOR(cursor_color)) {
if (cell_bg == cell_fg) {
rd->cursor_fg = rd->default_bg; rd->cursor_bg = rd->default_fg;
} else { rd->cursor_fg = cell_bg; rd->cursor_bg = cell_fg; }
} else {
rd->cursor_bg = COLOR(cursor_color);
if (IS_SPECIAL_COLOR(cursor_text_color)) rd->cursor_fg = cell_bg;
else rd->cursor_fg = COLOR(cursor_text_color);
}
} else rd->cursor_x = screen->columns, rd->cursor_y = screen->lines;
rd->cursor_w = rd->cursor_x;
if (
@ -304,12 +322,9 @@ cell_update_uniform_block(ssize_t vao_idx, Screen *screen, int uniform_buffer, G
rd->inverted = inverted ? 1 : 0;
rd->background_opacity = os_window->is_semi_transparent ? os_window->background_opacity : 1.0f;
#define COLOR(name) colorprofile_to_color(screen->color_profile, screen->color_profile->overridden.name, screen->color_profile->configured.name)
rd->default_fg = COLOR(default_fg); rd->default_bg = COLOR(default_bg); rd->highlight_fg = COLOR(highlight_fg); rd->highlight_bg = COLOR(highlight_bg);
rd->cursor_text_color = COLOR(cursor_text_color);
#undef COLOR
rd->cursor_color = cursor->color; rd->url_color = OPT(url_color); rd->url_style = OPT(url_style);
rd->cursor_text_uses_bg = cursor_text_as_bg(screen->color_profile);
#undef IS_SPECIAL_COLOR
rd->url_color = OPT(url_color); rd->url_style = OPT(url_style);
unmap_vao_buffer(vao_idx, uniform_buffer); rd = NULL;
}
@ -456,7 +471,7 @@ has_bgimage(OSWindow *w) {
static void
draw_tint(bool premult, Screen *screen, GLfloat xstart, GLfloat ystart, GLfloat width, GLfloat height) {
bind_program(TINT_PROGRAM);
color_type window_bg = colorprofile_to_color(screen->color_profile, screen->color_profile->overridden.default_bg, screen->color_profile->configured.default_bg);
color_type window_bg = colorprofile_to_color(screen->color_profile, screen->color_profile->overridden.default_bg, screen->color_profile->configured.default_bg).rgb;
#define C(shift) ((((GLfloat)((window_bg >> shift) & 0xFF)) / 255.0f))
float alpha = OPT(background_tint);
if (premult) glUniform4f(tint_program_layout.tint_color_location, C(16) * alpha, C(8) * alpha, C(0) * alpha, alpha);
@ -506,8 +521,8 @@ render_window_title(OSWindow *os_window, Screen *screen UNUSED, GLfloat xstart,
static char title[2048] = {0};
if (window->title_bar_data.last_drawn_title_object_id != window->title) {
snprintf(title, arraysz(title), " %s", PyUnicode_AsUTF8(window->title));
#define RGBCOL(which) ( 0xff000000 | colorprofile_to_color(screen->color_profile, screen->color_profile->overridden.which, screen->color_profile->configured.which) )
if (!draw_window_title(os_window, title, RGBCOL(highlight_fg), RGBCOL(highlight_bg), window->title_bar_data.buf, bar_width, bar_height)) return 0;
#define RGBCOL(which, fallback) ( 0xff000000 | colorprofile_to_color_with_fallback(screen->color_profile, screen->color_profile->overridden.which, screen->color_profile->configured.which, screen->color_profile->overridden.fallback, screen->color_profile->configured.fallback))
if (!draw_window_title(os_window, title, RGBCOL(highlight_fg, default_fg), RGBCOL(highlight_bg, default_bg), window->title_bar_data.buf, bar_width, bar_height)) return 0;
#undef RGBCOL
window->title_bar_data.last_drawn_title_object_id = window->title;
}
@ -550,7 +565,7 @@ draw_window_number(OSWindow *os_window, Screen *screen, GLfloat xstart, GLfloat
bind_program(SEVEN_SEGMENT_PROGRAM);
glUniform4f(seven_segment_program_layout.edges_location, xstart, ystart - height, xstart + width, ystart);
glUniform4f(seven_segment_program_layout.area_bounds_location, left, top, right - left, bottom - top);
color_type digit_color = colorprofile_to_color(screen->color_profile, screen->color_profile->overridden.highlight_bg, screen->color_profile->configured.highlight_bg);
color_type digit_color = colorprofile_to_color_with_fallback(screen->color_profile, screen->color_profile->overridden.highlight_bg, screen->color_profile->configured.highlight_bg, screen->color_profile->overridden.default_fg, screen->color_profile->configured.default_fg);
#define C(shift) ((((GLfloat)((digit_color >> shift) & 0xFF)) / 255.0f))
glUniform4f(seven_segment_program_layout.digit_color_location, C(16), C(8), C(0), 1.);
#undef C
@ -566,7 +581,8 @@ draw_visual_bell_flash(GLfloat intensity, GLfloat xstart, GLfloat ystart, GLfloa
glBlendFuncSeparate(GL_ONE, GL_ONE_MINUS_SRC_ALPHA, GL_ZERO, GL_ONE);
bind_program(TINT_PROGRAM);
GLfloat attenuation = 0.4f;
const color_type flash = colorprofile_to_color(screen->color_profile, screen->color_profile->overridden.highlight_bg, screen->color_profile->configured.highlight_bg);
const color_type flash = colorprofile_to_color_with_fallback(
screen->color_profile, screen->color_profile->overridden.highlight_bg, screen->color_profile->configured.highlight_bg, screen->color_profile->overridden.default_fg, screen->color_profile->configured.default_fg);
#define C(shift) ((((GLfloat)((flash >> shift) & 0xFF)) / 255.0f) )
const GLfloat r = C(16), g = C(8), b = C(0);
const GLfloat max_channel = r > g ? (r > b ? r : b) : (g > b ? g : b);

View File

@ -36,13 +36,13 @@ from .fast_data_types import (
from .keys import keyboard_mode_name, mod_mask
from .notify import NotificationCommand, handle_notification_cmd
from .options.types import Options
from .rgb import to_color
from .rgb import Color, to_color
from .terminfo import get_capabilities
from .types import MouseEvent, ScreenGeometry, WindowGeometry, ac
from .typing import BossType, ChildType, EdgeLiteral, TabType, TypedDict
from .utils import (
color_as_int, get_primary_selection, load_shaders, log_error, open_cmd,
open_url, parse_color_set, sanitize_title, set_primary_selection
get_primary_selection, load_shaders, log_error, open_cmd, open_url,
parse_color_set, sanitize_title, set_primary_selection
)
MatchPatternType = Union[Pattern[str], Tuple[Pattern[str], Optional[Pattern[str]]]]
@ -264,14 +264,14 @@ load_shader_programs = LoadShaderPrograms()
def setup_colors(screen: Screen, opts: Options) -> None:
screen.color_profile.update_ansi_color_table(build_ansi_color_table(opts))
cursor_text_color = opts.cursor_text_color or (12, 12, 12)
cursor_text_color_as_bg = 3 if opts.cursor_text_color is None else 1
sfg = (0, 0, 0) if opts.selection_foreground is None else opts.selection_foreground
screen.color_profile.set_configured_colors(*map(color_as_int, (
opts.foreground, opts.background, opts.cursor,
cursor_text_color, (0, 0, cursor_text_color_as_bg),
sfg, opts.selection_background)
))
def s(c: Optional[Color]) -> int:
return 0 if c is None else (0xff000000 | int(c))
screen.color_profile.set_configured_colors(
s(opts.foreground), s(opts.background),
s(opts.cursor), s(opts.cursor_text_color),
s(opts.selection_foreground), s(opts.selection_background)
)
def text_sanitizer(as_ansi: bool, add_wrap_markers: bool) -> Callable[[str], str]:
@ -762,16 +762,16 @@ class Window:
def change_colors(self, changes: Dict[DynamicColor, Optional[str]]) -> None:
dirtied = default_bg_changed = False
def item(raw: Optional[str]) -> Optional[int]:
def item(raw: Optional[str]) -> int:
if raw is None:
return 0
val = to_color(raw)
return None if val is None else (color_as_int(val) << 8) | 2
v = to_color(raw)
if v is None:
return 0
return 0xff000000 | int(v)
for which, val_ in changes.items():
val = item(val_)
if val is None:
continue
dirtied = True
setattr(self.screen.color_profile, which.name, val)
if which.name == 'default_bg':