/*
  'Acqua' kwin client

  Copyright (C) 2001 Rik Hemsley (rikkus) <rik@kde.org>

  This program is free software; you can redistribute it and/or
  modify it under the terms of the GNU General Public
  License as published by the Free Software Foundation; either
  version 2 of the License, or (at your option) any later version.

  This program 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
  General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program; see the file COPYING.  If not, write to
  the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  Boston, MA 02111-1307, USA.
*/

#include <qvariant.h>

#include <unistd.h> // for usleep
#include <math.h>

#include <qlayout.h>
#include <qpainter.h>

#include <netwm.h>
#include <kwin/workspace.h>
// undef Bool

#include <kconfig.h>
#include <kstddirs.h>

#include <kapp.h>
#include <kwin/options.h>

#include "Acqua.h"
#include "AcquaButton.h"
#include "AcquaButtonHelp.h"
#include "AcquaButtonIconify.h"
#include "AcquaButtonClose.h"
#include "AcquaButtonMenu.h"
#include "AcquaButtonMaximize.h"

#include <X11/extensions/shape.h>

#include <qfile.h>
#include <qtextstream.h>

using namespace KWinInternal;

namespace AcquaNamespace
{

static int shadowType; // 0=None  1=Windows  2=Mac OS X
static int shadowUpdateInterval; // In miliseconds
static bool allWindowsShadowed;
static int cornersType; // 0=none 1=top rounded 2=bottom rounded 3=all rounded
static int showIcons; // 0=no 1=yes
static int shadowedText; // 0=no 1=yes
static int biggerFonts; // guess...
static int rightButtonIs; // 0=menu 1=help
static int noBorders; // 0=borders 1=no borders
static int buttonStyle; // 0=grey inactive 1=white inactive
//static int forceStyle; // 0 = no 1 = yes
static int rightXIAButtons; // 0 = no 1 = yes

// This is a list of ALL the shadows in use by KWin.
QPtrList<AcquaShadow> shadowWidgets;

static void readConfig()
{
   KConfig config("kwinrc");
   config.setGroup("Style");
  // forceStyle=config.readNumEntry("AcquaForceStyle",1);
   rightXIAButtons=config.readNumEntry("AcquaRightXIAButtons",1);
   shadowType = config.readNumEntry("ShadowType",1);
   shadowUpdateInterval = config.readNumEntry("ShadowUpdateInterval",0);
   allWindowsShadowed = config.readBoolEntry("AllWindowsShadowed",0);
   cornersType=config.readNumEntry("CornersType",1);
   showIcons=config.readNumEntry("AcquaShowIcons",1);
   shadowedText=config.readNumEntry("AcquaShadowedTitlebarText",1);
   biggerFonts=config.readNumEntry("AcquaBiggerFonts",1);
   rightButtonIs=config.readNumEntry("AcquaRightButtonIs",1);
   noBorders=config.readNumEntry("AcquaNoBorders",1);
   buttonStyle=config.readNumEntry("AcquaButtonStyle",1);
   biggerFonts=config.readNumEntry("AcquaBiggerFonts",1);
}

}; // Namespace



uint sideMargin    = 2;
uint bottomMargin  = 2;

uint topSideMargin = 4; // 4
uint topMargin     = 4; // 4
uint textVMargin   = 2;



Acqua::Acqua(Workspace * ws, WId w, bool tool, QWidget * parent, const char * name)
  : Client        (ws, w, parent, name, WResizeNoErase),
    tool_         (tool),
    mainLayout_   (0),
    titleSpacer_  (0)
{
  setBackgroundMode(NoBackground);

   _resetLayout();

  leftButtonList_   .setAutoDelete(true);
  rightButtonList_  .setAutoDelete(true);

  connect(options, SIGNAL(resetClients()), this, SLOT(slotReset()));

  shadowDelayTimer = new QTimer(this,"shadowDelayTimer");
  connect(shadowDelayTimer, SIGNAL(timeout()), this, SLOT(slotDrawShadow()));
  shadowRedrawTimer = new QTimer(this,"shadowRedrawTimer");
  connect(shadowRedrawTimer, SIGNAL(timeout()), this, SLOT(slotDrawShadow()));

  se.w1 = NULL;
  se.w2 = NULL;
  se.w3 = NULL;
  moving=false;
}

Acqua::~Acqua()
{
  slotRemoveShadow();
}

  void
Acqua::resizeEvent(QResizeEvent * e)
{
	Client::resizeEvent(e);
	doShape();
	repaint();

	if (AcquaNamespace::shadowType == 0) return;
	if (!moving)
	{
		oldPos = geometry();
		moving = true;
	}
	shadowDelayTimer->stop();
	slotRemoveShadow();
	if(isActive())
	shadowDelayTimer->start(200,true); // Repaint the shadow in 500 miliseconds
}

  void
