]>
Dogcows Code - chaz/openbox/blob - otk/imagecontrol.cc
1 // -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
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 ImageControl
*ctrl
= 0;
44 ImageControl::ImageControl(const ScreenInfo
*scrn
,
45 bool _dither
, int _cpc
,
46 unsigned long cache_timeout
,
48 if (! ctrl
) ctrl
= this;
52 setColorsPerChannel(_cpc
);
56 timer
= new Timer(cache_timeout
, (Timer::TimeoutHandler
)timeout
, this);
60 colors
= (XColor
*) 0;
63 grad_xbuffer
= grad_ybuffer
= (unsigned int *) 0;
64 grad_buffer_width
= grad_buffer_height
= 0;
66 sqrt_table
= (unsigned long *) 0;
68 screen_depth
= screeninfo
->depth();
69 window
= screeninfo
->rootWindow();
70 screen_number
= screeninfo
->screen();
71 colormap
= screeninfo
->colormap();
74 XPixmapFormatValues
*pmv
= XListPixmapFormats(**display
,
78 for (int i
= 0; i
< count
; i
++)
79 if (pmv
[i
].depth
== screen_depth
) {
80 bits_per_pixel
= pmv
[i
].bits_per_pixel
;
87 if (bits_per_pixel
== 0) bits_per_pixel
= screen_depth
;
88 if (bits_per_pixel
>= 24) setDither(False
);
90 red_offset
= green_offset
= blue_offset
= 0;
92 switch (getVisual()->c_class
) {
96 // compute color tables
97 unsigned long red_mask
= getVisual()->red_mask
,
98 green_mask
= getVisual()->green_mask
,
99 blue_mask
= getVisual()->blue_mask
;
101 while (! (red_mask
& 1)) { red_offset
++; red_mask
>>= 1; }
102 while (! (green_mask
& 1)) { green_offset
++; green_mask
>>= 1; }
103 while (! (blue_mask
& 1)) { blue_offset
++; blue_mask
>>= 1; }
105 red_bits
= 255 / red_mask
;
106 green_bits
= 255 / green_mask
;
107 blue_bits
= 255 / blue_mask
;
109 for (i
= 0; i
< 256; i
++) {
110 red_color_table
[i
] = i
/ red_bits
;
111 green_color_table
[i
] = i
/ green_bits
;
112 blue_color_table
[i
] = i
/ blue_bits
;
119 ncolors
= colors_per_channel
* colors_per_channel
* colors_per_channel
;
121 if (ncolors
> (1 << screen_depth
)) {
122 colors_per_channel
= (1 << screen_depth
) / 3;
123 ncolors
= colors_per_channel
* colors_per_channel
* colors_per_channel
;
126 if (colors_per_channel
< 2 || ncolors
> (1 << screen_depth
)) {
128 "ImageControl::ImageControl: invalid colormap size %d "
129 "(%d/%d/%d) - reducing",
130 ncolors
, colors_per_channel
, colors_per_channel
,
133 colors_per_channel
= (1 << screen_depth
) / 3;
136 colors
= new XColor
[ncolors
];
138 fprintf(stderr
, "ImageControl::ImageControl: error allocating "
143 int i
= 0, ii
, p
, r
, g
, b
,
146 bits
= 256 / colors_per_channel
;
147 #else // !ORDEREDPSEUDO
148 bits
= 255 / (colors_per_channel
- 1);
149 #endif // ORDEREDPSEUDO
151 red_bits
= green_bits
= blue_bits
= bits
;
153 for (i
= 0; i
< 256; i
++)
154 red_color_table
[i
] = green_color_table
[i
] = blue_color_table
[i
] =
157 for (r
= 0, i
= 0; r
< colors_per_channel
; r
++)
158 for (g
= 0; g
< colors_per_channel
; g
++)
159 for (b
= 0; b
< colors_per_channel
; b
++, i
++) {
160 colors
[i
].red
= (r
* 0xffff) / (colors_per_channel
- 1);
161 colors
[i
].green
= (g
* 0xffff) / (colors_per_channel
- 1);
162 colors
[i
].blue
= (b
* 0xffff) / (colors_per_channel
- 1);;
163 colors
[i
].flags
= DoRed
|DoGreen
|DoBlue
;
166 for (i
= 0; i
< ncolors
; i
++) {
167 if (! XAllocColor(**display
, colormap
, &colors
[i
])) {
168 fprintf(stderr
, "couldn't alloc color %i %i %i\n",
169 colors
[i
].red
, colors
[i
].green
, colors
[i
].blue
);
172 colors
[i
].flags
= DoRed
|DoGreen
|DoBlue
;
177 int incolors
= (((1 << screen_depth
) > 256) ? 256 : (1 << screen_depth
));
179 for (i
= 0; i
< incolors
; i
++)
180 icolors
[i
].pixel
= i
;
182 XQueryColors(**display
, colormap
, icolors
, incolors
);
183 for (i
= 0; i
< ncolors
; i
++) {
184 if (! colors
[i
].flags
) {
185 unsigned long chk
= 0xffffffff, pixel
, close
= 0;
189 for (ii
= 0; ii
< incolors
; ii
++) {
190 r
= (colors
[i
].red
- icolors
[i
].red
) >> 8;
191 g
= (colors
[i
].green
- icolors
[i
].green
) >> 8;
192 b
= (colors
[i
].blue
- icolors
[i
].blue
) >> 8;
193 pixel
= (r
* r
) + (g
* g
) + (b
* b
);
200 colors
[i
].red
= icolors
[close
].red
;
201 colors
[i
].green
= icolors
[close
].green
;
202 colors
[i
].blue
= icolors
[close
].blue
;
204 if (XAllocColor(**display
, colormap
,
206 colors
[i
].flags
= DoRed
|DoGreen
|DoBlue
;
219 if (getVisual()->c_class
== StaticGray
) {
220 ncolors
= 1 << screen_depth
;
222 ncolors
= colors_per_channel
* colors_per_channel
* colors_per_channel
;
224 if (ncolors
> (1 << screen_depth
)) {
225 colors_per_channel
= (1 << screen_depth
) / 3;
227 colors_per_channel
* colors_per_channel
* colors_per_channel
;
231 if (colors_per_channel
< 2 || ncolors
> (1 << screen_depth
)) {
233 "ImageControl::ImageControl: invalid colormap size %d "
234 "(%d/%d/%d) - reducing",
235 ncolors
, colors_per_channel
, colors_per_channel
,
238 colors_per_channel
= (1 << screen_depth
) / 3;
241 colors
= new XColor
[ncolors
];
244 "ImageControl::ImageControl: error allocating colormap\n");
248 int i
= 0, ii
, p
, bits
= 255 / (colors_per_channel
- 1);
249 red_bits
= green_bits
= blue_bits
= bits
;
251 for (i
= 0; i
< 256; i
++)
252 red_color_table
[i
] = green_color_table
[i
] = blue_color_table
[i
] =
255 for (i
= 0; i
< ncolors
; i
++) {
256 colors
[i
].red
= (i
* 0xffff) / (colors_per_channel
- 1);
257 colors
[i
].green
= (i
* 0xffff) / (colors_per_channel
- 1);
258 colors
[i
].blue
= (i
* 0xffff) / (colors_per_channel
- 1);;
259 colors
[i
].flags
= DoRed
|DoGreen
|DoBlue
;
261 if (! XAllocColor(**display
, colormap
,
263 fprintf(stderr
, "couldn't alloc color %i %i %i\n",
264 colors
[i
].red
, colors
[i
].green
, colors
[i
].blue
);
267 colors
[i
].flags
= DoRed
|DoGreen
|DoBlue
;
272 int incolors
= (((1 << screen_depth
) > 256) ? 256 :
273 (1 << screen_depth
));
275 for (i
= 0; i
< incolors
; i
++)
276 icolors
[i
].pixel
= i
;
278 XQueryColors(**display
, colormap
, icolors
, incolors
);
279 for (i
= 0; i
< ncolors
; i
++) {
280 if (! colors
[i
].flags
) {
281 unsigned long chk
= 0xffffffff, pixel
, close
= 0;
285 for (ii
= 0; ii
< incolors
; ii
++) {
286 int r
= (colors
[i
].red
- icolors
[i
].red
) >> 8;
287 int g
= (colors
[i
].green
- icolors
[i
].green
) >> 8;
288 int b
= (colors
[i
].blue
- icolors
[i
].blue
) >> 8;
289 pixel
= (r
* r
) + (g
* g
) + (b
* b
);
296 colors
[i
].red
= icolors
[close
].red
;
297 colors
[i
].green
= icolors
[close
].green
;
298 colors
[i
].blue
= icolors
[close
].blue
;
300 if (XAllocColor(**display
, colormap
,
302 colors
[i
].flags
= DoRed
|DoGreen
|DoBlue
;
314 fprintf(stderr
, "ImageControl::ImageControl: unsupported visual %d\n",
315 getVisual()->c_class
);
321 ImageControl::~ImageControl(void) {
322 delete [] sqrt_table
;
324 delete [] grad_xbuffer
;
326 delete [] grad_ybuffer
;
329 unsigned long *pixels
= new unsigned long [ncolors
];
331 for (int i
= 0; i
< ncolors
; i
++)
332 *(pixels
+ i
) = (*(colors
+ i
)).pixel
;
334 XFreeColors(**display
, colormap
, pixels
, ncolors
, 0);
339 if (! cache
.empty()) {
341 fprintf(stderr
, "ImageContol::~ImageControl: pixmap cache - "
342 "releasing %d pixmaps\n", cache
.size());
344 CacheContainer::iterator it
= cache
.begin();
345 const CacheContainer::iterator end
= cache
.end();
346 for (; it
!= end
; ++it
)
347 XFreePixmap(**display
, it
->pixmap
);
354 Pixmap
ImageControl::searchCache(const unsigned int width
,
355 const unsigned int height
,
356 const unsigned long texture
,
357 const Color
&c1
, const Color
&c2
) {
361 CacheContainer::iterator it
= cache
.begin();
362 const CacheContainer::iterator end
= cache
.end();
363 for (; it
!= end
; ++it
) {
364 CachedImage
& tmp
= *it
;
365 if (tmp
.width
== width
&& tmp
.height
== height
&&
366 tmp
.texture
== texture
&& tmp
.pixel1
== c1
.pixel())
367 if (texture
& Texture::Gradient
) {
368 if (tmp
.pixel2
== c2
.pixel()) {
381 Pixmap
ImageControl::renderImage(unsigned int width
, unsigned int height
,
382 const Texture
&texture
) {
383 if (texture
.texture() & Texture::Parent_Relative
) return ParentRelative
;
385 Pixmap pixmap
= searchCache(width
, height
, texture
.texture(),
386 texture
.color(), texture
.colorTo());
387 if (pixmap
) return pixmap
;
389 Image
image(this, width
, height
);
390 pixmap
= image
.render(texture
);
401 tmp
.texture
= texture
.texture();
402 tmp
.pixel1
= texture
.color().pixel();
404 if (texture
.texture() & Texture::Gradient
)
405 tmp
.pixel2
= texture
.colorTo().pixel();
409 cache
.push_back(tmp
);
411 if (cache
.size() > cache_max
) {
413 fprintf(stderr
, "ImageControl::renderImage: cache is large, "
414 "forcing cleanout\n");
424 void ImageControl::removeImage(Pixmap pixmap
) {
428 CacheContainer::iterator it
= cache
.begin();
429 const CacheContainer::iterator end
= cache
.end();
430 for (; it
!= end
; ++it
) {
431 CachedImage
&tmp
= *it
;
432 if (tmp
.pixmap
== pixmap
&& tmp
.count
> 0)
441 void ImageControl::getColorTables(unsigned char **rmt
, unsigned char **gmt
,
443 int *roff
, int *goff
, int *boff
,
444 int *rbit
, int *gbit
, int *bbit
) {
445 if (rmt
) *rmt
= red_color_table
;
446 if (gmt
) *gmt
= green_color_table
;
447 if (bmt
) *bmt
= blue_color_table
;
449 if (roff
) *roff
= red_offset
;
450 if (goff
) *goff
= green_offset
;
451 if (boff
) *boff
= blue_offset
;
453 if (rbit
) *rbit
= red_bits
;
454 if (gbit
) *gbit
= green_bits
;
455 if (bbit
) *bbit
= blue_bits
;
459 void ImageControl::getXColorTable(XColor
**c
, int *n
) {
465 void ImageControl::getGradientBuffers(unsigned int w
,
470 if (w
> grad_buffer_width
) {
472 delete [] grad_xbuffer
;
474 grad_buffer_width
= w
;
476 grad_xbuffer
= new unsigned int[grad_buffer_width
* 3];
479 if (h
> grad_buffer_height
) {
481 delete [] grad_ybuffer
;
483 grad_buffer_height
= h
;
485 grad_ybuffer
= new unsigned int[grad_buffer_height
* 3];
488 *xbuf
= grad_xbuffer
;
489 *ybuf
= grad_ybuffer
;
493 void ImageControl::installRootColormap(void) {
496 XListInstalledColormaps(**display
, window
, &ncmap
);
500 for (int i
= 0; i
< ncmap
; i
++)
501 if (*(cmaps
+ i
) == colormap
)
505 XInstallColormap(**display
, colormap
);
512 void ImageControl::setColorsPerChannel(int cpc
) {
513 if (cpc
< 2) cpc
= 2;
514 if (cpc
> 6) cpc
= 6;
516 colors_per_channel
= cpc
;
520 unsigned long ImageControl::getSqrt(unsigned int x
) {
522 // build sqrt table for use with elliptic gradient
524 sqrt_table
= new unsigned long[(256 * 256 * 2) + 1];
526 for (int i
= 0; i
< (256 * 256 * 2); i
++)
527 *(sqrt_table
+ i
) = bsqrt(i
);
530 return (*(sqrt_table
+ x
));
534 struct ZeroRefCheck
{
535 inline bool operator()(const ImageControl::CachedImage
&image
) const {
536 return (image
.count
== 0);
540 struct CacheCleaner
{
541 ZeroRefCheck ref_check
;
543 inline void operator()(const ImageControl::CachedImage
& image
) const {
544 if (ref_check(image
))
545 XFreePixmap(**display
, image
.pixmap
);
550 void ImageControl::timeout(ImageControl
*t
) {
551 CacheCleaner cleaner
;
552 std::for_each(t
->cache
.begin(), t
->cache
.end(), cleaner
);
553 t
->cache
.remove_if(cleaner
.ref_check
);
This page took 0.057656 seconds and 4 git commands to generate.