diff --git a/kitty/cell_fragment.glsl b/kitty/cell_fragment.glsl index ac310dd1f..5006f4424 100644 --- a/kitty/cell_fragment.glsl +++ b/kitty/cell_fragment.glsl @@ -16,7 +16,7 @@ in vec3 underline_pos; in vec3 cursor_pos; in vec3 strike_pos; in vec3 foreground; -in vec4 cursor_color_vec; +in vec4 cursor_color_premult; in vec3 decoration_fg; in float colored_sprite; #endif @@ -134,7 +134,7 @@ vec4 calculate_premul_foreground_from_sprites(vec4 text_fg) { float combined_alpha = min(text_fg.a + strike_alpha, 1.0f); // Underline color might be different, so alpha blend vec4 ans = alpha_blend(vec4(text_fg.rgb, combined_alpha * effective_text_alpha), vec4(decoration_fg, underline_alpha * effective_text_alpha)); - return mix(ans, cursor_color_vec, cursor_alpha); + return mix(ans, cursor_color_premult, cursor_alpha); } vec4 adjust_foreground_contrast_with_background(vec4 text_fg, vec3 bg) { diff --git a/kitty/cell_vertex.glsl b/kitty/cell_vertex.glsl index 71086e255..b794dd371 100644 --- a/kitty/cell_vertex.glsl +++ b/kitty/cell_vertex.glsl @@ -9,7 +9,7 @@ layout(std140) uniform CellRenderData { 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; + float cursor_x, cursor_y, cursor_w, cursor_opacity; uint color_table[NUM_COLORS + MARK_MASK + MARK_MASK + 2]; }; @@ -44,7 +44,7 @@ uniform float dim_opacity; out vec3 sprite_pos; out vec3 underline_pos; out vec3 cursor_pos; -out vec4 cursor_color_vec; +out vec4 cursor_color_premult; out vec3 strike_pos; out vec3 foreground; out vec3 decoration_fg; @@ -185,7 +185,7 @@ void main() { strike_pos = to_sprite_pos(cell_data.pos, ((text_attrs >> STRIKE_SHIFT) & ONE) * STRIKE_SPRITE_INDEX, ZERO, ZERO); // Cursor - cursor_color_vec = vec4(color_to_vec(cursor_bg), 1.0); + cursor_color_premult = vec4(color_to_vec(cursor_bg) * cursor_opacity, cursor_opacity); vec3 final_cursor_text_color = color_to_vec(cursor_fg); foreground = choose_color(cell_data.has_block_cursor, final_cursor_text_color, foreground); decoration_fg = choose_color(cell_data.has_block_cursor, final_cursor_text_color, decoration_fg); @@ -222,7 +222,7 @@ void main() { // 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); - background = choose_color(cell_data.has_block_cursor, color_to_vec(cursor_bg), 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); diff --git a/kitty/child-monitor.c b/kitty/child-monitor.c index e299a01f7..039ad93c9 100644 --- a/kitty/child-monitor.c +++ b/kitty/child-monitor.c @@ -652,7 +652,7 @@ pyset_iutf8(ChildMonitor *self, PyObject *args) { static bool cursor_needs_render(Window *w) { #define cri w->render_data.screen->cursor_render_info - return w->cursor_visible_at_last_render != cri.is_visible || w->render_data.screen->last_rendered.cursor_x != cri.x || w->render_data.screen->last_rendered.cursor_y != cri.y || w->last_cursor_shape != cri.shape; + return w->cursor_opacity_at_last_render != cri.opacity || w->render_data.screen->last_rendered.cursor_x != cri.x || w->render_data.screen->last_rendered.cursor_y != cri.y || w->last_cursor_shape != cri.shape; #undef cri } @@ -669,7 +669,7 @@ collect_cursor_info(CursorRenderInfo *ans, Window *w, monotonic_t now, OSWindow cursor = rd->screen->paused_rendering.expires_at ? &rd->screen->paused_rendering.cursor : rd->screen->cursor; ans->x = cursor->x; ans->y = cursor->y; } - ans->is_visible = false; + ans->opacity = 0; if (rd->screen->scrolled_by || !screen_is_cursor_visible(rd->screen)) return cursor_needs_render(w); monotonic_t time_since_start_blink = now - os_window->cursor_blink_zero_time; bool cursor_blinking = OPT(cursor_blink_interval) > 0 && !cursor->non_blinking && os_window->is_focused && (OPT(cursor_stop_blinking_after) == 0 || time_since_start_blink <= OPT(cursor_stop_blinking_after)); @@ -683,8 +683,8 @@ collect_cursor_info(CursorRenderInfo *ans, Window *w, monotonic_t now, OSWindow monotonic_t delay = bucket - time_since_start_blink; set_maximum_wait(delay); } - if (!do_draw_cursor) { ans->is_visible = false; return cursor_needs_render(w); } - ans->is_visible = true; + if (!do_draw_cursor) { ans->opacity = 0; return cursor_needs_render(w); } + ans->opacity = 1; ans->shape = cursor->shape ? cursor->shape : OPT(cursor_shape); ans->is_focused = os_window->is_focused; return cursor_needs_render(w); @@ -752,7 +752,7 @@ prepare_to_render_os_window(OSWindow *os_window, monotonic_t now, unsigned int * if (collect_cursor_info(&WD.screen->cursor_render_info, w, now, os_window)) needs_render = true; WD.screen->cursor_render_info.is_focused = false; } else { - WD.screen->cursor_render_info.is_visible = false; + WD.screen->cursor_render_info.opacity = 0; } } if (scan_for_animated_images) { @@ -803,7 +803,7 @@ render_prepared_os_window(OSWindow *os_window, unsigned int active_window_id, co if (WD.screen->start_visual_bell_at != 0) { set_maximum_wait(OPT(repaint_delay)); } - w->cursor_visible_at_last_render = WD.screen->cursor_render_info.is_visible; w->last_cursor_shape = WD.screen->cursor_render_info.shape; + w->cursor_opacity_at_last_render = WD.screen->cursor_render_info.opacity; w->last_cursor_shape = WD.screen->cursor_render_info.shape; } } if (os_window->live_resize.in_progress) draw_resizing_text(os_window); diff --git a/kitty/data-types.h b/kitty/data-types.h index 64bc30fa9..ce6176575 100644 --- a/kitty/data-types.h +++ b/kitty/data-types.h @@ -300,9 +300,10 @@ typedef struct { } Cursor; typedef struct { - bool is_visible, is_focused, render_even_when_unfocused; + bool is_focused, render_even_when_unfocused; CursorShape shape; unsigned int x, y; + float opacity; } CursorRenderInfo; typedef enum DynamicColorType { diff --git a/kitty/shaders.c b/kitty/shaders.c index 1288bc8ab..4060fad2d 100644 --- a/kitty/shaders.c +++ b/kitty/shaders.c @@ -297,7 +297,7 @@ cell_update_uniform_block(ssize_t vao_idx, Screen *screen, int uniform_buffer, c 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; + GLfloat cursor_x, cursor_y, cursor_w, cursor_opacity; }; // Send the uniform data struct GPUCellRenderData *rd = (struct GPUCellRenderData*)map_vao_buffer(vao_idx, uniform_buffer, GL_WRITE_ONLY); @@ -322,8 +322,9 @@ cell_update_uniform_block(ssize_t vao_idx, Screen *screen, int uniform_buffer, c // Cursor position 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; - if (cursor->is_visible) { + if (cursor->opacity > 0) { rd->cursor_x = cursor->x, rd->cursor_y = cursor->y; + rd->cursor_opacity = cursor->opacity; if (cursor->is_focused) { switch(cursor->shape) { default: diff --git a/kitty/state.h b/kitty/state.h index a283bba55..b633f10c9 100644 --- a/kitty/state.h +++ b/kitty/state.h @@ -178,7 +178,8 @@ typedef struct WindowBarData { typedef struct { id_type id; - bool visible, cursor_visible_at_last_render; + bool visible; + float cursor_opacity_at_last_render; CursorShape last_cursor_shape; PyObject *title; WindowRenderData render_data;