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");
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"
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);
50
pref("ui.use_native_colors", true);
51
+#ifdef MOZ_WIDGET_GTK
52
+pref("ui.use_unity_menubar", true);
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
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"]
72
99
-moz-binding: url("chrome://global/content/bindings/toolbar.xml#toolbardecoration");
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 += [
107
'nsBidiKeyboard.cpp',
112
'nsImageToPixbuf.cpp',
115
+ 'nsMenuContainer.cpp',
117
+ 'nsMenuObject.cpp',
118
+ 'nsMenuSeparator.cpp',
119
+ 'nsNativeMenuAtoms.cpp',
120
+ 'nsNativeMenuDocListener.cpp',
121
'nsNativeThemeGTK.cpp',
123
'nsScreenManagerGtk.cpp',
124
@@ -40,6 +48,8 @@ UNIFIED_SOURCES += [
128
+ 'nsMenu.cpp', # conflicts with X11 headers
129
+ 'nsNativeMenuService.cpp',
130
'nsWindow.cpp', # conflicts with X11 headers
133
@@ -104,6 +114,7 @@ FINAL_LIBRARY = 'xul'
139
'/other-licenses/atk-1.0',
141
Index: firefox-53.0~a2~hg20170302r359591/widget/gtk/nsDbusmenu.cpp
75
142
===================================================================
77
+++ firefox-52.0~b9+build2/widget/gtk/nsDbusmenu.cpp
144
+++ firefox-53.0~a2~hg20170302r359591/widget/gtk/nsDbusmenu.cpp
79
146
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
80
147
+/* vim:expandtab:shiftwidth=4:tabstop=4:
291
362
+using namespace mozilla;
293
+class MOZ_STACK_CLASS nsMenuUpdateBatch
296
+ nsMenuUpdateBatch(nsMenu *aMenu MOZ_GUARD_OBJECT_NOTIFIER_PARAM) :
299
+ MOZ_GUARD_OBJECT_NOTIFIER_INIT;
300
+ mMenu->BeginUpdateBatchInternal();
303
+ ~nsMenuUpdateBatch()
305
+ mMenu->EndUpdateBatch();
309
+ MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
313
+class nsSetAttrRunnableNoNotify : public Runnable
316
+ nsSetAttrRunnableNoNotify(nsIContent *aContent, nsIAtom *aAttribute,
317
+ nsAString& aValue) :
318
+ mContent(aContent), mAttribute(aAttribute), mValue(aValue) { };
320
+ NS_IMETHODIMP Run()
322
+ return mContent->SetAttr(kNameSpaceID_None, mAttribute, mValue, false);
326
+ nsCOMPtr<nsIContent> mContent;
327
+ nsCOMPtr<nsIAtom> mAttribute;
328
+ nsAutoString mValue;
331
+class nsUnsetAttrRunnableNoNotify : public Runnable
334
+ nsUnsetAttrRunnableNoNotify(nsIContent *aContent, nsIAtom *aAttribute) :
335
+ mContent(aContent), mAttribute(aAttribute) { };
337
+ NS_IMETHODIMP Run()
339
+ return mContent->UnsetAttr(kNameSpaceID_None, mAttribute, false);
343
+ nsCOMPtr<nsIContent> mContent;
344
+ nsCOMPtr<nsIAtom> mAttribute;
364
+class nsMenuContentInsertedEvent : public Runnable
367
+ nsMenuContentInsertedEvent(nsMenu *aMenu,
368
+ nsIContent *aContainer,
369
+ nsIContent *aChild,
370
+ nsIContent *aPrevSibling) :
372
+ mContainer(aContainer),
374
+ mPrevSibling(aPrevSibling) { }
376
+ NS_IMETHODIMP Run()
382
+ static_cast<nsMenu *>(mWeakMenu.get())->HandleContentInserted(mContainer,
389
+ nsWeakMenuObject mWeakMenu;
391
+ nsCOMPtr<nsIContent> mContainer;
392
+ nsCOMPtr<nsIContent> mChild;
393
+ nsCOMPtr<nsIContent> mPrevSibling;
396
+class nsMenuContentRemovedEvent : public Runnable
399
+ nsMenuContentRemovedEvent(nsMenu *aMenu,
400
+ nsIContent *aContainer,
401
+ nsIContent *aChild) :
403
+ mContainer(aContainer),
406
+ NS_IMETHODIMP Run()
412
+ static_cast<nsMenu *>(mWeakMenu.get())->HandleContentRemoved(mContainer,
418
+ nsWeakMenuObject mWeakMenu;
420
+ nsCOMPtr<nsIContent> mContainer;
421
+ nsCOMPtr<nsIContent> mChild;
425
+DispatchMouseEvent(nsIContent *aTarget, mozilla::EventMessage aMsg)
431
+ WidgetMouseEvent event(true, aMsg, nullptr, WidgetMouseEvent::eReal);
432
+ aTarget->DispatchDOMEvent(&event, nullptr, nullptr, nullptr);
348
436
+AttachXBLBindings(nsIContent *aContent)
410
+ if (nsContentUtils::IsSafeToRunScript()) {
411
+ if (state.IsEmpty()) {
412
+ mPopupContent->UnsetAttr(kNameSpaceID_None,
413
+ nsNativeMenuAtoms::_moz_menupopupstate,
416
+ mPopupContent->SetAttr(kNameSpaceID_None,
417
+ nsNativeMenuAtoms::_moz_menupopupstate,
497
+ if (state.IsEmpty()) {
498
+ mPopupContent->UnsetAttr(kNameSpaceID_None,
499
+ nsNativeMenuAtoms::_moz_nativemenupopupstate,
421
+ nsCOMPtr<nsIRunnable> r;
422
+ if (state.IsEmpty()) {
423
+ r = new nsUnsetAttrRunnableNoNotify(
424
+ mPopupContent, nsNativeMenuAtoms::_moz_menupopupstate);
426
+ r = new nsSetAttrRunnableNoNotify(
427
+ mPopupContent, nsNativeMenuAtoms::_moz_menupopupstate,
430
+ nsContentUtils::AddScriptRunner(r);
502
+ mPopupContent->SetAttr(kNameSpaceID_None,
503
+ nsNativeMenuAtoms::_moz_nativemenupopupstate,
434
508
+/* static */ void
509
+nsMenu::DoOpenCallback(nsITimer *aTimer, void *aClosure)
511
+ nsMenu* self = static_cast<nsMenu *>(aClosure);
513
+ dbusmenu_menuitem_show_to_user(self->GetNativeData(), 0);
515
+ self->mOpenDelayTimer = nullptr;
435
519
+nsMenu::menu_event_cb(DbusmenuMenuitem *menu,
436
520
+ const gchar *name,
437
521
+ GVariant *value,
457
541
+nsMenu::MaybeAddPlaceholderItem()
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");
462
546
+ GList *children = dbusmenu_menuitem_get_children(GetNativeData());
463
547
+ if (!children) {
464
+ NS_ASSERTION(!HasPlaceholderItem(), "Huh?");
466
+ DbusmenuMenuitem *ph = dbusmenu_menuitem_new();
471
+ dbusmenu_menuitem_property_set_bool(
472
+ ph, DBUSMENU_MENUITEM_PROP_VISIBLE, false);
474
+ if (!dbusmenu_menuitem_child_append(GetNativeData(), ph)) {
475
+ NS_WARNING("Failed to create placeholder item");
476
+ g_object_unref(ph);
480
+ g_object_unref(ph);
482
+ SetHasPlaceholderItem(true);
548
+ MOZ_ASSERT(!mPlaceholderItem);
550
+ mPlaceholderItem = dbusmenu_menuitem_new();
551
+ if (!mPlaceholderItem) {
555
+ dbusmenu_menuitem_property_set_bool(mPlaceholderItem,
556
+ DBUSMENU_MENUITEM_PROP_VISIBLE,
560
+ dbusmenu_menuitem_child_append(GetNativeData(), mPlaceholderItem));
487
565
+nsMenu::EnsureNoPlaceholderItem()
489
+ NS_ASSERTION(!IsInUpdateBatch(),
490
+ "Shouldn't be modifying the native menu structure now");
492
+ if (HasPlaceholderItem()) {
493
+ GList *children = dbusmenu_menuitem_get_children(GetNativeData());
495
+ NS_ASSERTION(g_list_length(children) == 1,
496
+ "Unexpected number of children in native menu (should be 1!)");
498
+ SetHasPlaceholderItem(false);
504
+ if (!dbusmenu_menuitem_child_delete(
505
+ GetNativeData(), static_cast<DbusmenuMenuitem *>(children->data))) {
506
+ NS_ERROR("Failed to remove placeholder item");
515
+DispatchMouseEvent(nsIContent *aTarget, mozilla::EventMessage aMsg)
567
+ MOZ_ASSERT(!IsInBatchedUpdate(),
568
+ "Shouldn't be modifying the native menu structure now");
570
+ if (!mPlaceholderItem) {
521
+ WidgetMouseEvent event(true, aMsg, nullptr, WidgetMouseEvent::eReal);
522
+ aTarget->DispatchDOMEvent(&event, nullptr, nullptr, nullptr);
575
+ dbusmenu_menuitem_child_delete(GetNativeData(), mPlaceholderItem));
576
+ MOZ_ASSERT(!dbusmenu_menuitem_get_children(GetNativeData()));
578
+ g_object_unref(mPlaceholderItem);
579
+ mPlaceholderItem = nullptr;
526
583
+nsMenu::OnOpen()
528
+ if (NeedsRebuild()) {
585
+ if (mNeedsRebuild) {
532
+ nsWeakMenuObject<nsMenu> self(this);
589
+ nsWeakMenuObject self(this);
533
590
+ nsCOMPtr<nsIContent> origPopupContent(mPopupContent);
535
+ nsNativeMenuAutoUpdateBatch batch;
592
+ nsNativeMenuDocListener::BlockUpdatesScope updatesBlocker;
537
594
+ SetPopupState(ePopupState_Showing);
538
595
+ DispatchMouseEvent(mPopupContent, eXULPopupShowing);
583
638
+ for (uint32_t i = 0; i < count; ++i) {
584
639
+ nsIContent *childContent = mPopupContent->GetChildAt(i);
587
+ nsMenuObject *child = CreateChild(childContent, &rv);
590
+ rv = AppendChild(child);
593
+ if (NS_FAILED(rv)) {
594
+ NS_ERROR("Menu build failed");
595
+ SetNeedsRebuild(true);
641
+ UniquePtr<nsMenuObject> child = CreateChild(childContent);
647
+ AppendChild(Move(child));
602
+nsMenu::InitializeNativeData()
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);
615
+ UpdateSensitivity();
617
+ SetNeedsRebuild(true);
618
+ MaybeAddPlaceholderItem();
620
+ AttachXBLBindings(ContentNode());
624
+nsMenu::Update(nsStyleContext *aStyleContext)
626
+ UpdateVisibility(aStyleContext);
627
+ UpdateIcon(aStyleContext);
631
652
+nsMenu::InitializePopup()
633
654
+ nsCOMPtr<nsIContent> oldPopupContent;
669
+nsMenu::BeginUpdateBatchInternal()
671
+ NS_ASSERTION(!IsInUpdateBatch(), "Already in an update batch!");
673
+ SetIsInUpdateBatch(true);
674
+ SetDidStructureMutate(false);
678
690
+nsMenu::RemoveChildAt(size_t aIndex)
680
+ NS_ASSERTION(IsInUpdateBatch() || !HasPlaceholderItem(),
681
+ "Shouldn't have a placeholder menuitem");
683
+ SetDidStructureMutate(true);
685
+ nsresult rv = nsMenuContainer::RemoveChildAt(aIndex, !IsInUpdateBatch());
687
+ if (!IsInUpdateBatch()) {
692
+ MOZ_ASSERT(IsInBatchedUpdate() || !mPlaceholderItem,
693
+ "Shouldn't have a placeholder menuitem");
695
+ nsMenuContainer::RemoveChildAt(aIndex, !IsInBatchedUpdate());
696
+ StructureMutated();
698
+ if (!IsInBatchedUpdate()) {
688
699
+ MaybeAddPlaceholderItem();
695
704
+nsMenu::RemoveChild(nsIContent *aChild)
697
706
+ size_t index = IndexOf(aChild);
698
707
+ if (index == NoIndex) {
699
+ return NS_ERROR_INVALID_ARG;
702
+ return RemoveChildAt(index);
706
+nsMenu::InsertChildAfter(nsMenuObject *aChild, nsIContent *aPrevSibling)
708
+ if (!IsInUpdateBatch() && !EnsureNoPlaceholderItem()) {
709
+ return NS_ERROR_FAILURE;
712
+ SetDidStructureMutate(true);
714
+ return nsMenuContainer::InsertChildAfter(aChild, aPrevSibling,
715
+ !IsInUpdateBatch());
719
+nsMenu::AppendChild(nsMenuObject *aChild)
721
+ if (!IsInUpdateBatch() && !EnsureNoPlaceholderItem()) {
722
+ return NS_ERROR_FAILURE;
725
+ SetDidStructureMutate(true);
727
+ return nsMenuContainer::AppendChild(aChild, !IsInUpdateBatch());
711
+ RemoveChildAt(index);
715
+nsMenu::InsertChildAfter(UniquePtr<nsMenuObject> aChild,
716
+ nsIContent *aPrevSibling)
718
+ if (!IsInBatchedUpdate()) {
719
+ EnsureNoPlaceholderItem();
722
+ nsMenuContainer::InsertChildAfter(Move(aChild), aPrevSibling,
723
+ !IsInBatchedUpdate());
724
+ StructureMutated();
728
+nsMenu::AppendChild(UniquePtr<nsMenuObject> aChild)
730
+ if (!IsInBatchedUpdate()) {
731
+ EnsureNoPlaceholderItem();
734
+ nsMenuContainer::AppendChild(Move(aChild), !IsInBatchedUpdate());
735
+ StructureMutated();
739
+nsMenu::IsInBatchedUpdate() const
741
+ return mBatchedUpdateState != eBatchedUpdateState_Inactive;
745
+nsMenu::StructureMutated()
747
+ if (!IsInBatchedUpdate()) {
751
+ mBatchedUpdateState = eBatchedUpdateState_DidMutate;
740
764
+ return (isVisible && !isDisabled);
768
+nsMenu::HandleContentInserted(nsIContent *aContainer,
769
+ nsIContent *aChild,
770
+ nsIContent *aPrevSibling)
772
+ if (aContainer == mPopupContent) {
773
+ UniquePtr<nsMenuObject> child = CreateChild(aChild);
776
+ InsertChildAfter(Move(child), aPrevSibling);
784
+nsMenu::HandleContentRemoved(nsIContent *aContainer, nsIContent *aChild)
786
+ if (aContainer == mPopupContent) {
787
+ RemoveChild(aChild);
794
+nsMenu::InitializeNativeData()
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);
806
+ mNeedsRebuild = true;
807
+ mNeedsUpdate = true;
809
+ MaybeAddPlaceholderItem();
811
+ AttachXBLBindings(ContentNode());
815
+nsMenu::Update(nsStyleContext *aStyleContext)
817
+ if (mNeedsUpdate) {
818
+ mNeedsUpdate = false;
821
+ UpdateSensitivity();
824
+ UpdateVisibility(aStyleContext);
825
+ UpdateIcon(aStyleContext);
743
828
+nsMenuObject::PropertyFlags
744
829
+nsMenu::SupportedProperties() const
758
+ MOZ_COUNT_CTOR(nsMenu);
763
+ if (IsInUpdateBatch()) {
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) {
774
+ EnsureNoPlaceholderItem();
776
+ if (DocListener() && mPopupContent) {
777
+ DocListener()->UnregisterForContentChanges(mPopupContent);
780
+ if (GetNativeData()) {
781
+ g_signal_handlers_disconnect_by_func(GetNativeData(),
782
+ FuncToGpointer(menu_event_cb),
786
+ MOZ_COUNT_DTOR(nsMenu);
789
+/* static */ nsMenuObject*
790
+nsMenu::Create(nsMenuContainer *aParent, nsIContent *aContent)
792
+ nsAutoPtr<nsMenu> menu(new nsMenu());
793
+ if (NS_FAILED(menu->Init(aParent, aContent))) {
797
+ return menu.forget();
801
+DoOpen(nsITimer *aTimer, void *aClosure)
803
+ nsAutoWeakMenuObject<nsMenu> weakMenu(
804
+ static_cast<nsWeakMenuObject<nsMenu> *>(aClosure));
807
+ dbusmenu_menuitem_show_to_user(weakMenu->GetNativeData(), 0);
810
+ NS_RELEASE(aTimer);
814
+nsMenu::Type() const
816
+ return nsMenuObject::eType_Menu;
820
+nsMenu::IsBeingDisplayed() const
822
+ return PopupState() == ePopupState_Open;
826
+nsMenu::NeedsRebuild() const
828
+ return HasFlags(eFlag_NeedsRebuild);
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
846
+ nsCOMPtr<nsITimer> timer = do_CreateInstance(NS_TIMER_CONTRACTID);
851
+ nsAutoWeakMenuObject<nsMenu> weakMenu(this);
853
+ if (NS_FAILED(timer->InitWithFuncCallback(DoOpen, weakMenu.getWeakPtr(),
854
+ 100, nsITimer::TYPE_ONE_SHOT))) {
865
+ if (PopupState() == ePopupState_Closed) {
869
+ // We do this to avoid mutating our view of the menu until
870
+ // after we have finished
871
+ nsNativeMenuAutoUpdateBatch batch;
873
+ SetPopupState(ePopupState_Hiding);
874
+ DispatchMouseEvent(mPopupContent, eXULPopupHiding);
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
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();
886
+ SetPopupState(ePopupState_Closed);
887
+ DispatchMouseEvent(mPopupContent, eXULPopupHidden);
889
+ ContentNode()->UnsetAttr(kNameSpaceID_None, nsGkAtoms::open, true);
893
841
+nsMenu::OnAttributeChanged(nsIContent *aContent, nsIAtom *aAttribute)
895
+ NS_ASSERTION(aContent == ContentNode() || aContent == mPopupContent,
896
+ "Received an event that wasn't meant for us!");
898
+ if (aAttribute == nsGkAtoms::open) {
902
+ if (Parent()->NeedsRebuild()) {
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) {
916
+ if (!Parent()->IsBeingDisplayed() || aContent != ContentNode()) {
920
+ if (aAttribute == nsGkAtoms::hidden ||
843
+ MOZ_ASSERT(aContent == ContentNode() || aContent == mPopupContent,
844
+ "Received an event that wasn't meant for us!");
846
+ if (mNeedsUpdate) {
850
+ if (aContent != ContentNode()) {
854
+ if (!Parent()->IsBeingDisplayed()) {
855
+ mNeedsUpdate = true;
859
+ if (aAttribute == nsGkAtoms::disabled) {
860
+ UpdateSensitivity();
861
+ } else if (aAttribute == nsGkAtoms::label ||
862
+ aAttribute == nsGkAtoms::accesskey ||
863
+ aAttribute == nsGkAtoms::crop) {
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)
934
+ NS_ASSERTION(aContainer == ContentNode() || aContainer == mPopupContent,
935
+ "Received an event that wasn't meant for us!");
937
+ if (NeedsRebuild()) {
941
+ if (PopupState() == ePopupState_Closed) {
942
+ SetNeedsRebuild(true);
946
+ if (aContainer == mPopupContent) {
948
+ nsMenuObject *child = CreateChild(aChild, &rv);
951
+ rv = InsertChildAfter(child, aPrevSibling);
953
+ if (NS_FAILED(rv)) {
954
+ NS_ERROR("OnContentInserted() failed");
955
+ SetNeedsRebuild(true);
879
+ MOZ_ASSERT(aContainer == ContentNode() || aContainer == mPopupContent,
880
+ "Received an event that wasn't meant for us!");
882
+ if (mNeedsRebuild) {
886
+ if (mPopupState == ePopupState_Closed) {
887
+ mNeedsRebuild = true;
891
+ nsContentUtils::AddScriptRunner(
892
+ new nsMenuContentInsertedEvent(this, aContainer, aChild,
963
897
+nsMenu::OnContentRemoved(nsIContent *aContainer, nsIContent *aChild)
965
+ NS_ASSERTION(aContainer == ContentNode() || aContainer == mPopupContent,
966
+ "Received an event that wasn't meant for us!");
968
+ if (NeedsRebuild()) {
972
+ if (PopupState() == ePopupState_Closed) {
973
+ SetNeedsRebuild(true);
977
+ if (aContainer == mPopupContent) {
978
+ if (NS_FAILED(RemoveChild(aChild))) {
979
+ NS_ERROR("OnContentRemoved() failed");
980
+ SetNeedsRebuild(true);
899
+ MOZ_ASSERT(aContainer == ContentNode() || aContainer == mPopupContent,
900
+ "Received an event that wasn't meant for us!");
902
+ if (mNeedsRebuild) {
906
+ if (mPopupState == ePopupState_Closed) {
907
+ mNeedsRebuild = true;
911
+ nsContentUtils::AddScriptRunner(
912
+ new nsMenuContentRemovedEvent(this, aContainer, aChild));
1001
+nsMenu::BeginUpdateBatch(nsIContent *aContent)
929
+nsMenu::OnBeginUpdates(nsIContent *aContent)
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!");
1006
+ if (aContent == mPopupContent) {
1007
+ BeginUpdateBatchInternal();
935
+ if (aContent != mPopupContent) {
939
+ mBatchedUpdateState = eBatchedUpdateState_Active;
1012
+nsMenu::EndUpdateBatch()
943
+nsMenu::OnEndUpdates()
1014
+ NS_ASSERTION(IsInUpdateBatch(), "Not in an update batch");
945
+ if (!IsInBatchedUpdate()) {
1016
+ SetIsInUpdateBatch(false);
949
+ bool didMutate = mBatchedUpdateState == eBatchedUpdateState_DidMutate;
950
+ mBatchedUpdateState = eBatchedUpdateState_Inactive;
1018
952
+ /* Optimize for the case where we only had attribute changes */
1019
+ if (!DidStructureMutate()) {
1023
+ if (!EnsureNoPlaceholderItem()) {
1024
+ SetNeedsRebuild(true);
957
+ EnsureNoPlaceholderItem();
1028
959
+ GList *nextNativeChild = dbusmenu_menuitem_get_children(GetNativeData());
1029
960
+ DbusmenuMenuitem *nextOwnedNativeChild = nullptr;
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(),
1096
+ NS_ERROR("Failed to add new native item");
1097
+ SetNeedsRebuild(true);
1022
+ dbusmenu_menuitem_child_add_position(GetNativeData(),
1023
+ child->GetNativeData(),
1104
1029
+ while (nextNativeChild) {
1106
1030
+ DbusmenuMenuitem *data =
1107
1031
+ static_cast<DbusmenuMenuitem *>(nextNativeChild->data);
1108
1032
+ nextNativeChild = nextNativeChild->next;
1110
+ if (!dbusmenu_menuitem_child_delete(GetNativeData(), data)) {
1111
+ NS_ERROR("Failed to remove orphaned native item from menu");
1112
+ SetNeedsRebuild(true);
1034
+ MOZ_ALWAYS_TRUE(dbusmenu_menuitem_child_delete(GetNativeData(), data));
1037
+ MaybeAddPlaceholderItem();
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)
1048
+ MOZ_COUNT_CTOR(nsMenu);
1053
+ if (IsInBatchedUpdate()) {
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) {
1064
+ EnsureNoPlaceholderItem();
1066
+ if (DocListener() && mPopupContent) {
1067
+ DocListener()->UnregisterForContentChanges(mPopupContent);
1070
+ if (GetNativeData()) {
1071
+ g_signal_handlers_disconnect_by_func(GetNativeData(),
1072
+ FuncToGpointer(menu_event_cb),
1076
+ MOZ_COUNT_DTOR(nsMenu);
1079
+nsMenuObject::EType
1080
+nsMenu::Type() const
1082
+ return eType_Menu;
1086
+nsMenu::IsBeingDisplayed() const
1088
+ return mPopupState == ePopupState_Open;
1092
+nsMenu::NeedsRebuild() const
1094
+ return mNeedsRebuild;
1104
+ if (mOpenDelayTimer) {
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
1116
+ mOpenDelayTimer = do_CreateInstance(NS_TIMER_CONTRACTID);
1117
+ if (!mOpenDelayTimer) {
1121
+ if (NS_FAILED(mOpenDelayTimer->InitWithFuncCallback(DoOpenCallback,
1124
+ nsITimer::TYPE_ONE_SHOT))) {
1125
+ mOpenDelayTimer = nullptr;
1132
+ if (mPopupState == ePopupState_Closed) {
1136
+ MOZ_ASSERT(nsContentUtils::IsSafeToRunScript());
1138
+ // We do this to avoid mutating our view of the menu until
1139
+ // after we have finished
1140
+ nsNativeMenuDocListener::BlockUpdatesScope updatesBlocker;
1142
+ SetPopupState(ePopupState_Hiding);
1143
+ DispatchMouseEvent(mPopupContent, eXULPopupHiding);
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
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();
1117
+ MaybeAddPlaceholderItem();
1155
+ SetPopupState(ePopupState_Closed);
1156
+ DispatchMouseEvent(mPopupContent, eXULPopupHidden);
1158
+ ContentNode()->UnsetAttr(kNameSpaceID_None, nsGkAtoms::open, true);
1119
Index: firefox-52.0~b9+build2/widget/gtk/nsMenu.h
1161
Index: firefox-53.0~a2~hg20170302r359591/widget/gtk/nsMenu.h
1120
1162
===================================================================
1122
+++ firefox-52.0~b9+build2/widget/gtk/nsMenu.h
1164
+++ firefox-53.0~a2~hg20170302r359591/widget/gtk/nsMenu.h
1124
1166
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
1125
1167
+/* vim:expandtab:shiftwidth=4:tabstop=4:
1168
1210
+ // menuitems can do the shells work. Sigh....
1169
1211
+ void OnClose();
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();
1179
+ friend class nsMenuUpdateBatch;
1182
+ // This menu needs rebuilding the next time it is opened
1183
+ eFlag_NeedsRebuild = 1 << 0,
1185
+ // This menu contains a placeholder
1186
+ eFlag_HasPlaceholderItem = 1 << 1,
1188
+ // This menu is currently receiving a batch of updates, and
1189
+ // the native structure should not be modified
1190
+ eFlag_InUpdateBatch = 1 << 2,
1192
+ // Children were added to / removed from this menu (only valid
1193
+ // when eFlag_InUpdateBatch is set)
1194
+ eFlag_StructureMutated = 1 << 3
1214
+ friend class nsMenuContentInsertedEvent;
1215
+ friend class nsMenuContentRemovedEvent;
1197
1217
+ enum EPopupState {
1198
1218
+ ePopupState_Closed,
1201
1221
+ ePopupState_Hiding
1206
+ void SetNeedsRebuild(bool aValue)
1209
+ SetFlags(eFlag_NeedsRebuild);
1211
+ ClearFlags(eFlag_NeedsRebuild);
1214
+ bool HasPlaceholderItem() const
1216
+ return HasFlags(eFlag_HasPlaceholderItem);
1218
+ void SetHasPlaceholderItem(bool aValue)
1221
+ SetFlags(eFlag_HasPlaceholderItem);
1223
+ ClearFlags(eFlag_HasPlaceholderItem);
1227
+ bool IsInUpdateBatch() const
1229
+ return HasFlags(eFlag_InUpdateBatch);
1231
+ void SetIsInUpdateBatch(bool aValue)
1234
+ SetFlags(eFlag_InUpdateBatch);
1236
+ ClearFlags(eFlag_InUpdateBatch);
1240
+ bool DidStructureMutate() const
1242
+ return HasFlags(eFlag_StructureMutated);
1244
+ void SetDidStructureMutate(bool aValue)
1247
+ SetFlags(eFlag_StructureMutated);
1249
+ ClearFlags(eFlag_StructureMutated);
1253
+ EPopupState PopupState() const
1255
+ return static_cast<EPopupState>(
1257
+ (((1U << NSMENU_NUMBER_OF_POPUPSTATE_BITS) - 1U)
1258
+ << NSMENU_NUMBER_OF_FLAGS)) >> NSMENU_NUMBER_OF_FLAGS);
1260
1224
+ void SetPopupState(EPopupState aState);
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();
1237
+ // Removes a placeholder item if it exists and asserts that this succeeds
1238
+ void EnsureNoPlaceholderItem();
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;
1252
+ void HandleContentInserted(nsIContent *aContainer,
1253
+ nsIContent *aChild,
1254
+ nsIContent *aPrevSibling);
1255
+ void HandleContentRemoved(nsIContent *aContainer,
1256
+ nsIContent *aChild);
1258
+ void InitializeNativeData() override;
1259
+ void Update(nsStyleContext *aStyleContext) override;
1260
+ nsMenuObject::PropertyFlags SupportedProperties() const override;
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;
1269
+ bool mNeedsRebuild;
1270
+ bool mNeedsUpdate;
1272
+ DbusmenuMenuitem *mPlaceholderItem;
1274
+ EPopupState mPopupState;
1276
+ enum EBatchedUpdateState {
1277
+ eBatchedUpdateState_Inactive,
1278
+ eBatchedUpdateState_Active,
1279
+ eBatchedUpdateState_DidMutate
1282
+ EBatchedUpdateState mBatchedUpdateState;
1286
1284
+ nsCOMPtr<nsIContent> mPopupContent;
1286
+ nsCOMPtr<nsITimer> mOpenDelayTimer;
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
===================================================================
1293
+++ firefox-52.0~b9+build2/widget/gtk/nsMenuBar.cpp
1293
+++ firefox-53.0~a2~hg20170302r359591/widget/gtk/nsMenuBar.cpp
1295
1295
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
1296
1296
+/* vim:expandtab:shiftwidth=4:tabstop=4:
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/. */
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"
1326
1330
+using namespace mozilla;
1328
+class nsMenuBarDocEventListener final : public nsIDOMEventListener
1333
+ShouldHandleKeyEvent(nsIDOMEvent *aEvent)
1335
+ bool handled, trusted = false;
1336
+ aEvent->GetPreventDefault(&handled);
1337
+ aEvent->GetIsTrusted(&trusted);
1339
+ if (handled || !trusted) {
1346
+class nsMenuBarContentInsertedEvent : public Runnable
1349
+ nsMenuBarContentInsertedEvent(nsMenuBar *aMenuBar,
1350
+ nsIContent *aChild,
1351
+ nsIContent *aPrevSibling) :
1352
+ mWeakMenuBar(aMenuBar),
1354
+ mPrevSibling(aPrevSibling) { }
1356
+ NS_IMETHODIMP Run()
1358
+ if (!mWeakMenuBar) {
1362
+ static_cast<nsMenuBar *>(mWeakMenuBar.get())->HandleContentInserted(mChild,
1368
+ nsWeakMenuObject mWeakMenuBar;
1370
+ nsCOMPtr<nsIContent> mChild;
1371
+ nsCOMPtr<nsIContent> mPrevSibling;
1374
+class nsMenuBarContentRemovedEvent : public Runnable
1377
+ nsMenuBarContentRemovedEvent(nsMenuBar *aMenuBar,
1378
+ nsIContent *aChild) :
1379
+ mWeakMenuBar(aMenuBar),
1380
+ mChild(aChild) { }
1382
+ NS_IMETHODIMP Run()
1384
+ if (!mWeakMenuBar) {
1388
+ static_cast<nsMenuBar *>(mWeakMenuBar.get())->HandleContentRemoved(mChild);
1393
+ nsWeakMenuObject mWeakMenuBar;
1395
+ nsCOMPtr<nsIContent> mChild;
1398
+class nsMenuBar::DocEventListener final : public nsIDOMEventListener
1331
1401
+ NS_DECL_ISUPPORTS
1332
1402
+ NS_DECL_NSIDOMEVENTLISTENER
1334
+ nsMenuBarDocEventListener(nsMenuBar *aOwner) : mOwner(aOwner) { };
1404
+ DocEventListener(nsMenuBar *aOwner) : mOwner(aOwner) { };
1337
+ ~nsMenuBarDocEventListener() { };
1407
+ ~DocEventListener() { };
1339
1409
+ nsMenuBar *mOwner;
1342
+NS_IMPL_ISUPPORTS(nsMenuBarDocEventListener, nsIDOMEventListener)
1412
+NS_IMPL_ISUPPORTS(nsMenuBar::DocEventListener, nsIDOMEventListener)
1345
+nsMenuBarDocEventListener::HandleEvent(nsIDOMEvent *aEvent)
1415
+nsMenuBar::DocEventListener::HandleEvent(nsIDOMEvent *aEvent)
1347
1417
+ nsAutoString type;
1348
1418
+ nsresult rv = aEvent->GetType(type);
1439
+nsMenuBar::nsMenuBar(nsIContent *aMenuBarNode) :
1440
+ nsMenuContainer(new nsNativeMenuDocListener(aMenuBarNode), aMenuBarNode),
1441
+ mTopLevel(nullptr),
1445
+ MOZ_COUNT_CTOR(nsMenuBar);
1449
+nsMenuBar::Init(nsIWidget *aParent)
1451
+ MOZ_ASSERT(aParent);
1453
+ GdkWindow *gdkWin = static_cast<GdkWindow *>(
1454
+ aParent->GetNativeData(NS_NATIVE_WINDOW));
1456
+ return NS_ERROR_FAILURE;
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;
1465
+ mTopLevel = gtk_widget_get_toplevel(GTK_WIDGET(user_data));
1467
+ return NS_ERROR_FAILURE;
1470
+ g_object_ref(mTopLevel);
1472
+ nsAutoCString path;
1473
+ path.Append(NS_LITERAL_CSTRING("/com/canonical/menu/"));
1475
+ sprintf(xid, "%X", static_cast<uint32_t>(
1476
+ GDK_WINDOW_XID(gtk_widget_get_window(mTopLevel))));
1479
+ mServer = dbusmenu_server_new(path.get());
1481
+ return NS_ERROR_FAILURE;
1484
+ CreateNativeData();
1485
+ if (!GetNativeData()) {
1486
+ return NS_ERROR_FAILURE;
1489
+ dbusmenu_server_set_root(mServer, GetNativeData());
1491
+ mEventListener = new DocEventListener(this);
1493
+ mDocument = do_QueryInterface(ContentNode()->OwnerDoc());
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;
1505
+ mAccessKeyMask = eModifierAlt;
1370
1512
+nsMenuBar::Build()
1576
1700
+ return NS_OK;
1579
+nsMenuBar::nsMenuBar() :
1580
+ nsMenuContainer(),
1581
+ mTopLevel(nullptr),
1585
+ MOZ_COUNT_CTOR(nsMenuBar);
1589
+nsMenuBar::Init(nsIWidget *aParent, nsIContent *aMenuBarNode)
1591
+ NS_ENSURE_ARG(aParent);
1592
+ NS_ENSURE_ARG(aMenuBarNode);
1594
+ GdkWindow *gdkWin = static_cast<GdkWindow *>(
1595
+ aParent->GetNativeData(NS_NATIVE_WINDOW));
1597
+ return NS_ERROR_FAILURE;
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;
1606
+ mTopLevel = gtk_widget_get_toplevel(GTK_WIDGET(user_data));
1608
+ return NS_ERROR_FAILURE;
1611
+ g_object_ref(mTopLevel);
1613
+ RefPtr<nsNativeMenuDocListener> listener =
1614
+ nsNativeMenuDocListener::Create(aMenuBarNode);
1616
+ return NS_ERROR_FAILURE;
1619
+ nsMenuObject::Init(listener, aMenuBarNode);
1621
+ nsAutoCString path;
1622
+ path.Append(NS_LITERAL_CSTRING("/com/canonical/menu/"));
1624
+ sprintf(xid, "%X", static_cast<uint32_t>(
1625
+ GDK_WINDOW_XID(gtk_widget_get_window(mTopLevel))));
1628
+ mServer = dbusmenu_server_new(path.get());
1630
+ return NS_ERROR_FAILURE;
1633
+ CreateNativeData();
1634
+ if (!GetNativeData()) {
1635
+ return NS_ERROR_FAILURE;
1638
+ dbusmenu_server_set_root(mServer, GetNativeData());
1640
+ mEventListener = new nsMenuBarDocEventListener(this);
1642
+ mDocument = do_QueryInterface(ContentNode()->OwnerDoc());
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;
1654
+ mAccessKeyMask = eModifierAlt;
1704
+nsMenuBar::HandleContentInserted(nsIContent *aChild, nsIContent *aPrevSibling)
1706
+ UniquePtr<nsMenuObject> child = CreateChild(aChild);
1712
+ InsertChildAfter(Move(child), aPrevSibling);
1716
+nsMenuBar::HandleContentRemoved(nsIContent *aChild)
1718
+ RemoveChild(aChild);
1722
+nsMenuBar::OnContentInserted(nsIContent *aContainer, nsIContent *aChild,
1723
+ nsIContent *aPrevSibling)
1725
+ MOZ_ASSERT(aContainer == ContentNode(),
1726
+ "Received an event that wasn't meant for us");
1728
+ nsContentUtils::AddScriptRunner(
1729
+ new nsMenuBarContentInsertedEvent(this, aChild, aPrevSibling));
1733
+nsMenuBar::OnContentRemoved(nsIContent *aContainer, nsIContent *aChild)
1735
+ MOZ_ASSERT(aContainer == ContentNode(),
1736
+ "Received an event that wasn't meant for us");
1738
+ nsContentUtils::AddScriptRunner(
1739
+ new nsMenuBarContentRemovedEvent(this, aChild));
1660
1742
+nsMenuBar::~nsMenuBar()
1804
1864
+ DocListener()->Stop();
1805
1865
+ DisconnectDocumentEventListeners();
1809
+nsMenuBar::OnAttributeChanged(nsIContent *aContent, nsIAtom *aAttribute)
1815
+nsMenuBar::OnContentInserted(nsIContent *aContainer, nsIContent *aChild,
1816
+ nsIContent *aPrevSibling)
1818
+ NS_ASSERTION(aContainer == ContentNode(),
1819
+ "Received an event that wasn't meant for us");
1822
+ nsMenuObject *child = CreateChild(aChild, &rv);
1825
+ rv = InsertChildAfter(child, aPrevSibling);
1828
+ NS_ASSERTION(NS_SUCCEEDED(rv), "Failed to insert item in to menubar");
1832
+nsMenuBar::OnContentRemoved(nsIContent *aContainer, nsIContent *aChild)
1834
+ NS_ASSERTION(aContainer == ContentNode(),
1835
+ "Received an event that wasn't meant for us");
1837
+ DebugOnly<nsresult> rv = RemoveChild(aChild);
1838
+ NS_ASSERTION(NS_SUCCEEDED(rv), "Failed to remove item from menubar");
1840
Index: firefox-52.0~b9+build2/widget/gtk/nsMenuBar.h
1867
Index: firefox-53.0~a2~hg20170302r359591/widget/gtk/nsMenuBar.h
1841
1868
===================================================================
1843
+++ firefox-52.0~b9+build2/widget/gtk/nsMenuBar.h
1870
+++ firefox-53.0~a2~hg20170302r359591/widget/gtk/nsMenuBar.h
1845
1872
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
1846
1873
+/* vim:expandtab:shiftwidth=4:tabstop=4:
1942
1957
+ nsresult KeyDown(nsIDOMEvent *aEvent);
1943
1958
+ nsresult KeyUp(nsIDOMEvent *aEvent);
1960
+ void HandleContentInserted(nsIContent *aChild,
1961
+ nsIContent *aPrevSibling);
1962
+ void HandleContentRemoved(nsIContent *aChild);
1964
+ void OnContentInserted(nsIContent *aContainer, nsIContent *aChild,
1965
+ nsIContent *aPrevSibling) override;
1966
+ void OnContentRemoved(nsIContent *aContainer, nsIContent *aChild) override;
1945
1968
+ GtkWidget *mTopLevel;
1946
1969
+ DbusmenuServer *mServer;
1947
1970
+ nsCOMPtr<nsIDOMEventTarget> mDocument;
1948
+ nsNativeMenuGIORequest mRegisterRequestCanceller;
1949
+ RefPtr<nsMenuBarDocEventListener> mEventListener;
1971
+ RefPtr<DocEventListener> mEventListener;
1951
1973
+ uint32_t mAccessKey;
1952
1974
+ ModifierFlags mAccessKeyMask;
1978
2002
+#include "nsMenuContainer.h"
2004
+using namespace mozilla;
1980
2006
+const nsMenuContainer::ChildTArray::index_type nsMenuContainer::NoIndex = nsMenuContainer::ChildTArray::NoIndex;
1982
+typedef nsMenuObject* (*nsMenuObjectConstructor)(nsMenuContainer*,
2008
+typedef UniquePtr<nsMenuObject> (*nsMenuObjectConstructor)(nsMenuContainer*,
2012
+static UniquePtr<nsMenuObject> CreateMenuObject(nsMenuContainer *aContainer,
2013
+ nsIContent *aContent)
2015
+ return UniquePtr<T>(new T(aContainer, aContent));
1984
2018
+static nsMenuObjectConstructor
1985
2019
+GetMenuObjectConstructor(nsIContent *aContent)
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>;
1995
2029
+ return nullptr;
2001
2035
+ return GetMenuObjectConstructor(aContent) ? true : false;
2005
+nsMenuContainer::CreateChild(nsIContent *aContent, nsresult *aRv)
2038
+nsMenuContainer::nsMenuContainer(nsMenuContainer *aParent,
2039
+ nsIContent *aContent) :
2040
+ nsMenuObject(aParent, aContent)
2044
+nsMenuContainer::nsMenuContainer(nsNativeMenuDocListener *aListener,
2045
+ nsIContent *aContent) :
2046
+ nsMenuObject(aListener, aContent)
2050
+UniquePtr<nsMenuObject>
2051
+nsMenuContainer::CreateChild(nsIContent *aContent)
2007
2053
+ nsMenuObjectConstructor ctor = GetMenuObjectConstructor(aContent);
2009
2055
+ // There are plenty of node types we might stumble across that
2010
+ // aren't supported. This isn't an error though
2017
+ nsMenuObject *res = ctor(this, aContent);
2020
+ *aRv = NS_ERROR_FAILURE;
2056
+ // aren't supported
2060
+ UniquePtr<nsMenuObject> res = ctor(this, aContent);
2045
2078
+ return NoIndex;
2049
2082
+nsMenuContainer::RemoveChildAt(size_t aIndex, bool aUpdateNative)
2051
+ if (aIndex >= ChildCount()) {
2052
+ return NS_ERROR_INVALID_ARG;
2084
+ MOZ_ASSERT(aIndex < ChildCount());
2055
2086
+ if (aUpdateNative) {
2056
+ if (!dbusmenu_menuitem_child_delete(GetNativeData(),
2057
+ ChildAt(aIndex)->GetNativeData())) {
2058
+ return NS_ERROR_FAILURE;
2088
+ dbusmenu_menuitem_child_delete(GetNativeData(),
2089
+ ChildAt(aIndex)->GetNativeData()));
2062
2092
+ mChildren.RemoveElementAt(aIndex);
2068
2096
+nsMenuContainer::RemoveChild(nsIContent *aChild, bool aUpdateNative)
2070
2098
+ size_t index = IndexOf(aChild);
2071
2099
+ if (index == NoIndex) {
2072
+ return NS_ERROR_INVALID_ARG;
2075
+ return RemoveChildAt(index, aUpdateNative);
2103
+ RemoveChildAt(index, aUpdateNative);
2079
+nsMenuContainer::InsertChildAfter(nsMenuObject *aChild,
2107
+nsMenuContainer::InsertChildAfter(UniquePtr<nsMenuObject> aChild,
2080
2108
+ nsIContent *aPrevSibling,
2081
2109
+ bool aUpdateNative)
2083
2111
+ size_t index = IndexOf(aPrevSibling);
2084
+ if (index == NoIndex && aPrevSibling) {
2085
+ return NS_ERROR_INVALID_ARG;
2112
+ MOZ_ASSERT(!aPrevSibling || index != NoIndex);
2090
2116
+ if (aUpdateNative) {
2091
2117
+ aChild->CreateNativeData();
2092
+ if (!dbusmenu_menuitem_child_add_position(GetNativeData(),
2093
+ aChild->GetNativeData(),
2095
+ return NS_ERROR_FAILURE;
2119
+ dbusmenu_menuitem_child_add_position(GetNativeData(),
2120
+ aChild->GetNativeData(),
2099
+ return mChildren.InsertElementAt(index, aChild) ? NS_OK : NS_ERROR_FAILURE;
2124
+ MOZ_ALWAYS_TRUE(mChildren.InsertElementAt(index, Move(aChild)));
2103
+nsMenuContainer::AppendChild(nsMenuObject *aChild, bool aUpdateNative)
2128
+nsMenuContainer::AppendChild(UniquePtr<nsMenuObject> aChild,
2129
+ bool aUpdateNative)
2105
2131
+ if (aUpdateNative) {
2106
2132
+ aChild->CreateNativeData();
2107
+ if (!dbusmenu_menuitem_child_append(GetNativeData(),
2108
+ aChild->GetNativeData())) {
2109
+ return NS_ERROR_FAILURE;
2134
+ dbusmenu_menuitem_child_append(GetNativeData(),
2135
+ aChild->GetNativeData()));
2113
+ return mChildren.AppendElement(aChild) ? NS_OK : NS_ERROR_FAILURE;
2116
+nsMenuContainer::nsMenuContainer() :
2138
+ MOZ_ALWAYS_TRUE(mChildren.AppendElement(Move(aChild)));
2177
2198
+ static const ChildTArray::index_type NoIndex;
2180
+ nsMenuContainer();
2201
+ nsMenuContainer(nsMenuContainer *aParent, nsIContent *aContent);
2202
+ nsMenuContainer(nsNativeMenuDocListener *aListener, nsIContent *aContent);
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);
2185
2207
+ // Return the index of the child for the specified content node
2186
2208
+ size_t IndexOf(nsIContent *aChild) const;
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(); }
2191
+ nsresult RemoveChildAt(size_t aIndex, bool aUpdateNative = true);
2213
+ void RemoveChildAt(size_t aIndex, bool aUpdateNative = true);
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);
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);
2200
+ nsresult AppendChild(nsMenuObject *aChild, bool aUpdateNative = true);
2223
+ void AppendChild(mozilla::UniquePtr<nsMenuObject> aChild,
2224
+ bool aUpdateNative = true);
2203
2227
+ ChildTArray mChildren;
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
===================================================================
2210
+++ firefox-52.0~b9+build2/widget/gtk/nsMenuItem.cpp
2234
+++ firefox-53.0~a2~hg20170302r359591/widget/gtk/nsMenuItem.cpp
2212
2236
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2213
2237
+/* vim:expandtab:shiftwidth=4:tabstop=4:
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;
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,
2559
2585
+ NS_LITERAL_STRING("false") : NS_LITERAL_STRING("true"),
2769
+nsMenuItem::MenuBar()
2771
+ nsMenuObject *tmp = this;
2772
+ while (tmp->Parent()) {
2773
+ tmp = tmp->Parent();
2776
+ MOZ_ASSERT(tmp->Type() == eType_MenuBar, "The top-level should be a menubar");
2778
+ return static_cast<nsMenuBar *>(tmp);
2782
+nsMenuItem::UncheckSiblings()
2784
+ if (!ContentNode()->AttrValueIs(kNameSpaceID_None, nsGkAtoms::type,
2785
+ nsGkAtoms::radio, eCaseMatters)) {
2786
+ // If we're not a radio button, we don't care
2790
+ nsAutoString name;
2791
+ ContentNode()->GetAttr(kNameSpaceID_None, nsGkAtoms::name, name);
2793
+ nsIContent *parent = ContentNode()->GetParent();
2798
+ uint32_t count = parent->GetChildCount();
2799
+ for (uint32_t i = 0; i < count; ++i) {
2800
+ nsIContent *sibling = parent->GetChildAt(i);
2802
+ nsAutoString otherName;
2803
+ sibling->GetAttr(kNameSpaceID_None, nsGkAtoms::name, otherName);
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);
2743
2814
+nsMenuItem::InitializeNativeData()
2745
2816
+ g_signal_connect(G_OBJECT(GetNativeData()),
2746
2817
+ DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED,
2747
2818
+ G_CALLBACK(item_activated_cb), this);
2749
+ UpdateTypeAndState();
2752
+ UpdateSensitivity();
2819
+ mNeedsUpdate = true;
2789
2856
+nsMenuItem::Update(nsStyleContext *aStyleContext)
2858
+ if (mNeedsUpdate) {
2859
+ mNeedsUpdate = false;
2861
+ UpdateTypeAndState();
2864
+ UpdateSensitivity();
2791
2867
+ UpdateVisibility(aStyleContext);
2792
2868
+ UpdateIcon(aStyleContext);
2796
+nsMenuItem::UncheckSiblings()
2798
+ if (!ContentNode()->AttrValueIs(kNameSpaceID_None, nsGkAtoms::type,
2799
+ nsGkAtoms::radio, eCaseMatters)) {
2800
+ // If we're not a radio button, we don't care
2804
+ nsAutoString name;
2805
+ ContentNode()->GetAttr(kNameSpaceID_None, nsGkAtoms::name, name);
2807
+ nsIContent *parent = ContentNode()->GetParent();
2812
+ uint32_t count = parent->GetChildCount();
2813
+ for (uint32_t i = 0; i < count; ++i) {
2814
+ nsIContent *sibling = parent->GetChildAt(i);
2816
+ nsAutoString otherName;
2817
+ sibling->GetAttr(kNameSpaceID_None, nsGkAtoms::name, otherName);
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);
2828
2872
+nsMenuItem::IsCompatibleWithNativeData(DbusmenuMenuitem *aNativeData) const
2862
+nsMenuItem::nsMenuItem() :
2865
+ MOZ_COUNT_CTOR(nsMenuItem);
2868
+nsMenuItem::~nsMenuItem()
2870
+ if (DocListener() && mKeyContent) {
2871
+ DocListener()->UnregisterForContentChanges(mKeyContent);
2874
+ if (GetNativeData()) {
2875
+ g_signal_handlers_disconnect_by_func(GetNativeData(),
2876
+ FuncToGpointer(item_activated_cb),
2880
+ MOZ_COUNT_DTOR(nsMenuItem);
2883
+nsMenuObject::EType
2884
+nsMenuItem::Type() const
2886
+ return nsMenuObject::eType_MenuItem;
2889
+/* static */ nsMenuObject*
2890
+nsMenuItem::Create(nsMenuContainer *aParent, nsIContent *aContent)
2892
+ nsAutoPtr<nsMenuItem> menuitem(new nsMenuItem());
2893
+ if (NS_FAILED(menuitem->Init(aParent, aContent))) {
2897
+ return menuitem.forget();
2901
2894
+nsMenuItem::OnAttributeChanged(nsIContent *aContent, nsIAtom *aAttribute)
2903
+ NS_ASSERTION(aContent == ContentNode() || aContent == mKeyContent,
2904
+ "Received an event that wasn't meant for us!");
2906
+ if (Parent()->NeedsRebuild()) {
2896
+ MOZ_ASSERT(aContent == ContentNode() || aContent == mKeyContent,
2897
+ "Received an event that wasn't meant for us!");
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();
2916
+ nsContentUtils::AddScriptRunner(
2917
+ new nsMenuItemUncheckSiblingsRunnable(this));
2902
+ nsContentUtils::AddScriptRunner(
2903
+ new nsMenuItemUncheckSiblingsRunnable(this));
2906
+ if (mNeedsUpdate) {
2910
+ if (!Parent()->IsBeingDisplayed()) {
2911
+ mNeedsUpdate = true;
2921
2915
+ if (aContent == ContentNode()) {
2938
2939
+ aAttribute == nsGkAtoms::modifiers)) {
2939
2940
+ UpdateAccel();
2942
+ if (!Parent()->IsBeingDisplayed() || aContent != ContentNode()) {
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();
2955
Index: firefox-52.0~b9+build2/widget/gtk/nsMenuItem.h
2944
+nsMenuItem::nsMenuItem(nsMenuContainer *aParent, nsIContent *aContent) :
2945
+ nsMenuObject(aParent, aContent),
2946
+ mType(eMenuItemType_Normal),
2947
+ mIsChecked(false),
2948
+ mNeedsUpdate(false)
2950
+ MOZ_COUNT_CTOR(nsMenuItem);
2953
+nsMenuItem::~nsMenuItem()
2955
+ if (DocListener() && mKeyContent) {
2956
+ DocListener()->UnregisterForContentChanges(mKeyContent);
2959
+ if (GetNativeData()) {
2960
+ g_signal_handlers_disconnect_by_func(GetNativeData(),
2961
+ FuncToGpointer(item_activated_cb),
2965
+ MOZ_COUNT_DTOR(nsMenuItem);
2968
+nsMenuObject::EType
2969
+nsMenuItem::Type() const
2971
+ return eType_MenuItem;
2973
Index: firefox-53.0~a2~hg20170302r359591/widget/gtk/nsMenuItem.h
2956
2974
===================================================================
2958
+++ firefox-52.0~b9+build2/widget/gtk/nsMenuItem.h
2976
+++ firefox-53.0~a2~hg20170302r359591/widget/gtk/nsMenuItem.h
2960
2978
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2961
2979
+/* vim:expandtab:shiftwidth=4:tabstop=4:
3013
3024
+ eMenuItemType_CheckBox
3018
+ EMenuItemType MenuItemType() const
3020
+ return static_cast<EMenuItemType>(
3022
+ (((1U << NSMENUITEM_NUMBER_OF_TYPE_BITS) - 1U)
3023
+ << NSMENUITEM_NUMBER_OF_FLAGS)) >> NSMENUITEM_NUMBER_OF_FLAGS);
3025
+ void SetMenuItemType(EMenuItemType aType)
3027
+ ClearFlags(((1U << NSMENUITEM_NUMBER_OF_TYPE_BITS) - 1U) << NSMENUITEM_NUMBER_OF_FLAGS);
3028
+ SetFlags(aType << NSMENUITEM_NUMBER_OF_FLAGS);
3030
3027
+ bool IsCheckboxOrRadioItem() const;
3032
+ bool IsChecked() const
3034
+ return HasFlags(eMenuItemFlag_ToggleState);
3036
+ void SetCheckState(bool aState)
3039
+ SetFlags(eMenuItemFlag_ToggleState);
3041
+ ClearFlags(eMenuItemFlag_ToggleState);
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();
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;
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;
3047
+ void OnAttributeChanged(nsIContent *aContent, nsIAtom *aAttribute) override;
3049
+ EMenuItemType mType;
3053
+ bool mNeedsUpdate;
3063
3055
+ nsCOMPtr<nsIContent> mKeyContent;
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
===================================================================
3070
+++ firefox-52.0~b9+build2/widget/gtk/nsMenuObject.cpp
3062
+++ firefox-53.0~a2~hg20170302r359591/widget/gtk/nsMenuObject.cpp
3072
3064
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3073
3065
+/* vim:expandtab:shiftwidth=4:tabstop=4:
3397
3370
+ return sEllipsisWidth;
3401
+nsMenuObject::InitializeNativeData()
3405
+nsMenuObject::PropertyFlags
3406
+nsMenuObject::SupportedProperties() const
3408
+ return static_cast<nsMenuObject::PropertyFlags>(0);
3412
+nsMenuObject::IsCompatibleWithNativeData(DbusmenuMenuitem *aNativeData) const
3418
+nsMenuObject::UpdateContentAttributes()
3423
+nsMenuObject::Update(nsStyleContext *aStyleContext)
3428
+nsMenuObject::ShouldShowIcon() const
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();
3440
+ for (uint32_t i = 0; i < classes->GetAtomCount(); ++i) {
3441
+ if (classes->AtomAt(i) == nsNativeMenuAtoms::menuitem_with_favicon) {
3450
+nsMenuObject::ClearIcon()
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()),
3377
+ mNativeData(nullptr)
3379
+ MOZ_ASSERT(mContent);
3380
+ MOZ_ASSERT(mListener);
3381
+ MOZ_ASSERT(mParent);
3384
+nsMenuObject::nsMenuObject(nsNativeMenuDocListener *aListener,
3385
+ nsIContent *aContent) :
3386
+ mContent(aContent),
3387
+ mListener(aListener),
3389
+ mNativeData(nullptr)
3391
+ MOZ_ASSERT(mContent);
3392
+ MOZ_ASSERT(mListener);
3615
3553
+ return sc.forget();
3619
+nsMenuObject::Init(nsMenuContainer *aParent, nsIContent *aContent)
3621
+ NS_ENSURE_ARG(aParent);
3622
+ NS_ENSURE_ARG(aContent);
3624
+ mParent = aParent;
3625
+ mContent = aContent;
3626
+ mListener = aParent->DocListener();
3627
+ NS_ENSURE_ARG(mListener);
3633
+nsMenuObject::Init(nsNativeMenuDocListener *aListener, nsIContent *aContent)
3635
+ NS_ENSURE_ARG(aListener);
3636
+ NS_ENSURE_ARG(aContent);
3638
+ mParent = nullptr;
3639
+ mContent = aContent;
3640
+ mListener = aListener;
3645
+nsMenuObject::nsMenuObject() :
3646
+ mParent(nullptr), mNativeData(nullptr), mFlags(0)
3557
+nsMenuObject::InitializeNativeData()
3561
+nsMenuObject::PropertyFlags
3562
+nsMenuObject::SupportedProperties() const
3564
+ return static_cast<nsMenuObject::PropertyFlags>(0);
3568
+nsMenuObject::IsCompatibleWithNativeData(DbusmenuMenuitem *aNativeData) const
3574
+nsMenuObject::UpdateContentAttributes()
3579
+nsMenuObject::Update(nsStyleContext *aStyleContext)
3584
+nsMenuObject::ShouldShowIcon() const
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();
3596
+ for (uint32_t i = 0; i < classes->GetAtomCount(); ++i) {
3597
+ if (classes->AtomAt(i) == nsNativeMenuAtoms::menuitem_with_favicon) {
3606
+nsMenuObject::ClearIcon()
3608
+ dbusmenu_menuitem_property_remove(mNativeData,
3609
+ DBUSMENU_MENUITEM_PROP_ICON_DATA);
3650
3612
+nsMenuObject::~nsMenuObject()
3652
+ nsWeakMenuObjectBase::NotifyDestroyed(this);
3614
+ nsWeakMenuObject::NotifyDestroyed(this);
3654
3616
+ if (mIconLoader) {
3655
3617
+ mIconLoader->Destroy();
3729
3687
+/* static */ void
3730
+nsWeakMenuObjectBase::AddWeakReference(nsWeakMenuObjectBase *aWeak)
3688
+nsWeakMenuObject::AddWeakReference(nsWeakMenuObject *aWeak)
3732
+ aWeak->SetPrevious(sHead);
3690
+ aWeak->mPrev = sHead;
3733
3691
+ sHead = aWeak;
3736
3694
+/* static */ void
3737
+nsWeakMenuObjectBase::RemoveWeakReference(nsWeakMenuObjectBase *aWeak)
3695
+nsWeakMenuObject::RemoveWeakReference(nsWeakMenuObject *aWeak)
3739
3697
+ if (aWeak == sHead) {
3740
+ sHead = aWeak->GetPrevious();
3698
+ sHead = aWeak->mPrev;
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;
3750
+ weak->SetPrevious(aWeak->GetPrevious());
3708
+ weak->mPrev = aWeak->mPrev;
3754
3712
+/* static */ void
3755
+nsWeakMenuObjectBase::NotifyDestroyed(nsMenuObject *aMenuObject)
3713
+nsWeakMenuObject::NotifyDestroyed(nsMenuObject *aMenuObject)
3757
+ nsWeakMenuObjectBase *weak = sHead;
3715
+ nsWeakMenuObject *weak = sHead;
3758
3716
+ while (weak) {
3759
+ if (weak->getBase() == aMenuObject) {
3717
+ if (weak->mMenuObject == aMenuObject) {
3718
+ weak->mMenuObject = nullptr;
3763
+ weak = weak->GetPrevious();
3721
+ weak = weak->mPrev;
3766
Index: firefox-52.0~b9+build2/widget/gtk/nsMenuObject.h
3724
Index: firefox-53.0~a2~hg20170302r359591/widget/gtk/nsMenuObject.h
3767
3725
===================================================================
3769
+++ firefox-52.0~b9+build2/widget/gtk/nsMenuObject.h
3727
+++ firefox-53.0~a2~hg20170302r359591/widget/gtk/nsMenuObject.h
3771
3729
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3772
3730
+/* vim:expandtab:shiftwidth=4:tabstop=4:
3919
3861
+ nsMenuContainer *mParent; // [weak]
3920
3862
+ DbusmenuMenuitem *mNativeData; // [strong]
3921
3863
+ RefPtr<nsMenuObjectIconLoader> mIconLoader;
3925
+class nsWeakMenuObjectBase
3866
+// Keep a weak pointer to a menu object
3867
+class nsWeakMenuObject
3928
+ ~nsWeakMenuObjectBase()
3870
+ nsWeakMenuObject() : mPrev(nullptr), mMenuObject(nullptr) {}
3872
+ nsWeakMenuObject(nsMenuObject *aMenuObject) :
3873
+ mPrev(nullptr), mMenuObject(aMenuObject)
3930
+ RemoveWeakReference(this);
3875
+ AddWeakReference(this);
3933
+ nsMenuObject* getBase() const { return mMenuObject; }
3878
+ ~nsWeakMenuObject() { RemoveWeakReference(this); }
3880
+ nsMenuObject* get() const { return mMenuObject; }
3882
+ nsMenuObject* operator->() const { return mMenuObject; }
3884
+ explicit operator bool() const { return !!mMenuObject; }
3935
3886
+ static void NotifyDestroyed(nsMenuObject *aMenuObject);
3938
+ nsWeakMenuObjectBase() : mMenuObject(nullptr) { };
3940
+ void SetMenuObject(nsMenuObject *aMenuObject)
3942
+ mMenuObject = aMenuObject;
3944
+ mMenuObject ? AddWeakReference(this) : RemoveWeakReference(this);
3948
+ nsWeakMenuObjectBase* GetPrevious() const { return mPrev; }
3949
+ void SetPrevious(nsWeakMenuObjectBase *aPrev)
3953
+ void Clear() { mMenuObject = nullptr; }
3955
+ static void AddWeakReference(nsWeakMenuObjectBase *aWeak);
3956
+ static void RemoveWeakReference(nsWeakMenuObjectBase *aWeak);
3958
+ nsWeakMenuObjectBase *mPrev;
3959
+ static nsWeakMenuObjectBase *sHead;
3889
+ static void AddWeakReference(nsWeakMenuObject *aWeak);
3890
+ static void RemoveWeakReference(nsWeakMenuObject *aWeak);
3892
+ nsWeakMenuObject *mPrev;
3893
+ static nsWeakMenuObject *sHead;
3961
3895
+ nsMenuObject *mMenuObject;
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
3967
+class nsWeakMenuObject : public nsWeakMenuObjectBase
3970
+ nsWeakMenuObject() :
3971
+ nsWeakMenuObjectBase() { };
3973
+ nsWeakMenuObject(T *aMenuObject) :
3974
+ nsWeakMenuObjectBase()
3976
+ SetMenuObject(aMenuObject);
3979
+ T* get() const { return static_cast<T *>(getBase()); }
3981
+ T* operator->() const { return get(); }
3983
+ operator T*() const { return get(); }
3987
+class nsAutoWeakMenuObject
3990
+ nsAutoWeakMenuObject() { };
3992
+ nsAutoWeakMenuObject(T *aMenuObject) :
3993
+ mPtr(new nsWeakMenuObject<T>(aMenuObject)) { };
3995
+ nsAutoWeakMenuObject(nsWeakMenuObject<T> *aWeak) :
3998
+ T* get() const { return static_cast<T *>(*mPtr); }
4000
+ T* operator->() const { return get(); }
4002
+ operator T*() const { return get(); }
4004
+ nsWeakMenuObject<T>* getWeakPtr() const { return mPtr; }
4006
+ nsWeakMenuObject<T>* forget() { return mPtr.forget(); }
4009
+ nsAutoPtr<nsWeakMenuObject<T> > mPtr;
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
===================================================================
4016
+++ firefox-52.0~b9+build2/widget/gtk/nsMenuSeparator.cpp
3902
+++ firefox-53.0~a2~hg20170302r359591/widget/gtk/nsMenuSeparator.cpp
4018
3904
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
4019
3905
+/* vim:expandtab:shiftwidth=4:tabstop=4:
4076
3984
+nsMenuObject::EType
4077
3985
+nsMenuSeparator::Type() const
4079
+ return nsMenuObject::eType_MenuSeparator;
4082
+/* static */ nsMenuObject*
4083
+nsMenuSeparator::Create(nsMenuContainer *aParent, nsIContent *aContent)
4085
+ nsAutoPtr<nsMenuSeparator> sep(new nsMenuSeparator());
4086
+ if (NS_FAILED(sep->Init(aParent, aContent))) {
4090
+ return sep.forget();
4094
+nsMenuSeparator::OnAttributeChanged(nsIContent *aContent, nsIAtom *aAttribute)
4096
+ NS_ASSERTION(aContent == ContentNode(), "Received an event that wasn't meant for us!");
4098
+ if (!Parent()->IsBeingDisplayed()) {
4102
+ if (aAttribute == nsGkAtoms::hidden ||
4103
+ aAttribute == nsGkAtoms::collapsed) {
4104
+ RefPtr<nsStyleContext> sc = GetStyleContext();
4105
+ UpdateVisibility(sc);
4108
Index: firefox-52.0~b9+build2/widget/gtk/nsMenuSeparator.h
3987
+ return eType_MenuItem;
3989
Index: firefox-53.0~a2~hg20170302r359591/widget/gtk/nsMenuSeparator.h
4109
3990
===================================================================
4111
+++ firefox-52.0~b9+build2/widget/gtk/nsMenuSeparator.h
3992
+++ firefox-53.0~a2~hg20170302r359591/widget/gtk/nsMenuSeparator.h
4113
3994
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
4114
3995
+/* vim:expandtab:shiftwidth=4:tabstop=4:
4132
4013
+class nsMenuSeparator final : public nsMenuObject
4016
+ nsMenuSeparator(nsMenuContainer *aParent, nsIContent *aContent);
4135
4017
+ ~nsMenuSeparator();
4137
+ nsMenuObject::EType Type() const;
4139
+ static nsMenuObject* Create(nsMenuContainer *aParent,
4140
+ nsIContent *aContent);
4142
+ void OnAttributeChanged(nsIContent *aContent, nsIAtom *aAttribute);
4019
+ nsMenuObject::EType Type() const override;
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;
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;
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
===================================================================
4157
+++ firefox-52.0~b9+build2/widget/gtk/nsNativeMenuAtomList.h
4034
+++ firefox-53.0~a2~hg20170302r359591/widget/gtk/nsNativeMenuAtomList.h
4159
4036
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
4160
4037
+/* vim:expandtab:shiftwidth=4:tabstop=4:
4164
4041
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
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
===================================================================
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:
4309
4189
+NS_IMPL_ISUPPORTS(nsNativeMenuDocListener, nsIMutationObserver)
4191
+nsNativeMenuDocListener::~nsNativeMenuDocListener()
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);
4199
+nsNativeMenuDocListener::AttributeChanged(nsIDocument *aDocument,
4200
+ mozilla::dom::Element *aElement,
4201
+ int32_t aNameSpaceID,
4202
+ nsIAtom *aAttribute,
4204
+ const nsAttrValue* aOldValue)
4206
+ if (sUpdateBlockersCount == 0) {
4207
+ DoAttributeChanged(aElement, aAttribute);
4211
+ MutationRecord *m = *mPendingMutations.AppendElement(new MutationRecord);
4212
+ m->mType = MutationRecord::eAttributeChanged;
4213
+ m->mTarget = aElement;
4214
+ m->mAttribute = aAttribute;
4216
+ ScheduleFlush(this);
4220
+nsNativeMenuDocListener::ContentAppended(nsIDocument *aDocument,
4221
+ nsIContent *aContainer,
4222
+ nsIContent *aFirstNewContent,
4223
+ int32_t aNewIndexInContainer)
4225
+ for (nsIContent *c = aFirstNewContent; c; c = c->GetNextSibling()) {
4226
+ ContentInserted(aDocument, aContainer, c, 0);
4231
+nsNativeMenuDocListener::ContentInserted(nsIDocument *aDocument,
4232
+ nsIContent *aContainer,
4233
+ nsIContent *aChild,
4234
+ int32_t aIndexInContainer)
4236
+ nsIContent *prevSibling = nsMenuContainer::GetPreviousSupportedSibling(aChild);
4238
+ if (sUpdateBlockersCount == 0) {
4239
+ DoContentInserted(aContainer, aChild, prevSibling);
4243
+ MutationRecord *m = *mPendingMutations.AppendElement(new MutationRecord);
4244
+ m->mType = MutationRecord::eContentInserted;
4245
+ m->mTarget = aContainer;
4246
+ m->mChild = aChild;
4247
+ m->mPrevSibling = prevSibling;
4249
+ ScheduleFlush(this);
4253
+nsNativeMenuDocListener::ContentRemoved(nsIDocument *aDocument,
4254
+ nsIContent *aContainer,
4255
+ nsIContent *aChild,
4256
+ int32_t aIndexInContainer,
4257
+ nsIContent *aPreviousSibling)
4259
+ if (sUpdateBlockersCount == 0) {
4260
+ DoContentRemoved(aContainer, aChild);
4264
+ MutationRecord *m = *mPendingMutations.AppendElement(new MutationRecord);
4265
+ m->mType = MutationRecord::eContentRemoved;
4266
+ m->mTarget = aContainer;
4267
+ m->mChild = aChild;
4269
+ ScheduleFlush(this);
4273
+nsNativeMenuDocListener::NodeWillBeDestroyed(const nsINode *aNode)
4275
+ mDocument = nullptr;
4312
4279
+nsNativeMenuDocListener::DoAttributeChanged(nsIContent *aContent,
4313
4280
+ nsIAtom *aAttribute)
4343
+nsNativeMenuDocListener::DoBeginUpdateBatch(nsIContent *aTarget)
4310
+nsNativeMenuDocListener::DoBeginUpdates(nsIContent *aTarget)
4345
4312
+ DispatchHelper h(this, aTarget);
4346
4313
+ if (h.HasObserver()) {
4347
+ h.Observer()->BeginUpdateBatch(aTarget);
4314
+ h.Observer()->OnBeginUpdates(aTarget);
4352
+nsNativeMenuDocListener::DoEndUpdateBatch(nsIContent *aTarget)
4319
+nsNativeMenuDocListener::DoEndUpdates(nsIContent *aTarget)
4354
4321
+ DispatchHelper h(this, aTarget);
4355
4322
+ if (h.HasObserver()) {
4356
+ h.Observer()->EndUpdateBatch();
4323
+ h.Observer()->OnEndUpdates();
4361
4328
+nsNativeMenuDocListener::FlushPendingMutations()
4363
+ nsIContent *batchTarget = nullptr;
4364
+ bool inUpdateBatch = false;
4330
+ nsIContent *currentTarget = nullptr;
4331
+ bool inUpdateSequence = false;
4366
4333
+ while (mPendingMutations.Length() > 0) {
4367
4334
+ MutationRecord *m = mPendingMutations[0];
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;
4375
+ batchTarget = m->mTarget;
4342
+ currentTarget = m->mTarget;
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;
4450
4418
+ MOZ_COUNT_CTOR(nsNativeMenuDocListener);
4453
+nsNativeMenuDocListener::~nsNativeMenuDocListener()
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);
4461
+nsNativeMenuDocListener::Init(nsIContent *aRootNode)
4463
+ NS_ENSURE_ARG(aRootNode);
4465
+ mRootNode = aRootNode;
4471
+nsNativeMenuDocListener::AttributeChanged(nsIDocument *aDocument,
4472
+ mozilla::dom::Element *aElement,
4473
+ int32_t aNameSpaceID,
4474
+ nsIAtom *aAttribute,
4476
+ const nsAttrValue* aOldValue)
4478
+ if (sUpdateDepth == 0) {
4479
+ DoAttributeChanged(aElement, aAttribute);
4483
+ MutationRecord *m = *mPendingMutations.AppendElement(new MutationRecord);
4484
+ m->mType = MutationRecord::eAttributeChanged;
4485
+ m->mTarget = aElement;
4486
+ m->mAttribute = aAttribute;
4488
+ ScheduleFlush(this);
4492
+nsNativeMenuDocListener::ContentAppended(nsIDocument *aDocument,
4493
+ nsIContent *aContainer,
4494
+ nsIContent *aFirstNewContent,
4495
+ int32_t aNewIndexInContainer)
4497
+ for (nsIContent *c = aFirstNewContent; c; c = c->GetNextSibling()) {
4498
+ ContentInserted(aDocument, aContainer, c, 0);
4503
+nsNativeMenuDocListener::ContentInserted(nsIDocument *aDocument,
4504
+ nsIContent *aContainer,
4505
+ nsIContent *aChild,
4506
+ int32_t aIndexInContainer)
4508
+ nsIContent *prevSibling = nsMenuContainer::GetPreviousSupportedSibling(aChild);
4510
+ if (sUpdateDepth == 0) {
4511
+ DoContentInserted(aContainer, aChild, prevSibling);
4515
+ MutationRecord *m = *mPendingMutations.AppendElement(new MutationRecord);
4516
+ m->mType = MutationRecord::eContentInserted;
4517
+ m->mTarget = aContainer;
4518
+ m->mChild = aChild;
4519
+ m->mPrevSibling = prevSibling;
4521
+ ScheduleFlush(this);
4525
+nsNativeMenuDocListener::ContentRemoved(nsIDocument *aDocument,
4526
+ nsIContent *aContainer,
4527
+ nsIContent *aChild,
4528
+ int32_t aIndexInContainer,
4529
+ nsIContent *aPreviousSibling)
4531
+ if (sUpdateDepth == 0) {
4532
+ DoContentRemoved(aContainer, aChild);
4536
+ MutationRecord *m = *mPendingMutations.AppendElement(new MutationRecord);
4537
+ m->mType = MutationRecord::eContentRemoved;
4538
+ m->mTarget = aContainer;
4539
+ m->mChild = aChild;
4541
+ ScheduleFlush(this);
4545
+nsNativeMenuDocListener::NodeWillBeDestroyed(const nsINode *aNode)
4547
+ mDocument = nullptr;
4550
+/* static */ already_AddRefed<nsNativeMenuDocListener>
4551
+nsNativeMenuDocListener::Create(nsIContent *aRootNode)
4553
+ RefPtr<nsNativeMenuDocListener> listener = new nsNativeMenuDocListener();
4554
+ if (NS_FAILED(listener->Init(aRootNode))) {
4558
+ return listener.forget();
4562
4422
+nsNativeMenuDocListener::RegisterForContentChanges(nsIContent *aContent,
4563
4423
+ nsNativeMenuChangeObserver *aObserver)
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) {
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");
4575
4435
+ mContentToObserverTable.Put(aContent, aObserver);
4677
4532
+ // to registered observers.
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
4542
+ class MOZ_STACK_CLASS BlockUpdatesScope
4545
+ BlockUpdatesScope(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM)
4547
+ MOZ_GUARD_OBJECT_NOTIFIER_INIT;
4548
+ nsNativeMenuDocListener::AddUpdateBlocker();
4551
+ ~BlockUpdatesScope()
4553
+ nsNativeMenuDocListener::RemoveUpdateBlocker();
4557
+ MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
4681
+ friend class nsNativeMenuAutoUpdateBatch;
4682
4561
+ friend class DispatchHelper;
4684
4563
+ struct MutationRecord {
4694
4573
+ nsCOMPtr<nsIAtom> mAttribute;
4697
+ nsNativeMenuDocListener();
4698
4576
+ ~nsNativeMenuDocListener();
4699
+ nsresult Init(nsIContent *aRootNode);
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
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);
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();
4596
+ static void AddUpdateBlocker() { ++sUpdateBlockersCount; }
4597
+ static void RemoveUpdateBlocker();
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;
4721
+ static uint32_t sUpdateDepth;
4606
+ static uint32_t sUpdateBlockersCount;
4724
4609
+typedef nsTArray<RefPtr<nsNativeMenuDocListener> > nsNativeMenuDocListenerTArray;
4612
+ * Implemented by classes that want to listen to mutation events from content
4726
4615
+class nsNativeMenuChangeObserver
4729
+ virtual void OnAttributeChanged(nsIContent *aContent, nsIAtom *aAttribute)
4731
+ NS_ERROR("Unhandled AttributeChanged() notification");
4618
+ virtual void OnAttributeChanged(nsIContent *aContent, nsIAtom *aAttribute) {}
4734
4620
+ virtual void OnContentInserted(nsIContent *aContainer,
4735
4621
+ nsIContent *aChild,
4736
+ nsIContent *aPrevSibling)
4738
+ NS_ERROR("Unhandled ContentInserted() notification");
4741
+ virtual void OnContentRemoved(nsIContent *aContainer, nsIContent *aChild)
4743
+ NS_ERROR("Unhandled ContentRemoved() notification");
4746
+ virtual void BeginUpdateBatch(nsIContent *aContent) { };
4748
+ virtual void EndUpdateBatch() { };
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
4758
+class MOZ_STACK_CLASS nsNativeMenuAutoUpdateBatch
4761
+ nsNativeMenuAutoUpdateBatch(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM)
4763
+ MOZ_GUARD_OBJECT_NOTIFIER_INIT;