#+titl the final code here.
¶The final piece
Desktop notifications are pretty common in applications, it’s good to support them in our desktop environment.
It’s also a useful tool for our own Emacs extensions and scripts!
Password sync script (View on GitHub)
We’ll use a program called Dunst to accomplish this.
¶Dunst
- Minimal
- Easy to customize
- Keyboard controlled
- Fits in well with Polybar
Homepage: https://dunst-project.org/
On Ubuntu you can install via apt:
sudo apt install dunst
It’s pretty commonly available in other Linux distributions as well!
¶Launching Dunst
It’s just as simple as running dunst! We can run it and see its output with async-shell-command (M-&)
Now to try it out with notify-send:
notify-send "Test!" notify-send -u critical "Your computer asplode" notify-send -i "emblem-synchronizing" "Passwords synced!"
We can also call up previous notifications using the global C-` keybinding! Useful if you saw a notification but didn’t have a chance to read it.
We can add it to our efs/exwm-init-hook function:
(efs/run-in-background "dunst")
¶Customizing Dunst
Much of this is boilerplate, you can read more about how to configure Dunst here:
https://dunst-project.org/documentation/
We’ll add this to our Desktop.org file:
:tangle ~/.config/dunst/dunstrc :mkdirp yes
[global] ### Display ### monitor = 0 # The geometry of the window: # [{width}]x{height}[+/-{x}+/-{y}] geometry = "500x10-10+50" # Show how many messages are currently hidden (because of geometry). indicate_hidden = yes # Shrink window if it's smaller than the width. Will be ignored if # width is 0. shrink = no # The transparency of the window. Range: [0; 100]. transparency = 10 # The height of the entire notification. If the height is smaller # than the font height and padding combined, it will be raised # to the font height and padding. notification_height = 0 # Draw a line of "separator_height" pixel height between two # notifications. # Set to 0 to disable. separator_height = 1 separator_color = frame # Padding between text and separator. padding = 8 # Horizontal padding. horizontal_padding = 8 # Defines width in pixels of frame around the notification window. # Set to 0 to disable. frame_width = 2 # Defines color of the frame around the notification window. frame_color = "#89AAEB" # Sort messages by urgency. sort = yes # Don't remove messages, if the user is idle (no mouse or keyboard input) # for longer than idle_threshold seconds. idle_threshold = 120 ### Text ### font = Cantarell 20 # The spacing between lines. If the height is smaller than the # font height, it will get raised to the font height. line_height = 0 markup = full # The format of the message. Possible variables are: # %a appname # %s summary # %b body # %i iconname (including its path) # %I iconname (without its path) # %p progress value if set ([ 0%] to [100%]) or nothing # %n progress value if set without any extra characters # %% Literal % # Markup is allowed format = "<b>%s</b>\n%b" # Alignment of message text. # Possible values are "left", "center" and "right". alignment = left # Show age of message if message is older than show_age_threshold # seconds. # Set to -1 to disable. show_age_threshold = 60 # Split notifications into multiple lines if they don't fit into # geometry. word_wrap = yes # When word_wrap is set to no, specify where to make an ellipsis in long lines. # Possible values are "start", "middle" and "end". ellipsize = middle # Ignore newlines '\n' in notifications. ignore_newline = no # Stack together notifications with the same content stack_duplicates = true # Hide the count of stacked notifications with the same content hide_duplicate_count = false # Display indicators for URLs (U) and actions (A). show_indicators = yes ### Icons ### # Align icons left/right/off icon_position = left # Scale larger icons down to this size, set to 0 to disable max_icon_size = 88 # Paths to default icons. icon_path = /home/daviwil/.guix-extra-profiles/desktop/desktop/share/icons/gnome/256x256/status/:/home/daviwil/.guix-extra-profiles/desktop/desktop/share/icons/gnome/256x256/devices/:/home/daviwil/.guix-extra-profiles/desktop/desktop/share/icons/gnome/256x256/emblems/ ### History ### # Should a notification popped up from history be sticky or timeout # as if it would normally do. sticky_history = no # Maximum amount of notifications kept in history history_length = 20 ### Misc/Advanced ### # Browser for opening urls in context menu. browser = qutebrowser # Always run rule-defined scripts, even if the notification is suppressed always_run_script = true # Define the title of the windows spawned by dunst title = Dunst # Define the class of the windows spawned by dunst class = Dunst startup_notification = false verbosity = mesg # Define the corner radius of the notification window # in pixel size. If the radius is 0, you have no rounded # corners. # The radius will be automatically lowered if it exceeds half of the # notification height to avoid clipping text and/or icons. corner_radius = 4 mouse_left_click = close_current mouse_middle_click = do_action mouse_right_click = close_all # Experimental features that may or may not work correctly. Do not expect them # to have a consistent behaviour across releases. [experimental] # Calculate the dpi to use on a per-monitor basis. # If this setting is enabled the Xft.dpi value will be ignored and instead # dunst will attempt to calculate an appropriate dpi value for each monitor # using the resolution and physical size. This might be useful in setups # where there are multiple screens with very different dpi values. per_monitor_dpi = false [shortcuts] # Shortcuts are specified as [modifier+][modifier+]...key # Available modifiers are "ctrl", "mod1" (the alt-key), "mod2", # "mod3" and "mod4" (windows-key). # Xev might be helpful to find names for keys. # Close notification. #close = ctrl+space # Close all notifications. #close_all = ctrl+shift+space # Redisplay last message(s). # On the US keyboard layout "grave" is normally above TAB and left # of "1". Make sure this key actually exists on your keyboard layout, # e.g. check output of 'xmodmap -pke' history = ctrl+grave # Context menu. context = ctrl+shift+period [urgency_low] # IMPORTANT: colors have to be defined in quotation marks. # Otherwise the "#" and following would be interpreted as a comment. background = "#222222" foreground = "#888888" timeout = 10 # Icon for notifications with low urgency, uncomment to enable #icon = /path/to/icon [urgency_normal] background = "#1c1f26" foreground = "#ffffff" timeout = 10 # Icon for notifications with normal urgency, uncomment to enable #icon = /path/to/icon [urgency_critical] background = "#900000" foreground = "#ffffff" frame_color = "#ff0000" timeout = 0 # Icon for notifications with critical urgency, uncomment to enable #icon = /path/to/icon
To refresh the configuration you’ll need to kill and restart Dunst:
pkill dunst && dunst &
Some things you’ll want to consider setting:
format- Customize how notification text contents are displayedgeometry- Where the notification appears and how large it should be by defaultmax_icon_size- Constrain icon display since some icons will be larger than othersicon_path- Important if your icons are not in a common location (like when using GNU Guix)idle_threshold- Wait for user to become active for this long before hiding notificationsmouse_left/right/middle_click- Action to take when clicking a notification- Any of the key bindings in the
shortcutssection (though these are deprecated in 1.5.0, usedunstctl)
¶Control Dunst with dunstctl
Starting with Dunst 1.5.0 there is a new command line tool called dunstctl which enables you to set up key bindings in your desktop environment (Emacs!) which launch dunstctl to control the running Dunst instance:
λ dunstctl --help
Usage: dunstctl <command> [parameters]
Commands:
action Perform the default action, or open the
context menu of the notification at the
given position
close Close the last notification
close-all Close the all notifications
context Open context menu
history-pop Pop one notification from history
is-paused Check if dunst is running or paused
set-paused [true|false|toggle] Set the pause status
debug Print debugging information
help Show this help
(defun efs/dunstctl (command) (start-process-shell-command "dunstctl" nil (concat "dunstctl " command))) (exwm-input-set-key (kbd "s-n") (lambda () (interactive) (efs/dunstctl "history-pop"))) (exwm-input-set-key (kbd "s-N") (lambda () (interactive) (efs/dunstctl "close-all")))
¶Enabling and disabling notifications
You can use either of the following commands to disable desktop notifications temporarily:
notify-send "DUNST_COMMAND_PAUSE" killall -SIGUSR1 dunst dunstctl set-paused true # Only available form 1.5.0 onward
You can resume notifications (and see all the notifications that occurred while disabled) by running any of these commands:
notify-send "DUNST_COMMAND_RESUME" killall -SIGUSR2 dunst dunstctl set-paused false # Only available from 1.5.0 onward
It can be useful to create an interactive function to enable/disable notifications so that you can use it in your configuration!
(defun efs/disable-desktop-notifications () (interactive) (start-process-shell-command "notify-send" nil "notify-send \"DUNST_COMMAND_PAUSE\"")) (defun efs/enable-desktop-notifications () (interactive) (start-process-shell-command "notify-send" nil "notify-send \"DUNST_COMMAND_RESUME\"")) (defun efs/toggle-desktop-notifications () (interactive) (start-process-shell-command "notify-send" nil "notify-send \"DUNST_COMMAND_TOGGLE\"")) (start-process-shell-command "notify-send" nil "notify-send \"This is from Emacs!\"")
¶Sending notifications from Emacs
Now that we can display notifications, we can use them in our Emacs configuration too:
¶Built-in functions
Emacs has a built-in function for this:
(notifications-notify :title "Test!" :body "This is just a test!")
Manual: https://www.gnu.org/software/emacs/manual/html_node/elisp/Desktop-Notifications.html
¶alert.el
An alternative is alert.el: https://github.com/jwiegley/alert
(alert "This is just a test!" :title "Test!")
However, this library is usually only preferrable if you are writing a package that needs to show notifications that the user might want to customize.
