From 49491d32b6385634227f779828bb6de97449f273 Mon Sep 17 00:00:00 2001 From: fluxgen <fluxgen> Date: Sat, 30 Nov 2002 20:07:06 +0000 Subject: moved from Image.hh/cc --- src/ImageControl.cc | 636 ++++++++++++++++++++++++++++++++++++++++++++++++++++ src/ImageControl.hh | 125 +++++++++++ 2 files changed, 761 insertions(+) create mode 100644 src/ImageControl.cc create mode 100644 src/ImageControl.hh diff --git a/src/ImageControl.cc b/src/ImageControl.cc new file mode 100644 index 0000000..8a60461 --- /dev/null +++ b/src/ImageControl.cc @@ -0,0 +1,636 @@ +// ImageControl.cc for Fluxbox Window Manager +// Copyright (c) 2001 - 2002 Henrik Kinnunen (fluxbox at linuxmail.org) +// +// Image.cc for Blackbox - an X11 Window manager +// Copyright (c) 1997 - 2000 Brad Hughes (bhughes at tcac.net) +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +// $Id: ImageControl.cc,v 1.1 2002/11/30 20:07:06 fluxgen Exp $ + +#include "ImageControl.hh" + +#include "TextureRender.hh" +#include "App.hh" + +//use GNU extensions +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif // _GNU_SOURCE + +#include "i18n.hh" + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif // HAVE_CONFIG_H + +#ifdef HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif // HAVE_SYS_TYPES_H + +#include <cstdlib> +#include <cstring> +#include <cstdio> + +#ifdef HAVE_CTYPE_H +#include <ctype.h> +#endif // HAVE_CTYPE_H + +#include <iostream> + +using namespace std; + +// lookup table for texture +unsigned long *BImageControl::sqrt_table = 0; + +namespace { // anonymous + +unsigned long bsqrt(unsigned long x) { + if (x <= 0) return 0; + if (x == 1) return 1; + + unsigned long r = x >> 1; + unsigned long q; + + while (1) { + q = x / r; + if (q >= r) return r; + r = (r + q) >> 1; + } +} + +}; + + +BImageControl::BImageControl(int screen_num, bool dither, + int cpc, unsigned long cache_timeout, unsigned long cmax): +m_dither(dither), +m_timer(this), +m_colors(0), +m_num_colors(0), +m_colors_per_channel(cpc) { + + Display *disp = FbTk::App::instance()->display(); + + m_screen_depth = DefaultDepth(disp, screen_num); + m_screen_num = screen_num; + m_root_window = RootWindow(disp, screen_num); + m_visual = DefaultVisual(disp, screen_num); + m_colormap = DefaultColormap(disp, screen_num); + + cache_max = cmax; +#ifdef TIMEDCACHE + if (cache_timeout) { + m_timer.setTimeout(cache_timeout); + m_timer.start(); + } +#endif // TIMEDCACHE + + createColorTable(); +} + + +BImageControl::~BImageControl() { + if (sqrt_table) { + delete [] sqrt_table; + } + + if (grad_xbuffer) { + delete [] grad_xbuffer; + } + + if (grad_ybuffer) { + delete [] grad_ybuffer; + } + + if (m_colors) { + unsigned long *pixels = new unsigned long [m_num_colors]; + + for (unsigned int color = 0; color < m_num_colors; color++) + *(pixels + color) = (*(m_colors + color)).pixel; + + XFreeColors(FbTk::App::instance()->display(), m_colormap, pixels, m_num_colors, 0); + + delete [] m_colors; + } + + if (cache.size() > 0) { + fprintf(stderr, + I18n::instance()-> + getMessage( + FBNLS::ImageSet, FBNLS::ImagePixmapRelease, + "BImageContol::~BImageControl: pixmap cache - " + "releasing %d pixmaps\n"), cache.size()); + + CacheList::iterator it = cache.begin(); + CacheList::iterator it_end = cache.end(); + Display *disp = FbTk::App::instance()->display(); + for (; it != it_end; ++it) { + XFreePixmap(disp, (*it)->pixmap); + delete (*it); + } + + } +} + + +Pixmap BImageControl::searchCache(unsigned int width, unsigned int height, + unsigned long texture_type, + const FbTk::Color &color, const FbTk::Color &color_to) const { + CacheList::iterator it = cache.begin(); + CacheList::iterator it_end = cache.end(); + for (; it != it_end; ++it) { + if (((*it)->width == width) && + ((*it)->height == height) && + ((*it)->texture == texture_type) && + ((*it)->pixel1 == color.pixel())) { + if (texture_type & FbTk::Texture::GRADIENT) { + if ((*it)->pixel2 == color_to.pixel()) { + (*it)->count++; + return (*it)->pixmap; + } + } else { + (*it)->count++; + return (*it)->pixmap; + } + } + } + + return None; +} + + +Pixmap BImageControl::renderImage(unsigned int width, unsigned int height, + const FbTk::Texture &texture) { + + if (texture.type() & FbTk::Texture::PARENTRELATIVE) + return ParentRelative; + + // search cache first + Pixmap pixmap = searchCache(width, height, texture.type(), + texture.color(), texture.colorTo()); + if (pixmap) + return pixmap; // return cache item + + // render new image + TextureRender image(*this, width, height); + pixmap = image.render(texture); + + if (pixmap) { + // create new cache item and add it to cache list + + Cache *tmp = new Cache; + + tmp->pixmap = pixmap; + tmp->width = width; + tmp->height = height; + tmp->count = 1; + tmp->texture = texture.type(); + tmp->pixel1 = texture.color().pixel(); + + if (texture.type() & FbTk::Texture::GRADIENT) + tmp->pixel2 = texture.colorTo().pixel(); + else + tmp->pixel2 = 0l; + + cache.push_back(tmp); + + if ((unsigned) cache.size() > cache_max) { +#ifdef DEBUG + cerr<<I18n::instance()-> + getMessage( + FBNLS::ImageSet, FBNLS::ImagePixmapCacheLarge, + "BImageControl::renderImage: cache is large, " + "forcing cleanout\n")<<endl; +#endif // DEBUG + timeout(); + } + + return pixmap; + } + + return None; +} + + +void BImageControl::removeImage(Pixmap pixmap) { + if (!pixmap) + return; + + CacheList::iterator it = cache.begin(); + CacheList::iterator it_end = cache.end(); + for (; it != it_end; ++it) { + if ((*it)->pixmap == pixmap) { + if ((*it)->count) { + (*it)->count--; + +#ifdef TIMEDCACHE + timeout(); +#else // !TIMEDCACHE + if (! (*it)->count) timeout(); +#endif // TIMEDCACHE + } + + return; + } + } +} + + +void BImageControl::colorTables(const unsigned char **rmt, const unsigned char **gmt, + const unsigned char **bmt, + int *roff, int *goff, int *boff, + int *rbit, int *gbit, int *bbit) const { + + if (rmt) *rmt = red_color_table; + if (gmt) *gmt = green_color_table; + if (bmt) *bmt = blue_color_table; + + if (roff) *roff = red_offset; + if (goff) *goff = green_offset; + if (boff) *boff = blue_offset; + + if (rbit) *rbit = red_bits; + if (gbit) *gbit = green_bits; + if (bbit) *bbit = blue_bits; +} + + +void BImageControl::getXColorTable(XColor **c, int *n) { + if (c) *c = m_colors; + if (n) *n = m_num_colors; +} + + +void BImageControl::getGradientBuffers(unsigned int w, + unsigned int h, + unsigned int **xbuf, + unsigned int **ybuf) { + + if (w > grad_buffer_width) { + if (grad_xbuffer) { + delete [] grad_xbuffer; + } + + grad_buffer_width = w; + + grad_xbuffer = new unsigned int[grad_buffer_width * 3]; + } + + if (h > grad_buffer_height) { + if (grad_ybuffer) { + delete [] grad_ybuffer; + } + + grad_buffer_height = h; + + grad_ybuffer = new unsigned int[grad_buffer_height * 3]; + } + + *xbuf = grad_xbuffer; + *ybuf = grad_ybuffer; +} + + +void BImageControl::installRootColormap() { + XGrabServer(FbTk::App::instance()->display()); + + + Display *disp = FbTk::App::instance()->display(); + bool install = true; + int i = 0, ncmap = 0; + Colormap *cmaps = + XListInstalledColormaps(disp, m_root_window, &ncmap); + + if (cmaps) { + for (i = 0; i < ncmap; i++) { + if (*(cmaps + i) == m_colormap) + install = false; + } + + if (install) + XInstallColormap(disp, m_colormap); + + XFree(cmaps); + } + + XUngrabServer(FbTk::App::instance()->display()); +} + + +void BImageControl::setColorsPerChannel(int cpc) { + if (cpc < 2) cpc = 2; + if (cpc > 6) cpc = 6; + + m_colors_per_channel = cpc; +} + + +unsigned long BImageControl::getSqrt(unsigned int x) const { + if (! sqrt_table) { + // build sqrt table for use with elliptic gradient + + sqrt_table = new unsigned long[(256 * 256 * 2) + 1]; + int i = 0; + + for (; i < (256 * 256 * 2); i++) + *(sqrt_table + i) = bsqrt(i); + } + + return (*(sqrt_table + x)); +} + +void BImageControl::timeout() { + Display *disp = FbTk::App::instance()->display(); + CacheList::iterator it = cache.begin(); + CacheList::iterator it_end = cache.end(); + for (; it != it_end; ++it) { + Cache *tmp = (*it); + + if (tmp->count <= 0) { + XFreePixmap(disp, tmp->pixmap); + it = cache.erase(it); + delete tmp; + if (it == it_end) break; + } + } +} + +void BImageControl::createColorTable() { + Display *disp = FbTk::App::instance()->display(); + + grad_xbuffer = grad_ybuffer = (unsigned int *) 0; + grad_buffer_width = grad_buffer_height = 0; + + int count; + XPixmapFormatValues *pmv = XListPixmapFormats(disp, &count); + + if (pmv) { + bits_per_pixel = 0; + for (int i = 0; i < count; i++) { + if (pmv[i].depth == m_screen_depth) { + bits_per_pixel = pmv[i].bits_per_pixel; + break; + } + } + + XFree(pmv); + } + + if (bits_per_pixel == 0) + bits_per_pixel = m_screen_depth; + if (bits_per_pixel >= 24) + setDither(false); + + red_offset = green_offset = blue_offset = 0; + I18n *i18n = I18n::instance(); + switch (visual()->c_class) { + case TrueColor: { + int i; + + // compute color tables + unsigned long red_mask = visual()->red_mask, + green_mask = visual()->green_mask, + blue_mask = visual()->blue_mask; + + while (! (red_mask & 1)) { red_offset++; red_mask >>= 1; } + while (! (green_mask & 1)) { green_offset++; green_mask >>= 1; } + while (! (blue_mask & 1)) { blue_offset++; blue_mask >>= 1; } + + red_bits = 255 / red_mask; + green_bits = 255 / green_mask; + blue_bits = 255 / blue_mask; + + for (i = 0; i < 256; i++) { + red_color_table[i] = i / red_bits; + green_color_table[i] = i / green_bits; + blue_color_table[i] = i / blue_bits; + } + } + + break; + + case PseudoColor: + case StaticColor: { + + m_num_colors = m_colors_per_channel * m_colors_per_channel * m_colors_per_channel; + + if (m_num_colors > static_cast<unsigned int>(1 << m_screen_depth)) { + m_colors_per_channel = (1 << m_screen_depth) / 3; + m_num_colors = m_colors_per_channel * m_colors_per_channel * m_colors_per_channel; + } + + if (m_colors_per_channel < 2 || m_num_colors > static_cast<unsigned int>(1 << m_screen_depth)) { + fprintf(stderr, + i18n-> + getMessage( + FBNLS::ImageSet, FBNLS::ImageInvalidColormapSize, + "BImageControl::BImageControl: invalid colormap size %d " + "(%d/%d/%d) - reducing"), + m_num_colors, m_colors_per_channel, m_colors_per_channel, + m_colors_per_channel); + + m_colors_per_channel = (1 << m_screen_depth) / 3; + } + + m_colors = new XColor[m_num_colors]; + + int bits = 256 / m_colors_per_channel; + +#ifndef ORDEREDPSEUDO + bits = 255 / (m_colors_per_channel - 1); +#endif // ORDEREDPSEUDO + + red_bits = green_bits = blue_bits = bits; + + for (unsigned int i = 0; i < 256; i++) { + red_color_table[i] = green_color_table[i] = blue_color_table[i] = + i / bits; + } + + for (int r = 0, i = 0; r < m_colors_per_channel; r++) { + for (int g = 0; g < m_colors_per_channel; g++) { + for (int b = 0; b < m_colors_per_channel; b++, i++) { + m_colors[i].red = (r * 0xffff) / (m_colors_per_channel - 1); + m_colors[i].green = (g * 0xffff) / (m_colors_per_channel - 1); + m_colors[i].blue = (b * 0xffff) / (m_colors_per_channel - 1);; + m_colors[i].flags = DoRed|DoGreen|DoBlue; + } + } + } + + for (unsigned int i = 0; i < m_num_colors; i++) { + if (! XAllocColor(disp, m_colormap, &m_colors[i])) { + fprintf(stderr, + i18n->getMessage( + FBNLS::ImageSet, FBNLS::ImageColorAllocFail, + "couldn't alloc color %i %i %i\n"), + m_colors[i].red, m_colors[i].green, m_colors[i].blue); + m_colors[i].flags = 0; + } else + m_colors[i].flags = DoRed|DoGreen|DoBlue; + } + + XColor icolors[256]; + unsigned int incolors = (((1 << m_screen_depth) > 256) ? 256 : (1 << m_screen_depth)); + + for (unsigned int i = 0; i < incolors; i++) + icolors[i].pixel = i; + + XQueryColors(disp, m_colormap, icolors, incolors); + for (unsigned int i = 0; i < m_num_colors; i++) { + if (! m_colors[i].flags) { + unsigned long chk = 0xffffffff, pixel, close = 0; + char p = 2; + + while (p--) { + for (unsigned int ii = 0; ii < incolors; ii++) { + int r = (m_colors[i].red - icolors[i].red) >> 8; + int g = (m_colors[i].green - icolors[i].green) >> 8; + int b = (m_colors[i].blue - icolors[i].blue) >> 8; + pixel = (r * r) + (g * g) + (b * b); + + if (pixel < chk) { + chk = pixel; + close = ii; + } + + m_colors[i].red = icolors[close].red; + m_colors[i].green = icolors[close].green; + m_colors[i].blue = icolors[close].blue; + + if (XAllocColor(disp, m_colormap, + &m_colors[i])) { + m_colors[i].flags = DoRed|DoGreen|DoBlue; + break; + } + } + } + } + } + + break; + } + + case GrayScale: + case StaticGray: + { + + if (visual()->c_class == StaticGray) { + m_num_colors = 1 << m_screen_depth; + } else { + m_num_colors = m_colors_per_channel * m_colors_per_channel * m_colors_per_channel; + + if (m_num_colors > static_cast<unsigned int>(1 << m_screen_depth)) { + m_colors_per_channel = (1 << m_screen_depth) / 3; + m_num_colors = m_colors_per_channel * m_colors_per_channel * m_colors_per_channel; + } + } + + if (m_colors_per_channel < 2 || m_num_colors > static_cast<unsigned int>(1 << m_screen_depth)) { + fprintf(stderr, + i18n-> + getMessage( + FBNLS::ImageSet, FBNLS::ImageInvalidColormapSize, + "BImageControl::BImageControl: invalid colormap size %d " + "(%d/%d/%d) - reducing"), + m_num_colors, m_colors_per_channel, m_colors_per_channel, + m_colors_per_channel); + + m_colors_per_channel = (1 << m_screen_depth) / 3; + } + + m_colors = new XColor[m_num_colors]; + + int p, bits = 255 / (m_colors_per_channel - 1); + red_bits = green_bits = blue_bits = bits; + + for (unsigned int i = 0; i < 256; i++) + red_color_table[i] = green_color_table[i] = blue_color_table[i] = + i / bits; + + for (unsigned int i = 0; i < m_num_colors; i++) { + m_colors[i].red = (i * 0xffff) / (m_colors_per_channel - 1); + m_colors[i].green = (i * 0xffff) / (m_colors_per_channel - 1); + m_colors[i].blue = (i * 0xffff) / (m_colors_per_channel - 1);; + m_colors[i].flags = DoRed|DoGreen|DoBlue; + + if (! XAllocColor(disp, m_colormap, + &m_colors[i])) { + fprintf(stderr, + i18n-> + getMessage( + FBNLS::ImageSet, FBNLS::ImageColorAllocFail, + "couldn't alloc color %i %i %i\n"), + m_colors[i].red, m_colors[i].green, m_colors[i].blue); + m_colors[i].flags = 0; + } else + m_colors[i].flags = DoRed|DoGreen|DoBlue; + } + + + XColor icolors[256]; + unsigned int incolors = (((1 << m_screen_depth) > 256) ? 256 : + (1 << m_screen_depth)); + + for (unsigned int i = 0; i < incolors; i++) + icolors[i].pixel = i; + + XQueryColors(disp, m_colormap, icolors, incolors); + for (unsigned int i = 0; i < m_num_colors; i++) { + if (! m_colors[i].flags) { + unsigned long chk = 0xffffffff, pixel, close = 0; + + p = 2; + while (p--) { + for (unsigned int ii = 0; ii < incolors; ii++) { + int r = (m_colors[i].red - icolors[i].red) >> 8; + int g = (m_colors[i].green - icolors[i].green) >> 8; + int b = (m_colors[i].blue - icolors[i].blue) >> 8; + pixel = (r * r) + (g * g) + (b * b); + + if (pixel < chk) { + chk = pixel; + close = ii; + } + + m_colors[i].red = icolors[close].red; + m_colors[i].green = icolors[close].green; + m_colors[i].blue = icolors[close].blue; + + if (XAllocColor(disp, m_colormap, &m_colors[i])) { + m_colors[i].flags = DoRed|DoGreen|DoBlue; + break; + } + } + } + } + } + + break; + } + + default: + throw string(i18n-> + getMessage( + FBNLS::ImageSet, FBNLS::ImageUnsupVisual, + "BImageControl::BImageControl: unsupported visual")); + + } +} diff --git a/src/ImageControl.hh b/src/ImageControl.hh new file mode 100644 index 0000000..ec89c8d --- /dev/null +++ b/src/ImageControl.hh @@ -0,0 +1,125 @@ +// ImageControl.hh for Fluxbox Window Manager +// Copyright (c) 2001 - 2002 Henrik Kinnunen (fluxbox at linuxmail.org) +// +// Image.hh for Blackbox - an X11 Window manager +// Copyright (c) 1997 - 2000 Brad Hughes (bhughes at tcac.net) +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +// $Id: ImageControl.hh,v 1.1 2002/11/30 20:07:06 fluxgen Exp $ + +#ifndef IMAGECONTROL_HH +#define IMAGECONTROL_HH + +#include "Texture.hh" +#include "Timer.hh" + +#include <X11/Xlib.h> +#include <X11/Xutil.h> +#include <list> + +/** + Holds screen info and color tables +*/ +class BImageControl : public TimeoutHandler { +public: + BImageControl(int screen_num, bool dither = false, int colors_per_channel = 4, + unsigned long cache_timeout = 300000l, unsigned long cache_max = 200l); + virtual ~BImageControl(); + + inline bool doDither() const { return m_dither; } + inline int bitsPerPixel() const { return bits_per_pixel; } + inline int depth() const { return m_screen_depth; } + inline int colorsPerChannel() const { return m_colors_per_channel; } + int screenNum() const { return m_screen_num; } + Visual *visual() const { return m_visual; } + unsigned long getSqrt(unsigned int val) const; + + /** + Render to pixmap + @param width width of pixmap + @param height height of pixmap + @param src_texture texture type to render + @return pixmap of the rendered image, on failure None + */ + Pixmap renderImage(unsigned int width, unsigned int height, + const FbTk::Texture &src_texture); + + void installRootColormap(); + void removeImage(Pixmap thepix); + void colorTables(const unsigned char **, const unsigned char **, const unsigned char **, + int *, int *, int *, int *, int *, int *) const; + void getXColorTable(XColor **, int *); + void getGradientBuffers(unsigned int, unsigned int, + unsigned int **, unsigned int **); + void setDither(bool d) { m_dither = d; } + void setColorsPerChannel(int cpc); + + virtual void timeout(); + +private: + /** + Search cache for a specific pixmap + @return None if no cache was found + */ + Pixmap searchCache(unsigned int width, unsigned int height, unsigned long texture_type, + const FbTk::Color &color, const FbTk::Color &color_to) const; + + void createColorTable(); + bool m_dither; + + BTimer m_timer; + + Colormap m_colormap; + + Window m_root_window; + + XColor *m_colors; ///< color table + unsigned int m_num_colors; ///< number of colors in color table + + Visual *m_visual; + + int bits_per_pixel, red_offset, green_offset, blue_offset, + red_bits, green_bits, blue_bits; + int m_colors_per_channel; ///< number of colors per channel + int m_screen_depth; ///< bit depth of screen + int m_screen_num; ///< screen number + unsigned char red_color_table[256], green_color_table[256], + blue_color_table[256]; + unsigned int *grad_xbuffer, *grad_ybuffer, grad_buffer_width, + grad_buffer_height; + + static unsigned long *sqrt_table; /// sqrt lookup table + + typedef struct Cache { + Pixmap pixmap; + + unsigned int count, width, height; + unsigned long pixel1, pixel2, texture; + } Cache; + + unsigned long cache_max; + typedef std::list<Cache *> CacheList; + + mutable CacheList cache; +}; + + +#endif // IMAGECONTROL_HH + -- cgit v0.11.2