X-Git-Url: https://git.brokenzipper.com/gitweb?a=blobdiff_plain;f=otk_c%2Fcolor.c;h=81f5b76a6b2a3fd3d069d580ea0cab710d5ec92c;hb=6ca5c5891a58c616b32b733c99fe373aa58bc360;hp=9f71821799761868e0b9aa9d1d21c0d94bf77606;hpb=59b65db2cac9f359dfcff3ab988e70eab053bdb4;p=chaz%2Fopenbox diff --git a/otk_c/color.c b/otk_c/color.c index 9f718217..81f5b76a 100644 --- a/otk_c/color.c +++ b/otk_c/color.c @@ -1,4 +1,4 @@ -// -*- mode: C; indent-tabs-mode: nil; -*- +// -*- mode: C; indent-tabs-mode: nil; c-basic-offset: 2; -*- #include "../config.h" #include "color.h" @@ -10,116 +10,38 @@ #endif static Bool cleancache = False; -static PyObject *colorcache; +static PyObject *colorcache = NULL; -// global color allocator/deallocator -typedef struct RGB { - PyObject_HEAD - int screen; - int r, g, b; -} RGB; - -static void rgb_dealloc(PyObject* self) -{ - PyObject_Del(self); -} - -static int rgb_compare(PyObject *py1, PyObject *py2) -{ - long result; - unsigned long p1, p2; - RGB *r1, *r2; - - r1 = (RGB*) r1; - r2 = (RGB*) r2; - p1 = (r1->screen << 24 | r1->r << 16 | r1->g << 8 | r1->b) & 0x00ffffff; - p2 = (r2->screen << 24 | r2->r << 16 | r2->g << 8 | r2->b) & 0x00ffffff; - - if (p1 < p2) - result = -1; - else if (p1 > p2) - result = 1; - else - result = 0; - return result; -} - -static PyTypeObject RGB_Type = { - PyObject_HEAD_INIT(NULL) - 0, - "RGB", - sizeof(RGB), - 0, - rgb_dealloc, /*tp_dealloc*/ - 0, /*tp_print*/ - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - rgb_compare, /*tp_compare*/ - 0, /*tp_repr*/ - 0, /*tp_as_number*/ - 0, /*tp_as_sequence*/ - 0, /*tp_as_mapping*/ - 0, /*tp_hash */ -}; - -static PyObject *RGB_New(int screen, int r, int g, int b) { - RGB *self = (RGB*) PyObject_New(RGB, &RGB_Type); - self->screen = screen; - self->r = r; - self->g = g; - self->b = b; - return (PyObject*)self; -} - -typedef struct PixelRef { - unsigned long p; - unsigned int count; -} PixelRef; - -static PixelRef *PixelRef_New(unsigned long p) { - PixelRef* self = malloc(sizeof(PixelRef)); - self->p = p; - self->count = 1; - return self; -} - -static void OtkColor_ParseColorName(OtkColor *self) { +static void parseColorName(OtkColor *self, const char *name) { XColor xcol; - if (!self->colorname) { - fprintf(stderr, "OtkColor: empty colorname, cannot parse (using black)\n"); - OtkColor_SetRGB(self, 0, 0, 0); - } - // get rgb values from colorname xcol.red = 0; xcol.green = 0; xcol.blue = 0; xcol.pixel = 0; - if (!XParseColor(OBDisplay->display, self->colormap, - PyString_AsString(self->colorname), &xcol)) { - fprintf(stderr, "BColor::allocate: color parse error: \"%s\"\n", - PyString_AsString(self->colorname)); - OtkColor_SetRGB(self, 0, 0, 0); - return; + if (!XParseColor(OBDisplay->display, + OtkDisplay_ScreenInfo(OBDisplay, self->screen)->colormap, + name, &xcol)) { + fprintf(stderr, "OtkColor: color parse error: \"%s\"\n", name); + self->red = self->green = self->blue = 0; + } else { + self->red = xcol.red >> 8; + self->green = xcol.green >> 8; + self->blue = xcol.blue >> 8; } - - OtkColor_SetRGB(self, xcol.red >> 8, xcol.green >> 8, xcol.blue >> 8); } -static void OtkColor_DoCacheCleanup() { +static void doCacheCleanup() { unsigned long *pixels; - int i; + int i, ppos; unsigned int count; - PyObject *rgb, *pixref; - int ppos; + PyObject *key; // this is a color too, but i dont need to use it as such + OtkColor *color; // ### TODO - support multiple displays! - if (!PyDict_Size(colorcache)) { - // nothing to do - return; - } + if (!PyDict_Size(colorcache)) return; // nothing to do pixels = malloc(sizeof(unsigned long) * PyDict_Size(colorcache)); @@ -127,19 +49,22 @@ static void OtkColor_DoCacheCleanup() { count = 0; ppos = 0; - while (PyDict_Next(colorcache, &ppos, &rgb, &pixref)) { - if (((PixelRef*)pixref)->count != 0 || ((RGB*)rgb)->screen != i) + while (PyDict_Next(colorcache, &ppos, &key, (PyObject**)&color)) { + // get the screen from the hash + if (color->screen != i) continue; // wrong screen + + // does someone other than the cache have a reference? (the cache gets 2) + if (color->ob_refcnt > 2) continue; - pixels[count++] = ((PixelRef*)pixref)->p; - PyDict_DelItem(colorcache, rgb); - free(pixref); // not really a PyObject, it just pretends + pixels[count++] = color->pixel; + PyDict_DelItem(colorcache, key); --ppos; // back up one in the iteration } if (count > 0) XFreeColors(OBDisplay->display, - OtkDisplay_ScreenInfo(OBDisplay, i)->colormap, + OtkDisplay_ScreenInfo(OBDisplay, i)->colormap, pixels, count, 0); } @@ -147,175 +72,141 @@ static void OtkColor_DoCacheCleanup() { cleancache = False; } -static void OtkColor_Allocate(OtkColor *self) { +static void allocate(OtkColor *self) { XColor xcol; - PyObject *rgb, *pixref; - - if (!OtkColor_IsValid(self)) { - if (!self->colorname) { - fprintf(stderr, "BColor: cannot allocate invalid color (using black)\n"); - OtkColor_SetRGB(self, 0, 0, 0); - } else { - OtkColor_ParseColorName(self); - } - } - - // see if we have allocated this color before - rgb = RGB_New(self->screen, self->red, self->green, self->blue); - pixref = PyDict_GetItem((PyObject*)colorcache, rgb); - if (pixref) { - // found - self->allocated = True; - self->pixel = ((PixelRef*)pixref)->p; - ((PixelRef*)pixref)->count++; - return; - } // allocate color from rgb values xcol.red = self->red | self->red << 8; xcol.green = self->green | self->green << 8; xcol.blue = self->blue | self->blue << 8; xcol.pixel = 0; - - if (!XAllocColor(OBDisplay->display, self->colormap, &xcol)) { - fprintf(stderr, "BColor::allocate: color alloc error: rgb:%x/%x/%x\n", + + if (!XAllocColor(OBDisplay->display, + OtkDisplay_ScreenInfo(OBDisplay, self->screen)->colormap, + &xcol)) { + fprintf(stderr, "OtkColor: color alloc error: rgb:%x/%x/%x\n", self->red, self->green, self->blue); xcol.pixel = 0; } - + self->pixel = xcol.pixel; - self->allocated = True; - - PyDict_SetItem(colorcache, rgb, (PyObject*)PixelRef_New(self->pixel)); - - if (cleancache) - OtkColor_DoCacheCleanup(); -} - -static void OtkColor_Deallocate(OtkColor *self) { - PyObject *rgb, *pixref; - - if (!self->allocated) - return; - - rgb = RGB_New(self->screen, self->red, self->green, self->blue); - pixref = PyDict_GetItem(colorcache, rgb); - if (pixref) { - if (((PixelRef*)pixref)->count >= 1) - ((PixelRef*)pixref)->count--; - } - + if (cleancache) - OtkColor_DoCacheCleanup(); - - self->allocated = False; + doCacheCleanup(); } - -OtkColor *OtkColor_New(int screen) +PyObject *OtkColor_FromRGB(int r, int g, int b, int screen) { - OtkColor *self = malloc(sizeof(OtkColor)); + OtkColor *self = PyObject_New(OtkColor, &OtkColor_Type); + PyObject *cached; - self->allocated = False; - self->red = -1; - self->green = -1; - self->blue = -1; - self->pixel = 0; - self->screen = screen; - self->colorname = NULL; - self->colormap = OtkDisplay_ScreenInfo(OBDisplay, self->screen)->colormap; - - return self; -} + assert(screen >= 0); assert(r >= 0); assert(g >= 0); assert(b >= 0); + assert(r <= 0xff); assert(g <= 0xff); assert(b <= 0xff); -OtkColor *OtkColor_FromRGB(int r, int g, int b, int screen) -{ - OtkColor *self = malloc(sizeof(OtkColor)); + if (!colorcache) colorcache = PyDict_New(); - self->allocated = False; self->red = r; self->green = g; self->blue = b; - self->pixel = 0; self->screen = screen; - self->colorname = NULL; - self->colormap = OtkDisplay_ScreenInfo(OBDisplay, self->screen)->colormap; - return self; + // does this color already exist in the cache? + cached = PyDict_GetItem(colorcache, (PyObject*)self); + if (cached) { + Py_INCREF(cached); + return cached; + } + + // add it to the cache + PyDict_SetItem(colorcache, (PyObject*)self, (PyObject*)self); + allocate(self); + return (PyObject*)self; } -OtkColor *OtkColor_FromName(const char *name, int screen) +PyObject *OtkColor_FromName(const char *name, int screen) { - OtkColor *self = malloc(sizeof(OtkColor)); + OtkColor *self = PyObject_New(OtkColor, &OtkColor_Type); + PyObject *cached; + + assert(screen >= 0); assert(name); - self->allocated = False; + if (!colorcache) colorcache = PyDict_New(); + self->red = -1; self->green = -1; self->blue = -1; - self->pixel = 0; self->screen = screen; - self->colorname = PyString_FromString(name); - self->colormap = OtkDisplay_ScreenInfo(OBDisplay, self->screen)->colormap; - return self; -} + parseColorName(self, name); -void OtkColor_Destroy(OtkColor *self) -{ - if (self->colorname) - Py_DECREF(self->colorname); - free(self); -} + // does this color already exist in the cache? + cached = PyDict_GetItem(colorcache, (PyObject*)self); + if (cached) { + Py_INCREF(cached); + return cached; + } -void OtkColor_SetRGB(OtkColor *self, int r, int g, int b) -{ - OtkColor_Deallocate(self); - self->red = r; - self->green = g; - self->blue = b; + // add it to the cache + PyDict_SetItem(colorcache, (PyObject*)self, (PyObject*)self); + allocate(self); + return (PyObject*)self; } -void OtkColor_SetScreen(OtkColor *self, int screen) +void OtkColor_CleanupColorCache() { - if (screen == self->screen) { - // nothing to do - return; - } - - Otk_Deallocate(self); - - self->colormap = OtkDisplay_ScreenInfo(OBDisplay, self->screen)->colormap; + cleancache = True; +} - self->screen = screen; - if (self->colorname) - parseColorName(); -} -Bool OtkColor_IsValid(OtkColor *self) +static void otkcolor_dealloc(OtkColor* self) { - return self->red != -1 && self->blue != -1 && self->green != -1; + // when this is called, the color has already been cleaned out of the cache + PyObject_Del((PyObject*)self); } -unsigned long OtkColor_Pixel(OtkColor *self) +static int otkcolor_compare(OtkColor *c1, OtkColor *c2) { - if (!self->allocated) - OtkColor_Allocate(self); - return self->pixel; -} + long result; + unsigned long p1, p2; -void OtkColor_InitializeCache() -{ - colorcache = PyDict_New(); + p1 = c1->red << 16 | c1->green << 8 | c1->blue; + p2 = c2->red << 16 | c2->green << 8 | c2->blue; + + if (p1 < p2) + result = -1; + else if (p1 > p2) + result = 1; + else + result = 0; + return result; } -void OtkColor_DestroyCache() +static PyObject *otkcolor_repr(OtkColor *self) { - Py_DECREF(colorcache); - colorcache = NULL; + return PyString_FromFormat("rgb:%x/%x/%x", self->red, self->green, + self->blue); } -void OtkColor_CleanupColorCache() +static long otkcolor_hash(OtkColor *self) { - cleancache = True; + return self->screen << 24 | self->red << 16 | self->green << 8 | self->blue; } + +PyTypeObject OtkColor_Type = { + PyObject_HEAD_INIT(NULL) + 0, + "OtkColor", + sizeof(OtkColor), + 0, + (destructor)otkcolor_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + (cmpfunc)otkcolor_compare, /*tp_compare*/ + (reprfunc)otkcolor_repr, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + (hashfunc)otkcolor_hash, /*tp_hash */ +};