Re: gtk-2 bug, inconsistency or simply misunderstanding on my side ?



Olivier Fourdan wrote:

Hi all,

I've seem some behaviour in gkt that I don't understand well.

The problem shows like this :

create a container (a frame)
add another container (another frame) inside the first one.
at last, add a widget to the last container.

It looks like this :

container1
   +-> container2
            +->widget

It happens that, when destroying container2 the widget is freed twice
(even if the widget is *not* destroyed explicitely by the program).

This is because (if I understand well) when destroying the container,
the widget is removed from the container first, so its reference count
is decremented and reach zero, so it gets automatically free, and then
the widget is freed again because its parent is destroyed.

The (easy to tell, hard to find) workarround is to force a
g_object_ref() on the widget at creation. This way, the
gtk_container_remove performed automatically doesn't free the widget, so
it gets freed only once.

Do all this make any sense ? Am I missing something obvious here ?

Hello, Olivier

Looks like you're killing the second container by g_object_unref().
Use gtk_widget_destroy instead(). Look at the little prog I've attached.

Olexiy


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


static void (*button_class_finalize)(GObject *object);


static void on_destroy(GtkWidget *widget)
{
        printf("%p::destroy\n", widget);
}

static void on_finalize(GObject *object)
{
        printf("%p::finalize\n", object);
        button_class_finalize(object);
}

static void frame_slayer(GtkWidget *button, GtkWidget **frame)
{
        if (*frame) {
                gtk_widget_destroy(*frame);
                *frame = NULL;
        }
        else    printf("what frame ?\n");
}

int main(int argc, char **argv)
{
GtkWidget *window;
GtkWidget *vbox;
GtkWidget *frame1,*frame2;
GtkWidget *button;
    
        gtk_init(&argc, &argv);

        window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
        g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(gtk_main_quit), window);
        gtk_container_set_border_width(GTK_CONTAINER(window), 8);

        vbox = gtk_vbox_new(FALSE, 0);
        gtk_container_add(GTK_CONTAINER(window), vbox);

        frame1 = gtk_frame_new(" <frame 1> ");
        gtk_container_add(GTK_CONTAINER(vbox), frame1);
        gtk_container_set_border_width(GTK_CONTAINER(frame1), 8);

        frame2 = gtk_frame_new(" <frame 2> ");
        gtk_container_add(GTK_CONTAINER(frame1), frame2);
        gtk_container_set_border_width(GTK_CONTAINER(frame2), 8);

        button = gtk_button_new_with_label(" test widget ");
        gtk_container_add(GTK_CONTAINER(frame2), button);
        g_signal_connect(G_OBJECT(button), "destroy", G_CALLBACK(on_destroy), NULL);

        /* a little hack used to override the GObject::finalize method
           (creation of the new widget is much more lines of code)
        */
        button_class_finalize = G_OBJECT_CLASS(g_type_class_peek(GTK_TYPE_BUTTON))->finalize;
        G_OBJECT_CLASS(g_type_class_peek(GTK_TYPE_BUTTON))->finalize = on_finalize;

        button = gtk_button_new_with_label("slay the second frame");
        gtk_container_add(GTK_CONTAINER(vbox), button);
        g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(frame_slayer), &frame2);

        gtk_widget_show_all(window);
        
        gtk_main();

        return 0;
}


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]