mirror of
https://git.savannah.gnu.org/git/emacs.git
synced 2024-11-21 06:55:39 +00:00
Port more notification senders to non-XDG systems
* doc/lispref/os.texi (Desktop Notifications): Document that `:timeout' is now implemented. * java/org/gnu/emacs/EmacsDesktopNotification.java (EmacsDesktopNotification): New field delay. (display1): Set delay on Android 8.0 and up. * lisp/erc/erc-desktop-notifications.el (erc-notifications-notify): Call Android or Haiku notification functions on those systems. * lisp/gnus/gnus-notifications.el (gnus-notifications-action) (gnus-notification-close): Remove dismissed notifications from the notification to message map. (gnus-notifications-notify): Call android-notifications-notify if possible. * src/androidselect.c (android_init_emacs_desktop_notification): Update accordingly. (android_notifications_notify_1): New argument TIMEOUT. (Fandroid_notifications_notify): New argument QCtimeout. (syms_of_androidselect) <QCtimeout>: New symbol.
This commit is contained in:
parent
4afafa0370
commit
6b40d557c4
@ -3244,6 +3244,7 @@ of parameters analogous to its namesake in
|
||||
@item :on-action @var{on-action}
|
||||
@item :on-cancel @var{on-close}
|
||||
@item :actions @var{actions}
|
||||
@item :timeout @var{timeout}
|
||||
@item :resident @var{resident}
|
||||
These have the same meaning as they do when used in calls to
|
||||
@code{notifications-notify}, except that no more than three non-default
|
||||
|
@ -83,11 +83,16 @@ public final class EmacsDesktopNotification
|
||||
notification. */
|
||||
public final String[] actions, titles;
|
||||
|
||||
/* Delay in miliseconds after which this notification should be
|
||||
automatically dismissed. */
|
||||
public final long delay;
|
||||
|
||||
public
|
||||
EmacsDesktopNotification (String title, String content,
|
||||
String group, String tag, int icon,
|
||||
int importance,
|
||||
String[] actions, String[] titles)
|
||||
String[] actions, String[] titles,
|
||||
long delay)
|
||||
{
|
||||
this.content = content;
|
||||
this.title = title;
|
||||
@ -97,6 +102,7 @@ public final class EmacsDesktopNotification
|
||||
this.importance = importance;
|
||||
this.actions = actions;
|
||||
this.titles = titles;
|
||||
this.delay = delay;
|
||||
}
|
||||
|
||||
|
||||
@ -191,6 +197,8 @@ public final class EmacsDesktopNotification
|
||||
builder.setContentTitle (title);
|
||||
builder.setContentText (content);
|
||||
builder.setSmallIcon (icon);
|
||||
builder.setTimeoutAfter (delay);
|
||||
|
||||
insertActions (context, builder);
|
||||
notification = builder.build ();
|
||||
}
|
||||
|
@ -54,6 +54,9 @@
|
||||
|
||||
(defvar dbus-debug) ; used in the macroexpansion of dbus-ignore-errors
|
||||
|
||||
(declare-function haiku-notifications-notify "haikuselect.c")
|
||||
(declare-function android-notifications-notify "androidselect.c")
|
||||
|
||||
(defun erc-notifications-notify (nick msg &optional privp)
|
||||
"Notify that NICK send some MSG, where PRIVP should be non-nil for PRIVMSGs.
|
||||
This will replace the last notification sent with this function."
|
||||
@ -64,14 +67,19 @@ This will replace the last notification sent with this function."
|
||||
(let* ((channel (if privp (erc-get-buffer nick) (current-buffer)))
|
||||
(title (format "%s in %s" (xml-escape-string nick t) channel))
|
||||
(body (xml-escape-string (erc-controls-strip msg) t)))
|
||||
(notifications-notify :bus erc-notifications-bus
|
||||
:title title
|
||||
:body body
|
||||
:replaces-id erc-notifications-last-notification
|
||||
:app-icon erc-notifications-icon
|
||||
:actions '("default" "Switch to buffer")
|
||||
:on-action (lambda (&rest _)
|
||||
(pop-to-buffer channel)))))))
|
||||
(funcall (cond ((featurep 'android)
|
||||
#'android-notifications-notify)
|
||||
((featurep 'haiku)
|
||||
#'haiku-notifications-notify)
|
||||
(t #'notifications-notify))
|
||||
:bus erc-notifications-bus
|
||||
:title title
|
||||
:body body
|
||||
:replaces-id erc-notifications-last-notification
|
||||
:app-icon erc-notifications-icon
|
||||
:actions '("default" "Switch to buffer")
|
||||
:on-action (lambda (&rest _)
|
||||
(pop-to-buffer channel)))))))
|
||||
|
||||
(defun erc-notifications-PRIVMSG (_proc parsed)
|
||||
(let ((nick (car (erc-parse-user (erc-response.sender parsed))))
|
||||
|
@ -83,27 +83,46 @@ not get notifications."
|
||||
group
|
||||
(delq article (gnus-list-of-unread-articles group)))
|
||||
;; gnus-group-refresh-group
|
||||
(gnus-group-update-group group)))))))
|
||||
(gnus-group-update-group group))))))
|
||||
;; Notifications are removed unless otherwise specified once they (or
|
||||
;; an action of theirs) are selected
|
||||
(assoc-delete-all id gnus-notifications-id-to-msg))
|
||||
|
||||
(defun gnus-notification-close (id reason)
|
||||
"Remove ID from the alist of notification identifiers to messages.
|
||||
REASON is ignored."
|
||||
(assoc-delete-all id gnus-notifications-id-to-msg))
|
||||
|
||||
(defun gnus-notifications-notify (from subject photo-file)
|
||||
"Send a notification about a new mail.
|
||||
Return a notification id if any, or t on success."
|
||||
(if (fboundp 'notifications-notify)
|
||||
(if (featurep 'android)
|
||||
(gnus-funcall-no-warning
|
||||
'notifications-notify
|
||||
'android-notifications-notify
|
||||
:title from
|
||||
:body subject
|
||||
:actions '("read" "Read" "mark-read" "Mark As Read")
|
||||
:on-action 'gnus-notifications-action
|
||||
:app-icon (gnus-funcall-no-warning
|
||||
'image-search-load-path "gnus/gnus.png")
|
||||
:image-path photo-file
|
||||
:app-name "Gnus"
|
||||
:category "email.arrived"
|
||||
:on-close 'gnus-notifications-close
|
||||
:group "Email arrivals"
|
||||
:timeout gnus-notifications-timeout)
|
||||
(message "New message from %s: %s" from subject)
|
||||
;; Don't return an id
|
||||
t))
|
||||
(if (fboundp 'notifications-notify)
|
||||
(gnus-funcall-no-warning
|
||||
'notifications-notify
|
||||
:title from
|
||||
:body subject
|
||||
:actions '("read" "Read" "mark-read" "Mark As Read")
|
||||
:on-action 'gnus-notifications-action
|
||||
:on-close 'gnus-notifications-close
|
||||
:app-icon (gnus-funcall-no-warning
|
||||
'image-search-load-path "gnus/gnus.png")
|
||||
:image-path photo-file
|
||||
:app-name "Gnus"
|
||||
:category "email.arrived"
|
||||
:timeout gnus-notifications-timeout)
|
||||
(message "New message from %s: %s" from subject)
|
||||
;; Don't return an id
|
||||
t)))
|
||||
|
||||
(declare-function gravatar-retrieve-synchronously "gravatar.el"
|
||||
(mail-address))
|
||||
|
@ -526,7 +526,7 @@ android_init_emacs_desktop_notification (void)
|
||||
FIND_METHOD (init, "<init>", "(Ljava/lang/String;"
|
||||
"Ljava/lang/String;Ljava/lang/String;"
|
||||
"Ljava/lang/String;II[Ljava/lang/String;"
|
||||
"[Ljava/lang/String;)V");
|
||||
"[Ljava/lang/String;J)V");
|
||||
FIND_METHOD (display, "display", "()V");
|
||||
#undef FIND_METHOD
|
||||
}
|
||||
@ -567,16 +567,17 @@ android_locate_icon (const char *name)
|
||||
}
|
||||
|
||||
/* Display a desktop notification with the provided TITLE, BODY,
|
||||
REPLACES_ID, GROUP, ICON, URGENCY, ACTIONS, RESIDENT, ACTION_CB and
|
||||
CLOSE_CB. Return an identifier for the resulting notification. */
|
||||
REPLACES_ID, GROUP, ICON, URGENCY, ACTIONS, TIMEOUT, RESIDENT,
|
||||
ACTION_CB and CLOSE_CB. Return an identifier for the resulting
|
||||
notification. */
|
||||
|
||||
static intmax_t
|
||||
android_notifications_notify_1 (Lisp_Object title, Lisp_Object body,
|
||||
Lisp_Object replaces_id,
|
||||
Lisp_Object group, Lisp_Object icon,
|
||||
Lisp_Object urgency, Lisp_Object actions,
|
||||
Lisp_Object resident, Lisp_Object action_cb,
|
||||
Lisp_Object close_cb)
|
||||
Lisp_Object timeout, Lisp_Object resident,
|
||||
Lisp_Object action_cb, Lisp_Object close_cb)
|
||||
{
|
||||
static intmax_t counter;
|
||||
intmax_t id;
|
||||
@ -593,6 +594,7 @@ android_notifications_notify_1 (Lisp_Object title, Lisp_Object body,
|
||||
jint nitems, i;
|
||||
jstring item;
|
||||
Lisp_Object length;
|
||||
jlong timeout_val;
|
||||
|
||||
if (EQ (urgency, Qlow))
|
||||
type = 2; /* IMPORTANCE_LOW */
|
||||
@ -603,6 +605,23 @@ android_notifications_notify_1 (Lisp_Object title, Lisp_Object body,
|
||||
else
|
||||
signal_error ("Invalid notification importance given", urgency);
|
||||
|
||||
/* Decode the timeout. */
|
||||
|
||||
timeout_val = 0;
|
||||
|
||||
if (!NILP (timeout))
|
||||
{
|
||||
CHECK_INTEGER (timeout);
|
||||
|
||||
if (!integer_to_intmax (timeout, &id)
|
||||
|| id > TYPE_MAXIMUM (jlong)
|
||||
|| id < TYPE_MINIMUM (jlong))
|
||||
signal_error ("Invalid timeout", timeout);
|
||||
|
||||
if (id > 0)
|
||||
timeout_val = id;
|
||||
}
|
||||
|
||||
nitems = 0;
|
||||
|
||||
/* If ACTIONS is provided, split it into two arrays of Java strings
|
||||
@ -714,7 +733,8 @@ android_notifications_notify_1 (Lisp_Object title, Lisp_Object body,
|
||||
notification_class.init,
|
||||
title1, body1, group1,
|
||||
identifier1, icon1, type,
|
||||
action_keys, action_titles);
|
||||
action_keys, action_titles,
|
||||
timeout_val);
|
||||
android_exception_check_6 (title1, body1, group1, identifier1,
|
||||
action_titles, action_keys);
|
||||
|
||||
@ -723,12 +743,8 @@ android_notifications_notify_1 (Lisp_Object title, Lisp_Object body,
|
||||
ANDROID_DELETE_LOCAL_REF (body1);
|
||||
ANDROID_DELETE_LOCAL_REF (group1);
|
||||
ANDROID_DELETE_LOCAL_REF (identifier1);
|
||||
|
||||
if (action_keys)
|
||||
ANDROID_DELETE_LOCAL_REF (action_keys);
|
||||
|
||||
if (action_titles)
|
||||
ANDROID_DELETE_LOCAL_REF (action_titles);
|
||||
ANDROID_DELETE_LOCAL_REF (action_keys);
|
||||
ANDROID_DELETE_LOCAL_REF (action_titles);
|
||||
|
||||
/* Display the notification. */
|
||||
(*android_java_env)->CallNonvirtualVoidMethod (android_java_env,
|
||||
@ -769,8 +785,14 @@ keywords is understood:
|
||||
The action for which CALLBACK is called when the
|
||||
notification itself is selected is named "default",
|
||||
its existence is implied, and its TITLE is ignored.
|
||||
No more than three actions can be defined, not
|
||||
counting any action with "default" as its key.
|
||||
No more than three actions defined here will be
|
||||
displayed, not counting any with "default" as its
|
||||
key.
|
||||
:timeout Number of miliseconds from the display of the
|
||||
notification at which it will be automatically
|
||||
dismissed, or a value of zero or smaller if it
|
||||
is to remain until user action is taken to dismiss
|
||||
it.
|
||||
:resident When set the notification will not be automatically
|
||||
dismissed when it or an action is selected.
|
||||
:on-action Function to call when an action is invoked.
|
||||
@ -780,12 +802,15 @@ keywords is understood:
|
||||
with the notification id and the symbol `undefined'
|
||||
for arguments.
|
||||
|
||||
The notification group is ignored on Android 7.1 and earlier versions
|
||||
of Android. Outside such older systems, it identifies a category that
|
||||
will be displayed in the system Settings menu, and the urgency
|
||||
provided always extends to affect all notifications displayed within
|
||||
that category. If the group is not provided, it defaults to the
|
||||
string "Desktop Notifications".
|
||||
The notification group and timeout are ignored on Android 7.1 and
|
||||
earlier versions of Android. On more recent versions, the urgency
|
||||
identifies a category that will be displayed in the system Settings
|
||||
menu, and the urgency provided always extends to affect all
|
||||
notifications displayed within that category, though it may be ignored
|
||||
if higher than any previously-specified urgency or if the user have
|
||||
already configured a different urgency for this category from Settings.
|
||||
If the group is not provided, it defaults to the string "Desktop
|
||||
Notifications" with the urgency suffixed.
|
||||
|
||||
Each caller should strive to provide one unchanging combination of
|
||||
notification group and urgency for each kind of notification it sends,
|
||||
@ -795,8 +820,8 @@ first notification sent to its notification group.
|
||||
|
||||
The provided icon should be the name of a "drawable resource" present
|
||||
within the "android.R.drawable" class designating an icon with a
|
||||
transparent background. If no icon is provided (or the icon is absent
|
||||
from this system), it defaults to "ic_dialog_alert".
|
||||
transparent background. Should no icon be provided (or the icon is
|
||||
absent from this system), it defaults to "ic_dialog_alert".
|
||||
|
||||
Actions specified with :actions cannot be displayed on Android 4.0 and
|
||||
earlier versions of the system.
|
||||
@ -814,17 +839,18 @@ this function.
|
||||
usage: (android-notifications-notify &rest ARGS) */)
|
||||
(ptrdiff_t nargs, Lisp_Object *args)
|
||||
{
|
||||
Lisp_Object title, body, replaces_id, group, urgency, resident;
|
||||
Lisp_Object title, body, replaces_id, group, urgency, timeout, resident;
|
||||
Lisp_Object icon;
|
||||
Lisp_Object key, value, actions, action_cb, close_cb;
|
||||
ptrdiff_t i;
|
||||
AUTO_STRING (default_icon, "ic_dialog_alert");
|
||||
|
||||
if (!android_init_gui)
|
||||
error ("No Android display connection!");
|
||||
|
||||
/* Clear each variable above. */
|
||||
title = body = replaces_id = group = icon = urgency = actions = Qnil;
|
||||
resident = action_cb = close_cb = Qnil;
|
||||
timeout = resident = action_cb = close_cb = Qnil;
|
||||
|
||||
/* If NARGS is odd, error. */
|
||||
|
||||
@ -852,6 +878,8 @@ usage: (android-notifications-notify &rest ARGS) */)
|
||||
icon = value;
|
||||
else if (EQ (key, QCactions))
|
||||
actions = value;
|
||||
else if (EQ (key, QCtimeout))
|
||||
timeout = value;
|
||||
else if (EQ (key, QCresident))
|
||||
resident = value;
|
||||
else if (EQ (key, QCon_action))
|
||||
@ -874,16 +902,19 @@ usage: (android-notifications-notify &rest ARGS) */)
|
||||
urgency = Qlow;
|
||||
|
||||
if (NILP (group))
|
||||
group = build_string ("Desktop Notifications");
|
||||
{
|
||||
AUTO_STRING (format, "Desktop Notifications (%s importance)");
|
||||
group = CALLN (Fformat, format, urgency);
|
||||
}
|
||||
|
||||
if (NILP (icon))
|
||||
icon = build_string ("ic_dialog_alert");
|
||||
icon = default_icon;
|
||||
else
|
||||
CHECK_STRING (icon);
|
||||
|
||||
return make_int (android_notifications_notify_1 (title, body, replaces_id,
|
||||
group, icon, urgency,
|
||||
actions, resident,
|
||||
actions, timeout, resident,
|
||||
action_cb, close_cb));
|
||||
}
|
||||
|
||||
@ -1001,6 +1032,7 @@ syms_of_androidselect (void)
|
||||
DEFSYM (QCurgency, ":urgency");
|
||||
DEFSYM (QCicon, ":icon");
|
||||
DEFSYM (QCactions, ":actions");
|
||||
DEFSYM (QCtimeout, ":timeout");
|
||||
DEFSYM (QCresident, ":resident");
|
||||
DEFSYM (QCon_action, ":on-action");
|
||||
DEFSYM (QCon_close, ":on-close");
|
||||
|
Loading…
Reference in New Issue
Block a user