Acqua::captionChange(const QString &)
{
  repaint();
}

  void
Acqua::paintEvent(QPaintEvent * pe)
{
  QColor borderColor=QColor(115,117,115);
  QRect titleRect(1, 1, width()-2, titleSpacer_->geometry().height()+topMargin*2-1);

  QPainter p(this);

  p.setPen(borderColor);
  p.setBrush(colorGroup().background());

  p.drawRect(rect());

  p.setClipRegion(pe->region() - titleRect);

  p.setClipRegion(pe->region());

	QListIterator<AcquaButton> it(leftButtonList_);
	QRect brect;
	if (!it.current())
	{
		QListIterator<AcquaButton> it2(rightButtonList_);
		brect = QRect(1, it2.current()->geometry().top(), width()-2, it2.current()->geometry().height());
	}
	else
		brect = QRect(1, it.current()->geometry().top(), width()-2, it.current()->geometry().height());

  /* The folowing lines are a bit strange, because i have to match the
   * background of the buttons. If anybody can provid some transparent
   * backgound button image, it can be quicker and more graceful.
   */
  QColor cols[16];
  int xx=width()-2, hh=titleSpacer_->geometry().height()+topMargin*2-2;
if ((!isActive())&& (AcquaNamespace::buttonStyle==0)) {
    cols[0].setRgb(222, 222, 222);
    cols[1].setRgb(239, 239, 239);
    cols[2].setRgb(222, 222, 222);
    cols[3].setRgb(216, 216, 216);

    for(int i=brect.top()-1, ci=0; i>0; i--, ci++)
    {
      if(ci>=4)ci=0;
      p.setPen(cols[ci]);
      p.drawLine(1, i, xx, i);
    }
    cols[0].setRgb(0xD9, 0xD9, 0xD9);
     cols[1].setRgb(0xE1, 0xE1, 0xE1);
     cols[2].setRgb(0xEF, 0xEF, 0xEF);
     cols[3].setRgb(0xE1, 0xE1, 0xE1);
     cols[4].setRgb(0xD9, 0xD9, 0xD9);
     cols[5].setRgb(0xDE, 0xDE, 0xDE);
     cols[6].setRgb(0xED, 0xED, 0xED);
     cols[7].setRgb(0xDF, 0xDF, 0xDF);
     cols[8].setRgb(0xD6, 0xD6, 0xD6);
     cols[9].setRgb(0xDA, 0xDA, 0xDA);
    cols[10].setRgb(0xE7, 0xE7, 0xE7);
    cols[11].setRgb(0xD8, 0xD8, 0xD8);
    cols[12].setRgb(0xCE, 0xCE, 0xCE);
    cols[13].setRgb(0xD0, 0xD0, 0xD0);
    cols[14].setRgb(0xDA, 0xDA, 0xDA);
    cols[15].setRgb(0xC9, 0xC9, 0xC9);

    for(int i=brect.top(), ci=0; i<=brect.bottom(); i++, ci++)
    {
      p.setPen(cols[ci]);
      p.drawLine(1, i, xx, i);
    }

    cols[0].setRgb(198, 198, 198);
    cols[1].setRgb(202, 202, 202);
    cols[2].setRgb(213, 213, 213);
    cols[3].setRgb(199, 199, 199);

    for(int i=brect.bottom()+1, ci=0; i<hh; i++, ci++){
      if(ci>=4)ci=0;
      p.setPen(cols[ci]);
      p.drawLine(1, i, xx, i);
    }

    p.setPen(QColor(213, 213, 213));
    p.drawLine(1, hh, xx, hh);
  }
  else {
    cols[0].setRgb(241, 241, 241);
    cols[1].setRgb(255, 255, 255);
    cols[2].setRgb(241, 241, 241);
    cols[3].setRgb(233, 233, 233);

    for(int i=brect.top()-1, ci=0; i>0; i--, ci++)
    {
      if(ci>=4)ci=0;
      p.setPen(cols[ci]);
      p.drawLine(1, i, xx, i);
    }

    cols[0].setRgb(0xE9, 0xE9, 0xE9);
    cols[1].setRgb(0xF1, 0xF1, 0xF1);
    cols[2].setRgb(0xFF, 0xFF, 0xFF);
    cols[3].setRgb(0xF1, 0xF1, 0xF1);
    cols[4].setRgb(0xE9, 0xE9, 0xE9);
    cols[5].setRgb(0xEE, 0xEE, 0xEE);
    cols[6].setRgb(0xFD, 0xFD, 0xFD);
    cols[7].setRgb(0xEF, 0xEF, 0xEF);
    cols[8].setRgb(0xE6, 0xE6, 0xE6);
    cols[9].setRgb(0xEA, 0xEA, 0xEA);
    cols[10].setRgb(0xF7, 0xF7, 0xF7);
    cols[11].setRgb(0xE8, 0xE8, 0xE8);
    cols[12].setRgb(0xDE, 0xDE, 0xDE);
    cols[13].setRgb(0xE0, 0xE0, 0xE0);
    cols[14].setRgb(0xEA, 0xEA, 0xEA);
    cols[15].setRgb(0xD9, 0xD9, 0xD9);
    for(int i=brect.top(), ci=0; i<=brect.bottom(); i++, ci++)
    {
      p.setPen(cols[ci]);
      p.drawLine(1, i, xx, i);
    }

    cols[0].setRgb(214, 214, 214);
    cols[1].setRgb(217, 217, 217);
    cols[2].setRgb(234, 234, 234);
    cols[3].setRgb(217, 217, 217);

    for(int i=brect.bottom()+1, ci=0; i<hh; i++, ci++){
      if(ci>=4)ci=0;
      p.setPen(cols[ci]);
      p.drawLine(1, i, xx, i);
    }

  p.setPen(QColor(232, 232, 232));
  p.drawLine(1, hh, xx, hh);
  }
    /* end of the strange code. */

  p.setPen(QColor(96, 96, 96));
  p.drawLine(1, hh+1, xx, hh+1);

  p.setPen(borderColor);
  //if (shape_)
  //{
  int r(width());
  int b(height());

  if (AcquaNamespace::noBorders==1) {
	sideMargin    = 0;
	bottomMargin  = 0;
	}
  else {
	sideMargin    = 2;
	bottomMargin  = 2;
	}

 if (AcquaNamespace::biggerFonts==1) {
       topSideMargin = 3;
       topMargin     = 3;
       textVMargin   = 0;
	}
else {
       topSideMargin = 4;
       topMargin     = 4;
       textVMargin   = 2;
	}

   if(AcquaNamespace::cornersType==1 | AcquaNamespace::cornersType==3)
   {
      // Draw edge of top-left corner inside the area removed by the mask.
      p.drawPoint(3, 1);
      p.drawPoint(4, 1);
      p.drawPoint(2, 2);
      p.drawPoint(1, 3);
      p.drawPoint(1, 4);

      // Draw edge of top-right corner inside the area removed by the mask.
      p.drawPoint(r - 5, 1);
      p.drawPoint(r - 4, 1);
      p.drawPoint(r - 3, 2);
      p.drawPoint(r - 2, 3);
      p.drawPoint(r - 2, 4);
   }

   if(AcquaNamespace::cornersType==2 | AcquaNamespace::cornersType==3)
   {
      // Draw edge of bottom-left corner inside the area removed by the mask.
      p.drawPoint(3, b-1-1);
      p.drawPoint(4, b-1-1);
      p.drawPoint(2, b-1-2);
      p.drawPoint(1, b-1-3);
      //p.drawPoint(1, b-1-4);
      // Draw edge of bottom-right corner inside the area removed by the mask.
      p.drawPoint(r - 5, b-1-1);
      p.drawPoint(r - 4, b-1-1);
      p.drawPoint(r - 3, b-1-2);
      p.drawPoint(r - 2, b-1-3);
      //p.drawPoint(r - 2, b-1-4);
  }
  //}

  p.setFont(options->font(isActive(), tool_));
    //p.setPen(options->color(Options::Font, isActive()).dark(130));

	int textOffset = 0;
	if (AcquaNamespace::showIcons == 1) textOffset = miniIcon().width();

    int centerOffset = -29;
    if (AcquaNamespace::rightButtonIs==0) centerOffset-=24;
    if (AcquaNamespace::rightXIAButtons==1) centerOffset*=-1;
    if (AcquaNamespace::shadowedText==1) {
    	p.setPen(QColor(200,200,200));
    	p.drawText(titleSpacer_->geometry().x()+1+textOffset, titleSpacer_->geometry().y()+1, titleSpacer_->geometry().width()-24+centerOffset, titleSpacer_->geometry().height(), AlignCenter, caption());
    }

  p.setPen(options->color(Options::Font, isActive()));
  p.drawText(titleSpacer_->geometry().x()+textOffset, titleSpacer_->geometry().y(), titleSpacer_->geometry().width()-24+centerOffset, titleSpacer_->geometry().height(),AlignCenter, caption());
//  p.drawText(titleSpacer_->geometry(), AlignCenter, caption());

  if(AcquaNamespace::showIcons==1)
  {
  int x1=(titleSpacer_->geometry().width()
         - p.fontMetrics().width(caption()))/2
         + titleSpacer_->geometry().x()
         -miniIcon().width()-29;
         ;
	 if (AcquaNamespace::rightXIAButtons==1) x1+=25;
  if (x1 > 52)
  p.drawPixmap( x1, topMargin , miniIcon() );
  }

}

  void
