Texture scaling in resize effect and disabling the drawbound when the effect is present.

This provides a good resizing performance for users having problems with the live-updating resize.
Patch by Thomas Lübking.

svn path=/trunk/KDE/kdebase/workspace/; revision=1118714
This commit is contained in:
Martin Gräßlin 2010-04-25 18:40:04 +00:00
parent fa0bc81364
commit f6ebb5d913
6 changed files with 111 additions and 48 deletions

View file

@ -213,6 +213,14 @@ void EffectsHandlerImpl::postPaintWindow( EffectWindow* w )
// no special final code
}
bool EffectsHandlerImpl::provideResizeEffect()
{
for( int i = 0; i < loaded_effects.size(); ++i )
if( loaded_effects.at(i).second->isResizeEffect() )
return true;
return false;
}
void EffectsHandlerImpl::drawWindow( EffectWindow* w, int mask, QRegion region, WindowPaintData& data )
{
if( current_draw_window < loaded_effects.size())

View file

@ -47,6 +47,8 @@ class EffectsHandlerImpl : public EffectsHandler
virtual void paintWindow( EffectWindow* w, int mask, QRegion region, WindowPaintData& data );
virtual void postPaintWindow( EffectWindow* w );
bool provideResizeEffect();
virtual void drawWindow( EffectWindow* w, int mask, QRegion region, WindowPaintData& data );
virtual void buildQuads( EffectWindow* w, WindowQuadList& quadList );

View file

@ -55,50 +55,82 @@ void ResizeEffect::prePaintScreen( ScreenPrePaintData& data, int time )
effects->prePaintScreen( data, time );
}
void ResizeEffect::prePaintWindow( EffectWindow* w, WindowPrePaintData& data, int time )
{
if( m_active && w == m_resizeWindow )
data.mask |= PAINT_WINDOW_TRANSFORMED;
effects->prePaintWindow( w, data, time );
}
void ResizeEffect::paintWindow( EffectWindow* w, int mask, QRegion region, WindowPaintData& data )
{
effects->paintWindow( w, mask, region, data );
if( m_active && w == m_resizeWindow )
{
QRegion intersection = m_originalWindowRect.intersected( m_currentGeometry );
QRegion paintRegion = m_originalWindowRect.united( m_currentGeometry ).subtracted( intersection );
float alpha = 0.8f;
QColor color = KColorScheme( QPalette::Normal, KColorScheme::Selection ).background().color();
if( m_features & TextureScale )
{
data.xTranslate += m_currentGeometry.x() - m_originalGeometry.x();
data.xScale *= m_currentGeometry.width();
data.xScale /= m_originalGeometry.width();
data.yTranslate += m_currentGeometry.y() - m_originalGeometry.y();
data.yScale *= m_currentGeometry.height();
data.yScale /= m_originalGeometry.height();
}
effects->paintWindow( w, mask, region, data );
if( m_features & Outline )
{
QRegion intersection = m_originalGeometry.intersected( m_currentGeometry );
QRegion paintRegion = QRegion(m_originalGeometry).united( m_currentGeometry ).subtracted( intersection );
float alpha = 0.8f;
QColor color = KColorScheme( QPalette::Normal, KColorScheme::Selection ).background().color();
#ifdef KWIN_HAVE_OPENGL_COMPOSITING
if( effects->compositingType() == OpenGLCompositing)
{
glPushAttrib( GL_CURRENT_BIT | GL_ENABLE_BIT );
glEnable( GL_BLEND );
glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
glColor4f( color.red() / 255.0f, color.green() / 255.0f, color.blue() / 255.0f, alpha );
glBegin( GL_QUADS );
foreach( const QRect &r, paintRegion.rects() )
if( effects->compositingType() == OpenGLCompositing)
{
glVertex2i( r.x(), r.y() );
glVertex2i( r.x() + r.width(), r.y() );
glVertex2i( r.x() + r.width(), r.y() + r.height() );
glVertex2i( r.x(), r.y() + r.height() );
glPushAttrib( GL_CURRENT_BIT | GL_ENABLE_BIT );
glEnable( GL_BLEND );
glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
glColor4f( color.red() / 255.0f, color.green() / 255.0f, color.blue() / 255.0f, alpha );
glBegin( GL_QUADS );
foreach( const QRect &r, paintRegion.rects() )
{
glVertex2i( r.x(), r.y() );
glVertex2i( r.x() + r.width(), r.y() );
glVertex2i( r.x() + r.width(), r.y() + r.height() );
glVertex2i( r.x(), r.y() + r.height() );
}
glEnd();
glPopAttrib();
}
glEnd();
glPopAttrib();
}
#endif
#ifdef KWIN_HAVE_XRENDER_COMPOSITING
if( effects->compositingType() == XRenderCompositing)
{
XRenderColor col;
col.alpha = int( alpha * 0xffff );
col.red = int( alpha * 0xffff * color.red() / 255 );
col.green = int( alpha * 0xffff * color.green() / 255 );
col.blue= int( alpha * 0xffff * color.blue() / 255 );
foreach( const QRect &r, paintRegion.rects() )
XRenderFillRectangle( display(), PictOpOver, effects->xrenderBufferPicture(),
&col, r.x(), r.y(), r.width(), r.height());
}
if( effects->compositingType() == XRenderCompositing)
{
XRenderColor col;
col.alpha = int( alpha * 0xffff );
col.red = int( alpha * 0xffff * color.red() / 255 );
col.green = int( alpha * 0xffff * color.green() / 255 );
col.blue= int( alpha * 0xffff * color.blue() / 255 );
foreach( const QRect &r, paintRegion.rects() )
XRenderFillRectangle( display(), PictOpOver, effects->xrenderBufferPicture(),
&col, r.x(), r.y(), r.width(), r.height());
}
#endif
}
}
else
effects->paintWindow( w, mask, region, data );
}
void ResizeEffect::reconfigure( ReconfigureFlags )
{
KConfigGroup conf = effects->effectConfig("Resize");
m_features = 0;
if ( conf.readEntry( "TextureScale", true ) )
m_features |= TextureScale;
if ( conf.readEntry( "Outline", false ) )
m_features |= Outline;
}
void ResizeEffect::windowUserMovedResized( EffectWindow* w, bool first, bool last )
@ -112,7 +144,7 @@ void ResizeEffect::windowUserMovedResized( EffectWindow* w, bool first, bool las
{
m_active = true;
m_resizeWindow = w;
m_originalWindowRect = w->geometry();
m_originalGeometry = w->geometry();
m_currentGeometry = w->geometry();
w->addRepaintFull();
}

View file

@ -32,16 +32,20 @@ class ResizeEffect
public:
ResizeEffect();
~ResizeEffect();
virtual inline bool isResizeEffect() { return true; }
virtual void prePaintScreen( ScreenPrePaintData& data, int time );
virtual void prePaintWindow( EffectWindow* w, WindowPrePaintData& data, int time );
virtual void paintWindow( EffectWindow* w, int mask, QRegion region, WindowPaintData& data );
virtual void reconfigure( ReconfigureFlags );
virtual void windowUserMovedResized( EffectWindow *w, bool first, bool last );
virtual void windowMoveResizeGeometryUpdate(EffectWindow* c, const QRect& geometry);
private:
enum Feature { TextureScale = 1<<0, Outline = 1<<1 };
bool m_active;
int m_features;
EffectWindow* m_resizeWindow;
QRegion m_originalWindowRect;
QRect m_currentGeometry;
QRect m_currentGeometry, m_originalGeometry;
};
}

