Improve docs of Fl_Widget::callback() and do_callback().

Clarify that all variants of do_callback() call clear_changed() after
the callback and that 'long Fl_Widget::argument()' may truncate the
user_data value on some (particularly Windows 64-bit) platforms.

Some code has been reformatted and refactored with better variable names,
but there are no effective code changes.

Obsolete, inactive code was removed.


git-svn-id: file:///fltk/svn/fltk/branches/branch-1.4@12345 ea41ed52-d2ee-0310-a9c1-e6b18d33e121
This commit is contained in:
Albrecht Schlosser 2017-07-20 15:16:37 +00:00
parent db1f29fdb5
commit a8c4f77d50
2 changed files with 99 additions and 68 deletions

View File

@ -549,26 +549,29 @@ public:
\param[in] cb new callback
\param[in] p user data
*/
void callback(Fl_Callback* cb, void* p) {callback_=cb; user_data_=p;}
void callback(Fl_Callback* cb, void* p) {callback_ = cb; user_data_ = p;}
/** Sets the current callback function for the widget.
Each widget has a single callback.
\param[in] cb new callback
*/
void callback(Fl_Callback* cb) {callback_=cb;}
void callback(Fl_Callback* cb) {callback_ = cb;}
/** Sets the current callback function for the widget.
Each widget has a single callback.
\param[in] cb new callback
*/
void callback(Fl_Callback0*cb) {callback_=(Fl_Callback*)cb;}
void callback(Fl_Callback0* cb) {callback_ = (Fl_Callback*)cb;}
/** Sets the current callback function for the widget.
Each widget has a single callback.
\param[in] cb new callback
\param[in] p user data
*/
void callback(Fl_Callback1*cb, long p=0) {callback_=(Fl_Callback*)cb; user_data_=(void*)(fl_intptr_t)p;}
void callback(Fl_Callback1* cb, long p = 0) {
callback_ = (Fl_Callback*)cb;
user_data_ = (void*)(fl_intptr_t)p;
}
/** Gets the user data for this widget.
Gets the current user data (void *) argument that is passed to the callback function.
@ -583,14 +586,24 @@ public:
void user_data(void* v) {user_data_ = v;}
/** Gets the current user data (long) argument that is passed to the callback function.
\todo The user data value must be implemented using \em intptr_t or similar
to avoid 64-bit machine incompatibilities.
*/
\note On platforms with <tt>sizeof(long) \< sizeof(void*)</tt>, particularly
on Windows 64-bit platforms, this method can truncate stored addresses
\p (void*) to the size of a \p long value. Use with care and only
if you are sure that the stored user_data value fits in a \p long
value because it was stored with argument(long) or another method
using only \p long values. You may want to use user_data() instead.
\see user_data()
\todo [Internal] The user_data value must be implemented using
\p fl_intptr_t or similar to avoid 64-bit platform incompatibilities.
*/
long argument() const {return (long)(fl_intptr_t)user_data_;}
/** Sets the current user data (long) argument that is passed to the callback function.
\todo The user data value must be implemented using \em intptr_t or similar
to avoid 64-bit machine incompatibilities.
\see argument()
*/
void argument(long v) {user_data_ = (void*)(fl_intptr_t)v;}
@ -759,10 +772,13 @@ public:
Most widgets turn this flag off when they do the callback, and when
the program sets the stored value.
\retval 0 if the value did not change
\see set_changed(), clear_changed()
\note do_callback() turns this flag off after the callback.
\retval 0 if the value did not change
\see set_changed(), clear_changed()
\see do_callback(Fl_Widget *widget, void *data)
*/
unsigned int changed() const {return flags_&CHANGED;}
unsigned int changed() const {return flags_ & CHANGED;}
/** Marks the value of the widget as changed.
\see changed(), clear_changed()
@ -819,42 +835,54 @@ public:
\retval 0 if this widget has no visible focus.
\see visible_focus(int), set_visible_focus(), clear_visible_focus()
*/
unsigned int visible_focus() { return flags_ & VISIBLE_FOCUS; }
unsigned int visible_focus() { return flags_ & VISIBLE_FOCUS; }
/** The default callback for all widgets that don't set a callback.
This callback function puts a pointer to the widget on the queue
returned by Fl::readqueue().
returned by Fl::readqueue(). This is the default for all widgets
if you don't set a callback.
You can avoid the overhead of this default handling if you set the
callback to \p NULL explicitly.
Relying on the default callback and reading the callback queue with
Fl::readqueue() is not recommended. If you need a callback, you should
set one with Fl_Widget::callback(Fl_Callback *cb, void *data)
or one of its variants.
\param[in] cb the widget given to the callback
\param[in] d user data associated with that callback
\param[in] widget the Fl_Widget given to the callback
\param[in] data user data associated with that callback
\see callback(), do_callback(), Fl::readqueue()
\see callback(), Fl::readqueue()
\see do_callback(Fl_Widget *widget, void *data)
*/
static void default_callback(Fl_Widget *cb, void *d);
static void default_callback(Fl_Widget *widget, void *data);
/** Calls the widget callback.
Causes a widget to invoke its callback function with default arguments.
\see callback()
*/
void do_callback() {do_callback(this,user_data_);}
/** Calls the widget callback function with default arguments.
/** Calls the widget callback.
Causes a widget to invoke its callback function with arbitrary arguments.
\param[in] o call the callback with \p o as the widget argument
\param[in] arg call the callback with \p arg as the user data argument
\see callback()
*/
void do_callback(Fl_Widget* o,long arg) {do_callback(o,(void*)(fl_intptr_t)arg);}
This is the same as calling
\code
do_callback(this, user_data());
\endcode
\see callback()
\see do_callback(Fl_Widget *widget, void *data)
*/
void do_callback() {do_callback(this, user_data_);}
/** Calls the widget callback function with arbitrary arguments.
\param[in] widget call the callback with \p widget as the first argument
\param[in] arg call the callback with \p arg as the user data (second) argument
\see callback()
\see do_callback(Fl_Widget *widget, void *data)
*/
void do_callback(Fl_Widget *widget, long arg) {
do_callback(widget, (void*)(fl_intptr_t)arg);
}
// Causes a widget to invoke its callback function with arbitrary arguments.
// Documentation and implementation in Fl_Widget.cxx
void do_callback(Fl_Widget* o,void* arg=0);
void do_callback(Fl_Widget *widget, void *arg = 0);
/* Internal use only. */
int test_shortcut();
@ -879,7 +907,7 @@ public:
\param[in] wgt the possible parent widget.
\see contains()
*/
int inside(const Fl_Widget* wgt) const {return wgt ? wgt->contains(this) : 0;}
int inside(const Fl_Widget *wgt) const {return wgt ? wgt->contains(this) : 0;}
/** Schedules the drawing of the widget.
Marks the widget as needing its draw() routine called.
@ -957,7 +985,7 @@ public:
void my_callback (Fl_Widget *w, void *) {
Fl_Group *g = w->as_group();
if (g)
printf ("This group has %d children\n",g->children());
printf ("This group has %d children\n", g->children());
else
printf ("This widget is not a group!\n");
}

View File

@ -3,7 +3,7 @@
//
// Base widget class for the Fast Light Tool Kit (FLTK).
//
// Copyright 1998-2010 by Bill Spitzak and others.
// Copyright 1998-2017 by Bill Spitzak and others.
//
// This library is free software. Distribution and use rights are outlined in
// the file "COPYING" which should have been included with this file. If this
@ -36,17 +36,8 @@ const int QUEUE_SIZE = 20;
static Fl_Widget *obj_queue[QUEUE_SIZE];
static int obj_head, obj_tail;
void Fl_Widget::default_callback(Fl_Widget *o, void * /*v*/) {
#if 0
// This is necessary for strict forms compatibility but is confusing.
// Use the parent's callback if this widget does not have one.
for (Fl_Widget *p = o->parent(); p; p = p->parent())
if (p->callback() != default_callback) {
p->do_callback(o,v);
return;
}
#endif
obj_queue[obj_head++] = o;
void Fl_Widget::default_callback(Fl_Widget *widget, void * /*v*/) {
obj_queue[obj_head++] = widget;
if (obj_head >= QUEUE_SIZE) obj_head = 0;
if (obj_head == obj_tail) {
obj_tail++;
@ -75,9 +66,9 @@ void Fl_Widget::default_callback(Fl_Widget *o, void * /*v*/) {
*/
Fl_Widget *Fl::readqueue() {
if (obj_tail==obj_head) return 0;
Fl_Widget *o = obj_queue[obj_tail++];
Fl_Widget *widget = obj_queue[obj_tail++];
if (obj_tail >= QUEUE_SIZE) obj_tail = 0;
return o;
return widget;
}
/*
This static internal function removes all pending callbacks for a
@ -192,9 +183,9 @@ Fl_Widget::~Fl_Widget() {
if (callback_ == default_callback) cleanup_readqueue(this);
}
/** Draws a focus box for the widget at the given position and size */
void
Fl_Widget::draw_focus(Fl_Boxtype B, int X, int Y, int W, int H) const {
/** Draws a focus box for the widget at the given position and size. */
void Fl_Widget::draw_focus(Fl_Boxtype B, int X, int Y, int W, int H) const {
if (!Fl::visible_focus()) return;
switch (B) {
case FL_DOWN_BOX:
@ -284,8 +275,7 @@ int Fl_Widget::contains(const Fl_Widget *o) const {
}
void
Fl_Widget::label(const char *a) {
void Fl_Widget::label(const char *a) {
if (flags() & COPIED_LABEL) {
// reassigning a copied label remains the same copied label
if (label_.value == a)
@ -298,8 +288,7 @@ Fl_Widget::label(const char *a) {
}
void
Fl_Widget::copy_label(const char *a) {
void Fl_Widget::copy_label(const char *a) {
// reassigning a copied label remains the same copied label
if ((flags() & COPIED_LABEL) && (label_.value == a))
return;
@ -311,19 +300,33 @@ Fl_Widget::copy_label(const char *a) {
}
}
/** Calls the widget callback.
/** Calls the widget callback function with arbitrary arguments.
Causes a widget to invoke its callback function with arbitrary arguments.
All overloads of do_callback() call this method.
It does nothing if the widget's callback() is NULL.
It clears the widget's \e changed flag \b after the callback was
called unless the callback is the default callback. Hence it is not
necessary to call clear_changed() after calling do_callback()
in your own widget's handle() method.
\param[in] o call the callback with \p o as the widget argument
\param[in] arg use \p arg as the user data argument
\note It is legal to delete the widget in the callback (i.e. in user code),
but you must not access the widget in the handle() method after
calling do_callback() if the widget was deleted in the callback.
We recommend to use Fl_Widget_Tracker to check whether the widget
was deleted in the callback.
\param[in] widget call the callback with \p widget as the first argument
\param[in] arg use \p arg as the user data (second) argument
\see default_callback()
\see callback()
\see class Fl_Widget_Tracker
*/
void
Fl_Widget::do_callback(Fl_Widget* o,void* arg) {
void Fl_Widget::do_callback(Fl_Widget *widget, void *arg) {
if (!callback_) return;
Fl_Widget_Tracker wp(this);
callback_(o,arg);
callback_(widget, arg);
if (wp.deleted()) return;
if (callback_ != default_callback)
clear_changed();