Send jabber.el Alerts Through Growl
Let’s say you’re using Emacs as your Jabber client. (Stop looking at me like that.) You like it well enough, but you’d like it to be a little more aggressive about telling you when you have a new message.
Oh, and you’re using a Mac. Because Macs have Growl. (You might be able to make this work with GNotify or KNotify on Linux/*BSD/etc. or Snarl on Windows.)
Making Emacs send notifications of all kinds through Growl (including those from jabber.el) turns out to be surprisingly easy. Here’s how I did it.
Growl
First you need a way for Emacs to talk to Growl. This is easy, thanks to growlnotify. In fact, it’s already been written at least twice.
I’m kind of partial to that last one, but I’ve tweaked it a bit, thusly:
(defvar growl-program "/usr/local/bin/growlnotify")
(defun growl (title message &optional id)
(if (eq id nil)
(start-process "growl" " growl"
growl-program title "-w")
(start-process "growl" " growl"
growl-program title "-w" "-d" id))
(process-send-string " growl" message)
(process-send-string " growl" "\n")
(process-send-eof " growl"))
All this does is call growl “title” -w and echo the message into it. (growlnotify seems to prefer taking its messages from STDIN.) The -w keeps the subprocess around until the notification is dismissed—at least long enough to pipe the message into it. I found that if I didn’t, the process would go away before I could pipe in the message.
If passed an id argument, growl calls growlnotify with -d <id>. This keeps the desktop clean; if a notification balloon is already active with that id, Growl will reuse it instead of making another one. This is a particular problem with group chats; the server keeps a log of recent messages and sends them to you when you join. Without -d, this results in Growl notification spam taking up a quarter or more of your screen real estate.
jabber.el
To tell jabber.el to notify us via Growl when people talk to us, add a hook to jabber-alert-message-hooks (for one-on-one conversations) and another to jabber-alert-muc-hooks (for groupchats or chatrooms, a.k.a multi-user chats, or MUCs).
;; Make jabber.el notify through growl when I get a new message
(setq jabber-message-alert-same-buffer nil)
(defun pg-jabber-growl-notify (from buf text proposed-alert)
"(jabber.el hook) Notify of new Jabber chat messages via Growl"
(when (or jabber-message-alert-same-buffer
(not (memq (selected-window) (get-buffer-window-list buf))))
(if (jabber-muc-sender-p from)
(growl (format "(PM) %s"
(jabber-jid-displayname (jabber-jid-user from)))
(format "%s: %s" (jabber-jid-resource from) text)
(format "jabber-from-%s" (jabber-jid-resource from)))
(growl (format "%s" (jabber-jid-displayname from))
text "jabber-from-unknown"))))
(add-hook 'jabber-alert-message-hooks 'pg-jabber-growl-notify)
;; Same as above, for groupchats
(defun pg-jabber-muc-growl-notify (nick group buf text proposed-alert)
"(jabber.el hook) Notify of new Jabber MUC messages via Growl"
(when (or jabber-message-alert-same-buffer
(not (memq (selected-window) (get-buffer-window-list buf))))
(if nick
(when (or jabber-muc-alert-self
(not (string=
nick (cdr (assoc group *jabber-active-groupchats*)))))
(growl (format "%s" (jabber-jid-displayname group))
(format "%s: %s" nick text)
(format "jabber-chat-%s" (jabber-jid-displayname group))))
(growl (format "%s" (jabber-jid-displayname group))
text "jabber-chat-unknown"))))
(add-hook 'jabber-alert-muc-hooks 'pg-jabber-muc-growl-notify)
Some of the niceties I’ve implemented above:
- Don’t alert if the message is coming to the active buffer already, indicating that you’re already actively participating in the chat. (Note, however, that the buffer remains “active” on the Mac if you select another application, so either switch away from any chat buffers before selecting an app other than Emacs, or set
jabber-message-alert-same-buffer.) - You won’t get alerts for messages from yourself unless you set
jabber-muc-alert-self. This is rarely a problem, unless you’re testing this setup by sending messages to yourself….
Conclusion and future work
This approach obviously has a lot of potential. It’s easy enough to configure new mail notification this way, but I tend not to like that sort of thing; IM on work-related topics is all the distraction I need. I do, however, plan to make this work with upcoming appointments in my org-mode agenda and/or diary. We’ll see how that goes.
Copyright © 2006-2008 Phil Groce. All Rights Reserved.