]> Dogcows Code - chaz/openbox/blob - otk_c/gccache.c
move where transient shit will be
[chaz/openbox] / otk_c / gccache.c
1 // -*- mode: C; indent-tabs-mode: nil; c-basic-offset: 2; -*-
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 = NULL;
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 = color->pixel;
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 return self;
86 }
87
88
89 void OtkGCCache_Initialize()
90 {
91 unsigned int i;
92
93 gccache = malloc(sizeof(OtkGCCache));
94
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;
99
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();
104
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();
108 }
109
110
111 /*void OtkGCCache_Destroy()
112 {
113 unsigned int i;
114
115 for (i = 0; i < gccache->context_count; ++i)
116 OtkGCCacheContext_Destroy(gccache->contexts[i]);
117
118 for (i = 0; i < gccache->cache_total_size; ++i)
119 free(gccache->cache[i]);
120
121 free(gccache->contexts);
122 free(gccache->cache);
123 free(gccache);
124 gccache = NULL;
125 }*/
126
127 static OtkGCCacheContext *nextContext(int screen)
128 {
129 Window hd = OtkDisplay_ScreenInfo(OBDisplay, screen)->root_window;
130 OtkGCCacheContext *c;
131 unsigned int i;
132
133 for (i = 0; i < gccache->context_count; ++i) {
134 c = gccache->contexts[i];
135
136 if (! c->gc) {
137 c->gc = XCreateGC(OBDisplay->display, hd, 0, 0);
138 c->used = False;
139 c->screen = screen;
140 }
141 if (! c->used && c->screen == screen)
142 return c;
143 }
144
145 fprintf(stderr, "OtkGCCache: context fault!\n");
146 abort();
147 return NULL; // shut gcc up
148 }
149
150
151 static void OtkGCCache_InternalRelease(OtkGCCacheContext *ctx)
152 {
153 ctx->used = False;
154 }
155
156 OtkGCCacheItem *OtkGCCache_Find(OtkColor *color, XFontStruct *font,
157 int function, int subwindow, int linewidth)
158 {
159 const unsigned long pixel = color->pixel;
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;
165
166 /*
167 this will either loop cache_buckets times then return/abort or
168 it will stop matching
169 */
170 while (c->ctx &&
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)) {
175 prev = c;
176 c = gccache->cache[++k];
177 ++i;
178 continue;
179 }
180 if (c->count == 0 && c->ctx->screen == screen) {
181 // use this cache item
182 OtkGCCacheContext_Set(c->ctx, color, font, function, subwindow,
183 linewidth);
184 c->ctx->used = True;
185 c->count = 1;
186 c->hits = 1;
187 return c;
188 }
189 // cache fault!
190 fprintf(stderr, "OtkGCCache: cache fault, count: %d, screen: %d, item screen: %d\n", c->count, screen, c->ctx->screen);
191 abort();
192 }
193
194 if (c->ctx) {
195 // reuse existing context
196 if (font && font->fid && font->fid != c->ctx->fontid)
197 OtkGCCacheContext_SetFont(c->ctx, font);
198 c->count++;
199 c->hits++;
200 if (prev && c->hits > prev->hits) {
201 gccache->cache[k] = prev;
202 gccache->cache[k-1] = c;
203 }
204 } else {
205 c->ctx = nextContext(screen);
206 OtkGCCacheContext_Set(c->ctx, color, font, function, subwindow, linewidth);
207 c->ctx->used = True;
208 c->count = 1;
209 c->hits = 1;
210 }
211
212 return c;
213 }
214
215
216 void OtkGCCache_Release(OtkGCCacheItem *item)
217 {
218 item->count--;
219 }
220
221
222 void OtkGCCache_Purge()
223 {
224 unsigned int i;
225
226 for (i = 0; i < gccache->cache_total_size; ++i) {
227 OtkGCCacheItem *d = gccache->cache[i];
228
229 if (d->ctx && d->count == 0) {
230 OtkGCCache_InternalRelease(d->ctx);
231 d->ctx = 0;
232 }
233 }
234 }
This page took 0.051756 seconds and 4 git commands to generate.