diff options
Diffstat (limited to 'src/plugins/platforms/winrt/qwinrtdrag.cpp')
-rw-r--r-- | src/plugins/platforms/winrt/qwinrtdrag.cpp | 889 |
1 files changed, 0 insertions, 889 deletions
diff --git a/src/plugins/platforms/winrt/qwinrtdrag.cpp b/src/plugins/platforms/winrt/qwinrtdrag.cpp deleted file mode 100644 index 3ed4cd692d..0000000000 --- a/src/plugins/platforms/winrt/qwinrtdrag.cpp +++ /dev/null @@ -1,889 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://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.LGPL3 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-3.0.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 (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.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 = UINT32(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 = 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, int(l))); -} - -inline HString qStringToHString(const QString &qString) -{ - HString h; - h.Set(reinterpret_cast<const wchar_t*>(qString.utf16()), uint(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); - } -} - -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()), uint(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 propertyType; - propertyValue->get_Type(&propertyType); - switch (propertyType) { - 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:" << propertyType; - } - 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 = UINT32(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, int(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 ~QtDragEventHandler##name() {\ - }\ - STDMETHODIMP 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(nullptr) -{ - 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]() { - - 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()), int(image.sizeInBytes())); - - 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(UINT64(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; -} - -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(int(relativePoint.X), int(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" |