Make a branch to make krunner Good Enough For Aaron™.
[kdebase/uwolfer.git] / workspace / kwin / effects / shadow.cpp
blobdbac01d9c0bd08644b24b2190aea24f1875a4d99
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 *********************************************************************/
21 #include "shadow.h"
23 #include <kwinglutils.h>
25 #include <kconfiggroup.h>
26 #include <kdebug.h>
27 #include <KStandardDirs>
29 namespace KWin
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 )
57 shadowDatas.clear();
59 // Draw windows
60 effects->paintScreen( mask, region, data );
62 // Draw shadows
63 drawQueuedShadows( 0 );
66 void ShadowEffect::prePaintWindow( EffectWindow* w, WindowPrePaintData& data, int time )
68 if( useShadow( w ))
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 ));
80 if( !optimize )
82 // Transformed or translucent windows are drawn bottom-to-top, so
83 // first we need to draw all queued shadows.
84 drawQueuedShadows( w );
86 if( useShadow( w ))
88 if( !optimize )
90 // For translucent windows, shadow needs to be drawn before the
91 // window itself.
92 drawShadow( w, mask, region, data );
94 else
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;
101 d.mask = mask;
102 foreach(QRect r, region.rects())
103 d.region |= shadowRectangle(r);
104 d.region &= region;
105 shadowDatas.append(d);
109 effects->drawWindow( w, mask, region, data );
112 QRect ShadowEffect::transformWindowDamage( EffectWindow* w, const QRect& r )
114 if( !useShadow( w ))
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
132 verts << x1 << y1;
133 verts << x1 << y2;
134 verts << x2 << y2;
135 verts << x2 << y1;
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 );
150 else
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);
169 glPushMatrix();
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;
178 verts.reserve(80);
179 texcoords.reserve(80);
180 // center
181 addQuadVertices(verts, 0 + fuzzy, 0 + fuzzy, w - fuzzy, h - fuzzy);
182 addQuadVertices(texcoords, 0.5, 0.5, 0.5, 0.5);
183 // sides
184 // left
185 addQuadVertices(verts, 0 - fuzzy, 0 + fuzzy, 0 + fuzzy, h - fuzzy);
186 addQuadVertices(texcoords, 0.0, 0.5, 0.5, 0.5);
187 // top
188 addQuadVertices(verts, 0 + fuzzy, 0 - fuzzy, w - fuzzy, 0 + fuzzy);
189 addQuadVertices(texcoords, 0.5, 0.0, 0.5, 0.5);
190 // right
191 addQuadVertices(verts, w - fuzzy, 0 + fuzzy, w + fuzzy, h - fuzzy);
192 addQuadVertices(texcoords, 0.5, 0.5, 1.0, 0.5);
193 // bottom
194 addQuadVertices(verts, 0 + fuzzy, h - fuzzy, w - fuzzy, h + fuzzy);
195 addQuadVertices(texcoords, 0.5, 0.5, 0.5, 1.0);
196 // corners
197 // top-left
198 addQuadVertices(verts, 0 - fuzzy, 0 - fuzzy, 0 + fuzzy, 0 + fuzzy);
199 addQuadVertices(texcoords, 0.0, 0.0, 0.5, 0.5);
200 // top-right
201 addQuadVertices(verts, w - fuzzy, 0 - fuzzy, w + fuzzy, 0 + fuzzy);
202 addQuadVertices(texcoords, 0.5, 0.0, 1.0, 0.5);
203 // bottom-left
204 addQuadVertices(verts, 0 - fuzzy, h - fuzzy, 0 + fuzzy, h + fuzzy);
205 addQuadVertices(texcoords, 0.0, 0.5, 0.5, 1.0);
206 // bottom-right
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();
225 glPopMatrix();
226 glPopAttrib();
229 } // namespace