~jbicha/firefox/update-dependencies

« back to all changes in this revision

Viewing changes to debian/patches/unity-menubar.patch

  • Committer: Rico Tzschichholz
  • Date: 2017-03-08 11:50:00 UTC
  • Revision ID: ricotz@ubuntu.com-20170308115000-1wrt5h8i66xu8ph4
releasing package firefox version 53.0~b1+build1-0ubuntu0.17.04.1

[ Chris Coulson ]
* Update unity-menubar.patch with the latest version submitted upstream
* Build with --disable-rust for now
* Stop installing the NPAPI headers and make firefox-dev a transitional
  package
  - update debian/build/rules.mk
  - update debian/rules
  - update debian/control{,.in}
  - remove debian/firefox-dev.install.in
  - remove debian/firefox-dev.links.in
  - remove debian/pkgconfig/mozilla-plugin.pc.in
* Add Urdu language pack
* Refresh patches
  - update debian/patches/revert-upstream-search-engine-changes.patch
  - update debian/patches/unity-menubar.patch

[ Rico Tzschichholz ]
* New upstream release from the beta channel (FIREFOX_53_0b1_BUILD1)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
Index: firefox-52.0~b9+build2/browser/base/content/browser-menubar.inc
 
1
Index: firefox-53.0~a2~hg20170302r359591/browser/base/content/browser-menubar.inc
2
2
===================================================================
3
 
--- firefox-52.0~b9+build2.orig/browser/base/content/browser-menubar.inc
4
 
+++ firefox-52.0~b9+build2/browser/base/content/browser-menubar.inc
 
3
--- firefox-53.0~a2~hg20170302r359591.orig/browser/base/content/browser-menubar.inc
 
4
+++ firefox-53.0~a2~hg20170302r359591/browser/base/content/browser-menubar.inc
5
5
@@ -5,7 +5,11 @@
6
6
 
7
7
        <menubar id="main-menubar"
14
14
                                   this.setAttribute('openedwithkey',
15
15
                                                     event.target.parentNode.openedWithKey);"
16
16
                 style="border:0px;padding:0px;margin:0px;-moz-appearance:none">
17
 
Index: firefox-52.0~b9+build2/browser/components/places/content/places.xul
18
 
===================================================================
19
 
--- firefox-52.0~b9+build2.orig/browser/components/places/content/places.xul
20
 
+++ firefox-52.0~b9+build2/browser/components/places/content/places.xul
 
17
Index: firefox-53.0~a2~hg20170302r359591/browser/base/content/browser.js
 
18
===================================================================
 
19
--- firefox-53.0~a2~hg20170302r359591.orig/browser/base/content/browser.js
 
20
+++ firefox-53.0~a2~hg20170302r359591/browser/base/content/browser.js
 
21
@@ -5108,6 +5108,8 @@ function getTogglableToolbars() {
 
22
   let toolbarNodes = Array.slice(gNavToolbox.childNodes);
 
23
   toolbarNodes = toolbarNodes.concat(gNavToolbox.externalToolbars);
 
24
   toolbarNodes = toolbarNodes.filter(node => node.getAttribute("toolbarname"));
 
25
+  if (document.documentElement.getAttribute("shellshowingmenubar") == "true")
 
26
+    toolbarNodes = toolbarNodes.filter(node => node.id != "toolbar-menubar");
 
27
   return toolbarNodes;
 
28
 }
 
29
 
 
30
Index: firefox-53.0~a2~hg20170302r359591/browser/components/places/content/places.xul
 
31
===================================================================
 
32
--- firefox-53.0~a2~hg20170302r359591.orig/browser/components/places/content/places.xul
 
33
+++ firefox-53.0~a2~hg20170302r359591/browser/components/places/content/places.xul
21
34
@@ -157,7 +157,7 @@
22
35
         <toolbarbutton type="menu" class="tabbable"
23
36
               onpopupshowing="document.getElementById('placeContent').focus()"
27
40
         <menu accesskey="&organize.accesskey;" class="menu-iconic"
28
41
 #endif
29
42
               id="organizeButton" label="&organize.label;"
30
 
Index: firefox-52.0~b9+build2/toolkit/content/widgets/popup.xml
31
 
===================================================================
32
 
--- firefox-52.0~b9+build2.orig/toolkit/content/widgets/popup.xml
33
 
+++ firefox-52.0~b9+build2/toolkit/content/widgets/popup.xml
 
43
Index: firefox-53.0~a2~hg20170302r359591/modules/libpref/init/all.js
 
44
===================================================================
 
45
--- firefox-53.0~a2~hg20170302r359591.orig/modules/libpref/init/all.js
 
46
+++ firefox-53.0~a2~hg20170302r359591/modules/libpref/init/all.js
 
47
@@ -230,6 +230,9 @@ pref("dom.compartment_per_addon", true);
 
48
 pref("browser.sessionhistory.max_total_viewers", -1);
 
49
 
 
50
 pref("ui.use_native_colors", true);
 
51
+#ifdef MOZ_WIDGET_GTK
 
52
+pref("ui.use_unity_menubar", true);
 
53
+#endif
 
54
 pref("ui.click_hold_context_menus", false);
 
55
 // Duration of timeout of incremental search in menus (ms).  0 means infinite.
 
56
 pref("ui.menu.incremental_search.timeout", 1000);
 
57
Index: firefox-53.0~a2~hg20170302r359591/toolkit/content/widgets/popup.xml
 
58
===================================================================
 
59
--- firefox-53.0~a2~hg20170302r359591.orig/toolkit/content/widgets/popup.xml
 
60
+++ firefox-53.0~a2~hg20170302r359591/toolkit/content/widgets/popup.xml
34
61
@@ -25,8 +25,14 @@
35
62
         </getter>
36
63
       </property>
39
66
-                onget="return this.popupBoxObject.popupState"/>
40
67
+      <property name="state" readonly="true">
41
68
+        <getter><![CDATA[
42
 
+          if (this.hasAttribute('_moz-menupopupstate'))
43
 
+            return this.getAttribute('_moz-menupopupstate');
 
69
+          if (this.hasAttribute('_moz-nativemenupopupstate'))
 
70
+            return this.getAttribute('_moz-nativemenupopupstate');
44
71
+          else
45
72
+            return this.popupBoxObject.popupState;
46
73
+        ]]></getter>
48
75
 
49
76
       <property name="triggerNode" readonly="true"
50
77
                 onget="return this.popupBoxObject.triggerNode"/>
51
 
Index: firefox-52.0~b9+build2/toolkit/content/xul.css
 
78
Index: firefox-53.0~a2~hg20170302r359591/toolkit/content/xul.css
52
79
===================================================================
53
 
--- firefox-52.0~b9+build2.orig/toolkit/content/xul.css
54
 
+++ firefox-52.0~b9+build2/toolkit/content/xul.css
55
 
@@ -307,6 +307,18 @@ toolbar[type="menubar"][autohide="true"]
 
80
--- firefox-53.0~a2~hg20170302r359591.orig/toolkit/content/xul.css
 
81
+++ firefox-53.0~a2~hg20170302r359591/toolkit/content/xul.css
 
82
@@ -314,6 +314,18 @@ toolbar[type="menubar"][autohide="true"]
56
83
 }
57
84
 %endif
58
85
 
71
98
 toolbarseparator {
72
99
   -moz-binding: url("chrome://global/content/bindings/toolbar.xml#toolbardecoration");
73
100
 }
74
 
Index: firefox-52.0~b9+build2/widget/gtk/nsDbusmenu.cpp
 
101
Index: firefox-53.0~a2~hg20170302r359591/widget/gtk/moz.build
 
102
===================================================================
 
103
--- firefox-53.0~a2~hg20170302r359591.orig/widget/gtk/moz.build
 
104
+++ firefox-53.0~a2~hg20170302r359591/widget/gtk/moz.build
 
