2001-09-28 20:14:13 +00:00
|
|
|
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
|
|
/* ***** BEGIN LICENSE BLOCK *****
|
2004-04-18 14:30:37 +00:00
|
|
|
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
1999-07-18 06:36:37 +00:00
|
|
|
*
|
2004-04-18 14:30:37 +00:00
|
|
|
* The contents of this file are subject to the Mozilla Public License Version
|
|
|
|
* 1.1 (the "License"); you may not use this file except in compliance with
|
|
|
|
* the License. You may obtain a copy of the License at
|
|
|
|
* http://www.mozilla.org/MPL/
|
1999-07-18 06:36:37 +00:00
|
|
|
*
|
2001-09-28 20:14:13 +00:00
|
|
|
* Software distributed under the License is distributed on an "AS IS" basis,
|
|
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
|
|
|
* for the specific language governing rights and limitations under the
|
|
|
|
* License.
|
1999-07-18 06:36:37 +00:00
|
|
|
*
|
1999-11-06 03:40:37 +00:00
|
|
|
* The Original Code is mozilla.org code.
|
|
|
|
*
|
2004-04-18 14:30:37 +00:00
|
|
|
* The Initial Developer of the Original Code is
|
2001-09-28 20:14:13 +00:00
|
|
|
* Netscape Communications Corporation.
|
|
|
|
* Portions created by the Initial Developer are Copyright (C) 1998
|
|
|
|
* the Initial Developer. All Rights Reserved.
|
1999-11-06 03:40:37 +00:00
|
|
|
*
|
2001-09-28 20:14:13 +00:00
|
|
|
* Contributor(s):
|
2004-04-18 14:30:37 +00:00
|
|
|
* Original Author: David W. Hyatt (hyatt@netscape.com)
|
2000-02-02 22:24:56 +00:00
|
|
|
* Michael Lowe <michael.lowe@bigfoot.com>
|
|
|
|
* Pierre Phaneuf <pp@ludusdesign.com>
|
2000-03-01 03:12:51 +00:00
|
|
|
* Dean Tessman <dean_tessman@hotmail.com>
|
2001-09-28 20:14:13 +00:00
|
|
|
*
|
|
|
|
* Alternatively, the contents of this file may be used under the terms of
|
2004-04-18 14:30:37 +00:00
|
|
|
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
|
|
|
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
2001-09-28 20:14:13 +00:00
|
|
|
* in which case the provisions of the GPL or the LGPL are applicable instead
|
|
|
|
* of those above. If you wish to allow use of your version of this file only
|
|
|
|
* under the terms of either the GPL or the LGPL, and not to allow others to
|
2004-04-18 14:30:37 +00:00
|
|
|
* use your version of this file under the terms of the MPL, indicate your
|
2001-09-28 20:14:13 +00:00
|
|
|
* decision by deleting the provisions above and replace them with the notice
|
|
|
|
* and other provisions required by the GPL or the LGPL. If you do not delete
|
|
|
|
* the provisions above, a recipient may use your version of this file under
|
2004-04-18 14:30:37 +00:00
|
|
|
* the terms of any one of the MPL, the GPL or the LGPL.
|
2001-09-28 20:14:13 +00:00
|
|
|
*
|
|
|
|
* ***** END LICENSE BLOCK ***** */
|
1999-07-18 06:36:37 +00:00
|
|
|
|
2007-01-30 00:06:41 +00:00
|
|
|
#include "nsGkAtoms.h"
|
1999-10-14 23:59:18 +00:00
|
|
|
#include "nsHTMLParts.h"
|
1999-07-18 06:36:37 +00:00
|
|
|
#include "nsMenuFrame.h"
|
1999-07-21 02:56:23 +00:00
|
|
|
#include "nsBoxFrame.h"
|
1999-07-18 06:36:37 +00:00
|
|
|
#include "nsIContent.h"
|
|
|
|
#include "prtypes.h"
|
|
|
|
#include "nsIAtom.h"
|
2004-07-31 23:15:21 +00:00
|
|
|
#include "nsPresContext.h"
|
1999-10-14 23:59:18 +00:00
|
|
|
#include "nsIPresShell.h"
|
2003-02-22 00:32:13 +00:00
|
|
|
#include "nsStyleContext.h"
|
1999-07-18 06:36:37 +00:00
|
|
|
#include "nsCSSRendering.h"
|
|
|
|
#include "nsINameSpaceManager.h"
|
1999-07-20 09:35:35 +00:00
|
|
|
#include "nsMenuPopupFrame.h"
|
1999-07-21 07:42:16 +00:00
|
|
|
#include "nsMenuBarFrame.h"
|
1999-07-26 02:26:26 +00:00
|
|
|
#include "nsIView.h"
|
1999-07-31 01:43:33 +00:00
|
|
|
#include "nsIDocument.h"
|
|
|
|
#include "nsIDOMNSDocument.h"
|
|
|
|
#include "nsIDOMDocument.h"
|
|
|
|
#include "nsIDOMElement.h"
|
|
|
|
#include "nsIDOMText.h"
|
2000-01-21 21:56:09 +00:00
|
|
|
#include "nsILookAndFeel.h"
|
|
|
|
#include "nsIComponentManager.h"
|
|
|
|
#include "nsWidgetsCID.h"
|
2000-03-31 07:02:06 +00:00
|
|
|
#include "nsBoxLayoutState.h"
|
2000-05-15 04:12:31 +00:00
|
|
|
#include "nsIScrollableFrame.h"
|
|
|
|
#include "nsIViewManager.h"
|
2007-02-16 23:02:08 +00:00
|
|
|
#include "nsBindingManager.h"
|
2000-08-06 08:11:05 +00:00
|
|
|
#include "nsIServiceManager.h"
|
2000-08-03 00:22:36 +00:00
|
|
|
#include "nsCSSFrameConstructor.h"
|
2000-08-17 00:09:16 +00:00
|
|
|
#include "nsIDOMKeyEvent.h"
|
2007-07-04 15:49:38 +00:00
|
|
|
#include "nsEventDispatcher.h"
|
|
|
|
#include "nsIPrivateDOMEvent.h"
|
2001-01-09 01:28:36 +00:00
|
|
|
#include "nsXPIDLString.h"
|
2001-09-29 08:28:41 +00:00
|
|
|
#include "nsReadableUtils.h"
|
2001-12-17 07:14:49 +00:00
|
|
|
#include "nsUnicharUtils.h"
|
2001-01-09 01:28:36 +00:00
|
|
|
#include "nsIStringBundle.h"
|
2001-07-16 02:40:48 +00:00
|
|
|
#include "nsGUIEvent.h"
|
2004-04-29 23:34:19 +00:00
|
|
|
#include "nsContentUtils.h"
|
2006-01-26 02:29:17 +00:00
|
|
|
#include "nsDisplayList.h"
|
2007-03-05 21:55:23 +00:00
|
|
|
#include "nsIReflowCallback.h"
|
2008-12-10 17:23:20 +00:00
|
|
|
#include "nsISound.h"
|
2004-04-29 23:34:19 +00:00
|
|
|
|
2007-07-04 15:49:38 +00:00
|
|
|
#define NS_MENU_POPUP_LIST_INDEX 0
|
1999-07-18 06:48:03 +00:00
|
|
|
|
2003-04-02 22:45:08 +00:00
|
|
|
#if defined(XP_WIN) || defined(XP_OS2)
|
2001-03-29 03:33:09 +00:00
|
|
|
#define NSCONTEXTMENUISMOUSEUP 1
|
|
|
|
#endif
|
|
|
|
|
1999-08-07 06:01:31 +00:00
|
|
|
static PRInt32 gEatMouseMove = PR_FALSE;
|
1999-07-26 06:29:48 +00:00
|
|
|
|
2000-01-21 21:56:09 +00:00
|
|
|
static NS_DEFINE_IID(kLookAndFeelCID, NS_LOOKANDFEEL_CID);
|
|
|
|
|
2001-07-03 00:26:41 +00:00
|
|
|
nsrefcnt nsMenuFrame::gRefCnt = 0;
|
|
|
|
nsString *nsMenuFrame::gShiftText = nsnull;
|
|
|
|
nsString *nsMenuFrame::gControlText = nsnull;
|
|
|
|
nsString *nsMenuFrame::gMetaText = nsnull;
|
|
|
|
nsString *nsMenuFrame::gAltText = nsnull;
|
|
|
|
nsString *nsMenuFrame::gModifierSeparator = nsnull;
|
|
|
|
|
2007-07-26 04:14:32 +00:00
|
|
|
// this class is used for dispatching menu activation events asynchronously.
|
|
|
|
class nsMenuActivateEvent : public nsRunnable
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
nsMenuActivateEvent(nsIContent *aMenu,
|
|
|
|
nsPresContext* aPresContext,
|
|
|
|
PRBool aIsActivate)
|
|
|
|
: mMenu(aMenu), mPresContext(aPresContext), mIsActivate(aIsActivate)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHOD Run()
|
|
|
|
{
|
|
|
|
nsAutoString domEventToFire;
|
|
|
|
|
|
|
|
if (mIsActivate) {
|
|
|
|
// Highlight the menu.
|
|
|
|
mMenu->SetAttr(kNameSpaceID_None, nsGkAtoms::menuactive,
|
|
|
|
NS_LITERAL_STRING("true"), PR_TRUE);
|
|
|
|
// The menuactivated event is used by accessibility to track the user's
|
|
|
|
// movements through menus
|
|
|
|
domEventToFire.AssignLiteral("DOMMenuItemActive");
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// Unhighlight the menu.
|
|
|
|
mMenu->UnsetAttr(kNameSpaceID_None, nsGkAtoms::menuactive, PR_TRUE);
|
|
|
|
domEventToFire.AssignLiteral("DOMMenuItemInactive");
|
|
|
|
}
|
|
|
|
|
|
|
|
nsCOMPtr<nsIDOMEvent> event;
|
|
|
|
if (NS_SUCCEEDED(nsEventDispatcher::CreateEvent(mPresContext, nsnull,
|
|
|
|
NS_LITERAL_STRING("Events"),
|
|
|
|
getter_AddRefs(event)))) {
|
|
|
|
event->InitEvent(domEventToFire, PR_TRUE, PR_TRUE);
|
|
|
|
|
|
|
|
nsCOMPtr<nsIPrivateDOMEvent> privateEvent(do_QueryInterface(event));
|
|
|
|
privateEvent->SetTrusted(PR_TRUE);
|
|
|
|
|
|
|
|
nsEventDispatcher::DispatchDOMEvent(mMenu, nsnull, event,
|
|
|
|
mPresContext, nsnull);
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
nsCOMPtr<nsIContent> mMenu;
|
|
|
|
nsCOMPtr<nsPresContext> mPresContext;
|
|
|
|
PRBool mIsActivate;
|
|
|
|
};
|
|
|
|
|
1999-07-18 06:36:37 +00:00
|
|
|
//
|
2009-01-19 18:31:33 +00:00
|
|
|
// NS_NewMenuFrame and NS_NewMenuItemFrame
|
1999-07-18 06:36:37 +00:00
|
|
|
//
|
2009-01-19 18:31:33 +00:00
|
|
|
// Wrappers for creating a new menu popup container
|
1999-07-18 06:36:37 +00:00
|
|
|
//
|
2005-10-26 21:46:39 +00:00
|
|
|
nsIFrame*
|
2009-01-19 18:31:33 +00:00
|
|
|
NS_NewMenuFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
|
1999-07-18 06:36:37 +00:00
|
|
|
{
|
2006-03-26 21:30:36 +00:00
|
|
|
nsMenuFrame* it = new (aPresShell) nsMenuFrame (aPresShell, aContext);
|
2005-10-26 21:46:39 +00:00
|
|
|
|
2009-01-19 18:31:33 +00:00
|
|
|
if (it)
|
1999-07-23 05:10:57 +00:00
|
|
|
it->SetIsMenu(PR_TRUE);
|
2005-10-26 21:46:39 +00:00
|
|
|
|
|
|
|
return it;
|
1999-07-18 06:36:37 +00:00
|
|
|
}
|
|
|
|
|
2009-01-19 18:31:33 +00:00
|
|
|
nsIFrame*
|
|
|
|
NS_NewMenuItemFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
|
|
|
|
{
|
|
|
|
nsMenuFrame* it = new (aPresShell) nsMenuFrame (aPresShell, aContext);
|
|
|
|
|
|
|
|
if (it)
|
|
|
|
it->SetIsMenu(PR_FALSE);
|
|
|
|
|
|
|
|
return it;
|
|
|
|
}
|
|
|
|
|
2009-09-12 16:49:24 +00:00
|
|
|
NS_IMPL_FRAMEARENA_HELPERS(nsMenuFrame)
|
|
|
|
|
2009-01-12 19:20:59 +00:00
|
|
|
NS_QUERYFRAME_HEAD(nsMenuFrame)
|
|
|
|
NS_QUERYFRAME_ENTRY(nsIMenuFrame)
|
|
|
|
NS_QUERYFRAME_TAIL_INHERITING(nsBoxFrame)
|
1999-07-18 06:36:37 +00:00
|
|
|
|
|
|
|
//
|
|
|
|
// nsMenuFrame cntr
|
|
|
|
//
|
2006-03-26 21:30:36 +00:00
|
|
|
nsMenuFrame::nsMenuFrame(nsIPresShell* aShell, nsStyleContext* aContext):
|
|
|
|
nsBoxFrame(aShell, aContext),
|
2000-03-02 03:01:30 +00:00
|
|
|
mIsMenu(PR_FALSE),
|
1999-10-15 21:13:24 +00:00
|
|
|
mChecked(PR_FALSE),
|
1999-10-17 21:37:37 +00:00
|
|
|
mType(eMenuType_Normal),
|
1999-09-03 03:47:06 +00:00
|
|
|
mMenuParent(nsnull),
|
2007-09-18 14:35:17 +00:00
|
|
|
mPopupFrame(nsnull)
|
1999-07-18 06:36:37 +00:00
|
|
|
{
|
|
|
|
|
|
|
|
} // cntr
|
|
|
|
|
2000-05-26 22:45:26 +00:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsMenuFrame::SetParent(const nsIFrame* aParent)
|
|
|
|
{
|
2000-08-17 00:09:16 +00:00
|
|
|
nsBoxFrame::SetParent(aParent);
|
2007-07-08 07:08:04 +00:00
|
|
|
InitMenuParent(const_cast<nsIFrame *>(aParent));
|
2007-07-04 15:49:38 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
2000-05-26 22:45:26 +00:00
|
|
|
|
2007-07-04 15:49:38 +00:00
|
|
|
void
|
|
|
|
nsMenuFrame::InitMenuParent(nsIFrame* aParent)
|
|
|
|
{
|
|
|
|
while (aParent) {
|
|
|
|
nsIAtom* type = aParent->GetType();
|
|
|
|
if (type == nsGkAtoms::menuPopupFrame) {
|
2007-07-08 07:08:04 +00:00
|
|
|
mMenuParent = static_cast<nsMenuPopupFrame *>(aParent);
|
2007-07-04 15:49:38 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
else if (type == nsGkAtoms::menuBarFrame) {
|
2007-07-08 07:08:04 +00:00
|
|
|
mMenuParent = static_cast<nsMenuBarFrame *>(aParent);
|
2007-07-04 15:49:38 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
aParent = aParent->GetParent();
|
2000-05-26 22:45:26 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-03-05 21:55:23 +00:00
|
|
|
class nsASyncMenuInitialization : public nsIReflowCallback
|
2006-09-03 20:25:58 +00:00
|
|
|
{
|
|
|
|
public:
|
2006-09-13 19:15:08 +00:00
|
|
|
nsASyncMenuInitialization(nsIFrame* aFrame)
|
|
|
|
: mWeakFrame(aFrame)
|
2006-09-03 20:25:58 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2007-12-01 07:22:44 +00:00
|
|
|
virtual PRBool ReflowFinished()
|
|
|
|
{
|
2007-03-05 21:55:23 +00:00
|
|
|
PRBool shouldFlush = PR_FALSE;
|
2006-09-13 19:15:08 +00:00
|
|
|
if (mWeakFrame.IsAlive()) {
|
2007-07-04 15:49:38 +00:00
|
|
|
if (mWeakFrame.GetFrame()->GetType() == nsGkAtoms::menuFrame) {
|
2007-07-08 07:08:04 +00:00
|
|
|
nsMenuFrame* menu = static_cast<nsMenuFrame*>(mWeakFrame.GetFrame());
|
2007-03-30 21:11:41 +00:00
|
|
|
menu->UpdateMenuType(menu->PresContext());
|
2007-03-05 21:55:23 +00:00
|
|
|
shouldFlush = PR_TRUE;
|
2006-09-13 19:15:08 +00:00
|
|
|
}
|
|
|
|
}
|
2007-03-05 21:55:23 +00:00
|
|
|
delete this;
|
|
|
|
return shouldFlush;
|
2006-09-03 20:25:58 +00:00
|
|
|
}
|
|
|
|
|
2007-12-01 07:22:44 +00:00
|
|
|
virtual void ReflowCallbackCanceled()
|
|
|
|
{
|
|
|
|
delete this;
|
|
|
|
}
|
|
|
|
|
2006-09-13 19:15:08 +00:00
|
|
|
nsWeakFrame mWeakFrame;
|
2006-09-03 20:25:58 +00:00
|
|
|
};
|
|
|
|
|
1999-07-21 07:42:16 +00:00
|
|
|
NS_IMETHODIMP
|
2006-03-09 18:55:21 +00:00
|
|
|
nsMenuFrame::Init(nsIContent* aContent,
|
|
|
|
nsIFrame* aParent,
|
|
|
|
nsIFrame* aPrevInFlow)
|
1999-07-21 07:42:16 +00:00
|
|
|
{
|
2006-03-26 21:30:36 +00:00
|
|
|
nsresult rv = nsBoxFrame::Init(aContent, aParent, aPrevInFlow);
|
1999-07-21 07:42:16 +00:00
|
|
|
|
2006-01-12 16:40:47 +00:00
|
|
|
// Set up a mediator which can be used for callbacks on this frame.
|
|
|
|
mTimerMediator = new nsMenuTimerMediator(this);
|
|
|
|
if (NS_UNLIKELY(!mTimerMediator))
|
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
|
2007-07-04 15:49:38 +00:00
|
|
|
InitMenuParent(aParent);
|
2000-01-25 06:35:27 +00:00
|
|
|
|
2001-07-03 00:26:41 +00:00
|
|
|
//load the display strings for the keyboard accelerators, but only once
|
|
|
|
if (gRefCnt++ == 0) {
|
|
|
|
|
|
|
|
nsCOMPtr<nsIStringBundleService> bundleService(do_GetService(NS_STRINGBUNDLE_CONTRACTID, &rv));
|
|
|
|
nsCOMPtr<nsIStringBundle> bundle;
|
|
|
|
if (NS_SUCCEEDED(rv) && bundleService) {
|
|
|
|
rv = bundleService->CreateBundle( "chrome://global-platform/locale/platformKeys.properties",
|
|
|
|
getter_AddRefs(bundle));
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_ASSERTION(NS_SUCCEEDED(rv) && bundle, "chrome://global/locale/platformKeys.properties could not be loaded");
|
|
|
|
nsXPIDLString shiftModifier;
|
|
|
|
nsXPIDLString metaModifier;
|
|
|
|
nsXPIDLString altModifier;
|
|
|
|
nsXPIDLString controlModifier;
|
|
|
|
nsXPIDLString modifierSeparator;
|
|
|
|
if (NS_SUCCEEDED(rv) && bundle) {
|
|
|
|
//macs use symbols for each modifier key, so fetch each from the bundle, which also covers i18n
|
|
|
|
rv = bundle->GetStringFromName(NS_LITERAL_STRING("VK_SHIFT").get(), getter_Copies(shiftModifier));
|
|
|
|
rv = bundle->GetStringFromName(NS_LITERAL_STRING("VK_META").get(), getter_Copies(metaModifier));
|
|
|
|
rv = bundle->GetStringFromName(NS_LITERAL_STRING("VK_ALT").get(), getter_Copies(altModifier));
|
|
|
|
rv = bundle->GetStringFromName(NS_LITERAL_STRING("VK_CONTROL").get(), getter_Copies(controlModifier));
|
|
|
|
rv = bundle->GetStringFromName(NS_LITERAL_STRING("MODIFIER_SEPARATOR").get(), getter_Copies(modifierSeparator));
|
|
|
|
} else {
|
|
|
|
rv = NS_ERROR_NOT_AVAILABLE;
|
|
|
|
}
|
|
|
|
//if any of these don't exist, we get an empty string
|
|
|
|
gShiftText = new nsString(shiftModifier);
|
|
|
|
gMetaText = new nsString(metaModifier);
|
|
|
|
gAltText = new nsString(altModifier);
|
|
|
|
gControlText = new nsString(controlModifier);
|
|
|
|
gModifierSeparator = new nsString(modifierSeparator);
|
|
|
|
}
|
2006-09-03 20:25:58 +00:00
|
|
|
|
2006-09-07 09:17:52 +00:00
|
|
|
BuildAcceleratorText();
|
2007-03-05 21:55:23 +00:00
|
|
|
nsIReflowCallback* cb = new nsASyncMenuInitialization(this);
|
|
|
|
NS_ENSURE_TRUE(cb, NS_ERROR_OUT_OF_MEMORY);
|
2007-03-30 21:11:41 +00:00
|
|
|
PresContext()->PresShell()->PostReflowCallback(cb);
|
1999-07-21 07:42:16 +00:00
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
2001-07-03 00:26:41 +00:00
|
|
|
nsMenuFrame::~nsMenuFrame()
|
|
|
|
{
|
|
|
|
// Clean up shared statics
|
|
|
|
if (--gRefCnt == 0) {
|
|
|
|
delete gShiftText;
|
|
|
|
gShiftText = nsnull;
|
|
|
|
delete gControlText;
|
|
|
|
gControlText = nsnull;
|
|
|
|
delete gMetaText;
|
|
|
|
gMetaText = nsnull;
|
|
|
|
delete gAltText;
|
|
|
|
gAltText = nsnull;
|
|
|
|
delete gModifierSeparator;
|
|
|
|
gModifierSeparator = nsnull;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1999-07-31 11:29:03 +00:00
|
|
|
// The following methods are all overridden to ensure that the menupopup frame
|
1999-07-18 06:44:03 +00:00
|
|
|
// is placed in the appropriate list.
|
2009-07-28 12:51:09 +00:00
|
|
|
nsFrameList
|
|
|
|
nsMenuFrame::GetChildList(nsIAtom* aListName) const
|
1999-07-18 06:41:41 +00:00
|
|
|
{
|
2006-12-26 17:47:52 +00:00
|
|
|
if (nsGkAtoms::popupList == aListName) {
|
2009-09-18 11:09:36 +00:00
|
|
|
return nsFrameList(mPopupFrame, mPopupFrame);
|
1999-07-18 06:41:41 +00:00
|
|
|
}
|
2009-07-28 12:51:09 +00:00
|
|
|
return nsBoxFrame::GetChildList(aListName);
|
1999-07-18 06:41:41 +00:00
|
|
|
}
|
|
|
|
|
2009-07-28 12:53:20 +00:00
|
|
|
void
|
|
|
|
nsMenuFrame::SetPopupFrame(nsFrameList& aFrameList)
|
|
|
|
{
|
|
|
|
for (nsFrameList::Enumerator e(aFrameList); !e.AtEnd(); e.Next()) {
|
|
|
|
if (e.get()->GetType() == nsGkAtoms::menuPopupFrame) {
|
2007-07-04 15:49:38 +00:00
|
|
|
// Remove this frame from the list and set it as mPopupFrame
|
2009-07-28 12:53:20 +00:00
|
|
|
mPopupFrame = (nsMenuPopupFrame *)e.get();
|
|
|
|
aFrameList.RemoveFrame(e.get());
|
2007-07-04 15:49:38 +00:00
|
|
|
break;
|
1999-07-20 08:19:47 +00:00
|
|
|
}
|
2007-06-29 22:15:59 +00:00
|
|
|
}
|
2007-11-17 15:47:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsMenuFrame::SetInitialChildList(nsIAtom* aListName,
|
2009-07-28 12:53:20 +00:00
|
|
|
nsFrameList& aChildList)
|
2007-11-17 15:47:38 +00:00
|
|
|
{
|
|
|
|
NS_ASSERTION(!mPopupFrame, "already have a popup frame set");
|
|
|
|
if (!aListName || aListName == nsGkAtoms::popupList)
|
2009-07-28 12:53:20 +00:00
|
|
|
SetPopupFrame(aChildList);
|
2007-07-04 15:49:38 +00:00
|
|
|
return nsBoxFrame::SetInitialChildList(aListName, aChildList);
|
1999-07-18 06:44:03 +00:00
|
|
|
}
|
1999-07-18 06:48:03 +00:00
|
|
|
|
2004-01-09 14:20:53 +00:00
|
|
|
nsIAtom*
|
|
|
|
nsMenuFrame::GetAdditionalChildListName(PRInt32 aIndex) const
|
1999-07-18 06:48:03 +00:00
|
|
|
{
|
2000-07-28 22:09:45 +00:00
|
|
|
if (NS_MENU_POPUP_LIST_INDEX == aIndex) {
|
2006-12-26 17:47:52 +00:00
|
|
|
return nsGkAtoms::popupList;
|
2000-07-28 22:09:45 +00:00
|
|
|
}
|
2004-01-09 14:20:53 +00:00
|
|
|
return nsnull;
|
1999-07-18 06:48:03 +00:00
|
|
|
}
|
1999-07-18 06:52:06 +00:00
|
|
|
|
2006-04-10 00:16:29 +00:00
|
|
|
void
|
2009-12-24 05:21:15 +00:00
|
|
|
nsMenuFrame::DestroyFrom(nsIFrame* aDestructRoot)
|
2001-12-17 22:51:39 +00:00
|
|
|
{
|
2006-01-12 16:40:47 +00:00
|
|
|
// Kill our timer if one is active. This is not strictly necessary as
|
|
|
|
// the pointer to this frame will be cleared from the mediator, but
|
|
|
|
// this is done for added safety.
|
|
|
|
if (mOpenTimer) {
|
|
|
|
mOpenTimer->Cancel();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Null out the pointer to this frame in the mediator wrapper so that it
|
|
|
|
// doesn't try to interact with a deallocated frame.
|
|
|
|
mTimerMediator->ClearFrame();
|
|
|
|
|
2008-01-30 07:18:07 +00:00
|
|
|
// if the menu content is just being hidden, it may be made visible again
|
|
|
|
// later, so make sure to clear the highlighting.
|
|
|
|
mContent->UnsetAttr(kNameSpaceID_None, nsGkAtoms::menuactive, PR_FALSE);
|
|
|
|
|
2005-01-07 23:59:12 +00:00
|
|
|
// are we our menu parent's current menu item?
|
2007-07-04 15:49:38 +00:00
|
|
|
if (mMenuParent && mMenuParent->GetCurrentMenuItem() == this) {
|
|
|
|
// yes; tell it that we're going away
|
|
|
|
mMenuParent->CurrentMenuIsBeingDestroyed();
|
2005-01-07 23:59:12 +00:00
|
|
|
}
|
|
|
|
|
2007-07-04 15:49:38 +00:00
|
|
|
if (mPopupFrame)
|
2009-12-24 05:21:15 +00:00
|
|
|
mPopupFrame->DestroyFrom(aDestructRoot);
|
2007-07-04 15:49:38 +00:00
|
|
|
|
2009-12-24 05:21:15 +00:00
|
|
|
nsBoxFrame::DestroyFrom(aDestructRoot);
|
1999-07-18 06:52:06 +00:00
|
|
|
}
|
1999-07-19 09:36:24 +00:00
|
|
|
|
2006-01-26 02:29:17 +00:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsMenuFrame::BuildDisplayListForChildren(nsDisplayListBuilder* aBuilder,
|
|
|
|
const nsRect& aDirtyRect,
|
|
|
|
const nsDisplayListSet& aLists)
|
1999-07-19 09:36:24 +00:00
|
|
|
{
|
2006-01-26 02:29:17 +00:00
|
|
|
if (!aBuilder->IsForEventDelivery())
|
|
|
|
return nsBoxFrame::BuildDisplayListForChildren(aBuilder, aDirtyRect, aLists);
|
|
|
|
|
|
|
|
nsDisplayListCollection set;
|
|
|
|
nsresult rv = nsBoxFrame::BuildDisplayListForChildren(aBuilder, aDirtyRect, set);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
return WrapListsInRedirector(aBuilder, set, aLists);
|
1999-07-20 08:19:47 +00:00
|
|
|
}
|
1999-07-20 09:35:35 +00:00
|
|
|
|
2007-07-04 15:49:38 +00:00
|
|
|
NS_IMETHODIMP
|
2004-07-31 23:15:21 +00:00
|
|
|
nsMenuFrame::HandleEvent(nsPresContext* aPresContext,
|
2007-07-04 15:49:38 +00:00
|
|
|
nsGUIEvent* aEvent,
|
|
|
|
nsEventStatus* aEventStatus)
|
1999-07-20 09:35:35 +00:00
|
|
|
{
|
1999-11-24 06:03:41 +00:00
|
|
|
NS_ENSURE_ARG_POINTER(aEventStatus);
|
2009-02-27 10:48:25 +00:00
|
|
|
if (nsEventStatus_eConsumeNoDefault == *aEventStatus) {
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2006-09-03 20:25:58 +00:00
|
|
|
nsWeakFrame weakFrame(this);
|
2004-08-19 18:36:42 +00:00
|
|
|
if (*aEventStatus == nsEventStatus_eIgnore)
|
|
|
|
*aEventStatus = nsEventStatus_eConsumeDoDefault;
|
2007-07-04 15:49:38 +00:00
|
|
|
|
|
|
|
PRBool onmenu = IsOnMenu();
|
|
|
|
|
2000-03-13 10:37:57 +00:00
|
|
|
if (aEvent->message == NS_KEY_PRESS && !IsDisabled()) {
|
2000-02-25 08:37:49 +00:00
|
|
|
nsKeyEvent* keyEvent = (nsKeyEvent*)aEvent;
|
|
|
|
PRUint32 keyCode = keyEvent->keyCode;
|
2005-03-23 10:43:45 +00:00
|
|
|
#ifdef XP_MACOSX
|
|
|
|
// On mac, open menulist on either up/down arrow or space (w/o Cmd pressed)
|
|
|
|
if (!IsOpen() && ((keyEvent->charCode == NS_VK_SPACE && !keyEvent->isMeta) ||
|
2009-05-01 12:24:49 +00:00
|
|
|
(keyCode == NS_VK_UP || keyCode == NS_VK_DOWN))) {
|
|
|
|
*aEventStatus = nsEventStatus_eConsumeNoDefault;
|
2007-07-04 15:49:38 +00:00
|
|
|
OpenMenu(PR_FALSE);
|
2009-05-01 12:24:49 +00:00
|
|
|
}
|
2005-03-23 10:43:45 +00:00
|
|
|
#else
|
|
|
|
// On other platforms, toggle menulist on unmodified F4 or Alt arrow
|
2004-07-03 21:00:07 +00:00
|
|
|
if ((keyCode == NS_VK_F4 && !keyEvent->isAlt) ||
|
2009-05-01 12:24:49 +00:00
|
|
|
((keyCode == NS_VK_UP || keyCode == NS_VK_DOWN) && keyEvent->isAlt)) {
|
|
|
|
*aEventStatus = nsEventStatus_eConsumeNoDefault;
|
2007-07-04 15:49:38 +00:00
|
|
|
ToggleMenuState();
|
2009-05-01 12:24:49 +00:00
|
|
|
}
|
2005-03-23 10:43:45 +00:00
|
|
|
#endif
|
2000-02-25 08:37:49 +00:00
|
|
|
}
|
2006-11-16 21:35:39 +00:00
|
|
|
else if (aEvent->eventStructType == NS_MOUSE_EVENT &&
|
|
|
|
aEvent->message == NS_MOUSE_BUTTON_DOWN &&
|
2007-07-08 07:08:04 +00:00
|
|
|
static_cast<nsMouseEvent*>(aEvent)->button == nsMouseEvent::eLeftButton &&
|
2006-11-16 21:35:39 +00:00
|
|
|
!IsDisabled() && IsMenu()) {
|
1999-09-01 00:39:12 +00:00
|
|
|
// The menu item was selected. Bring up the menu.
|
|
|
|
// We have children.
|
2009-06-04 02:43:03 +00:00
|
|
|
// Don't prevent the default action here, since that will also cancel
|
|
|
|
// potential drag starts.
|
2007-07-04 15:49:38 +00:00
|
|
|
if (!mMenuParent || mMenuParent->IsMenuBar()) {
|
1999-07-31 11:29:03 +00:00
|
|
|
ToggleMenuState();
|
1999-07-20 09:35:35 +00:00
|
|
|
}
|
2007-07-04 15:49:38 +00:00
|
|
|
else {
|
2009-05-01 12:24:49 +00:00
|
|
|
if (!IsOpen()) {
|
2007-07-04 15:49:38 +00:00
|
|
|
OpenMenu(PR_FALSE);
|
2009-05-01 12:24:49 +00:00
|
|
|
}
|
2007-07-04 15:49:38 +00:00
|
|
|
}
|
1999-07-20 09:35:35 +00:00
|
|
|
}
|
2001-03-29 03:33:09 +00:00
|
|
|
else if (
|
|
|
|
#ifndef NSCONTEXTMENUISMOUSEUP
|
2006-11-16 21:35:39 +00:00
|
|
|
(aEvent->eventStructType == NS_MOUSE_EVENT &&
|
|
|
|
aEvent->message == NS_MOUSE_BUTTON_UP &&
|
2007-07-08 07:08:04 +00:00
|
|
|
static_cast<nsMouseEvent*>(aEvent)->button ==
|
2006-11-16 21:35:39 +00:00
|
|
|
nsMouseEvent::eRightButton) &&
|
2001-03-29 03:33:09 +00:00
|
|
|
#else
|
|
|
|
aEvent->message == NS_CONTEXTMENU &&
|
|
|
|
#endif
|
2007-07-04 15:49:38 +00:00
|
|
|
onmenu && !IsMenu() && !IsDisabled()) {
|
2000-03-01 03:12:51 +00:00
|
|
|
// if this menu is a context menu it accepts right-clicks...fire away!
|
2001-03-29 03:33:09 +00:00
|
|
|
// Make sure we cancel default processing of the context menu event so
|
|
|
|
// that it doesn't bubble and get seen again by the popuplistener and show
|
|
|
|
// another context menu.
|
|
|
|
//
|
|
|
|
// Furthermore (there's always more, isn't there?), on some platforms (win32
|
|
|
|
// being one of them) we get the context menu event on a mouse up while
|
|
|
|
// on others we get it on a mouse down. For the ones where we get it on a
|
|
|
|
// mouse down, we must continue listening for the right button up event to
|
|
|
|
// dismiss the menu.
|
2007-07-04 15:49:38 +00:00
|
|
|
if (mMenuParent->IsContextMenu()) {
|
2001-03-29 03:33:09 +00:00
|
|
|
*aEventStatus = nsEventStatus_eConsumeNoDefault;
|
2002-09-26 23:21:59 +00:00
|
|
|
Execute(aEvent);
|
2001-03-29 03:33:09 +00:00
|
|
|
}
|
2000-03-01 03:12:51 +00:00
|
|
|
}
|
2006-11-16 21:35:39 +00:00
|
|
|
else if (aEvent->eventStructType == NS_MOUSE_EVENT &&
|
|
|
|
aEvent->message == NS_MOUSE_BUTTON_UP &&
|
2007-07-08 07:08:04 +00:00
|
|
|
static_cast<nsMouseEvent*>(aEvent)->button == nsMouseEvent::eLeftButton &&
|
2007-07-04 15:49:38 +00:00
|
|
|
!IsMenu() && !IsDisabled()) {
|
1999-07-31 01:43:33 +00:00
|
|
|
// Execute the execute event handler.
|
2009-05-01 12:24:49 +00:00
|
|
|
*aEventStatus = nsEventStatus_eConsumeNoDefault;
|
2002-09-26 23:21:59 +00:00
|
|
|
Execute(aEvent);
|
1999-07-24 01:59:32 +00:00
|
|
|
}
|
2000-04-24 04:41:27 +00:00
|
|
|
else if (aEvent->message == NS_MOUSE_EXIT_SYNTH) {
|
1999-07-25 00:16:11 +00:00
|
|
|
// Kill our timer if one is active.
|
|
|
|
if (mOpenTimer) {
|
|
|
|
mOpenTimer->Cancel();
|
|
|
|
mOpenTimer = nsnull;
|
|
|
|
}
|
|
|
|
|
1999-07-21 07:42:16 +00:00
|
|
|
// Deactivate the menu.
|
1999-07-23 08:36:39 +00:00
|
|
|
if (mMenuParent) {
|
2007-07-04 15:49:38 +00:00
|
|
|
PRBool onmenubar = mMenuParent->IsMenuBar();
|
|
|
|
if (!(onmenubar && mMenuParent->IsActive())) {
|
|
|
|
if (IsMenu() && !onmenubar && IsOpen()) {
|
2000-02-13 08:33:39 +00:00
|
|
|
// Submenus don't get closed up immediately.
|
1999-07-26 04:38:28 +00:00
|
|
|
}
|
2007-10-02 09:41:29 +00:00
|
|
|
else if (this == mMenuParent->GetCurrentMenuItem()) {
|
2007-07-04 15:49:38 +00:00
|
|
|
mMenuParent->ChangeMenuItem(nsnull, PR_FALSE);
|
2007-10-02 09:41:29 +00:00
|
|
|
}
|
1999-07-26 04:38:28 +00:00
|
|
|
}
|
1999-07-23 08:36:39 +00:00
|
|
|
}
|
1999-07-21 07:42:16 +00:00
|
|
|
}
|
2007-07-04 15:49:38 +00:00
|
|
|
else if (aEvent->message == NS_MOUSE_MOVE &&
|
|
|
|
(onmenu || (mMenuParent && mMenuParent->IsMenuBar()))) {
|
1999-07-26 06:29:48 +00:00
|
|
|
if (gEatMouseMove) {
|
|
|
|
gEatMouseMove = PR_FALSE;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
1999-08-02 07:26:24 +00:00
|
|
|
// Let the menu parent know we're the new item.
|
2007-07-04 15:49:38 +00:00
|
|
|
mMenuParent->ChangeMenuItem(this, PR_FALSE);
|
2006-09-03 20:25:58 +00:00
|
|
|
NS_ENSURE_TRUE(weakFrame.IsAlive(), NS_OK);
|
|
|
|
NS_ENSURE_TRUE(mMenuParent, NS_OK);
|
2007-07-04 15:49:38 +00:00
|
|
|
|
2005-09-28 18:48:27 +00:00
|
|
|
// we need to check if we really became the current menu
|
|
|
|
// item or not
|
2007-07-04 15:49:38 +00:00
|
|
|
nsMenuFrame *realCurrentItem = mMenuParent->GetCurrentMenuItem();
|
2005-09-28 18:48:27 +00:00
|
|
|
if (realCurrentItem != this) {
|
|
|
|
// we didn't (presumably because a context menu was active)
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2007-07-04 15:49:38 +00:00
|
|
|
// Hovering over a menu in a popup should open it without a need for a click.
|
|
|
|
// A timer is used so that it doesn't open if the user moves the mouse quickly
|
|
|
|
// past the menu. This conditional check ensures that only menus have this
|
|
|
|
// behaviour
|
|
|
|
if (!IsDisabled() && IsMenu() && !IsOpen() && !mOpenTimer && !mMenuParent->IsMenuBar()) {
|
2000-02-13 08:33:39 +00:00
|
|
|
PRInt32 menuDelay = 300; // ms
|
2000-01-21 21:56:09 +00:00
|
|
|
|
2004-10-28 07:25:57 +00:00
|
|
|
nsCOMPtr<nsILookAndFeel> lookAndFeel(do_GetService(kLookAndFeelCID));
|
2001-01-09 01:28:36 +00:00
|
|
|
if (lookAndFeel)
|
2000-01-21 21:56:09 +00:00
|
|
|
lookAndFeel->GetMetric(nsILookAndFeel::eMetric_SubmenuDelay, menuDelay);
|
|
|
|
|
|
|
|
// We're a menu, we're built, we're closed, and no timer has been kicked off.
|
2000-09-13 23:57:52 +00:00
|
|
|
mOpenTimer = do_CreateInstance("@mozilla.org/timer;1");
|
2006-01-12 16:40:47 +00:00
|
|
|
mOpenTimer->InitWithCallback(mTimerMediator, menuDelay, nsITimer::TYPE_ONE_SHOT);
|
1999-07-25 01:14:43 +00:00
|
|
|
}
|
1999-07-21 07:42:16 +00:00
|
|
|
}
|
2000-08-16 23:14:50 +00:00
|
|
|
|
1999-07-20 09:35:35 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2007-07-04 15:49:38 +00:00
|
|
|
void
|
1999-07-20 09:35:35 +00:00
|
|
|
nsMenuFrame::ToggleMenuState()
|
2007-06-29 19:04:45 +00:00
|
|
|
{
|
2007-07-04 15:49:38 +00:00
|
|
|
if (IsOpen())
|
|
|
|
CloseMenu(PR_FALSE);
|
2007-12-03 16:33:42 +00:00
|
|
|
else
|
2007-06-29 22:15:59 +00:00
|
|
|
OpenMenu(PR_FALSE);
|
2007-07-04 15:49:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsMenuFrame::PopupOpened()
|
|
|
|
{
|
|
|
|
nsWeakFrame weakFrame(this);
|
|
|
|
mContent->SetAttr(kNameSpaceID_None, nsGkAtoms::open,
|
|
|
|
NS_LITERAL_STRING("true"), PR_TRUE);
|
|
|
|
if (!weakFrame.IsAlive())
|
|
|
|
return;
|
2003-01-20 11:58:30 +00:00
|
|
|
|
|
|
|
if (mMenuParent) {
|
2007-07-04 15:49:38 +00:00
|
|
|
mMenuParent->SetActive(PR_TRUE);
|
2003-01-20 11:58:30 +00:00
|
|
|
// Make sure the current menu which is being toggled on
|
|
|
|
// the menubar is highlighted
|
|
|
|
mMenuParent->SetCurrentMenuItem(this);
|
1999-07-21 07:42:16 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-07-04 15:49:38 +00:00
|
|
|
void
|
|
|
|
nsMenuFrame::PopupClosed(PRBool aDeselectMenu)
|
1999-07-21 07:42:16 +00:00
|
|
|
{
|
2006-09-03 20:25:58 +00:00
|
|
|
nsWeakFrame weakFrame(this);
|
2008-12-03 10:56:58 +00:00
|
|
|
nsContentUtils::AddScriptRunner(
|
|
|
|
new nsUnsetAttrRunnable(mContent, nsGkAtoms::open));
|
2007-07-04 15:49:38 +00:00
|
|
|
if (!weakFrame.IsAlive())
|
|
|
|
return;
|
1999-09-21 01:03:00 +00:00
|
|
|
|
2007-07-04 15:49:38 +00:00
|
|
|
// if the popup is for a menu on a menubar, inform menubar to deactivate
|
|
|
|
if (mMenuParent && mMenuParent->MenuClosed()) {
|
2007-07-26 04:14:32 +00:00
|
|
|
if (aDeselectMenu) {
|
2007-07-04 15:49:38 +00:00
|
|
|
SelectMenu(PR_FALSE);
|
2007-07-26 04:14:32 +00:00
|
|
|
} else {
|
|
|
|
// We are not deselecting the parent menu while closing the popup, so send
|
|
|
|
// a DOMMenuItemActive event to the menu to indicate that the menu is
|
|
|
|
// becoming active again.
|
|
|
|
nsMenuFrame *current = mMenuParent->GetCurrentMenuItem();
|
|
|
|
if (current) {
|
|
|
|
nsCOMPtr<nsIRunnable> event =
|
|
|
|
new nsMenuActivateEvent(current->GetContent(),
|
|
|
|
PresContext(), PR_TRUE);
|
|
|
|
NS_DispatchToCurrentThread(event);
|
|
|
|
}
|
2007-07-04 15:49:38 +00:00
|
|
|
}
|
2000-05-15 04:12:31 +00:00
|
|
|
}
|
2007-07-26 04:14:32 +00:00
|
|
|
}
|
1999-08-12 20:45:47 +00:00
|
|
|
|
2007-06-29 22:15:59 +00:00
|
|
|
NS_IMETHODIMP
|
2007-07-04 15:49:38 +00:00
|
|
|
nsMenuFrame::SelectMenu(PRBool aActivateFlag)
|
2007-06-29 22:15:59 +00:00
|
|
|
{
|
2007-07-04 15:49:38 +00:00
|
|
|
if (mContent) {
|
2007-07-11 12:05:40 +00:00
|
|
|
// When a menu opens a submenu, the mouse will often be moved onto a
|
|
|
|
// sibling before moving onto an item within the submenu, causing the
|
|
|
|
// parent to become deselected. We need to ensure that the parent menu
|
|
|
|
// is reselected when an item in the submenu is selected, so navigate up
|
|
|
|
// from the item to its popup, and then to the popup above that.
|
|
|
|
if (aActivateFlag) {
|
|
|
|
nsIFrame* parent = GetParent();
|
|
|
|
while (parent) {
|
|
|
|
if (parent->GetType() == nsGkAtoms::menuPopupFrame) {
|
|
|
|
// a menu is always the direct parent of a menupopup
|
|
|
|
parent = parent->GetParent();
|
|
|
|
if (parent && parent->GetType() == nsGkAtoms::menuFrame) {
|
|
|
|
// a popup however is not necessarily the direct parent of a menu
|
|
|
|
nsIFrame* popupParent = parent->GetParent();
|
|
|
|
while (popupParent) {
|
|
|
|
if (popupParent->GetType() == nsGkAtoms::menuPopupFrame) {
|
|
|
|
nsMenuPopupFrame* popup = static_cast<nsMenuPopupFrame *>(popupParent);
|
|
|
|
popup->SetCurrentMenuItem(static_cast<nsMenuFrame *>(parent));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
popupParent = popupParent->GetParent();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
parent = parent->GetParent();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// cancel the close timer if selecting a menu within the popup to be closed
|
|
|
|
nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
|
|
|
|
if (pm)
|
|
|
|
pm->CancelMenuTimer(mMenuParent);
|
|
|
|
|
2007-07-04 15:49:38 +00:00
|
|
|
nsCOMPtr<nsIRunnable> event =
|
|
|
|
new nsMenuActivateEvent(mContent, PresContext(), aActivateFlag);
|
|
|
|
NS_DispatchToCurrentThread(event);
|
2007-06-29 22:15:59 +00:00
|
|
|
}
|
2007-07-04 15:49:38 +00:00
|
|
|
|
2007-06-29 22:15:59 +00:00
|
|
|
return NS_OK;
|
2007-07-04 15:49:38 +00:00
|
|
|
}
|
2007-06-29 22:15:59 +00:00
|
|
|
|
1999-09-08 03:51:41 +00:00
|
|
|
NS_IMETHODIMP
|
2005-09-07 16:49:21 +00:00
|
|
|
nsMenuFrame::AttributeChanged(PRInt32 aNameSpaceID,
|
1999-09-08 03:51:41 +00:00
|
|
|
nsIAtom* aAttribute,
|
2003-07-11 21:16:12 +00:00
|
|
|
PRInt32 aModType)
|
1999-09-08 03:51:41 +00:00
|
|
|
{
|
1999-09-17 20:12:02 +00:00
|
|
|
nsAutoString value;
|
|
|
|
|
2006-12-26 17:47:52 +00:00
|
|
|
if (aAttribute == nsGkAtoms::checked) {
|
1999-10-17 21:37:37 +00:00
|
|
|
if (mType != eMenuType_Normal)
|
2007-03-30 21:11:41 +00:00
|
|
|
UpdateMenuSpecialState(PresContext());
|
2006-12-26 17:47:52 +00:00
|
|
|
} else if (aAttribute == nsGkAtoms::acceltext) {
|
2001-10-11 03:03:42 +00:00
|
|
|
// someone reset the accelText attribute, so clear the bit that says *we* set it
|
2003-08-04 12:39:51 +00:00
|
|
|
AddStateBits(NS_STATE_ACCELTEXT_IS_DERIVED);
|
2001-10-11 03:03:42 +00:00
|
|
|
BuildAcceleratorText();
|
2006-12-26 17:47:52 +00:00
|
|
|
} else if (aAttribute == nsGkAtoms::key) {
|
2001-10-11 03:03:42 +00:00
|
|
|
BuildAcceleratorText();
|
2007-07-04 15:49:38 +00:00
|
|
|
} else if (aAttribute == nsGkAtoms::type || aAttribute == nsGkAtoms::name)
|
2007-03-30 21:11:41 +00:00
|
|
|
UpdateMenuType(PresContext());
|
1999-09-17 20:12:02 +00:00
|
|
|
|
1999-09-08 03:51:41 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2007-07-04 15:49:38 +00:00
|
|
|
void
|
|
|
|
nsMenuFrame::OpenMenu(PRBool aSelectFirstItem)
|
1999-09-08 03:51:41 +00:00
|
|
|
{
|
2002-06-28 03:10:08 +00:00
|
|
|
if (!mContent)
|
2007-06-29 22:15:59 +00:00
|
|
|
return;
|
|
|
|
|
2007-07-04 15:49:38 +00:00
|
|
|
gEatMouseMove = PR_TRUE;
|
2007-06-29 22:15:59 +00:00
|
|
|
|
2007-07-04 15:49:38 +00:00
|
|
|
nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
|
|
|
|
if (pm) {
|
|
|
|
pm->KillMenuTimer();
|
|
|
|
// This opens the menu asynchronously
|
|
|
|
pm->ShowMenu(mContent, aSelectFirstItem, PR_TRUE);
|
2007-06-29 22:15:59 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2007-07-04 15:49:38 +00:00
|
|
|
nsMenuFrame::CloseMenu(PRBool aDeselectMenu)
|
2007-06-29 22:15:59 +00:00
|
|
|
{
|
2007-07-04 15:49:38 +00:00
|
|
|
gEatMouseMove = PR_TRUE;
|
|
|
|
|
|
|
|
// Close the menu asynchronously
|
|
|
|
nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
|
|
|
|
if (pm && mPopupFrame)
|
|
|
|
pm->HidePopup(mPopupFrame->GetContent(), PR_FALSE, aDeselectMenu, PR_TRUE);
|
1999-07-20 09:35:35 +00:00
|
|
|
}
|
|
|
|
|
2002-03-17 23:41:22 +00:00
|
|
|
PRBool
|
|
|
|
nsMenuFrame::IsSizedToPopup(nsIContent* aContent, PRBool aRequireAlways)
|
|
|
|
{
|
|
|
|
PRBool sizeToPopup;
|
2006-12-26 17:47:52 +00:00
|
|
|
if (aContent->Tag() == nsGkAtoms::select)
|
2002-03-17 23:41:22 +00:00
|
|
|
sizeToPopup = PR_TRUE;
|
|
|
|
else {
|
|
|
|
nsAutoString sizedToPopup;
|
2006-12-26 17:47:52 +00:00
|
|
|
aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::sizetopopup, sizedToPopup);
|
2004-04-30 13:23:43 +00:00
|
|
|
sizeToPopup = sizedToPopup.EqualsLiteral("always") ||
|
2008-09-15 15:40:25 +00:00
|
|
|
(!aRequireAlways && sizedToPopup.EqualsLiteral("pref"));
|
2002-03-17 23:41:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return sizeToPopup;
|
|
|
|
}
|
|
|
|
|
2007-01-08 02:57:59 +00:00
|
|
|
nsSize
|
|
|
|
nsMenuFrame::GetMinSize(nsBoxLayoutState& aBoxLayoutState)
|
2002-02-28 07:28:39 +00:00
|
|
|
{
|
2007-01-08 02:57:59 +00:00
|
|
|
nsSize size = nsBoxFrame::GetMinSize(aBoxLayoutState);
|
|
|
|
DISPLAY_MIN_SIZE(this, size);
|
2002-02-28 07:28:39 +00:00
|
|
|
|
2005-06-25 09:35:05 +00:00
|
|
|
if (IsSizedToPopup(mContent, PR_TRUE))
|
2007-01-08 02:57:59 +00:00
|
|
|
SizeToPopup(aBoxLayoutState, size);
|
2002-02-28 07:28:39 +00:00
|
|
|
|
2007-01-08 02:57:59 +00:00
|
|
|
return size;
|
2002-02-28 07:28:39 +00:00
|
|
|
}
|
|
|
|
|
2000-03-31 07:02:06 +00:00
|
|
|
NS_IMETHODIMP
|
2000-07-07 22:24:06 +00:00
|
|
|
nsMenuFrame::DoLayout(nsBoxLayoutState& aState)
|
2000-03-31 07:02:06 +00:00
|
|
|
{
|
|
|
|
// lay us out
|
2000-07-07 22:24:06 +00:00
|
|
|
nsresult rv = nsBoxFrame::DoLayout(aState);
|
2000-03-31 07:02:06 +00:00
|
|
|
|
|
|
|
// layout the popup. First we need to get it.
|
2007-07-04 15:49:38 +00:00
|
|
|
if (mPopupFrame) {
|
2002-03-17 23:41:22 +00:00
|
|
|
PRBool sizeToPopup = IsSizedToPopup(mContent, PR_FALSE);
|
2000-03-31 07:02:06 +00:00
|
|
|
// then get its preferred size
|
2007-07-04 15:49:38 +00:00
|
|
|
nsSize prefSize = mPopupFrame->GetPrefSize(aState);
|
|
|
|
nsSize minSize = mPopupFrame->GetMinSize(aState);
|
|
|
|
nsSize maxSize = mPopupFrame->GetMaxSize(aState);
|
2000-03-31 07:02:06 +00:00
|
|
|
|
2008-01-05 05:49:44 +00:00
|
|
|
prefSize = BoundsCheck(minSize, prefSize, maxSize);
|
2000-03-31 07:02:06 +00:00
|
|
|
|
2001-11-27 00:03:36 +00:00
|
|
|
if (sizeToPopup)
|
2007-01-31 16:02:42 +00:00
|
|
|
prefSize.width = mRect.width;
|
2000-03-31 07:02:06 +00:00
|
|
|
|
2000-05-15 04:12:31 +00:00
|
|
|
// if the pref size changed then set bounds to be the pref size
|
2007-12-19 16:37:32 +00:00
|
|
|
PRBool sizeChanged = (mPopupFrame->PreferredSize() != prefSize);
|
2007-07-04 15:49:38 +00:00
|
|
|
if (sizeChanged) {
|
2007-12-19 16:37:32 +00:00
|
|
|
mPopupFrame->SetPreferredBounds(aState, nsRect(0,0,prefSize.width, prefSize.height));
|
2000-05-15 04:12:31 +00:00
|
|
|
}
|
|
|
|
|
2007-07-04 15:49:38 +00:00
|
|
|
// if the menu has just been opened, or its size changed, position
|
|
|
|
// the popup. The flag that the popup checks in the HasOpenChanged
|
|
|
|
// method will get cleared in AdjustView which is called below.
|
|
|
|
if (IsOpen() && (sizeChanged || mPopupFrame->HasOpenChanged()))
|
2010-02-01 15:11:08 +00:00
|
|
|
mPopupFrame->SetPopupPosition(this, PR_FALSE);
|
2007-07-04 15:49:38 +00:00
|
|
|
|
2000-05-15 04:12:31 +00:00
|
|
|
// is the new size too small? Make sure we handle scrollbars correctly
|
2007-07-04 15:49:38 +00:00
|
|
|
nsIBox* child = mPopupFrame->GetChildBox();
|
2000-05-15 04:12:31 +00:00
|
|
|
|
2007-07-04 15:49:38 +00:00
|
|
|
nsRect bounds(mPopupFrame->GetRect());
|
2000-05-15 04:12:31 +00:00
|
|
|
|
2009-01-12 19:20:59 +00:00
|
|
|
nsIScrollableFrame *scrollframe = do_QueryFrame(child);
|
2004-09-03 00:43:46 +00:00
|
|
|
if (scrollframe &&
|
|
|
|
scrollframe->GetScrollbarStyles().mVertical == NS_STYLE_OVERFLOW_AUTO) {
|
|
|
|
if (bounds.height < prefSize.height) {
|
|
|
|
// layout the child
|
2007-07-04 15:49:38 +00:00
|
|
|
mPopupFrame->Layout(aState);
|
2004-09-03 00:43:46 +00:00
|
|
|
|
|
|
|
nsMargin scrollbars = scrollframe->GetActualScrollbarSizes();
|
|
|
|
if (bounds.width < prefSize.width + scrollbars.left + scrollbars.right)
|
|
|
|
{
|
|
|
|
bounds.width += scrollbars.left + scrollbars.right;
|
2007-07-04 15:49:38 +00:00
|
|
|
mPopupFrame->SetBounds(aState, bounds);
|
2000-05-15 04:12:31 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2007-06-29 22:15:59 +00:00
|
|
|
|
2007-07-04 15:49:38 +00:00
|
|
|
// layout the child
|
|
|
|
mPopupFrame->Layout(aState);
|
|
|
|
mPopupFrame->AdjustView();
|
2000-03-31 07:02:06 +00:00
|
|
|
}
|
|
|
|
|
2000-05-15 04:12:31 +00:00
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
2004-06-19 09:07:47 +00:00
|
|
|
#ifdef DEBUG_LAYOUT
|
2000-03-02 03:01:30 +00:00
|
|
|
NS_IMETHODIMP
|
2000-03-31 07:02:06 +00:00
|
|
|
nsMenuFrame::SetDebug(nsBoxLayoutState& aState, PRBool aDebug)
|
2000-03-02 03:01:30 +00:00
|
|
|
{
|
|
|
|
// see if our state matches the given debug state
|
|
|
|
PRBool debugSet = mState & NS_STATE_CURRENTLY_IN_DEBUG;
|
|
|
|
PRBool debugChanged = (!aDebug && debugSet) || (aDebug && !debugSet);
|
|
|
|
|
|
|
|
// if it doesn't then tell each child below us the new debug state
|
|
|
|
if (debugChanged)
|
|
|
|
{
|
2000-03-31 07:02:06 +00:00
|
|
|
nsBoxFrame::SetDebug(aState, aDebug);
|
2007-07-04 15:49:38 +00:00
|
|
|
if (mPopupFrame)
|
|
|
|
SetDebug(aState, mPopupFrame, aDebug);
|
2000-03-02 03:01:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
2000-03-31 07:02:06 +00:00
|
|
|
nsMenuFrame::SetDebug(nsBoxLayoutState& aState, nsIFrame* aList, PRBool aDebug)
|
2000-03-02 03:01:30 +00:00
|
|
|
{
|
|
|
|
if (!aList)
|
|
|
|
return NS_OK;
|
|
|
|
|
|
|
|
while (aList) {
|
2004-09-28 18:37:50 +00:00
|
|
|
if (aList->IsBoxFrame())
|
|
|
|
aList->SetDebug(aState, aDebug);
|
2000-03-02 03:01:30 +00:00
|
|
|
|
2004-09-28 18:37:50 +00:00
|
|
|
aList = aList->GetNextSibling();
|
2000-03-02 03:01:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
2004-06-19 09:07:47 +00:00
|
|
|
#endif
|
2000-03-02 03:01:30 +00:00
|
|
|
|
2000-08-25 01:59:53 +00:00
|
|
|
//
|
|
|
|
// Enter
|
|
|
|
//
|
|
|
|
// Called when the user hits the <Enter>/<Return> keys or presses the
|
|
|
|
// shortcut key. If this is a leaf item, the item's action will be executed.
|
|
|
|
// In either case, do nothing if the item is disabled.
|
|
|
|
//
|
2007-07-04 15:49:38 +00:00
|
|
|
nsMenuFrame*
|
1999-07-24 22:02:23 +00:00
|
|
|
nsMenuFrame::Enter()
|
|
|
|
{
|
2002-02-15 03:53:26 +00:00
|
|
|
if (IsDisabled()) {
|
|
|
|
#ifdef XP_WIN
|
|
|
|
// behavior on Windows - close the popup chain
|
2007-07-04 15:49:38 +00:00
|
|
|
if (mMenuParent) {
|
|
|
|
nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
|
2007-09-18 15:00:43 +00:00
|
|
|
if (pm) {
|
|
|
|
nsIFrame* popup = pm->GetTopPopup(ePopupTypeAny);
|
|
|
|
if (popup)
|
|
|
|
pm->HidePopup(popup->GetContent(), PR_TRUE, PR_TRUE, PR_TRUE);
|
|
|
|
}
|
2007-07-04 15:49:38 +00:00
|
|
|
}
|
2002-02-15 03:53:26 +00:00
|
|
|
#endif // #ifdef XP_WIN
|
|
|
|
// this menu item was disabled - exit
|
2007-07-04 15:49:38 +00:00
|
|
|
return nsnull;
|
2002-02-15 03:53:26 +00:00
|
|
|
}
|
2007-07-04 15:49:38 +00:00
|
|
|
|
|
|
|
if (!IsOpen()) {
|
1999-07-24 22:02:23 +00:00
|
|
|
// The enter key press applies to us.
|
2000-08-25 01:59:53 +00:00
|
|
|
if (!IsMenu() && mMenuParent)
|
2002-09-26 23:21:59 +00:00
|
|
|
Execute(0); // Execute our event handler
|
2007-07-04 15:49:38 +00:00
|
|
|
else
|
|
|
|
return this;
|
2007-06-29 22:15:59 +00:00
|
|
|
}
|
|
|
|
|
2007-07-04 15:49:38 +00:00
|
|
|
return nsnull;
|
1999-07-24 22:02:23 +00:00
|
|
|
}
|
|
|
|
|
2007-07-04 15:49:38 +00:00
|
|
|
PRBool
|
|
|
|
nsMenuFrame::IsOpen()
|
1999-07-22 09:01:55 +00:00
|
|
|
{
|
2007-07-04 15:49:38 +00:00
|
|
|
return mPopupFrame && mPopupFrame->IsOpen();
|
1999-07-25 00:16:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
PRBool
|
|
|
|
nsMenuFrame::IsMenu()
|
|
|
|
{
|
2000-03-13 10:20:34 +00:00
|
|
|
return mIsMenu;
|
1999-07-25 01:14:43 +00:00
|
|
|
}
|
|
|
|
|
2006-01-12 16:40:47 +00:00
|
|
|
nsresult
|
1999-07-25 01:14:43 +00:00
|
|
|
nsMenuFrame::Notify(nsITimer* aTimer)
|
|
|
|
{
|
|
|
|
// Our timer has fired.
|
1999-07-26 04:38:28 +00:00
|
|
|
if (aTimer == mOpenTimer.get()) {
|
2007-07-04 15:49:38 +00:00
|
|
|
mOpenTimer = nsnull;
|
|
|
|
|
|
|
|
if (!IsOpen() && mMenuParent) {
|
2005-09-28 18:48:27 +00:00
|
|
|
// make sure we didn't open a context menu in the meantime
|
2005-09-30 17:35:14 +00:00
|
|
|
// (i.e. the user right-clicked while hovering over a submenu).
|
2007-07-04 15:49:38 +00:00
|
|
|
nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
|
|
|
|
if (pm) {
|
|
|
|
if ((!pm->HasContextMenu(nsnull) || mMenuParent->IsContextMenu()) &&
|
|
|
|
mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::menuactive,
|
2006-12-26 17:47:52 +00:00
|
|
|
nsGkAtoms::_true, eCaseMatters)) {
|
2007-07-04 15:49:38 +00:00
|
|
|
OpenMenu(PR_FALSE);
|
2005-09-28 18:48:27 +00:00
|
|
|
}
|
1999-07-26 04:38:28 +00:00
|
|
|
}
|
1999-07-25 01:14:43 +00:00
|
|
|
}
|
|
|
|
}
|
2007-07-04 15:49:38 +00:00
|
|
|
|
2002-09-07 05:38:16 +00:00
|
|
|
return NS_OK;
|
1999-07-25 01:14:43 +00:00
|
|
|
}
|
1999-07-26 01:35:39 +00:00
|
|
|
|
|
|
|
PRBool
|
|
|
|
nsMenuFrame::IsDisabled()
|
|
|
|
{
|
2006-12-26 17:47:52 +00:00
|
|
|
return mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::disabled,
|
|
|
|
nsGkAtoms::_true, eCaseMatters);
|
1999-07-26 01:35:39 +00:00
|
|
|
}
|
1999-07-31 01:43:33 +00:00
|
|
|
|
1999-10-15 21:13:24 +00:00
|
|
|
void
|
2004-07-31 23:15:21 +00:00
|
|
|
nsMenuFrame::UpdateMenuType(nsPresContext* aPresContext)
|
1999-10-15 21:13:24 +00:00
|
|
|
{
|
2006-04-24 05:40:11 +00:00
|
|
|
static nsIContent::AttrValuesArray strings[] =
|
2006-12-26 17:47:52 +00:00
|
|
|
{&nsGkAtoms::checkbox, &nsGkAtoms::radio, nsnull};
|
|
|
|
switch (mContent->FindAttrValueIn(kNameSpaceID_None, nsGkAtoms::type,
|
2006-04-24 05:40:11 +00:00
|
|
|
strings, eCaseMatters)) {
|
|
|
|
case 0: mType = eMenuType_Checkbox; break;
|
|
|
|
case 1:
|
|
|
|
mType = eMenuType_Radio;
|
2006-12-26 17:47:52 +00:00
|
|
|
mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::name, mGroupName);
|
2006-04-24 05:40:11 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
2006-09-03 20:25:58 +00:00
|
|
|
if (mType != eMenuType_Normal) {
|
|
|
|
nsWeakFrame weakFrame(this);
|
2006-12-26 17:47:52 +00:00
|
|
|
mContent->UnsetAttr(kNameSpaceID_None, nsGkAtoms::checked,
|
2006-04-24 05:40:11 +00:00
|
|
|
PR_TRUE);
|
2006-09-03 20:25:58 +00:00
|
|
|
ENSURE_TRUE(weakFrame.IsAlive());
|
|
|
|
}
|
2006-04-24 05:40:11 +00:00
|
|
|
mType = eMenuType_Normal;
|
|
|
|
break;
|
1999-10-15 21:13:24 +00:00
|
|
|
}
|
2000-01-22 01:16:50 +00:00
|
|
|
UpdateMenuSpecialState(aPresContext);
|
1999-10-15 21:13:24 +00:00
|
|
|
}
|
|
|
|
|
1999-10-17 21:37:37 +00:00
|
|
|
/* update checked-ness for type="checkbox" and type="radio" */
|
1999-10-15 21:13:24 +00:00
|
|
|
void
|
2007-07-04 15:49:38 +00:00
|
|
|
nsMenuFrame::UpdateMenuSpecialState(nsPresContext* aPresContext)
|
|
|
|
{
|
2006-04-24 05:40:11 +00:00
|
|
|
PRBool newChecked =
|
2006-12-26 17:47:52 +00:00
|
|
|
mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::checked,
|
|
|
|
nsGkAtoms::_true, eCaseMatters);
|
1999-10-17 21:37:37 +00:00
|
|
|
if (newChecked == mChecked) {
|
|
|
|
/* checked state didn't change */
|
|
|
|
|
|
|
|
if (mType != eMenuType_Radio)
|
|
|
|
return; // only Radio possibly cares about other kinds of change
|
|
|
|
|
2004-05-06 20:39:21 +00:00
|
|
|
if (!mChecked || mGroupName.IsEmpty())
|
1999-10-17 21:37:37 +00:00
|
|
|
return; // no interesting change
|
|
|
|
} else {
|
|
|
|
mChecked = newChecked;
|
|
|
|
if (mType != eMenuType_Radio || !mChecked)
|
|
|
|
/*
|
|
|
|
* Unchecking something requires no further changes, and only
|
|
|
|
* menuRadio has to do additional work when checked.
|
|
|
|
*/
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If we get this far, we're type=radio, and:
|
|
|
|
* - our name= changed, or
|
|
|
|
* - we went from checked="false" to checked="true"
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Behavioural note:
|
|
|
|
* If we're checked and renamed _into_ an existing radio group, we are
|
|
|
|
* made the new checked item, and we unselect the previous one.
|
|
|
|
*
|
|
|
|
* The only other reasonable behaviour would be to check for another selected
|
|
|
|
* item in that group. If found, unselect ourselves, otherwise we're the
|
|
|
|
* selected item. That, however, would be a lot more work, and I don't think
|
|
|
|
* it's better at all.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* walk siblings, looking for the other checked item with the same name */
|
2000-02-22 01:50:48 +00:00
|
|
|
// get the first sibling in this menu popup. This frame may be it, and if we're
|
|
|
|
// being called at creation time, this frame isn't yet in the parent's child list.
|
|
|
|
// All I'm saying is that this may fail, but it's most likely alright.
|
2004-01-09 14:20:53 +00:00
|
|
|
nsIFrame* sib = GetParent()->GetFirstChild(nsnull);
|
1999-10-17 21:37:37 +00:00
|
|
|
|
2007-07-04 15:49:38 +00:00
|
|
|
while (sib) {
|
|
|
|
if (sib != this && sib->GetType() == nsGkAtoms::menuFrame) {
|
2007-07-08 07:08:04 +00:00
|
|
|
nsMenuFrame* menu = static_cast<nsMenuFrame*>(sib);
|
2007-07-04 15:49:38 +00:00
|
|
|
if (menu->GetMenuType() == eMenuType_Radio &&
|
|
|
|
menu->IsChecked() &&
|
|
|
|
(menu->GetRadioGroupName() == mGroupName)) {
|
|
|
|
/* uncheck the old item */
|
|
|
|
sib->GetContent()->UnsetAttr(kNameSpaceID_None, nsGkAtoms::checked,
|
|
|
|
PR_TRUE);
|
|
|
|
/* XXX in DEBUG, check to make sure that there aren't two checked items */
|
|
|
|
return;
|
|
|
|
}
|
1999-10-17 21:37:37 +00:00
|
|
|
}
|
|
|
|
|
2007-07-04 15:49:38 +00:00
|
|
|
sib = sib->GetNextSibling();
|
|
|
|
}
|
1999-10-15 21:13:24 +00:00
|
|
|
}
|
|
|
|
|
1999-07-31 01:43:33 +00:00
|
|
|
void
|
2001-10-11 03:03:42 +00:00
|
|
|
nsMenuFrame::BuildAcceleratorText()
|
1999-07-31 01:43:33 +00:00
|
|
|
{
|
2000-03-28 00:41:33 +00:00
|
|
|
nsAutoString accelText;
|
2001-10-11 03:03:42 +00:00
|
|
|
|
2003-08-04 12:39:51 +00:00
|
|
|
if ((GetStateBits() & NS_STATE_ACCELTEXT_IS_DERIVED) == 0) {
|
2006-12-26 17:47:52 +00:00
|
|
|
mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::acceltext, accelText);
|
2001-10-11 03:03:42 +00:00
|
|
|
if (!accelText.IsEmpty())
|
|
|
|
return;
|
1999-07-31 01:43:33 +00:00
|
|
|
}
|
2001-10-11 03:03:42 +00:00
|
|
|
// accelText is definitely empty here.
|
|
|
|
|
|
|
|
// Now we're going to compute the accelerator text, so remember that we did.
|
2003-08-04 12:39:51 +00:00
|
|
|
AddStateBits(NS_STATE_ACCELTEXT_IS_DERIVED);
|
2001-10-11 03:03:42 +00:00
|
|
|
|
|
|
|
// If anything below fails, just leave the accelerator text blank.
|
2006-09-03 20:25:58 +00:00
|
|
|
nsWeakFrame weakFrame(this);
|
2006-12-26 17:47:52 +00:00
|
|
|
mContent->UnsetAttr(kNameSpaceID_None, nsGkAtoms::acceltext, PR_FALSE);
|
2006-09-03 20:25:58 +00:00
|
|
|
ENSURE_TRUE(weakFrame.IsAlive());
|
1999-07-31 01:43:33 +00:00
|
|
|
|
|
|
|
// See if we have a key node and use that instead.
|
2000-03-28 00:41:33 +00:00
|
|
|
nsAutoString keyValue;
|
2006-12-26 17:47:52 +00:00
|
|
|
mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::key, keyValue);
|
2000-07-28 21:48:08 +00:00
|
|
|
if (keyValue.IsEmpty())
|
|
|
|
return;
|
|
|
|
|
2003-03-26 07:41:30 +00:00
|
|
|
// Turn the document into a DOM document so we can use getElementById
|
2003-07-28 21:25:13 +00:00
|
|
|
nsCOMPtr<nsIDOMDocument> domDocument(do_QueryInterface(mContent->GetDocument()));
|
2003-03-26 07:41:30 +00:00
|
|
|
if (!domDocument)
|
1999-07-31 01:43:33 +00:00
|
|
|
return;
|
|
|
|
|
2001-01-09 01:28:36 +00:00
|
|
|
nsCOMPtr<nsIDOMElement> keyDOMElement;
|
2003-03-26 07:41:30 +00:00
|
|
|
domDocument->GetElementById(keyValue, getter_AddRefs(keyDOMElement));
|
2007-02-24 05:42:36 +00:00
|
|
|
if (!keyDOMElement) {
|
|
|
|
#ifdef DEBUG
|
|
|
|
nsAutoString label;
|
|
|
|
mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::label, label);
|
|
|
|
nsAutoString msg = NS_LITERAL_STRING("Key '") +
|
|
|
|
keyValue +
|
|
|
|
NS_LITERAL_STRING("' of menu item '") +
|
|
|
|
label +
|
|
|
|
NS_LITERAL_STRING("' could not be found");
|
|
|
|
NS_WARNING(NS_ConvertUTF16toUTF8(msg).get());
|
|
|
|
#endif
|
2001-01-09 01:28:36 +00:00
|
|
|
return;
|
2007-02-24 05:42:36 +00:00
|
|
|
}
|
2001-01-09 01:28:36 +00:00
|
|
|
|
|
|
|
nsCOMPtr<nsIContent> keyElement(do_QueryInterface(keyDOMElement));
|
1999-07-31 01:43:33 +00:00
|
|
|
if (!keyElement)
|
|
|
|
return;
|
2000-08-17 00:09:16 +00:00
|
|
|
|
2001-01-09 01:28:36 +00:00
|
|
|
// get the string to display as accelerator text
|
|
|
|
// check the key element's attributes in this order:
|
|
|
|
// |keytext|, |key|, |keycode|
|
|
|
|
nsAutoString accelString;
|
2006-12-26 17:47:52 +00:00
|
|
|
keyElement->GetAttr(kNameSpaceID_None, nsGkAtoms::keytext, accelString);
|
2001-01-09 01:28:36 +00:00
|
|
|
|
|
|
|
if (accelString.IsEmpty()) {
|
2006-12-26 17:47:52 +00:00
|
|
|
keyElement->GetAttr(kNameSpaceID_None, nsGkAtoms::key, accelString);
|
2001-01-09 01:28:36 +00:00
|
|
|
|
|
|
|
if (!accelString.IsEmpty()) {
|
2001-12-17 07:14:49 +00:00
|
|
|
ToUpperCase(accelString);
|
2001-01-09 01:28:36 +00:00
|
|
|
} else {
|
|
|
|
nsAutoString keyCode;
|
2006-12-26 17:47:52 +00:00
|
|
|
keyElement->GetAttr(kNameSpaceID_None, nsGkAtoms::keycode, keyCode);
|
2001-12-17 07:14:49 +00:00
|
|
|
ToUpperCase(keyCode);
|
2001-01-09 01:28:36 +00:00
|
|
|
|
|
|
|
nsresult rv;
|
|
|
|
nsCOMPtr<nsIStringBundleService> bundleService(do_GetService(NS_STRINGBUNDLE_CONTRACTID, &rv));
|
|
|
|
if (NS_SUCCEEDED(rv) && bundleService) {
|
|
|
|
nsCOMPtr<nsIStringBundle> bundle;
|
|
|
|
rv = bundleService->CreateBundle("chrome://global/locale/keys.properties",
|
|
|
|
getter_AddRefs(bundle));
|
|
|
|
|
|
|
|
if (NS_SUCCEEDED(rv) && bundle) {
|
|
|
|
nsXPIDLString keyName;
|
2001-06-30 11:02:25 +00:00
|
|
|
rv = bundle->GetStringFromName(keyCode.get(), getter_Copies(keyName));
|
2001-01-09 01:28:36 +00:00
|
|
|
if (keyName)
|
|
|
|
accelString = keyName;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// nothing usable found, bail
|
|
|
|
if (accelString.IsEmpty())
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static PRInt32 accelKey = 0;
|
2000-08-17 00:09:16 +00:00
|
|
|
|
2000-09-22 05:02:20 +00:00
|
|
|
if (!accelKey)
|
2000-08-17 00:09:16 +00:00
|
|
|
{
|
|
|
|
// Compiled-in defaults, in case we can't get LookAndFeel --
|
|
|
|
// command for mac, control for all other platforms.
|
2007-10-01 23:20:37 +00:00
|
|
|
#ifdef XP_MACOSX
|
2000-08-17 00:09:16 +00:00
|
|
|
accelKey = nsIDOMKeyEvent::DOM_VK_META;
|
|
|
|
#else
|
|
|
|
accelKey = nsIDOMKeyEvent::DOM_VK_CONTROL;
|
1999-12-08 04:52:42 +00:00
|
|
|
#endif
|
1999-07-31 01:43:33 +00:00
|
|
|
|
2000-08-17 00:09:16 +00:00
|
|
|
// Get the accelerator key value from prefs, overriding the default:
|
2004-04-29 23:34:19 +00:00
|
|
|
accelKey = nsContentUtils::GetIntPref("ui.key.accelKey", accelKey);
|
2000-09-22 05:02:20 +00:00
|
|
|
}
|
2000-08-17 00:09:16 +00:00
|
|
|
|
2000-09-22 05:02:20 +00:00
|
|
|
nsAutoString modifiers;
|
2006-12-26 17:47:52 +00:00
|
|
|
keyElement->GetAttr(kNameSpaceID_None, nsGkAtoms::modifiers, modifiers);
|
2000-09-22 05:02:20 +00:00
|
|
|
|
2001-09-29 08:28:41 +00:00
|
|
|
char* str = ToNewCString(modifiers);
|
2000-09-22 05:02:20 +00:00
|
|
|
char* newStr;
|
2005-09-02 15:54:27 +00:00
|
|
|
char* token = nsCRT::strtok(str, ", \t", &newStr);
|
2001-01-09 01:28:36 +00:00
|
|
|
while (token) {
|
2000-09-22 05:02:20 +00:00
|
|
|
|
|
|
|
if (PL_strcmp(token, "shift") == 0)
|
2001-10-11 03:03:42 +00:00
|
|
|
accelText += *gShiftText;
|
2000-09-22 05:02:20 +00:00
|
|
|
else if (PL_strcmp(token, "alt") == 0)
|
2001-10-11 03:03:42 +00:00
|
|
|
accelText += *gAltText;
|
2000-09-22 05:02:20 +00:00
|
|
|
else if (PL_strcmp(token, "meta") == 0)
|
2001-10-11 03:03:42 +00:00
|
|
|
accelText += *gMetaText;
|
2000-09-22 05:02:20 +00:00
|
|
|
else if (PL_strcmp(token, "control") == 0)
|
2001-10-11 03:03:42 +00:00
|
|
|
accelText += *gControlText;
|
2000-09-22 05:02:20 +00:00
|
|
|
else if (PL_strcmp(token, "accel") == 0) {
|
|
|
|
switch (accelKey)
|
|
|
|
{
|
|
|
|
case nsIDOMKeyEvent::DOM_VK_META:
|
2001-10-11 03:03:42 +00:00
|
|
|
accelText += *gMetaText;
|
2000-09-22 05:02:20 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case nsIDOMKeyEvent::DOM_VK_ALT:
|
2001-10-11 03:03:42 +00:00
|
|
|
accelText += *gAltText;
|
2000-09-22 05:02:20 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case nsIDOMKeyEvent::DOM_VK_CONTROL:
|
|
|
|
default:
|
2001-10-11 03:03:42 +00:00
|
|
|
accelText += *gControlText;
|
2000-09-22 05:02:20 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2001-10-11 03:03:42 +00:00
|
|
|
accelText += *gModifierSeparator;
|
2001-01-09 01:28:36 +00:00
|
|
|
|
2005-09-02 15:54:27 +00:00
|
|
|
token = nsCRT::strtok(newStr, ", \t", &newStr);
|
1999-07-31 01:43:33 +00:00
|
|
|
}
|
|
|
|
|
2000-09-22 05:02:20 +00:00
|
|
|
nsMemory::Free(str);
|
|
|
|
|
2001-10-11 03:03:42 +00:00
|
|
|
accelText += accelString;
|
|
|
|
|
2006-12-26 17:47:52 +00:00
|
|
|
mContent->SetAttr(kNameSpaceID_None, nsGkAtoms::acceltext, accelText, PR_FALSE);
|
1999-07-31 01:43:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2002-09-26 23:21:59 +00:00
|
|
|
nsMenuFrame::Execute(nsGUIEvent *aEvent)
|
1999-07-31 01:43:33 +00:00
|
|
|
{
|
2006-09-03 20:25:58 +00:00
|
|
|
nsWeakFrame weakFrame(this);
|
2002-11-18 14:01:20 +00:00
|
|
|
// flip "checked" state if we're a checkbox menu, or an un-checked radio menu
|
|
|
|
if (mType == eMenuType_Checkbox || (mType == eMenuType_Radio && !mChecked)) {
|
2006-12-26 17:47:52 +00:00
|
|
|
if (!mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::autocheck,
|
|
|
|
nsGkAtoms::_false, eCaseMatters)) {
|
2002-10-08 18:02:34 +00:00
|
|
|
if (mChecked) {
|
2006-12-26 17:47:52 +00:00
|
|
|
mContent->UnsetAttr(kNameSpaceID_None, nsGkAtoms::checked,
|
2002-10-08 18:02:34 +00:00
|
|
|
PR_TRUE);
|
2006-09-03 20:25:58 +00:00
|
|
|
ENSURE_TRUE(weakFrame.IsAlive());
|
2002-10-08 18:02:34 +00:00
|
|
|
}
|
|
|
|
else {
|
2006-12-26 17:47:52 +00:00
|
|
|
mContent->SetAttr(kNameSpaceID_None, nsGkAtoms::checked, NS_LITERAL_STRING("true"),
|
2002-10-08 18:02:34 +00:00
|
|
|
PR_TRUE);
|
2006-09-03 20:25:58 +00:00
|
|
|
ENSURE_TRUE(weakFrame.IsAlive());
|
2001-03-21 08:15:49 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-12-10 17:23:20 +00:00
|
|
|
nsCOMPtr<nsISound> sound(do_CreateInstance("@mozilla.org/sound;1"));
|
|
|
|
if (sound)
|
2009-07-09 01:55:46 +00:00
|
|
|
sound->PlayEventSound(nsISound::EVENT_MENU_EXECUTE);
|
2008-12-10 17:23:20 +00:00
|
|
|
|
2007-07-04 15:49:38 +00:00
|
|
|
nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
|
|
|
|
if (pm && mMenuParent)
|
|
|
|
pm->ExecuteMenu(mContent, aEvent);
|
1999-07-31 11:29:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2005-02-07 01:58:25 +00:00
|
|
|
nsMenuFrame::RemoveFrame(nsIAtom* aListName,
|
|
|
|
nsIFrame* aOldFrame)
|
1999-07-31 11:29:03 +00:00
|
|
|
{
|
2007-07-04 15:49:38 +00:00
|
|
|
nsresult rv = NS_OK;
|
1999-08-19 03:51:25 +00:00
|
|
|
|
2007-07-04 15:49:38 +00:00
|
|
|
if (mPopupFrame == aOldFrame) {
|
1999-07-31 11:29:03 +00:00
|
|
|
// Go ahead and remove this frame.
|
2007-07-04 15:49:38 +00:00
|
|
|
mPopupFrame->Destroy();
|
|
|
|
mPopupFrame = nsnull;
|
2007-03-30 21:11:41 +00:00
|
|
|
PresContext()->PresShell()->
|
2007-05-06 19:16:51 +00:00
|
|
|
FrameNeedsReflow(this, nsIPresShell::eTreeChange,
|
|
|
|
NS_FRAME_HAS_DIRTY_CHILDREN);
|
Bug 300030: Move intrinsic width computation out of nsIFrame::Reflow and into its own methods on nsIFrame. Replace reflow reasons, types, and commands with dirty bits/notifications. Thanks to bzbarsky for almost all of the HTML form controls (mozilla/layout/forms) changes, and many others for help testing and patching. For detailed commit logs, see REFLOW_YYYYMMDD_BRANCH, where YYYYMMDD is one of 20061031, 20060830, 20060603, 20060302, 20060119, 20051011, 20050804, 20050429, 20050315, 20050111, and 20041213.
2006-12-08 05:38:33 +00:00
|
|
|
rv = NS_OK;
|
1999-08-19 03:51:25 +00:00
|
|
|
} else {
|
2005-02-07 01:58:25 +00:00
|
|
|
rv = nsBoxFrame::RemoveFrame(aListName, aOldFrame);
|
1999-07-31 11:29:03 +00:00
|
|
|
}
|
|
|
|
|
1999-08-19 03:51:25 +00:00
|
|
|
return rv;
|
1999-07-31 11:29:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2005-02-07 01:58:25 +00:00
|
|
|
nsMenuFrame::InsertFrames(nsIAtom* aListName,
|
|
|
|
nsIFrame* aPrevFrame,
|
2009-07-30 17:23:32 +00:00
|
|
|
nsFrameList& aFrameList)
|
1999-07-31 11:29:03 +00:00
|
|
|
{
|
2007-11-17 15:47:38 +00:00
|
|
|
if (!mPopupFrame && (!aListName || aListName == nsGkAtoms::popupList)) {
|
2009-07-30 17:23:32 +00:00
|
|
|
SetPopupFrame(aFrameList);
|
2007-11-17 15:47:38 +00:00
|
|
|
if (mPopupFrame) {
|
2004-06-19 09:07:47 +00:00
|
|
|
#ifdef DEBUG_LAYOUT
|
2007-11-17 15:47:38 +00:00
|
|
|
nsBoxLayoutState state(PresContext());
|
|
|
|
SetDebug(state, aFrameList, mState & NS_STATE_CURRENTLY_IN_DEBUG);
|
2004-06-19 09:07:47 +00:00
|
|
|
#endif
|
2007-11-17 15:47:38 +00:00
|
|
|
|
|
|
|
PresContext()->PresShell()->
|
|
|
|
FrameNeedsReflow(this, nsIPresShell::eTreeChange,
|
|
|
|
NS_FRAME_HAS_DIRTY_CHILDREN);
|
2007-10-20 05:43:38 +00:00
|
|
|
}
|
1999-07-31 11:29:03 +00:00
|
|
|
}
|
1999-08-19 03:51:25 +00:00
|
|
|
|
2009-07-30 17:23:32 +00:00
|
|
|
if (aFrameList.IsEmpty())
|
2007-11-17 15:47:38 +00:00
|
|
|
return NS_OK;
|
|
|
|
|
|
|
|
if (NS_UNLIKELY(aPrevFrame == mPopupFrame)) {
|
|
|
|
aPrevFrame = nsnull;
|
|
|
|
}
|
|
|
|
|
|
|
|
return nsBoxFrame::InsertFrames(aListName, aPrevFrame, aFrameList);
|
1999-07-31 11:29:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2005-02-07 01:58:25 +00:00
|
|
|
nsMenuFrame::AppendFrames(nsIAtom* aListName,
|
2009-07-30 17:23:32 +00:00
|
|
|
nsFrameList& aFrameList)
|
1999-07-31 11:29:03 +00:00
|
|
|
{
|
2007-11-17 15:47:38 +00:00
|
|
|
if (!mPopupFrame && (!aListName || aListName == nsGkAtoms::popupList)) {
|
2009-07-30 17:23:32 +00:00
|
|
|
SetPopupFrame(aFrameList);
|
2007-11-17 15:47:38 +00:00
|
|
|
if (mPopupFrame) {
|
2000-05-15 04:12:31 +00:00
|
|
|
|
2004-06-19 09:07:47 +00:00
|
|
|
#ifdef DEBUG_LAYOUT
|
2007-11-17 15:47:38 +00:00
|
|
|
nsBoxLayoutState state(PresContext());
|
|
|
|
SetDebug(state, aFrameList, mState & NS_STATE_CURRENTLY_IN_DEBUG);
|
2004-06-19 09:07:47 +00:00
|
|
|
#endif
|
2007-11-17 15:47:38 +00:00
|
|
|
PresContext()->PresShell()->
|
|
|
|
FrameNeedsReflow(this, nsIPresShell::eTreeChange,
|
|
|
|
NS_FRAME_HAS_DIRTY_CHILDREN);
|
|
|
|
}
|
1999-07-31 11:29:03 +00:00
|
|
|
}
|
1999-08-19 03:51:25 +00:00
|
|
|
|
2009-07-30 17:23:32 +00:00
|
|
|
if (aFrameList.IsEmpty())
|
2007-11-17 15:47:38 +00:00
|
|
|
return NS_OK;
|
|
|
|
|
|
|
|
return nsBoxFrame::AppendFrames(aListName, aFrameList);
|
1999-07-31 18:39:47 +00:00
|
|
|
}
|
1999-09-21 01:03:00 +00:00
|
|
|
|
2005-06-25 09:35:05 +00:00
|
|
|
PRBool
|
|
|
|
nsMenuFrame::SizeToPopup(nsBoxLayoutState& aState, nsSize& aSize)
|
2000-03-31 07:02:06 +00:00
|
|
|
{
|
2007-01-31 16:02:42 +00:00
|
|
|
if (!IsCollapsed(aState)) {
|
2005-06-25 09:35:05 +00:00
|
|
|
nsSize tmpSize(-1, 0);
|
2000-11-28 08:52:36 +00:00
|
|
|
nsIBox::AddCSSPrefSize(aState, this, tmpSize);
|
2007-01-31 16:02:42 +00:00
|
|
|
if (tmpSize.width == -1 && GetFlex(aState) == 0) {
|
2007-07-04 15:49:38 +00:00
|
|
|
if (!mPopupFrame)
|
2006-09-03 20:25:58 +00:00
|
|
|
return PR_FALSE;
|
2007-07-04 15:49:38 +00:00
|
|
|
tmpSize = mPopupFrame->GetPrefSize(aState);
|
2000-11-28 08:52:36 +00:00
|
|
|
aSize.width = tmpSize.width;
|
2005-06-25 09:35:05 +00:00
|
|
|
return PR_TRUE;
|
|
|
|
}
|
|
|
|
}
|
2002-04-16 23:51:07 +00:00
|
|
|
|
2005-06-25 09:35:05 +00:00
|
|
|
return PR_FALSE;
|
|
|
|
}
|
2002-04-16 23:51:07 +00:00
|
|
|
|
2007-01-08 02:57:59 +00:00
|
|
|
nsSize
|
|
|
|
nsMenuFrame::GetPrefSize(nsBoxLayoutState& aState)
|
2005-06-25 09:35:05 +00:00
|
|
|
{
|
2007-01-08 02:57:59 +00:00
|
|
|
nsSize size = nsBoxFrame::GetPrefSize(aState);
|
|
|
|
DISPLAY_PREF_SIZE(this, size);
|
2002-04-16 23:51:07 +00:00
|
|
|
|
2005-06-25 09:35:05 +00:00
|
|
|
// If we are using sizetopopup="always" then
|
|
|
|
// nsBoxFrame will already have enforced the minimum size
|
|
|
|
if (!IsSizedToPopup(mContent, PR_TRUE) &&
|
|
|
|
IsSizedToPopup(mContent, PR_FALSE) &&
|
2007-01-08 02:57:59 +00:00
|
|
|
SizeToPopup(aState, size)) {
|
|
|
|
// We now need to ensure that size is within the min - max range.
|
|
|
|
nsSize minSize = nsBoxFrame::GetMinSize(aState);
|
|
|
|
nsSize maxSize = GetMaxSize(aState);
|
2008-01-05 05:49:44 +00:00
|
|
|
size = BoundsCheck(minSize, size, maxSize);
|
2000-03-31 07:02:06 +00:00
|
|
|
}
|
|
|
|
|
2007-01-08 02:57:59 +00:00
|
|
|
return size;
|
2000-03-31 07:02:06 +00:00
|
|
|
}
|
|
|
|
|
2000-08-17 09:15:51 +00:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsMenuFrame::GetActiveChild(nsIDOMElement** aResult)
|
|
|
|
{
|
2007-07-04 15:49:38 +00:00
|
|
|
if (!mPopupFrame)
|
2000-08-17 09:15:51 +00:00
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
|
2007-07-04 15:49:38 +00:00
|
|
|
nsMenuFrame* menuFrame = mPopupFrame->GetCurrentMenuItem();
|
2000-08-17 09:15:51 +00:00
|
|
|
if (!menuFrame) {
|
|
|
|
*aResult = nsnull;
|
|
|
|
}
|
|
|
|
else {
|
2007-07-04 15:49:38 +00:00
|
|
|
nsCOMPtr<nsIDOMElement> elt(do_QueryInterface(menuFrame->GetContent()));
|
2000-08-17 09:15:51 +00:00
|
|
|
*aResult = elt;
|
|
|
|
NS_IF_ADDREF(*aResult);
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsMenuFrame::SetActiveChild(nsIDOMElement* aChild)
|
|
|
|
{
|
2007-07-04 15:49:38 +00:00
|
|
|
if (!mPopupFrame)
|
2000-08-17 09:15:51 +00:00
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
|
2000-08-24 03:58:42 +00:00
|
|
|
if (!aChild) {
|
|
|
|
// Remove the current selection
|
2007-07-04 15:49:38 +00:00
|
|
|
mPopupFrame->ChangeMenuItem(nsnull, PR_FALSE);
|
2000-08-24 03:58:42 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2000-08-17 09:15:51 +00:00
|
|
|
nsCOMPtr<nsIContent> child(do_QueryInterface(aChild));
|
2007-07-04 15:49:38 +00:00
|
|
|
|
2009-12-24 21:20:06 +00:00
|
|
|
nsIFrame* kid = child->GetPrimaryFrame();
|
2007-07-04 15:49:38 +00:00
|
|
|
if (kid && kid->GetType() == nsGkAtoms::menuFrame)
|
2007-07-08 07:08:04 +00:00
|
|
|
mPopupFrame->ChangeMenuItem(static_cast<nsMenuFrame *>(kid), PR_FALSE);
|
2000-08-17 09:15:51 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2009-09-01 11:22:31 +00:00
|
|
|
nsIScrollableFrame* nsMenuFrame::GetScrollTargetFrame()
|
|
|
|
{
|
|
|
|
if (!mPopupFrame)
|
|
|
|
return nsnull;
|
|
|
|
nsIFrame* childFrame = mPopupFrame->GetFirstChild(nsnull);
|
|
|
|
if (childFrame)
|
|
|
|
return mPopupFrame->GetScrollFrame(childFrame);
|
|
|
|
return nsnull;
|
|
|
|
}
|
|
|
|
|
2006-01-12 16:40:47 +00:00
|
|
|
// nsMenuTimerMediator implementation.
|
|
|
|
NS_IMPL_ISUPPORTS1(nsMenuTimerMediator, nsITimerCallback)
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Constructs a wrapper around an nsMenuFrame.
|
|
|
|
* @param aFrame nsMenuFrame to create a wrapper around.
|
|
|
|
*/
|
|
|
|
nsMenuTimerMediator::nsMenuTimerMediator(nsMenuFrame *aFrame) :
|
|
|
|
mFrame(aFrame)
|
|
|
|
{
|
|
|
|
NS_ASSERTION(mFrame, "Must have frame");
|
|
|
|
}
|
|
|
|
|
|
|
|
nsMenuTimerMediator::~nsMenuTimerMediator()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Delegates the notification to the contained frame if it has not been destroyed.
|
|
|
|
* @param aTimer Timer which initiated the callback.
|
|
|
|
* @return NS_ERROR_FAILURE if the frame has been destroyed.
|
|
|
|
*/
|
|
|
|
NS_IMETHODIMP nsMenuTimerMediator::Notify(nsITimer* aTimer)
|
|
|
|
{
|
|
|
|
if (!mFrame)
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
|
|
|
|
return mFrame->Notify(aTimer);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Clear the pointer to the contained nsMenuFrame. This should be called
|
|
|
|
* when the contained nsMenuFrame is destroyed.
|
|
|
|
*/
|
|
|
|
void nsMenuTimerMediator::ClearFrame()
|
|
|
|
{
|
|
|
|
mFrame = nsnull;
|
|
|
|
}
|