summaryrefslogtreecommitdiff
path: root/fluid/Fl_Menu_Type.cxx
diff options
context:
space:
mode:
authorMatthias Melcher <github@matthiasm.com>2024-07-27 20:22:50 +0200
committerMatthias Melcher <github@matthiasm.com>2024-07-27 20:22:50 +0200
commitd265009b66cbc69ca6edf502dc23199a01d62220 (patch)
tree85afd145bfd05c152371ea00388bf71f745ab1fe /fluid/Fl_Menu_Type.cxx
parent8cffbd694106a2371d297caa008f2290185fed2f (diff)
FLUID: fixes crash bug in Fl_Sys_Men_Bar inside a Class. #977
Diffstat (limited to 'fluid/Fl_Menu_Type.cxx')
-rw-r--r--fluid/Fl_Menu_Type.cxx124
1 files changed, 112 insertions, 12 deletions
diff --git a/fluid/Fl_Menu_Type.cxx b/fluid/Fl_Menu_Type.cxx
index 6ab652e14..bf88d57eb 100644
--- a/fluid/Fl_Menu_Type.cxx
+++ b/fluid/Fl_Menu_Type.cxx
@@ -290,19 +290,49 @@ void Fl_Menu_Item_Type::write_static(Fd_Code_Writer& f) {
f.write_c("\n");
// Matt: disabled f.tag(FD_TAG_MENU_CALLBACK, get_uid());
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) {
+ // 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("%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 *q = 0;
- // Go up one more level for Fl_Input_Choice, as these are groups themselves
- if (t && t->is_a(ID_Input_Choice))
- f.write_c("->parent()");
- for (t = t->parent; t && t->is_widget() && !is_class(); q = t, t = t->parent)
- f.write_c("->parent()");
- if (!q || !q->is_a(ID_Widget_Class))
- f.write_c("->user_data()");
- f.write_c("))->%s_i(o,v);\n}\n", cn);
+ if (t) {
+ Fl_Widget_Type *tw = (t->is_widget()) ? static_cast<Fl_Widget_Type*>(t) : NULL;
+ Fl_Type *q = NULL;
+ // Generate code to call the callback
+ if (tw->is_a(ID_Menu_Bar) && ((Fl_Menu_Bar_Type*)tw)->is_sys_menu_bar()) {
+ // Fl_Sys_Menu_Bar removes itself from any parent on macOS, so we
+ // wrapped it in a class and remeber the parent class in a new
+ // class memeber variable.
+ 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) {
@@ -700,10 +730,80 @@ Fl_Type* Fl_Input_Choice_Type::click_test(int, int) {
Fl_Menu_Bar_Type Fl_Menu_Bar_type;
-////////////////////////////////////////////////////////////////
-// Shortcut entry item in panel:
+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:
void shortcut_in_cb(Fl_Shortcut_Button* i, void* v) {
if (v == LOAD) {
if (current_widget->is_button())