aboutsummaryrefslogtreecommitdiff
path: root/src/FbTk/ImageControl.cc
diff options
context:
space:
mode:
authorfluxgen <fluxgen>2003-01-09 21:09:49 (GMT)
committerfluxgen <fluxgen>2003-01-09 21:09:49 (GMT)
commit7dd4823340ae5f710a08ff3a8fbe4276defc6b85 (patch)
treef4b6623ecf435a643fcf247d3075aaf79d6e82f3 /src/FbTk/ImageControl.cc
parent7a74a56fe48b319fecf56cede8e16f9c03dfaa96 (diff)
downloadfluxbox-7dd4823340ae5f710a08ff3a8fbe4276defc6b85.zip
fluxbox-7dd4823340ae5f710a08ff3a8fbe4276defc6b85.tar.bz2
moved from fluxbox to fbtk
Diffstat (limited to 'src/FbTk/ImageControl.cc')
-rw-r--r--src/FbTk/ImageControl.cc613
1 files changed, 613 insertions, 0 deletions
diff --git a/src/FbTk/ImageControl.cc b/src/FbTk/ImageControl.cc
new file mode 100644
index 0000000..f43628f
--- /dev/null
+++ b/src/FbTk/ImageControl.cc
@@ -0,0 +1,613 @@
1// ImageControl.cc for FbTk - Fluxbox Toolkit
2// Copyright (c) 2001 - 2003 Henrik Kinnunen (fluxbox at users.sourceforge.net)
3//
4// Image.cc for Blackbox - an X11 Window manager
5// Copyright (c) 1997 - 2000 Brad Hughes (bhughes at tcac.net)
6//
7// Permission is hereby granted, free of charge, to any person obtaining a
8// copy of this software and associated documentation files (the "Software"),
9// to deal in the Software without restriction, including without limitation
10// the rights to use, copy, modify, merge, publish, distribute, sublicense,
11// and/or sell copies of the Software, and to permit persons to whom the
12// Software is furnished to do so, subject to the following conditions:
13//
14// The above copyright notice and this permission notice shall be included in
15// all copies or substantial portions of the Software.
16//
17// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23// DEALINGS IN THE SOFTWARE.
24
25// $Id: ImageControl.cc,v 1.1 2003/01/09 21:09:49 fluxgen Exp $
26
27#include "ImageControl.hh"
28
29#include "TextureRender.hh"
30#include "App.hh"
31
32//use GNU extensions
33#ifndef _GNU_SOURCE
34#define _GNU_SOURCE
35#endif // _GNU_SOURCE
36
37
38#ifdef HAVE_CONFIG_H
39#include "config.h"
40#endif // HAVE_CONFIG_H
41
42#ifdef HAVE_SYS_TYPES_H
43#include <sys/types.h>
44#endif // HAVE_SYS_TYPES_H
45
46#include <cstdlib>
47#include <cstring>
48#include <cstdio>
49
50#ifdef HAVE_CTYPE_H
51#include <ctype.h>
52#endif // HAVE_CTYPE_H
53
54#include <iostream>
55
56using namespace std;
57
58namespace FbTk {
59
60// lookup table for texture
61unsigned long *ImageControl::sqrt_table = 0;
62
63namespace { // anonymous
64
65unsigned long bsqrt(unsigned long x) {
66 if (x <= 0) return 0;
67 if (x == 1) return 1;
68
69 unsigned long r = x >> 1;
70 unsigned long q;
71
72 while (1) {
73 q = x / r;
74 if (q >= r) return r;
75 r = (r + q) >> 1;
76 }
77}
78
79}; // end anonymous namespace
80
81
82ImageControl::ImageControl(int screen_num, bool dither,
83 int cpc, unsigned long cache_timeout, unsigned long cmax):
84 m_dither(dither),
85 m_timer(this),
86 m_colors(0),
87 m_num_colors(0),
88 m_colors_per_channel(cpc) {
89
90 Display *disp = FbTk::App::instance()->display();
91
92 m_screen_depth = DefaultDepth(disp, screen_num);
93 m_screen_num = screen_num;
94 m_root_window = RootWindow(disp, screen_num);
95 m_visual = DefaultVisual(disp, screen_num);
96 m_colormap = DefaultColormap(disp, screen_num);
97
98 cache_max = cmax;
99#ifdef TIMEDCACHE
100 if (cache_timeout) {
101 m_timer.setTimeout(cache_timeout);
102 m_timer.start();
103 }
104#endif // TIMEDCACHE
105
106 createColorTable();
107}
108
109
110ImageControl::~ImageControl() {
111 if (sqrt_table) {
112 delete [] sqrt_table;
113 }
114
115 if (grad_xbuffer) {
116 delete [] grad_xbuffer;
117 }
118
119 if (grad_ybuffer) {
120 delete [] grad_ybuffer;
121 }
122
123 if (m_colors) {
124 unsigned long *pixels = new unsigned long [m_num_colors];
125
126 for (unsigned int color = 0; color < m_num_colors; color++)
127 *(pixels + color) = (*(m_colors + color)).pixel;
128
129 XFreeColors(FbTk::App::instance()->display(), m_colormap, pixels, m_num_colors, 0);
130
131 delete [] m_colors;
132 }
133
134 if (cache.size() > 0) {
135#ifdef DEBUG
136 cerr<<"FbTk::ImageContol: pixmap cache - releasing "<<cache.size()<<" pixmaps."<<endl;
137#endif // DEBUG
138 CacheList::iterator it = cache.begin();
139 CacheList::iterator it_end = cache.end();
140 Display *disp = FbTk::App::instance()->display();
141 for (; it != it_end; ++it) {
142 XFreePixmap(disp, (*it)->pixmap);
143 delete (*it);
144 }
145
146 }
147}
148
149
150Pixmap ImageControl::searchCache(unsigned int width, unsigned int height,
151 unsigned long texture_type,
152 const FbTk::Color &color, const FbTk::Color &color_to) const {
153 CacheList::iterator it = cache.begin();
154 CacheList::iterator it_end = cache.end();
155 for (; it != it_end; ++it) {
156 if (((*it)->width == width) &&
157 ((*it)->height == height) &&
158 ((*it)->texture == texture_type) &&
159 ((*it)->pixel1 == color.pixel())) {
160 if (texture_type & FbTk::Texture::GRADIENT) {
161 if ((*it)->pixel2 == color_to.pixel()) {
162 (*it)->count++;
163 return (*it)->pixmap;
164 }
165 } else {
166 (*it)->count++;
167 return (*it)->pixmap;
168 }
169 }
170 }
171
172 return None;
173}
174
175
176Pixmap ImageControl::renderImage(unsigned int width, unsigned int height,
177 const FbTk::Texture &texture) {
178
179 if (texture.type() & FbTk::Texture::PARENTRELATIVE)
180 return ParentRelative;
181
182 // search cache first
183 Pixmap pixmap = searchCache(width, height, texture.type(),
184 texture.color(), texture.colorTo());
185 if (pixmap)
186 return pixmap; // return cache item
187
188 // render new image
189 TextureRender image(*this, width, height);
190 pixmap = image.render(texture);
191
192 if (pixmap) {
193 // create new cache item and add it to cache list
194
195 Cache *tmp = new Cache;
196
197 tmp->pixmap = pixmap;
198 tmp->width = width;
199 tmp->height = height;
200 tmp->count = 1;
201 tmp->texture = texture.type();
202 tmp->pixel1 = texture.color().pixel();
203
204 if (texture.type() & FbTk::Texture::GRADIENT)
205 tmp->pixel2 = texture.colorTo().pixel();
206 else
207 tmp->pixel2 = 0l;
208
209 cache.push_back(tmp);
210
211 if ((unsigned) cache.size() > cache_max) {
212#ifdef DEBUG
213 cerr<<"FbTk::ImageControl::renderImage(): cache is large, forcing cleanout"<<endl;
214#endif // DEBUG
215 timeout();
216 }
217
218 return pixmap;
219 }
220
221 return None;
222}
223
224
225void ImageControl::removeImage(Pixmap pixmap) {
226 if (!pixmap)
227 return;
228
229 CacheList::iterator it = cache.begin();
230 CacheList::iterator it_end = cache.end();
231 for (; it != it_end; ++it) {
232 if ((*it)->pixmap == pixmap) {
233 if ((*it)->count) {
234 (*it)->count--;
235
236#ifdef TIMEDCACHE
237 timeout();
238#else // !TIMEDCACHE
239 if (! (*it)->count) timeout();
240#endif // TIMEDCACHE
241 }
242
243 return;
244 }
245 }
246}
247
248
249void ImageControl::colorTables(const unsigned char **rmt, const unsigned char **gmt,
250 const unsigned char **bmt,
251 int *roff, int *goff, int *boff,
252 int *rbit, int *gbit, int *bbit) const {
253
254 if (rmt) *rmt = red_color_table;
255 if (gmt) *gmt = green_color_table;
256 if (bmt) *bmt = blue_color_table;
257
258 if (roff) *roff = red_offset;
259 if (goff) *goff = green_offset;
260 if (boff) *boff = blue_offset;
261
262 if (rbit) *rbit = red_bits;
263 if (gbit) *gbit = green_bits;
264 if (bbit) *bbit = blue_bits;
265}
266
267
268void ImageControl::getXColorTable(XColor **c, int *n) {
269 if (c) *c = m_colors;
270 if (n) *n = m_num_colors;
271}
272
273
274void ImageControl::getGradientBuffers(unsigned int w,
275 unsigned int h,
276 unsigned int **xbuf,
277 unsigned int **ybuf) {
278
279 if (w > grad_buffer_width) {
280 if (grad_xbuffer) {
281 delete [] grad_xbuffer;
282 }
283
284 grad_buffer_width = w;
285
286 grad_xbuffer = new unsigned int[grad_buffer_width * 3];
287 }
288
289 if (h > grad_buffer_height) {
290 if (grad_ybuffer) {
291 delete [] grad_ybuffer;
292 }
293
294 grad_buffer_height = h;
295
296 grad_ybuffer = new unsigned int[grad_buffer_height * 3];
297 }
298
299 *xbuf = grad_xbuffer;
300 *ybuf = grad_ybuffer;
301}
302
303
304void ImageControl::installRootColormap() {
305 XGrabServer(FbTk::App::instance()->display());
306
307
308 Display *disp = FbTk::App::instance()->display();
309 bool install = true;
310 int i = 0, ncmap = 0;
311 Colormap *cmaps =
312 XListInstalledColormaps(disp, m_root_window, &ncmap);
313
314 if (cmaps) {
315 for (i = 0; i < ncmap; i++) {
316 if (*(cmaps + i) == m_colormap)
317 install = false;
318 }
319
320 if (install)
321 XInstallColormap(disp, m_colormap);
322
323 XFree(cmaps);
324 }
325
326 XUngrabServer(FbTk::App::instance()->display());
327}
328
329
330void ImageControl::setColorsPerChannel(int cpc) {
331 if (cpc < 2) cpc = 2;
332 if (cpc > 6) cpc = 6;
333
334 m_colors_per_channel = cpc;
335}
336
337
338unsigned long ImageControl::getSqrt(unsigned int x) const {
339 if (! sqrt_table) {
340 // build sqrt table for use with elliptic gradient
341
342 sqrt_table = new unsigned long[(256 * 256 * 2) + 1];
343 int i = 0;
344
345 for (; i < (256 * 256 * 2); i++)
346 *(sqrt_table + i) = bsqrt(i);
347 }
348
349 return (*(sqrt_table + x));
350}
351
352void ImageControl::timeout() {
353 Display *disp = FbTk::App::instance()->display();
354 CacheList::iterator it = cache.begin();
355 CacheList::iterator it_end = cache.end();
356 for (; it != it_end; ++it) {
357 Cache *tmp = (*it);
358
359 if (tmp->count <= 0) {
360 XFreePixmap(disp, tmp->pixmap);
361 it = cache.erase(it);
362 delete tmp;
363 if (it == it_end) break;
364 }
365 }
366}
367
368void ImageControl::createColorTable() {
369 Display *disp = FbTk::App::instance()->display();
370
371 grad_xbuffer = grad_ybuffer = (unsigned int *) 0;
372 grad_buffer_width = grad_buffer_height = 0;
373
374 int count;
375 XPixmapFormatValues *pmv = XListPixmapFormats(disp, &count);
376
377 if (pmv) {
378 bits_per_pixel = 0;
379 for (int i = 0; i < count; i++) {
380 if (pmv[i].depth == m_screen_depth) {
381 bits_per_pixel = pmv[i].bits_per_pixel;
382 break;
383 }
384 }
385
386 XFree(pmv);
387 }
388
389 if (bits_per_pixel == 0)
390 bits_per_pixel = m_screen_depth;
391 if (bits_per_pixel >= 24)
392 setDither(false);
393
394 red_offset = green_offset = blue_offset = 0;
395
396 switch (visual()->c_class) {
397 case TrueColor: {
398 int i;
399
400 // compute color tables
401 unsigned long red_mask = visual()->red_mask,
402 green_mask = visual()->green_mask,
403 blue_mask = visual()->blue_mask;
404
405 while (! (red_mask & 1)) { red_offset++; red_mask >>= 1; }
406 while (! (green_mask & 1)) { green_offset++; green_mask >>= 1; }
407 while (! (blue_mask & 1)) { blue_offset++; blue_mask >>= 1; }
408
409 red_bits = 255 / red_mask;
410 green_bits = 255 / green_mask;
411 blue_bits = 255 / blue_mask;
412
413 for (i = 0; i < 256; i++) {
414 red_color_table[i] = i / red_bits;
415 green_color_table[i] = i / green_bits;
416 blue_color_table[i] = i / blue_bits;
417 }
418 }
419
420 break;
421
422 case PseudoColor:
423 case StaticColor: {
424
425 m_num_colors = m_colors_per_channel * m_colors_per_channel * m_colors_per_channel;
426
427 if (m_num_colors > static_cast<unsigned int>(1 << m_screen_depth)) {
428 m_colors_per_channel = (1 << m_screen_depth) / 3;
429 m_num_colors = m_colors_per_channel * m_colors_per_channel * m_colors_per_channel;
430 }
431
432 if (m_colors_per_channel < 2 || m_num_colors > static_cast<unsigned int>(1 << m_screen_depth)) {
433 fprintf(stderr, "ImageControl::ImageControl: invalid colormap size %d "
434 "(%d/%d/%d) - reducing",
435 m_num_colors, m_colors_per_channel, m_colors_per_channel,
436 m_colors_per_channel);
437
438 m_colors_per_channel = (1 << m_screen_depth) / 3;
439 }
440
441 m_colors = new XColor[m_num_colors];
442
443 int bits = 256 / m_colors_per_channel;
444
445#ifndef ORDEREDPSEUDO
446 bits = 255 / (m_colors_per_channel - 1);
447#endif // ORDEREDPSEUDO
448
449 red_bits = green_bits = blue_bits = bits;
450
451 for (unsigned int i = 0; i < 256; i++) {
452 red_color_table[i] = green_color_table[i] = blue_color_table[i] =
453 i / bits;
454 }
455
456 for (int r = 0, i = 0; r < m_colors_per_channel; r++) {
457 for (int g = 0; g < m_colors_per_channel; g++) {
458 for (int b = 0; b < m_colors_per_channel; b++, i++) {
459 m_colors[i].red = (r * 0xffff) / (m_colors_per_channel - 1);
460 m_colors[i].green = (g * 0xffff) / (m_colors_per_channel - 1);
461 m_colors[i].blue = (b * 0xffff) / (m_colors_per_channel - 1);;
462 m_colors[i].flags = DoRed|DoGreen|DoBlue;
463 }
464 }
465 }
466
467 for (unsigned int i = 0; i < m_num_colors; i++) {
468 if (! XAllocColor(disp, m_colormap, &m_colors[i])) {
469 fprintf(stderr, "couldn't alloc color %i %i %i\n",
470 m_colors[i].red, m_colors[i].green, m_colors[i].blue);
471 m_colors[i].flags = 0;
472 } else
473 m_colors[i].flags = DoRed|DoGreen|DoBlue;
474 }
475
476 XColor icolors[256];
477 unsigned int incolors = (((1 << m_screen_depth) > 256) ? 256 : (1 << m_screen_depth));
478
479 for (unsigned int i = 0; i < incolors; i++)
480 icolors[i].pixel = i;
481
482 XQueryColors(disp, m_colormap, icolors, incolors);
483 for (unsigned int i = 0; i < m_num_colors; i++) {
484 if (! m_colors[i].flags) {
485 unsigned long chk = 0xffffffff, pixel, close = 0;
486 char p = 2;
487
488 while (p--) {
489 for (unsigned int ii = 0; ii < incolors; ii++) {
490 int r = (m_colors[i].red - icolors[i].red) >> 8;
491 int g = (m_colors[i].green - icolors[i].green) >> 8;
492 int b = (m_colors[i].blue - icolors[i].blue) >> 8;
493 pixel = (r * r) + (g * g) + (b * b);
494
495 if (pixel < chk) {
496 chk = pixel;
497 close = ii;
498 }
499
500 m_colors[i].red = icolors[close].red;
501 m_colors[i].green = icolors[close].green;
502 m_colors[i].blue = icolors[close].blue;
503
504 if (XAllocColor(disp, m_colormap,
505 &m_colors[i])) {
506 m_colors[i].flags = DoRed|DoGreen|DoBlue;
507 break;
508 }
509 }
510 }
511 }
512 }
513
514 break;
515 }
516
517 case GrayScale:
518 case StaticGray:
519 {
520
521 if (visual()->c_class == StaticGray) {
522 m_num_colors = 1 << m_screen_depth;
523 } else {
524 m_num_colors = m_colors_per_channel * m_colors_per_channel * m_colors_per_channel;
525
526 if (m_num_colors > static_cast<unsigned int>(1 << m_screen_depth)) {
527 m_colors_per_channel = (1 << m_screen_depth) / 3;
528 m_num_colors = m_colors_per_channel * m_colors_per_channel * m_colors_per_channel;
529 }
530 }
531
532 if (m_colors_per_channel < 2 || m_num_colors > static_cast<unsigned int>(1 << m_screen_depth)) {
533 fprintf(stderr,"FbTk::ImageControl: invalid colormap size %d "
534 "(%d/%d/%d) - reducing",
535 m_num_colors, m_colors_per_channel, m_colors_per_channel,
536 m_colors_per_channel);
537
538 m_colors_per_channel = (1 << m_screen_depth) / 3;
539 }
540
541 m_colors = new XColor[m_num_colors];
542
543 int p, bits = 255 / (m_colors_per_channel - 1);
544 red_bits = green_bits = blue_bits = bits;
545
546 for (unsigned int i = 0; i < 256; i++)
547 red_color_table[i] = green_color_table[i] = blue_color_table[i] =
548 i / bits;
549
550 for (unsigned int i = 0; i < m_num_colors; i++) {
551 m_colors[i].red = (i * 0xffff) / (m_colors_per_channel - 1);
552 m_colors[i].green = (i * 0xffff) / (m_colors_per_channel - 1);
553 m_colors[i].blue = (i * 0xffff) / (m_colors_per_channel - 1);;
554 m_colors[i].flags = DoRed|DoGreen|DoBlue;
555
556 if (! XAllocColor(disp, m_colormap,
557 &m_colors[i])) {
558 fprintf(stderr, "Couldn't alloc color %i %i %i\n",
559 m_colors[i].red, m_colors[i].green, m_colors[i].blue);
560 m_colors[i].flags = 0;
561 } else
562 m_colors[i].flags = DoRed|DoGreen|DoBlue;
563 }
564
565
566 XColor icolors[256];
567 unsigned int incolors = (((1 << m_screen_depth) > 256) ? 256 :
568 (1 << m_screen_depth));
569
570 for (unsigned int i = 0; i < incolors; i++)
571 icolors[i].pixel = i;
572
573 XQueryColors(disp, m_colormap, icolors, incolors);
574 for (unsigned int i = 0; i < m_num_colors; i++) {
575 if (! m_colors[i].flags) {
576 unsigned long chk = 0xffffffff, pixel, close = 0;
577
578 p = 2;
579 while (p--) {
580 for (unsigned int ii = 0; ii < incolors; ii++) {
581 int r = (m_colors[i].red - icolors[i].red) >> 8;
582 int g = (m_colors[i].green - icolors[i].green) >> 8;
583 int b = (m_colors[i].blue - icolors[i].blue) >> 8;
584 pixel = (r * r) + (g * g) + (b * b);
585
586 if (pixel < chk) {
587 chk = pixel;
588 close = ii;
589 }
590
591 m_colors[i].red = icolors[close].red;
592 m_colors[i].green = icolors[close].green;
593 m_colors[i].blue = icolors[close].blue;
594
595 if (XAllocColor(disp, m_colormap, &m_colors[i])) {
596 m_colors[i].flags = DoRed|DoGreen|DoBlue;
597 break;
598 }
599 }
600 }
601 }
602 }
603
604 break;
605 }
606
607 default:
608 cerr<<"FbTk::ImageControl: Unsupported visual"<<endl;
609 break;
610 }
611}
612
613}; // end namespace FbTk