1 //////////////////////////////////////////////////////////////////////////////
4 // Oxygen window decoration for KDE.
6 // Copyright (c) 2006, 2007 Riccardo Iaconelli <riccardo@kde.org>
8 // Permission is hereby granted, free of charge, to any person obtaining a copy
9 // of this software and associated documentation files (the "Software"), to
10 // deal in the Software without restriction, including without limitation the
11 // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
12 // sell copies of the Software, and to permit persons to whom the Software is
13 // furnished to do so, subject to the following conditions:
15 // The above copyright notice and this permission notice shall be included in
16 // all copies or substantial portions of the Software.
18 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
25 //////////////////////////////////////////////////////////////////////////////
30 #include "oxygenclient.h"
31 #include <kconfiggroup.h>
32 #include <QApplication>
36 KDE_EXPORT KDecorationFactory
* create_factory()
38 return new Oxygen::OxygenFactory();
44 OxygenHelper
*oxygenHelper(); // referenced from definition in oxygendclient.cpp
47 //////////////////////////////////////////////////////////////////////////////
48 // OxygenFactory Class //
49 //////////////////////////////////////////////////////////////////////////////
51 bool OxygenFactory::initialized_
= false;
52 Qt::Alignment
OxygenFactory::titleAlignment_
= Qt::AlignLeft
;
53 bool OxygenFactory::showStripes_
= true;
55 //////////////////////////////////////////////////////////////////////////////
60 OxygenFactory::OxygenFactory()
66 //////////////////////////////////////////////////////////////////////////////
71 OxygenFactory::~OxygenFactory() { initialized_
= false; }
73 //////////////////////////////////////////////////////////////////////////////
76 // Create the decoration
78 KDecoration
* OxygenFactory::createDecoration(KDecorationBridge
* b
)
80 return (new OxygenClient(b
, this))->decoration();
83 //////////////////////////////////////////////////////////////////////////////
86 // Reset the handler. Returns true if decorations need to be remade, false if
87 // only a repaint is necessary
89 bool OxygenFactory::reset(unsigned long changed
)
91 // read in the configuration
93 bool confchange
= readConfig();
97 (changed
& (SettingDecoration
| SettingButtons
| SettingBorder
))) {
100 resetDecorations(changed
);
105 //////////////////////////////////////////////////////////////////////////////
108 // Read in the configuration file
110 bool OxygenFactory::readConfig()
112 // create a config object
113 KConfig
config("oxygenrc");
114 KConfigGroup group
= config
.group("Windeco");
117 Qt::Alignment oldalign
= titleAlignment_
;
118 QString value
= group
.readEntry("TitleAlignment", "Left");
120 titleAlignment_
= Qt::AlignLeft
;
121 else if (value
== "Center")
122 titleAlignment_
= Qt::AlignHCenter
;
123 else if (value
== "Right")
124 titleAlignment_
= Qt::AlignRight
;
126 bool oldstripes
= showStripes
;
127 showStripes_
= group
.readEntry( "ShowStripes", true );
129 if (oldalign
== titleAlignment_
&& oldstripes
== showStripes_
)
135 bool OxygenFactory::supports( Ability ability
) const
139 case AbilityAnnounceButtons
:
140 case AbilityAnnounceColors
:
142 case AbilityButtonMenu
:
143 case AbilityButtonHelp
:
144 case AbilityButtonMinimize
:
145 case AbilityButtonMaximize
:
146 case AbilityButtonClose
:
147 case AbilityButtonOnAllDesktops
:
148 case AbilityButtonAboveOthers
:
149 case AbilityButtonBelowOthers
:
150 case AbilityButtonSpacer
:
151 case AbilityButtonShade
:
153 case AbilityCompositingShadow
: // TODO: UI option to use default shadows instead
155 // no colors supported at this time
161 //////////////////////////////////////////////////////////////////////////////
164 QList
< QList
<QImage
> > OxygenFactory::shadowTextures()
166 QPalette palette
= qApp
->palette();
168 // Set palette to the right group. Which is active right now while drawing the glow
169 palette
.setCurrentColorGroup(QPalette::Active
);
171 // TODO: THIS IS ALL VERY UGLY! Not recommended to do it this way.
172 // Copied from the shadow effect's XRender picture generator
174 // TODO: You can add fake anti-aliasing here :)
176 QList
< QList
<QImage
> > textureLists
;
177 QList
<QImage
> textures
;
179 #define shadowFuzzyness 10
180 #define shadowSize 10
182 //---------------------------------------------------------------
183 // Active shadow texture
185 QColor color
= palette
.window().color();
186 QColor light
= oxygenHelper()->calcLightColor(oxygenHelper()->backgroundTopColor(color
));
187 QColor dark
= oxygenHelper()->calcDarkColor(oxygenHelper()->backgroundBottomColor(color
));
188 QColor glow
= KDecoration::options()->color(ColorFrame
);
189 QColor glow2
= KDecoration::options()->color(ColorTitleBar
);
192 QPixmap
*shadow
= new QPixmap( size
*2, size
*2 );
193 shadow
->fill( Qt::transparent
);
194 QRadialGradient
rg( size
, size
, size
);
196 c
.setAlpha( 255 ); rg
.setColorAt( 4.4/size
, c
);
198 c
.setAlpha( 220 ); rg
.setColorAt( 4.5/size
, c
);
199 c
.setAlpha( 180 ); rg
.setColorAt( 5/size
, c
);
200 c
.setAlpha( 25 ); rg
.setColorAt( 5.5/size
, c
);
201 c
.setAlpha( 0 ); rg
.setColorAt( 6.5/size
, c
);
202 QPainter
p( shadow
);
203 p
.setRenderHint( QPainter::Antialiasing
);
204 p
.setPen( Qt::NoPen
);
206 p
.drawRect( shadow
->rect() );
208 rg
= QRadialGradient( size
, size
, size
);
210 c
.setAlpha( 255 ); rg
.setColorAt( 4.4/size
, c
);
212 c
.setAlpha( 0.58*255 ); rg
.setColorAt( 4.5/size
, c
);
213 c
.setAlpha( 0.43*255 ); rg
.setColorAt( 5.5/size
, c
);
214 c
.setAlpha( 0.30*255 ); rg
.setColorAt( 6.5/size
, c
);
215 c
.setAlpha( 0.22*255 ); rg
.setColorAt( 7.5/size
, c
);
216 c
.setAlpha( 0.15*255 ); rg
.setColorAt( 8.5/size
, c
);
217 c
.setAlpha( 0.08*255 ); rg
.setColorAt( 11.5/size
, c
);
218 c
.setAlpha( 0); rg
.setColorAt( 14.5/size
, c
);
219 p
.setRenderHint( QPainter::Antialiasing
);
220 p
.setPen( Qt::NoPen
);
222 p
.drawRect( shadow
->rect() );
224 // draw the corner of the window - actually all 4 corners as one circle
225 p
.setBrush( Qt::NoBrush
);
226 QLinearGradient lg
= QLinearGradient(0.0, size
-4.5, 0.0, size
+4.5);
227 lg
.setColorAt(0.52, light
);
228 lg
.setColorAt(1.0, dark
);
229 p
.setPen(QPen(lg
, 0.8));
230 p
.drawEllipse(QRectF(size
-4, size
-4, 8, 8));
232 // cut out the part of the texture that is under the window
233 p
.setCompositionMode( QPainter::CompositionMode_DestinationOut
);
234 p
.setBrush( QColor( 0, 0, 0, 255 ));
235 p
.setPen( Qt::NoPen
);
236 p
.drawEllipse(QRectF(size
-3, size
-3, 6, 6));
237 p
.drawRect(QRectF(size
-3, size
-1, 6, 2));
238 p
.drawRect(QRectF(size
-1, size
-3, 2, 6));
242 int w
= shadow
->width() / 2;
243 int h
= shadow
->height() / 2;
246 #define MAKE_TEX( _W_, _H_, _XOFF_, _YOFF_ ) \
247 dump = QPixmap( _W_, _H_ ); \
248 dump.fill( Qt::transparent ); \
250 p.drawPixmap( 0, 0, *shadow, _XOFF_, _YOFF_, _W_, _H_ ); \
252 textures.append( dump.toImage() );
254 MAKE_TEX( w
, h
, 0, h
+1 ); // corner
255 MAKE_TEX( 1, h
, w
, h
+1 );
256 MAKE_TEX( w
, h
, w
+1, h
+1 );// corner
257 MAKE_TEX( w
, 1, 0, h
);
258 MAKE_TEX( w
, 1, w
+1, h
);
259 MAKE_TEX( w
, h
, 0, 0);// corner
260 MAKE_TEX( 1, h
, w
, 0);
261 MAKE_TEX( w
, h
, w
+1, 0);// corner
263 textureLists
.append( textures
);
265 //---------------------------------------------------------------
266 // Inactive shadow texture
270 shadow
->fill( Qt::transparent
);
272 p
.setRenderHint( QPainter::Antialiasing
);
273 p
.setPen( Qt::NoPen
);
275 rg
= QRadialGradient( size
, size
+4, size
);
276 c
= QColor( Qt::black
);
277 c
.setAlpha( 0.12*255 ); rg
.setColorAt( 4.5/size
, c
);
278 c
.setAlpha( 0.11*255 ); rg
.setColorAt( 6.6/size
, c
);
279 c
.setAlpha( 0.075*255 ); rg
.setColorAt( 8.5/size
, c
);
280 c
.setAlpha( 0.06*255 ); rg
.setColorAt( 11.5/size
, c
);
281 c
.setAlpha( 0.035*255 ); rg
.setColorAt( 14.5/size
, c
);
282 c
.setAlpha( 0.025*255 ); rg
.setColorAt( 17.5/size
, c
);
283 c
.setAlpha( 0.01*255 ); rg
.setColorAt( 21.5/size
, c
);
284 c
.setAlpha( 0.0*255 ); rg
.setColorAt( 25.5/size
, c
);
285 p
.setRenderHint( QPainter::Antialiasing
);
286 p
.setPen( Qt::NoPen
);
288 p
.drawRect( shadow
->rect() );
290 rg
= QRadialGradient( size
, size
+2, size
);
291 c
= QColor( Qt::black
);
292 c
.setAlpha( 0.25*255 ); rg
.setColorAt( 4.5/size
, c
);
293 c
.setAlpha( 0.20*255 ); rg
.setColorAt( 5.5/size
, c
);
294 c
.setAlpha( 0.13*255 ); rg
.setColorAt( 7.5/size
, c
);
295 c
.setAlpha( 0.06*255 ); rg
.setColorAt( 8.5/size
, c
);
296 c
.setAlpha( 0.015*255 ); rg
.setColorAt( 11.5/size
, c
);
297 c
.setAlpha( 0.0*255 ); rg
.setColorAt( 14.5/size
, c
);
298 p
.setRenderHint( QPainter::Antialiasing
);
299 p
.setPen( Qt::NoPen
);
301 p
.drawRect( shadow
->rect() );
303 rg
= QRadialGradient( size
, size
+0.2, size
);
305 c
= QColor( Qt::black
);
306 c
.setAlpha( 0.35*255 ); rg
.setColorAt( 0/size
, c
);
307 c
.setAlpha( 0.32*255 ); rg
.setColorAt( 4.5/size
, c
);
308 c
.setAlpha( 0.22*255 ); rg
.setColorAt( 5.0/size
, c
);
309 c
.setAlpha( 0.03*255 ); rg
.setColorAt( 5.5/size
, c
);
310 c
.setAlpha( 0.0*255 ); rg
.setColorAt( 6.5/size
, c
);
311 p
.setRenderHint( QPainter::Antialiasing
);
312 p
.setPen( Qt::NoPen
);
314 p
.drawRect( shadow
->rect() );
316 rg
= QRadialGradient( size
, size
, size
);
318 c
.setAlpha( 255 ); rg
.setColorAt( 4.0/size
, c
);
319 c
.setAlpha( 0 ); rg
.setColorAt( 4.01/size
, c
);
320 p
.setRenderHint( QPainter::Antialiasing
);
321 p
.setPen( Qt::NoPen
);
323 p
.drawRect( shadow
->rect() );
325 // draw the corner of the window - actually all 4 corners as one circle
326 p
.setBrush( Qt::NoBrush
);
327 p
.setPen(QPen(lg
, 0.8));
328 p
.drawEllipse(QRectF(size
-4, size
-4, 8, 8));
330 // cut out the part of the texture that is under the window
331 p
.setCompositionMode( QPainter::CompositionMode_DestinationOut
);
332 p
.setBrush( QColor( 0, 0, 0, 255 ));
333 p
.setPen( Qt::NoPen
);
334 p
.drawEllipse(QRectF(size
-3, size
-3, 6, 6));
335 p
.drawRect(QRectF(size
-3, size
-1, 6, 2));
336 p
.drawRect(QRectF(size
-1, size
-3, 2, 6));
340 MAKE_TEX( w
, h
, 0, h
+1 ); // corner
341 MAKE_TEX( 1, h
, w
, h
+1 );
342 MAKE_TEX( w
, h
, w
+1, h
+1 );// corner
343 MAKE_TEX( w
, 1, 0, h
);
344 MAKE_TEX( w
, 1, w
+1, h
);
345 MAKE_TEX( w
, h
, 0, 0);// corner
346 MAKE_TEX( 1, h
, w
, 0);
347 MAKE_TEX( w
, h
, w
+1, 0);// corner
349 textureLists
.append( textures
);
356 int OxygenFactory::shadowTextureList( ShadowType type
) const
359 case ShadowBorderedActive
:
361 case ShadowBorderedInactive
:
364 abort(); // Should never be reached
367 QList
<QRect
> OxygenFactory::shadowQuads( ShadowType type
, QSize size
) const
369 int outside
=20, underlap
=5, cornersize
=25;
370 // These are underlap under the decoration so the corners look nicer 10px on the outside
372 /*quads.append(QRect(-outside, size.height()-underlap, cornersize, cornersize));
373 quads.append(QRect(underlap, size.height()-underlap, size.width()-2*underlap, cornersize));
374 quads.append(QRect(size.width()-underlap, size.height()-underlap, cornersize, cornersize));
375 quads.append(QRect(-outside, underlap, cornersize, size.height()-2*underlap));
376 quads.append(QRect(size.width()-underlap, underlap, cornersize, size.height()-2*underlap));
377 quads.append(QRect(-outside, -outside, cornersize, cornersize));
378 quads.append(QRect(underlap, -outside, size.width()-2*underlap, cornersize));
379 quads.append(QRect(size.width()-underlap, -outside, cornersize, cornersize));*/
383 double OxygenFactory::shadowOpacity( ShadowType type
) const