Search code examples
pythongtkpygtkcairopycairo

How to get transparent background in window with PyGTK and PyCairo?


I've been trying really hard to create a window with no decoration and a transparent background using PyGTK. I would then draw the content of the window with Cairo. But I can't get it to work.

I've tried a lot of different ways, they all failed, this is one of them

#!/usr/bin/env python

import pygtk
pygtk.require('2.0')
import gtk, sys, cairo

win = None

def expose (widget, event):
    cr = widget.window.cairo_create()

    #Start drawing
    cr.set_operator(cairo.OPERATOR_CLEAR)
    cr.set_source_rgba(0.5,1.0,0.0,0.5)
    cr.rectangle(0, 0, 0.9, 0.8)
    cr.fill()

def main (argc):
    global win

    win = gtk.Window()

    win.set_decorated(False)

    win.connect('delete_event', gtk.main_quit)
    win.connect('expose-event', expose)

    win.set_app_paintable(True)

    win.show()

    gtk.main()

if __name__ == '__main__':
    sys.exit(main(sys.argv))

So, what is the simplest way to do this?


Solution

  • So, I actually figured this out myself.

    This is a working example. I've commented the relevant parts just in case somebody else is interested in how to do this.

    #!/usr/bin/env python
    
    import pygtk
    pygtk.require('2.0')
    import gtk, sys, cairo
    from math import pi
    
    def expose (widget, event):
        cr = widget.window.cairo_create()
    
        # Sets the operator to clear which deletes everything below where an object is drawn
        cr.set_operator(cairo.OPERATOR_CLEAR)
        # Makes the mask fill the entire window
        cr.rectangle(0.0, 0.0, *widget.get_size())
        # Deletes everything in the window (since the compositing operator is clear and mask fills the entire window
        cr.fill()
        # Set the compositing operator back to the default
        cr.set_operator(cairo.OPERATOR_OVER)
    
        # Draw a fancy little circle for demonstration purpose
        cr.set_source_rgba(0.5,1.0,0.0,1)
        cr.arc(widget.get_size()[0]/2,widget.get_size()[1]/2,
               widget.get_size()[0]/2,0,pi*2)
        cr.fill()
    
    def main (argc):
    
        win = gtk.Window()
    
        win.set_decorated(False)
    
        # Makes the window paintable, so we can draw directly on it
        win.set_app_paintable(True)
        win.set_size_request(100, 100)
    
        # This sets the windows colormap, so it supports transparency.
        # This will only work if the wm support alpha channel
        screen = win.get_screen()
        rgba = screen.get_rgba_colormap()
        win.set_colormap(rgba)
    
        win.connect('expose-event', expose)
    
        win.show()