#!/usr/bin/env python

# exailecover - displays Exaile album covers on the desktop
# Copyright (C) 2006 Johannes Sasongko <sasongko@gmail.com>
#
# 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()
