c1d76aa70d
svn path=/trunk/KDE/kdebase/workspace/; revision=535697
1831 lines
56 KiB
C++
1831 lines
56 KiB
C++
/*
|
||
*
|
||
* Keramik KWin client (version 0.8)
|
||
*
|
||
* Copyright (C) 2002 Fredrik H<>lund <fredrik@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., 51 Franklin Street, Fifth Floor,
|
||
* Boston, MA 02110-1301, USA.
|
||
*/
|
||
|
||
#include <kconfig.h>
|
||
#include <klocale.h>
|
||
#include <kiconeffect.h>
|
||
|
||
#include <qpainter.h>
|
||
#include <qlayout.h>
|
||
#include <qbitmap.h>
|
||
#include <qstyle.h>
|
||
#include <qtooltip.h>
|
||
#include <qwidget.h>
|
||
#include <qlabel.h>
|
||
#include <QEvent>
|
||
#include <QApplication>
|
||
#include <QStyle>
|
||
|
||
#include <X11/Xlib.h>
|
||
|
||
#include "keramik.h"
|
||
#include "keramik.moc"
|
||
|
||
|
||
|
||
// -------------------------------------------------------------------------------------------
|
||
|
||
static void flip( QPixmap *&pix )
|
||
{
|
||
QPixmap *tmp = new QPixmap( pix->transformed( QWMatrix(-1,0,0,1,pix->width(),0) ) );
|
||
delete pix;
|
||
pix = tmp;
|
||
}
|
||
|
||
static void flip( QBitmap *&pix )
|
||
{
|
||
QBitmap *tmp = new QBitmap( pix->transformed( QWMatrix(-1,0,0,1,pix->width(),0) ) );
|
||
delete pix;
|
||
pix = tmp;
|
||
}
|
||
|
||
namespace Keramik
|
||
{
|
||
|
||
const int buttonMargin = 9; // Margin between the window edge and the buttons
|
||
const int buttonSpacing = 4; // Spacing between the titlebar buttons
|
||
const int iconSpacing = 5; // Spacing between the icon and the text label
|
||
|
||
// Default button layout
|
||
const char default_left[] = "M";
|
||
const char default_right[] = "HIAX";
|
||
|
||
// Titlebar button bitmaps
|
||
const unsigned char menu_bits[] = {
|
||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x0f, 0x00, 0xf0, 0x07, 0x00,
|
||
0xe0, 0x03, 0x00, 0xc0, 0x01, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
0x00, 0x00, 0x00};
|
||
|
||
const unsigned char on_all_desktops_bits[] = {
|
||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
0x80, 0x01, 0x00, 0x80, 0x01, 0x00, 0x80, 0x01, 0x00, 0xf0, 0x0f, 0x00,
|
||
0xf0, 0x0f, 0x00, 0x80, 0x01, 0x00, 0x80, 0x01, 0x00, 0x80, 0x01, 0x00,
|
||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
0x00, 0x00, 0x00};
|
||
|
||
const unsigned char not_on_all_desktops_bits[] = {
|
||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x0f, 0x00,
|
||
0xf0, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
0x00, 0x00, 0x00};
|
||
|
||
const unsigned char help_bits[] = {
|
||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x03, 0x00,
|
||
0xf0, 0x07, 0x00, 0x30, 0x06, 0x00, 0x00, 0x07, 0x00, 0x80, 0x03, 0x00,
|
||
0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x80, 0x01, 0x00,
|
||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
0x00, 0x00, 0x00};
|
||
|
||
const unsigned char minimize_bits[] = {
|
||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x0f, 0x00, 0xf0, 0x0f, 0x00,
|
||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
0x00, 0x00, 0x00};
|
||
|
||
const unsigned char maximize_bits[] = {
|
||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
0x80, 0x01, 0x00, 0xc0, 0x03, 0x00, 0xe0, 0x07, 0x00, 0xf0, 0x0f, 0x00,
|
||
0xf0, 0x0f, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x0f, 0x00, 0xf0, 0x0f, 0x00,
|
||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
0x00, 0x00, 0x00};
|
||
|
||
const unsigned char restore_bits[] = {
|
||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
0xf0, 0x0f, 0x00, 0xf0, 0x0f, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x0f, 0x00,
|
||
0xf0, 0x0f, 0x00, 0xe0, 0x07, 0x00, 0xc0, 0x03, 0x00, 0x80, 0x01, 0x00,
|
||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
0x00, 0x00, 0x00};
|
||
|
||
const unsigned char close_bits[] = {
|
||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
0x30, 0x0c, 0x00, 0x70, 0x0e, 0x00, 0xe0, 0x07, 0x00, 0xc0, 0x03, 0x00,
|
||
0xc0, 0x03, 0x00, 0xe0, 0x07, 0x00, 0x70, 0x0e, 0x00, 0x30, 0x0c, 0x00,
|
||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
0x00, 0x00, 0x00};
|
||
|
||
const unsigned char above_on_bits[] = {
|
||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x0f, 0x00, 0xf0, 0x0f, 0x00,
|
||
0x80, 0x01, 0x00, 0xe0, 0x07, 0x00, 0xc0, 0x03, 0x00, 0x80, 0x01, 0x00,
|
||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
0x00, 0x00, 0x00 };
|
||
|
||
const unsigned char above_off_bits[] = {
|
||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0xc0, 0x03, 0x00,
|
||
0xe0, 0x07, 0x00, 0x80, 0x01, 0x00, 0xf0, 0x0f, 0x00, 0xf0, 0x0f, 0x00,
|
||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
0x00, 0x00, 0x00 };
|
||
|
||
const unsigned char below_on_bits[] = {
|
||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0xc0, 0x03, 0x00,
|
||
0xe0, 0x07, 0x00, 0x80, 0x01, 0x00, 0xf0, 0x0f, 0x00, 0xf0, 0x0f, 0x00,
|
||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
0x00, 0x00, 0x00 };
|
||
|
||
const unsigned char below_off_bits[] = {
|
||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x0f, 0x00, 0xf0, 0x0f, 0x00,
|
||
0x80, 0x01, 0x00, 0xe0, 0x07, 0x00, 0xc0, 0x03, 0x00, 0x80, 0x01, 0x00,
|
||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
0x00, 0x00, 0x00 };
|
||
|
||
const unsigned char shade_on_bits[] = {
|
||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x0f, 0x00, 0xf0, 0x0f, 0x00,
|
||
0x10, 0x08, 0x00, 0x10, 0x08, 0x00, 0x10, 0x08, 0x00, 0x10, 0x08, 0x00,
|
||
0x10, 0x08, 0x00, 0x10, 0x08, 0x00, 0x10, 0x08, 0x00, 0xf0, 0x0f, 0x00,
|
||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
0x00, 0x00, 0x00 };
|
||
|
||
const unsigned char shade_off_bits[] = {
|
||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x0f, 0x00, 0xf0, 0x0f, 0x00,
|
||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
0x00, 0x00, 0x00 };
|
||
|
||
KeramikHandler *clientHandler = NULL;
|
||
bool keramik_initialized = false;
|
||
|
||
|
||
|
||
// -------------------------------------------------------------------------------------------
|
||
|
||
|
||
|
||
KeramikHandler::KeramikHandler()
|
||
{
|
||
for ( int i = 0; i < NumTiles; i++ ) {
|
||
activeTiles[i] = NULL;
|
||
inactiveTiles[i] = NULL;
|
||
}
|
||
|
||
settings_cache = NULL;
|
||
|
||
// Create the button deco bitmaps
|
||
buttonDecos[ Menu ] = new QBitmap( QBitmap::fromData( QSize( 17, 17 ), menu_bits ) );
|
||
buttonDecos[ OnAllDesktops ] = new QBitmap( QBitmap::fromData( QSize( 17, 17 ), on_all_desktops_bits ) );
|
||
buttonDecos[ NotOnAllDesktops ] = new QBitmap( QBitmap::fromData( QSize( 17, 17 ), not_on_all_desktops_bits ) );
|
||
buttonDecos[ Help ] = new QBitmap( QBitmap::fromData( QSize( 17, 17 ), help_bits ) );
|
||
buttonDecos[ Minimize ] = new QBitmap( QBitmap::fromData( QSize( 17, 17 ), minimize_bits ) );
|
||
buttonDecos[ Maximize ] = new QBitmap( QBitmap::fromData( QSize( 17, 17 ), maximize_bits ) );
|
||
buttonDecos[ Restore ] = new QBitmap( QBitmap::fromData( QSize( 17, 17 ), restore_bits ) );
|
||
buttonDecos[ Close ] = new QBitmap( QBitmap::fromData( QSize( 17, 17 ), close_bits ) );
|
||
buttonDecos[ AboveOn ] = new QBitmap( QBitmap::fromData( QSize( 17, 17 ), above_on_bits ) );
|
||
buttonDecos[ AboveOff ] = new QBitmap( QBitmap::fromData( QSize( 17, 17 ), above_off_bits ) );
|
||
buttonDecos[ BelowOn ] = new QBitmap( QBitmap::fromData( QSize( 17, 17 ), below_on_bits ) );
|
||
buttonDecos[ BelowOff ] = new QBitmap( QBitmap::fromData( QSize( 17, 17 ), below_off_bits ) );
|
||
buttonDecos[ ShadeOn ] = new QBitmap( QBitmap::fromData( QSize( 17, 17 ), shade_on_bits ) );
|
||
buttonDecos[ ShadeOff ] = new QBitmap( QBitmap::fromData( QSize( 17, 17 ), shade_off_bits ) );
|
||
|
||
// Selfmask the bitmaps
|
||
for ( int i = 0; i < NumButtonDecos; i++ )
|
||
buttonDecos[i]->setMask( *buttonDecos[i] );
|
||
|
||
// Flip the bitmaps horizontally in right-to-left mode
|
||
if ( QApplication::isRightToLeft() ) {
|
||
for ( int i = 0; i < Help; ++i )
|
||
::flip( buttonDecos[i] );
|
||
|
||
for ( int i = Help + 1; i < NumButtonDecos; ++i )
|
||
::flip( buttonDecos[i] );
|
||
}
|
||
|
||
readConfig();
|
||
createPixmaps();
|
||
|
||
keramik_initialized = true;
|
||
}
|
||
|
||
|
||
KeramikHandler::~KeramikHandler()
|
||
{
|
||
keramik_initialized = false;
|
||
destroyPixmaps();
|
||
|
||
for ( int i = 0; i < NumButtonDecos; i++ )
|
||
delete buttonDecos[i];
|
||
|
||
delete settings_cache;
|
||
|
||
clientHandler = NULL;
|
||
}
|
||
|
||
|
||
void KeramikHandler::createPixmaps()
|
||
{
|
||
int heightOffset;
|
||
int widthOffset;
|
||
switch(options()->preferredBorderSize(this)) {
|
||
case BorderLarge:
|
||
widthOffset = 4;
|
||
heightOffset = 0;
|
||
break;
|
||
case BorderVeryLarge:
|
||
widthOffset = 8;
|
||
heightOffset = 0;
|
||
break;
|
||
case BorderHuge:
|
||
widthOffset = 14;
|
||
heightOffset = 0;
|
||
break;
|
||
case BorderVeryHuge:
|
||
widthOffset = 23;
|
||
heightOffset = 10;
|
||
break;
|
||
case BorderOversized:
|
||
widthOffset = 36;
|
||
heightOffset = 25;
|
||
break;
|
||
case BorderTiny:
|
||
case BorderNormal:
|
||
default:
|
||
widthOffset = 0;
|
||
heightOffset = 0;
|
||
}
|
||
int fontHeight = QFontMetrics(options()->font(true)).height();
|
||
if (fontHeight > heightOffset + 20)
|
||
heightOffset = fontHeight - 20;
|
||
|
||
QString size = (heightOffset < 8) ? "" : (heightOffset < 20) ? "-large" : "-huge";
|
||
|
||
QColor titleColor, captionColor, buttonColor;
|
||
QImage *titleCenter = NULL, *captionLeft = NULL,
|
||
*captionRight = NULL, *captionCenter = NULL;
|
||
|
||
|
||
// Active tiles
|
||
// -------------------------------------------------------------------------
|
||
captionColor = KDecoration::options()->color( ColorTitleBar, true );
|
||
titleColor = KDecoration::options()->color( ColorTitleBlend, true );
|
||
|
||
// Load the titlebar corners.
|
||
activeTiles[ TitleLeft ] = loadPixmap( "titlebar-left", titleColor );
|
||
activeTiles[ TitleRight ] = loadPixmap( "titlebar-right", titleColor );
|
||
|
||
// Load the titlebar center tile image (this will be used as
|
||
// the background for the caption bubble tiles).
|
||
titleCenter = loadImage( "titlebar-center", titleColor );
|
||
|
||
// Load the small version of the caption bubble corner & center images.
|
||
captionLeft = loadImage( "caption-small-left", captionColor );
|
||
captionRight = loadImage( "caption-small-right", captionColor );
|
||
captionCenter = loadImage( "caption-small-center", captionColor );
|
||
|
||
// Create the caption bubble tiles (by blending the images onto the titlebar)
|
||
activeTiles[ CaptionSmallLeft ] = composite( captionLeft, titleCenter );
|
||
activeTiles[ CaptionSmallRight ] = composite( captionRight, titleCenter );
|
||
activeTiles[ CaptionSmallCenter ] = composite( captionCenter, titleCenter );
|
||
|
||
delete captionLeft;
|
||
delete captionRight;
|
||
delete captionCenter;
|
||
|
||
// Now do the same with the large version
|
||
captionLeft = loadImage( "caption-large-left", captionColor );
|
||
captionRight = loadImage( "caption-large-right", captionColor );
|
||
captionCenter = loadImage( "caption-large-center", captionColor );
|
||
|
||
activeTiles[ CaptionLargeLeft ] = composite( captionLeft, titleCenter );
|
||
activeTiles[ CaptionLargeRight ] = composite( captionRight, titleCenter );
|
||
activeTiles[ CaptionLargeCenter ] = composite( captionCenter, titleCenter );
|
||
|
||
delete captionLeft;
|
||
delete captionRight;
|
||
delete captionCenter;
|
||
|
||
// Create the titlebar center tile
|
||
activeTiles[ TitleCenter ] = new QPixmap( QPixmap::fromImage( *titleCenter ) );
|
||
|
||
delete titleCenter;
|
||
|
||
// Load the left & right border pixmaps
|
||
activeTiles[ BorderLeft ] = loadPixmap( "border-left", titleColor );
|
||
activeTiles[ BorderRight ] = loadPixmap( "border-right", titleColor );
|
||
|
||
// Load the bottom grabbar pixmaps
|
||
if ( largeGrabBars ) {
|
||
activeTiles[ GrabBarLeft ] = loadPixmap( "grabbar-left", titleColor );
|
||
activeTiles[ GrabBarRight ] = loadPixmap( "grabbar-right", titleColor );
|
||
activeTiles[ GrabBarCenter ] = loadPixmap( "grabbar-center", titleColor );
|
||
} else {
|
||
activeTiles[ GrabBarLeft ] = loadPixmap( "bottom-left", titleColor );
|
||
activeTiles[ GrabBarRight ] = loadPixmap( "bottom-right", titleColor );
|
||
activeTiles[ GrabBarCenter ] = loadPixmap( "bottom-center", titleColor );
|
||
}
|
||
|
||
// Inactive tiles
|
||
// -------------------------------------------------------------------------
|
||
captionColor = KDecoration::options()->color( ColorTitleBar, false );
|
||
titleColor = KDecoration::options()->color( ColorTitleBlend, false );
|
||
|
||
inactiveTiles[ TitleLeft ] = loadPixmap( "titlebar-left", titleColor );
|
||
inactiveTiles[ TitleRight ] = loadPixmap( "titlebar-right", titleColor );
|
||
|
||
titleCenter = loadImage( "titlebar-center", titleColor );
|
||
|
||
captionLeft = loadImage( "caption-small-left", captionColor );
|
||
captionRight = loadImage( "caption-small-right", captionColor );
|
||
captionCenter = loadImage( "caption-small-center", captionColor );
|
||
|
||
inactiveTiles[ CaptionSmallLeft ] = composite( captionLeft, titleCenter );
|
||
inactiveTiles[ CaptionSmallRight ] = composite( captionRight, titleCenter );
|
||
inactiveTiles[ CaptionSmallCenter ] = composite( captionCenter, titleCenter );
|
||
|
||
delete captionLeft;
|
||
delete captionRight;
|
||
delete captionCenter;
|
||
|
||
inactiveTiles[ TitleCenter ] = new QPixmap( QPixmap::fromImage( *titleCenter ) );
|
||
|
||
delete titleCenter;
|
||
|
||
inactiveTiles[ BorderLeft ] = loadPixmap( "border-left", titleColor );
|
||
inactiveTiles[ BorderRight ] = loadPixmap( "border-right", titleColor );
|
||
|
||
if ( largeGrabBars ) {
|
||
inactiveTiles[ GrabBarLeft ] = loadPixmap( "grabbar-left", titleColor );
|
||
inactiveTiles[ GrabBarRight ] = loadPixmap( "grabbar-right", titleColor );
|
||
inactiveTiles[ GrabBarCenter ] = loadPixmap( "grabbar-center", titleColor );
|
||
} else {
|
||
inactiveTiles[ GrabBarLeft ] = loadPixmap( "bottom-left", titleColor );
|
||
inactiveTiles[ GrabBarRight ] = loadPixmap( "bottom-right", titleColor );
|
||
inactiveTiles[ GrabBarCenter ] = loadPixmap( "bottom-center", titleColor );
|
||
}
|
||
|
||
// Buttons
|
||
// -------------------------------------------------------------------------
|
||
buttonColor = QColor(); //KDecoration::options()->color( ButtonBg, true );
|
||
|
||
titleButtonRound = loadPixmap( "titlebutton-round"+size, buttonColor );
|
||
titleButtonSquare = loadPixmap( "titlebutton-square"+size, buttonColor );
|
||
|
||
|
||
// Prepare the tiles for use
|
||
// -------------------------------------------------------------------------
|
||
if ( QApplication::isRightToLeft() ) {
|
||
|
||
// Fix lighting
|
||
flip( activeTiles[CaptionSmallLeft], activeTiles[CaptionSmallRight] );
|
||
flip( inactiveTiles[CaptionSmallLeft], inactiveTiles[CaptionSmallRight] );
|
||
|
||
flip( activeTiles[CaptionLargeLeft], activeTiles[CaptionLargeRight] );
|
||
|
||
flip( activeTiles[TitleLeft], activeTiles[TitleRight] );
|
||
flip( inactiveTiles[TitleLeft], inactiveTiles[TitleRight] );
|
||
|
||
flip( activeTiles[BorderLeft], activeTiles[BorderRight] );
|
||
flip( inactiveTiles[BorderLeft], inactiveTiles[BorderRight] );
|
||
|
||
flip( activeTiles[GrabBarLeft], activeTiles[GrabBarRight] );
|
||
flip( inactiveTiles[GrabBarLeft], inactiveTiles[GrabBarRight] );
|
||
|
||
::flip( titleButtonRound );
|
||
::flip( titleButtonSquare );
|
||
}
|
||
|
||
// Pretile the center & border tiles for optimal performance
|
||
pretile( activeTiles[ CaptionSmallCenter ], 64, Qt::Horizontal );
|
||
pretile( activeTiles[ CaptionLargeCenter ], 64, Qt::Horizontal );
|
||
pretile( activeTiles[ TitleCenter ], 64, Qt::Horizontal );
|
||
pretile( activeTiles[ GrabBarCenter ], 128, Qt::Horizontal );
|
||
pretile( activeTiles[ BorderLeft ], 128, Qt::Vertical );
|
||
pretile( activeTiles[ BorderRight ], 128, Qt::Vertical );
|
||
|
||
pretile( inactiveTiles[ CaptionSmallCenter ], 64, Qt::Horizontal );
|
||
pretile( inactiveTiles[ TitleCenter ], 64, Qt::Horizontal );
|
||
pretile( inactiveTiles[ GrabBarCenter ], 128, Qt::Horizontal );
|
||
pretile( inactiveTiles[ BorderLeft ], 128, Qt::Vertical );
|
||
pretile( inactiveTiles[ BorderRight ], 128, Qt::Vertical );
|
||
|
||
if (heightOffset > 0) {
|
||
addHeight (heightOffset, activeTiles[TitleLeft]);
|
||
addHeight (heightOffset, activeTiles[TitleCenter]);
|
||
addHeight (heightOffset, activeTiles[TitleRight]);
|
||
addHeight (heightOffset, activeTiles[CaptionSmallLeft]);
|
||
addHeight (heightOffset, activeTiles[CaptionSmallCenter]);
|
||
addHeight (heightOffset, activeTiles[CaptionSmallRight]);
|
||
addHeight (heightOffset, activeTiles[CaptionLargeLeft]);
|
||
addHeight (heightOffset, activeTiles[CaptionLargeCenter]);
|
||
addHeight (heightOffset, activeTiles[CaptionLargeRight]);
|
||
|
||
addHeight (heightOffset, inactiveTiles[TitleLeft]);
|
||
addHeight (heightOffset, inactiveTiles[TitleCenter]);
|
||
addHeight (heightOffset, inactiveTiles[TitleRight]);
|
||
addHeight (heightOffset, inactiveTiles[CaptionSmallLeft]);
|
||
addHeight (heightOffset, inactiveTiles[CaptionSmallCenter]);
|
||
addHeight (heightOffset, inactiveTiles[CaptionSmallRight]);
|
||
}
|
||
|
||
if (widthOffset > 0) {
|
||
addWidth (widthOffset, activeTiles[BorderLeft], true, activeTiles[GrabBarCenter]);
|
||
addWidth (widthOffset, activeTiles[BorderRight], false, activeTiles[GrabBarCenter]);
|
||
addWidth (widthOffset, inactiveTiles[BorderLeft], true, inactiveTiles[GrabBarCenter]);
|
||
addWidth (widthOffset, inactiveTiles[BorderRight], false, inactiveTiles[GrabBarCenter]);
|
||
|
||
if (largeGrabBars)
|
||
widthOffset = widthOffset*3/2;
|
||
|
||
addHeight (widthOffset, activeTiles[GrabBarLeft]);
|
||
addHeight (widthOffset, activeTiles[GrabBarCenter]);
|
||
addHeight (widthOffset, activeTiles[GrabBarRight]);
|
||
addHeight (widthOffset, inactiveTiles[GrabBarLeft]);
|
||
addHeight (widthOffset, inactiveTiles[GrabBarCenter]);
|
||
addHeight (widthOffset, inactiveTiles[GrabBarRight]);
|
||
}
|
||
}
|
||
|
||
|
||
|
||
void KeramikHandler::destroyPixmaps()
|
||
{
|
||
for ( int i = 0; i < NumTiles; i++ ) {
|
||
delete activeTiles[i];
|
||
delete inactiveTiles[i];
|
||
activeTiles[i] = NULL;
|
||
inactiveTiles[i] = NULL;
|
||
}
|
||
|
||
delete titleButtonRound;
|
||
delete titleButtonSquare;
|
||
}
|
||
|
||
|
||
void KeramikHandler::addWidth (int width, QPixmap *&pix, bool left, QPixmap *bottomPix) {
|
||
int w = pix->width()+width;
|
||
int h = pix->height();
|
||
|
||
QPixmap *tmp = new QPixmap (w, h);
|
||
tmp->fill ();
|
||
QPainter p;
|
||
p.begin (tmp);
|
||
|
||
for (int i = 0; i < h; i++)
|
||
p.drawPixmap (0, i, *bottomPix, i%2, 0, w,1);
|
||
|
||
if (left)
|
||
p.drawPixmap(0, 0, *pix);
|
||
else
|
||
p.drawPixmap(width, 0, *pix);
|
||
|
||
p.end();
|
||
|
||
delete pix;
|
||
pix = tmp;
|
||
}
|
||
|
||
|
||
void KeramikHandler::addHeight (int height, QPixmap *&pix) {
|
||
int w = pix->width();
|
||
int h = pix->height()+height;
|
||
|
||
QPixmap *tmp = new QPixmap (w, h);
|
||
QPainter p;
|
||
p.begin (tmp);
|
||
if (pix->height() > 10) {
|
||
p.drawPixmap(0, 0, *pix, 0, 0, w, 11);
|
||
for (int i = 0; i < height; i+=2)
|
||
p.drawPixmap(0, 11+i, *pix, 0, 11, w, 2);
|
||
p.drawPixmap(0, 11+height, *pix, 0, 11, w, -1);
|
||
}
|
||
else {
|
||
int lines = h-3;
|
||
int factor = pix->height()-3;
|
||
for (int i = 0; i < lines; i++)
|
||
p.drawPixmap(0, i, *pix, 0, i*factor/lines, w, 1);
|
||
p.drawPixmap(0, lines, *pix, 0, factor, w, 3);
|
||
}
|
||
p.end();
|
||
|
||
delete pix;
|
||
pix = tmp;
|
||
}
|
||
|
||
|
||
void KeramikHandler::flip( QPixmap *&pix1, QPixmap *&pix2 )
|
||
{
|
||
// Flip the pixmaps horizontally
|
||
QPixmap *tmp = new QPixmap( pix1->transformed( QMatrix(-1,0,0,1,pix1->width(),0) ) );
|
||
|
||
delete pix1;
|
||
pix1 = new QPixmap( pix2->transformed( QMatrix(-1,0,0,1,pix2->width(),0) ) );
|
||
|
||
delete pix2;
|
||
pix2 = tmp;
|
||
}
|
||
|
||
|
||
void KeramikHandler::pretile( QPixmap *&pix, int size, Qt::Orientation dir )
|
||
{
|
||
QPixmap *newpix;
|
||
QPainter p;
|
||
|
||
if ( dir == Qt::Horizontal )
|
||
newpix = new QPixmap( size, pix->height() );
|
||
else
|
||
newpix = new QPixmap( pix->width(), size );
|
||
|
||
p.begin( newpix );
|
||
p.drawTiledPixmap( newpix->rect(), *pix ) ;
|
||
p.end();
|
||
|
||
delete pix;
|
||
pix = newpix;
|
||
}
|
||
|
||
|
||
void KeramikHandler::readConfig()
|
||
{
|
||
KConfig *c = new KConfig( "kwinkeramikrc" );
|
||
|
||
c->setGroup( "General" );
|
||
showIcons = c->readEntry( "ShowAppIcons", QVariant(true )).toBool();
|
||
shadowedText = c->readEntry( "UseShadowedText", QVariant(true )).toBool();
|
||
smallCaptionBubbles = c->readEntry( "SmallCaptionBubbles", QVariant(false )).toBool();
|
||
largeGrabBars = c->readEntry( "LargeGrabBars", QVariant(true )).toBool();
|
||
|
||
if ( ! settings_cache ) {
|
||
settings_cache = new SettingsCache;
|
||
settings_cache->largeGrabBars = largeGrabBars;
|
||
settings_cache->smallCaptionBubbles = smallCaptionBubbles;
|
||
}
|
||
|
||
delete c;
|
||
}
|
||
|
||
|
||
QPixmap *KeramikHandler::composite( QImage *over, QImage *under )
|
||
{
|
||
QImage dest( over->width(), over->height(), QImage::Format_RGB32 );
|
||
int width = over->width(), height = over->height();
|
||
|
||
// Clear the destination image
|
||
Q_UINT32 *data = reinterpret_cast<Q_UINT32*>( dest.bits() );
|
||
for (int i = 0; i < width * height; i++)
|
||
*(data++) = 0;
|
||
|
||
// Copy the under image (bottom aligned) to the destination image
|
||
for (int y1 = height - under->height(), y2 = 0; y1 < height; y1++, y2++ )
|
||
{
|
||
register Q_UINT32 *dst = reinterpret_cast<Q_UINT32*>( dest.scanLine(y1) );
|
||
register Q_UINT32 *src = reinterpret_cast<Q_UINT32*>( under->scanLine(y2) );
|
||
|
||
for ( int x = 0; x < width; x++ )
|
||
*(dst++) = *(src++);
|
||
}
|
||
|
||
// Blend the over image onto the destination
|
||
register Q_UINT32 *dst = reinterpret_cast<Q_UINT32*>( dest.bits() );
|
||
register Q_UINT32 *src = reinterpret_cast<Q_UINT32*>( over->bits() );
|
||
for ( int i = 0; i < width * height; i++ )
|
||
{
|
||
int r1 = qRed( *dst ), g1 = qGreen( *dst ), b1 = qBlue( *dst );
|
||
int r2 = qRed( *src ), g2 = qGreen( *src ), b2 = qBlue( *src );
|
||
int a = qAlpha( *src );
|
||
|
||
if ( a == 0xff )
|
||
*dst = *src;
|
||
|
||
else if ( a != 0x00 )
|
||
*dst = qRgba( Q_UINT8( r1 + (((r2 - r1) * a) >> 8) ),
|
||
Q_UINT8( g1 + (((g2 - g1) * a) >> 8) ),
|
||
Q_UINT8( b1 + (((b2 - b1) * a) >> 8) ),
|
||
0xff );
|
||
|
||
else if ( qAlpha(*dst) == 0x00 )
|
||
*dst = 0;
|
||
|
||
src++; dst++;
|
||
}
|
||
|
||
// Create the final pixmap and return it
|
||
return new QPixmap( QPixmap::fromImage( dest ) );
|
||
}
|
||
|
||
|
||
QImage *KeramikHandler::loadImage( const QString &name, const QColor &col )
|
||
{
|
||
if ( col.isValid() ) {
|
||
QImage *img = new QImage( ":/pics/" + name + ".png" );
|
||
KIconEffect::colorize( *img, col, 1.0 );
|
||
return img;
|
||
} else
|
||
return new QImage( ":/pics/" + name + ".png" );
|
||
}
|
||
|
||
|
||
QPixmap *KeramikHandler::loadPixmap( const QString &name, const QColor &col )
|
||
{
|
||
QImage *img = loadImage( name, col );
|
||
QPixmap *pix = new QPixmap( QPixmap::fromImage( *img ) );
|
||
delete img;
|
||
|
||
return pix;
|
||
}
|
||
|
||
|
||
bool KeramikHandler::reset( unsigned long changed )
|
||
{
|
||
keramik_initialized = false;
|
||
|
||
bool needHardReset = false;
|
||
bool pixmapsInvalid = false;
|
||
|
||
// Re-read the config file
|
||
readConfig();
|
||
|
||
if ( changed & SettingBorder )
|
||
{
|
||
pixmapsInvalid = true;
|
||
needHardReset = true;
|
||
}
|
||
if ( changed & SettingFont )
|
||
{
|
||
pixmapsInvalid = true;
|
||
needHardReset = true;
|
||
}
|
||
// Check if the color scheme has changed
|
||
if ( changed & SettingColors )
|
||
{
|
||
pixmapsInvalid = true;
|
||
}
|
||
// Check if button positions have changed
|
||
|
||
if ( changed & SettingButtons ) {
|
||
needHardReset = true;
|
||
}
|
||
|
||
// Check if tooltips options have changed
|
||
if ( changed & SettingTooltips ) {
|
||
needHardReset = true;
|
||
}
|
||
|
||
if ( (settings_cache->largeGrabBars != largeGrabBars) ) {
|
||
pixmapsInvalid = true;
|
||
needHardReset = true;
|
||
}
|
||
|
||
if ( (settings_cache->smallCaptionBubbles != smallCaptionBubbles) ) {
|
||
needHardReset = true;
|
||
}
|
||
|
||
// Update our config cache
|
||
settings_cache->largeGrabBars = largeGrabBars;
|
||
settings_cache->smallCaptionBubbles = smallCaptionBubbles;
|
||
|
||
// Do we need to recreate the pixmaps?
|
||
if ( pixmapsInvalid ) {
|
||
destroyPixmaps();
|
||
createPixmaps();
|
||
}
|
||
|
||
keramik_initialized = true;
|
||
|
||
// Do we need to "hit the wooden hammer" ?
|
||
if ( !needHardReset )
|
||
resetDecorations( changed );
|
||
return needHardReset;
|
||
}
|
||
|
||
|
||
bool KeramikHandler::supports( Ability ability )
|
||
{
|
||
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;
|
||
};
|
||
}
|
||
|
||
|
||
const QPixmap *KeramikHandler::tile( TilePixmap tilePix, bool active ) const
|
||
{
|
||
return ( active ? activeTiles[ tilePix ] : inactiveTiles[ tilePix ] );
|
||
}
|
||
|
||
KDecoration* KeramikHandler::createDecoration( KDecorationBridge* bridge )
|
||
{
|
||
return new KeramikClient( bridge, this );
|
||
}
|
||
|
||
QList< KeramikHandler::BorderSize > KeramikHandler::borderSizes() const
|
||
{ // the list must be sorted
|
||
return QList< BorderSize >() << BorderNormal << BorderLarge <<
|
||
BorderVeryLarge << BorderHuge << BorderVeryHuge << BorderOversized;
|
||
}
|
||
|
||
|
||
// -------------------------------------------------------------------------------------------
|
||
|
||
|
||
|
||
KeramikButton::KeramikButton( KeramikClient* c, const char *name, Button btn, const QString &tip, const int realizeBtns )
|
||
: Q3Button( c->widget(), name ),
|
||
client( c ), button( btn ), hover( false ), lastbutton( Qt::NoButton )
|
||
{
|
||
realizeButtons = realizeBtns;
|
||
|
||
this->setToolTip( tip ); // FRAME
|
||
setAttribute( Qt::WA_NoSystemBackground );
|
||
setCursor( Qt::ArrowCursor );
|
||
int size = clientHandler->roundButton()->height();
|
||
setFixedSize( size, size );
|
||
|
||
setCheckable( (button == OnAllDesktopsButton) );
|
||
}
|
||
|
||
|
||
KeramikButton::~KeramikButton()
|
||
{
|
||
// Empty.
|
||
}
|
||
|
||
|
||
void KeramikButton::enterEvent( QEvent *e )
|
||
{
|
||
Q3Button::enterEvent( e );
|
||
|
||
hover = true;
|
||
repaint();
|
||
}
|
||
|
||
|
||
void KeramikButton::leaveEvent( QEvent *e )
|
||
{
|
||
Q3Button::leaveEvent( e );
|
||
|
||
hover = false;
|
||
repaint();
|
||
}
|
||
|
||
|
||
void KeramikButton::mousePressEvent( QMouseEvent *e )
|
||
{
|
||
lastbutton = e->button();
|
||
QMouseEvent me( e->type(), e->pos(), e->globalPos(),
|
||
(e->button()&realizeButtons)?Qt::LeftButton : Qt::NoButton,
|
||
(e->button()&realizeButtons)?Qt::LeftButton : Qt::NoButton,
|
||
e->modifiers() );
|
||
Q3Button::mousePressEvent( &me );
|
||
}
|
||
|
||
|
||
void KeramikButton::mouseReleaseEvent( QMouseEvent *e )
|
||
{
|
||
lastbutton = e->button();
|
||
QMouseEvent me( e->type(), e->pos(), e->globalPos(),
|
||
(e->button()&realizeButtons)?Qt::LeftButton : Qt::NoButton,
|
||
(e->button()&realizeButtons)?Qt::LeftButton : Qt::NoButton,
|
||
e->modifiers() );
|
||
Q3Button::mouseReleaseEvent( &me );
|
||
}
|
||
|
||
|
||
void KeramikButton::drawButton( QPainter *p )
|
||
{
|
||
const QPixmap *pix;
|
||
const QBitmap *deco;
|
||
int size = clientHandler->roundButton()->height();
|
||
|
||
// Get the bevel from the client handler
|
||
if ( button == MenuButton || button == OnAllDesktopsButton || button == HelpButton )
|
||
pix = clientHandler->roundButton();
|
||
else
|
||
pix = clientHandler->squareButton();
|
||
|
||
// Draw the button background
|
||
const QPixmap *background = clientHandler->tile( TitleCenter, client->isActive() );
|
||
p->drawPixmap( 0, 0, *background,
|
||
0, (background->height()-size+1)/2, size, size );
|
||
|
||
if ( isDown() ) {
|
||
// Pressed
|
||
p->drawPixmap( QPoint(), *pix, QStyle::visualRect( QApplication::isRightToLeft() ? Qt::RightToLeft : Qt::LeftToRight, QRect(2*size, 0, size, size), pix->rect() ) );
|
||
p->translate( QApplication::isRightToLeft() ? -1 : 1, 1 );
|
||
} else if ( hover )
|
||
// Mouse over
|
||
p->drawPixmap( QPoint(), *pix, QStyle::visualRect( QApplication::isRightToLeft() ? Qt::RightToLeft : Qt::LeftToRight, QRect(size, 0, size, size), pix->rect() ) );
|
||
else
|
||
// Normal
|
||
p->drawPixmap( QPoint(), *pix, QStyle::visualRect( QApplication::isRightToLeft() ? Qt::RightToLeft : Qt::LeftToRight, QRect(0, 0, size, size), pix->rect() ) );
|
||
|
||
|
||
// Draw the button deco on the bevel
|
||
switch ( button ) {
|
||
case MenuButton:
|
||
deco = clientHandler->buttonDeco( Menu );
|
||
break;
|
||
|
||
case OnAllDesktopsButton:
|
||
deco = clientHandler->buttonDeco( client->isOnAllDesktops() ? NotOnAllDesktops : OnAllDesktops );
|
||
break;
|
||
|
||
case HelpButton:
|
||
deco = clientHandler->buttonDeco( Help );
|
||
// The '?' won't be flipped around in the ctor, so we need to
|
||
// shift it to the right to compensate for the button shadow
|
||
// being on the left side of the button in RTL mode.
|
||
if ( QApplication::isRightToLeft() )
|
||
p->translate( 2, 0 );
|
||
break;
|
||
|
||
case MinButton:
|
||
deco = clientHandler->buttonDeco( Minimize );
|
||
break;
|
||
|
||
case MaxButton:
|
||
deco = clientHandler->buttonDeco( client->maximizeMode() == KeramikClient::MaximizeFull ? Restore : Maximize );
|
||
break;
|
||
|
||
case CloseButton:
|
||
deco = clientHandler->buttonDeco( Close );
|
||
break;
|
||
|
||
case AboveButton:
|
||
deco = clientHandler->buttonDeco( client->keepAbove() ? AboveOn : AboveOff );
|
||
break;
|
||
|
||
case BelowButton:
|
||
deco = clientHandler->buttonDeco( client->keepBelow() ? BelowOn : BelowOff );
|
||
break;
|
||
|
||
case ShadeButton:
|
||
deco = clientHandler->buttonDeco( client->isSetShade() ? ShadeOn : ShadeOff );
|
||
break;
|
||
|
||
default:
|
||
deco = NULL;
|
||
}
|
||
|
||
p->setPen( Qt::black ); // ### hardcoded color
|
||
if (deco)
|
||
p->drawPixmap( (size-17)/2, (size-17)/2, *deco );
|
||
}
|
||
|
||
|
||
|
||
// ------------------------------------------------------------------------------------------
|
||
|
||
|
||
|
||
KeramikClient::KeramikClient( KDecorationBridge* bridge, KDecorationFactory* factory )
|
||
: KDecoration( bridge, factory ),
|
||
activeIcon( NULL ), inactiveIcon( NULL ), captionBufferDirty( true ), maskDirty( true )
|
||
{
|
||
}
|
||
|
||
void KeramikClient::init()
|
||
{
|
||
connect( this, SIGNAL( keepAboveChanged( bool )), SLOT( keepAboveChange( bool )));
|
||
connect( this, SIGNAL( keepBelowChanged( bool )), SLOT( keepBelowChange( bool )));
|
||
|
||
createMainWidget( Qt::WResizeNoErase );
|
||
widget()->setAttribute( Qt::WA_StaticContents );
|
||
widget()->installEventFilter( this );
|
||
|
||
// Minimize flicker
|
||
widget()->setAttribute( Qt::WA_NoSystemBackground );
|
||
|
||
for ( int i=0; i < NumButtons; i++ )
|
||
button[i] = NULL;
|
||
|
||
createLayout();
|
||
}
|
||
|
||
void KeramikClient::createLayout()
|
||
{
|
||
|
||
QVBoxLayout *mainLayout = new QVBoxLayout( widget() );
|
||
QBoxLayout *titleLayout = new QBoxLayout( QBoxLayout::LeftToRight );
|
||
titleLayout->setMargin( 0 );
|
||
titleLayout->setSpacing( 0 );
|
||
QHBoxLayout *windowLayout = new QHBoxLayout();
|
||
|
||
largeTitlebar = ( !maximizedVertical() && clientHandler->largeCaptionBubbles() );
|
||
largeCaption = ( isActive() && largeTitlebar );
|
||
|
||
int grabBarHeight = clientHandler->grabBarHeight();
|
||
int topSpacing = ( largeTitlebar ? 4 : 1 );
|
||
int leftBorderWidth = clientHandler->tile( BorderLeft, true )->width();
|
||
int rightBorderWidth = clientHandler->tile( BorderRight, true )->width();
|
||
topSpacer = new QSpacerItem( 10, topSpacing,
|
||
QSizePolicy::Expanding, QSizePolicy::Minimum );
|
||
|
||
mainLayout->addItem( topSpacer );
|
||
|
||
mainLayout->addLayout( titleLayout ); // Titlebar
|
||
mainLayout->addLayout( windowLayout, 1 ); // Left border + window + right border
|
||
mainLayout->addSpacing( grabBarHeight ); // Bottom grab bar
|
||
|
||
titleLayout->setSpacing( buttonSpacing );
|
||
|
||
titleLayout->addSpacing( buttonMargin ); // Left button margin
|
||
addButtons( titleLayout, options()->customButtonPositions() ?
|
||
options()->titleButtonsLeft() : QString(default_left) );
|
||
|
||
titlebar = new QSpacerItem( 10, clientHandler->titleBarHeight(largeTitlebar)
|
||
- topSpacing, QSizePolicy::Expanding, QSizePolicy::Minimum );
|
||
titleLayout->addItem( titlebar );
|
||
|
||
titleLayout->addSpacing( buttonSpacing );
|
||
addButtons( titleLayout, options()->customButtonPositions() ?
|
||
options()->titleButtonsRight() : QString(default_right) );
|
||
titleLayout->addSpacing( buttonMargin - 1 ); // Right button margin
|
||
|
||
windowLayout->addSpacing( leftBorderWidth ); // Left border
|
||
if( isPreview())
|
||
windowLayout->addWidget( new QLabel( i18n( "<center><b>Keramik preview</b></center>" ), widget()));
|
||
else
|
||
windowLayout->addItem( new QSpacerItem( 0, 0 )); //no widget in the middle
|
||
windowLayout->addSpacing( rightBorderWidth ); // Right border
|
||
}
|
||
|
||
|
||
KeramikClient::~KeramikClient()
|
||
{
|
||
delete activeIcon;
|
||
delete inactiveIcon;
|
||
|
||
activeIcon = inactiveIcon = NULL;
|
||
}
|
||
|
||
|
||
void KeramikClient::reset( unsigned long )
|
||
{
|
||
if ( clientHandler->largeCaptionBubbles() && !largeTitlebar )
|
||
{
|
||
// We're switching from small caption bubbles to large
|
||
if ( !maximizedVertical() ) {
|
||
topSpacer->changeSize( 10, 4, QSizePolicy::Expanding, QSizePolicy::Minimum );
|
||
largeTitlebar = true;
|
||
largeCaption = isActive();
|
||
|
||
widget()->layout()->activate();
|
||
|
||
// Compensate for the titlebar size change
|
||
|
||
// TODO This is wrong, this may break size increments (see bug #53784).
|
||
// FRAME
|
||
widget()->setGeometry( widget()->x(), widget()->y() - 3, width(), height() + 3 );
|
||
}
|
||
}
|
||
else if ( !clientHandler->largeCaptionBubbles() && largeTitlebar )
|
||
{
|
||
// We're switching from large caption bubbles to small
|
||
topSpacer->changeSize( 10, 1, QSizePolicy::Expanding, QSizePolicy::Minimum );
|
||
largeTitlebar = largeCaption = false;
|
||
|
||
widget()->layout()->activate();
|
||
|
||
// Compensate for the titlebar size change
|
||
// FRAME
|
||
widget()->setGeometry( widget()->x(), widget()->y() + 3, width(), height() - 3 );
|
||
}
|
||
|
||
calculateCaptionRect();
|
||
|
||
captionBufferDirty = maskDirty = true;
|
||
|
||
// Only repaint the window if it's visible
|
||
// (i.e. not minimized and on the current desktop)
|
||
if ( widget()->isVisible() ) {
|
||
widget()->repaint();
|
||
|
||
for ( int i = 0; i < NumButtons; i++ )
|
||
if ( button[i] ) button[i]->repaint();
|
||
}
|
||
}
|
||
|
||
|
||
void KeramikClient::addButtons( QBoxLayout *layout, const QString &s )
|
||
{
|
||
for ( int i=0; i < s.length(); i++ )
|
||
{
|
||
switch ( s[i].toLatin1() )
|
||
{
|
||
// Menu button
|
||
case 'M' :
|
||
if ( !button[MenuButton] ) {
|
||
button[MenuButton] = new KeramikButton( this, "menu", MenuButton, i18n("Menu"), Qt::LeftButton|Qt::RightButton );
|
||
connect( button[MenuButton], SIGNAL( pressed() ), SLOT( menuButtonPressed() ) );
|
||
layout->addWidget( button[MenuButton] );
|
||
}
|
||
break;
|
||
|
||
// OnAllDesktops button
|
||
case 'S' :
|
||
if ( !button[OnAllDesktopsButton] ) {
|
||
button[OnAllDesktopsButton] = new KeramikButton( this, "on_all_desktops",
|
||
OnAllDesktopsButton, isOnAllDesktops()?i18n("Not on all desktops"):i18n("On all desktops") );
|
||
if(isOnAllDesktops())
|
||
button[OnAllDesktopsButton]->toggle();
|
||
connect( button[OnAllDesktopsButton], SIGNAL( clicked() ), SLOT( toggleOnAllDesktops() ) );
|
||
layout->addWidget( button[OnAllDesktopsButton] );
|
||
}
|
||
break;
|
||
|
||
// Help button
|
||
case 'H' :
|
||
if ( !button[HelpButton] && providesContextHelp() ) {
|
||
button[HelpButton] = new KeramikButton( this, "help", HelpButton, i18n("Help") );
|
||
connect( button[HelpButton], SIGNAL( clicked() ), SLOT( showContextHelp() ) );
|
||
layout->addWidget( button[HelpButton] );
|
||
}
|
||
break;
|
||
|
||
// Minimize button
|
||
case 'I' :
|
||
if ( !button[MinButton] && isMinimizable() ) {
|
||
button[MinButton] = new KeramikButton( this, "minimize", MinButton, i18n("Minimize") );
|
||
connect( button[MinButton], SIGNAL( clicked() ), SLOT( minimize() ) );
|
||
layout->addWidget( button[MinButton] );
|
||
}
|
||
break;
|
||
|
||
// Maximize button
|
||
case 'A' :
|
||
if ( !button[MaxButton] && isMaximizable() ) {
|
||
button[MaxButton] = new KeramikButton( this, "maximize", MaxButton, i18n("Maximize"), Qt::LeftButton|Qt::MidButton|Qt::RightButton );
|
||
connect( button[MaxButton], SIGNAL( clicked() ), SLOT( slotMaximize() ) );
|
||
layout->addWidget( button[MaxButton] );
|
||
}
|
||
break;
|
||
|
||
// Close button
|
||
case 'X' :
|
||
if ( !button[CloseButton] && isCloseable() ) {
|
||
button[CloseButton] = new KeramikButton( this, "close", CloseButton, i18n("Close") );
|
||
connect( button[CloseButton], SIGNAL( clicked() ), SLOT( closeWindow() ) );
|
||
layout->addWidget( button[CloseButton] );
|
||
}
|
||
break;
|
||
|
||
// Above button
|
||
case 'F' :
|
||
if ( !button[AboveButton]) {
|
||
button[AboveButton] = new KeramikButton( this, "above", AboveButton, i18n("Keep Above Others") );
|
||
connect( button[AboveButton], SIGNAL( clicked() ), SLOT( slotAbove() ) );
|
||
layout->addWidget( button[AboveButton] );
|
||
}
|
||
break;
|
||
|
||
// Below button
|
||
case 'B' :
|
||
if ( !button[BelowButton]) {
|
||
button[BelowButton] = new KeramikButton( this, "below", BelowButton, i18n("Keep Below Others") );
|
||
connect( button[BelowButton], SIGNAL( clicked() ), SLOT( slotBelow() ) );
|
||
layout->addWidget( button[BelowButton] );
|
||
}
|
||
break;
|
||
|
||
// Shade button
|
||
case 'L' :
|
||
if ( !button[ShadeButton] && isShadeable() ) {
|
||
button[ShadeButton] = new KeramikButton( this, "shade", ShadeButton,
|
||
isSetShade() ? i18n("Unshade") : i18n( "Shade" ));
|
||
connect( button[ShadeButton], SIGNAL( clicked() ), SLOT( slotShade() ) );
|
||
layout->addWidget( button[ShadeButton] );
|
||
}
|
||
break;
|
||
|
||
// Additional spacing
|
||
case '_' :
|
||
layout->addSpacing( buttonSpacing );
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
void KeramikClient::updateMask()
|
||
{
|
||
if ( !keramik_initialized )
|
||
return;
|
||
|
||
// To maximize performance this code uses precalculated bounding rects
|
||
// to set the window mask. This saves us from having to allocate a 1bpp
|
||
// pixmap, paint the mask on it and then have the X server iterate
|
||
// over the pixels to compute the bounding rects from it.
|
||
|
||
QRegion r;
|
||
register int w, y = 0;
|
||
int nrects;
|
||
|
||
if ( QApplication::isRightToLeft() ) {
|
||
|
||
// If the caption bubble is visible and extends above the titlebar
|
||
if ( largeCaption && captionRect.width() >= 25 ) {
|
||
register int x = captionRect.left();
|
||
w = captionRect.width();
|
||
r += QRegion( x + 11, y++, w - 19, 1 );
|
||
r += QRegion( x + 9, y++, w - 15, 1 );
|
||
r += QRegion( x + 7, y++, w - 12, 1 );
|
||
} else {
|
||
nrects = 8;
|
||
|
||
// Do we have a large titlebar with a retracted caption bubble?
|
||
// (i.e. the style is set to use large caption bubbles, we're
|
||
// not maximized and not active)
|
||
if ( largeTitlebar )
|
||
y = 3;
|
||
}
|
||
|
||
w = width(); // FRAME
|
||
|
||
// The rounded titlebar corners
|
||
r += QRegion( 9, y++, w - 17, 1 );
|
||
r += QRegion( 7, y++, w - 13, 1 );
|
||
r += QRegion( 5, y++, w - 9, 1 );
|
||
r += QRegion( 4, y++, w - 7, 1 );
|
||
r += QRegion( 3, y++, w - 5, 1 );
|
||
r += QRegion( 2, y++, w - 4, 1 );
|
||
r += QRegion( 1, y++, w - 2, 2 );
|
||
} else {
|
||
|
||
// If the caption bubble is visible and extends above the titlebar
|
||
if ( largeCaption && captionRect.width() >= 25 ) {
|
||
nrects = 11;
|
||
register int x = captionRect.left();
|
||
w = captionRect.width();
|
||
r += QRegion( x + 8, y++, w - 19, 1 );
|
||
r += QRegion( x + 6, y++, w - 15, 1 );
|
||
r += QRegion( x + 5, y++, w - 12, 1 );
|
||
} else {
|
||
nrects = 8;
|
||
|
||
// Do we have a large titlebar with a retracted caption bubble?
|
||
// (i.e. the style is set to use large caption bubbles, we're
|
||
// not maximized and not active)
|
||
if ( largeTitlebar )
|
||
y = 3;
|
||
}
|
||
|
||
w = width(); // FRAME
|
||
|
||
// The rounded titlebar corners
|
||
r += QRegion( 8, y++, w - 17, 1 );
|
||
r += QRegion( 6, y++, w - 13, 1 );
|
||
r += QRegion( 4, y++, w - 9, 1 );
|
||
r += QRegion( 3, y++, w - 7, 1 );
|
||
r += QRegion( 2, y++, w - 5, 1 );
|
||
r += QRegion( 2, y++, w - 4, 1 );
|
||
r += QRegion( 1, y++, w - 2, 2 );
|
||
}
|
||
|
||
y++;
|
||
|
||
// The part of the window below the titlebar
|
||
r += QRegion( 0, y, w, height() - y );
|
||
|
||
setMask( r, YXBanded );
|
||
|
||
maskDirty = false;
|
||
}
|
||
|
||
|
||
void KeramikClient::updateCaptionBuffer()
|
||
{
|
||
if ( !keramik_initialized )
|
||
return;
|
||
|
||
bool active = isActive();
|
||
QPixmap *icon = NULL;
|
||
|
||
if ( captionBuffer.size() != captionRect.size() )
|
||
captionBuffer = QPixmap( captionRect.size() );
|
||
|
||
if ( captionBuffer.isNull() )
|
||
return;
|
||
|
||
QPainter p( &captionBuffer );
|
||
|
||
// Draw the caption bubble
|
||
if ( active && largeCaption ) {
|
||
p.drawPixmap( 0, 0, *clientHandler->tile( CaptionLargeLeft, true ) );
|
||
p.drawTiledPixmap( 15, 0, captionRect.width() - 30, captionRect.height(),
|
||
*clientHandler->tile( CaptionLargeCenter, true ) );
|
||
p.drawPixmap( captionRect.width() - 15, 0, *clientHandler->tile( CaptionLargeRight, true ) );
|
||
} else {
|
||
p.drawPixmap( 0, 0, *clientHandler->tile( CaptionSmallLeft, active ) );
|
||
p.drawTiledPixmap( 15, 0, captionRect.width() - 30, captionRect.height(),
|
||
*clientHandler->tile( CaptionSmallCenter, active ) );
|
||
p.drawPixmap( captionRect.width() - 15, 0, *clientHandler->tile( CaptionSmallRight, active ) );
|
||
}
|
||
|
||
if ( clientHandler->showAppIcons() )
|
||
{
|
||
QStyle *style = button[ 0 ]->style();
|
||
if ( active ) {
|
||
if ( ! activeIcon )
|
||
activeIcon = new QPixmap( this->icon().pixmap( style->pixelMetric( QStyle::PM_SmallIconSize ), QIcon::Normal )); // FRAME
|
||
icon = activeIcon;
|
||
} else {
|
||
if ( ! inactiveIcon ) {
|
||
QImage img = this->icon().pixmap( style->pixelMetric( QStyle::PM_SmallIconSize ), QIcon::Normal ).toImage();
|
||
KIconEffect::semiTransparent( img );
|
||
inactiveIcon = new QPixmap( QPixmap::fromImage( img ) );
|
||
}
|
||
icon = inactiveIcon;
|
||
}
|
||
}
|
||
|
||
p.setFont( options()->font( active ) );
|
||
int tw = p.fontMetrics().width( caption() ) +
|
||
( clientHandler->showAppIcons() ? 16 + iconSpacing : 0 );
|
||
|
||
int xpos = qMax( (captionRect.width() - tw) / 3, 8 );
|
||
QRect tr = QStyle::visualRect( QApplication::isRightToLeft() ? Qt::RightToLeft : Qt::LeftToRight, QRect(xpos, 1, captionRect.width() - xpos - 10,
|
||
captionRect.height() - 4), captionBuffer.rect() );
|
||
|
||
//p.setPen( Qt::red ); // debug
|
||
//p.drawRect( tr ); // debug
|
||
|
||
// Application icon
|
||
if ( clientHandler->showAppIcons() )
|
||
{
|
||
QRect iconRect = QStyle::visualRect( QApplication::isRightToLeft() ? Qt::RightToLeft : Qt::LeftToRight, QRect(tr.x(),
|
||
1 + (captionRect.height() - 4 - 16) / 2, 16, 16), tr );
|
||
QRect r( icon->rect() );
|
||
r.moveCenter( iconRect.center() );
|
||
|
||
if ( tr.width() > 16 ) {
|
||
p.drawPixmap( r, *icon );
|
||
} else {
|
||
QRect sr( 0, 0, icon->width(), icon->height() );
|
||
|
||
if ( QApplication::isRightToLeft() )
|
||
sr.adjust( icon->width() - tr.width(), 0, 0, 0 );
|
||
else
|
||
sr.adjust( 0, 0, -( icon->width() - tr.width() ), 0 );
|
||
|
||
p.drawPixmap( r.x() + sr.x(), r.y() + sr.y(), *icon,
|
||
sr.x(), sr.y(), sr.width(), sr.height() );
|
||
}
|
||
|
||
//p.drawRect( r ); // debug
|
||
|
||
if ( QApplication::isRightToLeft() )
|
||
tr.adjust( 0, 0, -(16 + iconSpacing), 0 );
|
||
else
|
||
tr.adjust( (16 + iconSpacing), 0, 0, 0 );
|
||
}
|
||
|
||
// Draw the titlebar text
|
||
int flags = Qt::AlignVCenter | Qt::TextSingleLine;
|
||
flags |= ( QApplication::isRightToLeft() ? Qt::AlignRight : Qt::AlignLeft );
|
||
|
||
if ( clientHandler->useShadowedText() )
|
||
{
|
||
p.translate( QApplication::isRightToLeft() ? -1 : 1, 1 );
|
||
//p.setPen( options()->color(ColorTitleBar, active).dark() );
|
||
if (qGray(options()->color(ColorFont, active).rgb()) < 100)
|
||
p.setPen( QColor(200,200,200) );
|
||
else
|
||
p.setPen( Qt::black );
|
||
p.drawText( tr, flags, caption() );
|
||
p.translate( QApplication::isRightToLeft() ? 1 : -1, -1 );
|
||
}
|
||
|
||
p.setPen( options()->color( ColorFont, active ) );
|
||
p.drawText( tr, flags, caption() );
|
||
|
||
captionBufferDirty = false;
|
||
}
|
||
|
||
|
||
void KeramikClient::calculateCaptionRect()
|
||
{
|
||
QFontMetrics fm( options()->font(isActive()) );
|
||
int cw = fm.width( caption() ) + 95;
|
||
int titleBaseY = ( largeTitlebar ? 3 : 0 );
|
||
|
||
if ( clientHandler->showAppIcons() )
|
||
cw += 16 + 4; // icon width + space
|
||
|
||
cw = qMin( cw, titlebar->geometry().width() );
|
||
captionRect = QStyle::visualRect( QApplication::isRightToLeft() ? Qt::RightToLeft : Qt::LeftToRight, QRect(titlebar->geometry().x(), (largeCaption ? 0 : titleBaseY),
|
||
cw, clientHandler->titleBarHeight(largeCaption) ),
|
||
titlebar->geometry() );
|
||
}
|
||
|
||
|
||
void KeramikClient::captionChange()
|
||
{
|
||
QRect r( captionRect );
|
||
calculateCaptionRect();
|
||
|
||
if ( r.size() != captionRect.size() )
|
||
maskDirty = true;
|
||
|
||
captionBufferDirty = true;
|
||
|
||
widget()->repaint( r | captionRect );
|
||
}
|
||
|
||
|
||
void KeramikClient::iconChange()
|
||
{
|
||
if ( clientHandler->showAppIcons() ) {
|
||
|
||
// Force updateCaptionBuffer() to recreate the cached icons
|
||
delete activeIcon;
|
||
|
||
delete inactiveIcon;
|
||
|
||
activeIcon = inactiveIcon = NULL;
|
||
|
||
captionBufferDirty = true;
|
||
widget()->repaint( captionRect );
|
||
}
|
||
}
|
||
|
||
|
||
void KeramikClient::activeChange()
|
||
{
|
||
bool active = isActive();
|
||
// Note: It's assumed that the same font will always be used for both active
|
||
// and inactive windows, since the fonts kcm hasn't supported setting
|
||
// different fonts for different window states for some time.
|
||
if ( largeTitlebar ) {
|
||
largeCaption = ( active && !maximizedVertical() );
|
||
calculateCaptionRect();
|
||
maskDirty = true;
|
||
}
|
||
|
||
captionBufferDirty = true;
|
||
|
||
widget()->repaint();
|
||
|
||
for ( int i=0; i < NumButtons; i++ )
|
||
if ( button[i] ) button[i]->repaint();
|
||
}
|
||
|
||
|
||
void KeramikClient::maximizeChange()
|
||
{
|
||
if ( clientHandler->largeCaptionBubbles() )
|
||
{
|
||
if ( maximizeMode() & MaximizeVertical ) {
|
||
// We've been maximized - shrink the titlebar by 3 pixels
|
||
topSpacer->changeSize( 10, 1, QSizePolicy::Expanding, QSizePolicy::Minimum );
|
||
largeCaption = largeTitlebar = false;
|
||
|
||
calculateCaptionRect();
|
||
captionBufferDirty = maskDirty = true;
|
||
|
||
widget()->layout()->activate();
|
||
widget()->repaint();
|
||
} else if (( maximizeMode() & MaximizeVertical ) == 0 && !largeTitlebar ) {
|
||
// We've been restored - enlarge the titlebar by 3 pixels
|
||
topSpacer->changeSize( 10, 4, QSizePolicy::Expanding, QSizePolicy::Minimum );
|
||
largeCaption = largeTitlebar = true;
|
||
|
||
calculateCaptionRect();
|
||
captionBufferDirty = maskDirty = true;
|
||
|
||
widget()->layout()->activate();
|
||
widget()->repaint();
|
||
}
|
||
}
|
||
|
||
if ( button[ MaxButton ] ) {
|
||
button[ MaxButton ]->setToolTip( maximizeMode() == MaximizeFull ? i18n("Restore") : i18n("Maximize") );
|
||
button[ MaxButton ]->repaint();
|
||
}
|
||
}
|
||
|
||
|
||
void KeramikClient::desktopChange()
|
||
{
|
||
if ( button[ OnAllDesktopsButton ] )
|
||
{
|
||
button[ OnAllDesktopsButton ]->repaint();
|
||
button[ OnAllDesktopsButton ]->setToolTip( isOnAllDesktops() ? i18n("Not on all desktops") : i18n("On all desktops") );
|
||
}
|
||
}
|
||
|
||
|
||
void KeramikClient::shadeChange()
|
||
{
|
||
if ( button[ ShadeButton ] )
|
||
{
|
||
button[ ShadeButton ]->repaint();
|
||
button[ ShadeButton ]->setToolTip( isSetShade() ? i18n("Unshade") : i18n("Shade") );
|
||
}
|
||
}
|
||
|
||
|
||
void KeramikClient::keepAboveChange( bool )
|
||
{
|
||
if ( button[ AboveButton ] )
|
||
button[ AboveButton ]->repaint();
|
||
}
|
||
|
||
|
||
void KeramikClient::keepBelowChange( bool )
|
||
{
|
||
if ( button[ BelowButton ] )
|
||
button[ BelowButton ]->repaint();
|
||
}
|
||
|
||
|
||
void KeramikClient::menuButtonPressed()
|
||
{
|
||
QPoint menuTop ( button[MenuButton]->rect().topLeft() );
|
||
QPoint menuBottom ( button[MenuButton]->rect().bottomRight() );
|
||
menuTop += QPoint(-6, -3);
|
||
menuBottom += QPoint(6, 3);
|
||
KDecorationFactory* f = factory();
|
||
showWindowMenu( QRect( button[MenuButton]->mapToGlobal( menuTop ),
|
||
button[MenuButton]->mapToGlobal( menuBottom )) );
|
||
if( !f->exists( this )) // 'this' was destroyed
|
||
return;
|
||
button[MenuButton]->setDown(false);
|
||
}
|
||
|
||
|
||
void KeramikClient::slotMaximize()
|
||
{
|
||
maximize( button[ MaxButton ]->lastButton() );
|
||
}
|
||
|
||
|
||
void KeramikClient::slotAbove()
|
||
{
|
||
setKeepAbove( !keepAbove());
|
||
button[ AboveButton ]->repaint();
|
||
}
|
||
|
||
|
||
void KeramikClient::slotBelow()
|
||
{
|
||
setKeepBelow( !keepBelow());
|
||
button[ BelowButton ]->repaint();
|
||
}
|
||
|
||
|
||
void KeramikClient::slotShade()
|
||
{
|
||
setShade( !isSetShade());
|
||
button[ ShadeButton ]->repaint();
|
||
}
|
||
|
||
|
||
void KeramikClient::paintEvent( QPaintEvent *e )
|
||
{
|
||
if ( !keramik_initialized )
|
||
return;
|
||
|
||
QPainter p( widget());
|
||
QRect updateRect( e->rect() );
|
||
bool active = isActive();
|
||
|
||
int titleBaseY = ( largeTitlebar ? 3 : 0 );
|
||
int titleBarHeight = clientHandler->titleBarHeight( largeTitlebar );
|
||
int grabBarHeight = clientHandler->grabBarHeight();
|
||
int leftBorderWidth = clientHandler->tile( BorderLeft, active )->width();
|
||
int rightBorderWidth = clientHandler->tile( BorderRight, active )->width();
|
||
|
||
if ( maskDirty )
|
||
updateMask();
|
||
|
||
// Titlebar
|
||
// -----------------------------------------------------------------------
|
||
if ( updateRect.y() < titleBarHeight )
|
||
{
|
||
int titleBarBaseHeight = titleBarHeight - titleBaseY;
|
||
|
||
if ( captionBufferDirty )
|
||
updateCaptionBuffer();
|
||
|
||
// Top left corner
|
||
if ( updateRect.x() < 15 )
|
||
p.drawPixmap( 0, titleBaseY,
|
||
*clientHandler->tile( TitleLeft, active ) );
|
||
|
||
// Space between the top left corner and the caption bubble
|
||
if ( updateRect.x() < captionRect.left() && updateRect.right() >= 15 ) {
|
||
int x1 = qMax( 15, updateRect.x() );
|
||
int x2 = qMin( captionRect.left(), updateRect.right() );
|
||
|
||
p.drawTiledPixmap( x1, titleBaseY, x2 - x1 + 1, titleBarBaseHeight,
|
||
*clientHandler->tile( TitleCenter, active ) );
|
||
}
|
||
|
||
// Caption bubble
|
||
if ( updateRect.x() <= captionRect.right() && updateRect.right() > 15 ) {
|
||
if ( captionRect.width() >= 25 )
|
||
p.drawPixmap( captionRect.left(), active ? 0 : titleBaseY, captionBuffer );
|
||
else
|
||
p.drawTiledPixmap( captionRect.x(), titleBaseY, captionRect.width(),
|
||
titleBarBaseHeight, *clientHandler->tile( TitleCenter, active ) );
|
||
}
|
||
|
||
// Space between the caption bubble and the top right corner
|
||
if ( updateRect.right() > captionRect.right() && updateRect.x() < width() - 15 ) { // FRAME
|
||
int x1 = qMax( captionRect.right() + 1, updateRect.x() );
|
||
int x2 = qMin( width() - 15, updateRect.right() );
|
||
|
||
p.drawTiledPixmap( x1, titleBaseY, x2 - x1 + 1, titleBarBaseHeight,
|
||
*clientHandler->tile( TitleCenter, active ) );
|
||
}
|
||
|
||
// Top right corner
|
||
if ( updateRect.right() >= width() - 15 )
|
||
p.drawPixmap( width() - 15, titleBaseY,
|
||
*clientHandler->tile( TitleRight, active ) );
|
||
}
|
||
|
||
// Borders
|
||
// -----------------------------------------------------------------------
|
||
if ( updateRect.bottom() >= titleBarHeight &&
|
||
updateRect.top() < height() - grabBarHeight )
|
||
{
|
||
int top = qMax( titleBarHeight, updateRect.top() );
|
||
int bottom = qMin( updateRect.bottom(), height() - grabBarHeight );
|
||
|
||
// Left border
|
||
if ( updateRect.x() < leftBorderWidth )
|
||
p.drawTiledPixmap( 0, top, leftBorderWidth, bottom - top + 1,
|
||
*clientHandler->tile( BorderLeft, active ) );
|
||
|
||
// Right border
|
||
if ( e->rect().right() > width() - rightBorderWidth - 1 )
|
||
p.drawTiledPixmap( width() - rightBorderWidth, top, rightBorderWidth,
|
||
bottom - top + 1, *clientHandler->tile( BorderRight, active ) );
|
||
}
|
||
|
||
// Bottom grab bar
|
||
// -----------------------------------------------------------------------
|
||
if ( updateRect.bottom() >= height() - grabBarHeight ) {
|
||
// Bottom left corner
|
||
if ( updateRect.x() < 9 )
|
||
p.drawPixmap( 0, height() - grabBarHeight,
|
||
*clientHandler->tile( GrabBarLeft, active ) );
|
||
|
||
// Space between the left corner and the right corner
|
||
if ( updateRect.x() < width() - 9 ) {
|
||
int x1 = qMax( 9, updateRect.x() );
|
||
int x2 = qMin( width() - 9, updateRect.right() );
|
||
|
||
p.drawTiledPixmap( x1, height() - grabBarHeight, x2 - x1 + 1,
|
||
grabBarHeight, *clientHandler->tile( GrabBarCenter, active ) );
|
||
}
|
||
|
||
// Bottom right corner
|
||
if ( updateRect.right() > width() - 9 )
|
||
p.drawPixmap( width() - 9, height() - grabBarHeight,
|
||
*clientHandler->tile( GrabBarRight, active ) );
|
||
}
|
||
|
||
// Extra drawline for the 1 pixel empty space QLayout leaves when a window is shaded.
|
||
p.setPen( options()->color( ColorTitleBlend, active ) );
|
||
p.drawLine( leftBorderWidth, height() - grabBarHeight - 1,
|
||
width() - rightBorderWidth - 1, height() - grabBarHeight - 1 );
|
||
}
|
||
|
||
|
||
void KeramikClient::resizeEvent( QResizeEvent *e )
|
||
{
|
||
// FRAME Client::resizeEvent( e );
|
||
|
||
QRect r( captionRect );
|
||
calculateCaptionRect();
|
||
|
||
if ( r.size() != captionRect.size() )
|
||
captionBufferDirty = true;
|
||
|
||
maskDirty = true;
|
||
|
||
if ( widget()->isVisible() )
|
||
{
|
||
widget()->update( widget()->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 )
|
||
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( this, new QPaintEvent( titlebar->geometry() ) );
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
void KeramikClient::mouseDoubleClickEvent( QMouseEvent *e )
|
||
{
|
||
if ( e->button() == Qt::LeftButton
|
||
&& QRect( 0, 0, width(), clientHandler->titleBarHeight( largeTitlebar ) ).contains( e->pos() ) )
|
||
titlebarDblClickOperation();
|
||
}
|
||
|
||
|
||
KeramikClient::Position KeramikClient::mousePosition( const QPoint &p ) const
|
||
{
|
||
int titleBaseY = (largeTitlebar ? 3 : 0);
|
||
|
||
int leftBorder = clientHandler->tile( BorderLeft, true )->width();
|
||
int rightBorder = width() - clientHandler->tile( BorderRight, true )->width() - 1;
|
||
int bottomBorder = height() - clientHandler->grabBarHeight() - 1;
|
||
int bottomCornerSize = 3*clientHandler->tile( BorderRight, true )->width()/2 + 24;
|
||
|
||
// Test if the mouse is over the titlebar area
|
||
if ( p.y() < titleBaseY + 11 ) {
|
||
// Test for the top left corner
|
||
if ( p.x() < leftBorder + 11 ) {
|
||
if ( (p.y() < titleBaseY + 3 && p.x() < leftBorder + 11) ||
|
||
(p.y() < titleBaseY + 6 && p.x() < leftBorder + 6) ||
|
||
(p.y() < titleBaseY + 11 && p.x() < leftBorder + 3) )
|
||
return PositionTopLeft;
|
||
}
|
||
|
||
// Test for the top right corner
|
||
if ( p.x() > rightBorder - 11 ) {
|
||
if ( (p.y() < titleBaseY + 3 && p.x() > rightBorder - 11) ||
|
||
(p.y() < titleBaseY + 6 && p.x() > rightBorder - 6) ||
|
||
(p.y() < titleBaseY + 11 && p.x() > rightBorder - 3) )
|
||
return PositionTopRight;
|
||
}
|
||
|
||
// Test for the top border
|
||
if ( p.y() <= 3 || (p.y() <= titleBaseY+3 &&
|
||
(p.x() < captionRect.left() || p.x() > captionRect.right()) ) )
|
||
return PositionTop;
|
||
|
||
// The cursor must be over the center of the titlebar.
|
||
return PositionCenter;
|
||
}
|
||
|
||
// Test the sides
|
||
else if ( p.y() < bottomBorder ) {
|
||
// Test for the left side
|
||
if ( p.x() < leftBorder ) {
|
||
if ( p.y() < height() - bottomCornerSize )
|
||
return PositionLeft;
|
||
else
|
||
return PositionBottomLeft;
|
||
}
|
||
|
||
// Test for the right side
|
||
else if ( p.x() > rightBorder ) {
|
||
if ( p.y() < height() - bottomCornerSize )
|
||
return PositionRight;
|
||
else
|
||
return PositionBottomRight;
|
||
}
|
||
|
||
// The cursor must be over the center of the window
|
||
return PositionCenter;
|
||
}
|
||
|
||
// Test the grab bar / bottom border
|
||
else {
|
||
// Test for the bottom left corner
|
||
if ( p.x() < bottomCornerSize )
|
||
return PositionBottomLeft;
|
||
|
||
// Test for the bottom right corner
|
||
else if ( p.x() > width() - bottomCornerSize - 1 )
|
||
return PositionBottomRight;
|
||
|
||
// The cursor must be over the bottom border
|
||
return PositionBottom;
|
||
}
|
||
|
||
// We should never get here
|
||
return PositionCenter;
|
||
}
|
||
|
||
|
||
void KeramikClient::resize( const QSize& s )
|
||
{
|
||
widget()->resize( s );
|
||
}
|
||
|
||
|
||
void KeramikClient::borders( int& left, int& right, int& top, int& bottom ) const
|
||
{
|
||
int titleBarHeight = clientHandler->titleBarHeight( clientHandler->largeCaptionBubbles() );
|
||
int grabBarHeight = clientHandler->grabBarHeight();
|
||
int leftBorderWidth = clientHandler->tile( BorderLeft, isActive() )->width();
|
||
int rightBorderWidth = clientHandler->tile( BorderRight, isActive() )->width();
|
||
|
||
left = leftBorderWidth;
|
||
right = rightBorderWidth;
|
||
top = titleBarHeight;
|
||
bottom = grabBarHeight;
|
||
|
||
if ( ( maximizeMode() & MaximizeHorizontal ) && !options()->moveResizeMaximizedWindows())
|
||
left = right = 0;
|
||
if( maximizeMode() & MaximizeVertical)
|
||
{
|
||
top = clientHandler->titleBarHeight( false );
|
||
if( !options()->moveResizeMaximizedWindows())
|
||
bottom = 0;
|
||
}
|
||
}
|
||
|
||
|
||
QSize KeramikClient::minimumSize() const
|
||
{
|
||
return widget()->minimumSize();
|
||
}
|
||
|
||
|
||
bool KeramikClient::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;
|
||
|
||
default:
|
||
return false;
|
||
}
|
||
}
|
||
|
||
} // namespace Keramik
|
||
|
||
|
||
|
||
// -------------------------------------------------------------------------------------------
|
||
|
||
|
||
|
||
extern "C"
|
||
{
|
||
KDE_EXPORT KDecorationFactory *create_factory()
|
||
{
|
||
Keramik::clientHandler = new Keramik::KeramikHandler();
|
||
return Keramik::clientHandler;
|
||
}
|
||
}
|
||
|
||
|
||
|
||
// vim: set noet ts=4 sw=4:
|