Merge Libkdecoration2 Git branch.

WARNING: Breaks shadow effect. I don't think it causes anything to crash anymore but it is VERY ugly visually.

Contains:
 - New decoration API that allows decorations to change the way shadows look.
 - Shadows now wobble.
 - API example code in the Oxygen decoration.
 - Added buildQuads() effect plugin hook.
 - Work on the shadow effect to use the new decoration shadow API as well.
 - Added IDs to WindowQuads.
 - Added public accessors to texture coords in WindowVertex.

Would like all this to be reviewed.

CCMAIL: kwin@kde.org

svn path=/trunk/KDE/kdebase/workspace/; revision=872473
icc-effect-5.14.5
Lucas Murray 2008-10-17 10:30:43 +00:00
parent 844f815ff8
commit 899d578c49
27 changed files with 1144 additions and 45 deletions

View File

@ -22,6 +22,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "client.h"
#include "options.h"
#include "effects.h"
namespace KWin
{
@ -200,4 +201,29 @@ void Bridge::grabXServer( bool grab )
KWin::ungrabXServer();
}
void Bridge::repaintShadow()
{
// TODO
}
bool Bridge::compositingActive() const
{
return c->workspace()->compositingActive();
}
bool Bridge::shadowsActive() const
{
if( !c->workspace()->compositingActive() )
return false;
if( effects && static_cast<EffectsHandlerImpl*>( effects )->isEffectLoaded( "kwin4_effect_shadow" ))
return true;
return false;
}
double Bridge::opacity() const
{
return c->opacity();
}
} // namespace

View File

@ -28,7 +28,7 @@ namespace KWin
class Client;
class Bridge : public KDecorationBridge
class Bridge : public KDecorationBridge2
{
public:
Bridge( Client* cl );
@ -74,6 +74,11 @@ class Bridge : public KDecorationBridge
virtual QWidget* initialParentWidget() const;
virtual Qt::WFlags initialWFlags() const;
virtual void grabXServer( bool grab );
virtual void repaintShadow();
virtual bool compositingActive() const;
virtual bool shadowsActive() const;
virtual double opacity() const;
private:
Client* c;
};

View File

@ -284,6 +284,12 @@ class Client
return moveResizeMode && mode != PositionCenter;
}
// Decorations <-> Effects
QList<QRect> shadowQuads( ShadowType type ) const;
double shadowOpacity( ShadowType type, double dataOpacity ) const;
double shadowBrightness( ShadowType type ) const;
double shadowSaturation( ShadowType type ) const;
private slots:
void autoRaise();
void shadeHover();
@ -789,6 +795,34 @@ inline bool Client::hiddenPreview() const
return mapping_state == Kept;
}
inline QList<QRect> Client::shadowQuads( ShadowType type ) const
{
if( KDecoration2* decoration2 = dynamic_cast< KDecoration2* >( decoration ))
return decoration2->shadowQuads( type );
return QList<QRect>();
}
inline double Client::shadowOpacity( ShadowType type, double dataOpacity ) const
{
if( KDecoration2* decoration2 = dynamic_cast< KDecoration2* >( decoration ))
return decoration2->shadowOpacity( type, dataOpacity );
return dataOpacity;
}
inline double Client::shadowBrightness( ShadowType type ) const
{
if( KDecoration2* decoration2 = dynamic_cast< KDecoration2* >( decoration ))
return decoration2->shadowBrightness( type );
return 1.0;
}
inline double Client::shadowSaturation( ShadowType type ) const
{
if( KDecoration2* decoration2 = dynamic_cast< KDecoration2* >( decoration ))
return decoration2->shadowSaturation( type );
return 1.0;
}
KWIN_COMPARE_PREDICATE( WrapperIdMatchPredicate, Client, Window, cl->wrapperId() == value );
} // namespace

View File

@ -24,6 +24,8 @@
// IN THE SOFTWARE.
//////////////////////////////////////////////////////////////////////////////
#include <QPainter>
#include "oxygen.h"
#include "oxygenclient.h"
#include <kconfiggroup.h>
@ -144,6 +146,8 @@ bool OxygenFactory::supports( Ability ability ) const
case AbilityButtonBelowOthers:
case AbilityButtonSpacer:
case AbilityButtonShade:
// compositing
case AbilityCompositingShadow: // TODO: UI option to use default shadows instead
return true;
// no colors supported at this time
default:
@ -151,4 +155,128 @@ bool OxygenFactory::supports( Ability ability ) const
};
}
//////////////////////////////////////////////////////////////////////////////
// Shadows
QList< QList<QImage> > OxygenFactory::shadowTextures()
{
// TODO: THIS IS ALL VERY UGLY! Not recommended to do it this way.
// Copied from the shadow effect's XRender picture generator
// TODO: You can add fake anti-aliasing here :)
QList< QList<QImage> > textureLists;
QList<QImage> textures;
#define shadowFuzzyness 10
#define shadowSize 10
//---------------------------------------------------------------
// Active shadow texture
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( 150, 234, 255, 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();
int w = shadow->width() / 2;
int h = shadow->height() / 2;
QPixmap dump;
#define MAKE_TEX( _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(); \
textures.append( dump.toImage() );
MAKE_TEX( w, h, 0, h );
MAKE_TEX( 1, h, w, h );
MAKE_TEX( w, h, w, h );
MAKE_TEX( w, 1, 0, h );
//MAKE_TEX( 1, 1, w, h );
MAKE_TEX( w, 1, w, h );
MAKE_TEX( w, h, 0, 0 );
MAKE_TEX( 1, h, w, 0 );
MAKE_TEX( w, h, w, 0 );
delete shadow;
textureLists.append( textures );
//---------------------------------------------------------------
// Inactive shadow texture
for( int i = 0; i < 8; i++ )
{
QPainter pi( &textures[i] );
pi.fillRect( textures[i].rect(), QColor( 0, 0, 0, 255 ));
pi.end();
textures[i].setAlphaChannel( textureLists[0][i].alphaChannel() );
}
textureLists.append( textures );
return textureLists;
}
int OxygenFactory::shadowTextureList( ShadowType type ) const
{
switch( type ) {
case ShadowBorderedActive:
case ShadowBorderlessActive:
return 0;
case ShadowBorderedInactive:
case ShadowBorderlessInactive:
case ShadowOther:
return 1;
}
abort(); // Should never be reached
}
QList<QRect> OxygenFactory::shadowQuads( ShadowType type, QSize size ) const
{
#define shadowFuzzyness 15
// These are slightly under the decoration so the corners look nicer
QList<QRect> quads;
quads.append( QRect( -shadowFuzzyness+5, -shadowFuzzyness+5, shadowFuzzyness, shadowFuzzyness ));
quads.append( QRect( 0+5, -shadowFuzzyness+5, size.width()-10, shadowFuzzyness ));
quads.append( QRect( size.width()-5, -shadowFuzzyness+5, shadowFuzzyness, shadowFuzzyness ));
quads.append( QRect( -shadowFuzzyness+5, 0+5, shadowFuzzyness, size.height()-10 ));
//quads.append( QRect( 0+5, 0+5, size.width()-10, size.height()-10 ));
quads.append( QRect( size.width()-5, 0+5, shadowFuzzyness, size.height()-10 ));
quads.append( QRect( -shadowFuzzyness+5, size.height()-5, shadowFuzzyness, shadowFuzzyness ));
quads.append( QRect( 0+5, size.height()-5, size.width()-10, shadowFuzzyness ));
quads.append( QRect( size.width()-5, size.height()-5, shadowFuzzyness, shadowFuzzyness ));
return quads;
}
double OxygenFactory::shadowOpacity( ShadowType type, double dataOpacity ) const
{
switch( type ) {
case ShadowBorderlessActive:
return dataOpacity;
case ShadowBorderlessInactive:
case ShadowOther:
return dataOpacity * 0.25;
}
abort(); // Should never be reached
}
} //namespace Oxygen

View File

@ -53,7 +53,7 @@ enum ButtonType {
};
Q_DECLARE_FLAGS(ButtonTypes, ButtonType)
class OxygenFactory: public KDecorationFactory
class OxygenFactory: public KDecorationFactory2
{
public:
OxygenFactory();
@ -62,6 +62,11 @@ public:
virtual bool reset(unsigned long changed);
virtual bool supports( Ability ability ) const;
virtual QList< QList<QImage> > shadowTextures();
virtual int shadowTextureList( ShadowType type ) const;
virtual QList<QRect> shadowQuads( ShadowType type, QSize size ) const;
virtual double shadowOpacity( ShadowType type, double dataOpacity ) const;
static bool initialized();
static Qt::Alignment titleAlignment();
static bool showStripes();

View File

@ -70,7 +70,7 @@ void renderDot(QPainter *p, const QPointF &point, qreal diameter)
OxygenClient::OxygenClient(KDecorationBridge *b, KDecorationFactory *f)
: KCommonDecoration(b, f)
: KCommonDecoration2(b, f)
, colorCacheInvalid_(true)
, helper_(*globalHelper)
{
@ -415,6 +415,41 @@ void OxygenClient::updateWindowShape()
setMask(mask);
}
QList<QRect> OxygenClient::shadowQuads( ShadowType type ) const
{
QSize size = widget()->size();
#define shadowFuzzyness 15
// These are slightly under the decoration so the corners look nicer
QList<QRect> quads;
quads.append( QRect( -shadowFuzzyness+5, -shadowFuzzyness+5, shadowFuzzyness, shadowFuzzyness ));
quads.append( QRect( 0+5, -shadowFuzzyness+5, size.width()-10, shadowFuzzyness ));
quads.append( QRect( size.width()-5, -shadowFuzzyness+5, shadowFuzzyness, shadowFuzzyness ));
quads.append( QRect( -shadowFuzzyness+5, 0+5, shadowFuzzyness, size.height()-10 ));
//quads.append( QRect( 0+5, 0+5, size.width()-10, size.height()-10 ));
quads.append( QRect( size.width()-5, 0+5, shadowFuzzyness, size.height()-10 ));
quads.append( QRect( -shadowFuzzyness+5, size.height()-5, shadowFuzzyness, shadowFuzzyness ));
quads.append( QRect( 0+5, size.height()-5, size.width()-10, shadowFuzzyness ));
quads.append( QRect( size.width()-5, size.height()-5, shadowFuzzyness, shadowFuzzyness ));
return quads;
}
double OxygenClient::shadowOpacity( ShadowType type, double dataOpacity ) const
{
switch( type ) {
case ShadowBorderedActive:
if( isActive() )
return dataOpacity;
return 0.0;
case ShadowBorderedInactive:
if( isActive() )
return 0.0;
return dataOpacity * 0.25;
}
abort(); // Should never be reached
}
} //namespace Oxygen
//#include "oxygenclient.moc"

View File

