parent
239d5757f2
commit
39fb788103
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue