File indexing completed on 2024-05-05 16:19:53

0001 /*
0002     This file is part of the KDE libraries
0003     SPDX-FileCopyrightText: 2008 Lubos Lunak <l.lunak@kde.org>
0004     SPDX-FileCopyrightText: 2013 Martin Gräßlin <mgraesslin@kde.org>
0005 
0006     SPDX-License-Identifier: LGPL-2.1-or-later
0007 */
0008 
0009 #include "cptr_p.h"
0010 #include "kwindowsystem_xcb_debug.h"
0011 #include "kxutils_p.h"
0012 #include <QBitmap>
0013 
0014 #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
0015 #include <private/qtx11extras_p.h>
0016 #else
0017 #include <QX11Info>
0018 #endif
0019 
0020 #include <xcb/xcb.h>
0021 
0022 namespace KXUtils
0023 {
0024 template<typename T>
0025 T fromNative(xcb_pixmap_t pixmap, xcb_connection_t *c)
0026 {
0027     const xcb_get_geometry_cookie_t geoCookie = xcb_get_geometry_unchecked(c, pixmap);
0028     UniqueCPointer<xcb_get_geometry_reply_t> geo(xcb_get_geometry_reply(c, geoCookie, nullptr));
0029     if (!geo) {
0030         // getting geometry for the pixmap failed
0031         return T();
0032     }
0033 
0034     const xcb_get_image_cookie_t imageCookie = xcb_get_image_unchecked(c, XCB_IMAGE_FORMAT_Z_PIXMAP, pixmap, 0, 0, geo->width, geo->height, ~0);
0035     UniqueCPointer<xcb_get_image_reply_t> xImage(xcb_get_image_reply(c, imageCookie, nullptr));
0036     if (!xImage) {
0037         // request for image data failed
0038         return T();
0039     }
0040     QImage::Format format = QImage::Format_Invalid;
0041     switch (xImage->depth) {
0042     case 1:
0043         format = QImage::Format_MonoLSB;
0044         break;
0045     case 16:
0046         format = QImage::Format_RGB16;
0047         break;
0048     case 24:
0049         format = QImage::Format_RGB32;
0050         break;
0051     case 30: {
0052         // Qt doesn't have a matching image format. We need to convert manually
0053         uint32_t *pixels = reinterpret_cast<uint32_t *>(xcb_get_image_data(xImage.get()));
0054         for (uint i = 0; i < xImage.get()->length; ++i) {
0055             int r = (pixels[i] >> 22) & 0xff;
0056             int g = (pixels[i] >> 12) & 0xff;
0057             int b = (pixels[i] >> 2) & 0xff;
0058 
0059             pixels[i] = qRgba(r, g, b, 0xff);
0060         }
0061         // fall through, Qt format is still Format_ARGB32_Premultiplied
0062         Q_FALLTHROUGH();
0063     }
0064     case 32:
0065         format = QImage::Format_ARGB32_Premultiplied;
0066         break;
0067     default:
0068         return T(); // we don't know
0069     }
0070     QImage image(xcb_get_image_data(xImage.get()), geo->width, geo->height, xcb_get_image_data_length(xImage.get()) / geo->height, format, free, xImage.get());
0071     xImage.release();
0072     if (image.isNull()) {
0073         return T();
0074     }
0075     if (image.format() == QImage::Format_MonoLSB) {
0076         // work around an abort in QImage::color
0077         image.setColorCount(2);
0078         image.setColor(0, QColor(Qt::white).rgb());
0079         image.setColor(1, QColor(Qt::black).rgb());
0080     }
0081     return T::fromImage(image);
0082 }
0083 
0084 // Create QPixmap from X pixmap. Take care of different depths if needed.
0085 QPixmap createPixmapFromHandle(WId pixmap, WId pixmap_mask)
0086 {
0087     return createPixmapFromHandle(QX11Info::connection(), pixmap, pixmap_mask);
0088 }
0089 
0090 QPixmap createPixmapFromHandle(xcb_connection_t *c, WId pixmap, WId pixmap_mask)
0091 {
0092 #if Q_BYTE_ORDER == Q_BIG_ENDIAN
0093     qCDebug(LOG_KKEYSERVER_X11) << "Byte order not supported";
0094     return QPixmap();
0095 #endif
0096     const xcb_setup_t *setup = xcb_get_setup(c);
0097     if (setup->image_byte_order != XCB_IMAGE_ORDER_LSB_FIRST) {
0098         qCDebug(LOG_KKEYSERVER_X11) << "Byte order not supported";
0099         return QPixmap();
0100     }
0101 
0102     QPixmap pix = fromNative<QPixmap>(pixmap, c);
0103     if (pixmap_mask != XCB_PIXMAP_NONE) {
0104         QBitmap mask = fromNative<QBitmap>(pixmap_mask, c);
0105         if (mask.size() != pix.size()) {
0106             return QPixmap();
0107         }
0108         pix.setMask(mask);
0109     }
0110     return pix;
0111 }
0112 
0113 // Functions for X timestamp comparing. For Time being 32bit they're fairly simple
0114 // (the #if 0 part), but on 64bit architectures Time is 64bit unsigned long,
0115 // so there special care needs to be taken to always use only the lower 32bits.
0116 #if 0
0117 int timestampCompare(Time time1, Time time2)   // like strcmp()
0118 {
0119     if (time1 == time2) {
0120         return 0;
0121     }
0122     return (time1 - time2) < 0x7fffffffU ? 1 : -1;   // time1 > time2 -> 1, handle wrapping
0123 }
0124 
0125 Time timestampDiff(Time time1, Time time2)   // returns time2 - time1
0126 {
0127     // no need to handle wrapping?
0128     return time2 - time1;
0129 }
0130 #else
0131 int timestampCompare(unsigned long time1_, unsigned long time2_) // like strcmp()
0132 {
0133     quint32 time1 = time1_;
0134     quint32 time2 = time2_;
0135     if (time1 == time2) {
0136         return 0;
0137     }
0138     return quint32(time1 - time2) < 0x7fffffffU ? 1 : -1; // time1 > time2 -> 1, handle wrapping
0139 }
0140 
0141 int timestampDiff(unsigned long time1_, unsigned long time2_) // returns time2 - time1
0142 {
0143     // no need to handle wrapping?
0144     quint32 time1 = time1_;
0145     quint32 time2 = time2_;
0146     return quint32(time2 - time1);
0147 }
0148 #endif
0149 
0150 } // namespace