layout/xul/nsXULPopupManager.h

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/layout/xul/nsXULPopupManager.h	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,769 @@
     1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.8 +
     1.9 +/**
    1.10 + * The XUL Popup Manager keeps track of all open popups.
    1.11 + */
    1.12 +
    1.13 +#ifndef nsXULPopupManager_h__
    1.14 +#define nsXULPopupManager_h__
    1.15 +
    1.16 +#include "prlog.h"
    1.17 +#include "nsIContent.h"
    1.18 +#include "nsIRollupListener.h"
    1.19 +#include "nsIDOMEventListener.h"
    1.20 +#include "nsPoint.h"
    1.21 +#include "nsCOMPtr.h"
    1.22 +#include "nsTArray.h"
    1.23 +#include "nsIObserver.h"
    1.24 +#include "nsITimer.h"
    1.25 +#include "nsIReflowCallback.h"
    1.26 +#include "nsThreadUtils.h"
    1.27 +#include "nsStyleConsts.h"
    1.28 +#include "nsWidgetInitData.h"
    1.29 +#include "mozilla/Attributes.h"
    1.30 +
    1.31 +// X.h defines KeyPress
    1.32 +#ifdef KeyPress
    1.33 +#undef KeyPress
    1.34 +#endif
    1.35 +
    1.36 +/**
    1.37 + * There are two types that are used:
    1.38 + *   - dismissable popups such as menus, which should close up when there is a
    1.39 + *     click outside the popup. In this situation, the entire chain of menus
    1.40 + *     above should also be closed.
    1.41 + *   - panels, which stay open until a request is made to close them. This
    1.42 + *     type is used by tooltips.
    1.43 + *
    1.44 + * When a new popup is opened, it is appended to the popup chain, stored in a
    1.45 + * linked list in mPopups for dismissable menus and panels or mNoHidePanels
    1.46 + * for tooltips and panels with noautohide="true".
    1.47 + * Popups are stored in this list linked from newest to oldest. When a click
    1.48 + * occurs outside one of the open dismissable popups, the chain is closed by
    1.49 + * calling Rollup.
    1.50 + */
    1.51 +
    1.52 +class nsMenuFrame;
    1.53 +class nsMenuPopupFrame;
    1.54 +class nsMenuBarFrame;
    1.55 +class nsMenuParent;
    1.56 +class nsIDOMKeyEvent;
    1.57 +class nsIDocShellTreeItem;
    1.58 +class nsPIDOMWindow;
    1.59 +
    1.60 +// when a menu command is executed, the closemenu attribute may be used
    1.61 +// to define how the menu should be closed up
    1.62 +enum CloseMenuMode {
    1.63 +  CloseMenuMode_Auto, // close up the chain of menus, default value
    1.64 +  CloseMenuMode_None, // don't close up any menus
    1.65 +  CloseMenuMode_Single // close up only the menu the command is inside
    1.66 +};
    1.67 +
    1.68 +/**
    1.69 + * nsNavigationDirection: an enum expressing navigation through the menus in
    1.70 + * terms which are independent of the directionality of the chrome. The
    1.71 + * terminology, derived from XSL-FO and CSS3 (e.g. 
    1.72 + * http://www.w3.org/TR/css3-text/#TextLayout), is BASE (Before, After, Start,
    1.73 + * End), with the addition of First and Last (mapped to Home and End
    1.74 + * respectively).
    1.75 + *
    1.76 + * In languages such as English where the inline progression is left-to-right
    1.77 + * and the block progression is top-to-bottom (lr-tb), these terms will map out
    1.78 + * as in the following diagram
    1.79 + *
    1.80 + *  --- inline progression --->
    1.81 + *
    1.82 + *           First              |
    1.83 + *           ...                |
    1.84 + *           Before             |
    1.85 + *         +--------+         block
    1.86 + *   Start |        | End  progression
    1.87 + *         +--------+           |
    1.88 + *           After              |
    1.89 + *           ...                |
    1.90 + *           Last               V
    1.91 + * 
    1.92 + */
    1.93 +
    1.94 +enum nsNavigationDirection {
    1.95 +  eNavigationDirection_Last,
    1.96 +  eNavigationDirection_First,
    1.97 +  eNavigationDirection_Start,
    1.98 +  eNavigationDirection_Before,
    1.99 +  eNavigationDirection_End,
   1.100 +  eNavigationDirection_After
   1.101 +};
   1.102 +
   1.103 +#define NS_DIRECTION_IS_INLINE(dir) (dir == eNavigationDirection_Start ||     \
   1.104 +                                     dir == eNavigationDirection_End)
   1.105 +#define NS_DIRECTION_IS_BLOCK(dir) (dir == eNavigationDirection_Before || \
   1.106 +                                    dir == eNavigationDirection_After)
   1.107 +#define NS_DIRECTION_IS_BLOCK_TO_EDGE(dir) (dir == eNavigationDirection_First ||    \
   1.108 +                                            dir == eNavigationDirection_Last)
   1.109 +
   1.110 +PR_STATIC_ASSERT(NS_STYLE_DIRECTION_LTR == 0 && NS_STYLE_DIRECTION_RTL == 1);
   1.111 +
   1.112 +/**
   1.113 + * DirectionFromKeyCodeTable: two arrays, the first for left-to-right and the
   1.114 + * other for right-to-left, that map keycodes to values of
   1.115 + * nsNavigationDirection.
   1.116 + */
   1.117 +extern const nsNavigationDirection DirectionFromKeyCodeTable[2][6];
   1.118 +
   1.119 +#define NS_DIRECTION_FROM_KEY_CODE(frame, keycode)                     \
   1.120 +  (DirectionFromKeyCodeTable[frame->StyleVisibility()->mDirection]  \
   1.121 +                            [keycode - nsIDOMKeyEvent::DOM_VK_END])
   1.122 +
   1.123 +// nsMenuChainItem holds info about an open popup. Items are stored in a
   1.124 +// doubly linked list. Note that the linked list is stored beginning from
   1.125 +// the lowest child in a chain of menus, as this is the active submenu.
   1.126 +class nsMenuChainItem
   1.127 +{
   1.128 +private:
   1.129 +  nsMenuPopupFrame* mFrame; // the popup frame
   1.130 +  nsPopupType mPopupType; // the popup type of the frame
   1.131 +  bool mIsContext; // true for context menus
   1.132 +  bool mOnMenuBar; // true if the menu is on a menu bar
   1.133 +  bool mIgnoreKeys; // true if keyboard listeners should not be used
   1.134 +
   1.135 +  nsMenuChainItem* mParent;
   1.136 +  nsMenuChainItem* mChild;
   1.137 +
   1.138 +public:
   1.139 +  nsMenuChainItem(nsMenuPopupFrame* aFrame, bool aIsContext, nsPopupType aPopupType)
   1.140 +    : mFrame(aFrame),
   1.141 +      mPopupType(aPopupType),
   1.142 +      mIsContext(aIsContext),
   1.143 +      mOnMenuBar(false),
   1.144 +      mIgnoreKeys(false),
   1.145 +      mParent(nullptr),
   1.146 +      mChild(nullptr)
   1.147 +  {
   1.148 +    NS_ASSERTION(aFrame, "null frame passed to nsMenuChainItem constructor");
   1.149 +    MOZ_COUNT_CTOR(nsMenuChainItem);
   1.150 +  }
   1.151 +
   1.152 +  ~nsMenuChainItem()
   1.153 +  {
   1.154 +    MOZ_COUNT_DTOR(nsMenuChainItem);
   1.155 +  }
   1.156 +
   1.157 +  nsIContent* Content();
   1.158 +  nsMenuPopupFrame* Frame() { return mFrame; }
   1.159 +  nsPopupType PopupType() { return mPopupType; }
   1.160 +  bool IsMenu() { return mPopupType == ePopupTypeMenu; }
   1.161 +  bool IsContextMenu() { return mIsContext; }
   1.162 +  bool IgnoreKeys() { return mIgnoreKeys; }
   1.163 +  bool IsOnMenuBar() { return mOnMenuBar; }
   1.164 +  void SetIgnoreKeys(bool aIgnoreKeys) { mIgnoreKeys = aIgnoreKeys; }
   1.165 +  void SetOnMenuBar(bool aOnMenuBar) { mOnMenuBar = aOnMenuBar; }
   1.166 +  nsMenuChainItem* GetParent() { return mParent; }
   1.167 +  nsMenuChainItem* GetChild() { return mChild; }
   1.168 +
   1.169 +  // set the parent of this item to aParent, also changing the parent
   1.170 +  // to have this as a child.
   1.171 +  void SetParent(nsMenuChainItem* aParent);
   1.172 +
   1.173 +  // removes an item from the chain. The root pointer must be supplied in case
   1.174 +  // the item is the first item in the chain in which case the pointer will be
   1.175 +  // set to the next item, or null if there isn't another item. After detaching,
   1.176 +  // this item will not have a parent or a child.
   1.177 +  void Detach(nsMenuChainItem** aRoot);
   1.178 +};
   1.179 +
   1.180 +// this class is used for dispatching popupshowing events asynchronously.
   1.181 +class nsXULPopupShowingEvent : public nsRunnable
   1.182 +{
   1.183 +public:
   1.184 +  nsXULPopupShowingEvent(nsIContent *aPopup,
   1.185 +                         bool aIsContextMenu,
   1.186 +                         bool aSelectFirstItem)
   1.187 +    : mPopup(aPopup),
   1.188 +      mIsContextMenu(aIsContextMenu),
   1.189 +      mSelectFirstItem(aSelectFirstItem)
   1.190 +  {
   1.191 +    NS_ASSERTION(aPopup, "null popup supplied to nsXULPopupShowingEvent constructor");
   1.192 +  }
   1.193 +
   1.194 +  NS_IMETHOD Run() MOZ_OVERRIDE;
   1.195 +
   1.196 +private:
   1.197 +  nsCOMPtr<nsIContent> mPopup;
   1.198 +  bool mIsContextMenu;
   1.199 +  bool mSelectFirstItem;
   1.200 +};
   1.201 +
   1.202 +// this class is used for dispatching popuphiding events asynchronously.
   1.203 +class nsXULPopupHidingEvent : public nsRunnable
   1.204 +{
   1.205 +public:
   1.206 +  nsXULPopupHidingEvent(nsIContent *aPopup,
   1.207 +                        nsIContent* aNextPopup,
   1.208 +                        nsIContent* aLastPopup,
   1.209 +                        nsPopupType aPopupType,
   1.210 +                        bool aDeselectMenu,
   1.211 +                        bool aIsRollup)
   1.212 +    : mPopup(aPopup),
   1.213 +      mNextPopup(aNextPopup),
   1.214 +      mLastPopup(aLastPopup),
   1.215 +      mPopupType(aPopupType),
   1.216 +      mDeselectMenu(aDeselectMenu),
   1.217 +      mIsRollup(aIsRollup)
   1.218 +  {
   1.219 +    NS_ASSERTION(aPopup, "null popup supplied to nsXULPopupHidingEvent constructor");
   1.220 +    // aNextPopup and aLastPopup may be null
   1.221 +  }
   1.222 +
   1.223 +  NS_IMETHOD Run() MOZ_OVERRIDE;
   1.224 +
   1.225 +private:
   1.226 +  nsCOMPtr<nsIContent> mPopup;
   1.227 +  nsCOMPtr<nsIContent> mNextPopup;
   1.228 +  nsCOMPtr<nsIContent> mLastPopup;
   1.229 +  nsPopupType mPopupType;
   1.230 +  bool mDeselectMenu;
   1.231 +  bool mIsRollup;
   1.232 +};
   1.233 +
   1.234 +// this class is used for dispatching menu command events asynchronously.
   1.235 +class nsXULMenuCommandEvent : public nsRunnable
   1.236 +{
   1.237 +public:
   1.238 +  nsXULMenuCommandEvent(nsIContent *aMenu,
   1.239 +                        bool aIsTrusted,
   1.240 +                        bool aShift,
   1.241 +                        bool aControl,
   1.242 +                        bool aAlt,
   1.243 +                        bool aMeta,
   1.244 +                        bool aUserInput,
   1.245 +                        bool aFlipChecked)
   1.246 +    : mMenu(aMenu),
   1.247 +      mIsTrusted(aIsTrusted),
   1.248 +      mShift(aShift),
   1.249 +      mControl(aControl),
   1.250 +      mAlt(aAlt),
   1.251 +      mMeta(aMeta),
   1.252 +      mUserInput(aUserInput),
   1.253 +      mFlipChecked(aFlipChecked),
   1.254 +      mCloseMenuMode(CloseMenuMode_Auto)
   1.255 +  {
   1.256 +    NS_ASSERTION(aMenu, "null menu supplied to nsXULMenuCommandEvent constructor");
   1.257 +  }
   1.258 +
   1.259 +  NS_IMETHOD Run() MOZ_OVERRIDE;
   1.260 +
   1.261 +  void SetCloseMenuMode(CloseMenuMode aCloseMenuMode) { mCloseMenuMode = aCloseMenuMode; }
   1.262 +
   1.263 +private:
   1.264 +  nsCOMPtr<nsIContent> mMenu;
   1.265 +  bool mIsTrusted;
   1.266 +  bool mShift;
   1.267 +  bool mControl;
   1.268 +  bool mAlt;
   1.269 +  bool mMeta;
   1.270 +  bool mUserInput;
   1.271 +  bool mFlipChecked;
   1.272 +  CloseMenuMode mCloseMenuMode;
   1.273 +};
   1.274 +
   1.275 +class nsXULPopupManager MOZ_FINAL : public nsIDOMEventListener,
   1.276 +                                    public nsIRollupListener,
   1.277 +                                    public nsITimerCallback,
   1.278 +                                    public nsIObserver
   1.279 +{
   1.280 +
   1.281 +public:
   1.282 +  friend class nsXULPopupShowingEvent;
   1.283 +  friend class nsXULPopupHidingEvent;
   1.284 +  friend class nsXULMenuCommandEvent;
   1.285 +  friend class TransitionEnder;
   1.286 +
   1.287 +  NS_DECL_ISUPPORTS
   1.288 +  NS_DECL_NSIOBSERVER
   1.289 +  NS_DECL_NSITIMERCALLBACK
   1.290 +  NS_DECL_NSIDOMEVENTLISTENER
   1.291 +
   1.292 +  // nsIRollupListener
   1.293 +  virtual bool Rollup(uint32_t aCount, const nsIntPoint* pos, nsIContent** aLastRolledUp) MOZ_OVERRIDE;
   1.294 +  virtual bool ShouldRollupOnMouseWheelEvent() MOZ_OVERRIDE;
   1.295 +  virtual bool ShouldConsumeOnMouseWheelEvent() MOZ_OVERRIDE;
   1.296 +  virtual bool ShouldRollupOnMouseActivate() MOZ_OVERRIDE;
   1.297 +  virtual uint32_t GetSubmenuWidgetChain(nsTArray<nsIWidget*> *aWidgetChain) MOZ_OVERRIDE;
   1.298 +  virtual void NotifyGeometryChange() MOZ_OVERRIDE {}
   1.299 +  virtual nsIWidget* GetRollupWidget() MOZ_OVERRIDE;
   1.300 +
   1.301 +  static nsXULPopupManager* sInstance;
   1.302 +
   1.303 +  // initialize and shutdown methods called by nsLayoutStatics
   1.304 +  static nsresult Init();
   1.305 +  static void Shutdown();
   1.306 +
   1.307 +  // returns a weak reference to the popup manager instance, could return null
   1.308 +  // if a popup manager could not be allocated
   1.309 +  static nsXULPopupManager* GetInstance();
   1.310 +
   1.311 +  // This should be called when a window is moved or resized to adjust the
   1.312 +  // popups accordingly.
   1.313 +  void AdjustPopupsOnWindowChange(nsPIDOMWindow* aWindow);
   1.314 +  void AdjustPopupsOnWindowChange(nsIPresShell* aPresShell);
   1.315 +
   1.316 +  // given a menu frame, find the prevous or next menu frame. If aPopup is
   1.317 +  // true then navigate a menupopup, from one item on the menu to the previous
   1.318 +  // or next one. This is used for cursor navigation between items in a popup
   1.319 +  // menu. If aIsPopup is false, the navigation is on a menubar, so navigate
   1.320 +  // between menus on the menubar. This is used for left/right cursor navigation.
   1.321 +  //
   1.322 +  // Items that are not valid, such as non-menu or non-menuitem elements are
   1.323 +  // skipped, and the next or previous item after that is checked.
   1.324 +  //
   1.325 +  // If aStart is null, the first valid item is retrieved by GetNextMenuItem
   1.326 +  // and the last valid item is retrieved by GetPreviousMenuItem.
   1.327 +  //
   1.328 +  // Both methods will loop around the beginning or end if needed.
   1.329 +  //
   1.330 +  // aParent - the parent menubar or menupopup
   1.331 +  // aStart - the menu/menuitem to start navigation from. GetPreviousMenuItem
   1.332 +  //          returns the item before it, while GetNextMenuItem returns the
   1.333 +  //          item after it.
   1.334 +  // aIsPopup - true for menupopups, false for menubars
   1.335 +  static nsMenuFrame* GetPreviousMenuItem(nsIFrame* aParent,
   1.336 +                                          nsMenuFrame* aStart,
   1.337 +                                          bool aIsPopup);
   1.338 +  static nsMenuFrame* GetNextMenuItem(nsIFrame* aParent,
   1.339 +                                      nsMenuFrame* aStart,
   1.340 +                                      bool aIsPopup);
   1.341 +
   1.342 +  // returns true if the menu item aContent is a valid menuitem which may
   1.343 +  // be navigated to. aIsPopup should be true for items on a popup, or false
   1.344 +  // for items on a menubar.
   1.345 +  static bool IsValidMenuItem(nsPresContext* aPresContext,
   1.346 +                                nsIContent* aContent,
   1.347 +                                bool aOnPopup);
   1.348 +
   1.349 +  // inform the popup manager that a menu bar has been activated or deactivated,
   1.350 +  // either because one of its menus has opened or closed, or that the menubar
   1.351 +  // has been focused such that its menus may be navigated with the keyboard.
   1.352 +  // aActivate should be true when the menubar should be focused, and false
   1.353 +  // when the active menu bar should be defocused. In the latter case, if
   1.354 +  // aMenuBar isn't currently active, yet another menu bar is, that menu bar
   1.355 +  // will remain active.
   1.356 +  void SetActiveMenuBar(nsMenuBarFrame* aMenuBar, bool aActivate);
   1.357 +
   1.358 +  // retrieve the node and offset of the last mouse event used to open a
   1.359 +  // context menu. This information is determined from the rangeParent and
   1.360 +  // the rangeOffset of the event supplied to ShowPopup or ShowPopupAtScreen.
   1.361 +  // This is used by the implementation of nsIDOMXULDocument::GetPopupRangeParent
   1.362 +  // and nsIDOMXULDocument::GetPopupRangeOffset.
   1.363 +  void GetMouseLocation(nsIDOMNode** aNode, int32_t* aOffset);
   1.364 +
   1.365 +  /**
   1.366 +   * Open a <menu> given its content node. If aSelectFirstItem is
   1.367 +   * set to true, the first item on the menu will automatically be
   1.368 +   * selected. If aAsynchronous is true, the event will be dispatched
   1.369 +   * asynchronously. This should be true when called from frame code.
   1.370 +   */
   1.371 +  void ShowMenu(nsIContent *aMenu, bool aSelectFirstItem, bool aAsynchronous);
   1.372 +
   1.373 +  /**
   1.374 +   * Open a popup, either anchored or unanchored. If aSelectFirstItem is
   1.375 +   * true, then the first item in the menu is selected. The arguments are
   1.376 +   * similar to those for nsIPopupBoxObject::OpenPopup.
   1.377 +   *
   1.378 +   * aTriggerEvent should be the event that triggered the event. This is used
   1.379 +   * to determine the coordinates and trigger node for the popup. This may be
   1.380 +   * null if the popup was not triggered by an event.
   1.381 +   *
   1.382 +   * This fires the popupshowing event synchronously.
   1.383 +   */
   1.384 +  void ShowPopup(nsIContent* aPopup,
   1.385 +                 nsIContent* aAnchorContent,
   1.386 +                 const nsAString& aPosition,
   1.387 +                 int32_t aXPos, int32_t aYPos,
   1.388 +                 bool aIsContextMenu,
   1.389 +                 bool aAttributesOverride,
   1.390 +                 bool aSelectFirstItem,
   1.391 +                 nsIDOMEvent* aTriggerEvent);
   1.392 +
   1.393 +  /**
   1.394 +   * Open a popup at a specific screen position specified by aXPos and aYPos,
   1.395 +   * measured in CSS pixels.
   1.396 +   *
   1.397 +   * This fires the popupshowing event synchronously.
   1.398 +   * 
   1.399 +   * If aIsContextMenu is true, the popup is positioned at a slight
   1.400 +   * offset from aXPos/aYPos to ensure that it is not under the mouse
   1.401 +   * cursor.
   1.402 +   */
   1.403 +  void ShowPopupAtScreen(nsIContent* aPopup,
   1.404 +                         int32_t aXPos, int32_t aYPos,
   1.405 +                         bool aIsContextMenu,
   1.406 +                         nsIDOMEvent* aTriggerEvent);
   1.407 +
   1.408 +  /**
   1.409 +   * Open a tooltip at a specific screen position specified by aXPos and aYPos,
   1.410 +   * measured in CSS pixels.
   1.411 +   *
   1.412 +   * This fires the popupshowing event synchronously.
   1.413 +   */
   1.414 +  void ShowTooltipAtScreen(nsIContent* aPopup,
   1.415 +                           nsIContent* aTriggerContent,
   1.416 +                           int32_t aXPos, int32_t aYPos);
   1.417 +
   1.418 +  /**
   1.419 +   * This method is provided only for compatibility with an older popup API.
   1.420 +   * New code should not call this function and should call ShowPopup instead.
   1.421 +   *
   1.422 +   * This fires the popupshowing event synchronously.
   1.423 +   */
   1.424 +  void ShowPopupWithAnchorAlign(nsIContent* aPopup,
   1.425 +                                nsIContent* aAnchorContent,
   1.426 +                                nsAString& aAnchor,
   1.427 +                                nsAString& aAlign,
   1.428 +                                int32_t aXPos, int32_t aYPos,
   1.429 +                                bool aIsContextMenu);
   1.430 +
   1.431 +  /*
   1.432 +   * Hide a popup aPopup. If the popup is in a <menu>, then also inform the
   1.433 +   * menu that the popup is being hidden.
   1.434 +   *
   1.435 +   * aHideChain - true if the entire chain of menus should be closed. If false,
   1.436 +   *              only this popup is closed.
   1.437 +   * aDeselectMenu - true if the parent <menu> of the popup should be deselected.
   1.438 +   *                 This will be false when the menu is closed by pressing the
   1.439 +   *                 Escape key.
   1.440 +   * aAsynchronous - true if the first popuphiding event should be sent
   1.441 +   *                 asynchrously. This should be true if HidePopup is called
   1.442 +   *                 from a frame.
   1.443 +   * aIsRollup - true if this popup is hiding due to a rollup or escape keypress.
   1.444 +   * aLastPopup - optional popup to close last when hiding a chain of menus.
   1.445 +   *              If null, then all popups will be closed.
   1.446 +   */
   1.447 +  void HidePopup(nsIContent* aPopup,
   1.448 +                 bool aHideChain,
   1.449 +                 bool aDeselectMenu,
   1.450 +                 bool aAsynchronous,
   1.451 +                 bool aIsRollup,
   1.452 +                 nsIContent* aLastPopup = nullptr);
   1.453 +
   1.454 +  /**
   1.455 +   * Hide the popup aFrame. This method is called by the view manager when the
   1.456 +   * close button is pressed.
   1.457 +   */
   1.458 +  void HidePopup(nsIFrame* aFrame);
   1.459 +
   1.460 +  /**
   1.461 +   * Hide a popup after a short delay. This is used when rolling over menu items.
   1.462 +   * This timer is stored in mCloseTimer. The timer may be cancelled and the popup
   1.463 +   * closed by calling KillMenuTimer.
   1.464 +   */
   1.465 +  void HidePopupAfterDelay(nsMenuPopupFrame* aPopup);
   1.466 +
   1.467 +  /**
   1.468 +   * Hide all of the popups from a given docshell. This should be called when the
   1.469 +   * document is hidden.
   1.470 +   */
   1.471 +  void HidePopupsInDocShell(nsIDocShellTreeItem* aDocShellToHide);
   1.472 +
   1.473 +  /**
   1.474 +   * Execute a menu command from the triggering event aEvent.
   1.475 +   *
   1.476 +   * aMenu - a menuitem to execute
   1.477 +   * aEvent - an nsXULMenuCommandEvent that contains all the info from the mouse
   1.478 +   *          event which triggered the menu to be executed, may not be null
   1.479 +   */
   1.480 +  void ExecuteMenu(nsIContent* aMenu, nsXULMenuCommandEvent* aEvent);
   1.481 +
   1.482 +  /**
   1.483 +   * Return true if the popup for the supplied content node is open.
   1.484 +   */
   1.485 +  bool IsPopupOpen(nsIContent* aPopup);
   1.486 +
   1.487 +  /**
   1.488 +   * Return true if the popup for the supplied menu parent is open.
   1.489 +   */
   1.490 +  bool IsPopupOpenForMenuParent(nsMenuParent* aMenuParent);
   1.491 +
   1.492 +  /**
   1.493 +   * Return the frame for the topmost open popup of a given type, or null if
   1.494 +   * no popup of that type is open. If aType is ePopupTypeAny, a menu of any
   1.495 +   * type is returned, except for popups in the mNoHidePanels list.
   1.496 +   */
   1.497 +  nsIFrame* GetTopPopup(nsPopupType aType);
   1.498 +
   1.499 +  /**
   1.500 +   * Return an array of all the open and visible popup frames for
   1.501 +   * menus, in order from top to bottom.
   1.502 +   */
   1.503 +  void GetVisiblePopups(nsTArray<nsIFrame *>& aPopups);
   1.504 +
   1.505 +  /**
   1.506 +   * Get the node that last triggered a popup or tooltip in the document
   1.507 +   * aDocument. aDocument must be non-null and be a document contained within
   1.508 +   * the same window hierarchy as the popup to retrieve.
   1.509 +   */
   1.510 +  already_AddRefed<nsIDOMNode> GetLastTriggerPopupNode(nsIDocument* aDocument)
   1.511 +  {
   1.512 +    return GetLastTriggerNode(aDocument, false);
   1.513 +  }
   1.514 +
   1.515 +  already_AddRefed<nsIDOMNode> GetLastTriggerTooltipNode(nsIDocument* aDocument)
   1.516 +  {
   1.517 +    return GetLastTriggerNode(aDocument, true);
   1.518 +  }
   1.519 +
   1.520 +  /**
   1.521 +   * Return false if a popup may not be opened. This will return false if the
   1.522 +   * popup is already open, if the popup is in a content shell that is not
   1.523 +   * focused, or if it is a submenu of another menu that isn't open.
   1.524 +   */
   1.525 +  bool MayShowPopup(nsMenuPopupFrame* aFrame);
   1.526 +
   1.527 +  /**
   1.528 +   * Indicate that the popup associated with aView has been moved to the
   1.529 +   * specified screen coordiates.
   1.530 +   */
   1.531 +  void PopupMoved(nsIFrame* aFrame, nsIntPoint aPoint);
   1.532 +
   1.533 +  /**
   1.534 +   * Indicate that the popup associated with aView has been resized to the
   1.535 +   * specified screen width and height.
   1.536 +   */
   1.537 +  void PopupResized(nsIFrame* aFrame, nsIntSize ASize);
   1.538 +
   1.539 +  /**
   1.540 +   * Called when a popup frame is destroyed. In this case, just remove the
   1.541 +   * item and later popups from the list. No point going through HidePopup as
   1.542 +   * the frames have gone away.
   1.543 +   */
   1.544 +  void PopupDestroyed(nsMenuPopupFrame* aFrame);
   1.545 +
   1.546 +  /**
   1.547 +   * Returns true if there is a context menu open. If aPopup is specified,
   1.548 +   * then the context menu must be later in the chain than aPopup. If aPopup
   1.549 +   * is null, returns true if any context menu at all is open.
   1.550 +   */
   1.551 +  bool HasContextMenu(nsMenuPopupFrame* aPopup);
   1.552 +
   1.553 +  /**
   1.554 +   * Update the commands for the menus within the menu popup for a given
   1.555 +   * content node. aPopup should be a XUL menupopup element. This method
   1.556 +   * changes attributes on the children of aPopup, and deals only with the
   1.557 +   * content of the popup, not the frames.
   1.558 +   */
   1.559 +  void UpdateMenuItems(nsIContent* aPopup);
   1.560 +
   1.561 +  /**
   1.562 +   * Stop the timer which hides a popup after a delay, started by a previous
   1.563 +   * call to HidePopupAfterDelay. In addition, the popup awaiting to be hidden
   1.564 +   * is closed asynchronously.
   1.565 +   */
   1.566 +  void KillMenuTimer();
   1.567 +
   1.568 +  /**
   1.569 +   * Cancel the timer which closes menus after delay, but only if the menu to
   1.570 +   * close is aMenuParent. When a submenu is opened, the user might move the
   1.571 +   * mouse over a sibling menuitem which would normally close the menu. This
   1.572 +   * menu is closed via a timer. However, if the user moves the mouse over the
   1.573 +   * submenu before the timer fires, we should instead cancel the timer. This
   1.574 +   * ensures that the user can move the mouse diagonally over a menu.
   1.575 +   */
   1.576 +  void CancelMenuTimer(nsMenuParent* aMenuParent);
   1.577 +
   1.578 +  /**
   1.579 +   * Handles navigation for menu accelkeys. Returns true if the key has
   1.580 +   * been handled. If aFrame is specified, then the key is handled by that
   1.581 +   * popup, otherwise if aFrame is null, the key is handled by the active
   1.582 +   * popup or menubar.
   1.583 +   */
   1.584 +  bool HandleShortcutNavigation(nsIDOMKeyEvent* aKeyEvent,
   1.585 +                                  nsMenuPopupFrame* aFrame);
   1.586 +
   1.587 +  /**
   1.588 +   * Handles cursor navigation within a menu. Returns true if the key has
   1.589 +   * been handled.
   1.590 +   */
   1.591 +  bool HandleKeyboardNavigation(uint32_t aKeyCode);
   1.592 +
   1.593 +  /**
   1.594 +   * Handle keyboard navigation within a menu popup specified by aFrame.
   1.595 +   * Returns true if the key was handled and other default handling
   1.596 +   * should not occur.
   1.597 +   */
   1.598 +  bool HandleKeyboardNavigationInPopup(nsMenuPopupFrame* aFrame,
   1.599 +                                         nsNavigationDirection aDir)
   1.600 +  {
   1.601 +    return HandleKeyboardNavigationInPopup(nullptr, aFrame, aDir);
   1.602 +  }
   1.603 +
   1.604 +  /**
   1.605 +   * Handles the keyboard event with keyCode value. Returns true if the event
   1.606 +   * has been handled.
   1.607 +   */
   1.608 +  bool HandleKeyboardEventWithKeyCode(nsIDOMKeyEvent* aKeyEvent,
   1.609 +                                      nsMenuChainItem* aTopVisibleMenuItem);
   1.610 +
   1.611 +  nsresult KeyUp(nsIDOMKeyEvent* aKeyEvent);
   1.612 +  nsresult KeyDown(nsIDOMKeyEvent* aKeyEvent);
   1.613 +  nsresult KeyPress(nsIDOMKeyEvent* aKeyEvent);
   1.614 +
   1.615 +protected:
   1.616 +  nsXULPopupManager();
   1.617 +  ~nsXULPopupManager();
   1.618 +
   1.619 +  // get the nsMenuPopupFrame, if any, for the given content node
   1.620 +  nsMenuPopupFrame* GetPopupFrameForContent(nsIContent* aContent, bool aShouldFlush);
   1.621 +
   1.622 +  // return the topmost menu, skipping over invisible popups
   1.623 +  nsMenuChainItem* GetTopVisibleMenu();
   1.624 +
   1.625 +  // Hide all of the visible popups from the given list. aDeselectMenu
   1.626 +  // indicates whether to deselect the menu of popups when hiding; this
   1.627 +  // flag is passed as the first argument to HidePopup. This function
   1.628 +  // can cause style changes and frame destruction.
   1.629 +  void HidePopupsInList(const nsTArray<nsMenuPopupFrame *> &aFrames,
   1.630 +                        bool aDeselectMenu);
   1.631 +
   1.632 +  // set the event that was used to trigger the popup, or null to clear the
   1.633 +  // event details. aTriggerContent will be set to the target of the event.
   1.634 +  void InitTriggerEvent(nsIDOMEvent* aEvent, nsIContent* aPopup, nsIContent** aTriggerContent);
   1.635 +
   1.636 +  // callbacks for ShowPopup and HidePopup as events may be done asynchronously
   1.637 +  void ShowPopupCallback(nsIContent* aPopup,
   1.638 +                         nsMenuPopupFrame* aPopupFrame,
   1.639 +                         bool aIsContextMenu,
   1.640 +                         bool aSelectFirstItem);
   1.641 +  void HidePopupCallback(nsIContent* aPopup,
   1.642 +                         nsMenuPopupFrame* aPopupFrame,
   1.643 +                         nsIContent* aNextPopup,
   1.644 +                         nsIContent* aLastPopup,
   1.645 +                         nsPopupType aPopupType,
   1.646 +                         bool aDeselectMenu);
   1.647 +
   1.648 +  /**
   1.649 +   * Fire a popupshowing event on the popup and then open the popup.
   1.650 +   *
   1.651 +   * aPopup - the popup to open
   1.652 +   * aIsContextMenu - true for context menus
   1.653 +   * aSelectFirstItem - true to select the first item in the menu
   1.654 +   */
   1.655 +  void FirePopupShowingEvent(nsIContent* aPopup,
   1.656 +                             bool aIsContextMenu,
   1.657 +                             bool aSelectFirstItem);
   1.658 +
   1.659 +  /**
   1.660 +   * Fire a popuphiding event and then hide the popup. This will be called
   1.661 +   * recursively if aNextPopup and aLastPopup are set in order to hide a chain
   1.662 +   * of open menus. If these are not set, only one popup is closed. However,
   1.663 +   * if the popup type indicates a menu, yet the next popup is not a menu,
   1.664 +   * then this ends the closing of popups. This allows a menulist inside a
   1.665 +   * non-menu to close up the menu but not close up the panel it is contained
   1.666 +   * within.
   1.667 +   *
   1.668 +   * The caller must keep a strong reference to aPopup, aNextPopup and aLastPopup.
   1.669 +   *
   1.670 +   * aPopup - the popup to hide
   1.671 +   * aNextPopup - the next popup to hide
   1.672 +   * aLastPopup - the last popup in the chain to hide
   1.673 +   * aPresContext - nsPresContext for the popup's frame
   1.674 +   * aPopupType - the PopupType of the frame. 
   1.675 +   * aDeselectMenu - true to unhighlight the menu when hiding it
   1.676 +   * aIsRollup - true if this popup is hiding due to a rollup or escape keypress
   1.677 +   */
   1.678 +  void FirePopupHidingEvent(nsIContent* aPopup,
   1.679 +                            nsIContent* aNextPopup,
   1.680 +                            nsIContent* aLastPopup,
   1.681 +                            nsPresContext *aPresContext,
   1.682 +                            nsPopupType aPopupType,
   1.683 +                            bool aDeselectMenu,
   1.684 +                            bool aIsRollup);
   1.685 +
   1.686 +  /**
   1.687 +   * Handle keyboard navigation within a menu popup specified by aItem.
   1.688 +   */
   1.689 +  bool HandleKeyboardNavigationInPopup(nsMenuChainItem* aItem,
   1.690 +                                         nsNavigationDirection aDir)
   1.691 +  {
   1.692 +    return HandleKeyboardNavigationInPopup(aItem, aItem->Frame(), aDir);
   1.693 +  }
   1.694 +
   1.695 +private:
   1.696 +  /**
   1.697 +   * Handle keyboard navigation within a menu popup aFrame. If aItem is
   1.698 +   * supplied, then it is expected to have a frame equal to aFrame.
   1.699 +   * If aItem is non-null, then the navigation may be redirected to
   1.700 +   * an open submenu if one exists. Returns true if the key was
   1.701 +   * handled and other default handling should not occur.
   1.702 +   */
   1.703 +  bool HandleKeyboardNavigationInPopup(nsMenuChainItem* aItem,
   1.704 +                                         nsMenuPopupFrame* aFrame,
   1.705 +                                         nsNavigationDirection aDir);
   1.706 +
   1.707 +protected:
   1.708 +
   1.709 +  already_AddRefed<nsIDOMNode> GetLastTriggerNode(nsIDocument* aDocument, bool aIsTooltip);
   1.710 +
   1.711 +  /**
   1.712 +   * Set mouse capturing for the current popup. This traps mouse clicks that
   1.713 +   * occur outside the popup so that it can be closed up. aOldPopup should be
   1.714 +   * set to the popup that was previously the current popup.
   1.715 +   */
   1.716 +  void SetCaptureState(nsIContent *aOldPopup);
   1.717 +
   1.718 +  /**
   1.719 +   * Key event listeners are attached to the document containing the current
   1.720 +   * menu for menu and shortcut navigation. Only one listener is needed at a
   1.721 +   * time, stored in mKeyListener, so switch it only if the document changes.
   1.722 +   * Having menus in different documents is very rare, so the listeners will
   1.723 +   * usually only be attached when the first menu opens and removed when all
   1.724 +   * menus have closed.
   1.725 +   *
   1.726 +   * This is also used when only a menubar is active without any open menus,
   1.727 +   * so that keyboard navigation between menus on the menubar may be done.
   1.728 +   */
   1.729 +  void UpdateKeyboardListeners();
   1.730 +
   1.731 +  /*
   1.732 +   * Returns true if the docshell for aDoc is aExpected or a child of aExpected.
   1.733 +   */
   1.734 +  bool IsChildOfDocShell(nsIDocument* aDoc, nsIDocShellTreeItem* aExpected);
   1.735 +
   1.736 +  // the document the key event listener is attached to
   1.737 +  nsCOMPtr<mozilla::dom::EventTarget> mKeyListener;
   1.738 +
   1.739 +  // widget that is currently listening to rollup events
   1.740 +  nsCOMPtr<nsIWidget> mWidget;
   1.741 +
   1.742 +  // range parent and offset set in SetTriggerEvent
   1.743 +  nsCOMPtr<nsIDOMNode> mRangeParent;
   1.744 +  int32_t mRangeOffset;
   1.745 +  // Device pixels relative to the showing popup's presshell's
   1.746 +  // root prescontext's root frame.
   1.747 +  nsIntPoint mCachedMousePoint;
   1.748 +
   1.749 +  // cached modifiers
   1.750 +  mozilla::Modifiers mCachedModifiers;
   1.751 +
   1.752 +  // set to the currently active menu bar, if any
   1.753 +  nsMenuBarFrame* mActiveMenuBar;
   1.754 +
   1.755 +  // linked list of normal menus and panels.
   1.756 +  nsMenuChainItem* mPopups;
   1.757 +
   1.758 +  // linked list of noautohide panels and tooltips.
   1.759 +  nsMenuChainItem* mNoHidePanels;
   1.760 +
   1.761 +  // timer used for HidePopupAfterDelay
   1.762 +  nsCOMPtr<nsITimer> mCloseTimer;
   1.763 +
   1.764 +  // a popup that is waiting on the timer
   1.765 +  nsMenuPopupFrame* mTimerMenu;
   1.766 +
   1.767 +  // the popup that is currently being opened, stored only during the
   1.768 +  // popupshowing event
   1.769 +  nsCOMPtr<nsIContent> mOpeningPopup;
   1.770 +};
   1.771 +
   1.772 +#endif

mercurial