2008-08-06

The story of dbus, knotify4 and erc

I'm using erc in Emacs as my irc client and by default there is no notification outside of Emacs. Trying to get something working in kde4 I first tried calling kdialog, it worked, but it wasn't a fair sight.

After deciding that the kdialog popup is too ugly I started looking for alternatives. The alternative I found where right in front of my eyes: The Notify plasmoid. The problem was that there's no easy way of calling knotify (like kdialog --passivepopup) but some googling turned up http://mvidner.blogspot.com/2008/06/knotify-client.html which describes how to patch knotify4 (the dbus signature is apparently erronous) and how to call it from python.

Sure enough, after patching knotify, the nicely skinned notices popped up, and the text were even customizable using html.

Starting from emacs 23 dbus support is built-in, and luckily I am running a cvs version. I started trying to make some dbus calls but I always got an error stating that the "event" method of knotify did not exist. After many hours and double-checking the parameters I tried it with perl, worked instantly. Now I was starting to lose hope, thinking that maybe Emacs dbus implementation didn't really work.

Just as I were beginning to give up, after staring myself blind on the function signatures, I tried the following, thinking it was really a long shot:

(dbus-call-method :session "org.kde.knotify" "/Notify" "org.kde.KNotify" "event" "warning" "kde" '(:array (:variant nil)) "message" '(:array :byte 0 :byte 0 :byte 0 :byte 0) '(:array) :int64 0)

And there it was (albeit a bit ugly)! My notification popup, called from Emacs!

But I wasn't finished yet, it still said "from kde" and it was apparently a "warning". Trying to change does values didn't bring up anything.. curios. Looking around my ~/.kde/share/config I found kopete.notifyrc. It was the key! Creating my own called emacs.notifyrc and entering


[Event/erc_nick]
Action=Sound|Popup|Taskbar
Execute=
KTTS=
Logfile=
Sound=KDE-Im-Message-In.ogg


I could call "erc_nick" and "emacs" and now I had my "own" notification. It even got the Emacs icon!

Finally I added this code to my personal erc file and I hade working erc notification:




(defun thomasa88-erc-knotify4 (type message) 
(dbus-call-method :session "org.kde.knotify" "/Notify" "org.kde.KNotify"
"event"
type "emacs" '(:array (:variant nil)) message '(:array :byte 0 :byte 0 :byte 0 :byte 0) '(:array) :int64 0)

)

;;test (dbus-call-method :session "org.kde.knotify" "/Notify" "org.kde.KNotify" "event" "erc_nick" "emacs" '(:array (:variant nil)) "message" '(:array :byte 0 :byte 0 :byte 0 :byte 0) '(:array) :int64 0)

(defun thomasa88-erc-notify-match (type from rawmsg)
(let ((erc-resp (get-text-property 0 'erc-parsed rawmsg)))
(when (and (or (eq type 'current-nick) (eq type 'keyword))
(equal (erc-response.command erc-resp) "PRIVMSG"))
(thomasa88-erc-notify erc-resp nil))))

(defun thomasa88-erc-notify-PRIVMSG (proc erc-resp)
(thomasa88-erc-notify erc-resp t))

(defun thomasa88-erc-notify (erc-resp check-privmsg)
(let ((target (first (erc-response.command-args erc-resp)))
(from-nick (first (erc-parse-user (erc-response.sender erc-resp))))
(message (erc-response.contents erc-resp)))
(when (or (not check-privmsg)
(and (erc-current-nick-p target)
(not (erc-is-message-ctcp-and-not-action-p message))))
(thomasa88-erc-knotify4 "erc_nick"
(concat target " <" from-nick "> " message)))))

(add-hook 'erc-text-matched-hook 'thomasa88-erc-notify-match)
(add-hook 'erc-server-PRIVMSG-functions 'thomasa88-erc-notify-PRIVMSG t)



edit: Current svn knotify has a correct signature

5 comments:

Anonymous said...
This comment has been removed by a blog administrator.
Kevin Brubeck Unhammer said...

So.. A year later, is this patch still not in kNotify?

On trying

(dbus-call-method :session
"org.kde.knotify"
"/Notify"
"org.kde.KNotify"
"event"
"warning"
"kde"
'(:array (:variant nil))
"message"
'(:array :byte 0 :byte 0 :byte 0 :byte 0)
'(:array)
:int64 0)


I get

Debugger entered--Lisp error: (dbus-error "No such method 'event' in interface 'org.kde.KNotify' at object path '/Notify' (signature 'ssavsayasx')")
dbus-call-method(:session "org.kde.knotify" "/Notify" "org.kde.KNotify" "event" "warning" "kde" (:array (:variant nil)) "message" (:array :byte 0 :byte 0 :byte 0 :byte 0) (:array) :int64 0)
eval((dbus-call-method :session "org.kde.knotify" "/Notify" "org.kde.KNotify" "event" "warning" "kde" (quote (:array ...)) "message" (quote (:array :byte 0 :byte 0 :byte 0 :byte 0)) (quote (:array)) :int64 0))
eval-last-sexp-1(nil)
eval-last-sexp(nil)
call-interactively(eval-last-sexp nil nil)
recursive-edit()
byte-code("Æ @Ç=ƒ!

Thomas A said...

I have not used this for a long time, but there are some comments about a signature change here:
http://mvidner.blogspot.com/2008/06/knotify-client.html?showComment=1259074111392#c4598109641644736936

I hope you will succeed to change the call using this new information.

Kevin Brubeck Unhammer said...

Ugh. You'd think it could be as simple as (dbus-send "org.kde.KNotify" "message") but then, why make things easy when you can complicate...

Oh well, I guess I'll have to dig deeper.

necr0n said...

I've managed to make this work on KDE 4.6.4 and Emacs 24.0.50.1 (emacs-snapshot in Kubuntu 11.04). DBus call should be like this:
(dbus-call-method :session "org.kde.knotify" "/Notify" "org.kde.KNotify" "event" "warning" "kde" '(:array (:variant nil)) "Test header" "Test message" '(:array :byte 0 :byte 0 :byte 0 :byte 0) '(:array ) :int32 0 :int64 0)
And you can alter rest of functions in order to form a header as well as message.