1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/layout/xul/nsMenuFrame.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,286 @@ 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 +// nsMenuFrame 1.11 +// 1.12 + 1.13 +#ifndef nsMenuFrame_h__ 1.14 +#define nsMenuFrame_h__ 1.15 + 1.16 +#include "nsIAtom.h" 1.17 +#include "nsCOMPtr.h" 1.18 + 1.19 +#include "nsBoxFrame.h" 1.20 +#include "nsFrameList.h" 1.21 +#include "nsGkAtoms.h" 1.22 +#include "nsMenuParent.h" 1.23 +#include "nsXULPopupManager.h" 1.24 +#include "nsITimer.h" 1.25 +#include "mozilla/Attributes.h" 1.26 + 1.27 +nsIFrame* NS_NewMenuFrame(nsIPresShell* aPresShell, nsStyleContext* aContext); 1.28 +nsIFrame* NS_NewMenuItemFrame(nsIPresShell* aPresShell, nsStyleContext* aContext); 1.29 + 1.30 +class nsIContent; 1.31 +class nsMenuBarFrame; 1.32 + 1.33 +#define NS_STATE_ACCELTEXT_IS_DERIVED NS_STATE_BOX_CHILD_RESERVED 1.34 + 1.35 +// the type of menuitem 1.36 +enum nsMenuType { 1.37 + // a normal menuitem where a command is carried out when activated 1.38 + eMenuType_Normal = 0, 1.39 + // a menuitem with a checkmark that toggles when activated 1.40 + eMenuType_Checkbox = 1, 1.41 + // a radio menuitem where only one of it and its siblings with the same 1.42 + // name attribute can be checked at a time 1.43 + eMenuType_Radio = 2 1.44 +}; 1.45 + 1.46 +enum nsMenuListType { 1.47 + eNotMenuList, // not a menulist 1.48 + eReadonlyMenuList, // <menulist/> 1.49 + eEditableMenuList // <menulist editable="true"/> 1.50 +}; 1.51 + 1.52 +class nsMenuFrame; 1.53 + 1.54 +/** 1.55 + * nsMenuTimerMediator is a wrapper around an nsMenuFrame which can be safely 1.56 + * passed to timers. The class is reference counted unlike the underlying 1.57 + * nsMenuFrame, so that it will exist as long as the timer holds a reference 1.58 + * to it. The callback is delegated to the contained nsMenuFrame as long as 1.59 + * the contained nsMenuFrame has not been destroyed. 1.60 + */ 1.61 +class nsMenuTimerMediator MOZ_FINAL : public nsITimerCallback 1.62 +{ 1.63 +public: 1.64 + nsMenuTimerMediator(nsMenuFrame* aFrame); 1.65 + ~nsMenuTimerMediator(); 1.66 + 1.67 + NS_DECL_ISUPPORTS 1.68 + NS_DECL_NSITIMERCALLBACK 1.69 + 1.70 + void ClearFrame(); 1.71 + 1.72 +private: 1.73 + 1.74 + // Pointer to the wrapped frame. 1.75 + nsMenuFrame* mFrame; 1.76 +}; 1.77 + 1.78 +class nsMenuFrame : public nsBoxFrame 1.79 +{ 1.80 +public: 1.81 + nsMenuFrame(nsIPresShell* aShell, nsStyleContext* aContext); 1.82 + 1.83 + NS_DECL_QUERYFRAME_TARGET(nsMenuFrame) 1.84 + NS_DECL_QUERYFRAME 1.85 + NS_DECL_FRAMEARENA_HELPERS 1.86 + 1.87 + NS_IMETHOD DoLayout(nsBoxLayoutState& aBoxLayoutState) MOZ_OVERRIDE; 1.88 + virtual nsSize GetMinSize(nsBoxLayoutState& aBoxLayoutState) MOZ_OVERRIDE; 1.89 + virtual nsSize GetPrefSize(nsBoxLayoutState& aBoxLayoutState) MOZ_OVERRIDE; 1.90 + 1.91 + virtual void Init(nsIContent* aContent, 1.92 + nsIFrame* aParent, 1.93 + nsIFrame* aPrevInFlow) MOZ_OVERRIDE; 1.94 + 1.95 +#ifdef DEBUG_LAYOUT 1.96 + virtual nsresult SetDebug(nsBoxLayoutState& aState, bool aDebug) MOZ_OVERRIDE; 1.97 +#endif 1.98 + 1.99 + // The following methods are all overridden so that the menupopup 1.100 + // can be stored in a separate list, so that it doesn't impact reflow of the 1.101 + // actual menu item at all. 1.102 + virtual const nsFrameList& GetChildList(ChildListID aList) const MOZ_OVERRIDE; 1.103 + virtual void GetChildLists(nsTArray<ChildList>* aLists) const MOZ_OVERRIDE; 1.104 + virtual nsresult SetInitialChildList(ChildListID aListID, 1.105 + nsFrameList& aChildList) MOZ_OVERRIDE; 1.106 + virtual void DestroyFrom(nsIFrame* aDestructRoot) MOZ_OVERRIDE; 1.107 + 1.108 + // Overridden to prevent events from going to children of the menu. 1.109 + virtual void BuildDisplayListForChildren(nsDisplayListBuilder* aBuilder, 1.110 + const nsRect& aDirtyRect, 1.111 + const nsDisplayListSet& aLists) MOZ_OVERRIDE; 1.112 + 1.113 + // this method can destroy the frame 1.114 + virtual nsresult HandleEvent(nsPresContext* aPresContext, 1.115 + mozilla::WidgetGUIEvent* aEvent, 1.116 + nsEventStatus* aEventStatus) MOZ_OVERRIDE; 1.117 + 1.118 + virtual nsresult AppendFrames(ChildListID aListID, 1.119 + nsFrameList& aFrameList) MOZ_OVERRIDE; 1.120 + 1.121 + virtual nsresult InsertFrames(ChildListID aListID, 1.122 + nsIFrame* aPrevFrame, 1.123 + nsFrameList& aFrameList) MOZ_OVERRIDE; 1.124 + 1.125 + virtual nsresult RemoveFrame(ChildListID aListID, 1.126 + nsIFrame* aOldFrame) MOZ_OVERRIDE; 1.127 + 1.128 + virtual nsIAtom* GetType() const MOZ_OVERRIDE { return nsGkAtoms::menuFrame; } 1.129 + 1.130 + NS_IMETHOD SelectMenu(bool aActivateFlag); 1.131 + 1.132 + virtual nsIScrollableFrame* GetScrollTargetFrame() MOZ_OVERRIDE; 1.133 + 1.134 + // Retrieve the element that the menu should be anchored to. By default this is 1.135 + // the menu itself. However, the anchor attribute may refer to the value of an 1.136 + // anonid within the menu's binding, or, if not found, the id of an element in 1.137 + // the document. 1.138 + nsIContent* GetAnchor(); 1.139 + 1.140 + /** 1.141 + * NOTE: OpenMenu will open the menu asynchronously. 1.142 + */ 1.143 + void OpenMenu(bool aSelectFirstItem); 1.144 + // CloseMenu closes the menu asynchronously 1.145 + void CloseMenu(bool aDeselectMenu); 1.146 + 1.147 + bool IsChecked() { return mChecked; } 1.148 + 1.149 + NS_IMETHOD GetActiveChild(nsIDOMElement** aResult); 1.150 + NS_IMETHOD SetActiveChild(nsIDOMElement* aChild); 1.151 + 1.152 + // called when the Enter key is pressed while the menuitem is the current 1.153 + // one in its parent popup. This will carry out the command attached to 1.154 + // the menuitem. If the menu should be opened, this frame will be returned, 1.155 + // otherwise null will be returned. 1.156 + nsMenuFrame* Enter(mozilla::WidgetGUIEvent* aEvent); 1.157 + 1.158 + virtual void SetParent(nsIFrame* aParent) MOZ_OVERRIDE; 1.159 + 1.160 + virtual nsMenuParent *GetMenuParent() { return mMenuParent; } 1.161 + const nsAString& GetRadioGroupName() { return mGroupName; } 1.162 + nsMenuType GetMenuType() { return mType; } 1.163 + nsMenuPopupFrame* GetPopup(); 1.164 + 1.165 + /** 1.166 + * @return true if this frame has a popup child frame. 1.167 + */ 1.168 + bool HasPopup() const 1.169 + { 1.170 + return (GetStateBits() & NS_STATE_MENU_HAS_POPUP_LIST) != 0; 1.171 + } 1.172 + 1.173 + 1.174 + // nsMenuFrame methods 1.175 + 1.176 + bool IsOnMenuBar() { return mMenuParent && mMenuParent->IsMenuBar(); } 1.177 + bool IsOnActiveMenuBar() { return IsOnMenuBar() && mMenuParent->IsActive(); } 1.178 + virtual bool IsOpen(); 1.179 + virtual bool IsMenu(); 1.180 + nsMenuListType GetParentMenuListType(); 1.181 + bool IsDisabled(); 1.182 + void ToggleMenuState(); 1.183 + 1.184 + // indiciate that the menu's popup has just been opened, so that the menu 1.185 + // can update its open state. This method modifies the open attribute on 1.186 + // the menu, so the frames could be gone after this call. 1.187 + void PopupOpened(); 1.188 + // indiciate that the menu's popup has just been closed, so that the menu 1.189 + // can update its open state. The menu should be unhighlighted if 1.190 + // aDeselectedMenu is true. This method modifies the open attribute on 1.191 + // the menu, so the frames could be gone after this call. 1.192 + void PopupClosed(bool aDeselectMenu); 1.193 + 1.194 + // returns true if this is a menu on another menu popup. A menu is a submenu 1.195 + // if it has a parent popup or menupopup. 1.196 + bool IsOnMenu() { return mMenuParent && mMenuParent->IsMenu(); } 1.197 + void SetIsMenu(bool aIsMenu) { mIsMenu = aIsMenu; } 1.198 + 1.199 +#ifdef DEBUG_FRAME_DUMP 1.200 + virtual nsresult GetFrameName(nsAString& aResult) const MOZ_OVERRIDE 1.201 + { 1.202 + return MakeFrameName(NS_LITERAL_STRING("Menu"), aResult); 1.203 + } 1.204 +#endif 1.205 + 1.206 + static bool IsSizedToPopup(nsIContent* aContent, bool aRequireAlways); 1.207 + 1.208 +protected: 1.209 + friend class nsMenuTimerMediator; 1.210 + friend class nsASyncMenuInitialization; 1.211 + friend class nsMenuAttributeChangedEvent; 1.212 + 1.213 + /** 1.214 + * Initialize the popup list to the first popup frame within 1.215 + * aChildList. Removes the popup, if any, from aChildList. 1.216 + */ 1.217 + void SetPopupFrame(nsFrameList& aChildList); 1.218 + 1.219 + /** 1.220 + * Get the popup frame list from the frame property. 1.221 + * @return the property value if it exists, nullptr otherwise. 1.222 + */ 1.223 + nsFrameList* GetPopupList() const; 1.224 + 1.225 + /** 1.226 + * Destroy the popup list property. The list must exist and be empty. 1.227 + */ 1.228 + void DestroyPopupList(); 1.229 + 1.230 + // set mMenuParent to the nearest enclosing menu bar or menupopup frame of 1.231 + // aParent (or aParent itself). This is called when initializing the frame, 1.232 + // so aParent should be the expected parent of this frame. 1.233 + void InitMenuParent(nsIFrame* aParent); 1.234 + 1.235 + // Update the menu's type (normal, checkbox, radio). 1.236 + // This method can destroy the frame. 1.237 + void UpdateMenuType(nsPresContext* aPresContext); 1.238 + // Update the checked state of the menu, and for radios, clear any other 1.239 + // checked items. This method can destroy the frame. 1.240 + void UpdateMenuSpecialState(nsPresContext* aPresContext); 1.241 + 1.242 + // Examines the key node and builds the accelerator. 1.243 + void BuildAcceleratorText(bool aNotify); 1.244 + 1.245 + // Called to execute our command handler. This method can destroy the frame. 1.246 + void Execute(mozilla::WidgetGUIEvent *aEvent); 1.247 + 1.248 + // This method can destroy the frame 1.249 + virtual nsresult AttributeChanged(int32_t aNameSpaceID, 1.250 + nsIAtom* aAttribute, 1.251 + int32_t aModType) MOZ_OVERRIDE; 1.252 + virtual ~nsMenuFrame() { } 1.253 + 1.254 + bool SizeToPopup(nsBoxLayoutState& aState, nsSize& aSize); 1.255 + 1.256 + bool ShouldBlink(); 1.257 + void StartBlinking(mozilla::WidgetGUIEvent* aEvent, bool aFlipChecked); 1.258 + void StopBlinking(); 1.259 + void CreateMenuCommandEvent(mozilla::WidgetGUIEvent* aEvent, 1.260 + bool aFlipChecked); 1.261 + void PassMenuCommandEventToPopupManager(); 1.262 + 1.263 +protected: 1.264 +#ifdef DEBUG_LAYOUT 1.265 + nsresult SetDebug(nsBoxLayoutState& aState, nsIFrame* aList, bool aDebug); 1.266 +#endif 1.267 + NS_HIDDEN_(nsresult) Notify(nsITimer* aTimer); 1.268 + 1.269 + bool mIsMenu; // Whether or not we can even have children or not. 1.270 + bool mChecked; // are we checked? 1.271 + bool mIgnoreAccelTextChange; // temporarily set while determining the accelerator key 1.272 + nsMenuType mType; 1.273 + 1.274 + nsMenuParent* mMenuParent; // Our parent menu. 1.275 + 1.276 + // Reference to the mediator which wraps this frame. 1.277 + nsRefPtr<nsMenuTimerMediator> mTimerMediator; 1.278 + 1.279 + nsCOMPtr<nsITimer> mOpenTimer; 1.280 + nsCOMPtr<nsITimer> mBlinkTimer; 1.281 + 1.282 + uint8_t mBlinkState; // 0: not blinking, 1: off, 2: on 1.283 + nsRefPtr<nsXULMenuCommandEvent> mDelayedMenuCommandEvent; 1.284 + 1.285 + nsString mGroupName; 1.286 + 1.287 +}; // class nsMenuFrame 1.288 + 1.289 +#endif