//////////////////////////////////////////////////////////////////////////////
// polyester.cc
// -------------------
// Polyester window decoration for KDE
// Copyright (c) 2006 Marco Martin
// -------------------
// derived from Smooth Blend
// Copyright (c) 2005 Ryan Nickell
// -------------------
// Shadow engine from Plastik decoration
// Copyright (C) 2003 Sandro Giessl <ceebx@users.sourceforge.net>
// -------------------
// Please see the header file for copyright and license information.
//////////////////////////////////////////////////////////////////////////////


#include <tdeconfig.h>
#include <tdeversion.h>
#include <tdeglobal.h>
#include <tdeglobalsettings.h>
#include <tdelocale.h>
#include <kpixmap.h>
#include <kimageeffect.h>
#include <kpixmapeffect.h>
#include <kpixmap.h>

#include <tqbitmap.h>
#include <tqlabel.h>
#include <tqlayout.h>
#include <tqpainter.h>
#include <tqtooltip.h>
#include <tqtimer.h>
#include <tqapplication.h>
#include <tqsettings.h>
#include <math.h>
#include <stdlib.h>

#include "polyester.h"
#include "buttons.h"
#include "shadow.h"
#include "../style/misc.h"

using namespace polyester;

//////////////////////////////////////////////////////////////////////////////
// polyesterFactory Class
//////////////////////////////////////////////////////////////////////////////
polyesterFactory* factory=NULL;

bool polyesterFactory::initialized_              = false;
TQt::AlignmentFlags polyesterFactory::titlealign_ = TQt::AlignHCenter;
int polyesterFactory::contrast_                  = 6;
bool polyesterFactory::cornerflags_              = true;
int polyesterFactory::titlesize_                 = 22;
int polyesterFactory::buttonsize_                = 18;
bool polyesterFactory::squareButton_             = false;
int polyesterFactory::framesize_                 = 2;
int polyesterFactory::roundsize_                 = 50;
int polyesterFactory::titleBarStyle_             = 0;
int polyesterFactory::buttonStyle_               = 1;
bool polyesterFactory::titleshadow_              = true;
bool polyesterFactory::nomodalbuttons            = false;
bool polyesterFactory::lightBorder_              = true;
bool polyesterFactory::animatebuttons            = true;
int polyesterFactory::btnComboBox                = 0;
bool polyesterFactory::menuClose                 = false;

// global constants
static const int TOPMARGIN       = 4; // do not change
static const int DECOHEIGHT      = 4; // do not change
static const int SIDETITLEMARGIN = 2;
// Default button layout
const char default_left[]  = "M";
const char default_right[] = "HIAX";

static const uint TIMERINTERVAL = 25; // msec
static const uint ANIMATIONSTEPS = 20;

extern "C" KDE_EXPORT KDecorationFactory* create_factory() {
    return new polyester::polyesterFactory();
}

//////////////////////////////////////////////////////////////////////////////
// polyesterFactory()
// ----------------
// Constructor

polyesterFactory::polyesterFactory() {
    readConfig();
    initialized_ = true;
}

//////////////////////////////////////////////////////////////////////////////
// ~polyesterFactory()
// -----------------
// Destructor

polyesterFactory::~polyesterFactory() {
    initialized_ = false;
}

//////////////////////////////////////////////////////////////////////////////
// createDecoration()
// -----------------
// Create the decoration

KDecoration* polyesterFactory::createDecoration(KDecorationBridge* b) {
    return new polyesterClient(b, this);
}

//////////////////////////////////////////////////////////////////////////////
// reset()
// -------
// Reset the handler. Returns true if decorations need to be remade, false if
// only a repaint is necessary

bool polyesterFactory::reset(unsigned long changed) {
    // read in the configuration
    initialized_ = false;
    bool confchange = readConfig();
    initialized_ = true;

    if (confchange ||
            (changed & (SettingDecoration | SettingButtons | SettingBorder))) {
        return true;
    } else {
        resetDecorations(changed);
        return false;
    }
}

//////////////////////////////////////////////////////////////////////////////
// readConfig()
// ------------
// Read in the configuration file

bool polyesterFactory::readConfig() {
    // create a config object
    TDEConfig config("twinpolyesterrc");
    config.setGroup("General");

    // grab settings
    TQString value = config.readEntry("TitleAlignment", "AlignHCenter");
    if (value == "AlignLeft")
        titlealign_ = TQt::AlignLeft;
    else if (value == "AlignHCenter")
        titlealign_ = TQt::AlignHCenter;
    else if (value == "AlignRight")
        titlealign_ = TQt::AlignRight;

    TQSettings globalSettings;
    contrast_ = globalSettings.readNumEntry("/TQt/KDE/contrast", 6);
    cornerflags_ = config.readBoolEntry("RoundCorners", true);
    titlesize_ = config.readNumEntry("TitleSize",20);
    titleBarStyle_ = config.readNumEntry("TitleBarStyle", 0);
    buttonStyle_ = config.readNumEntry("ButtonStyle", 1);

    buttonsize_ = config.readNumEntry("ButtonSize",18);
    squareButton_ = config.readBoolEntry("SquareButton", false);
    framesize_ = config.readNumEntry("FrameSize",2);
    roundsize_ = config.readNumEntry("RoundPercent",50);


    titleshadow_ = config.readBoolEntry("TitleShadow", true);
    lightBorder_ = config.readBoolEntry("LightBorder", true);
    animatebuttons = config.readBoolEntry("AnimateButtons", true);
    nomodalbuttons = config.readBoolEntry("NoModalButtons", false);
    btnComboBox = config.readNumEntry("ButtonComboBox", 0);
    menuClose = config.readBoolEntry("CloseOnMenuDoubleClick");

    if(buttonsize_ > titlesize_ - framesize_)
    {
        buttonsize_ = titlesize_-framesize_;
    }

    return true;
}

//////////////////////////////////////////////////////////////////////////////
// polyesterButton Class 
//////////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////////
// polyesterButton()
// ---------------
// Constructor
polyesterButton::polyesterButton(polyesterClient *parent, const char *name, const TQString& tip, ButtonType type, int button_size, bool squareButton, bool toggle): TQButton(parent->widget(), name), 
     client_(parent), 
     type_(type), 
     size_(button_size),
     deco_(0), 
     lastmouse_(NoButton),
     buttonImgActive_created(false),
     buttonImgInactive_created(false),
     hover_(false)
{
    setBackgroundMode(NoBackground);

    int buttonWidth = button_size;
    if( squareButton )
      buttonProportions_ = 1;
    else
    {
      buttonProportions_ = sqrt(2);
      buttonWidth = (int)round(button_size*buttonProportions_);
      //makes always centered icons
      if( buttonWidth % 2 != 0 )
        buttonWidth++;
    }

    setFixedSize( buttonWidth, button_size);
    setCursor(arrowCursor);
    TQToolTip::add(this, tip);
    setToggleButton(toggle);
    //button animation setup
    animTmr = new TQTimer(this);
    connect(animTmr, TQ_SIGNAL(timeout() ), this, TQ_SLOT(animate() ) );
    connect(this, TQ_SIGNAL(pressed() ), this, TQ_SLOT(buttonClicked() ) );
    connect(this, TQ_SIGNAL(released() ), this, TQ_SLOT(buttonReleased() ) );
    animProgress = 0;
    m_clicked=false;
}

polyesterButton::~polyesterButton() {
    if ( deco_ )
        delete deco_;
}

//////////////////////////////////////////////////////////////////////////////
// sizeHint()
// ----------
// Return size hint

TQSize polyesterButton::sizeHint() const {
    return TQSize(size_, size_);
}

//////////////////////////////////////////////////////////////////////////////
// buttonClicked()
// ----------
// Button animation progress reset so we don't get any leave event animation
// when the mouse is still pressed
void polyesterButton::buttonClicked() {
    m_clicked=true;
    animProgress=0;
}
void polyesterButton::buttonReleased() {
    //This doesn't work b/c a released() TQ_SIGNAL is thrown when a leaveEvent occurs
    //m_clicked=false;
}

