diff options
Diffstat (limited to 'src/plugins/platforms/winrt')
23 files changed, 2393 insertions, 1094 deletions
diff --git a/src/plugins/platforms/winrt/blit.hlsl b/src/plugins/platforms/winrt/blit.hlsl deleted file mode 100644 index 170e7f40ca..0000000000 --- a/src/plugins/platforms/winrt/blit.hlsl +++ /dev/null @@ -1,14 +0,0 @@ -uniform SamplerState Sampler : register(s0); -uniform Texture2D Texture : register(t0); - -void blitvs(in float4 pos0 : TEXCOORD0, in float2 tex0 : TEXCOORD1, - out float4 gl_Position : SV_POSITION, out float2 coord : TEXCOORD0) -{ - coord = tex0; - gl_Position = pos0 * float4(1.0, -1.0, 1.0, 1.0); -} - -float4 blitps(in float4 gl_Position : SV_POSITION, in float2 coord : TEXCOORD0) : SV_TARGET0 -{ - return Texture.Sample(Sampler, coord); -} diff --git a/src/plugins/platforms/winrt/qwinrtbackingstore.cpp b/src/plugins/platforms/winrt/qwinrtbackingstore.cpp index b8418eef6a..8513e872e2 100644 --- a/src/plugins/platforms/winrt/qwinrtbackingstore.cpp +++ b/src/plugins/platforms/winrt/qwinrtbackingstore.cpp @@ -45,343 +45,136 @@ #include "qwinrtwindow.h" #include "qwinrteglcontext.h" #include <QtGui/QOpenGLContext> +#include <QtGui/QOpenGLFramebufferObject> -#include <GLES2/gl2.h> -#include <GLES2/gl2ext.h> +#include <GLES3/gl3.h> +#include <GLES3/gl3ext.h> -// Generated shader headers -#include "blitps.h" -#include "blitvs.h" - -namespace { // Utility namespace for writing out an ANGLE-compatible binary blob - -// Must match packaged ANGLE -enum : quint32 { - AngleMajorVersion = 1, - AngleMinorVersion = 3 -}; - -struct ShaderString -{ - ShaderString(const char *data = 0) : data(data) { } - const char *data; -}; - -// ANGLE stream compatibility - when size_t is 32-bit, QDataStream::writeBytes() also works -QDataStream &operator<<(QDataStream &stream, const ShaderString &shaderString) -{ - if (!shaderString.data) - return stream << size_t(0); - - size_t len = strlen(shaderString.data); - stream << len; - stream.writeRawData(shaderString.data, int(len)); - return stream; -} - -struct Attribute -{ - Attribute(GLenum type = 0, const char *name = 0, quint32 index = 0) - : type(type), name(name), index(index) { } - GLenum type; - ShaderString name; - quint32 index; -}; - -struct Sampler -{ - enum TextureType { Texture2D, TextureCube }; - Sampler(bool active = false, GLint unit = 0, TextureType type = Texture2D) - : active(active), unit(unit), type(type) { } - bool active; - GLint unit; - TextureType type; -}; - -struct Uniform -{ - Uniform() { } - Uniform(GLenum type, quint32 precision, const char *name, quint32 arraySize, - quint32 psRegisterIndex, quint32 vsRegisterIndex, quint32 registerCount) - : type(type), precision(precision), name(name), arraySize(arraySize) - , psRegisterIndex(psRegisterIndex), vsRegisterIndex(vsRegisterIndex), registerCount(registerCount) { } - GLenum type; - quint32 precision; - ShaderString name; - quint32 arraySize; - quint32 psRegisterIndex; - quint32 vsRegisterIndex; - quint32 registerCount; -}; +QT_BEGIN_NAMESPACE -struct UniformIndex +class QWinRTBackingStorePrivate { - UniformIndex(const char *name = 0, quint32 element = 0, quint32 index = 0) - : name(name), element(element), index(index) { } - ShaderString name; - quint32 element; - quint32 index; +public: + bool initialized; + QSize size; + QScopedPointer<QOpenGLContext> context; + QScopedPointer<QOpenGLFramebufferObject> fbo; + QWinRTScreen *screen; + QImage paintDevice; }; -static const QByteArray createAngleBinary( - const QVector<Attribute> &attributes, - const QVector<Sampler> &textureSamplers, - const QVector<Sampler> &vertexSamplers, - const QVector<Uniform> &uniforms, - const QVector<UniformIndex> &uniformIndex, - const QByteArray &pixelShader, - const QByteArray &vertexShader, - const QByteArray &geometryShader = QByteArray(), - bool usesPointSize = false) +QWinRTBackingStore::QWinRTBackingStore(QWindow *window) + : QPlatformBackingStore(window), d_ptr(new QWinRTBackingStorePrivate) { - QByteArray binary; - - QDataStream stream(&binary, QIODevice::WriteOnly); - stream.setByteOrder(QDataStream::LittleEndian); - - stream << quint32(GL_PROGRAM_BINARY_ANGLE) - << qint32(AngleMajorVersion) - << qint32(AngleMinorVersion); - - // Vertex attributes - for (int i = 0; i < 16; ++i) { - if (i < attributes.size()) - stream << quint32(attributes[i].type) << attributes[i].name << attributes[i].index; - else - stream << quint32(GL_NONE) << ShaderString() << qint32(-1); - } - - // Texture units - for (int i = 0; i < 16; ++i) { - if (i < textureSamplers.size()) - stream << textureSamplers[i].active << textureSamplers[i].unit << qint32(textureSamplers[i].type); - else - stream << false << qint32(0) << qint32(Sampler::Texture2D); - } - - // Vertex texture units - for (int i = 0; i < 16; ++i) { - if (i < vertexSamplers.size()) - stream << vertexSamplers[i].active << vertexSamplers[i].unit << qint32(vertexSamplers[i].type); - else - stream << false << qint32(0) << qint32(Sampler::Texture2D); - } - - stream << vertexSamplers.size() - << textureSamplers.size() - << usesPointSize; - - stream << size_t(uniforms.size()); - foreach (const Uniform &uniform, uniforms) { - stream << uniform.type << uniform.precision << uniform.name << uniform.arraySize - << uniform.psRegisterIndex << uniform.vsRegisterIndex << uniform.registerCount; - } - - stream << size_t(uniformIndex.size()); - foreach (const UniformIndex &index, uniformIndex) - stream << index.name << index.element << index.index; - - stream << quint32(pixelShader.size()) - << quint32(vertexShader.size()) - << quint32(geometryShader.size()); - - stream.writeRawData(pixelShader.constData(), pixelShader.size()); - stream.writeRawData(vertexShader.constData(), vertexShader.size()); - if (!geometryShader.isEmpty()) - stream.writeRawData(geometryShader.constData(), geometryShader.size()); - - return binary; -} - -} // namespace - -QT_BEGIN_NAMESPACE + Q_D(QWinRTBackingStore); -static const GLfloat normCoords[] = { -1, 1, 1, 1, 1, -1, -1, -1 }; -static const GLfloat quadCoords[] = { 0, 0, 1, 0, 1, 1, 0, 1 }; + d->initialized = false; + d->screen = static_cast<QWinRTScreen*>(window->screen()->handle()); -QWinRTBackingStore::QWinRTBackingStore(QWindow *window) - : QPlatformBackingStore(window) - , m_context(new QOpenGLContext) - , m_shaderProgram(0) - , m_fbo(0) - , m_texture(0) - , m_screen(static_cast<QWinRTScreen*>(window->screen()->handle())) - , m_initialized(false) -{ window->setSurfaceType(QSurface::OpenGLSurface); // Required for flipping, but could be done in the swap } bool QWinRTBackingStore::initialize() { - if (m_initialized) + Q_D(QWinRTBackingStore); + + if (d->initialized) return true; - m_context->setFormat(window()->requestedFormat()); - m_context->setScreen(window()->screen()); - if (!m_context->create()) + d->context.reset(new QOpenGLContext); + QSurfaceFormat format = window()->requestedFormat(); + format.setVersion(3, 0); // Required for ES3 framebuffer blit + d->context->setFormat(format); + d->context->setScreen(window()->screen()); + if (!d->context->create()) return false; - if (!m_context->makeCurrent(window())) + if (!d->context->makeCurrent(window())) return false; - glGenFramebuffers(1, &m_fbo); - glGenRenderbuffers(1, &m_rbo); - glGenTextures(1, &m_texture); - m_shaderProgram = glCreateProgram(); - -#if 0 // Standard GLES passthrough shader program - static const char *vertexShaderSource = - "attribute vec4 pos0;\n" - "attribute vec2 tex0;\n" - "varying vec2 coord;\n" - "void main() {\n" - " coord = tex0;\n" - " gl_Position = pos0;\n" - "}\n"; - static const char *fragmentShaderSource = - "uniform sampler2D texture;\n" - "varying highp vec2 coord;\n" - "void main() {\n" - " gl_FragColor = texture2D(texture, coord);\n" - "}\n"; - GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER); - glShaderSource(vertexShader, 1, &vertexShaderSource, NULL); - glCompileShader(vertexShader); - GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER); - glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL); - glCompileShader(fragmentShader); - glAttachShader(m_shaderProgram, vertexShader); - glAttachShader(m_shaderProgram, fragmentShader); - glLinkProgram(m_shaderProgram); -#else // Precompiled passthrough shader - QVector<Attribute> attributes = QVector<Attribute>() << Attribute(GL_FLOAT_VEC4, "pos0", 0) - << Attribute(GL_FLOAT_VEC2, "tex0", 1); - QVector<Sampler> textureSamplers = QVector<Sampler>() << Sampler(true, 0, Sampler::Texture2D); - QVector<Sampler> vertexSamplers; - QVector<Uniform> uniforms = QVector<Uniform>() << Uniform(GL_SAMPLER_2D, 0, "texture", 0, 0, -1, 1); - QVector<UniformIndex> uniformsIndex = QVector<UniformIndex>() << UniformIndex("texture", 0, 0); - QByteArray pixelShader(reinterpret_cast<const char *>(q_blitps), sizeof(q_blitps)); - QByteArray vertexShader(reinterpret_cast<const char *>(q_blitvs), sizeof(q_blitvs)); - QByteArray binary = createAngleBinary(attributes, textureSamplers, vertexSamplers, - uniforms, uniformsIndex, pixelShader, vertexShader); - glProgramBinaryOES(m_shaderProgram, GL_PROGRAM_BINARY_ANGLE, binary.constData(), binary.size()); -#endif - m_context->doneCurrent(); - m_initialized = true; + d->context->doneCurrent(); + d->initialized = true; return true; } QWinRTBackingStore::~QWinRTBackingStore() { - if (!m_initialized) - return; - glDeleteBuffers(1, &m_fbo); - glDeleteRenderbuffers(1, &m_rbo); - glDeleteTextures(1, &m_texture); - glDeleteProgram(m_shaderProgram); } QPaintDevice *QWinRTBackingStore::paintDevice() { - return &m_paintDevice; + Q_D(QWinRTBackingStore); + return &d->paintDevice; } void QWinRTBackingStore::flush(QWindow *window, const QRegion ®ion, const QPoint &offset) { + Q_D(QWinRTBackingStore); Q_UNUSED(offset) - if (m_size.isEmpty()) + + if (d->size.isEmpty()) return; - m_context->makeCurrent(window); - - // Blitting the entire image width trades zero image copy/relayout for a larger texture upload. - // Since we're blitting the whole width anyway, the boundingRect() is used in the assumption that - // we don't repeat upload. This is of course dependent on the distance between update regions. - // Ideally, we would use the GL_EXT_unpack_subimage extension, which should be possible to implement - // since D3D11_MAPPED_SUBRESOURCE supports RowPitch (see below). - // Note that single-line blits in a loop are *very* slow, so reducing calls to glTexSubImage2D - // is probably a good idea anyway. - glBindTexture(GL_TEXTURE_2D, m_texture); - QRect bounds = region.boundingRect(); - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, bounds.y(), m_size.width(), bounds.height(), - GL_BGRA_EXT, GL_UNSIGNED_BYTE, m_paintDevice.constScanLine(bounds.y())); - // TODO: Implement GL_EXT_unpack_subimage in ANGLE for more minimal uploads - //glPixelStorei(GL_UNPACK_ROW_LENGTH, image->bytesPerLine()); - //glTexSubImage2D(GL_TEXTURE_2D, 0, bounds.x(), bounds.y(), bounds.width(), bounds.height(), - // GL_BGRA_EXT, GL_UNSIGNED_BYTE, image->scanLine(bounds.y()) + bounds.x() * 4); - - // Bind render buffer - glBindFramebuffer(GL_FRAMEBUFFER, m_fbo); - glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, m_rbo); - - // Bind position - glUseProgram(m_shaderProgram); - glEnableVertexAttribArray(0); - glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, normCoords); - glEnableVertexAttribArray(1); - glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, quadCoords); - - // Render - const QSize blitSize = m_size * window->devicePixelRatio(); - glViewport(0, 0, blitSize.width(), blitSize.height()); - glDrawArrays(GL_TRIANGLE_FAN, 0, 4); - - // Unbind - glDisableVertexAttribArray(0); - glDisableVertexAttribArray(1); - glUseProgram(0); - glBindFramebuffer(GL_FRAMEBUFFER, 0); - glBindTexture(GL_TEXTURE_2D, 0); + const bool ok = d->context->makeCurrent(window); + if (!ok) + qWarning("unable to flush"); - // fast blit - TODO: perform the blit inside swap buffers instead - glBindFramebuffer(GL_READ_FRAMEBUFFER_ANGLE, m_fbo); - glBindFramebuffer(GL_DRAW_FRAMEBUFFER_ANGLE, 0); - glBlitFramebufferANGLE(0, 0, blitSize.width(), blitSize.height(), // TODO: blit only the changed rectangle - 0, 0, blitSize.width(), blitSize.height(), - GL_COLOR_BUFFER_BIT, GL_NEAREST); + const QRect bounds = region.boundingRect(); + glBindTexture(GL_TEXTURE_2D, d->fbo->texture()); + // TODO: when ANGLE GLES3 support is finished, use the glPixelStorei functions to minimize upload + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, bounds.y(), d->size.width(), bounds.height(), + GL_RGBA, GL_UNSIGNED_BYTE, d->paintDevice.constScanLine(bounds.y())); + glBindTexture(GL_TEXTURE_2D, 0); - m_context->swapBuffers(window); - m_context->doneCurrent(); + glBindFramebuffer(GL_READ_FRAMEBUFFER, d->fbo->handle()); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); + const int y1 = bounds.y(); + const int y2 = y1 + bounds.height(); + const int x1 = bounds.x(); + const int x2 = x1 + bounds.width(); + glBlitFramebuffer(x1, y1, x2, y2, + x1, d->size.height() - y1, x2, d->size.height() - y2, + GL_COLOR_BUFFER_BIT, GL_NEAREST); + + d->context->swapBuffers(window); + d->context->doneCurrent(); } void QWinRTBackingStore::resize(const QSize &size, const QRegion &staticContents) { + Q_D(QWinRTBackingStore); Q_UNUSED(staticContents) + if (!initialize()) return; - if (m_size == size) + if (d->size == size) return; - m_size = size; - if (m_size.isEmpty()) + d->size = size; + if (d->size.isEmpty()) return; - m_paintDevice = QImage(m_size, QImage::Format_ARGB32_Premultiplied); - - m_context->makeCurrent(window()); - // Input texture - glBindTexture(GL_TEXTURE_2D, m_texture); - glTexImage2D(GL_TEXTURE_2D, 0, GL_BGRA_EXT, m_size.width(), m_size.height(), - 0, GL_BGRA_EXT, GL_UNSIGNED_BYTE, NULL); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glBindTexture(GL_TEXTURE_2D, 0); - // Render buffer - glBindRenderbuffer(GL_RENDERBUFFER, m_rbo); - const QSize blitSize = m_size * window()->devicePixelRatio(); - glRenderbufferStorage(GL_RENDERBUFFER, GL_BGRA8_EXT, blitSize.width(), blitSize.height()); - glBindRenderbuffer(GL_RENDERBUFFER, 0); - m_context->doneCurrent(); + d->paintDevice = QImage(d->size, QImage::Format_RGBA8888_Premultiplied); + + const bool ok = d->context->makeCurrent(window()); + if (!ok) + qWarning("unable to resize"); + + d->fbo.reset(new QOpenGLFramebufferObject(d->size)); + + d->context->doneCurrent(); +} + +QImage QWinRTBackingStore::toImage() const +{ + Q_D(const QWinRTBackingStore); + return d->paintDevice; } void QWinRTBackingStore::beginPaint(const QRegion ®ion) { - Q_UNUSED(region) - resize(window()->size(), QRegion()); + resize(window()->size(), region); } void QWinRTBackingStore::endPaint() diff --git a/src/plugins/platforms/winrt/qwinrtbackingstore.h b/src/plugins/platforms/winrt/qwinrtbackingstore.h index f00fa85a26..40728559f7 100644 --- a/src/plugins/platforms/winrt/qwinrtbackingstore.h +++ b/src/plugins/platforms/winrt/qwinrtbackingstore.h @@ -48,8 +48,8 @@ QT_BEGIN_NAMESPACE class QWinRTScreen; -class QOpenGLContext; +class QWinRTBackingStorePrivate; class QWinRTBackingStore : public QPlatformBackingStore { public: @@ -60,19 +60,13 @@ public: void endPaint(); void flush(QWindow *window, const QRegion ®ion, const QPoint &offset); void resize(const QSize &size, const QRegion &staticContents); - QImage toImage() const Q_DECL_OVERRIDE { return m_paintDevice; } + QImage toImage() const Q_DECL_OVERRIDE; private: bool initialize(); - bool m_initialized; - QSize m_size; - QScopedPointer<QOpenGLContext> m_context; - quint32 m_shaderProgram; - quint32 m_fbo; - quint32 m_rbo; - quint32 m_texture; - QWinRTScreen *m_screen; - QImage m_paintDevice; + + QScopedPointer<QWinRTBackingStorePrivate> d_ptr; + Q_DECLARE_PRIVATE(QWinRTBackingStore) }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/winrt/qwinrtcursor.cpp b/src/plugins/platforms/winrt/qwinrtcursor.cpp index f09454ebc3..d2d87bde0b 100644 --- a/src/plugins/platforms/winrt/qwinrtcursor.cpp +++ b/src/plugins/platforms/winrt/qwinrtcursor.cpp @@ -40,40 +40,54 @@ ****************************************************************************/ #include "qwinrtcursor.h" +#include "qwinrtscreen.h" + +#include <QtCore/qfunctions_winrt.h> +#include <QtGui/QGuiApplication> +#include <QtGui/QScreen> #include <wrl.h> #include <windows.ui.core.h> #include <windows.foundation.h> +using namespace Microsoft::WRL; using namespace Microsoft::WRL::Wrappers; using namespace ABI::Windows::UI::Core; using namespace ABI::Windows::Foundation; -QT_BEGIN_NAMESPACE +QT_USE_NAMESPACE + +class QWinRTCursorPrivate +{ +public: + ComPtr<ICoreCursorFactory> cursorFactory; +}; -QWinRTCursor::QWinRTCursor(ICoreWindow *window) : m_window(window), m_cursorFactory(nullptr) +QWinRTCursor::QWinRTCursor() + : d_ptr(new QWinRTCursorPrivate) { -#ifndef Q_OS_WINPHONE - GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_UI_Core_CoreCursor).Get(), &m_cursorFactory); -#endif + Q_D(QWinRTCursor); + + HRESULT hr; + hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_UI_Core_CoreCursor).Get(), + IID_PPV_ARGS(&d->cursorFactory)); + Q_ASSERT_SUCCEEDED(hr); } QWinRTCursor::~QWinRTCursor() { - if (m_cursorFactory) - m_cursorFactory->Release(); } #ifndef QT_NO_CURSOR -void QWinRTCursor::changeCursor(QCursor *windowCursor, QWindow *) +void QWinRTCursor::changeCursor(QCursor *windowCursor, QWindow *window) { -#ifndef Q_OS_WINPHONE - if (!m_cursorFactory) - return; + Q_D(QWinRTCursor); + + ICoreWindow *coreWindow = static_cast<QWinRTScreen *>(window->screen()->handle())->coreWindow(); CoreCursorType type; switch (windowCursor ? windowCursor->shape() : Qt::ArrowCursor) { case Qt::BlankCursor: - m_window->put_PointerCursor(nullptr); + coreWindow->put_PointerCursor(Q_NULLPTR); return; default: case Qt::OpenHandCursor: @@ -132,24 +146,20 @@ void QWinRTCursor::changeCursor(QCursor *windowCursor, QWindow *) break; } - ICoreCursor *cursor; - if (SUCCEEDED(m_cursorFactory->CreateCursor(type, 0, &cursor))) - m_window->put_PointerCursor(cursor); -#else // Q_OS_WINPHONE - Q_UNUSED(windowCursor) -#endif // Q_OS_WINPHONE + ComPtr<ICoreCursor> cursor; + HRESULT 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."); } #endif // QT_NO_CURSOR QPoint QWinRTCursor::pos() const { -#ifdef Q_OS_WINPHONE - return QPlatformCursor::pos(); -#else + ICoreWindow *coreWindow = + static_cast<QWinRTScreen *>(QGuiApplication::primaryScreen()->handle())->coreWindow(); Point point; - m_window->get_PointerPosition(&point); + coreWindow->get_PointerPosition(&point); return QPoint(point.X, point.Y); -#endif } - -QT_END_NAMESPACE diff --git a/src/plugins/platforms/winrt/qwinrtcursor.h b/src/plugins/platforms/winrt/qwinrtcursor.h index f7b301a98b..a08002f34c 100644 --- a/src/plugins/platforms/winrt/qwinrtcursor.h +++ b/src/plugins/platforms/winrt/qwinrtcursor.h @@ -44,34 +44,22 @@ #include <qpa/qplatformcursor.h> -namespace ABI { - namespace Windows { - namespace UI { - namespace Core { - struct ICoreWindow; - struct ICoreCursorFactory; - } - } - } -} - -QT_BEGIN_NAMESPACE +QT_USE_NAMESPACE +class QWinRTCursorPrivate; class QWinRTCursor : public QPlatformCursor { public: - explicit QWinRTCursor(ABI::Windows::UI::Core::ICoreWindow *window); + explicit QWinRTCursor(); ~QWinRTCursor(); #ifndef QT_NO_CURSOR - void changeCursor(QCursor * windowCursor, QWindow *); + void changeCursor(QCursor * windowCursor, QWindow *window); #endif QPoint pos() const; private: - ABI::Windows::UI::Core::ICoreWindow *m_window; - ABI::Windows::UI::Core::ICoreCursorFactory *m_cursorFactory; + QScopedPointer<QWinRTCursorPrivate> d_ptr; + Q_DECLARE_PRIVATE(QWinRTCursor) }; -QT_END_NAMESPACE - #endif // QWINRTCURSOR_H diff --git a/src/plugins/platforms/winrt/qwinrteglcontext.cpp b/src/plugins/platforms/winrt/qwinrteglcontext.cpp index 3a1958a20e..9e77a1a88a 100644 --- a/src/plugins/platforms/winrt/qwinrteglcontext.cpp +++ b/src/plugins/platforms/winrt/qwinrteglcontext.cpp @@ -60,4 +60,159 @@ EGLSurface QWinRTEGLContext::eglSurfaceForPlatformSurface(QPlatformSurface *surf } } +QFunctionPointer QWinRTEGLContext::getProcAddress(const QByteArray &procName) +{ + static QHash<QByteArray, QFunctionPointer> standardFuncs; + if (standardFuncs.isEmpty()) { + standardFuncs.insert(QByteArrayLiteral("glBindTexture"), (QFunctionPointer)&glBindTexture); + standardFuncs.insert(QByteArrayLiteral("glBlendFunc"), (QFunctionPointer)&glBlendFunc); + standardFuncs.insert(QByteArrayLiteral("glClear"), (QFunctionPointer)&glClear); + standardFuncs.insert(QByteArrayLiteral("glClearColor"), (QFunctionPointer)&glClearColor); + standardFuncs.insert(QByteArrayLiteral("glClearStencil"), (QFunctionPointer)&glClearStencil); + standardFuncs.insert(QByteArrayLiteral("glColorMask"), (QFunctionPointer)&glColorMask); + standardFuncs.insert(QByteArrayLiteral("glCopyTexImage2D"), (QFunctionPointer)&glCopyTexImage2D); + standardFuncs.insert(QByteArrayLiteral("glCopyTexSubImage2D"), (QFunctionPointer)&glCopyTexSubImage2D); + standardFuncs.insert(QByteArrayLiteral("glCullFace"), (QFunctionPointer)&glCullFace); + standardFuncs.insert(QByteArrayLiteral("glDeleteTextures"), (QFunctionPointer)&glDeleteTextures); + standardFuncs.insert(QByteArrayLiteral("glDepthFunc"), (QFunctionPointer)&glDepthFunc); + standardFuncs.insert(QByteArrayLiteral("glDepthMask"), (QFunctionPointer)&glDepthMask); + standardFuncs.insert(QByteArrayLiteral("glDisable"), (QFunctionPointer)&glDisable); + standardFuncs.insert(QByteArrayLiteral("glDrawArrays"), (QFunctionPointer)&glDrawArrays); + standardFuncs.insert(QByteArrayLiteral("glDrawElements"), (QFunctionPointer)&glDrawElements); + standardFuncs.insert(QByteArrayLiteral("glEnable"), (QFunctionPointer)&glEnable); + standardFuncs.insert(QByteArrayLiteral("glFinish"), (QFunctionPointer)&glFinish); + standardFuncs.insert(QByteArrayLiteral("glFlush"), (QFunctionPointer)&glFlush); + standardFuncs.insert(QByteArrayLiteral("glFrontFace"), (QFunctionPointer)&glFrontFace); + standardFuncs.insert(QByteArrayLiteral("glGenTextures"), (QFunctionPointer)&glGenTextures); + standardFuncs.insert(QByteArrayLiteral("glGetBooleanv"), (QFunctionPointer)&glGetBooleanv); + standardFuncs.insert(QByteArrayLiteral("glGetError"), (QFunctionPointer)&glGetError); + standardFuncs.insert(QByteArrayLiteral("glGetFloatv"), (QFunctionPointer)&glGetFloatv); + standardFuncs.insert(QByteArrayLiteral("glGetIntegerv"), (QFunctionPointer)&glGetIntegerv); + standardFuncs.insert(QByteArrayLiteral("glGetString"), (QFunctionPointer)&glGetString); + standardFuncs.insert(QByteArrayLiteral("glGetTexParameterfv"), (QFunctionPointer)&glGetTexParameterfv); + standardFuncs.insert(QByteArrayLiteral("glGetTexParameteriv"), (QFunctionPointer)&glGetTexParameteriv); + standardFuncs.insert(QByteArrayLiteral("glHint"), (QFunctionPointer)&glHint); + standardFuncs.insert(QByteArrayLiteral("glIsEnabled"), (QFunctionPointer)&glIsEnabled); + standardFuncs.insert(QByteArrayLiteral("glIsTexture"), (QFunctionPointer)&glIsTexture); + standardFuncs.insert(QByteArrayLiteral("glLineWidth"), (QFunctionPointer)&glLineWidth); + standardFuncs.insert(QByteArrayLiteral("glPixelStorei"), (QFunctionPointer)&glPixelStorei); + standardFuncs.insert(QByteArrayLiteral("glPolygonOffset"), (QFunctionPointer)&glPolygonOffset); + standardFuncs.insert(QByteArrayLiteral("glReadPixels"), (QFunctionPointer)&glReadPixels); + standardFuncs.insert(QByteArrayLiteral("glScissor"), (QFunctionPointer)&glScissor); + standardFuncs.insert(QByteArrayLiteral("glStencilFunc"), (QFunctionPointer)&glStencilFunc); + standardFuncs.insert(QByteArrayLiteral("glStencilMask"), (QFunctionPointer)&glStencilMask); + standardFuncs.insert(QByteArrayLiteral("glStencilOp"), (QFunctionPointer)&glStencilOp); + standardFuncs.insert(QByteArrayLiteral("glTexImage2D"), (QFunctionPointer)&glTexImage2D); + standardFuncs.insert(QByteArrayLiteral("glTexParameterf"), (QFunctionPointer)&glTexParameterf); + standardFuncs.insert(QByteArrayLiteral("glTexParameterfv"), (QFunctionPointer)&glTexParameterfv); + standardFuncs.insert(QByteArrayLiteral("glTexParameteri"), (QFunctionPointer)&glTexParameteri); + standardFuncs.insert(QByteArrayLiteral("glTexParameteriv"), (QFunctionPointer)&glTexParameteriv); + standardFuncs.insert(QByteArrayLiteral("glTexSubImage2D"), (QFunctionPointer)&glTexSubImage2D); + standardFuncs.insert(QByteArrayLiteral("glViewport"), (QFunctionPointer)&glViewport); + standardFuncs.insert(QByteArrayLiteral("glActiveTexture"), (QFunctionPointer)&glActiveTexture); + standardFuncs.insert(QByteArrayLiteral("glAttachShader"), (QFunctionPointer)&glAttachShader); + standardFuncs.insert(QByteArrayLiteral("glBindAttribLocation"), (QFunctionPointer)&glBindAttribLocation); + standardFuncs.insert(QByteArrayLiteral("glBindBuffer"), (QFunctionPointer)&glBindBuffer); + standardFuncs.insert(QByteArrayLiteral("glBindFramebuffer"), (QFunctionPointer)&glBindFramebuffer); + standardFuncs.insert(QByteArrayLiteral("glBindRenderbuffer"), (QFunctionPointer)&glBindRenderbuffer); + standardFuncs.insert(QByteArrayLiteral("glBlendColor"), (QFunctionPointer)&glBlendColor); + standardFuncs.insert(QByteArrayLiteral("glBlendEquation"), (QFunctionPointer)&glBlendEquation); + standardFuncs.insert(QByteArrayLiteral("glBlendEquationSeparate"), (QFunctionPointer)&glBlendEquationSeparate); + standardFuncs.insert(QByteArrayLiteral("glBlendFuncSeparate"), (QFunctionPointer)&glBlendFuncSeparate); + standardFuncs.insert(QByteArrayLiteral("glBufferData"), (QFunctionPointer)&glBufferData); + standardFuncs.insert(QByteArrayLiteral("glBufferSubData"), (QFunctionPointer)&glBufferSubData); + standardFuncs.insert(QByteArrayLiteral("glCheckFramebufferStatus"), (QFunctionPointer)&glCheckFramebufferStatus); + standardFuncs.insert(QByteArrayLiteral("glCompileShader"), (QFunctionPointer)&glCompileShader); + standardFuncs.insert(QByteArrayLiteral("glCompressedTexImage2D"), (QFunctionPointer)&glCompressedTexImage2D); + standardFuncs.insert(QByteArrayLiteral("glCompressedTexSubImage2D"), (QFunctionPointer)&glCompressedTexSubImage2D); + standardFuncs.insert(QByteArrayLiteral("glCreateProgram"), (QFunctionPointer)&glCreateProgram); + standardFuncs.insert(QByteArrayLiteral("glCreateShader"), (QFunctionPointer)&glCreateShader); + standardFuncs.insert(QByteArrayLiteral("glDeleteBuffers"), (QFunctionPointer)&glDeleteBuffers); + standardFuncs.insert(QByteArrayLiteral("glDeleteFramebuffers"), (QFunctionPointer)&glDeleteFramebuffers); + standardFuncs.insert(QByteArrayLiteral("glDeleteProgram"), (QFunctionPointer)&glDeleteProgram); + standardFuncs.insert(QByteArrayLiteral("glDeleteRenderbuffers"), (QFunctionPointer)&glDeleteRenderbuffers); + standardFuncs.insert(QByteArrayLiteral("glDeleteShader"), (QFunctionPointer)&glDeleteShader); + standardFuncs.insert(QByteArrayLiteral("glDetachShader"), (QFunctionPointer)&glDetachShader); + standardFuncs.insert(QByteArrayLiteral("glDisableVertexAttribArray"), (QFunctionPointer)&glDisableVertexAttribArray); + standardFuncs.insert(QByteArrayLiteral("glEnableVertexAttribArray"), (QFunctionPointer)&glEnableVertexAttribArray); + standardFuncs.insert(QByteArrayLiteral("glFramebufferRenderbuffer"), (QFunctionPointer)&glFramebufferRenderbuffer); + standardFuncs.insert(QByteArrayLiteral("glFramebufferTexture2D"), (QFunctionPointer)&glFramebufferTexture2D); + standardFuncs.insert(QByteArrayLiteral("glGenBuffers"), (QFunctionPointer)&glGenBuffers); + standardFuncs.insert(QByteArrayLiteral("glGenerateMipmap"), (QFunctionPointer)&glGenerateMipmap); + standardFuncs.insert(QByteArrayLiteral("glGenFramebuffers"), (QFunctionPointer)&glGenFramebuffers); + standardFuncs.insert(QByteArrayLiteral("glGenRenderbuffers"), (QFunctionPointer)&glGenRenderbuffers); + standardFuncs.insert(QByteArrayLiteral("glGetActiveAttrib"), (QFunctionPointer)&glGetActiveAttrib); + standardFuncs.insert(QByteArrayLiteral("glGetActiveUniform"), (QFunctionPointer)&glGetActiveUniform); + standardFuncs.insert(QByteArrayLiteral("glGetAttachedShaders"), (QFunctionPointer)&glGetAttachedShaders); + standardFuncs.insert(QByteArrayLiteral("glGetAttribLocation"), (QFunctionPointer)&glGetAttribLocation); + standardFuncs.insert(QByteArrayLiteral("glGetBufferParameteriv"), (QFunctionPointer)&glGetBufferParameteriv); + standardFuncs.insert(QByteArrayLiteral("glGetFramebufferAttachmentParameteriv"), (QFunctionPointer)&glGetFramebufferAttachmentParameteriv); + standardFuncs.insert(QByteArrayLiteral("glGetProgramiv"), (QFunctionPointer)&glGetProgramiv); + standardFuncs.insert(QByteArrayLiteral("glGetProgramInfoLog"), (QFunctionPointer)&glGetProgramInfoLog); + standardFuncs.insert(QByteArrayLiteral("glGetRenderbufferParameteriv"), (QFunctionPointer)&glGetRenderbufferParameteriv); + standardFuncs.insert(QByteArrayLiteral("glGetShaderiv"), (QFunctionPointer)&glGetShaderiv); + standardFuncs.insert(QByteArrayLiteral("glGetShaderInfoLog"), (QFunctionPointer)&glGetShaderInfoLog); + standardFuncs.insert(QByteArrayLiteral("glGetShaderPrecisionFormat"), (QFunctionPointer)&glGetShaderPrecisionFormat); + standardFuncs.insert(QByteArrayLiteral("glGetShaderSource"), (QFunctionPointer)&glGetShaderSource); + standardFuncs.insert(QByteArrayLiteral("glGetUniformfv"), (QFunctionPointer)&glGetUniformfv); + standardFuncs.insert(QByteArrayLiteral("glGetUniformiv"), (QFunctionPointer)&glGetUniformiv); + standardFuncs.insert(QByteArrayLiteral("glGetUniformLocation"), (QFunctionPointer)&glGetUniformLocation); + standardFuncs.insert(QByteArrayLiteral("glGetVertexAttribfv"), (QFunctionPointer)&glGetVertexAttribfv); + standardFuncs.insert(QByteArrayLiteral("glGetVertexAttribiv"), (QFunctionPointer)&glGetVertexAttribiv); + standardFuncs.insert(QByteArrayLiteral("glGetVertexAttribPointerv"), (QFunctionPointer)&glGetVertexAttribPointerv); + standardFuncs.insert(QByteArrayLiteral("glIsBuffer"), (QFunctionPointer)&glIsBuffer); + standardFuncs.insert(QByteArrayLiteral("glIsFramebuffer"), (QFunctionPointer)&glIsFramebuffer); + standardFuncs.insert(QByteArrayLiteral("glIsProgram"), (QFunctionPointer)&glIsProgram); + standardFuncs.insert(QByteArrayLiteral("glIsRenderbuffer"), (QFunctionPointer)&glIsRenderbuffer); + standardFuncs.insert(QByteArrayLiteral("glIsShader"), (QFunctionPointer)&glIsShader); + standardFuncs.insert(QByteArrayLiteral("glLinkProgram"), (QFunctionPointer)&glLinkProgram); + standardFuncs.insert(QByteArrayLiteral("glReleaseShaderCompiler"), (QFunctionPointer)&glReleaseShaderCompiler); + standardFuncs.insert(QByteArrayLiteral("glRenderbufferStorage"), (QFunctionPointer)&glRenderbufferStorage); + standardFuncs.insert(QByteArrayLiteral("glSampleCoverage"), (QFunctionPointer)&glSampleCoverage); + standardFuncs.insert(QByteArrayLiteral("glShaderBinary"), (QFunctionPointer)&glShaderBinary); + standardFuncs.insert(QByteArrayLiteral("glShaderSource"), (QFunctionPointer)&glShaderSource); + standardFuncs.insert(QByteArrayLiteral("glStencilFuncSeparate"), (QFunctionPointer)&glStencilFuncSeparate); + standardFuncs.insert(QByteArrayLiteral("glStencilMaskSeparate"), (QFunctionPointer)&glStencilMaskSeparate); + standardFuncs.insert(QByteArrayLiteral("glStencilOpSeparate"), (QFunctionPointer)&glStencilOpSeparate); + standardFuncs.insert(QByteArrayLiteral("glUniform1f"), (QFunctionPointer)&glUniform1f); + standardFuncs.insert(QByteArrayLiteral("glUniform1fv"), (QFunctionPointer)&glUniform1fv); + standardFuncs.insert(QByteArrayLiteral("glUniform1i"), (QFunctionPointer)&glUniform1i); + standardFuncs.insert(QByteArrayLiteral("glUniform1iv"), (QFunctionPointer)&glUniform1iv); + standardFuncs.insert(QByteArrayLiteral("glUniform2f"), (QFunctionPointer)&glUniform2f); + standardFuncs.insert(QByteArrayLiteral("glUniform2fv"), (QFunctionPointer)&glUniform2fv); + standardFuncs.insert(QByteArrayLiteral("glUniform2i"), (QFunctionPointer)&glUniform2i); + standardFuncs.insert(QByteArrayLiteral("glUniform2iv"), (QFunctionPointer)&glUniform2iv); + standardFuncs.insert(QByteArrayLiteral("glUniform3f"), (QFunctionPointer)&glUniform3f); + standardFuncs.insert(QByteArrayLiteral("glUniform3fv"), (QFunctionPointer)&glUniform3fv); + standardFuncs.insert(QByteArrayLiteral("glUniform3i"), (QFunctionPointer)&glUniform3i); + standardFuncs.insert(QByteArrayLiteral("glUniform3iv"), (QFunctionPointer)&glUniform3iv); + standardFuncs.insert(QByteArrayLiteral("glUniform4f"), (QFunctionPointer)&glUniform4f); + standardFuncs.insert(QByteArrayLiteral("glUniform4fv"), (QFunctionPointer)&glUniform4fv); + standardFuncs.insert(QByteArrayLiteral("glUniform4i"), (QFunctionPointer)&glUniform4i); + standardFuncs.insert(QByteArrayLiteral("glUniform4iv"), (QFunctionPointer)&glUniform4iv); + standardFuncs.insert(QByteArrayLiteral("glUniformMatrix2fv"), (QFunctionPointer)&glUniformMatrix2fv); + standardFuncs.insert(QByteArrayLiteral("glUniformMatrix3fv"), (QFunctionPointer)&glUniformMatrix3fv); + standardFuncs.insert(QByteArrayLiteral("glUniformMatrix4fv"), (QFunctionPointer)&glUniformMatrix4fv); + standardFuncs.insert(QByteArrayLiteral("glUseProgram"), (QFunctionPointer)&glUseProgram); + standardFuncs.insert(QByteArrayLiteral("glValidateProgram"), (QFunctionPointer)&glValidateProgram); + standardFuncs.insert(QByteArrayLiteral("glVertexAttrib1f"), (QFunctionPointer)&glVertexAttrib1f); + standardFuncs.insert(QByteArrayLiteral("glVertexAttrib1fv"), (QFunctionPointer)&glVertexAttrib1fv); + standardFuncs.insert(QByteArrayLiteral("glVertexAttrib2f"), (QFunctionPointer)&glVertexAttrib2f); + standardFuncs.insert(QByteArrayLiteral("glVertexAttrib2fv"), (QFunctionPointer)&glVertexAttrib2fv); + standardFuncs.insert(QByteArrayLiteral("glVertexAttrib3f"), (QFunctionPointer)&glVertexAttrib3f); + standardFuncs.insert(QByteArrayLiteral("glVertexAttrib3fv"), (QFunctionPointer)&glVertexAttrib3fv); + standardFuncs.insert(QByteArrayLiteral("glVertexAttrib4f"), (QFunctionPointer)&glVertexAttrib4f); + standardFuncs.insert(QByteArrayLiteral("glVertexAttrib4fv"), (QFunctionPointer)&glVertexAttrib4fv); + standardFuncs.insert(QByteArrayLiteral("glVertexAttribPointer"), (QFunctionPointer)&glVertexAttribPointer); + standardFuncs.insert(QByteArrayLiteral("glClearDepthf"), (QFunctionPointer)&glClearDepthf); + standardFuncs.insert(QByteArrayLiteral("glDepthRangef"), (QFunctionPointer)&glDepthRangef); + }; + + QHash<QByteArray, QFunctionPointer>::const_iterator i = standardFuncs.find(procName); + if (i != standardFuncs.end()) + return i.value(); + + return QEGLPlatformContext::getProcAddress(procName); +} + QT_END_NAMESPACE diff --git a/src/plugins/platforms/winrt/qwinrteglcontext.h b/src/plugins/platforms/winrt/qwinrteglcontext.h index c065847374..6dc8dc6c9f 100644 --- a/src/plugins/platforms/winrt/qwinrteglcontext.h +++ b/src/plugins/platforms/winrt/qwinrteglcontext.h @@ -51,6 +51,8 @@ class QWinRTEGLContext : public QEGLPlatformContext public: explicit QWinRTEGLContext(const QSurfaceFormat &format, QPlatformOpenGLContext *share, EGLDisplay display, EGLSurface surface); + QFunctionPointer getProcAddress(const QByteArray &procName) Q_DECL_OVERRIDE; + protected: EGLSurface eglSurfaceForPlatformSurface(QPlatformSurface *surface); diff --git a/src/plugins/platforms/winrt/qwinrteventdispatcher.cpp b/src/plugins/platforms/winrt/qwinrteventdispatcher.cpp index 98eb83f5eb..2bc8e6602f 100644 --- a/src/plugins/platforms/winrt/qwinrteventdispatcher.cpp +++ b/src/plugins/platforms/winrt/qwinrteventdispatcher.cpp @@ -42,7 +42,6 @@ #include "qwinrteventdispatcher.h" #include <qpa/qwindowsysteminterface.h> #include <qpa/qplatformscreen.h> -#include <qpa/qplatformscreenpageflipper.h> #include <QtCore/QThread> #include <QtGui/QGuiApplication> diff --git a/src/plugins/platforms/winrt/qwinrtfiledialoghelper.cpp b/src/plugins/platforms/winrt/qwinrtfiledialoghelper.cpp new file mode 100644 index 0000000000..768a94e951 --- /dev/null +++ b/src/plugins/platforms/winrt/qwinrtfiledialoghelper.cpp @@ -0,0 +1,512 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qwinrtfiledialoghelper.h" +#include "qwinrtfileengine.h" + +#include <QtCore/QEventLoop> +#include <QtCore/QMap> +#include <QtCore/QVector> +#include <QtCore/qfunctions_winrt.h> + +#include <wrl.h> +#include <windows.foundation.h> +#include <windows.storage.pickers.h> + +using namespace Microsoft::WRL; +using namespace Microsoft::WRL::Wrappers; +using namespace ABI::Windows::Foundation; +using namespace ABI::Windows::Foundation::Collections; +using namespace ABI::Windows::Storage; +using namespace ABI::Windows::Storage::Pickers; + +typedef IAsyncOperationCompletedHandler<StorageFile *> SingleFileHandler; +typedef IAsyncOperationCompletedHandler<IVectorView<StorageFile *> *> MultipleFileHandler; +typedef IAsyncOperationCompletedHandler<StorageFolder *> SingleFolderHandler; + +QT_BEGIN_NAMESPACE + +// Required for save file picker +class WindowsStringVector : public RuntimeClass<IVector<HSTRING>> +{ +public: + HRESULT __stdcall GetAt(quint32 index, HSTRING *item) + { + *item = impl.at(index); + return S_OK; + } + HRESULT __stdcall get_Size(quint32 *size) + { + *size = impl.size(); + return S_OK; + } + HRESULT __stdcall GetView(IVectorView<HSTRING> **view) + { + *view = Q_NULLPTR; + return E_NOTIMPL; + } + HRESULT __stdcall IndexOf(HSTRING value, quint32 *index, boolean *found) + { + *found = false; + for (int i = 0; i < impl.size(); ++i) { + qint32 result; + HRESULT hr = WindowsCompareStringOrdinal(impl.at(i), value, &result); + if (FAILED(hr)) + return hr; + if (result == 0) { + *index = quint32(i); + *found = true; + break; + } + } + return S_OK; + } + HRESULT __stdcall SetAt(quint32 index, HSTRING item) + { + HSTRING newItem; + HRESULT hr = WindowsDuplicateString(item, &newItem); + if (FAILED(hr)) + return hr; + impl[index] = newItem; + return S_OK; + } + HRESULT __stdcall InsertAt(quint32 index, HSTRING item) + { + HSTRING newItem; + HRESULT hr = WindowsDuplicateString(item, &newItem); + if (FAILED(hr)) + return hr; + impl.insert(index, newItem); + return S_OK; + } + HRESULT __stdcall RemoveAt(quint32 index) + { + WindowsDeleteString(impl.takeAt(index)); + return S_OK; + } + HRESULT __stdcall Append(HSTRING item) + { + HSTRING newItem; + HRESULT hr = WindowsDuplicateString(item, &newItem); + if (FAILED(hr)) + return hr; + impl.append(newItem); + return S_OK; + } + HRESULT __stdcall RemoveAtEnd() + { + WindowsDeleteString(impl.takeLast()); + return S_OK; + } + HRESULT __stdcall Clear() + { + foreach (const HSTRING &item, impl) + WindowsDeleteString(item); + impl.clear(); + return S_OK; + } +private: + QVector<HSTRING> impl; +}; + +template<typename T> +static bool initializePicker(HSTRING runtimeId, T **picker, const QSharedPointer<QFileDialogOptions> &options) +{ + HRESULT hr; + + ComPtr<IInspectable> basePicker; + hr = RoActivateInstance(runtimeId, &basePicker); + RETURN_FALSE_IF_FAILED("Failed to instantiate file picker"); + hr = basePicker.Get()->QueryInterface(IID_PPV_ARGS(picker)); + RETURN_FALSE_IF_FAILED("Failed to cast file picker"); + + if (options->isLabelExplicitlySet(QFileDialogOptions::Accept)) { + const QString labelText = options->labelText(QFileDialogOptions::Accept); + HStringReference labelTextRef(reinterpret_cast<const wchar_t *>(labelText.utf16()), + labelText.length()); + hr = (*picker)->put_CommitButtonText(labelTextRef.Get()); + RETURN_FALSE_IF_FAILED("Failed to set commit button text"); + } + + return true; +} + +template<typename T> +static bool initializeOpenPickerOptions(T *picker, const QSharedPointer<QFileDialogOptions> &options) +{ + HRESULT hr; + hr = picker->put_ViewMode(options->viewMode() == QFileDialogOptions::Detail + ? PickerViewMode_Thumbnail : PickerViewMode_List); + RETURN_FALSE_IF_FAILED("Failed to set picker view mode"); + + ComPtr<IVector<HSTRING>> filters; + hr = picker->get_FileTypeFilter(&filters); + RETURN_FALSE_IF_FAILED("Failed to get file type filters list"); + foreach (const QString &namedFilter, options->nameFilters()) { + foreach (const QString &filter, QPlatformFileDialogHelper::cleanFilterList(namedFilter)) { + // Remove leading star + const int offset = (filter.length() > 1 && filter.startsWith(QLatin1Char('*'))) ? 1 : 0; + HStringReference filterRef(reinterpret_cast<const wchar_t *>(filter.utf16() + offset), + filter.length() - offset); + hr = filters->Append(filterRef.Get()); + if (FAILED(hr)) { + qWarning("Failed to add named file filter \"%s\": %s", + qPrintable(filter), qPrintable(qt_error_string(hr))); + } + } + } + // The file dialog won't open with an empty list - add a default wildcard + quint32 size; + hr = filters->get_Size(&size); + RETURN_FALSE_IF_FAILED("Failed to get file type filters list size"); + if (!size) { + hr = filters->Append(HString::MakeReference(L"*").Get()); + RETURN_FALSE_IF_FAILED("Failed to add default wildcard to file type filters list"); + } + + return true; +} + +class QWinRTFileDialogHelperPrivate +{ +public: + bool shown; + QEventLoop loop; + + // Input + QUrl directory; + QUrl saveFileName; + QString selectedNameFilter; + + // Output + QList<QUrl> selectedFiles; +}; + +QWinRTFileDialogHelper::QWinRTFileDialogHelper() + : QPlatformFileDialogHelper(), d_ptr(new QWinRTFileDialogHelperPrivate) +{ + Q_D(QWinRTFileDialogHelper); + + d->shown = false; +} + +QWinRTFileDialogHelper::~QWinRTFileDialogHelper() +{ +} + +void QWinRTFileDialogHelper::exec() +{ + Q_D(QWinRTFileDialogHelper); + + if (!d->shown) + show(Qt::Dialog, Qt::ApplicationModal, 0); + d->loop.exec(); +} + +bool QWinRTFileDialogHelper::show(Qt::WindowFlags windowFlags, Qt::WindowModality windowModality, QWindow *parent) +{ + Q_UNUSED(windowFlags) + Q_UNUSED(windowModality) + Q_UNUSED(parent) + Q_D(QWinRTFileDialogHelper); + + HRESULT hr; + const QSharedPointer<QFileDialogOptions> dialogOptions = options(); + switch (dialogOptions->acceptMode()) { + default: + case QFileDialogOptions::AcceptOpen: { + switch (dialogOptions->fileMode()) { + case QFileDialogOptions::AnyFile: + case QFileDialogOptions::ExistingFile: + case QFileDialogOptions::ExistingFiles: { + ComPtr<IFileOpenPicker> picker; + if (!initializePicker(HString::MakeReference(RuntimeClass_Windows_Storage_Pickers_FileOpenPicker).Get(), + picker.GetAddressOf(), dialogOptions)) { + return false; + } + if (!initializeOpenPickerOptions(picker.Get(), dialogOptions)) + return false; + + if (dialogOptions->fileMode() == QFileDialogOptions::ExistingFiles) { + ComPtr<IAsyncOperation<IVectorView<StorageFile *> *>> op; + hr = picker->PickMultipleFilesAsync(&op); + RETURN_FALSE_IF_FAILED("Failed to open multi file picker"); + hr = op->put_Completed(Callback<MultipleFileHandler>(this, &QWinRTFileDialogHelper::onMultipleFilesPicked).Get()); + } else { + ComPtr<IAsyncOperation<StorageFile *>> op; + hr = picker->PickSingleFileAsync(&op); + RETURN_FALSE_IF_FAILED("Failed to open single file picker"); + hr = op->put_Completed(Callback<SingleFileHandler>(this, &QWinRTFileDialogHelper::onSingleFilePicked).Get()); + } + RETURN_FALSE_IF_FAILED("Failed to attach file picker callback"); + break; + } + case QFileDialogOptions::Directory: + case QFileDialogOptions::DirectoryOnly: { + ComPtr<IFolderPicker> picker; + if (!initializePicker(HString::MakeReference(RuntimeClass_Windows_Storage_Pickers_FolderPicker).Get(), + picker.GetAddressOf(), dialogOptions)) { + return false; + } + if (!initializeOpenPickerOptions(picker.Get(), dialogOptions)) + return false; + + ComPtr<IAsyncOperation<StorageFolder *>> op; + hr = picker->PickSingleFolderAsync(&op); + RETURN_FALSE_IF_FAILED("Failed to open folder picker"); + hr = op->put_Completed(Callback<SingleFolderHandler>(this, &QWinRTFileDialogHelper::onSingleFolderPicked).Get()); + RETURN_FALSE_IF_FAILED("Failed to attach folder picker callback"); + break; + } + } + break; + } + case QFileDialogOptions::AcceptSave: { + ComPtr<IFileSavePicker> picker; + if (!initializePicker(HString::MakeReference(RuntimeClass_Windows_Storage_Pickers_FileSavePicker).Get(), + picker.GetAddressOf(), dialogOptions)) { + return false; + } + + ComPtr<IMap<HSTRING, IVector<HSTRING> *>> choices; + hr = picker->get_FileTypeChoices(&choices); + RETURN_FALSE_IF_FAILED("Failed to get file extension choices"); + foreach (const QString &namedFilter, dialogOptions->nameFilters()) { + ComPtr<IVector<HSTRING>> entry = Make<WindowsStringVector>(); + foreach (const QString &filter, QPlatformFileDialogHelper::cleanFilterList(namedFilter)) { + // Remove leading star + const int offset = (filter.length() > 1 && filter.startsWith(QLatin1Char('*'))) ? 1 : 0; + HStringReference filterRef(reinterpret_cast<const wchar_t *>(filter.utf16() + offset), + filter.length() - offset); + hr = entry->Append(filterRef.Get()); + if (FAILED(hr)) { + qWarning("Failed to add named file filter \"%s\": %s", + qPrintable(filter), qPrintable(qt_error_string(hr))); + } + } + const int offset = namedFilter.indexOf(QLatin1String(" (")); + const QString filterTitle = offset > 0 ? namedFilter.left(offset) : filterTitle; + HStringReference namedFilterRef(reinterpret_cast<const wchar_t *>(filterTitle.utf16()), + filterTitle.length()); + boolean replaced; + hr = choices->Insert(namedFilterRef.Get(), entry.Get(), &replaced); + RETURN_FALSE_IF_FAILED("Failed to insert file extension choice entry"); + } + + const QString suffix = dialogOptions->defaultSuffix(); + HStringReference nativeSuffix(reinterpret_cast<const wchar_t *>(suffix.utf16()), + suffix.length()); + hr = picker->put_DefaultFileExtension(nativeSuffix.Get()); + RETURN_FALSE_IF_FAILED("Failed to set default file extension"); + + const QString suggestedName = QFileInfo(d->saveFileName.toLocalFile()).fileName(); + HStringReference nativeSuggestedName(reinterpret_cast<const wchar_t *>(suggestedName.utf16()), + suggestedName.length()); + hr = picker->put_SuggestedFileName(nativeSuggestedName.Get()); + RETURN_FALSE_IF_FAILED("Failed to set suggested file name"); + + ComPtr<IAsyncOperation<StorageFile *>> op; + hr = picker->PickSaveFileAsync(&op); + RETURN_FALSE_IF_FAILED("Failed to open save file picker"); + hr = op->put_Completed(Callback<SingleFileHandler>(this, &QWinRTFileDialogHelper::onSingleFilePicked).Get()); + RETURN_FALSE_IF_FAILED("Failed to attach file picker callback"); + break; + } + } + + d->shown = true; + return true; +} + +void QWinRTFileDialogHelper::hide() +{ + Q_D(QWinRTFileDialogHelper); + + if (!d->shown) + return; + + d->shown = false; +} + +void QWinRTFileDialogHelper::setDirectory(const QUrl &directory) +{ + Q_D(QWinRTFileDialogHelper); + d->directory = directory; +} + +QUrl QWinRTFileDialogHelper::directory() const +{ + Q_D(const QWinRTFileDialogHelper); + return d->directory; +} + +void QWinRTFileDialogHelper::selectFile(const QUrl &saveFileName) +{ + Q_D(QWinRTFileDialogHelper); + d->saveFileName = saveFileName; +} + +QList<QUrl> QWinRTFileDialogHelper::selectedFiles() const +{ + Q_D(const QWinRTFileDialogHelper); + return d->selectedFiles; +} + +void QWinRTFileDialogHelper::selectNameFilter(const QString &selectedNameFilter) +{ + Q_D(QWinRTFileDialogHelper); + d->selectedNameFilter = selectedNameFilter; +} + +QString QWinRTFileDialogHelper::selectedNameFilter() const +{ + Q_D(const QWinRTFileDialogHelper); + return d->selectedNameFilter; +} + +HRESULT QWinRTFileDialogHelper::onSingleFilePicked(IAsyncOperation<StorageFile *> *args, AsyncStatus status) +{ + Q_D(QWinRTFileDialogHelper); + + QEventLoopLocker locker(&d->loop); + d->shown = false; + d->selectedFiles.clear(); + if (status == Canceled || status == Error) { + emit reject(); + return S_OK; + } + + HRESULT hr; + ComPtr<IStorageFile> file; + hr = args->GetResults(&file); + Q_ASSERT_SUCCEEDED(hr); + if (!file) { + emit reject(); + return S_OK; + } + + appendFile(file.Get()); + emit accept(); + return S_OK; +} + +HRESULT QWinRTFileDialogHelper::onMultipleFilesPicked(IAsyncOperation<IVectorView<StorageFile *> *> *args, AsyncStatus status) +{ + Q_D(QWinRTFileDialogHelper); + + QEventLoopLocker locker(&d->loop); + d->shown = false; + d->selectedFiles.clear(); + if (status == Canceled || status == Error) { + emit reject(); + return S_OK; + } + + HRESULT hr; + ComPtr<IVectorView<StorageFile *>> fileList; + hr = args->GetResults(&fileList); + RETURN_HR_IF_FAILED("Failed to get file list"); + + quint32 size; + hr = fileList->get_Size(&size); + Q_ASSERT_SUCCEEDED(hr); + if (!size) { + emit reject(); + return S_OK; + } + for (quint32 i = 0; i < size; ++i) { + ComPtr<IStorageFile> file; + hr = fileList->GetAt(i, &file); + Q_ASSERT_SUCCEEDED(hr); + appendFile(file.Get()); + } + + emit accept(); + return S_OK; +} + +HRESULT QWinRTFileDialogHelper::onSingleFolderPicked(IAsyncOperation<StorageFolder *> *args, AsyncStatus status) +{ + Q_D(QWinRTFileDialogHelper); + + QEventLoopLocker locker(&d->loop); + d->shown = false; + d->selectedFiles.clear(); + if (status == Canceled || status == Error) { + emit reject(); + return S_OK; + } + + HRESULT hr; + ComPtr<IStorageFolder> folder; + hr = args->GetResults(&folder); + Q_ASSERT_SUCCEEDED(hr); + if (!folder) { + emit reject(); + return S_OK; + } + + appendFile(folder.Get()); + emit accept(); + return S_OK; +} + +void QWinRTFileDialogHelper::appendFile(IInspectable *file) +{ + Q_D(QWinRTFileDialogHelper); + + HRESULT hr; + ComPtr<IStorageItem> item; + hr = file->QueryInterface(IID_PPV_ARGS(&item)); + Q_ASSERT_SUCCEEDED(hr); + + HString path; + hr = item->get_Path(path.GetAddressOf()); + Q_ASSERT_SUCCEEDED(hr); + + quint32 pathLen; + const wchar_t *pathStr = path.GetRawBuffer(&pathLen); + const QString filePath = QString::fromWCharArray(pathStr, pathLen); + QWinRTFileEngineHandler::registerFile(filePath, item.Get()); + d->selectedFiles.append(QUrl::fromLocalFile(filePath)); +} + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/winrt/qwinrtfiledialoghelper.h b/src/plugins/platforms/winrt/qwinrtfiledialoghelper.h new file mode 100644 index 0000000000..f333f3f4ae --- /dev/null +++ b/src/plugins/platforms/winrt/qwinrtfiledialoghelper.h @@ -0,0 +1,104 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWINRTFILEDIALOGHELPER_H +#define QWINRTFILEDIALOGHELPER_H + +#include <qpa/qplatformdialoghelper.h> +#include <QtCore/qt_windows.h> + +struct IInspectable; +namespace ABI { + namespace Windows { + namespace Storage { + class StorageFile; + class StorageFolder; + struct IStorageFile; + } + namespace Foundation { + enum class AsyncStatus; + template <typename T> struct IAsyncOperation; + namespace Collections { + template <typename T> struct IVectorView; + } + } + } +} + +QT_BEGIN_NAMESPACE + +class QWinRTFileDialogHelperPrivate; +class QWinRTFileDialogHelper : public QPlatformFileDialogHelper +{ + Q_OBJECT +public: + explicit QWinRTFileDialogHelper(); + ~QWinRTFileDialogHelper(); + + void exec() Q_DECL_OVERRIDE; + bool show(Qt::WindowFlags, Qt::WindowModality, QWindow *) Q_DECL_OVERRIDE; + void hide() Q_DECL_OVERRIDE; + + bool defaultNameFilterDisables() const Q_DECL_OVERRIDE { return false; } + void setDirectory(const QUrl &directory) Q_DECL_OVERRIDE; + QUrl directory() const Q_DECL_OVERRIDE; + void selectFile(const QUrl &saveFileName); + QList<QUrl> selectedFiles() const Q_DECL_OVERRIDE; + void setFilter() Q_DECL_OVERRIDE { } + void selectNameFilter(const QString &selectedNameFilter) Q_DECL_OVERRIDE; + QString selectedNameFilter() const; + +private: + HRESULT onSingleFilePicked(ABI::Windows::Foundation::IAsyncOperation<ABI::Windows::Storage::StorageFile *> *, + ABI::Windows::Foundation::AsyncStatus); + HRESULT onMultipleFilesPicked(ABI::Windows::Foundation::IAsyncOperation<ABI::Windows::Foundation::Collections::IVectorView<ABI::Windows::Storage::StorageFile *> *> *, + ABI::Windows::Foundation::AsyncStatus); + HRESULT onSingleFolderPicked(ABI::Windows::Foundation::IAsyncOperation<ABI::Windows::Storage::StorageFolder *> *, + ABI::Windows::Foundation::AsyncStatus); + void appendFile(IInspectable *); + + QScopedPointer<QWinRTFileDialogHelperPrivate> d_ptr; + Q_DECLARE_PRIVATE(QWinRTFileDialogHelper) +}; + +QT_END_NAMESPACE + +#endif // QWINRTFILEDIALOGHELPER_H diff --git a/src/plugins/platforms/winrt/qwinrtfileengine.cpp b/src/plugins/platforms/winrt/qwinrtfileengine.cpp new file mode 100644 index 0000000000..3a4aa519cc --- /dev/null +++ b/src/plugins/platforms/winrt/qwinrtfileengine.cpp @@ -0,0 +1,505 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qwinrtfileengine.h" + +#include <QtCore/QDateTime> +#include <QtCore/QCoreApplication> +#include <QtCore/QHash> +#include <QtCore/qfunctions_winrt.h> + +#include <wrl.h> +#include <windows.storage.h> +#include <robuffer.h> + +using namespace Microsoft::WRL; +using namespace Microsoft::WRL::Wrappers; +using namespace ABI::Windows::Foundation; +using namespace ABI::Windows::Storage; +using namespace ABI::Windows::Storage::Streams; + +typedef IAsyncOperationCompletedHandler<IRandomAccessStream *> StreamCompletedHandler; +typedef IAsyncOperationWithProgressCompletedHandler<IBuffer *, UINT32> StreamReadCompletedHandler; + +QT_BEGIN_NAMESPACE + +#define RETURN_AND_SET_ERROR_IF_FAILED(error, ret) \ + setError(error, qt_error_string(hr)); \ + if (FAILED(hr)) \ + return ret; + +Q_GLOBAL_STATIC(QWinRTFileEngineHandler, handlerInstance) + +class QWinRTFileEngineHandlerPrivate +{ +public: + QHash<QString, ComPtr<IStorageItem>> files; +}; + +class QWinRTFileEnginePrivate +{ +public: + QWinRTFileEnginePrivate(const QString &fileName, IStorageItem *file) + : fileName(fileName), file(file) + { + HRESULT hr; + hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Storage_Streams_Buffer).Get(), + IID_PPV_ARGS(&bufferFactory)); + Q_ASSERT_SUCCEEDED(hr); + + lastSeparator = fileName.size() - 1; + for (int i = lastSeparator; i >= 0; --i) { + if (fileName.at(i).unicode() == '/' || fileName.at(i).unicode() == '\\') { + lastSeparator = i; + break; + } + } + + firstDot = fileName.size(); + for (int i = lastSeparator; i > fileName.size(); ++i) { + if (fileName.at(i).unicode() == '.') { + firstDot = i; + break; + } + } + } + + ComPtr<IBufferFactory> bufferFactory; + + QString fileName; + int lastSeparator; + int firstDot; + ComPtr<IStorageItem> file; + ComPtr<IRandomAccessStream> stream; + + qint64 pos; + +private: + QWinRTFileEngineHandler *q_ptr; + Q_DECLARE_PUBLIC(QWinRTFileEngineHandler) +}; + + +QWinRTFileEngineHandler::QWinRTFileEngineHandler() + : d_ptr(new QWinRTFileEngineHandlerPrivate) +{ +} + +QWinRTFileEngineHandler::~QWinRTFileEngineHandler() +{ +} + +void QWinRTFileEngineHandler::registerFile(const QString &fileName, IStorageItem *file) +{ + handlerInstance->d_func()->files.insert(QDir::cleanPath(fileName), file); +} + +IStorageItem *QWinRTFileEngineHandler::registeredFile(const QString &fileName) +{ + return handlerInstance->d_func()->files.value(fileName).Get(); +} + +QAbstractFileEngine *QWinRTFileEngineHandler::create(const QString &fileName) const +{ + Q_D(const QWinRTFileEngineHandler); + + QHash<QString, ComPtr<IStorageItem>>::const_iterator file = d->files.find(fileName); + if (file != d->files.end()) + return new QWinRTFileEngine(fileName, file.value().Get()); + + return Q_NULLPTR; +} + +static HRESULT getDestinationFolder(const QString &fileName, const QString newFileName, + IStorageItem *file, IStorageFolder **folder) +{ + HRESULT hr; + ComPtr<IAsyncOperation<StorageFolder *>> op; + QFileInfo newFileInfo(newFileName); +#ifndef Q_OS_WINPHONE + QFileInfo fileInfo(fileName); + if (fileInfo.dir() == newFileInfo.dir()) { + ComPtr<IStorageItem2> item; + hr = file->QueryInterface(IID_PPV_ARGS(&item)); + Q_ASSERT_SUCCEEDED(hr); + + hr = item->GetParentAsync(&op); + } else +#else + Q_UNUSED(fileName); + Q_UNUSED(file) +#endif + { + ComPtr<IStorageFolderStatics> folderFactory; + hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Storage_StorageFolder).Get(), + IID_PPV_ARGS(&folderFactory)); + Q_ASSERT_SUCCEEDED(hr); + + const QString newFilePath = QDir::toNativeSeparators(newFileInfo.absolutePath()); + HStringReference nativeNewFilePath(reinterpret_cast<LPCWSTR>(newFilePath.utf16()), + newFilePath.length()); + hr = folderFactory->GetFolderFromPathAsync(nativeNewFilePath.Get(), &op); + } + if (FAILED(hr)) + return hr; + return QWinRTFunctions::await(op, folder); +} + +QWinRTFileEngine::QWinRTFileEngine(const QString &fileName, IStorageItem *file) + : d_ptr(new QWinRTFileEnginePrivate(fileName, file)) +{ +} + +QWinRTFileEngine::~QWinRTFileEngine() +{ +} + +bool QWinRTFileEngine::open(QIODevice::OpenMode openMode) +{ + Q_D(QWinRTFileEngine); + + FileAccessMode fileAccessMode = (openMode & QIODevice::WriteOnly) + ? FileAccessMode_ReadWrite : FileAccessMode_Read; + + HRESULT hr; + ComPtr<IStorageFile> file; + hr = d->file.As(&file); + RETURN_AND_SET_ERROR_IF_FAILED(QFileDevice::OpenError, false); + + ComPtr<IAsyncOperation<IRandomAccessStream *>> op; + hr = file->OpenAsync(fileAccessMode, &op); + RETURN_AND_SET_ERROR_IF_FAILED(QFileDevice::OpenError, false); + + hr = QWinRTFunctions::await(op, d->stream.GetAddressOf()); + RETURN_AND_SET_ERROR_IF_FAILED(QFileDevice::OpenError, false); + + return SUCCEEDED(hr); +} + +bool QWinRTFileEngine::close() +{ + Q_D(QWinRTFileEngine); + + if (!d->stream) + return false; + + ComPtr<IClosable> closable; + HRESULT hr = d->stream.As(&closable); + Q_ASSERT_SUCCEEDED(hr); + + hr = closable->Close(); + RETURN_AND_SET_ERROR_IF_FAILED(QFileDevice::UnspecifiedError, false); + d->stream.Reset(); + return SUCCEEDED(hr); +} + +qint64 QWinRTFileEngine::size() const +{ + Q_D(const QWinRTFileEngine); + + if (!d->stream) + return 0; + + UINT64 size; + HRESULT hr; + hr = d->stream->get_Size(&size); + RETURN_IF_FAILED("Failed to get file size", return 0); + + return qint64(size); +} + +qint64 QWinRTFileEngine::pos() const +{ + Q_D(const QWinRTFileEngine); + return d->pos; +} + +bool QWinRTFileEngine::seek(qint64 pos) +{ + Q_D(QWinRTFileEngine); + + if (!d->stream) + return false; + + HRESULT hr = d->stream->Seek(pos); + RETURN_AND_SET_ERROR_IF_FAILED(QFileDevice::PositionError, false); + d->pos = pos; + return SUCCEEDED(hr); +} + +bool QWinRTFileEngine::remove() +{ + Q_D(QWinRTFileEngine); + + ComPtr<IAsyncAction> op; + HRESULT hr = d->file->DeleteAsync(StorageDeleteOption_Default, &op); + RETURN_AND_SET_ERROR_IF_FAILED(QFileDevice::RemoveError, false); + + hr = QWinRTFunctions::await(op); + RETURN_AND_SET_ERROR_IF_FAILED(QFileDevice::RemoveError, false); + return SUCCEEDED(hr); +} + +bool QWinRTFileEngine::copy(const QString &newName) +{ + Q_D(QWinRTFileEngine); + + HRESULT hr; + ComPtr<IStorageFolder> destinationFolder; + hr = getDestinationFolder(d->fileName, newName, d->file.Get(), destinationFolder.GetAddressOf()); + RETURN_AND_SET_ERROR_IF_FAILED(QFileDevice::CopyError, false); + + ComPtr<IStorageFile> file; + hr = d->file.As(&file); + RETURN_AND_SET_ERROR_IF_FAILED(QFileDevice::CopyError, false); + + const QString destinationName = QFileInfo(newName).fileName(); + HStringReference nativeDestinationName(reinterpret_cast<LPCWSTR>(destinationName.utf16()), destinationName.length()); + ComPtr<IAsyncOperation<StorageFile *>> op; + hr = file->CopyOverloadDefaultOptions(destinationFolder.Get(), nativeDestinationName.Get(), &op); + RETURN_AND_SET_ERROR_IF_FAILED(QFileDevice::CopyError, false); + + ComPtr<IStorageFile> newFile; + hr = QWinRTFunctions::await(op, newFile.GetAddressOf()); + RETURN_AND_SET_ERROR_IF_FAILED(QFileDevice::CopyError, false); + return SUCCEEDED(hr); +} + +bool QWinRTFileEngine::rename(const QString &newName) +{ + Q_D(QWinRTFileEngine); + + HRESULT hr; + ComPtr<IStorageFolder> destinationFolder; + hr = getDestinationFolder(d->fileName, newName, d->file.Get(), destinationFolder.GetAddressOf()); + RETURN_AND_SET_ERROR_IF_FAILED(QFileDevice::RenameError, false); + + const QString destinationName = QFileInfo(newName).fileName(); + HStringReference nativeDestinationName(reinterpret_cast<LPCWSTR>(destinationName.utf16()), destinationName.length()); + ComPtr<IAsyncAction> op; + hr = d->file->RenameAsyncOverloadDefaultOptions(nativeDestinationName.Get(), &op); + RETURN_AND_SET_ERROR_IF_FAILED(QFileDevice::RenameError, false); + return SUCCEEDED(hr); +} + +bool QWinRTFileEngine::renameOverwrite(const QString &newName) +{ + Q_D(QWinRTFileEngine); + + HRESULT hr; + ComPtr<IStorageFolder> destinationFolder; + hr = getDestinationFolder(d->fileName, newName, d->file.Get(), destinationFolder.GetAddressOf()); + RETURN_AND_SET_ERROR_IF_FAILED(QFileDevice::RenameError, false); + + const QString destinationName = QFileInfo(newName).fileName(); + HStringReference nativeDestinationName(reinterpret_cast<LPCWSTR>(destinationName.utf16()), destinationName.length()); + ComPtr<IAsyncAction> op; + hr = d->file->RenameAsync(nativeDestinationName.Get(), NameCollisionOption_ReplaceExisting, &op); + RETURN_AND_SET_ERROR_IF_FAILED(QFileDevice::RenameError, false); + return SUCCEEDED(hr); +} + +QAbstractFileEngine::FileFlags QWinRTFileEngine::fileFlags(FileFlags type) const +{ + Q_D(const QWinRTFileEngine); + + FileFlags flags = ExistsFlag|ReadOwnerPerm|ReadUserPerm|WriteOwnerPerm|WriteUserPerm; + + HRESULT hr; + FileAttributes attributes; + hr = d->file->get_Attributes(&attributes); + RETURN_IF_FAILED("Failed to get file attributes", return flags); + if (attributes & FileAttributes_ReadOnly) + flags ^= WriteUserPerm; + if (attributes & FileAttributes_Directory) + flags |= DirectoryType; + else + flags |= FileType; + + return type & flags; +} + +bool QWinRTFileEngine::setPermissions(uint perms) +{ + Q_UNUSED(perms); + Q_UNIMPLEMENTED(); + return false; +} + +QString QWinRTFileEngine::fileName(FileName type) const +{ + Q_D(const QWinRTFileEngine); + + switch (type) { + default: + case DefaultName: + case AbsoluteName: + case CanonicalName: + break; + case BaseName: + return d->lastSeparator < 0 + ? d->fileName : d->fileName.mid(d->lastSeparator, d->firstDot - d->lastSeparator); + case PathName: + case AbsolutePathName: + case CanonicalPathName: + return d->fileName.mid(0, d->lastSeparator); + case LinkName: + case BundleName: + return QString(); + } + return d->fileName; +} + +QDateTime QWinRTFileEngine::fileTime(FileTime type) const +{ + Q_D(const QWinRTFileEngine); + + HRESULT hr; + DateTime dateTime = { 0 }; + switch (type) { + case CreationTime: + hr = d->file->get_DateCreated(&dateTime); + RETURN_IF_FAILED("Failed to get file creation time", return QDateTime()); + break; + case ModificationTime: + case AccessTime: { + ComPtr<IAsyncOperation<FileProperties::BasicProperties *>> op; + hr = d->file->GetBasicPropertiesAsync(&op); + RETURN_IF_FAILED("Failed to initiate file properties", return QDateTime()); + ComPtr<FileProperties::IBasicProperties> properties; + hr = QWinRTFunctions::await(op, properties.GetAddressOf()); + RETURN_IF_FAILED("Failed to get file properties", return QDateTime()); + hr = type == ModificationTime ? properties->get_DateModified(&dateTime) + : properties->get_ItemDate(&dateTime); + RETURN_IF_FAILED("Failed to get file date", return QDateTime()); + } + break; + } + + SYSTEMTIME systemTime; + FileTimeToSystemTime((const FILETIME *)&dateTime, &systemTime); + QDate date(systemTime.wYear, systemTime.wMonth, systemTime.wDay); + QTime time(systemTime.wHour, systemTime.wMinute, systemTime.wSecond, systemTime.wMilliseconds); + return QDateTime(date, time); +} + +qint64 QWinRTFileEngine::read(char *data, qint64 maxlen) +{ + Q_D(QWinRTFileEngine); + + if (!d->stream) + return -1; + + ComPtr<IInputStream> stream; + HRESULT hr = d->stream.As(&stream); + RETURN_AND_SET_ERROR_IF_FAILED(QFileDevice::ReadError, -1); + + UINT32 length = qBound(quint64(0), quint64(maxlen), quint64(UINT_MAX)); + ComPtr<IBuffer> buffer; + hr = d->bufferFactory->Create(length, &buffer); + RETURN_AND_SET_ERROR_IF_FAILED(QFileDevice::ReadError, -1); + + ComPtr<IAsyncOperationWithProgress<IBuffer *, UINT32>> op; + hr = stream->ReadAsync(buffer.Get(), length, InputStreamOptions_None, &op); + RETURN_AND_SET_ERROR_IF_FAILED(QFileDevice::ReadError, -1); + + hr = QWinRTFunctions::await(op, buffer.GetAddressOf()); + RETURN_AND_SET_ERROR_IF_FAILED(QFileDevice::ReadError, -1); + + hr = buffer->get_Length(&length); + RETURN_AND_SET_ERROR_IF_FAILED(QFileDevice::ReadError, -1); + + ComPtr<Windows::Storage::Streams::IBufferByteAccess> byteArrayAccess; + hr = buffer.As(&byteArrayAccess); + RETURN_AND_SET_ERROR_IF_FAILED(QFileDevice::ReadError, -1); + + byte *bytes; + hr = byteArrayAccess->Buffer(&bytes); + RETURN_AND_SET_ERROR_IF_FAILED(QFileDevice::ReadError, -1); + memcpy(data, bytes, length); + return qint64(length); +} + +qint64 QWinRTFileEngine::write(const char *data, qint64 maxlen) +{ + Q_D(QWinRTFileEngine); + + if (!d->stream) + return -1; + + ComPtr<IOutputStream> stream; + HRESULT hr = d->stream.As(&stream); + RETURN_AND_SET_ERROR_IF_FAILED(QFileDevice::WriteError, -1); + + UINT32 length = qBound(quint64(0), quint64(maxlen), quint64(UINT_MAX)); + ComPtr<IBuffer> buffer; + hr = d->bufferFactory->Create(length, &buffer); + RETURN_AND_SET_ERROR_IF_FAILED(QFileDevice::WriteError, -1); + hr = buffer->put_Length(length); + RETURN_AND_SET_ERROR_IF_FAILED(QFileDevice::WriteError, -1); + + ComPtr<Windows::Storage::Streams::IBufferByteAccess> byteArrayAccess; + hr = buffer.As(&byteArrayAccess); + RETURN_AND_SET_ERROR_IF_FAILED(QFileDevice::WriteError, -1); + + byte *bytes; + hr = byteArrayAccess->Buffer(&bytes); + RETURN_AND_SET_ERROR_IF_FAILED(QFileDevice::WriteError, -1); + memcpy(bytes, data, length); + + ComPtr<IAsyncOperationWithProgress<UINT32, UINT32>> op; + hr = stream->WriteAsync(buffer.Get(), &op); + RETURN_AND_SET_ERROR_IF_FAILED(QFileDevice::WriteError, -1); + + hr = QWinRTFunctions::await(op, &length); + RETURN_AND_SET_ERROR_IF_FAILED(QFileDevice::WriteError, -1); + + ComPtr<IAsyncOperation<bool>> flushOp; + hr = stream->FlushAsync(&flushOp); + RETURN_AND_SET_ERROR_IF_FAILED(QFileDevice::WriteError, -1); + boolean flushed; + hr = QWinRTFunctions::await(flushOp, &flushed); + RETURN_AND_SET_ERROR_IF_FAILED(QFileDevice::WriteError, -1); + + return qint64(length); +} + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/winrt/qwinrtplatformtheme.cpp b/src/plugins/platforms/winrt/qwinrtfileengine.h index d4034ec571..59eeb1c44c 100644 --- a/src/plugins/platforms/winrt/qwinrtplatformtheme.cpp +++ b/src/plugins/platforms/winrt/qwinrtfileengine.h @@ -39,38 +39,66 @@ ** ****************************************************************************/ -#include "qwinrtplatformtheme.h" -#include "qwinrtplatformmessagedialoghelper.h" +#ifndef QWINRTFILEENGINE_H +#define QWINRTFILEENGINE_H + +#include <private/qabstractfileengine_p.h> QT_BEGIN_NAMESPACE -QWinRTPlatformTheme::QWinRTPlatformTheme() -{ +namespace ABI { + namespace Windows { + namespace Storage { + struct IStorageItem; + } + } } -bool QWinRTPlatformTheme::usePlatformNativeDialog(QPlatformTheme::DialogType type) const +class QWinRTFileEngineHandlerPrivate; +class QWinRTFileEngineHandler : public QAbstractFileEngineHandler { -#if !(defined(Q_OS_WINPHONE) && _MSC_VER<=1700) - if (type == QPlatformTheme::MessageDialog) - return true; -#else - Q_UNUSED(type) -#endif // !(Q_OS_WINPHONE && _MSC_VER<=1700) - return false; -} +public: + QWinRTFileEngineHandler(); + ~QWinRTFileEngineHandler(); + QAbstractFileEngine *create(const QString &fileName) const Q_DECL_OVERRIDE; + + static void registerFile(const QString &fileName, ABI::Windows::Storage::IStorageItem *file); + static ABI::Windows::Storage::IStorageItem *registeredFile(const QString &fileName); + +private: + QScopedPointer<QWinRTFileEngineHandlerPrivate> d_ptr; + Q_DECLARE_PRIVATE(QWinRTFileEngineHandler) +}; -QPlatformDialogHelper *QWinRTPlatformTheme::createPlatformDialogHelper(QPlatformTheme::DialogType type) const +class QWinRTFileEnginePrivate; +class QWinRTFileEngine : public QAbstractFileEngine { -#if !(defined(Q_OS_WINPHONE) && _MSC_VER<=1700) - switch (type) { - case QPlatformTheme::MessageDialog: - return new QWinRTPlatformMessageDialogHelper(); - default: - return QPlatformTheme::createPlatformDialogHelper(type); - } -#else // !(Q_OS_WINPHONE && _MSC_VER<=1700) - return QPlatformTheme::createPlatformDialogHelper(type); -#endif // Q_OS_WINPHONE && _MSC_VER<=1700 -} +public: + QWinRTFileEngine(const QString &fileName, ABI::Windows::Storage::IStorageItem *file); + ~QWinRTFileEngine(); + + bool open(QIODevice::OpenMode openMode) Q_DECL_OVERRIDE; + bool close() Q_DECL_OVERRIDE; + qint64 size() const Q_DECL_OVERRIDE; + qint64 pos() const Q_DECL_OVERRIDE; + bool seek(qint64 pos) Q_DECL_OVERRIDE; + bool remove() Q_DECL_OVERRIDE; + bool copy(const QString &newName) Q_DECL_OVERRIDE; + bool rename(const QString &newName) Q_DECL_OVERRIDE; + bool renameOverwrite(const QString &newName) Q_DECL_OVERRIDE; + FileFlags fileFlags(FileFlags type=FileInfoAll) const Q_DECL_OVERRIDE; + bool setPermissions(uint perms) Q_DECL_OVERRIDE; + QString fileName(FileName type=DefaultName) const Q_DECL_OVERRIDE; + QDateTime fileTime(FileTime type) const Q_DECL_OVERRIDE; + + qint64 read(char *data, qint64 maxlen) Q_DECL_OVERRIDE; + qint64 write(const char *data, qint64 len) Q_DECL_OVERRIDE; + +private: + QScopedPointer<QWinRTFileEnginePrivate> d_ptr; + Q_DECLARE_PRIVATE(QWinRTFileEngine) +}; QT_END_NAMESPACE + +#endif // QWINRTFILEENGINE_H diff --git a/src/plugins/platforms/winrt/qwinrtintegration.cpp b/src/plugins/platforms/winrt/qwinrtintegration.cpp index b3a2cafa2e..53d52a430c 100644 --- a/src/plugins/platforms/winrt/qwinrtintegration.cpp +++ b/src/plugins/platforms/winrt/qwinrtintegration.cpp @@ -48,7 +48,7 @@ #include "qwinrtservices.h" #include "qwinrteglcontext.h" #include "qwinrtfontdatabase.h" -#include "qwinrtplatformtheme.h" +#include "qwinrttheme.h" #include <QtGui/QOpenGLContext> @@ -63,18 +63,6 @@ using namespace ABI::Windows::UI::Core; using namespace ABI::Windows::UI::ViewManagement; using namespace ABI::Windows::ApplicationModel::Core; -static IUISettings *getSettings() -{ - static IUISettings *settings = 0; - if (!settings) { - if (FAILED(RoActivateInstance(Wrappers::HString::MakeReference(RuntimeClass_Windows_UI_ViewManagement_UISettings).Get(), - reinterpret_cast<IInspectable **>(&settings)))) { - qWarning("Could not activate UISettings."); - } - } - return settings; -} - QT_BEGIN_NAMESPACE QWinRTIntegration::QWinRTIntegration() @@ -82,26 +70,7 @@ QWinRTIntegration::QWinRTIntegration() , m_fontDatabase(new QWinRTFontDatabase) , m_services(new QWinRTServices) { - // Obtain the WinRT Application, view, and window - ICoreApplication *application; - if (FAILED(RoGetActivationFactory(Wrappers::HString::MakeReference(RuntimeClass_Windows_ApplicationModel_Core_CoreApplication).Get(), - IID_PPV_ARGS(&application)))) - qCritical("Could not attach to the application factory."); - - ICoreApplicationView *view; - if (FAILED(application->GetCurrentView(&view))) { - qCritical("Could not obtain the application view - have you started outside of WinRT?"); - return; - } - - // Get core window (will act as our screen) - ICoreWindow *window; - if (FAILED(view->get_CoreWindow(&window))) { - qCritical("Could not obtain the application window - have you started outside of WinRT?"); - return; - } - window->Activate(); - m_screen = new QWinRTScreen(window); + m_screen = new QWinRTScreen; screenAdded(m_screen); m_success = true; @@ -133,26 +102,7 @@ bool QWinRTIntegration::hasCapability(QPlatformIntegration::Capability cap) cons QVariant QWinRTIntegration::styleHint(StyleHint hint) const { - switch (hint) { - case CursorFlashTime: - if (IUISettings *settings = getSettings()) { - quint32 blinkRate; - settings->get_CaretBlinkRate(&blinkRate); - return blinkRate; - } - break; - case MouseDoubleClickInterval: - if (IUISettings *settings = getSettings()) { - quint32 doubleClickTime; - settings->get_DoubleClickTime(&doubleClickTime); - return doubleClickTime; - } - case ShowIsFullScreen: - return true; - default: - break; - } - return QPlatformIntegration::styleHint(hint); + return QWinRTTheme::styleHint(hint); } QPlatformWindow *QWinRTIntegration::createPlatformWindow(QWindow *window) const @@ -200,7 +150,7 @@ QPlatformTheme *QWinRTIntegration::createPlatformTheme(const QString & name) const { if (name == QLatin1String("winrt")) - return new QWinRTPlatformTheme(); + return new QWinRTTheme(); return 0; } diff --git a/src/plugins/platforms/winrt/qwinrtmessagedialoghelper.cpp b/src/plugins/platforms/winrt/qwinrtmessagedialoghelper.cpp new file mode 100644 index 0000000000..6de90ba1ec --- /dev/null +++ b/src/plugins/platforms/winrt/qwinrtmessagedialoghelper.cpp @@ -0,0 +1,232 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qwinrtmessagedialoghelper.h" +#include "qwinrttheme.h" + +#include <QtCore/qfunctions_winrt.h> + +#include <windows.ui.popups.h> +#include <windows.foundation.h> +#include <windows.foundation.collections.h> +#include <wrl.h> + +using namespace ABI::Windows::Foundation; +using namespace ABI::Windows::Foundation::Collections; +using namespace ABI::Windows::UI::Popups; +using namespace Microsoft::WRL; +using namespace Microsoft::WRL::Wrappers; + +typedef IAsyncOperationCompletedHandler<IUICommand *> DialogCompletedHandler; + +QT_BEGIN_NAMESPACE + +class CommandId : public RuntimeClass<IInspectable> +{ +public: + CommandId(QPlatformDialogHelper::StandardButton button) + : button(button) { } + QPlatformDialogHelper::StandardButton button; +}; + +class QWinRTMessageDialogHelperPrivate +{ +public: + const QWinRTTheme *theme; + bool shown; + ComPtr<IAsyncInfo> info; + QEventLoop loop; +}; + +QWinRTMessageDialogHelper::QWinRTMessageDialogHelper(const QWinRTTheme *theme) + : QPlatformMessageDialogHelper(), d_ptr(new QWinRTMessageDialogHelperPrivate) +{ + Q_D(QWinRTMessageDialogHelper); + + d->theme = theme; + d->shown = false; +} + +QWinRTMessageDialogHelper::~QWinRTMessageDialogHelper() +{ + Q_D(QWinRTMessageDialogHelper); + + if (d->shown) + hide(); +} + +void QWinRTMessageDialogHelper::exec() +{ + Q_D(QWinRTMessageDialogHelper); + + if (!d->shown) + show(Qt::Dialog, Qt::ApplicationModal, 0); + d->loop.exec(); +} + +bool QWinRTMessageDialogHelper::show(Qt::WindowFlags windowFlags, Qt::WindowModality windowModality, QWindow *parent) +{ + Q_UNUSED(windowFlags) + Q_UNUSED(windowModality) + Q_UNUSED(parent) + Q_D(QWinRTMessageDialogHelper); + + QSharedPointer<QMessageDialogOptions> options = this->options(); + const QString informativeText = options->informativeText(); + const QString title = options->windowTitle(); + const QString text = informativeText.isEmpty() ? options->text() : (options->text() + QLatin1Char('\n') + informativeText); + + HRESULT hr; + ComPtr<IMessageDialogFactory> dialogFactory; + hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_UI_Popups_MessageDialog).Get(), + IID_PPV_ARGS(&dialogFactory)); + RETURN_FALSE_IF_FAILED("Failed to create dialog factory"); + + ComPtr<IUICommandFactory> commandFactory; + hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_UI_Popups_UICommand).Get(), + IID_PPV_ARGS(&commandFactory)); + RETURN_FALSE_IF_FAILED("Failed to create command factory"); + + ComPtr<IMessageDialog> dialog; + HStringReference nativeText(reinterpret_cast<LPCWSTR>(text.utf16()), text.size()); + if (!title.isEmpty()) { + HStringReference nativeTitle(reinterpret_cast<LPCWSTR>(title.utf16()), title.size()); + hr = dialogFactory->CreateWithTitle(nativeText.Get(), nativeTitle.Get(), &dialog); + RETURN_FALSE_IF_FAILED("Failed to create dialog with title"); + } else { + hr = dialogFactory->Create(nativeText.Get(), &dialog); + RETURN_FALSE_IF_FAILED("Failed to create dialog"); + } + + // Add Buttons + ComPtr<IVector<IUICommand *>> dialogCommands; + hr = dialog->get_Commands(&dialogCommands); + RETURN_FALSE_IF_FAILED("Failed to get dialog commands"); + + // If no button is specified we need to create one to get close notification + int buttons = options->standardButtons(); + if (buttons == 0) + buttons = Ok; + + for (int i = FirstButton; i < LastButton; i<<=1) { + if (!(buttons & i)) + continue; + // Add native command + const QString label = d->theme->standardButtonText(i); + HStringReference nativeLabel(reinterpret_cast<LPCWSTR>(label.utf16()), label.size()); + ComPtr<IUICommand> command; + hr = commandFactory->Create(nativeLabel.Get(), &command); + RETURN_FALSE_IF_FAILED("Failed to create message box command"); + ComPtr<IInspectable> id = Make<CommandId>(static_cast<StandardButton>(i)); + hr = command->put_Id(id.Get()); + RETURN_FALSE_IF_FAILED("Failed to set command ID"); + hr = dialogCommands->Append(command.Get()); + if (hr == E_BOUNDS) { + qErrnoWarning(hr, "The WinRT message dialog supports a maximum of three buttons"); + continue; + } + RETURN_FALSE_IF_FAILED("Failed to append message box command"); + if (i == Abort || i == Cancel || i == Close) { + quint32 size; + hr = dialogCommands->get_Size(&size); + RETURN_FALSE_IF_FAILED("Failed to get command list size"); + hr = dialog->put_CancelCommandIndex(size - 1); + RETURN_FALSE_IF_FAILED("Failed to set cancel index"); + } + } + + ComPtr<IAsyncOperation<IUICommand *>> op; + hr = dialog->ShowAsync(&op); + RETURN_FALSE_IF_FAILED("Failed to show dialog"); + hr = op->put_Completed(Callback<DialogCompletedHandler>(this, &QWinRTMessageDialogHelper::onCompleted).Get()); + RETURN_FALSE_IF_FAILED("Failed to set dialog callback"); + + d->shown = true; + hr = op.As(&d->info); + RETURN_FALSE_IF_FAILED("Failed to acquire AsyncInfo for MessageDialog"); + + return true; +} + +void QWinRTMessageDialogHelper::hide() +{ + Q_D(QWinRTMessageDialogHelper); + + if (!d->shown) + return; + + HRESULT hr = d->info->Cancel(); + if (FAILED(hr)) + qErrnoWarning(hr, "Failed to cancel dialog operation"); + + d->shown = false; +} + +HRESULT QWinRTMessageDialogHelper::onCompleted(IAsyncOperation<IUICommand *> *asyncInfo, AsyncStatus status) +{ + Q_UNUSED(status); + Q_D(QWinRTMessageDialogHelper); + + if (d->loop.isRunning()) + d->loop.exit(); + + d->shown = false; + + if (status == Canceled) { + emit reject(); + return S_OK; + } + + HRESULT hr; + ComPtr<IUICommand> command; + hr = asyncInfo->GetResults(&command); + RETURN_OK_IF_FAILED("Failed to get command"); + + ComPtr<CommandId> id; + hr = command->get_Id(&id); + RETURN_OK_IF_FAILED("Failed to get command ID"); + + ButtonRole role = buttonRole(id->button); + emit clicked(id->button, role); + return S_OK; +} + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/winrt/qwinrtplatformmessagedialoghelper.h b/src/plugins/platforms/winrt/qwinrtmessagedialoghelper.h index fbb21ed69c..25199e569c 100644 --- a/src/plugins/platforms/winrt/qwinrtplatformmessagedialoghelper.h +++ b/src/plugins/platforms/winrt/qwinrtmessagedialoghelper.h @@ -39,11 +39,10 @@ ** ****************************************************************************/ -#ifndef QWINRTPLATFORMMESSAGEDIALOGHELPER_H -#define QWINRTPLATFORMMESSAGEDIALOGHELPER_H +#ifndef QWINRTMESSAGEDIALOGHELPER_H +#define QWINRTMESSAGEDIALOGHELPER_H #include <qpa/qplatformdialoghelper.h> -#include <QtCore/QEventLoop> #include <QtCore/qt_windows.h> namespace ABI { @@ -53,19 +52,24 @@ namespace ABI { struct IUICommand; } } + namespace Foundation { + enum class AsyncStatus; + template <typename T> struct IAsyncOperation; + } } } QT_BEGIN_NAMESPACE -struct QWinRTPlatformMessageDialogInfo; +class QWinRTTheme; -class QWinRTPlatformMessageDialogHelper : public QPlatformMessageDialogHelper +class QWinRTMessageDialogHelperPrivate; +class QWinRTMessageDialogHelper : public QPlatformMessageDialogHelper { Q_OBJECT public: - explicit QWinRTPlatformMessageDialogHelper(); - ~QWinRTPlatformMessageDialogHelper(); + explicit QWinRTMessageDialogHelper(const QWinRTTheme *theme); + ~QWinRTMessageDialogHelper(); void exec(); bool show(Qt::WindowFlags windowFlags, @@ -73,13 +77,14 @@ public: QWindow *parent); void hide(); - HRESULT onInvoked(ABI::Windows::UI::Popups::IUICommand *command); private: - QWinRTPlatformMessageDialogInfo *m_info; - QEventLoop m_loop; - bool m_shown; + HRESULT onCompleted(ABI::Windows::Foundation::IAsyncOperation<ABI::Windows::UI::Popups::IUICommand *> *asyncInfo, + ABI::Windows::Foundation::AsyncStatus status); + + QScopedPointer<QWinRTMessageDialogHelperPrivate> d_ptr; + Q_DECLARE_PRIVATE(QWinRTMessageDialogHelper) }; QT_END_NAMESPACE -#endif // QWINRTPLATFORMMESSAGEDIALOGHELPER_H +#endif // QWINRTMESSAGEDIALOGHELPER_H diff --git a/src/plugins/platforms/winrt/qwinrtplatformmessagedialoghelper.cpp b/src/plugins/platforms/winrt/qwinrtplatformmessagedialoghelper.cpp deleted file mode 100644 index c2f884055d..0000000000 --- a/src/plugins/platforms/winrt/qwinrtplatformmessagedialoghelper.cpp +++ /dev/null @@ -1,204 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal -** -** This file is part of the plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Digia. For licensing terms and -** conditions see http://qt.digia.com/licensing. For further information -** use the contact form at http://qt.digia.com/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Digia gives you certain additional -** rights. These rights are described in the Digia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qwinrtplatformmessagedialoghelper.h" - -#include <QtGui/QGuiApplication> -#include <private/qguiapplication_p.h> -#include <qpa/qplatformtheme.h> - -#include <asyncinfo.h> -#include <windows.ui.popups.h> -#include <windows.foundation.h> -#include <windows.foundation.collections.h> -#include <wrl.h> - -using namespace ABI::Windows::Foundation; -using namespace ABI::Windows::Foundation::Collections; -using namespace ABI::Windows::UI::Popups; -using namespace Microsoft::WRL; -using namespace Microsoft::WRL::Wrappers; - -QT_BEGIN_NAMESPACE - -struct QWinRTPlatformMessageDialogInfo -{ - ComPtr<IAsyncInfo> info; -}; - -QWinRTPlatformMessageDialogHelper::QWinRTPlatformMessageDialogHelper() : - QPlatformMessageDialogHelper(), - m_info(new QWinRTPlatformMessageDialogInfo), - m_shown(false) -{ -} - -QWinRTPlatformMessageDialogHelper::~QWinRTPlatformMessageDialogHelper() -{ - if (m_shown) - hide(); - delete m_info; -} - -void QWinRTPlatformMessageDialogHelper::exec() -{ - if (!m_shown) - show(Qt::Dialog, Qt::ApplicationModal, 0); - m_loop.exec(); -} - -bool QWinRTPlatformMessageDialogHelper::show(Qt::WindowFlags windowFlags, Qt::WindowModality windowModality, QWindow *parent) -{ - Q_UNUSED(windowFlags) - Q_UNUSED(windowModality) - Q_UNUSED(parent) - - QSharedPointer<QMessageDialogOptions> options = this->options(); - - const QString informativeText = options->informativeText(); - const QString title = options->windowTitle(); - const QString text = informativeText.isEmpty() ? options->text() : (options->text() + QLatin1Char('\n') + informativeText); - - - ComPtr<IMessageDialogFactory> dialogFactory; - if (FAILED(GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_UI_Popups_MessageDialog).Get(), &dialogFactory))) - return false; - - ComPtr<IUICommandFactory> commandFactory; - if (FAILED(GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_UI_Popups_UICommand).Get(), &commandFactory))) - return false; - - HString nativeText; - nativeText.Set(reinterpret_cast<LPCWSTR>(text.utf16()), text.size()); - ComPtr<IMessageDialog> dialog; - - if (!title.isEmpty()) { - HString nativeTitle; - nativeTitle.Set(reinterpret_cast<LPCWSTR>(title.utf16()), title.size()); - if (FAILED(dialogFactory->CreateWithTitle(nativeText.Get(), nativeTitle.Get(), &dialog))) - return false; - } else { - if (FAILED(dialogFactory->Create(nativeText.Get(), &dialog))) - return false; - } - - // Add Buttons - ComPtr<IVector<IUICommand*> > dialogCommands; - if (FAILED(dialog->get_Commands(&dialogCommands))) - return false; - - // If no button is specified we need to create one to get close notification - int buttons = options->standardButtons(); - if (buttons == 0) - buttons = QPlatformDialogHelper::Ok; - - for (int i = QPlatformDialogHelper::FirstButton; i < QPlatformDialogHelper::LastButton; i<<=1) { - if (buttons & i) { - // Add native command - const QString label = QGuiApplicationPrivate::platformTheme()->standardButtonText(i); - - HString hLabel; - hLabel.Set(reinterpret_cast<LPCWSTR>(label.utf16()), label.size()); - - ABI::Windows::UI::Popups::IUICommand *command; - if (FAILED(commandFactory->CreateWithHandler(hLabel.Get(), - Callback<IUICommandInvokedHandler>(this, &QWinRTPlatformMessageDialogHelper::onInvoked).Get(), - &command))) - return false; - dialogCommands->Append(command); - } - } - - ComPtr<IAsyncOperation<IUICommand*> > op; - if (FAILED(dialog->ShowAsync(&op))) - return false; - - m_shown = true; - if (FAILED(op.As(&m_info->info))) { - m_shown = false; - // The dialog is shown already, so we cannot return false - qWarning("Failed to acquire AsyncInfo for MessageDialog"); - } - return true; -} - -void QWinRTPlatformMessageDialogHelper::hide() -{ - if (!m_shown) - return; - - m_info->info->Cancel(); - m_shown = false; -} - -HRESULT QWinRTPlatformMessageDialogHelper::onInvoked(ABI::Windows::UI::Popups::IUICommand *command) -{ - HString hLabel; - UINT32 labelLength; - command->get_Label(hLabel.GetAddressOf()); - PCWSTR rawString = hLabel.GetRawBuffer(&labelLength); - QString label = QString::fromWCharArray(rawString, labelLength); - int buttonId = -1; - for (int i = QPlatformDialogHelper::FirstButton; i < QPlatformDialogHelper::LastButton; i<<=1) { - if ( options()->standardButtons() & i ) { - if (QGuiApplicationPrivate::platformTheme()->standardButtonText(i) == label) { - buttonId = i; - break; - } - } - } - if (m_loop.isRunning()) - m_loop.exit(); - - m_shown = false; - - if (buttonId < 0) { - emit reject(); - return S_OK; - } - - QPlatformDialogHelper::StandardButton standardButton = static_cast<QPlatformDialogHelper::StandardButton>(buttonId); - QPlatformDialogHelper::ButtonRole role = QPlatformDialogHelper::buttonRole(standardButton); - emit clicked(standardButton, role); - return S_OK; -} - -QT_END_NAMESPACE diff --git a/src/plugins/platforms/winrt/qwinrtscreen.cpp b/src/plugins/platforms/winrt/qwinrtscreen.cpp index f948cf9924..a18bd2834e 100644 --- a/src/plugins/platforms/winrt/qwinrtscreen.cpp +++ b/src/plugins/platforms/winrt/qwinrtscreen.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the plugins of the Qt Toolkit. @@ -51,6 +51,7 @@ #include <QtPlatformSupport/private/qeglconvenience_p.h> #include <qpa/qwindowsysteminterface.h> #include <QtCore/qt_windows.h> +#include <QtCore/qfunctions_winrt.h> #include <wrl.h> #include <windows.system.h> @@ -93,11 +94,7 @@ typedef ITypedEventHandler<CoreWindow*, PointerEventArgs*> PointerHandler; typedef ITypedEventHandler<CoreWindow*, WindowSizeChangedEventArgs*> SizeChangedHandler; typedef ITypedEventHandler<CoreWindow*, VisibilityChangedEventArgs*> VisibilityChangedHandler; typedef ITypedEventHandler<CoreWindow*, AutomationProviderRequestedEventArgs*> AutomationProviderRequestedHandler; -#if _MSC_VER <=1700 -typedef IDisplayPropertiesEventHandler DisplayInformationHandler; -#else typedef ITypedEventHandler<DisplayInformation*, IInspectable*> DisplayInformationHandler; -#endif #ifdef Q_OS_WINPHONE typedef IEventHandler<BackPressedEventArgs*> BackPressedHandler; #endif @@ -419,199 +416,266 @@ static inline Qt::Key qKeyFromCode(quint32 code, int mods) return static_cast<Qt::Key>(code & 0xff); } -QWinRTScreen::QWinRTScreen(ICoreWindow *window) - : m_coreWindow(window) - , m_depth(32) - , m_format(QImage::Format_ARGB32_Premultiplied) +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 - , m_inputContext(new QWinRTInputContext(m_coreWindow)) -#else - , m_inputContext(Make<QWinRTInputContext>(m_coreWindow).Detach()) +typedef HRESULT (__stdcall IHardwareButtonsStatics::*HardwareButtonsCallbackRemover)(EventRegistrationToken); +uint qHash(HardwareButtonsCallbackRemover key) { void *ptr = *(void **)(&key); return qHash(ptr); } #endif - , m_cursor(new QWinRTCursor(window)) - , m_devicePixelRatio(1.0) - , m_orientation(Qt::PrimaryOrientation) - , m_touchDevice(Q_NULLPTR) + +class QWinRTScreenPrivate { - Rect rect; - window->get_Bounds(&rect); - m_geometry = QRectF(0, 0, rect.Width, rect.Height); - - m_surfaceFormat.setAlphaBufferSize(0); - m_surfaceFormat.setRedBufferSize(8); - m_surfaceFormat.setGreenBufferSize(8); - m_surfaceFormat.setBlueBufferSize(8); - - m_surfaceFormat.setRenderableType(QSurfaceFormat::OpenGLES); - m_surfaceFormat.setSamples(1); - m_surfaceFormat.setSwapBehavior(QSurfaceFormat::DoubleBuffer); - m_surfaceFormat.setDepthBufferSize(24); - m_surfaceFormat.setStencilBufferSize(8); - - m_eglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); - if (m_eglDisplay == EGL_NO_DISPLAY) - qFatal("Qt WinRT platform plugin: failed to initialize EGL display."); - - if (!eglInitialize(m_eglDisplay, NULL, NULL)) - qFatal("Qt WinRT platform plugin: failed to initialize EGL. This can happen if you haven't included the D3D compiler DLL in your application package."); - - // TODO: move this to Window - m_eglSurface = eglCreateWindowSurface(m_eglDisplay, q_configFromGLFormat(m_eglDisplay, m_surfaceFormat), window, NULL); - if (m_eglSurface == EGL_NO_SURFACE) - qFatal("Could not create EGL surface, error 0x%X", eglGetError()); - - // Event handlers mapped to QEvents - m_coreWindow->add_KeyDown(Callback<KeyHandler>(this, &QWinRTScreen::onKeyDown).Get(), &m_tokens[QEvent::KeyPress]); - m_coreWindow->add_KeyUp(Callback<KeyHandler>(this, &QWinRTScreen::onKeyUp).Get(), &m_tokens[QEvent::KeyRelease]); - m_coreWindow->add_CharacterReceived(Callback<CharacterReceivedHandler>(this, &QWinRTScreen::onCharacterReceived).Get(), &m_tokens[QEvent::User]); - m_coreWindow->add_PointerEntered(Callback<PointerHandler>(this, &QWinRTScreen::onPointerEntered).Get(), &m_tokens[QEvent::Enter]); - m_coreWindow->add_PointerExited(Callback<PointerHandler>(this, &QWinRTScreen::onPointerExited).Get(), &m_tokens[QEvent::Leave]); - m_coreWindow->add_PointerMoved(Callback<PointerHandler>(this, &QWinRTScreen::onPointerUpdated).Get(), &m_tokens[QEvent::MouseMove]); - m_coreWindow->add_PointerPressed(Callback<PointerHandler>(this, &QWinRTScreen::onPointerUpdated).Get(), &m_tokens[QEvent::MouseButtonPress]); - m_coreWindow->add_PointerReleased(Callback<PointerHandler>(this, &QWinRTScreen::onPointerUpdated).Get(), &m_tokens[QEvent::MouseButtonRelease]); - m_coreWindow->add_PointerWheelChanged(Callback<PointerHandler>(this, &QWinRTScreen::onPointerUpdated).Get(), &m_tokens[QEvent::Wheel]); - m_coreWindow->add_SizeChanged(Callback<SizeChangedHandler>(this, &QWinRTScreen::onSizeChanged).Get(), &m_tokens[QEvent::Resize]); +public: + ComPtr<ICoreApplication> application; + ComPtr<ICoreWindow> coreWindow; + ComPtr<IDisplayInformation> displayInformation; #ifdef Q_OS_WINPHONE ComPtr<IHardwareButtonsStatics> hardwareButtons; - if (SUCCEEDED(GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Phone_UI_Input_HardwareButtons).Get(), &hardwareButtons))) - hardwareButtons->add_BackPressed(Callback<BackPressedHandler>(this, &QWinRTScreen::onBackButtonPressed).Get(), &m_tokens[QEvent::User]); -#endif // Q_OS_WINPHONE - - // Window event handlers - m_coreWindow->add_Activated(Callback<ActivatedHandler>(this, &QWinRTScreen::onActivated).Get(), &m_tokens[QEvent::WindowActivate]); - m_coreWindow->add_Closed(Callback<ClosedHandler>(this, &QWinRTScreen::onClosed).Get(), &m_tokens[QEvent::WindowDeactivate]); - m_coreWindow->add_VisibilityChanged(Callback<VisibilityChangedHandler>(this, &QWinRTScreen::onVisibilityChanged).Get(), &m_tokens[QEvent::Show]); - m_coreWindow->add_AutomationProviderRequested(Callback<AutomationProviderRequestedHandler>(this, &QWinRTScreen::onAutomationProviderRequested).Get(), &m_tokens[QEvent::InputMethodQuery]); +#endif - // Orientation handling -#if _MSC_VER<=1700 - HRESULT hr = GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Graphics_Display_DisplayProperties).Get(), - &m_displayInformation); + QScopedPointer<QWinRTCursor> cursor; +#ifdef Q_OS_WINPHONE + QScopedPointer<QWinRTInputContext> inputContext; #else - HRESULT hr = GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Graphics_Display_DisplayInformation).Get(), - &m_displayInformationFactory); - if (FAILED(hr)) { - qErrnoWarning(hr, "Failed to get display information factory."); - return; - } - - hr = m_displayInformationFactory->GetForCurrentView(&m_displayInformation); + ComPtr<QWinRTInputContext> inputContext; #endif - if (FAILED(hr)) { - qErrnoWarning(hr, "Failed to get display information for the current view."); - return; - } + QSizeF logicalSize; + QSurfaceFormat surfaceFormat; + qreal logicalDpi; + QDpi physicalDpi; + qreal scaleFactor; + Qt::ScreenOrientation nativeOrientation; + Qt::ScreenOrientation orientation; + QList<QWindow *> visibleWindows; +#ifndef Q_OS_WINPHONE + QHash<quint32, QPair<Qt::Key, QString>> activeKeys; +#endif + QTouchDevice *touchDevice; + QHash<quint32, QWindowSystemInterface::TouchPoint> touchPoints; - // Set native orientation - DisplayOrientations displayOrientation; - hr = m_displayInformation->get_NativeOrientation(&displayOrientation); - if (FAILED(hr)) { - qErrnoWarning(hr, "Failed to get native orientation."); - return; - } + EGLDisplay eglDisplay; + EGLSurface eglSurface; - m_nativeOrientation = static_cast<Qt::ScreenOrientation>(static_cast<int>(qtOrientationsFromNative(displayOrientation))); + QHash<CoreApplicationCallbackRemover, EventRegistrationToken> applicationTokens; + QHash<CoreWindowCallbackRemover, EventRegistrationToken> windowTokens; + QHash<DisplayCallbackRemover, EventRegistrationToken> displayTokens; +#ifdef Q_OS_WINPHONE + QHash<HardwareButtonsCallbackRemover, EventRegistrationToken> buttonsTokens; +#endif +}; - hr = m_displayInformation->add_OrientationChanged(Callback<DisplayInformationHandler>(this, &QWinRTScreen::onOrientationChanged).Get(), - &m_tokens[QEvent::OrientationChange]); - if (FAILED(hr)) { - qErrnoWarning(hr, "Failed to add orientation change callback."); - return; - } +QWinRTScreen::QWinRTScreen() + : d_ptr(new QWinRTScreenPrivate) +{ + Q_D(QWinRTScreen); + d->orientation = Qt::PrimaryOrientation; + d->touchDevice = Q_NULLPTR; + + // 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); + Q_ASSERT_SUCCEEDED(hr); + hr = d->coreWindow->Activate(); + Q_ASSERT_SUCCEEDED(hr); -#if _MSC_VER<=1700 - hr = m_displayInformation->add_LogicalDpiChanged(Callback<DisplayInformationHandler>(this, &QWinRTScreen::onDpiChanged).Get(), - &m_tokens[QEvent::Type(QEvent::User + 1)]); +#ifdef Q_OS_WINPHONE + d->inputContext.reset(new QWinRTInputContext(d->coreWindow.Get())); #else - hr = m_displayInformation->add_DpiChanged(Callback<DisplayInformationHandler>(this, &QWinRTScreen::onDpiChanged).Get(), - &m_tokens[QEvent::Type(QEvent::User + 1)]); + d->inputContext = Make<QWinRTInputContext>(d->coreWindow.Get()); #endif - if (FAILED(hr)) { - qErrnoWarning(hr, "Failed to add logical dpi change callback."); - return; - } + + 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.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]); + Q_ASSERT_SUCCEEDED(hr); + hr = d->coreWindow->add_CharacterReceived(Callback<CharacterReceivedHandler>(this, &QWinRTScreen::onCharacterReceived).Get(), &d->windowTokens[&ICoreWindow::remove_CharacterReceived]); + Q_ASSERT_SUCCEEDED(hr); + hr = d->coreWindow->add_PointerEntered(Callback<PointerHandler>(this, &QWinRTScreen::onPointerEntered).Get(), &d->windowTokens[&ICoreWindow::remove_PointerEntered]); + Q_ASSERT_SUCCEEDED(hr); + hr = d->coreWindow->add_PointerExited(Callback<PointerHandler>(this, &QWinRTScreen::onPointerExited).Get(), &d->windowTokens[&ICoreWindow::remove_PointerExited]); + Q_ASSERT_SUCCEEDED(hr); + hr = d->coreWindow->add_PointerMoved(Callback<PointerHandler>(this, &QWinRTScreen::onPointerUpdated).Get(), &d->windowTokens[&ICoreWindow::remove_PointerMoved]); + Q_ASSERT_SUCCEEDED(hr); + hr = d->coreWindow->add_PointerPressed(Callback<PointerHandler>(this, &QWinRTScreen::onPointerUpdated).Get(), &d->windowTokens[&ICoreWindow::remove_PointerPressed]); + Q_ASSERT_SUCCEEDED(hr); + hr = d->coreWindow->add_PointerReleased(Callback<PointerHandler>(this, &QWinRTScreen::onPointerUpdated).Get(), &d->windowTokens[&ICoreWindow::remove_PointerReleased]); + Q_ASSERT_SUCCEEDED(hr); + hr = d->coreWindow->add_PointerWheelChanged(Callback<PointerHandler>(this, &QWinRTScreen::onPointerUpdated).Get(), &d->windowTokens[&ICoreWindow::remove_PointerWheelChanged]); + Q_ASSERT_SUCCEEDED(hr); + hr = d->coreWindow->add_SizeChanged(Callback<SizeChangedHandler>(this, &QWinRTScreen::onSizeChanged).Get(), &d->windowTokens[&ICoreWindow::remove_SizeChanged]); + Q_ASSERT_SUCCEEDED(hr); + 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; + hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Graphics_Display_DisplayInformation).Get(), + IID_PPV_ARGS(&displayInformationStatics)); + Q_ASSERT_SUCCEEDED(hr); + + hr = displayInformationStatics->GetForCurrentView(&d->displayInformation); + Q_ASSERT_SUCCEEDED(hr); + + // Set native orientation + DisplayOrientations displayOrientation; + hr = d->displayInformation->get_NativeOrientation(&displayOrientation); + Q_ASSERT_SUCCEEDED(hr); + d->nativeOrientation = static_cast<Qt::ScreenOrientation>(static_cast<int>(qtOrientationsFromNative(displayOrientation))); + + hr = d->displayInformation->add_OrientationChanged(Callback<DisplayInformationHandler>(this, &QWinRTScreen::onOrientationChanged).Get(), &d->displayTokens[&IDisplayInformation::remove_OrientationChanged]); + Q_ASSERT_SUCCEEDED(hr); + + hr = d->displayInformation->add_DpiChanged(Callback<DisplayInformationHandler>(this, &QWinRTScreen::onDpiChanged).Get(), &d->displayTokens[&IDisplayInformation::remove_DpiChanged]); + Q_ASSERT_SUCCEEDED(hr); // Set initial orientation & pixel density -#if _MSC_VER<=1700 - onOrientationChanged(Q_NULLPTR); - onDpiChanged(Q_NULLPTR); -#else - onOrientationChanged(Q_NULLPTR, Q_NULLPTR); onDpiChanged(Q_NULLPTR, Q_NULLPTR); -#endif - setOrientationUpdateMask(m_nativeOrientation); + d->orientation = d->nativeOrientation; + onOrientationChanged(Q_NULLPTR, Q_NULLPTR); - if (SUCCEEDED(RoGetActivationFactory(Wrappers::HString::MakeReference(RuntimeClass_Windows_ApplicationModel_Core_CoreApplication).Get(), - IID_PPV_ARGS(&m_application)))) { - m_application->add_Suspending(Callback<SuspendHandler>(this, &QWinRTScreen::onSuspended).Get(), &m_suspendTokens[Qt::ApplicationSuspended]); - m_application->add_Resuming(Callback<ResumeHandler>(this, &QWinRTScreen::onResume).Get(), &m_suspendTokens[Qt::ApplicationHidden]); - } + d->eglDisplay = eglGetDisplay(d->displayInformation.Get()); + if (d->eglDisplay == EGL_NO_DISPLAY) + qCritical("Failed to initialize EGL display: 0x%x", eglGetError()); + + if (!eglInitialize(d->eglDisplay, NULL, NULL)) + qCritical("Failed to initialize EGL: 0x%x", eglGetError()); + + d->eglSurface = eglCreateWindowSurface(d->eglDisplay, q_configFromGLFormat(d->eglDisplay, d->surfaceFormat), d->coreWindow.Get(), NULL); + if (d->eglSurface == EGL_NO_SURFACE) + qCritical("Failed to create EGL window surface: 0x%x", eglGetError()); +} + +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 } QRect QWinRTScreen::geometry() const { - return m_geometry.toRect(); + Q_D(const QWinRTScreen); + return QRect(QPoint(), (d->logicalSize * d->scaleFactor).toSize()); } int QWinRTScreen::depth() const { - return m_depth; + return 32; } QImage::Format QWinRTScreen::format() const { - return m_format; + return QImage::Format_ARGB32_Premultiplied; } QSurfaceFormat QWinRTScreen::surfaceFormat() const { - return m_surfaceFormat; + Q_D(const QWinRTScreen); + return d->surfaceFormat; } QSizeF QWinRTScreen::physicalSize() const { - return m_geometry.size() / m_dpi * qreal(25.4); + Q_D(const QWinRTScreen); + return QSizeF(d->logicalSize.width() * d->scaleFactor / d->physicalDpi.first * qreal(25.4), + d->logicalSize.height() * d->scaleFactor / d->physicalDpi.second * qreal(25.4)); } QDpi QWinRTScreen::logicalDpi() const { - return QDpi(m_dpi, m_dpi); -} - -qreal QWinRTScreen::devicePixelRatio() const -{ - return m_devicePixelRatio; + Q_D(const QWinRTScreen); + return QDpi(d->logicalDpi, d->logicalDpi); } QWinRTInputContext *QWinRTScreen::inputContext() const { - return m_inputContext; + Q_D(const QWinRTScreen); +#ifdef Q_OS_WINPHONE + return d->inputContext.data(); +#else + return d->inputContext.Get(); +#endif } QPlatformCursor *QWinRTScreen::cursor() const { - return m_cursor; + Q_D(const QWinRTScreen); + if (!d->cursor) + const_cast<QWinRTScreenPrivate *>(d)->cursor.reset(new QWinRTCursor); + return d->cursor.data(); } Qt::KeyboardModifiers QWinRTScreen::keyboardModifiers() const { + Q_D(const QWinRTScreen); + Qt::KeyboardModifiers mods; CoreVirtualKeyStates mod; - m_coreWindow->GetAsyncKeyState(VirtualKey_Shift, &mod); + d->coreWindow->GetAsyncKeyState(VirtualKey_Shift, &mod); if (mod == CoreVirtualKeyStates_Down) mods |= Qt::ShiftModifier; - m_coreWindow->GetAsyncKeyState(VirtualKey_Menu, &mod); + d->coreWindow->GetAsyncKeyState(VirtualKey_Menu, &mod); if (mod == CoreVirtualKeyStates_Down) mods |= Qt::AltModifier; - m_coreWindow->GetAsyncKeyState(VirtualKey_Control, &mod); + d->coreWindow->GetAsyncKeyState(VirtualKey_Control, &mod); if (mod == CoreVirtualKeyStates_Down) mods |= Qt::ControlModifier; - m_coreWindow->GetAsyncKeyState(VirtualKey_LeftWindows, &mod); + d->coreWindow->GetAsyncKeyState(VirtualKey_LeftWindows, &mod); if (mod == CoreVirtualKeyStates_Down) { mods |= Qt::MetaModifier; } else { - m_coreWindow->GetAsyncKeyState(VirtualKey_RightWindows, &mod); + d->coreWindow->GetAsyncKeyState(VirtualKey_RightWindows, &mod); if (mod == CoreVirtualKeyStates_Down) mods |= Qt::MetaModifier; } @@ -620,56 +684,55 @@ Qt::KeyboardModifiers QWinRTScreen::keyboardModifiers() const Qt::ScreenOrientation QWinRTScreen::nativeOrientation() const { - return m_nativeOrientation; + Q_D(const QWinRTScreen); + return d->nativeOrientation; } Qt::ScreenOrientation QWinRTScreen::orientation() const { - return m_orientation; -} - -void QWinRTScreen::setOrientationUpdateMask(Qt::ScreenOrientations mask) -{ -#if _MSC_VER<=1700 - m_displayInformation->put_AutoRotationPreferences(nativeOrientationsFromQt(mask)); -#else - m_displayInformationFactory->put_AutoRotationPreferences(nativeOrientationsFromQt(mask)); -#endif + Q_D(const QWinRTScreen); + return d->orientation; } ICoreWindow *QWinRTScreen::coreWindow() const { - return m_coreWindow; + Q_D(const QWinRTScreen); + return d->coreWindow.Get(); } EGLDisplay QWinRTScreen::eglDisplay() const { - return m_eglDisplay; + Q_D(const QWinRTScreen); + return d->eglDisplay; } EGLSurface QWinRTScreen::eglSurface() const { - return m_eglSurface; + Q_D(const QWinRTScreen); + return d->eglSurface; } QWindow *QWinRTScreen::topWindow() const { - return m_visibleWindows.isEmpty() ? 0 : m_visibleWindows.first(); + Q_D(const QWinRTScreen); + return d->visibleWindows.isEmpty() ? 0 : d->visibleWindows.first(); } void QWinRTScreen::addWindow(QWindow *window) { + Q_D(QWinRTScreen); if (window == topWindow()) return; - m_visibleWindows.prepend(window); + d->visibleWindows.prepend(window); QWindowSystemInterface::handleWindowActivated(window, Qt::OtherFocusReason); handleExpose(); } void QWinRTScreen::removeWindow(QWindow *window) { + Q_D(QWinRTScreen); const bool wasTopWindow = window == topWindow(); - if (!m_visibleWindows.removeAll(window)) + if (!d->visibleWindows.removeAll(window)) return; if (wasTopWindow) QWindowSystemInterface::handleWindowActivated(window, Qt::OtherFocusReason); @@ -678,17 +741,19 @@ void QWinRTScreen::removeWindow(QWindow *window) void QWinRTScreen::raise(QWindow *window) { - m_visibleWindows.removeAll(window); + Q_D(QWinRTScreen); + d->visibleWindows.removeAll(window); addWindow(window); } void QWinRTScreen::lower(QWindow *window) { + Q_D(QWinRTScreen); const bool wasTopWindow = window == topWindow(); - if (wasTopWindow && m_visibleWindows.size() == 1) + if (wasTopWindow && d->visibleWindows.size() == 1) return; - m_visibleWindows.removeAll(window); - m_visibleWindows.append(window); + d->visibleWindows.removeAll(window); + d->visibleWindows.append(window); if (wasTopWindow) QWindowSystemInterface::handleWindowActivated(window, Qt::OtherFocusReason); handleExpose(); @@ -696,18 +761,17 @@ void QWinRTScreen::lower(QWindow *window) void QWinRTScreen::handleExpose() { - if (m_visibleWindows.isEmpty()) + Q_D(QWinRTScreen); + if (d->visibleWindows.isEmpty()) return; - QList<QWindow *>::const_iterator it = m_visibleWindows.constBegin(); - QWindowSystemInterface::handleExposeEvent(*it, m_geometry.toRect()); - while (++it != m_visibleWindows.constEnd()) + QList<QWindow *>::const_iterator it = d->visibleWindows.constBegin(); + QWindowSystemInterface::handleExposeEvent(*it, geometry()); + while (++it != d->visibleWindows.constEnd()) QWindowSystemInterface::handleExposeEvent(*it, QRegion()); - QWindowSystemInterface::flushWindowSystemEvents(); } -HRESULT QWinRTScreen::onKeyDown(ABI::Windows::UI::Core::ICoreWindow *window, ABI::Windows::UI::Core::IKeyEventArgs *args) +HRESULT QWinRTScreen::onKeyDown(ABI::Windows::UI::Core::ICoreWindow *, ABI::Windows::UI::Core::IKeyEventArgs *args) { - Q_UNUSED(window); VirtualKey virtualKey; args->get_VirtualKey(&virtualKey); Qt::Key key = qKeyFromVirtual(virtualKey); @@ -718,14 +782,14 @@ HRESULT QWinRTScreen::onKeyDown(ABI::Windows::UI::Core::ICoreWindow *window, ABI return S_OK; } -HRESULT QWinRTScreen::onKeyUp(ABI::Windows::UI::Core::ICoreWindow *window, ABI::Windows::UI::Core::IKeyEventArgs *args) +HRESULT QWinRTScreen::onKeyUp(ABI::Windows::UI::Core::ICoreWindow *, ABI::Windows::UI::Core::IKeyEventArgs *args) { - Q_UNUSED(window); Qt::KeyboardModifiers mods = keyboardModifiers(); #ifndef Q_OS_WINPHONE + Q_D(QWinRTScreen); CorePhysicalKeyStatus status; // Look for a pressed character key - if (SUCCEEDED(args->get_KeyStatus(&status)) && m_activeKeys.contains(status.ScanCode)) { - QPair<Qt::Key, QString> keyStatus = m_activeKeys.take(status.ScanCode); + if (SUCCEEDED(args->get_KeyStatus(&status)) && d->activeKeys.contains(status.ScanCode)) { + QPair<Qt::Key, QString> keyStatus = d->activeKeys.take(status.ScanCode); QWindowSystemInterface::handleKeyEvent(topWindow(), QEvent::KeyRelease, keyStatus.first, mods, keyStatus.second); return S_OK; @@ -738,10 +802,8 @@ HRESULT QWinRTScreen::onKeyUp(ABI::Windows::UI::Core::ICoreWindow *window, ABI:: return S_OK; } -HRESULT QWinRTScreen::onCharacterReceived(ICoreWindow *window, ICharacterReceivedEventArgs *args) +HRESULT QWinRTScreen::onCharacterReceived(ICoreWindow *, ICharacterReceivedEventArgs *args) { - Q_UNUSED(window); - quint32 keyCode; args->get_KeyCode(&keyCode); // Don't generate character events for non-printables; the meta key stage is enough @@ -753,9 +815,10 @@ HRESULT QWinRTScreen::onCharacterReceived(ICoreWindow *window, ICharacterReceive QString text = QChar(keyCode); QWindowSystemInterface::handleKeyEvent(topWindow(), QEvent::KeyPress, key, mods, text); #ifndef Q_OS_WINPHONE + Q_D(QWinRTScreen); CorePhysicalKeyStatus status; // Defer release to onKeyUp for physical keys if (SUCCEEDED(args->get_KeyStatus(&status)) && !status.IsKeyReleased) { - m_activeKeys.insert(status.ScanCode, qMakePair(key, text)); + d->activeKeys.insert(status.ScanCode, qMakePair(key, text)); return S_OK; } #endif // !Q_OS_WINPHONE @@ -763,42 +826,39 @@ HRESULT QWinRTScreen::onCharacterReceived(ICoreWindow *window, ICharacterReceive return S_OK; } -HRESULT QWinRTScreen::onPointerEntered(ICoreWindow *window, IPointerEventArgs *args) +HRESULT QWinRTScreen::onPointerEntered(ICoreWindow *, IPointerEventArgs *args) { - Q_UNUSED(window); - IPointerPoint *pointerPoint; + Q_D(QWinRTScreen); + + ComPtr<IPointerPoint> pointerPoint; if (SUCCEEDED(args->get_CurrentPoint(&pointerPoint))) { // Assumes full-screen window Point point; pointerPoint->get_Position(&point); - QPoint pos(point.X, point.Y); + QPoint pos(point.X * d->scaleFactor, point.Y * d->scaleFactor); QWindowSystemInterface::handleEnterEvent(topWindow(), pos, pos); - pointerPoint->Release(); } return S_OK; } -HRESULT QWinRTScreen::onPointerExited(ICoreWindow *window, IPointerEventArgs *args) +HRESULT QWinRTScreen::onPointerExited(ICoreWindow *, IPointerEventArgs *) { - Q_UNUSED(window); - Q_UNUSED(args); QWindowSystemInterface::handleLeaveEvent(0); return S_OK; } -HRESULT QWinRTScreen::onPointerUpdated(ICoreWindow *window, IPointerEventArgs *args) +HRESULT QWinRTScreen::onPointerUpdated(ICoreWindow *, IPointerEventArgs *args) { - Q_UNUSED(window); - - IPointerPoint *pointerPoint; + Q_D(QWinRTScreen); + ComPtr<IPointerPoint> pointerPoint; if (FAILED(args->get_CurrentPoint(&pointerPoint))) return E_INVALIDARG; // Common traits - point, modifiers, properties Point point; pointerPoint->get_Position(&point); - QPointF pos(point.X, point.Y); + QPointF pos(point.X * d->scaleFactor, point.Y * d->scaleFactor); VirtualKeyModifiers modifiers; args->get_KeyModifiers(&modifiers); @@ -812,27 +872,18 @@ HRESULT QWinRTScreen::onPointerUpdated(ICoreWindow *window, IPointerEventArgs *a if (modifiers & VirtualKeyModifiers_Windows) mods |= Qt::MetaModifier; - IPointerPointProperties *properties; + ComPtr<IPointerPointProperties> properties; if (FAILED(pointerPoint->get_Properties(&properties))) return E_INVALIDARG; - PointerDeviceType pointerDeviceType; -#if defined(Q_OS_WINPHONE) && _MSC_VER <= 1700 - pointerDeviceType = PointerDeviceType_Touch; -#else ComPtr<IPointerDevice> pointerDevice; HRESULT hr = pointerPoint->get_PointerDevice(&pointerDevice); - if (FAILED(hr)) { - qErrnoWarning(hr, "Failed to get pointer device."); - return S_OK; - } + RETURN_OK_IF_FAILED("Failed to get pointer device."); + PointerDeviceType pointerDeviceType; hr = pointerDevice->get_PointerDeviceType(&pointerDeviceType); - if (FAILED(hr)) { - qErrnoWarning(hr, "Failed to get pointer device type."); - return S_OK; - } -#endif + RETURN_OK_IF_FAILED("Failed to get pointer device type."); + switch (pointerDeviceType) { case PointerDeviceType_Mouse: { qint32 delta; @@ -872,12 +923,12 @@ HRESULT QWinRTScreen::onPointerUpdated(ICoreWindow *window, IPointerEventArgs *a break; } case PointerDeviceType_Touch: { - if (!m_touchDevice) { - m_touchDevice = new QTouchDevice; - m_touchDevice->setName(QStringLiteral("WinRTTouchScreen")); - m_touchDevice->setType(QTouchDevice::TouchScreen); - m_touchDevice->setCapabilities(QTouchDevice::Position | QTouchDevice::Area | QTouchDevice::Pressure | QTouchDevice::NormalizedPosition); - QWindowSystemInterface::registerTouchDevice(m_touchDevice); + if (!d->touchDevice) { + d->touchDevice = new QTouchDevice; + d->touchDevice->setName(QStringLiteral("WinRTTouchScreen")); + d->touchDevice->setType(QTouchDevice::TouchScreen); + d->touchDevice->setCapabilities(QTouchDevice::Position | QTouchDevice::Area | QTouchDevice::Pressure | QTouchDevice::NormalizedPosition); + QWindowSystemInterface::registerTouchDevice(d->touchDevice); } quint32 id; @@ -889,8 +940,8 @@ HRESULT QWinRTScreen::onPointerUpdated(ICoreWindow *window, IPointerEventArgs *a float pressure; properties->get_Pressure(&pressure); - QHash<quint32, QWindowSystemInterface::TouchPoint>::iterator it = m_touchPoints.find(id); - if (it != m_touchPoints.end()) { + QHash<quint32, QWindowSystemInterface::TouchPoint>::iterator it = d->touchPoints.find(id); + if (it != d->touchPoints.end()) { boolean isPressed; #ifndef Q_OS_WINPHONE pointerPoint->get_IsInContact(&isPressed); @@ -899,20 +950,21 @@ HRESULT QWinRTScreen::onPointerUpdated(ICoreWindow *window, IPointerEventArgs *a #endif it.value().state = isPressed ? Qt::TouchPointMoved : Qt::TouchPointReleased; } else { - it = m_touchPoints.insert(id, QWindowSystemInterface::TouchPoint()); + it = d->touchPoints.insert(id, QWindowSystemInterface::TouchPoint()); it.value().state = Qt::TouchPointPressed; it.value().id = id; } - it.value().area = QRectF(area.X, area.Y, area.Width, area.Height); - it.value().normalPosition = QPointF(pos.x()/m_geometry.width(), pos.y()/m_geometry.height()); + it.value().area = QRectF(area.X * d->scaleFactor, area.Y * d->scaleFactor, + area.Width * d->scaleFactor, area.Height * d->scaleFactor); + it.value().normalPosition = QPointF(point.X/d->logicalSize.width(), point.Y/d->logicalSize.height()); it.value().pressure = pressure; - QWindowSystemInterface::handleTouchEvent(topWindow(), m_touchDevice, m_touchPoints.values(), mods); + QWindowSystemInterface::handleTouchEvent(topWindow(), d->touchDevice, d->touchPoints.values(), mods); // Remove released points, station others - for (QHash<quint32, QWindowSystemInterface::TouchPoint>::iterator i = m_touchPoints.begin(); i != m_touchPoints.end();) { + for (QHash<quint32, QWindowSystemInterface::TouchPoint>::iterator i = d->touchPoints.begin(); i != d->touchPoints.end();) { if (i.value().state == Qt::TouchPointReleased) - i = m_touchPoints.erase(i); + i = d->touchPoints.erase(i); else (i++).value().state = Qt::TouchPointStationary; } @@ -950,46 +1002,46 @@ HRESULT QWinRTScreen::onPointerUpdated(ICoreWindow *window, IPointerEventArgs *a } } - properties->Release(); - pointerPoint->Release(); - return S_OK; } HRESULT QWinRTScreen::onAutomationProviderRequested(ICoreWindow *, IAutomationProviderRequestedEventArgs *args) { + Q_D(const QWinRTScreen); #ifndef Q_OS_WINPHONE - args->put_AutomationProvider(m_inputContext); + args->put_AutomationProvider(d->inputContext.Get()); #else Q_UNUSED(args) #endif return S_OK; } -HRESULT QWinRTScreen::onSizeChanged(ICoreWindow *window, IWindowSizeChangedEventArgs *args) +HRESULT QWinRTScreen::onSizeChanged(ICoreWindow *, IWindowSizeChangedEventArgs *args) { - Q_UNUSED(window); + Q_D(QWinRTScreen); Size size; - if (FAILED(args->get_Size(&size))) { - qWarning(Q_FUNC_INFO ": failed to get size"); + HRESULT hr = args->get_Size(&size); + RETURN_OK_IF_FAILED("Failed to get window size."); + + QSizeF logicalSize = QSizeF(size.Width, size.Height); + if (d->logicalSize == logicalSize) return S_OK; - } // Regardless of state, all top-level windows are viewport-sized - this might change if // a more advanced compositor is written. - m_geometry.setSize(QSizeF(size.Width, size.Height)); - QWindowSystemInterface::handleScreenGeometryChange(screen(), m_geometry.toRect()); - QWindowSystemInterface::handleScreenAvailableGeometryChange(screen(), m_geometry.toRect()); + d->logicalSize = logicalSize; + const QRect newGeometry = geometry(); + QWindowSystemInterface::handleScreenGeometryChange(screen(), newGeometry, newGeometry); QPlatformScreen::resizeMaximizedWindows(); handleExpose(); return S_OK; } -HRESULT QWinRTScreen::onActivated(ICoreWindow *window, IWindowActivatedEventArgs *args) +HRESULT QWinRTScreen::onActivated(ICoreWindow *, IWindowActivatedEventArgs *args) { - Q_UNUSED(window); + Q_D(QWinRTScreen); CoreWindowActivationState activationState; args->get_WindowActivationState(&activationState); @@ -999,7 +1051,7 @@ HRESULT QWinRTScreen::onActivated(ICoreWindow *window, IWindowActivatedEventArgs } // Activate topWindow - if (!m_visibleWindows.isEmpty()) { + if (!d->visibleWindows.isEmpty()) { Qt::FocusReason focusReason = activationState == CoreWindowActivationState_PointerActivated ? Qt::MouseFocusReason : Qt::ActiveWindowFocusReason; QWindowSystemInterface::handleWindowActivated(topWindow(), focusReason); @@ -1022,21 +1074,15 @@ HRESULT QWinRTScreen::onResume(IInspectable *, IInspectable *) return S_OK; } -HRESULT QWinRTScreen::onClosed(ICoreWindow *window, ICoreWindowEventArgs *args) +HRESULT QWinRTScreen::onClosed(ICoreWindow *, ICoreWindowEventArgs *) { - Q_UNUSED(window); - Q_UNUSED(args); - foreach (QWindow *w, QGuiApplication::topLevelWindows()) QWindowSystemInterface::handleCloseEvent(w); return S_OK; } -HRESULT QWinRTScreen::onVisibilityChanged(ICoreWindow *window, IVisibilityChangedEventArgs *args) +HRESULT QWinRTScreen::onVisibilityChanged(ICoreWindow *, IVisibilityChangedEventArgs *args) { - Q_UNUSED(window); - Q_UNUSED(args); - boolean visible; args->get_Visible(&visible); QWindowSystemInterface::handleApplicationStateChanged(visible ? Qt::ApplicationActive : Qt::ApplicationHidden); @@ -1045,60 +1091,52 @@ HRESULT QWinRTScreen::onVisibilityChanged(ICoreWindow *window, IVisibilityChange return S_OK; } -#if _MSC_VER<=1700 -HRESULT QWinRTScreen::onOrientationChanged(IInspectable *) -#else HRESULT QWinRTScreen::onOrientationChanged(IDisplayInformation *, IInspectable *) -#endif { + Q_D(QWinRTScreen); + DisplayOrientations displayOrientation; - m_displayInformation->get_CurrentOrientation(&displayOrientation); + HRESULT hr = d->displayInformation->get_CurrentOrientation(&displayOrientation); + RETURN_OK_IF_FAILED("Failed to get current orientations."); + Qt::ScreenOrientation newOrientation = static_cast<Qt::ScreenOrientation>(static_cast<int>(qtOrientationsFromNative(displayOrientation))); - if (m_orientation != newOrientation) { - m_orientation = newOrientation; - QWindowSystemInterface::handleScreenOrientationChange(screen(), m_orientation); + if (d->orientation != newOrientation) { + d->orientation = newOrientation; + QWindowSystemInterface::handleScreenOrientationChange(screen(), d->orientation); } return S_OK; } -#if _MSC_VER<=1700 -HRESULT QWinRTScreen::onDpiChanged(IInspectable *) -#else HRESULT QWinRTScreen::onDpiChanged(IDisplayInformation *, IInspectable *) -#endif { -#if defined(Q_OS_WINPHONE) && _MSC_VER>=1800 // WP 8.1 + Q_D(QWinRTScreen); + + HRESULT hr; +#ifdef Q_OS_WINPHONE ComPtr<IDisplayInformation2> displayInformation; - HRESULT hr = m_displayInformation->QueryInterface(IID_IDisplayInformation2, &displayInformation); - if (FAILED(hr)) { - qErrnoWarning(hr, "Failed to cast display information."); - return S_OK; - } - hr = displayInformation->get_RawPixelsPerViewPixel(&m_devicePixelRatio); + hr = d->displayInformation.As(&displayInformation); + RETURN_OK_IF_FAILED("Failed to cast display information."); + hr = displayInformation->get_RawPixelsPerViewPixel(&d->scaleFactor); #else ResolutionScale resolutionScale; - HRESULT hr = m_displayInformation->get_ResolutionScale(&resolutionScale); -#endif - if (FAILED(hr)) { - qErrnoWarning(hr, "Failed to get display resolution scale."); - return S_OK; - } -#if !(defined(Q_OS_WINPHONE) && _MSC_VER>=1800) // !WP8.1 - m_devicePixelRatio = qreal(resolutionScale) / 100; + hr = d->displayInformation->get_ResolutionScale(&resolutionScale); + d->scaleFactor = qreal(resolutionScale) / 100; #endif - - // Correct the scale factor for integer window size - m_devicePixelRatio = m_devicePixelRatio * ((m_geometry.width()/qRound(m_geometry.width()) + - m_geometry.height()/qRound(m_geometry.height())) / 2.0); + RETURN_OK_IF_FAILED("Failed to get scale factor"); FLOAT dpi; - hr = m_displayInformation->get_LogicalDpi(&dpi); - if (FAILED(hr)) { - qErrnoWarning(hr, "Failed to get logical DPI."); - return S_OK; - } - m_dpi = dpi; + hr = d->displayInformation->get_LogicalDpi(&dpi); + RETURN_OK_IF_FAILED("Failed to get logical DPI."); + d->logicalDpi = dpi; + + hr = d->displayInformation->get_RawDpiX(&dpi); + RETURN_OK_IF_FAILED("Failed to get x raw DPI."); + d->physicalDpi.first = dpi ? dpi : 96.0; + + hr = d->displayInformation->get_RawDpiY(&dpi); + RETURN_OK_IF_FAILED("Failed to get y raw DPI."); + d->physicalDpi.second = dpi ? dpi : 96.0; return S_OK; } @@ -1106,14 +1144,16 @@ HRESULT QWinRTScreen::onDpiChanged(IDisplayInformation *, IInspectable *) #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 = m_visibleWindows.isEmpty() + QObject *receiver = d->visibleWindows.isEmpty() ? static_cast<QObject *>(QGuiApplication::instance()) - : static_cast<QObject *>(m_visibleWindows.first()); + : static_cast<QObject *>(d->visibleWindows.first()); // If the event is ignored, the app will suspend QGuiApplication::sendEvent(receiver, &backPress); diff --git a/src/plugins/platforms/winrt/qwinrtscreen.h b/src/plugins/platforms/winrt/qwinrtscreen.h index d39683a960..6764450d84 100644 --- a/src/plugins/platforms/winrt/qwinrtscreen.h +++ b/src/plugins/platforms/winrt/qwinrtscreen.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the plugins of the Qt Toolkit. @@ -45,19 +45,12 @@ #include <qpa/qplatformscreen.h> #include <qpa/qwindowsysteminterface.h> -#include <QtCore/QHash> -#include <QtGui/QSurfaceFormat> #include <EGL/egl.h> -#include <EventToken.h> - namespace ABI { namespace Windows { namespace ApplicationModel { struct ISuspendingEventArgs; - namespace Core { - struct ICoreApplication; - } } namespace UI { namespace Core { @@ -71,14 +64,9 @@ namespace ABI { struct IWindowActivatedEventArgs; struct IWindowSizeChangedEventArgs; } - namespace ViewManagement { - struct IApplicationViewStatics; - } } namespace Graphics { namespace Display { - struct IDisplayPropertiesStatics; - struct IDisplayInformationStatics; struct IDisplayInformation; } } @@ -99,28 +87,26 @@ QT_BEGIN_NAMESPACE class QTouchDevice; class QWinRTEGLContext; -class QWinRTPageFlipper; class QWinRTCursor; class QWinRTInputContext; - +class QWinRTScreenPrivate; class QWinRTScreen : public QPlatformScreen { public: - explicit QWinRTScreen(ABI::Windows::UI::Core::ICoreWindow *window); + explicit QWinRTScreen(); + ~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 devicePixelRatio() const Q_DECL_OVERRIDE; QWinRTInputContext *inputContext() const; QPlatformCursor *cursor() const; Qt::KeyboardModifiers keyboardModifiers() const; Qt::ScreenOrientation nativeOrientation() const; Qt::ScreenOrientation orientation() const; - void setOrientationUpdateMask(Qt::ScreenOrientations mask); QWindow *topWindow() const; void addWindow(QWindow *window); @@ -135,69 +121,31 @@ public: private: void handleExpose(); - // Event handlers - QHash<QEvent::Type, EventRegistrationToken> m_tokens; - QHash<Qt::ApplicationState, EventRegistrationToken> m_suspendTokens; + HRESULT onKeyDown(ABI::Windows::UI::Core::ICoreWindow *, ABI::Windows::UI::Core::IKeyEventArgs *); + HRESULT onKeyUp(ABI::Windows::UI::Core::ICoreWindow *, ABI::Windows::UI::Core::IKeyEventArgs *); + HRESULT onCharacterReceived(ABI::Windows::UI::Core::ICoreWindow *, ABI::Windows::UI::Core::ICharacterReceivedEventArgs *); + HRESULT onPointerEntered(ABI::Windows::UI::Core::ICoreWindow *, ABI::Windows::UI::Core::IPointerEventArgs *); + HRESULT onPointerExited(ABI::Windows::UI::Core::ICoreWindow *, ABI::Windows::UI::Core::IPointerEventArgs *); + HRESULT onPointerUpdated(ABI::Windows::UI::Core::ICoreWindow *, ABI::Windows::UI::Core::IPointerEventArgs *); + HRESULT onSizeChanged(ABI::Windows::UI::Core::ICoreWindow *, ABI::Windows::UI::Core::IWindowSizeChangedEventArgs *); - HRESULT onKeyDown(ABI::Windows::UI::Core::ICoreWindow *window, ABI::Windows::UI::Core::IKeyEventArgs *args); - HRESULT onKeyUp(ABI::Windows::UI::Core::ICoreWindow *window, ABI::Windows::UI::Core::IKeyEventArgs *args); - HRESULT onCharacterReceived(ABI::Windows::UI::Core::ICoreWindow *window, ABI::Windows::UI::Core::ICharacterReceivedEventArgs *args); - HRESULT onPointerEntered(ABI::Windows::UI::Core::ICoreWindow *window, ABI::Windows::UI::Core::IPointerEventArgs *args); - HRESULT onPointerExited(ABI::Windows::UI::Core::ICoreWindow *window, ABI::Windows::UI::Core::IPointerEventArgs *args); - HRESULT onPointerUpdated(ABI::Windows::UI::Core::ICoreWindow *window, ABI::Windows::UI::Core::IPointerEventArgs *args); - HRESULT onSizeChanged(ABI::Windows::UI::Core::ICoreWindow *window, ABI::Windows::UI::Core::IWindowSizeChangedEventArgs *args); - - HRESULT onActivated(ABI::Windows::UI::Core::ICoreWindow *, ABI::Windows::UI::Core::IWindowActivatedEventArgs *args); + 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 *args); - HRESULT onVisibilityChanged(ABI::Windows::UI::Core::ICoreWindow *, ABI::Windows::UI::Core::IVisibilityChangedEventArgs *args); - HRESULT onAutomationProviderRequested(ABI::Windows::UI::Core::ICoreWindow *, ABI::Windows::UI::Core::IAutomationProviderRequestedEventArgs *args); + 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 *); -#if _MSC_VER<=1700 - HRESULT onOrientationChanged(IInspectable *); - HRESULT onDpiChanged(IInspectable *); -#else HRESULT onOrientationChanged(ABI::Windows::Graphics::Display::IDisplayInformation *, IInspectable *); HRESULT onDpiChanged(ABI::Windows::Graphics::Display::IDisplayInformation *, IInspectable *); -#endif #ifdef Q_OS_WINPHONE HRESULT onBackButtonPressed(IInspectable *, ABI::Windows::Phone::UI::Input::IBackPressedEventArgs *args); #endif - ABI::Windows::UI::Core::ICoreWindow *m_coreWindow; - ABI::Windows::UI::ViewManagement::IApplicationViewStatics *m_applicationView; - ABI::Windows::ApplicationModel::Core::ICoreApplication *m_application; - - QRectF m_geometry; - QImage::Format m_format; - QSurfaceFormat m_surfaceFormat; - qreal m_dpi; - int m_depth; - QWinRTInputContext *m_inputContext; - QWinRTCursor *m_cursor; - QList<QWindow *> m_visibleWindows; - - EGLDisplay m_eglDisplay; - EGLSurface m_eglSurface; - -#if _MSC_VER<=1700 - ABI::Windows::Graphics::Display::IDisplayPropertiesStatics *m_displayInformation; -#else - ABI::Windows::Graphics::Display::IDisplayInformationStatics *m_displayInformationFactory; - ABI::Windows::Graphics::Display::IDisplayInformation *m_displayInformation; -#endif - qreal m_devicePixelRatio; - Qt::ScreenOrientation m_nativeOrientation; - Qt::ScreenOrientation m_orientation; - -#ifndef Q_OS_WINPHONE - QHash<quint32, QPair<Qt::Key, QString> > m_activeKeys; -#endif - QTouchDevice *m_touchDevice; - QHash<quint32, QWindowSystemInterface::TouchPoint> m_touchPoints; + QScopedPointer<QWinRTScreenPrivate> d_ptr; + Q_DECLARE_PRIVATE(QWinRTScreen) }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/winrt/qwinrtservices.cpp b/src/plugins/platforms/winrt/qwinrtservices.cpp index b0f9247d36..4ee2aa68f8 100644 --- a/src/plugins/platforms/winrt/qwinrtservices.cpp +++ b/src/plugins/platforms/winrt/qwinrtservices.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the plugins of the Qt Toolkit. @@ -40,9 +40,11 @@ ****************************************************************************/ #include "qwinrtservices.h" +#include "qwinrtfileengine.h" #include <QtCore/QUrl> #include <QtCore/QDir> #include <QtCore/QCoreApplication> +#include <QtCore/qfunctions_winrt.h> #include <wrl.h> #include <windows.foundation.h> @@ -56,83 +58,90 @@ using namespace ABI::Windows::System; QT_BEGIN_NAMESPACE +class QWinRTServicesPrivate +{ +public: + ComPtr<IUriRuntimeClassFactory> uriFactory; + ComPtr<IStorageFileStatics> fileFactory; + ComPtr<ILauncherStatics> launcher; +}; + QWinRTServices::QWinRTServices() + : d_ptr(new QWinRTServicesPrivate) { - GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Foundation_Uri).Get(), &m_uriFactory); - GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Storage_StorageFile).Get(), &m_fileFactory); - GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_System_Launcher).Get(), &m_launcher); + Q_D(QWinRTServices); + + HRESULT hr; + hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Foundation_Uri).Get(), + IID_PPV_ARGS(&d->uriFactory)); + Q_ASSERT_X(SUCCEEDED(hr), Q_FUNC_INFO, qPrintable(qt_error_string(hr))); + + hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Storage_StorageFile).Get(), + IID_PPV_ARGS(&d->fileFactory)); + Q_ASSERT_X(SUCCEEDED(hr), Q_FUNC_INFO, qPrintable(qt_error_string(hr))); + + hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_System_Launcher).Get(), + IID_PPV_ARGS(&d->launcher)); + Q_ASSERT_X(SUCCEEDED(hr), Q_FUNC_INFO, qPrintable(qt_error_string(hr))); } QWinRTServices::~QWinRTServices() { - if (m_uriFactory) - m_uriFactory->Release(); - - if (m_fileFactory) - m_fileFactory->Release(); - - if (m_launcher) - m_launcher->Release(); } bool QWinRTServices::openUrl(const QUrl &url) { - if (!(m_uriFactory && m_launcher)) - return QPlatformServices::openUrl(url); + Q_D(QWinRTServices); - IUriRuntimeClass *uri; + ComPtr<IUriRuntimeClass> uri; QString urlString = url.toString(); - // ### TODO: Replace with HStringReference when WP8.0 support is removed - HString uriString; - uriString.Set((const wchar_t*)urlString.utf16(), urlString.length()); - m_uriFactory->CreateUri(uriString.Get(), &uri); - if (!uri) - return false; - - IAsyncOperation<bool> *launchOp; - m_launcher->LaunchUriAsync(uri, &launchOp); - uri->Release(); - if (!launchOp) - return false; - - boolean result = false; - while (launchOp->GetResults(&result) == E_ILLEGAL_METHOD_CALL) - QCoreApplication::processEvents(); - launchOp->Release(); + HStringReference uriString(reinterpret_cast<LPCWSTR>(urlString.utf16()), urlString.length()); + HRESULT hr = d->uriFactory->CreateUri(uriString.Get(), &uri); + RETURN_FALSE_IF_FAILED("Failed to create URI from QUrl."); + + ComPtr<IAsyncOperation<bool>> op; + hr = d->launcher->LaunchUriAsync(uri.Get(), &op); + RETURN_FALSE_IF_FAILED("Failed to start URI launch."); + + boolean result; + hr = QWinRTFunctions::await(op, &result); + RETURN_FALSE_IF_FAILED("Failed to launch URI."); return result; } bool QWinRTServices::openDocument(const QUrl &url) { - if (!(m_fileFactory && m_launcher)) - return QPlatformServices::openDocument(url); - - const QString pathString = QDir::toNativeSeparators(url.toLocalFile()); - // ### TODO: Replace with HStringReference when WP8.0 support is removed - HString path; - path.Set((const wchar_t*)pathString.utf16(), pathString.length()); - IAsyncOperation<StorageFile*> *fileOp; - m_fileFactory->GetFileFromPathAsync(path.Get(), &fileOp); - if (!fileOp) - return false; - - IStorageFile *file = nullptr; - while (fileOp->GetResults(&file) == E_ILLEGAL_METHOD_CALL) - QCoreApplication::processEvents(); - fileOp->Release(); - if (!file) - return false; - - IAsyncOperation<bool> *launchOp; - m_launcher->LaunchFileAsync(file, &launchOp); - if (!launchOp) - return false; - - boolean result = false; - while (launchOp->GetResults(&result) == E_ILLEGAL_METHOD_CALL) - QCoreApplication::processEvents(); - launchOp->Release(); + Q_D(QWinRTServices); + + HRESULT hr; + ComPtr<IStorageFile> file; + ComPtr<IStorageItem> item = QWinRTFileEngineHandler::registeredFile(url.toLocalFile()); + if (item) { + hr = item.As(&file); + if (FAILED(hr)) + qErrnoWarning(hr, "Failed to cast picked item to a file"); + } + if (!file) { + const QString pathString = QDir::toNativeSeparators(url.toLocalFile()); + HStringReference path(reinterpret_cast<LPCWSTR>(pathString.utf16()), pathString.length()); + ComPtr<IAsyncOperation<StorageFile *>> op; + hr = d->fileFactory->GetFileFromPathAsync(path.Get(), &op); + RETURN_FALSE_IF_FAILED("Failed to initialize file URI."); + + hr = QWinRTFunctions::await(op, file.GetAddressOf()); + RETURN_FALSE_IF_FAILED("Failed to get file URI."); + } + + boolean result; + { + ComPtr<IAsyncOperation<bool>> op; + hr = d->launcher->LaunchFileAsync(file.Get(), &op); + RETURN_FALSE_IF_FAILED("Failed to start file launch."); + + hr = QWinRTFunctions::await(op, &result); + RETURN_FALSE_IF_FAILED("Failed to launch file."); + } return result; } diff --git a/src/plugins/platforms/winrt/qwinrtservices.h b/src/plugins/platforms/winrt/qwinrtservices.h index 9cc917030a..d3abe6f2bd 100644 --- a/src/plugins/platforms/winrt/qwinrtservices.h +++ b/src/plugins/platforms/winrt/qwinrtservices.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the plugins of the Qt Toolkit. @@ -43,23 +43,11 @@ #define QWINRTSERVICES_H #include <qpa/qplatformservices.h> +#include <QtCore/QScopedPointer> -namespace ABI { - namespace Windows { - namespace Foundation { - struct IUriRuntimeClassFactory; - } - namespace Storage { - struct IStorageFileStatics; - } - namespace System { - struct ILauncherStatics; - } - } -} - -QT_BEGIN_NAMESPACE +QT_USE_NAMESPACE +class QWinRTServicesPrivate; class QWinRTServices : public QPlatformServices { public: @@ -70,11 +58,8 @@ public: bool openDocument(const QUrl &url); private: - ABI::Windows::Foundation::IUriRuntimeClassFactory *m_uriFactory; - ABI::Windows::Storage::IStorageFileStatics *m_fileFactory; - ABI::Windows::System::ILauncherStatics *m_launcher; + QScopedPointer<QWinRTServicesPrivate> d_ptr; + Q_DECLARE_PRIVATE(QWinRTServices) }; -QT_END_NAMESPACE - #endif // QWINRTSERVICES_H diff --git a/src/plugins/platforms/winrt/qwinrttheme.cpp b/src/plugins/platforms/winrt/qwinrttheme.cpp new file mode 100644 index 0000000000..7004abf888 --- /dev/null +++ b/src/plugins/platforms/winrt/qwinrttheme.cpp @@ -0,0 +1,259 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qwinrttheme.h" +#include "qwinrtmessagedialoghelper.h" +#include "qwinrtfiledialoghelper.h" + +#include <QtCore/qfunctions_winrt.h> +#include <QtGui/QPalette> + +#include <wrl.h> +#include <windows.ui.h> +#include <windows.ui.viewmanagement.h> +using namespace Microsoft::WRL; +using namespace ABI::Windows::UI; +using namespace ABI::Windows::UI::ViewManagement; + +QT_BEGIN_NAMESPACE + +static IUISettings *uiSettings() +{ + static ComPtr<IUISettings> settings; + if (!settings) { + HRESULT hr; + hr = RoActivateInstance(Wrappers::HString::MakeReference(RuntimeClass_Windows_UI_ViewManagement_UISettings).Get(), + &settings); + Q_ASSERT_SUCCEEDED(hr); + } + return settings.Get(); +} + +class QWinRTThemePrivate +{ +public: + QPalette palette; +}; + +static inline QColor fromColor(const Color &color) +{ + return QColor(color.R, color.G, color.B, color.A); +} + +QWinRTTheme::QWinRTTheme() + : d_ptr(new QWinRTThemePrivate) +{ + Q_D(QWinRTTheme); + + HRESULT hr; + Color color; + +#ifdef Q_OS_WINPHONE + hr = uiSettings()->UIElementColor(UIElementType_PopupBackground, &color); + Q_ASSERT_SUCCEEDED(hr); + d->palette.setColor(QPalette::ToolTipBase, fromColor(color)); + d->palette.setColor(QPalette::AlternateBase, fromColor(color)); + + hr = uiSettings()->UIElementColor(UIElementType_NonTextMedium, &color); + Q_ASSERT_SUCCEEDED(hr); + d->palette.setColor(QPalette::Button, fromColor(color)); + hr = uiSettings()->UIElementColor(UIElementType_NonTextMediumHigh, &color); + Q_ASSERT_SUCCEEDED(hr); + d->palette.setColor(QPalette::Midlight, fromColor(color)); + hr = uiSettings()->UIElementColor(UIElementType_NonTextHigh, &color); + Q_ASSERT_SUCCEEDED(hr); + d->palette.setColor(QPalette::Light, fromColor(color)); + hr = uiSettings()->UIElementColor(UIElementType_NonTextMediumLow, &color); + Q_ASSERT_SUCCEEDED(hr); + d->palette.setColor(QPalette::Mid, fromColor(color)); + hr = uiSettings()->UIElementColor(UIElementType_NonTextLow, &color); + Q_ASSERT_SUCCEEDED(hr); + d->palette.setColor(QPalette::Dark, fromColor(color)); + + hr = uiSettings()->UIElementColor(UIElementType_TextHigh, &color); + Q_ASSERT_SUCCEEDED(hr); + d->palette.setColor(QPalette::ButtonText, fromColor(color)); + d->palette.setColor(QPalette::Text, fromColor(color)); + d->palette.setColor(QPalette::WindowText, fromColor(color)); + + hr = uiSettings()->UIElementColor(UIElementType_TextMedium, &color); + Q_ASSERT_SUCCEEDED(hr); + d->palette.setColor(QPalette::ToolTipText, fromColor(color)); + + hr = uiSettings()->UIElementColor(UIElementType_AccentColor, &color); + Q_ASSERT_SUCCEEDED(hr); + d->palette.setColor(QPalette::Highlight, fromColor(color)); + + hr = uiSettings()->UIElementColor(UIElementType_PageBackground, &color); + Q_ASSERT_SUCCEEDED(hr); + d->palette.setColor(QPalette::Window, fromColor(color)); + d->palette.setColor(QPalette::Base, fromColor(color)); + + hr = uiSettings()->UIElementColor(UIElementType_TextContrastWithHigh, &color); + Q_ASSERT_SUCCEEDED(hr); + d->palette.setColor(QPalette::BrightText, fromColor(color)); +#else + hr = uiSettings()->UIElementColor(UIElementType_ActiveCaption, &color); + Q_ASSERT_SUCCEEDED(hr); + d->palette.setColor(QPalette::ToolTipBase, fromColor(color)); + + hr = uiSettings()->UIElementColor(UIElementType_Background, &color); + Q_ASSERT_SUCCEEDED(hr); + d->palette.setColor(QPalette::AlternateBase, fromColor(color)); + + hr = uiSettings()->UIElementColor(UIElementType_ButtonFace, &color); + Q_ASSERT_SUCCEEDED(hr); + d->palette.setColor(QPalette::Button, fromColor(color)); + d->palette.setColor(QPalette::Midlight, fromColor(color).lighter(110)); + d->palette.setColor(QPalette::Light, fromColor(color).lighter(150)); + d->palette.setColor(QPalette::Mid, fromColor(color).dark(130)); + d->palette.setColor(QPalette::Dark, fromColor(color).dark(150)); + + hr = uiSettings()->UIElementColor(UIElementType_ButtonText, &color); + Q_ASSERT_SUCCEEDED(hr); + d->palette.setColor(QPalette::ButtonText, fromColor(color)); + d->palette.setColor(QPalette::Text, fromColor(color)); + + hr = uiSettings()->UIElementColor(UIElementType_CaptionText, &color); + Q_ASSERT_SUCCEEDED(hr); + d->palette.setColor(QPalette::ToolTipText, fromColor(color)); + + hr = uiSettings()->UIElementColor(UIElementType_Highlight, &color); + Q_ASSERT_SUCCEEDED(hr); + d->palette.setColor(QPalette::Highlight, fromColor(color)); + + hr = uiSettings()->UIElementColor(UIElementType_HighlightText, &color); + Q_ASSERT_SUCCEEDED(hr); + d->palette.setColor(QPalette::HighlightedText, fromColor(color)); + + hr = uiSettings()->UIElementColor(UIElementType_Window, &color); + Q_ASSERT_SUCCEEDED(hr); + d->palette.setColor(QPalette::Window, fromColor(color)); + d->palette.setColor(QPalette::Base, fromColor(color)); + + hr = uiSettings()->UIElementColor(UIElementType_Hotlight, &color); + Q_ASSERT_SUCCEEDED(hr); + d->palette.setColor(QPalette::BrightText, fromColor(color)); +#endif +} + +bool QWinRTTheme::usePlatformNativeDialog(DialogType type) const +{ + static bool useNativeDialogs = qEnvironmentVariableIsSet("QT_USE_WINRT_NATIVE_DIALOGS") + ? qgetenv("QT_USE_WINRT_NATIVE_DIALOGS").toInt() : true; + + if (type == FileDialog || type == MessageDialog) + return useNativeDialogs; + return false; +} + +QPlatformDialogHelper *QWinRTTheme::createPlatformDialogHelper(DialogType type) const +{ + switch (type) { + case FileDialog: + return new QWinRTFileDialogHelper; + case MessageDialog: + return new QWinRTMessageDialogHelper(this); + default: + break; + } + return QPlatformTheme::createPlatformDialogHelper(type); +} + +QVariant QWinRTTheme::styleHint(QPlatformIntegration::StyleHint hint) +{ + HRESULT hr; + switch (hint) { + case QPlatformIntegration::CursorFlashTime: { + quint32 blinkRate; + hr = uiSettings()->get_CaretBlinkRate(&blinkRate); + RETURN_IF_FAILED("Failed to get caret blink rate", return defaultThemeHint(CursorFlashTime)); + return blinkRate; + } + case QPlatformIntegration::KeyboardInputInterval: + return defaultThemeHint(KeyboardInputInterval); + case QPlatformIntegration::MouseDoubleClickInterval: { + quint32 doubleClickTime; + hr = uiSettings()->get_DoubleClickTime(&doubleClickTime); + RETURN_IF_FAILED("Failed to get double click time", return defaultThemeHint(MouseDoubleClickInterval)); + return doubleClickTime; + } + case QPlatformIntegration::StartDragDistance: + return defaultThemeHint(StartDragDistance); + case QPlatformIntegration::StartDragTime: + return defaultThemeHint(StartDragTime); + case QPlatformIntegration::KeyboardAutoRepeatRate: + return defaultThemeHint(KeyboardAutoRepeatRate); + case QPlatformIntegration::ShowIsFullScreen: + return true; + case QPlatformIntegration::PasswordMaskDelay: + return defaultThemeHint(PasswordMaskDelay); + case QPlatformIntegration::FontSmoothingGamma: + return qreal(1.7); + case QPlatformIntegration::StartDragVelocity: + return defaultThemeHint(StartDragVelocity); + case QPlatformIntegration::UseRtlExtensions: + return false; + case QPlatformIntegration::SynthesizeMouseFromTouchEvents: + return true; + case QPlatformIntegration::PasswordMaskCharacter: + return defaultThemeHint(PasswordMaskCharacter); + case QPlatformIntegration::SetFocusOnTouchRelease: + return false; + case QPlatformIntegration::ShowIsMaximized: + return false; + case MousePressAndHoldInterval: + return defaultThemeHint(MousePressAndHoldInterval); + default: + break; + } + return QVariant(); +} + +const QPalette *QWinRTTheme::palette(Palette type) const +{ + Q_D(const QWinRTTheme); + if (type == SystemPalette) + return &d->palette; + return QPlatformTheme::palette(type); +} + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/winrt/qwinrtplatformtheme.h b/src/plugins/platforms/winrt/qwinrttheme.h index f4a61982b2..f7fd07c70d 100644 --- a/src/plugins/platforms/winrt/qwinrtplatformtheme.h +++ b/src/plugins/platforms/winrt/qwinrttheme.h @@ -39,22 +39,32 @@ ** ****************************************************************************/ -#ifndef QWINRTPLATFORMTHEME_H -#define QWINRTPLATFORMTHEME_H +#ifndef QWINRTTHEME_H +#define QWINRTTHEME_H #include <qpa/qplatformtheme.h> +#include <qpa/qplatformintegration.h> QT_BEGIN_NAMESPACE -class QWinRTPlatformTheme : public QPlatformTheme +class QWinRTThemePrivate; +class QWinRTTheme : public QPlatformTheme { public: - QWinRTPlatformTheme(); + QWinRTTheme(); bool usePlatformNativeDialog(DialogType type) const; QPlatformDialogHelper *createPlatformDialogHelper(DialogType type) const; + + const QPalette *palette(Palette type = SystemPalette) const Q_DECL_OVERRIDE; + + static QVariant styleHint(QPlatformIntegration::StyleHint hint); + +private: + QScopedPointer<QWinRTThemePrivate> d_ptr; + Q_DECLARE_PRIVATE(QWinRTTheme) }; QT_END_NAMESPACE -#endif // QWINRTPLATFORMTHEME_H +#endif // QWINRTTHEME_H diff --git a/src/plugins/platforms/winrt/winrt.pro b/src/plugins/platforms/winrt/winrt.pro index 349cdf11c9..80429daeed 100644 --- a/src/plugins/platforms/winrt/winrt.pro +++ b/src/plugins/platforms/winrt/winrt.pro @@ -32,48 +32,37 @@ SOURCES = \ qwinrtcursor.cpp \ qwinrteglcontext.cpp \ qwinrteventdispatcher.cpp \ + qwinrtfiledialoghelper.cpp \ + qwinrtfileengine.cpp \ qwinrtfontdatabase.cpp \ qwinrtinputcontext.cpp \ qwinrtintegration.cpp \ - qwinrtplatformmessagedialoghelper.cpp \ - qwinrtplatformtheme.cpp \ + qwinrtmessagedialoghelper.cpp \ qwinrtscreen.cpp \ qwinrtservices.cpp \ + qwinrttheme.cpp \ qwinrtwindow.cpp + HEADERS = \ qwinrtbackingstore.h \ qwinrtcursor.h \ qwinrteglcontext.h \ qwinrteventdispatcher.h \ + qwinrtfiledialoghelper.h \ + qwinrtfileengine.h \ qwinrtfontdatabase.h \ qwinrtinputcontext.h \ qwinrtintegration.h \ - qwinrtplatformmessagedialoghelper.h \ - qwinrtplatformtheme.h \ + qwinrtmessagedialoghelper.h \ qwinrtscreen.h \ qwinrtservices.h \ + qwinrttheme.h \ qwinrtwindow.h -BLIT_INPUT = $$PWD/blit.hlsl -fxc_blitps.commands = fxc.exe /nologo /T ps_4_0_level_9_1 /E blitps /Vn q_blitps /Fh ${QMAKE_FILE_OUT} ${QMAKE_FILE_NAME} -fxc_blitps.output = $$OUT_PWD/blitps.h -fxc_blitps.input = BLIT_INPUT -fxc_blitps.dependency_type = TYPE_C -fxc_blitps.variable_out = HEADERS -fxc_blitps.CONFIG += target_predeps -fxc_blitvs.commands = fxc.exe /nologo /T vs_4_0_level_9_1 /E blitvs /Vn q_blitvs /Fh ${QMAKE_FILE_OUT} ${QMAKE_FILE_NAME} -fxc_blitvs.output = $$OUT_PWD/blitvs.h -fxc_blitvs.input = BLIT_INPUT -fxc_blitvs.dependency_type = TYPE_C -fxc_blitvs.variable_out = HEADERS -fxc_blitvs.CONFIG += target_predeps -QMAKE_EXTRA_COMPILERS += fxc_blitps fxc_blitvs - winphone:equals(WINSDK_VER, 8.0): { SOURCES -= qwinrtplatformmessagedialoghelper.cpp HEADERS -= qwinrtplatformmessagedialoghelper.h } -OTHER_FILES += winrt.json \ - blit.hlsl +OTHER_FILES += winrt.json |