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/. */
7 #include "XULMenuBarElement.h"
8 #include "MenuBarListener.h"
9 #include "XULButtonElement.h"
10 #include "nsXULPopupManager.h"
11 #include "mozilla/Assertions.h"
12 #include "mozilla/dom/BindContext.h"
13 #include "mozilla/AsyncEventDispatcher.h"
14 #include "mozilla/Try.h"
16 namespace mozilla::dom
{
18 NS_IMPL_CYCLE_COLLECTION_CLASS(XULMenuBarElement
)
19 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(XULMenuBarElement
,
22 tmp
->mListener
->Detach();
23 tmp
->mListener
= nullptr;
25 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
26 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(XULMenuBarElement
,
28 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mListener
)
29 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
30 NS_IMPL_ISUPPORTS_CYCLE_COLLECTION_INHERITED_0(XULMenuBarElement
,
33 XULMenuBarElement::XULMenuBarElement(
34 already_AddRefed
<class NodeInfo
>&& aNodeInfo
)
35 : XULMenuParentElement(std::move(aNodeInfo
)) {}
37 XULMenuBarElement::~XULMenuBarElement() { MOZ_DIAGNOSTIC_ASSERT(!mListener
); }
39 void XULMenuBarElement::SetActive(bool aActiveFlag
) {
40 // If the activity is not changed, there is nothing to do.
41 if (mIsActive
== aActiveFlag
) {
45 // We can't activate a menubar outside of the document.
46 if (!IsInComposedDoc()) {
47 MOZ_ASSERT(!mIsActive
, "How?");
52 // If there is a request to deactivate the menu bar, check to see whether
53 // there is a menu popup open for the menu bar. In this case, don't
54 // deactivate the menu bar.
55 if (auto* activeChild
= GetActiveMenuChild()) {
56 if (activeChild
->IsMenuPopupOpen()) {
62 mIsActive
= aActiveFlag
;
63 if (nsXULPopupManager
* pm
= nsXULPopupManager::GetInstance()) {
64 pm
->SetActiveMenuBar(this, aActiveFlag
);
67 mActiveByKeyboard
= false;
68 SetActiveMenuChild(nullptr);
71 RefPtr dispatcher
= new AsyncEventDispatcher(
72 this, aActiveFlag
? u
"DOMMenuBarActive"_ns
: u
"DOMMenuBarInactive"_ns
,
73 CanBubble::eYes
, ChromeOnlyDispatch::eNo
);
74 DebugOnly
<nsresult
> rv
= dispatcher
->PostDOMEvent();
75 NS_ASSERTION(NS_SUCCEEDED(rv
), "AsyncEventDispatcher failed to dispatch");
78 nsresult
XULMenuBarElement::BindToTree(BindContext
& aContext
,
80 MOZ_TRY(XULMenuParentElement::BindToTree(aContext
, aParent
));
81 MOZ_DIAGNOSTIC_ASSERT(!mListener
);
82 if (aContext
.InComposedDoc()) {
83 mListener
= new MenuBarListener(*this);
88 void XULMenuBarElement::UnbindFromTree(UnbindContext
& aContext
) {
93 if (NS_WARN_IF(mIsActive
)) {
94 // Clean up silently when getting removed from the document while active.
96 if (nsXULPopupManager
* pm
= nsXULPopupManager::GetInstance()) {
97 pm
->SetActiveMenuBar(this, false);
100 return XULMenuParentElement::UnbindFromTree(aContext
);
103 } // namespace mozilla::dom