news download themes documentation links










ImageControl.cc

00001 // ImageControl.cc for FbTk - Fluxbox Toolkit
00002 // Copyright (c) 2001 - 2003 Henrik Kinnunen (fluxbox at users.sourceforge.net)
00003 //
00004 // Image.cc for Blackbox - an X11 Window manager
00005 // Copyright (c) 1997 - 2000 Brad Hughes (bhughes at tcac.net)
00006 //
00007 // Permission is hereby granted, free of charge, to any person obtaining a
00008 // copy of this software and associated documentation files (the "Software"),
00009 // to deal in the Software without restriction, including without limitation
00010 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
00011 // and/or sell copies of the Software, and to permit persons to whom the
00012 // Software is furnished to do so, subject to the following conditions:
00013 //
00014 // The above copyright notice and this permission notice shall be included in
00015 // all copies or substantial portions of the Software.
00016 //
00017 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
00018 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00019 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
00020 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
00021 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
00022 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
00023 // DEALINGS IN THE SOFTWARE.
00024 
00025 // $Id: ImageControl.cc,v 1.11 2004/01/11 12:40:47 fluxgen Exp $
00026 
00027 #include "ImageControl.hh"
00028 
00029 #include "TextureRender.hh"
00030 #include "App.hh"
00031 #include "SimpleCommand.hh"
00032 
00033 //use GNU extensions
00034 #ifndef _GNU_SOURCE
00035 #define _GNU_SOURCE
00036 #endif // _GNU_SOURCE
00037 
00038 
00039 #ifdef HAVE_CONFIG_H
00040 #include "config.h"
00041 #endif // HAVE_CONFIG_H
00042 
00043 #ifdef HAVE_SYS_TYPES_H
00044 #include <sys/types.h>
00045 #endif // HAVE_SYS_TYPES_H
00046 
00047 #include <cstdlib>
00048 #include <cstring>
00049 #include <cstdio>
00050 
00051 #ifdef HAVE_CTYPE_H
00052 #include <ctype.h>
00053 #endif // HAVE_CTYPE_H
00054 
00055 #include <iostream>
00056 
00057 using namespace std;
00058 
00059 namespace FbTk {
00060 
00061 // lookup table for texture
00062 unsigned long *ImageControl::sqrt_table = 0;
00063 #ifdef TIMEDCACHE
00064 bool ImageControl::s_timed_cache = true;
00065 #else
00066 bool ImageControl::s_timed_cache = false;
00067 #endif // TIMEDCACHE
00068 
00069 namespace { // anonymous
00070 
00071 inline unsigned long bsqrt(unsigned long x) {
00072     if (x <= 0) return 0;
00073     if (x == 1) return 1;
00074 
00075     unsigned long r = x >> 1;
00076     unsigned long q;
00077 
00078     while (1) {
00079         q = x / r;
00080         if (q >= r) return r;
00081         r = (r + q) >> 1;
00082     }
00083 }
00084 
00085 }; // end anonymous namespace
00086 
00087 ImageControl::ImageControl(int screen_num, bool dither,
00088                            int cpc, unsigned long cache_timeout, unsigned long cmax):
00089     m_dither(dither),
00090     m_colors(0),
00091     m_num_colors(0),
00092     m_colors_per_channel(cpc) {
00093 
00094     Display *disp = FbTk::App::instance()->display();
00095 
00096     m_screen_depth = DefaultDepth(disp, screen_num);
00097     m_screen_num = screen_num;
00098     m_root_window = RootWindow(disp, screen_num);
00099     m_visual = DefaultVisual(disp, screen_num);
00100     m_colormap = DefaultColormap(disp, screen_num);
00101 
00102     cache_max = cmax;
00103 
00104     if (cache_timeout && s_timed_cache) {
00105         m_timer.setTimeout(cache_timeout);
00106         RefCount<Command> clean_cache(new SimpleCommand<ImageControl>(*this, &ImageControl::cleanCache));
00107         m_timer.setCommand(clean_cache);
00108         m_timer.start();
00109     }
00110     
00111     createColorTable();
00112 }
00113 
00114 
00115 ImageControl::~ImageControl() {
00116     if (sqrt_table) {
00117         delete [] sqrt_table;
00118     }
00119 
00120     if (grad_xbuffer) {
00121         delete [] grad_xbuffer;
00122     }
00123 
00124     if (grad_ybuffer) {
00125         delete [] grad_ybuffer;
00126     }
00127 
00128     if (m_colors) {
00129         unsigned long *pixels = new unsigned long [m_num_colors];
00130 
00131         for (unsigned int color = 0; color < m_num_colors; color++)
00132             *(pixels + color) = (*(m_colors + color)).pixel;
00133 
00134         XFreeColors(FbTk::App::instance()->display(), m_colormap, pixels, m_num_colors, 0);
00135 
00136         delete [] m_colors;
00137     }
00138 
00139     if (cache.size() > 0) {
00140         CacheList::iterator it = cache.begin();
00141         CacheList::iterator it_end = cache.end();
00142         Display *disp = FbTk::App::instance()->display();
00143         for (; it != it_end; ++it) {
00144             XFreePixmap(disp, (*it)->pixmap);
00145             delete (*it);
00146         }
00147 
00148     }
00149 
00150 }
00151 
00152 
00153 Pixmap ImageControl::searchCache(unsigned int width, unsigned int height,
00154                                  const Texture &text) const {
00155     
00156     if (text.pixmap().drawable() != None) {
00157         // do comparsion with width/height and texture_pixmap
00158         CacheList::iterator it = cache.begin();
00159         CacheList::iterator it_end = cache.end();
00160         for (; it != it_end; ++it) {
00161             if ((*it)->texture_pixmap == text.pixmap().drawable() &&
00162                 (*it)->width == width && (*it)->height == height &&
00163                 (*it)->texture == text.type()) {
00164                 (*it)->count++;
00165                 return (*it)->pixmap;
00166             }
00167         }
00168         return None;
00169     }
00170 
00171     /*    Cache tmp;
00172     tmp.texture_pixmap = text.pixmap().drawable();
00173     tmp.width = width;
00174     tmp.height = height;
00175     tmp.texture = text.type();
00176     tmp.pixel1 = text.color().pixel();
00177     tmp.pixel2 = text.colorTo().pixel();
00178     */
00179     CacheList::iterator it = cache.begin();      
00180     CacheList::iterator it_end = cache.end();    
00181     for (; it != it_end; ++it) {     
00182         if (((*it)->width == width) &&   
00183             ((*it)->height == height) &&     
00184             ((*it)->texture == text.type()) &&   
00185             ((*it)->pixel1 == text.color().pixel())) {   
00186             if (text.type() & FbTk::Texture::GRADIENT) {     
00187                 if ((*it)->pixel2 == text.colorTo().pixel()) {   
00188                     (*it)->count++;      
00189                     return (*it)->pixmap;    
00190                 }    
00191             } else {     
00192                 (*it)->count++;      
00193                 return (*it)->pixmap;    
00194             }    
00195         }    
00196     }
00197 
00198     return None;
00199     
00200 }
00201 
00202 
00203 Pixmap ImageControl::renderImage(unsigned int width, unsigned int height,
00204                                  const FbTk::Texture &texture) {
00205 
00206     if (texture.type() & FbTk::Texture::PARENTRELATIVE)
00207         return ParentRelative;
00208 
00209     // search cache first
00210     Pixmap pixmap = searchCache(width, height, texture);
00211     if (pixmap) {
00212         return pixmap; // return cache item
00213     }
00214 
00215     // render new image
00216     TextureRender image(*this, width, height, m_colors, m_num_colors);
00217     pixmap = image.render(texture);
00218 
00219     if (pixmap) {
00220         // create new cache item and add it to cache list
00221 
00222         Cache *tmp = new Cache;
00223 
00224         tmp->pixmap = pixmap;
00225         tmp->texture_pixmap = texture.pixmap().drawable();
00226         tmp->width = width;
00227         tmp->height = height;
00228         tmp->count = 1;
00229         tmp->texture = texture.type();
00230         tmp->pixel1 = texture.color().pixel();
00231 
00232         if (texture.type() & FbTk::Texture::GRADIENT)
00233             tmp->pixel2 = texture.colorTo().pixel();
00234         else
00235             tmp->pixel2 = 0l;
00236 
00237         cache.push_back(tmp); 
00238 
00239         if ((unsigned) cache.size() > cache_max)
00240             cleanCache();
00241 
00242         return pixmap;
00243     }
00244 
00245     return None;
00246 }
00247 
00248 
00249 void ImageControl::removeImage(Pixmap pixmap) {
00250     if (!pixmap)
00251         return;
00252 
00253     CacheList::iterator it = cache.begin();
00254     CacheList::iterator it_end = cache.end();
00255     for (; it != it_end; ++it) {
00256         if ((*it)->pixmap == pixmap) {
00257             if ((*it)->count) {
00258                 (*it)->count--;
00259                 if (s_timed_cache) {
00260                     cleanCache();
00261                     return;
00262                 }
00263             }
00264 
00265             if ((*it)->count <= 0)
00266                 cleanCache();
00267 
00268             return;
00269         }
00270     }
00271 }
00272 
00273 
00274 void ImageControl::colorTables(const unsigned char **rmt, const unsigned char **gmt,
00275                                const unsigned char **bmt,
00276                                int *roff, int *goff, int *boff,
00277                                int *rbit, int *gbit, int *bbit) const {
00278 
00279     if (rmt) *rmt = red_color_table;
00280     if (gmt) *gmt = green_color_table;
00281     if (bmt) *bmt = blue_color_table;
00282 
00283     if (roff) *roff = red_offset;
00284     if (goff) *goff = green_offset;
00285     if (boff) *boff = blue_offset;
00286 
00287     if (rbit) *rbit = red_bits;
00288     if (gbit) *gbit = green_bits;
00289     if (bbit) *bbit = blue_bits;
00290 }
00291 
00292 
00293 void ImageControl::getXColorTable(XColor **c, int *n) {
00294     if (c) *c = m_colors;
00295     if (n) *n = m_num_colors;
00296 }
00297 
00298 
00299 void ImageControl::getGradientBuffers(unsigned int w,
00300                                       unsigned int h,
00301                                       unsigned int **xbuf,
00302                                       unsigned int **ybuf) {
00303 
00304     if (w > grad_buffer_width) {
00305         if (grad_xbuffer) {
00306             delete [] grad_xbuffer;
00307         }
00308 
00309         grad_buffer_width = w;
00310 
00311         grad_xbuffer = new unsigned int[grad_buffer_width * 3];
00312     }
00313 
00314     if (h > grad_buffer_height) {
00315         if (grad_ybuffer) {
00316             delete [] grad_ybuffer;
00317         }
00318 
00319         grad_buffer_height = h;
00320 
00321         grad_ybuffer = new unsigned int[grad_buffer_height * 3];
00322     }
00323 
00324     *xbuf = grad_xbuffer;
00325     *ybuf = grad_ybuffer;
00326 }
00327 
00328 
00329 void ImageControl::installRootColormap() {
00330     XGrabServer(FbTk::App::instance()->display());
00331 
00332 
00333     Display *disp = FbTk::App::instance()->display();
00334     bool install = true;
00335     int i = 0, ncmap = 0;
00336     Colormap *cmaps =
00337         XListInstalledColormaps(disp, m_root_window, &ncmap);
00338 
00339     if (cmaps) {
00340         for (i = 0; i < ncmap; i++) {
00341             if (*(cmaps + i) == m_colormap)
00342                 install = false;
00343         }
00344         
00345         if (install)
00346             XInstallColormap(disp, m_colormap);
00347 
00348         XFree(cmaps);
00349     }
00350 
00351     XUngrabServer(FbTk::App::instance()->display());
00352 }
00353 
00354 
00355 void ImageControl::setColorsPerChannel(int cpc) {
00356     if (cpc < 2) cpc = 2;
00357     if (cpc > 6) cpc = 6;
00358 
00359     m_colors_per_channel = cpc;
00360 }
00361 
00362 
00363 unsigned long ImageControl::getSqrt(unsigned int x) const {
00364     if (! sqrt_table) {
00365         // build sqrt table for use with elliptic gradient
00366 
00367         sqrt_table = new unsigned long[256 * 256 * 2 + 1];
00368         int i = 0;
00369 
00370         for (; i < (256 * 256 * 2); i++)
00371             sqrt_table[i] = bsqrt(i);
00372     }
00373 
00374     return sqrt_table[x];
00375 }
00376 
00377 void ImageControl::cleanCache() {
00378     Display *disp = FbTk::App::instance()->display();
00379     std::list<CacheList::iterator> deadlist;
00380     CacheList::iterator it = cache.begin();
00381     CacheList::iterator it_end = cache.end();
00382     for (; it != it_end; ++it) {
00383         Cache *tmp = (*it);
00384         if (tmp->count <= 0) {
00385             XFreePixmap(disp, tmp->pixmap);
00386             deadlist.push_back(it);
00387             delete tmp;
00388             tmp=0;
00389         } 
00390     }
00391 
00392     std::list<CacheList::iterator>::iterator dead_it = deadlist.begin();
00393     std::list<CacheList::iterator>::iterator dead_it_end = deadlist.end();
00394     for (; dead_it != dead_it_end; ++dead_it) {
00395         cache.erase(*dead_it);
00396     }
00397     
00398 }
00399 
00400 void ImageControl::createColorTable() {
00401     Display *disp = FbTk::App::instance()->display();
00402 
00403     grad_xbuffer = grad_ybuffer = (unsigned int *) 0;
00404     grad_buffer_width = grad_buffer_height = 0;
00405 
00406     int count;
00407     XPixmapFormatValues *pmv = XListPixmapFormats(disp, &count);
00408 
00409     if (pmv) {
00410         bits_per_pixel = 0;
00411         for (int i = 0; i < count; i++) {
00412             if (pmv[i].depth == m_screen_depth) {
00413                 bits_per_pixel = pmv[i].bits_per_pixel;
00414                 break;
00415             }
00416         }
00417 
00418         XFree(pmv);
00419     }
00420 
00421     if (bits_per_pixel == 0)
00422         bits_per_pixel = m_screen_depth;
00423     if (bits_per_pixel >= 24)
00424         setDither(false);
00425 
00426     red_offset = green_offset = blue_offset = 0;
00427 
00428     switch (visual()->c_class) {
00429     case TrueColor: {
00430         int i;
00431 
00432         // compute color tables
00433         unsigned long red_mask = visual()->red_mask,
00434             green_mask = visual()->green_mask,
00435             blue_mask = visual()->blue_mask;
00436 
00437         while (! (red_mask & 1)) { red_offset++; red_mask >>= 1; }
00438         while (! (green_mask & 1)) { green_offset++; green_mask >>= 1; }
00439         while (! (blue_mask & 1)) { blue_offset++; blue_mask >>= 1; }
00440 
00441         red_bits = 255 / red_mask;
00442         green_bits = 255 / green_mask;
00443         blue_bits = 255 / blue_mask;
00444 
00445         for (i = 0; i < 256; i++) {
00446             red_color_table[i] = i / red_bits;
00447             green_color_table[i] = i / green_bits;
00448             blue_color_table[i] = i / blue_bits;
00449         }
00450     }
00451 
00452         break;
00453 
00454     case PseudoColor:
00455     case StaticColor: {
00456 
00457         m_num_colors = m_colors_per_channel * m_colors_per_channel * m_colors_per_channel;
00458 
00459         if (m_num_colors > static_cast<unsigned int>(1 << m_screen_depth)) {
00460             m_colors_per_channel = (1 << m_screen_depth) / 3;
00461             m_num_colors = m_colors_per_channel * m_colors_per_channel * m_colors_per_channel;
00462         }
00463 
00464         if (m_colors_per_channel < 2 || m_num_colors > static_cast<unsigned int>(1 << m_screen_depth)) {
00465             fprintf(stderr, "ImageControl::ImageControl: invalid colormap size %d "
00466                     "(%d/%d/%d) - reducing",
00467                     m_num_colors, m_colors_per_channel, m_colors_per_channel,
00468                     m_colors_per_channel);
00469 
00470             m_colors_per_channel = (1 << m_screen_depth) / 3;
00471         }
00472 
00473         m_colors = new XColor[m_num_colors];
00474 
00475         int bits = 256 / m_colors_per_channel;
00476 
00477 #ifndef ORDEREDPSEUDO
00478         bits = 255 / (m_colors_per_channel - 1);
00479 #endif // ORDEREDPSEUDO
00480 
00481         red_bits = green_bits = blue_bits = bits;
00482 
00483         for (unsigned int i = 0; i < 256; i++) {
00484             red_color_table[i] = green_color_table[i] = blue_color_table[i] =
00485                 i / bits;
00486         }
00487 
00488         for (int r = 0, i = 0; r < m_colors_per_channel; r++) {
00489             for (int g = 0; g < m_colors_per_channel; g++) {
00490                 for (int b = 0; b < m_colors_per_channel; b++, i++) {
00491                     m_colors[i].red = (r * 0xffff) / (m_colors_per_channel - 1);
00492                     m_colors[i].green = (g * 0xffff) / (m_colors_per_channel - 1);
00493                     m_colors[i].blue = (b * 0xffff) / (m_colors_per_channel - 1);;
00494                     m_colors[i].flags = DoRed|DoGreen|DoBlue;
00495                 }
00496             }
00497         }
00498         
00499         for (unsigned int i = 0; i < m_num_colors; i++) {
00500             if (! XAllocColor(disp, m_colormap, &m_colors[i])) {
00501                 fprintf(stderr, "couldn't alloc color %i %i %i\n",
00502                         m_colors[i].red, m_colors[i].green, m_colors[i].blue);
00503                 m_colors[i].flags = 0;
00504             } else
00505                 m_colors[i].flags = DoRed|DoGreen|DoBlue;
00506         }
00507         
00508         XColor icolors[256];
00509         unsigned int incolors = (((1 << m_screen_depth) > 256) ? 256 : (1 << m_screen_depth));
00510 
00511         for (unsigned int i = 0; i < incolors; i++)
00512             icolors[i].pixel = i;
00513 
00514         XQueryColors(disp, m_colormap, icolors, incolors);
00515         for (unsigned int i = 0; i < m_num_colors; i++) {
00516             if (! m_colors[i].flags) {
00517                 unsigned long chk = 0xffffffff, pixel, close = 0;
00518                 char p = 2;
00519         
00520                 while (p--) {
00521                     for (unsigned int ii = 0; ii < incolors; ii++) {
00522                         int r = (m_colors[i].red - icolors[i].red) >> 8;
00523                         int g = (m_colors[i].green - icolors[i].green) >> 8;
00524                         int b = (m_colors[i].blue - icolors[i].blue) >> 8;
00525                         pixel = (r * r) + (g * g) + (b * b);
00526 
00527                         if (pixel < chk) {
00528                             chk = pixel;
00529                             close = ii;
00530                         }
00531 
00532                         m_colors[i].red = icolors[close].red;
00533                         m_colors[i].green = icolors[close].green;
00534                         m_colors[i].blue = icolors[close].blue;
00535 
00536                         if (XAllocColor(disp, m_colormap,
00537                                         &m_colors[i])) {
00538                             m_colors[i].flags = DoRed|DoGreen|DoBlue;
00539                             break;
00540                         }
00541                     }
00542                 }
00543             }
00544         }
00545 
00546         break;
00547     }
00548 
00549     case GrayScale:
00550     case StaticGray:
00551         {
00552 
00553             if (visual()->c_class == StaticGray) {
00554                 m_num_colors = 1 << m_screen_depth;
00555             } else {
00556                 m_num_colors = m_colors_per_channel * m_colors_per_channel * m_colors_per_channel;
00557 
00558                 if (m_num_colors > static_cast<unsigned int>(1 << m_screen_depth)) {
00559                     m_colors_per_channel = (1 << m_screen_depth) / 3;
00560                     m_num_colors = m_colors_per_channel * m_colors_per_channel * m_colors_per_channel;
00561                 }
00562             }
00563 
00564             if (m_colors_per_channel < 2 || m_num_colors > static_cast<unsigned int>(1 << m_screen_depth)) {
00565                 fprintf(stderr,"FbTk::ImageControl: invalid colormap size %d "
00566                         "(%d/%d/%d) - reducing",
00567                         m_num_colors, m_colors_per_channel, m_colors_per_channel,
00568                         m_colors_per_channel);
00569 
00570                 m_colors_per_channel = (1 << m_screen_depth) / 3;
00571             }
00572 
00573             m_colors = new XColor[m_num_colors];
00574 
00575             int p, bits = 255 / (m_colors_per_channel - 1);
00576             red_bits = green_bits = blue_bits = bits;
00577 
00578             for (unsigned int i = 0; i < 256; i++)
00579                 red_color_table[i] = green_color_table[i] = blue_color_table[i] =
00580                     i / bits;
00581 
00582             for (unsigned int i = 0; i < m_num_colors; i++) {
00583                 m_colors[i].red = (i * 0xffff) / (m_colors_per_channel - 1);
00584                 m_colors[i].green = (i * 0xffff) / (m_colors_per_channel - 1);
00585                 m_colors[i].blue = (i * 0xffff) / (m_colors_per_channel - 1);;
00586                 m_colors[i].flags = DoRed|DoGreen|DoBlue;
00587 
00588                 if (! XAllocColor(disp, m_colormap,
00589                                   &m_colors[i])) {
00590                     fprintf(stderr, "Couldn't alloc color %i %i %i\n",
00591                             m_colors[i].red, m_colors[i].green, m_colors[i].blue);
00592                     m_colors[i].flags = 0;
00593                 } else
00594                     m_colors[i].flags = DoRed|DoGreen|DoBlue;
00595             }
00596 
00597 
00598             XColor icolors[256];
00599             unsigned int incolors = (((1 << m_screen_depth) > 256) ? 256 :
00600                                      (1 << m_screen_depth));
00601 
00602             for (unsigned int i = 0; i < incolors; i++)
00603                 icolors[i].pixel = i;
00604 
00605             XQueryColors(disp, m_colormap, icolors, incolors);
00606             for (unsigned int i = 0; i < m_num_colors; i++) {
00607                 if (! m_colors[i].flags) {
00608                     unsigned long chk = 0xffffffff, pixel, close = 0;
00609 
00610                     p = 2;
00611                     while (p--) {
00612                         for (unsigned int ii = 0; ii < incolors; ii++) {
00613                             int r = (m_colors[i].red - icolors[i].red) >> 8;
00614                             int g = (m_colors[i].green - icolors[i].green) >> 8;
00615                             int b = (m_colors[i].blue - icolors[i].blue) >> 8;
00616                             pixel = (r * r) + (g * g) + (b * b);
00617 
00618                             if (pixel < chk) {
00619                                 chk = pixel;
00620                                 close = ii;
00621                             }
00622 
00623                             m_colors[i].red = icolors[close].red;
00624                             m_colors[i].green = icolors[close].green;
00625                             m_colors[i].blue = icolors[close].blue;
00626 
00627                             if (XAllocColor(disp, m_colormap, &m_colors[i])) {
00628                                 m_colors[i].flags = DoRed|DoGreen|DoBlue;
00629                                 break;
00630                             }
00631                         }
00632                     }
00633                 }
00634             }
00635 
00636             break;
00637         }
00638 
00639     default:
00640         cerr<<"FbTk::ImageControl: Unsupported visual"<<endl;
00641         break;
00642     }
00643 }
00644 
00645 }; // end namespace FbTk

Fluxbox CVS-Jan-2003




      



Got comments about the page? Send them to webmaster.
If you have general Fluxbox related questions ask them on our irc channel or mailing lists.

Show Source








Designed by aLEczapKA