//////////////////////////////////////////////////////////////////////////////
// animate()
// ----------
// Button animation timing
void polyesterButton::animate() {
    animTmr->stop();
    if (!::factory->animateButtons() )
      return;

    if(hover_) {
        if(animProgress < ANIMATIONSTEPS) {
            animProgress++;
            animTmr->start(TIMERINTERVAL, true); // single-shot
        }
    } else {
        if(animProgress > 0) {
            animProgress--;
            animTmr->start(TIMERINTERVAL, true); // single-shot
        }
    }
    repaint(false);
}
//////////////////////////////////////////////////////////////////////////////
// enterEvent()
// ------------
// Mouse has entered the button

void polyesterButton::enterEvent(TQEvent *e) {
    // we wanted to pass on the event
    TQButton::enterEvent(e);
    // we want to do mouseovers, so keep track of it here
    hover_=true;
    if(!m_clicked)
    {
        animate();
    }
}

//////////////////////////////////////////////////////////////////////////////
// leaveEvent()
// ------------
// Mouse has left the button

void polyesterButton::leaveEvent(TQEvent *e) {
    // we wanted to pass on the event
    TQButton::leaveEvent(e);
    // we want to do mouseovers, so keep track of it here
    hover_=false; 
    if(!m_clicked)
    {
        animate();
    }
}

//////////////////////////////////////////////////////////////////////////////
// mousePressEvent()
// -----------------
// Button has been pressed

void polyesterButton::mousePressEvent(TQMouseEvent* e) {
    lastmouse_ = e->button();

    // translate and pass on mouse event
    int button = LeftButton;
    if ((type_ != ButtonMax) && (e->button() != LeftButton)) {
        button = NoButton; // middle & right buttons inappropriate
    }
    TQMouseEvent me(e->type(), e->pos(), e->globalPos(),
                   button, e->state());
    TQButton::mousePressEvent(&me);
}

//////////////////////////////////////////////////////////////////////////////
// mouseReleaseEvent()
// -----------------
// Button has been released

void polyesterButton::mouseReleaseEvent(TQMouseEvent* e) {
    lastmouse_ = e->button();

    // translate and pass on mouse event
    int button = LeftButton;
    if ((type_ != ButtonMax) && (e->button() != LeftButton)) {
        button = NoButton; // middle & right buttons inappropriate
    }
    TQMouseEvent me(e->type(), e->pos(), e->globalPos(), button, e->state());
    TQButton::mouseReleaseEvent(&me);
    if(m_clicked)
    {
        m_clicked=false;
    }
}

void polyesterButton::setOn(bool on)
{
    TQButton::setOn(on);
}

void polyesterButton::setDown(bool on)
{
    TQButton::setDown(on);
}

//////////////////////////////////////////////////////////
// getButtonImage()
// ----------------
// get the button TQImage based on type and window mode
TQImage polyesterButton::getButtonImage(ButtonType type)
{
    TQImage finalImage;
    switch(type) {
        case ButtonClose:
            finalImage = uic_findImage( "close.png" );
            break;
        case ButtonHelp:
            finalImage = uic_findImage( "help.png" );
            break;
        case ButtonMin:
            finalImage = uic_findImage( "minimize.png" );
            break;
        case ButtonMax:
            if(client_->maximizeMode() == KDecorationDefines::MaximizeFull)
            {
                finalImage = uic_findImage( "restore.png" );
            }
            else
            {
                finalImage = uic_findImage( "maximize.png" );
            }
            break;
        case ButtonSticky:
            if(client_->isOnAllDesktops())
            {
                finalImage = uic_findImage( "circle2.png" );
            }
            else
            {
                finalImage = uic_findImage( "circle.png" );
            }
            break;
        case ButtonShade:
            if(client_->isShade())
            {
                finalImage = uic_findImage( "unsplat.png" );
            }
            else
            {
                finalImage = uic_findImage( "splat.png" );
            }
            break;
        case ButtonAbove:
            if(client_->keepAbove())
            {
                finalImage = uic_findImage( "keep_above_lit.png" );
            }
            else
            {
                finalImage = uic_findImage( "keep_above.png" );
            }
            break;
        case ButtonBelow:
            if(client_->keepBelow())
            {
                finalImage = uic_findImage( "keep_below_lit.png" );
            }
            else
            {
                finalImage = uic_findImage( "keep_below.png" );
            }
            break;
        default:
            finalImage = uic_findImage( "splat.png" );
            break;
    }
    if(tqGray(KDecoration::options()->color(KDecoration::ColorButtonBg, client_->isActive()).rgb()) < 150)
        finalImage.invertPixels();

    return finalImage;
}

//////////////////////////////////////////////////////////
// drawButton()
// -------------------------
// draw the pixmap button

void polyesterButton::drawButton( TQPainter *painter ) {
    if ( !polyesterFactory::initialized() )
        return ;

    int newWidth = width() - 2;
    int newHeight = height() - 2;
    int dx = (width() - newWidth) / 2;
    int dy = (height() - newHeight) / 2;
    TQImage tmpResult;
    TQColorGroup group;
    TQColor redColor(red);
    bool active = client_->isActive();

    genButtonPix(active);

    TQPixmap backgroundTile = client_->getTitleBarTile(active);
    group = KDecoration::options()->colorGroup(KDecoration::ColorButtonBg, active);

    //draw the titlebar behind the buttons and app icons
    if ((client_->maximizeMode()==client_->MaximizeFull) && !KDecoration::options()->moveResizeMaximizedWindows())
    {
        painter->drawTiledPixmap(0, 0, width(), height(), backgroundTile, 0, 1);
    }
    else
    {
        painter->drawTiledPixmap(0, 0, width(), height(), backgroundTile,
                                 0, y()-::factory->frameSize());
    }

    //the menu button doesn't have a button appearance
    if (type_ == ButtonMenu)
    {
      //slight movement to show the menu button is depressed
      if (isDown()) {
          dx++;
          dy++;
      }
      TQPixmap menuButtonPixmap(client_->icon().pixmap(TQIconSet::Small, TQIconSet::Normal));
      TQImage menuButtonImage(menuButtonPixmap.convertToImage());
      //draw the menu button the same size as the other buttons
      //using TQIconSet::Large gives us a 32x32 icon to resize, resizing larger than
      //that may produce pixilation of the image
      //painter->setPen(group.background());

      painter->drawImage( dx+(int)round(abs(width()-size_)/2), dy, menuButtonImage.smoothScale(size_-2, newHeight) );
      return;
    }

    //build the button image with the icon superimposed to the button
    TQImage buttonImage = (active?(buttonImgActive):(buttonImgInactive))->copy();
    KImageEffect::blendOnLower( (int)round(abs(width()-size_)/2), 0,
                                getButtonImage(type_).smoothScale( size_,size_),
                                buttonImage );

    //highlight on a mouse over repaint
    double factor = animProgress * 0.05;//0.13;

    //do the animation thing
    if( !isDown() && factor != 0.0 )
    {
      tmpResult = buttonImage.copy();
      //always colorize with a threatening red color the close button
      if( type_ == ButtonClose)
      {
        //tmpResult = KImageEffect::blend( TQColor(180, 50, 50), buttonImage, factor );
        KImageEffect::desaturate( tmpResult, factor );
        KImageEffect::channelIntensity( tmpResult, factor/3, KImageEffect::Red );
        KImageEffect::channelIntensity( tmpResult, -factor/2, KImageEffect::Green );
        KImageEffect::channelIntensity( tmpResult, -factor/2, KImageEffect::Blue );
      }
      else
          switch(::factory->getBtnComboBox())
          {
              //colorize
              case 0:
                  if( type_ == ButtonMax)
                  {
                    KImageEffect::desaturate( tmpResult, factor );
                    KImageEffect::channelIntensity( tmpResult, -factor/3, KImageEffect::Red );
                    KImageEffect::channelIntensity( tmpResult, factor/2, KImageEffect::Green );
                    KImageEffect::channelIntensity( tmpResult, -factor/3, KImageEffect::Blue );
                  }
                  else if( type_ == ButtonMin)
                  {
                    KImageEffect::desaturate( tmpResult, factor );
                    KImageEffect::channelIntensity( tmpResult, factor/4, KImageEffect::Red );
                    KImageEffect::channelIntensity( tmpResult, factor/4, KImageEffect::Green );
                    KImageEffect::channelIntensity( tmpResult, -factor/2, KImageEffect::Blue );
                  }
                  else if( type_ == ButtonSticky)
                  {
                    KImageEffect::desaturate( tmpResult, factor );
                    KImageEffect::channelIntensity( tmpResult, -factor/3, KImageEffect::Red );
                    KImageEffect::channelIntensity( tmpResult, -factor/3, KImageEffect::Green );
                    KImageEffect::channelIntensity( tmpResult, factor/2, KImageEffect::Blue );
                  }
                  else
                  {
                    KImageEffect::desaturate( tmpResult, factor );
                    KImageEffect::channelIntensity( tmpResult, -factor/2, KImageEffect::Red );
                    KImageEffect::channelIntensity( tmpResult, factor/3, KImageEffect::Green );
                    KImageEffect::channelIntensity( tmpResult, factor/3, KImageEffect::Blue );
                  }
                  break;
              //intensify
              case 1:
                  KImageEffect::intensity( tmpResult, factor);
                  break;
              //fade
              case 2:
                  KImageEffect::intensity( tmpResult, -factor/2);

                  break;
          }
    }

    KImageEffect::blendOnLower(tmpResult, TQPoint(1,1), buttonImage, TQRect(1,1,width()-2, height()-2) );

    TQPixmap finalButton = TQPixmap(buttonImage);

    painter->drawPixmap( 0, 0, finalButton );
}

