1
0
Fork 0

Bug-fix: Cocoa menus work in aircraft with custom dialogs.

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.
This commit is contained in:
James Turner 2014-01-15 22:00:09 +00:00
parent 2b55acd3eb
commit 5e7574c9c2
3 changed files with 72 additions and 51 deletions

View file

@ -24,6 +24,41 @@ typedef std::map<NSMenuItem*, SGBindingList> MenuItemBindings;
@class CocoaMenuDelegate; @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 class FGCocoaMenuBar::CocoaMenuBarPrivate
{ {
public: public:
@ -38,7 +73,7 @@ public:
CocoaMenuDelegate* delegate; CocoaMenuDelegate* delegate;
MenuItemBindings itemBindings; MenuItemBindings itemBindings;
std::vector<SGPropertyChangeListener*> listeners; std::vector<CocoaEnabledListener*> listeners;
}; };
// prior to the 10.6 SDK, NSMenuDelegate was an informal protocol // 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]; [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() FGCocoaMenuBar::CocoaMenuBarPrivate::CocoaMenuBarPrivate()
{ {
delegate = [[CocoaMenuDelegate alloc] init]; delegate = [[CocoaMenuDelegate alloc] init];
@ -195,9 +201,9 @@ void FGCocoaMenuBar::CocoaMenuBarPrivate::menuFromProps(NSMenu* menu, SGProperty
setItemShortcutFromString(item, shortcut); setItemShortcutFromString(item, shortcut);
} }
SGPropertyChangeListener* enableListener = new CocoaEnabledListener(item); CocoaEnabledListener* cl = new CocoaEnabledListener(n, item);
listeners.push_back(enableListener); listeners.push_back(cl);
n->getNode("enabled")->addChangeListener(enableListener);
[item setTarget:delegate]; [item setTarget:delegate];
[item setAction:@selector(itemAction:)]; [item setAction:@selector(itemAction:)];
} }
@ -243,10 +249,18 @@ FGCocoaMenuBar::~FGCocoaMenuBar()
[topLevelItem.submenu removeAllItems]; [topLevelItem.submenu removeAllItems];
} }
std::vector<SGPropertyChangeListener*>::iterator it; std::vector<CocoaEnabledListener*>::iterator it;
for (it = p->listeners.begin(); it != p->listeners.end(); ++it) { for (it = p->listeners.begin(); it != p->listeners.end(); ++it) {
delete *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() void FGCocoaMenuBar::init()
@ -291,9 +305,8 @@ void FGCocoaMenuBar::init()
n->setBoolValue("enabled", true); n->setBoolValue("enabled", true);
} }
SGPropertyChangeListener* l = new CocoaEnabledListener(item); CocoaEnabledListener* l = new CocoaEnabledListener( n, item);
p->listeners.push_back(l); p->listeners.push_back(l);
n->getNode("enabled")->addChangeListener(l);
} }
} }

View file

@ -63,23 +63,18 @@ NewGUI::~NewGUI ()
void void
NewGUI::init () NewGUI::init ()
{ {
#if defined(SG_MAC) createMenuBarImplementation();
if (fgGetBool("/sim/menubar/native", true)) {
_menubar.reset(new FGCocoaMenuBar);
}
#endif
if (!_menubar.get()) {
_menubar.reset(new FGPUIMenuBar);
}
fgTie("/sim/menubar/visibility", this, fgTie("/sim/menubar/visibility", this,
&NewGUI::getMenuBarVisible, &NewGUI::setMenuBarVisible); &NewGUI::getMenuBarVisible, &NewGUI::setMenuBarVisible);
setStyle(); setStyle();
SGPath p(globals->get_fg_root(), "gui/dialogs"); SGPath p(globals->get_fg_root(), "gui/dialogs");
readDir(p); 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 // Fix for http://code.google.com/p/flightgear-bugs/issues/detail?id=947
fgGetNode("sim/menubar")->setAttribute(SGPropertyNode::PRESERVE, true); fgGetNode("sim/menubar")->setAttribute(SGPropertyNode::PRESERVE, true);
@ -107,6 +102,19 @@ NewGUI::redraw ()
reset(false); 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 void
NewGUI::reset (bool reload) NewGUI::reset (bool reload)
{ {
@ -122,15 +130,13 @@ NewGUI::reset (bool reload)
setStyle(); setStyle();
unbind(); unbind();
#if !defined(SG_MAC)
_menubar.reset(new FGPUIMenuBar);
#endif
if (reload) { if (reload) {
_dialog_props.clear(); _dialog_props.clear();
_dialog_names.clear(); _dialog_names.clear();
init(); init();
} else { } else {
createMenuBarImplementation();
_menubar->init(); _menubar->init();
} }

View file

@ -201,6 +201,8 @@ protected:
virtual void reset (bool reload); virtual void reset (bool reload);
private: private:
void createMenuBarImplementation();
struct ltstr struct ltstr
{ {
bool operator()(const char* s1, const char* s2) const { bool operator()(const char* s1, const char* s2) const {