Re: Equivalent of the gtk g_object_ref/unref functions in gtkmm?



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...




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