105
@@ -24,10 +24,18 @@ UNIFIED_SOURCES += [
 
106
     'nsAppShell.cpp',
 
107
     'nsBidiKeyboard.cpp',
 
108
     'nsColorPicker.cpp',
 
109
+    'nsDbusmenu.cpp',
 
110
     'nsFilePicker.cpp',
 
111
     'nsGtkKeyUtils.cpp',
 
112
     'nsImageToPixbuf.cpp',
 
113
     'nsLookAndFeel.cpp',
 
114
+    'nsMenuBar.cpp',
 
115
+    'nsMenuContainer.cpp',
 
116
+    'nsMenuItem.cpp',
 
117
+    'nsMenuObject.cpp',
 
118
+    'nsMenuSeparator.cpp',
 
119
+    'nsNativeMenuAtoms.cpp',
 
120
+    'nsNativeMenuDocListener.cpp',
 
121
     'nsNativeThemeGTK.cpp',
 
122
     'nsScreenGtk.cpp',
 
123
     'nsScreenManagerGtk.cpp',
 
124
@@ -40,6 +48,8 @@ UNIFIED_SOURCES += [
 
125
 ]
 
126
 
 
127
 SOURCES += [
 
128
+    'nsMenu.cpp', # conflicts with X11 headers
 
129
+    'nsNativeMenuService.cpp',
 
130
     'nsWindow.cpp', # conflicts with X11 headers
 
131
 ]
 
132
 
 
133
@@ -104,6 +114,7 @@ FINAL_LIBRARY = 'xul'
 
134
 
 
135
 LOCAL_INCLUDES += [
 
136
     '/layout/generic',
 
137
+    '/layout/style',
 
138
     '/layout/xul',
 
139
     '/other-licenses/atk-1.0',
 
140
     '/widget',
 
141
Index: firefox-53.0~a2~hg20170302r359591/widget/gtk/nsDbusmenu.cpp
75
142
===================================================================
76
143
--- /dev/null
77
 
+++ firefox-52.0~b9+build2/widget/gtk/nsDbusmenu.cpp
 
144
+++ firefox-53.0~a2~hg20170302r359591/widget/gtk/nsDbusmenu.cpp
78
145
@@ -0,0 +1,63 @@
79
146
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
80
147
+/* vim:expandtab:shiftwidth=4:tabstop=4:
139
206
+
140
207
+    return NS_OK;
141
208
+}
142
 
Index: firefox-52.0~b9+build2/widget/gtk/nsDbusmenu.h
 
209
Index: firefox-53.0~a2~hg20170302r359591/widget/gtk/nsDbusmenu.h
143
210
===================================================================
144
211
--- /dev/null
145
 
+++ firefox-52.0~b9+build2/widget/gtk/nsDbusmenu.h
146
 
@@ -0,0 +1,99 @@
 
212
+++ firefox-53.0~a2~hg20170302r359591/widget/gtk/nsDbusmenu.h
 
213
@@ -0,0 +1,101 @@
147
214
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
148
215
+/* vim:expandtab:shiftwidth=4:tabstop=4:
149
216
+ */
211
278
+class nsDbusmenuFunctions
212
279
+{
213
280
+public:
 
281
+    nsDbusmenuFunctions() = delete;
 
282
+
214
283
+    static nsresult Init();
215
284
+
216
285
+#define FUNC(name, type, params) \
243
312
+#define dbusmenu_menuitem_property_set_shortcut nsDbusmenuFunctions::s_dbusmenu_menuitem_property_set_shortcut
244
313
+
245
314
+#endif /* __nsDbusmenu_h__ */
246
 
Index: firefox-52.0~b9+build2/widget/gtk/nsMenu.cpp
 
315
Index: firefox-53.0~a2~hg20170302r359591/widget/gtk/nsMenu.cpp
247
316
===================================================================
248
317
--- /dev/null
249
 
+++ firefox-52.0~b9+build2/widget/gtk/nsMenu.cpp
250
 
@@ -0,0 +1,868 @@
 
318
+++ firefox-53.0~a2~hg20170302r359591/widget/gtk/nsMenu.cpp
 
319
@@ -0,0 +1,841 @@
251
320
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
252
321
+/* vim:expandtab:shiftwidth=4:tabstop=4:
253
322
+ */
257
326
+
258
327
+#define _IMPL_NS_LAYOUT
259
328
+
 
329
+#include "mozilla/Assertions.h"
260
330
+#include "mozilla/GuardObjects.h"
261
331
+#include "mozilla/MouseEvents.h"
 
332
+#include "mozilla/Move.h"
262
333
+#include "mozilla/StyleSetHandleInlines.h"
263
334
+#include "nsAutoPtr.h"
264
335
+#include "nsBindingManager.h"
290
361
+
291
362
+using namespace mozilla;
292
363
+
293
 
+class MOZ_STACK_CLASS nsMenuUpdateBatch
294
 
+{
295
 
+public:
296
 
+    nsMenuUpdateBatch(nsMenu *aMenu MOZ_GUARD_OBJECT_NOTIFIER_PARAM) :
297
 
+        mMenu(aMenu)
298
 
+    {
299
 
+        MOZ_GUARD_OBJECT_NOTIFIER_INIT;
300
 
+        mMenu->BeginUpdateBatchInternal();
301
 
+    }
302
 
+
303
 
+    ~nsMenuUpdateBatch()
304
 
+    {
305
 
+        mMenu->EndUpdateBatch();
306
 
+    }
307
 
+
308
 
+private:
309
 
+    MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
310
 
+    nsMenu *mMenu;
311
 
+};
312
 
+
313
 
+class nsSetAttrRunnableNoNotify : public Runnable
314
 
+{
315
 
+public:
316
 
+    nsSetAttrRunnableNoNotify(nsIContent *aContent, nsIAtom *aAttribute,
317
 
+                              nsAString& aValue) :
318
 
+        mContent(aContent), mAttribute(aAttribute), mValue(aValue) { };
319
 
+
320
 
+    NS_IMETHODIMP Run()
321
 
+    {
322
 
+        return mContent->SetAttr(kNameSpaceID_None, mAttribute, mValue, false);
323
 
+    }
324
 
+
325
 
+private:
326
 
+    nsCOMPtr<nsIContent> mContent;
327
 
+    nsCOMPtr<nsIAtom> mAttribute;
328
 
+    nsAutoString mValue;
329
 
+};
330
 
+
331
 
+class nsUnsetAttrRunnableNoNotify : public Runnable
332
 
+{
333
 
+public:
334
 
+    nsUnsetAttrRunnableNoNotify(nsIContent *aContent, nsIAtom *aAttribute) :
335
 
+        mContent(aContent), mAttribute(aAttribute) { };
336
 
+
337
 
+    NS_IMETHODIMP Run()
338
 
+    {
339
 
+        return mContent->UnsetAttr(kNameSpaceID_None, mAttribute, false);
340
 
+    }
341
 
+
342
 
+private:
343
 
+    nsCOMPtr<nsIContent> mContent;
344
 
+    nsCOMPtr<nsIAtom> mAttribute;
345
 
+};
 
364
+class nsMenuContentInsertedEvent : public Runnable
 
365
+{
 
366
+public:
 
367
+    nsMenuContentInsertedEvent(nsMenu *aMenu,
 
368
+                               nsIContent *aContainer,
 
369
+                               nsIContent *aChild,
 
370
+                               nsIContent *aPrevSibling) :
 
371
+        mWeakMenu(aMenu),
 
372
+        mContainer(aContainer),
 
373
+        mChild(aChild),
 
374
+        mPrevSibling(aPrevSibling) { }
 
375
+
 
376
+    NS_IMETHODIMP Run()
 
377
+    {
 
378
+        if (!mWeakMenu) {
 
379
+            return NS_OK;
 
380
+        }
 
381
+
 
382
+        static_cast<nsMenu *>(mWeakMenu.get())->HandleContentInserted(mContainer,
 
383
+                                                                      mChild,
 
384
+                                                                      mPrevSibling);
 
385
+        return NS_OK;
 
386
+    }
 
387
+
 
388
+private:
 
389
+    nsWeakMenuObject mWeakMenu;
 
390
+
 
391
+    nsCOMPtr<nsIContent> mContainer;
 
392
+    nsCOMPtr<nsIContent> mChild;
 
393
+    nsCOMPtr<nsIContent> mPrevSibling;
 
394
+};
 
395
+
 
396
+class nsMenuContentRemovedEvent : public Runnable
 
397
+{
 
398
+public:
 
399
+    nsMenuContentRemovedEvent(nsMenu *aMenu,
 
400
+                              nsIContent *aContainer,
 
401
+                              nsIContent *aChild) :
 
402
+        mWeakMenu(aMenu),
 
403
+        mContainer(aContainer),
 
404
+        mChild(aChild) { }
 
405
+
 
406
+    NS_IMETHODIMP Run()
 
407
+    {
 
408
+        if (!mWeakMenu) {
 
409
+            return NS_OK;
 
410
+        }
 
411
+
 
412
+        static_cast<nsMenu *>(mWeakMenu.get())->HandleContentRemoved(mContainer,
 
413
+                                                                     mChild);
 
414
+        return NS_OK;
 
415
+    }
 
416
+
 
417
+private:
 
418
+    nsWeakMenuObject mWeakMenu;
 
419
+
 
420
+    nsCOMPtr<nsIContent> mContainer;
 
421
+    nsCOMPtr<nsIContent> mChild;
 
422
+};
 
423
+
 
424
+static void
 
425
+DispatchMouseEvent(nsIContent *aTarget, mozilla::EventMessage aMsg)
 
426
+{
 
427
+    if (!aTarget) {
 
428
+        return;
 
429
+    }
 
430
+
 
431
+    WidgetMouseEvent event(true, aMsg, nullptr, WidgetMouseEvent::eReal);
 
432
+    aTarget->DispatchDOMEvent(&event, nullptr, nullptr, nullptr);
 
433
+}
346
434
+
347
435
+static void
348
436
+AttachXBLBindings(nsIContent *aContent)
354
442
+    }
355
443
+
356
444
+    RefPtr<nsStyleContext> sc =
357
 
+        shell->StyleSet()->ResolveStyleFor(aContent->AsElement(),
358
 
+                                           nullptr);
 
445
+        shell->StyleSet()->AsGecko()->ResolveStyleFor(aContent->AsElement(),
 
446
+                                                      nullptr);
359
447
+    if (!sc) {
360
448
+        return;
361
449
+    }
385
473
+void
386
474
+nsMenu::SetPopupState(EPopupState aState)
387
475
+{
388
 
+    ClearFlags(((1U << NSMENU_NUMBER_OF_POPUPSTATE_BITS) - 1U) << NSMENU_NUMBER_OF_FLAGS);
389
 
+    SetFlags(aState << NSMENU_NUMBER_OF_FLAGS);
 
476
+    mPopupState = aState;
390
477
+
391
478
+    if (!mPopupContent) {
392
479
+        return;
407
494
+            break;
408
495
+    }
409
496
+
410
 
+    if (nsContentUtils::IsSafeToRunScript()) {
411
 
+        if (state.IsEmpty()) {
412
 
+            mPopupContent->UnsetAttr(kNameSpaceID_None,
413
 
+                                     nsNativeMenuAtoms::_moz_menupopupstate,
414
 
+                                     false);
415
 
+        } else {
416
 
+            mPopupContent->SetAttr(kNameSpaceID_None,
417
 
+                                   nsNativeMenuAtoms::_moz_menupopupstate,
418
 
+                                   state, false);
419
 
+        }
 
497
+    if (state.IsEmpty()) {
 
498
+        mPopupContent->UnsetAttr(kNameSpaceID_None,
 
499
+                                 nsNativeMenuAtoms::_moz_nativemenupopupstate,
 
500
+                                 false);
420
501
+    } else {
421
 
+        nsCOMPtr<nsIRunnable> r;
422
 
+        if (state.IsEmpty()) {
423
 
+            r = new nsUnsetAttrRunnableNoNotify(
424
 
+                        mPopupContent, nsNativeMenuAtoms::_moz_menupopupstate);
425
 
+        } else {
426
 
+            r = new nsSetAttrRunnableNoNotify(
427
 
+                        mPopupContent, nsNativeMenuAtoms::_moz_menupopupstate,
428
 
+                        state);
429
 
+        }
430
 
+        nsContentUtils::AddScriptRunner(r);
 
502
+        mPopupContent->SetAttr(kNameSpaceID_None,
 
503
+                               nsNativeMenuAtoms::_moz_nativemenupopupstate,
 
504
+                               state, false);
431
505
+    }
432
506
+}
433
507
+
434
508
+/* static */ void
 
509
+nsMenu::DoOpenCallback(nsITimer *aTimer, void *aClosure)
 
510
+{
 
511
+    nsMenu* self = static_cast<nsMenu *>(aClosure);
 
512
+
 
513
+    dbusmenu_menuitem_show_to_user(self->GetNativeData(), 0);
 
514
+
 
515
+    self->mOpenDelayTimer = nullptr;
 
516
+}
 
517
+
 
518
+/* static */ void
435
519
+nsMenu::menu_event_cb(DbusmenuMenuitem *menu,
436
520
+                      const gchar *name,
437
521
+                      GVariant *value,
456
540
+void
457
541
+nsMenu::MaybeAddPlaceholderItem()
458
542
+{
459
 
+    NS_ASSERTION(!IsInUpdateBatch(),
460
 
+                 "Shouldn't be modifying the native menu structure now");
 
543
+    MOZ_ASSERT(!IsInBatchedUpdate(),
 
544
+               "Shouldn't be modifying the native menu structure now");
461
545
+
462
546
+    GList *children = dbusmenu_menuitem_get_children(GetNativeData());
463
547
+    if (!children) {
464
 
+        NS_ASSERTION(!HasPlaceholderItem(), "Huh?");
465
 
+
466
 
+        DbusmenuMenuitem *ph = dbusmenu_menuitem_new();
467
 
+        if (!ph) {
468
 
+            return;
469
 
+        }
470
 
+
471
 
+        dbusmenu_menuitem_property_set_bool(
472
 
+            ph, DBUSMENU_MENUITEM_PROP_VISIBLE, false);
473
 
+
474
 
+        if (!dbusmenu_menuitem_child_append(GetNativeData(), ph)) {
475
 
+            NS_WARNING("Failed to create placeholder item");
476
 
+            g_object_unref(ph);
477
 
+            return;
478
 
+        }
479
 
+
480
 
+        g_object_unref(ph);
481
 
+
482
 
+        SetHasPlaceholderItem(true);
 
548
+        MOZ_ASSERT(!mPlaceholderItem);
 
549
+
 
550
+        mPlaceholderItem = dbusmenu_menuitem_new();
 
551
+        if (!mPlaceholderItem) {
 
552
+            return;
 
553
+        }
 
554
+
 
555
+        dbusmenu_menuitem_property_set_bool(mPlaceholderItem,
 
556
+                                            DBUSMENU_MENUITEM_PROP_VISIBLE,
 
557
+                                            false);
 
558
+
 
559
+        MOZ_ALWAYS_TRUE(
 
560
+            dbusmenu_menuitem_child_append(GetNativeData(), mPlaceholderItem));
483
561
+    }
484
562
+}
485
563
+
486
 
+bool
 
564
+void
487
565
+nsMenu::EnsureNoPlaceholderItem()
488
566
+{
489
 
+    NS_ASSERTION(!IsInUpdateBatch(),
490
 
+                 "Shouldn't be modifying the native menu structure now");
491
 
+
492
 
+    if (HasPlaceholderItem()) {
493
 
+        GList *children = dbusmenu_menuitem_get_children(GetNativeData());
494
 
+
495
 
+        NS_ASSERTION(g_list_length(children) == 1,
496
 
+                     "Unexpected number of children in native menu (should be 1!)");
497
 
+
498
 
+        SetHasPlaceholderItem(false);
499
 
+
500
 
+        if (!children) {
501
 
+            return true;
502
 
+        }
503
 
+
504
 
+        if (!dbusmenu_menuitem_child_delete(
505
 
+                GetNativeData(), static_cast<DbusmenuMenuitem *>(children->data))) {
506
 
+            NS_ERROR("Failed to remove placeholder item");
507
 
+            return false;
508
 
+        }
509
 
+    }
510
 
+
511
 
+    return true;
512
 
+}
513
 
+
514
 
+static void
515
 
+DispatchMouseEvent(nsIContent *aTarget, mozilla::EventMessage aMsg)
516
 
+{
517
 
+    if (!aTarget) {
 
567
+    MOZ_ASSERT(!IsInBatchedUpdate(),
 
568
+               "Shouldn't be modifying the native menu structure now");
 
569
+
 
570
+    if (!mPlaceholderItem) {
518
571
+        return;
519
572
+    }
520
573
+
521
 
+    WidgetMouseEvent event(true, aMsg, nullptr, WidgetMouseEvent::eReal);
522
 
+    aTarget->DispatchDOMEvent(&event, nullptr, nullptr, nullptr);
 
574
+    MOZ_ALWAYS_TRUE(
 
575
+        dbusmenu_menuitem_child_delete(GetNativeData(), mPlaceholderItem));
 
576
+    MOZ_ASSERT(!dbusmenu_menuitem_get_children(GetNativeData()));
 
577
+
 
578
+    g_object_unref(mPlaceholderItem);
 
579
+    mPlaceholderItem = nullptr;
523
580
+}
524
581
+
525
582
+void
526
583
+nsMenu::OnOpen()
527
584
+{
528
 
+    if (NeedsRebuild()) {
 
585
+    if (mNeedsRebuild) {
529
586
+        Build();
530
587
+    }
531
588
+
532
 
+    nsWeakMenuObject<nsMenu> self(this);
 
589
+    nsWeakMenuObject self(this);
533
590
+    nsCOMPtr<nsIContent> origPopupContent(mPopupContent);
534
591
+    {
535
 
+        nsNativeMenuAutoUpdateBatch batch;
 
592
+        nsNativeMenuDocListener::BlockUpdatesScope updatesBlocker;
536
593
+
537
594
+        SetPopupState(ePopupState_Showing);
538
595
+        DispatchMouseEvent(mPopupContent, eXULPopupShowing);
551
608
+        return;
552
609
+    }
553
610
+
554
 
+    nsNativeMenuAutoUpdateBatch batch;
 
611
+    nsNativeMenuDocListener::BlockUpdatesScope updatesBlocker;
555
612
+
556
613
+    size_t count = ChildCount();
557
614
+    for (size_t i = 0; i < count; ++i) {
565
622
+void
566
623
+nsMenu::Build()
567
624
+{
568
 
+    nsMenuUpdateBatch batch(this);
569
 
+
570
 
+    SetNeedsRebuild(false);
 
625
+    mNeedsRebuild = false;
571
626
+
572
627
+    while (ChildCount() > 0) {
573
628
+        RemoveChildAt(0);
583
638
+    for (uint32_t i = 0; i < count; ++i) {
584
639
+        nsIContent *childContent = mPopupContent->GetChildAt(i);
585
640
+
586
 
+        nsresult rv;
587
 
+        nsMenuObject *child = CreateChild(childContent, &rv);
588
 
+
589
 
+        if (child) {
590
 
+            rv = AppendChild(child);
591
 
+        }
592
 
+
593
 
+        if (NS_FAILED(rv)) {
594
 
+            NS_ERROR("Menu build failed");
595
 
+            SetNeedsRebuild(true);
596
 
+            return;
597
 
+        }
 
641
+        UniquePtr<nsMenuObject> child = CreateChild(childContent);
 
642
+
 
643
+        if (!child) {
 
644
+            continue;
 
645
+        }
 
646
+
 
647
+        AppendChild(Move(child));
598
648
+    }
599
649
+}
600
650
+
601
651
+void
602
 
+nsMenu::InitializeNativeData()
603
 
+{
604
 
+    // Dbusmenu provides an "about-to-show" signal, and also "opened" and
605
 
+    // "closed" events. However, Unity is the only thing that sends
606
 
+    // both "about-to-show" and "opened" events. Unity 2D and the HUD only
607
 
+    // send "opened" events, so we ignore "about-to-show" (I don't think
608
 
+    // there's any real difference between them anyway).
609
 
+    // To complicate things, there are certain conditions where we don't
610
 
+    // get a "closed" event, so we need to be able to handle this :/
611
 
+    g_signal_connect(G_OBJECT(GetNativeData()), "event",
612
 
+                     G_CALLBACK(menu_event_cb), this);
613
 
+
614
 
+    UpdateLabel();
615
 
+    UpdateSensitivity();
616
 
+
617
 
+    SetNeedsRebuild(true);
618
 
+    MaybeAddPlaceholderItem();
619
 
+
620
 
+    AttachXBLBindings(ContentNode());
621
 
+}
622
 
+
623
 
+void
624
 
+nsMenu::Update(nsStyleContext *aStyleContext)
625
 
+{
626
 
+    UpdateVisibility(aStyleContext);
627
 
+    UpdateIcon(aStyleContext);
628
 
+}
629
 
+
630
 
+void
631
652
+nsMenu::InitializePopup()
632
653
+{
633
654
+    nsCOMPtr<nsIContent> oldPopupContent;
666
687
+}
667
688
+
668
689
+void
669
 
+nsMenu::BeginUpdateBatchInternal()
670
 
+{
671
 
+    NS_ASSERTION(!IsInUpdateBatch(), "Already in an update batch!");
672
 
+
673
 
+    SetIsInUpdateBatch(true);
674
 
+    SetDidStructureMutate(false);
675
 
+}
676
 
+
677
 
+nsresult
678
690
+nsMenu::RemoveChildAt(size_t aIndex)
679
691
+{
680
 
+    NS_ASSERTION(IsInUpdateBatch() || !HasPlaceholderItem(),
681
 
+                 "Shouldn't have a placeholder menuitem");
682
 
+
683
 
+    SetDidStructureMutate(true);
684
 
+
685
 
+    nsresult rv = nsMenuContainer::RemoveChildAt(aIndex, !IsInUpdateBatch());
686
 
+
687
 
+    if (!IsInUpdateBatch()) {
 
692
+    MOZ_ASSERT(IsInBatchedUpdate() || !mPlaceholderItem,
 
693
+               "Shouldn't have a placeholder menuitem");
 
694
+
 
695
+    nsMenuContainer::RemoveChildAt(aIndex, !IsInBatchedUpdate());
 
696
+    StructureMutated();
 
697
+
 
698
+    if (!IsInBatchedUpdate()) {
688
699
+        MaybeAddPlaceholderItem();
689
700
+    }
690
 
+
691
 
+    return rv;
692
701
+}
693
702
+
694
 
+nsresult
 
703
+void
695
704
+nsMenu::RemoveChild(nsIContent *aChild)
696
705
+{
697
706
+    size_t index = IndexOf(aChild);
698
707
+    if (index == NoIndex) {
699
 
+        return NS_ERROR_INVALID_ARG;
700
 
+    }
701
 
+
702
 
+    return RemoveChildAt(index);
703
 
+}
704
 
+
705
 
+nsresult
706
 
+nsMenu::InsertChildAfter(nsMenuObject *aChild, nsIContent *aPrevSibling)
707
 
+{
708
 
+    if (!IsInUpdateBatch() && !EnsureNoPlaceholderItem()) {
709
 
+        return NS_ERROR_FAILURE;
710
 
+    }
711
 
+
712
 
+    SetDidStructureMutate(true);
713
 
+
714
 
+    return nsMenuContainer::InsertChildAfter(aChild, aPrevSibling,
715
 
+                                             !IsInUpdateBatch());
716
 
+}
717
 
+
718
 
+nsresult
719
 
+nsMenu::AppendChild(nsMenuObject *aChild)
720
 
+{
721
 
+    if (!IsInUpdateBatch() && !EnsureNoPlaceholderItem()) {
722
 
+        return NS_ERROR_FAILURE;
723
 
+    }
724
 
+
725
 
+    SetDidStructureMutate(true);
726
 
+
727
 
+    return nsMenuContainer::AppendChild(aChild, !IsInUpdateBatch());
 
708
+        return;
 
709
+    }
 
710
+
 
711
+    RemoveChildAt(index);
 
712
+}
 
713
+
 
714
+void
 
715
+nsMenu::InsertChildAfter(UniquePtr<nsMenuObject> aChild,
 
716
+                         nsIContent *aPrevSibling)
 
717
+{
 
718
+    if (!IsInBatchedUpdate()) {
 
719
+        EnsureNoPlaceholderItem();
 
720
+    }
 
721
+
 
722
+    nsMenuContainer::InsertChildAfter(Move(aChild), aPrevSibling,
 
723
+                                      !IsInBatchedUpdate());
 
724
+    StructureMutated();
 
725
+}
 
726
+
 
727
+void
 
728
+nsMenu::AppendChild(UniquePtr<nsMenuObject> aChild)
 
729
+{
 
730
+    if (!IsInBatchedUpdate()) {
 
731
+        EnsureNoPlaceholderItem();
 
732
+    }
 
733
+
 
734
+    nsMenuContainer::AppendChild(Move(aChild), !IsInBatchedUpdate());
 
735
+    StructureMutated();
 
736
+}
 
737
+
 
738
+bool 
 
739
+nsMenu::IsInBatchedUpdate() const
 
740
+{
 
741
+    return mBatchedUpdateState != eBatchedUpdateState_Inactive;
 
742
+}
 
743
+
 
744
+void
 
745
+nsMenu::StructureMutated()
 
746
+{
 
747
+    if (!IsInBatchedUpdate()) {
 
748
+        return;
 
749
+    }
 
750
+
 
751
+    mBatchedUpdateState = eBatchedUpdateState_DidMutate;
728
752
+}
729
753
+
730
754
+bool
740
764
+    return (isVisible && !isDisabled);
741
765
+}
742
766
+
 
767
+void
 
768
+nsMenu::HandleContentInserted(nsIContent *aContainer,
 
769
+                              nsIContent *aChild,
 
770
+                              nsIContent *aPrevSibling)
 
771
+{
 
772
+    if (aContainer == mPopupContent) {
 
773
+        UniquePtr<nsMenuObject> child = CreateChild(aChild);
 
774
+
 
775
+        if (child) {
 
776
+            InsertChildAfter(Move(child), aPrevSibling);
 
777
+        }
 
778
+    } else {
 
779
+        Build();
 
780
+    }
 
781
+}
 
782
+
 
783
+void
 
784
+nsMenu::HandleContentRemoved(nsIContent *aContainer, nsIContent *aChild)
 
785
+{
 
786
+    if (aContainer == mPopupContent) {
 
787
+        RemoveChild(aChild);
 
788
+    } else {
 
789
+        Build();
 
790
+    }
 
791
+}
 
792
+
 
793
+void
 
794
+nsMenu::InitializeNativeData()
 
795
+{
 
796
+    // Dbusmenu provides an "about-to-show" signal, and also "opened" and
 
797
+    // "closed" events. However, Unity is the only thing that sends
 
798
+    // both "about-to-show" and "opened" events. Unity 2D and the HUD only
 
799
+    // send "opened" events, so we ignore "about-to-show" (I don't think
 
800
+    // there's any real difference between them anyway).
 
801
+    // To complicate things, there are certain conditions where we don't
 
802
+    // get a "closed" event, so we need to be able to handle this :/
 
803
+    g_signal_connect(G_OBJECT(GetNativeData()), "event",
 
804
+                     G_CALLBACK(menu_event_cb), this);
 
805
+
 
806
+    mNeedsRebuild = true;
 
807
+    mNeedsUpdate = true;
 
808
+
 
809
+    MaybeAddPlaceholderItem();
 
810
+
 
811
+    AttachXBLBindings(ContentNode());
 
812
+}
 
813
+
 
814
+void
 
815
+nsMenu::Update(nsStyleContext *aStyleContext)
 
816
+{
 
817
+    if (mNeedsUpdate) {
 
818
+        mNeedsUpdate = false;
 
819
+
 
820
+        UpdateLabel();
 
821
+        UpdateSensitivity();
 
822
+    }
 
823
+
 
824
+    UpdateVisibility(aStyleContext);
 
825
+    UpdateIcon(aStyleContext);
 
826
+}
 
827
+
743
828
+nsMenuObject::PropertyFlags
744
829
+nsMenu::SupportedProperties() const
745
830
+{
752
837
+    );
753
838
+}
754
839
+
755
 
+nsMenu::nsMenu() :
756
 
+    nsMenuContainer()
757
 
+{
758
 
+    MOZ_COUNT_CTOR(nsMenu);
759
 
+}
760
 
+
761
 
+nsMenu::~nsMenu()
762
 
+{
763
 
+    if (IsInUpdateBatch()) {
764
 
+        EndUpdateBatch();
765
 
+    }
766
 
+
767
 
+    // Although nsTArray will take care of this in its destructor,
768
 
+    // we have to manually ensure children are removed from our native menu
769
 
+    // item, just in case our parent recycles us
770
 
+    while (ChildCount() > 0) {
771
 
+        RemoveChildAt(0);
772
 
+    }
773
 
+
774
 
+    EnsureNoPlaceholderItem();
775
 
+
776
 
+    if (DocListener() && mPopupContent) {
777
 
+        DocListener()->UnregisterForContentChanges(mPopupContent);
778
 
+    }
779
 
+
780
 
+    if (GetNativeData()) {
781
 
+        g_signal_handlers_disconnect_by_func(GetNativeData(),
782
 
+                                             FuncToGpointer(menu_event_cb),
783
 
+                                             this);
784
 
+    }
785
 
+
786
 
+    MOZ_COUNT_DTOR(nsMenu);
787
 
+}
788
 
+
789
 
+/* static */ nsMenuObject*
790
 
+nsMenu::Create(nsMenuContainer *aParent, nsIContent *aContent)
791
 
+{
792
 
+    nsAutoPtr<nsMenu> menu(new nsMenu());
793
 
+    if (NS_FAILED(menu->Init(aParent, aContent))) {
794
 
+        return nullptr;
795
 
+    }
796
 
+
797
 
+    return menu.forget();
798
 
+}
799
 
+
800
 
+static void
801
 
+DoOpen(nsITimer *aTimer, void *aClosure)
802
 
+{
803
 
+    nsAutoWeakMenuObject<nsMenu> weakMenu(
804
 
+        static_cast<nsWeakMenuObject<nsMenu> *>(aClosure));
805
 
+
806
 
+    if (weakMenu) {
807
 
+        dbusmenu_menuitem_show_to_user(weakMenu->GetNativeData(), 0);
808
 
+    }
809
 
+
810
 
+    NS_RELEASE(aTimer);
811
 
+}
812
 
+
813
 
+nsMenuObject::EType
814
 
+nsMenu::Type() const
815
 
+{
816
 
+    return nsMenuObject::eType_Menu;
817
 
+}
818
 
+
819
 
+bool
820
 
+nsMenu::IsBeingDisplayed() const
821
 
+{
822
 
+    return PopupState() == ePopupState_Open;
823
 
+}
824
 
+
825
 
+bool
826
 
+nsMenu::NeedsRebuild() const
827
 
+{
828
 
+    return HasFlags(eFlag_NeedsRebuild);
829
 
+}
830
 
+
831
 
+void
832
 
+nsMenu::OpenMenu()
833
 
+{
834
 
+    if (!CanOpen()) {
835
 
+        return;
836
 
+    }
837
 
+
838
 
+    // Here, we synchronously fire popupshowing and popupshown events and then
839
 
+    // open the menu after a short delay. This allows the menu to refresh before
840
 
+    // it's shown, and avoids an issue where keyboard focus is not on the first
841
 
+    // item of the history menu in Firefox when opening it with the keyboard,
842
 
+    // because extra items to appear at the top of the menu
843
 
+
844
 
+    OnOpen();
845
 
+
846
 
+    nsCOMPtr<nsITimer> timer = do_CreateInstance(NS_TIMER_CONTRACTID);
847
 
+    if (!timer) {
848
 
+        return;
849
 
+    }
850
 
+
851
 
+    nsAutoWeakMenuObject<nsMenu> weakMenu(this);
852
 
+
853
 
+    if (NS_FAILED(timer->InitWithFuncCallback(DoOpen, weakMenu.getWeakPtr(),
854
 
+                                              100, nsITimer::TYPE_ONE_SHOT))) {
855
 
+        return;
856
 
+    }
857
 
+
858
 
+    timer.forget();
859
 
+    weakMenu.forget();
860
 
+}
861
 
+
862
 
+void
863
 
+nsMenu::OnClose()
864
 
+{
865
 
+    if (PopupState() == ePopupState_Closed) {
866
 
+        return;
867
 
+    }
868
 
+
869
 
+    // We do this to avoid mutating our view of the menu until
870
 
+    // after we have finished
871
 
+    nsNativeMenuAutoUpdateBatch batch;
872
 
+
873
 
+    SetPopupState(ePopupState_Hiding);
874
 
+    DispatchMouseEvent(mPopupContent, eXULPopupHiding);
875
 
+
876
 
+    // Sigh, make sure all of our descendants are closed, as we don't
877
 
+    // always get closed events for submenus when scrubbing quickly through
878
 
+    // the menu
879
 
+    size_t count = ChildCount();
880
 
+    for (size_t i = 0; i < count; ++i) {
881
 
+        if (ChildAt(i)->Type() == nsMenuObject::eType_Menu) {
882
 
+            static_cast<nsMenu *>(ChildAt(i))->OnClose();
883
 
+        }
884
 
+    }
885
 
+
886
 
+    SetPopupState(ePopupState_Closed);
887
 
+    DispatchMouseEvent(mPopupContent, eXULPopupHidden);
888
 
+
889
 
+    ContentNode()->UnsetAttr(kNameSpaceID_None, nsGkAtoms::open, true);
890
 
+}
891
 
+
892
840
+void
893
841
+nsMenu::OnAttributeChanged(nsIContent *aContent, nsIAtom *aAttribute)
894
842
+{
895
 
+    NS_ASSERTION(aContent == ContentNode() || aContent == mPopupContent,
896
 
+                 "Received an event that wasn't meant for us!");
897
 
+
898
 
+    if (aAttribute == nsGkAtoms::open) {
899
 
+        return;
900
 
+    }
901
 
+
902
 
+    if (Parent()->NeedsRebuild()) {
903
 
+        return;
904
 
+    }
905
 
+
906
 
+    if (aContent == ContentNode()) {
907
 
+        if (aAttribute == nsGkAtoms::disabled) {
908
 
+            UpdateSensitivity();
909
 
+        } else if (aAttribute == nsGkAtoms::label || 
910
 
+                   aAttribute == nsGkAtoms::accesskey ||
911
 
+                   aAttribute == nsGkAtoms::crop) {
912
 
+            UpdateLabel();
913
 
+        }
914
 
+    }
915
 
+
916
 
+    if (!Parent()->IsBeingDisplayed() || aContent != ContentNode()) {
917
 
+        return;
918
 
+    }
919
 
+
920
 
+    if (aAttribute == nsGkAtoms::hidden ||
 
843
+    MOZ_ASSERT(aContent == ContentNode() || aContent == mPopupContent,
 
844
+               "Received an event that wasn't meant for us!");
 
845
+
 
846
+    if (mNeedsUpdate) {
 
847
+        return;
 
848
+    }
 
849
+
 
850
+    if (aContent != ContentNode()) {
 
851
+        return;
 
852
+    }
 
853
+
 
854
+    if (!Parent()->IsBeingDisplayed()) {
 
855
+        mNeedsUpdate = true;
 
856
+        return;
 
857
+    }
 
858
+
 
859
+    if (aAttribute == nsGkAtoms::disabled) {
 
860
+        UpdateSensitivity();
 
861
+    } else if (aAttribute == nsGkAtoms::label || 
 
862
+               aAttribute == nsGkAtoms::accesskey ||
 
863
+               aAttribute == nsGkAtoms::crop) {
 
864
+        UpdateLabel();
 
865
+    } else if (aAttribute == nsGkAtoms::hidden ||
921
866
+        aAttribute == nsGkAtoms::collapsed) {
922
867
+        RefPtr<nsStyleContext> sc = GetStyleContext();
923
868
+        UpdateVisibility(sc);
931
876
+nsMenu::OnContentInserted(nsIContent *aContainer, nsIContent *aChild,
932
877
+                          nsIContent *aPrevSibling)
933
878
+{
934
 
+    NS_ASSERTION(aContainer == ContentNode() || aContainer == mPopupContent,
935
 
+                 "Received an event that wasn't meant for us!");
936
 
+
937
 
+    if (NeedsRebuild()) {
938
 
+        return;
939
 
+    }
940
 
+
941
 
+    if (PopupState() == ePopupState_Closed) {
942
 
+        SetNeedsRebuild(true);
943
 
+        return;
944
 
+    }
945
 
+
946
 
+    if (aContainer == mPopupContent) {
947
 
+        nsresult rv;
948
 
+        nsMenuObject *child = CreateChild(aChild, &rv);
949
 
+
950
 
+        if (child) {
951
 
+            rv = InsertChildAfter(child, aPrevSibling);
952
 
+        }
953
 
+        if (NS_FAILED(rv)) {
954
 
+            NS_ERROR("OnContentInserted() failed");
955
 
+            SetNeedsRebuild(true);
956
 
+        }
957
 
+    } else {
958
 
+        Build();
959
 
+    }
 
879
+    MOZ_ASSERT(aContainer == ContentNode() || aContainer == mPopupContent,
 
880
+               "Received an event that wasn't meant for us!");
 
881
+
 
882
+    if (mNeedsRebuild) {
 
883
+        return;
 
884
+    }
 
885
+
 
886
+    if (mPopupState == ePopupState_Closed) {
 
887
+        mNeedsRebuild = true;
 
888
+        return;
 
889
+    }
 
890
+
 
891
+    nsContentUtils::AddScriptRunner(
 
892
+        new nsMenuContentInsertedEvent(this, aContainer, aChild,
 
893
+                                       aPrevSibling));
960
894
+}
961
895
+
962
896
+void
963
897
+nsMenu::OnContentRemoved(nsIContent *aContainer, nsIContent *aChild)
964
898
+{
965
 
+    NS_ASSERTION(aContainer == ContentNode() || aContainer == mPopupContent,
966
 
+                 "Received an event that wasn't meant for us!");
967
 
+
968
 
+    if (NeedsRebuild()) {
969
 
+        return;
970
 
+    }
971
 
+
972
 
+    if (PopupState() == ePopupState_Closed) {
973
 
+        SetNeedsRebuild(true);
974
 
+        return;
975
 
+    }
976
 
+
977
 
+    if (aContainer == mPopupContent) {
978
 
+        if (NS_FAILED(RemoveChild(aChild))) {
979
 
+            NS_ERROR("OnContentRemoved() failed");
980
 
+            SetNeedsRebuild(true);
981
 
+        }
982
 
+    } else {
983
 
+        Build();
984
 
+    }
 
899
+    MOZ_ASSERT(aContainer == ContentNode() || aContainer == mPopupContent,
 
900
+               "Received an event that wasn't meant for us!");
 
901
+
 
902
+    if (mNeedsRebuild) {
 
903
+        return;
 
904
+    }
 
905
+
 
906
+    if (mPopupState == ePopupState_Closed) {
 
907
+        mNeedsRebuild = true;
 
908
+        return;
 
909
+    }
 
910
+
 
911
+    nsContentUtils::AddScriptRunner(
 
912
+        new nsMenuContentRemovedEvent(this, aContainer, aChild));
985
913
+}
986
914
+
987
915
+/*
998
926
+ */
999
927
+
1000
928
+void
1001
 
+nsMenu::BeginUpdateBatch(nsIContent *aContent)
 
929
+nsMenu::OnBeginUpdates(nsIContent *aContent)
1002
930
+{
1003
 
+    NS_ASSERTION(aContent == ContentNode() || aContent == mPopupContent,
1004
 
+                 "Received an event that wasn't meant for us!");
 
931
+    MOZ_ASSERT(aContent == ContentNode() || aContent == mPopupContent,
 
932
+               "Received an event that wasn't meant for us!");
 
933
+    MOZ_ASSERT(!IsInBatchedUpdate(), "Already in an update batch!");
1005
934
+
1006
 
+    if (aContent == mPopupContent) {
1007
 
+        BeginUpdateBatchInternal();
 
935
+    if (aContent != mPopupContent) {
 
936
+        return;
1008
937
+    }
 
938
+
 
939
+    mBatchedUpdateState = eBatchedUpdateState_Active;
1009
940
+}
1010
941
+
1011
942
+void
1012
 
+nsMenu::EndUpdateBatch()
 
943
+nsMenu::OnEndUpdates()
1013
944
+{
1014
 
+    NS_ASSERTION(IsInUpdateBatch(), "Not in an update batch");
 
945
+    if (!IsInBatchedUpdate()) {
 
946
+        return;
 
947
+    }
1015
948
+
1016
 
+    SetIsInUpdateBatch(false);
 
949
+    bool didMutate = mBatchedUpdateState == eBatchedUpdateState_DidMutate;
 
950
+    mBatchedUpdateState = eBatchedUpdateState_Inactive;
1017
951
+
1018
952
+    /* Optimize for the case where we only had attribute changes */
1019
 
+    if (!DidStructureMutate()) {
 
953
+    if (!didMutate) {
1020
954
+        return;
1021
955
+    }
1022
956
+
1023
 
+    if (!EnsureNoPlaceholderItem()) {
1024
 
+        SetNeedsRebuild(true);
1025
 
+        return;
1026
 
+    }
 
957
+    EnsureNoPlaceholderItem();
1027
958
+
1028
959
+    GList *nextNativeChild = dbusmenu_menuitem_get_children(GetNativeData());
1029
960
+    DbusmenuMenuitem *nextOwnedNativeChild = nullptr;
1054
985
+                    static_cast<DbusmenuMenuitem *>(nextNativeChild->data);
1055
986
+                nextNativeChild = nextNativeChild->next;
1056
987
+
1057
 
+                if (!dbusmenu_menuitem_child_delete(GetNativeData(), data)) {
1058
 
+                    NS_ERROR("Failed to remove orphaned native item from menu");
1059
 
+                    SetNeedsRebuild(true);
1060
 
+                    return;
1061
 
+                }
 
988
+                MOZ_ALWAYS_TRUE(dbusmenu_menuitem_child_delete(GetNativeData(),
 
989
+                                                               data));
1062
990
+            }
1063
991
+
1064
992
+            if (nextNativeChild) {
1090
1018
+            // At this point, we modify the native menu structure.
1091
1019
+            if (!child->GetNativeData()) {
1092
1020
+                child->CreateNativeData();
1093
 
+                if (!dbusmenu_menuitem_child_add_position(GetNativeData(),
1094
 
+                                                          child->GetNativeData(),
1095
 
+                                                          i)) {
1096
 
+                    NS_ERROR("Failed to add new native item");
1097
 
+                    SetNeedsRebuild(true);
1098
 
+                    return;
1099
 
+                }
 
1021
+                MOZ_ALWAYS_TRUE(
 
1022
+                    dbusmenu_menuitem_child_add_position(GetNativeData(),
 
1023
+                                                         child->GetNativeData(),
 
1024
+                                                         i));
1100
1025
+            }
1101
1026
+        }
1102
1027
+    }
1103
1028
+
1104
1029
+    while (nextNativeChild) {
1105
 
+
1106
1030
+        DbusmenuMenuitem *data =
1107
1031
+            static_cast<DbusmenuMenuitem *>(nextNativeChild->data);
1108
1032
+        nextNativeChild = nextNativeChild->next;
1109
1033
+
1110
 
+        if (!dbusmenu_menuitem_child_delete(GetNativeData(), data)) {
1111
 
+            NS_ERROR("Failed to remove orphaned native item from menu");
1112
 
+            SetNeedsRebuild(true);
1113
 
+            return;
 
1034
+        MOZ_ALWAYS_TRUE(dbusmenu_menuitem_child_delete(GetNativeData(), data));
 
1035
+    }
 
1036
+
 
1037
+    MaybeAddPlaceholderItem();
 
1038
+}
 
1039
+
 
1040
+nsMenu::nsMenu(nsMenuContainer *aParent, nsIContent *aContent) :
 
1041
+    nsMenuContainer(aParent, aContent),
 
1042
+    mNeedsRebuild(false),
 
1043
+    mNeedsUpdate(false),
 
1044
+    mPlaceholderItem(nullptr),
 
1045
+    mPopupState(ePopupState_Closed),
 
1046
+    mBatchedUpdateState(eBatchedUpdateState_Inactive)
 
1047
+{
 
1048
+    MOZ_COUNT_CTOR(nsMenu);
 
1049
+}
 
1050
+
 
1051
+nsMenu::~nsMenu()
 
1052
+{
 
1053
+    if (IsInBatchedUpdate()) {
 
1054
+        OnEndUpdates();
 
1055
+    }
 
1056
+
 
1057
+    // Although nsTArray will take care of this in its destructor,
 
1058
+    // we have to manually ensure children are removed from our native menu
 
1059
+    // item, just in case our parent recycles us
 
1060
+    while (ChildCount() > 0) {
 
1061
+        RemoveChildAt(0);
 
1062
+    }
 
1063
+
 
1064
+    EnsureNoPlaceholderItem();
 
1065
+
 
1066
+    if (DocListener() && mPopupContent) {
 
1067
+        DocListener()->UnregisterForContentChanges(mPopupContent);
 
1068
+    }
 
1069
+
 
1070
+    if (GetNativeData()) {
 
1071
+        g_signal_handlers_disconnect_by_func(GetNativeData(),
 
1072
+                                             FuncToGpointer(menu_event_cb),
 
1073
+                                             this);
 
1074
+    }
 
1075
+
 
1076
+    MOZ_COUNT_DTOR(nsMenu);
 
1077
+}
 
1078
+
 
1079
+nsMenuObject::EType
 
1080
+nsMenu::Type() const
 
1081
+{
 
1082
+    return eType_Menu;
 
1083
+}
 
1084
+
 
1085
+bool
 
1086
+nsMenu::IsBeingDisplayed() const
 
1087
+{
 
1088
+    return mPopupState == ePopupState_Open;
 
1089
+}
 
1090
+
 
1091
+bool
 
1092
+nsMenu::NeedsRebuild() const
 
1093
+{
 
1094
+    return mNeedsRebuild;
 
1095
+}
 
1096
+
 
1097
+void
 
1098
+nsMenu::OpenMenu()
 
1099
+{
 
1100
+    if (!CanOpen()) {
 
1101
+        return;
 
1102
+    }
 
1103
+
 
1104
+    if (mOpenDelayTimer) {
 
1105
+        return;
 
1106
+    }
 
1107
+
 
1108
+    // Here, we synchronously fire popupshowing and popupshown events and then
 
1109
+    // open the menu after a short delay. This allows the menu to refresh before
 
1110
+    // it's shown, and avoids an issue where keyboard focus is not on the first
 
1111
+    // item of the history menu in Firefox when opening it with the keyboard,
 
1112
+    // because extra items to appear at the top of the menu
 
1113
+
 
1114
+    OnOpen();
 
1115
+
 
1116
+    mOpenDelayTimer = do_CreateInstance(NS_TIMER_CONTRACTID);
 
1117
+    if (!mOpenDelayTimer) {
 
1118
+        return;
 
1119
+    }
 
1120
+
 
1121
+    if (NS_FAILED(mOpenDelayTimer->InitWithFuncCallback(DoOpenCallback,
 
1122
+                                                        this,
 
1123
+                                                        100,
 
1124
+                                                        nsITimer::TYPE_ONE_SHOT))) {
 
1125
+        mOpenDelayTimer = nullptr;
 
1126
+    }
 
1127
+}
 
1128
+
 
1129
+void
 
1130
+nsMenu::OnClose()
 
1131
+{
 
1132
+    if (mPopupState == ePopupState_Closed) {
 
1133
+        return;
 
1134
+    }
 
1135
+
 
1136
+    MOZ_ASSERT(nsContentUtils::IsSafeToRunScript());
 
1137
+
 
1138
+    // We do this to avoid mutating our view of the menu until
 
1139
+    // after we have finished
 
1140
+    nsNativeMenuDocListener::BlockUpdatesScope updatesBlocker;
 
1141
+
 
1142
+    SetPopupState(ePopupState_Hiding);
 
1143
+    DispatchMouseEvent(mPopupContent, eXULPopupHiding);
 
1144
+
 
1145
+    // Sigh, make sure all of our descendants are closed, as we don't
 
1146
+    // always get closed events for submenus when scrubbing quickly through
 
1147
+    // the menu
 
1148
+    size_t count = ChildCount();
 
1149
+    for (size_t i = 0; i < count; ++i) {
 
1150
+        if (ChildAt(i)->Type() == nsMenuObject::eType_Menu) {
 
1151
+            static_cast<nsMenu *>(ChildAt(i))->OnClose();
1114
1152
+        }
1115
1153
+    }
1116
1154
+
1117
 
+    MaybeAddPlaceholderItem();
 
1155
+    SetPopupState(ePopupState_Closed);
 
1156
+    DispatchMouseEvent(mPopupContent, eXULPopupHidden);
 
1157
+
 
1158
+    ContentNode()->UnsetAttr(kNameSpaceID_None, nsGkAtoms::open, true);
1118
1159
+}
1119
 
Index: firefox-52.0~b9+build2/widget/gtk/nsMenu.h
 
1160
+
 
1161
Index: firefox-53.0~a2~hg20170302r359591/widget/gtk/nsMenu.h
1120
1162
===================================================================
1121
1163
--- /dev/null
1122
 
+++ firefox-52.0~b9+build2/widget/gtk/nsMenu.h
1123
 
@@ -0,0 +1,166 @@
 
1164
+++ firefox-53.0~a2~hg20170302r359591/widget/gtk/nsMenu.h
 
1165
@@ -0,0 +1,124 @@
1124
1166
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
1125
1167
+/* vim:expandtab:shiftwidth=4:tabstop=4:
1126
1168
+ */
1132
1174
+#define __nsMenu_h__
1133
1175
+
1134
1176
+#include "mozilla/Attributes.h"
 
1177
+#include "mozilla/UniquePtr.h"
1135
1178
+#include "nsCOMPtr.h"
1136
1179
+
1137
1180
+#include "nsDbusmenu.h"
1142
1185
+
1143
1186
+class nsIAtom;
1144
1187
+class nsIContent;
 
1188
+class nsITimer;
1145
1189
+class nsStyleContext;
1146
1190
+
1147
1191
+#define NSMENU_NUMBER_OF_POPUPSTATE_BITS 2U
1151
1195
+class nsMenu final : public nsMenuContainer
1152
1196
+{
1153
1197
+public:
 
1198
+    nsMenu(nsMenuContainer *aParent, nsIContent *aContent);
1154
1199
+    ~nsMenu();
1155
1200
+
1156
 
+    static nsMenuObject* Create(nsMenuContainer *aParent,
1157
 
+                                nsIContent *aContent);
1158
 
+
1159
 
+    nsMenuObject::EType Type() const;
1160
 
+
1161
 
+    bool IsBeingDisplayed() const;
1162
 
+    bool NeedsRebuild() const;
 
1201
+    nsMenuObject::EType Type() const override;
 
1202
+
 
1203
+    bool IsBeingDisplayed() const override;
 
1204
+    bool NeedsRebuild() const override;
1163
1205
+
1164
1206
+    // Tell the desktop shell to display this menu
1165
1207
+    void OpenMenu();
1168
1210
+    // menuitems can do the shells work. Sigh....
1169
1211
+    void OnClose();
1170
1212
+
1171
 
+    void OnAttributeChanged(nsIContent *aContent, nsIAtom *aAttribute);
1172
 
+    void OnContentInserted(nsIContent *aContainer, nsIContent *aChild,
1173
 
+                           nsIContent *aPrevSibling);
1174
 
+    void OnContentRemoved(nsIContent *aContainer, nsIContent *aChild);
1175
 
+    void BeginUpdateBatch(nsIContent *aContent);
1176
 
+    void EndUpdateBatch();
1177
 
+
1178
1213
+private:
1179
 
+    friend class nsMenuUpdateBatch;
1180
 
+
1181
 
+    enum {
1182
 
+        // This menu needs rebuilding the next time it is opened
1183
 
+        eFlag_NeedsRebuild = 1 << 0,
1184
 
+
1185
 
+        // This menu contains a placeholder
1186
 
+        eFlag_HasPlaceholderItem = 1 << 1,
1187
 
+
1188
 
+        // This menu is currently receiving a batch of updates, and
1189
 
+        // the native structure should not be modified
1190
 
+        eFlag_InUpdateBatch = 1 << 2,
1191
 
+
1192
 
+        // Children were added to / removed from this menu (only valid
1193
 
+        // when eFlag_InUpdateBatch is set)
1194
 
+        eFlag_StructureMutated = 1 << 3
1195
 
+    };
 
1214
+    friend class nsMenuContentInsertedEvent;
 
1215
+    friend class nsMenuContentRemovedEvent;
1196
1216
+
1197
1217
+    enum EPopupState {
1198
1218
+        ePopupState_Closed,
1201
1221
+        ePopupState_Hiding
1202
1222
+    };
1203
1223
+
1204
 
+    nsMenu();
1205
 
+
1206
 
+    void SetNeedsRebuild(bool aValue)
1207
 
+    {
1208
 
+        if (aValue) {
1209
 
+            SetFlags(eFlag_NeedsRebuild);
1210
 
+        } else {
1211
 
+            ClearFlags(eFlag_NeedsRebuild);
1212
 
+        }
1213
 
+    }
1214
 
+    bool HasPlaceholderItem() const
1215
 
+    {
1216
 
+        return HasFlags(eFlag_HasPlaceholderItem);
1217
 
+    }
1218
 
+    void SetHasPlaceholderItem(bool aValue)
1219
 
+    {
1220
 
+        if (aValue) {
1221
 
+            SetFlags(eFlag_HasPlaceholderItem);
1222
 
+        } else {
1223
 
+            ClearFlags(eFlag_HasPlaceholderItem);
1224
 
+        }
1225
 
+    }
1226
 
+
1227
 
+    bool IsInUpdateBatch() const
1228
 
+    {
1229
 
+        return HasFlags(eFlag_InUpdateBatch);
1230
 
+    }
1231
 
+    void SetIsInUpdateBatch(bool aValue)
1232
 
+    {
1233
 
+        if (aValue) {
1234
 
+            SetFlags(eFlag_InUpdateBatch);
1235
 
+        } else {
1236
 
+            ClearFlags(eFlag_InUpdateBatch);
1237
 
+        }
1238
 
+    }
1239
 
+
1240
 
+    bool DidStructureMutate() const
1241
 
+    {
1242
 
+        return HasFlags(eFlag_StructureMutated);
1243
 
+    }
1244
 
+    void SetDidStructureMutate(bool aValue)
1245
 
+    {
1246
 
+        if (aValue) {
1247
 
+            SetFlags(eFlag_StructureMutated);
1248
 
+        } else {
1249
 
+            ClearFlags(eFlag_StructureMutated);
1250
 
+        }
1251
 
+    }
1252
 
+
1253
 
+    EPopupState PopupState() const
1254
 
+    {
1255
 
+        return static_cast<EPopupState>(
1256
 
+            (GetFlags() &
1257
 
+             (((1U << NSMENU_NUMBER_OF_POPUPSTATE_BITS) - 1U)
1258
 
+              << NSMENU_NUMBER_OF_FLAGS)) >> NSMENU_NUMBER_OF_FLAGS);
1259
 
+    };
1260
1224
+    void SetPopupState(EPopupState aState);
1261
1225
+
 
1226
+    static void DoOpenCallback(nsITimer *aTimer, void *aClosure);
1262
1227
+    static void menu_event_cb(DbusmenuMenuitem *menu,
1263
1228
+                              const gchar *name,
1264
1229
+                              GVariant *value,
1268
1233
+    // We add a placeholder item to empty menus so that Unity actually treats
1269
1234
+    // us as a proper menu, rather than a menuitem without a submenu
1270
1235
+    void MaybeAddPlaceholderItem();
1271
 
+    bool EnsureNoPlaceholderItem();
 
1236
+
 
1237
+    // Removes a placeholder item if it exists and asserts that this succeeds
 
1238
+    void EnsureNoPlaceholderItem();
1272
1239
+
1273
1240
+    void OnOpen();
1274
1241
+    void Build();
1275
 
+    void InitializeNativeData();
1276
 
+    void Update(nsStyleContext *aStyleContext);
1277
1242
+    void InitializePopup();
1278
 
+    void BeginUpdateBatchInternal();
1279
 
+    nsresult RemoveChildAt(size_t aIndex);
1280
 
+    nsresult RemoveChild(nsIContent *aChild);
1281
 
+    nsresult InsertChildAfter(nsMenuObject *aChild, nsIContent *aPrevSibling);
1282
 
+    nsresult AppendChild(nsMenuObject *aChild);
 
1243
+    void RemoveChildAt(size_t aIndex);
 
1244
+    void RemoveChild(nsIContent *aChild);
 
1245
+    void InsertChildAfter(mozilla::UniquePtr<nsMenuObject> aChild,
 
1246
+                          nsIContent *aPrevSibling);
 
1247
+    void AppendChild(mozilla::UniquePtr<nsMenuObject> aChild);
 
1248
+    bool IsInBatchedUpdate() const;
 
1249
+    void StructureMutated();
1283
1250
+    bool CanOpen() const;
1284
 
+    nsMenuObject::PropertyFlags SupportedProperties() const;
 
1251
+
 
1252
+    void HandleContentInserted(nsIContent *aContainer,
 
1253
+                               nsIContent *aChild,
 
1254
+                               nsIContent *aPrevSibling);
 
1255
+    void HandleContentRemoved(nsIContent *aContainer,
 
1256
+                              nsIContent *aChild);
 
1257
+
 
1258
+    void InitializeNativeData() override;
 
1259
+    void Update(nsStyleContext *aStyleContext) override;
 
1260
+    nsMenuObject::PropertyFlags SupportedProperties() const override;
 
1261
+
 
1262
+    void OnAttributeChanged(nsIContent *aContent, nsIAtom *aAttribute) override;
 
1263
+    void OnContentInserted(nsIContent *aContainer, nsIContent *aChild,
 
1264
+                           nsIContent *aPrevSibling) override;
 
1265
+    void OnContentRemoved(nsIContent *aContainer, nsIContent *aChild) override;
 
1266
+    void OnBeginUpdates(nsIContent *aContent) override;
 
1267
+    void OnEndUpdates() override;
 
1268
+
 
1269
+    bool mNeedsRebuild;
 
1270
+    bool mNeedsUpdate;
 
1271
+
 
1272
+    DbusmenuMenuitem *mPlaceholderItem;
 
1273
+
 
1274
+    EPopupState mPopupState;
 
1275
+
 
1276
+    enum EBatchedUpdateState {
 
1277
+        eBatchedUpdateState_Inactive,
 
1278
+        eBatchedUpdateState_Active,
 
1279
+        eBatchedUpdateState_DidMutate
 
1280
+    };
 
1281
+
 
1282
+    EBatchedUpdateState mBatchedUpdateState;
1285
1283
+
1286
1284
+    nsCOMPtr<nsIContent> mPopupContent;
 
1285
+
 
1286
+    nsCOMPtr<nsITimer> mOpenDelayTimer;
1287
1287
+};
1288
1288
+
1289
1289
+#endif /* __nsMenu_h__ */
1290
 
Index: firefox-52.0~b9+build2/widget/gtk/nsMenuBar.cpp
 
1290
Index: firefox-53.0~a2~hg20170302r359591/widget/gtk/nsMenuBar.cpp
1291
1291
===================================================================
1292
1292
--- /dev/null
1293
 
+++ firefox-52.0~b9+build2/widget/gtk/nsMenuBar.cpp
1294
 
@@ -0,0 +1,545 @@
 
1293
+++ firefox-53.0~a2~hg20170302r359591/widget/gtk/nsMenuBar.cpp
 
1294
@@ -0,0 +1,572 @@
1295
1295
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
1296
1296
+/* vim:expandtab:shiftwidth=4:tabstop=4:
1297
1297
+ */
1299
1299
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
1300
1300
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
1301
1301
+
 
1302
+#include "mozilla/Assertions.h"
1302
1303
+#include "mozilla/DebugOnly.h"
1303
1304
+#include "mozilla/dom/Element.h"
 
1305
+#include "mozilla/Move.h"
1304
1306
+#include "mozilla/Preferences.h"
1305
1307
+#include "nsAutoPtr.h"
 
1308
+#include "nsContentUtils.h"
1306
1309
+#include "nsIDocument.h"
1307
1310
+#include "nsIDOMEvent.h"
1308
1311
+#include "nsIDOMEventListener.h"
1309
1312
+#include "nsIDOMEventTarget.h"
1310
1313
+#include "nsIDOMKeyEvent.h"
 
1314
+#include "nsIRunnable.h"
1311
1315
+#include "nsIWidget.h"
1312
1316
+#include "nsTArray.h"
1313
1317
+#include "nsUnicharUtils.h"
1325
1329
+
1326
1330
+using namespace mozilla;
1327
1331
+
1328
 
+class nsMenuBarDocEventListener final : public nsIDOMEventListener
 
1332
+static bool
 
1333
+ShouldHandleKeyEvent(nsIDOMEvent *aEvent)
 
1334
+{
 
1335
+    bool handled, trusted = false;
 
1336
+    aEvent->GetPreventDefault(&handled);
 
1337
+    aEvent->GetIsTrusted(&trusted);
 
1338
+
 
1339
+    if (handled || !trusted) {
 
1340
+        return false;
 
1341
+    }
 
1342
+
 
1343
+    return true;
 
1344
+}
 
1345
+
 
1346
+class nsMenuBarContentInsertedEvent : public Runnable
 
1347
+{
 
1348
+public:
 
1349
+    nsMenuBarContentInsertedEvent(nsMenuBar *aMenuBar,
 
1350
+                                  nsIContent *aChild,
 
1351
+                                  nsIContent *aPrevSibling) :
 
1352
+        mWeakMenuBar(aMenuBar),
 
1353
+        mChild(aChild),
 
1354
+        mPrevSibling(aPrevSibling) { }
 
1355
+
 
1356
+    NS_IMETHODIMP Run()
 
1357
+    {
 
1358
+        if (!mWeakMenuBar) {
 
1359
+            return NS_OK;
 
1360
+        }
 
1361
+
 
1362
+        static_cast<nsMenuBar *>(mWeakMenuBar.get())->HandleContentInserted(mChild,
 
1363
+                                                                            mPrevSibling);
 
1364
+        return NS_OK;
 
1365
+    }
 
1366
+
 
1367
+private:
 
1368
+    nsWeakMenuObject mWeakMenuBar;
 
1369
+
 
1370
+    nsCOMPtr<nsIContent> mChild;
 
1371
+    nsCOMPtr<nsIContent> mPrevSibling;
 
1372
+};
 
1373
+
 
1374
+class nsMenuBarContentRemovedEvent : public Runnable
 
1375
+{
 
1376
+public:
 
1377
+    nsMenuBarContentRemovedEvent(nsMenuBar *aMenuBar,
 
1378
+                                 nsIContent *aChild) :
 
1379
+        mWeakMenuBar(aMenuBar),
 
1380
+        mChild(aChild) { }
 
1381
+
 
1382
+    NS_IMETHODIMP Run()
 
1383
+    {
 
1384
+        if (!mWeakMenuBar) {
 
1385
+            return NS_OK;
 
1386
+        }
 
1387
+
 
1388
+        static_cast<nsMenuBar *>(mWeakMenuBar.get())->HandleContentRemoved(mChild);
 
1389
+        return NS_OK;
 
1390
+    }
 
1391
+
 
1392
+private:
 
1393
+    nsWeakMenuObject mWeakMenuBar;
 
1394
+
 
1395
+    nsCOMPtr<nsIContent> mChild;
 
1396
+};
 
1397
+
 
1398
+class nsMenuBar::DocEventListener final : public nsIDOMEventListener
1329
1399
+{
1330
1400
+public:
1331
1401
+    NS_DECL_ISUPPORTS
1332
1402
+    NS_DECL_NSIDOMEVENTLISTENER
1333
1403
+
1334
 
+    nsMenuBarDocEventListener(nsMenuBar *aOwner) : mOwner(aOwner) { };
 
1404
+    DocEventListener(nsMenuBar *aOwner) : mOwner(aOwner) { };
1335
1405
+
1336
1406
+private:
1337
 
+    ~nsMenuBarDocEventListener() { };
 
1407
+    ~DocEventListener() { };
1338
1408
+
1339
1409
+    nsMenuBar *mOwner;
1340
1410
+};
1341
1411
+
1342
 
+NS_IMPL_ISUPPORTS(nsMenuBarDocEventListener, nsIDOMEventListener)
 
1412
+NS_IMPL_ISUPPORTS(nsMenuBar::DocEventListener, nsIDOMEventListener)
1343
1413
+
1344
1414
+NS_IMETHODIMP
1345
 
+nsMenuBarDocEventListener::HandleEvent(nsIDOMEvent *aEvent)
 
1415
+nsMenuBar::DocEventListener::HandleEvent(nsIDOMEvent *aEvent)
1346
1416
+{
1347
1417
+    nsAutoString type;
1348
1418
+    nsresult rv = aEvent->GetType(type);
1366
1436
+    return rv;
1367
1437
+}
1368
1438
+
 
1439
+nsMenuBar::nsMenuBar(nsIContent *aMenuBarNode) :
 
1440
+    nsMenuContainer(new nsNativeMenuDocListener(aMenuBarNode), aMenuBarNode),
 
1441
+    mTopLevel(nullptr),
 
1442
+    mServer(nullptr),
 
1443
+    mIsActive(false)
 
1444
+{
 
1445
+    MOZ_COUNT_CTOR(nsMenuBar);
 
1446
+}
 
1447
+
 
1448
+nsresult
 
1449
+nsMenuBar::Init(nsIWidget *aParent)
 
1450
+{
 
1451
+    MOZ_ASSERT(aParent);
 
1452
+
 
1453
+    GdkWindow *gdkWin = static_cast<GdkWindow *>(
 
1454
+        aParent->GetNativeData(NS_NATIVE_WINDOW));
 
1455
+    if (!gdkWin) {
 
1456
+        return NS_ERROR_FAILURE;
 
1457
+    }
 
1458
+
 
1459
+    gpointer user_data = nullptr;
 
1460
+    gdk_window_get_user_data(gdkWin, &user_data);
 
1461
+    if (!user_data || !GTK_IS_CONTAINER(user_data)) {
 
1462
+        return NS_ERROR_FAILURE;
 
1463
+    }
 
1464
+
 
1465
+    mTopLevel = gtk_widget_get_toplevel(GTK_WIDGET(user_data));
 
1466
+    if (!mTopLevel) {
 
1467
+        return NS_ERROR_FAILURE;
 
1468
+    }
 
1469
+
 
1470
+    g_object_ref(mTopLevel);
 
1471
+
 
1472
+    nsAutoCString path;
 
1473
+    path.Append(NS_LITERAL_CSTRING("/com/canonical/menu/"));
 
1474
+    char xid[10];
 
1475
+    sprintf(xid, "%X", static_cast<uint32_t>(
 
1476
+        GDK_WINDOW_XID(gtk_widget_get_window(mTopLevel))));
 
1477
+    path.Append(xid);
 
1478
+
 
1479
+    mServer = dbusmenu_server_new(path.get());
 
1480
+    if (!mServer) {
 
1481
+        return NS_ERROR_FAILURE;
 
1482
+    }
 
1483
+
 
1484
+    CreateNativeData();
 
1485
+    if (!GetNativeData()) {
 
1486
+        return NS_ERROR_FAILURE;
 
1487
+    }
 
1488
+
 
1489
+    dbusmenu_server_set_root(mServer, GetNativeData());
 
1490
+
 
1491
+    mEventListener = new DocEventListener(this);
 
1492
+
 
1493
+    mDocument = do_QueryInterface(ContentNode()->OwnerDoc());
 
1494
+
 
1495
+    mAccessKey = Preferences::GetInt("ui.key.menuAccessKey");
 
1496
+    if (mAccessKey == nsIDOMKeyEvent::DOM_VK_SHIFT) {
 
1497
+        mAccessKeyMask = eModifierShift;
 
1498
+    } else if (mAccessKey == nsIDOMKeyEvent::DOM_VK_CONTROL) {
 
1499
+        mAccessKeyMask = eModifierCtrl;
 
1500
+    } else if (mAccessKey == nsIDOMKeyEvent::DOM_VK_ALT) {
 
1501
+        mAccessKeyMask = eModifierAlt;
 
1502
+    } else if (mAccessKey == nsIDOMKeyEvent::DOM_VK_META) {
 
1503
+        mAccessKeyMask = eModifierMeta;
 
1504
+    } else {
 
1505
+        mAccessKeyMask = eModifierAlt;
 
1506
+    }
 
1507
+
 
1508
+    return NS_OK;
 
1509
+}
 
1510
+
1369
1511
+void
1370
1512
+nsMenuBar::Build()
1371
1513
+{
1373
1515
+    for (uint32_t i = 0; i < count; ++i) {
1374
1516
+        nsIContent *childContent = ContentNode()->GetChildAt(i);
1375
1517
+
1376
 
+        nsresult rv;
1377
 
+        nsMenuObject *child = CreateChild(childContent, &rv);
1378
 
+
1379
 
+        if (child) {
1380
 
+            rv = AppendChild(child);
1381
 
+        }
1382
 
+
1383
 
+        if (NS_FAILED(rv)) {
1384
 
+            NS_ERROR("Failed to build menubar");
1385
 
+            return;
1386
 
+        }
 
1518
+        UniquePtr<nsMenuObject> child = CreateChild(childContent);
 
1519
+
 
1520
+        if (!child) {
 
1521
+            continue;
 
1522
+        }
 
1523
+
 
1524
+        AppendChild(Move(child));
1387
1525
+    }
1388
1526
+}
1389
1527
+
1432
1570
+    dbusmenu_server_set_status(mServer, DBUSMENU_STATUS_NORMAL);
1433
1571
+}
1434
1572
+
1435
 
+static bool
1436
 
+ShouldHandleKeyEvent(nsIDOMEvent *aEvent)
1437
 
+{
1438
 
+    bool handled, trusted = false;
1439
 
+    aEvent->GetPreventDefault(&handled);
1440
 
+    aEvent->GetIsTrusted(&trusted);
1441
 
+
1442
 
+    if (handled || !trusted) {
1443
 
+        return false;
1444
 
+    }
1445
 
+
1446
 
+    return true;
1447
 
+}
1448
 
+
1449
1573
+nsMenuBar::ModifierFlags
1450
1574
+nsMenuBar::GetModifiersFromEvent(nsIDOMKeyEvent *aEvent)
1451
1575
+{
1576
1700
+    return NS_OK;
1577
1701
+}
1578
1702
+
1579
 
+nsMenuBar::nsMenuBar() :
1580
 
+    nsMenuContainer(),
1581
 
+    mTopLevel(nullptr),
1582
 
+    mServer(nullptr),
1583
 
+    mIsActive(false)
1584
 
+{
1585
 
+    MOZ_COUNT_CTOR(nsMenuBar);
1586
 
+}
1587
 
+
1588
 
+nsresult
1589
 
+nsMenuBar::Init(nsIWidget *aParent, nsIContent *aMenuBarNode)
1590
 
+{
1591
 
+    NS_ENSURE_ARG(aParent);
1592
 
+    NS_ENSURE_ARG(aMenuBarNode);
1593
 
+
1594
 
+    GdkWindow *gdkWin = static_cast<GdkWindow *>(
1595
 
+        aParent->GetNativeData(NS_NATIVE_WINDOW));
1596
 
+    if (!gdkWin) {
1597
 
+        return NS_ERROR_FAILURE;
1598
 
+    }
1599
 
+
1600
 
+    gpointer user_data = nullptr;
1601
 
+    gdk_window_get_user_data(gdkWin, &user_data);
1602
 
+    if (!user_data || !GTK_IS_CONTAINER(user_data)) {
1603
 
+        return NS_ERROR_FAILURE;
1604
 
+    }
1605
 
+
1606
 
+    mTopLevel = gtk_widget_get_toplevel(GTK_WIDGET(user_data));
1607
 
+    if (!mTopLevel) {
1608
 
+        return NS_ERROR_FAILURE;
1609
 
+    }
1610
 
+
1611
 
+    g_object_ref(mTopLevel);
1612
 
+
1613
 
+    RefPtr<nsNativeMenuDocListener> listener =
1614
 
+        nsNativeMenuDocListener::Create(aMenuBarNode);
1615
 
+    if (!listener) {
1616
 
+        return NS_ERROR_FAILURE;
1617
 
+    }
1618
 
+
1619
 
+    nsMenuObject::Init(listener, aMenuBarNode);
1620
 
+
1621
 
+    nsAutoCString path;
1622
 
+    path.Append(NS_LITERAL_CSTRING("/com/canonical/menu/"));
1623
 
+    char xid[10];
1624
 
+    sprintf(xid, "%X", static_cast<uint32_t>(
1625
 
+        GDK_WINDOW_XID(gtk_widget_get_window(mTopLevel))));
1626
 
+    path.Append(xid);
1627
 
+
1628
 
+    mServer = dbusmenu_server_new(path.get());
1629
 
+    if (!mServer) {
1630
 
+        return NS_ERROR_FAILURE;
1631
 
+    }
1632
 
+
1633
 
+    CreateNativeData();
1634
 
+    if (!GetNativeData()) {
1635
 
+        return NS_ERROR_FAILURE;
1636
 
+    }
1637
 
+
1638
 
+    dbusmenu_server_set_root(mServer, GetNativeData());
1639
 
+
1640
 
+    mEventListener = new nsMenuBarDocEventListener(this);
1641
 
+
1642
 
+    mDocument = do_QueryInterface(ContentNode()->OwnerDoc());
1643
 
+
1644
 
+    mAccessKey = Preferences::GetInt("ui.key.menuAccessKey");
1645
 
+    if (mAccessKey == nsIDOMKeyEvent::DOM_VK_SHIFT) {
1646
 
+        mAccessKeyMask = eModifierShift;
1647
 
+    } else if (mAccessKey == nsIDOMKeyEvent::DOM_VK_CONTROL) {
1648
 
+        mAccessKeyMask = eModifierCtrl;
1649
 
+    } else if (mAccessKey == nsIDOMKeyEvent::DOM_VK_ALT) {
1650
 
+        mAccessKeyMask = eModifierAlt;
1651
 
+    } else if (mAccessKey == nsIDOMKeyEvent::DOM_VK_META) {
1652
 
+        mAccessKeyMask = eModifierMeta;
1653
 
+    } else {
1654
 
+        mAccessKeyMask = eModifierAlt;
1655
 
+    }
1656
 
+
1657
 
+    return NS_OK;
 
1703
+void
 
1704
+nsMenuBar::HandleContentInserted(nsIContent *aChild, nsIContent *aPrevSibling)
 
1705
+{
 
1706
+    UniquePtr<nsMenuObject> child = CreateChild(aChild);
 
1707
+
 
1708
+    if (!child) {
 
1709
+        return;
 
1710
+    }
 
1711
+
 
1712
+    InsertChildAfter(Move(child), aPrevSibling);
 
1713
+}
 
1714
+
 
1715
+void
 
1716
+nsMenuBar::HandleContentRemoved(nsIContent *aChild)
 
1717
+{
 
1718
+    RemoveChild(aChild);
 
1719
+}
 
1720
+
 
1721
+void
 
1722
+nsMenuBar::OnContentInserted(nsIContent *aContainer, nsIContent *aChild,
 
1723
+                             nsIContent *aPrevSibling)
 
1724
+{
 
1725
+    MOZ_ASSERT(aContainer == ContentNode(),
 
1726
+               "Received an event that wasn't meant for us");
 
1727
+
 
1728
+    nsContentUtils::AddScriptRunner(
 
1729
+        new nsMenuBarContentInsertedEvent(this, aChild, aPrevSibling));
 
1730
+}
 
1731
+
 
1732
+void
 
1733
+nsMenuBar::OnContentRemoved(nsIContent *aContainer, nsIContent *aChild)
 
1734
+{
 
1735
+    MOZ_ASSERT(aContainer == ContentNode(),
 
1736
+               "Received an event that wasn't meant for us");
 
1737
+
 
1738
+    nsContentUtils::AddScriptRunner(
 
1739
+        new nsMenuBarContentRemovedEvent(this, aChild));
1658
1740
+}
1659
1741
+
1660
1742
+nsMenuBar::~nsMenuBar()
1693
1775
+    MOZ_COUNT_DTOR(nsMenuBar);
1694
1776
+}
1695
1777
+
1696
 
+/* static */ nsMenuBar*
 
1778
+/* static */ UniquePtr<nsMenuBar>
1697
1779
+nsMenuBar::Create(nsIWidget *aParent, nsIContent *aMenuBarNode)
1698
1780
+{
1699
 
+    nsAutoPtr<nsMenuBar> menubar(new nsMenuBar());
1700
 
+    if (NS_FAILED(menubar->Init(aParent, aMenuBarNode))) {
 
1781
+    UniquePtr<nsMenuBar> menubar(new nsMenuBar(aMenuBarNode));
 
1782
+    if (NS_FAILED(menubar->Init(aParent))) {
1701
1783
+        return nullptr;
1702
1784
+    }
1703
1785
+
1704
 
+    return menubar.forget();
 
1786
+    return Move(menubar);
1705
1787
+}
1706
1788
+
1707
1789
+nsMenuObject::EType
1708
1790
+nsMenuBar::Type() const
1709
1791
+{
1710
 
+    return nsMenuObject::eType_MenuBar;
 
1792
+    return eType_MenuBar;
1711
1793
+}
1712
1794
+
1713
1795
+bool
1732
1814
+    return result;
1733
1815
+}
1734
1816
+
1735
 
+nsNativeMenuGIORequest&
1736
 
+nsMenuBar::BeginRegisterRequest()
1737
 
+{
1738
 
+    mRegisterRequestCanceller.Start();
1739
 
+    return mRegisterRequestCanceller;
1740
 
+}
1741
 
+
1742
 
+void
1743
 
+nsMenuBar::EndRegisterRequest()
1744
 
+{
1745
 
+    NS_ASSERTION(RegisterRequestInProgress(), "No request in progress");
1746
 
+    mRegisterRequestCanceller.Finish();
1747
 
+}
1748
 
+
1749
 
+bool
1750
 
+nsMenuBar::RegisterRequestInProgress() const
1751
 
+{
1752
 
+    return mRegisterRequestCanceller.InProgress();
1753
 
+}
1754
 
+
1755
1817
+void
1756
1818
+nsMenuBar::Activate()
1757
1819
+{
1795
1857
+
1796
1858
+    mIsActive = false;
1797
1859
+
1798
 
+    mRegisterRequestCanceller.Cancel();
1799
 
+
1800
1860
+    SetShellShowingMenuBar(false);
1801
1861
+    while (ChildCount() > 0) {
1802
1862
+        RemoveChildAt(0);
1804
1864
+    DocListener()->Stop();
1805
1865
+    DisconnectDocumentEventListeners();
1806
1866
+}
1807
 
+
1808
 
+void
1809
 
+nsMenuBar::OnAttributeChanged(nsIContent *aContent, nsIAtom *aAttribute)
1810
 
+{
1811
 
+
1812
 
+}
1813
 
+
1814
 
+void
1815
 
+nsMenuBar::OnContentInserted(nsIContent *aContainer, nsIContent *aChild,
1816
 
+                             nsIContent *aPrevSibling)
1817
 
+{
1818
 
+    NS_ASSERTION(aContainer == ContentNode(),
1819
 
+                 "Received an event that wasn't meant for us");
1820
 
+
1821
 
+    nsresult rv;
1822
 
+    nsMenuObject *child = CreateChild(aChild, &rv);
1823
 
+
1824
 
+    if (child) {
1825
 
+        rv = InsertChildAfter(child, aPrevSibling);
1826
 
+    }
1827
 
+
1828
 
+    NS_ASSERTION(NS_SUCCEEDED(rv), "Failed to insert item in to menubar");
1829
 
+}
1830
 
+
1831
 
+void
1832
 
+nsMenuBar::OnContentRemoved(nsIContent *aContainer, nsIContent *aChild)
1833
 
+{
1834
 
+    NS_ASSERTION(aContainer == ContentNode(),
1835
 
+                 "Received an event that wasn't meant for us");
1836
 
+
1837
 
+    DebugOnly<nsresult> rv = RemoveChild(aChild);
1838
 
+    NS_ASSERTION(NS_SUCCEEDED(rv), "Failed to remove item from menubar");
1839
 
+}
1840
 
Index: firefox-52.0~b9+build2/widget/gtk/nsMenuBar.h
 
1867
Index: firefox-53.0~a2~hg20170302r359591/widget/gtk/nsMenuBar.h
1841
1868
===================================================================
1842
1869
--- /dev/null
1843
 
+++ firefox-52.0~b9+build2/widget/gtk/nsMenuBar.h
1844
 
@@ -0,0 +1,112 @@
 
1870
+++ firefox-53.0~a2~hg20170302r359591/widget/gtk/nsMenuBar.h
 
1871
@@ -0,0 +1,107 @@
1845
1872
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
1846
1873
+/* vim:expandtab:shiftwidth=4:tabstop=4:
1847
1874
+ */
1853
1880
+#define __nsMenuBar_h__
1854
1881
+
1855
1882
+#include "mozilla/Attributes.h"
 
1883
+#include "mozilla/UniquePtr.h"
1856
1884
+#include "nsCOMPtr.h"
1857
1885
+#include "nsString.h"
1858
1886
+
1859
1887
+#include "nsDbusmenu.h"
1860
1888
+#include "nsMenuContainer.h"
1861
1889
+#include "nsMenuObject.h"
1862
 
+#include "nsNativeMenuUtils.h"
1863
1890
+
1864
1891
+#include <gtk/gtk.h>
1865
1892
+
1880
1907
+class nsMenuBar final : public nsMenuContainer
1881
1908
+{
1882
1909
+public:
1883
 
+    ~nsMenuBar();
1884
 
+
1885
 
+    static nsMenuBar* Create(nsIWidget *aParent,
1886
 
+                             nsIContent *aMenuBarNode);
1887
 
+
1888
 
+    nsMenuObject::EType Type() const;
1889
 
+
1890
 
+    bool IsBeingDisplayed() const;
 
1910
+    ~nsMenuBar() override;
 
1911
+
 
1912
+    static mozilla::UniquePtr<nsMenuBar> Create(nsIWidget *aParent,
 
1913
+                                                nsIContent *aMenuBarNode);
 
1914
+
 
1915
+    nsMenuObject::EType Type() const override;
 
1916
+
 
1917
+    bool IsBeingDisplayed() const override;
1891
1918
+
1892
1919
+    // Get the native window ID for this menubar
1893
1920
+    uint32_t WindowId() const;
1895
1922
+    // Get the object path for this menubar
1896
1923
+    nsAdoptingCString ObjectPath() const;
1897
1924
+
1898
 
+    // Initializes and returns a cancellable request object, used
1899
 
+    // by the menuservice when registering this menubar
1900
 
+    nsNativeMenuGIORequest& BeginRegisterRequest();
1901
 
+
1902
 
+    // Finishes the current request to register the menubar
1903
 
+    void EndRegisterRequest();
1904
 
+
1905
 
+    bool RegisterRequestInProgress() const;
1906
 
+
1907
1925
+    // Get the top-level GtkWindow handle
1908
1926
+    GtkWidget* TopLevelWindow() { return mTopLevel; }
1909
1927
+
1915
1933
+    // with the desktop shell. Will cause the XUL menubar to be shown again
1916
1934
+    void Deactivate();
1917
1935
+
1918
 
+    void OnAttributeChanged(nsIContent *aContent, nsIAtom *aAttribute);
1919
 
+    void OnContentInserted(nsIContent *aContainer, nsIContent *aChild,
1920
 
+                           nsIContent *aPrevSibling);
1921
 
+    void OnContentRemoved(nsIContent *aContainer, nsIContent *aChild);
1922
 
+
1923
1936
+private:
1924
 
+    friend class nsMenuBarDocEventListener;
 
1937
+    class DocEventListener;
 
1938
+    friend class nsMenuBarContentInsertedEvent;
 
1939
+    friend class nsMenuBarContentRemovedEvent;
1925
1940
+
1926
1941
+    enum ModifierFlags {
1927
1942
+        eModifierShift = (1 << 0),
1930
1945
+        eModifierMeta = (1 << 3)
1931
1946
+    };
1932
1947
+
1933
 
+    nsMenuBar();
1934
 
+    nsresult Init(nsIWidget *aParent, nsIContent *aMenuBarNode);
 
1948
+    nsMenuBar(nsIContent *aMenuBarNode);
 
1949
+    nsresult Init(nsIWidget *aParent);
1935
1950
+    void Build();
1936
1951
+    void DisconnectDocumentEventListeners();
1937
1952
+    void SetShellShowingMenuBar(bool aShowing);
1942
1957
+    nsresult KeyDown(nsIDOMEvent *aEvent);
1943
1958
+    nsresult KeyUp(nsIDOMEvent *aEvent);
1944
1959
+
 
1960
+    void HandleContentInserted(nsIContent *aChild,
 
1961
+                               nsIContent *aPrevSibling);
 
1962
+    void HandleContentRemoved(nsIContent *aChild);
 
1963
+
 
1964
+    void OnContentInserted(nsIContent *aContainer, nsIContent *aChild,
 
1965
+                           nsIContent *aPrevSibling) override;
 
1966
+    void OnContentRemoved(nsIContent *aContainer, nsIContent *aChild) override;
 
1967
+
1945
1968
+    GtkWidget *mTopLevel;
1946
1969
+    DbusmenuServer *mServer;
1947
1970
+    nsCOMPtr<nsIDOMEventTarget> mDocument;
1948
 
+    nsNativeMenuGIORequest mRegisterRequestCanceller;
1949
 
+    RefPtr<nsMenuBarDocEventListener> mEventListener;
 
1971
+    RefPtr<DocEventListener> mEventListener;
1950
1972
+
1951
1973
+    uint32_t mAccessKey;
1952
1974
+    ModifierFlags mAccessKeyMask;
1954
1976
+};
1955
1977
+
1956
1978
+#endif /* __nsMenuBar_h__ */
1957
 
Index: firefox-52.0~b9+build2/widget/gtk/nsMenuContainer.cpp
 
1979
Index: firefox-53.0~a2~hg20170302r359591/widget/gtk/nsMenuContainer.cpp
1958
1980
===================================================================
1959
1981
--- /dev/null
1960
 
+++ firefox-52.0~b9+build2/widget/gtk/nsMenuContainer.cpp
1961
 
@@ -0,0 +1,174 @@
 
1982
+++ firefox-53.0~a2~hg20170302r359591/widget/gtk/nsMenuContainer.cpp
 
1983
@@ -0,0 +1,172 @@
1962
1984
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
1963
1985
+/* vim:expandtab:shiftwidth=4:tabstop=4:
1964
1986
+ */
1966
1988
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
1967
1989
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
1968
1990
+
 
1991
+#include "mozilla/DebugOnly.h"
 
1992
+#include "mozilla/Move.h"
1969
1993
+#include "nsGkAtoms.h"
1970
1994
+#include "nsIAtom.h"
1971
1995
+#include "nsIContent.h"
1977
2001
+
1978
2002
+#include "nsMenuContainer.h"
1979
2003
+
 
2004
+using namespace mozilla;
 
2005
+
1980
2006
+const nsMenuContainer::ChildTArray::index_type nsMenuContainer::NoIndex = nsMenuContainer::ChildTArray::NoIndex;
1981
2007
+
1982
 
+typedef nsMenuObject* (*nsMenuObjectConstructor)(nsMenuContainer*,
1983
 
+                                                 nsIContent*);
 
2008
+typedef UniquePtr<nsMenuObject> (*nsMenuObjectConstructor)(nsMenuContainer*,
 
2009
+                                                           nsIContent*);
 
2010
+
 
2011
+template<class T>
 
2012
+static UniquePtr<nsMenuObject> CreateMenuObject(nsMenuContainer *aContainer,
 
2013
+                                                nsIContent *aContent)
 
2014
+{
 
2015
+    return UniquePtr<T>(new T(aContainer, aContent));
 
2016
+}
 
2017
+
1984
2018
+static nsMenuObjectConstructor
1985
2019
+GetMenuObjectConstructor(nsIContent *aContent)
1986
2020
+{
1987
2021
+    if (aContent->IsXULElement(nsGkAtoms::menuitem)) {
1988
 
+        return nsMenuItem::Create;
 
2022
+        return CreateMenuObject<nsMenuItem>;
1989
2023
+    } else if (aContent->IsXULElement(nsGkAtoms::menu)) {
1990
 
+        return nsMenu::Create;
 
2024
+        return CreateMenuObject<nsMenu>;
1991
2025
+    } else if (aContent->IsXULElement(nsGkAtoms::menuseparator)) {
1992
 
+        return nsMenuSeparator::Create;
 
2026
+        return CreateMenuObject<nsMenuSeparator>;
1993
2027
+    }
1994
2028
+
1995
2029
+    return nullptr;
2001
2035
+    return GetMenuObjectConstructor(aContent) ? true : false;
2002
2036
+}
2003
2037
+
2004
 
+nsMenuObject*
2005
 
+nsMenuContainer::CreateChild(nsIContent *aContent, nsresult *aRv)
 
2038
+nsMenuContainer::nsMenuContainer(nsMenuContainer *aParent,
 
2039
+                                 nsIContent *aContent) :
 
2040
+    nsMenuObject(aParent, aContent)
 
2041
+{
 
2042
+}
 
2043
+
 
2044
+nsMenuContainer::nsMenuContainer(nsNativeMenuDocListener *aListener,
 
2045
+                                 nsIContent *aContent) :
 
2046
+    nsMenuObject(aListener, aContent)
 
2047
+{
 
2048
+}
 
2049
+
 
2050
+UniquePtr<nsMenuObject>
 
2051
+nsMenuContainer::CreateChild(nsIContent *aContent)
2006
2052
+{
2007
2053
+    nsMenuObjectConstructor ctor = GetMenuObjectConstructor(aContent);
2008
2054
+    if (!ctor) {
2009
2055
+        // There are plenty of node types we might stumble across that
2010
 
+        // aren't supported. This isn't an error though
2011
 
+        if (aRv) {
2012
 
+            *aRv = NS_OK;
2013
 
+        }
2014
 
+        return nullptr;
2015
 
+    }
2016
 
+
2017
 
+    nsMenuObject *res = ctor(this, aContent);
2018
 
+    if (!res) {
2019
 
+        if (aRv) {
2020
 
+            *aRv = NS_ERROR_FAILURE;
2021
 
+        }
2022
 
+        return nullptr;
2023
 
+    }
2024
 
+
2025
 
+    if (aRv) {
2026
 
+        *aRv = NS_OK;
2027
 
+    }
2028
 
+    return res;
 
2056
+        // aren't supported
 
2057
+        return nullptr;
 
2058
+    }
 
2059
+
 
2060
+    UniquePtr<nsMenuObject> res = ctor(this, aContent);
 
2061
+    return Move(res);
2029
2062
+}
2030
2063
+
2031
2064
+size_t
2045
2078
+    return NoIndex;
2046
2079
+}
2047
2080
+
2048
 
+nsresult
 
2081
+void
2049
2082
+nsMenuContainer::RemoveChildAt(size_t aIndex, bool aUpdateNative)
2050
2083
+{
2051
 
+    if (aIndex >= ChildCount()) {
2052
 
+        return NS_ERROR_INVALID_ARG;
2053
 
+    }
 
2084
+    MOZ_ASSERT(aIndex < ChildCount());
2054
2085
+
2055
2086
+    if (aUpdateNative) {
2056
 
+        if (!dbusmenu_menuitem_child_delete(GetNativeData(),
2057
 
+                                            ChildAt(aIndex)->GetNativeData())) {
2058
 
+            return NS_ERROR_FAILURE;
2059
 
+        }
 
2087
+        MOZ_ALWAYS_TRUE(
 
2088
+            dbusmenu_menuitem_child_delete(GetNativeData(),
 
2089
+                                           ChildAt(aIndex)->GetNativeData()));
2060
2090
+    }
2061
2091
+
2062
2092
+    mChildren.RemoveElementAt(aIndex);
2063
 
+
2064
 
+    return NS_OK;
2065
2093
+}
2066
2094
+
2067
 
+nsresult
 
2095
+void
2068
2096
+nsMenuContainer::RemoveChild(nsIContent *aChild, bool aUpdateNative)
2069
2097
+{
2070
2098
+    size_t index = IndexOf(aChild);
2071
2099
+    if (index == NoIndex) {
2072
 
+        return NS_ERROR_INVALID_ARG;
 
2100
+        return;
2073
2101
+    }
2074
2102
+
2075
 
+    return RemoveChildAt(index, aUpdateNative);
 
2103
+    RemoveChildAt(index, aUpdateNative);
2076
2104
+}
2077
2105
+
2078
 
+nsresult
2079
 
+nsMenuContainer::InsertChildAfter(nsMenuObject *aChild,
 
2106
+void
 
2107
+nsMenuContainer::InsertChildAfter(UniquePtr<nsMenuObject> aChild,
2080
2108
+                                  nsIContent *aPrevSibling,
2081
2109
+                                  bool aUpdateNative)
2082
2110
+{
2083
2111
+    size_t index = IndexOf(aPrevSibling);
2084
 
+    if (index == NoIndex && aPrevSibling) {
2085
 
+        return NS_ERROR_INVALID_ARG;
2086
 
+    }
 
2112
+    MOZ_ASSERT(!aPrevSibling || index != NoIndex);
2087
2113
+
2088
2114
+    ++index;
2089
2115
+
2090
2116
+    if (aUpdateNative) {
2091
2117
+        aChild->CreateNativeData();
2092
 
+        if (!dbusmenu_menuitem_child_add_position(GetNativeData(),
2093
 
+                                                  aChild->GetNativeData(),
2094
 
+                                                  index)) {
2095
 
+            return NS_ERROR_FAILURE;
2096
 
+        }
 
2118
+        MOZ_ALWAYS_TRUE(
 
2119
+            dbusmenu_menuitem_child_add_position(GetNativeData(),
 
2120
+                                                 aChild->GetNativeData(),
 
2121
+                                                 index));
2097
2122
+    }
2098
2123
+
2099
 
+    return mChildren.InsertElementAt(index, aChild) ? NS_OK : NS_ERROR_FAILURE;
 
2124
+    MOZ_ALWAYS_TRUE(mChildren.InsertElementAt(index, Move(aChild)));
2100
2125
+}
2101
2126
+
2102
 
+nsresult
2103
 
+nsMenuContainer::AppendChild(nsMenuObject *aChild, bool aUpdateNative)
 
2127
+void
 
2128
+nsMenuContainer::AppendChild(UniquePtr<nsMenuObject> aChild,
 
2129
+                             bool aUpdateNative)
2104
2130
+{
2105
2131
+    if (aUpdateNative) {
2106
2132
+        aChild->CreateNativeData();
2107
 
+        if (!dbusmenu_menuitem_child_append(GetNativeData(),
2108
 
+                                            aChild->GetNativeData())) {
2109
 
+            return NS_ERROR_FAILURE;
2110
 
+        }
 
2133
+        MOZ_ALWAYS_TRUE(
 
2134
+            dbusmenu_menuitem_child_append(GetNativeData(),
 
2135
+                                           aChild->GetNativeData()));
2111
2136
+    }
2112
2137
+
2113
 
+    return mChildren.AppendElement(aChild) ? NS_OK : NS_ERROR_FAILURE;
2114
 
+}
2115
 
+
2116
 
+nsMenuContainer::nsMenuContainer() :
2117
 
+    nsMenuObject()
2118
 
+{
 
2138
+    MOZ_ALWAYS_TRUE(mChildren.AppendElement(Move(aChild)));
2119
2139
+}
2120
2140
+
2121
2141
+bool
2133
2153
+
2134
2154
+    return aContent;
2135
2155
+}
2136
 
Index: firefox-52.0~b9+build2/widget/gtk/nsMenuContainer.h
 
2156
Index: firefox-53.0~a2~hg20170302r359591/widget/gtk/nsMenuContainer.h
2137
2157
===================================================================
2138
2158
--- /dev/null
2139
 
+++ firefox-52.0~b9+build2/widget/gtk/nsMenuContainer.h
2140
 
@@ -0,0 +1,66 @@
 
2159
+++ firefox-53.0~a2~hg20170302r359591/widget/gtk/nsMenuContainer.h
 
2160
@@ -0,0 +1,70 @@
2141
2161
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2142
2162
+/* vim:expandtab:shiftwidth=4:tabstop=4:
2143
2163
+ */
2148
2168
+#ifndef __nsMenuContainer_h__
2149
2169
+#define __nsMenuContainer_h__
2150
2170
+
2151
 
+#include "nsAutoPtr.h"
 
2171
+#include "mozilla/UniquePtr.h"
2152
2172
+#include "nsTArray.h"
2153
2173
+
2154
2174
+#include "nsMenuObject.h"
2155
2175
+
2156
2176
+class nsIContent;
 
2177
+class nsNativeMenuDocListener;
2157
2178
+
2158
2179
+// Base class for containers (menus and menubars)
2159
2180
+class nsMenuContainer : public nsMenuObject
2160
2181
+{
2161
2182
+public:
2162
 
+    typedef nsTArray<nsAutoPtr<nsMenuObject> > ChildTArray;
 
2183
+    typedef nsTArray<mozilla::UniquePtr<nsMenuObject> > ChildTArray;
2163
2184
+
2164
2185
+    // Determine if this container is being displayed on screen. Must be
2165
2186
+    // implemented by subclasses. Must return true if the container is
2177
2198
+    static const ChildTArray::index_type NoIndex;
2178
2199
+
2179
2200
+protected:
2180
 
+    nsMenuContainer();
 
2201
+    nsMenuContainer(nsMenuContainer *aParent, nsIContent *aContent);
 
2202
+    nsMenuContainer(nsNativeMenuDocListener *aListener, nsIContent *aContent);
2181
2203
+
2182
2204
+    // Create a new child element for the specified content node
2183
 
+    nsMenuObject* CreateChild(nsIContent *aContent, nsresult *aRv);
 
2205
+    mozilla::UniquePtr<nsMenuObject> CreateChild(nsIContent *aContent);
2184
2206
+
2185
2207
+    // Return the index of the child for the specified content node
2186
2208
+    size_t IndexOf(nsIContent *aChild) const;
2187
2209
+
2188
2210
+    size_t ChildCount() const { return mChildren.Length(); }
2189
 
+    nsMenuObject* ChildAt(size_t aIndex) const { return mChildren[aIndex]; }
 
2211
+    nsMenuObject* ChildAt(size_t aIndex) const { return mChildren[aIndex].get(); }
2190
2212
+
2191
 
+    nsresult RemoveChildAt(size_t aIndex, bool aUpdateNative = true);
 
2213
+    void RemoveChildAt(size_t aIndex, bool aUpdateNative = true);
2192
2214
+
2193
2215
+    // Remove the child that owns the specified content node
2194
 
+    nsresult RemoveChild(nsIContent *aChild, bool aUpdateNative = true);
 
2216
+    void RemoveChild(nsIContent *aChild, bool aUpdateNative = true);
2195
2217
+
2196
2218
+    // Insert a new child after the child that owns the specified content node
2197
 
+    nsresult InsertChildAfter(nsMenuObject *aChild, nsIContent *aPrevSibling,
2198
 
+                              bool aUpdateNative = true);
 
2219
+    void InsertChildAfter(mozilla::UniquePtr<nsMenuObject> aChild,
 
2220
+                          nsIContent *aPrevSibling,
 
2221
+                          bool aUpdateNative = true);
2199
2222
+
2200
 
+    nsresult AppendChild(nsMenuObject *aChild, bool aUpdateNative = true);
 
2223
+    void AppendChild(mozilla::UniquePtr<nsMenuObject> aChild,
 
2224
+                     bool aUpdateNative = true);
2201
2225
+
2202
2226
+private:
2203
2227
+    ChildTArray mChildren;
2204
2228
+};
2205
2229
+
2206
2230
+#endif /* __nsMenuContainer_h__ */
2207
 
Index: firefox-52.0~b9+build2/widget/gtk/nsMenuItem.cpp
 
2231
Index: firefox-53.0~a2~hg20170302r359591/widget/gtk/nsMenuItem.cpp
2208
2232
===================================================================
2209
2233
--- /dev/null
2210
 
+++ firefox-52.0~b9+build2/widget/gtk/nsMenuItem.cpp
2211
 
@@ -0,0 +1,743 @@
 
2234
+++ firefox-53.0~a2~hg20170302r359591/widget/gtk/nsMenuItem.cpp
 
2235
@@ -0,0 +1,737 @@
2212
2236
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2213
2237
+/* vim:expandtab:shiftwidth=4:tabstop=4:
2214
2238
+ */
2217
2241
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
2218
2242
+
2219
2243
+#include "mozilla/ArrayUtils.h"
 
2244
+#include "mozilla/Assertions.h"
2220
2245
+#include "mozilla/dom/Element.h"
 
2246
+#include "mozilla/Move.h"
2221
2247
+#include "mozilla/Preferences.h"
2222
2248
+#include "mozilla/TextEvents.h"
2223
2249
+#include "nsAutoPtr.h"
2511
2537
+    NS_IMETHODIMP Run()
2512
2538
+    {
2513
2539
+        if (mMenuItem) {
2514
 
+            mMenuItem->UncheckSiblings();
 
2540
+            static_cast<nsMenuItem *>(mMenuItem.get())->UncheckSiblings();
2515
2541
+        }
2516
2542
+        return NS_OK;
2517
2543
+    }
2520
2546
+        mMenuItem(aMenuItem) { };
2521
2547
+
2522
2548
+private:
2523
 
+    nsWeakMenuObject<nsMenuItem> mMenuItem;
 
2549
+    nsWeakMenuObject mMenuItem;
2524
2550
+};
2525
2551
+
2526
2552
+bool
2527
2553
+nsMenuItem::IsCheckboxOrRadioItem() const
2528
2554
+{
2529
 
+    return MenuItemType() == eMenuItemType_Radio ||
2530
 
+           MenuItemType() == eMenuItemType_CheckBox;
 
2555
+    return mType == eMenuItemType_Radio ||
 
2556
+           mType == eMenuItemType_CheckBox;
2531
2557
+}
2532
2558
+
2533
2559
+/* static */ void
2548
2574
+
2549
2575
+    // We do this to avoid mutating our view of the menu until
2550
2576
+    // after we have finished
2551
 
+    nsNativeMenuAutoUpdateBatch batch;
 
2577
+    nsNativeMenuDocListener::BlockUpdatesScope updatesBlocker;
2552
2578
+
2553
2579
+    if (!ContentNode()->AttrValueIs(kNameSpaceID_None, nsGkAtoms::autocheck,
2554
2580
+                                    nsGkAtoms::_false, eCaseMatters) &&
2555
 
+        (MenuItemType() == eMenuItemType_CheckBox ||
2556
 
+         (MenuItemType() == eMenuItemType_Radio && !IsChecked()))) {
 
2581
+        (mType == eMenuItemType_CheckBox ||
 
2582
+         (mType == eMenuItemType_Radio && !mIsChecked))) {
2557
2583
+        ContentNode()->SetAttr(kNameSpaceID_None, nsGkAtoms::checked,
2558
 
+                               IsChecked() ?
 
2584
+                               mIsChecked ?
2559
2585
+                               NS_LITERAL_STRING("false") :  NS_LITERAL_STRING("true"),
2560
2586
+                               true);
2561
2587
+    }
2604
2630
+        return;
2605
2631
+    }
2606
2632
+
2607
 
+    SetCheckState(ContentNode()->AttrValueIs(kNameSpaceID_None,
2608
 
+                                             nsGkAtoms::checked,
2609
 
+                                             nsGkAtoms::_true,
2610
 
+                                             eCaseMatters));
 
2633
+    mIsChecked = ContentNode()->AttrValueIs(kNameSpaceID_None,
 
2634
+                                            nsGkAtoms::checked,
 
2635
+                                            nsGkAtoms::_true,
 
2636
+                                            eCaseMatters);
2611
2637
+    dbusmenu_menuitem_property_set_int(GetNativeData(),
2612
2638
+                                       DBUSMENU_MENUITEM_PROP_TOGGLE_STATE,
2613
 
+                                       IsChecked() ?
 
2639
+                                       mIsChecked ?
2614
2640
+                                         DBUSMENU_MENUITEM_TOGGLE_STATE_CHECKED : 
2615
2641
+                                         DBUSMENU_MENUITEM_TOGGLE_STATE_UNCHECKED);
2616
2642
+}
2629
2655
+            dbusmenu_menuitem_property_set(GetNativeData(),
2630
2656
+                                           DBUSMENU_MENUITEM_PROP_TOGGLE_TYPE,
2631
2657
+                                           DBUSMENU_MENUITEM_TOGGLE_CHECK);
2632
 
+            SetMenuItemType(eMenuItemType_CheckBox);
 
2658
+            mType = eMenuItemType_CheckBox;
2633
2659
+        } else if (type == 1) {
2634
2660
+            dbusmenu_menuitem_property_set(GetNativeData(),
2635
2661
+                                           DBUSMENU_MENUITEM_PROP_TOGGLE_TYPE,
2636
2662
+                                           DBUSMENU_MENUITEM_TOGGLE_RADIO);
2637
 
+            SetMenuItemType(eMenuItemType_Radio);
 
2663
+            mType = eMenuItemType_Radio;
2638
2664
+        }
2639
2665
+
2640
2666
+        UpdateState();
2643
2669
+                                          DBUSMENU_MENUITEM_PROP_TOGGLE_TYPE);
2644
2670
+        dbusmenu_menuitem_property_remove(GetNativeData(),
2645
2671
+                                          DBUSMENU_MENUITEM_PROP_TOGGLE_STATE);
2646
 
+        SetMenuItemType(eMenuItemType_Normal);
 
2672
+        mType = eMenuItemType_Normal;
2647
2673
+    }
2648
2674
+}
2649
2675
+
2739
2765
+    }
2740
2766
+}
2741
2767
+
 
2768
+nsMenuBar*
 
2769
+nsMenuItem::MenuBar()
 
2770
+{
 
2771
+    nsMenuObject *tmp = this;
 
2772
+    while (tmp->Parent()) {
 
2773
+        tmp = tmp->Parent();
 
2774
+    }
 
2775
+
 
2776
+    MOZ_ASSERT(tmp->Type() == eType_MenuBar, "The top-level should be a menubar");
 
2777
+
 
2778
+    return static_cast<nsMenuBar *>(tmp);
 
2779
+}
 
2780
+
 
2781
+void
 
2782
+nsMenuItem::UncheckSiblings()
 
2783
+{
 
2784
+    if (!ContentNode()->AttrValueIs(kNameSpaceID_None, nsGkAtoms::type,
 
2785
+                                    nsGkAtoms::radio, eCaseMatters)) {
 
2786
+        // If we're not a radio button, we don't care
 
2787
+        return;
 
2788
+    }
 
2789
+
 
2790
+    nsAutoString name;
 
2791
+    ContentNode()->GetAttr(kNameSpaceID_None, nsGkAtoms::name, name);
 
2792
+
 
2793
+    nsIContent *parent = ContentNode()->GetParent();
 
2794
+    if (!parent) {
 
2795
+        return;
 
2796
+    }
 
2797
+
 
2798
+    uint32_t count = parent->GetChildCount();
 
2799
+    for (uint32_t i = 0; i < count; ++i) {
 
2800
+        nsIContent *sibling = parent->GetChildAt(i);
 
2801
+
 
2802
+        nsAutoString otherName;
 
2803
+        sibling->GetAttr(kNameSpaceID_None, nsGkAtoms::name, otherName);
 
2804
+
 
2805
+        if (sibling != ContentNode() && otherName == name && 
 
2806
+            sibling->AttrValueIs(kNameSpaceID_None, nsGkAtoms::type,
 
2807
+                                 nsGkAtoms::radio, eCaseMatters)) {
 
2808
+            sibling->UnsetAttr(kNameSpaceID_None, nsGkAtoms::checked, true);
 
2809
+        }
 
2810
+    }
 
2811
+}
 
2812
+
2742
2813
+void
2743
2814
+nsMenuItem::InitializeNativeData()
2744
2815
+{
2745
2816
+    g_signal_connect(G_OBJECT(GetNativeData()),
2746
2817
+                     DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED,
2747
2818
+                     G_CALLBACK(item_activated_cb), this);
2748
 
+
2749
 
+    UpdateTypeAndState();
2750
 
+    UpdateAccel();
2751
 
+    UpdateLabel();
2752
 
+    UpdateSensitivity();
 
2819
+    mNeedsUpdate = true;
2753
2820
+}
2754
2821
+
2755
2822
+void
2788
2855
+void
2789
2856
+nsMenuItem::Update(nsStyleContext *aStyleContext)
2790
2857
+{
 
2858
+    if (mNeedsUpdate) {
 
2859
+        mNeedsUpdate = false;
 
2860
+
 
2861
+        UpdateTypeAndState();
 
2862
+        UpdateAccel();
 
2863
+        UpdateLabel();
 
2864
+        UpdateSensitivity();
 
2865
+    }
 
2866
+
2791
2867
+    UpdateVisibility(aStyleContext);
2792
2868
+    UpdateIcon(aStyleContext);
2793
2869
+}
2794
2870
+
2795
 
+void
2796
 
+nsMenuItem::UncheckSiblings()
2797
 
+{
2798
 
+    if (!ContentNode()->AttrValueIs(kNameSpaceID_None, nsGkAtoms::type,
2799
 
+                                    nsGkAtoms::radio, eCaseMatters)) {
2800
 
+        // If we're not a radio button, we don't care
2801
 
+        return;
2802
 
+    }
2803
 
+
2804
 
+    nsAutoString name;
2805
 
+    ContentNode()->GetAttr(kNameSpaceID_None, nsGkAtoms::name, name);
2806
 
+
2807
 
+    nsIContent *parent = ContentNode()->GetParent();
2808
 
+    if (!parent) {
2809
 
+        return;
2810
 
+    }
2811
 
+
2812
 
+    uint32_t count = parent->GetChildCount();
2813
 
+    for (uint32_t i = 0; i < count; ++i) {
2814
 
+        nsIContent *sibling = parent->GetChildAt(i);
2815
 
+
2816
 
+        nsAutoString otherName;
2817
 
+        sibling->GetAttr(kNameSpaceID_None, nsGkAtoms::name, otherName);
2818
 
+
2819
 
+        if (sibling != ContentNode() && otherName == name && 
2820
 
+            sibling->AttrValueIs(kNameSpaceID_None, nsGkAtoms::type,
2821
 
+                                 nsGkAtoms::radio, eCaseMatters)) {
2822
 
+            sibling->UnsetAttr(kNameSpaceID_None, nsGkAtoms::checked, true);
2823
 
+        }
2824
 
+    }
2825
 
+}
2826
 
+
2827
2871
+bool
2828
2872
+nsMenuItem::IsCompatibleWithNativeData(DbusmenuMenuitem *aNativeData) const
2829
2873
+{
2832
2876
+                         "separator") != 0;
2833
2877
+}
2834
2878
+
2835
 
