]> Dogcows Code - chaz/openbox/blob - otk_c/color.c
it compiles.. does it work?
[chaz/openbox] / otk_c / color.c
1 // -*- mode: C; indent-tabs-mode: nil; -*-
2
3 #include "../config.h"
4 #include "color.h"
5 #include "display.h"
6 #include "screeninfo.h"
7
8 #ifdef HAVE_STDLIB_H
9 # include <stdlib.h>
10 #endif
11
12 static Bool cleancache = False;
13 static PyObject *colorcache;
14
15 // global color allocator/deallocator
16 typedef struct RGB {
17 PyObject_HEAD
18 int screen;
19 int r, g, b;
20 } RGB;
21
22 static void rgb_dealloc(PyObject* self)
23 {
24 PyObject_Del(self);
25 }
26
27 static int rgb_compare(PyObject *py1, PyObject *py2)
28 {
29 long result;
30 unsigned long p1, p2;
31 RGB *r1, *r2;
32
33 r1 = (RGB*) r1;
34 r2 = (RGB*) r2;
35 p1 = (r1->screen << 24 | r1->r << 16 | r1->g << 8 | r1->b) & 0x00ffffff;
36 p2 = (r2->screen << 24 | r2->r << 16 | r2->g << 8 | r2->b) & 0x00ffffff;
37
38 if (p1 < p2)
39 result = -1;
40 else if (p1 > p2)
41 result = 1;
42 else
43 result = 0;
44 return result;
45 }
46
47 static PyTypeObject RGB_Type = {
48 PyObject_HEAD_INIT(NULL)
49 0,
50 "RGB",
51 sizeof(RGB),
52 0,
53 rgb_dealloc, /*tp_dealloc*/
54 0, /*tp_print*/
55 0, /*tp_getattr*/
56 0, /*tp_setattr*/
57 rgb_compare, /*tp_compare*/
58 0, /*tp_repr*/
59 0, /*tp_as_number*/
60 0, /*tp_as_sequence*/
61 0, /*tp_as_mapping*/
62 0, /*tp_hash */
63 };
64
65 static PyObject *RGB_New(int screen, int r, int g, int b) {
66 RGB *self = (RGB*) PyObject_New(RGB, &RGB_Type);
67 self->screen = screen;
68 self->r = r;
69 self->g = g;
70 self->b = b;
71 return (PyObject*)self;
72 }
73
74 typedef struct PixelRef {
75 unsigned long p;
76 unsigned int count;
77 } PixelRef;
78
79 static PixelRef *PixelRef_New(unsigned long p) {
80 PixelRef* self = malloc(sizeof(PixelRef));
81 self->p = p;
82 self->count = 1;
83 return self;
84 }
85
86 static void OtkColor_ParseColorName(OtkColor *self) {
87 XColor xcol;
88
89 if (!self->colorname) {
90 fprintf(stderr, "OtkColor: empty colorname, cannot parse (using black)\n");
91 OtkColor_SetRGB(self, 0, 0, 0);
92 }
93
94 // get rgb values from colorname
95 xcol.red = 0;
96 xcol.green = 0;
97 xcol.blue = 0;
98 xcol.pixel = 0;
99
100 if (!XParseColor(OBDisplay->display, self->colormap,
101 PyString_AsString(self->colorname), &xcol)) {
102 fprintf(stderr, "BColor::allocate: color parse error: \"%s\"\n",
103 PyString_AsString(self->colorname));
104 OtkColor_SetRGB(self, 0, 0, 0);
105 return;
106 }
107
108 OtkColor_SetRGB(self, xcol.red >> 8, xcol.green >> 8, xcol.blue >> 8);
109 }
110
111 static void OtkColor_DoCacheCleanup() {
112 unsigned long *pixels;
113 int i;
114 unsigned int count;
115 PyObject *rgb, *pixref;
116 int ppos;
117
118 // ### TODO - support multiple displays!
119 if (!PyDict_Size(colorcache)) {
120 // nothing to do
121 return;
122 }
123
124 pixels = malloc(sizeof(unsigned long) * PyDict_Size(colorcache));
125
126 for (i = 0; i < ScreenCount(OBDisplay->display); i++) {
127 count = 0;
128 ppos = 0;
129
130 while (PyDict_Next(colorcache, &ppos, &rgb, &pixref)) {
131 if (((PixelRef*)pixref)->count != 0 || ((RGB*)rgb)->screen != i)
132 continue;
133
134 pixels[count++] = ((PixelRef*)pixref)->p;
135 PyDict_DelItem(colorcache, rgb);
136 free(pixref); // not really a PyObject, it just pretends
137 --ppos; // back up one in the iteration
138 }
139
140 if (count > 0)
141 XFreeColors(OBDisplay->display,
142 OtkDisplay_ScreenInfo(OBDisplay, i)->colormap,
143 pixels, count, 0);
144 }
145
146 free(pixels);
147 cleancache = False;
148 }
149
150 static void OtkColor_Allocate(OtkColor *self) {
151 XColor xcol;
152 PyObject *rgb, *pixref;
153
154 if (!OtkColor_IsValid(self)) {
155 if (!self->colorname) {
156 fprintf(stderr, "BColor: cannot allocate invalid color (using black)\n");
157 OtkColor_SetRGB(self, 0, 0, 0);
158 } else {
159 OtkColor_ParseColorName(self);
160 }
161 }
162
163 // see if we have allocated this color before
164 rgb = RGB_New(self->screen, self->red, self->green, self->blue);
165 pixref = PyDict_GetItem((PyObject*)colorcache, rgb);
166 if (pixref) {
167 // found
168 self->allocated = True;
169 self->pixel = ((PixelRef*)pixref)->p;
170 ((PixelRef*)pixref)->count++;
171 return;
172 }
173
174 // allocate color from rgb values
175 xcol.red = self->red | self->red << 8;
176 xcol.green = self->green | self->green << 8;
177 xcol.blue = self->blue | self->blue << 8;
178 xcol.pixel = 0;
179
180 if (!XAllocColor(OBDisplay->display, self->colormap, &xcol)) {
181 fprintf(stderr, "BColor::allocate: color alloc error: rgb:%x/%x/%x\n",
182 self->red, self->green, self->blue);
183 xcol.pixel = 0;
184 }
185
186 self->pixel = xcol.pixel;
187 self->allocated = True;
188
189 PyDict_SetItem(colorcache, rgb, (PyObject*)PixelRef_New(self->pixel));
190
191 if (cleancache)
192 OtkColor_DoCacheCleanup();
193 }
194
195 static void OtkColor_Deallocate(OtkColor *self) {
196 PyObject *rgb, *pixref;
197
198 if (!self->allocated)
199 return;
200
201 rgb = RGB_New(self->screen, self->red, self->green, self->blue);
202 pixref = PyDict_GetItem(colorcache, rgb);
203 if (pixref) {
204 if (((PixelRef*)pixref)->count >= 1)
205 ((PixelRef*)pixref)->count--;
206 }
207
208 if (cleancache)
209 OtkColor_DoCacheCleanup();
210
211 self->allocated = False;
212 }
213
214
215 OtkColor *OtkColor_New(int screen)
216 {
217 OtkColor *self = malloc(sizeof(OtkColor));
218
219 self->allocated = False;
220 self->red = -1;
221 self->green = -1;
222 self->blue = -1;
223 self->pixel = 0;
224 self->screen = screen;
225 self->colorname = NULL;
226 self->colormap = OtkDisplay_ScreenInfo(OBDisplay, self->screen)->colormap;
227
228 return self;
229 }
230
231 OtkColor *OtkColor_FromRGB(int r, int g, int b, int screen)
232 {
233 OtkColor *self = malloc(sizeof(OtkColor));
234
235 self->allocated = False;
236 self->red = r;
237 self->green = g;
238 self->blue = b;
239 self->pixel = 0;
240 self->screen = screen;
241 self->colorname = NULL;
242 self->colormap = OtkDisplay_ScreenInfo(OBDisplay, self->screen)->colormap;
243
244 return self;
245 }
246
247 OtkColor *OtkColor_FromName(const char *name, int screen)
248 {
249 OtkColor *self = malloc(sizeof(OtkColor));
250
251 self->allocated = False;
252 self->red = -1;
253 self->green = -1;
254 self->blue = -1;
255 self->pixel = 0;
256 self->screen = screen;
257 self->colorname = PyString_FromString(name);
258 self->colormap = OtkDisplay_ScreenInfo(OBDisplay, self->screen)->colormap;
259
260 return self;
261 }
262
263 void OtkColor_Destroy(OtkColor *self)
264 {
265 if (self->colorname)
266 Py_DECREF(self->colorname);
267 free(self);
268 }
269
270 void OtkColor_SetRGB(OtkColor *self, int r, int g, int b)
271 {
272 OtkColor_Deallocate(self);
273 self->red = r;
274 self->green = g;
275 self->blue = b;
276 }
277
278 void OtkColor_SetScreen(OtkColor *self, int screen)
279 {
280 if (screen == self->screen) {
281 // nothing to do
282 return;
283 }
284
285 Otk_Deallocate(self);
286
287 self->colormap = OtkDisplay_ScreenInfo(OBDisplay, self->screen)->colormap;
288
289 self->screen = screen;
290
291 if (self->colorname)
292 parseColorName();
293 }
294
295 Bool OtkColor_IsValid(OtkColor *self)
296 {
297 return self->red != -1 && self->blue != -1 && self->green != -1;
298 }
299
300 unsigned long OtkColor_Pixel(OtkColor *self)
301 {
302 if (!self->allocated)
303 OtkColor_Allocate(self);
304 return self->pixel;
305 }
306
307 void OtkColor_InitializeCache()
308 {
309 colorcache = PyDict_New();
310 }
311
312 void OtkColor_DestroyCache()
313 {
314 Py_DECREF(colorcache);
315 colorcache = NULL;
316 }
317
318 void OtkColor_CleanupColorCache()
319 {
320 cleancache = True;
321 }
This page took 0.047017 seconds and 5 git commands to generate.