summarylogtreecommitdiffstats
diff options
context:
space:
mode:
authorBjörn Bidar2017-04-25 08:16:40 +0200
committerBjörn Bidar2017-04-25 08:16:40 +0200
commit554051fcb52a9f16437889b916600b1d78ed7ede (patch)
tree29e9286e15542abef33d29c4b694a0cfa6c1fad0
parent04aae9bce477d8ded5b591fd535c5ace6b016895 (diff)
downloadaur-554051fcb52a9f16437889b916600b1d78ed7ede.tar.gz
upkg
-rw-r--r--.SRCINFO32
-rw-r--r--PKGBUILD38
-rw-r--r--rust-i686.patch16
-rw-r--r--unity-menubar.patch3247
4 files changed, 1534 insertions, 1799 deletions
diff --git a/.SRCINFO b/.SRCINFO
index d3a4addf7e27..0e161b0c73ef 100644
--- a/.SRCINFO
+++ b/.SRCINFO
@@ -1,8 +1,8 @@
# Generated by mksrcinfo v8
-# Wed Apr 12 05:34:54 UTC 2017
+# Tue Apr 25 06:14:44 UTC 2017
pkgbase = firefox-kde-opensuse
pkgdesc = Standalone web browser from mozilla.org with OpenSUSE patch, integrate better with KDE
- pkgver = 52.0.2
+ pkgver = 53.0
pkgrel = 1
url = https://build.opensuse.org/package/show/mozilla:Factory/MozillaFirefox
arch = i686
@@ -44,50 +44,48 @@ pkgbase = firefox-kde-opensuse
depends = gtk3
optdepends = networkmanager: Location detection via available WiFi networks
optdepends = speech-dispatcher: Text-to-Speech
- provides = firefox=52.0.2
+ provides = firefox=53.0
conflicts = firefox
options = !emptydirs
options = strip
- source = https://ftp.mozilla.org/pub/mozilla.org/firefox/releases/52.0.2/source/firefox-52.0.2.source.tar.xz
+ source = https://ftp.mozilla.org/pub/mozilla.org/firefox/releases/53.0/source/firefox-53.0.source.tar.xz
source = mozconfig
source = firefox.desktop
source = firefox-install-dir.patch
source = vendor.js
source = kde.js
source = firefox-fixed-loading-icon.png
- source = http://www.rosenauer.org/hg/mozilla/raw-file/d91c918a6511/firefox-branded-icons.patch
- source = http://www.rosenauer.org/hg/mozilla/raw-file/d91c918a6511/firefox-kde.patch
- source = http://www.rosenauer.org/hg/mozilla/raw-file/d91c918a6511/firefox-no-default-ualocale.patch
- source = http://www.rosenauer.org/hg/mozilla/raw-file/d91c918a6511/mozilla-kde.patch
- source = http://www.rosenauer.org/hg/mozilla/raw-file/d91c918a6511/mozilla-language.patch
- source = http://www.rosenauer.org/hg/mozilla/raw-file/d91c918a6511/mozilla-nongnome-proxies.patch
+ source = http://www.rosenauer.org/hg/mozilla/raw-file/4665fe34fbce/firefox-branded-icons.patch
+ source = http://www.rosenauer.org/hg/mozilla/raw-file/4665fe34fbce/firefox-kde.patch
+ source = http://www.rosenauer.org/hg/mozilla/raw-file/4665fe34fbce/firefox-no-default-ualocale.patch
+ source = http://www.rosenauer.org/hg/mozilla/raw-file/4665fe34fbce/mozilla-kde.patch
+ source = http://www.rosenauer.org/hg/mozilla/raw-file/4665fe34fbce/mozilla-language.patch
+ source = http://www.rosenauer.org/hg/mozilla/raw-file/4665fe34fbce/mozilla-nongnome-proxies.patch
source = unity-menubar.patch
source = add_missing_pgo_rule.patch
source = pgo_fix_missing_kdejs.patch
source = rb39193.patch
source = fix_mozalloc.patch
source = fix-wifi-scanner.diff
- source = rust-i686.patch
- md5sums = e24c6c4f0e2c8ce8694c6d6a4f712f93
+ md5sums = 73175f850d4ff6068c6af674df20477c
md5sums = 36b41345f62ec209e8ef7179649325c4
md5sums = 14e0f6237a79b85e60256f4808163160
md5sums = dbf14588e85812ee769bd735823a0146
md5sums = aa9f776d2187cba09de65cbb02b39ca0
md5sums = 05bb69d25fb3572c618e3adf1ee7b670
md5sums = 6e335a517c68488941340ee1c23f97b0
- md5sums = 3b3eb8c2747429887e4a03537932eac5
- md5sums = 688b522c10f805261f07c085848487eb
+ md5sums = 46a4971f26c990a66b913ba700c7f3fa
+ md5sums = 906efefafcbe3efd44c8827f699c05e2
md5sums = 1fad9a988826d69fe712ea973e43f6da
- md5sums = 4ac0c221feeee260172acf50581b2246
+ md5sums = 2ab6215a97ff35fbb46eea83df68f0c7
md5sums = fa6ac817f576b486419b5f308116a7cd
md5sums = 0c684360f1df4536512d51873c1d243d
- md5sums = 87eac57858072cfb3d8c3a128bb92da4
+ md5sums = 64b6e0aebd5b716847198fec849e4a6e
md5sums = fe24f5ea463013bb7f1c12d12dce41b2
md5sums = 3fa8bd22d97248de529780f5797178af
md5sums = 43550e772f110a338d5a42914ee2c3a6
md5sums = 0c1ed789c06297659137a2ed2ef769f7
md5sums = e2396b9918aa602427f80d48caf319b4
- md5sums = 40b197fcf8c855b3902414f4d591b18b
pkgname = firefox-kde-opensuse
diff --git a/PKGBUILD b/PKGBUILD
index 212f0cfd632b..7016c823a78d 100644
--- a/PKGBUILD
+++ b/PKGBUILD
@@ -20,7 +20,7 @@ _gtk3=true
_pkgname=firefox
pkgname=$_pkgname-kde-opensuse
-pkgver=52.0.2
+pkgver=53.0
pkgrel=1
pkgdesc="Standalone web browser from mozilla.org with OpenSUSE patch, integrate better with KDE"
arch=('i686' 'x86_64')
@@ -41,7 +41,7 @@ optdepends=('networkmanager: Location detection via available WiFi networks'
'speech-dispatcher: Text-to-Speech')
provides=("firefox=${pkgver}")
conflicts=('firefox')
-_patchrev=d91c918a6511
+_patchrev=4665fe34fbce
options=('!emptydirs' 'strip' )
_patchurl=http://www.rosenauer.org/hg/mozilla/raw-file/$_patchrev
source=(https://ftp.mozilla.org/pub/mozilla.org/firefox/releases/$pkgver/source/firefox-$pkgver.source.tar.xz
@@ -60,7 +60,6 @@ source=(https://ftp.mozilla.org/pub/mozilla.org/firefox/releases/$pkgver/source/
rb39193.patch
fix_mozalloc.patch
fix-wifi-scanner.diff
- rust-i686.patch
)
@@ -124,10 +123,6 @@ prepare() {
# https://bugzilla.mozilla.org/show_bug.cgi?id=1314968
patch -Np1 -i "$srcdir"/fix-wifi-scanner.diff
- # Build with the rust targets we actually ship
- patch -Np1 -i "$srcdir"/rust-i686.patch
-
-
# WebRTC build tries to execute "python" and expects Python 2
mkdir -p "$srcdir/path"
@@ -152,9 +147,6 @@ build() {
# _FORTIFY_SOURCE causes configure failures
CPPFLAGS+=" -O2"
- # GCC 6
- CXXFLAGS+=" -fPIC -fno-delete-null-pointer-checks -fno-schedule-insns2"
-
# Hardening
LDFLAGS+=" -Wl,-z,now"
@@ -182,6 +174,19 @@ package() {
install -Dm644 "$srcdir/vendor.js" "$pkgdir/usr/lib/firefox/browser/defaults/preferences/vendor.js"
install -Dm644 "$srcdir/kde.js" "$pkgdir/usr/lib/firefox/browser/defaults/preferences/kde.js"
+ _distini="$pkgdir/usr/lib/firefox/distribution/distribution.ini"
+ install -Dm644 /dev/stdin "$_distini" <<END
+[Global]
+id=archlinux
+version=1.0
+about=Mozilla Firefox for Arch Linux
+
+[Preferences]
+app.distributor=archlinux
+app.distributor.channel=$pkgname
+app.partner.archlinux=archlinux
+END
+
for i in 16 22 24 32 48 256; do
install -Dm644 browser/branding/official/default$i.png \
"$pkgdir/usr/share/icons/hicolor/${i}x${i}/apps/firefox.png"
@@ -207,23 +212,22 @@ package() {
#https://bugzilla.mozilla.org/show_bug.cgi?id=658850
ln -sf firefox "$pkgdir/usr/lib/firefox/firefox-bin"
}
-md5sums=('e24c6c4f0e2c8ce8694c6d6a4f712f93'
+md5sums=('73175f850d4ff6068c6af674df20477c'
'36b41345f62ec209e8ef7179649325c4'
'14e0f6237a79b85e60256f4808163160'
'dbf14588e85812ee769bd735823a0146'
'aa9f776d2187cba09de65cbb02b39ca0'
'05bb69d25fb3572c618e3adf1ee7b670'
'6e335a517c68488941340ee1c23f97b0'
- '3b3eb8c2747429887e4a03537932eac5'
- '688b522c10f805261f07c085848487eb'
+ '46a4971f26c990a66b913ba700c7f3fa'
+ '906efefafcbe3efd44c8827f699c05e2'
'1fad9a988826d69fe712ea973e43f6da'
- '4ac0c221feeee260172acf50581b2246'
+ '2ab6215a97ff35fbb46eea83df68f0c7'
'fa6ac817f576b486419b5f308116a7cd'
'0c684360f1df4536512d51873c1d243d'
- '87eac57858072cfb3d8c3a128bb92da4'
+ '64b6e0aebd5b716847198fec849e4a6e'
'fe24f5ea463013bb7f1c12d12dce41b2'
'3fa8bd22d97248de529780f5797178af'
'43550e772f110a338d5a42914ee2c3a6'
'0c1ed789c06297659137a2ed2ef769f7'
- 'e2396b9918aa602427f80d48caf319b4'
- '40b197fcf8c855b3902414f4d591b18b')
+ 'e2396b9918aa602427f80d48caf319b4')
diff --git a/rust-i686.patch b/rust-i686.patch
deleted file mode 100644
index 85512e1436b8..000000000000
--- a/rust-i686.patch
+++ /dev/null
@@ -1,16 +0,0 @@
- build/moz.configure/rust.configure | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git c/build/moz.configure/rust.configure i/build/moz.configure/rust.configure
-index cd86b24153debb1b..44911715e25d95e3 100644
---- c/build/moz.configure/rust.configure
-+++ i/build/moz.configure/rust.configure
-@@ -81,7 +81,7 @@ def rust_target(rust_compiler, rustc, target, cross_compiling):
- # OpenBSD
- ('x86_64', 'OpenBSD'): 'x86_64-unknown-openbsd',
- # Linux
-- ('x86', 'Linux'): 'i586-unknown-linux-gnu',
-+ ('x86', 'Linux'): 'i686-unknown-linux-gnu',
- # Linux
- ('x86_64', 'Linux'): 'x86_64-unknown-linux-gnu',
- # OS X and iOS
diff --git a/unity-menubar.patch b/unity-menubar.patch
index 09878c7a38da..325dec3bc3cb 100644
--- a/unity-menubar.patch
+++ b/unity-menubar.patch
@@ -1,7 +1,7 @@
-Index: firefox-52.0~b9+build2/browser/base/content/browser-menubar.inc
+Index: firefox-53.0~a2~hg20170302r359591/browser/base/content/browser-menubar.inc
===================================================================
---- firefox-52.0~b9+build2.orig/browser/base/content/browser-menubar.inc
-+++ firefox-52.0~b9+build2/browser/base/content/browser-menubar.inc
+--- firefox-53.0~a2~hg20170302r359591.orig/browser/base/content/browser-menubar.inc
++++ firefox-53.0~a2~hg20170302r359591/browser/base/content/browser-menubar.inc
@@ -5,7 +5,11 @@
<menubar id="main-menubar"
@@ -14,10 +14,23 @@ Index: firefox-52.0~b9+build2/browser/base/content/browser-menubar.inc
this.setAttribute('openedwithkey',
event.target.parentNode.openedWithKey);"
style="border:0px;padding:0px;margin:0px;-moz-appearance:none">
-Index: firefox-52.0~b9+build2/browser/components/places/content/places.xul
+Index: firefox-53.0~a2~hg20170302r359591/browser/base/content/browser.js
===================================================================
---- firefox-52.0~b9+build2.orig/browser/components/places/content/places.xul
-+++ firefox-52.0~b9+build2/browser/components/places/content/places.xul
+--- firefox-53.0~a2~hg20170302r359591.orig/browser/base/content/browser.js
++++ firefox-53.0~a2~hg20170302r359591/browser/base/content/browser.js
+@@ -5108,6 +5108,8 @@ function getTogglableToolbars() {
+ let toolbarNodes = Array.slice(gNavToolbox.childNodes);
+ toolbarNodes = toolbarNodes.concat(gNavToolbox.externalToolbars);
+ toolbarNodes = toolbarNodes.filter(node => node.getAttribute("toolbarname"));
++ if (document.documentElement.getAttribute("shellshowingmenubar") == "true")
++ toolbarNodes = toolbarNodes.filter(node => node.id != "toolbar-menubar");
+ return toolbarNodes;
+ }
+
+Index: firefox-53.0~a2~hg20170302r359591/browser/components/places/content/places.xul
+===================================================================
+--- firefox-53.0~a2~hg20170302r359591.orig/browser/components/places/content/places.xul
++++ firefox-53.0~a2~hg20170302r359591/browser/components/places/content/places.xul
@@ -157,7 +157,7 @@
<toolbarbutton type="menu" class="tabbable"
onpopupshowing="document.getElementById('placeContent').focus()"
@@ -27,10 +40,24 @@ Index: firefox-52.0~b9+build2/browser/components/places/content/places.xul
<menu accesskey="&organize.accesskey;" class="menu-iconic"
#endif
id="organizeButton" label="&organize.label;"
-Index: firefox-52.0~b9+build2/toolkit/content/widgets/popup.xml
+Index: firefox-53.0~a2~hg20170302r359591/modules/libpref/init/all.js
+===================================================================
+--- firefox-53.0~a2~hg20170302r359591.orig/modules/libpref/init/all.js
++++ firefox-53.0~a2~hg20170302r359591/modules/libpref/init/all.js
+@@ -230,6 +230,9 @@ pref("dom.compartment_per_addon", true);
+ pref("browser.sessionhistory.max_total_viewers", -1);
+
+ pref("ui.use_native_colors", true);
++#ifdef MOZ_WIDGET_GTK
++pref("ui.use_unity_menubar", true);
++#endif
+ pref("ui.click_hold_context_menus", false);
+ // Duration of timeout of incremental search in menus (ms). 0 means infinite.
+ pref("ui.menu.incremental_search.timeout", 1000);
+Index: firefox-53.0~a2~hg20170302r359591/toolkit/content/widgets/popup.xml
===================================================================
---- firefox-52.0~b9+build2.orig/toolkit/content/widgets/popup.xml
-+++ firefox-52.0~b9+build2/toolkit/content/widgets/popup.xml
+--- firefox-53.0~a2~hg20170302r359591.orig/toolkit/content/widgets/popup.xml
++++ firefox-53.0~a2~hg20170302r359591/toolkit/content/widgets/popup.xml
@@ -25,8 +25,14 @@
</getter>
</property>
@@ -39,8 +66,8 @@ Index: firefox-52.0~b9+build2/toolkit/content/widgets/popup.xml
- onget="return this.popupBoxObject.popupState"/>
+ <property name="state" readonly="true">
+ <getter><![CDATA[
-+ if (this.hasAttribute('_moz-menupopupstate'))
-+ return this.getAttribute('_moz-menupopupstate');
++ if (this.hasAttribute('_moz-nativemenupopupstate'))
++ return this.getAttribute('_moz-nativemenupopupstate');
+ else
+ return this.popupBoxObject.popupState;
+ ]]></getter>
@@ -48,11 +75,11 @@ Index: firefox-52.0~b9+build2/toolkit/content/widgets/popup.xml
<property name="triggerNode" readonly="true"
onget="return this.popupBoxObject.triggerNode"/>
-Index: firefox-52.0~b9+build2/toolkit/content/xul.css
+Index: firefox-53.0~a2~hg20170302r359591/toolkit/content/xul.css
===================================================================
---- firefox-52.0~b9+build2.orig/toolkit/content/xul.css
-+++ firefox-52.0~b9+build2/toolkit/content/xul.css
-@@ -307,6 +307,18 @@ toolbar[type="menubar"][autohide="true"]
+--- firefox-53.0~a2~hg20170302r359591.orig/toolkit/content/xul.css
++++ firefox-53.0~a2~hg20170302r359591/toolkit/content/xul.css
+@@ -314,6 +314,18 @@ toolbar[type="menubar"][autohide="true"]
}
%endif
@@ -71,10 +98,50 @@ Index: firefox-52.0~b9+build2/toolkit/content/xul.css
toolbarseparator {
-moz-binding: url("chrome://global/content/bindings/toolbar.xml#toolbardecoration");
}
-Index: firefox-52.0~b9+build2/widget/gtk/nsDbusmenu.cpp
+Index: firefox-53.0~a2~hg20170302r359591/widget/gtk/moz.build
+===================================================================
+--- firefox-53.0~a2~hg20170302r359591.orig/widget/gtk/moz.build
++++ firefox-53.0~a2~hg20170302r359591/widget/gtk/moz.build
+@@ -24,10 +24,18 @@ UNIFIED_SOURCES += [
+ 'nsAppShell.cpp',
+ 'nsBidiKeyboard.cpp',
+ 'nsColorPicker.cpp',
++ 'nsDbusmenu.cpp',
+ 'nsFilePicker.cpp',
+ 'nsGtkKeyUtils.cpp',
+ 'nsImageToPixbuf.cpp',
+ 'nsLookAndFeel.cpp',
++ 'nsMenuBar.cpp',
++ 'nsMenuContainer.cpp',
++ 'nsMenuItem.cpp',
++ 'nsMenuObject.cpp',
++ 'nsMenuSeparator.cpp',
++ 'nsNativeMenuAtoms.cpp',
++ 'nsNativeMenuDocListener.cpp',
+ 'nsNativeThemeGTK.cpp',
+ 'nsScreenGtk.cpp',
+ 'nsScreenManagerGtk.cpp',
+@@ -40,6 +48,8 @@ UNIFIED_SOURCES += [
+ ]
+
+ SOURCES += [
++ 'nsMenu.cpp', # conflicts with X11 headers
++ 'nsNativeMenuService.cpp',
+ 'nsWindow.cpp', # conflicts with X11 headers
+ ]
+
+@@ -104,6 +114,7 @@ FINAL_LIBRARY = 'xul'
+
+ LOCAL_INCLUDES += [
+ '/layout/generic',
++ '/layout/style',
+ '/layout/xul',
+ '/other-licenses/atk-1.0',
+ '/widget',
+Index: firefox-53.0~a2~hg20170302r359591/widget/gtk/nsDbusmenu.cpp
===================================================================
--- /dev/null
-+++ firefox-52.0~b9+build2/widget/gtk/nsDbusmenu.cpp
++++ firefox-53.0~a2~hg20170302r359591/widget/gtk/nsDbusmenu.cpp
@@ -0,0 +1,63 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* vim:expandtab:shiftwidth=4:tabstop=4:
@@ -139,11 +206,11 @@ Index: firefox-52.0~b9+build2/widget/gtk/nsDbusmenu.cpp
+
+ return NS_OK;
+}
-Index: firefox-52.0~b9+build2/widget/gtk/nsDbusmenu.h
+Index: firefox-53.0~a2~hg20170302r359591/widget/gtk/nsDbusmenu.h
===================================================================
--- /dev/null
-+++ firefox-52.0~b9+build2/widget/gtk/nsDbusmenu.h
-@@ -0,0 +1,99 @@
++++ firefox-53.0~a2~hg20170302r359591/widget/gtk/nsDbusmenu.h
+@@ -0,0 +1,101 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* vim:expandtab:shiftwidth=4:tabstop=4:
+ */
@@ -211,6 +278,8 @@ Index: firefox-52.0~b9+build2/widget/gtk/nsDbusmenu.h
+class nsDbusmenuFunctions
+{
+public:
++ nsDbusmenuFunctions() = delete;
++
+ static nsresult Init();
+
+#define FUNC(name, type, params) \
@@ -243,11 +312,11 @@ Index: firefox-52.0~b9+build2/widget/gtk/nsDbusmenu.h
+#define dbusmenu_menuitem_property_set_shortcut nsDbusmenuFunctions::s_dbusmenu_menuitem_property_set_shortcut
+
+#endif /* __nsDbusmenu_h__ */
-Index: firefox-52.0~b9+build2/widget/gtk/nsMenu.cpp
+Index: firefox-53.0~a2~hg20170302r359591/widget/gtk/nsMenu.cpp
===================================================================
--- /dev/null
-+++ firefox-52.0~b9+build2/widget/gtk/nsMenu.cpp
-@@ -0,0 +1,868 @@
++++ firefox-53.0~a2~hg20170302r359591/widget/gtk/nsMenu.cpp
+@@ -0,0 +1,841 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* vim:expandtab:shiftwidth=4:tabstop=4:
+ */
@@ -257,8 +326,10 @@ Index: firefox-52.0~b9+build2/widget/gtk/nsMenu.cpp
+
+#define _IMPL_NS_LAYOUT
+
++#include "mozilla/Assertions.h"
+#include "mozilla/GuardObjects.h"
+#include "mozilla/MouseEvents.h"
++#include "mozilla/Move.h"
+#include "mozilla/StyleSetHandleInlines.h"
+#include "nsAutoPtr.h"
+#include "nsBindingManager.h"
@@ -290,59 +361,76 @@ Index: firefox-52.0~b9+build2/widget/gtk/nsMenu.cpp
+
+using namespace mozilla;
+
-+class MOZ_STACK_CLASS nsMenuUpdateBatch
++class nsMenuContentInsertedEvent : public Runnable
+{
+public:
-+ nsMenuUpdateBatch(nsMenu *aMenu MOZ_GUARD_OBJECT_NOTIFIER_PARAM) :
-+ mMenu(aMenu)
-+ {
-+ MOZ_GUARD_OBJECT_NOTIFIER_INIT;
-+ mMenu->BeginUpdateBatchInternal();
-+ }
++ nsMenuContentInsertedEvent(nsMenu *aMenu,
++ nsIContent *aContainer,
++ nsIContent *aChild,
++ nsIContent *aPrevSibling) :
++ mWeakMenu(aMenu),
++ mContainer(aContainer),
++ mChild(aChild),
++ mPrevSibling(aPrevSibling) { }
+
-+ ~nsMenuUpdateBatch()
++ NS_IMETHODIMP Run()
+ {
-+ mMenu->EndUpdateBatch();
++ if (!mWeakMenu) {
++ return NS_OK;
++ }
++
++ static_cast<nsMenu *>(mWeakMenu.get())->HandleContentInserted(mContainer,
++ mChild,
++ mPrevSibling);
++ return NS_OK;
+ }
+
+private:
-+ MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
-+ nsMenu *mMenu;
++ nsWeakMenuObject mWeakMenu;
++
++ nsCOMPtr<nsIContent> mContainer;
++ nsCOMPtr<nsIContent> mChild;
++ nsCOMPtr<nsIContent> mPrevSibling;
+};
+
-+class nsSetAttrRunnableNoNotify : public Runnable
++class nsMenuContentRemovedEvent : public Runnable
+{
+public:
-+ nsSetAttrRunnableNoNotify(nsIContent *aContent, nsIAtom *aAttribute,
-+ nsAString& aValue) :
-+ mContent(aContent), mAttribute(aAttribute), mValue(aValue) { };
++ nsMenuContentRemovedEvent(nsMenu *aMenu,
++ nsIContent *aContainer,
++ nsIContent *aChild) :
++ mWeakMenu(aMenu),
++ mContainer(aContainer),
++ mChild(aChild) { }
+
+ NS_IMETHODIMP Run()
+ {
-+ return mContent->SetAttr(kNameSpaceID_None, mAttribute, mValue, false);
++ if (!mWeakMenu) {
++ return NS_OK;
++ }
++
++ static_cast<nsMenu *>(mWeakMenu.get())->HandleContentRemoved(mContainer,
++ mChild);
++ return NS_OK;
+ }
+
+private:
-+ nsCOMPtr<nsIContent> mContent;
-+ nsCOMPtr<nsIAtom> mAttribute;
-+ nsAutoString mValue;
++ nsWeakMenuObject mWeakMenu;
++
++ nsCOMPtr<nsIContent> mContainer;
++ nsCOMPtr<nsIContent> mChild;
+};
+
-+class nsUnsetAttrRunnableNoNotify : public Runnable
++static void
++DispatchMouseEvent(nsIContent *aTarget, mozilla::EventMessage aMsg)
+{
-+public:
-+ nsUnsetAttrRunnableNoNotify(nsIContent *aContent, nsIAtom *aAttribute) :
-+ mContent(aContent), mAttribute(aAttribute) { };
-+
-+ NS_IMETHODIMP Run()
-+ {
-+ return mContent->UnsetAttr(kNameSpaceID_None, mAttribute, false);
++ if (!aTarget) {
++ return;
+ }
+
-+private:
-+ nsCOMPtr<nsIContent> mContent;
-+ nsCOMPtr<nsIAtom> mAttribute;
-+};
++ WidgetMouseEvent event(true, aMsg, nullptr, WidgetMouseEvent::eReal);
++ aTarget->DispatchDOMEvent(&event, nullptr, nullptr, nullptr);
++}
+
+static void
+AttachXBLBindings(nsIContent *aContent)
@@ -354,8 +442,8 @@ Index: firefox-52.0~b9+build2/widget/gtk/nsMenu.cpp
+ }
+
+ RefPtr<nsStyleContext> sc =
-+ shell->StyleSet()->ResolveStyleFor(aContent->AsElement(),
-+ nullptr);
++ shell->StyleSet()->AsGecko()->ResolveStyleFor(aContent->AsElement(),
++ nullptr);
+ if (!sc) {
+ return;
+ }
@@ -385,8 +473,7 @@ Index: firefox-52.0~b9+build2/widget/gtk/nsMenu.cpp
+void
+nsMenu::SetPopupState(EPopupState aState)
+{
-+ ClearFlags(((1U << NSMENU_NUMBER_OF_POPUPSTATE_BITS) - 1U) << NSMENU_NUMBER_OF_FLAGS);
-+ SetFlags(aState << NSMENU_NUMBER_OF_FLAGS);
++ mPopupState = aState;
+
+ if (!mPopupContent) {
+ return;
@@ -407,31 +494,28 @@ Index: firefox-52.0~b9+build2/widget/gtk/nsMenu.cpp
+ break;
+ }
+
-+ if (nsContentUtils::IsSafeToRunScript()) {
-+ if (state.IsEmpty()) {
-+ mPopupContent->UnsetAttr(kNameSpaceID_None,
-+ nsNativeMenuAtoms::_moz_menupopupstate,
-+ false);
-+ } else {
-+ mPopupContent->SetAttr(kNameSpaceID_None,
-+ nsNativeMenuAtoms::_moz_menupopupstate,
-+ state, false);
-+ }
++ if (state.IsEmpty()) {
++ mPopupContent->UnsetAttr(kNameSpaceID_None,
++ nsNativeMenuAtoms::_moz_nativemenupopupstate,
++ false);
+ } else {
-+ nsCOMPtr<nsIRunnable> r;
-+ if (state.IsEmpty()) {
-+ r = new nsUnsetAttrRunnableNoNotify(
-+ mPopupContent, nsNativeMenuAtoms::_moz_menupopupstate);
-+ } else {
-+ r = new nsSetAttrRunnableNoNotify(
-+ mPopupContent, nsNativeMenuAtoms::_moz_menupopupstate,
-+ state);
-+ }
-+ nsContentUtils::AddScriptRunner(r);
++ mPopupContent->SetAttr(kNameSpaceID_None,
++ nsNativeMenuAtoms::_moz_nativemenupopupstate,
++ state, false);
+ }
+}
+
+/* static */ void
++nsMenu::DoOpenCallback(nsITimer *aTimer, void *aClosure)
++{
++ nsMenu* self = static_cast<nsMenu *>(aClosure);
++
++ dbusmenu_menuitem_show_to_user(self->GetNativeData(), 0);
++
++ self->mOpenDelayTimer = nullptr;
++}
++
++/* static */ void
+nsMenu::menu_event_cb(DbusmenuMenuitem *menu,
+ const gchar *name,
+ GVariant *value,
@@ -456,83 +540,56 @@ Index: firefox-52.0~b9+build2/widget/gtk/nsMenu.cpp
+void
+nsMenu::MaybeAddPlaceholderItem()
+{
-+ NS_ASSERTION(!IsInUpdateBatch(),
-+ "Shouldn't be modifying the native menu structure now");
++ MOZ_ASSERT(!IsInBatchedUpdate(),
++ "Shouldn't be modifying the native menu structure now");
+
+ GList *children = dbusmenu_menuitem_get_children(GetNativeData());
+ if (!children) {
-+ NS_ASSERTION(!HasPlaceholderItem(), "Huh?");
++ MOZ_ASSERT(!mPlaceholderItem);
+
-+ DbusmenuMenuitem *ph = dbusmenu_menuitem_new();
-+ if (!ph) {
++ mPlaceholderItem = dbusmenu_menuitem_new();
++ if (!mPlaceholderItem) {
+ return;
+ }
+
-+ dbusmenu_menuitem_property_set_bool(
-+ ph, DBUSMENU_MENUITEM_PROP_VISIBLE, false);
++ dbusmenu_menuitem_property_set_bool(mPlaceholderItem,
++ DBUSMENU_MENUITEM_PROP_VISIBLE,
++ false);
+
-+ if (!dbusmenu_menuitem_child_append(GetNativeData(), ph)) {
-+ NS_WARNING("Failed to create placeholder item");
-+ g_object_unref(ph);
-+ return;
-+ }
-+
-+ g_object_unref(ph);
-+
-+ SetHasPlaceholderItem(true);
++ MOZ_ALWAYS_TRUE(
++ dbusmenu_menuitem_child_append(GetNativeData(), mPlaceholderItem));
+ }
+}
+
-+bool
++void
+nsMenu::EnsureNoPlaceholderItem()
+{
-+ NS_ASSERTION(!IsInUpdateBatch(),
-+ "Shouldn't be modifying the native menu structure now");
-+
-+ if (HasPlaceholderItem()) {
-+ GList *children = dbusmenu_menuitem_get_children(GetNativeData());
-+
-+ NS_ASSERTION(g_list_length(children) == 1,
-+ "Unexpected number of children in native menu (should be 1!)");
++ MOZ_ASSERT(!IsInBatchedUpdate(),
++ "Shouldn't be modifying the native menu structure now");
+
-+ SetHasPlaceholderItem(false);
-+
-+ if (!children) {
-+ return true;
-+ }
-+
-+ if (!dbusmenu_menuitem_child_delete(
-+ GetNativeData(), static_cast<DbusmenuMenuitem *>(children->data))) {
-+ NS_ERROR("Failed to remove placeholder item");
-+ return false;
-+ }
-+ }
-+
-+ return true;
-+}
-+
-+static void
-+DispatchMouseEvent(nsIContent *aTarget, mozilla::EventMessage aMsg)
-+{
-+ if (!aTarget) {
++ if (!mPlaceholderItem) {
+ return;
+ }
+
-+ WidgetMouseEvent event(true, aMsg, nullptr, WidgetMouseEvent::eReal);
-+ aTarget->DispatchDOMEvent(&event, nullptr, nullptr, nullptr);
++ MOZ_ALWAYS_TRUE(
++ dbusmenu_menuitem_child_delete(GetNativeData(), mPlaceholderItem));
++ MOZ_ASSERT(!dbusmenu_menuitem_get_children(GetNativeData()));
++
++ g_object_unref(mPlaceholderItem);
++ mPlaceholderItem = nullptr;
+}
+
+void
+nsMenu::OnOpen()
+{
-+ if (NeedsRebuild()) {
++ if (mNeedsRebuild) {
+ Build();
+ }
+
-+ nsWeakMenuObject<nsMenu> self(this);
++ nsWeakMenuObject self(this);
+ nsCOMPtr<nsIContent> origPopupContent(mPopupContent);
+ {
-+ nsNativeMenuAutoUpdateBatch batch;
++ nsNativeMenuDocListener::BlockUpdatesScope updatesBlocker;
+
+ SetPopupState(ePopupState_Showing);
+ DispatchMouseEvent(mPopupContent, eXULPopupShowing);
@@ -551,7 +608,7 @@ Index: firefox-52.0~b9+build2/widget/gtk/nsMenu.cpp
+ return;
+ }
+
-+ nsNativeMenuAutoUpdateBatch batch;
++ nsNativeMenuDocListener::BlockUpdatesScope updatesBlocker;
+
+ size_t count = ChildCount();
+ for (size_t i = 0; i < count; ++i) {
@@ -565,9 +622,7 @@ Index: firefox-52.0~b9+build2/widget/gtk/nsMenu.cpp
+void
+nsMenu::Build()
+{
-+ nsMenuUpdateBatch batch(this);
-+
-+ SetNeedsRebuild(false);
++ mNeedsRebuild = false;
+
+ while (ChildCount() > 0) {
+ RemoveChildAt(0);
@@ -583,51 +638,17 @@ Index: firefox-52.0~b9+build2/widget/gtk/nsMenu.cpp
+ for (uint32_t i = 0; i < count; ++i) {
+ nsIContent *childContent = mPopupContent->GetChildAt(i);
+
-+ nsresult rv;
-+ nsMenuObject *child = CreateChild(childContent, &rv);
++ UniquePtr<nsMenuObject> child = CreateChild(childContent);
+
-+ if (child) {
-+ rv = AppendChild(child);
++ if (!child) {
++ continue;
+ }
+
-+ if (NS_FAILED(rv)) {
-+ NS_ERROR("Menu build failed");
-+ SetNeedsRebuild(true);
-+ return;
-+ }
++ AppendChild(Move(child));
+ }
+}
+
+void
-+nsMenu::InitializeNativeData()
-+{
-+ // Dbusmenu provides an "about-to-show" signal, and also "opened" and
-+ // "closed" events. However, Unity is the only thing that sends
-+ // both "about-to-show" and "opened" events. Unity 2D and the HUD only
-+ // send "opened" events, so we ignore "about-to-show" (I don't think
-+ // there's any real difference between them anyway).
-+ // To complicate things, there are certain conditions where we don't
-+ // get a "closed" event, so we need to be able to handle this :/
-+ g_signal_connect(G_OBJECT(GetNativeData()), "event",
-+ G_CALLBACK(menu_event_cb), this);
-+
-+ UpdateLabel();
-+ UpdateSensitivity();
-+
-+ SetNeedsRebuild(true);
-+ MaybeAddPlaceholderItem();
-+
-+ AttachXBLBindings(ContentNode());
-+}
-+
-+void
-+nsMenu::Update(nsStyleContext *aStyleContext)
-+{
-+ UpdateVisibility(aStyleContext);
-+ UpdateIcon(aStyleContext);
-+}
-+
-+void
+nsMenu::InitializePopup()
+{
+ nsCOMPtr<nsIContent> oldPopupContent;
@@ -666,65 +687,68 @@ Index: firefox-52.0~b9+build2/widget/gtk/nsMenu.cpp
+}
+
+void
-+nsMenu::BeginUpdateBatchInternal()
-+{
-+ NS_ASSERTION(!IsInUpdateBatch(), "Already in an update batch!");
-+
-+ SetIsInUpdateBatch(true);
-+ SetDidStructureMutate(false);
-+}
-+
-+nsresult
+nsMenu::RemoveChildAt(size_t aIndex)
+{
-+ NS_ASSERTION(IsInUpdateBatch() || !HasPlaceholderItem(),
-+ "Shouldn't have a placeholder menuitem");
++ MOZ_ASSERT(IsInBatchedUpdate() || !mPlaceholderItem,
++ "Shouldn't have a placeholder menuitem");
+
-+ SetDidStructureMutate(true);
++ nsMenuContainer::RemoveChildAt(aIndex, !IsInBatchedUpdate());
++ StructureMutated();
+
-+ nsresult rv = nsMenuContainer::RemoveChildAt(aIndex, !IsInUpdateBatch());
-+
-+ if (!IsInUpdateBatch()) {
++ if (!IsInBatchedUpdate()) {
+ MaybeAddPlaceholderItem();
+ }
-+
-+ return rv;
+}
+
-+nsresult
++void
+nsMenu::RemoveChild(nsIContent *aChild)
+{
+ size_t index = IndexOf(aChild);
+ if (index == NoIndex) {
-+ return NS_ERROR_INVALID_ARG;
++ return;
+ }
+
-+ return RemoveChildAt(index);
++ RemoveChildAt(index);
+}
+
-+nsresult
-+nsMenu::InsertChildAfter(nsMenuObject *aChild, nsIContent *aPrevSibling)
++void
++nsMenu::InsertChildAfter(UniquePtr<nsMenuObject> aChild,
++ nsIContent *aPrevSibling)
+{
-+ if (!IsInUpdateBatch() && !EnsureNoPlaceholderItem()) {
-+ return NS_ERROR_FAILURE;
++ if (!IsInBatchedUpdate()) {
++ EnsureNoPlaceholderItem();
+ }
+
-+ SetDidStructureMutate(true);
-+
-+ return nsMenuContainer::InsertChildAfter(aChild, aPrevSibling,
-+ !IsInUpdateBatch());
++ nsMenuContainer::InsertChildAfter(Move(aChild), aPrevSibling,
++ !IsInBatchedUpdate());
++ StructureMutated();
+}
+
-+nsresult
-+nsMenu::AppendChild(nsMenuObject *aChild)
++void
++nsMenu::AppendChild(UniquePtr<nsMenuObject> aChild)
+{
-+ if (!IsInUpdateBatch() && !EnsureNoPlaceholderItem()) {
-+ return NS_ERROR_FAILURE;
++ if (!IsInBatchedUpdate()) {
++ EnsureNoPlaceholderItem();
+ }
+
-+ SetDidStructureMutate(true);
++ nsMenuContainer::AppendChild(Move(aChild), !IsInBatchedUpdate());
++ StructureMutated();
++}
++
++bool
++nsMenu::IsInBatchedUpdate() const
++{
++ return mBatchedUpdateState != eBatchedUpdateState_Inactive;
++}
++
++void
++nsMenu::StructureMutated()
++{
++ if (!IsInBatchedUpdate()) {
++ return;
++ }
+
-+ return nsMenuContainer::AppendChild(aChild, !IsInUpdateBatch());
++ mBatchedUpdateState = eBatchedUpdateState_DidMutate;
+}
+
+bool
@@ -740,184 +764,105 @@ Index: firefox-52.0~b9+build2/widget/gtk/nsMenu.cpp
+ return (isVisible && !isDisabled);
+}
+
-+nsMenuObject::PropertyFlags
-+nsMenu::SupportedProperties() const
-+{
-+ return static_cast<nsMenuObject::PropertyFlags>(
-+ nsMenuObject::ePropLabel |
-+ nsMenuObject::ePropEnabled |
-+ nsMenuObject::ePropVisible |
-+ nsMenuObject::ePropIconData |
-+ nsMenuObject::ePropChildDisplay
-+ );
-+}
-+
-+nsMenu::nsMenu() :
-+ nsMenuContainer()
-+{
-+ MOZ_COUNT_CTOR(nsMenu);
-+}
-+
-+nsMenu::~nsMenu()
++void
++nsMenu::HandleContentInserted(nsIContent *aContainer,
++ nsIContent *aChild,
++ nsIContent *aPrevSibling)
+{
-+ if (IsInUpdateBatch()) {
-+ EndUpdateBatch();
-+ }
-+
-+ // Although nsTArray will take care of this in its destructor,
-+ // we have to manually ensure children are removed from our native menu
-+ // item, just in case our parent recycles us
-+ while (ChildCount() > 0) {
-+ RemoveChildAt(0);
-+ }
-+
-+ EnsureNoPlaceholderItem();
-+
-+ if (DocListener() && mPopupContent) {
-+ DocListener()->UnregisterForContentChanges(mPopupContent);
-+ }
++ if (aContainer == mPopupContent) {
++ UniquePtr<nsMenuObject> child = CreateChild(aChild);
+
-+ if (GetNativeData()) {
-+ g_signal_handlers_disconnect_by_func(GetNativeData(),
-+ FuncToGpointer(menu_event_cb),
-+ this);
++ if (child) {
++ InsertChildAfter(Move(child), aPrevSibling);
++ }
++ } else {
++ Build();
+ }
-+
-+ MOZ_COUNT_DTOR(nsMenu);
+}
+
-+/* static */ nsMenuObject*
-+nsMenu::Create(nsMenuContainer *aParent, nsIContent *aContent)
++void
++nsMenu::HandleContentRemoved(nsIContent *aContainer, nsIContent *aChild)
+{
-+ nsAutoPtr<nsMenu> menu(new nsMenu());
-+ if (NS_FAILED(menu->Init(aParent, aContent))) {
-+ return nullptr;
++ if (aContainer == mPopupContent) {
++ RemoveChild(aChild);
++ } else {
++ Build();
+ }
-+
-+ return menu.forget();
+}
+
-+static void
-+DoOpen(nsITimer *aTimer, void *aClosure)
++void
++nsMenu::InitializeNativeData()
+{
-+ nsAutoWeakMenuObject<nsMenu> weakMenu(
-+ static_cast<nsWeakMenuObject<nsMenu> *>(aClosure));
-+
-+ if (weakMenu) {
-+ dbusmenu_menuitem_show_to_user(weakMenu->GetNativeData(), 0);
-+ }
-+
-+ NS_RELEASE(aTimer);
-+}
++ // Dbusmenu provides an "about-to-show" signal, and also "opened" and
++ // "closed" events. However, Unity is the only thing that sends
++ // both "about-to-show" and "opened" events. Unity 2D and the HUD only
++ // send "opened" events, so we ignore "about-to-show" (I don't think
++ // there's any real difference between them anyway).
++ // To complicate things, there are certain conditions where we don't
++ // get a "closed" event, so we need to be able to handle this :/
++ g_signal_connect(G_OBJECT(GetNativeData()), "event",
++ G_CALLBACK(menu_event_cb), this);
+
-+nsMenuObject::EType
-+nsMenu::Type() const
-+{
-+ return nsMenuObject::eType_Menu;
-+}
++ mNeedsRebuild = true;
++ mNeedsUpdate = true;
+
-+bool
-+nsMenu::IsBeingDisplayed() const
-+{
-+ return PopupState() == ePopupState_Open;
-+}
++ MaybeAddPlaceholderItem();
+
-+bool
-+nsMenu::NeedsRebuild() const
-+{
-+ return HasFlags(eFlag_NeedsRebuild);
++ AttachXBLBindings(ContentNode());
+}
+
+void
-+nsMenu::OpenMenu()
++nsMenu::Update(nsStyleContext *aStyleContext)
+{
-+ if (!CanOpen()) {
-+ return;
-+ }
++ if (mNeedsUpdate) {
++ mNeedsUpdate = false;
+
-+ // Here, we synchronously fire popupshowing and popupshown events and then
-+ // open the menu after a short delay. This allows the menu to refresh before
-+ // it's shown, and avoids an issue where keyboard focus is not on the first
-+ // item of the history menu in Firefox when opening it with the keyboard,
-+ // because extra items to appear at the top of the menu
-+
-+ OnOpen();
-+
-+ nsCOMPtr<nsITimer> timer = do_CreateInstance(NS_TIMER_CONTRACTID);
-+ if (!timer) {
-+ return;
-+ }
-+
-+ nsAutoWeakMenuObject<nsMenu> weakMenu(this);
-+
-+ if (NS_FAILED(timer->InitWithFuncCallback(DoOpen, weakMenu.getWeakPtr(),
-+ 100, nsITimer::TYPE_ONE_SHOT))) {
-+ return;
++ UpdateLabel();
++ UpdateSensitivity();
+ }
+
-+ timer.forget();
-+ weakMenu.forget();
++ UpdateVisibility(aStyleContext);
++ UpdateIcon(aStyleContext);
+}
+
-+void
-+nsMenu::OnClose()
++nsMenuObject::PropertyFlags
++nsMenu::SupportedProperties() const
+{
-+ if (PopupState() == ePopupState_Closed) {
-+ return;
-+ }
-+
-+ // We do this to avoid mutating our view of the menu until
-+ // after we have finished
-+ nsNativeMenuAutoUpdateBatch batch;
-+
-+ SetPopupState(ePopupState_Hiding);
-+ DispatchMouseEvent(mPopupContent, eXULPopupHiding);
-+
-+ // Sigh, make sure all of our descendants are closed, as we don't
-+ // always get closed events for submenus when scrubbing quickly through
-+ // the menu
-+ size_t count = ChildCount();
-+ for (size_t i = 0; i < count; ++i) {
-+ if (ChildAt(i)->Type() == nsMenuObject::eType_Menu) {
-+ static_cast<nsMenu *>(ChildAt(i))->OnClose();
-+ }
-+ }
-+
-+ SetPopupState(ePopupState_Closed);
-+ DispatchMouseEvent(mPopupContent, eXULPopupHidden);
-+
-+ ContentNode()->UnsetAttr(kNameSpaceID_None, nsGkAtoms::open, true);
++ return static_cast<nsMenuObject::PropertyFlags>(
++ nsMenuObject::ePropLabel |
++ nsMenuObject::ePropEnabled |
++ nsMenuObject::ePropVisible |
++ nsMenuObject::ePropIconData |
++ nsMenuObject::ePropChildDisplay
++ );
+}
+
+void
+nsMenu::OnAttributeChanged(nsIContent *aContent, nsIAtom *aAttribute)
+{
-+ NS_ASSERTION(aContent == ContentNode() || aContent == mPopupContent,
-+ "Received an event that wasn't meant for us!");
++ MOZ_ASSERT(aContent == ContentNode() || aContent == mPopupContent,
++ "Received an event that wasn't meant for us!");
+
-+ if (aAttribute == nsGkAtoms::open) {
++ if (mNeedsUpdate) {
+ return;
+ }
+
-+ if (Parent()->NeedsRebuild()) {
++ if (aContent != ContentNode()) {
+ return;
+ }
+
-+ if (aContent == ContentNode()) {
-+ if (aAttribute == nsGkAtoms::disabled) {
-+ UpdateSensitivity();
-+ } else if (aAttribute == nsGkAtoms::label ||
-+ aAttribute == nsGkAtoms::accesskey ||
-+ aAttribute == nsGkAtoms::crop) {
-+ UpdateLabel();
-+ }
-+ }
-+
-+ if (!Parent()->IsBeingDisplayed() || aContent != ContentNode()) {
++ if (!Parent()->IsBeingDisplayed()) {
++ mNeedsUpdate = true;
+ return;
+ }
+
-+ if (aAttribute == nsGkAtoms::hidden ||
++ if (aAttribute == nsGkAtoms::disabled) {
++ UpdateSensitivity();
++ } else if (aAttribute == nsGkAtoms::label ||
++ aAttribute == nsGkAtoms::accesskey ||
++ aAttribute == nsGkAtoms::crop) {
++ UpdateLabel();
++ } else if (aAttribute == nsGkAtoms::hidden ||
+ aAttribute == nsGkAtoms::collapsed) {
+ RefPtr<nsStyleContext> sc = GetStyleContext();
+ UpdateVisibility(sc);
@@ -931,57 +876,40 @@ Index: firefox-52.0~b9+build2/widget/gtk/nsMenu.cpp
+nsMenu::OnContentInserted(nsIContent *aContainer, nsIContent *aChild,
+ nsIContent *aPrevSibling)
+{
-+ NS_ASSERTION(aContainer == ContentNode() || aContainer == mPopupContent,
-+ "Received an event that wasn't meant for us!");
++ MOZ_ASSERT(aContainer == ContentNode() || aContainer == mPopupContent,
++ "Received an event that wasn't meant for us!");
+
-+ if (NeedsRebuild()) {
++ if (mNeedsRebuild) {
+ return;
+ }
+
-+ if (PopupState() == ePopupState_Closed) {
-+ SetNeedsRebuild(true);
++ if (mPopupState == ePopupState_Closed) {
++ mNeedsRebuild = true;
+ return;
+ }
+
-+ if (aContainer == mPopupContent) {
-+ nsresult rv;
-+ nsMenuObject *child = CreateChild(aChild, &rv);
-+
-+ if (child) {
-+ rv = InsertChildAfter(child, aPrevSibling);
-+ }
-+ if (NS_FAILED(rv)) {
-+ NS_ERROR("OnContentInserted() failed");
-+ SetNeedsRebuild(true);
-+ }
-+ } else {
-+ Build();
-+ }
++ nsContentUtils::AddScriptRunner(
++ new nsMenuContentInsertedEvent(this, aContainer, aChild,
++ aPrevSibling));
+}
+
+void
+nsMenu::OnContentRemoved(nsIContent *aContainer, nsIContent *aChild)
+{
-+ NS_ASSERTION(aContainer == ContentNode() || aContainer == mPopupContent,
-+ "Received an event that wasn't meant for us!");
++ MOZ_ASSERT(aContainer == ContentNode() || aContainer == mPopupContent,
++ "Received an event that wasn't meant for us!");
+
-+ if (NeedsRebuild()) {
++ if (mNeedsRebuild) {
+ return;
+ }
+
-+ if (PopupState() == ePopupState_Closed) {
-+ SetNeedsRebuild(true);
++ if (mPopupState == ePopupState_Closed) {
++ mNeedsRebuild = true;
+ return;
+ }
+
-+ if (aContainer == mPopupContent) {
-+ if (NS_FAILED(RemoveChild(aChild))) {
-+ NS_ERROR("OnContentRemoved() failed");
-+ SetNeedsRebuild(true);
-+ }
-+ } else {
-+ Build();
-+ }
++ nsContentUtils::AddScriptRunner(
++ new nsMenuContentRemovedEvent(this, aContainer, aChild));
+}
+
+/*
@@ -998,32 +926,35 @@ Index: firefox-52.0~b9+build2/widget/gtk/nsMenu.cpp
+ */
+
+void
-+nsMenu::BeginUpdateBatch(nsIContent *aContent)
++nsMenu::OnBeginUpdates(nsIContent *aContent)
+{
-+ NS_ASSERTION(aContent == ContentNode() || aContent == mPopupContent,
-+ "Received an event that wasn't meant for us!");
++ MOZ_ASSERT(aContent == ContentNode() || aContent == mPopupContent,
++ "Received an event that wasn't meant for us!");
++ MOZ_ASSERT(!IsInBatchedUpdate(), "Already in an update batch!");
+
-+ if (aContent == mPopupContent) {
-+ BeginUpdateBatchInternal();
++ if (aContent != mPopupContent) {
++ return;
+ }
++
++ mBatchedUpdateState = eBatchedUpdateState_Active;
+}
+
+void
-+nsMenu::EndUpdateBatch()
++nsMenu::OnEndUpdates()
+{
-+ NS_ASSERTION(IsInUpdateBatch(), "Not in an update batch");
++ if (!IsInBatchedUpdate()) {
++ return;
++ }
+
-+ SetIsInUpdateBatch(false);
++ bool didMutate = mBatchedUpdateState == eBatchedUpdateState_DidMutate;
++ mBatchedUpdateState = eBatchedUpdateState_Inactive;
+
+ /* Optimize for the case where we only had attribute changes */
-+ if (!DidStructureMutate()) {
++ if (!didMutate) {
+ return;
+ }
+
-+ if (!EnsureNoPlaceholderItem()) {
-+ SetNeedsRebuild(true);
-+ return;
-+ }
++ EnsureNoPlaceholderItem();
+
+ GList *nextNativeChild = dbusmenu_menuitem_get_children(GetNativeData());
+ DbusmenuMenuitem *nextOwnedNativeChild = nullptr;
@@ -1054,11 +985,8 @@ Index: firefox-52.0~b9+build2/widget/gtk/nsMenu.cpp
+ static_cast<DbusmenuMenuitem *>(nextNativeChild->data);
+ nextNativeChild = nextNativeChild->next;
+
-+ if (!dbusmenu_menuitem_child_delete(GetNativeData(), data)) {
-+ NS_ERROR("Failed to remove orphaned native item from menu");
-+ SetNeedsRebuild(true);
-+ return;
-+ }
++ MOZ_ALWAYS_TRUE(dbusmenu_menuitem_child_delete(GetNativeData(),
++ data));
+ }
+
+ if (nextNativeChild) {
@@ -1090,37 +1018,151 @@ Index: firefox-52.0~b9+build2/widget/gtk/nsMenu.cpp
+ // At this point, we modify the native menu structure.
+ if (!child->GetNativeData()) {
+ child->CreateNativeData();
-+ if (!dbusmenu_menuitem_child_add_position(GetNativeData(),
-+ child->GetNativeData(),
-+ i)) {
-+ NS_ERROR("Failed to add new native item");
-+ SetNeedsRebuild(true);
-+ return;
-+ }
++ MOZ_ALWAYS_TRUE(
++ dbusmenu_menuitem_child_add_position(GetNativeData(),
++ child->GetNativeData(),
++ i));
+ }
+ }
+ }
+
+ while (nextNativeChild) {
-+
+ DbusmenuMenuitem *data =
+ static_cast<DbusmenuMenuitem *>(nextNativeChild->data);
+ nextNativeChild = nextNativeChild->next;
+
-+ if (!dbusmenu_menuitem_child_delete(GetNativeData(), data)) {
-+ NS_ERROR("Failed to remove orphaned native item from menu");
-+ SetNeedsRebuild(true);
-+ return;
-+ }
++ MOZ_ALWAYS_TRUE(dbusmenu_menuitem_child_delete(GetNativeData(), data));
+ }
+
+ MaybeAddPlaceholderItem();
+}
-Index: firefox-52.0~b9+build2/widget/gtk/nsMenu.h
++
++nsMenu::nsMenu(nsMenuContainer *aParent, nsIContent *aContent) :
++ nsMenuContainer(aParent, aContent),
++ mNeedsRebuild(false),
++ mNeedsUpdate(false),
++ mPlaceholderItem(nullptr),
++ mPopupState(ePopupState_Closed),
++ mBatchedUpdateState(eBatchedUpdateState_Inactive)
++{
++ MOZ_COUNT_CTOR(nsMenu);
++}
++
++nsMenu::~nsMenu()
++{
++ if (IsInBatchedUpdate()) {
++ OnEndUpdates();
++ }
++
++ // Although nsTArray will take care of this in its destructor,
++ // we have to manually ensure children are removed from our native menu
++ // item, just in case our parent recycles us
++ while (ChildCount() > 0) {
++ RemoveChildAt(0);
++ }
++
++ EnsureNoPlaceholderItem();
++
++ if (DocListener() && mPopupContent) {
++ DocListener()->UnregisterForContentChanges(mPopupContent);
++ }
++
++ if (GetNativeData()) {
++ g_signal_handlers_disconnect_by_func(GetNativeData(),
++ FuncToGpointer(menu_event_cb),
++ this);
++ }
++
++ MOZ_COUNT_DTOR(nsMenu);
++}
++
++nsMenuObject::EType
++nsMenu::Type() const
++{
++ return eType_Menu;
++}
++
++bool
++nsMenu::IsBeingDisplayed() const
++{
++ return mPopupState == ePopupState_Open;
++}
++
++bool
++nsMenu::NeedsRebuild() const
++{
++ return mNeedsRebuild;
++}
++
++void
++nsMenu::OpenMenu()
++{
++ if (!CanOpen()) {
++ return;
++ }
++
++ if (mOpenDelayTimer) {
++ return;
++ }
++
++ // Here, we synchronously fire popupshowing and popupshown events and then
++ // open the menu after a short delay. This allows the menu to refresh before
++ // it's shown, and avoids an issue where keyboard focus is not on the first
++ // item of the history menu in Firefox when opening it with the keyboard,
++ // because extra items to appear at the top of the menu
++
++ OnOpen();
++
++ mOpenDelayTimer = do_CreateInstance(NS_TIMER_CONTRACTID);
++ if (!mOpenDelayTimer) {
++ return;
++ }
++
++ if (NS_FAILED(mOpenDelayTimer->InitWithFuncCallback(DoOpenCallback,
++ this,
++ 100,
++ nsITimer::TYPE_ONE_SHOT))) {
++ mOpenDelayTimer = nullptr;
++ }
++}
++
++void
++nsMenu::OnClose()
++{
++ if (mPopupState == ePopupState_Closed) {
++ return;
++ }
++
++ MOZ_ASSERT(nsContentUtils::IsSafeToRunScript());
++
++ // We do this to avoid mutating our view of the menu until
++ // after we have finished
++ nsNativeMenuDocListener::BlockUpdatesScope updatesBlocker;
++
++ SetPopupState(ePopupState_Hiding);
++ DispatchMouseEvent(mPopupContent, eXULPopupHiding);
++
++ // Sigh, make sure all of our descendants are closed, as we don't
++ // always get closed events for submenus when scrubbing quickly through
++ // the menu
++ size_t count = ChildCount();
++ for (size_t i = 0; i < count; ++i) {
++ if (ChildAt(i)->Type() == nsMenuObject::eType_Menu) {
++ static_cast<nsMenu *>(ChildAt(i))->OnClose();
++ }
++ }
++
++ SetPopupState(ePopupState_Closed);
++ DispatchMouseEvent(mPopupContent, eXULPopupHidden);
++
++ ContentNode()->UnsetAttr(kNameSpaceID_None, nsGkAtoms::open, true);
++}
++
+Index: firefox-53.0~a2~hg20170302r359591/widget/gtk/nsMenu.h
===================================================================
--- /dev/null
-+++ firefox-52.0~b9+build2/widget/gtk/nsMenu.h
-@@ -0,0 +1,166 @@
++++ firefox-53.0~a2~hg20170302r359591/widget/gtk/nsMenu.h
+@@ -0,0 +1,124 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* vim:expandtab:shiftwidth=4:tabstop=4:
+ */
@@ -1132,6 +1174,7 @@ Index: firefox-52.0~b9+build2/widget/gtk/nsMenu.h
+#define __nsMenu_h__
+
+#include "mozilla/Attributes.h"
++#include "mozilla/UniquePtr.h"
+#include "nsCOMPtr.h"
+
+#include "nsDbusmenu.h"
@@ -1142,6 +1185,7 @@ Index: firefox-52.0~b9+build2/widget/gtk/nsMenu.h
+
+class nsIAtom;
+class nsIContent;
++class nsITimer;
+class nsStyleContext;
+
+#define NSMENU_NUMBER_OF_POPUPSTATE_BITS 2U
@@ -1151,15 +1195,13 @@ Index: firefox-52.0~b9+build2/widget/gtk/nsMenu.h
+class nsMenu final : public nsMenuContainer
+{
+public:
++ nsMenu(nsMenuContainer *aParent, nsIContent *aContent);
+ ~nsMenu();
+
-+ static nsMenuObject* Create(nsMenuContainer *aParent,
-+ nsIContent *aContent);
++ nsMenuObject::EType Type() const override;
+
-+ nsMenuObject::EType Type() const;
-+
-+ bool IsBeingDisplayed() const;
-+ bool NeedsRebuild() const;
++ bool IsBeingDisplayed() const override;
++ bool NeedsRebuild() const override;
+
+ // Tell the desktop shell to display this menu
+ void OpenMenu();
@@ -1168,31 +1210,9 @@ Index: firefox-52.0~b9+build2/widget/gtk/nsMenu.h
+ // menuitems can do the shells work. Sigh....
+ void OnClose();
+
-+ void OnAttributeChanged(nsIContent *aContent, nsIAtom *aAttribute);
-+ void OnContentInserted(nsIContent *aContainer, nsIContent *aChild,
-+ nsIContent *aPrevSibling);
-+ void OnContentRemoved(nsIContent *aContainer, nsIContent *aChild);
-+ void BeginUpdateBatch(nsIContent *aContent);
-+ void EndUpdateBatch();
-+
+private:
-+ friend class nsMenuUpdateBatch;
-+
-+ enum {
-+ // This menu needs rebuilding the next time it is opened
-+ eFlag_NeedsRebuild = 1 << 0,
-+
-+ // This menu contains a placeholder
-+ eFlag_HasPlaceholderItem = 1 << 1,
-+
-+ // This menu is currently receiving a batch of updates, and
-+ // the native structure should not be modified
-+ eFlag_InUpdateBatch = 1 << 2,
-+
-+ // Children were added to / removed from this menu (only valid
-+ // when eFlag_InUpdateBatch is set)
-+ eFlag_StructureMutated = 1 << 3
-+ };
++ friend class nsMenuContentInsertedEvent;
++ friend class nsMenuContentRemovedEvent;
+
+ enum EPopupState {
+ ePopupState_Closed,
@@ -1201,64 +1221,9 @@ Index: firefox-52.0~b9+build2/widget/gtk/nsMenu.h
+ ePopupState_Hiding
+ };
+
-+ nsMenu();
-+
-+ void SetNeedsRebuild(bool aValue)
-+ {
-+ if (aValue) {
-+ SetFlags(eFlag_NeedsRebuild);
-+ } else {
-+ ClearFlags(eFlag_NeedsRebuild);
-+ }
-+ }
-+ bool HasPlaceholderItem() const
-+ {
-+ return HasFlags(eFlag_HasPlaceholderItem);
-+ }
-+ void SetHasPlaceholderItem(bool aValue)
-+ {
-+ if (aValue) {
-+ SetFlags(eFlag_HasPlaceholderItem);
-+ } else {
-+ ClearFlags(eFlag_HasPlaceholderItem);
-+ }
-+ }
-+
-+ bool IsInUpdateBatch() const
-+ {
-+ return HasFlags(eFlag_InUpdateBatch);
-+ }
-+ void SetIsInUpdateBatch(bool aValue)
-+ {
-+ if (aValue) {
-+ SetFlags(eFlag_InUpdateBatch);
-+ } else {
-+ ClearFlags(eFlag_InUpdateBatch);
-+ }
-+ }
-+
-+ bool DidStructureMutate() const
-+ {
-+ return HasFlags(eFlag_StructureMutated);
-+ }
-+ void SetDidStructureMutate(bool aValue)
-+ {
-+ if (aValue) {
-+ SetFlags(eFlag_StructureMutated);
-+ } else {
-+ ClearFlags(eFlag_StructureMutated);
-+ }
-+ }
-+
-+ EPopupState PopupState() const
-+ {
-+ return static_cast<EPopupState>(
-+ (GetFlags() &
-+ (((1U << NSMENU_NUMBER_OF_POPUPSTATE_BITS) - 1U)
-+ << NSMENU_NUMBER_OF_FLAGS)) >> NSMENU_NUMBER_OF_FLAGS);
-+ };
+ void SetPopupState(EPopupState aState);
+
++ static void DoOpenCallback(nsITimer *aTimer, void *aClosure);
+ static void menu_event_cb(DbusmenuMenuitem *menu,
+ const gchar *name,
+ GVariant *value,
@@ -1268,30 +1233,65 @@ Index: firefox-52.0~b9+build2/widget/gtk/nsMenu.h
+ // We add a placeholder item to empty menus so that Unity actually treats
+ // us as a proper menu, rather than a menuitem without a submenu
+ void MaybeAddPlaceholderItem();
-+ bool EnsureNoPlaceholderItem();
++
++ // Removes a placeholder item if it exists and asserts that this succeeds
++ void EnsureNoPlaceholderItem();
+
+ void OnOpen();
+ void Build();
-+ void InitializeNativeData();
-+ void Update(nsStyleContext *aStyleContext);
+ void InitializePopup();
-+ void BeginUpdateBatchInternal();
-+ nsresult RemoveChildAt(size_t aIndex);
-+ nsresult RemoveChild(nsIContent *aChild);
-+ nsresult InsertChildAfter(nsMenuObject *aChild, nsIContent *aPrevSibling);
-+ nsresult AppendChild(nsMenuObject *aChild);
++ void RemoveChildAt(size_t aIndex);
++ void RemoveChild(nsIContent *aChild);
++ void InsertChildAfter(mozilla::UniquePtr<nsMenuObject> aChild,
++ nsIContent *aPrevSibling);
++ void AppendChild(mozilla::UniquePtr<nsMenuObject> aChild);
++ bool IsInBatchedUpdate() const;
++ void StructureMutated();
+ bool CanOpen() const;
-+ nsMenuObject::PropertyFlags SupportedProperties() const;
++
++ void HandleContentInserted(nsIContent *aContainer,
++ nsIContent *aChild,
++ nsIContent *aPrevSibling);
++ void HandleContentRemoved(nsIContent *aContainer,
++ nsIContent *aChild);
++
++ void InitializeNativeData() override;
++ void Update(nsStyleContext *aStyleContext) override;
++ nsMenuObject::PropertyFlags SupportedProperties() const override;
++
++ void OnAttributeChanged(nsIContent *aContent, nsIAtom *aAttribute) override;
++ void OnContentInserted(nsIContent *aContainer, nsIContent *aChild,
++ nsIContent *aPrevSibling) override;
++ void OnContentRemoved(nsIContent *aContainer, nsIContent *aChild) override;
++ void OnBeginUpdates(nsIContent *aContent) override;
++ void OnEndUpdates() override;
++
++ bool mNeedsRebuild;
++ bool mNeedsUpdate;
++
++ DbusmenuMenuitem *mPlaceholderItem;
++
++ EPopupState mPopupState;
++
++ enum EBatchedUpdateState {
++ eBatchedUpdateState_Inactive,
++ eBatchedUpdateState_Active,
++ eBatchedUpdateState_DidMutate
++ };
++
++ EBatchedUpdateState mBatchedUpdateState;
+
+ nsCOMPtr<nsIContent> mPopupContent;
++
++ nsCOMPtr<nsITimer> mOpenDelayTimer;
+};
+
+#endif /* __nsMenu_h__ */
-Index: firefox-52.0~b9+build2/widget/gtk/nsMenuBar.cpp
+Index: firefox-53.0~a2~hg20170302r359591/widget/gtk/nsMenuBar.cpp
===================================================================
--- /dev/null
-+++ firefox-52.0~b9+build2/widget/gtk/nsMenuBar.cpp
-@@ -0,0 +1,545 @@
++++ firefox-53.0~a2~hg20170302r359591/widget/gtk/nsMenuBar.cpp
+@@ -0,0 +1,572 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* vim:expandtab:shiftwidth=4:tabstop=4:
+ */
@@ -1299,15 +1299,19 @@ Index: firefox-52.0~b9+build2/widget/gtk/nsMenuBar.cpp
+ * 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/. */
+
++#include "mozilla/Assertions.h"
+#include "mozilla/DebugOnly.h"
+#include "mozilla/dom/Element.h"
++#include "mozilla/Move.h"
+#include "mozilla/Preferences.h"
+#include "nsAutoPtr.h"
++#include "nsContentUtils.h"
+#include "nsIDocument.h"
+#include "nsIDOMEvent.h"
+#include "nsIDOMEventListener.h"
+#include "nsIDOMEventTarget.h"
+#include "nsIDOMKeyEvent.h"
++#include "nsIRunnable.h"
+#include "nsIWidget.h"
+#include "nsTArray.h"
+#include "nsUnicharUtils.h"
@@ -1325,24 +1329,90 @@ Index: firefox-52.0~b9+build2/widget/gtk/nsMenuBar.cpp
+
+using namespace mozilla;
+
-+class nsMenuBarDocEventListener final : public nsIDOMEventListener
++static bool
++ShouldHandleKeyEvent(nsIDOMEvent *aEvent)
++{
++ bool handled, trusted = false;
++ aEvent->GetPreventDefault(&handled);
++ aEvent->GetIsTrusted(&trusted);
++
++ if (handled || !trusted) {
++ return false;
++ }
++
++ return true;
++}
++
++class nsMenuBarContentInsertedEvent : public Runnable
++{
++public:
++ nsMenuBarContentInsertedEvent(nsMenuBar *aMenuBar,
++ nsIContent *aChild,
++ nsIContent *aPrevSibling) :
++ mWeakMenuBar(aMenuBar),
++ mChild(aChild),
++ mPrevSibling(aPrevSibling) { }
++
++ NS_IMETHODIMP Run()
++ {
++ if (!mWeakMenuBar) {
++ return NS_OK;
++ }
++
++ static_cast<nsMenuBar *>(mWeakMenuBar.get())->HandleContentInserted(mChild,
++ mPrevSibling);
++ return NS_OK;
++ }
++
++private:
++ nsWeakMenuObject mWeakMenuBar;
++
++ nsCOMPtr<nsIContent> mChild;
++ nsCOMPtr<nsIContent> mPrevSibling;
++};
++
++class nsMenuBarContentRemovedEvent : public Runnable
++{
++public:
++ nsMenuBarContentRemovedEvent(nsMenuBar *aMenuBar,
++ nsIContent *aChild) :
++ mWeakMenuBar(aMenuBar),
++ mChild(aChild) { }
++
++ NS_IMETHODIMP Run()
++ {
++ if (!mWeakMenuBar) {
++ return NS_OK;
++ }
++
++ static_cast<nsMenuBar *>(mWeakMenuBar.get())->HandleContentRemoved(mChild);
++ return NS_OK;
++ }
++
++private:
++ nsWeakMenuObject mWeakMenuBar;
++
++ nsCOMPtr<nsIContent> mChild;
++};
++
++class nsMenuBar::DocEventListener final : public nsIDOMEventListener
+{
+public:
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSIDOMEVENTLISTENER
+
-+ nsMenuBarDocEventListener(nsMenuBar *aOwner) : mOwner(aOwner) { };
++ DocEventListener(nsMenuBar *aOwner) : mOwner(aOwner) { };
+
+private:
-+ ~nsMenuBarDocEventListener() { };
++ ~DocEventListener() { };
+
+ nsMenuBar *mOwner;
+};
+
-+NS_IMPL_ISUPPORTS(nsMenuBarDocEventListener, nsIDOMEventListener)
++NS_IMPL_ISUPPORTS(nsMenuBar::DocEventListener, nsIDOMEventListener)
+
+NS_IMETHODIMP
-+nsMenuBarDocEventListener::HandleEvent(nsIDOMEvent *aEvent)
++nsMenuBar::DocEventListener::HandleEvent(nsIDOMEvent *aEvent)
+{
+ nsAutoString type;
+ nsresult rv = aEvent->GetType(type);
@@ -1366,6 +1436,78 @@ Index: firefox-52.0~b9+build2/widget/gtk/nsMenuBar.cpp
+ return rv;
+}
+
++nsMenuBar::nsMenuBar(nsIContent *aMenuBarNode) :
++ nsMenuContainer(new nsNativeMenuDocListener(aMenuBarNode), aMenuBarNode),
++ mTopLevel(nullptr),
++ mServer(nullptr),
++ mIsActive(false)
++{
++ MOZ_COUNT_CTOR(nsMenuBar);
++}
++
++nsresult
++nsMenuBar::Init(nsIWidget *aParent)
++{
++ MOZ_ASSERT(aParent);
++
++ GdkWindow *gdkWin = static_cast<GdkWindow *>(
++ aParent->GetNativeData(NS_NATIVE_WINDOW));
++ if (!gdkWin) {
++ return NS_ERROR_FAILURE;
++ }
++
++ gpointer user_data = nullptr;
++ gdk_window_get_user_data(gdkWin, &user_data);
++ if (!user_data || !GTK_IS_CONTAINER(user_data)) {
++ return NS_ERROR_FAILURE;
++ }
++
++ mTopLevel = gtk_widget_get_toplevel(GTK_WIDGET(user_data));
++ if (!mTopLevel) {
++ return NS_ERROR_FAILURE;
++ }
++
++ g_object_ref(mTopLevel);
++
++ nsAutoCString path;
++ path.Append(NS_LITERAL_CSTRING("/com/canonical/menu/"));
++ char xid[10];
++ sprintf(xid, "%X", static_cast<uint32_t>(
++ GDK_WINDOW_XID(gtk_widget_get_window(mTopLevel))));
++ path.Append(xid);
++
++ mServer = dbusmenu_server_new(path.get());
++ if (!mServer) {
++ return NS_ERROR_FAILURE;
++ }
++
++ CreateNativeData();
++ if (!GetNativeData()) {
++ return NS_ERROR_FAILURE;
++ }
++
++ dbusmenu_server_set_root(mServer, GetNativeData());
++
++ mEventListener = new DocEventListener(this);
++
++ mDocument = do_QueryInterface(ContentNode()->OwnerDoc());
++
++ mAccessKey = Preferences::GetInt("ui.key.menuAccessKey");
++ if (mAccessKey == nsIDOMKeyEvent::DOM_VK_SHIFT) {
++ mAccessKeyMask = eModifierShift;
++ } else if (mAccessKey == nsIDOMKeyEvent::DOM_VK_CONTROL) {
++ mAccessKeyMask = eModifierCtrl;
++ } else if (mAccessKey == nsIDOMKeyEvent::DOM_VK_ALT) {
++ mAccessKeyMask = eModifierAlt;
++ } else if (mAccessKey == nsIDOMKeyEvent::DOM_VK_META) {
++ mAccessKeyMask = eModifierMeta;
++ } else {
++ mAccessKeyMask = eModifierAlt;
++ }
++
++ return NS_OK;
++}
++
+void
+nsMenuBar::Build()
+{
@@ -1373,17 +1515,13 @@ Index: firefox-52.0~b9+build2/widget/gtk/nsMenuBar.cpp
+ for (uint32_t i = 0; i < count; ++i) {
+ nsIContent *childContent = ContentNode()->GetChildAt(i);
+
-+ nsresult rv;
-+ nsMenuObject *child = CreateChild(childContent, &rv);
++ UniquePtr<nsMenuObject> child = CreateChild(childContent);
+
-+ if (child) {
-+ rv = AppendChild(child);
++ if (!child) {
++ continue;
+ }
+
-+ if (NS_FAILED(rv)) {
-+ NS_ERROR("Failed to build menubar");
-+ return;
-+ }
++ AppendChild(Move(child));
+ }
+}
+
@@ -1432,20 +1570,6 @@ Index: firefox-52.0~b9+build2/widget/gtk/nsMenuBar.cpp
+ dbusmenu_server_set_status(mServer, DBUSMENU_STATUS_NORMAL);
+}
+
-+static bool
-+ShouldHandleKeyEvent(nsIDOMEvent *aEvent)
-+{
-+ bool handled, trusted = false;
-+ aEvent->GetPreventDefault(&handled);
-+ aEvent->GetIsTrusted(&trusted);
-+
-+ if (handled || !trusted) {
-+ return false;
-+ }
-+
-+ return true;
-+}
-+
+nsMenuBar::ModifierFlags
+nsMenuBar::GetModifiersFromEvent(nsIDOMKeyEvent *aEvent)
+{
@@ -1576,85 +1700,43 @@ Index: firefox-52.0~b9+build2/widget/gtk/nsMenuBar.cpp
+ return NS_OK;
+}
+
-+nsMenuBar::nsMenuBar() :
-+ nsMenuContainer(),
-+ mTopLevel(nullptr),
-+ mServer(nullptr),
-+ mIsActive(false)
-+{
-+ MOZ_COUNT_CTOR(nsMenuBar);
-+}
-+
-+nsresult
-+nsMenuBar::Init(nsIWidget *aParent, nsIContent *aMenuBarNode)
++void
++nsMenuBar::HandleContentInserted(nsIContent *aChild, nsIContent *aPrevSibling)
+{
-+ NS_ENSURE_ARG(aParent);
-+ NS_ENSURE_ARG(aMenuBarNode);
-+
-+ GdkWindow *gdkWin = static_cast<GdkWindow *>(
-+ aParent->GetNativeData(NS_NATIVE_WINDOW));
-+ if (!gdkWin) {
-+ return NS_ERROR_FAILURE;
-+ }
-+
-+ gpointer user_data = nullptr;
-+ gdk_window_get_user_data(gdkWin, &user_data);
-+ if (!user_data || !GTK_IS_CONTAINER(user_data)) {
-+ return NS_ERROR_FAILURE;
-+ }
-+
-+ mTopLevel = gtk_widget_get_toplevel(GTK_WIDGET(user_data));
-+ if (!mTopLevel) {
-+ return NS_ERROR_FAILURE;
-+ }
-+
-+ g_object_ref(mTopLevel);
-+
-+ RefPtr<nsNativeMenuDocListener> listener =
-+ nsNativeMenuDocListener::Create(aMenuBarNode);
-+ if (!listener) {
-+ return NS_ERROR_FAILURE;
-+ }
++ UniquePtr<nsMenuObject> child = CreateChild(aChild);
+
-+ nsMenuObject::Init(listener, aMenuBarNode);
-+
-+ nsAutoCString path;
-+ path.Append(NS_LITERAL_CSTRING("/com/canonical/menu/"));
-+ char xid[10];
-+ sprintf(xid, "%X", static_cast<uint32_t>(
-+ GDK_WINDOW_XID(gtk_widget_get_window(mTopLevel))));
-+ path.Append(xid);
-+
-+ mServer = dbusmenu_server_new(path.get());
-+ if (!mServer) {
-+ return NS_ERROR_FAILURE;
++ if (!child) {
++ return;
+ }
+
-+ CreateNativeData();
-+ if (!GetNativeData()) {
-+ return NS_ERROR_FAILURE;
-+ }
++ InsertChildAfter(Move(child), aPrevSibling);
++}
+
-+ dbusmenu_server_set_root(mServer, GetNativeData());
++void
++nsMenuBar::HandleContentRemoved(nsIContent *aChild)
++{
++ RemoveChild(aChild);
++}
+
-+ mEventListener = new nsMenuBarDocEventListener(this);
++void
++nsMenuBar::OnContentInserted(nsIContent *aContainer, nsIContent *aChild,
++ nsIContent *aPrevSibling)
++{
++ MOZ_ASSERT(aContainer == ContentNode(),
++ "Received an event that wasn't meant for us");
+
-+ mDocument = do_QueryInterface(ContentNode()->OwnerDoc());
++ nsContentUtils::AddScriptRunner(
++ new nsMenuBarContentInsertedEvent(this, aChild, aPrevSibling));
++}
+
-+ mAccessKey = Preferences::GetInt("ui.key.menuAccessKey");
-+ if (mAccessKey == nsIDOMKeyEvent::DOM_VK_SHIFT) {
-+ mAccessKeyMask = eModifierShift;
-+ } else if (mAccessKey == nsIDOMKeyEvent::DOM_VK_CONTROL) {
-+ mAccessKeyMask = eModifierCtrl;
-+ } else if (mAccessKey == nsIDOMKeyEvent::DOM_VK_ALT) {
-+ mAccessKeyMask = eModifierAlt;
-+ } else if (mAccessKey == nsIDOMKeyEvent::DOM_VK_META) {
-+ mAccessKeyMask = eModifierMeta;
-+ } else {
-+ mAccessKeyMask = eModifierAlt;
-+ }
++void
++nsMenuBar::OnContentRemoved(nsIContent *aContainer, nsIContent *aChild)
++{
++ MOZ_ASSERT(aContainer == ContentNode(),
++ "Received an event that wasn't meant for us");
+
-+ return NS_OK;
++ nsContentUtils::AddScriptRunner(
++ new nsMenuBarContentRemovedEvent(this, aChild));
+}
+
+nsMenuBar::~nsMenuBar()
@@ -1693,21 +1775,21 @@ Index: firefox-52.0~b9+build2/widget/gtk/nsMenuBar.cpp
+ MOZ_COUNT_DTOR(nsMenuBar);
+}
+
-+/* static */ nsMenuBar*
++/* static */ UniquePtr<nsMenuBar>
+nsMenuBar::Create(nsIWidget *aParent, nsIContent *aMenuBarNode)
+{
-+ nsAutoPtr<nsMenuBar> menubar(new nsMenuBar());
-+ if (NS_FAILED(menubar->Init(aParent, aMenuBarNode))) {
++ UniquePtr<nsMenuBar> menubar(new nsMenuBar(aMenuBarNode));
++ if (NS_FAILED(menubar->Init(aParent))) {
+ return nullptr;
+ }
+
-+ return menubar.forget();
++ return Move(menubar);
+}
+
+nsMenuObject::EType
+nsMenuBar::Type() const
+{
-+ return nsMenuObject::eType_MenuBar;
++ return eType_MenuBar;
+}
+
+bool
@@ -1732,26 +1814,6 @@ Index: firefox-52.0~b9+build2/widget/gtk/nsMenuBar.cpp
+ return result;
+}
+
-+nsNativeMenuGIORequest&
-+nsMenuBar::BeginRegisterRequest()
-+{
-+ mRegisterRequestCanceller.Start();
-+ return mRegisterRequestCanceller;
-+}
-+
-+void
-+nsMenuBar::EndRegisterRequest()
-+{
-+ NS_ASSERTION(RegisterRequestInProgress(), "No request in progress");
-+ mRegisterRequestCanceller.Finish();
-+}
-+
-+bool
-+nsMenuBar::RegisterRequestInProgress() const
-+{
-+ return mRegisterRequestCanceller.InProgress();
-+}
-+
+void
+nsMenuBar::Activate()
+{
@@ -1795,8 +1857,6 @@ Index: firefox-52.0~b9+build2/widget/gtk/nsMenuBar.cpp
+
+ mIsActive = false;
+
-+ mRegisterRequestCanceller.Cancel();
-+
+ SetShellShowingMenuBar(false);
+ while (ChildCount() > 0) {
+ RemoveChildAt(0);
@@ -1804,44 +1864,11 @@ Index: firefox-52.0~b9+build2/widget/gtk/nsMenuBar.cpp
+ DocListener()->Stop();
+ DisconnectDocumentEventListeners();
+}
-+
-+void
-+nsMenuBar::OnAttributeChanged(nsIContent *aContent, nsIAtom *aAttribute)
-+{
-+
-+}
-+
-+void
-+nsMenuBar::OnContentInserted(nsIContent *aContainer, nsIContent *aChild,
-+ nsIContent *aPrevSibling)
-+{
-+ NS_ASSERTION(aContainer == ContentNode(),
-+ "Received an event that wasn't meant for us");
-+
-+ nsresult rv;
-+ nsMenuObject *child = CreateChild(aChild, &rv);
-+
-+ if (child) {
-+ rv = InsertChildAfter(child, aPrevSibling);
-+ }
-+
-+ NS_ASSERTION(NS_SUCCEEDED(rv), "Failed to insert item in to menubar");
-+}
-+
-+void
-+nsMenuBar::OnContentRemoved(nsIContent *aContainer, nsIContent *aChild)
-+{
-+ NS_ASSERTION(aContainer == ContentNode(),
-+ "Received an event that wasn't meant for us");
-+
-+ DebugOnly<nsresult> rv = RemoveChild(aChild);
-+ NS_ASSERTION(NS_SUCCEEDED(rv), "Failed to remove item from menubar");
-+}
-Index: firefox-52.0~b9+build2/widget/gtk/nsMenuBar.h
+Index: firefox-53.0~a2~hg20170302r359591/widget/gtk/nsMenuBar.h
===================================================================
--- /dev/null
-+++ firefox-52.0~b9+build2/widget/gtk/nsMenuBar.h
-@@ -0,0 +1,112 @@
++++ firefox-53.0~a2~hg20170302r359591/widget/gtk/nsMenuBar.h
+@@ -0,0 +1,107 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* vim:expandtab:shiftwidth=4:tabstop=4:
+ */
@@ -1853,13 +1880,13 @@ Index: firefox-52.0~b9+build2/widget/gtk/nsMenuBar.h
+#define __nsMenuBar_h__
+
+#include "mozilla/Attributes.h"
++#include "mozilla/UniquePtr.h"
+#include "nsCOMPtr.h"
+#include "nsString.h"
+
+#include "nsDbusmenu.h"
+#include "nsMenuContainer.h"
+#include "nsMenuObject.h"
-+#include "nsNativeMenuUtils.h"
+
+#include <gtk/gtk.h>
+
@@ -1880,14 +1907,14 @@ Index: firefox-52.0~b9+build2/widget/gtk/nsMenuBar.h
+class nsMenuBar final : public nsMenuContainer
+{
+public:
-+ ~nsMenuBar();
++ ~nsMenuBar() override;
+
-+ static nsMenuBar* Create(nsIWidget *aParent,
-+ nsIContent *aMenuBarNode);
++ static mozilla::UniquePtr<nsMenuBar> Create(nsIWidget *aParent,
++ nsIContent *aMenuBarNode);
+
-+ nsMenuObject::EType Type() const;
++ nsMenuObject::EType Type() const override;
+
-+ bool IsBeingDisplayed() const;
++ bool IsBeingDisplayed() const override;
+
+ // Get the native window ID for this menubar
+ uint32_t WindowId() const;
@@ -1895,15 +1922,6 @@ Index: firefox-52.0~b9+build2/widget/gtk/nsMenuBar.h
+ // Get the object path for this menubar
+ nsAdoptingCString ObjectPath() const;
+
-+ // Initializes and returns a cancellable request object, used
-+ // by the menuservice when registering this menubar
-+ nsNativeMenuGIORequest& BeginRegisterRequest();
-+
-+ // Finishes the current request to register the menubar
-+ void EndRegisterRequest();
-+
-+ bool RegisterRequestInProgress() const;
-+
+ // Get the top-level GtkWindow handle
+ GtkWidget* TopLevelWindow() { return mTopLevel; }
+
@@ -1915,13 +1933,10 @@ Index: firefox-52.0~b9+build2/widget/gtk/nsMenuBar.h
+ // with the desktop shell. Will cause the XUL menubar to be shown again
+ void Deactivate();
+
-+ void OnAttributeChanged(nsIContent *aContent, nsIAtom *aAttribute);
-+ void OnContentInserted(nsIContent *aContainer, nsIContent *aChild,
-+ nsIContent *aPrevSibling);
-+ void OnContentRemoved(nsIContent *aContainer, nsIContent *aChild);
-+
+private:
-+ friend class nsMenuBarDocEventListener;
++ class DocEventListener;
++ friend class nsMenuBarContentInsertedEvent;
++ friend class nsMenuBarContentRemovedEvent;
+
+ enum ModifierFlags {
+ eModifierShift = (1 << 0),
@@ -1930,8 +1945,8 @@ Index: firefox-52.0~b9+build2/widget/gtk/nsMenuBar.h
+ eModifierMeta = (1 << 3)
+ };
+
-+ nsMenuBar();
-+ nsresult Init(nsIWidget *aParent, nsIContent *aMenuBarNode);
++ nsMenuBar(nsIContent *aMenuBarNode);
++ nsresult Init(nsIWidget *aParent);
+ void Build();
+ void DisconnectDocumentEventListeners();
+ void SetShellShowingMenuBar(bool aShowing);
@@ -1942,11 +1957,18 @@ Index: firefox-52.0~b9+build2/widget/gtk/nsMenuBar.h
+ nsresult KeyDown(nsIDOMEvent *aEvent);
+ nsresult KeyUp(nsIDOMEvent *aEvent);
+
++ void HandleContentInserted(nsIContent *aChild,
++ nsIContent *aPrevSibling);
++ void HandleContentRemoved(nsIContent *aChild);
++
++ void OnContentInserted(nsIContent *aContainer, nsIContent *aChild,
++ nsIContent *aPrevSibling) override;
++ void OnContentRemoved(nsIContent *aContainer, nsIContent *aChild) override;
++
+ GtkWidget *mTopLevel;
+ DbusmenuServer *mServer;
+ nsCOMPtr<nsIDOMEventTarget> mDocument;
-+ nsNativeMenuGIORequest mRegisterRequestCanceller;
-+ RefPtr<nsMenuBarDocEventListener> mEventListener;
++ RefPtr<DocEventListener> mEventListener;
+
+ uint32_t mAccessKey;
+ ModifierFlags mAccessKeyMask;
@@ -1954,11 +1976,11 @@ Index: firefox-52.0~b9+build2/widget/gtk/nsMenuBar.h
+};
+
+#endif /* __nsMenuBar_h__ */
-Index: firefox-52.0~b9+build2/widget/gtk/nsMenuContainer.cpp
+Index: firefox-53.0~a2~hg20170302r359591/widget/gtk/nsMenuContainer.cpp
===================================================================
--- /dev/null
-+++ firefox-52.0~b9+build2/widget/gtk/nsMenuContainer.cpp
-@@ -0,0 +1,174 @@
++++ firefox-53.0~a2~hg20170302r359591/widget/gtk/nsMenuContainer.cpp
+@@ -0,0 +1,172 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* vim:expandtab:shiftwidth=4:tabstop=4:
+ */
@@ -1966,6 +1988,8 @@ Index: firefox-52.0~b9+build2/widget/gtk/nsMenuContainer.cpp
+ * 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/. */
+
++#include "mozilla/DebugOnly.h"
++#include "mozilla/Move.h"
+#include "nsGkAtoms.h"
+#include "nsIAtom.h"
+#include "nsIContent.h"
@@ -1977,19 +2001,29 @@ Index: firefox-52.0~b9+build2/widget/gtk/nsMenuContainer.cpp
+
+#include "nsMenuContainer.h"
+
++using namespace mozilla;
++
+const nsMenuContainer::ChildTArray::index_type nsMenuContainer::NoIndex = nsMenuContainer::ChildTArray::NoIndex;
+
-+typedef nsMenuObject* (*nsMenuObjectConstructor)(nsMenuContainer*,
-+ nsIContent*);
++typedef UniquePtr<nsMenuObject> (*nsMenuObjectConstructor)(nsMenuContainer*,
++ nsIContent*);
++
++template<class T>
++static UniquePtr<nsMenuObject> CreateMenuObject(nsMenuContainer *aContainer,
++ nsIContent *aContent)
++{
++ return UniquePtr<T>(new T(aContainer, aContent));
++}
++
+static nsMenuObjectConstructor
+GetMenuObjectConstructor(nsIContent *aContent)
+{
+ if (aContent->IsXULElement(nsGkAtoms::menuitem)) {
-+ return nsMenuItem::Create;
++ return CreateMenuObject<nsMenuItem>;
+ } else if (aContent->IsXULElement(nsGkAtoms::menu)) {
-+ return nsMenu::Create;
++ return CreateMenuObject<nsMenu>;
+ } else if (aContent->IsXULElement(nsGkAtoms::menuseparator)) {
-+ return nsMenuSeparator::Create;
++ return CreateMenuObject<nsMenuSeparator>;
+ }
+
+ return nullptr;
@@ -2001,31 +2035,30 @@ Index: firefox-52.0~b9+build2/widget/gtk/nsMenuContainer.cpp
+ return GetMenuObjectConstructor(aContent) ? true : false;
+}
+
-+nsMenuObject*
-+nsMenuContainer::CreateChild(nsIContent *aContent, nsresult *aRv)
++nsMenuContainer::nsMenuContainer(nsMenuContainer *aParent,
++ nsIContent *aContent) :
++ nsMenuObject(aParent, aContent)
++{
++}
++
++nsMenuContainer::nsMenuContainer(nsNativeMenuDocListener *aListener,
++ nsIContent *aContent) :
++ nsMenuObject(aListener, aContent)
++{
++}
++
++UniquePtr<nsMenuObject>
++nsMenuContainer::CreateChild(nsIContent *aContent)
+{
+ nsMenuObjectConstructor ctor = GetMenuObjectConstructor(aContent);
+ if (!ctor) {
+ // There are plenty of node types we might stumble across that
-+ // aren't supported. This isn't an error though
-+ if (aRv) {
-+ *aRv = NS_OK;
-+ }
++ // aren't supported
+ return nullptr;
+ }
+
-+ nsMenuObject *res = ctor(this, aContent);
-+ if (!res) {
-+ if (aRv) {
-+ *aRv = NS_ERROR_FAILURE;
-+ }
-+ return nullptr;
-+ }
-+
-+ if (aRv) {
-+ *aRv = NS_OK;
-+ }
-+ return res;
++ UniquePtr<nsMenuObject> res = ctor(this, aContent);
++ return Move(res);
+}
+
+size_t
@@ -2045,77 +2078,64 @@ Index: firefox-52.0~b9+build2/widget/gtk/nsMenuContainer.cpp
+ return NoIndex;
+}
+
-+nsresult
++void
+nsMenuContainer::RemoveChildAt(size_t aIndex, bool aUpdateNative)
+{
-+ if (aIndex >= ChildCount()) {
-+ return NS_ERROR_INVALID_ARG;
-+ }
++ MOZ_ASSERT(aIndex < ChildCount());
+
+ if (aUpdateNative) {
-+ if (!dbusmenu_menuitem_child_delete(GetNativeData(),
-+ ChildAt(aIndex)->GetNativeData())) {
-+ return NS_ERROR_FAILURE;
-+ }
++ MOZ_ALWAYS_TRUE(
++ dbusmenu_menuitem_child_delete(GetNativeData(),
++ ChildAt(aIndex)->GetNativeData()));
+ }
+
+ mChildren.RemoveElementAt(aIndex);
-+
-+ return NS_OK;
+}
+
-+nsresult
++void
+nsMenuContainer::RemoveChild(nsIContent *aChild, bool aUpdateNative)
+{
+ size_t index = IndexOf(aChild);
+ if (index == NoIndex) {
-+ return NS_ERROR_INVALID_ARG;
++ return;
+ }
+
-+ return RemoveChildAt(index, aUpdateNative);
++ RemoveChildAt(index, aUpdateNative);
+}
+
-+nsresult
-+nsMenuContainer::InsertChildAfter(nsMenuObject *aChild,
++void
++nsMenuContainer::InsertChildAfter(UniquePtr<nsMenuObject> aChild,
+ nsIContent *aPrevSibling,
+ bool aUpdateNative)
+{
+ size_t index = IndexOf(aPrevSibling);
-+ if (index == NoIndex && aPrevSibling) {
-+ return NS_ERROR_INVALID_ARG;
-+ }
++ MOZ_ASSERT(!aPrevSibling || index != NoIndex);
+
+ ++index;
+
+ if (aUpdateNative) {
+ aChild->CreateNativeData();
-+ if (!dbusmenu_menuitem_child_add_position(GetNativeData(),
-+ aChild->GetNativeData(),
-+ index)) {
-+ return NS_ERROR_FAILURE;
-+ }
++ MOZ_ALWAYS_TRUE(
++ dbusmenu_menuitem_child_add_position(GetNativeData(),
++ aChild->GetNativeData(),
++ index));
+ }
+
-+ return mChildren.InsertElementAt(index, aChild) ? NS_OK : NS_ERROR_FAILURE;
++ MOZ_ALWAYS_TRUE(mChildren.InsertElementAt(index, Move(aChild)));
+}
+
-+nsresult
-+nsMenuContainer::AppendChild(nsMenuObject *aChild, bool aUpdateNative)
++void
++nsMenuContainer::AppendChild(UniquePtr<nsMenuObject> aChild,
++ bool aUpdateNative)
+{
+ if (aUpdateNative) {
+ aChild->CreateNativeData();
-+ if (!dbusmenu_menuitem_child_append(GetNativeData(),
-+ aChild->GetNativeData())) {
-+ return NS_ERROR_FAILURE;
-+ }
++ MOZ_ALWAYS_TRUE(
++ dbusmenu_menuitem_child_append(GetNativeData(),
++ aChild->GetNativeData()));
+ }
+
-+ return mChildren.AppendElement(aChild) ? NS_OK : NS_ERROR_FAILURE;
-+}
-+
-+nsMenuContainer::nsMenuContainer() :
-+ nsMenuObject()
-+{
++ MOZ_ALWAYS_TRUE(mChildren.AppendElement(Move(aChild)));
+}
+
+bool
@@ -2133,11 +2153,11 @@ Index: firefox-52.0~b9+build2/widget/gtk/nsMenuContainer.cpp
+
+ return aContent;
+}
-Index: firefox-52.0~b9+build2/widget/gtk/nsMenuContainer.h
+Index: firefox-53.0~a2~hg20170302r359591/widget/gtk/nsMenuContainer.h
===================================================================
--- /dev/null
-+++ firefox-52.0~b9+build2/widget/gtk/nsMenuContainer.h
-@@ -0,0 +1,66 @@
++++ firefox-53.0~a2~hg20170302r359591/widget/gtk/nsMenuContainer.h
+@@ -0,0 +1,70 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* vim:expandtab:shiftwidth=4:tabstop=4:
+ */
@@ -2148,18 +2168,19 @@ Index: firefox-52.0~b9+build2/widget/gtk/nsMenuContainer.h
+#ifndef __nsMenuContainer_h__
+#define __nsMenuContainer_h__
+
-+#include "nsAutoPtr.h"
++#include "mozilla/UniquePtr.h"
+#include "nsTArray.h"
+
+#include "nsMenuObject.h"
+
+class nsIContent;
++class nsNativeMenuDocListener;
+
+// Base class for containers (menus and menubars)
+class nsMenuContainer : public nsMenuObject
+{
+public:
-+ typedef nsTArray<nsAutoPtr<nsMenuObject> > ChildTArray;
++ typedef nsTArray<mozilla::UniquePtr<nsMenuObject> > ChildTArray;
+
+ // Determine if this container is being displayed on screen. Must be
+ // implemented by subclasses. Must return true if the container is
@@ -2177,38 +2198,41 @@ Index: firefox-52.0~b9+build2/widget/gtk/nsMenuContainer.h
+ static const ChildTArray::index_type NoIndex;
+
+protected:
-+ nsMenuContainer();
++ nsMenuContainer(nsMenuContainer *aParent, nsIContent *aContent);
++ nsMenuContainer(nsNativeMenuDocListener *aListener, nsIContent *aContent);
+
+ // Create a new child element for the specified content node
-+ nsMenuObject* CreateChild(nsIContent *aContent, nsresult *aRv);
++ mozilla::UniquePtr<nsMenuObject> CreateChild(nsIContent *aContent);
+
+ // Return the index of the child for the specified content node
+ size_t IndexOf(nsIContent *aChild) const;
+
+ size_t ChildCount() const { return mChildren.Length(); }
-+ nsMenuObject* ChildAt(size_t aIndex) const { return mChildren[aIndex]; }
++ nsMenuObject* ChildAt(size_t aIndex) const { return mChildren[aIndex].get(); }
+
-+ nsresult RemoveChildAt(size_t aIndex, bool aUpdateNative = true);
++ void RemoveChildAt(size_t aIndex, bool aUpdateNative = true);
+
+ // Remove the child that owns the specified content node
-+ nsresult RemoveChild(nsIContent *aChild, bool aUpdateNative = true);
++ void RemoveChild(nsIContent *aChild, bool aUpdateNative = true);
+
+ // Insert a new child after the child that owns the specified content node
-+ nsresult InsertChildAfter(nsMenuObject *aChild, nsIContent *aPrevSibling,
-+ bool aUpdateNative = true);
++ void InsertChildAfter(mozilla::UniquePtr<nsMenuObject> aChild,
++ nsIContent *aPrevSibling,
++ bool aUpdateNative = true);
+
-+ nsresult AppendChild(nsMenuObject *aChild, bool aUpdateNative = true);
++ void AppendChild(mozilla::UniquePtr<nsMenuObject> aChild,
++ bool aUpdateNative = true);
+
+private:
+ ChildTArray mChildren;
+};
+
+#endif /* __nsMenuContainer_h__ */
-Index: firefox-52.0~b9+build2/widget/gtk/nsMenuItem.cpp
+Index: firefox-53.0~a2~hg20170302r359591/widget/gtk/nsMenuItem.cpp
===================================================================
--- /dev/null
-+++ firefox-52.0~b9+build2/widget/gtk/nsMenuItem.cpp
-@@ -0,0 +1,743 @@
++++ firefox-53.0~a2~hg20170302r359591/widget/gtk/nsMenuItem.cpp
+@@ -0,0 +1,737 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* vim:expandtab:shiftwidth=4:tabstop=4:
+ */
@@ -2217,7 +2241,9 @@ Index: firefox-52.0~b9+build2/widget/gtk/nsMenuItem.cpp
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "mozilla/ArrayUtils.h"
++#include "mozilla/Assertions.h"
+#include "mozilla/dom/Element.h"
++#include "mozilla/Move.h"
+#include "mozilla/Preferences.h"
+#include "mozilla/TextEvents.h"
+#include "nsAutoPtr.h"
@@ -2511,7 +2537,7 @@ Index: firefox-52.0~b9+build2/widget/gtk/nsMenuItem.cpp
+ NS_IMETHODIMP Run()
+ {
+ if (mMenuItem) {
-+ mMenuItem->UncheckSiblings();
++ static_cast<nsMenuItem *>(mMenuItem.get())->UncheckSiblings();
+ }
+ return NS_OK;
+ }
@@ -2520,14 +2546,14 @@ Index: firefox-52.0~b9+build2/widget/gtk/nsMenuItem.cpp
+ mMenuItem(aMenuItem) { };
+
+private:
-+ nsWeakMenuObject<nsMenuItem> mMenuItem;
++ nsWeakMenuObject mMenuItem;
+};
+
+bool
+nsMenuItem::IsCheckboxOrRadioItem() const
+{
-+ return MenuItemType() == eMenuItemType_Radio ||
-+ MenuItemType() == eMenuItemType_CheckBox;
++ return mType == eMenuItemType_Radio ||
++ mType == eMenuItemType_CheckBox;
+}
+
+/* static */ void
@@ -2548,14 +2574,14 @@ Index: firefox-52.0~b9+build2/widget/gtk/nsMenuItem.cpp
+
+ // We do this to avoid mutating our view of the menu until
+ // after we have finished
-+ nsNativeMenuAutoUpdateBatch batch;
++ nsNativeMenuDocListener::BlockUpdatesScope updatesBlocker;
+
+ if (!ContentNode()->AttrValueIs(kNameSpaceID_None, nsGkAtoms::autocheck,
+ nsGkAtoms::_false, eCaseMatters) &&
-+ (MenuItemType() == eMenuItemType_CheckBox ||
-+ (MenuItemType() == eMenuItemType_Radio && !IsChecked()))) {
++ (mType == eMenuItemType_CheckBox ||
++ (mType == eMenuItemType_Radio && !mIsChecked))) {
+ ContentNode()->SetAttr(kNameSpaceID_None, nsGkAtoms::checked,
-+ IsChecked() ?
++ mIsChecked ?
+ NS_LITERAL_STRING("false") : NS_LITERAL_STRING("true"),
+ true);
+ }
@@ -2604,13 +2630,13 @@ Index: firefox-52.0~b9+build2/widget/gtk/nsMenuItem.cpp
+ return;
+ }
+
-+ SetCheckState(ContentNode()->AttrValueIs(kNameSpaceID_None,
-+ nsGkAtoms::checked,
-+ nsGkAtoms::_true,
-+ eCaseMatters));
++ mIsChecked = ContentNode()->AttrValueIs(kNameSpaceID_None,
++ nsGkAtoms::checked,
++ nsGkAtoms::_true,
++ eCaseMatters);
+ dbusmenu_menuitem_property_set_int(GetNativeData(),
+ DBUSMENU_MENUITEM_PROP_TOGGLE_STATE,
-+ IsChecked() ?
++ mIsChecked ?
+ DBUSMENU_MENUITEM_TOGGLE_STATE_CHECKED :
+ DBUSMENU_MENUITEM_TOGGLE_STATE_UNCHECKED);
+}
@@ -2629,12 +2655,12 @@ Index: firefox-52.0~b9+build2/widget/gtk/nsMenuItem.cpp
+ dbusmenu_menuitem_property_set(GetNativeData(),
+ DBUSMENU_MENUITEM_PROP_TOGGLE_TYPE,
+ DBUSMENU_MENUITEM_TOGGLE_CHECK);
-+ SetMenuItemType(eMenuItemType_CheckBox);
++ mType = eMenuItemType_CheckBox;
+ } else if (type == 1) {
+ dbusmenu_menuitem_property_set(GetNativeData(),
+ DBUSMENU_MENUITEM_PROP_TOGGLE_TYPE,
+ DBUSMENU_MENUITEM_TOGGLE_RADIO);
-+ SetMenuItemType(eMenuItemType_Radio);
++ mType = eMenuItemType_Radio;
+ }
+
+ UpdateState();
@@ -2643,7 +2669,7 @@ Index: firefox-52.0~b9+build2/widget/gtk/nsMenuItem.cpp
+ DBUSMENU_MENUITEM_PROP_TOGGLE_TYPE);
+ dbusmenu_menuitem_property_remove(GetNativeData(),
+ DBUSMENU_MENUITEM_PROP_TOGGLE_STATE);
-+ SetMenuItemType(eMenuItemType_Normal);
++ mType = eMenuItemType_Normal;
+ }
+}
+
@@ -2739,17 +2765,58 @@ Index: firefox-52.0~b9+build2/widget/gtk/nsMenuItem.cpp
+ }
+}
+
++nsMenuBar*
++nsMenuItem::MenuBar()
++{
++ nsMenuObject *tmp = this;
++ while (tmp->Parent()) {
++ tmp = tmp->Parent();
++ }
++
++ MOZ_ASSERT(tmp->Type() == eType_MenuBar, "The top-level should be a menubar");
++
++ return static_cast<nsMenuBar *>(tmp);
++}
++
++void
++nsMenuItem::UncheckSiblings()
++{
++ if (!ContentNode()->AttrValueIs(kNameSpaceID_None, nsGkAtoms::type,
++ nsGkAtoms::radio, eCaseMatters)) {
++ // If we're not a radio button, we don't care
++ return;
++ }
++
++ nsAutoString name;
++ ContentNode()->GetAttr(kNameSpaceID_None, nsGkAtoms::name, name);
++
++ nsIContent *parent = ContentNode()->GetParent();
++ if (!parent) {
++ return;
++ }
++
++ uint32_t count = parent->GetChildCount();
++ for (uint32_t i = 0; i < count; ++i) {
++ nsIContent *sibling = parent->GetChildAt(i);
++
++ nsAutoString otherName;
++ sibling->GetAttr(kNameSpaceID_None, nsGkAtoms::name, otherName);
++
++ if (sibling != ContentNode() && otherName == name &&
++ sibling->AttrValueIs(kNameSpaceID_None, nsGkAtoms::type,
++ nsGkAtoms::radio, eCaseMatters)) {
++ sibling->UnsetAttr(kNameSpaceID_None, nsGkAtoms::checked, true);
++ }
++ }
++}
++
+void
+nsMenuItem::InitializeNativeData()
+{
+ g_signal_connect(G_OBJECT(GetNativeData()),
+ DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED,
+ G_CALLBACK(item_activated_cb), this);
-+
-+ UpdateTypeAndState();
-+ UpdateAccel();
-+ UpdateLabel();
-+ UpdateSensitivity();
++ mNeedsUpdate = true;
+}
+
+void
@@ -2788,40 +2855,17 @@ Index: firefox-52.0~b9+build2/widget/gtk/nsMenuItem.cpp
+void
+nsMenuItem::Update(nsStyleContext *aStyleContext)
+{
-+ UpdateVisibility(aStyleContext);
-+ UpdateIcon(aStyleContext);
-+}
-+
-+void
-+nsMenuItem::UncheckSiblings()
-+{
-+ if (!ContentNode()->AttrValueIs(kNameSpaceID_None, nsGkAtoms::type,
-+ nsGkAtoms::radio, eCaseMatters)) {
-+ // If we're not a radio button, we don't care
-+ return;
-+ }
-+
-+ nsAutoString name;
-+ ContentNode()->GetAttr(kNameSpaceID_None, nsGkAtoms::name, name);
++ if (mNeedsUpdate) {
++ mNeedsUpdate = false;
+
-+ nsIContent *parent = ContentNode()->GetParent();
-+ if (!parent) {
-+ return;
++ UpdateTypeAndState();
++ UpdateAccel();
++ UpdateLabel();
++ UpdateSensitivity();
+ }
+
-+ uint32_t count = parent->GetChildCount();
-+ for (uint32_t i = 0; i < count; ++i) {
-+ nsIContent *sibling = parent->GetChildAt(i);
-+
-+ nsAutoString otherName;
-+ sibling->GetAttr(kNameSpaceID_None, nsGkAtoms::name, otherName);
-+
-+ if (sibling != ContentNode() && otherName == name &&
-+ sibling->AttrValueIs(kNameSpaceID_None, nsGkAtoms::type,
-+ nsGkAtoms::radio, eCaseMatters)) {
-+ sibling->UnsetAttr(kNameSpaceID_None, nsGkAtoms::checked, true);
-+ }
-+ }
++ UpdateVisibility(aStyleContext);
++ UpdateIcon(aStyleContext);
+}
+
+bool
@@ -2832,19 +2876,6 @@ Index: firefox-52.0~b9+build2/widget/gtk/nsMenuItem.cpp
+ "separator") != 0;
+}
+
-+nsMenuBar*
-+nsMenuItem::MenuBar()
-+{
-+ nsMenuObject *tmp = this;
-+ while (tmp->Parent()) {
-+ tmp = tmp->Parent();
-+ }
-+
-+ MOZ_ASSERT(tmp->Type() == eType_MenuBar, "The top-level should be a menubar");
-+
-+ return static_cast<nsMenuBar *>(tmp);
-+}
-+
+nsMenuObject::PropertyFlags
+nsMenuItem::SupportedProperties() const
+{
@@ -2859,63 +2890,26 @@ Index: firefox-52.0~b9+build2/widget/gtk/nsMenuItem.cpp
+ );
+}
+
-+nsMenuItem::nsMenuItem() :
-+ nsMenuObject()
-+{
-+ MOZ_COUNT_CTOR(nsMenuItem);
-+}
-+
-+nsMenuItem::~nsMenuItem()
-+{
-+ if (DocListener() && mKeyContent) {
-+ DocListener()->UnregisterForContentChanges(mKeyContent);
-+ }
-+
-+ if (GetNativeData()) {
-+ g_signal_handlers_disconnect_by_func(GetNativeData(),
-+ FuncToGpointer(item_activated_cb),
-+ this);
-+ }
-+
-+ MOZ_COUNT_DTOR(nsMenuItem);
-+}
-+
-+nsMenuObject::EType
-+nsMenuItem::Type() const
-+{
-+ return nsMenuObject::eType_MenuItem;
-+}
-+
-+/* static */ nsMenuObject*
-+nsMenuItem::Create(nsMenuContainer *aParent, nsIContent *aContent)
-+{
-+ nsAutoPtr<nsMenuItem> menuitem(new nsMenuItem());
-+ if (NS_FAILED(menuitem->Init(aParent, aContent))) {
-+ return nullptr;
-+ }
-+
-+ return menuitem.forget();
-+}
-+
+void
+nsMenuItem::OnAttributeChanged(nsIContent *aContent, nsIAtom *aAttribute)
+{
-+ NS_ASSERTION(aContent == ContentNode() || aContent == mKeyContent,
-+ "Received an event that wasn't meant for us!");
-+
-+ if (Parent()->NeedsRebuild()) {
-+ return;
-+ }
++ MOZ_ASSERT(aContent == ContentNode() || aContent == mKeyContent,
++ "Received an event that wasn't meant for us!");
+
+ if (aContent == ContentNode() && aAttribute == nsGkAtoms::checked &&
+ aContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::checked,
+ nsGkAtoms::_true, eCaseMatters)) {
-+ if (nsContentUtils::IsSafeToRunScript()) {
-+ UncheckSiblings();
-+ } else {
-+ nsContentUtils::AddScriptRunner(
-+ new nsMenuItemUncheckSiblingsRunnable(this));
-+ }
++ nsContentUtils::AddScriptRunner(
++ new nsMenuItemUncheckSiblingsRunnable(this));
++ }
++
++ if (mNeedsUpdate) {
++ return;
++ }
++
++ if (!Parent()->IsBeingDisplayed()) {
++ mNeedsUpdate = true;
++ return;
+ }
+
+ if (aContent == ContentNode()) {
@@ -2931,6 +2925,13 @@ Index: firefox-52.0~b9+build2/widget/gtk/nsMenuItem.cpp
+ UpdateTypeAndState();
+ } else if (aAttribute == nsGkAtoms::checked) {
+ UpdateState();
++ } else if (aAttribute == nsGkAtoms::hidden ||
++ aAttribute == nsGkAtoms::collapsed) {
++ RefPtr<nsStyleContext> sc = GetStyleContext();
++ UpdateVisibility(sc);
++ } else if (aAttribute == nsGkAtoms::image) {
++ RefPtr<nsStyleContext> sc = GetStyleContext();
++ UpdateIcon(sc);
+ }
+ } else if (aContent == mKeyContent &&
+ (aAttribute == nsGkAtoms::key ||
@@ -2938,25 +2939,42 @@ Index: firefox-52.0~b9+build2/widget/gtk/nsMenuItem.cpp
+ aAttribute == nsGkAtoms::modifiers)) {
+ UpdateAccel();
+ }
++}
+
-+ if (!Parent()->IsBeingDisplayed() || aContent != ContentNode()) {
-+ return;
++nsMenuItem::nsMenuItem(nsMenuContainer *aParent, nsIContent *aContent) :
++ nsMenuObject(aParent, aContent),
++ mType(eMenuItemType_Normal),
++ mIsChecked(false),
++ mNeedsUpdate(false)
++{
++ MOZ_COUNT_CTOR(nsMenuItem);
++}
++
++nsMenuItem::~nsMenuItem()
++{
++ if (DocListener() && mKeyContent) {
++ DocListener()->UnregisterForContentChanges(mKeyContent);
+ }
+
-+ if (aAttribute == nsGkAtoms::hidden ||
-+ aAttribute == nsGkAtoms::collapsed) {
-+ RefPtr<nsStyleContext> sc = GetStyleContext();
-+ UpdateVisibility(sc);
-+ } else if (aAttribute == nsGkAtoms::image) {
-+ RefPtr<nsStyleContext> sc = GetStyleContext();
-+ UpdateIcon(sc);
++ if (GetNativeData()) {
++ g_signal_handlers_disconnect_by_func(GetNativeData(),
++ FuncToGpointer(item_activated_cb),
++ this);
+ }
++
++ MOZ_COUNT_DTOR(nsMenuItem);
++}
++
++nsMenuObject::EType
++nsMenuItem::Type() const
++{
++ return eType_MenuItem;
+}
-Index: firefox-52.0~b9+build2/widget/gtk/nsMenuItem.h
+Index: firefox-53.0~a2~hg20170302r359591/widget/gtk/nsMenuItem.h
===================================================================
--- /dev/null
-+++ firefox-52.0~b9+build2/widget/gtk/nsMenuItem.h
-@@ -0,0 +1,107 @@
++++ firefox-53.0~a2~hg20170302r359591/widget/gtk/nsMenuItem.h
+@@ -0,0 +1,81 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* vim:expandtab:shiftwidth=4:tabstop=4:
+ */
@@ -2975,9 +2993,6 @@ Index: firefox-52.0~b9+build2/widget/gtk/nsMenuItem.h
+
+#include <glib.h>
+
-+#define NSMENUITEM_NUMBER_OF_TYPE_BITS 2U
-+#define NSMENUITEM_NUMBER_OF_FLAGS 1U
-+
+class nsIAtom;
+class nsIContent;
+class nsStyleContext;
@@ -2991,14 +3006,10 @@ Index: firefox-52.0~b9+build2/widget/gtk/nsMenuItem.h
+class nsMenuItem final : public nsMenuObject
+{
+public:
-+ ~nsMenuItem();
-+
-+ nsMenuObject::EType Type() const;
-+
-+ static nsMenuObject* Create(nsMenuContainer *aParent,
-+ nsIContent *aContent);
++ nsMenuItem(nsMenuContainer *aParent, nsIContent *aContent);
++ ~nsMenuItem() override;
+
-+ void OnAttributeChanged(nsIContent *aContent, nsIAtom *aAttribute);
++ nsMenuObject::EType Type() const override;
+
+private:
+ friend class nsMenuItemUncheckSiblingsRunnable;
@@ -3013,35 +3024,8 @@ Index: firefox-52.0~b9+build2/widget/gtk/nsMenuItem.h
+ eMenuItemType_CheckBox
+ };
+
-+ nsMenuItem();
-+
-+ EMenuItemType MenuItemType() const
-+ {
-+ return static_cast<EMenuItemType>(
-+ (GetFlags() &
-+ (((1U << NSMENUITEM_NUMBER_OF_TYPE_BITS) - 1U)
-+ << NSMENUITEM_NUMBER_OF_FLAGS)) >> NSMENUITEM_NUMBER_OF_FLAGS);
-+ }
-+ void SetMenuItemType(EMenuItemType aType)
-+ {
-+ ClearFlags(((1U << NSMENUITEM_NUMBER_OF_TYPE_BITS) - 1U) << NSMENUITEM_NUMBER_OF_FLAGS);
-+ SetFlags(aType << NSMENUITEM_NUMBER_OF_FLAGS);
-+ }
+ bool IsCheckboxOrRadioItem() const;
+
-+ bool IsChecked() const
-+ {
-+ return HasFlags(eMenuItemFlag_ToggleState);
-+ }
-+ void SetCheckState(bool aState)
-+ {
-+ if (aState) {
-+ SetFlags(eMenuItemFlag_ToggleState);
-+ } else {
-+ ClearFlags(eMenuItemFlag_ToggleState);
-+ }
-+ }
-+
+ static void item_activated_cb(DbusmenuMenuitem *menuitem,
+ guint timestamp,
+ gpointer user_data);
@@ -3051,24 +3035,32 @@ Index: firefox-52.0~b9+build2/widget/gtk/nsMenuItem.h
+ void UpdateState();
+ void UpdateTypeAndState();
+ void UpdateAccel();
-+
-+ void InitializeNativeData();
-+ void UpdateContentAttributes();
-+ void Update(nsStyleContext *aStyleContext);
-+ void UncheckSiblings();
-+ bool IsCompatibleWithNativeData(DbusmenuMenuitem *aNativeData) const;
+ nsMenuBar* MenuBar();
-+ nsMenuObject::PropertyFlags SupportedProperties() const;
++ void UncheckSiblings();
++
++ void InitializeNativeData() override;
++ void UpdateContentAttributes() override;
++ void Update(nsStyleContext *aStyleContext) override;
++ bool IsCompatibleWithNativeData(DbusmenuMenuitem *aNativeData) const override;
++ nsMenuObject::PropertyFlags SupportedProperties() const override;
++
++ void OnAttributeChanged(nsIContent *aContent, nsIAtom *aAttribute) override;
++
++ EMenuItemType mType;
++
++ bool mIsChecked;
++
++ bool mNeedsUpdate;
+
+ nsCOMPtr<nsIContent> mKeyContent;
+};
+
+#endif /* __nsMenuItem_h__ */
-Index: firefox-52.0~b9+build2/widget/gtk/nsMenuObject.cpp
+Index: firefox-53.0~a2~hg20170302r359591/widget/gtk/nsMenuObject.cpp
===================================================================
--- /dev/null
-+++ firefox-52.0~b9+build2/widget/gtk/nsMenuObject.cpp
-@@ -0,0 +1,694 @@
++++ firefox-53.0~a2~hg20170302r359591/widget/gtk/nsMenuObject.cpp
+@@ -0,0 +1,660 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* vim:expandtab:shiftwidth=4:tabstop=4:
+ */
@@ -3082,6 +3074,7 @@ Index: firefox-52.0~b9+build2/widget/gtk/nsMenuObject.cpp
+#include "imgLoader.h"
+#include "imgRequestProxy.h"
+#include "mozilla/ArrayUtils.h"
++#include "mozilla/Assertions.h"
+#include "mozilla/dom/Element.h"
+#include "mozilla/Preferences.h"
+#include "nsAttrValue.h"
@@ -3103,13 +3096,11 @@ Index: firefox-52.0~b9+build2/widget/gtk/nsMenuObject.cpp
+#include "nsStyleConsts.h"
+#include "nsStyleContext.h"
+#include "nsStyleStruct.h"
-+#include "nsThreadUtils.h"
+#include "nsUnicharUtils.h"
+
+#include "nsMenuContainer.h"
+#include "nsNativeMenuAtoms.h"
+#include "nsNativeMenuDocListener.h"
-+#include "nsNativeMenuUtils.h"
+
+#include <gdk/gdk.h>
+#include <glib-object.h>
@@ -3129,27 +3120,9 @@ Index: firefox-52.0~b9+build2/widget/gtk/nsMenuObject.cpp
+ nullptr
+};
+
-+nsWeakMenuObjectBase* nsWeakMenuObjectBase::sHead;
++nsWeakMenuObject* nsWeakMenuObject::sHead;
+PangoLayout* gPangoLayout = nullptr;
+
-+class nsMenuObjectContainerOpeningRunnable : public Runnable
-+{
-+public:
-+ NS_IMETHODIMP Run()
-+ {
-+ if (mMenuObject) {
-+ mMenuObject->ContainerIsOpening();
-+ }
-+ return NS_OK;
-+ }
-+
-+ nsMenuObjectContainerOpeningRunnable(nsMenuObject *aMenuObject) :
-+ mMenuObject(aMenuObject) { };
-+
-+private:
-+ nsWeakMenuObject<nsMenuObject> mMenuObject;
-+};
-+
+class nsMenuObjectIconLoader final : public imgINotificationObserver
+{
+public:
@@ -3325,7 +3298,7 @@ Index: firefox-52.0~b9+build2/widget/gtk/nsMenuObject.cpp
+ return;
+ }
+
-+ loader->LoadImage(uri, nullptr, nullptr, mozilla::net::RP_Default,
++ loader->LoadImage(uri, nullptr, nullptr, mozilla::net::RP_Unset,
+ nullptr, loadGroup, this, nullptr, nullptr,
+ nsIRequest::LOAD_NORMAL, nullptr,
+ nsIContentPolicy::TYPE_IMAGE, EmptyString(),
@@ -3397,60 +3370,26 @@ Index: firefox-52.0~b9+build2/widget/gtk/nsMenuObject.cpp
+ return sEllipsisWidth;
+}
+
-+void
-+nsMenuObject::InitializeNativeData()
-+{
-+}
-+
-+nsMenuObject::PropertyFlags
-+nsMenuObject::SupportedProperties() const
-+{
-+ return static_cast<nsMenuObject::PropertyFlags>(0);
-+}
-+
-+bool
-+nsMenuObject::IsCompatibleWithNativeData(DbusmenuMenuitem *aNativeData) const
++nsMenuObject::nsMenuObject(nsMenuContainer *aParent, nsIContent *aContent) :
++ mContent(aContent),
++ mListener(aParent->DocListener()),
++ mParent(aParent),
++ mNativeData(nullptr)
+{
-+ return true;
++ MOZ_ASSERT(mContent);
++ MOZ_ASSERT(mListener);
++ MOZ_ASSERT(mParent);
+}
+
-+void
-+nsMenuObject::UpdateContentAttributes()
++nsMenuObject::nsMenuObject(nsNativeMenuDocListener *aListener,
++ nsIContent *aContent) :
++ mContent(aContent),
++ mListener(aListener),
++ mParent(nullptr),
++ mNativeData(nullptr)
+{
-+}
-+
-+void
-+nsMenuObject::Update(nsStyleContext *aStyleContext)
-+{
-+}
-+
-+bool
-+nsMenuObject::ShouldShowIcon() const
-+{
-+ // Ideally we want to know the visibility of the anonymous XUL image in
-+ // our menuitem, but this isn't created because we don't have a frame.
-+ // The following works by default (because xul.css hides images in menuitems
-+ // that don't have the "menuitem-with-favicon" class). It's possible a third
-+ // party theme could override this, but, oh well...
-+ const nsAttrValue *classes = mContent->GetClasses();
-+ if (!classes) {
-+ return false;
-+ }
-+
-+ for (uint32_t i = 0; i < classes->GetAtomCount(); ++i) {
-+ if (classes->AtomAt(i) == nsNativeMenuAtoms::menuitem_with_favicon) {
-+ return true;
-+ }
-+ }
-+
-+ return false;
-+}
-+
-+void
-+nsMenuObject::ClearIcon()
-+{
-+ dbusmenu_menuitem_property_remove(mNativeData,
-+ DBUSMENU_MENUITEM_PROP_ICON_DATA);
++ MOZ_ASSERT(mContent);
++ MOZ_ASSERT(mListener);
+}
+
+void
@@ -3506,13 +3445,12 @@ Index: firefox-52.0~b9+build2/widget/gtk/nsMenuObject.cpp
+ return;
+ }
+
-+ // This *COMPLETELY SUCKS*
++ // This sucks.
+ // This should be done at the point where the menu is drawn (hello Unity),
+ // but unfortunately it doesn't do that and will happily fill your entire
+ // screen width with a menu if you have a bookmark with a really long title.
+ // This leaves us with no other option but to ellipsize here, with no proper
+ // knowledge of Unity's render path, font size etc. This is better than nothing
-+ // BAH! @*&!$
+ nsAutoString truncated;
+ int target = MAX_WIDTH - GetEllipsisWidth();
+ length = label.Length();
@@ -3530,9 +3468,9 @@ Index: firefox-52.0~b9+build2/widget/gtk/nsMenuObject.cpp
+ switch (type) {
+ case 0:
+ case 1:
-+ // FIXME: Implement left cropping (do we really care?)
++ // FIXME: Implement left cropping
+ case 2:
-+ // FIXME: Implement center cropping (do we really care?)
++ // FIXME: Implement center cropping
+ case 3:
+ case 4:
+ default:
@@ -3615,41 +3553,65 @@ Index: firefox-52.0~b9+build2/widget/gtk/nsMenuObject.cpp
+ return sc.forget();
+}
+
-+nsresult
-+nsMenuObject::Init(nsMenuContainer *aParent, nsIContent *aContent)
++void
++nsMenuObject::InitializeNativeData()
+{
-+ NS_ENSURE_ARG(aParent);
-+ NS_ENSURE_ARG(aContent);
++}
+
-+ mParent = aParent;
-+ mContent = aContent;
-+ mListener = aParent->DocListener();
-+ NS_ENSURE_ARG(mListener);
++nsMenuObject::PropertyFlags
++nsMenuObject::SupportedProperties() const
++{
++ return static_cast<nsMenuObject::PropertyFlags>(0);
++}
+
-+ return NS_OK;
++bool
++nsMenuObject::IsCompatibleWithNativeData(DbusmenuMenuitem *aNativeData) const
++{
++ return true;
+}
+
-+nsresult
-+nsMenuObject::Init(nsNativeMenuDocListener *aListener, nsIContent *aContent)
++void
++nsMenuObject::UpdateContentAttributes()
+{
-+ NS_ENSURE_ARG(aListener);
-+ NS_ENSURE_ARG(aContent);
++}
+
-+ mParent = nullptr;
-+ mContent = aContent;
-+ mListener = aListener;
++void
++nsMenuObject::Update(nsStyleContext *aStyleContext)
++{
++}
+
-+ return NS_OK;
++bool
++nsMenuObject::ShouldShowIcon() const
++{
++ // Ideally we want to know the visibility of the anonymous XUL image in
++ // our menuitem, but this isn't created because we don't have a frame.
++ // The following works by default (because xul.css hides images in menuitems
++ // that don't have the "menuitem-with-favicon" class). It's possible a third
++ // party theme could override this, but, oh well...
++ const nsAttrValue *classes = mContent->GetClasses();
++ if (!classes) {
++ return false;
++ }
++
++ for (uint32_t i = 0; i < classes->GetAtomCount(); ++i) {
++ if (classes->AtomAt(i) == nsNativeMenuAtoms::menuitem_with_favicon) {
++ return true;
++ }
++ }
++
++ return false;
+}
+
-+nsMenuObject::nsMenuObject() :
-+ mParent(nullptr), mNativeData(nullptr), mFlags(0)
++void
++nsMenuObject::ClearIcon()
+{
++ dbusmenu_menuitem_property_remove(mNativeData,
++ DBUSMENU_MENUITEM_PROP_ICON_DATA);
+}
+
+nsMenuObject::~nsMenuObject()
+{
-+ nsWeakMenuObjectBase::NotifyDestroyed(this);
++ nsWeakMenuObject::NotifyDestroyed(this);
+
+ if (mIconLoader) {
+ mIconLoader->Destroy();
@@ -3668,7 +3630,7 @@ Index: firefox-52.0~b9+build2/widget/gtk/nsMenuObject.cpp
+void
+nsMenuObject::CreateNativeData()
+{
-+ NS_ASSERTION(mNativeData == nullptr, "This node already has a DbusmenuMenuitem. The old one will be leaked");
++ MOZ_ASSERT(mNativeData == nullptr, "This node already has a DbusmenuMenuitem. The old one will be leaked");
+
+ mNativeData = dbusmenu_menuitem_new();
+ InitializeNativeData();
@@ -3682,7 +3644,7 @@ Index: firefox-52.0~b9+build2/widget/gtk/nsMenuObject.cpp
+nsresult
+nsMenuObject::AdoptNativeData(DbusmenuMenuitem *aNativeData)
+{
-+ NS_ASSERTION(mNativeData == nullptr, "This node already has a DbusmenuMenuitem. The old one will be leaked");
++ MOZ_ASSERT(mNativeData == nullptr, "This node already has a DbusmenuMenuitem. The old one will be leaked");
+
+ if (!IsCompatibleWithNativeData(aNativeData)) {
+ return NS_ERROR_FAILURE;
@@ -3714,11 +3676,7 @@ Index: firefox-52.0~b9+build2/widget/gtk/nsMenuObject.cpp
+void
+nsMenuObject::ContainerIsOpening()
+{
-+ if (!nsContentUtils::IsSafeToRunScript()) {
-+ nsContentUtils::AddScriptRunner(
-+ new nsMenuObjectContainerOpeningRunnable(this));
-+ return;
-+ }
++ MOZ_ASSERT(nsContentUtils::IsSafeToRunScript());
+
+ UpdateContentAttributes();
+
@@ -3727,47 +3685,47 @@ Index: firefox-52.0~b9+build2/widget/gtk/nsMenuObject.cpp
+}
+
+/* static */ void
-+nsWeakMenuObjectBase::AddWeakReference(nsWeakMenuObjectBase *aWeak)
++nsWeakMenuObject::AddWeakReference(nsWeakMenuObject *aWeak)
+{
-+ aWeak->SetPrevious(sHead);
++ aWeak->mPrev = sHead;
+ sHead = aWeak;
+}
+
+/* static */ void
-+nsWeakMenuObjectBase::RemoveWeakReference(nsWeakMenuObjectBase *aWeak)
++nsWeakMenuObject::RemoveWeakReference(nsWeakMenuObject *aWeak)
+{
+ if (aWeak == sHead) {
-+ sHead = aWeak->GetPrevious();
++ sHead = aWeak->mPrev;
+ return;
+ }
+
-+ nsWeakMenuObjectBase *weak = sHead;
-+ while (weak && weak->GetPrevious() != aWeak) {
-+ weak = weak->GetPrevious();
++ nsWeakMenuObject *weak = sHead;
++ while (weak && weak->mPrev != aWeak) {
++ weak = weak->mPrev;
+ }
+
+ if (weak) {
-+ weak->SetPrevious(aWeak->GetPrevious());
++ weak->mPrev = aWeak->mPrev;
+ }
+}
+
+/* static */ void
-+nsWeakMenuObjectBase::NotifyDestroyed(nsMenuObject *aMenuObject)
++nsWeakMenuObject::NotifyDestroyed(nsMenuObject *aMenuObject)
+{
-+ nsWeakMenuObjectBase *weak = sHead;
++ nsWeakMenuObject *weak = sHead;
+ while (weak) {
-+ if (weak->getBase() == aMenuObject) {
-+ weak->Clear();
++ if (weak->mMenuObject == aMenuObject) {
++ weak->mMenuObject = nullptr;
+ }
+
-+ weak = weak->GetPrevious();
++ weak = weak->mPrev;
+ }
+}
-Index: firefox-52.0~b9+build2/widget/gtk/nsMenuObject.h
+Index: firefox-53.0~a2~hg20170302r359591/widget/gtk/nsMenuObject.h
===================================================================
--- /dev/null
-+++ firefox-52.0~b9+build2/widget/gtk/nsMenuObject.h
-@@ -0,0 +1,242 @@
++++ firefox-53.0~a2~hg20170302r359591/widget/gtk/nsMenuObject.h
+@@ -0,0 +1,170 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* vim:expandtab:shiftwidth=4:tabstop=4:
+ */
@@ -3817,14 +3775,7 @@ Index: firefox-52.0~b9+build2/widget/gtk/nsMenuObject.h
+ enum EType {
+ eType_MenuBar,
+ eType_Menu,
-+ eType_MenuItem,
-+ eType_MenuSeparator
-+ };
-+
-+ enum PropertyFlags {
-+#define DBUSMENU_PROPERTY(e, s, b) eProp##e = (1 << b),
-+ DBUSMENU_PROPERTIES
-+#undef DBUSMENU_PROPERTY
++ eType_MenuItem
+ };
+
+ virtual ~nsMenuObject();
@@ -3854,9 +3805,14 @@ Index: firefox-52.0~b9+build2/widget/gtk/nsMenuObject.h
+ void ContainerIsOpening();
+
+protected:
-+ nsMenuObject();
-+ nsresult Init(nsMenuContainer *aParent, nsIContent *aContent);
-+ nsresult Init(nsNativeMenuDocListener *aListener, nsIContent *aContent);
++ nsMenuObject(nsMenuContainer *aParent, nsIContent *aContent);
++ nsMenuObject(nsNativeMenuDocListener *aListener, nsIContent *aContent);
++
++ enum PropertyFlags {
++#define DBUSMENU_PROPERTY(e, s, b) eProp##e = (1 << b),
++ DBUSMENU_PROPERTIES
++#undef DBUSMENU_PROPERTY
++ };
+
+ void UpdateLabel();
+ void UpdateVisibility(nsStyleContext *aStyleContext);
@@ -3865,20 +3821,6 @@ Index: firefox-52.0~b9+build2/widget/gtk/nsMenuObject.h
+
+ already_AddRefed<nsStyleContext> GetStyleContext();
+
-+ uint8_t GetFlags() const { return mFlags; }
-+ bool HasFlags(uint8_t aFlags) const
-+ {
-+ return (mFlags & aFlags) == aFlags;
-+ }
-+ void SetFlags(uint8_t aFlags)
-+ {
-+ mFlags |= aFlags;
-+ }
-+ void ClearFlags(uint8_t aFlags)
-+ {
-+ mFlags &= ~aFlags;
-+ }
-+
+private:
+ friend class nsMenuObjectIconLoader;
+
@@ -3919,102 +3861,46 @@ Index: firefox-52.0~b9+build2/widget/gtk/nsMenuObject.h
+ nsMenuContainer *mParent; // [weak]
+ DbusmenuMenuitem *mNativeData; // [strong]
+ RefPtr<nsMenuObjectIconLoader> mIconLoader;
-+ uint8_t mFlags;
+};
+
-+class nsWeakMenuObjectBase
++// Keep a weak pointer to a menu object
++class nsWeakMenuObject
+{
+public:
-+ ~nsWeakMenuObjectBase()
++ nsWeakMenuObject() : mPrev(nullptr), mMenuObject(nullptr) {}
++
++ nsWeakMenuObject(nsMenuObject *aMenuObject) :
++ mPrev(nullptr), mMenuObject(aMenuObject)
+ {
-+ RemoveWeakReference(this);
++ AddWeakReference(this);
+ }
+
-+ nsMenuObject* getBase() const { return mMenuObject; }
++ ~nsWeakMenuObject() { RemoveWeakReference(this); }
+
-+ static void NotifyDestroyed(nsMenuObject *aMenuObject);
++ nsMenuObject* get() const { return mMenuObject; }
+
-+protected:
-+ nsWeakMenuObjectBase() : mMenuObject(nullptr) { };
++ nsMenuObject* operator->() const { return mMenuObject; }
+
-+ void SetMenuObject(nsMenuObject *aMenuObject)
-+ {
-+ mMenuObject = aMenuObject;
++ explicit operator bool() const { return !!mMenuObject; }
+
-+ mMenuObject ? AddWeakReference(this) : RemoveWeakReference(this);
-+ }
++ static void NotifyDestroyed(nsMenuObject *aMenuObject);
+
+private:
-+ nsWeakMenuObjectBase* GetPrevious() const { return mPrev; }
-+ void SetPrevious(nsWeakMenuObjectBase *aPrev)
-+ {
-+ mPrev = aPrev;
-+ }
-+ void Clear() { mMenuObject = nullptr; }
-+
-+ static void AddWeakReference(nsWeakMenuObjectBase *aWeak);
-+ static void RemoveWeakReference(nsWeakMenuObjectBase *aWeak);
++ static void AddWeakReference(nsWeakMenuObject *aWeak);
++ static void RemoveWeakReference(nsWeakMenuObject *aWeak);
+
-+ nsWeakMenuObjectBase *mPrev;
-+ static nsWeakMenuObjectBase *sHead;
++ nsWeakMenuObject *mPrev;
++ static nsWeakMenuObject *sHead;
+
+ nsMenuObject *mMenuObject;
+};
+
-+// Keep a weak pointer to a menu object. Note, if you need to work
-+// with a pointer to this class, use nsAutoWeakMenuObject instead
-+template<class T>
-+class nsWeakMenuObject : public nsWeakMenuObjectBase
-+{
-+public:
-+ nsWeakMenuObject() :
-+ nsWeakMenuObjectBase() { };
-+
-+ nsWeakMenuObject(T *aMenuObject) :
-+ nsWeakMenuObjectBase()
-+ {
-+ SetMenuObject(aMenuObject);
-+ }
-+
-+ T* get() const { return static_cast<T *>(getBase()); }
-+
-+ T* operator->() const { return get(); }
-+
-+ operator T*() const { return get(); }
-+};
-+
-+template<class T>
-+class nsAutoWeakMenuObject
-+{
-+public:
-+ nsAutoWeakMenuObject() { };
-+
-+ nsAutoWeakMenuObject(T *aMenuObject) :
-+ mPtr(new nsWeakMenuObject<T>(aMenuObject)) { };
-+
-+ nsAutoWeakMenuObject(nsWeakMenuObject<T> *aWeak) :
-+ mPtr(aWeak) { };
-+
-+ T* get() const { return static_cast<T *>(*mPtr); }
-+
-+ T* operator->() const { return get(); }
-+
-+ operator T*() const { return get(); }
-+
-+ nsWeakMenuObject<T>* getWeakPtr() const { return mPtr; }
-+
-+ nsWeakMenuObject<T>* forget() { return mPtr.forget(); }
-+
-+private:
-+ nsAutoPtr<nsWeakMenuObject<T> > mPtr;
-+};
-+
+#endif /* __nsMenuObject_h__ */
-Index: firefox-52.0~b9+build2/widget/gtk/nsMenuSeparator.cpp
+Index: firefox-53.0~a2~hg20170302r359591/widget/gtk/nsMenuSeparator.cpp
===================================================================
--- /dev/null
-+++ firefox-52.0~b9+build2/widget/gtk/nsMenuSeparator.cpp
-@@ -0,0 +1,90 @@
++++ firefox-53.0~a2~hg20170302r359591/widget/gtk/nsMenuSeparator.cpp
+@@ -0,0 +1,85 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* vim:expandtab:shiftwidth=4:tabstop=4:
+ */
@@ -4022,6 +3908,8 @@ Index: firefox-52.0~b9+build2/widget/gtk/nsMenuSeparator.cpp
+ * 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/. */
+
++#include "mozilla/Assertions.h"
++#include "mozilla/Move.h"
+#include "nsAutoPtr.h"
+#include "nsCRT.h"
+#include "nsGkAtoms.h"
@@ -4032,6 +3920,8 @@ Index: firefox-52.0~b9+build2/widget/gtk/nsMenuSeparator.cpp
+#include "nsMenuContainer.h"
+#include "nsMenuSeparator.h"
+
++using namespace mozilla;
++
+void
+nsMenuSeparator::InitializeNativeData()
+{
@@ -4063,37 +3953,10 @@ Index: firefox-52.0~b9+build2/widget/gtk/nsMenuSeparator.cpp
+ );
+}
+
-+nsMenuSeparator::nsMenuSeparator()
-+{
-+ MOZ_COUNT_CTOR(nsMenuSeparator);
-+}
-+
-+nsMenuSeparator::~nsMenuSeparator()
-+{
-+ MOZ_COUNT_DTOR(nsMenuSeparator);
-+}
-+
-+nsMenuObject::EType
-+nsMenuSeparator::Type() const
-+{
-+ return nsMenuObject::eType_MenuSeparator;
-+}
-+
-+/* static */ nsMenuObject*
-+nsMenuSeparator::Create(nsMenuContainer *aParent, nsIContent *aContent)
-+{
-+ nsAutoPtr<nsMenuSeparator> sep(new nsMenuSeparator());
-+ if (NS_FAILED(sep->Init(aParent, aContent))) {
-+ return nullptr;
-+ }
-+
-+ return sep.forget();
-+}
-+
+void
+nsMenuSeparator::OnAttributeChanged(nsIContent *aContent, nsIAtom *aAttribute)
+{
-+ NS_ASSERTION(aContent == ContentNode(), "Received an event that wasn't meant for us!");
++ MOZ_ASSERT(aContent == ContentNode(), "Received an event that wasn't meant for us!");
+
+ if (!Parent()->IsBeingDisplayed()) {
+ return;
@@ -4105,11 +3968,29 @@ Index: firefox-52.0~b9+build2/widget/gtk/nsMenuSeparator.cpp
+ UpdateVisibility(sc);
+ }
+}
-Index: firefox-52.0~b9+build2/widget/gtk/nsMenuSeparator.h
++
++nsMenuSeparator::nsMenuSeparator(nsMenuContainer *aParent,
++ nsIContent *aContent) :
++ nsMenuObject(aParent, aContent)
++{
++ MOZ_COUNT_CTOR(nsMenuSeparator);
++}
++
++nsMenuSeparator::~nsMenuSeparator()
++{
++ MOZ_COUNT_DTOR(nsMenuSeparator);
++}
++
++nsMenuObject::EType
++nsMenuSeparator::Type() const
++{
++ return eType_MenuItem;
++}
+Index: firefox-53.0~a2~hg20170302r359591/widget/gtk/nsMenuSeparator.h
===================================================================
--- /dev/null
-+++ firefox-52.0~b9+build2/widget/gtk/nsMenuSeparator.h
-@@ -0,0 +1,41 @@
++++ firefox-53.0~a2~hg20170302r359591/widget/gtk/nsMenuSeparator.h
+@@ -0,0 +1,37 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* vim:expandtab:shiftwidth=4:tabstop=4:
+ */
@@ -4132,30 +4013,26 @@ Index: firefox-52.0~b9+build2/widget/gtk/nsMenuSeparator.h
+class nsMenuSeparator final : public nsMenuObject
+{
+public:
++ nsMenuSeparator(nsMenuContainer *aParent, nsIContent *aContent);
+ ~nsMenuSeparator();
+
-+ nsMenuObject::EType Type() const;
-+
-+ static nsMenuObject* Create(nsMenuContainer *aParent,
-+ nsIContent *aContent);
-+
-+ void OnAttributeChanged(nsIContent *aContent, nsIAtom *aAttribute);
++ nsMenuObject::EType Type() const override;
+
+private:
-+ nsMenuSeparator();
++ void InitializeNativeData() override;
++ void Update(nsStyleContext *aStyleContext) override;
++ bool IsCompatibleWithNativeData(DbusmenuMenuitem *aNativeData) const override;
++ nsMenuObject::PropertyFlags SupportedProperties() const override;
+
-+ void InitializeNativeData();
-+ void Update(nsStyleContext *aStyleContext);
-+ bool IsCompatibleWithNativeData(DbusmenuMenuitem *aNativeData) const;
-+ nsMenuObject::PropertyFlags SupportedProperties() const;
++ void OnAttributeChanged(nsIContent *aContent, nsIAtom *aAttribute) override;
+};
+
+#endif /* __nsMenuSeparator_h__ */
-Index: firefox-52.0~b9+build2/widget/gtk/nsNativeMenuAtomList.h
+Index: firefox-53.0~a2~hg20170302r359591/widget/gtk/nsNativeMenuAtomList.h
===================================================================
--- /dev/null
-+++ firefox-52.0~b9+build2/widget/gtk/nsNativeMenuAtomList.h
-@@ -0,0 +1,11 @@
++++ firefox-53.0~a2~hg20170302r359591/widget/gtk/nsNativeMenuAtomList.h
+@@ -0,0 +1,12 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* vim:expandtab:shiftwidth=4:tabstop=4:
+ */
@@ -4164,13 +4041,14 @@ Index: firefox-52.0~b9+build2/widget/gtk/nsNativeMenuAtomList.h
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+WIDGET_ATOM2(menuitem_with_favicon, "menuitem-with-favicon")
-+WIDGET_ATOM2(_moz_menupopupstate, "_moz-menupopupstate")
++WIDGET_ATOM2(_moz_menubarkeeplocal, "_moz-menubarkeeplocal")
++WIDGET_ATOM2(_moz_nativemenupopupstate, "_moz-nativemenupopupstate")
+WIDGET_ATOM(openedwithkey)
+WIDGET_ATOM(shellshowingmenubar)
-Index: firefox-52.0~b9+build2/widget/gtk/nsNativeMenuAtoms.cpp
+Index: firefox-53.0~a2~hg20170302r359591/widget/gtk/nsNativeMenuAtoms.cpp
===================================================================
--- /dev/null
-+++ firefox-52.0~b9+build2/widget/gtk/nsNativeMenuAtoms.cpp
++++ firefox-53.0~a2~hg20170302r359591/widget/gtk/nsNativeMenuAtoms.cpp
@@ -0,0 +1,39 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* vim:expandtab:shiftwidth=4:tabstop=4:
@@ -4211,11 +4089,11 @@ Index: firefox-52.0~b9+build2/widget/gtk/nsNativeMenuAtoms.cpp
+{
+ NS_RegisterStaticAtoms(gAtoms);
+}
-Index: firefox-52.0~b9+build2/widget/gtk/nsNativeMenuAtoms.h
+Index: firefox-53.0~a2~hg20170302r359591/widget/gtk/nsNativeMenuAtoms.h
===================================================================
--- /dev/null
-+++ firefox-52.0~b9+build2/widget/gtk/nsNativeMenuAtoms.h
-@@ -0,0 +1,25 @@
++++ firefox-53.0~a2~hg20170302r359591/widget/gtk/nsNativeMenuAtoms.h
+@@ -0,0 +1,27 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* vim:expandtab:shiftwidth=4:tabstop=4:
+ */
@@ -4231,6 +4109,8 @@ Index: firefox-52.0~b9+build2/widget/gtk/nsNativeMenuAtoms.h
+class nsNativeMenuAtoms
+{
+public:
++ nsNativeMenuAtoms() = delete;
++
+ static void RegisterAtoms();
+
+#define WIDGET_ATOM(_name) static nsIAtom* _name;
@@ -4241,11 +4121,11 @@ Index: firefox-52.0~b9+build2/widget/gtk/nsNativeMenuAtoms.h
+};
+
+#endif /* __nsNativeMenuAtoms_h__ */
-Index: firefox-52.0~b9+build2/widget/gtk/nsNativeMenuDocListener.cpp
+Index: firefox-53.0~a2~hg20170302r359591/widget/gtk/nsNativeMenuDocListener.cpp
===================================================================
--- /dev/null
-+++ firefox-52.0~b9+build2/widget/gtk/nsNativeMenuDocListener.cpp
-@@ -0,0 +1,370 @@
++++ firefox-53.0~a2~hg20170302r359591/widget/gtk/nsNativeMenuDocListener.cpp
+@@ -0,0 +1,350 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* vim:expandtab:shiftwidth=4:tabstop=4:
+ */
@@ -4267,7 +4147,7 @@ Index: firefox-52.0~b9+build2/widget/gtk/nsNativeMenuDocListener.cpp
+
+using namespace mozilla;
+
-+uint32_t nsNativeMenuDocListener::sUpdateDepth = 0;
++uint32_t nsNativeMenuDocListener::sUpdateBlockersCount = 0;
+
+nsNativeMenuDocListenerTArray *gPendingListeners;
+
@@ -4308,6 +4188,93 @@ Index: firefox-52.0~b9+build2/widget/gtk/nsNativeMenuDocListener.cpp
+
+NS_IMPL_ISUPPORTS(nsNativeMenuDocListener, nsIMutationObserver)
+
++nsNativeMenuDocListener::~nsNativeMenuDocListener()
++{
++ MOZ_ASSERT(mContentToObserverTable.Count() == 0,
++ "Some nodes forgot to unregister listeners. This is bad! (and we're lucky we made it this far)");
++ MOZ_COUNT_DTOR(nsNativeMenuDocListener);
++}
++
++void
++nsNativeMenuDocListener::AttributeChanged(nsIDocument *aDocument,
++ mozilla::dom::Element *aElement,
++ int32_t aNameSpaceID,
++ nsIAtom *aAttribute,
++ int32_t aModType,
++ const nsAttrValue* aOldValue)
++{
++ if (sUpdateBlockersCount == 0) {
++ DoAttributeChanged(aElement, aAttribute);
++ return;
++ }
++
++ MutationRecord *m = *mPendingMutations.AppendElement(new MutationRecord);
++ m->mType = MutationRecord::eAttributeChanged;
++ m->mTarget = aElement;
++ m->mAttribute = aAttribute;
++
++ ScheduleFlush(this);
++}
++
++void
++nsNativeMenuDocListener::ContentAppended(nsIDocument *aDocument,
++ nsIContent *aContainer,
++ nsIContent *aFirstNewContent,
++ int32_t aNewIndexInContainer)
++{
++ for (nsIContent *c = aFirstNewContent; c; c = c->GetNextSibling()) {
++ ContentInserted(aDocument, aContainer, c, 0);
++ }
++}
++
++void
++nsNativeMenuDocListener::ContentInserted(nsIDocument *aDocument,
++ nsIContent *aContainer,
++ nsIContent *aChild,
++ int32_t aIndexInContainer)
++{
++ nsIContent *prevSibling = nsMenuContainer::GetPreviousSupportedSibling(aChild);
++
++ if (sUpdateBlockersCount == 0) {
++ DoContentInserted(aContainer, aChild, prevSibling);
++ return;
++ }
++
++ MutationRecord *m = *mPendingMutations.AppendElement(new MutationRecord);
++ m->mType = MutationRecord::eContentInserted;
++ m->mTarget = aContainer;
++ m->mChild = aChild;
++ m->mPrevSibling = prevSibling;
++
++ ScheduleFlush(this);
++}
++
++void
++nsNativeMenuDocListener::ContentRemoved(nsIDocument *aDocument,
++ nsIContent *aContainer,
++ nsIContent *aChild,
++ int32_t aIndexInContainer,
++ nsIContent *aPreviousSibling)
++{
++ if (sUpdateBlockersCount == 0) {
++ DoContentRemoved(aContainer, aChild);
++ return;
++ }
++
++ MutationRecord *m = *mPendingMutations.AppendElement(new MutationRecord);
++ m->mType = MutationRecord::eContentRemoved;
++ m->mTarget = aContainer;
++ m->mChild = aChild;
++
++ ScheduleFlush(this);
++}
++
++void
++nsNativeMenuDocListener::NodeWillBeDestroyed(const nsINode *aNode)
++{
++ mDocument = nullptr;
++}
++
+void
+nsNativeMenuDocListener::DoAttributeChanged(nsIContent *aContent,
+ nsIAtom *aAttribute)
@@ -4340,44 +4307,44 @@ Index: firefox-52.0~b9+build2/widget/gtk/nsNativeMenuDocListener.cpp
+}
+
+void
-+nsNativeMenuDocListener::DoBeginUpdateBatch(nsIContent *aTarget)
++nsNativeMenuDocListener::DoBeginUpdates(nsIContent *aTarget)
+{
+ DispatchHelper h(this, aTarget);
+ if (h.HasObserver()) {
-+ h.Observer()->BeginUpdateBatch(aTarget);
++ h.Observer()->OnBeginUpdates(aTarget);
+ }
+}
+
+void
-+nsNativeMenuDocListener::DoEndUpdateBatch(nsIContent *aTarget)
++nsNativeMenuDocListener::DoEndUpdates(nsIContent *aTarget)
+{
+ DispatchHelper h(this, aTarget);
+ if (h.HasObserver()) {
-+ h.Observer()->EndUpdateBatch();
++ h.Observer()->OnEndUpdates();
+ }
+}
+
+void
+nsNativeMenuDocListener::FlushPendingMutations()
+{
-+ nsIContent *batchTarget = nullptr;
-+ bool inUpdateBatch = false;
++ nsIContent *currentTarget = nullptr;
++ bool inUpdateSequence = false;
+
+ while (mPendingMutations.Length() > 0) {
+ MutationRecord *m = mPendingMutations[0];
+
-+ if (m->mTarget != batchTarget) {
-+ if (inUpdateBatch) {
-+ DoEndUpdateBatch(batchTarget);
-+ inUpdateBatch = false;
++ if (m->mTarget != currentTarget) {
++ if (inUpdateSequence) {
++ DoEndUpdates(currentTarget);
++ inUpdateSequence = false;
+ }
+
-+ batchTarget = m->mTarget;
++ currentTarget = m->mTarget;
+
+ if (mPendingMutations.Length() > 1 &&
-+ mPendingMutations[1]->mTarget == batchTarget) {
-+ DoBeginUpdateBatch(batchTarget);
-+ inUpdateBatch = true;
++ mPendingMutations[1]->mTarget == currentTarget) {
++ DoBeginUpdates(currentTarget);
++ inUpdateSequence = true;
+ }
+ }
+
@@ -4398,15 +4365,15 @@ Index: firefox-52.0~b9+build2/widget/gtk/nsNativeMenuDocListener.cpp
+ mPendingMutations.RemoveElementAt(0);
+ }
+
-+ if (inUpdateBatch) {
-+ DoEndUpdateBatch(batchTarget);
++ if (inUpdateSequence) {
++ DoEndUpdates(currentTarget);
+ }
+}
+
+/* static */ void
+nsNativeMenuDocListener::ScheduleFlush(nsNativeMenuDocListener *aListener)
+{
-+ NS_ASSERTION(sUpdateDepth > 0, "Shouldn't be doing this now");
++ MOZ_ASSERT(sUpdateBlockersCount > 0, "Shouldn't be doing this now");
+
+ if (!gPendingListeners) {
+ gPendingListeners = new nsNativeMenuDocListenerTArray;
@@ -4429,20 +4396,21 @@ Index: firefox-52.0~b9+build2/widget/gtk/nsNativeMenuDocListener.cpp
+}
+
+/* static */ void
-+nsNativeMenuDocListener::EndUpdates()
++nsNativeMenuDocListener::RemoveUpdateBlocker()
+{
-+ if (sUpdateDepth == 1 && gPendingListeners) {
++ if (sUpdateBlockersCount == 1 && gPendingListeners) {
+ while (gPendingListeners->Length() > 0) {
+ (*gPendingListeners)[0]->FlushPendingMutations();
+ gPendingListeners->RemoveElementAt(0);
+ }
+ }
+
-+ NS_ASSERTION(sUpdateDepth > 0, "Negative update depth!");
-+ sUpdateDepth--;
++ MOZ_ASSERT(sUpdateBlockersCount > 0, "Negative update blockers count!");
++ sUpdateBlockersCount--;
+}
+
-+nsNativeMenuDocListener::nsNativeMenuDocListener() :
++nsNativeMenuDocListener::nsNativeMenuDocListener(nsIContent *aRootNode) :
++ mRootNode(aRootNode),
+ mDocument(nullptr),
+ mLastSource(nullptr),
+ mLastTarget(nullptr)
@@ -4450,127 +4418,19 @@ Index: firefox-52.0~b9+build2/widget/gtk/nsNativeMenuDocListener.cpp
+ MOZ_COUNT_CTOR(nsNativeMenuDocListener);
+}
+
-+nsNativeMenuDocListener::~nsNativeMenuDocListener()
-+{
-+ MOZ_ASSERT(mContentToObserverTable.Count() == 0,
-+ "Some nodes forgot to unregister listeners. This is bad! (and we're lucky we made it this far)");
-+ MOZ_COUNT_DTOR(nsNativeMenuDocListener);
-+}
-+
-+nsresult
-+nsNativeMenuDocListener::Init(nsIContent *aRootNode)
-+{
-+ NS_ENSURE_ARG(aRootNode);
-+
-+ mRootNode = aRootNode;
-+
-+ return NS_OK;
-+}
-+
-+void
-+nsNativeMenuDocListener::AttributeChanged(nsIDocument *aDocument,
-+ mozilla::dom::Element *aElement,
-+ int32_t aNameSpaceID,
-+ nsIAtom *aAttribute,
-+ int32_t aModType,
-+ const nsAttrValue* aOldValue)
-+{
-+ if (sUpdateDepth == 0) {
-+ DoAttributeChanged(aElement, aAttribute);
-+ return;
-+ }
-+
-+ MutationRecord *m = *mPendingMutations.AppendElement(new MutationRecord);
-+ m->mType = MutationRecord::eAttributeChanged;
-+ m->mTarget = aElement;
-+ m->mAttribute = aAttribute;
-+
-+ ScheduleFlush(this);
-+}
-+
-+void
-+nsNativeMenuDocListener::ContentAppended(nsIDocument *aDocument,
-+ nsIContent *aContainer,
-+ nsIContent *aFirstNewContent,
-+ int32_t aNewIndexInContainer)
-+{
-+ for (nsIContent *c = aFirstNewContent; c; c = c->GetNextSibling()) {
-+ ContentInserted(aDocument, aContainer, c, 0);
-+ }
-+}
-+
-+void
-+nsNativeMenuDocListener::ContentInserted(nsIDocument *aDocument,
-+ nsIContent *aContainer,
-+ nsIContent *aChild,
-+ int32_t aIndexInContainer)
-+{
-+ nsIContent *prevSibling = nsMenuContainer::GetPreviousSupportedSibling(aChild);
-+
-+ if (sUpdateDepth == 0) {
-+ DoContentInserted(aContainer, aChild, prevSibling);
-+ return;
-+ }
-+
-+ MutationRecord *m = *mPendingMutations.AppendElement(new MutationRecord);
-+ m->mType = MutationRecord::eContentInserted;
-+ m->mTarget = aContainer;
-+ m->mChild = aChild;
-+ m->mPrevSibling = prevSibling;
-+
-+ ScheduleFlush(this);
-+}
-+
-+void
-+nsNativeMenuDocListener::ContentRemoved(nsIDocument *aDocument,
-+ nsIContent *aContainer,
-+ nsIContent *aChild,
-+ int32_t aIndexInContainer,
-+ nsIContent *aPreviousSibling)
-+{
-+ if (sUpdateDepth == 0) {
-+ DoContentRemoved(aContainer, aChild);
-+ return;
-+ }
-+
-+ MutationRecord *m = *mPendingMutations.AppendElement(new MutationRecord);
-+ m->mType = MutationRecord::eContentRemoved;
-+ m->mTarget = aContainer;
-+ m->mChild = aChild;
-+
-+ ScheduleFlush(this);
-+}
-+
-+void
-+nsNativeMenuDocListener::NodeWillBeDestroyed(const nsINode *aNode)
-+{
-+ mDocument = nullptr;
-+}
-+
-+/* static */ already_AddRefed<nsNativeMenuDocListener>
-+nsNativeMenuDocListener::Create(nsIContent *aRootNode)
-+{
-+ RefPtr<nsNativeMenuDocListener> listener = new nsNativeMenuDocListener();
-+ if (NS_FAILED(listener->Init(aRootNode))) {
-+ return nullptr;
-+ }
-+
-+ return listener.forget();
-+}
-+
+void
+nsNativeMenuDocListener::RegisterForContentChanges(nsIContent *aContent,
+ nsNativeMenuChangeObserver *aObserver)
+{
-+ NS_ASSERTION(aContent, "Need content parameter");
-+ NS_ASSERTION(aObserver, "Need observer parameter");
++ MOZ_ASSERT(aContent, "Need content parameter");
++ MOZ_ASSERT(aObserver, "Need observer parameter");
+ if (!aContent || !aObserver) {
+ return;
+ }
+
+ DebugOnly<nsNativeMenuChangeObserver *> old;
-+ NS_ASSERTION(!mContentToObserverTable.Get(aContent, &old) || old == aObserver,
-+ "Multiple observers for the same content node are not supported");
++ MOZ_ASSERT(!mContentToObserverTable.Get(aContent, &old) || old == aObserver,
++ "Multiple observers for the same content node are not supported");
+
+ mContentToObserverTable.Put(aContent, aObserver);
+}
@@ -4578,7 +4438,7 @@ Index: firefox-52.0~b9+build2/widget/gtk/nsNativeMenuDocListener.cpp
+void
+nsNativeMenuDocListener::UnregisterForContentChanges(nsIContent *aContent)
+{
-+ NS_ASSERTION(aContent, "Need content parameter");
++ MOZ_ASSERT(aContent, "Need content parameter");
+ if (!aContent) {
+ return;
+ }
@@ -4616,11 +4476,11 @@ Index: firefox-52.0~b9+build2/widget/gtk/nsNativeMenuDocListener.cpp
+ CancelFlush(this);
+ mPendingMutations.Clear();
+}
-Index: firefox-52.0~b9+build2/widget/gtk/nsNativeMenuDocListener.h
+Index: firefox-53.0~a2~hg20170302r359591/widget/gtk/nsNativeMenuDocListener.h
===================================================================
--- /dev/null
-+++ firefox-52.0~b9+build2/widget/gtk/nsNativeMenuDocListener.h
-@@ -0,0 +1,153 @@
++++ firefox-53.0~a2~hg20170302r359591/widget/gtk/nsNativeMenuDocListener.h
+@@ -0,0 +1,152 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* vim:expandtab:shiftwidth=4:tabstop=4:
+ */
@@ -4652,13 +4512,8 @@ Index: firefox-52.0~b9+build2/widget/gtk/nsNativeMenuDocListener.h
+{
+public:
+ NS_DECL_ISUPPORTS
-+ NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTECHANGED
-+ NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED
-+ NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED
-+ NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED
-+ NS_DECL_NSIMUTATIONOBSERVER_NODEWILLBEDESTROYED
+
-+ static already_AddRefed<nsNativeMenuDocListener> Create(nsIContent *aRootNode);
++ nsNativeMenuDocListener(nsIContent *aRootNode);
+
+ // Register an observer to receive mutation events for the specified
+ // content node. The caller must keep the observer alive until
@@ -4677,8 +4532,32 @@ Index: firefox-52.0~b9+build2/widget/gtk/nsNativeMenuDocListener.h
+ // to registered observers.
+ void Stop();
+
++ /*
++ * This class is intended to be used inside GObject signal handlers.
++ * It allows us to queue updates until we have finished delivering
++ * events to Gecko, and then we can batch updates to our view of the
++ * menu. This allows us to do menu updates without altering the structure
++ * seen by the OS.
++ */
++ class MOZ_STACK_CLASS BlockUpdatesScope
++ {
++ public:
++ BlockUpdatesScope(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM)
++ {
++ MOZ_GUARD_OBJECT_NOTIFIER_INIT;
++ nsNativeMenuDocListener::AddUpdateBlocker();
++ }
++
++ ~BlockUpdatesScope()
++ {
++ nsNativeMenuDocListener::RemoveUpdateBlocker();
++ }
++
++ private:
++ MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
++ };
++
+private:
-+ friend class nsNativeMenuAutoUpdateBatch;
+ friend class DispatchHelper;
+
+ struct MutationRecord {
@@ -4694,91 +4573,71 @@ Index: firefox-52.0~b9+build2/widget/gtk/nsNativeMenuDocListener.h
+ nsCOMPtr<nsIAtom> mAttribute;
+ };
+
-+ nsNativeMenuDocListener();
+ ~nsNativeMenuDocListener();
-+ nsresult Init(nsIContent *aRootNode);
++
++ NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTECHANGED
++ NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED
++ NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED
++ NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED
++ NS_DECL_NSIMUTATIONOBSERVER_NODEWILLBEDESTROYED
+
+ void DoAttributeChanged(nsIContent *aContent, nsIAtom *aAttribute);
+ void DoContentInserted(nsIContent *aContainer,
+ nsIContent *aChild,
+ nsIContent *aPrevSibling);
+ void DoContentRemoved(nsIContent *aContainer, nsIContent *aChild);
-+ void DoBeginUpdateBatch(nsIContent *aTarget);
-+ void DoEndUpdateBatch(nsIContent *aTarget);
++ void DoBeginUpdates(nsIContent *aTarget);
++ void DoEndUpdates(nsIContent *aTarget);
++
+ void FlushPendingMutations();
+ static void ScheduleFlush(nsNativeMenuDocListener *aListener);
+ static void CancelFlush(nsNativeMenuDocListener *aListener);
-+ static void BeginUpdates() { ++sUpdateDepth; }
-+ static void EndUpdates();
++
++ static void AddUpdateBlocker() { ++sUpdateBlockersCount; }
++ static void RemoveUpdateBlocker();
+
+ nsCOMPtr<nsIContent> mRootNode;
+ nsIDocument *mDocument;
+ nsIContent *mLastSource;
+ nsNativeMenuChangeObserver *mLastTarget;
+ nsTArray<nsAutoPtr<MutationRecord> > mPendingMutations;
-+ nsDataHashtable<nsPtrHashKey<nsIContent>, nsNativeMenuChangeObserver*> mContentToObserverTable;
++ nsDataHashtable<nsPtrHashKey<nsIContent>, nsNativeMenuChangeObserver *> mContentToObserverTable;
+
-+ static uint32_t sUpdateDepth;
++ static uint32_t sUpdateBlockersCount;
+};
+
+typedef nsTArray<RefPtr<nsNativeMenuDocListener> > nsNativeMenuDocListenerTArray;
+
++/*
++ * Implemented by classes that want to listen to mutation events from content
++ * nodes.
++ */
+class nsNativeMenuChangeObserver
+{
+public:
-+ virtual void OnAttributeChanged(nsIContent *aContent, nsIAtom *aAttribute)
-+ {
-+ NS_ERROR("Unhandled AttributeChanged() notification");
-+ }
++ virtual void OnAttributeChanged(nsIContent *aContent, nsIAtom *aAttribute) {}
+
+ virtual void OnContentInserted(nsIContent *aContainer,
+ nsIContent *aChild,
-+ nsIContent *aPrevSibling)
-+ {
-+ NS_ERROR("Unhandled ContentInserted() notification");
-+ }
-+
-+ virtual void OnContentRemoved(nsIContent *aContainer, nsIContent *aChild)
-+ {
-+ NS_ERROR("Unhandled ContentRemoved() notification");
-+ }
-+
-+ virtual void BeginUpdateBatch(nsIContent *aContent) { };
++ nsIContent *aPrevSibling) {}
+
-+ virtual void EndUpdateBatch() { };
-+};
-+
-+/*
-+ * This class is intended to be used inside GObject signal handlers.
-+ * It allows us to queue updates until we have finished delivering
-+ * events to Gecko, and then we can batch updates to our view of the
-+ * menu. This allows us to do menu updates without altering the structure
-+ * seen by the OS.
-+ */
-+class MOZ_STACK_CLASS nsNativeMenuAutoUpdateBatch
-+{
-+public:
-+ nsNativeMenuAutoUpdateBatch(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM)
-+ {
-+ MOZ_GUARD_OBJECT_NOTIFIER_INIT;
-+ nsNativeMenuDocListener::BeginUpdates();
-+ }
++ virtual void OnContentRemoved(nsIContent *aContainer, nsIContent *aChild) {}
+
-+ ~nsNativeMenuAutoUpdateBatch()
-+ {
-+ nsNativeMenuDocListener::EndUpdates();
-+ }
++ // Signals the start of a sequence of more than 1 event for the specified
++ // node. This only happens when events are flushed as all BlockUpdatesScope
++ // instances go out of scope
++ virtual void OnBeginUpdates(nsIContent *aContent) {};
+
-+private:
-+ MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
++ // Signals the end of a sequence of events
++ virtual void OnEndUpdates() {};
+};
+
+#endif /* __nsNativeMenuDocListener_h__ */
-Index: firefox-52.0~b9+build2/widget/gtk/nsNativeMenuService.cpp
+Index: firefox-53.0~a2~hg20170302r359591/widget/gtk/nsNativeMenuService.cpp
===================================================================
--- /dev/null
-+++ firefox-52.0~b9+build2/widget/gtk/nsNativeMenuService.cpp
-@@ -0,0 +1,506 @@
++++ firefox-53.0~a2~hg20170302r359591/widget/gtk/nsNativeMenuService.cpp
+@@ -0,0 +1,541 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* vim:expandtab:shiftwidth=4:tabstop=4:
+ */
@@ -4786,8 +4645,11 @@ Index: firefox-52.0~b9+build2/widget/gtk/nsNativeMenuService.cpp
+ * 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/. */
+
++#include "mozilla/Assertions.h"
++#include "mozilla/Move.h"
+#include "mozilla/Preferences.h"
+#include "mozilla/Services.h"
++#include "mozilla/UniquePtr.h"
+#include "nsAutoPtr.h"
+#include "nsCOMPtr.h"
+#include "nsCRT.h"
@@ -4909,6 +4771,96 @@ Index: firefox-52.0~b9+build2/widget/gtk/nsNativeMenuService.cpp
+
+NS_IMPL_ISUPPORTS(nsNativeMenuService, nsINativeMenuService, nsIObserver)
+
++nsNativeMenuService::nsNativeMenuService() :
++ mCreateProxyCancellable(nullptr), mDbusProxy(nullptr), mOnline(false)
++{
++}
++
++nsNativeMenuService::~nsNativeMenuService()
++{
++ SetOnline(false);
++
++ if (mCreateProxyCancellable) {
++ g_cancellable_cancel(mCreateProxyCancellable);
++ g_object_unref(mCreateProxyCancellable);
++ mCreateProxyCancellable = nullptr;
++ }
++
++ // Make sure we disconnect map-event handlers
++ while (mMenuBars.Length() > 0) {
++ NotifyNativeMenuBarDestroyed(mMenuBars[0]);
++ }
++
++ Preferences::UnregisterCallback(PrefChangedCallback,
++ "ui.use_unity_menubar");
++
++ if (mDbusProxy) {
++ g_signal_handlers_disconnect_by_func(mDbusProxy,
++ FuncToGpointer(name_owner_changed_cb),
++ NULL);
++ g_object_unref(mDbusProxy);
++ }
++
++ if (gPendingListeners) {
++ delete gPendingListeners;
++ gPendingListeners = nullptr;
++ }
++ if (gPangoLayout) {
++ g_object_unref(gPangoLayout);
++ gPangoLayout = nullptr;
++ }
++}
++
++nsresult
++nsNativeMenuService::Init()
++{
++ nsresult rv = nsDbusmenuFunctions::Init();
++ if (NS_FAILED(rv)) {
++ return rv;
++ }
++
++ rv = GDBusInit();
++ if (NS_FAILED(rv)) {
++ return rv;
++ }
++
++ Preferences::RegisterCallback(PrefChangedCallback,
++ "ui.use_unity_menubar");
++
++ mCreateProxyCancellable = g_cancellable_new();
++
++ g_dbus_proxy_new_for_bus(G_BUS_TYPE_SESSION,
++ static_cast<GDBusProxyFlags>(
++ G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES |
++ G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS |
++ G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START),
++ nullptr,
++ "com.canonical.AppMenu.Registrar",
++ "/com/canonical/AppMenu/Registrar",
++ "com.canonical.AppMenu.Registrar",
++ mCreateProxyCancellable, proxy_created_cb,
++ nullptr);
++
++ /* We don't technically know that the shell will draw the menubar until
++ * we know whether anybody owns the name of the menubar service on the
++ * session bus. However, discovering this happens asynchronously so
++ * we optimize for the common case here by assuming that the shell will
++ * draw window menubars if we are running inside Unity. This should
++ * mean that we avoid temporarily displaying the window menubar ourselves
++ */
++ const char *desktop = getenv("XDG_CURRENT_DESKTOP");
++ if (nsCRT::strcmp(desktop, "Unity") == 0) {
++ SetOnline(true);
++ }
++
++ nsCOMPtr<nsIObserverService> os = services::GetObserverService();
++ if (os) {
++ os->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false);
++ }
++
++ return NS_OK;
++}
++
+/* static */ void
+nsNativeMenuService::EnsureInitialized()
+{
@@ -4916,8 +4868,8 @@ Index: firefox-52.0~b9+build2/widget/gtk/nsNativeMenuService.cpp
+ nsCOMPtr<nsINativeMenuService> service =
+ do_GetService("@mozilla.org/widget/nativemenuservice;1");
+ }
-+ NS_ASSERTION(sService != nullptr || sShutdown == true,
-+ "Failed to create native menu service");
++ MOZ_ASSERT(sService != nullptr || sShutdown == true,
++ "Failed to create native menu service");
+}
+
+void
@@ -4952,7 +4904,7 @@ Index: firefox-52.0~b9+build2/widget/gtk/nsNativeMenuService.cpp
+
+ if (!mDbusProxy ||
+ !gtk_widget_get_mapped(aMenuBar->TopLevelWindow()) ||
-+ aMenuBar->RegisterRequestInProgress()) {
++ mMenuBarRegistrationCancellables.Get(aMenuBar, nullptr)) {
+ // Don't go further if we don't have a proxy for the shell menu
+ // service, the window isn't mapped or there is a request in progress.
+ return;
@@ -4965,15 +4917,17 @@ Index: firefox-52.0~b9+build2/widget/gtk/nsNativeMenuService.cpp
+ return;
+ }
+
++ GCancellable *cancellable = g_cancellable_new();
++ mMenuBarRegistrationCancellables.Put(aMenuBar, cancellable);
++
+ // We keep a weak ref because we can't assume that GDBus cancellation
+ // is reliable (see https://launchpad.net/bugs/953562)
-+ nsAutoWeakMenuObject<nsMenuBar> weakMenuBar(aMenuBar);
+
+ g_dbus_proxy_call(mDbusProxy, "RegisterWindow",
+ g_variant_new("(uo)", xid, path.get()),
+ G_DBUS_CALL_FLAGS_NONE, -1,
-+ aMenuBar->BeginRegisterRequest(),
-+ register_native_menubar_cb, weakMenuBar.forget());
++ cancellable,
++ register_native_menubar_cb, aMenuBar);
+}
+
+/* static */ void
@@ -5017,8 +4971,7 @@ Index: firefox-52.0~b9+build2/widget/gtk/nsNativeMenuService.cpp
+ GAsyncResult *res,
+ gpointer user_data)
+{
-+ nsAutoWeakMenuObject<nsMenuBar> weakMenuBar(
-+ static_cast<nsWeakMenuObject<nsMenuBar> *>(user_data));
++ nsMenuBar *menuBar = static_cast<nsMenuBar *>(user_data);
+
+ GError *error = nullptr;
+ GVariant *results = g_dbus_proxy_call_finish(G_DBUS_PROXY(source_object),
@@ -5038,11 +4991,11 @@ Index: firefox-52.0~b9+build2/widget/gtk/nsNativeMenuService.cpp
+ g_error_free(error);
+ }
+
-+ if (sShutdown || !weakMenuBar) {
++ if (sShutdown) {
+ return;
+ }
+
-+ nsNativeMenuService::GetSingleton()->OnNativeMenuBarRegistered(weakMenuBar,
++ nsNativeMenuService::GetSingleton()->OnNativeMenuBarRegistered(menuBar,
+ success);
+}
+
@@ -5069,7 +5022,9 @@ Index: firefox-52.0~b9+build2/widget/gtk/nsNativeMenuService.cpp
+nsNativeMenuService::OnProxyCreated(GDBusProxy *aProxy)
+{
+ mDbusProxy = aProxy;
-+ mCreateProxyRequest.Finish();
++
++ g_object_unref(mCreateProxyCancellable);
++ mCreateProxyCancellable = nullptr;
+
+ if (!mDbusProxy) {
+ SetOnline(false);
@@ -5086,7 +5041,16 @@ Index: firefox-52.0~b9+build2/widget/gtk/nsNativeMenuService.cpp
+nsNativeMenuService::OnNativeMenuBarRegistered(nsMenuBar *aMenuBar,
+ bool aSuccess)
+{
-+ aMenuBar->EndRegisterRequest();
++ // Don't assume that GDBus cancellation is reliable (ie, |aMenuBar| might
++ // have already been deleted (see https://launchpad.net/bugs/953562)
++ GCancellable *cancellable = nullptr;
++ if (!mMenuBarRegistrationCancellables.Get(aMenuBar, &cancellable)) {
++ return;
++ }
++
++ g_object_unref(cancellable);
++ mMenuBarRegistrationCancellables.Remove(aMenuBar);
++
+ if (!aSuccess) {
+ aMenuBar->Deactivate();
+ }
@@ -5110,86 +5074,55 @@ Index: firefox-52.0~b9+build2/widget/gtk/nsNativeMenuService.cpp
+ OnNameOwnerChanged();
+}
+
-+nsNativeMenuService::nsNativeMenuService() :
-+ mDbusProxy(nullptr), mOnline(false)
-+{
-+}
-+
-+nsNativeMenuService::~nsNativeMenuService()
++NS_IMETHODIMP
++nsNativeMenuService::Observe(nsISupports *aSubject,
++ const char *aTopic,
++ const char16_t *aData)
+{
-+ SetOnline(false);
-+
-+ // Make sure we disconnect map-event handlers
-+ while (mMenuBars.Length() > 0) {
-+ NotifyNativeMenuBarDestroyed(mMenuBars[0]);
-+ }
-+
-+ Preferences::UnregisterCallback(PrefChangedCallback,
-+ "ui.use_unity_menubar");
-+
-+ if (mDbusProxy) {
-+ g_signal_handlers_disconnect_by_func(mDbusProxy,
-+ FuncToGpointer(name_owner_changed_cb),
-+ NULL);
-+ g_object_unref(mDbusProxy);
++ if (!nsCRT::strcmp(NS_XPCOM_SHUTDOWN_OBSERVER_ID, aTopic)) {
++ sShutdown = true;
++ nsCOMPtr<nsIObserverService> os = services::GetObserverService();
++ if (os) {
++ os->RemoveObserver(sService, NS_XPCOM_SHUTDOWN_OBSERVER_ID);
++ }
++ NS_IF_RELEASE(sService);
+ }
+
-+ if (gPendingListeners) {
-+ delete gPendingListeners;
-+ gPendingListeners = nullptr;
-+ }
-+ if (gPangoLayout) {
-+ g_object_unref(gPangoLayout);
-+ gPangoLayout = nullptr;
-+ }
++ return NS_OK;
+}
+
-+nsresult
-+nsNativeMenuService::Init()
++NS_IMETHODIMP
++nsNativeMenuService::CreateNativeMenuBar(nsIWidget *aParent,
++ nsIContent *aMenuBarNode)
+{
-+ nsresult rv = nsDbusmenuFunctions::Init();
-+ if (NS_FAILED(rv)) {
-+ return rv;
-+ }
++ NS_ENSURE_ARG(aParent);
++ NS_ENSURE_ARG(aMenuBarNode);
+
-+ rv = GDBusInit();
-+ if (NS_FAILED(rv)) {
-+ return rv;
++ if (aMenuBarNode->AttrValueIs(kNameSpaceID_None,
++ nsNativeMenuAtoms::_moz_menubarkeeplocal,
++ nsGkAtoms::_true,
++ eCaseMatters)) {
++ return NS_OK;
+ }
+
-+ Preferences::RegisterCallback(PrefChangedCallback,
-+ "ui.use_unity_menubar");
-+
-+ mCreateProxyRequest.Start();
++ UniquePtr<nsMenuBar> menubar(nsMenuBar::Create(aParent, aMenuBarNode));
++ if (!menubar) {
++ NS_WARNING("Failed to create menubar");
++ return NS_ERROR_FAILURE;
++ }
+
-+ g_dbus_proxy_new_for_bus(G_BUS_TYPE_SESSION,
-+ static_cast<GDBusProxyFlags>(
-+ G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES |
-+ G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS |
-+ G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START),
-+ nullptr,
-+ "com.canonical.AppMenu.Registrar",
-+ "/com/canonical/AppMenu/Registrar",
-+ "com.canonical.AppMenu.Registrar",
-+ mCreateProxyRequest, proxy_created_cb,
-+ nullptr);
++ // Unity forgets our window if it is unmapped by the application, which
++ // happens with some extensions that add "minimize to tray" type
++ // functionality. We hook on to the MapNotify event to re-register our menu
++ // with Unity
++ g_signal_connect(G_OBJECT(menubar->TopLevelWindow()),
++ "map-event", G_CALLBACK(map_event_cb),
++ menubar.get());
+
-+ /* We don't technically know that the shell will draw the menubar until
-+ * we know whether anybody owns the name of the menubar service on the
-+ * session bus. However, discovering this happens asynchronously so
-+ * we optimize for the common case here by assuming that the shell will
-+ * draw window menubars if we are running inside Unity. This should
-+ * mean that we avoid temporarily displaying the window menubar ourselves
-+ */
-+ const char *desktop = getenv("XDG_CURRENT_DESKTOP");
-+ if (nsCRT::strcmp(desktop, "Unity") == 0) {
-+ SetOnline(true);
-+ }
++ mMenuBars.AppendElement(menubar.get());
++ RegisterNativeMenuBar(menubar.get());
+
-+ nsCOMPtr<nsIObserverService> os = services::GetObserverService();
-+ if (os) {
-+ os->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false);
-+ }
++ static_cast<nsWindow *>(aParent)->SetMenuBar(Move(menubar));
+
+ return NS_OK;
+}
@@ -5203,8 +5136,8 @@ Index: firefox-52.0~b9+build2/widget/gtk/nsNativeMenuService.cpp
+ return service.forget();
+ }
+
-+ NS_ASSERTION(sShutdown == false,
-+ "Attempted to access menubar service too late");
++ MOZ_ASSERT(sShutdown == false,
++ "Attempted to access menubar service too late");
+
+ if (sShutdown) {
+ return nullptr;
@@ -5230,23 +5163,6 @@ Index: firefox-52.0~b9+build2/widget/gtk/nsNativeMenuService.cpp
+ return sService;
+}
+
-+NS_IMETHODIMP
-+nsNativeMenuService::Observe(nsISupports *aSubject,
-+ const char *aTopic,
-+ const char16_t *aData)
-+{
-+ if (!nsCRT::strcmp(NS_XPCOM_SHUTDOWN_OBSERVER_ID, aTopic)) {
-+ sShutdown = true;
-+ nsCOMPtr<nsIObserverService> os = services::GetObserverService();
-+ if (os) {
-+ os->RemoveObserver(sService, NS_XPCOM_SHUTDOWN_OBSERVER_ID);
-+ }
-+ NS_IF_RELEASE(sService);
-+ }
-+
-+ return NS_OK;
-+}
-+
+void
+nsNativeMenuService::NotifyNativeMenuBarDestroyed(nsMenuBar *aMenuBar)
+{
@@ -5255,41 +5171,19 @@ Index: firefox-52.0~b9+build2/widget/gtk/nsNativeMenuService.cpp
+ aMenuBar);
+
+ mMenuBars.RemoveElement(aMenuBar);
-+}
+
-+NS_IMETHODIMP
-+nsNativeMenuService::CreateNativeMenuBar(nsIWidget *aParent,
-+ nsIContent *aMenuBarNode)
-+{
-+ NS_ENSURE_ARG(aParent);
-+ NS_ENSURE_ARG(aMenuBarNode);
-+
-+ nsAutoPtr<nsMenuBar> menubar(nsMenuBar::Create(aParent, aMenuBarNode));
-+ if (!menubar) {
-+ NS_WARNING("Failed to create menubar");
-+ return NS_ERROR_FAILURE;
++ GCancellable *cancellable = nullptr;
++ if (mMenuBarRegistrationCancellables.Get(aMenuBar, &cancellable)) {
++ mMenuBarRegistrationCancellables.Remove(aMenuBar);
++ g_cancellable_cancel(cancellable);
++ g_object_unref(cancellable);
+ }
-+
-+ // Unity forgets our window if it is unmapped by the application, which
-+ // happens with some extensions that add "minimize to tray" type
-+ // functionality. We hook on to the MapNotify event to re-register our menu
-+ // with Unity
-+ g_signal_connect(G_OBJECT(menubar->TopLevelWindow()),
-+ "map-event", G_CALLBACK(map_event_cb),
-+ menubar);
-+
-+ mMenuBars.AppendElement(menubar);
-+ RegisterNativeMenuBar(menubar);
-+
-+ static_cast<nsWindow *>(aParent)->SetMenuBar(menubar.forget());
-+
-+ return NS_OK;
+}
-Index: firefox-52.0~b9+build2/widget/gtk/nsNativeMenuService.h
+Index: firefox-53.0~a2~hg20170302r359591/widget/gtk/nsNativeMenuService.h
===================================================================
--- /dev/null
-+++ firefox-52.0~b9+build2/widget/gtk/nsNativeMenuService.h
-@@ -0,0 +1,88 @@
++++ firefox-53.0~a2~hg20170302r359591/widget/gtk/nsNativeMenuService.h
+@@ -0,0 +1,87 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* vim:expandtab:shiftwidth=4:tabstop=4:
+ */
@@ -5302,12 +5196,11 @@ Index: firefox-52.0~b9+build2/widget/gtk/nsNativeMenuService.h
+
+#include "mozilla/Attributes.h"
+#include "nsCOMPtr.h"
++#include "nsDataHashtable.h"
+#include "nsINativeMenuService.h"
+#include "nsIObserver.h"
+#include "nsTArray.h"
+
-+#include "nsNativeMenuUtils.h"
-+
+#include <gdk/gdk.h>
+#include <gio/gio.h>
+#include <gtk/gtk.h>
@@ -5330,9 +5223,7 @@ Index: firefox-52.0~b9+build2/widget/gtk/nsNativeMenuService.h
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSIOBSERVER
+
-+ NS_IMETHOD CreateNativeMenuBar(nsIWidget* aParent, nsIContent* aMenuBarNode);
-+
-+ nsresult Init();
++ NS_IMETHOD CreateNativeMenuBar(nsIWidget* aParent, nsIContent* aMenuBarNode) override;
+
+ // Returns the singleton addref'd for the service manager
+ static already_AddRefed<nsNativeMenuService> GetInstance();
@@ -5340,12 +5231,13 @@ Index: firefox-52.0~b9+build2/widget/gtk/nsNativeMenuService.h
+ // Returns the singleton without increasing the reference count
+ static nsNativeMenuService* GetSingleton();
+
-+ // Called by a menubar when the last reference to it is dropped
++ // Called by a menubar when it is deleted
+ void NotifyNativeMenuBarDestroyed(nsMenuBar *aMenuBar);
+
+private:
+ nsNativeMenuService();
+ ~nsNativeMenuService();
++ nsresult Init();
+
+ static void EnsureInitialized();
+ void SetOnline(bool aOnline);
@@ -5368,84 +5260,33 @@ Index: firefox-52.0~b9+build2/widget/gtk/nsNativeMenuService.h
+ static void PrefChangedCallback(const char *aPref, void *aClosure);
+ void PrefChanged();
+
-+ nsNativeMenuGIORequest mCreateProxyRequest;
++ GCancellable *mCreateProxyCancellable;
+ GDBusProxy *mDbusProxy;
+ bool mOnline;
+ nsTArray<nsMenuBar *> mMenuBars;
++ nsDataHashtable<nsPtrHashKey<nsMenuBar>, GCancellable*> mMenuBarRegistrationCancellables;
+
+ static bool sShutdown;
+ static nsNativeMenuService *sService;
+};
+
+#endif /* __nsNativeMenuService_h__ */
-Index: firefox-52.0~b9+build2/widget/gtk/nsNativeMenuUtils.h
+Index: firefox-53.0~a2~hg20170302r359591/widget/gtk/nsScreenGtk.cpp
===================================================================
---- /dev/null
-+++ firefox-52.0~b9+build2/widget/gtk/nsNativeMenuUtils.h
-@@ -0,0 +1,59 @@
-+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
-+/* vim:expandtab:shiftwidth=4:tabstop=4:
-+ */
-+/* 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/. */
-+
-+#ifndef __nsNativeMenuUtils_h__
-+#define __nsNativeMenuUtils_h__
-+
-+#include <glib-object.h>
-+#include <gio/gio.h>
-+
-+class nsNativeMenuGIORequest
-+{
-+public:
-+ nsNativeMenuGIORequest() : mCancellable(nullptr) { };
-+
-+ ~nsNativeMenuGIORequest() {
-+ Cancel();
-+ }
-+
-+ void Start() {
-+ Cancel();
-+ mCancellable = g_cancellable_new();
-+ }
-+
-+ void Finish() {
-+ if (mCancellable) {
-+ g_object_unref(mCancellable);
-+ mCancellable = nullptr;
-+ }
-+ }
-+
-+ void Cancel() {
-+ if (mCancellable) {
-+ g_cancellable_cancel(mCancellable);
-+ g_object_unref(mCancellable);
-+ mCancellable = nullptr;
-+ }
-+ }
-+
-+ bool InProgress() const {
-+ if (!mCancellable) {
-+ return false;
-+ }
-+
-+ return !g_cancellable_is_cancelled(mCancellable);
-+ }
-+
-+ operator GCancellable*() const {
-+ return mCancellable;
-+ }
-+
-+private:
-+ GCancellable *mCancellable;
-+};
-+
-+#endif /* __nsNativeMenuUtils_h__ */
-Index: firefox-52.0~b9+build2/widget/gtk/nsWidgetFactory.cpp
+--- firefox-53.0~a2~hg20170302r359591.orig/widget/gtk/nsScreenGtk.cpp
++++ firefox-53.0~a2~hg20170302r359591/widget/gtk/nsScreenGtk.cpp
+@@ -15,6 +15,7 @@
+ #include <gtk/gtk.h>
+ #include <dlfcn.h>
+ #include "gfxPlatformGtk.h"
++#include "nsIWidget.h"
+
+ static uint32_t sScreenId = 0;
+
+Index: firefox-53.0~a2~hg20170302r359591/widget/gtk/nsWidgetFactory.cpp
===================================================================
---- firefox-52.0~b9+build2.orig/widget/gtk/nsWidgetFactory.cpp
-+++ firefox-52.0~b9+build2/widget/gtk/nsWidgetFactory.cpp
+--- firefox-53.0~a2~hg20170302r359591.orig/widget/gtk/nsWidgetFactory.cpp
++++ firefox-53.0~a2~hg20170302r359591/widget/gtk/nsWidgetFactory.cpp
@@ -49,6 +49,8 @@
#include "GfxInfoX11.h"
#endif
@@ -5489,26 +5330,34 @@ Index: firefox-52.0~b9+build2/widget/gtk/nsWidgetFactory.cpp
{ nullptr }
};
-Index: firefox-52.0~b9+build2/widget/gtk/nsWindow.cpp
+Index: firefox-53.0~a2~hg20170302r359591/widget/gtk/nsWindow.cpp
===================================================================
---- firefox-52.0~b9+build2.orig/widget/gtk/nsWindow.cpp
-+++ firefox-52.0~b9+build2/widget/gtk/nsWindow.cpp
-@@ -5175,6 +5175,11 @@ nsWindow::HideWindowChrome(bool aShouldH
- return NS_OK;
+--- firefox-53.0~a2~hg20170302r359591.orig/widget/gtk/nsWindow.cpp
++++ firefox-53.0~a2~hg20170302r359591/widget/gtk/nsWindow.cpp
+@@ -67,6 +67,7 @@
+
+ #include "mozilla/Assertions.h"
+ #include "mozilla/Likely.h"
++#include "mozilla/Move.h"
+ #include "mozilla/Preferences.h"
+ #include "nsIPrefService.h"
+ #include "nsIGConfService.h"
+@@ -5161,6 +5162,11 @@ nsWindow::HideWindowChrome(bool aShouldH
+ #endif /* MOZ_X11 */
}
+void
-+nsWindow::SetMenuBar(nsMenuBar *aMenuBar) {
-+ mMenuBar.reset(aMenuBar);
++nsWindow::SetMenuBar(UniquePtr<nsMenuBar> aMenuBar) {
++ mMenuBar = mozilla::Move(aMenuBar);
+}
+
bool
nsWindow::CheckForRollup(gdouble aMouseX, gdouble aMouseY,
bool aIsWheel, bool aAlwaysRollup)
-Index: firefox-52.0~b9+build2/widget/gtk/nsWindow.h
+Index: firefox-53.0~a2~hg20170302r359591/widget/gtk/nsWindow.h
===================================================================
---- firefox-52.0~b9+build2.orig/widget/gtk/nsWindow.h
-+++ firefox-52.0~b9+build2/widget/gtk/nsWindow.h
+--- firefox-53.0~a2~hg20170302r359591.orig/widget/gtk/nsWindow.h
++++ firefox-53.0~a2~hg20170302r359591/widget/gtk/nsWindow.h
@@ -35,6 +35,8 @@
#include "IMContextWrapper.h"
@@ -5520,14 +5369,14 @@ Index: firefox-52.0~b9+build2/widget/gtk/nsWindow.h
@@ -162,6 +164,8 @@ public:
nsIScreen* aTargetScreen = nullptr) override;
- NS_IMETHOD HideWindowChrome(bool aShouldHide) override;
+ virtual void HideWindowChrome(bool aShouldHide) override;
-+ void SetMenuBar(nsMenuBar *aMenuBar);
++ void SetMenuBar(mozilla::UniquePtr<nsMenuBar> aMenuBar);
+
/**
* GetLastUserInputTime returns a timestamp for the most recent user input
* event. This is intended for pointer grab requests (including drags).
-@@ -569,6 +573,8 @@ private:
+@@ -571,6 +575,8 @@ private:
RefPtr<mozilla::widget::IMContextWrapper> mIMContext;
mozilla::UniquePtr<mozilla::CurrentX11TimeGetter> mCurrentTimeGetter;
@@ -5536,19 +5385,11 @@ Index: firefox-52.0~b9+build2/widget/gtk/nsWindow.h
};
class nsChildWindow : public nsWindow {
-Index: firefox-52.0~b9+build2/xpfe/appshell/nsWebShellWindow.cpp
+Index: firefox-53.0~a2~hg20170302r359591/xpfe/appshell/nsWebShellWindow.cpp
===================================================================
---- firefox-52.0~b9+build2.orig/xpfe/appshell/nsWebShellWindow.cpp
-+++ firefox-52.0~b9+build2/xpfe/appshell/nsWebShellWindow.cpp
-@@ -58,6 +58,7 @@
- #include "nsIScreen.h"
-
- #include "nsIContent.h" // for menus
-+#include "nsIAtom.h"
- #include "nsIScriptSecurityManager.h"
-
- // For calculating size
-@@ -73,7 +74,7 @@
+--- firefox-53.0~a2~hg20170302r359591.orig/xpfe/appshell/nsWebShellWindow.cpp
++++ firefox-53.0~a2~hg20170302r359591/xpfe/appshell/nsWebShellWindow.cpp
+@@ -73,7 +73,7 @@
#include "nsPIWindowRoot.h"
@@ -5557,119 +5398,27 @@ Index: firefox-52.0~b9+build2/xpfe/appshell/nsWebShellWindow.cpp
#include "nsINativeMenuService.h"
#define USE_NATIVE_MENUS
#endif
-@@ -498,6 +499,11 @@ static void LoadNativeMenus(nsIDOMDocume
-
- if (menubarNode) {
- nsCOMPtr<nsIContent> menubarContent(do_QueryInterface(menubarNode));
-+#ifdef MOZ_WIDGET_GTK
-+ nsCOMPtr<nsIAtom> atom = NS_Atomize(NS_LITERAL_CSTRING("_moz-menubarkeeplocal"));
-+ if (menubarContent->AttrValueIs(kNameSpaceID_None, atom, nsGkAtoms::_true, eCaseMatters))
-+ return;
-+#endif
- nms->CreateNativeMenuBar(aParentWindow, menubarContent);
- } else {
- nms->CreateNativeMenuBar(aParentWindow, nullptr);
-Index: firefox-52.0~b9+build2/widget/gtk/moz.build
+Index: firefox-53.0~a2~hg20170302r359591/widget/moz.build
===================================================================
---- firefox-52.0~b9+build2.orig/widget/gtk/moz.build
-+++ firefox-52.0~b9+build2/widget/gtk/moz.build
-@@ -24,10 +24,18 @@ UNIFIED_SOURCES += [
- 'nsAppShell.cpp',
- 'nsBidiKeyboard.cpp',
- 'nsColorPicker.cpp',
-+ 'nsDbusmenu.cpp',
- 'nsFilePicker.cpp',
- 'nsGtkKeyUtils.cpp',
- 'nsImageToPixbuf.cpp',
- 'nsLookAndFeel.cpp',
-+ 'nsMenuBar.cpp',
-+ 'nsMenuContainer.cpp',
-+ 'nsMenuItem.cpp',
-+ 'nsMenuObject.cpp',
-+ 'nsMenuSeparator.cpp',
-+ 'nsNativeMenuAtoms.cpp',
-+ 'nsNativeMenuDocListener.cpp',
- 'nsNativeThemeGTK.cpp',
- 'nsScreenGtk.cpp',
- 'nsScreenManagerGtk.cpp',
-@@ -40,6 +48,8 @@ UNIFIED_SOURCES += [
- ]
-
- SOURCES += [
-+ 'nsMenu.cpp', # conflicts with X11 headers
-+ 'nsNativeMenuService.cpp',
- 'nsWindow.cpp', # conflicts with X11 headers
- ]
-
-@@ -104,6 +114,7 @@ FINAL_LIBRARY = 'xul'
-
- LOCAL_INCLUDES += [
- '/layout/generic',
-+ '/layout/style',
- '/layout/xul',
- '/other-licenses/atk-1.0',
- '/widget',
-Index: firefox-52.0~b9+build2/browser/base/content/browser.js
-===================================================================
---- firefox-52.0~b9+build2.orig/browser/base/content/browser.js
-+++ firefox-52.0~b9+build2/browser/base/content/browser.js
-@@ -5079,6 +5079,8 @@ function getTogglableToolbars() {
- let toolbarNodes = Array.slice(gNavToolbox.childNodes);
- toolbarNodes = toolbarNodes.concat(gNavToolbox.externalToolbars);
- toolbarNodes = toolbarNodes.filter(node => node.getAttribute("toolbarname"));
-+ if (document.documentElement.getAttribute("shellshowingmenubar") == "true")
-+ toolbarNodes = toolbarNodes.filter(node => node.id != "toolbar-menubar");
- return toolbarNodes;
- }
-
-Index: firefox-52.0~b9+build2/widget/moz.build
-===================================================================
---- firefox-52.0~b9+build2.orig/widget/moz.build
-+++ firefox-52.0~b9+build2/widget/moz.build
-@@ -37,10 +37,12 @@ elif toolkit == 'cocoa':
+--- firefox-53.0~a2~hg20170302r359591.orig/widget/moz.build
++++ firefox-53.0~a2~hg20170302r359591/widget/moz.build
+@@ -36,9 +36,9 @@ elif toolkit == 'cocoa':
+ 'nsISystemStatusBar.idl',
'nsITaskbarProgress.idl',
]
- EXPORTS += [
+- EXPORTS += [
- 'nsINativeMenuService.h',
- 'nsIPrintDialogService.h',
- ]
-
+- ]
++
+if toolkit in ('cocoa', 'gtk2', 'gtk3'):
+ EXPORTS += ['nsINativeMenuService.h']
-+
- TEST_DIRS += ['tests']
-
- # Don't build the DSO under the 'build' directory as windows does.
-Index: firefox-52.0~b9+build2/modules/libpref/init/all.js
-===================================================================
---- firefox-52.0~b9+build2.orig/modules/libpref/init/all.js
-+++ firefox-52.0~b9+build2/modules/libpref/init/all.js
-@@ -229,6 +229,9 @@ pref("dom.compartment_per_addon", true);
- pref("browser.sessionhistory.max_total_viewers", -1);
- pref("ui.use_native_colors", true);
-+#ifdef MOZ_WIDGET_GTK
-+pref("ui.use_unity_menubar", true);
-+#endif
- pref("ui.click_hold_context_menus", false);
- // Duration of timeout of incremental search in menus (ms). 0 means infinite.
- pref("ui.menu.incremental_search.timeout", 1000);
-Index: firefox-52.0~b9+build2/widget/gtk/nsScreenGtk.cpp
-===================================================================
---- firefox-52.0~b9+build2.orig/widget/gtk/nsScreenGtk.cpp
-+++ firefox-52.0~b9+build2/widget/gtk/nsScreenGtk.cpp
-@@ -15,6 +15,7 @@
- #include <gtk/gtk.h>
- #include <dlfcn.h>
- #include "gfxPlatformGtk.h"
-+#include "nsIWidget.h"
-
- static uint32_t sScreenId = 0;
+ TEST_DIRS += ['tests']
-Index: firefox-52.0~b9+build2/layout/build/moz.build
+Index: firefox-53.0~a2~hg20170302r359591/layout/build/moz.build
===================================================================
---- firefox-52.0~b9+build2.orig/layout/build/moz.build
-+++ firefox-52.0~b9+build2/layout/build/moz.build
+--- firefox-53.0~a2~hg20170302r359591.orig/layout/build/moz.build
++++ firefox-53.0~a2~hg20170302r359591/layout/build/moz.build
@@ -77,6 +77,10 @@ elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'go
LOCAL_INCLUDES += [
'/dom/system/gonk',
@@ -5681,11 +5430,11 @@ Index: firefox-52.0~b9+build2/layout/build/moz.build
if CONFIG['MOZ_WEBSPEECH']:
LOCAL_INCLUDES += [
-Index: firefox-52.0~b9+build2/layout/build/nsLayoutStatics.cpp
+Index: firefox-53.0~a2~hg20170302r359591/layout/build/nsLayoutStatics.cpp
===================================================================
---- firefox-52.0~b9+build2.orig/layout/build/nsLayoutStatics.cpp
-+++ firefox-52.0~b9+build2/layout/build/nsLayoutStatics.cpp
-@@ -132,6 +132,10 @@ using namespace mozilla::system;
+--- firefox-53.0~a2~hg20170302r359591.orig/layout/build/nsLayoutStatics.cpp
++++ firefox-53.0~a2~hg20170302r359591/layout/build/nsLayoutStatics.cpp
+@@ -133,6 +133,10 @@ using namespace mozilla::system;
#include "mozilla/StaticPresData.h"
#include "mozilla/dom/WebIDLGlobalNameHash.h"