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