]> icculus.org git repositories - mikachu/openbox.git/blob - otk/color.cc
add next/prev desktop, give them the no_wrap optional arg
[mikachu/openbox.git] / 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 BColor::ColorCache BColor::colorcache;
20 bool BColor::cleancache = false;
21
22 BColor::BColor(unsigned int _screen)
23   : allocated(false), r(-1), g(-1), b(-1), p(0), scrn(_screen)
24 {}
25
26 BColor::BColor(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 BColor::BColor(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 BColor::~BColor(void) {
39   deallocate();
40 }
41
42
43 void BColor::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 BColor::pixel(void) const {
60   if (! allocated) {
61     // mutable
62     BColor *that = (BColor *) this;
63     that->allocate();
64   }
65
66   return p;
67 }
68
69
70 void BColor::parseColorName(void) {
71   if (colorname.empty()) {
72     fprintf(stderr, "BColor: empty colorname, cannot parse (using black)\n");
73     setRGB(0, 0, 0);
74   }
75
76   if (scrn == ~(0u))
77     scrn = DefaultScreen(OBDisplay::display);
78   Colormap colormap = OBDisplay::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(OBDisplay::display, colormap,
88                     colorname.c_str(), &xcol)) {
89     fprintf(stderr, "BColor::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 BColor::allocate(void) {
100   if (scrn == ~(0u)) scrn = DefaultScreen(OBDisplay::display);
101   Colormap colormap = OBDisplay::screenInfo(scrn)->colormap();
102
103   if (! isValid()) {
104     if (colorname.empty()) {
105       fprintf(stderr, "BColor: 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(OBDisplay::display, colormap, &xcol)) {
131     fprintf(stderr, "BColor::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 BColor::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 BColor &BColor::operator=(const BColor &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 BColor::cleanupColorCache(void) {
174   cleancache = true;
175 }
176
177
178 void BColor::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(OBDisplay::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(OBDisplay::display,
208                   OBDisplay::screenInfo(i)->colormap(),
209                   pixels, count, 0);
210   }
211
212   delete [] pixels;
213   cleancache = false;
214 }
215
216 }