A new option to specify the path to a sound file to use as the bell sound

This commit is contained in:
Kovid Goyal 2021-09-24 07:55:38 +05:30
parent bbdfdb978d
commit c2641458e7
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
10 changed files with 65 additions and 15 deletions

View File

@ -22,6 +22,9 @@ To update |kitty|, :doc:`follow the instructions <binary>`.
the request by default instead of denying by default. See the request by default instead of denying by default. See
:opt:`clipboard_control` for details (:iss:`4022`) :opt:`clipboard_control` for details (:iss:`4022`)
- A new option :opt:`bell_path` to specify the path to a sound file
to use as the bell sound
- Fix a regression that caused :option:`kitty --title` to not work when - Fix a regression that caused :option:`kitty --title` to not work when
opening new OS windows using :option:`kitty --single-instance` (:iss:`3893`) opening new OS windows using :option:`kitty --single-instance` (:iss:`3893`)

View File

@ -633,12 +633,16 @@ cocoa_set_titlebar_color(void *w, color_type titlebar_color)
} // autoreleasepool } // autoreleasepool
} }
static NSSound *beep_sound = nil;
static void static void
cleanup() { cleanup() {
@autoreleasepool { @autoreleasepool {
if (dockMenu) [dockMenu release]; if (dockMenu) [dockMenu release];
dockMenu = nil; dockMenu = nil;
if (beep_sound) [beep_sound release];
beep_sound = nil;
#ifndef KITTY_USE_DEPRECATED_MACOS_NOTIFICATION_API #ifndef KITTY_USE_DEPRECATED_MACOS_NOTIFICATION_API
drain_pending_notifications(NO); drain_pending_notifications(NO);
@ -662,8 +666,15 @@ cocoa_hide_window_title(void *w)
} }
void void
cocoa_system_beep(void) { cocoa_system_beep(const char *path) {
NSBeep(); if (!path) { NSBeep(); return; }
static const char *beep_path = NULL;
if (beep_path != path) {
if (beep_sound) [beep_sound release];
beep_sound = [[NSSound alloc] initWithContentsOfFile:@(path) byReference:YES];
}
if (beep_sound) [beep_sound play];
else NSBeep();
} }
static PyMethodDef module_methods[] = { static PyMethodDef module_methods[] = {

View File

@ -19,7 +19,7 @@ extern void cocoa_focus_window(void *w);
extern long cocoa_window_number(void *w); extern long cocoa_window_number(void *w);
extern void cocoa_create_global_menu(void); extern void cocoa_create_global_menu(void);
extern void cocoa_hide_window_title(void *w); extern void cocoa_hide_window_title(void *w);
extern void cocoa_system_beep(void); extern void cocoa_system_beep(const char*);
extern void cocoa_set_activation_policy(bool); extern void cocoa_set_activation_policy(bool);
extern void cocoa_set_titlebar_color(void *w, color_type color); extern void cocoa_set_titlebar_color(void *w, color_type color);
extern bool cocoa_alt_option_key_pressed(unsigned long); extern bool cocoa_alt_option_key_pressed(unsigned long);
@ -1115,9 +1115,10 @@ ring_audio_bell(void) {
if (last_bell_at >= 0 && now - last_bell_at <= ms_to_monotonic_t(100ll)) return; if (last_bell_at >= 0 && now - last_bell_at <= ms_to_monotonic_t(100ll)) return;
last_bell_at = now; last_bell_at = now;
#ifdef __APPLE__ #ifdef __APPLE__
cocoa_system_beep(); cocoa_system_beep(OPT(bell_path));
#else #else
play_canberra_sound("bell", "kitty bell", false); if (OPT(bell_path)) play_canberra_sound(OPT(bell_path), "kitty bell", true);
else play_canberra_sound("bell", "kitty bell", false);
#endif #endif
} }

View File

@ -681,6 +681,13 @@ opt('command_on_bell', 'none',
' The environment variable :envvar:`KITTY_CHILD_CMDLINE` can be used to get the program running in' ' The environment variable :envvar:`KITTY_CHILD_CMDLINE` can be used to get the program running in'
' the window in which the bell occurred.' ' the window in which the bell occurred.'
) )
opt('bell_path', 'none',
option_type='config_or_absolute_path', ctype='!bell_path',
long_text='Path to a sound file to play as the bell sound. Must be in a format supported by the'
' operating systems sound API, such as WAV or OGA on Linux (libcanberra) or AIFF, MP3 or WAV on macOS (NSSound)'
)
egr() # }}} egr() # }}}
# window {{{ # window {{{

View File

@ -81,6 +81,9 @@ class Parser:
def bell_on_tab(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: def bell_on_tab(self, val: str, ans: typing.Dict[str, typing.Any]) -> None:
ans['bell_on_tab'] = to_bool(val) ans['bell_on_tab'] = to_bool(val)
def bell_path(self, val: str, ans: typing.Dict[str, typing.Any]) -> None:
ans['bell_path'] = config_or_absolute_path(val)
def bold_font(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: def bold_font(self, val: str, ans: typing.Dict[str, typing.Any]) -> None:
ans['bold_font'] = str(val) ans['bold_font'] = str(val)

View File

@ -434,6 +434,19 @@ convert_from_opts_window_alert_on_bell(PyObject *py_opts, Options *opts) {
Py_DECREF(ret); Py_DECREF(ret);
} }
static void
convert_from_python_bell_path(PyObject *val, Options *opts) {
bell_path(val, opts);
}
static void
convert_from_opts_bell_path(PyObject *py_opts, Options *opts) {
PyObject *ret = PyObject_GetAttrString(py_opts, "bell_path");
if (ret == NULL) return;
convert_from_python_bell_path(ret, opts);
Py_DECREF(ret);
}
static void static void
convert_from_python_active_border_color(PyObject *val, Options *opts) { convert_from_python_active_border_color(PyObject *val, Options *opts) {
opts->active_border_color = active_border_color(val); opts->active_border_color = active_border_color(val);
@ -983,6 +996,8 @@ convert_opts_from_python_opts(PyObject *py_opts, Options *opts) {
if (PyErr_Occurred()) return false; if (PyErr_Occurred()) return false;
convert_from_opts_window_alert_on_bell(py_opts, opts); convert_from_opts_window_alert_on_bell(py_opts, opts);
if (PyErr_Occurred()) return false; if (PyErr_Occurred()) return false;
convert_from_opts_bell_path(py_opts, opts);
if (PyErr_Occurred()) return false;
convert_from_opts_active_border_color(py_opts, opts); convert_from_opts_active_border_color(py_opts, opts);
if (PyErr_Occurred()) return false; if (PyErr_Occurred()) return false;
convert_from_opts_inactive_border_color(py_opts, opts); convert_from_opts_inactive_border_color(py_opts, opts);

View File

@ -78,17 +78,22 @@ bglayout(PyObject *layout_name) {
return TILING; return TILING;
} }
static void #define STR_SETTER(name) { \
background_image(PyObject *src, Options *opts) { free(opts->name); opts->name = NULL; \
if (opts->background_image) free(opts->background_image); if (src == Py_None || !PyUnicode_Check(src)) return; \
opts->background_image = NULL; Py_ssize_t sz; \
if (src == Py_None || !PyUnicode_Check(src)) return; const char *s = PyUnicode_AsUTF8AndSize(src, &sz); \
Py_ssize_t sz; opts->name = calloc(sz + 1, 1); \
const char *s = PyUnicode_AsUTF8AndSize(src, &sz); if (opts->name) memcpy(opts->name, s, sz); \
opts->background_image = calloc(sz + 1, 1);
if (opts->background_image) memcpy(opts->background_image, s, sz);
} }
static void
background_image(PyObject *src, Options *opts) { STR_SETTER(background_image); }
static void
bell_path(PyObject *src, Options *opts) { STR_SETTER(bell_path); }
#undef STR_SETTER
static MouseShape static MouseShape
pointer_shape(PyObject *shape_name) { pointer_shape(PyObject *shape_name) {

View File

@ -60,6 +60,7 @@ option_names = ( # {{{
'background_tint', 'background_tint',
'bell_border_color', 'bell_border_color',
'bell_on_tab', 'bell_on_tab',
'bell_path',
'bold_font', 'bold_font',
'bold_italic_font', 'bold_italic_font',
'box_drawing_scale', 'box_drawing_scale',
@ -457,6 +458,7 @@ class Options:
background_tint: float = 0 background_tint: float = 0
bell_border_color: Color = Color(red=255, green=90, blue=0) bell_border_color: Color = Color(red=255, green=90, blue=0)
bell_on_tab: bool = True bell_on_tab: bool = True
bell_path: typing.Optional[str] = None
bold_font: str = 'auto' bold_font: str = 'auto'
bold_italic_font: str = 'auto' bold_italic_font: str = 'auto'
box_drawing_scale: typing.Tuple[float, float, float, float] = (0.001, 1.0, 1.5, 2.0) box_drawing_scale: typing.Tuple[float, float, float, float] = (0.001, 1.0, 1.5, 2.0)

View File

@ -1135,7 +1135,9 @@ finalize(void) {
} }
if (detached_windows.windows) free(detached_windows.windows); if (detached_windows.windows) free(detached_windows.windows);
detached_windows.capacity = 0; detached_windows.capacity = 0;
if (OPT(background_image)) free(OPT(background_image)); #define F(x) free(OPT(x)); OPT(x) = NULL;
F(background_image); F(bell_path);
#undef F
// we leak the texture here since it is not guaranteed // we leak the texture here since it is not guaranteed
// that freeing the texture will work during shutdown and // that freeing the texture will work during shutdown and
// the GPU driver should take care of it when the OpenGL context is // the GPU driver should take care of it when the OpenGL context is

View File

@ -40,6 +40,7 @@ typedef struct {
unsigned int macos_option_as_alt; unsigned int macos_option_as_alt;
float macos_thicken_font; float macos_thicken_font;
WindowTitleIn macos_show_window_title_in; WindowTitleIn macos_show_window_title_in;
char *bell_path;
int adjust_line_height_px, adjust_column_width_px, adjust_baseline_px; int adjust_line_height_px, adjust_column_width_px, adjust_baseline_px;
float adjust_line_height_frac, adjust_column_width_frac, adjust_baseline_frac; float adjust_line_height_frac, adjust_column_width_frac, adjust_baseline_frac;
float background_opacity, dim_opacity; float background_opacity, dim_opacity;