#!/usr/bin/env python
# A simple demonstration of using cairo to shape windows.
# Natan 'whatah' Zohar
import gtk
import math
import cairo

class ShapedGUI:
    def __init__(self):
        self.window = gtk.Window()
        self.window.show() # We show here so the window gets a border on it by the WM
        x,y,w,h = self.window.get_allocation()
        self.window.set_default_size(w,h)
        self.window.set_border_width(10)

        self.rounded = 0
        self.padding = 5
        
        self.scale = gtk.HScale()
        self.scale.set_range(0, 100)
        self.window.add(self.scale)
        self.window.connect('size-allocate', self.reshaperect)
        self.scale.connect('adjust-bounds', self.slider_moved_cb)
        self.window.show_all()

    # Find how round the edges should be based on slider value (maximum rounding is = min(width,height)/2)
    def find_edge_rounding(self):
        val = self.scale.get_value()
        val = min(100, val)
        val = max(self.padding, val)
        self.rounded = (val / 100.0) * min(self.width, self.height) / 2 - self.padding
    
    # Slide callback
    def slider_moved_cb(self, obj, data):
        self.window.set_default_size(self.width, self.height)

    # size allocation callback.
    # Shape the window into a rounded rectangle
    def reshaperect(self, obj, allocation):
        w,h = allocation.width, allocation.height
        self.width, self.height = h,w
        self.find_edge_rounding()
        bitmap = gtk.gdk.Pixmap(None, w, h, 1)
        cr = bitmap.cairo_create()
        
        # Clear the bitmap
        # Clear the bitmap
        cr.set_source_rgb(0,0,0)
        cr.set_operator(cairo.OPERATOR_DEST_OUT)
        cr.paint()
        cr.set_operator(cairo.OPERATOR_OVER)

        # Draw our shape into the pixmap using cairo
        # Let's try drawing a rectangle with rounded edges.
        padding=self.padding # Padding from the edges of the window
        rounded=self.rounded # How round to make the edges

        cr.set_source_rgb(0,0,0)
        # Move to top corner
        cr.move_to(0+padding+rounded, 0+padding)
        
        # Top right corner and round the edge
        cr.line_to(w-padding-rounded, 0+padding)
        cr.arc(w-padding-rounded, 0+padding+rounded, rounded, math.pi/2, 0)

        # Bottom right corner and round the edge
        cr.line_to(w-padding, h-padding-rounded)
        cr.arc(w-padding-rounded, h-padding-rounded, rounded, 0, math.pi/2)
       
        # Bottom left corner and round the edge.
        cr.line_to(0+padding+rounded, h-padding)
        cr.arc(0+padding+rounded, h-padding-rounded, rounded, math.pi+math.pi/2, math.pi)

        # Top left corner and round the edge
        cr.line_to(0+padding, 0+padding+rounded)
        cr.arc(0+padding+rounded, 0+padding+rounded, rounded, math.pi/2, 0)
        
        # Fill in the shape.
        cr.fill()

        # Set the window shape
        self.window.shape_combine_mask(bitmap, 0, 0)
        self.window.show()


    # Reshape the window into a circle
    def reshapecircle(self, obj, allocation):
        w,h = allocation.width, allocation.height
        bitmap = gtk.gdk.Pixmap(None, w, h, 1)
        
        # Clear the bitmap 
        fg = gtk.gdk.Color(pixel=0)
        bg = gtk.gdk.Color(pixel=-1)
        fg_gc = bitmap.new_gc(foreground=fg, background=bg)
        bitmap.draw_rectangle(fg_gc, True, 0, 0, w, h)

        # Draw our shape into the bitmap using cairo      
        cr = bitmap.cairo_create()
        cr.set_source_rgb(0,0,0)
        cr.arc(w/2,h/2,min(h,w)/2,0,2*math.pi)
        cr.fill()

        # Set the window shape
        self.window.shape_combine_mask(bitmap, 0, 0)
        self.window.show()

shapedWin = ShapedGUI()
shapedWin.window.connect("destroy", lambda w: gtk.main_quit())
gtk.main()
