winrt: Refactor platform plugin for XAML support

By using XAML as the platform compositor, many benefits are possible:
 - Better input context handling for tablets
 - Better multiple window support (including non-fullscreen windows)
 - Support for transparent windows and window opacity
 - Integration with native platform controls
 - Simpler orientation handling on Windows Phone with built-in transitions

This patch applies only the minimal parts to make XAML mode work just as
the raw D3D mode. It does this by:
 - Moving all OpenGL parts into QWinRTEGLContext. This will allow us to
   have non-OpenGL windows later (e.g. Direct2D raster surfaces).
 - Moving more window-specific parts into QWinRTWindow. Each window creates
   a SwapChainPanel which can then be used for ANGLE (or Direct2D) content.
 - Moving non screen-specific parts into QWinRTIntegration.
 - Having QWinRTScreen create the base XAML element Canvas.
 - Running certain calls on the UI thread where necessary.

The following code parts were removed:
 - The UIAutomationCore code in QWinRTInputContext, as this is incompatible
   with XAML automation.
 - The D3D Trim and device blacklist, as these have been fixed in ANGLE.
 - Core dispatcher processing in QEventDispatcherWinRT. Now there is only
   one native event dispatcher; it is always running and never needs to be
   pumped.

Future commits should address:
 - Maintaining the window stack list and visibility using the XAML Canvas.
 - Allowing for windows (e.g. popups) to be sized and positioned instead
   of fullscreen.
 - Using the XAML automation API to improve the platform input context.

[ChangeLog][QPA][winrt] Windows Store apps are now composited inside a
XAML container, allowing for tighter integration with the native UI layer.

Change-Id: I285c6dea657c5dab2fda2b1bd8e8e5dd15882c72
Reviewed-by: Oliver Wolff <oliver.wolff@theqtcompany.com>
bb10
Andrew Knight 2015-08-12 12:43:54 +03:00
parent ebc2b963aa
commit 807ec8ea48
13 changed files with 624 additions and 557 deletions

View File

