From ccf5391b4549f7112a720adba1038e56bf496475 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Tue, 12 Sep 2017 14:40:30 +0530 Subject: [PATCH] Move visual bell tracking into the Screen object --- kitty/boss.py | 2 +- kitty/char_grid.py | 10 ++++------ kitty/data-types.h | 14 ++++++++++++++ kitty/screen.c | 29 +++++++++++++++++++++++++++++ kitty/screen.h | 1 + kitty/shaders.c | 10 +++++----- kitty/state.c | 12 +++--------- kitty/window.py | 16 ---------------- 8 files changed, 57 insertions(+), 37 deletions(-) diff --git a/kitty/boss.py b/kitty/boss.py index 9ec62c466..eb2918b72 100644 --- a/kitty/boss.py +++ b/kitty/boss.py @@ -369,7 +369,7 @@ class Boss: self.tab_manager.render() for window in tab.visible_windows(): if not window.needs_layout: - window.render_cells() + window.char_grid.render_cells() active = self.active_window if active is not None: draw_cursor = True diff --git a/kitty/char_grid.py b/kitty/char_grid.py index 01831cb3d..40c69ef17 100644 --- a/kitty/char_grid.py +++ b/kitty/char_grid.py @@ -42,8 +42,8 @@ def calculate_gl_geometry(window_geometry, viewport_width, viewport_height, cell return ScreenGeometry(xstart, ystart, window_geometry.xnum, window_geometry.ynum, dx, dy) -def render_cells(vao_id, sg, screen, invert_colors=False): - draw_cells(vao_id, sg.xstart, sg.ystart, sg.dx, sg.dy, invert_colors, screen) +def render_cells(vao_id, sg, screen): + draw_cells(vao_id, sg.xstart, sg.ystart, sg.dx, sg.dy, screen) class CharGrid: @@ -172,10 +172,8 @@ class CharGrid: def text_for_selection(self): return ''.join(self.screen.text_for_selection()) - def render_cells(self, invert_colors=False): - render_cells( - self.vao_id, self.screen_geometry, - self.screen, invert_colors=invert_colors) + def render_cells(self): + render_cells(self.vao_id, self.screen_geometry, self.screen) def render_cursor(self, is_focused): if not self.screen.cursor_visible or self.screen.scrolled_by: diff --git a/kitty/data-types.h b/kitty/data-types.h index 69e5756e9..696bed39f 100644 --- a/kitty/data-types.h +++ b/kitty/data-types.h @@ -247,6 +247,7 @@ typedef struct { bool *tabstops, *main_tabstops, *alt_tabstops; ScreenModes modes; ColorProfile *color_profile; + double start_visual_bell_at; uint32_t parser_buf[PARSER_BUF_SZ]; unsigned int parser_state, parser_text_start, parser_buf_pos; @@ -286,6 +287,19 @@ typedef struct { } ChildMonitor; PyTypeObject ChildMonitor_Type; +typedef struct { + double visual_bell_duration; + bool enable_audio_bell; +} Options; + +typedef struct { + Options opts; +} GlobalState; + +#ifndef IS_STATE +extern GlobalState global_state; +#endif + #define clear_sprite_position(cell) (cell).sprite_x = 0; (cell).sprite_y = 0; (cell).sprite_z = 0; #define left_shift_line(line, at, num) \ diff --git a/kitty/screen.c b/kitty/screen.c index 0508feee7..04a7237be 100644 --- a/kitty/screen.c +++ b/kitty/screen.c @@ -16,6 +16,9 @@ #include "screen.h" #include #include +#include +#include +#include #include "unicode-data.h" #include "modes.h" #include "wcwidth9.h" @@ -911,8 +914,34 @@ screen_use_latin1(Screen *self, bool on) { CALLBACK("use_utf8", "O", on ? Py_False : Py_True); } +bool +screen_invert_colors(Screen *self) { + bool inverted = false; + if (self->start_visual_bell_at > 0) { + if (monotonic() - self->start_visual_bell_at <= global_state.opts.visual_bell_duration) inverted = true; + else self->start_visual_bell_at = 0; + } + if (self->modes.mDECSCNM) inverted = inverted ? false : true; + return inverted; +} + void screen_bell(Screen UNUSED *self) { + if (global_state.opts.enable_audio_bell) { + int fd = open("/dev/tty", O_WRONLY | O_CLOEXEC | O_NOCTTY); + if (fd > 0) { + static const char bell[2] = {7, 0}; + while(true) { + if (write(fd, &bell, sizeof(bell)) == sizeof(bell)) break; + if (errno == EINTR) continue; + break; + } + close(fd); + } + } + if (global_state.opts.visual_bell_duration > 0) { + self->start_visual_bell_at = monotonic(); + } CALLBACK("bell", NULL); } diff --git a/kitty/screen.h b/kitty/screen.h index 57b8946f5..d2df3119a 100644 --- a/kitty/screen.h +++ b/kitty/screen.h @@ -61,6 +61,7 @@ void report_device_status(Screen *self, unsigned int which, bool UNUSED); void report_mode_status(Screen *self, unsigned int which, bool); void screen_apply_selection(Screen *self, void *address, size_t size); bool screen_is_selection_dirty(Screen *self); +bool screen_invert_colors(Screen *self); void screen_update_cell_data(Screen *self, void *address, size_t sz); #define DECLARE_CH_SCREEN_HANDLER(name) void screen_##name(Screen *screen); DECLARE_CH_SCREEN_HANDLER(bell) diff --git a/kitty/shaders.c b/kitty/shaders.c index 3712cfa8d..37fefda11 100644 --- a/kitty/shaders.c +++ b/kitty/shaders.c @@ -596,10 +596,10 @@ create_cell_vao() { } static void -draw_cells(ssize_t vao_idx, GLfloat xstart, GLfloat ystart, GLfloat dx, GLfloat dy, bool inverted, Screen *screen) { +draw_cells(ssize_t vao_idx, GLfloat xstart, GLfloat ystart, GLfloat dx, GLfloat dy, Screen *screen) { size_t sz; void *address; - if (screen->modes.mDECSCNM) inverted = inverted ? false : true; + bool inverted = screen_invert_colors(screen); if (screen->scroll_changed || screen->is_dirty) { sz = sizeof(Cell) * screen->lines * screen->columns; address = map_vao_buffer(vao_idx, sz, 0, GL_STREAM_DRAW, GL_WRITE_ONLY); @@ -839,11 +839,11 @@ NO_ARG(init_cell_program) NO_ARG_INT(create_cell_vao) PYWRAP1(draw_cells) { float xstart, ystart, dx, dy; - int vao_idx, inverted; + int vao_idx; Screen *screen; - PA("iffffpO", &vao_idx, &xstart, &ystart, &dx, &dy, &inverted, &screen); - draw_cells(vao_idx, xstart, ystart, dx, dy, inverted & 1, screen); + PA("iffffO", &vao_idx, &xstart, &ystart, &dx, &dy, &screen); + draw_cells(vao_idx, xstart, ystart, dx, dy, screen); Py_RETURN_NONE; } NO_ARG(destroy_sprite_map) diff --git a/kitty/state.c b/kitty/state.c index 2b24c3ff2..21a4ccc87 100644 --- a/kitty/state.c +++ b/kitty/state.c @@ -5,6 +5,7 @@ * Distributed under terms of the GPL3 license. */ +#define IS_STATE #include "data-types.h" #define PYWRAP0(name) static PyObject* py##name(PyObject UNUSED *self) @@ -12,21 +13,14 @@ #define PYWRAP2(name) static PyObject* py##name(PyObject UNUSED *self, PyObject *args, PyObject *kw) #define PA(fmt, ...) if(!PyArg_ParseTuple(args, fmt, __VA_ARGS__)) return NULL; -typedef struct { - double visual_bell_duration; -} Options; - -typedef struct { - Options opts; -} GlobalState; - -static GlobalState global_state = {{0}}; +GlobalState global_state = {{0}}; // Python API {{{ PYWRAP1(set_options) { #define S(name, convert) { PyObject *ret = PyObject_GetAttrString(args, #name); if (ret == NULL) return NULL; global_state.opts.name = convert(ret); Py_DECREF(ret); } S(visual_bell_duration, PyFloat_AsDouble); + S(enable_audio_bell, PyObject_IsTrue); #undef S Py_RETURN_NONE; } diff --git a/kitty/window.py b/kitty/window.py index 7607c1b05..14a9ae9df 100644 --- a/kitty/window.py +++ b/kitty/window.py @@ -117,14 +117,6 @@ class Window: print('Failed to write to child %d as it does not exist' % self.id, file=sys.stderr) def bell(self): - if self.opts.enable_audio_bell: - try: - with open('/dev/tty', 'wb') as f: - f.write(b'\007') - except EnvironmentError: - pass # failure to beep is not critical - if self.opts.visual_bell_duration > 0: - self.start_visual_bell_at = monotonic() get_boss().request_attention() glfw_post_empty_event() @@ -281,14 +273,6 @@ class Window: def buf_toggled(self, is_main_linebuf): self.screen.scroll(SCROLL_FULL, False) - def render_cells(self): - invert_colors = False - if self.start_visual_bell_at is not None: - invert_colors = monotonic() - self.start_visual_bell_at <= self.opts.visual_bell_duration - if not invert_colors: - self.start_visual_bell_at = None - self.char_grid.render_cells(invert_colors) - # actions {{{ def show_scrollback(self):