[pygtk] cairo + transparent png + XShape

Sebastian Bartos seth.kriticos at googlemail.com
Sat Jan 3 23:45:10 WST 2009


Hello there,

well, just to help the people who come after me, here is the solution I
did. It's a bit dirty, sorry for that. Anyways, it loads the file
base.png in the same folder and puts it on a 800x650 window with
transparency and XShape clipping:

import sys
import gobject
import pango
import pygtk
import gtk
from gtk import gdk
import cairo
# import Images
import gobject

class pngtranswin:
	def __init__(self):
		self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
		
		self.window.set_decorated(0)
		self.window.set_default_size(800, 650)
		
		self.window.set_events(gtk.gdk.ALL_EVENTS_MASK)
		
		# Initialize colors, alpha transparency		
		self.window.set_app_paintable(1)
		self.gtk_screen = self.window.get_screen()
		colormap = self.gtk_screen.get_rgba_colormap()
		if colormap == None:
			colormap = self.gtk_screen.get_rgb_colormap()
		gtk.widget_set_default_colormap(colormap)
		if not self.window.is_composited():
			self.supports_alpha = False
		else:
			self.supports_alpha = True
		
		self.w,self.h = self.window.get_size()
		
		self.window.connect("expose_event", self.expose)
		self.window.connect("destroy", gtk.main_quit)
		

	def expose (self, widget, event):
		self.ctx = self.window.window.cairo_create()
		# set a clip region for the expose event, XShape stuff
		self.ctx.save()
		if self.supports_alpha == False:
			self.ctx.set_source_rgb(1, 1, 1)
		else:
			self.ctx.set_source_rgba(1, 1, 1,0)
		self.ctx.set_operator (cairo.OPERATOR_SOURCE)
		self.ctx.paint()
		self.ctx.restore()
		self.ctx.rectangle(event.area.x, event.area.y,
				event.area.width, event.area.height)
		self.ctx.clip()
		self.draw_image(self.ctx,0,0,'base.png')

	def setup(self):
		# Set menu background image
		self.background =  gtk.Image()
		self.frame = gtk.Fixed()
		self.window.add (self.frame)
		
		# Set window shape from alpha mask of background image
		w,h = self.window.get_size()
		if w==0: w = 800
		if h==0: h = 650
		self.w = w
		self.h = h
		self.pixmap = gtk.gdk.Pixmap (None, w, h, 1)
		ctx = self.pixmap.cairo_create()
		# todo: modify picture source
		#self.bgpb = gtk.gdk.pixbuf_new_from_file('base.png')
		ctx.save()
		ctx.set_source_rgba(1, 1, 1,0)
		ctx.set_operator (cairo.OPERATOR_SOURCE)
		ctx.paint()
		ctx.restore()
		self.draw_image(ctx,0,0,'base.png')
		
		if self.window.is_composited():
			ctx.rectangle(0,0,w,h)
			ctx.fill()			
			self.window.input_shape_combine_mask(self.pixmap,0,0)
		else:
			self.window.shape_combine_mask(self.pixmap, 0, 0)

	def draw_image(self,ctx,x,y, pix):
		"""Draws a picture from specified path with a certain width and
height"""

		ctx.save()
		ctx.translate(x, y)	
		pixbuf = gtk.gdk.pixbuf_new_from_file(pix)
		format = cairo.FORMAT_RGB24
		if pixbuf.get_has_alpha():
			format = cairo.FORMAT_ARGB32
		#if Images.flip != None:
		#	pixbuf = pixbuf.flip(Images.flip)
	
		iw = pixbuf.get_width()
		ih = pixbuf.get_height()
		image = cairo.ImageSurface(format, iw, ih)
		image = ctx.set_source_pixbuf(pixbuf, 0, 0)
		
		ctx.paint()
		puxbuf = None
		image = None
		ctx.restore()
		ctx.clip()

	def show_window(self):
		self.window.show_all()
		while gtk.events_pending():
			gtk.main_iteration()
		self.window.present()
		self.window.grab_focus()
		self.p = 1

if __name__ == "__main__":
	m = pngtranswin()
	m.setup()
	m.show_window()
	gtk.main()

Ok, you can see that it is a bit prototype state, but works. Any
functional comments?

~ Seth


On Sat, 2009-01-03 at 11:48 +0100, Pietro Battiston wrote:
> Il giorno mer, 31/12/2008 alle 01.22 +0100, Sebastian Bartos ha scritto:
> > Hello there,
> > 
> > I'm working on a little app here that uses cairo and a transparent png
> > for nifty window design (kind of like widgets/screenlets, no border,
> > transparency, etc.)
> > 
> > Now I try to figure out how to tell the XShape extension to take the
> > fully transparent parts of the window and cut them away (really
> > irregular borders).
> > 
> > Any ideas?
> > 
> > Thanks
> > Seth Kriticos
> 
> 
> I once tried it, please look if this does what you want (and eventually
> do it in some less chaotic way! It was really just a proof of concept):
> 
> -----------------------------------------------------------------------
> 
> 
> import gtk, gobject
> 
> 
> N,M=200,200
> 
> drag_icon_xpm = [
> str(N)+" "+str(M)+" 1 1",
> "       c None"]+[' '*N]*M
> 
> 
> w = gtk.Window()
> 
> 
> def apply_mask():
>     p = gtk.gdk.pixmap_create_from_xpm_d(w.window , None,
> drag_icon_xpm)[1]
>     r=p.cairo_create()
>     r.arc(N/2, M/2, min(N,M)/2, .0001, 0)
>     r.fill()
>     w.shape_combine_mask(p, 0, 0)
>     w.set_decorated(False)
>     return
>     
>     
> b=gtk.Button("Click me,\n stupid")
> w.add(b)
> b.connect('released', gtk.main_quit)
> w.set_size_request(200,200)
> w.show_all()
> 
> gobject.timeout_add(1, apply_mask)
> 
> gtk.main()
> 
-- 
Sebastian Bartos, <seth.kriticos at googlemail.com>
keyserevr: pgp.mit.edu
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 197 bytes
Desc: This is a digitally signed message part
Url : http://www.daa.com.au/pipermail/pygtk/attachments/20090103/c09ff96c/attachment.pgp 


More information about the pygtk mailing list