Acqua::doShape()
{
  //if (!shape_)
  //  return;
  
  QRegion mask(0, 0, width(), height());

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

   if(AcquaNamespace::cornersType==1 | AcquaNamespace::cornersType==3)
   {
      // Remove top-left corner.
      mask -= QRegion(0, 0, 5, 1);
      mask -= QRegion(0, 1, 3, 1);
      mask -= QRegion(0, 2, 2, 1);
      mask -= QRegion(0, 3, 1, 2);
      // Remove top-right corner.
      mask -= QRegion(r - 5, 0, 5, 1);
      mask -= QRegion(r - 3, 1, 3, 1);
      mask -= QRegion(r - 2, 2, 2, 1);
      mask -= QRegion(r - 1, 3, 1, 2);
  }


   if(AcquaNamespace::cornersType==2 | AcquaNamespace::cornersType==3)
   {
      // Remove bottom-left corner.
      mask -= QRegion(0, b-1-0, 5, b-1-1);
      mask -= QRegion(0, b-1-1, 3, b-1-1);
      mask -= QRegion(0, b-1-2, 2, b-1-1);
      mask -= QRegion(0, b-1-3, 1, b-1-2);

      // Remove bottom-right corner.
      mask -= QRegion(r - 5, b-1-0, 5, b-1-1);
      mask -= QRegion(r - 3, b-1-1, 3, b-1-1);
      mask -= QRegion(r - 2, b-1-2, 2, b-1-1);
      mask -= QRegion(r - 1, b-1-3, 1, b-1-2);
   }

  setMask(mask);
}

  void