void polyesterButton::genButtonPix( bool active )
{
 if(active && buttonImgActive_created) return;
 else if(!active && buttonImgInactive_created) return;

 KPixmap tempPixmap;
 TQPixmap *tempButton = new TQPixmap(width(), height());
 TQPainter painter(tempButton);

 TQColorGroup group;
 group = KDecoration::options()->colorGroup(KDecoration::ColorButtonBg, client_->isActive());

 if( ::factory->buttonStyle() == BUTTON_GLASS )
    tempPixmap.resize(width()-2, (height()/2)-1);
 else
    tempPixmap.resize(width()-2, height()-2);

 /*
 if(  ::factory->buttonStyle() != BUTTON_FLAT  )
 {
  tempPixmap = KPixmapEffect::gradient(tempPixmap,
                                       group.background().light(100+(::factory->buttonStyle()!=BUTTON_REVGRADIENT?60:-20)),
                                       group.background().light(100+(::factory->buttonStyle()!=BUTTON_GLASS?
                                                                       (::factory->buttonStyle()==BUTTON_REVGRADIENT?
                                                                          60:-20)
                                                                       :0)),
                                       KPixmapEffect::VerticalGradient
                                      );
 }
 else
 {
  tempPixmap = KPixmapEffect::gradient(tempPixmap,
                                       group.background(),
                                       group.background(),
                                       KPixmapEffect::VerticalGradient
                                      );
 }
*/

 int contrast = ::factory->contrast();

 switch( ::factory->buttonStyle() )
 {
   case BUTTON_GRADIENT:
       tempPixmap = KPixmapEffect::gradient(tempPixmap,
                                       group.background().light(105+contrast*8),
                                       group.background().dark(100+contrast*2),
                                       KPixmapEffect::VerticalGradient
                                      );
     break;
   case BUTTON_GLASS:
       tempPixmap = KPixmapEffect::gradient(tempPixmap,
                                       group.background().light(105+contrast*8),
                                       group.background(),
                                       KPixmapEffect::VerticalGradient
                                      );
     break;
   case BUTTON_REVGRADIENT:
       tempPixmap = KPixmapEffect::gradient(tempPixmap,
                                       group.background().dark(100+contrast*2),
                                       group.background().light(105+contrast*8),
                                       KPixmapEffect::VerticalGradient
                                      );
     break;

   //case BUTTON_FLAT:
   default:
       tempPixmap = KPixmapEffect::gradient(tempPixmap,
                                       group.background(),
                                       group.background(),
                                       KPixmapEffect::VerticalGradient
                                      );
     break;
 }

 //draw the main area of the buttons
 //painter.begin(tempButton);
 painter.drawPixmap(1, 1, tempPixmap);

 //if the button is glass create the second gradient
 if( ::factory->buttonStyle() == BUTTON_GLASS )
 {
    tempPixmap = KPixmapEffect::gradient(tempPixmap,
                                        group.background().dark(105+contrast),
                                        group.background(),
                                        KPixmapEffect::VerticalGradient
                                       );

    painter.drawPixmap(1, (height()/2), tempPixmap);
  }

 //border
 TQColor borderColor = group.background().dark(160);
 painter.setPen( borderColor );
 painter.drawLine(0, 2, 0, height()-3);
 painter.drawLine(width()-1, 2, width()-1, height()-3);
 painter.drawLine(2, 0, width()-3, 0);
 painter.drawLine(2, height()-1, width()-3, height()-1);
 painter.drawPoint(1, 1);
 painter.drawPoint(width()-2, 1);
 painter.drawPoint(1, height()-2);
 painter.drawPoint(width()-2, height()-2);

 //little 3d effect
 painter.setPen( group.background().light(140) );
 painter.drawLine(1, 2, 1, height()-3);
 painter.drawLine(2, 1, width()-3, 1);
 if(!::factory->lightBorder())
   painter.setPen( group.background().dark(110) );
 painter.drawLine(width()-2, 2, width()-2, height()-3);
 painter.drawLine(2, height()-2, width()-3, height()-2);
 painter.end();

  //border antialiasing
 TQImage *tempAlphaImg = new TQImage( tempButton->convertToImage() );
 //tempAlphaImg = tempPixmap.convertToImage();
 tempAlphaImg->setAlphaBuffer(true);
 int borderRed = borderColor.red();
 int borderGreen = borderColor.green();
 int borderBlue = borderColor.blue();

 tempAlphaImg->setPixel(0,0, tqRgba(borderRed, borderGreen , borderBlue, 40));
 tempAlphaImg->setPixel(width()-1, 0, tqRgba(borderRed, borderGreen , borderBlue, 40));
 tempAlphaImg->setPixel(0,height()-1, tqRgba(borderRed, borderGreen , borderBlue, 40));
 tempAlphaImg->setPixel(width()-1,height()-1, tqRgba(borderRed, borderGreen , borderBlue, 40));

 tempAlphaImg->setPixel(0,1, tqRgba(borderRed, borderGreen , borderBlue, 127));
 tempAlphaImg->setPixel(1,0, tqRgba(borderRed, borderGreen , borderBlue, 127));

 tempAlphaImg->setPixel(width()-2,0, tqRgba(borderRed, borderGreen , borderBlue, 127));
 tempAlphaImg->setPixel(width()-1,1, tqRgba(borderRed, borderGreen , borderBlue, 127));

 tempAlphaImg->setPixel(0,height()-2, tqRgba(borderRed, borderGreen , borderBlue, 127));
 tempAlphaImg->setPixel(1,height()-1, tqRgba(borderRed, borderGreen , borderBlue, 127));

 tempAlphaImg->setPixel(width()-1,height()-2, tqRgba(borderRed, borderGreen , borderBlue, 127));
 tempAlphaImg->setPixel(width()-2,height()-1, tqRgba(borderRed, borderGreen , borderBlue, 127));


 if( client_->isActive() )
 {
   buttonImgActive = tempAlphaImg;
   buttonImgActive_created = true;
 }
 else
 {
   buttonImgInactive = tempAlphaImg;
   buttonImgInactive_created = true;
 }

}

//////////////////////////////////////////////////////////////////////////////
// polyesterClient Class
//////////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////////
// polyesterClient()
// ---------------
// Constructor

polyesterClient::polyesterClient(KDecorationBridge *b, KDecorationFactory *f)
    : KDecoration(b, f),
    mainLayout_(0),
    titleLayout_(0),
    topSpacer_(0),
    titleSpacer_(0),
    leftTitleSpacer_(0), rightTitleSpacer_(0),
    decoSpacer_(0),
    leftSpacer_(0), rightSpacer_(0),
    bottomSpacer_(0), windowSpacer_(0),
    aCaptionBuffer(0), iCaptionBuffer(0),
    aTitleBarTile(0), iTitleBarTile(0), aTitleBarTopTile(0), iTitleBarTopTile(0),
    pixmaps_created(false),
    //captionBufferDirty(true),
    closing(false),
    s_titleHeight(0),
    s_titleFont(TQFont()),
    maskDirty(true),
    aDoubleBufferDirty(true),
    iDoubleBufferDirty(true)
    {
        aCaptionBuffer = new TQPixmap();
        iCaptionBuffer = new TQPixmap();

        //copying the most used configuration options
        frameSize = ::factory->frameSize();

        NET::WindowType type = windowType(NET::NormalMask | NET::DesktopMask |
                                          NET::DockMask | NET::ToolbarMask |
                                          NET::MenuMask | NET::DialogMask|
                                          NET::OverrideMask | NET::TopMenuMask |
                                          NET::UtilityMask | NET::SplashMask);
        if( type == NET::Utility || type == NET::Menu || type == NET::Toolbar )
        {
           titleSize = (int)((double)::factory->titleSize()/1.2);
           buttonSize = titleSize - 2;
           roundedCorners = false;
        }
        else
        {
           titleSize = ::factory->titleSize();
           //don't allow buttonSize > titleSize
           buttonSize = titleSize - 2 < ::factory->buttonSize()?
                                                 titleSize - 2 :
                                                 ::factory->buttonSize();
           roundedCorners = ::factory->roundedCorners();
        }

        //s_titleFont = isTool()?polyesterFactory::titleFontTool():polyesterFactory::titleFont();
        s_titleFont = options()->font();
        s_titleHeight = titleSize;
    }

//////////////////////////////////////////////////////////////////////////////////
// ~polyesterClient()
// --------------------
// Destructor
polyesterClient::~polyesterClient() {
    delete aCaptionBuffer;
    delete iCaptionBuffer;
}

void polyesterClient::create_pixmaps() {
    if(pixmaps_created)
        return;
    KPixmap tempPixmap;
    TQPainter painter;


    // active top title bar tile
    tempPixmap.resize(1, s_titleHeight+frameSize);
    tempPixmap = KPixmapEffect::gradient(tempPixmap,
                                         KDecoration::options()->color(ColorTitleBar, true).light(160),
                                         KDecoration::options()->color(ColorTitleBlend, true).light(104),
                                         KPixmapEffect::VerticalGradient
                                        );
    // tempPixmap.fill(KDecoration::options()->color(ColorTitleBar, true).light(150));
    aTitleBarTopTile = new TQPixmap(1, s_titleHeight+frameSize);
    painter.begin(aTitleBarTopTile);
    painter.drawPixmap(0, 0, tempPixmap);
    painter.end();
    
    // inactive top title bar tile
    tempPixmap = KPixmapEffect::gradient(tempPixmap,
                                         KDecoration::options()->color(ColorTitleBar, false).light(160),
                                         KDecoration::options()->color(ColorTitleBlend, false),
                                         KPixmapEffect::VerticalGradient
                                        );
    iTitleBarTopTile = new TQPixmap(1, s_titleHeight+frameSize);
    painter.begin(iTitleBarTopTile);
    painter.drawPixmap(0, 0, tempPixmap);
    painter.end();

    // active title bar tile
    if( ::factory->titleBarStyle() == TITLEBAR_GLASS)
       tempPixmap.resize(1, ((s_titleHeight+frameSize)/2) - 1 );
    else
       tempPixmap.resize(1, s_titleHeight+frameSize);

    TQColor color1;
    TQColor color2;
    TQColor glassColor;
    if( ::factory->titleBarStyle() == TITLEBAR_GLASS )
    {
      glassColor = alphaBlendColors( KDecoration::options()->color(ColorTitleBar, true),
                                     KDecoration::options()->color(ColorTitleBlend, true),
                                     127 );
      color1 = glassColor.light(105+::factory->contrast()*4);
      color2 = glassColor;
    }
    else
    {
      color1 = KDecoration::options()->color(ColorTitleBar, true);
      color2 = KDecoration::options()->color(ColorTitleBlend, true);
    }

    tempPixmap = KPixmapEffect::gradient(tempPixmap,
                                         color1,
                                         color2,
                                         KPixmapEffect::VerticalGradient
                                        );

    aTitleBarTile = new TQPixmap(1, s_titleHeight+frameSize);
    painter.begin(aTitleBarTile);
    painter.drawPixmap(0, 0, tempPixmap);

    if( ::factory->titleBarStyle() == TITLEBAR_GLASS )
    {
       int y = tempPixmap.height();
       tempPixmap.resize(1, (s_titleHeight+frameSize)-y );
       tempPixmap = KPixmapEffect::gradient(tempPixmap,
                                            glassColor.dark(105+::factory->contrast()),
                                            glassColor,
                                            KPixmapEffect::VerticalGradient
                                           );
       painter.drawPixmap(0, y, tempPixmap);
    }
    //  painter.drawPixmap(0, 0, *aTitleBarTopTile);
    painter.end();

    // inactive title bar tile
    //de-glassify inactive titlebar
    if( ::factory->titleBarStyle() == TITLEBAR_GLASS )
       tempPixmap.resize(1, s_titleHeight+frameSize);
    tempPixmap = KPixmapEffect::gradient(tempPixmap,
                                         KDecoration::options()->color(ColorTitleBar, false),
                                         KDecoration::options()->color(ColorTitleBlend, false),
                                         KPixmapEffect::VerticalGradient
                                        );
    iTitleBarTile = new TQPixmap(1, s_titleHeight+frameSize);
    painter.begin(iTitleBarTile);
    painter.drawPixmap(0, 0, tempPixmap);
    painter.end();


    pixmaps_created = true;
}

void polyesterClient::delete_pixmaps() {
    delete aTitleBarTopTile;
    aTitleBarTopTile = 0;

    delete iTitleBarTopTile;
    iTitleBarTopTile = 0;

    delete aTitleBarTile;
    aTitleBarTile = 0;

    delete iTitleBarTile;
    iTitleBarTile = 0;

    pixmaps_created = false;
}
//////////////////////////////////////////////////////////////////////////////
// init()
// ------
// Actual initializer for class

