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>
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
19 *********************************************************************/
23 #include <kwinglutils.h>
25 #include <kconfiggroup.h>
27 #include <KStandardDirs>
32 KWIN_EFFECT( shadow
, ShadowEffect
)
34 ShadowEffect::ShadowEffect()
36 KConfigGroup conf
= effects
->effectConfig("Shadow");
37 shadowXOffset
= conf
.readEntry( "XOffset", 0 );
38 shadowYOffset
= conf
.readEntry( "YOffset", 3 );
39 shadowOpacity
= conf
.readEntry( "Opacity", 0.25 );
40 shadowFuzzyness
= conf
.readEntry( "Fuzzyness", 10 );
41 shadowSize
= conf
.readEntry( "Size", 5 );
42 intensifyActiveShadow
= conf
.readEntry( "IntensifyActiveShadow", true );
44 QString shadowtexture
= KGlobal::dirs()->findResource("data", "kwin/shadow-texture.png");
45 mShadowTexture
= new GLTexture(shadowtexture
);
48 QRect
ShadowEffect::shadowRectangle(const QRect
& windowRectangle
) const
50 int shadowGrow
= shadowFuzzyness
+ shadowSize
;
51 return windowRectangle
.adjusted( shadowXOffset
- shadowGrow
, shadowYOffset
- shadowGrow
,
52 shadowXOffset
+ shadowGrow
, shadowYOffset
+ shadowGrow
);
55 void ShadowEffect::paintScreen( int mask
, QRegion region
, ScreenPaintData
& data
)
60 effects
->paintScreen( mask
, region
, data
);
63 drawQueuedShadows( 0 );
66 void ShadowEffect::prePaintWindow( EffectWindow
* w
, WindowPrePaintData
& data
, int time
)
70 data
.paint
|= shadowRectangle( data
.paint
.boundingRect() );
72 effects
->prePaintWindow( w
, data
, time
);
75 void ShadowEffect::drawWindow( EffectWindow
* w
, int mask
, QRegion region
, WindowPaintData
& data
)
77 // Whether the shadow drawing can be delayed or not.
78 bool optimize
= !( mask
& ( PAINT_WINDOW_TRANSFORMED
| PAINT_SCREEN_TRANSFORMED
|
79 PAINT_SCREEN_WITH_TRANSFORMED_WINDOWS
| PAINT_WINDOW_TRANSLUCENT
));
82 // Transformed or translucent windows are drawn bottom-to-top, so
83 // first we need to draw all queued shadows.
84 drawQueuedShadows( w
);
90 // For translucent windows, shadow needs to be drawn before the
92 drawShadow( w
, mask
, region
, data
);
96 // For opaque windows, just schedule the shadow to be drawn later
97 ShadowData
d(w
, data
);
98 d
.clip
= w
->shape().translated( w
->x(), w
->y());
99 if( !shadowDatas
.isEmpty())
100 d
.clip
|= shadowDatas
.last().clip
;
102 foreach(QRect r
, region
.rects())
103 d
.region
|= shadowRectangle(r
);
105 shadowDatas
.append(d
);
109 effects
->drawWindow( w
, mask
, region
, data
);
112 QRect
ShadowEffect::transformWindowDamage( EffectWindow
* w
, const QRect
& r
)
115 return effects
->transformWindowDamage( w
, r
);
116 QRect r2
= r
| shadowRectangle( r
);
117 return effects
->transformWindowDamage( w
, r2
);
120 void ShadowEffect::windowClosed( EffectWindow
* c
)
122 effects
->addRepaint( shadowRectangle( c
->geometry() ));
125 bool ShadowEffect::useShadow( EffectWindow
* w
) const
127 return !w
->isDeleted() && !w
->isDesktop() && !w
->isDock() && !w
->hasOwnShape();
130 void ShadowEffect::addQuadVertices(QVector
<float>& verts
, float x1
, float y1
, float x2
, float y2
) const
138 void ShadowEffect::drawQueuedShadows( EffectWindow
* behindWindow
)
140 QList
<ShadowData
> newShadowDatas
;
141 EffectWindowList stack
= effects
->stackingOrder();
142 foreach( ShadowData d
, shadowDatas
)
144 // If behindWindow is given then only render shadows of the windows
145 // that are behind that window.
146 if( !behindWindow
|| stack
.indexOf(d
.w
) < stack
.indexOf(behindWindow
))
148 drawShadow( d
.w
, d
.mask
, d
.region
.subtracted( d
.clip
), d
.data
);
152 newShadowDatas
.append(d
);
155 shadowDatas
= newShadowDatas
;
158 void ShadowEffect::drawShadow( EffectWindow
* window
, int mask
, QRegion region
, WindowPaintData
& data
)
160 glPushAttrib( GL_CURRENT_BIT
| GL_ENABLE_BIT
| GL_TEXTURE_BIT
);
161 glEnable( GL_BLEND
);
162 glBlendFunc( GL_SRC_ALPHA
, GL_ONE_MINUS_SRC_ALPHA
);
164 int fuzzy
= shadowFuzzyness
;
165 // Shadow's size must be a least 2*fuzzy in both directions (or the corners will be broken)
166 int w
= qMax(fuzzy
*2, window
->width() + 2*shadowSize
);
167 int h
= qMax(fuzzy
*2, window
->height() + 2*shadowSize
);
170 if( mask
& PAINT_WINDOW_TRANSFORMED
)
171 glTranslatef( data
.xTranslate
, data
.yTranslate
, 0 );
172 glTranslatef( window
->x() + shadowXOffset
- qMax(0, w
- window
->width()) / 2.0,
173 window
->y() + shadowYOffset
- qMax(0, h
- window
->height()) / 2.0, 0 );
174 if(( mask
& PAINT_WINDOW_TRANSFORMED
) && ( data
.xScale
!= 1 || data
.yScale
!= 1 ))
175 glScalef( data
.xScale
, data
.yScale
, 1 );
177 QVector
<float> verts
, texcoords
;
179 texcoords
.reserve(80);
181 addQuadVertices(verts
, 0 + fuzzy
, 0 + fuzzy
, w
- fuzzy
, h
- fuzzy
);
182 addQuadVertices(texcoords
, 0.5, 0.5, 0.5, 0.5);
185 addQuadVertices(verts
, 0 - fuzzy
, 0 + fuzzy
, 0 + fuzzy
, h
- fuzzy
);
186 addQuadVertices(texcoords
, 0.0, 0.5, 0.5, 0.5);
188 addQuadVertices(verts
, 0 + fuzzy
, 0 - fuzzy
, w
- fuzzy
, 0 + fuzzy
);
189 addQuadVertices(texcoords
, 0.5, 0.0, 0.5, 0.5);
191 addQuadVertices(verts
, w
- fuzzy
, 0 + fuzzy
, w
+ fuzzy
, h
- fuzzy
);
192 addQuadVertices(texcoords
, 0.5, 0.5, 1.0, 0.5);
194 addQuadVertices(verts
, 0 + fuzzy
, h
- fuzzy
, w
- fuzzy
, h
+ fuzzy
);
195 addQuadVertices(texcoords
, 0.5, 0.5, 0.5, 1.0);
198 addQuadVertices(verts
, 0 - fuzzy
, 0 - fuzzy
, 0 + fuzzy
, 0 + fuzzy
);
199 addQuadVertices(texcoords
, 0.0, 0.0, 0.5, 0.5);
201 addQuadVertices(verts
, w
- fuzzy
, 0 - fuzzy
, w
+ fuzzy
, 0 + fuzzy
);
202 addQuadVertices(texcoords
, 0.5, 0.0, 1.0, 0.5);
204 addQuadVertices(verts
, 0 - fuzzy
, h
- fuzzy
, 0 + fuzzy
, h
+ fuzzy
);
205 addQuadVertices(texcoords
, 0.0, 0.5, 0.5, 1.0);
207 addQuadVertices(verts
, w
- fuzzy
, h
- fuzzy
, w
+ fuzzy
, h
+ fuzzy
);
208 addQuadVertices(texcoords
, 0.5, 0.5, 1.0, 1.0);
210 mShadowTexture
->bind();
211 // Take the transparency settings and window's transparency into account.
212 // Also make the shadow more transparent if we've made it bigger
213 float opacity
= shadowOpacity
;
214 if( intensifyActiveShadow
&& window
== effects
->activeWindow() )
216 opacity
= 1 - (1 - shadowOpacity
)*(1 - shadowOpacity
);
218 glColor4f(0, 0, 0, opacity
* data
.opacity
* (window
->width() / (double)w
) * (window
->height() / (double)h
));
219 glTexEnvi(GL_TEXTURE_ENV
, GL_TEXTURE_ENV_MODE
, GL_MODULATE
);
220 // We have two elements per vertex in the verts array
221 int verticesCount
= verts
.count() / 2;
222 renderGLGeometry( region
, verticesCount
, verts
.data(), texcoords
.data() );
223 mShadowTexture
->unbind();