1 // -*- mode: C++; indent-tabs-mode: nil; -*-
4 # include "../config.h"
5 #endif // HAVE_CONFIG_H
10 #endif // HAVE_STDIO_H
14 #endif // HAVE_CTYPE_H
21 #include "blackbox.hh"
22 #include "basedisplay.hh"
27 static unsigned long bsqrt(unsigned long x) {
31 unsigned long r = x >> 1;
41 BImageControl *ctrl = 0;
43 BImageControl::BImageControl(BaseDisplay *dpy, const ScreenInfo *scrn,
44 bool _dither, int _cpc,
45 unsigned long cache_timeout,
47 if (! ctrl) ctrl = this;
52 setColorsPerChannel(_cpc);
56 timer = new BTimer(basedisplay, this);
57 timer->setTimeout(cache_timeout);
63 colors = (XColor *) 0;
66 grad_xbuffer = grad_ybuffer = (unsigned int *) 0;
67 grad_buffer_width = grad_buffer_height = 0;
69 sqrt_table = (unsigned long *) 0;
71 screen_depth = screeninfo->getDepth();
72 window = screeninfo->getRootWindow();
73 screen_number = screeninfo->getScreenNumber();
74 colormap = screeninfo->getColormap();
77 XPixmapFormatValues *pmv = XListPixmapFormats(basedisplay->getXDisplay(),
81 for (int i = 0; i < count; i++)
82 if (pmv[i].depth == screen_depth) {
83 bits_per_pixel = pmv[i].bits_per_pixel;
90 if (bits_per_pixel == 0) bits_per_pixel = screen_depth;
91 if (bits_per_pixel >= 24) setDither(False);
93 red_offset = green_offset = blue_offset = 0;
95 switch (getVisual()->c_class) {
99 // compute color tables
100 unsigned long red_mask = getVisual()->red_mask,
101 green_mask = getVisual()->green_mask,
102 blue_mask = getVisual()->blue_mask;
104 while (! (red_mask & 1)) { red_offset++; red_mask >>= 1; }
105 while (! (green_mask & 1)) { green_offset++; green_mask >>= 1; }
106 while (! (blue_mask & 1)) { blue_offset++; blue_mask >>= 1; }
108 red_bits = 255 / red_mask;
109 green_bits = 255 / green_mask;
110 blue_bits = 255 / blue_mask;
112 for (i = 0; i < 256; i++) {
113 red_color_table[i] = i / red_bits;
114 green_color_table[i] = i / green_bits;
115 blue_color_table[i] = i / blue_bits;
122 ncolors = colors_per_channel * colors_per_channel * colors_per_channel;
124 if (ncolors > (1 << screen_depth)) {
125 colors_per_channel = (1 << screen_depth) / 3;
126 ncolors = colors_per_channel * colors_per_channel * colors_per_channel;
129 if (colors_per_channel < 2 || ncolors > (1 << screen_depth)) {
131 "BImageControl::BImageControl: invalid colormap size %d "
132 "(%d/%d/%d) - reducing",
133 ncolors, colors_per_channel, colors_per_channel,
136 colors_per_channel = (1 << screen_depth) / 3;
139 colors = new XColor[ncolors];
141 fprintf(stderr, "BImageControl::BImageControl: error allocating "
146 int i = 0, ii, p, r, g, b,
149 bits = 256 / colors_per_channel;
150 #else // !ORDEREDPSEUDO
151 bits = 255 / (colors_per_channel - 1);
152 #endif // ORDEREDPSEUDO
154 red_bits = green_bits = blue_bits = bits;
156 for (i = 0; i < 256; i++)
157 red_color_table[i] = green_color_table[i] = blue_color_table[i] =
160 for (r = 0, i = 0; r < colors_per_channel; r++)
161 for (g = 0; g < colors_per_channel; g++)
162 for (b = 0; b < colors_per_channel; b++, i++) {
163 colors[i].red = (r * 0xffff) / (colors_per_channel - 1);
164 colors[i].green = (g * 0xffff) / (colors_per_channel - 1);
165 colors[i].blue = (b * 0xffff) / (colors_per_channel - 1);;
166 colors[i].flags = DoRed|DoGreen|DoBlue;
169 for (i = 0; i < ncolors; i++) {
170 if (! XAllocColor(basedisplay->getXDisplay(), colormap, &colors[i])) {
171 fprintf(stderr, "couldn't alloc color %i %i %i\n",
172 colors[i].red, colors[i].green, colors[i].blue);
175 colors[i].flags = DoRed|DoGreen|DoBlue;
180 int incolors = (((1 << screen_depth) > 256) ? 256 : (1 << screen_depth));
182 for (i = 0; i < incolors; i++)
183 icolors[i].pixel = i;
185 XQueryColors(basedisplay->getXDisplay(), colormap, icolors, incolors);
186 for (i = 0; i < ncolors; i++) {
187 if (! colors[i].flags) {
188 unsigned long chk = 0xffffffff, pixel, close = 0;
192 for (ii = 0; ii < incolors; ii++) {
193 r = (colors[i].red - icolors[i].red) >> 8;
194 g = (colors[i].green - icolors[i].green) >> 8;
195 b = (colors[i].blue - icolors[i].blue) >> 8;
196 pixel = (r * r) + (g * g) + (b * b);
203 colors[i].red = icolors[close].red;
204 colors[i].green = icolors[close].green;
205 colors[i].blue = icolors[close].blue;
207 if (XAllocColor(basedisplay->getXDisplay(), colormap,
209 colors[i].flags = DoRed|DoGreen|DoBlue;
222 if (getVisual()->c_class == StaticGray) {
223 ncolors = 1 << screen_depth;
225 ncolors = colors_per_channel * colors_per_channel * colors_per_channel;
227 if (ncolors > (1 << screen_depth)) {
228 colors_per_channel = (1 << screen_depth) / 3;
230 colors_per_channel * colors_per_channel * colors_per_channel;
234 if (colors_per_channel < 2 || ncolors > (1 << screen_depth)) {
236 "BImageControl::BImageControl: invalid colormap size %d "
237 "(%d/%d/%d) - reducing",
238 ncolors, colors_per_channel, colors_per_channel,
241 colors_per_channel = (1 << screen_depth) / 3;
244 colors = new XColor[ncolors];
247 "BImageControl::BImageControl: error allocating colormap\n");
251 int i = 0, ii, p, bits = 255 / (colors_per_channel - 1);
252 red_bits = green_bits = blue_bits = bits;
254 for (i = 0; i < 256; i++)
255 red_color_table[i] = green_color_table[i] = blue_color_table[i] =
258 for (i = 0; i < ncolors; i++) {
259 colors[i].red = (i * 0xffff) / (colors_per_channel - 1);
260 colors[i].green = (i * 0xffff) / (colors_per_channel - 1);
261 colors[i].blue = (i * 0xffff) / (colors_per_channel - 1);;
262 colors[i].flags = DoRed|DoGreen|DoBlue;
264 if (! XAllocColor(basedisplay->getXDisplay(), colormap,
266 fprintf(stderr, "couldn't alloc color %i %i %i\n",
267 colors[i].red, colors[i].green, colors[i].blue);
270 colors[i].flags = DoRed|DoGreen|DoBlue;
275 int incolors = (((1 << screen_depth) > 256) ? 256 :
276 (1 << screen_depth));
278 for (i = 0; i < incolors; i++)
279 icolors[i].pixel = i;
281 XQueryColors(basedisplay->getXDisplay(), colormap, icolors, incolors);
282 for (i = 0; i < ncolors; i++) {
283 if (! colors[i].flags) {
284 unsigned long chk = 0xffffffff, pixel, close = 0;
288 for (ii = 0; ii < incolors; ii++) {
289 int r = (colors[i].red - icolors[i].red) >> 8;
290 int g = (colors[i].green - icolors[i].green) >> 8;
291 int b = (colors[i].blue - icolors[i].blue) >> 8;
292 pixel = (r * r) + (g * g) + (b * b);
299 colors[i].red = icolors[close].red;
300 colors[i].green = icolors[close].green;
301 colors[i].blue = icolors[close].blue;
303 if (XAllocColor(basedisplay->getXDisplay(), colormap,
305 colors[i].flags = DoRed|DoGreen|DoBlue;
317 fprintf(stderr, "BImageControl::BImageControl: unsupported visual %d\n",
318 getVisual()->c_class);
324 BImageControl::~BImageControl(void) {
325 delete [] sqrt_table;
327 delete [] grad_xbuffer;
329 delete [] grad_ybuffer;
332 unsigned long *pixels = new unsigned long [ncolors];
334 for (int i = 0; i < ncolors; i++)
335 *(pixels + i) = (*(colors + i)).pixel;
337 XFreeColors(basedisplay->getXDisplay(), colormap, pixels, ncolors, 0);
342 if (! cache.empty()) {
344 fprintf(stderr, "BImageContol::~BImageControl: pixmap cache - "
345 "releasing %d pixmaps\n", cache.size());
347 CacheContainer::iterator it = cache.begin();
348 const CacheContainer::iterator end = cache.end();
349 for (; it != end; ++it)
350 XFreePixmap(basedisplay->getXDisplay(), it->pixmap);
359 Pixmap BImageControl::searchCache(const unsigned int width,
360 const unsigned int height,
361 const unsigned long texture,
362 const BColor &c1, const BColor &c2) {
366 CacheContainer::iterator it = cache.begin();
367 const CacheContainer::iterator end = cache.end();
368 for (; it != end; ++it) {
369 CachedImage& tmp = *it;
370 if (tmp.width == width && tmp.height == height &&
371 tmp.texture == texture && tmp.pixel1 == c1.pixel())
372 if (texture & BTexture::Gradient) {
373 if (tmp.pixel2 == c2.pixel()) {
386 Pixmap BImageControl::renderImage(unsigned int width, unsigned int height,
387 const BTexture &texture) {
388 if (texture.texture() & BTexture::Parent_Relative) return ParentRelative;
390 Pixmap pixmap = searchCache(width, height, texture.texture(),
391 texture.color(), texture.colorTo());
392 if (pixmap) return pixmap;
394 BImage image(this, width, height);
395 pixmap = image.render(texture);
406 tmp.texture = texture.texture();
407 tmp.pixel1 = texture.color().pixel();
409 if (texture.texture() & BTexture::Gradient)
410 tmp.pixel2 = texture.colorTo().pixel();
414 cache.push_back(tmp);
416 if (cache.size() > cache_max) {
418 fprintf(stderr, "BImageControl::renderImage: cache is large, "
419 "forcing cleanout\n");
429 void BImageControl::removeImage(Pixmap pixmap) {
433 CacheContainer::iterator it = cache.begin();
434 const CacheContainer::iterator end = cache.end();
435 for (; it != end; ++it) {
436 CachedImage &tmp = *it;
437 if (tmp.pixmap == pixmap && tmp.count > 0)
446 void BImageControl::getColorTables(unsigned char **rmt, unsigned char **gmt,
448 int *roff, int *goff, int *boff,
449 int *rbit, int *gbit, int *bbit) {
450 if (rmt) *rmt = red_color_table;
451 if (gmt) *gmt = green_color_table;
452 if (bmt) *bmt = blue_color_table;
454 if (roff) *roff = red_offset;
455 if (goff) *goff = green_offset;
456 if (boff) *boff = blue_offset;
458 if (rbit) *rbit = red_bits;
459 if (gbit) *gbit = green_bits;
460 if (bbit) *bbit = blue_bits;
464 void BImageControl::getXColorTable(XColor **c, int *n) {
470 void BImageControl::getGradientBuffers(unsigned int w,
475 if (w > grad_buffer_width) {
477 delete [] grad_xbuffer;
479 grad_buffer_width = w;
481 grad_xbuffer = new unsigned int[grad_buffer_width * 3];
484 if (h > grad_buffer_height) {
486 delete [] grad_ybuffer;
488 grad_buffer_height = h;
490 grad_ybuffer = new unsigned int[grad_buffer_height * 3];
493 *xbuf = grad_xbuffer;
494 *ybuf = grad_ybuffer;
498 void BImageControl::installRootColormap(void) {
501 XListInstalledColormaps(basedisplay->getXDisplay(), window, &ncmap);
505 for (int i = 0; i < ncmap; i++)
506 if (*(cmaps + i) == colormap)
510 XInstallColormap(basedisplay->getXDisplay(), colormap);
517 void BImageControl::setColorsPerChannel(int cpc) {
518 if (cpc < 2) cpc = 2;
519 if (cpc > 6) cpc = 6;
521 colors_per_channel = cpc;
525 unsigned long BImageControl::getSqrt(unsigned int x) {
527 // build sqrt table for use with elliptic gradient
529 sqrt_table = new unsigned long[(256 * 256 * 2) + 1];
531 for (int i = 0; i < (256 * 256 * 2); i++)
532 *(sqrt_table + i) = bsqrt(i);
535 return (*(sqrt_table + x));
539 struct ZeroRefCheck {
540 inline bool operator()(const BImageControl::CachedImage &image) const {
541 return (image.count == 0);
545 struct CacheCleaner {
547 ZeroRefCheck ref_check;
548 CacheCleaner(Display *d): display(d) {}
549 inline void operator()(const BImageControl::CachedImage& image) const {
550 if (ref_check(image))
551 XFreePixmap(display, image.pixmap);
556 void BImageControl::timeout(void) {
557 CacheCleaner cleaner(basedisplay->getXDisplay());
558 std::for_each(cache.begin(), cache.end(), cleaner);
559 cache.remove_if(cleaner.ref_check);