mirror of
https://github.com/linuxdeepin/dde-dock.git
synced 2025-06-04 17:33:05 +00:00
feat: add get preview image from shm
Change-Id: Iac90562643c02e9916a65c0e4ab823b8d99e2cf9
This commit is contained in:
parent
e57674b206
commit
081522f02c
Notes:
gerrit
2018-08-02 17:28:11 +08:00
Verified+1: <jenkins@deepin.com> Code-Review+2: listenerri <listenerri@gmail.com> Submitted-by: listenerri <listenerri@gmail.com> Submitted-at: Thu, 02 Aug 2018 17:28:11 +0800 Reviewed-on: https://cr.deepin.io/37187 Project: dde/dde-dock Branch: refs/heads/master
@ -26,10 +26,29 @@
|
|||||||
#include <X11/X.h>
|
#include <X11/X.h>
|
||||||
#include <X11/Xutil.h>
|
#include <X11/Xutil.h>
|
||||||
#include <X11/Xatom.h>
|
#include <X11/Xatom.h>
|
||||||
|
#include <sys/shm.h>
|
||||||
|
|
||||||
#include <QX11Info>
|
#include <QX11Info>
|
||||||
#include <QPainter>
|
#include <QPainter>
|
||||||
#include <QVBoxLayout>
|
#include <QVBoxLayout>
|
||||||
|
#include <QSizeF>
|
||||||
|
|
||||||
|
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)
|
AppSnapshot::AppSnapshot(const WId wid, QWidget *parent)
|
||||||
: QWidget(parent),
|
: QWidget(parent),
|
||||||
@ -111,53 +130,62 @@ void AppSnapshot::fetchSnapshot()
|
|||||||
if (!m_wmHelper->hasComposite())
|
if (!m_wmHelper->hasComposite())
|
||||||
return;
|
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;
|
do {
|
||||||
int unused_int;
|
// get window image from shm(only for deepin app)
|
||||||
unsigned unused_uint, w, h;
|
info = getImageDSHM();
|
||||||
XGetGeometry(display, m_wid, &unused_window, &unused_int, &unused_int, &w, &h, &unused_uint, &unused_uint);
|
if (info) {
|
||||||
XImage *ximage = XGetImage(display, m_wid, 0, 0, w, h, AllPlanes, ZPixmap);
|
qDebug() << "get Image from dxcbplugin SHM...";
|
||||||
if (!ximage)
|
//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);
|
||||||
emit requestCheckWindow();
|
m_snapshot = QImage(image_data, info->width, info->height, info->bytesPerLine, (QImage::Format)info->format);
|
||||||
return;
|
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);
|
if (!image_data || qimage.isNull())
|
||||||
Q_ASSERT(!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);
|
Q_ASSERT(!qimage.isNull());
|
||||||
Atom actual_type_return;
|
|
||||||
int actual_format_return;
|
|
||||||
unsigned long n_items_return;
|
|
||||||
unsigned long bytes_after_return;
|
|
||||||
unsigned char *prop_to_return;
|
|
||||||
|
|
||||||
const auto r = XGetWindowProperty(display, m_wid, gtk_frame_extents, 0, 4, false, XA_CARDINAL,
|
// remove shadow frame
|
||||||
&actual_type_return, &actual_format_return, &n_items_return, &bytes_after_return, &prop_to_return);
|
m_snapshotSrcRect = rectRemovedShadow(qimage, prop_to_return_gtk);
|
||||||
if (!r && prop_to_return && n_items_return == 4 && actual_format_return == 32)
|
|
||||||
{
|
|
||||||
const unsigned long *extents = reinterpret_cast<const unsigned long *>(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 {
|
|
||||||
m_snapshot = qimage;
|
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();
|
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);
|
m_snapshot.setDevicePixelRatio(ratio);
|
||||||
|
|
||||||
XDestroyImage(ximage);
|
if (image_data) shmdt(image_data);
|
||||||
XFree(prop_to_return);
|
if (ximage) XDestroyImage(ximage);
|
||||||
|
if (info) XFree(info);
|
||||||
|
if (prop_to_return_gtk) XFree(prop_to_return_gtk);
|
||||||
|
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
@ -181,10 +209,7 @@ void AppSnapshot::leaveEvent(QEvent *e)
|
|||||||
|
|
||||||
void AppSnapshot::paintEvent(QPaintEvent *e)
|
void AppSnapshot::paintEvent(QPaintEvent *e)
|
||||||
{
|
{
|
||||||
QWidget::paintEvent(e);
|
|
||||||
|
|
||||||
QPainter painter(this);
|
QPainter painter(this);
|
||||||
painter.setRenderHint(QPainter::Antialiasing);
|
|
||||||
|
|
||||||
if (!m_wmHelper->hasComposite())
|
if (!m_wmHelper->hasComposite())
|
||||||
{
|
{
|
||||||
@ -211,9 +236,10 @@ void AppSnapshot::paintEvent(QPaintEvent *e)
|
|||||||
const QImage &im = m_snapshot;
|
const QImage &im = m_snapshot;
|
||||||
|
|
||||||
const QRect ir = im.rect();
|
const QRect ir = im.rect();
|
||||||
const int offset_x = r.x() + r.width() / 2 - ir.width() / ratio / 2;
|
const qreal offset_x = r.x() + r.width() / 2.0 - ir.width() / ratio / 2 + m_snapshotSrcRect.x();
|
||||||
const int offset_y = r.y() + r.height() / 2 - ir.height() / ratio / 2;
|
const qreal offset_y = r.y() + r.height() / 2.0 - ir.height() / ratio / 2 + m_snapshotSrcRect.y();
|
||||||
painter.drawImage(offset_x, offset_y, im);
|
|
||||||
|
painter.drawImage(QPointF(offset_x, offset_y), im, m_snapshotSrcRect);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AppSnapshot::resizeEvent(QResizeEvent *e)
|
void AppSnapshot::resizeEvent(QResizeEvent *e)
|
||||||
@ -229,3 +255,66 @@ void AppSnapshot::mousePressEvent(QMouseEvent *e)
|
|||||||
|
|
||||||
emit clicked(m_wid);
|
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<SHMInfo *>(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<const unsigned long *>(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());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -37,6 +37,10 @@ DWIDGET_USE_NAMESPACE
|
|||||||
#define SNAP_WIDTH 200
|
#define SNAP_WIDTH 200
|
||||||
#define SNAP_HEIGHT 130
|
#define SNAP_HEIGHT 130
|
||||||
|
|
||||||
|
struct SHMInfo;
|
||||||
|
struct _XImage;
|
||||||
|
typedef _XImage XImage;
|
||||||
|
|
||||||
class AppSnapshot : public QWidget
|
class AppSnapshot : public QWidget
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
@ -47,6 +51,7 @@ public:
|
|||||||
WId wid() const { return m_wid; }
|
WId wid() const { return m_wid; }
|
||||||
bool attentioned() const { return m_windowInfo.attention; }
|
bool attentioned() const { return m_windowInfo.attention; }
|
||||||
const QImage snapshot() const { return m_snapshot; }
|
const QImage snapshot() const { return m_snapshot; }
|
||||||
|
const QRectF snapshotGeometry() const { return m_snapshotSrcRect; }
|
||||||
const QString title() const { return m_windowInfo.title; }
|
const QString title() const { return m_windowInfo.title; }
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
@ -67,15 +72,20 @@ private:
|
|||||||
void paintEvent(QPaintEvent *e);
|
void paintEvent(QPaintEvent *e);
|
||||||
void resizeEvent(QResizeEvent *e);
|
void resizeEvent(QResizeEvent *e);
|
||||||
void mousePressEvent(QMouseEvent *e);
|
void mousePressEvent(QMouseEvent *e);
|
||||||
|
SHMInfo *getImageDSHM();
|
||||||
|
XImage * getImageXlib();
|
||||||
|
QRect rectRemovedShadow(const QImage &qimage, unsigned char *prop_to_return_gtk);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const WId m_wid;
|
const WId m_wid;
|
||||||
|
|
||||||
WindowInfo m_windowInfo;
|
WindowInfo m_windowInfo;
|
||||||
QImage m_snapshot;
|
QImage m_snapshot;
|
||||||
QLabel *m_title;
|
QRectF m_snapshotSrcRect;
|
||||||
DImageButton *m_closeBtn;
|
|
||||||
|
|
||||||
|
QLabel *m_title;
|
||||||
|
|
||||||
|
DImageButton *m_closeBtn;
|
||||||
DWindowManagerHelper *m_wmHelper;
|
DWindowManagerHelper *m_wmHelper;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -77,6 +77,8 @@ void FloatingPreview::paintEvent(QPaintEvent *e)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
const QImage &snapshot = m_tracked->snapshot();
|
const QImage &snapshot = m_tracked->snapshot();
|
||||||
|
const QRectF &snapshot_geometry = m_tracked->snapshotGeometry();
|
||||||
|
|
||||||
if (snapshot.isNull())
|
if (snapshot.isNull())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -86,12 +88,9 @@ void FloatingPreview::paintEvent(QPaintEvent *e)
|
|||||||
const QRect r = rect().marginsRemoved(QMargins(8, 8, 8, 8));
|
const QRect r = rect().marginsRemoved(QMargins(8, 8, 8, 8));
|
||||||
const auto ratio = devicePixelRatioF();
|
const auto ratio = devicePixelRatioF();
|
||||||
|
|
||||||
QImage im = snapshot.scaled(r.size() * ratio, Qt::KeepAspectRatio, Qt::SmoothTransformation);
|
const QRect ir = snapshot.rect();
|
||||||
im.setDevicePixelRatio(ratio);
|
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 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 int radius = 4;
|
const int radius = 4;
|
||||||
|
|
||||||
// draw background
|
// draw background
|
||||||
@ -100,7 +99,7 @@ void FloatingPreview::paintEvent(QPaintEvent *e)
|
|||||||
painter.drawRoundedRect(r, radius, radius);
|
painter.drawRoundedRect(r, radius, radius);
|
||||||
|
|
||||||
// draw preview image
|
// draw preview image
|
||||||
painter.drawImage(offset_x, offset_y, im);
|
painter.drawImage(QPointF(offset_x, offset_y), snapshot, m_tracked->snapshotGeometry());
|
||||||
|
|
||||||
// bottom black background
|
// bottom black background
|
||||||
QRect bgr = r;
|
QRect bgr = r;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user