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