View Single Post
Posts: 87 | Thanked: 98 times | Joined on Oct 2007 @ Austria
#17
Googling on this topic, I came across this example of semi-transparent windows with cairo, and to my utter amazement it works perfectly on OS2008!

So I went ahead and remodeled this clock widget to a desktop maemo plugin.

Here's how it looks (it's resizable too!)

Name:  pyclock.jpg
Views: 5119
Size:  16.5 KB

And this is the code - following SpiritGeeks example I'll just paste it in

/usr/share/applications/hildon-home/pyclock.desktop:
Code:
[Desktop Entry]
Name=Python Cairo Clock
Type=python
X-Path=pyclock
/usr/lib/hildon-desktop/pyclock.py:
Code:
import sys
import gobject
import pango
import pygtk
pygtk.require('2.0')
import gtk
from gtk import gdk
import hildondesktop
import cairo
from datetime import datetime
import gobject
import math


# set this to False to disable display of seconds and update 
# only once per minute (saves CPU cycles on the tablet)
enable_seconds = True

supports_alpha = False


class PyClock(hildondesktop.HomeItem):
	def __init__(self):
		hildondesktop.HomeItem.__init__(self)
				
		self.set_resize_type(hildondesktop.HOME_ITEM_RESIZE_BOTH)
		self.set_size_request(140, 140)
		self.connect("expose-event", self.expose)
		self.connect("screen-changed", self.screen_changed)
		self.connect ("background", self.set_timer, False)
		self.connect ("foreground", self.set_timer, True)
		self.connect ("unrealize", self.unrealize)

		# set a timeout to update the clock, depending
		# on whether we are in the foreground or background
		self.timer = None
		self.set_timer(self, True)

		self.show_all()


	def expose(self, widget, event):

		global supports_alpha

		width, height = self.allocation[2], self.allocation[3]

		#Get a cairo context
		cr = widget.window.cairo_create()

		if supports_alpha == True:
			cr.set_source_rgba(1.0, 1.0, 1.0, 0.0) # Transparent
		else:
			cr.set_source_rgb(1.0, 1.0, 1.0) # Opaque white

		# Draw the background
		cr.set_operator(cairo.OPERATOR_SOURCE)
		cr.paint()

		#And draw everything we want
		#Some cos/sin magic is done, never mind
		if supports_alpha == True:
			cr.set_source_rgba(1.0, 1.0, 1.0, 0.5)
		else:
			cr.set_source_rgb(1.0, 1.0, 1.0)			
		if width < height:
			radius = float(width)/2 - 0.8
		else:
			radius = float(height)/2 - 0.8
			
		cr.arc(float(width)/2, float(height)/2, radius, 0, 2.0*3.14)
		cr.fill()
		cr.stroke()
	
		if supports_alpha == True:
			cr.set_source_rgba(0.0, 0.0, 0.0, 1.0)
		else:
			cr.set_source_rgb(0.0, 0.0, 0.0)

		cr.set_line_width(0.07 * radius)
		cr.move_to(-0.05 * radius + float(width/2 + radius), float(height)/2)
		cr.rel_line_to(-0.1 * radius, 0)
		cr.stroke()
		cr.move_to(float(width)/2, -0.05 * radius + float(height/2 + radius))
		cr.rel_line_to(0, -0.1 * radius)
		cr.stroke()
		cr.move_to(0.05 * radius + float(width/2 - radius), float(height)/2)
		cr.rel_line_to(0.1 * radius, 0)
		cr.stroke()
		cr.move_to(float(width)/2, 0.05 * radius + float(height/2 - radius))
		cr.rel_line_to(0, 0.1 * radius)
		cr.stroke()

		time = datetime.now()
		hour = time.hour
		minutes = time.minute
		seconds = time.second
		per_hour = (2 * 3.14) / 12
		dh = (hour * per_hour) + ((per_hour / 60) * minutes)
		dh += 2 * 3.14 / 4
		cr.set_line_width(0.07 * radius)
		cr.move_to(float(width)/2, float(height)/2)
		cr.rel_line_to(-0.6 * radius * math.cos(dh), -0.6 * radius * math.sin(dh))
		cr.stroke()
		per_minute = (2 * 3.14) / 60
		dm = minutes * per_minute
		dm += 2 * 3.14 / 4
		cr.set_line_width(0.05 * radius)
		cr.move_to(float(width)/2, float(height)/2)
		cr.rel_line_to(-0.9 * radius * math.cos(dm), -0.9 * radius * math.sin(dm))
		cr.stroke()
		# only draw seconds when in foreground
		if enable_seconds: # disable seconds, to much work for little tablets
			per_second = (2 * 3.14) / 60
			ds = seconds * per_second
			ds += 2 * 3.14 / 4
			cr.set_line_width(0.02 * radius)
			cr.move_to(float(width)/2, float(height)/2)
			cr.rel_line_to(-0.9 * radius * math.cos(ds), -0.9 * radius * math.sin(ds))
			cr.stroke()
		
		cr.arc(float(width)/2, float(height)/2, 0.1 * radius, 0, 2.0*3.14)
		cr.fill()
		cr.stroke()
		
		#Once everything has been drawn, create our XShape mask
		#Our window content is contained inside the big circle,
		#so let's use that one as our mask
		"""pm = gtk.gdk.Pixmap(None, width, height, 1)
		pmcr = pm.cairo_create()
		pmcr.arc(float(width)/2, float(height)/2, radius, 0, 2.0*3.14)
		pmcr.fill()
		pmcr.stroke()
		#Apply input mask
		self.input_shape_combine_mask(pm, 0, 0)"""
	
		return False


	def screen_changed(self, widget, old_screen=None):
		global supports_alpha
		# print "screen changed"
		
		# To check if the display supports alpha channels, get the colormap
		screen = self.get_screen()
		colormap = screen.get_rgba_colormap()
		if colormap == None:
			# print 'Your screen does not support alpha channels!'
			colormap = screen.get_rgb_colormap()
			supports_alpha = False
		else:
			# print 'Your screen supports alpha channels!'
			supports_alpha = True
    
		# Now we have a colormap appropriate for the screen, use it
		self.set_colormap(colormap)
    
		return False
	
	def unrealize(self, widget, date=None):
		# cancel timeout
		if self.timer:
			v = gobject.source_remove(self.timer)
			print "canceled pyclock timeout:", v
			self.timer = None


	def set_timer(self, widget, on):
		# when called first time from __init__ widget is None
		if self.timer != None:
			# print "removing old timer"
			gobject.source_remove(self.timer)
		if on:
			# print "creating new timer"
			delay = 1000 if enable_seconds else 60000
			self.timer = gobject.timeout_add(delay, self.update)
			# repaint immediately when coming to the foreground
			self.update()


	def update(self):
		# print "updating pyclock"
		self.queue_draw()
		return True


def hd_plugin_get_objects():
	plugin = PyClock()
	return [plugin]
Remember that you need the hildondesktop python bindings installed which aren't in the main repositories yet. Happy hacking!

Last edited by hns; 03-07-2008 at 05:22 AM. Reason: Update code to cancel timeout call when plugin is removed.
 

The Following 6 Users Say Thank You to hns For This Useful Post: