Bug 1284825 part.3 nsMenuBarListener should clear its accesskey state when its top level window is deactivated rather than it receives a blur event r?enndeakin
This patch makes nsMenuBarListener clear its accesskey state when it receives a "deactivate" event of its top level window and reverts the change of nsMenuBarListener::Blur() by
bug 625151.
"blur" event may be caused by focus move in the contents after "mosuedown" event. Therefore, mAccessKeyDownCanceled may be cleared unexpectedly. Listening to "deactive" event keeps
bug 625151's fix because it's a bug after deactivating the window with Alt+Tab.
MozReview-Commit-ID: 4mAmXpxmDdv
--- a/layout/xul/nsMenuBarListener.cpp
+++ b/layout/xul/nsMenuBarListener.cpp
@@ -35,16 +35,17 @@ NS_IMPL_ISUPPORTS(nsMenuBarListener, nsI
int32_t nsMenuBarListener::mAccessKey = -1;
Modifiers nsMenuBarListener::mAccessKeyMask = 0;
bool nsMenuBarListener::mAccessKeyFocuses = false;
nsMenuBarListener::nsMenuBarListener(nsMenuBarFrame* aMenuBarFrame,
nsIContent* aMenuBarContent)
: mMenuBarFrame(aMenuBarFrame)
, mEventTarget(aMenuBarContent ? aMenuBarContent->GetComposedDoc() : nullptr)
+ , mTopWindowEventTarget(nullptr)
, mAccessKeyDown(false)
, mAccessKeyDownCanceled(false)
{
MOZ_ASSERT(mEventTarget);
// Hook up the menubar as a key listener on the whole document. This will
// see every keypress that occurs, but after everyone else does.
@@ -61,16 +62,24 @@ nsMenuBarListener::nsMenuBarListener(nsM
// mousedown event should be handled in all phase
mEventTarget->AddEventListener(NS_LITERAL_STRING("mousedown"), this, true);
mEventTarget->AddEventListener(NS_LITERAL_STRING("mousedown"), this, false);
mEventTarget->AddEventListener(NS_LITERAL_STRING("blur"), this, true);
mEventTarget->AddEventListener(
NS_LITERAL_STRING("MozDOMFullscreen:Entered"), this, false);
+
+ // Needs to listen to the deactivate event of the window.
+ RefPtr<EventTarget> topWindowEventTarget =
+ nsContentUtils::GetWindowRoot(aMenuBarContent->GetComposedDoc());
+ mTopWindowEventTarget = topWindowEventTarget.get();
+
+ mTopWindowEventTarget->AddSystemEventListener(NS_LITERAL_STRING("deactivate"),
+ this, true);
}
////////////////////////////////////////////////////////////////////////
nsMenuBarListener::~nsMenuBarListener()
{
MOZ_ASSERT(!mEventTarget,
"OnDestroyMenuBarFrame() should've alreay been called");
}
@@ -90,18 +99,22 @@ nsMenuBarListener::OnDestroyMenuBarFrame
mEventTarget->RemoveEventListener(NS_LITERAL_STRING("mousedown"), this, true);
mEventTarget->RemoveEventListener(NS_LITERAL_STRING("mousedown"),
this, false);
mEventTarget->RemoveEventListener(NS_LITERAL_STRING("blur"), this, true);
mEventTarget->RemoveEventListener(
NS_LITERAL_STRING("MozDOMFullscreen:Entered"), this, false);
+ mTopWindowEventTarget->RemoveSystemEventListener(
+ NS_LITERAL_STRING("deactivate"), this, true);
+
mMenuBarFrame = nullptr;
mEventTarget = nullptr;
+ mTopWindowEventTarget = nullptr;
}
void
nsMenuBarListener::InitializeStatics()
{
Preferences::AddBoolVarCache(&mAccessKeyFocuses,
"ui.key.menuAccessKeyFocuses");
}
@@ -410,24 +423,34 @@ nsMenuBarListener::KeyDown(nsIDOMEvent*
////////////////////////////////////////////////////////////////////////
nsresult
nsMenuBarListener::Blur(nsIDOMEvent* aEvent)
{
if (!mMenuBarFrame->IsMenuOpen() && mMenuBarFrame->IsActive()) {
ToggleMenuActiveState();
+ mAccessKeyDown = false;
+ mAccessKeyDownCanceled = false;
}
+ return NS_OK; // means I am NOT consuming event
+}
+
+////////////////////////////////////////////////////////////////////////
+
+nsresult
+nsMenuBarListener::OnWindowDeactivated(nsIDOMEvent* aEvent)
+{
// Reset the accesskey state because we cannot receive the keyup event for
// the pressing accesskey.
mAccessKeyDown = false;
mAccessKeyDownCanceled = false;
return NS_OK; // means I am NOT consuming event
}
-
+
////////////////////////////////////////////////////////////////////////
nsresult
nsMenuBarListener::MouseDown(nsIDOMEvent* aMouseEvent)
{
// NOTE: MouseDown method listens all phases
// Even if the mousedown event is canceled, it means the user don't want
// to activate the menu. Therefore, we need to record it at capturing (or
@@ -483,16 +506,19 @@ nsMenuBarListener::HandleEvent(nsIDOMEve
return KeyPress(aEvent);
}
if (eventType.EqualsLiteral("mozaccesskeynotfound")) {
return KeyPress(aEvent);
}
if (eventType.EqualsLiteral("blur")) {
return Blur(aEvent);
}
+ if (eventType.EqualsLiteral("deactivate")) {
+ return OnWindowDeactivated(aEvent);
+ }
if (eventType.EqualsLiteral("mousedown")) {
return MouseDown(aEvent);
}
if (eventType.EqualsLiteral("MozDOMFullscreen:Entered")) {
return Fullscreen(aEvent);
}
NS_ABORT();
--- a/layout/xul/nsMenuBarListener.h
+++ b/layout/xul/nsMenuBarListener.h
@@ -60,16 +60,17 @@ public:
protected:
virtual ~nsMenuBarListener();
nsresult KeyUp(nsIDOMEvent* aMouseEvent);
nsresult KeyDown(nsIDOMEvent* aMouseEvent);
nsresult KeyPress(nsIDOMEvent* aMouseEvent);
nsresult Blur(nsIDOMEvent* aEvent);
+ nsresult OnWindowDeactivated(nsIDOMEvent* aEvent);
nsresult MouseDown(nsIDOMEvent* aMouseEvent);
nsresult Fullscreen(nsIDOMEvent* aEvent);
static void InitAccessKey();
static mozilla::Modifiers GetModifiersForAccessKey(nsIDOMKeyEvent* event);
// This should only be called by the nsMenuBarListener during event dispatch,
@@ -80,16 +81,18 @@ protected:
// The menu bar object.
nsMenuBarFrame* mMenuBarFrame;
// The event target to listen to the events.
// XXX Should this store this as strong reference? However,
// OnDestroyMenuBarFrame() should be called at destroying mMenuBarFrame.
// So, weak reference must be safe.
mozilla::dom::EventTarget* mEventTarget;
+ // The top window as EventTarget.
+ mozilla::dom::EventTarget* mTopWindowEventTarget;
// Whether or not the ALT key is currently down.
bool mAccessKeyDown;
// Whether or not the ALT key down is canceled by other action.
bool mAccessKeyDownCanceled;
// Does the access key by itself focus the menubar?
static bool mAccessKeyFocuses;
// See nsIDOMKeyEvent.h for sample values.
static int32_t mAccessKey;