]> git.mxchange.org Git - flightgear.git/commitdiff
Bug-fix: Cocoa menus work in aircraft with custom dialogs.
authorJames Turner <zakalawe@mac.com>
Wed, 15 Jan 2014 22:00:09 +0000 (22:00 +0000)
committerJames Turner <zakalawe@mac.com>
Wed, 15 Jan 2014 22:00:09 +0000 (22:00 +0000)
Restarting the GUI could cause Cocoa menus to misbehave, due to
destruction behaviour of SGBinding. Use new clear() helper in the
short term to work around this.

src/GUI/FGCocoaMenuBar.mm
src/GUI/new_gui.cxx
src/GUI/new_gui.hxx

index 9ec02523a6563b1eca4367caf429a082f24e2e0f..048eb5769542bb76d984c5c2c7f34718591e4891 100644 (file)
@@ -24,6 +24,41 @@ typedef std::map<NSMenuItem*, SGBindingList> MenuItemBindings;
 
 @class CocoaMenuDelegate;
 
+namespace {
+    
+    class CocoaEnabledListener : public SGPropertyChangeListener
+    {
+    public:
+        CocoaEnabledListener(SGPropertyNode_ptr prop, NSMenuItem* i) :
+            property(prop->getNode("enabled")),
+            item(i)
+        {
+            if (property.get()) {
+                property->addChangeListener(this);
+            }
+        }
+        
+        ~CocoaEnabledListener()
+        {
+            if (property.get()) {
+                property->removeChangeListener(this);
+            }
+        }
+        
+        
+        virtual void valueChanged(SGPropertyNode *node)
+        {
+            CocoaAutoreleasePool pool;
+            BOOL b = node->getBoolValue();
+            [item setEnabled:b];
+        }
+        
+    private:
+        SGPropertyNode_ptr property;
+        NSMenuItem* item;
+    };
+} // of anonymous namespace
+
 class FGCocoaMenuBar::CocoaMenuBarPrivate
 {
 public:
@@ -38,7 +73,7 @@ public:
   CocoaMenuDelegate* delegate;
   
   MenuItemBindings itemBindings;
-    std::vector<SGPropertyChangeListener*> listeners;
+    std::vector<CocoaEnabledListener*> listeners;
 };
 
 // prior to the 10.6 SDK, NSMenuDelegate was an informal protocol
@@ -126,35 +161,6 @@ static void setItemShortcutFromString(NSMenuItem* item, const string& s)
   [item setKeyEquivalentModifierMask:modifiers];
 }
 
-namespace {
-
-  class CocoaEnabledListener : public SGPropertyChangeListener
-  {
-  public:
-    CocoaEnabledListener(NSMenuItem* i) :
-      item(i)
-    {
-    
-    }
-      
-      ~CocoaEnabledListener()
-      {
-          
-      }
-    
-    
-    virtual void valueChanged(SGPropertyNode *node) 
-    {
-      CocoaAutoreleasePool pool;
-      BOOL b = node->getBoolValue();
-      [item setEnabled:b];
-    }
-    
-  private:
-    NSMenuItem* item;
-  };
-} // of anonymous namespace
-
 FGCocoaMenuBar::CocoaMenuBarPrivate::CocoaMenuBarPrivate()
 {
   delegate = [[CocoaMenuDelegate alloc] init];
@@ -195,9 +201,9 @@ void FGCocoaMenuBar::CocoaMenuBarPrivate::menuFromProps(NSMenu* menu, SGProperty
           setItemShortcutFromString(item, shortcut);
         }
         
-        SGPropertyChangeListener* enableListener = new CocoaEnabledListener(item);
-        listeners.push_back(enableListener);
-        n->getNode("enabled")->addChangeListener(enableListener);
+        CocoaEnabledListener* cl = new CocoaEnabledListener(n, item);
+        listeners.push_back(cl);
+          
         [item setTarget:delegate];
         [item setAction:@selector(itemAction:)];
       }
@@ -243,10 +249,18 @@ FGCocoaMenuBar::~FGCocoaMenuBar()
         [topLevelItem.submenu removeAllItems];
     }
     
-    std::vector<SGPropertyChangeListener*>::iterator it;
+    std::vector<CocoaEnabledListener*>::iterator it;
     for (it = p->listeners.begin(); it != p->listeners.end(); ++it) {
         delete *it;
-    }    
+    }
+    
+    // owing to the bizarre destructor behaviour of SGBinding, we need
+    // to explicitly clear these bindings. (PUIMenuBar takes a different
+    // approach, and copies each binding into /sim/bindings)
+    MenuItemBindings::iterator j;
+    for (j = p->itemBindings.begin(); j != p->itemBindings.end(); ++j) {
+        clearBindingList(j->second);
+    }
 }
 
 void FGCocoaMenuBar::init()
@@ -291,9 +305,8 @@ void FGCocoaMenuBar::init()
       n->setBoolValue("enabled", true);
     }
     
-    SGPropertyChangeListener* l = new CocoaEnabledListener(item);
+    CocoaEnabledListener* l = new CocoaEnabledListener( n, item);
     p->listeners.push_back(l);
-    n->getNode("enabled")->addChangeListener(l);
   }
 }
 
index af073812173e1ad22587a82dce047778a5e7d687..d679c44c94e5037912c86afa7b12851f7a374cf3 100644 (file)
@@ -63,23 +63,18 @@ NewGUI::~NewGUI ()
 void
 NewGUI::init ()
 {
-#if defined(SG_MAC)
-    if (fgGetBool("/sim/menubar/native", true)) {
-        _menubar.reset(new FGCocoaMenuBar);
-    }
-#endif
-    if (!_menubar.get()) {
-        _menubar.reset(new FGPUIMenuBar);
-    }
-    
+    createMenuBarImplementation();
     fgTie("/sim/menubar/visibility", this,
           &NewGUI::getMenuBarVisible, &NewGUI::setMenuBarVisible);
     
     setStyle();
     SGPath p(globals->get_fg_root(), "gui/dialogs");
     readDir(p);
-    const std::string aircraft_dir(fgGetString("/sim/aircraft-dir"));
-    readDir( SGPath(aircraft_dir, "gui/dialogs") );
+    
+    SGPath aircraftDialogDir(string(fgGetString("/sim/aircraft-dir")), "gui/dialogs");
+    if (aircraftDialogDir.exists()) {
+        readDir(aircraftDialogDir);
+    }
     
     // Fix for http://code.google.com/p/flightgear-bugs/issues/detail?id=947
     fgGetNode("sim/menubar")->setAttribute(SGPropertyNode::PRESERVE, true);
@@ -107,6 +102,19 @@ NewGUI::redraw ()
     reset(false);
 }
 
+void
+NewGUI::createMenuBarImplementation()
+{
+#if defined(SG_MAC)
+    if (fgGetBool("/sim/menubar/native", true)) {
+        _menubar.reset(new FGCocoaMenuBar);
+    }
+#endif
+    if (!_menubar.get()) {
+        _menubar.reset(new FGPUIMenuBar);
+    }
+}
+
 void
 NewGUI::reset (bool reload)
 {
@@ -122,15 +130,13 @@ NewGUI::reset (bool reload)
     setStyle();
 
     unbind();
-#if !defined(SG_MAC)
-    _menubar.reset(new FGPUIMenuBar);
-#endif
 
     if (reload) {
         _dialog_props.clear();
         _dialog_names.clear();
         init();
     } else {
+        createMenuBarImplementation();
         _menubar->init();
     }
 
index d3ee2979e8cacdf6795517c8d1171e47f6fcd0a5..1ab1361c8f86ebdb5fa60e15f91bdb12484b2e51 100644 (file)
@@ -201,6 +201,8 @@ protected:
     virtual void reset (bool reload);
 
 private:
+    void createMenuBarImplementation();
+    
     struct ltstr
     {
         bool operator()(const char* s1, const char* s2) const {