fix: 修复wayland下窗口预览为空的问题

将获取窗口预览图的接口修改为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
This commit is contained in:
donghualin 2022-10-11 08:29:02 +00:00
parent ebccd73378
commit cb96a7bab8
7 changed files with 87 additions and 95 deletions

View File

@ -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);

View File

@ -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;
};

View File

@ -38,6 +38,7 @@
#include <QVBoxLayout>
#include <QSizeF>
#include <QTimer>
#include <QPainterPath>
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)

View File

@ -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;

View File

@ -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;

View File

@ -32,9 +32,15 @@
#include <QDBusInterface>
#include <QDBusReply>
#include <QFile>
#include <QDBusUnixFileDescriptor>
#include <QDir>
#include <X11/Xcursor/Xcursor.h>
#include <fcntl.h>
#include <unistd.h>
#include <iosfwd>
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<QVariant> args;
args << QVariant::fromValue(windowId);
args << QVariant::fromValue(quint32(width));
args << QVariant::fromValue(quint32(height));
QDBusReply<QString> 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<QVariant> 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<QString> 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<QVariantMap> 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<uchar *>(fileContent.data()), imageWidth, imageHeight, imageStride, static_cast<QImage::Format>(imageFormat));
QPixmap pixmap = QPixmap::fromImage(image);
close(fileId);
return pixmap;
}
QString ImageUtil::imagePath()
{
return QString("%1/dde-dock/windowthumb").arg(QDir::tempPath());
}

View File

@ -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