/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "XULMenuBarElement.h" #include "MenuBarListener.h" #include "XULButtonElement.h" #include "nsXULPopupManager.h" #include "mozilla/Assertions.h" #include "mozilla/dom/BindContext.h" #include "mozilla/AsyncEventDispatcher.h" namespace mozilla::dom { NS_IMPL_CYCLE_COLLECTION_CLASS(XULMenuBarElement) NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(XULMenuBarElement, XULMenuParentElement) if (tmp->mListener) { tmp->mListener->Detach(); tmp->mListener = nullptr; } NS_IMPL_CYCLE_COLLECTION_UNLINK_END NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(XULMenuBarElement, XULMenuParentElement) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mListener) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_IMPL_ISUPPORTS_CYCLE_COLLECTION_INHERITED_0(XULMenuBarElement, XULMenuParentElement) XULMenuBarElement::XULMenuBarElement( already_AddRefed&& aNodeInfo) : XULMenuParentElement(std::move(aNodeInfo)) {} XULMenuBarElement::~XULMenuBarElement() { MOZ_DIAGNOSTIC_ASSERT(!mListener); } void XULMenuBarElement::SetActive(bool aActiveFlag) { // If the activity is not changed, there is nothing to do. if (mIsActive == aActiveFlag) { return; } // We can't activate a menubar outside of the document. if (!IsInComposedDoc()) { MOZ_ASSERT(!mIsActive, "How?"); return; } if (!aActiveFlag) { // If there is a request to deactivate the menu bar, check to see whether // there is a menu popup open for the menu bar. In this case, don't // deactivate the menu bar. if (auto* activeChild = GetActiveMenuChild()) { if (activeChild->IsMenuPopupOpen()) { return; } } } mIsActive = aActiveFlag; if (nsXULPopupManager* pm = nsXULPopupManager::GetInstance()) { pm->SetActiveMenuBar(this, aActiveFlag); } if (!aActiveFlag) { mActiveByKeyboard = false; SetActiveMenuChild(nullptr); } RefPtr dispatcher = new AsyncEventDispatcher( this, aActiveFlag ? u"DOMMenuBarActive"_ns : u"DOMMenuBarInactive"_ns, CanBubble::eYes, ChromeOnlyDispatch::eNo); DebugOnly rv = dispatcher->PostDOMEvent(); NS_ASSERTION(NS_SUCCEEDED(rv), "AsyncEventDispatcher failed to dispatch"); } nsresult XULMenuBarElement::BindToTree(BindContext& aContext, nsINode& aParent) { MOZ_TRY(XULMenuParentElement::BindToTree(aContext, aParent)); MOZ_DIAGNOSTIC_ASSERT(!mListener); if (aContext.InComposedDoc()) { mListener = new MenuBarListener(*this); } return NS_OK; } void XULMenuBarElement::UnbindFromTree(bool aNullParent) { if (mListener) { mListener->Detach(); mListener = nullptr; } if (NS_WARN_IF(mIsActive)) { // Clean up silently when getting removed from the document while active. mIsActive = false; if (nsXULPopupManager* pm = nsXULPopupManager::GetInstance()) { pm->SetActiveMenuBar(this, false); } } return XULMenuParentElement::UnbindFromTree(aNullParent); } } // namespace mozilla::dom