From b01c3483de9cc7260757e466a1a93d4931fba583 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Thu, 28 Dec 2017 10:36:48 +0530 Subject: [PATCH] Add an option to fade text in inactive windows Fixes #256 --- CHANGELOG.rst | 2 ++ kitty/cell_fragment.glsl | 5 ++-- kitty/child-monitor.c | 6 ++--- kitty/config.py | 1 + kitty/graphics_fragment.glsl | 2 ++ kitty/kitty.conf | 4 ++++ kitty/shaders.c | 46 +++++++++++++++++++++++++----------- kitty/state.c | 1 + kitty/state.h | 3 ++- 9 files changed, 50 insertions(+), 20 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 99846f230..917f7195c 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -6,6 +6,8 @@ kitty is a feature full, cross-platform, *fast*, GPU based terminal emulator. version 0.6.1 [future] --------------------------- +- Add an option to fade the text in inactive windows + - Add new actions to open windows/tabs/etc. with the working directory set to the working directory of the current window. diff --git a/kitty/cell_fragment.glsl b/kitty/cell_fragment.glsl index b40714198..7cf8f7cec 100644 --- a/kitty/cell_fragment.glsl +++ b/kitty/cell_fragment.glsl @@ -19,6 +19,7 @@ in float bg_alpha; #ifdef NEEDS_FOREGROUND uniform sampler2DArray sprites; +uniform float inactive_text_alpha; in vec3 sprite_pos; in vec3 underline_pos; in vec3 strike_pos; @@ -60,7 +61,7 @@ vec4 calculate_foreground() { // Since strike and text are the same color, we simply add the alpha values float combined_alpha = min(text_alpha + strike_alpha, 1.0f); // Underline color might be different, so alpha blend - return alpha_blend(decoration_fg, underline_alpha, fg, combined_alpha); + return alpha_blend(decoration_fg, underline_alpha * inactive_text_alpha, fg, combined_alpha * inactive_text_alpha); } #endif @@ -99,7 +100,7 @@ void main() { final_color = alpha_blend_premul(fg.rgb, fg.a, background * bg_alpha, bg_alpha); final_color = vec4(final_color.rgb / final_color.a, final_color.a); #else - // since background alpha is 1.0, it is effectively premultipled + // since background alpha is 1.0, it is effectively pre-multiplied final_color = vec4(premul_blend(fg.rgb, fg.a, background), 1.0f); final_color = vec4(final_color.rgb / final_color.a, final_color.a); #endif diff --git a/kitty/child-monitor.c b/kitty/child-monitor.c index 6ac69bda4..667bfeadd 100644 --- a/kitty/child-monitor.c +++ b/kitty/child-monitor.c @@ -551,7 +551,7 @@ simple_render_screen(PyObject UNUSED *self, PyObject *args) { if (vao_idx == -1) vao_idx = create_cell_vao(); if (gvao_idx == -1) gvao_idx = create_graphics_vao(); if (!PyArg_ParseTuple(args, "O!ffff", &Screen_Type, &screen, &xstart, &ystart, &dx, &dy)) return NULL; - draw_cells(vao_idx, gvao_idx, xstart, ystart, dx, dy, screen, current_os_window()); + draw_cells(vao_idx, gvao_idx, xstart, ystart, dx, dy, screen, current_os_window(), true); Py_RETURN_NONE; } @@ -577,7 +577,7 @@ render_os_window(OSWindow *os_window, double now, unsigned int *active_window_id collect_cursor_info(&WD.screen->cursor_render_info, w, now, os_window); update_window_title(w, os_window); } else WD.screen->cursor_render_info.is_visible = false; - draw_cells(WD.vao_idx, WD.gvao_idx, WD.xstart, WD.ystart, WD.dx, WD.dy, WD.screen, os_window); + draw_cells(WD.vao_idx, WD.gvao_idx, WD.xstart, WD.ystart, WD.dx, WD.dy, WD.screen, os_window, is_active_window); if (is_active_window && WD.screen->cursor_render_info.is_visible && (!WD.screen->cursor_render_info.is_focused || WD.screen->cursor_render_info.shape != CURSOR_BLOCK)) { draw_cursor(&WD.screen->cursor_render_info, os_window->is_focused); } @@ -613,7 +613,7 @@ render(double now) { Tab *active_tab = w->tabs + w->active_tab; BorderRects *br = &active_tab->border_rects; draw_borders(br->vao_idx, br->num_border_rects, br->rect_buf, br->is_dirty, w->viewport_width, w->viewport_height); - if (TD.screen && w->num_tabs > 1) draw_cells(TD.vao_idx, 0, TD.xstart, TD.ystart, TD.dx, TD.dy, TD.screen, w); + if (TD.screen && w->num_tabs > 1) draw_cells(TD.vao_idx, 0, TD.xstart, TD.ystart, TD.dx, TD.dy, TD.screen, w, true); swap_window_buffers(w); w->last_active_tab = w->active_tab; w->last_num_tabs = w->num_tabs; w->last_active_window_id = active_window_id; br->is_dirty = false; diff --git a/kitty/config.py b/kitty/config.py index 8e4e2a301..703a0aaf2 100644 --- a/kitty/config.py +++ b/kitty/config.py @@ -291,6 +291,7 @@ type_map = { 'tab_separator': tab_separator, 'active_tab_font_style': tab_font_style, 'inactive_tab_font_style': tab_font_style, + 'inactive_text_alpha': unit_float, 'url_style': url_style, 'prefer_color_emoji': to_bool, } diff --git a/kitty/graphics_fragment.glsl b/kitty/graphics_fragment.glsl index c0de67afb..d09a6785a 100644 --- a/kitty/graphics_fragment.glsl +++ b/kitty/graphics_fragment.glsl @@ -2,12 +2,14 @@ #define ALPHA_TYPE uniform sampler2D image; +uniform float inactive_text_alpha; in vec2 texcoord; out vec4 color; void main() { color = texture(image, texcoord); + color.a *= inactive_text_alpha; #ifdef PREMULT color = vec4(color.rgb * color.a, color.a); #endif diff --git a/kitty/kitty.conf b/kitty/kitty.conf index e33385052..6bb1251fc 100644 --- a/kitty/kitty.conf +++ b/kitty/kitty.conf @@ -181,6 +181,10 @@ active_border_color #00ff00 # The color for the border of inactive windows inactive_border_color #cccccc +# Fade the text in inactive windows by the specified amount (a number between +# zero and one, with 0 being fully faded). +inactive_text_alpha 1.0 + # Tab-bar customization active_tab_foreground #000 active_tab_background #eee diff --git a/kitty/shaders.c b/kitty/shaders.c index 5514f8480..8705090ce 100644 --- a/kitty/shaders.c +++ b/kitty/shaders.c @@ -201,6 +201,14 @@ create_graphics_vao() { return vao_idx; } +struct CellUniformData { + bool constants_set; + GLint gploc, gpploc, cploc, cfploc; + GLfloat prev_inactive_text_alpha; +}; + +static struct CellUniformData cell_uniform_data = {0, .prev_inactive_text_alpha=-1}; + 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) { struct CellRenderData { @@ -284,12 +292,6 @@ static void draw_graphics(int program, ssize_t vao_idx, ssize_t gvao_idx, ImageRenderData *data, GLuint start, GLuint count) { bind_program(program); bind_vertex_array(gvao_idx); - static bool graphics_constants_set = false; - if (!graphics_constants_set) { - glUniform1i(glGetUniformLocation(program_id(GRAPHICS_PROGRAM), "image"), GRAPHICS_UNIT); - glUniform1i(glGetUniformLocation(program_id(GRAPHICS_PREMULT_PROGRAM), "image"), GRAPHICS_UNIT); - graphics_constants_set = true; - } glActiveTexture(GL_TEXTURE0 + GRAPHICS_UNIT); GLuint base = 4 * start; @@ -389,8 +391,29 @@ draw_cells_interleaved_premult(ssize_t vao_idx, ssize_t gvao_idx, Screen *screen glDisable(GL_SCISSOR_TEST); } +static inline void +set_cell_uniforms(float current_inactive_text_alpha) { + if (!cell_uniform_data.constants_set) { + cell_uniform_data.gploc = glGetUniformLocation(program_id(GRAPHICS_PROGRAM), "inactive_text_alpha"); + 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"); +#define S(prog, name, val) { bind_program(prog); glUniform1i(glGetUniformLocation(program_id(prog), #name), val); } + S(GRAPHICS_PROGRAM, image, GRAPHICS_UNIT); S(GRAPHICS_PREMULT_PROGRAM, image, GRAPHICS_UNIT); + S(CELL_PROGRAM, sprites, SPRITE_MAP_UNIT); S(CELL_FG_PROGRAM, sprites, SPRITE_MAP_UNIT); +#undef S + cell_uniform_data.constants_set = true; + } + if (current_inactive_text_alpha != cell_uniform_data.prev_inactive_text_alpha) { + cell_uniform_data.prev_inactive_text_alpha = current_inactive_text_alpha; +#define S(prog, loc) { bind_program(prog); glUniform1f(cell_uniform_data.loc, current_inactive_text_alpha); } + S(CELL_PROGRAM, cploc); S(CELL_FG_PROGRAM, cfploc); S(GRAPHICS_PROGRAM, gploc); S(GRAPHICS_PREMULT_PROGRAM, gpploc); +#undef S + } +} + void -draw_cells(ssize_t vao_idx, ssize_t gvao_idx, GLfloat xstart, GLfloat ystart, GLfloat dx, GLfloat dy, Screen *screen, OSWindow *os_window) { +draw_cells(ssize_t vao_idx, ssize_t gvao_idx, GLfloat xstart, GLfloat ystart, GLfloat dx, GLfloat dy, Screen *screen, OSWindow *os_window, bool is_active_window) { if (os_window->clear_count < 2) { os_window->clear_count++; #define C(shift) (((GLfloat)((OPT(background) >> shift) & 0xFF)) / 255.0f) @@ -400,6 +423,8 @@ draw_cells(ssize_t vao_idx, ssize_t gvao_idx, GLfloat xstart, GLfloat ystart, GL } cell_prepare_to_render(vao_idx, gvao_idx, screen, xstart, ystart, dx, dy); + float current_inactive_text_alpha = screen->cursor_render_info.is_focused && is_active_window ? 1.0 : OPT(inactive_text_alpha); + set_cell_uniforms(current_inactive_text_alpha); GLfloat w = (GLfloat)screen->columns * dx, h = (GLfloat)screen->lines * dy; #define SCALE(w, x) ((GLfloat)(os_window->viewport_##w) * (GLfloat)(x)) glScissor( @@ -409,13 +434,6 @@ draw_cells(ssize_t vao_idx, ssize_t gvao_idx, GLfloat xstart, GLfloat ystart, GL (GLsizei)(ceilf(SCALE(height, h / 2.0f))) ); #undef SCALE - static bool cell_constants_set = false; - if (!cell_constants_set) { - bind_program(CELL_PROGRAM); - glUniform1i(glGetUniformLocation(program_id(CELL_PROGRAM), "sprites"), SPRITE_MAP_UNIT); - glUniform1i(glGetUniformLocation(program_id(CELL_FG_PROGRAM), "sprites"), SPRITE_MAP_UNIT); - cell_constants_set = true; - } if (os_window->is_semi_transparent) { if (screen->grman->count) draw_cells_interleaved_premult(vao_idx, gvao_idx, screen, os_window); else draw_cells_simple(vao_idx, gvao_idx, screen); diff --git a/kitty/state.c b/kitty/state.c index 9ca2001a1..9c9255b50 100644 --- a/kitty/state.c +++ b/kitty/state.c @@ -311,6 +311,7 @@ PYWRAP1(set_options) { S(cursor_blink_interval, PyFloat_AsDouble); S(cursor_stop_blinking_after, PyFloat_AsDouble); S(background_opacity, PyFloat_AsDouble); + S(inactive_text_alpha, PyFloat_AsDouble); S(cursor_shape, PyLong_AsLong); S(url_style, PyLong_AsUnsignedLong); S(x11_bell_volume, PyLong_AsLong); diff --git a/kitty/state.h b/kitty/state.h index 28bac6d4d..6c93ca75f 100644 --- a/kitty/state.h +++ b/kitty/state.h @@ -27,6 +27,7 @@ typedef struct { int x11_bell_volume; float adjust_line_height_frac; float background_opacity; + float inactive_text_alpha; } Options; typedef struct { @@ -164,7 +165,7 @@ void draw_borders(ssize_t vao_idx, unsigned int num_border_rects, BorderRect *re ssize_t create_cell_vao(); ssize_t create_graphics_vao(); ssize_t create_border_vao(); -void draw_cells(ssize_t, ssize_t, float, float, float, float, Screen *, OSWindow *); +void draw_cells(ssize_t, ssize_t, float, float, float, float, Screen *, OSWindow *, bool); void draw_cursor(CursorRenderInfo *, bool); void update_surface_size(int, int, uint32_t); void free_texture(uint32_t*);