Programming

Cairo, XShape, Transparency, and .NET: Together at last

Have ever you thought to yourself, “Man, I’d really like to make a transparent window using Gtk#?” I did. So I tried reading through the one really transparent program I had, MacSlow’s cairo-clock, and discovered the stuff going on under the hood was freakin’ nuts. Well, on February 17th, Ikke on Planet Gnome posted a swanky program called pycairoshape-clock.py which did pretty much the exact same thing with a few exceptions:

  • The code was a lot simpler.
  • It was witten in a much friendlier language.
  • It contained 100% Gtk/Gdk/Cairo functions thanks to some lovely additions in Gtk+-2.10

Well, I have some lovely news. That program was really easy to read and I C-sharped it into a friendly little program which is functionally identical. I give you CairoShapeClock.cs. In just 13^2 lines of code, you can have your very own transparent clock to wobble around the screen. I’d post screenshots but as the program is EXACTLY the same to the python one, you should just check out Ikke’s post.

Well, that’s a nice clock, but how does it work?

There are three parts: Checking if we can draw transparently, drawing the widget, and shaping the window.

The first part is straightforward. You create your window, then check that window.Screen.RgbaColormap != null. If the colormap is not null, then you have the much covetted “a” part of the Rgba and can draw transparently. window.Colormap should then be assigned to the RgbaColormap or RgbColormap based on whichever applied to the situation. Since the window may lose this power if your compositing engine (beryl or compiz) dies, you need to monitor the window.ScreenChanged event. Any time it is called, there’s a new screen at window.Screen for you to check out.

For the second part, you need to render the window’s background when its exposed. To do this, you need to monitor the window.ExposeEvent event. When this event is called, you get your chance to draw stuff on the screen. To draw the background, the program does the following:

private static void Expose (object o, Gtk.ExposeEventArgs args)
{
int width;
int height;

win.GetSize (out width, out height);

// Create the cairo context
Cairo.Context cr = Gdk.CairoHelper.Create (win.GdkWindow);

// Make the window transparent.
if (supports_alpha)
cr.Color = new Cairo.Color (1.0, 1.0, 1.0, 0.0);
else
cr.Color = new Cairo.Color (1.0, 1.0, 1.0);

cr.Operator = Cairo.Operator.Source;
cr.Paint ();

...

This function starts each expose event by creating a cairo context and a color, either transparent or plain, and painting the color onto the context. With the background set, the program can continue drawing everything else, business as usual.

The last part is shaping the window. This is done by creating a mask pixmap of equal size and shape to the window, drawing the clock’s shape on it, and calling (the new in Gtk# 2.10) win.InputShapeCombineMask (pixmap, 0, 0);. This method, restricts input signals to the window to the masked area with everything else falling through it to the window below. This is similar to ShapeCombineMask, but it doesn’t trim the visual, letting us keep our nice smooth edges.

Hopefully this will be helpful someone. Happy coding.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s