diff --git a/ChangeLog b/ChangeLog index 309107bda..baffb175d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -17,6 +17,7 @@ Unreleased Version 2.2.2-pre * Fix: Don't crash when filling with feathering and a canvas-filling selection. Thanks Meru for reporting. * Fix: Don't carry over HUD button presses to dock UI in small screen mode. Thanks Meru for reporting. * Feature: Make list action buttons in settings dialog clearer, adding an edit button for canvas shortcuts. Thanks Maffi for suggesting. + * Fix: Work around broken transparency when copying images between canvases on Wayland. Thanks Absolute Goober for reporting. 2024-11-06 Version 2.2.2-beta.4 * Fix: Solve rendering glitches with selection outlines that happen on some systems. Thanks xxxx for reporting. diff --git a/src/desktop/mainwindow.cpp b/src/desktop/mainwindow.cpp index 7abf5cbfc..212c9ddf1 100644 --- a/src/desktop/mainwindow.cpp +++ b/src/desktop/mainwindow.cpp @@ -3593,11 +3593,13 @@ void MainWindow::copyText() textedit->copy(); } +// clang-format on void MainWindow::paste() { utils::ScopedOverrideCursor waitCursor; const QMimeData *mimeData = Document::getClipboardData(); - if(mimeData && mimeData->hasImage()) { + QImage img = Document::getClipboardImageData(mimeData); + if(!img.isNull()) { QPoint pastepos; bool pasteAtPos = false; @@ -3611,25 +3613,27 @@ void MainWindow::paste() qint64 pid = pos.at(2).toLongLong(&ok3); qulonglong doc = pos.at(3).toULongLong(&ok4); pasteAtPos = ok1 && ok2 && ok3 && ok4 && - pid == qApp->applicationPid() && doc == m_doc->pasteId(); + pid == qApp->applicationPid() && + doc == m_doc->pasteId(); } } // Paste-in-place if we're the source (same process, same document) - if(pasteAtPos && m_canvasView->isPointVisible(pastepos)) - pasteImage(mimeData->imageData().value(), &pastepos, true); - else - pasteImage(mimeData->imageData().value()); + if(pasteAtPos && m_canvasView->isPointVisible(pastepos)) { + pasteImage(img, &pastepos, true); + } else { + pasteImage(img); + } } } -// clang-format on void MainWindow::pasteCentered() { utils::ScopedOverrideCursor waitCursor; const QMimeData *mimeData = Document::getClipboardData(); - if(mimeData && mimeData->hasImage()) { - pasteImage(mimeData->imageData().value(), nullptr, true); + QImage img = Document::getClipboardImageData(mimeData); + if(!img.isNull()) { + pasteImage(img, nullptr, true); } } diff --git a/src/libclient/document.cpp b/src/libclient/document.cpp index 5bcfcb8f7..6e8ad0bd3 100644 --- a/src/libclient/document.cpp +++ b/src/libclient/document.cpp @@ -1443,7 +1443,24 @@ bool Document::copyFromLayer(int layer) if(!img.isNull() && layer == 0) { fillBackground(img); } + +#ifdef Q_OS_LINUX + // Copying image data from one Drawpile canvas to another is busted on + // Wayland, obliterating transparency. We store a PNG directly instead. + if(QGuiApplication::platformName() == QStringLiteral("wayland")) { + QByteArray bytes; + { + QBuffer buffer(&bytes); + buffer.open(QIODevice::WriteOnly); + img.save(&buffer, "PNG"); + } + data->setData(QStringLiteral("image/png"), bytes); + } else { + data->setImageData(img); + } +#else data->setImageData(img); +#endif // Store also original coordinates QRect bounds = m_canvas->selection()->bounds(); @@ -1684,6 +1701,22 @@ const QMimeData *Document::getClipboardData() #endif } +QImage Document::getClipboardImageData(const QMimeData *mimeData) +{ + if(mimeData) { + if(mimeData->hasImage()) { + return mimeData->imageData().value(); + } else if(mimeData->hasFormat(QStringLiteral("image/png"))) { + QImage img; + if(img.loadFromData( + mimeData->data(QStringLiteral("image/png")), "PNG")) { + return img; + } + } + } + return QImage(); +} + #ifdef HAVE_CLIPBOARD_EMULATION QMimeData Document::clipboardData; #endif diff --git a/src/libclient/document.h b/src/libclient/document.h index 125524165..ffe9ef752 100644 --- a/src/libclient/document.h +++ b/src/libclient/document.h @@ -302,6 +302,7 @@ public slots: void addServerLogEntry(const QString &log); static const QMimeData *getClipboardData(); + static QImage getClipboardImageData(const QMimeData *mimeData); private slots: void onServerLogin(