void polyesterClient::init() {
    createMainWidget( WResizeNoErase | WRepaintNoErase);
    widget()->installEventFilter(this);
    handlebar = frameSize < 4 ? 4 - frameSize : 0;

    // for flicker-free redraws
    widget()->setBackgroundMode(NoBackground);

    create_pixmaps();
    _resetLayout();

}
void polyesterClient::_resetLayout()
{
    // basic layout:
    //  _______________________________________________________________
    // |                         topSpacer                             |
    // |_______________________________________________________________|
    // | leftTitleSpacer | btns |  titlebar   | bts | rightTitleSpacer |
    // |_________________|______|_____________|_____|__________________|
    // |                         decoSpacer                            |
    // |_______________________________________________________________|
    // | |                                                           | |
    // | |                      windowWrapper                        | |
    // | |                                                           | |
    // |leftSpacer                                          rightSpacer|
    // |_|___________________________________________________________|_|
    // |                           bottomSpacer                        |
    // |_______________________________________________________________|
    //
    if (!::factory->initialized()) return;
    
    delete mainLayout_;
    delete titleLayout_;
    delete topSpacer_;
    delete titleSpacer_;
    delete leftTitleSpacer_;
    delete rightTitleSpacer_;
    delete decoSpacer_;
    delete leftSpacer_;
    delete rightSpacer_;
    delete bottomSpacer_;
    delete windowSpacer_;

    mainLayout_ = new TQVBoxLayout(widget());
    // title
    titleLayout_ = new TQHBoxLayout();
    TQHBoxLayout *windowLayout_ = new TQHBoxLayout();


    topSpacer_        = new TQSpacerItem(1, frameSize, TQSizePolicy::Expanding, TQSizePolicy::Fixed);
    titlebar_         = new TQSpacerItem(1, s_titleHeight,
                                        TQSizePolicy::Expanding, TQSizePolicy::Fixed);
    leftTitleSpacer_  = new TQSpacerItem(frameSize, s_titleHeight,
                                        TQSizePolicy::Fixed, TQSizePolicy::Fixed);
    rightTitleSpacer_ = new TQSpacerItem(frameSize, s_titleHeight,
                                        TQSizePolicy::Fixed, TQSizePolicy::Fixed);
    decoSpacer_       = new TQSpacerItem(1, frameSize, TQSizePolicy::Expanding, TQSizePolicy::Fixed);
    leftSpacer_       = new TQSpacerItem(frameSize, 1,
                                        TQSizePolicy::Fixed, TQSizePolicy::Expanding);
    rightSpacer_      = new TQSpacerItem(frameSize, 1,
                                        TQSizePolicy::Fixed, TQSizePolicy::Expanding);
    bottomSpacer_     = new TQSpacerItem(1, frameSize,
                                        TQSizePolicy::Expanding, TQSizePolicy::Fixed);
    
    // sizeof(...) is calculated at compile time
    memset(button, 0, sizeof(polyesterButton *) * ButtonTypeCount);

    // message in preview widget
    if (isPreview()) {
        windowLayout_->addWidget(
            new TQLabel( i18n("<b><center>Polyester Preview</center></b>"), widget() ), 1 ); 
    } else {
        windowLayout_->addItem(new TQSpacerItem(0, 0));
    }

    // setup titlebar buttons
    for (int n=0; n<ButtonTypeCount; n++)
        button[n] = 0;
    //Deal with the title and buttons
   titleLayout_->addItem(leftTitleSpacer_);

    if( !::factory->noModalButtons() || !isModal() || isResizable())
        addButtons(titleLayout_,
                   options()->customButtonPositions() ? options()->titleButtonsLeft() : TQString(default_left),
                   buttonSize);
    titleLayout_->addItem(titlebar_);
    if( !::factory->noModalButtons() ||  !isModal() || isResizable())
        addButtons(titleLayout_,
                   options()->customButtonPositions() ? options()->titleButtonsRight() : TQString(default_right),
                   buttonSize);
        titleLayout_->addItem(rightTitleSpacer_);

    //Mid - left side, middle contents and right side
    TQHBoxLayout * midLayout_   = new TQHBoxLayout();
    midLayout_->addItem(leftSpacer_);
    midLayout_->addLayout(windowLayout_);
    midLayout_->addItem(rightSpacer_);

    //Layout order
    mainLayout_->addItem( topSpacer_ );
    mainLayout_->addLayout( titleLayout_ );
    mainLayout_->addItem( decoSpacer_ );
    mainLayout_->addLayout( midLayout_ );
    mainLayout_->addItem( bottomSpacer_ );
    
    // connections
  //TODO: probably these two connections could be removed
  //  connect(this, TQ_SIGNAL(keepAboveChanged(bool)), TQ_SLOT(keepAboveChange(bool)));
  //  connect(this, TQ_SIGNAL(keepBelowChanged(bool)), TQ_SLOT(keepBelowChange(bool)));
}

//////////////////////////////////////////////////////////////////////////////
// addButtons()
// ------------
// Add buttons to title layout

void polyesterClient::addButtons(TQBoxLayout *layout, const TQString& s, int button_size) {
    TQString tip;
    if (s.length() > 0) {
        for (unsigned n=0; n < s.length(); n++) {
            switch (s[n]) {
            case 'M': // Menu button
                if (!button[ButtonMenu]) {
                    button[ButtonMenu] =
                        new polyesterButton(this, "splat.png", i18n("Menu"),ButtonMenu,button_size,::factory->squareButton());
                    connect(button[ButtonMenu], TQ_SIGNAL(pressed()), this, TQ_SLOT(menuButtonPressed()));
                    connect(button[ButtonMenu], TQ_SIGNAL(released()), this, TQ_SLOT(menuButtonReleased()));
                    layout->addWidget(button[ButtonMenu]);
                    if (n < s.length()-1) layout->addSpacing(1);
                }
                break;

            case 'S': // Sticky button
                if (!button[ButtonSticky]) {
                    if (isOnAllDesktops()) {
                        tip = i18n("Un-Sticky");
                    } else {
                        tip = i18n("Sticky");
                    }
                    button[ButtonSticky] =
                        new polyesterButton(this, "circle.png", tip, ButtonSticky, button_size,::factory->squareButton(), true);
                    connect(button[ButtonSticky], TQ_SIGNAL(clicked()),
                            this, TQ_SLOT(toggleOnAllDesktops()));
                    layout->addWidget(button[ButtonSticky]);
                    if (n < s.length()-1) layout->addSpacing(1);
                }
                break;

            case 'H': // Help button
                if ((!button[ButtonHelp]) && providesContextHelp()) {
                    button[ButtonHelp] =
                        new polyesterButton(this, "help.png", i18n("Help"), ButtonHelp, button_size, ::factory->squareButton());
                    connect(button[ButtonHelp], TQ_SIGNAL(clicked()),
                            this, TQ_SLOT(showContextHelp()));
                    layout->addWidget(button[ButtonHelp]);
                    if (n < s.length()-1) layout->addSpacing(1);
                }
                break;

            case 'I': // Minimize button
                if ((!button[ButtonMin]) && isMinimizable())  {
                    button[ButtonMin] =
                        new polyesterButton(this, "minimize.png", i18n("Minimize"), ButtonMin, button_size,::factory->squareButton());
                    connect(button[ButtonMin], TQ_SIGNAL(clicked()),
                            this, TQ_SLOT(minimize()));
                    layout->addWidget(button[ButtonMin]);
                    if (n < s.length()-1) layout->addSpacing(1);
                }
                break;

            case 'A': // Maximize button
                if ((!button[ButtonMax]) && isMaximizable()) {
                    if (maximizeMode() == MaximizeFull) {
                        tip = i18n("Restore");
                    } else {
                        tip = i18n("Maximize");
                    }
                    button[ButtonMax]  =
                        new polyesterButton(this, "maximize.png", tip, ButtonMax, button_size,::factory->squareButton(), true);
                    connect(button[ButtonMax], TQ_SIGNAL(clicked()),
                            this, TQ_SLOT(maxButtonPressed()));
                    layout->addWidget(button[ButtonMax]);
                    if (n < s.length()-1) layout->addSpacing(1);
                }
                break;

            case 'X': // Close button
                if ((!button[ButtonClose]) && isCloseable()) {
                    button[ButtonClose] =
                        new polyesterButton(this, "close.png", i18n("Close"), ButtonClose, button_size, ::factory->squareButton());
                    connect(button[ButtonClose], TQ_SIGNAL(clicked()),
                            this, TQ_SLOT(closeWindow()));
                    layout->addWidget(button[ButtonClose]);
                    if (n < s.length()-1) layout->addSpacing(1);
                }
                break;

            case 'F': // Above button
                if ((!button[ButtonAbove])) {
                    button[ButtonAbove] =
                        new polyesterButton(this, "keep_above.png",
                                            i18n("Keep Above Others"), ButtonAbove, button_size, ::factory->squareButton(), true);
                    connect(button[ButtonAbove], TQ_SIGNAL(clicked()),
                            this, TQ_SLOT(aboveButtonPressed()));
                    layout->addWidget(button[ButtonAbove]);
                    if (n < s.length()-1) layout->addSpacing(1);
                }
                break;

            case 'B': // Below button
                if ((!button[ButtonBelow])) {
                    button[ButtonBelow] =
                        new polyesterButton(this, "keep_below.png",
                                            i18n("Keep Below Others"), ButtonBelow, button_size, ::factory->squareButton(), true);
                    connect(button[ButtonBelow], TQ_SIGNAL(clicked()),
                            this, TQ_SLOT(belowButtonPressed()));
                    layout->addWidget(button[ButtonBelow]);
                    if (n < s.length()-1) layout->addSpacing(1);
                }
                break;

            case 'L': // Shade button
                if ((!button[ButtonShade && isShadeable()])) {
                    if ( isSetShade()) {
                        tip = i18n("Unshade");
                    } else {
                        tip = i18n("Shade");
                    }
                    button[ButtonShade] =
                        new polyesterButton(this, "splat.png", tip, ButtonShade, button_size, ::factory->squareButton(), true);
                    connect(button[ButtonShade], TQ_SIGNAL(clicked()),
                            this, TQ_SLOT(shadeButtonPressed()));
                    layout->addWidget(button[ButtonShade]);
                    if (n < s.length()-1) layout->addSpacing(1);
                }
                break;

            case '_': // Spacer item
                layout->addSpacing(frameSize);
            }
        }
    }
}

