Blob Blame History Raw
diff --git a/kwin/composite.cpp b/kwin/composite.cpp
index ea540a4..e179b8b 100644
--- a/kwin/composite.cpp
+++ b/kwin/composite.cpp
@@ -389,7 +389,7 @@ void Compositor::slotReinitialize()
 
     // Update any settings that can be set in the compositing kcm.
 #ifdef KWIN_BUILD_SCREENEDGES
-    Workspace::self()->screenEdge()->update();
+    Workspace::self()->screenEdge()->recreateEdges();
 #endif
     // Restart compositing
     finish();
diff --git a/kwin/desktoplayout.cpp b/kwin/desktoplayout.cpp
index f275782..5470eab 100644
--- a/kwin/desktoplayout.cpp
+++ b/kwin/desktoplayout.cpp
@@ -53,6 +53,7 @@ void Workspace::updateDesktopLayout()
         m_screenEdge.reserveDesktopSwitching(true, m_screenEdgeOrientation);
     }
 #endif
+
 }
 
 void Workspace::setNETDesktopLayout(Qt::Orientation orientation, int width, int height,
diff --git a/kwin/effects.cpp b/kwin/effects.cpp
index 112c814..8e87f10 100644
--- a/kwin/effects.cpp
+++ b/kwin/effects.cpp
@@ -1108,28 +1108,30 @@ QPoint EffectsHandlerImpl::cursorPos() const
 void EffectsHandlerImpl::checkElectricBorder(const QPoint &pos, Time time)
 {
 #ifdef KWIN_BUILD_SCREENEDGES
-    Workspace::self()->screenEdge()->check(pos, time);
+    Workspace::self()->screenEdge()->check(pos, QDateTime::fromMSecsSinceEpoch(time));
 #else
     Q_UNUSED(pos)
     Q_UNUSED(time)
 #endif
 }
 
-void EffectsHandlerImpl::reserveElectricBorder(ElectricBorder border)
+void EffectsHandlerImpl::reserveElectricBorder(ElectricBorder border, Effect *effect)
 {
 #ifdef KWIN_BUILD_SCREENEDGES
-    Workspace::self()->screenEdge()->reserve(border);
+    Workspace::self()->screenEdge()->reserve(border, effect, "borderActivated");
 #else
     Q_UNUSED(border)
+    Q_UNUSED(effect)
 #endif
 }
 
-void EffectsHandlerImpl::unreserveElectricBorder(ElectricBorder border)
+void EffectsHandlerImpl::unreserveElectricBorder(ElectricBorder border, Effect *effect)
 {
 #ifdef KWIN_BUILD_SCREENEDGES
-    Workspace::self()->screenEdge()->unreserve(border);
+    Workspace::self()->screenEdge()->unreserve(border, effect);
 #else
     Q_UNUSED(border)
+    Q_UNUSED(effect)
 #endif
 }
 
diff --git a/kwin/effects.h b/kwin/effects.h
index d985de4..2a56cdd 100644
--- a/kwin/effects.h
+++ b/kwin/effects.h
@@ -140,8 +140,8 @@ public:
     virtual void checkInputWindowStacking();
 
     virtual void checkElectricBorder(const QPoint &pos, Time time);
-    virtual void reserveElectricBorder(ElectricBorder border);
-    virtual void unreserveElectricBorder(ElectricBorder border);
+    virtual void reserveElectricBorder(ElectricBorder border, Effect *effect);
+    virtual void unreserveElectricBorder(ElectricBorder border, Effect *effect);
     virtual void reserveElectricBorderSwitching(bool reserve, Qt::Orientations o);
 
     virtual unsigned long xrenderBufferPicture();
diff --git a/kwin/effects/cube/cube.cpp b/kwin/effects/cube/cube.cpp
index 3fffbd0..840bcf0 100644
--- a/kwin/effects/cube/cube.cpp
+++ b/kwin/effects/cube/cube.cpp
@@ -122,13 +122,13 @@ void CubeEffect::reconfigure(ReconfigureFlags)
 {
     CubeConfig::self()->readConfig();
     foreach (ElectricBorder border, borderActivate) {
-        effects->unreserveElectricBorder(border);
+        effects->unreserveElectricBorder(border, this);
     }
     foreach (ElectricBorder border, borderActivateCylinder) {
-        effects->unreserveElectricBorder(border);
+        effects->unreserveElectricBorder(border, this);
     }
     foreach (ElectricBorder border, borderActivateSphere) {
-        effects->unreserveElectricBorder(border);
+        effects->unreserveElectricBorder(border, this);
     }
     borderActivate.clear();
     borderActivateCylinder.clear();
@@ -138,21 +138,21 @@ void CubeEffect::reconfigure(ReconfigureFlags)
     borderList = CubeConfig::borderActivate();
     foreach (int i, borderList) {
         borderActivate.append(ElectricBorder(i));
-        effects->reserveElectricBorder(ElectricBorder(i));
+        effects->reserveElectricBorder(ElectricBorder(i), this);
     }
     borderList.clear();
     borderList.append(int(ElectricNone));
     borderList = CubeConfig::borderActivateCylinder();
     foreach (int i, borderList) {
         borderActivateCylinder.append(ElectricBorder(i));
-        effects->reserveElectricBorder(ElectricBorder(i));
+        effects->reserveElectricBorder(ElectricBorder(i), this);
     }
     borderList.clear();
     borderList.append(int(ElectricNone));
     borderList = CubeConfig::borderActivateSphere();
     foreach (int i, borderList) {
         borderActivateSphere.append(ElectricBorder(i));
-        effects->reserveElectricBorder(ElectricBorder(i));
+        effects->reserveElectricBorder(ElectricBorder(i), this);
     }
 
     cubeOpacity = (float)CubeConfig::opacity() / 100.0f;
@@ -218,13 +218,13 @@ void CubeEffect::reconfigure(ReconfigureFlags)
 CubeEffect::~CubeEffect()
 {
     foreach (ElectricBorder border, borderActivate) {
-        effects->unreserveElectricBorder(border);
+        effects->unreserveElectricBorder(border, this);
     }
     foreach (ElectricBorder border, borderActivateCylinder) {
-        effects->unreserveElectricBorder(border);
+        effects->unreserveElectricBorder(border, this);
     }
     foreach (ElectricBorder border, borderActivateSphere) {
-        effects->unreserveElectricBorder(border);
+        effects->unreserveElectricBorder(border, this);
     }
     delete wallpaper;
     delete capTexture;
diff --git a/kwin/effects/desktopgrid/desktopgrid.cpp b/kwin/effects/desktopgrid/desktopgrid.cpp
index 61c814e..826ec9b 100644
--- a/kwin/effects/desktopgrid/desktopgrid.cpp
+++ b/kwin/effects/desktopgrid/desktopgrid.cpp
@@ -90,7 +90,7 @@ DesktopGridEffect::DesktopGridEffect()
 DesktopGridEffect::~DesktopGridEffect()
 {
     foreach (ElectricBorder border, borderActivate) {
-        effects->unreserveElectricBorder(border);
+        effects->unreserveElectricBorder(border, this);
     }
     QHash< DesktopButtonsView*, EffectWindow* >::iterator i = m_desktopButtonsViews.begin();
     while (i != m_desktopButtonsViews.end()) {
@@ -105,12 +105,12 @@ void DesktopGridEffect::reconfigure(ReconfigureFlags)
     DesktopGridConfig::self()->readConfig();
 
     foreach (ElectricBorder border, borderActivate) {
-        effects->unreserveElectricBorder(border);
+        effects->unreserveElectricBorder(border, this);
     }
     borderActivate.clear();
     foreach (int i, DesktopGridConfig::borderActivate()) {
         borderActivate.append(ElectricBorder(i));
-        effects->reserveElectricBorder(ElectricBorder(i));
+        effects->reserveElectricBorder(ElectricBorder(i), this);
     }
 
     // TODO: rename zoomDuration to duration
diff --git a/kwin/effects/flipswitch/flipswitch.cpp b/kwin/effects/flipswitch/flipswitch.cpp
index 445405e..bb92216 100644
--- a/kwin/effects/flipswitch/flipswitch.cpp
+++ b/kwin/effects/flipswitch/flipswitch.cpp
@@ -80,10 +80,10 @@ FlipSwitchEffect::FlipSwitchEffect()
 FlipSwitchEffect::~FlipSwitchEffect()
 {
     foreach (ElectricBorder border, m_borderActivate) {
-        effects->unreserveElectricBorder(border);
+        effects->unreserveElectricBorder(border, this);
     }
     foreach (ElectricBorder border, m_borderActivateAll) {
-        effects->unreserveElectricBorder(border);
+        effects->unreserveElectricBorder(border, this);
     }
     delete m_captionFrame;
 }
@@ -97,20 +97,20 @@ void FlipSwitchEffect::reconfigure(ReconfigureFlags)
 {
     FlipSwitchConfig::self()->readConfig();
     foreach (ElectricBorder border, m_borderActivate) {
-        effects->unreserveElectricBorder(border);
+        effects->unreserveElectricBorder(border, this);
     }
     foreach (ElectricBorder border, m_borderActivateAll) {
-        effects->unreserveElectricBorder(border);
+        effects->unreserveElectricBorder(border, this);
     }
     m_borderActivate.clear();
     m_borderActivateAll.clear();
     foreach (int i, FlipSwitchConfig::borderActivate()) {
         m_borderActivate.append(ElectricBorder(i));
-        effects->reserveElectricBorder(ElectricBorder(i));
+        effects->reserveElectricBorder(ElectricBorder(i), this);
     }
     foreach (int i, FlipSwitchConfig::borderActivateAll()) {
         m_borderActivateAll.append(ElectricBorder(i));
-        effects->reserveElectricBorder(ElectricBorder(i));
+        effects->reserveElectricBorder(ElectricBorder(i), this);
     }
     m_tabbox = FlipSwitchConfig::tabBox();
     m_tabboxAlternative = FlipSwitchConfig::tabBoxAlternative();
diff --git a/kwin/effects/presentwindows/presentwindows.cpp b/kwin/effects/presentwindows/presentwindows.cpp
index 79baadb..59eacca 100755
--- a/kwin/effects/presentwindows/presentwindows.cpp
+++ b/kwin/effects/presentwindows/presentwindows.cpp
@@ -116,10 +116,10 @@ PresentWindowsEffect::~PresentWindowsEffect()
     XDeleteProperty(display(), rootWindow(), m_atomWindows);
     effects->registerPropertyType(m_atomWindows, false);
     foreach (ElectricBorder border, m_borderActivate) {
-        effects->unreserveElectricBorder(border);
+        effects->unreserveElectricBorder(border, this);
     }
     foreach (ElectricBorder border, m_borderActivateAll) {
-        effects->unreserveElectricBorder(border);
+        effects->unreserveElectricBorder(border, this);
     }
     delete m_filterFrame;
     delete m_closeView;
@@ -129,24 +129,24 @@ void PresentWindowsEffect::reconfigure(ReconfigureFlags)
 {
     PresentWindowsConfig::self()->readConfig();
     foreach (ElectricBorder border, m_borderActivate) {
-        effects->unreserveElectricBorder(border);
+        effects->unreserveElectricBorder(border, this);
     }
     foreach (ElectricBorder border, m_borderActivateAll) {
-        effects->unreserveElectricBorder(border);
+        effects->unreserveElectricBorder(border, this);
     }
     m_borderActivate.clear();
     m_borderActivateAll.clear();
     foreach (int i, PresentWindowsConfig::borderActivate()) {
         m_borderActivate.append(ElectricBorder(i));
-        effects->reserveElectricBorder(ElectricBorder(i));
+        effects->reserveElectricBorder(ElectricBorder(i), this);
     }
     foreach (int i, PresentWindowsConfig::borderActivateAll()) {
         m_borderActivateAll.append(ElectricBorder(i));
-        effects->reserveElectricBorder(ElectricBorder(i));
+        effects->reserveElectricBorder(ElectricBorder(i), this);
     }
     foreach (int i, PresentWindowsConfig::borderActivateClass()) {
         m_borderActivateClass.append(ElectricBorder(i));
-        effects->reserveElectricBorder(ElectricBorder(i));
+        effects->reserveElectricBorder(ElectricBorder(i), this);
     }
     m_layoutMode = PresentWindowsConfig::layoutMode();
     m_showCaptions = PresentWindowsConfig::drawWindowCaptions();
diff --git a/kwin/geometry.cpp b/kwin/geometry.cpp
index 5a0eae1..5344ffe 100644
--- a/kwin/geometry.cpp
+++ b/kwin/geometry.cpp
@@ -77,7 +77,7 @@ void Workspace::desktopResized()
     updateClientArea();
     saveOldScreenSizes(); // after updateClientArea(), so that one still uses the previous one
 #ifdef KWIN_BUILD_SCREENEDGES
-    m_screenEdge.update(true);
+    m_screenEdge.recreateEdges();
 #endif
     if (effects) {
         static_cast<EffectsHandlerImpl*>(effects)->desktopResized(geom.size());
@@ -2589,9 +2589,7 @@ bool Client::startMoveResize()
     Notify::raise(isResize() ? Notify::ResizeStart : Notify::MoveStart);
     emit clientStartUserMovedResized(this);
 #ifdef KWIN_BUILD_SCREENEDGES
-    if (options->electricBorders() == Options::ElectricMoveOnly ||
-            options->electricBorderMaximize() ||
-            options->electricBorderTiling())
+    if (workspace()->screenEdge()->isDesktopSwitchingMovingClients())
         workspace()->screenEdge()->reserveDesktopSwitching(true, Qt::Vertical|Qt::Horizontal);
 #endif
     if (fakeMove) // fix geom_restore position - it HAS to happen at the end, ie. when all moving is set up. inline call will lock focus!!
@@ -2599,37 +2597,6 @@ bool Client::startMoveResize()
     return true;
 }
 
-static ElectricBorder electricBorderFromMode(QuickTileMode mode)
-{
-    // special case, currently maxmizing is done from the electric top corner
-    if (mode == QuickTileMaximize)
-        return ElectricTop;
-
-    // sanitize the mode, ie. simplify "invalid" combinations
-    if ((mode & QuickTileHorizontal) == QuickTileHorizontal)
-        mode &= ~QuickTileHorizontal;
-    if ((mode & QuickTileVertical) == QuickTileVertical)
-        mode &= ~QuickTileVertical;
-
-    if (mode == QuickTileLeft)
-        return ElectricLeft;
-    if (mode == QuickTileRight)
-        return ElectricRight;
-    if (mode == (QuickTileTop|QuickTileLeft))
-        return ElectricTopLeft;
-    if (mode == (QuickTileTop|QuickTileRight))
-        return ElectricTopRight;
-    if (mode == (QuickTileBottom|QuickTileLeft))
-        return ElectricBottomLeft;
-    if (mode == (QuickTileBottom|QuickTileRight))
-        return ElectricBottomRight;
-    if (mode == QuickTileTop)
-        return ElectricTop;
-    if (mode == QuickTileBottom)
-        return ElectricBottom;
-    return ElectricNone;
-}
-
 void Client::finishMoveResize(bool cancel)
 {
     const bool wasResize = isResize(); // store across leaveMoveResize
@@ -2658,14 +2625,6 @@ void Client::finishMoveResize(bool cancel)
 
     if (isElectricBorderMaximizing()) {
         setQuickTileMode(electricMode);
-        const ElectricBorder border = electricBorderFromMode(electricMode);
-        if (border == ElectricNone)
-            kDebug(1212) << "invalid electric mode" << electricMode << "leading to invalid array access,\
-                                                                        this should not have happened!";
-#ifdef KWIN_BUILD_SCREENEDGES
-        else
-            workspace()->screenEdge()->restoreSize(border);
-#endif
         electricMaximizing = false;
         workspace()->outline()->hide();
     } else if (!cancel) {
@@ -2713,9 +2672,7 @@ void Client::leaveMoveResize()
     syncRequest.timeout = NULL;
 #endif
 #ifdef KWIN_BUILD_SCREENEDGES
-    if (options->electricBorders() == Options::ElectricMoveOnly ||
-            options->electricBorderMaximize() ||
-            options->electricBorderTiling())
+    if (workspace()->screenEdge()->isDesktopSwitchingMovingClients())
         workspace()->screenEdge()->reserveDesktopSwitching(false, Qt::Vertical|Qt::Horizontal);
 #endif
 }
@@ -3082,7 +3039,7 @@ void Client::handleMoveResize(int x, int y, int x_root, int y_root)
 
     if (isMove()) {
 #ifdef KWIN_BUILD_SCREENEDGES
-        workspace()->screenEdge()->check(globalPos, xTime());
+        workspace()->screenEdge()->check(globalPos, QDateTime::fromMSecsSinceEpoch(xTime()));
 #endif
     }
 }
diff --git a/kwin/libkwineffects/kwineffects.h b/kwin/libkwineffects/kwineffects.h
index f6bb636..731869f 100644
--- a/kwin/libkwineffects/kwineffects.h
+++ b/kwin/libkwineffects/kwineffects.h
@@ -438,8 +438,6 @@ public:
     virtual void windowInputMouseEvent(Window w, QEvent* e);
     virtual void grabbedKeyboardEvent(QKeyEvent* e);
 
-    virtual bool borderActivated(ElectricBorder border);
-
     /**
      * Overwrite this method to indicate whether your effect will be doing something in
      * the next frame to be rendered. If the method returns @c false the effect will be
@@ -496,6 +494,9 @@ public:
      **/
     static void setPositionTransformations(WindowPaintData& data, QRect& region, EffectWindow* w,
                                            const QRect& r, Qt::AspectRatioMode aspect);
+
+public Q_SLOTS:
+    virtual bool borderActivated(ElectricBorder border);
 };
 
 
@@ -653,8 +654,8 @@ public:
     virtual void stopMousePolling() = 0;
 
     virtual void checkElectricBorder(const QPoint &pos, Time time) = 0;
-    virtual void reserveElectricBorder(ElectricBorder border) = 0;
-    virtual void unreserveElectricBorder(ElectricBorder border) = 0;
+    virtual void reserveElectricBorder(ElectricBorder border, Effect *effect) = 0;
+    virtual void unreserveElectricBorder(ElectricBorder border, Effect *effect) = 0;
     virtual void reserveElectricBorderSwitching(bool reserve, Qt::Orientations o) = 0;
 
     // functions that allow controlling windows/desktop
diff --git a/kwin/screenedge.cpp b/kwin/screenedge.cpp
index 80a3931..cc114c2 100644
--- a/kwin/screenedge.cpp
+++ b/kwin/screenedge.cpp
@@ -41,14 +41,415 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 #include <QtCore/QVector>
 #include <QtCore/QTextStream>
 #include <QtDBus/QDBusInterface>
+#include <QtDBus/QDBusPendingCall>
+#include <QDesktopWidget>
 
 namespace KWin {
 
+  // Mouse should not move more than this many pixels
+static const int DISTANCE_RESET = 30;
+
+Edge::Edge(ScreenEdge *parent)
+    : QObject(parent)
+    , m_edges(parent)
+    , m_border(ElectricNone)
+    , m_action(ElectricActionNone)
+    , m_reserved(0)
+    , m_blocked(false)
+{
+}
+
+Edge::~Edge()
+{
+}
+
+void Edge::reserve()
+{
+    m_reserved++;
+    if (m_reserved == 1) {
+        activate();
+    }
+}
+
+void Edge::reserve(QObject *object, const char *slot)
+{
+    connect(object, SIGNAL(destroyed(QObject*)), SLOT(unreserve(QObject*)));
+    m_callBacks.insert(object, QByteArray(slot));
+    reserve();
+}
+
+void Edge::unreserve()
+{
+    m_reserved--;
+    if (m_reserved == 0) {
+        deactivate();
+    }
+}
+
+void Edge::unreserve(QObject *object)
+{
+    if (m_callBacks.contains(object)) {
+        m_callBacks.remove(object);
+        disconnect(object, SIGNAL(destroyed(QObject*)), this, SLOT(unreserve(QObject*)));
+        unreserve();
+    }
+}
+
+bool Edge::triggersFor(const QPoint &cursorPos) const
+{
+    if (isBlocked()) {
+        return false;
+    }
+    if (!m_geometry.contains(cursorPos)) {
+        return false;
+    }
+    if (isLeft() && cursorPos.x() != m_geometry.x()) {
+        return false;
+    }
+    if (isRight() && cursorPos.x() != (m_geometry.x() + m_geometry.width() -1)) {
+        return false;
+    }
+    if (isTop() && cursorPos.y() != m_geometry.y()) {
+        return false;
+    }
+    if (isBottom() && cursorPos.y() != (m_geometry.y() + m_geometry.height() -1)) {
+        return false;
+    }
+    return true;
+}
+
+void Edge::check(const QPoint &cursorPos, const QDateTime &triggerTime, bool forceNoPushback)
+{
+    if (!triggersFor(cursorPos)) {
+         return;
+    }
+    // no pushback so we have to activate at once
+    bool directActivate = forceNoPushback || edges()->cursorPushBackDistance().isNull();
+    if (directActivate || canActivate(cursorPos, triggerTime)) {
+        m_lastTrigger = triggerTime;
+        m_lastReset = QDateTime(); // invalidate
+        handle(cursorPos);
+    } else {
+        pushCursorBack(cursorPos);
+    }
+    m_triggeredPoint = cursorPos;
+}
+
+bool Edge::canActivate(const QPoint &cursorPos, const QDateTime &triggerTime)
+{
+    // we check whether either the timer has explicitly been invalidated (successfull trigger) or is
+    // bigger than the reactivation threshold (activation "aborted", usually due to moving away the cursor
+    // from the corner after successfull activation)
+    // either condition means that "this is the first event in a new attempt"
+    if (!m_lastReset.isValid() || m_lastReset.msecsTo(triggerTime) > edges()->reActivationThreshold()) {
+        m_lastReset = triggerTime;
+        return false;
+    }
+    if (m_lastTrigger.msecsTo(triggerTime) < edges()->reActivationThreshold()) {
+        return false;
+    }
+    if (m_lastReset.msecsTo(triggerTime) < edges()->timeThreshold()) {
+        return false;
+    }
+    // does the check on position make any sense at all?
+    if ((cursorPos - m_triggeredPoint).manhattanLength() > DISTANCE_RESET) {
+        return false;
+    }
+    return true;
+}
+
+void Edge::handle(const QPoint &cursorPos)
+{
+    if ((edges()->isDesktopSwitchingMovingClients() && Workspace::self()->getMovingClient()) ||
+        (edges()->isDesktopSwitching() && isScreenEdge())) {
+        // always switch desktop in case:
+        // moving a Client and option for switch on client move is enabled
+        // or switch on screen edge is enabled
+        switchDesktop(cursorPos);
+        return;
+    }
+    if (Workspace::self()->getMovingClient()) {
+        // if we are moving a window we don't want to trigger the actions. This just results in
+        // problems, e.g. Desktop Grid activated or screen locker activated which just cannot
+        // work as we hold a grab
+        return;
+    }
+    if (handleAction() || handleByCallback()) {
+        return;
+    }
+    if (edges()->isDesktopSwitching() && isCorner()) {
+        // try again desktop switching in the corder
+        switchDesktop(cursorPos);
+    }
+}
+
+bool Edge::handleAction()
+{
+    switch (m_action) {
+    case ElectricActionDashboard: { // Display Plasma dashboard
+        QDBusInterface plasmaApp("org.kde.plasma-desktop", "/App");
+        plasmaApp.asyncCall("toggleDashboard");
+        return true;
+    }
+    case ElectricActionShowDesktop: {
+        Workspace::self()->setShowingDesktop(!Workspace::self()->showingDesktop());
+        return true;
+    }
+    case ElectricActionLockScreen: { // Lock the screen
+        QDBusInterface screenSaver("org.kde.screensaver", "/ScreenSaver");
+        screenSaver.asyncCall("Lock");
+        return true;
+    }
+    default:
+        return false;
+    }
+}
+
+bool Edge::handleByCallback()
+{
+    if (m_callBacks.isEmpty()) {
+        return false;
+    }
+    for (QHash<QObject *, QByteArray>::iterator it = m_callBacks.begin();
+        it != m_callBacks.end();
+        ++it) {
+        bool retVal = false;
+        QMetaObject::invokeMethod(it.key(), it.value().constData(), Q_RETURN_ARG(bool, retVal), Q_ARG(ElectricBorder, m_border));
+        if (retVal) {
+            return true;
+        }
+    }
+    return false;
+}
+
+void Edge::switchDesktop(const QPoint& cursorPos)
+{
+    QPoint pos(cursorPos);
+    const uint oldDesktop = Workspace::self()->currentDesktop();
+    uint desktop = oldDesktop;
+    const int OFFSET = 2;
+    if (isLeft()) {
+        const uint interimDesktop = desktop;
+        desktop = Workspace::self()->desktopToLeft(desktop, options->isRollOverDesktops());
+        if (desktop != interimDesktop)
+            pos.setX(displayWidth() - 1 - OFFSET);
+    } else if (isRight()) {
+        const uint interimDesktop = desktop;
+        desktop = Workspace::self()->desktopToRight(desktop, options->isRollOverDesktops());
+        if (desktop != interimDesktop)
+            pos.setX(OFFSET);
+    }
+    if (isTop()) {
+        const uint interimDesktop = desktop;
+        desktop = Workspace::self()->desktopAbove(desktop, options->isRollOverDesktops());
+        if (desktop != interimDesktop)
+            pos.setY(displayHeight() - 1 - OFFSET);
+    } else if (isBottom()) {
+        const uint interimDesktop = desktop;
+        desktop = Workspace::self()->desktopBelow(desktop, options->isRollOverDesktops());
+        if (desktop != interimDesktop)
+            pos.setY(OFFSET);
+    }
+    if (Client *c = Workspace::self()->getMovingClient()) {
+        if (c->rules()->checkDesktop(desktop) != int(desktop)) {
+            // user attempts to move a client to another desktop where it is ruleforced to not be
+            return;
+        }
+    }
+    Workspace::self()->setCurrentDesktop(desktop);
+    if (desktop != oldDesktop) {
+        QCursor::setPos(pos);
+    }
+}
+
+void Edge::pushCursorBack(const QPoint& cursorPos)
+{
+    int x = cursorPos.x();
+    int y = cursorPos.y();
+    const QSize &distance = edges()->cursorPushBackDistance();
+    if (isLeft()) {
+        x += distance.width();
+    }
+    if (isRight()) {
+        x -= distance.width();
+    }
+    if (isTop()) {
+        y += distance.height();
+    }
+    if (isBottom()) {
+        y -= distance.height();
+    }
+    QCursor::setPos(x, y);
+}
+
+void Edge::setGeometry(const QRect &geometry)
+{
+    if (m_geometry == geometry) {
+        return;
+    }
+    m_geometry = geometry;
+    int x = m_geometry.x();
+    int y = m_geometry.y();
+    int width = m_geometry.width();
+    int height = m_geometry.height();
+    const int size = m_edges->cornerOffset();
+    if (isCorner()) {
+        if (isRight()) {
+            x = x - size +1;
+        }
+        if (isBottom()) {
+            y = y - size +1;
+        }
+        width = size;
+        height = size;
+    } else {
+        if (isLeft()) {
+            y += size + 1;
+            width = size;
+            height = height - size * 2;
+        } else if (isRight()) {
+            x = x - size + 1;
+            y += size;
+            width = size;
+            height = height - size * 2;
+        } else if (isTop()) {
+            x += size;
+            width = width - size * 2;
+            height = size;
+        } else if (isBottom()) {
+            x += size;
+            y = y - size +1;
+            width = width - size * 2;
+            height = size;
+        }
+    }
+    doGeometryUpdate();
+}
+
+void Edge::checkBlocking()
+{
+    if (isCorner()) {
+        return;
+    }
+    bool newValue = false;
+    if (Client *client = Workspace::self()->activeClient()) {
+        newValue = client->isFullScreen() && client->geometry().contains(m_geometry.center());
+    }
+    if (newValue == m_blocked) {
+        return;
+    }
+    m_blocked = newValue;
+    doUpdateBlocking();
+}
+
+void Edge::doUpdateBlocking()
+{
+}
+
+void Edge::doGeometryUpdate()
+{
+}
+
+void Edge::activate()
+{
+}
+
+void Edge::deactivate()
+{
+}
+
+/**********************************************************
+ * ScreenEdge
+ *********************************************************/
+
+WindowBasedEdge::WindowBasedEdge(ScreenEdge* parent)
+    : Edge(parent)
+    , m_window(None)
+{
+}
+
+WindowBasedEdge::~WindowBasedEdge()
+{
+}
+
+void WindowBasedEdge::activate()
+{
+    createWindow();
+    doUpdateBlocking();
+}
+
+void WindowBasedEdge::deactivate()
+{
+    if (m_window != None) {
+        XDestroyWindow(display(), m_window);
+        m_window = None;
+    }
+}
+
+void WindowBasedEdge::createWindow()
+{
+    if (m_window != None) {
+        return;
+    }
+
+    XSetWindowAttributes attributes;
+    attributes.override_redirect = True;
+    attributes.event_mask = EnterWindowMask | LeaveWindowMask;
+    unsigned long valuemask = CWOverrideRedirect | CWEventMask;
+
+    const QRect geom = geometry();
+    m_window = XCreateWindow(display(), rootWindow(),
+                             geom.x(), geom.y(), geom.width(), geom.height(),
+                             0, CopyFromParent, InputOnly, CopyFromParent, valuemask, &attributes);
+    XMapWindow(display(), m_window);
+    // Set XdndAware on the windows, so that DND enter events are received (#86998)
+    Atom version = 4; // XDND version
+    XChangeProperty(display(), m_window, atoms->xdnd_aware, XA_ATOM,
+                    32, PropModeReplace, (unsigned char*)(&version), 1);
+}
+
+void WindowBasedEdge::doGeometryUpdate()
+{
+    const QRect geom = geometry();
+    XMoveResizeWindow(display(), m_window,
+                      geom.x(), geom.y(), geom.width(), geom.height());
+}
+
+void WindowBasedEdge::doUpdateBlocking()
+{
+    if (!isReserved()) {
+        return;
+    }
+    if (isBlocked()) {
+        XUnmapWindow(display(), m_window);
+    } else {
+        XMapWindow(display(), m_window);
+    }
+}
+
+/**********************************************************
+ * ScreenEdges
+ *********************************************************/
+
 ScreenEdge::ScreenEdge()
     : QObject(NULL)
-    , m_screenEdgeWindows(ELECTRIC_COUNT, None)
-    , m_screenEdgeReserved(ELECTRIC_COUNT, 0)
+    , m_desktopSwitching(false)
+    , m_desktopSwitchingMovingClients(false)
+    , m_timeThreshold(0)
+    , m_reactivateThreshold(0)
+    , m_virtualDesktopLayout(0)
+    , m_actionTopLeft(ElectricActionNone)
+    , m_actionTop(ElectricActionNone)
+    , m_actionTopRight(ElectricActionNone)
+    , m_actionRight(ElectricActionNone)
+    , m_actionBottomRight(ElectricActionNone)
+    , m_actionBottom(ElectricActionNone)
+    , m_actionBottomLeft(ElectricActionNone)
+    , m_actionLeft(ElectricActionNone)
+    , m_cornerOffset(0)
 {
+    QWidget w;
+    m_cornerOffset = (w.physicalDpiX() + w.physicalDpiY() + 5) / 6;
 }
 
 ScreenEdge::~ScreenEdge()
@@ -57,326 +458,432 @@ ScreenEdge::~ScreenEdge()
 
 void ScreenEdge::init()
 {
-    reserveActions(true);
-    update();
+    reconfigure();
+    updateLayout();
+    recreateEdges();
+}
+
+static ElectricBorderAction electricBorderAction(const QString &name)
+{
+    QString lowerName = name.toLower();
+    if (lowerName == "dashboard") {
+        return ElectricActionDashboard;
+    } else if (lowerName == "showdesktop") {
+        return ElectricActionShowDesktop;
+    } else if (lowerName == "lockscreen") {
+        return ElectricActionLockScreen;
+    } else if (lowerName == "preventscreenlocking") {
+        return ElectricActionPreventScreenLocking;
+    }
+    return ElectricActionNone;
+}
+
+void ScreenEdge::reconfigure()
+{
+    if (!m_config) {
+        return;
+    }
+    // TODO: migrate settings to a group ScreenEdges
+    KConfigGroup windowsConfig = m_config->group("Windows");
+    setTimeThreshold(windowsConfig.readEntry("ElectricBorderDelay", 150));
+    setReActivationThreshold(qMax(timeThreshold() + 50, windowsConfig.readEntry("ElectricBorderCooldown", 350)));
+    int desktopSwitching = windowsConfig.readEntry("ElectricBorders", static_cast<int>(ElectricDisabled));
+    if (desktopSwitching == ElectricDisabled) {
+        setDesktopSwitching(false);
+        setDesktopSwitchingMovingClients(false);
+    } else if (desktopSwitching == ElectricMoveOnly) {
+        setDesktopSwitching(false);
+        setDesktopSwitchingMovingClients(true);
+    } else if (desktopSwitching == ElectricAlways) {
+        setDesktopSwitching(true);
+        setDesktopSwitchingMovingClients(true);
+    }
+    const int pushBack = windowsConfig.readEntry("ElectricBorderPushbackPixels", 1);
+    m_cursorPushBackDistance = QSize(pushBack, pushBack);
+
+    KConfigGroup borderConfig = m_config->group("ElectricBorders");
+    setActionForBorder(ElectricTopLeft,     &m_actionTopLeft,
+                       electricBorderAction(borderConfig.readEntry("TopLeft", "None")));
+    setActionForBorder(ElectricTop,         &m_actionTop,
+                       electricBorderAction(borderConfig.readEntry("Top", "None")));
+    setActionForBorder(ElectricTopRight,    &m_actionTopRight,
+                       electricBorderAction(borderConfig.readEntry("TopRight", "None")));
+    setActionForBorder(ElectricRight,       &m_actionRight,
+                       electricBorderAction(borderConfig.readEntry("Right", "None")));
+    setActionForBorder(ElectricBottomRight, &m_actionBottomRight,
+                       electricBorderAction(borderConfig.readEntry("BottomRight", "None")));
+    setActionForBorder(ElectricBottom,      &m_actionBottom,
+                       electricBorderAction(borderConfig.readEntry("Bottom", "None")));
+    setActionForBorder(ElectricBottomLeft,  &m_actionBottomLeft,
+                       electricBorderAction(borderConfig.readEntry("BottomLeft", "None")));
+    setActionForBorder(ElectricLeft,        &m_actionLeft,
+                       electricBorderAction(borderConfig.readEntry("Left", "None")));
 }
 
-void ScreenEdge::update(bool force)
+void ScreenEdge::setActionForBorder(ElectricBorder border, ElectricBorderAction* oldValue, ElectricBorderAction newValue)
 {
-    m_screenEdgeTimeFirst = xTime();
-    m_screenEdgeTimeLast = xTime();
-    m_screenEdgeTimeLastTrigger = xTime();
-    m_currentScreenEdge = ElectricNone;
-    QRect r = QRect(0, 0, displayWidth(), displayHeight());
-    m_screenEdgeTop = r.top();
-    m_screenEdgeBottom = r.bottom();
-    m_screenEdgeLeft = r.left();
-    m_screenEdgeRight = r.right();
 
-    for (int pos = 0; pos < ELECTRIC_COUNT; ++pos) {
-        if (force || m_screenEdgeReserved[pos] == 0) {
-            if (m_screenEdgeWindows[pos] != None)
-                XDestroyWindow(display(), m_screenEdgeWindows[pos]);
-            m_screenEdgeWindows[pos] = None;
+    if (*oldValue == newValue) {
+        return;
+    }
+    if (*oldValue == ElectricActionNone) {
+        // have to reserve
+        for (QList<WindowBasedEdge*>::iterator it = m_edges.begin(); it != m_edges.end(); ++it) {
+            if ((*it)->border() == border) {
+                (*it)->reserve();
+            }
         }
-        if (m_screenEdgeReserved[pos] == 0) {
+    }
+    if (newValue == ElectricActionNone) {
+        // have to unreserve
+        for (QList<WindowBasedEdge*>::iterator it = m_edges.begin(); it != m_edges.end(); ++it) {
+            if ((*it)->border() == border) {
+                (*it)->unreserve();
+            }
+        }
+    }
+    *oldValue = newValue;
+    // update action on all Edges for given border
+    for (QList<WindowBasedEdge*>::iterator it = m_edges.begin(); it != m_edges.end(); ++it) {
+        if ((*it)->border() == border) {
+            (*it)->setAction(newValue);
+        }
+    }
+}
+
+void ScreenEdge::updateLayout()
+{
+    const QSize desktopMatrix = Workspace::self()->desktopGridSize();
+    Qt::Orientations newLayout = 0;
+    if (desktopMatrix.width() > 1) {
+        newLayout |= Qt::Horizontal;
+    }
+    if (desktopMatrix.height() > 1) {
+        newLayout |= Qt::Vertical;
+    }
+    if (newLayout == m_virtualDesktopLayout) {
+        return;
+    }
+    if (isDesktopSwitching()) {
+        reserveDesktopSwitching(false, m_virtualDesktopLayout);
+    }
+    m_virtualDesktopLayout = newLayout;
+    if (isDesktopSwitching()) {
+        reserveDesktopSwitching(true, m_virtualDesktopLayout);
+    }
+}
+
+static bool isLeftScreen(const QRect &screen, const QRect &fullArea)
+{
+    if (QApplication::desktop()->screenCount() == 1) {
+        return true;
+    }
+    if (screen.x() == fullArea.x()) {
+        return true;
+    }
+    // the screen is also on the left in case of a vertical layout with a second screen
+    // more to the left. In that case no screen ends left of screen's x coord
+    for (int i=0; i<QApplication::desktop()->screenCount(); ++i) {
+        const QRect otherGeo = QApplication::desktop()->screenGeometry(i);
+        if (otherGeo == screen) {
+            // that's our screen to test
             continue;
         }
-        if (m_screenEdgeWindows[pos] != None)
+        if (otherGeo.x() + otherGeo.width() <= screen.x()) {
+            // other screen is completely in the left
+            return false;
+        }
+    }
+    // did not find a screen left of our current screen, so it is the left most
+    return true;
+}
+
+static bool isRightScreen(const QRect &screen, const QRect &fullArea)
+{
+    if (QApplication::desktop()->screenCount() == 1) {
+        return true;
+    }
+    if (screen.x() + screen.width() == fullArea.x() + fullArea.width()) {
+        return true;
+    }
+    // the screen is also on the right in case of a vertical layout wit a second screen
+    // more to the right. In that case no screen starts right of this screen
+    for (int i=0; i<QApplication::desktop()->screenCount(); ++i) {
+        const QRect otherGeo = QApplication::desktop()->screenGeometry(i);
+        if (otherGeo == screen) {
+            // that's our screen to test
             continue;
-        XSetWindowAttributes attributes;
-        attributes.override_redirect = True;
-        attributes.event_mask = EnterWindowMask | LeaveWindowMask;
-        unsigned long valuemask = CWOverrideRedirect | CWEventMask;
-        int xywh[ELECTRIC_COUNT][4] = {
-            { r.left() + 1, r.top(), r.width() - 2, 1 },   // Top
-            { r.right(), r.top(), 1, 1 },                  // Top-right
-            { r.right(), r.top() + 1, 1, r.height() - 2 }, // Etc.
-            { r.right(), r.bottom(), 1, 1 },
-            { r.left() + 1, r.bottom(), r.width() - 2, 1 },
-            { r.left(), r.bottom(), 1, 1 },
-            { r.left(), r.top() + 1, 1, r.height() - 2 },
-            { r.left(), r.top(), 1, 1 }
-        };
-        m_screenEdgeWindows[pos] = XCreateWindow(display(), rootWindow(),
-                                              xywh[pos][0], xywh[pos][1], xywh[pos][2], xywh[pos][3],
-                                              0, CopyFromParent, InputOnly, CopyFromParent, valuemask, &attributes);
-        XMapWindow(display(), m_screenEdgeWindows[pos]);
-
-        // Set XdndAware on the windows, so that DND enter events are received (#86998)
-        Atom version = 4; // XDND version
-        XChangeProperty(display(), m_screenEdgeWindows[pos], atoms->xdnd_aware, XA_ATOM,
-                        32, PropModeReplace, (unsigned char*)(&version), 1);
-    }
-}
-
-void ScreenEdge::restoreSize(ElectricBorder border)
-{
-    if (m_screenEdgeWindows[border] == None)
-        return;
-    QRect r(0, 0, displayWidth(), displayHeight());
-    int xywh[ELECTRIC_COUNT][4] = {
-        { r.left() + 1, r.top(), r.width() - 2, 1 },   // Top
-        { r.right(), r.top(), 1, 1 },                  // Top-right
-        { r.right(), r.top() + 1, 1, r.height() - 2 }, // Etc.
-        { r.right(), r.bottom(), 1, 1 },
-        { r.left() + 1, r.bottom(), r.width() - 2, 1 },
-        { r.left(), r.bottom(), 1, 1 },
-        { r.left(), r.top() + 1, 1, r.height() - 2 },
-        { r.left(), r.top(), 1, 1 }
-    };
-    XMoveResizeWindow(display(), m_screenEdgeWindows[border],
-                      xywh[border][0], xywh[border][1], xywh[border][2], xywh[border][3]);
-}
-
-void ScreenEdge::reserveActions(bool isToReserve)
-{
-    for (int pos = 0; pos < ELECTRIC_COUNT; ++pos)
-        if (options->electricBorderAction(static_cast<ElectricBorder>(pos))) {
-            if (isToReserve)
-                reserve(static_cast<ElectricBorder>(pos));
-            else
-                unreserve(static_cast<ElectricBorder>(pos));
         }
+        if (otherGeo.x() >= screen.x() + screen.width()) {
+            // other screen is completely in the right
+            return false;
+        }
+    }
+    // did not find a screen right of our current screen, so it is the right most
+    return true;
 }
 
-void ScreenEdge::reserveDesktopSwitching(bool isToReserve, Qt::Orientations o)
+static bool isTopScreen(const QRect &screen, const QRect &fullArea)
 {
-    if (!o)
-        return;
-    if (isToReserve) {
-        reserve(ElectricTopLeft);
-        reserve(ElectricTopRight);
-        reserve(ElectricBottomRight);
-        reserve(ElectricBottomLeft);
-
-        if (o & Qt::Horizontal) {
-            reserve(ElectricLeft);
-            reserve(ElectricRight);
+    if (QApplication::desktop()->screenCount() == 1) {
+        return true;
+    }
+    if (screen.y() == fullArea.y()) {
+        return true;
+    }
+    // the screen is also top most in case of a horizontal layout with a second screen
+    // more to the top. In that case no screen ends above screen's y cord
+    for (int i=0; i<QApplication::desktop()->screenCount(); ++i) {
+        const QRect otherGeo = QApplication::desktop()->screenGeometry(i);
+        if (otherGeo == screen) {
+              // that's our screen to test
+            continue;
         }
-        if (o & Qt::Vertical) {
-            reserve(ElectricTop);
-            reserve(ElectricBottom);
+        if (otherGeo.y() + otherGeo.height() <= screen.y()) {
+            // other screen is completely above
+            return false;
         }
-    } else {
-        unreserve(ElectricTopLeft);
-        unreserve(ElectricTopRight);
-        unreserve(ElectricBottomRight);
-        unreserve(ElectricBottomLeft);
-
-        if (o & Qt::Horizontal) {
-            unreserve(ElectricLeft);
-            unreserve(ElectricRight);
+    }
+    // did not find a screen above our current screen, os it is the top most
+    return true;
+}
+
+static bool isBottomScreen(const QRect &screen, const QRect &fullArea)
+{
+    if (QApplication::desktop()->screenCount() == 1) {
+        return true;
+    }
+    if (screen.y() + screen.height() == fullArea.y() + fullArea.height()) {
+        return true;
+    }
+    // the screen is also bottom most in case of a horizontal layout with a second screen
+    // more below. In that case no screen starts below screen's y coord + height
+    for (int i=0; i<QApplication::desktop()->screenCount(); ++i) {
+        const QRect otherGeo = QApplication::desktop()->screenGeometry(i);
+        if (otherGeo == screen) {
+            // that's our screen to test
+            continue;
         }
-        if (o & Qt::Vertical) {
-            unreserve(ElectricTop);
-            unreserve(ElectricBottom);
+        if (otherGeo.y() >= screen.y() + screen.height()) {
+            // other screen is completely below
+            return false;
         }
     }
+    // did not find a screen below our current screen, so it is the bottom most
+    return true;
 }
 
-void ScreenEdge::reserve(ElectricBorder border)
+void ScreenEdge::recreateEdges()
 {
-    if (border == ElectricNone)
-        return;
-    if (m_screenEdgeReserved[border]++ == 0)
-        QTimer::singleShot(0, this, SLOT(update()));
+  QList<WindowBasedEdge*> oldEdges = m_edges;
+  m_edges.clear();
+  QRect fullArea = QRect(0, 0, displayWidth(), displayHeight());
+  for (int i = 0, c = QApplication::desktop()->screenCount(); i < c; ++i) {
+        const QRect screen = QApplication::desktop()->screenGeometry(i);
+        if (isLeftScreen(screen, fullArea)) {
+            createVerticalEdge(ElectricLeft, screen, fullArea);
+        }
+        if (isRightScreen(screen, fullArea)) {
+            createVerticalEdge(ElectricRight, screen, fullArea);
+        }
+        if (isTopScreen(screen, fullArea)) {
+            createHorizontalEdge(ElectricTop, screen, fullArea);
+        }
+        if (isBottomScreen(screen, fullArea)) {
+            createHorizontalEdge(ElectricBottom, screen, fullArea);
+        }
+    }
+
+    for (QList<WindowBasedEdge*>::iterator it = m_edges.begin(); it != m_edges.end(); ++it) {
+        WindowBasedEdge *edge = *it;
+        for (QList<WindowBasedEdge*>::const_iterator oldIt = oldEdges.constBegin();
+                oldIt != oldEdges.constEnd();
+                ++oldIt) {
+            WindowBasedEdge *oldEdge = *oldIt;
+            if (oldEdge->border() != edge->border()) {
+                continue;
+            }
+            const QHash<QObject *, QByteArray> &callbacks = oldEdge->callBacks();
+            for (QHash<QObject *, QByteArray>::const_iterator callback = callbacks.begin();
+                    callback != callbacks.end();
+                    ++callback) {
+                edge->reserve(callback.key(), callback.value().constData());
+            }
+        }
+    }
+    qDeleteAll(oldEdges);
 }
 
-void ScreenEdge::unreserve(ElectricBorder border)
+void ScreenEdge::createVerticalEdge(ElectricBorder border, const QRect &screen, const QRect &fullArea)
 {
-    if (border == ElectricNone)
+    if (border != KWin::ElectricRight && border != KWin::ElectricLeft) {
         return;
-    assert(m_screenEdgeReserved[border] > 0);
-    if (--m_screenEdgeReserved[border] == 0)
-        QTimer::singleShot(0, this, SLOT(update()));
+    }
+    const int y = screen.y();
+    const int height = screen.height();
+    const int x = (border == ElectricLeft) ? screen.x() : screen.x() + screen.width() - 1;
+    if (isTopScreen(screen, fullArea)) {
+        // also top most screen
+        // create top left/right edge
+        const ElectricBorder edge = (border == ElectricLeft) ? ElectricTopLeft : ElectricTopRight;
+        m_edges << createEdge(edge, x, screen.y(), 1, 1);
+    }
+    if (isBottomScreen(screen, fullArea)) {
+          // also bottom most screen
+        // create bottom left/right edge
+        const ElectricBorder edge = (border == ElectricLeft) ? ElectricBottomLeft : ElectricBottomRight;
+        m_edges << createEdge(edge, x, screen.y() + screen.height() - 1, 1, 1);
+    }
+    m_edges << createEdge(border, x, y, 1, height);
 }
 
-void ScreenEdge::check(const QPoint& pos, Time now, bool forceNoPushback)
+void ScreenEdge::createHorizontalEdge(ElectricBorder border, const QRect &screen, const QRect &fullArea)
 {
-    if ((pos.x() != m_screenEdgeLeft) &&
-            (pos.x() != m_screenEdgeRight) &&
-            (pos.y() != m_screenEdgeTop) &&
-            (pos.y() != m_screenEdgeBottom))
-        return;
+    Q_UNUSED(fullArea)
 
-    bool have_borders = false;
-    for (int i = 0; i < ELECTRIC_COUNT; ++i)
-        if (m_screenEdgeWindows[i] != None)
-            have_borders = true;
-    if (!have_borders)
+    if (border != ElectricTop && border != ElectricBottom) {
         return;
+    }
+    const int x = screen.x();
+    const int width = screen.width();
+    const int y = (border == ElectricTop) ? screen.y() : screen.y() + screen.height() - 1;
+    m_edges << createEdge(border, x, y, width, 1);
+}
 
-    Time treshold_set = options->electricBorderDelay(); // Set timeout
-    Time treshold_reset = 250; // Reset timeout
-    Time treshold_trigger = options->electricBorderCooldown(); // Minimum time between triggers
-    int distance_reset = 30; // Mouse should not move more than this many pixels
-    int pushback_pixels = forceNoPushback ? 0 : options->electricBorderPushbackPixels();
-
-    ElectricBorder border;
-    if (pos.x() == m_screenEdgeLeft && pos.y() == m_screenEdgeTop)
-        border = ElectricTopLeft;
-    else if (pos.x() == m_screenEdgeRight && pos.y() == m_screenEdgeTop)
-        border = ElectricTopRight;
-    else if (pos.x() == m_screenEdgeLeft && pos.y() == m_screenEdgeBottom)
-        border = ElectricBottomLeft;
-    else if (pos.x() == m_screenEdgeRight && pos.y() == m_screenEdgeBottom)
-        border = ElectricBottomRight;
-    else if (pos.x() == m_screenEdgeLeft)
-        border = ElectricLeft;
-    else if (pos.x() == m_screenEdgeRight)
-        border = ElectricRight;
-    else if (pos.y() == m_screenEdgeTop)
-        border = ElectricTop;
-    else if (pos.y() == m_screenEdgeBottom)
-        border = ElectricBottom;
-    else
-        abort();
-
-    if (m_screenEdgeWindows[border] == None)
-        return;
+WindowBasedEdge* ScreenEdge::createEdge(ElectricBorder border, int x, int y, int width, int height)
+{
+    WindowBasedEdge *edge = new WindowBasedEdge(this);
+    edge->setBorder(border);
+    edge->setGeometry(QRect(x, y, width, height));
+    const ElectricBorderAction action = actionForEdge(edge);
+    if (action != KWin::ElectricActionNone) {
+        edge->reserve();
+        edge->setAction(action);
+    }
+    if (isDesktopSwitching()) {
+        if (edge->isCorner()) {
+            edge->reserve();
+        } else {
+            if ((m_virtualDesktopLayout & Qt::Horizontal) && (edge->isLeft() || edge->isRight())) {
+                edge->reserve();
+            }
+            if ((m_virtualDesktopLayout & Qt::Vertical) & (edge->isTop() || edge->isBottom())) {
+                edge->reserve();
+            }
+        }
+    }
+    return edge;
+}
 
-    if (pushback_pixels == 0) {
-        // no pushback so we have to activate at once
-        m_screenEdgeTimeLast = now;
-        m_currentScreenEdge = border;
-        m_screenEdgePushPoint = pos;
-    }
-
-    if ((m_currentScreenEdge == border) &&
-            (timestampDiff(m_screenEdgeTimeLast, now) < treshold_reset) &&
-            (timestampDiff(m_screenEdgeTimeLastTrigger, now) > treshold_trigger) &&
-            ((pos - m_screenEdgePushPoint).manhattanLength() < distance_reset)) {
-        m_screenEdgeTimeLast = now;
-
-        if (timestampDiff(m_screenEdgeTimeFirst, now) > treshold_set) {
-            m_currentScreenEdge = ElectricNone;
-            m_screenEdgeTimeLastTrigger = now;
-            if (Workspace::self()->getMovingClient()) {
-                // If moving a client or have force doing the desktop switch
-                if (options->electricBorders() != Options::ElectricDisabled)
-                    switchDesktop(border, pos);
-                return; // Don't reset cursor position
-            } else {
-                if (options->electricBorders() == Options::ElectricAlways &&
-                        (border == ElectricTop || border == ElectricRight ||
-                         border == ElectricBottom || border == ElectricLeft)) {
-                    // If desktop switching is always enabled don't apply it to the corners if
-                    // an effect is applied to it (We will check that later).
-                    switchDesktop(border, pos);
-                    return; // Don't reset cursor position
-                }
-                switch(options->electricBorderAction(border)) {
-                case ElectricActionDashboard: { // Display Plasma dashboard
-                    QDBusInterface plasmaApp("org.kde.plasma-desktop", "/App");
-                    plasmaApp.call("toggleDashboard");
-                }
-                break;
-                case ElectricActionShowDesktop: {
-                    Workspace::self()->setShowingDesktop(!Workspace::self()->showingDesktop());
-                    break;
-                }
-                case ElectricActionLockScreen: { // Lock the screen
-                    QDBusInterface screenSaver("org.kde.screensaver", "/ScreenSaver");
-                    screenSaver.call("Lock");
-                }
-                break;
-                case ElectricActionPreventScreenLocking: {
-                    break;
-                }
-                case ElectricActionNone: // Either desktop switching or an effect
-                default: {
-                    if (effects && static_cast<EffectsHandlerImpl*>(effects)->borderActivated(border))
-                        {} // Handled by effects
-                    else {
-                        if (options->electricBorders() == Options::ElectricAlways) {
-                            switchDesktop(border, pos);
-                            return; // Don't reset cursor position
-                        }
-                        emit activated(border);
-                    }
-                }
-                }
+ElectricBorderAction ScreenEdge::actionForEdge(Edge* edge) const
+{
+    switch (edge->border()) {
+    case ElectricTopLeft:
+        return m_actionTopLeft;
+    case ElectricTop:
+        return m_actionTop;
+    case ElectricTopRight:
+        return m_actionTopRight;
+    case ElectricRight:
+        return m_actionRight;
+    case ElectricBottomRight:
+        return m_actionBottomRight;
+    case ElectricBottom:
+        return m_actionBottom;
+    case ElectricBottomLeft:
+        return m_actionBottomLeft;
+    case ElectricLeft:
+        return m_actionLeft;
+    default:
+        // fall through
+        break;
+    }
+    return ElectricActionNone;
+}
+
+void ScreenEdge::reserveDesktopSwitching(bool isToReserve, Qt::Orientations o)
+{
+    if (!o)
+        return;
+    for (QList<WindowBasedEdge*>::iterator it = m_edges.begin(); it != m_edges.end(); ++it) {
+        WindowBasedEdge *edge = *it;
+        if (edge->isCorner()) {
+            isToReserve ? edge->reserve() : edge->unreserve();
+        } else {
+            if ((m_virtualDesktopLayout & Qt::Horizontal) && (edge->isLeft() || edge->isRight())) {
+                isToReserve ? edge->reserve() : edge->unreserve();
+            }
+            if ((m_virtualDesktopLayout & Qt::Vertical) && (edge->isTop() || edge->isBottom())) {
+                isToReserve ? edge->reserve() : edge->unreserve();
             }
         }
-    } else {
-        m_currentScreenEdge = border;
-        m_screenEdgeTimeFirst = now;
-        m_screenEdgeTimeLast = now;
-        m_screenEdgePushPoint = pos;
-    }
-
-    // Reset the pointer to find out whether the user is really pushing
-    // (the direction back from which it came, starting from top clockwise)
-    const int xdiff[ELECTRIC_COUNT] = { 0,
-                                        -pushback_pixels,
-                                        -pushback_pixels,
-                                        -pushback_pixels,
-                                        0,
-                                        pushback_pixels,
-                                        pushback_pixels,
-                                        pushback_pixels
-                                      };
-    const int ydiff[ELECTRIC_COUNT] = { pushback_pixels,
-                                        pushback_pixels,
-                                        0,
-                                        -pushback_pixels,
-                                        -pushback_pixels,
-                                        -pushback_pixels,
-                                        0,
-                                        pushback_pixels
-                                      };
-    QCursor::setPos(pos.x() + xdiff[border], pos.y() + ydiff[border]);
-}
-
-void ScreenEdge::switchDesktop(ElectricBorder border, const QPoint& _pos)
-{
-    QPoint pos = _pos;
-    int desk = Workspace::self()->currentDesktop();
-    const int OFFSET = 2;
-    if (border == ElectricLeft || border == ElectricTopLeft || border == ElectricBottomLeft) {
-        desk = Workspace::self()->desktopToLeft(desk, options->isRollOverDesktops());
-        pos.setX(displayWidth() - 1 - OFFSET);
-    }
-    if (border == ElectricRight || border == ElectricTopRight || border == ElectricBottomRight) {
-        desk = Workspace::self()->desktopToRight(desk, options->isRollOverDesktops());
-        pos.setX(OFFSET);
-    }
-    if (border == ElectricTop || border == ElectricTopLeft || border == ElectricTopRight) {
-        desk = Workspace::self()->desktopAbove(desk, options->isRollOverDesktops());
-        pos.setY(displayHeight() - 1 - OFFSET);
-    }
-    if (border == ElectricBottom || border == ElectricBottomLeft || border == ElectricBottomRight) {
-        desk = Workspace::self()->desktopBelow(desk, options->isRollOverDesktops());
-        pos.setY(OFFSET);
-    }
-    Client *c = Workspace::self()->getMovingClient();
-    if (c && c->rules()->checkDesktop(desk) != desk)
-        return; // user attempts to move a client to another desktop where it is ruleforced to not be
-    int desk_before = Workspace::self()->currentDesktop();
-    Workspace::self()->setCurrentDesktop(desk);
-    if (Workspace::self()->currentDesktop() != desk_before)
-        QCursor::setPos(pos);
+    }
+}
+
+void ScreenEdge::reserve(ElectricBorder border, QObject* object, const char* slot)
+{
+   for (QList<WindowBasedEdge*>::iterator it = m_edges.begin(); it != m_edges.end(); ++it) {
+        if ((*it)->border() == border) {
+            (*it)->reserve(object, slot);
+        }
+    }
+}
+
+void ScreenEdge::unreserve(ElectricBorder border, QObject* object)
+{
+    for (QList<WindowBasedEdge*>::iterator it = m_edges.begin(); it != m_edges.end(); ++it) {
+        if ((*it)->border() == border) {
+            (*it)->unreserve(object);
+        }
+    }
+}
+
+void ScreenEdge::check(const QPoint& pos, const QDateTime &now, bool forceNoPushback)
+{
+    for (QList<WindowBasedEdge*>::iterator it = m_edges.begin(); it != m_edges.end(); ++it) {
+        (*it)->check(pos, now, forceNoPushback);
+    }
 }
 
 bool ScreenEdge::isEntered(XEvent* e)
 {
     if (e->type == EnterNotify) {
-        for (int i = 0; i < ELECTRIC_COUNT; ++i)
-            if (m_screenEdgeWindows[i] != None && e->xcrossing.window == m_screenEdgeWindows[i]) {
-                // The user entered an electric border
-                check(QPoint(e->xcrossing.x_root, e->xcrossing.y_root), e->xcrossing.time);
-                return true;
-            }
+        return handleEnterNotify(e->xcrossing.window,
+                                 QPoint(e->xcrossing.x_root, e->xcrossing.y_root),
+                                 QDateTime::fromMSecsSinceEpoch(e->xcrossing.time));
     }
     if (e->type == ClientMessage) {
         if (e->xclient.message_type == atoms->xdnd_position) {
-            for (int i = 0; i < ELECTRIC_COUNT; ++i)
-                if (m_screenEdgeWindows[i] != None && e->xclient.window == m_screenEdgeWindows[i]) {
-                    updateXTime();
-                    check(QPoint(e->xclient.data.l[2] >> 16, e->xclient.data.l[2] & 0xffff), xTime(), true);
-                    return true;
-                }
+            return handleDndNotify(e->xclient.window,
+                                   QPoint(e->xclient.data.l[2] >> 16, e->xclient.data.l[2] & 0xffff));
+        }
+    }
+    return false;
+}
+
+bool ScreenEdge::handleEnterNotify(Window window, const QPoint &point, const QDateTime &timestamp)
+{
+    for (QList<WindowBasedEdge*>::iterator it = m_edges.begin(); it != m_edges.end(); ++it) {
+        WindowBasedEdge *edge = *it;
+        if (!edge->isReserved()) {
+            continue;
+        }
+        if (edge->window() == window) {
+            edge->check(point, timestamp);
+            return true;
+        }
+    }
+    return false;
+}
+
+bool ScreenEdge::handleDndNotify(Window window, const QPoint& point)
+{
+    for (QList<WindowBasedEdge*>::iterator it = m_edges.begin(); it != m_edges.end(); ++it) {
+        WindowBasedEdge *edge = *it;
+        if (edge->isReserved() && edge->window() == window) {
+            updateXTime();
+            edge->check(point, QDateTime::fromMSecsSinceEpoch(xTime()), true);
+            return true;
         }
     }
     return false;
@@ -386,9 +893,14 @@ void ScreenEdge::ensureOnTop()
 {
     Window* windows = new Window[ 8 ]; // There are up to 8 borders
     int pos = 0;
-    for (int i = 0; i < ELECTRIC_COUNT; ++i)
-        if (m_screenEdgeWindows[ i ] != None)
-            windows[ pos++ ] = m_screenEdgeWindows[ i ];
+    for (QList<WindowBasedEdge*>::const_iterator it = m_edges.constBegin();
+            it != m_edges.constEnd();
+            ++it) {
+        WindowBasedEdge *edge = *it;
+        if (edge->window() == None) {
+            windows[pos++] = edge->window();
+        }
+    }
     if (!pos) {
         delete [] windows;
         return; // No borders at all
@@ -399,9 +911,19 @@ void ScreenEdge::ensureOnTop()
 }
 
 
-const QVector< Window >& ScreenEdge::windows()
+QVector<Window> ScreenEdge::windows() const
 {
-    return m_screenEdgeWindows;
+    QVector<Window> wins;
+    for (QList<WindowBasedEdge*>::const_iterator it = m_edges.constBegin();
+          it != m_edges.constEnd();
+          ++it) {
+        Window win =(*it)->window();
+        if (win != None) {
+            wins.append(win);
+        }
+    }
+    return wins;
 }
+
 } //namespace
 
diff --git a/kwin/screenedge.h b/kwin/screenedge.h
index d7da6e9..83669ce 100644
--- a/kwin/screenedge.h
+++ b/kwin/screenedge.h
@@ -30,11 +30,93 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 #define KWIN_SCREENEDGE_H
 #include <QtCore/QObject>
 #include <QtCore/QVector>
-#include "kwinglobals.h"
+#include <QtCore/QDateTime>
+#include <QtCore/QHash>
+
+#include <KSharedConfig>
 
+#include "kwinglobals.h"
 
 namespace KWin {
 
+class ScreenEdge;
+
+class Edge: public QObject
+{
+    Q_OBJECT
+public:
+    explicit Edge(ScreenEdge *edges);
+    virtual ~Edge();
+    bool isLeft() const;
+    bool isRight() const;
+    bool isTop() const;
+    bool isBottom() const;
+    bool isCorner() const;
+    bool isScreenEdge();
+    bool triggersFor(const QPoint &cursorPos) const;
+    void check(const QPoint &cursorPos, const QDateTime &triggerTime, bool forceNoPushBack = false);
+    bool isReserved() const;
+
+    ElectricBorder border() const;
+    void reserve(QObject *object, const char *slot);
+    const QHash<QObject *, QByteArray> &callBacks() const;
+
+public Q_SLOTS:
+    void reserve();
+    void unreserve();
+    void unreserve(QObject *object);
+    void setBorder(ElectricBorder border);
+    void setAction(ElectricBorderAction action);
+    void setGeometry(const QRect &geometry);
+    void checkBlocking();
+protected:
+    ScreenEdge *edges();
+    const ScreenEdge *edges() const;
+    const QRect &geometry() const;
+    bool isBlocked() const;
+    virtual void doGeometryUpdate();
+    virtual void activate();
+    virtual void deactivate();
+    virtual void doUpdateBlocking();
+private:
+    bool canActivate(const QPoint &cursorPos, const QDateTime &triggerTime);
+    void handle(const QPoint &cursorPos);
+    bool handleAction();
+    bool handleByCallback();
+    void switchDesktop(const QPoint &cursorPos);
+    void pushCursorBack(const QPoint &cursorPos);
+    ScreenEdge *m_edges;
+    ElectricBorder m_border;
+    ElectricBorderAction m_action;
+    int m_reserved;
+    QRect m_geometry;
+    QDateTime m_lastTrigger;
+    QDateTime m_lastReset;
+    QPoint m_triggeredPoint;
+    QHash<QObject *, QByteArray> m_callBacks;
+    bool m_blocked;
+};
+
+class WindowBasedEdge : public Edge
+{
+    Q_OBJECT
+public:
+    explicit WindowBasedEdge(ScreenEdge *parent);
+    virtual ~WindowBasedEdge();
+
+    Window window() const;
+
+protected:
+    virtual void doGeometryUpdate();
+    virtual void doUpdateBlocking();
+    virtual void activate();
+    virtual void deactivate();
+
+private:
+    void createWindow();
+    Window m_window;
+};
+
 /**
  * @short This class is used to handle the screen edges
  * Screen Edge Window management. Screen Edges allow a user to change the virtual
@@ -50,6 +132,10 @@ public:
     ScreenEdge();
     ~ScreenEdge();
     /**
+     * @internal
+     */
+    void setConfig(KSharedConfig::Ptr config);
+    /**
      * Initialize the screen edges.
      */
     void init();
@@ -60,27 +146,33 @@ public:
      * @param now the time when the function is called
      * @param forceNoPushBack needs to be called to workaround some DnD clients, don't use unless you want to chek on a DnD event
      */
-    void check(const QPoint& pos, Time now, bool forceNoPushBack = false);
+    void check(const QPoint& pos, const QDateTime &now, bool forceNoPushBack = false);
     /**
-     * Restore the size of the specified screen edges
-     * @param border the screen edge to restore the size of
+     * The (dpi dependent) length, reserved for the active corners of each edge - 1/3"
      */
-    void restoreSize(ElectricBorder border);
-    /**
-     * Mark the specified screen edge as reserved in m_screenEdgeReserved
+    int cornerOffset() const;
+   /**
+     * Mark the specified screen edge as reserved. This method is provided for external activation
+     * like effects and scripts. When the effect/script does no longer need the edge it is supposed
+     * to call @link unreserve.
      * @param border the screen edge to mark as reserved
+     * @param object The object on which the @p callback needs to be invoked
+     * @param callback The method name to be invoked - uses QMetaObject::invokeMethod
+     * @see unreserve
+     * @todo: add pointer to script/effect
      */
-    void reserve(ElectricBorder border);
+    void reserve(ElectricBorder border, QObject *object, const char *slot);
     /**
-     * Mark the specified screen edge as unreserved in m_screenEdgeReserved
+     * Mark the specified screen edge as unreserved. This method is provided for external activation
+     * like effects and scripts. This method is only allowed to be called if @link reserve had been
+     * called before for the same @p border. An unbalanced calling of reserve/unreserve leads to the
+     * edge never being active or never being able to deactivate again.
      * @param border the screen edge to mark as unreserved
+     * @param object the object on which the callback had been invoked
+     * @see reserve
+     * @todo: add pointer to script/effect
      */
-    void unreserve(ElectricBorder border);
-    /**
-     * Reserve actions for screen edges, if reserve is true. Unreserve otherwise.
-     * @param reserve indicated weather actions should be reserved or unreseved
-     */
-    void reserveActions(bool isToReserve);
+    void unreserve(ElectricBorder border, QObject *object);
     /**
      * Reserve desktop switching for screen edges, if reserve is true. Unreserve otherwise.
      * @param reserve indicated weather desktop switching should be reserved or unreseved
@@ -97,18 +189,45 @@ public:
     * @param e the X event which is passed to this method.
     */
     bool isEntered(XEvent * e);
+
     /**
      * Returns a QVector of all existing screen edge windows
      * @return all existing screen edge windows in a QVector
      */
-    const QVector< Window >& windows();
-public Q_SLOTS:
+    QVector< Window > windows() const;
+
+    bool isDesktopSwitching() const;
+    bool isDesktopSwitchingMovingClients() const;
+    const QSize &cursorPushBackDistance() const;
     /**
-     * Update the screen edge windows. Add new ones if the user specified
-     * a new action or enabled desktop switching. Remove, if user deleted
-     * actions or disabled desktop switching.
+     * Minimum time between the push back of the cursor and the activation by re-entering the edge.
      */
-    void update(bool force=false);
+    int timeThreshold() const;
+    /**
+     * Minimum time between triggers
+     **/
+    int reActivationThreshold() const;
+    ElectricBorderAction actionTopLeft() const;
+    ElectricBorderAction actionTop() const;
+    ElectricBorderAction actionTopRight() const;
+    ElectricBorderAction actionRight() const;
+    ElectricBorderAction actionBottomRight() const;
+    ElectricBorderAction actionBottom() const;
+    ElectricBorderAction actionBottomLeft() const;
+    ElectricBorderAction actionLeft() const;
+
+public Q_SLOTS:
+    void reconfigure();
+    /**
+     * Updates the layout of virtual desktops and adjust the reserved borders in case of
+     * virtual desktop switching on edges.
+     **/
+    void updateLayout();
+    /**
+     * Recreates all edges e.g. after the screen size changes.
+     **/
+    void recreateEdges();
+
 Q_SIGNALS:
     /**
      * Emitted when the @p border got activated and there is neither an effect nor a global
@@ -116,24 +235,226 @@ Q_SIGNALS:
      * @param border The border which got activated
      **/
     void activated(ElectricBorder border);
+
+    void checkBlocking();
+
 private:
-    /**
-     * Switch the desktop if desktop switching is enabled and a screen edge
-     * is entered to trigger this action.
-     */
-    void switchDesktop(ElectricBorder border, const QPoint& pos);
-
-    QVector< Window > m_screenEdgeWindows;
-    QVector< int > m_screenEdgeReserved; // Corners/edges used by something
-    ElectricBorder m_currentScreenEdge;
-    int m_screenEdgeLeft;
-    int m_screenEdgeRight;
-    int m_screenEdgeTop;
-    int m_screenEdgeBottom;
-    Time m_screenEdgeTimeFirst;
-    Time m_screenEdgeTimeLast;
-    Time m_screenEdgeTimeLastTrigger;
-    QPoint m_screenEdgePushPoint;
+    enum { ElectricDisabled = 0, ElectricMoveOnly = 1, ElectricAlways = 2 };
+    void setDesktopSwitching(bool enable);
+    void setDesktopSwitchingMovingClients(bool enable);
+    void setCursorPushBackDistance(const QSize &distance);
+    void setTimeThreshold(int treshold);
+    void setReActivationThreshold(int reshold);
+    void createHorizontalEdge(ElectricBorder border, const QRect &screen, const QRect &fullArea);
+    void createVerticalEdge(ElectricBorder border, const QRect &screen, const QRect &fullArea);
+    WindowBasedEdge *createEdge(ElectricBorder border, int x, int y, int width, int height);
+    void setActionForBorder(ElectricBorder border, ElectricBorderAction *oldValue, ElectricBorderAction newValue);
+    ElectricBorderAction actionForEdge(Edge *edge) const;
+    bool handleEnterNotify(Window window, const QPoint &point, const QDateTime &timestamp);
+    bool handleDndNotify(Window window, const QPoint &point);
+    bool m_desktopSwitching;
+    bool m_desktopSwitchingMovingClients;
+    QSize m_cursorPushBackDistance;
+    int m_timeThreshold;
+    int m_reactivateThreshold;
+    Qt::Orientations m_virtualDesktopLayout;
+    QList<WindowBasedEdge*> m_edges;
+    KSharedConfig::Ptr m_config;
+    ElectricBorderAction m_actionTopLeft;
+    ElectricBorderAction m_actionTop;
+    ElectricBorderAction m_actionTopRight;
+    ElectricBorderAction m_actionRight;
+    ElectricBorderAction m_actionBottomRight;
+    ElectricBorderAction m_actionBottom;
+    ElectricBorderAction m_actionBottomLeft;
+    ElectricBorderAction m_actionLeft;
+    int m_cornerOffset;
 };
+
+
+
+/**********************************************************
+ * Inlines Edge
+ *********************************************************/
+
+inline bool Edge::isBottom() const
+{
+    return m_border == ElectricBottom || m_border == ElectricBottomLeft || m_border == ElectricBottomRight;
+}
+
+inline bool Edge::isLeft() const
+{
+    return m_border == ElectricLeft || m_border == ElectricTopLeft || m_border == ElectricBottomLeft;
+}
+
+inline bool Edge::isRight() const
+{
+    return m_border == ElectricRight || m_border == ElectricTopRight || m_border == ElectricBottomRight;
+}
+
+inline bool Edge::isTop() const
+{
+    return m_border == ElectricTop || m_border == ElectricTopLeft || m_border == ElectricTopRight;
+}
+
+inline bool Edge::isCorner() const
+{
+    return m_border == ElectricTopLeft
+        || m_border == ElectricTopRight
+        || m_border == ElectricBottomRight
+        || m_border == ElectricBottomLeft;
+}
+
+inline bool Edge::isScreenEdge()
+{
+    return m_border == ElectricLeft
+        || m_border == ElectricTop
+        || m_border == ElectricRight
+        || m_border == ElectricBottom;
 }
+
+inline bool Edge::isReserved() const
+{
+    return m_reserved != 0;
+}
+
+inline void Edge::setAction(ElectricBorderAction action)
+{
+    m_action = action;
+}
+
+inline void Edge::setBorder(ElectricBorder border)
+{
+    m_border = border;
+}
+
+inline ScreenEdge *Edge::edges()
+{
+    return m_edges;
+}
+
+inline const ScreenEdge *Edge::edges() const
+{
+    return m_edges;
+}
+
+inline const QRect &Edge::geometry() const
+{
+    return m_geometry;
+}
+
+inline ElectricBorder Edge::border() const
+{
+    return m_border;
+}
+
+inline const QHash<QObject *, QByteArray> &Edge::callBacks() const
+{
+    return m_callBacks;
+}
+
+inline bool Edge::isBlocked() const
+{
+    return m_blocked;
+}
+
+
+/**********************************************************
+ * Inlines WindowBasedEdge
+ *********************************************************/
+
+inline Window KWin::WindowBasedEdge::window() const
+{
+    return m_window;
+}
+
+
+/**********************************************************
+ * Inlines ScreenEdges
+ *********************************************************/
+
+inline void ScreenEdge::setConfig(KSharedConfig::Ptr config)
+{
+    m_config = config;
+}
+
+inline int ScreenEdge::cornerOffset() const
+{
+    return m_cornerOffset;
+}
+
+inline const QSize &ScreenEdge::cursorPushBackDistance() const
+{
+    return m_cursorPushBackDistance;
+}
+
+inline bool ScreenEdge::isDesktopSwitching() const
+{
+    return m_desktopSwitching;
+}
+
+inline bool ScreenEdge::isDesktopSwitchingMovingClients() const
+{
+    return m_desktopSwitchingMovingClients;
+}
+
+inline int ScreenEdge::reActivationThreshold() const
+{
+    return m_reactivateThreshold;
+}
+
+inline int ScreenEdge::timeThreshold() const
+{
+    return m_timeThreshold;
+}
+
+inline void ScreenEdge::setCursorPushBackDistance(const QSize &distance)
+{
+    m_cursorPushBackDistance = distance;
+}
+
+inline void ScreenEdge::setDesktopSwitching(bool enable)
+{
+    if (enable == m_desktopSwitching) {
+        return;
+    }
+    m_desktopSwitching = enable;
+    reserveDesktopSwitching(enable, m_virtualDesktopLayout);
+}
+
+inline void ScreenEdge::setDesktopSwitchingMovingClients(bool enable)
+{
+    m_desktopSwitchingMovingClients = enable;
+}
+
+inline void ScreenEdge::setReActivationThreshold(int treshold)
+{
+    m_reactivateThreshold = treshold;
+}
+
+inline void ScreenEdge::setTimeThreshold(int treshold)
+{
+    m_timeThreshold = treshold;
+}
+
+#define ACTION( name) \
+inline ElectricBorderAction ScreenEdge::name() const \
+{ \
+    return m_##name; \
+}
+
+ACTION(actionTopLeft)
+ACTION(actionTop)
+ACTION(actionTopRight)
+ACTION(actionRight)
+ACTION(actionBottomRight)
+ACTION(actionBottom)
+ACTION(actionBottomLeft)
+ACTION(actionLeft)
+
+#undef ACTION
+
+} // namespace
+
 #endif // KWIN_SCREENEDGE_H
+
diff --git a/kwin/scripting/scriptedeffect.cpp b/kwin/scripting/scriptedeffect.cpp
index e9c0509..a651556 100644
--- a/kwin/scripting/scriptedeffect.cpp
+++ b/kwin/scripting/scriptedeffect.cpp
@@ -269,20 +269,10 @@ ScriptedEffect::ScriptedEffect()
     , m_scriptFile(QString())
 {
     connect(m_engine, SIGNAL(signalHandlerException(QScriptValue)), SLOT(signalHandlerException(QScriptValue)));
-#ifdef KWIN_BUILD_SCREENEDGES
-    connect(Workspace::self()->screenEdge(), SIGNAL(activated(ElectricBorder)), SLOT(slotBorderActivated(ElectricBorder)));
-#endif
 }
 
 ScriptedEffect::~ScriptedEffect()
 {
-#ifdef KWIN_BUILD_SCREENEDGES
-    for (QHash<int, QList<QScriptValue> >::const_iterator it = m_screenEdgeCallbacks.constBegin();
-            it != m_screenEdgeCallbacks.constEnd();
-            ++it) {
-        KWin::Workspace::self()->screenEdge()->unreserve(static_cast<KWin::ElectricBorder>(it.key()));
-    }
-#endif
 }
 
 bool ScriptedEffect::init(const QString &effectName, const QString &pathToScript)
diff --git a/kwin/scripting/scripting.cpp b/kwin/scripting/scripting.cpp
index 16a696c..59f2b43 100644
--- a/kwin/scripting/scripting.cpp
+++ b/kwin/scripting/scripting.cpp
@@ -215,20 +215,10 @@ KWin::AbstractScript::AbstractScript(int id, QString scriptName, QString pluginN
     if (m_pluginName.isNull()) {
         m_pluginName = scriptName;
     }
-#ifdef KWIN_BUILD_SCREENEDGES
-    connect(KWin::Workspace::self()->screenEdge(), SIGNAL(activated(ElectricBorder)), SLOT(borderActivated(ElectricBorder)));
-#endif
 }
 
 KWin::AbstractScript::~AbstractScript()
 {
-#ifdef KWIN_BUILD_SCREENEDGES
-    for (QHash<int, QList<QScriptValue> >::const_iterator it = m_screenEdgeCallbacks.constBegin();
-            it != m_screenEdgeCallbacks.constEnd();
-            ++it) {
-        KWin::Workspace::self()->screenEdge()->unreserve(static_cast<KWin::ElectricBorder>(it.key()));
-    }
-#endif
 }
 
 KConfigGroup KWin::AbstractScript::config() const
diff --git a/kwin/scripting/scriptingutils.h b/kwin/scripting/scriptingutils.h
index 3ed7845..5d68ad7 100644
--- a/kwin/scripting/scriptingutils.h
+++ b/kwin/scripting/scriptingutils.h
@@ -159,7 +159,7 @@ QScriptValue registerScreenEdge(QScriptContext *context, QScriptEngine *engine)
     if (it == script->screenEdgeCallbacks().end()) {
         // not yet registered
 #ifdef KWIN_BUILD_SCREENEDGES
-        KWin::Workspace::self()->screenEdge()->reserve(static_cast<KWin::ElectricBorder>(edge));
+        KWin::Workspace::self()->screenEdge()->reserve(static_cast<KWin::ElectricBorder>(edge), script, "borderActivated");
 #endif
         script->screenEdgeCallbacks().insert(edge, QList<QScriptValue>() << context->argument(1));
     } else {
diff --git a/kwin/workspace.cpp b/kwin/workspace.cpp
index dccc41f..343eed3 100644
--- a/kwin/workspace.cpp
+++ b/kwin/workspace.cpp
@@ -270,7 +270,9 @@ void Workspace::screenChangeTimeout()
 void Workspace::init()
 {
 #ifdef KWIN_BUILD_SCREENEDGES
+    m_screenEdge.setConfig(KGlobal::config());
     m_screenEdge.init();
+    connect(options, SIGNAL(configChanged()), &m_screenEdge, SLOT(reconfigure()));
 #endif
 
     // Not used yet
@@ -1008,12 +1010,6 @@ void Workspace::slotReconfigure()
     kDebug(1212) << "Workspace::slotReconfigure()";
     reconfigureTimer.stop();
 
-#ifdef KWIN_BUILD_SCREENEDGES
-    m_screenEdge.reserveActions(false);
-    if (options->electricBorders() == Options::ElectricAlways)
-        m_screenEdge.reserveDesktopSwitching(false, m_screenEdgeOrientation);
-#endif
-
     bool borderlessMaximizedWindows = options->borderlessMaximizedWindows();
 
     KGlobal::config()->reparseConfiguration();
@@ -1046,19 +1042,6 @@ void Workspace::slotReconfigure()
             c->triggerDecorationRepaint();
     }
 
-#ifdef KWIN_BUILD_SCREENEDGES
-    m_screenEdge.reserveActions(true);
-    if (options->electricBorders() == Options::ElectricAlways) {
-        QSize desktopMatrix = rootInfo->desktopLayoutColumnsRows();
-        m_screenEdgeOrientation = 0;
-        if (desktopMatrix.width() > 1)
-            m_screenEdgeOrientation |= Qt::Horizontal;
-        if (desktopMatrix.height() > 1)
-            m_screenEdgeOrientation |= Qt::Vertical;
-        m_screenEdge.reserveDesktopSwitching(true, m_screenEdgeOrientation);
-    }
-    m_screenEdge.update();
-#endif
     loadWindowRules();
     for (ClientList::Iterator it = clients.begin();
             it != clients.end();