1 // -*- mode: C; indent-tabs-mode: nil; c-basic-offset: 2; -*-
4 #include "imagecontrol.h"
6 #include "screeninfo.h"
9 typedef struct CachedImage
{
12 unsigned int count
, width
, height
;
13 unsigned long pixel1
, pixel2
, texture
;
16 static void timeout(OtkImageControl
*self
);
17 static void initColors(OtkImageControl
*self
, Visual
*visual
);
19 PyObject
*OtkImageControl_New(int screen
)
21 OtkImageControl
*self
;
23 XPixmapFormatValues
*pmv
;
25 self
= PyObject_New(OtkImageControl
, &OtkImageControl_Type
);
27 self
->screen
= OtkDisplay_ScreenInfo(OBDisplay
, screen
);
29 self
->timer
= (OtkTimer
*)OtkTimer_New((OtkTimeoutHandler
)timeout
, self
);
30 self
->timer
->timeout
= 300000;
31 OtkTimer_Start(self
->timer
);
32 self
->cache_max
= 200;
34 self
->dither
= True
; // default value
35 self
->cpc
= 4; // default value
37 // get the BPP from the X server
39 if ((pmv
= XListPixmapFormats(OBDisplay
->display
, &count
))) {
40 for (i
= 0; i
< count
; i
++)
41 if (pmv
[i
].depth
== self
->screen
->depth
) {
42 self
->bpp
= pmv
[i
].bits_per_pixel
;
47 if (!self
->bpp
) self
->bpp
= self
->screen
->depth
;
48 if (self
->bpp
>= 24) self
->dither
= False
; // don't need dither at >= 24 bpp
50 self
->grad_xbuffer
= self
->grad_ybuffer
= NULL
;
51 self
->grad_buffer_width
= self
->grad_buffer_height
= 0;
52 self
->sqrt_table
= NULL
;
54 initColors(self
, self
->screen
->visual
);
56 return (PyObject
*)self
;
59 static void initColors(OtkImageControl
*self
, Visual
*visual
)
61 // these are not used for !TrueColor
62 self
->red_offset
= self
->green_offset
= self
->blue_offset
= 0;
63 // these are not used for TrueColor
67 // figure out all our color settings based on the visual type
68 switch (visual
->class) {
71 unsigned long red_mask
, green_mask
, blue_mask
;
73 // find the offsets for each color in the visual's masks
74 red_mask
= visual
->red_mask
;
75 green_mask
= visual
->green_mask
;
76 blue_mask
= visual
->blue_mask
;
78 while (! (red_mask
& 1)) { self
->red_offset
++; red_mask
>>= 1; }
79 while (! (green_mask
& 1)) { self
->green_offset
++; green_mask
>>= 1; }
80 while (! (blue_mask
& 1)) { self
->blue_offset
++; blue_mask
>>= 1; }
82 // use the mask to determine the number of bits for each shade of color
83 // so, best case, red_mask == 0xff (255), and so each bit is a different
85 self
->red_bits
= 255 / red_mask
;
86 self
->green_bits
= 255 / green_mask
;
87 self
->blue_bits
= 255 / blue_mask
;
89 // compute color tables, based on the number of bits for each shade
90 for (i
= 0; i
< 256; i
++) {
91 self
->red_color_table
[i
] = i
/ self
->red_bits
;
92 self
->green_color_table
[i
] = i
/ self
->green_bits
;
93 self
->blue_color_table
[i
] = i
/ self
->blue_bits
;
100 ncolors = self->cpc * self->cpc * self->cpc; // cpc ^ 3
102 if (ncolors > (1 << self->screen->depth)) {
103 self->cpc = (1 << self->screen->depth) / 3;
104 ncolors = self->cpc * self->cpc * self->cpc; // cpc ^ 3
107 if (self->cpc < 2 || self->ncolors > (1 << self->screen->depth)) {
109 "OtkImageControl_New: invalid colormap size %d "
110 "(%d/%d/%d) - reducing",
111 self->ncolors, self->cpc, self->cpc, self->cpc);
113 self->cpc = (1 << self->screen->depth) / 3;
116 self->colors = malloc(sizeof(XColor) * self->ncolors);
117 if (! self->colors) {
118 fprintf(stderr, "OtkImageControl_New: error allocating colormap\n");
122 int i = 0, ii, p, r, g, b,
123 bits = 255 / (colors_per_channel - 1);
125 red_bits = green_bits = blue_bits = bits;
127 for (i = 0; i < 256; i++)
128 red_color_table[i] = green_color_table[i] = blue_color_table[i] =
131 for (r = 0, i = 0; r < colors_per_channel; r++)
132 for (g = 0; g < colors_per_channel; g++)
133 for (b = 0; b < colors_per_channel; b++, i++) {
134 colors[i].red = (r * 0xffff) / (colors_per_channel - 1);
135 colors[i].green = (g * 0xffff) / (colors_per_channel - 1);
136 colors[i].blue = (b * 0xffff) / (colors_per_channel - 1);;
137 colors[i].flags = DoRed|DoGreen|DoBlue;
140 for (i = 0; i < ncolors; i++) {
141 if (! XAllocColor(OBDisplay::display, colormap, &colors[i])) {
142 fprintf(stderr, "couldn't alloc color %i %i %i\n",
143 colors[i].red, colors[i].green, colors[i].blue);
146 colors[i].flags = DoRed|DoGreen|DoBlue;
151 int incolors = (((1 << screen_depth) > 256) ? 256 : (1 << screen_depth));
153 for (i = 0; i < incolors; i++)
154 icolors[i].pixel = i;
156 XQueryColors(OBDisplay::display, colormap, icolors, incolors);
157 for (i = 0; i < ncolors; i++) {
158 if (! colors[i].flags) {
159 unsigned long chk = 0xffffffff, pixel, close = 0;
163 for (ii = 0; ii < incolors; ii++) {
164 r = (colors[i].red - icolors[i].red) >> 8;
165 g = (colors[i].green - icolors[i].green) >> 8;
166 b = (colors[i].blue - icolors[i].blue) >> 8;
167 pixel = (r * r) + (g * g) + (b * b);
174 colors[i].red = icolors[close].red;
175 colors[i].green = icolors[close].green;
176 colors[i].blue = icolors[close].blue;
178 if (XAllocColor(OBDisplay::display, colormap,
180 colors[i].flags = DoRed|DoGreen|DoBlue;
193 if (visual->c_class == StaticGray) {
194 ncolors = 1 << screen_depth;
196 ncolors = colors_per_channel * colors_per_channel * colors_per_channel;
198 if (ncolors > (1 << screen_depth)) {
199 colors_per_channel = (1 << screen_depth) / 3;
201 colors_per_channel * colors_per_channel * colors_per_channel;
205 if (colors_per_channel < 2 || ncolors > (1 << screen_depth)) {
207 "BImageControl::BImageControl: invalid colormap size %d "
208 "(%d/%d/%d) - reducing",
209 ncolors, colors_per_channel, colors_per_channel,
212 colors_per_channel = (1 << screen_depth) / 3;
215 colors = new XColor[ncolors];
218 "BImageControl::BImageControl: error allocating colormap\n");
222 int i = 0, ii, p, bits = 255 / (colors_per_channel - 1);
223 red_bits = green_bits = blue_bits = bits;
225 for (i = 0; i < 256; i++)
226 red_color_table[i] = green_color_table[i] = blue_color_table[i] =
229 for (i = 0; i < ncolors; i++) {
230 colors[i].red = (i * 0xffff) / (colors_per_channel - 1);
231 colors[i].green = (i * 0xffff) / (colors_per_channel - 1);
232 colors[i].blue = (i * 0xffff) / (colors_per_channel - 1);;
233 colors[i].flags = DoRed|DoGreen|DoBlue;
235 if (! XAllocColor(OBDisplay::display, colormap,
237 fprintf(stderr, "couldn't alloc color %i %i %i\n",
238 colors[i].red, colors[i].green, colors[i].blue);
241 colors[i].flags = DoRed|DoGreen|DoBlue;
246 int incolors = (((1 << screen_depth) > 256) ? 256 :
247 (1 << screen_depth));
249 for (i = 0; i < incolors; i++)
250 icolors[i].pixel = i;
252 XQueryColors(OBDisplay::display, colormap, icolors, incolors);
253 for (i = 0; i < ncolors; i++) {
254 if (! colors[i].flags) {
255 unsigned long chk = 0xffffffff, pixel, close = 0;
259 for (ii = 0; ii < incolors; ii++) {
260 int r = (colors[i].red - icolors[i].red) >> 8;
261 int g = (colors[i].green - icolors[i].green) >> 8;
262 int b = (colors[i].blue - icolors[i].blue) >> 8;
263 pixel = (r * r) + (g * g) + (b * b);
270 colors[i].red = icolors[close].red;
271 colors[i].green = icolors[close].green;
272 colors[i].blue = icolors[close].blue;
274 if (XAllocColor(OBDisplay::display, colormap,
276 colors[i].flags = DoRed|DoGreen|DoBlue;
288 fprintf(stderr
, "OtkImageControl: unsupported visual class: %d\n",
295 static void timeout(OtkImageControl
*self
)
302 static void otkimagecontrol_dealloc(OtkImageControl
* self
)
304 Py_DECREF(self
->screen
);
305 Py_DECREF(self
->timer
);
306 PyObject_Del((PyObject
*)self
);
309 PyTypeObject OtkImageControl_Type
= {
310 PyObject_HEAD_INIT(NULL
)
313 sizeof(OtkImageControl
),
315 (destructor
)otkimagecontrol_dealloc
, /*tp_dealloc*/
322 0, /*tp_as_sequence*/