]> icculus.org git repositories - mikachu/openbox.git/blob - src/Color.cc
fixed the geometry window not getting the proper pixmap. This was caused by using...
[mikachu/openbox.git] / src / Color.cc
1 // -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
2 // Color.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 #include "Color.hh"
29 #include "BaseDisplay.hh"
30
31 extern "C" {
32 #include <stdio.h>
33 }
34
35
36 BColor::ColorCache BColor::colorcache;
37 bool BColor::cleancache = false;
38
39 BColor::BColor(const BaseDisplay * const _display, unsigned int _screen)
40   : allocated(false), r(-1), g(-1), b(-1), p(0), dpy(_display), scrn(_screen)
41 {}
42
43 BColor::BColor(int _r, int _g, int _b,
44                const BaseDisplay * const _display, unsigned int _screen)
45   : allocated(false), r(_r), g(_g), b(_b), p(0), dpy(_display), scrn(_screen)
46 {}
47
48
49 BColor::BColor(const std::string &_name,
50                const BaseDisplay * const _display, unsigned int _screen)
51   : allocated(false), r(-1), g(-1), b(-1), p(0), dpy(_display), scrn(_screen),
52     colorname(_name) {
53   parseColorName();
54 }
55
56
57 BColor::~BColor(void) {
58   deallocate();
59 }
60
61
62 void BColor::setDisplay(const BaseDisplay * const _display,
63                         unsigned int _screen) {
64   if (_display == display() && _screen == screen()) {
65     // nothing to do
66     return;
67   }
68
69   deallocate();
70
71   dpy = _display;
72   scrn = _screen;
73
74   if (! colorname.empty()) {
75     parseColorName();
76   }
77 }
78
79
80 unsigned long BColor::pixel(void) const {
81   if (! allocated) {
82     // mutable
83     BColor *that = (BColor *) this;
84     that->allocate();
85   }
86
87   return p;
88 }
89
90
91 void BColor::parseColorName(void) {
92   assert(dpy != 0);
93
94   if (colorname.empty()) {
95     fprintf(stderr, "BColor: empty colorname, cannot parse (using black)\n");
96     setRGB(0, 0, 0);
97   }
98
99   if (scrn == ~(0u))
100     scrn = DefaultScreen(display()->getXDisplay());
101   Colormap colormap = display()->getScreenInfo(scrn)->getColormap();
102
103   // get rgb values from colorname
104   XColor xcol;
105   xcol.red = 0;
106   xcol.green = 0;
107   xcol.blue = 0;
108   xcol.pixel = 0;
109
110   if (! XParseColor(display()->getXDisplay(), colormap,
111                     colorname.c_str(), &xcol)) {
112     fprintf(stderr, "BColor::allocate: color parse error: \"%s\"\n",
113             colorname.c_str());
114     setRGB(0, 0, 0);
115     return;
116   }
117
118   setRGB(xcol.red >> 8, xcol.green >> 8, xcol.blue >> 8);
119 }
120
121
122 void BColor::allocate(void) {
123   assert(dpy != 0);
124
125   if (scrn == ~(0u)) scrn = DefaultScreen(display()->getXDisplay());
126   Colormap colormap = display()->getScreenInfo(scrn)->getColormap();
127
128   if (! isValid()) {
129     if (colorname.empty()) {
130       fprintf(stderr, "BColor: cannot allocate invalid color (using black)\n");
131       setRGB(0, 0, 0);
132     } else {
133       parseColorName();
134     }
135   }
136
137   // see if we have allocated this color before
138   RGB rgb(display(), scrn, r, g, b);
139   ColorCache::iterator it = colorcache.find(rgb);
140   if (it != colorcache.end()) {
141     // found
142     allocated = true;
143     p = (*it).second.p;
144     (*it).second.count++;
145     return;
146   }
147
148   // allocate color from rgb values
149   XColor xcol;
150   xcol.red =   r | r << 8;
151   xcol.green = g | g << 8;
152   xcol.blue =  b | b << 8;
153   xcol.pixel = 0;
154
155   if (! XAllocColor(display()->getXDisplay(), colormap, &xcol)) {
156     fprintf(stderr, "BColor::allocate: color alloc error: rgb:%x/%x/%x\n",
157             r, g, b);
158     xcol.pixel = 0;
159   }
160
161   p = xcol.pixel;
162   allocated = true;
163
164   colorcache.insert(ColorCacheItem(rgb, PixelRef(p)));
165
166   if (cleancache)
167     doCacheCleanup();
168 }
169
170
171 void BColor::deallocate(void) {
172   if (! allocated)
173     return;
174
175   assert(dpy != 0);
176
177   ColorCache::iterator it = colorcache.find(RGB(display(), scrn, r, g, b));
178   if (it != colorcache.end()) {
179     if ((*it).second.count >= 1)
180       (*it).second.count--;
181   }
182
183   if (cleancache)
184     doCacheCleanup();
185
186   allocated = false;
187 }
188
189
190 BColor &BColor::operator=(const BColor &c) {
191   deallocate();
192
193   setRGB(c.r, c.g, c.b);
194   colorname = c.colorname;
195   dpy = c.dpy;
196   scrn = c.scrn;
197   return *this;
198 }
199
200
201 void BColor::cleanupColorCache(void) {
202   cleancache = true;
203 }
204
205
206 void BColor::doCacheCleanup(void) {
207   // ### TODO - support multiple displays!
208   ColorCache::iterator it = colorcache.begin();
209   if (it == colorcache.end()) {
210     // nothing to do
211     return;
212   }
213
214   const BaseDisplay* const display = (*it).first.display;
215   unsigned long *pixels = new unsigned long[ colorcache.size() ];
216   unsigned int i, count;
217
218   for (i = 0; i < display->getNumberOfScreens(); i++) {
219     count = 0;
220     it = colorcache.begin();
221
222     while (it != colorcache.end()) {
223       if ((*it).second.count != 0 || (*it).first.screen != i) {
224         ++it;
225         continue;
226       }
227
228       pixels[ count++ ] = (*it).second.p;
229       ColorCache::iterator it2 = it;
230       ++it;
231       colorcache.erase(it2);
232     }
233
234     if (count > 0)
235       XFreeColors(display->getXDisplay(),
236                   display->getScreenInfo(i)->getColormap(),
237                   pixels, count, 0);
238   }
239
240   delete [] pixels;
241   cleancache = false;
242 }