summaryrefslogtreecommitdiffstats
path: root/layout/xul/nsMenuPopupFrame.h
diff options
context:
space:
mode:
Diffstat (limited to 'layout/xul/nsMenuPopupFrame.h')
-rw-r--r--layout/xul/nsMenuPopupFrame.h643
1 files changed, 643 insertions, 0 deletions
diff --git a/layout/xul/nsMenuPopupFrame.h b/layout/xul/nsMenuPopupFrame.h
new file mode 100644
index 0000000000..e9f0b2a521
--- /dev/null
+++ b/layout/xul/nsMenuPopupFrame.h
@@ -0,0 +1,643 @@
+/* -*- 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/. */
+
+//
+// nsMenuPopupFrame
+//
+
+#ifndef nsMenuPopupFrame_h__
+#define nsMenuPopupFrame_h__
+
+#include "mozilla/Attributes.h"
+#include "mozilla/gfx/Types.h"
+#include "mozilla/StaticPrefs_ui.h"
+#include "mozilla/TimeStamp.h"
+#include "nsAtom.h"
+#include "nsGkAtoms.h"
+#include "nsCOMPtr.h"
+#include "nsIDOMEventListener.h"
+#include "nsXULPopupManager.h"
+
+#include "nsBlockFrame.h"
+
+#include "Units.h"
+
+class nsIWidget;
+
+namespace mozilla {
+class PresShell;
+namespace dom {
+class KeyboardEvent;
+class XULButtonElement;
+class XULPopupElement;
+} // namespace dom
+namespace widget {
+enum class PopupLevel : uint8_t;
+}
+} // namespace mozilla
+
+enum ConsumeOutsideClicksResult {
+ ConsumeOutsideClicks_ParentOnly =
+ 0, // Only consume clicks on the parent anchor
+ ConsumeOutsideClicks_True = 1, // Always consume clicks
+ ConsumeOutsideClicks_Never = 2 // Never consume clicks
+};
+
+// How a popup may be flipped. Flipping to the outside edge is like how
+// a submenu would work. The entire popup is flipped to the opposite side
+// of the anchor.
+enum FlipStyle {
+ FlipStyle_None = 0,
+ FlipStyle_Outside = 1,
+ FlipStyle_Inside = 2
+};
+
+// Values for the flip attribute
+enum FlipType {
+ FlipType_Default = 0,
+ FlipType_None = 1, // don't try to flip or translate to stay onscreen
+ FlipType_Both = 2, // flip in both directions
+ FlipType_Slide = 3 // allow the arrow to "slide" instead of resizing
+};
+
+enum MenuPopupAnchorType {
+ MenuPopupAnchorType_Node = 0, // anchored to a node
+ MenuPopupAnchorType_Point = 1, // unanchored and positioned at a screen point
+ MenuPopupAnchorType_Rect = 2, // anchored at a screen rectangle
+};
+
+// values are selected so that the direction can be flipped just by
+// changing the sign
+#define POPUPALIGNMENT_NONE 0
+#define POPUPALIGNMENT_TOPLEFT 1
+#define POPUPALIGNMENT_TOPRIGHT -1
+#define POPUPALIGNMENT_BOTTOMLEFT 2
+#define POPUPALIGNMENT_BOTTOMRIGHT -2
+
+#define POPUPALIGNMENT_LEFTCENTER 16
+#define POPUPALIGNMENT_RIGHTCENTER -16
+#define POPUPALIGNMENT_TOPCENTER 17
+#define POPUPALIGNMENT_BOTTOMCENTER 18
+
+// The constants here are selected so that horizontally and vertically flipping
+// can be easily handled using the two flip macros below.
+#define POPUPPOSITION_UNKNOWN -1
+#define POPUPPOSITION_BEFORESTART 0
+#define POPUPPOSITION_BEFOREEND 1
+#define POPUPPOSITION_AFTERSTART 2
+#define POPUPPOSITION_AFTEREND 3
+#define POPUPPOSITION_STARTBEFORE 4
+#define POPUPPOSITION_ENDBEFORE 5
+#define POPUPPOSITION_STARTAFTER 6
+#define POPUPPOSITION_ENDAFTER 7
+#define POPUPPOSITION_OVERLAP 8
+#define POPUPPOSITION_AFTERPOINTER 9
+#define POPUPPOSITION_SELECTION 10
+
+#define POPUPPOSITION_HFLIP(v) (v ^ 1)
+#define POPUPPOSITION_VFLIP(v) (v ^ 2)
+
+nsIFrame* NS_NewMenuPopupFrame(mozilla::PresShell* aPresShell,
+ mozilla::ComputedStyle* aStyle);
+
+class nsView;
+class nsMenuPopupFrame;
+
+// this class is used for dispatching popupshown events asynchronously.
+class nsXULPopupShownEvent final : public mozilla::Runnable,
+ public nsIDOMEventListener {
+ public:
+ nsXULPopupShownEvent(nsIContent* aPopup, nsPresContext* aPresContext)
+ : mozilla::Runnable("nsXULPopupShownEvent"),
+ mPopup(aPopup),
+ mPresContext(aPresContext) {}
+
+ NS_DECL_ISUPPORTS_INHERITED
+ NS_DECL_NSIRUNNABLE
+ NS_DECL_NSIDOMEVENTLISTENER
+
+ void CancelListener();
+
+ protected:
+ virtual ~nsXULPopupShownEvent() = default;
+
+ private:
+ const nsCOMPtr<nsIContent> mPopup;
+ const RefPtr<nsPresContext> mPresContext;
+};
+
+class nsMenuPopupFrame final : public nsBlockFrame {
+ using PopupLevel = mozilla::widget::PopupLevel;
+ using PopupType = mozilla::widget::PopupType;
+
+ public:
+ NS_DECL_QUERYFRAME
+ NS_DECL_FRAMEARENA_HELPERS(nsMenuPopupFrame)
+
+ explicit nsMenuPopupFrame(ComputedStyle* aStyle, nsPresContext* aPresContext);
+ ~nsMenuPopupFrame();
+
+ // as popups are opened asynchronously, the popup pending state is used to
+ // prevent multiple requests from attempting to open the same popup twice
+ nsPopupState PopupState() const { return mPopupState; }
+ void SetPopupState(nsPopupState);
+
+ /*
+ * When this popup is open, should clicks outside of it be consumed?
+ * Return true if the popup should rollup on an outside click,
+ * but consume that click so it can't be used for anything else.
+ * Return false to allow clicks outside the popup to activate content
+ * even when the popup is open.
+ * ---------------------------------------------------------------------
+ *
+ * Should clicks outside of a popup be eaten?
+ *
+ * Menus Autocomplete Comboboxes
+ * Mac Eat No Eat
+ * Win No No Eat
+ * Unix Eat No Eat
+ *
+ */
+ ConsumeOutsideClicksResult ConsumeOutsideClicks();
+
+ mozilla::dom::XULPopupElement& PopupElement() const;
+
+ nscoord GetPrefISize(gfxContext*) final;
+ nscoord GetMinISize(gfxContext*) final;
+ void Reflow(nsPresContext* aPresContext, ReflowOutput& aDesiredSize,
+ const ReflowInput& aReflowInput,
+ nsReflowStatus& aStatus) override;
+
+ nsIWidget* GetWidget() const;
+
+ enum class WidgetStyle : uint8_t {
+ ColorScheme,
+ InputRegion,
+ Opacity,
+ Shadow,
+ Transform,
+ };
+ using WidgetStyleFlags = mozilla::EnumSet<WidgetStyle>;
+ static constexpr WidgetStyleFlags AllWidgetStyleFlags() {
+ return {WidgetStyle::ColorScheme, WidgetStyle::InputRegion,
+ WidgetStyle::Opacity, WidgetStyle::Shadow, WidgetStyle::Transform};
+ }
+ void PropagateStyleToWidget(WidgetStyleFlags = AllWidgetStyleFlags()) const;
+
+ // Overridden methods
+ void Init(nsIContent* aContent, nsContainerFrame* aParent,
+ nsIFrame* aPrevInFlow) override;
+
+ nsresult AttributeChanged(int32_t aNameSpaceID, nsAtom* aAttribute,
+ int32_t aModType) override;
+
+ // FIXME: This shouldn't run script (this can end up calling HidePopup).
+ MOZ_CAN_RUN_SCRIPT_BOUNDARY void Destroy(DestroyContext&) override;
+
+ bool HasRemoteContent() const;
+
+ // Whether we should create a widget on Init().
+ bool ShouldCreateWidgetUpfront() const;
+
+ // Whether we should expand the menu to take the size of the parent menulist.
+ bool ShouldExpandToInflowParentOrAnchor() const;
+
+ // Returns true if the popup is a panel with the noautohide attribute set to
+ // true. These panels do not roll up automatically.
+ bool IsNoAutoHide() const;
+
+ PopupLevel GetPopupLevel() const { return GetPopupLevel(IsNoAutoHide()); }
+
+ // Ensure that a widget has already been created for this view, and create
+ // one if it hasn't. If aRecreate is true, destroys any existing widget and
+ // creates a new one, regardless of whether one has already been created.
+ void PrepareWidget(bool aRecreate = false);
+
+ MOZ_CAN_RUN_SCRIPT void EnsureActiveMenuListItemIsVisible();
+
+ nsresult CreateWidgetForView(nsView* aView);
+ mozilla::StyleWindowShadow GetShadowStyle() const;
+
+ void DidSetComputedStyle(ComputedStyle* aOldStyle) override;
+
+ // layout, position and display the popup as needed
+ MOZ_CAN_RUN_SCRIPT_BOUNDARY
+ void LayoutPopup(nsPresContext*, ReflowOutput&, const ReflowInput&,
+ nsReflowStatus&);
+
+ // Set the position of the popup relative to the anchor content, anchored at a
+ // rectangle, or at a specific point if a screen position is set. The popup
+ // will be adjusted so that it is on screen. If aIsMove is true, then the
+ // popup is being moved, and should not be flipped.
+ void SetPopupPosition(bool aIsMove);
+
+ // Called when the Enter key is pressed while the popup is open. This will
+ // just pass the call down to the current menu, if any.
+ // Also, calling Enter will reset the current incremental search string,
+ // calculated in FindMenuWithShortcut.
+ MOZ_CAN_RUN_SCRIPT void HandleEnterKeyPress(mozilla::WidgetEvent&);
+
+ // Locate and return the menu frame that should be activated for the supplied
+ // key event. If aDoAction is set to true by this method, then the menu's
+ // action should be carried out, as if the user had pressed the Enter key. If
+ // aDoAction is false, the menu should just be highlighted.
+ // This method also handles incremental searching in menus so the user can
+ // type the first few letters of an item/s name to select it.
+ mozilla::dom::XULButtonElement* FindMenuWithShortcut(
+ mozilla::dom::KeyboardEvent& aKeyEvent, bool& aDoAction);
+
+ mozilla::dom::XULButtonElement* GetCurrentMenuItem() const;
+ nsIFrame* GetCurrentMenuItemFrame() const;
+
+ PopupType GetPopupType() const { return mPopupType; }
+ bool IsContextMenu() const { return mIsContextMenu; }
+
+ bool IsOpen() const {
+ return mPopupState == ePopupOpening || mPopupState == ePopupVisible ||
+ mPopupState == ePopupShown;
+ }
+ bool IsVisible() {
+ return mPopupState == ePopupVisible || mPopupState == ePopupShown;
+ }
+ bool IsVisibleOrShowing() {
+ return IsOpen() || mPopupState == ePopupPositioning ||
+ mPopupState == ePopupShowing;
+ }
+ bool IsNativeMenu() const { return mIsNativeMenu; }
+ bool IsMouseTransparent() const;
+
+ // Return true if the popup is for a menulist.
+ bool IsMenuList() const;
+
+ bool IsDragSource() const { return mIsDragSource; }
+ void SetIsDragSource(bool aIsDragSource) { mIsDragSource = aIsDragSource; }
+
+ static nsIContent* GetTriggerContent(nsMenuPopupFrame* aMenuPopupFrame);
+ void ClearTriggerContent() { mTriggerContent = nullptr; }
+ void ClearTriggerContentIncludingDocument();
+
+ // returns true if the popup is in a content shell, or false for a popup in
+ // a chrome shell
+ bool IsInContentShell() const { return mInContentShell; }
+
+ // the Initialize methods are used to set the anchor position for
+ // each way of opening a popup.
+ void InitializePopup(nsIContent* aAnchorContent, nsIContent* aTriggerContent,
+ const nsAString& aPosition, int32_t aXPos, int32_t aYPos,
+ MenuPopupAnchorType aAnchorType,
+ bool aAttributesOverride);
+
+ void InitializePopupAtRect(nsIContent* aTriggerContent,
+ const nsAString& aPosition, const nsIntRect& aRect,
+ bool aAttributesOverride);
+
+ /**
+ * @param aIsContextMenu if true, then the popup is
+ * positioned at a slight offset from aXPos/aYPos to ensure the
+ * (presumed) mouse position is not over the menu.
+ */
+ void InitializePopupAtScreen(nsIContent* aTriggerContent, int32_t aXPos,
+ int32_t aYPos, bool aIsContextMenu);
+
+ // Called if this popup should be displayed as an OS-native context menu.
+ void InitializePopupAsNativeContextMenu(nsIContent* aTriggerContent,
+ int32_t aXPos, int32_t aYPos);
+
+ // indicate that the popup should be opened
+ void ShowPopup(bool aIsContextMenu);
+ // indicate that the popup should be hidden. The new state should either be
+ // ePopupClosed or ePopupInvisible.
+ MOZ_CAN_RUN_SCRIPT void HidePopup(bool aDeselectMenu, nsPopupState aNewState,
+ bool aFromFrameDestruction = false);
+
+ void ClearIncrementalString() { mIncrementalString.Truncate(); }
+ static bool IsWithinIncrementalTime(mozilla::TimeStamp time) {
+ return !sLastKeyTime.IsNull() &&
+ ((time - sLastKeyTime).ToMilliseconds() <=
+ mozilla::StaticPrefs::ui_menu_incremental_search_timeout());
+ }
+
+#ifdef DEBUG_FRAME_DUMP
+ virtual nsresult GetFrameName(nsAString& aResult) const override {
+ return MakeFrameName(u"MenuPopup"_ns, aResult);
+ }
+#endif
+
+ MOZ_CAN_RUN_SCRIPT void ChangeByPage(bool aIsUp);
+
+ // Move the popup to the screen coordinate |aPos| in CSS pixels.
+ // If aUpdateAttrs is true, and the popup already has left or top attributes,
+ // then those attributes are updated to the new location.
+ // The frame may be destroyed by this method.
+ void MoveTo(const mozilla::CSSPoint& aPos, bool aUpdateAttrs,
+ bool aByMoveToRect = false);
+
+ void MoveToAnchor(nsIContent* aAnchorContent, const nsAString& aPosition,
+ int32_t aXPos, int32_t aYPos, bool aAttributesOverride);
+
+ nsIScrollableFrame* GetScrollFrame() const;
+
+ void SetOverrideConstraintRect(const mozilla::CSSIntRect& aRect) {
+ mOverrideConstraintRect = mozilla::CSSIntRect::ToAppUnits(aRect);
+ }
+
+ struct Rects {
+ // For anchored popups, the anchor rectangle. For non-anchored popups, the
+ // size will be 0.
+ nsRect mAnchorRect;
+ // mAnchorRect before accounting for flipping / resizing / intersecting with
+ // the screen. This is needed for Wayland, which flips / resizes at the
+ // widget level.
+ nsRect mUntransformedAnchorRect;
+ // The final used rect we want to occupy.
+ nsRect mUsedRect;
+ // The alignment offset for sliding the panel, see
+ // nsMenuPopupFrame::mAlignmentOffset.
+ nscoord mAlignmentOffset = 0;
+ bool mHFlip = false;
+ bool mVFlip = false;
+ // The client offset of our widget.
+ mozilla::LayoutDeviceIntPoint mClientOffset;
+ nsPoint mViewPoint;
+ };
+
+ // For a popup that should appear anchored at the given rect, gets the anchor
+ // and constraint rects for that popup.
+ // This will be the available area of the screen the popup should be displayed
+ // on. Content popups, however, will also be constrained by the content area.
+ //
+ // For non-toplevel popups (which will always be panels), we will also
+ // constrain them to the available screen rect, ie they will not fall
+ // underneath the taskbar, dock or other fixed OS elements.
+ Rects GetRects(const nsSize& aPrefSize) const;
+ Maybe<nsRect> GetConstraintRect(const nsRect& aAnchorRect,
+ const nsRect& aRootScreenRect,
+ PopupLevel) const;
+ void PerformMove(const Rects&);
+
+ // Return true if the popup is positioned relative to an anchor.
+ bool IsAnchored() const { return mAnchorType != MenuPopupAnchorType_Point; }
+
+ // Return the anchor if there is one.
+ nsIContent* GetAnchor() const { return mAnchorContent; }
+
+ // Return the screen coordinates in CSS pixels of the popup,
+ // or (-1, -1, 0, 0) if anchored.
+ mozilla::CSSIntRect GetScreenAnchorRect() const {
+ return mozilla::CSSRect::FromAppUnitsRounded(mScreenRect);
+ }
+
+ mozilla::LayoutDeviceIntPoint GetLastClientOffset() const {
+ return mLastClientOffset;
+ }
+
+ // Return the alignment of the popup
+ int8_t GetAlignmentPosition() const;
+
+ // Return the offset applied to the alignment of the popup
+ nscoord GetAlignmentOffset() const { return mAlignmentOffset; }
+
+ // Clear the mPopupShownDispatcher, remove the listener and return true if
+ // mPopupShownDispatcher was non-null.
+ bool ClearPopupShownDispatcher() {
+ if (mPopupShownDispatcher) {
+ mPopupShownDispatcher->CancelListener();
+ mPopupShownDispatcher = nullptr;
+ return true;
+ }
+
+ return false;
+ }
+
+ void ShowWithPositionedEvent() { mPopupState = ePopupPositioning; }
+
+ // Checks for the anchor to change and either moves or hides the popup
+ // accordingly. The original position of the anchor should be supplied as
+ // the argument. If the popup needs to be hidden, HidePopup will be called by
+ // CheckForAnchorChange. If the popup needs to be moved, aRect will be updated
+ // with the new rectangle.
+ void CheckForAnchorChange(nsRect& aRect);
+
+ void WillDispatchPopupPositioned() { mPendingPositionedEvent = false; }
+
+ protected:
+ // returns the popup's level.
+ PopupLevel GetPopupLevel(bool aIsNoAutoHide) const;
+ void TweakMinPrefISize(nscoord&);
+
+ void InitPositionFromAnchorAlign(const nsAString& aAnchor,
+ const nsAString& aAlign);
+
+ // return the position where the popup should be, when it should be
+ // anchored at anchorRect. aHFlip and aVFlip will be set if the popup may be
+ // flipped in that direction if there is not enough space available.
+ nsPoint AdjustPositionForAnchorAlign(nsRect& aAnchorRect,
+ const nsSize& aPrefSize,
+ FlipStyle& aHFlip,
+ FlipStyle& aVFlip) const;
+
+ // For popups that are going to align to their selected item, get the frame of
+ // the selected item.
+ nsIFrame* GetSelectedItemForAlignment() const;
+
+ // check if the popup will fit into the available space and resize it. This
+ // method handles only one axis at a time so is called twice, once for
+ // horizontal and once for vertical. All arguments are specified for this
+ // one axis. All coordinates are in app units relative to the screen.
+ // aScreenPoint - the point where the popup should appear
+ // aSize - the size of the popup
+ // aScreenBegin - the left or top edge of the screen
+ // aScreenEnd - the right or bottom edge of the screen
+ // aAnchorBegin - the left or top edge of the anchor rectangle
+ // aAnchorEnd - the right or bottom edge of the anchor rectangle
+ // aMarginBegin - the left or top margin of the popup
+ // aMarginEnd - the right or bottom margin of the popup
+ // aFlip - how to flip or resize the popup when there isn't space
+ // aFlipSide - pointer to where current flip mode is stored
+ nscoord FlipOrResize(nscoord& aScreenPoint, nscoord aSize,
+ nscoord aScreenBegin, nscoord aScreenEnd,
+ nscoord aAnchorBegin, nscoord aAnchorEnd,
+ nscoord aMarginBegin, nscoord aMarginEnd,
+ FlipStyle aFlip, bool aIsOnEnd, bool* aFlipSide) const;
+
+ // check if the popup can fit into the available space by "sliding" (i.e.,
+ // by having the anchor arrow slide along one axis and only resizing if that
+ // can't provide the requested size). Only one axis can be slid - the other
+ // axis is "flipped" as normal. This method can handle either axis, but is
+ // only called for the sliding axis. All coordinates are in app units
+ // relative to the screen.
+ // aScreenPoint - the point where the popup should appear
+ // aSize - the size of the popup
+ // aScreenBegin - the left or top edge of the screen
+ // aScreenEnd - the right or bottom edge of the screen
+ // aOffset - the amount by which the arrow must be slid such that it is
+ // still aligned with the anchor.
+ // Result is the new size of the popup, which will typically be the same
+ // as aSize, unless aSize is greater than the screen width/height.
+ nscoord SlideOrResize(nscoord& aScreenPoint, nscoord aSize,
+ nscoord aScreenBegin, nscoord aScreenEnd,
+ nscoord* aOffset) const;
+
+ // Given an anchor frame, compute the anchor rectangle relative to the screen,
+ // using the popup frame's app units, and taking into account transforms.
+ nsRect ComputeAnchorRect(nsPresContext* aRootPresContext,
+ nsIFrame* aAnchorFrame) const;
+
+ // Move the popup to the position specified in its |left| and |top|
+ // attributes.
+ void MoveToAttributePosition();
+
+ // Create a popup view for this frame. The view is added a child of the root
+ // view, and is initially hidden.
+ void CreatePopupView();
+
+ nsView* GetViewInternal() const override { return mView; }
+ void SetViewInternal(nsView* aView) override { mView = aView; }
+
+ // Returns true if the popup should try to remain at the same relative
+ // location as the anchor while it is open. If the anchor becomes hidden
+ // either directly or indirectly because a parent popup or other element
+ // is no longer visible, or a parent deck page is changed, the popup hides
+ // as well. The second variation also sets the anchor rectangle, relative to
+ // the popup frame.
+ bool ShouldFollowAnchor() const;
+
+ nsIFrame* GetAnchorFrame() const;
+
+ public:
+ /**
+ * Return whether the popup direction should be RTL.
+ * If the popup has an anchor, its direction is the anchor direction.
+ * Otherwise, its the general direction of the UI.
+ *
+ * Return whether the popup direction should be RTL.
+ */
+ bool IsDirectionRTL() const;
+
+ bool ShouldFollowAnchor(nsRect& aRect);
+
+ // Returns parent menu widget for submenus that are in the same
+ // frame hierarchy, it's needed for Linux/Wayland which demands
+ // strict popup windows hierarchy.
+ nsIWidget* GetParentMenuWidget();
+
+ // Returns the effective margin for this popup. This is the CSS margin plus
+ // the context-menu shift, if needed.
+ nsMargin GetMargin() const;
+
+ // These are used by Wayland backend.
+ const nsRect& GetUntransformedAnchorRect() const {
+ return mUntransformedAnchorRect;
+ }
+ int GetPopupAlignment() const { return mPopupAlignment; }
+ int GetPopupAnchor() const { return mPopupAnchor; }
+ FlipType GetFlipType() const { return mFlip; }
+ bool IsFlippedByLayout() const { return mHFlip || mVFlip; }
+
+ void WidgetPositionOrSizeDidChange();
+
+ protected:
+ nsString mIncrementalString; // for incremental typing navigation
+
+ // the content that the popup is anchored to, if any, which may be in a
+ // different document than the popup.
+ nsCOMPtr<nsIContent> mAnchorContent;
+
+ // the content that triggered the popup, typically the node where the mouse
+ // was clicked. It will be cleared when the popup is hidden.
+ nsCOMPtr<nsIContent> mTriggerContent;
+
+ nsView* mView = nullptr;
+
+ RefPtr<nsXULPopupShownEvent> mPopupShownDispatcher;
+
+ // The popup's screen rectangle in app units.
+ nsRect mUsedScreenRect;
+
+ // A popup's preferred size may be different than its actual size stored in
+ // mRect in the case where the popup was resized because it was too large
+ // for the screen. The preferred size mPrefSize holds the full size the popup
+ // would be before resizing. Computations are performed using this size.
+ nsSize mPrefSize{-1, -1};
+
+ // The position of the popup, in CSS pixels.
+ // The screen coordinates, if set to values other than -1,
+ // override mXPos and mYPos.
+ int32_t mXPos = 0;
+ int32_t mYPos = 0;
+ nsRect mScreenRect;
+ // Used for store rectangle which the popup is going to be anchored to, we
+ // need that for Wayland. It's important that this rect is unflipped, and
+ // without margins applied, as GTK is what takes care of determining how to
+ // flip etc. on Wayland.
+ nsRect mUntransformedAnchorRect;
+
+ // If the panel prefers to "slide" rather than resize, then the arrow gets
+ // positioned at this offset (along either the x or y axis, depending on
+ // mPosition)
+ nscoord mAlignmentOffset = 0;
+
+ // The value of the client offset of our widget the last time we positioned
+ // ourselves. We store this so that we can detect when it changes but the
+ // position of our widget didn't change.
+ mozilla::LayoutDeviceIntPoint mLastClientOffset;
+
+ PopupType mPopupType = PopupType::Panel; // type of popup
+ nsPopupState mPopupState = ePopupClosed; // open state of the popup
+
+ // popup alignment relative to the anchor node
+ int8_t mPopupAlignment = POPUPALIGNMENT_NONE;
+ int8_t mPopupAnchor = POPUPALIGNMENT_NONE;
+ int8_t mPosition = POPUPPOSITION_UNKNOWN;
+
+ FlipType mFlip = FlipType_Default; // Whether to flip
+
+ // Whether we were moved by the move-to-rect Wayland callback. In that case,
+ // we stop updating the anchor so that we can end up with a stable position.
+ bool mPositionedByMoveToRect = false;
+ // true if the open state changed since the last layout.
+ bool mIsOpenChanged = false;
+ // true for context menus and their submenus.
+ bool mIsContextMenu = false;
+ // true for the topmost context menu.
+ bool mIsTopLevelContextMenu = false;
+ // true if the popup is in a content shell.
+ bool mInContentShell = true;
+
+ // The flip modes that were used when the popup was opened
+ bool mHFlip = false;
+ bool mVFlip = false;
+
+ // Whether the most recent initialization of this menupopup happened via
+ // InitializePopupAsNativeContextMenu.
+ bool mIsNativeMenu = false;
+
+ // Whether we have a pending `popuppositioned` event.
+ bool mPendingPositionedEvent = false;
+
+ // Whether this popup is source of D&D operation. We can't close such
+ // popup on Wayland as it cancel whole D&D operation.
+ bool mIsDragSource = false;
+
+ // When POPUPPOSITION_SELECTION is used, this indicates the vertical offset
+ // that the original selected item was. This needs to be used in case the
+ // popup gets changed so that we can keep the popup at the same vertical
+ // offset.
+ // TODO(emilio): try to make this not mutable.
+ mutable nscoord mPositionedOffset = 0;
+
+ // How the popup is anchored.
+ MenuPopupAnchorType mAnchorType = MenuPopupAnchorType_Node;
+
+ nsRect mOverrideConstraintRect;
+
+ static int8_t sDefaultLevelIsTop;
+
+ static mozilla::TimeStamp sLastKeyTime;
+
+}; // class nsMenuPopupFrame
+
+#endif