Ported fill and stroke Cairo drawing example on Zetcode.com to GTK+3

If you do any searching for Cairo or GTK+ tutorials, you’ll eventually wind up on zetcode.com. I’d be content with only a fraction of this guy’s talent for explaining difficult subject matters with such brevity and clarity. It’s not coincidence that much of my code style matches his.

That said, his GTK+ and Cairo tutorials are a bit out of date. The migration from GTK+2 to GTK+3 was pretty dramatic. There is no longer an “expose-event” signal to trigger redrawing of a window. It’s been replaced by “draw”, and the prototype for the callback changed, too. I’ve been meaning to learn Cairo now that GTK+ is completely in bed with it, so I thought I’d tackle porting the fill and stroke example on zetcode.com to be GTK+3 compatible.


/* This is a GTK+3 ported version of the Basic Drawing
 * fill and stroke Cairo tutorial at zetcode.com
 * http://zetcode.com/tutorials/cairographicstutorial/basicdrawing/
 */

#include <stdio.h>
#include <stdlib.h>
#include <cairo.h>
#include <gtk/gtk.h>
#include <math.h>

gboolean on_draw_event (GtkWidget *widget, cairo_t *cr, gpointer user_data)
{
 /* http://stackoverflow.com/questions/8722084/using-cairo-with-gtk3 */

 cr = gdk_cairo_create(gtk_widget_get_window(widget));

 int width, height;
 gtk_window_get_size(GTK_WINDOW(widget), &width, &height);
 cairo_set_line_width(cr, 9);

 cairo_set_source_rgb(cr, 0.69, 0.19, 0);
 cairo_arc(cr, width/2, height/2, (width < height ? width : height) / 2 - 10, 0, 2 * M_PI);
 cairo_stroke_preserve(cr);

 cairo_set_source_rgb(cr, 0.3, 0.4, 0.6);
 cairo_fill(cr);

 cairo_destroy(cr);

 return FALSE;
}

int main (int argc, char *argv[])
{
 GtkWidget *window;

 gtk_init(&argc, &argv);

 window = gtk_window_new(GTK_WINDOW_TOPLEVEL);

 g_signal_connect(G_OBJECT(window), "draw", G_CALLBACK(on_draw_event), NULL);
 g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(gtk_main_quit), NULL);

 gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
 gtk_window_set_default_size(GTK_WINDOW(window), 200, 150);

 gtk_widget_set_app_paintable(window, TRUE);
 gtk_widget_show_all(window);

 gtk_main();

 return 0;
}

No big deal here, only three changes required.

1) Change the signal connection


g_signal_connect(G_OBJECT(window), "expose-event", G_CALLBACK(on_expose_event), NULL);

to

g_signal_connect(G_OBJECT(window), "draw", G_CALLBACK(on_draw_event), NULL);

because there is no “expose-event” signal anymore.

2) Change the event callback prototype


on_expose_event (GtkWidget *widget, GdkEventExpose *event, gpointer data)

to

on_draw_event(GtkWidget *widget, cairo_t *cr, gpointer data)

and note that the names on_draw_event and on_expose_event are arbitrary. It’s common in most examples to name them as such.

3) In the draw event callback change


cr = gdk_cairo_create (widget->window);

to

cr = gdk_cairo_create(gtk_widget_get_window(widget));

because the window member is considered private now. You need to use the function gtk_widget_get_window() to get a pointer to the window.

I really want to get a grip on Cairo since it’s the new way forward in Gnome development. Porting the zetcode.com examples might help start me out.

This entry was posted in Hobbies, Programming. Bookmark the permalink.

3 Responses to Ported fill and stroke Cairo drawing example on Zetcode.com to GTK+3

  1. yf777a says:

    Interesting. I’ve been trying to learn cairo in GTK+3 a little, also.
    I did the same thing with the timer.c example. But I added experimental
    drawing code of my own. Just a idea on your article, the
    cairo context cr is passed as a parameter by GTK to “draw” in version 3.
    No need to create a new one.
    gdk_cairo_create is depreciated, but only gives a warning.
    Peace.

  2. yf777a says:

    My mistake… I can’t figure out how to use
    //GdkDrawingContext *dc =gdk_window_begin_draw_frame (GTK_WINDOW(widget), cr);
    //cr = gdk_drawing_context_get_cairo_context (dc);
    or something similar that the compiler puts in the warning.
    From what I understand, GTK 3 at this time has a wrapper for the depreciated
    gdk_cairo_create that uses the updated method.
    For a drawing area, I just use the passed ‘cr’ and it works fine with no warnings.

  3. yf777a says:

    I’m an idiot… I forgot to take out the cairo_destroy(cr) after taking out the depreciate
    gdk_cairo_create… so naturally I kept crashing with a null cr after the window flash for a brief instant sometimes. It also works whether or not I use //gtk_widget_set_app_paintable(window, TRUE); in main(); Live and learn.

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 )

Google photo

You are commenting using your Google 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 )

Connecting to %s