diff --git a/effects/CMakeLists.txt b/effects/CMakeLists.txt
index b12ca6c988..0c4bf08872 100644
--- a/effects/CMakeLists.txt
+++ b/effects/CMakeLists.txt
@@ -71,6 +71,7 @@ include( showfps/CMakeLists.txt )
include( showpaint/CMakeLists.txt )
include( slide/CMakeLists.txt )
include( slideback/CMakeLists.txt )
+include( slidingpopups/CMakeLists.txt )
include( taskbarthumbnail/CMakeLists.txt )
include( thumbnailaside/CMakeLists.txt )
include( zoom/CMakeLists.txt )
diff --git a/effects/slidingpopups/CMakeLists.txt b/effects/slidingpopups/CMakeLists.txt
new file mode 100644
index 0000000000..fec1a1b14b
--- /dev/null
+++ b/effects/slidingpopups/CMakeLists.txt
@@ -0,0 +1,12 @@
+#######################################
+# Effect
+
+# Source files
+set( kwin4_effect_builtins_sources ${kwin4_effect_builtins_sources}
+ slidingpopups/slidingpopups.cpp
+ )
+
+# .desktop files
+install( FILES
+ slidingpopups/slidingpopups.desktop
+ DESTINATION ${SERVICES_INSTALL_DIR}/kwin )
diff --git a/effects/slidingpopups/slidingpopups.cpp b/effects/slidingpopups/slidingpopups.cpp
new file mode 100644
index 0000000000..41276c7878
--- /dev/null
+++ b/effects/slidingpopups/slidingpopups.cpp
@@ -0,0 +1,179 @@
+/********************************************************************
+ KWin - the KDE window manager
+ This file is part of the KDE project.
+
+Copyright (C) 2009 Marco Martin notmart@gmail.com
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see .
+*********************************************************************/
+
+#include "slidingpopups.h"
+
+#include
+
+namespace KWin
+{
+
+KWIN_EFFECT( slidingpopups, SlidingPopupsEffect )
+
+SlidingPopupsEffect::SlidingPopupsEffect()
+ {
+ mAtom = XInternAtom( display(), "_KDE_SLIDE", False );
+ effects->registerPropertyType( mAtom, true );
+ // TODO hackish way to announce support, make better after 4.0
+ unsigned char dummy = 0;
+ XChangeProperty( display(), rootWindow(), mAtom, mAtom, 8, PropModeReplace, &dummy, 1 );
+ }
+
+SlidingPopupsEffect::~SlidingPopupsEffect()
+ {
+ XDeleteProperty( display(), rootWindow(), mAtom );
+ effects->registerPropertyType( mAtom, false );
+ }
+
+void SlidingPopupsEffect::prePaintScreen( ScreenPrePaintData& data, int time )
+ {
+ if( !mAppearingWindows.isEmpty() || !mDisappearingWindows.isEmpty() )
+ data.mask |= PAINT_SCREEN_WITH_TRANSFORMED_WINDOWS;
+ effects->prePaintScreen( data, time );
+ }
+
+void SlidingPopupsEffect::prePaintWindow( EffectWindow* w, WindowPrePaintData& data, int time )
+ {
+ if( mAppearingWindows.contains( w ) )
+ {
+ mAppearingWindows[ w ].addTime( time );
+ if( mAppearingWindows[ w ].value() < 1 )
+ data.setTransformed();
+ else
+ mAppearingWindows.remove( w );
+ }
+ else if( mDisappearingWindows.contains( w ) )
+ {
+ mDisappearingWindows[ w ].addTime( time );
+ if( mDisappearingWindows[ w ].value() < 1 )
+ data.setTransformed();
+ else
+ {
+ mDisappearingWindows.remove( w );
+ w->unrefWindow();
+ }
+ }
+ effects->prePaintWindow( w, data, time );
+ }
+
+void SlidingPopupsEffect::paintWindow( EffectWindow* w, int mask, QRegion region, WindowPaintData& data )
+ {
+ bool animating = false;
+ bool appearing = false;
+ QRegion clippedRegion = region;
+
+ if( mAppearingWindows.contains( w ) )
+ {
+ appearing = true;
+ animating = true;
+ }
+ else if( mDisappearingWindows.contains( w ) )
+ {
+ appearing = false;
+ animating = true;
+ }
+
+
+ if( animating )
+ {
+ const qreal progress = appearing?(1 - mAppearingWindows[ w ].value()):mDisappearingWindows[ w ].value();
+ const int start = mWindowsData[ w ].start;
+
+ switch (mWindowsData[ w ].from)
+ {
+ case West:
+ data.xTranslate += (start - w->width()) * progress;
+ clippedRegion = clippedRegion.subtracted(QRegion(start - w->width(), w->y(), w->width(), w->height()));
+ break;
+ case North:
+ data.yTranslate += (start - w->height()) * progress;
+ clippedRegion = clippedRegion.subtracted(QRegion(w->x(), start - w->height(), w->width(), w->height()));
+ break;
+ case East:
+ data.xTranslate += (start - w->x()) * progress;
+ clippedRegion = clippedRegion.subtracted(QRegion(w->x()+w->width(), w->y(), w->width(), w->height()));
+ break;
+ case South:
+ default:
+ data.yTranslate += (start - w->y()) * progress;
+ clippedRegion = clippedRegion.subtracted(QRegion(w->x(), start, w->width(), w->height()));
+ }
+ }
+
+ effects->paintWindow( w, mask, clippedRegion, data );
+ }
+
+void SlidingPopupsEffect::postPaintWindow( EffectWindow* w )
+ {
+ if( mAppearingWindows.contains( w ) || mDisappearingWindows.contains( w ) )
+ w->addRepaintFull(); // trigger next animation repaint
+ effects->postPaintWindow( w );
+ }
+
+void SlidingPopupsEffect::windowAdded( EffectWindow* w )
+ {
+ propertyNotify( w, mAtom );
+ if( w->isOnCurrentDesktop() && mWindowsData.contains( w ) )
+ {
+ mAppearingWindows[ w ].setDuration( animationTime( 250 ));
+ mAppearingWindows[ w ].setProgress( 0.0 );
+ mAppearingWindows[ w ].setCurveShape( TimeLine::EaseOutCurve );
+
+ w->addRepaintFull();
+ }
+ }
+
+void SlidingPopupsEffect::windowClosed( EffectWindow* w )
+ {
+ propertyNotify( w, mAtom );
+ if( w->isOnCurrentDesktop() && !w->isMinimized() && mWindowsData.contains( w ) )
+ {
+ w->refWindow();
+ mAppearingWindows.remove( w );
+ mDisappearingWindows[ w ].setDuration( animationTime( 250 ));
+ mDisappearingWindows[ w ].setProgress( 0.0 );
+ mDisappearingWindows[ w ].setCurveShape( TimeLine::EaseOutCurve );
+
+ w->addRepaintFull();
+ }
+ }
+
+void SlidingPopupsEffect::windowDeleted( EffectWindow* w )
+ {
+ mAppearingWindows.remove( w );
+ mDisappearingWindows.remove( w );
+ mWindowsData.remove( w );
+ }
+
+void SlidingPopupsEffect::propertyNotify( EffectWindow* w, long a )
+ {
+ if( a != mAtom )
+ return;
+
+ QByteArray data = w->readProperty( mAtom, mAtom, 32 );
+ if( data.length() < 1 )
+ return;
+ long* d = reinterpret_cast< long* >( data.data());
+ Data animData;
+ animData.start = d[ 0 ];
+ animData.from = (Position)d[ 1 ];
+ mWindowsData[ w ] = animData;
+ }
+} // namespace
diff --git a/effects/slidingpopups/slidingpopups.desktop b/effects/slidingpopups/slidingpopups.desktop
new file mode 100644
index 0000000000..06620050e7
--- /dev/null
+++ b/effects/slidingpopups/slidingpopups.desktop
@@ -0,0 +1,18 @@
+[Desktop Entry]
+Name=Sliding popups
+
+Type=Service
+Comment=Sliding animation for Plasma popups
+
+Icon=preferences-system-windows-effect-slidingpopups
+X-KDE-ServiceTypes=KWin/Effect
+X-KDE-PluginInfo-Author=Marco Martin
+X-KDE-PluginInfo-Email=notmart@gmail.com
+X-KDE-PluginInfo-Name=kwin4_effect_slidingpopups
+X-KDE-PluginInfo-Version=0.1
+X-KDE-PluginInfo-Category=Appearance
+X-KDE-PluginInfo-Depends=
+X-KDE-PluginInfo-License=GPL
+X-KDE-PluginInfo-EnabledByDefault=true
+X-KDE-Library=kwin4_effect_builtins
+X-KDE-Ordering=50
diff --git a/effects/slidingpopups/slidingpopups.h b/effects/slidingpopups/slidingpopups.h
new file mode 100644
index 0000000000..d75cc3e650
--- /dev/null
+++ b/effects/slidingpopups/slidingpopups.h
@@ -0,0 +1,67 @@
+/********************************************************************
+ KWin - the KDE window manager
+ This file is part of the KDE project.
+
+Copyright (C) 2009 Marco Martin notmart@gmail.com
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see .
+*********************************************************************/
+
+#ifndef KWIN_SLIDEBACK_H
+#define KWIN_SLIDEBACK_H
+
+// Include with base class for effects.
+#include
+
+namespace KWin
+{
+
+class SlidingPopupsEffect
+ : public Effect
+ {
+ public:
+ SlidingPopupsEffect();
+ ~SlidingPopupsEffect();
+ 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 postPaintWindow( EffectWindow* w );
+ // TODO react also on virtual desktop changes
+ virtual void windowAdded( EffectWindow* c );
+ virtual void windowClosed( EffectWindow* c );
+ virtual void windowDeleted( EffectWindow* c );
+ virtual void propertyNotify( EffectWindow* w, long a );
+ private:
+ enum Position
+ {
+ West = 0,
+ North = 1,
+ East = 2,
+ South = 3
+ };
+ struct Data
+ {
+ int start; //point in screen coordinates where the window starts
+ //to animate, from decides if this point is an x or an y
+ Position from;
+ };
+ long mAtom;
+ QHash< const EffectWindow*, TimeLine > mAppearingWindows;
+ QHash< const EffectWindow*, TimeLine > mDisappearingWindows;
+ QHash< const EffectWindow*, Data > mWindowsData;
+ };
+
+} // namespace
+
+#endif