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