2001-09-29 00:14:13 +04:00
|
|
|
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
2012-05-21 15:12:37 +04:00
|
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
1999-07-18 10:36:37 +04:00
|
|
|
|
2007-01-30 03:06:41 +03:00
|
|
|
#include "nsGkAtoms.h"
|
1999-10-15 03:59:18 +04:00
|
|
|
#include "nsHTMLParts.h"
|
1999-07-18 10:36:37 +04:00
|
|
|
#include "nsMenuFrame.h"
|
1999-07-21 06:56:23 +04:00
|
|
|
#include "nsBoxFrame.h"
|
1999-07-18 10:36:37 +04:00
|
|
|
#include "nsIContent.h"
|
|
|
|
#include "nsIAtom.h"
|
2004-08-01 03:15:21 +04:00
|
|
|
#include "nsPresContext.h"
|
1999-10-15 03:59:18 +04:00
|
|
|
#include "nsIPresShell.h"
|
2003-02-22 03:32:13 +03:00
|
|
|
#include "nsStyleContext.h"
|
1999-07-18 10:36:37 +04:00
|
|
|
#include "nsCSSRendering.h"
|
2014-02-28 03:04:46 +04:00
|
|
|
#include "nsNameSpaceManager.h"
|
1999-07-20 13:35:35 +04:00
|
|
|
#include "nsMenuPopupFrame.h"
|
1999-07-21 11:42:16 +04:00
|
|
|
#include "nsMenuBarFrame.h"
|
1999-07-31 05:43:33 +04:00
|
|
|
#include "nsIDocument.h"
|
|
|
|
#include "nsIDOMElement.h"
|
2000-01-22 00:56:09 +03:00
|
|
|
#include "nsIComponentManager.h"
|
2000-03-31 11:02:06 +04:00
|
|
|
#include "nsBoxLayoutState.h"
|
2000-05-15 08:12:31 +04:00
|
|
|
#include "nsIScrollableFrame.h"
|
2007-02-17 02:02:08 +03:00
|
|
|
#include "nsBindingManager.h"
|
2000-08-06 12:11:05 +04:00
|
|
|
#include "nsIServiceManager.h"
|
2000-08-03 04:22:36 +04:00
|
|
|
#include "nsCSSFrameConstructor.h"
|
2000-08-17 04:09:16 +04:00
|
|
|
#include "nsIDOMKeyEvent.h"
|
2001-01-09 04:28:36 +03:00
|
|
|
#include "nsXPIDLString.h"
|
2001-09-29 12:28:41 +04:00
|
|
|
#include "nsReadableUtils.h"
|
2001-12-17 10:14:49 +03:00
|
|
|
#include "nsUnicharUtils.h"
|
2001-01-09 04:28:36 +03:00
|
|
|
#include "nsIStringBundle.h"
|
2004-04-30 03:34:19 +04:00
|
|
|
#include "nsContentUtils.h"
|
2006-01-26 05:29:17 +03:00
|
|
|
#include "nsDisplayList.h"
|
2007-03-06 00:55:23 +03:00
|
|
|
#include "nsIReflowCallback.h"
|
2008-12-10 20:23:20 +03:00
|
|
|
#include "nsISound.h"
|
2010-04-19 18:12:58 +04:00
|
|
|
#include "nsIDOMXULMenuListElement.h"
|
2012-07-11 08:03:55 +04:00
|
|
|
#include "mozilla/Attributes.h"
|
2014-03-18 08:48:21 +04:00
|
|
|
#include "mozilla/EventDispatcher.h"
|
2014-04-01 08:09:23 +04:00
|
|
|
#include "mozilla/EventStateManager.h"
|
2012-10-26 17:32:10 +04:00
|
|
|
#include "mozilla/Likely.h"
|
|
|
|
#include "mozilla/LookAndFeel.h"
|
2013-09-25 15:21:18 +04:00
|
|
|
#include "mozilla/MouseEvents.h"
|
2012-10-26 17:32:10 +04:00
|
|
|
#include "mozilla/Preferences.h"
|
|
|
|
#include "mozilla/Services.h"
|
2013-09-25 15:21:19 +04:00
|
|
|
#include "mozilla/TextEvents.h"
|
2013-08-20 02:55:18 +04:00
|
|
|
#include "mozilla/dom/Element.h"
|
2015-08-12 14:39:31 +03:00
|
|
|
#include "mozilla/dom/Event.h"
|
2013-01-15 16:22:03 +04:00
|
|
|
#include <algorithm>
|
2011-05-25 10:32:00 +04:00
|
|
|
|
|
|
|
using namespace mozilla;
|
2004-04-30 03:34:19 +04:00
|
|
|
|
2007-07-04 19:49:38 +04:00
|
|
|
#define NS_MENU_POPUP_LIST_INDEX 0
|
1999-07-18 10:48:03 +04:00
|
|
|
|
2014-02-11 02:57:01 +04:00
|
|
|
#if defined(XP_WIN)
|
2001-03-29 07:33:09 +04:00
|
|
|
#define NSCONTEXTMENUISMOUSEUP 1
|
|
|
|
#endif
|
|
|
|
|
2012-03-08 05:57:37 +04:00
|
|
|
static void
|
|
|
|
AssertNotCalled(void* aPropertyValue)
|
|
|
|
{
|
|
|
|
NS_ERROR("popup list should never be destroyed by the FramePropertyTable");
|
|
|
|
}
|
|
|
|
NS_DECLARE_FRAME_PROPERTY(PopupListProperty, AssertNotCalled)
|
|
|
|
|
2012-08-22 19:56:38 +04:00
|
|
|
static int32_t gEatMouseMove = false;
|
1999-07-26 10:29:48 +04:00
|
|
|
|
2012-08-22 19:56:38 +04:00
|
|
|
const int32_t kBlinkDelay = 67; // milliseconds
|
2001-07-03 04:26:41 +04:00
|
|
|
|
2007-07-26 08:14:32 +04:00
|
|
|
// this class is used for dispatching menu activation events asynchronously.
|
|
|
|
class nsMenuActivateEvent : public nsRunnable
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
nsMenuActivateEvent(nsIContent *aMenu,
|
|
|
|
nsPresContext* aPresContext,
|
2011-09-29 10:19:26 +04:00
|
|
|
bool aIsActivate)
|
2007-07-26 08:14:32 +04:00
|
|
|
: mMenu(aMenu), mPresContext(aPresContext), mIsActivate(aIsActivate)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2015-03-21 19:28:04 +03:00
|
|
|
NS_IMETHOD Run() override
|
2007-07-26 08:14:32 +04:00
|
|
|
{
|
|
|
|
nsAutoString domEventToFire;
|
|
|
|
|
|
|
|
if (mIsActivate) {
|
|
|
|
// Highlight the menu.
|
|
|
|
mMenu->SetAttr(kNameSpaceID_None, nsGkAtoms::menuactive,
|
2011-10-17 18:59:28 +04:00
|
|
|
NS_LITERAL_STRING("true"), true);
|
2007-07-26 08:14:32 +04:00
|
|
|
// The menuactivated event is used by accessibility to track the user's
|
|
|
|
// movements through menus
|
|
|
|
domEventToFire.AssignLiteral("DOMMenuItemActive");
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// Unhighlight the menu.
|
2011-10-17 18:59:28 +04:00
|
|
|
mMenu->UnsetAttr(kNameSpaceID_None, nsGkAtoms::menuactive, true);
|
2007-07-26 08:14:32 +04:00
|
|
|
domEventToFire.AssignLiteral("DOMMenuItemInactive");
|
|
|
|
}
|
|
|
|
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<Event> event = NS_NewDOMEvent(mMenu, mPresContext, nullptr);
|
2015-08-12 14:39:31 +03:00
|
|
|
event->InitEvent(domEventToFire, true, true);
|
2007-07-26 08:14:32 +04:00
|
|
|
|
2015-08-12 14:39:31 +03:00
|
|
|
event->SetTrusted(true);
|
2007-07-26 08:14:32 +04:00
|
|
|
|
2015-08-12 14:39:31 +03:00
|
|
|
EventDispatcher::DispatchDOMEvent(mMenu, nullptr, event,
|
|
|
|
mPresContext, nullptr);
|
2007-07-26 08:14:32 +04:00
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
nsCOMPtr<nsIContent> mMenu;
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<nsPresContext> mPresContext;
|
2011-09-29 10:19:26 +04:00
|
|
|
bool mIsActivate;
|
2007-07-26 08:14:32 +04:00
|
|
|
};
|
|
|
|
|
2010-08-12 15:59:03 +04:00
|
|
|
class nsMenuAttributeChangedEvent : public nsRunnable
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
nsMenuAttributeChangedEvent(nsIFrame* aFrame, nsIAtom* aAttr)
|
|
|
|
: mFrame(aFrame), mAttr(aAttr)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2015-03-21 19:28:04 +03:00
|
|
|
NS_IMETHOD Run() override
|
2010-08-12 15:59:03 +04:00
|
|
|
{
|
|
|
|
nsMenuFrame* frame = static_cast<nsMenuFrame*>(mFrame.GetFrame());
|
|
|
|
NS_ENSURE_STATE(frame);
|
|
|
|
if (mAttr == nsGkAtoms::checked) {
|
2015-12-07 04:15:53 +03:00
|
|
|
frame->UpdateMenuSpecialState();
|
2010-08-12 15:59:03 +04:00
|
|
|
} else if (mAttr == nsGkAtoms::acceltext) {
|
|
|
|
// someone reset the accelText attribute,
|
|
|
|
// so clear the bit that says *we* set it
|
2011-02-13 15:28:00 +03:00
|
|
|
frame->RemoveStateBits(NS_STATE_ACCELTEXT_IS_DERIVED);
|
2011-10-17 18:59:28 +04:00
|
|
|
frame->BuildAcceleratorText(true);
|
2011-02-13 15:28:00 +03:00
|
|
|
}
|
|
|
|
else if (mAttr == nsGkAtoms::key) {
|
2011-10-17 18:59:28 +04:00
|
|
|
frame->BuildAcceleratorText(true);
|
2010-08-12 15:59:03 +04:00
|
|
|
} else if (mAttr == nsGkAtoms::type || mAttr == nsGkAtoms::name) {
|
2015-12-07 04:15:53 +03:00
|
|
|
frame->UpdateMenuType();
|
2010-08-12 15:59:03 +04:00
|
|
|
}
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
protected:
|
|
|
|
nsWeakFrame mFrame;
|
|
|
|
nsCOMPtr<nsIAtom> mAttr;
|
|
|
|
};
|
|
|
|
|
1999-07-18 10:36:37 +04:00
|
|
|
//
|
2009-01-19 21:31:33 +03:00
|
|
|
// NS_NewMenuFrame and NS_NewMenuItemFrame
|
1999-07-18 10:36:37 +04:00
|
|
|
//
|
2009-01-19 21:31:33 +03:00
|
|
|
// Wrappers for creating a new menu popup container
|
1999-07-18 10:36:37 +04:00
|
|
|
//
|
2005-10-27 01:46:39 +04:00
|
|
|
nsIFrame*
|
2009-01-19 21:31:33 +03:00
|
|
|
NS_NewMenuFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
|
1999-07-18 10:36:37 +04:00
|
|
|
{
|
2015-01-06 12:27:56 +03:00
|
|
|
nsMenuFrame* it = new (aPresShell) nsMenuFrame(aContext);
|
2012-11-07 23:55:53 +04:00
|
|
|
it->SetIsMenu(true);
|
2005-10-27 01:46:39 +04:00
|
|
|
return it;
|
1999-07-18 10:36:37 +04:00
|
|
|
}
|
|
|
|
|
2009-01-19 21:31:33 +03:00
|
|
|
nsIFrame*
|
|
|
|
NS_NewMenuItemFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
|
|
|
|
{
|
2015-01-06 12:27:56 +03:00
|
|
|
nsMenuFrame* it = new (aPresShell) nsMenuFrame(aContext);
|
2012-11-07 23:55:53 +04:00
|
|
|
it->SetIsMenu(false);
|
2009-01-19 21:31:33 +03:00
|
|
|
return it;
|
|
|
|
}
|
|
|
|
|
2009-09-12 20:49:24 +04:00
|
|
|
NS_IMPL_FRAMEARENA_HELPERS(nsMenuFrame)
|
|
|
|
|
2009-01-12 22:20:59 +03:00
|
|
|
NS_QUERYFRAME_HEAD(nsMenuFrame)
|
2011-07-11 18:05:07 +04:00
|
|
|
NS_QUERYFRAME_ENTRY(nsMenuFrame)
|
2009-01-12 22:20:59 +03:00
|
|
|
NS_QUERYFRAME_TAIL_INHERITING(nsBoxFrame)
|
1999-07-18 10:36:37 +04:00
|
|
|
|
2015-01-06 12:27:56 +03:00
|
|
|
nsMenuFrame::nsMenuFrame(nsStyleContext* aContext):
|
|
|
|
nsBoxFrame(aContext),
|
2011-10-17 18:59:28 +04:00
|
|
|
mIsMenu(false),
|
|
|
|
mChecked(false),
|
|
|
|
mIgnoreAccelTextChange(false),
|
1999-10-18 01:37:37 +04:00
|
|
|
mType(eMenuType_Normal),
|
2010-04-19 18:12:58 +04:00
|
|
|
mBlinkState(0)
|
1999-07-18 10:36:37 +04:00
|
|
|
{
|
2012-03-08 05:57:37 +04:00
|
|
|
}
|
1999-07-18 10:36:37 +04:00
|
|
|
|
2014-05-25 02:20:41 +04:00
|
|
|
nsMenuParent*
|
|
|
|
nsMenuFrame::GetMenuParent() const
|
2007-07-04 19:49:38 +04:00
|
|
|
{
|
2014-05-25 02:20:41 +04:00
|
|
|
nsContainerFrame* parent = GetParent();
|
|
|
|
for (; parent; parent = parent->GetParent()) {
|
|
|
|
nsMenuPopupFrame* popup = do_QueryFrame(parent);
|
2012-07-31 04:43:28 +04:00
|
|
|
if (popup) {
|
2014-05-25 02:20:41 +04:00
|
|
|
return popup;
|
2007-07-04 19:49:38 +04:00
|
|
|
}
|
2014-05-25 02:20:41 +04:00
|
|
|
nsMenuBarFrame* menubar = do_QueryFrame(parent);
|
2012-07-31 04:43:28 +04:00
|
|
|
if (menubar) {
|
2014-05-25 02:20:41 +04:00
|
|
|
return menubar;
|
2007-07-04 19:49:38 +04:00
|
|
|
}
|
2000-05-27 02:45:26 +04:00
|
|
|
}
|
2014-05-25 02:20:41 +04:00
|
|
|
return nullptr;
|
2000-05-27 02:45:26 +04:00
|
|
|
}
|
|
|
|
|
2015-03-21 19:28:04 +03:00
|
|
|
class nsASyncMenuInitialization final : public nsIReflowCallback
|
2006-09-04 00:25:58 +04:00
|
|
|
{
|
|
|
|
public:
|
2014-09-01 07:36:37 +04:00
|
|
|
explicit nsASyncMenuInitialization(nsIFrame* aFrame)
|
2006-09-13 23:15:08 +04:00
|
|
|
: mWeakFrame(aFrame)
|
2006-09-04 00:25:58 +04:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2015-03-21 19:28:04 +03:00
|
|
|
virtual bool ReflowFinished() override
|
2007-12-01 10:22:44 +03:00
|
|
|
{
|
2011-09-29 10:19:26 +04:00
|
|
|
bool shouldFlush = false;
|
2012-07-31 04:43:28 +04:00
|
|
|
nsMenuFrame* menu = do_QueryFrame(mWeakFrame.GetFrame());
|
|
|
|
if (menu) {
|
2015-12-07 04:15:53 +03:00
|
|
|
menu->UpdateMenuType();
|
2012-07-31 04:43:28 +04:00
|
|
|
shouldFlush = true;
|
2006-09-13 23:15:08 +04:00
|
|
|
}
|
2007-03-06 00:55:23 +03:00
|
|
|
delete this;
|
|
|
|
return shouldFlush;
|
2006-09-04 00:25:58 +04:00
|
|
|
}
|
|
|
|
|
2015-03-21 19:28:04 +03:00
|
|
|
virtual void ReflowCallbackCanceled() override
|
2007-12-01 10:22:44 +03:00
|
|
|
{
|
|
|
|
delete this;
|
|
|
|
}
|
|
|
|
|
2006-09-13 23:15:08 +04:00
|
|
|
nsWeakFrame mWeakFrame;
|
2006-09-04 00:25:58 +04:00
|
|
|
};
|
|
|
|
|
2013-03-20 05:47:48 +04:00
|
|
|
void
|
2014-05-25 02:20:40 +04:00
|
|
|
nsMenuFrame::Init(nsIContent* aContent,
|
|
|
|
nsContainerFrame* aParent,
|
|
|
|
nsIFrame* aPrevInFlow)
|
1999-07-21 11:42:16 +04:00
|
|
|
{
|
2013-03-20 05:47:48 +04:00
|
|
|
nsBoxFrame::Init(aContent, aParent, aPrevInFlow);
|
1999-07-21 11:42:16 +04:00
|
|
|
|
2006-01-12 19:40:47 +03:00
|
|
|
// Set up a mediator which can be used for callbacks on this frame.
|
|
|
|
mTimerMediator = new nsMenuTimerMediator(this);
|
|
|
|
|
2011-10-17 18:59:28 +04:00
|
|
|
BuildAcceleratorText(false);
|
2007-03-06 00:55:23 +03:00
|
|
|
nsIReflowCallback* cb = new nsASyncMenuInitialization(this);
|
2007-03-31 01:11:41 +04:00
|
|
|
PresContext()->PresShell()->PostReflowCallback(cb);
|
1999-07-21 11:42:16 +04:00
|
|
|
}
|
|
|
|
|
2012-03-08 05:57:37 +04:00
|
|
|
const nsFrameList&
|
2011-08-25 00:54:29 +04:00
|
|
|
nsMenuFrame::GetChildList(ChildListID aListID) const
|
1999-07-18 10:41:41 +04:00
|
|
|
{
|
2011-08-25 00:54:29 +04:00
|
|
|
if (kPopupList == aListID) {
|
2012-03-08 05:57:37 +04:00
|
|
|
nsFrameList* list = GetPopupList();
|
|
|
|
return list ? *list : nsFrameList::EmptyList();
|
1999-07-18 10:41:41 +04:00
|
|
|
}
|
2011-08-25 00:54:29 +04:00
|
|
|
return nsBoxFrame::GetChildList(aListID);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsMenuFrame::GetChildLists(nsTArray<ChildList>* aLists) const
|
|
|
|
{
|
|
|
|
nsBoxFrame::GetChildLists(aLists);
|
2012-03-08 05:57:37 +04:00
|
|
|
nsFrameList* list = GetPopupList();
|
|
|
|
if (list) {
|
|
|
|
list->AppendIfNonempty(aLists, kPopupList);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
nsMenuPopupFrame*
|
|
|
|
nsMenuFrame::GetPopup()
|
|
|
|
{
|
|
|
|
nsFrameList* popupList = GetPopupList();
|
|
|
|
return popupList ? static_cast<nsMenuPopupFrame*>(popupList->FirstChild()) :
|
2012-07-30 18:20:58 +04:00
|
|
|
nullptr;
|
2012-03-08 05:57:37 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
nsFrameList*
|
|
|
|
nsMenuFrame::GetPopupList() const
|
|
|
|
{
|
|
|
|
if (!HasPopup()) {
|
2012-07-30 18:20:58 +04:00
|
|
|
return nullptr;
|
2012-03-08 05:57:37 +04:00
|
|
|
}
|
|
|
|
nsFrameList* prop =
|
|
|
|
static_cast<nsFrameList*>(Properties().Get(PopupListProperty()));
|
|
|
|
NS_ASSERTION(prop && prop->GetLength() == 1 &&
|
|
|
|
prop->FirstChild()->GetType() == nsGkAtoms::menuPopupFrame,
|
|
|
|
"popup list should have exactly one nsMenuPopupFrame");
|
|
|
|
return prop;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsMenuFrame::DestroyPopupList()
|
|
|
|
{
|
|
|
|
NS_ASSERTION(HasPopup(), "huh?");
|
|
|
|
nsFrameList* prop =
|
|
|
|
static_cast<nsFrameList*>(Properties().Remove(PopupListProperty()));
|
|
|
|
NS_ASSERTION(prop && prop->IsEmpty(),
|
|
|
|
"popup list must exist and be empty when destroying");
|
|
|
|
RemoveStateBits(NS_STATE_MENU_HAS_POPUP_LIST);
|
2013-04-01 19:26:02 +04:00
|
|
|
prop->Delete(PresContext()->PresShell());
|
1999-07-18 10:41:41 +04:00
|
|
|
}
|
|
|
|
|
2009-07-28 16:53:20 +04:00
|
|
|
void
|
|
|
|
nsMenuFrame::SetPopupFrame(nsFrameList& aFrameList)
|
|
|
|
{
|
|
|
|
for (nsFrameList::Enumerator e(aFrameList); !e.AtEnd(); e.Next()) {
|
2012-07-31 04:43:28 +04:00
|
|
|
nsMenuPopupFrame* popupFrame = do_QueryFrame(e.get());
|
|
|
|
if (popupFrame) {
|
2012-03-08 05:57:37 +04:00
|
|
|
// Remove the frame from the list and store it in a nsFrameList* property.
|
|
|
|
aFrameList.RemoveFrame(popupFrame);
|
2013-04-01 19:26:02 +04:00
|
|
|
nsFrameList* popupList = new (PresContext()->PresShell()) nsFrameList(popupFrame, popupFrame);
|
2012-03-08 05:57:37 +04:00
|
|
|
Properties().Set(PopupListProperty(), popupList);
|
|
|
|
AddStateBits(NS_STATE_MENU_HAS_POPUP_LIST);
|
2007-07-04 19:49:38 +04:00
|
|
|
break;
|
1999-07-20 12:19:47 +04:00
|
|
|
}
|
2007-06-30 02:15:59 +04:00
|
|
|
}
|
2007-11-17 18:47:38 +03:00
|
|
|
}
|
|
|
|
|
2014-05-28 23:36:58 +04:00
|
|
|
void
|
2011-08-25 00:54:30 +04:00
|
|
|
nsMenuFrame::SetInitialChildList(ChildListID aListID,
|
2009-07-28 16:53:20 +04:00
|
|
|
nsFrameList& aChildList)
|
2007-11-17 18:47:38 +03:00
|
|
|
{
|
2011-08-25 00:54:30 +04:00
|
|
|
if (aListID == kPrincipalList || aListID == kPopupList) {
|
2016-01-28 02:11:00 +03:00
|
|
|
NS_ASSERTION(!HasPopup(), "SetInitialChildList called twice?");
|
2009-07-28 16:53:20 +04:00
|
|
|
SetPopupFrame(aChildList);
|
2011-08-25 00:54:30 +04:00
|
|
|
}
|
2014-05-28 23:36:58 +04:00
|
|
|
nsBoxFrame::SetInitialChildList(aListID, aChildList);
|
1999-07-18 10:44:03 +04:00
|
|
|
}
|
1999-07-18 10:48:03 +04:00
|
|
|
|
2006-04-10 04:16:29 +04:00
|
|
|
void
|
2009-12-24 08:21:15 +03:00
|
|
|
nsMenuFrame::DestroyFrom(nsIFrame* aDestructRoot)
|
2001-12-18 01:51:39 +03:00
|
|
|
{
|
2006-01-12 19:40:47 +03: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();
|
|
|
|
}
|
|
|
|
|
2010-04-19 18:12:58 +04:00
|
|
|
StopBlinking();
|
|
|
|
|
2006-01-12 19:40:47 +03:00
|
|
|
// 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 10:18:07 +03:00
|
|
|
// if the menu content is just being hidden, it may be made visible again
|
|
|
|
// later, so make sure to clear the highlighting.
|
2011-10-17 18:59:28 +04:00
|
|
|
mContent->UnsetAttr(kNameSpaceID_None, nsGkAtoms::menuactive, false);
|
2008-01-30 10:18:07 +03:00
|
|
|
|
2005-01-08 02:59:12 +03:00
|
|
|
// are we our menu parent's current menu item?
|
2014-05-25 02:20:41 +04:00
|
|
|
nsMenuParent* menuParent = GetMenuParent();
|
|
|
|
if (menuParent && menuParent->GetCurrentMenuItem() == this) {
|
2007-07-04 19:49:38 +04:00
|
|
|
// yes; tell it that we're going away
|
2014-05-25 02:20:41 +04:00
|
|
|
menuParent->CurrentMenuIsBeingDestroyed();
|
2005-01-08 02:59:12 +03:00
|
|
|
}
|
|
|
|
|
2012-03-08 05:57:37 +04:00
|
|
|
nsFrameList* popupList = GetPopupList();
|
|
|
|
if (popupList) {
|
|
|
|
popupList->DestroyFramesFrom(aDestructRoot);
|
|
|
|
DestroyPopupList();
|
|
|
|
}
|
2007-07-04 19:49:38 +04:00
|
|
|
|
2009-12-24 08:21:15 +03:00
|
|
|
nsBoxFrame::DestroyFrom(aDestructRoot);
|
1999-07-18 10:52:06 +04:00
|
|
|
}
|
1999-07-19 13:36:24 +04:00
|
|
|
|
2013-02-14 15:12:27 +04:00
|
|
|
void
|
2006-01-26 05:29:17 +03:00
|
|
|
nsMenuFrame::BuildDisplayListForChildren(nsDisplayListBuilder* aBuilder,
|
|
|
|
const nsRect& aDirtyRect,
|
|
|
|
const nsDisplayListSet& aLists)
|
1999-07-19 13:36:24 +04:00
|
|
|
{
|
2013-02-14 15:12:27 +04:00
|
|
|
if (!aBuilder->IsForEventDelivery()) {
|
|
|
|
nsBoxFrame::BuildDisplayListForChildren(aBuilder, aDirtyRect, aLists);
|
|
|
|
return;
|
|
|
|
}
|
2006-01-26 05:29:17 +03:00
|
|
|
|
|
|
|
nsDisplayListCollection set;
|
2013-02-14 15:12:27 +04:00
|
|
|
nsBoxFrame::BuildDisplayListForChildren(aBuilder, aDirtyRect, set);
|
2006-01-26 05:29:17 +03:00
|
|
|
|
2013-02-14 15:12:27 +04:00
|
|
|
WrapListsInRedirector(aBuilder, set, aLists);
|
1999-07-20 12:19:47 +04:00
|
|
|
}
|
1999-07-20 13:35:35 +04:00
|
|
|
|
2014-02-18 11:47:48 +04:00
|
|
|
nsresult
|
2013-10-02 07:46:03 +04:00
|
|
|
nsMenuFrame::HandleEvent(nsPresContext* aPresContext,
|
|
|
|
WidgetGUIEvent* aEvent,
|
|
|
|
nsEventStatus* aEventStatus)
|
1999-07-20 13:35:35 +04:00
|
|
|
{
|
1999-11-24 09:03:41 +03:00
|
|
|
NS_ENSURE_ARG_POINTER(aEventStatus);
|
2014-05-25 02:20:41 +04:00
|
|
|
if (nsEventStatus_eConsumeNoDefault == *aEventStatus) {
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
nsMenuParent* menuParent = GetMenuParent();
|
|
|
|
if (menuParent && menuParent->IsMenuLocked()) {
|
2009-02-27 13:48:25 +03:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2006-09-04 00:25:58 +04:00
|
|
|
nsWeakFrame weakFrame(this);
|
2004-08-19 22:36:42 +04:00
|
|
|
if (*aEventStatus == nsEventStatus_eIgnore)
|
|
|
|
*aEventStatus = nsEventStatus_eConsumeDoDefault;
|
2007-07-04 19:49:38 +04:00
|
|
|
|
2011-09-29 10:19:26 +04:00
|
|
|
bool onmenu = IsOnMenu();
|
2007-07-04 19:49:38 +04:00
|
|
|
|
2015-08-29 02:58:27 +03:00
|
|
|
if (aEvent->mMessage == eKeyPress && !IsDisabled()) {
|
2013-10-18 10:10:24 +04:00
|
|
|
WidgetKeyboardEvent* keyEvent = aEvent->AsKeyboardEvent();
|
2012-08-22 19:56:38 +04:00
|
|
|
uint32_t keyCode = keyEvent->keyCode;
|
2005-03-23 13:43:45 +03:00
|
|
|
#ifdef XP_MACOSX
|
|
|
|
// On mac, open menulist on either up/down arrow or space (w/o Cmd pressed)
|
2012-04-25 07:00:02 +04:00
|
|
|
if (!IsOpen() && ((keyEvent->charCode == NS_VK_SPACE && !keyEvent->IsMeta()) ||
|
2009-05-01 16:24:49 +04:00
|
|
|
(keyCode == NS_VK_UP || keyCode == NS_VK_DOWN))) {
|
|
|
|
*aEventStatus = nsEventStatus_eConsumeNoDefault;
|
2011-10-17 18:59:28 +04:00
|
|
|
OpenMenu(false);
|
2009-05-01 16:24:49 +04:00
|
|
|
}
|
2005-03-23 13:43:45 +03:00
|
|
|
#else
|
|
|
|
// On other platforms, toggle menulist on unmodified F4 or Alt arrow
|
2012-04-25 07:00:02 +04:00
|
|
|
if ((keyCode == NS_VK_F4 && !keyEvent->IsAlt()) ||
|
|
|
|
((keyCode == NS_VK_UP || keyCode == NS_VK_DOWN) && keyEvent->IsAlt())) {
|
2009-05-01 16:24:49 +04:00
|
|
|
*aEventStatus = nsEventStatus_eConsumeNoDefault;
|
2007-07-04 19:49:38 +04:00
|
|
|
ToggleMenuState();
|
2009-05-01 16:24:49 +04:00
|
|
|
}
|
2005-03-23 13:43:45 +03:00
|
|
|
#endif
|
2000-02-25 11:37:49 +03:00
|
|
|
}
|
2015-08-29 02:58:30 +03:00
|
|
|
else if (aEvent->mMessage == eMouseDown &&
|
2013-10-22 12:55:20 +04:00
|
|
|
aEvent->AsMouseEvent()->button == WidgetMouseEvent::eLeftButton &&
|
2006-11-17 00:35:39 +03:00
|
|
|
!IsDisabled() && IsMenu()) {
|
1999-09-01 04:39:12 +04:00
|
|
|
// The menu item was selected. Bring up the menu.
|
|
|
|
// We have children.
|
2009-06-04 06:43:03 +04:00
|
|
|
// Don't prevent the default action here, since that will also cancel
|
|
|
|
// potential drag starts.
|
2014-05-25 02:20:41 +04:00
|
|
|
if (!menuParent || menuParent->IsMenuBar()) {
|
1999-07-31 15:29:03 +04:00
|
|
|
ToggleMenuState();
|
1999-07-20 13:35:35 +04:00
|
|
|
}
|
2007-07-04 19:49:38 +04:00
|
|
|
else {
|
2009-05-01 16:24:49 +04:00
|
|
|
if (!IsOpen()) {
|
2015-07-14 20:06:45 +03:00
|
|
|
menuParent->ChangeMenuItem(this, false, false);
|
2011-10-17 18:59:28 +04:00
|
|
|
OpenMenu(false);
|
2009-05-01 16:24:49 +04:00
|
|
|
}
|
2007-07-04 19:49:38 +04:00
|
|
|
}
|
1999-07-20 13:35:35 +04:00
|
|
|
}
|
2001-03-29 07:33:09 +04:00
|
|
|
else if (
|
|
|
|
#ifndef NSCONTEXTMENUISMOUSEUP
|
2015-08-29 02:58:30 +03:00
|
|
|
(aEvent->mMessage == eMouseUp &&
|
2013-10-22 12:55:20 +04:00
|
|
|
aEvent->AsMouseEvent()->button == WidgetMouseEvent::eRightButton) &&
|
2001-03-29 07:33:09 +04:00
|
|
|
#else
|
2015-08-31 18:20:06 +03:00
|
|
|
aEvent->mMessage == eContextMenu &&
|
2001-03-29 07:33:09 +04:00
|
|
|
#endif
|
2013-10-22 12:55:20 +04:00
|
|
|
onmenu && !IsMenu() && !IsDisabled()) {
|
2000-03-01 06:12:51 +03:00
|
|
|
// if this menu is a context menu it accepts right-clicks...fire away!
|
2001-03-29 07:33:09 +04: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.
|
2014-05-25 02:20:41 +04:00
|
|
|
if (menuParent->IsContextMenu()) {
|
2001-03-29 07:33:09 +04:00
|
|
|
*aEventStatus = nsEventStatus_eConsumeNoDefault;
|
2002-09-27 03:21:59 +04:00
|
|
|
Execute(aEvent);
|
2001-03-29 07:33:09 +04:00
|
|
|
}
|
2000-03-01 06:12:51 +03:00
|
|
|
}
|
2015-08-29 02:58:30 +03:00
|
|
|
else if (aEvent->mMessage == eMouseUp &&
|
2013-10-22 12:55:20 +04:00
|
|
|
aEvent->AsMouseEvent()->button == WidgetMouseEvent::eLeftButton &&
|
2007-07-04 19:49:38 +04:00
|
|
|
!IsMenu() && !IsDisabled()) {
|
1999-07-31 05:43:33 +04:00
|
|
|
// Execute the execute event handler.
|
2009-05-01 16:24:49 +04:00
|
|
|
*aEventStatus = nsEventStatus_eConsumeNoDefault;
|
2002-09-27 03:21:59 +04:00
|
|
|
Execute(aEvent);
|
1999-07-24 05:59:32 +04:00
|
|
|
}
|
2015-08-29 02:58:32 +03:00
|
|
|
else if (aEvent->mMessage == eMouseOut) {
|
1999-07-25 04:16:11 +04:00
|
|
|
// Kill our timer if one is active.
|
|
|
|
if (mOpenTimer) {
|
|
|
|
mOpenTimer->Cancel();
|
2012-07-30 18:20:58 +04:00
|
|
|
mOpenTimer = nullptr;
|
1999-07-25 04:16:11 +04:00
|
|
|
}
|
|
|
|
|
1999-07-21 11:42:16 +04:00
|
|
|
// Deactivate the menu.
|
2014-05-25 02:20:41 +04:00
|
|
|
if (menuParent) {
|
|
|
|
bool onmenubar = menuParent->IsMenuBar();
|
|
|
|
if (!(onmenubar && menuParent->IsActive())) {
|
2007-07-04 19:49:38 +04:00
|
|
|
if (IsMenu() && !onmenubar && IsOpen()) {
|
2000-02-13 11:33:39 +03:00
|
|
|
// Submenus don't get closed up immediately.
|
1999-07-26 08:38:28 +04:00
|
|
|
}
|
2014-05-25 02:20:41 +04:00
|
|
|
else if (this == menuParent->GetCurrentMenuItem()) {
|
2015-06-26 19:32:25 +03:00
|
|
|
menuParent->ChangeMenuItem(nullptr, false, false);
|
2007-10-02 13:41:29 +04:00
|
|
|
}
|
1999-07-26 08:38:28 +04:00
|
|
|
}
|
1999-07-23 12:36:39 +04:00
|
|
|
}
|
1999-07-21 11:42:16 +04:00
|
|
|
}
|
2015-08-29 02:58:29 +03:00
|
|
|
else if (aEvent->mMessage == eMouseMove &&
|
2014-05-25 02:20:41 +04:00
|
|
|
(onmenu || (menuParent && menuParent->IsMenuBar()))) {
|
1999-07-26 10:29:48 +04:00
|
|
|
if (gEatMouseMove) {
|
2011-10-17 18:59:28 +04:00
|
|
|
gEatMouseMove = false;
|
1999-07-26 10:29:48 +04:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
1999-08-02 11:26:24 +04:00
|
|
|
// Let the menu parent know we're the new item.
|
2015-06-26 19:32:25 +03:00
|
|
|
menuParent->ChangeMenuItem(this, false, false);
|
2006-09-04 00:25:58 +04:00
|
|
|
NS_ENSURE_TRUE(weakFrame.IsAlive(), NS_OK);
|
2014-05-25 02:20:41 +04:00
|
|
|
NS_ENSURE_TRUE(menuParent, NS_OK);
|
2007-07-04 19:49:38 +04:00
|
|
|
|
2005-09-28 22:48:27 +04:00
|
|
|
// we need to check if we really became the current menu
|
|
|
|
// item or not
|
2014-05-25 02:20:41 +04:00
|
|
|
nsMenuFrame *realCurrentItem = menuParent->GetCurrentMenuItem();
|
2005-09-28 22:48:27 +04:00
|
|
|
if (realCurrentItem != this) {
|
|
|
|
// we didn't (presumably because a context menu was active)
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2007-07-04 19:49:38 +04: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
|
2014-05-25 02:20:41 +04:00
|
|
|
if (!IsDisabled() && IsMenu() && !IsOpen() && !mOpenTimer && !menuParent->IsMenuBar()) {
|
2012-08-22 19:56:38 +04:00
|
|
|
int32_t menuDelay =
|
2011-09-09 06:27:13 +04:00
|
|
|
LookAndFeel::GetInt(LookAndFeel::eIntID_SubmenuDelay, 300); // ms
|
2000-01-22 00:56:09 +03:00
|
|
|
|
|
|
|
// We're a menu, we're built, we're closed, and no timer has been kicked off.
|
2000-09-14 03:57:52 +04:00
|
|
|
mOpenTimer = do_CreateInstance("@mozilla.org/timer;1");
|
2006-01-12 19:40:47 +03:00
|
|
|
mOpenTimer->InitWithCallback(mTimerMediator, menuDelay, nsITimer::TYPE_ONE_SHOT);
|
1999-07-25 05:14:43 +04:00
|
|
|
}
|
1999-07-21 11:42:16 +04:00
|
|
|
}
|
2000-08-17 03:14:50 +04:00
|
|
|
|
1999-07-20 13:35:35 +04:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2007-07-04 19:49:38 +04:00
|
|
|
void
|
1999-07-20 13:35:35 +04:00
|
|
|
nsMenuFrame::ToggleMenuState()
|
2007-06-29 23:04:45 +04:00
|
|
|
{
|
2007-07-04 19:49:38 +04:00
|
|
|
if (IsOpen())
|
2011-10-17 18:59:28 +04:00
|
|
|
CloseMenu(false);
|
2007-12-03 19:33:42 +03:00
|
|
|
else
|
2011-10-17 18:59:28 +04:00
|
|
|
OpenMenu(false);
|
2007-07-04 19:49:38 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsMenuFrame::PopupOpened()
|
|
|
|
{
|
|
|
|
nsWeakFrame weakFrame(this);
|
|
|
|
mContent->SetAttr(kNameSpaceID_None, nsGkAtoms::open,
|
2011-10-17 18:59:28 +04:00
|
|
|
NS_LITERAL_STRING("true"), true);
|
2007-07-04 19:49:38 +04:00
|
|
|
if (!weakFrame.IsAlive())
|
|
|
|
return;
|
2003-01-20 14:58:30 +03:00
|
|
|
|
2014-05-25 02:20:41 +04:00
|
|
|
nsMenuParent* menuParent = GetMenuParent();
|
|
|
|
if (menuParent) {
|
|
|
|
menuParent->SetActive(true);
|
2003-01-20 14:58:30 +03:00
|
|
|
// Make sure the current menu which is being toggled on
|
|
|
|
// the menubar is highlighted
|
2014-05-25 02:20:41 +04:00
|
|
|
menuParent->SetCurrentMenuItem(this);
|
1999-07-21 11:42:16 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-07-04 19:49:38 +04:00
|
|
|
void
|
2011-09-29 10:19:26 +04:00
|
|
|
nsMenuFrame::PopupClosed(bool aDeselectMenu)
|
1999-07-21 11:42:16 +04:00
|
|
|
{
|
2006-09-04 00:25:58 +04:00
|
|
|
nsWeakFrame weakFrame(this);
|
2008-12-03 13:56:58 +03:00
|
|
|
nsContentUtils::AddScriptRunner(
|
|
|
|
new nsUnsetAttrRunnable(mContent, nsGkAtoms::open));
|
2007-07-04 19:49:38 +04:00
|
|
|
if (!weakFrame.IsAlive())
|
|
|
|
return;
|
1999-09-21 05:03:00 +04:00
|
|
|
|
2007-07-04 19:49:38 +04:00
|
|
|
// if the popup is for a menu on a menubar, inform menubar to deactivate
|
2014-05-25 02:20:41 +04:00
|
|
|
nsMenuParent* menuParent = GetMenuParent();
|
|
|
|
if (menuParent && menuParent->MenuClosed()) {
|
2007-07-26 08:14:32 +04:00
|
|
|
if (aDeselectMenu) {
|
2011-10-17 18:59:28 +04:00
|
|
|
SelectMenu(false);
|
2007-07-26 08:14:32 +04: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.
|
2014-05-25 02:20:41 +04:00
|
|
|
nsMenuFrame *current = menuParent->GetCurrentMenuItem();
|
2007-07-26 08:14:32 +04:00
|
|
|
if (current) {
|
2013-01-12 00:21:48 +04:00
|
|
|
// However, if the menu is a descendant on a menubar, and the menubar
|
|
|
|
// has the 'stay active' flag set, it means that the menubar is switching
|
|
|
|
// to another toplevel menu entirely (for example from Edit to View), so
|
|
|
|
// don't fire the DOMMenuItemActive event or else we'll send extraneous
|
|
|
|
// events for submenus. nsMenuBarFrame::ChangeMenuItem has already deselected
|
|
|
|
// the old menu, so it doesn't need to happen again here, and the new
|
|
|
|
// menu can be selected right away.
|
|
|
|
nsIFrame* parent = current;
|
|
|
|
while (parent) {
|
|
|
|
nsMenuBarFrame* menubar = do_QueryFrame(parent);
|
|
|
|
if (menubar && menubar->GetStayActive())
|
|
|
|
return;
|
|
|
|
|
|
|
|
parent = parent->GetParent();
|
|
|
|
}
|
|
|
|
|
2007-07-26 08:14:32 +04:00
|
|
|
nsCOMPtr<nsIRunnable> event =
|
|
|
|
new nsMenuActivateEvent(current->GetContent(),
|
2011-10-17 18:59:28 +04:00
|
|
|
PresContext(), true);
|
2007-07-26 08:14:32 +04:00
|
|
|
NS_DispatchToCurrentThread(event);
|
|
|
|
}
|
2007-07-04 19:49:38 +04:00
|
|
|
}
|
2000-05-15 08:12:31 +04:00
|
|
|
}
|
2007-07-26 08:14:32 +04:00
|
|
|
}
|
1999-08-13 00:45:47 +04:00
|
|
|
|
2007-06-30 02:15:59 +04:00
|
|
|
NS_IMETHODIMP
|
2011-09-29 10:19:26 +04:00
|
|
|
nsMenuFrame::SelectMenu(bool aActivateFlag)
|
2007-06-30 02:15:59 +04:00
|
|
|
{
|
2007-07-04 19:49:38 +04:00
|
|
|
if (mContent) {
|
2007-07-11 16:05:40 +04: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) {
|
2012-07-31 04:43:28 +04:00
|
|
|
nsMenuPopupFrame* menupopup = do_QueryFrame(parent);
|
|
|
|
if (menupopup) {
|
2007-07-11 16:05:40 +04:00
|
|
|
// a menu is always the direct parent of a menupopup
|
2012-07-31 04:43:28 +04:00
|
|
|
nsMenuFrame* menu = do_QueryFrame(menupopup->GetParent());
|
|
|
|
if (menu) {
|
2007-07-11 16:05:40 +04:00
|
|
|
// a popup however is not necessarily the direct parent of a menu
|
2012-07-31 04:43:28 +04:00
|
|
|
nsIFrame* popupParent = menu->GetParent();
|
2007-07-11 16:05:40 +04:00
|
|
|
while (popupParent) {
|
2012-07-31 04:43:28 +04:00
|
|
|
menupopup = do_QueryFrame(popupParent);
|
|
|
|
if (menupopup) {
|
|
|
|
menupopup->SetCurrentMenuItem(menu);
|
2007-07-11 16:05:40 +04:00
|
|
|
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();
|
2014-05-25 02:20:41 +04:00
|
|
|
if (pm) {
|
|
|
|
nsMenuParent* menuParent = GetMenuParent();
|
|
|
|
pm->CancelMenuTimer(menuParent);
|
|
|
|
}
|
2007-07-11 16:05:40 +04:00
|
|
|
|
2007-07-04 19:49:38 +04:00
|
|
|
nsCOMPtr<nsIRunnable> event =
|
|
|
|
new nsMenuActivateEvent(mContent, PresContext(), aActivateFlag);
|
|
|
|
NS_DispatchToCurrentThread(event);
|
2007-06-30 02:15:59 +04:00
|
|
|
}
|
2007-07-04 19:49:38 +04:00
|
|
|
|
2007-06-30 02:15:59 +04:00
|
|
|
return NS_OK;
|
2007-07-04 19:49:38 +04:00
|
|
|
}
|
2007-06-30 02:15:59 +04:00
|
|
|
|
2014-02-18 11:47:48 +04:00
|
|
|
nsresult
|
2012-08-22 19:56:38 +04:00
|
|
|
nsMenuFrame::AttributeChanged(int32_t aNameSpaceID,
|
1999-09-08 07:51:41 +04:00
|
|
|
nsIAtom* aAttribute,
|
2012-08-22 19:56:38 +04:00
|
|
|
int32_t aModType)
|
1999-09-08 07:51:41 +04:00
|
|
|
{
|
2011-02-13 15:28:00 +03:00
|
|
|
if (aAttribute == nsGkAtoms::acceltext && mIgnoreAccelTextChange) {
|
|
|
|
// Reset the flag so that only one change is ignored.
|
2011-10-17 18:59:28 +04:00
|
|
|
mIgnoreAccelTextChange = false;
|
2011-02-13 15:28:00 +03:00
|
|
|
return NS_OK;
|
|
|
|
}
|
1999-09-18 00:12:02 +04:00
|
|
|
|
2010-08-12 15:59:03 +04:00
|
|
|
if (aAttribute == nsGkAtoms::checked ||
|
|
|
|
aAttribute == nsGkAtoms::acceltext ||
|
|
|
|
aAttribute == nsGkAtoms::key ||
|
|
|
|
aAttribute == nsGkAtoms::type ||
|
|
|
|
aAttribute == nsGkAtoms::name) {
|
|
|
|
nsCOMPtr<nsIRunnable> event =
|
|
|
|
new nsMenuAttributeChangedEvent(this, aAttribute);
|
|
|
|
nsContentUtils::AddScriptRunner(event);
|
|
|
|
}
|
1999-09-08 07:51:41 +04:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2014-01-28 20:28:45 +04:00
|
|
|
nsIContent*
|
|
|
|
nsMenuFrame::GetAnchor()
|
|
|
|
{
|
|
|
|
mozilla::dom::Element* anchor = nullptr;
|
|
|
|
|
|
|
|
nsAutoString id;
|
|
|
|
mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::anchor, id);
|
|
|
|
if (!id.IsEmpty()) {
|
|
|
|
nsIDocument* doc = mContent->OwnerDoc();
|
|
|
|
|
|
|
|
anchor =
|
|
|
|
doc->GetAnonymousElementByAttribute(mContent, nsGkAtoms::anonid, id);
|
|
|
|
if (!anchor) {
|
|
|
|
anchor = doc->GetElementById(id);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Always return the menu's content if the anchor wasn't set or wasn't found.
|
|
|
|
return anchor && anchor->GetPrimaryFrame() ? anchor : mContent;
|
|
|
|
}
|
|
|
|
|
2007-07-04 19:49:38 +04:00
|
|
|
void
|
2011-09-29 10:19:26 +04:00
|
|
|
nsMenuFrame::OpenMenu(bool aSelectFirstItem)
|
1999-09-08 07:51:41 +04:00
|
|
|
{
|
2002-06-28 07:10:08 +04:00
|
|
|
if (!mContent)
|
2007-06-30 02:15:59 +04:00
|
|
|
return;
|
|
|
|
|
2011-10-17 18:59:28 +04:00
|
|
|
gEatMouseMove = true;
|
2007-06-30 02:15:59 +04:00
|
|
|
|
2007-07-04 19:49:38 +04:00
|
|
|
nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
|
|
|
|
if (pm) {
|
|
|
|
pm->KillMenuTimer();
|
|
|
|
// This opens the menu asynchronously
|
2011-10-17 18:59:28 +04:00
|
|
|
pm->ShowMenu(mContent, aSelectFirstItem, true);
|
2007-06-30 02:15:59 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2011-09-29 10:19:26 +04:00
|
|
|
nsMenuFrame::CloseMenu(bool aDeselectMenu)
|
2007-06-30 02:15:59 +04:00
|
|
|
{
|
2011-10-17 18:59:28 +04:00
|
|
|
gEatMouseMove = true;
|
2007-07-04 19:49:38 +04:00
|
|
|
|
|
|
|
// Close the menu asynchronously
|
|
|
|
nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
|
2012-03-08 05:57:37 +04:00
|
|
|
if (pm && HasPopup())
|
2014-04-08 16:45:52 +04:00
|
|
|
pm->HidePopup(GetPopup()->GetContent(), false, aDeselectMenu, true, false);
|
1999-07-20 13:35:35 +04:00
|
|
|
}
|
|
|
|
|
2011-09-29 10:19:26 +04:00
|
|
|
bool
|
|
|
|
nsMenuFrame::IsSizedToPopup(nsIContent* aContent, bool aRequireAlways)
|
2002-03-18 02:41:22 +03:00
|
|
|
{
|
2014-01-15 07:07:31 +04:00
|
|
|
nsAutoString sizedToPopup;
|
|
|
|
aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::sizetopopup, sizedToPopup);
|
|
|
|
return sizedToPopup.EqualsLiteral("always") ||
|
|
|
|
(!aRequireAlways && sizedToPopup.EqualsLiteral("pref"));
|
2002-03-18 02:41:22 +03:00
|
|
|
}
|
|
|
|
|
2007-01-08 05:57:59 +03:00
|
|
|
nsSize
|
|
|
|
nsMenuFrame::GetMinSize(nsBoxLayoutState& aBoxLayoutState)
|
2002-02-28 10:28:39 +03:00
|
|
|
{
|
2007-01-08 05:57:59 +03:00
|
|
|
nsSize size = nsBoxFrame::GetMinSize(aBoxLayoutState);
|
|
|
|
DISPLAY_MIN_SIZE(this, size);
|
2002-02-28 10:28:39 +03:00
|
|
|
|
2011-10-17 18:59:28 +04:00
|
|
|
if (IsSizedToPopup(mContent, true))
|
2007-01-08 05:57:59 +03:00
|
|
|
SizeToPopup(aBoxLayoutState, size);
|
2002-02-28 10:28:39 +03:00
|
|
|
|
2007-01-08 05:57:59 +03:00
|
|
|
return size;
|
2002-02-28 10:28:39 +03:00
|
|
|
}
|
|
|
|
|
2000-03-31 11:02:06 +04:00
|
|
|
NS_IMETHODIMP
|
2000-07-08 02:24:06 +04:00
|
|
|
nsMenuFrame::DoLayout(nsBoxLayoutState& aState)
|
2000-03-31 11:02:06 +04:00
|
|
|
{
|
|
|
|
// lay us out
|
2000-07-08 02:24:06 +04:00
|
|
|
nsresult rv = nsBoxFrame::DoLayout(aState);
|
2000-03-31 11:02:06 +04:00
|
|
|
|
2012-03-08 05:57:37 +04:00
|
|
|
nsMenuPopupFrame* popupFrame = GetPopup();
|
|
|
|
if (popupFrame) {
|
2011-09-29 10:19:26 +04:00
|
|
|
bool sizeToPopup = IsSizedToPopup(mContent, false);
|
2014-01-28 20:28:45 +04:00
|
|
|
popupFrame->LayoutPopup(aState, this, GetAnchor()->GetPrimaryFrame(), sizeToPopup);
|
2000-03-31 11:02:06 +04:00
|
|
|
}
|
|
|
|
|
2000-05-15 08:12:31 +04:00
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
2004-06-19 13:07:47 +04:00
|
|
|
#ifdef DEBUG_LAYOUT
|
2014-02-18 11:47:48 +04:00
|
|
|
nsresult
|
2011-09-29 10:19:26 +04:00
|
|
|
nsMenuFrame::SetDebug(nsBoxLayoutState& aState, bool aDebug)
|
2000-03-02 06:01:30 +03:00
|
|
|
{
|
|
|
|
// see if our state matches the given debug state
|
2011-09-29 10:19:26 +04:00
|
|
|
bool debugSet = mState & NS_STATE_CURRENTLY_IN_DEBUG;
|
|
|
|
bool debugChanged = (!aDebug && debugSet) || (aDebug && !debugSet);
|
2000-03-02 06:01:30 +03:00
|
|
|
|
|
|
|
// if it doesn't then tell each child below us the new debug state
|
|
|
|
if (debugChanged)
|
|
|
|
{
|
2000-03-31 11:02:06 +04:00
|
|
|
nsBoxFrame::SetDebug(aState, aDebug);
|
2012-03-08 05:57:37 +04:00
|
|
|
nsMenuPopupFrame* popupFrame = GetPopup();
|
|
|
|
if (popupFrame)
|
|
|
|
SetDebug(aState, popupFrame, aDebug);
|
2000-03-02 06:01:30 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
2011-09-29 10:19:26 +04:00
|
|
|
nsMenuFrame::SetDebug(nsBoxLayoutState& aState, nsIFrame* aList, bool aDebug)
|
2000-03-02 06:01:30 +03:00
|
|
|
{
|
|
|
|
if (!aList)
|
|
|
|
return NS_OK;
|
|
|
|
|
|
|
|
while (aList) {
|
2004-09-28 22:37:50 +04:00
|
|
|
if (aList->IsBoxFrame())
|
|
|
|
aList->SetDebug(aState, aDebug);
|
2000-03-02 06:01:30 +03:00
|
|
|
|
2004-09-28 22:37:50 +04:00
|
|
|
aList = aList->GetNextSibling();
|
2000-03-02 06:01:30 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
2004-06-19 13:07:47 +04:00
|
|
|
#endif
|
2000-03-02 06:01:30 +03:00
|
|
|
|
2000-08-25 05:59:53 +04: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 19:49:38 +04:00
|
|
|
nsMenuFrame*
|
2013-10-02 07:46:03 +04:00
|
|
|
nsMenuFrame::Enter(WidgetGUIEvent* aEvent)
|
1999-07-25 02:02:23 +04:00
|
|
|
{
|
2002-02-15 06:53:26 +03:00
|
|
|
if (IsDisabled()) {
|
|
|
|
#ifdef XP_WIN
|
|
|
|
// behavior on Windows - close the popup chain
|
2014-05-25 02:20:41 +04:00
|
|
|
nsMenuParent* menuParent = GetMenuParent();
|
|
|
|
if (menuParent) {
|
2007-07-04 19:49:38 +04:00
|
|
|
nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
|
2007-09-18 19:00:43 +04:00
|
|
|
if (pm) {
|
|
|
|
nsIFrame* popup = pm->GetTopPopup(ePopupTypeAny);
|
|
|
|
if (popup)
|
2014-04-08 16:45:52 +04:00
|
|
|
pm->HidePopup(popup->GetContent(), true, true, true, false);
|
2007-09-18 19:00:43 +04:00
|
|
|
}
|
2007-07-04 19:49:38 +04:00
|
|
|
}
|
2002-02-15 06:53:26 +03:00
|
|
|
#endif // #ifdef XP_WIN
|
|
|
|
// this menu item was disabled - exit
|
2012-07-30 18:20:58 +04:00
|
|
|
return nullptr;
|
2002-02-15 06:53:26 +03:00
|
|
|
}
|
2007-07-04 19:49:38 +04:00
|
|
|
|
|
|
|
if (!IsOpen()) {
|
1999-07-25 02:02:23 +04:00
|
|
|
// The enter key press applies to us.
|
2014-05-25 02:20:41 +04:00
|
|
|
nsMenuParent* menuParent = GetMenuParent();
|
|
|
|
if (!IsMenu() && menuParent)
|
2011-04-13 21:53:24 +04:00
|
|
|
Execute(aEvent); // Execute our event handler
|
2007-07-04 19:49:38 +04:00
|
|
|
else
|
|
|
|
return this;
|
2007-06-30 02:15:59 +04:00
|
|
|
}
|
|
|
|
|
2012-07-30 18:20:58 +04:00
|
|
|
return nullptr;
|
1999-07-25 02:02:23 +04:00
|
|
|
}
|
|
|
|
|
2011-09-29 10:19:26 +04:00
|
|
|
bool
|
2007-07-04 19:49:38 +04:00
|
|
|
nsMenuFrame::IsOpen()
|
1999-07-22 13:01:55 +04:00
|
|
|
{
|
2012-03-08 05:57:37 +04:00
|
|
|
nsMenuPopupFrame* popupFrame = GetPopup();
|
|
|
|
return popupFrame && popupFrame->IsOpen();
|
1999-07-25 04:16:11 +04:00
|
|
|
}
|
|
|
|
|
2011-09-29 10:19:26 +04:00
|
|
|
bool
|
1999-07-25 04:16:11 +04:00
|
|
|
nsMenuFrame::IsMenu()
|
|
|
|
{
|
2000-03-13 13:20:34 +03:00
|
|
|
return mIsMenu;
|
1999-07-25 05:14:43 +04:00
|
|
|
}
|
|
|
|
|
2011-06-25 01:00:35 +04:00
|
|
|
nsMenuListType
|
|
|
|
nsMenuFrame::GetParentMenuListType()
|
|
|
|
{
|
2014-05-25 02:20:41 +04:00
|
|
|
nsMenuParent* menuParent = GetMenuParent();
|
|
|
|
if (menuParent && menuParent->IsMenu()) {
|
|
|
|
nsMenuPopupFrame* popupFrame = static_cast<nsMenuPopupFrame*>(menuParent);
|
2011-06-25 01:00:35 +04:00
|
|
|
nsIFrame* parentMenu = popupFrame->GetParent();
|
|
|
|
if (parentMenu) {
|
|
|
|
nsCOMPtr<nsIDOMXULMenuListElement> menulist = do_QueryInterface(parentMenu->GetContent());
|
|
|
|
if (menulist) {
|
2011-09-29 10:19:26 +04:00
|
|
|
bool isEditable = false;
|
2011-06-25 01:00:35 +04:00
|
|
|
menulist->GetEditable(&isEditable);
|
|
|
|
return isEditable ? eEditableMenuList : eReadonlyMenuList;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return eNotMenuList;
|
|
|
|
}
|
|
|
|
|
2006-01-12 19:40:47 +03:00
|
|
|
nsresult
|
1999-07-25 05:14:43 +04:00
|
|
|
nsMenuFrame::Notify(nsITimer* aTimer)
|
|
|
|
{
|
|
|
|
// Our timer has fired.
|
1999-07-26 08:38:28 +04:00
|
|
|
if (aTimer == mOpenTimer.get()) {
|
2012-07-30 18:20:58 +04:00
|
|
|
mOpenTimer = nullptr;
|
2007-07-04 19:49:38 +04:00
|
|
|
|
2014-05-25 02:20:41 +04:00
|
|
|
nsMenuParent* menuParent = GetMenuParent();
|
|
|
|
if (!IsOpen() && menuParent) {
|
2005-09-28 22:48:27 +04:00
|
|
|
// make sure we didn't open a context menu in the meantime
|
2005-09-30 21:35:14 +04:00
|
|
|
// (i.e. the user right-clicked while hovering over a submenu).
|
2007-07-04 19:49:38 +04:00
|
|
|
nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
|
|
|
|
if (pm) {
|
2014-05-25 02:20:41 +04:00
|
|
|
if ((!pm->HasContextMenu(nullptr) || menuParent->IsContextMenu()) &&
|
2007-07-04 19:49:38 +04:00
|
|
|
mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::menuactive,
|
2006-12-26 20:47:52 +03:00
|
|
|
nsGkAtoms::_true, eCaseMatters)) {
|
2011-10-17 18:59:28 +04:00
|
|
|
OpenMenu(false);
|
2005-09-28 22:48:27 +04:00
|
|
|
}
|
1999-07-26 08:38:28 +04:00
|
|
|
}
|
1999-07-25 05:14:43 +04:00
|
|
|
}
|
2010-04-19 18:12:58 +04:00
|
|
|
} else if (aTimer == mBlinkTimer) {
|
|
|
|
switch (mBlinkState++) {
|
|
|
|
case 0:
|
|
|
|
NS_ASSERTION(false, "Blink timer fired while not blinking");
|
|
|
|
StopBlinking();
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
{
|
|
|
|
// Turn the highlight back on and wait for a while before closing the menu.
|
|
|
|
nsWeakFrame weakFrame(this);
|
|
|
|
mContent->SetAttr(kNameSpaceID_None, nsGkAtoms::menuactive,
|
2011-10-17 18:59:28 +04:00
|
|
|
NS_LITERAL_STRING("true"), true);
|
2010-04-19 18:12:58 +04:00
|
|
|
if (weakFrame.IsAlive()) {
|
|
|
|
aTimer->InitWithCallback(mTimerMediator, kBlinkDelay, nsITimer::TYPE_ONE_SHOT);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
2014-05-25 02:20:41 +04:00
|
|
|
default: {
|
|
|
|
nsMenuParent* menuParent = GetMenuParent();
|
|
|
|
if (menuParent) {
|
|
|
|
menuParent->LockMenuUntilClosed(false);
|
2010-04-19 18:12:58 +04:00
|
|
|
}
|
|
|
|
PassMenuCommandEventToPopupManager();
|
|
|
|
StopBlinking();
|
|
|
|
break;
|
2014-05-25 02:20:41 +04:00
|
|
|
}
|
2010-04-19 18:12:58 +04:00
|
|
|
}
|
1999-07-25 05:14:43 +04:00
|
|
|
}
|
2007-07-04 19:49:38 +04:00
|
|
|
|
2002-09-07 09:38:16 +04:00
|
|
|
return NS_OK;
|
1999-07-25 05:14:43 +04:00
|
|
|
}
|
1999-07-26 05:35:39 +04:00
|
|
|
|
2011-09-29 10:19:26 +04:00
|
|
|
bool
|
1999-07-26 05:35:39 +04:00
|
|
|
nsMenuFrame::IsDisabled()
|
|
|
|
{
|
2006-12-26 20:47:52 +03:00
|
|
|
return mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::disabled,
|
|
|
|
nsGkAtoms::_true, eCaseMatters);
|
1999-07-26 05:35:39 +04:00
|
|
|
}
|
1999-07-31 05:43:33 +04:00
|
|
|
|
1999-10-16 01:13:24 +04:00
|
|
|
void
|
2015-12-07 04:15:53 +03:00
|
|
|
nsMenuFrame::UpdateMenuType()
|
1999-10-16 01:13:24 +04:00
|
|
|
{
|
2006-04-24 09:40:11 +04:00
|
|
|
static nsIContent::AttrValuesArray strings[] =
|
2012-07-30 18:20:58 +04:00
|
|
|
{&nsGkAtoms::checkbox, &nsGkAtoms::radio, nullptr};
|
2006-12-26 20:47:52 +03:00
|
|
|
switch (mContent->FindAttrValueIn(kNameSpaceID_None, nsGkAtoms::type,
|
2006-04-24 09:40:11 +04:00
|
|
|
strings, eCaseMatters)) {
|
|
|
|
case 0: mType = eMenuType_Checkbox; break;
|
|
|
|
case 1:
|
|
|
|
mType = eMenuType_Radio;
|
2006-12-26 20:47:52 +03:00
|
|
|
mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::name, mGroupName);
|
2006-04-24 09:40:11 +04:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
2006-09-04 00:25:58 +04:00
|
|
|
if (mType != eMenuType_Normal) {
|
|
|
|
nsWeakFrame weakFrame(this);
|
2006-12-26 20:47:52 +03:00
|
|
|
mContent->UnsetAttr(kNameSpaceID_None, nsGkAtoms::checked,
|
2011-10-17 18:59:28 +04:00
|
|
|
true);
|
2006-09-04 00:25:58 +04:00
|
|
|
ENSURE_TRUE(weakFrame.IsAlive());
|
|
|
|
}
|
2006-04-24 09:40:11 +04:00
|
|
|
mType = eMenuType_Normal;
|
|
|
|
break;
|
1999-10-16 01:13:24 +04:00
|
|
|
}
|
2015-12-07 04:15:53 +03:00
|
|
|
UpdateMenuSpecialState();
|
1999-10-16 01:13:24 +04:00
|
|
|
}
|
|
|
|
|
1999-10-18 01:37:37 +04:00
|
|
|
/* update checked-ness for type="checkbox" and type="radio" */
|
1999-10-16 01:13:24 +04:00
|
|
|
void
|
2015-12-07 04:15:53 +03:00
|
|
|
nsMenuFrame::UpdateMenuSpecialState()
|
2007-07-04 19:49:38 +04:00
|
|
|
{
|
2011-09-29 10:19:26 +04:00
|
|
|
bool newChecked =
|
2006-12-26 20:47:52 +03:00
|
|
|
mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::checked,
|
|
|
|
nsGkAtoms::_true, eCaseMatters);
|
1999-10-18 01:37:37 +04: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-07 00:39:21 +04:00
|
|
|
if (!mChecked || mGroupName.IsEmpty())
|
1999-10-18 01:37:37 +04: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 04:50:48 +03: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.
|
2014-05-13 00:23:12 +04:00
|
|
|
nsIFrame* firstMenuItem = nsXULPopupManager::GetNextMenuItem(GetParent(), nullptr, true);
|
|
|
|
nsIFrame* sib = firstMenuItem;
|
2007-07-04 19:49:38 +04:00
|
|
|
while (sib) {
|
2014-05-13 00:23:12 +04:00
|
|
|
nsMenuFrame* menu = do_QueryFrame(sib);
|
2012-07-31 04:43:28 +04:00
|
|
|
if (sib != this) {
|
|
|
|
if (menu && menu->GetMenuType() == eMenuType_Radio &&
|
|
|
|
menu->IsChecked() && menu->GetRadioGroupName() == mGroupName) {
|
2007-07-04 19:49:38 +04:00
|
|
|
/* uncheck the old item */
|
|
|
|
sib->GetContent()->UnsetAttr(kNameSpaceID_None, nsGkAtoms::checked,
|
2011-10-17 18:59:28 +04:00
|
|
|
true);
|
2007-07-04 19:49:38 +04:00
|
|
|
/* XXX in DEBUG, check to make sure that there aren't two checked items */
|
|
|
|
return;
|
|
|
|
}
|
1999-10-18 01:37:37 +04:00
|
|
|
}
|
2014-05-13 00:23:12 +04:00
|
|
|
sib = nsXULPopupManager::GetNextMenuItem(GetParent(), menu, true);
|
|
|
|
if (sib == firstMenuItem) {
|
|
|
|
break;
|
|
|
|
}
|
2007-07-04 19:49:38 +04:00
|
|
|
}
|
1999-10-16 01:13:24 +04:00
|
|
|
}
|
|
|
|
|
1999-07-31 05:43:33 +04:00
|
|
|
void
|
2011-09-29 10:19:26 +04:00
|
|
|
nsMenuFrame::BuildAcceleratorText(bool aNotify)
|
1999-07-31 05:43:33 +04:00
|
|
|
{
|
2000-03-28 04:41:33 +04:00
|
|
|
nsAutoString accelText;
|
2001-10-11 07:03:42 +04:00
|
|
|
|
2003-08-04 16:39:51 +04:00
|
|
|
if ((GetStateBits() & NS_STATE_ACCELTEXT_IS_DERIVED) == 0) {
|
2006-12-26 20:47:52 +03:00
|
|
|
mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::acceltext, accelText);
|
2001-10-11 07:03:42 +04:00
|
|
|
if (!accelText.IsEmpty())
|
|
|
|
return;
|
1999-07-31 05:43:33 +04:00
|
|
|
}
|
2001-10-11 07:03:42 +04:00
|
|
|
// accelText is definitely empty here.
|
|
|
|
|
|
|
|
// Now we're going to compute the accelerator text, so remember that we did.
|
2003-08-04 16:39:51 +04:00
|
|
|
AddStateBits(NS_STATE_ACCELTEXT_IS_DERIVED);
|
2001-10-11 07:03:42 +04:00
|
|
|
|
|
|
|
// If anything below fails, just leave the accelerator text blank.
|
2006-09-04 00:25:58 +04:00
|
|
|
nsWeakFrame weakFrame(this);
|
2011-02-13 15:28:00 +03:00
|
|
|
mContent->UnsetAttr(kNameSpaceID_None, nsGkAtoms::acceltext, aNotify);
|
2006-09-04 00:25:58 +04:00
|
|
|
ENSURE_TRUE(weakFrame.IsAlive());
|
1999-07-31 05:43:33 +04:00
|
|
|
|
|
|
|
// See if we have a key node and use that instead.
|
2000-03-28 04:41:33 +04:00
|
|
|
nsAutoString keyValue;
|
2006-12-26 20:47:52 +03:00
|
|
|
mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::key, keyValue);
|
2000-07-29 01:48:08 +04:00
|
|
|
if (keyValue.IsEmpty())
|
|
|
|
return;
|
|
|
|
|
2003-03-26 10:41:30 +03:00
|
|
|
// Turn the document into a DOM document so we can use getElementById
|
2014-08-23 00:11:27 +04:00
|
|
|
nsIDocument *document = mContent->GetUncomposedDoc();
|
2010-06-24 01:35:57 +04:00
|
|
|
if (!document)
|
1999-07-31 05:43:33 +04:00
|
|
|
return;
|
|
|
|
|
2014-08-23 00:11:27 +04:00
|
|
|
//XXXsmaug If mContent is in shadow dom, should we use
|
|
|
|
// ShadowRoot::GetElementById()?
|
2010-06-24 01:35:57 +04:00
|
|
|
nsIContent *keyElement = document->GetElementById(keyValue);
|
|
|
|
if (!keyElement) {
|
2007-02-24 08:42:36 +03:00
|
|
|
#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 04:28:36 +03:00
|
|
|
return;
|
2007-02-24 08:42:36 +03:00
|
|
|
}
|
2001-01-09 04:28:36 +03: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 20:47:52 +03:00
|
|
|
keyElement->GetAttr(kNameSpaceID_None, nsGkAtoms::keytext, accelString);
|
2001-01-09 04:28:36 +03:00
|
|
|
|
|
|
|
if (accelString.IsEmpty()) {
|
2006-12-26 20:47:52 +03:00
|
|
|
keyElement->GetAttr(kNameSpaceID_None, nsGkAtoms::key, accelString);
|
2001-01-09 04:28:36 +03:00
|
|
|
|
|
|
|
if (!accelString.IsEmpty()) {
|
2001-12-17 10:14:49 +03:00
|
|
|
ToUpperCase(accelString);
|
2001-01-09 04:28:36 +03:00
|
|
|
} else {
|
|
|
|
nsAutoString keyCode;
|
2006-12-26 20:47:52 +03:00
|
|
|
keyElement->GetAttr(kNameSpaceID_None, nsGkAtoms::keycode, keyCode);
|
2001-12-17 10:14:49 +03:00
|
|
|
ToUpperCase(keyCode);
|
2001-01-09 04:28:36 +03:00
|
|
|
|
|
|
|
nsresult rv;
|
2010-05-14 13:24:41 +04:00
|
|
|
nsCOMPtr<nsIStringBundleService> bundleService =
|
|
|
|
mozilla::services::GetStringBundleService();
|
|
|
|
if (bundleService) {
|
2001-01-09 04:28:36 +03:00
|
|
|
nsCOMPtr<nsIStringBundle> bundle;
|
|
|
|
rv = bundleService->CreateBundle("chrome://global/locale/keys.properties",
|
|
|
|
getter_AddRefs(bundle));
|
|
|
|
|
|
|
|
if (NS_SUCCEEDED(rv) && bundle) {
|
|
|
|
nsXPIDLString keyName;
|
2001-06-30 15:02:25 +04:00
|
|
|
rv = bundle->GetStringFromName(keyCode.get(), getter_Copies(keyName));
|
2001-01-09 04:28:36 +03:00
|
|
|
if (keyName)
|
|
|
|
accelString = keyName;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// nothing usable found, bail
|
|
|
|
if (accelString.IsEmpty())
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2000-09-22 09:02:20 +04:00
|
|
|
nsAutoString modifiers;
|
2006-12-26 20:47:52 +03:00
|
|
|
keyElement->GetAttr(kNameSpaceID_None, nsGkAtoms::modifiers, modifiers);
|
2000-09-22 09:02:20 +04:00
|
|
|
|
2001-09-29 12:28:41 +04:00
|
|
|
char* str = ToNewCString(modifiers);
|
2000-09-22 09:02:20 +04:00
|
|
|
char* newStr;
|
2005-09-02 19:54:27 +04:00
|
|
|
char* token = nsCRT::strtok(str, ", \t", &newStr);
|
2011-07-31 23:43:54 +04:00
|
|
|
|
|
|
|
nsAutoString shiftText;
|
|
|
|
nsAutoString altText;
|
|
|
|
nsAutoString metaText;
|
|
|
|
nsAutoString controlText;
|
2012-07-19 05:28:16 +04:00
|
|
|
nsAutoString osText;
|
2011-07-31 23:43:54 +04:00
|
|
|
nsAutoString modifierSeparator;
|
|
|
|
|
|
|
|
nsContentUtils::GetShiftText(shiftText);
|
|
|
|
nsContentUtils::GetAltText(altText);
|
|
|
|
nsContentUtils::GetMetaText(metaText);
|
|
|
|
nsContentUtils::GetControlText(controlText);
|
2012-07-19 05:28:16 +04:00
|
|
|
nsContentUtils::GetOSText(osText);
|
2011-07-31 23:43:54 +04:00
|
|
|
nsContentUtils::GetModifierSeparatorText(modifierSeparator);
|
|
|
|
|
2001-01-09 04:28:36 +03:00
|
|
|
while (token) {
|
2000-09-22 09:02:20 +04:00
|
|
|
|
|
|
|
if (PL_strcmp(token, "shift") == 0)
|
2011-07-31 23:43:54 +04:00
|
|
|
accelText += shiftText;
|
2000-09-22 09:02:20 +04:00
|
|
|
else if (PL_strcmp(token, "alt") == 0)
|
2011-07-31 23:43:54 +04:00
|
|
|
accelText += altText;
|
2000-09-22 09:02:20 +04:00
|
|
|
else if (PL_strcmp(token, "meta") == 0)
|
2011-07-31 23:43:54 +04:00
|
|
|
accelText += metaText;
|
2012-07-19 05:28:16 +04:00
|
|
|
else if (PL_strcmp(token, "os") == 0)
|
|
|
|
accelText += osText;
|
2000-09-22 09:02:20 +04:00
|
|
|
else if (PL_strcmp(token, "control") == 0)
|
2011-07-31 23:43:54 +04:00
|
|
|
accelText += controlText;
|
2000-09-22 09:02:20 +04:00
|
|
|
else if (PL_strcmp(token, "accel") == 0) {
|
2014-05-22 08:06:06 +04:00
|
|
|
switch (WidgetInputEvent::AccelModifier()) {
|
|
|
|
case MODIFIER_META:
|
2011-07-31 23:43:54 +04:00
|
|
|
accelText += metaText;
|
2000-09-22 09:02:20 +04:00
|
|
|
break;
|
2014-05-22 08:06:06 +04:00
|
|
|
case MODIFIER_OS:
|
2012-07-19 05:28:16 +04:00
|
|
|
accelText += osText;
|
|
|
|
break;
|
2014-05-22 08:06:06 +04:00
|
|
|
case MODIFIER_ALT:
|
2011-07-31 23:43:54 +04:00
|
|
|
accelText += altText;
|
2000-09-22 09:02:20 +04:00
|
|
|
break;
|
2014-05-22 08:06:06 +04:00
|
|
|
case MODIFIER_CONTROL:
|
2011-07-31 23:43:54 +04:00
|
|
|
accelText += controlText;
|
2000-09-22 09:02:20 +04:00
|
|
|
break;
|
2014-05-22 08:06:06 +04:00
|
|
|
default:
|
|
|
|
MOZ_CRASH(
|
|
|
|
"Handle the new result of WidgetInputEvent::AccelModifier()");
|
|
|
|
break;
|
2000-09-22 09:02:20 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-07-31 23:43:54 +04:00
|
|
|
accelText += modifierSeparator;
|
2001-01-09 04:28:36 +03:00
|
|
|
|
2005-09-02 19:54:27 +04:00
|
|
|
token = nsCRT::strtok(newStr, ", \t", &newStr);
|
1999-07-31 05:43:33 +04:00
|
|
|
}
|
|
|
|
|
2015-03-27 03:01:12 +03:00
|
|
|
free(str);
|
2000-09-22 09:02:20 +04:00
|
|
|
|
2001-10-11 07:03:42 +04:00
|
|
|
accelText += accelString;
|
2011-02-13 15:28:00 +03:00
|
|
|
|
2011-10-17 18:59:28 +04:00
|
|
|
mIgnoreAccelTextChange = true;
|
2011-02-13 15:28:00 +03:00
|
|
|
mContent->SetAttr(kNameSpaceID_None, nsGkAtoms::acceltext, accelText, aNotify);
|
|
|
|
ENSURE_TRUE(weakFrame.IsAlive());
|
|
|
|
|
2011-10-17 18:59:28 +04:00
|
|
|
mIgnoreAccelTextChange = false;
|
1999-07-31 05:43:33 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2013-10-02 07:46:03 +04:00
|
|
|
nsMenuFrame::Execute(WidgetGUIEvent* aEvent)
|
1999-07-31 05:43:33 +04:00
|
|
|
{
|
2002-11-18 17:01:20 +03:00
|
|
|
// flip "checked" state if we're a checkbox menu, or an un-checked radio menu
|
2011-09-29 10:19:26 +04:00
|
|
|
bool needToFlipChecked = false;
|
2002-11-18 17:01:20 +03:00
|
|
|
if (mType == eMenuType_Checkbox || (mType == eMenuType_Radio && !mChecked)) {
|
2010-04-19 18:12:58 +04:00
|
|
|
needToFlipChecked = !mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::autocheck,
|
|
|
|
nsGkAtoms::_false, eCaseMatters);
|
2001-03-21 11:15:49 +03:00
|
|
|
}
|
|
|
|
|
2008-12-10 20:23:20 +03:00
|
|
|
nsCOMPtr<nsISound> sound(do_CreateInstance("@mozilla.org/sound;1"));
|
|
|
|
if (sound)
|
2009-07-09 05:55:46 +04:00
|
|
|
sound->PlayEventSound(nsISound::EVENT_MENU_EXECUTE);
|
2008-12-10 20:23:20 +03:00
|
|
|
|
2010-04-19 18:12:58 +04:00
|
|
|
StartBlinking(aEvent, needToFlipChecked);
|
|
|
|
}
|
|
|
|
|
2011-09-29 10:19:26 +04:00
|
|
|
bool
|
2010-04-19 18:12:58 +04:00
|
|
|
nsMenuFrame::ShouldBlink()
|
|
|
|
{
|
2012-08-22 19:56:38 +04:00
|
|
|
int32_t shouldBlink =
|
2011-09-09 06:27:13 +04:00
|
|
|
LookAndFeel::GetInt(LookAndFeel::eIntID_ChosenMenuItemsShouldBlink, 0);
|
2010-04-19 18:12:58 +04:00
|
|
|
if (!shouldBlink)
|
2011-10-17 18:59:28 +04:00
|
|
|
return false;
|
2010-04-19 18:12:58 +04:00
|
|
|
|
|
|
|
// Don't blink in editable menulists.
|
2011-06-25 01:00:35 +04:00
|
|
|
if (GetParentMenuListType() == eEditableMenuList)
|
2011-10-17 18:59:28 +04:00
|
|
|
return false;
|
2011-06-25 01:00:35 +04:00
|
|
|
|
2011-10-17 18:59:28 +04:00
|
|
|
return true;
|
2010-04-19 18:12:58 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2013-10-02 07:46:03 +04:00
|
|
|
nsMenuFrame::StartBlinking(WidgetGUIEvent* aEvent, bool aFlipChecked)
|
2010-04-19 18:12:58 +04:00
|
|
|
{
|
|
|
|
StopBlinking();
|
|
|
|
CreateMenuCommandEvent(aEvent, aFlipChecked);
|
|
|
|
|
|
|
|
if (!ShouldBlink()) {
|
|
|
|
PassMenuCommandEventToPopupManager();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Blink off.
|
|
|
|
nsWeakFrame weakFrame(this);
|
2011-10-17 18:59:28 +04:00
|
|
|
mContent->UnsetAttr(kNameSpaceID_None, nsGkAtoms::menuactive, true);
|
2010-04-19 18:12:58 +04:00
|
|
|
if (!weakFrame.IsAlive())
|
|
|
|
return;
|
|
|
|
|
2014-05-25 02:20:41 +04:00
|
|
|
nsMenuParent* menuParent = GetMenuParent();
|
|
|
|
if (menuParent) {
|
2010-04-19 18:12:58 +04:00
|
|
|
// Make this menu ignore events from now on.
|
2014-05-25 02:20:41 +04:00
|
|
|
menuParent->LockMenuUntilClosed(true);
|
2010-04-19 18:12:58 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
// Set up a timer to blink back on.
|
|
|
|
mBlinkTimer = do_CreateInstance("@mozilla.org/timer;1");
|
|
|
|
mBlinkTimer->InitWithCallback(mTimerMediator, kBlinkDelay, nsITimer::TYPE_ONE_SHOT);
|
|
|
|
mBlinkState = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsMenuFrame::StopBlinking()
|
|
|
|
{
|
|
|
|
mBlinkState = 0;
|
|
|
|
if (mBlinkTimer) {
|
|
|
|
mBlinkTimer->Cancel();
|
2012-07-30 18:20:58 +04:00
|
|
|
mBlinkTimer = nullptr;
|
2010-04-19 18:12:58 +04:00
|
|
|
}
|
2012-07-30 18:20:58 +04:00
|
|
|
mDelayedMenuCommandEvent = nullptr;
|
2010-04-19 18:12:58 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2013-10-02 07:46:03 +04:00
|
|
|
nsMenuFrame::CreateMenuCommandEvent(WidgetGUIEvent* aEvent, bool aFlipChecked)
|
2010-04-19 18:12:58 +04:00
|
|
|
{
|
|
|
|
// Create a trusted event if the triggering event was trusted, or if
|
|
|
|
// we're called from chrome code (since at least one of our caller
|
|
|
|
// passes in a null event).
|
2012-12-16 05:26:03 +04:00
|
|
|
bool isTrusted = aEvent ? aEvent->mFlags.mIsTrusted :
|
2010-04-19 18:12:58 +04:00
|
|
|
nsContentUtils::IsCallerChrome();
|
|
|
|
|
2011-09-29 10:19:26 +04:00
|
|
|
bool shift = false, control = false, alt = false, meta = false;
|
2013-10-18 10:10:26 +04:00
|
|
|
WidgetInputEvent* inputEvent = aEvent ? aEvent->AsInputEvent() : nullptr;
|
|
|
|
if (inputEvent) {
|
|
|
|
shift = inputEvent->IsShift();
|
|
|
|
control = inputEvent->IsControl();
|
|
|
|
alt = inputEvent->IsAlt();
|
|
|
|
meta = inputEvent->IsMeta();
|
2010-04-19 18:12:58 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
// Because the command event is firing asynchronously, a flag is needed to
|
|
|
|
// indicate whether user input is being handled. This ensures that a popup
|
|
|
|
// window won't get blocked.
|
2014-04-01 08:09:23 +04:00
|
|
|
bool userinput = EventStateManager::IsHandlingUserInput();
|
2010-04-19 18:12:58 +04:00
|
|
|
|
|
|
|
mDelayedMenuCommandEvent =
|
|
|
|
new nsXULMenuCommandEvent(mContent, isTrusted, shift, control, alt, meta,
|
|
|
|
userinput, aFlipChecked);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsMenuFrame::PassMenuCommandEventToPopupManager()
|
|
|
|
{
|
2007-07-04 19:49:38 +04:00
|
|
|
nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
|
2014-05-25 02:20:41 +04:00
|
|
|
nsMenuParent* menuParent = GetMenuParent();
|
|
|
|
if (pm && menuParent && mDelayedMenuCommandEvent) {
|
2010-04-19 18:12:58 +04:00
|
|
|
pm->ExecuteMenu(mContent, mDelayedMenuCommandEvent);
|
|
|
|
}
|
2012-07-30 18:20:58 +04:00
|
|
|
mDelayedMenuCommandEvent = nullptr;
|
1999-07-31 15:29:03 +04:00
|
|
|
}
|
|
|
|
|
2014-05-28 23:36:58 +04:00
|
|
|
void
|
2011-08-25 00:54:30 +04:00
|
|
|
nsMenuFrame::RemoveFrame(ChildListID aListID,
|
2005-02-07 04:58:25 +03:00
|
|
|
nsIFrame* aOldFrame)
|
1999-07-31 15:29:03 +04:00
|
|
|
{
|
2012-03-08 05:57:37 +04:00
|
|
|
nsFrameList* popupList = GetPopupList();
|
2013-02-28 03:05:45 +04:00
|
|
|
if (popupList && popupList->FirstChild() == aOldFrame) {
|
|
|
|
popupList->RemoveFirstChild();
|
|
|
|
aOldFrame->Destroy();
|
2012-03-08 05:57:37 +04:00
|
|
|
DestroyPopupList();
|
2007-03-31 01:11:41 +04:00
|
|
|
PresContext()->PresShell()->
|
2007-05-06 23:16:51 +04:00
|
|
|
FrameNeedsReflow(this, nsIPresShell::eTreeChange,
|
|
|
|
NS_FRAME_HAS_DIRTY_CHILDREN);
|
2014-05-28 23:36:58 +04:00
|
|
|
return;
|
1999-07-31 15:29:03 +04:00
|
|
|
}
|
2014-05-28 23:36:58 +04:00
|
|
|
nsBoxFrame::RemoveFrame(aListID, aOldFrame);
|
1999-07-31 15:29:03 +04:00
|
|
|
}
|
|
|
|
|
2014-05-28 23:36:58 +04:00
|
|
|
void
|
2011-08-25 00:54:30 +04:00
|
|
|
nsMenuFrame::InsertFrames(ChildListID aListID,
|
2005-02-07 04:58:25 +03:00
|
|
|
nsIFrame* aPrevFrame,
|
2009-07-30 21:23:32 +04:00
|
|
|
nsFrameList& aFrameList)
|
1999-07-31 15:29:03 +04:00
|
|
|
{
|
2012-03-08 05:57:37 +04:00
|
|
|
if (!HasPopup() && (aListID == kPrincipalList || aListID == kPopupList)) {
|
2009-07-30 21:23:32 +04:00
|
|
|
SetPopupFrame(aFrameList);
|
2012-03-08 05:57:37 +04:00
|
|
|
if (HasPopup()) {
|
2004-06-19 13:07:47 +04:00
|
|
|
#ifdef DEBUG_LAYOUT
|
2007-11-17 18:47:38 +03:00
|
|
|
nsBoxLayoutState state(PresContext());
|
|
|
|
SetDebug(state, aFrameList, mState & NS_STATE_CURRENTLY_IN_DEBUG);
|
2004-06-19 13:07:47 +04:00
|
|
|
#endif
|
2007-11-17 18:47:38 +03:00
|
|
|
|
|
|
|
PresContext()->PresShell()->
|
|
|
|
FrameNeedsReflow(this, nsIPresShell::eTreeChange,
|
|
|
|
NS_FRAME_HAS_DIRTY_CHILDREN);
|
2007-10-20 09:43:38 +04:00
|
|
|
}
|
1999-07-31 15:29:03 +04:00
|
|
|
}
|
1999-08-19 07:51:25 +04:00
|
|
|
|
2009-07-30 21:23:32 +04:00
|
|
|
if (aFrameList.IsEmpty())
|
2014-05-28 23:36:58 +04:00
|
|
|
return;
|
2007-11-17 18:47:38 +03:00
|
|
|
|
2012-10-26 17:32:10 +04:00
|
|
|
if (MOZ_UNLIKELY(aPrevFrame && aPrevFrame == GetPopup())) {
|
2012-07-30 18:20:58 +04:00
|
|
|
aPrevFrame = nullptr;
|
2007-11-17 18:47:38 +03:00
|
|
|
}
|
|
|
|
|
2014-05-28 23:36:58 +04:00
|
|
|
nsBoxFrame::InsertFrames(aListID, aPrevFrame, aFrameList);
|
1999-07-31 15:29:03 +04:00
|
|
|
}
|
|
|
|
|
2014-05-28 23:36:58 +04:00
|
|
|
void
|
2011-08-25 00:54:30 +04:00
|
|
|
nsMenuFrame::AppendFrames(ChildListID aListID,
|
2009-07-30 21:23:32 +04:00
|
|
|
nsFrameList& aFrameList)
|
1999-07-31 15:29:03 +04:00
|
|
|
{
|
2012-03-08 05:57:37 +04:00
|
|
|
if (!HasPopup() && (aListID == kPrincipalList || aListID == kPopupList)) {
|
2009-07-30 21:23:32 +04:00
|
|
|
SetPopupFrame(aFrameList);
|
2012-03-08 05:57:37 +04:00
|
|
|
if (HasPopup()) {
|
2000-05-15 08:12:31 +04:00
|
|
|
|
2004-06-19 13:07:47 +04:00
|
|
|
#ifdef DEBUG_LAYOUT
|
2007-11-17 18:47:38 +03:00
|
|
|
nsBoxLayoutState state(PresContext());
|
|
|
|
SetDebug(state, aFrameList, mState & NS_STATE_CURRENTLY_IN_DEBUG);
|
2004-06-19 13:07:47 +04:00
|
|
|
#endif
|
2007-11-17 18:47:38 +03:00
|
|
|
PresContext()->PresShell()->
|
|
|
|
FrameNeedsReflow(this, nsIPresShell::eTreeChange,
|
|
|
|
NS_FRAME_HAS_DIRTY_CHILDREN);
|
|
|
|
}
|
1999-07-31 15:29:03 +04:00
|
|
|
}
|
1999-08-19 07:51:25 +04:00
|
|
|
|
2009-07-30 21:23:32 +04:00
|
|
|
if (aFrameList.IsEmpty())
|
2014-05-28 23:36:58 +04:00
|
|
|
return;
|
2007-11-17 18:47:38 +03:00
|
|
|
|
2014-05-28 23:36:58 +04:00
|
|
|
nsBoxFrame::AppendFrames(aListID, aFrameList);
|
1999-07-31 22:39:47 +04:00
|
|
|
}
|
1999-09-21 05:03:00 +04:00
|
|
|
|
2011-09-29 10:19:26 +04:00
|
|
|
bool
|
2005-06-25 13:35:05 +04:00
|
|
|
nsMenuFrame::SizeToPopup(nsBoxLayoutState& aState, nsSize& aSize)
|
2000-03-31 11:02:06 +04:00
|
|
|
{
|
2011-06-16 01:03:49 +04:00
|
|
|
if (!IsCollapsed()) {
|
2011-09-29 10:19:26 +04:00
|
|
|
bool widthSet, heightSet;
|
2005-06-25 13:35:05 +04:00
|
|
|
nsSize tmpSize(-1, 0);
|
2012-08-06 07:00:57 +04:00
|
|
|
nsIFrame::AddCSSPrefSize(this, tmpSize, widthSet, heightSet);
|
2015-12-07 21:17:47 +03:00
|
|
|
if (!widthSet && GetFlex() == 0) {
|
2012-03-08 05:57:37 +04:00
|
|
|
nsMenuPopupFrame* popupFrame = GetPopup();
|
|
|
|
if (!popupFrame)
|
2011-10-17 18:59:28 +04:00
|
|
|
return false;
|
2012-03-08 05:57:37 +04:00
|
|
|
tmpSize = popupFrame->GetPrefSize(aState);
|
2011-06-30 01:39:21 +04:00
|
|
|
|
|
|
|
// Produce a size such that:
|
|
|
|
// (1) the menu and its popup can be the same width
|
|
|
|
// (2) there's enough room in the menu for the content and its
|
|
|
|
// border-padding
|
|
|
|
// (3) there's enough room in the popup for the content and its
|
|
|
|
// scrollbar
|
|
|
|
nsMargin borderPadding;
|
|
|
|
GetBorderAndPadding(borderPadding);
|
2010-09-15 19:25:08 +04:00
|
|
|
|
|
|
|
// if there is a scroll frame, add the desired width of the scrollbar as well
|
2012-03-08 05:57:37 +04:00
|
|
|
nsIScrollableFrame* scrollFrame = do_QueryFrame(popupFrame->GetFirstPrincipalChild());
|
2011-06-30 01:39:21 +04:00
|
|
|
nscoord scrollbarWidth = 0;
|
2010-09-15 19:25:08 +04:00
|
|
|
if (scrollFrame) {
|
2011-06-30 01:39:21 +04:00
|
|
|
scrollbarWidth =
|
|
|
|
scrollFrame->GetDesiredScrollbarSizes(&aState).LeftRight();
|
2010-09-15 19:25:08 +04:00
|
|
|
}
|
|
|
|
|
2011-06-30 01:39:21 +04:00
|
|
|
aSize.width =
|
2013-01-15 16:22:03 +04:00
|
|
|
tmpSize.width + std::max(borderPadding.LeftRight(), scrollbarWidth);
|
2011-06-30 01:39:21 +04:00
|
|
|
|
2011-10-17 18:59:28 +04:00
|
|
|
return true;
|
2005-06-25 13:35:05 +04:00
|
|
|
}
|
|
|
|
}
|
2002-04-17 03:51:07 +04:00
|
|
|
|
2011-10-17 18:59:28 +04:00
|
|
|
return false;
|
2005-06-25 13:35:05 +04:00
|
|
|
}
|
2002-04-17 03:51:07 +04:00
|
|
|
|
2007-01-08 05:57:59 +03:00
|
|
|
nsSize
|
|
|
|
nsMenuFrame::GetPrefSize(nsBoxLayoutState& aState)
|
2005-06-25 13:35:05 +04:00
|
|
|
{
|
2007-01-08 05:57:59 +03:00
|
|
|
nsSize size = nsBoxFrame::GetPrefSize(aState);
|
|
|
|
DISPLAY_PREF_SIZE(this, size);
|
2002-04-17 03:51:07 +04:00
|
|
|
|
2005-06-25 13:35:05 +04:00
|
|
|
// If we are using sizetopopup="always" then
|
|
|
|
// nsBoxFrame will already have enforced the minimum size
|
2011-10-17 18:59:28 +04:00
|
|
|
if (!IsSizedToPopup(mContent, true) &&
|
|
|
|
IsSizedToPopup(mContent, false) &&
|
2007-01-08 05:57:59 +03: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 08:49:44 +03:00
|
|
|
size = BoundsCheck(minSize, size, maxSize);
|
2000-03-31 11:02:06 +04:00
|
|
|
}
|
|
|
|
|
2007-01-08 05:57:59 +03:00
|
|
|
return size;
|
2000-03-31 11:02:06 +04:00
|
|
|
}
|
|
|
|
|
2000-08-17 13:15:51 +04:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsMenuFrame::GetActiveChild(nsIDOMElement** aResult)
|
|
|
|
{
|
2012-03-08 05:57:37 +04:00
|
|
|
nsMenuPopupFrame* popupFrame = GetPopup();
|
|
|
|
if (!popupFrame)
|
2000-08-17 13:15:51 +04:00
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
|
2012-03-08 05:57:37 +04:00
|
|
|
nsMenuFrame* menuFrame = popupFrame->GetCurrentMenuItem();
|
2000-08-17 13:15:51 +04:00
|
|
|
if (!menuFrame) {
|
2012-07-30 18:20:58 +04:00
|
|
|
*aResult = nullptr;
|
2000-08-17 13:15:51 +04:00
|
|
|
}
|
|
|
|
else {
|
2007-07-04 19:49:38 +04:00
|
|
|
nsCOMPtr<nsIDOMElement> elt(do_QueryInterface(menuFrame->GetContent()));
|
2000-08-17 13:15:51 +04:00
|
|
|
*aResult = elt;
|
|
|
|
NS_IF_ADDREF(*aResult);
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsMenuFrame::SetActiveChild(nsIDOMElement* aChild)
|
|
|
|
{
|
2012-03-08 05:57:37 +04:00
|
|
|
nsMenuPopupFrame* popupFrame = GetPopup();
|
|
|
|
if (!popupFrame)
|
2000-08-17 13:15:51 +04:00
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
|
2000-08-24 07:58:42 +04:00
|
|
|
if (!aChild) {
|
|
|
|
// Remove the current selection
|
2015-06-26 19:32:25 +03:00
|
|
|
popupFrame->ChangeMenuItem(nullptr, false, false);
|
2000-08-24 07:58:42 +04:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2000-08-17 13:15:51 +04:00
|
|
|
nsCOMPtr<nsIContent> child(do_QueryInterface(aChild));
|
2007-07-04 19:49:38 +04:00
|
|
|
|
2012-07-31 04:43:28 +04:00
|
|
|
nsMenuFrame* menu = do_QueryFrame(child->GetPrimaryFrame());
|
|
|
|
if (menu)
|
2015-06-26 19:32:25 +03:00
|
|
|
popupFrame->ChangeMenuItem(menu, false, false);
|
2000-08-17 13:15:51 +04:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2009-09-01 15:22:31 +04:00
|
|
|
nsIScrollableFrame* nsMenuFrame::GetScrollTargetFrame()
|
|
|
|
{
|
2012-03-08 05:57:37 +04:00
|
|
|
nsMenuPopupFrame* popupFrame = GetPopup();
|
|
|
|
if (!popupFrame)
|
2012-07-30 18:20:58 +04:00
|
|
|
return nullptr;
|
2012-03-08 05:57:37 +04:00
|
|
|
nsIFrame* childFrame = popupFrame->GetFirstPrincipalChild();
|
2009-09-01 15:22:31 +04:00
|
|
|
if (childFrame)
|
2012-03-08 05:57:37 +04:00
|
|
|
return popupFrame->GetScrollFrame(childFrame);
|
2012-07-30 18:20:58 +04:00
|
|
|
return nullptr;
|
2009-09-01 15:22:31 +04:00
|
|
|
}
|
|
|
|
|
2006-01-12 19:40:47 +03:00
|
|
|
// nsMenuTimerMediator implementation.
|
2014-04-27 11:06:00 +04:00
|
|
|
NS_IMPL_ISUPPORTS(nsMenuTimerMediator, nsITimerCallback)
|
2006-01-12 19:40:47 +03:00
|
|
|
|
|
|
|
/**
|
|
|
|
* 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()
|
|
|
|
{
|
2012-07-30 18:20:58 +04:00
|
|
|
mFrame = nullptr;
|
2006-01-12 19:40:47 +03:00
|
|
|
}
|