diff options
| author | Albrecht Schlosser <albrechts.fltk@online.de> | 2019-06-27 16:04:30 +0200 |
|---|---|---|
| committer | Albrecht Schlosser <albrechts.fltk@online.de> | 2019-06-27 16:04:03 +0200 |
| commit | 42b8cb7bb8211117d2e4c0b64632458c6815e56b (patch) | |
| tree | 1defbe64677b90296e7468244c313885dae86403 | |
| parent | 44b2b7126c121d425d0856a4528db8ae5721bbbf (diff) | |
Add method Fl_Menu_::menu_end() (STR 3523)
This method can be called after all menu modifications to make sure
the menu() array is relocated (copied from the internal working area)
to a private place owned by the Fl_Menu_ instance.
menu_end() is now called in Fl_Menu_Button::popup() to make sure
the menu array is in private storage.
This fixes STR 3523 w/o user code changes. Calling menu_end() is
in most cases optional.
Todo: call menu_end() where useful (or necessary), e.g. in
Fl_Choice, Fl_Menu_Bar, etc. ?
| -rw-r--r-- | FL/Fl_Menu_.H | 24 | ||||
| -rw-r--r-- | src/Fl_Menu_Button.cxx | 8 | ||||
| -rw-r--r-- | src/Fl_Menu_add.cxx | 50 |
3 files changed, 69 insertions, 13 deletions
diff --git a/FL/Fl_Menu_.H b/FL/Fl_Menu_.H index f74670175..4cca761d9 100644 --- a/FL/Fl_Menu_.H +++ b/FL/Fl_Menu_.H @@ -3,7 +3,7 @@ // // Menu base class header file for the Fast Light Tool Kit (FLTK). // -// Copyright 1998-2016 by Bill Spitzak and others. +// Copyright 1998-2019 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 @@ -95,8 +95,25 @@ public: /** Returns a pointer to the array of Fl_Menu_Items. This will either be - the value passed to menu(value) or the private copy. - \sa size() -- returns the size of the Fl_Menu_Item array. + the value passed to menu(value) or the private copy or an internal + (temporary) location (see note below). + + \note <b>Implementation details - may be changed in the future.</b> + All modifications of the menu array are done by copying the entire + menu array to an internal storage for optimization of memory + allocations, for instance when using add() or insert(). While this + is done, menu() returns the pointer to this internal location. The + entire menu will be copied back to private storage when needed, + i.e. when \b another Fl_Menu_ is modified. You can force this + reallocation after you're done with all menu modifications by calling + Fl_Menu_::menu_end() to make sure menu() returns a permanent pointer + to private storage (until the menu is modified again). + Note also that some menu methods (e.g. Fl_Menu_Button::popup()) call + menu_end() internally to ensure a consistent menu array while the + menu is open. + + \see size() -- returns the size of the Fl_Menu_Item array. + \see menu_end() -- finish %menu modifications (optional) \b Example: How to walk the array: \code @@ -112,6 +129,7 @@ public: */ const Fl_Menu_Item *menu() const {return menu_;} + const Fl_Menu_Item *menu_end(); // in src/Fl_Menu_add.cxx void menu(const Fl_Menu_Item *m); void copy(const Fl_Menu_Item *m, void* user_data = 0); int insert(int index, const char*, int shortcut, Fl_Callback*, void* = 0, int = 0); diff --git a/src/Fl_Menu_Button.cxx b/src/Fl_Menu_Button.cxx index 74bf62430..0a5099b2c 100644 --- a/src/Fl_Menu_Button.cxx +++ b/src/Fl_Menu_Button.cxx @@ -3,7 +3,7 @@ // // Menu button widget for the Fast Light Tool Kit (FLTK). // -// Copyright 1998-2010 by Bill Spitzak and others. +// Copyright 1998-2019 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 @@ -46,8 +46,14 @@ void Fl_Menu_Button::draw() { and if they pick one it sets value() and does the callback or sets changed() as described above. The menu item is returned or NULL if the user dismisses the menu. + + \note Since FLTK 1.4.0 Fl_Menu_::menu_end() is called before the menu + pops up to make sure the menu array is located in private storage. + + \see Fl_Menu_::menu_end() */ const Fl_Menu_Item* Fl_Menu_Button::popup() { + menu_end(); const Fl_Menu_Item* m; pressed_menu_button_ = this; redraw(); diff --git a/src/Fl_Menu_add.cxx b/src/Fl_Menu_add.cxx index 57534f4e3..d29d75a42 100644 --- a/src/Fl_Menu_add.cxx +++ b/src/Fl_Menu_add.cxx @@ -3,7 +3,7 @@ // // Menu utilities for the Fast Light Tool Kit (FLTK). // -// Copyright 1998-2016 by Bill Spitzak and others. +// Copyright 1998-2019 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 @@ -44,7 +44,6 @@ extern Fl_Menu_* fl_menu_array_owner; // in Fl_Menu_.cxx // widget, and if so it reallocates as necessary. - // Insert a single Fl_Menu_Item into an array of size at offset n, // if this is local_array it will be reallocated if needed. static Fl_Menu_Item* array_insert( @@ -376,13 +375,7 @@ int Fl_Menu_::insert( // make this widget own the local array: if (this != fl_menu_array_owner) { if (fl_menu_array_owner) { - Fl_Menu_* o = fl_menu_array_owner; - // the previous owner gets its own correctly-sized array: - int value_offset = (int) (o->value_-local_array); - int n = local_array_size; - Fl_Menu_Item* newMenu = o->menu_ = new Fl_Menu_Item[n]; - memcpy(newMenu, local_array, n*sizeof(Fl_Menu_Item)); - if (o->value_) o->value_ = newMenu+value_offset; + fl_menu_array_owner->menu_end(); } if (menu_) { // this already has a menu array, use it as the local one: @@ -495,6 +488,45 @@ void Fl_Menu_::remove(int i) { memmove(item, next_item, (menu_+n-next_item)*sizeof(Fl_Menu_Item)); } +/** + Finishes menu modifications and returns menu(). + + Call menu_end() after using add(), insert(), remove(), or any other + methods that may change the menu array if you want to access the + menu array anytime later with menu(). This should be called only + once after the \b last menu modification for performance reasons. + + Does nothing if the menu array is already in a private location. + + Some methods like Fl_Menu_Button::popup() call this method before + their menu is opened. + + \note After menu changes like add(), insert(), etc. menu() would + return a pointer to a temporary internal menu array that may be + relocated at unexpected times. This is due to performance + considerations and may be changed w/o further notice. + + \since 1.4.0 + + \returns New Fl_Menu_Item array pointer. + + \see Fl_Menu_::menu() +*/ + +const Fl_Menu_Item *Fl_Menu_::menu_end() { + if (menu_ == local_array && fl_menu_array_owner == this) { + // copy the menu array to a private correctly-sized array: + int value_offset = (int)(value_ - local_array); + int n = local_array_size; + Fl_Menu_Item* newMenu = menu_ = new Fl_Menu_Item[n]; + memcpy(newMenu, local_array, n * sizeof(Fl_Menu_Item)); + if (value_) + value_ = newMenu + value_offset; + } + fl_menu_array_owner = 0; + return menu_; +} + // // End of "$Id$". // |
