1 // -*- mode: C; indent-tabs-mode: nil; -*-
6 #include "screeninfo.h"
12 static Bool cleancache = False;
13 static PyObject *colorcache = NULL;
15 static void otkcolor_dealloc(OtkColor* self)
17 // when this is called, the color has already been cleaned out of the cache
18 PyObject_Del((PyObject*)self);
21 static int otkcolor_compare(OtkColor *c1, OtkColor *c2)
26 p1 = c1->red << 16 | c1->green << 8 | c1->blue;
27 p2 = c2->red << 16 | c2->green << 8 | c2->blue;
38 static PyObject *otkcolor_repr(OtkColor *self)
40 return PyString_FromFormat("rgb:%x/%x/%x", self->red, self->green,
44 static long otkcolor_hash(OtkColor *self)
46 return self->screen << 24 | self->red << 16 | self->green << 8 | self->blue;
49 static PyTypeObject OtkColor_Type = {
50 PyObject_HEAD_INIT(NULL)
55 (destructor)otkcolor_dealloc, /*tp_dealloc*/
59 (cmpfunc)otkcolor_compare, /*tp_compare*/
60 (reprfunc)otkcolor_repr, /*tp_repr*/
64 (hashfunc)otkcolor_hash, /*tp_hash */
68 static void parseColorName(OtkColor *self, const char *name) {
71 // get rgb values from colorname
77 if (!XParseColor(OBDisplay->display,
78 OtkDisplay_ScreenInfo(OBDisplay, self->screen)->colormap,
80 fprintf(stderr, "OtkColor: color parse error: \"%s\"\n", name);
81 self->red = self->green = self->blue = 0;
83 self->red = xcol.red >> 8;
84 self->green = xcol.green >> 8;
85 self->blue = xcol.blue >> 8;
90 static void doCacheCleanup() {
91 unsigned long *pixels;
94 PyObject *key; // this is a color too, but i dont need to use it as such
97 // ### TODO - support multiple displays!
98 if (!PyDict_Size(colorcache)) return; // nothing to do
100 printf("Cleaning Cache...\n");
102 pixels = malloc(sizeof(unsigned long) * PyDict_Size(colorcache));
104 for (i = 0; i < ScreenCount(OBDisplay->display); i++) {
105 printf("Screen %d\n", i);
109 while (PyDict_Next(colorcache, &ppos, &key, (PyObject**)&color)) {
110 // get the screen from the hash
111 if (color->screen != i) continue; // wrong screen
113 printf("has %d refs\n", color->ob_refcnt);
115 // does someone other than the cache have a reference? (the cache gets 2)
116 if (color->ob_refcnt > 2)
119 printf("ppos: %d\n", ppos);
120 printf("Cleaning pixel: %lx Count: %d\n", color->pixel, count+1);
122 pixels[count++] = color->pixel;
123 printf("pixref references before: %d\n", color->ob_refcnt);
124 PyDict_DelItem(colorcache, key);
125 printf("pixref references after: %d\n", color->ob_refcnt);
126 --ppos; // back up one in the iteration
130 XFreeColors(OBDisplay->display,
131 OtkDisplay_ScreenInfo(OBDisplay, i)->colormap,
133 printf("Done Cleaning Cache. Cleaned %d pixels\n", count);
140 static void allocate(OtkColor *self) {
143 assert(!self->allocated);
145 printf("allocating! %d\n", cleancache);
147 // allocate color from rgb values
148 xcol.red = self->red | self->red << 8;
149 xcol.green = self->green | self->green << 8;
150 xcol.blue = self->blue | self->blue << 8;
153 if (!XAllocColor(OBDisplay->display,
154 OtkDisplay_ScreenInfo(OBDisplay, self->screen)->colormap,
156 fprintf(stderr, "OtkColor: color alloc error: rgb:%x/%x/%x\n",
157 self->red, self->green, self->blue);
161 self->pixel = xcol.pixel;
162 self->allocated = True;
168 PyObject *OtkColor_FromRGB(int r, int g, int b, int screen)
170 OtkColor *self = PyObject_New(OtkColor, &OtkColor_Type);
173 assert(screen >= 0); assert(r >= 0); assert(g >= 0); assert(b >= 0);
174 assert(r <= 0xff); assert(g <= 0xff); assert(b <= 0xff);
176 if (!colorcache) colorcache = PyDict_New();
178 self->allocated = False;
183 self->screen = screen;
185 // does this color already exist in the cache?
186 cached = PyDict_GetItem(colorcache, (PyObject*)self);
192 // add it to the cache
193 PyDict_SetItem(colorcache, (PyObject*)self, (PyObject*)self);
194 return (PyObject*)self;
197 PyObject *OtkColor_FromName(const char *name, int screen)
199 OtkColor *self = PyObject_New(OtkColor, &OtkColor_Type);
202 assert(screen >= 0); assert(name);
204 if (!colorcache) colorcache = PyDict_New();
206 self->allocated = False;
211 self->screen = screen;
213 parseColorName(self, name);
215 // does this color already exist in the cache?
216 cached = PyDict_GetItem(colorcache, (PyObject*)self);
222 // add it to the cache
223 PyDict_SetItem(colorcache, (PyObject*)self, (PyObject*)self);
224 return (PyObject*)self;
227 unsigned long OtkColor_Pixel(OtkColor *self)
229 if (!self->allocated)
234 void OtkColor_CleanupColorCache()