emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

master 6b40d557c4a: Port more notification senders to non-XDG systems


From: Po Lu
Subject: master 6b40d557c4a: Port more notification senders to non-XDG systems
Date: Tue, 12 Mar 2024 23:02:10 -0400 (EDT)

branch: master
commit 6b40d557c4a9a4152565c1a1b0da49a1aaaec84f
Author: Po Lu <luangruo@yahoo.com>
Commit: Po Lu <luangruo@yahoo.com>

    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.
---
 doc/lispref/os.texi                              |  1 +
 java/org/gnu/emacs/EmacsDesktopNotification.java | 10 ++-
 lisp/erc/erc-desktop-notifications.el            | 24 ++++---
 lisp/gnus/gnus-notifications.el                  | 41 ++++++++---
 src/androidselect.c                              | 86 ++++++++++++++++--------
 5 files changed, 115 insertions(+), 47 deletions(-)

diff --git a/doc/lispref/os.texi b/doc/lispref/os.texi
index 435886320fd..3ba3da459bf 100644
--- a/doc/lispref/os.texi
+++ b/doc/lispref/os.texi
@@ -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
diff --git a/java/org/gnu/emacs/EmacsDesktopNotification.java 
b/java/org/gnu/emacs/EmacsDesktopNotification.java
index d05ed2e6203..d00b9f2ea22 100644
--- a/java/org/gnu/emacs/EmacsDesktopNotification.java
+++ b/java/org/gnu/emacs/EmacsDesktopNotification.java
@@ -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 ();
       }
diff --git a/lisp/erc/erc-desktop-notifications.el 
b/lisp/erc/erc-desktop-notifications.el
index 2e905097f97..9bb89fbfc81 100644
--- a/lisp/erc/erc-desktop-notifications.el
+++ b/lisp/erc/erc-desktop-notifications.el
@@ -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))))
diff --git a/lisp/gnus/gnus-notifications.el b/lisp/gnus/gnus-notifications.el
index f34f5ea0e26..9ef21c91627 100644
--- a/lisp/gnus/gnus-notifications.el
+++ b/lisp/gnus/gnus-notifications.el
@@ -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))
diff --git a/src/androidselect.c b/src/androidselect.c
index 521133976a7..87dd2c3d079 100644
--- a/src/androidselect.c
+++ b/src/androidselect.c
@@ -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");



reply via email to

[Prev in Thread] Current Thread [Next in Thread]