]>
Dogcows Code - chaz/openbox/blob - imagecontrol.cc
348e2343781cf8fbb87498f0448d14d7f5cc8e66
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(TimerQueueManager
*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 Timer(timermanager
, (TimeoutHandler
)timeout
, this);
58 timer
->setTimeout(cache_timeout
);
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
->depth();
73 window
= screeninfo
->rootWindow();
74 screen_number
= screeninfo
->screen();
75 colormap
= screeninfo
->colormap();
78 XPixmapFormatValues
*pmv
= XListPixmapFormats(**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 "ImageControl::ImageControl: 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
, "ImageControl::ImageControl: 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(**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(**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(**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 "ImageControl::ImageControl: 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 "ImageControl::ImageControl: 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(**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(**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(**display
, colormap
,
306 colors
[i
].flags
= DoRed
|DoGreen
|DoBlue
;
318 fprintf(stderr
, "ImageControl::ImageControl: unsupported visual %d\n",
319 getVisual()->c_class
);
325 ImageControl::~ImageControl(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(**display
, colormap
, pixels
, ncolors
, 0);
343 if (! cache
.empty()) {
345 fprintf(stderr
, "ImageContol::~ImageControl: 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(**display
, it
->pixmap
);
360 Pixmap
ImageControl::searchCache(const unsigned int width
,
361 const unsigned int height
,
362 const unsigned long texture
,
363 const Color
&c1
, const Color
&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
& Texture::Gradient
) {
374 if (tmp
.pixel2
== c2
.pixel()) {
387 Pixmap
ImageControl::renderImage(unsigned int width
, unsigned int height
,
388 const Texture
&texture
) {
389 if (texture
.texture() & Texture::Parent_Relative
) return ParentRelative
;
391 Pixmap pixmap
= searchCache(width
, height
, texture
.texture(),
392 texture
.color(), texture
.colorTo());
393 if (pixmap
) return pixmap
;
395 Image
image(this, width
, height
);
396 pixmap
= image
.render(texture
);
407 tmp
.texture
= texture
.texture();
408 tmp
.pixel1
= texture
.color().pixel();
410 if (texture
.texture() & Texture::Gradient
)
411 tmp
.pixel2
= texture
.colorTo().pixel();
415 cache
.push_back(tmp
);
417 if (cache
.size() > cache_max
) {
419 fprintf(stderr
, "ImageControl::renderImage: cache is large, "
420 "forcing cleanout\n");
430 void ImageControl::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 ImageControl::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 ImageControl::getXColorTable(XColor
**c
, int *n
) {
471 void ImageControl::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 ImageControl::installRootColormap(void) {
502 XListInstalledColormaps(**display
, window
, &ncmap
);
506 for (int i
= 0; i
< ncmap
; i
++)
507 if (*(cmaps
+ i
) == colormap
)
511 XInstallColormap(**display
, colormap
);
518 void ImageControl::setColorsPerChannel(int cpc
) {
519 if (cpc
< 2) cpc
= 2;
520 if (cpc
> 6) cpc
= 6;
522 colors_per_channel
= cpc
;
526 unsigned long ImageControl::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 ImageControl::CachedImage
&image
) const {
542 return (image
.count
== 0);
546 struct CacheCleaner
{
547 ZeroRefCheck ref_check
;
549 inline void operator()(const ImageControl::CachedImage
& image
) const {
550 if (ref_check(image
))
551 XFreePixmap(**display
, image
.pixmap
);
556 void ImageControl::timeout(ImageControl
*t
) {
557 CacheCleaner cleaner
;
558 std::for_each(t
->cache
.begin(), t
->cache
.end(), cleaner
);
559 t
->cache
.remove_if(cleaner
.ref_check
);
This page took 0.053399 seconds and 3 git commands to generate.