it compiles.. does it work?
This commit is contained in:
parent
607bf10d6d
commit
59b65db2ca
4 changed files with 684 additions and 0 deletions
321
otk_c/color.c
Normal file
321
otk_c/color.c
Normal 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
33
otk_c/color.h
Normal 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
232
otk_c/gccache.c
Normal 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
98
otk_c/gccache.h
Normal 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
|
Loading…
Reference in a new issue