@ -40,6 +40,7 @@
#include <private/qabstracteventdispatcher_p.h>
#include <private/qcoreapplication_p.h>
#include <functional>
#include <wrl.h>
#include <windows.foundation.h>
#include <windows.system.threading.h>
@ -70,6 +71,23 @@ struct WinRTTimerInfo : public QAbstractEventDispatcher::TimerInfo {
quint64 targetTime;
};
class AgileDispatchedHandler : public RuntimeClass<RuntimeClassFlags<WinRtClassicComMix>, IDispatchedHandler, IAgileObject>
{
public:
AgileDispatchedHandler(const std::function<HRESULT()> &delegate)
: delegate(delegate)
{
}
HRESULT __stdcall Invoke()
{
return delegate();
}
private:
std::function<HRESULT()> delegate;
};
class QEventDispatcherWinRTPrivate : public QAbstractEventDispatcherPrivate
{
Q_DECLARE_PUBLIC(QEventDispatcherWinRT)
@ -80,8 +98,6 @@ public:
private:
ComPtr<IThreadPoolTimerStatics> timerFactory;
ComPtr<ICoreDispatcher> coreDispatcher;
QPointer<QThread> thread;
QHash<int, QObject *> timerIdToObject;
QVector<WinRTTimerInfo> timerInfos;
@ -136,40 +152,11 @@ private:
}
return true;
}
void fetchCoreDispatcher()
{
ComPtr<ICoreImmersiveApplication> application;
HRESULT hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_ApplicationModel_Core_CoreApplication).Get(),
IID_PPV_ARGS(&application));
RETURN_VOID_IF_FAILED("Failed to get the application factory");
static ComPtr<ICoreApplicationView> view;
if (view)
return;
hr = application->get_MainView(&view);
RETURN_VOID_IF_FAILED("Failed to get the main view");
ComPtr<ICoreApplicationView2> view2;
hr = view.As(&view2);
RETURN_VOID_IF_FAILED("Failed to cast the main view");
hr = view2->get_Dispatcher(&coreDispatcher);
if (hr == HRESULT_FROM_WIN32(ERROR_NOT_FOUND)) // expected in thread pool cases
return;
RETURN_VOID_IF_FAILED("Failed to get core dispatcher");
thread = QThread::currentThread();
}
};
QEventDispatcherWinRT::QEventDispatcherWinRT(QObject *parent)
: QAbstractEventDispatcher(*new QEventDispatcherWinRTPrivate, parent)
{
Q_D(QEventDispatcherWinRT);
d->fetchCoreDispatcher();
}
QEventDispatcherWinRT::QEventDispatcherWinRT(QEventDispatcherWinRTPrivate &dd, QObject *parent)
@ -180,25 +167,43 @@ QEventDispatcherWinRT::~QEventDispatcherWinRT()
{
}
HRESULT QEventDispatcherWinRT::runOnXamlThread(const std::function<HRESULT ()> &delegate)
{
static __declspec(thread) ICoreDispatcher *dispatcher = nullptr;
if (!dispatcher) {
HRESULT hr;
ComPtr<ICoreImmersiveApplication> application;
hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_ApplicationModel_Core_CoreApplication).Get(),
IID_PPV_ARGS(&application));
ComPtr<ICoreApplicationView> view;
hr = application->get_MainView(&view);
Q_ASSERT_SUCCEEDED(hr);
ComPtr<ICoreWindow> window;
hr = view->get_CoreWindow(&window);
Q_ASSERT_SUCCEEDED(hr);
hr = window->get_Dispatcher(&dispatcher);
Q_ASSERT_SUCCEEDED(hr);
}
HRESULT hr;
boolean onXamlThread;
hr = dispatcher->get_HasThreadAccess(&onXamlThread);
Q_ASSERT_SUCCEEDED(hr);
if (onXamlThread) // Already there
return delegate();
ComPtr<IAsyncAction> op;
hr = dispatcher->RunAsync(CoreDispatcherPriority_Normal, Make<AgileDispatchedHandler>(delegate).Get(), &op);
if (FAILED(hr))
return hr;
return QWinRTFunctions::await(op);
}
bool QEventDispatcherWinRT::processEvents(QEventLoop::ProcessEventsFlags flags)
{
Q_D(QEventDispatcherWinRT);
if (d->thread && d->thread != QThread::currentThread())
d->fetchCoreDispatcher();
do {
// Process native events
if (d->coreDispatcher) {
boolean hasThreadAccess;
HRESULT hr = d->coreDispatcher->get_HasThreadAccess(&hasThreadAccess);
if (SUCCEEDED(hr) && hasThreadAccess) {
hr = d->coreDispatcher->ProcessEvents(CoreProcessEventsOption_ProcessAllIfPresent);
if (FAILED(hr))
qErrnoWarning(hr, "Failed to process events");
}
}
// Additional user events have to be handled before timer events, but the function may not
// return yet.
const bool userEventsSent = sendPostedEvents(flags);
@ -284,10 +289,11 @@ void QEventDispatcherWinRT::registerTimer(int timerId, int interval, Qt::TimerTy
TimeSpan period;
period.Duration = interval ? (interval * 10000) : 1; // TimeSpan is based on 100-nanosecond units
IThreadPoolTimer *timer;
const HANDLE handle = CreateEventEx(NULL, NULL, CREATE_EVENT_MANUAL_RESET, SYNCHRONIZE | EVENT_MODIFY_STATE);
const HANDLE cancelHandle = CreateEventEx(NULL, NULL, CREATE_EVENT_MANUAL_RESET, SYNCHRONIZE|EVENT_MODIFY_STATE);
HRESULT hr = d->timerFactory->CreatePeriodicTimerWithCompletion(
HRESULT hr = runOnXamlThread([&]() {
IThreadPoolTimer *timer;
HRESULT hr = d->timerFactory->CreatePeriodicTimerWithCompletion(
Callback<ITimerElapsedHandler>([handle, cancelHandle](IThreadPoolTimer *timer) {
DWORD cancelResult = WaitForSingleObjectEx(cancelHandle, 0, TRUE);
if (cancelResult == WAIT_OBJECT_0) {
@ -306,13 +312,15 @@ void QEventDispatcherWinRT::registerTimer(int timerId, int interval, Qt::TimerTy
CloseHandle(cancelHandle);
return S_OK;
}).Get(), &timer);
RETURN_HR_IF_FAILED("Failed to create periodic timer");
d->addTimer(timerId, interval, timerType, object, handle, cancelHandle);
return hr;
});
if (FAILED(hr)) {
qErrnoWarning(hr, "Failed to create periodic timer");
CloseHandle(handle);
CloseHandle(cancelHandle);
return;
}
d->addTimer(timerId, interval, timerType, object, handle, cancelHandle);
}
bool QEventDispatcherWinRT::unregisterTimer(int timerId)

View File

@ -50,6 +50,8 @@
#include <qt_windows.h>
namespace std { template <typename T> class function; }
QT_BEGIN_NAMESPACE
quint64 qt_msectime();
@ -65,6 +67,8 @@ public:
explicit QEventDispatcherWinRT(QObject *parent = 0);
~QEventDispatcherWinRT();
static HRESULT runOnXamlThread(const std::function<HRESULT()> &delegate);
bool processEvents(QEventLoop::ProcessEventsFlags flags);
bool hasPendingEvents();

View File

@ -36,11 +36,13 @@
#include "qwinrtcursor.h"
#include "qwinrtscreen.h"
#include <private/qeventdispatcher_winrt_p.h>
#include <QtCore/qfunctions_winrt.h>
#include <QtGui/QGuiApplication>
#include <QtGui/QScreen>
#include <functional>
#include <wrl.h>
#include <windows.ui.core.h>
#include <windows.foundation.h>
@ -77,12 +79,17 @@ void QWinRTCursor::changeCursor(QCursor *windowCursor, QWindow *window)
{
Q_D(QWinRTCursor);
HRESULT hr;
ICoreWindow *coreWindow = static_cast<QWinRTScreen *>(window->screen()->handle())->coreWindow();
CoreCursorType type;
switch (windowCursor ? windowCursor->shape() : Qt::ArrowCursor) {
case Qt::BlankCursor:
coreWindow->put_PointerCursor(Q_NULLPTR);
hr = QEventDispatcherWinRT::runOnXamlThread([coreWindow]() {
coreWindow->put_PointerCursor(Q_NULLPTR);
return S_OK;
});
RETURN_VOID_IF_FAILED("Failed to set blank native cursor");
return;
default:
case Qt::OpenHandCursor:
@ -142,11 +149,13 @@ void QWinRTCursor::changeCursor(QCursor *windowCursor, QWindow *window)
}
ComPtr<ICoreCursor> cursor;
HRESULT hr = d->cursorFactory->CreateCursor(type, 0, &cursor);
hr = d->cursorFactory->CreateCursor(type, 0, &cursor);
RETURN_VOID_IF_FAILED("Failed to create native cursor.");
hr = coreWindow->put_PointerCursor(cursor.Get());
RETURN_VOID_IF_FAILED("Failed to set native cursor.");
hr = QEventDispatcherWinRT::runOnXamlThread([coreWindow, &cursor]() {
return coreWindow->put_PointerCursor(cursor.Get());
});
RETURN_VOID_IF_FAILED("Failed to set native cursor");
}
#endif // QT_NO_CURSOR
@ -154,8 +163,12 @@ QPoint QWinRTCursor::pos() const
{
ICoreWindow *coreWindow =
static_cast<QWinRTScreen *>(QGuiApplication::primaryScreen()->handle())->coreWindow();
HRESULT hr;
Point point;
coreWindow->get_PointerPosition(&point);
hr = QEventDispatcherWinRT::runOnXamlThread([coreWindow, &point]() {
return coreWindow->get_PointerPosition(&point);
});
RETURN_IF_FAILED("Failed to get native cursor position", QPoint());
return QPoint(point.X, point.Y);
}

View File

@ -35,40 +35,133 @@
****************************************************************************/
#include "qwinrteglcontext.h"
#include "qwinrtwindow.h"
#include <private/qeventdispatcher_winrt_p.h>
#include <functional>
#include <EGL/egl.h>
#define EGL_EGLEXT_PROTOTYPES
#include "EGL/eglext.h"
#include <EGL/eglext.h>
#include <QOpenGLContext>
#include <QtPlatformSupport/private/qeglconvenience_p.h>
QT_BEGIN_NAMESPACE
QWinRTEGLContext::QWinRTEGLContext(const QSurfaceFormat &format, QPlatformOpenGLContext *share, EGLDisplay display, EGLSurface surface, EGLConfig config)
: QEGLPlatformContext(format, share, display, &config), m_eglSurface(surface)
class QWinRTEGLContextPrivate
{
public:
QSurfaceFormat format;
EGLDisplay eglDisplay;
EGLConfig eglConfig;
EGLContext eglContext;
QHash<QPlatformSurface *, EGLSurface> surfaceForWindow;
};
QWinRTEGLContext::QWinRTEGLContext(QOpenGLContext *context)
: d_ptr(new QWinRTEGLContextPrivate)
{
Q_D(QWinRTEGLContext);
d->format = context->format();
d->format.setRenderableType(QSurfaceFormat::OpenGLES);
}
void QWinRTEGLContext::swapBuffers(QPlatformSurface *surface)
QWinRTEGLContext::~QWinRTEGLContext()
{
#ifdef Q_OS_WINPHONE
const QSize size = surface->surface()->size();
eglPostSubBufferNV(eglDisplay(), eglSurfaceForPlatformSurface(surface),
0, 0, size.width(), size.height());
#else
eglSwapBuffers(eglDisplay(), eglSurfaceForPlatformSurface(surface));
#endif
Q_D(QWinRTEGLContext);
foreach (const EGLSurface &surface, d->surfaceForWindow)
eglDestroySurface(d->eglDisplay, surface);
if (d->eglContext != EGL_NO_CONTEXT)
eglDestroyContext(d->eglDisplay, d->eglContext);
if (d->eglDisplay != EGL_NO_DISPLAY)
eglTerminate(d->eglDisplay);
}
EGLSurface QWinRTEGLContext::eglSurfaceForPlatformSurface(QPlatformSurface *surface)
void QWinRTEGLContext::initialize()
{
if (surface->surface()->surfaceClass() == QSurface::Window) {
// All windows use the same surface
return m_eglSurface;
} else {
// TODO: return EGL surfaces for offscreen surfaces
qWarning("This plugin does not support offscreen surfaces.");
return EGL_NO_SURFACE;
Q_D(QWinRTEGLContext);
eglBindAPI(EGL_OPENGL_ES_API);
d->eglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
if (d->eglDisplay == EGL_NO_DISPLAY)
qCritical("Failed to initialize EGL display: 0x%x", eglGetError());
if (!eglInitialize(d->eglDisplay, nullptr, nullptr))
qCritical("Failed to initialize EGL: 0x%x", eglGetError());
d->eglConfig = q_configFromGLFormat(d->eglDisplay, d->format);
const EGLint flags = d->format.testOption(QSurfaceFormat::DebugContext)
? EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR : 0;
const EGLint attributes[] = {
EGL_CONTEXT_CLIENT_VERSION, d->format.majorVersion(),
EGL_CONTEXT_MINOR_VERSION_KHR, d->format.minorVersion(),
EGL_CONTEXT_FLAGS_KHR, flags,
EGL_NONE
};
d->eglContext = eglCreateContext(d->eglDisplay, d->eglConfig, nullptr, attributes);
if (d->eglContext == EGL_NO_CONTEXT) {
qWarning("QEGLPlatformContext: Failed to create context: %x", eglGetError());
return;
}
}
bool QWinRTEGLContext::makeCurrent(QPlatformSurface *windowSurface)
{
Q_D(QWinRTEGLContext);
Q_ASSERT(windowSurface->surface()->surfaceType() == QSurface::OpenGLSurface);
EGLSurface surface = d->surfaceForWindow.value(windowSurface);
if (surface == EGL_NO_SURFACE) {
QWinRTWindow *window = static_cast<QWinRTWindow *>(windowSurface);
HRESULT hr = QEventDispatcherWinRT::runOnXamlThread([this, d, window, &surface]() {
surface = eglCreateWindowSurface(d->eglDisplay, d->eglConfig,
reinterpret_cast<EGLNativeWindowType>(window->winId()),
nullptr);
if (surface == EGL_NO_SURFACE) {
qCritical("Failed to create EGL window surface: 0x%x", eglGetError());
return E_FAIL;
}
return S_OK;
});
if (FAILED(hr))
return false;
d->surfaceForWindow.insert(windowSurface, surface);
}
const bool ok = eglMakeCurrent(d->eglDisplay, surface, surface, d->eglContext);
if (!ok) {
qWarning("QEGLPlatformContext: eglMakeCurrent failed: %x", eglGetError());
return false;
}
eglSwapInterval(d->eglDisplay, d->format.swapInterval());
return true;
}
void QWinRTEGLContext::doneCurrent()
{
Q_D(const QWinRTEGLContext);
const bool ok = eglMakeCurrent(d->eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
if (!ok)
qWarning("QEGLPlatformContext: eglMakeCurrent failed: %x", eglGetError());
}
void QWinRTEGLContext::swapBuffers(QPlatformSurface *windowSurface)
{
Q_D(QWinRTEGLContext);
Q_ASSERT(windowSurface->surface()->surfaceType() == QSurface::OpenGLSurface);
eglSwapBuffers(d->eglDisplay, d->surfaceForWindow.value(windowSurface));
}
QSurfaceFormat QWinRTEGLContext::format() const
{
Q_D(const QWinRTEGLContext);
return d->format;
}
QFunctionPointer QWinRTEGLContext::getProcAddress(const QByteArray &procName)
{
static QHash<QByteArray, QFunctionPointer> standardFuncs;
@ -221,7 +314,7 @@ QFunctionPointer QWinRTEGLContext::getProcAddress(const QByteArray &procName)
if (i != standardFuncs.end())
return i.value();
return QEGLPlatformContext::getProcAddress(procName);
return eglGetProcAddress(procName.constData());
}
QT_END_NAMESPACE

View File

@ -37,23 +37,29 @@
#ifndef QWINDOWSEGLCONTEXT_H
#define QWINDOWSEGLCONTEXT_H
#include <QtPlatformSupport/private/qeglplatformcontext_p.h>
#include <qpa/qplatformopenglcontext.h>
QT_BEGIN_NAMESPACE
class QWinRTEGLContext : public QEGLPlatformContext
class QWinRTEGLContextPrivate;
class QWinRTEGLContext : public QPlatformOpenGLContext
{
public:
explicit QWinRTEGLContext(const QSurfaceFormat &format, QPlatformOpenGLContext *share, EGLDisplay display, EGLSurface surface, EGLConfig config);
explicit QWinRTEGLContext(QOpenGLContext *context);
~QWinRTEGLContext();
void swapBuffers(QPlatformSurface *surface) Q_DECL_OVERRIDE;
void initialize() Q_DECL_OVERRIDE;
bool makeCurrent(QPlatformSurface *windowSurface) Q_DECL_OVERRIDE;
void doneCurrent() Q_DECL_OVERRIDE;
void swapBuffers(QPlatformSurface *windowSurface) Q_DECL_OVERRIDE;
QSurfaceFormat format() const Q_DECL_OVERRIDE;
QFunctionPointer getProcAddress(const QByteArray &procName) Q_DECL_OVERRIDE;
protected:
EGLSurface eglSurfaceForPlatformSurface(QPlatformSurface *surface);
private:
EGLSurface m_eglSurface;
QScopedPointer<QWinRTEGLContextPrivate> d_ptr;
Q_DECLARE_PRIVATE(QWinRTEGLContext)
};
QT_END_NAMESPACE

View File

@ -182,135 +182,6 @@ void QWinRTInputContext::hideInputPanel()
qErrnoWarning(hr, "Failed to hide input panel.");
}
#else // Q_OS_WINPHONE
// IRawElementProviderSimple
HRESULT QWinRTInputContext::get_ProviderOptions(ProviderOptions *retVal)
{
*retVal = ProviderOptions_ServerSideProvider|ProviderOptions_UseComThreading;
return S_OK;
}
HRESULT QWinRTInputContext::GetPatternProvider(PATTERNID id, IUnknown **retVal)
{
switch (id) {
case 10002: //UIA_ValuePatternId
return QueryInterface(__uuidof(IValueProvider), (void**)retVal);
break;
case 10014: //UIA_TextPatternId:
return QueryInterface(__uuidof(ITextProvider), (void**)retVal);
case 10029: //UIA_TextChildPatternId:
*retVal = nullptr;
break;
default:
qWarning("Unhandled pattern ID: %d", id);
break;
}
return S_OK;
}
HRESULT QWinRTInputContext::GetPropertyValue(PROPERTYID idProp, VARIANT *retVal)
{
switch (idProp) {
case 30003: //UIA_ControlTypePropertyId
retVal->vt = VT_I4;
retVal->lVal = 50025; //UIA_CustomControlTypeId
break;
case 30008: //UIA_IsKeyboardFocusablePropertyId
case 30009: //UIA_HasKeyboardFocusPropertyId
// These are probably never actually called
case 30016: //UIA_IsControlElementPropertyId
case 30017: //UIA_IsContentElementPropertyId
retVal->vt = VT_BOOL;
retVal->boolVal = VARIANT_TRUE;
break;
case 30019: //UIA_IsPasswordPropertyId
retVal->vt = VT_BOOL;
retVal->boolVal = VARIANT_FALSE;
break;
case 30020: //UIA_NativeWindowHandlePropertyId
retVal->vt = VT_PTR;
retVal->punkVal = m_screen->coreWindow();
break;
}
return S_OK;
}
HRESULT QWinRTInputContext::get_HostRawElementProvider(IRawElementProviderSimple **retVal)
{
// Return the window's element provider
IInspectable *hostProvider;
HRESULT hr = m_screen->coreWindow()->get_AutomationHostProvider(&hostProvider);
if (SUCCEEDED(hr)) {
hr = hostProvider->QueryInterface(IID_PPV_ARGS(retVal));
hostProvider->Release();
}
return hr;
}
// ITextProvider
HRESULT QWinRTInputContext::GetSelection(SAFEARRAY **)
{
// To be useful, requires listening to the focus object for a selection change and raising an event
return S_OK;
}
HRESULT QWinRTInputContext::GetVisibleRanges(SAFEARRAY **)
{
// To be useful, requires listening to the focus object for a selection change and raising an event
return S_OK;
}
HRESULT QWinRTInputContext::RangeFromChild(IRawElementProviderSimple *,ITextRangeProvider **)
{
// To be useful, requires listening to the focus object for a selection change and raising an event
return S_OK;
}
HRESULT QWinRTInputContext::RangeFromPoint(UiaPoint, ITextRangeProvider **)
{
// To be useful, requires listening to the focus object for a selection change and raising an event
return S_OK;
}
HRESULT QWinRTInputContext::get_DocumentRange(ITextRangeProvider **)
{
// To be useful, requires listening to the focus object for a selection change and raising an event
return S_OK;
}
HRESULT QWinRTInputContext::get_SupportedTextSelection(SupportedTextSelection *)
{
// To be useful, requires listening to the focus object for a selection change and raising an event
return S_OK;
}
// IValueProvider
HRESULT QWinRTInputContext::SetValue(LPCWSTR)
{
// To be useful, requires listening to the focus object for a value change and raising an event
// May be useful for inputPanel autocomplete, etc.
return S_OK;
}
HRESULT QWinRTInputContext::get_Value(BSTR *)
{
// To be useful, requires listening to the focus object for a value change and raising an event
// May be useful for inputPanel autocomplete, etc.
return S_OK;
}
HRESULT QWinRTInputContext::get_IsReadOnly(BOOL *isReadOnly)
{
// isReadOnly dictates keyboard opening behavior when view is tapped.
// We need to decide if the user tapped within a control which is about to receive focus...
// Since this isn't possible (this function gets called before we receive the touch event),
// the most platform-aligned option is to show the keyboard if an editable item has focus,
// and close the keyboard if it is already open.
*isReadOnly = m_isInputPanelVisible || !inputMethodAccepted();
return S_OK;
}
#endif // !Q_OS_WINPHONE
#endif // Q_OS_WINPHONE
QT_END_NAMESPACE

View File

@ -41,9 +41,6 @@
#include <QtCore/QRectF>
#include <wrl.h>
#ifndef Q_OS_WINPHONE
# include <UIAutomationCore.h>
#endif
namespace ABI {
namespace Windows {
@ -63,11 +60,6 @@ QT_BEGIN_NAMESPACE
class QWinRTScreen;
class QWinRTInputContext : public QPlatformInputContext
#ifndef Q_OS_WINPHONE
, public Microsoft::WRL::RuntimeClass<
Microsoft::WRL::RuntimeClassFlags<Microsoft::WRL::WinRtClassicComMix>,
IRawElementProviderSimple, ITextProvider, IValueProvider>
#endif // !Q_OS_WINPHONE
{
public:
explicit QWinRTInputContext(QWinRTScreen *);
@ -79,26 +71,7 @@ public:
#ifdef Q_OS_WINPHONE
void showInputPanel();
void hideInputPanel();
#else // Q_OS_WINPHONE
// IRawElementProviderSimple
HRESULT __stdcall get_ProviderOptions(ProviderOptions *retVal);
HRESULT __stdcall GetPatternProvider(PATTERNID, IUnknown **);
HRESULT __stdcall GetPropertyValue(PROPERTYID idProp, VARIANT *retVal);
HRESULT __stdcall get_HostRawElementProvider(IRawElementProviderSimple **retVal);
// ITextProvider
HRESULT __stdcall GetSelection(SAFEARRAY **);
HRESULT __stdcall GetVisibleRanges(SAFEARRAY **);
HRESULT __stdcall RangeFromChild(IRawElementProviderSimple *,ITextRangeProvider **);
HRESULT __stdcall RangeFromPoint(UiaPoint, ITextRangeProvider **);
HRESULT __stdcall get_DocumentRange(ITextRangeProvider **);
HRESULT __stdcall get_SupportedTextSelection(SupportedTextSelection *);
// IValueProvider
HRESULT __stdcall SetValue(LPCWSTR);
HRESULT __stdcall get_Value(BSTR *);
HRESULT __stdcall get_IsReadOnly(BOOL *);
#endif // !Q_OS_WINPHONE
#endif
private:
HRESULT onShowing(ABI::Windows::UI::ViewManagement::IInputPane *,

View File

@ -45,37 +45,138 @@
#include "qwinrtfontdatabase.h"
#include "qwinrttheme.h"
#include <QtCore/QCoreApplication>
#include <QtGui/QSurface>
#include <QtGui/QOpenGLContext>
#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.ApplicationModel.core.h>
#include <windows.graphics.display.h>
#ifdef Q_OS_WINPHONE
# include <windows.phone.ui.input.h>
#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;
#ifdef Q_OS_WINPHONE
using namespace ABI::Windows::Phone::UI::Input;
#endif
typedef IEventHandler<IInspectable *> ResumeHandler;
typedef IEventHandler<SuspendingEventArgs *> SuspendHandler;
#ifdef Q_OS_WINPHONE
typedef IEventHandler<BackPressedEventArgs*> BackPressedHandler;
#endif
QT_BEGIN_NAMESPACE
QWinRTIntegration::QWinRTIntegration()
: m_success(false)
, m_fontDatabase(new QWinRTFontDatabase)
, m_services(new QWinRTServices)
{
m_screen = new QWinRTScreen;
screenAdded(m_screen);
typedef HRESULT (__stdcall ICoreApplication::*CoreApplicationCallbackRemover)(EventRegistrationToken);
uint qHash(CoreApplicationCallbackRemover key) { void *ptr = *(void **)(&key); return qHash(ptr); }
#ifdef Q_OS_WINPHONE
typedef HRESULT (__stdcall IHardwareButtonsStatics::*HardwareButtonsCallbackRemover)(EventRegistrationToken);
uint qHash(HardwareButtonsCallbackRemover key) { void *ptr = *(void **)(&key); return qHash(ptr); }
#endif
m_success = true;
class QWinRTIntegrationPrivate
{
public:
QPlatformFontDatabase *fontDatabase;
QPlatformServices *platformServices;
QWinRTScreen *mainScreen;
QScopedPointer<QWinRTInputContext> inputContext;
ComPtr<ICoreApplication> application;
QHash<CoreApplicationCallbackRemover, EventRegistrationToken> applicationTokens;
#ifdef Q_OS_WINPHONE
ComPtr<IHardwareButtonsStatics> hardwareButtons;
QHash<HardwareButtonsCallbackRemover, EventRegistrationToken> buttonsTokens;
#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_Resuming]);
Q_ASSERT_SUCCEEDED(hr);
hr = d->application->add_Resuming(Callback<ResumeHandler>(this, &QWinRTIntegration::onResume).Get(),
&d->applicationTokens[&ICoreApplication::remove_Resuming]);
Q_ASSERT_SUCCEEDED(hr);
#ifdef Q_OS_WINPHONE
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);
#endif // Q_OS_WINPHONE
hr = QEventDispatcherWinRT::runOnXamlThread([this, d]() {
HRESULT hr;
ComPtr<Xaml::IWindowStatics> windowStatics;
hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_UI_Xaml_Window).Get(),
IID_PPV_ARGS(&windowStatics));
Q_ASSERT_SUCCEEDED(hr);
ComPtr<Xaml::IWindow> window;
hr = windowStatics->get_Current(&window);
Q_ASSERT_SUCCEEDED(hr);
hr = window->Activate();
Q_ASSERT_SUCCEEDED(hr);
d->mainScreen = new QWinRTScreen(window.Get());
d->inputContext.reset(new QWinRTInputContext(d->mainScreen));
screenAdded(d->mainScreen);
return S_OK;
});
Q_ASSERT_SUCCEEDED(hr);
}
QWinRTIntegration::~QWinRTIntegration()
{
Q_D(QWinRTIntegration);
HRESULT hr;
#ifdef Q_OS_WINPHONE
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);
}
#endif
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);
}
destroyScreen(d->mainScreen);
Windows::Foundation::Uninitialize();
}
bool QWinRTIntegration::succeeded() const
{
Q_D(const QWinRTIntegration);
return d->mainScreen;
}
QAbstractEventDispatcher *QWinRTIntegration::createEventDispatcher() const
{
return new QWinRTEventDispatcher;
@ -112,28 +213,31 @@ QPlatformBackingStore *QWinRTIntegration::createPlatformBackingStore(QWindow *wi
QPlatformOpenGLContext *QWinRTIntegration::createPlatformOpenGLContext(QOpenGLContext *context) const
{
QWinRTScreen *screen = static_cast<QWinRTScreen *>(context->screen()->handle());
return new QWinRTEGLContext(context->format(), context->handle(), screen->eglDisplay(), screen->eglSurface(), screen->eglConfig());
return new QWinRTEGLContext(context);
}
QPlatformFontDatabase *QWinRTIntegration::fontDatabase() const
{
return m_fontDatabase;
Q_D(const QWinRTIntegration);
return d->fontDatabase;
}
QPlatformInputContext *QWinRTIntegration::inputContext() const
{
return m_screen->inputContext();
Q_D(const QWinRTIntegration);
return d->inputContext.data();
}
QPlatformServices *QWinRTIntegration::services() const
{
return m_services;
Q_D(const QWinRTIntegration);
return d->platformServices;
}
Qt::KeyboardModifiers QWinRTIntegration::queryKeyboardModifiers() const
{
return m_screen->keyboardModifiers();
Q_D(const QWinRTIntegration);
return d->mainScreen->keyboardModifiers();
}
QStringList QWinRTIntegration::themeNames() const
@ -149,4 +253,45 @@ name) const
return 0;
}
// System-level integration points
#ifdef Q_OS_WINPHONE
HRESULT QWinRTIntegration::onBackButtonPressed(IInspectable *, IBackPressedEventArgs *args)
{
Q_D(QWinRTIntegration);
QKeyEvent backPress(QEvent::KeyPress, Qt::Key_Back, Qt::NoModifier);
QKeyEvent backRelease(QEvent::KeyRelease, Qt::Key_Back, Qt::NoModifier);
backPress.setAccepted(false);
backRelease.setAccepted(false);
QWindow *window = d->mainScreen->topWindow();
QObject *receiver = window ? static_cast<QObject *>(window)
: static_cast<QObject *>(QCoreApplication::instance());
// If the event is ignored, the app go to the background
QCoreApplication::sendEvent(receiver, &backPress);
QCoreApplication::sendEvent(receiver, &backRelease);
args->put_Handled(backPress.isAccepted() || backRelease.isAccepted());
return S_OK;
}
#endif // Q_OS_WINPHONE
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;
}
QT_END_NAMESPACE

View File

@ -39,11 +39,33 @@
#include <qpa/qplatformintegration.h>
namespace ABI {
namespace Windows {
namespace ApplicationModel {
struct ISuspendingEventArgs;
}
namespace Foundation {
struct IAsyncAction;
}
#ifdef Q_OS_WINPHONE
namespace Phone {
namespace UI {
namespace Input {
struct IBackPressedEventArgs;
}
}
}
#endif
}
}
struct IAsyncInfo;
struct IInspectable;
QT_BEGIN_NAMESPACE
class QAbstractEventDispatcher;
class QWinRTScreen;
class QWinRTIntegrationPrivate;
class QWinRTIntegration : public QPlatformIntegration
{
private:
@ -53,10 +75,12 @@ public:
static QWinRTIntegration *create()
{
QWinRTIntegration *integration = new QWinRTIntegration;
return integration->m_success ? integration : 0;
QScopedPointer<QWinRTIntegration> integration(new QWinRTIntegration);
return integration->succeeded() ? integration.take() : nullptr;
}
bool succeeded() const;
bool hasCapability(QPlatformIntegration::Capability cap) const;
QVariant styleHint(StyleHint hint) const;
@ -71,11 +95,16 @@ public:
QStringList themeNames() const;
QPlatformTheme *createPlatformTheme(const QString &name) const;
private:
bool m_success;
QWinRTScreen *m_screen;
QPlatformFontDatabase *m_fontDatabase;
QPlatformServices *m_services;
#ifdef Q_OS_WINPHONE
HRESULT onBackButtonPressed(IInspectable *, ABI::Windows::Phone::UI::Input::IBackPressedEventArgs *args);
#endif
HRESULT onSuspended(IInspectable *, ABI::Windows::ApplicationModel::ISuspendingEventArgs *);
HRESULT onResume(IInspectable *, IInspectable *);
QScopedPointer<QWinRTIntegrationPrivate> d_ptr;
Q_DECLARE_PRIVATE(QWinRTIntegration)
};
QT_END_NAMESPACE

View File

@ -36,26 +36,18 @@
#include "qwinrtscreen.h"
#define EGL_EGLEXT_PROTOTYPES
#include <EGL/eglext.h>
#include <d3d11.h>
#include <dxgi1_2.h>
#ifndef Q_OS_WINPHONE
#include <dxgi1_3.h>
#endif
#include "qwinrtbackingstore.h"
#include "qwinrtinputcontext.h"
#include "qwinrtcursor.h"
#include "qwinrteglcontext.h"
#include <private/qeventdispatcher_winrt_p.h>
#include <QtGui/QSurfaceFormat>
#include <QtGui/QGuiApplication>
#include <QtPlatformSupport/private/qeglconvenience_p.h>
#include <qpa/qwindowsysteminterface.h>
#include <QtCore/qt_windows.h>
#include <QtCore/qfunctions_winrt.h>
#include <functional>
#include <wrl.h>
#include <windows.system.h>
#include <Windows.Applicationmodel.h>
@ -64,12 +56,10 @@
#include <windows.ui.h>
#include <windows.ui.core.h>
#include <windows.ui.input.h>
#include <windows.ui.xaml.h>
#include <windows.ui.viewmanagement.h>
#include <windows.graphics.display.h>
#include <windows.foundation.h>
#ifdef Q_OS_WINPHONE
#include <windows.phone.ui.input.h>
#endif
using namespace Microsoft::WRL;
using namespace Microsoft::WRL::Wrappers;
@ -77,17 +67,13 @@ using namespace ABI::Windows::ApplicationModel;
using namespace ABI::Windows::ApplicationModel::Core;
using namespace ABI::Windows::Foundation;
using namespace ABI::Windows::System;
using namespace ABI::Windows::UI;
using namespace ABI::Windows::UI::Core;
using namespace ABI::Windows::UI::Input;
using namespace ABI::Windows::UI::ViewManagement;
using namespace ABI::Windows::Devices::Input;
using namespace ABI::Windows::Graphics::Display;
#ifdef Q_OS_WINPHONE
using namespace ABI::Windows::Phone::UI::Input;
#endif
typedef IEventHandler<IInspectable*> ResumeHandler;
typedef IEventHandler<SuspendingEventArgs*> SuspendHandler;
typedef ITypedEventHandler<CoreWindow*, WindowActivatedEventArgs*> ActivatedHandler;
typedef ITypedEventHandler<CoreWindow*, CoreWindowEventArgs*> ClosedHandler;
typedef ITypedEventHandler<CoreWindow*, CharacterReceivedEventArgs*> CharacterReceivedHandler;
@ -96,11 +82,7 @@ typedef ITypedEventHandler<CoreWindow*, KeyEventArgs*> KeyHandler;
typedef ITypedEventHandler<CoreWindow*, PointerEventArgs*> PointerHandler;
typedef ITypedEventHandler<CoreWindow*, WindowSizeChangedEventArgs*> SizeChangedHandler;
typedef ITypedEventHandler<CoreWindow*, VisibilityChangedEventArgs*> VisibilityChangedHandler;
typedef ITypedEventHandler<CoreWindow*, AutomationProviderRequestedEventArgs*> AutomationProviderRequestedHandler;
typedef ITypedEventHandler<DisplayInformation*, IInspectable*> DisplayInformationHandler;
#ifdef Q_OS_WINPHONE
typedef IEventHandler<BackPressedEventArgs*> BackPressedHandler;
#endif
QT_BEGIN_NAMESPACE
@ -419,33 +401,23 @@ static inline Qt::Key qKeyFromCode(quint32 code, int mods)
return static_cast<Qt::Key>(code & 0xff);
}
typedef HRESULT (__stdcall ICoreApplication::*CoreApplicationCallbackRemover)(EventRegistrationToken);
uint qHash(CoreApplicationCallbackRemover key) { void *ptr = *(void **)(&key); return qHash(ptr); }
typedef HRESULT (__stdcall ICoreWindow::*CoreWindowCallbackRemover)(EventRegistrationToken);
uint qHash(CoreWindowCallbackRemover key) { void *ptr = *(void **)(&key); return qHash(ptr); }
typedef HRESULT (__stdcall IDisplayInformation::*DisplayCallbackRemover)(EventRegistrationToken);
uint qHash(DisplayCallbackRemover key) { void *ptr = *(void **)(&key); return qHash(ptr); }
#ifdef Q_OS_WINPHONE
typedef HRESULT (__stdcall IHardwareButtonsStatics::*HardwareButtonsCallbackRemover)(EventRegistrationToken);
uint qHash(HardwareButtonsCallbackRemover key) { void *ptr = *(void **)(&key); return qHash(ptr); }
#endif
class QWinRTScreenPrivate
{
public:
ComPtr<ICoreApplication> application;
QTouchDevice *touchDevice;
ComPtr<ICoreWindow> coreWindow;
ComPtr<Xaml::IDependencyObject> canvas;
ComPtr<IApplicationView> view;
ComPtr<IDisplayInformation> displayInformation;
#ifdef Q_OS_WINPHONE
ComPtr<IHardwareButtonsStatics> hardwareButtons;
#endif
QScopedPointer<QWinRTCursor> cursor;
#ifdef Q_OS_WINPHONE
QScopedPointer<QWinRTInputContext> inputContext;
#else
ComPtr<QWinRTInputContext> inputContext;
#endif
QHash<quint32, QWindowSystemInterface::TouchPoint> touchPoints;
QSizeF logicalSize;
QSurfaceFormat surfaceFormat;
@ -458,68 +430,30 @@ public:
#ifndef Q_OS_WINPHONE
QHash<quint32, QPair<Qt::Key, QString>> activeKeys;
#endif
QTouchDevice *touchDevice;
QHash<quint32, QWindowSystemInterface::TouchPoint> touchPoints;
EGLDisplay eglDisplay;
EGLSurface eglSurface;
EGLConfig eglConfig;
QHash<CoreApplicationCallbackRemover, EventRegistrationToken> applicationTokens;
QHash<CoreWindowCallbackRemover, EventRegistrationToken> windowTokens;
QHash<DisplayCallbackRemover, EventRegistrationToken> displayTokens;
#ifdef Q_OS_WINPHONE
QHash<HardwareButtonsCallbackRemover, EventRegistrationToken> buttonsTokens;
#endif
};
QWinRTScreen::QWinRTScreen()
// To be called from the XAML thread
QWinRTScreen::QWinRTScreen(Xaml::IWindow *xamlWindow)
: d_ptr(new QWinRTScreenPrivate)
{
Q_D(QWinRTScreen);
d->orientation = Qt::PrimaryOrientation;
d->touchDevice = Q_NULLPTR;
d->eglDisplay = EGL_NO_DISPLAY;
// Obtain the WinRT Application, view, and window
HRESULT hr;
hr = RoGetActivationFactory(Wrappers::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, &QWinRTScreen::onSuspended).Get(), &d->applicationTokens[&ICoreApplication::remove_Resuming]);
Q_ASSERT_SUCCEEDED(hr);
hr = d->application->add_Resuming(Callback<ResumeHandler>(this, &QWinRTScreen::onResume).Get(), &d->applicationTokens[&ICoreApplication::remove_Resuming]);
Q_ASSERT_SUCCEEDED(hr);
ComPtr<ICoreApplicationView> view;
hr = d->application->GetCurrentView(&view);
Q_ASSERT_SUCCEEDED(hr);
hr = view->get_CoreWindow(&d->coreWindow);
hr = xamlWindow->get_CoreWindow(&d->coreWindow);
Q_ASSERT_SUCCEEDED(hr);
hr = d->coreWindow->Activate();
Q_ASSERT_SUCCEEDED(hr);
#ifdef Q_OS_WINPHONE
d->inputContext.reset(new QWinRTInputContext(this));
#else
d->inputContext = Make<QWinRTInputContext>(this);
#endif
Rect rect;
hr = d->coreWindow->get_Bounds(&rect);
Q_ASSERT_SUCCEEDED(hr);
d->logicalSize = QSizeF(rect.Width, rect.Height);
d->surfaceFormat.setAlphaBufferSize(0);
d->surfaceFormat.setRedBufferSize(8);
d->surfaceFormat.setGreenBufferSize(8);
d->surfaceFormat.setBlueBufferSize(8);
d->surfaceFormat.setDepthBufferSize(24);
d->surfaceFormat.setStencilBufferSize(8);
d->surfaceFormat.setRenderableType(QSurfaceFormat::OpenGLES);
d->surfaceFormat.setSamples(1);
d->surfaceFormat.setSwapBehavior(QSurfaceFormat::DoubleBuffer);
hr = d->coreWindow->add_KeyDown(Callback<KeyHandler>(this, &QWinRTScreen::onKeyDown).Get(), &d->windowTokens[&ICoreWindow::remove_KeyDown]);
Q_ASSERT_SUCCEEDED(hr);
hr = d->coreWindow->add_KeyUp(Callback<KeyHandler>(this, &QWinRTScreen::onKeyUp).Get(), &d->windowTokens[&ICoreWindow::remove_KeyUp]);
@ -538,24 +472,14 @@ QWinRTScreen::QWinRTScreen()
Q_ASSERT_SUCCEEDED(hr);
hr = d->coreWindow->add_PointerWheelChanged(Callback<PointerHandler>(this, &QWinRTScreen::onPointerUpdated).Get(), &d->windowTokens[&ICoreWindow::remove_PointerWheelChanged]);
Q_ASSERT_SUCCEEDED(hr);
#ifndef Q_OS_WINPHONE
hr = d->coreWindow->add_SizeChanged(Callback<SizeChangedHandler>(this, &QWinRTScreen::onSizeChanged).Get(), &d->windowTokens[&ICoreWindow::remove_SizeChanged]);
Q_ASSERT_SUCCEEDED(hr);
#endif
hr = d->coreWindow->add_Activated(Callback<ActivatedHandler>(this, &QWinRTScreen::onActivated).Get(), &d->windowTokens[&ICoreWindow::remove_Activated]);
Q_ASSERT_SUCCEEDED(hr);
hr = d->coreWindow->add_Closed(Callback<ClosedHandler>(this, &QWinRTScreen::onClosed).Get(), &d->windowTokens[&ICoreWindow::remove_Closed]);
Q_ASSERT_SUCCEEDED(hr);
hr = d->coreWindow->add_VisibilityChanged(Callback<VisibilityChangedHandler>(this, &QWinRTScreen::onVisibilityChanged).Get(), &d->windowTokens[&ICoreWindow::remove_VisibilityChanged]);
Q_ASSERT_SUCCEEDED(hr);
hr = d->coreWindow->add_AutomationProviderRequested(Callback<AutomationProviderRequestedHandler>(this, &QWinRTScreen::onAutomationProviderRequested).Get(), &d->windowTokens[&ICoreWindow::remove_AutomationProviderRequested]);
Q_ASSERT_SUCCEEDED(hr);
#ifdef Q_OS_WINPHONE
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, &QWinRTScreen::onBackButtonPressed).Get(), &d->buttonsTokens[&IHardwareButtonsStatics::remove_BackPressed]);
Q_ASSERT_SUCCEEDED(hr);
#endif // Q_OS_WINPHONE
// Orientation handling
ComPtr<IDisplayInformationStatics> displayInformationStatics;
@ -583,45 +507,34 @@ QWinRTScreen::QWinRTScreen()
d->orientation = d->nativeOrientation;
onOrientationChanged(Q_NULLPTR, Q_NULLPTR);
d->eglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
if (d->eglDisplay == EGL_NO_DISPLAY)
qCritical("Failed to initialize EGL display: 0x%x", eglGetError());
ComPtr<IApplicationViewStatics2> applicationViewStatics;
hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_UI_ViewManagement_ApplicationView).Get(),
IID_PPV_ARGS(&applicationViewStatics));
RETURN_VOID_IF_FAILED("Could not get ApplicationViewStatics");
if (!eglInitialize(d->eglDisplay, NULL, NULL))
qCritical("Failed to initialize EGL: 0x%x", eglGetError());
hr = applicationViewStatics->GetForCurrentView(&d->view);
RETURN_VOID_IF_FAILED("Could not access currentView");
// Check that the device properly supports depth/stencil rendering, and disable them if not
ComPtr<ID3D11Device> d3dDevice;
const EGLBoolean ok = eglQuerySurfacePointerANGLE(d->eglDisplay, EGL_NO_SURFACE, EGL_DEVICE_EXT, (void **)d3dDevice.GetAddressOf());
if (ok && d3dDevice) {
ComPtr<IDXGIDevice> dxgiDevice;
hr = d3dDevice.As(&dxgiDevice);
if (SUCCEEDED(hr)) {
ComPtr<IDXGIAdapter> dxgiAdapter;
hr = dxgiDevice->GetAdapter(&dxgiAdapter);
if (SUCCEEDED(hr)) {
ComPtr<IDXGIAdapter2> dxgiAdapter2;
hr = dxgiAdapter.As(&dxgiAdapter2);
if (SUCCEEDED(hr)) {
DXGI_ADAPTER_DESC2 desc;
hr = dxgiAdapter2->GetDesc2(&desc);
if (SUCCEEDED(hr)) {
// The following GPUs do not render properly with depth/stencil
if ((desc.VendorId == 0x4d4f4351 && desc.DeviceId == 0x32303032)) { // Qualcomm Adreno 225
d->surfaceFormat.setDepthBufferSize(-1);
d->surfaceFormat.setStencilBufferSize(-1);
}
}
}
}
}
}
// Create a canvas and set it as the window content. Eventually, this should have its own method so multiple "screens" can be added
ComPtr<Xaml::Controls::ICanvas> canvas;
hr = RoActivateInstance(HString::MakeReference(RuntimeClass_Windows_UI_Xaml_Controls_Canvas).Get(), &canvas);
Q_ASSERT_SUCCEEDED(hr);
ComPtr<Xaml::IFrameworkElement> frameworkElement;
hr = canvas.As(&frameworkElement);
Q_ASSERT_SUCCEEDED(hr);
hr = frameworkElement->put_Width(d->logicalSize.width());
Q_ASSERT_SUCCEEDED(hr);
hr = frameworkElement->put_Height(d->logicalSize.height());
Q_ASSERT_SUCCEEDED(hr);
ComPtr<Xaml::IUIElement> uiElement;
hr = canvas.As(&uiElement);
Q_ASSERT_SUCCEEDED(hr);
hr = xamlWindow->put_Content(uiElement.Get());
Q_ASSERT_SUCCEEDED(hr);
hr = canvas.As(&d->canvas);
Q_ASSERT_SUCCEEDED(hr);
d->eglConfig = q_configFromGLFormat(d->eglDisplay, d->surfaceFormat);
d->surfaceFormat = q_glFormatFromConfig(d->eglDisplay, d->eglConfig, d->surfaceFormat);
d->eglSurface = eglCreateWindowSurface(d->eglDisplay, d->eglConfig, d->coreWindow.Get(), NULL);
if (d->eglSurface == EGL_NO_SURFACE)
qCritical("Failed to create EGL window surface: 0x%x", eglGetError());
d->cursor.reset(new QWinRTCursor);
}
QWinRTScreen::~QWinRTScreen()
@ -629,16 +542,20 @@ QWinRTScreen::~QWinRTScreen()
Q_D(QWinRTScreen);
// Unregister callbacks
for (QHash<CoreApplicationCallbackRemover, EventRegistrationToken>::const_iterator i = d->applicationTokens.begin(); i != d->applicationTokens.end(); ++i)
(d->application.Get()->*i.key())(i.value());
for (QHash<CoreWindowCallbackRemover, EventRegistrationToken>::const_iterator i = d->windowTokens.begin(); i != d->windowTokens.end(); ++i)
(d->coreWindow.Get()->*i.key())(i.value());
for (QHash<DisplayCallbackRemover, EventRegistrationToken>::const_iterator i = d->displayTokens.begin(); i != d->displayTokens.end(); ++i)
(d->displayInformation.Get()->*i.key())(i.value());
#ifdef Q_OS_WINPHONE
for (QHash<HardwareButtonsCallbackRemover, EventRegistrationToken>::const_iterator i = d->buttonsTokens.begin(); i != d->buttonsTokens.end(); ++i)
(d->hardwareButtons.Get()->*i.key())(i.value());
#endif
HRESULT hr;
hr = QEventDispatcherWinRT::runOnXamlThread([this, d]() {
HRESULT hr;
for (QHash<CoreWindowCallbackRemover, EventRegistrationToken>::const_iterator i = d->windowTokens.begin(); i != d->windowTokens.end(); ++i) {
hr = (d->coreWindow.Get()->*i.key())(i.value());
Q_ASSERT_SUCCEEDED(hr);
}
for (QHash<DisplayCallbackRemover, EventRegistrationToken>::const_iterator i = d->displayTokens.begin(); i != d->displayTokens.end(); ++i) {
hr = (d->displayInformation.Get()->*i.key())(i.value());
Q_ASSERT_SUCCEEDED(hr);
}
return hr;
});
RETURN_VOID_IF_FAILED("Failed to unregister screen event callbacks");
}
QRect QWinRTScreen::geometry() const
@ -657,12 +574,6 @@ QImage::Format QWinRTScreen::format() const
return QImage::Format_ARGB32_Premultiplied;
}
QSurfaceFormat QWinRTScreen::surfaceFormat() const
{
Q_D(const QWinRTScreen);
return d->surfaceFormat;
}
QSizeF QWinRTScreen::physicalSize() const
{
Q_D(const QWinRTScreen);
@ -682,21 +593,9 @@ qreal QWinRTScreen::scaleFactor() const
return d->scaleFactor;
}
QWinRTInputContext *QWinRTScreen::inputContext() const
{
Q_D(const QWinRTScreen);
#ifdef Q_OS_WINPHONE
return d->inputContext.data();
#else
return d->inputContext.Get();
#endif
}
QPlatformCursor *QWinRTScreen::cursor() const
{
Q_D(const QWinRTScreen);
if (!d->cursor)
const_cast<QWinRTScreenPrivate *>(d)->cursor.reset(new QWinRTCursor);
return d->cursor.data();
}
@ -744,22 +643,10 @@ ICoreWindow *QWinRTScreen::coreWindow() const
return d->coreWindow.Get();
}
EGLDisplay QWinRTScreen::eglDisplay() const
Xaml::IDependencyObject *QWinRTScreen::canvas() const
{
Q_D(const QWinRTScreen);
return d->eglDisplay;
}
EGLSurface QWinRTScreen::eglSurface() const
{
Q_D(const QWinRTScreen);
return d->eglSurface;
}
EGLConfig QWinRTScreen::eglConfig() const
{
Q_D(const QWinRTScreen);
return d->eglConfig;
return d->canvas.Get();
}
QWindow *QWinRTScreen::topWindow() const
@ -809,6 +696,20 @@ void QWinRTScreen::lower(QWindow *window)
handleExpose();
}
void QWinRTScreen::updateWindowTitle()
{
Q_D(QWinRTScreen);
QWindow *window = topWindow();
if (!window)
return;
const QString title = window->title();
HStringReference titleRef(reinterpret_cast<LPCWSTR>(title.utf16()), title.length());
HRESULT hr = d->view->put_Title(titleRef.Get());
RETURN_VOID_IF_FAILED("Unable to set window title");
}
void QWinRTScreen::handleExpose()
{
Q_D(QWinRTScreen);
@ -1055,17 +956,6 @@ HRESULT QWinRTScreen::onPointerUpdated(ICoreWindow *, IPointerEventArgs *args)
return S_OK;
}
HRESULT QWinRTScreen::onAutomationProviderRequested(ICoreWindow *, IAutomationProviderRequestedEventArgs *args)
{
#ifndef Q_OS_WINPHONE
Q_D(const QWinRTScreen);
args->put_AutomationProvider(d->inputContext.Get());
#else
Q_UNUSED(args)
#endif
return S_OK;
}
HRESULT QWinRTScreen::onSizeChanged(ICoreWindow *, IWindowSizeChangedEventArgs *)
{
Q_D(QWinRTScreen);
@ -1075,18 +965,14 @@ HRESULT QWinRTScreen::onSizeChanged(ICoreWindow *, IWindowSizeChangedEventArgs *
hr = d->coreWindow->get_Bounds(&size);
RETURN_OK_IF_FAILED("Failed to get window bounds");
QSizeF logicalSize = QSizeF(size.Width, size.Height);
#ifndef Q_OS_WINPHONE // This handler is called from orientation changed, in which case we should always update the size
if (d->logicalSize == logicalSize)
return S_OK;
#endif
d->logicalSize = logicalSize;
if (d->eglDisplay) {
const QRect newGeometry = geometry();
QWindowSystemInterface::handleScreenGeometryChange(screen(), newGeometry, newGeometry);
QPlatformScreen::resizeMaximizedWindows();
handleExpose();
}
const QRect newGeometry = geometry();
QWindowSystemInterface::handleScreenGeometryChange(screen(), newGeometry, newGeometry);
QPlatformScreen::resizeMaximizedWindows();
handleExpose();
return S_OK;
}
@ -1110,31 +996,6 @@ HRESULT QWinRTScreen::onActivated(ICoreWindow *, IWindowActivatedEventArgs *args
return S_OK;
}
HRESULT QWinRTScreen::onSuspended(IInspectable *, ISuspendingEventArgs *)
{
#ifndef Q_OS_WINPHONE
Q_D(QWinRTScreen);
ComPtr<ID3D11Device> d3dDevice;
const EGLBoolean ok = eglQuerySurfacePointerANGLE(d->eglDisplay, EGL_NO_SURFACE, EGL_DEVICE_EXT, (void **)d3dDevice.GetAddressOf());
if (ok && d3dDevice) {
ComPtr<IDXGIDevice3> dxgiDevice;
if (SUCCEEDED(d3dDevice.As(&dxgiDevice)))
dxgiDevice->Trim();
}
#endif
QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationSuspended);
QWindowSystemInterface::flushWindowSystemEvents();
return S_OK;
}
HRESULT QWinRTScreen::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;
}
HRESULT QWinRTScreen::onClosed(ICoreWindow *, ICoreWindowEventArgs *)
{
foreach (QWindow *w, QGuiApplication::topLevelWindows())
@ -1165,10 +1026,6 @@ HRESULT QWinRTScreen::onOrientationChanged(IDisplayInformation *, IInspectable *
d->orientation = newOrientation;
QWindowSystemInterface::handleScreenOrientationChange(screen(), d->orientation);
}
#ifdef Q_OS_WINPHONE // The size changed handler is ignored in favor of this callback
onSizeChanged(Q_NULLPTR, Q_NULLPTR);
#endif
return S_OK;
}
@ -1205,27 +1062,4 @@ HRESULT QWinRTScreen::onDpiChanged(IDisplayInformation *, IInspectable *)
return S_OK;
}
#ifdef Q_OS_WINPHONE
HRESULT QWinRTScreen::onBackButtonPressed(IInspectable *, IBackPressedEventArgs *args)
{
Q_D(QWinRTScreen);
QKeyEvent backPress(QEvent::KeyPress, Qt::Key_Back, Qt::NoModifier);
QKeyEvent backRelease(QEvent::KeyRelease, Qt::Key_Back, Qt::NoModifier);
backPress.setAccepted(false);
backRelease.setAccepted(false);
QObject *receiver = d->visibleWindows.isEmpty()
? static_cast<QObject *>(QGuiApplication::instance())
: static_cast<QObject *>(d->visibleWindows.first());
// If the event is ignored, the app will suspend
QGuiApplication::sendEvent(receiver, &backPress);
QGuiApplication::sendEvent(receiver, &backRelease);
args->put_Handled(backPress.isAccepted() || backRelease.isAccepted());
return S_OK;
}
#endif // Q_OS_WINPHONE
QT_END_NAMESPACE

