kwin/clients/kde2/kde2.cpp
Luboš Luňák 0170623a9c Separate KCommonDecoration from KDecoration, in order to allow
greater possibilities in extending KDecoration. KCommonDecoration
now does not inherit KDecoration, only wraps it (i.e. it's source
compatible). Added comments on how to extend KDecoration
in the future by subclassing to KDecoration2, added PORTING
document with all API changes in KDE4.
CCMAIL: kwin@kde.org


svn path=/trunk/KDE/kdebase/workspace/; revision=742976
2007-11-29 14:11:02 +00:00

1078 lines
31 KiB
C++

/*
*
* KDE2 Default KWin client
*
* Copyright (C) 1999, 2001 Daniel Duley <mosfet@kde.org>
* Matthias Ettrich <ettrich@kde.org>
* Karol Szwed <gallium@kde.org>
*
* Draws mini titlebars for tool windows.
* Many features are now customizable.
*
* drawColorBitmaps orignally from kdefx:
* Copyright (C) 1999 Daniel M. Duley <mosfet@kde.org>
*/
#include "kde2.h"
#include <kconfiggroup.h>
#include <kglobal.h>
#include <klocale.h>
#include <kdebug.h>
#include <QLayout>
#include <QBitmap>
#include <QImage>
#include <QApplication>
#include <QLabel>
#include <QPixmap>
#include <QPolygon>
#include <QStyle>
#include <QPainter>
namespace KDE2
{
static const unsigned char iconify_bits[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x78, 0x00, 0x78, 0x00,
0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
static const unsigned char close_bits[] = {
0x00, 0x00, 0x84, 0x00, 0xce, 0x01, 0xfc, 0x00, 0x78, 0x00, 0x78, 0x00,
0xfc, 0x00, 0xce, 0x01, 0x84, 0x00, 0x00, 0x00};
static const unsigned char maximize_bits[] = {
0x00, 0x00, 0xfe, 0x01, 0xfe, 0x01, 0x86, 0x01, 0x86, 0x01, 0x86, 0x01,
0x86, 0x01, 0xfe, 0x01, 0xfe, 0x01, 0x00, 0x00};
static const unsigned char minmax_bits[] = {
0x7f, 0x00, 0x7f, 0x00, 0x63, 0x00, 0xfb, 0x03, 0xfb, 0x03, 0x1f, 0x03,
0x1f, 0x03, 0x18, 0x03, 0xf8, 0x03, 0xf8, 0x03};
static const unsigned char question_bits[] = {
0x00, 0x00, 0x78, 0x00, 0xcc, 0x00, 0xc0, 0x00, 0x60, 0x00, 0x30, 0x00,
0x00, 0x00, 0x30, 0x00, 0x30, 0x00, 0x00, 0x00};
static const unsigned char above_on_bits[] = {
0x00, 0x00, 0xfe, 0x01, 0xfe, 0x01, 0x30, 0x00, 0xfc, 0x00, 0x78, 0x00,
0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
static const unsigned char above_off_bits[] = {
0x30, 0x00, 0x78, 0x00, 0xfc, 0x00, 0x30, 0x00, 0xfe, 0x01, 0xfe, 0x01,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
static const unsigned char below_on_bits[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x78, 0x00, 0xfc, 0x00,
0x30, 0x00, 0xfe, 0x01, 0xfe, 0x01, 0x00, 0x00 };
static const unsigned char below_off_bits[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x01, 0xfe, 0x01,
0x30, 0x00, 0xfc, 0x00, 0x78, 0x00, 0x30, 0x00 };
static const unsigned char shade_on_bits[] = {
0x00, 0x00, 0xfe, 0x01, 0xfe, 0x01, 0xfe, 0x01, 0x02, 0x01, 0x02, 0x01,
0x02, 0x01, 0x02, 0x01, 0xfe, 0x01, 0x00, 0x00 };
static const unsigned char shade_off_bits[] = {
0x00, 0x00, 0xfe, 0x01, 0xfe, 0x01, 0xfe, 0x01, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
static const unsigned char pindown_white_bits[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x80, 0x1f, 0xa0, 0x03,
0xb0, 0x01, 0x30, 0x01, 0xf0, 0x00, 0x70, 0x00, 0x20, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
static const unsigned char pindown_gray_bits[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c,
0x00, 0x0e, 0x00, 0x06, 0x00, 0x00, 0x80, 0x07, 0xc0, 0x03, 0xe0, 0x01,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
static const unsigned char pindown_dgray_bits[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xc0, 0x10, 0x70, 0x20, 0x50, 0x20,
0x48, 0x30, 0xc8, 0x38, 0x08, 0x1f, 0x08, 0x18, 0x10, 0x1c, 0x10, 0x0e,
0xe0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
static const unsigned char pindown_mask_bits[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xc0, 0x1f, 0xf0, 0x3f, 0xf0, 0x3f,
0xf8, 0x3f, 0xf8, 0x3f, 0xf8, 0x1f, 0xf8, 0x1f, 0xf0, 0x1f, 0xf0, 0x0f,
0xe0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
static const unsigned char pinup_white_bits[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x80, 0x11,
0x3f, 0x15, 0x00, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
static const unsigned char pinup_gray_bits[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x80, 0x0a, 0xbf, 0x0a, 0x80, 0x15, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
static const unsigned char pinup_dgray_bits[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x20, 0x40, 0x31, 0x40, 0x2e,
0x40, 0x20, 0x40, 0x20, 0x7f, 0x2a, 0x40, 0x3f, 0xc0, 0x31, 0xc0, 0x20,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
static const unsigned char pinup_mask_bits[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x20, 0xc0, 0x31, 0xc0, 0x3f,
0xff, 0x3f, 0xff, 0x3f, 0xff, 0x3f, 0xc0, 0x3f, 0xc0, 0x31, 0xc0, 0x20,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
void drawColorBitmaps(QPainter *p, const QPalette &pal, int x, int y, int w, int h,
const uchar *lightColor, const uchar *midColor, const uchar *blackColor)
{
const uchar *data[]={lightColor, midColor, blackColor};
QColor colors[]={pal.color(QPalette::Light), pal.color(QPalette::Mid), Qt::black};
int i;
QSize s(w,h);
for(i=0; i < 3; ++i){
QBitmap b = QBitmap::fromData(s, data[i], QImage::Format_MonoLSB );
b.setMask(b);
p->setPen(colors[i]);
p->drawPixmap(x, y, b);
}
}
// ===========================================================================
static QPixmap* titlePix;
static QPixmap* titleBuffer;
static QPixmap* aUpperGradient;
static QPixmap* iUpperGradient;
static QPixmap* pinDownPix;
static QPixmap* pinUpPix;
static QPixmap* ipinDownPix;
static QPixmap* ipinUpPix;
static QPixmap* rightBtnUpPix[2];
static QPixmap* rightBtnDownPix[2];
static QPixmap* irightBtnUpPix[2];
static QPixmap* irightBtnDownPix[2];
static QPixmap* leftBtnUpPix[2];
static QPixmap* leftBtnDownPix[2];
static QPixmap* ileftBtnUpPix[2];
static QPixmap* ileftBtnDownPix[2];
static KDE2Handler* clientHandler;
static int toolTitleHeight;
static int normalTitleHeight;
static int borderWidth;
static int grabBorderWidth;
static bool KDE2_initialized = false;
static bool useGradients;
static bool showGrabBar;
static bool showTitleBarStipple;
// ===========================================================================
KDE2Handler::KDE2Handler()
{
clientHandler = this;
readConfig( false );
createPixmaps();
KDE2_initialized = true;
}
KDE2Handler::~KDE2Handler()
{
KDE2_initialized = false;
freePixmaps();
clientHandler = NULL;
}
KDecoration* KDE2Handler::createDecoration( KDecorationBridge* b )
{
return ( new KDE2Client( b, this ))->decoration();
}
bool KDE2Handler::reset( unsigned long changed )
{
KDE2_initialized = false;
changed |= readConfig( true );
if( changed & SettingColors )
{ // pixmaps need to be recreated
freePixmaps();
createPixmaps();
}
KDE2_initialized = true;
// SettingButtons is handled by KCommonDecoration
bool need_recreate = ( changed & ( SettingDecoration | SettingFont | SettingBorder )) != 0;
if( need_recreate ) // something else than colors changed
return true;
resetDecorations( changed );
return false;
}
unsigned long KDE2Handler::readConfig( bool update )
{
unsigned long changed = 0;
KConfig c("kwinKDE2rc");
KConfigGroup conf(&c, "General");
bool new_showGrabBar = conf.readEntry("ShowGrabBar", true);
bool new_showTitleBarStipple = conf.readEntry("ShowTitleBarStipple", true);
bool new_useGradients = conf.readEntry("UseGradients", true);
int new_titleHeight = QFontMetrics(options()->font(true)).height() - 2;
int new_toolTitleHeight = QFontMetrics(options()->font(true, true)).height() - 4;
int new_borderWidth;
switch(options()->preferredBorderSize(this)) {
case BorderLarge:
new_borderWidth = 8;
break;
case BorderVeryLarge:
new_borderWidth = 12;
break;
case BorderHuge:
new_borderWidth = 18;
break;
case BorderVeryHuge:
new_borderWidth = 27;
break;
case BorderOversized:
new_borderWidth = 40;
break;
case BorderTiny:
case BorderNormal:
default:
new_borderWidth = 4;
}
if (new_titleHeight < 16) new_titleHeight = 16;
if (new_titleHeight < new_borderWidth) new_titleHeight = new_borderWidth;
if (new_toolTitleHeight < 12) new_toolTitleHeight = 12;
if (new_toolTitleHeight < new_borderWidth) new_toolTitleHeight = new_borderWidth;
if( update )
{
if( new_showGrabBar != showGrabBar
|| new_titleHeight != normalTitleHeight
|| new_toolTitleHeight != toolTitleHeight
|| new_borderWidth != borderWidth )
changed |= SettingDecoration; // need recreating the decoration
if( new_showTitleBarStipple != showTitleBarStipple
|| new_useGradients != useGradients
|| new_titleHeight != normalTitleHeight
|| new_toolTitleHeight != toolTitleHeight )
changed |= SettingColors; // just recreate the pixmaps and repaint
}
showGrabBar = new_showGrabBar;
showTitleBarStipple = new_showTitleBarStipple;
useGradients = new_useGradients;
normalTitleHeight = new_titleHeight;
toolTitleHeight = new_toolTitleHeight;
borderWidth = new_borderWidth;
grabBorderWidth = (borderWidth > 15) ? borderWidth + 15 : 2*borderWidth;
return changed;
}
static void gradientFill(QPixmap *pixmap, const QColor &color1, const QColor &color2)
{
QPainter p(pixmap);
QLinearGradient gradient(0, 0, 0, pixmap->height());
gradient.setColorAt(0.0, color1);
gradient.setColorAt(1.0, color2);
QBrush brush(gradient);
p.fillRect(pixmap->rect(), brush);
}
// This paints the button pixmaps upon loading the style.
void KDE2Handler::createPixmaps()
{
bool highcolor = useGradients && (QPixmap::defaultDepth() > 8);
// Make the titlebar stipple optional
if (showTitleBarStipple)
{
QPainter p;
QPainter maskPainter;
int i, x, y;
titlePix = new QPixmap(132, normalTitleHeight+2);
QBitmap mask(132, normalTitleHeight+2);
mask.fill(Qt::color0);
p.begin(titlePix);
maskPainter.begin(&mask);
maskPainter.setPen(Qt::color1);
for(i=0, y=2; i < 9; ++i, y+=4)
for(x=1; x <= 132; x+=3)
{
p.setPen(options()->color(ColorTitleBar, true).light(150));
p.drawPoint(x, y);
maskPainter.drawPoint(x, y);
p.setPen(options()->color(ColorTitleBar, true).dark(150));
p.drawPoint(x+1, y+1);
maskPainter.drawPoint(x+1, y+1);
}
maskPainter.end();
p.end();
titlePix->setMask(mask);
} else
titlePix = NULL;
QColor activeTitleColor1(options()->color(ColorTitleBar, true));
QColor activeTitleColor2(options()->color(ColorTitleBlend, true));
QColor inactiveTitleColor1(options()->color(ColorTitleBar, false));
QColor inactiveTitleColor2(options()->color(ColorTitleBlend, false));
// Create titlebar gradient images if required
aUpperGradient = NULL;
iUpperGradient = NULL;
if(highcolor)
{
QSize s(128, normalTitleHeight + 2);
// Create the titlebar gradients
if (activeTitleColor1 != activeTitleColor2)
{
aUpperGradient = new QPixmap(s);
gradientFill(aUpperGradient, activeTitleColor1, activeTitleColor2);
}
if (inactiveTitleColor1 != inactiveTitleColor2)
{
iUpperGradient = new QPixmap(s);
gradientFill(iUpperGradient, inactiveTitleColor1, inactiveTitleColor2);
}
}
// Set the sticky pin pixmaps;
QPalette g;
QPainter p;
// Active pins
g = options()->palette( ColorButtonBg, true );
QImage pinUpImg = QImage(16, 16, QImage::Format_ARGB32_Premultiplied);
p.begin( &pinUpImg );
drawColorBitmaps( &p, g, 0, 0, 16, 16, pinup_white_bits, pinup_gray_bits, pinup_dgray_bits );
p.end();
pinUpPix = new QPixmap(QPixmap::fromImage(pinUpImg));
pinUpPix->setMask( QBitmap::fromData(QSize( 16, 16 ), pinup_mask_bits) );
QImage pinDownImg = QImage(16, 16, QImage::Format_ARGB32_Premultiplied);
p.begin( &pinDownImg );
drawColorBitmaps( &p, g, 0, 0, 16, 16, pindown_white_bits, pindown_gray_bits, pindown_dgray_bits );
p.end();
pinDownPix = new QPixmap(QPixmap::fromImage(pinDownImg));
pinDownPix->setMask( QBitmap::fromData(QSize( 16, 16 ), pindown_mask_bits) );
// Inactive pins
g = options()->palette( ColorButtonBg, false );
QImage ipinUpImg = QImage(16, 16, QImage::Format_ARGB32_Premultiplied);
p.begin( &ipinUpImg );
drawColorBitmaps( &p, g, 0, 0, 16, 16, pinup_white_bits, pinup_gray_bits, pinup_dgray_bits );
p.end();
ipinUpPix = new QPixmap(QPixmap::fromImage(ipinUpImg));
ipinUpPix->setMask( QBitmap::fromData(QSize( 16, 16 ), pinup_mask_bits) );
QImage ipinDownImg = QImage(16, 16, QImage::Format_ARGB32_Premultiplied);
p.begin( &ipinDownImg );
drawColorBitmaps( &p, g, 0, 0, 16, 16, pindown_white_bits, pindown_gray_bits, pindown_dgray_bits );
p.end();
ipinDownPix = new QPixmap(QPixmap::fromImage(ipinDownImg));
ipinDownPix->setMask( QBitmap::fromData(QSize( 16, 16 ), pindown_mask_bits) );
// Create a title buffer for flicker-free painting
titleBuffer = new QPixmap();
// Cache all possible button states
leftBtnUpPix[true] = new QPixmap(normalTitleHeight, normalTitleHeight);
leftBtnDownPix[true] = new QPixmap(normalTitleHeight, normalTitleHeight);
ileftBtnUpPix[true] = new QPixmap(normalTitleHeight, normalTitleHeight);
ileftBtnDownPix[true] = new QPixmap(normalTitleHeight, normalTitleHeight);
rightBtnUpPix[true] = new QPixmap(normalTitleHeight, normalTitleHeight);
rightBtnDownPix[true] = new QPixmap(normalTitleHeight, normalTitleHeight);
irightBtnUpPix[true] = new QPixmap(normalTitleHeight, normalTitleHeight);
irightBtnDownPix[true] = new QPixmap(normalTitleHeight, normalTitleHeight);
leftBtnUpPix[false] = new QPixmap(toolTitleHeight, normalTitleHeight);
leftBtnDownPix[false] = new QPixmap(toolTitleHeight, normalTitleHeight);
ileftBtnUpPix[false] = new QPixmap(normalTitleHeight, normalTitleHeight);
ileftBtnDownPix[false] = new QPixmap(normalTitleHeight, normalTitleHeight);
rightBtnUpPix[false] = new QPixmap(toolTitleHeight, toolTitleHeight);
rightBtnDownPix[false] = new QPixmap(toolTitleHeight, toolTitleHeight);
irightBtnUpPix[false] = new QPixmap(toolTitleHeight, toolTitleHeight);
irightBtnDownPix[false] = new QPixmap(toolTitleHeight, toolTitleHeight);
// Draw the button state pixmaps
g = options()->palette( ColorTitleBar, true );
drawButtonBackground( leftBtnUpPix[true], g, false );
drawButtonBackground( leftBtnDownPix[true], g, true );
drawButtonBackground( leftBtnUpPix[false], g, false );
drawButtonBackground( leftBtnDownPix[false], g, true );
g = options()->palette( ColorButtonBg, true );
drawButtonBackground( rightBtnUpPix[true], g, false );
drawButtonBackground( rightBtnDownPix[true], g, true );
drawButtonBackground( rightBtnUpPix[false], g, false );
drawButtonBackground( rightBtnDownPix[false], g, true );
g = options()->palette( ColorTitleBar, false );
drawButtonBackground( ileftBtnUpPix[true], g, false );
drawButtonBackground( ileftBtnDownPix[true], g, true );
drawButtonBackground( ileftBtnUpPix[false], g, false );
drawButtonBackground( ileftBtnDownPix[false], g, true );
g = options()->palette( ColorButtonBg, false );
drawButtonBackground( irightBtnUpPix[true], g, false );
drawButtonBackground( irightBtnDownPix[true], g, true );
drawButtonBackground( irightBtnUpPix[false], g, false );
drawButtonBackground( irightBtnDownPix[false], g, true );
}
void KDE2Handler::freePixmaps()
{
// Free button pixmaps
if (rightBtnUpPix[true])
delete rightBtnUpPix[true];
if(rightBtnDownPix[true])
delete rightBtnDownPix[true];
if (irightBtnUpPix[true])
delete irightBtnUpPix[true];
if (irightBtnDownPix[true])
delete irightBtnDownPix[true];
if (leftBtnUpPix[true])
delete leftBtnUpPix[true];
if(leftBtnDownPix[true])
delete leftBtnDownPix[true];
if (ileftBtnUpPix[true])
delete ileftBtnUpPix[true];
if (ileftBtnDownPix[true])
delete ileftBtnDownPix[true];
if (rightBtnUpPix[false])
delete rightBtnUpPix[false];
if(rightBtnDownPix[false])
delete rightBtnDownPix[false];
if (irightBtnUpPix[false])
delete irightBtnUpPix[false];
if (irightBtnDownPix[false])
delete irightBtnDownPix[false];
if (leftBtnUpPix[false])
delete leftBtnUpPix[false];
if(leftBtnDownPix[false])
delete leftBtnDownPix[false];
if (ileftBtnUpPix[false])
delete ileftBtnUpPix[false];
if (ileftBtnDownPix[false])
delete ileftBtnDownPix[false];
// Title images
if (titleBuffer)
delete titleBuffer;
if (titlePix)
delete titlePix;
if (aUpperGradient)
delete aUpperGradient;
if (iUpperGradient)
delete iUpperGradient;
// Sticky pin images
if (pinUpPix)
delete pinUpPix;
if (ipinUpPix)
delete ipinUpPix;
if (pinDownPix)
delete pinDownPix;
if (ipinDownPix)
delete ipinDownPix;
}
void KDE2Handler::drawButtonBackground(QPixmap *pix,
const QPalette &g, bool sunken)
{
QPainter p;
int w = pix->width();
int h = pix->height();
int x2 = w-1;
int y2 = h-1;
bool highcolor = useGradients && (QPixmap::defaultDepth() > 8);
QColor c = g.color( QPalette::Background );
// Fill the background with a gradient if possible
if (highcolor)
gradientFill(pix, c.light(130), c.dark(130));
else
pix->fill(c);
p.begin(pix);
// outer frame
p.setPen(g.color( QPalette::Mid ));
p.drawLine(0, 0, x2, 0);
p.drawLine(0, 0, 0, y2);
p.setPen(g.color( QPalette::Light ));
p.drawLine(x2, 0, x2, y2);
p.drawLine(0, x2, y2, x2);
p.setPen(g.color( QPalette::Dark ));
p.drawRect(1, 1, w-3, h-3);
p.setPen(sunken ? g.color( QPalette::Mid ) : g.color( QPalette::Light ));
p.drawLine(2, 2, x2-2, 2);
p.drawLine(2, 2, 2, y2-2);
p.setPen(sunken ? g.color( QPalette::Light ) : g.color( QPalette::Mid ));
p.drawLine(x2-2, 2, x2-2, y2-2);
p.drawLine(2, x2-2, y2-2, x2-2);
}
QList< KDE2Handler::BorderSize > KDE2Handler::borderSizes() const
{ // the list must be sorted
return QList< BorderSize >() << BorderNormal << BorderLarge <<
BorderVeryLarge << BorderHuge << BorderVeryHuge << BorderOversized;
}
bool KDE2Handler::supports( Ability ability ) const
{
switch( ability )
{
case AbilityAnnounceButtons:
case AbilityButtonMenu:
case AbilityButtonOnAllDesktops:
case AbilityButtonSpacer:
case AbilityButtonHelp:
case AbilityButtonMinimize:
case AbilityButtonMaximize:
case AbilityButtonClose:
case AbilityButtonAboveOthers:
case AbilityButtonBelowOthers:
case AbilityButtonShade:
return true;
default:
return false;
};
}
// ===========================================================================
KDE2Button::KDE2Button(ButtonType type, KDE2Client *parent, const char *name)
: KCommonDecorationButton(type, parent)
{
setObjectName( name );
setAttribute( Qt::WA_NoBackground );
isMouseOver = false;
deco = NULL;
large = !decoration()->isToolWindow();
}
KDE2Button::~KDE2Button()
{
if (deco)
delete deco;
}
void KDE2Button::reset(unsigned long changed)
{
if (changed&DecorationReset || changed&ManualReset || changed&SizeChange || changed&StateChange) {
switch (type() ) {
case CloseButton:
setBitmap(close_bits);
break;
case HelpButton:
setBitmap(question_bits);
break;
case MinButton:
setBitmap(iconify_bits);
break;
case MaxButton:
setBitmap( isChecked() ? minmax_bits : maximize_bits );
break;
case OnAllDesktopsButton:
setBitmap(0);
break;
case ShadeButton:
setBitmap( isChecked() ? shade_on_bits : shade_off_bits );
break;
case AboveButton:
setBitmap( isChecked() ? above_on_bits : above_off_bits );
break;
case BelowButton:
setBitmap( isChecked() ? below_on_bits : below_off_bits );
break;
default:
setBitmap(0);
break;
}
this->update();
}
}
void KDE2Button::setBitmap(const unsigned char *bitmap)
{
delete deco;
deco = 0;
if (bitmap) {
deco = new QBitmap( QBitmap::fromData(QSize( 10, 10 ), bitmap) );
deco->setMask( *deco );
}
}
void KDE2Button::paintEvent(QPaintEvent *)
{
QPainter p(this);
drawButton(&p);
}
void KDE2Button::drawButton(QPainter *p)
{
if (!KDE2_initialized)
return;
const bool active = decoration()->isActive();
if (deco) {
// Fill the button background with an appropriate button image
QPixmap btnbg;
if (isLeft() ) {
if (isDown())
btnbg = active ?
*leftBtnDownPix[large] : *ileftBtnDownPix[large];
else
btnbg = active ?
*leftBtnUpPix[large] : *ileftBtnUpPix[large];
} else {
if (isDown())
btnbg = active ?
*rightBtnDownPix[large] : *irightBtnDownPix[large];
else
btnbg = active ?
*rightBtnUpPix[large] : *irightBtnUpPix[large];
}
p->drawPixmap( 0, 0, btnbg );
} else if ( isLeft() ) {
// Fill the button background with an appropriate color/gradient
// This is for sticky and menu buttons
QPixmap* grad = active ? aUpperGradient : iUpperGradient;
if (!grad) {
QColor c = KDecoration::options()->color(KDecoration::ColorTitleBar, active);
p->fillRect(0, 0, width(), height(), c );
} else
p->drawPixmap( 0, 0, *grad, 0,1, width(), height() );
} else {
// Draw a plain background for menus or sticky buttons on RHS
QColor c = KDecoration::options()->color(KDecoration::ColorFrame, active);
p->fillRect(0, 0, width(), height(), c);
}
// If we have a decoration bitmap, then draw that
// otherwise we paint a menu button (with mini icon), or a sticky button.
if( deco ) {
// Select the appropriate button decoration color
bool darkDeco = qGray( KDecoration::options()->color(
isLeft() ? KDecoration::ColorTitleBar : KDecoration::ColorButtonBg,
active).rgb() ) > 127;
if (isMouseOver)
p->setPen( darkDeco ? Qt::darkGray : Qt::lightGray );
else
p->setPen( darkDeco ? Qt::black : Qt::white );
int xOff = (width()-10)/2;
int yOff = (height()-10)/2;
p->drawPixmap(isDown() ? xOff+1: xOff, isDown() ? yOff+1 : yOff, *deco);
} else {
QPixmap btnpix;
if (type()==OnAllDesktopsButton) {
if (active)
btnpix = isChecked() ? *pinDownPix : *pinUpPix;
else
btnpix = isChecked() ? *ipinDownPix : *ipinUpPix;
} else
btnpix = decoration()->icon().pixmap( style()->pixelMetric( QStyle::PM_SmallIconSize ), QIcon::Normal );
// Intensify the image if required
if (isMouseOver) {
// XXX Find a suitable substitute for this.
// btnpix = KPixmapEffect::intensity(btnpix, 0.8);
}
// Smooth scale the pixmap for small titlebars
// This is slow, but we assume this isn't done too often
if ( width() < 16 ) {
btnpix = btnpix.scaled(12, 12);
p->drawPixmap( 0, 0, btnpix );
}
else
p->drawPixmap( width()/2-8, height()/2-8, btnpix );
}
}
void KDE2Button::enterEvent(QEvent *e)
{
isMouseOver=true;
repaint();
KCommonDecorationButton::enterEvent(e);
}
void KDE2Button::leaveEvent(QEvent *e)
{
isMouseOver=false;
repaint();
KCommonDecorationButton::leaveEvent(e);
}
// ===========================================================================
KDE2Client::KDE2Client( KDecorationBridge* b, KDecorationFactory* f )
: KCommonDecoration( b, f )/*,
m_closing(false)*/
{
}
QString KDE2Client::visibleName() const
{
return i18n("KDE 2");
}
QString KDE2Client::defaultButtonsLeft() const
{
return "MS";
}
QString KDE2Client::defaultButtonsRight() const
{
return "HIAX";
}
bool KDE2Client::decorationBehaviour(DecorationBehaviour behaviour) const
{
switch (behaviour) {
case DB_MenuClose:
return true;
case DB_WindowMask:
return true;
case DB_ButtonHide:
return true;
default:
return KCommonDecoration::decorationBehaviour(behaviour);
}
}
int KDE2Client::layoutMetric(LayoutMetric lm, bool respectWindowState, const KCommonDecorationButton *btn) const
{
switch (lm) {
case LM_BorderLeft:
case LM_BorderRight:
return borderWidth;
case LM_BorderBottom:
return mustDrawHandle() ? grabBorderWidth : borderWidth;
case LM_TitleEdgeLeft:
case LM_TitleEdgeRight:
return borderWidth;
case LM_TitleEdgeTop:
return 3;
case LM_TitleEdgeBottom:
return 1;
case LM_TitleBorderLeft:
case LM_TitleBorderRight:
return 1;
case LM_TitleHeight:
return titleHeight;
case LM_ButtonWidth:
case LM_ButtonHeight:
return titleHeight;
case LM_ButtonSpacing:
return 0;
case LM_ExplicitButtonSpacer:
if ( !isToolWindow() )
return borderWidth/2;
// fall through
default:
return KCommonDecoration::layoutMetric(lm, respectWindowState, btn);
}
}
KCommonDecorationButton *KDE2Client::createButton(ButtonType type)
{
switch (type) {
case MenuButton:
return new KDE2Button(MenuButton, this, "menu");
case OnAllDesktopsButton:
return new KDE2Button(OnAllDesktopsButton, this, "on_all_desktops");
case HelpButton:
return new KDE2Button(HelpButton, this, "help");
case MinButton:
return new KDE2Button(MinButton, this, "minimize");
case MaxButton:
return new KDE2Button(MaxButton, this, "maximize");
case CloseButton:
return new KDE2Button(CloseButton, this, "close");
case AboveButton:
return new KDE2Button(AboveButton, this, "above");
case BelowButton:
return new KDE2Button(BelowButton, this, "below");
case ShadeButton:
return new KDE2Button(ShadeButton, this, "shade");
default:
return 0;
}
}
void KDE2Client::init()
{
// Finally, toolWindows look small
if ( isToolWindow() ) {
titleHeight = toolTitleHeight;
}
else {
titleHeight = normalTitleHeight;
}
KCommonDecoration::init();
}
void KDE2Client::reset( unsigned long changed)
{
widget()->repaint();
KCommonDecoration::reset(changed);
}
bool KDE2Client::mustDrawHandle() const
{
bool drawSmallBorders = !options()->moveResizeMaximizedWindows();
if (drawSmallBorders && (maximizeMode() & MaximizeVertical)) {
return false;
} else {
return showGrabBar && isResizable();
}
}
void KDE2Client::paintEvent( QPaintEvent* )
{
if (!KDE2_initialized)
return;
QPalette g;
int offset;
QPixmap* upperGradient = isActive() ? aUpperGradient : iUpperGradient;
QPainter p(widget());
// Obtain widget bounds.
QRect r(widget()->rect());
int x = r.x();
int y = r.y();
int x2 = r.width() - 1;
int y2 = r.height() - 1;
int w = r.width();
int h = r.height();
// Determine where to place the extended left titlebar
int leftFrameStart = (h > 42) ? y+titleHeight+26: y+titleHeight;
// Determine where to make the titlebar color transition
r = titleRect();
int rightOffset = r.x()+r.width()+1;
// Create a disposable pixmap buffer for the titlebar
// very early before drawing begins so there is no lag
// during painting pixels.
*titleBuffer = QPixmap( rightOffset-3, titleHeight+1 );
// Draw an outer black frame
p.setPen(Qt::black);
p.drawRect(x,y,w-1,h-1);
// Draw part of the frame that is the titlebar color
g = options()->palette(ColorTitleBar, isActive());
p.setPen(g.color( QPalette::Light ));
p.drawLine(x+1, y+1, rightOffset-1, y+1);
p.drawLine(x+1, y+1, x+1, leftFrameStart+borderWidth-4);
// Draw titlebar colour separator line
p.setPen(g.color( QPalette::Dark ));
p.drawLine(rightOffset-1, y+1, rightOffset-1, titleHeight+2);
p.fillRect(x+2, y+titleHeight+3,
borderWidth-4, leftFrameStart+borderWidth-y-titleHeight-8,
options()->color(ColorTitleBar, isActive() ));
// Finish drawing the titlebar extension
p.setPen(Qt::black);
p.drawLine(x+1, leftFrameStart+borderWidth-4, x+borderWidth-2, leftFrameStart-1);
p.setPen(g.color( QPalette::Mid ));
p.drawLine(x+borderWidth-2, y+titleHeight+3, x+borderWidth-2, leftFrameStart-2);
// Fill out the border edges
g = options()->palette(ColorFrame, isActive());
p.setPen(g.color( QPalette::Light ));
p.drawLine(rightOffset, y+1, x2-1, y+1);
p.drawLine(x+1, leftFrameStart+borderWidth-3, x+1, y2-1);
p.setPen(g.color( QPalette::Dark ));
p.drawLine(x2-1, y+1, x2-1, y2-1);
p.drawLine(x+1, y2-1, x2-1, y2-1);
p.setPen(options()->color(ColorFrame, isActive()));
QPolygon a;
QBrush brush( options()->color(ColorFrame, isActive()), Qt::SolidPattern );
p.setBrush( brush ); // use solid, yellow brush
a.setPoints( 4, x+2, leftFrameStart+borderWidth-4,
x+borderWidth-2, leftFrameStart,
x+borderWidth-2, y2-2,
x+2, y2-2);
p.drawPolygon( a );
p.fillRect(x2-borderWidth+2, y+titleHeight+3,
borderWidth-3, y2-y-titleHeight-4,
options()->color(ColorFrame, isActive() ));
// Draw the bottom handle if required
if (mustDrawHandle())
{
if(w > 50)
{
qDrawShadePanel(&p, x+1, y2-grabBorderWidth+3, 2*borderWidth+12, grabBorderWidth-3,
g, false, 1, &g.brush(QPalette::Mid));
qDrawShadePanel(&p, x+2*borderWidth+13, y2-grabBorderWidth+3, w-4*borderWidth-26, grabBorderWidth-3,
g, false, 1, isActive() ?
&g.brush(QPalette::Background) :
&g.brush(QPalette::Mid));
qDrawShadePanel(&p, x2-2*borderWidth-12, y2-grabBorderWidth+3, 2*borderWidth+12, grabBorderWidth-3,
g, false, 1, &g.brush(QPalette::Mid));
} else
qDrawShadePanel(&p, x+1, y2-grabBorderWidth+3, w-2, grabBorderWidth-3,
g, false, 1, isActive() ?
&g.brush(QPalette::Background) :
&g.brush(QPalette::Mid));
offset = grabBorderWidth;
} else
{
p.fillRect(x+2, y2-borderWidth+2, w-4, borderWidth-3,
options()->color(ColorFrame, isActive() ));
offset = borderWidth;
}
// Draw a frame around the wrapped widget.
p.setPen( g.color( QPalette::Dark ) );
p.drawRect( x+borderWidth-1, y+titleHeight+3, w-2*borderWidth+1, h-titleHeight-offset-2 );
// Draw the title bar.
r = titleRect();
// Obtain titlebar blend colours
QColor c1 = options()->color(ColorTitleBar, isActive() );
QColor c2 = options()->color(ColorFrame, isActive() );
// Fill with frame color behind RHS buttons
p.fillRect( rightOffset, y+2, x2-rightOffset-1, titleHeight+1, c2);
QPainter p2( titleBuffer );
p2.initFrom( widget());
// Draw the titlebar gradient
if (upperGradient)
p2.drawTiledPixmap(0, 0, rightOffset-3, titleHeight+1, *upperGradient);
else
p2.fillRect(0, 0, rightOffset-3, titleHeight+1, c1);
// Draw the title text on the pixmap, and with a smaller font
// for toolwindows than the default.
QFont fnt = options()->font(true);
if ( isToolWindow() )
fnt.setPointSize( fnt.pointSize()-2 ); // Shrink font by 2pt
p2.setFont( fnt );
// Draw the titlebar stipple if active and available
if (isActive() && titlePix)
{
QFontMetrics fm(fnt);
int captionWidth = fm.width(caption());
if (caption().isRightToLeft())
p2.drawTiledPixmap( r.x(), 0, r.width()-captionWidth-4,
titleHeight+1, *titlePix );
else
p2.drawTiledPixmap( r.x()+captionWidth+3, 0, r.width()-captionWidth-4,
titleHeight+1, *titlePix );
}
p2.setPen( options()->color(ColorFont, isActive()) );
p2.drawText(r.x(), 1, r.width()-1, r.height(),
(caption().isRightToLeft() ? Qt::AlignRight : Qt::AlignLeft) | Qt::AlignVCenter,
caption() );
p2.end();
p.drawPixmap( 2, 2, *titleBuffer );
// Ensure a shaded window has no unpainted areas
// Is this still needed?
#if 1
p.setPen(c2);
p.drawLine(x+borderWidth, y+titleHeight+4, x2-borderWidth, y+titleHeight+4);
#endif
}
QRegion KDE2Client::cornerShape(WindowCorner corner)
{
switch (corner) {
case WC_TopLeft:
return QRect(0, 0, 1, 1);
case WC_TopRight:
return QRect(width()-1, 0, 1, 1);
case WC_BottomLeft:
return QRect(0, height()-1, 1, 1);
case WC_BottomRight:
return QRect(width()-1, height()-1, 1, 1);
default:
return QRegion();
}
}
} // namespace
// Extended KWin plugin interface
extern "C" KDE_EXPORT KDecorationFactory* create_factory()
{
return new KDE2::KDE2Handler();
}
// vim: ts=4 sw=4
// kate: space-indent off; tab-width 4;