Since my dbus post last week, I’ve been playing around more with dbus whenever I get a few minutes. The modern Linux desktop is pretty good, but with minor tweaks, you can make things even better. (all this code is now up in a mercurial repository called dbus-hackery).
Automating Inactivity
Pidgin makes sounds on every message to me, xchat makes sounds on certain key words. Without these cues, I’d never remember to go check these applications. Because I have a tendency to leave my laptop on overnight, I found that I’d often have xchat ringing away at midnight when someone was looking for me. If I forgot to mute my machine before that, it would often wake me up.
One of the programs sending signals on dbus is gnome-screensaver.
def connect_screensaver(session_bus) ss_dbus = session_bus.service("org.gnome.ScreenSaver") ss = ss_dbus.object("/org/gnome/ScreenSaver") ss.introspect if ss.has_iface? "org.gnome.ScreenSaver" ss.default_iface = "org.gnome.ScreenSaver" puts "Connected to screensaver" end return ss end def mute() IO.popen("aumix -vq") {|r| r.read.scan(/(d+)/) {|m| @@vol = m puts "saved volume: #{@@vol}" break } } puts "muting" system("aumix -v 0") end def unmute() puts "unmuting" system("aumix -v #{@@vol}") end ss = connect_screensaver(session_bus) ss.on_signal("ActiveChanged") {|s| if s mute else unmute end }
The connect will look exactly as expected from the previous look at dbus. The ActiveChanged signal outputs a single parameter, a boolean, which is true when the screensave goes active, false when the screensaver is deactivated.
Volume control on the command line is most easily done with aumix (though if you are on Ubuntu Gutsy you’ll have issues until you rebuild aumix yourself. Hopefully they’ll fix that bug soon.) A little regex fun captures the current levels to a package variable, and restores them back on unmute.
Now I’ve got global mute when the screensaver fires, restored when I return.
Better Away with Pidgin
My screensaver being locked is a pretty clear indication that I’m away, though it being unlocked isn’t a clear indication that I’m back. Especially on weekends, I pop back for a quick check of something, then the computer is put away again.
def set_away(pidgin) puts "trying to set away" name = "screensaver" status = pidgin.PurpleSavedstatusFind(name)[0] if not status > 0 status = pidgin.PurpleSavedstatusNew(name, 5)[0] end puts "Status #{status}" pidgin.PurpleSavedstatusSetMessage(status, "screen saver auto away") pidgin.PurpleSavedstatusActivate(status) end ss.on_signal("ActiveChanged") {|s| if s mute set_away(pidgin) else unmute end }
In order to set a status with a message, it has to be a saved status. To prevent growing that to infinity, I first look to see if it is defined, creating a new saved status if not. 5 is a magic number here meaning STATUS_AWAY (reference the pidgin status.h for more info). Then we set the message on that status, and activate it. A single line change on our screen saver signal adds this into play.
Keep on Hacking
One of the things I’m hoping to impress in these posts on dbus is that with a highly functional language like ruby, linking applications on a modern gnome desktop can be done even by mere mortals. Linking sound to your screen saver is something that would have required a reasonable chunk of c code. Now you can do it in 20 lines of ruby, thanks to dbus.
I’ve thought about creating some sort of extended control panel to enable the features I’ve hacked together, but the reality is the code is so small, and so simple, it seems like overkill. With code this easy, you should just jump in and hack it to your own needs.
As I keep playing with dbus, I’ll post more bits here. Twitter integration is still on my list of things to do, and maybe something I’ll even manage to get to this week.