2007-11-27 19:40:25 +00:00
|
|
|
/********************************************************************
|
2007-04-29 17:35:43 +00:00
|
|
|
KWin - the KDE window manager
|
|
|
|
This file is part of the KDE project.
|
|
|
|
|
|
|
|
Copyright (C) 2007 Lubos Lunak <l.lunak@kde.org>
|
|
|
|
|
2007-11-27 19:40:25 +00:00
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
|
|
it under the terms of the GNU General Public License as published by
|
|
|
|
the Free Software Foundation; either version 2 of the License, or
|
|
|
|
(at your option) any later version.
|
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*********************************************************************/
|
2007-04-29 17:35:43 +00:00
|
|
|
|
|
|
|
#include "shadow.h"
|
|
|
|
|
|
|
|
#include <kwinglutils.h>
|
|
|
|
|
2007-05-28 11:34:12 +00:00
|
|
|
#include <kconfiggroup.h>
|
2007-10-23 14:20:37 +00:00
|
|
|
#include <kdebug.h>
|
2007-07-04 11:39:30 +00:00
|
|
|
#include <KStandardDirs>
|
2007-05-28 11:34:12 +00:00
|
|
|
|
2007-04-29 17:35:43 +00:00
|
|
|
namespace KWin
|
|
|
|
{
|
|
|
|
|
2007-05-28 11:16:18 +00:00
|
|
|
KWIN_EFFECT( shadow, ShadowEffect )
|
2007-04-29 17:35:43 +00:00
|
|
|
|
|
|
|
ShadowEffect::ShadowEffect()
|
|
|
|
{
|
2007-05-29 11:48:10 +00:00
|
|
|
KConfigGroup conf = effects->effectConfig("Shadow");
|
2007-11-02 15:33:46 +00:00
|
|
|
shadowXOffset = conf.readEntry( "XOffset", 0 );
|
|
|
|
shadowYOffset = conf.readEntry( "YOffset", 3 );
|
|
|
|
shadowOpacity = conf.readEntry( "Opacity", 0.25 );
|
2007-06-14 11:00:22 +00:00
|
|
|
shadowFuzzyness = conf.readEntry( "Fuzzyness", 10 );
|
2007-11-02 15:33:46 +00:00
|
|
|
shadowSize = conf.readEntry( "Size", 5 );
|
2007-09-28 12:43:51 +00:00
|
|
|
intensifyActiveShadow = conf.readEntry( "IntensifyActiveShadow", true );
|
2007-07-04 11:39:30 +00:00
|
|
|
|
|
|
|
QString shadowtexture = KGlobal::dirs()->findResource("data", "kwin/shadow-texture.png");
|
|
|
|
mShadowTexture = new GLTexture(shadowtexture);
|
2007-04-29 17:35:43 +00:00
|
|
|
}
|
|
|
|
|
2007-07-04 11:39:30 +00:00
|
|
|
QRect ShadowEffect::shadowRectangle(const QRect& windowRectangle) const
|
|
|
|
{
|
2007-11-28 15:40:59 +00:00
|
|
|
int shadowGrow = shadowFuzzyness + shadowSize;
|
2007-09-28 12:24:11 +00:00
|
|
|
return windowRectangle.adjusted( shadowXOffset - shadowGrow, shadowYOffset - shadowGrow,
|
|
|
|
shadowXOffset + shadowGrow, shadowYOffset + shadowGrow);
|
2007-07-04 11:39:30 +00:00
|
|
|
}
|
2007-10-23 12:40:03 +00:00
|
|
|
|
2007-12-08 16:24:48 +00:00
|
|
|
void ShadowEffect::paintScreen( int mask, QRegion region, ScreenPaintData& data )
|
|
|
|
{
|
|
|
|
shadowDatas.clear();
|
|
|
|
|
|
|
|
// Draw windows
|
|
|
|
effects->paintScreen( mask, region, data );
|
|
|
|
|
|
|
|
// Draw shadows
|
|
|
|
drawQueuedShadows( 0 );
|
|
|
|
}
|
|
|
|
|
2007-07-07 14:01:32 +00:00
|
|
|
void ShadowEffect::prePaintWindow( EffectWindow* w, WindowPrePaintData& data, int time )
|
2007-04-29 17:35:43 +00:00
|
|
|
{
|
2007-10-23 12:40:03 +00:00
|
|
|
if( useShadow( w ))
|
|
|
|
{
|
2007-12-08 16:24:48 +00:00
|
|
|
data.paint |= shadowRectangle( data.paint.boundingRect() );
|
2007-10-23 12:40:03 +00:00
|
|
|
}
|
2007-07-07 14:01:32 +00:00
|
|
|
effects->prePaintWindow( w, data, time );
|
2007-04-29 17:35:43 +00:00
|
|
|
}
|
|
|
|
|
2007-12-08 16:24:48 +00:00
|
|
|
void ShadowEffect::drawWindow( EffectWindow* w, int mask, QRegion region, WindowPaintData& data )
|
2007-04-29 17:35:43 +00:00
|
|
|
{
|
2007-12-08 16:24:48 +00:00
|
|
|
// Whether the shadow drawing can be delayed or not.
|
|
|
|
bool optimize = !( mask & ( PAINT_WINDOW_TRANSFORMED | PAINT_SCREEN_TRANSFORMED |
|
|
|
|
PAINT_SCREEN_WITH_TRANSFORMED_WINDOWS | PAINT_WINDOW_TRANSLUCENT ));
|
|
|
|
if( !optimize )
|
|
|
|
{
|
|
|
|
// Transformed or translucent windows are drawn bottom-to-top, so
|
|
|
|
// first we need to draw all queued shadows.
|
|
|
|
drawQueuedShadows( w );
|
|
|
|
}
|
2007-10-23 12:40:03 +00:00
|
|
|
if( useShadow( w ))
|
2007-12-08 16:24:48 +00:00
|
|
|
{
|
|
|
|
if( !optimize )
|
|
|
|
{
|
|
|
|
// For translucent windows, shadow needs to be drawn before the
|
|
|
|
// window itself.
|
2008-02-25 11:32:21 +00:00
|
|
|
drawShadow( w, mask, region, data );
|
2007-12-08 16:24:48 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// For opaque windows, just schedule the shadow to be drawn later
|
|
|
|
ShadowData d(w, data);
|
|
|
|
d.clip = w->shape().translated( w->x(), w->y());
|
|
|
|
if( !shadowDatas.isEmpty())
|
|
|
|
d.clip |= shadowDatas.last().clip;
|
|
|
|
d.mask = mask;
|
|
|
|
foreach(QRect r, region.rects())
|
|
|
|
d.region |= shadowRectangle(r);
|
|
|
|
d.region &= region;
|
|
|
|
shadowDatas.append(d);
|
|
|
|
}
|
|
|
|
}
|
2007-04-29 17:35:43 +00:00
|
|
|
|
2007-12-08 16:24:48 +00:00
|
|
|
effects->drawWindow( w, mask, region, data );
|
2007-04-29 17:35:43 +00:00
|
|
|
}
|
|
|
|
|
2008-01-03 19:51:22 +00:00
|
|
|
QRect ShadowEffect::transformWindowDamage( EffectWindow* w, const QRect& r )
|
|
|
|
{
|
|
|
|
if( !useShadow( w ))
|
|
|
|
return effects->transformWindowDamage( w, r );
|
|
|
|
QRect r2 = r | shadowRectangle( r );
|
|
|
|
return effects->transformWindowDamage( w, r2 );
|
|
|
|
}
|
|
|
|
|
2007-11-03 11:35:39 +00:00
|
|
|
void ShadowEffect::windowClosed( EffectWindow* c )
|
|
|
|
{
|
|
|
|
effects->addRepaint( shadowRectangle( c->geometry() ));
|
|
|
|
}
|
2007-04-29 17:35:43 +00:00
|
|
|
|
2007-10-23 12:40:03 +00:00
|
|
|
bool ShadowEffect::useShadow( EffectWindow* w ) const
|
|
|
|
{
|
2008-01-03 19:39:18 +00:00
|
|
|
return !w->isDeleted() && !w->isDesktop() && !w->isDock() && !w->hasOwnShape();
|
2007-10-23 12:40:03 +00:00
|
|
|
}
|
|
|
|
|
2007-07-04 11:39:30 +00:00
|
|
|
void ShadowEffect::addQuadVertices(QVector<float>& verts, float x1, float y1, float x2, float y2) const
|
2007-11-02 15:33:46 +00:00
|
|
|
{
|
2007-07-04 11:39:30 +00:00
|
|
|
verts << x1 << y1;
|
|
|
|
verts << x1 << y2;
|
|
|
|
verts << x2 << y2;
|
|
|
|
verts << x2 << y1;
|
2007-11-02 15:33:46 +00:00
|
|
|
}
|
2007-07-04 11:39:30 +00:00
|
|
|
|
2007-12-08 16:24:48 +00:00
|
|
|
void ShadowEffect::drawQueuedShadows( EffectWindow* behindWindow )
|
|
|
|
{
|
|
|
|
QList<ShadowData> newShadowDatas;
|
|
|
|
EffectWindowList stack = effects->stackingOrder();
|
|
|
|
foreach( ShadowData d, shadowDatas )
|
|
|
|
{
|
|
|
|
// If behindWindow is given then only render shadows of the windows
|
|
|
|
// that are behind that window.
|
|
|
|
if( !behindWindow || stack.indexOf(d.w) < stack.indexOf(behindWindow))
|
|
|
|
{
|
2008-02-25 11:32:21 +00:00
|
|
|
drawShadow( d.w, d.mask, d.region.subtracted( d.clip ), d.data );
|
2007-12-08 16:24:48 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
newShadowDatas.append(d);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
shadowDatas = newShadowDatas;
|
|
|
|
}
|
|
|
|
|
2008-02-25 11:32:21 +00:00
|
|
|
void ShadowEffect::drawShadow( EffectWindow* window, int mask, QRegion region, WindowPaintData& data )
|
2007-04-29 17:35:43 +00:00
|
|
|
{
|
2007-07-04 11:39:30 +00:00
|
|
|
glPushAttrib( GL_CURRENT_BIT | GL_ENABLE_BIT | GL_TEXTURE_BIT );
|
2007-04-29 17:35:43 +00:00
|
|
|
glEnable( GL_BLEND );
|
|
|
|
glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
|
|
|
|
|
2007-07-04 18:24:54 +00:00
|
|
|
int fuzzy = shadowFuzzyness;
|
|
|
|
// Shadow's size must be a least 2*fuzzy in both directions (or the corners will be broken)
|
2007-09-28 12:24:11 +00:00
|
|
|
int w = qMax(fuzzy*2, window->width() + 2*shadowSize);
|
|
|
|
int h = qMax(fuzzy*2, window->height() + 2*shadowSize);
|
2007-07-04 18:24:54 +00:00
|
|
|
|
2007-04-29 17:35:43 +00:00
|
|
|
glPushMatrix();
|
|
|
|
if( mask & PAINT_WINDOW_TRANSFORMED )
|
|
|
|
glTranslatef( data.xTranslate, data.yTranslate, 0 );
|
2007-09-28 12:47:37 +00:00
|
|
|
glTranslatef( window->x() + shadowXOffset - qMax(0, w - window->width()) / 2.0,
|
|
|
|
window->y() + shadowYOffset - qMax(0, h - window->height()) / 2.0, 0 );
|
2007-04-29 17:35:43 +00:00
|
|
|
if(( mask & PAINT_WINDOW_TRANSFORMED ) && ( data.xScale != 1 || data.yScale != 1 ))
|
|
|
|
glScalef( data.xScale, data.yScale, 1 );
|
|
|
|
|
2007-11-24 16:51:48 +00:00
|
|
|
QVector<float> verts, texcoords;
|
|
|
|
verts.reserve(80);
|
|
|
|
texcoords.reserve(80);
|
2007-07-04 11:39:30 +00:00
|
|
|
// center
|
|
|
|
addQuadVertices(verts, 0 + fuzzy, 0 + fuzzy, w - fuzzy, h - fuzzy);
|
|
|
|
addQuadVertices(texcoords, 0.5, 0.5, 0.5, 0.5);
|
|
|
|
// sides
|
|
|
|
// left
|
|
|
|
addQuadVertices(verts, 0 - fuzzy, 0 + fuzzy, 0 + fuzzy, h - fuzzy);
|
|
|
|
addQuadVertices(texcoords, 0.0, 0.5, 0.5, 0.5);
|
|
|
|
// top
|
|
|
|
addQuadVertices(verts, 0 + fuzzy, 0 - fuzzy, w - fuzzy, 0 + fuzzy);
|
|
|
|
addQuadVertices(texcoords, 0.5, 0.0, 0.5, 0.5);
|
|
|
|
// right
|
|
|
|
addQuadVertices(verts, w - fuzzy, 0 + fuzzy, w + fuzzy, h - fuzzy);
|
|
|
|
addQuadVertices(texcoords, 0.5, 0.5, 1.0, 0.5);
|
|
|
|
// bottom
|
|
|
|
addQuadVertices(verts, 0 + fuzzy, h - fuzzy, w - fuzzy, h + fuzzy);
|
|
|
|
addQuadVertices(texcoords, 0.5, 0.5, 0.5, 1.0);
|
|
|
|
// corners
|
|
|
|
// top-left
|
|
|
|
addQuadVertices(verts, 0 - fuzzy, 0 - fuzzy, 0 + fuzzy, 0 + fuzzy);
|
|
|
|
addQuadVertices(texcoords, 0.0, 0.0, 0.5, 0.5);
|
|
|
|
// top-right
|
|
|
|
addQuadVertices(verts, w - fuzzy, 0 - fuzzy, w + fuzzy, 0 + fuzzy);
|
|
|
|
addQuadVertices(texcoords, 0.5, 0.0, 1.0, 0.5);
|
|
|
|
// bottom-left
|
|
|
|
addQuadVertices(verts, 0 - fuzzy, h - fuzzy, 0 + fuzzy, h + fuzzy);
|
|
|
|
addQuadVertices(texcoords, 0.0, 0.5, 0.5, 1.0);
|
|
|
|
// bottom-right
|
|
|
|
addQuadVertices(verts, w - fuzzy, h - fuzzy, w + fuzzy, h + fuzzy);
|
|
|
|
addQuadVertices(texcoords, 0.5, 0.5, 1.0, 1.0);
|
|
|
|
|
|
|
|
mShadowTexture->bind();
|
2007-07-04 18:24:54 +00:00
|
|
|
// Take the transparency settings and window's transparency into account.
|
|
|
|
// Also make the shadow more transparent if we've made it bigger
|
2007-09-28 12:43:51 +00:00
|
|
|
float opacity = shadowOpacity;
|
|
|
|
if( intensifyActiveShadow && window == effects->activeWindow() )
|
|
|
|
{
|
|
|
|
opacity = 1 - (1 - shadowOpacity)*(1 - shadowOpacity);
|
|
|
|
}
|
|
|
|
glColor4f(0, 0, 0, opacity * data.opacity * (window->width() / (double)w) * (window->height() / (double)h));
|
2007-07-04 11:39:30 +00:00
|
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
|
|
|
// We have two elements per vertex in the verts array
|
|
|
|
int verticesCount = verts.count() / 2;
|
2008-02-25 11:32:21 +00:00
|
|
|
renderGLGeometry( region, verticesCount, verts.data(), texcoords.data() );
|
2007-07-04 11:39:30 +00:00
|
|
|
mShadowTexture->unbind();
|
2007-04-29 17:35:43 +00:00
|
|
|
|
|
|
|
glPopMatrix();
|
|
|
|
glPopAttrib();
|
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace
|