Implement missing shadows in XRender mode, patch from Thomas Lübking.
BUG: 153144 svn path=/trunk/KDE/kdebase/workspace/; revision=817553
This commit is contained in:
parent
75cd7922df
commit
bc137cca3b
2 changed files with 241 additions and 66 deletions
|
@ -28,12 +28,51 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
#include <KStandardDirs>
|
||||
#include <kcolorscheme.h>
|
||||
#include <KGlobalSettings>
|
||||
#ifdef KWIN_HAVE_XRENDER_COMPOSITING
|
||||
#include <QRadialGradient>
|
||||
#endif
|
||||
|
||||
#include <cmath>
|
||||
|
||||
namespace KWin
|
||||
{
|
||||
|
||||
KWIN_EFFECT( shadow, ShadowEffect )
|
||||
|
||||
ShadowTiles::ShadowTiles(const QPixmap& shadow)
|
||||
{
|
||||
int w = shadow.width() / 2, h = shadow.height() / 2;
|
||||
cornerSize = QSize(w, h);
|
||||
#define DUMP_CNR(_TILE_, _W_, _H_, _XOFF_, _YOFF_)\
|
||||
dump = QPixmap(_W_, _H_);\
|
||||
dump.fill(Qt::transparent);\
|
||||
p.begin(&dump);\
|
||||
p.drawPixmap( 0, 0, shadow, _XOFF_, _YOFF_, _W_, _H_ );\
|
||||
p.end();\
|
||||
_TILE_ = dump
|
||||
|
||||
QPixmap dump; QPainter p;
|
||||
DUMP_CNR(topLeft, w, h, 0, 0);
|
||||
DUMP_CNR(topRight, w, h, w, 0);
|
||||
DUMP_CNR(btmLeft, w, h, 0, h);
|
||||
DUMP_CNR(btmRight, w, h, w, h);
|
||||
|
||||
XRenderPictureAttributes pa; pa.repeat = True;
|
||||
#define DUMP_TILE(_TILE_, _W_, _H_, _XOFF_, _YOFF_)\
|
||||
DUMP_CNR(_TILE_, _W_, _H_, _XOFF_, _YOFF_);\
|
||||
XRenderChangePicture (display(), _TILE_, CPRepeat, &pa)
|
||||
|
||||
DUMP_TILE(top, 1, h, w, 0);
|
||||
DUMP_TILE(btm, 1, h, w, h);
|
||||
DUMP_TILE(left, w, 1, 0, h);
|
||||
DUMP_TILE(right, w, 1, w, h);
|
||||
|
||||
DUMP_TILE(center, 1, 1, w, h);
|
||||
}
|
||||
|
||||
#undef DUMP_CNR
|
||||
#undef DUMP_TILE
|
||||
|
||||
ShadowEffect::ShadowEffect()
|
||||
{
|
||||
KConfigGroup conf = effects->effectConfig("Shadow");
|
||||
|
@ -43,9 +82,40 @@ ShadowEffect::ShadowEffect()
|
|||
shadowFuzzyness = conf.readEntry( "Fuzzyness", 10 );
|
||||
shadowSize = conf.readEntry( "Size", 5 );
|
||||
intensifyActiveShadow = conf.readEntry( "IntensifyActiveShadow", true );
|
||||
#ifdef KWIN_HAVE_OPENGL_COMPOSITING
|
||||
if ( effects->compositingType() == OpenGLCompositing)
|
||||
{
|
||||
QString shadowtexture = KGlobal::dirs()->findResource("data", "kwin/shadow-texture.png");
|
||||
mShadowTexture = new GLTexture(shadowtexture);
|
||||
}
|
||||
else
|
||||
mShadowTexture = NULL;
|
||||
#endif
|
||||
#ifdef KWIN_HAVE_XRENDER_COMPOSITING
|
||||
if ( effects->compositingType() == XRenderCompositing)
|
||||
{
|
||||
qreal size = 2*(shadowFuzzyness+shadowSize)+1;
|
||||
QPixmap *shadow = new QPixmap(size, size); shadow->fill(Qt::transparent);
|
||||
size /= 2.0;
|
||||
QRadialGradient rg(size, size, size);
|
||||
QColor c(0,0,0,255);
|
||||
rg.setColorAt(0, c);
|
||||
c.setAlpha(0.3*c.alpha());
|
||||
if (shadowSize > 0)
|
||||
rg.setColorAt(((float)shadowSize)/(shadowFuzzyness+shadowSize), c);
|
||||
c.setAlpha(0); rg.setColorAt(0.8, c);
|
||||
QPainter p(shadow);
|
||||
p.setRenderHint(QPainter::Antialiasing);
|
||||
p.setPen(Qt::NoPen); p.setBrush(rg);
|
||||
p.drawRect(shadow->rect());
|
||||
p.end();
|
||||
|
||||
QString shadowtexture = KGlobal::dirs()->findResource("data", "kwin/shadow-texture.png");
|
||||
mShadowTexture = new GLTexture(shadowtexture);
|
||||
mShadowPics = new ShadowTiles(*shadow);
|
||||
delete shadow;
|
||||
}
|
||||
else
|
||||
mShadowPics = NULL;
|
||||
#endif
|
||||
|
||||
updateShadowColor();
|
||||
connect(KGlobalSettings::self(), SIGNAL(kdisplayPaletteChanged()),
|
||||
|
@ -54,7 +124,12 @@ ShadowEffect::ShadowEffect()
|
|||
|
||||
ShadowEffect::~ShadowEffect()
|
||||
{
|
||||
#ifdef KWIN_HAVE_OPENGL_COMPOSITING
|
||||
delete mShadowTexture;
|
||||
#endif
|
||||
#ifdef KWIN_HAVE_XRENDER_COMPOSITING
|
||||
delete mShadowPics;
|
||||
#endif
|
||||
}
|
||||
|
||||
void ShadowEffect::updateShadowColor()
|
||||
|
@ -70,10 +145,23 @@ QRect ShadowEffect::shadowRectangle(const QRect& windowRectangle) const
|
|||
shadowXOffset + shadowGrow, shadowYOffset + shadowGrow);
|
||||
}
|
||||
|
||||
#ifdef KWIN_HAVE_XRENDER_COMPOSITING
|
||||
static ScreenPaintData gScreenData;
|
||||
#endif
|
||||
|
||||
void ShadowEffect::paintScreen( int mask, QRegion region, ScreenPaintData& data )
|
||||
{
|
||||
shadowDatas.clear();
|
||||
|
||||
#ifdef KWIN_HAVE_XRENDER_COMPOSITING
|
||||
if ((mask & PAINT_SCREEN_TRANSFORMED) &&
|
||||
(effects->compositingType() == XRenderCompositing)) // TODO: copy constructor?
|
||||
{
|
||||
gScreenData.xTranslate = data.xTranslate;
|
||||
gScreenData.yTranslate = data.yTranslate;
|
||||
gScreenData.xScale = data.xScale;
|
||||
gScreenData.yScale = data.yScale;
|
||||
}
|
||||
#endif
|
||||
// Draw windows
|
||||
effects->paintScreen( mask, region, data );
|
||||
|
||||
|
@ -177,73 +265,149 @@ void ShadowEffect::drawQueuedShadows( EffectWindow* behindWindow )
|
|||
|
||||
void ShadowEffect::drawShadow( EffectWindow* window, int mask, QRegion region, WindowPaintData& data )
|
||||
{
|
||||
glPushAttrib( GL_CURRENT_BIT | GL_ENABLE_BIT | GL_TEXTURE_BIT );
|
||||
glEnable( GL_BLEND );
|
||||
glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
|
||||
#ifdef KWIN_HAVE_OPENGL_COMPOSITING
|
||||
if( effects->compositingType() == OpenGLCompositing)
|
||||
{
|
||||
glPushAttrib( GL_CURRENT_BIT | GL_ENABLE_BIT | GL_TEXTURE_BIT );
|
||||
glEnable( GL_BLEND );
|
||||
glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
|
||||
|
||||
int fuzzy = shadowFuzzyness;
|
||||
// Shadow's size must be a least 2*fuzzy in both directions (or the corners will be broken)
|
||||
int w = qMax(fuzzy*2, window->width() + 2*shadowSize);
|
||||
int h = qMax(fuzzy*2, window->height() + 2*shadowSize);
|
||||
int fuzzy = shadowFuzzyness;
|
||||
// Shadow's size must be a least 2*fuzzy in both directions (or the corners will be broken)
|
||||
int w = qMax(fuzzy*2, window->width() + 2*shadowSize);
|
||||
int h = qMax(fuzzy*2, window->height() + 2*shadowSize);
|
||||
|
||||
glPushMatrix();
|
||||
if( mask & PAINT_WINDOW_TRANSFORMED )
|
||||
glTranslatef( data.xTranslate, data.yTranslate, 0 );
|
||||
glTranslatef( window->x() + shadowXOffset - qMax(0, w - window->width()) / 2.0,
|
||||
window->y() + shadowYOffset - qMax(0, h - window->height()) / 2.0, 0 );
|
||||
if(( mask & PAINT_WINDOW_TRANSFORMED ) && ( data.xScale != 1 || data.yScale != 1 ))
|
||||
glScalef( data.xScale, data.yScale, 1 );
|
||||
glPushMatrix();
|
||||
if( mask & PAINT_WINDOW_TRANSFORMED )
|
||||
glTranslatef( data.xTranslate, data.yTranslate, 0 );
|
||||
glTranslatef( window->x() + shadowXOffset - qMax(0, w - window->width()) / 2.0,
|
||||
window->y() + shadowYOffset - qMax(0, h - window->height()) / 2.0, 0 );
|
||||
if(( mask & PAINT_WINDOW_TRANSFORMED ) && ( data.xScale != 1 || data.yScale != 1 ))
|
||||
glScalef( data.xScale, data.yScale, 1 );
|
||||
|
||||
QVector<float> verts, texcoords;
|
||||
verts.reserve(80);
|
||||
texcoords.reserve(80);
|
||||
// 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);
|
||||
QVector<float> verts, texcoords;
|
||||
verts.reserve(80);
|
||||
texcoords.reserve(80);
|
||||
// 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();
|
||||
// Take the transparency settings and window's transparency into account.
|
||||
// Also make the shadow more transparent if we've made it bigger
|
||||
float opacity = shadowOpacity;
|
||||
if( intensifyActiveShadow && window == effects->activeWindow() )
|
||||
{
|
||||
opacity = 1 - (1 - shadowOpacity)*(1 - shadowOpacity);
|
||||
}
|
||||
glColor4f(shadowColor.redF(), shadowColor.greenF(), shadowColor.blueF(), opacity * data.opacity * (window->width() / (double)w) * (window->height() / (double)h));
|
||||
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;
|
||||
renderGLGeometry( region, verticesCount, verts.data(), texcoords.data() );
|
||||
mShadowTexture->unbind();
|
||||
mShadowTexture->bind();
|
||||
// Take the transparency settings and window's transparency into account.
|
||||
// Also make the shadow more transparent if we've made it bigger
|
||||
float opacity = shadowOpacity;
|
||||
if( intensifyActiveShadow && window == effects->activeWindow() )
|
||||
{
|
||||
opacity = 1 - (1 - shadowOpacity)*(1 - shadowOpacity);
|
||||
}
|
||||
glColor4f(shadowColor.redF(), shadowColor.greenF(), shadowColor.blueF(), opacity * data.opacity * (window->width() / (double)w) * (window->height() / (double)h));
|
||||
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;
|
||||
renderGLGeometry( region, verticesCount, verts.data(), texcoords.data() );
|
||||
mShadowTexture->unbind();
|
||||
|
||||
glPopMatrix();
|
||||
glPopAttrib();
|
||||
glPopMatrix();
|
||||
glPopAttrib();
|
||||
}
|
||||
#endif
|
||||
#ifdef KWIN_HAVE_XRENDER_COMPOSITING
|
||||
if( effects->compositingType() == XRenderCompositing)
|
||||
{
|
||||
// calculate opacity =================================================
|
||||
float opacity;
|
||||
if( intensifyActiveShadow && window == effects->activeWindow() )
|
||||
{
|
||||
opacity = (1 - (1 - shadowOpacity)*(1 - shadowOpacity)) * data.opacity;
|
||||
}
|
||||
else
|
||||
{
|
||||
opacity = data.opacity * shadowOpacity;
|
||||
}
|
||||
|
||||
// query rect and translate in case (may have impact on opacity)===========================
|
||||
QRect r = window->geometry();
|
||||
if ( mask & (PAINT_WINDOW_TRANSFORMED | PAINT_SCREEN_TRANSFORMED))
|
||||
{
|
||||
float xScale = 1.0, yScale = 1.0, xTranslate = 0.0, yTranslate = 0.0;
|
||||
if ( mask & PAINT_SCREEN_TRANSFORMED)
|
||||
{
|
||||
xScale = gScreenData.xScale; yScale = gScreenData.yScale;
|
||||
xTranslate += (xScale-1.0)*r.x() + gScreenData.xTranslate;
|
||||
yTranslate += (yScale-1.0)*r.y() + gScreenData.yTranslate;
|
||||
}
|
||||
|
||||
if ( mask & PAINT_WINDOW_TRANSFORMED)
|
||||
{
|
||||
xTranslate += xScale*data.xTranslate;
|
||||
yTranslate += yScale*data.yTranslate;
|
||||
xScale *= data.xScale; yScale *= data.yScale;
|
||||
}
|
||||
|
||||
r.translate(xTranslate, yTranslate);
|
||||
|
||||
if (xScale != 1.0 || yScale != 1.0)
|
||||
{
|
||||
r.setWidth(xScale * r.width());
|
||||
r.setHeight(yScale * r.height());
|
||||
// opacity *= 2.0/(2 - (2 - (xScale + yScale))*(2 - (xScale + yScale)));
|
||||
}
|
||||
}
|
||||
r = shadowRectangle(r);
|
||||
|
||||
// create render mask ==================================================================
|
||||
|
||||
XRenderColor xc = preMultiply(shadowColor, opacity);
|
||||
XRenderPicture fill = xRenderFill(&xc);
|
||||
|
||||
// clip, then paint shadow tiles ========================================================
|
||||
XRenderSetPictureClipRegion (display(), effects->xrenderBufferPicture(), region.handle());
|
||||
#define DRAW_CORNER(_CNR_, _X_, _Y_)\
|
||||
XRenderComposite( display(), PictOpOver, fill, mShadowPics->_CNR_, effects->xrenderBufferPicture(), 0, 0, 0, 0, _X_, _Y_, w, h )
|
||||
#define DRAW_TILE(_TILE_, _X_, _Y_, _W_, _H_)\
|
||||
XRenderComposite( display(), PictOpOver, fill, mShadowPics->_TILE_, effects->xrenderBufferPicture(), 0, 0, 0, 0, _X_, _Y_, _W_, _H_ )
|
||||
int w = qMin(mShadowPics->cornerSize.width(), r.width()/2);
|
||||
int h = qMin(mShadowPics->cornerSize.height(), r.height()/2);
|
||||
DRAW_CORNER(topLeft, r.x(), r.y());
|
||||
DRAW_CORNER(topRight, r.right()-w, r.y());
|
||||
DRAW_CORNER(btmLeft, r.x(), r.bottom()-h);
|
||||
DRAW_CORNER(btmRight, r.right()-w, r.bottom()-h);
|
||||
int w2 = r.width()-2*w-1, h2 = r.height()-2*h-1;
|
||||
DRAW_TILE(top, r.x()+w, r.y(), w2, h);
|
||||
DRAW_TILE(btm, r.x()+w, r.bottom()-h, w2, h);
|
||||
DRAW_TILE(left, r.x(), r.y()+h, w, h2);
|
||||
DRAW_TILE(right, r.right()-w, r.y()+h, w, h2);
|
||||
DRAW_TILE(center, r.x()+w, r.y()+h, w2, h2);
|
||||
#undef DRAW_CORNER
|
||||
#undef DRAW_TILE
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
|
|
@ -22,13 +22,23 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
#define KWIN_SHADOW_H
|
||||
|
||||
#include <kwineffects.h>
|
||||
|
||||
#include <kwinxrenderutils.h>
|
||||
|
||||
namespace KWin
|
||||
{
|
||||
|
||||
class GLTexture;
|
||||
|
||||
class ShadowTiles
|
||||
{
|
||||
public:
|
||||
ShadowTiles(const QPixmap& shadow);
|
||||
XRenderPicture topLeft, top, topRight,
|
||||
left, center, right,
|
||||
btmLeft, btm, btmRight;
|
||||
QSize cornerSize;
|
||||
};
|
||||
|
||||
class ShadowEffect
|
||||
: public QObject, public Effect
|
||||
{
|
||||
|
@ -60,6 +70,7 @@ class ShadowEffect
|
|||
bool intensifyActiveShadow;
|
||||
QColor shadowColor;
|
||||
GLTexture* mShadowTexture;
|
||||
ShadowTiles *mShadowPics;
|
||||
|
||||
struct ShadowData
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue