1 // -*- mode: C; indent-tabs-mode: nil; -*-
5 #include "screeninfo.h"
11 static OtkGCCache *gccache;
13 OtkGCCacheContext *OtkGCCacheContext_New()
15 OtkGCCacheContext *self = malloc(sizeof(OtkGCCacheContext));
29 void OtkGCCacheContext_Destroy(OtkGCCacheContext *self)
32 XFreeGC(OBDisplay->display, self->gc);
36 void OtkGCCacheContext_Set(OtkGCCacheContext *self,
37 OtkColor *color, XFontStruct *font,
38 int function, int subwindow, int linewidth)
43 self->pixel = gcv.foreground = OtkColor_Pixel(color);
44 self->function = gcv.function = function;
45 self->subwindow = gcv.subwindow_mode = subwindow;
46 self->linewidth = gcv.line_width = linewidth;
47 gcv.cap_style = CapProjecting;
49 mask = GCForeground | GCFunction | GCSubwindowMode | GCLineWidth |
53 self->fontid = gcv.font = font->fid;
59 XChangeGC(OBDisplay->display, self->gc, mask, &gcv);
62 void OtkGCCacheContext_SetFont(OtkGCCacheContext *self,
71 self->fontid = gcv.font = font->fid;
72 XChangeGC(OBDisplay->display, self->gc, GCFont, &gcv);
76 OtkGCCacheItem *OtkGCCacheItem_New()
78 OtkGCCacheItem *self = malloc(sizeof(OtkGCCacheItem));
87 void OtkGCCache_Initialize(int screen_count)
91 gccache = malloc(sizeof(OtkGCCache));
93 gccache->context_count = 128;
94 gccache->cache_size = 16;
95 gccache->cache_buckets = 8 * screen_count;
96 gccache->cache_total_size = gccache->cache_size * gccache->cache_buckets;
98 gccache->contexts = malloc(sizeof(OtkGCCacheContext*) *
99 gccache->context_count);
100 for (i = 0; i < gccache->context_count; ++i)
101 gccache->contexts[i] = OtkGCCacheContext_New();
103 gccache->cache = malloc(sizeof(OtkGCCacheItem*) * gccache->cache_total_size);
104 for (i = 0; i < gccache->cache_total_size; ++i)
105 gccache->cache[i] = OtkGCCacheItem_New();
109 void OtkGCCache_Destroy()
113 for (i = 0; i < gccache->context_count; ++i)
114 OtkGCCacheContext_Destroy(gccache->contexts[i]);
116 for (i = 0; i < gccache->cache_total_size; ++i)
117 free(gccache->cache[i]);
119 free(gccache->contexts);
120 free(gccache->cache);
125 OtkGCCacheContext *OtkGCCache_NextContext(int screen)
127 Window hd = OtkDisplay_ScreenInfo(OBDisplay, screen)->root_window;
128 OtkGCCacheContext *c;
131 for (i = 0; i < gccache->context_count; ++i) {
132 c = gccache->contexts[i];
135 c->gc = XCreateGC(OBDisplay->display, hd, 0, 0);
139 if (! c->used && c->screen == screen)
143 fprintf(stderr, "OtkGCCache: context fault!\n");
145 return NULL; // shut gcc up
149 static void OtkGCCache_InternalRelease(OtkGCCacheContext *ctx)
154 OtkGCCacheItem *OtkGCCache_Find(OtkColor *color, XFontStruct *font,
155 int function, int subwindow, int linewidth)
157 const unsigned long pixel = OtkColor_Pixel(color);
158 const unsigned int screen = color->screen;
159 const int key = color->red ^ color->green ^ color->blue;
160 int k = (key % gccache->cache_size) * gccache->cache_buckets;
161 int i = 0; // loop variable
162 OtkGCCacheItem *c = gccache->cache[k], *prev = 0;
165 this will either loop cache_buckets times then return/abort or
166 it will stop matching
169 (c->ctx->pixel != pixel || c->ctx->function != function ||
170 c->ctx->subwindow != subwindow || c->ctx->screen != screen ||
171 c->ctx->linewidth != linewidth)) {
172 if (i < (gccache->cache_buckets - 1)) {
174 c = gccache->cache[++k];
178 if (c->count == 0 && c->ctx->screen == screen) {
179 // use this cache item
180 OtkGCCacheContext_Set(c->ctx, color, font, function, subwindow,
188 fprintf(stderr, "OtkGCCache: cache fault, count: %d, screen: %d, item screen: %d\n", c->count, screen, c->ctx->screen);
193 // reuse existing context
194 if (font && font->fid && font->fid != c->ctx->fontid)
195 OtkGCCacheContext_SetFont(c->ctx, font);
198 if (prev && c->hits > prev->hits) {
199 gccache->cache[k] = prev;
200 gccache->cache[k-1] = c;
203 c->ctx = OtkGCCache_NextContext(screen);
204 OtkGCCacheContext_Set(c->ctx, color, font, function, subwindow, linewidth);
214 void OtkGCCache_Release(OtkGCCacheItem *item)
220 void OtkGCCache_Purge()
224 for (i = 0; i < gccache->cache_total_size; ++i) {
225 OtkGCCacheItem *d = gccache->cache[i];
227 if (d->ctx && d->count == 0) {