+nsMenuBar*
2836
 
+nsMenuItem::MenuBar()
2837
 
+{
2838
 
+    nsMenuObject *tmp = this;
2839
 
+    while (tmp->Parent()) {
2840
 
+        tmp = tmp->Parent();
2841
 
+    }
2842
 
+
2843
 
+    MOZ_ASSERT(tmp->Type() == eType_MenuBar, "The top-level should be a menubar");
2844
 
+
2845
 
+    return static_cast<nsMenuBar *>(tmp);
2846
 
+}
2847
 
+
2848
2879
+nsMenuObject::PropertyFlags
2849
2880
+nsMenuItem::SupportedProperties() const
2850
2881
+{
2859
2890
+    );
2860
2891
+}
2861
2892
+
2862
 
+nsMenuItem::nsMenuItem() :
2863
 
+    nsMenuObject()
2864
 
+{
2865
 
+    MOZ_COUNT_CTOR(nsMenuItem);
2866
 
+}
2867
 
+
2868
 
+nsMenuItem::~nsMenuItem()
2869
 
+{
2870
 
+    if (DocListener() && mKeyContent) {
2871
 
+        DocListener()->UnregisterForContentChanges(mKeyContent);
2872
 
+    }
2873
 
+
2874
 
+    if (GetNativeData()) {
2875
 
+        g_signal_handlers_disconnect_by_func(GetNativeData(),
2876
 
+                                             FuncToGpointer(item_activated_cb),
2877
 
+                                             this);
2878
 
+    }
2879
 
+
2880
 
+    MOZ_COUNT_DTOR(nsMenuItem);
2881
 
+}
2882
 
