]>
Dogcows Code - chaz/openbox/blob - src/imagecontrol.cc
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
);
This page took 0.065999 seconds and 5 git commands to generate.