]> icculus.org git repositories - mikachu/openbox.git/blob - src/GCCache.cc
backing out sticky transients change, this should go in the netwm branch
[mikachu/openbox.git] / src / GCCache.cc
1 // -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
2 // GCCache.cc for Blackbox - an X11 Window manager
3 // Copyright (c) 2001 - 2002 Sean 'Shaleh' Perry <shaleh at debian.org>
4 // Copyright (c) 1997 - 2000, 2002 Bradley T Hughes <bhughes at trolltech.com>
5 //
6 // Permission is hereby granted, free of charge, to any person obtaining a
7 // copy of this software and associated documentation files (the "Software"),
8 // to deal in the Software without restriction, including without limitation
9 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 // and/or sell copies of the Software, and to permit persons to whom the
11 // Software is furnished to do so, subject to the following conditions:
12 //
13 // The above copyright notice and this permission notice shall be included in
14 // all copies or substantial portions of the Software.
15 //
16 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 // DEALINGS IN THE SOFTWARE.
23
24 #ifdef HAVE_CONFIG_H
25 #  include "../config.h"
26 #endif // HAVE_CONFIG_H
27
28 extern "C" {
29 #include <stdio.h>
30 }
31
32 #include "GCCache.hh"
33 #include "BaseDisplay.hh"
34 #include "Color.hh"
35 #include "Util.hh"
36
37
38 void BGCCacheContext::set(const BColor &_color,
39                           const XFontStruct * const _font,
40                           const int _function, const int _subwindow) {
41   XGCValues gcv;
42   pixel = gcv.foreground = _color.pixel();
43   function = gcv.function = _function;
44   subwindow = gcv.subwindow_mode = _subwindow;
45   unsigned long mask = GCForeground | GCFunction | GCSubwindowMode;
46
47   if (_font) {
48     fontid = gcv.font = _font->fid;
49     mask |= GCFont;
50   } else {
51     fontid = 0;
52   }
53
54   XChangeGC(display->getXDisplay(), gc, mask, &gcv);
55 }
56
57
58 void BGCCacheContext::set(const XFontStruct * const _font) {
59   if (! _font) {
60     fontid = 0;
61     return;
62   }
63
64   XGCValues gcv;
65   fontid = gcv.font = _font->fid;
66   XChangeGC(display->getXDisplay(), gc, GCFont, &gcv);
67 }
68
69
70 BGCCache::BGCCache(const BaseDisplay * const _display)
71   : display(_display),  context_count(128u),
72     cache_size(16u), cache_buckets(8u),
73     cache_total_size(cache_size * cache_buckets) {
74
75   contexts = new BGCCacheContext*[context_count];
76   unsigned int i;
77   for (i = 0; i < context_count; i++) {
78     contexts[i] = new BGCCacheContext(display);
79   }
80
81   cache = new BGCCacheItem*[cache_total_size];
82   for (i = 0; i < cache_total_size; ++i) {
83     cache[i] = new BGCCacheItem;
84   }
85 }
86
87
88 BGCCache::~BGCCache(void) {
89   std::for_each(contexts, contexts + context_count, PointerAssassin());
90   std::for_each(cache, cache + cache_total_size, PointerAssassin());
91   delete [] cache;
92   delete [] contexts;
93 }
94
95
96 BGCCacheContext *BGCCache::nextContext(unsigned int scr) {
97   Window hd = display->getScreenInfo(scr)->getRootWindow();
98
99   BGCCacheContext *c;
100
101   for (unsigned int i = 0; i < context_count; ++i) {
102     c = contexts[i];
103
104     if (! c->gc) {
105       c->gc = XCreateGC(display->getXDisplay(), hd, 0, 0);
106       c->used = false;
107       c->screen = scr;
108     }
109     if (! c->used && c->screen == scr) {
110       c->used = true;
111       return c;
112     }
113   }
114
115   fprintf(stderr, "BGCCache: context fault!\n");
116   abort();
117   return (BGCCacheContext*) 0; // not reached
118 }
119
120
121 void BGCCache::release(BGCCacheContext *ctx) {
122   ctx->used = false;
123 }
124
125
126 BGCCacheItem *BGCCache::find(const BColor &_color,
127                              const XFontStruct * const _font,
128                              int _function, int _subwindow) {
129   const unsigned long pixel = _color.pixel();
130   const unsigned int screen = _color.screen();
131   const int key = _color.red() ^ _color.green() ^ _color.blue();
132   int k = (key % cache_size) * cache_buckets;
133   int i = 0; // loop variable
134   BGCCacheItem *c = cache[ k ], *prev = 0;
135
136   // this will either loop 8 times then return/abort or it will stop matching
137   while (c->ctx &&
138          (c->ctx->pixel != pixel || c->ctx->function != _function ||
139           c->ctx->subwindow != _subwindow || c->ctx->screen != screen)) {
140     if (i < 7) {
141       prev = c;
142       c = cache[ ++k ];
143       ++i;
144       continue;
145     }
146     if (c->count == 0 && c->ctx->screen == screen) {
147       // use this cache item
148       c->ctx->set(_color, _font, _function, _subwindow);
149       c->ctx->used = true;
150       c->count = 1;
151       c->hits = 1;
152       return c;
153     }
154     // cache fault!
155     fprintf(stderr, "BGCCache: cache fault\n");
156     abort();
157   }
158
159   const unsigned long fontid = _font ? _font->fid : 0;
160   if (c->ctx) {
161     // reuse existing context
162     if (fontid && fontid != c->ctx->fontid)
163       c->ctx->set(_font);
164     c->count++;
165     c->hits++;
166     if (prev && c->hits > prev->hits) {
167       cache[ k     ] = prev;
168       cache[ k - 1 ] = c;
169     }
170   } else {
171     c->ctx = nextContext(screen);
172     c->ctx->set(_color, _font, _function, _subwindow);
173     c->ctx->used = true;
174     c->count = 1;
175     c->hits = 1;
176   }
177
178   return c;
179 }
180
181
182 void BGCCache::release(BGCCacheItem *_item) {
183   _item->count--;
184 }
185
186
187 void BGCCache::purge(void) {
188   for (unsigned int i = 0; i < cache_total_size; ++i) {
189     BGCCacheItem *d = cache[ i ];
190
191     if (d->ctx && d->count == 0) {
192       release(d->ctx);
193       d->ctx = 0;
194     }
195   }
196 }