From b3f71b5986bc580ab2092c33e9b2805e1d603313 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20L=C3=BCbking?= Date: Fri, 4 Jan 2013 00:00:39 +0100 Subject: [PATCH 1/2] protect list iterators against ext. manipulation REVIEW: 108151 --- libkwineffects/kwinanimationeffect.cpp | 28 +++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/libkwineffects/kwinanimationeffect.cpp b/libkwineffects/kwinanimationeffect.cpp index e0a66941b1..5ed4308cba 100644 --- a/libkwineffects/kwinanimationeffect.cpp +++ b/libkwineffects/kwinanimationeffect.cpp @@ -30,10 +30,10 @@ QElapsedTimer AnimationEffect::s_clock; struct AnimationEffectPrivate { public: - AnimationEffectPrivate() { m_animated = m_damageDirty = false; } + AnimationEffectPrivate() { m_animated = m_damageDirty = m_animationsTouched = false; } AnimationEffect::AniMap m_animations; EffectWindowList m_zombies; - bool m_animated, m_damageDirty, m_needSceneRepaint; + bool m_animated, m_damageDirty, m_needSceneRepaint, m_animationsTouched; }; } @@ -182,6 +182,8 @@ void AnimationEffect::animate( EffectWindow *w, Attribute a, uint meta, int ms, it->first.append(AniData(a, meta, ms, to, curve, delay, from, waitAtSource)); it->second = QRect(); + d->m_animationsTouched = true; + if (delay > 0) { QTimer::singleShot(delay, this, SLOT(triggerRepaint())); if (waitAtSource) @@ -200,16 +202,19 @@ void AnimationEffect::prePaintScreen( ScreenPrePaintData& data, int time ) return; } + d->m_animationsTouched = false; AniMap::iterator entry = d->m_animations.begin(), mapEnd = d->m_animations.end(); d->m_animated = false; // short int transformed = 0; while (entry != mapEnd) { bool invalidateLayerRect = false; QList::iterator anim = entry->first.begin(), animEnd = entry->first.end(); + int animCounter = 0; while (anim != animEnd) { if (anim->startTime > clock()) { if (!anim->waitAtSource) { ++anim; + ++animCounter; continue; } } else { @@ -221,8 +226,25 @@ void AnimationEffect::prePaintScreen( ScreenPrePaintData& data, int time ) // transformed = true; d->m_animated = true; ++anim; + ++animCounter; } else { - animationEnded(entry.key(), anim->attribute, anim->meta); + EffectWindow *oldW = entry.key(); + AniData *aData = &(*anim); + animationEnded(oldW, anim->attribute, anim->meta); + // NOTICE animationEnded is an external call and might have called "::animate" + // as a result our iterators could now point random junk on the heap + // so we've to restore the former states, ie. find our window list and animation + if (d->m_animationsTouched) { + d->m_animationsTouched = false; + entry = d->m_animations.begin(), mapEnd = d->m_animations.end(); + while (entry.key() != oldW && entry != mapEnd) + ++entry; + Q_ASSERT(entry != mapEnd); // usercode should not delete animations from animationEnded (not even possible atm.) + anim = entry->first.begin(), animEnd = entry->first.end(); + Q_ASSERT(animCounter < entry->first.count()); + for (int i = 0; i < animCounter; ++i) + ++anim; + } anim = entry->first.erase(anim); invalidateLayerRect = d->m_damageDirty = true; animEnd = entry->first.end(); From a402c7b80163bb633aa9b991e9eb545535860008 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20L=C3=BCbking?= Date: Mon, 7 Jan 2013 19:50:47 +0100 Subject: [PATCH 2/2] don't use input windows on Qt < 4.8.3 According to aacid, it's been broken in every Qt version before BUG: 312784 REVIEW: 108249 --- client.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/client.cpp b/client.cpp index 43296b3a06..0e9c10d0ce 100644 --- a/client.cpp +++ b/client.cpp @@ -353,8 +353,22 @@ void Client::destroyClient() deleteClient(this, Allowed); } +// DnD handling for input shaping is broken in the clients for all Qt versions before 4.8.3 +// NOTICE do not query the Qt version macro, this is a runtime problem! +// TODO KDE5 remove this +static inline bool qtBefore483() +{ + QStringList l = QString(qVersion()).split("."); + // "4.x.y" + return l.at(1).toUInt() < 5 && l.at(1).toUInt() < 9 && l.at(2).toUInt() < 3; +} + void Client::updateInputWindow() { + static bool brokenQtInputHandling = qtBefore483(); + if (brokenQtInputHandling) + return; + QRegion region; if (!noBorder()) {