diff --git a/kitty/boss.py b/kitty/boss.py index 2cbef3331..ec9dc8d9e 100644 --- a/kitty/boss.py +++ b/kitty/boss.py @@ -1010,3 +1010,10 @@ class Boss: if identifier == 'new-version': from .update_check import notification_activated notification_activated() + + def dbus_notification_callback(self, activated, *args): + from .notify import dbus_notification_created + if activated: + pass + else: + dbus_notification_created(*args) diff --git a/kitty/glfw.c b/kitty/glfw.c index 31a159466..12476c363 100644 --- a/kitty/glfw.c +++ b/kitty/glfw.c @@ -1027,6 +1027,28 @@ wayland_request_frame_render(OSWindow *w) { w->wayland_render_state = RENDER_FRAME_REQUESTED; } +#ifndef __APPLE__ + +void +dbus_notification_created_callback(unsigned long long notification_id, uint32_t new_notification_id, void* data UNUSED) { + unsigned long new_id = new_notification_id; + call_boss(dbus_notification_callback, "OKk", Py_False, notification_id, new_id); +} + +static PyObject* +dbus_send_notification(PyObject *self UNUSED, PyObject *args) { + char *app_name, *icon, *summary, *body; + int timeout = -1; + if (!PyArg_ParseTuple(args, "ssss|i", &app_name, &icon, &summary, &body, &timeout)) return NULL; + if (!glfwDBusUserNotify) { + PyErr_SetString(PyExc_RuntimeError, "Failed to load glfwDBusUserNotify, did you call glfw_init?"); + return NULL; + } + unsigned long long notification_id = glfwDBusUserNotify(app_name, icon, summary, body, timeout, dbus_notification_created_callback, NULL); + return PyLong_FromUnsignedLongLong(notification_id); +} +#endif + // Boilerplate {{{ static PyMethodDef module_methods[] = { @@ -1048,6 +1070,7 @@ static PyMethodDef module_methods[] = { METHODB(x11_window_id, METH_O), METHODB(set_primary_selection, METH_VARARGS), METHODB(glfw_poll_events, METH_NOARGS), + METHODB(dbus_send_notification, METH_VARARGS), {"glfw_init", (PyCFunction)glfw_init, METH_VARARGS, ""}, {"glfw_terminate", (PyCFunction)glfw_terminate, METH_NOARGS, ""}, {"glfw_post_empty_event", (PyCFunction)glfw_post_empty_event, METH_NOARGS, ""}, diff --git a/kitty/notify.py b/kitty/notify.py index 9122b5a0d..8850df640 100644 --- a/kitty/notify.py +++ b/kitty/notify.py @@ -2,7 +2,6 @@ # vim:fileencoding=utf-8 # License: GPLv3 Copyright: 2019, Kovid Goyal -import subprocess from .constants import is_macos, logo_png_file @@ -23,9 +22,15 @@ if is_macos: else: - # libnotify depends on GTK, so we are not using it, instead - # use the command line notify-send wrapper it provides - # May want to just implement this in glfw using DBUS + from .fast_data_types import dbus_send_notification + + alloc_map = {} + identifier_map = {} + + def dbus_notification_created(alloc_id, notification_id): + identifier = alloc_map.get(alloc_id) + if identifier is not None: + identifier_map[identifier] = notification_id def notify( title, @@ -35,16 +40,8 @@ else: icon=True, identifier=None ): - cmd = ['notify-send', '-a', application] - if timeout > -1: - cmd.append('-t'), cmd.append(str(timeout)) if icon is True: icon = logo_png_file - if icon: - cmd.extend(['-i', icon]) - subprocess.Popen( - cmd + [title, body], - stdout=subprocess.DEVNULL, - stderr=subprocess.DEVNULL, - stdin=subprocess.DEVNULL, - ) + alloc_id = dbus_send_notification(application, icon, title, body, timeout) + if alloc_id and identifier is not None: + alloc_map[alloc_id] = identifier