nsMenuPopupFrame.h (26870B)
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/. */ 6 7 // 8 // nsMenuPopupFrame 9 // 10 11 #ifndef nsMenuPopupFrame_h__ 12 #define nsMenuPopupFrame_h__ 13 14 #include "Units.h" 15 #include "mozilla/Attributes.h" 16 #include "mozilla/StaticPrefs_ui.h" 17 #include "mozilla/TimeStamp.h" 18 #include "mozilla/gfx/Types.h" 19 #include "nsAtom.h" 20 #include "nsBlockFrame.h" 21 #include "nsCOMPtr.h" 22 #include "nsExpirationState.h" 23 #include "nsIDOMEventListener.h" 24 #include "nsIWidgetListener.h" 25 #include "nsXULPopupManager.h" 26 27 class nsIWidget; 28 29 namespace mozilla { 30 class PresShell; 31 enum class WindowShadow : uint8_t; 32 namespace dom { 33 class KeyboardEvent; 34 class XULButtonElement; 35 class XULPopupElement; 36 } // namespace dom 37 namespace widget { 38 enum class PopupLevel : uint8_t; 39 } 40 } // namespace mozilla 41 42 enum ConsumeOutsideClicksResult { 43 ConsumeOutsideClicks_ParentOnly = 44 0, // Only consume clicks on the parent anchor 45 ConsumeOutsideClicks_True = 1, // Always consume clicks 46 ConsumeOutsideClicks_Never = 2 // Never consume clicks 47 }; 48 49 // How a popup may be flipped. Flipping to the outside edge is like how a 50 // submenu would work. The entire popup is flipped to the opposite side of the 51 // anchor. 52 enum class FlipStyle { 53 None = 0, 54 Outside = 1, 55 Inside = 2, 56 }; 57 58 // Values for the flip attribute 59 enum class FlipType { 60 Default = 0, 61 None = 1, // don't try to flip or translate to stay onscreen 62 Both = 2, // flip in both directions 63 Slide = 3, // allow the arrow to "slide" instead of resizing 64 }; 65 66 enum class MenuPopupAnchorType : uint8_t { 67 Node = 0, // anchored to a node 68 Point = 1, // unanchored, and positioned at a screen point 69 Rect = 2, // anchored at a screen rectangle 70 }; 71 72 // values are selected so that the direction can be flipped just by 73 // changing the sign 74 #define POPUPALIGNMENT_NONE 0 75 #define POPUPALIGNMENT_TOPLEFT 1 76 #define POPUPALIGNMENT_TOPRIGHT -1 77 #define POPUPALIGNMENT_BOTTOMLEFT 2 78 #define POPUPALIGNMENT_BOTTOMRIGHT -2 79 80 #define POPUPALIGNMENT_LEFTCENTER 16 81 #define POPUPALIGNMENT_RIGHTCENTER -16 82 #define POPUPALIGNMENT_TOPCENTER 17 83 #define POPUPALIGNMENT_BOTTOMCENTER 18 84 85 // The constants here are selected so that horizontally and vertically flipping 86 // can be easily handled using the two flip macros below. 87 #define POPUPPOSITION_UNKNOWN -1 88 #define POPUPPOSITION_BEFORESTART 0 89 #define POPUPPOSITION_BEFOREEND 1 90 #define POPUPPOSITION_AFTERSTART 2 91 #define POPUPPOSITION_AFTEREND 3 92 #define POPUPPOSITION_STARTBEFORE 4 93 #define POPUPPOSITION_ENDBEFORE 5 94 #define POPUPPOSITION_STARTAFTER 6 95 #define POPUPPOSITION_ENDAFTER 7 96 #define POPUPPOSITION_OVERLAP 8 97 #define POPUPPOSITION_AFTERPOINTER 9 98 #define POPUPPOSITION_SELECTION 10 99 100 #define POPUPPOSITION_HFLIP(v) (v ^ 1) 101 #define POPUPPOSITION_VFLIP(v) (v ^ 2) 102 103 nsIFrame* NS_NewMenuPopupFrame(mozilla::PresShell* aPresShell, 104 mozilla::ComputedStyle* aStyle); 105 106 class nsMenuPopupFrame; 107 108 // this class is used for dispatching popupshown events asynchronously. 109 class nsXULPopupShownEvent final : public mozilla::Runnable, 110 public nsIDOMEventListener { 111 public: 112 nsXULPopupShownEvent(nsIContent* aPopup, nsPresContext* aPresContext) 113 : mozilla::Runnable("nsXULPopupShownEvent"), 114 mPopup(aPopup), 115 mPresContext(aPresContext) {} 116 117 NS_DECL_ISUPPORTS_INHERITED 118 NS_DECL_NSIRUNNABLE 119 NS_DECL_NSIDOMEVENTLISTENER 120 121 void CancelListener(); 122 123 protected: 124 virtual ~nsXULPopupShownEvent() = default; 125 126 private: 127 const nsCOMPtr<nsIContent> mPopup; 128 const RefPtr<nsPresContext> mPresContext; 129 }; 130 131 class nsMenuPopupFrame final : public nsBlockFrame, public nsIWidgetListener { 132 using PopupLevel = mozilla::widget::PopupLevel; 133 using PopupType = mozilla::widget::PopupType; 134 135 public: 136 NS_DECL_QUERYFRAME 137 NS_DECL_FRAMEARENA_HELPERS(nsMenuPopupFrame) 138 139 explicit nsMenuPopupFrame(ComputedStyle* aStyle, nsPresContext* aPresContext); 140 ~nsMenuPopupFrame(); 141 142 // as popups are opened asynchronously, the popup pending state is used to 143 // prevent multiple requests from attempting to open the same popup twice 144 nsPopupState PopupState() const { return mPopupState; } 145 void SetPopupState(nsPopupState); 146 147 /* 148 * When this popup is open, should clicks outside of it be consumed? 149 * Return true if the popup should rollup on an outside click, 150 * but consume that click so it can't be used for anything else. 151 * Return false to allow clicks outside the popup to activate content 152 * even when the popup is open. 153 * --------------------------------------------------------------------- 154 * 155 * Should clicks outside of a popup be eaten? 156 * 157 * Menus Autocomplete Comboboxes 158 * Mac Eat No Eat 159 * Win No No Eat 160 * Unix Eat No Eat 161 * 162 */ 163 ConsumeOutsideClicksResult ConsumeOutsideClicks(); 164 165 mozilla::dom::XULPopupElement& PopupElement() const; 166 167 nscoord IntrinsicISize(const mozilla::IntrinsicSizeInput& aInput, 168 mozilla::IntrinsicISizeType aType) override; 169 170 void Reflow(nsPresContext* aPresContext, ReflowOutput& aDesiredSize, 171 const ReflowInput& aReflowInput, 172 nsReflowStatus& aStatus) override; 173 174 nsIWidget* GetWidget() const; 175 already_AddRefed<nsIWidget> ComputeParentWidget() const; 176 177 enum class WidgetStyle : uint8_t { 178 ColorScheme, 179 InputRegion, 180 Opacity, 181 Shadow, 182 Transform, 183 MicaBackdrop, 184 }; 185 using WidgetStyleFlags = mozilla::EnumSet<WidgetStyle>; 186 static constexpr WidgetStyleFlags AllWidgetStyleFlags() { 187 return {WidgetStyle::ColorScheme, WidgetStyle::InputRegion, 188 WidgetStyle::Opacity, WidgetStyle::Shadow, 189 WidgetStyle::Transform, WidgetStyle::MicaBackdrop}; 190 } 191 void PropagateStyleToWidget(WidgetStyleFlags = AllWidgetStyleFlags()) const; 192 193 // Overridden methods 194 void Init(nsIContent* aContent, nsContainerFrame* aParent, 195 nsIFrame* aPrevInFlow) override; 196 197 nsresult AttributeChanged(int32_t aNameSpaceID, nsAtom* aAttribute, 198 AttrModType aModType) override; 199 200 // nsIWidgetListener 201 mozilla::PresShell* GetPresShell() override { return PresShell(); } 202 nsMenuPopupFrame* GetAsMenuPopupFrame() override { return this; } 203 void WindowMoved(nsIWidget*, const mozilla::LayoutDeviceIntPoint&, 204 ByMoveToRect) override; 205 void WindowResized(nsIWidget*, const mozilla::LayoutDeviceIntSize&) override; 206 bool RequestWindowClose(nsIWidget*) override; 207 MOZ_CAN_RUN_SCRIPT_BOUNDARY 208 nsEventStatus HandleEvent(mozilla::WidgetGUIEvent* aEvent) override; 209 MOZ_CAN_RUN_SCRIPT_BOUNDARY 210 void PaintWindow(nsIWidget* aWidget) override; 211 void DidCompositeWindow(mozilla::layers::TransactionId aTransactionId, 212 const mozilla::TimeStamp& aCompositeStart, 213 const mozilla::TimeStamp& aCompositeEnd) override; 214 bool ShouldNotBeVisible() override { return !IsOpen(); } 215 using nsIFrame::HandleEvent; // Needed to silence warning. 216 217 // FIXME: This shouldn't run script (this can end up calling HidePopup). 218 MOZ_CAN_RUN_SCRIPT_BOUNDARY void Destroy(DestroyContext&) override; 219 220 bool HasRemoteContent() const; 221 222 // Whether this is a drag popup to show drag feedback. 223 bool IsDragPopup() const; 224 225 // Whether we should have a widget even when we're not shown. 226 bool ShouldHaveWidgetWhenHidden() const; 227 228 // Whether we should expand the menu to take the size of the parent menulist. 229 bool ShouldExpandToInflowParentOrAnchor() const; 230 231 // Returns true if the popup is a panel with the noautohide attribute set to 232 // true. These panels do not roll up automatically. 233 bool IsNoAutoHide() const; 234 235 PopupLevel GetPopupLevel() const { return GetPopupLevel(IsNoAutoHide()); } 236 237 // Ensure that a widget has already been created for this view, and create 238 // one if it hasn't. If aForceRecreate is true, destroys any existing widget 239 // and creates a new one, regardless of whether one has already been created. 240 // Otherwise does so only if needed. 241 void PrepareWidget(bool aForceRecreate = false); 242 243 MOZ_CAN_RUN_SCRIPT void EnsureActiveMenuListItemIsVisible(); 244 245 void CreateWidget(); 246 void DestroyWidget(); 247 mozilla::WindowShadow GetShadowStyle() const; 248 249 void DidSetComputedStyle(ComputedStyle* aOldStyle) override; 250 251 // layout, position and display the popup as needed 252 MOZ_CAN_RUN_SCRIPT_BOUNDARY 253 void LayoutPopup(nsPresContext*, ReflowOutput&, const ReflowInput&, 254 nsReflowStatus&); 255 256 // Set the position of the popup relative to the anchor content, anchored at a 257 // rectangle, or at a specific point if a screen position is set. The popup 258 // will be adjusted so that it is on screen. If aIsMove is true, then the 259 // popup is being moved, and should not be flipped. 260 void SetPopupPosition(bool aIsMove); 261 262 // Called when the Enter key is pressed while the popup is open. This will 263 // just pass the call down to the current menu, if any. 264 // Also, calling Enter will reset the current incremental search string, 265 // calculated in FindMenuWithShortcut. 266 MOZ_CAN_RUN_SCRIPT void HandleEnterKeyPress(mozilla::WidgetEvent&); 267 268 // Locate and return the menu frame that should be activated for the supplied 269 // key event. If aDoAction is set to true by this method, then the menu's 270 // action should be carried out, as if the user had pressed the Enter key. If 271 // aDoAction is false, the menu should just be highlighted. 272 // This method also handles incremental searching in menus so the user can 273 // type the first few letters of an item/s name to select it. 274 mozilla::dom::XULButtonElement* FindMenuWithShortcut( 275 mozilla::dom::KeyboardEvent& aKeyEvent, bool& aDoAction); 276 277 mozilla::dom::XULButtonElement* GetCurrentMenuItem() const; 278 nsIFrame* GetCurrentMenuItemFrame() const; 279 280 PopupType GetPopupType() const { return mPopupType; } 281 bool IsContextMenu() const { return mIsContextMenu; } 282 283 bool IsOpen() const { 284 return mPopupState == ePopupOpening || mPopupState == ePopupVisible || 285 mPopupState == ePopupShown; 286 } 287 bool IsVisible() const { 288 return mPopupState == ePopupVisible || mPopupState == ePopupShown; 289 } 290 bool IsVisibleOrShowing() const { 291 return IsOpen() || mPopupState == ePopupPositioning || 292 mPopupState == ePopupShowing; 293 } 294 bool IsNativeMenu() const { return mIsNativeMenu; } 295 bool CanSkipLayout() const; 296 bool IsMouseTransparent() const; 297 298 // Return true if the popup is for a menulist. 299 bool IsMenuList() const; 300 301 bool IsDragSource() const { return mIsDragSource; } 302 void SetIsDragSource(bool aIsDragSource) { mIsDragSource = aIsDragSource; } 303 304 bool PendingWidgetMoveResize() const { return mPendingWidgetMoveResize; } 305 void ClearPendingWidgetMoveResize() { mPendingWidgetMoveResize = false; } 306 void SchedulePendingWidgetMoveResize(); 307 308 static nsIContent* GetTriggerContent(nsMenuPopupFrame* aMenuPopupFrame); 309 void ClearTriggerContent() { mTriggerContent = nullptr; } 310 void ClearTriggerContentIncludingDocument(); 311 312 // returns true if the popup is in a content shell, or false for a popup in 313 // a chrome shell 314 bool IsInContentShell() const { return mInContentShell; } 315 316 // the Initialize methods are used to set the anchor position for 317 // each way of opening a popup. 318 void InitializePopup(nsIContent* aAnchorContent, nsIContent* aTriggerContent, 319 const nsAString& aPosition, int32_t aXPos, int32_t aYPos, 320 MenuPopupAnchorType aAnchorType, 321 bool aAttributesOverride); 322 323 void InitializePopupAtRect(nsIContent* aTriggerContent, 324 const nsAString& aPosition, const nsIntRect& aRect, 325 bool aAttributesOverride); 326 327 /** 328 * @param aIsContextMenu if true, then the popup is 329 * positioned at a slight offset from aXPos/aYPos to ensure the 330 * (presumed) mouse position is not over the menu. 331 */ 332 void InitializePopupAtScreen(nsIContent* aTriggerContent, int32_t aXPos, 333 int32_t aYPos, bool aIsContextMenu); 334 335 // Called if this popup should be displayed as an OS-native context menu. 336 void InitializePopupAsNativeContextMenu(nsIContent* aTriggerContent, 337 int32_t aXPos, int32_t aYPos); 338 339 // indicate that the popup should be opened 340 void ShowPopup(bool aIsContextMenu); 341 // indicate that the popup should be hidden. The new state should either be 342 // ePopupClosed or ePopupInvisible. 343 MOZ_CAN_RUN_SCRIPT void HidePopup(bool aDeselectMenu, nsPopupState aNewState, 344 bool aFromFrameDestruction = false); 345 346 void ClearIncrementalString() { mIncrementalString.Truncate(); } 347 static bool IsWithinIncrementalTime(mozilla::TimeStamp time) { 348 return !sLastKeyTime.IsNull() && 349 ((time - sLastKeyTime).ToMilliseconds() <= 350 mozilla::StaticPrefs::ui_menu_incremental_search_timeout()); 351 } 352 353 #ifdef DEBUG_FRAME_DUMP 354 virtual nsresult GetFrameName(nsAString& aResult) const override { 355 return MakeFrameName(u"MenuPopup"_ns, aResult); 356 } 357 #endif 358 359 MOZ_CAN_RUN_SCRIPT void ChangeByPage(bool aIsUp); 360 361 // Move the popup to the screen coordinate |aPos| in CSS pixels. 362 // If aUpdateAttrs is true, and the popup already has left or top attributes, 363 // then those attributes are updated to the new location. 364 // The frame may be destroyed by this method. 365 void MoveTo(const mozilla::CSSPoint& aPos, bool aUpdateAttrs, 366 bool aByMoveToRect = false); 367 368 void MoveToAnchor(nsIContent* aAnchorContent, const nsAString& aPosition, 369 int32_t aXPos, int32_t aYPos, bool aAttributesOverride); 370 371 mozilla::ScrollContainerFrame* GetScrollContainerFrame() const; 372 373 void SetOverrideConstraintRect(const mozilla::CSSIntRect& aRect) { 374 mOverrideConstraintRect = mozilla::CSSIntRect::ToAppUnits(aRect); 375 } 376 377 bool IsConstrainedByLayout() const { return mConstrainedByLayout; } 378 379 struct Rects { 380 // For anchored popups, the anchor rectangle. For non-anchored popups, the 381 // size will be 0. 382 nsRect mAnchorRect; 383 // mAnchorRect before accounting for flipping / resizing / intersecting with 384 // the screen. This is needed for Wayland, which flips / resizes at the 385 // widget level. 386 nsRect mUntransformedAnchorRect; 387 // The final used rect we want to occupy. 388 nsRect mUsedRect; 389 // The alignment offset for sliding the panel, see 390 // nsMenuPopupFrame::mAlignmentOffset. 391 nscoord mAlignmentOffset = 0; 392 bool mHFlip = false; 393 bool mVFlip = false; 394 bool mConstrainedByLayout = false; 395 nsPoint mViewPoint; 396 }; 397 398 // For a popup that should appear anchored at the given rect, gets the anchor 399 // and constraint rects for that popup. 400 // This will be the available area of the screen the popup should be displayed 401 // on. Content popups, however, will also be constrained by the content area. 402 // 403 // For non-toplevel popups (which will always be panels), we will also 404 // constrain them to the available screen rect, ie they will not fall 405 // underneath the taskbar, dock or other fixed OS elements. 406 Rects GetRects(const nsSize& aPrefSize) const; 407 Maybe<nsRect> GetConstraintRect(const nsRect& aAnchorRect, 408 const nsRect& aRootScreenRect, 409 PopupLevel) const; 410 void PerformMove(const Rects&); 411 412 // Return true if the popup is positioned relative to an anchor. 413 bool IsAnchored() const { return mAnchorType != MenuPopupAnchorType::Point; } 414 415 // Return the anchor if there is one. 416 nsIContent* GetAnchor() const { return mAnchorContent; } 417 418 // Return the screen coordinates in CSS pixels of the popup, 419 // or (-1, -1, 0, 0) if anchored. 420 mozilla::CSSIntRect GetScreenAnchorRect() const { 421 return mozilla::CSSRect::FromAppUnitsRounded(mScreenRect); 422 } 423 424 mozilla::LayoutDeviceIntRect CalcWidgetBounds() const; 425 426 // Return the alignment of the popup 427 int8_t GetAlignmentPosition() const; 428 429 // Return the offset applied to the alignment of the popup 430 nscoord GetAlignmentOffset() const { return mAlignmentOffset; } 431 432 // Clear the mPopupShownDispatcher, remove the listener and return true if 433 // mPopupShownDispatcher was non-null. 434 bool ClearPopupShownDispatcher() { 435 if (mPopupShownDispatcher) { 436 mPopupShownDispatcher->CancelListener(); 437 mPopupShownDispatcher = nullptr; 438 return true; 439 } 440 441 return false; 442 } 443 444 void ShowWithPositionedEvent() { mPopupState = ePopupPositioning; } 445 446 // Checks for the anchor to change and either moves or hides the popup 447 // accordingly. The original position of the anchor should be supplied as 448 // the argument. If the popup needs to be hidden, HidePopup will be called by 449 // CheckForAnchorChange. If the popup needs to be moved, aRect will be updated 450 // with the new rectangle. 451 void CheckForAnchorChange(nsRect& aRect); 452 453 void WillDispatchPopupPositioned() { mPendingPositionedEvent = false; } 454 455 protected: 456 // returns the popup's level. 457 PopupLevel GetPopupLevel(bool aIsNoAutoHide) const; 458 459 void InitPositionFromAnchorAlign(const nsAString& aAnchor, 460 const nsAString& aAlign); 461 462 // return the position where the popup should be, when it should be 463 // anchored at anchorRect. aHFlip and aVFlip will be set if the popup may be 464 // flipped in that direction if there is not enough space available. 465 nsPoint AdjustPositionForAnchorAlign(nsRect& aAnchorRect, 466 const nsSize& aPrefSize, 467 FlipStyle& aHFlip, 468 FlipStyle& aVFlip) const; 469 470 // For popups that are going to align to their selected item, get the frame of 471 // the selected item. 472 nsIFrame* GetSelectedItemForAlignment() const; 473 474 // check if the popup will fit into the available space and resize it. This 475 // method handles only one axis at a time so is called twice, once for 476 // horizontal and once for vertical. All arguments are specified for this 477 // one axis. All coordinates are in app units relative to the screen. 478 // aScreenPoint - the point where the popup should appear 479 // aSize - the size of the popup 480 // aScreenBegin - the left or top edge of the screen 481 // aScreenEnd - the right or bottom edge of the screen 482 // aAnchorBegin - the left or top edge of the anchor rectangle 483 // aAnchorEnd - the right or bottom edge of the anchor rectangle 484 // aMarginBegin - the left or top margin of the popup 485 // aMarginEnd - the right or bottom margin of the popup 486 // aFlip - how to flip or resize the popup when there isn't space 487 // aFlipSide - pointer to where current flip mode is stored 488 nscoord FlipOrResize(nscoord& aScreenPoint, nscoord aSize, 489 nscoord aScreenBegin, nscoord aScreenEnd, 490 nscoord aAnchorBegin, nscoord aAnchorEnd, 491 nscoord aMarginBegin, nscoord aMarginEnd, 492 FlipStyle aFlip, bool aIsOnEnd, bool* aFlipSide) const; 493 494 // check if the popup can fit into the available space by "sliding" (i.e., 495 // by having the anchor arrow slide along one axis and only resizing if that 496 // can't provide the requested size). Only one axis can be slid - the other 497 // axis is "flipped" as normal. This method can handle either axis, but is 498 // only called for the sliding axis. All coordinates are in app units 499 // relative to the screen. 500 // aScreenPoint - the point where the popup should appear 501 // aSize - the size of the popup 502 // aScreenBegin - the left or top edge of the screen 503 // aScreenEnd - the right or bottom edge of the screen 504 // aOffset - the amount by which the arrow must be slid such that it is 505 // still aligned with the anchor. 506 // Result is the new size of the popup, which will typically be the same 507 // as aSize, unless aSize is greater than the screen width/height. 508 nscoord SlideOrResize(nscoord& aScreenPoint, nscoord aSize, 509 nscoord aScreenBegin, nscoord aScreenEnd, 510 nscoord* aOffset) const; 511 512 // Given an anchor frame, compute the anchor rectangle relative to the screen, 513 // using the popup frame's app units, and taking into account transforms. 514 nsRect ComputeAnchorRect(nsPresContext* aRootPresContext, 515 nsIFrame* aAnchorFrame) const; 516 517 // Move the popup to the position specified in its |left| and |top| 518 // attributes. 519 void MoveToAttributePosition(); 520 521 // Returns true if the popup should try to remain at the same relative 522 // location as the anchor while it is open. If the anchor becomes hidden 523 // either directly or indirectly because a parent popup or other element 524 // is no longer visible, or a parent deck page is changed, the popup hides 525 // as well. The second variation also sets the anchor rectangle, relative to 526 // the popup frame. 527 bool ShouldFollowAnchor() const; 528 529 nsIFrame* GetAnchorFrame() const; 530 531 public: 532 /** 533 * Return whether the popup direction should be RTL. 534 * If the popup has an anchor, its direction is the anchor direction. 535 * Otherwise, its the general direction of the UI. 536 * 537 * Return whether the popup direction should be RTL. 538 */ 539 bool IsDirectionRTL() const; 540 541 bool ShouldFollowAnchor(nsRect& aRect); 542 543 // Returns parent menu widget for submenus that are in the same 544 // frame hierarchy, it's needed for Linux/Wayland which demands 545 // strict popup windows hierarchy. 546 nsIWidget* GetParentMenuWidget(); 547 548 // Returns the effective margin for this popup. This is the CSS margin plus 549 // the context-menu shift, if needed. 550 nsMargin GetMargin() const; 551 552 // These are used by Wayland backend. 553 const nsRect& GetUntransformedAnchorRect() const { 554 return mUntransformedAnchorRect; 555 } 556 int8_t GetUntransformedPopupAlignment() const { 557 return mUntransformedPopupAlignment; 558 } 559 int8_t GetUntransformedPopupAnchor() const { 560 return mUntransformedPopupAnchor; 561 } 562 563 int8_t GetPopupAlignment() const { return mPopupAlignment; } 564 int8_t GetPopupAnchor() const { return mPopupAnchor; } 565 FlipType GetFlipType() const { return mFlip; } 566 567 uint64_t GetAPZFocusSequenceNumber() const { return mAPZFocusSequenceNumber; } 568 569 void UpdateAPZFocusSequenceNumber(uint64_t aNewNumber) { 570 mAPZFocusSequenceNumber = aNewNumber; 571 } 572 573 void DestroyWidgetIfNeeded(); 574 nsExpirationState* GetExpirationState() { return &mExpirationState; } 575 576 protected: 577 nsString mIncrementalString; // for incremental typing navigation 578 579 // the content that the popup is anchored to, if any, which may be in a 580 // different document than the popup. 581 nsCOMPtr<nsIContent> mAnchorContent; 582 583 // the content that triggered the popup, typically the node where the mouse 584 // was clicked. It will be cleared when the popup is hidden. 585 nsCOMPtr<nsIContent> mTriggerContent; 586 587 RefPtr<nsIWidget> mWidget; 588 589 RefPtr<nsXULPopupShownEvent> mPopupShownDispatcher; 590 591 // The popup's screen rectangle in app units. 592 nsRect mUsedScreenRect; 593 594 // A popup's preferred size may be different than its actual size stored in 595 // mRect in the case where the popup was resized because it was too large 596 // for the screen. The preferred size mPrefSize holds the full size the popup 597 // would be before resizing. Computations are performed using this size. 598 nsSize mPrefSize{-1, -1}; 599 600 // A point with extra offsets to apply in the horizontal and vertical axes. We 601 // don't use an nsMargin because the values would be the same for the same 602 // axis. 603 nsPoint mExtraMargin; 604 605 nsRect mScreenRect; 606 // Used for store rectangle which the popup is going to be anchored to, we 607 // need that for Wayland. It's important that this rect is unflipped, and 608 // without margins applied, as GTK is what takes care of determining how to 609 // flip etc. on Wayland. 610 nsRect mUntransformedAnchorRect; 611 612 // If the panel prefers to "slide" rather than resize, then the arrow gets 613 // positioned at this offset (along either the x or y axis, depending on 614 // mPosition) 615 nscoord mAlignmentOffset = 0; 616 617 // The focus sequence number of the last processed input event 618 uint64_t mAPZFocusSequenceNumber = 0; 619 620 PopupType mPopupType = PopupType::Panel; // type of popup 621 nsPopupState mPopupState = ePopupClosed; // open state of the popup 622 623 // popup alignment relative to the anchor node 624 // The untransformed variants are needed for Wayland 625 int8_t mUntransformedPopupAlignment = POPUPALIGNMENT_NONE; 626 int8_t mUntransformedPopupAnchor = POPUPALIGNMENT_NONE; 627 int8_t mPopupAlignment = POPUPALIGNMENT_NONE; 628 int8_t mPopupAnchor = POPUPALIGNMENT_NONE; 629 int8_t mPosition = POPUPPOSITION_UNKNOWN; 630 631 FlipType mFlip = FlipType::Default; // Whether to flip 632 633 // Whether we were moved by the move-to-rect Wayland callback. In that case, 634 // we stop updating the anchor so that we can end up with a stable position. 635 bool mPositionedByMoveToRect = false; 636 // true if the open state changed since the last layout. 637 bool mIsOpenChanged = false; 638 // true for context menus and their submenus. 639 bool mIsContextMenu = false; 640 // true for the topmost context menu. 641 bool mIsTopLevelContextMenu = false; 642 // true if the popup is in a content shell. 643 bool mInContentShell = true; 644 645 // The flip modes that were used when the popup was opened 646 bool mHFlip = false; 647 bool mVFlip = false; 648 // Whether layout has constrained this popup in some way. 649 bool mConstrainedByLayout = false; 650 651 // Whether the most recent initialization of this menupopup happened via 652 // InitializePopupAsNativeContextMenu. 653 bool mIsNativeMenu = false; 654 655 // Whether we have a pending `popuppositioned` event. 656 bool mPendingPositionedEvent = false; 657 658 // Whether this popup is source of D&D operation. We can't close such 659 // popup on Wayland as it cancel whole D&D operation. 660 bool mIsDragSource = false; 661 662 // Whether there's a pending move-resize of our widget. 663 bool mPendingWidgetMoveResize = false; 664 665 // When POPUPPOSITION_SELECTION is used, this indicates the vertical offset 666 // that the original selected item was. This needs to be used in case the 667 // popup gets changed so that we can keep the popup at the same vertical 668 // offset. 669 // TODO(emilio): try to make this not mutable. 670 mutable nscoord mPositionedOffset = 0; 671 672 // How the popup is anchored. 673 MenuPopupAnchorType mAnchorType = MenuPopupAnchorType::Node; 674 675 nsRect mOverrideConstraintRect; 676 677 nsExpirationState mExpirationState; 678 static mozilla::TimeStamp sLastKeyTime; 679 }; // class nsMenuPopupFrame 680 681 #endif