Created
September 26, 2018 20:12
-
-
Save daleharvey/0e37d38b0d6fa05f148746ff4d6344fb to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
From fb33d1c9334762cbedbfc40c343ee006ef8c7726 Mon Sep 17 00:00:00 2001 | |
From: Dale Harvey <dale@arandomurl.com> | |
Date: Wed, 26 Sep 2018 21:09:00 +0100 | |
Subject: [PATCH] Bug 1363169 - Add support for native windows share | |
--- | |
browser/base/content/browser-pageActions.js | 14 ++- | |
browser/base/content/test/urlbar/browser.ini | 4 + | |
.../browser_page_action_menu_share_win.html | 2 + | |
.../browser_page_action_menu_share_win.js | 45 +++++++ | |
browser/modules/PageActions.jsm | 15 +++ | |
browser/themes/windows/browser.css | 4 + | |
browser/themes/windows/jar.mn | 1 + | |
browser/themes/windows/share.svg | 7 ++ | |
widget/nsIWindowsUIUtils.idl | 6 +- | |
widget/windows/WindowsUIUtils.cpp | 110 ++++++++++++++++++ | |
10 files changed, 203 insertions(+), 5 deletions(-) | |
create mode 100644 browser/base/content/test/urlbar/browser_page_action_menu_share_win.html | |
create mode 100644 browser/base/content/test/urlbar/browser_page_action_menu_share_win.js | |
create mode 100644 browser/themes/windows/share.svg | |
diff --git a/browser/base/content/browser-pageActions.js b/browser/base/content/browser-pageActions.js | |
index 9510d58d344e..91295e0a16c1 100644 | |
--- a/browser/base/content/browser-pageActions.js | |
+++ b/browser/base/content/browser-pageActions.js | |
@@ -1197,6 +1197,12 @@ BrowserPageActions.addSearchEngine = { | |
// share URL | |
BrowserPageActions.shareURL = { | |
+ onCommand(event, buttonNode) { | |
+ let browser = gBrowser.selectedBrowser; | |
+ let currentURI = gURLBar.makeURIReadable(browser.currentURI).displaySpec; | |
+ this._windowsUIUtils.shareUrl(currentURI, browser.contentTitle); | |
+ }, | |
+ | |
onShowingInPanel(buttonNode) { | |
this._cached = false; | |
}, | |
@@ -1258,7 +1264,7 @@ BrowserPageActions.shareURL = { | |
}; | |
// Attach sharingService here so tests can override the implementation | |
-XPCOMUtils.defineLazyServiceGetter(BrowserPageActions.shareURL, | |
- "_sharingService", | |
- "@mozilla.org/widget/macsharingservice;1", | |
- "nsIMacSharingService"); | |
+XPCOMUtils.defineLazyServiceGetters(BrowserPageActions.shareURL, { | |
+ _sharingService: ["@mozilla.org/widget/macsharingservice;1", "nsIMacSharingService"], | |
+ _windowsUIUtils: ["@mozilla.org/windows-ui-utils;1", "nsIWindowsUIUtils"], | |
+}); | |
diff --git a/browser/base/content/test/urlbar/browser.ini b/browser/base/content/test/urlbar/browser.ini | |
index 71bbb56162e7..cd8a8249bf9b 100644 | |
--- a/browser/base/content/test/urlbar/browser.ini | |
+++ b/browser/base/content/test/urlbar/browser.ini | |
@@ -57,6 +57,10 @@ support-files = | |
subsuite = clipboard | |
[browser_page_action_menu_share_mac.js] | |
skip-if = os != "mac" # Mac only feature | |
+[browser_page_action_menu_share_win.js] | |
+support-files = | |
+ browser_page_action_menu_share_win.html | |
+skip-if = os != "win" # Windows only feature | |
[browser_pasteAndGo.js] | |
subsuite = clipboard | |
[browser_populateAfterPushState.js] | |
diff --git a/browser/base/content/test/urlbar/browser_page_action_menu_share_win.html b/browser/base/content/test/urlbar/browser_page_action_menu_share_win.html | |
new file mode 100644 | |
index 000000000000..6c47f98c7e24 | |
--- /dev/null | |
+++ b/browser/base/content/test/urlbar/browser_page_action_menu_share_win.html | |
@@ -0,0 +1,2 @@ | |
+<!doctype html> | |
+<title>Windows Sharing</title> | |
diff --git a/browser/base/content/test/urlbar/browser_page_action_menu_share_win.js b/browser/base/content/test/urlbar/browser_page_action_menu_share_win.js | |
new file mode 100644 | |
index 000000000000..f98602571578 | |
--- /dev/null | |
+++ b/browser/base/content/test/urlbar/browser_page_action_menu_share_win.js | |
@@ -0,0 +1,45 @@ | |
+/* Any copyright is dedicated to the Public Domain. | |
+ * http://creativecommons.org/publicdomain/zero/1.0/ */ | |
+ | |
+"use strict"; | |
+ | |
+/* global sinon */ | |
+Services.scriptloader.loadSubScript("resource://testing-common/sinon-2.3.2.js"); | |
+ | |
+const TEST_URL = getRootDirectory(gTestPath) + "browser_page_action_menu_share_win.html"; | |
+ | |
+// Keep track of site details we are sharing | |
+let sharedUrl, sharedTitle; | |
+ | |
+let stub = sinon.stub(BrowserPageActions.shareURL, "_windowsUIUtils").get(() => { | |
+ return { | |
+ shareUrl(url, title) { | |
+ sharedUrl = url; | |
+ sharedTitle = title; | |
+ }, | |
+ }; | |
+}); | |
+ | |
+registerCleanupFunction(async function() { | |
+ stub.restore(); | |
+ delete window.sinon; | |
+}); | |
+ | |
+add_task(async function shareURL() { | |
+ await BrowserTestUtils.withNewTab(TEST_URL, async () => { | |
+ // Open the panel. | |
+ await promisePageActionPanelOpen(); | |
+ | |
+ // Click Share URL. | |
+ let shareURLButton = document.getElementById("pageAction-panel-shareURL"); | |
+ let hiddenPromise = promisePageActionPanelHidden(); | |
+ EventUtils.synthesizeMouseAtCenter(shareURLButton, {}); | |
+ | |
+ await hiddenPromise; | |
+ | |
+ Assert.equal(sharedUrl, TEST_URL, | |
+ "Shared correct URL"); | |
+ Assert.equal(sharedTitle, "Windows Sharing", | |
+ "Shared with the correct title"); | |
+ }); | |
+}); | |
diff --git a/browser/modules/PageActions.jsm b/browser/modules/PageActions.jsm | |
index 40c4b307fd0b..6a1dc698c27f 100644 | |
--- a/browser/modules/PageActions.jsm | |
+++ b/browser/modules/PageActions.jsm | |
@@ -1179,6 +1179,21 @@ if (AppConstants.platform == "macosx") { | |
}); | |
} | |
+if (AppConstants.isPlatformAndVersionAtLeast("win", "6.4")) { | |
+ gBuiltInActions.push( | |
+ // Share URL | |
+ { | |
+ id: "shareURL", | |
+ title: "shareURL-title", | |
+ onBeforePlacedInWindow(buttonNode) { | |
+ browserPageActions(buttonNode).shareURL.onBeforePlacedInWindow(buttonNode); | |
+ }, | |
+ onCommand(event, buttonNode) { | |
+ browserPageActions(buttonNode).shareURL.onCommand(event, buttonNode); | |
+ }, | |
+ }); | |
+} | |
+ | |
/** | |
* Gets a BrowserPageActions object in a browser window. | |
* | |
diff --git a/browser/themes/windows/browser.css b/browser/themes/windows/browser.css | |
index e79e700a0f3a..4206918a82ce 100644 | |
--- a/browser/themes/windows/browser.css | |
+++ b/browser/themes/windows/browser.css | |
@@ -597,6 +597,10 @@ html|*.urlbar-input:-moz-lwtheme::placeholder, | |
color: GrayText; | |
} | |
+#pageAction-panel-shareURL { | |
+ list-style-image: url("chrome://browser/skin/share.svg"); | |
+} | |
+ | |
%include ../shared/urlbarSearchSuggestionsNotification.inc.css | |
#search-container { | |
diff --git a/browser/themes/windows/jar.mn b/browser/themes/windows/jar.mn | |
index e6ce8e18a498..57e60ea7cbaa 100644 | |
--- a/browser/themes/windows/jar.mn | |
+++ b/browser/themes/windows/jar.mn | |
@@ -41,6 +41,7 @@ browser.jar: | |
* skin/classic/browser/preferences/in-content/preferences.css (preferences/in-content/preferences.css) | |
* skin/classic/browser/preferences/in-content/dialog.css (preferences/in-content/dialog.css) | |
skin/classic/browser/preferences/applications.css (preferences/applications.css) | |
+ skin/classic/browser/share.svg (share.svg) | |
skin/classic/browser/tabbrowser/tabDragIndicator.png (tabbrowser/tabDragIndicator.png) | |
skin/classic/browser/window-controls/close.svg (window-controls/close.svg) | |
skin/classic/browser/window-controls/close-highcontrast.svg (window-controls/close-highcontrast.svg) | |
diff --git a/browser/themes/windows/share.svg b/browser/themes/windows/share.svg | |
new file mode 100644 | |
index 000000000000..3d5c2fe86f2b | |
--- /dev/null | |
+++ b/browser/themes/windows/share.svg | |
@@ -0,0 +1,7 @@ | |
+<!-- 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/. --> | |
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"> | |
+ <path fill="context-fill" d="M 15.707 4.293 l -4 -4 a 1 1 0 0 0 -1.414 1.414 L 12.585 4 H 11 a 7.008 7.008 0 0 0 -7 7 a 1 1 0 0 0 2 0 a 5.006 5.006 0 0 1 5 -5 h 1.585 l -2.293 2.293 a 1 1 0 1 0 1.414 1.414 l 4 -4 a 1 1 0 0 0 0.001 -1.414 Z" /> | |
+ <path fill="context-fill" d="M 13 11 a 1 1 0 0 0 -1 1 v 1 a 1 1 0 0 1 -1 1 H 3 a 1 1 0 0 1 -1 -1 V 6 a 1 1 0 0 1 1 -1 h 1 a 1 1 0 0 0 0 -2 H 3 a 3 3 0 0 0 -3 3 v 7 a 3 3 0 0 0 3 3 h 8 a 3 3 0 0 0 3 -3 v -1 a 1 1 0 0 0 -1 -1 Z" /> | |
+</svg> | |
diff --git a/widget/nsIWindowsUIUtils.idl b/widget/nsIWindowsUIUtils.idl | |
index 331562a67245..779cc4ac9af5 100644 | |
--- a/widget/nsIWindowsUIUtils.idl | |
+++ b/widget/nsIWindowsUIUtils.idl | |
@@ -20,5 +20,9 @@ interface nsIWindowsUIUtils : nsISupports | |
* Update the tablet mode state | |
*/ | |
void updateTabletModeState(); | |
-}; | |
+ /** | |
+ * Share URL | |
+ */ | |
+ void shareUrl(in AString shareTitle, in AString urlToShare); | |
+}; | |
diff --git a/widget/windows/WindowsUIUtils.cpp b/widget/windows/WindowsUIUtils.cpp | |
index 4d916d25cf1e..ca4514e31ae5 100644 | |
--- a/widget/windows/WindowsUIUtils.cpp | |
+++ b/widget/windows/WindowsUIUtils.cpp | |
@@ -35,6 +35,7 @@ using namespace ABI::Windows::UI::ViewManagement; | |
using namespace Microsoft::WRL; | |
using namespace Microsoft::WRL::Wrappers; | |
using namespace ABI::Windows::Foundation; | |
+using namespace ABI::Windows::ApplicationModel::DataTransfer; | |
/* All of this is win10 stuff and we're compiling against win81 headers | |
* for now, so we may need to do some legwork: */ | |
@@ -90,6 +91,20 @@ public: | |
}; | |
#endif | |
+#ifndef __IDataTransferManagerInterop_INTERFACE_DEFINED__ | |
+ | |
+typedef interface IDataTransferManagerInterop IDataTransferManagerInterop; | |
+ | |
+MIDL_INTERFACE("3A3DCD6C-3EAB-43DC-BCDE-45671CE800C8") | |
+IDataTransferManagerInterop : public IUnknown | |
+{ | |
+public: | |
+ virtual HRESULT STDMETHODCALLTYPE GetForWindow(HWND appWindow, REFIID riid, void **dataTransferManager) = 0; | |
+ virtual HRESULT STDMETHODCALLTYPE ShowShareUIForWindow(HWND appWindow) = 0; | |
+}; | |
+ | |
+#endif | |
+ | |
#endif | |
WindowsUIUtils::WindowsUIUtils() : | |
@@ -178,3 +193,98 @@ WindowsUIUtils::UpdateTabletModeState() | |
return NS_OK; | |
} | |
+ | |
+struct HStringDeleter | |
+{ | |
+ typedef HSTRING pointer; | |
+ void operator()(pointer aString) | |
+ { | |
+ WindowsDeleteString(aString); | |
+ } | |
+}; | |
+ | |
+typedef mozilla::UniquePtr<HSTRING, HStringDeleter> HStringUniquePtr; | |
+ | |
+NS_IMETHODIMP | |
+WindowsUIUtils::ShareUrl(const nsAString& aUrlToShare, | |
+ const nsAString& aShareTitle) | |
+{ | |
+#ifndef __MINGW32__ | |
+ if (!IsWin10OrLater()) { | |
+ return NS_OK; | |
+ } | |
+ | |
+ HStringUniquePtr title; | |
+ HSTRING rawTitle; | |
+ HSTRING url; | |
+ | |
+ HRESULT hr = WindowsCreateString(PromiseFlatString(aShareTitle).get(), aShareTitle.Length(), &rawTitle); | |
+ if (FAILED(hr)) { | |
+ return NS_OK; | |
+ } | |
+ title.reset(rawTitle); | |
+ | |
+ hr = WindowsCreateString(PromiseFlatString(aUrlToShare).get(), aUrlToShare.Length(), &url); | |
+ if (FAILED(hr)) { | |
+ return NS_OK; | |
+ } | |
+ | |
+ ComPtr<IUriRuntimeClassFactory> uriFactory; | |
+ hr = GetActivationFactory(HStringReference(RuntimeClass_Windows_Foundation_Uri).Get(), &uriFactory); | |
+ if (FAILED(hr)) { | |
+ return NS_OK; | |
+ } | |
+ | |
+ ComPtr<IUriRuntimeClass> uri; | |
+ hr = uriFactory->CreateUri(url, &uri); | |
+ if (FAILED(hr)) { | |
+ return NS_OK; | |
+ } | |
+ | |
+ HWND hwnd = GetForegroundWindow(); | |
+ ComPtr<IDataTransferManagerInterop> dtmInterop; | |
+ ComPtr<IDataTransferManager> dtm; | |
+ EventRegistrationToken dataRequestedToken; | |
+ | |
+ hr = RoGetActivationFactory(HStringReference( | |
+ RuntimeClass_Windows_ApplicationModel_DataTransfer_DataTransferManager) | |
+ .Get(), IID_PPV_ARGS(&dtmInterop)); | |
+ if (FAILED(hr)) { | |
+ return NS_OK; | |
+ } | |
+ | |
+ hr = dtmInterop->GetForWindow(hwnd, IID_PPV_ARGS(&dtm)); | |
+ if (FAILED(hr)) { | |
+ return NS_OK; | |
+ } | |
+ | |
+ auto callback = Callback < ITypedEventHandler<DataTransferManager*, DataRequestedEventArgs* >> ( | |
+ [=](IDataTransferManager*, IDataRequestedEventArgs* pArgs) -> HRESULT | |
+ { | |
+ ComPtr<IDataRequest> spDataRequest; | |
+ pArgs->get_Request(&spDataRequest); | |
+ ComPtr<IDataPackage> spDataPackage; | |
+ spDataRequest->get_Data(&spDataPackage); | |
+ ComPtr<IDataPackagePropertySet> spDataPackageProperties; | |
+ spDataPackage->get_Properties(&spDataPackageProperties); | |
+ | |
+ spDataPackageProperties->put_Title(title.get()); | |
+ spDataPackage->SetUri(uri.Get()); | |
+ | |
+ return S_OK; | |
+ }); | |
+ | |
+ hr = dtm->add_DataRequested(callback.Get(), &dataRequestedToken); | |
+ if (FAILED(hr)) { | |
+ return NS_OK; | |
+ } | |
+ | |
+ hr = dtmInterop->ShowShareUIForWindow(hwnd); | |
+ if (FAILED(hr)) { | |
+ return NS_OK; | |
+ } | |
+ | |
+#endif | |
+ | |
+ return NS_OK; | |
+} | |
-- | |
2.18.0.windows.1 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment