You say you like the recent "simple" API, I was looking at the 2.0.x API and it 
has four callback setup m/fs and I was suggesting replacing them with one.  
Isn't that even simpler?  Is there an even newer API?

What I should say is that my proposed replacement for the set of
overloaded "callback" m/fs wasn't so much to increase flexibility but to
try and make it safer. Setting up a callback with a function:

void callback( void (*)(Widget*, void*), void* );

is a very old C-style pattern.  The description in the tutorial of how to 
connect an object into this using a static member function and passing the 
"this" pointer as the void* was how original C++ code plugged into C-style APIs 
with this callback mechanism.  Of course the danger is that it requires the 
user to type cast the void* back to the right type.

I think the point I am trying to make is that FLTK is a C++ API and as
such can avoid the need for type casting, one way being the method I
suggested.  From this perspective Fl_Signal is just a fix to this C-Style part 
of the, what should be a C++, API.

As I said, I have only been looking at FLTK a couple of days so I am not
that familiar with it or its history.  My discussion is really more
idealistic than practical i.e. what would the perfect FLTK C++ API look
like wrt setting up callbacks?

You bring up a problem of users needing to destroy the user_data when the 
widget goes.  With the method I propose there is no "user data", the
widget simply has a reference to a functor and what you bring up is sort
of a separate issue.  Now if user data was required it would be in the
functor or an object referenced by the functor.  But you are right, a
developer will often want to clean up these objects if they are only
required when the widget exists.

One easy solution is for handlers to derive from the widget and receive
the callback by overriding a virtual function. When the widget goes the
the user data is tidied up because it "is" the widget.  The downside of
this is it adds to already deep hierarchies which can be difficult to
understand/debug.  More generally, high coupling is considered
undesirable and there is no more higher coupling than inheritance.
Inheritance should only be used when you have a true "is a"
relationship.  What we have is a "button handler" not a "button".

The other solution would be to have an abstract receiver class:

struct Receiver {
        virtual void handle(Widget*) = 0;
        virtual ~Receiver() {}
};

If users' classes want callbacks they inherit this class and then in
Widget we would have:

        void callback(shared_ptr<Receiver> r);

If the programmer keeps their own shared_ptr to the receiver then the
Receiver will continue to exist when the Widget disappears, if they don't then 
the Receiver gets deleted when the Widget disappears.  Note that shared_ptr is 
in the new C++ standard for 2010, so for the moment you would have to use 
boost::shared_ptr.

Mike.


> I actually like the recent simple system - otherwise the hunger always
> grows and at some point somebody will want multiple callback, subcalls
> etc. The system actually allows to build powerful "external" callback
> system (see Fl_Signal extension in the baasar - shameless plug).
>
> That said you have a valid point that widget class could be more
> flexible. One thing I am missing in the widget class is possibility to
> destruct user_data()  - ie by a simple "plugin" system which would
> control lifespan of other objects. Two possible solution come to my mind:
>
> 1) An extra pointer to some plugin list within the widget.
>
> 2) Possibility to "destruct" user_data() when widget is destructed by an
> extra call during destruction
>
> I do not like the first solution too much (an extra data within widget,
> existence of a special "plugin" class, ...) so lets elaborate on the
> second possibility.
>
> Lets have an extra bit like FL_DESTRUCTION_CALLBACK among the flags()
> and two functions to assign callback:
>
>
> 1) Old-style callback:
> ----------------------
> void Fl_Widget::callback(Fl_Callback * c, void *user_data = 0){
>   destruct_user_data(); // check for the special user data dest.
>   callback_ = c; user_data = user_data;
>   clear_flag(FL_DESTRUCTION_CALLBACK);
> }
>
> 2) New user_data-destructed callback:
> ------------------------------------
> void Fl_Widget::destructed_callback(Fl_Callback* c, void* user_data=0){
>   destruct_user_data();
>   callback_ = c; user_data = user_data;
>   set_flag(FL_DESTRUCTION_CALLBACK);
> }
>
> and within Fl_Widget destructor:
>
> Fl_Widget::~Fl_Widget(){
>     ...
>     destruct_user_data()
> }
>
> // protected or private:
> void Fl_Widget::destruct_user_data(){
>   if(flags()&FL_DESTRUCTION_CALLBACK && callback_)
>      callback_(0, user_data());
> }
>
>
>
>
> Now you see  that destruct_user_data(), called during widget
> destruction, there is one last call to the callback function but -
> unlike during normal call - this time with "null" as the widget
> argument. This is logical because the widget can already be partially
> destructed so there is not much use of it. It also allows callback
> function to recognize that this is NOT normal call but the "destruction"
>  and it should do something with the user data. Your callback can be then:
>
> void my_callback(Fl_Widget * w, void * data){
>   if(w){ // do normal call
>       ...
>       ...
>   }else{ // last call during widget destruction, destructing user data!
>      delete ((My_Callback_Structure *)data);
>   }
> }
>
> The advantage of above solution is that it is simple, backward
> compatible, does nor use any extra data within the widget but allows to
> build powerful system above the existing callbacks and control the
> destruction of user_data() by the widget.
>
> R.
>
>
>
>
>
>
>
> Mike wrote:
> > Hi all,
> >
> > I've just started looking at FLTK (like it lots already) and I have been 
> > reading through the forums.
> > Four years ago there was discussion about updating the callback mechanism 
> > to use functors.  It seems to have died off because, obviously, it used 
> > templates whose support was patchy in places at the time.  I think it is 
> > fair to say this is no longer true.
> > Are there any plans to replace the several overloaded "callback" methods 
> > with a single:
> >
> > template <typename F> void callback(F& f);
> >
> > This single m/f could handle being passed pointer to function taking 
> > Widget* (so is backwards compatible that far) as well as functors.  Using 
> > binding it also handles calling functions and m/fs with any signature, 
> > which makes this interface cleaner as well as more powerful.
> >
> > Just thought it might be worth reigniting this discussion, now that 
> > templates are widely supported.
> >
> > Mike.

_______________________________________________
fltk-dev mailing list
fltk-dev@easysw.com
http://lists.easysw.com/mailman/listinfo/fltk-dev

Reply via email to