+
2883
 
+nsMenuObject::EType
2884
 
+nsMenuItem::Type() const
2885
 
+{
2886
 
+    return nsMenuObject::eType_MenuItem;
2887
 
+}
2888
 
+
2889
 
+/* static */ nsMenuObject*
2890
 
+nsMenuItem::Create(nsMenuContainer *aParent, nsIContent *aContent)
2891
 
+{
2892
 
+    nsAutoPtr<nsMenuItem> menuitem(new nsMenuItem());
2893
 
+    if (NS_FAILED(menuitem->Init(aParent, aContent))) {
2894
 
+        return nullptr;
2895
 
+    }
2896
 
+
2897
 
+    return menuitem.forget();
2898
 
+}
2899
 
+
2900
2893
+void
2901
2894
+nsMenuItem::OnAttributeChanged(nsIContent *aContent, nsIAtom *aAttribute)
2902
2895
+{
2903
 
+    NS_ASSERTION(aContent == ContentNode() || aContent == mKeyContent,
2904
 
+                 "Received an event that wasn't meant for us!");
2905
 
+
2906
 
+    if (Parent()->NeedsRebuild()) {
2907
 
+        return;
2908
 
+    }
 
2896
+    MOZ_ASSERT(aContent == ContentNode() || aContent == mKeyContent,
 
2897
+               "Received an event that wasn't meant for us!");
2909
2898
+
2910
2899
+    if (aContent == ContentNode() && aAttribute == nsGkAtoms::checked &&
2911
2900
+        aContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::checked,
2912
2901
+                              nsGkAtoms::_true, eCaseMatters)) {
2913
 
+        if (nsContentUtils::IsSafeToRunScript()) {
2914
 
+            UncheckSiblings();
2915
 
+        } else {
2916
 
+            nsContentUtils::AddScriptRunner(
2917
 
+                new nsMenuItemUncheckSiblingsRunnable(this));
2918
 
+        }
 
2902
+        nsContentUtils::AddScriptRunner(
 
2903
+            new nsMenuItemUncheckSiblingsRunnable(this));
 
2904
+    }
 