Acqua::showEvent(QShowEvent *)
{
  doShape();
  repaint();
}


void Acqua::moveEvent(QMoveEvent *)
{
	if (AcquaNamespace::shadowType == 0) return;
	if (!moving)
	{
			oldPos = geometry();
			moving = true;
	}
	shadowDelayTimer->stop();
	slotRemoveShadow();
	if(isActive())
	shadowDelayTimer->start(200,true); // Repaint the shadow in 200 miliseconds
}

  void
Acqua::windowWrapperShowEvent(QShowEvent *)
{
  doShape();
  repaint();
}

  void
Acqua::mouseDoubleClickEvent(QMouseEvent * e)
{
  if (titleSpacer_->geometry().contains(e->pos()))
  {
    workspace()
      ->performWindowOperation(this, options->operationTitlebarDblClick());
  }
}

  void
Acqua::stickyChange(bool b)
{
}

  void
Acqua::maximizeChange(bool b)
{
  emit(maxChange(b));
}

void Acqua::bottomShadow(QImage& dst)
 {
         if (dst.depth() != 32)
                 dst = dst.convertDepth(32);
 
         int line = 0;
         int width = dst.width() - 4;
         double* corner = const_cast<double*>(win_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
 
   if (AcquaNamespace::shadowType == 1) // Windows shadows
   {
      double strip_data = win_shadow_strip[0];
      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 = win_shadow_strip[++line];
      }
    }
    else // Mac OS X shadows
    {
      double strip_data = macosx_shadow_strip_bottom[0];
      for(int y = 0; y < 17; y++) // for(int y = 0; y < 18; y++)
      {
         strip_data = macosx_shadow_strip_bottom[line++];
	 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 = macosx_shadow_strip_right[++line];
      }
   }
 }

 void Acqua::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
   if (AcquaNamespace::shadowType == 1) // Windows shadows
   {
      for(register int i = 0; i < 16; i++) {
         *data++ = (unsigned char)((*data)*win_top_right_corner[i]);
         *data++ = (unsigned char)((*data)*win_top_right_corner[i]);
         *data++ = (unsigned char)((*data)*win_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)*win_shadow_strip[c]);
         *data++ = (unsigned char)((*data)*win_shadow_strip[c]);
         *data++ = (unsigned char)((*data)*win_shadow_strip[c]);
         data++; // skip alpha
         c = ++c % 4;
      }

      // tint bottom edge
      for(register int i = 0; i < 16; i++) {
         *data++ = (unsigned char)((*data)*win_bottom_right_corner[i]);
         *data++ = (unsigned char)((*data)*win_bottom_right_corner[i]);
         *data++ = (unsigned char)((*data)*win_bottom_right_corner[i]);
         data++; // skip alpha
      }
   }
   else // Mac OS X shadows
   {
      for(register int i = 0; i < 256; i++) {  
         *data++ = (unsigned char)((*data)*macosx_top_right_corner[i]);
         *data++ = (unsigned char)((*data)*macosx_top_right_corner[i]);
         *data++ = (unsigned char)((*data)*macosx_top_right_corner[i]);
         data++;  // skip alpha
      }
      pixels -= 512; // tint right strip without rounded edges.
      register int c = 0;
      for(register int i = 0; i < pixels; i++) {
         *data++ = (unsigned char)((*data)*macosx_shadow_strip_right[c]);
         *data++ = (unsigned char)((*data)*macosx_shadow_strip_right[c]);
         *data++ = (unsigned char)((*data)*macosx_shadow_strip_right[c]);
         data++; // skip alpha
         c = ++c % 16;
      }
      for(register int i = 0; i < 256; i++) {
         *data++ = (unsigned char)((*data)*macosx_bottom_right_corner[i]);
         *data++ = (unsigned char)((*data)*macosx_bottom_right_corner[i]);
         *data++ = (unsigned char)((*data)*macosx_bottom_right_corner[i]);
         data++;  // skip alpha
      }
   }
}

