KWin
Loading...
Searching...
No Matches
x11shadowreader.cpp
Go to the documentation of this file.
1/*
2 SPDX-FileCopyrightText: 2016 Martin Gräßlin <mgraesslin@kde.org>
3
4 SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
5*/
6#include "utils/xcbutils.h"
7
8#include <QApplication>
9#include <QCommandLineParser>
10#include <QDebug>
11#include <QFormLayout>
12#include <QLabel>
13#include <QVBoxLayout>
14#include <QWidget>
15#include <private/qtx11extras_p.h>
16
17static QList<uint32_t> readShadow(quint32 windowId)
18{
19 KWin::Xcb::Atom atom(QByteArrayLiteral("_KDE_NET_WM_SHADOW"), false, QX11Info::connection());
20 QList<uint32_t> ret;
21 if (windowId != XCB_WINDOW) {
22 KWin::Xcb::Property property(false, windowId, atom, XCB_ATOM_CARDINAL, 0, 12);
23 uint32_t *shadow = property.value<uint32_t *>();
24 if (shadow) {
25 ret.reserve(12);
26 for (int i = 0; i < 12; ++i) {
27 ret << shadow[i];
28 }
29 } else {
30 qDebug() << "!!!! no shadow";
31 }
32 } else {
33 qDebug() << "!!!! no window";
34 }
35 return ret;
36}
37
38static QList<QPixmap> getPixmaps(const QList<uint32_t> &data)
39{
40 QList<QPixmap> ret;
41 static const int ShadowElementsCount = 8;
42 QList<KWin::Xcb::WindowGeometry> pixmapGeometries(ShadowElementsCount);
43 QList<xcb_get_image_cookie_t> getImageCookies(ShadowElementsCount);
44 auto *c = KWin::connection();
45 for (int i = 0; i < ShadowElementsCount; ++i) {
46 pixmapGeometries[i] = KWin::Xcb::WindowGeometry(data[i]);
47 }
48 auto discardReplies = [&getImageCookies](int start) {
49 for (int i = start; i < getImageCookies.size(); ++i) {
50 xcb_discard_reply(KWin::connection(), getImageCookies.at(i).sequence);
51 }
52 };
53 for (int i = 0; i < ShadowElementsCount; ++i) {
54 auto &geo = pixmapGeometries[i];
55 if (geo.isNull()) {
56 discardReplies(0);
57 return QList<QPixmap>();
58 }
59 getImageCookies[i] = xcb_get_image_unchecked(c, XCB_IMAGE_FORMAT_Z_PIXMAP, data[i],
60 0, 0, geo->width, geo->height, ~0);
61 }
62 for (int i = 0; i < ShadowElementsCount; ++i) {
63 auto *reply = xcb_get_image_reply(c, getImageCookies.at(i), nullptr);
64 if (!reply) {
65 discardReplies(i + 1);
66 return QList<QPixmap>();
67 }
68 auto &geo = pixmapGeometries[i];
69 QImage image(xcb_get_image_data(reply), geo->width, geo->height, QImage::Format_ARGB32);
70 ret << QPixmap::fromImage(image);
71 free(reply);
72 }
73 return ret;
74}
75
76int main(int argc, char **argv)
77{
78 qputenv("QT_QPA_PLATFORM", "xcb");
79 QApplication app(argc, argv);
80 app.setProperty("x11Connection", QVariant::fromValue<void *>(QX11Info::connection()));
81
82 QCommandLineParser parser;
83 parser.addPositionalArgument(QStringLiteral("windowId"), QStringLiteral("The X11 windowId from which to read the shadow"));
84 parser.addHelpOption();
85 parser.process(app);
86
87 if (parser.positionalArguments().count() != 1) {
88 parser.showHelp(1);
89 }
90
91 bool ok = false;
92 const auto shadow = readShadow(parser.positionalArguments().constFirst().toULongLong(&ok, 16));
93 if (!ok) {
94 qDebug() << "!!! Failed to read window id";
95 return 1;
96 }
97 if (shadow.isEmpty()) {
98 qDebug() << "!!!! Read shadow failed";
99 return 1;
100 }
101 const auto pixmaps = getPixmaps(shadow);
102 if (pixmaps.isEmpty()) {
103 qDebug() << "!!!! Read pixmap failed";
104 return 1;
105 }
106
107 std::unique_ptr<QWidget> widget(new QWidget());
108 QFormLayout *layout = new QFormLayout(widget.get());
109 for (const auto &pix : pixmaps) {
110 QLabel *l = new QLabel(widget.get());
111 l->setPixmap(pix);
112 layout->addRow(QStringLiteral("%1x%2:").arg(pix.width()).arg(pix.height()), l);
113 }
114 widget->setLayout(layout);
115 widget->show();
116 return app.exec();
117}
KWIN_EXPORT xcb_connection_t * connection()
Definition xcb.h:19