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') 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