File indexing completed on 2024-10-13 13:14:58
0001 /* 0002 SPDX-FileCopyrightText: 2016 Martin Gräßlin <mgraesslin@kde.org> 0003 0004 SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL 0005 */ 0006 #include "utils/xcbutils.h" 0007 0008 #include <QApplication> 0009 #include <QCommandLineParser> 0010 #include <QDebug> 0011 #include <QFormLayout> 0012 #include <QLabel> 0013 #include <QVBoxLayout> 0014 #include <QWidget> 0015 #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) 0016 #include <private/qtx11extras_p.h> 0017 #else 0018 #include <QX11Info> 0019 #endif 0020 0021 static QVector<uint32_t> readShadow(quint32 windowId) 0022 { 0023 KWin::Xcb::Atom atom(QByteArrayLiteral("_KDE_NET_WM_SHADOW"), false, QX11Info::connection()); 0024 QVector<uint32_t> ret; 0025 if (windowId != XCB_WINDOW) { 0026 KWin::Xcb::Property property(false, windowId, atom, XCB_ATOM_CARDINAL, 0, 12); 0027 uint32_t *shadow = property.value<uint32_t *>(); 0028 if (shadow) { 0029 ret.reserve(12); 0030 for (int i = 0; i < 12; ++i) { 0031 ret << shadow[i]; 0032 } 0033 } else { 0034 qDebug() << "!!!! no shadow"; 0035 } 0036 } else { 0037 qDebug() << "!!!! no window"; 0038 } 0039 return ret; 0040 } 0041 0042 static QVector<QPixmap> getPixmaps(const QVector<uint32_t> &data) 0043 { 0044 QVector<QPixmap> ret; 0045 static const int ShadowElementsCount = 8; 0046 QVector<KWin::Xcb::WindowGeometry> pixmapGeometries(ShadowElementsCount); 0047 QVector<xcb_get_image_cookie_t> getImageCookies(ShadowElementsCount); 0048 auto *c = KWin::connection(); 0049 for (int i = 0; i < ShadowElementsCount; ++i) { 0050 pixmapGeometries[i] = KWin::Xcb::WindowGeometry(data[i]); 0051 } 0052 auto discardReplies = [&getImageCookies](int start) { 0053 for (int i = start; i < getImageCookies.size(); ++i) { 0054 xcb_discard_reply(KWin::connection(), getImageCookies.at(i).sequence); 0055 } 0056 }; 0057 for (int i = 0; i < ShadowElementsCount; ++i) { 0058 auto &geo = pixmapGeometries[i]; 0059 if (geo.isNull()) { 0060 discardReplies(0); 0061 return QVector<QPixmap>(); 0062 } 0063 getImageCookies[i] = xcb_get_image_unchecked(c, XCB_IMAGE_FORMAT_Z_PIXMAP, data[i], 0064 0, 0, geo->width, geo->height, ~0); 0065 } 0066 for (int i = 0; i < ShadowElementsCount; ++i) { 0067 auto *reply = xcb_get_image_reply(c, getImageCookies.at(i), nullptr); 0068 if (!reply) { 0069 discardReplies(i + 1); 0070 return QVector<QPixmap>(); 0071 } 0072 auto &geo = pixmapGeometries[i]; 0073 QImage image(xcb_get_image_data(reply), geo->width, geo->height, QImage::Format_ARGB32); 0074 ret << QPixmap::fromImage(image); 0075 free(reply); 0076 } 0077 return ret; 0078 } 0079 0080 int main(int argc, char **argv) 0081 { 0082 qputenv("QT_QPA_PLATFORM", "xcb"); 0083 QApplication app(argc, argv); 0084 app.setProperty("x11Connection", QVariant::fromValue<void *>(QX11Info::connection())); 0085 0086 QCommandLineParser parser; 0087 parser.addPositionalArgument(QStringLiteral("windowId"), QStringLiteral("The X11 windowId from which to read the shadow")); 0088 parser.addHelpOption(); 0089 parser.process(app); 0090 0091 if (parser.positionalArguments().count() != 1) { 0092 parser.showHelp(1); 0093 } 0094 0095 bool ok = false; 0096 const auto shadow = readShadow(parser.positionalArguments().constFirst().toULongLong(&ok, 16)); 0097 if (!ok) { 0098 qDebug() << "!!! Failed to read window id"; 0099 return 1; 0100 } 0101 if (shadow.isEmpty()) { 0102 qDebug() << "!!!! Read shadow failed"; 0103 return 1; 0104 } 0105 const auto pixmaps = getPixmaps(shadow); 0106 if (pixmaps.isEmpty()) { 0107 qDebug() << "!!!! Read pixmap failed"; 0108 return 1; 0109 } 0110 0111 std::unique_ptr<QWidget> widget(new QWidget()); 0112 QFormLayout *layout = new QFormLayout(widget.get()); 0113 for (const auto &pix : pixmaps) { 0114 QLabel *l = new QLabel(widget.get()); 0115 l->setPixmap(pix); 0116 layout->addRow(QStringLiteral("%1x%2:").arg(pix.width()).arg(pix.height()), l); 0117 } 0118 widget->setLayout(layout); 0119 widget->show(); 0120 return app.exec(); 0121 }