void Acqua::leftShadow(QImage& dst)
{
    if (dst.depth() != 32)
        dst = dst.convertDepth(32);
    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 < 256; i++) {
           *data++ = (unsigned char)((*data)*macosx_top_left_corner[i]);
         *data++ = (unsigned char)((*data)*macosx_top_left_corner[i]);
      *data++ = (unsigned char)((*data)*macosx_top_left_corner[i]);
         data++; // skip alpha
    }
    pixels -= 512;   
    register int c = 0;
    for(register int i = 0; i < pixels; i++) {
              *data++ = (unsigned char)((*data)*macosx_shadow_strip_left[c]);
           *data++ = (unsigned char)((*data)*macosx_shadow_strip_left[c]);
           *data++ = (unsigned char)((*data)*macosx_shadow_strip_left[c]);
           data++; // skip alpha
        c = ++c % 16;
   }
    for(register int i = 0; i < 256; i++) {
      *data++ = (unsigned char)((*data)*macosx_bottom_left_corner[i]);
      *data++ = (unsigned char)((*data)*macosx_bottom_left_corner[i]);
      *data++ = (unsigned char)((*data)*macosx_bottom_left_corner[i]);
      data++; // skip alpha
    }
}

void Acqua::slotRemoveShadow()
{
 	if (se.w1 != NULL)
 	{
 		AcquaNamespace::shadowWidgets.removeRef(se.w1);
 		delete se.w1;
 	}
 	if (se.w2 != NULL)
 	{
 		AcquaNamespace::shadowWidgets.removeRef(se.w2);
 		delete se.w2;
 	}
 	if (se.w3 != NULL)
 	{
 		delete se.w3;
 		AcquaNamespace::shadowWidgets.removeRef(se.w3);
 	}
 	se.w1 = NULL;
 	se.w2 = NULL;
 	se.w3 = NULL;

 	shadowRedrawTimer->stop();
}

void Acqua::slotDrawShadow()
{
 	slotRemoveShadow();

 	switch(AcquaNamespace::shadowType)
 	{
 		case 1: drawWindowsShadow(); break;
 		case 2: drawMacOSXShadow(); break;
 	}

 	if (AcquaNamespace::shadowUpdateInterval != 0)
 		shadowRedrawTimer->start(AcquaNamespace::shadowUpdateInterval); // Paint again in a specified number of miliseconds
}

