File indexing completed on 2024-11-10 08:00:57

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 #include <private/qtx11extras_p.h>
0016 
0017 static QList<uint32_t> readShadow(quint32 windowId)
0018 {
0019     KWin::Xcb::Atom atom(QByteArrayLiteral("_KDE_NET_WM_SHADOW"), false, QX11Info::connection());
0020     QList<uint32_t> ret;
0021     if (windowId != XCB_WINDOW) {
0022         KWin::Xcb::Property property(false, windowId, atom, XCB_ATOM_CARDINAL, 0, 12);
0023         uint32_t *shadow = property.value<uint32_t *>();
0024         if (shadow) {
0025             ret.reserve(12);
0026             for (int i = 0; i < 12; ++i) {
0027                 ret << shadow[i];
0028             }
0029         } else {
0030             qDebug() << "!!!! no shadow";
0031         }
0032     } else {
0033         qDebug() << "!!!! no window";
0034     }
0035     return ret;
0036 }
0037 
0038 static QList<QPixmap> getPixmaps(const QList<uint32_t> &data)
0039 {
0040     QList<QPixmap> ret;
0041     static const int ShadowElementsCount = 8;
0042     QList<KWin::Xcb::WindowGeometry> pixmapGeometries(ShadowElementsCount);
0043     QList<xcb_get_image_cookie_t> getImageCookies(ShadowElementsCount);
0044     auto *c = KWin::connection();
0045     for (int i = 0; i < ShadowElementsCount; ++i) {
0046         pixmapGeometries[i] = KWin::Xcb::WindowGeometry(data[i]);
0047     }
0048     auto discardReplies = [&getImageCookies](int start) {
0049         for (int i = start; i < getImageCookies.size(); ++i) {
0050             xcb_discard_reply(KWin::connection(), getImageCookies.at(i).sequence);
0051         }
0052     };
0053     for (int i = 0; i < ShadowElementsCount; ++i) {
0054         auto &geo = pixmapGeometries[i];
0055         if (geo.isNull()) {
0056             discardReplies(0);
0057             return QList<QPixmap>();
0058         }
0059         getImageCookies[i] = xcb_get_image_unchecked(c, XCB_IMAGE_FORMAT_Z_PIXMAP, data[i],
0060                                                      0, 0, geo->width, geo->height, ~0);
0061     }
0062     for (int i = 0; i < ShadowElementsCount; ++i) {
0063         auto *reply = xcb_get_image_reply(c, getImageCookies.at(i), nullptr);
0064         if (!reply) {
0065             discardReplies(i + 1);
0066             return QList<QPixmap>();
0067         }
0068         auto &geo = pixmapGeometries[i];
0069         QImage image(xcb_get_image_data(reply), geo->width, geo->height, QImage::Format_ARGB32);
0070         ret << QPixmap::fromImage(image);
0071         free(reply);
0072     }
0073     return ret;
0074 }
0075 
0076 int main(int argc, char **argv)
0077 {
0078     qputenv("QT_QPA_PLATFORM", "xcb");
0079     QApplication app(argc, argv);
0080     app.setProperty("x11Connection", QVariant::fromValue<void *>(QX11Info::connection()));
0081 
0082     QCommandLineParser parser;
0083     parser.addPositionalArgument(QStringLiteral("windowId"), QStringLiteral("The X11 windowId from which to read the shadow"));
0084     parser.addHelpOption();
0085     parser.process(app);
0086 
0087     if (parser.positionalArguments().count() != 1) {
0088         parser.showHelp(1);
0089     }
0090 
0091     bool ok = false;
0092     const auto shadow = readShadow(parser.positionalArguments().constFirst().toULongLong(&ok, 16));
0093     if (!ok) {
0094         qDebug() << "!!! Failed to read window id";
0095         return 1;
0096     }
0097     if (shadow.isEmpty()) {
0098         qDebug() << "!!!! Read shadow failed";
0099         return 1;
0100     }
0101     const auto pixmaps = getPixmaps(shadow);
0102     if (pixmaps.isEmpty()) {
0103         qDebug() << "!!!! Read pixmap failed";
0104         return 1;
0105     }
0106 
0107     std::unique_ptr<QWidget> widget(new QWidget());
0108     QFormLayout *layout = new QFormLayout(widget.get());
0109     for (const auto &pix : pixmaps) {
0110         QLabel *l = new QLabel(widget.get());
0111         l->setPixmap(pix);
0112         layout->addRow(QStringLiteral("%1x%2:").arg(pix.width()).arg(pix.height()), l);
0113     }
0114     widget->setLayout(layout);
0115     widget->show();
0116     return app.exec();
0117 }