2905
+
 
2906
+    if (mNeedsUpdate) {
 
2907
+        return;
 
2908
+    }
 
2909
+
 
2910
+    if (!Parent()->IsBeingDisplayed()) {
 
2911
+        mNeedsUpdate = true;
 
2912
+        return;
2919
2913
+    }
2920
2914
+
2921
2915
+    if (aContent == ContentNode()) {
2931
2925
+            UpdateTypeAndState();
2932
2926
+        } else if (aAttribute == nsGkAtoms::checked) {
2933
2927
+            UpdateState();
 
2928
+        } else if (aAttribute == nsGkAtoms::hidden ||
 
2929
+                   aAttribute == nsGkAtoms::collapsed) {
 
2930
+            RefPtr<nsStyleContext> sc = GetStyleContext();
 
2931
+            UpdateVisibility(sc);
 
2932
+        } else if (aAttribute == nsGkAtoms::image) {
 
2933
+            RefPtr<nsStyleContext> sc = GetStyleContext();
 
2934
+            UpdateIcon(sc);
2934
2935
+        }
2935
2936
+    } else if (aContent == mKeyContent &&
2936
2937
+               (aAttribute == nsGkAtoms::key ||
2938
2939
+                aAttribute == nsGkAtoms::modifiers)) {
2939
2940
+        UpdateAccel();
2940
2941
+    }
2941
 
