openbox/otk/gccache.cc

192 lines
4.5 KiB
C++
Raw Normal View History

2002-11-01 03:27:41 +00:00
// -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
#ifdef HAVE_CONFIG_H
# include "../config.h"
#endif // HAVE_CONFIG_H
extern "C" {
#include <stdio.h>
}
2002-11-03 19:50:09 +00:00
#include <algorithm>
2002-11-01 03:27:41 +00:00
#include "gccache.hh"
#include "color.hh"
#include "assassin.hh"
#include "screeninfo.hh"
2002-11-01 03:27:41 +00:00
namespace otk {
2002-11-01 03:27:41 +00:00
BGCCacheContext::~BGCCacheContext(void) {
if (gc)
XFreeGC(OBDisplay::display, gc);
2002-11-01 03:27:41 +00:00
}
void BGCCacheContext::set(const BColor &_color,
const XFontStruct * const _font,
const int _function, const int _subwindow,
int _linewidth) {
XGCValues gcv;
pixel = gcv.foreground = _color.pixel();
function = gcv.function = _function;
subwindow = gcv.subwindow_mode = _subwindow;
linewidth = gcv.line_width = _linewidth;
gcv.cap_style = CapProjecting;
unsigned long mask = GCForeground | GCFunction | GCSubwindowMode |
GCLineWidth | GCCapStyle;
if (_font) {
fontid = gcv.font = _font->fid;
mask |= GCFont;
} else {
fontid = 0;
}
XChangeGC(OBDisplay::display, gc, mask, &gcv);
2002-11-01 03:27:41 +00:00
}
void BGCCacheContext::set(const XFontStruct * const _font) {
if (! _font) {
fontid = 0;
return;
}
XGCValues gcv;
fontid = gcv.font = _font->fid;
XChangeGC(OBDisplay::display, gc, GCFont, &gcv);
2002-11-01 03:27:41 +00:00
}
BGCCache::BGCCache(unsigned int screen_count)
: context_count(128u), cache_size(16u), cache_buckets(8u * screen_count),
2002-11-01 03:27:41 +00:00
cache_total_size(cache_size * cache_buckets) {
contexts = new BGCCacheContext*[context_count];
unsigned int i;
for (i = 0; i < context_count; i++) {
contexts[i] = new BGCCacheContext();
2002-11-01 03:27:41 +00:00
}
cache = new BGCCacheItem*[cache_total_size];
for (i = 0; i < cache_total_size; ++i) {
cache[i] = new BGCCacheItem;
}
}
BGCCache::~BGCCache(void) {
std::for_each(contexts, contexts + context_count, PointerAssassin());
std::for_each(cache, cache + cache_total_size, PointerAssassin());
delete [] cache;
delete [] contexts;
}
BGCCacheContext *BGCCache::nextContext(unsigned int scr) {
Window hd = OBDisplay::screenInfo(scr)->getRootWindow();
2002-11-01 03:27:41 +00:00
BGCCacheContext *c;
for (unsigned int i = 0; i < context_count; ++i) {
c = contexts[i];
if (! c->gc) {
c->gc = XCreateGC(OBDisplay::display, hd, 0, 0);
2002-11-01 03:27:41 +00:00
c->used = false;
c->screen = scr;
}
if (! c->used && c->screen == scr)
return c;
}
fprintf(stderr, "BGCCache: context fault!\n");
abort();
return (BGCCacheContext*) 0; // not reached
}
void BGCCache::release(BGCCacheContext *ctx) {
ctx->used = false;
}
BGCCacheItem *BGCCache::find(const BColor &_color,
const XFontStruct * const _font,
int _function, int _subwindow, int _linewidth) {
const unsigned long pixel = _color.pixel();
const unsigned int screen = _color.screen();
const int key = _color.red() ^ _color.green() ^ _color.blue();
int k = (key % cache_size) * cache_buckets;
unsigned int i = 0; // loop variable
BGCCacheItem *c = 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 < (cache_buckets - 1)) {
prev = c;
c = cache[ ++k ];
++i;
continue;
}
if (c->count == 0 && c->ctx->screen == screen) {
// use this cache item
c->ctx->set(_color, _font, _function, _subwindow, _linewidth);
c->ctx->used = true;
c->count = 1;
c->hits = 1;
return c;
}
// cache fault!
fprintf(stderr, "BGCCache: 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)
c->ctx->set(_font);
c->count++;
c->hits++;
if (prev && c->hits > prev->hits) {
cache[ k ] = prev;
cache[ k - 1 ] = c;
}
} else {
c->ctx = nextContext(screen);
c->ctx->set(_color, _font, _function, _subwindow, _linewidth);
c->ctx->used = true;
c->count = 1;
c->hits = 1;
}
return c;
}
void BGCCache::release(BGCCacheItem *_item) {
_item->count--;
}
void BGCCache::purge(void) {
for (unsigned int i = 0; i < cache_total_size; ++i) {
BGCCacheItem *d = cache[ i ];
if (d->ctx && d->count == 0) {
release(d->ctx);
d->ctx = 0;
}
}
}
}