]>
Dogcows Code - chaz/openbox/blob - src/imagecontrol.cc
1 // -*- mode: C++; indent-tabs-mode: nil; -*-
2 // ImageControl.cc for Blackbox - an X11 Window manager
3 // Copyright (c) 2001 - 2002 Sean 'Shaleh' Perry <shaleh@debian.org>
4 // Copyright (c) 1997 - 2000 Brad Hughes (bhughes@tcac.net)
6 // Permission is hereby granted, free of charge, to any person obtaining a
7 // copy of this software and associated documentation files (the "Software"),
8 // to deal in the Software without restriction, including without limitation
9 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 // and/or sell copies of the Software, and to permit persons to whom the
11 // Software is furnished to do so, subject to the following conditions:
13 // The above copyright notice and this permission notice shall be included in
14 // all copies or substantial portions of the Software.
16 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 // DEALINGS IN THE SOFTWARE.
25 # include "../config.h"
26 #endif // HAVE_CONFIG_H
31 #endif // HAVE_STDIO_H
35 #endif // HAVE_CTYPE_H
42 #include "blackbox.hh"
43 #include "basedisplay.hh"
48 static unsigned long bsqrt(unsigned long x
) {
52 unsigned long r
= x
>> 1;
62 BImageControl
*ctrl
= 0;
64 BImageControl::BImageControl(BaseDisplay
*dpy
, const ScreenInfo
*scrn
,
65 bool _dither
, int _cpc
,
66 unsigned long cache_timeout
,
68 if (! ctrl
) ctrl
= this;
73 setColorsPerChannel(_cpc
);
77 timer
= new BTimer(basedisplay
, this);
78 timer
->setTimeout(cache_timeout
);
84 colors
= (XColor
*) 0;
87 grad_xbuffer
= grad_ybuffer
= (unsigned int *) 0;
88 grad_buffer_width
= grad_buffer_height
= 0;
90 sqrt_table
= (unsigned long *) 0;
92 screen_depth
= screeninfo
->getDepth();
93 window
= screeninfo
->getRootWindow();
94 screen_number
= screeninfo
->getScreenNumber();
95 colormap
= screeninfo
->getColormap();
98 XPixmapFormatValues
*pmv
= XListPixmapFormats(basedisplay
->getXDisplay(),
102 for (int i
= 0; i
< count
; i
++)
103 if (pmv
[i
].depth
== screen_depth
) {
104 bits_per_pixel
= pmv
[i
].bits_per_pixel
;
111 if (bits_per_pixel
== 0) bits_per_pixel
= screen_depth
;
112 if (bits_per_pixel
>= 24) setDither(False
);
114 red_offset
= green_offset
= blue_offset
= 0;
116 switch (getVisual()->c_class
) {
120 // compute color tables
121 unsigned long red_mask
= getVisual()->red_mask
,
122 green_mask
= getVisual()->green_mask
,
123 blue_mask
= getVisual()->blue_mask
;
125 while (! (red_mask
& 1)) { red_offset
++; red_mask
>>= 1; }
126 while (! (green_mask
& 1)) { green_offset
++; green_mask
>>= 1; }
127 while (! (blue_mask
& 1)) { blue_offset
++; blue_mask
>>= 1; }
129 red_bits
= 255 / red_mask
;
130 green_bits
= 255 / green_mask
;
131 blue_bits
= 255 / blue_mask
;
133 for (i
= 0; i
< 256; i
++) {
134 red_color_table
[i
] = i
/ red_bits
;
135 green_color_table
[i
] = i
/ green_bits
;
136 blue_color_table
[i
] = i
/ blue_bits
;
143 ncolors
= colors_per_channel
* colors_per_channel
* colors_per_channel
;
145 if (ncolors
> (1 << screen_depth
)) {
146 colors_per_channel
= (1 << screen_depth
) / 3;
147 ncolors
= colors_per_channel
* colors_per_channel
* colors_per_channel
;
150 if (colors_per_channel
< 2 || ncolors
> (1 << screen_depth
)) {
152 "BImageControl::BImageControl: invalid colormap size %d "
153 "(%d/%d/%d) - reducing",
154 ncolors
, colors_per_channel
, colors_per_channel
,
157 colors_per_channel
= (1 << screen_depth
) / 3;
160 colors
= new XColor
[ncolors
];
162 fprintf(stderr
, "BImageControl::BImageControl: error allocating "
167 int i
= 0, ii
, p
, r
, g
, b
,
170 bits
= 256 / colors_per_channel
;
171 #else // !ORDEREDPSEUDO
172 bits
= 255 / (colors_per_channel
- 1);
173 #endif // ORDEREDPSEUDO
175 red_bits
= green_bits
= blue_bits
= bits
;
177 for (i
= 0; i
< 256; i
++)
178 red_color_table
[i
] = green_color_table
[i
] = blue_color_table
[i
] =
181 for (r
= 0, i
= 0; r
< colors_per_channel
; r
++)
182 for (g
= 0; g
< colors_per_channel
; g
++)
183 for (b
= 0; b
< colors_per_channel
; b
++, i
++) {
184 colors
[i
].red
= (r
* 0xffff) / (colors_per_channel
- 1);
185 colors
[i
].green
= (g
* 0xffff) / (colors_per_channel
- 1);
186 colors
[i
].blue
= (b
* 0xffff) / (colors_per_channel
- 1);;
187 colors
[i
].flags
= DoRed
|DoGreen
|DoBlue
;
190 for (i
= 0; i
< ncolors
; i
++) {
191 if (! XAllocColor(basedisplay
->getXDisplay(), colormap
, &colors
[i
])) {
192 fprintf(stderr
, "couldn't alloc color %i %i %i\n",
193 colors
[i
].red
, colors
[i
].green
, colors
[i
].blue
);
196 colors
[i
].flags
= DoRed
|DoGreen
|DoBlue
;
201 int incolors
= (((1 << screen_depth
) > 256) ? 256 : (1 << screen_depth
));
203 for (i
= 0; i
< incolors
; i
++)
204 icolors
[i
].pixel
= i
;
206 XQueryColors(basedisplay
->getXDisplay(), colormap
, icolors
, incolors
);
207 for (i
= 0; i
< ncolors
; i
++) {
208 if (! colors
[i
].flags
) {
209 unsigned long chk
= 0xffffffff, pixel
, close
= 0;
213 for (ii
= 0; ii
< incolors
; ii
++) {
214 r
= (colors
[i
].red
- icolors
[i
].red
) >> 8;
215 g
= (colors
[i
].green
- icolors
[i
].green
) >> 8;
216 b
= (colors
[i
].blue
- icolors
[i
].blue
) >> 8;
217 pixel
= (r
* r
) + (g
* g
) + (b
* b
);
224 colors
[i
].red
= icolors
[close
].red
;
225 colors
[i
].green
= icolors
[close
].green
;
226 colors
[i
].blue
= icolors
[close
].blue
;
228 if (XAllocColor(basedisplay
->getXDisplay(), colormap
,
230 colors
[i
].flags
= DoRed
|DoGreen
|DoBlue
;
243 if (getVisual()->c_class
== StaticGray
) {
244 ncolors
= 1 << screen_depth
;
246 ncolors
= colors_per_channel
* colors_per_channel
* colors_per_channel
;
248 if (ncolors
> (1 << screen_depth
)) {
249 colors_per_channel
= (1 << screen_depth
) / 3;
251 colors_per_channel
* colors_per_channel
* colors_per_channel
;
255 if (colors_per_channel
< 2 || ncolors
> (1 << screen_depth
)) {
257 "BImageControl::BImageControl: invalid colormap size %d "
258 "(%d/%d/%d) - reducing",
259 ncolors
, colors_per_channel
, colors_per_channel
,
262 colors_per_channel
= (1 << screen_depth
) / 3;
265 colors
= new XColor
[ncolors
];
268 "BImageControl::BImageControl: error allocating colormap\n");
272 int i
= 0, ii
, p
, bits
= 255 / (colors_per_channel
- 1);
273 red_bits
= green_bits
= blue_bits
= bits
;
275 for (i
= 0; i
< 256; i
++)
276 red_color_table
[i
] = green_color_table
[i
] = blue_color_table
[i
] =
279 for (i
= 0; i
< ncolors
; i
++) {
280 colors
[i
].red
= (i
* 0xffff) / (colors_per_channel
- 1);
281 colors
[i
].green
= (i
* 0xffff) / (colors_per_channel
- 1);
282 colors
[i
].blue
= (i
* 0xffff) / (colors_per_channel
- 1);;
283 colors
[i
].flags
= DoRed
|DoGreen
|DoBlue
;
285 if (! XAllocColor(basedisplay
->getXDisplay(), colormap
,
287 fprintf(stderr
, "couldn't alloc color %i %i %i\n",
288 colors
[i
].red
, colors
[i
].green
, colors
[i
].blue
);
291 colors
[i
].flags
= DoRed
|DoGreen
|DoBlue
;
296 int incolors
= (((1 << screen_depth
) > 256) ? 256 :
297 (1 << screen_depth
));
299 for (i
= 0; i
< incolors
; i
++)
300 icolors
[i
].pixel
= i
;
302 XQueryColors(basedisplay
->getXDisplay(), colormap
, icolors
, incolors
);
303 for (i
= 0; i
< ncolors
; i
++) {
304 if (! colors
[i
].flags
) {
305 unsigned long chk
= 0xffffffff, pixel
, close
= 0;
309 for (ii
= 0; ii
< incolors
; ii
++) {
310 int r
= (colors
[i
].red
- icolors
[i
].red
) >> 8;
311 int g
= (colors
[i
].green
- icolors
[i
].green
) >> 8;
312 int b
= (colors
[i
].blue
- icolors
[i
].blue
) >> 8;
313 pixel
= (r
* r
) + (g
* g
) + (b
* b
);
320 colors
[i
].red
= icolors
[close
].red
;
321 colors
[i
].green
= icolors
[close
].green
;
322 colors
[i
].blue
= icolors
[close
].blue
;
324 if (XAllocColor(basedisplay
->getXDisplay(), colormap
,
326 colors
[i
].flags
= DoRed
|DoGreen
|DoBlue
;
338 fprintf(stderr
, "BImageControl::BImageControl: unsupported visual %d\n",
339 getVisual()->c_class
);
345 BImageControl::~BImageControl(void) {
346 delete [] sqrt_table
;
348 delete [] grad_xbuffer
;
350 delete [] grad_ybuffer
;
353 unsigned long *pixels
= new unsigned long [ncolors
];
355 for (int i
= 0; i
< ncolors
; i
++)
356 *(pixels
+ i
) = (*(colors
+ i
)).pixel
;
358 XFreeColors(basedisplay
->getXDisplay(), colormap
, pixels
, ncolors
, 0);
363 if (! cache
.empty()) {
365 fprintf(stderr
, "BImageContol::~BImageControl: pixmap cache - "
366 "releasing %d pixmaps\n", cache
.size());
368 CacheContainer::iterator it
= cache
.begin();
369 const CacheContainer::iterator end
= cache
.end();
370 for (; it
!= end
; ++it
)
371 XFreePixmap(basedisplay
->getXDisplay(), it
->pixmap
);
380 Pixmap
BImageControl::searchCache(const unsigned int width
,
381 const unsigned int height
,
382 const unsigned long texture
,
383 const BColor
&c1
, const BColor
&c2
) {
387 CacheContainer::iterator it
= cache
.begin();
388 const CacheContainer::iterator end
= cache
.end();
389 for (; it
!= end
; ++it
) {
390 CachedImage
& tmp
= *it
;
391 if (tmp
.width
== width
&& tmp
.height
== height
&&
392 tmp
.texture
== texture
&& tmp
.pixel1
== c1
.pixel())
393 if (texture
& BTexture::Gradient
) {
394 if (tmp
.pixel2
== c2
.pixel()) {
407 Pixmap
BImageControl::renderImage(unsigned int width
, unsigned int height
,
408 const BTexture
&texture
) {
409 if (texture
.texture() & BTexture::Parent_Relative
) return ParentRelative
;
411 Pixmap pixmap
= searchCache(width
, height
, texture
.texture(),
412 texture
.color(), texture
.colorTo());
413 if (pixmap
) return pixmap
;
415 BImage
image(this, width
, height
);
416 pixmap
= image
.render(texture
);
427 tmp
.texture
= texture
.texture();
428 tmp
.pixel1
= texture
.color().pixel();
430 if (texture
.texture() & BTexture::Gradient
)
431 tmp
.pixel2
= texture
.colorTo().pixel();
435 cache
.push_back(tmp
);
437 if (cache
.size() > cache_max
) {
439 fprintf(stderr
, "BImageControl::renderImage: cache is large, "
440 "forcing cleanout\n");
450 void BImageControl::removeImage(Pixmap pixmap
) {
454 CacheContainer::iterator it
= cache
.begin();
455 const CacheContainer::iterator end
= cache
.end();
456 for (; it
!= end
; ++it
) {
457 CachedImage
&tmp
= *it
;
458 if (tmp
.pixmap
== pixmap
&& tmp
.count
> 0)
467 void BImageControl::getColorTables(unsigned char **rmt
, unsigned char **gmt
,
469 int *roff
, int *goff
, int *boff
,
470 int *rbit
, int *gbit
, int *bbit
) {
471 if (rmt
) *rmt
= red_color_table
;
472 if (gmt
) *gmt
= green_color_table
;
473 if (bmt
) *bmt
= blue_color_table
;
475 if (roff
) *roff
= red_offset
;
476 if (goff
) *goff
= green_offset
;
477 if (boff
) *boff
= blue_offset
;
479 if (rbit
) *rbit
= red_bits
;
480 if (gbit
) *gbit
= green_bits
;
481 if (bbit
) *bbit
= blue_bits
;
485 void BImageControl::getXColorTable(XColor
**c
, int *n
) {
491 void BImageControl::getGradientBuffers(unsigned int w
,
496 if (w
> grad_buffer_width
) {
498 delete [] grad_xbuffer
;
500 grad_buffer_width
= w
;
502 grad_xbuffer
= new unsigned int[grad_buffer_width
* 3];
505 if (h
> grad_buffer_height
) {
507 delete [] grad_ybuffer
;
509 grad_buffer_height
= h
;
511 grad_ybuffer
= new unsigned int[grad_buffer_height
* 3];
514 *xbuf
= grad_xbuffer
;
515 *ybuf
= grad_ybuffer
;
519 void BImageControl::installRootColormap(void) {
522 XListInstalledColormaps(basedisplay
->getXDisplay(), window
, &ncmap
);
526 for (int i
= 0; i
< ncmap
; i
++)
527 if (*(cmaps
+ i
) == colormap
)
531 XInstallColormap(basedisplay
->getXDisplay(), colormap
);
538 void BImageControl::setColorsPerChannel(int cpc
) {
539 if (cpc
< 2) cpc
= 2;
540 if (cpc
> 6) cpc
= 6;
542 colors_per_channel
= cpc
;
546 unsigned long BImageControl::getSqrt(unsigned int x
) {
548 // build sqrt table for use with elliptic gradient
550 sqrt_table
= new unsigned long[(256 * 256 * 2) + 1];
552 for (int i
= 0; i
< (256 * 256 * 2); i
++)
553 *(sqrt_table
+ i
) = bsqrt(i
);
556 return (*(sqrt_table
+ x
));
560 struct ZeroRefCheck
{
561 inline bool operator()(const BImageControl::CachedImage
&image
) const {
562 return (image
.count
== 0);
566 struct CacheCleaner
{
568 ZeroRefCheck ref_check
;
569 CacheCleaner(Display
*d
): display(d
) {}
570 inline void operator()(const BImageControl::CachedImage
& image
) const {
571 if (ref_check(image
))
572 XFreePixmap(display
, image
.pixmap
);
577 void BImageControl::timeout(void) {
578 CacheCleaner
cleaner(basedisplay
->getXDisplay());
579 std::for_each(cache
.begin(), cache
.end(), cleaner
);
580 cache
.remove_if(cleaner
.ref_check
);
This page took 0.062695 seconds and 5 git commands to generate.