//////////////////////////////////////////////////////////////////////////////
// activeChange()
// --------------
// window active state has changed

void polyesterClient::activeChange() {
    for (int n=0; n<ButtonTypeCount; n++)
        if (button[n])
            button[n]->reset();
    maskDirty = true;
    widget()->repaint(false);
}

//////////////////////////////////////////////////////////////////////////////
// captionChange()
// ---------------
// The title has changed

void polyesterClient::captionChange() {
    aDoubleBufferDirty = iDoubleBufferDirty = true;
    widget()->repaint(titlebar_->geometry(), false);
}

//////////////////////////////////////////////////////////////////////////////
// desktopChange()
// ---------------
// Called when desktop/sticky changes

void polyesterClient::desktopChange() {
    bool d = isOnAllDesktops();
    if (button[ButtonSticky]) {
        TQToolTip::remove(button[ButtonSticky]);
        TQToolTip::add(button[ButtonSticky], d ? i18n("Un-Sticky") : i18n("Sticky"));
        button[ButtonSticky]->repaint(false);
    }
}

//////////////////////////////////////////////////////////////////////////////
// iconChange()
// ------------
// The title has changed

void polyesterClient::iconChange() {
    if (button[ButtonMenu]) {
        button[ButtonMenu]->repaint(false);
    }
}

//////////////////////////////////////////////////////////////////////////////
// maximizeChange()
// ----------------
// Maximized state has changed

void polyesterClient::maximizeChange() {
    maskDirty = aDoubleBufferDirty = iDoubleBufferDirty = true;
    bool m = (maximizeMode() == MaximizeFull);
    if (button[ButtonMax]) {
        TQToolTip::remove(button[ButtonMax]);
        TQToolTip::add(button[ButtonMax], m ? i18n("Restore") : i18n("Maximize"));
        button[ButtonMax]->repaint(false);
    }
}

//////////////////////////////////////////////////////////////////////////////
// shadeChange()
// -------------
// Called when window shading changes

void polyesterClient::shadeChange() {
    bool s = isSetShade();
    if (button[ButtonShade]) {
        TQToolTip::remove(button[ButtonShade]);
        TQToolTip::add(button[ButtonShade], s ? i18n("Unshade") : i18n("Shade"));
        button[ButtonShade]->repaint(false);
    }
}

//////////////////////////////////////////////////////////////////////////////
// TODO: probably these two functions can be removed
// keepAboveChange()
// ------------
// The above state has changed

void polyesterClient::keepAboveChange(bool a) {
    if (button[ButtonAbove]) {
        button[ButtonAbove]->setOn(a);
        button[ButtonAbove]->repaint(false);
    }
}

//////////////////////////////////////////////////////////////////////////////
// keepBelowChange()
// ------------
// The below state has changed

void polyesterClient::keepBelowChange(bool b) {
    if (button[ButtonBelow]) {
        button[ButtonBelow]->setOn(b);
        button[ButtonBelow]->repaint(false);
    }
}

//////////////////////////////////////////////////////////////////////////////
// borders()
// ----------
// Get the size of the borders

void polyesterClient::borders(int &left, int &right, int &top, int &bottom) const {

    if ((maximizeMode()==MaximizeFull) && !options()->moveResizeMaximizedWindows()) {
        left = right = bottom = 0;
        top = s_titleHeight;

        // update layout etc.
        topSpacer_->changeSize(1, -1, TQSizePolicy::Expanding, TQSizePolicy::Fixed);
        decoSpacer_->changeSize(1, 0, TQSizePolicy::Expanding, TQSizePolicy::Fixed);
        leftSpacer_->changeSize(left, 1, TQSizePolicy::Fixed, TQSizePolicy::Expanding);
        leftTitleSpacer_->changeSize(left, s_titleHeight, TQSizePolicy::Fixed, TQSizePolicy::Fixed);
        rightSpacer_->changeSize(right, 1, TQSizePolicy::Fixed, TQSizePolicy::Expanding);
        rightTitleSpacer_->changeSize(right, s_titleHeight, TQSizePolicy::Fixed, TQSizePolicy::Fixed);
        bottomSpacer_->changeSize(1, bottom, TQSizePolicy::Expanding, TQSizePolicy::Fixed);
    } else {
        /*if the borders are rounded add more left and right borders*/
        if( roundedCorners )
          left = right = bottom = frameSize*2;
        else
          left = right = bottom = frameSize+1;
        top = titleSize + (frameSize*2);

        // update layout etc.
        topSpacer_->changeSize(1, frameSize, TQSizePolicy::Expanding, TQSizePolicy::Fixed);
        decoSpacer_->changeSize(1, frameSize, TQSizePolicy::Expanding, TQSizePolicy::Fixed);
        leftSpacer_->changeSize(left, 1, TQSizePolicy::Fixed, TQSizePolicy::Expanding);
        leftTitleSpacer_->changeSize(left, s_titleHeight, TQSizePolicy::Fixed, TQSizePolicy::Fixed);
        rightSpacer_->changeSize(right, 1, TQSizePolicy::Fixed, TQSizePolicy::Expanding);
        rightTitleSpacer_->changeSize(right,s_titleHeight,TQSizePolicy::Fixed, TQSizePolicy::Fixed);
        bottomSpacer_->changeSize(1, bottom, TQSizePolicy::Expanding, TQSizePolicy::Fixed);
    }
    widget()->layout()->activate();
}

//////////////////////////////////////////////////////////////////////////////
// resize()
// --------
// Called to resize the window

void polyesterClient::resize(const TQSize &size) {
    widget()->resize(size);
}

//////////////////////////////////////////////////////////////////////////////
// minimumSize()
// -------------
// Return the minimum allowable size for this window

TQSize polyesterClient::minimumSize() const {
    return widget()->minimumSize();
}

//////////////////////////////////////////////////////////////////////////////
// mousePosition()
// ---------------
// Return logical mouse position

KDecoration::Position polyesterClient::mousePosition(const TQPoint &point) const {
    const int corner = 24;
    Position pos;
    int fs = frameSize + handlebar;
    //int fs = ::factory->frameSize();

    if (point.y() <= fs) {
        // inside top frame
        if (point.x() <= corner)
            pos = PositionTopLeft;
        else if (point.x() >= (width()-corner))
            pos = PositionTopRight;
        else
            pos = PositionTop;
    } else if (point.y() >= (height()-fs*2)) {
        // inside handle
        if (point.x() <= corner)
            pos = PositionBottomLeft;
        else if (point.x() >= (width()-corner))
            pos = PositionBottomRight;
        else
            pos = PositionBottom;
    } else if (point.x() <= fs ) {
        // on left frame
        if (point.y() <= corner)
            pos = PositionTopLeft;
        else if (point.y() >= (height()-corner))
            pos = PositionBottomLeft;
        else
            pos = PositionLeft;
    } else if (point.x() >= width()-fs) {
        // on right frame
        if (point.y() <= corner)
            pos = PositionTopRight;
        else if (point.y() >= (height()-corner))
            pos = PositionBottomRight;
        else
            pos = PositionRight;
    } else {
        // inside the frame
        pos = PositionCenter;
    }
    return pos;
}

//////////////////////////////////////////////////////////////////////////////
// eventFilter()
// -------------
// Event filter

