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