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