Bug 1812329 - Remove nsMenuBarFrame. r=smaug

This ended up being a lot more straight-forward than the menu changes.

TLDR:

 * nsMenuBarFrame -> XULMenuBarElement
 * nsMenuBarListener -> MenuBarListener

Rest should be rather straight-forward.

Depends on D168649

Differential Revision: https://phabricator.services.mozilla.com/D167809
This commit is contained in:
Emilio Cobos Álvarez 2023-02-07 18:09:37 +00:00
parent 720ce2d73f
commit b9833bfcca
23 changed files with 379 additions and 476 deletions

View file

@ -6,6 +6,7 @@
#include "XULMenuAccessible.h"
#include "LocalAccessible-inl.h"
#include "XULMenuBarElement.h"
#include "XULMenuParentElement.h"
#include "XULPopupElement.h"
#include "mozilla/Assertions.h"
@ -21,7 +22,6 @@
#include "nsIDOMXULSelectCntrlEl.h"
#include "nsIDOMXULSelectCntrlItemEl.h"
#include "nsIContent.h"
#include "nsMenuBarFrame.h"
#include "nsMenuPopupFrame.h"
#include "mozilla/Preferences.h"
@ -464,8 +464,8 @@ role XULMenubarAccessible::NativeRole() const { return roles::MENUBAR; }
// XULMenubarAccessible: Widgets
bool XULMenubarAccessible::IsActiveWidget() const {
nsMenuBarFrame* menuBarFrame = do_QueryFrame(GetFrame());
return menuBarFrame && menuBarFrame->IsActive();
auto* menuBar = dom::XULMenuBarElement::FromNode(GetContent());
return menuBar && menuBar->IsActive();
}
bool XULMenubarAccessible::AreItemsOperable() const { return true; }

View file