View File

@ -40,8 +40,6 @@
#include <qpa/qplatformscreen.h>
#include <qpa/qwindowsysteminterface.h>
#include <EGL/egl.h>
namespace ABI {
namespace Windows {
namespace ApplicationModel {
@ -59,21 +57,16 @@ namespace ABI {
struct IWindowActivatedEventArgs;
struct IWindowSizeChangedEventArgs;
}
namespace Xaml {
struct IDependencyObject;
struct IWindow;
}
}
namespace Graphics {
namespace Display {
struct IDisplayInformation;
}
}
#ifdef Q_OS_WINPHONE
namespace Phone {
namespace UI {
namespace Input {
struct IBackPressedEventArgs;
}
}
}
#endif
}
}
struct IInspectable;
@ -81,23 +74,20 @@ struct IInspectable;
QT_BEGIN_NAMESPACE
class QTouchDevice;
class QWinRTEGLContext;
class QWinRTCursor;
class QWinRTInputContext;
class QWinRTScreenPrivate;
class QWinRTScreen : public QPlatformScreen
{
public:
explicit QWinRTScreen();
explicit QWinRTScreen(ABI::Windows::UI::Xaml::IWindow *xamlWindow);
~QWinRTScreen();
QRect geometry() const;
int depth() const;
QImage::Format format() const;
QSurfaceFormat surfaceFormat() const;
QSizeF physicalSize() const Q_DECL_OVERRIDE;
QDpi logicalDpi() const Q_DECL_OVERRIDE;
qreal scaleFactor() const;
QWinRTInputContext *inputContext() const;
QPlatformCursor *cursor() const;
Qt::KeyboardModifiers keyboardModifiers() const;
@ -110,10 +100,10 @@ public:
void raise(QWindow *window);
void lower(QWindow *window);
void updateWindowTitle();
ABI::Windows::UI::Core::ICoreWindow *coreWindow() const;
EGLDisplay eglDisplay() const; // To opengl context
EGLSurface eglSurface() const; // To window
EGLConfig eglConfig() const;
ABI::Windows::UI::Xaml::IDependencyObject *canvas() const;
private:
void handleExpose();
@ -127,20 +117,13 @@ private:
HRESULT onSizeChanged(ABI::Windows::UI::Core::ICoreWindow *, ABI::Windows::UI::Core::IWindowSizeChangedEventArgs *);
HRESULT onActivated(ABI::Windows::UI::Core::ICoreWindow *, ABI::Windows::UI::Core::IWindowActivatedEventArgs *);
HRESULT onSuspended(IInspectable *, ABI::Windows::ApplicationModel::ISuspendingEventArgs *);
HRESULT onResume(IInspectable *, IInspectable *);
HRESULT onClosed(ABI::Windows::UI::Core::ICoreWindow *, ABI::Windows::UI::Core::ICoreWindowEventArgs *);
HRESULT onVisibilityChanged(ABI::Windows::UI::Core::ICoreWindow *, ABI::Windows::UI::Core::IVisibilityChangedEventArgs *);
HRESULT onAutomationProviderRequested(ABI::Windows::UI::Core::ICoreWindow *, ABI::Windows::UI::Core::IAutomationProviderRequestedEventArgs *);
HRESULT onOrientationChanged(ABI::Windows::Graphics::Display::IDisplayInformation *, IInspectable *);
HRESULT onDpiChanged(ABI::Windows::Graphics::Display::IDisplayInformation *, IInspectable *);
#ifdef Q_OS_WINPHONE
HRESULT onBackButtonPressed(IInspectable *, ABI::Windows::Phone::UI::Input::IBackPressedEventArgs *args);
#endif
QScopedPointer<QWinRTScreenPrivate> d_ptr;
Q_DECLARE_PRIVATE(QWinRTScreen)
};