@ -37,7 +37,7 @@ class QPoint;
namespace Oxygen {
class OxygenClient : public KCommonDecoration
class OxygenClient : public KCommonDecoration2
{
Q_OBJECT
public:
@ -51,6 +51,9 @@ public:
virtual void updateWindowShape();
virtual void init();
virtual QList<QRect> shadowQuads( ShadowType type ) const;
virtual double shadowOpacity( ShadowType type, double dataOpacity ) const;
private:
void paintEvent(QPaintEvent *e);
void drawScratch(QPainter *p, QPalette &palette, const int start, const int end, const int topMargin);

View File

@ -51,6 +51,7 @@ EffectsHandlerImpl::EffectsHandlerImpl(CompositingType type)
: EffectsHandler(type)
, keyboard_grab_effect( NULL )
, fullscreen_effect( 0 )
, next_window_quad_type( EFFECT_QUAD_TYPE_START )
{
reconfigure();
}
@ -176,12 +177,37 @@ void EffectsHandlerImpl::drawWindow( EffectWindow* w, int mask, QRegion region,
scene->finalDrawWindow( static_cast<EffectWindowImpl*>( w ), mask, region, data );
}
void EffectsHandlerImpl::buildQuads( EffectWindow* w, WindowQuadList& quadList )
{
if( current_build_quads < loaded_effects.size())
{
loaded_effects[current_build_quads++].second->buildQuads( w, quadList );
--current_build_quads;
}
}
bool EffectsHandlerImpl::hasDecorationShadows() const
{
return Workspace::self()->hasDecorationShadows();
}
QList< QList<QImage> > EffectsHandlerImpl::shadowTextures()
{
return Workspace::self()->decorationShadowTextures();
}
int EffectsHandlerImpl::shadowTextureList( ShadowType type ) const
{
return Workspace::self()->decorationShadowTextureList( type );
}
// start another painting pass
void EffectsHandlerImpl::startPaint()
{
assert( current_paint_screen == 0 );
assert( current_paint_window == 0 );
assert( current_draw_window == 0 );
assert( current_build_quads == 0 );
assert( current_transform == 0 );
}
@ -431,6 +457,11 @@ double EffectsHandlerImpl::animationTimeFactor() const
return options->animationTimeFactor();
}
WindowQuadType EffectsHandlerImpl::newWindowQuadType()
{
return WindowQuadType( next_window_quad_type++ );
}
int EffectsHandlerImpl::displayWidth() const
{
return KWin::displayWidth();
@ -767,6 +798,7 @@ bool EffectsHandlerImpl::loadEffect( const QString& name )
assert( current_paint_screen == 0 );
assert( current_paint_window == 0 );
assert( current_draw_window == 0 );
assert( current_build_quads == 0 );
assert( current_transform == 0 );
if( !name.startsWith("kwin4_effect_") )
@ -872,6 +904,7 @@ void EffectsHandlerImpl::unloadEffect( const QString& name )
assert( current_paint_screen == 0 );
assert( current_paint_window == 0 );
assert( current_draw_window == 0 );
assert( current_build_quads == 0 );
assert( current_transform == 0 );
for( QMap< int, EffectPair >::iterator it = effect_order.begin(); it != effect_order.end(); ++it)
@ -1303,6 +1336,51 @@ EffectWindowList EffectWindowImpl::mainWindows() const
return EffectWindowList();
}
QList<QRect> EffectWindowImpl::shadowQuads( ShadowType type ) const
{
if( type == ShadowBorderedActive || type == ShadowBorderedInactive )
{
if( Client* c = dynamic_cast< Client* >( toplevel ))
return c->shadowQuads( type );
return QList<QRect>();
}
return toplevel->workspace()->decorationShadowQuads( type, toplevel->size() );
}
double EffectWindowImpl::shadowOpacity( ShadowType type, double dataOpacity ) const
{
dataOpacity *= opacity();
if( type == ShadowBorderedActive || type == ShadowBorderedInactive )
{
if( Client* c = dynamic_cast< Client* >( toplevel ))
return c->shadowOpacity( type, dataOpacity );
return dataOpacity;
}
return toplevel->workspace()->decorationShadowOpacity( type, dataOpacity );
}
double EffectWindowImpl::shadowBrightness( ShadowType type ) const
{
if( type == ShadowBorderedActive || type == ShadowBorderedInactive )
{
if( Client* c = dynamic_cast< Client* >( toplevel ))
return c->shadowBrightness( type );
return 1.0;
}
return toplevel->workspace()->decorationShadowBrightness( type );
}
double EffectWindowImpl::shadowSaturation( ShadowType type ) const
{
if( type == ShadowBorderedActive || type == ShadowBorderedInactive )
{
if( Client* c = dynamic_cast< Client* >( toplevel ))
return c->shadowSaturation( type );
return 1.0;
}
return toplevel->workspace()->decorationShadowSaturation( type );
}
WindowQuadList EffectWindowImpl::buildQuads() const
{
return sceneWindow()->buildQuads();

View File

@ -49,6 +49,8 @@ class EffectsHandlerImpl : public EffectsHandler
virtual void drawWindow( EffectWindow* w, int mask, QRegion region, WindowPaintData& data );
virtual void buildQuads( EffectWindow* w, WindowQuadList& quadList );
virtual void activateWindow( EffectWindow* c );
virtual EffectWindow* activeWindow() const;
virtual void moveWindow( EffectWindow* w, const QPoint& pos );
@ -100,6 +102,7 @@ class EffectsHandlerImpl : public EffectsHandler
virtual int desktopUp( int desktop, bool wrap ) const;
virtual int desktopDown( int desktop, bool wrap ) const;
virtual double animationTimeFactor() const;
virtual WindowQuadType newWindowQuadType();
virtual Window createInputWindow( Effect* e, int x, int y, int w, int h, const QCursor& cursor );
using EffectsHandler::createInputWindow;
@ -116,6 +119,10 @@ class EffectsHandlerImpl : public EffectsHandler
virtual void reconfigure();
virtual void registerPropertyType( long atom, bool reg );
virtual bool hasDecorationShadows() const;
virtual QList< QList<QImage> > shadowTextures();
virtual int shadowTextureList( ShadowType type ) const;
// internal (used by kwin core or compositing code)
void startPaint();
void windowUserMovedResized( EffectWindow* c, bool first, bool last );
@ -160,6 +167,7 @@ class EffectsHandlerImpl : public EffectsHandler
QList<EffectWindow*> elevated_windows;
QMultiMap< int, EffectPair > effect_order;
QHash< long, int > registered_atoms;
int next_window_quad_type;
};
class EffectWindowImpl : public EffectWindow
@ -230,6 +238,11 @@ class EffectWindowImpl : public EffectWindow
virtual EffectWindow* findModal();
virtual EffectWindowList mainWindows() const;
virtual QList<QRect> shadowQuads( ShadowType type ) const;
virtual double shadowOpacity( ShadowType type, double dataOpacity ) const;
virtual double shadowBrightness( ShadowType type ) const;
virtual double shadowSaturation( ShadowType type ) const;
virtual WindowQuadList buildQuads() const;
const Toplevel* window() const;

View File

@ -78,9 +78,6 @@ ShadowTiles::ShadowTiles(const QPixmap& shadow)
ShadowEffect::ShadowEffect()
: shadowSize( 0 )
#ifdef KWIN_HAVE_OPENGL_COMPOSITING
, mShadowTexture( NULL )
#endif
#ifdef KWIN_HAVE_XRENDER_COMPOSITING
, mShadowPics( NULL )
#endif
@ -93,7 +90,9 @@ ShadowEffect::ShadowEffect()
ShadowEffect::~ShadowEffect()
{
#ifdef KWIN_HAVE_OPENGL_COMPOSITING
delete mShadowTexture;
for( int i = 0; i < mShadowTextures.size(); i++ )
for( int j = 0; j < mShadowTextures.at( i ).size(); j++ )
delete mShadowTextures.at( i ).at( j );
#endif
#ifdef KWIN_HAVE_XRENDER_COMPOSITING
delete mShadowPics;
@ -109,15 +108,6 @@ void ShadowEffect::reconfigure( ReconfigureFlags )
shadowFuzzyness = conf.readEntry( "Fuzzyness", 10 );
shadowSize = conf.readEntry( "Size", 5 );
intensifyActiveShadow = conf.readEntry( "IntensifyActiveShadow", true );
#ifdef KWIN_HAVE_OPENGL_COMPOSITING
delete mShadowTexture;
mShadowTexture = NULL;
if ( effects->compositingType() == OpenGLCompositing)
{
QString shadowtexture = KGlobal::dirs()->findResource("data", "kwin/shadow-texture.png");
mShadowTexture = new GLTexture(shadowtexture);
}
#endif
#ifdef KWIN_HAVE_XRENDER_COMPOSITING
delete mShadowPics;
mShadowPics = NULL;
@ -144,6 +134,48 @@ void ShadowEffect::reconfigure( ReconfigureFlags )
}
#endif
updateShadowColor();
// Load decoration shadow related things
mShadowQuadTypes.clear(); // Changed decoration? TODO: Unregister?
#ifdef KWIN_HAVE_OPENGL_COMPOSITING
if( effects->compositingType() == OpenGLCompositing )
{
for( int i = 0; i < mShadowTextures.size(); i++ )
for( int j = 0; j < mShadowTextures.at( i ).size(); j++ )
delete mShadowTextures.at( i ).at( j );
mShadowTextures.clear();
if( effects->hasDecorationShadows() )
{
QList< QList<QImage> > shadowTextures = effects->shadowTextures();
for( int i = 0; i < shadowTextures.size(); i++ )
{
mShadowQuadTypes.append( effects->newWindowQuadType() );
QList<GLTexture*> textures;
for( int j = 0; j < shadowTextures.at( i ).size(); j++ )
textures.append( new GLTexture( shadowTextures.at( i ).at( j )));
mShadowTextures.append( textures );
}
}
else
{
mShadowQuadTypes.append( effects->newWindowQuadType() );
QImage shadowTexture( KGlobal::dirs()->findResource( "data", "kwin/shadow-texture.png" ));
int hw = shadowTexture.width() / 2;
int hh = shadowTexture.height() / 2;
QList<GLTexture*> textures;
textures.append( new GLTexture( shadowTexture.copy( 0, hh, hw, hh )));
textures.append( new GLTexture( shadowTexture.copy( hw, hh, 1, hh )));
textures.append( new GLTexture( shadowTexture.copy( hw, hh, hw, hh )));
textures.append( new GLTexture( shadowTexture.copy( 0, hh, hw, 1 )));
textures.append( new GLTexture( shadowTexture.copy( hw, hh, 1, 1 )));
textures.append( new GLTexture( shadowTexture.copy( hw, hh, hw, 1 )));
textures.append( new GLTexture( shadowTexture.copy( 0, 0, hw, hh )));
textures.append( new GLTexture( shadowTexture.copy( hw, 0, 1, hh )));
textures.append( new GLTexture( shadowTexture.copy( hw, 0, hw, hh )));
mShadowTextures.append( textures );
}
}
#endif
}
void ShadowEffect::updateShadowColor()
@ -185,7 +217,7 @@ void ShadowEffect::paintScreen( int mask, QRegion region, ScreenPaintData& data
void ShadowEffect::prePaintWindow( EffectWindow* w, WindowPrePaintData& data, int time )
{
if( useShadow( w ) && !data.quads.isTransformed())
if( useShadow( w ))
{
data.paint |= shadowRectangle( data.paint.boundingRect() );
}
@ -203,7 +235,7 @@ void ShadowEffect::drawWindow( EffectWindow* w, int mask, QRegion region, Window
// first we need to draw all queued shadows.
drawQueuedShadows( w );
}
if( useShadow( w ) && !data.quads.isTransformed())
if( useShadow( w ))
{
if( !optimize )
{
@ -229,6 +261,165 @@ void ShadowEffect::drawWindow( EffectWindow* w, int mask, QRegion region, Window
effects->drawWindow( w, mask, region, data );
}
void ShadowEffect::buildQuads( EffectWindow* w, WindowQuadList& quadList )
{
if( effects->hasDecorationShadows() )
{
// TODO: shadowQuads() is allowed to return different quads for
// active and inactive shadows. Is implementing it worth
// the performance drop?
int id = 0;
if( w->hasDecoration() )
{ // Decorated windows must be normal windows
foreach( const QRect &r, w->shadowQuads( ShadowBorderedActive ))
{
WindowQuad quad( mShadowQuadTypes.at( effects->shadowTextureList( ShadowBorderedActive )), id++ );
quad[ 0 ] = WindowVertex( r.x(), r.y(), 0, 0 );
quad[ 1 ] = WindowVertex( r.x() + r.width(), r.y(), 1, 0 );
quad[ 2 ] = WindowVertex( r.x() + r.width(), r.y() + r.height(), 1, 1 );
quad[ 3 ] = WindowVertex( r.x(), r.y() + r.height(), 0, 1 );
quadList.append( quad );
}
}
else if( w->isNormalWindow() )
{ // No decoration on a normal window
foreach( const QRect &r, w->shadowQuads( ShadowBorderlessActive ))
{
WindowQuad quad( mShadowQuadTypes.at( effects->shadowTextureList( ShadowBorderlessActive )), id++ );
quad[ 0 ] = WindowVertex( r.x(), r.y(), 0, 0 );
quad[ 1 ] = WindowVertex( r.x() + r.width(), r.y(), 1, 0 );
quad[ 2 ] = WindowVertex( r.x() + r.width(), r.y() + r.height(), 1, 1 );
quad[ 3 ] = WindowVertex( r.x(), r.y() + r.height(), 0, 1 );
quadList.append( quad );
}
}
else
{ // All other undecorated windows
foreach( const QRect &r, w->shadowQuads( ShadowOther ))
{
WindowQuad quad( mShadowQuadTypes.at( effects->shadowTextureList( ShadowOther )), id++ );
quad[ 0 ] = WindowVertex( r.x(), r.y(), 0, 0 );
quad[ 1 ] = WindowVertex( r.x() + r.width(), r.y(), 1, 0 );
quad[ 2 ] = WindowVertex( r.x() + r.width(), r.y() + r.height(), 1, 1 );
quad[ 3 ] = WindowVertex( r.x(), r.y() + r.height(), 0, 1 );
quadList.append( quad );
}
}
}
else
{
//TODO: add config option to not have shadows for menus, etc.
// Make our own shadow as the decoration doesn't support it
int fuzzy = shadowFuzzyness;
// Shadow's size must be a least 2*fuzzy in both directions (or the corners will be broken)
int width = qMax(fuzzy*2, w->width());
int height = qMax(fuzzy*2, w->height());
double x1, y1, x2, y2;
int id = 0;
// top-left
x1 = 0 - fuzzy;
y1 = 0 - fuzzy;
x2 = 0;
y2 = 0;
WindowQuad topLeftQuad( mShadowQuadTypes.at( 0 ), id++ );
topLeftQuad[ 0 ] = WindowVertex( x1, y1, 0, 0 );
topLeftQuad[ 1 ] = WindowVertex( x2, y1, 1, 0 );
topLeftQuad[ 2 ] = WindowVertex( x2, y2, 1, 1 );
topLeftQuad[ 3 ] = WindowVertex( x1, y2, 0, 1 );
quadList.append( topLeftQuad );
// top
x1 = 0;
y1 = 0 - fuzzy;
x2 = width;
y2 = 0;
WindowQuad topQuad( mShadowQuadTypes.at( 0 ), id++ );
topQuad[ 0 ] = WindowVertex( x1, y1, 0, 0 );
topQuad[ 1 ] = WindowVertex( x2, y1, 1, 0 );
topQuad[ 2 ] = WindowVertex( x2, y2, 1, 1 );
topQuad[ 3 ] = WindowVertex( x1, y2, 0, 1 );
quadList.append( topQuad );
// top-right
x1 = width;
y1 = 0 - fuzzy;
x2 = width + fuzzy;
y2 = 0;
WindowQuad topRightQuad( mShadowQuadTypes.at( 0 ), id++ );
topRightQuad[ 0 ] = WindowVertex( x1, y1, 0, 0 );
topRightQuad[ 1 ] = WindowVertex( x2, y1, 1, 0 );
topRightQuad[ 2 ] = WindowVertex( x2, y2, 1, 1 );
topRightQuad[ 3 ] = WindowVertex( x1, y2, 0, 1 );
quadList.append( topRightQuad );
// left
x1 = 0 - fuzzy;
y1 = 0;
x2 = 0;
y2 = height;
WindowQuad leftQuad( mShadowQuadTypes.at( 0 ), id++ );
leftQuad[ 0 ] = WindowVertex( x1, y1, 0, 0 );
leftQuad[ 1 ] = WindowVertex( x2, y1, 1, 0 );
leftQuad[ 2 ] = WindowVertex( x2, y2, 1, 1 );
leftQuad[ 3 ] = WindowVertex( x1, y2, 0, 1 );
quadList.append( leftQuad );
// center
x1 = 0;
y1 = 0;
x2 = width;
y2 = height;
WindowQuad contentsQuad( mShadowQuadTypes.at( 0 ), id++ );
contentsQuad[ 0 ] = WindowVertex( x1, y1, 0, 0 );
contentsQuad[ 1 ] = WindowVertex( x2, y1, 1, 0 );
contentsQuad[ 2 ] = WindowVertex( x2, y2, 1, 1 );
contentsQuad[ 3 ] = WindowVertex( x1, y2, 0, 1 );
quadList.append( contentsQuad );
// right
x1 = width;
y1 = 0;
x2 = width + fuzzy;
y2 = height;
WindowQuad rightQuad( mShadowQuadTypes.at( 0 ), id++ );
rightQuad[ 0 ] = WindowVertex( x1, y1, 0, 0 );
rightQuad[ 1 ] = WindowVertex( x2, y1, 1, 0 );
rightQuad[ 2 ] = WindowVertex( x2, y2, 1, 1 );
rightQuad[ 3 ] = WindowVertex( x1, y2, 0, 1 );
quadList.append( rightQuad );
// bottom-left
x1 = 0 - fuzzy;
y1 = height;
x2 = 0;
y2 = height + fuzzy;
WindowQuad bottomLeftQuad( mShadowQuadTypes.at( 0 ), id++ );
bottomLeftQuad[ 0 ] = WindowVertex( x1, y1, 0, 0 );
bottomLeftQuad[ 1 ] = WindowVertex( x2, y1, 1, 0 );
bottomLeftQuad[ 2 ] = WindowVertex( x2, y2, 1, 1 );
bottomLeftQuad[ 3 ] = WindowVertex( x1, y2, 0, 1 );
quadList.append( bottomLeftQuad );
// bottom
x1 = 0;
y1 = height;
x2 = width;
y2 = height + fuzzy;
WindowQuad bottomQuad( mShadowQuadTypes.at( 0 ), id++ );
bottomQuad[ 0 ] = WindowVertex( x1, y1, 0, 0 );
bottomQuad[ 1 ] = WindowVertex( x2, y1, 1, 0 );
bottomQuad[ 2 ] = WindowVertex( x2, y2, 1, 1 );
bottomQuad[ 3 ] = WindowVertex( x1, y2, 0, 1 );
quadList.append( bottomQuad );
// bottom-right
x1 = width;
y1 = height;
x2 = width + fuzzy;
y2 = height + fuzzy;
WindowQuad bottomRightQuad( mShadowQuadTypes.at( 0 ), id++ );
bottomRightQuad[ 0 ] = WindowVertex( x1, y1, 0, 0 );
bottomRightQuad[ 1 ] = WindowVertex( x2, y1, 1, 0 );
bottomRightQuad[ 2 ] = WindowVertex( x2, y2, 1, 1 );
bottomRightQuad[ 3 ] = WindowVertex( x1, y2, 0, 1 );
quadList.append( bottomRightQuad );
} // This is called for menus, tooltips, windows where the user has disabled borders and shaped windows
effects->buildQuads( w, quadList );
}
QRect ShadowEffect::transformWindowDamage( EffectWindow* w, const QRect& r )
{
if( !useShadow( w ))
@ -286,6 +477,94 @@ void ShadowEffect::drawShadow( EffectWindow* window, int mask, QRegion region, c
glEnable( GL_BLEND );
glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
foreach( const WindowQuad &quad, data.quads )
{
if( !mShadowQuadTypes.contains( quad.type() ))
continue; // Not a shadow quad
glPushMatrix();
// Use the window's top-left as the origin
glTranslatef( window->x(), window->y(), 0 );
if( mask & PAINT_WINDOW_TRANSFORMED )
glTranslatef( data.xTranslate, data.yTranslate, 0 );
if(( mask & PAINT_WINDOW_TRANSFORMED ) && ( data.xScale != 1 || data.yScale != 1 ))
glScalef( data.xScale, data.yScale, 1 );
// Create our polygon
QVector<float> verts, texcoords;
verts.reserve(8);
texcoords.reserve(8);
verts << quad[0].x() << quad[0].y();
verts << quad[1].x() << quad[1].y();
verts << quad[2].x() << quad[2].y();
verts << quad[3].x() << quad[3].y();
texcoords << quad[0].textureX() << quad[0].textureY();
texcoords << quad[1].textureX() << quad[1].textureY();
texcoords << quad[2].textureX() << quad[2].textureY();
texcoords << quad[3].textureX() << quad[3].textureY();
// Work out which texture to use
int texture = mShadowQuadTypes.indexOf( quad.type() );
if( texture != -1 && texture < mShadowTextures.size() ) // TODO: Needed?
{
// Render it!
// Cheat a little, assume the active and inactive shadows have identical quads
// TODO: Opacity, saturation, brightness, etc.
if( window->hasDecoration() &&
effects->shadowTextureList( ShadowBorderedActive ) == texture )
{ // Decorated windows
// Active shadow
mShadowTextures.at( texture ).at( quad.id() )->bind();
glColor4f( 1.0, 1.0, 1.0, window->shadowOpacity( ShadowBorderedActive, data.opacity ));
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
mShadowTextures.at( texture ).at( quad.id() )->enableNormalizedTexCoords();
renderGLGeometry( region, 4, verts.data(), texcoords.data() );
mShadowTextures.at( texture ).at( quad.id() )->disableNormalizedTexCoords();
mShadowTextures.at( texture ).at( quad.id() )->unbind();
// Inactive shadow
texture = effects->shadowTextureList( ShadowBorderedInactive );
mShadowTextures.at( texture ).at( quad.id() )->bind();
glColor4f( 1.0, 1.0, 1.0, window->shadowOpacity( ShadowBorderedInactive, data.opacity ));
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
mShadowTextures.at( texture ).at( quad.id() )->enableNormalizedTexCoords();
renderGLGeometry( region, 4, verts.data(), texcoords.data() );
mShadowTextures.at( texture ).at( quad.id() )->disableNormalizedTexCoords();
mShadowTextures.at( texture ).at( quad.id() )->unbind();
}
else if( effects->shadowTextureList( ShadowBorderlessActive ) == texture )
{ // Decoration-less normal windows
if( effects->activeWindow() == window )
glColor4f( 1.0, 1.0, 1.0, window->shadowOpacity( ShadowBorderlessActive, data.opacity ));
else
{
texture = effects->shadowTextureList( ShadowBorderlessInactive );
glColor4f( 1.0, 1.0, 1.0, window->shadowOpacity( ShadowBorderlessInactive, data.opacity ));
}
mShadowTextures.at( texture ).at( quad.id() )->bind();
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
mShadowTextures.at( texture ).at( quad.id() )->enableNormalizedTexCoords();
renderGLGeometry( region, 4, verts.data(), texcoords.data() );
mShadowTextures.at( texture ).at( quad.id() )->disableNormalizedTexCoords();
mShadowTextures.at( texture ).at( quad.id() )->unbind();
}
else
{ // Other windows
mShadowTextures.at( texture ).at( quad.id() )->bind();
glColor4f( 1.0, 1.0, 1.0, window->shadowOpacity( ShadowOther, data.opacity ));
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
mShadowTextures.at( texture ).at( quad.id() )->enableNormalizedTexCoords();
renderGLGeometry( region, 4, verts.data(), texcoords.data() );
mShadowTextures.at( texture ).at( quad.id() )->disableNormalizedTexCoords();
mShadowTextures.at( texture ).at( quad.id() )->unbind();
}
}
glPopMatrix();
}
/*
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);
@ -348,8 +627,7 @@ void ShadowEffect::drawShadow( EffectWindow* window, int mask, QRegion region, c
renderGLGeometry( region, verticesCount, verts.data(), texcoords.data() );
mShadowTexture->disableNormalizedTexCoords();
mShadowTexture->unbind();
glPopMatrix();
*/
glPopAttrib();
}
#endif

View File

@ -53,6 +53,7 @@ class ShadowEffect
virtual void drawWindow( EffectWindow* w, int mask, QRegion region, WindowPaintData& data );
virtual void paintScreen( int mask, QRegion region, ScreenPaintData& data );
virtual void windowClosed( EffectWindow* c );
virtual void buildQuads( EffectWindow* w, WindowQuadList& quadList );
virtual QRect transformWindowDamage( EffectWindow* w, const QRect& r );
private slots:
@ -73,12 +74,14 @@ class ShadowEffect
bool intensifyActiveShadow;
QColor shadowColor;
#ifdef KWIN_HAVE_OPENGL_COMPOSITING
GLTexture* mShadowTexture;
QList< QList<GLTexture*> > mShadowTextures;
#endif
#ifdef KWIN_HAVE_XRENDER_COMPOSITING
ShadowTiles *mShadowPics;
#endif
QList<WindowQuadType> mShadowQuadTypes;
struct ShadowData
{
ShadowData(EffectWindow* _w, WindowPaintData& _data) : w(_w), data(_data) {}

View File

@ -429,6 +429,25 @@ void KDecorationPreviewBridge::grabXServer( bool )
{
}
void KDecorationPreviewBridge::repaintShadow()
{
}
bool KDecorationPreviewBridge::compositingActive() const
{
return false;
}
bool KDecorationPreviewBridge::shadowsActive() const
{
return false;
}
double KDecorationPreviewBridge::opacity() const
{
return 1.0;
}
KDecorationPreviewOptions::KDecorationPreviewOptions()
{
customBorderSize = BordersCount; // invalid

View File

@ -66,7 +66,7 @@ class KDecorationPreview
};
class KDecorationPreviewBridge
: public KDecorationBridge
: public KDecorationBridge2
{
public:
KDecorationPreviewBridge( KDecorationPreview* preview, bool active );
@ -112,6 +112,11 @@ class KDecorationPreviewBridge
virtual QWidget* initialParentWidget() const;
virtual Qt::WFlags initialWFlags() const;
virtual void grabXServer( bool grab );
virtual void repaintShadow();
virtual bool compositingActive() const;
virtual bool shadowsActive() const;
virtual double opacity() const;
private:
KDecorationPreview* preview;
bool active;

View File

@ -1221,5 +1221,58 @@ KDecoration* KCommonDecoration::decoration()
return wrapper;
}
KCommonDecoration2::KCommonDecoration2(KDecorationBridge* bridge, KDecorationFactory* factory)
: KCommonDecoration( bridge, factory )
{
Q_ASSERT( dynamic_cast<const KDecoration2*>( decoration() ));
}
KCommonDecoration2::~KCommonDecoration2()
{
}
// All copied from kdecoration.cpp
QList<QRect> KCommonDecoration2::shadowQuads( ShadowType type ) const
{
Q_UNUSED( type );
return QList<QRect>();
}
double KCommonDecoration2::shadowOpacity( ShadowType type, double dataOpacity ) const
{
if( isActive() && type == ShadowBorderedActive )
return dataOpacity;
else if( !isActive() && type == ShadowBorderedInactive )
return dataOpacity;
return 0.0;
}
double KCommonDecoration2::shadowBrightness( ShadowType type ) const
{
Q_UNUSED( type );
return 1.0;
}
double KCommonDecoration2::shadowSaturation( ShadowType type ) const
{
Q_UNUSED( type );
return 1.0;
}
void KCommonDecoration2::repaintShadow()
{
return static_cast<const KDecoration2*>( decoration() )->repaintShadow();
}
bool KCommonDecoration2::compositingActive() const
{
return static_cast<const KDecoration2*>( decoration() )->compositingActive();
}
bool KCommonDecoration2::shadowsActive() const
{
return static_cast<const KDecoration2*>( decoration() )->shadowsActive();
}
double KCommonDecoration2::opacity() const
{
return static_cast<const KDecoration2*>( decoration() )->opacity();
}
// kate: space-indent on; indent-width 4; mixedindent off; indent-mode cstyle;

View File

@ -362,6 +362,23 @@ class KWIN_EXPORT KCommonDecoration : public QObject, public KDecorationDefines
KCommonDecorationPrivate *d;
};
class KWIN_EXPORT KCommonDecoration2
: public KCommonDecoration
{
Q_OBJECT
public:
KCommonDecoration2(KDecorationBridge* bridge, KDecorationFactory* factory);
virtual ~KCommonDecoration2();
virtual QList<QRect> shadowQuads( ShadowType type ) const;
virtual double shadowOpacity( ShadowType type, double dataOpacity ) const;
virtual double shadowBrightness( ShadowType type ) const;
virtual double shadowSaturation( ShadowType type ) const;
void repaintShadow();
bool compositingActive() const;
bool shadowsActive() const;
double opacity() const;
};
/**
* Title bar buttons of KCommonDecoration need to inherit this class.
*/

View File

@ -25,11 +25,14 @@
#include "kcommondecoration_p.h"
#include "kcommondecoration.h"
#include "kdecorationbridge.h"
#include <assert.h>
#include "kcommondecoration_p.moc"
KCommonDecorationWrapper::KCommonDecorationWrapper( KCommonDecoration* deco, KDecorationBridge* bridge, KDecorationFactory* factory )
: KDecoration( bridge, factory )
: KDecoration2( bridge, factory )
, decoration( deco )
{
}
@ -109,3 +112,31 @@ void KCommonDecorationWrapper::reset( unsigned long changed )
{
return decoration->reset( changed );
}
QList<QRect> KCommonDecorationWrapper::shadowQuads( ShadowType type ) const
{
if( KCommonDecoration2 *decoration2 = dynamic_cast<KCommonDecoration2*>( decoration ))
return decoration2->shadowQuads( type );
return QList<QRect>();
}
double KCommonDecorationWrapper::shadowOpacity( ShadowType type, double dataOpacity ) const
{
if( KCommonDecoration2 *decoration2 = dynamic_cast<KCommonDecoration2*>( decoration ))
return decoration2->shadowOpacity( type, dataOpacity );
return dataOpacity;
}
double KCommonDecorationWrapper::shadowBrightness( ShadowType type ) const
{
if( KCommonDecoration2 *decoration2 = dynamic_cast<KCommonDecoration2*>( decoration ))
return decoration2->shadowBrightness( type );
return 1.0;
}
double KCommonDecorationWrapper::shadowSaturation( ShadowType type ) const
{
if( KCommonDecoration2 *decoration2 = dynamic_cast<KCommonDecoration2*>( decoration ))
return decoration2->shadowSaturation( type );
return 1.0;
}

View File

@ -32,12 +32,13 @@
//
class KCommonDecoration;
class KCommonDecoration2;
class KDecorationBridge;
class KDecorationFactory;
// wrapper all functionality that needs reimplementing in KDecoration and forward it to KCommonDecoration
class KCommonDecorationWrapper
: public KDecoration
: public KDecoration2
{
Q_OBJECT
public:
@ -57,6 +58,11 @@ class KCommonDecorationWrapper
virtual bool drawbound( const QRect& geom, bool clear );
virtual bool windowDocked( Position side );
virtual void reset( unsigned long changed );
virtual QList<QRect> shadowQuads( ShadowType type ) const;
virtual double shadowOpacity( ShadowType type, double dataOpacity ) const;
virtual double shadowBrightness( ShadowType type ) const;
virtual double shadowSaturation( ShadowType type ) const;
private:
KCommonDecoration* decoration;
};

View File

@ -382,6 +382,65 @@ KDecoration::Position KDecoration::mousePosition( const QPoint& p ) const
return m;
}
KDecoration2::KDecoration2( KDecorationBridge* bridge, KDecorationFactory* factory )
: KDecoration( bridge, factory )
{
Q_ASSERT( dynamic_cast< KDecorationBridge2* >( bridge ));
}
KDecoration2::~KDecoration2()
{
}
QList<QRect> KDecoration2::shadowQuads( ShadowType type ) const
{
Q_UNUSED( type );
return QList<QRect>();
}
double KDecoration2::shadowOpacity( ShadowType type, double dataOpacity ) const
{
if( isActive() && type == ShadowBorderedActive )
return dataOpacity;
else if( !isActive() && type == ShadowBorderedInactive )
return dataOpacity;
return 0.0;
}
double KDecoration2::shadowBrightness( ShadowType type ) const
{
Q_UNUSED( type );
return 1.0;
}
double KDecoration2::shadowSaturation( ShadowType type ) const
{
Q_UNUSED( type );
return 1.0;
}
void KDecoration2::repaintShadow()
{
static_cast< KDecorationBridge2* >( bridge_ )->repaintShadow();
}
bool KDecoration2::compositingActive() const
{
return static_cast< KDecorationBridge2* >( bridge_ )->compositingActive();
}
bool KDecoration2::shadowsActive() const
{
return static_cast< KDecorationBridge2* >( bridge_ )->shadowsActive();
}
double KDecoration2::opacity() const
{
return static_cast< KDecorationBridge2* >( bridge_ )->opacity();
}
KDecorationOptions::KDecorationOptions()
: d( new KDecorationOptionsPrivate )
{

View File

@ -184,6 +184,8 @@ public:
AbilityColorButtonBack = 2020, ///< decoration supports button background color
AbilityColorButtonFore = 2021, ///< decoration supports button foreground color
ABILITYCOLOR_END, ///< @internal
// compositing
AbilityCompositingShadow = 3000, ///< decoration supports window shadows
// TODO colors for individual button types
ABILITY_DUMMY = 10000000
};
@ -191,6 +193,18 @@ public:
enum Requirement { REQUIREMENT_DUMMY = 1000000 };
};
/**
* Decoration shadow type.
*/
enum ShadowType
{
ShadowBorderedActive = 0, ///< Active shadow of decorated windows
ShadowBorderedInactive, ///< Inctive shadow of decorated windows
ShadowBorderlessActive, ///< Active shadow of undecorated windows
ShadowBorderlessInactive, ///< Inctive shadow of undecorated windows
ShadowOther ///< Shadow of all other windows (Menus, comboboxes, tooltips, etc.)
};
class KDecorationProvides
: public KDecorationDefines
{
@ -845,10 +859,59 @@ class KWIN_EXPORT KDecoration
QWidget* w_;
KDecorationFactory* factory_;
friend class KDecorationOptions; // for options_
friend class KDecoration2; // for bridge_
static KDecorationOptions* options_;
KDecorationPrivate* d;
};
class KWIN_EXPORT KDecoration2
: public KDecoration
{
Q_OBJECT
public:
KDecoration2( KDecorationBridge* bridge, KDecorationFactory* factory );
virtual ~KDecoration2();
/**
* This function should return the positions of the shadow quads to be rendered.
* All positions are relative to the window's top-left corner. Only "bordered"
* windows will call this method.
*/
virtual QList<QRect> shadowQuads( ShadowType type ) const;
/**
* This function should return the opacity of the shadow. This is not multiplied
* with the opacity of the window afterwards but is instead provided as \a dataOpacity
*/
virtual double shadowOpacity( ShadowType type, double dataOpacity ) const;
/**
* This function should return the desired brightness of the shadow.
*/
virtual double shadowBrightness( ShadowType type ) const;
/**
* This function should return the desired saturation of the shadow.
*/
virtual double shadowSaturation( ShadowType type ) const;
/**
* Force a repaint of the shadow. Automatically called when the window changes states.
*/
void repaintShadow();
/**
* Returns @a true if compositing is enabled (Currently useless to decorations,
* use \a shadowsActive() instead).
*/
bool compositingActive() const;
/**
* Returns @a true if compositing is enabled and the shadow effect is activated
* by the current user.
*/
bool shadowsActive() const;
/**
* Returns the opacity that the decoration will be rendered at.
*/
double opacity() const;
};
inline
KDecorationDefines::MaximizeMode operator^( KDecorationDefines::MaximizeMode m1, KDecorationDefines::MaximizeMode m2 )
{

View File

@ -89,6 +89,16 @@ class KDecorationBridge : public KDecorationDefines
virtual void grabXServer( bool grab ) = 0;
};
class KWIN_EXPORT KDecorationBridge2
: public KDecorationBridge
{
public:
virtual void repaintShadow() = 0;
virtual bool compositingActive() const = 0;
virtual bool shadowsActive() const = 0;
virtual double opacity() const = 0;
};
/** @} */
#endif

View File

@ -78,3 +78,39 @@ NET::WindowType KDecorationFactory::windowType( unsigned long supported_types, K
{
return bridge->windowType( supported_types );
}
QList< QList<QImage> > KDecorationFactory2::shadowTextures()
{
return QList< QList<QImage> >();
}
int KDecorationFactory2::shadowTextureList( ShadowType type ) const
{
Q_UNUSED( type );
return -1;
}
QList<QRect> KDecorationFactory2::shadowQuads( ShadowType type, QSize size ) const
{
Q_UNUSED( type );
Q_UNUSED( size );
return QList<QRect>();
}
double KDecorationFactory2::shadowOpacity( ShadowType type, double dataOpacity ) const
{
Q_UNUSED( type );
return dataOpacity;
}
double KDecorationFactory2::shadowBrightness( ShadowType type ) const
{
Q_UNUSED( type );
return 1.0;
}
double KDecorationFactory2::shadowSaturation( ShadowType type ) const
{
Q_UNUSED( type );
return 1.0;
}

View File

@ -114,7 +114,44 @@ class KWIN_EXPORT KDecorationFactory
QList< KDecoration* > _decorations;
KDecorationFactoryPrivate* d;
};
class KWIN_EXPORT KDecorationFactory2
: public KDecorationFactory
{
public:
/**
* This function should return the texture lists that contain the textures of the
* shadow quads. Textures are mapped to the quad that has the same list offset.
* E.g. texture[0][2] is rendered where the third QRect that shadowQuads()
* returns is if using the first texture list.
*/
virtual QList< QList<QImage> > shadowTextures();
/**
* This function should return the texture list offset for the requested type.
*/
virtual int shadowTextureList( ShadowType type ) const;
/**
* This function should return the positions of the shadow quads to be rendered.
* All positions are relative to the window's top-left corner. Only "borderless"
* and "other" types will call this method.
* @param size The size of the window.
*/
virtual QList<QRect> shadowQuads( ShadowType type, QSize size ) const;
/**
* This function should return the opacity of the shadow. This is not multiplied
* with the opacity of the window afterwards but is instead provided as \a dataOpacity
*/
virtual double shadowOpacity( ShadowType type, double dataOpacity ) const;
/**
* This function should return the desired brightness of the shadow.
*/
virtual double shadowBrightness( ShadowType type ) const;
/**
* This function should return the desired saturation of the shadow.
*/
virtual double shadowSaturation( ShadowType type ) const;
};
inline const KDecorationOptions* KDecorationFactory::options()
{
return KDecoration::options();

View File

@ -224,6 +224,11 @@ void Effect::drawWindow( EffectWindow* w, int mask, QRegion region, WindowPaintD
effects->drawWindow( w, mask, region, data );
}
void Effect::buildQuads( EffectWindow* w, WindowQuadList& quadList )
{
effects->buildQuads( w, quadList );
}
QRect Effect::transformWindowDamage( EffectWindow* w, const QRect& r )
{
return effects->transformWindowDamage( w, r );
@ -279,6 +284,7 @@ EffectsHandler::EffectsHandler(CompositingType type)
: current_paint_screen( 0 )
, current_paint_window( 0 )
, current_draw_window( 0 )
, current_build_quads( 0 )
, current_transform( 0 )
, compositing_type( type )
{
@ -741,12 +747,12 @@ WindowQuadList WindowQuadList::select( WindowQuadType type ) const
{
foreach( const WindowQuad &q, *this )
{
if( q.type != type ) // something else than ones to select, make a copy and filter
if( q.type() != type ) // something else than ones to select, make a copy and filter
{
WindowQuadList ret;
foreach( const WindowQuad &q, *this )
{
if( q.type == type )
if( q.type() == type )
ret.append( q );
}
return ret;
@ -759,12 +765,12 @@ WindowQuadList WindowQuadList::filterOut( WindowQuadType type ) const
{
foreach( const WindowQuad &q, *this )
{
if( q.type == type ) // something to filter out, make a copy and filter
if( q.type() == type ) // something to filter out, make a copy and filter
{
WindowQuadList ret;
foreach( const WindowQuad &q, *this )
{
if( q.type != type )
if( q.type() != type )
ret.append( q );
}
return ret;

View File

@ -23,6 +23,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <kwinconfig.h>
#include <kwinglobals.h>
#include "kdecoration.h"
#include <QtCore/QPair>
#include <QtCore/QRect>
@ -167,6 +168,14 @@ X-KDE-Library=kwin4_effect_cooleffect
#define KWIN_EFFECT_API_VERSION KWIN_EFFECT_API_MAKE_VERSION( \
KWIN_EFFECT_API_VERSION_MAJOR, KWIN_EFFECT_API_VERSION_MINOR )
enum WindowQuadType
{
WindowQuadError, // for the stupid default ctor
WindowQuadContents,
WindowQuadDecoration,
EFFECT_QUAD_TYPE_START = 100 ///< @internal
};
/**
* Infinite region (i.e. a special region type saying that everything needs to be painted).
*/
@ -343,6 +352,13 @@ class KWIN_EXPORT Effect
* do any transformations
**/
virtual void drawWindow( EffectWindow* w, int mask, QRegion region, WindowPaintData& data );
/**
* Define new window quads so that they can be transformed by other effects.
* It's up to the effect to keep track of them.
**/
virtual void buildQuads( EffectWindow* w, WindowQuadList& quadList );
/**
* This function is used e.g. by the shadow effect which adds area around windows
* that needs to be painted as well - e.g. when a window is hidden and the workspace needs
@ -479,6 +495,7 @@ class KWIN_EXPORT EffectsHandler
virtual void paintWindow( EffectWindow* w, int mask, QRegion region, WindowPaintData& data ) = 0;
virtual void postPaintWindow( EffectWindow* w ) = 0;
virtual void drawWindow( EffectWindow* w, int mask, QRegion region, WindowPaintData& data ) = 0;
virtual void buildQuads( EffectWindow* w, WindowQuadList& quadList ) = 0;
virtual QRect transformWindowDamage( EffectWindow* w, const QRect& r );
// Functions for handling input - e.g. when an Expose-like effect is shown, an input window
// covering the whole screen is created and all mouse events will be intercepted by it.
@ -526,6 +543,7 @@ class KWIN_EXPORT EffectsHandler
* if used manually.
*/
virtual double animationTimeFactor() const = 0;
virtual WindowQuadType newWindowQuadType() = 0;
virtual EffectWindow* findWindow( WId id ) const = 0;
virtual EffectWindowList stackingOrder() const = 0;
@ -571,6 +589,22 @@ class KWIN_EXPORT EffectsHandler
*/
virtual void registerPropertyType( long atom, bool reg ) = 0;
/**
* Returns @a true if the active window decoration has shadow API hooks.
*/
virtual bool hasDecorationShadows() const = 0;
/**
* Returns the textures to be used in the shadow. Textures are mapped
* to the quad that has the same list offset. E.g. texture[2] is
* rendered where the third QRect that EffectWindow::shadowQuads()
* returns is.
*/
virtual QList< QList<QImage> > shadowTextures() = 0;
/**
* Returns the texture list offset for the requested type.
*/
virtual int shadowTextureList( ShadowType type ) const = 0;
/**
* Paints given text onto screen, possibly in elided form
* @param text
@ -611,6 +645,7 @@ class KWIN_EXPORT EffectsHandler
int current_paint_screen;
int current_paint_window;
int current_draw_window;
int current_build_quads;
int current_transform;
CompositingType compositing_type;
};
@ -784,6 +819,25 @@ class KWIN_EXPORT EffectWindow
virtual EffectWindow* findModal() = 0;
virtual EffectWindowList mainWindows() const = 0;
/**
* Returns the positions of the shadow quads to be rendered. All positions
* are relative to the window's top-left corner.
*/
virtual QList<QRect> shadowQuads( ShadowType type ) const = 0;
/**
* Returns the opacity of the shadow. This has already been pre-multiplied by
* the window's opacity if the decoration desires so.
*/
virtual double shadowOpacity( ShadowType type, double dataOpacity ) const = 0;
/**
* Returns the desired brightness of the shadow.
*/
virtual double shadowBrightness( ShadowType type ) const = 0;
/**
* Returns the desired saturation of the shadow.
*/
virtual double shadowSaturation( ShadowType type ) const = 0;
// TODO internal?
virtual WindowQuadList buildQuads() const = 0;
};
@ -817,6 +871,8 @@ class KWIN_EXPORT WindowVertex
void setY( double y );
double originalX() const;
double originalY() const;
double textureX() const;
double textureY() const;
WindowVertex();
WindowVertex( double x, double y, double tx, double ty );
private:
@ -827,13 +883,6 @@ class KWIN_EXPORT WindowVertex
double tx, ty; // texture coords
};
enum WindowQuadType
{
WindowQuadError, // for the stupid default ctor
WindowQuadContents,
WindowQuadDecoration
};
/**
* @short Class representing one area of a window.
*
@ -843,11 +892,14 @@ enum WindowQuadType
class KWIN_EXPORT WindowQuad
{
public:
explicit WindowQuad( WindowQuadType type );
explicit WindowQuad( WindowQuadType type, int id = -1 );
WindowQuad makeSubQuad( double x1, double y1, double x2, double y2 ) const;
WindowVertex& operator[]( int index );
const WindowVertex& operator[]( int index ) const;
WindowQuadType type() const;
int id() const;
bool decoration() const;
bool effect() const;
double left() const;
double right() const;
double top() const;
@ -861,7 +913,8 @@ class KWIN_EXPORT WindowQuad
private:
friend class WindowQuadList;
WindowVertex verts[ 4 ];
WindowQuadType type; // 0 - contents, 1 - decoration
WindowQuadType quadType; // 0 - contents, 1 - decoration
int quadID;
};
class KWIN_EXPORT WindowQuadList
@ -1472,6 +1525,18 @@ double WindowVertex::originalY() const
return oy;
}
inline
double WindowVertex::textureX() const
{
return tx;
}
inline
double WindowVertex::textureY() const
{
return ty;
}
inline
void WindowVertex::move( double x, double y )
{
@ -1496,8 +1561,9 @@ void WindowVertex::setY( double y )
***************************************************************/
inline
WindowQuad::WindowQuad( WindowQuadType t )
: type( t )
WindowQuad::WindowQuad( WindowQuadType t, int id )
: quadType( t )
, quadID( id )
{
}
@ -1515,11 +1581,31 @@ const WindowVertex& WindowQuad::operator[]( int index ) const
return verts[ index ];
}
inline
WindowQuadType WindowQuad::type() const
{
assert( quadType != WindowQuadError );
return quadType;
}
inline
int WindowQuad::id() const
{
return quadID;
}
inline
bool WindowQuad::decoration() const
{
assert( type != WindowQuadError );
return type == WindowQuadDecoration;
assert( quadType != WindowQuadError );
return quadType == WindowQuadDecoration;
}
inline
bool WindowQuad::effect() const
{
assert( quadType != WindowQuadError );
return quadType >= EFFECT_QUAD_TYPE_START;
}
inline

View File

@ -461,6 +461,7 @@ WindowQuadList Scene::Window::buildQuads() const
ret = makeQuads( WindowQuadContents, contents );
ret += makeQuads( WindowQuadDecoration, decoration );
}
effects->buildQuads( static_cast<Client*>( toplevel )->effectWindow(), ret );
cached_quad_list = new WindowQuadList( ret );
return ret;
}

View File

@ -43,7 +43,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <kconfiggroup.h>
#include <QtDBus/QtDBus>
#include "plugins.h"
#include "client.h"
#include "popupinfo.h"
#include "tabbox.h"
@ -57,7 +56,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "scene.h"
#include "deleted.h"
#include "effects.h"
#include "kdecorationfactory.h"
#include <X11/extensions/shape.h>
#include <X11/keysym.h>

View File

@ -31,8 +31,10 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <QDateTime>
#include <kmanagerselection.h>
#include "plugins.h"
#include "utils.h"
#include "kdecoration.h"
#include "kdecorationfactory.h"
#include "sm.h"
#include <X11/Xlib.h>
@ -242,6 +244,14 @@ class Workspace : public QObject, public KDecorationDefines
void disableRulesUpdates( bool disable );
bool rulesUpdatesDisabled() const;
bool hasDecorationShadows() const;
QList< QList<QImage> > decorationShadowTextures();
int decorationShadowTextureList( ShadowType type ) const;
QList<QRect> decorationShadowQuads( ShadowType type, QSize size ) const;
double decorationShadowOpacity( ShadowType type, double dataOpacity ) const;
double decorationShadowBrightness( ShadowType type ) const;
double decorationShadowSaturation( ShadowType type ) const;
// dcop interface
void cascadeDesktop();
void unclutterDesktop();
@ -981,6 +991,60 @@ void Workspace::checkCompositeTimer()
setCompositeTimer();
}
inline
bool Workspace::hasDecorationShadows() const
{
return mgr->factory()->supports( AbilityCompositingShadow );
}
inline
QList< QList<QImage> > Workspace::decorationShadowTextures()
{
if( KDecorationFactory2* factory = dynamic_cast< KDecorationFactory2* >( mgr->factory() ))
return factory->shadowTextures();
return QList< QList<QImage> >();
}
inline
int Workspace::decorationShadowTextureList( ShadowType type ) const
{
if( KDecorationFactory2* factory = dynamic_cast< KDecorationFactory2* >( mgr->factory() ))
return factory->shadowTextureList( type );
return -1;
}
inline
QList<QRect> Workspace::decorationShadowQuads( ShadowType type, QSize size ) const
{
if( KDecorationFactory2* factory = dynamic_cast< KDecorationFactory2* >( mgr->factory() ))
return factory->shadowQuads( type, size );
return QList<QRect>();
}
inline
double Workspace::decorationShadowOpacity( ShadowType type, double dataOpacity ) const
{
if( KDecorationFactory2* factory = dynamic_cast< KDecorationFactory2* >( mgr->factory() ))
return factory->shadowOpacity( type, dataOpacity );
return dataOpacity;
}
inline
double Workspace::decorationShadowBrightness( ShadowType type ) const
{
if( KDecorationFactory2* factory = dynamic_cast< KDecorationFactory2* >( mgr->factory() ))
return factory->shadowBrightness( type );
return 1.0;
}
inline
double Workspace::decorationShadowSaturation( ShadowType type ) const
{
if( KDecorationFactory2* factory = dynamic_cast< KDecorationFactory2* >( mgr->factory() ))
return factory->shadowSaturation( type );
return 1.0;
}
} // namespace
#endif