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