XULMenuBarElement.cpp (3490B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #include "XULMenuBarElement.h" 8 9 #include "MenuBarListener.h" 10 #include "XULButtonElement.h" 11 #include "mozilla/Assertions.h" 12 #include "mozilla/AsyncEventDispatcher.h" 13 #include "mozilla/Try.h" 14 #include "mozilla/dom/BindContext.h" 15 #include "nsXULPopupManager.h" 16 17 namespace mozilla::dom { 18 19 NS_IMPL_CYCLE_COLLECTION_CLASS(XULMenuBarElement) 20 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(XULMenuBarElement, 21 XULMenuParentElement) 22 if (tmp->mListener) { 23 tmp->mListener->Detach(); 24 tmp->mListener = nullptr; 25 } 26 NS_IMPL_CYCLE_COLLECTION_UNLINK_END 27 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(XULMenuBarElement, 28 XULMenuParentElement) 29 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mListener) 30 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END 31 NS_IMPL_ISUPPORTS_CYCLE_COLLECTION_INHERITED_0(XULMenuBarElement, 32 XULMenuParentElement) 33 34 XULMenuBarElement::XULMenuBarElement( 35 already_AddRefed<class NodeInfo>&& aNodeInfo) 36 : XULMenuParentElement(std::move(aNodeInfo)) {} 37 38 XULMenuBarElement::~XULMenuBarElement() { MOZ_DIAGNOSTIC_ASSERT(!mListener); } 39 40 void XULMenuBarElement::SetActive(bool aActiveFlag) { 41 // If the activity is not changed, there is nothing to do. 42 if (mIsActive == aActiveFlag) { 43 return; 44 } 45 46 // We can't activate a menubar outside of the document. 47 if (!IsInComposedDoc()) { 48 MOZ_ASSERT(!mIsActive, "How?"); 49 return; 50 } 51 52 if (!aActiveFlag) { 53 // If there is a request to deactivate the menu bar, check to see whether 54 // there is a menu popup open for the menu bar. In this case, don't 55 // deactivate the menu bar. 56 if (auto* activeChild = GetActiveMenuChild()) { 57 if (activeChild->IsMenuPopupOpen()) { 58 return; 59 } 60 } 61 } 62 63 mIsActive = aActiveFlag; 64 if (nsXULPopupManager* pm = nsXULPopupManager::GetInstance()) { 65 pm->SetActiveMenuBar(this, aActiveFlag); 66 } 67 if (!aActiveFlag) { 68 mActiveByKeyboard = false; 69 SetActiveMenuChild(nullptr); 70 } 71 72 RefPtr dispatcher = new AsyncEventDispatcher( 73 this, aActiveFlag ? u"DOMMenuBarActive"_ns : u"DOMMenuBarInactive"_ns, 74 CanBubble::eYes, ChromeOnlyDispatch::eNo); 75 DebugOnly<nsresult> rv = dispatcher->PostDOMEvent(); 76 NS_ASSERTION(NS_SUCCEEDED(rv), "AsyncEventDispatcher failed to dispatch"); 77 } 78 79 nsresult XULMenuBarElement::BindToTree(BindContext& aContext, 80 nsINode& aParent) { 81 MOZ_TRY(XULMenuParentElement::BindToTree(aContext, aParent)); 82 MOZ_DIAGNOSTIC_ASSERT(!mListener); 83 if (aContext.InComposedDoc()) { 84 mListener = new MenuBarListener(*this); 85 } 86 return NS_OK; 87 } 88 89 void XULMenuBarElement::UnbindFromTree(UnbindContext& aContext) { 90 if (mListener) { 91 mListener->Detach(); 92 mListener = nullptr; 93 } 94 if (NS_WARN_IF(mIsActive)) { 95 // Clean up silently when getting removed from the document while active. 96 mIsActive = false; 97 if (nsXULPopupManager* pm = nsXULPopupManager::GetInstance()) { 98 pm->SetActiveMenuBar(this, false); 99 } 100 } 101 return XULMenuParentElement::UnbindFromTree(aContext); 102 } 103 104 } // namespace mozilla::dom