From 9989363ecd7f849b1b572a4e613ad26f18ebd249 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Fri, 15 Sep 2017 07:15:16 +0530 Subject: [PATCH] Make the URL highlight color configurable --- kitty/cell_vertex.glsl | 20 ++++++++++++-------- kitty/config.py | 2 +- kitty/kitty.conf | 3 +++ kitty/shaders.c | 33 ++++++++++++++++----------------- kitty/state.c | 9 +++++++++ kitty/state.h | 1 + 6 files changed, 42 insertions(+), 26 deletions(-) diff --git a/kitty/cell_vertex.glsl b/kitty/cell_vertex.glsl index bc3719332..91129ee9f 100644 --- a/kitty/cell_vertex.glsl +++ b/kitty/cell_vertex.glsl @@ -4,6 +4,7 @@ uniform vec4 steps; // xstart, ystart, dx, dy uniform vec2 sprite_layout; // dx, dy uniform ivec2 color_indices; // which color to use as fg and which as bg uniform uvec4 default_colors; // The default colors +uniform uint url_color; // The color to use for the URL highlight uniform uvec4 url_range; // The range for the currently highlighted URL (start_x, end_x, start_y, end_y) uniform ColorTable { uint color_table[256]; // The color table @@ -30,6 +31,7 @@ const uint BYTE_MASK = uint(0xFF); const uint SHORT_MASK = uint(0xFFFF); const uint ZERO = uint(0); const uint ONE = uint(1); +const uint TWO = uint(2); const uint THREE = uint(3); const uint DECORATION_MASK = uint(3); const uint STRIKE_MASK = uint(1); @@ -72,16 +74,19 @@ vec3 apply_selection(vec3 color, uint which) { return is_selected * color_to_vec(which) + (1.0 - is_selected) * color; } -uint in_range(uvec4 range, uint x, uint y) { - if (range[0] <= x && x <= range[1] && range[2] <= y && y <= range[3]) return ONE; - return ZERO; +vec3 mix_vecs(float q, vec3 a, vec3 b) { + return q * a + (1.0 - q) * b; +} + +float in_range(uvec4 range, uint x, uint y) { + if (range[2] == y && range[0] <= x && x <= range[1]) return 1.0; + return 0.0; } void main() { uint instance_id = uint(gl_InstanceID); uint r = instance_id / dimensions.x; uint c = instance_id - r * dimensions.x; - uint in_url = in_range(url_range, c, r); float left = steps[0] + c * steps[2]; float top = steps[1] - r * steps[3]; vec2 xpos = vec2(left, left + steps[2]); @@ -94,11 +99,10 @@ void main() { uint fg = colors[color_indices[reverse]]; uint bg = colors[color_indices[ONE - reverse]]; uint resolved_fg = as_color(fg, default_colors[color_indices[0]]); - uint underline; foreground = apply_selection(color_to_vec(resolved_fg), default_colors[2]); background = apply_selection(to_color(bg, default_colors[color_indices[1]]), default_colors[3]); - if (in_url == ONE) { underline = ONE; decoration_fg = color_to_vec(uint(255)); } - else { underline = (text_attrs >> 26) & DECORATION_MASK; decoration_fg = to_color(colors[2], resolved_fg); } - underline_pos = to_sprite_pos(pos, underline, ZERO, ZERO); + float in_url = in_range(url_range, c, r); + decoration_fg = mix_vecs(in_url, color_to_vec(url_color), to_color(colors[2], resolved_fg)); + underline_pos = mix_vecs(in_url, to_sprite_pos(pos, TWO, ZERO, ZERO), to_sprite_pos(pos, (text_attrs >> 26) & DECORATION_MASK, ZERO, ZERO)); strike_pos = to_sprite_pos(pos, ((text_attrs >> 31) & STRIKE_MASK) * THREE, ZERO, ZERO); } diff --git a/kitty/config.py b/kitty/config.py index 567218c11..a6d06f526 100644 --- a/kitty/config.py +++ b/kitty/config.py @@ -235,7 +235,7 @@ type_map = { for name in ( 'foreground background cursor active_border_color inactive_border_color' - ' selection_foreground selection_background' + ' selection_foreground selection_background url_color' ).split(): type_map[name] = lambda x: to_color(x, validate=True) for i in range(16): diff --git a/kitty/kitty.conf b/kitty/kitty.conf index 0e9278633..a19918958 100644 --- a/kitty/kitty.conf +++ b/kitty/kitty.conf @@ -45,6 +45,9 @@ selection_foreground #000000 # The background for selections selection_background #FFFACD +# The color for highlighting URLs on mouse-over +url_color #0087BD + # The cursor color cursor #ffffff diff --git a/kitty/shaders.c b/kitty/shaders.c index 999f7c179..dc45e50ff 100644 --- a/kitty/shaders.c +++ b/kitty/shaders.c @@ -552,7 +552,7 @@ destroy_sprite_map() { // Cell {{{ -enum CellUniforms { CELL_dimensions, CELL_default_colors, CELL_color_indices, CELL_steps, CELL_sprites, CELL_sprite_layout, CELL_url_range, CELL_color_table, NUM_CELL_UNIFORMS }; +enum CellUniforms { CELL_dimensions, CELL_default_colors, CELL_color_indices, CELL_steps, CELL_sprites, CELL_sprite_layout, CELL_url_color, CELL_url_range, CELL_color_table, NUM_CELL_UNIFORMS }; static GLint cell_uniform_locations[NUM_CELL_UNIFORMS] = {0}; static GLint cell_color_table_stride = 0, cell_color_table_offset = 0, cell_color_table_size = 0, cell_color_table_block_index = 0; @@ -570,6 +570,7 @@ init_cell_program() { else SET_LOC(sprites); else SET_LOC(sprite_layout); else SET_LOC(url_range); + else SET_LOC(url_color); else if (strcmp(p->uniforms[i].name, "color_table[0]") == 0) { ctable_idx = i; cell_uniform_locations[CELL_color_table] = p->uniforms[i].location; } else { fatal("Unknown uniform in cell program: %s", p->uniforms[i].name); } } @@ -601,6 +602,8 @@ create_cell_vao() { #undef A1 } +static bool cell_constants_sent = false; + static void draw_cells_impl(ssize_t vao_idx, GLfloat xstart, GLfloat ystart, GLfloat dx, GLfloat dy, Screen *screen) { size_t sz; @@ -628,29 +631,25 @@ draw_cells_impl(ssize_t vao_idx, GLfloat xstart, GLfloat ystart, GLfloat dx, GLf #define UL(name) cell_uniform_locations[CELL_##name] bind_program(CELL_PROGRAM); bind_vao_uniform_buffer(vao_idx, 2, cell_color_table_block_index); - glUniform2ui(UL(dimensions), screen->columns, screen->lines); - check_gl(); - glUniform4f(UL(steps), xstart, ystart, dx, dy); - check_gl(); - glUniform2i(UL(color_indices), inverted & 1, 1 - (inverted & 1)); - check_gl(); + glUniform2ui(UL(dimensions), screen->columns, screen->lines); check_gl(); + glUniform4f(UL(steps), xstart, ystart, dx, dy); check_gl(); + glUniform2i(UL(color_indices), inverted & 1, 1 - (inverted & 1)); check_gl(); #define COLOR(name) colorprofile_to_color(screen->color_profile, screen->color_profile->overridden.name, screen->color_profile->configured.name) - glUniform4ui(UL(default_colors), COLOR(default_fg), COLOR(default_bg), COLOR(highlight_fg), COLOR(highlight_bg)); - check_gl(); + glUniform4ui(UL(default_colors), COLOR(default_fg), COLOR(default_bg), COLOR(highlight_fg), COLOR(highlight_bg)); check_gl(); #undef COLOR GLuint start_x, start_y, end_x, end_y; screen_url_range(screen, &start_x, &start_y, &end_x, &end_y); - glUniform4ui(UL(url_range), start_x, end_x, start_y, end_y); - check_gl(); - glUniform1i(UL(sprites), sprite_map_unit); - check_gl(); + glUniform4ui(UL(url_range), start_x, end_x, start_y, end_y); check_gl(); + glUniform1i(UL(sprites), sprite_map_unit); check_gl(); unsigned int x, y, z; sprite_map_current_layout(&x, &y, &z); - glUniform2f(UL(sprite_layout), 1.0 / (float)x, 1.0 / (float)y); - check_gl(); + glUniform2f(UL(sprite_layout), 1.0 / (float)x, 1.0 / (float)y); check_gl(); + if (!cell_constants_sent) { + glUniform1ui(UL(url_color), OPT(url_color)); check_gl(); + cell_constants_sent = true; + } bind_vertex_array(vao_idx); - glDrawArraysInstanced(GL_TRIANGLE_FAN, 0, 4, screen->lines * screen->columns); - check_gl(); + glDrawArraysInstanced(GL_TRIANGLE_FAN, 0, 4, screen->lines * screen->columns); check_gl(); unbind_vertex_array(); unbind_program(); unbind_sprite_map(); diff --git a/kitty/state.c b/kitty/state.c index cf9e30e06..d00661749 100644 --- a/kitty/state.c +++ b/kitty/state.c @@ -118,6 +118,14 @@ swap_windows(unsigned int tab_id, unsigned int a, unsigned int b) { #define TWO_UINT(name) PYWRAP1(name) { unsigned int a, b; PA("II", &a, &b); name(a, b); Py_RETURN_NONE; } #define THREE_UINT(name) PYWRAP1(name) { unsigned int a, b, c; PA("III", &a, &b, &c); name(a, b, c); Py_RETURN_NONE; } +static inline color_type +color_as_int(PyObject *color) { + if (!PyTuple_Check(color)) { PyErr_SetString(PyExc_TypeError, "Not a color tuple"); return 0; } +#define I(n, s) ((PyLong_AsUnsignedLong(PyTuple_GET_ITEM(color, n)) & 0xff) << s) + return (I(0, 16) | I(1, 8) | I(2, 0)) & 0xffffff; +#undef I +} + PYWRAP1(set_options) { #define S(name, convert) { PyObject *ret = PyObject_GetAttrString(args, #name); if (ret == NULL) return NULL; global_state.opts.name = convert(ret); Py_DECREF(ret); if (PyErr_Occurred()) return NULL; } S(visual_bell_duration, PyFloat_AsDouble); @@ -130,6 +138,7 @@ PYWRAP1(set_options) { S(wheel_scroll_multiplier, PyFloat_AsDouble); S(open_url_modifiers, PyLong_AsUnsignedLong); S(click_interval, PyFloat_AsDouble); + S(url_color, color_as_int); PyObject *chars = PyObject_GetAttrString(args, "select_by_word_characters"); if (chars == NULL) return NULL; for (size_t i = 0; i < MIN((size_t)PyUnicode_GET_LENGTH(chars), sizeof(OPT(select_by_word_characters))/sizeof(OPT(select_by_word_characters[0]))); i++) { diff --git a/kitty/state.h b/kitty/state.h index c3de33b0c..980e8c6ec 100644 --- a/kitty/state.h +++ b/kitty/state.h @@ -15,6 +15,7 @@ typedef struct { CursorShape cursor_shape; unsigned int open_url_modifiers; char_type select_by_word_characters[256]; size_t select_by_word_characters_count; + color_type url_color; } Options; typedef struct {