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.
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.
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.
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.