420 lines
16 KiB
C++
420 lines
16 KiB
C++
/****************************************************************************
|
|
**
|
|
** Copyright (C) 2015 The Qt Company Ltd.
|
|
** Contact: http://www.qt.io/licensing/
|
|
**
|
|
** This file is part of the plugins of the Qt Toolkit.
|
|
**
|
|
** $QT_BEGIN_LICENSE:LGPL3$
|
|
** Commercial License Usage
|
|
** Licensees holding valid commercial Qt licenses may use this file in
|
|
** accordance with the commercial license agreement provided with the
|
|
** Software or, alternatively, in accordance with the terms contained in
|
|
** a written agreement between you and The Qt Company. For licensing terms
|
|
** and conditions see http://www.qt.io/terms-conditions. For further
|
|
** information use the contact form at http://www.qt.io/contact-us.
|
|
**
|
|
** GNU Lesser General Public License Usage
|
|
** Alternatively, this file may be used under the terms of the GNU Lesser
|
|
** General Public License version 3 as published by the Free Software
|
|
** Foundation and appearing in the file LICENSE.LGPLv3 included in the
|
|
** packaging of this file. Please review the following information to
|
|
** ensure the GNU Lesser General Public License version 3 requirements
|
|
** will be met: https://www.gnu.org/licenses/lgpl.html.
|
|
**
|
|
** GNU General Public License Usage
|
|
** Alternatively, this file may be used under the terms of the GNU
|
|
** General Public License version 2.0 or later as published by the Free
|
|
** Software Foundation and appearing in the file LICENSE.GPL included in
|
|
** the packaging of this file. Please review the following information to
|
|
** ensure the GNU General Public License version 2.0 requirements will be
|
|
** met: http://www.gnu.org/licenses/gpl-2.0.html.
|
|
**
|
|
** $QT_END_LICENSE$
|
|
**
|
|
****************************************************************************/
|
|
|
|
#include "qwinrtintegration.h"
|
|
#include "qwinrtwindow.h"
|
|
#include "qwinrteventdispatcher.h"
|
|
#include "qwinrtbackingstore.h"
|
|
#include "qwinrtscreen.h"
|
|
#include "qwinrtinputcontext.h"
|
|
#include "qwinrtservices.h"
|
|
#include "qwinrteglcontext.h"
|
|
#include "qwinrtfontdatabase.h"
|
|
#include "qwinrttheme.h"
|
|
#include "qwinrtclipboard.h"
|
|
|
|
#include <QtGui/QOffscreenSurface>
|
|
#include <QtGui/QOpenGLContext>
|
|
#include <QtGui/QSurface>
|
|
|
|
#include <QtPlatformSupport/private/qeglpbuffer_p.h>
|
|
#include <qpa/qwindowsysteminterface.h>
|
|
#include <qpa/qplatformwindow.h>
|
|
#include <qpa/qplatformoffscreensurface.h>
|
|
|
|
#include <qfunctions_winrt.h>
|
|
|
|
#include <functional>
|
|
#include <wrl.h>
|
|
#include <windows.ui.xaml.h>
|
|
#include <windows.applicationmodel.h>
|
|
#include <windows.applicationmodel.core.h>
|
|
#include <windows.ui.core.h>
|
|
#include <windows.ui.viewmanagement.h>
|
|
#include <windows.graphics.display.h>
|
|
|
|
#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE_APP)
|
|
# include <windows.phone.ui.input.h>
|
|
# if _MSC_VER >= 1900
|
|
# include <windows.foundation.metadata.h>
|
|
using namespace ABI::Windows::Foundation::Metadata;
|
|
# endif
|
|
#endif
|
|
|
|
|
|
using namespace Microsoft::WRL;
|
|
using namespace Microsoft::WRL::Wrappers;
|
|
using namespace ABI::Windows::Foundation;
|
|
using namespace ABI::Windows::ApplicationModel;
|
|
using namespace ABI::Windows::ApplicationModel::Core;
|
|
using namespace ABI::Windows::UI;
|
|
using namespace ABI::Windows::UI::Core;
|
|
using namespace ABI::Windows::UI::ViewManagement;
|
|
using namespace ABI::Windows::Graphics::Display;
|
|
using namespace ABI::Windows::ApplicationModel::Core;
|
|
#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE_APP)
|
|
using namespace ABI::Windows::Phone::UI::Input;
|
|
#endif
|
|
|
|
typedef IEventHandler<IInspectable *> ResumeHandler;
|
|
typedef IEventHandler<SuspendingEventArgs *> SuspendHandler;
|
|
#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE_APP)
|
|
typedef IEventHandler<BackPressedEventArgs*> BackPressedHandler;
|
|
typedef IEventHandler<CameraEventArgs*> CameraButtonHandler;
|
|
#endif
|
|
|
|
QT_BEGIN_NAMESPACE
|
|
|
|
typedef HRESULT (__stdcall ICoreApplication::*CoreApplicationCallbackRemover)(EventRegistrationToken);
|
|
uint qHash(CoreApplicationCallbackRemover key) { void *ptr = *(void **)(&key); return qHash(ptr); }
|
|
#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE_APP)
|
|
typedef HRESULT (__stdcall IHardwareButtonsStatics::*HardwareButtonsCallbackRemover)(EventRegistrationToken);
|
|
uint qHash(HardwareButtonsCallbackRemover key) { void *ptr = *(void **)(&key); return qHash(ptr); }
|
|
typedef HRESULT (__stdcall IHardwareButtonsStatics2::*HardwareButtons2CallbackRemover)(EventRegistrationToken);
|
|
uint qHash(HardwareButtons2CallbackRemover key) { void *ptr = *(void **)(&key); return qHash(ptr); }
|
|
#endif
|
|
|
|
class QWinRTIntegrationPrivate
|
|
{
|
|
public:
|
|
QPlatformFontDatabase *fontDatabase;
|
|
QPlatformServices *platformServices;
|
|
QPlatformClipboard *clipboard;
|
|
QWinRTScreen *mainScreen;
|
|
QScopedPointer<QWinRTInputContext> inputContext;
|
|
|
|
ComPtr<ICoreApplication> application;
|
|
QHash<CoreApplicationCallbackRemover, EventRegistrationToken> applicationTokens;
|
|
#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE_APP)
|
|
ComPtr<IHardwareButtonsStatics> hardwareButtons;
|
|
QHash<HardwareButtonsCallbackRemover, EventRegistrationToken> buttonsTokens;
|
|
ComPtr<IHardwareButtonsStatics2> cameraButtons;
|
|
QHash<HardwareButtons2CallbackRemover, EventRegistrationToken> cameraTokens;
|
|
boolean hasHardwareButtons;
|
|
bool cameraHalfPressed : 1;
|
|
bool cameraPressed : 1;
|
|
#endif
|
|
};
|
|
|
|
QWinRTIntegration::QWinRTIntegration() : d_ptr(new QWinRTIntegrationPrivate)
|
|
{
|
|
Q_D(QWinRTIntegration);
|
|
|
|
d->fontDatabase = new QWinRTFontDatabase;
|
|
|
|
HRESULT hr;
|
|
hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_ApplicationModel_Core_CoreApplication).Get(),
|
|
IID_PPV_ARGS(&d->application));
|
|
Q_ASSERT_SUCCEEDED(hr);
|
|
hr = d->application->add_Suspending(Callback<SuspendHandler>(this, &QWinRTIntegration::onSuspended).Get(),
|
|
&d->applicationTokens[&ICoreApplication::remove_Suspending]);
|
|
Q_ASSERT_SUCCEEDED(hr);
|
|
hr = d->application->add_Resuming(Callback<ResumeHandler>(this, &QWinRTIntegration::onResume).Get(),
|
|
&d->applicationTokens[&ICoreApplication::remove_Resuming]);
|
|
Q_ASSERT_SUCCEEDED(hr);
|
|
|
|
#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE_APP)
|
|
#if _MSC_VER >= 1900
|
|
d->hasHardwareButtons = false;
|
|
ComPtr<IApiInformationStatics> apiInformationStatics;
|
|
hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Foundation_Metadata_ApiInformation).Get(),
|
|
IID_PPV_ARGS(&apiInformationStatics));
|
|
|
|
if (SUCCEEDED(hr)) {
|
|
const HStringReference valueRef(L"Windows.Phone.UI.Input.HardwareButtons");
|
|
hr = apiInformationStatics->IsTypePresent(valueRef.Get(), &d->hasHardwareButtons);
|
|
}
|
|
#else
|
|
d->hasHardwareButtons = true;
|
|
#endif // _MSC_VER >= 1900
|
|
|
|
if (d->hasHardwareButtons) {
|
|
hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Phone_UI_Input_HardwareButtons).Get(),
|
|
IID_PPV_ARGS(&d->hardwareButtons));
|
|
Q_ASSERT_SUCCEEDED(hr);
|
|
hr = d->hardwareButtons->add_BackPressed(Callback<BackPressedHandler>(this, &QWinRTIntegration::onBackButtonPressed).Get(),
|
|
&d->buttonsTokens[&IHardwareButtonsStatics::remove_BackPressed]);
|
|
Q_ASSERT_SUCCEEDED(hr);
|
|
|
|
hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Phone_UI_Input_HardwareButtons).Get(),
|
|
IID_PPV_ARGS(&d->cameraButtons));
|
|
Q_ASSERT_SUCCEEDED(hr);
|
|
if (qEnvironmentVariableIntValue("QT_QPA_ENABLE_CAMERA_KEYS")) {
|
|
hr = d->cameraButtons->add_CameraPressed(Callback<CameraButtonHandler>(this, &QWinRTIntegration::onCameraPressed).Get(),
|
|
&d->cameraTokens[&IHardwareButtonsStatics2::remove_CameraPressed]);
|
|
Q_ASSERT_SUCCEEDED(hr);
|
|
hr = d->cameraButtons->add_CameraHalfPressed(Callback<CameraButtonHandler>(this, &QWinRTIntegration::onCameraHalfPressed).Get(),
|
|
&d->cameraTokens[&IHardwareButtonsStatics2::remove_CameraHalfPressed]);
|
|
Q_ASSERT_SUCCEEDED(hr);
|
|
hr = d->cameraButtons->add_CameraReleased(Callback<CameraButtonHandler>(this, &QWinRTIntegration::onCameraReleased).Get(),
|
|
&d->cameraTokens[&IHardwareButtonsStatics2::remove_CameraReleased]);
|
|
Q_ASSERT_SUCCEEDED(hr);
|
|
}
|
|
d->cameraPressed = false;
|
|
d->cameraHalfPressed = false;
|
|
}
|
|
#endif // WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE_APP)
|
|
|
|
|
|
QEventDispatcherWinRT::runOnXamlThread([d]() {
|
|
d->mainScreen = new QWinRTScreen;
|
|
d->inputContext.reset(new QWinRTInputContext(d->mainScreen));
|
|
return S_OK;
|
|
});
|
|
|
|
screenAdded(d->mainScreen);
|
|
d->platformServices = new QWinRTServices;
|
|
d->clipboard = new QWinRTClipboard;
|
|
}
|
|
|
|
QWinRTIntegration::~QWinRTIntegration()
|
|
{
|
|
Q_D(QWinRTIntegration);
|
|
HRESULT hr;
|
|
|
|
#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE_APP)
|
|
if (d->hasHardwareButtons) {
|
|
for (QHash<HardwareButtonsCallbackRemover, EventRegistrationToken>::const_iterator i = d->buttonsTokens.begin(); i != d->buttonsTokens.end(); ++i) {
|
|
hr = (d->hardwareButtons.Get()->*i.key())(i.value());
|
|
Q_ASSERT_SUCCEEDED(hr);
|
|
}
|
|
for (QHash<HardwareButtons2CallbackRemover, EventRegistrationToken>::const_iterator i = d->cameraTokens.begin(); i != d->cameraTokens.end(); ++i) {
|
|
hr = (d->cameraButtons.Get()->*i.key())(i.value());
|
|
Q_ASSERT_SUCCEEDED(hr);
|
|
}
|
|
}
|
|
#endif
|
|
// Do not execute this on Windows Phone as the application is already
|
|
// shutting down and trying to unregister suspending/resume handler will
|
|
// cause exceptions and assert in debug mode
|
|
#ifndef Q_OS_WINPHONE
|
|
for (QHash<CoreApplicationCallbackRemover, EventRegistrationToken>::const_iterator i = d->applicationTokens.begin(); i != d->applicationTokens.end(); ++i) {
|
|
hr = (d->application.Get()->*i.key())(i.value());
|
|
Q_ASSERT_SUCCEEDED(hr);
|
|
}
|
|
#endif
|
|
destroyScreen(d->mainScreen);
|
|
Windows::Foundation::Uninitialize();
|
|
}
|
|
|
|
bool QWinRTIntegration::succeeded() const
|
|
{
|
|
Q_D(const QWinRTIntegration);
|
|
return d->mainScreen;
|
|
}
|
|
|
|
QAbstractEventDispatcher *QWinRTIntegration::createEventDispatcher() const
|
|
{
|
|
return new QWinRTEventDispatcher;
|
|
}
|
|
|
|
void QWinRTIntegration::initialize()
|
|
{
|
|
Q_D(const QWinRTIntegration);
|
|
QEventDispatcherWinRT::runOnXamlThread([d]() {
|
|
d->mainScreen->initialize();
|
|
return S_OK;
|
|
});
|
|
}
|
|
|
|
bool QWinRTIntegration::hasCapability(QPlatformIntegration::Capability cap) const
|
|
{
|
|
switch (cap) {
|
|
case ThreadedPixmaps:
|
|
case OpenGL:
|
|
case ApplicationState:
|
|
case NonFullScreenWindows:
|
|
case MultipleWindows:
|
|
case RasterGLSurface:
|
|
return true;
|
|
default:
|
|
return QPlatformIntegration::hasCapability(cap);
|
|
}
|
|
}
|
|
|
|
QVariant QWinRTIntegration::styleHint(StyleHint hint) const
|
|
{
|
|
return QWinRTTheme::styleHint(hint);
|
|
}
|
|
|
|
QPlatformWindow *QWinRTIntegration::createPlatformWindow(QWindow *window) const
|
|
{
|
|
return new QWinRTWindow(window);
|
|
}
|
|
|
|
QPlatformBackingStore *QWinRTIntegration::createPlatformBackingStore(QWindow *window) const
|
|
{
|
|
return new QWinRTBackingStore(window);
|
|
}
|
|
|
|
QPlatformOpenGLContext *QWinRTIntegration::createPlatformOpenGLContext(QOpenGLContext *context) const
|
|
{
|
|
return new QWinRTEGLContext(context);
|
|
}
|
|
|
|
QPlatformFontDatabase *QWinRTIntegration::fontDatabase() const
|
|
{
|
|
Q_D(const QWinRTIntegration);
|
|
return d->fontDatabase;
|
|
}
|
|
|
|
QPlatformInputContext *QWinRTIntegration::inputContext() const
|
|
{
|
|
Q_D(const QWinRTIntegration);
|
|
return d->inputContext.data();
|
|
}
|
|
|
|
QPlatformServices *QWinRTIntegration::services() const
|
|
{
|
|
Q_D(const QWinRTIntegration);
|
|
return d->platformServices;
|
|
}
|
|
|
|
QPlatformClipboard *QWinRTIntegration::clipboard() const
|
|
{
|
|
Q_D(const QWinRTIntegration);
|
|
return d->clipboard;
|
|
}
|
|
|
|
Qt::KeyboardModifiers QWinRTIntegration::queryKeyboardModifiers() const
|
|
{
|
|
Q_D(const QWinRTIntegration);
|
|
return d->mainScreen->keyboardModifiers();
|
|
}
|
|
|
|
QStringList QWinRTIntegration::themeNames() const
|
|
{
|
|
return QStringList(QLatin1String("winrt"));
|
|
}
|
|
|
|
QPlatformTheme *QWinRTIntegration::createPlatformTheme(const QString &name) const
|
|
{
|
|
if (name == QLatin1String("winrt"))
|
|
return new QWinRTTheme();
|
|
|
|
return 0;
|
|
}
|
|
|
|
// System-level integration points
|
|
|
|
#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE_APP)
|
|
HRESULT QWinRTIntegration::onBackButtonPressed(IInspectable *, IBackPressedEventArgs *args)
|
|
{
|
|
Q_D(QWinRTIntegration);
|
|
QWindow *window = d->mainScreen->topWindow();
|
|
QWindowSystemInterface::setSynchronousWindowSystemEvents(true);
|
|
const bool pressed = QWindowSystemInterface::handleExtendedKeyEvent(window, QEvent::KeyPress, Qt::Key_Back, Qt::NoModifier,
|
|
0, 0, 0, QString(), false, 1, false);
|
|
const bool released = QWindowSystemInterface::handleExtendedKeyEvent(window, QEvent::KeyRelease, Qt::Key_Back, Qt::NoModifier,
|
|
0, 0, 0, QString(), false, 1, false);
|
|
QWindowSystemInterface::setSynchronousWindowSystemEvents(false);
|
|
args->put_Handled(pressed || released);
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT QWinRTIntegration::onCameraPressed(IInspectable *, ICameraEventArgs *)
|
|
{
|
|
Q_D(QWinRTIntegration);
|
|
QWindow *window = d->mainScreen->topWindow();
|
|
QWindowSystemInterface::handleExtendedKeyEvent(window, QEvent::KeyPress, Qt::Key_Camera, Qt::NoModifier,
|
|
0, 0, 0, QString(), false, 1, false);
|
|
d->cameraPressed = true;
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT QWinRTIntegration::onCameraHalfPressed(IInspectable *, ICameraEventArgs *)
|
|
{
|
|
Q_D(QWinRTIntegration);
|
|
QWindow *window = d->mainScreen->topWindow();
|
|
QWindowSystemInterface::handleExtendedKeyEvent(window, QEvent::KeyPress, Qt::Key_CameraFocus, Qt::NoModifier,
|
|
0, 0, 0, QString(), false, 1, false);
|
|
d->cameraHalfPressed = true;
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT QWinRTIntegration::onCameraReleased(IInspectable *, ICameraEventArgs *)
|
|
{
|
|
Q_D(QWinRTIntegration);
|
|
QWindow *window = d->mainScreen->topWindow();
|
|
if (d->cameraHalfPressed)
|
|
QWindowSystemInterface::handleExtendedKeyEvent(window, QEvent::KeyRelease, Qt::Key_CameraFocus, Qt::NoModifier,
|
|
0, 0, 0, QString(), false, 1, false);
|
|
|
|
if (d->cameraPressed)
|
|
QWindowSystemInterface::handleExtendedKeyEvent(window, QEvent::KeyRelease, Qt::Key_Camera, Qt::NoModifier,
|
|
0, 0, 0, QString(), false, 1, false);
|
|
d->cameraHalfPressed = false;
|
|
d->cameraPressed = false;
|
|
return S_OK;
|
|
}
|
|
#endif // WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE_APP)
|
|
|
|
HRESULT QWinRTIntegration::onSuspended(IInspectable *, ISuspendingEventArgs *)
|
|
{
|
|
QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationSuspended);
|
|
QWindowSystemInterface::flushWindowSystemEvents();
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT QWinRTIntegration::onResume(IInspectable *, IInspectable *)
|
|
{
|
|
// First the system invokes onResume and then changes
|
|
// the visibility of the screen to be active.
|
|
QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationHidden);
|
|
return S_OK;
|
|
}
|
|
|
|
QPlatformOffscreenSurface *QWinRTIntegration::createPlatformOffscreenSurface(QOffscreenSurface *surface) const
|
|
{
|
|
QEGLPbuffer *pbuffer = nullptr;
|
|
HRESULT hr = QEventDispatcherWinRT::runOnXamlThread([&pbuffer, surface]() {
|
|
pbuffer = new QEGLPbuffer(QWinRTEGLContext::display(), surface->requestedFormat(), surface);
|
|
return S_OK;
|
|
});
|
|
if (hr == UI_E_WINDOW_CLOSED) {
|
|
// This is only used for shutdown of applications.
|
|
// In case we do not return an empty surface the scenegraph will try
|
|
// to create a new native window during application exit causing crashes
|
|
// or assertions.
|
|
return new QPlatformOffscreenSurface(surface);
|
|
}
|
|
|
|
return pbuffer;
|
|
}
|
|
|
|
|
|
QT_END_NAMESPACE
|