View File

@ -36,47 +36,138 @@
#include "qwinrtwindow.h"
#include "qwinrtscreen.h"
#include <private/qeventdispatcher_winrt_p.h>
#include <qpa/qwindowsysteminterface.h>
#include <qpa/qplatformscreen.h>
#include <QtGui/QGuiApplication>
#include <QtGui/QWindow>
#include <QtGui/QOpenGLContext>
#include <EGL/egl.h>
#define EGL_EGLEXT_PROTOTYPES
#include <EGL/eglext.h>
#include <qfunctions_winrt.h>
#include <windows.ui.viewmanagement.h>
#include <qpa/qplatformscreen.h>
#include <qpa/qwindowsysteminterface.h>
#include <QtGui/QGuiApplication>
#include <QtGui/QOpenGLContext>
#include <QtGui/QWindow>
#include <QtPlatformSupport/private/qeglconvenience_p.h>
#include <functional>
#include <wrl.h>
#include <windows.foundation.h>
#include <windows.foundation.collections.h>
#include <windows.ui.xaml.h>
#include <windows.ui.xaml.controls.h>
#include <windows.ui.viewmanagement.h>
using namespace ABI::Windows::UI::ViewManagement;
using namespace Microsoft::WRL;
using namespace Microsoft::WRL::Wrappers;
using namespace ABI::Windows::Foundation;
using namespace ABI::Windows::Foundation::Collections;
using namespace ABI::Windows::UI;
QT_BEGIN_NAMESPACE
class QWinRTWindowPrivate
{
public:
QWinRTScreen *screen;
QSurfaceFormat surfaceFormat;
QString windowTitle;
ComPtr<Xaml::Controls::ISwapChainPanel> swapChainPanel;
};
QWinRTWindow::QWinRTWindow(QWindow *window)
: QPlatformWindow(window)
, m_screen(static_cast<QWinRTScreen*>(screen()))
, d_ptr(new QWinRTWindowPrivate)
{
Q_D(QWinRTWindow);
d->screen = static_cast<QWinRTScreen *>(screen());
setWindowFlags(window->flags());
setWindowState(window->windowState());
setWindowTitle(window->title());
handleContentOrientationChange(window->contentOrientation());
d->surfaceFormat.setAlphaBufferSize(0);
d->surfaceFormat.setRedBufferSize(8);
d->surfaceFormat.setGreenBufferSize(8);
d->surfaceFormat.setBlueBufferSize(8);
d->surfaceFormat.setDepthBufferSize(24);
d->surfaceFormat.setStencilBufferSize(8);
d->surfaceFormat.setRenderableType(QSurfaceFormat::OpenGLES);
d->surfaceFormat.setSamples(1);
d->surfaceFormat.setSwapBehavior(QSurfaceFormat::DoubleBuffer);
HRESULT hr;
hr = QEventDispatcherWinRT::runOnXamlThread([this, d]() {
// Create a new swapchain and place it inside the canvas
HRESULT hr;
hr = RoActivateInstance(HString::MakeReference(RuntimeClass_Windows_UI_Xaml_Controls_SwapChainPanel).Get(),
&d->swapChainPanel);
Q_ASSERT_SUCCEEDED(hr);
ComPtr<Xaml::IUIElement> uiElement;
hr = d->swapChainPanel.As(&uiElement);
Q_ASSERT_SUCCEEDED(hr);
ComPtr<Xaml::IDependencyObject> canvas = d->screen->canvas();
ComPtr<Xaml::Controls::IPanel> panel;
hr = canvas.As(&panel);
Q_ASSERT_SUCCEEDED(hr);
ComPtr<IVector<Xaml::UIElement *>> children;
hr = panel->get_Children(&children);
Q_ASSERT_SUCCEEDED(hr);
hr = children->Append(uiElement.Get());
Q_ASSERT_SUCCEEDED(hr);
return S_OK;
});
Q_ASSERT_SUCCEEDED(hr);
setGeometry(window->geometry());
}
QWinRTWindow::~QWinRTWindow()
{
m_screen->removeWindow(window());
Q_D(QWinRTWindow);
HRESULT hr;
hr = QEventDispatcherWinRT::runOnXamlThread([d]() {
HRESULT hr;
ComPtr<Xaml::IDependencyObject> canvas = d->screen->canvas();
ComPtr<Xaml::Controls::IPanel> panel;
hr = canvas.As(&panel);
Q_ASSERT_SUCCEEDED(hr);
ComPtr<IVector<Xaml::UIElement *>> children;
hr = panel->get_Children(&children);
Q_ASSERT_SUCCEEDED(hr);
ComPtr<Xaml::IUIElement> uiElement;
hr = d->swapChainPanel.As(&uiElement);
Q_ASSERT_SUCCEEDED(hr);
quint32 index;
boolean found;
hr = children->IndexOf(uiElement.Get(), &index, &found);
Q_ASSERT_SUCCEEDED(hr);
if (found) {
hr = children->RemoveAt(index);
Q_ASSERT_SUCCEEDED(hr);
}
return S_OK;
});
RETURN_VOID_IF_FAILED("Failed to completely destroy window resources, likely because the application is shutting down");
}
QSurfaceFormat QWinRTWindow::format() const
{
return m_screen->surfaceFormat();
Q_D(const QWinRTWindow);
return d->surfaceFormat;
}
bool QWinRTWindow::isActive() const
{
return m_screen->topWindow() == window();
Q_D(const QWinRTWindow);
return d->screen->topWindow() == window();
}
bool QWinRTWindow::isExposed() const
@ -87,55 +178,70 @@ bool QWinRTWindow::isExposed() const
void QWinRTWindow::setGeometry(const QRect &rect)
{
Q_D(QWinRTWindow);
if (window()->isTopLevel()) {
QPlatformWindow::setGeometry(m_screen->geometry());
QPlatformWindow::setGeometry(d->screen->geometry());
QWindowSystemInterface::handleGeometryChange(window(), geometry());
} else {
QPlatformWindow::setGeometry(rect);
QWindowSystemInterface::handleGeometryChange(window(), rect);
}
HRESULT hr;
hr = QEventDispatcherWinRT::runOnXamlThread([this, d]() {
HRESULT hr;
ComPtr<Xaml::IFrameworkElement> frameworkElement;
hr = d->swapChainPanel.As(&frameworkElement);
Q_ASSERT_SUCCEEDED(hr);
const QSizeF size = QSizeF(geometry().size()) / d->screen->scaleFactor();
hr = frameworkElement->put_Width(size.width());
Q_ASSERT_SUCCEEDED(hr);
hr = frameworkElement->put_Height(size.height());
Q_ASSERT_SUCCEEDED(hr);
return S_OK;
});
Q_ASSERT_SUCCEEDED(hr);
}
void QWinRTWindow::setVisible(bool visible)
{
Q_D(QWinRTWindow);
if (!window()->isTopLevel())
return;
if (visible)
m_screen->addWindow(window());
d->screen->addWindow(window());
else
m_screen->removeWindow(window());
d->screen->removeWindow(window());
}
void QWinRTWindow::setWindowTitle(const QString &title)
{
ComPtr<IApplicationViewStatics2> statics;
HRESULT hr;
hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_UI_ViewManagement_ApplicationView).Get(),
IID_PPV_ARGS(&statics));
RETURN_VOID_IF_FAILED("Could not get ApplicationViewStatics");
ComPtr<IApplicationView> view;
hr = statics->GetForCurrentView(&view);
RETURN_VOID_IF_FAILED("Could not access currentView");
HStringReference str(reinterpret_cast<LPCWSTR>(title.utf16()), title.length());
hr = view->put_Title(str.Get());
RETURN_VOID_IF_FAILED("Unable to set window title");
Q_D(QWinRTWindow);
d->windowTitle = title;
d->screen->updateWindowTitle();
}
void QWinRTWindow::raise()
{
Q_D(QWinRTWindow);
if (!window()->isTopLevel())
return;
m_screen->raise(window());
d->screen->raise(window());
}
void QWinRTWindow::lower()
{
Q_D(QWinRTWindow);
if (!window()->isTopLevel())
return;
m_screen->lower(window());
d->screen->lower(window());
}
WId QWinRTWindow::winId() const
{
Q_D(const QWinRTWindow);
return WId(d->swapChainPanel.Get());
}
qreal QWinRTWindow::devicePixelRatio() const

View File

@ -42,8 +42,7 @@
QT_BEGIN_NAMESPACE
class QWinRTScreen;
class QWinRTWindowPrivate;
class QWinRTWindow : public QPlatformWindow
{
public:
@ -59,10 +58,13 @@ public:
void raise();
void lower();
WId winId() const Q_DECL_OVERRIDE;
qreal devicePixelRatio() const Q_DECL_OVERRIDE;
private:
QWinRTScreen *m_screen;
QScopedPointer<QWinRTWindowPrivate> d_ptr;
Q_DECLARE_PRIVATE(QWinRTWindow)
};
QT_END_NAMESPACE