it compiles.. does it work?

This commit is contained in:
Dana Jansens 2002-12-21 02:09:54 +00:00
parent 607bf10d6d
commit 59b65db2ca
4 changed files with 684 additions and 0 deletions

321
otk_c/color.c Normal file
View file

@ -0,0 +1,321 @@
// -*- mode: C; indent-tabs-mode: nil; -*-
#include "../config.h"
#include "color.h"
#include "display.h"
#include "screeninfo.h"
#ifdef HAVE_STDLIB_H
# include <stdlib.h>
#endif
static Bool cleancache = False;
static PyObject *colorcache;
// 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) {
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;
}
OtkColor_SetRGB(self, xcol.red >> 8, xcol.green >> 8, xcol.blue >> 8);
}
static void OtkColor_DoCacheCleanup() {
unsigned long *pixels;
int i;
unsigned int count;
PyObject *rgb, *pixref;
int ppos;
// ### TODO - support multiple displays!
if (!PyDict_Size(colorcache)) {
// nothing to do
return;
}
pixels = malloc(sizeof(unsigned long) * PyDict_Size(colorcache));
for (i = 0; i < ScreenCount(OBDisplay->display); i++) {
count = 0;
ppos = 0;
while (PyDict_Next(colorcache, &ppos, &rgb, &pixref)) {
if (((PixelRef*)pixref)->count != 0 || ((RGB*)rgb)->screen != i)
continue;
pixels[count++] = ((PixelRef*)pixref)->p;
PyDict_DelItem(colorcache, rgb);
free(pixref); // not really a PyObject, it just pretends
--ppos; // back up one in the iteration
}
if (count > 0)
XFreeColors(OBDisplay->display,
OtkDisplay_ScreenInfo(OBDisplay, i)->colormap,
pixels, count, 0);
}
free(pixels);
cleancache = False;
}
static void OtkColor_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",
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;
}
OtkColor *OtkColor_New(int screen)
{
OtkColor *self = malloc(sizeof(OtkColor));
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;
}
OtkColor *OtkColor_FromRGB(int r, int g, int b, int screen)
{
OtkColor *self = malloc(sizeof(OtkColor));
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;
}
OtkColor *OtkColor_FromName(const char *name, int screen)
{
OtkColor *self = malloc(sizeof(OtkColor));
self->allocated = False;
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;
}
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;
}
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;
}
unsigned long OtkColor_Pixel(OtkColor *self)
{
if (!self->allocated)
OtkColor_Allocate(self);
return self->pixel;
}
void OtkColor_InitializeCache()
{
colorcache = PyDict_New();
}
void OtkColor_DestroyCache()
{
Py_DECREF(colorcache);
colorcache = NULL;
}
void OtkColor_CleanupColorCache()
{
cleancache = True;
}

33
otk_c/color.h Normal file
View file

@ -0,0 +1,33 @@
// -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
#ifndef __color_h
#define __color_h
#include <X11/Xlib.h>
#include <Python.h>
typedef struct OtkColor {
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);
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

232
otk_c/gccache.c Normal file
View file

