require 'gtk2'

# This program shows you how to create semi-transparent windows,
# without any of the historical screenshot hacks. It requires
# a modern system, with a compositing manager. I use xcompmgr
# and the nvidia drivers with RenderAccel, and it works well.
#
# I'll take you through each step as we go. Minimal GTK+ knowledge is
# assumed.

# Only some X servers support alpha channels. Always have a fallback
$supports_alpha = false

def clicked(widget, event)
# toggle window manager frames
widget.decorated = !widget.decorated?
end

# This is called when we need to draw the windows contents
def expose_event(widget, event)
cr = widget.window.create_cairo_context

if $supports_alpha
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
end

# Draw the background
cr.operator = Cairo::OPERATOR_SOURCE
cr.paint

# Draw a circle
width, height = widget.size
cr.set_source_rgba(1.0, 0.2, 0.2, 0.6)

if width < height
radius = width.to_f/2 - 0.8
else
radius = height.to_f/2 - 0.8
end

cr.arc(width.to_f/2, height.to_f/2, radius, 0, 2.0*3.14)
cr.fill
cr.stroke
return false
end

def screen_changed(widget, old_screen = nil)
# To check if the display supports alpha channels, get the colormap
screen = widget.screen
colormap = screen.rgba_colormap

if colormap.nil?
puts 'Your screen does not support alpha channels!'
colormap = screen.rgb_colormap
$supports_alpha = false
else
puts 'Your screen supports alpha channels!'
$supports_alpha = true
end

# Now we have a colormap appropriate for the screen, use it
widget.colormap = colormap

return false
end

def main
window = Gtk::Window.new

window.title = "Alpha Demo"
window.signal_connect('delete-event') { |widget, event| Gtk.main_quit }

# Tell GTK+ that we want to draw the windows background ourself.
# If we don't do this then GTK+ will clear the window to the
# opaque theme default color, which isn't what we want.
window.app_paintable = true

# The X server sends us an expose event when the window becomes
# visible on screen. It means we need to draw the contents. On a
# composited desktop expose is normally only sent when the window
# is put on the screen. On a non-composited desktop it can be
# sent whenever the window is uncovered by another.
#
# The screen-changed event means the display to which we are
# drawing changed. GTK+ supports migration of running
# applications between X servers, which might not support the
# same features, so we need to check each time.

window.signal_connect('expose-event') { |widget, event| expose_event(widget, event) }
window.signal_connect('screen-changed') { |widget, old_screen| screen_changed(widget, old_screen) }

# toggle title bar on click - we add the mask to tell
# X we are interested in this event
window.decorated = false
window.add_events(Gdk::Event::BUTTON_PRESS_MASK)
window.signal_connect('button-press-event') { |widget, event| clicked(widget, event) }

# initialize for the current display
screen_changed(window)

# Run the program
window.show_all
Gtk.main
end

main