From: Gustavo S. B. <bar...@pr...> - 2009-07-17 17:47:09
|
On Fri, Jul 17, 2009 at 12:52 PM, Andreas Volz<li...@br...> wrote: > Am Fri, 17 Jul 2009 10:38:04 -0300 schrieb Gustavo Sverzut Barbieri: > >> On Fri, Jul 17, 2009 at 6:13 AM, Andreas Volz<li...@br...> >> wrote: >> > Hello, >> > >> > while wrapping Elementary to C++ I have this problem: >> > >> > How could I find out in the parent container widget that a child >> > widget has been added or removed. I tried the "sub-object-add" and >> > "sub-object-del" callback, but it's not what I want as it calls this >> > signal more often than when I add/del an object to a container. >> > Maybe the member_add and member_del callbacks in ESMART are what I >> > need, but they're not used in Elementary. Any other ideas? >> >> member_add() should be called on children, at least that's what I >> remember... if not I guess is missing as one object should contain the >> children (given the container member). >> >> anyway, I wish I had time to merge guarana and elementary as guarana >> way of creating widgets makes things much easier for bindings and all. > > Any ideas when you've time for it. Then I'll stop my work and continue > after this merge. No idea other than "not soon". Really, the changes are nothing that different, just require lots of effort to port it and i don't have that time now. So don't halt your work for that, but keep in mind it could change in future The major change, if someone want to implement, is to follow ClippedSmartObject, Box and Table way of doing inheritance. It would be extending Evas_Smart_Class and overriding methods, possibly calling methods from parent class and such. This is in contrast with current codebase that just have one "widget" class where you set hooks when objects are created. Things would be much easier to wrappers since you could check for Evas_Smart_Class. >> > I tried to suicide my C++ object if the C object deletes itself and >> > throws the delete signal, but that's a very bad design. It's the job >> > of the container to destroy the widgets. >> >> this is the way to go. Each shell/wrapper object should listen to >> EVAS_CALLBACK_DEL and EVAS_CALLBACK_FREE (pre/post memory being >> deleted) and either delete itself or make it shallow (make the now >> dead wrapped pointer NULL). > > I'll show you my current implementation and the problem I have with it. For more > code look in SVN... > > ElmWidget is the base class of all Elementary widgets and EvasSmart itself. > > #ifdef HAVE_CONFIG_H > #include <config.h> > #endif > > #include "../include/elementaryxx/ElmWidget.h" > > using namespace std; > > namespace efl { > > ElmWidget::ElmWidget () > { > > } > > ElmWidget::~ElmWidget () > { > } > > void ElmWidget::elmInit () > { > init (); // call init() from EvasObject > > // this is EVAS_CALLBACK_FREE > signalHandleFree.connect (sigc::mem_fun (this, &ElmWidget::freeSignalHandler)); > } > > void ElmWidget::freeSignalHandler () > { > //cout << "freeSignalHandler()" << endl; > mFree = false; // mark the object to don't delete the C object. In this case it's yet deleted. > delete (this); > // !!!ATTENTION!!! > // suicide for a C++ object is dangerous, but allowed > // the simple rule is that no member functions or member variables are allowed to access > // FIXME: Here is a design problem as child destructors access mFree member variable. Solution needed! > } > > Then all ElmWidgets do it like this: > > // private > ElmButton::ElmButton (EvasObject &parent) > { > o = elm_button_add (parent.obj ()); > > elmInit (); > } > > ElmButton::~ElmButton () > { > if (mFree) > { > evas_object_del (o); > } > } > > ElmButton *ElmButton::factory (EvasObject &parent) > { > return new ElmButton (parent); > } > > I use a factory design to be sure that Elementary widgets are only > constructed on the heap and could be deleted. The implementation works, > but I found a problem. After the delete(this) the destructor of ElmButton > is called and access mFree again, but it's not longer existing, as it's > as member deleted with the class itself. > > I thought about several solutions: > > 1) Make a private destructor and tell the user to use a destroy() member function. > Then the C++ destructor is empty and does nothing. This gives the library control > when to delete only the wrapper and when to delete also the C object. > > 2) Implement a global map where all deleted wrappers are marked and look in the > destructor in this map if to delete the C object or not. > > 3) As two, but let a second thread do this. More like a garbage collector. > > I think I'll check solution 1. Any comment about it. The C design here is really hard > to wrap with a good C++ design. Look at Python, the way I do it should work for you if you refcount the shell/wrapper: http://trac.enlightenment.org/e/browser/trunk/BINDINGS/python/python-evas/evas/evas.c_evas_object.pxi the wrapper it just deleted when refcount drops to 0. When object is created, it will get an extra reference since canvas owns it as well. When C object dies it looses this reference, but Python code keep its reference. If there was no python code holding references, then wrapper is really deleted. If python code holds reference, then self.obj (C object) is now NULL and this should cause no harm to users as Evas ignores obj == NULL, but I could add checkers for that and even raise exception in such case. I know that some libs (boost) do automatic refcount using operator overloading, that may be a solution for you as well. Something else is to make object destructor to check if o == NULL before calling evas_object_delete() and make o = NULL on EVAS_CALLBACK_DEL/FREE. -- Gustavo Sverzut Barbieri http://profusion.mobi embedded systems -------------------------------------- MSN: bar...@gm... Skype: gsbarbieri Mobile: +55 (19) 9225-2202 |