Bug 508473 part III: Pass destruction root to frame destruction methods r=bz sr=roc
[gecko.git] / layout / xul / base / src / nsMenuPopupFrame.h
blobf6a0d4e7f2230efca7be3e2d2199450bd9c7bcb5
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
13 * License.
15 * The Original Code is mozilla.org code.
17 * The Initial Developer of the Original Code is
18 * Netscape Communications Corporation.
19 * Portions created by the Initial Developer are Copyright (C) 1998
20 * the Initial Developer. All Rights Reserved.
22 * Contributor(s):
23 * Original Author: David W. Hyatt (hyatt@netscape.com)
24 * Mike Pinkerton (pinkerton@netscape.com)
25 * Dean Tessman <dean_tessman@hotmail.com>
27 * Alternatively, the contents of this file may be used under the terms of
28 * either of the GNU General Public License Version 2 or later (the "GPL"),
29 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
30 * in which case the provisions of the GPL or the LGPL are applicable instead
31 * of those above. If you wish to allow use of your version of this file only
32 * under the terms of either the GPL or the LGPL, and not to allow others to
33 * use your version of this file under the terms of the MPL, indicate your
34 * decision by deleting the provisions above and replace them with the notice
35 * and other provisions required by the GPL or the LGPL. If you do not delete
36 * the provisions above, a recipient may use your version of this file under
37 * the terms of any one of the MPL, the GPL or the LGPL.
39 * ***** END LICENSE BLOCK ***** */
42 // nsMenuPopupFrame
45 #ifndef nsMenuPopupFrame_h__
46 #define nsMenuPopupFrame_h__
48 #include "prtypes.h"
49 #include "nsIAtom.h"
50 #include "nsGkAtoms.h"
51 #include "nsCOMPtr.h"
52 #include "nsMenuFrame.h"
53 #include "nsIDOMEventTarget.h"
55 #include "nsBoxFrame.h"
56 #include "nsMenuParent.h"
58 #include "nsITimer.h"
60 class nsIWidget;
62 // XUL popups can be in several different states. When opening a popup, the
63 // state changes as follows:
64 // ePopupClosed - initial state
65 // ePopupShowing - during the period when the popupshowing event fires
66 // ePopupOpen - between the popupshowing event and being visible. Creation
67 // of the child frames, layout and reflow occurs in this state.
68 // ePopupOpenAndVisible - layout is done and AdjustView is called to make
69 // the popup's widget visible. The popup is now
70 // visible and the popupshown event fires.
71 // When closing a popup:
72 // ePopupHidden - during the period when the popuphiding event fires and
73 // the popup is removed.
74 // ePopupClosed - the popup's widget is made invisible.
75 enum nsPopupState {
76 // state when a popup is not open
77 ePopupClosed,
78 // state from when a popup is requested to be shown to after the
79 // popupshowing event has been fired.
80 ePopupShowing,
81 // state while a popup is open but the widget is not yet visible
82 ePopupOpen,
83 // state while a popup is open and visible on screen
84 ePopupOpenAndVisible,
85 // state from when a popup is requested to be hidden to when it is closed.
86 ePopupHiding,
87 // state which indicates that the popup was hidden without firing the
88 // popuphiding or popuphidden events. It is used when executing a menu
89 // command because the menu needs to be hidden before the command event
90 // fires, yet the popuphiding and popuphidden events are fired after. This
91 // state can also occur when the popup is removed because the document is
92 // unloaded.
93 ePopupInvisible
96 // values are selected so that the direction can be flipped just by
97 // changing the sign
98 #define POPUPALIGNMENT_NONE 0
99 #define POPUPALIGNMENT_TOPLEFT 1
100 #define POPUPALIGNMENT_TOPRIGHT -1
101 #define POPUPALIGNMENT_BOTTOMLEFT 2
102 #define POPUPALIGNMENT_BOTTOMRIGHT -2
104 #define INC_TYP_INTERVAL 1000 // 1s. If the interval between two keypresses is shorter than this,
105 // treat as a continue typing
106 // XXX, kyle.yuan@sun.com, there are 4 definitions for the same purpose:
107 // nsMenuPopupFrame.h, nsListControlFrame.cpp, listbox.xml, tree.xml
108 // need to find a good place to put them together.
109 // if someone changes one, please also change the other.
111 nsIFrame* NS_NewMenuPopupFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
113 class nsIViewManager;
114 class nsIView;
115 class nsMenuPopupFrame;
117 class nsMenuPopupFrame : public nsBoxFrame, public nsMenuParent
119 public:
120 NS_DECL_FRAMEARENA_HELPERS
122 nsMenuPopupFrame(nsIPresShell* aShell, nsStyleContext* aContext);
124 // nsMenuParent interface
125 virtual nsMenuFrame* GetCurrentMenuItem();
126 NS_IMETHOD SetCurrentMenuItem(nsMenuFrame* aMenuItem);
127 virtual void CurrentMenuIsBeingDestroyed();
128 NS_IMETHOD ChangeMenuItem(nsMenuFrame* aMenuItem, PRBool aSelectFirstItem);
130 // as popups are opened asynchronously, the popup pending state is used to
131 // prevent multiple requests from attempting to open the same popup twice
132 nsPopupState PopupState() { return mPopupState; }
133 void SetPopupState(nsPopupState aPopupState) { mPopupState = aPopupState; }
135 NS_IMETHOD SetActive(PRBool aActiveFlag) { return NS_OK; } // We don't care.
136 virtual PRBool IsActive() { return PR_FALSE; }
137 virtual PRBool IsMenuBar() { return PR_FALSE; }
140 * When this popup is open, should clicks outside of it be consumed?
141 * Return PR_TRUE if the popup should rollup on an outside click,
142 * but consume that click so it can't be used for anything else.
143 * Return PR_FALSE to allow clicks outside the popup to activate content
144 * even when the popup is open.
145 * ---------------------------------------------------------------------
147 * Should clicks outside of a popup be eaten?
149 * Menus Autocomplete Comboboxes
150 * Mac Eat No Eat
151 * Win No No Eat
152 * Unix Eat No Eat
155 PRBool ConsumeOutsideClicks();
157 virtual PRBool IsContextMenu() { return mIsContextMenu; }
159 virtual PRBool MenuClosed() { return PR_TRUE; }
161 NS_IMETHOD GetWidget(nsIWidget **aWidget);
163 // The dismissal listener gets created and attached to the window.
164 void AttachedDismissalListener();
166 // Overridden methods
167 NS_IMETHOD Init(nsIContent* aContent,
168 nsIFrame* aParent,
169 nsIFrame* aPrevInFlow);
171 NS_IMETHOD AttributeChanged(PRInt32 aNameSpaceID,
172 nsIAtom* aAttribute,
173 PRInt32 aModType);
175 virtual void DestroyFrom(nsIFrame* aDestructRoot);
177 virtual void InvalidateInternal(const nsRect& aDamageRect,
178 nscoord aX, nscoord aY, nsIFrame* aForChild,
179 PRUint32 aFlags);
181 // returns true if the popup is a panel with the noautohide attribute set to
182 // true. These panels do not roll up automatically.
183 PRBool IsNoAutoHide();
185 // returns true if the popup is a top-most window. Otherwise, the
186 // panel appears in front of the parent window.
187 PRBool IsTopMost();
189 void EnsureWidget();
191 nsresult CreateWidgetForView(nsIView* aView);
193 NS_IMETHOD SetInitialChildList(nsIAtom* aListName,
194 nsFrameList& aChildList);
196 virtual PRBool IsLeaf() const;
198 // AdjustView should be called by the parent frame after the popup has been
199 // laid out, so that the view can be shown.
200 void AdjustView();
202 nsIView* GetRootViewForPopup(nsIFrame* aStartFrame);
204 // set the position of the popup either relative to the anchor aAnchorFrame
205 // (or the frame for mAnchorContent if aAnchorFrame is null) or at a specific
206 // point if a screen position (mScreenXPos and mScreenYPos) are set. The popup
207 // will be adjusted so that it is on screen.
208 nsresult SetPopupPosition(nsIFrame* aAnchorFrame);
210 PRBool HasGeneratedChildren() { return mGeneratedChildren; }
211 void SetGeneratedChildren() { mGeneratedChildren = PR_TRUE; }
213 // called when the Enter key is pressed while the popup is open. This will
214 // just pass the call down to the current menu, if any. If a current menu
215 // should be opened as a result, this method should return the frame for
216 // that menu, or null if no menu should be opened. Also, calling Enter will
217 // reset the current incremental search string, calculated in
218 // FindMenuWithShortcut.
219 nsMenuFrame* Enter();
221 nsPopupType PopupType() const { return mPopupType; }
222 PRBool IsMenu() { return mPopupType == ePopupTypeMenu; }
223 PRBool IsOpen() { return mPopupState == ePopupOpen || mPopupState == ePopupOpenAndVisible; }
224 PRBool HasOpenChanged() { return mIsOpenChanged; }
226 // returns true if the popup is in a content shell, or false for a popup in
227 // a chrome shell
228 PRBool IsInContentShell() { return mInContentShell; }
230 // the Initialize methods are used to set the anchor position for
231 // each way of opening a popup.
232 void InitializePopup(nsIContent* aAnchorContent,
233 const nsAString& aPosition,
234 PRInt32 aXPos, PRInt32 aYPos,
235 PRBool aAttributesOverride);
238 * @param aIsContextMenu if true, then the popup is
239 * positioned at a slight offset from aXPos/aYPos to ensure the
240 * (presumed) mouse position is not over the menu.
242 void InitializePopupAtScreen(PRInt32 aXPos, PRInt32 aYPos,
243 PRBool aIsContextMenu);
245 void InitializePopupWithAnchorAlign(nsIContent* aAnchorContent,
246 nsAString& aAnchor,
247 nsAString& aAlign,
248 PRInt32 aXPos, PRInt32 aYPos);
250 // indicate that the popup should be opened
251 PRBool ShowPopup(PRBool aIsContextMenu, PRBool aSelectFirstItem);
252 // indicate that the popup should be hidden. The new state should either be
253 // ePopupClosed or ePopupInvisible.
254 void HidePopup(PRBool aDeselectMenu, nsPopupState aNewState);
256 // locate and return the menu frame that should be activated for the
257 // supplied key event. If doAction is set to true by this method,
258 // then the menu's action should be carried out, as if the user had pressed
259 // the Enter key. If doAction is false, the menu should just be highlighted.
260 // This method also handles incremental searching in menus so the user can
261 // type the first few letters of an item/s name to select it.
262 nsMenuFrame* FindMenuWithShortcut(nsIDOMKeyEvent* aKeyEvent, PRBool& doAction);
264 void ClearIncrementalString() { mIncrementalString.Truncate(); }
266 virtual nsIAtom* GetType() const { return nsGkAtoms::menuPopupFrame; }
268 #ifdef DEBUG
269 NS_IMETHOD GetFrameName(nsAString& aResult) const
271 return MakeFrameName(NS_LITERAL_STRING("MenuPopup"), aResult);
273 #endif
275 void EnsureMenuItemIsVisible(nsMenuFrame* aMenuFrame);
277 // Move the popup to the screen coordinate (aLeft, aTop). If aUpdateAttrs
278 // is true, and the popup already has left or top attributes, then those
279 // attributes are updated to the new location.
280 // The frame may be destroyed by this method.
281 void MoveTo(PRInt32 aLeft, PRInt32 aTop, PRBool aUpdateAttrs);
283 PRBool GetAutoPosition();
284 void SetAutoPosition(PRBool aShouldAutoPosition);
285 void SetConsumeRollupEvent(PRUint32 aConsumeMode);
287 nsIScrollableView* GetScrollableView(nsIFrame* aStart);
289 // same as SetBounds except the preferred size mPrefSize is also set.
290 void SetPreferredBounds(nsBoxLayoutState& aState, const nsRect& aRect);
292 // retrieve the last preferred size
293 nsSize PreferredSize() { return mPrefSize; }
294 // set the last preferred size
295 void SetPreferredSize(nsSize aSize) { mPrefSize = aSize; }
297 // For a popup that should appear at the given anchor point, determine
298 // the screen area that it is constrained by. This will be the available
299 // area of the screen the popup should be displayed on. Content popups,
300 // however, will also be constrained by the content area, given by
301 // aRootScreenRect. All coordinates are in app units.
302 nsRect GetConstraintRect(nsPoint aAnchorPoint, nsRect& aRootScreenRect);
304 // Determines whether the given edges of the popup may be moved, where
305 // aHorizontalSide and aVerticalSide are one of the NS_SIDE_* constants, or
306 // 0 for no movement in that direction. aChange is the distance to move on
307 // those sides. If will be reset to 0 if the side cannot be adjusted at all
308 // in that direction. For example, a popup cannot be moved if it is anchored
309 // on a particular side.
311 // Later, when bug 357725 is implemented, we can make this adjust aChange by
312 // the amount that the side can be resized, so that minimums and maximums
313 // can be taken into account.
314 void CanAdjustEdges(PRInt8 aHorizontalSide, PRInt8 aVerticalSide, nsIntPoint& aChange);
316 protected:
318 // redefine to tell the box system not to move the views.
319 virtual void GetLayoutFlags(PRUint32& aFlags);
321 void InitPositionFromAnchorAlign(const nsAString& aAnchor,
322 const nsAString& aAlign);
324 // return the position where the popup should be, when it should be
325 // anchored at anchorRect. aHFlip and aVFlip will be set if the popup may be
326 // flipped in that direction if there is not enough space available.
327 nsPoint AdjustPositionForAnchorAlign(const nsRect& anchorRect, PRBool& aHFlip, PRBool& aVFlip);
330 // check if the popup will fit into the available space and resize it. This
331 // method handles only one axis at a time so is called twice, once for
332 // horizontal and once for vertical. All arguments are specified for this
333 // one axis. All coordinates are in app units relative to the screen.
334 // aScreenPoint - the point where the popup should appear
335 // aSize - the size of the popup
336 // aScreenBegin - the left or top edge of the screen
337 // aScreenEnd - the right or bottom edge of the screen
338 // aAnchorBegin - the left or top edge of the anchor rectangle
339 // aAnchorEnd - the right or bottom edge of the anchor rectangle
340 // aMarginBegin - the left or top margin of the popup
341 // aMarginEnd - the right or bottom margin of the popup
342 // aOffsetForContextMenu - the additional offset to add for context menus
343 // aFlip - whether to flip or resize the popup when there isn't space
344 // aFlipSide - pointer to where current flip mode is stored
345 nscoord FlipOrResize(nscoord& aScreenPoint, nscoord aSize,
346 nscoord aScreenBegin, nscoord aScreenEnd,
347 nscoord aAnchorBegin, nscoord aAnchorEnd,
348 nscoord aMarginBegin, nscoord aMarginEnd,
349 nscoord aOffsetForContextMenu, PRBool aFlip,
350 PRPackedBool* aFlipSide);
352 // Move the popup to the position specified in its |left| and |top| attributes.
353 void MoveToAttributePosition();
355 nsString mIncrementalString; // for incremental typing navigation
357 // the content that the popup is anchored to, if any, which may be in a
358 // different document than the popup.
359 nsCOMPtr<nsIContent> mAnchorContent;
361 nsMenuFrame* mCurrentMenu; // The current menu that is active.
363 // A popup's preferred size may be different than its actual size stored in
364 // mRect in the case where the popup was resized because it was too large
365 // for the screen. The preferred size mPrefSize holds the full size the popup
366 // would be before resizing. Computations are performed using this size.
367 // The parent frame is responsible for setting the preferred size using
368 // SetPreferredBounds or SetPreferredSize before positioning the popup with
369 // SetPopupPosition.
370 nsSize mPrefSize;
372 // the position of the popup. The screen coordinates, if set to values other
373 // than -1, override mXPos and mYPos.
374 PRInt32 mXPos;
375 PRInt32 mYPos;
376 PRInt32 mScreenXPos;
377 PRInt32 mScreenYPos;
379 nsPopupType mPopupType; // type of popup
380 nsPopupState mPopupState; // open state of the popup
382 // popup alignment relative to the anchor node
383 PRInt8 mPopupAlignment;
384 PRInt8 mPopupAnchor;
386 PRPackedBool mIsOpenChanged; // true if the open state changed since the last layout
387 PRPackedBool mIsContextMenu; // true for context menus
388 // true if we need to offset the popup to ensure it's not under the mouse
389 PRPackedBool mAdjustOffsetForContextMenu;
390 PRPackedBool mGeneratedChildren; // true if the contents have been created
392 PRPackedBool mMenuCanOverlapOSBar; // can we appear over the taskbar/menubar?
393 PRPackedBool mShouldAutoPosition; // Should SetPopupPosition be allowed to auto position popup?
394 PRPackedBool mConsumeRollupEvent; // Should the rollup event be consumed?
395 PRPackedBool mInContentShell; // True if the popup is in a content shell
397 // the flip modes that were used when the popup was opened
398 PRPackedBool mHFlip;
399 PRPackedBool mVFlip;
401 static PRInt8 sDefaultLevelParent;
402 }; // class nsMenuPopupFrame
404 #endif