File indexing completed on 2024-04-28 16:49:19

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 }