don't include "cvs" in the version (not using cvs anymore :D)
[blackbox.git] / lib / PixmapCache.cc
blob2e66b7875ff060eebd9bfa9f3ec0b0ed1a7751f3
1 // -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
2 // PixmapCache.cc for Blackbox - an X11 Window manager
3 // Copyright (c) 2001 - 2005 Sean 'Shaleh' Perry <shaleh@debian.org>
4 // Copyright (c) 1997 - 2000, 2002 - 2005
5 // Bradley T Hughes <bhughes at trolltech.com>
6 //
7 // Permission is hereby granted, free of charge, to any person obtaining a
8 // copy of this software and associated documentation files (the "Software"),
9 // to deal in the Software without restriction, including without limitation
10 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 // and/or sell copies of the Software, and to permit persons to whom the
12 // Software is furnished to do so, subject to the following conditions:
14 // The above copyright notice and this permission notice shall be included in
15 // all copies or substantial portions of the Software.
17 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23 // DEALINGS IN THE SOFTWARE.
26 #include "PixmapCache.hh"
27 #include "Display.hh"
28 #include "Image.hh"
29 #include "Texture.hh"
31 #include <X11/Xlib.h>
32 #include <assert.h>
33 #include <stdio.h>
35 #include <algorithm>
36 #include <list>
38 // #define PIXMAPCACHE_DEBUG
41 namespace bt {
43 class RealPixmapCache {
44 public:
45 RealPixmapCache(const Display &display);
46 ~RealPixmapCache(void);
48 Pixmap find(unsigned int screen,
49 const Texture &texture,
50 unsigned int width, unsigned int height,
51 Pixmap old_pixmap = 0ul);
52 void release(Pixmap pixmap);
54 void clear(bool force);
56 struct CacheItem {
57 const Texture texture;
58 const unsigned int screen;
59 const unsigned int width;
60 const unsigned int height;
61 Pixmap pixmap;
62 unsigned int count;
64 inline CacheItem(void)
65 : screen(~0u), width(0u), height(0u),
66 pixmap(0ul), count(0u)
67 { }
68 inline CacheItem(const unsigned int s, const Texture &t,
69 const unsigned int w, const unsigned int h)
70 : texture(t), screen(s), width(w), height(h),
71 pixmap(0ul), count(1u)
72 { }
74 inline bool operator==(const CacheItem &x) const {
75 return texture == x.texture &&
76 screen == x.screen &&
77 width == x.width &&
78 height == x.height;
82 struct PixmapMatch {
83 inline PixmapMatch(Pixmap p)
84 : pixmap(p)
85 { }
86 inline bool operator()(const RealPixmapCache::CacheItem& item) const
87 { return item.pixmap == pixmap; }
89 const Pixmap pixmap;
92 const Display &_display;
94 typedef std::list<CacheItem> Cache;
95 Cache cache;
99 static RealPixmapCache *realpixmapcache = 0;
100 static unsigned long maxmem_usage = 2ul*1024ul*1024ul; // 2mb default
101 static unsigned long mem_usage = 0ul;
104 void createPixmapCache(const Display &display) {
105 assert(realpixmapcache == 0);
106 realpixmapcache = new RealPixmapCache(display);
110 void destroyPixmapCache(void) {
111 delete realpixmapcache;
112 realpixmapcache = 0;
114 assert(mem_usage == 0ul);
117 } // namespace bt
120 bt::RealPixmapCache::RealPixmapCache(const Display &display)
121 : _display(display)
125 bt::RealPixmapCache::~RealPixmapCache(void)
126 { clear(true); }
129 Pixmap bt::RealPixmapCache::find(unsigned int screen,
130 const Texture &texture,
131 unsigned int width, unsigned int height,
132 Pixmap old_pixmap) {
133 release(old_pixmap);
135 if (texture.texture() == (Texture::Flat | Texture::Solid))
136 return None;
138 if (texture.texture() == Texture::Parent_Relative)
139 return ParentRelative;
141 Pixmap p;
142 // find one in the cache
143 CacheItem item(screen, texture, width, height);
144 Cache::iterator it = std::find(cache.begin(), cache.end(), item);
146 if (it != cache.end()) {
147 // found
148 ++(it->count);
150 p = it->pixmap;
152 #ifdef PIXMAPCACHE_DEBUG
153 fprintf(stderr, "bt::PixmapCache: use %08lx %4ux%4u, count %4u\n",
154 it->pixmap, width, height, it->count);
155 #endif // PIXMAPCACHE_DEBUG
156 } else {
157 Image image(width, height);
158 p = image.render(_display, screen, texture);
160 if (p) {
161 item.pixmap = p;
163 #ifdef PIXMAPCACHE_DEBUG
164 fprintf(stderr,
165 "bt::PixmapCache: add %08lx %4ux%4u\n"
166 " mem %8lu max %8lu\n",
167 p, width, height, mem_usage, maxmem_usage);
168 #endif // PIXMAPCACHE_DEBUG
170 cache.push_front(item);
172 // keep track of memory usage server side
173 const unsigned long mem =
174 ( ( width * height ) * (_display.screenInfo(screen).depth() / 8 ) );
175 mem_usage += mem;
176 if (mem_usage > maxmem_usage)
177 clear(false);
179 #ifdef PIXMAPCACHE_DEBUG
180 if (mem_usage > maxmem_usage) {
181 fprintf(stderr,
182 "bt::PixmapCache: maximum size (%lu kb) exceeded\n"
183 "bt::PixmapCache: current size: %lu kb\n",
184 maxmem_usage / 1024, mem_usage / 1024);
186 #endif // PIXMAPCACHE_DEBUG
190 return p;
194 void bt::RealPixmapCache::release(Pixmap pixmap) {
195 if (!pixmap || pixmap == ParentRelative)
196 return;
198 Cache::iterator it = std::find_if(cache.begin(), cache.end(),
199 PixmapMatch(pixmap));
200 assert(it != cache.end() && it->count > 0);
202 // decrement the refcount
203 --(it->count);
205 #ifdef PIXMAPCACHE_DEBUG
206 fprintf(stderr, "bt::PixmapCache: rel %08lx %4ux%4u, count %4u\n",
207 it->pixmap, it->width, it->height, it->count);
208 #endif // PIXMAPCACHE_DEBUG
212 void bt::RealPixmapCache::clear(bool force) {
213 if (cache.empty())
214 return; // nothing to do
216 #ifdef PIXMAPCACHE_DEBUG
217 fprintf(stderr, "bt::PixmapCache: clearing cache, %u entries\n",
218 cache.size());
219 #endif // PIXMAPCACHE_DEBUG
221 Cache::iterator it = cache.begin();
222 while (it != cache.end()) {
223 if (it->count != 0 && !force) {
224 #ifdef PIXMAPCACHE_DEBUG
225 fprintf(stderr, "bt::PixmapCache: skp %08lx %4ux%4u, count %4u\n",
226 it->pixmap, it->width, it->height, it->count);
227 #endif // PIXMAPCACHE_DEBUG
229 ++it;
230 continue;
233 #ifdef PIXMAPCACHE_DEBUG
234 fprintf(stderr, "bt::PixmapCache: fre %08lx %4ux%4u\n",
235 it->pixmap, it->width, it->height);
236 #endif // PIXMAPCACHE_DEBUG
238 // keep track of memory usage server side
239 const unsigned long mem =
240 ( ( it->width * it->height ) *
241 (_display.screenInfo(it->screen).depth() / 8 ) );
242 assert(mem <= mem_usage);
243 mem_usage -= mem;
245 // free pixmap
246 XFreePixmap(_display.XDisplay(), it->pixmap);
248 // remove from cache
249 it = cache.erase(it);
252 #ifdef PIXMAPCACHE_DEBUG
253 fprintf(stderr,
254 "bt::PixmapCache: cleared, %u entries remain\n"
255 " mem %8lu max %8lu\n",
256 cache.size(), mem_usage, maxmem_usage);
257 #endif // PIXMAPCACHE_DEBUG
261 unsigned long bt::PixmapCache::cacheLimit(void)
262 { return maxmem_usage / 1024; }
265 void bt::PixmapCache::setCacheLimit(unsigned long limit)
266 { maxmem_usage = limit * 1024; }
269 unsigned long bt::PixmapCache::memoryUsage(void)
270 { return mem_usage / 1024; }
273 Pixmap bt::PixmapCache::find(unsigned int screen,
274 const Texture &texture,
275 unsigned int width, unsigned int height,
276 Pixmap old_pixmap)
277 { return realpixmapcache->find(screen, texture, width, height, old_pixmap); }
280 void bt::PixmapCache::release(Pixmap pixmap)
281 { realpixmapcache->release(pixmap); }
284 void bt::PixmapCache::clearCache(void)
285 { realpixmapcache->clear(false); }