gecko-dev/widget/windows/WindowsUIUtils.cpp

379 строки
10 KiB
C++

/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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/. */
#include <windows.h>
#include <winsdkver.h>
#include <wrl.h>
#include "nsServiceManagerUtils.h"
#include "WindowsUIUtils.h"
#include "nsIObserverService.h"
#include "nsIAppShellService.h"
#include "nsAppShellCID.h"
#include "mozilla/Services.h"
#include "mozilla/WidgetUtils.h"
#include "mozilla/WindowsVersion.h"
#include "nsString.h"
#include "nsIWidget.h"
#include "nsIWindowMediator.h"
#include "nsPIDOMWindow.h"
#include "nsWindowGfx.h"
#include "Units.h"
/* mingw currently doesn't support windows.ui.viewmanagement.h, so we disable it
* until it's fixed. */
#ifndef __MINGW32__
# include <windows.ui.viewmanagement.h>
# pragma comment(lib, "runtimeobject.lib")
using namespace mozilla;
using namespace ABI::Windows::UI;
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: */
# if WINVER_MAXVER < 0x0A00
namespace ABI {
namespace Windows {
namespace UI {
namespace ViewManagement {
enum UserInteractionMode {
UserInteractionMode_Mouse = 0,
UserInteractionMode_Touch = 1
};
}
} // namespace UI
} // namespace Windows
} // namespace ABI
# endif
# ifndef RuntimeClass_Windows_UI_ViewManagement_UIViewSettings
# define RuntimeClass_Windows_UI_ViewManagement_UIViewSettings \
L"Windows.UI.ViewManagement.UIViewSettings"
# endif
# if WINVER_MAXVER < 0x0A00
namespace ABI {
namespace Windows {
namespace UI {
namespace ViewManagement {
interface IUIViewSettings;
MIDL_INTERFACE("C63657F6-8850-470D-88F8-455E16EA2C26")
IUIViewSettings : public IInspectable {
public:
virtual HRESULT STDMETHODCALLTYPE get_UserInteractionMode(
UserInteractionMode * value) = 0;
};
extern const __declspec(selectany) IID& IID_IUIViewSettings =
__uuidof(IUIViewSettings);
} // namespace ViewManagement
} // namespace UI
} // namespace Windows
} // namespace ABI
# endif
# ifndef IUIViewSettingsInterop
typedef interface IUIViewSettingsInterop IUIViewSettingsInterop;
MIDL_INTERFACE("3694dbf9-8f68-44be-8ff5-195c98ede8a6")
IUIViewSettingsInterop : public IInspectable {
public:
virtual HRESULT STDMETHODCALLTYPE GetForWindow(HWND hwnd, REFIID riid,
void** ppv) = 0;
};
# endif
# ifndef __IDataTransferManagerInterop_INTERFACE_DEFINED__
# define __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() : mInTabletMode(eTabletModeUnknown) {}
WindowsUIUtils::~WindowsUIUtils() {}
/*
* Implement the nsISupports methods...
*/
NS_IMPL_ISUPPORTS(WindowsUIUtils, nsIWindowsUIUtils)
NS_IMETHODIMP
WindowsUIUtils::GetSystemSmallIconSize(int32_t* aSize) {
NS_ENSURE_ARG(aSize);
mozilla::LayoutDeviceIntSize size =
nsWindowGfx::GetIconMetrics(nsWindowGfx::kSmallIcon);
*aSize = std::max(size.width, size.height);
return NS_OK;
}
NS_IMETHODIMP
WindowsUIUtils::GetSystemLargeIconSize(int32_t* aSize) {
NS_ENSURE_ARG(aSize);
mozilla::LayoutDeviceIntSize size =
nsWindowGfx::GetIconMetrics(nsWindowGfx::kRegularIcon);
*aSize = std::max(size.width, size.height);
return NS_OK;
}
NS_IMETHODIMP
WindowsUIUtils::SetWindowIcon(mozIDOMWindowProxy* aWindow,
imgIContainer* aSmallIcon,
imgIContainer* aBigIcon) {
NS_ENSURE_ARG(aWindow);
nsCOMPtr<nsIWidget> widget =
nsGlobalWindowOuter::Cast(aWindow)->GetMainWidget();
nsWindow* window = static_cast<nsWindow*>(widget.get());
nsresult rv;
if (aSmallIcon) {
HICON hIcon = nullptr;
rv = nsWindowGfx::CreateIcon(
aSmallIcon, false, mozilla::LayoutDeviceIntPoint(),
nsWindowGfx::GetIconMetrics(nsWindowGfx::kSmallIcon), &hIcon);
NS_ENSURE_SUCCESS(rv, rv);
window->SetSmallIcon(hIcon);
}
if (aBigIcon) {
HICON hIcon = nullptr;
rv = nsWindowGfx::CreateIcon(
aBigIcon, false, mozilla::LayoutDeviceIntPoint(),
nsWindowGfx::GetIconMetrics(nsWindowGfx::kRegularIcon), &hIcon);
NS_ENSURE_SUCCESS(rv, rv);
window->SetBigIcon(hIcon);
}
return NS_OK;
}
NS_IMETHODIMP
WindowsUIUtils::GetInTabletMode(bool* aResult) {
if (mInTabletMode == eTabletModeUnknown) {
UpdateTabletModeState();
}
*aResult = mInTabletMode == eTabletModeOn;
return NS_OK;
}
NS_IMETHODIMP
WindowsUIUtils::UpdateTabletModeState() {
#ifndef __MINGW32__
if (!IsWin10OrLater()) {
return NS_OK;
}
nsresult rv;
nsCOMPtr<nsIWindowMediator> winMediator(
do_GetService(NS_WINDOWMEDIATOR_CONTRACTID, &rv));
if (NS_FAILED(rv)) {
return rv;
}
nsCOMPtr<nsIWidget> widget;
nsCOMPtr<mozIDOMWindowProxy> navWin;
rv = winMediator->GetMostRecentWindow(u"navigator:browser",
getter_AddRefs(navWin));
if (NS_FAILED(rv) || !navWin) {
// Fall back to the hidden window
nsCOMPtr<nsIAppShellService> appShell(
do_GetService(NS_APPSHELLSERVICE_CONTRACTID));
rv = appShell->GetHiddenDOMWindow(getter_AddRefs(navWin));
if (NS_FAILED(rv) || !navWin) {
return rv;
}
}
nsPIDOMWindowOuter* win = nsPIDOMWindowOuter::From(navWin);
widget = widget::WidgetUtils::DOMWindowToWidget(win);
if (!widget) return NS_ERROR_FAILURE;
HWND winPtr = (HWND)widget->GetNativeData(NS_NATIVE_WINDOW);
ComPtr<IUIViewSettingsInterop> uiViewSettingsInterop;
HRESULT hr = GetActivationFactory(
HStringReference(RuntimeClass_Windows_UI_ViewManagement_UIViewSettings)
.Get(),
&uiViewSettingsInterop);
if (SUCCEEDED(hr)) {
ComPtr<IUIViewSettings> uiViewSettings;
hr = uiViewSettingsInterop->GetForWindow(winPtr,
IID_PPV_ARGS(&uiViewSettings));
if (SUCCEEDED(hr)) {
UserInteractionMode mode;
hr = uiViewSettings->get_UserInteractionMode(&mode);
if (SUCCEEDED(hr)) {
TabletModeState oldTabletModeState = mInTabletMode;
mInTabletMode = (mode == UserInteractionMode_Touch) ? eTabletModeOn
: eTabletModeOff;
if (mInTabletMode != oldTabletModeState) {
nsCOMPtr<nsIObserverService> observerService =
mozilla::services::GetObserverService();
observerService->NotifyObservers(
nullptr, "tablet-mode-change",
((mInTabletMode == eTabletModeOn) ? u"tablet-mode"
: u"normal-mode"));
}
}
}
}
#endif
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;
}
HSTRING rawTitle;
HRESULT hr = WindowsCreateString(PromiseFlatString(aShareTitle).get(),
aShareTitle.Length(), &rawTitle);
if (FAILED(hr)) {
return NS_OK;
}
HStringUniquePtr title(rawTitle);
HSTRING rawUrl;
hr = WindowsCreateString(PromiseFlatString(aUrlToShare).get(),
aUrlToShare.Length(), &rawUrl);
if (FAILED(hr)) {
return NS_OK;
}
HStringUniquePtr url(rawUrl);
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.get(), &uri);
if (FAILED(hr)) {
return NS_OK;
}
HWND hwnd = GetForegroundWindow();
if (!hwnd) {
return NS_OK;
}
ComPtr<IDataTransferManagerInterop> dtmInterop;
hr = RoGetActivationFactory(
HStringReference(
RuntimeClass_Windows_ApplicationModel_DataTransfer_DataTransferManager)
.Get(),
IID_PPV_ARGS(&dtmInterop));
if (FAILED(hr)) {
return NS_OK;
}
ComPtr<IDataTransferManager> dtm;
hr = dtmInterop->GetForWindow(hwnd, IID_PPV_ARGS(&dtm));
if (FAILED(hr)) {
return NS_OK;
}
auto callback = Callback<
ITypedEventHandler<DataTransferManager*, DataRequestedEventArgs*>>(
[uri = std::move(uri), title = std::move(title)](
IDataTransferManager*, IDataRequestedEventArgs* pArgs) -> HRESULT {
ComPtr<IDataRequest> spDataRequest;
HRESULT hr = pArgs->get_Request(&spDataRequest);
if (FAILED(hr)) {
return hr;
}
ComPtr<IDataPackage> spDataPackage;
hr = spDataRequest->get_Data(&spDataPackage);
if (FAILED(hr)) {
return hr;
}
ComPtr<IDataPackage2> spDataPackage2;
hr = spDataPackage->QueryInterface(IID_PPV_ARGS(&spDataPackage2));
if (FAILED(hr)) {
return hr;
}
ComPtr<IDataPackagePropertySet> spDataPackageProperties;
hr = spDataPackage->get_Properties(&spDataPackageProperties);
if (FAILED(hr)) {
return hr;
}
hr = spDataPackageProperties->put_Title(title.get());
if (FAILED(hr)) {
return hr;
}
hr = spDataPackage2->SetWebLink(uri.Get());
if (FAILED(hr)) {
return hr;
}
return S_OK;
});
EventRegistrationToken dataRequestedToken;
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;
}