Send Notifications from Emacs with i3wm and Dunst

I barely use notifications, but recently I think it's a valuable way to remind me things like helping me nurture habits, or to notify me of emergencies like a critically low laptop battery.

So I try to integrate notifications to org-mode and Emacs today.

The org-notify package from org-contrib (install it by (package-install 'org-contrib) ) could do this job easily before, so I first test it in the minibuffer with (org-notify "test").

Unfortunately, it errors out:

Debugger entered--Lisp error: (dbus-error "Could not activate remote peer.")
  signal(dbus-error ("Could not activate remote peer."))
  dbus-call-method(:session "org.freedesktop.Notifications" "/org/freedesktop/Notifications" "org.freedesktop.Notifications" "Notify" :string "Emacs" :uint32 0 :string "/usr/share/emacs/27.2/etc/images/icons/hicolor/sca..." :string "Org mode message" :string "test" (:array) ((:dict-entry "urgency" (:variant :byte 0))) :int32 3000)
  notifications-notify(:title "Org mode message" :body "test" :timeout 3000 :urgency low)
  eval((org-notify "test") t)
  eval-expression((org-notify "test") nil nil 127)
  funcall-interactively(eval-expression (org-notify "test") nil nil 127)
  call-interactively(eval-expression nil nil)

Before switching to i3wm, I did receive notifications on GNOME, but I never saw one on i3wm. After searching for i3wm and notification, I realized that it's because there is no notification daemon running, and Dunst pops into my eyes.

Dunst is a lightweight replacement for the notification daemons provided by most desktop environments. The selling points are:

  1. Customizability
  2. Rules
  3. Multi-monitor Support
  4. History
  5. Keyboard-Driven
  6. Context Menu
  7. Scriptable

That sounds a perfect fit for me. Let's get started with it.

Install dunst from the repository and start it up with systemctl start --user dunst and test it with notify-send summary hi, it works!

Test Notifications with notify-send

But I don't like the default styling and the popup window position (at the top-right corner), and let's tweak it.

Copy the default file (cp /usr/share/dunst/dunstrc ~/.config/dunst/dunstrc) and start from the default settings. Since the file is well commented, I barely look up the online docs, the things that I customize are:

@@ -1,3 +1,4 @@
     ### Display ###
@@ -29,7 +30,7 @@
     # the top and down respectively.
     # The width can be negative.  In this case the actual width is the
     # screen width minus the width defined in within the geometry option.
-    geometry = "300x5-30+20"
+    geometry = "300x5+30+20"
     # Show how many messages are currently hidden (because of geometry).
     indicate_hidden = yes
@@ -61,10 +62,10 @@
     # Defines width in pixels of frame around the notification window.
     # Set to 0 to disable.
-    frame_width = 3
+    frame_width = 2
     # Defines color of the frame around the notification window.
-    frame_color = "#aaaaaa"
+    frame_color = "#fefefe"
     # Define a color for the separator.
     # possible values are:
@@ -86,7 +87,7 @@
     ### Text ###
-    font = Monospace 8
+    font = Monospace 14
     # The spacing between lines.  If the height is smaller than the
     # font height, it will get raised to the font height.
@@ -126,7 +127,7 @@
     #   %n  progress value if set without any extra characters
     #   %%  Literal %
     # Markup is allowed
-    format = "<b>%s</b>\n%b"
+    format = "<b>%s</b>\n%b\n\nfrom <i>%a</i>"
     # Alignment of message text.
     # Possible values are "left", "center" and "right".
@@ -183,7 +184,7 @@
     dmenu = /usr/bin/dmenu -p dunst:
     # Browser for opening urls in context menu.
-    browser = /usr/bin/firefox -new-tab
+    browser = xdg-open
     # Always run rule-defined scripts, even if the notification is suppressed
     always_run_script = true
@@ -213,7 +214,7 @@
     # corners.
     # The radius will be automatically lowered if it exceeds half of the
     # notification height to avoid clipping text and/or icons.
-    corner_radius = 0
+    corner_radius = 2
     ### Legacy
@@ -258,19 +259,19 @@
     # Xev might be helpful to find names for keys.
     # Close notification.
-    close = ctrl+space
+    # close = ctrl+space
     # Close all notifications.
-    close_all = ctrl+shift+space
+    # 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
+    # history = ctrl+grave
     # Context menu.
-    context = ctrl+shift+period
+    # context = ctrl+shift+period
     # IMPORTANT: colors have to be defined in quotation marks.

You can check out my final config at

Then test it with (org-notify "Emacs org-mode test"), it works as expected:

Test Notifications with Emacs

The last thing is to remind me things when Emacs starts up:

(run-with-timer 60 nil
                (lambda ()
                  (org-notify "Start your good day with org-mode agenda!")))

To recap, Dunst is well documented. It doesn't cost me much time to get it up. And if you use a tiling window manager like i3wm, you should give it a try.

See also

comments powered by Disqus