bool polyesterClient::eventFilter(TQObject *obj, TQEvent *e) {
    if (obj != widget())
        return false;

    switch (e->type()) {
    case TQEvent::MouseButtonDblClick: {
            mouseDoubleClickEvent(static_cast<TQMouseEvent *>(e));
            return true;
        }
    case TQEvent::MouseButtonPress: {
            processMousePressEvent(static_cast<TQMouseEvent *>(e));
            return true;
        }
    case TQEvent::Wheel: {
           wheelEvent(static_cast< TQWheelEvent* >(e));
           return true;
        }
    case TQEvent::Paint: {
            paintEvent(static_cast<TQPaintEvent *>(e));
            return true;
        }
    case TQEvent::Resize: {
            resizeEvent(static_cast<TQResizeEvent *>(e));
            return true;
        }
    case TQEvent::Show: {
            showEvent(static_cast<TQShowEvent *>(e));
            return true;
        }
    default: {
            return false;
        }
    }

    return false;
}

//////////////////////////////////////////////////////////////////////////////
// mouseDoubleClickEvent()
// -----------------------
// Doubleclick on title

void polyesterClient::mouseDoubleClickEvent(TQMouseEvent *e) {
    if (titlebar_->geometry().contains(e->pos()))
        titlebarDblClickOperation();
}

//////////////////////////////////////////////////////////////////////////////
// wheelEvent()
// -----------------------
// Mousewheel over titlebar

void polyesterClient::wheelEvent(TQWheelEvent * e) {
#if TDE_VERSION > TDE_MAKE_VERSION(3,4,3)
if (titleLayout_->geometry().contains(e->pos()))
titlebarMouseWheelOperation(e->delta());
#endif
}

//////////////////////////////////////////////////////////////////////////////
// paintEvent()
// ------------
// Repaint the window

void polyesterClient::paintEvent(TQPaintEvent* e) {
    if (!::factory->initialized())
    {
        return;
    }

    //int frameSize = ::factory->frameSize();
    const uint maxCaptionLength = 200; // truncate captions longer than this!
                                       // FIXME: truncate related to window size
//titlebar_->geometry().width()/(widget()->font().pointSize());
    TQString captionText(caption());
    if (captionText.length() > maxCaptionLength) {
        captionText.truncate(maxCaptionLength);
        captionText.append(" [...]");
    }


    TQColor blackColor(black);
    TQColor redColor(red);
    TQColorGroup group,widgetGroup;

    bool active = isActive();

    //doublebuffering everything to avoid the flicker
    TQPainter finalPainter(widget());

    //an ugly debug red border used to thest the speed...
    //finalPainter.fillRect(e->rect(),red);return;

    // mask off which corners we dont want
    // otherwise recycle the old buffer
    /*if( doubleBuff.width()>0 )
    {
       finalPainter.drawPixmap(0,0, doubleBuff);
       finalPainter.end();
       return;
    }*/
    if( maskDirty )
        updateMask();
    if( !(active?aDoubleBufferDirty:iDoubleBufferDirty) && ((active?activeBuff.width():inactiveBuff.width()) == widget()->width() ))
    {
       finalPainter.drawPixmap(0,0, active?activeBuff:inactiveBuff );
       finalPainter.end();
       return;
    }


    if( active )
       activeBuff  =  TQPixmap(widget()->width(), widget()->height());
    else
       inactiveBuff  =  TQPixmap(widget()->width(), widget()->height());

    TQPainter painter(active?&activeBuff:&inactiveBuff);
    //get group information first
    group = options()->colorGroup(KDecoration::ColorTitleBlend, active);
    widgetGroup = widget()->colorGroup();

    TQRect topRect( topSpacer_->geometry() );
    TQRect titleRect( titleLayout_->geometry() );
    TQRect textRect( titlebar_->geometry() );
    TQRect Rltitle( leftTitleSpacer_->geometry() );
    TQRect Rrtitle( rightTitleSpacer_->geometry() );
    TQRect Rdeco( decoSpacer_->geometry() );
    TQRect Rleft( leftSpacer_->geometry() );
    TQRect Rright( rightSpacer_->geometry() );
    TQRect Rbottom( bottomSpacer_->geometry() );
    TQRect tempRect;

    
    /*
    if(active)
    {
        tqDebug("topRect.y()   = %i\tbottom() = %i",topRect.top(),topRect.bottom());
        tqDebug("titleRect.y() = %i\tbottom() = %i",titleRect.top(),titleRect.bottom());
        tqDebug("textRect.y()  = %i\tbottom() = %i",textRect.top(),textRect.bottom());
        tqDebug("Rltitle.y()   = %i\tbottom() = %i",Rltitle.top(),Rltitle.bottom());
        tqDebug("Rrtitle.y()   = %i\tbottom() = %i",Rrtitle.top(),Rrtitle.bottom());
        tqDebug("Rdeco.y()     = %i\tbottom() = %i",Rdeco.top(),Rdeco.bottom());
        tqDebug("Rleft.y()     = %i\tbottom() = %i",Rleft.top(),Rleft.bottom());
        tqDebug("Rright.y()    = %i\tbottom() = %i",Rright.top(),Rright.bottom());
        tqDebug("Rbottom.y()   = %i\tbottom() = %i",Rbottom.top(),Rbottom.bottom());
    }
    */

    // top
    painter.drawTiledPixmap(topRect, active ? *aTitleBarTopTile:*iTitleBarTopTile);
    painter.drawTiledPixmap(titleRect.x(),
                            titleRect.y(),
                            titleRect.width(),
                            titleRect.height() + Rdeco.height(),
                            active ? *aTitleBarTile:*iTitleBarTile);

    textRect.setRect(textRect.x()+SIDETITLEMARGIN,
                     textRect.y(),
                     textRect.width()-SIDETITLEMARGIN*2,
                     textRect.height());


    //is the title text too long?
    bool titleTooLong = false;
    TQt::AlignmentFlags titleAlign = ::factory->titleAlign();
    const int gradientWidth = 60;
    if( TQFontMetrics(widget()->font()).width(captionText) > (textRect.width() - gradientWidth) )
    {
        titleTooLong = true;
        titleAlign = TQt::AlignLeft;
    }

    //we are shadowing title bar text only if there is some text
    if(::factory->titleShadow() && textRect.width()>0 && textRect.height()>0)
    {
        TQPixmap textPixmap;
        TQPainter tempPainter;
        TQColor shadowColor;

        textPixmap = TQPixmap(textRect.width(), textRect.height());
        textPixmap.fill(TQColor(0,0,0));
        textPixmap.setMask( textPixmap.createHeuristicMask(TRUE) );
        tempPainter.begin(&textPixmap);


        //shadow text
        tempPainter.setFont(options()->font(isActive(), false));

        tempPainter.setPen(white);

        tempPainter.drawText(1, 1, textRect.width(), textRect.height(),
                         titleAlign | AlignVCenter | TQt::SingleLine,
                         captionText);
        tempPainter.end();

        // make the cute blurred text shadow from Plastik engine
        TQImage shadow;
        ShadowEngine se;

        //deciding if the shadow will be black or white
        if(tqGray(options()->color(KDecoration::ColorFont, isActive()).rgb()) > 150)
            shadowColor = blackColor;
        else
            shadowColor = white;

        shadow = se.makeShadow(textPixmap, shadowColor);

        painter.drawImage(textRect, shadow);

    }

    // draw title text
    painter.setFont(options()->font(isActive(), false));
    painter.setPen(options()->color(KDecoration::ColorFont, isActive()));
    painter.drawText(textRect,
                     titleAlign | AlignVCenter | TQt::SingleLine,
                     captionText);

    // make title fade out when the caption is too long, veery slow but veery cool :-)
    if( titleTooLong )
    {
        int xGradient = textRect.right()-(gradientWidth-1);

        TQPixmap backLayerP = TQPixmap(gradientWidth, textRect.height());
        TQPainter layerPainter(&backLayerP);
        layerPainter.drawTiledPixmap(backLayerP.rect(), active ? *aTitleBarTile:*iTitleBarTile);
        layerPainter.end();
        TQImage backLayer = backLayerP.convertToImage();

        TQImage textLayer = ( active ?
                             activeBuff.convertToImage():
                             inactiveBuff.convertToImage()
                            ).copy( xGradient, textRect.y(),
                                    gradientWidth, textRect.height()
                                  );
        KImageEffect::blend(backLayer,  textLayer, KImageEffect::HorizontalGradient);
        painter.drawImage(xGradient, textRect.y(), backLayer);

    }

    //left of buttons and title
    painter.drawTiledPixmap(Rltitle.x(),
                            Rltitle.y(),
                            Rltitle.width(),
                            Rltitle.height()+Rdeco.height(),
                            active ? *aTitleBarTile:*iTitleBarTile);

    //left 3d effect
    painter.drawTiledPixmap(Rltitle.x(),
                            Rltitle.y(),
                            2,
                            Rltitle.height()+Rdeco.height(),
                            active ? *aTitleBarTopTile:*iTitleBarTopTile);

    // left mid layout
    painter.fillRect(Rleft,widgetGroup.background());

    // right of buttons and title
    painter.drawTiledPixmap(Rrtitle.x(),
                            Rrtitle.y(),
                            Rrtitle.width(),
                            Rrtitle.height()+Rdeco.height(),
                            active ? *aTitleBarTile:*iTitleBarTile);
    //right 3d effect
    painter.drawTiledPixmap(width()-2,
                            Rltitle.y(),
                            2,
                            Rltitle.height()+Rdeco.height(),
                            active ? *aTitleBarTopTile:*iTitleBarTopTile);

    // right mid layout
    painter.fillRect(Rright,widgetGroup.background());
    
    // bottom
    /*
    if(isShade())
    {
        frame.setRect(0,::factory->titleSize()+FRAMESIZE, width(), FRAMESIZE);
    }
    else
    {
        frame.setRect(0, height() - (FRAMESIZE*2), width(),  (FRAMESIZE*2));
    }
    */
    painter.fillRect(Rbottom, KDecoration::options()->color(ColorTitleBlend, active));//widgetGroup.background());

    //if the window is maximized the border is invisible
    if( (maximizeMode()==MaximizeFull) && !options()->moveResizeMaximizedWindows() )
      painter.setPen(KDecoration::options()->color(ColorTitleBar, active));
    else
      painter.setPen(group.background().dark(150));

    // outline outside the frame but not the corners if they are rounded
    tempRect = widget()->rect();
    painter.drawRect(tempRect);

    if(roundedCorners && !maximizeMode()) {
        // local temp right and bottom
        int r(width());
        painter.setPen(group.background().dark(150));
        painter.drawPoint(4, 1);
        painter.drawPoint(3, 1);
        painter.drawPoint(2, 2);
        painter.drawPoint(1, 3);
        painter.drawPoint(1, 4);
        painter.drawPoint(r - 5, 1);
        painter.drawPoint(r - 4, 1);
        painter.drawPoint(r - 3, 2);
        painter.drawPoint(r - 2, 3);
        painter.drawPoint(r - 2, 4);

        painter.setPen(KDecoration::options()->color(ColorTitleBar, active).light(160));
        painter.drawPoint(4, 2);
        painter.drawPoint(3, 2);
        painter.drawPoint(2, 3);
        painter.drawPoint(2, 4);

        //painter.setPen(KDecoration::options()->color(ColorTitleBlend, active));
        painter.drawPoint(r - 5, 2);
        painter.drawPoint(r - 4, 2);
        painter.drawPoint(r - 3, 3);
        painter.drawPoint(r - 3, 4);
    } 

    // finally copy the buffer into the widget
    //finalPainter.begin(doubleBuff);
    finalPainter.drawPixmap(0,0, active?activeBuff:inactiveBuff);
    finalPainter.end();

    if( active )
        aDoubleBufferDirty = false;
    else
        iDoubleBufferDirty = false;
}

