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
parent
ebc2b963aa
commit
807ec8ea48
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 *,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Reference in New Issue