From cd56597e7e381f78b2643fe5723edd4bc19dce08 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Wed, 7 Jun 2023 15:36:05 +0530 Subject: [PATCH] Remove the resize_draw_strategy option Use scale + size as the fixed strategy. This is because static looks bad with translucent windows (the cell area ends up a different opacity than the newly exposed window area). --- docs/changelog.rst | 2 ++ kitty/child-monitor.c | 43 +++++++++++++--------------------- kitty/graphics_fragment.glsl | 14 +++++++++-- kitty/options/definition.py | 11 --------- kitty/options/parse.py | 13 ++++------ kitty/options/to-c-generated.h | 15 ------------ kitty/options/types.py | 2 -- kitty/shaders.c | 14 +++++++---- kitty/state.h | 2 -- 9 files changed, 45 insertions(+), 71 deletions(-) diff --git a/docs/changelog.rst b/docs/changelog.rst index 425e24ff9..a9bee8a5c 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -42,6 +42,8 @@ Detailed list of changes - A new option :opt:`text_fg_override_threshold` to force text colors to have high contrast regardless of color scheme (:pull:`6283`) +- When resizing OS Windows make the animation less jerky on macOS and Wayland. Also always show the window size in cells during the resize and scale the window contents while the resize is in progress to give a visual indicator of the relative size change (:iss:`6341`) + - unicode_input kitten: Fix a regression in 0.28.0 that caused the order of recent and favorites entries to not be respected (:iss:`6214`) - unicode_input kitten: Fix a regression in 0.28.0 that caused editing of favorites to sometimes hang diff --git a/kitty/child-monitor.c b/kitty/child-monitor.c index ad3110578..4c4367017 100644 --- a/kitty/child-monitor.c +++ b/kitty/child-monitor.c @@ -733,20 +733,28 @@ prepare_to_render_os_window(OSWindow *os_window, monotonic_t now, unsigned int * return needs_render; } +static void +draw_resizing_text(OSWindow *w) { + char text[32] = {0}; + unsigned int width = w->live_resize.width, height = w->live_resize.height; + snprintf(text, sizeof(text), "%u x %u cells", width / w->fonts_data->cell_width, height / w->fonts_data->cell_height); + StringCanvas rendered = render_simple_text(w->fonts_data, text); + if (rendered.canvas) { + draw_centered_alpha_mask(w, width, height, rendered.width, rendered.height, rendered.canvas); + free(rendered.canvas); + } +} + + static void render_os_window(OSWindow *os_window, unsigned int active_window_id, color_type active_window_bg, unsigned int num_visible_windows, bool all_windows_have_same_bg) { // ensure all pixels are cleared to background color at least once in every buffer if (os_window->clear_count++ < 3) blank_os_window(os_window); Tab *tab = os_window->tabs + os_window->active_tab; BorderRects *br = &tab->border_rects; - float x_ratio = 1, y_ratio = 1; + static const float x_ratio = 1, y_ratio = 1; draw_borders(br->vao_idx, br->num_border_rects, br->rect_buf, br->is_dirty, os_window->viewport_width, os_window->viewport_height, active_window_bg, num_visible_windows, all_windows_have_same_bg, os_window); br->is_dirty = false; - bool static_live_resize_in_progress = os_window->live_resize.in_progress && OPT(resize_draw_strategy) == RESIZE_DRAW_STATIC; - if (static_live_resize_in_progress) { - x_ratio = (float) os_window->viewport_width / (float) os_window->live_resize.width; - y_ratio = (float) os_window->viewport_height / (float) os_window->live_resize.height; - } if (TD.screen && os_window->num_tabs >= OPT(tab_bar_min_tabs)) draw_cells(TD.vao_idx, 0, &TD, x_ratio, y_ratio, os_window, true, false, NULL); for (unsigned int i = 0; i < tab->num_windows; i++) { Window *w = tab->windows + i; @@ -759,6 +767,7 @@ render_os_window(OSWindow *os_window, unsigned int active_window_id, color_type w->cursor_visible_at_last_render = WD.screen->cursor_render_info.is_visible; w->last_cursor_x = WD.screen->cursor_render_info.x; w->last_cursor_y = WD.screen->cursor_render_info.y; w->last_cursor_shape = WD.screen->cursor_render_info.shape; } } + if (os_window->live_resize.in_progress) draw_resizing_text(os_window); swap_window_buffers(os_window); os_window->last_active_tab = os_window->active_tab; os_window->last_num_tabs = os_window->num_tabs; os_window->last_active_window_id = active_window_id; os_window->focused_at_last_render = os_window->is_focused; @@ -768,18 +777,6 @@ render_os_window(OSWindow *os_window, unsigned int active_window_id, color_type #undef TD } -static void -draw_resizing_text(OSWindow *w) { - char text[32] = {0}; - unsigned int width = w->live_resize.width, height = w->live_resize.height; - snprintf(text, sizeof(text), "%u x %u cells", width / w->fonts_data->cell_width, height / w->fonts_data->cell_height); - StringCanvas rendered = render_simple_text(w->fonts_data, text); - if (rendered.canvas) { - draw_centered_alpha_mask(w, width, height, rendered.width, rendered.height, rendered.canvas); - free(rendered.canvas); - } -} - static bool no_render_frame_received_recently(OSWindow *w, monotonic_t now, monotonic_t max_wait) { bool ans = now - w->last_render_frame_received_at > max_wait; @@ -826,14 +823,7 @@ render(monotonic_t now, bool input_read) { } w->render_calls++; make_os_window_context_current(w); - if (w->live_resize.in_progress && OPT(resize_draw_strategy) >= RESIZE_DRAW_BLANK) { - blank_os_window(w); - if (OPT(resize_draw_strategy) == RESIZE_DRAW_SIZE) draw_resizing_text(w); - swap_window_buffers(w); - if (USE_RENDER_FRAMES) request_frame_render(w); - continue; - } - if (w->live_resize.in_progress && OPT(resize_draw_strategy) == RESIZE_DRAW_STATIC) blank_os_window(w); + if (w->live_resize.in_progress) blank_os_window(w); bool needs_render = w->is_damaged || w->live_resize.in_progress; if (w->viewport_size_dirty) { w->clear_count = 0; @@ -1020,7 +1010,6 @@ process_pending_resizes(monotonic_t now) { // if more than one resize event has occurred, wait at least 0.2 secs // before repainting, to avoid rapid transitions between the cells banner // and the normal screen - if (w->live_resize.num_of_resize_events > 1 && OPT(resize_draw_strategy) == RESIZE_DRAW_SIZE) debounce_time = MAX(ms_to_monotonic_t(200ll), debounce_time); if (now - w->live_resize.last_resize_event_at >= debounce_time) update_viewport = true; else { global_state.has_pending_resizes = true; diff --git a/kitty/graphics_fragment.glsl b/kitty/graphics_fragment.glsl index 2a1c71146..55617f018 100644 --- a/kitty/graphics_fragment.glsl +++ b/kitty/graphics_fragment.glsl @@ -4,7 +4,7 @@ uniform sampler2D image; #ifdef ALPHA_MASK uniform vec3 amask_fg; -uniform float alpha_mask_premult; +uniform vec4 amask_bg_premult; #else uniform float inactive_text_alpha; #endif @@ -12,11 +12,21 @@ uniform float inactive_text_alpha; in vec2 texcoord; out vec4 color; +#ifdef ALPHA_MASK +vec4 alpha_blend_premul(vec4 over, vec4 under) { + // Same as alpha_blend() except that it assumes over and under are both premultiplied. + float inv_over_alpha = 1.0f - over.a; + float alpha = over.a + under.a * inv_over_alpha; + return vec4(over.rgb + under.rgb * inv_over_alpha, alpha); +} +#endif + void main() { color = texture(image, texcoord); #ifdef ALPHA_MASK color = vec4(amask_fg, color.r); - color = mix(color, vec4(color.rgb * color.a, color.a), alpha_mask_premult); + color = vec4(color.rgb * color.a, color.a); + color = alpha_blend_premul(color, amask_bg_premult); #else color.a *= inactive_text_alpha; #ifdef PREMULT diff --git a/kitty/options/definition.py b/kitty/options/definition.py index 75babd98c..6af35c98d 100644 --- a/kitty/options/definition.py +++ b/kitty/options/definition.py @@ -1080,17 +1080,6 @@ resizing, while not also continuously redrawing, to save energy. ''' ) -opt('resize_draw_strategy', 'static', - option_type='resize_draw_strategy', ctype='int', - long_text=''' -Choose how kitty draws a window while a resize is in progress. A value of -:code:`static` means draw the current window contents, mostly unchanged. A value -of :code:`scale` means draw the current window contents scaled. A value of -:code:`blank` means draw a blank window. A value of :code:`size` means show the -window size in cells. -''' - ) - opt('resize_in_steps', 'no', option_type='to_bool', ctype='bool', long_text=''' diff --git a/kitty/options/parse.py b/kitty/options/parse.py index 799475847..fc0972e45 100644 --- a/kitty/options/parse.py +++ b/kitty/options/parse.py @@ -14,11 +14,11 @@ from kitty.options.utils import ( deprecated_send_text, disable_ligatures, edge_width, env, font_features, hide_window_decorations, macos_option_as_alt, macos_titlebar_color, modify_font, narrow_symbols, optional_edge_width, parse_map, parse_mouse_map, paste_actions, remote_control_password, resize_debounce_time, - resize_draw_strategy, scrollback_lines, scrollback_pager_history_size, 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_title_template, titlebar_color, - to_cursor_shape, to_font_size, to_layout_names, to_modifiers, url_prefixes, url_style, - visual_window_select_characters, window_border_width, window_size + scrollback_lines, scrollback_pager_history_size, 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_title_template, titlebar_color, to_cursor_shape, to_font_size, + to_layout_names, to_modifiers, url_prefixes, url_style, visual_window_select_characters, + window_border_width, window_size ) @@ -1153,9 +1153,6 @@ class Parser: def resize_debounce_time(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: ans['resize_debounce_time'] = resize_debounce_time(val) - def resize_draw_strategy(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: - ans['resize_draw_strategy'] = resize_draw_strategy(val) - def resize_in_steps(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: ans['resize_in_steps'] = to_bool(val) diff --git a/kitty/options/to-c-generated.h b/kitty/options/to-c-generated.h index 027fd398e..cf57edf7a 100644 --- a/kitty/options/to-c-generated.h +++ b/kitty/options/to-c-generated.h @@ -603,19 +603,6 @@ convert_from_opts_resize_debounce_time(PyObject *py_opts, Options *opts) { Py_DECREF(ret); } -static void -convert_from_python_resize_draw_strategy(PyObject *val, Options *opts) { - opts->resize_draw_strategy = PyLong_AsLong(val); -} - -static void -convert_from_opts_resize_draw_strategy(PyObject *py_opts, Options *opts) { - PyObject *ret = PyObject_GetAttrString(py_opts, "resize_draw_strategy"); - if (ret == NULL) return; - convert_from_python_resize_draw_strategy(ret, opts); - Py_DECREF(ret); -} - static void convert_from_python_resize_in_steps(PyObject *val, Options *opts) { opts->resize_in_steps = PyObject_IsTrue(val); @@ -1152,8 +1139,6 @@ convert_opts_from_python_opts(PyObject *py_opts, Options *opts) { if (PyErr_Occurred()) return false; convert_from_opts_resize_debounce_time(py_opts, opts); if (PyErr_Occurred()) return false; - convert_from_opts_resize_draw_strategy(py_opts, opts); - if (PyErr_Occurred()) return false; convert_from_opts_resize_in_steps(py_opts, opts); if (PyErr_Occurred()) return false; convert_from_opts_tab_bar_edge(py_opts, opts); diff --git a/kitty/options/types.py b/kitty/options/types.py index 5dcb4e6b2..f750aff02 100644 --- a/kitty/options/types.py +++ b/kitty/options/types.py @@ -410,7 +410,6 @@ option_names = ( # {{{ 'remote_control_password', 'repaint_delay', 'resize_debounce_time', - 'resize_draw_strategy', 'resize_in_steps', 'scrollback_fill_enlarged_window', 'scrollback_lines', @@ -565,7 +564,6 @@ class Options: remember_window_size: bool = True repaint_delay: int = 10 resize_debounce_time: typing.Tuple[float, float] = (0.1, 0.5) - resize_draw_strategy: int = 0 resize_in_steps: bool = False scrollback_fill_enlarged_window: bool = False scrollback_lines: int = 2000 diff --git a/kitty/shaders.c b/kitty/shaders.c index 1edb689c9..f4f9d1ff8 100644 --- a/kitty/shaders.c +++ b/kitty/shaders.c @@ -40,6 +40,12 @@ color_vec3(GLint location, color_type color) { glUniform3f(location, srgb_lut[(color >> 16) & 0xFF], srgb_lut[(color >> 8) & 0xFF], srgb_lut[color & 0xFF]); } +static void +color_vec4_premult(GLint location, color_type color, GLfloat alpha) { + glUniform4f(location, srgb_lut[(color >> 16) & 0xFF]*alpha, srgb_lut[(color >> 8) & 0xFF]*alpha, srgb_lut[color & 0xFF]*alpha, alpha); +} + + SPRITE_MAP_HANDLE alloc_sprite_map(unsigned int cell_width, unsigned int cell_height) { if (!max_texture_size) { @@ -266,7 +272,7 @@ create_graphics_vao(void) { struct CellUniformData { bool constants_set; - GLint gploc, gpploc, cploc, cfploc, fg_loc, amask_premult_loc, amask_fg_loc, amask_image_loc; + GLint gploc, gpploc, cploc, cfploc, fg_loc, amask_bg_premult_loc, amask_fg_loc, amask_image_loc; GLfloat prev_inactive_text_alpha; }; @@ -511,7 +517,7 @@ draw_centered_alpha_mask(OSWindow *os_window, size_t screen_width, size_t screen bind_program(GRAPHICS_ALPHA_MASK_PROGRAM); glUniform1i(cell_uniform_data.amask_image_loc, GRAPHICS_UNIT); color_vec3(cell_uniform_data.amask_fg_loc, OPT(foreground)); - glUniform1f(cell_uniform_data.amask_premult_loc, os_window->is_semi_transparent ? 1.f : 0.f); + color_vec4_premult(cell_uniform_data.amask_bg_premult_loc, OPT(background), 1); send_graphics_data_to_gpu(1, os_window->gvao_idx, data); glEnable(GL_BLEND); if (os_window->is_semi_transparent) { @@ -561,7 +567,7 @@ set_cell_uniforms(float current_inactive_text_alpha, bool force) { cell_uniform_data.gpploc = glGetUniformLocation(program_id(GRAPHICS_PREMULT_PROGRAM), "inactive_text_alpha"); cell_uniform_data.cploc = glGetUniformLocation(program_id(CELL_PROGRAM), "inactive_text_alpha"); cell_uniform_data.cfploc = glGetUniformLocation(program_id(CELL_FG_PROGRAM), "inactive_text_alpha"); - cell_uniform_data.amask_premult_loc = glGetUniformLocation(program_id(GRAPHICS_ALPHA_MASK_PROGRAM), "alpha_mask_premult"); + cell_uniform_data.amask_bg_premult_loc = glGetUniformLocation(program_id(GRAPHICS_ALPHA_MASK_PROGRAM), "amask_bg_premult"); cell_uniform_data.amask_fg_loc = glGetUniformLocation(program_id(GRAPHICS_ALPHA_MASK_PROGRAM), "amask_fg"); cell_uniform_data.amask_image_loc = glGetUniformLocation(program_id(GRAPHICS_ALPHA_MASK_PROGRAM), "image"); #define S(prog, name, val, type) { bind_program(prog); glUniform##type(glGetUniformLocation(program_id(prog), #name), val); } @@ -726,7 +732,7 @@ draw_window_number(OSWindow *os_window, Screen *screen, const CellRenderData *cr glUniform1i(cell_uniform_data.amask_image_loc, GRAPHICS_UNIT); 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); color_vec3(cell_uniform_data.amask_fg_loc, digit_color); - glUniform1f(cell_uniform_data.amask_premult_loc, 1.f); + glUniform4f(cell_uniform_data.amask_bg_premult_loc, 0.f, 0.f, 0.f, 0.f); send_graphics_data_to_gpu(1, os_window->gvao_idx, ird); draw_graphics(GRAPHICS_ALPHA_MASK_PROGRAM, 0, os_window->gvao_idx, ird, 0, 1); glDisable(GL_BLEND); diff --git a/kitty/state.h b/kitty/state.h index 0a8d45d7a..0332efb92 100644 --- a/kitty/state.h +++ b/kitty/state.h @@ -13,7 +13,6 @@ #define OPT(name) global_state.opts.name typedef enum { LEFT_EDGE, TOP_EDGE, RIGHT_EDGE, BOTTOM_EDGE } Edge; -typedef enum { RESIZE_DRAW_STATIC, RESIZE_DRAW_SCALED, RESIZE_DRAW_BLANK, RESIZE_DRAW_SIZE } ResizeDrawStrategy; typedef enum { REPEAT_MIRROR, REPEAT_CLAMP, REPEAT_DEFAULT } RepeatStrategy; typedef enum { WINDOW_NORMAL, WINDOW_FULLSCREEN, WINDOW_MAXIMIZED, WINDOW_MINIMIZED } WindowState; @@ -63,7 +62,6 @@ typedef struct { unsigned long tab_bar_min_tabs; DisableLigature disable_ligatures; bool force_ltr; - ResizeDrawStrategy resize_draw_strategy; bool resize_in_steps; bool sync_to_monitor; bool close_on_child_death;