From 410db13a8c0bab044db136106576979c1579ad7b Mon Sep 17 00:00:00 2001 From: Paul Rouget Date: Wed, 18 Feb 2015 16:34:00 +0100 Subject: [PATCH] Bug 1127205 - Can't quit B2G Desktop on Mac. r=mstange --- .../chrome/global/fallbackMenubar.properties | 8 ++ toolkit/locales/jar.mn | 1 + widget/cocoa/nsMenuBarX.h | 1 + widget/cocoa/nsMenuBarX.mm | 100 ++++++++++++++---- xpfe/appshell/nsWebShellWindow.cpp | 15 ++- 5 files changed, 98 insertions(+), 27 deletions(-) create mode 100644 toolkit/locales/en-US/chrome/global/fallbackMenubar.properties diff --git a/toolkit/locales/en-US/chrome/global/fallbackMenubar.properties b/toolkit/locales/en-US/chrome/global/fallbackMenubar.properties new file mode 100644 index 000000000000..9765689ec282 --- /dev/null +++ b/toolkit/locales/en-US/chrome/global/fallbackMenubar.properties @@ -0,0 +1,8 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +# OSX only. Default menu label when there is no xul menubar. + +quitMenuitem.label=Quit +quitMenuitem.key=q diff --git a/toolkit/locales/jar.mn b/toolkit/locales/jar.mn index cea951d0f0cc..b8984f12c043 100644 --- a/toolkit/locales/jar.mn +++ b/toolkit/locales/jar.mn @@ -38,6 +38,7 @@ locale/@AB_CD@/global/devtools/styleinspector.properties (%chrome/global/devtools/styleinspector.properties) locale/@AB_CD@/global/dialogOverlay.dtd (%chrome/global/dialogOverlay.dtd) locale/@AB_CD@/global/editMenuOverlay.dtd (%chrome/global/editMenuOverlay.dtd) + locale/@AB_CD@/global/fallbackMenubar.properties (%chrome/global/fallbackMenubar.properties) locale/@AB_CD@/global/filefield.properties (%chrome/global/filefield.properties) locale/@AB_CD@/global/filepicker.dtd (%chrome/global/filepicker.dtd) locale/@AB_CD@/global/filepicker.properties (%chrome/global/filepicker.properties) diff --git a/widget/cocoa/nsMenuBarX.h b/widget/cocoa/nsMenuBarX.h index f62bb064ed09..4f94c9db7be1 100644 --- a/widget/cocoa/nsMenuBarX.h +++ b/widget/cocoa/nsMenuBarX.h @@ -130,6 +130,7 @@ public: protected: void ConstructNativeMenus(); + void ConstructFallbackNativeMenus(); nsresult InsertMenuAtIndex(nsMenuX* aMenu, uint32_t aIndex); void RemoveMenuAtIndex(uint32_t aIndex); void HideItem(nsIDOMDocument* inDoc, const nsAString & inID, nsIContent** outHiddenNode); diff --git a/widget/cocoa/nsMenuBarX.mm b/widget/cocoa/nsMenuBarX.mm index 99c96db2a6cb..90c681f9dce5 100644 --- a/widget/cocoa/nsMenuBarX.mm +++ b/widget/cocoa/nsMenuBarX.mm @@ -25,6 +25,9 @@ #include "nsIDocument.h" #include "nsIDOMDocument.h" #include "nsIDOMElement.h" +#include "nsIAppStartup.h" +#include "nsIStringBundle.h" +#include "nsToolkitCompsCID.h" NativeMenuItemTarget* nsMenuBarX::sNativeEventTarget = nil; nsMenuBarX* nsMenuBarX::sLastGeckoMenuBarPainted = nullptr; // Weak @@ -80,7 +83,9 @@ nsMenuBarX::~nsMenuBarX() sPrefItemContent = nullptr; // make sure we unregister ourselves as a content observer - UnregisterForContentChanges(mContent); + if (mContent) { + UnregisterForContentChanges(mContent); + } // We have to manually clear the array here because clearing causes menu items // to call back into the menu bar to unregister themselves. We don't want to @@ -96,21 +101,24 @@ nsMenuBarX::~nsMenuBarX() nsresult nsMenuBarX::Create(nsIWidget* aParent, nsIContent* aContent) { - if (!aParent || !aContent) + if (!aParent) return NS_ERROR_INVALID_ARG; mParentWindow = aParent; mContent = aContent; - AquifyMenuBar(); + if (mContent) { + AquifyMenuBar(); - nsresult rv = nsMenuGroupOwnerX::Create(aContent); - if (NS_FAILED(rv)) - return rv; + nsresult rv = nsMenuGroupOwnerX::Create(mContent); + if (NS_FAILED(rv)) + return rv; - RegisterForContentChanges(aContent, this); - - ConstructNativeMenus(); + RegisterForContentChanges(mContent, this); + ConstructNativeMenus(); + } else { + ConstructFallbackNativeMenus(); + } // Give this to the parent window. The parent takes ownership. static_cast(mParentWindow)->SetMenuBar(this); @@ -138,6 +146,49 @@ void nsMenuBarX::ConstructNativeMenus() } } +void nsMenuBarX::ConstructFallbackNativeMenus() +{ + if (sApplicationMenu) { + // Menu has already been built. + return; + } + + nsCOMPtr stringBundle; + + nsCOMPtr bundleSvc = do_GetService(NS_STRINGBUNDLE_CONTRACTID); + bundleSvc->CreateBundle("chrome://global/locale/fallbackMenubar.properties", getter_AddRefs(stringBundle)); + + if (!stringBundle) { + return; + } + + nsXPIDLString labelUTF16; + nsXPIDLString keyUTF16; + + const char16_t* labelProp = MOZ_UTF16("quitMenuitem.label"); + const char16_t* keyProp = MOZ_UTF16("quitMenuitem.key"); + + stringBundle->GetStringFromName(labelProp, getter_Copies(labelUTF16)); + stringBundle->GetStringFromName(keyProp, getter_Copies(keyUTF16)); + + NSString* labelStr = [NSString stringWithUTF8String: + NS_ConvertUTF16toUTF8(labelUTF16).get()]; + NSString* keyStr= [NSString stringWithUTF8String: + NS_ConvertUTF16toUTF8(keyUTF16).get()]; + + if (!nsMenuBarX::sNativeEventTarget) { + nsMenuBarX::sNativeEventTarget = [[NativeMenuItemTarget alloc] init]; + } + + sApplicationMenu = [[[[NSApp mainMenu] itemAtIndex:0] submenu] retain]; + NSMenuItem* quitMenuItem = [[[NSMenuItem alloc] initWithTitle:labelStr + action:@selector(menuItemHit:) + keyEquivalent:keyStr] autorelease]; + [quitMenuItem setTarget:nsMenuBarX::sNativeEventTarget]; + [quitMenuItem setTag:eCommand_ID_Quit]; + [sApplicationMenu addItem:quitMenuItem]; +} + uint32_t nsMenuBarX::GetMenuCount() { return mMenuArray.Length(); @@ -878,23 +929,25 @@ static BOOL gMenuItemsExecuteCommands = YES; return; } + int tag = [sender tag]; + if (!gMenuItemsExecuteCommands) { return; } - int tag = [sender tag]; - - MenuItemInfo* info = [sender representedObject]; - if (!info) - return; - - nsMenuGroupOwnerX* menuGroupOwner = [info menuGroupOwner]; - if (!menuGroupOwner) - return; - + nsMenuGroupOwnerX* menuGroupOwner = nullptr; nsMenuBarX* menuBar = nullptr; - if (menuGroupOwner->MenuObjectType() == eMenuBarObjectType) - menuBar = static_cast(menuGroupOwner); + MenuItemInfo* info = [sender representedObject]; + + if (info) { + menuGroupOwner = [info menuGroupOwner]; + if (!menuGroupOwner) { + return; + } + if (menuGroupOwner->MenuObjectType() == eMenuBarObjectType) { + menuBar = static_cast(menuGroupOwner); + } + } // Do special processing if this is for an app-global command. if (tag == eCommand_ID_About) { @@ -934,7 +987,10 @@ static BOOL gMenuItemsExecuteCommands = YES; nsMenuUtilsX::DispatchCommandTo(mostSpecificContent); } else { - [NSApp terminate:nil]; + nsCOMPtr appStartup = do_GetService(NS_APPSTARTUP_CONTRACTID); + if (appStartup) { + appStartup->Quit(nsIAppStartup::eAttemptQuit); + } } return; } diff --git a/xpfe/appshell/nsWebShellWindow.cpp b/xpfe/appshell/nsWebShellWindow.cpp index 2f42e8aa565c..29dde6155d25 100644 --- a/xpfe/appshell/nsWebShellWindow.cpp +++ b/xpfe/appshell/nsWebShellWindow.cpp @@ -418,6 +418,11 @@ nsWebShellWindow::WindowDeactivated() #ifdef USE_NATIVE_MENUS static void LoadNativeMenus(nsIDOMDocument *aDOMDoc, nsIWidget *aParentWindow) { + nsCOMPtr nms = do_GetService("@mozilla.org/widget/nativemenuservice;1"); + if (!nms) { + return; + } + // Find the menubar tag (if there is more than one, we ignore all but // the first). nsCOMPtr menubarElements; @@ -428,13 +433,13 @@ static void LoadNativeMenus(nsIDOMDocument *aDOMDoc, nsIWidget *aParentWindow) nsCOMPtr menubarNode; if (menubarElements) menubarElements->Item(0, getter_AddRefs(menubarNode)); - if (!menubarNode) - return; - nsCOMPtr nms = do_GetService("@mozilla.org/widget/nativemenuservice;1"); - nsCOMPtr menubarContent(do_QueryInterface(menubarNode)); - if (nms && menubarContent) + if (menubarNode) { + nsCOMPtr menubarContent(do_QueryInterface(menubarNode)); nms->CreateNativeMenuBar(aParentWindow, menubarContent); + } else { + nms->CreateNativeMenuBar(aParentWindow, nullptr); + } } #endif