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:
parent
2b55acd3eb
commit
5e7574c9c2
3 changed files with 72 additions and 51 deletions
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -201,6 +201,8 @@ protected:
|
|||
virtual void reset (bool reload);
|
||||
|
||||
private:
|
||||
void createMenuBarImplementation();
|
||||
|
||||
struct ltstr
|
||||
{
|
||||
bool operator()(const char* s1, const char* s2) const {
|
||||
|
|
Loading…
Reference in a new issue