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