Warning, file /plasma/oxygen/kdecoration/oxygendecoration.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001 /* 0002 SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org> 0003 SPDX-FileCopyrightText: 2014 Hugo Pereira Da Costa <hugo.pereira@free.fr> 0004 SPDX-FileCopyrightText: 2015 David Edmundson <davidedmundson@kde.org> 0005 0006 SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL 0007 */ 0008 0009 #include "oxygendecoration.h" 0010 0011 #include "config-oxygen.h" 0012 #include "config/oxygenconfigwidget.h" 0013 #include "oxygensettingsprovider.h" 0014 #include "oxygenshadowcache.h" 0015 0016 #include "oxygenbutton.h" 0017 #include "oxygensizegrip.h" 0018 0019 #include <KDecoration2/DecorationButtonGroup> 0020 #include <KDecoration2/DecorationShadow> 0021 0022 #include <KColorUtils> 0023 #include <KConfigGroup> 0024 #include <KPluginFactory> 0025 #include <KSharedConfig> 0026 0027 #include <QPainter> 0028 #include <QTextStream> 0029 #include <QTimer> 0030 0031 #if OXYGEN_HAVE_X11 0032 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) 0033 #include <QX11Info> 0034 #else 0035 #include <private/qtx11extras_p.h> 0036 #endif 0037 #endif 0038 0039 K_PLUGIN_FACTORY_WITH_JSON(OxygenDecoFactory, "oxygen.json", registerPlugin<Oxygen::Decoration>(); registerPlugin<Oxygen::Button>(); 0040 registerPlugin<Oxygen::ConfigWidget>();) 0041 0042 namespace Oxygen 0043 { 0044 0045 using KDecoration2::ColorGroup; 0046 using KDecoration2::ColorRole; 0047 0048 //________________________________________________________________ 0049 using DecorationShadowPointer = QSharedPointer<KDecoration2::DecorationShadow>; 0050 using ShadowMap = QHash<int, DecorationShadowPointer>; 0051 0052 static int g_sDecoCount = 0; 0053 static ShadowMap g_sShadows; 0054 0055 Decoration::Decoration(QObject *parent, const QVariantList &args) 0056 : KDecoration2::Decoration(parent, args) 0057 , m_animation(new QPropertyAnimation(this)) 0058 { 0059 g_sDecoCount++; 0060 } 0061 0062 //________________________________________________________________ 0063 Decoration::~Decoration() 0064 { 0065 g_sDecoCount--; 0066 if (g_sDecoCount == 0) 0067 g_sShadows.clear(); 0068 0069 deleteSizeGrip(); 0070 } 0071 0072 //________________________________________________________________ 0073 void Decoration::setOpacity(qreal value) 0074 { 0075 if (m_opacity == value) 0076 return; 0077 m_opacity = value; 0078 updateShadow(); 0079 update(); 0080 0081 if (m_sizeGrip) 0082 m_sizeGrip->update(); 0083 } 0084 0085 //_________________________________________________________ 0086 QColor Decoration::titleBarColor(const QPalette &palette) const 0087 { 0088 if (m_animation->state() == QPropertyAnimation::Running) { 0089 return KColorUtils::mix(titleBarColor(palette, false), titleBarColor(palette, true), m_opacity); 0090 0091 } else { 0092 return titleBarColor(palette, client().toStrongRef()->isActive()); 0093 } 0094 } 0095 0096 //_________________________________________________________ 0097 QColor Decoration::titleBarColor(const QPalette &palette, bool active) const 0098 { 0099 if (m_internalSettings->useWindowColors()) { 0100 return palette.color(active ? QPalette::Active : QPalette::Inactive, QPalette::Window); 0101 0102 } else { 0103 return client().toStrongRef()->color(active ? ColorGroup::Active : ColorGroup::Inactive, ColorRole::TitleBar); 0104 } 0105 } 0106 0107 //_________________________________________________________ 0108 QColor Decoration::fontColor(const QPalette &palette) const 0109 { 0110 if (hideTitleBar()) 0111 return fontColor(palette, false); 0112 if (m_animation->state() == QPropertyAnimation::Running) { 0113 return KColorUtils::mix(fontColor(palette, false), fontColor(palette, true), m_opacity); 0114 0115 } else { 0116 return fontColor(palette, client().toStrongRef()->isActive()); 0117 } 0118 } 0119 0120 //_________________________________________________________ 0121 QColor Decoration::fontColor(const QPalette &palette, bool active) const 0122 { 0123 if (m_internalSettings->useWindowColors()) { 0124 return palette.color(active ? QPalette::Active : QPalette::Disabled, QPalette::WindowText); 0125 0126 } else { 0127 return client().toStrongRef()->color(active ? ColorGroup::Active : ColorGroup::Inactive, ColorRole::Foreground); 0128 } 0129 } 0130 0131 //_________________________________________________________ 0132 QColor Decoration::contrastColor(const QPalette &palette) const 0133 { 0134 if (m_internalSettings->useWindowColors()) 0135 return contrastColor(palette.color(QPalette::Window)); 0136 else { 0137 const auto cl = client().toStrongRef(); 0138 return contrastColor(cl->color(cl->isActive() ? ColorGroup::Active : ColorGroup::Inactive, ColorRole::TitleBar)); 0139 } 0140 } 0141 0142 //_________________________________________________________ 0143 QColor Decoration::contrastColor(const QColor &color) const 0144 { 0145 return SettingsProvider::self()->helper()->calcLightColor(color); 0146 } 0147 0148 //________________________________________________________________ 0149 void Decoration::init() 0150 { 0151 // active state change animation 0152 m_animation->setStartValue(0); 0153 m_animation->setEndValue(1.0); 0154 m_animation->setTargetObject(this); 0155 m_animation->setPropertyName("opacity"); 0156 m_animation->setEasingCurve(QEasingCurve::InOutQuad); 0157 0158 reconfigure(); 0159 updateTitleBar(); 0160 auto s = settings(); 0161 connect(s.data(), &KDecoration2::DecorationSettings::borderSizeChanged, this, &Decoration::recalculateBorders); 0162 0163 // a change in font might cause the borders to change 0164 connect(s.data(), &KDecoration2::DecorationSettings::fontChanged, this, &Decoration::recalculateBorders); 0165 connect(s.data(), &KDecoration2::DecorationSettings::spacingChanged, this, &Decoration::recalculateBorders); 0166 0167 // buttons 0168 connect(s.data(), &KDecoration2::DecorationSettings::spacingChanged, this, &Decoration::updateButtonsGeometryDelayed); 0169 connect(s.data(), &KDecoration2::DecorationSettings::decorationButtonsLeftChanged, this, &Decoration::updateButtonsGeometryDelayed); 0170 connect(s.data(), &KDecoration2::DecorationSettings::decorationButtonsRightChanged, this, &Decoration::updateButtonsGeometryDelayed); 0171 0172 // full reconfiguration 0173 connect(s.data(), &KDecoration2::DecorationSettings::reconfigured, this, &Decoration::reconfigure); 0174 connect(s.data(), &KDecoration2::DecorationSettings::reconfigured, SettingsProvider::self(), &SettingsProvider::reconfigure, Qt::UniqueConnection); 0175 0176 const auto *cl = client().toStrongRef().data(); 0177 connect(cl, &KDecoration2::DecoratedClient::adjacentScreenEdgesChanged, this, &Decoration::recalculateBorders); 0178 connect(cl, &KDecoration2::DecoratedClient::maximizedHorizontallyChanged, this, &Decoration::recalculateBorders); 0179 connect(cl, &KDecoration2::DecoratedClient::maximizedVerticallyChanged, this, &Decoration::recalculateBorders); 0180 connect(cl, &KDecoration2::DecoratedClient::captionChanged, this, [this]() { 0181 // update the caption area 0182 update(titleBar()); 0183 }); 0184 0185 connect(cl, &KDecoration2::DecoratedClient::activeChanged, this, &Decoration::updateAnimationState); 0186 connect(cl, &KDecoration2::DecoratedClient::activeChanged, this, &Decoration::updateShadow); 0187 0188 // decoration has an overloaded update function, force the compiler to choose the right one 0189 connect(cl, &KDecoration2::DecoratedClient::paletteChanged, this, static_cast<void (Decoration::*)()>(&Decoration::update)); 0190 connect(cl, &KDecoration2::DecoratedClient::widthChanged, this, &Decoration::updateTitleBar); 0191 connect(cl, &KDecoration2::DecoratedClient::maximizedChanged, this, &Decoration::updateTitleBar); 0192 connect(cl, &KDecoration2::DecoratedClient::maximizedChanged, this, &Decoration::setOpaque); 0193 0194 connect(cl, &KDecoration2::DecoratedClient::widthChanged, this, &Decoration::updateButtonsGeometry); 0195 connect(cl, &KDecoration2::DecoratedClient::maximizedChanged, this, &Decoration::updateButtonsGeometry); 0196 connect(cl, &KDecoration2::DecoratedClient::shadedChanged, this, &Decoration::recalculateBorders); 0197 connect(cl, &KDecoration2::DecoratedClient::shadedChanged, this, &Decoration::updateButtonsGeometry); 0198 0199 createButtons(); 0200 updateShadow(); 0201 } 0202 0203 //________________________________________________________________ 0204 void Decoration::updateTitleBar() 0205 { 0206 auto s = settings(); 0207 const bool maximized = isMaximized(); 0208 const auto clientPtr = client().toStrongRef(); 0209 const int width = maximized ? clientPtr->width() : clientPtr->width() - 2 * s->largeSpacing() * Metrics::TitleBar_SideMargin; 0210 const int height = maximized ? borderTop() : borderTop() - s->smallSpacing() * Metrics::TitleBar_TopMargin; 0211 const int x = maximized ? 0 : s->largeSpacing() * Metrics::TitleBar_SideMargin; 0212 const int y = maximized ? 0 : s->smallSpacing() * Metrics::TitleBar_TopMargin; 0213 setTitleBar(QRect(x, y, width, height)); 0214 } 0215 0216 //________________________________________________________________ 0217 void Decoration::updateAnimationState() 0218 { 0219 if (m_internalSettings->animationsEnabled()) { 0220 m_animation->setDirection(client().toStrongRef()->isActive() ? QPropertyAnimation::Forward : QPropertyAnimation::Backward); 0221 if (m_animation->state() != QPropertyAnimation::Running) 0222 m_animation->start(); 0223 0224 } else { 0225 update(); 0226 } 0227 } 0228 0229 //________________________________________________________________ 0230 void Decoration::updateSizeGripVisibility() 0231 { 0232 const auto c = client().toStrongRef(); 0233 if (m_sizeGrip) { 0234 m_sizeGrip->setVisible(c->isResizeable() && !isMaximized() && !c->isShaded()); 0235 } 0236 } 0237 0238 //________________________________________________________________ 0239 int Decoration::borderSize(bool bottom) const 0240 { 0241 const int baseSize = settings()->smallSpacing(); 0242 if (m_internalSettings && (m_internalSettings->mask() & BorderSize)) { 0243 switch (m_internalSettings->borderSize()) { 0244 case InternalSettings::BorderNone: 0245 return 0; 0246 case InternalSettings::BorderNoSides: 0247 return bottom ? qMax(4, baseSize) : 0; 0248 default: 0249 case InternalSettings::BorderTiny: 0250 return bottom ? qMax(4, baseSize) : baseSize; 0251 case InternalSettings::BorderNormal: 0252 return baseSize * 2; 0253 case InternalSettings::BorderLarge: 0254 return baseSize * 3; 0255 case InternalSettings::BorderVeryLarge: 0256 return baseSize * 4; 0257 case InternalSettings::BorderHuge: 0258 return baseSize * 5; 0259 case InternalSettings::BorderVeryHuge: 0260 return baseSize * 6; 0261 case InternalSettings::BorderOversized: 0262 return baseSize * 10; 0263 } 0264 0265 } else { 0266 switch (settings()->borderSize()) { 0267 case KDecoration2::BorderSize::None: 0268 return 0; 0269 case KDecoration2::BorderSize::NoSides: 0270 return bottom ? qMax(4, baseSize) : 0; 0271 default: 0272 case KDecoration2::BorderSize::Tiny: 0273 return bottom ? qMax(4, baseSize) : baseSize; 0274 case KDecoration2::BorderSize::Normal: 0275 return baseSize * 2; 0276 case KDecoration2::BorderSize::Large: 0277 return baseSize * 3; 0278 case KDecoration2::BorderSize::VeryLarge: 0279 return baseSize * 4; 0280 case KDecoration2::BorderSize::Huge: 0281 return baseSize * 5; 0282 case KDecoration2::BorderSize::VeryHuge: 0283 return baseSize * 6; 0284 case KDecoration2::BorderSize::Oversized: 0285 return baseSize * 10; 0286 } 0287 } 0288 } 0289 0290 //________________________________________________________________ 0291 void Decoration::reconfigure() 0292 { 0293 m_internalSettings = SettingsProvider::self()->internalSettings(this); 0294 0295 // animation 0296 m_animation->setDuration(m_internalSettings->shadowAnimationsDuration()); 0297 0298 // borders 0299 recalculateBorders(); 0300 0301 // clear shadows 0302 g_sShadows.clear(); 0303 0304 // size grip 0305 if (hasNoBorders() && m_internalSettings->drawSizeGrip()) 0306 createSizeGrip(); 0307 else 0308 deleteSizeGrip(); 0309 } 0310 0311 //________________________________________________________________ 0312 void Decoration::recalculateBorders() 0313 { 0314 auto s = settings(); 0315 const auto c = client().toStrongRef(); 0316 const auto edges = c->adjacentScreenEdges(); 0317 0318 // left, right and bottom borders 0319 auto testFlag = [&](Qt::Edge edge) { 0320 return edges.testFlag(edge) && !m_internalSettings->drawBorderOnMaximizedWindows(); 0321 }; 0322 const int left = isMaximizedHorizontally() || testFlag(Qt::LeftEdge) ? 0 : borderSize(); 0323 const int right = isMaximizedHorizontally() || testFlag(Qt::RightEdge) ? 0 : borderSize(); 0324 const int bottom = isMaximizedVertically() || c->isShaded() || testFlag(Qt::BottomEdge) ? 0 : borderSize(true); 0325 0326 int top = 0; 0327 if (hideTitleBar()) 0328 top = bottom; 0329 else { 0330 QFontMetrics fm(s->font()); 0331 top += qMax(fm.height(), buttonHeight()); 0332 0333 // padding below 0334 const int baseSize = s->smallSpacing(); 0335 top += baseSize * Metrics::TitleBar_BottomMargin; 0336 0337 // padding above 0338 top += baseSize * TitleBar_TopMargin; 0339 } 0340 0341 setBorders(QMargins(left, top, right, bottom)); 0342 0343 // extended sizes 0344 const int extSize = s->largeSpacing(); 0345 int extSides = 0; 0346 int extBottom = 0; 0347 if (hasNoBorders()) { 0348 if (!isMaximizedHorizontally()) 0349 extSides = extSize; 0350 if (!isMaximizedVertically()) 0351 extBottom = extSize; 0352 0353 } else if (hasNoSideBorders() && !isMaximizedHorizontally()) { 0354 extSides = extSize; 0355 } 0356 0357 setResizeOnlyBorders(QMargins(extSides, 0, extSides, extBottom)); 0358 } 0359 0360 //________________________________________________________________ 0361 void Decoration::createButtons() 0362 { 0363 m_leftButtons = new KDecoration2::DecorationButtonGroup(KDecoration2::DecorationButtonGroup::Position::Left, this, &Button::create); 0364 m_rightButtons = new KDecoration2::DecorationButtonGroup(KDecoration2::DecorationButtonGroup::Position::Right, this, &Button::create); 0365 updateButtonsGeometry(); 0366 } 0367 0368 //________________________________________________________________ 0369 void Decoration::updateButtonsGeometryDelayed() 0370 { 0371 QTimer::singleShot(0, this, &Decoration::updateButtonsGeometry); 0372 } 0373 0374 //________________________________________________________________ 0375 void Decoration::updateButtonsGeometry() 0376 { 0377 auto s = settings(); 0378 0379 // adjust button position 0380 const int bHeight = captionHeight() + (isMaximized() ? s->smallSpacing() * Metrics::TitleBar_TopMargin : 0); 0381 const int bWidth = buttonHeight(); 0382 const int verticalOffset = (isMaximized() ? s->smallSpacing() * Metrics::TitleBar_TopMargin : 0) + (captionHeight() - buttonHeight()) / 2; 0383 0384 const QVector<QPointer<KDecoration2::DecorationButton>> leftButtons = m_leftButtons->buttons(); 0385 const QVector<QPointer<KDecoration2::DecorationButton>> rightButtons = m_rightButtons->buttons(); 0386 0387 const auto allButtons = leftButtons + rightButtons; 0388 for (const auto &button : allButtons) { 0389 button.data()->setGeometry(QRectF(QPoint(0, 0), QSizeF(bWidth, bHeight))); 0390 static_cast<Button *>(button.data())->setOffset(QPointF(0, verticalOffset)); 0391 static_cast<Button *>(button.data())->setIconSize(QSize(bWidth, bWidth)); 0392 } 0393 0394 // left buttons 0395 if (!leftButtons.isEmpty()) { 0396 // spacing 0397 m_leftButtons->setSpacing(s->smallSpacing() * Metrics::TitleBar_ButtonSpacing); 0398 0399 // padding 0400 const int vPadding = isMaximized() ? 0 : s->smallSpacing() * Metrics::TitleBar_TopMargin; 0401 const int hPadding = s->smallSpacing() * Metrics::TitleBar_SideMargin; 0402 if (isMaximizedHorizontally()) { 0403 // add offsets on the side buttons, to preserve padding, but satisfy Fitts law 0404 auto button = static_cast<Button *>(leftButtons.front().data()); 0405 button->setGeometry(QRectF(QPoint(0, 0), QSizeF(bWidth + hPadding, bHeight))); 0406 button->setFlag(Button::FlagFirstInList); 0407 button->setHorizontalOffset(hPadding); 0408 0409 m_leftButtons->setPos(QPointF(0, vPadding)); 0410 0411 } else 0412 m_leftButtons->setPos(QPointF(hPadding + borderLeft(), vPadding)); 0413 } 0414 0415 // right buttons 0416 if (!rightButtons.isEmpty()) { 0417 // spacing 0418 m_rightButtons->setSpacing(s->smallSpacing() * Metrics::TitleBar_ButtonSpacing); 0419 0420 // padding 0421 const int vPadding = isMaximized() ? 0 : s->smallSpacing() * Metrics::TitleBar_TopMargin; 0422 const int hPadding = s->smallSpacing() * Metrics::TitleBar_SideMargin; 0423 if (isMaximizedHorizontally()) { 0424 auto button = static_cast<Button *>(rightButtons.back().data()); 0425 button->setGeometry(QRectF(QPoint(0, 0), QSizeF(bWidth + hPadding, bHeight))); 0426 button->setFlag(Button::FlagLastInList); 0427 0428 m_rightButtons->setPos(QPointF(size().width() - m_rightButtons->geometry().width(), vPadding)); 0429 0430 } else 0431 m_rightButtons->setPos(QPointF(size().width() - m_rightButtons->geometry().width() - hPadding - borderRight(), vPadding)); 0432 } 0433 0434 update(); 0435 } 0436 0437 //________________________________________________________________ 0438 void Decoration::paint(QPainter *painter, const QRect &repaintRegion) 0439 { 0440 const auto c = client().toStrongRef(); 0441 const auto palette = c->palette(); 0442 0443 const auto rect = c->isShaded() ? QRect(QPoint(0, 0), QSize(size().width(), borderTop())) : this->rect(); 0444 renderWindowBorder(painter, rect, palette); 0445 if (!isMaximized()) 0446 renderCorners(painter, rect, palette); 0447 0448 if (!hideTitleBar()) { 0449 m_leftButtons->paint(painter, repaintRegion); 0450 m_rightButtons->paint(painter, repaintRegion); 0451 0452 renderTitleText(painter, palette); 0453 } 0454 } 0455 0456 //________________________________________________________________ 0457 int Decoration::buttonHeight() const 0458 { 0459 const int baseSize = settings()->gridUnit() + 2; // oxygen icons were always slightly larger 0460 switch (m_internalSettings->buttonSize()) { 0461 case InternalSettings::ButtonSmall: 0462 return baseSize * 1.5; 0463 default: 0464 case InternalSettings::ButtonDefault: 0465 return baseSize * 2; 0466 case InternalSettings::ButtonLarge: 0467 return baseSize * 2.5; 0468 case InternalSettings::ButtonVeryLarge: 0469 return baseSize * 3.5; 0470 } 0471 } 0472 0473 //________________________________________________________________ 0474 int Decoration::captionHeight() const 0475 { 0476 return hideTitleBar() ? borderTop() : borderTop() - settings()->smallSpacing() * (Metrics::TitleBar_BottomMargin + Metrics::TitleBar_TopMargin); 0477 } 0478 0479 //________________________________________________________________ 0480 QPair<QRect, Qt::Alignment> Decoration::captionRect() const 0481 { 0482 if (hideTitleBar()) 0483 return qMakePair(QRect(), Qt::AlignCenter); 0484 else { 0485 const int leftOffset = m_leftButtons->buttons().isEmpty() 0486 ? Metrics::TitleBar_SideMargin * settings()->smallSpacing() 0487 : m_leftButtons->geometry().x() + m_leftButtons->geometry().width() + Metrics::TitleBar_SideMargin * settings()->smallSpacing(); 0488 0489 const int rightOffset = m_rightButtons->buttons().isEmpty() 0490 ? Metrics::TitleBar_SideMargin * settings()->smallSpacing() 0491 : size().width() - m_rightButtons->geometry().x() + Metrics::TitleBar_SideMargin * settings()->smallSpacing(); 0492 0493 const int yOffset = settings()->smallSpacing() * Metrics::TitleBar_TopMargin; 0494 const QRect maxRect(leftOffset, yOffset, size().width() - leftOffset - rightOffset, captionHeight()); 0495 0496 switch (m_internalSettings->titleAlignment()) { 0497 case InternalSettings::AlignLeft: 0498 return qMakePair(maxRect, Qt::AlignVCenter | Qt::AlignLeft); 0499 0500 case InternalSettings::AlignRight: 0501 return qMakePair(maxRect, Qt::AlignVCenter | Qt::AlignRight); 0502 0503 case InternalSettings::AlignCenter: 0504 return qMakePair(maxRect, Qt::AlignCenter); 0505 0506 default: 0507 case InternalSettings::AlignCenterFullWidth: { 0508 // full caption rect 0509 const QRect fullRect = QRect(0, yOffset, size().width(), captionHeight()); 0510 QRect boundingRect(settings()->fontMetrics().boundingRect(client().toStrongRef()->caption()).toRect()); 0511 0512 // text bounding rect 0513 boundingRect.setTop(yOffset); 0514 boundingRect.setHeight(captionHeight()); 0515 boundingRect.moveLeft((size().width() - boundingRect.width()) / 2); 0516 0517 if (boundingRect.left() < leftOffset) 0518 return qMakePair(maxRect, Qt::AlignVCenter | Qt::AlignLeft); 0519 else if (boundingRect.right() > size().width() - rightOffset) 0520 return qMakePair(maxRect, Qt::AlignVCenter | Qt::AlignRight); 0521 else 0522 return qMakePair(fullRect, Qt::AlignCenter); 0523 } 0524 } 0525 } 0526 } 0527 0528 //________________________________________________________________ 0529 void Decoration::updateShadow() 0530 { 0531 // do nothing if palettes are disabled 0532 if (!(SettingsProvider::self()->shadowCache()->isEnabled(QPalette::Active) || SettingsProvider::self()->shadowCache()->isEnabled(QPalette::Inactive))) { 0533 return; 0534 } 0535 0536 // see if shadow should be animated 0537 const bool animated(m_animation->state() == QPropertyAnimation::Running && SettingsProvider::self()->shadowCache()->isEnabled(QPalette::Active) 0538 && SettingsProvider::self()->shadowCache()->isEnabled(QPalette::Inactive)); 0539 0540 // generate key 0541 ShadowCache::Key key; 0542 const auto clientPtr = client().toStrongRef(); 0543 key.active = SettingsProvider::self()->shadowCache()->isEnabled(QPalette::Active) && clientPtr->isActive(); 0544 key.isShade = clientPtr->isShaded(); 0545 key.hasBorder = !hasNoBorders(); 0546 0547 if (animated) { 0548 static const int maxIndex = 255; 0549 key.index = m_opacity * maxIndex; 0550 } 0551 0552 const int hash(key.hash()); 0553 0554 // find key in map 0555 auto iter = g_sShadows.find(hash); 0556 if (iter == g_sShadows.end()) { 0557 auto decorationShadow = DecorationShadowPointer::create(); 0558 QPixmap shadowPixmap = 0559 animated ? SettingsProvider::self()->shadowCache()->animatedPixmap(key, m_opacity) : SettingsProvider::self()->shadowCache()->pixmap(key); 0560 0561 const int shadowSize(shadowPixmap.width() / 2); 0562 const int overlap = 4; 0563 decorationShadow->setPadding(QMargins(shadowSize - overlap, shadowSize - overlap, shadowSize - overlap, shadowSize - overlap)); 0564 decorationShadow->setInnerShadowRect(QRect(shadowSize, shadowSize, 1, 1)); 0565 decorationShadow->setShadow(shadowPixmap.toImage()); 0566 0567 iter = g_sShadows.insert(hash, decorationShadow); 0568 } 0569 0570 setShadow(iter.value()); 0571 } 0572 0573 //_________________________________________________________ 0574 void Decoration::renderCorners(QPainter *painter, const QRect &frame, const QPalette &palette) const 0575 { 0576 const QColor color(titleBarColor(palette)); 0577 0578 QLinearGradient lg = QLinearGradient(0, -0.5, 0, qreal(frame.height()) + 0.5); 0579 lg.setColorAt(0.0, SettingsProvider::self()->helper()->calcLightColor(SettingsProvider::self()->helper()->backgroundTopColor(color))); 0580 lg.setColorAt(0.51, SettingsProvider::self()->helper()->backgroundBottomColor(color)); 0581 lg.setColorAt(1.0, SettingsProvider::self()->helper()->backgroundBottomColor(color)); 0582 0583 painter->setPen(QPen(lg, 1)); 0584 painter->setBrush(Qt::NoBrush); 0585 painter->drawRoundedRect(QRectF(frame).adjusted(0.5, 0.5, -0.5, -0.5), 3.5, 3.5); 0586 } 0587 0588 //_________________________________________________________ 0589 void Decoration::renderWindowBackground(QPainter *painter, const QRect &clipRect, const QPalette &palette) const 0590 { 0591 const auto c = client().toStrongRef(); 0592 auto innerClientRect = c->isShaded() ? QRect(QPoint(0, 0), QSize(size().width(), borderTop())) : rect(); 0593 0594 // size of window minus the outlines for the rounded corners 0595 if (settings()->isAlphaChannelSupported() && !isMaximized()) { 0596 innerClientRect.adjust(1, 1, -1, -1); 0597 } 0598 0599 if (SettingsProvider::self()->helper()->hasBackgroundGradient(c->windowId())) { 0600 SettingsProvider::self()->helper()->renderWindowBackground(painter, clipRect, innerClientRect, titleBarColor(palette), borderTop() - 24); 0601 0602 } else { 0603 painter->fillRect(innerClientRect, titleBarColor(palette)); 0604 } 0605 } 0606 0607 //_________________________________________________________ 0608 void Decoration::renderWindowBorder(QPainter *painter, const QRect &clipRect, const QPalette &palette) const 0609 { 0610 // save painter 0611 if (clipRect.isValid()) { 0612 painter->save(); 0613 painter->setClipRegion(clipRect, Qt::IntersectClip); 0614 } 0615 0616 // title height 0617 renderWindowBackground(painter, clipRect, palette); 0618 0619 // restore painter 0620 if (clipRect.isValid()) { 0621 painter->restore(); 0622 } 0623 } 0624 0625 //_________________________________________________________ 0626 void Decoration::renderTitleText(QPainter *painter, const QPalette &palette) const 0627 { 0628 // setup font 0629 painter->setFont(settings()->font()); 0630 0631 // caption rect 0632 const auto cR = captionRect(); 0633 0634 // copy caption 0635 const QString caption = painter->fontMetrics().elidedText(client().toStrongRef()->caption(), Qt::ElideMiddle, cR.first.width()); 0636 0637 const auto contrast(contrastColor(palette)); 0638 if (contrast.isValid()) { 0639 painter->setPen(contrast); 0640 painter->translate(0, 1); 0641 painter->drawText(cR.first, cR.second | Qt::TextSingleLine, caption); 0642 painter->translate(0, -1); 0643 } 0644 0645 const auto color(fontColor(palette)); 0646 painter->setPen(color); 0647 painter->drawText(cR.first, cR.second | Qt::TextSingleLine, caption); 0648 } 0649 0650 //_________________________________________________________________ 0651 void Decoration::createSizeGrip(void) 0652 { 0653 // do nothing if size grip already exist 0654 if (m_sizeGrip) 0655 return; 0656 0657 #if OXYGEN_HAVE_X11 0658 if (!QX11Info::isPlatformX11()) 0659 return; 0660 0661 // access client 0662 const auto clientPtr = client().toStrongRef(); 0663 if (!clientPtr) 0664 return; 0665 0666 if (clientPtr->windowId() != 0) { 0667 m_sizeGrip = new SizeGrip(this); 0668 const auto *clientP = clientPtr.data(); 0669 connect(clientP, &KDecoration2::DecoratedClient::maximizedChanged, this, &Decoration::updateSizeGripVisibility); 0670 connect(clientP, &KDecoration2::DecoratedClient::shadedChanged, this, &Decoration::updateSizeGripVisibility); 0671 connect(clientP, &KDecoration2::DecoratedClient::resizeableChanged, this, &Decoration::updateSizeGripVisibility); 0672 } 0673 #endif 0674 } 0675 0676 //_________________________________________________________________ 0677 void Decoration::deleteSizeGrip(void) 0678 { 0679 if (m_sizeGrip) { 0680 m_sizeGrip->deleteLater(); 0681 m_sizeGrip = nullptr; 0682 } 0683 } 0684 0685 } // namespace 0686 0687 #include "oxygendecoration.moc"