Skip to content

Instantly share code, notes, and snippets.

@daleharvey
Created September 26, 2018 20:12
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save daleharvey/0e37d38b0d6fa05f148746ff4d6344fb to your computer and use it in GitHub Desktop.
Save daleharvey/0e37d38b0d6fa05f148746ff4d6344fb to your computer and use it in GitHub Desktop.
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