mirror of https://github.com/djcb/mu.git
mu4e: implement optional desktop notifications
This commit is contained in:
parent
b37cf7341b
commit
08cb28da8c
|
@ -46,6 +46,7 @@ mu4e_srcs=[
|
|||
'mu4e-mark.el',
|
||||
'mu4e-message.el',
|
||||
'mu4e-modeline.el',
|
||||
'mu4e-notification.el',
|
||||
'mu4e-obsolete.el',
|
||||
'mu4e-org.el',
|
||||
'mu4e-query-items.el',
|
||||
|
|
|
@ -0,0 +1,90 @@
|
|||
;;; mu4e-notification.el --- -*- coding: utf-8; lexical-binding: t -*-
|
||||
;;
|
||||
;; Copyright (C) 1996-2023 Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
|
||||
|
||||
;;; Commentary:
|
||||
;;; Generic support for showing new-mail notifications.
|
||||
|
||||
;;; Code:
|
||||
|
||||
(require 'mu4e-query-items)
|
||||
(require 'mu4e-bookmarks)
|
||||
|
||||
;; for emacs' built-in desktop notifications to work, we need
|
||||
;; dbus
|
||||
(when (featurep 'dbus)
|
||||
(require 'notifications))
|
||||
|
||||
(defcustom mu4e-notification-filter #'mu4e--default-notification-filter
|
||||
"Function for determining if a notification is to be emitted.
|
||||
|
||||
If this is the case, the function should return non-nil.
|
||||
|
||||
The function must accept an optional single parameter, unused for
|
||||
now."
|
||||
:type 'function
|
||||
:group 'mu4e-notification)
|
||||
|
||||
(defcustom mu4e-notification-function
|
||||
#'mu4e--default-notification-function
|
||||
"Function to emit a notification.
|
||||
|
||||
The function is invoked when we need to emit a new-mail
|
||||
notification in some system-specific way. The function is invoked
|
||||
when the query-items have been updated and
|
||||
`mu4e-notification-filter' returns t.
|
||||
|
||||
The function must accept an optional single parameter, unused for
|
||||
now."
|
||||
:type 'function
|
||||
:group 'mu4e-notification)
|
||||
|
||||
(defun mu4e--default-notification-filter (&optional _)
|
||||
"Return t if a notification should be shown.
|
||||
|
||||
This default implementation does so when there are more unread
|
||||
messages since baseline for the favorite bookmark."
|
||||
(when-let ((fav (mu4e-bookmark-favorite)))
|
||||
(> (or (plist-get fav :delta-unread) 0) 0)))
|
||||
|
||||
(defvar mu4e--notification-id nil
|
||||
"The last notification id, so we can replace it.")
|
||||
|
||||
(defun mu4e--default-notification-function (&optional _)
|
||||
"Default function for handling notifications.
|
||||
The default implementation uses emacs' built-in dbus-notification
|
||||
support."
|
||||
(when-let ((fav (mu4e-bookmark-favorite)))
|
||||
(let* ((title "Mu4e found new mail")
|
||||
(delta-unread (or (plist-get fav :delta-unread) 0))
|
||||
(body (format "There %s %d new message%s for your favorite bookmark"
|
||||
(if (= delta-unread 1) "is" "are")
|
||||
delta-unread
|
||||
(if (= delta-unread 1) "" "s"))))
|
||||
(cond
|
||||
((fboundp 'notifications-notify)
|
||||
;; notifactions available
|
||||
(setq mu4e--notification-id
|
||||
(notifications-notify
|
||||
:title title
|
||||
:body body
|
||||
:app-name "mu4e@emacs"
|
||||
:replaces-id mu4e--notification-id
|
||||
;; a custom mu4e icon would be nice...
|
||||
;; :app-icon (ignore-errors
|
||||
;; (image-search-load-path
|
||||
;; "gnus/gnus.png"))
|
||||
:actions '("Show" "Favorite bookmark")
|
||||
:on-action (lambda (_ _) (mu4e-jump-to-favorite)))))
|
||||
;; ... TBI: other notifications ...
|
||||
(t ;; last resort
|
||||
(mu4e-message "%s: %s" title body))))))
|
||||
|
||||
(defun mu4e--notification ()
|
||||
"Function called when the query items have been updated."
|
||||
(when (and (funcall mu4e-notification-filter)
|
||||
(functionp mu4e-notification-function))
|
||||
(funcall mu4e-notification-function)))
|
||||
|
||||
(provide 'mu4e-notification)
|
||||
;;; mu4e-notification.el ends here
|
30
mu4e/mu4e.el
30
mu4e/mu4e.el
|
@ -39,6 +39,7 @@
|
|||
(require 'mu4e-bookmarks)
|
||||
(require 'mu4e-update)
|
||||
(require 'mu4e-main)
|
||||
(require 'mu4e-notification)
|
||||
(require 'mu4e-server) ;; communication with backend
|
||||
|
||||
|
||||
|
@ -49,7 +50,12 @@
|
|||
:group 'mu4e)
|
||||
|
||||
(defcustom mu4e-modeline-support t
|
||||
"Support for shoiwing information in the modeline."
|
||||
"Support for showing information in the modeline."
|
||||
:type 'boolean
|
||||
:group 'mu4e)
|
||||
|
||||
(defcustom mu4e-notification-support nil
|
||||
"Support for new-message notifications."
|
||||
:type 'boolean
|
||||
:group 'mu4e)
|
||||
|
||||
|
@ -82,8 +88,8 @@ is non-nil."
|
|||
(interactive "P")
|
||||
;; start mu4e, then show the main view
|
||||
(mu4e--init-handlers)
|
||||
(mu4e--start (unless background #'mu4e--main-view))
|
||||
(mu4e--query-items-refresh))
|
||||
(mu4e--query-items-refresh)
|
||||
(mu4e--start (unless background #'mu4e--main-view)))
|
||||
|
||||
(defun mu4e-quit()
|
||||
"Quit the mu4e session."
|
||||
|
@ -134,13 +140,6 @@ Invoke FUNC if non-nil."
|
|||
(lambda () (mu4e-update-mail-and-index
|
||||
mu4e-index-update-in-background)))))))
|
||||
|
||||
;; ;; 2. update the main view, if any
|
||||
;; (when-let ((mainbuf (get-buffer mu4e-main-buffer-name)))
|
||||
;; (when (buffer-live-p mainbuf)
|
||||
;; (mu4e--main-redraw-buffer)))
|
||||
;; ;; 3. modeline.
|
||||
;; (mu4e--modeline-update)
|
||||
|
||||
(defun mu4e--start (&optional func)
|
||||
"Start mu4e.
|
||||
If `mu4e-contexts' have been defined, but we don't have a context
|
||||
|
@ -153,12 +152,16 @@ Otherwise, check requirements, then start mu4e. When successful, invoke
|
|||
(mu4e--context-autoswitch nil mu4e-context-policy))
|
||||
(setq mu4e-pong-func
|
||||
(lambda (info) (mu4e--pong-handler info func)))
|
||||
(mu4e--modeline-register #'mu4e--bookmarks-modeline-item 'global)
|
||||
;; modeline support
|
||||
(when mu4e-modeline-support
|
||||
(mu4e--modeline-register #'mu4e--bookmarks-modeline-item 'global)
|
||||
(mu4e-modeline-mode)
|
||||
(add-hook 'mu4e-query-items-updated-hook
|
||||
#'mu4e--modeline-update))
|
||||
(mu4e-modeline-mode (if mu4e-modeline-support 1 -1))
|
||||
(when mu4e-notification-support
|
||||
(add-hook 'mu4e-query-items-updated-hook
|
||||
#'mu4e--notification))
|
||||
(mu4e--server-ping)
|
||||
;; maybe request the list of contacts, automatically refreshed after
|
||||
;; reindexing
|
||||
|
@ -172,6 +175,8 @@ Otherwise, check requirements, then start mu4e. When successful, invoke
|
|||
(mu4e-clear-caches)
|
||||
(remove-hook 'mu4e-query-items-updated-hook
|
||||
#'mu4e--modeline-update)
|
||||
(remove-hook 'mu4e-query-items-updated-hook
|
||||
#'mu4e--notification)
|
||||
(mu4e-kill-update-mail)
|
||||
(mu4e-modeline-mode -1)
|
||||
(mu4e--server-kill)
|
||||
|
@ -271,6 +276,7 @@ chance."
|
|||
mu4e-maildir-list nil
|
||||
mu4e--contacts-set nil
|
||||
mu4e--contacts-tstamp "0"))
|
||||
;;; _
|
||||
|
||||
;;;
|
||||
(provide 'mu4e)
|
||||
;;; mu4e.el ends here
|
||||
|
|
|
@ -96,6 +96,7 @@ with answers to frequently asked questions, @ref{FAQ}.
|
|||
* Dynamic folders:: Folders that change based on circumstances
|
||||
* Actions:: Defining and using custom actions
|
||||
* Extending mu4e:: Writing code for @t{mu4e}
|
||||
* Integration:: Integrating @t{mu4e} with Emacs facilities
|
||||
|
||||
Appendices
|
||||
* Other tools:: mu4e and the rest of the world
|
||||
|
@ -2479,7 +2480,7 @@ contexts very often, and e.g. manually changes contexts with @kbd{M-x
|
|||
mu4e-context-switch}.
|
||||
@end itemize
|
||||
|
||||
You can easily switch contexts manually using the @kbd{;} key from
|
||||
You can easily switch contexts manually using the @kbd{;} key from
|
||||
the main screen, or by pressing @kbd{C-c ;} when drafting a message
|
||||
using the editor view.
|
||||
|
||||
|
@ -3059,23 +3060,46 @@ see @code{mu4e-toggle-logging}.
|
|||
@code{user-error} and @code{error} functions.
|
||||
@end itemize
|
||||
|
||||
@node Integrating with Emacs
|
||||
@chapter Integrating with Emacs
|
||||
@node Integration
|
||||
@chapter Integrating @t{mu4e} with Emacs facilities
|
||||
|
||||
In this chapter, we discuss how you can integrate @t{mu4e} with Emacs in various
|
||||
ways. Here we focus on Emacs built-ins; for dealing with external tools,
|
||||
@xref{Other tools}.
|
||||
|
||||
@menu
|
||||
* Modeline::Showing mu4e's status in the modeline
|
||||
* Default email client::Making mu4e the default emacs e-mail program
|
||||
* Using bookmarks::Using Emacs' bookmark system
|
||||
* Modeline::Showing mu4e's status in the modeline
|
||||
* Desktop notifications::Get desktop notifications for new mail
|
||||
* Emacs bookmarks::Using Emacs' bookmark system
|
||||
* Org-mode links::Adding mu4e to your organized life
|
||||
* iCalendar::Enabling iCalendar invite processing
|
||||
* Speedbar::A special frame with your folders
|
||||
* Dired:: Attaching files using @t{dired}
|
||||
@end menu
|
||||
|
||||
|
||||
@node Default email client
|
||||
@section Default email client
|
||||
|
||||
Emacs allows you to select an e-mail program as the default program it uses when
|
||||
you press @key{C-x m} (@code{compose-mail}), call @code{report-emacs-bug} and so
|
||||
on. If you want to use @t{mu4e} for this, you can do so by adding the following
|
||||
to your configuration:
|
||||
|
||||
@lisp
|
||||
(setq mail-user-agent 'mu4e-user-agent)
|
||||
@end lisp
|
||||
|
||||
Similarly, to specify @t{mu4e} as your preferred method for reading
|
||||
mail, customize the variable @code{read-mail-command}.
|
||||
|
||||
@lisp
|
||||
(set-variable 'read-mail-command 'mu4e)
|
||||
@end lisp
|
||||
|
||||
(@pxref{Top,,Emacs,Sending Mail, Mail Methods})
|
||||
|
||||
@node Modeline
|
||||
@section Modeline
|
||||
@cindex modeline
|
||||
|
@ -3130,29 +3154,28 @@ Due to the way queries work, the modeline is @emph{not} immediately updated when
|
|||
you read messages; but going back to the main view (with @kbd{M-x mu4e} restores
|
||||
things.
|
||||
|
||||
@node Default email client
|
||||
@section Default email client
|
||||
@node Desktop notifications
|
||||
@section Desktop notifications
|
||||
|
||||
Emacs allows you to select an e-mail program as the default program it uses when
|
||||
you press @key{C-x m} (@code{compose-mail}), call @code{report-emacs-bug} and so
|
||||
on. If you want to use @t{mu4e} for this, you can do so by adding the following
|
||||
to your configuration:
|
||||
Depending on your desktop environment, it is possible to get notification when
|
||||
there is new mail.
|
||||
|
||||
@lisp
|
||||
(setq mail-user-agent 'mu4e-user-agent)
|
||||
@end lisp
|
||||
The default implementation (which you can override) depends on the same system
|
||||
used for the @xref{Bookmarks and Maildirs} in the main view and the
|
||||
@xref{Modeline}, and thus gives updates when there new messages compared to some
|
||||
``baseline'', as discussed earlier.
|
||||
|
||||
Similarly, to specify @t{mu4e} as your preferred method for reading
|
||||
mail, customize the variable @code{read-mail-command}.
|
||||
For now, notifications are implemented for desktop environments that support
|
||||
DBus-based notifications, as per Emacs' notification sub-system
|
||||
@xref{Desktop Notifications,,,elisp,GNU Emacs Lisp Reference Manual}.
|
||||
|
||||
@lisp
|
||||
(set-variable 'read-mail-command 'mu4e)
|
||||
@end lisp
|
||||
You can enable mu4e's desktop notifications (provided that you are on a
|
||||
supported system) by setting @code{mu4e-notification-support} to @t{t}. If you
|
||||
want tweak the details, have a look at @code{mu4e-notification-filter} and
|
||||
@code{mu4e-notification-function}.
|
||||
|
||||
(@pxref{Top,,Emacs,Sending Mail, Mail Methods})
|
||||
|
||||
@node Using bookmarks
|
||||
@section Using bookmarks
|
||||
@node Emacs bookmarks
|
||||
@section Emacs bookmarks
|
||||
|
||||
Note, emacs bookmarks are not to be confused with mu4e's bookmarks; the former
|
||||
are a generic linking system, while the latter are remember stored queries.
|
||||
|
|
Loading…
Reference in New Issue