diff --git a/docs/changelog.rst b/docs/changelog.rst index b26e2a9a0..d10148d28 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -18,6 +18,9 @@ Changelog - Fix Private use Unicode area characters followed by spaces at the end of text not being rendered correctly (:iss:`1210`) +- Fix changing :opt:`cursor_text_color` via remote control not working + (:iss:`1229`) + 0.13.1 [2018-12-06] ------------------------------ diff --git a/kitty/boss.py b/kitty/boss.py index c0c54ea20..936ea7daa 100644 --- a/kitty/boss.py +++ b/kitty/boss.py @@ -106,6 +106,7 @@ class Boss: set_draw_minimal_borders(opts) self.window_id_map = WeakValueDictionary() self.startup_colors = {k: opts[k] for k in opts if isinstance(opts[k], Color)} + self.startup_cursor_text_color = opts.cursor_text_color self.pending_sequences = None self.cached_values = cached_values self.os_window_map = {} @@ -951,11 +952,13 @@ class Boss: if tm is not None: tm.move_tab(-1) - def patch_colors(self, spec, configured=False): + def patch_colors(self, spec, cursor_text_color, configured=False): if configured: for k, v in spec.items(): if hasattr(self.opts, k): setattr(self.opts, k, color_from_int(v)) + if cursor_text_color is not False: + self.opts.cursor_text_color = cursor_text_color for tm in self.all_tab_managers: tm.tab_bar.patch_colors(spec) patch_global_colors(spec, configured) diff --git a/kitty/cell_vertex.glsl b/kitty/cell_vertex.glsl index 707188cce..c774163f3 100644 --- a/kitty/cell_vertex.glsl +++ b/kitty/cell_vertex.glsl @@ -5,13 +5,12 @@ #define REVERSE_SHIFT {REVERSE_SHIFT} #define STRIKE_SHIFT {STRIKE_SHIFT} #define DIM_SHIFT {DIM_SHIFT} -#define CURSOR_TEXT_COLOR {CURSOR_TEXT_COLOR} // Inputs {{{ layout(std140) uniform CellRenderData { - float xstart, ystart, dx, dy, sprite_dx, sprite_dy, background_opacity; + float xstart, ystart, dx, dy, sprite_dx, sprite_dy, background_opacity, cursor_text_uses_bg; - uint default_fg, default_bg, highlight_fg, highlight_bg, cursor_color, url_color, url_style, inverted; + uint default_fg, default_bg, highlight_fg, highlight_bg, cursor_color, cursor_text_color, url_color, url_style, inverted; uint xnum, ynum, cursor_fg_sprite_idx; float cursor_x, cursor_y, cursor_w; @@ -182,8 +181,9 @@ void main() { // Cursor cursor_color_vec = vec4(color_to_vec(cursor_color), 1.0); - foreground = choose_color(cell_has_block_cursor, CURSOR_TEXT_COLOR, foreground); - decoration_fg = choose_color(cell_has_block_cursor, CURSOR_TEXT_COLOR, decoration_fg); + vec3 final_cursor_text_color = mix(color_to_vec(cursor_text_color), bg, cursor_text_uses_bg); + 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); #endif // }}} diff --git a/kitty/cmds.py b/kitty/cmds.py index 60af99173..d963d8280 100644 --- a/kitty/cmds.py +++ b/kitty/cmds.py @@ -684,7 +684,7 @@ this option, any color arguments are ignored and --configured and --all are impl ) def cmd_set_colors(global_opts, opts, args): from .rgb import color_as_int, Color - colors = {} + colors, cursor_text_color = {}, False if not opts.reset: for spec in args: if '=' in spec: @@ -692,15 +692,17 @@ def cmd_set_colors(global_opts, opts, args): else: with open(os.path.expanduser(spec), encoding='utf-8', errors='replace') as f: colors.update(parse_config(f)) + cursor_text_color = colors.pop('cursor_text_color', False) colors = {k: color_as_int(v) for k, v in colors.items() if isinstance(v, Color)} return { - 'title': ' '.join(args), 'match_window': opts.match, 'match_tab': opts.match_tab, - 'all': opts.all or opts.reset, 'configured': opts.configured or opts.reset, 'colors': colors, 'reset': opts.reset + 'title': ' '.join(args), 'match_window': opts.match, 'match_tab': opts.match_tab, + 'all': opts.all or opts.reset, 'configured': opts.configured or opts.reset, + 'colors': colors, 'reset': opts.reset, 'cursor_text_color': cursor_text_color } def set_colors(boss, window, payload): - from .rgb import color_as_int + from .rgb import color_as_int, Color if payload['all']: windows = tuple(boss.all_windows) else: @@ -717,10 +719,14 @@ def set_colors(boss, window, payload): windows += tuple(tab) if payload['reset']: payload['colors'] = {k: color_as_int(v) for k, v in boss.startup_colors.items()} + payload['cursor_text_color'] = boss.startup_cursor_text_color profiles = tuple(w.screen.color_profile for w in windows) from .fast_data_types import patch_color_profiles - patch_color_profiles(payload['colors'], profiles, payload['configured']) - boss.patch_colors(payload['colors'], payload['configured']) + cursor_text_color = payload.get('cursor_text_color', False) + if isinstance(cursor_text_color, (tuple, list, Color)): + cursor_text_color = color_as_int(Color(*cursor_text_color)) + patch_color_profiles(payload['colors'], cursor_text_color, profiles, payload['configured']) + boss.patch_colors(payload['colors'], cursor_text_color, payload['configured']) default_bg_changed = 'background' in payload['colors'] for w in windows: if default_bg_changed: diff --git a/kitty/colors.c b/kitty/colors.c index 175d7200f..f646c981a 100644 --- a/kitty/colors.c +++ b/kitty/colors.c @@ -100,8 +100,8 @@ update_ansi_color_table(ColorProfile *self, PyObject *val) { static PyObject* patch_color_profiles(PyObject *module UNUSED, PyObject *args) { - PyObject *spec, *profiles, *v; ColorProfile *self; int change_configured; - if (!PyArg_ParseTuple(args, "O!O!p", &PyDict_Type, &spec, &PyTuple_Type, &profiles, &change_configured)) return NULL; + PyObject *spec, *profiles, *v; ColorProfile *self; int change_configured; PyObject *cursor_text_color; + if (!PyArg_ParseTuple(args, "O!OO!p", &PyDict_Type, &spec, &cursor_text_color, &PyTuple_Type, &profiles, &change_configured)) return NULL; char key[32] = {0}; for (size_t i = 0; i < arraysz(FG_BG_256); i++) { snprintf(key, sizeof(key) - 1, "color%zu", i); @@ -131,6 +131,22 @@ 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); #undef S + if (cursor_text_color != Py_False) { + 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 (cursor_text_color != Py_None) { + 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; } @@ -149,6 +165,14 @@ colorprofile_to_color(ColorProfile *self, color_type entry, color_type defval) { } } +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; + } + return self->configured.cursor_text_uses_bg & 2 ? 1.f : 0.f; +} + static PyObject* as_dict(ColorProfile *self, PyObject *args UNUSED) { @@ -174,7 +198,7 @@ as_dict(ColorProfile *self, PyObject *args UNUSED) { if (ret != 0) { Py_CLEAR(ans); return NULL; } \ }} D(default_fg, foreground); D(default_bg, background); - D(cursor_color, cursor); 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); #undef D @@ -236,7 +260,11 @@ 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|III", &(self->configured.default_fg), &(self->configured.default_bg), &(self->configured.cursor_color), &(self->configured.highlight_fg), &(self->configured.highlight_bg))) return NULL; + 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; self->dirty = true; Py_RETURN_NONE; } @@ -286,6 +314,7 @@ default_color_table(PyObject *self UNUSED, PyObject *args UNUSED) { CGETSET(default_fg) CGETSET(default_bg) CGETSET(cursor_color) +CGETSET(cursor_text_color) CGETSET(highlight_fg) CGETSET(highlight_bg) @@ -293,6 +322,7 @@ static PyGetSetDef getsetters[] = { GETSET(default_fg) GETSET(default_bg) GETSET(cursor_color) + GETSET(cursor_text_color) GETSET(highlight_fg) GETSET(highlight_bg) {NULL} /* Sentinel */ diff --git a/kitty/data-types.h b/kitty/data-types.h index f3295629c..9b540b5a0 100644 --- a/kitty/data-types.h +++ b/kitty/data-types.h @@ -210,7 +210,7 @@ typedef struct { } CursorRenderInfo; typedef struct { - color_type default_fg, default_bg, cursor_color, highlight_fg, highlight_bg; + color_type default_fg, default_bg, cursor_color, cursor_text_color, cursor_text_uses_bg, highlight_fg, highlight_bg; } DynamicColor; typedef struct { @@ -285,6 +285,7 @@ bool schedule_write_to_child(unsigned long id, unsigned int num, ...); 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); void copy_color_table_to_buffer(ColorProfile *self, color_type *address, int offset, size_t stride); void colorprofile_push_dynamic_colors(ColorProfile*); void colorprofile_pop_dynamic_colors(ColorProfile*); diff --git a/kitty/main.py b/kitty/main.py index be691b5f4..97ad663af 100644 --- a/kitty/main.py +++ b/kitty/main.py @@ -83,13 +83,10 @@ def talk_to_instance(args): def load_all_shaders(semi_transparent=0): - load_shader_programs(semi_transparent, load_all_shaders.cursor_text_color) + load_shader_programs(semi_transparent) load_borders_program() -load_all_shaders.cursor_text_color = None - - def init_glfw(debug_keyboard=False): glfw_module = 'cocoa' if is_macos else ('wayland' if is_wayland else 'x11') if not glfw_init(glfw_path(glfw_module), debug_keyboard): @@ -122,7 +119,6 @@ def _run_app(opts, args): new_os_window_trigger = get_new_os_window_trigger(opts) if is_macos and opts.macos_custom_beam_cursor: set_custom_ibeam_cursor() - load_all_shaders.cursor_text_color = opts.cursor_text_color if not is_wayland and not is_macos: # no window icons on wayland with open(logo_data_file, 'rb') as f: set_default_window_icon(f.read(), 256, 256) diff --git a/kitty/shaders.c b/kitty/shaders.c index ae18fb16f..5d9915c9f 100644 --- a/kitty/shaders.c +++ b/kitty/shaders.c @@ -219,9 +219,9 @@ static struct CellUniformData cell_uniform_data = {0, .prev_inactive_text_alpha= static inline 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; + GLfloat xstart, ystart, dx, dy, sprite_dx, sprite_dy, background_opacity, cursor_text_uses_bg; - GLuint default_fg, default_bg, highlight_fg, highlight_bg, cursor_color, url_color, url_style, inverted; + GLuint default_fg, default_bg, highlight_fg, highlight_bg, cursor_color, cursor_text_color, url_color, url_style, inverted; GLuint xnum, ynum, cursor_fg_sprite_idx; GLfloat cursor_x, cursor_y, cursor_w; @@ -260,8 +260,10 @@ cell_update_uniform_block(ssize_t vao_idx, Screen *screen, int uniform_buffer, G #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); unmap_vao_buffer(vao_idx, uniform_buffer); rd = NULL; } diff --git a/kitty/window.py b/kitty/window.py index cda1610be..9695e906c 100644 --- a/kitty/window.py +++ b/kitty/window.py @@ -56,14 +56,13 @@ def calculate_gl_geometry(window_geometry, viewport_width, viewport_height, cell return ScreenGeometry(xstart, ystart, window_geometry.xnum, window_geometry.ynum, dx, dy) -def load_shader_programs(semi_transparent=0, cursor_text_color=None): +def load_shader_programs(semi_transparent=0): compile_program(BLIT_PROGRAM, *load_shaders('blit')) v, f = load_shaders('cell') def color_as_vec3(x): return 'vec3({}, {}, {})'.format(x.red / 255, x.green / 255, x.blue / 255) - cursor_text_color = color_as_vec3(cursor_text_color) if cursor_text_color else 'bg' for which, p in { 'SIMPLE': CELL_PROGRAM, 'BACKGROUND': CELL_BG_PROGRAM, @@ -76,7 +75,6 @@ def load_shader_programs(semi_transparent=0, cursor_text_color=None): 'STRIKE_SHIFT': STRIKETHROUGH, 'DIM_SHIFT': DIM, 'DECORATION_SHIFT': DECORATION, - 'CURSOR_TEXT_COLOR': cursor_text_color, }.items(): vv = vv.replace('{{{}}}'.format(gln), str(pyn), 1) if semi_transparent: @@ -95,8 +93,13 @@ def load_shader_programs(semi_transparent=0, cursor_text_color=None): def setup_colors(screen, opts): 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 cursor_text_color is None else 1 screen.color_profile.set_configured_colors(*map(color_as_int, ( - opts.foreground, opts.background, opts.cursor, opts.selection_foreground, opts.selection_background))) + opts.foreground, opts.background, opts.cursor, + cursor_text_color, (0, 0, cursor_text_color_as_bg), + opts.selection_foreground, opts.selection_background) + )) def text_sanitizer(as_ansi, add_wrap_markers):