#ifdef HAVE_CONFIG_H # include #endif #include "grafix.hh" #include Vector Grafix::all_cached_gcs; Vector Grafix::all_instances; Grafix::Grafix(Display *display, Window window) : _display(display) { XWindowAttributes attr; XGetWindowAttributes(_display, window, &attr); _screen = attr.screen; _colormap = attr.colormap; _depth = attr.depth; _drawable = XCreatePixmap(_display, window, 1, 1, _depth); all_instances.push_back(this); for (int i = 0; i < all_cached_gcs.size(); i++) update_gc(i, 0, &all_cached_gcs[i]); } Grafix::~Grafix() { for (int i = 0; i < _gcs.size(); i++) if (_gcs[i]) XFreeGC(_display, _gcs[i]); XFreeColors(_display, _colormap, &_pixels[0], _pixels.size(), 0); XFreePixmap(_display, _drawable); for (int i = 0; i < all_instances.size(); i++) if (all_instances[i] == this) { all_instances[i] = all_instances.back(); all_instances.pop_back(); } } void Grafix::alloc_color(XColor *xc) { if (XAllocColor(_display, _colormap, xc) == 0) xc->pixel = WhitePixelOfScreen(_screen); else _pixels.push_back(xc->pixel); } void Grafix::update_gc(int number, unsigned long old_mask, GCCache *cache) { if (_gcs.size() <= number) { _gcs.resize(number+1, 0); _gc_foregrounds.resize(number+1, 0); } if ((cache->_mask & GCForeground) != 0 && (old_mask & GCForeground) == 0) { alloc_color(&cache->_foreground); _gc_foregrounds[number] = cache->_foreground.pixel; } cache->_xgcv.foreground = _gc_foregrounds[number]; if (!_gcs[number]) _gcs[number] = XCreateGC(_display, _drawable, cache->_mask, &cache->_xgcv); else XChangeGC(_display, _gcs[number], cache->_mask, &cache->_xgcv); } int Grafix::line_gc(int r, int g, int b) { XGCValues xgcv; xgcv.function = GXcopy; xgcv.line_width = 0; XColor xc; xc.red = (r << 8) | r; xc.green = (g << 8) | g; xc.blue = (b << 8) | b; return make_cached_gc(GCFunction | GCForeground | GCLineWidth, &xgcv, &xc); } bool Grafix::gc_foreground(int gc, int &r, int &g, int &b) { if (gc < 0 || gc >= all_cached_gcs.size()) return false; GCCache &gcc = all_cached_gcs[gc]; if (!(gcc._mask & GCForeground)) return false; r = gcc._foreground.red >> 8; g = gcc._foreground.green >> 8; b = gcc._foreground.blue >> 8; return true; } /***** * Graphics context caching stuff **/ bool Grafix::GCCache::acceptable(const GCCache &o) { unsigned long m = _mask & o._mask; if (m & GCFunction) if (_xgcv.function != o._xgcv.function) return false; if (m & GCForeground) if (_foreground.red != o._foreground.red || _foreground.green != o._foreground.green || _foreground.blue != o._foreground.blue) return false; if (m & GCLineWidth) if (_xgcv.line_width != o._xgcv.line_width) return false; if (m & GCLineStyle) if (_xgcv.line_style != o._xgcv.line_style) return false; return true; } bool Grafix::GCCache::combine(const GCCache &o) { if ((o._mask & ~_mask) == 0) return false; if (o._mask & GCFunction) _xgcv.function = o._xgcv.function; if (o._mask & GCForeground) _foreground = o._foreground; if (o._mask & GCLineWidth) _xgcv.line_width = o._xgcv.line_width; if (o._mask & GCLineStyle) _xgcv.line_style = o._xgcv.line_style; _mask |= o._mask; return true; } int Grafix::make_cached_gc(unsigned long mask, XGCValues *xgcv, XColor *foreground) { // initialize first cached GC if (all_cached_gcs.size() == 0) { GCCache cache; cache._foreground.red = 0; cache._foreground.green = 0; cache._foreground.blue = 0; cache._mask = GCForeground; all_cached_gcs.push_back(cache); } GCCache cache; cache._xgcv = *xgcv; cache._mask = mask; if (foreground) cache._foreground = *foreground; unsigned long old_mask; int actual; for (int i = 0; i < all_cached_gcs.size(); i++) { GCCache &cur_cache = all_cached_gcs[i]; if (cur_cache.acceptable(cache)) { old_mask = cur_cache._mask; actual = i; cur_cache.combine(cache); goto found; } } all_cached_gcs.push_back(cache); old_mask = 0; actual = all_cached_gcs.size() - 1; found: if (old_mask != all_cached_gcs[actual]._mask) for (int i = 0; i < all_instances.size(); i++) all_instances[i]->update_gc(actual, old_mask, &all_cached_gcs[actual]); return actual; }