I have some Gtk+
code written in C
that does some animation using Cairo
and a timer. Most of the time when I click on the close application icon I get the following message on the terminal:
Gtk-CRITICAL **: gtk_widget_queue_draw: assertion `GTK_IS_WIDGET (widget)' failed
Now I'm assuming this is happing because at the moment I close the application the timer is fired and the main window widget is accessed but has since been destroyed. What is the usual method to determine if a Gtk widget is still valid and can be referenced?
The offending code is here:
gboolean rotate_cb( void *degrees )
{
rotation += DegreesToRadians((*(int*)(degrees)));
// Tell our window that it should repaint itself (ie. emit an expose event)
/* need to only call gtk_widget_queue_draw() if window is still valid / exists */
gtk_widget_queue_draw(window);
return( TRUE );
}
I'm assuming there must be some way to test whether or not window
is still active and valid?
Your problem is quite subtle. This usually happens because of the rules of ownership and destruction of GObject/GtkObject. Let me remind them:
GObject
s are simply count referenced. They are destroyed when the count reaches 0. A newly created object has count 1. GInitiallyUnowned
s are also count referenced, and they are also destroyed when the count reaches 0. But a newly created object has a floating count. That means that the first time the count is to be incremented it is not actually incremented, but the floating count is sunk, that is, converted to a normal reference.GtkObject
s are GInitiallyUnowned
objects, so they have the magic floating count.
But you probably know all this... Now, my question:
Who owns the counter of the visible main GtkWindow?
That's actually easy, the GTK framework has a list of these and retains a reference of every visible GtkWindow
. But then, another question:
When does the GTK framework free the references of its GtkWindow?
Do you remember the gtk_widget_destroy()
function and the destroy
signal? They are exactly for that: when you want to remove a toplevel GtkWindow
you call gtk_widget_destroy()
, it activates the signal destroy
, that is received by the GTK framework that removes the actual window and frees its reference to the object.
And here comes the reason for your problem: if the GTK framework retains the only existing reference to the GtkWindow
, the object is actually freed. If then, your timer tries to access to it, it will fail, because the window is no more.
And here, at last, comes (hopefully) the solution:
g_object_ref()/g_object_ref_sink()
on the window when you start the timer. Also register a handler to the destroy
signal of the window.destroy
signal of the window: call g_object_unref()
on the window and stop the timer.Naturally, this partial solution should also work, because the window will not be destroyed without sending the destroy
signal:
destroy
signal of the window.destroy
signal of the window: stop the timer.But it is considered a good practice to increment the ref-counter of the objects when you are actually keeping a pointer to them.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With