From cb96a7bab85d29ea31aba9953ada743cf627ccc8 Mon Sep 17 00:00:00 2001 From: donghualin Date: Tue, 11 Oct 2022 08:29:02 +0000 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8Dwayland=E4=B8=8B?= =?UTF-8?q?=E7=AA=97=E5=8F=A3=E9=A2=84=E8=A7=88=E4=B8=BA=E7=A9=BA=E7=9A=84?= =?UTF-8?q?=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 将获取窗口预览图的接口修改为CaptureWindow接口来获取,在wayland和x11下接口统一 Log: 修复wayland下窗口预览图为空的问题 Influence: 进入wayland,鼠标放入任务栏已经打开的窗口图标上,观察预览图是否显示 Bug: https://pms.uniontech.com/bug-view-140919.html Bug: https://pms.uniontech.com/bug-view-150475.html Change-Id: Idc18a356c8df19a73130362e839a61ed26108d23 --- frame/item/appmultiitem.cpp | 15 +--- frame/item/appmultiitem.h | 2 +- frame/item/components/appsnapshot.cpp | 53 ++++-------- frame/item/components/appsnapshot.h | 6 +- frame/item/components/floatingpreview.cpp | 2 +- frame/util/imageutil.cpp | 98 ++++++++++++++--------- frame/util/imageutil.h | 6 +- 7 files changed, 87 insertions(+), 95 deletions(-) diff --git a/frame/item/appmultiitem.cpp b/frame/item/appmultiitem.cpp index f387912f8..cabb94260 100644 --- a/frame/item/appmultiitem.cpp +++ b/frame/item/appmultiitem.cpp @@ -109,20 +109,13 @@ void AppMultiItem::paintEvent(QPaintEvent *) painter.setRenderHint(QPainter::Antialiasing, true); painter.setRenderHint(QPainter::SmoothPixmapTransform, true); - if (m_snapImage.isNull()) { -#ifdef USE_AM - if (Utils::IS_WAYLAND_DISPLAY) - m_snapImage = ImageUtil::loadWindowThumb(m_windowInfo.uuid, width() - 20, height() - 20); - else -#endif - m_snapImage = ImageUtil::loadWindowThumb(m_winId, width() - 20, height() - 20); - } + if (m_pixmap.isNull()) + m_pixmap = ImageUtil::loadWindowThumb(Utils::IS_WAYLAND_DISPLAY ? m_windowInfo.uuid : QString::number(m_winId)); DStyleHelper dstyle(style()); const int radius = dstyle.pixelMetric(DStyle::PM_FrameRadius); QRect itemRect = rect(); itemRect.marginsRemoved(QMargins(6, 6, 6, 6)); - QPixmap pixmapWindowIcon = QPixmap::fromImage(m_snapImage); QPainterPath path; path.addRoundedRect(rect(), radius, radius); painter.fillPath(path, Qt::transparent); @@ -133,12 +126,12 @@ void AppMultiItem::paintEvent(QPaintEvent *) painter.fillPath(path, backColor); } - itemRect = m_snapImage.rect(); + itemRect = m_pixmap.rect(); int itemWidth = itemRect.width(); int itemHeight = itemRect.height(); int x = (rect().width() - itemWidth) / 2; int y = (rect().height() - itemHeight) / 2; - painter.drawPixmap(QRect(x, y, itemWidth, itemHeight), pixmapWindowIcon); + painter.drawPixmap(QRect(x, y, itemWidth, itemHeight), m_pixmap); QPixmap pixmapAppIcon; ThemeAppIcon::getIcon(pixmapAppIcon, m_entryInter->icon(), qMin(width(), height()) * 0.8); diff --git a/frame/item/appmultiitem.h b/frame/item/appmultiitem.h index ea9963f0c..3c0c2d0a5 100644 --- a/frame/item/appmultiitem.h +++ b/frame/item/appmultiitem.h @@ -59,7 +59,7 @@ private: AppItem *m_appItem; WindowInfo m_windowInfo; DockEntryInter *m_entryInter; - QImage m_snapImage; + QPixmap m_pixmap; WId m_winId; QMenu *m_menu; }; diff --git a/frame/item/components/appsnapshot.cpp b/frame/item/components/appsnapshot.cpp index dd598235a..a271fc617 100644 --- a/frame/item/components/appsnapshot.cpp +++ b/frame/item/components/appsnapshot.cpp @@ -38,6 +38,7 @@ #include #include #include +#include struct SHMInfo { long shmid; @@ -206,31 +207,24 @@ void AppSnapshot::fetchSnapshot() if (!m_wmHelper->hasComposite()) return; - QImage qimage; SHMInfo *info = nullptr; uchar *image_data = nullptr; XImage *ximage = nullptr; // 优先使用窗管进行窗口截图 if (isKWinAvailable()) { -#ifdef USE_AM - if (Utils::IS_WAYLAND_DISPLAY) - m_snapshot = ImageUtil::loadWindowThumb(m_windowInfo.uuid, SNAP_WIDTH, SNAP_HEIGHT); - else -#endif - m_snapshot = ImageUtil::loadWindowThumb(m_wid, SNAP_WIDTH, SNAP_HEIGHT); - - m_snapshotSrcRect = m_snapshot.rect(); + const QString windowInfoId = Utils::IS_WAYLAND_DISPLAY ? m_windowInfo.uuid : QString::number(m_wid); + m_pixmap = ImageUtil::loadWindowThumb(windowInfoId); } else { do { // get window image from shm(only for deepin app) + QImage qimage; info = getImageDSHM(); if (info) { qDebug() << "get Image from dxcbplugin SHM..."; image_data = (uchar *)shmat(info->shmid, 0, 0); if ((qint64)image_data != -1) { - m_snapshot = QImage(image_data, info->width, info->height, info->bytesPerLine, (QImage::Format)info->format); - m_snapshotSrcRect = QRect(info->rect.x, info->rect.y, info->rect.width, info->rect.height); + qimage = QImage(image_data, info->width, info->height, info->bytesPerLine, (QImage::Format)info->format); break; } qDebug() << "invalid pointer of shm!"; @@ -253,23 +247,10 @@ void AppSnapshot::fetchSnapshot() Q_ASSERT(!qimage.isNull()); - // remove shadow frame - m_snapshotSrcRect = rectRemovedShadow(qimage, nullptr); - m_snapshot = qimage; + m_pixmap = QPixmap::fromImage(qimage); } while (false); } - QSizeF size(rect().marginsRemoved(QMargins(8, 8, 8, 8)).size()); - const auto ratio = devicePixelRatioF(); - size = m_snapshotSrcRect.size().scaled(size * ratio, Qt::KeepAspectRatio); - qreal scale = qreal(size.width()) / m_snapshotSrcRect.width(); - m_snapshot = m_snapshot.scaled(qRound(m_snapshot.width() * scale), qRound(m_snapshot.height() * scale), - Qt::IgnoreAspectRatio, Qt::SmoothTransformation); - m_snapshotSrcRect.moveTop(m_snapshotSrcRect.top() * scale + 0.5); - m_snapshotSrcRect.moveLeft(m_snapshotSrcRect.left() * scale + 0.5); - m_snapshotSrcRect.setWidth(size.width() - 0.5); - m_snapshotSrcRect.setHeight(size.height() - 0.5); - if (image_data) shmdt(image_data); if (ximage) XDestroyImage(ximage); if (info) XFree(info); @@ -312,7 +293,7 @@ void AppSnapshot::paintEvent(QPaintEvent *e) return; } - if (m_snapshot.isNull()) + if (m_pixmap.isNull()) return; const auto ratio = devicePixelRatioF(); @@ -324,22 +305,20 @@ void AppSnapshot::paintEvent(QPaintEvent *e) painter.drawRoundedRect(rect(), 5, 5); } - // draw image - const QImage &im = m_snapshot; - - const qreal offset_x = width() / 2.0 - m_snapshotSrcRect.width() / ratio / 2 - m_snapshotSrcRect.left() / ratio; - const qreal offset_y = height() / 2.0 - m_snapshotSrcRect.height() / ratio / 2 - m_snapshotSrcRect.top() / ratio; + const qreal offset_x = width() / 2.0 - SNAP_WIDTH / ratio / 2; + const qreal offset_y = height() / 2.0 - SNAP_HEIGHT / ratio / 2; DStyleHelper dstyle(style()); const int radius = dstyle.pixelMetric(DStyle::PM_FrameRadius); - QBrush brush; - brush.setTextureImage(im); - painter.setBrush(brush); - painter.setPen(Qt::NoPen); - painter.scale(1 / ratio, 1 / ratio); + painter.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform); painter.translate(QPoint(offset_x * ratio, offset_y * ratio)); - painter.drawRoundedRect(m_snapshotSrcRect, radius * ratio, radius * ratio); + QRect imageRect(8, 8, width() - 16, height() - 16); + painter.setPen(Qt::NoPen); + QPainterPath path; + path.addRoundedRect(imageRect, radius * ratio, radius * ratio); + painter.setClipPath(path); + painter.drawPixmap(imageRect, m_pixmap, m_pixmap.rect()); } void AppSnapshot::mousePressEvent(QMouseEvent *e) diff --git a/frame/item/components/appsnapshot.h b/frame/item/components/appsnapshot.h index 8282caefe..811acdbd7 100644 --- a/frame/item/components/appsnapshot.h +++ b/frame/item/components/appsnapshot.h @@ -68,8 +68,7 @@ public: inline bool attentioned() const { return m_windowInfo.attention; } inline bool closeAble() const { return m_closeAble; } inline void setCloseAble(const bool value) { m_closeAble = value; } - inline const QImage snapshot() const { return m_snapshot; } - inline const QRectF snapshotGeometry() const { return m_snapshotSrcRect; } + inline const QPixmap snapshot() const { return m_pixmap; } inline const QString title() const { return m_windowInfo.title; } void setWindowState(); void setTitleVisible(bool bVisible); @@ -108,8 +107,7 @@ private: bool m_closeAble; bool m_isWidowHidden; - QImage m_snapshot; - QRectF m_snapshotSrcRect; + QPixmap m_pixmap; Dock::TipsWidget *m_title; DPushButton *m_3DtitleBtn; diff --git a/frame/item/components/floatingpreview.cpp b/frame/item/components/floatingpreview.cpp index be9960d0c..925f6d2f6 100644 --- a/frame/item/components/floatingpreview.cpp +++ b/frame/item/components/floatingpreview.cpp @@ -109,7 +109,7 @@ void FloatingPreview::paintEvent(QPaintEvent *e) if (m_tracked.isNull()) return; - const QImage &snapshot = m_tracked->snapshot(); + const QPixmap &snapshot = m_tracked->snapshot(); if (snapshot.isNull()) return; diff --git a/frame/util/imageutil.cpp b/frame/util/imageutil.cpp index e3bc0a00c..7167bc6b4 100644 --- a/frame/util/imageutil.cpp +++ b/frame/util/imageutil.cpp @@ -32,9 +32,15 @@ #include #include #include +#include +#include #include +#include +#include +#include + const QPixmap ImageUtil::loadSvg(const QString &iconName, const QString &localPath, const int size, const qreal ratio) { QIcon icon = QIcon::fromTheme(iconName); @@ -88,52 +94,66 @@ QCursor* ImageUtil::loadQCursorFromX11Cursor(const char* theme, const char* curs return cursor; } -QImage ImageUtil::loadWindowThumb(const WId &windowId, int width, int height) +QPixmap ImageUtil::loadWindowThumb(const QString &winInfoId) { - QDBusInterface interface(QStringLiteral("org.kde.KWin"), QStringLiteral("/Screenshot"), QStringLiteral("org.kde.kwin.Screenshot")); + // 在tmp下创建临时目录,用来存放缩略图 + QString thumbPath(imagePath()); + QDir dir(thumbPath); + if (!dir.exists()) + dir.mkpath(thumbPath); - QList args; - args << QVariant::fromValue(windowId); - args << QVariant::fromValue(quint32(width)); - args << QVariant::fromValue(quint32(height)); - - QDBusReply reply = interface.callWithArgumentList(QDBus::Block, QStringLiteral("screenshotForWindowExtend"), args); - if(reply.isValid()){ - const QString tmpFile = reply.value(); - if (QFile::exists(tmpFile)) { - QImage image(tmpFile); - QFile::remove(tmpFile); - return image; - } - qDebug() << "get current workspace background error, file does not exist : " << tmpFile; - } else { - qDebug() << "get current workspace background error: "<< reply.error().message(); + QString fileName = QString("%1/%2").arg(thumbPath).arg(winInfoId); + int fileId = open(fileName.toLocal8Bit().data(), O_CREAT | O_RDWR, S_IWUSR | S_IRUSR); + if (fileId < 0) { + //打开文件失败 + return QPixmap(); } - return QImage(); -} - -QImage ImageUtil::loadWindowThumb(const QString &uuid, int width, int height) -{ - QDBusInterface interface(QStringLiteral("org.kde.KWin"), QStringLiteral("/Screenshot"), QStringLiteral("org.kde.kwin.Screenshot")); - + QDBusInterface interface(QStringLiteral("org.kde.KWin"), QStringLiteral("/org/kde/KWin/ScreenShot2"), QStringLiteral("org.kde.KWin.ScreenShot2")); + // 第一个参数,winID或者UUID QList args; - args << QVariant::fromValue(uuid); - args << QVariant::fromValue(quint32(width)); - args << QVariant::fromValue(quint32(height)); + args << QVariant::fromValue(winInfoId); + // 第二个参数,需要截图的选项 + QVariantMap option; + option["include-decoration"] = true; + option["include-cursor"] = false; + option["native-resolution"] = true; + args << QVariant::fromValue(option); + // 第三个参数,文件描述符 + args << QVariant::fromValue(QDBusUnixFileDescriptor(fileId)); - QDBusReply reply = interface.callWithArgumentList(QDBus::Block, QStringLiteral("screenshotForWindowExtendUuid"), args); - if(reply.isValid()){ - const QString tmpFile = reply.value(); - if (QFile::exists(tmpFile)) { - QImage image(tmpFile); - QFile::remove(tmpFile); - return image; - } - qDebug() << "get current workspace background error, file does not exist : " << tmpFile; - } else { + QDBusReply reply = interface.callWithArgumentList(QDBus::Block, QStringLiteral("CaptureWindow"), args); + if(!reply.isValid()) { + close(fileId); qDebug() << "get current workspace background error: "<< reply.error().message(); + return QPixmap(); } - return QImage(); + QVariantMap imageInfo = reply.value(); + int imageWidth = imageInfo.value("width").toUInt(); + int imageHeight = imageInfo.value("height").toUInt(); + int imageStride = imageInfo.value("stride").toUInt(); + int imageFormat = imageInfo.value("format").toUInt(); + + QFile file; + if (!file.open(fileId, QIODevice::ReadOnly)) { + close(fileId); + return QPixmap(); + } + + if (file.size() == 0) { + file.close(); + return QPixmap(); + } + + QByteArray fileContent = file.readAll(); + QImage image(reinterpret_cast(fileContent.data()), imageWidth, imageHeight, imageStride, static_cast(imageFormat)); + QPixmap pixmap = QPixmap::fromImage(image); + close(fileId); + return pixmap; +} + +QString ImageUtil::imagePath() +{ + return QString("%1/dde-dock/windowthumb").arg(QDir::tempPath()); } diff --git a/frame/util/imageutil.h b/frame/util/imageutil.h index 204b10153..0cc336ea2 100644 --- a/frame/util/imageutil.h +++ b/frame/util/imageutil.h @@ -36,8 +36,10 @@ public: static const QPixmap loadSvg(const QString &iconName, const QSize size, const qreal ratio = qApp->devicePixelRatio()); static QCursor* loadQCursorFromX11Cursor(const char* theme, const char* cursorName, int cursorSize); // 加载窗口的预览图 - static QImage loadWindowThumb(const WId &windowId, int width, int height); // x11下加载,用windowID - static QImage loadWindowThumb(const QString &uuid, int width, int height); // wayland下加载,用uuid + static QPixmap loadWindowThumb(const QString &winInfoId); // 加载图片,参数为windowId或者窗口的UUID + +private: + static QString imagePath(); }; #endif // IMAGEUTIL_H