kwin/clients/default/kdedefault.cpp
Luciano Montanaro 866fc75200 'static' and 'const' added to local variables and pixmap data.
svn path=/trunk/kdebase/kwin/; revision=253599
2003-09-24 14:35:18 +00:00

1228 lines
33 KiB
C++

/*
* $Id$
*
* 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.
*/
#include "kdedefault.h"
#include <kconfig.h>
#include <kglobal.h>
#include <kpixmapeffect.h>
#include <kimageeffect.h>
#include <kdrawutil.h>
#include <klocale.h>
#include <qlayout.h>
#include <qdrawutil.h>
#include <qbitmap.h>
#include <qimage.h>
#include <qtooltip.h>
#include <qapplication.h>
#include <qlabel.h>
#include <kdebug.h>
namespace Default
{
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 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};
// ===========================================================================
static QPixmap* titlePix;
static KPixmap* titleBuffer;
static KPixmap* aUpperGradient;
static KPixmap* iUpperGradient;
static KPixmap* pinDownPix;
static KPixmap* pinUpPix;
static KPixmap* ipinDownPix;
static KPixmap* ipinUpPix;
static KPixmap* rightBtnUpPix;
static KPixmap* rightBtnDownPix;
static KPixmap* irightBtnUpPix;
static KPixmap* irightBtnDownPix;
static KPixmap* leftBtnUpPix;
static KPixmap* leftBtnDownPix;
static KPixmap* ileftBtnUpPix;
static KPixmap* ileftBtnDownPix;
static KDEDefaultHandler* clientHandler;
static int titleBarSize;
static int toolTitleHeight;
static int normalTitleHeight;
static bool KDEDefault_initialized = false;
static bool useGradients;
static bool showGrabBar;
static bool showTitleBarStipple;
static bool largeToolButtons;
// ===========================================================================
KDEDefaultHandler::KDEDefaultHandler()
{
clientHandler = this;
readConfig( false );
createPixmaps();
KDEDefault_initialized = true;
}
KDEDefaultHandler::~KDEDefaultHandler()
{
KDEDefault_initialized = false;
freePixmaps();
clientHandler = NULL;
}
KDecoration* KDEDefaultHandler::createDecoration( KDecorationBridge* b )
{
return new KDEDefaultClient( b, this );
}
bool KDEDefaultHandler::reset( unsigned long changed )
{
KDEDefault_initialized = false;
changed |= readConfig( true );
if( changed & SettingColors )
{ // pixmaps need to be recreated
freePixmaps();
createPixmaps();
}
KDEDefault_initialized = true;
bool need_recreate = ( changed & ( SettingDecoration | SettingFont | SettingButtons | SettingBorder )) != 0;
if( need_recreate ) // something else than colors changed
return true;
resetDecorations( changed );
return false;
}
unsigned long KDEDefaultHandler::readConfig( bool update )
{
unsigned long changed = 0;
KConfig* conf = KGlobal::config();
conf->setGroup("KDEDefault");
bool new_showGrabBar = conf->readBoolEntry("ShowGrabBar", true);
bool new_showTitleBarStipple = conf->readBoolEntry("ShowTitleBarStipple", true);
bool new_useGradients = conf->readBoolEntry("UseGradients", true);
int new_titleBarSize = conf->readNumEntry("TitleBarSize", 0);
if (new_titleBarSize < 0) new_titleBarSize = 0;
if (new_titleBarSize > 2) new_titleBarSize = 2;
if( update )
{
if( new_showGrabBar != showGrabBar
|| new_titleBarSize != titleBarSize )
changed |= SettingDecoration; // need recreating the decoration
if( new_showTitleBarStipple != showTitleBarStipple
|| new_useGradients != useGradients )
changed |= SettingColors; // just recreate the pixmaps and repaint
}
showGrabBar = new_showGrabBar;
showTitleBarStipple = new_showTitleBarStipple;
useGradients = new_useGradients;
titleBarSize = new_titleBarSize;
normalTitleHeight = 16 + (4*titleBarSize);
toolTitleHeight = normalTitleHeight - 4;
largeToolButtons = (toolTitleHeight >= 16) ? true : false;
return changed;
}
// This paints the button pixmaps upon loading the style.
void KDEDefaultHandler::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 < 6; ++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)
{
// Create the titlebar gradients
if (activeTitleColor1 != activeTitleColor2)
{
aUpperGradient = new KPixmap;
aUpperGradient->resize(128, normalTitleHeight+2);
KPixmapEffect::gradient(*aUpperGradient,
activeTitleColor1,
activeTitleColor2,
KPixmapEffect::VerticalGradient);
}
if (inactiveTitleColor1 != inactiveTitleColor2)
{
iUpperGradient = new KPixmap;
iUpperGradient->resize(128, normalTitleHeight+2);
KPixmapEffect::gradient(*iUpperGradient,
inactiveTitleColor1,
inactiveTitleColor2,
KPixmapEffect::VerticalGradient);
}
}
// Set the sticky pin pixmaps;
QColorGroup g;
QPainter p;
// Active pins
g = options()->colorGroup( ColorButtonBg, true );
pinUpPix = new KPixmap();
pinUpPix->resize(16, 16);
p.begin( pinUpPix );
kColorBitmaps( &p, g, 0, 0, 16, 16, true, pinup_white_bits,
pinup_gray_bits, NULL, NULL, pinup_dgray_bits, NULL );
p.end();
pinUpPix->setMask( QBitmap(16, 16, pinup_mask_bits, true) );
pinDownPix = new KPixmap();
pinDownPix->resize(16, 16);
p.begin( pinDownPix );
kColorBitmaps( &p, g, 0, 0, 16, 16, true, pindown_white_bits,
pindown_gray_bits, NULL, NULL, pindown_dgray_bits, NULL );
p.end();
pinDownPix->setMask( QBitmap(16, 16, pindown_mask_bits, true) );
// Inactive pins
g = options()->colorGroup( ColorButtonBg, false );
ipinUpPix = new KPixmap();
ipinUpPix->resize(16, 16);
p.begin( ipinUpPix );
kColorBitmaps( &p, g, 0, 0, 16, 16, true, pinup_white_bits,
pinup_gray_bits, NULL, NULL, pinup_dgray_bits, NULL );
p.end();
ipinUpPix->setMask( QBitmap(16, 16, pinup_mask_bits, true) );
ipinDownPix = new KPixmap();
ipinDownPix->resize(16, 16);
p.begin( ipinDownPix );
kColorBitmaps( &p, g, 0, 0, 16, 16, true, pindown_white_bits,
pindown_gray_bits, NULL, NULL, pindown_dgray_bits, NULL );
p.end();
ipinDownPix->setMask( QBitmap(16, 16, pindown_mask_bits, true) );
// Create a title buffer for flicker-free painting
titleBuffer = new KPixmap();
// Cache all possible button states
leftBtnUpPix = new KPixmap();
leftBtnUpPix->resize(16, 16);
leftBtnDownPix = new KPixmap();
leftBtnDownPix->resize(16, 16);
ileftBtnUpPix = new KPixmap();
ileftBtnUpPix->resize(16, 16);
ileftBtnDownPix = new KPixmap();
ileftBtnDownPix->resize(16, 16);
rightBtnUpPix = new KPixmap();
rightBtnUpPix->resize(16, 16);
rightBtnDownPix = new KPixmap();
rightBtnDownPix->resize(16, 16);
irightBtnUpPix = new KPixmap();
irightBtnUpPix->resize(16, 16);
irightBtnDownPix = new KPixmap();
irightBtnDownPix->resize(16, 16);
// Draw the button state pixmaps
g = options()->colorGroup( ColorTitleBar, true );
drawButtonBackground( leftBtnUpPix, g, false );
drawButtonBackground( leftBtnDownPix, g, true );
g = options()->colorGroup( ColorButtonBg, true );
drawButtonBackground( rightBtnUpPix, g, false );
drawButtonBackground( rightBtnDownPix, g, true );
g = options()->colorGroup( ColorTitleBar, false );
drawButtonBackground( ileftBtnUpPix, g, false );
drawButtonBackground( ileftBtnDownPix, g, true );
g = options()->colorGroup( ColorButtonBg, false );
drawButtonBackground( irightBtnUpPix, g, false );
drawButtonBackground( irightBtnDownPix, g, true );
}
void KDEDefaultHandler::freePixmaps()
{
// Free button pixmaps
if (rightBtnUpPix)
delete rightBtnUpPix;
if(rightBtnDownPix)
delete rightBtnDownPix;
if (irightBtnUpPix)
delete irightBtnUpPix;
if (irightBtnDownPix)
delete irightBtnDownPix;
if (leftBtnUpPix)
delete leftBtnUpPix;
if(leftBtnDownPix)
delete leftBtnDownPix;
if (ileftBtnUpPix)
delete ileftBtnUpPix;
if (ileftBtnDownPix)
delete ileftBtnDownPix;
// 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 KDEDefaultHandler::drawButtonBackground(KPixmap *pix,
const QColorGroup &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.background();
// Fill the background with a gradient if possible
if (highcolor)
KPixmapEffect::gradient(*pix, c.light(130), c.dark(130),
KPixmapEffect::VerticalGradient);
else
pix->fill(c);
p.begin(pix);
// outer frame
p.setPen(g.mid());
p.drawLine(0, 0, x2, 0);
p.drawLine(0, 0, 0, y2);
p.setPen(g.light());
p.drawLine(x2, 0, x2, y2);
p.drawLine(0, x2, y2, x2);
p.setPen(g.dark());
p.drawRect(1, 1, w-2, h-2);
p.setPen(sunken ? g.mid() : g.light());
p.drawLine(2, 2, x2-2, 2);
p.drawLine(2, 2, 2, y2-2);
p.setPen(sunken ? g.light() : g.mid());
p.drawLine(x2-2, 2, x2-2, y2-2);
p.drawLine(2, x2-2, y2-2, x2-2);
}
// ===========================================================================
KDEDefaultButton::KDEDefaultButton(KDEDefaultClient *parent, const char *name,
bool largeButton, bool isLeftButton, bool isStickyButton,
const unsigned char *bitmap, const QString& tip )
: QButton(parent->widget(), name)
{
QToolTip::add( this, tip );
setCursor( arrowCursor );
setBackgroundMode( QWidget::NoBackground );
setToggleButton( isStickyButton );
isMouseOver = false;
deco = NULL;
large = largeButton;
isLeft = isLeftButton;
isSticky = isStickyButton;
client = parent;
if (large)
setFixedSize(16, 16);
else
setFixedSize(12, 12);
if (bitmap)
setBitmap(bitmap);
}
KDEDefaultButton::~KDEDefaultButton()
{
if (deco)
delete deco;
}
QSize KDEDefaultButton::sizeHint() const
{
if ( large )
return( QSize(16,16) );
else
return( QSize(12,12) );
}
void KDEDefaultButton::setBitmap(const unsigned char *bitmap)
{
if (deco)
delete deco;
deco = new QBitmap(10, 10, bitmap, true);
deco->setMask( *deco );
repaint( false );
}
void KDEDefaultButton::drawButton(QPainter *p)
{
if (!KDEDefault_initialized)
return;
if (deco) {
// Fill the button background with an appropriate button image
KPixmap btnbg;
if (isLeft) {
if (isDown())
btnbg = client->isActive() ?
*leftBtnDownPix : *ileftBtnDownPix;
else
btnbg = client->isActive() ?
*leftBtnUpPix : *ileftBtnUpPix;
} else {
if (isDown())
btnbg = client->isActive() ?
*rightBtnDownPix : *irightBtnDownPix;
else
btnbg = client->isActive() ?
*rightBtnUpPix : *irightBtnUpPix;
}
// Scale the background image if required
// This is slow, but we assume this isn't done too often
if ( !large ) {
btnbg.detach();
btnbg.convertFromImage(btnbg.convertToImage().smoothScale(12, 12));
}
p->drawPixmap( 0, 0, btnbg );
} else if ( isLeft ) {
// Fill the button background with an appropriate color/gradient
// This is for sticky and menu buttons
KPixmap* grad = client->isActive() ? aUpperGradient : iUpperGradient;
if (!grad) {
QColor c = KDecoration::options()->color(ColorTitleBar, client->isActive());
p->fillRect(0, 0, width(), height(), c );
} else
p->drawPixmap( 0, 0, *grad, 0,((normalTitleHeight-height())/2)+1,
16, 16 );
} else {
// Draw a plain background for menus or sticky buttons on RHS
QColor c = KDecoration::options()->color(ColorFrame, client->isActive());
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? ColorTitleBar : ColorButtonBg,
client->isActive()).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 {
KPixmap btnpix;
if (isSticky) {
if (client->isActive())
btnpix = isOn() ? *pinDownPix : *pinUpPix;
else
btnpix = isOn() ? *ipinDownPix : *ipinUpPix;
} else
btnpix = client->icon().pixmap( QIconSet::Small, QIconSet::Normal );
// Intensify the image if required
if (isMouseOver) {
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 ( !large )
btnpix.convertFromImage(btnpix.convertToImage().smoothScale(12, 12));
p->drawPixmap( 0, 0, btnpix );
}
}
// Make the protected member public
void KDEDefaultButton::turnOn( bool isOn )
{
if ( isToggleButton() )
setOn( isOn );
}
void KDEDefaultButton::enterEvent(QEvent *e)
{
isMouseOver=true;
repaint(false);
QButton::enterEvent(e);
}
void KDEDefaultButton::leaveEvent(QEvent *e)
{
isMouseOver=false;
repaint(false);
QButton::leaveEvent(e);
}
void KDEDefaultButton::mousePressEvent( QMouseEvent* e )
{
last_button = e->button();
QMouseEvent me( e->type(), e->pos(), e->globalPos(),
LeftButton, e->state() );
QButton::mousePressEvent( &me );
}
void KDEDefaultButton::mouseReleaseEvent( QMouseEvent* e )
{
last_button = e->button();
QMouseEvent me( e->type(), e->pos(), e->globalPos(),
LeftButton, e->state() );
QButton::mouseReleaseEvent( &me );
}
// ===========================================================================
KDEDefaultClient::KDEDefaultClient( KDecorationBridge* b, KDecorationFactory* f )
: KDecoration( b, f ),
m_closing(false)
{
}
void KDEDefaultClient::init()
{
createMainWidget( WResizeNoErase | WStaticContents | WRepaintNoErase );
widget()->installEventFilter( this );
// No flicker thanks
widget()->setBackgroundMode( QWidget::NoBackground );
// Set button pointers to NULL so we can track things
for(int i=0; i < KDEDefaultClient::BtnCount; i++)
button[i] = NULL;
// Finally, toolWindows look small
if ( isTool() ) {
titleHeight = toolTitleHeight;
largeButtons = largeToolButtons;
}
else {
titleHeight = normalTitleHeight;
largeButtons = true;
}
// Pack the windowWrapper() window within a grid
g = new QGridLayout(widget(), 0, 0, 0);
g->setResizeMode(QLayout::FreeResize);
g->addRowSpacing(0, 3); // Top grab bar
g->addRowSpacing(2, 1); // line under titlebar
if( isPreview())
g->addWidget( new QLabel( i18n( "<b><center>KDE2 preview</center></b>" ), widget()), 3, 1);
else
g->addWidget( new QWidget( widget()), 3, 1);
// without the next line, unshade flickers
g->addItem( new QSpacerItem( 0, 0, QSizePolicy::Fixed,
QSizePolicy::Expanding ) );
g->setRowStretch(3, 10); // Wrapped window
// Determine the size of the lower grab bar
spacer = new QSpacerItem(10,
showGrabBar && isResizable() ? 8 : 4,
QSizePolicy::Expanding, QSizePolicy::Minimum);
g->addItem(spacer, 4, 1);
g->addColSpacing(0, 4);
g->addColSpacing(2, 4);
// Pack the titlebar HBox with items
hb = new QBoxLayout(0, QBoxLayout::LeftToRight, 0, 0, 0 );
hb->setResizeMode( QLayout::FreeResize );
g->addLayout ( hb, 1, 1 );
addClientButtons( options()->titleButtonsLeft() );
titlebar = new QSpacerItem( 10, titleHeight, QSizePolicy::Expanding,
QSizePolicy::Minimum );
hb->addItem(titlebar);
hb->addSpacing(2);
addClientButtons( options()->titleButtonsRight(), false );
}
void KDEDefaultClient::addClientButtons( const QString& s, bool isLeft )
{
if (s.length() > 0)
for(unsigned int i = 0; i < s.length(); i++) {
switch( s[i].latin1() )
{
// Menu button
case 'M':
if (!button[BtnMenu])
{
button[BtnMenu] = new KDEDefaultButton(this, "menu",
largeButtons, isLeft, false, NULL, i18n("Menu"));
connect( button[BtnMenu], SIGNAL(pressed()),
this, SLOT(menuButtonPressed()) );
connect( button[BtnMenu], SIGNAL(released()),
this, SLOT(menuButtonReleased()));
hb->addWidget( button[BtnMenu] );
}
break;
// Sticky button
case 'S':
if (!button[BtnSticky])
{
button[BtnSticky] = new KDEDefaultButton(this, "sticky",
largeButtons, isLeft, true, NULL, i18n("Sticky"));
button[BtnSticky]->turnOn( isOnAllDesktops() );
connect( button[BtnSticky], SIGNAL(clicked()),
this, SLOT(toggleOnAllDesktops()) );
hb->addWidget( button[BtnSticky] );
}
break;
// Help button
case 'H':
if( providesContextHelp() && (!button[BtnHelp]) )
{
button[BtnHelp] = new KDEDefaultButton(this, "help",
largeButtons, isLeft, true, question_bits,
i18n("Help"));
connect( button[BtnHelp], SIGNAL( clicked() ),
this, SLOT( showContextHelp() ));
hb->addWidget( button[BtnHelp] );
}
break;
// Minimize button
case 'I':
if ( (!button[BtnIconify]) && isMinimizable())
{
button[BtnIconify] = new KDEDefaultButton(this, "iconify",
largeButtons, isLeft, true, iconify_bits,
i18n("Minimize"));
connect( button[BtnIconify], SIGNAL( clicked()),
this, SLOT(minimize()) );
hb->addWidget( button[BtnIconify] );
}
break;
// Maximize button
case 'A':
if ( (!button[BtnMax]) && isMaximizable())
{
button[BtnMax] = new KDEDefaultButton(this, "maximize",
largeButtons, isLeft, true, maximize_bits,
i18n("Maximize"));
connect( button[BtnMax], SIGNAL( clicked()),
this, SLOT(slotMaximize()) );
hb->addWidget( button[BtnMax] );
}
break;
// Close button
case 'X':
if (!button[BtnClose] && isCloseable())
{
button[BtnClose] = new KDEDefaultButton(this, "close",
largeButtons, isLeft, true, close_bits,
i18n("Close"));
connect( button[BtnClose], SIGNAL( clicked()),
this, SLOT(closeWindow()) );
hb->addWidget( button[BtnClose] );
}
break;
// Spacer item (only for non-tool windows)
case '_':
if ( !isTool() )
hb->addSpacing(2);
}
}
}
void KDEDefaultClient::reset( unsigned long )
{
widget()->repaint();
}
void KDEDefaultClient::iconChange()
{
if (button[BtnMenu] && button[BtnMenu]->isVisible())
button[BtnMenu]->repaint(false);
}
void KDEDefaultClient::desktopChange()
{
if (button[BtnSticky]) {
bool on = isOnAllDesktops();
button[BtnSticky]->turnOn(on);
button[BtnSticky]->repaint(false);
QToolTip::remove( button[BtnSticky] );
QToolTip::add( button[BtnSticky], on ? i18n("Un-Sticky") : i18n("Sticky"));
}
}
void KDEDefaultClient::slotMaximize()
{
if ( button[BtnMax]->last_button == MidButton )
maximize( maximizeMode() ^ MaximizeVertical );
else if ( button[BtnMax]->last_button == RightButton )
maximize( maximizeMode() ^ MaximizeHorizontal );
else
maximize( maximizeMode() == MaximizeFull ? MaximizeRestore : MaximizeFull );
}
void KDEDefaultClient::resizeEvent( QResizeEvent* e)
{
doShape();
calcHiddenButtons();
if ( widget()->isShown())
{
widget()->update( widget()->rect());
#if 1 // what's the point of this, when paintEvent() repaints everything anyway?
int dx = 0;
int dy = 0;
if ( e->oldSize().width() != width() )
dx = 32 + QABS( e->oldSize().width() - width() );
if ( e->oldSize().height() != height() )
dy = 8 + QABS( e->oldSize().height() - height() );
if ( dy )
widget()->update( 0, height() - dy + 1, width(), dy );
if ( dx )
{
widget()->update( width() - dx + 1, 0, dx, height() );
widget()->update( QRect( QPoint(4,4), titlebar->geometry().bottomLeft() -
QPoint(1,0) ) );
widget()->update( QRect( titlebar->geometry().topRight(), QPoint(width() - 4,
titlebar->geometry().bottom()) ) );
// Titlebar needs no paint event
QApplication::postEvent( widget(), new QPaintEvent(titlebar->geometry(),
FALSE) );
}
#endif
}
}
void KDEDefaultClient::captionChange()
{
widget()->repaint( titlebar->geometry(), false );
}
void KDEDefaultClient::paintEvent( QPaintEvent* )
{
if (!KDEDefault_initialized)
return;
QColorGroup g;
int offset;
KPixmap* 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 = titlebar->geometry();
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->resize( rightOffset-3, titleHeight+1 );
// Draw an outer black frame
p.setPen(Qt::black);
p.drawRect(x,y,w,h);
// Draw part of the frame that is the titlebar color
g = options()->colorGroup(ColorTitleBar, isActive());
p.setPen(g.light());
p.drawLine(x+1, y+1, rightOffset-1, y+1);
p.drawLine(x+1, y+1, x+1, leftFrameStart);
// Draw titlebar colour separator line
p.setPen(g.dark());
p.drawLine(rightOffset-1, y+1, rightOffset-1, titleHeight+2);
// Finish drawing the titlebar extension
p.setPen(Qt::black);
p.drawLine(x+1, leftFrameStart, x+2, leftFrameStart-1);
p.setPen(g.mid());
p.drawLine(x+2, y+titleHeight+3, x+2, leftFrameStart-2);
// Fill out the border edges
g = options()->colorGroup(ColorFrame, isActive());
p.setPen(g.light());
p.drawLine(rightOffset, y+1, x2-1, y+1);
p.drawLine(x+1, leftFrameStart+1, x+1, y2-1);
p.setPen(g.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()));
p.drawLine(x+2, leftFrameStart, x+2, y2-2 );
p.drawLine(x2-2, y+titleHeight+3, x2-2, y2-2);
// Draw the bottom handle if required
if (showGrabBar && isResizable())
{
if(w > 50)
{
qDrawShadePanel(&p, x+1, y2-6, 20, 6,
g, false, 1, &g.brush(QColorGroup::Mid));
qDrawShadePanel(&p, x+21, y2-6, w-42, 6,
g, false, 1, isActive() ?
&g.brush(QColorGroup::Background) :
&g.brush(QColorGroup::Mid));
qDrawShadePanel(&p, x2-20, y2-6, 20, 6,
g, false, 1, &g.brush(QColorGroup::Mid));
} else
qDrawShadePanel(&p, x+1, y2-6, w-2, 6,
g, false, 1, isActive() ?
&g.brush(QColorGroup::Background) :
&g.brush(QColorGroup::Mid));
offset = 4;
} else
{
p.drawLine(x+2, y2-2, x2-2, y2-2);
offset = 0;
}
// Draw a frame around the wrapped widget.
p.setPen( g.dark() );
p.drawRect( x+3, y+titleHeight+3, w-6, h-titleHeight-offset-6 );
// Draw the title bar.
r = titlebar->geometry();
// 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, this );
// 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 ( isTool() )
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() ? AlignRight : AlignLeft) | AlignVCenter,
caption() );
bitBlt( widget(), 2, 2, titleBuffer );
p2.end();
// Ensure a shaded window has no unpainted areas
// Is this still needed?
#if 1
p.setPen(c2);
p.drawLine(x+4, y+titleHeight+4, x2-4, y+titleHeight+4);
#endif
}
void KDEDefaultClient::doShape()
{
QRegion mask(QRect(0, 0, width(), height()));
mask -= QRect(0, 0, 1, 1);
mask -= QRect(width()-1, 0, 1, 1);
mask -= QRect(0, height()-1, 1, 1);
mask -= QRect(width()-1, height()-1, 1, 1);
setMask(mask);
}
void KDEDefaultClient::showEvent(QShowEvent *)
{
calcHiddenButtons();
doShape();
}
void KDEDefaultClient::mouseDoubleClickEvent( QMouseEvent * e )
{
if (titlebar->geometry().contains( e->pos() ) )
titlebarDblClickOperation();
}
void KDEDefaultClient::maximizeChange()
{
if (button[BtnMax]) {
bool m = maximizeMode() == MaximizeFull;
button[BtnMax]->setBitmap(m ? minmax_bits : maximize_bits);
QToolTip::remove( button[ BtnMax ] );
QToolTip::add( button[BtnMax], m ? i18n("Restore") : i18n("Maximize"));
}
spacer->changeSize(10, showGrabBar && isResizable() ? 8 : 4,
QSizePolicy::Expanding, QSizePolicy::Minimum);
g->activate();
}
void KDEDefaultClient::activeChange()
{
for(int i=KDEDefaultClient::BtnHelp; i < KDEDefaultClient::BtnCount; i++)
if(button[i])
button[i]->repaint(false);
widget()->repaint(false);
}
void KDEDefaultClient::shadeChange()
{
}
QSize KDEDefaultClient::minimumSize() const
{
return QSize( 100, 50 ); // FRAME
}
void KDEDefaultClient::resize( const QSize& s )
{
widget()->resize( s );
}
void KDEDefaultClient::borders( int& left, int& right, int& top, int& bottom ) const
{ // FRAME
left = right = 4;
// , y+titleHeight+3, w-6, h-titleHeight-offset-6 );
top = titleHeight + 4;
bottom = isResizable() ? 8 : 4;
}
// The hiding button while shrinking, show button while expanding magic
void KDEDefaultClient::calcHiddenButtons()
{
// Hide buttons in this order:
// Sticky, Help, Maximize, Minimize, Close, Menu.
KDEDefaultButton* btnArray[] = { button[BtnSticky], button[BtnHelp],
button[BtnMax], button[BtnIconify], button[BtnClose],
button[BtnMenu] };
int minwidth = largeButtons ? 160 : 120; // Start hiding at this width
int btn_width = largeButtons ? 16 : 12;
int current_width = width();
int count = 0;
int i;
// Find out how many buttons we need to hide.
while (current_width < minwidth)
{
current_width += btn_width;
count++;
}
// Bound the number of buttons to hide
if (count > 6) count = 6;
// Hide the required buttons...
for(i = 0; i < count; i++)
{
if (btnArray[i] && btnArray[i]->isVisible() )
btnArray[i]->hide();
}
// Show the rest of the buttons...
for(i = count; i < 6; i++)
{
if (btnArray[i] && (!btnArray[i]->isVisible()) )
btnArray[i]->show();
}
}
KDecoration::MousePosition KDEDefaultClient::mousePosition( const QPoint& p ) const
{
MousePosition m = Nowhere;
// Modify the mouse position if we are using a grab bar.
if (showGrabBar && isResizable())
if (p.y() < (height() - 8))
m = KDecoration::mousePosition(p);
else
{
if (p.x() >= (width() - 20))
m = BottomRight2;
else if (p.x() <= 20)
m = BottomLeft2;
else
m = Bottom;
}
else
m = KDecoration::mousePosition(p);
return m;
}
// Make sure the menu button follows double click conventions set in kcontrol
void KDEDefaultClient::menuButtonPressed()
{
static QTime t;
static KDEDefaultClient* lastClient = NULL;
bool dbl = ( lastClient == this && t.elapsed() <= QApplication::doubleClickInterval());
lastClient = this;
t.start();
if (dbl)
{
m_closing = true;
return;
}
QPoint menupoint ( button[BtnMenu]->rect().bottomLeft().x()-1,
button[BtnMenu]->rect().bottomLeft().y()+2 );
showWindowMenu( button[BtnMenu]->mapToGlobal( menupoint ));
button[BtnMenu]->setDown(false);
}
void KDEDefaultClient::menuButtonReleased()
{
if (m_closing)
closeWindow();
}
const int SUPPORTED_WINDOW_TYPES_MASK = NET::NormalMask | NET::DesktopMask | NET::DockMask
| NET::ToolbarMask | NET::MenuMask | NET::DialogMask | NET::OverrideMask | NET::TopMenuMask
| NET::UtilityMask | NET::SplashMask;
bool KDEDefaultClient::isTool() const
{
NET::WindowType type = windowType( SUPPORTED_WINDOW_TYPES_MASK );
return type == NET::Toolbar || type == NET::Utility || type == NET::Menu;
}
bool KDEDefaultClient::eventFilter( QObject* o, QEvent* e )
{
if( o != widget())
return false;
switch( e->type())
{
case QEvent::Resize:
resizeEvent( static_cast< QResizeEvent* >( e ));
return true;
case QEvent::Paint:
paintEvent( static_cast< QPaintEvent* >( e ));
return true;
case QEvent::MouseButtonDblClick:
mouseDoubleClickEvent( static_cast< QMouseEvent* >( e ));
return true;
case QEvent::MouseButtonPress:
processMousePressEvent( static_cast< QMouseEvent* >( e ));
return true;
case QEvent::Show:
showEvent( static_cast< QShowEvent* >( e ));
return true;
default:
break;
}
return false;
}
} // namespace
// Extended KWin plugin interface
extern "C" KDecorationFactory* create_factory()
{
return new Default::KDEDefaultHandler();
}
#include "kdedefault.moc"
// vim: ts=4