From 7dd4823340ae5f710a08ff3a8fbe4276defc6b85 Mon Sep 17 00:00:00 2001 From: fluxgen Date: Thu, 9 Jan 2003 21:09:49 +0000 Subject: moved from fluxbox to fbtk --- src/FbTk/ImageControl.cc | 613 ++++++++++++++++ src/FbTk/ImageControl.hh | 126 ++++ src/FbTk/TextureRender.cc | 1791 +++++++++++++++++++++++++++++++++++++++++++++ src/FbTk/TextureRender.hh | 99 +++ src/FbTk/Timer.cc | 182 +++++ src/FbTk/Timer.hh | 96 +++ 6 files changed, 2907 insertions(+) create mode 100644 src/FbTk/ImageControl.cc create mode 100644 src/FbTk/ImageControl.hh create mode 100644 src/FbTk/TextureRender.cc create mode 100644 src/FbTk/TextureRender.hh create mode 100644 src/FbTk/Timer.cc create mode 100644 src/FbTk/Timer.hh diff --git a/src/FbTk/ImageControl.cc b/src/FbTk/ImageControl.cc new file mode 100644 index 0000000..f43628f --- /dev/null +++ b/src/FbTk/ImageControl.cc @@ -0,0 +1,613 @@ +// ImageControl.cc for FbTk - Fluxbox Toolkit +// Copyright (c) 2001 - 2003 Henrik Kinnunen (fluxbox at users.sourceforge.net) +// +// 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 2003/01/09 21:09:49 fluxgen Exp $ + +#include "ImageControl.hh" + +#include "TextureRender.hh" +#include "App.hh" + +//use GNU extensions +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif // _GNU_SOURCE + + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif // HAVE_CONFIG_H + +#ifdef HAVE_SYS_TYPES_H +#include +#endif // HAVE_SYS_TYPES_H + +#include +#include +#include + +#ifdef HAVE_CTYPE_H +#include +#endif // HAVE_CTYPE_H + +#include + +using namespace std; + +namespace FbTk { + +// lookup table for texture +unsigned long *ImageControl::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; + } +} + +}; // end anonymous namespace + + +ImageControl::ImageControl(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(); +} + + +ImageControl::~ImageControl() { + 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) { +#ifdef DEBUG + cerr<<"FbTk::ImageContol: pixmap cache - releasing "<display(); + for (; it != it_end; ++it) { + XFreePixmap(disp, (*it)->pixmap); + delete (*it); + } + + } +} + + +Pixmap ImageControl::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 ImageControl::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<<"FbTk::ImageControl::renderImage(): cache is large, forcing cleanout"<pixmap == pixmap) { + if ((*it)->count) { + (*it)->count--; + +#ifdef TIMEDCACHE + timeout(); +#else // !TIMEDCACHE + if (! (*it)->count) timeout(); +#endif // TIMEDCACHE + } + + return; + } + } +} + + +void ImageControl::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 ImageControl::getXColorTable(XColor **c, int *n) { + if (c) *c = m_colors; + if (n) *n = m_num_colors; +} + + +void ImageControl::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 ImageControl::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 ImageControl::setColorsPerChannel(int cpc) { + if (cpc < 2) cpc = 2; + if (cpc > 6) cpc = 6; + + m_colors_per_channel = cpc; +} + + +unsigned long ImageControl::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 ImageControl::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 ImageControl::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; + + 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(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(1 << m_screen_depth)) { + fprintf(stderr, "ImageControl::ImageControl: 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, "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(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(1 << m_screen_depth)) { + fprintf(stderr,"FbTk::ImageControl: 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, "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: + cerr<<"FbTk::ImageControl: Unsupported visual"< +#include +#include + +namespace FbTk { + +/// Holds screen info, color tables and caches textures +class ImageControl : public TimeoutHandler { +public: + ImageControl(int screen_num, bool dither = false, int colors_per_channel = 4, + unsigned long cache_timeout = 300000l, unsigned long cache_max = 200l); + virtual ~ImageControl(); + + 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; + + Timer 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 CacheList; + + mutable CacheList cache; +}; + +}; // end namespace FbTk + +#endif // FBTK_IMAGECONTROL_HH + diff --git a/src/FbTk/TextureRender.cc b/src/FbTk/TextureRender.cc new file mode 100644 index 0000000..fc7d76d --- /dev/null +++ b/src/FbTk/TextureRender.cc @@ -0,0 +1,1791 @@ +// TextureRender.cc for fluxbox +// Copyright (c) 2002 - 2003 Henrik Kinnunen (fluxgen at users.sourceforge.net) +// +// from 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: TextureRender.cc,v 1.1 2003/01/09 21:09:49 fluxgen Exp $ + +#include "TextureRender.hh" + +#include "ImageControl.hh" +#include "i18n.hh" +#include "App.hh" + +#include +#include +#include +using namespace std; + +namespace FbTk { + +TextureRender::TextureRender(ImageControl &imgctrl, + unsigned int w, unsigned int h, + XColor *_colors, size_t num_colors): + control(imgctrl), + colors(_colors), + ncolors(ncolors), + xtable(0), ytable(0) { + + width = ((signed) w > 0) ? w : 1; + height = ((signed) h > 0) ? h : 1; + // clamp to "normal" size + if (width > 3200) { + cerr<<"TextureRender: Warning! Width > 3200 setting Width = 3200"< 3200) { + cerr<<"TextureRender: Warning! Height > 3200 setting Height = 3200"<display(); + + Pixmap pixmap = XCreatePixmap(disp, + RootWindow(disp, control.screenNum()), width, + height, control.depth()); + if (pixmap == None) { + cerr< + getMessage( + FBNLS::ImageSet, FBNLS::ImageErrorCreatingSolidPixmap, + "BImage::render_solid: error creating pixmap")<display(); + XImage *image = + XCreateImage(disp, + DefaultVisual(disp, control.screenNum()), control.depth(), ZPixmap, 0, 0, + width, height, 32, 0); + + if (! image) { + fprintf(stderr, + i18n-> + getMessage( + FBNLS::ImageSet, FBNLS::ImageErrorCreatingXImage, + "BImage::renderXImage: error creating XImage\n")); + return 0; + } + + image->data = 0; + + unsigned char *d = new unsigned char[image->bytes_per_line * (height + 1)]; + register unsigned int x, y, dithx, dithy, r, g, b, o, er, eg, eb, offset; + + unsigned char *pixel_data = d, *ppixel_data = d; + unsigned long pixel; + + o = image->bits_per_pixel + ((image->byte_order == MSBFirst) ? 1 : 0); + + if (control.doDither() && width > 1 && height > 1) { + unsigned char dither4[4][4] = { + {0, 4, 1, 5}, + {6, 2, 7, 3}, + {1, 5, 0, 4}, + {7, 3, 6, 2} }; + +#ifdef ORDEREDPSEUDO + unsigned char dither8[8][8] = { + { 0, 32, 8, 40, 2, 34, 10, 42 }, + { 48, 16, 56, 24, 50, 18, 58, 26 }, + { 12, 44, 4, 36, 14, 46, 6, 38 }, + { 60, 28, 52, 20, 62, 30, 54, 22 }, + { 3, 35, 11, 43, 1, 33, 9, 41 }, + { 51, 19, 59, 27, 49, 17, 57, 25 }, + { 15, 47, 7, 39, 13, 45, 5, 37 }, + { 63, 31, 55, 23, 61, 29, 53, 21 } }; +#endif // ORDEREDPSEUDO + + switch (control.visual()->c_class) { + case TrueColor: + // algorithm: ordered dithering... many many thanks to rasterman + // (raster@rasterman.com) for telling me about this... portions of this + // code is based off of his code in Imlib + for (y = 0, offset = 0; y < height; y++) { + dithy = y & 0x3; + + for (x = 0; x < width; x++, offset++) { + dithx = x & 0x3; + r = red[offset]; + g = green[offset]; + b = blue[offset]; + + er = r & (red_bits - 1); + eg = g & (green_bits - 1); + eb = b & (blue_bits - 1); + + r = red_table[r]; + g = green_table[g]; + b = blue_table[b]; + + if ((dither4[dithy][dithx] < er) && (r < red_table[255])) r++; + if ((dither4[dithy][dithx] < eg) && (g < green_table[255])) g++; + if ((dither4[dithy][dithx] < eb) && (b < blue_table[255])) b++; + + pixel = (r << red_offset) | (g << green_offset) | (b << blue_offset); + + switch (o) { + case 8: // 8bpp + *pixel_data++ = pixel; + break; + + case 16: // 16bpp LSB + *pixel_data++ = pixel; + *pixel_data++ = pixel >> 8; + break; + + case 17: // 16bpp MSB + *pixel_data++ = pixel >> 8; + *pixel_data++ = pixel; + break; + + case 24: // 24bpp LSB + *pixel_data++ = pixel; + *pixel_data++ = pixel >> 8; + *pixel_data++ = pixel >> 16; + break; + + case 25: // 24bpp MSB + *pixel_data++ = pixel >> 16; + *pixel_data++ = pixel >> 8; + *pixel_data++ = pixel; + break; + + case 32: // 32bpp LSB + *pixel_data++ = pixel; + *pixel_data++ = pixel >> 8; + *pixel_data++ = pixel >> 16; + *pixel_data++ = pixel >> 24; + break; + + case 33: // 32bpp MSB + *pixel_data++ = pixel >> 24; + *pixel_data++ = pixel >> 16; + *pixel_data++ = pixel >> 8; + *pixel_data++ = pixel; + break; + } + } + + pixel_data = (ppixel_data += image->bytes_per_line); + } + + break; + + case StaticColor: + case PseudoColor: { +#ifndef ORDEREDPSEUDO + short *terr, + *rerr = new short[width + 2], + *gerr = new short[width + 2], + *berr = new short[width + 2], + *nrerr = new short[width + 2], + *ngerr = new short[width + 2], + *nberr = new short[width + 2]; + int rr, gg, bb, rer, ger, ber; + int dd = 255 / control.colorsPerChannel(); + + for (x = 0; x < width; x++) { + *(rerr + x) = *(red + x); + *(gerr + x) = *(green + x); + *(berr + x) = *(blue + x); + } + + *(rerr + x) = *(gerr + x) = *(berr + x) = 0; +#endif // ORDEREDPSEUDO + + for (y = 0, offset = 0; y < height; y++) { +#ifdef ORDEREDPSEUDO + dithy = y & 7; + + for (x = 0; x < width; x++, offset++) { + dithx = x & 7; + + r = red[offset]; + g = green[offset]; + b = blue[offset]; + + er = r & (red_bits - 1); + eg = g & (green_bits - 1); + eb = b & (blue_bits - 1); + + r = red_table[r]; + g = green_table[g]; + b = blue_table[b]; + + if ((dither8[dithy][dithx] < er) && (r < red_table[255])) r++; + if ((dither8[dithy][dithx] < eg) && (g < green_table[255])) g++; + if ((dither8[dithy][dithx] < eb) && (b < blue_table[255])) b++; + + pixel = (r * cpccpc) + (g * cpc) + b; + *(pixel_data++) = colors[pixel].pixel; + } + + pixel_data = (ppixel_data += image->bytes_per_line); + } +#else // !ORDEREDPSEUDO + if (y < (height - 1)) { + int i = offset + width; + for (x = 0; x < width; x++, i++) { + *(nrerr + x) = *(red + i); + *(ngerr + x) = *(green + i); + *(nberr + x) = *(blue + i); + } + + *(nrerr + x) = *(red + (--i)); + *(ngerr + x) = *(green + i); + *(nberr + x) = *(blue + i); + } + + for (x = 0; x < width; x++) { + rr = rerr[x]; + gg = gerr[x]; + bb = berr[x]; + + if (rr > 255) rr = 255; else if (rr < 0) rr = 0; + if (gg > 255) gg = 255; else if (gg < 0) gg = 0; + if (bb > 255) bb = 255; else if (bb < 0) bb = 0; + + r = red_table[rr]; + g = green_table[gg]; + b = blue_table[bb]; + + rer = rerr[x] - r*dd; + ger = gerr[x] - g*dd; + ber = berr[x] - b*dd; + + pixel = (r * cpccpc) + (g * cpc) + b; + *pixel_data++ = colors[pixel].pixel; + + r = rer >> 1; + g = ger >> 1; + b = ber >> 1; + rerr[x+1] += r; + gerr[x+1] += g; + berr[x+1] += b; + nrerr[x] += r; + ngerr[x] += g; + nberr[x] += b; + } + + offset += width; + + pixel_data = (ppixel_data += image->bytes_per_line); + + terr = rerr; + rerr = nrerr; + nrerr = terr; + + terr = gerr; + gerr = ngerr; + ngerr = terr; + + terr = berr; + berr = nberr; + nberr = terr; + } + + delete [] rerr; + delete [] gerr; + delete [] berr; + delete [] nrerr; + delete [] ngerr; + delete [] nberr; +#endif // ORDEREDPSUEDO + + } break; + + /* + case StaticGray: + case GrayScale: + for (y = 0, offset = 0; y < height; y++) { + dithy = y & 0x3; + + for (x = 0; x < width; x++, offset++) { + dithx = x & 0x3; + + r = *(red + offset); + g = *(green + offset); + b = *(blue + offset); + + er = r & 0x7; + eg = g & 0x7; + eb = b & 0x7; + + if ((dither[dithy][dithx] < er) && (r < (256 - 8))) + r += 8; + if ((dither[dithy][dithx] < (eg << 1)) && (g < (256 - 4))) + g += 4; + if ((dither[dithy][dithx] < eb) && (b < (256 - 8))) + b += 8; + + r = *(red_table + r); + g = *(green_table + g); + b = *(blue_table + b); + + g = ((r * 30) + (g * 59) + (b * 11)) / 100; + *pixel_data++ = colors[g].pixel; + } + + pixel_data = (ppixel_data += image->bytes_per_line); + } + + break; + */ + + default: + fprintf(stderr, + i18n-> + getMessage( + FBNLS::ImageSet, FBNLS::ImageUnsupVisual, + "BImage::renderXImage: unsupported visual\n")); + delete [] d; + XDestroyImage(image); + return (XImage *) 0; + } +} else { + switch (control.visual()->c_class) { + case StaticColor: + case PseudoColor: + for (y = 0, offset = 0; y < height; y++) { + for (x = 0; x < width; x++, offset++) { + r = red_table[red[offset]]; + g = green_table[green[offset]]; + b = blue_table[blue[offset]]; + + pixel = (r * cpccpc) + (g * cpc) + b; + *pixel_data++ = colors[pixel].pixel; + } + + pixel_data = (ppixel_data += image->bytes_per_line); + } + + break; + + case TrueColor: + for (y = 0, offset = 0; y < height; y++) { + for (x = 0; x < width; x++, offset++) { + r = red_table[red[offset]]; + g = green_table[green[offset]]; + b = blue_table[blue[offset]]; + + pixel = (r << red_offset) | (g << green_offset) | (b << blue_offset); + + switch (o) { + case 8: // 8bpp + *pixel_data++ = pixel; + break; + + case 16: // 16bpp LSB + *pixel_data++ = pixel; + *pixel_data++ = pixel >> 8; + break; + + case 17: // 16bpp MSB + *pixel_data++ = pixel >> 8; + *pixel_data++ = pixel; + break; + + case 24: // 24bpp LSB + *pixel_data++ = pixel; + *pixel_data++ = pixel >> 8; + *pixel_data++ = pixel >> 16; + break; + + case 25: // 24bpp MSB + *pixel_data++ = pixel >> 16; + *pixel_data++ = pixel >> 8; + *pixel_data++ = pixel; + break; + + case 32: // 32bpp LSB + *pixel_data++ = pixel; + *pixel_data++ = pixel >> 8; + *pixel_data++ = pixel >> 16; + *pixel_data++ = pixel >> 24; + break; + + case 33: // 32bpp MSB + *pixel_data++ = pixel >> 24; + *pixel_data++ = pixel >> 16; + *pixel_data++ = pixel >> 8; + *pixel_data++ = pixel; + break; + } + } + + pixel_data = (ppixel_data += image->bytes_per_line); + } + + break; + + case StaticGray: + case GrayScale: + for (y = 0, offset = 0; y < height; y++) { + for (x = 0; x < width; x++, offset++) { + r = *(red_table + *(red + offset)); + g = *(green_table + *(green + offset)); + b = *(blue_table + *(blue + offset)); + + g = ((r * 30) + (g * 59) + (b * 11)) / 100; + *pixel_data++ = colors[g].pixel; + } + + pixel_data = (ppixel_data += image->bytes_per_line); + } + + break; + + default: + fprintf(stderr, + i18n-> + getMessage( + FBNLS::ImageSet, FBNLS::ImageUnsupVisual, + "BImage::renderXImage: unsupported visual\n")); + delete [] d; + XDestroyImage(image); + return (XImage *) 0; + } +} + +image->data = (char *) d; +return image; +} + + +Pixmap TextureRender::renderPixmap() { + Display *disp = FbTk::App::instance()->display(); + I18n *i18n = I18n::instance(); + Pixmap pixmap = + XCreatePixmap(disp, + RootWindow(disp, control.screenNum()), width, height, control.depth()); + + if (pixmap == None) { + fprintf(stderr, + i18n->getMessage( + FBNLS::ImageSet, FBNLS::ImageErrorCreatingPixmap, + "BImage::renderPixmap: error creating pixmap\n")); + return None; + } + + XImage *image = renderXImage(); + + if (! image) { + XFreePixmap(disp, pixmap); + return None; + } else if (! image->data) { + XDestroyImage(image); + XFreePixmap(disp, pixmap); + return None; + } + + XPutImage(disp, pixmap, + DefaultGC(disp, control.screenNum()), + image, 0, 0, 0, 0, width, height); + + if (image->data != 0) { + delete [] image->data; + image->data = 0; + } + + XDestroyImage(image); + + return pixmap; +} + + +void TextureRender::bevel1() { + if (! (width > 2 && height > 2)) + return; + + unsigned char *pr = red, *pg = green, *pb = blue; + + register unsigned char r, g, b, rr ,gg ,bb; + register unsigned int w = width, h = height - 1, wh = w * h; + + while (--w) { + r = *pr; + rr = r + (r >> 1); + if (rr < r) rr = ~0; + g = *pg; + gg = g + (g >> 1); + if (gg < g) gg = ~0; + b = *pb; + bb = b + (b >> 1); + if (bb < b) bb = ~0; + + *pr = rr; + *pg = gg; + *pb = bb; + + r = *(pr + wh); + rr = (r >> 2) + (r >> 1); + if (rr > r) rr = 0; + g = *(pg + wh); + gg = (g >> 2) + (g >> 1); + if (gg > g) gg = 0; + b = *(pb + wh); + bb = (b >> 2) + (b >> 1); + if (bb > b) bb = 0; + + *((pr++) + wh) = rr; + *((pg++) + wh) = gg; + *((pb++) + wh) = bb; + } + + r = *pr; + rr = r + (r >> 1); + if (rr < r) rr = ~0; + g = *pg; + gg = g + (g >> 1); + if (gg < g) gg = ~0; + b = *pb; + bb = b + (b >> 1); + if (bb < b) bb = ~0; + + *pr = rr; + *pg = gg; + *pb = bb; + + r = *(pr + wh); + rr = (r >> 2) + (r >> 1); + if (rr > r) rr = 0; + g = *(pg + wh); + gg = (g >> 2) + (g >> 1); + if (gg > g) gg = 0; + b = *(pb + wh); + bb = (b >> 2) + (b >> 1); + if (bb > b) bb = 0; + + *(pr + wh) = rr; + *(pg + wh) = gg; + *(pb + wh) = bb; + + pr = red + width; + pg = green + width; + pb = blue + width; + + while (--h) { + r = *pr; + rr = r + (r >> 1); + if (rr < r) rr = ~0; + g = *pg; + gg = g + (g >> 1); + if (gg < g) gg = ~0; + b = *pb; + bb = b + (b >> 1); + if (bb < b) bb = ~0; + + *pr = rr; + *pg = gg; + *pb = bb; + + pr += width - 1; + pg += width - 1; + pb += width - 1; + + r = *pr; + rr = (r >> 2) + (r >> 1); + if (rr > r) rr = 0; + g = *pg; + gg = (g >> 2) + (g >> 1); + if (gg > g) gg = 0; + b = *pb; + bb = (b >> 2) + (b >> 1); + if (bb > b) bb = 0; + + *(pr++) = rr; + *(pg++) = gg; + *(pb++) = bb; + } + + r = *pr; + rr = r + (r >> 1); + if (rr < r) rr = ~0; + g = *pg; + gg = g + (g >> 1); + if (gg < g) gg = ~0; + b = *pb; + bb = b + (b >> 1); + if (bb < b) bb = ~0; + + *pr = rr; + *pg = gg; + *pb = bb; + + pr += width - 1; + pg += width - 1; + pb += width - 1; + + r = *pr; + rr = (r >> 2) + (r >> 1); + if (rr > r) rr = 0; + g = *pg; + gg = (g >> 2) + (g >> 1); + if (gg > g) gg = 0; + b = *pb; + bb = (b >> 2) + (b >> 1); + if (bb > b) bb = 0; + + *pr = rr; + *pg = gg; + *pb = bb; +} + + +void TextureRender::bevel2() { + if (! (width > 4 && height > 4)) + return; + + unsigned char r, g, b, rr ,gg ,bb, *pr = red + width + 1, + *pg = green + width + 1, *pb = blue + width + 1; + unsigned int w = width - 2, h = height - 1, wh = width * (height - 3); + + while (--w) { + r = *pr; + rr = r + (r >> 1); + if (rr < r) rr = ~0; + g = *pg; + gg = g + (g >> 1); + if (gg < g) gg = ~0; + b = *pb; + bb = b + (b >> 1); + if (bb < b) bb = ~0; + + *pr = rr; + *pg = gg; + *pb = bb; + + r = *(pr + wh); + rr = (r >> 2) + (r >> 1); + if (rr > r) rr = 0; + g = *(pg + wh); + gg = (g >> 2) + (g >> 1); + if (gg > g) gg = 0; + b = *(pb + wh); + bb = (b >> 2) + (b >> 1); + if (bb > b) bb = 0; + + *((pr++) + wh) = rr; + *((pg++) + wh) = gg; + *((pb++) + wh) = bb; + } + + pr = red + width; + pg = green + width; + pb = blue + width; + + while (--h) { + r = *pr; + rr = r + (r >> 1); + if (rr < r) rr = ~0; + g = *pg; + gg = g + (g >> 1); + if (gg < g) gg = ~0; + b = *pb; + bb = b + (b >> 1); + if (bb < b) bb = ~0; + + *(++pr) = rr; + *(++pg) = gg; + *(++pb) = bb; + + pr += width - 3; + pg += width - 3; + pb += width - 3; + + r = *pr; + rr = (r >> 2) + (r >> 1); + if (rr > r) rr = 0; + g = *pg; + gg = (g >> 2) + (g >> 1); + if (gg > g) gg = 0; + b = *pb; + bb = (b >> 2) + (b >> 1); + if (bb > b) bb = 0; + + *(pr++) = rr; + *(pg++) = gg; + *(pb++) = bb; + + pr++; pg++; pb++; + } +} + + +void TextureRender::invert() { + register unsigned int i, j, wh = (width * height) - 1; + unsigned char tmp; + + for (i = 0, j = wh; j > i; j--, i++) { + tmp = *(red + j); + *(red + j) = *(red + i); + *(red + i) = tmp; + + tmp = *(green + j); + *(green + j) = *(green + i); + *(green + i) = tmp; + + tmp = *(blue + j); + *(blue + j) = *(blue + i); + *(blue + i) = tmp; + } +} + + +void TextureRender::dgradient() { + // diagonal gradient code was written by Mike Cole + // modified for interlacing by Brad Hughes + + float drx, dgx, dbx, dry, dgy, dby, yr = 0.0, yg = 0.0, yb = 0.0, + xr = (float) from->red(), + xg = (float) from->green(), + xb = (float) from->blue(); + unsigned char *pr = red, *pg = green, *pb = blue; + unsigned int w = width * 2, h = height * 2; + unsigned int *xt = xtable, *yt = ytable; + + register unsigned int x, y; + + dry = drx = (float) (to->red() - from->red()); + dgy = dgx = (float) (to->green() - from->green()); + dby = dbx = (float) (to->blue() - from->blue()); + + // Create X table + drx /= w; + dgx /= w; + dbx /= w; + + for (x = 0; x < width; x++) { + *(xt++) = (unsigned char) (xr); + *(xt++) = (unsigned char) (xg); + *(xt++) = (unsigned char) (xb); + + xr += drx; + xg += dgx; + xb += dbx; + } + + // Create Y table + dry /= h; + dgy /= h; + dby /= h; + + for (y = 0; y < height; y++) { + *(yt++) = ((unsigned char) yr); + *(yt++) = ((unsigned char) yg); + *(yt++) = ((unsigned char) yb); + + yr += dry; + yg += dgy; + yb += dby; + } + + // Combine tables to create gradient + + + if (! interlaced) { + + + // normal dgradient + for (yt = ytable, y = 0; y < height; y++, yt += 3) { + for (xt = xtable, x = 0; x < width; x++) { + *(pr++) = *(xt++) + *(yt); + *(pg++) = *(xt++) + *(yt + 1); + *(pb++) = *(xt++) + *(yt + 2); + } + } + + } else { + // faked interlacing effect + unsigned char channel, channel2; + + for (yt = ytable, y = 0; y < height; y++, yt += 3) { + for (xt = xtable, x = 0; x < width; x++) { + if (y & 1) { + channel = *(xt++) + *(yt); + channel2 = (channel >> 1) + (channel >> 2); + if (channel2 > channel) channel2 = 0; + *(pr++) = channel2; + + channel = *(xt++) + *(yt + 1); + channel2 = (channel >> 1) + (channel >> 2); + if (channel2 > channel) channel2 = 0; + *(pg++) = channel2; + + channel = *(xt++) + *(yt + 2); + channel2 = (channel >> 1) + (channel >> 2); + if (channel2 > channel) channel2 = 0; + *(pb++) = channel2; + } else { + channel = *(xt++) + *(yt); + channel2 = channel + (channel >> 3); + if (channel2 < channel) channel2 = ~0; + *(pr++) = channel2; + + channel = *(xt++) + *(yt + 1); + channel2 = channel + (channel >> 3); + if (channel2 < channel) channel2 = ~0; + *(pg++) = channel2; + + channel = *(xt++) + *(yt + 2); + channel2 = channel + (channel >> 3); + if (channel2 < channel) channel2 = ~0; + *(pb++) = channel2; + } + } + } + } + + +} + + +void TextureRender::hgradient() { + float drx, dgx, dbx, + xr = (float) from->red(), + xg = (float) from->green(), + xb = (float) from->blue(); + unsigned char *pr = red, *pg = green, *pb = blue; + + register unsigned int x, y; + + drx = (float) (to->red() - from->red()); + dgx = (float) (to->green() - from->green()); + dbx = (float) (to->blue() - from->blue()); + + drx /= width; + dgx /= width; + dbx /= width; + + if (interlaced && height > 2) { + // faked interlacing effect + unsigned char channel, channel2; + + for (x = 0; x < width; x++, pr++, pg++, pb++) { + channel = (unsigned char) xr; + channel2 = (channel >> 1) + (channel >> 2); + if (channel2 > channel) channel2 = 0; + *pr = channel2; + + channel = (unsigned char) xg; + channel2 = (channel >> 1) + (channel >> 2); + if (channel2 > channel) channel2 = 0; + *pg = channel2; + + channel = (unsigned char) xb; + channel2 = (channel >> 1) + (channel >> 2); + if (channel2 > channel) channel2 = 0; + *pb = channel2; + + + channel = (unsigned char) xr; + channel2 = channel + (channel >> 3); + if (channel2 < channel) channel2 = ~0; + *(pr + width) = channel2; + + channel = (unsigned char) xg; + channel2 = channel + (channel >> 3); + if (channel2 < channel) channel2 = ~0; + *(pg + width) = channel2; + + channel = (unsigned char) xb; + channel2 = channel + (channel >> 3); + if (channel2 < channel) channel2 = ~0; + *(pb + width) = channel2; + + xr += drx; + xg += dgx; + xb += dbx; + } + + pr += width; + pg += width; + pb += width; + + int offset; + + for (y = 2; y < height; y++, pr += width, pg += width, pb += width) { + if (y & 1) offset = width; else offset = 0; + + memcpy(pr, (red + offset), width); + memcpy(pg, (green + offset), width); + memcpy(pb, (blue + offset), width); + } + } else { + + // normal hgradient + for (x = 0; x < width; x++) { + *(pr++) = (unsigned char) (xr); + *(pg++) = (unsigned char) (xg); + *(pb++) = (unsigned char) (xb); + + xr += drx; + xg += dgx; + xb += dbx; + } + + for (y = 1; y < height; y++, pr += width, pg += width, pb += width) { + memcpy(pr, red, width); + memcpy(pg, green, width); + memcpy(pb, blue, width); + } + + } + +} + + +void TextureRender::vgradient() { + float dry, dgy, dby, + yr = (float) from->red(), + yg = (float) from->green(), + yb = (float) from->blue(); + unsigned char *pr = red, *pg = green, *pb = blue; + + register unsigned int y; + + dry = (float) (to->red() - from->red()); + dgy = (float) (to->green() - from->green()); + dby = (float) (to->blue() - from->blue()); + + dry /= height; + dgy /= height; + dby /= height; + + if (interlaced) { + // faked interlacing effect + unsigned char channel, channel2; + + for (y = 0; y < height; y++, pr += width, pg += width, pb += width) { + if (y & 1) { + channel = (unsigned char) yr; + channel2 = (channel >> 1) + (channel >> 2); + if (channel2 > channel) channel2 = 0; + memset(pr, channel2, width); + + channel = (unsigned char) yg; + channel2 = (channel >> 1) + (channel >> 2); + if (channel2 > channel) channel2 = 0; + memset(pg, channel2, width); + + channel = (unsigned char) yb; + channel2 = (channel >> 1) + (channel >> 2); + if (channel2 > channel) channel2 = 0; + memset(pb, channel2, width); + } else { + channel = (unsigned char) yr; + channel2 = channel + (channel >> 3); + if (channel2 < channel) channel2 = ~0; + memset(pr, channel2, width); + + channel = (unsigned char) yg; + channel2 = channel + (channel >> 3); + if (channel2 < channel) channel2 = ~0; + memset(pg, channel2, width); + + channel = (unsigned char) yb; + channel2 = channel + (channel >> 3); + if (channel2 < channel) channel2 = ~0; + memset(pb, channel2, width); + } + + yr += dry; + yg += dgy; + yb += dby; + } + } else { + + // normal vgradient + for (y = 0; y < height; y++, pr += width, pg += width, pb += width) { + memset(pr, (unsigned char) yr, width); + memset(pg, (unsigned char) yg, width); + memset(pb, (unsigned char) yb, width); + + yr += dry; + yg += dgy; + yb += dby; + } + } + + +} + + +void TextureRender::pgradient() { + // pyramid gradient - based on original dgradient, written by + // Mosfet (mosfet@kde.org) + // adapted from kde sources for Blackbox by Brad Hughes + + float yr, yg, yb, drx, dgx, dbx, dry, dgy, dby, + xr, xg, xb; + int rsign, gsign, bsign; + unsigned char *pr = red, *pg = green, *pb = blue; + unsigned int tr = to->red(), tg = to->green(), tb = to->blue(); + unsigned int *xt = xtable, *yt = ytable; + + register unsigned int x, y; + + dry = drx = (float) (to->red() - from->red()); + dgy = dgx = (float) (to->green() - from->green()); + dby = dbx = (float) (to->blue() - from->blue()); + + rsign = (drx < 0) ? -1 : 1; + gsign = (dgx < 0) ? -1 : 1; + bsign = (dbx < 0) ? -1 : 1; + + xr = yr = (drx / 2); + xg = yg = (dgx / 2); + xb = yb = (dbx / 2); + + // Create X table + drx /= width; + dgx /= width; + dbx /= width; + + for (x = 0; x < width; x++) { + *(xt++) = (unsigned char) ((xr < 0) ? -xr : xr); + *(xt++) = (unsigned char) ((xg < 0) ? -xg : xg); + *(xt++) = (unsigned char) ((xb < 0) ? -xb : xb); + + xr -= drx; + xg -= dgx; + xb -= dbx; + } + + // Create Y table + dry /= height; + dgy /= height; + dby /= height; + + for (y = 0; y < height; y++) { + *(yt++) = ((unsigned char) ((yr < 0) ? -yr : yr)); + *(yt++) = ((unsigned char) ((yg < 0) ? -yg : yg)); + *(yt++) = ((unsigned char) ((yb < 0) ? -yb : yb)); + + yr -= dry; + yg -= dgy; + yb -= dby; + } + + // Combine tables to create gradient + + + if (! interlaced) { + + // normal pgradient + for (yt = ytable, y = 0; y < height; y++, yt += 3) { + for (xt = xtable, x = 0; x < width; x++) { + *(pr++) = (unsigned char) (tr - (rsign * (*(xt++) + *(yt)))); + *(pg++) = (unsigned char) (tg - (gsign * (*(xt++) + *(yt + 1)))); + *(pb++) = (unsigned char) (tb - (bsign * (*(xt++) + *(yt + 2)))); + } + } + + } else { + // faked interlacing effect + unsigned char channel, channel2; + + for (yt = ytable, y = 0; y < height; y++, yt += 3) { + for (xt = xtable, x = 0; x < width; x++) { + if (y & 1) { + channel = (unsigned char) (tr - (rsign * (*(xt++) + *(yt)))); + channel2 = (channel >> 1) + (channel >> 2); + if (channel2 > channel) channel2 = 0; + *(pr++) = channel2; + + channel = (unsigned char) (tg - (gsign * (*(xt++) + *(yt + 1)))); + channel2 = (channel >> 1) + (channel >> 2); + if (channel2 > channel) channel2 = 0; + *(pg++) = channel2; + + channel = (unsigned char) (tb - (bsign * (*(xt++) + *(yt + 2)))); + channel2 = (channel >> 1) + (channel >> 2); + if (channel2 > channel) channel2 = 0; + *(pb++) = channel2; + } else { + channel = (unsigned char) (tr - (rsign * (*(xt++) + *(yt)))); + channel2 = channel + (channel >> 3); + if (channel2 < channel) channel2 = ~0; + *(pr++) = channel2; + + channel = (unsigned char) (tg - (gsign * (*(xt++) + *(yt + 1)))); + channel2 = channel + (channel >> 3); + if (channel2 < channel) channel2 = ~0; + *(pg++) = channel2; + + channel = (unsigned char) (tb - (bsign * (*(xt++) + *(yt + 2)))); + channel2 = channel + (channel >> 3); + if (channel2 < channel) channel2 = ~0; + *(pb++) = channel2; + } + } + } + } + +} + + +void TextureRender::rgradient() { + // rectangle gradient - based on original dgradient, written by + // Mosfet (mosfet@kde.org) + // adapted from kde sources for Blackbox by Brad Hughes + + float drx, dgx, dbx, dry, dgy, dby, xr, xg, xb, yr, yg, yb; + int rsign, gsign, bsign; + unsigned char *pr = red, *pg = green, *pb = blue; + unsigned int tr = to->red(), tg = to->green(), tb = to->blue(); + unsigned int *xt = xtable, *yt = ytable; + + register unsigned int x, y; + + dry = drx = (float) (to->red() - from->red()); + dgy = dgx = (float) (to->green() - from->green()); + dby = dbx = (float) (to->blue() - from->blue()); + + rsign = (drx < 0) ? -2 : 2; + gsign = (dgx < 0) ? -2 : 2; + bsign = (dbx < 0) ? -2 : 2; + + xr = yr = (drx / 2); + xg = yg = (dgx / 2); + xb = yb = (dbx / 2); + + // Create X table + drx /= width; + dgx /= width; + dbx /= width; + + for (x = 0; x < width; x++) { + *(xt++) = (unsigned char) ((xr < 0) ? -xr : xr); + *(xt++) = (unsigned char) ((xg < 0) ? -xg : xg); + *(xt++) = (unsigned char) ((xb < 0) ? -xb : xb); + + xr -= drx; + xg -= dgx; + xb -= dbx; + } + + // Create Y table + dry /= height; + dgy /= height; + dby /= height; + + for (y = 0; y < height; y++) { + *(yt++) = ((unsigned char) ((yr < 0) ? -yr : yr)); + *(yt++) = ((unsigned char) ((yg < 0) ? -yg : yg)); + *(yt++) = ((unsigned char) ((yb < 0) ? -yb : yb)); + + yr -= dry; + yg -= dgy; + yb -= dby; + } + + // Combine tables to create gradient + + + if (! interlaced) { + + // normal rgradient + for (yt = ytable, y = 0; y < height; y++, yt += 3) { + for (xt = xtable, x = 0; x < width; x++) { + *(pr++) = (unsigned char) (tr - (rsign * std::max(*(xt++), *(yt)))); + *(pg++) = (unsigned char) (tg - (gsign * std::max(*(xt++), *(yt + 1)))); + *(pb++) = (unsigned char) (tb - (bsign * std::max(*(xt++), *(yt + 2)))); + } + } + + } else { + // faked interlacing effect + unsigned char channel, channel2; + + for (yt = ytable, y = 0; y < height; y++, yt += 3) { + for (xt = xtable, x = 0; x < width; x++) { + if (y & 1) { + channel = (unsigned char) (tr - (rsign * std::max(*(xt++), *(yt)))); + channel2 = (channel >> 1) + (channel >> 2); + if (channel2 > channel) channel2 = 0; + *(pr++) = channel2; + + channel = (unsigned char) (tg - (gsign * std::max(*(xt++), *(yt + 1)))); + channel2 = (channel >> 1) + (channel >> 2); + if (channel2 > channel) channel2 = 0; + *(pg++) = channel2; + + channel = (unsigned char) (tb - (bsign * std::max(*(xt++), *(yt + 2)))); + channel2 = (channel >> 1) + (channel >> 2); + if (channel2 > channel) channel2 = 0; + *(pb++) = channel2; + } else { + channel = (unsigned char) (tr - (rsign * std::max(*(xt++), *(yt)))); + channel2 = channel + (channel >> 3); + if (channel2 < channel) channel2 = ~0; + *(pr++) = channel2; + + channel = (unsigned char) (tg - (gsign * std::max(*(xt++), *(yt + 1)))); + channel2 = channel + (channel >> 3); + if (channel2 < channel) channel2 = ~0; + *(pg++) = channel2; + + channel = (unsigned char) (tb - (bsign * std::max(*(xt++), *(yt + 2)))); + channel2 = channel + (channel >> 3); + if (channel2 < channel) channel2 = ~0; + *(pb++) = channel2; + } + } + } + } + +} + + +void TextureRender::egradient() { + // elliptic gradient - based on original dgradient, written by + // Mosfet (mosfet@kde.org) + // adapted from kde sources for Blackbox by Brad Hughes + + float drx, dgx, dbx, dry, dgy, dby, yr, yg, yb, xr, xg, xb; + int rsign, gsign, bsign; + unsigned char *pr = red, *pg = green, *pb = blue; + unsigned int *xt = xtable, *yt = ytable; + unsigned int tr = (unsigned long) to->red(), + tg = (unsigned long) to->green(), + tb = (unsigned long) to->blue(); + + register unsigned int x, y; + + dry = drx = (float) (to->red() - from->red()); + dgy = dgx = (float) (to->green() - from->green()); + dby = dbx = (float) (to->blue() - from->blue()); + + rsign = (drx < 0) ? -1 : 1; + gsign = (dgx < 0) ? -1 : 1; + bsign = (dbx < 0) ? -1 : 1; + + xr = yr = (drx / 2); + xg = yg = (dgx / 2); + xb = yb = (dbx / 2); + + // Create X table + drx /= width; + dgx /= width; + dbx /= width; + + for (x = 0; x < width; x++) { + *(xt++) = (unsigned long) (xr * xr); + *(xt++) = (unsigned long) (xg * xg); + *(xt++) = (unsigned long) (xb * xb); + + xr -= drx; + xg -= dgx; + xb -= dbx; + } + + // Create Y table + dry /= height; + dgy /= height; + dby /= height; + + for (y = 0; y < height; y++) { + *(yt++) = (unsigned long) (yr * yr); + *(yt++) = (unsigned long) (yg * yg); + *(yt++) = (unsigned long) (yb * yb); + + yr -= dry; + yg -= dgy; + yb -= dby; + } + + // Combine tables to create gradient + if (! interlaced) { + // normal egradient + for (yt = ytable, y = 0; y < height; y++, yt += 3) { + for (xt = xtable, x = 0; x < width; x++) { + *(pr++) = (unsigned char) + (tr - (rsign * control.getSqrt(*(xt++) + *(yt)))); + *(pg++) = (unsigned char) + (tg - (gsign * control.getSqrt(*(xt++) + *(yt + 1)))); + *(pb++) = (unsigned char) + (tb - (bsign * control.getSqrt(*(xt++) + *(yt + 2)))); + } + } + + } else { + // faked interlacing effect + unsigned char channel, channel2; + + for (yt = ytable, y = 0; y < height; y++, yt += 3) { + for (xt = xtable, x = 0; x < width; x++) { + if (y & 1) { + channel = (unsigned char) + (tr - (rsign * control.getSqrt(*(xt++) + *(yt)))); + channel2 = (channel >> 1) + (channel >> 2); + if (channel2 > channel) channel2 = 0; + *(pr++) = channel2; + + channel = (unsigned char) + (tg - (gsign * control.getSqrt(*(xt++) + *(yt + 1)))); + channel2 = (channel >> 1) + (channel >> 2); + if (channel2 > channel) channel2 = 0; + *(pg++) = channel2; + + channel = (unsigned char) + (tb - (bsign * control.getSqrt(*(xt++) + *(yt + 2)))); + channel2 = (channel >> 1) + (channel >> 2); + if (channel2 > channel) channel2 = 0; + *(pb++) = channel2; + } else { + channel = (unsigned char) + (tr - (rsign * control.getSqrt(*(xt++) + *(yt)))); + channel2 = channel + (channel >> 3); + if (channel2 < channel) channel2 = ~0; + *(pr++) = channel2; + + channel = (unsigned char) + (tg - (gsign * control.getSqrt(*(xt++) + *(yt + 1)))); + channel2 = channel + (channel >> 3); + if (channel2 < channel) channel2 = ~0; + *(pg++) = channel2; + + channel = (unsigned char) + (tb - (bsign * control.getSqrt(*(xt++) + *(yt + 2)))); + channel2 = channel + (channel >> 3); + if (channel2 < channel) channel2 = ~0; + *(pb++) = channel2; + } + } + } + } + +} + + +void TextureRender::pcgradient() { + // pipe cross gradient - based on original dgradient, written by + // Mosfet (mosfet@kde.org) + // adapted from kde sources for Blackbox by Brad Hughes + + float drx, dgx, dbx, dry, dgy, dby, xr, xg, xb, yr, yg, yb; + int rsign, gsign, bsign; + unsigned char *pr = red, *pg = green, *pb = blue; + unsigned int *xt = xtable, *yt = ytable; + unsigned int tr = to->red(), + tg = to->green(), + tb = to->blue(); + + register unsigned int x, y; + + dry = drx = (float) (to->red() - from->red()); + dgy = dgx = (float) (to->green() - from->green()); + dby = dbx = (float) (to->blue() - from->blue()); + + rsign = (drx < 0) ? -2 : 2; + gsign = (dgx < 0) ? -2 : 2; + bsign = (dbx < 0) ? -2 : 2; + + xr = yr = (drx / 2); + xg = yg = (dgx / 2); + xb = yb = (dbx / 2); + + // Create X table + drx /= width; + dgx /= width; + dbx /= width; + + for (x = 0; x < width; x++) { + *(xt++) = (unsigned char) ((xr < 0) ? -xr : xr); + *(xt++) = (unsigned char) ((xg < 0) ? -xg : xg); + *(xt++) = (unsigned char) ((xb < 0) ? -xb : xb); + + xr -= drx; + xg -= dgx; + xb -= dbx; + } + + // Create Y table + dry /= height; + dgy /= height; + dby /= height; + + for (y = 0; y < height; y++) { + *(yt++) = ((unsigned char) ((yr < 0) ? -yr : yr)); + *(yt++) = ((unsigned char) ((yg < 0) ? -yg : yg)); + *(yt++) = ((unsigned char) ((yb < 0) ? -yb : yb)); + + yr -= dry; + yg -= dgy; + yb -= dby; + } + + // Combine tables to create gradient + if (! interlaced) { + + // normal pcgradient + for (yt = ytable, y = 0; y < height; y++, yt += 3) { + for (xt = xtable, x = 0; x < width; x++) { + *(pr++) = (unsigned char) (tr - (rsign * std::min(*(xt++), *(yt)))); + *(pg++) = (unsigned char) (tg - (gsign * std::min(*(xt++), *(yt + 1)))); + *(pb++) = (unsigned char) (tb - (bsign * std::min(*(xt++), *(yt + 2)))); + } + } + + } else { + // faked interlacing effect + unsigned char channel, channel2; + + for (yt = ytable, y = 0; y < height; y++, yt += 3) { + for (xt = xtable, x = 0; x < width; x++) { + if (y & 1) { + channel = (unsigned char) (tr - (rsign * std::min(*(xt++), *(yt)))); + channel2 = (channel >> 1) + (channel >> 2); + if (channel2 > channel) channel2 = 0; + *(pr++) = channel2; + + channel = (unsigned char) (tg - (bsign * std::min(*(xt++), *(yt + 1)))); + channel2 = (channel >> 1) + (channel >> 2); + if (channel2 > channel) channel2 = 0; + *(pg++) = channel2; + + channel = (unsigned char) (tb - (gsign * std::min(*(xt++), *(yt + 2)))); + channel2 = (channel >> 1) + (channel >> 2); + if (channel2 > channel) channel2 = 0; + *(pb++) = channel2; + } else { + channel = (unsigned char) (tr - (rsign * std::min(*(xt++), *(yt)))); + channel2 = channel + (channel >> 3); + if (channel2 < channel) channel2 = ~0; + *(pr++) = channel2; + + channel = (unsigned char) (tg - (gsign * std::min(*(xt++), *(yt + 1)))); + channel2 = channel + (channel >> 3); + if (channel2 < channel) channel2 = ~0; + *(pg++) = channel2; + + channel = (unsigned char) (tb - (bsign * std::min(*(xt++), *(yt + 2)))); + channel2 = channel + (channel >> 3); + if (channel2 < channel) channel2 = ~0; + *(pb++) = channel2; + } + } + } + } + +} + + +void TextureRender::cdgradient() { + // cross diagonal gradient - based on original dgradient, written by + // Mosfet (mosfet@kde.org) + // adapted from kde sources for Blackbox by Brad Hughes + + float drx, dgx, dbx, dry, dgy, dby, yr = 0.0, yg = 0.0, yb = 0.0, + xr = (float) from->red(), + xg = (float) from->green(), + xb = (float) from->blue(); + unsigned char *pr = red, *pg = green, *pb = blue; + unsigned int w = width * 2, h = height * 2, *xt, *yt; + + register unsigned int x, y; + + dry = drx = (float) (to->red() - from->red()); + dgy = dgx = (float) (to->green() - from->green()); + dby = dbx = (float) (to->blue() - from->blue()); + + // Create X table + drx /= w; + dgx /= w; + dbx /= w; + + for (xt = (xtable + (width * 3) - 1), x = 0; x < width; x++) { + *(xt--) = (unsigned char) xb; + *(xt--) = (unsigned char) xg; + *(xt--) = (unsigned char) xr; + + xr += drx; + xg += dgx; + xb += dbx; + } + + // Create Y table + dry /= h; + dgy /= h; + dby /= h; + + for (yt = ytable, y = 0; y < height; y++) { + *(yt++) = (unsigned char) yr; + *(yt++) = (unsigned char) yg; + *(yt++) = (unsigned char) yb; + + yr += dry; + yg += dgy; + yb += dby; + } + + // Combine tables to create gradient + + if (! interlaced) { + // normal cdgradient + for (yt = ytable, y = 0; y < height; y++, yt += 3) { + for (xt = xtable, x = 0; x < width; x++) { + *(pr++) = *(xt++) + *(yt); + *(pg++) = *(xt++) + *(yt + 1); + *(pb++) = *(xt++) + *(yt + 2); + } + } + + } else { + // faked interlacing effect + unsigned char channel, channel2; + + for (yt = ytable, y = 0; y < height; y++, yt += 3) { + for (xt = xtable, x = 0; x < width; x++) { + if (y & 1) { + channel = *(xt++) + *(yt); + channel2 = (channel >> 1) + (channel >> 2); + if (channel2 > channel) channel2 = 0; + *(pr++) = channel2; + + channel = *(xt++) + *(yt + 1); + channel2 = (channel >> 1) + (channel >> 2); + if (channel2 > channel) channel2 = 0; + *(pg++) = channel2; + + channel = *(xt++) + *(yt + 2); + channel2 = (channel >> 1) + (channel >> 2); + if (channel2 > channel) channel2 = 0; + *(pb++) = channel2; + } else { + channel = *(xt++) + *(yt); + channel2 = channel + (channel >> 3); + if (channel2 < channel) channel2 = ~0; + *(pr++) = channel2; + + channel = *(xt++) + *(yt + 1); + channel2 = channel + (channel >> 3); + if (channel2 < channel) channel2 = ~0; + *(pg++) = channel2; + + channel = *(xt++) + *(yt + 2); + channel2 = channel + (channel >> 3); + if (channel2 < channel) channel2 = ~0; + *(pb++) = channel2; + } + } + } + } + +} + +}; // end namespace FbTk diff --git a/src/FbTk/TextureRender.hh b/src/FbTk/TextureRender.hh new file mode 100644 index 0000000..5b77753 --- /dev/null +++ b/src/FbTk/TextureRender.hh @@ -0,0 +1,99 @@ +// TextureRender.hh for fluxbox +// Copyright (c) 2002 - 2003 Henrik Kinnunen (fluxgen at users.sourceforge.net) +// +// 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: TextureRender.hh,v 1.1 2003/01/09 21:09:49 fluxgen Exp $ + +#ifndef FBTK_TEXTURRENDER_HH +#define FBTK_TEXTURRENDER_HH + +#include "Texture.hh" + +#include + +namespace FbTk { + +class ImageControl; + + +/// Renders texture to pixmap +/** + This is used with BImageControl to render textures +*/ +class TextureRender { +public: + TextureRender(ImageControl &ic, unsigned int width, unsigned int height, + XColor *_colors=0, size_t num_colors=0); + ~TextureRender(); + /// render to pixmap + Pixmap render(const FbTk::Texture &src_texture); + /// render solid texture to pixmap + Pixmap renderSolid(const FbTk::Texture &src_texture); + /// render gradient texture to pixmap + Pixmap renderGradient(const FbTk::Texture &src_texture); + +private: + /** + Render to pixmap + @return rendered pixmap + */ + Pixmap renderPixmap(); + /** + Render to XImage + @returns allocated and rendered XImage, user is responsible to deallocate + */ + XImage *renderXImage(); + /** + @name render functions + */ + //@{ + void invert(); + void bevel1(); + void bevel2(); + void dgradient(); + void egradient(); + void hgradient(); + void pgradient(); + void rgradient(); + void vgradient(); + void cdgradient(); + void pcgradient(); + //@} + void makeGradientBuffers(); + + ImageControl &control; + bool interlaced; + + XColor *colors; // color table + + const FbTk::Color *from, *to; + int red_offset, green_offset, blue_offset, red_bits, green_bits, blue_bits, + ncolors, cpc, cpccpc; + unsigned char *red, *green, *blue; + const unsigned char *red_table, *green_table, *blue_table; + unsigned int width, height; + unsigned int *xtable, *ytable; +}; + +}; // end namespace FbTk +#endif // FBTK_TEXTURERENDER_HH diff --git a/src/FbTk/Timer.cc b/src/FbTk/Timer.cc new file mode 100644 index 0000000..4305658 --- /dev/null +++ b/src/FbTk/Timer.cc @@ -0,0 +1,182 @@ +// Timer.cc for FbTk - Fluxbox Toolkit +// Copyright (c) 2003 Henrik Kinnunen (fluxgen at users.sourceforge.net) +// +// Timer.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. + +#include "Timer.hh" + +//use GNU extensions +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif // _GNU_SOURCE + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif // HAVE_CONFIG_H + +#include +#include +#include +#include + +namespace FbTk { + +Timer::TimerList Timer::m_timerlist; + +Timer::Timer(TimeoutHandler *h): + m_handler(h), + m_timing(false), + m_once(false) { +} + + +Timer::~Timer() { + if (isTiming()) stop(); +} + + +void Timer::setTimeout(long t) { + m_timeout.tv_sec = t / 1000; + m_timeout.tv_usec = t; + m_timeout.tv_usec -= (m_timeout.tv_sec * 1000); + m_timeout.tv_usec *= 1000; +} + + +void Timer::setTimeout(timeval t) { + m_timeout.tv_sec = t.tv_sec; + m_timeout.tv_usec = t.tv_usec; +} + + +void Timer::start() { + gettimeofday(&m_start, 0); + + if (! m_timing) { + m_timing = true; + addTimer(this); //add us to the list + } +} + + +void Timer::stop() { + m_timing = false; + removeTimer(this); //remove us from the list +} + + +void Timer::fireTimeout() { + if (m_handler) m_handler->timeout(); +} + +void Timer::updateTimers(int fd) { + fd_set rfds; + timeval now, tm, *timeout = 0; + + FD_ZERO(&rfds); + FD_SET(fd, &rfds); + + if (m_timerlist.size() > 0) { + gettimeofday(&now, 0); + + tm.tv_sec = tm.tv_usec = 0l; + + Timer *timer = m_timerlist.front(); + + tm.tv_sec = timer->getStartTime().tv_sec + + timer->getTimeout().tv_sec - now.tv_sec; + tm.tv_usec = timer->getStartTime().tv_usec + + timer->getTimeout().tv_usec - now.tv_usec; + + while (tm.tv_usec >= 1000000) { + tm.tv_sec++; + tm.tv_usec -= 1000000; + } + + while (tm.tv_usec < 0) { + if (tm.tv_sec > 0) { + tm.tv_sec--; + tm.tv_usec += 1000000; + } else { + tm.tv_usec = 0; + break; + } + } + + timeout = &tm; + } + + select(fd + 1, &rfds, 0, 0, timeout); + + // check for timer timeout + gettimeofday(&now, 0); + + TimerList::iterator it = m_timerlist.begin(); + //must check end ...the timer might remove + //it self from the list (should be fixed in the future) + for(; it != m_timerlist.end(); ++it) { + //This is to make sure we don't get an invalid iterator + //when we do fireTimeout + Timer &t = *(*it); + tm.tv_sec = t.getStartTime().tv_sec + + t.getTimeout().tv_sec; + tm.tv_usec = t.getStartTime().tv_usec + + t.getTimeout().tv_usec; + + if ((now.tv_sec < tm.tv_sec) || + (now.tv_sec == tm.tv_sec && now.tv_usec < tm.tv_usec)) + break; + + t.fireTimeout(); + // restart the current timer so that the start time is updated + if (! t.doOnce()) + t.start(); + else { + t.stop(); + it--; + } + } +} + +void Timer::addTimer(Timer *timer) { + assert(timer); + + TimerList::iterator it = m_timerlist.begin(); + TimerList::iterator it_end = m_timerlist.end(); + int index = 0; + for (; it != it_end; ++it, ++index) { + if (((*it)->getTimeout().tv_sec > timer->getTimeout().tv_sec) || + (((*it)->getTimeout().tv_sec == timer->getTimeout().tv_sec) && + ((*it)->getTimeout().tv_usec >= timer->getTimeout().tv_usec))) { + break; + } + } + m_timerlist.insert(it, timer); + +} + +void Timer::removeTimer(Timer *timer) { + assert(timer); + m_timerlist.remove(timer); +} + +}; // end namespace FbTk diff --git a/src/FbTk/Timer.hh b/src/FbTk/Timer.hh new file mode 100644 index 0000000..df86d60 --- /dev/null +++ b/src/FbTk/Timer.hh @@ -0,0 +1,96 @@ +// Timer.hh for FbTk - Fluxbox Toolkit +// Copyright (c) 2002-2003 Henrik Kinnunen (fluxgen at users.sourceforge.net) +// +// Timer.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. + +#ifndef FBTK_TIMER_HH +#define FBTK_TIMER_HH + +#include +#include + +namespace FbTk { + +/// Handles timeouts +/** + Inherit this to have a timed object, that calls + timeout function when the time is out +*/ +class TimeoutHandler { +public: + /// called when the time is out + virtual void timeout() = 0; +}; + +/** + Handles TimeoutHandles +*/ +class Timer { +public: + explicit Timer(TimeoutHandler *handler); + virtual ~Timer(); + + inline int isTiming() const { return m_timing; } + inline int doOnce() const { return m_once; } + + inline const timeval &getTimeout() const { return m_timeout; } + inline const timeval &getStartTime() const { return m_start; } + + inline void fireOnce(bool once) { m_once = once; } + /// set timeout + void setTimeout(long val); + /// set timeout + void setTimeout(timeval val); + /// start timing + void start(); + /// stop timing + void stop(); + /// update all timers + static void updateTimers(int file_descriptor); + +protected: + /// force a timeout + void fireTimeout(); + +private: + /// add a timer to the static list + static void addTimer(Timer *timer); + /// remove a timer from the static list + static void removeTimer(Timer *timer); + + typedef std::list TimerList; + static TimerList m_timerlist; ///< list of all timers + + TimeoutHandler *m_handler; ///< handler + + bool m_timing; ///< clock running? + bool m_once; ///< do timeout only once? + + timeval m_start; ///< start time + timeval m_timeout; ///< time length + +}; + +}; // end namespace FbTk + +#endif // FBTK_TIMER_HH + -- cgit v0.11.2