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
28 static unsigned long bsqrt(unsigned long x) {
32 unsigned long r = x >> 1;
42 BImageControl *ctrl = 0;
44 BImageControl::BImageControl(OBTimerQueueManager *timermanager,
45 const ScreenInfo *scrn,
46 bool _dither, int _cpc,
47 unsigned long cache_timeout,
49 if (! ctrl) ctrl = this;
53 setColorsPerChannel(_cpc);
57 timer = new OBTimer(timermanager, (OBTimeoutHandler)timeout, this);
58 timer->setTimeout(cache_timeout);
61 timer = (OBTimer *) 0;
64 colors = (XColor *) 0;
67 grad_xbuffer = grad_ybuffer = (unsigned int *) 0;
68 grad_buffer_width = grad_buffer_height = 0;
70 sqrt_table = (unsigned long *) 0;
72 screen_depth = screeninfo->getDepth();
73 window = screeninfo->getRootWindow();
74 screen_number = screeninfo->getScreenNumber();
75 colormap = screeninfo->getColormap();
78 XPixmapFormatValues *pmv = XListPixmapFormats(OBDisplay::display,
82 for (int i = 0; i < count; i++)
83 if (pmv[i].depth == screen_depth) {
84 bits_per_pixel = pmv[i].bits_per_pixel;
91 if (bits_per_pixel == 0) bits_per_pixel = screen_depth;
92 if (bits_per_pixel >= 24) setDither(False);
94 red_offset = green_offset = blue_offset = 0;
96 switch (getVisual()->c_class) {
100 // compute color tables
101 unsigned long red_mask = getVisual()->red_mask,
102 green_mask = getVisual()->green_mask,
103 blue_mask = getVisual()->blue_mask;
105 while (! (red_mask & 1)) { red_offset++; red_mask >>= 1; }
106 while (! (green_mask & 1)) { green_offset++; green_mask >>= 1; }
107 while (! (blue_mask & 1)) { blue_offset++; blue_mask >>= 1; }
109 red_bits = 255 / red_mask;
110 green_bits = 255 / green_mask;
111 blue_bits = 255 / blue_mask;
113 for (i = 0; i < 256; i++) {
114 red_color_table[i] = i / red_bits;
115 green_color_table[i] = i / green_bits;
116 blue_color_table[i] = i / blue_bits;
123 ncolors = colors_per_channel * colors_per_channel * colors_per_channel;
125 if (ncolors > (1 << screen_depth)) {
126 colors_per_channel = (1 << screen_depth) / 3;
127 ncolors = colors_per_channel * colors_per_channel * colors_per_channel;
130 if (colors_per_channel < 2 || ncolors > (1 << screen_depth)) {
132 "BImageControl::BImageControl: invalid colormap size %d "
133 "(%d/%d/%d) - reducing",
134 ncolors, colors_per_channel, colors_per_channel,
137 colors_per_channel = (1 << screen_depth) / 3;
140 colors = new XColor[ncolors];
142 fprintf(stderr, "BImageControl::BImageControl: error allocating "
147 int i = 0, ii, p, r, g, b,
150 bits = 256 / colors_per_channel;
151 #else // !ORDEREDPSEUDO
152 bits = 255 / (colors_per_channel - 1);
153 #endif // ORDEREDPSEUDO
155 red_bits = green_bits = blue_bits = bits;
157 for (i = 0; i < 256; i++)
158 red_color_table[i] = green_color_table[i] = blue_color_table[i] =
161 for (r = 0, i = 0; r < colors_per_channel; r++)
162 for (g = 0; g < colors_per_channel; g++)
163 for (b = 0; b < colors_per_channel; b++, i++) {
164 colors[i].red = (r * 0xffff) / (colors_per_channel - 1);
165 colors[i].green = (g * 0xffff) / (colors_per_channel - 1);
166 colors[i].blue = (b * 0xffff) / (colors_per_channel - 1);;
167 colors[i].flags = DoRed|DoGreen|DoBlue;
170 for (i = 0; i < ncolors; i++) {
171 if (! XAllocColor(OBDisplay::display, colormap, &colors[i])) {
172 fprintf(stderr, "couldn't alloc color %i %i %i\n",
173 colors[i].red, colors[i].green, colors[i].blue);
176 colors[i].flags = DoRed|DoGreen|DoBlue;
181 int incolors = (((1 << screen_depth) > 256) ? 256 : (1 << screen_depth));
183 for (i = 0; i < incolors; i++)
184 icolors[i].pixel = i;
186 XQueryColors(OBDisplay::display, colormap, icolors, incolors);
187 for (i = 0; i < ncolors; i++) {
188 if (! colors[i].flags) {
189 unsigned long chk = 0xffffffff, pixel, close = 0;
193 for (ii = 0; ii < incolors; ii++) {
194 r = (colors[i].red - icolors[i].red) >> 8;
195 g = (colors[i].green - icolors[i].green) >> 8;
196 b = (colors[i].blue - icolors[i].blue) >> 8;
197 pixel = (r * r) + (g * g) + (b * b);
204 colors[i].red = icolors[close].red;
205 colors[i].green = icolors[close].green;
206 colors[i].blue = icolors[close].blue;
208 if (XAllocColor(OBDisplay::display, colormap,
210 colors[i].flags = DoRed|DoGreen|DoBlue;
223 if (getVisual()->c_class == StaticGray) {
224 ncolors = 1 << screen_depth;
226 ncolors = colors_per_channel * colors_per_channel * colors_per_channel;
228 if (ncolors > (1 << screen_depth)) {
229 colors_per_channel = (1 << screen_depth) / 3;
231 colors_per_channel * colors_per_channel * colors_per_channel;
235 if (colors_per_channel < 2 || ncolors > (1 << screen_depth)) {
237 "BImageControl::BImageControl: invalid colormap size %d "
238 "(%d/%d/%d) - reducing",
239 ncolors, colors_per_channel, colors_per_channel,
242 colors_per_channel = (1 << screen_depth) / 3;
245 colors = new XColor[ncolors];
248 "BImageControl::BImageControl: error allocating colormap\n");
252 int i = 0, ii, p, bits = 255 / (colors_per_channel - 1);
253 red_bits = green_bits = blue_bits = bits;
255 for (i = 0; i < 256; i++)
256 red_color_table[i] = green_color_table[i] = blue_color_table[i] =
259 for (i = 0; i < ncolors; i++) {
260 colors[i].red = (i * 0xffff) / (colors_per_channel - 1);
261 colors[i].green = (i * 0xffff) / (colors_per_channel - 1);
262 colors[i].blue = (i * 0xffff) / (colors_per_channel - 1);;
263 colors[i].flags = DoRed|DoGreen|DoBlue;
265 if (! XAllocColor(OBDisplay::display, colormap,
267 fprintf(stderr, "couldn't alloc color %i %i %i\n",
268 colors[i].red, colors[i].green, colors[i].blue);
271 colors[i].flags = DoRed|DoGreen|DoBlue;
276 int incolors = (((1 << screen_depth) > 256) ? 256 :
277 (1 << screen_depth));
279 for (i = 0; i < incolors; i++)
280 icolors[i].pixel = i;
282 XQueryColors(OBDisplay::display, colormap, icolors, incolors);
283 for (i = 0; i < ncolors; i++) {
284 if (! colors[i].flags) {
285 unsigned long chk = 0xffffffff, pixel, close = 0;
289 for (ii = 0; ii < incolors; ii++) {
290 int r = (colors[i].red - icolors[i].red) >> 8;
291 int g = (colors[i].green - icolors[i].green) >> 8;
292 int b = (colors[i].blue - icolors[i].blue) >> 8;
293 pixel = (r * r) + (g * g) + (b * b);
300 colors[i].red = icolors[close].red;
301 colors[i].green = icolors[close].green;
302 colors[i].blue = icolors[close].blue;
304 if (XAllocColor(OBDisplay::display, colormap,
306 colors[i].flags = DoRed|DoGreen|DoBlue;
318 fprintf(stderr, "BImageControl::BImageControl: unsupported visual %d\n",
319 getVisual()->c_class);
325 BImageControl::~BImageControl(void) {
326 delete [] sqrt_table;
328 delete [] grad_xbuffer;
330 delete [] grad_ybuffer;
333 unsigned long *pixels = new unsigned long [ncolors];
335 for (int i = 0; i < ncolors; i++)
336 *(pixels + i) = (*(colors + i)).pixel;
338 XFreeColors(OBDisplay::display, colormap, pixels, ncolors, 0);
343 if (! cache.empty()) {
345 fprintf(stderr, "BImageContol::~BImageControl: pixmap cache - "
346 "releasing %d pixmaps\n", cache.size());
348 CacheContainer::iterator it = cache.begin();
349 const CacheContainer::iterator end = cache.end();
350 for (; it != end; ++it)
351 XFreePixmap(OBDisplay::display, it->pixmap);
360 Pixmap BImageControl::searchCache(const unsigned int width,
361 const unsigned int height,
362 const unsigned long texture,
363 const BColor &c1, const BColor &c2) {
367 CacheContainer::iterator it = cache.begin();
368 const CacheContainer::iterator end = cache.end();
369 for (; it != end; ++it) {
370 CachedImage& tmp = *it;
371 if (tmp.width == width && tmp.height == height &&
372 tmp.texture == texture && tmp.pixel1 == c1.pixel())
373 if (texture & BTexture::Gradient) {
374 if (tmp.pixel2 == c2.pixel()) {
387 Pixmap BImageControl::renderImage(unsigned int width, unsigned int height,
388 const BTexture &texture) {
389 if (texture.texture() & BTexture::Parent_Relative) return ParentRelative;
391 Pixmap pixmap = searchCache(width, height, texture.texture(),
392 texture.color(), texture.colorTo());
393 if (pixmap) return pixmap;
395 BImage image(this, width, height);
396 pixmap = image.render(texture);
407 tmp.texture = texture.texture();
408 tmp.pixel1 = texture.color().pixel();
410 if (texture.texture() & BTexture::Gradient)
411 tmp.pixel2 = texture.colorTo().pixel();
415 cache.push_back(tmp);
417 if (cache.size() > cache_max) {
419 fprintf(stderr, "BImageControl::renderImage: cache is large, "
420 "forcing cleanout\n");
430 void BImageControl::removeImage(Pixmap pixmap) {
434 CacheContainer::iterator it = cache.begin();
435 const CacheContainer::iterator end = cache.end();
436 for (; it != end; ++it) {
437 CachedImage &tmp = *it;
438 if (tmp.pixmap == pixmap && tmp.count > 0)
447 void BImageControl::getColorTables(unsigned char **rmt, unsigned char **gmt,
449 int *roff, int *goff, int *boff,
450 int *rbit, int *gbit, int *bbit) {
451 if (rmt) *rmt = red_color_table;
452 if (gmt) *gmt = green_color_table;
453 if (bmt) *bmt = blue_color_table;
455 if (roff) *roff = red_offset;
456 if (goff) *goff = green_offset;
457 if (boff) *boff = blue_offset;
459 if (rbit) *rbit = red_bits;
460 if (gbit) *gbit = green_bits;
461 if (bbit) *bbit = blue_bits;
465 void BImageControl::getXColorTable(XColor **c, int *n) {
471 void BImageControl::getGradientBuffers(unsigned int w,
476 if (w > grad_buffer_width) {
478 delete [] grad_xbuffer;
480 grad_buffer_width = w;
482 grad_xbuffer = new unsigned int[grad_buffer_width * 3];
485 if (h > grad_buffer_height) {
487 delete [] grad_ybuffer;
489 grad_buffer_height = h;
491 grad_ybuffer = new unsigned int[grad_buffer_height * 3];
494 *xbuf = grad_xbuffer;
495 *ybuf = grad_ybuffer;
499 void BImageControl::installRootColormap(void) {
502 XListInstalledColormaps(OBDisplay::display, window, &ncmap);
506 for (int i = 0; i < ncmap; i++)
507 if (*(cmaps + i) == colormap)
511 XInstallColormap(OBDisplay::display, colormap);
518 void BImageControl::setColorsPerChannel(int cpc) {
519 if (cpc < 2) cpc = 2;
520 if (cpc > 6) cpc = 6;
522 colors_per_channel = cpc;
526 unsigned long BImageControl::getSqrt(unsigned int x) {
528 // build sqrt table for use with elliptic gradient
530 sqrt_table = new unsigned long[(256 * 256 * 2) + 1];
532 for (int i = 0; i < (256 * 256 * 2); i++)
533 *(sqrt_table + i) = bsqrt(i);
536 return (*(sqrt_table + x));
540 struct ZeroRefCheck {
541 inline bool operator()(const BImageControl::CachedImage &image) const {
542 return (image.count == 0);
546 struct CacheCleaner {
547 ZeroRefCheck ref_check;
549 inline void operator()(const BImageControl::CachedImage& image) const {
550 if (ref_check(image))
551 XFreePixmap(OBDisplay::display, image.pixmap);
556 void BImageControl::timeout(BImageControl *t) {
557 CacheCleaner cleaner;
558 std::for_each(t->cache.begin(), t->cache.end(), cleaner);
559 t->cache.remove_if(cleaner.ref_check);