1 // -*- mode: C; indent-tabs-mode: nil; -*-
6 #include "screeninfo.h"
12 static Bool cleancache = False;
13 static PyObject *colorcache;
15 // global color allocator/deallocator
22 static void rgb_dealloc(PyObject* self)
27 static int rgb_compare(PyObject *py1, PyObject *py2)
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;
47 static PyTypeObject RGB_Type = {
48 PyObject_HEAD_INIT(NULL)
53 rgb_dealloc, /*tp_dealloc*/
57 rgb_compare, /*tp_compare*/
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;
71 return (PyObject*)self;
74 typedef struct PixelRef {
79 static PixelRef *PixelRef_New(unsigned long p) {
80 PixelRef* self = malloc(sizeof(PixelRef));
86 static void OtkColor_ParseColorName(OtkColor *self) {
89 if (!self->colorname) {
90 fprintf(stderr, "OtkColor: empty colorname, cannot parse (using black)\n");
91 OtkColor_SetRGB(self, 0, 0, 0);
94 // get rgb values from colorname
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);
108 OtkColor_SetRGB(self, xcol.red >> 8, xcol.green >> 8, xcol.blue >> 8);
111 static void OtkColor_DoCacheCleanup() {
112 unsigned long *pixels;
115 PyObject *rgb, *pixref;
118 // ### TODO - support multiple displays!
119 if (!PyDict_Size(colorcache)) {
124 pixels = malloc(sizeof(unsigned long) * PyDict_Size(colorcache));
126 for (i = 0; i < ScreenCount(OBDisplay->display); i++) {
130 while (PyDict_Next(colorcache, &ppos, &rgb, &pixref)) {
131 if (((PixelRef*)pixref)->count != 0 || ((RGB*)rgb)->screen != i)
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
141 XFreeColors(OBDisplay->display,
142 OtkDisplay_ScreenInfo(OBDisplay, i)->colormap,
150 static void OtkColor_Allocate(OtkColor *self) {
152 PyObject *rgb, *pixref;
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);
159 OtkColor_ParseColorName(self);
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);
168 self->allocated = True;
169 self->pixel = ((PixelRef*)pixref)->p;
170 ((PixelRef*)pixref)->count++;
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;
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);
186 self->pixel = xcol.pixel;
187 self->allocated = True;
189 PyDict_SetItem(colorcache, rgb, (PyObject*)PixelRef_New(self->pixel));
192 OtkColor_DoCacheCleanup();
195 static void OtkColor_Deallocate(OtkColor *self) {
196 PyObject *rgb, *pixref;
198 if (!self->allocated)
201 rgb = RGB_New(self->screen, self->red, self->green, self->blue);
202 pixref = PyDict_GetItem(colorcache, rgb);
204 if (((PixelRef*)pixref)->count >= 1)
205 ((PixelRef*)pixref)->count--;
209 OtkColor_DoCacheCleanup();
211 self->allocated = False;
215 OtkColor *OtkColor_New(int screen)
217 OtkColor *self = malloc(sizeof(OtkColor));
219 self->allocated = False;
224 self->screen = screen;
225 self->colorname = NULL;
226 self->colormap = OtkDisplay_ScreenInfo(OBDisplay, self->screen)->colormap;
231 OtkColor *OtkColor_FromRGB(int r, int g, int b, int screen)
233 OtkColor *self = malloc(sizeof(OtkColor));
235 self->allocated = False;
240 self->screen = screen;
241 self->colorname = NULL;
242 self->colormap = OtkDisplay_ScreenInfo(OBDisplay, self->screen)->colormap;
247 OtkColor *OtkColor_FromName(const char *name, int screen)
249 OtkColor *self = malloc(sizeof(OtkColor));
251 self->allocated = False;
256 self->screen = screen;
257 self->colorname = PyString_FromString(name);
258 self->colormap = OtkDisplay_ScreenInfo(OBDisplay, self->screen)->colormap;
263 void OtkColor_Destroy(OtkColor *self)
266 Py_DECREF(self->colorname);
270 void OtkColor_SetRGB(OtkColor *self, int r, int g, int b)
272 OtkColor_Deallocate(self);
278 void OtkColor_SetScreen(OtkColor *self, int screen)
280 if (screen == self->screen) {
285 Otk_Deallocate(self);
287 self->colormap = OtkDisplay_ScreenInfo(OBDisplay, self->screen)->colormap;
289 self->screen = screen;
295 Bool OtkColor_IsValid(OtkColor *self)
297 return self->red != -1 && self->blue != -1 && self->green != -1;
300 unsigned long OtkColor_Pixel(OtkColor *self)
302 if (!self->allocated)
303 OtkColor_Allocate(self);
307 void OtkColor_InitializeCache()
309 colorcache = PyDict_New();
312 void OtkColor_DestroyCache()
314 Py_DECREF(colorcache);
318 void OtkColor_CleanupColorCache()