How can I suspend the GtkDrawingArea draw callbacks while the window is being resized?

524 views Asked by At

I am developping a small GTK+ program in which I placed a GtkDrawingArea. I use it in order to draw a rather specific kind of data representation graph, and the result is quite satisfying.

The problem is: the "graph" has a lot of data to process, and the draw signal's callback is called quite often. Most importantly, it is called every time the window (GtkWindow/GtkContainer) is resized by a few pixels. In order to avoid slowing down the application too much, I'd like to "suspend" the draw callbacks while the window is being resized. We could imagine that the whole area would be covered with a gray rectangle in the meantime, or something similar...

gboolean draw_callback(GtkWidget* widget, cairo_t* cr, gpointer data){
    /* A lot of drawing with Cairo 
     * This is called WAY too often. */
}

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

    gtk_init(&argc, &argv);
    builder = gtk_builder_new_from_file("myapp.ui");

    window = GTK_WIDGET(gtk_builder_get_object(builder, "main_window"));
    draw_area = GTK_WIDGET(gtk_builder_get_object(builder, "draw_area"));

    g_signal_connect(draw_area, "draw", G_CALLBACK(draw_callback), NULL);

    gtk_widget_show_all(GTK_WIDGET(window));

    g_object_unref(builder);
    gtk_main();

    return 0;
}

Note: the callbacks must still be executed once the window is resized (some coordinates need to be recomputed when that happens). I'm just trying to avoid it while the window is being resized.

My first idea was to connect a callback to the check-resize event, in which a boolean could be set and unset, as the window is grabbed and released (while resizing) :

gboolean resizing = false;

void resize_callback(GtkContainer* container, gpointer data){
    /* Set "resizing"... 
     * Is the window being grabbed? Released? */
}

gboolean draw_callback(GtkWidget* widget, cairo_t* cr, gpointer data){
    if(resizing){
        /* Draw a gray overlay or something if necessary... */
        return true;
    }

    /* Draw the actual stuff here... */
}

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

    // ...

    g_signal_connect(window, "check-resize", G_CALLBACK(resize_callback), NULL);
    g_signal_connect(draw_area, "draw", G_CALLBACK(draw_callback), NULL);

   // ...
}

However this event doesn't really suit me because it is not triggered when the window is being grabbed/released (only when its size actually changes).

Is there a way to be notified when the window is being grabbed and released (for resizing) ? Or is there a better way to suspend/simplify the calls to draw_callback when the window is being resized?

1

There are 1 answers

0
jcoppens On

Consider blocking the draw callback while the mouse button is down. Save the callback id:

draw_callback_id = g_signal_connect(draw_area, "draw",
                                    G_CALLBACK(draw_callback), NULL);

When the button-pressed signal is detected, do

g_signal_handler_block(draw_area, draw_callback_id);

And, of course, after the button-release-event:

g_signal_handler_block(draw_area, draw_callback_id);

You could then manually trigger a redraw event. To optimize, you can use the gtk_widget_queue_draw_region() call, which only redraws the specified rectangle.

Another possibility (though I haven't tried this) could be drawing only the window borders while resizing or moving. The Window manager (XFCE) has this option, but I haven't seen how to do it from inside GTK.