File indexing completed on 2024-04-21 03:59:22

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