summaryrefslogtreecommitdiffstats
path: root/src/plugins/platforms
diff options
context:
space:
mode:
authorLiang Qi <liang.qi@qt.io>2016-06-06 08:34:03 +0200
committerLiang Qi <liang.qi@qt.io>2016-06-06 09:04:55 +0200
commit57057f76add416d0faf2e09a90c126baafb6198e (patch)
tree07d54f8e5daeb3ed1161723542e94c324d745166 /src/plugins/platforms
parentdc0ae02ebc8e221f952829230c0301a718a6f10b (diff)
parentfd70978693bd92761e9989bc1c76bf83c1e8c987 (diff)
Merge remote-tracking branch 'origin/5.6' into 5.7
Conflicts: .qmake.conf config.tests/unix/nis/nis.cpp mkspecs/unsupported/freebsd-g++/qplatformdefs.h src/corelib/tools/qdatetime.cpp src/corelib/tools/qsimd.cpp src/corelib/tools/qsimd_p.h src/network/access/access.pri src/network/access/qnetworkreplynsurlconnectionimpl.mm src/network/access/qnetworkreplynsurlconnectionimpl_p.h src/plugins/platforms/cocoa/qnsview.mm src/plugins/printsupport/windows/qwindowsprintdevice.cpp tests/auto/corelib/kernel/qobject/tst_qobject.cpp tests/auto/network/access/qnetworkreply/BLACKLIST tests/auto/widgets/widgets/qopenglwidget/BLACKLIST Change-Id: I4b32055bbf922392ef0264fd403405416fffee57
Diffstat (limited to 'src/plugins/platforms')
-rw-r--r--src/plugins/platforms/cocoa/qcocoawindow.mm8
-rw-r--r--src/plugins/platforms/cocoa/qnsview.mm18
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmcursor.cpp2
-rw-r--r--src/plugins/platforms/ios/qiosinputcontext.h5
-rw-r--r--src/plugins/platforms/ios/qiosinputcontext.mm40
-rw-r--r--src/plugins/platforms/ios/qiostextresponder.mm1
-rw-r--r--src/plugins/platforms/minimal/minimal.pro1
-rw-r--r--src/plugins/platforms/platforms.pro4
-rw-r--r--src/plugins/platforms/windows/qwindowseglcontext.cpp67
-rw-r--r--src/plugins/platforms/windows/qwindowseglcontext.h2
-rw-r--r--src/plugins/platforms/windows/qwindowsfontengine.cpp6
-rw-r--r--src/plugins/platforms/windows/qwindowstheme.cpp11
-rw-r--r--src/plugins/platforms/windows/qwindowswindow.cpp7
-rw-r--r--src/plugins/platforms/winrt/qwinrtdrag.cpp893
-rw-r--r--src/plugins/platforms/winrt/qwinrtdrag.h113
-rw-r--r--src/plugins/platforms/winrt/qwinrtintegration.cpp14
-rw-r--r--src/plugins/platforms/winrt/qwinrtintegration.h4
-rw-r--r--src/plugins/platforms/winrt/qwinrtscreen.cpp18
-rw-r--r--src/plugins/platforms/winrt/winrt.pro11
-rw-r--r--src/plugins/platforms/xcb/qxcbconnection.cpp2
20 files changed, 1186 insertions, 41 deletions
diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm
index eaa0170748..91ce91004f 100644
--- a/src/plugins/platforms/cocoa/qcocoawindow.mm
+++ b/src/plugins/platforms/cocoa/qcocoawindow.mm
@@ -153,7 +153,7 @@ static bool isMouseEvent(NSEvent *ev)
if (NSMouseInRect(loc, windowFrame, NO) &&
!NSMouseInRect(loc, contentFrame, NO))
{
- QNSView *contentView = (QNSView *)pw->contentView();
+ QNSView *contentView = pw->m_qtView;
[contentView handleFrameStrutMouseEvent: theEvent];
}
}
@@ -1188,7 +1188,11 @@ NSView *QCocoaWindow::contentView() const
void QCocoaWindow::setContentView(NSView *contentView)
{
// Remove and release the previous content view
- [m_contentView removeFromSuperview];
+ if (m_nsWindow)
+ [m_nsWindow setContentView:nil];
+ else
+ [m_contentView removeFromSuperview];
+
[m_contentView release];
// Insert and retain the new content view
diff --git a/src/plugins/platforms/cocoa/qnsview.mm b/src/plugins/platforms/cocoa/qnsview.mm
index 5972cf9504..3469166fdc 100644
--- a/src/plugins/platforms/cocoa/qnsview.mm
+++ b/src/plugins/platforms/cocoa/qnsview.mm
@@ -663,7 +663,9 @@ QT_WARNING_POP
- (BOOL)becomeFirstResponder
{
- if (m_window && (m_window->flags() & Qt::WindowTransparentForInput) )
+ if (!m_window || !m_platformWindow)
+ return NO;
+ if (m_window->flags() & Qt::WindowTransparentForInput)
return NO;
if (!m_platformWindow->windowIsPopupType() && !m_isMenuView)
QWindowSystemInterface::handleWindowActivated([self topLevelWindow]);
@@ -672,11 +674,13 @@ QT_WARNING_POP
- (BOOL)acceptsFirstResponder
{
+ if (!m_window || !m_platformWindow)
+ return NO;
if (m_isMenuView)
return NO;
if (m_platformWindow->shouldRefuseKeyWindowAndFirstResponder())
return NO;
- if (m_window && (m_window->flags() & Qt::WindowTransparentForInput) )
+ if (m_window->flags() & Qt::WindowTransparentForInput)
return NO;
if ((m_window->flags() & Qt::ToolTip) == Qt::ToolTip)
return NO;
@@ -686,7 +690,9 @@ QT_WARNING_POP
- (BOOL)acceptsFirstMouse:(NSEvent *)theEvent
{
Q_UNUSED(theEvent)
- if (m_window && (m_window->flags() & Qt::WindowTransparentForInput) )
+ if (!m_window || !m_platformWindow)
+ return NO;
+ if (m_window->flags() & Qt::WindowTransparentForInput)
return NO;
return YES;
}
@@ -2199,7 +2205,11 @@ static QPoint mapWindowCoordinates(QWindow *source, QWindow *target, QPoint poin
// keep our state, and QGuiApplication state (buttons member) in-sync,
// or future mouse events will be processed incorrectly
- m_buttons &= ~(m_sendUpAsRightButton ? Qt::RightButton : Qt::LeftButton);
+ NSUInteger pmb = [NSEvent pressedMouseButtons];
+ for (int buttonNumber = 0; buttonNumber < 32; buttonNumber++) { // see cocoaButton2QtButton() for the 32 value
+ if (!(pmb & (1 << buttonNumber)))
+ m_buttons &= ~cocoaButton2QtButton(buttonNumber);
+ }
NSPoint windowPoint = [self convertPoint: point fromView: nil];
QPoint qtWindowPoint(windowPoint.x, windowPoint.y);
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmcursor.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmcursor.cpp
index abff88b4bd..5b779d6732 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmcursor.cpp
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmcursor.cpp
@@ -132,7 +132,7 @@ void QEglFSKmsGbmCursor::updateMouseStatus()
m_state = visible ? CursorPendingVisible : CursorPendingHidden;
#ifndef QT_NO_CURSOR
- changeCursor(nullptr, m_screen->topLevelAt(pos()));
+ changeCursor(Q_NULLPTR, m_screen->topLevelAt(pos()));
#endif
}
diff --git a/src/plugins/platforms/ios/qiosinputcontext.h b/src/plugins/platforms/ios/qiosinputcontext.h
index 82bcf48855..2b0643f26e 100644
--- a/src/plugins/platforms/ios/qiosinputcontext.h
+++ b/src/plugins/platforms/ios/qiosinputcontext.h
@@ -42,6 +42,7 @@
#include <UIKit/UIKit.h>
+#include <QtCore/qlocale.h>
#include <QtGui/qevent.h>
#include <QtGui/qtransform.h>
#include <qpa/qplatforminputcontext.h>
@@ -52,6 +53,7 @@ const char kImePlatformDataReturnKeyType[] = "returnKeyType";
QT_BEGIN_NAMESPACE
+@class QIOSLocaleListener;
@class QIOSKeyboardListener;
@class QIOSTextInputResponder;
@protocol KeyboardState;
@@ -98,6 +100,8 @@ public:
void reset() Q_DECL_OVERRIDE;
void commit() Q_DECL_OVERRIDE;
+ QLocale locale() const Q_DECL_OVERRIDE;
+
void clearCurrentFocusObject();
void setFocusObject(QObject *object) Q_DECL_OVERRIDE;
@@ -118,6 +122,7 @@ public:
private:
UIView* scrollableRootView();
+ QIOSLocaleListener *m_localeListener;
QIOSKeyboardListener *m_keyboardHideGesture;
QIOSTextInputResponder *m_textResponder;
KeyboardState m_keyboardState;
diff --git a/src/plugins/platforms/ios/qiosinputcontext.mm b/src/plugins/platforms/ios/qiosinputcontext.mm
index d553d16698..ef93d68cf0 100644
--- a/src/plugins/platforms/ios/qiosinputcontext.mm
+++ b/src/plugins/platforms/ios/qiosinputcontext.mm
@@ -62,6 +62,39 @@ static QUIView *focusView()
// -------------------------------------------------------------------------
+@interface QIOSLocaleListener : NSObject
+@end
+
+@implementation QIOSLocaleListener
+
+- (id)init
+{
+ if (self = [super init]) {
+ NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
+ [notificationCenter addObserver:self
+ selector:@selector(localeDidChange:)
+ name:NSCurrentLocaleDidChangeNotification object:nil];
+ }
+
+ return self;
+}
+
+- (void)dealloc
+{
+ [[NSNotificationCenter defaultCenter] removeObserver:self];
+ [super dealloc];
+}
+
+- (void)localeDidChange:(NSNotification *)notification
+{
+ Q_UNUSED(notification);
+ QIOSInputContext::instance()->emitLocaleChanged();
+}
+
+@end
+
+// -------------------------------------------------------------------------
+
@interface QIOSKeyboardListener : UIGestureRecognizer <UIGestureRecognizerDelegate> {
@private
QIOSInputContext *m_context;
@@ -291,6 +324,7 @@ QIOSInputContext *QIOSInputContext::instance()
QIOSInputContext::QIOSInputContext()
: QPlatformInputContext()
+ , m_localeListener([QIOSLocaleListener new])
, m_keyboardHideGesture([[QIOSKeyboardListener alloc] initWithQIOSInputContext:this])
, m_textResponder(0)
{
@@ -304,6 +338,7 @@ QIOSInputContext::QIOSInputContext()
QIOSInputContext::~QIOSInputContext()
{
+ [m_localeListener release];
[m_keyboardHideGesture.view removeGestureRecognizer:m_keyboardHideGesture];
[m_keyboardHideGesture release];
@@ -663,3 +698,8 @@ void QIOSInputContext::commit()
[m_textResponder unmarkText];
[m_textResponder notifyInputDelegate:Qt::ImSurroundingText];
}
+
+QLocale QIOSInputContext::locale() const
+{
+ return QLocale(QString::fromNSString([[NSLocale currentLocale] objectForKey:NSLocaleIdentifier]));
+}
diff --git a/src/plugins/platforms/ios/qiostextresponder.mm b/src/plugins/platforms/ios/qiostextresponder.mm
index eb12739e98..37d5557794 100644
--- a/src/plugins/platforms/ios/qiostextresponder.mm
+++ b/src/plugins/platforms/ios/qiostextresponder.mm
@@ -359,6 +359,7 @@
- (void)sendKeyPressRelease:(Qt::Key)key modifiers:(Qt::KeyboardModifiers)modifiers
{
+ QScopedValueRollback<BOOL> rollback(m_inSendEventToFocusObject, true);
QWindowSystemInterface::handleKeyEvent(qApp->focusWindow(), QEvent::KeyPress, key, modifiers);
QWindowSystemInterface::handleKeyEvent(qApp->focusWindow(), QEvent::KeyRelease, key, modifiers);
QWindowSystemInterface::flushWindowSystemEvents();
diff --git a/src/plugins/platforms/minimal/minimal.pro b/src/plugins/platforms/minimal/minimal.pro
index 0d31d6605b..bd6f2d8e6f 100644
--- a/src/plugins/platforms/minimal/minimal.pro
+++ b/src/plugins/platforms/minimal/minimal.pro
@@ -11,6 +11,7 @@ HEADERS = qminimalintegration.h \
OTHER_FILES += minimal.json
CONFIG += qpa/genericunixfontdatabase
+darwin: DEFINES += QT_NO_FONTCONFIG
PLUGIN_TYPE = platforms
PLUGIN_CLASS_NAME = QMinimalIntegrationPlugin
diff --git a/src/plugins/platforms/platforms.pro b/src/plugins/platforms/platforms.pro
index cb3764f5df..a5b64636af 100644
--- a/src/plugins/platforms/platforms.pro
+++ b/src/plugins/platforms/platforms.pro
@@ -2,9 +2,9 @@ TEMPLATE = subdirs
android: SUBDIRS += android
-SUBDIRS += minimal
+!android: SUBDIRS += minimal
-!win32|contains(QT_CONFIG, freetype):SUBDIRS += offscreen
+!android:if(!win32|contains(QT_CONFIG, freetype)): SUBDIRS += offscreen
contains(QT_CONFIG, xcb) {
SUBDIRS += xcb
diff --git a/src/plugins/platforms/windows/qwindowseglcontext.cpp b/src/plugins/platforms/windows/qwindowseglcontext.cpp
index a3f9f0b44b..0ce4e87e52 100644
--- a/src/plugins/platforms/windows/qwindowseglcontext.cpp
+++ b/src/plugins/platforms/windows/qwindowseglcontext.cpp
@@ -205,26 +205,9 @@ QWindowsEGLStaticContext::QWindowsEGLStaticContext(EGLDisplay display)
{
}
-QWindowsEGLStaticContext *QWindowsEGLStaticContext::create(QWindowsOpenGLTester::Renderers preferredType)
+bool QWindowsEGLStaticContext::initializeAngle(QWindowsOpenGLTester::Renderers preferredType, HDC dc,
+ EGLDisplay *display, EGLint *major, EGLint *minor)
{
- const HDC dc = QWindowsContext::instance()->displayContext();
- if (!dc){
- qWarning("%s: No Display", __FUNCTION__);
- return 0;
- }
-
- if (!libEGL.init()) {
- qWarning("%s: Failed to load and resolve libEGL functions", __FUNCTION__);
- return 0;
- }
- if (!libGLESv2.init()) {
- qWarning("%s: Failed to load and resolve libGLESv2 functions", __FUNCTION__);
- return 0;
- }
-
- EGLDisplay display = EGL_NO_DISPLAY;
- EGLint major = 0;
- EGLint minor = 0;
#ifdef EGL_ANGLE_platform_angle
if (libEGL.eglGetPlatformDisplayEXT
&& (preferredType & QWindowsOpenGLTester::AngleBackendMask)) {
@@ -242,16 +225,52 @@ QWindowsEGLStaticContext *QWindowsEGLStaticContext::create(QWindowsOpenGLTester:
else if (preferredType & QWindowsOpenGLTester::AngleRendererD3d11Warp)
attributes = anglePlatformAttributes[2];
if (attributes) {
- display = libEGL.eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE, dc, attributes);
- if (!libEGL.eglInitialize(display, &major, &minor)) {
- display = EGL_NO_DISPLAY;
- major = minor = 0;
+ *display = libEGL.eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE, dc, attributes);
+ if (!libEGL.eglInitialize(*display, major, minor)) {
+ libEGL.eglTerminate(*display);
+ *display = EGL_NO_DISPLAY;
+ *major = *minor = 0;
+ return false;
}
}
}
#else // EGL_ANGLE_platform_angle
- Q_UNUSED(preferredType)
+ Q_UNUSED(preferredType);
+ Q_UNUSED(dc);
+ Q_UNUSED(display);
+ Q_UNUSED(major);
+ Q_UNUSED(minor);
#endif
+ return true;
+}
+
+QWindowsEGLStaticContext *QWindowsEGLStaticContext::create(QWindowsOpenGLTester::Renderers preferredType)
+{
+ const HDC dc = QWindowsContext::instance()->displayContext();
+ if (!dc){
+ qWarning("%s: No Display", __FUNCTION__);
+ return 0;
+ }
+
+ if (!libEGL.init()) {
+ qWarning("%s: Failed to load and resolve libEGL functions", __FUNCTION__);
+ return 0;
+ }
+ if (!libGLESv2.init()) {
+ qWarning("%s: Failed to load and resolve libGLESv2 functions", __FUNCTION__);
+ return 0;
+ }
+
+ EGLDisplay display = EGL_NO_DISPLAY;
+ EGLint major = 0;
+ EGLint minor = 0;
+
+ if (!initializeAngle(preferredType, dc, &display, &major, &minor)
+ && (preferredType & QWindowsOpenGLTester::AngleRendererD3d11)) {
+ preferredType &= ~QWindowsOpenGLTester::AngleRendererD3d11;
+ initializeAngle(preferredType, dc, &display, &major, &minor);
+ }
+
if (display == EGL_NO_DISPLAY)
display = libEGL.eglGetDisplay(dc);
if (!display) {
diff --git a/src/plugins/platforms/windows/qwindowseglcontext.h b/src/plugins/platforms/windows/qwindowseglcontext.h
index c7f7cee3c2..48a19f81e5 100644
--- a/src/plugins/platforms/windows/qwindowseglcontext.h
+++ b/src/plugins/platforms/windows/qwindowseglcontext.h
@@ -131,6 +131,8 @@ public:
private:
explicit QWindowsEGLStaticContext(EGLDisplay display);
+ static bool initializeAngle(QWindowsOpenGLTester::Renderers preferredType, HDC dc,
+ EGLDisplay *display, EGLint *major, EGLint *minor);
const EGLDisplay m_display;
};
diff --git a/src/plugins/platforms/windows/qwindowsfontengine.cpp b/src/plugins/platforms/windows/qwindowsfontengine.cpp
index 806af6458b..4f3df32f16 100644
--- a/src/plugins/platforms/windows/qwindowsfontengine.cpp
+++ b/src/plugins/platforms/windows/qwindowsfontengine.cpp
@@ -1346,8 +1346,7 @@ QFontEngine *QWindowsMultiFontEngine::loadEngine(int at)
QWindowsFontEngineDirectWrite *fedw = new QWindowsFontEngineDirectWrite(directWriteFontFace,
fontEngine->fontDef.pixelSize,
data);
- if (fontEngine->fontDef.weight > QFont::Normal)
- fedw->fontDef.weight = fontEngine->fontDef.weight;
+ fedw->fontDef.weight = fontEngine->fontDef.weight;
if (fontEngine->fontDef.style > QFont::StyleNormal)
fedw->fontDef.style = fontEngine->fontDef.style;
fedw->fontDef.family = fam;
@@ -1364,8 +1363,7 @@ QFontEngine *QWindowsMultiFontEngine::loadEngine(int at)
// reason
QFontEngine *fe = new QWindowsFontEngine(fam, lf, data);
- if (fontEngine->fontDef.weight > QFont::Normal)
- fe->fontDef.weight = fontEngine->fontDef.weight;
+ fe->fontDef.weight = fontEngine->fontDef.weight;
if (fontEngine->fontDef.style > QFont::StyleNormal)
fe->fontDef.style = fontEngine->fontDef.style;
fe->fontDef.family = fam;
diff --git a/src/plugins/platforms/windows/qwindowstheme.cpp b/src/plugins/platforms/windows/qwindowstheme.cpp
index 96940f3f4c..4bf424f5f6 100644
--- a/src/plugins/platforms/windows/qwindowstheme.cpp
+++ b/src/plugins/platforms/windows/qwindowstheme.cpp
@@ -138,7 +138,16 @@ public:
explicit ShGetFileInfoFunction(const wchar_t *fn, DWORD a, SHFILEINFO *i, UINT f, bool *r) :
m_fileName(fn), m_attributes(a), m_flags(f), m_info(i), m_result(r) {}
- void operator()() const { *m_result = SHGetFileInfo(m_fileName, m_attributes, m_info, sizeof(SHFILEINFO), m_flags); }
+ void operator()() const
+ {
+#ifndef Q_OS_WINCE
+ const UINT oldErrorMode = SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
+#endif
+ *m_result = SHGetFileInfo(m_fileName, m_attributes, m_info, sizeof(SHFILEINFO), m_flags);
+#ifndef Q_OS_WINCE
+ SetErrorMode(oldErrorMode);
+#endif
+ }
private:
const wchar_t *m_fileName;
diff --git a/src/plugins/platforms/windows/qwindowswindow.cpp b/src/plugins/platforms/windows/qwindowswindow.cpp
index 31c9984559..76a36851ce 100644
--- a/src/plugins/platforms/windows/qwindowswindow.cpp
+++ b/src/plugins/platforms/windows/qwindowswindow.cpp
@@ -1677,11 +1677,12 @@ bool QWindowsWindow::handleWmPaint(HWND hwnd, UINT message,
return false;
PAINTSTRUCT ps;
+ BeginPaint(hwnd, &ps);
+
// Observed painting problems with Aero style disabled (QTBUG-7865).
+ // 5.8: Consider making it dependent on !DwmIsCompositionEnabled().
if (testFlag(OpenGLSurface) && testFlag(OpenGLDoubleBuffered))
- InvalidateRect(hwnd, 0, false);
-
- BeginPaint(hwnd, &ps);
+ SelectClipRgn(ps.hdc, NULL);
// If the a window is obscured by another window (such as a child window)
// we still need to send isExposed=true, for compatibility.
diff --git a/src/plugins/platforms/winrt/qwinrtdrag.cpp b/src/plugins/platforms/winrt/qwinrtdrag.cpp
new file mode 100644
index 0000000000..2ef50aa4e2
--- /dev/null
+++ b/src/plugins/platforms/winrt/qwinrtdrag.cpp
@@ -0,0 +1,893 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include "qwinrtdrag.h"
+
+#include <QtCore/qglobal.h>
+#include <QtCore/QMimeData>
+#include <QtCore/QStringList>
+#include <QtGui/QGuiApplication>
+#include <qpa/qwindowsysteminterface.h>
+
+#include <qfunctions_winrt.h>
+#include <private/qeventdispatcher_winrt_p.h>
+
+#include <Windows.ApplicationModel.datatransfer.h>
+#include <windows.ui.xaml.h>
+#include <windows.foundation.collections.h>
+#include <windows.graphics.imaging.h>
+#include <windows.storage.streams.h>
+#include <functional>
+#include <robuffer.h>
+
+using namespace ABI::Windows::ApplicationModel::DataTransfer;
+using namespace ABI::Windows::ApplicationModel::DataTransfer::DragDrop;
+using namespace ABI::Windows::Foundation;
+using namespace ABI::Windows::Foundation::Collections;
+using namespace ABI::Windows::Graphics::Imaging;
+using namespace ABI::Windows::Storage;
+using namespace ABI::Windows::Storage::Streams;
+using namespace ABI::Windows::UI::Xaml;
+using namespace Microsoft::WRL;
+using namespace Microsoft::WRL::Wrappers;
+
+QT_BEGIN_NAMESPACE
+
+Q_LOGGING_CATEGORY(lcQpaMime, "qt.qpa.mime")
+
+ComPtr<IBuffer> createIBufferFromData(const char *data, qint32 size)
+{
+ static ComPtr<IBufferFactory> bufferFactory;
+ HRESULT hr;
+ if (!bufferFactory) {
+ hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Storage_Streams_Buffer).Get(),
+ IID_PPV_ARGS(&bufferFactory));
+ Q_ASSERT_SUCCEEDED(hr);
+ }
+
+ ComPtr<IBuffer> buffer;
+ const UINT32 length = size;
+ hr = bufferFactory->Create(length, &buffer);
+ Q_ASSERT_SUCCEEDED(hr);
+ hr = buffer->put_Length(length);
+ Q_ASSERT_SUCCEEDED(hr);
+
+ ComPtr<Windows::Storage::Streams::IBufferByteAccess> byteArrayAccess;
+ hr = buffer.As(&byteArrayAccess);
+ Q_ASSERT_SUCCEEDED(hr);
+
+ byte *bytes;
+ hr = byteArrayAccess->Buffer(&bytes);
+ Q_ASSERT_SUCCEEDED(hr);
+ memcpy(bytes, data, length);
+ return buffer;
+}
+
+class DragThreadTransferData : public QObject
+{
+ Q_OBJECT
+public slots:
+ void handleDrag();
+public:
+ explicit DragThreadTransferData(QObject *parent = Q_NULLPTR);
+ QWindow *window;
+ QWinRTInternalMimeData *mime;
+ QPoint point;
+ Qt::DropActions actions;
+ bool dropAction;
+ ComPtr<IDragEventArgs> nativeArgs;
+ ComPtr<IDragOperationDeferral> deferral;
+};
+
+inline QString hStringToQString(const HString &hString)
+{
+ quint32 l;
+ const wchar_t *raw = hString.GetRawBuffer(&l);
+ return (QString::fromWCharArray(raw, l));
+}
+
+inline HString qStringToHString(const QString &qString)
+{
+ HString h;
+ h.Set(reinterpret_cast<const wchar_t*>(qString.utf16()), qString.size());
+ return h;
+}
+
+namespace NativeFormatStrings {
+ static ComPtr<IStandardDataFormatsStatics> dataStatics;
+ static HSTRING text; // text/plain
+ static HSTRING html; // text/html
+ static HSTRING storage; // text/uri-list
+}
+
+static inline DataPackageOperation translateFromQDragDropActions(const Qt::DropAction action)
+{
+ switch (action) {
+ case Qt::CopyAction:
+ return DataPackageOperation_Copy;
+ case Qt::MoveAction:
+ return DataPackageOperation_Move;
+ case Qt::LinkAction:
+ return DataPackageOperation_Link;
+ case Qt::IgnoreAction:
+ default:
+ return DataPackageOperation_None;
+ }
+}
+
+static inline Qt::DropActions translateToQDragDropActions(const DataPackageOperation op)
+{
+ Qt::DropActions actions = Qt::IgnoreAction;
+ // None needs to be interpreted as the sender being able to handle
+ // anything and let the receiver decide
+ if (op == DataPackageOperation_None)
+ actions = Qt::LinkAction | Qt::CopyAction | Qt::MoveAction;
+ if (op & DataPackageOperation_Link)
+ actions |= Qt::LinkAction;
+ if (op & DataPackageOperation_Copy)
+ actions |= Qt::CopyAction;
+ if (op & DataPackageOperation_Move)
+ actions |= Qt::MoveAction;
+ return actions;
+}
+
+QWinRTInternalMimeData::QWinRTInternalMimeData()
+ : QInternalMimeData()
+{
+ qCDebug(lcQpaMime) << __FUNCTION__;
+ if (!NativeFormatStrings::dataStatics) {
+ HRESULT hr;
+ hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_ApplicationModel_DataTransfer_StandardDataFormats).Get(),
+ IID_PPV_ARGS(&NativeFormatStrings::dataStatics));
+ Q_ASSERT_SUCCEEDED(hr);
+ hr = NativeFormatStrings::dataStatics->get_Text(&NativeFormatStrings::text);
+ Q_ASSERT_SUCCEEDED(hr);
+ hr = NativeFormatStrings::dataStatics->get_Html(&NativeFormatStrings::html);
+ Q_ASSERT_SUCCEEDED(hr);
+ hr = NativeFormatStrings::dataStatics->get_StorageItems(&NativeFormatStrings::storage);
+ Q_ASSERT_SUCCEEDED(hr);
+ }
+}
+
+QWinRTInternalMimeData::~QWinRTInternalMimeData()
+{
+}
+
+bool QWinRTInternalMimeData::hasFormat_sys(const QString &mimetype) const
+{
+ qCDebug(lcQpaMime) << __FUNCTION__ << mimetype;
+
+ if (!dataView)
+ return false;
+
+ return formats_sys().contains(mimetype);
+}
+
+QStringList QWinRTInternalMimeData::formats_sys() const
+{
+ qCDebug(lcQpaMime) << __FUNCTION__;
+
+ if (!dataView)
+ return QStringList();
+
+ if (!formats.isEmpty())
+ return formats;
+
+ HRESULT hr;
+ hr = QEventDispatcherWinRT::runOnXamlThread([this]() {
+ boolean contains;
+ HRESULT hr;
+ hr = dataView->Contains(NativeFormatStrings::text, &contains);
+ if (SUCCEEDED(hr) && contains)
+ formats.append(QLatin1String("text/plain"));
+
+ hr = dataView->Contains(NativeFormatStrings::html, &contains);
+ if (SUCCEEDED(hr) && contains)
+ formats.append(QLatin1String("text/html"));
+
+ hr = dataView->Contains(NativeFormatStrings::storage, &contains);
+ if (SUCCEEDED(hr) && contains)
+ formats.append(QLatin1String("text/uri-list"));
+
+ // We need to add any additional format as well, for legacy windows
+ // reasons, but also in case someone adds custom formats.
+ ComPtr<IVectorView<HSTRING>> availableFormats;
+ hr = dataView->get_AvailableFormats(&availableFormats);
+ RETURN_OK_IF_FAILED("Could not query available formats.");
+
+ quint32 size;
+ hr = availableFormats->get_Size(&size);
+ RETURN_OK_IF_FAILED("Could not query format vector size.");
+ for (quint32 i = 0; i < size; ++i) {
+ HString str;
+ hr = availableFormats->GetAt(i, str.GetAddressOf());
+ if (FAILED(hr))
+ continue;
+ formats.append(hStringToQString(str));
+ }
+ return S_OK;
+ });
+ Q_ASSERT_SUCCEEDED(hr);
+
+ return formats;
+}
+
+QVariant QWinRTInternalMimeData::retrieveData_sys(const QString &mimetype, QVariant::Type preferredType) const
+{
+ qCDebug(lcQpaMime) << __FUNCTION__ << mimetype << preferredType;
+
+ if (!dataView || !formats.contains(mimetype))
+ return QVariant();
+
+ QVariant result;
+ HRESULT hr;
+ if (mimetype == QLatin1String("text/plain")) {
+ hr = QEventDispatcherWinRT::runOnXamlThread([this, &result]() {
+ HRESULT hr;
+ ComPtr<IAsyncOperation<HSTRING>> op;
+ HString res;
+ hr = dataView->GetTextAsync(&op);
+ Q_ASSERT_SUCCEEDED(hr);
+ hr = QWinRTFunctions::await(op, res.GetAddressOf());
+ Q_ASSERT_SUCCEEDED(hr);
+ result.setValue(hStringToQString(res));
+ return S_OK;
+ });
+ } else if (mimetype == QLatin1String("text/uri-list")) {
+ hr = QEventDispatcherWinRT::runOnXamlThread([this, &result]() {
+ HRESULT hr;
+ ComPtr<IAsyncOperation<IVectorView<IStorageItem*>*>> op;
+ hr = dataView->GetStorageItemsAsync(&op);
+ Q_ASSERT_SUCCEEDED(hr);
+ ComPtr<IVectorView<IStorageItem*>> nativeItems;
+ hr = QWinRTFunctions::await(op, nativeItems.GetAddressOf());
+ Q_ASSERT_SUCCEEDED(hr);
+ QList<QVariant> items;
+ quint32 count;
+ hr = nativeItems->get_Size(&count);
+ for (quint32 i = 0; i < count; ++i) {
+ ComPtr<IStorageItem> item;
+ hr = nativeItems->GetAt(i, &item);
+ Q_ASSERT_SUCCEEDED(hr);
+ HString path;
+ hr = item->get_Path(path.GetAddressOf());
+ Q_ASSERT_SUCCEEDED(hr);
+ items.append(QUrl::fromLocalFile(hStringToQString(path)));
+ }
+ result.setValue(items);
+ return S_OK;
+ });
+ } else if (mimetype == QLatin1String("text/html")) {
+ hr = QEventDispatcherWinRT::runOnXamlThread([this, &result]() {
+ HRESULT hr;
+ ComPtr<IAsyncOperation<HSTRING>> op;
+ HString res;
+ hr = dataView->GetHtmlFormatAsync(&op);
+ Q_ASSERT_SUCCEEDED(hr);
+ hr = QWinRTFunctions::await(op, res.GetAddressOf());
+ Q_ASSERT_SUCCEEDED(hr);
+ result.setValue(hStringToQString(res));
+ return S_OK;
+ });
+ } else {
+ // Asking for custom data
+ hr = QEventDispatcherWinRT::runOnXamlThread([this, &result, mimetype]() {
+ HRESULT hr;
+ ComPtr<IAsyncOperation<IInspectable*>> op;
+ ComPtr<IInspectable> res;
+ HString type;
+ type.Set(reinterpret_cast<const wchar_t*>(mimetype.utf16()), mimetype.size());
+ hr = dataView->GetDataAsync(type.Get(), &op);
+ RETURN_OK_IF_FAILED("Could not query custom drag data.");
+ hr = QWinRTFunctions::await(op, res.GetAddressOf());
+ if (FAILED(hr) || !res) {
+ qCDebug(lcQpaMime) << "Custom drop data operation returned no results or failed.";
+ return S_OK;
+ }
+
+ // Test for properties
+ ComPtr<IPropertyValue> propertyValue;
+ hr = res.As(&propertyValue);
+ if (SUCCEEDED(hr)) {
+ // We need to check which type of custom data we are receiving
+ PropertyType type;
+ propertyValue->get_Type(&type);
+ switch (type) {
+ case PropertyType_UInt8: {
+ quint8 v;
+ hr = propertyValue->GetUInt8(&v);
+ Q_ASSERT_SUCCEEDED(hr);
+ result.setValue(v);
+ return S_OK;
+ }
+ case PropertyType_Int16: {
+ qint16 v;
+ hr = propertyValue->GetInt16(&v);
+ Q_ASSERT_SUCCEEDED(hr);
+ result.setValue(v);
+ return S_OK;
+ }
+ case PropertyType_UInt16: {
+ quint16 v;
+ hr = propertyValue->GetUInt16(&v);
+ Q_ASSERT_SUCCEEDED(hr);
+ result.setValue(v);
+ return S_OK;
+ }
+ case PropertyType_Int32: {
+ qint32 v;
+ hr = propertyValue->GetInt32(&v);
+ Q_ASSERT_SUCCEEDED(hr);
+ result.setValue(v);
+ return S_OK;
+ }
+ case PropertyType_UInt32: {
+ quint32 v;
+ hr = propertyValue->GetUInt32(&v);
+ Q_ASSERT_SUCCEEDED(hr);
+ result.setValue(v);
+ return S_OK;
+ }
+ case PropertyType_Int64: {
+ qint64 v;
+ hr = propertyValue->GetInt64(&v);
+ Q_ASSERT_SUCCEEDED(hr);
+ result.setValue(v);
+ return S_OK;
+ }
+ case PropertyType_UInt64: {
+ quint64 v;
+ hr = propertyValue->GetUInt64(&v);
+ Q_ASSERT_SUCCEEDED(hr);
+ result.setValue(v);
+ return S_OK;
+ }
+ case PropertyType_Single: {
+ float v;
+ hr = propertyValue->GetSingle(&v);
+ Q_ASSERT_SUCCEEDED(hr);
+ result.setValue(v);
+ return S_OK;
+ }
+ case PropertyType_Double: {
+ double v;
+ hr = propertyValue->GetDouble(&v);
+ Q_ASSERT_SUCCEEDED(hr);
+ result.setValue(v);
+ return S_OK;
+ }
+ case PropertyType_Char16: {
+ wchar_t v;
+ hr = propertyValue->GetChar16(&v);
+ Q_ASSERT_SUCCEEDED(hr);
+ result.setValue(QString::fromWCharArray(&v, 1));
+ return S_OK;
+ }
+ case PropertyType_Boolean: {
+ boolean v;
+ hr = propertyValue->GetBoolean(&v);
+ Q_ASSERT_SUCCEEDED(hr);
+ result.setValue(v);
+ return S_OK;
+ }
+ case PropertyType_String: {
+ HString stringProperty;
+ hr = propertyValue->GetString(stringProperty.GetAddressOf());
+ Q_ASSERT_SUCCEEDED(hr);
+ result.setValue(hStringToQString(stringProperty));
+ return S_OK;
+ }
+ default:
+ qCDebug(lcQpaMime) << "Unknown property type dropped:" << type;
+ }
+ return S_OK;
+ }
+
+ // Custom data can be read via input streams
+ ComPtr<IRandomAccessStream> randomAccessStream;
+ hr = res.As(&randomAccessStream);
+ if (SUCCEEDED(hr)) {
+ UINT64 size;
+ hr = randomAccessStream->get_Size(&size);
+ Q_ASSERT_SUCCEEDED(hr);
+ ComPtr<IInputStream> stream;
+ hr = randomAccessStream.As(&stream);
+ Q_ASSERT_SUCCEEDED(hr);
+
+ ComPtr<IBufferFactory> bufferFactory;
+ hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Storage_Streams_Buffer).Get(),
+ IID_PPV_ARGS(&bufferFactory));
+ Q_ASSERT_SUCCEEDED(hr);
+
+ UINT32 length = qBound(quint64(0), quint64(size), quint64(UINT_MAX));
+ ComPtr<IBuffer> buffer;
+ hr = bufferFactory->Create(length, &buffer);
+ Q_ASSERT_SUCCEEDED(hr);
+
+ ComPtr<IAsyncOperationWithProgress<IBuffer *, UINT32>> readOp;
+ hr = stream->ReadAsync(buffer.Get(), length, InputStreamOptions_None, &readOp);
+
+ ComPtr<IBuffer> effectiveBuffer;
+ hr = QWinRTFunctions::await(readOp, effectiveBuffer.GetAddressOf());
+
+ hr = effectiveBuffer->get_Length(&length);
+
+ ComPtr<Windows::Storage::Streams::IBufferByteAccess> byteArrayAccess;
+ hr = effectiveBuffer.As(&byteArrayAccess);
+
+ byte *bytes;
+ hr = byteArrayAccess->Buffer(&bytes);
+ QByteArray array((char *)bytes, length);
+ result.setValue(array);
+ return S_OK;
+ }
+
+ HSTRING runtimeClass;
+ hr = res->GetRuntimeClassName(&runtimeClass);
+ Q_ASSERT_SUCCEEDED(hr);
+ HString converted;
+ converted.Set(runtimeClass);
+ qCDebug(lcQpaMime) << "Unknown drop data type received (" << hStringToQString(converted)
+ << "). Ignoring...";
+ return S_OK;
+ });
+ }
+ return result;
+}
+
+void QWinRTInternalMimeData::setDataView(const Microsoft::WRL::ComPtr<IDataPackageView> &d)
+{
+ dataView = d;
+ formats.clear();
+}
+
+static HRESULT qt_drag_enter(IInspectable *sender, ABI::Windows::UI::Xaml::IDragEventArgs *e)
+{
+ QWinRTDrag::instance()->handleNativeDragEvent(sender, e);
+ return S_OK;
+}
+
+static HRESULT qt_drag_over(IInspectable *sender, ABI::Windows::UI::Xaml::IDragEventArgs *e)
+{
+ QWinRTDrag::instance()->handleNativeDragEvent(sender, e);
+ return S_OK;
+}
+
+static HRESULT qt_drag_leave(IInspectable *sender, ABI::Windows::UI::Xaml::IDragEventArgs *e)
+{
+ // Qt internally checks for new drags and auto sends leave events
+ // Also there is no QPA function for handling leave
+ Q_UNUSED(sender);
+ Q_UNUSED(e);
+ return S_OK;
+}
+
+static HRESULT qt_drop(IInspectable *sender, ABI::Windows::UI::Xaml::IDragEventArgs *e)
+{
+ QWinRTDrag::instance()->handleNativeDragEvent(sender, e, true);
+ return S_OK;
+}
+
+#define Q_DECLARE_DRAGHANDLER(name,func) \
+class QtDragEventHandler##name : public IDragEventHandler \
+{ \
+public: \
+ virtual HRESULT STDMETHODCALLTYPE Invoke(IInspectable *sender, \
+ ABI::Windows::UI::Xaml::IDragEventArgs *e) \
+ { \
+ return qt_##func(sender, e);\
+ } \
+ \
+ STDMETHODIMP \
+ QueryInterface(REFIID riid, void FAR* FAR* ppvObj) \
+ { \
+ if (riid == IID_IUnknown || riid == IID_IDragEventHandler) { \
+ *ppvObj = this; \
+ AddRef(); \
+ return NOERROR; \
+ } \
+ *ppvObj = NULL; \
+ return ResultFromScode(E_NOINTERFACE); \
+ } \
+ \
+ STDMETHODIMP_(ULONG) \
+ AddRef(void) \
+ { \
+ return ++m_refs; \
+ } \
+ \
+ STDMETHODIMP_(ULONG) \
+ Release(void) \
+ { \
+ if (--m_refs == 0) { \
+ delete this; \
+ return 0; \
+ } \
+ return m_refs; \
+ } \
+private: \
+ULONG m_refs{0}; \
+};
+
+Q_DECLARE_DRAGHANDLER(Enter, drag_enter)
+Q_DECLARE_DRAGHANDLER(Over, drag_over)
+Q_DECLARE_DRAGHANDLER(Leave, drag_leave)
+Q_DECLARE_DRAGHANDLER(Drop, drop)
+
+#define Q_INST_DRAGHANDLER(name) QtDragEventHandler##name()
+
+Q_GLOBAL_STATIC(QWinRTDrag, gDrag);
+
+extern ComPtr<ABI::Windows::UI::Input::IPointerPoint> qt_winrt_lastPointerPoint; // qwinrtscreen.cpp
+
+QWinRTDrag::QWinRTDrag()
+ : QPlatformDrag()
+ , m_dragTarget(0)
+{
+ qCDebug(lcQpaMime) << __FUNCTION__;
+ m_enter = new Q_INST_DRAGHANDLER(Enter);
+ m_over = new Q_INST_DRAGHANDLER(Over);
+ m_leave = new Q_INST_DRAGHANDLER(Leave);
+ m_drop = new Q_INST_DRAGHANDLER(Drop);
+ m_mimeData = new QWinRTInternalMimeData;
+}
+
+QWinRTDrag::~QWinRTDrag()
+{
+ qCDebug(lcQpaMime) << __FUNCTION__;
+ delete m_enter;
+ delete m_over;
+ delete m_leave;
+ delete m_drop;
+ delete m_mimeData;
+}
+
+QWinRTDrag *QWinRTDrag::instance()
+{
+ return gDrag;
+}
+
+inline HRESULT resetUiElementDrag(ComPtr<IUIElement3> &elem3, EventRegistrationToken startingToken)
+{
+ return QEventDispatcherWinRT::runOnXamlThread([elem3, startingToken]() {
+ HRESULT hr;
+ hr = elem3->put_CanDrag(false);
+ Q_ASSERT_SUCCEEDED(hr);
+ hr = elem3->remove_DragStarting(startingToken);
+ Q_ASSERT_SUCCEEDED(hr);
+ return S_OK;
+ });
+}
+
+Qt::DropAction QWinRTDrag::drag(QDrag *drag)
+{
+ qCDebug(lcQpaMime) << __FUNCTION__ << drag;
+
+ if (!qt_winrt_lastPointerPoint) {
+ Q_ASSERT_X(qt_winrt_lastPointerPoint, Q_FUNC_INFO, "No pointerpoint known");
+ return Qt::IgnoreAction;
+ }
+
+ ComPtr<IUIElement3> elem3;
+ HRESULT hr = m_ui.As(&elem3);
+ Q_ASSERT_SUCCEEDED(hr);
+
+ ComPtr<IAsyncOperation<ABI::Windows::ApplicationModel::DataTransfer::DataPackageOperation>> op;
+ EventRegistrationToken startingToken;
+
+ hr = QEventDispatcherWinRT::runOnXamlThread([drag, &op, &hr, elem3, &startingToken, this]() {
+
+ hr = elem3->put_CanDrag(true);
+ Q_ASSERT_SUCCEEDED(hr);
+
+ auto startingCallback = Callback<ITypedEventHandler<UIElement*, DragStartingEventArgs*>> ([drag](IInspectable *, IDragStartingEventArgs *args) {
+ qCDebug(lcQpaMime) << "Drag starting" << args;
+
+ ComPtr<IDataPackage> dataPackage;
+ HRESULT hr;
+ hr = args->get_Data(dataPackage.GetAddressOf());
+ Q_ASSERT_SUCCEEDED(hr);
+ Qt::DropAction action = drag->defaultAction();
+ hr = dataPackage->put_RequestedOperation(translateFromQDragDropActions(action));
+ Q_ASSERT_SUCCEEDED(hr);
+
+#ifndef QT_WINRT_LIMITED_DRAGANDDROP
+ ComPtr<IDragStartingEventArgs2> args2;
+ hr = args->QueryInterface(IID_PPV_ARGS(&args2));
+ Q_ASSERT_SUCCEEDED(hr);
+
+ Qt::DropActions actions = drag->supportedActions();
+ DataPackageOperation allowedOperations = DataPackageOperation_None;
+ if (actions & Qt::CopyAction)
+ allowedOperations |= DataPackageOperation_Copy;
+ if (actions & Qt::MoveAction)
+ allowedOperations |= DataPackageOperation_Move;
+ if (actions & Qt::LinkAction)
+ allowedOperations |= DataPackageOperation_Link;
+ hr = args2->put_AllowedOperations(allowedOperations);
+ Q_ASSERT_SUCCEEDED(hr);
+#endif // QT_WINRT_LIMITED_DRAGANDDROP
+ QMimeData *mimeData = drag->mimeData();
+ if (mimeData->hasText()) {
+ hr = dataPackage->SetText(qStringToHString(mimeData->text()).Get());
+ Q_ASSERT_SUCCEEDED(hr);
+ }
+ if (mimeData->hasHtml()) {
+ hr = dataPackage->SetHtmlFormat(qStringToHString(mimeData->html()).Get());
+ Q_ASSERT_SUCCEEDED(hr);
+ }
+ // ### TODO: Missing: weblink, image
+
+ if (!drag->pixmap().isNull()) {
+ const QImage image2 = drag->pixmap().toImage();
+ const QImage image = image2.convertToFormat(QImage::Format_ARGB32);
+ if (!image.isNull()) {
+ // Create IBuffer containing image
+ ComPtr<IBuffer> imageBuffer = createIBufferFromData(reinterpret_cast<const char*>(image.bits()), image.byteCount());
+
+ ComPtr<ISoftwareBitmapFactory> bitmapFactory;
+ hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Graphics_Imaging_SoftwareBitmap).Get(),
+ IID_PPV_ARGS(&bitmapFactory));
+ Q_ASSERT_SUCCEEDED(hr);
+
+ ComPtr<ISoftwareBitmap> bitmap;
+ hr = bitmapFactory->Create(BitmapPixelFormat_Rgba8, image.width(), image.height(), &bitmap);
+ Q_ASSERT_SUCCEEDED(hr);
+
+ hr = bitmap->CopyFromBuffer(imageBuffer.Get());
+ Q_ASSERT_SUCCEEDED(hr);
+
+ ComPtr<IDragUI> dragUi;
+ hr = args->get_DragUI(dragUi.GetAddressOf());
+ Q_ASSERT_SUCCEEDED(hr);
+
+ hr = dragUi->SetContentFromSoftwareBitmap(bitmap.Get());
+ Q_ASSERT_SUCCEEDED(hr);
+ }
+ }
+
+ const QStringList formats = mimeData->formats();
+ for (auto item : formats) {
+ QByteArray data = mimeData->data(item);
+
+ ComPtr<IBuffer> buffer = createIBufferFromData(data.constData(), data.size());
+
+ // We cannot push the buffer to the data package as the result on
+ // recipient side is different from native events. It still sends a
+ // buffer, but that potentially cannot be parsed. Hence we need to create
+ // a IRandomAccessStream which gets forwarded as is to the drop side.
+ ComPtr<IRandomAccessStream> ras;
+ hr = RoActivateInstance(HString::MakeReference(RuntimeClass_Windows_Storage_Streams_InMemoryRandomAccessStream).Get(), &ras);
+ Q_ASSERT_SUCCEEDED(hr);
+
+ hr = ras->put_Size(data.size());
+ ComPtr<IOutputStream> outputStream;
+ hr = ras->GetOutputStreamAt(0, &outputStream);
+ Q_ASSERT_SUCCEEDED(hr);
+
+ ComPtr<IAsyncOperationWithProgress<UINT32,UINT32>> writeOp;
+ hr = outputStream->WriteAsync(buffer.Get(), &writeOp);
+ Q_ASSERT_SUCCEEDED(hr);
+
+ UINT32 result;
+ hr = QWinRTFunctions::await(writeOp, &result);
+ Q_ASSERT_SUCCEEDED(hr);
+
+ unsigned char flushResult;
+ ComPtr<IAsyncOperation<bool>> flushOp;
+ hr = outputStream->FlushAsync(&flushOp);
+ Q_ASSERT_SUCCEEDED(hr);
+
+ hr = QWinRTFunctions::await(flushOp, &flushResult);
+ Q_ASSERT_SUCCEEDED(hr);
+
+ hr = dataPackage->SetData(qStringToHString(item).Get(), ras.Get());
+ Q_ASSERT_SUCCEEDED(hr);
+ }
+ return S_OK;
+ });
+
+ hr = elem3->add_DragStarting(startingCallback.Get(), &startingToken);
+ Q_ASSERT_SUCCEEDED(hr);
+
+ hr = elem3->StartDragAsync(qt_winrt_lastPointerPoint.Get(), &op);
+ Q_ASSERT_SUCCEEDED(hr);
+
+ return hr;
+ });
+ if (!op || FAILED(hr)) {
+ qCDebug(lcQpaMime) << "Drag failed:" << hr;
+ hr = resetUiElementDrag(elem3, startingToken);
+ Q_ASSERT_SUCCEEDED(hr);
+ return Qt::IgnoreAction;
+ }
+
+ DataPackageOperation nativeOperationType;
+ // Do not yield, as that can cause deadlocks when dropping inside the same app
+ hr = QWinRTFunctions::await(op, &nativeOperationType, QWinRTFunctions::ProcessThreadEvents);
+ Q_ASSERT_SUCCEEDED(hr);
+
+ hr = resetUiElementDrag(elem3, startingToken);
+ Q_ASSERT_SUCCEEDED(hr);
+
+ Qt::DropAction resultAction;
+ switch (nativeOperationType) {
+ case DataPackageOperation_Link:
+ resultAction = Qt::LinkAction;
+ break;
+ case DataPackageOperation_Copy:
+ resultAction = Qt::CopyAction;
+ break;
+ case DataPackageOperation_Move:
+ resultAction = Qt::MoveAction;
+ break;
+ case DataPackageOperation_None:
+ default:
+ resultAction = Qt::IgnoreAction;
+ break;
+ }
+
+ return resultAction;
+}
+
+void QWinRTDrag::setDropTarget(QWindow *target)
+{
+ qCDebug(lcQpaMime) << __FUNCTION__ << target;
+ m_dragTarget = target;
+}
+
+QMimeData *QWinRTDrag::platformDropData()
+{
+ qCDebug(lcQpaMime) << __FUNCTION__;
+ return m_mimeData;
+}
+
+void QWinRTDrag::setUiElement(ComPtr<ABI::Windows::UI::Xaml::IUIElement> &element)
+{
+ qCDebug(lcQpaMime) << __FUNCTION__;
+ m_ui = element;
+ // We set the element to always accept drops and then evaluate during
+ // runtime
+ HRESULT hr = element->put_AllowDrop(TRUE);
+ EventRegistrationToken tok;
+ hr = element->add_DragEnter(m_enter, &tok);
+ RETURN_VOID_IF_FAILED("Failed to add DragEnter handler.");
+ hr = element->add_DragOver(m_over, &tok);
+ RETURN_VOID_IF_FAILED("Failed to add DragOver handler.");
+ hr = element->add_DragLeave(m_leave, &tok);
+ RETURN_VOID_IF_FAILED("Failed to add DragLeave handler.");
+ hr = element->add_Drop(m_drop, &tok);
+ RETURN_VOID_IF_FAILED("Failed to add Drop handler.");
+}
+
+void QWinRTDrag::handleNativeDragEvent(IInspectable *sender, ABI::Windows::UI::Xaml::IDragEventArgs *e, bool drop)
+{
+ Q_UNUSED(sender);
+
+ if (!m_dragTarget)
+ return;
+
+ HRESULT hr;
+ Point relativePoint;
+ hr = e->GetPosition(m_ui.Get(), &relativePoint);
+ RETURN_VOID_IF_FAILED("Could not query drag position.");
+ const QPoint p(relativePoint.X, relativePoint.Y);
+
+ ComPtr<IDragEventArgs2> e2;
+ hr = e->QueryInterface(IID_PPV_ARGS(&e2));
+ RETURN_VOID_IF_FAILED("Could not convert drag event args");
+
+ DragDropModifiers modifiers;
+ hr = e2->get_Modifiers(&modifiers);
+
+#ifndef QT_WINRT_LIMITED_DRAGANDDROP
+ ComPtr<IDragEventArgs3> e3;
+ hr = e->QueryInterface(IID_PPV_ARGS(&e3));
+ Q_ASSERT_SUCCEEDED(hr);
+
+ DataPackageOperation dataOp;
+ hr = e3->get_AllowedOperations(&dataOp);
+ if (FAILED(hr))
+ qCDebug(lcQpaMime) << __FUNCTION__ << "Could not query drag operations";
+
+ const Qt::DropActions actions = translateToQDragDropActions(dataOp);
+#else // !QT_WINRT_LIMITED_DRAGANDDROP
+ const Qt::DropActions actions = Qt::LinkAction | Qt::CopyAction | Qt::MoveAction;;
+#endif // !QT_WINRT_LIMITED_DRAGANDDROP
+
+ ComPtr<IDataPackageView> dataView;
+ hr = e2->get_DataView(&dataView);
+ Q_ASSERT_SUCCEEDED(hr);
+
+ m_mimeData->setDataView(dataView);
+
+ // We use deferral as we need to jump to the Qt thread to handle
+ // the drag event
+ ComPtr<IDragOperationDeferral> deferral;
+ hr = e2->GetDeferral(&deferral);
+ Q_ASSERT_SUCCEEDED(hr);
+
+ DragThreadTransferData *transferData = new DragThreadTransferData;
+ transferData->moveToThread(qGuiApp->thread());
+ transferData->window = m_dragTarget;
+ transferData->point = p;
+ transferData->mime = m_mimeData;
+ transferData->actions = actions;
+ transferData->dropAction = drop;
+ transferData->nativeArgs = e;
+ transferData->deferral = deferral;
+ QMetaObject::invokeMethod(transferData, "handleDrag", Qt::QueuedConnection);
+}
+
+DragThreadTransferData::DragThreadTransferData(QObject *parent)
+ : QObject(parent)
+ , dropAction(false)
+{
+}
+
+void DragThreadTransferData::handleDrag()
+{
+ bool accepted = false;
+ Qt::DropAction acceptedAction;
+ if (dropAction) {
+ QPlatformDropQtResponse response = QWindowSystemInterface::handleDrop(window, mime, point, actions);
+ accepted = response.isAccepted();
+ acceptedAction = response.acceptedAction();
+ } else {
+ QPlatformDragQtResponse response = QWindowSystemInterface::handleDrag(window, mime, point, actions);
+ accepted = response.isAccepted();
+ acceptedAction = response.acceptedAction();
+ }
+
+ HRESULT hr;
+ hr = QEventDispatcherWinRT::runOnXamlThread([accepted, acceptedAction, this]() {
+ HRESULT hr;
+ hr = nativeArgs->put_Handled(accepted);
+ if (acceptedAction != Qt::IgnoreAction) {
+ ComPtr<IDragEventArgs2> e2;
+ hr = nativeArgs.As(&e2);
+ if (SUCCEEDED(hr))
+ hr = e2->put_AcceptedOperation(translateFromQDragDropActions(acceptedAction));
+ }
+ deferral->Complete();
+ return S_OK;
+ });
+ Q_ASSERT_SUCCEEDED(hr);
+ deleteLater();
+}
+
+QT_END_NAMESPACE
+
+#include "qwinrtdrag.moc"
diff --git a/src/plugins/platforms/winrt/qwinrtdrag.h b/src/plugins/platforms/winrt/qwinrtdrag.h
new file mode 100644
index 0000000000..97079d831b
--- /dev/null
+++ b/src/plugins/platforms/winrt/qwinrtdrag.h
@@ -0,0 +1,113 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <qpa/qplatformdrag.h>
+
+#include <QtCore/QLoggingCategory>
+#include <QtCore/QMimeData>
+#include <QtGui/private/qdnd_p.h> // QInternalMime
+
+#include <wrl.h>
+
+namespace ABI {
+ namespace Windows {
+ namespace ApplicationModel {
+ namespace DataTransfer {
+ struct IDataPackageView;
+ }
+ }
+ namespace UI {
+ namespace Xaml {
+ struct IUIElement;
+ struct IDragEventArgs;
+ struct IDragOperationDeferral;
+ //struct IDataPackageView;
+ }
+ }
+ }
+}
+
+QT_BEGIN_NAMESPACE
+
+Q_DECLARE_LOGGING_CATEGORY(lcQpaMime)
+
+class QtDragEventHandlerEnter;
+class QtDragEventHandlerOver;
+class QtDragEventHandlerLeave;
+class QtDragEventHandlerDrop;
+class QWinRTInternalMimeData;
+
+class QWinRTInternalMimeData : public QInternalMimeData {
+public:
+ QWinRTInternalMimeData();
+ virtual ~QWinRTInternalMimeData();
+
+ bool hasFormat_sys(const QString &mimetype) const Q_DECL_OVERRIDE;
+ QStringList formats_sys() const Q_DECL_OVERRIDE;
+ QVariant retrieveData_sys(const QString &mimetype, QVariant::Type preferredType) const Q_DECL_OVERRIDE;
+
+ void setDataView(const Microsoft::WRL::ComPtr<ABI::Windows::ApplicationModel::DataTransfer::IDataPackageView> &d);
+private:
+ Microsoft::WRL::ComPtr<ABI::Windows::ApplicationModel::DataTransfer::IDataPackageView> dataView;
+ mutable QStringList formats;
+};
+
+class QWinRTDrag : public QPlatformDrag {
+public:
+ QWinRTDrag();
+ virtual ~QWinRTDrag();
+ static QWinRTDrag *instance();
+
+ QMimeData *platformDropData(void) Q_DECL_OVERRIDE;
+ Qt::DropAction drag(QDrag *) Q_DECL_OVERRIDE;
+
+ void setDropTarget(QWindow *target);
+
+ // Native integration and registration
+ void setUiElement(Microsoft::WRL::ComPtr<ABI::Windows::UI::Xaml::IUIElement> &element);
+
+ void handleNativeDragEvent(IInspectable *sender, ABI::Windows::UI::Xaml::IDragEventArgs *e, bool drop = false);
+private:
+ Microsoft::WRL::ComPtr<ABI::Windows::UI::Xaml::IUIElement> m_ui;
+ QWindow *m_dragTarget;
+ QtDragEventHandlerEnter *m_enter;
+ QtDragEventHandlerOver *m_over;
+ QtDragEventHandlerLeave *m_leave;
+ QtDragEventHandlerDrop *m_drop;
+ QWinRTInternalMimeData *m_mimeData;
+};
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platforms/winrt/qwinrtintegration.cpp b/src/plugins/platforms/winrt/qwinrtintegration.cpp
index 8ef560ba20..42b7f7e909 100644
--- a/src/plugins/platforms/winrt/qwinrtintegration.cpp
+++ b/src/plugins/platforms/winrt/qwinrtintegration.cpp
@@ -48,6 +48,9 @@
#include "qwinrtfontdatabase.h"
#include "qwinrttheme.h"
#include "qwinrtclipboard.h"
+#ifndef QT_NO_DRAGANDDROP
+#include "qwinrtdrag.h"
+#endif
#include <QtGui/QOffscreenSurface>
#include <QtGui/QOpenGLContext>
@@ -312,6 +315,17 @@ QPlatformClipboard *QWinRTIntegration::clipboard() const
return d->clipboard;
}
+#ifndef QT_NO_DRAGANDDROP
+QPlatformDrag *QWinRTIntegration::drag() const
+{
+#if _MSC_VER >= 1900
+ return QWinRTDrag::instance();
+#else
+ return QPlatformIntegration::drag();
+#endif
+}
+#endif // QT_NO_DRAGANDDROP
+
Qt::KeyboardModifiers QWinRTIntegration::queryKeyboardModifiers() const
{
Q_D(const QWinRTIntegration);
diff --git a/src/plugins/platforms/winrt/qwinrtintegration.h b/src/plugins/platforms/winrt/qwinrtintegration.h
index 9e28beb8fa..7b4d5531fc 100644
--- a/src/plugins/platforms/winrt/qwinrtintegration.h
+++ b/src/plugins/platforms/winrt/qwinrtintegration.h
@@ -97,6 +97,10 @@ public:
QPlatformInputContext *inputContext() const Q_DECL_OVERRIDE;
QPlatformServices *services() const Q_DECL_OVERRIDE;
QPlatformClipboard *clipboard() const Q_DECL_OVERRIDE;
+#ifndef QT_NO_DRAGANDDROP
+ QPlatformDrag *drag() const Q_DECL_OVERRIDE;
+#endif
+
Qt::KeyboardModifiers queryKeyboardModifiers() const Q_DECL_OVERRIDE;
QStringList themeNames() const Q_DECL_OVERRIDE;
diff --git a/src/plugins/platforms/winrt/qwinrtscreen.cpp b/src/plugins/platforms/winrt/qwinrtscreen.cpp
index aed33f6b48..ad32e63cad 100644
--- a/src/plugins/platforms/winrt/qwinrtscreen.cpp
+++ b/src/plugins/platforms/winrt/qwinrtscreen.cpp
@@ -42,6 +42,9 @@
#include "qwinrtbackingstore.h"
#include "qwinrtinputcontext.h"
#include "qwinrtcursor.h"
+#ifndef QT_NO_DRAGANDDROP
+#include "qwinrtdrag.h"
+#endif
#include "qwinrtwindow.h"
#include <private/qeventdispatcher_winrt_p.h>
@@ -556,6 +559,9 @@ QWinRTScreen::QWinRTScreen()
ComPtr<Xaml::IUIElement> uiElement;
hr = canvas.As(&uiElement);
Q_ASSERT_SUCCEEDED(hr);
+#if _MSC_VER >= 1900 && !defined(QT_NO_DRAGANDDROP)
+ QWinRTDrag::instance()->setUiElement(uiElement);
+#endif
hr = window->put_Content(uiElement.Get());
Q_ASSERT_SUCCEEDED(hr);
hr = canvas.As(&d->canvas);
@@ -764,6 +770,10 @@ void QWinRTScreen::addWindow(QWindow *window)
QWindowSystemInterface::handleWindowActivated(window, Qt::OtherFocusReason);
handleExpose();
QWindowSystemInterface::flushWindowSystemEvents();
+
+#if _MSC_VER >= 1900 && !defined(QT_NO_DRAGANDDROP)
+ QWinRTDrag::instance()->setDropTarget(window);
+#endif
}
void QWinRTScreen::removeWindow(QWindow *window)
@@ -778,6 +788,10 @@ void QWinRTScreen::removeWindow(QWindow *window)
QWindowSystemInterface::handleWindowActivated(window, Qt::OtherFocusReason);
handleExpose();
QWindowSystemInterface::flushWindowSystemEvents();
+#if _MSC_VER >= 1900 && !defined(QT_NO_DRAGANDDROP)
+ if (wasTopWindow)
+ QWinRTDrag::instance()->setDropTarget(topWindow());
+#endif
}
void QWinRTScreen::raise(QWindow *window)
@@ -973,6 +987,9 @@ HRESULT QWinRTScreen::onPointerExited(ICoreWindow *, IPointerEventArgs *args)
return S_OK;
}
+// Required for qwinrtdrag.cpp
+ComPtr<IPointerPoint> qt_winrt_lastPointerPoint;
+
HRESULT QWinRTScreen::onPointerUpdated(ICoreWindow *, IPointerEventArgs *args)
{
Q_D(QWinRTScreen);
@@ -980,6 +997,7 @@ HRESULT QWinRTScreen::onPointerUpdated(ICoreWindow *, IPointerEventArgs *args)
if (FAILED(args->get_CurrentPoint(&pointerPoint)))
return E_INVALIDARG;
+ qt_winrt_lastPointerPoint = pointerPoint;
// Common traits - point, modifiers, properties
Point point;
pointerPoint->get_Position(&point);
diff --git a/src/plugins/platforms/winrt/winrt.pro b/src/plugins/platforms/winrt/winrt.pro
index 144c581015..28456f66ec 100644
--- a/src/plugins/platforms/winrt/winrt.pro
+++ b/src/plugins/platforms/winrt/winrt.pro
@@ -14,6 +14,7 @@ SOURCES = \
qwinrtbackingstore.cpp \
qwinrtclipboard.cpp \
qwinrtcursor.cpp \
+ qwinrtdrag.cpp \
qwinrteglcontext.cpp \
qwinrteventdispatcher.cpp \
qwinrtfiledialoghelper.cpp \
@@ -32,6 +33,7 @@ HEADERS = \
qwinrtbackingstore.h \
qwinrtclipboard.h \
qwinrtcursor.h \
+ qwinrtdrag.h \
qwinrteglcontext.h \
qwinrteventdispatcher.h \
qwinrtfiledialoghelper.h \
@@ -47,6 +49,15 @@ HEADERS = \
OTHER_FILES += winrt.json
+WINRT_SDK_VERSION_STRING = $$(UCRTVersion)
+WINRT_SDK_VERSION = $$member($$list($$split(WINRT_SDK_VERSION_STRING, .)), 2)
+lessThan(WINRT_SDK_VERSION, 14322): DEFINES += QT_WINRT_LIMITED_DRAGANDDROP
+
+*-msvc2013|contains(DEFINES, QT_NO_DRAGANDDROP) {
+ SOURCES -= qwinrtdrag.cpp
+ HEADERS -= qwinrtdrag.h
+}
+
PLUGIN_TYPE = platforms
PLUGIN_CLASS_NAME = QWinRTIntegrationPlugin
!equals(TARGET, $$QT_DEFAULT_QPA_PLUGIN): PLUGIN_EXTENDS = -
diff --git a/src/plugins/platforms/xcb/qxcbconnection.cpp b/src/plugins/platforms/xcb/qxcbconnection.cpp
index 4b0e94eda0..bc62b500e5 100644
--- a/src/plugins/platforms/xcb/qxcbconnection.cpp
+++ b/src/plugins/platforms/xcb/qxcbconnection.cpp
@@ -38,6 +38,7 @@
****************************************************************************/
#include <QtGui/private/qguiapplication_p.h>
+#include <QtGui/private/qhighdpiscaling_p.h>
#include <QtCore/QDebug>
#include "qxcbconnection.h"
@@ -264,6 +265,7 @@ void QXcbConnection::updateScreens(const xcb_randr_notify_event_t *event)
} else {
screen = createScreen(virtualDesktop, output, outputInfo.data());
qCDebug(lcQpaScreen) << "output" << screen->name() << "is connected and enabled";
+ QHighDpiScaling::updateHighDpiScaling();
}
}
} else if (screen) {