+
2942
 
+    if (!Parent()->IsBeingDisplayed() || aContent != ContentNode()) {
2943
 
+        return;
2944
 
+    }
2945
 
+
2946
 
+    if (aAttribute == nsGkAtoms::hidden ||
2947
 
+        aAttribute == nsGkAtoms::collapsed) {
2948
 
+        RefPtr<nsStyleContext> sc = GetStyleContext();
2949
 
+        UpdateVisibility(sc);
2950
 
+    } else if (aAttribute == nsGkAtoms::image) {
2951
 
+        RefPtr<nsStyleContext> sc = GetStyleContext();
2952
 
+        UpdateIcon(sc);
2953
 
+    }
2954
 
+}
2955
 
Index: firefox-52.0~b9+build2/widget/gtk/nsMenuItem.h
 
2942
+}
 
2943
+
 
2944
+nsMenuItem::nsMenuItem(nsMenuContainer *aParent, nsIContent *aContent) :
 
2945
+    nsMenuObject(aParent, aContent),
 
2946
+    mType(eMenuItemType_Normal),
 
2947
+    mIsChecked(false),
 
2948
+    mNeedsUpdate(false)
 
2949
+{
 
2950
+    MOZ_COUNT_CTOR(nsMenuItem);
 
2951
+}
 
2952
+
 
2953
+nsMenuItem::~nsMenuItem()
 
2954
+{
 
2955
+    if (DocListener() && mKeyContent) {
 
2956
+        DocListener()->UnregisterForContentChanges(mKeyContent);
 
2957
+    }
 
2958
+
 
2959
+    if (GetNativeData()) {
 
2960
+        g_signal_handlers_disconnect_by_func(GetNativeData(),
 
2961
+                                             FuncToGpointer(item_activated_cb),
 
2962
+                                             this);
 
2963
+    }
 
2964
+
 
2965
+    MOZ_COUNT_DTOR(nsMenuItem);
 
2966
+}
 
2967
+
 
2968
+nsMenuObject::EType
 
2969
+nsMenuItem::Type() const
 
2970
+{
 
2971
+    return eType_MenuItem;
 
2972
+}
 
2973
Index: firefox-53.0~a2~hg20170302r359591/widget/gtk/nsMenuItem.h
2956
2974
===================================================================
2957
2975
--- /dev/null
2958
 
+++ firefox-52.0~b9+build2/widget/gtk/nsMenuItem.h
2959
 
@@ -0,0 +1,107 @@
 
2976
+++ firefox-53.0~a2~hg20170302r359591/widget/gtk/nsMenuItem.h
 
2977
@@ -0,0 +1,81 @@
2960
2978
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2961
2979
+/* vim:expandtab:shiftwidth=4:tabstop=4:
2962
2980
+ */
2975
2993
+
2976
2994
+#include <glib.h>
2977
2995
+
2978
 
+#define NSMENUITEM_NUMBER_OF_TYPE_BITS 2U
2979
 
+#define NSMENUITEM_NUMBER_OF_FLAGS     1U
2980
 
+
2981
2996
+class nsIAtom;
2982
2997
+class nsIContent;
2983
2998
+class nsStyleContext;
2991
3006
+class nsMenuItem final : public nsMenuObject
2992
3007
+{
2993
3008
+public:
2994
 
+    ~nsMenuItem();
2995
 
+
2996
 
+    nsMenuObject::EType Type() const;
2997
 
+
2998
 
+    static nsMenuObject* Create(nsMenuContainer *aParent,
2999
 
+                                nsIContent *aContent);
3000
 
+
3001
 
+    void OnAttributeChanged(nsIContent *aContent, nsIAtom *aAttribute);
 
3009
+    nsMenuItem(nsMenuContainer *aParent, nsIContent *aContent);
 
3010
+    ~nsMenuItem() override;
 
3011
+
 
3012
+    nsMenuObject::EType Type() const override;
3002
3013
+
3003
3014
+private:
3004
3015
+    friend class nsMenuItemUncheckSiblingsRunnable;
3013
3024
+        eMenuItemType_CheckBox
3014
3025
+    };
3015
3026
+
3016
 
+    nsMenuItem();
3017
 
+
3018
 
+    EMenuItemType MenuItemType() const
3019
 
+    {
3020
 
+        return static_cast<EMenuItemType>(
3021
 
+            (GetFlags() &
3022
 
+             (((1U << NSMENUITEM_NUMBER_OF_TYPE_BITS) - 1U)
3023
 
+              << NSMENUITEM_NUMBER_OF_FLAGS)) >> NSMENUITEM_NUMBER_OF_FLAGS);
3024
 
+    }
3025
 
+    void SetMenuItemType(EMenuItemType aType)
3026
 
+    {
3027
 
+        ClearFlags(((1U << NSMENUITEM_NUMBER_OF_TYPE_BITS) - 1U) << NSMENUITEM_NUMBER_OF_FLAGS);
3028
 
+        SetFlags(aType << NSMENUITEM_NUMBER_OF_FLAGS);
3029
 
+    }
3030
3027
+    bool IsCheckboxOrRadioItem() const;
3031
3028
+
3032
 
+    bool IsChecked() const
3033
 
+    {
3034
 
+        return HasFlags(eMenuItemFlag_ToggleState);
3035
 
+    }
3036
 
+    void SetCheckState(bool aState)
3037
 
+    {
3038
 
+        if (aState) {
3039
 
+            SetFlags(eMenuItemFlag_ToggleState);
3040
 
+        } else {
3041
 
+            ClearFlags(eMenuItemFlag_ToggleState);
3042
 
+        }
3043
 
+    }
3044
 
+
3045
3029
+    static void item_activated_cb(DbusmenuMenuitem *menuitem,
3046
3030
+                                  guint timestamp,
3047
3031
+                                  gpointer user_data);
3051
3035
+    void UpdateState();
3052
3036
+    void UpdateTypeAndState();
3053
3037
+    void UpdateAccel();
3054
 
+
3055
 
+    void InitializeNativeData();
3056
 
+    void UpdateContentAttributes();
3057
 
+    void Update(nsStyleContext *aStyleContext);
 
3038
+    nsMenuBar* MenuBar();
3058
3039
+    void UncheckSiblings();
3059
 
+    bool IsCompatibleWithNativeData(DbusmenuMenuitem *aNativeData) const;
3060
 
+    nsMenuBar* MenuBar();
3061
 
+    nsMenuObject::PropertyFlags SupportedProperties() const;
 
3040
+
 
3041
+    void InitializeNativeData() override;
 
3042
+    void UpdateContentAttributes() override;
 
3043
+    void Update(nsStyleContext *aStyleContext) override;
 
3044
+    bool IsCompatibleWithNativeData(DbusmenuMenuitem *aNativeData) const override;
 
3045
+    nsMenuObject::PropertyFlags SupportedProperties() const override;
 
3046
+
 
3047
+    void OnAttributeChanged(nsIContent *aContent, nsIAtom *aAttribute) override;
 
3048
+
 
3049
+    EMenuItemType mType;
 
3050
+
 
3051
+    bool mIsChecked;
 
3052
+
 
3053
+    bool mNeedsUpdate;
3062
3054
+
3063
3055
+    nsCOMPtr<nsIContent> mKeyContent;
3064
3056
+};
3065
3057
+
3066
3058
+#endif /* __nsMenuItem_h__ */
3067
 
Index: firefox-52.0~b9+build2/widget/gtk/nsMenuObject.cpp
 
3059
Index: firefox-53.0~a2~hg20170302r359591/widget/gtk/nsMenuObject.cpp
3068
3060
===================================================================
3069
3061
--- /dev/null
3070
 
+++ firefox-52.0~b9+build2/widget/gtk/nsMenuObject.cpp
3071
 
@@ -0,0 +1,694 @@
 
3062
+++ firefox-53.0~a2~hg20170302r359591/widget/gtk/nsMenuObject.cpp
 
3063
@@ -0,0 +1,660 @@
3072
3064
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3073
3065
+/* vim:expandtab:shiftwidth=4:tabstop=4:
3074
3066
+ */
3082
3074
+#include "imgLoader.h"
3083
3075
+#include "imgRequestProxy.h"
3084
3076
+#include "mozilla/ArrayUtils.h"
 
3077
+#include "mozilla/Assertions.h"
3085
3078
+#include "mozilla/dom/Element.h"
3086
3079
+#include "mozilla/Preferences.h"
3087
3080
+#include "nsAttrValue.h"
3103
3096
+#include "nsStyleConsts.h"
3104
3097
+#include "nsStyleContext.h"
3105
3098
+#include "nsStyleStruct.h"
3106
 
+#include "nsThreadUtils.h"
3107
3099
+#include "nsUnicharUtils.h"
3108
3100
+
3109
3101
+#include "nsMenuContainer.h"
3110
3102
+#include "nsNativeMenuAtoms.h"
3111
3103
+#include "nsNativeMenuDocListener.h"
3112
 
+#include "nsNativeMenuUtils.h"
3113
3104
+
3114
3105
+#include <gdk/gdk.h>
3115
3106
+#include <glib-object.h>
3129
3120
+    nullptr
3130
3121
+};
3131
3122
+
3132
 
+nsWeakMenuObjectBase* nsWeakMenuObjectBase::sHead;
 
3123
+nsWeakMenuObject* nsWeakMenuObject::sHead;
3133
3124
+PangoLayout* gPangoLayout = nullptr;
3134
3125
+
3135
 
+class nsMenuObjectContainerOpeningRunnable : public Runnable
3136
 
+{
3137
 
+public:
3138
 
+    NS_IMETHODIMP Run()
3139
 
+    {
3140
 
+        if (mMenuObject) {
3141
 
+            mMenuObject->ContainerIsOpening();
3142
 
+        }
3143
 
+        return NS_OK;
3144
 
+    }
3145
 
+
3146
 
+    nsMenuObjectContainerOpeningRunnable(nsMenuObject *aMenuObject) :
3147
 
+        mMenuObject(aMenuObject) { };
3148
 
+
3149
 
+private:
3150
 
+    nsWeakMenuObject<nsMenuObject> mMenuObject;
3151
 
+};
3152
 
+
3153
3126
+class nsMenuObjectIconLoader final : public imgINotificationObserver
3154
3127
+{
3155
3128
+public:
3325
3298
+            return;
3326
3299
+        }
3327
3300
+
3328
 
