Mike wrote:
> 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?

It is essentially the same system as 1.1, the callback is overloaded
just to pass user_data with different syntax.


> 
> void callback( void (*)(Widget*, void*), void* );
> 
> is a very old C-style pattern.  

It is nothing wrong with this "very old C" style ... if it is flexible
enought. You can use user_data for your callaback object, have a single
wrapper function to call it and build an API to automatically assign
this wrapper and create the callback object - see Functor below


> The description in the tutorial of how to connect an object into this using a 
> static member function

The reason is that only ordinary "c" function can be a callback here;
class static function is completely the same animal (just inside a
namespace)


> 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

I agree that typesafety and flexibility is the goal, but I think it does
not need to be a part of Fl_Widget class. Having callback structure
"outside" the widget has a few advantages, like callback lifetime
management. Suppose widget A calls some object B method. Who should be
responsible for removal of  calback (in other words to whom it should
belong), A or B? Preferably both and callback should be removed by the
first who dies, ie if it is B it must inform A not to call it amymore.
Also attaching callbacks to non-widget objects, making callback chain or
tree propagation is easier.


> suggested.  From this perspective Fl_Signal is just a fix to this C-Style 
> part of the, what should be a C++, API.

and

> idealistic than practical i.e. what would the perfect FLTK C++ API look
> like wrt setting up callbacks?

I was looking to various callback systems: libsigc++, boost::singal, QT
signal/slot stuff and was not too much happy with any of them...

I see that good system should:


1) Be typesafe

2) Accept multiple callbacks so you do not need to define a list and
write a wrapper which would call this list. This also allows possibility
to make a call for many object - ie some single setting controls
appearance of many objects.

3) Accept any form of function, method (or operator) as callback. You do
not want to write any wrappers or subclass stock widgets just to add the
accepted syntax for the functionality what is already there by the means
of other functions or to define ugly signals and slots (hello, QT). This
means that making subcalls should be also available with possibility of
the use of return values as parameters to other functions

4)Should be flexible how to define the arguments to the function:
 - by value
 - by pointer to a variable
 - by a return value of some other function/method by making a subcall

5) Have good lifetime management and means to control when the callback
is removed




Essentially you should be able to do single-line callback assign  what
you would write normaly in single-line C code, so if you want to do
within the callback

  object1->method(var1, 6.3, object2->method2(function2(), var2));

would translate to callback assignment syntax

  callback(object, &Object1::method, &var1, 6.3, call(object2,
&Object2::method2, call(function2)));

and this exactly what Fl_Signal does. But instead of assigning callback like

  widget->callback(object, &Object1::method, &var1, ...)

it places the "widget" as the first parameter within the callback
constructor:

  Fl_Call(widget, object, &Object::method, &var1, ...)

I think it achieves all goals but 5) only partially: widget can not
automatically control the callback lifespan and you need to delete it
explicitly. And that is why I was asking for this "destructed callback"
functionality




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


You can already do that: place your "real" data in your functor and use
user_data() for your functor pointer, like:




class Functor{
  ... //some_internal
void operator (){ call_from_internal_data();}

template <typename T, ...>
Functor(T t, ..){ ... /* build internal data*/}
... // more constructors with more parameters

}

void functor_wrapper(Fl_Widget * w, void * data){
   (Functor *)data)->();
}

template <typename T, ...>
Functor * callback(Fl_Widget * w, T callback_function, ...){
  Functor * f = new Functor(callback_function, ...)
  w->callback(&functor_wrapper, f, ...));
  return f;
}

void destroy_functor(Fl_Widget * w){
  if(w->callback() == &functor_wrapper){// only destroying true functors
     delete (Functor *)(w->data());
     w->callback(0,0);
  }
}


and then type-safely write

   callback(widget, function, ...);

and later

   destroy_callback(widget);


> 
>       void callback(shared_ptr<Receiver> r);
> 

I do not think we want to use std template library too much because then
you need to link to libstdc++ : I always compile c++ code with "gcc" and
not "g++" to avoid linking to that beast (but this my be only my
personal detaste with stdc++ - rather writing my own templates)

One more thing: you said that templates are supported well with recent
compilers. This is only partially true: When I was witting it (a few
ears ago), I was trying to use not very advanced template functionality
bud still had to go around many bugs in their implementations. And I was
testing it only with gcc and MS visual studio!
So I think we should avoid the use of templates in fltk core at any cost.

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

Reply via email to