#!/usr/bin/env python # exailecover - displays Exaile album covers on the desktop # Copyright (C) 2006 Johannes Sasongko # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. """exailecover - displays Exaile album covers on the desktop Syntax: exailecover [geometry] [timeout_ms] - geometry : standard X geometry string; see `man 3 XParseGeometry` or http://www.xfree86.org/current/X.7.html#sect6 - timeout_ms : the timer interval, in milliseconds """ import gobject import gtk gobject.threads_init() import dbus import dbus.glib dbus.glib.threads_init() import re class CoverDisplay(gtk.Window): def __init__(self, geometry='', timer_ms=1000): self.geometry = geometry self.timer_ms = timer_ms self.cover = '' self.init_dbus() self.init_gtk() gobject.timeout_add(self.timer_ms, self.timeout) def init_dbus(self): bus = dbus.SessionBus() obj = bus.get_object( 'org.exaile.DBusInterface', '/DBusInterfaceObject') self.dbus_iface = dbus.Interface(obj, 'org.exaile.DBusInterface') self.dbus_ok = True def init_gtk(self): gtk.Window.__init__(self) self.connect('destroy', gtk.main_quit) self.set_accept_focus(False) self.set_decorated(False) self.set_keep_below(True) self.set_resizable(False) self.set_skip_pager_hint(True) self.set_skip_taskbar_hint(True) self.stick() self.img = gtk.Image() self.add(self.img) self.parse_geometry() self.show_all() def parse_geometry(self): match = re.match( '^=?(?:(\d+)?(?:[Xx](\d+))?)?' '(?:([+-])(\d+)?(?:([+-])(\d+))?)?$', self.geometry) if not match: raise ValueError('invalid geometry: ' + self.geometry) w, h, px, x, py, y = match.groups() if w and h: self.w = int(w) self.h = int(h) else: self.w = None self.h = None if x and y: gtk.Window.parse_geometry(self, self.geometry) else: self.set_position(gtk.WIN_POS_CENTER_ALWAYS) def timeout(self): try: newcover = self.dbus_iface.get_cover_path() except dbus.DBusException: if self.dbus_ok: self.display(None) self.dbus_ok = False return True else: self.dbus_ok = True print newcover if newcover != self.cover: self.cover = newcover if newcover.find('nocover') == -1: self.display(newcover) else: self.display(None) return True def display(self, cover): if cover == None: self.img.clear() return pixbuf = gtk.gdk.pixbuf_new_from_file(cover) width = pixbuf.get_width() height = pixbuf.get_height() if self.w is not None and self.h is not None: origw = float(width) origh = float(width) width, height = self.w, self.h scale = min(width / origw, height / origh) width = int(origw * scale) height = int(origh * scale) pixbuf = pixbuf.scale_simple( width, height, gtk.gdk.INTERP_BILINEAR) self.img.set_from_pixbuf(pixbuf) def run(self): gtk.main() import sys if __name__ == '__main__': argc = len(sys.argv) if argc > 1: geometry = sys.argv[1] else: geometry = '' if argc > 2: timeout = int(sys.argv[2]) else: timeout = 1000 cd = CoverDisplay(geometry, timeout) cd.run()