Add a remote command to control window opacity

Fixes #569
This commit is contained in:
Kovid Goyal 2018-05-23 08:13:37 +05:30
parent 6fbb953aa4
commit c0f790c928
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
9 changed files with 80 additions and 14 deletions

View File

@ -19,11 +19,11 @@ from .constants import (
appname, config_dir, editor, set_boss, supports_primary_selection
)
from .fast_data_types import (
ChildMonitor, create_os_window, current_os_window, destroy_global_data,
destroy_sprite_map, get_clipboard_string,
glfw_post_empty_event, layout_sprite_map, mark_os_window_for_close,
set_clipboard_string, set_dpi_from_os_window, set_in_sequence_mode,
show_window, toggle_fullscreen, viewport_for_window
ChildMonitor, change_background_opacity, create_os_window,
current_os_window, destroy_global_data, destroy_sprite_map,
get_clipboard_string, glfw_post_empty_event, layout_sprite_map,
mark_os_window_for_close, set_clipboard_string, set_dpi_from_os_window,
set_in_sequence_mode, show_window, toggle_fullscreen, viewport_for_window
)
from .fonts.render import prerender, resize_fonts, set_font_family
from .keys import get_shortcut, shortcut_matches
@ -361,6 +361,9 @@ class Boss:
def on_dpi_change(self, os_window_id):
self._change_font_size()
def _set_os_window_background_opacity(self, os_window_id, opacity):
change_background_opacity(os_window_id, opacity)
@property
def active_tab_manager(self):
os_window_id = current_os_window()

View File