View file

@ -2660,7 +2660,9 @@ void Client::clearbound()
void Client::doDrawbound( const QRect& geom, bool clear )
{
if( decoration != NULL && decoration->drawbound( geom, clear ))
if( effects && static_cast<EffectsHandlerImpl*>(effects)->provideResizeEffect() )
return; // done by effect
if( decoration != NULL && decoration->drawbound( geom, clear ) )
return; // done by decoration
XGCValues xgc;
xgc.function = GXxor;
@ -3275,9 +3277,18 @@ void Client::handleMoveResize( int x, int y, int x_root, int y_root )
void Client::performMoveResize()
{
bool haveResizeEffect = false;
bool transparent = false;
if( isResize() )
{
haveResizeEffect = effects && static_cast<EffectsHandlerImpl*>(effects)->provideResizeEffect();
transparent = haveResizeEffect || options->resizeMode == Options::Transparent;
}
else
transparent = options->moveMode == Options::Transparent;
#ifdef HAVE_XSYNC
if( isResize() && options->resizeMode == Options::Opaque &&
sync_counter != None && !sync_resize_pending )
if( isResize() && !transparent && sync_counter != None && !sync_resize_pending )
{
sync_timeout = new QTimer( this );
connect( sync_timeout, SIGNAL( timeout()), SLOT( syncTimeout()));
@ -3287,20 +3298,20 @@ void Client::performMoveResize()
}
#endif
sync_resize_pending = false;
if( rules()->checkMoveResizeMode
( isResize() ? options->resizeMode : options->moveMode ) == Options::Opaque )
if( transparent )
{
if( !haveResizeEffect )
clearbound(); // it's necessary to move the geometry tip when there's no outline
positionGeometryTip(); // shown, otherwise it would cause repaint problems in case
if( !haveResizeEffect )
drawbound( moveResizeGeom ); // they overlap; the paint event will come after this,
}
else
{
if( !workspace()->tilingMode() )
setGeometry( moveResizeGeom );
setGeometry( moveResizeGeom );
positionGeometryTip();
}
else if( rules()->checkMoveResizeMode
( isResize() ? options->resizeMode : options->moveMode ) == Options::Transparent )
{
clearbound(); // it's necessary to move the geometry tip when there's no outline
positionGeometryTip(); // shown, otherwise it would cause repaint problems in case
drawbound( moveResizeGeom ); // they overlap; the paint event will come after this,
} // so the geometry tip will be painted above the outline
if( effects )
{
static_cast<EffectsHandlerImpl*>(effects)->windowMoveResizeGeometryUpdate( effectWindow(), moveResizeGeom );

View file

@ -170,7 +170,7 @@ X-KDE-Library=kwin4_effect_cooleffect
#define KWIN_EFFECT_API_MAKE_VERSION( major, minor ) (( major ) << 8 | ( minor ))
#define KWIN_EFFECT_API_VERSION_MAJOR 0
#define KWIN_EFFECT_API_VERSION_MINOR 132
#define KWIN_EFFECT_API_VERSION_MINOR 133
#define KWIN_EFFECT_API_VERSION KWIN_EFFECT_API_MAKE_VERSION( \
KWIN_EFFECT_API_VERSION_MAJOR, KWIN_EFFECT_API_VERSION_MINOR )
@ -375,6 +375,12 @@ class KWIN_EXPORT Effect
**/
virtual void postPaintWindow( EffectWindow* w );
/**
* Called on Transparent resizes.
* return true if your effect substitutes the XOR rubberband
*/
virtual bool isResizeEffect() { return false; }
/**
* Can be called to draw multiple copies (e.g. thumbnails) of a window.
* You can change window's opacity/brightness/etc here, but you can't