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