Update sound support in desktop notifications spec
Add a short list of standard sound names.
This commit is contained in:
parent
40d1781404
commit
2c743dcdb2
7 changed files with 53 additions and 18 deletions
|
|
@ -343,13 +343,25 @@ By default, notifications may or may not have a sound associated with them
|
|||
depending on the policies of the OS notifications service. Sometimes it
|
||||
might be useful to ensure a notification is not accompanied by a sound.
|
||||
This can be done by using the ``s`` key which accepts :ref:`base64` encoded
|
||||
UTF-8 text as its value. Using a value of ``silent`` means the notification
|
||||
will not be accompanied with a sound. A value of ``system`` (the default)
|
||||
means that the OS notifications default policies are followed. Any other name
|
||||
is implementation dependent. For example, on Linux, one can use the `standard
|
||||
sound names
|
||||
<https://specifications.freedesktop.org/sound-naming-spec/latest/#names>`__.
|
||||
Support for sounds can be queried as described below.
|
||||
UTF-8 text as its value. The set of known sounds names is in the table below,
|
||||
any other names are implementation dependent, for instance, on Linux, terminal emulators will
|
||||
probably support the `standard sound names
|
||||
<https://specifications.freedesktop.org/sound-naming-spec/latest/#names>`__
|
||||
|
||||
.. table:: Standard sound names
|
||||
|
||||
======================== ==============================================
|
||||
Name Description
|
||||
======================== ==============================================
|
||||
``system`` The default system sound for a notification, which may be some kind of beep or just silence
|
||||
``silent`` No sound must accompany the notification
|
||||
``error`` A sound associated with error messages
|
||||
``warn``, ``warning`` A sound associated with warning messages
|
||||
``info`` A sound associated with information messages
|
||||
``question`` A sound associated with questions
|
||||
======================== ==============================================
|
||||
|
||||
Support for sound names can be queried as described below.
|
||||
|
||||
|
||||
Querying for support
|
||||
|
|
@ -391,11 +403,9 @@ Key Value
|
|||
``p`` key that the terminal implements). These must contain at least
|
||||
``title``.
|
||||
|
||||
``s`` Comma separated list of keywords ``silent`` and ``xdg-names`` indicating
|
||||
support for silent notifications and for passing of `Freedesktop
|
||||
standard sound names
|
||||
<https://specifications.freedesktop.org/sound-naming-spec/latest/#names>`__ to the
|
||||
desktop notification service for custom sounds.
|
||||
``s`` Comma separated list of sound names from the table of standard sound names above.
|
||||
Terminals will report the list of standard sound names they support.
|
||||
Terminals *should* support atleast ``system`` and ``silent``.
|
||||
|
||||
``u`` Comma separated list of urgency values that the terminal implements.
|
||||
If urgency is not supported, the ``u`` key must be absent from the
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@
|
|||
#include <Carbon/Carbon.h>
|
||||
#include <Cocoa/Cocoa.h>
|
||||
#include <UserNotifications/UserNotifications.h>
|
||||
#import <AudioToolbox/AudioServices.h>
|
||||
|
||||
#include <AvailabilityMacros.h>
|
||||
// Needed for _NSGetProgname
|
||||
|
|
@ -1185,7 +1186,15 @@ - (BOOL)openFileURLs:(NSPasteboard*)pasteboard
|
|||
return convert_image_to_png(icon, image_size, output_path);
|
||||
}}
|
||||
|
||||
static PyObject*
|
||||
play_system_sound_by_id_async(PyObject *self UNUSED, PyObject *which) {
|
||||
if (!PyLong_Check(which)) { PyErr_SetString(PyExc_TypeError, "system sound id must be an integer"); return NULL; }
|
||||
AudioServicesPlaySystemSound(PyLong_AsUnsignedLong(which));
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
static PyMethodDef module_methods[] = {
|
||||
{"cocoa_play_system_sound_by_id_async", play_system_sound_by_id_async, METH_O, ""},
|
||||
{"cocoa_get_lang", (PyCFunction)cocoa_get_lang, METH_NOARGS, ""},
|
||||
{"cocoa_set_global_shortcut", (PyCFunction)cocoa_set_global_shortcut, METH_VARARGS, ""},
|
||||
{"cocoa_send_notification", (PyCFunction)(void(*)(void))cocoa_send_notification, METH_VARARGS | METH_KEYWORDS, ""},
|
||||
|
|
|
|||
|
|
@ -204,6 +204,16 @@ def wakeup_io_loop() -> None:
|
|||
'text-editor': ('utilities-text-editor', '📄'),
|
||||
}
|
||||
|
||||
# See https://github.com/TUNER88/iOSSystemSoundsLibrary for Apple's system
|
||||
# sound ids not all of which are available on macOS.
|
||||
standard_sound_names = {
|
||||
'error': ('dialog-error', 1),
|
||||
'info': ('dialog-information', 2),
|
||||
'warning': ('dialog-warning', 3),
|
||||
'warn': ('dialog-warning', 3),
|
||||
'question': ('dialog-question', 4),
|
||||
}
|
||||
|
||||
|
||||
def glfw_path(module: str) -> str:
|
||||
prefix = 'kitty.' if getattr(sys, 'frozen', False) else ''
|
||||
|
|
|
|||
|
|
@ -1702,6 +1702,7 @@ def timed_debug_print(x: str) -> None: ...
|
|||
def opengl_version_string() -> str: ...
|
||||
def systemd_move_pid_into_new_scope(pid: int, scope_name: str, description: str) -> str: ...
|
||||
def play_desktop_sound_async(name: str, event_id: str = 'test sound', is_path: bool = False, theme_name: str = '') -> str: ...
|
||||
def cocoa_play_system_sound_by_id_async(sound_id: int) -> None: ...
|
||||
|
||||
class MousePosition(TypedDict):
|
||||
cell_x: int
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@
|
|||
from typing import Any, Callable, NamedTuple, Optional, Set, Union
|
||||
from weakref import ReferenceType, ref
|
||||
|
||||
from .constants import cache_dir, config_dir, is_macos, logo_png_file, standard_icon_names
|
||||
from .constants import cache_dir, config_dir, is_macos, logo_png_file, standard_icon_names, standard_sound_names
|
||||
from .fast_data_types import ESC_OSC, StreamingBase64Decoder, add_timer, base64_decode, current_focused_os_window_id, get_boss, get_options
|
||||
from .types import run_once
|
||||
from .typing import WindowType
|
||||
|
|
@ -486,7 +486,7 @@ def query_response(self, identifier: str) -> str:
|
|||
i = f'i={identifier or "0"}:'
|
||||
p = ','.join(x.value for x in PayloadType if x.value and self.payload_type_supported(x))
|
||||
c = ':c=1' if self.supports_close_events else ''
|
||||
s = 'silent' + (f',{self.supports_sound_names}' if self.supports_sound_names else '')
|
||||
s = 'system,silent,' + ','.join(sorted(standard_sound_names))
|
||||
return f'99;{i}p=?;a={actions}:o={when}:u={urgency}:p={p}{c}:w=1:s={s}'
|
||||
|
||||
|
||||
|
|
@ -596,7 +596,7 @@ def notify(self, nc: NotificationCommand, existing_desktop_notification_id: Opti
|
|||
cocoa_send_notification(
|
||||
nc.application_name or 'kitty', str(desktop_notification_id), nc.title, body,
|
||||
category=category, categories=categories, image_path=image_path, urgency=nc.urgency.value,
|
||||
muted=nc.sound_name == 'silent',
|
||||
muted=nc.sound_name == 'silent' or nc.sound_name in standard_sound_names,
|
||||
)
|
||||
return desktop_notification_id
|
||||
|
||||
|
|
@ -616,9 +616,12 @@ def notification_activated(self, event: str, ident: str, button_id: str) -> None
|
|||
log_error(f'Got unexpected notification activated event with id: {ident!r} from cocoa')
|
||||
return
|
||||
if event == 'created':
|
||||
self.notification_manager.notification_created(desktop_notification_id)
|
||||
n = self.notification_manager.notification_created(desktop_notification_id)
|
||||
from .fast_data_types import cocoa_live_delivered_notifications
|
||||
cocoa_live_delivered_notifications() # so that we purge dead notifications
|
||||
if n and n.sound_name in standard_sound_names:
|
||||
from .fast_data_types import cocoa_play_system_sound_by_id_async
|
||||
cocoa_play_system_sound_by_id_async(standard_sound_names[n.sound_name][1])
|
||||
elif event == 'activated':
|
||||
self.notification_manager.notification_activated(desktop_notification_id, 0)
|
||||
elif event == 'creation_failed':
|
||||
|
|
@ -690,8 +693,9 @@ def created(self, dbus_notification_id: int, desktop_notification_id: int) -> No
|
|||
# supports named sounds or not so we play the named sound
|
||||
# ourselves and tell the server to mute any sound it might play.
|
||||
if n.sound_name not in ('system', 'silent'):
|
||||
sn = standard_sound_names[n.sound_name][0] if n.sound_name in standard_sound_names else n.sound_name
|
||||
from .fast_data_types import play_desktop_sound_async
|
||||
play_desktop_sound_async(n.sound_name, event_id='desktop notification')
|
||||
play_desktop_sound_async(sn, event_id='desktop notification')
|
||||
|
||||
def dispatch_event_from_desktop(self, event_type: str, dbus_notification_id: int, extra: Union[int, str]) -> None:
|
||||
if event_type == 'capabilities':
|
||||
|
|
|
|||
|
|
@ -249,7 +249,7 @@ def enc(x):
|
|||
# Test querying
|
||||
h('i=xyz:p=?')
|
||||
self.assertFalse(di.notifications)
|
||||
qr = 'a=focus,report:o=always,unfocused,invisible:u=0,1,2:p=title,body,?,close,icon,alive,buttons:c=1:w=1:s=silent,xdg-names'
|
||||
qr = 'a=focus,report:o=always,unfocused,invisible:u=0,1,2:p=title,body,?,close,icon,alive,buttons:c=1:w=1:s=system,silent,error,info,question,warn,warning'
|
||||
self.ae(ch.responses, [f'99;i=xyz:p=?;{qr}'])
|
||||
reset()
|
||||
h('p=?')
|
||||
|
|
|
|||
1
setup.py
1
setup.py
|
|
@ -618,6 +618,7 @@ def kitty_env(args: Options) -> Env:
|
|||
if is_macos:
|
||||
platform_libs = [
|
||||
'-framework', 'Carbon', '-framework', 'CoreText', '-framework', 'CoreGraphics',
|
||||
'-framework', 'AudioToolbox',
|
||||
]
|
||||
test_program_src = '''#include <UserNotifications/UserNotifications.h>
|
||||
int main(void) { return 0; }\n'''
|
||||
|
|
|
|||
Loading…
Reference in a new issue