1 //////////////////////////////////////////////////////////////////////////////
4 // Ozone 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 Ozone::Oxygen::OxygenFactory();
46 OxygenHelper
*oxygenHelper(); // referenced from definition in oxygendclient.cpp
49 //////////////////////////////////////////////////////////////////////////////
50 // OxygenFactory Class //
51 //////////////////////////////////////////////////////////////////////////////
53 bool OxygenFactory::initialized_
= false;
54 Qt::Alignment
OxygenFactory::titleAlignment_
= Qt::AlignLeft
;
55 bool OxygenFactory::showStripes_
= true;
56 bool OxygenFactory::blendTitlebarColors_
= true;
58 //////////////////////////////////////////////////////////////////////////////
63 OxygenFactory::OxygenFactory()
69 //////////////////////////////////////////////////////////////////////////////
74 OxygenFactory::~OxygenFactory() { initialized_
= false; }
76 //////////////////////////////////////////////////////////////////////////////
79 // Create the decoration
81 KDecoration
* OxygenFactory::createDecoration(KDecorationBridge
* b
)
83 return (new OxygenClient(b
, this))->decoration();
86 //////////////////////////////////////////////////////////////////////////////
89 // Reset the handler. Returns true if decorations need to be remade, false if
90 // only a repaint is necessary
92 bool OxygenFactory::reset(unsigned long changed
)
94 // read in the configuration
96 bool confchange
= readConfig();
100 (changed
& (SettingDecoration
| SettingButtons
| SettingBorder
))) {
103 resetDecorations(changed
);
108 //////////////////////////////////////////////////////////////////////////////
111 // Read in the configuration file
113 bool OxygenFactory::readConfig()
115 // create a config object
116 KConfig
config("oxygenrc");
117 KConfigGroup group
= config
.group("Windeco");
120 Qt::Alignment oldalign
= titleAlignment_
;
121 QString value
= group
.readEntry("TitleAlignment", "Left");
123 titleAlignment_
= Qt::AlignLeft
;
124 else if (value
== "Center")
125 titleAlignment_
= Qt::AlignHCenter
;
126 else if (value
== "Right")
127 titleAlignment_
= Qt::AlignRight
;
129 bool oldstripes
= showStripes
;
130 showStripes_
= group
.readEntry( "ShowStripes", true );
132 bool oldblend
= blendTitlebarColors
;
133 blendTitlebarColors_
= group
.readEntry( "BlendTitlebarColors", true );
135 if (oldalign
== titleAlignment_
&& oldstripes
== showStripes_
&& oldblend
== blendTitlebarColors_
)
141 bool OxygenFactory::supports( Ability ability
) const
145 case AbilityAnnounceButtons
:
146 case AbilityAnnounceColors
:
148 case AbilityButtonMenu
:
149 case AbilityButtonHelp
:
150 case AbilityButtonMinimize
:
151 case AbilityButtonMaximize
:
152 case AbilityButtonClose
:
153 case AbilityButtonOnAllDesktops
:
154 case AbilityButtonAboveOthers
:
155 case AbilityButtonBelowOthers
:
156 case AbilityButtonSpacer
:
157 case AbilityButtonShade
:
159 case AbilityCompositingShadow
: // TODO: UI option to use default shadows instead
161 // no colors supported at this time
167 //////////////////////////////////////////////////////////////////////////////
170 QList
< QList
<QImage
> > OxygenFactory::shadowTextures()
172 QPalette palette
= qApp
->palette();
174 // Set palette to the right group. Which is active right now while drawing the glow
175 palette
.setCurrentColorGroup(QPalette::Active
);
177 // TODO: THIS IS ALL VERY UGLY! Not recommended to do it this way.
178 // Copied from the shadow effect's XRender picture generator
180 // TODO: You can add fake anti-aliasing here :)
182 QList
< QList
<QImage
> > textureLists
;
183 QList
<QImage
> textures
;
185 #define shadowFuzzyness 10
186 #define shadowSize 10
188 //---------------------------------------------------------------
189 // Active shadow texture
191 QColor color
= palette
.window().color();
192 QColor light
= oxygenHelper()->calcLightColor(oxygenHelper()->backgroundTopColor(color
));
193 QColor dark
= oxygenHelper()->calcDarkColor(oxygenHelper()->backgroundBottomColor(color
));
194 QColor glow
= KDecoration::options()->color(ColorFrame
);
195 QColor glow2
= KDecoration::options()->color(ColorTitleBar
);
198 QPixmap
*shadow
= new QPixmap( size
*2, size
*2 );
199 shadow
->fill( Qt::transparent
);
200 QRadialGradient
rg( size
, size
, size
);
202 c
.setAlpha( 255 ); rg
.setColorAt( 4.4/size
, c
);
204 c
.setAlpha( 220 ); rg
.setColorAt( 4.5/size
, c
);
205 c
.setAlpha( 180 ); rg
.setColorAt( 5/size
, c
);
206 c
.setAlpha( 25 ); rg
.setColorAt( 5.5/size
, c
);
207 c
.setAlpha( 0 ); rg
.setColorAt( 6.5/size
, c
);
208 QPainter
p( shadow
);
209 p
.setRenderHint( QPainter::Antialiasing
);
210 p
.setPen( Qt::NoPen
);
212 p
.drawRect( shadow
->rect() );
214 rg
= QRadialGradient( size
, size
, size
);
216 c
.setAlpha( 255 ); rg
.setColorAt( 4.4/size
, c
);
218 c
.setAlpha( 0.58*255 ); rg
.setColorAt( 4.5/size
, c
);
219 c
.setAlpha( 0.43*255 ); rg
.setColorAt( 5.5/size
, c
);
220 c
.setAlpha( 0.30*255 ); rg
.setColorAt( 6.5/size
, c
);
221 c
.setAlpha( 0.22*255 ); rg
.setColorAt( 7.5/size
, c
);
222 c
.setAlpha( 0.15*255 ); rg
.setColorAt( 8.5/size
, c
);
223 c
.setAlpha( 0.08*255 ); rg
.setColorAt( 11.5/size
, c
);
224 c
.setAlpha( 0); rg
.setColorAt( 14.5/size
, c
);
225 p
.setRenderHint( QPainter::Antialiasing
);
226 p
.setPen( Qt::NoPen
);
228 p
.drawRect( shadow
->rect() );
230 // draw the corner of the window - actually all 4 corners as one circle
231 p
.setBrush( Qt::NoBrush
);
232 QLinearGradient lg
= QLinearGradient(0.0, size
-4.5, 0.0, size
+4.5);
233 lg
.setColorAt(0.52, light
);
234 lg
.setColorAt(1.0, dark
);
235 p
.setPen(QPen(lg
, 0.8));
236 p
.drawEllipse(QRectF(size
-4, size
-4, 8, 8));
238 // cut out the part of the texture that is under the window
239 p
.setCompositionMode( QPainter::CompositionMode_DestinationOut
);
240 p
.setBrush( QColor( 0, 0, 0, 255 ));
241 p
.setPen( Qt::NoPen
);
242 p
.drawEllipse(QRectF(size
-3, size
-3, 6, 6));
243 p
.drawRect(QRectF(size
-3, size
-1, 6, 2));
244 p
.drawRect(QRectF(size
-1, size
-3, 2, 6));
248 int w
= shadow
->width() / 2;
249 int h
= shadow
->height() / 2;
252 #define MAKE_TEX( _W_, _H_, _XOFF_, _YOFF_ ) \
253 dump = QPixmap( _W_, _H_ ); \
254 dump.fill( Qt::transparent ); \
256 p.drawPixmap( 0, 0, *shadow, _XOFF_, _YOFF_, _W_, _H_ ); \
258 textures.append( dump.toImage() );
260 MAKE_TEX( w
, h
, 0, h
+1 ); // corner
261 MAKE_TEX( 1, h
, w
, h
+1 );
262 MAKE_TEX( w
, h
, w
+1, h
+1 );// corner
263 MAKE_TEX( w
, 1, 0, h
);
264 MAKE_TEX( w
, 1, w
+1, h
);
265 MAKE_TEX( w
, h
, 0, 0);// corner
266 MAKE_TEX( 1, h
, w
, 0);
267 MAKE_TEX( w
, h
, w
+1, 0);// corner
269 textureLists
.append( textures
);
271 //---------------------------------------------------------------
272 // Inactive shadow texture
276 shadow
->fill( Qt::transparent
);
278 p
.setRenderHint( QPainter::Antialiasing
);
279 p
.setPen( Qt::NoPen
);
281 rg
= QRadialGradient( size
, size
+4, size
);
282 c
= QColor( Qt::black
);
283 c
.setAlpha( 0.12*255 ); rg
.setColorAt( 4.5/size
, c
);
284 c
.setAlpha( 0.11*255 ); rg
.setColorAt( 6.6/size
, c
);
285 c
.setAlpha( 0.075*255 ); rg
.setColorAt( 8.5/size
, c
);
286 c
.setAlpha( 0.06*255 ); rg
.setColorAt( 11.5/size
, c
);
287 c
.setAlpha( 0.035*255 ); rg
.setColorAt( 14.5/size
, c
);
288 c
.setAlpha( 0.025*255 ); rg
.setColorAt( 17.5/size
, c
);
289 c
.setAlpha( 0.01*255 ); rg
.setColorAt( 21.5/size
, c
);
290 c
.setAlpha( 0.0*255 ); rg
.setColorAt( 25.5/size
, c
);
291 p
.setRenderHint( QPainter::Antialiasing
);
292 p
.setPen( Qt::NoPen
);
294 p
.drawRect( shadow
->rect() );
296 rg
= QRadialGradient( size
, size
+2, size
);
297 c
= QColor( Qt::black
);
298 c
.setAlpha( 0.25*255 ); rg
.setColorAt( 4.5/size
, c
);
299 c
.setAlpha( 0.20*255 ); rg
.setColorAt( 5.5/size
, c
);
300 c
.setAlpha( 0.13*255 ); rg
.setColorAt( 7.5/size
, c
);
301 c
.setAlpha( 0.06*255 ); rg
.setColorAt( 8.5/size
, c
);
302 c
.setAlpha( 0.015*255 ); rg
.setColorAt( 11.5/size
, c
);
303 c
.setAlpha( 0.0*255 ); rg
.setColorAt( 14.5/size
, c
);
304 p
.setRenderHint( QPainter::Antialiasing
);
305 p
.setPen( Qt::NoPen
);
307 p
.drawRect( shadow
->rect() );
309 rg
= QRadialGradient( size
, size
+0.2, size
);
311 c
= QColor( Qt::black
);
312 c
.setAlpha( 0.35*255 ); rg
.setColorAt( 0/size
, c
);
313 c
.setAlpha( 0.32*255 ); rg
.setColorAt( 4.5/size
, c
);
314 c
.setAlpha( 0.22*255 ); rg
.setColorAt( 5.0/size
, c
);
315 c
.setAlpha( 0.03*255 ); rg
.setColorAt( 5.5/size
, c
);
316 c
.setAlpha( 0.0*255 ); rg
.setColorAt( 6.5/size
, c
);
317 p
.setRenderHint( QPainter::Antialiasing
);
318 p
.setPen( Qt::NoPen
);
320 p
.drawRect( shadow
->rect() );
322 rg
= QRadialGradient( size
, size
, size
);
324 c
.setAlpha( 255 ); rg
.setColorAt( 4.0/size
, c
);
325 c
.setAlpha( 0 ); rg
.setColorAt( 4.01/size
, c
);
326 p
.setRenderHint( QPainter::Antialiasing
);
327 p
.setPen( Qt::NoPen
);
329 p
.drawRect( shadow
->rect() );
331 // draw the corner of the window - actually all 4 corners as one circle
332 p
.setBrush( Qt::NoBrush
);
333 p
.setPen(QPen(lg
, 0.8));
334 p
.drawEllipse(QRectF(size
-4, size
-4, 8, 8));
336 // cut out the part of the texture that is under the window
337 p
.setCompositionMode( QPainter::CompositionMode_DestinationOut
);
338 p
.setBrush( QColor( 0, 0, 0, 255 ));
339 p
.setPen( Qt::NoPen
);
340 p
.drawEllipse(QRectF(size
-3, size
-3, 6, 6));
341 p
.drawRect(QRectF(size
-3, size
-1, 6, 2));
342 p
.drawRect(QRectF(size
-1, size
-3, 2, 6));
346 MAKE_TEX( w
, h
, 0, h
+1 ); // corner
347 MAKE_TEX( 1, h
, w
, h
+1 );
348 MAKE_TEX( w
, h
, w
+1, h
+1 );// corner
349 MAKE_TEX( w
, 1, 0, h
);
350 MAKE_TEX( w
, 1, w
+1, h
);
351 MAKE_TEX( w
, h
, 0, 0);// corner
352 MAKE_TEX( 1, h
, w
, 0);
353 MAKE_TEX( w
, h
, w
+1, 0);// corner
355 textureLists
.append( textures
);
362 int OxygenFactory::shadowTextureList( ShadowType type
) const
365 case ShadowBorderedActive
:
367 case ShadowBorderedInactive
:
370 abort(); // Should never be reached
373 QList
<QRect
> OxygenFactory::shadowQuads( ShadowType type
, QSize size
) const
375 int outside
=20, underlap
=5, cornersize
=25;
376 // These are underlap under the decoration so the corners look nicer 10px on the outside
378 /*quads.append(QRect(-outside, size.height()-underlap, cornersize, cornersize));
379 quads.append(QRect(underlap, size.height()-underlap, size.width()-2*underlap, cornersize));
380 quads.append(QRect(size.width()-underlap, size.height()-underlap, cornersize, cornersize));
381 quads.append(QRect(-outside, underlap, cornersize, size.height()-2*underlap));
382 quads.append(QRect(size.width()-underlap, underlap, cornersize, size.height()-2*underlap));
383 quads.append(QRect(-outside, -outside, cornersize, cornersize));
384 quads.append(QRect(underlap, -outside, size.width()-2*underlap, cornersize));
385 quads.append(QRect(size.width()-underlap, -outside, cornersize, cornersize));*/
389 double OxygenFactory::shadowOpacity( ShadowType type
) const