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