Minimum user base according to our last poll (rounded, and I am sure that many 
users do not participate in polls):

FLTK 1.0.x:  40
FLTK 1.1.x: 400
FLTK 1.3.x: 200
FLTK 2.x.x: 360

possible user base if everyone agrees to move to FLTK 3.0: >1000

End of confusion why 1.3 is active and 2.0 is dead? Priceless (tm).


Hi,

those of you who read the commit logs will have been blasted with huge commits 
in the FLTK 3.0 branch. Yes, I am actively developing this again, and guess 
what, so far I believe I am pretty successful. 

This is how it works (plus some trickery):

the FLTK3 header reside in ./fltk3, FLTK2 headers remain in ./fltk, and the 
FLTK1 headers are as always in ./FL. The source code also stays in ./src, and 
even the individual source file names remained the same. Using the current 
FLTK1 makefiles and IDEs should be no problem!

All code in ./src is currently renamed into FLTK2 style naming (namespace is 
fltk3 though) which is a lot more logical than the FLTK1 naming ever was. Other 
than that, FLTK3 is internally a find/replace version of FLTK1 plus a hand full 
of minor features. When done, the FLTK3 source code should be as stable as the 
FLTK1 core, and as readable. Almost no extras were introduced to allow FLTK1 
and FLTK2 wrapping.

So how does the wrapping work? All FLTK1 and FLTK2 emulation is done in header 
file only! There is no extra code to link! Just make sure that the correct 
headers are found and you are good to go. 

Emulation works like this: the FLTK3 base class has a new member called 
"wrapper". The wrapper points to another class that is the emulation layer. 
This can be FLTK1, FLTK2, or any other interface or language binding for that 
matter. All FLTK1 and FLTK2 classes are derive from fltk3::Wrapper and have 
only a single member variable _p, which points to the FLTK3 implementation of 
the class. The emulation layer redirects all calls to FLTK1 and 2 into new 
calls in FLTK3. Once the emulation layers are complete (and there is a definite 
end if we stop writing 1.3 and 2.x core code), we can change pretty much 
everything in FLTK3, while always keeping the API for FLTK1 and FLTK2. Tadaa, 
frozen in time!

I have written wrappers for a bunch of classes, implementing some of the 
commonly used methods. The result is in 
http://svn.easysw.com/public/fltk/fltk/branches/branch-3.0 . Some of the test 
programs (hello, button, buttons, label) have three versions. hello1.cxx is the 
original FLTK1 hello program and compiles and runs without a single change in 
source code or makefile! hello2.cxx is the FLTK2 original and again runs 
without touching the source code or makefile! Well, hello.cxx is what could be 
called "native FLTK3". It looks like FLTK2 and feels like FLTK1. Only the 
future will show if we can make the users of both original libraries 
comfortable with FLTK3.

Be brave! The code is quite simple. The overhead is small. Once the wrappers 
are done, I would hope to get all FLTK1 *and* FLTK2 users and developers on 
board!

- Matthias


PS: Some Details

Documentation: I remove *all* documentation from FLTK1 and FLTK2 wrappers. 
FLTK3 keeps all doxygen comments and should still generate decent docs. A few 
manual changes may be required.

Arguments and Return Types: if an argument is an Fl_Widget, it is translated to 
the corresponding fltk3::Widget before used as an argument. Similarly, the 
return type is translated from fltk3::Widget to Fl_Widget. Both operations are 
cheap!

Callbacks: callbacks work just as is. The trick here is that 
fltk3::Widget::do_callback checks if a wrapper exists and translates the 
Fl_Widget/fltk3::Widget pointer accordingly. This is solved.

Constructors: the emulated constructors simply create the requested widget and 
set up the wrapper. Two lines of code.

Destructors: ah, now it gets more difficult. This has not been tested yet, but 
basically whichever destructor is called first (Original or Wrappe) will first 
unlink itself and then call the other destructor.

Interfacing: FLTK1, 2, and 3 code can happily coexist in a single application! 
However, calling a wrapper function will always return arguments in the wrapper 
class (myWidget->parent() returns an fltk3::Group only if myWidget is fltk3; if 
myWidget is an FLTK1 wrapper, the return value will also be an FLTK1 wrapper, 
or NULL if the parent is actually an unwrapped fltk3 widget). This is all no 
big deal if you know what's going on. Internally, all three styles live happily 
together.

Virtual Functions: this is a big cookie. The handle() function for example is a 
two-way street. It's called by the event handler, but it can also be called 
from the outside. This is untested, but a flag that I set somewhere will decide 
if the wrapper calls the original, or vice versa. It should solve 99% of the 
cases, if not all.

Overhead: FLTK1 and 2 code wil have one additional indirection per call. Every 
widget has a sister widget which is just one pointer in size. I am sure this is 
bearable for most systems.

Questions?

Please feel free to ask.


_______________________________________________
fltk-dev mailing list
[email protected]
http://lists.easysw.com/mailman/listinfo/fltk-dev

Reply via email to