File remove-kdefx-dependency.diff of Package thinkeramik

--- widget-engine/Makefile.am
+++ widget-engine/Makefile.am
@@ -1,13 +1,13 @@
 AM_CPPFLAGS = -DQT_PLUGIN
 
-INCLUDES = -I$(top_srcdir)/kdefx $(all_includes)
+INCLUDES = $(all_includes)
 # qembed's output needs that...
 KDE_CXXFLAGS = -UQT_NO_ASCII_CAST
 noinst_HEADERS = thinkeramik.h pixmaploader.h thinkeramikimage.h bitmaps.h gradients.h colorutil.h
 kde_style_LTLIBRARIES = thinkeramik.la
 thinkeramik_la_LDFLAGS = $(all_libraries) $(KDE_PLUGIN) -module
-thinkeramik_la_LIBADD = -lkdefx
-thinkeramik_la_SOURCES = thinkeramik.cpp pixmaploader.cpp gradients.cpp colorutil.cpp
+thinkeramik_la_LIBADD = -lqt-mt
+thinkeramik_la_SOURCES = thinkeramik.cpp pixmaploader.cpp gradients.cpp colorutil.cpp kpixmapeffect.cpp kimageeffect.cpp kpixmap.cpp kstyle.cpp
 thinkeramik_la_COMPILE_FIRST = thinkeramikrc.h
 thinkeramik_la_METASOURCES = AUTO
 
--- widget-engine/kimageeffect.cpp
+++ widget-engine/kimageeffect.cpp
@@ -0,0 +1,4927 @@
+/* This file is part of the KDE libraries
+    Copyright (C) 1998, 1999, 2001, 2002 Daniel M. Duley <mosfet@kde.org>
+    (C) 1998, 1999 Christian Tibirna <ctibirna@total.net>
+    (C) 1998, 1999 Dirk Mueller <mueller@kde.org>
+    (C) 1999 Geert Jansen <g.t.jansen@stud.tue.nl>
+    (C) 2000 Josef Weidendorfer <weidendo@in.tum.de>
+    (C) 2004 Zack Rusin <zack@kde.org>
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+// $Id$
+
+#include <math.h>
+#include <assert.h>
+
+#include <qimage.h>
+#include <stdlib.h>
+#include <iostream>
+
+#include "kimageeffect.h"
+#include "kcpuinfo.h"
+
+#include <config.h>
+
+#if 0
+//disabled until #74478 fixed.
+
+#if defined(__i386__) && ( defined(__GNUC__) || defined(__INTEL_COMPILER) )
+#  if defined( HAVE_X86_MMX )
+#    define USE_MMX_INLINE_ASM
+#  endif
+#  if defined( HAVE_X86_SSE2 )
+#    define USE_SSE2_INLINE_ASM
+#  endif
+#endif
+
+#endif
+//======================================================================
+//
+// Utility stuff for effects ported from ImageMagick to QImage
+//
+//======================================================================
+#define MaxRGB 255L
+#define DegreesToRadians(x) ((x)*M_PI/180.0)
+#define MagickSQ2PI 2.50662827463100024161235523934010416269302368164062
+#define MagickEpsilon  1.0e-12
+#define MagickPI  3.14159265358979323846264338327950288419716939937510
+#define MOD(x, y) ((x) < 0 ? ((y) - 1 - ((y) - 1 - (x)) % (y)) : (x) % (y))
+
+/**
+ * \relates KGlobal
+ * A typesafe function that returns x if it's between low and high values.
+ * low if x is smaller than then low and high if x is bigger than high.
+ */
+#define FXCLAMP(x,low,high) fxClamp(x,low,high)
+template<class T>
+inline const T& fxClamp( const T& x, const T& low, const T& high )
+{
+    if ( x < low )       return low;
+    else if ( x > high ) return high;
+    else                 return x;
+}
+
+static inline unsigned int intensityValue(unsigned int color)
+{
+    return((unsigned int)((0.299*qRed(color) +
+                           0.587*qGreen(color) +
+                           0.1140000000000001*qBlue(color))));
+}
+
+template<typename T>
+static inline void liberateMemory(T **memory)
+{
+    assert(memory != NULL);
+    if(*memory == NULL) return;
+    free((char*)*memory);
+    *memory=NULL;
+}
+
+struct double_packet
+{
+    double red;
+    double green;
+    double blue;
+    double alpha;
+};
+
+struct short_packet
+{
+    unsigned short int red;
+    unsigned short int green;
+    unsigned short int blue;
+    unsigned short int alpha;
+};
+
+
+//======================================================================
+//
+// Gradient effects
+//
+//======================================================================
+
+QImage KImageEffect::gradient(const QSize &size, const QColor &ca,
+	const QColor &cb, GradientType eff, int ncols)
+{
+    int rDiff, gDiff, bDiff;
+    int rca, gca, bca, rcb, gcb, bcb;
+
+    QImage image(size, 32);
+
+    if (size.width() == 0 || size.height() == 0) {
+#ifndef NDEBUG
+      std::cerr << "WARNING: KImageEffect::gradient: invalid image" << std::endl;
+#endif
+      return image;
+    }
+
+    register int x, y;
+
+    rDiff = (rcb = cb.red())   - (rca = ca.red());
+    gDiff = (gcb = cb.green()) - (gca = ca.green());
+    bDiff = (bcb = cb.blue())  - (bca = ca.blue());
+
+    if( eff == VerticalGradient || eff == HorizontalGradient ){
+
+        uint *p;
+        uint rgb;
+
+        register int rl = rca << 16;
+        register int gl = gca << 16;
+        register int bl = bca << 16;
+
+        if( eff == VerticalGradient ) {
+
+            int rcdelta = ((1<<16) / size.height()) * rDiff;
+            int gcdelta = ((1<<16) / size.height()) * gDiff;
+            int bcdelta = ((1<<16) / size.height()) * bDiff;
+
+            for ( y = 0; y < size.height(); y++ ) {
+                p = (uint *) image.scanLine(y);
+
+                rl += rcdelta;
+                gl += gcdelta;
+                bl += bcdelta;
+
+                rgb = qRgb( (rl>>16), (gl>>16), (bl>>16) );
+
+                for( x = 0; x < size.width(); x++ ) {
+                    *p = rgb;
+                    p++;
+                }
+            }
+
+        }
+        else {                  // must be HorizontalGradient
+
+            unsigned int *o_src = (unsigned int *)image.scanLine(0);
+            unsigned int *src = o_src;
+
+            int rcdelta = ((1<<16) / size.width()) * rDiff;
+            int gcdelta = ((1<<16) / size.width()) * gDiff;
+            int bcdelta = ((1<<16) / size.width()) * bDiff;
+
+            for( x = 0; x < size.width(); x++) {
+
+                rl += rcdelta;
+                gl += gcdelta;
+                bl += bcdelta;
+
+                *src++ = qRgb( (rl>>16), (gl>>16), (bl>>16));
+            }
+
+            src = o_src;
+
+            // Believe it or not, manually copying in a for loop is faster
+            // than calling memcpy for each scanline (on the order of ms...).
+            // I think this is due to the function call overhead (mosfet).
+
+            for (y = 1; y < size.height(); ++y) {
+
+                p = (unsigned int *)image.scanLine(y);
+                src = o_src;
+                for(x=0; x < size.width(); ++x)
+                    *p++ = *src++;
+            }
+        }
+    }
+
+    else {
+
+        float rfd, gfd, bfd;
+        float rd = rca, gd = gca, bd = bca;
+
+        unsigned char *xtable[3];
+        unsigned char *ytable[3];
+
+        unsigned int w = size.width(), h = size.height();
+        xtable[0] = new unsigned char[w];
+        xtable[1] = new unsigned char[w];
+        xtable[2] = new unsigned char[w];
+        ytable[0] = new unsigned char[h];
+        ytable[1] = new unsigned char[h];
+        ytable[2] = new unsigned char[h];
+        w*=2, h*=2;
+
+        if ( eff == DiagonalGradient || eff == CrossDiagonalGradient) {
+            // Diagonal dgradient code inspired by BlackBox (mosfet)
+            // BlackBox dgradient is (C) Brad Hughes, <bhughes@tcac.net> and
+            // Mike Cole <mike@mydot.com>.
+
+            rfd = (float)rDiff/w;
+            gfd = (float)gDiff/w;
+            bfd = (float)bDiff/w;
+
+            int dir;
+            for (x = 0; x < size.width(); x++, rd+=rfd, gd+=gfd, bd+=bfd) {
+                dir = eff == DiagonalGradient? x : size.width() - x - 1;
+                xtable[0][dir] = (unsigned char) rd;
+                xtable[1][dir] = (unsigned char) gd;
+                xtable[2][dir] = (unsigned char) bd;
+            }
+            rfd = (float)rDiff/h;
+            gfd = (float)gDiff/h;
+            bfd = (float)bDiff/h;
+            rd = gd = bd = 0;
+            for (y = 0; y < size.height(); y++, rd+=rfd, gd+=gfd, bd+=bfd) {
+                ytable[0][y] = (unsigned char) rd;
+                ytable[1][y] = (unsigned char) gd;
+                ytable[2][y] = (unsigned char) bd;
+            }
+
+            for (y = 0; y < size.height(); y++) {
+                unsigned int *scanline = (unsigned int *)image.scanLine(y);
+                for (x = 0; x < size.width(); x++) {
+                    scanline[x] = qRgb(xtable[0][x] + ytable[0][y],
+                                       xtable[1][x] + ytable[1][y],
+                                       xtable[2][x] + ytable[2][y]);
+                }
+            }
+        }
+
+        else if (eff == RectangleGradient ||
+                 eff == PyramidGradient ||
+                 eff == PipeCrossGradient ||
+                 eff == EllipticGradient)
+        {
+            int rSign = rDiff>0? 1: -1;
+            int gSign = gDiff>0? 1: -1;
+            int bSign = bDiff>0? 1: -1;
+
+            rfd = (float)rDiff / size.width();
+            gfd = (float)gDiff / size.width();
+            bfd = (float)bDiff / size.width();
+
+            rd = (float)rDiff/2;
+            gd = (float)gDiff/2;
+            bd = (float)bDiff/2;
+
+            for (x = 0; x < size.width(); x++, rd-=rfd, gd-=gfd, bd-=bfd)
+            {
+                xtable[0][x] = (unsigned char) abs((int)rd);
+                xtable[1][x] = (unsigned char) abs((int)gd);
+                xtable[2][x] = (unsigned char) abs((int)bd);
+            }
+
+            rfd = (float)rDiff/size.height();
+            gfd = (float)gDiff/size.height();
+            bfd = (float)bDiff/size.height();
+
+            rd = (float)rDiff/2;
+            gd = (float)gDiff/2;
+            bd = (float)bDiff/2;
+
+            for (y = 0; y < size.height(); y++, rd-=rfd, gd-=gfd, bd-=bfd)
+            {
+                ytable[0][y] = (unsigned char) abs((int)rd);
+                ytable[1][y] = (unsigned char) abs((int)gd);
+                ytable[2][y] = (unsigned char) abs((int)bd);
+            }
+
+            int h = (size.height()+1)>>1;
+            for (y = 0; y < h; y++) {
+                unsigned int *sl1 = (unsigned int *)image.scanLine(y);
+                unsigned int *sl2 = (unsigned int *)image.scanLine(QMAX(size.height()-y-1, y));
+
+                int w = (size.width()+1)>>1;
+                int x2 = size.width()-1;
+
+                for (x = 0; x < w; x++, x2--) {
+		    unsigned int rgb = 0;
+                    if (eff == PyramidGradient) {
+                        rgb = qRgb(rcb-rSign*(xtable[0][x]+ytable[0][y]),
+                                   gcb-gSign*(xtable[1][x]+ytable[1][y]),
+                                   bcb-bSign*(xtable[2][x]+ytable[2][y]));
+                    }
+                    if (eff == RectangleGradient) {
+                        rgb = qRgb(rcb - rSign *
+                                   QMAX(xtable[0][x], ytable[0][y]) * 2,
+                                   gcb - gSign *
+                                   QMAX(xtable[1][x], ytable[1][y]) * 2,
+                                   bcb - bSign *
+                                   QMAX(xtable[2][x], ytable[2][y]) * 2);
+                    }
+                    if (eff == PipeCrossGradient) {
+                        rgb = qRgb(rcb - rSign *
+                                   QMIN(xtable[0][x], ytable[0][y]) * 2,
+                                   gcb - gSign *
+                                   QMIN(xtable[1][x], ytable[1][y]) * 2,
+                                   bcb - bSign *
+                                   QMIN(xtable[2][x], ytable[2][y]) * 2);
+                    }
+                    if (eff == EllipticGradient) {
+                        rgb = qRgb(rcb - rSign *
+                                   (int)sqrt((xtable[0][x]*xtable[0][x] +
+                                              ytable[0][y]*ytable[0][y])*2.0),
+                                   gcb - gSign *
+                                   (int)sqrt((xtable[1][x]*xtable[1][x] +
+                                              ytable[1][y]*ytable[1][y])*2.0),
+                                   bcb - bSign *
+                                   (int)sqrt((xtable[2][x]*xtable[2][x] +
+                                              ytable[2][y]*ytable[2][y])*2.0));
+                    }
+
+                    sl1[x] = sl2[x] = rgb;
+                    sl1[x2] = sl2[x2] = rgb;
+                }
+            }
+        }
+
+        delete [] xtable[0];
+        delete [] xtable[1];
+        delete [] xtable[2];
+        delete [] ytable[0];
+        delete [] ytable[1];
+        delete [] ytable[2];
+    }
+
+    // dither if necessary
+    if (ncols && (QPixmap::defaultDepth() < 15 )) {
+	if ( ncols < 2 || ncols > 256 )
+	    ncols = 3;
+	QColor *dPal = new QColor[ncols];
+	for (int i=0; i<ncols; i++) {
+	    dPal[i].setRgb ( rca + rDiff * i / ( ncols - 1 ),
+			     gca + gDiff * i / ( ncols - 1 ),
+			     bca + bDiff * i / ( ncols - 1 ) );
+	}
+        dither(image, dPal, ncols);
+        delete [] dPal;
+    }
+
+    return image;
+}
+
+
+// -----------------------------------------------------------------------------
+
+//CT this was (before Dirk A. Mueller's speedup changes)
+//   merely the same code as in the above method, but it's supposedly
+//   way less performant since it introduces a lot of supplementary tests
+//   and simple math operations for the calculus of the balance.
+//      (surprizingly, it isn't less performant, in the contrary :-)
+//   Yes, I could have merged them, but then the excellent performance of
+//   the balanced code would suffer with no other gain than a mere
+//   source code and byte code size economy.
+
+QImage KImageEffect::unbalancedGradient(const QSize &size, const QColor &ca,
+	const QColor &cb, GradientType eff, int xfactor, int yfactor,
+	int ncols)
+{
+    int dir; // general parameter used for direction switches
+
+    bool _xanti = false , _yanti = false;
+
+    if (xfactor < 0) _xanti = true; // negative on X direction
+    if (yfactor < 0) _yanti = true; // negative on Y direction
+
+    xfactor = abs(xfactor);
+    yfactor = abs(yfactor);
+
+    if (!xfactor) xfactor = 1;
+    if (!yfactor) yfactor = 1;
+
+    if (xfactor > 200 ) xfactor = 200;
+    if (yfactor > 200 ) yfactor = 200;
+
+
+    //    float xbal = xfactor/5000.;
+    //    float ybal = yfactor/5000.;
+    float xbal = xfactor/30./size.width();
+    float ybal = yfactor/30./size.height();
+    float rat;
+
+    int rDiff, gDiff, bDiff;
+    int rca, gca, bca, rcb, gcb, bcb;
+
+    QImage image(size, 32);
+
+    if (size.width() == 0 || size.height() == 0) {
+#ifndef NDEBUG
+      std::cerr << "WARNING: KImageEffect::unbalancedGradient : invalid image\n";
+#endif
+      return image;
+    }
+
+    register int x, y;
+    unsigned int *scanline;
+
+    rDiff = (rcb = cb.red())   - (rca = ca.red());
+    gDiff = (gcb = cb.green()) - (gca = ca.green());
+    bDiff = (bcb = cb.blue())  - (bca = ca.blue());
+
+    if( eff == VerticalGradient || eff == HorizontalGradient){
+        QColor cRow;
+
+        uint *p;
+        uint rgbRow;
+
+	if( eff == VerticalGradient) {
+	  for ( y = 0; y < size.height(); y++ ) {
+	    dir = _yanti ? y : size.height() - 1 - y;
+            p = (uint *) image.scanLine(dir);
+            rat =  1 - exp( - (float)y  * ybal );
+
+            cRow.setRgb( rcb - (int) ( rDiff * rat ),
+                         gcb - (int) ( gDiff * rat ),
+                         bcb - (int) ( bDiff * rat ) );
+
+            rgbRow = cRow.rgb();
+
+            for( x = 0; x < size.width(); x++ ) {
+	      *p = rgbRow;
+	      p++;
+            }
+	  }
+	}
+	else {
+
+	  unsigned int *src = (unsigned int *)image.scanLine(0);
+	  for(x = 0; x < size.width(); x++ )
+          {
+	      dir = _xanti ? x : size.width() - 1 - x;
+	      rat = 1 - exp( - (float)x  * xbal );
+
+              src[dir] = qRgb(rcb - (int) ( rDiff * rat ),
+                              gcb - (int) ( gDiff * rat ),
+                              bcb - (int) ( bDiff * rat ));
+          }
+
+	  // Believe it or not, manually copying in a for loop is faster
+	  // than calling memcpy for each scanline (on the order of ms...).
+	  // I think this is due to the function call overhead (mosfet).
+
+	  for(y = 1; y < size.height(); ++y)
+          {
+	      scanline = (unsigned int *)image.scanLine(y);
+	      for(x=0; x < size.width(); ++x)
+                  scanline[x] = src[x];
+          }
+	}
+    }
+
+    else {
+      int w=size.width(), h=size.height();
+
+      unsigned char *xtable[3];
+      unsigned char *ytable[3];
+      xtable[0] = new unsigned char[w];
+      xtable[1] = new unsigned char[w];
+      xtable[2] = new unsigned char[w];
+      ytable[0] = new unsigned char[h];
+      ytable[1] = new unsigned char[h];
+      ytable[2] = new unsigned char[h];
+
+      if ( eff == DiagonalGradient || eff == CrossDiagonalGradient)
+      {
+	  for (x = 0; x < w; x++) {
+              dir = _xanti ? x : w - 1 - x;
+              rat = 1 - exp( - (float)x * xbal );
+
+              xtable[0][dir] = (unsigned char) ( rDiff/2 * rat );
+              xtable[1][dir] = (unsigned char) ( gDiff/2 * rat );
+              xtable[2][dir] = (unsigned char) ( bDiff/2 * rat );
+          }
+
+	  for (y = 0; y < h; y++) {
+              dir = _yanti ? y : h - 1 - y;
+              rat =  1 - exp( - (float)y  * ybal );
+
+              ytable[0][dir] = (unsigned char) ( rDiff/2 * rat );
+              ytable[1][dir] = (unsigned char) ( gDiff/2 * rat );
+              ytable[2][dir] = (unsigned char) ( bDiff/2 * rat );
+          }
+
+	  for (y = 0; y < h; y++) {
+              unsigned int *scanline = (unsigned int *)image.scanLine(y);
+              for (x = 0; x < w; x++) {
+                  scanline[x] = qRgb(rcb - (xtable[0][x] + ytable[0][y]),
+                                     gcb - (xtable[1][x] + ytable[1][y]),
+                                     bcb - (xtable[2][x] + ytable[2][y]));
+              }
+          }
+      }
+
+      else if (eff == RectangleGradient ||
+               eff == PyramidGradient ||
+               eff == PipeCrossGradient ||
+               eff == EllipticGradient)
+      {
+          int rSign = rDiff>0? 1: -1;
+          int gSign = gDiff>0? 1: -1;
+          int bSign = bDiff>0? 1: -1;
+
+          for (x = 0; x < w; x++)
+          {
+              dir = _xanti ? x : w - 1 - x;
+              rat =  1 - exp( - (float)x * xbal );
+
+              xtable[0][dir] = (unsigned char) abs((int)(rDiff*(0.5-rat)));
+              xtable[1][dir] = (unsigned char) abs((int)(gDiff*(0.5-rat)));
+              xtable[2][dir] = (unsigned char) abs((int)(bDiff*(0.5-rat)));
+          }
+
+          for (y = 0; y < h; y++)
+          {
+              dir = _yanti ? y : h - 1 - y;
+
+              rat =  1 - exp( - (float)y * ybal );
+
+              ytable[0][dir] = (unsigned char) abs((int)(rDiff*(0.5-rat)));
+              ytable[1][dir] = (unsigned char) abs((int)(gDiff*(0.5-rat)));
+              ytable[2][dir] = (unsigned char) abs((int)(bDiff*(0.5-rat)));
+          }
+
+          for (y = 0; y < h; y++) {
+              unsigned int *scanline = (unsigned int *)image.scanLine(y);
+              for (x = 0; x < w; x++) {
+                  if (eff == PyramidGradient)
+                  {
+                      scanline[x] = qRgb(rcb-rSign*(xtable[0][x]+ytable[0][y]),
+                                         gcb-gSign*(xtable[1][x]+ytable[1][y]),
+                                         bcb-bSign*(xtable[2][x]+ytable[2][y]));
+                  }
+                  else if (eff == RectangleGradient)
+                  {
+                      scanline[x] = qRgb(rcb - rSign *
+                                         QMAX(xtable[0][x], ytable[0][y]) * 2,
+                                         gcb - gSign *
+                                         QMAX(xtable[1][x], ytable[1][y]) * 2,
+                                         bcb - bSign *
+                                         QMAX(xtable[2][x], ytable[2][y]) * 2);
+                  }
+                  else if (eff == PipeCrossGradient)
+                  {
+                      scanline[x] = qRgb(rcb - rSign *
+                                         QMIN(xtable[0][x], ytable[0][y]) * 2,
+                                         gcb - gSign *
+                                         QMIN(xtable[1][x], ytable[1][y]) * 2,
+                                         bcb - bSign *
+                                         QMIN(xtable[2][x], ytable[2][y]) * 2);
+                  }
+                  else if (eff == EllipticGradient)
+                  {
+                      scanline[x] = qRgb(rcb - rSign *
+                                         (int)sqrt((xtable[0][x]*xtable[0][x] +
+                                                    ytable[0][y]*ytable[0][y])*2.0),
+                                         gcb - gSign *
+                                         (int)sqrt((xtable[1][x]*xtable[1][x] +
+                                                    ytable[1][y]*ytable[1][y])*2.0),
+                                         bcb - bSign *
+                                         (int)sqrt((xtable[2][x]*xtable[2][x] +
+                                                    ytable[2][y]*ytable[2][y])*2.0));
+                  }
+              }
+          }
+      }
+
+      if (ncols && (QPixmap::defaultDepth() < 15 )) {
+          if ( ncols < 2 || ncols > 256 )
+              ncols = 3;
+          QColor *dPal = new QColor[ncols];
+          for (int i=0; i<ncols; i++) {
+              dPal[i].setRgb ( rca + rDiff * i / ( ncols - 1 ),
+                               gca + gDiff * i / ( ncols - 1 ),
+                               bca + bDiff * i / ( ncols - 1 ) );
+          }
+          dither(image, dPal, ncols);
+          delete [] dPal;
+      }
+
+      delete [] xtable[0];
+      delete [] xtable[1];
+      delete [] xtable[2];
+      delete [] ytable[0];
+      delete [] ytable[1];
+      delete [] ytable[2];
+
+    }
+
+    return image;
+}
+
+/**
+Types for MMX and SSE packing of colors, for safe constraints
+*/
+namespace {
+
+struct KIE4Pack
+{
+    Q_UINT16 data[4];
+};
+
+struct KIE8Pack
+{
+    Q_UINT16 data[8];
+};
+
+}
+
+//======================================================================
+//
+// Intensity effects
+//
+//======================================================================
+
+
+/* This builds a 256 byte unsigned char lookup table with all
+ * the possible percent values prior to applying the effect, then uses
+ * integer math for the pixels. For any image larger than 9x9 this will be
+ * less expensive than doing a float operation on the 3 color components of
+ * each pixel. (mosfet)
+ */
+QImage& KImageEffect::intensity(QImage &image, float percent)
+{
+    if (image.width() == 0 || image.height() == 0) {
+#ifndef NDEBUG
+      std::cerr << "WARNING: KImageEffect::intensity : invalid image\n";
+#endif
+      return image;
+    }
+
+    int segColors = image.depth() > 8 ? 256 : image.numColors();
+    int pixels = image.depth() > 8 ? image.width()*image.height() :
+                 image.numColors();
+    unsigned int *data = image.depth() > 8 ? (unsigned int *)image.bits() :
+                         (unsigned int *)image.colorTable();
+
+    bool brighten = (percent >= 0);
+    if(percent < 0)
+        percent = -percent;
+
+#ifdef USE_MMX_INLINE_ASM
+    bool haveMMX = KCPUInfo::haveExtension( KCPUInfo::IntelMMX );
+
+    if(haveMMX)
+    {
+        Q_UINT16 p = Q_UINT16(256.0f*(percent));
+        KIE4Pack mult = {{p,p,p,0}};
+
+        __asm__ __volatile__(
+        "pxor %%mm7, %%mm7\n\t"                // zero mm7 for unpacking
+        "movq  (%0), %%mm6\n\t"                // copy intensity change to mm6
+        : : "r"(&mult), "m"(mult));
+
+        unsigned int rem = pixels % 4;
+        pixels -= rem;
+        Q_UINT32 *end = ( data + pixels );
+
+        if (brighten)
+        {
+            while ( data != end ) {
+                __asm__ __volatile__(
+                "movq       (%0), %%mm0\n\t"
+                "movq      8(%0), %%mm4\n\t"   // copy 4 pixels of data to mm0 and mm4
+                "movq      %%mm0, %%mm1\n\t"
+                "movq      %%mm0, %%mm3\n\t"
+                "movq      %%mm4, %%mm5\n\t"   // copy to registers for unpacking
+                "punpcklbw %%mm7, %%mm0\n\t"
+                "punpckhbw %%mm7, %%mm1\n\t"   // unpack the two pixels from mm0
+                "pmullw    %%mm6, %%mm0\n\t"
+                "punpcklbw %%mm7, %%mm4\n\t"
+                "pmullw    %%mm6, %%mm1\n\t"   // multiply by intensity*256
+                "psrlw        $8, %%mm0\n\t"   // divide by 256
+                "pmullw    %%mm6, %%mm4\n\t"
+                "psrlw        $8, %%mm1\n\t"
+                "psrlw        $8, %%mm4\n\t"
+                "packuswb  %%mm1, %%mm0\n\t"   // pack solution into mm0. saturates at 255
+                "movq      %%mm5, %%mm1\n\t"
+
+                "punpckhbw %%mm7, %%mm1\n\t"   // unpack 4th pixel in mm1
+
+                "pmullw    %%mm6, %%mm1\n\t"
+                "paddusb   %%mm3, %%mm0\n\t"   // add intesity result to original of mm0
+                "psrlw        $8, %%mm1\n\t"
+                "packuswb  %%mm1, %%mm4\n\t"   // pack upper two pixels into mm4
+
+                "movq      %%mm0, (%0)\n\t"    // rewrite to memory lower two pixels
+                "paddusb   %%mm5, %%mm4\n\t"
+                "movq      %%mm4, 8(%0)\n\t"   // rewrite upper two pixels
+                : : "r"(data) );
+                data += 4;
+            }
+
+            end += rem;
+            while ( data != end ) {
+                __asm__ __volatile__(
+                "movd       (%0), %%mm0\n\t"   // repeat above but for
+                "punpcklbw %%mm7, %%mm0\n\t"   // one pixel at a time
+                "movq      %%mm0, %%mm3\n\t"
+                "pmullw    %%mm6, %%mm0\n\t"
+                "psrlw        $8, %%mm0\n\t"
+                "paddw     %%mm3, %%mm0\n\t"
+                "packuswb  %%mm0, %%mm0\n\t"
+                "movd      %%mm0, (%0)\n\t"
+                : : "r"(data) );
+		data++;
+            }
+        }
+        else
+        {
+            while ( data != end ) {
+                __asm__ __volatile__(
+                "movq       (%0), %%mm0\n\t"
+                "movq      8(%0), %%mm4\n\t"
+                "movq      %%mm0, %%mm1\n\t"
+                "movq      %%mm0, %%mm3\n\t"
+
+                "movq      %%mm4, %%mm5\n\t"
+
+                "punpcklbw %%mm7, %%mm0\n\t"
+                "punpckhbw %%mm7, %%mm1\n\t"
+                "pmullw    %%mm6, %%mm0\n\t"
+                "punpcklbw %%mm7, %%mm4\n\t"
+                "pmullw    %%mm6, %%mm1\n\t"
+                "psrlw        $8, %%mm0\n\t"
+                "pmullw    %%mm6, %%mm4\n\t"
+                "psrlw        $8, %%mm1\n\t"
+                "psrlw        $8, %%mm4\n\t"
+                "packuswb  %%mm1, %%mm0\n\t"
+                "movq      %%mm5, %%mm1\n\t"
+
+                "punpckhbw %%mm7, %%mm1\n\t"
+
+                "pmullw    %%mm6, %%mm1\n\t"
+                "psubusb   %%mm0, %%mm3\n\t"   // subtract darkening amount
+                "psrlw        $8, %%mm1\n\t"
+                "packuswb  %%mm1, %%mm4\n\t"
+
+                "movq      %%mm3, (%0)\n\t"
+                "psubusb   %%mm4, %%mm5\n\t"   // only change for this version is
+                "movq      %%mm5, 8(%0)\n\t"   // subtraction here as we are darkening image
+                : : "r"(data) );
+                data += 4;
+            }
+
+            end += rem;
+            while ( data != end ) {
+                __asm__ __volatile__(
+                "movd       (%0), %%mm0\n\t"
+                "punpcklbw %%mm7, %%mm0\n\t"
+                "movq      %%mm0, %%mm3\n\t"
+                "pmullw    %%mm6, %%mm0\n\t"
+                "psrlw        $8, %%mm0\n\t"
+                "psubusw   %%mm0, %%mm3\n\t"
+                "packuswb  %%mm3, %%mm3\n\t"
+                "movd      %%mm3, (%0)\n\t"
+                : : "r"(data) );
+                data++;
+            }
+        }
+        __asm__ __volatile__("emms");          // clear mmx state
+    }
+    else
+#endif // USE_MMX_INLINE_ASM
+    {
+        unsigned char *segTbl = new unsigned char[segColors];
+        int tmp;
+        if(brighten){ // keep overflow check out of loops
+            for(int i=0; i < segColors; ++i){
+                tmp = (int)(i*percent);
+                if(tmp > 255)
+                    tmp = 255;
+                segTbl[i] = tmp;
+            }
+        }
+        else{
+            for(int i=0; i < segColors; ++i){
+                tmp = (int)(i*percent);
+                if(tmp < 0)
+                    tmp = 0;
+                 segTbl[i] = tmp;
+            }
+        }
+
+        if(brighten){ // same here
+            for(int i=0; i < pixels; ++i){
+                int r = qRed(data[i]);
+                int g = qGreen(data[i]);
+                int b = qBlue(data[i]);
+                int a = qAlpha(data[i]);
+                r = r + segTbl[r] > 255 ? 255 : r + segTbl[r];
+                g = g + segTbl[g] > 255 ? 255 : g + segTbl[g];
+                b = b + segTbl[b] > 255 ? 255 : b + segTbl[b];
+                data[i] = qRgba(r, g, b,a);
+            }
+        }
+        else{
+            for(int i=0; i < pixels; ++i){
+                int r = qRed(data[i]);
+                int g = qGreen(data[i]);
+                int b = qBlue(data[i]);
+                int a = qAlpha(data[i]);
+                r = r - segTbl[r] < 0 ? 0 : r - segTbl[r];
+                g = g - segTbl[g] < 0 ? 0 : g - segTbl[g];
+                b = b - segTbl[b] < 0 ? 0 : b - segTbl[b];
+                data[i] = qRgba(r, g, b, a);
+            }
+        }
+        delete [] segTbl;
+    }
+
+    return image;
+}
+
+QImage& KImageEffect::channelIntensity(QImage &image, float percent,
+                                       RGBComponent channel)
+{
+    if (image.width() == 0 || image.height() == 0) {
+#ifndef NDEBUG
+      std::cerr << "WARNING: KImageEffect::channelIntensity : invalid image\n";
+#endif
+      return image;
+    }
+
+    int segColors = image.depth() > 8 ? 256 : image.numColors();
+    unsigned char *segTbl = new unsigned char[segColors];
+    int pixels = image.depth() > 8 ? image.width()*image.height() :
+        image.numColors();
+    unsigned int *data = image.depth() > 8 ? (unsigned int *)image.bits() :
+        (unsigned int *)image.colorTable();
+    bool brighten = (percent >= 0);
+    if(percent < 0)
+        percent = -percent;
+
+    if(brighten){ // keep overflow check out of loops
+        for(int i=0; i < segColors; ++i){
+            int tmp = (int)(i*percent);
+            if(tmp > 255)
+                tmp = 255;
+            segTbl[i] = tmp;
+        }
+    }
+    else{
+        for(int i=0; i < segColors; ++i){
+            int tmp = (int)(i*percent);
+            if(tmp < 0)
+                tmp = 0;
+            segTbl[i] = tmp;
+        }
+    }
+
+    if(brighten){ // same here
+        if(channel == Red){ // and here ;-)
+            for(int i=0; i < pixels; ++i){
+                int c = qRed(data[i]);
+                c = c + segTbl[c] > 255 ? 255 : c + segTbl[c];
+                data[i] = qRgba(c, qGreen(data[i]), qBlue(data[i]), qAlpha(data[i]));
+            }
+        }
+        else if(channel == Green){
+            for(int i=0; i < pixels; ++i){
+                int c = qGreen(data[i]);
+                c = c + segTbl[c] > 255 ? 255 : c + segTbl[c];
+                data[i] = qRgba(qRed(data[i]), c, qBlue(data[i]), qAlpha(data[i]));
+            }
+        }
+        else{
+            for(int i=0; i < pixels; ++i){
+                int c = qBlue(data[i]);
+                c = c + segTbl[c] > 255 ? 255 : c + segTbl[c];
+                data[i] = qRgba(qRed(data[i]), qGreen(data[i]), c, qAlpha(data[i]));
+            }
+        }
+
+    }
+    else{
+        if(channel == Red){
+            for(int i=0; i < pixels; ++i){
+                int c = qRed(data[i]);
+                c = c - segTbl[c] < 0 ? 0 : c - segTbl[c];
+                data[i] = qRgba(c, qGreen(data[i]), qBlue(data[i]), qAlpha(data[i]));
+            }
+        }
+        else if(channel == Green){
+            for(int i=0; i < pixels; ++i){
+                int c = qGreen(data[i]);
+                c = c - segTbl[c] < 0 ? 0 : c - segTbl[c];
+                data[i] = qRgba(qRed(data[i]), c, qBlue(data[i]), qAlpha(data[i]));
+            }
+        }
+        else{
+            for(int i=0; i < pixels; ++i){
+                int c = qBlue(data[i]);
+                c = c - segTbl[c] < 0 ? 0 : c - segTbl[c];
+                data[i] = qRgba(qRed(data[i]), qGreen(data[i]), c, qAlpha(data[i]));
+            }
+        }
+    }
+    delete [] segTbl;
+
+    return image;
+}
+
+// Modulate an image with an RBG channel of another image
+//
+QImage& KImageEffect::modulate(QImage &image, QImage &modImage, bool reverse,
+	ModulationType type, int factor, RGBComponent channel)
+{
+    if (image.width() == 0 || image.height() == 0 ||
+        modImage.width() == 0 || modImage.height() == 0) {
+#ifndef NDEBUG
+      std::cerr << "WARNING: KImageEffect::modulate : invalid image\n";
+#endif
+      return image;
+    }
+
+    int r, g, b, h, s, v, a;
+    QColor clr;
+    int mod=0;
+    unsigned int x1, x2, y1, y2;
+    register int x, y;
+
+    // for image, we handle only depth 32
+    if (image.depth()<32) image = image.convertDepth(32);
+
+    // for modImage, we handle depth 8 and 32
+    if (modImage.depth()<8) modImage = modImage.convertDepth(8);
+
+    unsigned int *colorTable2 = (modImage.depth()==8) ?
+				 modImage.colorTable():0;
+    unsigned int *data1, *data2;
+    unsigned char *data2b;
+    unsigned int color1, color2;
+
+    x1 = image.width();    y1 = image.height();
+    x2 = modImage.width(); y2 = modImage.height();
+
+    for (y = 0; y < (int)y1; y++) {
+        data1 =  (unsigned int *) image.scanLine(y);
+	data2 =  (unsigned int *) modImage.scanLine( y%y2 );
+	data2b = (unsigned char *) modImage.scanLine( y%y2 );
+
+	x=0;
+	while(x < (int)x1) {
+	  color2 = (colorTable2) ? colorTable2[*data2b] : *data2;
+	  if (reverse) {
+	      color1 = color2;
+	      color2 = *data1;
+	  }
+	  else
+	      color1 = *data1;
+
+	  if (type == Intensity || type == Contrast) {
+              r = qRed(color1);
+	      g = qGreen(color1);
+	      b = qBlue(color1);
+	      if (channel != All) {
+      	        mod = (channel == Red) ? qRed(color2) :
+		    (channel == Green) ? qGreen(color2) :
+	    	    (channel == Blue) ? qBlue(color2) :
+		    (channel == Gray) ? qGray(color2) : 0;
+	        mod = mod*factor/50;
+	      }
+
+	      if (type == Intensity) {
+	        if (channel == All) {
+	          r += r * factor/50 * qRed(color2)/256;
+	          g += g * factor/50 * qGreen(color2)/256;
+	          b += b * factor/50 * qBlue(color2)/256;
+	        }
+	        else {
+	          r += r * mod/256;
+	          g += g * mod/256;
+	          b += b * mod/256;
+	        }
+	      }
+	      else { // Contrast
+	        if (channel == All) {
+		  r += (r-128) * factor/50 * qRed(color2)/128;
+	          g += (g-128) * factor/50 * qGreen(color2)/128;
+	          b += (b-128) * factor/50 * qBlue(color2)/128;
+	        }
+	        else {
+	          r += (r-128) * mod/128;
+	          g += (g-128) * mod/128;
+	          b += (b-128) * mod/128;
+	        }
+	      }
+
+	      if (r<0) r=0; if (r>255) r=255;
+	      if (g<0) g=0; if (g>255) g=255;
+	      if (b<0) b=0; if (b>255) b=255;
+	      a = qAlpha(*data1);
+	      *data1 = qRgba(r, g, b, a);
+	  }
+	  else if (type == Saturation || type == HueShift) {
+	      clr.setRgb(color1);
+	      clr.hsv(&h, &s, &v);
+      	      mod = (channel == Red) ? qRed(color2) :
+		    (channel == Green) ? qGreen(color2) :
+	    	    (channel == Blue) ? qBlue(color2) :
+		    (channel == Gray) ? qGray(color2) : 0;
+	      mod = mod*factor/50;
+
+	      if (type == Saturation) {
+		  s -= s * mod/256;
+		  if (s<0) s=0; if (s>255) s=255;
+	      }
+	      else { // HueShift
+	        h += mod;
+		while(h<0) h+=360;
+		h %= 360;
+	      }
+
+	      clr.setHsv(h, s, v);
+	      a = qAlpha(*data1);
+	      *data1 = clr.rgb() | ((uint)(a & 0xff) << 24);
+	  }
+	  data1++; data2++; data2b++; x++;
+	  if ( (x%x2) ==0) { data2 -= x2; data2b -= x2; }
+        }
+    }
+    return image;
+}
+
+
+
+//======================================================================
+//
+// Blend effects
+//
+//======================================================================
+
+
+// Nice and fast direct pixel manipulation
+QImage& KImageEffect::blend(const QColor& clr, QImage& dst, float opacity)
+{
+    if (dst.width() <= 0 || dst.height() <= 0)
+        return dst;
+
+    if (opacity < 0.0 || opacity > 1.0) {
+#ifndef NDEBUG
+        std::cerr << "WARNING: KImageEffect::blend : invalid opacity. Range [0, 1]\n";
+#endif
+        return dst;
+    }
+
+    if (dst.depth() != 32)
+        dst = dst.convertDepth(32);
+
+    int pixels = dst.width() * dst.height();
+
+#ifdef USE_SSE2_INLINE_ASM
+    if ( KCPUInfo::haveExtension( KCPUInfo::IntelSSE2 ) && pixels > 16 ) {
+        Q_UINT16 alpha = Q_UINT16( ( 1.0 - opacity ) * 256.0 );
+
+        KIE8Pack packedalpha = { { alpha, alpha, alpha, 256,
+                                   alpha, alpha, alpha, 256 } };
+
+        Q_UINT16 red   = Q_UINT16( clr.red()   * 256 * opacity );
+        Q_UINT16 green = Q_UINT16( clr.green() * 256 * opacity );
+        Q_UINT16 blue  = Q_UINT16( clr.blue()  * 256 * opacity );
+
+        KIE8Pack packedcolor = { { blue, green, red, 0,
+                                   blue, green, red, 0 } };
+
+        // Prepare the XMM5, XMM6 and XMM7 registers for unpacking and blending
+        __asm__ __volatile__(
+        "pxor        %%xmm7,  %%xmm7\n\t" // Zero out XMM7 for unpacking
+        "movdqu        (%0),  %%xmm6\n\t" // Set up (1 - alpha) * 256 in XMM6
+        "movdqu        (%1),  %%xmm5\n\t" // Set up color * alpha * 256 in XMM5
+        : : "r"(&packedalpha), "r"(&packedcolor),
+            "m"(packedcolor),  "m"(packedalpha) );
+
+        Q_UINT32 *data = reinterpret_cast<Q_UINT32*>( dst.bits() );
+
+        // Check how many pixels we need to process to achieve 16 byte alignment
+        int offset = (16 - (Q_UINT32( data ) & 0x0f)) / 4;
+
+        // The main loop processes 8 pixels / iteration
+        int remainder = (pixels - offset) % 8;
+        pixels -= remainder;
+
+        // Alignment loop
+        for ( int i = 0; i < offset; i++ ) {
+            __asm__ __volatile__(
+            "movd         (%0,%1,4),      %%xmm0\n\t"  // Load one pixel to XMM1
+            "punpcklbw       %%xmm7,      %%xmm0\n\t"  // Unpack the pixel
+            "pmullw          %%xmm6,      %%xmm0\n\t"  // Multiply the pixel with (1 - alpha) * 256
+            "paddw           %%xmm5,      %%xmm0\n\t"  // Add color * alpha * 256 to the result
+            "psrlw               $8,      %%xmm0\n\t"  // Divide by 256
+            "packuswb        %%xmm1,      %%xmm0\n\t"  // Pack the pixel to a dword
+            "movd            %%xmm0,   (%0,%1,4)\n\t"  // Write the pixel to the image
+            : : "r"(data), "r"(i) );
+        }
+
+        // Main loop
+        for ( int i = offset; i < pixels; i += 8 ) {
+            __asm__ __volatile(
+            // Load 8 pixels to XMM registers 1 - 4
+            "movq         (%0,%1,4),      %%xmm0\n\t"  // Load pixels 1 and 2 to XMM1
+            "movq        8(%0,%1,4),      %%xmm1\n\t"  // Load pixels 3 and 4 to XMM2
+            "movq       16(%0,%1,4),      %%xmm2\n\t"  // Load pixels 5 and 6 to XMM3
+            "movq       24(%0,%1,4),      %%xmm3\n\t"  // Load pixels 7 and 8 to XMM4
+
+            // Prefetch the pixels for next iteration
+            "prefetchnta 32(%0,%1,4)            \n\t"
+
+            // Blend pixels 1 and 2
+            "punpcklbw       %%xmm7,      %%xmm0\n\t"  // Unpack the pixels
+            "pmullw          %%xmm6,      %%xmm0\n\t"  // Multiply the pixels with (1 - alpha) * 256
+            "paddw           %%xmm5,      %%xmm0\n\t"  // Add color * alpha * 256 to the result
+            "psrlw               $8,      %%xmm0\n\t"  // Divide by 256
+
+            // Blend pixels 3 and 4
+            "punpcklbw       %%xmm7,      %%xmm1\n\t"  // Unpack the pixels
+            "pmullw          %%xmm6,      %%xmm1\n\t"  // Multiply the pixels with (1 - alpha) * 256
+            "paddw           %%xmm5,      %%xmm1\n\t"  // Add color * alpha * 256 to the result
+            "psrlw               $8,      %%xmm1\n\t"  // Divide by 256
+
+            // Blend pixels 5 and 6
+            "punpcklbw       %%xmm7,      %%xmm2\n\t"  // Unpack the pixels
+            "pmullw          %%xmm6,      %%xmm2\n\t"  // Multiply the pixels with (1 - alpha) * 256
+            "paddw           %%xmm5,      %%xmm2\n\t"  // Add color * alpha * 256 to the result
+            "psrlw               $8,      %%xmm2\n\t"  // Divide by 256
+
+            // Blend pixels 7 and 8
+            "punpcklbw       %%xmm7,      %%xmm3\n\t"  // Unpack the pixels
+            "pmullw          %%xmm6,      %%xmm3\n\t"  // Multiply the pixels with (1 - alpha) * 256
+            "paddw           %%xmm5,      %%xmm3\n\t"  // Add color * alpha * 256 to the result
+            "psrlw               $8,      %%xmm3\n\t"  // Divide by 256
+
+            // Pack the pixels into 2 double quadwords
+            "packuswb        %%xmm1,      %%xmm0\n\t"  // Pack pixels 1 - 4 to a double qword
+            "packuswb        %%xmm3,      %%xmm2\n\t"  // Pack pixles 5 - 8 to a double qword
+
+            // Write the pixels back to the image
+            "movdqa          %%xmm0,   (%0,%1,4)\n\t"  // Store pixels 1 - 4
+            "movdqa          %%xmm2, 16(%0,%1,4)\n\t"  // Store pixels 5 - 8
+            : : "r"(data), "r"(i) );
+        }
+
+        // Cleanup loop
+        for ( int i = pixels; i < pixels + remainder; i++ ) {
+            __asm__ __volatile__(
+            "movd         (%0,%1,4),      %%xmm0\n\t"  // Load one pixel to XMM1
+            "punpcklbw       %%xmm7,      %%xmm0\n\t"  // Unpack the pixel
+            "pmullw          %%xmm6,      %%xmm0\n\t"  // Multiply the pixel with (1 - alpha) * 256
+            "paddw           %%xmm5,      %%xmm0\n\t"  // Add color * alpha * 256 to the result
+            "psrlw               $8,      %%xmm0\n\t"  // Divide by 256
+            "packuswb        %%xmm1,      %%xmm0\n\t"  // Pack the pixel to a dword
+            "movd            %%xmm0,   (%0,%1,4)\n\t"  // Write the pixel to the image
+            : : "r"(data), "r"(i) );
+        }
+    } else
+#endif
+
+#ifdef USE_MMX_INLINE_ASM
+    if ( KCPUInfo::haveExtension( KCPUInfo::IntelMMX ) && pixels > 1 ) {
+        Q_UINT16 alpha = Q_UINT16( ( 1.0 - opacity ) * 256.0 );
+        KIE4Pack packedalpha = { { alpha, alpha, alpha, 256 } };
+
+        Q_UINT16 red   = Q_UINT16( clr.red()   * 256 * opacity );
+        Q_UINT16 green = Q_UINT16( clr.green() * 256 * opacity );
+        Q_UINT16 blue  = Q_UINT16( clr.blue()  * 256 * opacity );
+
+        KIE4Pack packedcolor = { { blue, green, red, 0 } };
+
+        __asm__ __volatile__(
+        "pxor        %%mm7,    %%mm7\n\t"       // Zero out MM7 for unpacking
+        "movq         (%0),    %%mm6\n\t"       // Set up (1 - alpha) * 256 in MM6
+        "movq         (%1),    %%mm5\n\t"       // Set up color * alpha * 256 in MM5
+        : : "r"(&packedalpha), "r"(&packedcolor), "m"(packedcolor), "m"(packedalpha) );
+
+        Q_UINT32 *data = reinterpret_cast<Q_UINT32*>( dst.bits() );
+
+        // The main loop processes 4 pixels / iteration
+        int remainder = pixels % 4;
+        pixels -= remainder;
+
+        // Main loop
+        for ( int i = 0; i < pixels; i += 4 ) {
+            __asm__ __volatile__(
+            // Load 4 pixels to MM registers 1 - 4
+            "movd         (%0,%1,4),      %%mm0\n\t"  // Load the 1st pixel to MM0
+            "movd        4(%0,%1,4),      %%mm1\n\t"  // Load the 2nd pixel to MM1
+            "movd        8(%0,%1,4),      %%mm2\n\t"  // Load the 3rd pixel to MM2
+            "movd       12(%0,%1,4),      %%mm3\n\t"  // Load the 4th pixel to MM3
+
+            // Blend the first pixel
+            "punpcklbw        %%mm7,      %%mm0\n\t"  // Unpack the pixel
+            "pmullw           %%mm6,      %%mm0\n\t"  // Multiply the pixel with (1 - alpha) * 256
+            "paddw            %%mm5,      %%mm0\n\t"  // Add color * alpha * 256 to the result
+            "psrlw               $8,      %%mm0\n\t"  // Divide by 256
+
+            // Blend the second pixel
+            "punpcklbw        %%mm7,      %%mm1\n\t"  // Unpack the pixel
+            "pmullw           %%mm6,      %%mm1\n\t"  // Multiply the pixel with (1 - alpha) * 256
+            "paddw            %%mm5,      %%mm1\n\t"  // Add color * alpha * 256 to the result
+            "psrlw               $8,      %%mm1\n\t"  // Divide by 256
+
+            // Blend the third pixel
+            "punpcklbw        %%mm7,      %%mm2\n\t"  // Unpack the pixel
+            "pmullw           %%mm6,      %%mm2\n\t"  // Multiply the pixel with (1 - alpha) * 256
+            "paddw            %%mm5,      %%mm2\n\t"  // Add color * alpha * 256 to the result
+            "psrlw               $8,      %%mm2\n\t"  // Divide by 256
+
+            // Blend the fourth pixel
+            "punpcklbw        %%mm7,      %%mm3\n\t"  // Unpack the pixel
+            "pmullw           %%mm6,      %%mm3\n\t"  // Multiply the pixel with (1 - alpha) * 256
+            "paddw            %%mm5,      %%mm3\n\t"  // Add color * alpha * 256 to the result
+            "psrlw               $8,      %%mm3\n\t"  // Divide by 256
+
+            // Pack the pixels into 2 quadwords
+            "packuswb         %%mm1,      %%mm0\n\t"  // Pack pixels 1 and 2 to a qword
+            "packuswb         %%mm3,      %%mm2\n\t"  // Pack pixels 3 and 4 to a qword
+
+            // Write the pixels back to the image
+            "movq             %%mm0,  (%0,%1,4)\n\t"  // Store pixels 1 and 2
+            "movq             %%mm2, 8(%0,%1,4)\n\t"  // Store pixels 3 and 4
+            : : "r"(data), "r"(i) );
+        }
+
+        // Cleanup loop
+        for ( int i = pixels; i < pixels + remainder; i++ ) {
+            __asm__ __volatile__(
+            "movd         (%0,%1,4),      %%mm0\n\t"  // Load one pixel to MM1
+            "punpcklbw        %%mm7,      %%mm0\n\t"  // Unpack the pixel
+            "pmullw           %%mm6,      %%mm0\n\t"  // Multiply the pixel with 1 - alpha * 256
+            "paddw            %%mm5,      %%mm0\n\t"  // Add color * alpha * 256 to the result
+            "psrlw               $8,      %%mm0\n\t"  // Divide by 256
+            "packuswb         %%mm0,      %%mm0\n\t"  // Pack the pixel to a dword
+            "movd             %%mm0,  (%0,%1,4)\n\t"  // Write the pixel to the image
+            : : "r"(data), "r"(i) );
+        }
+
+        // Empty the MMX state
+        __asm__ __volatile__("emms");
+    } else
+#endif // USE_MMX_INLINE_ASM
+
+    {
+        int rcol, gcol, bcol;
+        clr.rgb(&rcol, &gcol, &bcol);
+
+#ifdef WORDS_BIGENDIAN   // ARGB (skip alpha)
+        register unsigned char *data = (unsigned char *)dst.bits() + 1;
+#else                    // BGRA
+        register unsigned char *data = (unsigned char *)dst.bits();
+#endif
+
+        for (register int i=0; i<pixels; i++)
+        {
+#ifdef WORDS_BIGENDIAN
+            *data += (unsigned char)((rcol - *data) * opacity);
+            data++;
+            *data += (unsigned char)((gcol - *data) * opacity);
+            data++;
+            *data += (unsigned char)((bcol - *data) * opacity);
+            data++;
+#else
+            *data += (unsigned char)((bcol - *data) * opacity);
+            data++;
+            *data += (unsigned char)((gcol - *data) * opacity);
+            data++;
+            *data += (unsigned char)((rcol - *data) * opacity);
+            data++;
+#endif
+            data++; // skip alpha
+        }
+    }
+
+    return dst;
+}
+
+// Nice and fast direct pixel manipulation
+QImage& KImageEffect::blend(QImage& src, QImage& dst, float opacity)
+{
+    if (src.width() <= 0 || src.height() <= 0)
+        return dst;
+    if (dst.width() <= 0 || dst.height() <= 0)
+        return dst;
+
+    if (src.width() != dst.width() || src.height() != dst.height()) {
+#ifndef NDEBUG
+        std::cerr << "WARNING: KImageEffect::blend : src and destination images are not the same size\n";
+#endif
+        return dst;
+    }
+
+    if (opacity < 0.0 || opacity > 1.0) {
+#ifndef NDEBUG
+        std::cerr << "WARNING: KImageEffect::blend : invalid opacity. Range [0, 1]\n";
+#endif
+        return dst;
+    }
+
+    if (src.depth() != 32) src = src.convertDepth(32);
+    if (dst.depth() != 32) dst = dst.convertDepth(32);
+
+    int pixels = src.width() * src.height();
+
+#ifdef USE_SSE2_INLINE_ASM
+    if ( KCPUInfo::haveExtension( KCPUInfo::IntelSSE2 ) && pixels > 16 ) {
+        Q_UINT16 alpha = Q_UINT16( opacity * 256.0 );
+        KIE8Pack packedalpha = { { alpha, alpha, alpha, 0,
+                                   alpha, alpha, alpha, 0 } };
+
+        // Prepare the XMM6 and XMM7 registers for unpacking and blending
+        __asm__ __volatile__(
+        "pxor      %%xmm7, %%xmm7\n\t" // Zero out XMM7 for unpacking
+        "movdqu      (%0), %%xmm6\n\t" // Set up alpha * 256 in XMM6
+        : : "r"(&packedalpha), "m"(packedalpha) );
+
+        Q_UINT32 *data1 = reinterpret_cast<Q_UINT32*>( src.bits() );
+        Q_UINT32 *data2 = reinterpret_cast<Q_UINT32*>( dst.bits() );
+
+        // Check how many pixels we need to process to achieve 16 byte alignment
+        int offset = (16 - (Q_UINT32( data2 ) & 0x0f)) / 4;
+
+        // The main loop processes 4 pixels / iteration
+        int remainder = (pixels - offset) % 4;
+        pixels -= remainder;
+
+        // Alignment loop
+        for ( int i = 0; i < offset; i++ ) {
+            __asm__ __volatile__(
+            "movd       (%1,%2,4),    %%xmm1\n\t"  // Load one dst pixel to XMM1
+            "punpcklbw     %%xmm7,    %%xmm1\n\t"  // Unpack the pixel
+            "movd       (%0,%2,4),    %%xmm0\n\t"  // Load one src pixel to XMM0
+            "punpcklbw     %%xmm7,    %%xmm0\n\t"  // Unpack the pixel
+            "psubw         %%xmm1,    %%xmm0\n\t"  // Subtract dst from src
+            "pmullw        %%xmm6,    %%xmm0\n\t"  // Multiply the result with alpha * 256
+            "psllw             $8,    %%xmm1\n\t"  // Multiply dst with 256
+            "paddw         %%xmm1,    %%xmm0\n\t"  // Add dst to result
+            "psrlw             $8,    %%xmm0\n\t"  // Divide by 256
+            "packuswb      %%xmm1,    %%xmm0\n\t"  // Pack the pixel to a dword
+            "movd          %%xmm0, (%1,%2,4)\n\t"  // Write the pixel to the image
+            : : "r"(data1), "r"(data2), "r"(i) );
+        }
+
+        // Main loop
+        for ( int i = offset; i < pixels; i += 4 ) {
+            __asm__ __volatile__(
+            // Load 4 src pixels to XMM0 and XMM2 and 4 dst pixels to XMM1 and XMM3
+            "movq       (%0,%2,4),    %%xmm0\n\t"  // Load two src pixels to XMM0
+            "movq       (%1,%2,4),    %%xmm1\n\t"  // Load two dst pixels to XMM1
+            "movq      8(%0,%2,4),    %%xmm2\n\t"  // Load two src pixels to XMM2
+            "movq      8(%1,%2,4),    %%xmm3\n\t"  // Load two dst pixels to XMM3
+
+            // Prefetch the pixels for the iteration after the next one
+            "prefetchnta 32(%0,%2,4)        \n\t"
+            "prefetchnta 32(%1,%2,4)        \n\t"
+
+            // Blend the first two pixels
+            "punpcklbw     %%xmm7,    %%xmm1\n\t"  // Unpack the dst pixels
+            "punpcklbw     %%xmm7,    %%xmm0\n\t"  // Unpack the src pixels
+            "psubw         %%xmm1,    %%xmm0\n\t"  // Subtract dst from src
+            "pmullw        %%xmm6,    %%xmm0\n\t"  // Multiply the result with alpha * 256
+            "psllw             $8,    %%xmm1\n\t"  // Multiply dst with 256
+            "paddw         %%xmm1,    %%xmm0\n\t"  // Add dst to the result
+            "psrlw             $8,    %%xmm0\n\t"  // Divide by 256
+
+            // Blend the next two pixels
+            "punpcklbw     %%xmm7,    %%xmm3\n\t"  // Unpack the dst pixels
+            "punpcklbw     %%xmm7,    %%xmm2\n\t"  // Unpack the src pixels
+            "psubw         %%xmm3,    %%xmm2\n\t"  // Subtract dst from src
+            "pmullw        %%xmm6,    %%xmm2\n\t"  // Multiply the result with alpha * 256
+            "psllw             $8,    %%xmm3\n\t"  // Multiply dst with 256
+            "paddw         %%xmm3,    %%xmm2\n\t"  // Add dst to the result
+            "psrlw             $8,    %%xmm2\n\t"  // Divide by 256
+
+            // Write the pixels back to the image
+            "packuswb      %%xmm2,    %%xmm0\n\t"  // Pack the pixels to a double qword
+            "movdqa        %%xmm0, (%1,%2,4)\n\t"  // Store the pixels
+            : : "r"(data1), "r"(data2), "r"(i) );
+        }
+
+        // Cleanup loop
+        for ( int i = pixels; i < pixels + remainder; i++ ) {
+            __asm__ __volatile__(
+            "movd       (%1,%2,4),    %%xmm1\n\t"  // Load one dst pixel to XMM1
+            "punpcklbw     %%xmm7,    %%xmm1\n\t"  // Unpack the pixel
+            "movd       (%0,%2,4),    %%xmm0\n\t"  // Load one src pixel to XMM0
+            "punpcklbw     %%xmm7,    %%xmm0\n\t"  // Unpack the pixel
+            "psubw         %%xmm1,    %%xmm0\n\t"  // Subtract dst from src
+            "pmullw        %%xmm6,    %%xmm0\n\t"  // Multiply the result with alpha * 256
+            "psllw             $8,    %%xmm1\n\t"  // Multiply dst with 256
+            "paddw         %%xmm1,    %%xmm0\n\t"  // Add dst to result
+            "psrlw             $8,    %%xmm0\n\t"  // Divide by 256
+            "packuswb      %%xmm1,    %%xmm0\n\t"  // Pack the pixel to a dword
+            "movd          %%xmm0, (%1,%2,4)\n\t"  // Write the pixel to the image
+            : : "r"(data1), "r"(data2), "r"(i) );
+        }
+    } else
+#endif // USE_SSE2_INLINE_ASM
+
+#ifdef USE_MMX_INLINE_ASM
+    if ( KCPUInfo::haveExtension( KCPUInfo::IntelMMX ) && pixels > 1 ) {
+        Q_UINT16 alpha = Q_UINT16( opacity * 256.0 );
+        KIE4Pack packedalpha = { { alpha, alpha, alpha, 0 } };
+
+        // Prepare the MM6 and MM7 registers for blending and unpacking
+        __asm__ __volatile__(
+        "pxor       %%mm7,   %%mm7\n\t"      // Zero out MM7 for unpacking
+        "movq        (%0),   %%mm6\n\t"      // Set up alpha * 256 in MM6
+        : : "r"(&packedalpha), "m"(packedalpha) );
+
+        Q_UINT32 *data1 = reinterpret_cast<Q_UINT32*>( src.bits() );
+        Q_UINT32 *data2 = reinterpret_cast<Q_UINT32*>( dst.bits() );
+
+        // The main loop processes 2 pixels / iteration
+        int remainder = pixels % 2;
+        pixels -= remainder;
+
+        // Main loop
+        for ( int i = 0; i < pixels; i += 2 ) {
+            __asm__ __volatile__(
+            // Load 2 src pixels to MM0 and MM2 and 2 dst pixels to MM1 and MM3
+            "movd        (%0,%2,4),     %%mm0\n\t"  // Load the 1st src pixel to MM0
+            "movd        (%1,%2,4),     %%mm1\n\t"  // Load the 1st dst pixel to MM1
+            "movd       4(%0,%2,4),     %%mm2\n\t"  // Load the 2nd src pixel to MM2
+            "movd       4(%1,%2,4),     %%mm3\n\t"  // Load the 2nd dst pixel to MM3
+
+            // Blend the first pixel
+            "punpcklbw       %%mm7,     %%mm0\n\t"  // Unpack the src pixel
+            "punpcklbw       %%mm7,     %%mm1\n\t"  // Unpack the dst pixel
+            "psubw           %%mm1,     %%mm0\n\t"  // Subtract dst from src
+            "pmullw          %%mm6,     %%mm0\n\t"  // Multiply the result with alpha * 256
+            "psllw              $8,     %%mm1\n\t"  // Multiply dst with 256
+            "paddw           %%mm1,     %%mm0\n\t"  // Add dst to the result
+            "psrlw              $8,     %%mm0\n\t"  // Divide by 256
+
+            // Blend the second pixel
+            "punpcklbw       %%mm7,     %%mm2\n\t"  // Unpack the src pixel
+            "punpcklbw       %%mm7,     %%mm3\n\t"  // Unpack the dst pixel
+            "psubw           %%mm3,     %%mm2\n\t"  // Subtract dst from src
+            "pmullw          %%mm6,     %%mm2\n\t"  // Multiply the result with alpha * 256
+            "psllw              $8,     %%mm3\n\t"  // Multiply dst with 256
+            "paddw           %%mm3,     %%mm2\n\t"  // Add dst to the result
+            "psrlw              $8,     %%mm2\n\t"  // Divide by 256
+
+            // Write the pixels back to the image
+            "packuswb        %%mm2,     %%mm0\n\t"  // Pack the pixels to a qword
+            "movq            %%mm0, (%1,%2,4)\n\t"  // Store the pixels
+            : : "r"(data1), "r"(data2), "r"(i) );
+        }
+
+        // Blend the remaining pixel (if there is one)
+        if ( remainder ) {
+             __asm__ __volatile__(
+            "movd             (%0),     %%mm0\n\t"  // Load one src pixel to MM0
+            "punpcklbw       %%mm7,     %%mm0\n\t"  // Unpack the src pixel
+            "movd             (%1),     %%mm1\n\t"  // Load one dst pixel to MM1
+            "punpcklbw       %%mm7,     %%mm1\n\t"  // Unpack the dst pixel
+            "psubw           %%mm1,     %%mm0\n\t"  // Subtract dst from src
+            "pmullw          %%mm6,     %%mm0\n\t"  // Multiply the result with alpha * 256
+            "psllw              $8,     %%mm1\n\t"  // Multiply dst with 256
+            "paddw           %%mm1,     %%mm0\n\t"  // Add dst to result
+            "psrlw              $8,     %%mm0\n\t"  // Divide by 256
+            "packuswb        %%mm0,     %%mm0\n\t"  // Pack the pixel to a dword
+            "movd            %%mm0,      (%1)\n\t"  // Write the pixel to the image
+            : : "r"(data1 + pixels), "r"(data2 + pixels) );
+        }
+
+        // Empty the MMX state
+        __asm__ __volatile__("emms");
+    } else
+#endif // USE_MMX_INLINE_ASM
+
+    {
+#ifdef WORDS_BIGENDIAN   // ARGB (skip alpha)
+        register unsigned char *data1 = (unsigned char *)dst.bits() + 1;
+        register unsigned char *data2 = (unsigned char *)src.bits() + 1;
+#else                    // BGRA
+        register unsigned char *data1 = (unsigned char *)dst.bits();
+        register unsigned char *data2 = (unsigned char *)src.bits();
+#endif
+
+        for (register int i=0; i<pixels; i++)
+        {
+#ifdef WORDS_BIGENDIAN
+            *data1 += (unsigned char)((*(data2++) - *data1) * opacity);
+            data1++;
+            *data1 += (unsigned char)((*(data2++) - *data1) * opacity);
+            data1++;
+            *data1 += (unsigned char)((*(data2++) - *data1) * opacity);
+            data1++;
+#else
+            *data1 += (unsigned char)((*(data2++) - *data1) * opacity);
+            data1++;
+            *data1 += (unsigned char)((*(data2++) - *data1) * opacity);
+            data1++;
+            *data1 += (unsigned char)((*(data2++) - *data1) * opacity);
+            data1++;
+#endif
+            data1++; // skip alpha
+            data2++;
+        }
+    }
+
+    return dst;
+}
+
+
+QImage& KImageEffect::blend(QImage &image, float initial_intensity,
+                            const QColor &bgnd, GradientType eff,
+                            bool anti_dir)
+{
+    if (image.width() == 0 || image.height() == 0 || image.depth()!=32 ) {
+#ifndef NDEBUG
+      std::cerr << "WARNING: KImageEffect::blend : invalid image\n";
+#endif
+      return image;
+    }
+
+    int r_bgnd = bgnd.red(), g_bgnd = bgnd.green(), b_bgnd = bgnd.blue();
+    int r, g, b;
+    int ind;
+
+    unsigned int xi, xf, yi, yf;
+    unsigned int a;
+
+    // check the boundaries of the initial intesity param
+    float unaffected = 1;
+    if (initial_intensity >  1) initial_intensity =  1;
+    if (initial_intensity < -1) initial_intensity = -1;
+    if (initial_intensity < 0) {
+        unaffected = 1. + initial_intensity;
+        initial_intensity = 0;
+    }
+
+
+    float intensity = initial_intensity;
+    float var = 1. - initial_intensity;
+
+    if (anti_dir) {
+        initial_intensity = intensity = 1.;
+        var = -var;
+    }
+
+    register int x, y;
+
+    unsigned int *data =  (unsigned int *)image.bits();
+
+    int image_width = image.width(); //Those can't change
+    int image_height = image.height();
+
+
+    if( eff == VerticalGradient || eff == HorizontalGradient ) {
+
+        // set the image domain to apply the effect to
+        xi = 0, xf = image_width;
+        yi = 0, yf = image_height;
+        if (eff == VerticalGradient) {
+            if (anti_dir) yf = (int)(image_height * unaffected);
+            else yi = (int)(image_height * (1 - unaffected));
+        }
+        else {
+            if (anti_dir) xf = (int)(image_width * unaffected);
+            else xi = (int)(image_height * (1 - unaffected));
+        }
+
+        var /= (eff == VerticalGradient?yf-yi:xf-xi);
+
+        int ind_base;
+        for (y = yi; y < (int)yf; y++) {
+            intensity = eff == VerticalGradient? intensity + var :
+                initial_intensity;
+            ind_base = image_width  * y ;
+            for (x = xi; x < (int)xf ; x++) {
+                if (eff == HorizontalGradient) intensity += var;
+                ind = x + ind_base;
+                r = qRed  (data[ind]) + (int)(intensity *
+                                              (r_bgnd - qRed  (data[ind])));
+                g = qGreen(data[ind]) + (int)(intensity *
+                                              (g_bgnd - qGreen(data[ind])));
+                b = qBlue (data[ind]) + (int)(intensity *
+                                              (b_bgnd - qBlue (data[ind])));
+                if (r > 255) r = 255; if (r < 0 ) r = 0;
+                if (g > 255) g = 255; if (g < 0 ) g = 0;
+                if (b > 255) b = 255; if (b < 0 ) b = 0;
+                a = qAlpha(data[ind]);
+                data[ind] = qRgba(r, g, b, a);
+            }
+        }
+    }
+    else if (eff == DiagonalGradient  || eff == CrossDiagonalGradient) {
+        float xvar = var / 2 / image_width;  // / unaffected;
+        float yvar = var / 2 / image_height; // / unaffected;
+        float tmp;
+
+        for (x = 0; x < image_width ; x++) {
+            tmp =  xvar * (eff == DiagonalGradient? x : image.width()-x-1);
+            ind = x;
+            for (y = 0; y < image_height ; y++) {
+                intensity = initial_intensity + tmp + yvar * y;
+
+                r = qRed  (data[ind]) + (int)(intensity *
+                                              (r_bgnd - qRed  (data[ind])));
+                g = qGreen(data[ind]) + (int)(intensity *
+                                              (g_bgnd - qGreen(data[ind])));
+                b = qBlue (data[ind]) + (int)(intensity *
+                                              (b_bgnd - qBlue (data[ind])));
+                if (r > 255) r = 255; if (r < 0 ) r = 0;
+                if (g > 255) g = 255; if (g < 0 ) g = 0;
+                if (b > 255) b = 255; if (b < 0 ) b = 0;
+                a = qAlpha(data[ind]);
+                data[ind] = qRgba(r, g, b, a);
+
+                ind += image_width;
+            }
+        }
+    }
+
+    else if (eff == RectangleGradient || eff == EllipticGradient) {
+        float xvar;
+        float yvar;
+
+        for (x = 0; x < image_width / 2 + image_width % 2; x++) {
+            xvar = var / image_width  * (image_width - x*2/unaffected-1);
+            for (y = 0; y < image_height / 2 + image_height % 2; y++) {
+                yvar = var / image_height   * (image_height - y*2/unaffected -1);
+
+                if (eff == RectangleGradient)
+                    intensity = initial_intensity + QMAX(xvar, yvar);
+                else
+                    intensity = initial_intensity + sqrt(xvar * xvar + yvar * yvar);
+                if (intensity > 1) intensity = 1;
+                if (intensity < 0) intensity = 0;
+
+                //NW
+                ind = x + image_width  * y ;
+                r = qRed  (data[ind]) + (int)(intensity *
+                                              (r_bgnd - qRed  (data[ind])));
+                g = qGreen(data[ind]) + (int)(intensity *
+                                              (g_bgnd - qGreen(data[ind])));
+                b = qBlue (data[ind]) + (int)(intensity *
+                                              (b_bgnd - qBlue (data[ind])));
+                if (r > 255) r = 255; if (r < 0 ) r = 0;
+                if (g > 255) g = 255; if (g < 0 ) g = 0;
+                if (b > 255) b = 255; if (b < 0 ) b = 0;
+                a = qAlpha(data[ind]);
+                data[ind] = qRgba(r, g, b, a);
+
+                //NE
+                ind = image_width - x - 1 + image_width  * y ;
+                r = qRed  (data[ind]) + (int)(intensity *
+                                              (r_bgnd - qRed  (data[ind])));
+                g = qGreen(data[ind]) + (int)(intensity *
+                                              (g_bgnd - qGreen(data[ind])));
+                b = qBlue (data[ind]) + (int)(intensity *
+                                              (b_bgnd - qBlue (data[ind])));
+                if (r > 255) r = 255; if (r < 0 ) r = 0;
+                if (g > 255) g = 255; if (g < 0 ) g = 0;
+                if (b > 255) b = 255; if (b < 0 ) b = 0;
+                a = qAlpha(data[ind]);
+                data[ind] = qRgba(r, g, b, a);
+            }
+        }
+
+        //CT  loop is doubled because of stupid central row/column issue.
+        //    other solution?
+        for (x = 0; x < image_width / 2; x++) {
+            xvar = var / image_width  * (image_width - x*2/unaffected-1);
+            for (y = 0; y < image_height / 2; y++) {
+                yvar = var / image_height   * (image_height - y*2/unaffected -1);
+
+                if (eff == RectangleGradient)
+                    intensity = initial_intensity + QMAX(xvar, yvar);
+                else
+                    intensity = initial_intensity + sqrt(xvar * xvar + yvar * yvar);
+                if (intensity > 1) intensity = 1;
+                if (intensity < 0) intensity = 0;
+
+                //SW
+                ind = x + image_width  * (image_height - y -1) ;
+                r = qRed  (data[ind]) + (int)(intensity *
+                                              (r_bgnd - qRed  (data[ind])));
+                g = qGreen(data[ind]) + (int)(intensity *
+                                              (g_bgnd - qGreen(data[ind])));
+                b = qBlue (data[ind]) + (int)(intensity *
+                                              (b_bgnd - qBlue (data[ind])));
+                if (r > 255) r = 255; if (r < 0 ) r = 0;
+                if (g > 255) g = 255; if (g < 0 ) g = 0;
+                if (b > 255) b = 255; if (b < 0 ) b = 0;
+                a = qAlpha(data[ind]);
+                data[ind] = qRgba(r, g, b, a);
+
+                //SE
+                ind = image_width-x-1 + image_width * (image_height - y - 1) ;
+                r = qRed  (data[ind]) + (int)(intensity *
+                                              (r_bgnd - qRed  (data[ind])));
+                g = qGreen(data[ind]) + (int)(intensity *
+                                              (g_bgnd - qGreen(data[ind])));
+                b = qBlue (data[ind]) + (int)(intensity *
+                                              (b_bgnd - qBlue (data[ind])));
+                if (r > 255) r = 255; if (r < 0 ) r = 0;
+                if (g > 255) g = 255; if (g < 0 ) g = 0;
+                if (b > 255) b = 255; if (b < 0 ) b = 0;
+                a = qAlpha(data[ind]);
+                data[ind] = qRgba(r, g, b, a);
+            }
+        }
+    }
+#ifndef NDEBUG
+    else std::cerr << "KImageEffect::blend effect not implemented" << std::endl;
+#endif
+    return image;
+}
+
+// Not very efficient as we create a third big image...
+//
+QImage& KImageEffect::blend(QImage &image1, QImage &image2,
+			    GradientType gt, int xf, int yf)
+{
+  if (image1.width() == 0 || image1.height() == 0 ||
+      image2.width() == 0 || image2.height() == 0)
+    return image1;
+
+  QImage image3;
+
+  image3 = KImageEffect::unbalancedGradient(image1.size(),
+				    QColor(0,0,0), QColor(255,255,255),
+				    gt, xf, yf, 0);
+
+  return blend(image1,image2,image3, Red); // Channel to use is arbitrary
+}
+
+// Blend image2 into image1, using an RBG channel of blendImage
+//
+QImage& KImageEffect::blend(QImage &image1, QImage &image2,
+			    QImage &blendImage, RGBComponent channel)
+{
+    if (image1.width() == 0 || image1.height() == 0 ||
+        image2.width() == 0 || image2.height() == 0 ||
+        blendImage.width() == 0 || blendImage.height() == 0) {
+#ifndef NDEBUG
+        std::cerr << "KImageEffect::blend effect invalid image" << std::endl;
+#endif
+      return image1;
+    }
+
+    int r, g, b;
+    int ind1, ind2, ind3;
+
+    unsigned int x1, x2, x3, y1, y2, y3;
+    unsigned int a;
+
+    register int x, y;
+
+    // for image1 and image2, we only handle depth 32
+    if (image1.depth()<32) image1 = image1.convertDepth(32);
+    if (image2.depth()<32) image2 = image2.convertDepth(32);
+
+    // for blendImage, we handle depth 8 and 32
+    if (blendImage.depth()<8) blendImage = blendImage.convertDepth(8);
+
+    unsigned int *colorTable3 = (blendImage.depth()==8) ?
+				 blendImage.colorTable():0;
+
+    unsigned int *data1 =  (unsigned int *)image1.bits();
+    unsigned int *data2 =  (unsigned int *)image2.bits();
+    unsigned int *data3   =  (unsigned int *)blendImage.bits();
+    unsigned char *data3b =  (unsigned char *)blendImage.bits();
+    unsigned int color3;
+
+    x1 = image1.width();     y1 = image1.height();
+    x2 = image2.width();     y2 = image2.height();
+    x3 = blendImage.width(); y3 = blendImage.height();
+
+    for (y = 0; y < (int)y1; y++) {
+	ind1 = x1*y;
+	ind2 = x2*(y%y2);
+	ind3 = x3*(y%y3);
+
+	x=0;
+	while(x < (int)x1) {
+	  color3 = (colorTable3) ? colorTable3[data3b[ind3]] : data3[ind3];
+
+          a = (channel == Red) ? qRed(color3) :
+              (channel == Green) ? qGreen(color3) :
+	      (channel == Blue) ? qBlue(color3) : qGray(color3);
+
+	  r = (a*qRed(data1[ind1]) + (256-a)*qRed(data2[ind2]))/256;
+	  g = (a*qGreen(data1[ind1]) + (256-a)*qGreen(data2[ind2]))/256;
+	  b = (a*qBlue(data1[ind1]) + (256-a)*qBlue(data2[ind2]))/256;
+
+	  a = qAlpha(data1[ind1]);
+	  data1[ind1] = qRgba(r, g, b, a);
+
+	  ind1++; ind2++; ind3++; x++;
+	  if ( (x%x2) ==0) ind2 -= x2;
+	  if ( (x%x3) ==0) ind3 -= x3;
+        }
+    }
+    return image1;
+}
+
+
+//======================================================================
+//
+// Hash effects
+//
+//======================================================================
+
+unsigned int KImageEffect::lHash(unsigned int c)
+{
+    unsigned char r = qRed(c), g = qGreen(c), b = qBlue(c), a = qAlpha(c);
+    unsigned char nr, ng, nb;
+    nr =(r >> 1) + (r >> 2); nr = nr > r ? 0 : nr;
+    ng =(g >> 1) + (g >> 2); ng = ng > g ? 0 : ng;
+    nb =(b >> 1) + (b >> 2); nb = nb > b ? 0 : nb;
+
+    return qRgba(nr, ng, nb, a);
+}
+
+
+// -----------------------------------------------------------------------------
+
+unsigned int KImageEffect::uHash(unsigned int c)
+{
+    unsigned char r = qRed(c), g = qGreen(c), b = qBlue(c), a = qAlpha(c);
+    unsigned char nr, ng, nb;
+    nr = r + (r >> 3); nr = nr < r ? ~0 : nr;
+    ng = g + (g >> 3); ng = ng < g ? ~0 : ng;
+    nb = b + (b >> 3); nb = nb < b ? ~0 : nb;
+
+    return qRgba(nr, ng, nb, a);
+}
+
+
+// -----------------------------------------------------------------------------
+
+QImage& KImageEffect::hash(QImage &image, Lighting lite, unsigned int spacing)
+{
+    if (image.width() == 0 || image.height() == 0) {
+#ifndef NDEBUG
+        std::cerr << "KImageEffect::hash effect invalid image" << std::endl;
+#endif
+      return image;
+    }
+
+    register int x, y;
+    unsigned int *data =  (unsigned int *)image.bits();
+    unsigned int ind;
+
+    //CT no need to do it if not enough space
+    if ((lite == NorthLite ||
+         lite == SouthLite)&&
+        (unsigned)image.height() < 2+spacing) return image;
+    if ((lite == EastLite ||
+         lite == WestLite)&&
+        (unsigned)image.height() < 2+spacing) return image;
+
+    if (lite == NorthLite || lite == SouthLite) {
+        for (y = 0 ; y < image.height(); y = y + 2 + spacing) {
+            for (x = 0; x < image.width(); x++) {
+                ind = x + image.width() * y;
+                data[ind] = lite==NorthLite?uHash(data[ind]):lHash(data[ind]);
+
+                ind = ind + image.width();
+                data[ind] = lite==NorthLite?lHash(data[ind]):uHash(data[ind]);
+            }
+        }
+    }
+
+    else if (lite == EastLite || lite == WestLite) {
+        for (y = 0 ; y < image.height(); y++) {
+            for (x = 0; x < image.width(); x = x + 2 + spacing) {
+                ind = x + image.width() * y;
+                data[ind] = lite==EastLite?uHash(data[ind]):lHash(data[ind]);
+
+                ind++;
+                data[ind] = lite==EastLite?lHash(data[ind]):uHash(data[ind]);
+            }
+        }
+    }
+
+    else if (lite == NWLite || lite == SELite) {
+        for (y = 0 ; y < image.height(); y++) {
+            for (x = 0;
+                 x < (int)(image.width() - ((y & 1)? 1 : 0) * spacing);
+                 x = x + 2 + spacing) {
+                ind = x + image.width() * y + ((y & 1)? 1 : 0);
+                data[ind] = lite==NWLite?uHash(data[ind]):lHash(data[ind]);
+
+                ind++;
+                data[ind] = lite==NWLite?lHash(data[ind]):uHash(data[ind]);
+            }
+        }
+    }
+
+    else if (lite == SWLite || lite == NELite) {
+        for (y = 0 ; y < image.height(); y++) {
+            for (x = 0  + ((y & 1)? 1 : 0); x < image.width(); x = x + 2 + spacing) {
+                ind = x + image.width() * y - ((y & 1)? 1 : 0);
+                data[ind] = lite==SWLite?uHash(data[ind]):lHash(data[ind]);
+
+                ind++;
+                data[ind] = lite==SWLite?lHash(data[ind]):uHash(data[ind]);
+            }
+        }
+    }
+
+    return image;
+}
+
+
+//======================================================================
+//
+// Flatten effects
+//
+//======================================================================
+
+QImage& KImageEffect::flatten(QImage &img, const QColor &ca,
+                            const QColor &cb, int ncols)
+{
+    if (img.width() == 0 || img.height() == 0)
+      return img;
+
+    // a bitmap is easy...
+    if (img.depth() == 1) {
+	img.setColor(0, ca.rgb());
+	img.setColor(1, cb.rgb());
+	return img;
+    }
+
+    int r1 = ca.red(); int r2 = cb.red();
+    int g1 = ca.green(); int g2 = cb.green();
+    int b1 = ca.blue(); int b2 = cb.blue();
+    int min = 0, max = 255;
+
+    QRgb col;
+
+    // Get minimum and maximum greylevel.
+    if (img.numColors()) {
+	// pseudocolor
+	for (int i = 0; i < img.numColors(); i++) {
+	    col = img.color(i);
+	    int mean = (qRed(col) + qGreen(col) + qBlue(col)) / 3;
+	    min = QMIN(min, mean);
+	    max = QMAX(max, mean);
+	}
+    } else {
+	// truecolor
+	for (int y=0; y < img.height(); y++)
+	    for (int x=0; x < img.width(); x++) {
+		col = img.pixel(x, y);
+		int mean = (qRed(col) + qGreen(col) + qBlue(col)) / 3;
+		min = QMIN(min, mean);
+		max = QMAX(max, mean);
+	    }
+    }
+
+    // Conversion factors
+    float sr = ((float) r2 - r1) / (max - min);
+    float sg = ((float) g2 - g1) / (max - min);
+    float sb = ((float) b2 - b1) / (max - min);
+
+
+    // Repaint the image
+    if (img.numColors()) {
+	for (int i=0; i < img.numColors(); i++) {
+	    col = img.color(i);
+	    int mean = (qRed(col) + qGreen(col) + qBlue(col)) / 3;
+	    int r = (int) (sr * (mean - min) + r1 + 0.5);
+	    int g = (int) (sg * (mean - min) + g1 + 0.5);
+	    int b = (int) (sb * (mean - min) + b1 + 0.5);
+	    img.setColor(i, qRgba(r, g, b, qAlpha(col)));
+	}
+    } else {
+	for (int y=0; y < img.height(); y++)
+	    for (int x=0; x < img.width(); x++) {
+		col = img.pixel(x, y);
+		int mean = (qRed(col) + qGreen(col) + qBlue(col)) / 3;
+		int r = (int) (sr * (mean - min) + r1 + 0.5);
+		int g = (int) (sg * (mean - min) + g1 + 0.5);
+		int b = (int) (sb * (mean - min) + b1 + 0.5);
+		img.setPixel(x, y, qRgba(r, g, b, qAlpha(col)));
+	    }
+    }
+
+
+    // Dither if necessary
+    if ( (ncols <= 0) || ((img.numColors() != 0) && (img.numColors() <= ncols)))
+	return img;
+
+    if (ncols == 1) ncols++;
+    if (ncols > 256) ncols = 256;
+
+    QColor *pal = new QColor[ncols];
+    sr = ((float) r2 - r1) / (ncols - 1);
+    sg = ((float) g2 - g1) / (ncols - 1);
+    sb = ((float) b2 - b1) / (ncols - 1);
+
+    for (int i=0; i<ncols; i++)
+	pal[i] = QColor(r1 + int(sr*i), g1 + int(sg*i), b1 + int(sb*i));
+
+    dither(img, pal, ncols);
+
+    delete[] pal;
+    return img;
+}
+
+
+//======================================================================
+//
+// Fade effects
+//
+//======================================================================
+
+QImage& KImageEffect::fade(QImage &img, float val, const QColor &color)
+{
+    if (img.width() == 0 || img.height() == 0)
+      return img;
+
+    // We don't handle bitmaps
+    if (img.depth() == 1)
+	return img;
+
+    unsigned char tbl[256];
+    for (int i=0; i<256; i++)
+	tbl[i] = (int) (val * i + 0.5);
+
+    int red = color.red();
+    int green = color.green();
+    int blue = color.blue();
+
+    QRgb col;
+    int r, g, b, cr, cg, cb;
+
+    if (img.depth() <= 8) {
+	// pseudo color
+	for (int i=0; i<img.numColors(); i++) {
+	    col = img.color(i);
+	    cr = qRed(col); cg = qGreen(col); cb = qBlue(col);
+	    if (cr > red)
+		r = cr - tbl[cr - red];
+	    else
+		r = cr + tbl[red - cr];
+	    if (cg > green)
+		g = cg - tbl[cg - green];
+	    else
+		g = cg + tbl[green - cg];
+	    if (cb > blue)
+		b = cb - tbl[cb - blue];
+	    else
+		b = cb + tbl[blue - cb];
+	    img.setColor(i, qRgba(r, g, b, qAlpha(col)));
+	}
+
+    } else {
+	// truecolor
+        for (int y=0; y<img.height(); y++) {
+            QRgb *data = (QRgb *) img.scanLine(y);
+            for (int x=0; x<img.width(); x++) {
+                col = *data;
+                cr = qRed(col); cg = qGreen(col); cb = qBlue(col);
+                if (cr > red)
+                    r = cr - tbl[cr - red];
+                else
+                    r = cr + tbl[red - cr];
+                if (cg > green)
+                    g = cg - tbl[cg - green];
+                else
+                    g = cg + tbl[green - cg];
+                if (cb > blue)
+                    b = cb - tbl[cb - blue];
+                else
+                    b = cb + tbl[blue - cb];
+                *data++ = qRgba(r, g, b, qAlpha(col));
+            }
+        }
+    }
+
+    return img;
+}
+
+//======================================================================
+//
+// Color effects
+//
+//======================================================================
+
+// This code is adapted from code (C) Rik Hemsley <rik@kde.org>
+//
+// The formula used (r + b + g) /3 is different from the qGray formula
+// used by Qt.  This is because our formula is much much faster.  If,
+// however, it turns out that this is producing sub-optimal images,
+// then it will have to change (kurt)
+//
+// It does produce lower quality grayscale ;-) Use fast == true for the fast
+// algorithm, false for the higher quality one (mosfet).
+QImage& KImageEffect::toGray(QImage &img, bool fast)
+{
+    if (img.width() == 0 || img.height() == 0)
+      return img;
+
+    if(fast){
+        if (img.depth() == 32) {
+            register uchar * r(img.bits());
+            register uchar * g(img.bits() + 1);
+            register uchar * b(img.bits() + 2);
+
+            uchar * end(img.bits() + img.numBytes());
+
+            while (r != end) {
+
+                *r = *g = *b = (((*r + *g) >> 1) + *b) >> 1; // (r + b + g) / 3
+
+                r += 4;
+                g += 4;
+                b += 4;
+            }
+        }
+        else
+        {
+            for (int i = 0; i < img.numColors(); i++)
+            {
+                register uint r = qRed(img.color(i));
+                register uint g = qGreen(img.color(i));
+                register uint b = qBlue(img.color(i));
+
+                register uint gray = (((r + g) >> 1) + b) >> 1;
+                img.setColor(i, qRgba(gray, gray, gray, qAlpha(img.color(i))));
+            }
+        }
+    }
+    else{
+        int pixels = img.depth() > 8 ? img.width()*img.height() :
+            img.numColors();
+        unsigned int *data = img.depth() > 8 ? (unsigned int *)img.bits() :
+            (unsigned int *)img.colorTable();
+        int val, i;
+        for(i=0; i < pixels; ++i){
+            val = qGray(data[i]);
+            data[i] = qRgba(val, val, val, qAlpha(data[i]));
+        }
+    }
+    return img;
+}
+
+// CT 29Jan2000 - desaturation algorithms
+QImage& KImageEffect::desaturate(QImage &img, float desat)
+{
+    if (img.width() == 0 || img.height() == 0)
+      return img;
+
+    if (desat < 0) desat = 0.;
+    if (desat > 1) desat = 1.;
+    int pixels = img.depth() > 8 ? img.width()*img.height() :
+        img.numColors();
+    unsigned int *data = img.depth() > 8 ? (unsigned int *)img.bits() :
+        (unsigned int *)img.colorTable();
+    int h, s, v, i;
+    QColor clr; // keep constructor out of loop (mosfet)
+    for(i=0; i < pixels; ++i){
+        clr.setRgb(data[i]);
+	clr.hsv(&h, &s, &v);
+	clr.setHsv(h, (int)(s * (1. - desat)), v);
+	data[i] = clr.rgb();
+    }
+    return img;
+}
+
+// Contrast stuff (mosfet)
+QImage& KImageEffect::contrast(QImage &img, int c)
+{
+    if (img.width() == 0 || img.height() == 0)
+      return img;
+
+    if(c > 255)
+        c = 255;
+    if(c < -255)
+        c =  -255;
+    int pixels = img.depth() > 8 ? img.width()*img.height() :
+        img.numColors();
+    unsigned int *data = img.depth() > 8 ? (unsigned int *)img.bits() :
+        (unsigned int *)img.colorTable();
+    int i, r, g, b;
+    for(i=0; i < pixels; ++i){
+        r = qRed(data[i]);
+        g = qGreen(data[i]);
+        b = qBlue(data[i]);
+        if(qGray(data[i]) <= 127){
+            if(r - c > 0)
+                r -= c;
+            else
+                r = 0;
+            if(g - c > 0)
+                g -= c;
+            else
+                g = 0;
+            if(b - c > 0)
+                b -= c;
+            else
+                b = 0;
+        }
+        else{
+            if(r + c <= 255)
+                r += c;
+            else
+                r = 255;
+            if(g + c <= 255)
+                g += c;
+            else
+                g = 255;
+            if(b + c <= 255)
+                b += c;
+            else
+                b = 255;
+        }
+        data[i] = qRgba(r, g, b, qAlpha(data[i]));
+    }
+    return(img);
+}
+
+//======================================================================
+//
+// Dithering effects
+//
+//======================================================================
+
+// adapted from kFSDither (C) 1997 Martin Jones (mjones@kde.org)
+//
+// Floyd-Steinberg dithering
+// Ref: Bitmapped Graphics Programming in C++
+//      Marv Luse, Addison-Wesley Publishing, 1993.
+QImage& KImageEffect::dither(QImage &img, const QColor *palette, int size)
+{
+    if (img.width() == 0 || img.height() == 0 ||
+        palette == 0 || img.depth() <= 8)
+      return img;
+
+    QImage dImage( img.width(), img.height(), 8, size );
+    int i;
+
+    dImage.setNumColors( size );
+    for ( i = 0; i < size; i++ )
+        dImage.setColor( i, palette[ i ].rgb() );
+
+    int *rerr1 = new int [ img.width() * 2 ];
+    int *gerr1 = new int [ img.width() * 2 ];
+    int *berr1 = new int [ img.width() * 2 ];
+
+    memset( rerr1, 0, sizeof( int ) * img.width() * 2 );
+    memset( gerr1, 0, sizeof( int ) * img.width() * 2 );
+    memset( berr1, 0, sizeof( int ) * img.width() * 2 );
+
+    int *rerr2 = rerr1 + img.width();
+    int *gerr2 = gerr1 + img.width();
+    int *berr2 = berr1 + img.width();
+
+    for ( int j = 0; j < img.height(); j++ )
+    {
+        uint *ip = (uint * )img.scanLine( j );
+        uchar *dp = dImage.scanLine( j );
+
+        for ( i = 0; i < img.width(); i++ )
+        {
+            rerr1[i] = rerr2[i] + qRed( *ip );
+            rerr2[i] = 0;
+            gerr1[i] = gerr2[i] + qGreen( *ip );
+            gerr2[i] = 0;
+            berr1[i] = berr2[i] + qBlue( *ip );
+            berr2[i] = 0;
+            ip++;
+        }
+
+        *dp++ = nearestColor( rerr1[0], gerr1[0], berr1[0], palette, size );
+
+        for ( i = 1; i < img.width()-1; i++ )
+        {
+            int indx = nearestColor( rerr1[i], gerr1[i], berr1[i], palette, size );
+            *dp = indx;
+
+            int rerr = rerr1[i];
+            rerr -= palette[indx].red();
+            int gerr = gerr1[i];
+            gerr -= palette[indx].green();
+            int berr = berr1[i];
+            berr -= palette[indx].blue();
+
+            // diffuse red error
+            rerr1[ i+1 ] += ( rerr * 7 ) >> 4;
+            rerr2[ i-1 ] += ( rerr * 3 ) >> 4;
+            rerr2[  i  ] += ( rerr * 5 ) >> 4;
+            rerr2[ i+1 ] += ( rerr ) >> 4;
+
+            // diffuse green error
+            gerr1[ i+1 ] += ( gerr * 7 ) >> 4;
+            gerr2[ i-1 ] += ( gerr * 3 ) >> 4;
+            gerr2[  i  ] += ( gerr * 5 ) >> 4;
+            gerr2[ i+1 ] += ( gerr ) >> 4;
+
+            // diffuse red error
+            berr1[ i+1 ] += ( berr * 7 ) >> 4;
+            berr2[ i-1 ] += ( berr * 3 ) >> 4;
+            berr2[  i  ] += ( berr * 5 ) >> 4;
+            berr2[ i+1 ] += ( berr ) >> 4;
+
+            dp++;
+        }
+
+        *dp = nearestColor( rerr1[i], gerr1[i], berr1[i], palette, size );
+    }
+
+    delete [] rerr1;
+    delete [] gerr1;
+    delete [] berr1;
+
+    img = dImage;
+    return img;
+}
+
+int KImageEffect::nearestColor( int r, int g, int b, const QColor *palette, int size )
+{
+    if (palette == 0)
+      return 0;
+
+    int dr = palette[0].red() - r;
+    int dg = palette[0].green() - g;
+    int db = palette[0].blue() - b;
+
+    int minDist =  dr*dr + dg*dg + db*db;
+    int nearest = 0;
+
+    for (int i = 1; i < size; i++ )
+    {
+        dr = palette[i].red() - r;
+        dg = palette[i].green() - g;
+        db = palette[i].blue() - b;
+
+        int dist = dr*dr + dg*dg + db*db;
+
+        if ( dist < minDist )
+        {
+            minDist = dist;
+            nearest = i;
+        }
+    }
+
+    return nearest;
+}
+
+bool KImageEffect::blend(
+    const QImage & upper,
+    const QImage & lower,
+    QImage & output
+)
+{
+  if (
+      upper.width()  > lower.width()  ||
+      upper.height() > lower.height() ||
+      upper.depth() != 32             ||
+      lower.depth() != 32
+  )
+  {
+#ifndef NDEBUG
+    std::cerr << "KImageEffect::blend : Sizes not correct\n" ;
+#endif
+    return false;
+  }
+
+  output = lower.copy();
+
+  register uchar *i, *o;
+  register int a;
+  register int col;
+  register int w = upper.width();
+  int row(upper.height() - 1);
+
+  do {
+
+    i = upper.scanLine(row);
+    o = output.scanLine(row);
+
+    col = w << 2;
+    --col;
+
+    do {
+
+      while (!(a = i[col]) && (col != 3)) {
+        --col; --col; --col; --col;
+      }
+
+      --col;
+      o[col] += ((i[col] - o[col]) * a) >> 8;
+
+      --col;
+      o[col] += ((i[col] - o[col]) * a) >> 8;
+
+      --col;
+      o[col] += ((i[col] - o[col]) * a) >> 8;
+
+    } while (col--);
+
+  } while (row--);
+
+  return true;
+}
+
+#if 0
+// Not yet...
+bool KImageEffect::blend(
+    const QImage & upper,
+    const QImage & lower,
+    QImage & output,
+    const QRect & destRect
+)
+{
+  output = lower.copy();
+  return output;
+}
+
+#endif
+
+bool KImageEffect::blend(
+    int &x, int &y,
+    const QImage & upper,
+    const QImage & lower,
+    QImage & output
+)
+{
+  int cx=0, cy=0, cw=upper.width(), ch=upper.height();
+
+  if ( upper.width() + x > lower.width()  ||
+      upper.height() + y > lower.height() ||
+      x < 0 || y < 0 ||
+      upper.depth() != 32 || lower.depth() != 32 )
+  {
+    if ( x > lower.width() || y > lower.height() ) return false;
+    if ( upper.width()<=0 || upper.height() <= 0 ) return false;
+    if ( lower.width()<=0 || lower.height() <= 0 ) return false;
+
+    if (x<0) {cx=-x; cw+=x; x=0; };
+    if (cw + x > lower.width()) { cw=lower.width()-x; };
+    if (y<0) {cy=-y; ch+=y; y=0; };
+    if (ch + y > lower.height()) { ch=lower.height()-y; };
+
+    if ( cx >= upper.width() || cy >= upper.height() ) return true;
+    if ( cw <= 0 || ch <= 0 ) return true;
+  }
+
+  output.create(cw,ch,32);
+//  output.setAlphaBuffer(true); // I should do some benchmarks to see if
+	// this is worth the effort
+
+  register QRgb *i, *o, *b;
+
+  register int a;
+  register int j,k;
+  for (j=0; j<ch; j++)
+  {
+    b=reinterpret_cast<QRgb *>(&lower.scanLine(y+j) [ (x+cw) << 2 ]);
+    i=reinterpret_cast<QRgb *>(&upper.scanLine(cy+j)[ (cx+cw) << 2 ]);
+    o=reinterpret_cast<QRgb *>(&output.scanLine(j)  [ cw << 2 ]);
+
+    k=cw-1;
+    --b; --i; --o;
+    do
+    {
+      while ( !(a=qAlpha(*i)) && k>0 )
+      {
+        i--;
+//	*o=0;
+	*o=*b;
+	--o; --b;
+	k--;
+      };
+//      *o=0xFF;
+      *o = qRgb(qRed(*b) + (((qRed(*i) - qRed(*b)) * a) >> 8),
+                qGreen(*b) + (((qGreen(*i) - qGreen(*b)) * a) >> 8),
+                qBlue(*b) + (((qBlue(*i) - qBlue(*b)) * a) >> 8));
+      --i; --o; --b;
+    } while (k--);
+  }
+
+  return true;
+}
+
+bool KImageEffect::blendOnLower(
+    int x, int y,
+    const QImage & upper,
+    const QImage & lower
+)
+{
+  int cx=0, cy=0, cw=upper.width(), ch=upper.height();
+
+  if ( upper.depth() != 32 || lower.depth() != 32 ) return false;
+  if ( x + cw > lower.width()  ||
+      y + ch > lower.height() ||
+      x < 0 || y < 0 )
+  {
+    if ( x > lower.width() || y > lower.height() ) return true;
+    if ( upper.width()<=0 || upper.height() <= 0 ) return true;
+    if ( lower.width()<=0 || lower.height() <= 0 ) return true;
+
+    if (x<0) {cx=-x; cw+=x; x=0; };
+    if (cw + x > lower.width()) { cw=lower.width()-x; };
+    if (y<0) {cy=-y; ch+=y; y=0; };
+    if (ch + y > lower.height()) { ch=lower.height()-y; };
+
+    if ( cx >= upper.width() || cy >= upper.height() ) return true;
+    if ( cw <= 0 || ch <= 0 ) return true;
+  }
+
+  register uchar *i, *b;
+  register int a;
+  register int k;
+
+  for (int j=0; j<ch; j++)
+  {
+    b=&lower.scanLine(y+j) [ (x+cw) << 2 ];
+    i=&upper.scanLine(cy+j)[ (cx+cw) << 2 ];
+
+    k=cw-1;
+    --b; --i;
+    do
+    {
+#ifndef WORDS_BIGENDIAN
+      while ( !(a=*i) && k>0 )
+#else
+      while ( !(a=*(i-3)) && k>0 )
+#endif
+      {
+        i-=4; b-=4; k--;
+      };
+
+#ifndef WORDS_BIGENDIAN
+      --i; --b;
+      *b += ( ((*i - *b) * a) >> 8 );
+      --i; --b;
+      *b += ( ((*i - *b) * a) >> 8 );
+      --i; --b;
+      *b += ( ((*i - *b) * a) >> 8 );
+      --i; --b;
+#else
+      *b += ( ((*i - *b) * a) >> 8 );
+      --i; --b;
+      *b += ( ((*i - *b) * a) >> 8 );
+      --i; --b;
+      *b += ( ((*i - *b) * a) >> 8 );
+      i -= 2; b -= 2;
+#endif
+    } while (k--);
+  }
+
+  return true;
+}
+
+void KImageEffect::blendOnLower(const QImage &upper, const QPoint &upperOffset,
+                                QImage &lower, const QRect &lowerRect)
+{
+    // clip rect
+    QRect lr =  lowerRect & lower.rect();
+    lr.setWidth( QMIN(lr.width(), upper.width()-upperOffset.x()) );
+    lr.setHeight( QMIN(lr.height(), upper.height()-upperOffset.y()) );
+    if ( !lr.isValid() ) return;
+
+    // blend
+    for (int y = 0; y < lr.height(); y++) {
+        for (int x = 0; x < lr.width(); x++) {
+            QRgb *b = reinterpret_cast<QRgb*>(lower.scanLine(lr.y() + y)+ (lr.x() + x) * sizeof(QRgb));
+            QRgb *d = reinterpret_cast<QRgb*>(upper.scanLine(upperOffset.y() + y) + (upperOffset.x() + x) * sizeof(QRgb));
+            int a = qAlpha(*d);
+            *b = qRgb(qRed(*b) - (((qRed(*b) - qRed(*d)) * a) >> 8),
+                      qGreen(*b) - (((qGreen(*b) - qGreen(*d)) * a) >> 8),
+                      qBlue(*b) - (((qBlue(*b) - qBlue(*d)) * a) >> 8));
+        }
+    }
+}
+
+void KImageEffect::blendOnLower(const QImage &upper, const QPoint &upperOffset,
+                          QImage &lower, const QRect &lowerRect, float opacity)
+{
+    // clip rect
+    QRect lr =  lowerRect & lower.rect();
+    lr.setWidth( QMIN(lr.width(), upper.width()-upperOffset.x()) );
+    lr.setHeight( QMIN(lr.height(), upper.height()-upperOffset.y()) );
+    if ( !lr.isValid() ) return;
+
+    // blend
+    for (int y = 0; y < lr.height(); y++) {
+        for (int x = 0; x < lr.width(); x++) {
+            QRgb *b = reinterpret_cast<QRgb*>(lower.scanLine(lr.y() + y)+ (lr.x() + x) * sizeof(QRgb));
+            QRgb *d = reinterpret_cast<QRgb*>(upper.scanLine(upperOffset.y() + y) + (upperOffset.x() + x) * sizeof(QRgb));
+            int a = qRound(opacity * qAlpha(*d));
+            *b = qRgb(qRed(*b) - (((qRed(*b) - qRed(*d)) * a) >> 8),
+                      qGreen(*b) - (((qGreen(*b) - qGreen(*d)) * a) >> 8),
+                      qBlue(*b) - (((qBlue(*b) - qBlue(*d)) * a) >> 8));
+        }
+    }
+}
+
+QRect KImageEffect::computeDestinationRect(const QSize &lowerSize,
+                                       Disposition disposition, QImage &upper)
+{
+    int w = lowerSize.width();
+    int h = lowerSize.height();
+    int ww = upper.width();
+    int wh = upper.height();
+    QRect d;
+
+    switch (disposition) {
+    case NoImage:
+        break;
+    case Centered:
+        d.setRect((w - ww) / 2, (h - wh) / 2, ww, wh);
+        break;
+    case Tiled:
+        d.setRect(0, 0, w, h);
+        break;
+    case CenterTiled:
+        d.setCoords(-ww + ((w - ww) / 2) % ww, -wh + ((h - wh) / 2) % wh,
+                    w-1, h-1);
+        break;
+    case Scaled:
+        upper = upper.smoothScale(w, h);
+        d.setRect(0, 0, w, h);
+        break;
+    case CenteredAutoFit:
+        if( ww <= w && wh <= h ) {
+            d.setRect((w - ww) / 2, (h - wh) / 2, ww, wh); // like Centered
+            break;
+        }
+        // fall through
+    case CenteredMaxpect: {
+        double sx = (double) w / ww;
+        double sy = (double) h / wh;
+        if (sx > sy) {
+            ww = (int)(sy * ww);
+            wh = h;
+        } else {
+            wh = (int)(sx * wh);
+            ww = w;
+        }
+        upper = upper.smoothScale(ww, wh);
+        d.setRect((w - ww) / 2, (h - wh) / 2, ww, wh);
+        break;
+    }
+    case TiledMaxpect: {
+        double sx = (double) w / ww;
+        double sy = (double) h / wh;
+        if (sx > sy) {
+            ww = (int)(sy * ww);
+            wh = h;
+        } else {
+            wh = (int)(sx * wh);
+            ww = w;
+        }
+        upper = upper.smoothScale(ww, wh);
+        d.setRect(0, 0, w, h);
+        break;
+    }
+    }
+
+    return d;
+}
+
+void KImageEffect::blendOnLower(QImage &upper, QImage &lower,
+                                Disposition disposition, float opacity)
+{
+    QRect r = computeDestinationRect(lower.size(), disposition, upper);
+    for (int y = r.top(); y<r.bottom(); y += upper.height())
+        for (int x = r.left(); x<r.right(); x += upper.width())
+            blendOnLower(upper, QPoint(-QMIN(x, 0), -QMIN(y, 0)),
+                   lower, QRect(x, y, upper.width(), upper.height()), opacity);
+}
+
+
+// For selected icons
+QImage& KImageEffect::selectedImage( QImage &img, const QColor &col )
+{
+    return blend( col, img, 0.5);
+}
+
+//
+// ===================================================================
+// Effects originally ported from ImageMagick for PixiePlus, plus a few
+// new ones. (mosfet 05/26/2003)
+// ===================================================================
+//
+/*
+ Portions of this software are based on ImageMagick. Such portions are clearly
+marked as being ported from ImageMagick. ImageMagick is copyrighted under the
+following conditions:
+
+Copyright (C) 2003 ImageMagick Studio, a non-profit organization dedicated to
+making software imaging solutions freely available.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files ("ImageMagick"), to deal
+in ImageMagick without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense,  and/or sell
+copies of ImageMagick, and to permit persons to whom the ImageMagick 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 ImageMagick.
+
+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
+ImageMagick Studio 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 ImageMagick or the use or other dealings in ImageMagick.
+
+Except as contained in this notice, the name of the ImageMagick Studio shall
+not be used in advertising or otherwise to promote the sale, use or other
+dealings in ImageMagick without prior written authorization from the
+ImageMagick Studio.
+*/
+
+QImage KImageEffect::sample(QImage &src, int w, int h)
+{
+    if(w == src.width() && h == src.height())
+        return(src);
+
+    int depth = src.depth();
+    QImage dest(w, h, depth, depth <= 8 ? src.numColors() : 0,
+    depth == 1 ? QImage::LittleEndian : QImage::IgnoreEndian);
+    int *x_offset = (int *)malloc(w*sizeof(int));
+    int *y_offset = (int *)malloc(h*sizeof(int));
+    if(!x_offset || !y_offset){
+#ifndef NDEBUG
+        qWarning("KImageEffect::sample(): Unable to allocate pixel buffer");
+#endif
+        free(x_offset);
+        free(y_offset);
+        return(src);
+    }
+
+    // init pixel offsets
+    for(int x=0; x < w; ++x)
+        x_offset[x] = (int)(x*src.width()/((double)w));
+    for(int y=0; y < h; ++y)
+        y_offset[y] = (int)(y*src.height()/((double)h));
+
+    if(depth > 8){ // DirectClass source image
+        for(int y=0; y < h; ++y){
+            unsigned int *destData = (unsigned int *)dest.scanLine(y);
+            unsigned int *srcData = (unsigned int *)src.scanLine(y_offset[y]);
+            for(int x=0; x < w; ++x)
+                destData[x] = srcData[x_offset[x]];
+        }
+    }
+    else if(depth == 1) {
+        int r = src.bitOrder() == QImage::LittleEndian;
+        memcpy(dest.colorTable(), src.colorTable(), src.numColors()*sizeof(QRgb));
+        for(int y=0; y < h; ++y){
+            unsigned char *destData = dest.scanLine(y);
+            unsigned char *srcData = src.scanLine(y_offset[y]);
+            for(int x=0; x < w; ++x){
+                int k = x_offset[x];
+                int l = r ? (k & 7) : (7 - (k&7));
+                if(srcData[k >> 3] & (1 << l))
+                    destData[x >> 3] |= 1 << (x & 7);
+                else
+                    destData[x >> 3] &= ~(1 << (x & 7));
+            }
+        }
+    }
+    else{ // PseudoClass source image
+        memcpy(dest.colorTable(), src.colorTable(), src.numColors()*sizeof(QRgb));
+        for(int y=0; y < h; ++y){
+            unsigned char *destData = dest.scanLine(y);
+            unsigned char *srcData = src.scanLine(y_offset[y]);
+            for(int x=0; x < w; ++x)
+                destData[x] = srcData[x_offset[x]];
+        }
+    }
+    free(x_offset);
+    free(y_offset);
+    return(dest);
+}
+
+void KImageEffect::threshold(QImage &img, unsigned int threshold)
+{
+    int i, count;
+    unsigned int *data;
+    if(img.depth() > 8){ // DirectClass
+        count = img.width()*img.height();
+        data = (unsigned int *)img.bits();
+    }
+    else{ // PsudeoClass
+        count = img.numColors();
+        data = (unsigned int *)img.colorTable();
+    }
+    for(i=0; i < count; ++i)
+        data[i] = intensityValue(data[i]) < threshold ? Qt::black.rgb() : Qt::white.rgb();
+}
+
+void KImageEffect::hull(const int x_offset, const int y_offset,
+                        const int polarity, const int columns,
+                        const int rows,
+                        unsigned int *f, unsigned int *g)
+{
+    int x, y;
+
+    unsigned int *p, *q, *r, *s;
+    unsigned int v;
+    if(f == NULL || g == NULL)
+        return;
+    p=f+(columns+2);
+    q=g+(columns+2);
+    r=p+(y_offset*(columns+2)+x_offset);
+    for (y=0; y < rows; y++){
+        p++;
+        q++;
+        r++;
+        if(polarity > 0)
+            for (x=0; x < columns; x++){
+                v=(*p);
+                if (*r > v)
+                    v++;
+                *q=v;
+                p++;
+                q++;
+                r++;
+            }
+        else
+            for(x=0; x < columns; x++){
+                v=(*p);
+                if (v > (unsigned int) (*r+1))
+                    v--;
+                *q=v;
+                p++;
+                q++;
+                r++;
+            }
+        p++;
+        q++;
+        r++;
+    }
+    p=f+(columns+2);
+    q=g+(columns+2);
+    r=q+(y_offset*(columns+2)+x_offset);
+    s=q-(y_offset*(columns+2)+x_offset);
+    for(y=0; y < rows; y++){
+        p++;
+        q++;
+        r++;
+        s++;
+        if(polarity > 0)
+            for(x=0; x < (int) columns; x++){
+                v=(*q);
+                if (((unsigned int) (*s+1) > v) && (*r > v))
+                    v++;
+                *p=v;
+                p++;
+                q++;
+                r++;
+                s++;
+            }
+        else
+            for (x=0; x < columns; x++){
+                v=(*q);
+                if (((unsigned int) (*s+1) < v) && (*r < v))
+                    v--;
+                *p=v;
+                p++;
+                q++;
+                r++;
+                s++;
+            }
+        p++;
+        q++;
+        r++;
+        s++;
+    }
+}
+
+QImage KImageEffect::despeckle(QImage &src)
+{
+    int i, j, x, y;
+    unsigned int *blue_channel, *red_channel, *green_channel, *buffer,
+        *alpha_channel;
+    int packets;
+    static const int
+    X[4]= {0, 1, 1,-1},
+    Y[4]= {1, 0, 1, 1};
+
+    unsigned int *destData;
+    QImage dest(src.width(), src.height(), 32);
+
+    packets = (src.width()+2)*(src.height()+2);
+    red_channel = (unsigned int *)calloc(packets, sizeof(unsigned int));
+    green_channel = (unsigned int *)calloc(packets, sizeof(unsigned int));
+    blue_channel = (unsigned int *)calloc(packets, sizeof(unsigned int));
+    alpha_channel = (unsigned int *)calloc(packets, sizeof(unsigned int));
+    buffer = (unsigned int *)calloc(packets, sizeof(unsigned int));
+    if(!red_channel || ! green_channel || ! blue_channel || ! alpha_channel ||
+       !buffer){
+        free(red_channel);
+        free(green_channel);
+        free(blue_channel);
+        free(alpha_channel);
+        free(buffer);
+        return(src);
+    }
+
+    // copy image pixels to color component buffers
+    j = src.width()+2;
+    if(src.depth() > 8){ // DirectClass source image
+        unsigned int *srcData;
+        for(y=0; y < src.height(); ++y){
+            srcData = (unsigned int *)src.scanLine(y);
+            ++j;
+            for(x=0; x < src.width(); ++x){
+                red_channel[j] = qRed(srcData[x]);
+                green_channel[j] = qGreen(srcData[x]);
+                blue_channel[j] = qBlue(srcData[x]);
+                alpha_channel[j] = qAlpha(srcData[x]);
+                ++j;
+            }
+            ++j;
+        }
+    }
+    else{ // PsudeoClass source image
+        unsigned char *srcData;
+        unsigned int *cTable = src.colorTable();
+        unsigned int pixel;
+        for(y=0; y < src.height(); ++y){
+            srcData = (unsigned char *)src.scanLine(y);
+            ++j;
+            for(x=0; x < src.width(); ++x){
+                pixel = *(cTable+srcData[x]);
+                red_channel[j] = qRed(pixel);
+                green_channel[j] = qGreen(pixel);
+                blue_channel[j] = qBlue(pixel);
+                alpha_channel[j] = qAlpha(pixel);
+                ++j;
+            }
+            ++j;
+        }
+    }
+    // reduce speckle in red channel
+    for(i=0; i < 4; i++){
+        hull(X[i],Y[i],1,src.width(),src.height(),red_channel,buffer);
+        hull(-X[i],-Y[i],1,src.width(),src.height(),red_channel,buffer);
+        hull(-X[i],-Y[i],-1,src.width(),src.height(),red_channel,buffer);
+        hull(X[i],Y[i],-1,src.width(),src.height(),red_channel,buffer);
+    }
+    // reduce speckle in green channel
+    for (i=0; i < packets; i++)
+        buffer[i]=0;
+    for (i=0; i < 4; i++){
+        hull(X[i],Y[i],1,src.width(),src.height(),green_channel,buffer);
+        hull(-X[i],-Y[i],1,src.width(),src.height(),green_channel,buffer);
+        hull(-X[i],-Y[i],-1,src.width(),src.height(),green_channel,buffer);
+        hull(X[i],Y[i],-1,src.width(),src.height(),green_channel,buffer);
+    }
+    // reduce speckle in blue channel
+    for (i=0; i < packets; i++)
+        buffer[i]=0;
+    for (i=0; i < 4; i++){
+        hull(X[i],Y[i],1,src.width(),src.height(),blue_channel,buffer);
+        hull(-X[i],-Y[i],1,src.width(),src.height(),blue_channel,buffer);
+        hull(-X[i],-Y[i],-1,src.width(),src.height(),blue_channel,buffer);
+        hull(X[i],Y[i],-1,src.width(),src.height(),blue_channel,buffer);
+    }
+    // copy color component buffers to despeckled image
+    j = dest.width()+2;
+    for(y=0; y < dest.height(); ++y)
+    {
+        destData = (unsigned int *)dest.scanLine(y);
+        ++j;
+        for (x=0; x < dest.width(); ++x)
+        {
+            destData[x] = qRgba(red_channel[j], green_channel[j],
+                                blue_channel[j], alpha_channel[j]);
+            ++j;
+        }
+        ++j;
+    }
+    free(buffer);
+    free(red_channel);
+    free(green_channel);
+    free(blue_channel);
+    free(alpha_channel);
+    return(dest);
+}
+
+unsigned int KImageEffect::generateNoise(unsigned int pixel,
+                                         NoiseType noise_type)
+{
+#define NoiseEpsilon  1.0e-5
+#define NoiseMask  0x7fff
+#define SigmaUniform  4.0
+#define SigmaGaussian  4.0
+#define SigmaImpulse  0.10
+#define SigmaLaplacian 10.0
+#define SigmaMultiplicativeGaussian  0.5
+#define SigmaPoisson  0.05
+#define TauGaussian  20.0
+
+    double alpha, beta, sigma, value;
+    alpha=(double) (rand() & NoiseMask)/NoiseMask;
+    if (alpha == 0.0)
+        alpha=1.0;
+    switch(noise_type){
+    case UniformNoise:
+    default:
+        {
+            value=(double) pixel+SigmaUniform*(alpha-0.5);
+            break;
+        }
+    case GaussianNoise:
+        {
+            double tau;
+
+            beta=(double) (rand() & NoiseMask)/NoiseMask;
+            sigma=sqrt(-2.0*log(alpha))*cos(2.0*M_PI*beta);
+            tau=sqrt(-2.0*log(alpha))*sin(2.0*M_PI*beta);
+            value=(double) pixel+
+                (sqrt((double) pixel)*SigmaGaussian*sigma)+(TauGaussian*tau);
+            break;
+        }
+    case MultiplicativeGaussianNoise:
+        {
+            if (alpha <= NoiseEpsilon)
+                sigma=MaxRGB;
+            else
+                sigma=sqrt(-2.0*log(alpha));
+            beta=(rand() & NoiseMask)/NoiseMask;
+            value=(double) pixel+
+                pixel*SigmaMultiplicativeGaussian*sigma*cos(2.0*M_PI*beta);
+            break;
+        }
+    case ImpulseNoise:
+        {
+            if (alpha < (SigmaImpulse/2.0))
+                value=0;
+            else
+                if (alpha >= (1.0-(SigmaImpulse/2.0)))
+                    value=MaxRGB;
+                else
+                    value=pixel;
+            break;
+        }
+    case LaplacianNoise:
+        {
+            if (alpha <= 0.5)
+            {
+                if (alpha <= NoiseEpsilon)
+                    value=(double) pixel-MaxRGB;
+                else
+                    value=(double) pixel+SigmaLaplacian*log(2.0*alpha);
+                break;
+            }
+            beta=1.0-alpha;
+            if (beta <= (0.5*NoiseEpsilon))
+                value=(double) pixel+MaxRGB;
+            else
+                value=(double) pixel-SigmaLaplacian*log(2.0*beta);
+            break;
+        }
+    case PoissonNoise:
+        {
+            register int
+                i;
+
+            for (i=0; alpha > exp(-SigmaPoisson*pixel); i++)
+            {
+                beta=(double) (rand() & NoiseMask)/NoiseMask;
+                alpha=alpha*beta;
+            }
+            value=i/SigmaPoisson;
+            break;
+        }
+    }
+    if(value < 0.0)
+        return(0);
+    if(value > MaxRGB)
+        return(MaxRGB);
+    return((unsigned int) (value+0.5));
+}
+
+QImage KImageEffect::addNoise(QImage &src, NoiseType noise_type)
+{
+    int x, y;
+    QImage dest(src.width(), src.height(), 32);
+    unsigned int *destData;
+
+    if(src.depth() > 8){ // DirectClass source image
+        unsigned int *srcData;
+        for(y=0; y < src.height(); ++y){
+            srcData = (unsigned int *)src.scanLine(y);
+            destData = (unsigned int *)dest.scanLine(y);
+            for(x=0; x < src.width(); ++x){
+                destData[x] = qRgba(generateNoise(qRed(srcData[x]), noise_type),
+                                    generateNoise(qGreen(srcData[x]), noise_type),
+                                    generateNoise(qBlue(srcData[x]), noise_type),
+                                    qAlpha(srcData[x]));
+            }
+        }
+    }
+    else{ // PsudeoClass source image
+        unsigned char *srcData;
+        unsigned int *cTable = src.colorTable();
+        unsigned int pixel;
+        for(y=0; y < src.height(); ++y){
+            srcData = (unsigned char *)src.scanLine(y);
+            destData = (unsigned int *)dest.scanLine(y);
+            for(x=0; x < src.width(); ++x){
+                pixel = *(cTable+srcData[x]);
+                destData[x] = qRgba(generateNoise(qRed(pixel), noise_type),
+                                    generateNoise(qGreen(pixel), noise_type),
+                                    generateNoise(qBlue(pixel), noise_type),
+                                    qAlpha(pixel));
+            }
+        }
+
+    }
+    return(dest);
+}
+
+unsigned int KImageEffect::interpolateColor(QImage *image, double x_offset,
+                                            double y_offset,
+                                            unsigned int background)
+{
+    double alpha, beta;
+    unsigned int p, q, r, s;
+    int x, y;
+
+    x = (int)x_offset;
+    y = (int)y_offset;
+    if((x < -1) || (x >= image->width()) || (y < -1) || (y >= image->height()))
+        return(background);
+    if(image->depth() > 8){
+        if((x >= 0) && (y >= 0) && (x < (image->width()-1)) && (y < (image->height()-1)))    {
+            unsigned int *t = (unsigned int *)image->scanLine(y);
+            p = t[x];
+            q = t[x+1];
+            r = t[x+image->width()];
+            s = t[x+image->width()+1];
+        }
+        else{
+            unsigned int *t = (unsigned int *)image->scanLine(y);
+            p = background;
+            if((x >= 0) && (y >= 0)){
+                p = t[x];
+            }
+            q = background;
+            if(((x+1) < image->width()) && (y >= 0)){
+                q = t[x+1];
+            }
+            r = background;
+            if((x >= 0) && ((y+1) < image->height())){
+                t = (unsigned int *)image->scanLine(y+1);
+                r = t[x+image->width()];
+            }
+            s = background;
+            if(((x+1) < image->width()) && ((y+1) < image->height())){
+                t = (unsigned int *)image->scanLine(y+1);
+                s = t[x+image->width()+1];
+            }
+
+        }
+    }
+    else{
+        unsigned int *colorTable = (unsigned int *)image->colorTable();
+        if((x >= 0) && (y >= 0) && (x < (image->width()-1)) && (y < (image->height()-1)))    {
+            unsigned char *t;
+            t = (unsigned char *)image->scanLine(y);
+            p = *(colorTable+t[x]);
+            q = *(colorTable+t[x+1]);
+            t = (unsigned char *)image->scanLine(y+1);
+            r = *(colorTable+t[x]);
+            s = *(colorTable+t[x+1]);
+        }
+        else{
+            unsigned char *t;
+            p = background;
+            if((x >= 0) && (y >= 0)){
+                t = (unsigned char *)image->scanLine(y);
+                p = *(colorTable+t[x]);
+            }
+            q = background;
+            if(((x+1) < image->width()) && (y >= 0)){
+                t = (unsigned char *)image->scanLine(y);
+                q = *(colorTable+t[x+1]);
+            }
+            r = background;
+            if((x >= 0) && ((y+1) < image->height())){
+                t = (unsigned char *)image->scanLine(y+1);
+                r = *(colorTable+t[x]);
+            }
+            s = background;
+            if(((x+1) < image->width()) && ((y+1) < image->height())){
+                t = (unsigned char *)image->scanLine(y+1);
+                s = *(colorTable+t[x+1]);
+            }
+
+        }
+
+    }
+    x_offset -= floor(x_offset);
+    y_offset -= floor(y_offset);
+    alpha = 1.0-x_offset;
+    beta = 1.0-y_offset;
+
+    return(qRgba((unsigned char)(beta*(alpha*qRed(p)+x_offset*qRed(q))+y_offset*(alpha*qRed(r)+x_offset*qRed(s))),
+                 (unsigned char)(beta*(alpha*qGreen(p)+x_offset*qGreen(q))+y_offset*(alpha*qGreen(r)+x_offset*qGreen(s))),
+                 (unsigned char)(beta*(alpha*qBlue(p)+x_offset*qBlue(q))+y_offset*(alpha*qBlue(r)+x_offset*qBlue(s))),
+                 (unsigned char)(beta*(alpha*qAlpha(p)+x_offset*qAlpha(q))+y_offset*(alpha*qAlpha(r)+x_offset*qAlpha(s)))));
+}
+
+QImage KImageEffect::implode(QImage &src, double factor,
+                             unsigned int background)
+{
+    double amount, distance, radius;
+    double x_center, x_distance, x_scale;
+    double y_center, y_distance, y_scale;
+    unsigned int *destData;
+    int x, y;
+
+    QImage dest(src.width(), src.height(), 32);
+
+    // compute scaling factor
+    x_scale = 1.0;
+    y_scale = 1.0;
+    x_center = (double)0.5*src.width();
+    y_center = (double)0.5*src.height();
+    radius=x_center;
+    if(src.width() > src.height())
+        y_scale = (double)src.width()/src.height();
+    else if(src.width() < src.height()){
+        x_scale = (double) src.height()/src.width();
+        radius = y_center;
+    }
+    amount=factor/10.0;
+    if(amount >= 0)
+        amount/=10.0;
+    if(src.depth() > 8){ // DirectClass source image
+        unsigned int *srcData;
+        for(y=0; y < src.height(); ++y){
+            srcData = (unsigned int *)src.scanLine(y);
+            destData = (unsigned int *)dest.scanLine(y);
+            y_distance=y_scale*(y-y_center);
+            for(x=0; x < src.width(); ++x){
+                destData[x] = srcData[x];
+                x_distance = x_scale*(x-x_center);
+                distance= x_distance*x_distance+y_distance*y_distance;
+                if(distance < (radius*radius)){
+                    double factor;
+                    // Implode the pixel.
+                    factor=1.0;
+                    if(distance > 0.0)
+                        factor=
+                            pow(sin(0.5000000000000001*M_PI*sqrt(distance)/radius),-amount);
+                    destData[x] = interpolateColor(&src, factor*x_distance/x_scale+x_center,
+                                                   factor*y_distance/y_scale+y_center,
+                                                   background);
+                }
+            }
+        }
+    }
+    else{ // PsudeoClass source image
+        unsigned char *srcData;
+        unsigned char idx;
+        unsigned int *cTable = src.colorTable();
+        for(y=0; y < src.height(); ++y){
+            srcData = (unsigned char *)src.scanLine(y);
+            destData = (unsigned int *)dest.scanLine(y);
+            y_distance=y_scale*(y-y_center);
+            for(x=0; x < src.width(); ++x){
+                idx = srcData[x];
+                destData[x] = cTable[idx];
+                x_distance = x_scale*(x-x_center);
+                distance= x_distance*x_distance+y_distance*y_distance;
+                if(distance < (radius*radius)){
+                    double factor;
+                    // Implode the pixel.
+                    factor=1.0;
+                    if(distance > 0.0)
+                        factor=
+                            pow(sin(0.5000000000000001*M_PI*sqrt(distance)/radius),-amount);
+                    destData[x] = interpolateColor(&src, factor*x_distance/x_scale+x_center,
+                                                   factor*y_distance/y_scale+y_center,
+                                                   background);
+                }
+            }
+        }
+
+    }
+    return(dest);
+}
+
+QImage KImageEffect::rotate(QImage &img, RotateDirection r)
+{
+    QImage dest;
+    int x, y;
+    if(img.depth() > 8){
+        unsigned int *srcData, *destData;
+        switch(r){
+        case Rotate90:
+            dest.create(img.height(), img.width(), img.depth());
+            for(y=0; y < img.height(); ++y){
+                srcData = (unsigned int *)img.scanLine(y);
+                for(x=0; x < img.width(); ++x){
+                    destData = (unsigned int *)dest.scanLine(x);
+                    destData[img.height()-y-1] = srcData[x];
+                }
+            }
+            break;
+        case Rotate180:
+            dest.create(img.width(), img.height(), img.depth());
+            for(y=0; y < img.height(); ++y){
+                srcData = (unsigned int *)img.scanLine(y);
+                destData = (unsigned int *)dest.scanLine(img.height()-y-1);
+                for(x=0; x < img.width(); ++x)
+                    destData[img.width()-x-1] = srcData[x];
+            }
+            break;
+        case Rotate270:
+            dest.create(img.height(), img.width(), img.depth());
+            for(y=0; y < img.height(); ++y){
+                srcData = (unsigned int *)img.scanLine(y);
+                for(x=0; x < img.width(); ++x){
+                    destData = (unsigned int *)dest.scanLine(img.width()-x-1);
+                    destData[y] = srcData[x];
+                }
+            }
+            break;
+        default:
+            dest = img;
+            break;
+        }
+    }
+    else{
+        unsigned char *srcData, *destData;
+        unsigned int *srcTable, *destTable;
+        switch(r){
+        case Rotate90:
+            dest.create(img.height(), img.width(), img.depth());
+            dest.setNumColors(img.numColors());
+            srcTable = (unsigned int *)img.colorTable();
+            destTable = (unsigned int *)dest.colorTable();
+            for(x=0; x < img.numColors(); ++x)
+                destTable[x] = srcTable[x];
+            for(y=0; y < img.height(); ++y){
+                srcData = (unsigned char *)img.scanLine(y);
+                for(x=0; x < img.width(); ++x){
+                    destData = (unsigned char *)dest.scanLine(x);
+                    destData[img.height()-y-1] = srcData[x];
+                }
+            }
+            break;
+        case Rotate180:
+            dest.create(img.width(), img.height(), img.depth());
+            dest.setNumColors(img.numColors());
+            srcTable = (unsigned int *)img.colorTable();
+            destTable = (unsigned int *)dest.colorTable();
+            for(x=0; x < img.numColors(); ++x)
+                destTable[x] = srcTable[x];
+            for(y=0; y < img.height(); ++y){
+                srcData = (unsigned char *)img.scanLine(y);
+                destData = (unsigned char *)dest.scanLine(img.height()-y-1);
+                for(x=0; x < img.width(); ++x)
+                    destData[img.width()-x-1] = srcData[x];
+            }
+            break;
+        case Rotate270:
+            dest.create(img.height(), img.width(), img.depth());
+            dest.setNumColors(img.numColors());
+            srcTable = (unsigned int *)img.colorTable();
+            destTable = (unsigned int *)dest.colorTable();
+            for(x=0; x < img.numColors(); ++x)
+                destTable[x] = srcTable[x];
+            for(y=0; y < img.height(); ++y){
+                srcData = (unsigned char *)img.scanLine(y);
+                for(x=0; x < img.width(); ++x){
+                    destData = (unsigned char *)dest.scanLine(img.width()-x-1);
+                    destData[y] = srcData[x];
+                }
+            }
+            break;
+        default:
+            dest = img;
+            break;
+        }
+
+    }
+    return(dest);
+}
+
+void KImageEffect::solarize(QImage &img, double factor)
+{
+    int i, count;
+    int threshold;
+    unsigned int *data;
+
+    threshold = (int)(factor*(MaxRGB+1)/100.0);
+    if(img.depth() < 32){
+        data = (unsigned int *)img.colorTable();
+        count = img.numColors();
+    }
+    else{
+        data = (unsigned int *)img.bits();
+        count = img.width()*img.height();
+    }
+    for(i=0; i < count; ++i){
+        data[i] = qRgba(qRed(data[i]) > threshold ? MaxRGB-qRed(data[i]) : qRed(data[i]),
+                        qGreen(data[i]) > threshold ? MaxRGB-qGreen(data[i]) : qGreen(data[i]),
+                        qBlue(data[i]) > threshold ? MaxRGB-qBlue(data[i]) : qBlue(data[i]),
+                        qAlpha(data[i]));
+    }
+}
+
+QImage KImageEffect::spread(QImage &src, unsigned int amount)
+{
+    int quantum, x, y;
+    int x_distance, y_distance;
+    if(src.width() < 3 || src.height() < 3)
+        return(src);
+    QImage dest(src);
+    dest.detach();
+    quantum=(amount+1) >> 1;
+    if(src.depth() > 8){ // DirectClass source image
+        unsigned int *p, *q;
+        for(y=0; y < src.height(); y++){
+            q = (unsigned int *)dest.scanLine(y);
+            for(x=0; x < src.width(); x++){
+                x_distance = x + ((rand() & (amount+1))-quantum);
+                y_distance = y + ((rand() & (amount+1))-quantum);
+                x_distance = QMIN(x_distance, src.width()-1);
+                y_distance = QMIN(y_distance, src.height()-1);
+                if(x_distance < 0)
+                    x_distance = 0;
+                if(y_distance < 0)
+                    y_distance = 0;
+                p = (unsigned int *)src.scanLine(y_distance);
+                p += x_distance;
+                *q++=(*p);
+            }
+        }
+    }
+    else{ // PsudeoClass source image
+        // just do colortable values
+        unsigned char *p, *q;
+        for(y=0; y < src.height(); y++){
+            q = (unsigned char *)dest.scanLine(y);
+            for(x=0; x < src.width(); x++){
+                x_distance = x + ((rand() & (amount+1))-quantum);
+                y_distance = y + ((rand() & (amount+1))-quantum);
+                x_distance = QMIN(x_distance, src.width()-1);
+                y_distance = QMIN(y_distance, src.height()-1);
+                if(x_distance < 0)
+                    x_distance = 0;
+                if(y_distance < 0)
+                    y_distance = 0;
+                p = (unsigned char *)src.scanLine(y_distance);
+                p += x_distance;
+                *q++=(*p);
+            }
+        }
+    }
+    return(dest);
+}
+
+QImage KImageEffect::swirl(QImage &src, double degrees,
+                           unsigned int background)
+{
+    double cosine, distance, factor, radius, sine, x_center, x_distance,
+        x_scale, y_center, y_distance, y_scale;
+    int x, y;
+    unsigned int *q;
+    QImage dest(src.width(), src.height(), 32);
+
+    // compute scaling factor
+    x_center = src.width()/2.0;
+    y_center = src.height()/2.0;
+    radius = QMAX(x_center,y_center);
+    x_scale=1.0;
+    y_scale=1.0;
+    if(src.width() > src.height())
+        y_scale=(double)src.width()/src.height();
+    else if(src.width() < src.height())
+        x_scale=(double)src.height()/src.width();
+    degrees=DegreesToRadians(degrees);
+    // swirl each row
+    if(src.depth() > 8){ // DirectClass source image
+        unsigned int *p;
+        for(y=0; y < src.height(); y++){
+            p = (unsigned int *)src.scanLine(y);
+            q = (unsigned int *)dest.scanLine(y);
+            y_distance = y_scale*(y-y_center);
+            for(x=0; x < src.width(); x++){
+                // determine if the pixel is within an ellipse
+                *q=(*p);
+                x_distance = x_scale*(x-x_center);
+                distance = x_distance*x_distance+y_distance*y_distance;
+                if (distance < (radius*radius)){
+                    // swirl
+                    factor = 1.0-sqrt(distance)/radius;
+                    sine = sin(degrees*factor*factor);
+                    cosine = cos(degrees*factor*factor);
+                    *q = interpolateColor(&src,
+                                          (cosine*x_distance-sine*y_distance)/x_scale+x_center,
+                                          (sine*x_distance+cosine*y_distance)/y_scale+y_center,
+                                          background);
+                }
+                p++;
+                q++;
+            }
+        }
+    }
+    else{ // PsudeoClass source image
+        unsigned char *p;
+        unsigned int *cTable = (unsigned int *)src.colorTable();
+        for(y=0; y < src.height(); y++){
+            p = (unsigned char *)src.scanLine(y);
+            q = (unsigned int *)dest.scanLine(y);
+            y_distance = y_scale*(y-y_center);
+            for(x=0; x < src.width(); x++){
+                // determine if the pixel is within an ellipse
+                *q = *(cTable+(*p));
+                x_distance = x_scale*(x-x_center);
+                distance = x_distance*x_distance+y_distance*y_distance;
+                if (distance < (radius*radius)){
+                    // swirl
+                    factor = 1.0-sqrt(distance)/radius;
+                    sine = sin(degrees*factor*factor);
+                    cosine = cos(degrees*factor*factor);
+                    *q = interpolateColor(&src,
+                                          (cosine*x_distance-sine*y_distance)/x_scale+x_center,
+                                          (sine*x_distance+cosine*y_distance)/y_scale+y_center,
+                                          background);
+                }
+                p++;
+                q++;
+            }
+        }
+
+    }
+    return(dest);
+}
+
+QImage KImageEffect::wave(QImage &src, double amplitude, double wavelength,
+                          unsigned int background)
+{
+    double *sine_map;
+    int x, y;
+    unsigned int *q;
+
+    QImage dest(src.width(), src.height() + (int)(2*fabs(amplitude)), 32);
+    // allocate sine map
+    sine_map = (double *)malloc(dest.width()*sizeof(double));
+    if(!sine_map)
+        return(src);
+    for(x=0; x < dest.width(); ++x)
+        sine_map[x]=fabs(amplitude)+amplitude*sin((2*M_PI*x)/wavelength);
+    // wave image
+    for(y=0; y < dest.height(); ++y){
+        q = (unsigned int *)dest.scanLine(y);
+        for (x=0; x < dest.width(); x++){
+            *q=interpolateColor(&src, x, (int)(y-sine_map[x]), background);
+            ++q;
+        }
+    }
+    free(sine_map);
+    return(dest);
+}
+
+//
+// The following methods work by computing a value from neighboring pixels
+// (mosfet 05/26/03)
+//
+
+// New algorithms based on ImageMagick 5.5.6 (05/26/03)
+
+QImage KImageEffect::oilPaint(QImage &src, int /*radius*/)
+{
+    /* binary compat method - remove me when possible! */
+    return(oilPaintConvolve(src, 0));
+}
+
+QImage KImageEffect::oilPaintConvolve(QImage &src, double radius)
+{
+    unsigned long count /*,*histogram*/;
+    unsigned long histogram[256];
+    unsigned int k;
+    int width;
+    int x, y, mx, my, sx, sy;
+    int mcx, mcy;
+    unsigned int *s=0, *q;
+
+    if(src.depth() < 32)
+        src.convertDepth(32);
+    QImage dest(src);
+    dest.detach();
+
+    width = getOptimalKernelWidth(radius, 0.5);
+    if(src.width() < width){
+        qWarning("KImageEffect::oilPaintConvolve(): Image is smaller than radius!");
+        return(dest);
+    }
+    /*
+    histogram = (unsigned long *)malloc(256*sizeof(unsigned long));
+    if(!histogram){
+        qWarning("KImageEffect::oilPaintColvolve(): Unable to allocate memory!");
+        return(dest);
+    }
+    */
+    unsigned int **jumpTable = (unsigned int **)src.jumpTable();
+    for(y=0; y < dest.height(); ++y){
+        sy = y-(width/2);
+        q = (unsigned int *)dest.scanLine(y);
+        for(x=0; x < dest.width(); ++x){
+            count = 0;
+            memset(histogram, 0, 256*sizeof(unsigned long));
+            //memset(histogram, 0, 256);
+            sy = y-(width/2);
+            for(mcy=0; mcy < width; ++mcy, ++sy){
+                my = sy < 0 ? 0 : sy > src.height()-1 ?
+                    src.height()-1 : sy;
+                sx = x+(-width/2);
+                for(mcx=0; mcx < width; ++mcx, ++sx){
+                    mx = sx < 0 ? 0 : sx > src.width()-1 ?
+                        src.width()-1 : sx;
+
+                    k = intensityValue(jumpTable[my][mx]);
+                    if(k > 255){
+                        qWarning("KImageEffect::oilPaintConvolve(): k is %d",
+                                 k);
+                        k = 255;
+                    }
+                    histogram[k]++;
+                    if(histogram[k] > count){
+                        count = histogram[k];
+                        s = jumpTable[my]+mx;
+                    }
+                }
+            }
+            if (s)
+                *q++ = (*s);
+        }
+    }
+    /* liberateMemory((histogram); */
+    return(dest);
+}
+
+QImage KImageEffect::charcoal(QImage &src, double /*factor*/)
+{
+    /* binary compat method - remove me when possible! */
+    return(charcoal(src, 0, 1));
+}
+
+QImage KImageEffect::charcoal(QImage &src, double radius, double sigma)
+{
+    QImage img(edge(src, radius));
+    img = blur(img, radius, sigma);
+    normalize(img);
+    img.invertPixels(false);
+    KImageEffect::toGray(img);
+    return(img);
+}
+
+void KImageEffect::normalize(QImage &image)
+{
+    struct double_packet high, low, intensity, *histogram;
+    struct short_packet *normalize_map;
+    Q_INT64 number_pixels;
+    int x, y;
+    unsigned int *p, *q;
+    register long i;
+    unsigned long threshold_intensity;
+    unsigned char r, g, b, a;
+
+    if(image.depth() < 32) // result will always be 32bpp
+        image = image.convertDepth(32);
+
+    histogram = (struct double_packet *)
+        malloc(256*sizeof(struct double_packet));
+    normalize_map = (struct short_packet *)
+        malloc(256*sizeof(struct short_packet));
+
+    if(!histogram || !normalize_map){
+        if(histogram)
+            liberateMemory(&histogram);
+        if(normalize_map)
+            liberateMemory(&normalize_map);
+        qWarning("KImageEffect::normalize(): Unable to allocate memory!");
+        return;
+    }
+
+    /*
+    Form histogram.
+    */
+    memset(histogram, 0, 256*sizeof(struct double_packet));
+    for(y=0; y < image.height(); ++y){
+        p = (unsigned int *)image.scanLine(y);
+        for(x=0; x < image.width(); ++x){
+            histogram[(unsigned char)(qRed(*p))].red++;
+            histogram[(unsigned char)(qGreen(*p))].green++;
+            histogram[(unsigned char)(qBlue(*p))].blue++;
+            histogram[(unsigned char)(qAlpha(*p))].alpha++;
+            p++;
+        }
+    }
+
+    /*
+    Find the histogram boundaries by locating the 0.1 percent levels.
+    */
+    number_pixels = (Q_INT64)image.width()*image.height();
+    threshold_intensity = number_pixels/1000;
+
+    /* red */
+    memset(&intensity, 0, sizeof(struct double_packet));
+    memset(&high, 0, sizeof(struct double_packet));
+    memset(&low, 0, sizeof(struct double_packet));
+    for(high.red=255; high.red != 0; high.red--){
+        intensity.red+=histogram[(unsigned char)high.red].red;
+        if(intensity.red > threshold_intensity)
+            break;
+    }
+    if(low.red == high.red){
+        threshold_intensity = 0;
+        memset(&intensity, 0, sizeof(struct double_packet));
+        for(low.red=0; low.red < 255; low.red++){
+            intensity.red+=histogram[(unsigned char)low.red].red;
+            if(intensity.red > threshold_intensity)
+                break;
+        }
+        memset(&intensity, 0, sizeof(struct double_packet));
+        for(high.red=255; high.red != 0; high.red--){
+            intensity.red+=histogram[(unsigned char)high.red].red;
+            if(intensity.red > threshold_intensity)
+                break;
+        }
+    }
+
+    /* green */
+    memset(&intensity, 0, sizeof(struct double_packet));
+    for(high.green=255; high.green != 0; high.green--){
+        intensity.green+=histogram[(unsigned char)high.green].green;
+        if(intensity.green > threshold_intensity)
+            break;
+    }
+    if(low.green == high.green){
+        threshold_intensity = 0;
+        memset(&intensity, 0, sizeof(struct double_packet));
+        for(low.green=0; low.green < 255; low.green++){
+            intensity.green+=histogram[(unsigned char)low.green].green;
+            if(intensity.green > threshold_intensity)
+                break;
+        }
+        memset(&intensity,0,sizeof(struct double_packet));
+        for(high.green=255; high.green != 0; high.green--){
+            intensity.green+=histogram[(unsigned char)high.green].green;
+            if(intensity.green > threshold_intensity)
+                break;
+        }
+    }
+
+    /* blue */
+    memset(&intensity, 0, sizeof(struct double_packet));
+    for(high.blue=255; high.blue != 0; high.blue--){
+        intensity.blue+=histogram[(unsigned char)high.blue].blue;
+        if(intensity.blue > threshold_intensity)
+            break;
+    }
+    if(low.blue == high.blue){
+        threshold_intensity = 0;
+        memset(&intensity, 0, sizeof(struct double_packet));
+        for(low.blue=0; low.blue < 255; low.blue++){
+            intensity.blue+=histogram[(unsigned char)low.blue].blue;
+            if(intensity.blue > threshold_intensity)
+                break;
+        }
+        memset(&intensity,0,sizeof(struct double_packet));
+        for(high.blue=255; high.blue != 0; high.blue--){
+            intensity.blue+=histogram[(unsigned char)high.blue].blue;
+            if(intensity.blue > threshold_intensity)
+                break;
+        }
+    }
+
+    /* alpha */
+    memset(&intensity, 0, sizeof(struct double_packet));
+    for(high.alpha=255; high.alpha != 0; high.alpha--){
+        intensity.alpha+=histogram[(unsigned char)high.alpha].alpha;
+        if(intensity.alpha > threshold_intensity)
+            break;
+    }
+    if(low.alpha == high.alpha){
+        threshold_intensity = 0;
+        memset(&intensity, 0, sizeof(struct double_packet));
+        for(low.alpha=0; low.alpha < 255; low.alpha++){
+            intensity.alpha+=histogram[(unsigned char)low.alpha].alpha;
+            if(intensity.alpha > threshold_intensity)
+                break;
+        }
+        memset(&intensity,0,sizeof(struct double_packet));
+        for(high.alpha=255; high.alpha != 0; high.alpha--){
+            intensity.alpha+=histogram[(unsigned char)high.alpha].alpha;
+            if(intensity.alpha > threshold_intensity)
+                break;
+        }
+    }
+    liberateMemory(&histogram);
+
+    /*
+     Stretch the histogram to create the normalized image mapping.
+     */
+
+    // should the maxes be 65535?
+    memset(normalize_map, 0 ,256*sizeof(struct short_packet));
+    for(i=0; i <= (long) 255; i++){
+        if(i < (long) low.red)
+            normalize_map[i].red=0;
+        else if (i > (long) high.red)
+            normalize_map[i].red=65535;
+        else if (low.red != high.red)
+            normalize_map[i].red =
+                (unsigned short)((65535*(i-low.red))/(high.red-low.red));
+
+        if(i < (long) low.green)
+            normalize_map[i].green=0;
+        else if (i > (long) high.green)
+            normalize_map[i].green=65535;
+        else if (low.green != high.green)
+            normalize_map[i].green =
+                (unsigned short)((65535*(i-low.green))/(high.green-low.green));
+
+        if(i < (long) low.blue)
+            normalize_map[i].blue=0;
+        else if (i > (long) high.blue)
+            normalize_map[i].blue=65535;
+        else if (low.blue != high.blue)
+            normalize_map[i].blue =
+                (unsigned short)((65535*(i-low.blue))/(high.blue-low.blue));
+
+        if(i < (long) low.alpha)
+            normalize_map[i].alpha=0;
+        else if (i > (long) high.alpha)
+            normalize_map[i].alpha=65535;
+        else if (low.alpha != high.alpha)
+            normalize_map[i].alpha =
+                (unsigned short)((65535*(i-low.alpha))/(high.alpha-low.alpha));
+
+    }
+
+    for(y=0; y < image.height(); ++y){
+        q = (unsigned int *)image.scanLine(y);
+        for(x=0; x < image.width(); ++x){
+            if(low.red != high.red)
+                r = (normalize_map[(unsigned short)(qRed(q[x]))].red)/257;
+            else
+                r = qRed(q[x]);
+            if(low.green != high.green)
+                g = (normalize_map[(unsigned short)(qGreen(q[x]))].green)/257;
+            else
+                g = qGreen(q[x]);
+            if(low.blue != high.blue)
+                b = (normalize_map[(unsigned short)(qBlue(q[x]))].blue)/257;
+            else
+                b = qBlue(q[x]);
+            if(low.alpha != high.alpha)
+                a = (normalize_map[(unsigned short)(qAlpha(q[x]))].alpha)/257;
+            else
+                a = qAlpha(q[x]);
+            q[x] = qRgba(r, g, b, a);
+        }
+    }
+    liberateMemory(&normalize_map);
+}
+
+void KImageEffect::equalize(QImage &image)
+{
+    struct double_packet high, low, intensity, *map, *histogram;
+    struct short_packet *equalize_map;
+    int x, y;
+    unsigned int *p, *q;
+    long i;
+    unsigned char r, g, b, a;
+
+    if(image.depth() < 32) // result will always be 32bpp
+        image = image.convertDepth(32);
+
+    histogram=(struct double_packet *) malloc(256*sizeof(struct double_packet));
+    map=(struct double_packet *) malloc(256*sizeof(struct double_packet));
+    equalize_map=(struct short_packet *)malloc(256*sizeof(struct short_packet));
+    if(!histogram || !map || !equalize_map){
+        if(histogram)
+            liberateMemory(&histogram);
+        if(map)
+            liberateMemory(&map);
+        if(equalize_map)
+            liberateMemory(&equalize_map);
+        qWarning("KImageEffect::equalize(): Unable to allocate memory!");
+        return;
+    }
+
+    /*
+    Form histogram.
+    */
+    memset(histogram, 0, 256*sizeof(struct double_packet));
+    for(y=0; y < image.height(); ++y){
+        p = (unsigned int *)image.scanLine(y);
+        for(x=0; x < image.width(); ++x){
+            histogram[(unsigned char)(qRed(*p))].red++;
+            histogram[(unsigned char)(qGreen(*p))].green++;
+            histogram[(unsigned char)(qBlue(*p))].blue++;
+            histogram[(unsigned char)(qAlpha(*p))].alpha++;
+            p++;
+        }
+    }
+    /*
+     Integrate the histogram to get the equalization map.
+     */
+    memset(&intensity, 0 ,sizeof(struct double_packet));
+    for(i=0; i <= 255; ++i){
+        intensity.red += histogram[i].red;
+        intensity.green += histogram[i].green;
+        intensity.blue += histogram[i].blue;
+        intensity.alpha += histogram[i].alpha;
+        map[i]=intensity;
+    }
+    low=map[0];
+    high=map[255];
+    memset(equalize_map, 0, 256*sizeof(short_packet));
+    for(i=0; i <= 255; ++i){
+        if(high.red != low.red)
+            equalize_map[i].red=(unsigned short)
+                ((65535*(map[i].red-low.red))/(high.red-low.red));
+        if(high.green != low.green)
+            equalize_map[i].green=(unsigned short)
+                ((65535*(map[i].green-low.green))/(high.green-low.green));
+        if(high.blue != low.blue)
+            equalize_map[i].blue=(unsigned short)
+                ((65535*(map[i].blue-low.blue))/(high.blue-low.blue));
+        if(high.alpha != low.alpha)
+            equalize_map[i].alpha=(unsigned short)
+                ((65535*(map[i].alpha-low.alpha))/(high.alpha-low.alpha));
+    }
+    liberateMemory(&histogram);
+    liberateMemory(&map);
+
+    /*
+     Stretch the histogram.
+     */
+    for(y=0; y < image.height(); ++y){
+        q = (unsigned int *)image.scanLine(y);
+        for(x=0; x < image.width(); ++x){
+            if(low.red != high.red)
+                r = (equalize_map[(unsigned short)(qRed(q[x]))].red/257);
+            else
+                r = qRed(q[x]);
+            if(low.green != high.green)
+                g = (equalize_map[(unsigned short)(qGreen(q[x]))].green/257);
+            else
+                g = qGreen(q[x]);
+            if(low.blue != high.blue)
+                b = (equalize_map[(unsigned short)(qBlue(q[x]))].blue/257);
+            else
+                b = qBlue(q[x]);
+            if(low.alpha != high.alpha)
+                a = (equalize_map[(unsigned short)(qAlpha(q[x]))].alpha/257);
+            else
+                a = qAlpha(q[x]);
+            q[x] = qRgba(r, g, b, a);
+        }
+    }
+    liberateMemory(&equalize_map);
+
+}
+
+QImage KImageEffect::edge(QImage &image, double radius)
+{
+    double *kernel;
+    int width;
+    register long i;
+    QImage dest;
+
+    if(radius == 50.0){
+        /* For binary compatability! Remove me when possible! This used to
+         * take a different parameter, a factor, and this was the default
+         * value */
+        radius = 0.0;
+    }
+
+    width = getOptimalKernelWidth(radius, 0.5);
+    if(image.width() < width || image.height() < width){
+        qWarning("KImageEffect::edge(): Image is smaller than radius!");
+        return(dest);
+    }
+    kernel= (double *)malloc(width*width*sizeof(double));
+    if(!kernel){
+        qWarning("KImageEffect::edge(): Unable to allocate memory!");
+        return(dest);
+    }
+    for(i=0; i < (width*width); i++)
+        kernel[i]=(-1.0);
+    kernel[i/2]=width*width-1.0;
+    convolveImage(&image, &dest, width, kernel);
+    free(kernel);
+    return(dest);
+}
+
+QImage KImageEffect::emboss(QImage &src)
+{
+    /* binary compat method - remove me when possible! */
+    return(emboss(src, 0, 1));
+}
+
+QImage KImageEffect::emboss(QImage &image, double radius, double sigma)
+{
+    double alpha, *kernel;
+    int j, width;
+    register long i, u, v;
+    QImage dest;
+
+    if(sigma == 0.0){
+        qWarning("KImageEffect::emboss(): Zero sigma is not permitted!");
+        return(dest);
+    }
+
+    width = getOptimalKernelWidth(radius, sigma);
+    if(image.width() < width || image.height() < width){
+        qWarning("KImageEffect::emboss(): Image is smaller than radius!");
+        return(dest);
+    }
+    kernel= (double *)malloc(width*width*sizeof(double));
+    if(!kernel){
+        qWarning("KImageEffect::emboss(): Unable to allocate memory!");
+        return(dest);
+    }
+    if(image.depth() < 32)
+        image = image.convertDepth(32);
+
+    i=0;
+    j=width/2;
+    for(v=(-width/2); v <= (width/2); v++){
+        for(u=(-width/2); u <= (width/2); u++){
+            alpha=exp(-((double) u*u+v*v)/(2.0*sigma*sigma));
+            kernel[i]=((u < 0) || (v < 0) ? -8.0 : 8.0)*alpha/
+                (2.0*MagickPI*sigma*sigma);
+            if (u == j)
+                kernel[i]=0.0;
+            i++;
+        }
+        j--;
+    }
+    convolveImage(&image, &dest, width, kernel);
+    liberateMemory(&kernel);
+
+    equalize(dest);
+    return(dest);
+}
+
+void KImageEffect::blurScanLine(double *kernel, int width,
+                                unsigned int *src, unsigned int *dest,
+                                int columns)
+{
+    register double *p;
+    unsigned int *q;
+    register int x;
+    register long i;
+    double red, green, blue, alpha;
+    double scale = 0.0;
+
+    if(width > columns){
+        for(x=0; x < columns; ++x){
+            scale = 0.0;
+            red = blue = green = alpha = 0.0;
+            p = kernel;
+            q = src;
+            for(i=0; i < columns; ++i){
+                if((i >= (x-width/2)) && (i <= (x+width/2))){
+                    red += (*p)*(qRed(*q)*257);
+                    green += (*p)*(qGreen(*q)*257);
+                    blue += (*p)*(qBlue(*q)*257);
+                    alpha += (*p)*(qAlpha(*q)*257);
+                }
+                if(((i+width/2-x) >= 0) && ((i+width/2-x) < width))
+                    scale+=kernel[i+width/2-x];
+                p++;
+                q++;
+            }
+            scale = 1.0/scale;
+            red = scale*(red+0.5);
+            green = scale*(green+0.5);
+            blue = scale*(blue+0.5);
+            alpha = scale*(alpha+0.5);
+
+            red = red < 0 ? 0 : red > 65535 ? 65535 : red;
+            green = green < 0 ? 0 : green > 65535 ? 65535 : green;
+            blue = blue < 0 ? 0 : blue > 65535 ? 65535 : blue;
+            alpha = alpha < 0 ? 0 : alpha > 65535 ? 65535 : alpha;
+
+            dest[x] = qRgba((unsigned char)(red/257UL),
+                            (unsigned char)(green/257UL),
+                            (unsigned char)(blue/257UL),
+                            (unsigned char)(alpha/257UL));
+        }
+        return;
+    }
+
+    for(x=0; x < width/2; ++x){
+        scale = 0.0;
+        red = blue = green = alpha = 0.0;
+        p = kernel+width/2-x;
+        q = src;
+        for(i=width/2-x; i < width; ++i){
+            red += (*p)*(qRed(*q)*257);
+            green += (*p)*(qGreen(*q)*257);
+            blue += (*p)*(qBlue(*q)*257);
+            alpha += (*p)*(qAlpha(*q)*257);
+            scale += (*p);
+            p++;
+            q++;
+        }
+        scale=1.0/scale;
+
+        red = scale*(red+0.5);
+        green = scale*(green+0.5);
+        blue = scale*(blue+0.5);
+        alpha = scale*(alpha+0.5);
+
+        red = red < 0 ? 0 : red > 65535 ? 65535 : red;
+        green = green < 0 ? 0 : green > 65535 ? 65535 : green;
+        blue = blue < 0 ? 0 : blue > 65535 ? 65535 : blue;
+        alpha = alpha < 0 ? 0 : alpha > 65535 ? 65535 : alpha;
+
+        dest[x] = qRgba((unsigned char)(red/257UL),
+                        (unsigned char)(green/257UL),
+                        (unsigned char)(blue/257UL),
+                        (unsigned char)(alpha/257UL));
+    }
+
+    for(; x < columns-width/2; ++x){
+        red = blue = green = alpha = 0.0;
+        p = kernel;
+        q = src+(x-width/2);
+        for (i=0; i < (long) width; ++i){
+            red += (*p)*(qRed(*q)*257);
+            green += (*p)*(qGreen(*q)*257);
+            blue += (*p)*(qBlue(*q)*257);
+            alpha += (*p)*(qAlpha(*q)*257);
+            p++;
+            q++;
+        }
+        red = scale*(red+0.5);
+        green = scale*(green+0.5);
+        blue = scale*(blue+0.5);
+        alpha = scale*(alpha+0.5);
+
+        red = red < 0 ? 0 : red > 65535 ? 65535 : red;
+        green = green < 0 ? 0 : green > 65535 ? 65535 : green;
+        blue = blue < 0 ? 0 : blue > 65535 ? 65535 : blue;
+        alpha = alpha < 0 ? 0 : alpha > 65535 ? 65535 : alpha;
+
+        dest[x] = qRgba((unsigned char)(red/257UL),
+                        (unsigned char)(green/257UL),
+                        (unsigned char)(blue/257UL),
+                        (unsigned char)(alpha/257UL));
+    }
+
+    for(; x < columns; ++x){
+        red = blue = green = alpha = 0.0;
+        scale=0;
+        p = kernel;
+        q = src+(x-width/2);
+        for(i=0; i < columns-x+width/2; ++i){
+            red += (*p)*(qRed(*q)*257);
+            green += (*p)*(qGreen(*q)*257);
+            blue += (*p)*(qBlue(*q)*257);
+            alpha += (*p)*(qAlpha(*q)*257);
+            scale += (*p);
+            p++;
+            q++;
+        }
+        scale=1.0/scale;
+        red = scale*(red+0.5);
+        green = scale*(green+0.5);
+        blue = scale*(blue+0.5);
+        alpha = scale*(alpha+0.5);
+
+        red = red < 0 ? 0 : red > 65535 ? 65535 : red;
+        green = green < 0 ? 0 : green > 65535 ? 65535 : green;
+        blue = blue < 0 ? 0 : blue > 65535 ? 65535 : blue;
+        alpha = alpha < 0 ? 0 : alpha > 65535 ? 65535 : alpha;
+
+        dest[x] = qRgba((unsigned char)(red/257UL),
+                        (unsigned char)(green/257UL),
+                        (unsigned char)(blue/257UL),
+                        (unsigned char)(alpha/257UL));
+    }
+}
+
+int KImageEffect::getBlurKernel(int width, double sigma, double **kernel)
+{
+#define KernelRank 3
+    double alpha, normalize;
+    register long i;
+    int bias;
+
+    assert(sigma != 0.0);
+    if(width == 0)
+        width = 3;
+    *kernel=(double *)malloc(width*sizeof(double));
+    if(*kernel == (double *)NULL)
+        return(0);
+    memset(*kernel, 0, width*sizeof(double));
+    bias = KernelRank*width/2;
+    for(i=(-bias); i <= bias; i++){
+        alpha=exp(-((double) i*i)/(2.0*KernelRank*KernelRank*sigma*sigma));
+        (*kernel)[(i+bias)/KernelRank]+=alpha/(MagickSQ2PI*sigma);
+    }
+    normalize=0;
+    for(i=0; i < width; i++)
+        normalize+=(*kernel)[i];
+    for(i=0; i < width; i++)
+        (*kernel)[i]/=normalize;
+
+    return(width);
+}
+
+QImage KImageEffect::blur(QImage &src, double /*factor*/)
+{
+    /* binary compat method - remove me when possible! */
+    return(blur(src, 0, 1));
+}
+
+QImage KImageEffect::blur(QImage &src, double radius, double sigma)
+{
+    double *kernel;
+    QImage dest;
+    int width;
+    int x, y;
+    unsigned int *scanline, *temp;
+    unsigned int *p, *q;
+
+    if(sigma == 0.0){
+        qWarning("KImageEffect::blur(): Zero sigma is not permitted!");
+        return(dest);
+    }
+    if(src.depth() < 32)
+        src = src.convertDepth(32);
+
+    kernel=(double *) NULL;
+    if(radius > 0)
+        width=getBlurKernel((int) (2*ceil(radius)+1),sigma,&kernel);
+    else{
+        double *last_kernel;
+        last_kernel=(double *) NULL;
+        width=getBlurKernel(3,sigma,&kernel);
+
+        while ((long) (MaxRGB*kernel[0]) > 0){
+            if(last_kernel != (double *)NULL){
+                liberateMemory(&last_kernel);
+            }
+            last_kernel=kernel;
+            kernel = (double *)NULL;
+            width = getBlurKernel(width+2, sigma, &kernel);
+        }
+        if(last_kernel != (double *) NULL){
+            liberateMemory(&kernel);
+            width-=2;
+            kernel = last_kernel;
+        }
+    }
+
+    if(width < 3){
+        qWarning("KImageEffect::blur(): Kernel radius is too small!");
+        liberateMemory(&kernel);
+        return(dest);
+    }
+
+    dest.create(src.width(), src.height(), 32);
+
+    scanline = (unsigned int *)malloc(sizeof(unsigned int)*src.height());
+    temp = (unsigned int *)malloc(sizeof(unsigned int)*src.height());
+    for(y=0; y < src.height(); ++y){
+        p = (unsigned int *)src.scanLine(y);
+        q = (unsigned int *)dest.scanLine(y);
+        blurScanLine(kernel, width, p, q, src.width());
+    }
+
+    unsigned int **srcTable = (unsigned int **)src.jumpTable();
+    unsigned int **destTable = (unsigned int **)dest.jumpTable();
+    for(x=0; x < src.width(); ++x){
+        for(y=0; y < src.height(); ++y){
+            scanline[y] = srcTable[y][x];
+        }
+        blurScanLine(kernel, width, scanline, temp, src.height());
+        for(y=0; y < src.height(); ++y){
+            destTable[y][x] = temp[y];
+        }
+    }
+    free(scanline);
+    free(temp);
+    free(kernel);
+    return(dest);
+}
+
+bool KImageEffect::convolveImage(QImage *image, QImage *dest,
+                                 const unsigned int order,
+                                 const double *kernel)
+{
+    long width;
+    double red, green, blue, alpha;
+    double normalize, *normal_kernel;
+    register const double *k;
+    register unsigned int *q;
+    int x, y, mx, my, sx, sy;
+    long i;
+    int mcx, mcy;
+
+    width = order;
+    if((width % 2) == 0){
+        qWarning("KImageEffect: Kernel width must be an odd number!");
+        return(false);
+    }
+    normal_kernel = (double *)malloc(width*width*sizeof(double));
+    if(!normal_kernel){
+        qWarning("KImageEffect: Unable to allocate memory!");
+        return(false);
+    }
+    dest->reset();
+    dest->create(image->width(), image->height(), 32);
+    if(image->depth() < 32)
+        *image = image->convertDepth(32);
+
+    normalize=0.0;
+    for(i=0; i < (width*width); i++)
+        normalize += kernel[i];
+    if(fabs(normalize) <= MagickEpsilon)
+        normalize=1.0;
+    normalize=1.0/normalize;
+    for(i=0; i < (width*width); i++)
+        normal_kernel[i] = normalize*kernel[i];
+
+    unsigned int **jumpTable = (unsigned int **)image->jumpTable();
+    for(y=0; y < dest->height(); ++y){
+        sy = y-(width/2);
+        q = (unsigned int *)dest->scanLine(y);
+        for(x=0; x < dest->width(); ++x){
+            k = normal_kernel;
+            red = green = blue = alpha = 0;
+            sy = y-(width/2);
+            for(mcy=0; mcy < width; ++mcy, ++sy){
+                my = sy < 0 ? 0 : sy > image->height()-1 ?
+                    image->height()-1 : sy;
+                sx = x+(-width/2);
+                for(mcx=0; mcx < width; ++mcx, ++sx){
+                    mx = sx < 0 ? 0 : sx > image->width()-1 ?
+                        image->width()-1 : sx;
+                    red += (*k)*(qRed(jumpTable[my][mx])*257);
+                    green += (*k)*(qGreen(jumpTable[my][mx])*257);
+                    blue += (*k)*(qBlue(jumpTable[my][mx])*257);
+                    alpha += (*k)*(qAlpha(jumpTable[my][mx])*257);
+                    ++k;
+                }
+            }
+
+            red = red < 0 ? 0 : red > 65535 ? 65535 : red+0.5;
+            green = green < 0 ? 0 : green > 65535 ? 65535 : green+0.5;
+            blue = blue < 0 ? 0 : blue > 65535 ? 65535 : blue+0.5;
+            alpha = alpha < 0 ? 0 : alpha > 65535 ? 65535 : alpha+0.5;
+
+            *q++ = qRgba((unsigned char)(red/257UL),
+                         (unsigned char)(green/257UL),
+                         (unsigned char)(blue/257UL),
+                         (unsigned char)(alpha/257UL));
+        }
+    }
+    free(normal_kernel);
+    return(true);
+
+}
+
+int KImageEffect::getOptimalKernelWidth(double radius, double sigma)
+{
+    double normalize, value;
+    long width;
+    register long u;
+
+    assert(sigma != 0.0);
+    if(radius > 0.0)
+        return((int)(2.0*ceil(radius)+1.0));
+    for(width=5; ;){
+        normalize=0.0;
+        for(u=(-width/2); u <= (width/2); u++)
+            normalize+=exp(-((double) u*u)/(2.0*sigma*sigma))/(MagickSQ2PI*sigma);
+        u=width/2;
+        value=exp(-((double) u*u)/(2.0*sigma*sigma))/(MagickSQ2PI*sigma)/normalize;
+        if((long)(65535*value) <= 0)
+            break;
+        width+=2;
+    }
+    return((int)width-2);
+}
+
+QImage KImageEffect::sharpen(QImage &src, double /*factor*/)
+{
+    /* binary compat method - remove me when possible! */
+    return(sharpen(src, 0, 1));
+}
+
+QImage KImageEffect::sharpen(QImage &image, double radius, double sigma)
+{
+    double alpha, normalize, *kernel;
+    int width;
+    register long i, u, v;
+    QImage dest;
+
+    if(sigma == 0.0){
+        qWarning("KImageEffect::sharpen(): Zero sigma is not permitted!");
+        return(dest);
+    }
+    width = getOptimalKernelWidth(radius, sigma);
+    if(image.width() < width){
+        qWarning("KImageEffect::sharpen(): Image is smaller than radius!");
+        return(dest);
+    }
+    kernel = (double *)malloc(width*width*sizeof(double));
+    if(!kernel){
+        qWarning("KImageEffect::sharpen(): Unable to allocate memory!");
+        return(dest);
+    }
+
+    i = 0;
+    normalize=0.0;
+    for(v=(-width/2); v <= (width/2); v++){
+        for(u=(-width/2); u <= (width/2); u++){
+            alpha=exp(-((double) u*u+v*v)/(2.0*sigma*sigma));
+            kernel[i]=alpha/(2.0*MagickPI*sigma*sigma);
+            normalize+=kernel[i];
+            i++;
+        }
+    }
+    kernel[i/2]=(-2.0)*normalize;
+    convolveImage(&image, &dest, width, kernel);
+    free(kernel);
+    return(dest);
+}
+
+// End of new algorithms
+
+QImage KImageEffect::shade(QImage &src, bool color_shading, double azimuth,
+             double elevation)
+{
+    struct PointInfo{
+        double x, y, z;
+    };
+
+    double distance, normal_distance, shade;
+    int x, y;
+
+    struct PointInfo light, normal;
+
+    unsigned int *q;
+
+    QImage dest(src.width(), src.height(), 32);
+
+    azimuth = DegreesToRadians(azimuth);
+    elevation = DegreesToRadians(elevation);
+    light.x = MaxRGB*cos(azimuth)*cos(elevation);
+    light.y = MaxRGB*sin(azimuth)*cos(elevation);
+    light.z = MaxRGB*sin(elevation);
+    normal.z= 2*MaxRGB;  // constant Z of surface normal
+
+    if(src.depth() > 8){ // DirectClass source image
+        unsigned int *p, *s0, *s1, *s2;
+        for(y=0; y < src.height(); ++y){
+            p = (unsigned int *)src.scanLine(QMIN(QMAX(y-1,0),src.height()-3));
+            q = (unsigned int *)dest.scanLine(y);
+            // shade this row of pixels.
+            *q++=(*(p+src.width()));
+            p++;
+            s0 = p;
+            s1 = p + src.width();
+            s2 = p + 2*src.width();
+            for(x=1; x < src.width()-1; ++x){
+                // determine the surface normal and compute shading.
+                normal.x=intensityValue(*(s0-1))+intensityValue(*(s1-1))+intensityValue(*(s2-1))-
+                    (double) intensityValue(*(s0+1))-(double) intensityValue(*(s1+1))-
+                    (double) intensityValue(*(s2+1));
+                normal.y=intensityValue(*(s2-1))+intensityValue(*s2)+intensityValue(*(s2+1))-
+                    (double) intensityValue(*(s0-1))-(double) intensityValue(*s0)-
+                    (double) intensityValue(*(s0+1));
+                if((normal.x == 0) && (normal.y == 0))
+                    shade=light.z;
+                else{
+                    shade=0.0;
+                    distance=normal.x*light.x+normal.y*light.y+normal.z*light.z;
+                    if (distance > 0.0){
+                        normal_distance=
+                            normal.x*normal.x+normal.y*normal.y+normal.z*normal.z;
+                        if(fabs(normal_distance) > 0.0000001)
+                            shade=distance/sqrt(normal_distance);
+                    }
+                }
+                if(!color_shading){
+                    *q = qRgba((unsigned char)(shade),
+                               (unsigned char)(shade),
+                               (unsigned char)(shade),
+                               qAlpha(*s1));
+                }
+                else{
+                    *q = qRgba((unsigned char)((shade*qRed(*s1))/(MaxRGB+1)),
+                               (unsigned char)((shade*qGreen(*s1))/(MaxRGB+1)),
+                               (unsigned char)((shade*qBlue(*s1))/(MaxRGB+1)),
+                               qAlpha(*s1));
+                }
+                ++s0;
+                ++s1;
+                ++s2;
+                q++;
+            }
+            *q++=(*s1);
+        }
+    }
+    else{ // PsudeoClass source image
+        unsigned char *p, *s0, *s1, *s2;
+        int scanLineIdx;
+        unsigned int *cTable = (unsigned int *)src.colorTable();
+        for(y=0; y < src.height(); ++y){
+            scanLineIdx = QMIN(QMAX(y-1,0),src.height()-3);
+            p = (unsigned char *)src.scanLine(scanLineIdx);
+            q = (unsigned int *)dest.scanLine(y);
+            // shade this row of pixels.
+            s0 = p;
+            s1 = (unsigned char *) src.scanLine(scanLineIdx+1);
+            s2 = (unsigned char *) src.scanLine(scanLineIdx+2);
+            *q++=(*(cTable+(*s1)));
+            ++p;
+            ++s0;
+            ++s1;
+            ++s2;
+            for(x=1; x < src.width()-1; ++x){
+                // determine the surface normal and compute shading.
+                normal.x=intensityValue(*(cTable+(*(s0-1))))+intensityValue(*(cTable+(*(s1-1))))+intensityValue(*(cTable+(*(s2-1))))-
+                    (double) intensityValue(*(cTable+(*(s0+1))))-(double) intensityValue(*(cTable+(*(s1+1))))-
+                    (double) intensityValue(*(cTable+(*(s2+1))));
+                normal.y=intensityValue(*(cTable+(*(s2-1))))+intensityValue(*(cTable+(*s2)))+intensityValue(*(cTable+(*(s2+1))))-
+                    (double) intensityValue(*(cTable+(*(s0-1))))-(double) intensityValue(*(cTable+(*s0)))-
+                    (double) intensityValue(*(cTable+(*(s0+1))));
+                if((normal.x == 0) && (normal.y == 0))
+                    shade=light.z;
+                else{
+                    shade=0.0;
+                    distance=normal.x*light.x+normal.y*light.y+normal.z*light.z;
+                    if (distance > 0.0){
+                        normal_distance=
+                            normal.x*normal.x+normal.y*normal.y+normal.z*normal.z;
+                        if(fabs(normal_distance) > 0.0000001)
+                            shade=distance/sqrt(normal_distance);
+                    }
+                }
+                if(!color_shading){
+                    *q = qRgba((unsigned char)(shade),
+                               (unsigned char)(shade),
+                               (unsigned char)(shade),
+                               qAlpha(*(cTable+(*s1))));
+                }
+                else{
+                    *q = qRgba((unsigned char)((shade*qRed(*(cTable+(*s1))))/(MaxRGB+1)),
+                               (unsigned char)((shade*qGreen(*(cTable+(*s1))))/(MaxRGB+1)),
+                               (unsigned char)((shade*qBlue(*(cTable+(*s1))))/(MaxRGB+1)),
+                               qAlpha(*s1));
+                }
+                ++s0;
+                ++s1;
+                ++s2;
+                q++;
+            }
+            *q++=(*(cTable+(*s1)));
+        }
+    }
+    return(dest);
+}
+
+// High quality, expensive HSV contrast. You can do a faster one by just
+// taking a grayscale threshold (ie: 128) and incrementing RGB color
+// channels above it and decrementing those below it, but this gives much
+// better results. (mosfet 12/28/01)
+void KImageEffect::contrastHSV(QImage &img, bool sharpen)
+{
+    int i, sign;
+    unsigned int *data;
+    int count;
+    double brightness, scale, theta;
+    QColor c;
+    int h, s, v;
+
+    sign = sharpen ? 1 : -1;
+    scale=0.5000000000000001;
+    if(img.depth() > 8){
+        count = img.width()*img.height();
+        data = (unsigned int *)img.bits();
+    }
+    else{
+        count = img.numColors();
+        data = (unsigned int *)img.colorTable();
+    }
+    for(i=0; i < count; ++i){
+        c.setRgb(data[i]);
+        c.hsv(&h, &s, &v);
+        brightness = v/255.0;
+        theta=(brightness-0.5)*M_PI;
+        brightness+=scale*(((scale*((sin(theta)+1.0)))-brightness)*sign);
+        if (brightness > 1.0)
+            brightness=1.0;
+        else
+            if (brightness < 0)
+                brightness=0.0;
+        v = (int)(brightness*255);
+        c.setHsv(h, s, v);
+        data[i] = qRgba(c.red(), c.green(), c.blue(), qAlpha(data[i]));
+    }
+}
+
+
+struct BumpmapParams {
+    BumpmapParams( double bm_azimuth, double bm_elevation,
+                   int bm_depth, KImageEffect::BumpmapType bm_type,
+                   bool invert ) {
+         /* Convert to radians */
+        double azimuth = DegreesToRadians( bm_azimuth );
+        double elevation = DegreesToRadians( bm_elevation );
+
+        /* Calculate the light vector */
+        lx = (int)( cos(azimuth) * cos(elevation) * 255.0 );
+        ly = (int)( sin(azimuth) * cos(elevation) * 255.0 );
+        int lz         = (int)( sin(elevation) * 255.0 );
+
+        /* Calculate constant Z component of surface normal */
+        int nz  = (6 * 255) / bm_depth;
+        nz2     = nz * nz;
+        nzlz    = nz * lz;
+
+        /* Optimize for vertical normals */
+        background = lz;
+
+        /* Calculate darkness compensation factor */
+        compensation = sin(elevation);
+
+        /* Create look-up table for map type */
+        for (int i = 0; i < 256; i++)
+        {
+            double n = 0;
+            switch (bm_type)
+            {
+            case KImageEffect::Spherical:
+                n = i / 255.0 - 1.0;
+                lut[i] = (int) (255.0 * sqrt(1.0 - n * n) + 0.5);
+                break;
+
+            case KImageEffect::Sinuosidal:
+                n = i / 255.0;
+                lut[i] = (int) (255.0 * (sin((-M_PI / 2.0) + M_PI * n) + 1.0) /
+                                        2.0 + 0.5);
+                break;
+
+            case KImageEffect::Linear:
+            default:
+                lut[i] = i;
+            }
+
+            if (invert)
+                lut[i] = 255 - lut[i];
+        }
+    }
+    int lx,  ly;
+    int nz2, nzlz;
+    int background;
+    double compensation;
+    uchar lut[256];
+};
+
+
+static void bumpmap_convert_row( uint *row,
+                                 int    width,
+                                 int    bpp,
+                                 int    has_alpha,
+                                 uchar *lut,
+                                 int waterlevel )
+{
+  uint *p;
+
+  p = row;
+
+  has_alpha = has_alpha ? 1 : 0;
+
+  if (bpp >= 3)
+      for (; width; width--)
+      {
+          if (has_alpha) {
+              unsigned int idx = (unsigned int)(intensityValue( *row ) + 0.5);
+              *p++ = lut[(unsigned int) ( waterlevel +
+                                          ( ( idx -
+                                              waterlevel) * qBlue( *row )) / 255.0 )];
+          } else {
+              unsigned int idx = (unsigned int)(intensityValue( *row ) + 0.5);
+              *p++ = lut[idx];
+          }
+
+          ++row;
+      }
+}
+
+static void bumpmap_row( uint           *src,
+                         uint           *dest,
+                         int              width,
+                         int              bpp,
+                         int              has_alpha,
+                         uint           *bm_row1,
+                         uint           *bm_row2,
+                         uint           *bm_row3,
+                         int              bm_width,
+                         int              bm_xofs,
+                         bool          tiled,
+                         bool          row_in_bumpmap,
+                         int           ambient,
+                         bool          compensate,
+                         BumpmapParams *params )
+{
+    int xofs1, xofs2, xofs3;
+    int shade;
+    int ndotl;
+    int nx, ny;
+    int x;
+    int tmp;
+
+    tmp = bm_xofs;
+    xofs2 = MOD(tmp, bm_width);
+
+    for (x = 0; x < width; x++)
+    {
+        /* Calculate surface normal from bump map */
+
+        if (tiled || (row_in_bumpmap &&
+                      x >= - tmp && x < - tmp + bm_width)) {
+            if (tiled) {
+                xofs1 = MOD(xofs2 - 1, bm_width);
+                xofs3 = MOD(xofs2 + 1, bm_width);
+	    } else {
+                xofs1 = FXCLAMP(xofs2 - 1, 0, bm_width - 1);
+                xofs3 = FXCLAMP(xofs2 + 1, 0, bm_width - 1);
+	    }
+            nx = (bm_row1[xofs1] + bm_row2[xofs1] + bm_row3[xofs1] -
+                  bm_row1[xofs3] - bm_row2[xofs3] - bm_row3[xofs3]);
+            ny = (bm_row3[xofs1] + bm_row3[xofs2] + bm_row3[xofs3] -
+                  bm_row1[xofs1] - bm_row1[xofs2] - bm_row1[xofs3]);
+	} else {
+            nx = ny = 0;
+        }
+
+      /* Shade */
+
+        if ((nx == 0) && (ny == 0))
+            shade = params->background;
+        else {
+            ndotl = nx * params->lx + ny * params->ly + params->nzlz;
+
+            if (ndotl < 0)
+                shade = (int)( params->compensation * ambient );
+            else {
+                shade = (int)( ndotl / sqrt(double(nx * nx + ny * ny + params->nz2)) );
+
+                shade = (int)( shade + QMAX(0.0, (255 * params->compensation - shade)) *
+                               ambient / 255 );
+	    }
+	}
+
+        /* Paint */
+
+        /**
+         * NOTE: if we want to work with non-32bit images the alpha handling would
+         * also change
+         */
+        if (compensate) {
+            int red = (int)((qRed( *src ) * shade) / (params->compensation * 255));
+            int green = (int)((qGreen( *src ) * shade) / (params->compensation * 255));
+            int blue = (int)((qBlue( *src ) * shade) / (params->compensation * 255));
+            int alpha = (int)((qAlpha( *src ) * shade) / (params->compensation * 255));
+            ++src;
+            *dest++ = qRgba( red, green, blue, alpha );
+        } else {
+            int red = qRed( *src ) * shade / 255;
+            int green = qGreen( *src ) * shade / 255;
+            int blue = qBlue( *src ) * shade / 255;
+            int alpha = qAlpha( *src ) * shade / 255;
+            ++src;
+            *dest++ = qRgba( red, green, blue, alpha );
+        }
+
+        /* Next pixel */
+
+        if (++xofs2 == bm_width)
+            xofs2 = 0;
+    }
+}
+
+/**
+ * A bumpmapping algorithm.
+ *
+ * @param img the image you want bumpmap
+ * @param map the map used
+ * @param azimuth azimuth
+ * @param elevation elevation
+ * @param depth depth (not the depth of the image, but of the map)
+ * @param xofs X offset
+ * @param yofs Y offset
+ * @param waterlevel level that full transparency should represent
+ * @param ambient ambient lighting factor
+ * @param compensate compensate for darkening
+ * @param invert invert bumpmap
+ * @param type type of the bumpmap
+ *
+ * @return The destination image (dst) containing the result.
+ * @author Zack Rusin <zack@kde.org>
+ */
+QImage KImageEffect::bumpmap(QImage &img, QImage &map, double azimuth, double elevation,
+                             int depth, int xofs, int yofs, int waterlevel,
+                             int ambient, bool compensate, bool invert,
+                             BumpmapType type, bool tiled)
+{
+    QImage dst;
+
+    if ( img.depth() != 32 || img.depth() != 32 ) {
+        qWarning( "Bump-mapping effect works only with 32 bit images");
+        return dst;
+    }
+
+    dst.create( img.width(), img.height(), img.depth() );
+    int bm_width  = map.width();
+    int bm_height = map.height();
+    int bm_bpp = map.depth();
+    int bm_has_alpha = map.hasAlphaBuffer();
+
+    int yofs1, yofs2, yofs3;
+
+    if ( tiled ) {
+        yofs2 = MOD( yofs, bm_height );
+        yofs1 = MOD( yofs2 - 1, bm_height);
+        yofs3 = MOD( yofs2 + 1, bm_height);
+    } else {
+        yofs1 = 0;
+        yofs2 = 0;
+        yofs3 = FXCLAMP( yofs2+1, 0, bm_height - 1 );
+    }
+
+    BumpmapParams params( azimuth, elevation, depth, type, invert );
+
+    uint* bm_row1 = (unsigned int*)map.scanLine( yofs1 );
+    uint* bm_row2 = (unsigned int*)map.scanLine( yofs2 );
+    uint* bm_row3 = (unsigned int*)map.scanLine( yofs3 );
+
+    bumpmap_convert_row( bm_row1, bm_width, bm_bpp, bm_has_alpha, params.lut, waterlevel );
+    bumpmap_convert_row( bm_row2, bm_width, bm_bpp, bm_has_alpha, params.lut, waterlevel );
+    bumpmap_convert_row( bm_row3, bm_width, bm_bpp, bm_has_alpha, params.lut, waterlevel );
+
+    for (int y = 0; y < img.height(); ++y)
+    {
+        int row_in_bumpmap = (y >= - yofs && y < - yofs + bm_height);
+
+        uint* src_row = (unsigned int*)img.scanLine( y );
+        uint* dest_row = (unsigned int*)dst.scanLine( y );
+
+        bumpmap_row( src_row, dest_row, img.width(), img.depth(), img.hasAlphaBuffer(),
+                     bm_row1, bm_row2, bm_row3, bm_width, xofs,
+                     tiled,
+                     row_in_bumpmap, ambient, compensate,
+                     &params );
+
+        /* Next line */
+
+        if (tiled || row_in_bumpmap)
+	{
+            uint* bm_tmprow = bm_row1;
+            bm_row1   = bm_row2;
+            bm_row2   = bm_row3;
+            bm_row3   = bm_tmprow;
+
+            if (++yofs2 == bm_height)
+                yofs2 = 0;
+
+            if (tiled)
+                yofs3 = MOD(yofs2 + 1, bm_height);
+            else
+                yofs3 = FXCLAMP(yofs2 + 1, 0, bm_height - 1);
+
+            bm_row3 = (unsigned int*)map.scanLine( yofs3 );
+            bumpmap_convert_row( bm_row3, bm_width, bm_bpp, bm_has_alpha,
+                                 params.lut, waterlevel );
+	}
+    }
+    return dst;
+}
--- widget-engine/kimageeffect.h
+++ widget-engine/kimageeffect.h
@@ -0,0 +1,807 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 1998, 1999, 2001, 2002 Daniel M. Duley <mosfet@interaccess.com>
+ (C) 1998, 1999 Christian Tibirna <ctibirna@total.net>
+ (C) 1998, 1999 Dirk Mueller <mueller@kde.org>
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+// $Id: kimageeffect.h 399215 2005-03-20 14:33:45Z mueller $
+
+#ifndef __KIMAGE_EFFECT_H
+#define __KIMAGE_EFFECT_H
+
+#include <kdelibs_export.h>
+
+class QImage;
+class QSize;
+class QColor;
+class QPoint;
+class QRect;
+
+/**
+ * This class includes various QImage based graphical effects.
+ *
+ * Everything is
+ * static, so there is no need to create an instance of this class. You can
+ * just call the static methods. They are encapsulated here merely to provide
+ * a common namespace.
+ */
+class KDEFX_EXPORT KImageEffect
+{
+public:
+    /**
+     * This enum provides a gradient type specification
+     * @see KImageEffect::blend(), KImageEffect::gradient(),
+     * KImageEffect::unbalancedGradient()
+     */
+    enum GradientType { VerticalGradient,
+			HorizontalGradient,
+                        DiagonalGradient,
+			CrossDiagonalGradient,
+                        PyramidGradient,
+			RectangleGradient,
+                        PipeCrossGradient,
+			EllipticGradient
+    };
+
+    /**
+     * This enum provides a RGB channel specification
+     * @see KImageEffect::blend(), KImageEffect::channelIntensity(),
+     * KImageEffect::modulate()
+     */
+    enum RGBComponent { Red,   //!< Red channel
+			Green, //!< Green channel
+			Blue,  //!< Blue channel
+			Gray,  //!< Grey channel
+			All    //!< All channels
+    };
+
+    /**
+     * This enum provides a lighting direction specification
+     * @see KImageEffect::hash()
+     */
+    enum Lighting {NorthLite, //!< Lighting from the top of the image
+		   NWLite,    //!< Lighting from the top left of the image
+		   WestLite,  //!< Lighting from the left of the image
+		   SWLite,    //!< Lighting from the bottom left of the image
+                   SouthLite, //!< Lighting from the bottom of the image
+		   SELite,    //!< Lighting from the bottom right of the image
+		   EastLite,  //!< Lighting from the right of the image
+		   NELite     //!< Lighting from the top right of the image
+    };
+
+    /**
+     * This enum provides a modulation type specification
+     * @see KImageEffect::modulate()
+     */
+    enum ModulationType { Intensity,  //!< Modulate image intensity
+			  Saturation, //!< Modulate image saturation
+			  HueShift,   //!< Modulate image hue
+			  Contrast    //!< Modulate image contrast
+    };
+
+    /**
+     * This enum provides a noise type specification
+     * @see KImageEffect::addNoise()
+     */
+    enum NoiseType { UniformNoise=0,              //!< Uniform distribution
+		     GaussianNoise,               //!< Gaussian distribution
+		     MultiplicativeGaussianNoise, //!< Multiplicative Gaussian distribution
+                     ImpulseNoise,                //!< Impulse distribution
+		     LaplacianNoise,              //!< Laplacian distribution
+		     PoissonNoise                 //!< Poisson distribution
+    };
+
+    /**
+     * This enum provides a rotation specification.
+     * @see KImageEffect::rotate()
+     */
+    enum RotateDirection{ Rotate90,  //!< Rotate 90 degrees to the right.
+			  Rotate180, //!< Rotate 180 degrees.
+			  Rotate270  //!< Rotate 90 degrees to the left.
+    };
+
+    /**
+     * This enum lists possible bumpmapping implementations.
+     * @see KImageEffect::bumpmap()
+     */
+    enum BumpmapType {
+        Linear,
+        Spherical,
+        Sinuosidal
+    };
+
+    /**
+     * Create a gradient from color a to color b of the specified type.
+     *
+     * @param size The desired size of the gradient.
+     * @param ca Color a
+     * @param cb Color b
+     * @param type The type of gradient.
+     * @param ncols The number of colors to use when not running on a
+     * truecolor display. The gradient will be dithered to this number of
+     * colors. Pass 0 to prevent dithering.
+     */
+    static QImage gradient(const QSize &size, const QColor &ca,
+                           const QColor &cb, GradientType type, int ncols=3);
+
+    /**
+     * Create an unbalanced gradient.
+     *
+     * An unbalanced gradient is a gradient where the transition from
+     * color a to color b is not linear, but in this case, exponential.
+     *
+     * @param size The desired size of the gradient.
+     * @param ca Color a
+     * @param cb Color b
+     * @param type The type of gradient.
+     * @param xfactor The x decay length. Use a value between -200 and 200.
+     * @param yfactor The y decay length.
+     * @param ncols The number of colors. See KImageEffect:gradient.
+     */
+    static QImage unbalancedGradient(const QSize &size, const QColor &ca,
+	    const QColor &cb, GradientType type, int xfactor = 100,
+	    int yfactor = 100, int ncols = 3);
+
+    /**
+     * Blends a color into the destination image, using an opacity
+     * value for blending one into another. Very fast direct pixel
+     * manipulation is used.
+     *
+     * This function uses MMX and SSE2 instructions to blend the
+     * image on processors that support it.
+     *
+     * @param clr source color to be blended into the destination image.
+     * @param dst destination image in which the source will be blended into.
+     * @param opacity opacity (between 0.0 and 1.0) which determines how much
+     *             the source color will be blended into the destination image.
+     * @return The destination image (dst) containing the result.
+     * @author Karol Szwed (gallium@kde.org)
+     * @author Fredrik H&ouml;glund (fredrik@kde.org)
+     */
+    static QImage& blend(const QColor& clr, QImage& dst, float opacity);
+
+    /**
+     * Blend the src image into the destination image, using an opacity
+     * value for blending one into another. Very fast direct pixel
+     * manipulation is used.
+     *
+     * This function uses MMX and SSE2 instructions to blend the
+     * images on processors that support it.
+     *
+     * @param src source image to be blended into the destination image.
+     * @param dst destination image in which the source will be blended into.
+     * @param opacity opacity (between 0.0 and 1.0) which determines how much
+     *             the source image will be blended into the destination image.
+     * @return The destination image (dst) containing the result.
+     * @author Karol Szwed (gallium@kde.org)
+     * @author Fredrik H&ouml;glund (fredrik@kde.org)
+     */
+    static QImage& blend(QImage& src, QImage& dst, float opacity);
+
+    /**
+     * Blend the provided image into a background of the indicated color.
+     *
+     * @param initial_intensity this parameter takes values from -1 to 1:
+     *              a) if positive: how much to fade the image in its
+     *                              less affected spot
+     *              b) if negative: roughly indicates how much of the image
+     *                              remains unaffected
+     * @param bgnd indicates the color of the background to blend in
+     * @param eff lets you choose what kind of blending you like
+     * @param anti_dir blend in the opposite direction (makes no much sense
+     *                  with concentric blending effects)
+     * @param image must be 32bpp
+     */
+    static QImage& blend(QImage &image, float initial_intensity,
+                      const QColor &bgnd, GradientType eff,
+                      bool anti_dir=false);
+
+    /**
+     * Blend an image into another one, using a gradient type
+     * for blending from one to another.
+     *
+     * @param image1 source1 and result of blending
+     * @param image2 source2 of blending
+     * @param gt gradient type for blending between source1 and source2
+     * @param xf x decay length for unbalanced gradient tpye
+     * @param yf y decay length for unbalanced gradient tpye
+     */
+    static QImage& blend(QImage &image1,QImage &image2,
+			 GradientType gt, int xf=100, int yf=100);
+
+    /**
+     * Blend an image into another one, using a color channel of a
+     * third image for the decision of blending from one to another.
+     *
+     * @param image1 Source 1 and result of blending
+     * @param image2 Source 2 of blending
+     * @param blendImage If the gray value of of pixel is 0, the result
+     *               for this pixel is that of image1; for a gray value
+     *               of 1, the pixel of image2 is used; for a value
+     *               in between, a corresponding blending is used.
+     * @param channel The RBG channel to use for the blending decision.
+     */
+    static QImage& blend(QImage &image1, QImage &image2,
+			 QImage &blendImage, RGBComponent channel);
+
+    /**
+     * Blend an image into another one, using alpha in the expected way.
+     * @param upper the "upper" image
+     * @param lower the "lower" image
+     * @param output the target image
+     * @author Rik Hemsley (rikkus) <rik@kde.org>
+     */
+    static bool blend(const QImage & upper, const QImage & lower, QImage & output);
+// Not yet...    static bool blend(const QImage & image1, const QImage & image2, QImage & output, const QRect & destRect);
+
+    /**
+     * Blend an image into another one, using alpha in the expected way and
+     * over coordinates @p x and @p y with respect to the lower image.
+     * The output is a QImage which is the @p upper image already blended
+     * with the @p lower one, so its size will be (in general) the same than
+     * @p upper instead of the same size than @p lower like the method above.
+     * In fact, the size of @p output is like upper's one only when it can be
+     * painted on lower, if there has to be some clipping, output's size will
+     * be the clipped area and x and y will be set to the correct up-left corner
+     * where the clipped rectangle begins.
+     * @param x x-coordinate of lower image
+     * @param y y-coordinate of lower image
+     * @param upper the "upper" image
+     * @param lower the "lower" image
+     * @param output the target image
+     */
+    static bool blend(int &x, int &y, const QImage & upper, const QImage & lower, QImage & output);
+
+    /**
+     * Blend an image into another one, using alpha in the expected way and
+     * over coordinates @p x and @p y with respect to the lower image.
+     * The output is painted in the own @p lower image. This is an optimization
+     * of the blend method above provided by convenience.
+     * @param x x-coordinate of lower image
+     * @param y y-coordinate of lower image
+     * @param upper the "upper" image
+     * @param lower the "lower" image, which becomes the output image
+     */
+    static bool blendOnLower(int x, int y, const QImage & upper, const QImage & lower);
+
+    /**
+     * Blend part of an image into part of another, using the alpha channel in
+     * the expected way.
+     * Note that the destination rectangle will be correctly clipped.
+     *
+     * @param upper the "upper" image
+     * @param upperOffset Offset for the part of the upper image to be used.
+     * @param lower the "lower" image
+     * @param lowerRect Rectangle for the part of the lower image where the
+     *                  blending will occur.
+     * @since 3.2
+     */
+    static void blendOnLower(const QImage &upper, const QPoint &upperOffset,
+                             QImage &lower, const QRect &lowerRect);
+
+    /**
+     * Blend part of an image into part of another, using the opacity value
+     * and the alpha channel in the expected way.
+     * Note that the destination rectangle will be correctly clipped.
+     *
+     * @param upper the "upper" image
+     * @param upperOffset Offset for the part of the upper image to be used.
+     * @param lower the "lower" image
+     * @param lowerRect Rectangle for the part of the lower image where the
+     *                  blending will occur.
+     * @param opacity Opacity (between 0.0 and 1.0) which determines how much
+     *             the source image will be blended into the destination image.
+     * @since 3.2
+     */
+    static void blendOnLower(const QImage &upper, const QPoint &upperOffset,
+                             QImage &lower, const QRect &lowerRect, float opacity);
+
+    /**
+     * Disposition of a source image on top of a destination image.
+     * @see KImageEffect::computeDestinationRect, KImageEffect::blendOnLower
+     * @since 3.2
+     */
+    enum Disposition { NoImage = 0, //!< Don't overlay
+		       Centered,    //!< Center top image on botton image
+		       Tiled,       //!< Tile top image on bottom image
+		       CenterTiled, //!< Center and tile top image on bottom image
+		       CenteredMaxpect, //!< Center and scale aspect
+		       TiledMaxpect, //!< Tile and scale aspect
+		       Scaled,      //!< Scale
+		       CenteredAutoFit //!< Center and scale or scale aspect
+    };
+
+    /**
+     * Compute the destination rectangle where to draw the upper image on top
+     * of another image using the given disposition. For tiled
+     * disposition, the rectangle should be duplicated on the whole area to
+     * obtained the wanted effect.
+     *
+     * @param lowerSize The size of the destination image.
+     * @param disposition The wanted disposition.
+     * @param upper The upper image. Note that this image may be scaled to
+     *               adjust to the requested disposition.
+     *
+     * @return the computed rectangle. Its size may exceed @e lowerSize.
+     * @since 3.2
+     */
+    static QRect computeDestinationRect(const QSize &lowerSize,
+                                      Disposition disposition, QImage &upper);
+
+    /**
+     * Blend an image on top of another using a given disposition and a given
+     * opacity. The alpha channel of the upper image is used in the expected
+     * way. Beware the upper image may be modified.
+     * @since 3.2
+     */
+    static void blendOnLower(QImage &upper, QImage &lower,
+                             Disposition disposition, float opacity);
+
+    /**
+     * Modifies the intensity of a pixmap's RGB channel component.
+     *
+     * @param image The QImage to process.
+     * @param percent Percent value. Use a negative value to dim.
+     * @param channel Which channel(s) should be modified
+     * @return The @p image, provided for convenience.
+     * @author Daniel M. Duley (mosfet)
+     */
+    static QImage& channelIntensity(QImage &image, float percent,
+                                    RGBComponent channel);
+
+    /**
+     * Fade an image to a certain background color.
+     *
+     * The number of colors will not be changed.
+     *
+     * @param image The QImage to process.
+     * @param val   The strength of the effect. 0 <= val <= 1.
+     * @param color The background color.
+     * @return Returns the image(), provided for convenience.
+     */
+    static QImage& fade(QImage &image, float val, const QColor &color);
+
+
+    /**
+     * This recolors a pixmap. The most dark color will become color a,
+     * the most bright one color b, and in between.
+     *
+     * @param image A QImage to process.
+     * @param ca Color a
+     * @param cb Color b
+     * @param ncols The number of colors to dither the image to.
+     * Pass 0 to prevent dithering.
+     */
+    static QImage& flatten(QImage &image, const QColor &ca,
+           const QColor &cb, int ncols=0);
+
+    /**
+     * Build a hash on any given QImage
+     *
+     * @param image The QImage to process
+     * @param lite The hash faces the indicated lighting (cardinal poles).
+     * @param spacing How many unmodified pixels in between hashes.
+     * @return Returns the image(), provided for convenience.
+     */
+    static QImage& hash(QImage &image, Lighting lite=NorthLite,
+                        unsigned int spacing=0);
+
+    /**
+     * Either brighten or dim the image by a specified percent.
+     * For example, .50 will modify the colors by 50%.
+     *
+     * This function uses MMX instructions to process the image
+     * on processors that support it.
+     *
+     * @param image The QImage to process.
+     * @param percent The percent value. Use a negative value to dim.
+     * @return Returns The image(), provided for convenience.
+     * @author Daniel M. Duley (mosfet)
+     * @author Benjamin Roe (ben@benroe.com)
+     */
+    static QImage& intensity(QImage &image, float percent);
+
+    /**
+     * Modulate the image with a color channel of another image.
+     *
+     * @param image The QImage to modulate and result.
+     * @param modImage The QImage to use for modulation.
+     * @param reverse Invert the meaning of image/modImage; result is image!
+     * @param type The modulation Type to use.
+     * @param factor The modulation amplitude; with 0 no effect [-200;200].
+     * @param channel The RBG channel of image2 to use for modulation.
+     * @return Returns the image(), provided for convenience.
+     */
+    static QImage& modulate(QImage &image, QImage &modImage, bool reverse,
+		ModulationType type, int factor, RGBComponent channel);
+
+    /**
+     * Convert an image to grayscale.
+     *
+     * @param image The QImage to process.
+     * @param fast Set to @p true in order to use a faster but non-photographic
+     * quality algorithm. Appropriate for things such as toolbar icons.
+     * @return Returns the image(), provided for convenience.
+     * @author Daniel M. Duley (mosfet)
+     */
+    static QImage& toGray(QImage &image, bool fast = false);
+
+    /**
+     * Desaturate an image evenly.
+     *
+     * @param image The QImage to process.
+     * @param desat A value between 0 and 1 setting the degree of desaturation
+     * @return Returns the image(), provided for convenience.
+     */
+    static QImage& desaturate(QImage &image, float desat = 0.3);
+
+    /**
+     * Fast, but low quality contrast of an image. Also see contrastHSV.
+     *
+     * @param image The QImage to process.
+     * @param c A contrast value between -255 to 255.
+     * @return The image(), provided for convenience.
+     * @author Daniel M. Duley (mosfet)
+     * ### KDE 4: remove
+     */
+    static QImage& contrast(QImage &image, int c);
+
+    /**
+     * Dither an image using Floyd-Steinberg dithering for low-color
+     * situations.
+     *
+     * @param image The QImage to process.
+     * @param palette The color palette to use
+     * @param size The size of the palette
+     * @return Returns the image(), provided for convenience.
+     */
+    static QImage& dither(QImage &image, const QColor *palette, int size);
+
+    /**
+     * Calculate the image for a selected image, for instance a selected icon
+     * on the desktop.
+     * @param img the QImage to select
+     * @param col the selected color, usually from QColorGroup::highlight().
+     */
+    static QImage& selectedImage( QImage &img, const QColor &col );
+
+    /**
+     * High quality, expensive HSV contrast. You can do a faster one by just
+     * taking a intensity threshold (ie: 128) and incrementing RGB color
+     * channels above it and decrementing those below it, but this gives much
+     * better results.
+     *
+     * @param img The QImage to process.
+     * @param sharpen If true sharpness is increase, (spiffed). Otherwise
+     * it is decreased, (dulled).
+     * @author Daniel M. Duley (mosfet)
+     */
+    static void contrastHSV(QImage &img, bool sharpen=true);
+
+    /**
+     * Normalises the pixel values to span the full range of color values.
+     * This is a contrast enhancement technique.
+     * @param img the image that is normalised
+     * @author Daniel M. Duley (mosfet)
+     */
+    static void normalize(QImage &img);
+
+    /**
+     * Performs histogram equalisation on the reference
+     * image.
+     * @param img the image that is equalised
+     * @author Daniel M. Duley (mosfet)
+     */
+    static void equalize(QImage &img);
+
+    /**
+     * Thresholds the reference image. You can also threshold images by using
+     * ThresholdDither in the various QPixmap/QImage convert methods, but this
+     * lets you specify a threshold value.
+     *
+     * @param img The QImage to process.
+     * @param value The threshold value.
+     * @author Daniel M. Duley (mosfet)
+     */
+    static void threshold(QImage &img, unsigned int value=128);
+
+    /**
+     * Produces a 'solarization' effect seen when exposing a photographic
+     * film to light during the development process.
+     *
+     * @param img The QImage to process.
+     * @param factor The extent of the solarization (0-99.9)
+     * @author Daniel M. Duley (mosfet)
+     */
+    static void solarize(QImage &img, double factor=50.0);
+
+    /**
+     * Embosses the source image. This involves highlighting the edges
+     * and applying various other enhancements in order to get a metal
+     * effect.
+     *
+     * @param src The QImage to process.
+     * @param radius The radius of the gaussian not counting the
+     * center pixel. Use 0 and a suitable radius will be automatically used.
+     * @param sigma The standard deviation of the gaussian. Use 1 if you're not
+     * sure.
+     * @return The embossed image. The original is not changed.
+     * @author Daniel M. Duley (mosfet)
+     */
+    static QImage emboss(QImage &src, double radius, double sigma);
+
+    /**
+     * Convenience method.
+     */
+    static QImage emboss(QImage &src);
+
+    /**
+     * Minimizes speckle noise in the source image using the 8 hull
+     * algorithm.
+     *
+     * @param src The QImage to process.
+     * @return The despeckled image. The original is not changed.
+     * @author Daniel M. Duley (mosfet)
+     */
+    static QImage despeckle(QImage &src);
+
+    /**
+     * Produces a neat little "charcoal" effect.
+     *
+     * @param src The QImage to process.
+     * @param radius The radius of the gaussian not counting the
+     * center pixel. Use 0 and a suitable radius will be automatically used.
+     * @param sigma The standard deviation of the gaussian. Use 1 if you're not
+     * sure.
+     * @return The charcoal image. The original is not changed.
+     * @author Daniel M. Duley (mosfet)
+     */
+    static QImage charcoal(QImage &src, double radius, double sigma);
+
+    /**
+     * This is provided for binary compatability only! Use the above method
+     * with a radius and sigma instead!
+     */
+     static QImage charcoal(QImage &src, double factor=50.0);
+
+    /**
+     * Rotates the image by the specified amount
+     *
+     * @param src The QImage to process.
+     * @param r The rotate direction.
+     * @return The rotated image. The original is not changed.
+     * @author Daniel M. Duley (mosfet)
+     */
+    static QImage rotate(QImage &src, RotateDirection r);
+
+    /**
+     * Scales an image using simple pixel sampling. This does not produce
+     * nearly as nice a result as QImage::smoothScale(), but has the
+     * advantage of being much faster - only a few milliseconds.
+     *
+     * @param src The QImage to process.
+     * @param w The new width.
+     * @param h The new height.
+     * @return The scaled image. The original is not changed.
+     * @author Daniel M. Duley (mosfet)
+     */
+    static QImage sample(QImage &src, int w, int h);
+
+    /**
+     * Adds noise to an image.
+     *
+     * @param src The QImage to process.
+     * @param type The algorithm used to generate the noise.
+     * @return The image with noise added. The original is not changed.
+     * @author Daniel M. Duley (mosfet)
+     */
+    static QImage addNoise(QImage &src, NoiseType type = GaussianNoise);
+
+    /**
+     * Blurs an image by convolving pixel neighborhoods.
+     *
+     * @param src The QImage to process.
+     * @param radius The radius of the gaussian not counting the
+     * center pixel. Use 0 and a suitable radius will be automatically used.
+     * @param sigma The standard deviation of the gaussian. Use 1 if you're not
+     * sure.
+     * @return The blurred image. The original is not changed.
+     * @author Daniel M. Duley (mosfet)
+     */
+    static QImage blur(QImage &src, double radius, double sigma);
+
+    /**
+     * This is provided for binary compatability only! Use the above method
+     * with a radius and sigma instead!
+     */
+    static QImage blur(QImage &src, double factor=50.0);
+
+    /**
+     * Detects edges in an image using pixel neighborhoods and an edge
+     * detection mask.
+     *
+     * @param src The QImage to process.
+     * @param radius The radius of the gaussian not counting the
+     * center pixel. Use 0 and a suitable radius will be automatically used.
+     * @return The image with edges detected. The original is not changed.
+     * @author Daniel M. Duley (mosfet)
+     */
+    static QImage edge(QImage &src, double radius);
+
+    /**
+     * Implodes an image by a specified percent.
+     *
+     * @param src The QImage to process.
+     * @param factor The extent of the implosion.
+     * @param background An RGBA value to use for the background. After the
+     * effect some pixels may be "empty". This value is used for those pixels.
+     * @return The imploded image. The original is not changed.
+     * @author Daniel M. Duley (mosfet)
+     */
+    static QImage implode(QImage &src, double factor=30.0,
+                   unsigned int background = 0xFFFFFFFF);
+
+    /**
+     * Produces an oil painting effect.
+     *
+     * @param src The QImage to process.
+     * @param radius The radius of the gaussian not counting the
+     * center pixel. Use 0 and a suitable radius will be automatically used.
+     * @return The new image. The original is not changed.
+     * @author Daniel M. Duley (mosfet)
+     */
+    static QImage oilPaintConvolve(QImage &src, double radius);
+
+    /**
+     * This is provided for binary compatability only! Use the above method
+     * instead!
+     */
+    static QImage oilPaint(QImage &src, int radius=3);
+
+    /**
+     * Sharpens the pixels in the image using pixel neighborhoods.
+     *
+     * @param src The QImage to process.
+     * @param radius The radius of the gaussian not counting the
+     * center pixel. Use 0 and a suitable radius will be automatically used.
+     * @param sigma The standard deviation of the gaussian. Use 1 if you're not
+     * sure.
+     * @return The sharpened image. The original is not changed.
+     * @author Daniel M. Duley (mosfet)
+     */
+    static QImage sharpen(QImage &src, double radius, double sigma);
+
+    /**
+     * This is provided for binary compatability only! Use the above method
+     * instead!
+     */
+    static QImage sharpen(QImage &src, double factor=30.0);
+
+    /**
+     * Randomly displaces pixels.
+     *
+     * @param src The QImage to process.
+     * @param amount The vicinity for choosing a random pixel to swap.
+     * @return The image with pixels displaced. The original is not changed.
+     * @author Daniel M. Duley (mosfet)
+     */
+    static QImage spread(QImage &src, unsigned int amount=3);
+
+    /**
+     * Shades the image using a distance light source.
+     *
+     * @param src The QImage to process.
+     * @param color_shading If true do color shading, otherwise do grayscale.
+     * @param azimuth Determines the light source and direction.
+     * @param elevation Determines the light source and direction.
+     * @return The shaded image. The original is not changed.
+     * @author Daniel M. Duley (mosfet)
+     */
+    static QImage shade(QImage &src, bool color_shading=true, double azimuth=30.0,
+                        double elevation=30.0);
+    /**
+     * Swirls the image by a specified amount
+     *
+     * @param src The QImage to process.
+     * @param degrees The tightness of the swirl.
+     * @param background An RGBA value to use for the background. After the
+     * effect some pixels may be "empty". This value is used for those pixels.
+     * @return The swirled image. The original is not changed.
+     * @author Daniel M. Duley (mosfet)
+     */
+    static QImage swirl(QImage &src, double degrees=50.0, unsigned int background =
+                         0xFFFFFFFF);
+
+    /**
+     * Modifies the pixels along a sine wave.
+     *
+     * @param src        The QImage to process.
+     * @param amplitude  The amplitude of the sine wave.
+     * @param frequency  The frequency of the sine wave.
+     * @param background An RGBA value to use for the background. After the
+     * effect some pixels may be "empty". This value is used for those pixels.
+     * @return The new image. The original is not changed.
+     * @author Daniel M. Duley (mosfet)
+     */
+    static QImage wave(QImage &src, double amplitude=25.0, double frequency=150.0,
+                        unsigned int background = 0xFFFFFFFF);
+
+    /**
+     * A bumpmapping algorithm.
+     *
+     * @param img the image you want bumpmap
+     * @param map the map used
+     * @param azimuth azimuth
+     * @param elevation elevation
+     * @param depth depth (not the depth of the image, but of the map)
+     * @param xofs X offset
+     * @param yofs Y offset
+     * @param waterlevel level that full transparency should represent
+     * @param ambient ambient lighting factor
+     * @param compensate compensate for darkening
+     * @param invert invert bumpmap
+     * @param type type of the bumpmap
+     * @param tiled tile the bumpmap over the image through the Y offset
+     *
+     * @return The destination image (dst) containing the result.
+     * @author Zack Rusin <zack@kde.org>
+     */
+    static QImage bumpmap(QImage &img, QImage &map, double azimuth, double elevation,
+                          int depth, int xofs, int yofs, int waterlevel,
+                          int ambient, bool compensate, bool invert,
+                          BumpmapType type, bool tiled);
+
+private:
+
+    /**
+     * Helper function to fast calc some altered (lighten, shaded) colors
+     *
+     */
+    static unsigned int lHash(unsigned int c);
+    static unsigned int uHash(unsigned int c);
+
+    /**
+     * Helper function to find the nearest color to the RBG triplet
+     */
+    static int nearestColor( int r, int g, int b, const QColor *pal, int size );
+
+    static void hull(const int x_offset, const int y_offset, const int polarity,
+                     const int width, const int height,
+                     unsigned int *f, unsigned int *g);
+    static unsigned int generateNoise(unsigned int pixel, NoiseType type);
+    static unsigned int interpolateColor(QImage *image, double x, double y,
+                                         unsigned int background);
+    /* Various convolve routines */
+    static int getOptimalKernelWidth(double radius, double sigma);
+    static bool convolveImage(QImage *image, QImage *dest,
+                              const unsigned int order,
+                              const double *kernel);
+    static void blurScanLine(double *kernel, int width,
+                             unsigned int *src, unsigned int *dest,
+                             int columns);
+    static int getBlurKernel(int width, double sigma, double **kernel);
+};
+
+#endif
--- widget-engine/kpixmap.cpp
+++ widget-engine/kpixmap.cpp
@@ -0,0 +1,415 @@
+/*
+ *  This file is part of the KDE libraries
+ *  Copyright (C) 1998	Mark Donohoe <donohoe@kde.org>
+ * 			Stephan Kulow <coolo@kde.org>
+ *
+ *  $Id: kpixmap.cpp,v 1.43 2003/10/07 22:40:42 mueller Exp $
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Library General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Library General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Library General Public License
+ *  along with this library; see the file COPYING.LIB.  If not, write to
+ *  the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ *  Boston, MA 02111-1307, USA.
+ */
+
+#include <qpixmap.h>
+#include <qpainter.h>
+#include <qimage.h>
+#include <qbitmap.h>
+#include <qcolor.h>
+
+#include <stdlib.h>
+#include "kpixmap.h"
+
+// Fast diffuse dither to 3x3x3 color cube
+// Based on Qt's image conversion functions
+static bool kdither_32_to_8( const QImage *src, QImage *dst )
+{
+    // register QRgb *p;
+    uchar  *b;
+    int	    y;
+	
+    if ( !dst->create(src->width(), src->height(), 8, 256) ) {
+	qWarning("KPixmap: destination image not valid\n");
+	return false;
+    }
+
+    int ncols = 256;
+
+    static uint bm[16][16];
+    static int init=0;
+    if (!init) {
+
+	// Build a Bayer Matrix for dithering
+	init = 1;
+	int n, i, j;
+
+	bm[0][0]=0;
+
+	for (n=1; n<16; n*=2)
+	    for (i=0; i<n; i++)
+		for (j=0; j<n; j++) {
+		    bm[i][j]*=4;
+		    bm[i+n][j]=bm[i][j]+2;
+		    bm[i][j+n]=bm[i][j]+3;
+		    bm[i+n][j+n]=bm[i][j]+1;
+		}
+
+	for (i=0; i<16; i++)
+	    for (j=0; j<16; j++)
+		bm[i][j]<<=8;
+    }
+
+    dst->setNumColors( ncols );
+
+#define MAX_R 2
+#define MAX_G 2
+#define MAX_B 2
+#define INDEXOF(r,g,b) (((r)*(MAX_G+1)+(g))*(MAX_B+1)+(b))
+
+    int rc, gc, bc;
+
+    for ( rc=0; rc<=MAX_R; rc++ )		// build 2x2x2 color cube
+        for ( gc=0; gc<=MAX_G; gc++ )
+	    for ( bc=0; bc<=MAX_B; bc++ ) {
+		dst->setColor( INDEXOF(rc,gc,bc),
+		qRgb( rc*255/MAX_R, gc*255/MAX_G, bc*255/MAX_B ) );
+	    }	
+
+    int sw = src->width();
+    int* line1[3];
+    int* line2[3];
+    int* pv[3];
+
+    line1[0] = new int[src->width()];
+    line2[0] = new int[src->width()];
+    line1[1] = new int[src->width()];
+    line2[1] = new int[src->width()];
+    line1[2] = new int[src->width()];
+    line2[2] = new int[src->width()];
+    pv[0] = new int[sw];
+    pv[1] = new int[sw];
+    pv[2] = new int[sw];
+
+    for ( y=0; y < src->height(); y++ ) {
+	// p = (QRgb *)src->scanLine(y);
+	b = dst->scanLine(y);
+	int endian = (QImage::systemBitOrder() == QImage::BigEndian);
+	int x;
+	uchar* q = src->scanLine(y);
+	uchar* q2 = src->scanLine(y+1 < src->height() ? y + 1 : 0);
+
+	for (int chan = 0; chan < 3; chan++) {
+	    b = dst->scanLine(y);
+	    int *l1 = (y&1) ? line2[chan] : line1[chan];
+	    int *l2 = (y&1) ? line1[chan] : line2[chan];
+	    if ( y == 0 ) {
+		for (int i=0; i<sw; i++)
+		    l1[i] = q[i*4+chan+endian];
+	    }
+	    if ( y+1 < src->height() ) {
+		for (int i=0; i<sw; i++)
+		    l2[i] = q2[i*4+chan+endian];
+	    }
+
+	    // Bi-directional error diffusion
+	    if ( y&1 ) {
+		for (x=0; x<sw; x++) {
+		    int pix = QMAX(QMIN(2, (l1[x] * 2 + 128)/ 255), 0);
+		    int err = l1[x] - pix * 255 / 2;
+		    pv[chan][x] = pix;
+
+		    // Spread the error around...
+		    if ( x+1<sw ) {
+			l1[x+1] += (err*7)>>4;
+			l2[x+1] += err>>4;
+		    }
+		    l2[x]+=(err*5)>>4;
+		    if (x>1)
+			l2[x-1]+=(err*3)>>4;
+		}
+	    } else {
+		for (x=sw; x-->0; ) {
+		    int pix = QMAX(QMIN(2, (l1[x] * 2 + 128)/ 255), 0);
+		    int err = l1[x] - pix * 255 / 2;
+		    pv[chan][x] = pix;
+
+		    // Spread the error around...
+		    if ( x > 0 ) {
+			l1[x-1] += (err*7)>>4;
+			l2[x-1] += err>>4;
+		    }
+		    l2[x]+=(err*5)>>4;
+		    if (x+1 < sw)
+			l2[x+1]+=(err*3)>>4;
+		}
+	    }
+	}
+
+	if (!endian) {
+	    for (x=0; x<sw; x++)
+		*b++ = INDEXOF(pv[2][x],pv[1][x],pv[0][x]);
+	} else {
+	    for (x=0; x<sw; x++)
+		*b++ = INDEXOF(pv[0][x],pv[1][x],pv[2][x]);
+	}
+
+    }
+
+    delete [] line1[0];
+    delete [] line2[0];
+    delete [] line1[1];
+    delete [] line2[1];
+    delete [] line1[2];
+    delete [] line2[2];
+    delete [] pv[0];
+    delete [] pv[1];
+    delete [] pv[2];
+	
+#undef MAX_R
+#undef MAX_G
+#undef MAX_B
+#undef INDEXOF
+
+    return true;
+}
+
+KPixmap::~KPixmap()
+{
+}
+
+bool KPixmap::load( const QString& fileName, const char *format,
+		    int conversion_flags )
+{
+    QImageIO io( fileName, format );
+
+    bool result = io.read();
+	
+    if ( result ) {
+	detach();
+	result = convertFromImage( io.image(), conversion_flags );
+    }
+    return result;
+}
+
+bool KPixmap::load( const QString& fileName, const char *format,
+		    ColorMode mode )
+{
+    int conversion_flags = 0;
+    switch (mode) {
+    case Color:
+	conversion_flags |= ColorOnly;
+	break;
+    case Mono:
+	conversion_flags |= MonoOnly;
+	break;
+    case LowColor:
+	conversion_flags |= LowOnly;
+	break;
+    case WebColor:
+	conversion_flags |= WebOnly;
+	break;
+    default:
+	break;// Nothing.
+    }
+    return load( fileName, format, conversion_flags );
+}
+
+bool KPixmap::convertFromImage( const QImage &img, ColorMode mode )
+{
+    int conversion_flags = 0;
+    switch (mode) {
+    case Color:
+	conversion_flags |= ColorOnly;
+	break;
+    case Mono:
+	conversion_flags |= MonoOnly;
+	break;
+    case LowColor:
+	conversion_flags |= LowOnly;
+	break;
+    case WebColor:
+	conversion_flags |= WebOnly;
+	break;
+    default:
+	break;	// Nothing.
+    }
+    return convertFromImage( img, conversion_flags );
+}
+
+bool KPixmap::convertFromImage( const QImage &img, int conversion_flags  )
+{
+    if ( img.isNull() ) {
+#if defined(CHECK_NULL)
+	qWarning( "KPixmap::convertFromImage: Cannot convert a null image" );
+#endif
+	return false;
+    }
+    detach();					// detach other references
+	
+    int dd = defaultDepth();
+
+    // If color mode not one of KPixmaps extra modes nothing to do
+    if ( ( conversion_flags & KColorMode_Mask ) != LowOnly &&
+	 ( conversion_flags & KColorMode_Mask ) != WebOnly ) {
+	    return QPixmap::convertFromImage ( img, conversion_flags );
+    }
+
+    // If the default pixmap depth is not 8bpp, KPixmap color modes have no
+    // effect. Ignore them and use AutoColor instead.
+    if ( dd > 8 ) {
+	if ( ( conversion_flags & KColorMode_Mask ) == LowOnly ||
+	     ( conversion_flags & KColorMode_Mask ) == WebOnly )
+	    conversion_flags = (conversion_flags & ~KColorMode_Mask) | Auto;
+	return QPixmap::convertFromImage ( img, conversion_flags );
+    }
+	
+    if ( ( conversion_flags & KColorMode_Mask ) == LowOnly ) {
+	// Here we skimp a little on the possible conversion modes
+	// Don't offer ordered or threshold dither of RGB channels or
+	// diffuse or ordered dither of alpha channel. It hardly seems
+	// worth the effort for this specialized mode.
+	
+	// If image uses icon palette don't dither it.
+	if( img.numColors() > 0 && img.numColors() <=40 ) {
+	    if ( checkColorTable( img ) )
+		return QPixmap::convertFromImage( img, QPixmap::Auto );
+	}
+	
+	QBitmap mask;
+	bool isMask = false;
+
+	QImage  image = img.convertDepth(32);
+	QImage tImage( image.width(), image.height(), 8, 256 );
+	
+	if( img.hasAlphaBuffer() ) {
+	    image.setAlphaBuffer( true );
+	    tImage.setAlphaBuffer( true );
+	    isMask = mask.convertFromImage( img.createAlphaMask() );
+	}
+	
+	kdither_32_to_8( &image, &tImage );
+		
+	if( QPixmap::convertFromImage( tImage ) ) {
+	    if ( isMask ) QPixmap::setMask( mask );
+		return true;
+	} else
+	    return false;
+    } else {
+	QImage  image = img.convertDepth( 32 );
+	image.setAlphaBuffer( img.hasAlphaBuffer() );
+	conversion_flags = (conversion_flags & ~ColorMode_Mask) | Auto;
+	return QPixmap::convertFromImage ( image, conversion_flags );
+    }
+}
+
+static QColor* kpixmap_iconPalette = 0;
+
+bool KPixmap::checkColorTable( const QImage &image )
+{
+    int i = 0;
+
+    if (kpixmap_iconPalette == 0) {
+	kpixmap_iconPalette = new QColor[40];
+	
+	// Standard palette
+	kpixmap_iconPalette[i++] = red;
+	kpixmap_iconPalette[i++] = green;
+	kpixmap_iconPalette[i++] = blue;
+	kpixmap_iconPalette[i++] = cyan;
+	kpixmap_iconPalette[i++] = magenta;
+	kpixmap_iconPalette[i++] = yellow;
+	kpixmap_iconPalette[i++] = darkRed;
+	kpixmap_iconPalette[i++] = darkGreen;
+	kpixmap_iconPalette[i++] = darkBlue;
+	kpixmap_iconPalette[i++] = darkCyan;
+	kpixmap_iconPalette[i++] = darkMagenta;
+	kpixmap_iconPalette[i++] = darkYellow;
+	kpixmap_iconPalette[i++] = white;
+	kpixmap_iconPalette[i++] = lightGray;
+	kpixmap_iconPalette[i++] = gray;
+	kpixmap_iconPalette[i++] = darkGray;
+	kpixmap_iconPalette[i++] = black;
+	
+	// Pastels
+	kpixmap_iconPalette[i++] = QColor( 255, 192, 192 );
+	kpixmap_iconPalette[i++] = QColor( 192, 255, 192 );
+	kpixmap_iconPalette[i++] = QColor( 192, 192, 255 );
+	kpixmap_iconPalette[i++] = QColor( 255, 255, 192 );
+	kpixmap_iconPalette[i++] = QColor( 255, 192, 255 );
+	kpixmap_iconPalette[i++] = QColor( 192, 255, 255 );
+
+	// Reds
+	kpixmap_iconPalette[i++] = QColor( 64,   0,   0 );
+	kpixmap_iconPalette[i++] = QColor( 192,  0,   0 );
+
+	// Oranges
+	kpixmap_iconPalette[i++] = QColor( 255, 128,   0 );
+	kpixmap_iconPalette[i++] = QColor( 192,  88,   0 );
+	kpixmap_iconPalette[i++] = QColor( 255, 168,  88 );
+	kpixmap_iconPalette[i++] = QColor( 255, 220, 168 );
+
+	// Blues
+	kpixmap_iconPalette[i++] = QColor(   0,   0, 192 );
+
+	// Turquoise
+	kpixmap_iconPalette[i++] = QColor(   0,  64,  64 );
+	kpixmap_iconPalette[i++] = QColor(   0, 192, 192 );
+
+	// Yellows
+	kpixmap_iconPalette[i++] = QColor(  64,  64,   0 );
+	kpixmap_iconPalette[i++] = QColor( 192, 192,   0 );
+
+	// Greens
+	kpixmap_iconPalette[i++] = QColor(   0,  64,   0 );
+	kpixmap_iconPalette[i++] = QColor(   0, 192,   0 );
+
+	// Purples
+	kpixmap_iconPalette[i++] = QColor( 192,   0, 192 );
+
+	// Greys
+	kpixmap_iconPalette[i++] = QColor(  88,  88,  88 );
+	kpixmap_iconPalette[i++] = QColor(  48,  48,  48 );
+	kpixmap_iconPalette[i++] = QColor( 220, 220, 220 );
+	
+    }
+
+    QRgb* ctable = image.colorTable();
+
+    int ncols = image.numColors();
+    int j;
+
+    // Allow one failure which could be transparent background
+    int failures = 0;
+
+    for ( i=0; i<ncols; i++ ) {
+	for ( j=0; j<40; j++ ) {
+	    if ( kpixmap_iconPalette[j].red() == qRed( ctable[i] ) &&
+		 kpixmap_iconPalette[j].green() == qGreen( ctable[i] ) &&
+		 kpixmap_iconPalette[j].blue() == qBlue( ctable[i] ) ) {
+		break;
+	    }
+	}
+	
+	if ( j == 40 ) {
+	    failures ++;			
+	}
+    }
+
+    return ( failures <= 1 );
+
+}
+
+KPixmap::KPixmap(const QPixmap& p)
+    : QPixmap(p)
+{
+}
--- widget-engine/kpixmap.h
+++ widget-engine/kpixmap.h
@@ -0,0 +1,211 @@
+/*
+ *  This file is part of the KDE libraries
+ *  Copyright (C) 1998	Mark Donohoe <donohoe@kde.org>
+ * 			Stephan Kulow <coolo@kde.org>
+ *
+ *  $Id: kpixmap.h,v 1.31 2003/10/06 09:07:10 bhards Exp $
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Library General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Library General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Library General Public License
+ *  along with this library; see the file COPYING.LIB.  If not, write to
+ *  the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ *  Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __KPIXMAP_H__
+#define __KPIXMAP_H__
+
+#include <qpixmap.h>
+
+const int KColorMode_Mask	= 0x00000300;
+const int WebOnly 	= 0x00000200;
+const int LowOnly	= 0x00000300;
+
+class KPixmapPrivate;
+
+/**
+ * Off-screen paint device with extended features.
+
+ * KPixmap has two new color modes, WebColor and LowColor, applicable
+ * to 8bpp displays.
+
+ * In WebColor mode all images are dithered to the Netscape palette,
+ * even when they have their own color table. WebColor is the default
+ * mode for KPixmap so that standard applications can share the Netscape
+ * palette across the desktop.
+
+ * In LowColor mode images are checked to see if their color table
+ * matches the KDE icon palette. If the color tables do not match, the
+ * images are dithered to a minimal 3x3x3 color cube. LowColor mode can
+ * be used to load icons, background images etc. so that components of
+ * the desktop which are always present use no more than 40 colors.
+
+ * @author Mark Donohoe (donohoe@kde.org)
+ * @version $Id: kpixmap.h,v 1.31 2003/10/06 09:07:10 bhards Exp $
+ */
+class KPixmap : public QPixmap
+{
+public:
+	/**
+	 * This enumeration provides a color pallete specification
+	 * @see KPixmap::convertFromImage(), KPixmap::load()
+	 */
+        enum ColorMode { Auto,   //!< Convert to monochrome if possible
+			 Color,  //!< Native display depth
+			 Mono,   //!< Monochrome pixmap
+			 LowColor, //!< 3x3x3 color cube (or monochrome)
+			 WebColor //!< Netscape pallete (or monochrome)
+	};
+	/**
+	 * This enumeration provides a gradient mode specification
+	 */
+        enum GradientMode { Horizontal,
+			    Vertical,
+			    Diagonal,
+			    CrossDiagonal
+	};
+
+	/**
+	 * Constructs a null pixmap.
+	 */
+         KPixmap() : QPixmap() {};
+
+	/**
+	 * Destructs the pixmap.
+         * ### KDE 4: remove
+	 */
+	~KPixmap();
+
+	/**
+	 * Copies the QPixmap @p pix.
+         */
+	KPixmap(const QPixmap& pix);
+
+	/**
+	 * Converts an image and sets this pixmap.
+	 *
+	 * The conversion_flags argument is a bitwise-OR from the
+	 * following choices. The options marked (default) are the
+	 * choice if no other choice from the list is included (they
+	 * are zero):
+	 *
+	 * Color/Mono preference
+	 *
+	 * @li WebColor -  If the image has depth 1 and contains
+	 * only black and white pixels then the pixmap becomes monochrome. If
+	 * the pixmap has a depth of 8 bits per pixel then the Netscape
+	 * palette is used for the pixmap color table.
+	 * @li LowColor - If the image has depth 1 and contains only black and
+	 * white pixels then the pixmap becomes monochrome. If the pixmap has a
+	 * depth of 8 bits per pixel and the image does not posess a color table
+	 * that matches the Icon palette a 3x3x3 color cube is used for the
+	 * pixmap color table.
+	 * @li AutoColor (default) - If the image has depth 1 and contains
+	 * only black and white pixels, then the pixmap becomes
+	 * monochrome.
+	 * @li ColorOnly - The pixmap is dithered/converted to the native
+	 * display depth.
+	 * @li MonoOnly - The pixmap becomes monochrome. If necessary, it
+	 * is dithered using the chosen dithering algorithm.
+	 *
+	 * Dithering mode preference, for RGB channels
+	 *
+	 * @li DiffuseDither (default) - A high quality dither.
+	 * @li OrderedDither - A faster more ordered dither.
+	 * @li ThresholdDither - No dithering, closest color is used.
+	 *
+	 * Dithering mode preference, for alpha channel
+	 *
+	 * @li DiffuseAlphaDither - A high quality dither.
+	 * @li OrderedAlphaDither - A faster more ordered dither.
+	 * @li ThresholdAlphaDither (default) - No dithering.
+	 *
+	 * Color matching versus dithering preference
+	 *
+	 * @li PreferDither - Always dither 32-bit images when the image
+	 * is being converted to 8-bits. This is the default when
+	 * converting to a pixmap.
+	 * @li AvoidDither - Only dither 32-bit images if the image has
+	 * more than 256 colors and it is being converted to 8-bits.
+	 * This is the default when an image is converted for the
+	 * purpose of saving to a file.
+	 *
+	 * Passing 0 for @p conversion_flags gives all the default
+	 * options.
+	 *
+	 * @param img the image to convert
+	 * @param conversion_flags bitmask, described above
+	 * @return @p true if successful.
+	 **/
+	bool convertFromImage( const QImage &img, int conversion_flags );
+
+	/**
+	 * This is an overloaded member function, provided for
+	 * convenience. It differs from the above function only in
+	 * what argument(s) it accepts.
+	 * @param img the image to convert
+	 * @param mode a ColorMode to apply
+	 * @return @p true if successful.
+	 **/
+	bool convertFromImage( const QImage &img, ColorMode mode = WebColor );
+
+	/**
+	 * Loads a pixmap from the file @p fileName.
+	 *
+	 * If format is specified, the loader attempts to read the
+	 * pixmap using the specified format. If format is not
+	 * specified (default), the loader reads a few bytes from the
+	 * header to guess the file format.
+	 *
+	 * The QImageIO documentation lists the supported image
+	 * formats and explains how to add extra formats.
+	 *
+	 * @param fileName the name of the file to load the image from
+	 * @param format the format for the image
+	 * @param conversion_flags a bitmask, as described in 
+	 *        convertFromImage()
+	 * @return @p true if successful, or false if the pixmap
+	 *         could not be loaded.
+	 **/
+	bool load( const QString& fileName, const char *format,
+		int conversion_flags );
+
+	/**
+	 * This is an overloaded member function, provided for
+	 * convenience. It differs from the above function only in
+	 * what argument(s) it accepts.
+	 * @param fileName the name of the file to load the image from
+	 * @param format the format for the image
+	 * @param mode a ColorMode to apply
+	 * @return @p true if successful, or false if the pixmap
+	 *         could not be loaded.
+	 **/
+	bool load( const QString& fileName,
+		const char *format = 0,
+		ColorMode mode = WebColor );
+
+	/**
+	 * Returns true if the image posesses a color table that
+	 * matches the Icon palette or false otherwise.
+	 *
+	 * An image with one color not found in the Icon palette is
+	 * considered to be a match, since this extra color may be a
+	 * transparent background.
+	 * @param image the image to test
+	 **/
+	bool checkColorTable(const QImage &image);
+
+private:
+    KPixmapPrivate *d;
+};
+
+#endif
--- widget-engine/kpixmapeffect.cpp
+++ widget-engine/kpixmapeffect.cpp
@@ -0,0 +1,325 @@
+/* This file is part of the KDE libraries
+    Copyright (C) 1998, 1999 Christian Tibirna <ctibirna@total.net>
+              (C) 1998, 1999 Daniel M. Duley <mosfet@kde.org>
+              (C) 1998, 1999 Dirk A. Mueller <mueller@kde.org>
+
+*/
+
+// $Id: kpixmapeffect.cpp,v 1.37 2003/05/06 17:37:56 fredrik Exp $
+
+#include <qimage.h>
+#include <qpainter.h>
+
+#include "kpixmapeffect.h"
+#include "kpixmap.h"
+#include "kimageeffect.h"
+
+//======================================================================
+//
+// Gradient effects
+//
+//======================================================================
+
+
+KPixmap& KPixmapEffect::gradient(KPixmap &pixmap, const QColor &ca,
+	const QColor &cb, GradientType eff, int ncols)
+{
+    if(pixmap.depth() > 8 &&
+       (eff == VerticalGradient || eff == HorizontalGradient)) {
+
+        int rDiff, gDiff, bDiff;
+        int rca, gca, bca /*, rcb, gcb, bcb*/;
+
+        register int x, y;
+
+        rDiff = (/*rcb = */ cb.red())   - (rca = ca.red());
+        gDiff = (/*gcb = */ cb.green()) - (gca = ca.green());
+        bDiff = (/*bcb = */ cb.blue())  - (bca = ca.blue());
+
+        register int rl = rca << 16;
+        register int gl = gca << 16;
+        register int bl = bca << 16;
+
+        int rcdelta = ((1<<16) / (eff == VerticalGradient ? pixmap.height() : pixmap.width())) * rDiff;
+        int gcdelta = ((1<<16) / (eff == VerticalGradient ? pixmap.height() : pixmap.width())) * gDiff;
+        int bcdelta = ((1<<16) / (eff == VerticalGradient ? pixmap.height() : pixmap.width())) * bDiff;
+
+        QPainter p(&pixmap);
+
+        // these for-loops could be merged, but the if's in the inner loop
+        // would make it slow
+        switch(eff) {
+        case VerticalGradient:
+            for ( y = 0; y < pixmap.height(); y++ ) {
+                rl += rcdelta;
+                gl += gcdelta;
+                bl += bcdelta;
+
+                p.setPen(QColor(rl>>16, gl>>16, bl>>16));
+                p.drawLine(0, y, pixmap.width()-1, y);
+            }
+            break;
+        case HorizontalGradient:
+            for( x = 0; x < pixmap.width(); x++) {
+                rl += rcdelta;
+                gl += gcdelta;
+                bl += bcdelta;
+
+                p.setPen(QColor(rl>>16, gl>>16, bl>>16));
+                p.drawLine(x, 0, x, pixmap.height()-1);
+            }
+            break;
+        default:
+            ;
+        }
+    }
+    else {
+        QImage image = KImageEffect::gradient(pixmap.size(), ca, cb,
+                                              (KImageEffect::GradientType) eff, ncols);
+        pixmap.convertFromImage(image);
+    }
+
+    return pixmap;
+}
+
+
+// -----------------------------------------------------------------------------
+
+KPixmap& KPixmapEffect::unbalancedGradient(KPixmap &pixmap, const QColor &ca,
+         const QColor &cb, GradientType eff, int xfactor, int yfactor,
+         int ncols)
+{
+    QImage image = KImageEffect::unbalancedGradient(pixmap.size(), ca, cb,
+                                 (KImageEffect::GradientType) eff,
+                                 xfactor, yfactor, ncols);
+    pixmap.convertFromImage(image);
+
+    return pixmap;
+}
+
+
+//======================================================================
+//
+// Intensity effects
+//
+//======================================================================
+
+
+
+KPixmap& KPixmapEffect::intensity(KPixmap &pixmap, float percent)
+{
+    QImage image = pixmap.convertToImage();
+    KImageEffect::intensity(image, percent);
+    pixmap.convertFromImage(image);
+
+    return pixmap;
+}
+
+
+// -----------------------------------------------------------------------------
+
+KPixmap& KPixmapEffect::channelIntensity(KPixmap &pixmap, float percent,
+                                     RGBComponent channel)
+{
+    QImage image = pixmap.convertToImage();
+    KImageEffect::channelIntensity(image, percent,
+                   (KImageEffect::RGBComponent) channel);
+    pixmap.convertFromImage(image);
+
+    return pixmap;
+}
+
+
+//======================================================================
+//
+// Blend effects
+//
+//======================================================================
+
+
+KPixmap& KPixmapEffect::blend(KPixmap &pixmap, float initial_intensity,
+			  const QColor &bgnd, GradientType eff,
+			  bool anti_dir, int ncols)
+{
+
+    QImage image = pixmap.convertToImage();
+    if (image.depth() <=8)
+        image = image.convertDepth(32); //Sloww..
+
+    KImageEffect::blend(image, initial_intensity, bgnd,
+                  (KImageEffect::GradientType) eff, anti_dir);
+
+    unsigned int tmp;
+
+    if(pixmap.depth() <= 8 ) {
+        if ( ncols < 2 || ncols > 256 )
+            ncols = 3;
+        QColor *dPal = new QColor[ncols];
+        for (int i=0; i<ncols; i++) {
+            tmp = 0 + 255 * i / ( ncols - 1 );
+            dPal[i].setRgb ( tmp, tmp, tmp );
+        }
+        KImageEffect::dither(image, dPal, ncols);
+        pixmap.convertFromImage(image);
+        delete [] dPal;
+    }
+    else
+        pixmap.convertFromImage(image);
+
+    return pixmap;
+}
+
+
+//======================================================================
+//
+// Hash effects
+//
+//======================================================================
+
+KPixmap& KPixmapEffect::hash(KPixmap &pixmap, Lighting lite,
+			 unsigned int spacing, int ncols)
+{
+    QImage image = pixmap.convertToImage();
+    KImageEffect::hash(image, (KImageEffect::Lighting) lite, spacing);
+
+    unsigned int tmp;
+
+    if(pixmap.depth() <= 8 ) {
+        if ( ncols < 2 || ncols > 256 )
+            ncols = 3;
+        QColor *dPal = new QColor[ncols];
+        for (int i=0; i<ncols; i++) {
+            tmp = 0 + 255 * i / ( ncols - 1 );
+            dPal[i].setRgb ( tmp, tmp, tmp );
+        }
+        KImageEffect::dither(image, dPal, ncols);
+        pixmap.convertFromImage(image);
+        delete [] dPal;
+    }
+    else
+        pixmap.convertFromImage(image);
+
+    return pixmap;
+}
+
+
+//======================================================================
+//
+// Pattern effects
+//
+//======================================================================
+
+#if 0
+void KPixmapEffect::pattern(KPixmap &pixmap, const QColor &ca,
+	const QColor &cb, unsigned pat[8])
+{
+    QImage img = pattern(pixmap.size(), ca, cb, pat);
+    pixmap.convertFromImage(img);
+}
+#endif
+
+// -----------------------------------------------------------------------------
+
+KPixmap KPixmapEffect::pattern(const KPixmap& pmtile, QSize size,
+                       const QColor &ca, const QColor &cb, int ncols)
+{
+    if (pmtile.depth() > 8)
+	ncols = 0;
+
+    QImage img = pmtile.convertToImage();
+    KImageEffect::flatten(img, ca, cb, ncols);
+    KPixmap pixmap;
+    pixmap.convertFromImage(img);
+
+    return KPixmapEffect::createTiled(pixmap, size);
+}
+
+
+// -----------------------------------------------------------------------------
+
+KPixmap KPixmapEffect::createTiled(const KPixmap& pixmap, QSize size)
+{
+    KPixmap pix(size);
+
+    QPainter p(&pix);
+    p.drawTiledPixmap(0, 0, size.width(), size.height(), pixmap);
+
+    return pix;
+}
+
+
+//======================================================================
+//
+// Fade effects
+//
+//======================================================================
+
+KPixmap& KPixmapEffect::fade(KPixmap &pixmap, double val, const QColor &color)
+{
+    QImage img = pixmap.convertToImage();
+    KImageEffect::fade(img, val, color);
+    pixmap.convertFromImage(img);
+
+    return pixmap;
+}
+
+
+// -----------------------------------------------------------------------------
+KPixmap& KPixmapEffect::toGray(KPixmap &pixmap, bool fast)
+{
+    QImage img = pixmap.convertToImage();
+    KImageEffect::toGray(img, fast);
+    pixmap.convertFromImage(img);
+
+    return pixmap;
+}
+
+// -----------------------------------------------------------------------------
+KPixmap& KPixmapEffect::desaturate(KPixmap &pixmap, float desat)
+{
+    QImage img = pixmap.convertToImage();
+    KImageEffect::desaturate(img, desat);
+    pixmap.convertFromImage(img);
+
+    return pixmap;
+}
+// -----------------------------------------------------------------------------
+KPixmap& KPixmapEffect::contrast(KPixmap &pixmap, int c)
+{
+    QImage img = pixmap.convertToImage();
+    KImageEffect::contrast(img, c);
+    pixmap.convertFromImage(img);
+
+    return pixmap;
+}
+
+//======================================================================
+//
+// Dither effects
+//
+//======================================================================
+
+// -----------------------------------------------------------------------------
+KPixmap& KPixmapEffect::dither(KPixmap &pixmap, const QColor *palette, int size)
+{
+    QImage img = pixmap.convertToImage();
+    KImageEffect::dither(img, palette, size);
+    pixmap.convertFromImage(img);
+
+    return pixmap;
+}
+
+//======================================================================
+//
+// Other effects
+//
+//======================================================================
+
+KPixmap KPixmapEffect::selectedPixmap( const KPixmap &pix, const QColor &col )
+{
+    QImage img = pix.convertToImage();
+    KImageEffect::selectedImage(img, col);
+    KPixmap outPix;
+    outPix.convertFromImage(img);
+    return outPix;
+}
--- widget-engine/kpixmapeffect.h
+++ widget-engine/kpixmapeffect.h
@@ -0,0 +1,218 @@
+/* This file is part of the KDE libraries
+    Copyright (C) 1998, 1999 Christian Tibirna <ctibirna@total.net>
+              (C) 1998, 1999 Daniel M. Duley <mosfet@kde.org>
+              (C) 1998, 1999 Dirk Mueller <mueller@kde.org>
+
+*/
+
+// $Id: kpixmapeffect.h 399215 2005-03-20 14:33:45Z mueller $
+
+#ifndef __KPIXMAP_EFFECT_H
+#define __KPIXMAP_EFFECT_H
+
+#include <kdelibs_export.h>
+
+#include <qsize.h>
+class KPixmap;
+class QColor;
+
+/**
+ * This class includes various pixmap-based graphical effects.
+ *
+ * Everything is
+ * static, so there is no need to create an instance of this class. You can
+ * just call the static methods. They are encapsulated here merely to provide
+ * a common namespace.
+ */
+class KDEFX_EXPORT KPixmapEffect
+{
+public:
+    enum GradientType { VerticalGradient, HorizontalGradient,
+			DiagonalGradient, CrossDiagonalGradient,
+			PyramidGradient, RectangleGradient,
+			PipeCrossGradient, EllipticGradient };
+    enum RGBComponent { Red, Green, Blue };
+
+    enum Lighting {NorthLite, NWLite, WestLite, SWLite,
+		   SouthLite, SELite, EastLite, NELite};
+
+    /**
+     * Creates a gradient from color a to color b of the specified type.
+     *
+     * @param pixmap The pixmap to process.
+     * @param ca Color a.
+     * @param cb Color b.
+     * @param type The type of gradient.
+     * @param ncols The number of colors to use when not running on a
+     * truecolor display. The gradient will be dithered to this number of
+     * colors. Pass 0 to prevent dithering.
+     * @return Returns the generated pixmap, for convenience.
+     */
+    static KPixmap& gradient(KPixmap& pixmap, const QColor &ca, const QColor &cb,
+                            GradientType type, int ncols=3);
+
+    /**
+     * Creates an unbalanced gradient.
+     *
+     * An unbalanced gradient is a gradient where the transition from
+     * color a to color b is not linear, but in this case, exponential.
+     *
+     * @param pixmap The pixmap that should be written.
+     * @param ca Color a.
+     * @param cb Color b.
+     * @param type The type of gradient.
+     * @param xfactor The x decay length. Use a value between -200 and 200.
+     * @param yfactor The y decay length.
+     * @param ncols The number of colors. See #gradient.
+     * @return The generated pixmap, for convencience.
+     */
+    static KPixmap& unbalancedGradient(KPixmap& pixmap, const QColor &ca,
+                   const QColor &cb, GradientType type, int xfactor = 100,
+                   int yfactor = 100, int ncols=3);
+
+    /**
+     * Creates a pixmap of a given size with the given pixmap.
+     *
+     * if the
+     * given size is bigger than the size of the pixmap, the pixmap is
+     * tiled.
+     *
+     * @param pixmap This is the source pixmap
+     * @param size   The size the new pixmap should have.
+     * @return The generated, tiled pixmap.
+     */
+    static KPixmap createTiled(const KPixmap& pixmap, QSize size);
+
+    /**
+     * Either brightens or dims a pixmap by a specified ratio.
+     *
+     * @param pixmap The pixmap to process.
+     * @param ratio The ratio to use. Use negative value to dim.
+     * @return Returns The pixmap(), provided for convenience.
+     */
+    static KPixmap& intensity(KPixmap& pixmap, float ratio);
+
+    /**
+     * Modifies the intensity of a pixmap's RGB channel component.
+     *
+     * @param pixmap The pixmap to process.
+     * @param ratio value. Use negative value to dim.
+     * @param channel Which channel(s) should be modified
+     * @return Returns the pixmap(), provided for convenience.
+     */
+    static KPixmap& channelIntensity(KPixmap& pixmap, float ratio,
+                                    RGBComponent channel);
+
+    /**
+     * Blends the provided pixmap into a background of the indicated color.
+     *
+     * @param pixmap The pixmap to process.
+     * @param initial_intensity this parameter takes values from -1 to 1:
+     *              @li If positive, it tells how much to fade the image in its
+     *                              less affected spot.
+     *              @li If negative, it tells roughly indicates how much of the image
+     *                              remains unaffected
+     * @param bgnd Indicates the color of the background to blend in.
+     * @param eff Lets you choose what kind of blending you like.
+     * @param anti_dir Blend in the opposite direction (makes no much sense
+     *                  with concentric blending effects).
+     * @param ncols The number of colors to dither the pixmap to. Only
+     *                  used for 8 bpp pixmaps.
+     * @return Returns the pixmap(), provided for convenience.
+     */
+    static KPixmap& blend(KPixmap& pixmap, float initial_intensity,
+                         const QColor &bgnd, GradientType eff,
+                         bool anti_dir=false, int ncols=3);
+
+    /**
+     * Builds a hash on any given pixmap.
+     *
+     * @param pixmap The pixmap to process.
+     * @param lite The hash faces the indicated lighting (cardinal poles)
+     * @param spacing How many unmodified pixels inbetween hashes.
+     * @param ncols The number of colors to dither the pixmap to.
+     * Only used for 8 bpp pixmaps.
+     * @return Returns The pixmap(), provided for convenience.
+     */
+    static KPixmap& hash(KPixmap& pixmap, Lighting lite=NorthLite,
+                        unsigned int spacing=0, int ncols=3);
+
+    /**
+     * Creates a pattern from a pixmap.
+     *
+     * The given pixmap is "flattened"
+     * between color a to color b.
+     * Doesn't change the original pixmap.
+     *
+     * @param pixmap The pixmap to process.
+     * @param size The size of the returned pixmap. If @p size is larger than
+     * the original, the resulting pixmap will be tiled.
+     * @param ca Color a.
+     * @param cb Color b.
+     * @param ncols The number of colors to use. The image will be
+     * dithered to this depth. Pass zero to prevent dithering.
+     * @return The resulting pixmap.
+     */
+    static KPixmap pattern(const KPixmap& pixmap, QSize size,
+                   const QColor &ca, const QColor &cb, int ncols=8);
+
+    /**
+     * Fades a pixmap to a certain color.
+     *
+     * @param pixmap The pixmap to process.
+     * @param val The strength of the effect. 0 <= val <= 1.
+     * @param color The color to blend to.
+     * @return Returns the pixmap(), provided for convenience.
+     */
+    static KPixmap& fade(KPixmap& pixmap, double val, const QColor &color);
+
+    /**
+     * Converts a pixmap to grayscale.
+     *
+     * @param pixmap The pixmap to process.
+     * @param fast Set to @p true in order to use a faster but non-photographic
+     * quality algorithm. Appropriate for things such as toolbar icons.
+     * @return Returns the pixmap(), provided for convenience.
+     */
+    static KPixmap& toGray(KPixmap& pixmap, bool fast=false);
+
+    /**
+     * Desaturates a pixmap.
+     *
+     * @param pixmap The pixmap to process.
+     * @param desat A value between 0 and 1 setting the degree of desaturation
+     * @return Returns The pixmap(), provided for convenience.
+     */
+    static KPixmap& desaturate(KPixmap& pixmap, float desat = 0.3);
+
+    /**
+     * Modifies the contrast of a pixmap.
+     *
+     * @param pixmap The pixmap to process.
+     * @param c A contrast value between -255 and 255.
+     * @return Returns the pixmap(), provided for convenience.
+     */
+    static KPixmap& contrast(KPixmap& pixmap, int c);
+
+    /**
+     * Dithers a pixmap using Floyd-Steinberg dithering for low-color
+     * situations.
+     *
+     * @param pixmap The pixmap to process.
+     * @param palette The color palette to use.
+     * @param size The size of the palette.
+     * @return Returns the pixmap(), provided for convenience.
+     */
+    static KPixmap& dither(KPixmap &pixmap, const QColor *palette, int size);
+
+    /**
+     * Calculate a 'selected' pixmap, for instance a selected icon
+     * on the desktop.
+     * @param pixmap the pixmap to select
+     * @param col the selected color, usually from QColorGroup::highlight().
+     */
+    static KPixmap selectedPixmap( const KPixmap &pixmap, const QColor &col );
+};
+
+
+#endif
--- widget-engine/kstyle.cpp
+++ widget-engine/kstyle.cpp
@@ -0,0 +1,2152 @@
+/*
+ *
+ * KStyle
+ * Copyright (C) 2001-2002 Karol Szwed <gallium@kde.org>
+ *
+ * QWindowsStyle CC_ListView and style images were kindly donated by TrollTech,
+ * Copyright (C) 1998-2000 TrollTech AS.
+ *
+ * Many thanks to Bradley T. Hughes for the 3 button scrollbar code.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License version 2 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <qapplication.h>
+#include <qbitmap.h>
+#include <qcleanuphandler.h>
+#include <qmap.h>
+#include <qimage.h>
+#include <qlistview.h>
+#include <qmenubar.h>
+#include <qpainter.h>
+#include <qpixmap.h>
+#include <qpopupmenu.h>
+#include <qprogressbar.h>
+#include <qscrollbar.h>
+#include <qsettings.h>
+#include <qslider.h>
+#include <qstylefactory.h>
+#include <qtabbar.h>
+#include <qtoolbar.h>
+
+#include <kpixmap.h>
+#include <kpixmapeffect.h>
+#include <kimageeffect.h>
+#include "kstyle.h"
+
+//#if defined Q_WS_X11
+#if defined Q_WS_X11 && ! defined K_WS_QTONLY
+#include <X11/Xlib.h>
+#  ifdef HAVE_XRENDER
+#  include <X11/extensions/Xrender.h> // schroder
+extern bool qt_use_xrender;
+#  endif
+#else
+#undef HAVE_XRENDER
+#endif
+
+
+#include <limits.h>
+
+namespace
+{
+	// INTERNAL
+	enum TransparencyEngine {
+		Disabled = 0,
+		SoftwareTint,
+		SoftwareBlend,
+		XRender
+	};
+
+	// Drop Shadow
+	struct ShadowElements {
+		QWidget* w1;
+		QWidget* w2;
+	};
+	typedef QMap<const QPopupMenu*,ShadowElements> ShadowMap;
+        static ShadowMap *_shadowMap = 0;
+        QSingleCleanupHandler<ShadowMap> cleanupShadowMap;
+        ShadowMap &shadowMap() {
+	    if ( !_shadowMap ) {
+		_shadowMap = new ShadowMap;
+		cleanupShadowMap.set( &_shadowMap );
+	    }
+	    return *_shadowMap;
+	}
+
+
+	// DO NOT ASK ME HOW I MADE THESE TABLES!
+	// (I probably won't remember anyway ;)
+	const double top_right_corner[16] =
+		{ 0.949, 0.965, 0.980, 0.992,
+		  0.851, 0.890, 0.945, 0.980,
+		  0.706, 0.780, 0.890, 0.960,
+		  0.608, 0.706, 0.851, 0.949 };
+
+	const double bottom_right_corner[16] =
+		{ 0.608, 0.706, 0.851, 0.949,
+		  0.706, 0.780, 0.890, 0.960,
+		  0.851, 0.890, 0.945, 0.980,
+		  0.949, 0.965, 0.980, 0.992 };
+
+	const double bottom_left_corner[16] =
+		{ 0.949, 0.851, 0.706, 0.608,
+		  0.965, 0.890, 0.780, 0.706,
+		  0.980, 0.945, 0.890, 0.851,
+		  0.992, 0.980, 0.960, 0.949 };
+
+	const double shadow_strip[4] =
+		{ 0.565, 0.675, 0.835, 0.945 };
+}
+
+
+namespace
+{
+class TransparencyHandler : public QObject
+{
+	public:
+		TransparencyHandler(KStyle* style, TransparencyEngine tEngine,
+							float menuOpacity, bool useDropShadow);
+		~TransparencyHandler();
+		bool eventFilter(QObject* object, QEvent* event);
+
+	protected:
+		void blendToColor(const QColor &col);
+		void blendToPixmap(const QColorGroup &cg, const QPopupMenu* p);
+#ifdef HAVE_XRENDER
+		void XRenderBlendToPixmap(const QPopupMenu* p);
+#endif
+		void createShadowWindows(const QPopupMenu* p);
+		void removeShadowWindows(const QPopupMenu* p);
+		void rightShadow(QImage& dst);
+		void bottomShadow(QImage& dst);
+	private:
+		bool    dropShadow;
+		float   opacity;
+		QPixmap pix;
+		KStyle* kstyle;
+		TransparencyEngine te;
+};
+} // namespace
+
+struct KStylePrivate
+{
+	bool  highcolor                : 1;
+	bool  useFilledFrameWorkaround : 1;
+	bool  etchDisabledText         : 1;
+	bool  scrollablePopupmenus     : 1;
+	bool  menuAltKeyNavigation     : 1;
+	bool  menuDropShadow           : 1;
+	bool  sloppySubMenus           : 1;
+	int   popupMenuDelay;
+	float menuOpacity;
+
+	TransparencyEngine   transparencyEngine;
+	KStyle::KStyleScrollBarType  scrollbarType;
+	TransparencyHandler* menuHandler;
+	KStyle::KStyleFlags flags;
+	
+	//For KPE_ListViewBranch
+	QBitmap *verticalLine;
+	QBitmap *horizontalLine;
+};
+
+// -----------------------------------------------------------------------------
+
+
+KStyle::KStyle( KStyleFlags flags, KStyleScrollBarType sbtype )
+	: QCommonStyle(), d(new KStylePrivate)
+{
+	d->flags = flags;
+	bool useMenuTransparency    = (flags & AllowMenuTransparency);
+	d->useFilledFrameWorkaround = (flags & FilledFrameWorkaround);
+	d->scrollbarType = sbtype;
+	d->highcolor = QPixmap::defaultDepth() > 8;
+
+	// Read style settings
+	QSettings settings;
+	d->popupMenuDelay       = settings.readNumEntry ("/KStyle/Settings/PopupMenuDelay", 256);
+	d->sloppySubMenus       = settings.readBoolEntry("/KStyle/Settings/SloppySubMenus", false);
+	d->etchDisabledText     = settings.readBoolEntry("/KStyle/Settings/EtchDisabledText", true);
+	d->menuAltKeyNavigation = settings.readBoolEntry("/KStyle/Settings/MenuAltKeyNavigation", true);
+	d->scrollablePopupmenus = settings.readBoolEntry("/KStyle/Settings/ScrollablePopupMenus", false);
+	d->menuDropShadow       = settings.readBoolEntry("/KStyle/Settings/MenuDropShadow", false);
+	d->menuHandler = NULL;
+
+	if (useMenuTransparency) {
+		QString effectEngine = settings.readEntry("/KStyle/Settings/MenuTransparencyEngine", "Disabled");
+
+#ifdef HAVE_XRENDER
+		if (effectEngine == "XRender")
+			d->transparencyEngine = XRender;
+#else
+		if (effectEngine == "XRender")
+			d->transparencyEngine = SoftwareBlend;
+#endif
+		else if (effectEngine == "SoftwareBlend")
+			d->transparencyEngine = SoftwareBlend;
+		else if (effectEngine == "SoftwareTint")
+			d->transparencyEngine = SoftwareTint;
+		else
+			d->transparencyEngine = Disabled;
+
+		if (d->transparencyEngine != Disabled) {
+			// Create an instance of the menu transparency handler
+			d->menuOpacity = settings.readDoubleEntry("/KStyle/Settings/MenuOpacity", 0.90);
+			d->menuHandler = new TransparencyHandler(this, d->transparencyEngine,
+													 d->menuOpacity, d->menuDropShadow);
+		}
+	}
+	
+	d->verticalLine   = 0;
+	d->horizontalLine = 0;
+
+	// Create a transparency handler if only drop shadows are enabled.
+	if (!d->menuHandler && d->menuDropShadow)
+		d->menuHandler = new TransparencyHandler(this, Disabled, 1.0, d->menuDropShadow);
+}
+
+
+KStyle::~KStyle()
+{
+	delete d->verticalLine;
+	delete d->horizontalLine;
+
+	delete d->menuHandler;
+
+	d->menuHandler = NULL;
+	delete d;
+}
+
+
+QString KStyle::defaultStyle()
+{
+	if (QPixmap::defaultDepth() > 8)
+	   return QString("keramik");
+	else
+	   return QString("light, 3rd revision");
+}
+
+
+void KStyle::polish( QWidget* widget )
+{
+	if ( d->useFilledFrameWorkaround )
+	{
+		if ( QFrame *frame = ::qt_cast< QFrame* >( widget ) ) {
+			QFrame::Shape shape = frame->frameShape();
+			if (shape == QFrame::ToolBarPanel || shape == QFrame::MenuBarPanel)
+				widget->installEventFilter(this);
+		} 
+	}
+}
+
+
+void KStyle::unPolish( QWidget* widget )
+{
+	if ( d->useFilledFrameWorkaround )
+	{
+		if ( QFrame *frame = ::qt_cast< QFrame* >( widget ) ) {
+			QFrame::Shape shape = frame->frameShape();
+			if (shape == QFrame::ToolBarPanel || shape == QFrame::MenuBarPanel)
+				widget->removeEventFilter(this);
+		} 
+	}
+}
+
+
+// Style changes (should) always re-polish popups.
+void KStyle::polishPopupMenu( QPopupMenu* p )
+{
+	if (!p->testWState( WState_Polished ))
+		p->setCheckable(true);
+
+	// Install transparency handler if the effect is enabled.
+	if ( d->menuHandler &&
+		(strcmp(p->name(), "tear off menu") != 0))
+			p->installEventFilter(d->menuHandler);
+}
+
+
+// -----------------------------------------------------------------------------
+// KStyle extensions
+// -----------------------------------------------------------------------------
+
+void KStyle::setScrollBarType(KStyleScrollBarType sbtype)
+{
+	d->scrollbarType = sbtype;
+}
+
+KStyle::KStyleFlags KStyle::styleFlags() const
+{
+	return d->flags;
+}
+
+void KStyle::renderMenuBlendPixmap( KPixmap &pix, const QColorGroup &cg,
+	const QPopupMenu* /* popup */ ) const
+{
+	pix.fill(cg.button());	// Just tint as the default behavior
+}
+
+
+void KStyle::drawKStylePrimitive( KStylePrimitive kpe,
+								  QPainter* p,
+								  const QWidget* widget,
+								  const QRect &r,
+								  const QColorGroup &cg,
+								  SFlags flags,
+								  const QStyleOption& /* opt */ ) const
+{
+	switch( kpe )
+	{
+		// Dock / Toolbar / General handles.
+		// ---------------------------------
+
+		case KPE_DockWindowHandle: {
+
+			// Draws a nice DockWindow handle including the dock title.
+			QWidget* wid = const_cast<QWidget*>(widget);
+			bool horizontal = flags & Style_Horizontal;
+			int x,y,w,h,x2,y2;
+
+			r.rect( &x, &y, &w, &h );
+			if ((w <= 2) || (h <= 2)) {
+				p->fillRect(r, cg.highlight());
+				return;
+			}
+
+			
+			x2 = x + w - 1;
+			y2 = y + h - 1;
+
+			QFont fnt;
+			fnt = QApplication::font(wid);
+			fnt.setPointSize( fnt.pointSize()-2 );
+
+			// Draw the item on an off-screen pixmap
+			// to preserve Xft antialiasing for
+			// vertically oriented handles.
+			QPixmap pix;
+			if (horizontal)
+				pix.resize( h-2, w-2 );
+			else
+				pix.resize( w-2, h-2 );
+
+			QString title = wid->parentWidget()->caption();
+			QPainter p2;
+			p2.begin(&pix);
+			p2.fillRect(pix.rect(), cg.brush(QColorGroup::Highlight));
+			p2.setPen(cg.highlightedText());
+			p2.setFont(fnt);
+			p2.drawText(pix.rect(), AlignCenter, title);
+			p2.end();
+
+			// Draw a sunken bevel
+			p->setPen(cg.dark());
+			p->drawLine(x, y, x2, y);
+			p->drawLine(x, y, x, y2);
+			p->setPen(cg.light());
+			p->drawLine(x+1, y2, x2, y2);
+			p->drawLine(x2, y+1, x2, y2);
+
+			if (horizontal) {
+				QWMatrix m;
+				m.rotate(-90.0);
+				QPixmap vpix = pix.xForm(m);
+				bitBlt(wid, r.x()+1, r.y()+1, &vpix);
+			} else
+				bitBlt(wid, r.x()+1, r.y()+1, &pix);
+
+			break;
+		}
+
+
+		/*
+		 * KPE_ListViewExpander and KPE_ListViewBranch are based on code from
+		 * QWindowStyle's CC_ListView, kindly donated by TrollTech.
+		 * CC_ListView code is Copyright (C) 1998-2000 TrollTech AS.
+		 */
+
+		case KPE_ListViewExpander: {
+			// Typical Windows style expand/collapse element.
+			int radius = (r.width() - 4) / 2;
+			int centerx = r.x() + r.width()/2;
+			int centery = r.y() + r.height()/2;
+
+			// Outer box
+			p->setPen( cg.mid() );
+			p->drawRect( r );
+
+			// plus or minus
+			p->setPen( cg.text() );
+			p->drawLine( centerx - radius, centery, centerx + radius, centery );
+			if ( flags & Style_On )	// Collapsed = On
+				p->drawLine( centerx, centery - radius, centerx, centery + radius );
+			break;
+		}
+
+		case KPE_ListViewBranch: {
+			// Typical Windows style listview branch element (dotted line).
+
+			// Create the dotline pixmaps if not already created
+			if ( !d->verticalLine )
+			{
+				// make 128*1 and 1*128 bitmaps that can be used for
+				// drawing the right sort of lines.
+				d->verticalLine   = new QBitmap( 1, 129, true );
+				d->horizontalLine = new QBitmap( 128, 1, true );
+				QPointArray a( 64 );
+				QPainter p2;
+				p2.begin( d->verticalLine );
+
+				int i;
+				for( i=0; i < 64; i++ )
+					a.setPoint( i, 0, i*2+1 );
+				p2.setPen( color1 );
+				p2.drawPoints( a );
+				p2.end();
+				QApplication::flushX();
+				d->verticalLine->setMask( *d->verticalLine );
+
+				p2.begin( d->horizontalLine );
+				for( i=0; i < 64; i++ )
+					a.setPoint( i, i*2+1, 0 );
+				p2.setPen( color1 );
+				p2.drawPoints( a );
+				p2.end();
+				QApplication::flushX();
+				d->horizontalLine->setMask( *d->horizontalLine );
+			}
+
+			p->setPen( cg.text() );		// cg.dark() is bad for dark color schemes.
+
+			if (flags & Style_Horizontal)
+			{
+				int point = r.x();
+				int other = r.y();
+				int end = r.x()+r.width();
+				int thickness = r.height();
+
+				while( point < end )
+				{
+					int i = 128;
+					if ( i+point > end )
+						i = end-point;
+					p->drawPixmap( point, other, *d->horizontalLine, 0, 0, i, thickness );
+					point += i;
+				}
+
+			} else {
+				int point = r.y();
+				int other = r.x();
+				int end = r.y()+r.height();
+				int thickness = r.width();
+				int pixmapoffset = (flags & Style_NoChange) ? 0 : 1;	// ### Hackish
+
+				while( point < end )
+				{
+					int i = 128;
+					if ( i+point > end )
+						i = end-point;
+					p->drawPixmap( other, point, *d->verticalLine, 0, pixmapoffset, thickness, i );
+					point += i;
+				}
+			}
+
+			break;
+		}
+
+		// Reimplement the other primitives in your styles.
+		// The current implementation just paints something visibly different.
+		case KPE_ToolBarHandle:
+		case KPE_GeneralHandle:
+		case KPE_SliderHandle:
+			p->fillRect(r, cg.light());
+			break;
+
+		case KPE_SliderGroove:
+			p->fillRect(r, cg.dark());
+			break;
+
+		default:
+			p->fillRect(r, Qt::yellow);	// Something really bad happened - highlight.
+			break;
+	}
+}
+
+
+int KStyle::kPixelMetric( KStylePixelMetric kpm, const QWidget* /* widget */) const
+{
+	int value;
+	switch(kpm)
+	{
+		case KPM_ListViewBranchThickness:
+			value = 1;
+			break;
+
+		case KPM_MenuItemSeparatorHeight:
+		case KPM_MenuItemHMargin:
+		case KPM_MenuItemVMargin:
+		case KPM_MenuItemHFrame:
+		case KPM_MenuItemVFrame:
+		case KPM_MenuItemCheckMarkHMargin:
+		case KPM_MenuItemArrowHMargin:
+		case KPM_MenuItemTabSpacing:
+		default:
+			value = 0;
+	}
+
+	return value;
+}
+
+
+// -----------------------------------------------------------------------------
+
+void KStyle::drawPrimitive( PrimitiveElement pe,
+							QPainter* p,
+							const QRect &r,
+							const QColorGroup &cg,
+							SFlags flags,
+							const QStyleOption& opt ) const
+{
+	// TOOLBAR/DOCK WINDOW HANDLE
+	// ------------------------------------------------------------------------
+	if (pe == PE_DockWindowHandle)
+	{
+		// Wild workarounds are here. Beware.
+		QWidget *widget, *parent;
+
+		if (p && p->device()->devType() == QInternal::Widget) {
+			widget = static_cast<QWidget*>(p->device());
+			parent = widget->parentWidget();
+		} else
+			return;		// Don't paint on non-widgets
+
+		// Check if we are a normal toolbar or a hidden dockwidget.
+		if ( parent &&
+			(parent->inherits("QToolBar") ||		// Normal toolbar
+			(parent->inherits("QMainWindow")) ))	// Collapsed dock
+
+			// Draw a toolbar handle
+			drawKStylePrimitive( KPE_ToolBarHandle, p, widget, r, cg, flags, opt );
+
+		else if ( widget->inherits("QDockWindowHandle") )
+
+			// Draw a dock window handle
+			drawKStylePrimitive( KPE_DockWindowHandle, p, widget, r, cg, flags, opt );
+
+		else
+			// General handle, probably a kicker applet handle.
+			drawKStylePrimitive( KPE_GeneralHandle, p, widget, r, cg, flags, opt );
+
+	} else
+		QCommonStyle::drawPrimitive( pe, p, r, cg, flags, opt );
+}
+
+
+
+void KStyle::drawControl( ControlElement element,
+						  QPainter* p,
+						  const QWidget* widget,
+						  const QRect &r,
+						  const QColorGroup &cg,
+						  SFlags flags,
+						  const QStyleOption &opt ) const
+{
+	switch (element)
+	{
+		// TABS
+		// ------------------------------------------------------------------------
+		case CE_TabBarTab: {
+			const QTabBar* tb  = (const QTabBar*) widget;
+			QTabBar::Shape tbs = tb->shape();
+			bool selected      = flags & Style_Selected;
+			int x = r.x(), y=r.y(), bottom=r.bottom(), right=r.right();
+
+			switch (tbs) {
+
+				case QTabBar::RoundedAbove: {
+					if (!selected)
+						p->translate(0,1);
+					p->setPen(selected ? cg.light() : cg.shadow());
+					p->drawLine(x, y+4, x, bottom);
+					p->drawLine(x, y+4, x+4, y);
+					p->drawLine(x+4, y, right-1, y);
+					if (selected)
+						p->setPen(cg.shadow());
+					p->drawLine(right, y+1, right, bottom);
+
+					p->setPen(cg.midlight());
+					p->drawLine(x+1, y+4, x+1, bottom);
+					p->drawLine(x+1, y+4, x+4, y+1);
+					p->drawLine(x+5, y+1, right-2, y+1);
+
+					if (selected) {
+						p->setPen(cg.mid());
+						p->drawLine(right-1, y+1, right-1, bottom);
+					} else {
+						p->setPen(cg.mid());
+						p->drawPoint(right-1, y+1);
+						p->drawLine(x+4, y+2, right-1, y+2);
+						p->drawLine(x+3, y+3, right-1, y+3);
+						p->fillRect(x+2, y+4, r.width()-3, r.height()-6, cg.mid());
+
+						p->setPen(cg.light());
+						p->drawLine(x, bottom-1, right, bottom-1);
+						p->translate(0,-1);
+					}
+					break;
+				}
+
+				case QTabBar::RoundedBelow: {
+					if (!selected)
+						p->translate(0,-1);
+					p->setPen(selected ? cg.light() : cg.shadow());
+					p->drawLine(x, bottom-4, x, y);
+					if (selected)
+						p->setPen(cg.mid());
+					p->drawLine(x, bottom-4, x+4, bottom);
+					if (selected)
+						p->setPen(cg.shadow());
+					p->drawLine(x+4, bottom, right-1, bottom);
+					p->drawLine(right, bottom-1, right, y);
+
+					p->setPen(cg.midlight());
+					p->drawLine(x+1, bottom-4, x+1, y);
+					p->drawLine(x+1, bottom-4, x+4, bottom-1);
+					p->drawLine(x+5, bottom-1, right-2, bottom-1);
+
+					if (selected) {
+						p->setPen(cg.mid());
+						p->drawLine(right-1, y, right-1, bottom-1);
+					} else {
+						p->setPen(cg.mid());
+						p->drawPoint(right-1, bottom-1);
+						p->drawLine(x+4, bottom-2, right-1, bottom-2);
+						p->drawLine(x+3, bottom-3, right-1, bottom-3);
+						p->fillRect(x+2, y+2, r.width()-3, r.height()-6, cg.mid());
+						p->translate(0,1);
+						p->setPen(cg.dark());
+						p->drawLine(x, y, right, y);
+					}
+					break;
+				}
+
+				case QTabBar::TriangularAbove: {
+					if (!selected)
+						p->translate(0,1);
+					p->setPen(selected ? cg.light() : cg.shadow());
+					p->drawLine(x, bottom, x, y+6);
+					p->drawLine(x, y+6, x+6, y);
+					p->drawLine(x+6, y, right-6, y);
+					if (selected)
+						p->setPen(cg.mid());
+					p->drawLine(right-5, y+1, right-1, y+5);
+					p->setPen(cg.shadow());
+					p->drawLine(right, y+6, right, bottom);
+
+					p->setPen(cg.midlight());
+					p->drawLine(x+1, bottom, x+1, y+6);
+					p->drawLine(x+1, y+6, x+6, y+1);
+					p->drawLine(x+6, y+1, right-6, y+1);
+					p->drawLine(right-5, y+2, right-2, y+5);
+					p->setPen(cg.mid());
+					p->drawLine(right-1, y+6, right-1, bottom);
+
+					QPointArray a(6);
+					a.setPoint(0, x+2, bottom);
+					a.setPoint(1, x+2, y+7);
+					a.setPoint(2, x+7, y+2);
+					a.setPoint(3, right-7, y+2);
+					a.setPoint(4, right-2, y+7);
+					a.setPoint(5, right-2, bottom);
+					p->setPen  (selected ? cg.background() : cg.mid());
+					p->setBrush(selected ? cg.background() : cg.mid());
+					p->drawPolygon(a);
+					p->setBrush(NoBrush);
+					if (!selected) {
+						p->translate(0,-1);
+						p->setPen(cg.light());
+						p->drawLine(x, bottom, right, bottom);
+					}
+					break;
+				}
+
+				default: { // QTabBar::TriangularBelow
+					if (!selected)
+						p->translate(0,-1);
+					p->setPen(selected ? cg.light() : cg.shadow());
+					p->drawLine(x, y, x, bottom-6);
+					if (selected)
+						p->setPen(cg.mid());
+					p->drawLine(x, bottom-6, x+6, bottom);
+					if (selected)
+						p->setPen(cg.shadow());
+					p->drawLine(x+6, bottom, right-6, bottom);
+					p->drawLine(right-5, bottom-1, right-1, bottom-5);
+					if (!selected)
+						p->setPen(cg.shadow());
+					p->drawLine(right, bottom-6, right, y);
+
+					p->setPen(cg.midlight());
+					p->drawLine(x+1, y, x+1, bottom-6);
+					p->drawLine(x+1, bottom-6, x+6, bottom-1);
+					p->drawLine(x+6, bottom-1, right-6, bottom-1);
+					p->drawLine(right-5, bottom-2, right-2, bottom-5);
+					p->setPen(cg.mid());
+					p->drawLine(right-1, bottom-6, right-1, y);
+
+					QPointArray a(6);
+					a.setPoint(0, x+2, y);
+					a.setPoint(1, x+2, bottom-7);
+					a.setPoint(2, x+7, bottom-2);
+					a.setPoint(3, right-7, bottom-2);
+					a.setPoint(4, right-2, bottom-7);
+					a.setPoint(5, right-2, y);
+					p->setPen  (selected ? cg.background() : cg.mid());
+					p->setBrush(selected ? cg.background() : cg.mid());
+					p->drawPolygon(a);
+					p->setBrush(NoBrush);
+					if (!selected) {
+						p->translate(0,1);
+						p->setPen(cg.dark());
+						p->drawLine(x, y, right, y);
+					}
+					break;
+				}
+			};
+
+			break;
+		}
+		
+		// Popup menu scroller
+		// ------------------------------------------------------------------------
+		case CE_PopupMenuScroller: {
+			p->fillRect(r, cg.background());
+			drawPrimitive(PE_ButtonTool, p, r, cg, Style_Enabled);
+			drawPrimitive((flags & Style_Up) ? PE_ArrowUp : PE_ArrowDown, p, r, cg, Style_Enabled);
+			break;
+		}
+
+
+		// PROGRESSBAR
+		// ------------------------------------------------------------------------
+		case CE_ProgressBarGroove: {
+			QRect fr = subRect(SR_ProgressBarGroove, widget);
+			drawPrimitive(PE_Panel, p, fr, cg, Style_Sunken, QStyleOption::Default);
+			break;
+		}
+
+		case CE_ProgressBarContents: {
+			// ### Take into account totalSteps() for busy indicator
+			const QProgressBar* pb = (const QProgressBar*)widget;
+			QRect cr = subRect(SR_ProgressBarContents, widget);
+			double progress = pb->progress();
+			bool reverse = QApplication::reverseLayout();
+			int steps = pb->totalSteps();
+
+			if (!cr.isValid())
+				return;
+
+			// Draw progress bar
+			if (progress > 0 || steps == 0) {
+				double pg = (steps == 0) ? 0.1 : progress / steps;
+				int width = QMIN(cr.width(), (int)(pg * cr.width()));
+				if (steps == 0) { //Busy indicator
+
+					if (width < 1) width = 1; //A busy indicator with width 0 is kind of useless
+
+					int remWidth = cr.width() - width; //Never disappear completely
+					if (remWidth <= 0) remWidth = 1; //Do something non-crashy when too small...
+
+					int pstep =  int(progress) % ( 2 *  remWidth );
+
+					if ( pstep > remWidth ) {
+						//Bounce about.. We're remWidth + some delta, we want to be remWidth - delta...
+						// - ( (remWidth + some delta) - 2* remWidth )  = - (some deleta - remWidth) = remWidth - some delta..
+						pstep = - (pstep - 2 * remWidth );
+					}
+
+					if (reverse)
+						p->fillRect(cr.x() + cr.width() - width - pstep, cr.y(), width, cr.height(),
+									cg.brush(QColorGroup::Highlight));
+					else
+						p->fillRect(cr.x() + pstep, cr.y(), width, cr.height(),
+									cg.brush(QColorGroup::Highlight));
+
+					return;
+				}
+
+
+				// Do fancy gradient for highcolor displays
+				if (d->highcolor) {
+					QColor c(cg.highlight());
+					KPixmap pix;
+					pix.resize(cr.width(), cr.height());
+					KPixmapEffect::gradient(pix, reverse ? c.light(150) : c.dark(150),
+											reverse ? c.dark(150) : c.light(150),
+											KPixmapEffect::HorizontalGradient);
+					if (reverse)
+						p->drawPixmap(cr.x()+(cr.width()-width), cr.y(), pix,
+									  cr.width()-width, 0, width, cr.height());
+					else
+						p->drawPixmap(cr.x(), cr.y(), pix, 0, 0, width, cr.height());
+				} else
+					if (reverse)
+						p->fillRect(cr.x()+(cr.width()-width), cr.y(), width, cr.height(),
+									cg.brush(QColorGroup::Highlight));
+					else
+						p->fillRect(cr.x(), cr.y(), width, cr.height(),
+									cg.brush(QColorGroup::Highlight));
+			}
+			break;
+		}
+
+		case CE_ProgressBarLabel: {
+			const QProgressBar* pb = (const QProgressBar*)widget;
+			QRect cr = subRect(SR_ProgressBarContents, widget);
+			double progress = pb->progress();
+			bool reverse = QApplication::reverseLayout();
+			int steps = pb->totalSteps();
+
+			if (!cr.isValid())
+				return;
+
+			QFont font = p->font();
+			font.setBold(true);
+			p->setFont(font);
+
+			// Draw label
+			if (progress > 0 || steps == 0) {
+				double pg = (steps == 0) ? 1.0 : progress / steps;
+				int width = QMIN(cr.width(), (int)(pg * cr.width()));
+				QRect crect;
+				if (reverse)
+					crect.setRect(cr.x()+(cr.width()-width), cr.y(), cr.width(), cr.height());
+				else
+					crect.setRect(cr.x()+width, cr.y(), cr.width(), cr.height());
+					
+				p->save();
+				p->setPen(pb->isEnabled() ? (reverse ? cg.text() : cg.highlightedText()) : cg.text());
+				p->drawText(r, AlignCenter, pb->progressString());
+				p->setClipRect(crect);
+				p->setPen(reverse ? cg.highlightedText() : cg.text());
+				p->drawText(r, AlignCenter, pb->progressString());
+				p->restore();
+
+			} else {
+				p->setPen(cg.text());
+				p->drawText(r, AlignCenter, pb->progressString());
+			}
+
+			break;
+		}
+
+		default:
+			QCommonStyle::drawControl(element, p, widget, r, cg, flags, opt);
+	}
+}
+
+
+QRect KStyle::subRect(SubRect r, const QWidget* widget) const
+{
+	switch(r)
+	{
+		// KDE2 look smooth progress bar
+		// ------------------------------------------------------------------------
+		case SR_ProgressBarGroove:
+			return widget->rect();
+
+		case SR_ProgressBarContents:
+		case SR_ProgressBarLabel: {
+			// ### take into account indicatorFollowsStyle()
+			QRect rt = widget->rect();
+			return QRect(rt.x()+2, rt.y()+2, rt.width()-4, rt.height()-4);
+		}
+
+		default:
+			return QCommonStyle::subRect(r, widget);
+	}
+}
+
+
+int KStyle::pixelMetric(PixelMetric m, const QWidget* widget) const
+{
+	switch(m)
+	{
+		// BUTTONS
+		// ------------------------------------------------------------------------
+		case PM_ButtonShiftHorizontal:		// Offset by 1
+		case PM_ButtonShiftVertical:		// ### Make configurable
+			return 1;
+
+		case PM_DockWindowHandleExtent:
+		{
+			QWidget* parent = 0;
+			// Check that we are not a normal toolbar or a hidden dockwidget,
+			// in which case we need to adjust the height for font size
+			if (widget && (parent = widget->parentWidget() )
+				&& !parent->inherits("QToolBar")
+				&& !parent->inherits("QMainWindow")
+				&& widget->inherits("QDockWindowHandle") )
+					return widget->fontMetrics().lineSpacing();
+			else
+				return QCommonStyle::pixelMetric(m, widget);
+		}
+
+		// TABS
+		// ------------------------------------------------------------------------
+		case PM_TabBarTabHSpace:
+			return 24;
+
+		case PM_TabBarTabVSpace: {
+			const QTabBar * tb = (const QTabBar *) widget;
+			if ( tb->shape() == QTabBar::RoundedAbove ||
+				 tb->shape() == QTabBar::RoundedBelow )
+				return 10;
+			else
+				return 4;
+		}
+
+		case PM_TabBarTabOverlap: {
+			const QTabBar* tb = (const QTabBar*)widget;
+			QTabBar::Shape tbs = tb->shape();
+
+			if ( (tbs == QTabBar::RoundedAbove) ||
+				 (tbs == QTabBar::RoundedBelow) )
+				return 0;
+			else
+				return 2;
+		}
+
+		// SLIDER
+		// ------------------------------------------------------------------------
+		case PM_SliderLength:
+			return 18;
+
+		case PM_SliderThickness:
+			return 24;
+
+		// Determines how much space to leave for the actual non-tickmark
+		// portion of the slider.
+		case PM_SliderControlThickness: {
+			const QSlider* slider   = (const QSlider*)widget;
+			QSlider::TickSetting ts = slider->tickmarks();
+			int thickness = (slider->orientation() == Horizontal) ?
+							 slider->height() : slider->width();
+			switch (ts) {
+				case QSlider::NoMarks:				// Use total area.
+					break;
+				case QSlider::Both:
+					thickness = (thickness/2) + 3;	// Use approx. 1/2 of area.
+					break;
+				default:							// Use approx. 2/3 of area
+					thickness = ((thickness*2)/3) + 3;
+					break;
+			};
+			return thickness;
+		}
+
+		// SPLITTER
+		// ------------------------------------------------------------------------
+		case PM_SplitterWidth:
+			if (widget && widget->inherits("QDockWindowResizeHandle"))
+				return 8;	// ### why do we need 2pix extra?
+			else
+				return 6;
+
+		// FRAMES
+		// ------------------------------------------------------------------------
+		case PM_MenuBarFrameWidth:
+			return 1;
+
+		case PM_DockWindowFrameWidth:
+			return 1;
+
+		// GENERAL
+		// ------------------------------------------------------------------------
+		case PM_MaximumDragDistance:
+			return -1;
+
+#if QT_VERSION >= 0x030300
+		case PM_MenuBarItemSpacing:
+			return 5;
+
+		case PM_ToolBarItemSpacing:
+			return 0;
+#endif
+		case PM_PopupMenuScrollerHeight:
+			return pixelMetric( PM_ScrollBarExtent, 0);
+
+		default:
+			return QCommonStyle::pixelMetric( m, widget );
+	}
+}
+
+//Helper to find the next sibling that's not hidden
+static QListViewItem* nextVisibleSibling(QListViewItem* item)
+{
+    QListViewItem* sibling = item;
+    do
+    {
+        sibling = sibling->nextSibling();
+    }
+    while (sibling && !sibling->isVisible());
+    
+    return sibling;
+}
+
+void KStyle::drawComplexControl( ComplexControl control,
+								 QPainter* p,
+								 const QWidget* widget,
+								 const QRect &r,
+								 const QColorGroup &cg,
+								 SFlags flags,
+								 SCFlags controls,
+								 SCFlags active,
+								 const QStyleOption &opt ) const
+{
+	switch(control)
+	{
+		// 3 BUTTON SCROLLBAR
+		// ------------------------------------------------------------------------
+		case CC_ScrollBar: {
+			// Many thanks to Brad Hughes for contributing this code.
+			bool useThreeButtonScrollBar = (d->scrollbarType & ThreeButtonScrollBar);
+
+			const QScrollBar *sb = (const QScrollBar*)widget;
+			bool   maxedOut   = (sb->minValue()    == sb->maxValue());
+			bool   horizontal = (sb->orientation() == Qt::Horizontal);
+			SFlags sflags     = ((horizontal ? Style_Horizontal : Style_Default) |
+								 (maxedOut   ? Style_Default : Style_Enabled));
+
+			QRect  addline, subline, subline2, addpage, subpage, slider, first, last;
+			subline = querySubControlMetrics(control, widget, SC_ScrollBarSubLine, opt);
+			addline = querySubControlMetrics(control, widget, SC_ScrollBarAddLine, opt);
+			subpage = querySubControlMetrics(control, widget, SC_ScrollBarSubPage, opt);
+			addpage = querySubControlMetrics(control, widget, SC_ScrollBarAddPage, opt);
+			slider  = querySubControlMetrics(control, widget, SC_ScrollBarSlider,  opt);
+			first   = querySubControlMetrics(control, widget, SC_ScrollBarFirst,   opt);
+			last    = querySubControlMetrics(control, widget, SC_ScrollBarLast,    opt);
+			subline2 = addline;
+
+			if ( useThreeButtonScrollBar )
+				if (horizontal)
+					subline2.moveBy(-addline.width(), 0);
+				else
+					subline2.moveBy(0, -addline.height());
+
+			// Draw the up/left button set
+			if ((controls & SC_ScrollBarSubLine) && subline.isValid()) {
+				drawPrimitive(PE_ScrollBarSubLine, p, subline, cg,
+							sflags | (active == SC_ScrollBarSubLine ?
+								Style_Down : Style_Default));
+
+				if (useThreeButtonScrollBar && subline2.isValid())
+					drawPrimitive(PE_ScrollBarSubLine, p, subline2, cg,
+							sflags | (active == SC_ScrollBarSubLine ?
+								Style_Down : Style_Default));
+			}
+
+			if ((controls & SC_ScrollBarAddLine) && addline.isValid())
+				drawPrimitive(PE_ScrollBarAddLine, p, addline, cg,
+							sflags | ((active == SC_ScrollBarAddLine) ?
+										Style_Down : Style_Default));
+
+			if ((controls & SC_ScrollBarSubPage) && subpage.isValid())
+				drawPrimitive(PE_ScrollBarSubPage, p, subpage, cg,
+							sflags | ((active == SC_ScrollBarSubPage) ?
+										Style_Down : Style_Default));
+
+			if ((controls & SC_ScrollBarAddPage) && addpage.isValid())
+				drawPrimitive(PE_ScrollBarAddPage, p, addpage, cg,
+							sflags | ((active == SC_ScrollBarAddPage) ?
+										Style_Down : Style_Default));
+
+			if ((controls & SC_ScrollBarFirst) && first.isValid())
+				drawPrimitive(PE_ScrollBarFirst, p, first, cg,
+							sflags | ((active == SC_ScrollBarFirst) ?
+										Style_Down : Style_Default));
+
+			if ((controls & SC_ScrollBarLast) && last.isValid())
+				drawPrimitive(PE_ScrollBarLast, p, last, cg,
+							sflags | ((active == SC_ScrollBarLast) ?
+										Style_Down : Style_Default));
+
+			if ((controls & SC_ScrollBarSlider) && slider.isValid()) {
+				drawPrimitive(PE_ScrollBarSlider, p, slider, cg,
+							sflags | ((active == SC_ScrollBarSlider) ?
+										Style_Down : Style_Default));
+				// Draw focus rect
+				if (sb->hasFocus()) {
+					QRect fr(slider.x() + 2, slider.y() + 2,
+							 slider.width() - 5, slider.height() - 5);
+					drawPrimitive(PE_FocusRect, p, fr, cg, Style_Default);
+				}
+			}
+			break;
+		}
+
+
+		// SLIDER
+		// -------------------------------------------------------------------
+		case CC_Slider: {
+			const QSlider* slider = (const QSlider*)widget;
+			QRect groove = querySubControlMetrics(CC_Slider, widget, SC_SliderGroove, opt);
+			QRect handle = querySubControlMetrics(CC_Slider, widget, SC_SliderHandle, opt);
+
+			// Double-buffer slider for no flicker
+			QPixmap pix(widget->size());
+			QPainter p2;
+			p2.begin(&pix);
+
+			if ( slider->parentWidget() &&
+				 slider->parentWidget()->backgroundPixmap() &&
+				 !slider->parentWidget()->backgroundPixmap()->isNull() ) {
+				QPixmap pixmap = *(slider->parentWidget()->backgroundPixmap());
+				p2.drawTiledPixmap(r, pixmap, slider->pos());
+			} else
+				pix.fill(cg.background());
+
+			// Draw slider groove
+			if ((controls & SC_SliderGroove) && groove.isValid()) {
+				drawKStylePrimitive( KPE_SliderGroove, &p2, widget, groove, cg, flags, opt );
+
+				// Draw the focus rect around the groove
+				if (slider->hasFocus())
+					drawPrimitive(PE_FocusRect, &p2, groove, cg);
+			}
+
+			// Draw the tickmarks
+			if (controls & SC_SliderTickmarks)
+				QCommonStyle::drawComplexControl(control, &p2, widget,
+						r, cg, flags, SC_SliderTickmarks, active, opt);
+
+			// Draw the slider handle
+			if ((controls & SC_SliderHandle) && handle.isValid()) {
+				if (active == SC_SliderHandle)
+					flags |= Style_Active;
+				drawKStylePrimitive( KPE_SliderHandle, &p2, widget, handle, cg, flags, opt );
+			}
+
+			p2.end();
+			bitBlt((QWidget*)widget, r.x(), r.y(), &pix);
+			break;
+		}
+
+		// LISTVIEW
+		// -------------------------------------------------------------------
+		case CC_ListView: {
+
+			/*
+			 * Many thanks to TrollTech AS for donating CC_ListView from QWindowsStyle.
+			 * CC_ListView code is Copyright (C) 1998-2000 TrollTech AS.
+			 */
+
+			// Paint the icon and text.
+			if ( controls & SC_ListView )
+				QCommonStyle::drawComplexControl( control, p, widget, r, cg, flags, controls, active, opt );
+
+			// If we're have a branch or are expanded...
+			if ( controls & (SC_ListViewBranch | SC_ListViewExpand) )
+			{
+				// If no list view item was supplied, break
+				if (opt.isDefault())
+					break;
+
+				QListViewItem *item  = opt.listViewItem();
+				QListViewItem *child = item->firstChild();
+
+				int y = r.y();
+				int c;	// dotline vertice count
+				int dotoffset = 0;
+				QPointArray dotlines;
+
+				if ( active == SC_All && controls == SC_ListViewExpand ) {
+					// We only need to draw a vertical line
+					c = 2;
+					dotlines.resize(2);
+					dotlines[0] = QPoint( r.right(), r.top() );
+					dotlines[1] = QPoint( r.right(), r.bottom() );
+
+				} else {
+
+					int linetop = 0, linebot = 0;
+					// each branch needs at most two lines, ie. four end points
+					dotoffset = (item->itemPos() + item->height() - y) % 2;
+					dotlines.resize( item->childCount() * 4 );
+					c = 0;
+
+					// skip the stuff above the exposed rectangle
+					while ( child && y + child->height() <= 0 )
+					{
+						y += child->totalHeight();
+						child = nextVisibleSibling(child);
+					}
+
+					int bx = r.width() / 2;
+
+					// paint stuff in the magical area
+					QListView* v = item->listView();
+					int lh = QMAX( p->fontMetrics().height() + 2 * v->itemMargin(),
+								   QApplication::globalStrut().height() );
+					if ( lh % 2 > 0 )
+						lh++;
+
+					// Draw all the expand/close boxes...
+					QRect boxrect;
+					QStyle::StyleFlags boxflags;
+					while ( child && y < r.height() )
+					{
+						linebot = y + lh/2;
+						if ( (child->isExpandable() || child->childCount()) &&
+							 (child->height() > 0) )
+						{
+							// The primitive requires a rect.
+							boxrect = QRect( bx-4, linebot-4, 9, 9 );
+							boxflags = child->isOpen() ? QStyle::Style_Off : QStyle::Style_On;
+
+							// KStyle extension: Draw the box and expand/collapse indicator
+							drawKStylePrimitive( KPE_ListViewExpander, p, NULL, boxrect, cg, boxflags, opt );
+
+							// dotlinery
+							p->setPen( cg.mid() );
+							dotlines[c++] = QPoint( bx, linetop );
+							dotlines[c++] = QPoint( bx, linebot - 5 );
+							dotlines[c++] = QPoint( bx + 5, linebot );
+							dotlines[c++] = QPoint( r.width(), linebot );
+							linetop = linebot + 5;
+						} else {
+							// just dotlinery
+							dotlines[c++] = QPoint( bx+1, linebot );
+							dotlines[c++] = QPoint( r.width(), linebot );
+						}
+
+						y += child->totalHeight();
+						child = nextVisibleSibling(child);
+					}
+
+					if ( child ) // there's a child to draw, so move linebot to edge of rectangle
+						linebot = r.height();
+
+					if ( linetop < linebot )
+					{
+						dotlines[c++] = QPoint( bx, linetop );
+						dotlines[c++] = QPoint( bx, linebot );
+					}
+				}
+
+				// Draw all the branches...
+				static int thickness = kPixelMetric( KPM_ListViewBranchThickness );
+				int line; // index into dotlines
+				QRect branchrect;
+				QStyle::StyleFlags branchflags;
+				for( line = 0; line < c; line += 2 )
+				{
+					// assumptions here: lines are horizontal or vertical.
+					// lines always start with the numerically lowest
+					// coordinate.
+
+					// point ... relevant coordinate of current point
+					// end ..... same coordinate of the end of the current line
+					// other ... the other coordinate of the current point/line
+					if ( dotlines[line].y() == dotlines[line+1].y() )
+					{
+						// Horizontal branch
+						int end = dotlines[line+1].x();
+						int point = dotlines[line].x();
+						int other = dotlines[line].y();
+
+						branchrect  = QRect( point, other-(thickness/2), end-point, thickness );
+						branchflags = QStyle::Style_Horizontal;
+
+						// KStyle extension: Draw the horizontal branch
+						drawKStylePrimitive( KPE_ListViewBranch, p, NULL, branchrect, cg, branchflags, opt );
+
+					} else {
+						// Vertical branch
+						int end = dotlines[line+1].y();
+						int point = dotlines[line].y();
+						int other = dotlines[line].x();
+						int pixmapoffset = ((point & 1) != dotoffset ) ? 1 : 0;
+
+						branchrect  = QRect( other-(thickness/2), point, thickness, end-point );
+						if (!pixmapoffset)	// ### Hackish - used to hint the offset
+							branchflags = QStyle::Style_NoChange;
+						else
+							branchflags = QStyle::Style_Default;
+
+						// KStyle extension: Draw the vertical branch
+						drawKStylePrimitive( KPE_ListViewBranch, p, NULL, branchrect, cg, branchflags, opt );
+					}
+				}
+			}
+			break;
+		}
+
+		default:
+			QCommonStyle::drawComplexControl( control, p, widget, r, cg,
+											  flags, controls, active, opt );
+			break;
+	}
+}
+
+
+QStyle::SubControl KStyle::querySubControl( ComplexControl control,
+											const QWidget* widget,
+											const QPoint &pos,
+											const QStyleOption &opt ) const
+{
+	QStyle::SubControl ret = QCommonStyle::querySubControl(control, widget, pos, opt);
+
+	if (d->scrollbarType == ThreeButtonScrollBar) {
+		// Enable third button
+		if (control == CC_ScrollBar && ret == SC_None)
+			ret = SC_ScrollBarSubLine;
+	}
+	return ret;
+}
+
+
+QRect KStyle::querySubControlMetrics( ComplexControl control,
+									  const QWidget* widget,
+									  SubControl sc,
+									  const QStyleOption &opt ) const
+{
+    QRect ret;
+
+	if (control == CC_ScrollBar)
+	{
+		bool threeButtonScrollBar = d->scrollbarType & ThreeButtonScrollBar;
+		bool platinumScrollBar    = d->scrollbarType & PlatinumStyleScrollBar;
+		bool nextScrollBar        = d->scrollbarType & NextStyleScrollBar;
+
+		const QScrollBar *sb = (const QScrollBar*)widget;
+		bool horizontal = sb->orientation() == Qt::Horizontal;
+		int sliderstart = sb->sliderStart();
+		int sbextent    = pixelMetric(PM_ScrollBarExtent, widget);
+		int maxlen      = (horizontal ? sb->width() : sb->height())
+						  - (sbextent * (threeButtonScrollBar ? 3 : 2));
+		int sliderlen;
+
+		// calculate slider length
+		if (sb->maxValue() != sb->minValue())
+		{
+			uint range = sb->maxValue() - sb->minValue();
+			sliderlen = (sb->pageStep() * maxlen) /	(range + sb->pageStep());
+
+			int slidermin = pixelMetric( PM_ScrollBarSliderMin, widget );
+			if ( sliderlen < slidermin || range > INT_MAX / 2 )
+				sliderlen = slidermin;
+			if ( sliderlen > maxlen )
+				sliderlen = maxlen;
+		} else
+			sliderlen = maxlen;
+
+		// Subcontrols
+		switch (sc)
+		{
+			case SC_ScrollBarSubLine: {
+				// top/left button
+				if (platinumScrollBar) {
+					if (horizontal)
+						ret.setRect(sb->width() - 2 * sbextent, 0, sbextent, sbextent);
+					else
+						ret.setRect(0, sb->height() - 2 * sbextent, sbextent, sbextent);
+				} else
+					ret.setRect(0, 0, sbextent, sbextent);
+				break;
+			}
+
+			case SC_ScrollBarAddLine: {
+				// bottom/right button
+				if (nextScrollBar) {
+					if (horizontal)
+						ret.setRect(sbextent, 0, sbextent, sbextent);
+					else
+						ret.setRect(0, sbextent, sbextent, sbextent);
+				} else {
+					if (horizontal)
+						ret.setRect(sb->width() - sbextent, 0, sbextent, sbextent);
+					else
+						ret.setRect(0, sb->height() - sbextent, sbextent, sbextent);
+				}
+				break;
+			}
+
+			case SC_ScrollBarSubPage: {
+				// between top/left button and slider
+				if (platinumScrollBar) {
+					if (horizontal)
+						ret.setRect(0, 0, sliderstart, sbextent);
+					else
+						ret.setRect(0, 0, sbextent, sliderstart);
+				} else if (nextScrollBar) {
+					if (horizontal)
+						ret.setRect(sbextent*2, 0, sliderstart-2*sbextent, sbextent);
+					else
+						ret.setRect(0, sbextent*2, sbextent, sliderstart-2*sbextent);
+				} else {
+					if (horizontal)
+						ret.setRect(sbextent, 0, sliderstart - sbextent, sbextent);
+					else
+						ret.setRect(0, sbextent, sbextent, sliderstart - sbextent);
+				}
+				break;
+			}
+
+			case SC_ScrollBarAddPage: {
+				// between bottom/right button and slider
+				int fudge;
+
+				if (platinumScrollBar)
+					fudge = 0;
+				else if (nextScrollBar)
+					fudge = 2*sbextent;
+				else
+					fudge = sbextent;
+
+				if (horizontal)
+					ret.setRect(sliderstart + sliderlen, 0,
+							maxlen - sliderstart - sliderlen + fudge, sbextent);
+				else
+					ret.setRect(0, sliderstart + sliderlen, sbextent,
+							maxlen - sliderstart - sliderlen + fudge);
+				break;
+			}
+
+			case SC_ScrollBarGroove: {
+				int multi = threeButtonScrollBar ? 3 : 2;
+				int fudge;
+
+				if (platinumScrollBar)
+					fudge = 0;
+				else if (nextScrollBar)
+					fudge = 2*sbextent;
+				else
+					fudge = sbextent;
+
+				if (horizontal)
+					ret.setRect(fudge, 0, sb->width() - sbextent * multi, sb->height());
+				else
+					ret.setRect(0, fudge, sb->width(), sb->height() - sbextent * multi);
+				break;
+			}
+
+			case SC_ScrollBarSlider: {
+				if (horizontal)
+					ret.setRect(sliderstart, 0, sliderlen, sbextent);
+				else
+					ret.setRect(0, sliderstart, sbextent, sliderlen);
+				break;
+			}
+
+			default:
+				ret = QCommonStyle::querySubControlMetrics(control, widget, sc, opt);
+				break;
+		}
+	} else
+		ret = QCommonStyle::querySubControlMetrics(control, widget, sc, opt);
+
+	return ret;
+}
+
+static const char * const kstyle_close_xpm[] = {
+"12 12 2 1",
+"# c #000000",
+". c None",
+"............",
+"............",
+"..##....##..",
+"...##..##...",
+"....####....",
+".....##.....",
+"....####....",
+"...##..##...",
+"..##....##..",
+"............",
+"............",
+"............"};
+
+static const char * const kstyle_maximize_xpm[]={
+"12 12 2 1",
+"# c #000000",
+". c None",
+"............",
+"............",
+".##########.",
+".##########.",
+".#........#.",
+".#........#.",
+".#........#.",
+".#........#.",
+".#........#.",
+".#........#.",
+".##########.",
+"............"};
+
+
+static const char * const kstyle_minimize_xpm[] = {
+"12 12 2 1",
+"# c #000000",
+". c None",
+"............",
+"............",
+"............",
+"............",
+"............",
+"............",
+"............",
+"...######...",
+"...######...",
+"............",
+"............",
+"............"};
+
+static const char * const kstyle_normalizeup_xpm[] = {
+"12 12 2 1",
+"# c #000000",
+". c None",
+"............",
+"...#######..",
+"...#######..",
+"...#.....#..",
+".#######.#..",
+".#######.#..",
+".#.....#.#..",
+".#.....###..",
+".#.....#....",
+".#.....#....",
+".#######....",
+"............"};
+
+
+static const char * const kstyle_shade_xpm[] = {
+"12 12 2 1",
+"# c #000000",
+". c None",
+"............",
+"............",
+"............",
+"............",
+"............",
+".....#......",
+"....###.....",
+"...#####....",
+"..#######...",
+"............",
+"............",
+"............"};
+
+static const char * const kstyle_unshade_xpm[] = {
+"12 12 2 1",
+"# c #000000",
+". c None",
+"............",
+"............",
+"............",
+"............",
+"..#######...",
+"...#####....",
+"....###.....",
+".....#......",
+"............",
+"............",
+"............",
+"............"};
+
+static const char * const dock_window_close_xpm[] = {
+"8 8 2 1",
+"# c #000000",
+". c None",
+"##....##",
+".##..##.",
+"..####..",
+"...##...",
+"..####..",
+".##..##.",
+"##....##",
+"........"};
+
+// Message box icons, from page 210 of the Windows style guide.
+
+// Hand-drawn to resemble Microsoft's icons, but in the Mac/Netscape
+// palette.  The "question mark" icon, which Microsoft recommends not
+// using but a lot of people still use, is left out.
+
+/* XPM */
+static const char * const information_xpm[]={
+"32 32 5 1",
+". c None",
+"c c #000000",
+"* c #999999",
+"a c #ffffff",
+"b c #0000ff",
+"...........********.............",
+"........***aaaaaaaa***..........",
+"......**aaaaaaaaaaaaaa**........",
+".....*aaaaaaaaaaaaaaaaaa*.......",
+"....*aaaaaaaabbbbaaaaaaaac......",
+"...*aaaaaaaabbbbbbaaaaaaaac.....",
+"..*aaaaaaaaabbbbbbaaaaaaaaac....",
+".*aaaaaaaaaaabbbbaaaaaaaaaaac...",
+".*aaaaaaaaaaaaaaaaaaaaaaaaaac*..",
+"*aaaaaaaaaaaaaaaaaaaaaaaaaaaac*.",
+"*aaaaaaaaaabbbbbbbaaaaaaaaaaac*.",
+"*aaaaaaaaaaaabbbbbaaaaaaaaaaac**",
+"*aaaaaaaaaaaabbbbbaaaaaaaaaaac**",
+"*aaaaaaaaaaaabbbbbaaaaaaaaaaac**",
+"*aaaaaaaaaaaabbbbbaaaaaaaaaaac**",
+"*aaaaaaaaaaaabbbbbaaaaaaaaaaac**",
+".*aaaaaaaaaaabbbbbaaaaaaaaaac***",
+".*aaaaaaaaaaabbbbbaaaaaaaaaac***",
+"..*aaaaaaaaaabbbbbaaaaaaaaac***.",
+"...caaaaaaabbbbbbbbbaaaaaac****.",
+"....caaaaaaaaaaaaaaaaaaaac****..",
+".....caaaaaaaaaaaaaaaaaac****...",
+"......ccaaaaaaaaaaaaaacc****....",
+".......*cccaaaaaaaaccc*****.....",
+"........***cccaaaac*******......",
+"..........****caaac*****........",
+".............*caaac**...........",
+"...............caac**...........",
+"................cac**...........",
+".................cc**...........",
+"..................***...........",
+"...................**..........."};
+/* XPM */
+static const char* const warning_xpm[]={
+"32 32 4 1",
+". c None",
+"a c #ffff00",
+"* c #000000",
+"b c #999999",
+".............***................",
+"............*aaa*...............",
+"...........*aaaaa*b.............",
+"...........*aaaaa*bb............",
+"..........*aaaaaaa*bb...........",
+"..........*aaaaaaa*bb...........",
+".........*aaaaaaaaa*bb..........",
+".........*aaaaaaaaa*bb..........",
+"........*aaaaaaaaaaa*bb.........",
+"........*aaaa***aaaa*bb.........",
+".......*aaaa*****aaaa*bb........",
+".......*aaaa*****aaaa*bb........",
+"......*aaaaa*****aaaaa*bb.......",
+"......*aaaaa*****aaaaa*bb.......",
+".....*aaaaaa*****aaaaaa*bb......",
+".....*aaaaaa*****aaaaaa*bb......",
+"....*aaaaaaaa***aaaaaaaa*bb.....",
+"....*aaaaaaaa***aaaaaaaa*bb.....",
+"...*aaaaaaaaa***aaaaaaaaa*bb....",
+"...*aaaaaaaaaa*aaaaaaaaaa*bb....",
+"..*aaaaaaaaaaa*aaaaaaaaaaa*bb...",
+"..*aaaaaaaaaaaaaaaaaaaaaaa*bb...",
+".*aaaaaaaaaaaa**aaaaaaaaaaa*bb..",
+".*aaaaaaaaaaa****aaaaaaaaaa*bb..",
+"*aaaaaaaaaaaa****aaaaaaaaaaa*bb.",
+"*aaaaaaaaaaaaa**aaaaaaaaaaaa*bb.",
+"*aaaaaaaaaaaaaaaaaaaaaaaaaaa*bbb",
+"*aaaaaaaaaaaaaaaaaaaaaaaaaaa*bbb",
+".*aaaaaaaaaaaaaaaaaaaaaaaaa*bbbb",
+"..*************************bbbbb",
+"....bbbbbbbbbbbbbbbbbbbbbbbbbbb.",
+".....bbbbbbbbbbbbbbbbbbbbbbbbb.."};
+/* XPM */
+static const char* const critical_xpm[]={
+"32 32 4 1",
+". c None",
+"a c #999999",
+"* c #ff0000",
+"b c #ffffff",
+"...........********.............",
+".........************...........",
+".......****************.........",
+"......******************........",
+".....********************a......",
+"....**********************a.....",
+"...************************a....",
+"..*******b**********b*******a...",
+"..******bbb********bbb******a...",
+".******bbbbb******bbbbb******a..",
+".*******bbbbb****bbbbb*******a..",
+"*********bbbbb**bbbbb*********a.",
+"**********bbbbbbbbbb**********a.",
+"***********bbbbbbbb***********aa",
+"************bbbbbb************aa",
+"************bbbbbb************aa",
+"***********bbbbbbbb***********aa",
+"**********bbbbbbbbbb**********aa",
+"*********bbbbb**bbbbb*********aa",
+".*******bbbbb****bbbbb*******aa.",
+".******bbbbb******bbbbb******aa.",
+"..******bbb********bbb******aaa.",
+"..*******b**********b*******aa..",
+"...************************aaa..",
+"....**********************aaa...",
+"....a********************aaa....",
+".....a******************aaa.....",
+"......a****************aaa......",
+".......aa************aaaa.......",
+".........aa********aaaaa........",
+"...........aaaaaaaaaaa..........",
+".............aaaaaaa............"};
+
+QPixmap KStyle::stylePixmap( StylePixmap stylepixmap,
+						  const QWidget* widget,
+						  const QStyleOption& opt) const
+{
+	switch (stylepixmap) {
+		case SP_TitleBarShadeButton:
+			return QPixmap(const_cast<const char**>(kstyle_shade_xpm));
+		case SP_TitleBarUnshadeButton:
+			return QPixmap(const_cast<const char**>(kstyle_unshade_xpm));
+		case SP_TitleBarNormalButton:
+			return QPixmap(const_cast<const char**>(kstyle_normalizeup_xpm));
+		case SP_TitleBarMinButton:
+			return QPixmap(const_cast<const char**>(kstyle_minimize_xpm));
+		case SP_TitleBarMaxButton:
+			return QPixmap(const_cast<const char**>(kstyle_maximize_xpm));
+		case SP_TitleBarCloseButton:
+			return QPixmap(const_cast<const char**>(kstyle_close_xpm));
+		case SP_DockWindowCloseButton:
+			return QPixmap(const_cast<const char**>(dock_window_close_xpm ));
+		case SP_MessageBoxInformation:
+			return QPixmap(const_cast<const char**>(information_xpm));
+		case SP_MessageBoxWarning:
+			return QPixmap(const_cast<const char**>(warning_xpm));
+		case SP_MessageBoxCritical:
+			return QPixmap(const_cast<const char**>(critical_xpm));
+		default:
+			break;
+    }
+    return QCommonStyle::stylePixmap(stylepixmap, widget, opt);
+}
+
+
+int KStyle::styleHint( StyleHint sh, const QWidget* w,
+					   const QStyleOption &opt, QStyleHintReturn* shr) const
+{
+	switch (sh)
+	{
+		case SH_EtchDisabledText:
+			return d->etchDisabledText ? 1 : 0;
+
+		case SH_PopupMenu_Scrollable:
+			return d->scrollablePopupmenus ? 1 : 0;
+
+		case SH_MenuBar_AltKeyNavigation:
+			return d->menuAltKeyNavigation ? 1 : 0;
+
+		case SH_PopupMenu_SubMenuPopupDelay:
+			if ( styleHint( SH_PopupMenu_SloppySubMenus, w ) )
+				return QMIN( 100, d->popupMenuDelay );
+			else
+				return d->popupMenuDelay;
+
+		case SH_PopupMenu_SloppySubMenus:
+			return d->sloppySubMenus;
+
+		case SH_ItemView_ChangeHighlightOnFocus:
+		case SH_Slider_SloppyKeyEvents:
+		case SH_MainWindow_SpaceBelowMenuBar:
+		case SH_PopupMenu_AllowActiveAndDisabled:
+			return 0;
+
+		case SH_Slider_SnapToValue:
+		case SH_PrintDialog_RightAlignButtons:
+		case SH_FontDialog_SelectAssociatedText:
+		case SH_MenuBar_MouseTracking:
+		case SH_PopupMenu_MouseTracking:
+		case SH_ComboBox_ListMouseTracking:
+		case SH_ScrollBar_MiddleClickAbsolutePosition:
+			return 1;
+
+		default:
+			return QCommonStyle::styleHint(sh, w, opt, shr);
+	}
+}
+
+
+bool KStyle::eventFilter( QObject* object, QEvent* event )
+{
+	if ( d->useFilledFrameWorkaround )
+	{
+		// Make the QMenuBar/QToolBar paintEvent() cover a larger area to
+		// ensure that the filled frame contents are properly painted.
+		// We essentially modify the paintEvent's rect to include the
+		// panel border, which also paints the widget's interior.
+		// This is nasty, but I see no other way to properly repaint
+		// filled frames in all QMenuBars and QToolBars.
+		// -- Karol.
+		QFrame *frame = 0;
+		if ( event->type() == QEvent::Paint
+				&& (frame = ::qt_cast<QFrame*>(object)) )
+		{
+			if (frame->frameShape() != QFrame::ToolBarPanel && frame->frameShape() != QFrame::MenuBarPanel)
+				return false;
+				
+			bool horizontal = true;
+			QPaintEvent* pe = (QPaintEvent*)event;
+			QToolBar *toolbar = ::qt_cast< QToolBar *>( frame );
+			QRect r = pe->rect();
+
+			if (toolbar && toolbar->orientation() == Qt::Vertical)
+				horizontal = false;
+
+			if (horizontal) {
+				if ( r.height() == frame->height() )
+					return false;	// Let QFrame handle the painting now.
+
+				// Else, send a new paint event with an updated paint rect.
+				QPaintEvent dummyPE( QRect( r.x(), 0, r.width(), frame->height()) );
+				QApplication::sendEvent( frame, &dummyPE );
+			}
+			else {	// Vertical
+				if ( r.width() == frame->width() )
+					return false;
+
+				QPaintEvent dummyPE( QRect( 0, r.y(), frame->width(), r.height()) );
+				QApplication::sendEvent( frame, &dummyPE );
+			}
+
+			// Discard this event as we sent a new paintEvent.
+			return true;
+		}
+	}
+
+	return false;
+}
+
+
+// -----------------------------------------------------------------------------
+// I N T E R N A L -  KStyle menu transparency handler
+// -----------------------------------------------------------------------------
+
+TransparencyHandler::TransparencyHandler( KStyle* style,
+	TransparencyEngine tEngine, float menuOpacity, bool useDropShadow )
+	: QObject()
+{
+	te = tEngine;
+	kstyle = style;
+	opacity = menuOpacity;
+	dropShadow = useDropShadow;
+	pix.setOptimization(QPixmap::BestOptim);
+}
+
+TransparencyHandler::~TransparencyHandler()
+{
+}
+
+// This is meant to be ugly but fast.
+void TransparencyHandler::rightShadow(QImage& dst)
+{
+	if (dst.depth() != 32)
+		dst = dst.convertDepth(32);
+
+	// blend top-right corner.
+	int pixels = dst.width() * dst.height();
+#ifdef WORDS_BIGENDIAN
+	register unsigned char* data = dst.bits() + 1;	// Skip alpha
+#else
+	register unsigned char* data = dst.bits();		// Skip alpha
+#endif
+	for(register int i = 0; i < 16; i++) {
+		*data++ = (unsigned char)((*data)*top_right_corner[i]);
+		*data++ = (unsigned char)((*data)*top_right_corner[i]);
+		*data++ = (unsigned char)((*data)*top_right_corner[i]);
+		data++;	// skip alpha
+	}
+
+	pixels -= 32;	// tint right strip without rounded edges.
+	register int c = 0;
+	for(register int i = 0; i < pixels; i++) {
+		*data++ = (unsigned char)((*data)*shadow_strip[c]);
+		*data++ = (unsigned char)((*data)*shadow_strip[c]);
+		*data++ = (unsigned char)((*data)*shadow_strip[c]);
+		data++; // skip alpha
+		c = ++c % 4;
+	}
+
+	// tint bottom edge
+	for(register int i = 0; i < 16; i++) {
+		*data++ = (unsigned char)((*data)*bottom_right_corner[i]);
+		*data++ = (unsigned char)((*data)*bottom_right_corner[i]);
+		*data++ = (unsigned char)((*data)*bottom_right_corner[i]);
+		data++;	// skip alpha
+	}
+}
+
+void TransparencyHandler::bottomShadow(QImage& dst)
+{
+	if (dst.depth() != 32)
+		dst = dst.convertDepth(32);
+
+	int line = 0;
+	int width = dst.width() - 4;
+	double strip_data = shadow_strip[0];
+	double* corner = const_cast<double*>(bottom_left_corner);
+
+#ifdef WORDS_BIGENDIAN
+	register unsigned char* data = dst.bits() + 1;	// Skip alpha
+#else
+	register unsigned char* data = dst.bits();	// Skip alpha
+#endif
+
+	for(int y = 0; y < 4; y++)
+	{
+		// Bottom-left Corner
+		for(register int x = 0; x < 4; x++) {
+			*data++ = (unsigned char)((*data)*(*corner));
+			*data++ = (unsigned char)((*data)*(*corner));
+			*data++ = (unsigned char)((*data)*(*corner));
+			data++; // skip alpha
+			corner++;
+		}
+
+		// Scanline
+		for(register int x = 0; x < width; x++) {
+			*data++ = (unsigned char)((*data)*strip_data);
+			*data++ = (unsigned char)((*data)*strip_data);
+			*data++ = (unsigned char)((*data)*strip_data);
+			data++;
+		}
+
+		strip_data = shadow_strip[++line];
+	}
+}
+
+// Create a shadow of thickness 4.
+void TransparencyHandler::createShadowWindows(const QPopupMenu* p)
+{
+#if defined Q_WS_X11 && ! defined K_WS_QTONLY
+	int x2 = p->x()+p->width();
+	int y2 = p->y()+p->height();
+	QRect shadow1(x2, p->y() + 4, 4, p->height());
+	QRect shadow2(p->x() + 4, y2, p->width() - 4, 4);
+
+	// Create a fake drop-down shadow effect via blended Xwindows
+	ShadowElements se;
+	se.w1 = new QWidget(0, 0, WStyle_Customize | WType_Popup | WX11BypassWM );
+	se.w2 = new QWidget(0, 0, WStyle_Customize | WType_Popup | WX11BypassWM );
+	se.w1->setGeometry(shadow1);
+	se.w2->setGeometry(shadow2);
+	XSelectInput(qt_xdisplay(), se.w1->winId(), StructureNotifyMask );
+	XSelectInput(qt_xdisplay(), se.w2->winId(), StructureNotifyMask );
+
+	// Insert a new ShadowMap entry
+	shadowMap()[p] = se;
+
+	// Some hocus-pocus here to create the drop-shadow.
+	QPixmap pix_shadow1 = QPixmap::grabWindow(qt_xrootwin(),
+			shadow1.x(), shadow1.y(), shadow1.width(), shadow1.height());
+	QPixmap pix_shadow2 = QPixmap::grabWindow(qt_xrootwin(),
+			shadow2.x(), shadow2.y(), shadow2.width(), shadow2.height());
+
+	QImage img;
+	img = pix_shadow1.convertToImage();
+	rightShadow(img);
+	pix_shadow1.convertFromImage(img);
+	img = pix_shadow2.convertToImage();
+	bottomShadow(img);
+	pix_shadow2.convertFromImage(img);
+
+	// Set the background pixmaps
+	se.w1->setErasePixmap(pix_shadow1);
+	se.w2->setErasePixmap(pix_shadow2);
+
+	// Show the 'shadow' just before showing the popup menu window
+	// Don't use QWidget::show() so we don't confuse QEffects, thus causing broken focus.
+	XMapWindow(qt_xdisplay(), se.w1->winId());
+	XMapWindow(qt_xdisplay(), se.w2->winId());
+#else
+	Q_UNUSED( p )
+#endif
+}
+
+void TransparencyHandler::removeShadowWindows(const QPopupMenu* p)
+{
+#if defined Q_WS_X11 && ! defined K_WS_QTONLY
+	ShadowMap::iterator it = shadowMap().find(p);
+	if (it != shadowMap().end())
+	{
+		ShadowElements se = it.data();
+		XUnmapWindow(qt_xdisplay(), se.w1->winId());	// hide
+		XUnmapWindow(qt_xdisplay(), se.w2->winId());
+		XFlush(qt_xdisplay());							// try to hide faster
+		delete se.w1;
+		delete se.w2;
+		shadowMap().erase(it);
+	}
+#else
+	Q_UNUSED( p )
+#endif
+}
+
+bool TransparencyHandler::eventFilter( QObject* object, QEvent* event )
+{
+#ifndef Q_WS_MAC
+	// Transparency idea was borrowed from KDE2's "MegaGradient" Style,
+	// Copyright (C) 2000 Daniel M. Duley <mosfet@kde.org>
+
+	// Added 'fake' menu shadows <04-Jul-2002> -- Karol
+	QPopupMenu* p = (QPopupMenu*)object;
+	QEvent::Type et = event->type();
+
+	if (et == QEvent::Show)
+	{
+		// Handle translucency
+		if (te != Disabled)
+		{
+			pix = QPixmap::grabWindow(qt_xrootwin(),
+					p->x(), p->y(), p->width(), p->height());
+
+			switch (te) {
+#ifdef HAVE_XRENDER
+				case XRender:
+					if (qt_use_xrender) {
+						XRenderBlendToPixmap(p);
+						break;
+					}
+					// Fall through intended
+#else
+				case XRender:
+#endif
+				case SoftwareBlend:
+					blendToPixmap(p->colorGroup(), p);
+					break;
+
+				case SoftwareTint:
+				default:
+					blendToColor(p->colorGroup().button());
+			};
+
+			p->setErasePixmap(pix);
+		}
+
+		// Handle drop shadow
+		// * FIXME : !shadowMap().contains(p) is a workaround for leftover
+		// * shadows after duplicate show events.
+		// * TODO : determine real cause for duplicate events
+		// * till 20021005
+		if (dropShadow && p->width() > 16 && p->height() > 16 && !shadowMap().contains( p ))
+			createShadowWindows(p);
+	}
+	else if (et == QEvent::Hide)
+	{
+		// Handle drop shadow
+		if (dropShadow)
+			removeShadowWindows(p);
+
+		// Handle translucency
+		if (te != Disabled)
+			p->setErasePixmap(QPixmap());
+	}
+
+#endif
+	return false;
+}
+
+
+// Blends a QImage to a predefined color, with a given opacity.
+void TransparencyHandler::blendToColor(const QColor &col)
+{
+	if (opacity < 0.0 || opacity > 1.0)
+		return;
+
+	QImage img = pix.convertToImage();
+	KImageEffect::blend(col, img, opacity);
+	pix.convertFromImage(img);
+}
+
+
+void TransparencyHandler::blendToPixmap(const QColorGroup &cg, const QPopupMenu* p)
+{
+	if (opacity < 0.0 || opacity > 1.0)
+		return;
+
+	KPixmap blendPix;
+	blendPix.resize( pix.width(), pix.height() );
+
+	if (blendPix.width()  != pix.width() ||
+		blendPix.height() != pix.height())
+		return;
+
+	// Allow styles to define the blend pixmap - allows for some interesting effects.
+	kstyle->renderMenuBlendPixmap( blendPix, cg, p );
+
+	QImage blendImg = blendPix.convertToImage();
+	QImage backImg  = pix.convertToImage();
+	KImageEffect::blend(blendImg, backImg, opacity);
+	pix.convertFromImage(backImg);
+}
+
+
+#ifdef HAVE_XRENDER
+// Here we go, use XRender in all its glory.
+// NOTE: This is actually a bit slower than the above routines
+// on non-accelerated displays. -- Karol.
+void TransparencyHandler::XRenderBlendToPixmap(const QPopupMenu* p)
+{
+	KPixmap renderPix;
+	renderPix.resize( pix.width(), pix.height() );
+
+	// Allow styles to define the blend pixmap - allows for some interesting effects.
+	kstyle->renderMenuBlendPixmap( renderPix, p->colorGroup(), p );
+
+	Display* dpy = qt_xdisplay();
+	Pixmap   alphaPixmap;
+	Picture  alphaPicture;
+	XRenderPictFormat        Rpf;
+	XRenderPictureAttributes Rpa;
+	XRenderColor clr;
+	clr.alpha = ((unsigned short)(255*opacity) << 8);
+
+	Rpf.type  = PictTypeDirect;
+	Rpf.depth = 8;
+	Rpf.direct.alphaMask = 0xff;
+	Rpa.repeat = True;	// Tile
+
+	XRenderPictFormat* xformat = XRenderFindFormat(dpy,
+		PictFormatType | PictFormatDepth | PictFormatAlphaMask, &Rpf, 0);
+
+	alphaPixmap = XCreatePixmap(dpy, p->handle(), 1, 1, 8);
+	alphaPicture = XRenderCreatePicture(dpy, alphaPixmap, xformat, CPRepeat, &Rpa);
+
+	XRenderFillRectangle(dpy, PictOpSrc, alphaPicture, &clr, 0, 0, 1, 1);
+
+	XRenderComposite(dpy, PictOpOver,
+			renderPix.x11RenderHandle(), alphaPicture, pix.x11RenderHandle(), // src, mask, dst
+			0, 0, 	// srcx,  srcy
+			0, 0,	// maskx, masky
+			0, 0,	// dstx,  dsty
+			pix.width(), pix.height());
+
+	XRenderFreePicture(dpy, alphaPicture);
+	XFreePixmap(dpy, alphaPixmap);
+}
+#endif
+
+void KStyle::virtual_hook( int, void* )
+{ /*BASE::virtual_hook( id, data );*/ }
+
+// vim: set noet ts=4 sw=4:
+// kate: indent-width 4; replace-tabs off; tab-width 4; space-indent off;
+
+#include "kstyle.moc"
--- widget-engine/kstyle.h
+++ widget-engine/kstyle.h
@@ -0,0 +1,342 @@
+/*
+ * $Id: kstyle.h,v 1.15 2003/10/07 22:40:42 mueller Exp $
+ * 
+ * KStyle
+ * Copyright (C) 2001-2002 Karol Szwed <gallium@kde.org>
+ * 
+ * QWindowsStyle CC_ListView and style images were kindly donated by TrollTech,
+ * Copyright (C) 1998-2000 TrollTech AS.
+ * 
+ * Many thanks to Bradley T. Hughes for the 3 button scrollbar code.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License version 2 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __KSTYLE_H
+#define __KSTYLE_H
+
+// W A R N I N G
+// -------------
+// This API is still subject to change.
+// I will remove this warning when I feel the API is sufficiently flexible.
+
+#include <qcommonstyle.h>
+
+class KPixmap;
+
+class KStylePrivate;
+/** 
+ * Simplifies and extends the QStyle API to make style coding easier.
+ *  
+ * The KStyle class provides a simple internal menu transparency engine
+ * which attempts to use XRender for accelerated blending where requested,
+ * or falls back to fast internal software tinting/blending routines.
+ * It also simplifies more complex portions of the QStyle API, such as
+ * the PopupMenuItems, ScrollBars and Sliders by providing extra "primitive
+ * elements" which are simple to implement by the style writer.
+ *
+ * @see QStyle::QStyle
+ * @see QCommonStyle::QCommonStyle
+ * @author Karol Szwed (gallium@kde.org)
+ * @version $Id: kstyle.h,v 1.15 2003/10/07 22:40:42 mueller Exp $
+ */
+class KStyle: public QCommonStyle
+{
+	Q_OBJECT
+
+	public:
+
+		/**
+		 * KStyle Flags:
+		 * 
+		 * @li Default - Default style setting, where menu transparency
+		 * and the FilledFrameWorkaround are disabled.
+		 * 
+		 * @li AllowMenuTransparency - Enable this flag to use KStyle's 
+		 * internal menu transparency engine.
+		 * 
+		 * @li FilledFrameWorkaround - Enable this flag to facilitate 
+		 * proper repaints of QMenuBars and QToolBars when the style chooses 
+		 * to paint the interior of a QFrame. The style primitives in question 
+		 * are PE_PanelMenuBar and PE_PanelDockWindow. The HighColor style uses
+		 * this workaround to enable painting of gradients in menubars and 
+		 * toolbars.
+		 */
+		typedef uint KStyleFlags;
+		enum KStyleOption {
+			Default 	      =		0x00000000, //!< All options disabled
+			AllowMenuTransparency =		0x00000001, //!< Internal transparency enabled
+			FilledFrameWorkaround = 	0x00000002  //!< Filled frames enabled
+		};
+
+		/**
+		 * KStyle ScrollBarType:
+		 *
+		 * Allows the style writer to easily select what type of scrollbar
+		 * should be used without having to duplicate large amounts of source
+		 * code by implementing the complex control CC_ScrollBar.
+		 *
+		 * @li WindowsStyleScrollBar - Two button scrollbar with the previous
+		 * button at the top/left, and the next button at the bottom/right.
+		 *
+		 * @li PlatinumStyleScrollBar - Two button scrollbar with both the 
+		 * previous and next buttons at the bottom/right.
+		 *
+		 * @li ThreeButtonScrollBar - %KDE style three button scrollbar with
+		 * two previous buttons, and one next button. The next button is always
+		 * at the bottom/right, whilst the two previous buttons are on either 
+		 * end of the scrollbar.
+		 *
+		 * @li NextStyleScrollBar - Similar to the PlatinumStyle scroll bar, but
+		 * with the buttons grouped on the opposite end of the scrollbar.
+		 *
+		 * @see KStyle::KStyle()
+		 */
+		enum KStyleScrollBarType {
+			WindowsStyleScrollBar  = 	0x00000000, //!< two button, windows style
+			PlatinumStyleScrollBar = 	0x00000001, //!< two button, platinum style
+			ThreeButtonScrollBar   = 	0x00000002, //!< three buttons, %KDE style
+			NextStyleScrollBar     = 	0x00000004  //!< two button, NeXT style
+		};
+
+		/** 
+		 * Constructs a KStyle object.
+		 *
+		 * Select the appropriate KStyle flags and scrollbar type
+		 * for your style. The user's style preferences selected in KControl
+		 * are read by using QSettings and are automatically applied to the style.
+		 * As a fallback, KStyle paints progressbars and tabbars. It inherits from
+		 * QCommonStyle for speed, so don't expect much to be implemented. 
+		 *
+		 * It is advisable to use a currently implemented style such as the HighColor
+		 * style as a foundation for any new KStyle, so the limited number of
+		 * drawing fallbacks should not prove problematic.
+		 *
+		 * @param flags the style to be applied
+		 * @param sbtype the scroll bar type
+		 * @see KStyle::KStyleFlags
+		 * @see KStyle::KStyleScrollBarType
+		 * @author Karol Szwed (gallium@kde.org)
+		 */
+		KStyle( KStyleFlags flags = KStyle::Default, 
+			KStyleScrollBarType sbtype = KStyle::WindowsStyleScrollBar );
+
+		/** 
+		 * Destructs the KStyle object.
+		 */
+		~KStyle();
+
+		/**
+		 * Returns the default widget style depending on color depth.
+		 */
+		static QString defaultStyle();
+
+		/**
+		 * Modifies the scrollbar type used by the style.
+		 * 
+		 * This function is only provided for convenience. It allows
+		 * you to make a late decision about what scrollbar type to use for the
+		 * style after performing some processing in your style's constructor.
+		 * In most situations however, setting the scrollbar type via the KStyle
+		 * constructor should suffice.
+		 * @param sbtype the scroll bar type
+		 * @see KStyle::KStyleScrollBarType
+		 */
+		void setScrollBarType(KStyleScrollBarType sbtype);
+
+		/**
+		 * Returns the KStyle flags used to initialize the style.
+		 *
+		 * This is used solely for the kcmstyle module, and hence is internal.
+		 */
+		KStyleFlags styleFlags() const;
+
+		// ---------------------------------------------------------------------------
+
+		/**
+		 * This virtual function defines the pixmap used to blend between the popup
+		 * menu and the background to create different menu transparency effects.
+		 * For example, you can fill the pixmap "pix" with a gradient based on the
+		 * popup's colorGroup, a texture, or some other fancy painting routine.
+		 * KStyle will then internally blend this pixmap with a snapshot of the
+		 * background behind the popupMenu to create the illusion of transparency.
+		 * 
+		 * This virtual is never called if XRender/Software blending is disabled by
+		 * the user in KDE's style control module.
+		 */
+		virtual void renderMenuBlendPixmap( KPixmap& pix, const QColorGroup& cg, 
+						    const QPopupMenu* popup ) const;
+
+		/**
+		 * KStyle Primitive Elements:
+		 *
+		 * The KStyle class extends the Qt's Style API by providing certain 
+		 * simplifications for parts of QStyle. To do this, the KStylePrimitive
+		 * elements were defined, which are very similar to Qt's PrimitiveElement.
+		 * 
+		 * The first three Handle primitives simplify and extend PE_DockWindowHandle, 
+		 * so do not reimplement PE_DockWindowHandle if you want the KStyle handle 
+		 * simplifications to be operable. Similarly do not reimplement CC_Slider,
+		 * SC_SliderGroove and SC_SliderHandle when using the KStyle slider
+		 * primitives. KStyle automatically double-buffers slider painting
+		 * when they are drawn via these KStyle primitives to avoid flicker.
+		 *
+		 * @li KPE_DockWindowHandle - This primitive is already implemented in KStyle,
+		 * and paints a bevelled rect with the DockWindow caption text. Re-implement
+		 * this primitive to perform other more fancy effects when drawing the dock window
+		 * handle.
+		 *
+		 * @li KPE_ToolBarHandle - This primitive must be reimplemented. It currently
+		 * only paints a filled rectangle as default behavior. This primitive is used
+		 * to render QToolBar handles.
+		 *
+		 * @li KPE_GeneralHandle - This primitive must be reimplemented. It is used
+		 * to render general handles that are not part of a QToolBar or QDockWindow, such
+		 * as the applet handles used in Kicker. The default implementation paints a filled
+		 * rect of arbitrary color.
+		 *
+		 * @li KPE_SliderGroove - This primitive must be reimplemented. It is used to 
+		 * paint the slider groove. The default implementation paints a filled rect of
+		 * arbitrary color.
+		 *
+		 * @li KPE_SliderHandle - This primitive must be reimplemented. It is used to
+		 * paint the slider handle. The default implementation paints a filled rect of
+		 * arbitrary color.
+		 *
+		 * @li KPE_ListViewExpander - This primitive is already implemented in KStyle. It
+		 * is used to draw the Expand/Collapse element in QListViews. To indicate the 
+		 * expanded state, the style flags are set to Style_Off, while Style_On implies collapsed.
+		 *
+		 * @li KPE_ListViewBranch - This primitive is already implemented in KStyle. It is
+		 * used to draw the ListView branches where necessary.
+		 */
+		enum KStylePrimitive {
+			KPE_DockWindowHandle,
+			KPE_ToolBarHandle,
+			KPE_GeneralHandle,
+
+			KPE_SliderGroove,
+			KPE_SliderHandle,
+
+			KPE_ListViewExpander,
+			KPE_ListViewBranch
+		};
+
+		/**
+		 * This function is identical to Qt's QStyle::drawPrimitive(), except that 
+		 * it adds one further parameter, 'widget', that can be used to determine 
+		 * the widget state of the KStylePrimitive in question.
+		 *
+		 * @see KStyle::KStylePrimitive
+		 * @see QStyle::drawPrimitive
+		 * @see QStyle::drawComplexControl
+		 */
+		virtual void drawKStylePrimitive( KStylePrimitive kpe,
+					QPainter* p,
+					const QWidget* widget,
+					const QRect &r,
+					const QColorGroup &cg,
+					SFlags flags = Style_Default,
+					const QStyleOption& = QStyleOption::Default ) const;
+
+
+		enum KStylePixelMetric {
+			KPM_MenuItemSeparatorHeight		= 0x00000001,
+			KPM_MenuItemHMargin			= 0x00000002,
+			KPM_MenuItemVMargin			= 0x00000004,
+			KPM_MenuItemHFrame			= 0x00000008,
+			KPM_MenuItemVFrame			= 0x00000010,
+			KPM_MenuItemCheckMarkHMargin	        = 0x00000020,
+			KPM_MenuItemArrowHMargin		= 0x00000040,
+			KPM_MenuItemTabSpacing			= 0x00000080,
+			KPM_ListViewBranchThickness		= 0x00000100
+		};
+
+		int kPixelMetric( KStylePixelMetric kpm, const QWidget* widget = 0 ) const;
+
+		// ---------------------------------------------------------------------------
+
+		void polish( QWidget* widget );
+		void unPolish( QWidget* widget );
+		void polishPopupMenu( QPopupMenu* );
+
+		void drawPrimitive( PrimitiveElement pe,
+					QPainter* p,
+					const QRect &r,
+					const QColorGroup &cg,
+					SFlags flags = Style_Default,
+					const QStyleOption& = QStyleOption::Default ) const;
+
+		void drawControl( ControlElement element,
+					QPainter* p,
+					const QWidget* widget,
+					const QRect &r,
+					const QColorGroup &cg,
+					SFlags flags = Style_Default,
+					const QStyleOption& = QStyleOption::Default ) const;
+
+		void drawComplexControl( ComplexControl control,
+					QPainter *p,
+					const QWidget* widget,
+					const QRect &r,
+					const QColorGroup &cg,
+					SFlags flags = Style_Default,
+					SCFlags controls = SC_All,
+					SCFlags active = SC_None,
+					const QStyleOption& = QStyleOption::Default ) const;
+
+		SubControl querySubControl( ComplexControl control,
+					const QWidget* widget,
+					const QPoint &pos,
+					const QStyleOption& = QStyleOption::Default ) const;
+
+		QRect querySubControlMetrics( ComplexControl control,
+					const QWidget* widget,
+					SubControl sc,
+					const QStyleOption& = QStyleOption::Default ) const;
+
+		int pixelMetric( PixelMetric m, 
+					const QWidget* widget = 0 ) const;
+
+		QRect subRect( SubRect r, 
+					const QWidget* widget ) const;
+
+		QPixmap stylePixmap( StylePixmap stylepixmap,
+					const QWidget* widget = 0,
+					const QStyleOption& = QStyleOption::Default ) const;
+
+		int styleHint( StyleHint sh, 
+					const QWidget* w = 0,
+					const QStyleOption &opt = QStyleOption::Default,
+					QStyleHintReturn* shr = 0 ) const;
+
+	protected:
+		bool eventFilter( QObject* object, QEvent* event );
+
+	private:
+		// Disable copy constructor and = operator
+		KStyle( const KStyle & );
+		KStyle& operator=( const KStyle & );
+
+	protected:
+		virtual void virtual_hook( int id, void* data );
+	private:
+		KStylePrivate *d;
+};
+
+
+// vim: set noet ts=4 sw=4:
+#endif
+
openSUSE Build Service is sponsored by