add more spacing
[personal-kdebase.git] / workspace / kwin / clients / ozone / oxygen.cpp
blob63610bb41560b9e27c55c99f26b2d85c5b023519
1 //////////////////////////////////////////////////////////////////////////////
2 // oxygenbutton.h
3 // -------------------
4 // Ozone window decoration for KDE.
5 // -------------------
6 // Copyright (c) 2006, 2007 Riccardo Iaconelli <riccardo@kde.org>
7 //
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
24 // IN THE SOFTWARE.
25 //////////////////////////////////////////////////////////////////////////////
27 #include <QPainter>
29 #include "oxygen.h"
30 #include "oxygenclient.h"
31 #include <kconfiggroup.h>
32 #include <QApplication>
34 extern "C"
36 KDE_EXPORT KDecorationFactory* create_factory()
38 return new Ozone::Oxygen::OxygenFactory();
41 namespace Ozone
43 namespace Oxygen
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 //////////////////////////////////////////////////////////////////////////////
59 // OxygenFactory()
60 // ----------------
61 // Constructor
63 OxygenFactory::OxygenFactory()
65 readConfig();
66 initialized_ = true;
69 //////////////////////////////////////////////////////////////////////////////
70 // ~OxygenFactory()
71 // -----------------
72 // Destructor
74 OxygenFactory::~OxygenFactory() { initialized_ = false; }
76 //////////////////////////////////////////////////////////////////////////////
77 // createDecoration()
78 // -----------------
79 // Create the decoration
81 KDecoration* OxygenFactory::createDecoration(KDecorationBridge* b)
83 return (new OxygenClient(b, this))->decoration();
86 //////////////////////////////////////////////////////////////////////////////
87 // reset()
88 // -------
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
95 initialized_ = false;
96 bool confchange = readConfig();
97 initialized_ = true;
99 if (confchange ||
100 (changed & (SettingDecoration | SettingButtons | SettingBorder))) {
101 return true;
102 } else {
103 resetDecorations(changed);
104 return false;
108 //////////////////////////////////////////////////////////////////////////////
109 // readConfig()
110 // ------------
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");
119 // grab settings
120 Qt::Alignment oldalign = titleAlignment_;
121 QString value = group.readEntry("TitleAlignment", "Left");
122 if (value == "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_)
136 return false;
137 else
138 return true;
141 bool OxygenFactory::supports( Ability ability ) const
143 switch( ability ) {
144 // announce
145 case AbilityAnnounceButtons:
146 case AbilityAnnounceColors:
147 // buttons
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:
158 // compositing
159 case AbilityCompositingShadow: // TODO: UI option to use default shadows instead
160 return true;
161 // no colors supported at this time
162 default:
163 return false;
167 //////////////////////////////////////////////////////////////////////////////
168 // Shadows
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);
197 qreal size = 25.5;
198 QPixmap *shadow = new QPixmap( size*2, size*2 );
199 shadow->fill( Qt::transparent );
200 QRadialGradient rg( size, size, size );
201 QColor c = color;
202 c.setAlpha( 255 ); rg.setColorAt( 4.4/size, c );
203 c = glow;
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 );
211 p.setBrush( rg );
212 p.drawRect( shadow->rect() );
214 rg = QRadialGradient( size, size, size );
215 c = color;
216 c.setAlpha( 255 ); rg.setColorAt( 4.4/size, c );
217 c = glow2;
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 );
227 p.setBrush( rg );
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));
246 p.end();
248 int w = shadow->width() / 2;
249 int h = shadow->height() / 2;
250 QPixmap dump;
252 #define MAKE_TEX( _W_, _H_, _XOFF_, _YOFF_ ) \
253 dump = QPixmap( _W_, _H_ ); \
254 dump.fill( Qt::transparent ); \
255 p.begin( &dump ); \
256 p.drawPixmap( 0, 0, *shadow, _XOFF_, _YOFF_, _W_, _H_ ); \
257 p.end(); \
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
274 textures.clear();
276 shadow->fill( Qt::transparent );
277 p.begin(shadow);
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 );
293 p.setBrush( rg );
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 );
306 p.setBrush( rg );
307 p.drawRect( shadow->rect() );
309 rg = QRadialGradient( size, size+0.2, size );
310 c = color;
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 );
319 p.setBrush( rg );
320 p.drawRect( shadow->rect() );
322 rg = QRadialGradient( size, size, size );
323 c = color;
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 );
328 p.setBrush( rg );
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));
344 p.end();
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 );
357 delete shadow;
359 return textureLists;
362 int OxygenFactory::shadowTextureList( ShadowType type ) const
364 switch( type ) {
365 case ShadowBorderedActive:
366 return 0;
367 case ShadowBorderedInactive:
368 return 1;
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
377 QList<QRect> quads;
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));*/
386 return quads;
389 double OxygenFactory::shadowOpacity( ShadowType type ) const
391 return 1.0;
394 } //namespace Oxygen
395 } //namespace Ozone