mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-23 04:41:11 +00:00
954599ea69
This patch aligns the code paths for programmatic menu item activation and user-initiated menu item activation. Before this patch, user-initiated menu item activation caused the command event to fire synchronously from menuItemHit. After this patch, the command event fires from MenuClosedAsync, which, if an item was activated, is called asynchronously once the menu's nested event loop has been exited. (If no item has been activated, MenuClosedAsync is called *inside* the menu's event loop so that popuphiding / popuphidden events for submenus don't get delayed.) This patch makes three major changes to align the two code paths: - menuItemHit now calls ActivateItemAfterClosing. This fixes bug 1748815. - NativeMenuMac::ActivateItem (used in automated tests) calls the relevant methods in the same order as user-initiated item activation. This means that what we're testing is now closer to what we're shipping. This patch also removes the call to runAfterMenuClosed. The runnable that calls MenuClosedAsync is already guaranteed to run outside the menu's event loop when a menu item was activated (I'm 99% sure about this): For user-initiated activations, the macOS code exits the loop immediately after calling menuItemHit and doesn't give our CFRunLoopSource another chance to run until the stack is unwound. For test-initiated activations, we set MOZMenuOpeningCoordinator.needToUnwindForMenuClosing which tells our native event loop to not run anything until the stack is unwound. Differential Revision: https://phabricator.services.mozilla.com/D149316
106 lines
3.2 KiB
Objective-C
106 lines
3.2 KiB
Objective-C
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
/* 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 nsMenuItemX_h_
|
|
#define nsMenuItemX_h_
|
|
|
|
#include "mozilla/RefPtr.h"
|
|
#include "nsISupports.h"
|
|
#include "nsMenuGroupOwnerX.h"
|
|
#include "nsMenuItemIconX.h"
|
|
#include "nsChangeObserver.h"
|
|
#include "nsStringFwd.h"
|
|
|
|
#import <Cocoa/Cocoa.h>
|
|
|
|
class nsMenuItemIconX;
|
|
class nsMenuX;
|
|
class nsMenuParentX;
|
|
|
|
namespace mozilla {
|
|
namespace dom {
|
|
class Element;
|
|
}
|
|
} // namespace mozilla
|
|
|
|
enum {
|
|
knsMenuItemNoModifier = 0,
|
|
knsMenuItemShiftModifier = (1 << 0),
|
|
knsMenuItemAltModifier = (1 << 1),
|
|
knsMenuItemControlModifier = (1 << 2),
|
|
knsMenuItemCommandModifier = (1 << 3)
|
|
};
|
|
|
|
enum EMenuItemType {
|
|
eRegularMenuItemType = 0,
|
|
eCheckboxMenuItemType,
|
|
eRadioMenuItemType,
|
|
eSeparatorMenuItemType
|
|
};
|
|
|
|
// Once instantiated, this object lives until its DOM node or its parent window
|
|
// is destroyed. Do not hold references to this, they can become invalid any
|
|
// time the DOM node can be destroyed.
|
|
class nsMenuItemX final : public nsChangeObserver,
|
|
public nsMenuItemIconX::Listener {
|
|
public:
|
|
nsMenuItemX(nsMenuX* aParent, const nsString& aLabel, EMenuItemType aItemType,
|
|
nsMenuGroupOwnerX* aMenuGroupOwner, nsIContent* aNode);
|
|
|
|
bool IsVisible() const { return mIsVisible; }
|
|
|
|
// Unregisters nsMenuX from the nsMenuGroupOwner, and nulls out the group
|
|
// owner pointer. This is needed because nsMenuX is reference-counted and can
|
|
// outlive its owner, and the menu group owner asserts that everything has
|
|
// been unregistered when it is destroyed.
|
|
void DetachFromGroupOwner();
|
|
|
|
// Nulls out our reference to the parent.
|
|
// This is needed because nsMenuX is reference-counted and can outlive its
|
|
// parent.
|
|
void DetachFromParent() { mMenuParent = nullptr; }
|
|
|
|
NS_INLINE_DECL_REFCOUNTING(nsMenuItemX)
|
|
|
|
NS_DECL_CHANGEOBSERVER
|
|
|
|
// nsMenuItemIconX::Listener
|
|
void IconUpdated() override;
|
|
|
|
// nsMenuItemX
|
|
nsresult SetChecked(bool aIsChecked);
|
|
EMenuItemType GetMenuItemType();
|
|
void DoCommand(NSEventModifierFlags aModifierFlags, int16_t aButton);
|
|
nsresult DispatchDOMEvent(const nsString& eventName,
|
|
bool* preventDefaultCalled);
|
|
void SetupIcon();
|
|
nsMenuX* ParentMenu() { return mMenuParent; }
|
|
nsIContent* Content() { return mContent; }
|
|
NSMenuItem* NativeNSMenuItem() { return mNativeMenuItem; }
|
|
|
|
void Dump(uint32_t aIndent) const;
|
|
|
|
protected:
|
|
virtual ~nsMenuItemX();
|
|
|
|
void UncheckRadioSiblings(nsIContent* aCheckedElement);
|
|
void SetKeyEquiv();
|
|
|
|
nsCOMPtr<nsIContent> mContent; // XUL <menuitem> or <menuseparator>
|
|
|
|
EMenuItemType mType;
|
|
|
|
// nsMenuItemX objects should always have a valid native menu item.
|
|
NSMenuItem* mNativeMenuItem = nil; // [strong]
|
|
nsMenuX* mMenuParent = nullptr; // [weak]
|
|
nsMenuGroupOwnerX* mMenuGroupOwner = nullptr; // [weak]
|
|
RefPtr<mozilla::dom::Element> mCommandElement;
|
|
mozilla::UniquePtr<nsMenuItemIconX> mIcon; // always non-null
|
|
bool mIsChecked = false;
|
|
bool mIsVisible = false;
|
|
};
|
|
|
|
#endif // nsMenuItemX_h_
|