+        loader->LoadImage(uri, nullptr, nullptr, mozilla::net::RP_Default,
 
3301
+        loader->LoadImage(uri, nullptr, nullptr, mozilla::net::RP_Unset,
3329
3302
+                          nullptr, loadGroup, this, nullptr, nullptr,
3330
3303
+                          nsIRequest::LOAD_NORMAL, nullptr,
3331
3304
+                          nsIContentPolicy::TYPE_IMAGE, EmptyString(),
3397
3370
+    return sEllipsisWidth;
3398
3371
+}
3399
3372
+
3400
 
+void
3401
 
+nsMenuObject::InitializeNativeData()
3402
 
+{
3403
 
+}
3404
 
+
3405
 
+nsMenuObject::PropertyFlags
3406
 
+nsMenuObject::SupportedProperties() const
3407
 
+{
3408
 
+    return static_cast<nsMenuObject::PropertyFlags>(0);
3409
 
+}
3410
 
+
3411
 
+bool
3412
 
+nsMenuObject::IsCompatibleWithNativeData(DbusmenuMenuitem *aNativeData) const
3413
 
+{
3414
 
+    return true;
3415
 
+}
3416
 
+
3417
 
+void
3418
 
+nsMenuObject::UpdateContentAttributes()
3419
 
+{
3420
 
+}
3421
 
+
3422
 
+void
3423
 
+nsMenuObject::Update(nsStyleContext *aStyleContext)
3424
 
+{
3425
 
+}
3426
 
+
3427
 
+bool
3428
 
+nsMenuObject::ShouldShowIcon() const
3429
 
+{
3430
 
+    // Ideally we want to know the visibility of the anonymous XUL image in
3431
 
+    // our menuitem, but this isn't created because we don't have a frame.
3432
 
+    // The following works by default (because xul.css hides images in menuitems
3433
 
+    // that don't have the "menuitem-with-favicon" class). It's possible a third
3434
 
+    // party theme could override this, but, oh well...
3435
 
+    const nsAttrValue *classes = mContent->GetClasses();
3436
 
+    if (!classes) {
3437
 
+        return false;
3438
 
+    }
3439
 
+
3440
 
+    for (uint32_t i = 0; i < classes->GetAtomCount(); ++i) {
3441
 
+        if (classes->AtomAt(i) == nsNativeMenuAtoms::menuitem_with_favicon) {
3442
 
+            return true;
3443
 
+        }
3444
 
+    }
3445
 
+
3446
 
+    return false;
3447
 
+}
3448
 
+
3449
 
+void
3450
 
+nsMenuObject::ClearIcon()
3451
 
+{
3452
 
+    dbusmenu_menuitem_property_remove(mNativeData,
3453
 
+                                      DBUSMENU_MENUITEM_PROP_ICON_DATA);
 
3373
+nsMenuObject::nsMenuObject(nsMenuContainer *aParent, nsIContent *aContent) :
 
3374
+    mContent(aContent),
 
3375
+    mListener(aParent->DocListener()),
 
3376
+    mParent(aParent),
 
3377
+    mNativeData(nullptr)
 
3378
+{
 
3379
+    MOZ_ASSERT(mContent);
 
3380
+    MOZ_ASSERT(mListener);
 
3381
+    MOZ_ASSERT(mParent);
 
3382
+}
 
3383
+
 
3384
+nsMenuObject::nsMenuObject(nsNativeMenuDocListener *aListener,
 
3385
+                           nsIContent *aContent) :
 
3386
+    mContent(aContent),
 
3387
+    mListener(aListener),
 
3388
+    mParent(nullptr),
 
3389
+    mNativeData(nullptr)
 
3390
+{
 
3391
+    MOZ_ASSERT(mContent);
 
3392
+    MOZ_ASSERT(mListener);
3454
3393
+}
3455
3394
+
3456
3395
+void
3506
3445
+        return;
3507
3446
+    }
3508
3447
+
3509
 
+    // This *COMPLETELY SUCKS*
 
3448
+    // This sucks.
3510
3449
+    // This should be done at the point where the menu is drawn (hello Unity),
3511
3450
+    // but unfortunately it doesn't do that and will happily fill your entire
3512
3451
+    // screen width with a menu if you have a bookmark with a really long title.
3513
3452
+    // This leaves us with no other option but to ellipsize here, with no proper
3514
3453
+    // knowledge of Unity's render path, font size etc. This is better than nothing
3515
 
+    // BAH! @*&!$
3516
3454
+    nsAutoString truncated;
3517
3455
+    int target = MAX_WIDTH - GetEllipsisWidth();
3518
3456
+    length = label.Length();
3530
3468
+    switch (type) {
3531
3469
+        case 0:
3532
3470
+        case 1:
3533
 
+            // FIXME: Implement left cropping (do we really care?)
 
3471
+            // FIXME: Implement left cropping
3534
3472
+        case 2:
3535
 
+            // FIXME: Implement center cropping (do we really care?)
 
3473
+            // FIXME: Implement center cropping
3536
3474
+        case 3:
3537
3475
+        case 4:
3538
3476
+        default:
3615
3553
+    return sc.forget();
3616
3554
+}
3617
3555
+
3618
 
+nsresult
3619
 
+nsMenuObject::Init(nsMenuContainer *aParent, nsIContent *aContent)
3620
 
+{
3621
 
+    NS_ENSURE_ARG(aParent);
3622
 
+    NS_ENSURE_ARG(aContent);
3623
 
+
3624
 
+    mParent = aParent;
3625
 
+    mContent = aContent;
3626
 
+    mListener = aParent->DocListener();
3627
 
+    NS_ENSURE_ARG(mListener);
3628
 
+
3629
 
+    return NS_OK;    
3630
 
+}
3631
 
+
3632
 
+nsresult
3633
 
+nsMenuObject::Init(nsNativeMenuDocListener *aListener, nsIContent *aContent)
3634
 
+{
3635
 
+    NS_ENSURE_ARG(aListener);
3636
 
+    NS_ENSURE_ARG(aContent);
3637
 
+
3638
 
+    mParent = nullptr;
3639
 
+    mContent = aContent;
3640
 
+    mListener = aListener;
3641
 
+
3642
 
+    return NS_OK;
3643
 
+}
3644
 
+
3645
 
+nsMenuObject::nsMenuObject() :
3646
 
+    mParent(nullptr), mNativeData(nullptr), mFlags(0)
3647
 
+{
 
3556
+void
 
3557
+nsMenuObject::InitializeNativeData()
 
3558
+{
 
3559
+}
 
3560
+
 
3561
+nsMenuObject::PropertyFlags
 
3562
+nsMenuObject::SupportedProperties() const
 
3563
+{
 
3564
+    return static_cast<nsMenuObject::PropertyFlags>(0);
 
3565
+}
 
3566
+
 
3567
+bool
 
3568
+nsMenuObject::IsCompatibleWithNativeData(DbusmenuMenuitem *aNativeData) const
 
3569
+{
 
3570
+    return true;
 
3571
+}
 
3572
+
 
3573
+void
 
3574
+nsMenuObject::UpdateContentAttributes()
 
3575
+{
 
3576
+}
 
3577
+
 
3578
+void
 
3579
+nsMenuObject::Update(nsStyleContext *aStyleContext)
 
3580
+{
 
3581
+}
 
3582
+
 
3583
+bool
 
3584
+nsMenuObject::ShouldShowIcon() const
 
3585
+{
 
3586
+    // Ideally we want to know the visibility of the anonymous XUL image in
 
3587
+    // our menuitem, but this isn't created because we don't have a frame.
 
3588
+    // The following works by default (because xul.css hides images in menuitems
 
3589
+    // that don't have the "menuitem-with-favicon" class). It's possible a third
 
3590
+    // party theme could override this, but, oh well...
 
3591
+    const nsAttrValue *classes = mContent->GetClasses();
 
3592
+    if (!classes) {
 
3593
+        return false;
 
3594
+    }
 
3595
+
 
3596
+    for (uint32_t i = 0; i < classes->GetAtomCount(); ++i) {
 
3597
+        if (classes->AtomAt(i) == nsNativeMenuAtoms::menuitem_with_favicon) {
 
3598
+            return true;
 
3599
+        }
 
3600
+    }
 
3601
+
 
3602
+    return false;
 
3603
+}
 
3604
+
 
3605
+void
 
3606
+nsMenuObject::ClearIcon()
 
3607
+{
 
3608
+    dbusmenu_menuitem_property_remove(mNativeData,
 
3609
+                                      DBUSMENU_MENUITEM_PROP_ICON_DATA);
3648
3610
+}
3649
3611
+
3650
3612
+nsMenuObject::~nsMenuObject()
3651
3613
+{
3652
 
+    nsWeakMenuObjectBase::NotifyDestroyed(this);
 
3614
+    nsWeakMenuObject::NotifyDestroyed(this);
3653
3615
+
3654
3616
+    if (mIconLoader) {
3655
3617
+        mIconLoader->Destroy();
3668
3630
+void
3669
3631
+nsMenuObject::CreateNativeData()
3670
3632
+{
3671
 
+    NS_ASSERTION(mNativeData == nullptr, "This node already has a DbusmenuMenuitem. The old one will be leaked");
 
3633
+    MOZ_ASSERT(mNativeData == nullptr, "This node already has a DbusmenuMenuitem. The old one will be leaked");
3672
3634
+
3673
3635
+    mNativeData = dbusmenu_menuitem_new();
3674
3636
+    InitializeNativeData();
3682
3644
+nsresult
3683
3645
+nsMenuObject::AdoptNativeData(DbusmenuMenuitem *aNativeData)
3684
3646
+{
3685
 
+    NS_ASSERTION(mNativeData == nullptr, "This node already has a DbusmenuMenuitem. The old one will be leaked");
 
3647
+    MOZ_ASSERT(mNativeData == nullptr, "This node already has a DbusmenuMenuitem. The old one will be leaked");
3686
3648
+
3687
3649
+    if (!IsCompatibleWithNativeData(aNativeData)) {
3688
3650
+        return NS_ERROR_FAILURE;
3714
3676
+void
3715
3677
+nsMenuObject::ContainerIsOpening()
3716
3678
+{
3717
 
+    if (!nsContentUtils::IsSafeToRunScript()) {
3718
 
+        nsContentUtils::AddScriptRunner(
3719
 
+            new nsMenuObjectContainerOpeningRunnable(this));
3720
 
+        return;
3721
 
+    }
 
3679
+    MOZ_ASSERT(nsContentUtils::IsSafeToRunScript());
3722
3680
+
3723
3681
+    UpdateContentAttributes();
3724
3682
+
3727
3685
+}
3728
3686
+
3729
3687
+/* static */ void
3730
 
+nsWeakMenuObjectBase::AddWeakReference(nsWeakMenuObjectBase *aWeak)
 
3688
+nsWeakMenuObject::AddWeakReference(nsWeakMenuObject *aWeak)
3731
3689
+{
3732
 
+    aWeak->SetPrevious(sHead);
 
3690
+    aWeak->mPrev = sHead;
3733
3691
+    sHead = aWeak;
3734
3692
+}
3735
3693
+
3736
3694
+/* static */ void
3737
 
+nsWeakMenuObjectBase::RemoveWeakReference(nsWeakMenuObjectBase *aWeak)
 
3695
+nsWeakMenuObject::RemoveWeakReference(nsWeakMenuObject *aWeak)
3738
3696
+{
3739
3697
+    if (aWeak == sHead) {
3740
 
+        sHead = aWeak->GetPrevious();
 
3698
+        sHead = aWeak->mPrev;
3741
3699
+        return;
3742
3700
+    }
3743
3701
+
3744
 
+    nsWeakMenuObjectBase *weak = sHead;
3745
 
+    while (weak && weak->GetPrevious() != aWeak) {
3746
 
+        weak = weak->GetPrevious();
 
3702
+    nsWeakMenuObject *weak = sHead;
 
3703
+    while (weak && weak->mPrev != aWeak) {
 
3704
+        weak = weak->mPrev;
3747
3705
+    }
3748
3706
+
3749
3707
+    if (weak) {
3750
 
+        weak->SetPrevious(aWeak->GetPrevious());
 
3708
+        weak->mPrev = aWeak->mPrev;
3751
3709
+    }
3752
3710
+}
3753
3711
+
3754
3712
+/* static */ void
3755
 
+nsWeakMenuObjectBase::NotifyDestroyed(nsMenuObject *aMenuObject)
 
3713
+nsWeakMenuObject::NotifyDestroyed(nsMenuObject *aMenuObject)
3756
3714
+{
3757
 
+    nsWeakMenuObjectBase *weak = sHead;
 
3715
+    nsWeakMenuObject *weak = sHead;
3758
3716
+    while (weak) {
3759
 
+        if (weak->getBase() == aMenuObject) {
3760
 
+            weak->Clear();
 
3717
+        if (weak->mMenuObject == aMenuObject) {
 
3718
+            weak->mMenuObject = nullptr;
3761
3719
+        }
3762
3720
+
3763
 
+        weak = weak->GetPrevious();
 
3721
+        weak = weak->mPrev;
3764
3722
+    }
3765
3723
+}
3766
 
Index: firefox-52.0~b9+build2/widget/gtk/nsMenuObject.h
 
3724
Index: firefox-53.0~a2~hg20170302r359591/widget/gtk/nsMenuObject.h
3767
3725
===================================================================
3768
3726
--- /dev/null
3769
 
+++ firefox-52.0~b9+build2/widget/gtk/nsMenuObject.h
3770
 
@@ -0,0 +1,242 @@
 
3727
+++ firefox-53.0~a2~hg20170302r359591/widget/gtk/nsMenuObject.h
 
3728
@@ -0,0 +1,170 @@
3771
3729
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3772
3730
+/* vim:expandtab:shiftwidth=4:tabstop=4:
3773
3731
+ */
3817
3775
+    enum EType {
3818
3776
+        eType_MenuBar,
3819
3777
+        eType_Menu,
3820
 
+        eType_MenuItem,
3821
 
+        eType_MenuSeparator
3822
 
+    };
3823
 
+
3824
 
+    enum PropertyFlags {
3825
 
+#define DBUSMENU_PROPERTY(e, s, b) eProp##e = (1 << b),
3826
 
+        DBUSMENU_PROPERTIES
3827
 
+#undef DBUSMENU_PROPERTY
 
3778
+        eType_MenuItem
3828
3779
+    };
3829
3780
+
3830
3781
+    virtual ~nsMenuObject();
3854
3805
+    void ContainerIsOpening();
3855
3806
+
3856
3807
+protected:
3857
 
+    nsMenuObject();
3858
 
+    nsresult Init(nsMenuContainer *aParent, nsIContent *aContent);
3859
 
+    nsresult Init(nsNativeMenuDocListener *aListener, nsIContent *aContent);
 
3808
+    nsMenuObject(nsMenuContainer *aParent, nsIContent *aContent);
 
3809
+    nsMenuObject(nsNativeMenuDocListener *aListener, nsIContent *aContent);
 
3810
+
 
3811
+    enum PropertyFlags {
 
3812
+#define DBUSMENU_PROPERTY(e, s, b) eProp##e = (1 << b),
 
3813
+        DBUSMENU_PROPERTIES
 
3814
+#undef DBUSMENU_PROPERTY
 
3815
+    };
3860
3816
+
3861
3817
+    void UpdateLabel();
3862
3818
+    void UpdateVisibility(nsStyleContext *aStyleContext);
3865
3821
+
3866
3822
+    already_AddRefed<nsStyleContext> GetStyleContext();
3867
3823
+  
3868
 
+    uint8_t GetFlags() const { return mFlags; }
3869
 
+    bool HasFlags(uint8_t aFlags) const
3870
 
+    {
3871
 
+        return (mFlags & aFlags) == aFlags;
3872
 
+    }
3873
 
+    void SetFlags(uint8_t aFlags)
3874
 
+    {
3875
 
+        mFlags |= aFlags;
3876
 
+    }
3877
 
+    void ClearFlags(uint8_t aFlags)
3878
 
+    {
3879
 
+        mFlags &= ~aFlags;
3880
 
+    }
3881
 
+
3882
3824
+private:
3883
3825
+    friend class nsMenuObjectIconLoader;
3884
3826
+
3919
3861
+    nsMenuContainer *mParent; // [weak]
3920
3862
+    DbusmenuMenuitem *mNativeData; // [strong]
3921
3863
+    RefPtr<nsMenuObjectIconLoader> mIconLoader;
3922
 
+    uint8_t mFlags;
3923
3864
+};
3924
3865
+
3925
 
+class nsWeakMenuObjectBase
 
3866
+// Keep a weak pointer to a menu object
 
3867
+class nsWeakMenuObject
3926
3868
+{
3927
3869
+public:
3928
 
+    ~nsWeakMenuObjectBase()
 
3870
+    nsWeakMenuObject() : mPrev(nullptr), mMenuObject(nullptr) {}
 
3871
+
 
3872
+    nsWeakMenuObject(nsMenuObject *aMenuObject) :
 
3873
+        mPrev(nullptr), mMenuObject(aMenuObject)
3929
3874
+    {
3930
 
+        RemoveWeakReference(this);
 
3875
+        AddWeakReference(this);
3931
3876
+    }
3932
3877
+
3933
 
+    nsMenuObject* getBase() const { return mMenuObject; }
 
3878
+    ~nsWeakMenuObject() { RemoveWeakReference(this); }
 
3879
+
 
3880
+    nsMenuObject* get() const { return mMenuObject; }
 
3881
+
 
3882
+    nsMenuObject* operator->() const { return mMenuObject; }
 
3883
+
 
3884
+    explicit operator bool() const { return !!mMenuObject; }
3934
3885
+
3935
3886
+    static void NotifyDestroyed(nsMenuObject *aMenuObject);
3936
3887
+
3937
 
+protected:
3938
 
+    nsWeakMenuObjectBase() : mMenuObject(nullptr) { };
3939
 
+
3940
 
+    void SetMenuObject(nsMenuObject *aMenuObject)
3941
 
+    {
3942
 
+        mMenuObject = aMenuObject;
3943
 
+
3944
 
+        mMenuObject ? AddWeakReference(this) : RemoveWeakReference(this);
3945
 
+    }
3946
 
+
3947
3888
+private:
3948
 
+    nsWeakMenuObjectBase* GetPrevious() const { return mPrev; }
3949
 
+    void SetPrevious(nsWeakMenuObjectBase *aPrev)
3950
 
+    {
3951
 
+        mPrev = aPrev;
3952
 
+    }
3953
 
+    void Clear() { mMenuObject = nullptr; }
3954
 
+
3955
 
+    static void AddWeakReference(nsWeakMenuObjectBase *aWeak);
3956
 
+    static void RemoveWeakReference(nsWeakMenuObjectBase *aWeak);
3957
 
+
3958
 
+    nsWeakMenuObjectBase *mPrev;
3959
 
+    static nsWeakMenuObjectBase *sHead;
 
3889
+    static void AddWeakReference(nsWeakMenuObject *aWeak);
 
3890
+    static void RemoveWeakReference(nsWeakMenuObject *aWeak);
 
3891
+
 
3892
+    nsWeakMenuObject *mPrev;
 
3893
+    static nsWeakMenuObject *sHead;
3960
3894
+
3961
3895
+    nsMenuObject *mMenuObject;
3962
3896
+};
3963
3897
+
3964
 
+// Keep a weak pointer to a menu object. Note, if you need to work
3965
 
+// with a pointer to this class, use nsAutoWeakMenuObject instead
3966
 
+template<class T>
3967
 
+class nsWeakMenuObject : public nsWeakMenuObjectBase
3968
 
+{
3969
 
+public:
3970
 
+    nsWeakMenuObject() :
3971
 
+        nsWeakMenuObjectBase() { };
3972
 
+
3973
 
+    nsWeakMenuObject(T *aMenuObject) :
3974
 
+        nsWeakMenuObjectBase()
3975
 
+    {
3976
 
+        SetMenuObject(aMenuObject);
3977
 
+    }
3978
 
+
3979
 
+    T* get() const { return static_cast<T *>(getBase()); }
3980
 
+
3981
 
+    T* operator->() const { return get(); }
3982
 
+
3983
 
+    operator T*() const { return get(); }
3984
 
+};
3985
 
+
3986
 
+template<class T>
3987
 
+class nsAutoWeakMenuObject
3988
 
+{
3989
 
+public:
3990
 
+    nsAutoWeakMenuObject() { };
3991
 
+
3992
 
+    nsAutoWeakMenuObject(T *aMenuObject) :
3993
 
+        mPtr(new nsWeakMenuObject<T>(aMenuObject)) { };
3994
 
+
3995
 
+    nsAutoWeakMenuObject(nsWeakMenuObject<T> *aWeak) :
3996
 
+        mPtr(aWeak) { };
3997
 
+
3998
 
+    T* get() const { return static_cast<T *>(*mPtr); }
3999
 
+
4000
 
+    T* operator->() const { return get(); }
4001
 
+
4002
 
+    operator T*() const { return get(); }
4003
 
+
4004
 
+    nsWeakMenuObject<T>* getWeakPtr() const { return mPtr; }
4005
 
+
4006
 
+    nsWeakMenuObject<T>* forget() { return mPtr.forget(); }
4007
 
+
4008
 
+private:
4009
 
+    nsAutoPtr<nsWeakMenuObject<T> > mPtr;
4010
 
+};
4011
 
+
4012
3898
+#endif /* __nsMenuObject_h__ */
4013
 
Index: firefox-52.0~b9+build2/widget/gtk/nsMenuSeparator.cpp
 
3899
Index: firefox-53.0~a2~hg20170302r359591/widget/gtk/nsMenuSeparator.cpp
4014
3900
===================================================================
4015
3901
--- /dev/null
4016
 
+++ firefox-52.0~b9+build2/widget/gtk/nsMenuSeparator.cpp
4017
 
@@ -0,0 +1,90 @@
 
3902
+++ firefox-53.0~a2~hg20170302r359591/widget/gtk/nsMenuSeparator.cpp
 
3903
@@ -0,0 +1,85 @@
4018
3904
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
4019
3905
+/* vim:expandtab:shiftwidth=4:tabstop=4:
4020
3906
+ */
4022
3908
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
4023
3909
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4024
3910
+
 
3911
+#include "mozilla/Assertions.h"
 
3912
+#include "mozilla/Move.h"
4025
3913
+#include "nsAutoPtr.h"
4026
3914
+#include "nsCRT.h"
4027
3915
+#include "nsGkAtoms.h"
4032
3920
+#include "nsMenuContainer.h"
4033
3921
+#include "nsMenuSeparator.h"
4034
3922
+
 
3923
+using namespace mozilla;
 
3924
+
4035
3925
+void
4036
3926
+nsMenuSeparator::InitializeNativeData()
4037
3927
+{
4063
3953
+    );
4064
3954
+}
4065
3955
+
4066
 
+nsMenuSeparator::nsMenuSeparator()
 
3956
+void
 
3957
+nsMenuSeparator::OnAttributeChanged(nsIContent *aContent, nsIAtom *aAttribute)
 
3958
+{
 
3959
+    MOZ_ASSERT(aContent == ContentNode(), "Received an event that wasn't meant for us!");
 
3960
+
 
3961
+    if (!Parent()->IsBeingDisplayed()) {
 
3962
+        return;
 
3963
+    }
 
3964
+
 
3965
+    if (aAttribute == nsGkAtoms::hidden ||
 
3966
+        aAttribute == nsGkAtoms::collapsed) {
 
3967
+        RefPtr<nsStyleContext> sc = GetStyleContext();
 
3968
+        UpdateVisibility(sc);
 
3969
+    }
 
3970
+}
 
3971
+
 
3972
+nsMenuSeparator::nsMenuSeparator(nsMenuContainer *aParent,
 
3973
+                                 nsIContent *aContent) :
 
3974
+    nsMenuObject(aParent, aContent)
4067
3975
+{
4068
3976
+    MOZ_COUNT_CTOR(nsMenuSeparator);
4069
3977
+}
4076
3984
+nsMenuObject::EType
4077
3985
+nsMenuSeparator::Type() const
4078
3986
+{
4079
 
+    return nsMenuObject::eType_MenuSeparator;
4080
 
+}
4081
 
+
4082
 
+/* static */ nsMenuObject*
4083
 
+nsMenuSeparator::Create(nsMenuContainer *aParent, nsIContent *aContent)
4084
 
+{
4085
 
+    nsAutoPtr<nsMenuSeparator> sep(new nsMenuSeparator());
4086
 
+    if (NS_FAILED(sep->Init(aParent, aContent))) {
4087
 
+        return nullptr;
4088
 
+    }
4089
 
+
4090
 
+    return sep.forget();
4091
 
+}
4092
 
+
4093
 
+void
4094
 
+nsMenuSeparator::OnAttributeChanged(nsIContent *aContent, nsIAtom *aAttribute)
4095
 
+{
4096
 
+    NS_ASSERTION(aContent == ContentNode(), "Received an event that wasn't meant for us!");
4097
 
+
4098
 
+    if (!Parent()->IsBeingDisplayed()) {
4099
 
+        return;
4100
 
+    }
4101
 
+
4102
 
+    if (aAttribute == nsGkAtoms::hidden ||
4103
 
+        aAttribute == nsGkAtoms::collapsed) {
4104
 
+        RefPtr<nsStyleContext> sc = GetStyleContext();
4105
 
+        UpdateVisibility(sc);
4106
 
+    }
4107
 
+}
4108
 
Index: firefox-52.0~b9+build2/widget/gtk/nsMenuSeparator.h
 
3987
+    return eType_MenuItem;
 
3988
+}
 
3989
Index: firefox-53.0~a2~hg20170302r359591/widget/gtk/nsMenuSeparator.h
4109
3990
===================================================================
4110
3991
--- /dev/null
4111
 
+++ firefox-52.0~b9+build2/widget/gtk/nsMenuSeparator.h
4112
 
@@ -0,0 +1,41 @@
 
3992
+++ firefox-53.0~a2~hg20170302r359591/widget/gtk/nsMenuSeparator.h
 
3993
@@ -0,0 +1,37 @@
4113
3994
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
4114
3995
+/* vim:expandtab:shiftwidth=4:tabstop=4:
4115
3996
+ */
4132
4013
+class nsMenuSeparator final : public nsMenuObject
4133
4014
+{
4134
4015
+public:
 
4016
+    nsMenuSeparator(nsMenuContainer *aParent, nsIContent *aContent);
4135
4017
+    ~nsMenuSeparator();
4136
4018
+
4137
 
+    nsMenuObject::EType Type() const;
4138
 
+
4139
 
+    static nsMenuObject* Create(nsMenuContainer *aParent,
4140
 
+                                nsIContent *aContent);
4141
 
+
4142
 
+    void OnAttributeChanged(nsIContent *aContent, nsIAtom *aAttribute);
 
4019
+    nsMenuObject::EType Type() const override;
4143
4020
+
4144
4021
+private:
4145
 
+    nsMenuSeparator();
 
4022
+    void InitializeNativeData() override;
 
4023
+    void Update(nsStyleContext *aStyleContext) override;
 
4024
+    bool IsCompatibleWithNativeData(DbusmenuMenuitem *aNativeData) const override;
 
4025
+    nsMenuObject::PropertyFlags SupportedProperties() const override;
4146
4026
+
4147
 
+    void InitializeNativeData();
4148
 
+    void Update(nsStyleContext *aStyleContext);
4149
 
+    bool IsCompatibleWithNativeData(DbusmenuMenuitem *aNativeData) const;
4150
 
+    nsMenuObject::PropertyFlags SupportedProperties() const;
 
4027
+    void OnAttributeChanged(nsIContent *aContent, nsIAtom *aAttribute) override;
4151
4028
+};
4152
4029
+
4153
4030
+#endif /* __nsMenuSeparator_h__ */
4154
 
Index: firefox-52.0~b9+build2/widget/gtk/nsNativeMenuAtomList.h
 
4031
Index: firefox-53.0~a2~hg20170302r359591/widget/gtk/nsNativeMenuAtomList.h
4155
4032
===================================================================
4156
4033
--- /dev/null
4157
 
+++ firefox-52.0~b9+build2/widget/gtk/nsNativeMenuAtomList.h
4158
 
@@ -0,0 +1,11 @@
 
4034
+++ firefox-53.0~a2~hg20170302r359591/widget/gtk/nsNativeMenuAtomList.h
 
4035
@@ -0,0 +1,12 @@
4159
4036
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
4160
4037
+/* vim:expandtab:shiftwidth=4:tabstop=4:
4161
4038
+ */
4164
4041
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4165
4042
+
4166
4043
+WIDGET_ATOM2(menuitem_with_favicon, "menuitem-with-favicon")
4167
 
+WIDGET_ATOM2(_moz_menupopupstate, "_moz-menupopupstate")
 
4044
+WIDGET_ATOM2(_moz_menubarkeeplocal, "_moz-menubarkeeplocal")
 
4045
+WIDGET_ATOM2(_moz_nativemenupopupstate, "_moz-nativemenupopupstate")
4168
4046
+WIDGET_ATOM(openedwithkey)
4169
4047
+WIDGET_ATOM(shellshowingmenubar)
4170
 
Index: firefox-52.0~b9+build2/widget/gtk/nsNativeMenuAtoms.cpp
 
4048
Index: firefox-53.0~a2~hg20170302r359591/widget/gtk/nsNativeMenuAtoms.cpp
4171
4049
===================================================================
4172
4050
--- /dev/null
4173
 
+++ firefox-52.0~b9+build2/widget/gtk/nsNativeMenuAtoms.cpp
 
4051
+++ firefox-53.0~a2~hg20170302r359591/widget/gtk/nsNativeMenuAtoms.cpp
4174
4052
@@ -0,0 +1,39 @@
4175
4053
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
4176
4054
+/* vim:expandtab:shiftwidth=4:tabstop=4:
4211
4089
+{
4212
4090
+    NS_RegisterStaticAtoms(gAtoms);
4213
4091
+}
4214
 
Index: firefox-52.0~b9+build2/widget/gtk/nsNativeMenuAtoms.h
 
4092
Index: firefox-53.0~a2~hg20170302r359591/widget/gtk/nsNativeMenuAtoms.h
4215
4093
===================================================================
4216
4094
--- /dev/null
4217
 
+++ firefox-52.0~b9+build2/widget/gtk/nsNativeMenuAtoms.h
4218
 
@@ -0,0 +1,25 @@
 
4095
+++ firefox-53.0~a2~hg20170302r359591/widget/gtk/nsNativeMenuAtoms.h
 
4096
@@ -0,0 +1,27 @@
4219
4097
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
4220
4098
+/* vim:expandtab:shiftwidth=4:tabstop=4:
4221
4099
+ */
4231
4109
+class nsNativeMenuAtoms
4232
4110
+{
4233
4111
+public:
 
4112
+    nsNativeMenuAtoms() = delete;
 
4113
+
4234
4114
+    static void RegisterAtoms();
4235
4115
+
4236
4116
+#define WIDGET_ATOM(_name) static nsIAtom* _name;
4241
4121
+};
4242
4122
+
4243
4123
+#endif /* __nsNativeMenuAtoms_h__ */
4244
 
Index: firefox-52.0~b9+build2/widget/gtk/nsNativeMenuDocListener.cpp
 
4124
Index: firefox-53.0~a2~hg20170302r359591/widget/gtk/nsNativeMenuDocListener.cpp
4245
4125
===================================================================
4246
4126
--- /dev/null
4247
 
+++ firefox-52.0~b9+build2/widget/gtk/nsNativeMenuDocListener.cpp
4248
 
@@ -0,0 +1,370 @@
 
4127
+++ firefox-53.0~a2~hg20170302r359591/widget/gtk/nsNativeMenuDocListener.cpp
 
4128
@@ -0,0 +1,350 @@
4249
4129
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
4250
4130
+/* vim:expandtab:shiftwidth=4:tabstop=4:
4251
4131
+ */
4267
4147
+
4268
4148
+using namespace mozilla;
4269
4149
+
4270
 
+uint32_t nsNativeMenuDocListener::sUpdateDepth = 0;
 
4150
+uint32_t nsNativeMenuDocListener::sUpdateBlockersCount = 0;
4271
4151
+
4272
4152
+nsNativeMenuDocListenerTArray *gPendingListeners;
4273
4153
+
4308
4188
+
4309
4189
+NS_IMPL_ISUPPORTS(nsNativeMenuDocListener, nsIMutationObserver)
4310
4190
+
 
4191
+nsNativeMenuDocListener::~nsNativeMenuDocListener()
 
4192
+{
 
4193
+    MOZ_ASSERT(mContentToObserverTable.Count() == 0,
 
4194
+               "Some nodes forgot to unregister listeners. This is bad! (and we're lucky we made it this far)");
 
4195
+    MOZ_COUNT_DTOR(nsNativeMenuDocListener);
 
4196
+}
 
4197
+
 
4198
+void
 
4199
+nsNativeMenuDocListener::AttributeChanged(nsIDocument *aDocument,
 
4200
+                                          mozilla::dom::Element *aElement,
 
4201
+                                          int32_t aNameSpaceID,
 
4202
+                                          nsIAtom *aAttribute,
 
4203
+                                          int32_t aModType,
 
4204
+                                          const nsAttrValue* aOldValue)
 
4205
+{
 
4206
+    if (sUpdateBlockersCount == 0) {
 
4207
+        DoAttributeChanged(aElement, aAttribute);
 
4208
+        return;
 
4209
+    }
 
4210
+
 
4211
+    MutationRecord *m = *mPendingMutations.AppendElement(new MutationRecord);
 
4212
+    m->mType = MutationRecord::eAttributeChanged;
 
4213
+    m->mTarget = aElement;
 
4214
+    m->mAttribute = aAttribute;
 
4215
+
 
4216
+    ScheduleFlush(this);
 
4217
+}
 
4218
+
 
4219
+void
 
4220
+nsNativeMenuDocListener::ContentAppended(nsIDocument *aDocument,
 
4221
+                                         nsIContent *aContainer,
 
4222
+                                         nsIContent *aFirstNewContent,
 
4223
+                                         int32_t aNewIndexInContainer)
 
4224
+{
 
4225
+    for (nsIContent *c = aFirstNewContent; c; c = c->GetNextSibling()) {
 
4226
+        ContentInserted(aDocument, aContainer, c, 0);
 
4227
+    }
 
4228
+}
 
4229
+
 
4230
+void
 
4231
+nsNativeMenuDocListener::ContentInserted(nsIDocument *aDocument,
 
4232
+                                         nsIContent *aContainer,
 
4233
+                                         nsIContent *aChild,
 
4234
+                                         int32_t aIndexInContainer)
 
4235
+{
 
4236
+    nsIContent *prevSibling = nsMenuContainer::GetPreviousSupportedSibling(aChild);
 
4237
+
 
4238
+    if (sUpdateBlockersCount == 0) {
 
4239
+        DoContentInserted(aContainer, aChild, prevSibling);
 
4240
+        return;
 
4241
+    }
 
4242
+
 
4243
+    MutationRecord *m = *mPendingMutations.AppendElement(new MutationRecord);
 
4244
+    m->mType = MutationRecord::eContentInserted;
 
4245
+    m->mTarget = aContainer;
 
4246
+    m->mChild = aChild;
 
4247
+    m->mPrevSibling = prevSibling;
 
4248
+
 
4249
+    ScheduleFlush(this);
 
4250
+}
 
4251
+
 
4252
+void
 
4253
+nsNativeMenuDocListener::ContentRemoved(nsIDocument *aDocument,
 
4254
+                                        nsIContent *aContainer,
 
4255
+                                        nsIContent *aChild,
 
4256
+                                        int32_t aIndexInContainer,
 
4257
+                                        nsIContent *aPreviousSibling)
 
4258
+{
 
4259
+    if (sUpdateBlockersCount == 0) {
 
4260
+        DoContentRemoved(aContainer, aChild);
 
4261
+        return;
 
4262
+    }
 
4263
+
 
4264
+    MutationRecord *m = *mPendingMutations.AppendElement(new MutationRecord);
 
4265
+    m->mType = MutationRecord::eContentRemoved;
 
4266
+    m->mTarget = aContainer;
 
4267
+    m->mChild = aChild;
 
4268
+
 
4269
+    ScheduleFlush(this);
 
4270
+}                                                           
 
4271
+
 
4272
+void
 
4273
+nsNativeMenuDocListener::NodeWillBeDestroyed(const nsINode *aNode)
 
4274
+{
 
4275
+    mDocument = nullptr;
 
4276
+}
 
4277
+
4311
4278
+void
4312
4279
+nsNativeMenuDocListener::DoAttributeChanged(nsIContent *aContent,
4313
4280
+                                            nsIAtom *aAttribute)
4340
4307
+}
4341
4308
+
4342
4309
+void
4343
 
+nsNativeMenuDocListener::DoBeginUpdateBatch(nsIContent *aTarget)
 
4310
+nsNativeMenuDocListener::DoBeginUpdates(nsIContent *aTarget)
4344
4311
+{
4345
4312
+    DispatchHelper h(this, aTarget);
4346
4313
+    if (h.HasObserver()) {
4347
 
+        h.Observer()->BeginUpdateBatch(aTarget);
 
4314
+        h.Observer()->OnBeginUpdates(aTarget);
4348
4315
+    }
4349
4316
+}
4350
4317
+
4351
4318
+void
4352
 
+nsNativeMenuDocListener::DoEndUpdateBatch(nsIContent *aTarget)
 
4319
+nsNativeMenuDocListener::DoEndUpdates(nsIContent *aTarget)
4353
4320
+{
4354
4321
+    DispatchHelper h(this, aTarget);
4355
4322
+    if (h.HasObserver()) {
4356
 
+        h.Observer()->EndUpdateBatch();
 
4323
+        h.Observer()->OnEndUpdates();
4357
4324
+    }
4358
4325
+}
4359
4326
+
4360
4327
+void
4361
4328
+nsNativeMenuDocListener::FlushPendingMutations()
4362
4329
+{
4363
 
+    nsIContent *batchTarget = nullptr;
4364
 
+    bool inUpdateBatch = false;
 
4330
+    nsIContent *currentTarget = nullptr;
 
4331
+    bool inUpdateSequence = false;
4365
4332
+
4366
4333
+    while (mPendingMutations.Length() > 0) {
4367
4334
+        MutationRecord *m = mPendingMutations[0];
4368
4335
+
4369
 
+        if (m->mTarget != batchTarget) {
4370
 
+            if (inUpdateBatch) {
4371
 
+                DoEndUpdateBatch(batchTarget);
4372
 
+                inUpdateBatch = false;
 
4336
+        if (m->mTarget != currentTarget) {
 
4337
+            if (inUpdateSequence) {
 
4338
+                DoEndUpdates(currentTarget);
 
4339
+                inUpdateSequence = false;
4373
4340
+            }
4374
4341
+
4375
 
+            batchTarget = m->mTarget;
 
4342
+            currentTarget = m->mTarget;
4376
4343
+
4377
4344
+            if (mPendingMutations.Length() > 1 &&
4378
 
+                mPendingMutations[1]->mTarget == batchTarget) {
4379
 
+                DoBeginUpdateBatch(batchTarget);
4380
 
+                inUpdateBatch = true;
 
4345
+                mPendingMutations[1]->mTarget == currentTarget) {
 
4346
+                DoBeginUpdates(currentTarget);
 
4347
+                inUpdateSequence = true;
4381
4348
+            }
4382
4349
+        }
4383
4350
+
4398
4365
+        mPendingMutations.RemoveElementAt(0);
4399
4366
+    }
4400
4367
+
4401
 
+    if (inUpdateBatch) {
4402
 
+        DoEndUpdateBatch(batchTarget);
 
4368
+    if (inUpdateSequence) {
 
4369
+        DoEndUpdates(currentTarget);
4403
4370
+    }
4404
4371
+}
4405
4372
+
4406
4373
+/* static */ void
4407
4374
+nsNativeMenuDocListener::ScheduleFlush(nsNativeMenuDocListener *aListener)
4408
4375
+{
4409
 
+    NS_ASSERTION(sUpdateDepth > 0, "Shouldn't be doing this now");
 
4376
+    MOZ_ASSERT(sUpdateBlockersCount > 0, "Shouldn't be doing this now");
4410
4377
+
4411
4378
+    if (!gPendingListeners) {
4412
4379
+        gPendingListeners = new nsNativeMenuDocListenerTArray;
4429
4396
+}
4430
4397
+
4431
4398
+/* static */ void
4432
 
+nsNativeMenuDocListener::EndUpdates()
 
4399
+nsNativeMenuDocListener::RemoveUpdateBlocker()
4433
4400
+{
4434
 
+    if (sUpdateDepth == 1 && gPendingListeners) {
 
4401
+    if (sUpdateBlockersCount == 1 && gPendingListeners) {
4435
4402
+        while (gPendingListeners->Length() > 0) {
4436
4403
+            (*gPendingListeners)[0]->FlushPendingMutations();
4437
4404
+            gPendingListeners->RemoveElementAt(0);
4438
4405
+        }
4439
4406
+    }
4440
4407
4441
 
+    NS_ASSERTION(sUpdateDepth > 0, "Negative update depth!");
4442
 
+    sUpdateDepth--;
 
4408
+    MOZ_ASSERT(sUpdateBlockersCount > 0, "Negative update blockers count!");
 
4409
+    sUpdateBlockersCount--;
4443
4410
+}
4444
4411
+
4445
 
+nsNativeMenuDocListener::nsNativeMenuDocListener() :
 
4412
+nsNativeMenuDocListener::nsNativeMenuDocListener(nsIContent *aRootNode) :
 
4413
+    mRootNode(aRootNode),
4446
4414
+    mDocument(nullptr),
4447
4415
+    mLastSource(nullptr),
4448
4416
+    mLastTarget(nullptr)
4450
4418
+    MOZ_COUNT_CTOR(nsNativeMenuDocListener);
4451
4419
+}
4452
4420
+
4453
 
+nsNativeMenuDocListener::~nsNativeMenuDocListener()
4454
 
+{
4455
 
+    MOZ_ASSERT(mContentToObserverTable.Count() == 0,
4456
 
+               "Some nodes forgot to unregister listeners. This is bad! (and we're lucky we made it this far)");
4457
 
+    MOZ_COUNT_DTOR(nsNativeMenuDocListener);
4458
 
+}
4459
 
+
4460
 
+nsresult
4461
 
+nsNativeMenuDocListener::Init(nsIContent *aRootNode)
4462
 
+{
4463
 
+    NS_ENSURE_ARG(aRootNode);
4464
 
+
4465
 
+    mRootNode = aRootNode;
4466
 
+
4467
 
+    return NS_OK;
4468
 
+}
4469
 
+
4470
 
+void
4471
 
+nsNativeMenuDocListener::AttributeChanged(nsIDocument *aDocument,
4472
 
+                                          mozilla::dom::Element *aElement,
4473
 
+                                          int32_t aNameSpaceID,
4474
 
+                                          nsIAtom *aAttribute,
4475
 
+                                          int32_t aModType,
4476
 
+                                          const nsAttrValue* aOldValue)
4477
 
+{
4478
 
+    if (sUpdateDepth == 0) {
4479
 
+        DoAttributeChanged(aElement, aAttribute);
4480
 
+        return;
4481
 
+    }
4482
 
+
4483
 
+    MutationRecord *m = *mPendingMutations.AppendElement(new MutationRecord);
4484
 
+    m->mType = MutationRecord::eAttributeChanged;
4485
 
+    m->mTarget = aElement;
4486
 
+    m->mAttribute = aAttribute;
4487
 
+
4488
 
+    ScheduleFlush(this);
4489
 
+}
4490
 
+
4491
 
+void
4492
 
+nsNativeMenuDocListener::ContentAppended(nsIDocument *aDocument,
4493
 
+                                         nsIContent *aContainer,
4494
 
+                                         nsIContent *aFirstNewContent,
4495
 
+                                         int32_t aNewIndexInContainer)
4496
 
+{
4497
 
+    for (nsIContent *c = aFirstNewContent; c; c = c->GetNextSibling()) {
4498
 
+        ContentInserted(aDocument, aContainer, c, 0);
4499
 
+    }
4500
 
+}
4501
 
+
4502
 
+void
4503
 
+nsNativeMenuDocListener::ContentInserted(nsIDocument *aDocument,
4504
 
+                                         nsIContent *aContainer,
4505
 
+                                         nsIContent *aChild,
4506
 
+                                         int32_t aIndexInContainer)
4507
 
+{
4508
 
+    nsIContent *prevSibling = nsMenuContainer::GetPreviousSupportedSibling(aChild);
4509
 
+
4510
 
+    if (sUpdateDepth == 0) {
4511
 
+        DoContentInserted(aContainer, aChild, prevSibling);
4512
 
+        return;
4513
 
+    }
4514
 
+
4515
 
+    MutationRecord *m = *mPendingMutations.AppendElement(new MutationRecord);
4516
 
+    m->mType = MutationRecord::eContentInserted;
4517
 
+    m->mTarget = aContainer;
4518
 
+    m->mChild = aChild;
4519
 
+    m->mPrevSibling = prevSibling;
4520
 
+
4521
 
+    ScheduleFlush(this);
4522
 
+}
4523
 
+
4524
 
+void
4525
 
+nsNativeMenuDocListener::ContentRemoved(nsIDocument *aDocument,
4526
 
+                                        nsIContent *aContainer,
4527
 
+                                        nsIContent *aChild,
4528
 
+                                        int32_t aIndexInContainer,
4529
 
+                                        nsIContent *aPreviousSibling)
4530
 
+{
4531
 
+    if (sUpdateDepth == 0) {
4532
 
+        DoContentRemoved(aContainer, aChild);
4533
 
+        return;
4534
 
+    }
4535
 
+
4536
 
+    MutationRecord *m = *mPendingMutations.AppendElement(new MutationRecord);
4537
 
+    m->mType = MutationRecord::eContentRemoved;
4538
 
+    m->mTarget = aContainer;
4539
 
+    m->mChild = aChild;
4540
 
+
4541
 
+    ScheduleFlush(this);
4542
 
+}                                                           
4543
 
+
4544
 
+void
4545
 
+nsNativeMenuDocListener::NodeWillBeDestroyed(const nsINode *aNode)
4546
 
+{
4547
 
+    mDocument = nullptr;
4548
 
+}
4549
 
+
4550
 
+/* static */ already_AddRefed<nsNativeMenuDocListener>
4551
 
+nsNativeMenuDocListener::Create(nsIContent *aRootNode)
4552
 
+{
4553
 
+    RefPtr<nsNativeMenuDocListener> listener = new nsNativeMenuDocListener();
4554
 
+    if (NS_FAILED(listener->Init(aRootNode))) {
4555
 
+        return nullptr;
4556
 
+    }
4557
 
+
4558
 
+    return listener.forget();
4559
 
+}
4560
 
+
4561
4421
+void
4562
4422
+nsNativeMenuDocListener::RegisterForContentChanges(nsIContent *aContent,
4563
4423
+                                                   nsNativeMenuChangeObserver *aObserver)
4564
4424
+{
4565
 
+    NS_ASSERTION(aContent, "Need content parameter");
4566
 
+    NS_ASSERTION(aObserver, "Need observer parameter");
 
4425
+    MOZ_ASSERT(aContent, "Need content parameter");
 
4426
+    MOZ_ASSERT(aObserver, "Need observer parameter");
4567
4427
+    if (!aContent || !aObserver) {
4568
4428
+        return;
4569
4429
+    }
4570
4430
+
4571
4431
+    DebugOnly<nsNativeMenuChangeObserver *> old;
4572
 
+    NS_ASSERTION(!mContentToObserverTable.Get(aContent, &old) || old == aObserver,
4573
 
+                 "Multiple observers for the same content node are not supported");
 
4432
+    MOZ_ASSERT(!mContentToObserverTable.Get(aContent, &old) || old == aObserver,
 
4433
+               "Multiple observers for the same content node are not supported");
4574
4434
+
4575
4435
+    mContentToObserverTable.Put(aContent, aObserver);
4576
4436
+}
4578
4438
+void
4579
4439
+nsNativeMenuDocListener::UnregisterForContentChanges(nsIContent *aContent)
4580
4440
+{
4581
 
+    NS_ASSERTION(aContent, "Need content parameter");
 
4441
+    MOZ_ASSERT(aContent, "Need content parameter");
4582
4442
+    if (!aContent) {
4583
4443
+        return;
4584
4444
+    }
4616
4476
+    CancelFlush(this);
4617
4477
+    mPendingMutations.Clear();
4618
4478
+}
4619
 
Index: firefox-52.0~b9+build2/widget/gtk/nsNativeMenuDocListener.h
 
4479
Index: firefox-53.0~a2~hg20170302r359591/widget/gtk/nsNativeMenuDocListener.h
4620
4480
===================================================================
4621
4481
--- /dev/null
4622
 
+++ firefox-52.0~b9+build2/widget/gtk/nsNativeMenuDocListener.h
4623
 
@@ -0,0 +1,153 @@
 
4482
+++ firefox-53.0~a2~hg20170302r359591/widget/gtk/nsNativeMenuDocListener.h
 
4483
@@ -0,0 +1,152 @@
4624
4484
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
4625
4485
+/* vim:expandtab:shiftwidth=4:tabstop=4:
4626
4486
+ */
4652
4512
+{
4653
4513
+public:
4654
4514
+    NS_DECL_ISUPPORTS
4655
 
+    NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTECHANGED
4656
 
+    NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED
4657
 
+    NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED
4658
 
+    NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED
4659
 
+    NS_DECL_NSIMUTATIONOBSERVER_NODEWILLBEDESTROYED
4660
4515
+
4661
 
+    static already_AddRefed<nsNativeMenuDocListener> Create(nsIContent *aRootNode);
 
4516
+    nsNativeMenuDocListener(nsIContent *aRootNode);
4662
4517
+
4663
4518
+    // Register an observer to receive mutation events for the specified
4664
4519
+    // content node. The caller must keep the observer alive until
4677
4532
+    // to registered observers.
4678
4533
+    void Stop();
4679
4534
+
 
4535
+    /*
 
4536
+     * This class is intended to be used inside GObject signal handlers.
 
4537
+     * It allows us to queue updates until we have finished delivering
 
4538
+     * events to Gecko, and then we can batch updates to our view of the
 
4539
+     * menu. This allows us to do menu updates without altering the structure
 
4540
+     * seen by the OS.
 
4541
+     */
 
4542
+    class MOZ_STACK_CLASS BlockUpdatesScope
 
4543
+    {
 
4544
+    public:
 
4545
+        BlockUpdatesScope(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM)
 
4546
+        {
 
4547
+            MOZ_GUARD_OBJECT_NOTIFIER_INIT;
 
4548
+            nsNativeMenuDocListener::AddUpdateBlocker();
 
4549
+        }
 
4550
+
 
4551
+        ~BlockUpdatesScope()
 
4552
+        {
 
4553
+            nsNativeMenuDocListener::RemoveUpdateBlocker();
 
4554
+        }
 
4555
+
 
4556
+    private:
 
4557
+        MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
 
4558
+    };
 
4559
+
4680
4560
+private:
4681
 
+    friend class nsNativeMenuAutoUpdateBatch;
4682
4561
+    friend class DispatchHelper;
4683
4562
+
4684
4563
+    struct MutationRecord {
4694
4573
+        nsCOMPtr<nsIAtom> mAttribute;
4695
4574
+    };
4696
4575
+
4697
 
+    nsNativeMenuDocListener();
4698
4576
+    ~nsNativeMenuDocListener();
4699
 
+    nsresult Init(nsIContent *aRootNode);
 
4577
+
 
4578
+    NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTECHANGED
 
4579
+    NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED
 
4580
+    NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED
 
4581
+    NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED
 
4582
+    NS_DECL_NSIMUTATIONOBSERVER_NODEWILLBEDESTROYED
4700
4583
+
4701
4584
+    void DoAttributeChanged(nsIContent *aContent, nsIAtom *aAttribute);
4702
4585
+    void DoContentInserted(nsIContent *aContainer,
4703
4586
+                           nsIContent *aChild,
4704
4587
+                           nsIContent *aPrevSibling);
4705
4588
+    void DoContentRemoved(nsIContent *aContainer, nsIContent *aChild);
4706
 
+    void DoBeginUpdateBatch(nsIContent *aTarget);
4707
 
+    void DoEndUpdateBatch(nsIContent *aTarget);
 
4589
+    void DoBeginUpdates(nsIContent *aTarget);
 
4590
+    void DoEndUpdates(nsIContent *aTarget);
 
4591
+
4708
4592
+    void FlushPendingMutations();
4709
4593
+    static void ScheduleFlush(nsNativeMenuDocListener *aListener);
4710
4594
+    static void CancelFlush(nsNativeMenuDocListener *aListener);
4711
 
+    static void BeginUpdates() { ++sUpdateDepth; }
4712
 
+    static void EndUpdates();
 
4595
+
 
4596
+    static void AddUpdateBlocker() { ++sUpdateBlockersCount; }
 
4597
+    static void RemoveUpdateBlocker();
4713
4598
+
4714
4599
+    nsCOMPtr<nsIContent> mRootNode;
4715
4600
+    nsIDocument *mDocument;
4716
4601
+    nsIContent *mLastSource;
4717
4602
+    nsNativeMenuChangeObserver *mLastTarget;
4718
4603
+    nsTArray<nsAutoPtr<MutationRecord> > mPendingMutations;
4719
 
+    nsDataHashtable<nsPtrHashKey<nsIContent>, nsNativeMenuChangeObserver*> mContentToObserverTable;
 
4604
+    nsDataHashtable<nsPtrHashKey<nsIContent>, nsNativeMenuChangeObserver *> mContentToObserverTable;
4720
4605
+
4721
 
+    static uint32_t sUpdateDepth;
 
4606
+    static uint32_t sUpdateBlockersCount;
4722
4607
+};
4723
4608
+
4724
4609
+typedef nsTArray<RefPtr<nsNativeMenuDocListener> > nsNativeMenuDocListenerTArray;
4725
4610
+
 
4611
+/*
 
4612
+ * Implemented by classes that want to listen to mutation events from content
 
4613
+ * nodes.
 
4614
+ */
4726
4615
+class nsNativeMenuChangeObserver
4727
4616
+{
4728
4617
+public:
4729
 
+    virtual void OnAttributeChanged(nsIContent *aContent, nsIAtom *aAttribute)
4730
 
+    {
4731
 
+        NS_ERROR("Unhandled AttributeChanged() notification");
4732
 
+    }
 
4618
+    virtual void OnAttributeChanged(nsIContent *aContent, nsIAtom *aAttribute) {}
4733
4619
+
4734
4620
+    virtual void OnContentInserted(nsIContent *aContainer,
4735
4621
+                                   nsIContent *aChild,
4736
 
+                                   nsIContent *aPrevSibling)
4737
 
+    {
4738
 
+        NS_ERROR("Unhandled ContentInserted() notification");
4739
 
+    }
4740
 
+
4741
 
+    virtual void OnContentRemoved(nsIContent *aContainer, nsIContent *aChild)
4742
 
+    {
4743
 
+        NS_ERROR("Unhandled ContentRemoved() notification");
4744
 
+    }
4745
 
+
4746
 
+    virtual void BeginUpdateBatch(nsIContent *aContent) { };
4747
 
+
4748
 
+    virtual void EndUpdateBatch() { };
4749
 
+};
4750
 
+
4751
 
+/*
4752
 
+ * This class is intended to be used inside GObject signal handlers.
4753
 
+ * It allows us to queue updates until we have finished delivering
4754
 
+ * events to Gecko, and then we can batch updates to our view of the
4755
 
+ * menu. This allows us to do menu updates without altering the structure
4756
 
+ * seen by the OS.
4757
 
+ */
4758
 
+class MOZ_STACK_CLASS nsNativeMenuAutoUpdateBatch
4759
 
+{
4760
 
+public:
4761
 
+    nsNativeMenuAutoUpdateBatch(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM)
4762
 
+    {
4763
 
+        MOZ_GUARD_OBJECT_NOTIFIER_INIT;
4764