Support setting urgency for DBUS notifications
This commit is contained in:
@@ -328,7 +328,7 @@ def generate_wrappers(glfw_header: str) -> None:
|
||||
void glfwWaylandSetupLayerShellForNextWindow(GLFWLayerShellConfig c)
|
||||
pid_t glfwWaylandCompositorPID(void)
|
||||
unsigned long long glfwDBusUserNotify(const char *app_name, const char* icon, const char *summary, const char *body, \
|
||||
const char *action_text, int32_t timeout, GLFWDBusnotificationcreatedfun callback, void *data)
|
||||
const char *action_text, int32_t timeout, int urgency, GLFWDBusnotificationcreatedfun callback, void *data)
|
||||
void glfwDBusSetUserNotificationHandler(GLFWDBusnotificationactivatedfun handler)
|
||||
int glfwSetX11LaunchCommand(GLFWwindow *handle, char **argv, int argc)
|
||||
void glfwSetX11WindowAsDock(int32_t x11_window_id)
|
||||
|
||||
58
glfw/linux_notify.c
vendored
58
glfw/linux_notify.c
vendored
@@ -13,6 +13,11 @@
|
||||
#define NOTIFICATIONS_PATH "/org/freedesktop/Notifications"
|
||||
#define NOTIFICATIONS_IFACE "org.freedesktop.Notifications"
|
||||
|
||||
static inline void cleanup_free(void *p) { free(*(void**)p); }
|
||||
#define RAII_ALLOC(type, name, initializer) __attribute__((cleanup(cleanup_free))) type *name = initializer
|
||||
static inline void cleanup_msg(void *p) { dbus_message_unref(*(DBusMessage**)p); *(DBusMessage**)p = NULL; }
|
||||
#define RAII_MSG(name, initializer) __attribute__((cleanup(cleanup_msg))) DBusMessage *name = initializer
|
||||
|
||||
static notification_id_type notification_id = 0;
|
||||
|
||||
typedef struct {
|
||||
@@ -61,7 +66,7 @@ message_handler(DBusConnection *conn UNUSED, DBusMessage *msg, void *user_data U
|
||||
}
|
||||
|
||||
notification_id_type
|
||||
glfw_dbus_send_user_notification(const char *app_name, const char* icon, const char *summary, const char *body, const char* action_name, int32_t timeout, GLFWDBusnotificationcreatedfun callback, void *user_data) {
|
||||
glfw_dbus_send_user_notification(const char *app_name, const char* icon, const char *summary, const char *body, const char* action_name, int32_t timeout, int urgency, GLFWDBusnotificationcreatedfun callback, void *user_data) {
|
||||
DBusConnection *session_bus = glfw_dbus_session_bus();
|
||||
static DBusConnection *added_signal_match = NULL;
|
||||
if (!session_bus) return 0;
|
||||
@@ -70,36 +75,47 @@ glfw_dbus_send_user_notification(const char *app_name, const char* icon, const c
|
||||
dbus_connection_add_filter(session_bus, message_handler, NULL, NULL);
|
||||
added_signal_match = session_bus;
|
||||
}
|
||||
NotificationCreatedData *data = malloc(sizeof(NotificationCreatedData));
|
||||
RAII_ALLOC(NotificationCreatedData, data, malloc(sizeof(NotificationCreatedData)));
|
||||
if (!data) return 0;
|
||||
data->next_id = ++notification_id;
|
||||
data->callback = callback; data->data = user_data;
|
||||
if (!data->next_id) data->next_id = ++notification_id;
|
||||
uint32_t replaces_id = 0;
|
||||
|
||||
DBusMessage *msg = dbus_message_new_method_call(NOTIFICATIONS_SERVICE, NOTIFICATIONS_PATH, NOTIFICATIONS_IFACE, "Notify");
|
||||
if (!msg) { free(data); return 0; }
|
||||
DBusMessageIter args, array;
|
||||
RAII_MSG(msg, dbus_message_new_method_call(NOTIFICATIONS_SERVICE, NOTIFICATIONS_PATH, NOTIFICATIONS_IFACE, "Notify"));
|
||||
if (!msg) { return 0; }
|
||||
DBusMessageIter args, array, variant, dict;
|
||||
dbus_message_iter_init_append(msg, &args);
|
||||
#define OOMMSG { free(data); data = NULL; dbus_message_unref(msg); _glfwInputError(GLFW_PLATFORM_ERROR, "%s", "Out of memory allocating DBUS message for notification\n"); return 0; }
|
||||
#define APPEND(type, val) { if (!dbus_message_iter_append_basic(&args, type, val)) OOMMSG }
|
||||
APPEND(DBUS_TYPE_STRING, &app_name)
|
||||
APPEND(DBUS_TYPE_UINT32, &replaces_id)
|
||||
APPEND(DBUS_TYPE_STRING, &icon)
|
||||
APPEND(DBUS_TYPE_STRING, &summary)
|
||||
APPEND(DBUS_TYPE_STRING, &body)
|
||||
if (!dbus_message_iter_open_container(&args, DBUS_TYPE_ARRAY, "s", &array)) OOMMSG;
|
||||
#define check_call(func, ...) if (!func(__VA_ARGS__)) { _glfwInputError(GLFW_PLATFORM_ERROR, "%s", "Out of memory allocating DBUS message for notification\n"); return 0; }
|
||||
#define APPEND(to, type, val) check_call(dbus_message_iter_append_basic, &to, type, &val);
|
||||
APPEND(args, DBUS_TYPE_STRING, app_name)
|
||||
APPEND(args, DBUS_TYPE_UINT32, replaces_id)
|
||||
APPEND(args, DBUS_TYPE_STRING, icon)
|
||||
APPEND(args, DBUS_TYPE_STRING, summary)
|
||||
APPEND(args, DBUS_TYPE_STRING, body)
|
||||
check_call(dbus_message_iter_open_container, &args, DBUS_TYPE_ARRAY, "s", &array);
|
||||
if (action_name) {
|
||||
static const char* default_action = "default";
|
||||
dbus_message_iter_append_basic(&array, DBUS_TYPE_STRING, &default_action);
|
||||
dbus_message_iter_append_basic(&array, DBUS_TYPE_STRING, &action_name);
|
||||
APPEND(array, DBUS_TYPE_STRING, default_action);
|
||||
APPEND(array, DBUS_TYPE_STRING, action_name);
|
||||
}
|
||||
if (!dbus_message_iter_close_container(&args, &array)) OOMMSG;
|
||||
if (!dbus_message_iter_open_container(&args, DBUS_TYPE_ARRAY, "{sv}", &array)) OOMMSG;
|
||||
if (!dbus_message_iter_close_container(&args, &array)) OOMMSG;
|
||||
APPEND(DBUS_TYPE_INT32, &timeout)
|
||||
#undef OOMMSG
|
||||
check_call(dbus_message_iter_close_container, &args, &array);
|
||||
check_call(dbus_message_iter_open_container, &args, DBUS_TYPE_ARRAY, "{sv}", &array);
|
||||
|
||||
check_call(dbus_message_iter_open_container, &array, DBUS_TYPE_DICT_ENTRY, NULL, &dict);
|
||||
static const char* urgency_key = "urgency";
|
||||
APPEND(dict, DBUS_TYPE_STRING, urgency_key);
|
||||
check_call(dbus_message_iter_open_container, &dict, DBUS_TYPE_VARIANT, DBUS_TYPE_BYTE_AS_STRING, &variant);
|
||||
uint8_t urgencyb = urgency & 3;
|
||||
APPEND(variant, DBUS_TYPE_BYTE, urgencyb);
|
||||
check_call(dbus_message_iter_close_container, &dict, &variant);
|
||||
check_call(dbus_message_iter_close_container, &array, &dict);
|
||||
check_call(dbus_message_iter_close_container, &args, &array);
|
||||
APPEND(args, DBUS_TYPE_INT32, timeout)
|
||||
#undef check_call
|
||||
#undef APPEND
|
||||
if (!call_method_with_msg(session_bus, msg, 5000, notification_created, data)) return 0;
|
||||
return data->next_id;
|
||||
notification_id_type ans = data->next_id;
|
||||
data = NULL;
|
||||
return ans;
|
||||
}
|
||||
|
||||
2
glfw/linux_notify.h
vendored
2
glfw/linux_notify.h
vendored
@@ -14,6 +14,6 @@ typedef unsigned long long notification_id_type;
|
||||
typedef void (*GLFWDBusnotificationcreatedfun)(notification_id_type, uint32_t, void*);
|
||||
typedef void (*GLFWDBusnotificationactivatedfun)(uint32_t, const char*);
|
||||
notification_id_type
|
||||
glfw_dbus_send_user_notification(const char *app_name, const char* icon, const char *summary, const char *body, const char *action_name, int32_t timeout, GLFWDBusnotificationcreatedfun, void*);
|
||||
glfw_dbus_send_user_notification(const char *app_name, const char* icon, const char *summary, const char *body, const char *action_name, int32_t timeout, int urgency, GLFWDBusnotificationcreatedfun, void*);
|
||||
void
|
||||
glfw_dbus_set_user_notification_activated_handler(GLFWDBusnotificationactivatedfun handler);
|
||||
|
||||
4
glfw/wl_window.c
vendored
4
glfw/wl_window.c
vendored
@@ -2722,8 +2722,8 @@ GLFWAPI void glfwRequestWaylandFrameEvent(GLFWwindow *handle, unsigned long long
|
||||
}
|
||||
}
|
||||
|
||||
GLFWAPI unsigned long long glfwDBusUserNotify(const char *app_name, const char* icon, const char *summary, const char *body, const char *action_name, int32_t timeout, GLFWDBusnotificationcreatedfun callback, void *data) {
|
||||
return glfw_dbus_send_user_notification(app_name, icon, summary, body, action_name, timeout, callback, data);
|
||||
GLFWAPI unsigned long long glfwDBusUserNotify(const char *app_name, const char* icon, const char *summary, const char *body, const char *action_name, int32_t timeout, int urgency, GLFWDBusnotificationcreatedfun callback, void *data) {
|
||||
return glfw_dbus_send_user_notification(app_name, icon, summary, body, action_name, timeout, urgency, callback, data);
|
||||
}
|
||||
|
||||
GLFWAPI void glfwDBusSetUserNotificationHandler(GLFWDBusnotificationactivatedfun handler) {
|
||||
|
||||
4
glfw/x11_window.c
vendored
4
glfw/x11_window.c
vendored
@@ -3253,8 +3253,8 @@ GLFWAPI int glfwGetNativeKeyForName(const char* keyName, bool caseSensitive) {
|
||||
return glfw_xkb_keysym_from_name(keyName, caseSensitive);
|
||||
}
|
||||
|
||||
GLFWAPI unsigned long long glfwDBusUserNotify(const char *app_name, const char* icon, const char *summary, const char *body, const char *action_name, int32_t timeout, GLFWDBusnotificationcreatedfun callback, void *data) {
|
||||
return glfw_dbus_send_user_notification(app_name, icon, summary, body, action_name, timeout, callback, data);
|
||||
GLFWAPI unsigned long long glfwDBusUserNotify(const char *app_name, const char* icon, const char *summary, const char *body, const char *action_name, int32_t timeout, int urgency,GLFWDBusnotificationcreatedfun callback, void *data) {
|
||||
return glfw_dbus_send_user_notification(app_name, icon, summary, body, action_name, timeout, urgency, callback, data);
|
||||
}
|
||||
|
||||
GLFWAPI void glfwDBusSetUserNotificationHandler(GLFWDBusnotificationactivatedfun handler) {
|
||||
|
||||
@@ -493,7 +493,8 @@ def dbus_send_notification(
|
||||
summary: str,
|
||||
body: str,
|
||||
action_name: str,
|
||||
timeout: int = -1
|
||||
timeout: int = -1,
|
||||
urgency: int = 1,
|
||||
) -> int:
|
||||
pass
|
||||
|
||||
|
||||
2
kitty/glfw-wrapper.h
generated
2
kitty/glfw-wrapper.h
generated
@@ -2328,7 +2328,7 @@ typedef pid_t (*glfwWaylandCompositorPID_func)(void);
|
||||
GFW_EXTERN glfwWaylandCompositorPID_func glfwWaylandCompositorPID_impl;
|
||||
#define glfwWaylandCompositorPID glfwWaylandCompositorPID_impl
|
||||
|
||||
typedef unsigned long long (*glfwDBusUserNotify_func)(const char*, const char*, const char*, const char*, const char*, int32_t, GLFWDBusnotificationcreatedfun, void*);
|
||||
typedef unsigned long long (*glfwDBusUserNotify_func)(const char*, const char*, const char*, const char*, const char*, int32_t, int, GLFWDBusnotificationcreatedfun, void*);
|
||||
GFW_EXTERN glfwDBusUserNotify_func glfwDBusUserNotify_impl;
|
||||
#define glfwDBusUserNotify glfwDBusUserNotify_impl
|
||||
|
||||
|
||||
@@ -2064,13 +2064,13 @@ dbus_notification_created_callback(unsigned long long notification_id, uint32_t
|
||||
static PyObject*
|
||||
dbus_send_notification(PyObject *self UNUSED, PyObject *args) {
|
||||
char *app_name, *icon, *summary, *body, *action_name;
|
||||
int timeout = -1;
|
||||
if (!PyArg_ParseTuple(args, "sssss|i", &app_name, &icon, &summary, &body, &action_name, &timeout)) return NULL;
|
||||
int timeout = -1, urgency = 1;
|
||||
if (!PyArg_ParseTuple(args, "sssss|ii", &app_name, &icon, &summary, &body, &action_name, &timeout, &urgency)) 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, action_name, timeout, dbus_notification_created_callback, NULL);
|
||||
unsigned long long notification_id = glfwDBusUserNotify(app_name, icon, summary, body, action_name, timeout, urgency, dbus_notification_created_callback, NULL);
|
||||
return PyLong_FromUnsignedLongLong(notification_id);
|
||||
}
|
||||
|
||||
|
||||
@@ -14,7 +14,12 @@ from .fast_data_types import current_focused_os_window_id, get_boss
|
||||
from .types import run_once
|
||||
from .utils import get_custom_window_icon, log_error
|
||||
|
||||
NotifyImplementation = Callable[[str, str, str], None]
|
||||
|
||||
class Urgency(Enum):
|
||||
Low: int = 0
|
||||
Normal: int = 1
|
||||
Critical: int = 2
|
||||
|
||||
|
||||
if is_macos:
|
||||
from .fast_data_types import cocoa_send_notification
|
||||
@@ -27,6 +32,7 @@ if is_macos:
|
||||
icon: bool = True,
|
||||
identifier: Optional[str] = None,
|
||||
subtitle: Optional[str] = None,
|
||||
urgency: Urgency = Urgency.Normal,
|
||||
) -> None:
|
||||
cocoa_send_notification(identifier, title, body, subtitle)
|
||||
|
||||
@@ -56,17 +62,20 @@ else:
|
||||
icon: bool = True,
|
||||
identifier: Optional[str] = None,
|
||||
subtitle: Optional[str] = None,
|
||||
urgency: Urgency = Urgency.Normal,
|
||||
) -> None:
|
||||
icf = ''
|
||||
if icon is True:
|
||||
icf = get_custom_window_icon()[1] or logo_png_file
|
||||
alloc_id = dbus_send_notification(application, icf, title, body, 'Click to see changes', timeout)
|
||||
alloc_id = dbus_send_notification(application, icf, title, body, 'Click to see changes', timeout, urgency.value)
|
||||
if alloc_id and identifier is not None:
|
||||
alloc_map[alloc_id] = identifier
|
||||
|
||||
class NotifyImplementation:
|
||||
def __call__(self, title: str, body: str, identifier: str, urgency: Urgency = Urgency.Normal) -> None:
|
||||
notify(title, body, identifier=identifier, urgency=urgency)
|
||||
|
||||
def notify_implementation(title: str, body: str, identifier: str) -> None:
|
||||
notify(title, body, identifier=identifier)
|
||||
notify_implementation = NotifyImplementation()
|
||||
|
||||
|
||||
class OnlyWhen(Enum):
|
||||
|
||||
@@ -90,7 +90,9 @@ from .fast_data_types import (
|
||||
from .keys import keyboard_mode_name, mod_mask
|
||||
from .notify import (
|
||||
NotificationCommand,
|
||||
NotifyImplementation,
|
||||
OnlyWhen,
|
||||
Urgency,
|
||||
handle_notification_cmd,
|
||||
notify_with_command,
|
||||
sanitize_identifier_pat,
|
||||
@@ -1430,13 +1432,21 @@ class Window:
|
||||
if action == 'notify':
|
||||
notify_with_command(cmd, self.id)
|
||||
elif action == 'bell':
|
||||
def bell(title: str, body: str, identifier: str) -> None:
|
||||
self.screen.bell()
|
||||
notify_with_command(cmd, self.id, notify_implementation=bell)
|
||||
class Bell(NotifyImplementation):
|
||||
def __init__(self, window_id: int):
|
||||
self.window_id = window_id
|
||||
def __call__(self, title: str, body: str, identifier: str, urgency: Urgency = Urgency.Normal) -> None:
|
||||
w = get_boss().window_id_map.get(self.window_id)
|
||||
if w:
|
||||
w.screen.bell()
|
||||
notify_with_command(cmd, self.id, notify_implementation=Bell(self.id))
|
||||
elif action == 'command':
|
||||
def run_command(title: str, body: str, identifier: str) -> None:
|
||||
open_cmd([x.replace('%c', self.last_cmd_cmdline).replace('%s', exit_status) for x in notify_cmdline])
|
||||
notify_with_command(cmd, self.id, notify_implementation=run_command)
|
||||
class Run(NotifyImplementation):
|
||||
def __init__(self, last_cmd_cmdline: str):
|
||||
self.last_cmd_cmdline = last_cmd_cmdline
|
||||
def __call__(self, title: str, body: str, identifier: str, urgency: Urgency = Urgency.Normal) -> None:
|
||||
open_cmd([x.replace('%c', self.last_cmd_cmdline).replace('%s', exit_status) for x in notify_cmdline])
|
||||
notify_with_command(cmd, self.id, notify_implementation=Run(self.last_cmd_cmdline))
|
||||
else:
|
||||
raise ValueError(f'Unknown action in option `notify_on_cmd_finish`: {action}')
|
||||
|
||||
|
||||
Reference in New Issue
Block a user