layout/xul/nsXULPopupManager.h

Thu, 15 Jan 2015 15:59:08 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 15 Jan 2015 15:59:08 +0100
branch
TOR_BUG_9701
changeset 10
ac0c01689b40
permissions
-rw-r--r--

Implement a real Private Browsing Mode condition by changing the API/ABI;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

     1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     2 /* This Source Code Form is subject to the terms of the Mozilla Public
     3  * License, v. 2.0. If a copy of the MPL was not distributed with this
     4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     6 /**
     7  * The XUL Popup Manager keeps track of all open popups.
     8  */
    10 #ifndef nsXULPopupManager_h__
    11 #define nsXULPopupManager_h__
    13 #include "prlog.h"
    14 #include "nsIContent.h"
    15 #include "nsIRollupListener.h"
    16 #include "nsIDOMEventListener.h"
    17 #include "nsPoint.h"
    18 #include "nsCOMPtr.h"
    19 #include "nsTArray.h"
    20 #include "nsIObserver.h"
    21 #include "nsITimer.h"
    22 #include "nsIReflowCallback.h"
    23 #include "nsThreadUtils.h"
    24 #include "nsStyleConsts.h"
    25 #include "nsWidgetInitData.h"
    26 #include "mozilla/Attributes.h"
    28 // X.h defines KeyPress
    29 #ifdef KeyPress
    30 #undef KeyPress
    31 #endif
    33 /**
    34  * There are two types that are used:
    35  *   - dismissable popups such as menus, which should close up when there is a
    36  *     click outside the popup. In this situation, the entire chain of menus
    37  *     above should also be closed.
    38  *   - panels, which stay open until a request is made to close them. This
    39  *     type is used by tooltips.
    40  *
    41  * When a new popup is opened, it is appended to the popup chain, stored in a
    42  * linked list in mPopups for dismissable menus and panels or mNoHidePanels
    43  * for tooltips and panels with noautohide="true".
    44  * Popups are stored in this list linked from newest to oldest. When a click
    45  * occurs outside one of the open dismissable popups, the chain is closed by
    46  * calling Rollup.
    47  */
    49 class nsMenuFrame;
    50 class nsMenuPopupFrame;
    51 class nsMenuBarFrame;
    52 class nsMenuParent;
    53 class nsIDOMKeyEvent;
    54 class nsIDocShellTreeItem;
    55 class nsPIDOMWindow;
    57 // when a menu command is executed, the closemenu attribute may be used
    58 // to define how the menu should be closed up
    59 enum CloseMenuMode {
    60   CloseMenuMode_Auto, // close up the chain of menus, default value
    61   CloseMenuMode_None, // don't close up any menus
    62   CloseMenuMode_Single // close up only the menu the command is inside
    63 };
    65 /**
    66  * nsNavigationDirection: an enum expressing navigation through the menus in
    67  * terms which are independent of the directionality of the chrome. The
    68  * terminology, derived from XSL-FO and CSS3 (e.g. 
    69  * http://www.w3.org/TR/css3-text/#TextLayout), is BASE (Before, After, Start,
    70  * End), with the addition of First and Last (mapped to Home and End
    71  * respectively).
    72  *
    73  * In languages such as English where the inline progression is left-to-right
    74  * and the block progression is top-to-bottom (lr-tb), these terms will map out
    75  * as in the following diagram
    76  *
    77  *  --- inline progression --->
    78  *
    79  *           First              |
    80  *           ...                |
    81  *           Before             |
    82  *         +--------+         block
    83  *   Start |        | End  progression
    84  *         +--------+           |
    85  *           After              |
    86  *           ...                |
    87  *           Last               V
    88  * 
    89  */
    91 enum nsNavigationDirection {
    92   eNavigationDirection_Last,
    93   eNavigationDirection_First,
    94   eNavigationDirection_Start,
    95   eNavigationDirection_Before,
    96   eNavigationDirection_End,
    97   eNavigationDirection_After
    98 };
   100 #define NS_DIRECTION_IS_INLINE(dir) (dir == eNavigationDirection_Start ||     \
   101                                      dir == eNavigationDirection_End)
   102 #define NS_DIRECTION_IS_BLOCK(dir) (dir == eNavigationDirection_Before || \
   103                                     dir == eNavigationDirection_After)
   104 #define NS_DIRECTION_IS_BLOCK_TO_EDGE(dir) (dir == eNavigationDirection_First ||    \
   105                                             dir == eNavigationDirection_Last)
   107 PR_STATIC_ASSERT(NS_STYLE_DIRECTION_LTR == 0 && NS_STYLE_DIRECTION_RTL == 1);
   109 /**
   110  * DirectionFromKeyCodeTable: two arrays, the first for left-to-right and the
   111  * other for right-to-left, that map keycodes to values of
   112  * nsNavigationDirection.
   113  */
   114 extern const nsNavigationDirection DirectionFromKeyCodeTable[2][6];
   116 #define NS_DIRECTION_FROM_KEY_CODE(frame, keycode)                     \
   117   (DirectionFromKeyCodeTable[frame->StyleVisibility()->mDirection]  \
   118                             [keycode - nsIDOMKeyEvent::DOM_VK_END])
   120 // nsMenuChainItem holds info about an open popup. Items are stored in a
   121 // doubly linked list. Note that the linked list is stored beginning from
   122 // the lowest child in a chain of menus, as this is the active submenu.
   123 class nsMenuChainItem
   124 {
   125 private:
   126   nsMenuPopupFrame* mFrame; // the popup frame
   127   nsPopupType mPopupType; // the popup type of the frame
   128   bool mIsContext; // true for context menus
   129   bool mOnMenuBar; // true if the menu is on a menu bar
   130   bool mIgnoreKeys; // true if keyboard listeners should not be used
   132   nsMenuChainItem* mParent;
   133   nsMenuChainItem* mChild;
   135 public:
   136   nsMenuChainItem(nsMenuPopupFrame* aFrame, bool aIsContext, nsPopupType aPopupType)
   137     : mFrame(aFrame),
   138       mPopupType(aPopupType),
   139       mIsContext(aIsContext),
   140       mOnMenuBar(false),
   141       mIgnoreKeys(false),
   142       mParent(nullptr),
   143       mChild(nullptr)
   144   {
   145     NS_ASSERTION(aFrame, "null frame passed to nsMenuChainItem constructor");
   146     MOZ_COUNT_CTOR(nsMenuChainItem);
   147   }
   149   ~nsMenuChainItem()
   150   {
   151     MOZ_COUNT_DTOR(nsMenuChainItem);
   152   }
   154   nsIContent* Content();
   155   nsMenuPopupFrame* Frame() { return mFrame; }
   156   nsPopupType PopupType() { return mPopupType; }
   157   bool IsMenu() { return mPopupType == ePopupTypeMenu; }
   158   bool IsContextMenu() { return mIsContext; }
   159   bool IgnoreKeys() { return mIgnoreKeys; }
   160   bool IsOnMenuBar() { return mOnMenuBar; }
   161   void SetIgnoreKeys(bool aIgnoreKeys) { mIgnoreKeys = aIgnoreKeys; }
   162   void SetOnMenuBar(bool aOnMenuBar) { mOnMenuBar = aOnMenuBar; }
   163   nsMenuChainItem* GetParent() { return mParent; }
   164   nsMenuChainItem* GetChild() { return mChild; }
   166   // set the parent of this item to aParent, also changing the parent
   167   // to have this as a child.
   168   void SetParent(nsMenuChainItem* aParent);
   170   // removes an item from the chain. The root pointer must be supplied in case
   171   // the item is the first item in the chain in which case the pointer will be
   172   // set to the next item, or null if there isn't another item. After detaching,
   173   // this item will not have a parent or a child.
   174   void Detach(nsMenuChainItem** aRoot);
   175 };
   177 // this class is used for dispatching popupshowing events asynchronously.
   178 class nsXULPopupShowingEvent : public nsRunnable
   179 {
   180 public:
   181   nsXULPopupShowingEvent(nsIContent *aPopup,
   182                          bool aIsContextMenu,
   183                          bool aSelectFirstItem)
   184     : mPopup(aPopup),
   185       mIsContextMenu(aIsContextMenu),
   186       mSelectFirstItem(aSelectFirstItem)
   187   {
   188     NS_ASSERTION(aPopup, "null popup supplied to nsXULPopupShowingEvent constructor");
   189   }
   191   NS_IMETHOD Run() MOZ_OVERRIDE;
   193 private:
   194   nsCOMPtr<nsIContent> mPopup;
   195   bool mIsContextMenu;
   196   bool mSelectFirstItem;
   197 };
   199 // this class is used for dispatching popuphiding events asynchronously.
   200 class nsXULPopupHidingEvent : public nsRunnable
   201 {
   202 public:
   203   nsXULPopupHidingEvent(nsIContent *aPopup,
   204                         nsIContent* aNextPopup,
   205                         nsIContent* aLastPopup,
   206                         nsPopupType aPopupType,
   207                         bool aDeselectMenu,
   208                         bool aIsRollup)
   209     : mPopup(aPopup),
   210       mNextPopup(aNextPopup),
   211       mLastPopup(aLastPopup),
   212       mPopupType(aPopupType),
   213       mDeselectMenu(aDeselectMenu),
   214       mIsRollup(aIsRollup)
   215   {
   216     NS_ASSERTION(aPopup, "null popup supplied to nsXULPopupHidingEvent constructor");
   217     // aNextPopup and aLastPopup may be null
   218   }
   220   NS_IMETHOD Run() MOZ_OVERRIDE;
   222 private:
   223   nsCOMPtr<nsIContent> mPopup;
   224   nsCOMPtr<nsIContent> mNextPopup;
   225   nsCOMPtr<nsIContent> mLastPopup;
   226   nsPopupType mPopupType;
   227   bool mDeselectMenu;
   228   bool mIsRollup;
   229 };
   231 // this class is used for dispatching menu command events asynchronously.
   232 class nsXULMenuCommandEvent : public nsRunnable
   233 {
   234 public:
   235   nsXULMenuCommandEvent(nsIContent *aMenu,
   236                         bool aIsTrusted,
   237                         bool aShift,
   238                         bool aControl,
   239                         bool aAlt,
   240                         bool aMeta,
   241                         bool aUserInput,
   242                         bool aFlipChecked)
   243     : mMenu(aMenu),
   244       mIsTrusted(aIsTrusted),
   245       mShift(aShift),
   246       mControl(aControl),
   247       mAlt(aAlt),
   248       mMeta(aMeta),
   249       mUserInput(aUserInput),
   250       mFlipChecked(aFlipChecked),
   251       mCloseMenuMode(CloseMenuMode_Auto)
   252   {
   253     NS_ASSERTION(aMenu, "null menu supplied to nsXULMenuCommandEvent constructor");
   254   }
   256   NS_IMETHOD Run() MOZ_OVERRIDE;
   258   void SetCloseMenuMode(CloseMenuMode aCloseMenuMode) { mCloseMenuMode = aCloseMenuMode; }
   260 private:
   261   nsCOMPtr<nsIContent> mMenu;
   262   bool mIsTrusted;
   263   bool mShift;
   264   bool mControl;
   265   bool mAlt;
   266   bool mMeta;
   267   bool mUserInput;
   268   bool mFlipChecked;
   269   CloseMenuMode mCloseMenuMode;
   270 };
   272 class nsXULPopupManager MOZ_FINAL : public nsIDOMEventListener,
   273                                     public nsIRollupListener,
   274                                     public nsITimerCallback,
   275                                     public nsIObserver
   276 {
   278 public:
   279   friend class nsXULPopupShowingEvent;
   280   friend class nsXULPopupHidingEvent;
   281   friend class nsXULMenuCommandEvent;
   282   friend class TransitionEnder;
   284   NS_DECL_ISUPPORTS
   285   NS_DECL_NSIOBSERVER
   286   NS_DECL_NSITIMERCALLBACK
   287   NS_DECL_NSIDOMEVENTLISTENER
   289   // nsIRollupListener
   290   virtual bool Rollup(uint32_t aCount, const nsIntPoint* pos, nsIContent** aLastRolledUp) MOZ_OVERRIDE;
   291   virtual bool ShouldRollupOnMouseWheelEvent() MOZ_OVERRIDE;
   292   virtual bool ShouldConsumeOnMouseWheelEvent() MOZ_OVERRIDE;
   293   virtual bool ShouldRollupOnMouseActivate() MOZ_OVERRIDE;
   294   virtual uint32_t GetSubmenuWidgetChain(nsTArray<nsIWidget*> *aWidgetChain) MOZ_OVERRIDE;
   295   virtual void NotifyGeometryChange() MOZ_OVERRIDE {}
   296   virtual nsIWidget* GetRollupWidget() MOZ_OVERRIDE;
   298   static nsXULPopupManager* sInstance;
   300   // initialize and shutdown methods called by nsLayoutStatics
   301   static nsresult Init();
   302   static void Shutdown();
   304   // returns a weak reference to the popup manager instance, could return null
   305   // if a popup manager could not be allocated
   306   static nsXULPopupManager* GetInstance();
   308   // This should be called when a window is moved or resized to adjust the
   309   // popups accordingly.
   310   void AdjustPopupsOnWindowChange(nsPIDOMWindow* aWindow);
   311   void AdjustPopupsOnWindowChange(nsIPresShell* aPresShell);
   313   // given a menu frame, find the prevous or next menu frame. If aPopup is
   314   // true then navigate a menupopup, from one item on the menu to the previous
   315   // or next one. This is used for cursor navigation between items in a popup
   316   // menu. If aIsPopup is false, the navigation is on a menubar, so navigate
   317   // between menus on the menubar. This is used for left/right cursor navigation.
   318   //
   319   // Items that are not valid, such as non-menu or non-menuitem elements are
   320   // skipped, and the next or previous item after that is checked.
   321   //
   322   // If aStart is null, the first valid item is retrieved by GetNextMenuItem
   323   // and the last valid item is retrieved by GetPreviousMenuItem.
   324   //
   325   // Both methods will loop around the beginning or end if needed.
   326   //
   327   // aParent - the parent menubar or menupopup
   328   // aStart - the menu/menuitem to start navigation from. GetPreviousMenuItem
   329   //          returns the item before it, while GetNextMenuItem returns the
   330   //          item after it.
   331   // aIsPopup - true for menupopups, false for menubars
   332   static nsMenuFrame* GetPreviousMenuItem(nsIFrame* aParent,
   333                                           nsMenuFrame* aStart,
   334                                           bool aIsPopup);
   335   static nsMenuFrame* GetNextMenuItem(nsIFrame* aParent,
   336                                       nsMenuFrame* aStart,
   337                                       bool aIsPopup);
   339   // returns true if the menu item aContent is a valid menuitem which may
   340   // be navigated to. aIsPopup should be true for items on a popup, or false
   341   // for items on a menubar.
   342   static bool IsValidMenuItem(nsPresContext* aPresContext,
   343                                 nsIContent* aContent,
   344                                 bool aOnPopup);
   346   // inform the popup manager that a menu bar has been activated or deactivated,
   347   // either because one of its menus has opened or closed, or that the menubar
   348   // has been focused such that its menus may be navigated with the keyboard.
   349   // aActivate should be true when the menubar should be focused, and false
   350   // when the active menu bar should be defocused. In the latter case, if
   351   // aMenuBar isn't currently active, yet another menu bar is, that menu bar
   352   // will remain active.
   353   void SetActiveMenuBar(nsMenuBarFrame* aMenuBar, bool aActivate);
   355   // retrieve the node and offset of the last mouse event used to open a
   356   // context menu. This information is determined from the rangeParent and
   357   // the rangeOffset of the event supplied to ShowPopup or ShowPopupAtScreen.
   358   // This is used by the implementation of nsIDOMXULDocument::GetPopupRangeParent
   359   // and nsIDOMXULDocument::GetPopupRangeOffset.
   360   void GetMouseLocation(nsIDOMNode** aNode, int32_t* aOffset);
   362   /**
   363    * Open a <menu> given its content node. If aSelectFirstItem is
   364    * set to true, the first item on the menu will automatically be
   365    * selected. If aAsynchronous is true, the event will be dispatched
   366    * asynchronously. This should be true when called from frame code.
   367    */
   368   void ShowMenu(nsIContent *aMenu, bool aSelectFirstItem, bool aAsynchronous);
   370   /**
   371    * Open a popup, either anchored or unanchored. If aSelectFirstItem is
   372    * true, then the first item in the menu is selected. The arguments are
   373    * similar to those for nsIPopupBoxObject::OpenPopup.
   374    *
   375    * aTriggerEvent should be the event that triggered the event. This is used
   376    * to determine the coordinates and trigger node for the popup. This may be
   377    * null if the popup was not triggered by an event.
   378    *
   379    * This fires the popupshowing event synchronously.
   380    */
   381   void ShowPopup(nsIContent* aPopup,
   382                  nsIContent* aAnchorContent,
   383                  const nsAString& aPosition,
   384                  int32_t aXPos, int32_t aYPos,
   385                  bool aIsContextMenu,
   386                  bool aAttributesOverride,
   387                  bool aSelectFirstItem,
   388                  nsIDOMEvent* aTriggerEvent);
   390   /**
   391    * Open a popup at a specific screen position specified by aXPos and aYPos,
   392    * measured in CSS pixels.
   393    *
   394    * This fires the popupshowing event synchronously.
   395    * 
   396    * If aIsContextMenu is true, the popup is positioned at a slight
   397    * offset from aXPos/aYPos to ensure that it is not under the mouse
   398    * cursor.
   399    */
   400   void ShowPopupAtScreen(nsIContent* aPopup,
   401                          int32_t aXPos, int32_t aYPos,
   402                          bool aIsContextMenu,
   403                          nsIDOMEvent* aTriggerEvent);
   405   /**
   406    * Open a tooltip at a specific screen position specified by aXPos and aYPos,
   407    * measured in CSS pixels.
   408    *
   409    * This fires the popupshowing event synchronously.
   410    */
   411   void ShowTooltipAtScreen(nsIContent* aPopup,
   412                            nsIContent* aTriggerContent,
   413                            int32_t aXPos, int32_t aYPos);
   415   /**
   416    * This method is provided only for compatibility with an older popup API.
   417    * New code should not call this function and should call ShowPopup instead.
   418    *
   419    * This fires the popupshowing event synchronously.
   420    */
   421   void ShowPopupWithAnchorAlign(nsIContent* aPopup,
   422                                 nsIContent* aAnchorContent,
   423                                 nsAString& aAnchor,
   424                                 nsAString& aAlign,
   425                                 int32_t aXPos, int32_t aYPos,
   426                                 bool aIsContextMenu);
   428   /*
   429    * Hide a popup aPopup. If the popup is in a <menu>, then also inform the
   430    * menu that the popup is being hidden.
   431    *
   432    * aHideChain - true if the entire chain of menus should be closed. If false,
   433    *              only this popup is closed.
   434    * aDeselectMenu - true if the parent <menu> of the popup should be deselected.
   435    *                 This will be false when the menu is closed by pressing the
   436    *                 Escape key.
   437    * aAsynchronous - true if the first popuphiding event should be sent
   438    *                 asynchrously. This should be true if HidePopup is called
   439    *                 from a frame.
   440    * aIsRollup - true if this popup is hiding due to a rollup or escape keypress.
   441    * aLastPopup - optional popup to close last when hiding a chain of menus.
   442    *              If null, then all popups will be closed.
   443    */
   444   void HidePopup(nsIContent* aPopup,
   445                  bool aHideChain,
   446                  bool aDeselectMenu,
   447                  bool aAsynchronous,
   448                  bool aIsRollup,
   449                  nsIContent* aLastPopup = nullptr);
   451   /**
   452    * Hide the popup aFrame. This method is called by the view manager when the
   453    * close button is pressed.
   454    */
   455   void HidePopup(nsIFrame* aFrame);
   457   /**
   458    * Hide a popup after a short delay. This is used when rolling over menu items.
   459    * This timer is stored in mCloseTimer. The timer may be cancelled and the popup
   460    * closed by calling KillMenuTimer.
   461    */
   462   void HidePopupAfterDelay(nsMenuPopupFrame* aPopup);
   464   /**
   465    * Hide all of the popups from a given docshell. This should be called when the
   466    * document is hidden.
   467    */
   468   void HidePopupsInDocShell(nsIDocShellTreeItem* aDocShellToHide);
   470   /**
   471    * Execute a menu command from the triggering event aEvent.
   472    *
   473    * aMenu - a menuitem to execute
   474    * aEvent - an nsXULMenuCommandEvent that contains all the info from the mouse
   475    *          event which triggered the menu to be executed, may not be null
   476    */
   477   void ExecuteMenu(nsIContent* aMenu, nsXULMenuCommandEvent* aEvent);
   479   /**
   480    * Return true if the popup for the supplied content node is open.
   481    */
   482   bool IsPopupOpen(nsIContent* aPopup);
   484   /**
   485    * Return true if the popup for the supplied menu parent is open.
   486    */
   487   bool IsPopupOpenForMenuParent(nsMenuParent* aMenuParent);
   489   /**
   490    * Return the frame for the topmost open popup of a given type, or null if
   491    * no popup of that type is open. If aType is ePopupTypeAny, a menu of any
   492    * type is returned, except for popups in the mNoHidePanels list.
   493    */
   494   nsIFrame* GetTopPopup(nsPopupType aType);
   496   /**
   497    * Return an array of all the open and visible popup frames for
   498    * menus, in order from top to bottom.
   499    */
   500   void GetVisiblePopups(nsTArray<nsIFrame *>& aPopups);
   502   /**
   503    * Get the node that last triggered a popup or tooltip in the document
   504    * aDocument. aDocument must be non-null and be a document contained within
   505    * the same window hierarchy as the popup to retrieve.
   506    */
   507   already_AddRefed<nsIDOMNode> GetLastTriggerPopupNode(nsIDocument* aDocument)
   508   {
   509     return GetLastTriggerNode(aDocument, false);
   510   }
   512   already_AddRefed<nsIDOMNode> GetLastTriggerTooltipNode(nsIDocument* aDocument)
   513   {
   514     return GetLastTriggerNode(aDocument, true);
   515   }
   517   /**
   518    * Return false if a popup may not be opened. This will return false if the
   519    * popup is already open, if the popup is in a content shell that is not
   520    * focused, or if it is a submenu of another menu that isn't open.
   521    */
   522   bool MayShowPopup(nsMenuPopupFrame* aFrame);
   524   /**
   525    * Indicate that the popup associated with aView has been moved to the
   526    * specified screen coordiates.
   527    */
   528   void PopupMoved(nsIFrame* aFrame, nsIntPoint aPoint);
   530   /**
   531    * Indicate that the popup associated with aView has been resized to the
   532    * specified screen width and height.
   533    */
   534   void PopupResized(nsIFrame* aFrame, nsIntSize ASize);
   536   /**
   537    * Called when a popup frame is destroyed. In this case, just remove the
   538    * item and later popups from the list. No point going through HidePopup as
   539    * the frames have gone away.
   540    */
   541   void PopupDestroyed(nsMenuPopupFrame* aFrame);
   543   /**
   544    * Returns true if there is a context menu open. If aPopup is specified,
   545    * then the context menu must be later in the chain than aPopup. If aPopup
   546    * is null, returns true if any context menu at all is open.
   547    */
   548   bool HasContextMenu(nsMenuPopupFrame* aPopup);
   550   /**
   551    * Update the commands for the menus within the menu popup for a given
   552    * content node. aPopup should be a XUL menupopup element. This method
   553    * changes attributes on the children of aPopup, and deals only with the
   554    * content of the popup, not the frames.
   555    */
   556   void UpdateMenuItems(nsIContent* aPopup);
   558   /**
   559    * Stop the timer which hides a popup after a delay, started by a previous
   560    * call to HidePopupAfterDelay. In addition, the popup awaiting to be hidden
   561    * is closed asynchronously.
   562    */
   563   void KillMenuTimer();
   565   /**
   566    * Cancel the timer which closes menus after delay, but only if the menu to
   567    * close is aMenuParent. When a submenu is opened, the user might move the
   568    * mouse over a sibling menuitem which would normally close the menu. This
   569    * menu is closed via a timer. However, if the user moves the mouse over the
   570    * submenu before the timer fires, we should instead cancel the timer. This
   571    * ensures that the user can move the mouse diagonally over a menu.
   572    */
   573   void CancelMenuTimer(nsMenuParent* aMenuParent);
   575   /**
   576    * Handles navigation for menu accelkeys. Returns true if the key has
   577    * been handled. If aFrame is specified, then the key is handled by that
   578    * popup, otherwise if aFrame is null, the key is handled by the active
   579    * popup or menubar.
   580    */
   581   bool HandleShortcutNavigation(nsIDOMKeyEvent* aKeyEvent,
   582                                   nsMenuPopupFrame* aFrame);
   584   /**
   585    * Handles cursor navigation within a menu. Returns true if the key has
   586    * been handled.
   587    */
   588   bool HandleKeyboardNavigation(uint32_t aKeyCode);
   590   /**
   591    * Handle keyboard navigation within a menu popup specified by aFrame.
   592    * Returns true if the key was handled and other default handling
   593    * should not occur.
   594    */
   595   bool HandleKeyboardNavigationInPopup(nsMenuPopupFrame* aFrame,
   596                                          nsNavigationDirection aDir)
   597   {
   598     return HandleKeyboardNavigationInPopup(nullptr, aFrame, aDir);
   599   }
   601   /**
   602    * Handles the keyboard event with keyCode value. Returns true if the event
   603    * has been handled.
   604    */
   605   bool HandleKeyboardEventWithKeyCode(nsIDOMKeyEvent* aKeyEvent,
   606                                       nsMenuChainItem* aTopVisibleMenuItem);
   608   nsresult KeyUp(nsIDOMKeyEvent* aKeyEvent);
   609   nsresult KeyDown(nsIDOMKeyEvent* aKeyEvent);
   610   nsresult KeyPress(nsIDOMKeyEvent* aKeyEvent);
   612 protected:
   613   nsXULPopupManager();
   614   ~nsXULPopupManager();
   616   // get the nsMenuPopupFrame, if any, for the given content node
   617   nsMenuPopupFrame* GetPopupFrameForContent(nsIContent* aContent, bool aShouldFlush);
   619   // return the topmost menu, skipping over invisible popups
   620   nsMenuChainItem* GetTopVisibleMenu();
   622   // Hide all of the visible popups from the given list. aDeselectMenu
   623   // indicates whether to deselect the menu of popups when hiding; this
   624   // flag is passed as the first argument to HidePopup. This function
   625   // can cause style changes and frame destruction.
   626   void HidePopupsInList(const nsTArray<nsMenuPopupFrame *> &aFrames,
   627                         bool aDeselectMenu);
   629   // set the event that was used to trigger the popup, or null to clear the
   630   // event details. aTriggerContent will be set to the target of the event.
   631   void InitTriggerEvent(nsIDOMEvent* aEvent, nsIContent* aPopup, nsIContent** aTriggerContent);
   633   // callbacks for ShowPopup and HidePopup as events may be done asynchronously
   634   void ShowPopupCallback(nsIContent* aPopup,
   635                          nsMenuPopupFrame* aPopupFrame,
   636                          bool aIsContextMenu,
   637                          bool aSelectFirstItem);
   638   void HidePopupCallback(nsIContent* aPopup,
   639                          nsMenuPopupFrame* aPopupFrame,
   640                          nsIContent* aNextPopup,
   641                          nsIContent* aLastPopup,
   642                          nsPopupType aPopupType,
   643                          bool aDeselectMenu);
   645   /**
   646    * Fire a popupshowing event on the popup and then open the popup.
   647    *
   648    * aPopup - the popup to open
   649    * aIsContextMenu - true for context menus
   650    * aSelectFirstItem - true to select the first item in the menu
   651    */
   652   void FirePopupShowingEvent(nsIContent* aPopup,
   653                              bool aIsContextMenu,
   654                              bool aSelectFirstItem);
   656   /**
   657    * Fire a popuphiding event and then hide the popup. This will be called
   658    * recursively if aNextPopup and aLastPopup are set in order to hide a chain
   659    * of open menus. If these are not set, only one popup is closed. However,
   660    * if the popup type indicates a menu, yet the next popup is not a menu,
   661    * then this ends the closing of popups. This allows a menulist inside a
   662    * non-menu to close up the menu but not close up the panel it is contained
   663    * within.
   664    *
   665    * The caller must keep a strong reference to aPopup, aNextPopup and aLastPopup.
   666    *
   667    * aPopup - the popup to hide
   668    * aNextPopup - the next popup to hide
   669    * aLastPopup - the last popup in the chain to hide
   670    * aPresContext - nsPresContext for the popup's frame
   671    * aPopupType - the PopupType of the frame. 
   672    * aDeselectMenu - true to unhighlight the menu when hiding it
   673    * aIsRollup - true if this popup is hiding due to a rollup or escape keypress
   674    */
   675   void FirePopupHidingEvent(nsIContent* aPopup,
   676                             nsIContent* aNextPopup,
   677                             nsIContent* aLastPopup,
   678                             nsPresContext *aPresContext,
   679                             nsPopupType aPopupType,
   680                             bool aDeselectMenu,
   681                             bool aIsRollup);
   683   /**
   684    * Handle keyboard navigation within a menu popup specified by aItem.
   685    */
   686   bool HandleKeyboardNavigationInPopup(nsMenuChainItem* aItem,
   687                                          nsNavigationDirection aDir)
   688   {
   689     return HandleKeyboardNavigationInPopup(aItem, aItem->Frame(), aDir);
   690   }
   692 private:
   693   /**
   694    * Handle keyboard navigation within a menu popup aFrame. If aItem is
   695    * supplied, then it is expected to have a frame equal to aFrame.
   696    * If aItem is non-null, then the navigation may be redirected to
   697    * an open submenu if one exists. Returns true if the key was
   698    * handled and other default handling should not occur.
   699    */
   700   bool HandleKeyboardNavigationInPopup(nsMenuChainItem* aItem,
   701                                          nsMenuPopupFrame* aFrame,
   702                                          nsNavigationDirection aDir);
   704 protected:
   706   already_AddRefed<nsIDOMNode> GetLastTriggerNode(nsIDocument* aDocument, bool aIsTooltip);
   708   /**
   709    * Set mouse capturing for the current popup. This traps mouse clicks that
   710    * occur outside the popup so that it can be closed up. aOldPopup should be
   711    * set to the popup that was previously the current popup.
   712    */
   713   void SetCaptureState(nsIContent *aOldPopup);
   715   /**
   716    * Key event listeners are attached to the document containing the current
   717    * menu for menu and shortcut navigation. Only one listener is needed at a
   718    * time, stored in mKeyListener, so switch it only if the document changes.
   719    * Having menus in different documents is very rare, so the listeners will
   720    * usually only be attached when the first menu opens and removed when all
   721    * menus have closed.
   722    *
   723    * This is also used when only a menubar is active without any open menus,
   724    * so that keyboard navigation between menus on the menubar may be done.
   725    */
   726   void UpdateKeyboardListeners();
   728   /*
   729    * Returns true if the docshell for aDoc is aExpected or a child of aExpected.
   730    */
   731   bool IsChildOfDocShell(nsIDocument* aDoc, nsIDocShellTreeItem* aExpected);
   733   // the document the key event listener is attached to
   734   nsCOMPtr<mozilla::dom::EventTarget> mKeyListener;
   736   // widget that is currently listening to rollup events
   737   nsCOMPtr<nsIWidget> mWidget;
   739   // range parent and offset set in SetTriggerEvent
   740   nsCOMPtr<nsIDOMNode> mRangeParent;
   741   int32_t mRangeOffset;
   742   // Device pixels relative to the showing popup's presshell's
   743   // root prescontext's root frame.
   744   nsIntPoint mCachedMousePoint;
   746   // cached modifiers
   747   mozilla::Modifiers mCachedModifiers;
   749   // set to the currently active menu bar, if any
   750   nsMenuBarFrame* mActiveMenuBar;
   752   // linked list of normal menus and panels.
   753   nsMenuChainItem* mPopups;
   755   // linked list of noautohide panels and tooltips.
   756   nsMenuChainItem* mNoHidePanels;
   758   // timer used for HidePopupAfterDelay
   759   nsCOMPtr<nsITimer> mCloseTimer;
   761   // a popup that is waiting on the timer
   762   nsMenuPopupFrame* mTimerMenu;
   764   // the popup that is currently being opened, stored only during the
   765   // popupshowing event
   766   nsCOMPtr<nsIContent> mOpeningPopup;
   767 };
   769 #endif

mercurial