not quite so much needs to be delayed to the init() function
[personal-kdebase.git] / workspace / kwin / clients / oxygen / oxygen.cpp
blobc6b9e756bdad24dd4cee706a04c18956b2ee285b
1 //////////////////////////////////////////////////////////////////////////////
2 // oxygenbutton.h
3 // -------------------
4 // Oxygen 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 Oxygen::OxygenFactory();
41 namespace Oxygen
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 //////////////////////////////////////////////////////////////////////////////
56 // OxygenFactory()
57 // ----------------
58 // Constructor
60 OxygenFactory::OxygenFactory()
62 readConfig();
63 initialized_ = true;
66 //////////////////////////////////////////////////////////////////////////////
67 // ~OxygenFactory()
68 // -----------------
69 // Destructor
71 OxygenFactory::~OxygenFactory() { initialized_ = false; }
73 //////////////////////////////////////////////////////////////////////////////
74 // createDecoration()
75 // -----------------
76 // Create the decoration
78 KDecoration* OxygenFactory::createDecoration(KDecorationBridge* b)
80 return (new OxygenClient(b, this))->decoration();
83 //////////////////////////////////////////////////////////////////////////////
84 // reset()
85 // -------
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
92 initialized_ = false;
93 bool confchange = readConfig();
94 initialized_ = true;
96 if (confchange ||
97 (changed & (SettingDecoration | SettingButtons | SettingBorder))) {
98 return true;
99 } else {
100 resetDecorations(changed);
101 return false;
105 //////////////////////////////////////////////////////////////////////////////
106 // readConfig()
107 // ------------
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");
116 // grab settings
117 Qt::Alignment oldalign = titleAlignment_;
118 QString value = group.readEntry("TitleAlignment", "Left");
119 if (value == "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_)
130 return false;
131 else
132 return true;
135 bool OxygenFactory::supports( Ability ability ) const
137 switch( ability ) {
138 // announce
139 case AbilityAnnounceButtons:
140 case AbilityAnnounceColors:
141 // buttons
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:
152 // compositing
153 case AbilityCompositingShadow: // TODO: UI option to use default shadows instead
154 return true;
155 // no colors supported at this time
156 default:
157 return false;
161 //////////////////////////////////////////////////////////////////////////////
162 // Shadows
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);
191 qreal size = 25.5;
192 QPixmap *shadow = new QPixmap( size*2, size*2 );
193 shadow->fill( Qt::transparent );
194 QRadialGradient rg( size, size, size );
195 QColor c = color;
196 c.setAlpha( 255 ); rg.setColorAt( 4.4/size, c );
197 c = glow;
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 );
205 p.setBrush( rg );
206 p.drawRect( shadow->rect() );
208 rg = QRadialGradient( size, size, size );
209 c = color;
210 c.setAlpha( 255 ); rg.setColorAt( 4.4/size, c );
211 c = glow2;
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 );
221 p.setBrush( rg );
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));
240 p.end();
242 int w = shadow->width() / 2;
243 int h = shadow->height() / 2;
244 QPixmap dump;
246 #define MAKE_TEX( _W_, _H_, _XOFF_, _YOFF_ ) \
247 dump = QPixmap( _W_, _H_ ); \
248 dump.fill( Qt::transparent ); \
249 p.begin( &dump ); \
250 p.drawPixmap( 0, 0, *shadow, _XOFF_, _YOFF_, _W_, _H_ ); \
251 p.end(); \
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
268 textures.clear();
270 shadow->fill( Qt::transparent );
271 p.begin(shadow);
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 );
287 p.setBrush( rg );
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 );
300 p.setBrush( rg );
301 p.drawRect( shadow->rect() );
303 rg = QRadialGradient( size, size+0.2, size );
304 c = color;
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 );
313 p.setBrush( rg );
314 p.drawRect( shadow->rect() );
316 rg = QRadialGradient( size, size, size );
317 c = color;
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 );
322 p.setBrush( rg );
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));
338 p.end();
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 );
351 delete shadow;
353 return textureLists;
356 int OxygenFactory::shadowTextureList( ShadowType type ) const
358 switch( type ) {
359 case ShadowBorderedActive:
360 return 0;
361 case ShadowBorderedInactive:
362 return 1;
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
371 QList<QRect> quads;
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));*/
380 return quads;
383 double OxygenFactory::shadowOpacity( ShadowType type ) const
385 return 1.0;
388 } //namespace Oxygen