void Acqua::doShadowShape(QWidget* w)
{
	// This function gets a list of windows above this one, sees which ones overlap
	// our shadow (w), and creates a mask (a QRegion) to block out those parts of w


	unsigned int numkids, i;
	Window r, p, *kids;
	XQueryTree(x11AppDisplay(), x11AppRootWindow(), &r, &p, &kids, &numkids); // Gets a list of windows, in stacking order
	XWindowAttributes attr;
	bool add=false;
	QValueList<QRect> cropRects;
	QRegion mask(0,0,w->width(),w->height());
	QPtrList<Acqua> windowsToUpdate;
	for (i = 0; i < numkids;  ++i)
	{
		XGetWindowAttributes(x11AppDisplay(), kids[i], &attr);
		if (attr.map_state != IsViewable)
			continue;

		if (!add)
		{
			if ((kids[i] == winId()) || (isThisMyParent(x11AppDisplay(), kids[i], winId())))  // We havn't seen our window yet
			{
				add=true; // This is our window, that means the ones next will be above it, so start adding them to the mask
				continue;
			}

			/*if (moving) // If we've just moved, update any shadows
			{
				QPtrListIterator<AcquaShadow> it(AcquaNamespace::shadowWidgets); // Sees if this window is a shadow
				while (it.current() != 0)
				{
					qDebug("Iterating - " + QString::number(it.current()->winId()) + "," + QString::number(kids[i]));
					if (it.current()->winId() == kids[i])
					{
						qDebug("found shadow");
						// This window is a shadow
						QRect rect(attr.x,attr.y,attr.width,attr.height);
						if ((!rect.intersects(geometry())) && (!rect.intersects(oldPos))) // See if this shadow intersects me or my old location
							continue;
						qDebug("Intersects");
						if (windowsToUpdate.findRef(it.current()->owner) == -1) // We're not already updating this window
							windowsToUpdate.append(it.current()->owner);
						break;
					}
					++it;
				}
			}*/
		}
		else
		{
			bool skipIt = false;
			QPtrListIterator<AcquaShadow> it(AcquaNamespace::shadowWidgets); // Sees if this window is a shadow
			while (it.current() != 0)
			{
				if (it.current()->winId() == kids[i])
				{
					skipIt=true;
					break;
				}
				++it;
			}

			QRect rect(attr.x,attr.y,attr.width,attr.height);

			if ((skipIt) && (moving) && ((rect.intersects(geometry())) || (rect.intersects(oldPos))))
			{
				if (windowsToUpdate.findRef(it.current()->owner) == -1) // We're not already updating this window
				{
					windowsToUpdate.append(it.current()->owner);
				}
			}
			if (skipIt) continue;

			if (!rect.intersects(w->geometry())) // See if this window intersects our shadow
				continue;

			QRect cropRect = rect.intersect(w->geometry()); // Get the rect where this window and our shadow intersect
			cropRect.moveLeft(cropRect.x()-w->geometry().x()); // Move it so it's relative to the shadow rect
			cropRect.moveTop(cropRect.y()-w->geometry().y());
			mask -= QRegion(cropRect); // Subtract it from the mask
		}
	}
	if(kids != NULL)
		XFree(kids);

	if (moving)
	{
		moving = false;

		QPtrListIterator<Acqua> it(windowsToUpdate);
		while (it.current() != 0)
		{
			it.current()->slotDrawShadow();
			++it;
		}
	}

	w->setMask(mask);
	moving = false;
}

bool Acqua::isThisMyParent(Display* display, Window root, Window me)
{
	unsigned int numkids, i;
	Window r, p, *kids;

	XQueryTree(display, root, &r, &p, &kids, &numkids);
	XWindowAttributes attr;
	for (i = 0; i < numkids;  ++i)
	{
		XGetWindowAttributes(display, kids[i], &attr);
		if (attr.map_state != IsViewable)
			continue;

		if ((kids[i] == me) || (isThisMyParent(display,kids[i],me)))
		{
			XFree(kids);
			return true;
		}
	}
	if(kids != NULL)
		XFree(kids);
	return false;
}


void Acqua::drawWindowsShadow()
{
	se.w1 = new AcquaShadow(this);
	se.w2 = new AcquaShadow(this);
	int x2 = x()+width();
	int y2 = y()+height();
	QRect shadow1(x2, y() + 4, 4, height());
	QRect shadow2(x() + 4, y2, width() - 4, 4);

	// Delete previous shadows...
	XUnmapWindow(qt_xdisplay(), se.w1->winId());
	XUnmapWindow(qt_xdisplay(), se.w2->winId());
	QApplication::flush();

	doShadowShape(se.w1); // These take quite a long time, so we do it before the grab
	doShadowShape(se.w2); // to let the windows behind update themselves... in theory...

	// Create a fake drop-down shadow effect via blended Xwindows
	se.w1->setGeometry(shadow1);
	se.w2->setGeometry(shadow2);
	XSelectInput(qt_xdisplay(), se.w1->winId(), StructureNotifyMask );
	XSelectInput(qt_xdisplay(), se.w2->winId(), StructureNotifyMask );

	// Grab!
	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());


	//proccess image...
	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
	XMapWindow(qt_xdisplay(), se.w1->winId());
	XMapWindow(qt_xdisplay(), se.w2->winId());

	AcquaNamespace::shadowWidgets.append(se.w1);
	AcquaNamespace::shadowWidgets.append(se.w2);
}
void Acqua::drawMacOSXShadow()
{
	int x2 = x()+width();
	int y2 = y()+height();

	QRect shadow1(x2, y(), 16, height() + 8);          //right
	QRect shadow2(x(), y2, width(), 18);             //bottom
	QRect shadow3(x() - 16, y(), 16, height() + 8); //left

	// Create a fake drop-down shadow effect via blended Xwindows
	se.w1 = new AcquaShadow(this);
	se.w2 = new AcquaShadow(this);
	se.w3 = new AcquaShadow(this);

	// Delete previous shadows...
	XUnmapWindow(qt_xdisplay(), se.w1->winId());
	XUnmapWindow(qt_xdisplay(), se.w2->winId());
	XUnmapWindow(qt_xdisplay(), se.w3->winId());
	QApplication::flush();

	se.w1->setGeometry(shadow1);
	se.w2->setGeometry(shadow2);
	se.w3->setGeometry(shadow3);

	XSelectInput(qt_xdisplay(), se.w1->winId(), StructureNotifyMask );
	XSelectInput(qt_xdisplay(), se.w2->winId(), StructureNotifyMask );
	XSelectInput(qt_xdisplay(), se.w3->winId(), StructureNotifyMask );

	doShadowShape(se.w1);
	doShadowShape(se.w2);
	doShadowShape(se.w3);


	// 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());
	QPixmap pix_shadow3 = QPixmap::grabWindow(qt_xrootwin(),
			shadow3.x(), shadow3.y(), shadow3.width(), shadow3.height());

	QImage img;
	img = pix_shadow1.convertToImage();
		rightShadow(img);
		pix_shadow1.convertFromImage(img);
	img = pix_shadow2.convertToImage();
		bottomShadow(img);
		pix_shadow2.convertFromImage(img);
	img = pix_shadow3.convertToImage();
		leftShadow(img);
		pix_shadow3.convertFromImage(img);

	// Set the background pixmaps
	se.w1->setErasePixmap(pix_shadow1);
	se.w2->setErasePixmap(pix_shadow2);
	se.w3->setErasePixmap(pix_shadow3);

	// Show the 'shadow' just before showing the popup menu window
	XMapWindow(qt_xdisplay(), se.w1->winId());
	XMapWindow(qt_xdisplay(), se.w2->winId());
	XMapWindow(qt_xdisplay(), se.w3->winId());

	AcquaNamespace::shadowWidgets.append(se.w1);
	AcquaNamespace::shadowWidgets.append(se.w2);
	AcquaNamespace::shadowWidgets.append(se.w3);
}


