summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthias Melcher <fltk@matthiasm.com>2006-04-27 21:40:47 +0000
committerMatthias Melcher <fltk@matthiasm.com>2006-04-27 21:40:47 +0000
commitad0fc9ca23717b46639d2f28a83437300499870d (patch)
tree80502551cd9ec6701c76c5942a8bd6466376f945
parentcbbec03b5e44e8855dbcf424150be5e144044fb2 (diff)
STR #1162: Fl_Menu_Button::popup was trying to access a previously deleted widget (itself). The delayed deleting mechanism in 'Fl::delete_widget' did not work in this case because the main loop is called before the callback returns. The fix implements a type of automatic pointer that will be cleared to NULL should the widget get deleted. This may not be a 'nice' solution, but it does fix the problem reliably. We could actually use this for all widget pointers and remove the delayed delete mechanism alltogether
git-svn-id: file:///fltk/svn/fltk/branches/branch-1.1@5037 ea41ed52-d2ee-0310-a9c1-e6b18d33e121
-rw-r--r--CHANGES2
-rw-r--r--FL/Fl.H3
-rw-r--r--src/Fl.cxx47
-rw-r--r--src/Fl_Menu_Button.cxx5
-rw-r--r--src/Fl_Widget.cxx1
5 files changed, 57 insertions, 1 deletions
diff --git a/CHANGES b/CHANGES
index ebbe491a9..ce8822f7a 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,5 +1,7 @@
CHANGES IN FLTK 1.1.8
+ - Fixed usage of deleted object after menu pulldown
+ (STR #1162)
- Calling fl_font(0, 0) under Xft would access a NULL
pointer (STR #1205)
- Setting a new value in Fl_Input_ wil now actually move
diff --git a/FL/Fl.H b/FL/Fl.H
index cde76a4f9..d3cabd59d 100644
--- a/FL/Fl.H
+++ b/FL/Fl.H
@@ -271,6 +271,9 @@ public:
// Widget deletion:
static void delete_widget(Fl_Widget *w);
static void do_widget_deletion();
+ static void watch_widget_pointer(Fl_Widget *&w);
+ static void release_widget_pointer(Fl_Widget *&w);
+ static void clear_widget_pointer(Fl_Widget const *w);
};
#endif // !Fl_H
diff --git a/src/Fl.cxx b/src/Fl.cxx
index c9dcd0a6c..72ea71414 100644
--- a/src/Fl.cxx
+++ b/src/Fl.cxx
@@ -1207,6 +1207,53 @@ Fl::do_widget_deletion() {
num_dwidgets = 0;
}
+static Fl_Widget ***widget_watch = 0;
+static int num_widget_watch = 0;
+static int max_widget_watch = 0;
+
+void Fl::watch_widget_pointer(Fl_Widget *&w)
+{
+ Fl_Widget **wp = &w;
+ int i;
+ for (i=0; i<num_widget_watch; ++i) {
+ if (widget_watch[i]==wp) return;
+ }
+ for (i=0; i<num_widget_watch; ++i) {
+ if (widget_watch[i]==0L) {
+ widget_watch[i] = wp;
+ return;
+ }
+ }
+ if (num_widget_watch==max_widget_watch) {
+ max_widget_watch += 8;
+ widget_watch = (Fl_Widget***)realloc(widget_watch, sizeof(Fl_Widget**)*max_widget_watch);
+ }
+ widget_watch[num_widget_watch++] = wp;
+}
+
+void Fl::release_widget_pointer(Fl_Widget *&w)
+{
+ Fl_Widget **wp = &w;
+ int i;
+ for (i=0; i<num_widget_watch; ++i) {
+ if (widget_watch[i]==wp) {
+ widget_watch[i] = 0L;
+ return;
+ }
+ }
+}
+
+void Fl::clear_widget_pointer(Fl_Widget const *w)
+{
+ if (w==0L) return;
+ int i;
+ for (i=0; i<num_widget_watch; ++i) {
+ if (widget_watch[i] && *widget_watch[i]==w) {
+ *widget_watch[i] = 0L;
+ }
+ }
+}
+
//
// End of "$Id$".
diff --git a/src/Fl_Menu_Button.cxx b/src/Fl_Menu_Button.cxx
index 80768a6e0..a3c13a829 100644
--- a/src/Fl_Menu_Button.cxx
+++ b/src/Fl_Menu_Button.cxx
@@ -51,6 +51,8 @@ const Fl_Menu_Item* Fl_Menu_Button::popup() {
const Fl_Menu_Item* m;
pressed_menu_button_ = this;
redraw();
+ Fl_Widget *mb = this;
+ Fl::watch_widget_pointer(mb);
if (!box() || type()) {
m = menu()->popup(Fl::event_x(), Fl::event_y(), label(), mvalue(), this);
} else {
@@ -58,7 +60,8 @@ const Fl_Menu_Item* Fl_Menu_Button::popup() {
}
picked(m);
pressed_menu_button_ = 0;
- redraw();
+ if (mb) mb->redraw();
+ Fl::release_widget_pointer(mb);
return m;
}
diff --git a/src/Fl_Widget.cxx b/src/Fl_Widget.cxx
index 3c637767b..9f33b2cf3 100644
--- a/src/Fl_Widget.cxx
+++ b/src/Fl_Widget.cxx
@@ -133,6 +133,7 @@ extern void fl_throw_focus(Fl_Widget*); // in Fl_x.cxx
// However, it is only legal to destroy a "root" such as an Fl_Window,
// and automatic destructors may be called.
Fl_Widget::~Fl_Widget() {
+ Fl::clear_widget_pointer(this);
if (flags() & COPIED_LABEL) free((void *)(label_.value));
parent_ = 0; // Don't throw focus to a parent widget.
fl_throw_focus(this);