Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qcolormap_x11.cpp
Go to the documentation of this file.
1// Copyright (C) 2018 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include <QVarLengthArray>
5
6#include <private/qguiapplication_p.h>
7
8#include "qcolormap_x11_p.h"
10#include "qt_x11_p.h"
11
13
15{
16public:
18 : ref(1), mode(QXcbColormap::Direct), depth(0),
19 colormap(0), defaultColormap(true),
20 visual(0), defaultVisual(true),
21 r_max(0), g_max(0), b_max(0),
22 r_shift(0), g_shift(0), b_shift(0)
23 {}
24
26
28 int depth;
29
32
33 Visual *visual;
35
36 int r_max;
37 int g_max;
38 int b_max;
39
43
44 QList<QColor> colors;
45 QList<int> pixels;
46};
47
49{
50 while (!(v & 0x1))
51 v >>= 1;
52 return v;
53}
54
55static int cube_root(int v)
56{
57 if (v == 1)
58 return 1;
59 // brute force algorithm
60 int i = 1;
61 for (;;) {
62 const int b = i * i * i;
63 if (b <= v) {
64 ++i;
65 } else {
66 --i;
67 break;
68 }
69 }
70 return i;
71}
72
73static Visual *find_visual(Display *display,
74 int screen,
75 int visual_class,
76 int visual_id,
77 int *depth,
78 bool *defaultVisual)
79{
80 XVisualInfo *vi, rvi;
81 int count;
82
83 uint mask = VisualScreenMask;
84 rvi.screen = screen;
85
86 if (visual_class != -1) {
87 rvi.c_class = visual_class;
88 mask |= VisualClassMask;
89 }
90 if (visual_id != -1) {
91 rvi.visualid = visual_id;
92 mask |= VisualIDMask;
93 }
94
95 Visual *visual = DefaultVisual(display, screen);
96 *defaultVisual = true;
97 *depth = DefaultDepth(display, screen);
98
99 vi = XGetVisualInfo(display, mask, &rvi, &count);
100 if (vi) {
101 int best = 0;
102 for (int x = 0; x < count; ++x) {
103 if (vi[x].depth > vi[best].depth)
104 best = x;
105 }
106 if (best >= 0 && best <= count && vi[best].visualid != XVisualIDFromVisual(visual)) {
107 visual = vi[best].visual;
108 *defaultVisual = (visual == DefaultVisual(display, screen));
109 *depth = vi[best].depth;
110 }
111 }
112 if (vi)
113 XFree((char *)vi);
114 return visual;
115}
116
118{
119 Display *display = X11->display;
120
121 // query existing colormap
122 int q_colors = (((1u << d->depth) > 256u) ? 256u : (1u << d->depth));
123 XColor queried[256];
124 memset(queried, 0, sizeof(queried));
125 for (int x = 0; x < q_colors; ++x)
126 queried[x].pixel = x;
127 XQueryColors(display, d->colormap, queried, q_colors);
128
129 d->colors.resize(q_colors);
130 for (int x = 0; x < q_colors; ++x) {
131 if (queried[x].red == 0
132 && queried[x].green == 0
133 && queried[x].blue == 0
134 && queried[x].pixel != BlackPixel(display, screen)) {
135 // unallocated color cell, skip it
136 continue;
137 }
138
139 d->colors[x] = QColor::fromRgbF(queried[x].red / float(USHRT_MAX),
140 queried[x].green / float(USHRT_MAX),
141 queried[x].blue / float(USHRT_MAX));
142 }
143
144 // for missing colors, find the closest color in the existing colormap
145 Q_ASSERT(d->pixels.size());
146 for (int x = 0; x < d->pixels.size(); ++x) {
147 if (d->pixels.at(x) != -1)
148 continue;
149
150 QRgb rgb;
151 if (d->mode == QXcbColormap::Indexed) {
152 const int r = (x / (d->g_max * d->b_max)) % d->r_max;
153 const int g = (x / d->b_max) % d->g_max;
154 const int b = x % d->b_max;
155 rgb = qRgb((r * 0xff + (d->r_max - 1) / 2) / (d->r_max - 1),
156 (g * 0xff + (d->g_max - 1) / 2) / (d->g_max - 1),
157 (b * 0xff + (d->b_max - 1) / 2) / (d->b_max - 1));
158 } else {
159 rgb = qRgb(x, x, x);
160 }
161
162 // find closest color
163 int mindist = INT_MAX, best = -1;
164 for (int y = 0; y < q_colors; ++y) {
165 int r = qRed(rgb) - (queried[y].red >> 8);
166 int g = qGreen(rgb) - (queried[y].green >> 8);
167 int b = qBlue(rgb) - (queried[y].blue >> 8);
168 int dist = (r * r) + (g * g) + (b * b);
169 if (dist < mindist) {
170 mindist = dist;
171 best = y;
172 }
173 }
174
175 Q_ASSERT(best >= 0 && best < q_colors);
176 if (d->visual->c_class & 1) {
177 XColor xcolor;
178 xcolor.red = queried[best].red;
179 xcolor.green = queried[best].green;
180 xcolor.blue = queried[best].blue;
181 xcolor.pixel = queried[best].pixel;
182
183 if (XAllocColor(display, d->colormap, &xcolor)) {
184 d->pixels[x] = xcolor.pixel;
185 } else {
186 // some weird stuff is going on...
187 d->pixels[x] = (qGray(rgb) < 127
188 ? BlackPixel(display, screen)
189 : WhitePixel(display, screen));
190 }
191 } else {
192 d->pixels[x] = best;
193 }
194 }
195}
196
198{
199 d->pixels.resize(d->r_max);
200
201 for (int g = 0; g < d->g_max; ++g) {
202 const int gray = (g * 0xff + (d->r_max - 1) / 2) / (d->r_max - 1);
203 const QRgb rgb = qRgb(gray, gray, gray);
204
205 d->pixels[g] = -1;
206
207 if (d->visual->c_class & 1) {
208 XColor xcolor;
209 xcolor.red = qRed(rgb) * 0x101;
210 xcolor.green = qGreen(rgb) * 0x101;
211 xcolor.blue = qBlue(rgb) * 0x101;
212 xcolor.pixel = 0ul;
213
214 if (XAllocColor(X11->display, d->colormap, &xcolor))
215 d->pixels[g] = xcolor.pixel;
216 }
217 }
218
220}
221
223{
224 d->pixels.resize(d->r_max * d->g_max * d->b_max);
225
226 // create color cube
227 for (int x = 0, r = 0; r < d->r_max; ++r) {
228 for (int g = 0; g < d->g_max; ++g) {
229 for (int b = 0; b < d->b_max; ++b, ++x) {
230 const QRgb rgb = qRgb((r * 0xff + (d->r_max - 1) / 2) / (d->r_max - 1),
231 (g * 0xff + (d->g_max - 1) / 2) / (d->g_max - 1),
232 (b * 0xff + (d->b_max - 1) / 2) / (d->b_max - 1));
233
234 d->pixels[x] = -1;
235
236 if (d->visual->c_class & 1) {
237 XColor xcolor;
238 xcolor.red = qRed(rgb) * 0x101;
239 xcolor.green = qGreen(rgb) * 0x101;
240 xcolor.blue = qBlue(rgb) * 0x101;
241 xcolor.pixel = 0ul;
242
243 if (XAllocColor(X11->display, d->colormap, &xcolor))
244 d->pixels[x] = xcolor.pixel;
245 }
246 }
247 }
248 }
249
251}
252
253static void init_direct(QXcbColormapPrivate *d, bool ownColormap)
254{
255 if (d->visual->c_class != DirectColor || !ownColormap)
256 return;
257
258 // preallocate 768 on the stack, so that we don't have to malloc
259 // for the common case (<= 24 bpp)
260 QVarLengthArray<XColor, 768> colorTable(d->r_max + d->g_max + d->b_max);
261 int i = 0;
262
263 for (int r = 0; r < d->r_max; ++r) {
264 colorTable[i].red = r << 8 | r;
265 colorTable[i].pixel = r << d->r_shift;
266 colorTable[i].flags = DoRed;
267 ++i;
268 }
269
270 for (int g = 0; g < d->g_max; ++g) {
271 colorTable[i].green = g << 8 | g;
272 colorTable[i].pixel = g << d->g_shift;
273 colorTable[i].flags = DoGreen;
274 ++i;
275 }
276
277 for (int b = 0; b < d->b_max; ++b) {
278 colorTable[i].blue = (b << 8 | b);
279 colorTable[i].pixel = b << d->b_shift;
280 colorTable[i].flags = DoBlue;
281 ++i;
282 }
283
284 XStoreColors(X11->display, d->colormap, colorTable.data(), colorTable.count());
285}
286
287static QXcbColormap **cmaps = nullptr;
288
290{
291 Display *display = X11->display;
292 const int screens = ScreenCount(display);
293
294 cmaps = new QXcbColormap*[screens];
295
296 for (int i = 0; i < screens; ++i) {
297 cmaps[i] = new QXcbColormap;
298 QXcbColormapPrivate * const d = cmaps[i]->d;
299
300 bool use_stdcmap = false;
301 int color_count = X11->color_count;
302
303 // defaults
304 d->depth = DefaultDepth(display, i);
305 d->colormap = DefaultColormap(display, i);
306 d->defaultColormap = true;
307 d->visual = DefaultVisual(display, i);
308 d->defaultVisual = true;
309
310 Visual *argbVisual = nullptr;
311
312 if (X11->visual && i == DefaultScreen(display)) {
313 // only use the outside colormap on the default screen
314 d->visual = find_visual(display, i, X11->visual->c_class,
315 XVisualIDFromVisual(X11->visual),
316 &d->depth, &d->defaultVisual);
317 } else if ((X11->visual_class != -1 && X11->visual_class >= 0 && X11->visual_class < 6)
318 || (X11->visual_id != -1)) {
319 // look for a specific visual or type of visual
320 d->visual = find_visual(display, i, X11->visual_class, X11->visual_id,
321 &d->depth, &d->defaultVisual);
322 } else if (!X11->custom_cmap) {
323 XStandardColormap *stdcmap = nullptr;
324 int ncmaps = 0;
325
326#if QT_CONFIG(xrender)
327 if (X11->use_xrender) {
328 int nvi;
329 XVisualInfo templ;
330 templ.screen = i;
331 templ.depth = 32;
332 templ.c_class = TrueColor;
333 XVisualInfo *xvi = XGetVisualInfo(X11->display, VisualScreenMask |
334 VisualDepthMask |
335 VisualClassMask, &templ, &nvi);
336 for (int idx = 0; idx < nvi; ++idx) {
337 XRenderPictFormat *format = XRenderFindVisualFormat(X11->display,
338 xvi[idx].visual);
339 if (format->type == PictTypeDirect && format->direct.alphaMask) {
340 argbVisual = xvi[idx].visual;
341 break;
342 }
343 }
344 XFree(xvi);
345 }
346#endif
347 if (XGetRGBColormaps(display, RootWindow(display, i),
348 &stdcmap, &ncmaps, XA_RGB_DEFAULT_MAP)) {
349 if (stdcmap) {
350 for (int c = 0; c < ncmaps; ++c) {
351 if (!stdcmap[c].red_max ||
352 !stdcmap[c].green_max ||
353 !stdcmap[c].blue_max ||
354 !stdcmap[c].red_mult ||
355 !stdcmap[c].green_mult ||
356 !stdcmap[c].blue_mult)
357 continue; // invalid stdcmap
358
359 XVisualInfo proto;
360 proto.visualid = stdcmap[c].visualid;
361 proto.screen = i;
362
363 int nvisuals = 0;
364 XVisualInfo *vi = XGetVisualInfo(display, VisualIDMask | VisualScreenMask,
365 &proto, &nvisuals);
366 if (vi) {
367 if (nvisuals > 0) {
368 use_stdcmap = true;
369
370 d->mode = ((vi[0].visual->c_class < StaticColor)
371 ? Gray
372 : ((vi[0].visual->c_class < TrueColor)
373 ? Indexed
374 : Direct));
375
376 d->depth = vi[0].depth;
377 d->colormap = stdcmap[c].colormap;
378 d->defaultColormap = true;
379 d->visual = vi[0].visual;
380 d->defaultVisual = (d->visual == DefaultVisual(display, i));
381
382 d->r_max = stdcmap[c].red_max + 1;
383 d->g_max = stdcmap[c].green_max + 1;
384 d->b_max = stdcmap[c].blue_max + 1;
385
386 if (d->mode == Direct) {
387 // calculate offsets
388 d->r_shift = lowest_bit(d->visual->red_mask);
389 d->g_shift = lowest_bit(d->visual->green_mask);
390 d->b_shift = lowest_bit(d->visual->blue_mask);
391 } else {
392 d->r_shift = 0;
393 d->g_shift = 0;
394 d->b_shift = 0;
395 }
396 }
397 XFree(vi);
398 }
399 break;
400 }
401 XFree(stdcmap);
402 }
403 }
404 }
405 if (!use_stdcmap) {
406 switch (d->visual->c_class) {
407 case StaticGray:
408 d->mode = Gray;
409
410 d->r_max = d->g_max = d->b_max = d->visual->map_entries;
411 break;
412
413 case XGrayScale:
414 d->mode = Gray;
415
416 // follow precedent set in libXmu...
417 if (color_count != 0)
418 d->r_max = d->g_max = d->b_max = color_count;
419 else if (d->visual->map_entries > 65000)
420 d->r_max = d->g_max = d->b_max = 4096;
421 else if (d->visual->map_entries > 4000)
422 d->r_max = d->g_max = d->b_max = 512;
423 else if (d->visual->map_entries > 250)
424 d->r_max = d->g_max = d->b_max = 12;
425 else
426 d->r_max = d->g_max = d->b_max = 4;
427 break;
428
429 case StaticColor:
430 d->mode = Indexed;
431
432 d->r_max = right_align(d->visual->red_mask) + 1;
433 d->g_max = right_align(d->visual->green_mask) + 1;
434 d->b_max = right_align(d->visual->blue_mask) + 1;
435 break;
436
437 case PseudoColor:
438 d->mode = Indexed;
439
440 // follow precedent set in libXmu...
441 if (color_count != 0)
442 d->r_max = d->g_max = d->b_max = cube_root(color_count);
443 else if (d->visual->map_entries > 65000)
444 d->r_max = d->g_max = d->b_max = 27;
445 else if (d->visual->map_entries > 4000)
446 d->r_max = d->g_max = d->b_max = 12;
447 else if (d->visual->map_entries > 250)
448 d->r_max = d->g_max = d->b_max = cube_root(d->visual->map_entries - 125);
449 else
450 d->r_max = d->g_max = d->b_max = cube_root(d->visual->map_entries);
451 break;
452
453 case TrueColor:
454 case DirectColor:
455 d->mode = Direct;
456
457 d->r_max = right_align(d->visual->red_mask) + 1;
458 d->g_max = right_align(d->visual->green_mask) + 1;
459 d->b_max = right_align(d->visual->blue_mask) + 1;
460
461 d->r_shift = lowest_bit(d->visual->red_mask);
462 d->g_shift = lowest_bit(d->visual->green_mask);
463 d->b_shift = lowest_bit(d->visual->blue_mask);
464 break;
465 }
466 }
467
468 bool ownColormap = false;
469 if (X11->colormap && i == DefaultScreen(display)) {
470 // only use the outside colormap on the default screen
471 d->colormap = X11->colormap;
472 d->defaultColormap = (d->colormap == DefaultColormap(display, i));
473 } else if ((!use_stdcmap
474 && (((d->visual->c_class & 1) && X11->custom_cmap)
475 || d->visual != DefaultVisual(display, i)))
476 || d->visual->c_class == DirectColor) {
477 // allocate custom colormap (we always do this when using DirectColor visuals)
478 d->colormap =
479 XCreateColormap(display, RootWindow(display, i), d->visual,
480 d->visual->c_class == DirectColor ? AllocAll : AllocNone);
481 d->defaultColormap = false;
482 ownColormap = true;
483 }
484
485 switch (d->mode) {
486 case Gray:
487 init_gray(d, i);
488 break;
489 case Indexed:
490 init_indexed(d, i);
491 break;
492 case Direct:
493 init_direct(d, ownColormap);
494 break;
495 }
496
497 QX11InfoData *screen = X11->screens + i;
498 screen->depth = d->depth;
499 screen->visual = d->visual;
500 screen->defaultVisual = d->defaultVisual;
501 screen->colormap = d->colormap;
502 screen->defaultColormap = d->defaultColormap;
503 screen->cells = screen->visual->map_entries;
504
505 if (argbVisual) {
506 X11->argbVisuals[i] = argbVisual;
507 X11->argbColormaps[i] = XCreateColormap(display, RootWindow(display, i), argbVisual, AllocNone);
508 }
509
510 // ###
511 // We assume that 8bpp == pseudocolor, but this is not
512 // always the case (according to the X server), so we need
513 // to make sure that our internal data is setup in a way
514 // that is compatible with our assumptions
515 if (screen->visual->c_class == TrueColor && screen->depth == 8 && screen->cells == 8)
516 screen->cells = 256;
517 }
518}
519
521{
522 Display *display = X11->display;
523 const int screens = ScreenCount(display);
524
525 for (int i = 0; i < screens; ++i)
526 delete cmaps[i];
527
528 delete [] cmaps;
529 cmaps = 0;
530}
531
532
534{
535 if (screen == -1)
537 return *cmaps[screen];
538}
539
543QXcbColormap::QXcbColormap()
545{}
546
548 :d (colormap.d)
549{ d->ref.ref(); }
550
552{
553 if (!d->ref.deref()) {
554 if (!d->defaultColormap)
555 XFreeColormap(X11->display, d->colormap);
556 delete d;
557 }
558}
559
562
564{ return d->depth; }
565
567{
568 return (d->mode == Gray
569 ? d->r_max
570 : (d->mode == Indexed
571 ? d->r_max * d->g_max * d->b_max
572 : -1));
573}
574
576{
577 const QRgba64 rgba64 = color.rgba64();
578 // XXX We emulate the raster engine here by getting the
579 // 8-bit values, but we could instead use the 16-bit
580 // values for slightly better color accuracy
581 const uint r = (rgba64.red8() * d->r_max) >> 8;
582 const uint g = (rgba64.green8() * d->g_max) >> 8;
583 const uint b = (rgba64.blue8() * d->b_max) >> 8;
584 if (d->mode != Direct) {
585 if (d->mode == Gray)
586 return d->pixels.at((r * 30 + g * 59 + b * 11) / 100);
587 return d->pixels.at(r * d->g_max * d->b_max + g * d->b_max + b);
588 }
589 return (r << d->r_shift) + (g << d->g_shift) + (b << d->b_shift);
590}
591
593{
594 if (d->mode != Direct) {
595 Q_ASSERT(pixel <= (uint)d->colors.size());
596 return d->colors.at(pixel);
597 }
598
599 const int r = (((pixel & d->visual->red_mask) >> d->r_shift) << 8) / d->r_max;
600 const int g = (((pixel & d->visual->green_mask) >> d->g_shift) << 8) / d->g_max;
601 const int b = (((pixel & d->visual->blue_mask) >> d->b_shift) << 8) / d->b_max;
602 return QColor(r, g, b);
603}
604
605const QList<QColor> QXcbColormap::colormap() const
606{ return d->colors; }
607
609{
611 return *this;
612}
613
\inmodule QtCore
Definition qatomic.h:112
bool ref() noexcept
bool deref() noexcept
The QColor class provides colors based on RGB, HSV or CMYK values.
Definition qcolor.h:31
static QColor fromRgbF(float r, float g, float b, float a=1.0)
Static convenience function that returns a QColor constructed from the RGB color values,...
Definition qcolor.cpp:2427
qsizetype size() const noexcept
Definition qlist.h:397
const_reference at(qsizetype i) const noexcept
Definition qlist.h:446
constexpr quint8 blue8() const
Definition qrgba64.h:81
constexpr quint8 red8() const
Definition qrgba64.h:79
constexpr quint8 green8() const
Definition qrgba64.h:80
int depth
the color depth of the screen
Definition qscreen.h:40
QList< QColor > colors
QXcbColormap::Mode mode
const QList< QColor > colormap() const
int depth() const
Mode mode() const
static QXcbColormap instance(int screen=-1)
static void initialize()
const QColor colorAt(uint pixel) const
static void cleanup()
int size() const
QXcbColormap & operator=(const QXcbColormap &colormap)
uint pixel(const QColor &color) const
QXcbColormap(const QXcbColormap &colormap)
static int appScreen()
struct wl_display * display
Definition linuxdmabuf.h:41
Combined button and popup list for selecting options.
QT_WARNING_POP void qAtomicAssign(T *&d, T *x)
This is a helper for the assignment operators of implicitly shared classes.
Definition qatomic.h:180
#define rgb(r, g, b)
Definition qcolor.cpp:124
static void query_colormap(QXcbColormapPrivate *d, int screen)
static Visual * find_visual(Display *display, int screen, int visual_class, int visual_id, int *depth, bool *defaultVisual)
static void init_direct(QXcbColormapPrivate *d, bool ownColormap)
static void init_indexed(QXcbColormapPrivate *d, int screen)
static int cube_root(int v)
static uint right_align(uint v)
static QXcbColormap ** cmaps
static void init_gray(QXcbColormapPrivate *d, int screen)
@ XGrayScale
GLboolean GLboolean GLboolean b
GLsizei const GLfloat * v
[13]
GLint GLint GLint GLint GLint x
[0]
GLint GLenum GLsizei GLsizei GLsizei depth
GLenum mode
GLboolean r
[2]
GLenum GLenum GLsizei count
GLuint color
[2]
GLboolean GLboolean g
GLint ref
GLint GLint GLint GLint GLint GLint GLint GLbitfield mask
GLint GLsizei GLsizei GLenum format
GLint y
GLbyte GLbyte blue
Definition qopenglext.h:385
const GLubyte * c
GLbyte green
Definition qopenglext.h:385
#define X11
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
QT_BEGIN_NAMESPACE typedef unsigned int QRgb
Definition qrgb.h:13
constexpr QRgb qRgb(int r, int g, int b)
Definition qrgb.h:30
constexpr int qRed(QRgb rgb)
Definition qrgb.h:18
constexpr int qGreen(QRgb rgb)
Definition qrgb.h:21
constexpr int qGray(int r, int g, int b)
Definition qrgb.h:36
constexpr int qBlue(QRgb rgb)
Definition qrgb.h:24
constexpr int lowest_bit(T v) noexcept
Definition qt_x11_p.h:157
QScreen * screen
[1]
Definition main.cpp:29
struct _XDisplay Display
unsigned int uint
Definition qtypes.h:34
XID Colormap
std::uniform_real_distribution dist(1, 2.5)
[2]
QGraphicsSvgItem * red