@ -4,24 +4,21 @@
* 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 "nsMenuBarListener.h"
#include "MenuBarListener.h"
#include "XULButtonElement.h"
#include "mozilla/Attributes.h"
#include "mozilla/dom/XULButtonElement.h"
#include "nsMenuBarFrame.h"
#include "nsMenuPopupFrame.h"
#include "nsPIWindowRoot.h"
#include "nsISound.h"
// Drag & Drop, Clipboard
#include "nsWidgetsCID.h"
#include "nsCOMPtr.h"
#include "nsIContent.h"
#include "nsContentUtils.h"
#include "nsPIWindowRoot.h"
#include "nsIFrame.h"
#include "mozilla/BasicEvents.h"
#include "mozilla/LookAndFeel.h"
#include "mozilla/Preferences.h"
#include "mozilla/LookAndFeel.h"
#include "mozilla/StaticPrefs_ui.h"
#include "mozilla/TextEvents.h"
#include "mozilla/dom/Document.h"
@ -29,31 +26,30 @@
#include "mozilla/dom/EventBinding.h"
#include "mozilla/dom/KeyboardEvent.h"
#include "mozilla/dom/KeyboardEventBinding.h"
#include "mozilla/dom/XULButtonElement.h"
#include "mozilla/dom/XULMenuBarElement.h"
#include "mozilla/dom/XULMenuParentElement.h"
#include "nsXULPopupManager.h"
using namespace mozilla;
using mozilla::dom::Event;
using mozilla::dom::KeyboardEvent;
namespace mozilla::dom {
/*
* nsMenuBarListener implementation
*/
NS_IMPL_CYCLE_COLLECTION(MenuBarListener, mTopWindowEventTarget)
NS_IMPL_ISUPPORTS(nsMenuBarListener, nsIDOMEventListener)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(MenuBarListener)
NS_INTERFACE_MAP_ENTRY(nsIDOMEventListener)
NS_INTERFACE_MAP_END
////////////////////////////////////////////////////////////////////////
NS_IMPL_CYCLE_COLLECTING_ADDREF(MenuBarListener)
NS_IMPL_CYCLE_COLLECTING_RELEASE(MenuBarListener)
nsMenuBarListener::nsMenuBarListener(nsMenuBarFrame* aMenuBarFrame,
nsIContent* aMenuBarContent)
: mMenuBarFrame(aMenuBarFrame),
mContent(dom::XULMenuParentElement::FromNode(aMenuBarContent)),
mEventTarget(aMenuBarContent->GetComposedDoc()),
MenuBarListener::MenuBarListener(XULMenuBarElement& aElement)
: mMenuBar(&aElement),
mEventTarget(aElement.GetComposedDoc()),
mTopWindowEventTarget(nullptr),
mAccessKeyDown(false),
mAccessKeyDownCanceled(false) {
MOZ_ASSERT(mEventTarget);
MOZ_ASSERT(mContent);
MOZ_ASSERT(mMenuBar);
// Hook up the menubar as a key listener on the whole document. This will
// see every keypress that occurs, but after everyone else does.
@ -78,20 +74,16 @@ nsMenuBarListener::nsMenuBarListener(nsMenuBarFrame* aMenuBarFrame,
mEventTarget->AddEventListener(u"MozDOMFullscreen:Entered"_ns, this, false);
// Needs to listen to the deactivate event of the window.
RefPtr<dom::EventTarget> topWindowEventTarget =
nsContentUtils::GetWindowRoot(aMenuBarContent->GetComposedDoc());
mTopWindowEventTarget = topWindowEventTarget.get();
mTopWindowEventTarget = nsContentUtils::GetWindowRoot(mEventTarget);
mTopWindowEventTarget->AddSystemEventListener(u"deactivate"_ns, this, true);
}
////////////////////////////////////////////////////////////////////////
nsMenuBarListener::~nsMenuBarListener() {
MOZ_ASSERT(!mEventTarget,
"OnDestroyMenuBarFrame() should've alreay been called");
MenuBarListener::~MenuBarListener() {
MOZ_ASSERT(!mEventTarget, "Should've detached always");
}
void nsMenuBarListener::OnDestroyMenuBarFrame() {
void MenuBarListener::Detach() {
mEventTarget->RemoveSystemEventListener(u"keypress"_ns, this, false);
mEventTarget->RemoveSystemEventListener(u"keydown"_ns, this, false);
mEventTarget->RemoveSystemEventListener(u"keyup"_ns, this, false);
@ -109,23 +101,26 @@ void nsMenuBarListener::OnDestroyMenuBarFrame() {
mTopWindowEventTarget->RemoveSystemEventListener(u"deactivate"_ns, this,
true);
mMenuBarFrame = nullptr;
mMenuBar = nullptr;
mEventTarget = nullptr;
mTopWindowEventTarget = nullptr;
}
void nsMenuBarListener::ToggleMenuActiveState() {
if (mMenuBarFrame->IsActive()) {
mMenuBarFrame->SetActive(false);
void MenuBarListener::ToggleMenuActiveState(ByKeyboard aByKeyboard) {
RefPtr menuBar = mMenuBar;
if (menuBar->IsActive()) {
menuBar->SetActive(false);
} else {
RefPtr content = mContent;
mMenuBarFrame->SetActive(true);
content->SelectFirstItem();
if (aByKeyboard == ByKeyboard::Yes) {
menuBar->SetActiveByKeyboard();
}
menuBar->SetActive(true);
menuBar->SelectFirstItem();
}
}
////////////////////////////////////////////////////////////////////////
nsresult nsMenuBarListener::KeyUp(Event* aKeyEvent) {
nsresult MenuBarListener::KeyUp(Event* aKeyEvent) {
WidgetKeyboardEvent* nativeKeyEvent =
aKeyEvent->WidgetEventPtr()->AsKeyboardEvent();
if (!nativeKeyEvent) {
@ -149,7 +144,7 @@ nsresult nsMenuBarListener::KeyUp(Event* aKeyEvent) {
// The access key was down and is now up, and no other
// keys were pressed in between.
bool toggleMenuActiveState = true;
if (!mMenuBarFrame->IsActive()) {
if (!mMenuBar->IsActive()) {
// If the focused content is in a remote process, we should allow the
// focused web app to prevent to activate the menubar.
if (nativeKeyEvent->WillBeSentToRemoteProcess()) {
@ -165,20 +160,17 @@ nsresult nsMenuBarListener::KeyUp(Event* aKeyEvent) {
}
// If menubar active state is changed or the menubar is destroyed
// during closing the popups, we should do nothing anymore.
toggleMenuActiveState = !Destroyed() && !mMenuBarFrame->IsActive();
toggleMenuActiveState = !Destroyed() && !mMenuBar->IsActive();
}
if (toggleMenuActiveState) {
if (!mMenuBarFrame->IsActive()) {
mMenuBarFrame->SetActiveByKeyboard();
}
ToggleMenuActiveState();
ToggleMenuActiveState(ByKeyboard::Yes);
}
}
mAccessKeyDown = false;
mAccessKeyDownCanceled = false;
if (!Destroyed() && mMenuBarFrame->IsActive()) {
if (!Destroyed() && mMenuBar->IsActive()) {
nativeKeyEvent->StopPropagation();
nativeKeyEvent->PreventDefault();
}
@ -187,7 +179,7 @@ nsresult nsMenuBarListener::KeyUp(Event* aKeyEvent) {
}
////////////////////////////////////////////////////////////////////////
nsresult nsMenuBarListener::KeyPress(Event* aKeyEvent) {
nsresult MenuBarListener::KeyPress(Event* aKeyEvent) {
// if event has already been handled, bail
if (!aKeyEvent || aKeyEvent->DefaultPrevented()) {
return NS_OK; // don't consume event
@ -198,7 +190,7 @@ nsresult nsMenuBarListener::KeyPress(Event* aKeyEvent) {
return NS_OK;
}
auto accessKey = LookAndFeel::GetMenuAccessKey();
const auto accessKey = LookAndFeel::GetMenuAccessKey();
if (!accessKey) {
return NS_OK;
}
@ -235,12 +227,11 @@ nsresult nsMenuBarListener::KeyPress(Event* aKeyEvent) {
}
// The F10 key just went down by itself or with ctrl pressed.
// In Windows, both of these activate the menu bar.
mMenuBarFrame->SetActiveByKeyboard();
ToggleMenuActiveState();
ToggleMenuActiveState(ByKeyboard::Yes);
if (mMenuBarFrame->IsActive()) {
if (mMenuBar && mMenuBar->IsActive()) {
# ifdef MOZ_WIDGET_GTK
RefPtr child = mContent->GetActiveMenuChild();
RefPtr child = mMenuBar->GetActiveMenuChild();
// In GTK, this also opens the first menu.
child->OpenMenuPopup(false);
# endif
@ -260,11 +251,11 @@ nsresult nsMenuBarListener::KeyPress(Event* aKeyEvent) {
// the menu bar.
// TODO(emilio): This is rather odd, and I cannot get the beep to work,
// but this matches what old code was doing...
if (mMenuBarFrame->IsActive()) {
if (mMenuBar && mMenuBar->IsActive()) {
if (nsCOMPtr<nsISound> sound = do_GetService("@mozilla.org/sound;1")) {
sound->Beep();
}
mMenuBarFrame->SetActive(false);
ToggleMenuActiveState(ByKeyboard::Yes);
}
#endif
return NS_OK;
@ -282,8 +273,9 @@ nsresult nsMenuBarListener::KeyPress(Event* aKeyEvent) {
return NS_OK;
}
mMenuBarFrame->SetActiveByKeyboard();
mMenuBarFrame->SetActive(true);
RefPtr menuBar = mMenuBar;
menuBar->SetActiveByKeyboard();
menuBar->SetActive(true);
menuForKey->OpenMenuPopup(true);
// The opened menu will listen next keyup event.
@ -292,11 +284,10 @@ nsresult nsMenuBarListener::KeyPress(Event* aKeyEvent) {
aKeyEvent->StopPropagation();
aKeyEvent->PreventDefault();
return NS_OK;
}
dom::XULButtonElement* nsMenuBarListener::GetMenuForKeyEvent(
dom::XULButtonElement* MenuBarListener::GetMenuForKeyEvent(
KeyboardEvent& aKeyEvent) {
if (!aKeyEvent.IsMenuAccessKeyPressed()) {
return nullptr;
@ -318,10 +309,10 @@ dom::XULButtonElement* nsMenuBarListener::GetMenuForKeyEvent(
// Do shortcut navigation.
// A letter was pressed. We want to see if a shortcut gets matched. If
// so, we'll know the menu got activated.
return mMenuBarFrame->MenubarElement().FindMenuWithShortcut(aKeyEvent);
return mMenuBar->FindMenuWithShortcut(aKeyEvent);
}
void nsMenuBarListener::ReserveKeyIfNeeded(Event* aKeyEvent) {
void MenuBarListener::ReserveKeyIfNeeded(Event* aKeyEvent) {
WidgetKeyboardEvent* nativeKeyEvent =
aKeyEvent->WidgetEventPtr()->AsKeyboardEvent();
if (nsContentUtils::ShouldBlockReservedKeys(nativeKeyEvent)) {
@ -330,7 +321,7 @@ void nsMenuBarListener::ReserveKeyIfNeeded(Event* aKeyEvent) {
}
////////////////////////////////////////////////////////////////////////
nsresult nsMenuBarListener::KeyDown(Event* aKeyEvent) {
nsresult MenuBarListener::KeyDown(Event* aKeyEvent) {
// handlers shouldn't be triggered by non-trusted events.
if (!aKeyEvent || !aKeyEvent->IsTrusted()) {
return NS_OK;
@ -360,9 +351,9 @@ nsresult nsMenuBarListener::KeyDown(Event* aKeyEvent) {
// Especially CTRL. CTRL+ALT == AltGR, and we'll break on non-US
// enhanced 102-key keyboards if we don't check this.
bool isAccessKeyDownEvent =
theChar == accessKey &&
(keyEvent->GetModifiersForMenuAccessKey() &
~LookAndFeel::GetMenuAccessKeyModifiers()) == 0;
(theChar == accessKey &&
(keyEvent->GetModifiersForMenuAccessKey() &
~LookAndFeel::GetMenuAccessKeyModifiers()) == 0);
if (!capturing && !mAccessKeyDown) {
// If accesskey isn't being pressed and the key isn't the accesskey,
@ -389,7 +380,7 @@ nsresult nsMenuBarListener::KeyDown(Event* aKeyEvent) {
mAccessKeyDownCanceled = !isAccessKeyDownEvent;
}
if (capturing && LookAndFeel::GetMenuAccessKey()) {
if (capturing && accessKey) {
if (GetMenuForKeyEvent(*keyEvent)) {
ReserveKeyIfNeeded(aKeyEvent);
}
@ -400,9 +391,9 @@ nsresult nsMenuBarListener::KeyDown(Event* aKeyEvent) {
////////////////////////////////////////////////////////////////////////
nsresult nsMenuBarListener::Blur(Event* aEvent) {
if (!IsMenuOpen() && mMenuBarFrame->IsActive()) {
ToggleMenuActiveState();
nsresult MenuBarListener::Blur(Event* aEvent) {
if (!IsMenuOpen() && mMenuBar->IsActive()) {
ToggleMenuActiveState(ByKeyboard::No);
mAccessKeyDown = false;
mAccessKeyDownCanceled = false;
}
@ -411,7 +402,7 @@ nsresult nsMenuBarListener::Blur(Event* aEvent) {
////////////////////////////////////////////////////////////////////////
nsresult nsMenuBarListener::OnWindowDeactivated(Event* aEvent) {
nsresult MenuBarListener::OnWindowDeactivated(Event* aEvent) {
// Reset the accesskey state because we cannot receive the keyup event for
// the pressing accesskey.
mAccessKeyDown = false;
@ -419,13 +410,13 @@ nsresult nsMenuBarListener::OnWindowDeactivated(Event* aEvent) {
return NS_OK; // means I am NOT consuming event
}
bool nsMenuBarListener::IsMenuOpen() const {
auto* activeChild = mContent->GetActiveMenuChild();
bool MenuBarListener::IsMenuOpen() const {
auto* activeChild = mMenuBar->GetActiveMenuChild();
return activeChild && activeChild->IsMenuPopupOpen();
}
////////////////////////////////////////////////////////////////////////
nsresult nsMenuBarListener::MouseDown(Event* aMouseEvent) {
nsresult MenuBarListener::MouseDown(Event* aMouseEvent) {
// NOTE: MouseDown method listens all phases
// Even if the mousedown event is canceled, it means the user don't want
@ -440,8 +431,8 @@ nsresult nsMenuBarListener::MouseDown(Event* aMouseEvent) {
return NS_OK;
}
if (!IsMenuOpen() && mMenuBarFrame->IsActive()) {
ToggleMenuActiveState();
if (!IsMenuOpen() && mMenuBar->IsActive()) {
ToggleMenuActiveState(ByKeyboard::No);
}
return NS_OK; // means I am NOT consuming event
@ -449,18 +440,19 @@ nsresult nsMenuBarListener::MouseDown(Event* aMouseEvent) {
////////////////////////////////////////////////////////////////////////
nsresult nsMenuBarListener::Fullscreen(Event* aEvent) {
if (mMenuBarFrame->IsActive()) {
ToggleMenuActiveState();
nsresult MenuBarListener::Fullscreen(Event* aEvent) {
if (mMenuBar->IsActive()) {
ToggleMenuActiveState(ByKeyboard::No);
}
return NS_OK;
}
////////////////////////////////////////////////////////////////////////
MOZ_CAN_RUN_SCRIPT_BOUNDARY nsresult
nsMenuBarListener::HandleEvent(Event* aEvent) {
MenuBarListener::HandleEvent(Event* aEvent) {
// If the menu bar is collapsed, don't do anything.
if (!mMenuBarFrame->StyleVisibility()->IsVisible()) {
if (!mMenuBar->GetPrimaryFrame() ||
!mMenuBar->GetPrimaryFrame()->StyleVisibility()->IsVisible()) {
return NS_OK;
}
@ -495,3 +487,5 @@ nsMenuBarListener::HandleEvent(Event* aEvent) {
MOZ_ASSERT_UNREACHABLE("Unexpected eventType");
return NS_OK;
}
} // namespace mozilla::dom

83
dom/xul/MenuBarListener.h Normal file
View file

@ -0,0 +1,83 @@
/* -*- 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/. */
#ifndef mozilla_dom_MenuBarListener_h
#define mozilla_dom_MenuBarListener_h
#include "mozilla/Attributes.h"
#include "mozilla/EventForwards.h"
#include "nsIDOMEventListener.h"
#include "nsCycleCollectionParticipant.h"
#include "nsISupports.h"
namespace mozilla::dom {
class Document;
class EventTarget;
class KeyboardEvent;
class XULMenuBarElement;
class XULButtonElement;
class MenuBarListener final : public nsIDOMEventListener {
public:
explicit MenuBarListener(XULMenuBarElement&);
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_CLASS(MenuBarListener)
NS_DECL_NSIDOMEVENTLISTENER
// Should be called when unbound from the document and so on.
void Detach();
protected:
virtual ~MenuBarListener();
bool IsMenuOpen() const;
MOZ_CAN_RUN_SCRIPT nsresult KeyUp(Event* aMouseEvent);
MOZ_CAN_RUN_SCRIPT nsresult KeyDown(Event* aMouseEvent);
MOZ_CAN_RUN_SCRIPT nsresult KeyPress(Event* aMouseEvent);
MOZ_CAN_RUN_SCRIPT nsresult Blur(Event* aEvent);
MOZ_CAN_RUN_SCRIPT nsresult OnWindowDeactivated(Event* aEvent);
MOZ_CAN_RUN_SCRIPT nsresult MouseDown(Event* aMouseEvent);
MOZ_CAN_RUN_SCRIPT nsresult Fullscreen(Event* aEvent);
/**
* Given a key event for an Alt+shortcut combination,
* return the menu, if any, that would be opened. If aPeek
* is false, then play a beep and deactivate the menubar on Windows.
*/
XULButtonElement* GetMenuForKeyEvent(KeyboardEvent& aKeyEvent);
/**
* Call MarkAsReservedByChrome if the user's preferences indicate that
* the key should be chrome-only.
*/
void ReserveKeyIfNeeded(Event* aKeyEvent);
// This should only be called by the MenuBarListener during event dispatch.
enum class ByKeyboard : bool { No, Yes };
MOZ_CAN_RUN_SCRIPT void ToggleMenuActiveState(ByKeyboard);
bool Destroyed() const { return !mMenuBar; }
// The menu bar object. Safe because it keeps us alive.
XULMenuBarElement* mMenuBar;
// The event target to listen to the events.
//
// Weak reference is safe because we clear the listener on unbind from the
// document.
Document* mEventTarget;
// The top window as EventTarget.
RefPtr<EventTarget> mTopWindowEventTarget;
// Whether or not the ALT key is currently down.
bool mAccessKeyDown = false;
// Whether or not the ALT key down is canceled by other action.
bool mAccessKeyDownCanceled = false;
};
} // namespace mozilla::dom
#endif // #ifndef mozilla_dom_MenuBarListener_h

View file

@ -18,12 +18,12 @@
#include "mozilla/dom/MouseEventBinding.h"
#include "mozilla/dom/NameSpaceConstants.h"
#include "mozilla/dom/AncestorIterator.h"
#include "mozilla/dom/XULMenuBarElement.h"
#include "nsGkAtoms.h"
#include "nsITimer.h"
#include "nsLayoutUtils.h"
#include "nsCaseTreatment.h"
#include "nsChangeHint.h"
#include "nsMenuBarFrame.h"
#include "nsMenuPopupFrame.h"
#include "nsPlaceholderFrame.h"
#include "nsPresContext.h"
@ -444,7 +444,8 @@ void XULButtonElement::PostHandleEventForMenus(
// If we're open we never deselect. PopupClosed will do as needed.
return false;
}
if (!parent->IsMenuBar()) {
auto* menubar = XULMenuBarElement::FromNode(*parent);
if (!menubar) {
// Don't de-select when not in the menubar.
// NOTE(emilio): Behavior from before bug 1811466 is equivalent to
// returning true here, consider flipping this.
@ -452,9 +453,7 @@ void XULButtonElement::PostHandleEventForMenus(
}
// De-select when exiting a menubar item, if the menubar wasn't
// activated by keyboard.
nsMenuBarFrame* menubar = do_QueryFrame(parent->GetPrimaryFrame());
const bool openedByKey = menubar && menubar->IsActiveByKeyboard();
return !openedByKey;
return !menubar->IsActiveByKeyboard();
}();
if (shouldDeactivate) {
@ -756,17 +755,11 @@ auto XULButtonElement::GetMenuType() const -> Maybe<MenuType> {
}
}
nsMenuBarFrame* XULButtonElement::GetMenuBar(FlushType aFlushType) {
XULMenuBarElement* XULButtonElement::GetMenuBar() const {
if (!IsMenu()) {
return nullptr;
}
nsIFrame* frame = GetPrimaryFrame(aFlushType);
for (; frame; frame = frame->GetParent()) {
if (nsMenuBarFrame* menubar = do_QueryFrame(frame)) {
return menubar;
}
}
return nullptr;
return FirstAncestorOfType<XULMenuBarElement>();
}
XULMenuParentElement* XULButtonElement::GetMenuParent() const {
@ -800,8 +793,8 @@ nsMenuPopupFrame* XULButtonElement::GetMenuPopup(FlushType aFlushType) {
return do_QueryFrame(popup->GetPrimaryFrame(aFlushType));
}
bool XULButtonElement::OpenedWithKey() {
nsMenuBarFrame* menubar = GetMenuBar(FlushType::Frames);
bool XULButtonElement::OpenedWithKey() const {
auto* menubar = GetMenuBar();
return menubar && menubar->IsActiveByKeyboard();
}

View file

@ -19,6 +19,7 @@ namespace mozilla::dom {
class KeyboardEvent;
class XULPopupElement;
class XULMenuBarElement;
class XULMenuParentElement;
class XULButtonElement : public nsXULElement {
@ -57,7 +58,7 @@ class XULButtonElement : public nsXULElement {
void UnbindFromTree(bool aNullParent) override;
MOZ_CAN_RUN_SCRIPT bool HandleKeyPress(KeyboardEvent& keyEvent);
MOZ_CAN_RUN_SCRIPT bool OpenedWithKey();
bool OpenedWithKey() const;
// Called to execute our command handler.
MOZ_CAN_RUN_SCRIPT void ExecuteMenu(WidgetEvent&);
MOZ_CAN_RUN_SCRIPT void ExecuteMenu(Modifiers, int16_t aButton,
@ -93,8 +94,8 @@ class XULButtonElement : public nsXULElement {
bool IsDisabled() const { return GetXULBoolAttr(nsGkAtoms::disabled); }
private:
XULMenuBarElement* GetMenuBar() const;
void Blurred();
nsMenuBarFrame* GetMenuBar(FlushType aFlushType);
enum class MenuType {
Checkbox,
Radio,

View file

@ -0,0 +1,92 @@
/* -*- 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_INHERITED(XULMenuBarElement, XULMenuParentElement,
mListener)
NS_IMPL_ISUPPORTS_CYCLE_COLLECTION_INHERITED_0(XULMenuBarElement,
XULMenuParentElement)
XULMenuBarElement::XULMenuBarElement(
already_AddRefed<class NodeInfo>&& 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<nsresult> 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

View file

@ -0,0 +1,61 @@
/* -*- 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/. */
#ifndef XULMenuBarElement_h__
#define XULMenuBarElement_h__
#include "mozilla/Attributes.h"
#include "mozilla/dom/NameSpaceConstants.h"
#include "nsINode.h"
#include "nsISupports.h"
#include "XULMenuParentElement.h"
namespace mozilla::dom {
class KeyboardEvent;
class XULButtonElement;
class MenuBarListener;
nsXULElement* NS_NewXULMenuBarElement(
already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo);
class XULMenuBarElement final : public XULMenuParentElement {
public:
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(XULMenuBarElement,
XULMenuParentElement)
NS_IMPL_FROMNODE_WITH_TAG(XULMenuBarElement, kNameSpaceID_XUL, menubar)
explicit XULMenuBarElement(already_AddRefed<class NodeInfo>&&);
MOZ_CAN_RUN_SCRIPT void SetActive(bool);
bool IsActive() const { return mIsActive; }
void SetActiveByKeyboard() { mActiveByKeyboard = true; }
bool IsActiveByKeyboard() const { return mActiveByKeyboard; }
MOZ_CAN_RUN_SCRIPT void MenuClosed() { SetActive(false); }
nsresult BindToTree(BindContext&, nsINode& aParent) override;
void UnbindFromTree(bool aNullParent) override;
protected:
~XULMenuBarElement() override;
// Whether or not the menu bar is active (a menu item is highlighted or
// shown).
bool mIsActive = false;
// Whether the menubar was made active via the keyboard.
bool mActiveByKeyboard = false;
// The event listener that listens to document key presses and so on.
RefPtr<MenuBarListener> mListener;
};
} // namespace mozilla::dom
#endif // XULMenuBarElement_h

View file

@ -11,7 +11,6 @@
#include "mozilla/dom/XULPopupElement.h"
#include "mozilla/dom/KeyboardEvent.h"
#include "mozilla/dom/KeyboardEventBinding.h"
#include "nsMenuBarListener.h"
#include "nsXULPopupManager.h"
#include "nsMenuPopupFrame.h"

View file

@ -5,20 +5,20 @@
#include "XULMenuParentElement.h"
#include "XULButtonElement.h"
#include "XULMenuBarElement.h"
#include "XULPopupElement.h"
#include "mozilla/LookAndFeel.h"
#include "mozilla/StaticAnalysisFunctions.h"
#include "mozilla/TextEvents.h"
#include "mozilla/dom/DocumentInlines.h"
#include "mozilla/dom/KeyboardEvent.h"
#include "mozilla/EventDispatcher.h"
#include "nsDebug.h"
#include "nsMenuBarFrame.h"
#include "nsMenuPopupFrame.h"
#include "nsString.h"
#include "nsStringFwd.h"
#include "nsUTF8Utils.h"
#include "nsXULElement.h"
#include "nsMenuBarListener.h"
#include "nsXULPopupManager.h"
namespace mozilla::dom {
@ -127,8 +127,9 @@ void XULMenuParentElement::SetActiveMenuChild(XULButtonElement* aChild,
}
mActiveItem = nullptr;
if (nsMenuBarFrame* f = do_QueryFrame(GetPrimaryFrame())) {
f->SetActive(!!aChild);
if (auto* menuBar = XULMenuBarElement::FromNode(*this)) {
// KnownLive because `this` is known-live by definition.
MOZ_KnownLive(menuBar)->SetActive(!!aChild);
}
if (!aChild) {
@ -388,4 +389,10 @@ XULButtonElement* XULMenuParentElement::FindMenuWithShortcut(
return foundMenuBeforeCurrent;
}
void XULMenuParentElement::HandleEnterKeyPress(WidgetEvent& aEvent) {
if (RefPtr child = GetActiveMenuChild()) {
child->HandleEnterKeyPress(aEvent);
}
}
} // namespace mozilla::dom

View file

@ -41,6 +41,7 @@ class XULMenuParentElement : public nsXULElement {
XULButtonElement* FindMenuWithShortcut(KeyboardEvent&) const;
XULButtonElement* FindMenuWithShortcut(const nsAString& aString,
bool& aDoAction) const;
MOZ_CAN_RUN_SCRIPT void HandleEnterKeyPress(WidgetEvent&);
NS_IMPL_FROMNODE_HELPER(XULMenuParentElement,
IsAnyOfXULElements(nsGkAtoms::menupopup,

View file

@ -7,7 +7,6 @@
#include "XULMenuParentElement.h"
#include "nsCOMPtr.h"
#include "nsIContent.h"
#include "nsMenuBarListener.h"
#include "nsNameSpaceManager.h"
#include "nsGkAtoms.h"
#include "nsMenuPopupFrame.h"

View file

@ -24,6 +24,7 @@ EXPORTS.mozilla.dom += [
"XULBroadcastManager.h",
"XULButtonElement.h",
"XULFrameElement.h",
"XULMenuBarElement.h",
"XULMenuElement.h",
"XULMenuParentElement.h",
"XULPersist.h",
@ -35,6 +36,7 @@ EXPORTS.mozilla.dom += [
]
UNIFIED_SOURCES += [
"MenuBarListener.cpp",
"nsXULCommandDispatcher.cpp",
"nsXULContentSink.cpp",
"nsXULContentUtils.cpp",
@ -46,6 +48,7 @@ UNIFIED_SOURCES += [
"XULBroadcastManager.cpp",
"XULButtonElement.cpp",
"XULFrameElement.cpp",
"XULMenuBarElement.cpp",
"XULMenuElement.cpp",
"XULMenuParentElement.cpp",
"XULPersist.cpp",

View file

@ -14,6 +14,7 @@
#include "XULButtonElement.h"
#include "XULFrameElement.h"
#include "XULMenuElement.h"
#include "XULMenuBarElement.h"
#include "XULPopupElement.h"
#include "XULResizerElement.h"
#include "XULTextElement.h"
@ -185,7 +186,7 @@ nsXULElement* nsXULElement::Construct(
if (nodeInfo->Equals(nsGkAtoms::menubar)) {
auto* nim = nodeInfo->NodeInfoManager();
return new (nim) XULMenuParentElement(nodeInfo.forget());
return new (nim) XULMenuBarElement(nodeInfo.forget());
}
if (nodeInfo->Equals(nsGkAtoms::menu) ||

View file

@ -39,7 +39,6 @@
#include "mozilla/Unused.h"
#include "RetainedDisplayListBuilder.h"
#include "nsAbsoluteContainingBlock.h"
#include "nsMenuBarListener.h"
#include "nsCSSPseudoElements.h"
#include "nsCheckboxRadioFrame.h"
#include "nsCRT.h"
@ -221,8 +220,6 @@ nsIFrame* NS_NewMenuPopupFrame(PresShell* aPresShell, ComputedStyle* aStyle);
nsIFrame* NS_NewMenuFrame(PresShell* aPresShell, ComputedStyle* aStyle,
uint32_t aFlags);
nsIFrame* NS_NewMenuBarFrame(PresShell* aPresShell, ComputedStyle* aStyle);
nsIFrame* NS_NewTreeBodyFrame(PresShell* aPresShell, ComputedStyle* aStyle);
nsHTMLScrollFrame* NS_NewHTMLScrollFrame(PresShell* aPresShell,
@ -4155,8 +4152,6 @@ nsCSSFrameConstructor::FindXULTagData(const Element& aElement,
nsCSSFrameConstructor::FindXULLabelOrDescriptionData),
#ifdef XP_MACOSX
SIMPLE_TAG_CHAIN(menubar, nsCSSFrameConstructor::FindXULMenubarData),
#else
SIMPLE_XUL_CREATE(menubar, NS_NewMenuBarFrame),
#endif /* XP_MACOSX */
SIMPLE_XUL_CREATE(iframe, NS_NewSubDocumentFrame),
SIMPLE_XUL_CREATE(editor, NS_NewSubDocumentFrame),
@ -4209,9 +4204,7 @@ nsCSSFrameConstructor::FindXULMenubarData(const Element& aElement,
}
}
static constexpr FrameConstructionData sMenubarData =
SIMPLE_XUL_FCDATA(NS_NewMenuBarFrame);
return &sMenubarData;
return nullptr;
}
#endif /* XP_MACOSX */

View file

@ -63,7 +63,6 @@ FRAME_CLASSES = [
Frame("nsMathMLmunderoverFrame", "None", NOT_LEAF),
Frame("nsMathMLsemanticsFrame", "None", NOT_LEAF),
Frame("nsMathMLTokenFrame", "None", NOT_LEAF),
Frame("nsMenuBarFrame", "Box", NOT_LEAF),
Frame("nsMenuPopupFrame", "MenuPopup", NOT_LEAF),
Frame("nsMeterFrame", "Meter", LEAF),
Frame("nsNumberControlFrame", "TextInput", LEAF),

View file

@ -25,8 +25,6 @@ UNIFIED_SOURCES += [
"nsBoxLayoutState.cpp",
"nsImageBoxFrame.cpp",
"nsLeafBoxFrame.cpp",
"nsMenuBarFrame.cpp",
"nsMenuBarListener.cpp",
"nsMenuPopupFrame.cpp",
"nsRepeatService.cpp",
"nsScrollbarButtonFrame.cpp",

View file

@ -1,136 +0,0 @@
/* -*- 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 "nsMenuBarFrame.h"
#include "mozilla/BasicEvents.h"
#include "nsIContent.h"
#include "nsAtom.h"
#include "nsPresContext.h"
#include "nsCSSRendering.h"
#include "nsNameSpaceManager.h"
#include "nsGkAtoms.h"
#include "nsMenuPopupFrame.h"
#include "nsUnicharUtils.h"
#include "nsPIDOMWindow.h"
#include "nsIInterfaceRequestorUtils.h"
#include "nsCSSFrameConstructor.h"
#ifdef XP_WIN
# include "nsISound.h"
# include "nsWidgetsCID.h"
#endif
#include "nsUTF8Utils.h"
#include "mozilla/ComputedStyle.h"
#include "mozilla/PresShell.h"
#include "mozilla/dom/Document.h"
#include "mozilla/dom/XULMenuParentElement.h"
#include "mozilla/dom/XULButtonElement.h"
using namespace mozilla;
//
// NS_NewMenuBarFrame
//
// Wrapper for creating a new menu Bar container
//
nsIFrame* NS_NewMenuBarFrame(PresShell* aPresShell, ComputedStyle* aStyle) {
return new (aPresShell) nsMenuBarFrame(aStyle, aPresShell->GetPresContext());
}
NS_IMPL_FRAMEARENA_HELPERS(nsMenuBarFrame)
NS_QUERYFRAME_HEAD(nsMenuBarFrame)
NS_QUERYFRAME_ENTRY(nsMenuBarFrame)
NS_QUERYFRAME_TAIL_INHERITING(nsBoxFrame)
//
// nsMenuBarFrame cntr
//
nsMenuBarFrame::nsMenuBarFrame(ComputedStyle* aStyle,
nsPresContext* aPresContext)
: nsBoxFrame(aStyle, aPresContext, kClassID) {}
void nsMenuBarFrame::Init(nsIContent* aContent, nsContainerFrame* aParent,
nsIFrame* aPrevInFlow) {
nsBoxFrame::Init(aContent, aParent, aPrevInFlow);
// Create the menu bar listener.
mMenuBarListener = new nsMenuBarListener(this, aContent);
}
dom::XULMenuParentElement& nsMenuBarFrame::MenubarElement() const {
auto* content = dom::XULMenuParentElement::FromNode(GetContent());
MOZ_DIAGNOSTIC_ASSERT(content);
return *content;
}
MOZ_CAN_RUN_SCRIPT void nsMenuBarFrame::SetActive(bool aActiveFlag) {
// If the activity is not changed, there is nothing to do.
if (mIsActive == aActiveFlag) {
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 = MenubarElement().GetActiveMenuChild()) {
if (activeChild->IsMenuPopupOpen()) {
return;
}
}
}
mIsActive = aActiveFlag;
if (mIsActive) {
InstallKeyboardNavigator();
} else {
mActiveByKeyboard = false;
RemoveKeyboardNavigator();
}
RefPtr menubar = &MenubarElement();
if (!aActiveFlag) {
menubar->SetActiveMenuChild(nullptr);
}
constexpr auto active = u"DOMMenuBarActive"_ns;
constexpr auto inactive = u"DOMMenuBarInactive"_ns;
FireDOMEvent(aActiveFlag ? active : inactive, menubar);
}
void nsMenuBarFrame::InstallKeyboardNavigator() {
if (nsXULPopupManager* pm = nsXULPopupManager::GetInstance()) {
pm->SetActiveMenuBar(this, true);
}
}
void nsMenuBarFrame::MenuClosed() { SetActive(false); }
void nsMenuBarFrame::HandleEnterKeyPress(WidgetEvent& aEvent) {
if (RefPtr<dom::XULButtonElement> activeChild =
MenubarElement().GetActiveMenuChild()) {
activeChild->HandleEnterKeyPress(aEvent);
}
}
void nsMenuBarFrame::RemoveKeyboardNavigator() {
if (!mIsActive) {
if (nsXULPopupManager* pm = nsXULPopupManager::GetInstance()) {
pm->SetActiveMenuBar(this, false);
}
}
}
void nsMenuBarFrame::DestroyFrom(nsIFrame* aDestructRoot,
PostDestroyData& aPostDestroyData) {
nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
if (pm) pm->SetActiveMenuBar(this, false);
mMenuBarListener->OnDestroyMenuBarFrame();
mMenuBarListener = nullptr;
nsBoxFrame::DestroyFrom(aDestructRoot, aPostDestroyData);
}

View file

@ -1,83 +0,0 @@
/* -*- 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/. */
//
// nsMenuBarFrame
//
#ifndef nsMenuBarFrame_h__
#define nsMenuBarFrame_h__
#include "nsAtom.h"
#include "nsCOMPtr.h"
#include "nsBoxFrame.h"
#include "nsMenuBarListener.h"
class nsIContent;
namespace mozilla {
class PresShell;
namespace dom {
class KeyboardEvent;
class XULMenuParentElement;
} // namespace dom
} // namespace mozilla
nsIFrame* NS_NewMenuBarFrame(mozilla::PresShell* aPresShell,
mozilla::ComputedStyle* aStyle);
class nsMenuBarFrame final : public nsBoxFrame {
public:
NS_DECL_QUERYFRAME
NS_DECL_FRAMEARENA_HELPERS(nsMenuBarFrame)
explicit nsMenuBarFrame(ComputedStyle* aStyle, nsPresContext* aPresContext);
void InstallKeyboardNavigator();
void RemoveKeyboardNavigator();
MOZ_CAN_RUN_SCRIPT void MenuClosed();
void Init(nsIContent* aContent, nsContainerFrame* aParent,
nsIFrame* aPrevInFlow) override;
void DestroyFrom(nsIFrame* aDestructRoot,
PostDestroyData& aPostDestroyData) override;
bool IsActiveByKeyboard() { return mActiveByKeyboard; }
void SetActiveByKeyboard() { mActiveByKeyboard = true; }
MOZ_CAN_RUN_SCRIPT void SetActive(bool aActive);
bool IsActive() const { return mIsActive; }
mozilla::dom::XULMenuParentElement& MenubarElement() const;
// Called when Enter is pressed while the menubar is focused. If the current
// menu is open, let the child handle the key.
MOZ_CAN_RUN_SCRIPT void HandleEnterKeyPress(mozilla::WidgetEvent&);
bool IsFrameOfType(uint32_t aFlags) const override {
// Override bogus IsFrameOfType in nsBoxFrame.
if (aFlags & (nsIFrame::eReplacedContainsBlock | nsIFrame::eReplaced))
return false;
return nsBoxFrame::IsFrameOfType(aFlags);
}
#ifdef DEBUG_FRAME_DUMP
nsresult GetFrameName(nsAString& aResult) const override {
return MakeFrameName(u"MenuBar"_ns, aResult);
}
#endif
protected:
RefPtr<nsMenuBarListener> mMenuBarListener; // The listener that tells us
// about key and mouse events.
bool mIsActive = false; // Whether or not the menu bar is active (a menu item
// is highlighted or shown).
// Whether the menubar was made active via the keyboard.
bool mActiveByKeyboard = false;
}; // class nsMenuBarFrame
#endif

View file

@ -1,100 +0,0 @@
/* -*- 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/. */
#ifndef nsMenuBarListener_h
#define nsMenuBarListener_h
#include "mozilla/Attributes.h"
#include "mozilla/EventForwards.h"
#include "nsIContent.h"
#include "nsIDOMEventListener.h"
// X.h defines KeyPress
#ifdef KeyPress
# undef KeyPress
#endif
class nsMenuFrame;
class nsMenuBarFrame;
namespace mozilla {
namespace dom {
class EventTarget;
class KeyboardEvent;
class XULMenuParentElement;
class XULButtonElement;
} // namespace dom
} // namespace mozilla
/**
* EventListener implementation for menubar.
*/
class nsMenuBarListener final : public nsIDOMEventListener {
public:
explicit nsMenuBarListener(nsMenuBarFrame* aMenuBarFrame,
nsIContent* aMenuBarContent);
NS_DECL_ISUPPORTS
/**
* nsIDOMEventListener interface method.
*/
NS_DECL_NSIDOMEVENTLISTENER
/**
* When mMenuBarFrame is being destroyed, this should be called.
*/
void OnDestroyMenuBarFrame();
protected:
virtual ~nsMenuBarListener();
bool IsMenuOpen() const;
MOZ_CAN_RUN_SCRIPT nsresult KeyUp(mozilla::dom::Event* aMouseEvent);
MOZ_CAN_RUN_SCRIPT nsresult KeyDown(mozilla::dom::Event* aMouseEvent);
MOZ_CAN_RUN_SCRIPT nsresult KeyPress(mozilla::dom::Event* aMouseEvent);
MOZ_CAN_RUN_SCRIPT nsresult Blur(mozilla::dom::Event* aEvent);
MOZ_CAN_RUN_SCRIPT nsresult OnWindowDeactivated(mozilla::dom::Event* aEvent);
MOZ_CAN_RUN_SCRIPT nsresult MouseDown(mozilla::dom::Event* aMouseEvent);
MOZ_CAN_RUN_SCRIPT nsresult Fullscreen(mozilla::dom::Event* aEvent);
/**
* Given a key event for an Alt+shortcut combination,
* return the menu, if any, that would be opened. If aPeek
* is false, then play a beep and deactivate the menubar on Windows.
*/
mozilla::dom::XULButtonElement* GetMenuForKeyEvent(
mozilla::dom::KeyboardEvent& aKeyEvent);
/**
* Call MarkAsReservedByChrome if the user's preferences indicate that
* the key should be chrome-only.
*/
void ReserveKeyIfNeeded(mozilla::dom::Event* aKeyEvent);
// This should only be called by the nsMenuBarListener during event dispatch,
// thus ensuring that this doesn't get destroyed during the process.
MOZ_CAN_RUN_SCRIPT void ToggleMenuActiveState();
bool Destroyed() const { return !mMenuBarFrame; }
// The menu bar object.
nsMenuBarFrame* mMenuBarFrame;
mozilla::dom::XULMenuParentElement* mContent;
// The event target to listen to the events.
// XXX Should this store this as strong reference? However,
// OnDestroyMenuBarFrame() should be called at destroying mMenuBarFrame.
// So, weak reference must be safe.
mozilla::dom::EventTarget* mEventTarget;
// The top window as EventTarget.
mozilla::dom::EventTarget* mTopWindowEventTarget;
// Whether or not the ALT key is currently down.
bool mAccessKeyDown;
// Whether or not the ALT key down is canceled by other action.
bool mAccessKeyDownCanceled;
};
#endif // #ifndef nsMenuBarListener_h

View file

@ -19,7 +19,6 @@
#include "nsIFrameInlines.h"
#include "nsViewManager.h"
#include "nsWidgetsCID.h"
#include "nsMenuBarFrame.h"
#include "nsPIDOMWindow.h"
#include "nsFrameManager.h"
#include "mozilla/dom/Document.h"
@ -2028,10 +2027,8 @@ nsIFrame* nsMenuPopupFrame::GetCurrentMenuItemFrame() const {
void nsMenuPopupFrame::HandleEnterKeyPress(WidgetEvent& aEvent) {
mIncrementalString.Truncate();
if (RefPtr menu = GetCurrentMenuItem()) {
// Give it to the child.
menu->HandleEnterKeyPress(aEvent);
}
RefPtr popup = &PopupElement();
popup->HandleEnterKeyPress(aEvent);
}
XULButtonElement* nsMenuPopupFrame::FindMenuWithShortcut(

View file

@ -26,7 +26,6 @@
#include "nsIContent.h"
#include "nsNameSpaceManager.h"
#include "nsBoxLayoutState.h"
#include "nsMenuBarListener.h"
#include "nsString.h"
#include "nsITheme.h"
#include "nsUnicharUtils.h"

View file

@ -5,7 +5,6 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "XULButtonElement.h"
#include "XULMenuParentElement.h"
#include "mozilla/Assertions.h"
#include "mozilla/Attributes.h"
#include "mozilla/FlushType.h"
@ -14,8 +13,6 @@
#include "nsISound.h"
#include "nsXULPopupManager.h"
#include "nsMenuPopupFrame.h"
#include "nsMenuBarFrame.h"
#include "nsMenuBarListener.h"
#include "nsContentUtils.h"
#include "nsXULElement.h"
#include "nsIDOMXULCommandDispatcher.h"
@ -50,6 +47,7 @@
#include "mozilla/dom/PopupPositionedEventBinding.h"
#include "mozilla/dom/XULCommandEvent.h"
#include "mozilla/dom/XULMenuElement.h"
#include "mozilla/dom/XULMenuBarElement.h"
#include "mozilla/dom/XULPopupElement.h"
#include "mozilla/EventDispatcher.h"
#include "mozilla/EventStateManager.h"
@ -77,6 +75,17 @@ static_assert(KeyboardEvent_Binding::DOM_VK_HOME ==
KeyboardEvent_Binding::DOM_VK_END + 5,
"nsXULPopupManager assumes some keyCode values are consecutive");
#define NS_DIRECTION_IS_INLINE(dir) \
(dir == eNavigationDirection_Start || dir == eNavigationDirection_End)
#define NS_DIRECTION_IS_BLOCK(dir) \
(dir == eNavigationDirection_Before || dir == eNavigationDirection_After)
#define NS_DIRECTION_IS_BLOCK_TO_EDGE(dir) \
(dir == eNavigationDirection_First || dir == eNavigationDirection_Last)
static_assert(static_cast<uint8_t>(mozilla::StyleDirection::Ltr) == 0 &&
static_cast<uint8_t>(mozilla::StyleDirection::Rtl) == 1,
"Left to Right should be 0 and Right to Left should be 1");
const nsNavigationDirection DirectionFromKeyCodeTable[2][6] = {
{
eNavigationDirection_Last, // KeyboardEvent_Binding::DOM_VK_END
@ -707,7 +716,7 @@ nsMenuChainItem* nsXULPopupManager::GetRollupItem(RollupKind aKind) {
return nullptr;
}
void nsXULPopupManager::SetActiveMenuBar(nsMenuBarFrame* aMenuBar,
void nsXULPopupManager::SetActiveMenuBar(XULMenuBarElement* aMenuBar,
bool aActivate) {
if (aActivate) {
mActiveMenuBar = aMenuBar;
@ -2010,7 +2019,7 @@ void nsXULPopupManager::UpdateKeyboardListeners() {
}
isForMenu = item->GetPopupType() == PopupType::Menu;
} else if (mActiveMenuBar) {
newTarget = mActiveMenuBar->GetContent()->GetComposedDoc();
newTarget = mActiveMenuBar->GetComposedDoc();
isForMenu = true;
}
@ -2209,7 +2218,7 @@ bool nsXULPopupManager::HandleShortcutNavigation(KeyboardEvent& aKeyEvent,
}
if (mActiveMenuBar) {
RefPtr menubar = &mActiveMenuBar->MenubarElement();
RefPtr menubar = mActiveMenuBar;
if (RefPtr result = menubar->FindMenuWithShortcut(aKeyEvent)) {
result->OpenMenuPopup(true);
return true;
@ -2222,7 +2231,7 @@ bool nsXULPopupManager::HandleShortcutNavigation(KeyboardEvent& aKeyEvent,
if (nsCOMPtr<nsISound> sound = do_GetService("@mozilla.org/sound;1")) {
sound->Beep();
}
mActiveMenuBar->SetActive(false);
menubar->SetActive(false);
#endif
}
return false;
@ -2264,7 +2273,10 @@ bool nsXULPopupManager::HandleKeyboardNavigation(uint32_t aKeyCode) {
if (item) {
itemFrame = item->Frame();
} else if (mActiveMenuBar) {
itemFrame = mActiveMenuBar;
itemFrame = mActiveMenuBar->GetPrimaryFrame();
if (!itemFrame) {
return false;
}
} else {
return false;
}
@ -2301,7 +2313,7 @@ bool nsXULPopupManager::HandleKeyboardNavigation(uint32_t aKeyCode) {
if (!mActiveMenuBar) {
return false;
}
RefPtr menubar = XULMenuParentElement::FromNode(mActiveMenuBar->GetContent());
RefPtr menubar = mActiveMenuBar;
if (NS_DIRECTION_IS_INLINE(theDirection)) {
RefPtr prevActiveItem = menubar->GetActiveMenuChild();
const bool open = prevActiveItem && prevActiveItem->IsMenuPopupOpen();
@ -2460,7 +2472,8 @@ bool nsXULPopupManager::HandleKeyboardEventWithKeyCode(
if (aTopVisibleMenuItem) {
HidePopup(aTopVisibleMenuItem->Content(), {HidePopupOption::IsRollup});
} else if (mActiveMenuBar) {
mActiveMenuBar->MenuClosed();
RefPtr menubar = mActiveMenuBar;
menubar->MenuClosed();
}
break;
@ -2476,7 +2489,8 @@ bool nsXULPopupManager::HandleKeyboardEventWithKeyCode(
Rollup({});
break;
} else if (mActiveMenuBar) {
mActiveMenuBar->MenuClosed();
RefPtr menubar = mActiveMenuBar;
menubar->MenuClosed();
break;
}
// Intentional fall-through to RETURN case
@ -2490,7 +2504,8 @@ bool nsXULPopupManager::HandleKeyboardEventWithKeyCode(
if (aTopVisibleMenuItem) {
aTopVisibleMenuItem->Frame()->HandleEnterKeyPress(*event);
} else if (mActiveMenuBar) {
mActiveMenuBar->HandleEnterKeyPress(*event);
RefPtr menubar = mActiveMenuBar;
menubar->HandleEnterKeyPress(*event);
}
break;
}
@ -2541,8 +2556,7 @@ nsresult nsXULPopupManager::UpdateIgnoreKeys(bool aIgnoreKeys) {
return NS_OK;
}
nsPopupState nsXULPopupManager::GetPopupState(
mozilla::dom::Element* aPopupElement) {
nsPopupState nsXULPopupManager::GetPopupState(Element* aPopupElement) {
if (mNativeMenu && mNativeMenu->Element()->Contains(aPopupElement)) {
if (aPopupElement != mNativeMenu->Element()) {
// Submenu state is stored in mNativeMenuSubmenuStates.
@ -2621,7 +2635,8 @@ nsresult nsXULPopupManager::KeyDown(KeyboardEvent* aKeyEvent) {
if (item && !item->Frame()->IsMenuList()) {
Rollup({});
} else if (mActiveMenuBar) {
mActiveMenuBar->MenuClosed();
RefPtr menubar = mActiveMenuBar;
menubar->MenuClosed();
}
// Clear the item to avoid bugs as it may have been deleted during

View file

@ -12,23 +12,19 @@
#define nsXULPopupManager_h__
#include "mozilla/Logging.h"
#include "mozilla/widget/InitData.h"
#include "nsHashtablesFwd.h"
#include "nsIContent.h"
#include "nsIRollupListener.h"
#include "nsIDOMEventListener.h"
#include "Units.h"
#include "nsPoint.h"
#include "nsCOMPtr.h"
#include "nsTArray.h"
#include "nsIObserver.h"
#include "nsITimer.h"
#include "nsIReflowCallback.h"
#include "nsThreadUtils.h"
#include "nsPresContext.h"
#include "nsStyleConsts.h"
#include "mozilla/Attributes.h"
#include "mozilla/widget/InitData.h"
#include "mozilla/widget/NativeMenu.h"
#include "Units.h"
// XXX Avoid including this here by moving function bodies to the cpp file.
#include "mozilla/dom/Element.h"
@ -54,9 +50,9 @@
*/
class nsContainerFrame;
class nsMenuPopupFrame;
class nsMenuBarFrame;
class nsITimer;
class nsIDocShellTreeItem;
class nsMenuPopupFrame;
class nsPIDOMWindowOuter;
class nsRefreshDriver;
@ -67,6 +63,7 @@ class Event;
class KeyboardEvent;
class UIEvent;
class XULButtonElement;
class XULMenuBarElement;
} // namespace dom
} // namespace mozilla
@ -178,17 +175,6 @@ enum class HidePopupOption : uint8_t {
using HidePopupOptions = mozilla::EnumSet<HidePopupOption>;
#define NS_DIRECTION_IS_INLINE(dir) \
(dir == eNavigationDirection_Start || dir == eNavigationDirection_End)
#define NS_DIRECTION_IS_BLOCK(dir) \
(dir == eNavigationDirection_Before || dir == eNavigationDirection_After)
#define NS_DIRECTION_IS_BLOCK_TO_EDGE(dir) \
(dir == eNavigationDirection_First || dir == eNavigationDirection_Last)
static_assert(static_cast<uint8_t>(mozilla::StyleDirection::Ltr) == 0 &&
static_cast<uint8_t>(mozilla::StyleDirection::Rtl) == 1,
"Left to Right should be 0 and Right to Left should be 1");
/**
* DirectionFromKeyCodeTable: two arrays, the first for left-to-right and the
* other for right-to-left, that map keycodes to values of
@ -437,7 +423,8 @@ class nsXULPopupManager final : public nsIDOMEventListener,
// when the active menu bar should be defocused. In the latter case, if
// aMenuBar isn't currently active, yet another menu bar is, that menu bar
// will remain active.
void SetActiveMenuBar(nsMenuBarFrame* aMenuBar, bool aActivate);
void SetActiveMenuBar(mozilla::dom::XULMenuBarElement* aMenuBar,
bool aActivate);
struct MayShowMenuResult {
const bool mIsNative = false;
@ -865,7 +852,7 @@ class nsXULPopupManager final : public nsIDOMEventListener,
nsCOMPtr<nsIWidget> mWidget;
// set to the currently active menu bar, if any
nsMenuBarFrame* mActiveMenuBar;
mozilla::dom::XULMenuBarElement* mActiveMenuBar;
// linked list of normal menus and panels. mPopups points to the innermost
// popup, which keeps alive all their parents.