diff --git a/CHANGELOG.rst b/CHANGELOG.rst index a978a0ad6..1e2c08028 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -34,6 +34,8 @@ version 0.5.1 [2017-12-01] - Drop the dependency on glfw (kitty now uses a modified, bundled copy of glfw) +- Add an option to control the audio bell volume on X11 systems + version 0.5.0 [2017-11-19] --------------------------- diff --git a/kitty/cocoa_window.m b/kitty/cocoa_window.m index c81752a87..4e43acb8f 100644 --- a/kitty/cocoa_window.m +++ b/kitty/cocoa_window.m @@ -152,6 +152,10 @@ return true; } +void +cocoa_audio_bell(void) { + NSBeep(); +} PyObject* cocoa_get_lang(PyObject UNUSED *self) { diff --git a/kitty/config.py b/kitty/config.py index 8f50eaa32..3ea009a31 100644 --- a/kitty/config.py +++ b/kitty/config.py @@ -257,6 +257,7 @@ def box_drawing_scale(x): 'macos_hide_titlebar': to_bool, 'macos_option_as_alt': to_bool, 'box_drawing_scale': box_drawing_scale, + 'x11_bell_volume': int, } for name in ( diff --git a/kitty/data-types.h b/kitty/data-types.h index 774365779..f40338c5a 100644 --- a/kitty/data-types.h +++ b/kitty/data-types.h @@ -272,4 +272,4 @@ void scroll_event(double, double); void set_special_key_combo(int glfw_key, int mods); void on_text_input(unsigned int codepoint, int mods); void on_key_input(int key, int scancode, int action, int mods); -void request_window_attention(id_type); +void request_window_attention(id_type, bool); diff --git a/kitty/glfw.c b/kitty/glfw.c index d2e3bc9c8..645ee6a13 100644 --- a/kitty/glfw.c +++ b/kitty/glfw.c @@ -6,9 +6,11 @@ #include "state.h" #include +#include #include "glfw-wrapper.h" extern bool cocoa_make_window_resizable(void *w); extern void cocoa_create_global_menu(void); +extern void cocoa_audio_bell(void); #if GLFW_KEY_LAST >= MAX_KEY_COUNT #error "glfw has too many keys, you should increase MAX_KEY_COUNT" @@ -31,6 +33,23 @@ update_os_window_viewport(OSWindow *window, bool notify_boss) { window->last_resize_at = monotonic(); } +static void* +load_libX11(bool unload) { + static void* ans = NULL; + static bool tried = false; + if (unload) { if (ans) { dlclose(ans); ans = NULL; }; return NULL; } + if (!tried) { + tried = true; + ans = dlopen("libX11.so", RTLD_LAZY); + if (ans == NULL) fprintf(stderr, "Failed to load libX11.so with error: %s\n", dlerror()); + } + return ans; +} + +typedef bool (*xkb_bell_func)(void*, int32_t, int, void*); +xkb_bell_func xkb_bell = NULL; + + // callbacks {{{ @@ -327,6 +346,7 @@ glfw_init(PyObject UNUSED *self, PyObject *args) { PyObject* glfw_terminate(PyObject UNUSED *self) { glfwTerminate(); + load_libX11(true); Py_RETURN_NONE; } @@ -477,10 +497,38 @@ toggle_fullscreen(PyObject UNUSED *self) { } } +void +ring_audio_bell(OSWindow *w) { +#ifdef __APPLE__ + (void)w; + cocoa_audio_bell(); +#else + if (glfwGetX11Display) { + static bool tried = false; + if (!tried) { + tried = true; + void *lib = load_libX11(false); + if (lib) { + *(void **) (&xkb_bell) = dlsym(lib, "XkbBell"); + if (!xkb_bell) fprintf(stderr, "Failed to load the XkbBell function with error: %s\n", dlerror()); + } + } + if (xkb_bell) { + void* display = glfwGetX11Display(); + int32_t x11win = glfwGetX11Window(w->handle); + if (display) { + xkb_bell(display, x11win, OPT(x11_bell_volume), NULL); + } + } + } +#endif +} + void -request_window_attention(id_type kitty_window_id) { +request_window_attention(id_type kitty_window_id, bool audio_bell) { OSWindow *w = os_window_for_kitty_window(kitty_window_id); if (w) { + if (audio_bell) ring_audio_bell(w); glfwRequestWindowAttention(w->handle); glfwPostEmptyEvent(); } diff --git a/kitty/kitty.conf b/kitty/kitty.conf index 7cc81898a..d8e0d73d6 100644 --- a/kitty/kitty.conf +++ b/kitty/kitty.conf @@ -331,3 +331,7 @@ macos_hide_titlebar no # break any Alt+key keyboard shortcuts in your terminal programs, but you # can use the macOS unicode input technique. macos_option_as_alt yes + +# The number is a percentage of maximum volume. +# See man XBell for details. +x11_bell_volume 80 diff --git a/kitty/screen.c b/kitty/screen.c index 9bd7253e1..f1199c459 100644 --- a/kitty/screen.c +++ b/kitty/screen.c @@ -1009,22 +1009,7 @@ screen_invert_colors(Screen *self) { void screen_bell(Screen *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(); - } - request_window_attention(self->window_id); + request_window_attention(self->window_id, OPT(enable_audio_bell)); } void diff --git a/kitty/state.c b/kitty/state.c index 6655fab2f..500af4ec2 100644 --- a/kitty/state.c +++ b/kitty/state.c @@ -308,6 +308,7 @@ PYWRAP1(set_options) { S(cursor_blink_interval, PyFloat_AsDouble); S(cursor_stop_blinking_after, PyFloat_AsDouble); S(cursor_shape, PyLong_AsLong); + S(x11_bell_volume, PyLong_AsLong); S(mouse_hide_wait, PyFloat_AsDouble); S(wheel_scroll_multiplier, PyFloat_AsDouble); S(open_url_modifiers, PyLong_AsUnsignedLong); diff --git a/kitty/state.h b/kitty/state.h index 85fbe0c25..caa38fb03 100644 --- a/kitty/state.h +++ b/kitty/state.h @@ -21,6 +21,7 @@ typedef struct { bool focus_follows_mouse; bool macos_option_as_alt, macos_hide_titlebar; int adjust_line_height_px; + int x11_bell_volume; float adjust_line_height_frac; } Options;