a color cache to be proud of!

This commit is contained in:
Dana Jansens 2002-12-21 12:04:15 +00:00
parent 59b65db2ca
commit 187e7db9c0
8 changed files with 161 additions and 262 deletions

View file

@ -6,7 +6,7 @@ targets = libotk.so libotk.a
sources = display.c screeninfo.c rect.c gccache.c color.c
headers = display.h screeninfo.h rect.h gccache.h color.h
CFLAGS+=-I/usr/gwar/include/python2.2
CFLAGS+=-g -I/usr/gwar/include/python2.2 -W -Wall
.PHONY: all install clean

View file

@ -10,30 +10,21 @@
#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)
static void otkcolor_dealloc(OtkColor* self)
{
PyObject_Del(self);
// when this is called, the color has already been cleaned out of the cache
PyObject_Del((PyObject*)self);
}
static int rgb_compare(PyObject *py1, PyObject *py2)
static int otkcolor_compare(OtkColor *c1, OtkColor *c2)
{
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;
p1 = c1->red << 16 | c1->green << 8 | c1->blue;
p2 = c2->red << 16 | c2->green << 8 | c2->blue;
if (p1 < p2)
result = -1;
@ -44,132 +35,114 @@ static int rgb_compare(PyObject *py1, PyObject *py2)
return result;
}
static PyTypeObject RGB_Type = {
static PyObject *otkcolor_repr(OtkColor *self)
{
return PyString_FromFormat("rgb:%x/%x/%x", self->red, self->green,
self->blue);
}
static long otkcolor_hash(OtkColor *self)
{
return self->screen << 24 | self->red << 16 | self->green << 8 | self->blue;
}
static PyTypeObject OtkColor_Type = {
PyObject_HEAD_INIT(NULL)
0,
"RGB",
sizeof(RGB),
"Color",
sizeof(OtkColor),
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 */
(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 */
};
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() {
#include <stdio.h>
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
printf("Cleaning Cache...\n");
pixels = malloc(sizeof(unsigned long) * PyDict_Size(colorcache));
for (i = 0; i < ScreenCount(OBDisplay->display); i++) {
printf("Screen %d\n", i);
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
printf("has %d refs\n", color->ob_refcnt);
// 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
printf("ppos: %d\n", ppos);
printf("Cleaning pixel: %lx Count: %d\n", color->pixel, count+1);
pixels[count++] = color->pixel;
printf("pixref references before: %d\n", color->ob_refcnt);
PyDict_DelItem(colorcache, key);
printf("pixref references after: %d\n", color->ob_refcnt);
--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);
printf("Done Cleaning Cache. Cleaned %d pixels\n", count);
}
free(pixels);
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);
}
}
assert(!self->allocated);
// 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;
}
printf("allocating! %d\n", cleancache);
// allocate color from rgb values
xcol.red = self->red | self->red << 8;
@ -177,8 +150,10 @@ static void OtkColor_Allocate(OtkColor *self) {
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;
}
@ -186,51 +161,19 @@ static void OtkColor_Allocate(OtkColor *self) {
self->pixel = xcol.pixel;
self->allocated = True;
PyDict_SetItem(colorcache, rgb, (PyObject*)PixelRef_New(self->pixel));
if (cleancache)
OtkColor_DoCacheCleanup();
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;
}
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;
assert(screen >= 0); assert(r >= 0); assert(g >= 0); assert(b >= 0);
assert(r <= 0xff); assert(g <= 0xff); assert(b <= 0xff);
return self;
}
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;
@ -238,15 +181,27 @@ OtkColor *OtkColor_FromRGB(int r, int g, int b, int screen)
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);
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);
if (!colorcache) colorcache = PyDict_New();
self->allocated = False;
self->red = -1;
@ -254,67 +209,28 @@ OtkColor *OtkColor_FromName(const char *name, int screen)
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);
}
void OtkColor_SetRGB(OtkColor *self, int r, int g, int b)
{
OtkColor_Deallocate(self);
self->red = r;
self->green = g;
self->blue = b;
}
void OtkColor_SetScreen(OtkColor *self, int screen)
{
if (screen == self->screen) {
// nothing to do
return;
// does this color already exist in the cache?
cached = PyDict_GetItem(colorcache, (PyObject*)self);
if (cached) {
Py_INCREF(cached);
return cached;
}
Otk_Deallocate(self);
self->colormap = OtkDisplay_ScreenInfo(OBDisplay, self->screen)->colormap;
self->screen = screen;
if (self->colorname)
parseColorName();
}
Bool OtkColor_IsValid(OtkColor *self)
{
return self->red != -1 && self->blue != -1 && self->green != -1;
// add it to the cache
PyDict_SetItem(colorcache, (PyObject*)self, (PyObject*)self);
return (PyObject*)self;
}
unsigned long OtkColor_Pixel(OtkColor *self)
{
if (!self->allocated)
OtkColor_Allocate(self);
allocate(self);
return self->pixel;
}
void OtkColor_InitializeCache()
{
colorcache = PyDict_New();
}
void OtkColor_DestroyCache()
{
Py_DECREF(colorcache);
colorcache = NULL;
}
void OtkColor_CleanupColorCache()
{
cleancache = True;

View file

@ -5,29 +5,20 @@
#include <X11/Xlib.h>
#include <Python.h>
//! OtkColor objects are immutable. DONT CHANGE THEM.
typedef struct OtkColor {
PyObject_HEAD
int red, green, blue;
int screen;
Bool allocated;
unsigned long pixel;
PyObject *colorname; // PyStringObject
Colormap colormap;
} OtkColor;
OtkColor *OtkColor_New(int screen);
OtkColor *OtkColor_FromRGB(int r, int g, int b, int screen);
OtkColor *OtkColor_FromName(const char *name, int screen);
PyObject *OtkColor_FromRGB(int r, int g, int b, int screen);
PyObject *OtkColor_FromName(const char *name, int screen);
void OtkColor_Destroy(OtkColor *self);
void OtkColor_SetRGB(OtkColor *self, int r, int g, int b);
void OtkColor_SetScreen(OtkColor *self, int screen);
Bool OtkColor_IsValid(OtkColor *self);
unsigned long OtkColor_Pixel(OtkColor *self);
void OtkColor_InitializeCache();
void OtkColor_DestroyCache();
void OtkColor_CleanupColorCache();
#endif // __color_h

View file

@ -33,7 +33,9 @@ extern PyTypeObject OtkDisplay_Type;
static int xerrorHandler(Display *d, XErrorEvent *e);
PyObject *OtkDisplay_New(char *name)
struct OtkDisplay *OBDisplay = NULL;
void OtkDisplay_Initialize(char *name)
{
OtkDisplay* self;
PyObject *disp_env;
@ -117,14 +119,13 @@ line argument.\n\n"));
self->mask_list[6] = ScrollLockMask | NumLockMask;
self->mask_list[7] = ScrollLockMask | LockMask | NumLockMask;
// set the global var, for the new screeninfo's
OBDisplay = self;
// Get information on all the screens which are available.
self->screenInfoList = PyList_New(ScreenCount(self->display));
for (i = 0; i < ScreenCount(self->display); ++i)
PyList_SetItem(self->screenInfoList, i, OtkScreenInfo_New(i));
self->gccache = OtkGCCache_New(PyList_Size(self->screenInfoList));
return (PyObject*)self;
}
void OtkDisplay_Grab(OtkDisplay *self)

View file

@ -6,10 +6,9 @@
#include <Python.h>
struct OtkScreenInfo;
struct OtkGCCache;
struct OtkDisplay;
struct OtkDisplay *OBDisplay; // the global display XXX: move this to app.h and ob.h?
extern struct OtkDisplay *OBDisplay; // the global display XXX: move this to app.h and ob.h?
typedef struct OtkDisplay {
PyObject_HEAD
@ -35,25 +34,15 @@ typedef struct OtkDisplay {
//! A list of information for all screens on the display
PyObject *screenInfoList; // PyListObject
//! A cache for re-using GCs, used by the drawing objects
/*!
@see BPen
@see BFont
@see BImage
@see BImageControl
@see BTexture
*/
struct OtkGCCache *gccache;
} OtkDisplay;
//! Creates a struct, opens the X display
//! Opens the X display, and sets the global OBDisplay variable
/*!
@see OBDisplay::display
@param name The name of the X display to open. If it is null, the DISPLAY
environment variable is used instead.
*/
PyObject *OtkDisplay_New(char *name);
void OtkDisplay_Initialize(char *name);
//! Grabs the display
void OtkDisplay_Grab(OtkDisplay *self);

View file

@ -8,7 +8,7 @@
# include <stdlib.h>
#endif
static OtkGCCache *gccache;
static OtkGCCache *gccache = NULL;
OtkGCCacheContext *OtkGCCacheContext_New()
{
@ -81,12 +81,14 @@ OtkGCCacheItem *OtkGCCacheItem_New()
self->count = 0;
self->hits = 0;
self->fault = False;
return self;
}
void OtkGCCache_Initialize(int screen_count)
{
int i;
unsigned int i;
gccache = malloc(sizeof(OtkGCCache));
@ -108,7 +110,7 @@ void OtkGCCache_Initialize(int screen_count)
void OtkGCCache_Destroy()
{
int i;
unsigned int i;
for (i = 0; i < gccache->context_count; ++i)
OtkGCCacheContext_Destroy(gccache->contexts[i]);
@ -126,7 +128,7 @@ OtkGCCacheContext *OtkGCCache_NextContext(int screen)
{
Window hd = OtkDisplay_ScreenInfo(OBDisplay, screen)->root_window;
OtkGCCacheContext *c;
int i;
unsigned int i;
for (i = 0; i < gccache->context_count; ++i) {
c = gccache->contexts[i];
@ -155,10 +157,10 @@ OtkGCCacheItem *OtkGCCache_Find(OtkColor *color, XFontStruct *font,
int function, int subwindow, int linewidth)
{
const unsigned long pixel = OtkColor_Pixel(color);
const unsigned int screen = color->screen;
const int screen = color->screen;
const int key = color->red ^ color->green ^ color->blue;
int k = (key % gccache->cache_size) * gccache->cache_buckets;
int i = 0; // loop variable
unsigned int i = 0; // loop variable
OtkGCCacheItem *c = gccache->cache[k], *prev = 0;
/*
@ -219,13 +221,13 @@ void OtkGCCache_Release(OtkGCCacheItem *item)
void OtkGCCache_Purge()
{
int i;
unsigned int i;
for (i = 0; i < gccache->cache_total_size; ++i) {
OtkGCCacheItem *d = gccache->cache[i];
if (d->ctx && d->count == 0) {
release(d->ctx);
OtkGCCache_InternalRelease(d->ctx);
d->ctx = 0;
}
}

View file

@ -16,7 +16,7 @@ typedef struct OtkGCCacheContext {
int function;
int subwindow;
Bool used;
unsigned int screen;
int screen;
int linewidth;
} OtkGCCacheContext;

View file

@ -85,7 +85,7 @@ PyObject *OtkScreenInfo_New(int num)
if (dstr2) {
PyObject *str;
PyString_Resize(self->display_string, dstr2 - dstr);
_PyString_Resize(&self->display_string, dstr2 - dstr);
str = PyString_FromFormat(".%d", self->screen);
PyString_Concat(&self->display_string, str);
}