FLUID: fixes crash bug in Fl_Sys_Men_Bar inside a Class. #977
This commit is contained in:
parent
8cffbd6941
commit
d265009b66
@ -290,19 +290,49 @@ void Fl_Menu_Item_Type::write_static(Fd_Code_Writer& f) {
|
|||||||
f.write_c("\n");
|
f.write_c("\n");
|
||||||
// Matt: disabled f.tag(FD_TAG_MENU_CALLBACK, get_uid());
|
// Matt: disabled f.tag(FD_TAG_MENU_CALLBACK, get_uid());
|
||||||
f.write_c("}\n");
|
f.write_c("}\n");
|
||||||
|
|
||||||
|
// If the menu item is part of a Class or Widget Class, FLUID generates
|
||||||
|
// a dummy static callback which retrieves a pointer to the class and then
|
||||||
|
// calls the original callback from within the class context.
|
||||||
|
// k is the name of the enclosing class (or classes)
|
||||||
if (k) {
|
if (k) {
|
||||||
|
// Implement the callback as a static member function
|
||||||
f.write_c("void %s::%s(Fl_Menu_* o, %s v) {\n", k, cn, ut);
|
f.write_c("void %s::%s(Fl_Menu_* o, %s v) {\n", k, cn, ut);
|
||||||
f.write_c("%s((%s*)(o", f.indent(1), k);
|
// Find the Fl_Menu_ container for this menu item
|
||||||
Fl_Type* t = parent; while (t->is_a(ID_Menu_Item)) t = t->parent;
|
Fl_Type* t = parent; while (t->is_a(ID_Menu_Item)) t = t->parent;
|
||||||
Fl_Type *q = 0;
|
if (t) {
|
||||||
// Go up one more level for Fl_Input_Choice, as these are groups themselves
|
Fl_Widget_Type *tw = (t->is_widget()) ? static_cast<Fl_Widget_Type*>(t) : NULL;
|
||||||
if (t && t->is_a(ID_Input_Choice))
|
Fl_Type *q = NULL;
|
||||||
f.write_c("->parent()");
|
// Generate code to call the callback
|
||||||
for (t = t->parent; t && t->is_widget() && !is_class(); q = t, t = t->parent)
|
if (tw->is_a(ID_Menu_Bar) && ((Fl_Menu_Bar_Type*)tw)->is_sys_menu_bar()) {
|
||||||
f.write_c("->parent()");
|
// Fl_Sys_Menu_Bar removes itself from any parent on macOS, so we
|
||||||
if (!q || !q->is_a(ID_Widget_Class))
|
// wrapped it in a class and remeber the parent class in a new
|
||||||
f.write_c("->user_data()");
|
// class memeber variable.
|
||||||
f.write_c("))->%s_i(o,v);\n}\n", cn);
|
Fl_Menu_Bar_Type *tmb = (Fl_Menu_Bar_Type*)tw;
|
||||||
|
f.write_c("%s%s* sys_menu_bar = ((%s*)o);\n", f.indent(1),
|
||||||
|
tmb->sys_menubar_proxy_name(), tmb->sys_menubar_proxy_name());
|
||||||
|
f.write_c("%s%s* parent_class = ((%s*)sys_menu_bar->_parent_class);\n",
|
||||||
|
f.indent(1), k, k);
|
||||||
|
f.write_c("%sparent_class->%s_i(o,v);\n}\n",
|
||||||
|
f.indent(1), cn);
|
||||||
|
} else {
|
||||||
|
f.write_c("%s((%s*)(o", f.indent(1), k);
|
||||||
|
// The class pointer is in the user_data field of the top widget
|
||||||
|
if (t && t->is_a(ID_Input_Choice)) {
|
||||||
|
// Go up one more level for Fl_Input_Choice, as these are groups themselves
|
||||||
|
f.write_c("->parent()");
|
||||||
|
}
|
||||||
|
// Now generate code to find the topmost widget in this class
|
||||||
|
for (t = t->parent; t && t->is_widget() && !is_class(); q = t, t = t->parent)
|
||||||
|
f.write_c("->parent()");
|
||||||
|
// user_data is cast into a pointer to the
|
||||||
|
if (!q || !q->is_a(ID_Widget_Class))
|
||||||
|
f.write_c("->user_data()");
|
||||||
|
f.write_c("))->%s_i(o,v);\n}\n", cn);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
f.write_c("#error Enclosing Fl_Menu_* not found\n");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (image) {
|
if (image) {
|
||||||
@ -700,10 +730,80 @@ Fl_Type* Fl_Input_Choice_Type::click_test(int, int) {
|
|||||||
|
|
||||||
Fl_Menu_Bar_Type Fl_Menu_Bar_type;
|
Fl_Menu_Bar_Type Fl_Menu_Bar_type;
|
||||||
|
|
||||||
|
Fl_Menu_Item menu_bar_type_menu[] = {
|
||||||
|
{"Fl_Menu_Bar",0,0,(void*)0},
|
||||||
|
{"Fl_Sys_Menu_Bar",0,0,(void*)1},
|
||||||
|
{0}};
|
||||||
|
|
||||||
|
Fl_Menu_Bar_Type::Fl_Menu_Bar_Type()
|
||||||
|
: _proxy_name(NULL)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Fl_Menu_Bar_Type::~Fl_Menu_Bar_Type() {
|
||||||
|
if (_proxy_name)
|
||||||
|
::free(_proxy_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
\brief Return true if this is an Fl_Sys_Menu_Bar.
|
||||||
|
This test fails if subclass() is the name of a class that the user may have
|
||||||
|
derived from Fl_Sys_Menu_Bar.
|
||||||
|
*/
|
||||||
|
bool Fl_Menu_Bar_Type::is_sys_menu_bar() {
|
||||||
|
if (o->type()==1) return true;
|
||||||
|
return ( subclass() && (strcmp(subclass(), "Fl_Sys_Menu_Bar")==0) );
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *Fl_Menu_Bar_Type::sys_menubar_name() {
|
||||||
|
if (subclass())
|
||||||
|
return subclass();
|
||||||
|
else
|
||||||
|
return "Fl_Sys_Menu_Bar";
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *Fl_Menu_Bar_Type::sys_menubar_proxy_name() {
|
||||||
|
if (!_proxy_name)
|
||||||
|
_proxy_name = (char*)::malloc(128);
|
||||||
|
::snprintf(_proxy_name, 63, "%s_Proxy", sys_menubar_name());
|
||||||
|
return _proxy_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Fl_Menu_Bar_Type::write_static(Fd_Code_Writer& f) {
|
||||||
|
super::write_static(f);
|
||||||
|
if (is_sys_menu_bar()) {
|
||||||
|
f.write_h_once("#include <FL/Fl_Sys_Menu_Bar.H>");
|
||||||
|
if (is_in_class()) {
|
||||||
|
// Make room for a pointer to the enclosing class.
|
||||||
|
f.write_c_once( // must be less than 1024 bytes!
|
||||||
|
"\nclass %s: public %s {\n"
|
||||||
|
"public:\n"
|
||||||
|
" %s(int x, int y, int w, int h, const char *l=NULL)\n"
|
||||||
|
" : %s(x, y, w, h, l) { }\n"
|
||||||
|
" void *_parent_class;\n"
|
||||||
|
"};\n",
|
||||||
|
sys_menubar_proxy_name(), sys_menubar_name(),
|
||||||
|
sys_menubar_proxy_name(), sys_menubar_name()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Fl_Menu_Bar_Type::write_code1(Fd_Code_Writer& f) {
|
||||||
|
super::write_code1(f);
|
||||||
|
if (is_sys_menu_bar() && is_in_class()) {
|
||||||
|
f.write_c("%s((%s*)%s)->_parent_class = (void*)this;\n",
|
||||||
|
f.indent(), sys_menubar_proxy_name(), name() ? name() : "o");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//void Fl_Menu_Bar_Type::write_code2(Fd_Code_Writer& f) {
|
||||||
|
// super::write_code2(f);
|
||||||
|
//}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////
|
||||||
// Shortcut entry item in panel:
|
// Shortcut entry item in panel:
|
||||||
|
|
||||||
|
|
||||||
void shortcut_in_cb(Fl_Shortcut_Button* i, void* v) {
|
void shortcut_in_cb(Fl_Shortcut_Button* i, void* v) {
|
||||||
if (v == LOAD) {
|
if (v == LOAD) {
|
||||||
if (current_widget->is_button())
|
if (current_widget->is_button())
|
||||||
|
@ -35,6 +35,7 @@
|
|||||||
extern Fl_Menu_Item dummymenu[];
|
extern Fl_Menu_Item dummymenu[];
|
||||||
extern Fl_Menu_Item button_type_menu[];
|
extern Fl_Menu_Item button_type_menu[];
|
||||||
extern Fl_Menu_Item menu_item_type_menu[];
|
extern Fl_Menu_Item menu_item_type_menu[];
|
||||||
|
extern Fl_Menu_Item menu_bar_type_menu[];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
\brief Manage all types on menu items.
|
\brief Manage all types on menu items.
|
||||||
@ -261,13 +262,24 @@ public:
|
|||||||
class Fl_Menu_Bar_Type : public Fl_Menu_Base_Type
|
class Fl_Menu_Bar_Type : public Fl_Menu_Base_Type
|
||||||
{
|
{
|
||||||
typedef Fl_Menu_Base_Type super;
|
typedef Fl_Menu_Base_Type super;
|
||||||
|
Fl_Menu_Item *subtypes() FL_OVERRIDE {return menu_bar_type_menu;}
|
||||||
public:
|
public:
|
||||||
|
Fl_Menu_Bar_Type();
|
||||||
|
~Fl_Menu_Bar_Type() FL_OVERRIDE;
|
||||||
const char *type_name() FL_OVERRIDE {return "Fl_Menu_Bar";}
|
const char *type_name() FL_OVERRIDE {return "Fl_Menu_Bar";}
|
||||||
const char *alt_type_name() FL_OVERRIDE {return "fltk::MenuBar";}
|
const char *alt_type_name() FL_OVERRIDE {return "fltk::MenuBar";}
|
||||||
Fl_Widget *widget(int X,int Y,int W,int H) FL_OVERRIDE {return new Fl_Menu_Bar(X,Y,W,H);}
|
Fl_Widget *widget(int X,int Y,int W,int H) FL_OVERRIDE {return new Fl_Menu_Bar(X,Y,W,H);}
|
||||||
Fl_Widget_Type *_make() FL_OVERRIDE {return new Fl_Menu_Bar_Type();}
|
Fl_Widget_Type *_make() FL_OVERRIDE {return new Fl_Menu_Bar_Type();}
|
||||||
|
void write_static(Fd_Code_Writer& f) FL_OVERRIDE;
|
||||||
|
void write_code1(Fd_Code_Writer& f) FL_OVERRIDE;
|
||||||
|
// void write_code2(Fd_Code_Writer& f) FL_OVERRIDE;
|
||||||
ID id() const FL_OVERRIDE { return ID_Menu_Bar; }
|
ID id() const FL_OVERRIDE { return ID_Menu_Bar; }
|
||||||
bool is_a(ID inID) const FL_OVERRIDE { return (inID==ID_Menu_Bar) ? true : super::is_a(inID); }
|
bool is_a(ID inID) const FL_OVERRIDE { return (inID==ID_Menu_Bar) ? true : super::is_a(inID); }
|
||||||
|
bool is_sys_menu_bar();
|
||||||
|
const char *sys_menubar_name();
|
||||||
|
const char *sys_menubar_proxy_name();
|
||||||
|
protected:
|
||||||
|
char *_proxy_name;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -1006,6 +1006,19 @@ const char *Fl_Type::callback_name(Fd_Code_Writer& f) {
|
|||||||
return f.unique_id(this, "cb", name(), label());
|
return f.unique_id(this, "cb", name(), label());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
\brief Return the class name if this type is inside a Class or Widget Class.
|
||||||
|
|
||||||
|
This methods traverses up the hirarchy to find out if this Type is located
|
||||||
|
inside a Class or Widget Class. It then return the name of that class. If
|
||||||
|
need_nest is set, class_name searches all the way up the tree and concatenates
|
||||||
|
the names of classes within classes, separated by a "::".
|
||||||
|
|
||||||
|
\param need_nest if clear, search up one level to the first enclosing class.
|
||||||
|
If set, recurse all the way up to the top node.
|
||||||
|
\return the name of the enclosing class, or names of the enclosing classes
|
||||||
|
in a static buffe (don't call free), or NULL if this Type is not inside a class
|
||||||
|
*/
|
||||||
const char* Fl_Type::class_name(const int need_nest) const {
|
const char* Fl_Type::class_name(const int need_nest) const {
|
||||||
Fl_Type* p = parent;
|
Fl_Type* p = parent;
|
||||||
while (p) {
|
while (p) {
|
||||||
|
@ -54,6 +54,11 @@ int Fl_Widget_Type::is_widget() const {return 1;}
|
|||||||
int Fl_Widget_Type::is_public() const {return public_;}
|
int Fl_Widget_Type::is_public() const {return public_;}
|
||||||
|
|
||||||
const char* subclassname(Fl_Type* l) {
|
const char* subclassname(Fl_Type* l) {
|
||||||
|
if (l->is_a(ID_Menu_Bar)) {
|
||||||
|
Fl_Menu_Bar_Type *mb = static_cast<Fl_Menu_Bar_Type*>(l);
|
||||||
|
if (mb->is_sys_menu_bar())
|
||||||
|
return mb->sys_menubar_name();
|
||||||
|
}
|
||||||
if (l->is_widget()) {
|
if (l->is_widget()) {
|
||||||
Fl_Widget_Type* p = (Fl_Widget_Type*)l;
|
Fl_Widget_Type* p = (Fl_Widget_Type*)l;
|
||||||
const char* c = p->subclass();
|
const char* c = p->subclass();
|
||||||
@ -2991,6 +2996,12 @@ void Fl_Widget_Type::write_code1(Fd_Code_Writer& f) {
|
|||||||
f.write_c("new %s(0, 0, %d, %d", t, o->w(), o->h());
|
f.write_c("new %s(0, 0, %d, %d", t, o->w(), o->h());
|
||||||
else
|
else
|
||||||
f.write_c("new %s(%d, %d", t, o->w(), o->h());
|
f.write_c("new %s(%d, %d", t, o->w(), o->h());
|
||||||
|
} else if (is_a(ID_Menu_Bar)
|
||||||
|
&& ((Fl_Menu_Bar_Type*)this)->is_sys_menu_bar()
|
||||||
|
&& is_in_class()) {
|
||||||
|
f.write_c("(%s*)new %s(%d, %d, %d, %d",
|
||||||
|
t, ((Fl_Menu_Bar_Type*)this)->sys_menubar_proxy_name(),
|
||||||
|
o->x(), o->y(), o->w(), o->h());
|
||||||
} else {
|
} else {
|
||||||
f.write_c("new %s(%d, %d, %d, %d", t, o->x(), o->y(), o->w(), o->h());
|
f.write_c("new %s(%d, %d, %d, %d", t, o->x(), o->y(), o->w(), o->h());
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user