From 0ff45fbf1b9a6ab6da2541bb70533e49dc892954 Mon Sep 17 00:00:00 2001 From: Maurice Kalinowski Date: Wed, 30 Mar 2016 09:42:34 +0200 Subject: winrt: Enable drop support Allow Qt applications to receive drops. Dragging is not supported yet and will be handled in a separate commit. Task-number: QTBUG-50827 Change-Id: I684e3d5685ce73f74805691f6ac7bbc45e2d19ec Reviewed-by: Oliver Wolff --- src/plugins/platforms/winrt/qwinrtdrag.cpp | 672 ++++++++++++++++++++++ src/plugins/platforms/winrt/qwinrtdrag.h | 113 ++++ src/plugins/platforms/winrt/qwinrtintegration.cpp | 10 + src/plugins/platforms/winrt/qwinrtintegration.h | 4 + src/plugins/platforms/winrt/qwinrtscreen.cpp | 12 + src/plugins/platforms/winrt/winrt.pro | 7 + 6 files changed, 818 insertions(+) create mode 100644 src/plugins/platforms/winrt/qwinrtdrag.cpp create mode 100644 src/plugins/platforms/winrt/qwinrtdrag.h (limited to 'src/plugins/platforms/winrt') diff --git a/src/plugins/platforms/winrt/qwinrtdrag.cpp b/src/plugins/platforms/winrt/qwinrtdrag.cpp new file mode 100644 index 0000000000..a52ed91749 --- /dev/null +++ b/src/plugins/platforms/winrt/qwinrtdrag.cpp @@ -0,0 +1,672 @@ +/**************************************************************************** +** +** 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 +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + +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::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") + +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 nativeArgs; + ComPtr deferral; +}; + +inline QString hStringToQString(const HString &hString) +{ + quint32 l; + const wchar_t *raw = hString.GetRawBuffer(&l); + return (QString::fromWCharArray(raw, l)); +} + +namespace NativeFormatStrings { + static ComPtr 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; + + 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> availableFormats; + hr = dataView->get_AvailableFormats(&availableFormats); + RETURN_IF_FAILED("Could not query available formats.", return formats); + + quint32 size; + hr = availableFormats->get_Size(&size); + RETURN_IF_FAILED("Could not query format vector size.", return formats); + for (quint32 i = 0; i < size; ++i) { + HString str; + hr = availableFormats->GetAt(i, str.GetAddressOf()); + if (FAILED(hr)) + continue; + formats.append(hStringToQString(str)); + } + qDebug() << __FUNCTION__ << "Available formats:" << formats; + 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> 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*>> op; + hr = dataView->GetStorageItemsAsync(&op); + Q_ASSERT_SUCCEEDED(hr); + ComPtr> nativeItems; + hr = QWinRTFunctions::await(op, nativeItems.GetAddressOf()); + Q_ASSERT_SUCCEEDED(hr); + QList items; + quint32 count; + hr = nativeItems->get_Size(&count); + for (quint32 i = 0; i < count; ++i) { + ComPtr 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> 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 if (mimetype.startsWith(QLatin1String("image/"))) { + Q_UNIMPLEMENTED(); + } else { + // Asking for custom data + hr = QEventDispatcherWinRT::runOnXamlThread([this, &result, mimetype]() { + HRESULT hr; + ComPtr> op; + ComPtr res; + HString type; + type.Set(reinterpret_cast(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 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 randomAccessStream; + hr = res.As(&randomAccessStream); + if (SUCCEEDED(hr)) { + UINT64 size; + hr = randomAccessStream->get_Size(&size); + Q_ASSERT_SUCCEEDED(hr); + ComPtr stream; + hr = randomAccessStream.As(&stream); + Q_ASSERT_SUCCEEDED(hr); + + ComPtr 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 buffer; + hr = bufferFactory->Create(length, &buffer); + Q_ASSERT_SUCCEEDED(hr); + + ComPtr> readOp; + hr = stream->ReadAsync(buffer.Get(), length, InputStreamOptions_None, &readOp); + + ComPtr effectiveBuffer; + hr = QWinRTFunctions::await(readOp, effectiveBuffer.GetAddressOf()); + + hr = effectiveBuffer->get_Length(&length); + + ComPtr 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 &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); + +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; +} + +Qt::DropAction QWinRTDrag::drag(QDrag *drag) +{ + qCDebug(lcQpaMime) << __FUNCTION__ << drag; + // ### TODO: Add dragging from Window + return Qt::IgnoreAction; +} + +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 &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); + qDebug() << "Point received:" << relativePoint.X << "/" << relativePoint.Y; + + ComPtr 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); + + ComPtr 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); + + ComPtr 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 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 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 + +#include +#include +#include // QInternalMime + +#include + +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 &d); +private: + Microsoft::WRL::ComPtr 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 &element); + + void handleNativeDragEvent(IInspectable *sender, ABI::Windows::UI::Xaml::IDragEventArgs *e, bool drop = false); +private: + Microsoft::WRL::ComPtr 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 30c0e81e21..01e8a42b8e 100644 --- a/src/plugins/platforms/winrt/qwinrtintegration.cpp +++ b/src/plugins/platforms/winrt/qwinrtintegration.cpp @@ -45,6 +45,7 @@ #include "qwinrtfontdatabase.h" #include "qwinrttheme.h" #include "qwinrtclipboard.h" +#include "qwinrtdrag.h" #include #include @@ -309,6 +310,15 @@ QPlatformClipboard *QWinRTIntegration::clipboard() const return d->clipboard; } +QPlatformDrag *QWinRTIntegration::drag() const +{ +#if _MSC_VER >= 1900 + return QWinRTDrag::instance(); +#else + return QPlatformIntegration::drag(); +#endif +} + 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 1ed286ab2e..ffdfa55e49 100644 --- a/src/plugins/platforms/winrt/qwinrtintegration.h +++ b/src/plugins/platforms/winrt/qwinrtintegration.h @@ -94,6 +94,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 0255527e91..3d9baf555d 100644 --- a/src/plugins/platforms/winrt/qwinrtscreen.cpp +++ b/src/plugins/platforms/winrt/qwinrtscreen.cpp @@ -39,6 +39,7 @@ #include "qwinrtbackingstore.h" #include "qwinrtinputcontext.h" #include "qwinrtcursor.h" +#include "qwinrtdrag.h" #include "qwinrtwindow.h" #include @@ -553,6 +554,9 @@ QWinRTScreen::QWinRTScreen() ComPtr uiElement; hr = canvas.As(&uiElement); Q_ASSERT_SUCCEEDED(hr); +#if _MSC_VER >= 1900 + QWinRTDrag::instance()->setUiElement(uiElement); +#endif hr = window->put_Content(uiElement.Get()); Q_ASSERT_SUCCEEDED(hr); hr = canvas.As(&d->canvas); @@ -761,6 +765,10 @@ void QWinRTScreen::addWindow(QWindow *window) QWindowSystemInterface::handleWindowActivated(window, Qt::OtherFocusReason); handleExpose(); QWindowSystemInterface::flushWindowSystemEvents(); + +#if _MSC_VER >= 1900 + QWinRTDrag::instance()->setDropTarget(window); +#endif } void QWinRTScreen::removeWindow(QWindow *window) @@ -775,6 +783,10 @@ void QWinRTScreen::removeWindow(QWindow *window) QWindowSystemInterface::handleWindowActivated(window, Qt::OtherFocusReason); handleExpose(); QWindowSystemInterface::flushWindowSystemEvents(); +#if _MSC_VER >= 1900 + if (wasTopWindow) + QWinRTDrag::instance()->setDropTarget(topWindow()); +#endif } void QWinRTScreen::raise(QWindow *window) diff --git a/src/plugins/platforms/winrt/winrt.pro b/src/plugins/platforms/winrt/winrt.pro index 261295ef0b..5c62b5718b 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,11 @@ HEADERS = \ OTHER_FILES += winrt.json +*-msvc2013 { + SOURCES -= qwinrtdrag.cpp + HEADERS -= qwinrtdrag.h +} + PLUGIN_TYPE = platforms PLUGIN_CLASS_NAME = QWinRTIntegrationPlugin !equals(TARGET, $$QT_DEFAULT_QPA_PLUGIN): PLUGIN_EXTENDS = - -- cgit v1.2.3 From 94f319a2bb191b24498a7575d3b9e186eb772d4d Mon Sep 17 00:00:00 2001 From: Maurice Kalinowski Date: Thu, 26 May 2016 10:19:28 +0200 Subject: winrt: enable drag support Allow applications to initiate drag operations. Task-number: QTBUG-50827 Change-Id: I3c29b54756af1af24544f49803305f0c95d8b7f9 Reviewed-by: Oliver Wolff --- src/plugins/platforms/winrt/qwinrtdrag.cpp | 188 ++++++++++++++++++++++++++- src/plugins/platforms/winrt/qwinrtscreen.cpp | 4 + 2 files changed, 188 insertions(+), 4 deletions(-) (limited to 'src/plugins/platforms/winrt') diff --git a/src/plugins/platforms/winrt/qwinrtdrag.cpp b/src/plugins/platforms/winrt/qwinrtdrag.cpp index a52ed91749..8ccb211e4f 100644 --- a/src/plugins/platforms/winrt/qwinrtdrag.cpp +++ b/src/plugins/platforms/winrt/qwinrtdrag.cpp @@ -88,6 +88,13 @@ inline QString hStringToQString(const HString &hString) return (QString::fromWCharArray(raw, l)); } +inline HString qStringToHString(const QString &qString) +{ + HString h; + h.Set(reinterpret_cast(qString.utf16()), qString.size()); + return h; +} + namespace NativeFormatStrings { static ComPtr dataStatics; static HSTRING text; // text/plain @@ -198,7 +205,6 @@ QStringList QWinRTInternalMimeData::formats_sys() const continue; formats.append(hStringToQString(str)); } - qDebug() << __FUNCTION__ << "Available formats:" << formats; return formats; } @@ -510,6 +516,8 @@ Q_DECLARE_DRAGHANDLER(Drop, drop) Q_GLOBAL_STATIC(QWinRTDrag, gDrag); +extern ComPtr qt_winrt_lastPointerPoint; // qwinrtscreen.cpp + QWinRTDrag::QWinRTDrag() : QPlatformDrag() , m_dragTarget(0) @@ -537,11 +545,184 @@ QWinRTDrag *QWinRTDrag::instance() return gDrag; } +inline HRESULT resetUiElementDrag(ComPtr &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; - // ### TODO: Add dragging from Window - return Qt::IgnoreAction; + + if (!qt_winrt_lastPointerPoint) { + Q_ASSERT_X(qt_winrt_lastPointerPoint, Q_FUNC_INFO, "No pointerpoint known"); + return Qt::IgnoreAction; + } + + ComPtr elem3; + HRESULT hr = m_ui.As(&elem3); + Q_ASSERT_SUCCEEDED(hr); + + ComPtr> op; + EventRegistrationToken startingToken; + + hr = QEventDispatcherWinRT::runOnXamlThread([drag, &op, &hr, elem3, &startingToken, this]() { + + hr = elem3->put_CanDrag(true); + Q_ASSERT_SUCCEEDED(hr); + + auto startingCallback = Callback> ([drag](IInspectable *, IDragStartingEventArgs *args) { + qCDebug(lcQpaMime) << "Drag starting" << args; + + ComPtr 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); + + ComPtr 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); + + 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 + + const QStringList formats = mimeData->formats(); + for (auto item : formats) { + QByteArray data = mimeData->data(item); + + ComPtr bufferFactory; + hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Storage_Streams_Buffer).Get(), + IID_PPV_ARGS(&bufferFactory)); + Q_ASSERT_SUCCEEDED(hr); + + ComPtr buffer; + const UINT32 length = data.size(); + hr = bufferFactory->Create(length, &buffer); + Q_ASSERT_SUCCEEDED(hr); + hr = buffer->put_Length(length); + Q_ASSERT_SUCCEEDED(hr); + + ComPtr byteArrayAccess; + hr = buffer.As(&byteArrayAccess); + Q_ASSERT_SUCCEEDED(hr); + + byte *bytes; + hr = byteArrayAccess->Buffer(&bytes); + Q_ASSERT_SUCCEEDED(hr); + memcpy(bytes, data.constData(), length); + + // 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 ras; + hr = RoActivateInstance(HString::MakeReference(RuntimeClass_Windows_Storage_Streams_InMemoryRandomAccessStream).Get(), &ras); + Q_ASSERT_SUCCEEDED(hr); + + hr = ras->put_Size(length); + ComPtr outputStream; + hr = ras->GetOutputStreamAt(0, &outputStream); + Q_ASSERT_SUCCEEDED(hr); + + ComPtr> 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> flushOp; + hr = outputStream.Get()->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); + + ComPtr pointStatics; + + hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_UI_Input_PointerPoint).Get(), + IID_PPV_ARGS(&pointStatics)); + 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) @@ -586,7 +767,6 @@ void QWinRTDrag::handleNativeDragEvent(IInspectable *sender, ABI::Windows::UI::X hr = e->GetPosition(m_ui.Get(), &relativePoint); RETURN_VOID_IF_FAILED("Could not query drag position."); const QPoint p(relativePoint.X, relativePoint.Y); - qDebug() << "Point received:" << relativePoint.X << "/" << relativePoint.Y; ComPtr e2; hr = e->QueryInterface(IID_PPV_ARGS(&e2)); diff --git a/src/plugins/platforms/winrt/qwinrtscreen.cpp b/src/plugins/platforms/winrt/qwinrtscreen.cpp index 3d9baf555d..43847e1ecc 100644 --- a/src/plugins/platforms/winrt/qwinrtscreen.cpp +++ b/src/plugins/platforms/winrt/qwinrtscreen.cpp @@ -982,6 +982,9 @@ HRESULT QWinRTScreen::onPointerExited(ICoreWindow *, IPointerEventArgs *args) return S_OK; } +// Required for qwinrtdrag.cpp +ComPtr qt_winrt_lastPointerPoint; + HRESULT QWinRTScreen::onPointerUpdated(ICoreWindow *, IPointerEventArgs *args) { Q_D(QWinRTScreen); @@ -989,6 +992,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); -- cgit v1.2.3 From e8ff3c8cbc8a66c344e2c974ae92f2cea7a2e5fe Mon Sep 17 00:00:00 2001 From: Maurice Kalinowski Date: Fri, 27 May 2016 13:13:40 +0200 Subject: winrt: fix drag pixmap support Previously dragging only displayed the type of operation provided by the system. Now, in case a pixmap is specified, an image is shown. Also incorporated some cleanups. Task-number: QTBUG-50827 Change-Id: I471e2081eabfed014b08d189538d1d62cdb7248e Reviewed-by: Oliver Wolff --- src/plugins/platforms/winrt/qwinrtdrag.cpp | 156 ++++++++++++++++++----------- 1 file changed, 96 insertions(+), 60 deletions(-) (limited to 'src/plugins/platforms/winrt') diff --git a/src/plugins/platforms/winrt/qwinrtdrag.cpp b/src/plugins/platforms/winrt/qwinrtdrag.cpp index 8ccb211e4f..14bea7ab30 100644 --- a/src/plugins/platforms/winrt/qwinrtdrag.cpp +++ b/src/plugins/platforms/winrt/qwinrtdrag.cpp @@ -47,6 +47,7 @@ #include #include #include +#include #include #include #include @@ -55,6 +56,7 @@ 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; @@ -65,6 +67,34 @@ QT_BEGIN_NAMESPACE Q_LOGGING_CATEGORY(lcQpaMime, "qt.qpa.mime") +ComPtr createIBufferFromData(const char *data, qint32 size) +{ + static ComPtr bufferFactory; + HRESULT hr; + if (!bufferFactory) { + hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Storage_Streams_Buffer).Get(), + IID_PPV_ARGS(&bufferFactory)); + Q_ASSERT_SUCCEEDED(hr); + } + + ComPtr buffer; + const UINT32 length = size; + hr = bufferFactory->Create(length, &buffer); + Q_ASSERT_SUCCEEDED(hr); + hr = buffer->put_Length(length); + Q_ASSERT_SUCCEEDED(hr); + + ComPtr 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 @@ -175,36 +205,42 @@ QStringList QWinRTInternalMimeData::formats_sys() const if (!formats.isEmpty()) return formats; - 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> availableFormats; - hr = dataView->get_AvailableFormats(&availableFormats); - RETURN_IF_FAILED("Could not query available formats.", return formats); - - quint32 size; - hr = availableFormats->get_Size(&size); - RETURN_IF_FAILED("Could not query format vector size.", return formats); - for (quint32 i = 0; i < size; ++i) { - HString str; - hr = availableFormats->GetAt(i, str.GetAddressOf()); - if (FAILED(hr)) - continue; - formats.append(hStringToQString(str)); - } + 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> 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; } @@ -265,8 +301,6 @@ QVariant QWinRTInternalMimeData::retrieveData_sys(const QString &mimetype, QVari result.setValue(hStringToQString(res)); return S_OK; }); - } else if (mimetype.startsWith(QLatin1String("image/"))) { - Q_UNIMPLEMENTED(); } else { // Asking for custom data hr = QEventDispatcherWinRT::runOnXamlThread([this, &result, mimetype]() { @@ -615,30 +649,39 @@ Qt::DropAction QWinRTDrag::drag(QDrag *drag) } // ### TODO: Missing: weblink, image - const QStringList formats = mimeData->formats(); - for (auto item : formats) { - QByteArray data = mimeData->data(item); + 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 imageBuffer = createIBufferFromData(reinterpret_cast(image.bits()), image.byteCount()); - ComPtr bufferFactory; - hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Storage_Streams_Buffer).Get(), - IID_PPV_ARGS(&bufferFactory)); - Q_ASSERT_SUCCEEDED(hr); + ComPtr bitmapFactory; + hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Graphics_Imaging_SoftwareBitmap).Get(), + IID_PPV_ARGS(&bitmapFactory)); + Q_ASSERT_SUCCEEDED(hr); - ComPtr buffer; - const UINT32 length = data.size(); - hr = bufferFactory->Create(length, &buffer); - Q_ASSERT_SUCCEEDED(hr); - hr = buffer->put_Length(length); - Q_ASSERT_SUCCEEDED(hr); + ComPtr bitmap; + hr = bitmapFactory->Create(BitmapPixelFormat_Rgba8, image.width(), image.height(), &bitmap); + Q_ASSERT_SUCCEEDED(hr); - ComPtr byteArrayAccess; - hr = buffer.As(&byteArrayAccess); - Q_ASSERT_SUCCEEDED(hr); + hr = bitmap->CopyFromBuffer(imageBuffer.Get()); + Q_ASSERT_SUCCEEDED(hr); - byte *bytes; - hr = byteArrayAccess->Buffer(&bytes); - Q_ASSERT_SUCCEEDED(hr); - memcpy(bytes, data.constData(), length); + ComPtr 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 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 @@ -648,7 +691,7 @@ Qt::DropAction QWinRTDrag::drag(QDrag *drag) hr = RoActivateInstance(HString::MakeReference(RuntimeClass_Windows_Storage_Streams_InMemoryRandomAccessStream).Get(), &ras); Q_ASSERT_SUCCEEDED(hr); - hr = ras->put_Size(length); + hr = ras->put_Size(data.size()); ComPtr outputStream; hr = ras->GetOutputStreamAt(0, &outputStream); Q_ASSERT_SUCCEEDED(hr); @@ -663,7 +706,7 @@ Qt::DropAction QWinRTDrag::drag(QDrag *drag) unsigned char flushResult; ComPtr> flushOp; - hr = outputStream.Get()->FlushAsync(&flushOp); + hr = outputStream->FlushAsync(&flushOp); Q_ASSERT_SUCCEEDED(hr); hr = QWinRTFunctions::await(flushOp, &flushResult); @@ -671,7 +714,6 @@ Qt::DropAction QWinRTDrag::drag(QDrag *drag) hr = dataPackage->SetData(qStringToHString(item).Get(), ras.Get()); Q_ASSERT_SUCCEEDED(hr); - } return S_OK; }); @@ -679,12 +721,6 @@ Qt::DropAction QWinRTDrag::drag(QDrag *drag) hr = elem3->add_DragStarting(startingCallback.Get(), &startingToken); Q_ASSERT_SUCCEEDED(hr); - ComPtr pointStatics; - - hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_UI_Input_PointerPoint).Get(), - IID_PPV_ARGS(&pointStatics)); - Q_ASSERT_SUCCEEDED(hr); - hr = elem3->StartDragAsync(qt_winrt_lastPointerPoint.Get(), &op); Q_ASSERT_SUCCEEDED(hr); -- cgit v1.2.3 From bb30da895eca5a80265317db1fc7a0d151005e30 Mon Sep 17 00:00:00 2001 From: Maurice Kalinowski Date: Tue, 31 May 2016 13:46:51 +0200 Subject: winrt: fix compilation without drag and drop support Change-Id: Ifd0d2238e8dacffe34753d95e12cccfd13519c55 Reviewed-by: Oliver Wolff --- src/plugins/platforms/winrt/qwinrtintegration.cpp | 4 ++++ src/plugins/platforms/winrt/qwinrtscreen.cpp | 8 +++++--- src/plugins/platforms/winrt/winrt.pro | 2 +- 3 files changed, 10 insertions(+), 4 deletions(-) (limited to 'src/plugins/platforms/winrt') diff --git a/src/plugins/platforms/winrt/qwinrtintegration.cpp b/src/plugins/platforms/winrt/qwinrtintegration.cpp index 01e8a42b8e..8c419dcdbc 100644 --- a/src/plugins/platforms/winrt/qwinrtintegration.cpp +++ b/src/plugins/platforms/winrt/qwinrtintegration.cpp @@ -45,7 +45,9 @@ #include "qwinrtfontdatabase.h" #include "qwinrttheme.h" #include "qwinrtclipboard.h" +#ifndef QT_NO_DRAGANDDROP #include "qwinrtdrag.h" +#endif #include #include @@ -310,6 +312,7 @@ QPlatformClipboard *QWinRTIntegration::clipboard() const return d->clipboard; } +#ifndef QT_NO_DRAGANDDROP QPlatformDrag *QWinRTIntegration::drag() const { #if _MSC_VER >= 1900 @@ -318,6 +321,7 @@ QPlatformDrag *QWinRTIntegration::drag() const return QPlatformIntegration::drag(); #endif } +#endif // QT_NO_DRAGANDDROP Qt::KeyboardModifiers QWinRTIntegration::queryKeyboardModifiers() const { diff --git a/src/plugins/platforms/winrt/qwinrtscreen.cpp b/src/plugins/platforms/winrt/qwinrtscreen.cpp index 43847e1ecc..c1118cd0b8 100644 --- a/src/plugins/platforms/winrt/qwinrtscreen.cpp +++ b/src/plugins/platforms/winrt/qwinrtscreen.cpp @@ -39,7 +39,9 @@ #include "qwinrtbackingstore.h" #include "qwinrtinputcontext.h" #include "qwinrtcursor.h" +#ifndef QT_NO_DRAGANDDROP #include "qwinrtdrag.h" +#endif #include "qwinrtwindow.h" #include @@ -554,7 +556,7 @@ QWinRTScreen::QWinRTScreen() ComPtr uiElement; hr = canvas.As(&uiElement); Q_ASSERT_SUCCEEDED(hr); -#if _MSC_VER >= 1900 +#if _MSC_VER >= 1900 && !defined(QT_NO_DRAGANDDROP) QWinRTDrag::instance()->setUiElement(uiElement); #endif hr = window->put_Content(uiElement.Get()); @@ -766,7 +768,7 @@ void QWinRTScreen::addWindow(QWindow *window) handleExpose(); QWindowSystemInterface::flushWindowSystemEvents(); -#if _MSC_VER >= 1900 +#if _MSC_VER >= 1900 && !defined(QT_NO_DRAGANDDROP) QWinRTDrag::instance()->setDropTarget(window); #endif } @@ -783,7 +785,7 @@ void QWinRTScreen::removeWindow(QWindow *window) QWindowSystemInterface::handleWindowActivated(window, Qt::OtherFocusReason); handleExpose(); QWindowSystemInterface::flushWindowSystemEvents(); -#if _MSC_VER >= 1900 +#if _MSC_VER >= 1900 && !defined(QT_NO_DRAGANDDROP) if (wasTopWindow) QWinRTDrag::instance()->setDropTarget(topWindow()); #endif diff --git a/src/plugins/platforms/winrt/winrt.pro b/src/plugins/platforms/winrt/winrt.pro index 5c62b5718b..dd1e051c33 100644 --- a/src/plugins/platforms/winrt/winrt.pro +++ b/src/plugins/platforms/winrt/winrt.pro @@ -49,7 +49,7 @@ HEADERS = \ OTHER_FILES += winrt.json -*-msvc2013 { +*-msvc2013|contains(DEFINES, QT_NO_DRAGANDDROP) { SOURCES -= qwinrtdrag.cpp HEADERS -= qwinrtdrag.h } -- cgit v1.2.3 From 9c01fdb2badd0cbc5369cc31b6626718e5b4c23c Mon Sep 17 00:00:00 2001 From: Maurice Kalinowski Date: Thu, 2 Jun 2016 11:12:29 +0200 Subject: winrt: Fix compilation for 10586 SDK The current implementation of drag and drop requires Redstone 2 Update (SDK version 14322) to be fully functional. The API is limited for previous versions. However, this mostly affects passing allowed operations between sender and receiver, the rest is mostly functional still. Once RedStone 2 is out (estimated July 2016) we can bump the minimum SDK version to 14322. Task-number: QTBUG-50827 Change-Id: I5bab9d36a228d68c1809c241a64168d48c353335 Reviewed-by: Simon Hausmann Reviewed-by: Friedemann Kleint Reviewed-by: Liang Qi Reviewed-by: Oliver Wolff --- src/plugins/platforms/winrt/qwinrtdrag.cpp | 7 ++++++- src/plugins/platforms/winrt/winrt.pro | 4 ++++ 2 files changed, 10 insertions(+), 1 deletion(-) (limited to 'src/plugins/platforms/winrt') diff --git a/src/plugins/platforms/winrt/qwinrtdrag.cpp b/src/plugins/platforms/winrt/qwinrtdrag.cpp index 14bea7ab30..2ef50aa4e2 100644 --- a/src/plugins/platforms/winrt/qwinrtdrag.cpp +++ b/src/plugins/platforms/winrt/qwinrtdrag.cpp @@ -623,6 +623,7 @@ Qt::DropAction QWinRTDrag::drag(QDrag *drag) hr = dataPackage->put_RequestedOperation(translateFromQDragDropActions(action)); Q_ASSERT_SUCCEEDED(hr); +#ifndef QT_WINRT_LIMITED_DRAGANDDROP ComPtr args2; hr = args->QueryInterface(IID_PPV_ARGS(&args2)); Q_ASSERT_SUCCEEDED(hr); @@ -637,7 +638,7 @@ Qt::DropAction QWinRTDrag::drag(QDrag *drag) 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()); @@ -811,6 +812,7 @@ void QWinRTDrag::handleNativeDragEvent(IInspectable *sender, ABI::Windows::UI::X DragDropModifiers modifiers; hr = e2->get_Modifiers(&modifiers); +#ifndef QT_WINRT_LIMITED_DRAGANDDROP ComPtr e3; hr = e->QueryInterface(IID_PPV_ARGS(&e3)); Q_ASSERT_SUCCEEDED(hr); @@ -821,6 +823,9 @@ void QWinRTDrag::handleNativeDragEvent(IInspectable *sender, ABI::Windows::UI::X 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 dataView; hr = e2->get_DataView(&dataView); diff --git a/src/plugins/platforms/winrt/winrt.pro b/src/plugins/platforms/winrt/winrt.pro index dd1e051c33..f5591934f5 100644 --- a/src/plugins/platforms/winrt/winrt.pro +++ b/src/plugins/platforms/winrt/winrt.pro @@ -49,6 +49,10 @@ 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 -- cgit v1.2.3