From 081522f02ccbb628c75d8ae1e5c09da33d0ff5a2 Mon Sep 17 00:00:00 2001 From: listenerri Date: Mon, 30 Jul 2018 11:22:56 +0800 Subject: [PATCH] feat: add get preview image from shm Change-Id: Iac90562643c02e9916a65c0e4ab823b8d99e2cf9 --- frame/item/components/appsnapshot.cpp | 177 ++++++++++++++++------ frame/item/components/appsnapshot.h | 14 +- frame/item/components/floatingpreview.cpp | 13 +- 3 files changed, 151 insertions(+), 53 deletions(-) diff --git a/frame/item/components/appsnapshot.cpp b/frame/item/components/appsnapshot.cpp index 6b1970d52..6c3d421bd 100644 --- a/frame/item/components/appsnapshot.cpp +++ b/frame/item/components/appsnapshot.cpp @@ -26,10 +26,29 @@ #include #include #include +#include #include #include #include +#include + +struct SHMInfo +{ + long shmid; + long width; + long height; + long bytesPerLine; + long format; + + struct Rect + { + long x; + long y; + long width; + long height; + } rect; +}; AppSnapshot::AppSnapshot(const WId wid, QWidget *parent) : QWidget(parent), @@ -111,53 +130,62 @@ void AppSnapshot::fetchSnapshot() if (!m_wmHelper->hasComposite()) return; - const auto display = QX11Info::display(); + QImage qimage; + SHMInfo *info = nullptr; + uchar *image_data = nullptr; + XImage *ximage = nullptr; + unsigned char *prop_to_return_gtk = nullptr; - Window unused_window; - int unused_int; - unsigned unused_uint, w, h; - XGetGeometry(display, m_wid, &unused_window, &unused_int, &unused_int, &w, &h, &unused_uint, &unused_uint); - XImage *ximage = XGetImage(display, m_wid, 0, 0, w, h, AllPlanes, ZPixmap); - if (!ximage) - { - emit requestCheckWindow(); - return; - } + do { + // get window image from shm(only for deepin app) + info = getImageDSHM(); + if (info) { + qDebug() << "get Image from dxcbplugin SHM..."; + //qDebug() << info->shmid << info->width << info->height << info->bytesPerLine << info->format << info->rect.x << info->rect.y << info->rect.width << info->rect.height; + image_data = (uchar*)shmat(info->shmid, 0, 0); + 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); + break; + } - const QImage qimage((const uchar*)(ximage->data), ximage->width, ximage->height, ximage->bytes_per_line, QImage::Format_RGB32); - Q_ASSERT(!qimage.isNull()); + if (!image_data || qimage.isNull()) + { + // get window image from XGetImage(a little slow) + qDebug() << "get Image from dxcbplugin SHM failed!"; + qDebug() << "get Image from Xlib..."; + ximage = getImageXlib(); + if (!ximage) + { + qDebug() << "get Image from Xlib failed! giving up..."; + emit requestCheckWindow(); + return; + } + qimage = QImage((const uchar*)(ximage->data), ximage->width, ximage->height, ximage->bytes_per_line, QImage::Format_RGB32); + } - const Atom gtk_frame_extents = XInternAtom(display, "_GTK_FRAME_EXTENTS", true); - Atom actual_type_return; - int actual_format_return; - unsigned long n_items_return; - unsigned long bytes_after_return; - unsigned char *prop_to_return; + Q_ASSERT(!qimage.isNull()); - const auto r = XGetWindowProperty(display, m_wid, gtk_frame_extents, 0, 4, false, XA_CARDINAL, - &actual_type_return, &actual_format_return, &n_items_return, &bytes_after_return, &prop_to_return); - if (!r && prop_to_return && n_items_return == 4 && actual_format_return == 32) - { - const unsigned long *extents = reinterpret_cast(prop_to_return); - const int left = extents[0]; - const int right = extents[1]; - const int top = extents[2]; - const int bottom = extents[3]; - const int width = qimage.width(); - const int height = qimage.height(); - - m_snapshot = qimage.copy(left, top, width - left - right, height - top - bottom); - } else { + // remove shadow frame + m_snapshotSrcRect = rectRemovedShadow(qimage, prop_to_return_gtk); m_snapshot = qimage; - } + } while (false); - const auto size = rect().marginsRemoved(QMargins(8, 8, 8, 8)).size(); + QSizeF size(rect().marginsRemoved(QMargins(8, 8, 8, 8)).size()); const auto ratio = devicePixelRatioF(); - m_snapshot = m_snapshot.scaled(size * ratio, Qt::KeepAspectRatio, Qt::SmoothTransformation); + 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); m_snapshot.setDevicePixelRatio(ratio); - XDestroyImage(ximage); - XFree(prop_to_return); + if (image_data) shmdt(image_data); + if (ximage) XDestroyImage(ximage); + if (info) XFree(info); + if (prop_to_return_gtk) XFree(prop_to_return_gtk); update(); } @@ -181,10 +209,7 @@ void AppSnapshot::leaveEvent(QEvent *e) void AppSnapshot::paintEvent(QPaintEvent *e) { - QWidget::paintEvent(e); - QPainter painter(this); - painter.setRenderHint(QPainter::Antialiasing); if (!m_wmHelper->hasComposite()) { @@ -211,9 +236,10 @@ void AppSnapshot::paintEvent(QPaintEvent *e) const QImage &im = m_snapshot; const QRect ir = im.rect(); - const int offset_x = r.x() + r.width() / 2 - ir.width() / ratio / 2; - const int offset_y = r.y() + r.height() / 2 - ir.height() / ratio / 2; - painter.drawImage(offset_x, offset_y, im); + const qreal offset_x = r.x() + r.width() / 2.0 - ir.width() / ratio / 2 + m_snapshotSrcRect.x(); + const qreal offset_y = r.y() + r.height() / 2.0 - ir.height() / ratio / 2 + m_snapshotSrcRect.y(); + + painter.drawImage(QPointF(offset_x, offset_y), im, m_snapshotSrcRect); } void AppSnapshot::resizeEvent(QResizeEvent *e) @@ -229,3 +255,66 @@ void AppSnapshot::mousePressEvent(QMouseEvent *e) emit clicked(m_wid); } + +SHMInfo * AppSnapshot::getImageDSHM() +{ + const auto display = QX11Info::display(); + + Atom atom_prop = XInternAtom(display, "_DEEPIN_DXCB_SHM_INFO", true); + if (!atom_prop) { + return nullptr; + } + + Atom actual_type_return_deepin_shm; + int actual_format_return_deepin_shm; + unsigned long nitems_return_deepin_shm; + unsigned long bytes_after_return_deepin_shm; + unsigned char *prop_return_deepin_shm; + + XGetWindowProperty(display, m_wid, atom_prop, 0, 32 * 9, false, AnyPropertyType, + &actual_type_return_deepin_shm, &actual_format_return_deepin_shm, &nitems_return_deepin_shm, + &bytes_after_return_deepin_shm, &prop_return_deepin_shm); + + //qDebug() << actual_type_return_deepin_shm << actual_format_return_deepin_shm << nitems_return_deepin_shm << bytes_after_return_deepin_shm << prop_return_deepin_shm; + + return reinterpret_cast(prop_return_deepin_shm); +} + +XImage *AppSnapshot::getImageXlib() +{ + const auto display = QX11Info::display(); + Window unused_window; + int unused_int; + unsigned unused_uint, w, h; + XGetGeometry(display, m_wid, &unused_window, &unused_int, &unused_int, &w, &h, &unused_uint, &unused_uint); + return XGetImage(display, m_wid, 0, 0, w, h, AllPlanes, ZPixmap); +} + +QRect AppSnapshot::rectRemovedShadow(const QImage &qimage, unsigned char *prop_to_return_gtk) +{ + const auto display = QX11Info::display(); + + const Atom gtk_frame_extents = XInternAtom(display, "_GTK_FRAME_EXTENTS", true); + Atom actual_type_return_gtk; + int actual_format_return_gtk; + unsigned long n_items_return_gtk; + unsigned long bytes_after_return_gtk; + + const auto r = XGetWindowProperty(display, m_wid, gtk_frame_extents, 0, 4, false, XA_CARDINAL, + &actual_type_return_gtk, &actual_format_return_gtk, &n_items_return_gtk, &bytes_after_return_gtk, &prop_to_return_gtk); + if (!r && prop_to_return_gtk && n_items_return_gtk == 4 && actual_format_return_gtk == 32) + { + qDebug() << "remove shadow frame..."; + const unsigned long *extents = reinterpret_cast(prop_to_return_gtk); + const int left = extents[0]; + const int right = extents[1]; + const int top = extents[2]; + const int bottom = extents[3]; + const int width = qimage.width(); + const int height = qimage.height(); + + return QRect(left, top, width - left - right, height - top - bottom); + } else { + return QRect(0, 0, qimage.width(), qimage.height()); + } +} diff --git a/frame/item/components/appsnapshot.h b/frame/item/components/appsnapshot.h index 5415c1330..15c33a63e 100644 --- a/frame/item/components/appsnapshot.h +++ b/frame/item/components/appsnapshot.h @@ -37,6 +37,10 @@ DWIDGET_USE_NAMESPACE #define SNAP_WIDTH 200 #define SNAP_HEIGHT 130 +struct SHMInfo; +struct _XImage; +typedef _XImage XImage; + class AppSnapshot : public QWidget { Q_OBJECT @@ -47,6 +51,7 @@ public: WId wid() const { return m_wid; } bool attentioned() const { return m_windowInfo.attention; } const QImage snapshot() const { return m_snapshot; } + const QRectF snapshotGeometry() const { return m_snapshotSrcRect; } const QString title() const { return m_windowInfo.title; } signals: @@ -67,15 +72,20 @@ private: void paintEvent(QPaintEvent *e); void resizeEvent(QResizeEvent *e); void mousePressEvent(QMouseEvent *e); + SHMInfo *getImageDSHM(); + XImage * getImageXlib(); + QRect rectRemovedShadow(const QImage &qimage, unsigned char *prop_to_return_gtk); private: const WId m_wid; WindowInfo m_windowInfo; QImage m_snapshot; - QLabel *m_title; - DImageButton *m_closeBtn; + QRectF m_snapshotSrcRect; + QLabel *m_title; + + DImageButton *m_closeBtn; DWindowManagerHelper *m_wmHelper; }; diff --git a/frame/item/components/floatingpreview.cpp b/frame/item/components/floatingpreview.cpp index 5966c1a0a..3a9af9c05 100644 --- a/frame/item/components/floatingpreview.cpp +++ b/frame/item/components/floatingpreview.cpp @@ -77,6 +77,8 @@ void FloatingPreview::paintEvent(QPaintEvent *e) return; const QImage &snapshot = m_tracked->snapshot(); + const QRectF &snapshot_geometry = m_tracked->snapshotGeometry(); + if (snapshot.isNull()) return; @@ -86,12 +88,9 @@ void FloatingPreview::paintEvent(QPaintEvent *e) const QRect r = rect().marginsRemoved(QMargins(8, 8, 8, 8)); const auto ratio = devicePixelRatioF(); - QImage im = snapshot.scaled(r.size() * ratio, Qt::KeepAspectRatio, Qt::SmoothTransformation); - im.setDevicePixelRatio(ratio); - - const QRect ir = im.rect(); - const int offset_x = r.x() + r.width() / 2 - ir.width() / ratio / 2; - const int offset_y = r.y() + r.height() / 2 - ir.height() / ratio / 2; + const QRect ir = snapshot.rect(); + const qreal offset_x = r.x() + r.width() / 2.0 - ir.width() / ratio / 2 + snapshot_geometry.x(); + const qreal offset_y = r.y() + r.height() / 2.0 - ir.height() / ratio / 2 + snapshot_geometry.y(); const int radius = 4; // draw background @@ -100,7 +99,7 @@ void FloatingPreview::paintEvent(QPaintEvent *e) painter.drawRoundedRect(r, radius, radius); // draw preview image - painter.drawImage(offset_x, offset_y, im); + painter.drawImage(QPointF(offset_x, offset_y), snapshot, m_tracked->snapshotGeometry()); // bottom black background QRect bgr = r;