openbox/otk/color.cc

217 lines
4.2 KiB
C++
Raw Normal View History

2002-11-01 03:27:41 +00:00
// -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
#ifdef HAVE_CONFIG_H
# include "../config.h"
#endif // HAVE_CONFIG_H
extern "C" {
#include <stdio.h>
}
#include <assert.h>
#include "color.hh"
#include "display.hh"
#include "screeninfo.hh"
2002-11-01 03:27:41 +00:00
namespace otk {
2002-11-01 03:27:41 +00:00
Color::ColorCache Color::colorcache;
bool Color::cleancache = false;
2002-11-01 03:27:41 +00:00
Color::Color(unsigned int _screen)
: allocated(false), r(-1), g(-1), b(-1), p(0), scrn(_screen)
2002-11-01 03:27:41 +00:00
{}
Color::Color(int _r, int _g, int _b, unsigned int _screen)
: allocated(false), r(_r), g(_g), b(_b), p(0), scrn(_screen)
2002-11-01 03:27:41 +00:00
{}
Color::Color(const std::string &_name, unsigned int _screen)
: allocated(false), r(-1), g(-1), b(-1), p(0), scrn(_screen),
2002-11-01 03:27:41 +00:00
colorname(_name) {
parseColorName();
}
Color::~Color(void) {
2002-11-01 03:27:41 +00:00
deallocate();
}
void Color::setScreen(unsigned int _screen) {
if (_screen == screen()) {
2002-11-01 03:27:41 +00:00
// nothing to do
return;
}
deallocate();
scrn = _screen;
if (! colorname.empty()) {
parseColorName();
}
}
unsigned long Color::pixel(void) const {
2002-11-01 03:27:41 +00:00
if (! allocated) {
// mutable
Color *that = (Color *) this;
2002-11-01 03:27:41 +00:00
that->allocate();
}
return p;
}
void Color::parseColorName(void) {
2002-11-01 03:27:41 +00:00
if (colorname.empty()) {
fprintf(stderr, "Color: empty colorname, cannot parse (using black)\n");
2002-11-01 03:27:41 +00:00
setRGB(0, 0, 0);
}
if (scrn == ~(0u))
scrn = DefaultScreen(Display::display);
Colormap colormap = Display::screenInfo(scrn)->colormap();
2002-11-01 03:27:41 +00:00
// get rgb values from colorname
XColor xcol;
xcol.red = 0;
xcol.green = 0;
xcol.blue = 0;
xcol.pixel = 0;
if (! XParseColor(Display::display, colormap,
2002-11-01 03:27:41 +00:00
colorname.c_str(), &xcol)) {
fprintf(stderr, "Color::allocate: color parse error: \"%s\"\n",
2002-11-01 03:27:41 +00:00
colorname.c_str());
setRGB(0, 0, 0);
return;
}
setRGB(xcol.red >> 8, xcol.green >> 8, xcol.blue >> 8);
}
void Color::allocate(void) {
if (scrn == ~(0u)) scrn = DefaultScreen(Display::display);
Colormap colormap = Display::screenInfo(scrn)->colormap();
2002-11-01 03:27:41 +00:00
if (! isValid()) {
if (colorname.empty()) {
fprintf(stderr, "Color: cannot allocate invalid color (using black)\n");
2002-11-01 03:27:41 +00:00
setRGB(0, 0, 0);
} else {
parseColorName();
}
}
// see if we have allocated this color before
RGB rgb(scrn, r, g, b);
2002-11-01 03:27:41 +00:00
ColorCache::iterator it = colorcache.find(rgb);
if (it != colorcache.end()) {
// found
allocated = true;
p = (*it).second.p;
(*it).second.count++;
return;
}
// allocate color from rgb values
XColor xcol;
xcol.red = r | r << 8;
xcol.green = g | g << 8;
xcol.blue = b | b << 8;
xcol.pixel = 0;
if (! XAllocColor(Display::display, colormap, &xcol)) {
fprintf(stderr, "Color::allocate: color alloc error: rgb:%x/%x/%x\n",
2002-11-01 03:27:41 +00:00
r, g, b);
xcol.pixel = 0;
}
p = xcol.pixel;
allocated = true;
colorcache.insert(ColorCacheItem(rgb, PixelRef(p)));
if (cleancache)
doCacheCleanup();
}
void Color::deallocate(void) {
2002-11-01 03:27:41 +00:00
if (! allocated)
return;
ColorCache::iterator it = colorcache.find(RGB(scrn, r, g, b));
2002-11-01 03:27:41 +00:00
if (it != colorcache.end()) {
if ((*it).second.count >= 1)
(*it).second.count--;
}
if (cleancache)
doCacheCleanup();
allocated = false;
}
Color &Color::operator=(const Color &c) {
2002-11-01 03:27:41 +00:00
deallocate();
setRGB(c.r, c.g, c.b);
colorname = c.colorname;
scrn = c.scrn;
return *this;
}
void Color::cleanupColorCache(void) {
2002-11-01 03:27:41 +00:00
cleancache = true;
}
void Color::doCacheCleanup(void) {
2002-11-01 03:27:41 +00:00
// ### TODO - support multiple displays!
ColorCache::iterator it = colorcache.begin();
if (it == colorcache.end()) {
// nothing to do
return;
}
unsigned long *pixels = new unsigned long[ colorcache.size() ];
int i;
unsigned count;
2002-11-01 03:27:41 +00:00
for (i = 0; i < ScreenCount(Display::display); i++) {
2002-11-01 03:27:41 +00:00
count = 0;
it = colorcache.begin();
while (it != colorcache.end()) {
if ((*it).second.count != 0 || (*it).first.screen != i) {
++it;
continue;
}
pixels[ count++ ] = (*it).second.p;
ColorCache::iterator it2 = it;
++it;
colorcache.erase(it2);
}
if (count > 0)
XFreeColors(Display::display,
Display::screenInfo(i)->colormap(),
2002-11-01 03:27:41 +00:00
pixels, count, 0);
}
delete [] pixels;
cleancache = false;
}
}