restrict AnimationEffect repainting

BUMPs Effect API to 183
icc-effect-5.14.5
Thomas Lübking 2012-02-11 16:47:46 +01:00
parent 239d5757f2
commit 39fb788103
5 changed files with 161 additions and 15 deletions

View File

@ -1401,6 +1401,11 @@ QRect EffectWindowImpl::decorationInnerRect() const
return client ? client->transparentRect() : contentsRect();
}
QRect EffectWindowImpl::decorationRect() const
{
return toplevel->decorationRect();
}
QByteArray EffectWindowImpl::readProperty(long atom, long type, int format) const
{
return readWindowProperty(window()->window(), atom, type, format);

View File

@ -242,6 +242,7 @@ public:
virtual QRegion shape() const;
virtual QRect decorationInnerRect() const;
virtual QRect decorationRect() const;
virtual QByteArray readProperty(long atom, long type, int format) const;
virtual void deleteProperty(long atom) const;

View File

@ -27,10 +27,11 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
namespace KWin {
struct AnimationEffectPrivate {
public:
AnimationEffectPrivate() { m_animated = false; }
AnimationEffectPrivate() { m_animated = m_damageDirty = false; }
AnimationEffect::AniMap m_animations;
EffectWindowList m_zombies;
bool m_animated;
bool m_animated, m_damageDirty;
QRegion m_damageArea;
};
}
@ -160,8 +161,11 @@ void AnimationEffect::animate( EffectWindow *w, Attribute a, uint meta, int ms,
it = d->m_animations.insert(w, QList<AniData>());
it->append(AniData(a, meta, ms, to, curve, delay, from, waitAtSource));
if (delay > 0)
if (delay > 0) {
QTimer::singleShot(delay, this, SLOT(triggerRepaint()));
if (waitAtSource)
effects->addRepaintFull();
}
else
triggerRepaint();
}
@ -174,11 +178,12 @@ void AnimationEffect::prePaintScreen( ScreenPrePaintData& data, int time )
return;
}
AniMap::iterator entry = d->m_animations.begin();
AniMap::iterator entry = d->m_animations.begin(), mapEnd = d->m_animations.end();
d->m_animated = false;
while (entry != d->m_animations.end()) {
QList<AniData>::iterator anim = entry->begin();
while (anim != entry->end()) {
short int transformed = 0;
while (entry != mapEnd) {
QList<AniData>::iterator anim = entry->begin(), animEnd = entry->end();
while (anim != animEnd) {
if (QTime::currentTime() < anim->startTime) {
if (!anim->waitAtSource) {
++anim;
@ -188,12 +193,16 @@ void AnimationEffect::prePaintScreen( ScreenPrePaintData& data, int time )
anim->addTime(time);
if (anim->time < anim->duration) {
if (anim->attribute != Brightness && anim->attribute != Saturation && anim->attribute != Opacity)
transformed = true;
d->m_animated = true;
++anim;
}
else {
animationEnded(entry.key(), anim->attribute);
anim = entry->erase(anim);
d->m_damageDirty = true;
animEnd = entry->end();
}
}
if (entry->isEmpty()) {
@ -202,14 +211,18 @@ void AnimationEffect::prePaintScreen( ScreenPrePaintData& data, int time )
d->m_zombies.removeAt( i );
entry.key()->unrefWindow();
}
d->m_damageDirty = true;
entry = d->m_animations.erase(entry);
mapEnd = d->m_animations.end();
}
else
++entry;
}
if ( d->m_animated )
data.mask |= PAINT_SCREEN_WITH_TRANSFORMED_WINDOWS;
// NOTICE PAINT_SCREEN_WITH_TRANSFORMED_WINDOWS_WITHOUT_FULL_REPAINTS and thus now no flag should be required
// ... unless we start to get glitches ;-)
// if ( transformed )
// data.mask |= PAINT_SCREEN_WITH_TRANSFORMED_WINDOWS_WITHOUT_FULL_REPAINTS; //PAINT_SCREEN_WITH_TRANSFORMED_WINDOWS;
// janitorial...
if ( !(d->m_animations.count() || d->m_zombies.isEmpty()) )
@ -236,7 +249,7 @@ void AnimationEffect::prePaintWindow( EffectWindow* w, WindowPrePaintData& data,
isUsed = true;
if (anim->attribute == Opacity)
data.setTranslucent();
else {
else if (!(anim->attribute == Brightness || anim->attribute == Saturation)) {
data.setTransformed();
data.mask |= PAINT_WINDOW_TRANSFORMED;
}
@ -395,8 +408,11 @@ void AnimationEffect::paintWindow( EffectWindow* w, int mask, QRegion region, Wi
void AnimationEffect::postPaintScreen()
{
Q_D(AnimationEffect);
if ( d->m_animated )
effects->addRepaintFull();
if ( d->m_animated ) {
if (d->m_damageDirty)
updateDamageAreas();
effects->addRepaint(d->m_damageArea);
}
effects->postPaintScreen();
}
@ -478,10 +494,126 @@ void AnimationEffect::setMetaData( MetaType type, uint value, uint &meta )
void AnimationEffect::triggerRepaint()
{
Q_D(AnimationEffect);
if (!d->m_animated)
effects->addRepaintFull();
updateDamageAreas();
effects->addRepaint( d->m_damageArea );
}
static float fixOvershoot(float f, const AniData &d, short int dir, float s = 1.1)
{
switch(d.curve.type()) {
case QEasingCurve::InOutElastic:
case QEasingCurve::InOutBack:
return f * s;
case QEasingCurve::InElastic:
case QEasingCurve::OutInElastic:
case QEasingCurve::OutBack:
return (dir&2) ? f * s : f;
case QEasingCurve::OutElastic:
case QEasingCurve::InBack:
return (dir&1) ? f * s : f;
default:
return f;
}
}
void AnimationEffect::updateDamageAreas()
{
Q_D(AnimationEffect);
d->m_damageArea = QRegion();
for (AniMap::const_iterator entry = d->m_animations.constBegin(), mapEnd = d->m_animations.constEnd(); entry != mapEnd; ++entry) {
float f[2] = {1.0, 1.0};
float t[2] = {0.0, 0.0};
bool createRegion = false;
QList<QRect> rects;
for (QList<AniData>::const_iterator anim = entry->constBegin(), animEnd = entry->constEnd(); anim != animEnd; ++anim) {
if (QTime::currentTime() < anim->startTime)
continue;
switch (anim->attribute) {
case Opacity:
case Brightness:
case Saturation:
createRegion = true;
break;
case Rotation:
case Generic:
d->m_damageArea = QRegion(0, 0, displayWidth(), displayHeight());
return; // sic! no need to do anything else
case Translation:
case Position: {
createRegion = true;
QRect r(entry.key()->geometry());
int x[2] = {0,0};
int y[2] = {0,0};
if (anim->attribute == Translation) {
x[0] = anim->from[0];
x[1] = anim->to[0];
y[0] = anim->from[1];
y[1] = anim->to[1];
} else {
if ( anim->from[0] >= 0.0 && anim->to[0] >= 0.0 ) {
x[0] = anim->from[0] - xCoord(r, metaData(SourceAnchor, anim->meta));
x[1] = anim->to[0] - xCoord(r, metaData(TargetAnchor, anim->meta));
}
if ( anim->from[1] >= 0.0 && anim->to[1] >= 0.0 ) {
y[0] = anim->from[1] - yCoord(r, metaData(SourceAnchor, anim->meta));
y[1] = anim->to[1] - yCoord(r, metaData(TargetAnchor, anim->meta));
}
}
r = entry.key()->decorationRect().translated(r.topLeft());
rects << r.translated(x[0], y[0]) << r.translated(x[1], y[1]);
break;
}
case Size:
case Scale: {
createRegion = true;
const QSize sz = entry.key()->geometry().size();
float fx = qMax(fixOvershoot(anim->from[0], *anim, 1), fixOvershoot(anim->to[0], *anim, 2));
// float fx = qMax(interpolated(*anim,0), anim->to[0]);
if (fx >= 0.0) {
if (anim->attribute == Size)
fx /= sz.width();
f[0] *= fx;
t[0] += geometryCompensation( anim->meta & AnimationEffect::Horizontal, fx ) * sz.width();
}
// float fy = qMax(interpolated(*anim,1), anim->to[1]);
float fy = qMax(fixOvershoot(anim->from[1], *anim, 1), fixOvershoot(anim->to[1], *anim, 2));
if (fy >= 0.0) {
if (anim->attribute == Size)
fy /= sz.height();
if (!anim->isOneDimensional()) {
f[1] *= fy;
t[1] += geometryCompensation( anim->meta & AnimationEffect::Vertical, fy ) * sz.height();
} else if ( ((anim->meta & AnimationEffect::Vertical)>>1) != (anim->meta & AnimationEffect::Horizontal) ) {
f[1] *= fx;
t[1] += geometryCompensation( anim->meta & AnimationEffect::Vertical, fx ) * sz.height();
}
}
break;
}
}
}
if (createRegion) {
const QRect geo = entry.key()->decorationRect().translated(entry.key()->geometry().topLeft());
if (rects.isEmpty())
rects << geo;
QList<QRect>::const_iterator r, rEnd = rects.constEnd();
for ( r = rects.constBegin(); r != rEnd; ++r) { // transform
const_cast<QRect*>(&(*r))->setSize(QSize(qRound(r->width()*f[0]), qRound(r->height()*f[1])));
const_cast<QRect*>(&(*r))->translate(t[0], t[1]); // "const_cast" - don't do that at home, kids ;-)
}
QRect rect = rects.at(0);
if (rects.count() > 1) {
for ( r = rects.constBegin() + 1; r != rEnd; ++r) // unite
rect |= *r;
const int dx = 110*(rect.width() - geo.width())/100 + 1 - rect.width() + geo.width();
const int dy = 110*(rect.height() - geo.height())/100 + 1 - rect.height() + geo.height();
rect.adjust(-dx,-dy,dx,dy); // fix pot. overshoot
}
d->m_damageArea |= rect;
}
}
d->m_damageDirty = false;
}
void AnimationEffect::_windowClosed( EffectWindow* w )
{
@ -495,6 +627,7 @@ void AnimationEffect::_windowClosed( EffectWindow* w )
void AnimationEffect::_windowDeleted( EffectWindow* w )
{
Q_D(AnimationEffect);
d->m_zombies.removeAll( w ); // TODO this line is a workaround for a bug in KWin 4.8.0, remove for 4.8.1
d->m_animations.remove( w );
}

View File

@ -164,6 +164,7 @@ protected:
private:
float interpolated( const AniData&, int i = 0 ) const;
float progress( const AniData& ) const;
void updateDamageAreas();
private Q_SLOTS:
void init();
void triggerRepaint();

View File

@ -167,7 +167,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 182
#define KWIN_EFFECT_API_VERSION_MINOR 183
#define KWIN_EFFECT_API_VERSION KWIN_EFFECT_API_MAKE_VERSION( \
KWIN_EFFECT_API_VERSION_MAJOR, KWIN_EFFECT_API_VERSION_MINOR )
@ -1140,6 +1140,12 @@ public:
* @since 4.5
*/
virtual QRect decorationInnerRect() const = 0;
/**
* Geometry of the window including decoration & pot. shadows
* May be different from geometry() if the window has a shadow
* @since 4.5
*/
virtual QRect decorationRect() const = 0;
bool hasDecoration() const;
virtual QByteArray readProperty(long atom, long type, int format) const = 0;
virtual void deleteProperty(long atom) const = 0;