278c511d4f
his part of the patch, works fine but there's just the re-check needed to be added so when the effect for tooltips changes, the deco's tooltips take this as well. There are no new strings except the Un-Sticky tooltip, all others are translated. thd@kde.org agreed on the strings. svn path=/trunk/kdebase/kwin/; revision=104585
840 lines
22 KiB
C++
840 lines
22 KiB
C++
/*
|
|
* $Id$
|
|
*
|
|
* Gallium-Quartz KWin client
|
|
*
|
|
* Copyright 2001
|
|
* Karol Szwed <karlmail@usa.net>
|
|
* http://gallium.n3.net/
|
|
*
|
|
* Based upon the Win2K kwin client, which is based on the
|
|
* KDE default client.
|
|
*
|
|
* Includes mini titlebars for ToolWindow Support.
|
|
* Button positions are now customizable.
|
|
*
|
|
*/
|
|
|
|
#include <kconfig.h>
|
|
#include <kglobal.h>
|
|
#include <kpixmapeffect.h>
|
|
#include <kdrawutil.h>
|
|
#include <klocale.h>
|
|
#include <qlayout.h>
|
|
#include <qdrawutil.h>
|
|
#include <qbitmap.h>
|
|
#include "../../workspace.h"
|
|
#include "../../options.h"
|
|
#include "quartz.h"
|
|
|
|
using namespace KWinInternal;
|
|
|
|
|
|
static unsigned char iconify_bits[] = {
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00,
|
|
0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
|
|
|
static unsigned char close_bits[] = {
|
|
0x00, 0x00, 0x86, 0x01, 0xcc, 0x00, 0x78, 0x00, 0x30, 0x00, 0x78, 0x00,
|
|
0xcc, 0x00, 0x86, 0x01, 0x00, 0x00, 0x00, 0x00};
|
|
|
|
static unsigned char maximize_bits[] = {
|
|
0xff, 0x01, 0xff, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
|
0x01, 0x01, 0x01, 0x01, 0xff, 0x01, 0x00, 0x00};
|
|
|
|
static unsigned char minmax_bits[] = {
|
|
0xfc, 0x00, 0xfc, 0x00, 0x84, 0x00, 0xbf, 0x00, 0xbf, 0x00, 0xe1, 0x00,
|
|
0x21, 0x00, 0x21, 0x00, 0x3f, 0x00, 0x00, 0x00};
|
|
|
|
static unsigned char question_bits[] = {
|
|
0x00, 0x00, 0x3c, 0x00, 0x66, 0x00, 0x60, 0x00, 0x30, 0x00, 0x18, 0x00,
|
|
0x00, 0x00, 0x18, 0x00, 0x18, 0x00, 0x00, 0x00};
|
|
|
|
static 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 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 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 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 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 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};
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
// Titlebar button positions
|
|
bool stickyButtonOnLeft = true;
|
|
bool coloredFrame = true;
|
|
|
|
KPixmap* titleBlocks = NULL;
|
|
KPixmap* ititleBlocks = NULL;
|
|
KPixmap* pinDownPix = NULL;
|
|
KPixmap* pinUpPix = NULL;
|
|
KPixmap* ipinDownPix = NULL;
|
|
KPixmap* ipinUpPix = NULL;
|
|
|
|
bool quartz_initialized = false;
|
|
QuartzHandler* clientHandler;
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
QuartzHandler::QuartzHandler()
|
|
{
|
|
quartz_initialized = false;
|
|
readConfig();
|
|
createPixmaps();
|
|
quartz_initialized = true;
|
|
connect( options, SIGNAL(resetClients()), this, SLOT(slotReset()) );
|
|
}
|
|
|
|
|
|
QuartzHandler::~QuartzHandler()
|
|
{
|
|
quartz_initialized = false;
|
|
freePixmaps();
|
|
}
|
|
|
|
|
|
void QuartzHandler::slotReset()
|
|
{
|
|
quartz_initialized = false;
|
|
freePixmaps();
|
|
readConfig();
|
|
createPixmaps();
|
|
quartz_initialized = true;
|
|
|
|
// Make kwin create new clients for each window
|
|
Workspace::self()->slotResetAllClientsDelayed();
|
|
}
|
|
|
|
|
|
void QuartzHandler::readConfig()
|
|
{
|
|
KConfig conf("kwinquartzrc");
|
|
conf.setGroup("General");
|
|
coloredFrame = conf.readBoolEntry( "UseTitleBarBorderColors", true );
|
|
|
|
// A small hack to make the sticky button look nicer
|
|
stickyButtonOnLeft = (bool)options->titleButtonsLeft().contains( 'S' );
|
|
}
|
|
|
|
|
|
// This does the colour transition magic. (You say "Oh, is that it?")
|
|
// This may be made configurable at a later stage
|
|
void QuartzHandler::drawBlocks( KPixmap *pi, KPixmap &p, const QColor &c1, const QColor &c2 )
|
|
{
|
|
QPainter px;
|
|
|
|
px.begin( pi );
|
|
|
|
// Draw a background gradient first
|
|
KPixmapEffect::gradient(p, c1, c2, KPixmapEffect::HorizontalGradient);
|
|
|
|
px.fillRect( 2, 1, 3, 3, c1.light(120) );
|
|
px.fillRect( 2, 5, 3, 3, c1 );
|
|
px.fillRect( 2, 9, 3, 3, c1.light(110) );
|
|
px.fillRect( 2, 13, 3, 3, c1 );
|
|
|
|
px.fillRect( 6, 1, 3, 3, c1.light(110) );
|
|
px.fillRect( 6, 5, 3, 3, c2.light(110) );
|
|
px.fillRect( 6, 9, 3, 3, c1.light(120) );
|
|
px.fillRect( 6, 13, 3, 3, c2.light(130) );
|
|
|
|
px.fillRect( 10, 5, 3, 3, c1.light(110) );
|
|
px.fillRect( 10, 9, 3, 3, c2.light(120) );
|
|
px.fillRect( 10, 13, 3, 3, c2.light(150) );
|
|
|
|
px.fillRect( 14, 1, 3, 3, c1.dark(110) );
|
|
px.fillRect( 14, 9, 3, 3, c2.light(120) );
|
|
px.fillRect( 14, 13, 3, 3, c1.dark(120) );
|
|
|
|
px.fillRect( 18, 5, 3, 3, c1.light(110) );
|
|
px.fillRect( 18, 13, 3, 3, c1.dark(110) );
|
|
|
|
px.fillRect( 22, 9, 3, 3, c2.light(120));
|
|
px.fillRect( 22, 13, 3, 3, c2.light(110) );
|
|
}
|
|
|
|
|
|
// This paints the button pixmaps upon loading the style.
|
|
void QuartzHandler::createPixmaps()
|
|
{
|
|
// Obtain titlebar blend colours, and create the block stuff on pixmaps.
|
|
QColorGroup g2 = options->colorGroup(Options::TitleBlend, true);
|
|
QColor c2 = g2.background();
|
|
g2 = options->colorGroup(Options::TitleBar, true );
|
|
QColor c = g2.background().light(130);
|
|
|
|
titleBlocks = new KPixmap();
|
|
titleBlocks->resize( 25, 18 );
|
|
drawBlocks( titleBlocks, *titleBlocks, c, c2 );
|
|
|
|
g2 = options->colorGroup(Options::TitleBlend, false);
|
|
c2 = g2.background();
|
|
g2 = options->colorGroup(Options::TitleBar, false );
|
|
c = g2.background().light(130);
|
|
|
|
ititleBlocks = new KPixmap();
|
|
ititleBlocks->resize( 25, 18 );
|
|
drawBlocks( ititleBlocks, *ititleBlocks, c, c2 );
|
|
|
|
// Set the sticky pin pixmaps;
|
|
QColorGroup g;
|
|
QPainter p;
|
|
|
|
g = options->colorGroup( stickyButtonOnLeft ? Options::TitleBar : Options::TitleBlend, true );
|
|
c = stickyButtonOnLeft ? g.background().light(130) : g.background();
|
|
g2 = options->colorGroup( Options::ButtonBg, true );
|
|
|
|
pinUpPix = new KPixmap();
|
|
pinUpPix->resize(16, 16);
|
|
p.begin( pinUpPix );
|
|
p.fillRect( 0, 0, 16, 16, c);
|
|
kColorBitmaps( &p, g2, 0, 1, 16, 16, true, pinup_white_bits,
|
|
pinup_gray_bits, NULL, NULL, pinup_dgray_bits, NULL );
|
|
p.end();
|
|
|
|
pinDownPix = new KPixmap();
|
|
pinDownPix->resize(16, 16);
|
|
p.begin( pinDownPix );
|
|
p.fillRect( 0, 0, 16, 16, c);
|
|
kColorBitmaps( &p, g2, 0, 1, 16, 16, true, pindown_white_bits,
|
|
pindown_gray_bits, NULL, NULL, pindown_dgray_bits, NULL );
|
|
p.end();
|
|
|
|
|
|
// Inactive pins
|
|
g = options->colorGroup( stickyButtonOnLeft ? Options::TitleBar : Options::TitleBlend, false );
|
|
c = stickyButtonOnLeft ? g.background().light(130) : g.background();
|
|
g2 = options->colorGroup( Options::ButtonBg, false );
|
|
|
|
ipinUpPix = new KPixmap();
|
|
ipinUpPix->resize(16, 16);
|
|
p.begin( ipinUpPix );
|
|
p.fillRect( 0, 0, 16, 16, c);
|
|
kColorBitmaps( &p, g2, 0, 1, 16, 16, true, pinup_white_bits,
|
|
pinup_gray_bits, NULL, NULL, pinup_dgray_bits, NULL );
|
|
p.end();
|
|
|
|
ipinDownPix = new KPixmap();
|
|
ipinDownPix->resize(16, 16);
|
|
p.begin( ipinDownPix );
|
|
p.fillRect( 0, 0, 16, 16, c);
|
|
kColorBitmaps( &p, g2, 0, 1, 16, 16, true, pindown_white_bits,
|
|
pindown_gray_bits, NULL, NULL, pindown_dgray_bits, NULL );
|
|
p.end();
|
|
}
|
|
|
|
|
|
void QuartzHandler::freePixmaps()
|
|
{
|
|
// Title images
|
|
if (titleBlocks)
|
|
delete titleBlocks;
|
|
if (ititleBlocks)
|
|
delete ititleBlocks;
|
|
|
|
// Sticky pin images
|
|
if (pinUpPix)
|
|
delete pinUpPix;
|
|
if (ipinUpPix)
|
|
delete ipinUpPix;
|
|
if (pinDownPix)
|
|
delete pinDownPix;
|
|
if (ipinDownPix)
|
|
delete ipinDownPix;
|
|
}
|
|
|
|
|
|
QuartzButton::QuartzButton(Client *parent, const char *name, bool largeButton,
|
|
bool isLeftButton, bool isStickyButton, const unsigned char *bitmap,
|
|
const QString& tip)
|
|
: KWinButton(parent, name, tip)
|
|
{
|
|
// Eliminate any possible background flicker
|
|
setBackgroundMode( QWidget::NoBackground );
|
|
setToggleButton( isStickyButton );
|
|
|
|
deco = NULL;
|
|
large = largeButton;
|
|
isLeft = isLeftButton;
|
|
isSticky = isStickyButton;
|
|
client = parent;
|
|
|
|
if ( large )
|
|
setFixedSize(16, 16);
|
|
else
|
|
setFixedSize(10, 10);
|
|
|
|
if(bitmap)
|
|
setBitmap(bitmap);
|
|
}
|
|
|
|
|
|
QuartzButton::~QuartzButton()
|
|
{
|
|
if (deco)
|
|
delete deco;
|
|
}
|
|
|
|
|
|
QSize QuartzButton::sizeHint() const
|
|
{
|
|
if ( large )
|
|
return( QSize(16,16) );
|
|
else
|
|
return( QSize(10,10) );
|
|
}
|
|
|
|
|
|
void QuartzButton::setBitmap(const unsigned char *bitmap)
|
|
{
|
|
if (deco)
|
|
delete deco;
|
|
|
|
deco = new QBitmap(10, 10, bitmap, true);
|
|
deco->setMask( *deco );
|
|
repaint( false );
|
|
}
|
|
|
|
|
|
void QuartzButton::drawButton(QPainter *p)
|
|
{
|
|
// Never paint if the pixmaps have not been created
|
|
if (!quartz_initialized)
|
|
return;
|
|
|
|
QColor c;
|
|
|
|
if (isLeft)
|
|
c = options->color(Options::TitleBar, client->isActive()).light(130);
|
|
else
|
|
c = options->color(Options::TitleBlend, client->isActive());
|
|
|
|
// Fill the button background with an appropriate color
|
|
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 )
|
|
{
|
|
int xOff = (width()-10)/2;
|
|
int yOff = (height()-10)/2;
|
|
p->setPen( Qt::black );
|
|
p->drawPixmap(isDown() ? xOff+2: xOff+1, isDown() ? yOff+2 : yOff+1, *deco);
|
|
p->setPen( options->color(Options::ButtonBg, client->isActive()).light(150) );
|
|
p->drawPixmap(isDown() ? xOff+1: xOff, isDown() ? yOff+1 : yOff, *deco);
|
|
} else
|
|
{
|
|
QPixmap btnpix;
|
|
int Offset = 0;
|
|
|
|
if (isSticky)
|
|
{
|
|
if (isDown())
|
|
Offset = 1;
|
|
|
|
// Select the right sticky button to paint
|
|
if (client->isActive())
|
|
btnpix = isOn() ? *pinDownPix : *pinUpPix;
|
|
else
|
|
btnpix = isOn() ? *ipinDownPix : *ipinUpPix;
|
|
|
|
} else
|
|
btnpix = client->miniIcon();
|
|
|
|
// Shrink the miniIcon for tiny titlebars.
|
|
if ( !large )
|
|
{
|
|
QPixmap tmpPix;
|
|
|
|
// Smooth scale the image
|
|
tmpPix.convertFromImage( btnpix.convertToImage().smoothScale(10, 10));
|
|
p->drawPixmap( 0, 0, tmpPix );
|
|
} else
|
|
p->drawPixmap( Offset, Offset, btnpix );
|
|
}
|
|
}
|
|
|
|
|
|
// Make the protected member public
|
|
void QuartzButton::turnOn( bool isOn )
|
|
{
|
|
if ( isToggleButton() )
|
|
setOn( isOn );
|
|
}
|
|
|
|
|
|
void QuartzButton::mousePressEvent( QMouseEvent* e )
|
|
{
|
|
last_button = e->button();
|
|
QMouseEvent me( e->type(), e->pos(), e->globalPos(),
|
|
LeftButton, e->state() );
|
|
KWinButton::mousePressEvent( &me );
|
|
}
|
|
|
|
|
|
void QuartzButton::mouseReleaseEvent( QMouseEvent* e )
|
|
{
|
|
last_button = e->button();
|
|
QMouseEvent me( e->type(), e->pos(), e->globalPos(),
|
|
LeftButton, e->state() );
|
|
KWinButton::mouseReleaseEvent( &me );
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
QuartzClient::QuartzClient( Workspace *ws, WId w, QWidget *parent,
|
|
const char *name )
|
|
: Client( ws, w, parent, name, WResizeNoErase | WNorthWestGravity | WRepaintNoErase )
|
|
{
|
|
// No flicker thanks
|
|
setBackgroundMode( QWidget::NoBackground );
|
|
|
|
// Set button pointers to NULL so we can track things
|
|
for(int i=0; i < QuartzClient::BtnCount; i++)
|
|
button[i] = NULL;
|
|
|
|
// Finally, toolWindows look small
|
|
if ( isTool() ) {
|
|
titleHeight = 12;
|
|
largeButtons = false;
|
|
}
|
|
else {
|
|
titleHeight = 18;
|
|
largeButtons = true;
|
|
}
|
|
|
|
// Pack the windowWrapper() window within a grid
|
|
QGridLayout* g = new QGridLayout(this, 0, 0, 0);
|
|
g->setResizeMode(QLayout::FreeResize);
|
|
g->addRowSpacing(0, 3); // Top grab bar
|
|
g->addWidget(windowWrapper(), 3, 1);
|
|
// without the next line, unshade flickers
|
|
g->addItem( new QSpacerItem( 0, 0, QSizePolicy::Fixed,
|
|
QSizePolicy::Expanding ) );
|
|
g->setRowStretch(3, 10); // Wrapped window
|
|
g->addRowSpacing(2, 1); // line under titlebar
|
|
g->addRowSpacing(4, 4); // bottom handles
|
|
g->addColSpacing(0, 4);
|
|
g->addColSpacing(2, 4);
|
|
|
|
// Pack the titlebar HBox with items
|
|
hb = new QHBoxLayout();
|
|
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 );
|
|
|
|
hb->addSpacing(2);
|
|
}
|
|
|
|
|
|
void QuartzClient::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 QuartzButton(this, "menu",
|
|
largeButtons, isLeft, false, NULL, i18n("Menu"));
|
|
connect( button[BtnMenu], SIGNAL(pressed()),
|
|
this, SLOT(menuButtonPressed()) );
|
|
hb->addWidget( button[BtnMenu] );
|
|
}
|
|
break;
|
|
|
|
// Sticky button
|
|
case 'S':
|
|
if (!button[BtnSticky])
|
|
{
|
|
button[BtnSticky] = new QuartzButton(this, "sticky",
|
|
largeButtons, isLeft, true, NULL, i18n("Sticky"));
|
|
button[BtnSticky]->turnOn( isSticky() );
|
|
connect( button[BtnSticky], SIGNAL(clicked()),
|
|
this, SLOT(toggleSticky()) );
|
|
hb->addSpacing(1);
|
|
hb->addWidget( button[BtnSticky] );
|
|
hb->addSpacing(1);
|
|
}
|
|
break;
|
|
|
|
// Help button
|
|
case 'H':
|
|
if( providesContextHelp() && (!button[BtnHelp]) )
|
|
{
|
|
button[BtnHelp] = new QuartzButton(this, "help",
|
|
largeButtons, isLeft, true, question_bits, i18n("Help"));
|
|
connect( button[BtnHelp], SIGNAL( clicked() ),
|
|
this, SLOT(contextHelp()));
|
|
hb->addWidget( button[BtnHelp] );
|
|
}
|
|
break;
|
|
|
|
// Minimize button
|
|
case 'I':
|
|
if ( (!button[BtnIconify]) && isMinimizable())
|
|
{
|
|
button[BtnIconify] = new QuartzButton(this, "iconify",
|
|
largeButtons, isLeft, true, iconify_bits, i18n("Minimize"));
|
|
connect( button[BtnIconify], SIGNAL( clicked()),
|
|
this, SLOT(iconify()) );
|
|
hb->addWidget( button[BtnIconify] );
|
|
}
|
|
break;
|
|
|
|
// Maximize button
|
|
case 'A':
|
|
if ( (!button[BtnMax]) && isMaximizable())
|
|
{
|
|
button[BtnMax] = new QuartzButton(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])
|
|
{
|
|
button[BtnClose] = new QuartzButton(this, "close",
|
|
largeButtons, isLeft, true, close_bits, i18n("Close"));
|
|
connect( button[BtnClose], SIGNAL( clicked()),
|
|
this, SLOT(closeWindow()) );
|
|
hb->addWidget( button[BtnClose] );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void QuartzClient::iconChange()
|
|
{
|
|
if (button[BtnMenu] && button[BtnMenu]->isVisible())
|
|
button[BtnMenu]->repaint(false);
|
|
}
|
|
|
|
|
|
void QuartzClient::stickyChange(bool on)
|
|
{
|
|
if (button[BtnSticky])
|
|
{
|
|
button[BtnSticky]->turnOn(on);
|
|
button[BtnSticky]->repaint(false);
|
|
button[BtnSticky]->setTipText(on ? i18n("Un-Sticky") : i18n("Sticky"));
|
|
}
|
|
}
|
|
|
|
|
|
void QuartzClient::slotMaximize()
|
|
{
|
|
if ( button[BtnMax]->last_button == MidButton )
|
|
maximize( MaximizeVertical );
|
|
else if ( button[BtnMax]->last_button == RightButton )
|
|
maximize( MaximizeHorizontal );
|
|
else
|
|
maximize();
|
|
}
|
|
|
|
|
|
void QuartzClient::resizeEvent( QResizeEvent* e)
|
|
{
|
|
Client::resizeEvent( e );
|
|
|
|
calcHiddenButtons();
|
|
|
|
if (isVisibleToTLW())
|
|
{
|
|
update(rect());
|
|
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 )
|
|
update( 0, height() - dy + 1, width(), dy );
|
|
|
|
if ( dx )
|
|
{
|
|
update( width() - dx + 1, 0, dx, height() );
|
|
update( QRect( QPoint(4,4), titlebar->geometry().bottomLeft() - QPoint(1,0) ) );
|
|
update( QRect( titlebar->geometry().topRight(), QPoint( width() - 4, titlebar->geometry().bottom() ) ) );
|
|
// Titlebar needs no paint event
|
|
QApplication::postEvent( this, new QPaintEvent( titlebar->geometry(), FALSE ) );
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void QuartzClient::captionChange( const QString& )
|
|
{
|
|
repaint( titlebar->geometry(), false );
|
|
}
|
|
|
|
|
|
// Quartz Paint magic goes here.
|
|
void QuartzClient::paintEvent( QPaintEvent* )
|
|
{
|
|
// Never paint if the pixmaps have not been created
|
|
if (!quartz_initialized)
|
|
return;
|
|
|
|
QColorGroup g;
|
|
QPainter p(this);
|
|
|
|
// Obtain widget bounds.
|
|
QRect r(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();
|
|
|
|
// Draw part of the frame that is the title color
|
|
|
|
if( coloredFrame )
|
|
g = options->colorGroup(Options::TitleBar, isActive());
|
|
else
|
|
g = options->colorGroup(Options::Frame, isActive());
|
|
|
|
// Draw outer highlights and lowlights
|
|
p.setPen( g.light().light(120) );
|
|
p.drawLine( x, y, x2-1, y );
|
|
p.drawLine( x, y+1, x, y2-1 );
|
|
p.setPen( g.dark().light(120) );
|
|
p.drawLine( x2, y, x2, y2 );
|
|
p.drawLine( x, y2, x2, y2 );
|
|
|
|
// Fill out the border edges
|
|
if ( coloredFrame)
|
|
p.setPen( g.background().light(130) );
|
|
else
|
|
p.setPen( g.background() );
|
|
p.drawRect( x+1, y+1, w-2, h-2 );
|
|
p.drawRect( x+2, y+2, w-4, h-4 );
|
|
|
|
// Draw a frame around the wrapped widget.
|
|
p.setPen( g.background() );
|
|
p.drawRect( x+3, y + titleHeight + 3, w-6, h-titleHeight-6 );
|
|
|
|
// Drawing this extra line removes non-drawn areas when shaded
|
|
p.drawLine( x+4, y2-4, x2-4, y2-4);
|
|
|
|
// Highlight top corner
|
|
p.setPen( g.light().light(160) );
|
|
p.drawPoint( x, y );
|
|
p.setPen( g.light().light(140) );
|
|
p.drawPoint( x+1, y );
|
|
p.drawPoint( x, y+1 );
|
|
|
|
// Draw the title bar.
|
|
// ===================
|
|
r = titlebar->geometry();
|
|
|
|
// Obtain titlebar blend colours
|
|
QColor c1 = options->color(Options::TitleBar, isActive() ).light(130);
|
|
QColor c2 = options->color(Options::TitleBlend, isActive() );
|
|
|
|
// Create a disposable pixmap buffer for the titlebar
|
|
KPixmap* titleBuffer = new KPixmap;
|
|
titleBuffer->resize( w-6, titleHeight );
|
|
|
|
QPainter p2( titleBuffer, this );
|
|
|
|
int rightoffset = r.x()+r.width()-25-4; // subtract titleBlocks pixmap width and some
|
|
|
|
p2.fillRect( 0, 0, w, r.height(), c1 );
|
|
p2.fillRect( rightoffset, 0, w-rightoffset-6, r.height(), c2 );
|
|
|
|
// 8 bit displays will be a bit dithered, but they still look ok.
|
|
if ( isActive() )
|
|
p2.drawPixmap( rightoffset, 0, *titleBlocks );
|
|
else
|
|
p2.drawPixmap( rightoffset, 0, *ititleBlocks );
|
|
|
|
// Draw the title text on the pixmap, and with a smaller font
|
|
// for toolwindows than the default.
|
|
QFont fnt = options->font(true);
|
|
if ( !largeButtons )
|
|
{
|
|
fnt.setPointSize( fnt.pointSize() - 3 ); // Shrink font by 3pt
|
|
fnt.setWeight( QFont::Normal ); // and disable bold
|
|
}
|
|
p2.setFont( fnt );
|
|
|
|
p2.setPen( options->color(Options::Font, isActive() ));
|
|
p2.drawText(r.x(), 0, r.width()-3, r.height(),
|
|
AlignLeft | AlignVCenter, caption() );
|
|
p2.end();
|
|
|
|
p.drawPixmap( 3, 3, *titleBuffer );
|
|
|
|
delete titleBuffer;
|
|
}
|
|
|
|
|
|
void QuartzClient::showEvent(QShowEvent *ev)
|
|
{
|
|
calcHiddenButtons();
|
|
show();
|
|
Client::showEvent(ev);
|
|
}
|
|
|
|
|
|
void QuartzClient::mouseDoubleClickEvent( QMouseEvent * e )
|
|
{
|
|
if (titlebar->geometry().contains( e->pos() ) )
|
|
workspace()->performWindowOperation( this, options->operationTitlebarDblClick() );
|
|
workspace()->requestFocus( this );
|
|
}
|
|
|
|
|
|
void QuartzClient::maximizeChange(bool m)
|
|
{
|
|
if (button[BtnMax]) {
|
|
button[BtnMax]->setBitmap(m ? minmax_bits : maximize_bits);
|
|
button[BtnMax]->setTipText(m ? i18n("Restore") : i18n("Maximize"));
|
|
}
|
|
}
|
|
|
|
|
|
void QuartzClient::activeChange(bool)
|
|
{
|
|
for(int i=QuartzClient::BtnHelp; i < QuartzClient::BtnCount; i++)
|
|
if(button[i])
|
|
button[i]->repaint(false);
|
|
|
|
repaint(false);
|
|
}
|
|
|
|
|
|
// The hiding button while shrinking, show button while expanding magic
|
|
void QuartzClient::calcHiddenButtons()
|
|
{
|
|
//Hide buttons in this order - Sticky, Help, Maximize, Menu, Minimize, Close.
|
|
QuartzButton* btnArray[] = { button[BtnSticky], button[BtnHelp], button[BtnMax],
|
|
button[BtnMenu], button[BtnIconify], button[BtnClose] };
|
|
|
|
int minwidth = largeButtons ? 180 : 140; // Start hiding buttons at this width
|
|
int btn_width = largeButtons ? 16 : 10;
|
|
int current_width = width();
|
|
int count = 0;
|
|
int i;
|
|
|
|
// Find out how many buttons we have 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();
|
|
}
|
|
}
|
|
|
|
|
|
// Make sure the menu button follows double click conventions set in kcontrol
|
|
void QuartzClient::menuButtonPressed()
|
|
{
|
|
static QTime* t = 0;
|
|
static QuartzClient* tc = 0;
|
|
if ( !t )
|
|
t = new QTime;
|
|
|
|
if ( tc != this || t->elapsed() > QApplication::doubleClickInterval() )
|
|
{
|
|
QPoint menupoint ( button[BtnMenu]->rect().bottomLeft().x()-1,
|
|
button[BtnMenu]->rect().bottomLeft().y()+2 );
|
|
workspace()->clientPopup(this)->popup(button[BtnMenu]->mapToGlobal( menupoint ));
|
|
}
|
|
else closeWindow();
|
|
|
|
t->start();
|
|
tc = this;
|
|
}
|
|
|
|
|
|
// Extended KWin plugin interface
|
|
/////////////////////////////////
|
|
extern "C"
|
|
{
|
|
Client *allocate(Workspace *ws, WId w, int)
|
|
{
|
|
return(new QuartzClient(ws, w));
|
|
}
|
|
|
|
void init()
|
|
{
|
|
clientHandler = new QuartzHandler();
|
|
}
|
|
|
|
void reset()
|
|
{
|
|
// QuartzHandler takes care of this for us
|
|
}
|
|
|
|
void deinit()
|
|
{
|
|
delete clientHandler;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
#include "quartz.moc"
|
|
// vim: ts=4
|