1/*
2 This file is part of the KDE libraries
3 SPDX-FileCopyrightText: 2008 Lubos Lunak <l.lunak@kde.org>
4 SPDX-FileCopyrightText: 2013 Martin Gräßlin <mgraesslin@kde.org>
5
6 SPDX-License-Identifier: LGPL-2.1-or-later
7*/
8
9#include "cptr_p.h"
10#include "kxutils_p.h"
11#include <QBitmap>
12#include <QDebug>
13
14#include <private/qtx11extras_p.h>
15
16#include <xcb/xcb.h>
17
18namespace KXUtils
19{
20template<typename T>
21T fromNative(xcb_pixmap_t pixmap, xcb_connection_t *c)
22{
23 const xcb_get_geometry_cookie_t geoCookie = xcb_get_geometry_unchecked(c, drawable: pixmap);
24 UniqueCPointer<xcb_get_geometry_reply_t> geo(xcb_get_geometry_reply(c, cookie: geoCookie, e: nullptr));
25 if (!geo) {
26 // getting geometry for the pixmap failed
27 return T();
28 }
29
30 const xcb_get_image_cookie_t imageCookie = xcb_get_image_unchecked(c, format: XCB_IMAGE_FORMAT_Z_PIXMAP, drawable: pixmap, x: 0, y: 0, width: geo->width, height: geo->height, plane_mask: ~0);
31 UniqueCPointer<xcb_get_image_reply_t> xImage(xcb_get_image_reply(c, cookie: imageCookie, e: nullptr));
32 if (!xImage) {
33 // request for image data failed
34 return T();
35 }
36 QImage::Format format = QImage::Format_Invalid;
37 switch (xImage->depth) {
38 case 1:
39 format = QImage::Format_MonoLSB;
40 break;
41 case 16:
42 format = QImage::Format_RGB16;
43 break;
44 case 24:
45 format = QImage::Format_RGB32;
46 break;
47 case 30: {
48 // Qt doesn't have a matching image format. We need to convert manually
49 uint32_t *pixels = reinterpret_cast<uint32_t *>(xcb_get_image_data(R: xImage.get()));
50 for (uint i = 0; i < xImage.get()->length; ++i) {
51 int r = (pixels[i] >> 22) & 0xff;
52 int g = (pixels[i] >> 12) & 0xff;
53 int b = (pixels[i] >> 2) & 0xff;
54
55 pixels[i] = qRgba(r, g, b, a: 0xff);
56 }
57 // fall through, Qt format is still Format_ARGB32_Premultiplied
58 Q_FALLTHROUGH();
59 }
60 case 32:
61 format = QImage::Format_ARGB32_Premultiplied;
62 break;
63 default:
64 return T(); // we don't know
65 }
66 QImage image(xcb_get_image_data(R: xImage.get()), geo->width, geo->height, xcb_get_image_data_length(R: xImage.get()) / geo->height, format, free, xImage.get());
67 xImage.release();
68 if (image.isNull()) {
69 return T();
70 }
71 if (image.format() == QImage::Format_MonoLSB) {
72 // work around an abort in QImage::color
73 image.setColorCount(2);
74 image.setColor(i: 0, c: QColor(Qt::white).rgb());
75 image.setColor(i: 1, c: QColor(Qt::black).rgb());
76 }
77 return T::fromImage(image);
78}
79
80// Create QPixmap from X pixmap. Take care of different depths if needed.
81QPixmap createPixmapFromHandle(WId pixmap, WId pixmap_mask)
82{
83 return createPixmapFromHandle(c: QX11Info::connection(), pixmap, mask: pixmap_mask);
84}
85
86QPixmap createPixmapFromHandle(xcb_connection_t *c, WId pixmap, WId pixmap_mask)
87{
88#if Q_BYTE_ORDER == Q_BIG_ENDIAN
89 qDebug() << "Byte order not supported";
90 return QPixmap();
91#endif
92 const xcb_setup_t *setup = xcb_get_setup(c);
93 if (setup->image_byte_order != XCB_IMAGE_ORDER_LSB_FIRST) {
94 qDebug() << "Byte order not supported";
95 return QPixmap();
96 }
97
98 QPixmap pix = fromNative<QPixmap>(pixmap, c);
99 if (pixmap_mask != XCB_PIXMAP_NONE) {
100 QBitmap mask = fromNative<QBitmap>(pixmap: pixmap_mask, c);
101 if (mask.size() != pix.size()) {
102 return QPixmap();
103 }
104 pix.setMask(mask);
105 }
106 return pix;
107}
108
109// Functions for X timestamp comparing. For Time being 32bit they're fairly simple
110// (the #if 0 part), but on 64bit architectures Time is 64bit unsigned long,
111// so there special care needs to be taken to always use only the lower 32bits.
112#if 0
113int timestampCompare(Time time1, Time time2) // like strcmp()
114{
115 if (time1 == time2) {
116 return 0;
117 }
118 return (time1 - time2) < 0x7fffffffU ? 1 : -1; // time1 > time2 -> 1, handle wrapping
119}
120
121Time timestampDiff(Time time1, Time time2) // returns time2 - time1
122{
123 // no need to handle wrapping?
124 return time2 - time1;
125}
126#else
127int timestampCompare(unsigned long time1_, unsigned long time2_) // like strcmp()
128{
129 quint32 time1 = time1_;
130 quint32 time2 = time2_;
131 if (time1 == time2) {
132 return 0;
133 }
134 return quint32(time1 - time2) < 0x7fffffffU ? 1 : -1; // time1 > time2 -> 1, handle wrapping
135}
136
137int timestampDiff(unsigned long time1_, unsigned long time2_) // returns time2 - time1
138{
139 // no need to handle wrapping?
140 quint32 time1 = time1_;
141 quint32 time2 = time2_;
142 return quint32(time2 - time1);
143}
144#endif
145
146} // namespace
147

source code of kwindowsystem/src/platforms/xcb/kxutils.cpp