void Acqua::activeChange(bool b)
{
	for (QListIterator<AcquaButton> it(leftButtonList_); it.current(); ++it)
	{
		it.current()->repaint();
	}

	for (QListIterator<AcquaButton> it(rightButtonList_); it.current(); ++it)
	{
		it.current()->repaint();
	}

	if ((!AcquaNamespace::allWindowsShadowed) && (!b)) // Only the current window should be painted, and this window has gone inactive
		slotRemoveShadow();
	else
	{
		if ((AcquaNamespace::shadowType != 0) && (!isIconified()))
			slotDrawShadow(); // do first painting NOW
	}

 repaint();
}

//  Client::MousePosition
//Acqua::mousePosition(const QPoint & p) const
//{
//  int x = p.x();
//  int y = p.y();
//
//  if (y < titleSpacer_->geometry().height()+8)
//  {
//      return Client::Center;
//  }
//  else if (y < height() - 20)
//  {
//    if (x < 4)
//      return Client::Left;
//    else
//      return Client::Right;
//  }
//  else
//  {
//    if (x < 20)
//      return Client::BottomLeft;
//    else
//      if (x > width() - 20)
//        return Client::BottomRight;
//      else
//        return Client::Bottom;
//  }
//
//  return Client::mousePosition(p);
//}

  void
Acqua::slotReset()
{
  _resetLayout();
  repaint();
}

  void
Acqua::slotMaximize(int button)
{
  switch (button)
  {
    case MidButton:
      maximize(MaximizeVertical);
      break;

    case RightButton:
      maximize(MaximizeHorizontal);
      break;

    case LeftButton:
    default:
      maximize(MaximizeFull);
  }
}

void 
Acqua::slotPopupMenu(QPoint pos)
{
  workspace()->clientPopup(this)->popup(pos);
}

AcquaButton *
Acqua::_createButton(const QString & s, QWidget * parent)
{
  AcquaButton * b = 0;

  if (("Help" == s) && providesContextHelp())
  {
    b = new AcquaButtonHelp(parent);
    connect(b, SIGNAL(help()), this, SLOT(contextHelp()));
  }
  else if ("Menu" == s)
  {
    b = new AcquaButtonMenu(parent);
    connect(b, SIGNAL(popupMenu(QPoint)), this, SLOT(slotPopupMenu(QPoint)));
  }
  else if ("Iconify" == s && isMinimizable())
  {
    b = new AcquaButtonIconify(parent);
    connect(b, SIGNAL(iconify()), this, SLOT(iconify()));
  }

  else if ("Maximize" == s && isMaximizable())
  {
    b = new AcquaButtonMaximize(isMaximized(), parent);
    connect(b, SIGNAL(maximize(int)), this, SLOT(slotMaximize(int)));
    connect(this, SIGNAL(maxChange(bool)), b, SLOT(slotMaximizeChange(bool)));
  }

  else if ("Close" == s)
  {
    b = new AcquaButtonClose(parent);
    connect(b, SIGNAL(closeWindow()), this, SLOT(closeWindow()));
  }

  return b;
}

  void
