use the new non-static display
[mikachu/openbox.git] / otk_c / imagecontrol.c
1 // -*- mode: C; indent-tabs-mode: nil; c-basic-offset: 2; -*-
2
3 #include "../config.h"
4 #include "imagecontrol.h"
5 #include "timer.h"
6 #include "screeninfo.h"
7 #include "display.h"
8
9 typedef struct CachedImage {
10   Pixmap pixmap;
11   
12   unsigned int count, width, height;
13   unsigned long pixel1, pixel2, texture;
14 } CachedImage;
15
16 static void timeout(OtkImageControl *self);
17 static void initColors(OtkImageControl *self, Visual *visual);
18
19 PyObject *OtkImageControl_New(int screen)
20 {
21   OtkImageControl *self;
22   int count, i;
23   XPixmapFormatValues *pmv;
24
25   self = PyObject_New(OtkImageControl, &OtkImageControl_Type);
26
27   self->screen = OtkDisplay_ScreenInfo(OBDisplay, screen);
28
29   self->timer = (OtkTimer*)OtkTimer_New((OtkTimeoutHandler)timeout, self);
30   self->timer->timeout = 300000;
31   OtkTimer_Start(self->timer);
32   self->cache_max = 200;
33   
34   self->dither = True; // default value
35   self->cpc = 4; // default value
36
37   // get the BPP from the X server
38   self->bpp = 0;
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;
43         break;
44       }
45     XFree(pmv);
46   }
47   if (!self->bpp) self->bpp = self->screen->depth;
48   if (self->bpp >= 24) self->dither = False; // don't need dither at >= 24 bpp
49
50   self->grad_xbuffer = self->grad_ybuffer = NULL;
51   self->grad_buffer_width = self->grad_buffer_height = 0;
52   self->sqrt_table = NULL;
53
54   initColors(self, self->screen->visual);
55
56   return (PyObject*)self;
57 }
58
59 static void initColors(OtkImageControl *self, Visual *visual)
60 {
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
64   self->colors = NULL;
65   self->ncolors = 0;
66
67   // figure out all our color settings based on the visual type
68   switch (visual->class) {
69   case TrueColor: {
70     int i;
71     unsigned long red_mask, green_mask, blue_mask;
72
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;
77
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; }
81
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
84     // shade!
85     self->red_bits = 255 / red_mask;
86     self->green_bits = 255 / green_mask;
87     self->blue_bits = 255 / blue_mask;
88
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;
94     }
95     break;
96   }
97 /*
98   case PseudoColor:
99   case StaticColor: {
100     ncolors = self->cpc * self->cpc * self->cpc; // cpc ^ 3
101
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
105     }
106
107     if (self->cpc < 2 || self->ncolors > (1 << self->screen->depth)) {
108       fprintf(stderr,
109               "OtkImageControl_New: invalid colormap size %d "
110               "(%d/%d/%d) - reducing",
111               self->ncolors, self->cpc, self->cpc, self->cpc);
112
113       self->cpc = (1 << self->screen->depth) / 3;
114     }
115
116     self->colors = malloc(sizeof(XColor) * self->ncolors);
117     if (! self->colors) {
118       fprintf(stderr, "OtkImageControl_New: error allocating colormap\n");
119       exit(1);
120     }
121
122     int i = 0, ii, p, r, g, b,
123       bits = 255 / (colors_per_channel - 1);
124
125     red_bits = green_bits = blue_bits = bits;
126
127     for (i = 0; i < 256; i++)
128       red_color_table[i] = green_color_table[i] = blue_color_table[i] =
129         i / bits;
130
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;
138         }
139
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);
144         colors[i].flags = 0;
145       } else {
146         colors[i].flags = DoRed|DoGreen|DoBlue;
147       }
148     }
149
150     XColor icolors[256];
151     int incolors = (((1 << screen_depth) > 256) ? 256 : (1 << screen_depth));
152
153     for (i = 0; i < incolors; i++)
154       icolors[i].pixel = i;
155
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;
160
161         p = 2;
162         while (p--) {
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);
168
169             if (pixel < chk) {
170               chk = pixel;
171               close = ii;
172             }
173
174             colors[i].red = icolors[close].red;
175             colors[i].green = icolors[close].green;
176             colors[i].blue = icolors[close].blue;
177
178             if (XAllocColor(OBDisplay::display, colormap,
179                             &colors[i])) {
180               colors[i].flags = DoRed|DoGreen|DoBlue;
181               break;
182             }
183           }
184         }
185       }
186     }
187
188     break;
189   }
190
191   case GrayScale:
192   case StaticGray: {
193     if (visual->c_class == StaticGray) {
194       ncolors = 1 << screen_depth;
195     } else {
196       ncolors = colors_per_channel * colors_per_channel * colors_per_channel;
197
198       if (ncolors > (1 << screen_depth)) {
199         colors_per_channel = (1 << screen_depth) / 3;
200         ncolors =
201           colors_per_channel * colors_per_channel * colors_per_channel;
202       }
203     }
204
205     if (colors_per_channel < 2 || ncolors > (1 << screen_depth)) {
206       fprintf(stderr,
207               "BImageControl::BImageControl: invalid colormap size %d "
208               "(%d/%d/%d) - reducing",
209               ncolors, colors_per_channel, colors_per_channel,
210               colors_per_channel);
211
212       colors_per_channel = (1 << screen_depth) / 3;
213     }
214
215     colors = new XColor[ncolors];
216     if (! colors) {
217       fprintf(stderr,
218               "BImageControl::BImageControl: error allocating colormap\n");
219       exit(1);
220     }
221
222     int i = 0, ii, p, bits = 255 / (colors_per_channel - 1);
223     red_bits = green_bits = blue_bits = bits;
224
225     for (i = 0; i < 256; i++)
226       red_color_table[i] = green_color_table[i] = blue_color_table[i] =
227         i / bits;
228
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;
234
235       if (! XAllocColor(OBDisplay::display, colormap,
236                         &colors[i])) {
237         fprintf(stderr, "couldn't alloc color %i %i %i\n",
238                 colors[i].red, colors[i].green, colors[i].blue);
239         colors[i].flags = 0;
240       } else {
241         colors[i].flags = DoRed|DoGreen|DoBlue;
242       }
243     }
244
245     XColor icolors[256];
246     int incolors = (((1 << screen_depth) > 256) ? 256 :
247                     (1 << screen_depth));
248
249     for (i = 0; i < incolors; i++)
250       icolors[i].pixel = i;
251
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;
256
257         p = 2;
258         while (p--) {
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);
264
265             if (pixel < chk) {
266               chk = pixel;
267               close = ii;
268             }
269
270             colors[i].red = icolors[close].red;
271             colors[i].green = icolors[close].green;
272             colors[i].blue = icolors[close].blue;
273
274             if (XAllocColor(OBDisplay::display, colormap,
275                             &colors[i])) {
276               colors[i].flags = DoRed|DoGreen|DoBlue;
277               break;
278             }
279           }
280         }
281       }
282     }
283
284     break;
285   }
286 */
287   default:
288     fprintf(stderr, "OtkImageControl: unsupported visual class: %d\n",
289             visual->class);
290     exit(1);
291   }
292 }
293
294
295 static void timeout(OtkImageControl *self)
296 {
297   (void)self;
298 }
299
300
301
302 static void otkimagecontrol_dealloc(OtkImageControl* self)
303 {
304   Py_DECREF(self->screen);
305   Py_DECREF(self->timer);
306   PyObject_Del((PyObject*)self);
307 }
308
309 PyTypeObject OtkImageControl_Type = {
310   PyObject_HEAD_INIT(NULL)
311   0,
312   "OtkImageControl",
313   sizeof(OtkImageControl),
314   0,
315   (destructor)otkimagecontrol_dealloc, /*tp_dealloc*/
316   0,                            /*tp_print*/
317   0,                            /*tp_getattr*/
318   0,                            /*tp_setattr*/
319   0,                            /*tp_compare*/
320   0,                            /*tp_repr*/
321   0,                            /*tp_as_number*/
322   0,                            /*tp_as_sequence*/
323   0,                            /*tp_as_mapping*/
324   0,                            /*tp_hash */
325 };