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 draft
authorMasayuki Nakano <masayuki@d-toybox.com>
Mon, 26 Dec 2016 16:22:13 +0900
changeset 453914 cae745ba586ba8b2748c7adcf9824e6e16822066
parent 453913 0f3d5a3daa88c9dfba82abbbdd5a718bfc05dafa
child 540552 306076528de222597cb900e587f5667195ed03d5
push id39762
push usermasayuki@d-toybox.com
push dateMon, 26 Dec 2016 10:38:02 +0000
reviewersenndeakin
bugs1284825, 625151
milestone53.0a1
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
layout/xul/nsMenuBarListener.cpp
layout/xul/nsMenuBarListener.h
--- 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;