Acqua::_createButtons()
{
  leftButtonList_   .clear();
  rightButtonList_  .clear();

  QString buttons;

  if (AcquaNamespace::rightXIAButtons==0) {

      if (AcquaNamespace::rightButtonIs==2) { buttons = "XIA|H" ;}
      else if (AcquaNamespace::rightButtonIs==1) { buttons = "XIA|M" ;}
      else { buttons = "XIA" ;}
        }
  //else buttons = options->titleButtonsLeft() + "|" + options->titleButtonsRight();
  else {

      if (AcquaNamespace::rightButtonIs==2) { buttons = "H|IAX" ;}
      else if (AcquaNamespace::rightButtonIs==1) { buttons = "M|IAX" ;}
      else { buttons = "|IAX" ;}
        }


  QList<AcquaButton> *buttonList = &leftButtonList_;

  for (unsigned int i = 0; i < buttons.length(); ++i)
  {
    AcquaButton * tb = 0;
    switch (buttons[i].latin1())
    {
      case 'M': // Menu
        tb = _createButton("Menu", this);
        break;

      case 'H': // Help
        tb = _createButton("Help", this);
        break;

      case 'I': // Minimize
        tb = _createButton("Iconify", this);
        break;

      case 'A': // Maximize
        tb = _createButton("Maximize", this);
        break;

      case 'X': // Close
        tb = _createButton("Close", this);
        break;

      case '|':
        buttonList = &rightButtonList_;
        break;
    }
    if (0 != tb)
      buttonList->append(tb);
  }
}

  void
Acqua::_resetLayout()
{
//  KConfig c(locate("config", "kwinwebrc"));
//  c.setGroup("General");
//  shape_ = c.readBoolEntry("Shape", true);

  //  ____________________________________
  // |  |                              |  |
  // |Xo|     titleSpacer              |v^| <--- topLayout
  // |__|______________________________|__|
  // | |                                | |
  // | |                                | |
  // | |     windowWrapper              | |
  // | |                                | | <--- midLayout
  // | |                                | |
  // | |                                | |
  // | |________________________________| |
  // |____________________________________|

  QFontMetrics fm(options->font(isActive(), tool_));

  uint titleHeight = QMAX(14, fm.height());

  if (0 != titleHeight % 2)
    titleHeight += 1;

  delete mainLayout_;

  mainLayout_  = new QVBoxLayout(this, 0, 0);

  titleSpacer_ =
    new QSpacerItem
    (
     0,
     titleHeight,
     QSizePolicy::Expanding,
     QSizePolicy::Fixed
    );

  QHBoxLayout * topLayout   = new QHBoxLayout(mainLayout_, 0, 0);
  topLayout->setMargin(topMargin);

  _createButtons();

  // Add left-side buttons.

  topLayout->addSpacing(topSideMargin);
  topLayout->addSpacing(1);
  for (QListIterator<AcquaButton> it(leftButtonList_); it.current(); ++it)
      {
        topLayout->addWidget(it.current(), Qt::AlignVCenter);
        topLayout->setStretchFactor(it.current(), 0);
        if (AcquaNamespace::rightXIAButtons==0) topLayout->addSpacing(6);
        //  it.current()->setFixedSize(titleHeight, titleHeight);
      }


  topLayout->addItem(titleSpacer_);

  // Add right-side buttons.

  for (QListIterator<AcquaButton> it(rightButtonList_); it.current(); ++it)
  {
    if (AcquaNamespace::rightXIAButtons==1) topLayout->addSpacing(6);
    topLayout->addWidget(it.current(), Qt::AlignVCenter);
    topLayout->setStretchFactor(it.current(), 0);
  //  it.current()->setFixedSize(titleHeight, titleHeight);
  }

  topLayout->addSpacing(topSideMargin);
  // -------------------------------------------------------------------

  QHBoxLayout * midLayout   = new QHBoxLayout(mainLayout_, 0, 0);

  midLayout->addSpacing(sideMargin);
  midLayout->addWidget(windowWrapper());
  midLayout->addSpacing(sideMargin);

  // -------------------------------------------------------------------

  mainLayout_->addSpacing(bottomMargin);

  // Make sure that topLayout doesn't stretch - midLayout should take
  // all spare space.

  mainLayout_->setStretchFactor(topLayout, 0);
  mainLayout_->setStretchFactor(midLayout, 1);
}

  void
Acqua::animateIconifyOrDeiconify(bool /* iconify */)
{
  // Nice and simple ;)
}

extern "C"
{
  Client * allocate(Workspace * ws, WId w, int tool)
  {
    return new Acqua(ws, w, tool != 0);
  }

  void init()
  {
    AcquaNamespace::readConfig();
  }

  void reset()
  {
    AcquaNamespace::readConfig();
    Workspace::self()->slotResetAllClientsDelayed();
  }

  void deinit()
  {
    // Empty.
  }
}


#include "Acqua.moc"
// vim:ts=2:sw=2:tw=78:set et:
