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;
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);
}
}

View 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();
}

View 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 {