Add an option to fade text in inactive windows

Fixes #256
This commit is contained in:
Kovid Goyal 2017-12-28 10:36:48 +05:30
parent db7f566a0c
commit b01c3483de
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
9 changed files with 50 additions and 20 deletions

View File

@ -6,6 +6,8 @@ kitty is a feature full, cross-platform, *fast*, GPU based terminal emulator.
version 0.6.1 [future] 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 - Add new actions to open windows/tabs/etc. with the working directory set to
the working directory of the current window. the working directory of the current window.

View File

@ -19,6 +19,7 @@ in float bg_alpha;
#ifdef NEEDS_FOREGROUND #ifdef NEEDS_FOREGROUND
uniform sampler2DArray sprites; uniform sampler2DArray sprites;
uniform float inactive_text_alpha;
in vec3 sprite_pos; in vec3 sprite_pos;
in vec3 underline_pos; in vec3 underline_pos;
in vec3 strike_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 // Since strike and text are the same color, we simply add the alpha values
float combined_alpha = min(text_alpha + strike_alpha, 1.0f); float combined_alpha = min(text_alpha + strike_alpha, 1.0f);
// Underline color might be different, so alpha blend // 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 #endif
@ -99,7 +100,7 @@ void main() {
final_color = alpha_blend_premul(fg.rgb, fg.a, background * bg_alpha, bg_alpha); 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); final_color = vec4(final_color.rgb / final_color.a, final_color.a);
#else #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(premul_blend(fg.rgb, fg.a, background), 1.0f);
final_color = vec4(final_color.rgb / final_color.a, final_color.a); final_color = vec4(final_color.rgb / final_color.a, final_color.a);
#endif #endif

View File

@ -551,7 +551,7 @@ simple_render_screen(PyObject UNUSED *self, PyObject *args) {
if (vao_idx == -1) vao_idx = create_cell_vao(); if (vao_idx == -1) vao_idx = create_cell_vao();
if (gvao_idx == -1) gvao_idx = create_graphics_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; 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; 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); collect_cursor_info(&WD.screen->cursor_render_info, w, now, os_window);
update_window_title(w, os_window); update_window_title(w, os_window);
} else WD.screen->cursor_render_info.is_visible = false; } 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)) { 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); 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; Tab *active_tab = w->tabs + w->active_tab;
BorderRects *br = &active_tab->border_rects; 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); 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); 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; 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; br->is_dirty = false;

View File

@ -291,6 +291,7 @@ type_map = {
'tab_separator': tab_separator, 'tab_separator': tab_separator,
'active_tab_font_style': tab_font_style, 'active_tab_font_style': tab_font_style,
'inactive_tab_font_style': tab_font_style, 'inactive_tab_font_style': tab_font_style,
'inactive_text_alpha': unit_float,
'url_style': url_style, 'url_style': url_style,
'prefer_color_emoji': to_bool, 'prefer_color_emoji': to_bool,
} }

View File

@ -2,12 +2,14 @@
#define ALPHA_TYPE #define ALPHA_TYPE
uniform sampler2D image; uniform sampler2D image;
uniform float inactive_text_alpha;
in vec2 texcoord; in vec2 texcoord;
out vec4 color; out vec4 color;
void main() { void main() {
color = texture(image, texcoord); color = texture(image, texcoord);
color.a *= inactive_text_alpha;
#ifdef PREMULT #ifdef PREMULT
color = vec4(color.rgb * color.a, color.a); color = vec4(color.rgb * color.a, color.a);
#endif #endif

View File

@ -181,6 +181,10 @@ active_border_color #00ff00
# The color for the border of inactive windows # The color for the border of inactive windows
inactive_border_color #cccccc 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 # Tab-bar customization
active_tab_foreground #000 active_tab_foreground #000
active_tab_background #eee active_tab_background #eee

View File

@ -201,6 +201,14 @@ create_graphics_vao() {
return vao_idx; 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 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) { 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 { 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) { draw_graphics(int program, ssize_t vao_idx, ssize_t gvao_idx, ImageRenderData *data, GLuint start, GLuint count) {
bind_program(program); bind_program(program);
bind_vertex_array(gvao_idx); 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); glActiveTexture(GL_TEXTURE0 + GRAPHICS_UNIT);
GLuint base = 4 * start; 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); 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 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) { if (os_window->clear_count < 2) {
os_window->clear_count++; os_window->clear_count++;
#define C(shift) (((GLfloat)((OPT(background) >> shift) & 0xFF)) / 255.0f) #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); 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; GLfloat w = (GLfloat)screen->columns * dx, h = (GLfloat)screen->lines * dy;
#define SCALE(w, x) ((GLfloat)(os_window->viewport_##w) * (GLfloat)(x)) #define SCALE(w, x) ((GLfloat)(os_window->viewport_##w) * (GLfloat)(x))
glScissor( 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))) (GLsizei)(ceilf(SCALE(height, h / 2.0f)))
); );
#undef SCALE #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 (os_window->is_semi_transparent) {
if (screen->grman->count) draw_cells_interleaved_premult(vao_idx, gvao_idx, screen, os_window); if (screen->grman->count) draw_cells_interleaved_premult(vao_idx, gvao_idx, screen, os_window);
else draw_cells_simple(vao_idx, gvao_idx, screen); else draw_cells_simple(vao_idx, gvao_idx, screen);

View File

@ -311,6 +311,7 @@ PYWRAP1(set_options) {
S(cursor_blink_interval, PyFloat_AsDouble); S(cursor_blink_interval, PyFloat_AsDouble);
S(cursor_stop_blinking_after, PyFloat_AsDouble); S(cursor_stop_blinking_after, PyFloat_AsDouble);
S(background_opacity, PyFloat_AsDouble); S(background_opacity, PyFloat_AsDouble);
S(inactive_text_alpha, PyFloat_AsDouble);
S(cursor_shape, PyLong_AsLong); S(cursor_shape, PyLong_AsLong);
S(url_style, PyLong_AsUnsignedLong); S(url_style, PyLong_AsUnsignedLong);
S(x11_bell_volume, PyLong_AsLong); S(x11_bell_volume, PyLong_AsLong);

View File

@ -27,6 +27,7 @@ typedef struct {
int x11_bell_volume; int x11_bell_volume;
float adjust_line_height_frac; float adjust_line_height_frac;
float background_opacity; float background_opacity;
float inactive_text_alpha;
} Options; } Options;
typedef struct { 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_cell_vao();
ssize_t create_graphics_vao(); ssize_t create_graphics_vao();
ssize_t create_border_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 draw_cursor(CursorRenderInfo *, bool);
void update_surface_size(int, int, uint32_t); void update_surface_size(int, int, uint32_t);
void free_texture(uint32_t*); void free_texture(uint32_t*);