]> Dogcows Code - chaz/openbox/blob - otk/gccache.cc
blef
[chaz/openbox] / otk / gccache.cc
1 // -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
2
3 #ifdef HAVE_CONFIG_H
4 # include "../config.h"
5 #endif // HAVE_CONFIG_H
6
7 extern "C" {
8 #include <stdio.h>
9 }
10
11 #include <algorithm>
12
13 #include "gccache.hh"
14 #include "color.hh"
15 #include "assassin.hh"
16 #include "screeninfo.hh"
17
18 namespace otk {
19
20 GCCacheContext::~GCCacheContext(void) {
21 if (gc)
22 XFreeGC(**display, gc);
23 }
24
25
26 void GCCacheContext::set(const Color &_color,
27 const XFontStruct * const _font,
28 const int _function, const int _subwindow,
29 int _linewidth) {
30 XGCValues gcv;
31 pixel = gcv.foreground = _color.pixel();
32 function = gcv.function = _function;
33 subwindow = gcv.subwindow_mode = _subwindow;
34 linewidth = gcv.line_width = _linewidth;
35 gcv.cap_style = CapProjecting;
36
37 unsigned long mask = GCForeground | GCFunction | GCSubwindowMode |
38 GCLineWidth | GCCapStyle;
39
40 if (_font) {
41 fontid = gcv.font = _font->fid;
42 mask |= GCFont;
43 } else {
44 fontid = 0;
45 }
46
47 XChangeGC(**display, gc, mask, &gcv);
48 }
49
50
51 void GCCacheContext::set(const XFontStruct * const _font) {
52 if (! _font) {
53 fontid = 0;
54 return;
55 }
56
57 XGCValues gcv;
58 fontid = gcv.font = _font->fid;
59 XChangeGC(**display, gc, GCFont, &gcv);
60 }
61
62
63 GCCache::GCCache(unsigned int screen_count)
64 : context_count(128u), cache_size(16u), cache_buckets(8u * screen_count),
65 cache_total_size(cache_size * cache_buckets) {
66
67 contexts = new GCCacheContext*[context_count];
68 unsigned int i;
69 for (i = 0; i < context_count; i++) {
70 contexts[i] = new GCCacheContext();
71 }
72
73 cache = new GCCacheItem*[cache_total_size];
74 for (i = 0; i < cache_total_size; ++i) {
75 cache[i] = new GCCacheItem;
76 }
77 }
78
79
80 GCCache::~GCCache(void) {
81 std::for_each(contexts, contexts + context_count, PointerAssassin());
82 std::for_each(cache, cache + cache_total_size, PointerAssassin());
83 delete [] cache;
84 delete [] contexts;
85 }
86
87
88 GCCacheContext *GCCache::nextContext(unsigned int scr) {
89 Window hd = display->screenInfo(scr)->rootWindow();
90
91 GCCacheContext *c;
92
93 for (unsigned int i = 0; i < context_count; ++i) {
94 c = contexts[i];
95
96 if (! c->gc) {
97 c->gc = XCreateGC(**display, hd, 0, 0);
98 c->used = false;
99 c->screen = scr;
100 }
101 if (! c->used && c->screen == scr)
102 return c;
103 }
104
105 fprintf(stderr, "GCCache: context fault!\n");
106 abort();
107 return (GCCacheContext*) 0; // not reached
108 }
109
110
111 void GCCache::release(GCCacheContext *ctx) {
112 ctx->used = false;
113 }
114
115
116 GCCacheItem *GCCache::find(const Color &_color,
117 const XFontStruct * const _font,
118 int _function, int _subwindow, int _linewidth) {
119 const unsigned long pixel = _color.pixel();
120 const unsigned int screen = _color.screen();
121 const int key = _color.red() ^ _color.green() ^ _color.blue();
122 int k = (key % cache_size) * cache_buckets;
123 unsigned int i = 0; // loop variable
124 GCCacheItem *c = cache[ k ], *prev = 0;
125
126 /*
127 this will either loop cache_buckets times then return/abort or
128 it will stop matching
129 */
130 while (c->ctx &&
131 (c->ctx->pixel != pixel || c->ctx->function != _function ||
132 c->ctx->subwindow != _subwindow || c->ctx->screen != screen ||
133 c->ctx->linewidth != _linewidth)) {
134 if (i < (cache_buckets - 1)) {
135 prev = c;
136 c = cache[ ++k ];
137 ++i;
138 continue;
139 }
140 if (c->count == 0 && c->ctx->screen == screen) {
141 // use this cache item
142 c->ctx->set(_color, _font, _function, _subwindow, _linewidth);
143 c->ctx->used = true;
144 c->count = 1;
145 c->hits = 1;
146 return c;
147 }
148 // cache fault!
149 fprintf(stderr, "GCCache: cache fault, count: %d, screen: %d, item screen: %d\n", c->count, screen, c->ctx->screen);
150 abort();
151 }
152
153 if (c->ctx) {
154 // reuse existing context
155 if (_font && _font->fid && _font->fid != c->ctx->fontid)
156 c->ctx->set(_font);
157 c->count++;
158 c->hits++;
159 if (prev && c->hits > prev->hits) {
160 cache[ k ] = prev;
161 cache[ k - 1 ] = c;
162 }
163 } else {
164 c->ctx = nextContext(screen);
165 c->ctx->set(_color, _font, _function, _subwindow, _linewidth);
166 c->ctx->used = true;
167 c->count = 1;
168 c->hits = 1;
169 }
170
171 return c;
172 }
173
174
175 void GCCache::release(GCCacheItem *_item) {
176 _item->count--;
177 }
178
179
180 void GCCache::purge(void) {
181 for (unsigned int i = 0; i < cache_total_size; ++i) {
182 GCCacheItem *d = cache[ i ];
183
184 if (d->ctx && d->count == 0) {
185 release(d->ctx);
186 d->ctx = 0;
187 }
188 }
189 }
190
191 }
This page took 0.044988 seconds and 4 git commands to generate.