@ -0,0 +1,232 @@
// -*- mode: C; indent-tabs-mode: nil; -*-
#include "../config.h"
#include "gccache.h"
#include "screeninfo.h"
#ifdef HAVE_STDLIB_H
# include <stdlib.h>
#endif
static OtkGCCache *gccache;
OtkGCCacheContext *OtkGCCacheContext_New()
{
OtkGCCacheContext *self = malloc(sizeof(OtkGCCacheContext));
self->gc = 0;
self->pixel = 0ul;
self->fontid = 0ul;
self->function = 0;
self->subwindow = 0;
self->used = False;
self->screen = ~0;
self->linewidth = 0;
return self;
}
void OtkGCCacheContext_Destroy(OtkGCCacheContext *self)
{
if (self->gc)
XFreeGC(OBDisplay->display, self->gc);
free(self);
}
void OtkGCCacheContext_Set(OtkGCCacheContext *self,
OtkColor *color, XFontStruct *font,
int function, int subwindow, int linewidth)
{
XGCValues gcv;
unsigned long mask;
self->pixel = gcv.foreground = OtkColor_Pixel(color);
self->function = gcv.function = function;
self->subwindow = gcv.subwindow_mode = subwindow;
self->linewidth = gcv.line_width = linewidth;
gcv.cap_style = CapProjecting;
mask = GCForeground | GCFunction | GCSubwindowMode | GCLineWidth |
GCCapStyle;
if (font) {
self->fontid = gcv.font = font->fid;
mask |= GCFont;
} else {
self->fontid = 0;
}
XChangeGC(OBDisplay->display, self->gc, mask, &gcv);
}
void OtkGCCacheContext_SetFont(OtkGCCacheContext *self,
XFontStruct *font)
{
if (!font) {
self->fontid = 0;
return;
}
XGCValues gcv;
self->fontid = gcv.font = font->fid;
XChangeGC(OBDisplay->display, self->gc, GCFont, &gcv);
}
OtkGCCacheItem *OtkGCCacheItem_New()
{
OtkGCCacheItem *self = malloc(sizeof(OtkGCCacheItem));
self->ctx = 0;
self->count = 0;
self->hits = 0;
self->fault = False;
}
void OtkGCCache_Initialize(int screen_count)
{
int i;
gccache = malloc(sizeof(OtkGCCache));
gccache->context_count = 128;
gccache->cache_size = 16;
gccache->cache_buckets = 8 * screen_count;
gccache->cache_total_size = gccache->cache_size * gccache->cache_buckets;
gccache->contexts = malloc(sizeof(OtkGCCacheContext*) *
gccache->context_count);
for (i = 0; i < gccache->context_count; ++i)
gccache->contexts[i] = OtkGCCacheContext_New();
gccache->cache = malloc(sizeof(OtkGCCacheItem*) * gccache->cache_total_size);
for (i = 0; i < gccache->cache_total_size; ++i)
gccache->cache[i] = OtkGCCacheItem_New();
}
void OtkGCCache_Destroy()
{
int i;
for (i = 0; i < gccache->context_count; ++i)
OtkGCCacheContext_Destroy(gccache->contexts[i]);
for (i = 0; i < gccache->cache_total_size; ++i)
free(gccache->cache[i]);
free(gccache->contexts);
free(gccache->cache);
free(gccache);
gccache = NULL;
}
OtkGCCacheContext *OtkGCCache_NextContext(int screen)
{
Window hd = OtkDisplay_ScreenInfo(OBDisplay, screen)->root_window;
OtkGCCacheContext *c;
int i;
for (i = 0; i < gccache->context_count; ++i) {
c = gccache->contexts[i];
if (! c->gc) {
c->gc = XCreateGC(OBDisplay->display, hd, 0, 0);
c->used = False;
c->screen = screen;
}
if (! c->used && c->screen == screen)
return c;
}
fprintf(stderr, "OtkGCCache: context fault!\n");
abort();
return NULL; // shut gcc up
}
static void OtkGCCache_InternalRelease(OtkGCCacheContext *ctx)
{
ctx->used = False;
}
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 key = color->red ^ color->green ^ color->blue;
int k = (key % gccache->cache_size) * gccache->cache_buckets;
int i = 0; // loop variable
OtkGCCacheItem *c = gccache->cache[k], *prev = 0;
/*
this will either loop cache_buckets times then return/abort or
it will stop matching
*/
while (c->ctx &&
(c->ctx->pixel != pixel || c->ctx->function != function ||
c->ctx->subwindow != subwindow || c->ctx->screen != screen ||
c->ctx->linewidth != linewidth)) {
if (i < (gccache->cache_buckets - 1)) {
prev = c;
c = gccache->cache[++k];
++i;
continue;
}
if (c->count == 0 && c->ctx->screen == screen) {
// use this cache item
OtkGCCacheContext_Set(c->ctx, color, font, function, subwindow,
linewidth);
c->ctx->used = True;
c->count = 1;
c->hits = 1;
return c;
}
// cache fault!
fprintf(stderr, "OtkGCCache: cache fault, count: %d, screen: %d, item screen: %d\n", c->count, screen, c->ctx->screen);
abort();
}
if (c->ctx) {
// reuse existing context
if (font && font->fid && font->fid != c->ctx->fontid)
OtkGCCacheContext_SetFont(c->ctx, font);
c->count++;
c->hits++;
if (prev && c->hits > prev->hits) {
gccache->cache[k] = prev;
gccache->cache[k-1] = c;
}
} else {
c->ctx = OtkGCCache_NextContext(screen);
OtkGCCacheContext_Set(c->ctx, color, font, function, subwindow, linewidth);
c->ctx->used = True;
c->count = 1;
c->hits = 1;
}
return c;
}
void OtkGCCache_Release(OtkGCCacheItem *item)
{
item->count--;
}
void OtkGCCache_Purge()
{
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);
d->ctx = 0;
}
}
}

