kwin/clients/aurorae/src/aurorae.cpp
Fredrik Höglund 92fc39b5eb Aurorae supports AbilityExtendIntoClientArea.
svn path=/trunk/KDE/kdebase/workspace/; revision=1063011
2009-12-16 17:51:58 +00:00

976 lines
31 KiB
C++

/********************************************************************
Copyright (C) 2009 Martin Gräßlin <kde@martin-graesslin.com>
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. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************/
#include "aurorae.h"
#include <kglobal.h>
#include <kstandarddirs.h>
#include <kdebug.h>
#include <KConfig>
#include <KConfigGroup>
#include <KDE/Plasma/Animator>
#include <KDE/Plasma/PaintUtils>
#include <KIconEffect>
#include <KIconLoader>
#include <QPainter>
namespace Aurorae
{
AuroraeFactory::AuroraeFactory()
: QObject()
, KDecorationFactoryUnstable()
{
init();
}
void AuroraeFactory::init()
{
KConfig conf("auroraerc");
KConfigGroup group(&conf, "Engine");
m_themeName = group.readEntry("ThemeName", "example-deco");
QString file("aurorae/themes/" + m_themeName + "/decoration.svg");
QString path = KGlobal::dirs()->findResource("data", file);
if (path.isEmpty()) {
file += 'z';
path = KGlobal::dirs()->findResource("data", file);
}
if (path.isEmpty()) {
kDebug(1216) << "Could not find decoration svg: aborting";
abort();
}
m_frame.setImagePath(path);
m_frame.setCacheAllRenderedFrames(true);
m_frame.setEnabledBorders(Plasma::FrameSvg::AllBorders);
// load the buttons
initButtonFrame("minimize");
initButtonFrame("maximize");
initButtonFrame("restore");
initButtonFrame("close");
initButtonFrame("alldesktops");
initButtonFrame("keepabove");
initButtonFrame("keepbelow");
initButtonFrame("shade");
initButtonFrame("help");
readThemeConfig();
}
void AuroraeFactory::readThemeConfig()
{
// read config values
KConfig conf("aurorae/themes/" + m_themeName + '/' + m_themeName + "rc", KConfig::FullConfig, "data");
m_themeConfig.load(&conf);
}
AuroraeFactory::~AuroraeFactory()
{
s_instance = NULL;
}
AuroraeFactory *AuroraeFactory::instance()
{
if (!s_instance) {
s_instance = new AuroraeFactory;
}
return s_instance;
}
bool AuroraeFactory::reset(unsigned long changed)
{
// re-read config
m_frame.clearCache();
m_buttons.clear();
init();
resetDecorations(changed);
return false; // need hard reset
}
bool AuroraeFactory::supports(Ability ability) const
{
switch (ability) {
case AbilityAnnounceButtons:
case AbilityUsesAlphaChannel:
case AbilityButtonMenu:
case AbilityButtonSpacer:
case AbilityExtendIntoClientArea:
return true;
case AbilityButtonMinimize:
return m_buttons.contains("minimize");
case AbilityButtonMaximize:
return m_buttons.contains("maximize") || m_buttons.contains("restore");
case AbilityButtonClose:
return m_buttons.contains("close");
case AbilityButtonAboveOthers:
return m_buttons.contains("keepabove");
case AbilityButtonBelowOthers:
return m_buttons.contains("keepbelow");
case AbilityButtonShade:
return m_buttons.contains("shade");
case AbilityButtonOnAllDesktops:
return m_buttons.contains("alldesktops");
case AbilityButtonHelp:
return m_buttons.contains("help");
case AbilityProvidesShadow:
return m_themeConfig.shadow();
default:
return false;
}
}
KDecoration *AuroraeFactory::createDecoration(KDecorationBridge *bridge)
{
AuroraeClient *client = new AuroraeClient(bridge, this);
return client->decoration();
}
void AuroraeFactory::initButtonFrame(const QString &button)
{
QString file("aurorae/themes/" + m_themeName + '/' + button + ".svg");
QString path = KGlobal::dirs()->findResource("data", file);
if (path.isEmpty()) {
// let's look for svgz
file.append("z");
path = KGlobal::dirs()->findResource("data", file);
}
if (!path.isEmpty()) {
Plasma::FrameSvg *frame = new Plasma::FrameSvg(this);
frame->setImagePath(path);
frame->setCacheAllRenderedFrames(true);
frame->setEnabledBorders(Plasma::FrameSvg::NoBorder);
m_buttons[ button ] = frame;
} else {
kDebug(1216) << "No button for: " << button;
}
}
Plasma::FrameSvg *AuroraeFactory::button(const QString &b)
{
if (hasButton(b)) {
return m_buttons[ b ];
} else {
return NULL;
}
}
QList< KDecorationDefines::BorderSize > AuroraeFactory::borderSizes() const
{
return QList< BorderSize >() << BorderTiny << BorderNormal <<
BorderLarge << BorderVeryLarge << BorderHuge <<
BorderVeryHuge << BorderOversized;
}
AuroraeFactory *AuroraeFactory::s_instance = NULL;
/*******************************************************
* Button
*******************************************************/
AuroraeButton::AuroraeButton(ButtonType type, KCommonDecoration *parent)
: KCommonDecorationButton(type, parent)
, m_animationId(0)
, m_animationProgress(0.0)
, m_pressed(false)
{
setAttribute(Qt::WA_NoSystemBackground);
connect(Plasma::Animator::self(), SIGNAL(customAnimationFinished(int)), this, SLOT(animationFinished(int)));
}
void AuroraeButton::reset(unsigned long changed)
{
Q_UNUSED(changed)
}
void AuroraeButton::enterEvent(QEvent *event)
{
Q_UNUSED(event)
if (m_animationId != 0) {
Plasma::Animator::self()->stopCustomAnimation(m_animationId);
}
m_animationProgress = 0.0;
int time = AuroraeFactory::instance()->themeConfig().animationTime();
if (time != 0) {
m_animationId = Plasma::Animator::self()->customAnimation(40 / (1000.0 / qreal(time)),
time, Plasma::Animator::EaseInCurve, this, "animationUpdate");
}
update();
}
void AuroraeButton::leaveEvent(QEvent *event)
{
Q_UNUSED(event)
if (m_animationId != 0) {
Plasma::Animator::self()->stopCustomAnimation(m_animationId);
}
m_animationProgress = 0.0;
int time = AuroraeFactory::instance()->themeConfig().animationTime();
if (time != 0) {
m_animationId = Plasma::Animator::self()->customAnimation(40 / (1000.0 / qreal(time)),
time, Plasma::Animator::EaseOutCurve, this, "animationUpdate");
}
update();
}
void AuroraeButton::mousePressEvent(QMouseEvent *e)
{
m_pressed = true;
update();
KCommonDecorationButton::mousePressEvent(e);
}
void AuroraeButton::mouseReleaseEvent(QMouseEvent *e)
{
m_pressed = false;
update();
KCommonDecorationButton::mouseReleaseEvent(e);
}
void AuroraeButton::animationUpdate(qreal progress, int id)
{
Q_UNUSED(id)
m_animationProgress = progress;
update();
}
void AuroraeButton::animationFinished(int id)
{
if (m_animationId == id) {
m_animationId = 0;
update();
}
}
void AuroraeButton::paintEvent(QPaintEvent *event)
{
Q_UNUSED(event)
if (decoration()->isPreview()) {
return;
}
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing);
bool active = decoration()->isActive();
if (type() == MenuButton) {
const QIcon icon = decoration()->icon();
ThemeConfig config = AuroraeFactory::instance()->themeConfig();
int iconSize = qMin(config.buttonWidthMenu(), config.buttonHeight());
const QSize size = icon.actualSize(QSize(iconSize, iconSize));
QPixmap iconPix = icon.pixmap(size);
KIconEffect *effect = KIconLoader::global()->iconEffect();
if (active) {
if (underMouse()) {
iconPix = effect->apply(iconPix, KIconLoader::Desktop, KIconLoader::ActiveState);
}
} else {
iconPix = effect->apply(iconPix, KIconLoader::Desktop, KIconLoader::DisabledState);
}
AuroraeClient *deco = dynamic_cast<AuroraeClient*>(decoration());
if (deco && deco->isAnimating()) {
// animation
QPixmap oldPix = icon.pixmap(size);
if (!active) {
if (underMouse()) {
oldPix = effect->apply(iconPix, KIconLoader::Desktop, KIconLoader::ActiveState);
}
} else {
oldPix = effect->apply(iconPix, KIconLoader::Desktop, KIconLoader::DisabledState);
}
iconPix = Plasma::PaintUtils::transition(oldPix, iconPix, deco->animationProgress());
}
painter.drawPixmap(0, 0, iconPix);
return;
}
ButtonStates states;
if (active) {
states |= Active;
}
if (underMouse()) {
states |= Hover;
}
if (m_pressed) {
states |= Pressed;
}
QString buttonName = "";
switch (type()) {
case MinButton:
if (!decoration()->isMinimizable()) {
states |= Deactivated;
}
buttonName = "minimize";
break;
case CloseButton:
if (!decoration()->isCloseable()) {
states |= Deactivated;
}
buttonName = "close";
break;
case MaxButton: {
if (!decoration()->isMaximizable()) {
states |= Deactivated;
}
buttonName = "maximize";
if (decoration()->maximizeMode() == KDecorationDefines::MaximizeFull &&
!decoration()->options()->moveResizeMaximizedWindows()) {
buttonName = "restore";
if (!AuroraeFactory::instance()->hasButton(buttonName)) {
buttonName = "maximize";
}
}
break;
}
case OnAllDesktopsButton:
if (decoration()->isOnAllDesktops()) {
states |= Hover;
}
buttonName = "alldesktops";
break;
case AboveButton:
buttonName = "keepabove";
break;
case BelowButton:
buttonName = "keepbelow";
break;
case ShadeButton:
if (!decoration()->isShadeable()) {
states |= Deactivated;
}
if (decoration()->isShade()) {
states |= Hover;
}
buttonName = "shade";
break;
case HelpButton:
buttonName = "help";
break;
default:
buttonName.clear();
}
if (!buttonName.isEmpty()) {
if (AuroraeFactory::instance()->hasButton(buttonName)) {
Plasma::FrameSvg *button = AuroraeFactory::instance()->button(buttonName);
paintButton(painter, button, states);
}
}
}
void AuroraeButton::paintButton(QPainter &painter, Plasma::FrameSvg *frame, ButtonStates states)
{
QString prefix = "active";
QString animationPrefix = "active";
bool hasInactive = false;
// check for inactive prefix
if (!states.testFlag(Active) && frame->hasElementPrefix("inactive")) {
// we have inactive, so we use it
hasInactive = true;
prefix = "inactive";
animationPrefix = "inactive";
}
if (states.testFlag(Hover)) {
if (states.testFlag(Active)) {
if (frame->hasElementPrefix("hover")) {
prefix = "hover";
}
} else {
if (hasInactive) {
if (frame->hasElementPrefix("hover-inactive")) {
prefix = "hover-inactive";
}
} else {
if (frame->hasElementPrefix("hover")) {
prefix = "hover";
}
}
}
}
if (states.testFlag(Pressed)) {
if (states.testFlag(Active)) {
if (frame->hasElementPrefix("pressed")) {
prefix = "pressed";
}
} else {
if (hasInactive) {
if (frame->hasElementPrefix("pressed-inactive")) {
prefix = "pressed-inactive";
}
} else {
if (frame->hasElementPrefix("pressed")) {
prefix = "pressed";
}
}
}
}
if (states.testFlag(Deactivated)) {
if (states.testFlag(Active)) {
if (frame->hasElementPrefix("deactivated")) {
prefix = "deactivated";
}
} else {
if (hasInactive) {
if (frame->hasElementPrefix("deactivated-inactive")) {
prefix = "deactivated-inactive";
}
} else {
if (frame->hasElementPrefix("deactivated")) {
prefix = "deactivated";
}
}
}
}
frame->setElementPrefix(prefix);
frame->resizeFrame(size());
if (m_animationId != 0) {
// there is an animation so we have to use it
// the animation is definately a hover animation as currently nothing else is supported
if (!states.testFlag(Hover)) {
// only have to set for not hover state as animationPrefix is set to (in)active by default
if (states.testFlag(Active)) {
if (frame->hasElementPrefix("hover")) {
animationPrefix = "hover";
}
} else {
if (hasInactive) {
if (frame->hasElementPrefix("hover-inactive")) {
animationPrefix = "hover-inactive";
}
} else {
if (frame->hasElementPrefix("hover")) {
animationPrefix = "hover";
}
}
}
}
QPixmap target = frame->framePixmap();
frame->setElementPrefix(animationPrefix);
frame->resizeFrame(size());
QPixmap result = Plasma::PaintUtils::transition(frame->framePixmap(),
target, m_animationProgress);
painter.drawPixmap(rect(), result);
} else {
bool animation = false;
AuroraeClient *deco = dynamic_cast<AuroraeClient*>(decoration());
if (deco && deco->isAnimating()) {
animationPrefix = prefix;
if (prefix.endsWith("-inactive")) {
animationPrefix.remove("-inactive");
} else {
animationPrefix = animationPrefix + "-inactive";
}
if (frame->hasElementPrefix(animationPrefix)) {
animation = true;
QPixmap target = frame->framePixmap();
frame->setElementPrefix(animationPrefix);
frame->resizeFrame(size());
QPixmap result = Plasma::PaintUtils::transition(frame->framePixmap(),
target, deco->animationProgress());
painter.drawPixmap(rect(), result);
}
}
if (!animation) {
frame->paintFrame(&painter);
}
}
}
/*******************************************************
* Client
*******************************************************/
AuroraeClient::AuroraeClient(KDecorationBridge *bridge, KDecorationFactory *factory)
: KCommonDecorationUnstable(bridge, factory)
{
connect(Plasma::Animator::self(), SIGNAL(customAnimationFinished(int)), this, SLOT(animationFinished(int)));
}
AuroraeClient::~AuroraeClient()
{
}
void AuroraeClient::init()
{
KCommonDecoration::init();
}
void AuroraeClient::reset(unsigned long changed)
{
if (changed & SettingCompositing) {
updateWindowShape();
}
widget()->update();
KCommonDecoration::reset(changed);
}
QString AuroraeClient::visibleName() const
{
return i18n("Aurorae Theme Engine");
}
QString AuroraeClient::defaultButtonsLeft() const
{
return AuroraeFactory::instance()->themeConfig().defaultButtonsLeft();
}
QString AuroraeClient::defaultButtonsRight() const
{
return AuroraeFactory::instance()->themeConfig().defaultButtonsRight();
}
bool AuroraeClient::decorationBehaviour(DecorationBehaviour behavior) const
{
switch (behavior) {
case DB_MenuClose:
return true; // Close on double click
case DB_WindowMask:
case DB_ButtonHide:
return false;
default:
return false;
}
}
int AuroraeClient::layoutMetric(LayoutMetric lm, bool respectWindowState,
const KCommonDecorationButton *button) const
{
bool maximized = maximizeMode() == MaximizeFull &&
!options()->moveResizeMaximizedWindows();
const ThemeConfig &conf = AuroraeFactory::instance()->themeConfig();
qreal left, top, right, bottom;
AuroraeFactory::instance()->frame()->getMargins(left, top, right, bottom);
int borderLeft, borderRight, borderBottom;;
switch (KDecoration::options()->preferredBorderSize(AuroraeFactory::instance())) {
case BorderTiny:
if (compositingActive()) {
borderLeft = qMin(0, (int)left - conf.borderLeft() - conf.paddingLeft());
borderRight = qMin(0, (int)right - conf.borderRight() - conf.paddingRight());
borderBottom = qMin(0, (int)bottom - conf.borderBottom() - conf.paddingBottom());
} else {
borderLeft = qMin(0, (int)left - conf.borderLeft());
borderRight = qMin(0, (int)right - conf.borderRight());
borderBottom = qMin(0, (int)bottom - conf.borderBottom());
}
break;
case BorderLarge:
borderLeft = borderRight = borderBottom = 4;
break;
case BorderVeryLarge:
borderLeft = borderRight = borderBottom = 8;
break;
case BorderHuge:
borderLeft = borderRight = borderBottom = 12;
break;
case BorderVeryHuge:
borderLeft = borderRight = borderBottom = 23;
break;
case BorderOversized:
borderLeft = borderRight = borderBottom = 36;
break;
case BorderNormal:
default:
borderLeft = borderRight = borderBottom = 0;
}
switch (lm) {
case LM_BorderLeft:
return maximized && respectWindowState ? 0 : conf.borderLeft() + borderLeft;
case LM_BorderRight:
return maximized && respectWindowState ? 0 : conf.borderRight() + borderRight;
case LM_BorderBottom:
return maximized && respectWindowState ? 0 : conf.borderBottom() + borderBottom;
case LM_OuterPaddingLeft:
return conf.paddingLeft();
case LM_OuterPaddingRight:
return conf.paddingRight();
case LM_OuterPaddingTop:
return conf.paddingTop();
case LM_OuterPaddingBottom:
return conf.paddingBottom();
case LM_TitleEdgeLeft:
return maximized && respectWindowState ? conf.titleEdgeLeftMaximized() : conf.titleEdgeLeft();
case LM_TitleEdgeRight:
return maximized && respectWindowState ? conf.titleEdgeRightMaximized() : conf.titleBorderRight();
case LM_TitleEdgeTop:
return maximized && respectWindowState ? conf.titleEdgeTopMaximized() : conf.titleEdgeTop();
case LM_TitleEdgeBottom:
return maximized && respectWindowState ? conf.titleEdgeBottomMaximized() : conf.titleEdgeBottom();
case LM_ButtonMarginTop:
return conf.buttonMarginTop();
case LM_TitleBorderLeft:
return conf.titleBorderLeft();
case LM_TitleBorderRight:
return conf.titleBorderRight();
case LM_TitleHeight:
return conf.titleHeight();
case LM_ButtonWidth:
switch (button->type()) {
case MinButton:
return conf.buttonWidthMinimize();
case MaxButton:
return conf.buttonWidthMaximizeRestore();
case CloseButton:
return conf.buttonWidthClose();
case OnAllDesktopsButton:
return conf.buttonWidthAllDesktops();
case AboveButton:
return conf.buttonWidthKeepAbove();
case BelowButton:
return conf.buttonWidthKeepBelow();
case ShadeButton:
return conf.buttonWidthShade();
case MenuButton:
return conf.buttonWidthMenu();
default:
return conf.buttonWidth();
}
case LM_ButtonHeight:
return conf.buttonHeight();
case LM_ButtonSpacing:
return conf.buttonSpacing();
case LM_ExplicitButtonSpacer:
return conf.explicitButtonSpacer();
default:
return KCommonDecoration::layoutMetric(lm, respectWindowState, button);
}
}
KCommonDecorationButton *AuroraeClient::createButton(ButtonType type)
{
AuroraeFactory *factory = AuroraeFactory::instance();
switch (type) {
case MenuButton:
return new AuroraeButton(type, this);
case MinButton:
if (factory->hasButton("minimize")) {
return new AuroraeButton(type, this);
} else {
return NULL;
}
case MaxButton:
if (factory->hasButton("maximize") || factory->hasButton("restore")) {
return new AuroraeButton(type, this);
} else {
return NULL;
}
case CloseButton:
if (factory->hasButton("close")) {
return new AuroraeButton(type, this);
} else {
return NULL;
}
case OnAllDesktopsButton:
if (factory->hasButton("alldesktops")) {
return new AuroraeButton(type, this);
} else {
return NULL;
}
case HelpButton:
if (factory->hasButton("help")) {
return new AuroraeButton(type, this);
} else {
return NULL;
}
case AboveButton:
if (factory->hasButton("keepabove")) {
return new AuroraeButton(type, this);
} else {
return NULL;
}
case BelowButton:
if (factory->hasButton("keepbelow")) {
return new AuroraeButton(type, this);
} else {
return NULL;
}
case ShadeButton:
if (factory->hasButton("shade")) {
return new AuroraeButton(type, this);
} else {
return NULL;
}
default:
return NULL;
}
}
void AuroraeClient::paintEvent(QPaintEvent *event)
{
Q_UNUSED(event);
if (isPreview()) {
return;
}
bool maximized = maximizeMode() == MaximizeFull &&
!options()->moveResizeMaximizedWindows();
QPainter painter(widget());
painter.setRenderHint(QPainter::Antialiasing);
painter.setCompositionMode(QPainter::CompositionMode_Source);
const ThemeConfig &conf = AuroraeFactory::instance()->themeConfig();
Plasma::FrameSvg *frame = AuroraeFactory::instance()->frame();
frame->setElementPrefix("decoration");
if (!isActive() && frame->hasElementPrefix("decoration-inactive")) {
frame->setElementPrefix("decoration-inactive");
}
if (!compositingActive() && frame->hasElementPrefix("decoration-opaque")) {
frame->setElementPrefix("decoration-opaque");
if (!isActive() && frame->hasElementPrefix("decoration-opaque-inactive")) {
frame->setElementPrefix("decoration-opaque-inactive");
}
}
// restrict painting on the decoration - no need to paint behind the window
int left, right, top, bottom;
decoration()->borders(left, right, top, bottom);
if (!compositingActive() || (compositingActive() && !transparentRect().isNull())) {
// only clip when compositing is not active and we don't extend into the client
painter.setClipping(true);
painter.setClipRect(0, 0,
left + conf.paddingLeft(),
height() + conf.paddingTop() + conf.paddingBottom(),
Qt::ReplaceClip);
painter.setClipRect(0, 0,
width() + conf.paddingLeft() + conf.paddingRight(),
top + conf.paddingTop(),
Qt::UniteClip);
painter.setClipRect(width() - right + conf.paddingLeft(), 0,
right + conf.paddingRight(),
height() + conf.paddingTop() + conf.paddingBottom(),
Qt::UniteClip);
painter.setClipRect(0, height() - bottom + conf.paddingTop(),
width() + conf.paddingLeft() + conf.paddingRight(),
bottom + conf.paddingBottom(),
Qt::UniteClip);
}
// top
if (maximized) {
frame->setEnabledBorders(Plasma::FrameSvg::NoBorder);
} else {
frame->setEnabledBorders(Plasma::FrameSvg::AllBorders);
}
QRectF rect = QRectF(0.0, 0.0, widget()->width(), widget()->height());
if (maximized) {
rect = QRectF(conf.paddingLeft(), conf.paddingTop(),
widget()->width() - conf.paddingRight(),
widget()->height() - conf.paddingBottom());
}
QRectF sourceRect = rect;
if (!compositingActive()) {
if (frame->hasElementPrefix("decoration-opaque")) {
rect = QRectF(conf.paddingLeft(), conf.paddingTop(),
widget()->width()-conf.paddingRight()-conf.paddingLeft(),
widget()->height()-conf.paddingBottom()-conf.paddingTop());
sourceRect = QRectF(0.0, 0.0, rect.width(), rect.height());
}
else {
rect = QRectF(conf.paddingLeft(), conf.paddingTop(), widget()->width(), widget()->height());
sourceRect = rect;
}
}
frame->resizeFrame(rect.size());
// animation
if (m_animationId != 0 && frame->hasElementPrefix("decoration-inactive")) {
QPixmap target = frame->framePixmap();
frame->setElementPrefix("decoration-inactive");
if (!isActive()) {
frame->setElementPrefix("decoration");
}
if (!compositingActive() && frame->hasElementPrefix("decoration-opaque-inactive")) {
frame->setElementPrefix("decoration-opaque-inactive");
if (!isActive()) {
frame->setElementPrefix("decoration-opaque");
}
}
frame->resizeFrame(rect.size());
QPixmap result = Plasma::PaintUtils::transition(frame->framePixmap(),
target, m_animationProgress);
painter.drawPixmap(rect.toRect(), result);
} else {
frame->paintFrame(&painter, rect, sourceRect);
}
painter.setCompositionMode(QPainter::CompositionMode_SourceOver);
if (m_animationId != 0) {
QPixmap result;
if (isActive()) {
result = Plasma::PaintUtils::transition(m_inactiveText, m_activeText, m_animationProgress);
} else {
result = Plasma::PaintUtils::transition(m_activeText, m_inactiveText, m_animationProgress);
}
painter.drawPixmap(titleRect(), result);
} else {
if (isActive()) {
painter.drawPixmap(titleRect(), m_activeText);
} else {
painter.drawPixmap(titleRect(), m_inactiveText);
}
}
}
void AuroraeClient::generateTextPixmap(QPixmap& pixmap, bool active)
{
QPainter painter(&pixmap);
pixmap.fill(Qt::transparent);
const ThemeConfig &conf = AuroraeFactory::instance()->themeConfig();
painter.setFont(options()->font(active));
if (conf.useTextShadow()) {
// shadow code is inspired by Qt FAQ: How can I draw shadows behind text?
// see http://www.qtsoftware.com/developer/faqs/faq.2007-07-27.3052836051
const ThemeConfig &conf = AuroraeFactory::instance()->themeConfig();
painter.save();
if (active) {
painter.setPen(conf.activeTextShadowColor());
}
else {
painter.setPen(conf.inactiveTextShadowColor());
}
int dx = conf.textShadowOffsetX();
int dy = conf.textShadowOffsetY();
painter.setOpacity(0.5);
painter.drawText(pixmap.rect().translated(dx, dy),
conf.alignment() | conf.verticalAlignment() | Qt::TextSingleLine,
caption());
painter.setOpacity(0.2);
painter.drawText(pixmap.rect().translated(dx+1, dy),
conf.alignment() | conf.verticalAlignment() | Qt::TextSingleLine,
caption());
painter.drawText(pixmap.rect().translated(dx-1, dy),
conf.alignment() | conf.verticalAlignment() | Qt::TextSingleLine,
caption());
painter.drawText(pixmap.rect().translated(dx, dy+1),
conf.alignment() | conf.verticalAlignment() | Qt::TextSingleLine,
caption());
painter.drawText(pixmap.rect().translated(dx, dy-1),
conf.alignment() | conf.verticalAlignment() | Qt::TextSingleLine,
caption());
painter.restore();
}
if (active) {
painter.setPen(conf.activeTextColor());
} else {
painter.setPen(conf.inactiveTextColor());
}
painter.drawText(pixmap.rect(), conf.alignment() | conf.verticalAlignment() | Qt::TextSingleLine,
caption());
painter.end();
}
void AuroraeClient::captionChange()
{
generateTextPixmap(m_activeText, true);
generateTextPixmap(m_inactiveText, false);
KCommonDecoration::captionChange();
}
void AuroraeClient::updateWindowShape()
{
bool maximized = maximizeMode()==KDecorationDefines::MaximizeFull && !options()->moveResizeMaximizedWindows();
int w=widget()->width();
int h=widget()->height();
if (maximized || compositingActive()) {
QRegion mask(0,0,w,h);
setMask(mask);
return;
}
const ThemeConfig &conf = AuroraeFactory::instance()->themeConfig();
Plasma::FrameSvg *deco = AuroraeFactory::instance()->frame();
if (!deco->hasElementPrefix("decoration-opaque")) {
// opaque element is missing: set generic mask
w = w - conf.paddingLeft() - conf.paddingRight();
h = h - conf.paddingTop() - conf.paddingBottom();
QRegion mask(conf.paddingLeft(),conf.paddingTop(),w,h);
setMask(mask);
return;
}
deco->setElementPrefix("decoration-opaque");
deco->resizeFrame(QSize(w-conf.paddingLeft()-conf.paddingRight(),
h-conf.paddingTop()-conf.paddingBottom()));
QRegion mask = deco->mask().translated(conf.paddingLeft(), conf.paddingTop());
setMask(mask);
}
void AuroraeClient::activeChange()
{
if (m_animationId != 0) {
Plasma::Animator::self()->stopCustomAnimation(m_animationId);
}
m_animationProgress = 0.0;
int time = AuroraeFactory::instance()->themeConfig().animationTime();
if (time != 0) {
m_animationId = Plasma::Animator::self()->customAnimation(40 / (1000.0 / qreal(time)),
time, Plasma::Animator::EaseInOutCurve, this, "animationUpdate");
}
KCommonDecoration::activeChange();
}
void AuroraeClient::animationUpdate(qreal progress, int id)
{
if (m_animationId == id) {
m_animationProgress = progress;
widget()->update();
}
}
void AuroraeClient::animationFinished(int id)
{
if (m_animationId == id) {
m_animationId = 0;
widget()->update();
}
}
void AuroraeClient::resize(const QSize& s)
{
KCommonDecoration::resize(s);
m_activeText = QPixmap(titleRect().size());
m_activeText.fill(Qt::transparent);
m_inactiveText = QPixmap(titleRect().size());
m_inactiveText.fill(Qt::transparent);
captionChange();
}
} // namespace Aurorae
extern "C"
{
KDE_EXPORT KDecorationFactory *create_factory() {
return Aurorae::AuroraeFactory::instance();
}
}
#include "aurorae.moc"