]> Dogcows Code - chaz/openbox/blob - otk_c/gccache.c
7d96677c747a3d34e9c4bbd88c9c751c4f9bcb8a
[chaz/openbox] / otk_c / gccache.c
1 // -*- mode: C; indent-tabs-mode: nil; -*-
2
3 #include "../config.h"
4 #include "gccache.h"
5 #include "screeninfo.h"
6
7 #ifdef HAVE_STDLIB_H
8 # include <stdlib.h>
9 #endif
10
11 static OtkGCCache *gccache;
12
13 OtkGCCacheContext *OtkGCCacheContext_New()
14 {
15 OtkGCCacheContext *self = malloc(sizeof(OtkGCCacheContext));
16
17 self->gc = 0;
18 self->pixel = 0ul;
19 self->fontid = 0ul;
20 self->function = 0;
21 self->subwindow = 0;
22 self->used = False;
23 self->screen = ~0;
24 self->linewidth = 0;
25
26 return self;
27 }
28
29 void OtkGCCacheContext_Destroy(OtkGCCacheContext *self)
30 {
31 if (self->gc)
32 XFreeGC(OBDisplay->display, self->gc);
33 free(self);
34 }
35
36 void OtkGCCacheContext_Set(OtkGCCacheContext *self,
37 OtkColor *color, XFontStruct *font,
38 int function, int subwindow, int linewidth)
39 {
40 XGCValues gcv;
41 unsigned long mask;
42
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;
48
49 mask = GCForeground | GCFunction | GCSubwindowMode | GCLineWidth |
50 GCCapStyle;
51
52 if (font) {
53 self->fontid = gcv.font = font->fid;
54 mask |= GCFont;
55 } else {
56 self->fontid = 0;
57 }
58
59 XChangeGC(OBDisplay->display, self->gc, mask, &gcv);
60 }
61
62 void OtkGCCacheContext_SetFont(OtkGCCacheContext *self,
63 XFontStruct *font)
64 {
65 if (!font) {
66 self->fontid = 0;
67 return;
68 }
69
70 XGCValues gcv;
71 self->fontid = gcv.font = font->fid;
72 XChangeGC(OBDisplay->display, self->gc, GCFont, &gcv);
73 }
74
75
76 OtkGCCacheItem *OtkGCCacheItem_New()
77 {
78 OtkGCCacheItem *self = malloc(sizeof(OtkGCCacheItem));
79
80 self->ctx = 0;
81 self->count = 0;
82 self->hits = 0;
83 self->fault = False;
84 }
85
86
87 void OtkGCCache_Initialize(int screen_count)
88 {
89 int i;
90
91 gccache = malloc(sizeof(OtkGCCache));
92
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;
97
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();
102
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();
106 }
107
108
109 void OtkGCCache_Destroy()
110 {
111 int i;
112
113 for (i = 0; i < gccache->context_count; ++i)
114 OtkGCCacheContext_Destroy(gccache->contexts[i]);
115
116 for (i = 0; i < gccache->cache_total_size; ++i)
117 free(gccache->cache[i]);
118
119 free(gccache->contexts);
120 free(gccache->cache);
121 free(gccache);
122 gccache = NULL;
123 }
124
125 OtkGCCacheContext *OtkGCCache_NextContext(int screen)
126 {
127 Window hd = OtkDisplay_ScreenInfo(OBDisplay, screen)->root_window;
128 OtkGCCacheContext *c;
129 int i;
130
131 for (i = 0; i < gccache->context_count; ++i) {
132 c = gccache->contexts[i];
133
134 if (! c->gc) {
135 c->gc = XCreateGC(OBDisplay->display, hd, 0, 0);
136 c->used = False;
137 c->screen = screen;
138 }
139 if (! c->used && c->screen == screen)
140 return c;
141 }
142
143 fprintf(stderr, "OtkGCCache: context fault!\n");
144 abort();
145 return NULL; // shut gcc up
146 }
147
148
149 static void OtkGCCache_InternalRelease(OtkGCCacheContext *ctx)
150 {
151 ctx->used = False;
152 }
153
154 OtkGCCacheItem *OtkGCCache_Find(OtkColor *color, XFontStruct *font,
155 int function, int subwindow, int linewidth)
156 {
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;
163
164 /*
165 this will either loop cache_buckets times then return/abort or
166 it will stop matching
167 */
168 while (c->ctx &&
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)) {
173 prev = c;
174 c = gccache->cache[++k];
175 ++i;
176 continue;
177 }
178 if (c->count == 0 && c->ctx->screen == screen) {
179 // use this cache item
180 OtkGCCacheContext_Set(c->ctx, color, font, function, subwindow,
181 linewidth);
182 c->ctx->used = True;
183 c->count = 1;
184 c->hits = 1;
185 return c;
186 }
187 // cache fault!
188 fprintf(stderr, "OtkGCCache: cache fault, count: %d, screen: %d, item screen: %d\n", c->count, screen, c->ctx->screen);
189 abort();
190 }
191
192 if (c->ctx) {
193 // reuse existing context
194 if (font && font->fid && font->fid != c->ctx->fontid)
195 OtkGCCacheContext_SetFont(c->ctx, font);
196 c->count++;
197 c->hits++;
198 if (prev && c->hits > prev->hits) {
199 gccache->cache[k] = prev;
200 gccache->cache[k-1] = c;
201 }
202 } else {
203 c->ctx = OtkGCCache_NextContext(screen);
204 OtkGCCacheContext_Set(c->ctx, color, font, function, subwindow, linewidth);
205 c->ctx->used = True;
206 c->count = 1;
207 c->hits = 1;
208 }
209
210 return c;
211 }
212
213
214 void OtkGCCache_Release(OtkGCCacheItem *item)
215 {
216 item->count--;
217 }
218
219
220 void OtkGCCache_Purge()
221 {
222 int i;
223
224 for (i = 0; i < gccache->cache_total_size; ++i) {
225 OtkGCCacheItem *d = gccache->cache[i];
226
227 if (d->ctx && d->count == 0) {
228 release(d->ctx);
229 d->ctx = 0;
230 }
231 }
232 }
This page took 0.046373 seconds and 4 git commands to generate.