Changeset View
Changeset View
Standalone View
Standalone View
kdecoration/breezedecoration.cpp
Show All 23 Lines | |||||
24 | #include "breeze.h" | 24 | #include "breeze.h" | ||
25 | #include "breezesettingsprovider.h" | 25 | #include "breezesettingsprovider.h" | ||
26 | #include "config-breeze.h" | 26 | #include "config-breeze.h" | ||
27 | #include "config/breezeconfigwidget.h" | 27 | #include "config/breezeconfigwidget.h" | ||
28 | 28 | | |||
29 | #include "breezebutton.h" | 29 | #include "breezebutton.h" | ||
30 | #include "breezesizegrip.h" | 30 | #include "breezesizegrip.h" | ||
31 | 31 | | |||
32 | #include "breezeboxshadowhelper.h" | ||||
33 | | ||||
32 | #include <KDecoration2/DecoratedClient> | 34 | #include <KDecoration2/DecoratedClient> | ||
33 | #include <KDecoration2/DecorationButtonGroup> | 35 | #include <KDecoration2/DecorationButtonGroup> | ||
34 | #include <KDecoration2/DecorationSettings> | 36 | #include <KDecoration2/DecorationSettings> | ||
35 | #include <KDecoration2/DecorationShadow> | 37 | #include <KDecoration2/DecorationShadow> | ||
36 | 38 | | |||
37 | #include <KConfigGroup> | 39 | #include <KConfigGroup> | ||
38 | #include <KColorUtils> | 40 | #include <KColorUtils> | ||
39 | #include <KSharedConfig> | 41 | #include <KSharedConfig> | ||
40 | #include <KPluginFactory> | 42 | #include <KPluginFactory> | ||
41 | 43 | | |||
44 | #include <QGuiApplication> | ||||
42 | #include <QPainter> | 45 | #include <QPainter> | ||
46 | #include <QScreen> | ||||
43 | #include <QTextStream> | 47 | #include <QTextStream> | ||
44 | #include <QTimer> | 48 | #include <QTimer> | ||
45 | 49 | | |||
46 | #if BREEZE_HAVE_X11 | 50 | #if BREEZE_HAVE_X11 | ||
47 | #include <QX11Info> | 51 | #include <QX11Info> | ||
48 | #endif | 52 | #endif | ||
49 | 53 | | |||
50 | #include <cmath> | 54 | #include <cmath> | ||
51 | 55 | | |||
52 | K_PLUGIN_FACTORY_WITH_JSON( | 56 | K_PLUGIN_FACTORY_WITH_JSON( | ||
53 | BreezeDecoFactory, | 57 | BreezeDecoFactory, | ||
54 | "breeze.json", | 58 | "breeze.json", | ||
55 | registerPlugin<Breeze::Decoration>(); | 59 | registerPlugin<Breeze::Decoration>(); | ||
56 | registerPlugin<Breeze::Button>(QStringLiteral("button")); | 60 | registerPlugin<Breeze::Button>(QStringLiteral("button")); | ||
57 | registerPlugin<Breeze::ConfigWidget>(QStringLiteral("kcmodule")); | 61 | registerPlugin<Breeze::ConfigWidget>(QStringLiteral("kcmodule")); | ||
58 | ) | 62 | ) | ||
59 | 63 | | |||
64 | namespace | ||||
65 | { | ||||
66 | struct ShadowParam { | ||||
67 | // Offset relative to decoration. | ||||
68 | QPoint offset; | ||||
69 | | ||||
70 | struct { | ||||
71 | // Offset relative to a box. | ||||
72 | QPoint offset; | ||||
73 | | ||||
74 | // Blur radius. | ||||
75 | int radius; | ||||
76 | | ||||
77 | // Shadow opacity(1 is opaque, 0 is transparent). | ||||
78 | qreal opacity; | ||||
79 | } shadow1 | ||||
80 | , shadow2; | ||||
81 | | ||||
82 | bool isNone() const { | ||||
83 | return qMax(shadow1.radius, shadow2.radius) == 0; | ||||
84 | } | ||||
85 | }; | ||||
86 | | ||||
87 | // TODO: adjust existing params. | ||||
88 | const ShadowParam s_shadowParams[] = { | ||||
89 | { | ||||
90 | // None | ||||
91 | .offset = QPoint(0, 0), | ||||
92 | .shadow1 = { | ||||
93 | .offset = QPoint(0, 0), | ||||
94 | .radius = 0, | ||||
95 | .opacity = 0 | ||||
96 | }, | ||||
97 | .shadow2 = { | ||||
98 | .offset = QPoint(0, 0), | ||||
99 | .radius = 0, | ||||
100 | .opacity = 0 | ||||
101 | } | ||||
102 | }, | ||||
103 | { | ||||
104 | // Small | ||||
105 | .offset = QPoint(0, 6), | ||||
106 | .shadow1 = { | ||||
107 | .offset = QPoint(0, 0), | ||||
108 | .radius = 16, | ||||
109 | .opacity = 1.0 | ||||
110 | }, | ||||
111 | .shadow2 = { | ||||
112 | .offset = QPoint(0, 0), | ||||
113 | .radius = 4, | ||||
114 | .opacity = 0.1 | ||||
115 | } | ||||
116 | }, | ||||
117 | { | ||||
118 | // Medium | ||||
119 | .offset = QPoint(0, 12), | ||||
120 | .shadow1 = { | ||||
121 | .offset = QPoint(0, 0), | ||||
122 | .radius = 32, | ||||
123 | .opacity = 1.0 | ||||
124 | }, | ||||
125 | .shadow2 = { | ||||
126 | .offset = QPoint(0, 0), | ||||
127 | .radius = 16, | ||||
128 | .opacity = 0.1 | ||||
129 | } | ||||
130 | }, | ||||
131 | { | ||||
132 | // Large | ||||
133 | .offset = QPoint(0, 20), | ||||
134 | .shadow1 = { | ||||
135 | .offset = QPoint(0, 0), | ||||
136 | .radius = 64, | ||||
137 | .opacity = 1.0 | ||||
138 | }, | ||||
139 | .shadow2 = { | ||||
140 | .offset = QPoint(0, 0), | ||||
141 | .radius = 24, | ||||
142 | .opacity = 0.1 | ||||
143 | } | ||||
144 | }, | ||||
145 | { | ||||
146 | // Very large | ||||
147 | .offset = QPoint(0, 34), | ||||
148 | .shadow1 = { | ||||
149 | .offset = QPoint(0, 0), | ||||
150 | .radius = 96, | ||||
151 | .opacity = 1.0 | ||||
152 | }, | ||||
153 | .shadow2 = { | ||||
154 | .offset = QPoint(0, 0), | ||||
155 | .radius = 28, | ||||
156 | .opacity = 0.1 | ||||
157 | } | ||||
158 | } | ||||
159 | }; | ||||
160 | | ||||
161 | inline ShadowParam lookupShadowParams(int size) | ||||
162 | { | ||||
163 | switch (size) { | ||||
164 | case Breeze::InternalSettings::ShadowNone: | ||||
165 | return s_shadowParams[0]; | ||||
166 | case Breeze::InternalSettings::ShadowSmall: | ||||
167 | return s_shadowParams[1]; | ||||
168 | case Breeze::InternalSettings::ShadowMedium: | ||||
169 | return s_shadowParams[2]; | ||||
170 | case Breeze::InternalSettings::ShadowLarge: | ||||
171 | return s_shadowParams[3]; | ||||
172 | case Breeze::InternalSettings::ShadowVeryLarge: | ||||
173 | return s_shadowParams[4]; | ||||
174 | default: | ||||
175 | // Fallback to the Large size. | ||||
176 | return s_shadowParams[3]; | ||||
177 | } | ||||
178 | } | ||||
179 | } | ||||
180 | | ||||
60 | namespace Breeze | 181 | namespace Breeze | ||
61 | { | 182 | { | ||
62 | 183 | | |||
63 | using KDecoration2::ColorRole; | 184 | using KDecoration2::ColorRole; | ||
64 | using KDecoration2::ColorGroup; | 185 | using KDecoration2::ColorGroup; | ||
65 | 186 | | |||
66 | //________________________________________________________________ | 187 | //________________________________________________________________ | ||
67 | static int g_sDecoCount = 0; | 188 | static int g_sDecoCount = 0; | ||
68 | static int g_shadowSizeEnum = InternalSettings::ShadowLarge; | 189 | static int g_shadowSizeEnum = InternalSettings::ShadowLarge; | ||
69 | static int g_shadowStrength = 90; | 190 | static int g_shadowStrength = 216; | ||
70 | static QColor g_shadowColor = Qt::black; | 191 | static QColor g_shadowColor = Qt::black; | ||
71 | static QSharedPointer<KDecoration2::DecorationShadow> g_sShadow; | 192 | static QSharedPointer<KDecoration2::DecorationShadow> g_sShadow; | ||
72 | 193 | | |||
73 | //________________________________________________________________ | 194 | //________________________________________________________________ | ||
74 | Decoration::Decoration(QObject *parent, const QVariantList &args) | 195 | Decoration::Decoration(QObject *parent, const QVariantList &args) | ||
75 | : KDecoration2::Decoration(parent, args) | 196 | : KDecoration2::Decoration(parent, args) | ||
76 | , m_animation( new QPropertyAnimation( this ) ) | 197 | , m_animation( new QPropertyAnimation( this ) ) | ||
77 | { | 198 | { | ||
▲ Show 20 Lines • Show All 539 Lines • ▼ Show 20 Line(s) | 691 | { | |||
617 | 738 | | |||
618 | } | 739 | } | ||
619 | 740 | | |||
620 | } | 741 | } | ||
621 | 742 | | |||
622 | //________________________________________________________________ | 743 | //________________________________________________________________ | ||
623 | void Decoration::createShadow() | 744 | void Decoration::createShadow() | ||
624 | { | 745 | { | ||
625 | 746 | if (!g_sShadow | |||
626 | // assign global shadow if exists and parameters match | 747 | ||g_shadowSizeEnum != m_internalSettings->shadowSize() | ||
627 | if( | 748 | || g_shadowStrength != m_internalSettings->shadowStrength() | ||
628 | !g_sShadow || | 749 | || g_shadowColor != m_internalSettings->shadowColor()) | ||
629 | g_shadowSizeEnum != m_internalSettings->shadowSize() || | | |||
630 | g_shadowStrength != m_internalSettings->shadowStrength() || | | |||
631 | g_shadowColor != m_internalSettings->shadowColor() | | |||
632 | ) | | |||
633 | { | 750 | { | ||
634 | // assign parameters | | |||
635 | g_shadowSizeEnum = m_internalSettings->shadowSize(); | 751 | g_shadowSizeEnum = m_internalSettings->shadowSize(); | ||
636 | g_shadowStrength = m_internalSettings->shadowStrength(); | 752 | g_shadowStrength = m_internalSettings->shadowStrength(); | ||
637 | g_shadowColor = m_internalSettings->shadowColor(); | 753 | g_shadowColor = m_internalSettings->shadowColor(); | ||
638 | 754 | | |||
639 | // shadow size from enum | 755 | const ShadowParam params = lookupShadowParams(g_shadowSizeEnum); | ||
640 | int shadowSize = 0; | 756 | if (params.isNone()) { | ||
641 | switch( g_shadowSizeEnum ) | 757 | g_sShadow.clear(); | ||
642 | { | 758 | setShadow(g_sShadow); | ||
643 | default: | 759 | return; | ||
644 | case InternalSettings::ShadowLarge: shadowSize = 64; break; | | |||
645 | | ||||
646 | case InternalSettings::ShadowNone: shadowSize = Metrics::Shadow_Overlap + 1; break; | | |||
647 | case InternalSettings::ShadowSmall: shadowSize = 16; break; | | |||
648 | case InternalSettings::ShadowMedium: shadowSize = 32; break; | | |||
649 | case InternalSettings::ShadowVeryLarge: shadowSize = 96; break; | | |||
650 | } | 760 | } | ||
651 | 761 | | |||
652 | // offset | 762 | auto withOpacity = [](const QColor &color, qreal opacity) -> QColor { | ||
653 | int shadowOffset = (g_shadowSizeEnum == InternalSettings::ShadowNone) ? 0 : qMax( 6*shadowSize/16, Metrics::Shadow_Overlap*2 ); | 763 | QColor c(color); | ||
654 | 764 | c.setAlphaF(opacity); | |||
655 | // create image | 765 | return c; | ||
656 | QImage image(2*shadowSize, 2*shadowSize, QImage::Format_ARGB32_Premultiplied); | | |||
657 | image.fill(Qt::transparent); | | |||
658 | | ||||
659 | // painter | | |||
660 | QPainter painter(&image); | | |||
661 | painter.setRenderHint( QPainter::Antialiasing, true ); | | |||
662 | | ||||
663 | // color calculation delta function | | |||
664 | auto gradientStopColor = [](QColor color, int alpha) | | |||
665 | { | | |||
666 | color.setAlpha(alpha); | | |||
667 | return color; | | |||
668 | }; | 766 | }; | ||
669 | 767 | | |||
670 | // create gradient | 768 | // Calculate the scaling factor by ourselves because devicePixelRatio() is not | ||
671 | if( g_shadowSizeEnum != InternalSettings::ShadowNone ) | 769 | // available inside of KWin. | ||
672 | { | 770 | const qreal dpr = QGuiApplication::primaryScreen()->logicalDotsPerInch() / 96.0; | ||
673 | 771 | | |||
674 | // gaussian lambda function | 772 | // In order to properly render a box shadow with a given radius `shadowSize`, | ||
675 | auto alpha = [](qreal x) { return std::exp( -x*x/0.15 ); }; | 773 | // the box size should be at least `2 * QSize(shadowSize, shadowSize)`. | ||
676 | 774 | const int shadowSize = qMax(params.shadow1.radius, params.shadow2.radius); | |||
677 | QRadialGradient radialGradient( shadowSize, shadowSize, shadowSize ); | 775 | const QRect box(shadowSize, shadowSize, 2 * shadowSize + 1, 2 * shadowSize + 1); | ||
678 | for( int i = 0; i < 10; ++i ) | 776 | const QRect rect = box.adjusted(-shadowSize, -shadowSize, shadowSize, shadowSize); | ||
679 | { | 777 | | ||
680 | const qreal x( qreal( i )/9 ); | 778 | QImage shadow(rect.size() * dpr, QImage::Format_ARGB32_Premultiplied); | ||
681 | radialGradient.setColorAt(x, gradientStopColor( g_shadowColor, alpha(x)*g_shadowStrength ) ); | 779 | shadow.setDevicePixelRatio(dpr); | ||
682 | } | 780 | shadow.fill(Qt::transparent); | ||
683 | 781 | | |||
684 | radialGradient.setColorAt(1, gradientStopColor( g_shadowColor, 0 ) ); | 782 | QPainter painter(&shadow); | ||
685 | 783 | painter.setRenderHint(QPainter::Antialiasing); | |||
686 | // fill | 784 | | ||
687 | painter.fillRect( image.rect(), radialGradient); | 785 | const qreal strength = static_cast<qreal>(g_shadowStrength) / 255.0; | ||
786 | | ||||
787 | // Draw the "shape" shadow. | ||||
788 | BoxShadowHelper::boxShadow( | ||||
789 | &painter, | ||||
790 | box, | ||||
791 | params.shadow1.offset, | ||||
792 | params.shadow1.radius, | ||||
793 | withOpacity(g_shadowColor, params.shadow1.opacity * strength)); | ||||
794 | | ||||
795 | // Draw the "contrast" shadow. | ||||
796 | BoxShadowHelper::boxShadow( | ||||
797 | &painter, | ||||
798 | box, | ||||
799 | params.shadow2.offset, | ||||
800 | params.shadow2.radius, | ||||
801 | withOpacity(g_shadowColor, params.shadow2.opacity * strength)); | ||||
802 | | ||||
803 | // Mask out inner rect. | ||||
804 | const QMargins padding = QMargins( | ||||
805 | shadowSize - Metrics::Shadow_Overlap - params.offset.x(), | ||||
806 | shadowSize - Metrics::Shadow_Overlap - params.offset.y(), | ||||
807 | shadowSize - Metrics::Shadow_Overlap + params.offset.x(), | ||||
808 | shadowSize - Metrics::Shadow_Overlap + params.offset.y()); | ||||
688 | 809 | | |||
689 | } | | |||
690 | | ||||
691 | // contrast pixel | | |||
692 | QRectF innerRect = QRectF( | | |||
693 | shadowSize - Metrics::Shadow_Overlap, shadowSize - shadowOffset - Metrics::Shadow_Overlap, | | |||
694 | 2*Metrics::Shadow_Overlap, shadowOffset + 2*Metrics::Shadow_Overlap ); | | |||
695 | | ||||
696 | painter.setPen( gradientStopColor( g_shadowColor, (g_shadowSizeEnum == InternalSettings::ShadowNone) ? g_shadowStrength:(g_shadowStrength*0.5) ) ); | | |||
697 | painter.setBrush( Qt::NoBrush ); | | |||
698 | painter.drawRoundedRect( innerRect, -0.5 + Metrics::Frame_FrameRadius, -0.5 + Metrics::Frame_FrameRadius ); | | |||
699 | | ||||
700 | // mask out inner rect | | |||
701 | painter.setPen( Qt::NoPen ); | 810 | painter.setPen(Qt::NoPen); | ||
702 | painter.setBrush( Qt::black ); | 811 | painter.setBrush(Qt::black); | ||
703 | painter.setCompositionMode(QPainter::CompositionMode_DestinationOut ); | 812 | painter.setCompositionMode(QPainter::CompositionMode_DestinationOut); | ||
704 | painter.drawRoundedRect( innerRect, 0.5 + Metrics::Frame_FrameRadius, 0.5 + Metrics::Frame_FrameRadius ); | 813 | painter.drawRoundedRect( | ||
814 | rect - padding, | ||||
815 | Metrics::Frame_FrameRadius + 0.5, | ||||
816 | Metrics::Frame_FrameRadius + 0.5); | ||||
817 | | ||||
818 | // Draw pixel contrast. | ||||
819 | painter.setPen(withOpacity(g_shadowColor, 0.2 * strength)); | ||||
820 | painter.setBrush(Qt::NoBrush); | ||||
821 | painter.setCompositionMode(QPainter::CompositionMode_SourceOver); | ||||
822 | painter.drawRoundedRect( | ||||
823 | rect - padding, | ||||
824 | Metrics::Frame_FrameRadius - 0.5, | ||||
825 | Metrics::Frame_FrameRadius - 0.5); | ||||
705 | 826 | | |||
706 | painter.end(); | 827 | painter.end(); | ||
707 | 828 | | |||
708 | g_sShadow = QSharedPointer<KDecoration2::DecorationShadow>::create(); | 829 | g_sShadow = QSharedPointer<KDecoration2::DecorationShadow>::create(); | ||
709 | g_sShadow->setPadding( QMargins( | 830 | g_sShadow->setPadding(padding * dpr); | ||
710 | shadowSize - Metrics::Shadow_Overlap, | 831 | g_sShadow->setInnerShadowRect(QRect(shadow.rect().center(), QSize(1, 1))); | ||
711 | shadowSize - shadowOffset - Metrics::Shadow_Overlap, | 832 | g_sShadow->setShadow(shadow); | ||
712 | shadowSize - Metrics::Shadow_Overlap, | | |||
713 | shadowSize - Metrics::Shadow_Overlap ) ); | | |||
714 | | ||||
715 | g_sShadow->setInnerShadowRect(QRect( shadowSize, shadowSize, 1, 1) ); | | |||
716 | | ||||
717 | // assign image | | |||
718 | g_sShadow->setShadow(image); | | |||
719 | | ||||
720 | } | 833 | } | ||
721 | 834 | | |||
722 | setShadow(g_sShadow); | 835 | setShadow(g_sShadow); | ||
723 | | ||||
724 | } | 836 | } | ||
725 | 837 | | |||
726 | //_________________________________________________________________ | 838 | //_________________________________________________________________ | ||
727 | void Decoration::createSizeGrip( void ) | 839 | void Decoration::createSizeGrip( void ) | ||
728 | { | 840 | { | ||
729 | 841 | | |||
730 | // do nothing if size grip already exist | 842 | // do nothing if size grip already exist | ||
731 | if( m_sizeGrip ) return; | 843 | if( m_sizeGrip ) return; | ||
Show All 33 Lines |