From 300ed443b97ad3bd4bf4a85092c52b7b7f216b0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20Cobos=20=C3=81lvarez?= Date: Wed, 22 May 2019 17:21:29 +0000 Subject: [PATCH] Bug 416771 - Allow window.focus() to switch tabs. r=NeilDeakin,dao CLOSED TREE Differential Revision: https://phabricator.services.mozilla.com/D31643 --HG-- extra : source : 5acccb49a66840b5c2266edfb7a8953878a2a040 extra : histedit_source : 33a19d54114ef5eda00aefb1c997d6dbcfb40501 --- browser/base/content/tabbrowser.js | 14 ++++++++++++++ dom/base/nsContentUtils.cpp | 26 ++++++++++++++++++++++++++ dom/base/nsContentUtils.h | 6 ++++++ dom/base/nsGlobalWindowOuter.cpp | 19 +++---------------- dom/ipc/BrowserBridgeChild.cpp | 16 ++-------------- dom/ipc/BrowserParent.cpp | 14 ++------------ 6 files changed, 53 insertions(+), 42 deletions(-) diff --git a/browser/base/content/tabbrowser.js b/browser/base/content/tabbrowser.js index 86ded254be08..3e34e958ac6d 100644 --- a/browser/base/content/tabbrowser.js +++ b/browser/base/content/tabbrowser.js @@ -30,6 +30,7 @@ window._gBrowser = { } window.addEventListener("sizemodechange", this); window.addEventListener("occlusionstatechange", this); + window.addEventListener("framefocusrequested", this); this._setupInitialBrowserAndTab(); @@ -4298,6 +4299,18 @@ window._gBrowser = { case "keypress": this._handleKeyPressEventMac(aEvent); break; + case "framefocusrequested": { + let tab = this.getTabForBrowser(aEvent.target); + if (!tab || tab == this.selectedTab) { + // Let the focus manager try to do its thing by not calling + // preventDefault(). It will still raise the window if appropriate. + break; + } + this.selectedTab = tab; + window.focus(); + aEvent.preventDefault(); + break; + } case "sizemodechange": case "occlusionstatechange": if (aEvent.target == window && !this._switcher) { @@ -4508,6 +4521,7 @@ window._gBrowser = { } window.removeEventListener("sizemodechange", this); window.removeEventListener("occlusionstatechange", this); + window.removeEventListener("framefocusrequested", this); if (gMultiProcessBrowser) { let messageManager = window.getGroupMessageManager("browsers"); diff --git a/dom/base/nsContentUtils.cpp b/dom/base/nsContentUtils.cpp index d2da7937729b..fd5456a67ba2 100644 --- a/dom/base/nsContentUtils.cpp +++ b/dom/base/nsContentUtils.cpp @@ -4176,6 +4176,32 @@ nsresult nsContentUtils::DispatchFocusChromeEvent(nsPIDOMWindowOuter* aWindow) { CanBubble::eYes, Cancelable::eYes); } +void nsContentUtils::RequestFrameFocus(Element& aFrameElement, bool aCanRaise) { + RefPtr target = &aFrameElement; + bool defaultAction = true; + if (aCanRaise) { + DispatchEventOnlyToChrome(target->OwnerDoc(), target, + NS_LITERAL_STRING("framefocusrequested"), + CanBubble::eYes, Cancelable::eYes, + &defaultAction); + } + if (!defaultAction) { + return; + } + + nsCOMPtr fm = nsFocusManager::GetFocusManager(); + if (!fm) { + return; + } + + uint32_t flags = nsIFocusManager::FLAG_NOSCROLL; + if (aCanRaise) { + flags |= nsIFocusManager::FLAG_RAISE; + } + + fm->SetFocus(target, flags); +} + nsresult nsContentUtils::DispatchEventOnlyToChrome( Document* aDoc, nsISupports* aTarget, const nsAString& aEventName, CanBubble aCanBubble, Cancelable aCancelable, bool* aDefaultAction) { diff --git a/dom/base/nsContentUtils.h b/dom/base/nsContentUtils.h index 38f577db1e1d..7490f4292fe2 100644 --- a/dom/base/nsContentUtils.h +++ b/dom/base/nsContentUtils.h @@ -1520,6 +1520,12 @@ class nsContentUtils { */ static nsresult DispatchFocusChromeEvent(nsPIDOMWindowOuter* aWindow); + /** + * Helper to dispatch a "framefocusrequested" event to chrome, which will only + * bring the window to the foreground and switch tabs if aCanRaise is true. + */ + static void RequestFrameFocus(Element& aFrameElement, bool aCanRaise); + /** * This method creates and dispatches a trusted event. * If aTarget is not a chrome object, the nearest chrome object in the diff --git a/dom/base/nsGlobalWindowOuter.cpp b/dom/base/nsGlobalWindowOuter.cpp index 9bcf6b6970db..c972f202fe66 100644 --- a/dom/base/nsGlobalWindowOuter.cpp +++ b/dom/base/nsGlobalWindowOuter.cpp @@ -4866,14 +4866,7 @@ void nsGlobalWindowOuter::FocusOuter() { } nsCOMPtr baseWin = do_QueryInterface(mDocShell); - - bool isVisible = false; - if (baseWin) { - baseWin->GetVisibility(&isVisible); - } - - if (!isVisible) { - // A hidden tab is being focused, ignore this call. + if (!baseWin) { return; } @@ -4932,14 +4925,8 @@ void nsGlobalWindowOuter::FocusOuter() { return; } - RefPtr frame = parentdoc->FindContentForSubDocument(mDoc); - if (frame) { - uint32_t flags = nsIFocusManager::FLAG_NOSCROLL; - if (canFocus) flags |= nsIFocusManager::FLAG_RAISE; - DebugOnly rv = fm->SetFocus(frame, flags); - MOZ_ASSERT(NS_SUCCEEDED(rv), - "SetFocus only fails if the first argument is null, " - "but we pass an element"); + if (Element* frame = parentdoc->FindContentForSubDocument(mDoc)) { + nsContentUtils::RequestFrameFocus(*frame, canFocus); } return; } diff --git a/dom/ipc/BrowserBridgeChild.cpp b/dom/ipc/BrowserBridgeChild.cpp index 89b8eb779cfc..f615608f686f 100644 --- a/dom/ipc/BrowserBridgeChild.cpp +++ b/dom/ipc/BrowserBridgeChild.cpp @@ -159,22 +159,11 @@ IPCResult BrowserBridgeChild::RecvSetLayersId( mozilla::ipc::IPCResult BrowserBridgeChild::RecvRequestFocus( const bool& aCanRaise) { // Adapted from BrowserParent - nsCOMPtr fm = nsFocusManager::GetFocusManager(); - if (!fm) { - return IPC_OK(); - } - RefPtr owner = mFrameLoader->GetOwnerContent(); if (!owner) { return IPC_OK(); } - - uint32_t flags = nsIFocusManager::FLAG_NOSCROLL; - if (aCanRaise) { - flags |= nsIFocusManager::FLAG_RAISE; - } - - fm->SetFocus(owner, flags); + nsContentUtils::RequestFrameFocus(*owner, aCanRaise); return IPC_OK(); } @@ -187,8 +176,7 @@ mozilla::ipc::IPCResult BrowserBridgeChild::RecvMoveFocus( } RefPtr owner = mFrameLoader->GetOwnerContent(); - - if (!owner || !owner->OwnerDoc()) { + if (!owner) { return IPC_OK(); } diff --git a/dom/ipc/BrowserParent.cpp b/dom/ipc/BrowserParent.cpp index de561baacc0d..5a28e7e7d359 100644 --- a/dom/ipc/BrowserParent.cpp +++ b/dom/ipc/BrowserParent.cpp @@ -2121,26 +2121,16 @@ mozilla::ipc::IPCResult BrowserParent::RecvOnWindowedPluginKeyEvent( mozilla::ipc::IPCResult BrowserParent::RecvRequestFocus(const bool& aCanRaise) { LOGBROWSERFOCUS(("RecvRequestFocus %p, aCanRaise: %d", this, aCanRaise)); - BrowserBridgeParent* bridgeParent = GetBrowserBridgeParent(); - if (bridgeParent) { + if (BrowserBridgeParent* bridgeParent = GetBrowserBridgeParent()) { mozilla::Unused << bridgeParent->SendRequestFocus(aCanRaise); return IPC_OK(); } - nsCOMPtr fm = nsFocusManager::GetFocusManager(); - if (!fm) { - return IPC_OK(); - } - if (!mFrameElement) { return IPC_OK(); } - uint32_t flags = nsIFocusManager::FLAG_NOSCROLL; - if (aCanRaise) flags |= nsIFocusManager::FLAG_RAISE; - - RefPtr element = mFrameElement; - fm->SetFocus(element, flags); + nsContentUtils::RequestFrameFocus(*mFrameElement, aCanRaise); return IPC_OK(); }