]> Dogcows Code - chaz/openbox/commitdiff
it compiles.. does it work?
authorDana Jansens <danakj@orodu.net>
Sat, 21 Dec 2002 02:09:54 +0000 (02:09 +0000)
committerDana Jansens <danakj@orodu.net>
Sat, 21 Dec 2002 02:09:54 +0000 (02:09 +0000)
otk_c/color.c [new file with mode: 0644]
otk_c/color.h [new file with mode: 0644]
otk_c/gccache.c [new file with mode: 0644]
otk_c/gccache.h [new file with mode: 0644]

diff --git a/otk_c/color.c b/otk_c/color.c
new file mode 100644 (file)
index 0000000..9f71821
--- /dev/null
@@ -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;
+}
diff --git a/otk_c/color.h b/otk_c/color.h
new file mode 100644 (file)
index 0000000..91b83e0
--- /dev/null
@@ -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
diff --git a/otk_c/gccache.c b/otk_c/gccache.c
new file mode 100644 (file)
index 0000000..7d96677
--- /dev/null
@@ -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;
+    }
+  }
+}
diff --git a/otk_c/gccache.h b/otk_c/gccache.h
new file mode 100644 (file)
index 0000000..f6657f4
--- /dev/null
@@ -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
This page took 0.033307 seconds and 4 git commands to generate.