1 // -*- mode: C; indent-tabs-mode: nil; -*-
5 #include "screeninfo.h"
11 static OtkGCCache *gccache = NULL;
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));
89 void OtkGCCache_Initialize()
93 gccache = malloc(sizeof(OtkGCCache));
95 gccache->context_count = 128;
96 gccache->cache_size = 16;
97 gccache->cache_buckets = 8 * ScreenCount(OBDisplay->display);
98 gccache->cache_total_size = gccache->cache_size * gccache->cache_buckets;
100 gccache->contexts = malloc(sizeof(OtkGCCacheContext*) *
101 gccache->context_count);
102 for (i = 0; i < gccache->context_count; ++i)
103 gccache->contexts[i] = OtkGCCacheContext_New();
105 gccache->cache = malloc(sizeof(OtkGCCacheItem*) * gccache->cache_total_size);
106 for (i = 0; i < gccache->cache_total_size; ++i)
107 gccache->cache[i] = OtkGCCacheItem_New();
111 /*void OtkGCCache_Destroy()
115 for (i = 0; i < gccache->context_count; ++i)
116 OtkGCCacheContext_Destroy(gccache->contexts[i]);
118 for (i = 0; i < gccache->cache_total_size; ++i)
119 free(gccache->cache[i]);
121 free(gccache->contexts);
122 free(gccache->cache);
127 static OtkGCCacheContext *nextContext(int screen)
129 Window hd = OtkDisplay_ScreenInfo(OBDisplay, screen)->root_window;
130 OtkGCCacheContext *c;
133 for (i = 0; i < gccache->context_count; ++i) {
134 c = gccache->contexts[i];
137 c->gc = XCreateGC(OBDisplay->display, hd, 0, 0);
141 if (! c->used && c->screen == screen)
145 fprintf(stderr, "OtkGCCache: context fault!\n");
147 return NULL; // shut gcc up
151 static void OtkGCCache_InternalRelease(OtkGCCacheContext *ctx)
156 OtkGCCacheItem *OtkGCCache_Find(OtkColor *color, XFontStruct *font,
157 int function, int subwindow, int linewidth)
159 const unsigned long pixel = OtkColor_Pixel(color);
160 const int screen = color->screen;
161 const int key = color->red ^ color->green ^ color->blue;
162 int k = (key % gccache->cache_size) * gccache->cache_buckets;
163 unsigned int i = 0; // loop variable
164 OtkGCCacheItem *c = gccache->cache[k], *prev = 0;
167 this will either loop cache_buckets times then return/abort or
168 it will stop matching
171 (c->ctx->pixel != pixel || c->ctx->function != function ||
172 c->ctx->subwindow != subwindow || c->ctx->screen != screen ||
173 c->ctx->linewidth != linewidth)) {
174 if (i < (gccache->cache_buckets - 1)) {
176 c = gccache->cache[++k];
180 if (c->count == 0 && c->ctx->screen == screen) {
181 // use this cache item
182 OtkGCCacheContext_Set(c->ctx, color, font, function, subwindow,
190 fprintf(stderr, "OtkGCCache: cache fault, count: %d, screen: %d, item screen: %d\n", c->count, screen, c->ctx->screen);
195 // reuse existing context
196 if (font && font->fid && font->fid != c->ctx->fontid)
197 OtkGCCacheContext_SetFont(c->ctx, font);
200 if (prev && c->hits > prev->hits) {
201 gccache->cache[k] = prev;
202 gccache->cache[k-1] = c;
205 c->ctx = nextContext(screen);
206 OtkGCCacheContext_Set(c->ctx, color, font, function, subwindow, linewidth);
216 void OtkGCCache_Release(OtkGCCacheItem *item)
222 void OtkGCCache_Purge()
226 for (i = 0; i < gccache->cache_total_size; ++i) {
227 OtkGCCacheItem *d = gccache->cache[i];
229 if (d->ctx && d->count == 0) {
230 OtkGCCache_InternalRelease(d->ctx);