@ -614,7 +614,7 @@ static inline void
render_os_window(OSWindow *os_window, double now, unsigned int active_window_id, color_type active_window_bg, unsigned int num_visible_windows) {
Tab *tab = os_window->tabs + os_window->active_tab;
BorderRects *br = &tab->border_rects;
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);
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, os_window);
if (TD.screen && os_window->num_tabs > 1) draw_cells(TD.vao_idx, 0, TD.xstart, TD.ystart, TD.dx, TD.dy, TD.screen, os_window, true);
for (unsigned int i = 0; i < tab->num_windows; i++) {
Window *w = tab->windows + i;

View File

@ -586,6 +586,45 @@ def set_colors(boss, window, payload):
# }}}
# set_background_opacity {{{
@cmd(
'Set the background_opacity',
'Set the background opacity for the specified windows. This will only work if you have turned on'
' dynamic_background_opacity in kitty.conf. The background opacity affects all kitty windows in a'
' single os_window. For example: kitty @ set-background-opacity 0.5',
options_spec='''\
--all -a
type=bool-set
By default, colors are only changed for the currently active window. This option will
cause colors to be changed in all windows.
''' + '\n\n' + MATCH_WINDOW_OPTION + '\n\n' + MATCH_TAB_OPTION.replace('--match -m', '--match-tab -t'),
argspec='OPACITY'
)
def cmd_set_background_opacity(global_opts, opts, args):
if len(args) != 1:
raise SystemExit('Must specify exactly one argument, the new opacity')
opacity = max(0.1, min(float(args[0]), 1.0))
return {
'opacity': opacity, 'match_window': opts.match,
'all': opts.all or opts.reset,
}
def set_background_opacity(boss, window, payload):
if payload['all']:
windows = tuple(boss.all_windows)
else:
windows = (window or boss.active_window,)
if payload['match_window']:
windows = tuple(boss.match_windows(payload['match_window']))
if not windows:
raise MatchError(payload['match_window'])
for os_window_id in {w.os_window_id for w in windows}:
boss._set_os_window_background_opacity(os_window_id, payload['opacity'])
# }}}
cmap = {v.name: v for v in globals().values() if hasattr(v, 'is_cmd')}

View File

@ -354,6 +354,7 @@ type_map = {
'macos_option_as_alt': to_bool,
'macos_titlebar_color': macos_titlebar_color,
'box_drawing_scale': box_drawing_scale,
'dynamic_background_opacity': to_bool,
'background_opacity': unit_float,
'dim_opacity': unit_float,
'tab_separator': tab_separator,

View File

@ -365,7 +365,7 @@ create_os_window(PyObject UNUSED *self, PyObject *args) {
PyErr_SetString(PyExc_ValueError, "Too many windows");
return NULL;
}
bool want_semi_transparent = (1.0 - OPT(background_opacity) >= 0.01) ? true : false;
bool want_semi_transparent = (1.0 - OPT(background_opacity) >= 0.01) || OPT(dynamic_background_opacity);
glfwWindowHint(GLFW_TRANSPARENT_FRAMEBUFFER, want_semi_transparent);
GLFWwindow *glfw_window = glfwCreateWindow(width, height, title, NULL, global_state.num_os_windows ? global_state.os_windows[0].handle : NULL);
if (glfw_window == NULL) {

View File

@ -257,7 +257,10 @@ background #000000
# in the editor color scheme. Or use the escape codes to set the terminals
# default colors in a shell script to launch your editor.
# Be aware that using a value less than 1.0 is a (possibly significant) performance hit.
# If you want to dynamically change transparency of windows using the kitty remote control facility,
# set dynamic_background_opacity to yes
background_opacity 1.0
dynamic_background_opacity no
# How much to dim text that has the DIM/FAINT attribute set. 1.0 means no dimming and
# 0.0 means fully dimmed (i.e. invisible).

View File

@ -209,7 +209,7 @@ struct CellUniformData {
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) {
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, OSWindow *os_window) {
struct CellRenderData {
GLfloat xstart, ystart, dx, dy, sprite_dx, sprite_dy, background_opacity;
@ -239,7 +239,7 @@ cell_update_uniform_block(ssize_t vao_idx, Screen *screen, int uniform_buffer, G
sprite_tracker_current_layout(&x, &y, &z);
rd->sprite_dx = 1.0f / (float)x; rd->sprite_dy = 1.0f / (float)y;
rd->inverted = inverted ? 1 : 0;
rd->background_opacity = OPT(background_opacity);
rd->background_opacity = os_window->background_opacity;
#define COLOR(name) colorprofile_to_color(screen->color_profile, screen->color_profile->overridden.name, screen->color_profile->configured.name)
rd->default_fg = COLOR(default_fg); rd->default_bg = COLOR(default_bg); rd->highlight_fg = COLOR(highlight_fg); rd->highlight_bg = COLOR(highlight_bg);
@ -415,7 +415,7 @@ send_cell_data_to_gpu(ssize_t vao_idx, ssize_t gvao_idx, GLfloat xstart, GLfloat
if (os_window->clear_count < 2) {
os_window->clear_count++;
#define C(shift) (((GLfloat)((OPT(background) >> shift) & 0xFF)) / 255.0f)
glClearColor(C(16), C(8), C(0), os_window->is_semi_transparent ? OPT(background_opacity) : 1.0f);
glClearColor(C(16), C(8), C(0), os_window->is_semi_transparent ? os_window->background_opacity : 1.0f);
#undef C
glClear(GL_COLOR_BUFFER_BIT);
changed = true;
@ -430,7 +430,7 @@ draw_cells(ssize_t vao_idx, ssize_t gvao_idx, GLfloat xstart, GLfloat ystart, GL
CELL_BUFFERS;
bool inverted = screen_invert_colors(screen);
cell_update_uniform_block(vao_idx, screen, uniform_buffer, xstart, ystart, dx, dy, &screen->cursor_render_info, inverted);
cell_update_uniform_block(vao_idx, screen, uniform_buffer, xstart, ystart, dx, dy, &screen->cursor_render_info, inverted, os_window);
bind_vao_uniform_buffer(vao_idx, uniform_buffer, cell_program_layouts[CELL_PROGRAM].render_data.index);
bind_vertex_array(vao_idx);
@ -522,7 +522,7 @@ create_border_vao() {
}
void
draw_borders(ssize_t vao_idx, unsigned int num_border_rects, BorderRect *rect_buf, bool rect_data_is_dirty, uint32_t viewport_width, uint32_t viewport_height, color_type active_window_bg, unsigned int num_visible_windows) {
draw_borders(ssize_t vao_idx, unsigned int num_border_rects, BorderRect *rect_buf, bool rect_data_is_dirty, uint32_t viewport_width, uint32_t viewport_height, color_type active_window_bg, unsigned int num_visible_windows, OSWindow *w) {
if (num_border_rects) {
if (rect_data_is_dirty) {
size_t sz = sizeof(GLuint) * 5 * num_border_rects;
@ -535,11 +535,14 @@ draw_borders(ssize_t vao_idx, unsigned int num_border_rects, BorderRect *rect_bu
#define CV3(x) (((float)((x >> 16) & 0xff))/255.f), (((float)((x >> 8) & 0xff))/255.f), (((float)(x & 0xff))/255.f)
if (!constants_set) {
constants_set = true;
glUniform1f(border_uniform_locations[BORDER_background_opacity], OPT(background_opacity));
glUniform1f(border_uniform_locations[BORDER_background_opacity], w->background_opacity);
glUniform3f(border_uniform_locations[BORDER_active_border_color], CV3(OPT(active_border_color)));
glUniform3f(border_uniform_locations[BORDER_inactive_border_color], CV3(OPT(inactive_border_color)));
glUniform3f(border_uniform_locations[BORDER_bell_border_color], CV3(OPT(bell_border_color)));
}
if (OPT(dynamic_background_opacity)) {
glUniform1f(border_uniform_locations[BORDER_background_opacity], w->background_opacity);
}
glUniform2ui(border_uniform_locations[BORDER_viewport], viewport_width, viewport_height);
color_type default_bg = num_visible_windows > 1 ? OPT(background) : active_window_bg;
glUniform3f(border_uniform_locations[BORDER_default_bg], CV3(default_bg));

View File

@ -81,6 +81,7 @@ add_os_window() {
memset(ans, 0, sizeof(OSWindow));
ans->id = ++global_state.os_window_id_counter;
ans->tab_bar_render_data.vao_idx = create_cell_vao();
ans->background_opacity = OPT(background_opacity);
END_WITH_OS_WINDOW_REFS
return ans;
}
@ -360,6 +361,7 @@ PYWRAP1(set_options) {
S(cursor_stop_blinking_after, PyFloat_AsDouble);
S(background_opacity, PyFloat_AsDouble);
S(dim_opacity, PyFloat_AsDouble);
S(dynamic_background_opacity, PyObject_IsTrue);
S(inactive_text_alpha, PyFloat_AsDouble);
S(window_padding_width, PyFloat_AsDouble);
S(cursor_shape, PyLong_AsLong);
@ -503,6 +505,18 @@ PYWRAP1(mark_tab_bar_dirty) {
Py_RETURN_NONE;
}
PYWRAP1(change_background_opacity) {
id_type os_window_id;
float opacity;
PA("Kf", &os_window_id, &opacity);
WITH_OS_WINDOW(os_window_id)
os_window->background_opacity = opacity;
os_window->is_damaged = true;
Py_RETURN_TRUE;
END_WITH_OS_WINDOW
Py_RETURN_FALSE;
}
static inline bool
fix_window_idx(Tab *tab, id_type window_id, unsigned int *window_idx) {
for (id_type fix = 0; fix < tab->num_windows; fix++) {
@ -630,6 +644,7 @@ static PyMethodDef module_methods[] = {
MW(mark_os_window_for_close, METH_VARARGS),
MW(set_titlebar_color, METH_VARARGS),
MW(mark_tab_bar_dirty, METH_O),
MW(change_background_opacity, METH_VARARGS),
MW(update_window_visibility, METH_VARARGS),
MW(set_boss, METH_O),
MW(set_display_state, METH_VARARGS),

View File

@ -27,6 +27,7 @@ typedef struct {
int adjust_line_height_px, adjust_column_width_px;
float adjust_line_height_frac, adjust_column_width_frac;
float background_opacity, dim_opacity;
bool dynamic_background_opacity;
float inactive_text_alpha;
float window_padding_width;
Edge tab_bar_edge;
@ -118,6 +119,7 @@ typedef struct {
uint32_t offscreen_texture_id;
unsigned int clear_count;
color_type last_titlebar_color;
float background_opacity;
} OSWindow;
@ -171,7 +173,7 @@ OSWindow* add_os_window();
OSWindow* current_os_window();
void os_window_regions(OSWindow*, Region *main, Region *tab_bar);
bool drag_scroll(Window *, OSWindow*);
void draw_borders(ssize_t vao_idx, unsigned int num_border_rects, BorderRect *rect_buf, bool rect_data_is_dirty, uint32_t viewport_width, uint32_t viewport_height, color_type, unsigned int);
void draw_borders(ssize_t vao_idx, unsigned int num_border_rects, BorderRect *rect_buf, bool rect_data_is_dirty, uint32_t viewport_width, uint32_t viewport_height, color_type, unsigned int, OSWindow *w);
ssize_t create_cell_vao();
ssize_t create_graphics_vao();
ssize_t create_border_vao();