Parsa Mousavi
Parsa Mousavi

Reputation: 1212

How to create a cairo object within a gtk window in GTK+3

I'm trying to use cairo to draw some arcs but gcc warns me that gdk_cairo_create() is deprecated. Use gdk_window_begin_draw_frame() and gdk_drawing_context_get_cairo_context() instead.

To get around this I did some research and found out that for gdk_window_begin_draw_frame() I need "GdkWindow".I've always been using GtkWidget for my windows so I need to convert "GtkWidget" to "GdkWindow", but gtk_widget_get_window() returns NULL and causes segfault.

#include <gtk/gtk.h>
#include <cairo.h>
void main(int argc , char **argv){
    gtk_init(&argc , &argv);
    GtkWidget *win;
    GdkWindow *gdkwin;
    GdkDrawingContext *dc;

    cairo_region_t *region;

    cairo_t *cr;


    win = gtk_window_new(GTK_WINDOW_TOPLEVEL);

    region = cairo_region_create();

    gdkwin = gtk_widget_get_window(GTK_WIDGET(win));

    //Here gdkwin should contain a GdkWindow but it's NULL.

    gc = gdk_window_begin_draw_frame(gdkwin , (const cairo_region_t*)&region);
    ...
    ...

Here's the runtime errors:

(a.out:6852): Gdk-CRITICAL **: 23:53:06.042: gdk_window_begin_draw_frame: assertion 'GDK_IS_WINDOW (window)' failed

(a.out:6852): Gdk-CRITICAL **: 23:53:06.042: gdk_drawing_context_get_cairo_context: assertion 'GDK_IS_DRAWING_CONTEXT (context)' failed
Segmentation fault

I want to get a cairo object and use it for cairo_arc().

Thanks.Best regards.

Upvotes: 6

Views: 5424

Answers (4)

OldUrologist
OldUrologist

Reputation: 91

The Dark Trick's program is complete. He uses the functions as follows,

GdkWindow* window = gtk_widget_get_window (widget);
cairo_region_t *cairoRegion = cairo_region_create();
GdkDrawingContext *drawingContext;
drawingContext = gdk_window_begin_draw_frame (window, cairoRegion);
cairo_t *cr = gdk_drawing_context_get_cairo_context (drawingContext);

But I am using the the functions as follows,

GdkWindow *window = gtk_widget_get_window(widget);
cairo_rectangle_int_t cairoRectangle = {0, 0, 200, 200};
cairo_region_t *cairoRegion = cairo_region_create_rectangle (&cairoRectangle);
GdkDrawingContext *drawingContext;
drawingContext = gdk_window_begin_draw_frame (window,cairoRegion);
cairo_t *cr = gdk_drawing_context_get_cairo_context (drawingContext);

This worked, but I can not understand the differencies, for I am an OldUrologist.

Upvotes: 1

DarkTrick
DarkTrick

Reputation: 3529

The below is the complete source code to get Cairo working under GTK 3. It should be compilable as is.

As the others already pointed out, you have to use the draw signal to make things work.

    #include <gtk/gtk.h>
    #include <cairo.h>

    // ------------------------------------------------------------

    gboolean on_draw (GtkWidget *widget,
                    GdkEventExpose *event,
                    gpointer data) 
    {

        // "convert" the G*t*kWidget to G*d*kWindow (no, it's not a GtkWindow!)
        GdkWindow* window = gtk_widget_get_window(widget);  

        cairo_region_t * cairoRegion = cairo_region_create();

        GdkDrawingContext * drawingContext;
        drawingContext = gdk_window_begin_draw_frame (window,cairoRegion);

        { 
            // say: "I want to start drawing"
            cairo_t * cr = gdk_drawing_context_get_cairo_context (drawingContext);

            { // do your drawing
                cairo_move_to(cr, 30, 30);
                cairo_set_font_size(cr,15);
                cairo_show_text(cr, "hello world");
            }

            // say: "I'm finished drawing
            gdk_window_end_draw_frame(window,drawingContext);
        }

        // cleanup
        cairo_region_destroy(cairoRegion);

        return FALSE;
    }

    // ------------------------------------------------------------

    int main (int argc, char * argv[]) {
        gtk_init(&argc, &argv);

        GtkWindow * window; 
        { // window setup
            window = (GtkWindow*)gtk_window_new(GTK_WINDOW_TOPLEVEL);
            gtk_window_set_default_size (window, 200, 200);
            gtk_window_set_position     (window, GTK_WIN_POS_CENTER);
            gtk_window_set_title        (window, "Drawing");

            g_signal_connect(window, "destroy", gtk_main_quit, NULL);
        }  

        // create the are we can draw in
        GtkDrawingArea* drawingArea;
        {
            drawingArea = (GtkDrawingArea*) gtk_drawing_area_new();
            gtk_container_add(GTK_CONTAINER(window), (GtkWidget*)drawingArea);

            g_signal_connect((GtkWidget*)drawingArea, "draw", G_CALLBACK(on_draw), NULL);    
        }  


        gtk_widget_show_all ((GtkWidget*)window);
        gtk_main();

        return 0;
    }



    // ------------------------------------------------------------

Upvotes: 6

liberforce
liberforce

Reputation: 11454

In GTK+ 3, you're supposed to do your drawing in response to the draw signal. Doing it in the main makes no sense (the widgets have just been created, but initializing them further in done when running the main event loop).

Please read: https://developer.gnome.org/gtk3/stable/chap-drawing-model.html

Upvotes: 2

user2062604
user2062604

Reputation: 285

I'm not positive, but I think you're trying to get the GdkWindow before it is ready. I think you need to connect to the window's "realize" signal, and only when that signal has been emitted should you try to access the underlying GdkWindow.

#include <gtk/gtk.h>
#include <cairo.h>


void OnWindowRealize(GtkWidget *pWidget, gpointer data)
{
    GdkWindow *pUnderlyingWindow = gtk_widget_get_window(pWidget);

    cairo_region_t *region = cairo_region_create();

    GdkDrawingContext *gc = gdk_window_begin_draw_frame(pUnderlyingWindow, (const cairo_region_t*)&region);

    //etc...
}


void main(int argc , char **argv)
{
    gtk_init(&argc , &argv);

    GtkWidget *win = gtk_window_new(GTK_WINDOW_TOPLEVEL);

    g_signal_connect(G_OBJECT(win), "realize", OnWindowRealize, NULL);

    //etc...
}


Upvotes: 0

Related Questions