Wed, 31 Dec 2014 07:16:47 +0100
Revert simplistic fix pending revisit of Mozilla integration attempt.
michael@0 | 1 | /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
michael@0 | 2 | /* This Source Code Form is subject to the terms of the Mozilla Public |
michael@0 | 3 | * License, v. 2.0. If a copy of the MPL was not distributed with this |
michael@0 | 4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
michael@0 | 5 | |
michael@0 | 6 | // |
michael@0 | 7 | // nsMenuFrame |
michael@0 | 8 | // |
michael@0 | 9 | |
michael@0 | 10 | #ifndef nsMenuFrame_h__ |
michael@0 | 11 | #define nsMenuFrame_h__ |
michael@0 | 12 | |
michael@0 | 13 | #include "nsIAtom.h" |
michael@0 | 14 | #include "nsCOMPtr.h" |
michael@0 | 15 | |
michael@0 | 16 | #include "nsBoxFrame.h" |
michael@0 | 17 | #include "nsFrameList.h" |
michael@0 | 18 | #include "nsGkAtoms.h" |
michael@0 | 19 | #include "nsMenuParent.h" |
michael@0 | 20 | #include "nsXULPopupManager.h" |
michael@0 | 21 | #include "nsITimer.h" |
michael@0 | 22 | #include "mozilla/Attributes.h" |
michael@0 | 23 | |
michael@0 | 24 | nsIFrame* NS_NewMenuFrame(nsIPresShell* aPresShell, nsStyleContext* aContext); |
michael@0 | 25 | nsIFrame* NS_NewMenuItemFrame(nsIPresShell* aPresShell, nsStyleContext* aContext); |
michael@0 | 26 | |
michael@0 | 27 | class nsIContent; |
michael@0 | 28 | class nsMenuBarFrame; |
michael@0 | 29 | |
michael@0 | 30 | #define NS_STATE_ACCELTEXT_IS_DERIVED NS_STATE_BOX_CHILD_RESERVED |
michael@0 | 31 | |
michael@0 | 32 | // the type of menuitem |
michael@0 | 33 | enum nsMenuType { |
michael@0 | 34 | // a normal menuitem where a command is carried out when activated |
michael@0 | 35 | eMenuType_Normal = 0, |
michael@0 | 36 | // a menuitem with a checkmark that toggles when activated |
michael@0 | 37 | eMenuType_Checkbox = 1, |
michael@0 | 38 | // a radio menuitem where only one of it and its siblings with the same |
michael@0 | 39 | // name attribute can be checked at a time |
michael@0 | 40 | eMenuType_Radio = 2 |
michael@0 | 41 | }; |
michael@0 | 42 | |
michael@0 | 43 | enum nsMenuListType { |
michael@0 | 44 | eNotMenuList, // not a menulist |
michael@0 | 45 | eReadonlyMenuList, // <menulist/> |
michael@0 | 46 | eEditableMenuList // <menulist editable="true"/> |
michael@0 | 47 | }; |
michael@0 | 48 | |
michael@0 | 49 | class nsMenuFrame; |
michael@0 | 50 | |
michael@0 | 51 | /** |
michael@0 | 52 | * nsMenuTimerMediator is a wrapper around an nsMenuFrame which can be safely |
michael@0 | 53 | * passed to timers. The class is reference counted unlike the underlying |
michael@0 | 54 | * nsMenuFrame, so that it will exist as long as the timer holds a reference |
michael@0 | 55 | * to it. The callback is delegated to the contained nsMenuFrame as long as |
michael@0 | 56 | * the contained nsMenuFrame has not been destroyed. |
michael@0 | 57 | */ |
michael@0 | 58 | class nsMenuTimerMediator MOZ_FINAL : public nsITimerCallback |
michael@0 | 59 | { |
michael@0 | 60 | public: |
michael@0 | 61 | nsMenuTimerMediator(nsMenuFrame* aFrame); |
michael@0 | 62 | ~nsMenuTimerMediator(); |
michael@0 | 63 | |
michael@0 | 64 | NS_DECL_ISUPPORTS |
michael@0 | 65 | NS_DECL_NSITIMERCALLBACK |
michael@0 | 66 | |
michael@0 | 67 | void ClearFrame(); |
michael@0 | 68 | |
michael@0 | 69 | private: |
michael@0 | 70 | |
michael@0 | 71 | // Pointer to the wrapped frame. |
michael@0 | 72 | nsMenuFrame* mFrame; |
michael@0 | 73 | }; |
michael@0 | 74 | |
michael@0 | 75 | class nsMenuFrame : public nsBoxFrame |
michael@0 | 76 | { |
michael@0 | 77 | public: |
michael@0 | 78 | nsMenuFrame(nsIPresShell* aShell, nsStyleContext* aContext); |
michael@0 | 79 | |
michael@0 | 80 | NS_DECL_QUERYFRAME_TARGET(nsMenuFrame) |
michael@0 | 81 | NS_DECL_QUERYFRAME |
michael@0 | 82 | NS_DECL_FRAMEARENA_HELPERS |
michael@0 | 83 | |
michael@0 | 84 | NS_IMETHOD DoLayout(nsBoxLayoutState& aBoxLayoutState) MOZ_OVERRIDE; |
michael@0 | 85 | virtual nsSize GetMinSize(nsBoxLayoutState& aBoxLayoutState) MOZ_OVERRIDE; |
michael@0 | 86 | virtual nsSize GetPrefSize(nsBoxLayoutState& aBoxLayoutState) MOZ_OVERRIDE; |
michael@0 | 87 | |
michael@0 | 88 | virtual void Init(nsIContent* aContent, |
michael@0 | 89 | nsIFrame* aParent, |
michael@0 | 90 | nsIFrame* aPrevInFlow) MOZ_OVERRIDE; |
michael@0 | 91 | |
michael@0 | 92 | #ifdef DEBUG_LAYOUT |
michael@0 | 93 | virtual nsresult SetDebug(nsBoxLayoutState& aState, bool aDebug) MOZ_OVERRIDE; |
michael@0 | 94 | #endif |
michael@0 | 95 | |
michael@0 | 96 | // The following methods are all overridden so that the menupopup |
michael@0 | 97 | // can be stored in a separate list, so that it doesn't impact reflow of the |
michael@0 | 98 | // actual menu item at all. |
michael@0 | 99 | virtual const nsFrameList& GetChildList(ChildListID aList) const MOZ_OVERRIDE; |
michael@0 | 100 | virtual void GetChildLists(nsTArray<ChildList>* aLists) const MOZ_OVERRIDE; |
michael@0 | 101 | virtual nsresult SetInitialChildList(ChildListID aListID, |
michael@0 | 102 | nsFrameList& aChildList) MOZ_OVERRIDE; |
michael@0 | 103 | virtual void DestroyFrom(nsIFrame* aDestructRoot) MOZ_OVERRIDE; |
michael@0 | 104 | |
michael@0 | 105 | // Overridden to prevent events from going to children of the menu. |
michael@0 | 106 | virtual void BuildDisplayListForChildren(nsDisplayListBuilder* aBuilder, |
michael@0 | 107 | const nsRect& aDirtyRect, |
michael@0 | 108 | const nsDisplayListSet& aLists) MOZ_OVERRIDE; |
michael@0 | 109 | |
michael@0 | 110 | // this method can destroy the frame |
michael@0 | 111 | virtual nsresult HandleEvent(nsPresContext* aPresContext, |
michael@0 | 112 | mozilla::WidgetGUIEvent* aEvent, |
michael@0 | 113 | nsEventStatus* aEventStatus) MOZ_OVERRIDE; |
michael@0 | 114 | |
michael@0 | 115 | virtual nsresult AppendFrames(ChildListID aListID, |
michael@0 | 116 | nsFrameList& aFrameList) MOZ_OVERRIDE; |
michael@0 | 117 | |
michael@0 | 118 | virtual nsresult InsertFrames(ChildListID aListID, |
michael@0 | 119 | nsIFrame* aPrevFrame, |
michael@0 | 120 | nsFrameList& aFrameList) MOZ_OVERRIDE; |
michael@0 | 121 | |
michael@0 | 122 | virtual nsresult RemoveFrame(ChildListID aListID, |
michael@0 | 123 | nsIFrame* aOldFrame) MOZ_OVERRIDE; |
michael@0 | 124 | |
michael@0 | 125 | virtual nsIAtom* GetType() const MOZ_OVERRIDE { return nsGkAtoms::menuFrame; } |
michael@0 | 126 | |
michael@0 | 127 | NS_IMETHOD SelectMenu(bool aActivateFlag); |
michael@0 | 128 | |
michael@0 | 129 | virtual nsIScrollableFrame* GetScrollTargetFrame() MOZ_OVERRIDE; |
michael@0 | 130 | |
michael@0 | 131 | // Retrieve the element that the menu should be anchored to. By default this is |
michael@0 | 132 | // the menu itself. However, the anchor attribute may refer to the value of an |
michael@0 | 133 | // anonid within the menu's binding, or, if not found, the id of an element in |
michael@0 | 134 | // the document. |
michael@0 | 135 | nsIContent* GetAnchor(); |
michael@0 | 136 | |
michael@0 | 137 | /** |
michael@0 | 138 | * NOTE: OpenMenu will open the menu asynchronously. |
michael@0 | 139 | */ |
michael@0 | 140 | void OpenMenu(bool aSelectFirstItem); |
michael@0 | 141 | // CloseMenu closes the menu asynchronously |
michael@0 | 142 | void CloseMenu(bool aDeselectMenu); |
michael@0 | 143 | |
michael@0 | 144 | bool IsChecked() { return mChecked; } |
michael@0 | 145 | |
michael@0 | 146 | NS_IMETHOD GetActiveChild(nsIDOMElement** aResult); |
michael@0 | 147 | NS_IMETHOD SetActiveChild(nsIDOMElement* aChild); |
michael@0 | 148 | |
michael@0 | 149 | // called when the Enter key is pressed while the menuitem is the current |
michael@0 | 150 | // one in its parent popup. This will carry out the command attached to |
michael@0 | 151 | // the menuitem. If the menu should be opened, this frame will be returned, |
michael@0 | 152 | // otherwise null will be returned. |
michael@0 | 153 | nsMenuFrame* Enter(mozilla::WidgetGUIEvent* aEvent); |
michael@0 | 154 | |
michael@0 | 155 | virtual void SetParent(nsIFrame* aParent) MOZ_OVERRIDE; |
michael@0 | 156 | |
michael@0 | 157 | virtual nsMenuParent *GetMenuParent() { return mMenuParent; } |
michael@0 | 158 | const nsAString& GetRadioGroupName() { return mGroupName; } |
michael@0 | 159 | nsMenuType GetMenuType() { return mType; } |
michael@0 | 160 | nsMenuPopupFrame* GetPopup(); |
michael@0 | 161 | |
michael@0 | 162 | /** |
michael@0 | 163 | * @return true if this frame has a popup child frame. |
michael@0 | 164 | */ |
michael@0 | 165 | bool HasPopup() const |
michael@0 | 166 | { |
michael@0 | 167 | return (GetStateBits() & NS_STATE_MENU_HAS_POPUP_LIST) != 0; |
michael@0 | 168 | } |
michael@0 | 169 | |
michael@0 | 170 | |
michael@0 | 171 | // nsMenuFrame methods |
michael@0 | 172 | |
michael@0 | 173 | bool IsOnMenuBar() { return mMenuParent && mMenuParent->IsMenuBar(); } |
michael@0 | 174 | bool IsOnActiveMenuBar() { return IsOnMenuBar() && mMenuParent->IsActive(); } |
michael@0 | 175 | virtual bool IsOpen(); |
michael@0 | 176 | virtual bool IsMenu(); |
michael@0 | 177 | nsMenuListType GetParentMenuListType(); |
michael@0 | 178 | bool IsDisabled(); |
michael@0 | 179 | void ToggleMenuState(); |
michael@0 | 180 | |
michael@0 | 181 | // indiciate that the menu's popup has just been opened, so that the menu |
michael@0 | 182 | // can update its open state. This method modifies the open attribute on |
michael@0 | 183 | // the menu, so the frames could be gone after this call. |
michael@0 | 184 | void PopupOpened(); |
michael@0 | 185 | // indiciate that the menu's popup has just been closed, so that the menu |
michael@0 | 186 | // can update its open state. The menu should be unhighlighted if |
michael@0 | 187 | // aDeselectedMenu is true. This method modifies the open attribute on |
michael@0 | 188 | // the menu, so the frames could be gone after this call. |
michael@0 | 189 | void PopupClosed(bool aDeselectMenu); |
michael@0 | 190 | |
michael@0 | 191 | // returns true if this is a menu on another menu popup. A menu is a submenu |
michael@0 | 192 | // if it has a parent popup or menupopup. |
michael@0 | 193 | bool IsOnMenu() { return mMenuParent && mMenuParent->IsMenu(); } |
michael@0 | 194 | void SetIsMenu(bool aIsMenu) { mIsMenu = aIsMenu; } |
michael@0 | 195 | |
michael@0 | 196 | #ifdef DEBUG_FRAME_DUMP |
michael@0 | 197 | virtual nsresult GetFrameName(nsAString& aResult) const MOZ_OVERRIDE |
michael@0 | 198 | { |
michael@0 | 199 | return MakeFrameName(NS_LITERAL_STRING("Menu"), aResult); |
michael@0 | 200 | } |
michael@0 | 201 | #endif |
michael@0 | 202 | |
michael@0 | 203 | static bool IsSizedToPopup(nsIContent* aContent, bool aRequireAlways); |
michael@0 | 204 | |
michael@0 | 205 | protected: |
michael@0 | 206 | friend class nsMenuTimerMediator; |
michael@0 | 207 | friend class nsASyncMenuInitialization; |
michael@0 | 208 | friend class nsMenuAttributeChangedEvent; |
michael@0 | 209 | |
michael@0 | 210 | /** |
michael@0 | 211 | * Initialize the popup list to the first popup frame within |
michael@0 | 212 | * aChildList. Removes the popup, if any, from aChildList. |
michael@0 | 213 | */ |
michael@0 | 214 | void SetPopupFrame(nsFrameList& aChildList); |
michael@0 | 215 | |
michael@0 | 216 | /** |
michael@0 | 217 | * Get the popup frame list from the frame property. |
michael@0 | 218 | * @return the property value if it exists, nullptr otherwise. |
michael@0 | 219 | */ |
michael@0 | 220 | nsFrameList* GetPopupList() const; |
michael@0 | 221 | |
michael@0 | 222 | /** |
michael@0 | 223 | * Destroy the popup list property. The list must exist and be empty. |
michael@0 | 224 | */ |
michael@0 | 225 | void DestroyPopupList(); |
michael@0 | 226 | |
michael@0 | 227 | // set mMenuParent to the nearest enclosing menu bar or menupopup frame of |
michael@0 | 228 | // aParent (or aParent itself). This is called when initializing the frame, |
michael@0 | 229 | // so aParent should be the expected parent of this frame. |
michael@0 | 230 | void InitMenuParent(nsIFrame* aParent); |
michael@0 | 231 | |
michael@0 | 232 | // Update the menu's type (normal, checkbox, radio). |
michael@0 | 233 | // This method can destroy the frame. |
michael@0 | 234 | void UpdateMenuType(nsPresContext* aPresContext); |
michael@0 | 235 | // Update the checked state of the menu, and for radios, clear any other |
michael@0 | 236 | // checked items. This method can destroy the frame. |
michael@0 | 237 | void UpdateMenuSpecialState(nsPresContext* aPresContext); |
michael@0 | 238 | |
michael@0 | 239 | // Examines the key node and builds the accelerator. |
michael@0 | 240 | void BuildAcceleratorText(bool aNotify); |
michael@0 | 241 | |
michael@0 | 242 | // Called to execute our command handler. This method can destroy the frame. |
michael@0 | 243 | void Execute(mozilla::WidgetGUIEvent *aEvent); |
michael@0 | 244 | |
michael@0 | 245 | // This method can destroy the frame |
michael@0 | 246 | virtual nsresult AttributeChanged(int32_t aNameSpaceID, |
michael@0 | 247 | nsIAtom* aAttribute, |
michael@0 | 248 | int32_t aModType) MOZ_OVERRIDE; |
michael@0 | 249 | virtual ~nsMenuFrame() { } |
michael@0 | 250 | |
michael@0 | 251 | bool SizeToPopup(nsBoxLayoutState& aState, nsSize& aSize); |
michael@0 | 252 | |
michael@0 | 253 | bool ShouldBlink(); |
michael@0 | 254 | void StartBlinking(mozilla::WidgetGUIEvent* aEvent, bool aFlipChecked); |
michael@0 | 255 | void StopBlinking(); |
michael@0 | 256 | void CreateMenuCommandEvent(mozilla::WidgetGUIEvent* aEvent, |
michael@0 | 257 | bool aFlipChecked); |
michael@0 | 258 | void PassMenuCommandEventToPopupManager(); |
michael@0 | 259 | |
michael@0 | 260 | protected: |
michael@0 | 261 | #ifdef DEBUG_LAYOUT |
michael@0 | 262 | nsresult SetDebug(nsBoxLayoutState& aState, nsIFrame* aList, bool aDebug); |
michael@0 | 263 | #endif |
michael@0 | 264 | NS_HIDDEN_(nsresult) Notify(nsITimer* aTimer); |
michael@0 | 265 | |
michael@0 | 266 | bool mIsMenu; // Whether or not we can even have children or not. |
michael@0 | 267 | bool mChecked; // are we checked? |
michael@0 | 268 | bool mIgnoreAccelTextChange; // temporarily set while determining the accelerator key |
michael@0 | 269 | nsMenuType mType; |
michael@0 | 270 | |
michael@0 | 271 | nsMenuParent* mMenuParent; // Our parent menu. |
michael@0 | 272 | |
michael@0 | 273 | // Reference to the mediator which wraps this frame. |
michael@0 | 274 | nsRefPtr<nsMenuTimerMediator> mTimerMediator; |
michael@0 | 275 | |
michael@0 | 276 | nsCOMPtr<nsITimer> mOpenTimer; |
michael@0 | 277 | nsCOMPtr<nsITimer> mBlinkTimer; |
michael@0 | 278 | |
michael@0 | 279 | uint8_t mBlinkState; // 0: not blinking, 1: off, 2: on |
michael@0 | 280 | nsRefPtr<nsXULMenuCommandEvent> mDelayedMenuCommandEvent; |
michael@0 | 281 | |
michael@0 | 282 | nsString mGroupName; |
michael@0 | 283 | |
michael@0 | 284 | }; // class nsMenuFrame |
michael@0 | 285 | |
michael@0 | 286 | #endif |