allow the user to override the rootCommand from their ~/.blackboxrc
[blackbox.git] / lib / PixmapCache.cc
blob6073761583bac03933f75e337db5a245299fceff
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 if (mem_usage > maxmem_usage) {
180 fprintf(stderr,
181 "bt::PixmapCache: maximum size (%lu kb) exceeded\n"
182 "bt::PixmapCache: current size: %lu kb\n",
183 maxmem_usage / 1024, mem_usage / 1024);
188 return p;
192 void bt::RealPixmapCache::release(Pixmap pixmap) {
193 if (!pixmap || pixmap == ParentRelative)
194 return;
196 Cache::iterator it = std::find_if(cache.begin(), cache.end(),
197 PixmapMatch(pixmap));
198 assert(it != cache.end() && it->count > 0);
200 // decrement the refcount
201 --(it->count);
203 #ifdef PIXMAPCACHE_DEBUG
204 fprintf(stderr, "bt::PixmapCache: rel %08lx %4ux%4u, count %4u\n",
205 it->pixmap, it->width, it->height, it->count);
206 #endif // PIXMAPCACHE_DEBUG
210 void bt::RealPixmapCache::clear(bool force) {
211 if (cache.empty())
212 return; // nothing to do
214 #ifdef PIXMAPCACHE_DEBUG
215 fprintf(stderr, "bt::PixmapCache: clearing cache, %u entries\n",
216 cache.size());
217 #endif // PIXMAPCACHE_DEBUG
219 Cache::iterator it = cache.begin();
220 while (it != cache.end()) {
221 if (it->count != 0 && !force) {
222 #ifdef PIXMAPCACHE_DEBUG
223 fprintf(stderr, "bt::PixmapCache: skp %08lx %4ux%4u, count %4u\n",
224 it->pixmap, it->width, it->height, it->count);
225 #endif // PIXMAPCACHE_DEBUG
227 ++it;
228 continue;
231 #ifdef PIXMAPCACHE_DEBUG
232 fprintf(stderr, "bt::PixmapCache: fre %08lx %4ux%4u\n",
233 it->pixmap, it->width, it->height);
234 #endif // PIXMAPCACHE_DEBUG
236 // keep track of memory usage server side
237 const unsigned long mem =
238 ( ( it->width * it->height ) *
239 (_display.screenInfo(it->screen).depth() / 8 ) );
240 assert(mem <= mem_usage);
241 mem_usage -= mem;
243 // free pixmap
244 XFreePixmap(_display.XDisplay(), it->pixmap);
246 // remove from cache
247 it = cache.erase(it);
250 #ifdef PIXMAPCACHE_DEBUG
251 fprintf(stderr,
252 "bt::PixmapCache: cleared, %u entries remain\n"
253 " mem %8lu max %8lu\n",
254 cache.size(), mem_usage, maxmem_usage);
255 #endif // PIXMAPCACHE_DEBUG
259 unsigned long bt::PixmapCache::cacheLimit(void)
260 { return maxmem_usage / 1024; }
263 void bt::PixmapCache::setCacheLimit(unsigned long limit)
264 { maxmem_usage = limit * 1024; }
267 unsigned long bt::PixmapCache::memoryUsage(void)
268 { return mem_usage / 1024; }
271 Pixmap bt::PixmapCache::find(unsigned int screen,
272 const Texture &texture,
273 unsigned int width, unsigned int height,
274 Pixmap old_pixmap)
275 { return realpixmapcache->find(screen, texture, width, height, old_pixmap); }
278 void bt::PixmapCache::release(Pixmap pixmap)
279 { realpixmapcache->release(pixmap); }
282 void bt::PixmapCache::clearCache(void)
283 { realpixmapcache->clear(false); }