Paul Davis wrote:
> On Thu, 2007-03-22 at 16:49 +0100, Jef Driesen wrote:
>> When I look at some gtk C code, I see everywhere pointers to widgets 
>> (and other things). As i understand all gtk objects are reference 
>> counted to keep the objects alive until the last pointer is released.
>>
>> How does that work in gtkmm? At first sight, gtkmm widgets doesn't seem 
>> to be reference counted, because something like this does not work 
>> (because of the private copy constructor):
>>
>> Gtk::Button a, b(a);
>>
>> Do I need to use smart pointers (e.g. boost::shared_ptr) for that? Does 
>> that means the underlying gtk reference counting mechanism is not used 
>> in gtkmm?
> 
> you're thinking much too hard. stop thinking, and just use the toolkit.

The problem is my application is crashing and I can't find the reason. 
That's why I started looking more closely at the gtk(mm) memory 
management. This is the code that is causing the problem:

class IView : public Gtk::VBox {
public:
    virtual Glib::RefPtr<Gdk::Pixbuf> icon () = 0;
    virtual Glib::ustring name () = 0;
};

class ViewList : public Gtk::ScrolledWindow {
public:
    ViewList()
    {
       m_treeview.get_selection()->signal_changed().connect(
          sigc::mem_fun(*this, &ViewList::on_treeview_selection_changed));
       m_store = Gtk::ListStore::create (m_columns);
       m_treeview.set_headers_clickable (false);
       m_treeview.set_headers_visible (false);
       m_treeview.append_column ("Icon", m_columns.icon);
       m_treeview.append_column ("Description", m_columns.name);
       m_treeview.set_model (m_store);
       set_policy (Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
       set_shadow_type (Gtk::SHADOW_IN);
       add (m_treeview);
    }
    ~ViewList() {}
    void append (IView *view)
    {
       Gtk::TreeModel::iterator iter = m_store->append ();
       Gtk::TreeModel::Row row = *iter;
       row[m_columns.icon] = view->icon ();
       row[m_columns.name] = view->name ();
       row[m_columns.view] = view;
    }
    void remove (IView *view)
    {
       Gtk::TreeModel::iterator i = find(view);
       if (i)
          m_store->erase(i);
    }
    void select (IView *view)
    {
       Gtk::TreeModel::iterator i = find(view);
       if (i)
          m_treeview.get_selection()->select(i);
    }
    sigc::signal<void, IView*> signal_selected;
protected:
    void on_treeview_selection_changed ()
    {
       Gtk::TreeModel::iterator iterator = m_store->get_iter(path);
       if (iterator) {
          Gtk::TreeModel::Row row = *iterator;
          IView *view = row[m_columns.view];
          signal_activated.emit(view);
       }
    }
    class ModelColumns : public Gtk::TreeModelColumnRecord {
    public:
        Gtk::TreeModelColumn<Glib::RefPtr<Gdk::Pixbuf> > icon;
        Gtk::TreeModelColumn<Glib::ustring>              name;
        Gtk::TreeModelColumn<IView*>                     view;
        ModelColumns ()
        {
            add (icon);
            add (name);
            add (view);
        }
     };
private:
    Gtk::TreeView m_treeview;
    Glib::RefPtr<Gtk::ListStore> m_store;
    ModelColumns m_columns;
    Gtk::TreeModel::iterator find (IView *view)
    {
       typedef Gtk::TreeModel::iterator iterator;
       for (iterator i = m_store->children().begin();
          i != m_store->children().end(); ++i) {
          Gtk::TreeModel::Row row = *i;
          if (row[m_columns.view] == view)
             return i;
       }
       return iterator();
    }

class Application : public Gtk::Window {
public:
    Application()
    {
       Glib::RefPtr<Gnome::Glade::Xml> glade =
          Gnome::Glade::Xml::create("app.glade", "vbox1");

       glade->get_widget("notebook4", m_notebook);
       glade->get_widget("vbox16", m_pane_sidebar);
       glade->get_widget("vbox5", m_pane_content);

       m_viewlist.signal_selected.connect(
          sigc::mem_fun(*this, &Application::on_view_selected));

       a = new ViewA();
       b = new ViewB();
       m_viewlist.append(a);
       m_viewlist.append(b);
       m_notebook->append_page(*a);
       m_notebook->append_page(*b);

       m_pane_sidebar->add(m_viewlist);

       Gtk::Widget *widget = 0;
       glade->get_widget("vbox1", widget);
       add(*widget);
       show_all();
    }
    ~Application()
    {
       delete a;
       delete b;
    }
protected:
    // Application variables
    void on_view_selected(IView *view)
    {
       int page = m_notebook->page_num (*view);
       m_notebook->set_current_page (page);
    }

    Gtk::VBox *m_pane_sidebar, *m_pane_content;
    Gtk::Notebook *m_notebook;
    DMViewList m_viewlist;
    IView *a,*b;
};

int main (int argc, char *argv[])
{
    Gtk::Main kit(argc, argv);
    Application application;
    kit.run(application);
    return 0;
}

ViewA and ViewB are some test classes with a very simple implementation:

class ViewX : public IView {
public:
    ViewX();
    ~ViewX();
    Glib::RefPtr<Gdk::Pixbuf> ViewX::icon ()
    {
       return Gdk::Pixbuf::create_from_file ("viewx.png");
    }
    Glib::ustring ViewX::name ()
    {
       return "ViewX";
    }
}

The application works fine, but closing the main window results in a 
segmentation fault (core dump). As far as I can tell (from a gdb 
backtrace) the crash is not in my own code, but somewhere inside the 
gtk(mm) library.

>> I read in the gtkmm documentation there is a Glib::RefPtr, that uses the 
>> internal gtk/gobject reference counting. If I understand that correctly, 
>> I can use this smart pointer (instead of third party implementation like 
>> boost)?
>>
>> Glib::RefPtr<Gtk::Button> a(new Gtk::Button()), b(a);
> 
> nope, don't do this.
> 
>> But I've never seen that before, only with non-widgets objects like 
>> pixbufs and treemodels.
> 
> correct.
> 
>> look like in gtkmm? Is a smart pointer going to interfere with the 
>> automatic memory management when I add the widget to the notebook? Do I 
>> need smart pointers at all for all this?
> 
> no, you don't smart pointers for anything directly related to GTKmm.
> just create widgets. if they are on the heap (allocated via new
> SomeWidget()), then wrap them with manage():
> 
>     Gtk::SomeWidget* foo = manage (new Gtk::SomeWidget())
> 
> if they are on the stack or members of objects, you don't even need to
> do that.

I was thinking that putting my IView widgets inside the notebook AND 
deleting them in the destructor somehow caused a double destruction. I 
understand now that this is not the case, but that doesn't fix my problem...

_______________________________________________
gtkmm-list mailing list
[email protected]
http://mail.gnome.org/mailman/listinfo/gtkmm-list

Reply via email to