1 /********************************************************************
2 KWin - the KDE window manager
3 This file is part of the KDE project.
5 Copyright (C) 2007 Lubos Lunak <l.lunak@kde.org>
6 Copyright (C) 2008 Lucas Murray <lmurray@undefinedfire.com>
7 Copyright (C) 2008 Martin Gräßlin <ubuntu@martin-graesslin.com>
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
21 *********************************************************************/
24 #include "shadow_helper.h"
26 #include <kwinglutils.h>
28 #include <kconfiggroup.h>
30 #include <KStandardDirs>
31 #include <kcolorscheme.h>
32 #include <KGlobalSettings>
39 KWIN_EFFECT( shadow
, ShadowEffect
)
41 ShadowEffect::ShadowEffect()
44 reconfigure( ReconfigureAll
);
45 connect(KGlobalSettings::self(), SIGNAL(kdisplayPaletteChanged()),
46 this, SLOT(updateShadowColor()));
49 ShadowEffect::~ShadowEffect()
51 #ifdef KWIN_HAVE_OPENGL_COMPOSITING
52 for( int i
= 0; i
< mShadowTextures
.size(); i
++ )
53 for( int j
= 0; j
< mShadowTextures
.at( i
).size(); j
++ )
54 delete mShadowTextures
.at( i
).at( j
);
55 for( int i
= 0; i
< mDefaultShadowTextures
.size(); i
++ )
56 delete mDefaultShadowTextures
.at( i
);
58 #ifdef KWIN_HAVE_XRENDER_COMPOSITING
59 for( int i
= 0; i
< mShadowPics
.size(); i
++ )
60 for( int j
= 0; j
< mShadowPics
.at( i
).size(); j
++ )
61 delete mShadowPics
.at( i
).at( j
);
62 for( int i
= 0; i
< mDefaultShadowPics
.size(); i
++ )
63 delete mDefaultShadowPics
.at( i
);
67 void ShadowEffect::reconfigure( ReconfigureFlags
)
69 KConfigGroup conf
= effects
->effectConfig("Shadow");
70 shadowXOffset
= conf
.readEntry( "XOffset", 0 );
71 shadowYOffset
= conf
.readEntry( "YOffset", 3 );
72 shadowOpacity
= conf
.readEntry( "Opacity", 0.25 );
73 shadowFuzzyness
= conf
.readEntry( "Fuzzyness", 10 );
74 shadowSize
= conf
.readEntry( "Size", 5 );
75 intensifyActiveShadow
= conf
.readEntry( "IntensifyActiveShadow", true );
77 forceDecorated
= conf
.readEntry( "forceDecoratedToDefault", false );
78 forceUndecorated
= conf
.readEntry( "forceUndecoratedToDefault", false );
79 forceOther
= conf
.readEntry( "forceOtherToDefault", false );
81 // Load decoration shadow related things
82 bool reconfiguring
= false;
83 if( mShadowQuadTypes
.count() )
85 mShadowQuadTypes
.clear(); // Changed decoration? TODO: Unregister?
86 #ifdef KWIN_HAVE_OPENGL_COMPOSITING
87 if( effects
->compositingType() == OpenGLCompositing
)
89 // Delete any other textures in memory
90 for( int i
= 0; i
< mShadowTextures
.size(); i
++ )
91 for( int j
= 0; j
< mShadowTextures
.at( i
).size(); j
++ )
92 delete mShadowTextures
.at( i
).at( j
);
93 mShadowTextures
.clear();
94 for( int i
= 0; i
< mDefaultShadowTextures
.size(); i
++ )
95 delete mDefaultShadowTextures
.at( i
);
96 mDefaultShadowTextures
.clear();
98 // Create decoration shadows
99 if( effects
->hasDecorationShadows() )
101 QList
< QList
<QImage
> > shadowImages
= effects
->shadowTextures();
102 for( int i
= 0; i
< shadowImages
.size(); i
++ )
104 mShadowQuadTypes
.append( effects
->newWindowQuadType() );
105 QList
<GLTexture
*> textures
;
106 for( int j
= 0; j
< shadowImages
.at( i
).size(); j
++ )
107 textures
.append( new GLTexture( shadowImages
.at( i
).at( j
)));
108 mShadowTextures
.append( textures
);
112 // Create default textures
113 mDefaultShadowQuadType
= effects
->newWindowQuadType(); // TODO: Unregister?
114 QImage
shadowImage( KGlobal::dirs()->findResource( "data", "kwin/shadow-texture.png" ));
115 int hw
= shadowImage
.width() / 2;
116 int hh
= shadowImage
.height() / 2;
117 mDefaultShadowTextures
.append( new GLTexture( shadowImage
.copy( 0, 0, hw
, hh
)));
118 mDefaultShadowTextures
.append( new GLTexture( shadowImage
.copy( hw
, 0, 1, hh
)));
119 mDefaultShadowTextures
.append( new GLTexture( shadowImage
.copy( hw
, 0, hw
, hh
)));
120 mDefaultShadowTextures
.append( new GLTexture( shadowImage
.copy( 0, hh
, hw
, 1 )));
121 mDefaultShadowTextures
.append( new GLTexture( shadowImage
.copy( hw
, hh
, 1, 1 )));
122 mDefaultShadowTextures
.append( new GLTexture( shadowImage
.copy( hw
, hh
, hw
, 1 )));
123 mDefaultShadowTextures
.append( new GLTexture( shadowImage
.copy( 0, hh
, hw
, hh
)));
124 mDefaultShadowTextures
.append( new GLTexture( shadowImage
.copy( hw
, hh
, 1, hh
)));
125 mDefaultShadowTextures
.append( new GLTexture( shadowImage
.copy( hw
, hh
, hw
, hh
)));
128 #ifdef KWIN_HAVE_XRENDER_COMPOSITING
129 if( effects
->compositingType() == XRenderCompositing
)
131 // Delete any other pictures in memory
132 for( int i
= 0; i
< mShadowPics
.size(); i
++ )
133 for( int j
= 0; j
< mShadowPics
.at( i
).size(); j
++ )
134 delete mShadowPics
.at( i
).at( j
);
136 for( int i
= 0; i
< mDefaultShadowPics
.size(); i
++ )
137 delete mDefaultShadowPics
.at( i
);
138 mDefaultShadowPics
.clear();
140 // Create decoration pictures
141 if( effects
->hasDecorationShadows() )
143 QList
< QList
<QImage
> > shadowImages
= effects
->shadowTextures();
144 for( int i
= 0; i
< shadowImages
.size(); i
++ )
146 mShadowQuadTypes
.append( effects
->newWindowQuadType() );
147 QList
<XRenderPicture
*> pictures
;
148 for( int j
= 0; j
< shadowImages
.at( i
).size(); j
++ )
149 pictures
.append( new XRenderPicture( QPixmap::fromImage( shadowImages
.at( i
).at( j
))));
150 mShadowPics
.append( pictures
);
154 // Create default pictures
155 mDefaultShadowQuadType
= effects
->newWindowQuadType(); // TODO: Unregister?
156 QPixmap
shadowPixmap( KGlobal::dirs()->findResource( "data", "kwin/shadow-texture.png" ));
157 shadowPixmap
= shadowPixmap
.scaled( QSize( shadowFuzzyness
* 4, shadowFuzzyness
* 4 ),
158 Qt::IgnoreAspectRatio
, Qt::SmoothTransformation
);
159 int hw
= shadowPixmap
.width() / 2;
160 int hh
= shadowPixmap
.height() / 2;
161 mDefaultShadowPics
.append( new XRenderPicture( shadowPixmap
.copy( 0, 0, hw
, hh
)));
162 mDefaultShadowPics
.append( new XRenderPicture( shadowPixmap
.copy( hw
, 0, 1, hh
)));
163 mDefaultShadowPics
.append( new XRenderPicture( shadowPixmap
.copy( hw
, 0, hw
, hh
)));
164 mDefaultShadowPics
.append( new XRenderPicture( shadowPixmap
.copy( 0, hh
, hw
, 1 )));
165 mDefaultShadowPics
.append( new XRenderPicture( shadowPixmap
.copy( hw
, hh
, 1, 1 )));
166 mDefaultShadowPics
.append( new XRenderPicture( shadowPixmap
.copy( hw
, hh
, hw
, 1 )));
167 mDefaultShadowPics
.append( new XRenderPicture( shadowPixmap
.copy( 0, hh
, hw
, hh
)));
168 mDefaultShadowPics
.append( new XRenderPicture( shadowPixmap
.copy( hw
, hh
, 1, hh
)));
169 mDefaultShadowPics
.append( new XRenderPicture( shadowPixmap
.copy( hw
, hh
, hw
, hh
)));
171 // Apply repeat attribute to all pictures
172 XRenderPictureAttributes pa
;
174 for( int i
= 0; i
< mShadowPics
.size(); i
++ )
175 for( int j
= 0; j
< mShadowPics
.at( i
).size(); j
++ )
176 XRenderChangePicture( display(), *mShadowPics
.at( i
).at( j
), CPRepeat
, &pa
);
177 for( int i
= 0; i
< mDefaultShadowPics
.size(); i
++ )
178 XRenderChangePicture( display(), *mDefaultShadowPics
.at( i
), CPRepeat
, &pa
);
183 { // Force rebuild of all quads to clear their caches
184 foreach( EffectWindow
*w
, effects
->stackingOrder() )
185 w
->buildQuads( true );
189 void ShadowEffect::updateShadowColor()
191 KConfigGroup conf
= effects
->effectConfig("Shadow");
192 shadowColor
= conf
.readEntry( "Color", schemeShadowColor() );
195 QRect
ShadowEffect::shadowRectangle( EffectWindow
* w
, const QRect
& windowRectangle
) const
198 bool shadowDefined
= false;
199 if( effects
->hasDecorationShadows() )
200 { // TODO: This function is called for EVERY damage, we need to cache this
201 // (But how? Decoration shadow can change shape if it wanted to)
202 if( w
->hasDecoration() && !forceDecorated
)
203 { // Decorated windows must be normal windows
204 foreach( const QRect
&r
, w
->shadowQuads( ShadowBorderedActive
))
206 shadowDefined
= true;
210 else if( w
->isNormalWindow() && !forceUndecorated
)
211 { // No decoration on a normal window
212 foreach( const QRect
&r
, w
->shadowQuads( ShadowBorderlessActive
))
214 shadowDefined
= true;
218 else if( !forceOther
)
219 { // All other undecorated windows
220 foreach( const QRect
&r
, w
->shadowQuads( ShadowOther
))
222 shadowDefined
= true;
229 int shadowGrow
= shadowFuzzyness
+ shadowSize
;
230 return windowRectangle
.adjusted( shadowXOffset
- shadowGrow
, shadowYOffset
- shadowGrow
,
231 shadowXOffset
+ shadowGrow
, shadowYOffset
+ shadowGrow
);
233 return windowRectangle
.adjusted(
234 qMin( shadowRect
.x(), qreal(0.0) ),
235 qMin( shadowRect
.y(), qreal(0.0) ),
236 qMax( shadowRect
.x() + shadowRect
.width() - w
->width(), qreal(0.0) ),
237 qMax( shadowRect
.y() + shadowRect
.height() - w
->height(), qreal(0.0) )
241 #ifdef KWIN_HAVE_XRENDER_COMPOSITING
242 static ScreenPaintData gScreenData
;
245 void ShadowEffect::paintScreen( int mask
, QRegion region
, ScreenPaintData
& data
)
248 #ifdef KWIN_HAVE_XRENDER_COMPOSITING
249 if ((mask
& PAINT_SCREEN_TRANSFORMED
) &&
250 (effects
->compositingType() == XRenderCompositing
)) // TODO: copy constructor?
252 gScreenData
.xTranslate
= data
.xTranslate
;
253 gScreenData
.yTranslate
= data
.yTranslate
;
254 gScreenData
.xScale
= data
.xScale
;
255 gScreenData
.yScale
= data
.yScale
;
259 effects
->paintScreen( mask
, region
, data
);
262 drawQueuedShadows( 0 );
265 void ShadowEffect::prePaintWindow( EffectWindow
* w
, WindowPrePaintData
& data
, int time
)
268 data
.paint
|= shadowRectangle( w
, data
.paint
.boundingRect() );
269 effects
->prePaintWindow( w
, data
, time
);
272 void ShadowEffect::drawWindow( EffectWindow
* w
, int mask
, QRegion region
, WindowPaintData
& data
)
274 // Whether the shadow drawing can be delayed or not.
275 bool optimize
= !( mask
& ( PAINT_WINDOW_TRANSFORMED
| PAINT_SCREEN_TRANSFORMED
|
276 PAINT_SCREEN_WITH_TRANSFORMED_WINDOWS
| PAINT_WINDOW_TRANSLUCENT
));
279 // Transformed or translucent windows are drawn bottom-to-top, so
280 // first we need to draw all queued shadows.
281 drawQueuedShadows( w
);
287 // For translucent windows, shadow needs to be drawn before the
289 drawShadow( w
, mask
, region
, data
);
293 // For opaque windows, just schedule the shadow to be drawn later
294 ShadowData
d(w
, data
);
295 d
.clip
= w
->shape().translated( w
->x(), w
->y());
296 if( !shadowDatas
.isEmpty())
297 d
.clip
|= shadowDatas
.last().clip
;
299 foreach( const QRect
&r
, region
.rects() )
300 d
.region
|= shadowRectangle( w
, r
);
302 shadowDatas
.append(d
);
306 effects
->drawWindow( w
, mask
, region
, data
);
309 void ShadowEffect::buildQuads( EffectWindow
* w
, WindowQuadList
& quadList
)
311 bool shadowDefined
= false;
312 if( effects
->hasDecorationShadows() )
314 // TODO: shadowQuads() is allowed to return different quads for
315 // active and inactive shadows. Is implementing it worth
316 // the performance drop?
318 if( w
->hasDecoration() && !forceDecorated
)
319 { // Decorated windows must be normal windows
320 foreach( const QRect
&r
, w
->shadowQuads( ShadowBorderedActive
))
322 shadowDefined
= true;
323 WindowQuad
quad( mShadowQuadTypes
.at( effects
->shadowTextureList( ShadowBorderedActive
)), id
++ );
324 quad
[ 0 ] = WindowVertex( r
.x(), r
.y(), 0, 1 );
325 quad
[ 1 ] = WindowVertex( r
.x() + r
.width(), r
.y(), 1, 1 );
326 quad
[ 2 ] = WindowVertex( r
.x() + r
.width(), r
.y() + r
.height(), 1, 0 );
327 quad
[ 3 ] = WindowVertex( r
.x(), r
.y() + r
.height(), 0, 0 );
328 quadList
.append( quad
);
331 else if( w
->isNormalWindow() && !forceUndecorated
)
332 { // No decoration on a normal window
333 foreach( const QRect
&r
, w
->shadowQuads( ShadowBorderlessActive
))
335 shadowDefined
= true;
336 WindowQuad
quad( mShadowQuadTypes
.at( effects
->shadowTextureList( ShadowBorderlessActive
)), id
++ );
337 quad
[ 0 ] = WindowVertex( r
.x(), r
.y(), 0, 1 );
338 quad
[ 1 ] = WindowVertex( r
.x() + r
.width(), r
.y(), 1, 1 );
339 quad
[ 2 ] = WindowVertex( r
.x() + r
.width(), r
.y() + r
.height(), 1, 0 );
340 quad
[ 3 ] = WindowVertex( r
.x(), r
.y() + r
.height(), 0, 0 );
341 quadList
.append( quad
);
344 else if( !forceOther
)
345 { // All other undecorated windows
346 foreach( const QRect
&r
, w
->shadowQuads( ShadowOther
))
348 shadowDefined
= true;
349 WindowQuad
quad( mShadowQuadTypes
.at( effects
->shadowTextureList( ShadowOther
)), id
++ );
350 quad
[ 0 ] = WindowVertex( r
.x(), r
.y(), 0, 1 );
351 quad
[ 1 ] = WindowVertex( r
.x() + r
.width(), r
.y(), 1, 1 );
352 quad
[ 2 ] = WindowVertex( r
.x() + r
.width(), r
.y() + r
.height(), 1, 0 );
353 quad
[ 3 ] = WindowVertex( r
.x(), r
.y() + r
.height(), 0, 0 );
354 quadList
.append( quad
);
360 //TODO: add config option to not have shadows for menus, etc.
361 // Make our own shadow as the decoration doesn't support it
362 int fuzzy
= shadowFuzzyness
;
363 // Shadow's size must be a least 2*fuzzy in both directions (or the corners will be broken)
364 int width
= qMax( fuzzy
* 2, w
->width() + 2 * shadowSize
);
365 int height
= qMax( fuzzy
* 2, w
->height() + 2 * shadowSize
);
366 double x1
, y1
, x2
, y2
;
369 x1
= shadowXOffset
- shadowSize
+ 0 - fuzzy
;
370 y1
= shadowYOffset
- shadowSize
+ 0 - fuzzy
;
371 x2
= shadowXOffset
- shadowSize
+ 0 + fuzzy
;
372 y2
= shadowYOffset
- shadowSize
+ 0 + fuzzy
;
373 WindowQuad
topLeftQuad( mDefaultShadowQuadType
, id
++ );
374 topLeftQuad
[ 0 ] = WindowVertex( x1
, y1
, 0, 1 );
375 topLeftQuad
[ 1 ] = WindowVertex( x2
, y1
, 1, 1 );
376 topLeftQuad
[ 2 ] = WindowVertex( x2
, y2
, 1, 0 );
377 topLeftQuad
[ 3 ] = WindowVertex( x1
, y2
, 0, 0 );
378 quadList
.append( topLeftQuad
);
380 x1
= shadowXOffset
- shadowSize
+ 0 + fuzzy
;
381 y1
= shadowYOffset
- shadowSize
+ 0 - fuzzy
;
382 x2
= shadowXOffset
- shadowSize
+ width
- fuzzy
;
383 y2
= shadowYOffset
- shadowSize
+ 0 + fuzzy
;
384 WindowQuad
topQuad( mDefaultShadowQuadType
, id
++ );
385 topQuad
[ 0 ] = WindowVertex( x1
, y1
, 0, 1 );
386 topQuad
[ 1 ] = WindowVertex( x2
, y1
, 1, 1 );
387 topQuad
[ 2 ] = WindowVertex( x2
, y2
, 1, 0 );
388 topQuad
[ 3 ] = WindowVertex( x1
, y2
, 0, 0 );
389 quadList
.append( topQuad
);
391 x1
= shadowXOffset
- shadowSize
+ width
- fuzzy
;
392 y1
= shadowYOffset
- shadowSize
+ 0 - fuzzy
;
393 x2
= shadowXOffset
- shadowSize
+ width
+ fuzzy
;
394 y2
= shadowYOffset
- shadowSize
+ 0 + fuzzy
;
395 WindowQuad
topRightQuad( mDefaultShadowQuadType
, id
++ );
396 topRightQuad
[ 0 ] = WindowVertex( x1
, y1
, 0, 1 );
397 topRightQuad
[ 1 ] = WindowVertex( x2
, y1
, 1, 1 );
398 topRightQuad
[ 2 ] = WindowVertex( x2
, y2
, 1, 0 );
399 topRightQuad
[ 3 ] = WindowVertex( x1
, y2
, 0, 0 );
400 quadList
.append( topRightQuad
);
402 x1
= shadowXOffset
- shadowSize
+ 0 - fuzzy
;
403 y1
= shadowYOffset
- shadowSize
+ 0 + fuzzy
;
404 x2
= shadowXOffset
- shadowSize
+ 0 + fuzzy
;
405 y2
= shadowYOffset
- shadowSize
+ height
- fuzzy
;
406 WindowQuad
leftQuad( mDefaultShadowQuadType
, id
++ );
407 leftQuad
[ 0 ] = WindowVertex( x1
, y1
, 0, 1 );
408 leftQuad
[ 1 ] = WindowVertex( x2
, y1
, 1, 1 );
409 leftQuad
[ 2 ] = WindowVertex( x2
, y2
, 1, 0 );
410 leftQuad
[ 3 ] = WindowVertex( x1
, y2
, 0, 0 );
411 quadList
.append( leftQuad
);
413 x1
= shadowXOffset
- shadowSize
+ 0 + fuzzy
;
414 y1
= shadowYOffset
- shadowSize
+ 0 + fuzzy
;
415 x2
= shadowXOffset
- shadowSize
+ width
- fuzzy
;
416 y2
= shadowYOffset
- shadowSize
+ height
- fuzzy
;
417 WindowQuad
contentsQuad( mDefaultShadowQuadType
, id
++ );
418 contentsQuad
[ 0 ] = WindowVertex( x1
, y1
, 0, 1 );
419 contentsQuad
[ 1 ] = WindowVertex( x2
, y1
, 1, 1 );
420 contentsQuad
[ 2 ] = WindowVertex( x2
, y2
, 1, 0 );
421 contentsQuad
[ 3 ] = WindowVertex( x1
, y2
, 0, 0 );
422 quadList
.append( contentsQuad
);
424 x1
= shadowXOffset
- shadowSize
+ width
- fuzzy
;
425 y1
= shadowYOffset
- shadowSize
+ 0 + fuzzy
;
426 x2
= shadowXOffset
- shadowSize
+ width
+ fuzzy
;
427 y2
= shadowYOffset
- shadowSize
+ height
- fuzzy
;
428 WindowQuad
rightQuad( mDefaultShadowQuadType
, id
++ );
429 rightQuad
[ 0 ] = WindowVertex( x1
, y1
, 0, 1 );
430 rightQuad
[ 1 ] = WindowVertex( x2
, y1
, 1, 1 );
431 rightQuad
[ 2 ] = WindowVertex( x2
, y2
, 1, 0 );
432 rightQuad
[ 3 ] = WindowVertex( x1
, y2
, 0, 0 );
433 quadList
.append( rightQuad
);
435 x1
= shadowXOffset
- shadowSize
+ 0 - fuzzy
;
436 y1
= shadowYOffset
- shadowSize
+ height
- fuzzy
;
437 x2
= shadowXOffset
- shadowSize
+ 0 + fuzzy
;
438 y2
= shadowYOffset
- shadowSize
+ height
+ fuzzy
;
439 WindowQuad
bottomLeftQuad( mDefaultShadowQuadType
, id
++ );
440 bottomLeftQuad
[ 0 ] = WindowVertex( x1
, y1
, 0, 1 );
441 bottomLeftQuad
[ 1 ] = WindowVertex( x2
, y1
, 1, 1 );
442 bottomLeftQuad
[ 2 ] = WindowVertex( x2
, y2
, 1, 0 );
443 bottomLeftQuad
[ 3 ] = WindowVertex( x1
, y2
, 0, 0 );
444 quadList
.append( bottomLeftQuad
);
446 x1
= shadowXOffset
- shadowSize
+ 0 + fuzzy
;
447 y1
= shadowYOffset
- shadowSize
+ height
- fuzzy
;
448 x2
= shadowXOffset
- shadowSize
+ width
- fuzzy
;
449 y2
= shadowYOffset
- shadowSize
+ height
+ fuzzy
;
450 WindowQuad
bottomQuad( mDefaultShadowQuadType
, id
++ );
451 bottomQuad
[ 0 ] = WindowVertex( x1
, y1
, 0, 1 );
452 bottomQuad
[ 1 ] = WindowVertex( x2
, y1
, 1, 1 );
453 bottomQuad
[ 2 ] = WindowVertex( x2
, y2
, 1, 0 );
454 bottomQuad
[ 3 ] = WindowVertex( x1
, y2
, 0, 0 );
455 quadList
.append( bottomQuad
);
457 x1
= shadowXOffset
- shadowSize
+ width
- fuzzy
;
458 y1
= shadowYOffset
- shadowSize
+ height
- fuzzy
;
459 x2
= shadowXOffset
- shadowSize
+ width
+ fuzzy
;
460 y2
= shadowYOffset
- shadowSize
+ height
+ fuzzy
;
461 WindowQuad
bottomRightQuad( mDefaultShadowQuadType
, id
++ );
462 bottomRightQuad
[ 0 ] = WindowVertex( x1
, y1
, 0, 1 );
463 bottomRightQuad
[ 1 ] = WindowVertex( x2
, y1
, 1, 1 );
464 bottomRightQuad
[ 2 ] = WindowVertex( x2
, y2
, 1, 0 );
465 bottomRightQuad
[ 3 ] = WindowVertex( x1
, y2
, 0, 0 );
466 quadList
.append( bottomRightQuad
);
467 } // This is called for menus, tooltips, windows where the user has disabled borders and shaped windows
469 effects
->buildQuads( w
, quadList
);
472 QRect
ShadowEffect::transformWindowDamage( EffectWindow
* w
, const QRect
& r
)
475 return effects
->transformWindowDamage( w
, r
);
476 QRect r2
= r
| shadowRectangle( w
, r
);
477 return effects
->transformWindowDamage( w
, r2
);
480 void ShadowEffect::windowClosed( EffectWindow
* c
)
482 effects
->addRepaint( shadowRectangle( c
, c
->geometry() ));
485 bool ShadowEffect::useShadow( EffectWindow
* w
) const
487 return !w
->isDeleted() && !w
->isDesktop() && !w
->isDock()
488 // popups may have shadow even if shaped, their shape is almost rectangular
489 && ( !w
->hasOwnShape() || w
->isDropdownMenu() || w
->isPopupMenu() || w
->isComboBox());
492 void ShadowEffect::addQuadVertices(QVector
<float>& verts
, float x1
, float y1
, float x2
, float y2
) const
500 void ShadowEffect::drawQueuedShadows( EffectWindow
* behindWindow
)
502 QList
<ShadowData
> newShadowDatas
;
503 QList
<ShadowData
> thisTime
;
504 EffectWindowList stack
= effects
->stackingOrder();
505 foreach( const ShadowData
&d
, shadowDatas
)
507 // If behindWindow is given then only render shadows of the windows
508 // that are behind that window.
509 if( !behindWindow
|| stack
.indexOf(d
.w
) < stack
.indexOf(behindWindow
))
512 newShadowDatas
.append(d
);
514 if( thisTime
.count() )
515 { // Render them in stacking order
516 foreach( EffectWindow
*w
, stack
)
517 for( int i
= 0; i
< thisTime
.size(); i
++ )
518 { // Cannot use foreach() due to thisTime.removeOne()
519 const ShadowData d
= thisTime
.at(i
);
522 drawShadow( d
.w
, d
.mask
,
523 d
.region
.subtracted( d
.clip
), d
.data
);
524 thisTime
.removeAt( i
);
529 // Render the rest on the top (For menus, etc.)
530 foreach( const ShadowData
&d
, thisTime
)
531 drawShadow( d
.w
, d
.mask
, d
.region
.subtracted( d
.clip
), d
.data
);
532 shadowDatas
= newShadowDatas
;
535 // Modified version of SceneOpenGL::Window::prepareRenderStates() from scene_opengl.cpp
536 void ShadowEffect::prepareRenderStates( GLTexture
*texture
, double opacity
, double brightness
, double saturation
)
538 #ifdef KWIN_HAVE_OPENGL_COMPOSITING
539 // setup blending of transparent windows
540 glPushAttrib( GL_ENABLE_BIT
);
541 /*if( saturation != 1.0 && texture->saturationSupported() )
543 // First we need to get the color from [0; 1] range to [0.5; 1] range
544 glActiveTexture( GL_TEXTURE0 );
545 glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE );
546 glTexEnvi( GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_INTERPOLATE );
547 glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_TEXTURE );
548 glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR );
549 glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_CONSTANT );
550 glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR );
551 glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE2_RGB, GL_CONSTANT );
552 glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND2_RGB, GL_SRC_ALPHA );
553 const float scale_constant[] = { 1.0, 1.0, 1.0, 0.5 };
554 glTexEnvfv( GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, scale_constant );
557 // Then we take dot product of the result of previous pass and
558 // saturation_constant. This gives us completely unsaturated
560 // Note that both operands have to be in range [0.5; 1] since opengl
561 // automatically substracts 0.5 from them
562 glActiveTexture( GL_TEXTURE1 );
563 float saturation_constant[] = { 0.5 + 0.5*0.30, 0.5 + 0.5*0.59, 0.5 + 0.5*0.11, saturation };
564 glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE );
565 glTexEnvi( GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_DOT3_RGB );
566 glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_PREVIOUS );
567 glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR );
568 glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_CONSTANT );
569 glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR );
570 glTexEnvfv( GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, saturation_constant );
573 // Finally we need to interpolate between the original image and the
574 // greyscale image to get wanted level of saturation
575 glActiveTexture( GL_TEXTURE2 );
576 glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE );
577 glTexEnvi( GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_INTERPOLATE );
578 glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_TEXTURE0 );
579 glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR );
580 glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_PREVIOUS );
581 glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR );
582 glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE2_RGB, GL_CONSTANT );
583 glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND2_RGB, GL_SRC_ALPHA );
584 glTexEnvfv( GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, saturation_constant );
585 // Also replace alpha by primary color's alpha here
586 glTexEnvi( GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE );
587 glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_PRIMARY_COLOR );
588 glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA );
589 // And make primary color contain the wanted opacity
590 glColor4f( opacity, opacity, opacity, opacity );
593 if( brightness != 1.0 )
595 glActiveTexture( GL_TEXTURE3 );
596 glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE );
597 glTexEnvi( GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE );
598 glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_PREVIOUS );
599 glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR );
600 glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_PRIMARY_COLOR );
601 glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR );
602 // The color has to be multiplied by both opacity and brightness
603 float opacityByBrightness = opacity * brightness;
604 glColor4f( opacityByBrightness, opacityByBrightness, opacityByBrightness, opacity );
605 glTexEnvi( GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE );
606 glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_PREVIOUS );
607 glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA );
611 glActiveTexture(GL_TEXTURE0 );
613 else*/ if( opacity
!= 1.0 || brightness
!= 1.0 )
615 // the window is additionally configured to have its opacity adjusted,
617 float opacityByBrightness
= opacity
* brightness
;
618 glTexEnvi( GL_TEXTURE_ENV
, GL_TEXTURE_ENV_MODE
, GL_MODULATE
);
619 glColor4f( opacityByBrightness
, opacityByBrightness
, opacityByBrightness
, opacity
);
624 // Modified version of SceneOpenGL::Window::restoreRenderStates() from scene_opengl.cpp
625 void ShadowEffect::restoreRenderStates( GLTexture
*texture
, double opacity
, double brightness
, double saturation
)
627 #ifdef KWIN_HAVE_OPENGL_COMPOSITING
628 if( opacity
!= 1.0 || saturation
!= 1.0 || brightness
!= 1.0 )
630 /*if( saturation != 1.0 && texture->saturationSupported())
632 glActiveTexture(GL_TEXTURE3);
633 glDisable( texture->target() );
634 glActiveTexture(GL_TEXTURE2);
635 glDisable( texture->target() );
636 glActiveTexture(GL_TEXTURE1);
637 glDisable( texture->target() );
638 glActiveTexture(GL_TEXTURE0);
640 glTexEnvi( GL_TEXTURE_ENV
, GL_TEXTURE_ENV_MODE
, GL_REPLACE
);
641 glColor4f( 0, 0, 0, 0 );
644 glPopAttrib(); // ENABLE_BIT
648 void ShadowEffect::drawShadowQuadOpenGL( GLTexture
*texture
, QVector
<float> verts
, QVector
<float> texCoords
,
649 QColor color
, QRegion region
, float opacity
, float brightness
, float saturation
)
651 #ifdef KWIN_HAVE_OPENGL_COMPOSITING
652 if( color
.isValid() )
653 glColor4f( color
.redF(), color
.greenF(), color
.blueF(), 1.0 );
655 glColor4f( 1.0, 1.0, 1.0, 1.0 );
656 glTexEnvi(GL_TEXTURE_ENV
, GL_TEXTURE_ENV_MODE
, GL_MODULATE
);
657 prepareRenderStates( texture
, opacity
, brightness
, saturation
);
659 texture
->enableNormalizedTexCoords();
660 glTexParameteri( GL_TEXTURE_2D
, GL_TEXTURE_WRAP_S
, GL_CLAMP_TO_EDGE
);
661 glTexParameteri( GL_TEXTURE_2D
, GL_TEXTURE_WRAP_T
, GL_CLAMP_TO_EDGE
);
662 renderGLGeometry( region
, 4, verts
.data(), texCoords
.data() );
663 texture
->disableNormalizedTexCoords();
665 restoreRenderStates( texture
, opacity
, brightness
, saturation
);
669 void ShadowEffect::drawShadowQuadXRender( XRenderPicture
*picture
, QRect rect
, float xScale
, float yScale
,
670 QColor color
, float opacity
, float brightness
, float saturation
)
672 #ifdef KWIN_HAVE_XRENDER_COMPOSITING
674 if( color
.isValid() )
675 xc
= preMultiply( color
, opacity
);
677 xc
= preMultiply( QColor( 255, 255, 255 ), opacity
);
678 XRenderPicture fill
= xRenderFill( &xc
);
681 if( xScale
!= 1.0 || yScale
!= 1.0 )
683 XTransform xform
= {{
684 { XDoubleToFixed( 1.0 / xScale
), XDoubleToFixed( 0.0 ), XDoubleToFixed( 0.0 ) },
685 { XDoubleToFixed( 0.0 ), XDoubleToFixed( 1.0 / yScale
), XDoubleToFixed( 0.0 ) },
686 { XDoubleToFixed( 0.0 ), XDoubleToFixed( 0.0 ), XDoubleToFixed( 1.0 ) }
688 XRenderSetPictureTransform( display(), *picture
, &xform
);
692 // TODO: This always uses the fast filter, detect when to use smooth instead
693 if( color
.isValid() )
694 XRenderComposite( display(), PictOpOver
, fill
, *picture
, effects
->xrenderBufferPicture(), 0, 0, 0, 0,
695 rect
.x(), rect
.y(), rect
.width(), rect
.height() );
697 XRenderComposite( display(), PictOpOver
, *picture
, fill
, effects
->xrenderBufferPicture(), 0, 0, 0, 0,
698 rect
.x(), rect
.y(), rect
.width(), rect
.height() );
700 // Fake brightness by overlaying black
701 // Cannot use XRenderFillRectangle() due to ARGB
702 XRenderColor col
= { 0, 0, 0, 0xffff * ( 1 - brightness
) * opacity
};
703 fill
= xRenderFill( &col
);
704 XRenderComposite( display(), PictOpOver
, fill
, *picture
, effects
->xrenderBufferPicture(), 0, 0, 0, 0,
705 rect
.x(), rect
.y(), rect
.width(), rect
.height() );
707 // Return to scale to 1.0
708 if( xScale
!= 1.0 || yScale
!= 1.0 )
710 XTransform xform
= {{
711 { XDoubleToFixed( 1.0 ), XDoubleToFixed( 0.0 ), XDoubleToFixed( 0.0 ) },
712 { XDoubleToFixed( 0.0 ), XDoubleToFixed( 1.0 ), XDoubleToFixed( 0.0 ) },
713 { XDoubleToFixed( 0.0 ), XDoubleToFixed( 0.0 ), XDoubleToFixed( 1.0 ) }
715 XRenderSetPictureTransform( display(), *picture
, &xform
);
720 void ShadowEffect::drawShadow( EffectWindow
* window
, int mask
, QRegion region
, const WindowPaintData
& data
)
722 // Don't allow windows to cast shadows on other displays
724 for( int screen
= 0; screen
< effects
->numScreens(); screen
++ )
726 QRect screenGeom
= effects
->clientArea( ScreenArea
, screen
, 0 );
727 if( !( window
->geometry() & screenGeom
).isNull() )
728 clipperGeom
|= screenGeom
;
730 PaintClipper
pc( clipperGeom
);
732 #ifdef KWIN_HAVE_OPENGL_COMPOSITING
733 if( effects
->compositingType() == OpenGLCompositing
)
735 glPushAttrib( GL_CURRENT_BIT
| GL_ENABLE_BIT
| GL_TEXTURE_BIT
);
736 glEnable( GL_BLEND
);
737 glBlendFunc( GL_SRC_ALPHA
, GL_ONE_MINUS_SRC_ALPHA
);
739 foreach( const WindowQuad
&quad
, data
.quads
)
741 if( !mShadowQuadTypes
.contains( quad
.type() ) && quad
.type() != mDefaultShadowQuadType
)
742 continue; // Not a shadow quad
746 // Use the window's top-left as the origin
747 glTranslatef( window
->x(), window
->y(), 0 );
748 if( mask
& PAINT_WINDOW_TRANSFORMED
)
749 glTranslatef( data
.xTranslate
, data
.yTranslate
, data
.zTranslate
);
750 if(( mask
& PAINT_WINDOW_TRANSFORMED
) && ( data
.xScale
!= 1 || data
.yScale
!= 1 ))
751 glScalef( data
.xScale
, data
.yScale
, data
.zScale
);
752 if(( mask
& PAINT_WINDOW_TRANSFORMED
) && data
.rotation
)
754 glTranslatef( data
.rotation
->xRotationPoint
,
755 data
.rotation
->yRotationPoint
,
756 data
.rotation
->zRotationPoint
);
760 switch( data
.rotation
->axis
)
762 case RotationData::XAxis
:
765 case RotationData::YAxis
:
768 case RotationData::ZAxis
:
772 glRotatef( data
.rotation
->angle
, xAxis
, yAxis
, zAxis
);
773 glTranslatef( -data
.rotation
->xRotationPoint
,
774 -data
.rotation
->yRotationPoint
,
775 -data
.rotation
->zRotationPoint
);
778 // Create our polygon
779 QVector
<float> verts
, texcoords
;
781 texcoords
.reserve(8);
782 verts
<< quad
[0].x() << quad
[0].y();
783 verts
<< quad
[1].x() << quad
[1].y();
784 verts
<< quad
[2].x() << quad
[2].y();
785 verts
<< quad
[3].x() << quad
[3].y();
786 texcoords
<< quad
[0].textureX() << quad
[0].textureY();
787 texcoords
<< quad
[1].textureX() << quad
[1].textureY();
788 texcoords
<< quad
[2].textureX() << quad
[2].textureY();
789 texcoords
<< quad
[3].textureX() << quad
[3].textureY();
791 // Work out which texture to use
792 int texture
= mShadowQuadTypes
.indexOf( quad
.type() );
793 if( texture
!= -1 && texture
< mShadowTextures
.size() ) // TODO: Needed?
796 // Cheat a little, assume the active and inactive shadows have identical quads
797 if( effects
->hasDecorationShadows() )
799 if( window
->hasDecoration() &&
800 effects
->shadowTextureList( ShadowBorderedActive
) == texture
)
801 { // Decorated windows
803 drawShadowQuadOpenGL( mShadowTextures
.at( texture
).at( quad
.id() ),
804 verts
, texcoords
, QColor(), region
,
805 data
.opacity
* window
->shadowOpacity( ShadowBorderedActive
),
806 data
.brightness
* window
->shadowBrightness( ShadowBorderedActive
),
807 data
.saturation
* window
->shadowSaturation( ShadowBorderedActive
));
810 texture
= effects
->shadowTextureList( ShadowBorderedInactive
);
811 drawShadowQuadOpenGL( mShadowTextures
.at( texture
).at( quad
.id() ),
812 verts
, texcoords
, QColor(), region
,
813 data
.opacity
* window
->shadowOpacity( ShadowBorderedInactive
),
814 data
.brightness
* window
->shadowBrightness( ShadowBorderedInactive
),
815 data
.saturation
* window
->shadowSaturation( ShadowBorderedInactive
));
817 else if( effects
->shadowTextureList( ShadowBorderlessActive
) == texture
)
818 { // Decoration-less normal windows
819 if( effects
->activeWindow() == window
)
821 drawShadowQuadOpenGL( mShadowTextures
.at( texture
).at( quad
.id() ),
822 verts
, texcoords
, QColor(), region
,
823 data
.opacity
* window
->shadowOpacity( ShadowBorderlessActive
),
824 data
.brightness
* window
->shadowBrightness( ShadowBorderlessActive
),
825 data
.saturation
* window
->shadowSaturation( ShadowBorderlessActive
));
829 texture
= effects
->shadowTextureList( ShadowBorderlessInactive
);
830 drawShadowQuadOpenGL( mShadowTextures
.at( texture
).at( quad
.id() ),
831 verts
, texcoords
, QColor(), region
,
832 data
.opacity
* window
->shadowOpacity( ShadowBorderlessInactive
),
833 data
.brightness
* window
->shadowBrightness( ShadowBorderlessInactive
),
834 data
.saturation
* window
->shadowSaturation( ShadowBorderlessInactive
));
839 drawShadowQuadOpenGL( mShadowTextures
.at( texture
).at( quad
.id() ),
840 verts
, texcoords
, QColor(), region
,
841 data
.opacity
* window
->shadowOpacity( ShadowOther
),
842 data
.brightness
* window
->shadowBrightness( ShadowOther
),
843 data
.saturation
* window
->shadowSaturation( ShadowOther
));
847 if( quad
.type() == mDefaultShadowQuadType
)
849 float opacity
= shadowOpacity
;
850 if( intensifyActiveShadow
&& window
== effects
->activeWindow() )
851 opacity
= 1 - ( 1 - shadowOpacity
) * ( 1 - shadowOpacity
);
853 drawShadowQuadOpenGL( mDefaultShadowTextures
.at( quad
.id() ),
854 verts
, texcoords
, shadowColor
, region
,
855 data
.opacity
* opacity
,
866 #ifdef KWIN_HAVE_XRENDER_COMPOSITING
867 if( effects
->compositingType() == XRenderCompositing
)
869 XRenderSetPictureClipRegion( display(), effects
->xrenderBufferPicture(), region
.handle() );
871 foreach( const WindowQuad
&quad
, data
.quads
)
873 if( !mShadowQuadTypes
.contains( quad
.type() ) && quad
.type() != mDefaultShadowQuadType
)
874 continue; // Not a shadow quad
876 // Determine transformed quad position
877 QRect windowRect
= window
->geometry();
880 float xTranslate
= 0.0;
881 float yTranslate
= 0.0;
882 if( mask
& PAINT_SCREEN_TRANSFORMED
)
884 xScale
= gScreenData
.xScale
;
885 yScale
= gScreenData
.yScale
;
886 xTranslate
+= ( xScale
- 1.0 ) * windowRect
.x() + gScreenData
.xTranslate
;
887 yTranslate
+= ( yScale
- 1.0 ) * windowRect
.y() + gScreenData
.yTranslate
;
889 if( mask
& PAINT_WINDOW_TRANSFORMED
)
891 xTranslate
+= xScale
* data
.xTranslate
;
892 yTranslate
+= yScale
* data
.yTranslate
;
893 xScale
*= data
.xScale
;
894 yScale
*= data
.yScale
;
897 window
->x() + quad
[0].x() * xScale
+ xTranslate
,
898 window
->y() + quad
[0].y() * yScale
+ yTranslate
,
899 ( quad
[2].x() - quad
[0].x() ) * xScale
,
900 ( quad
[2].y() - quad
[0].y() ) * yScale
);
902 // Work out which texture to use
903 int texture
= mShadowQuadTypes
.indexOf( quad
.type() );
907 // Cheat a little, assume the active and inactive shadows have identical quads
908 if( effects
->hasDecorationShadows() )
910 if( window
->hasDecoration() &&
911 effects
->shadowTextureList( ShadowBorderedActive
) == texture
)
912 { // Decorated windows
914 drawShadowQuadXRender( mShadowPics
.at( texture
).at( quad
.id() ), quadRect
,
915 xScale
, yScale
, QColor(),
916 data
.opacity
* window
->shadowOpacity( ShadowBorderedActive
),
917 data
.brightness
* window
->shadowBrightness( ShadowBorderedActive
),
918 data
.saturation
* window
->shadowSaturation( ShadowBorderedActive
));
921 texture
= effects
->shadowTextureList( ShadowBorderedInactive
);
922 drawShadowQuadXRender( mShadowPics
.at( texture
).at( quad
.id() ), quadRect
,
923 xScale
, yScale
, QColor(),
924 data
.opacity
* window
->shadowOpacity( ShadowBorderedInactive
),
925 data
.brightness
* window
->shadowBrightness( ShadowBorderedInactive
),
926 data
.saturation
* window
->shadowSaturation( ShadowBorderedInactive
));
928 else if( effects
->shadowTextureList( ShadowBorderlessActive
) == texture
)
929 { // Decoration-less normal windows
930 if( effects
->activeWindow() == window
)
932 drawShadowQuadXRender( mShadowPics
.at( texture
).at( quad
.id() ), quadRect
,
933 xScale
, yScale
, QColor(),
934 data
.opacity
* window
->shadowOpacity( ShadowBorderlessActive
),
935 data
.brightness
* window
->shadowBrightness( ShadowBorderlessActive
),
936 data
.saturation
* window
->shadowSaturation( ShadowBorderlessActive
));
940 texture
= effects
->shadowTextureList( ShadowBorderedInactive
);
941 drawShadowQuadXRender( mShadowPics
.at( texture
).at( quad
.id() ), quadRect
,
942 xScale
, yScale
, QColor(),
943 data
.opacity
* window
->shadowOpacity( ShadowBorderlessInactive
),
944 data
.brightness
* window
->shadowBrightness( ShadowBorderlessInactive
),
945 data
.saturation
* window
->shadowSaturation( ShadowBorderlessInactive
));
950 drawShadowQuadXRender( mShadowPics
.at( texture
).at( quad
.id() ), quadRect
,
951 xScale
, yScale
, QColor(),
952 data
.opacity
* window
->shadowOpacity( ShadowOther
),
953 data
.brightness
* window
->shadowBrightness( ShadowOther
),
954 data
.saturation
* window
->shadowSaturation( ShadowOther
));
958 if( quad
.type() == mDefaultShadowQuadType
)
960 float opacity
= shadowOpacity
;
961 if( intensifyActiveShadow
&& window
== effects
->activeWindow() )
962 opacity
= 1 - ( 1 - shadowOpacity
) * ( 1 - shadowOpacity
);
964 drawShadowQuadXRender( mDefaultShadowPics
.at( quad
.id() ), quadRect
, xScale
, yScale
,
965 shadowColor
, opacity
* data
.opacity
, data
.brightness
, data
.saturation
);