//////////////////////////////////////////////////////////////////////////////
// updateMask()
// ------------
// update the frame mask
void polyesterClient::updateMask() {

    if ( (!options()->moveResizeMaximizedWindows() && maximizeMode() & MaximizeFull ) ) 
    {
        setMask(TQRegion(widget()->rect()));
        return;
    }

    int r(width());
    int b(height());
    TQRegion mask;

    mask=TQRegion(widget()->rect());
    mask=TQRegion( 0, 0, r, b );

   // Remove top-left corner.
    if( roundedCorners &&
        maximizeMode() != KDecorationDefines::MaximizeFull )
    {
        mask -= TQRegion(0, 0, 5, 1);
        mask -= TQRegion(0, 1, 3, 1);
        mask -= TQRegion(0, 2, 2, 1);
        mask -= TQRegion(0, 3, 1, 2);
        mask -= TQRegion(r - 5, 0, 5, 1);
        mask -= TQRegion(r - 3, 1, 3, 1);
        mask -= TQRegion(r - 2, 2, 2, 1);
        mask -= TQRegion(r - 1, 3, 1, 2);
    }
    //always remove one corner pixel so it simulates a soft corner like plastik
    mask -= TQRegion(0,0,1,1);
    mask -= TQRegion(r-1,0,1,1);
    mask -= TQRegion(0, b-1, 1,1);
    mask -= TQRegion(r-1,b-1,1,1);

    setMask(mask, 1);

    maskDirty =  false;
}

//////////////////////////////////////////////////////////////////////////////
// resizeEvent()
// -------------
// Window is being resized

void polyesterClient::resizeEvent(TQResizeEvent *) {
    maskDirty = aDoubleBufferDirty = iDoubleBufferDirty = true;
    if (widget()->isShown()) {
        TQRegion region = widget()->rect();
        region = region.subtract(titlebar_->geometry());
        widget()->erase(region);
    }
    updateMask();
}

//////////////////////////////////////////////////////////////////////////////
// showEvent()
// -----------
// Window is being shown

void polyesterClient::showEvent(TQShowEvent *) {
    widget()->repaint();
    updateMask();
}

//////////////////////////////////////////////////////////////////////////////
// maxButtonPressed()
// -----------------
// Max button was pressed

void polyesterClient::maxButtonPressed() {
    if (button[ButtonMax]) {
#if KDE_IS_VERSION(3, 3, 0)
        maximize(button[ButtonMax]->lastMousePress());
#else

        switch (button[ButtonMax]->lastMousePress()) {
        case MidButton:
            maximize(maximizeMode() ^ MaximizeVertical);
            break;
        case RightButton:
            maximize(maximizeMode() ^ MaximizeHorizontal);
            break;
        default:
            (maximizeMode() == MaximizeFull) ? maximize(MaximizeRestore)
            : maximize(MaximizeFull);
        }
#endif

    }
}

//////////////////////////////////////////////////////////////////////////////
// shadeButtonPressed()
// -----------------
// Shade button was pressed

void polyesterClient::shadeButtonPressed() {
    if (button[ButtonShade]) {
        setShade( !isSetShade());
    }
}

//////////////////////////////////////////////////////////////////////////////
// aboveButtonPressed()
// -----------------
// Above button was pressed

void polyesterClient::aboveButtonPressed() {
    if (button[ButtonAbove]) {
        setKeepAbove( !keepAbove());
    }
}

//////////////////////////////////////////////////////////////////////////////
// belowButtonPressed()
// -----------------
// Below button was pressed

void polyesterClient::belowButtonPressed() {
    if (button[ButtonBelow]) {
        setKeepBelow( !keepBelow());
    }
}

//////////////////////////////////////////////////////////////////////////////
// menuButtonPressed()
// -------------------
// Menu button was pressed (popup the menu)

void polyesterClient::menuButtonPressed() {
    static TQTime* t = NULL;
    static polyesterClient* lastClient = NULL;
    if (t == NULL)
        t = new TQTime;
    bool dbl = (lastClient==this && t->elapsed() <= TQApplication::doubleClickInterval());
    lastClient = this;
    t->start();
    //if (button[ButtonMenu] && !dbl && !::factory->menuClosed()) {
    if ( !dbl || !::factory->menuClosed()) {
        TQPoint p(button[ButtonMenu]->rect().bottomLeft().x(),
                 button[ButtonMenu]->rect().bottomLeft().y());
        KDecorationFactory* f = factory();
        showWindowMenu(button[ButtonMenu]->mapToGlobal(p));
        if (!f->exists(this))
            return; // decoration was destroyed
        button[ButtonMenu]->setDown(false);
    }
    else
    {
        closing = true;
    }
}

void polyesterClient::menuButtonReleased()
{
    if(closing)
    {
        closeWindow();
    }
}

#include "polyester.moc"