98
otk_c/gccache.h Normal file
View file

@ -0,0 +1,98 @@
// -*- mode: C; indent-tabs-mode: nil; -*-
#ifndef __gccache_h
#define __gccache_h
#include <X11/Xlib.h>
#include "display.h"
#include "color.h"
struct OtkGCCacheItem;
typedef struct OtkGCCacheContext {
GC gc;
unsigned long pixel;
unsigned long fontid;
int function;
int subwindow;
Bool used;
unsigned int screen;
int linewidth;
} OtkGCCacheContext;
OtkGCCacheContext *OtkGCCacheContext_New();
void OtkGCCacheContext_Destroy(OtkGCCacheContext *self);
void OtkGCCacheContext_Set(OtkGCCacheContext *self,
OtkColor *color, XFontStruct *font,
int function, int subwindow, int linewidth);
void OtkGCCacheContext_SetFont(OtkGCCacheContext *self,
XFontStruct *font);
typedef struct OtkGCCacheItem {
OtkGCCacheContext *ctx;
unsigned int count;
unsigned int hits;
Bool fault;
} OtkGCCacheItem;
OtkGCCacheItem *OtkGCCacheItem_New();
typedef struct OtkGCCache {
// this is closely modelled after the Qt GC cache, but with some of the
// complexity stripped out
unsigned int context_count;
unsigned int cache_size;
unsigned int cache_buckets;
unsigned int cache_total_size;
OtkGCCacheContext **contexts;
OtkGCCacheItem **cache;
} OtkGCCache;
void OtkGCCache_Initialize(int screen_count);
void OtkGCCache_Destroy();
// cleans up the cache
void OtkGCCache_Purge();
OtkGCCacheItem *OtkGCCache_Find(OtkColor *color,
XFontStruct *font, int function,
int subwindow, int linewidth);
void OtkGCCache_Release(OtkGCCacheItem *item);
/*
class BPen {
public:
inline BPen(const BColor &_color, const XFontStruct * const _font = 0,
int _linewidth = 0, int _function = GXcopy,
int _subwindow = ClipByChildren)
: color(_color), font(_font), linewidth(_linewidth), function(_function),
subwindow(_subwindow), cache(OBDisplay::gcCache()), item(0) { }
inline ~BPen(void) { if (item) cache->release(item); }
inline const GC &gc(void) const {
if (! item) item = cache->find(color, font, function, subwindow,
linewidth);
return item->gc();
}
private:
const BColor &color;
const XFontStruct *font;
int linewidth;
int function;
int subwindow;
mutable BGCCache *cache;
mutable BGCCacheItem *item;
};
}*/
#endif // __gccache_h