Commit a4a94776 authored by Martin Flöser's avatar Martin Flöser
Browse files

Rewrite of KWin's Screen Edge Handling

This rewrite is mostly motivated by the need to handle multi screen
setups correctly. That is have edges per screen and not for the combined
geometry. Also porting from XLib to XCB has been a motivation for the
rewrite.

The design of the new ScreenEdge handling is described in the
documentation of ScreenEdges in screenedge.h.

In addition the following changes have been performed:
* move configuration from Options to ScreenEdge
* add screen edge information to Workspace::supportInformation (obviously
  replaces what had been read from Options)
* have Workspace hold a pointer to ScreenEdges instead of an object
* forward declaration of ScreenEdges in workspaces.h, this explains the
  seemingly unrelated changes of just another include in some files

BUG: 290887
FIXED-IN: 4.11
parent 78364ac0
......@@ -31,6 +31,9 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#ifdef KWIN_BUILD_TABBOX
#include "tabbox.h"
#endif
#ifdef KWIN_BUILD_SCREENEDGES
#include "screenedge.h"
#endif
#ifdef KWIN_BUILD_SCRIPTING
#include "scripting/scriptedeffect.h"
#endif
......
......@@ -39,6 +39,9 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "unmanaged.h"
#include "useractions.h"
#include "effects.h"
#ifdef KWIN_BUILD_SCREENEDGES
#include "screenedge.h"
#endif
#include "xcbutils.h"
#include <QWhatsThis>
......@@ -383,7 +386,7 @@ bool Workspace::workspaceEvent(XEvent * e)
QWhatsThis::leaveWhatsThisMode();
}
#ifdef KWIN_BUILD_SCREENEDGES
if (m_screenEdge.isEntered(e))
if (m_screenEdge->isEntered(e))
return true;
#endif
break;
......@@ -437,7 +440,7 @@ bool Workspace::workspaceEvent(XEvent * e)
return true; // always eat these, they would tell Qt that KWin is the active app
case ClientMessage:
#ifdef KWIN_BUILD_SCREENEDGES
if (m_screenEdge.isEntered(e))
if (m_screenEdge->isEntered(e))
return true;
#endif
break;
......
......@@ -40,6 +40,9 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "geometrytip.h"
#include "rules.h"
#include "effects.h"
#ifdef KWIN_BUILD_SCREENEDGES
#include "screenedge.h"
#endif
#include <QtGui/QDesktopWidget>
#include <QPainter>
#include <QVarLengthArray>
......@@ -76,9 +79,12 @@ void Workspace::desktopResized()
updateClientArea();
saveOldScreenSizes(); // after updateClientArea(), so that one still uses the previous one
// TODO: emit a signal instead and remove the deep function calls into edges and effects
#ifdef KWIN_BUILD_SCREENEDGES
m_screenEdge.update(true);
m_screenEdge->recreateEdges();
#endif
if (effects) {
static_cast<EffectsHandlerImpl*>(effects)->desktopResized(geom.size());
}
......@@ -2574,7 +2580,7 @@ bool Client::startMoveResize()
Notify::raise(isResize() ? Notify::ResizeStart : Notify::MoveStart);
emit clientStartUserMovedResized(this);
#ifdef KWIN_BUILD_SCREENEDGES
if (options->electricBorders() == Options::ElectricMoveOnly)
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!!
......@@ -2656,7 +2662,7 @@ void Client::leaveMoveResize()
syncRequest.timeout = NULL;
#endif
#ifdef KWIN_BUILD_SCREENEDGES
if (options->electricBorders() == Options::ElectricMoveOnly)
if (workspace()->screenEdge()->isDesktopSwitchingMovingClients())
workspace()->screenEdge()->reserveDesktopSwitching(false, Qt::Vertical|Qt::Horizontal);
#endif
}
......@@ -3023,7 +3029,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
}
}
......
......@@ -87,6 +87,9 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "effects.h"
#include <QX11Info>
#include "composite.h"
#ifdef KWIN_BUILD_SCREENEDGES
#include "screenedge.h"
#endif
namespace KWin
{
......@@ -160,7 +163,7 @@ void Workspace::propagateClients(bool propagate_new_clients)
// windows (e.g. popups).
newWindowStack << (Window*)supportWindow->winId();
#ifdef KWIN_BUILD_SCREENEDGES
QVectorIterator<Window> it(m_screenEdge.windows());
QVectorIterator<xcb_window_t> it(m_screenEdge->windows());
while (it.hasNext()) {
if ((Window)it.next() != None) {
newWindowStack << (Window*)&it;
......
......@@ -176,18 +176,6 @@ Options::Options(QObject *parent)
, CmdAll3(Options::defaultCommandAll3())
, CmdAllWheel(Options::defaultCommandAllWheel())
, CmdAllModKey(Options::defaultKeyCmdAllModKey())
, electric_border_top(Options::defaultElectricBorderTop())
, electric_border_top_right(Options::defaultElectricBorderTopRight())
, electric_border_right(Options::defaultElectricBorderRight())
, electric_border_bottom_right(Options::defaultElectricBorderBottomRight())
, electric_border_bottom(Options::defaultElectricBorderBottom())
, electric_border_bottom_left(Options::defaultElectricBorderBottomLeft())
, electric_border_left(Options::defaultElectricBorderLeft())
, electric_border_top_left(Options::defaultElectricBorderTopLeft())
, electric_borders(Options::defaultElectricBorders())
, electric_border_delay(Options::defaultElectricBorderDelay())
, electric_border_cooldown(Options::defaultElectricBorderCooldown())
, electric_border_pushback_pixels(Options::defaultElectricBorderPushbackPixels())
, electric_border_maximize(Options::defaultElectricBorderMaximize())
, electric_border_tiling(Options::defaultElectricBorderTiling())
, electric_border_corner_ratio(Options::defaultElectricBorderCornerRatio())
......@@ -551,33 +539,6 @@ void Options::setCondensedTitle(bool condensedTitle)
emit condensedTitleChanged();
}
void Options::setElectricBorderDelay(int electricBorderDelay)
{
if (electric_border_delay == electricBorderDelay) {
return;
}
electric_border_delay = electricBorderDelay;
emit electricBorderDelayChanged();
}
void Options::setElectricBorderCooldown(int electricBorderCooldown)
{
if (electric_border_cooldown == electricBorderCooldown) {
return;
}
electric_border_cooldown = electricBorderCooldown;
emit electricBorderCooldownChanged();
}
void Options::setElectricBorderPushbackPixels(int electricBorderPushbackPixels)
{
if (electric_border_pushback_pixels == electricBorderPushbackPixels) {
return;
}
electric_border_pushback_pixels = electricBorderPushbackPixels;
emit electricBorderPushbackPixelsChanged();
}
void Options::setElectricBorderMaximize(bool electricBorderMaximize)
{
if (electric_border_maximize == electricBorderMaximize) {
......@@ -803,15 +764,6 @@ void Options::setGlLegacy(bool glLegacy)
emit glLegacyChanged();
}
void Options::setElectricBorders(int borders)
{
if (electric_borders == borders) {
return;
}
electric_borders = borders;
emit electricBordersChanged();
}
void Options::reparseConfiguration()
{
KGlobal::config()->reparseConfiguration();
......@@ -893,20 +845,6 @@ unsigned long Options::loadConfig()
setSnapOnlyWhenOverlapping(config.readEntry("SnapOnlyWhenOverlapping", Options::defaultSnapOnlyWhenOverlapping()));
// Electric borders
KConfigGroup borderConfig(_config, "ElectricBorders");
// TODO: add setters
electric_border_top = electricBorderAction(borderConfig.readEntry("Top", "None"));
electric_border_top_right = electricBorderAction(borderConfig.readEntry("TopRight", "None"));
electric_border_right = electricBorderAction(borderConfig.readEntry("Right", "None"));
electric_border_bottom_right = electricBorderAction(borderConfig.readEntry("BottomRight", "None"));
electric_border_bottom = electricBorderAction(borderConfig.readEntry("Bottom", "None"));
electric_border_bottom_left = electricBorderAction(borderConfig.readEntry("BottomLeft", "None"));
electric_border_left = electricBorderAction(borderConfig.readEntry("Left", "None"));
electric_border_top_left = electricBorderAction(borderConfig.readEntry("TopLeft", "None"));
setElectricBorders(config.readEntry("ElectricBorders", Options::defaultElectricBorders()));
setElectricBorderDelay(config.readEntry("ElectricBorderDelay", Options::defaultElectricBorderDelay()));
setElectricBorderCooldown(config.readEntry("ElectricBorderCooldown", Options::defaultElectricBorderCooldown()));
setElectricBorderPushbackPixels(config.readEntry("ElectricBorderPushbackPixels", Options::defaultElectricBorderPushbackPixels()));
setElectricBorderMaximize(config.readEntry("ElectricBorderMaximize", Options::defaultElectricBorderMaximize()));
setElectricBorderTiling(config.readEntry("ElectricBorderTiling", Options::defaultElectricBorderTiling()));
const float ebr = config.readEntry("ElectricBorderCornerRatio", Options::defaultElectricBorderCornerRatio());
......@@ -1052,17 +990,6 @@ void Options::reloadCompositingSettings(bool force)
animationSpeed = qBound(0, config.readEntry("AnimationSpeed", Options::defaultAnimationSpeed()), 6);
}
ElectricBorderAction Options::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;
}
// restricted should be true for operations that the user may not be able to repeat
// if the window is moved out of the workspace (e.g. if the user moves a window
// by the titlebar, and moves it too high beneath Kicker at the top edge, they
......@@ -1147,47 +1074,6 @@ bool Options::condensedTitle() const
return condensed_title;
}
ElectricBorderAction Options::electricBorderAction(ElectricBorder edge) const
{
switch(edge) {
case ElectricTop:
return electric_border_top;
case ElectricTopRight:
return electric_border_top_right;
case ElectricRight:
return electric_border_right;
case ElectricBottomRight:
return electric_border_bottom_right;
case ElectricBottom:
return electric_border_bottom;
case ElectricBottomLeft:
return electric_border_bottom_left;
case ElectricLeft:
return electric_border_left;
case ElectricTopLeft:
return electric_border_top_left;
default:
// fallthrough
break;
}
return ElectricActionNone;
}
int Options::electricBorders() const
{
return electric_borders;
}
int Options::electricBorderDelay() const
{
return electric_border_delay;
}
int Options::electricBorderCooldown() const
{
return electric_border_cooldown;
}
Options::MouseCommand Options::wheelToMouseCommand(MouseWheelCommand com, int delta) const
{
switch(com) {
......
......@@ -134,24 +134,6 @@ class Options : public QObject, public KDecorationOptions
*/
Q_PROPERTY(bool condensedTitle READ condensedTitle WRITE setCondensedTitle NOTIFY condensedTitleChanged)
/**
* Whether electric borders are enabled. With electric borders
* you can change desktop by moving the mouse pointer towards the edge
* of the screen
*/
Q_PROPERTY(bool electricBorders READ electricBorders NOTIFY electricBordersChanged)
/**
* the activation delay for electric borders in milliseconds.
*/
Q_PROPERTY(int electricBorderDelay READ electricBorderDelay WRITE setElectricBorderDelay NOTIFY electricBorderDelayChanged)
/**
* the trigger cooldown for electric borders in milliseconds.
*/
Q_PROPERTY(int electricBorderCooldown READ electricBorderCooldown WRITE setElectricBorderCooldown NOTIFY electricBorderCooldownChanged)
/**
* the number of pixels the mouse cursor is pushed back when it reaches the screen edge.
*/
Q_PROPERTY(int electricBorderPushbackPixels READ electricBorderPushbackPixels WRITE setElectricBorderPushbackPixels NOTIFY electricBorderPushbackPixelsChanged)
/**
* Whether a window gets maximized when it reaches top screen edge while being moved.
*/
Q_PROPERTY(bool electricBorderMaximize READ electricBorderMaximize WRITE setElectricBorderMaximize NOTIFY electricBorderMaximizeChanged)
......@@ -439,7 +421,6 @@ public:
return CmdAllModKey;
}
static ElectricBorderAction electricBorderAction(const QString& name);
static WindowOperation windowOperation(const QString &name, bool restricted);
static MouseCommand mouseCommand(const QString &name, bool restricted);
static MouseWheelCommand mouseWheelCommand(const QString &name);
......@@ -454,32 +435,6 @@ public:
*/
bool condensedTitle() const;
enum { ElectricDisabled = 0, ElectricMoveOnly = 1, ElectricAlways = 2 };
/**
* @returns The action assigned to the specified electric border
*/
ElectricBorderAction electricBorderAction(ElectricBorder edge) const;
/**
* @returns true if electric borders are enabled. With electric borders
* you can change desktop by moving the mouse pointer towards the edge
* of the screen
*/
int electricBorders() const;
/**
* @returns the activation delay for electric borders in milliseconds.
*/
int electricBorderDelay() const;
/**
* @returns the trigger cooldown for electric borders in milliseconds.
*/
int electricBorderCooldown() const;
/**
* @returns the number of pixels the mouse cursor is pushed back when it
* reaches the screen edge.
*/
int electricBorderPushbackPixels() const {
return electric_border_pushback_pixels;
}
/**
* @returns true if a window gets maximized when it reaches top screen edge
* while being moved.
......@@ -630,9 +585,6 @@ public:
void setKeyCmdAllModKey(uint keyCmdAllModKey);
void setShowGeometryTip(bool showGeometryTip);
void setCondensedTitle(bool condensedTitle);
void setElectricBorderDelay(int electricBorderDelay);
void setElectricBorderCooldown(int electricBorderCooldown);
void setElectricBorderPushbackPixels(int electricBorderPushbackPixels);
void setElectricBorderMaximize(bool electricBorderMaximize);
void setElectricBorderTiling(bool electricBorderTiling);
void setElectricBorderCornerRatio(float electricBorderCornerRatio);
......@@ -774,42 +726,6 @@ public:
static bool defaultCondensedTitle() {
return false;
}
static ElectricBorderAction defaultElectricBorderTop() {
return ElectricActionNone;
}
static ElectricBorderAction defaultElectricBorderTopRight() {
return ElectricActionNone;
}
static ElectricBorderAction defaultElectricBorderRight() {
return ElectricActionNone;
}
static ElectricBorderAction defaultElectricBorderBottomRight() {
return ElectricActionNone;
}
static ElectricBorderAction defaultElectricBorderBottom() {
return ElectricActionNone;
}
static ElectricBorderAction defaultElectricBorderBottomLeft() {
return ElectricActionNone;
}
static ElectricBorderAction defaultElectricBorderLeft() {
return ElectricActionNone;
}
static ElectricBorderAction defaultElectricBorderTopLeft() {
return ElectricActionNone;
}
static int defaultElectricBorders() {
return 0;
}
static int defaultElectricBorderDelay() {
return 150;
}
static int defaultElectricBorderCooldown() {
return 350;
}
static int defaultElectricBorderPushbackPixels() {
return 1;
}
static bool defaultElectricBorderMaximize() {
return true;
}
......@@ -943,10 +859,6 @@ Q_SIGNALS:
void keyCmdAllModKeyChanged();
void showGeometryTipChanged();
void condensedTitleChanged();
void electricBordersChanged();
void electricBorderDelayChanged();
void electricBorderCooldownChanged();
void electricBorderPushbackPixelsChanged();
void electricBorderMaximizeChanged();
void electricBorderTilingChanged();
void electricBorderCornerRatioChanged();
......@@ -1041,18 +953,6 @@ private:
MouseWheelCommand CmdAllWheel;
uint CmdAllModKey;
ElectricBorderAction electric_border_top;
ElectricBorderAction electric_border_top_right;
ElectricBorderAction electric_border_right;
ElectricBorderAction electric_border_bottom_right;
ElectricBorderAction electric_border_bottom;
ElectricBorderAction electric_border_bottom_left;
ElectricBorderAction electric_border_left;
ElectricBorderAction electric_border_top_left;
int electric_borders;
int electric_border_delay;
int electric_border_cooldown;
int electric_border_pushback_pixels;
bool electric_border_maximize;
bool electric_border_tiling;
float electric_border_corner_ratio;
......
This diff is collapsed.
......@@ -3,6 +3,7 @@
This file is part of the KDE project.
Copyright (C) 2011 Arthur Arlt <a.arlt@stud.uni-heidelberg.de>
Copyright (C) 2013 Martin Gräßlin <mgraesslin@kde.org>
Since the functionality provided in this class has been moved from
class Workspace, it is not clear who exactly has written the code.
......@@ -28,29 +29,162 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#ifndef KWIN_SCREENEDGE_H
#define KWIN_SCREENEDGE_H
// KWin
#include "kwinglobals.h"
// KDE includes
#include <KDE/KConfig>
// Qt
#include <QtCore/QObject>
#include <QtCore/QVector>
#include "kwinglobals.h"
#include <QDateTime>
namespace KWin {
class ScreenEdges;
class Edge : public QObject
{
Q_OBJECT
public:
explicit Edge(ScreenEdges *parent);
virtual ~Edge();
bool isLeft() const;
bool isTop() const;
bool isRight() const;
bool isBottom() const;
bool isCorner() const;
bool isScreenEdge() const;
bool triggersFor(const QPoint &cursorPos) const;
void check(const QPoint &cursorPos, const QDateTime &triggerTime, bool forceNoPushBack = false);
bool isReserved() const;
ElectricBorder border() const;
public Q_SLOTS:
void reserve();
void unreserve();
void setBorder(ElectricBorder border);
void setAction(ElectricBorderAction action);
void setGeometry(const QRect &geometry);
Q_SIGNALS:
/**
* Emitted when the @p border got activated and there is neither an effect nor a global
* action configured for this @p border.
* @param border The border which got activated
**/
void activated(ElectricBorder border);
protected:
ScreenEdges *edges();
const ScreenEdges *edges() const;
const QRect &geometry() const;
virtual void doGeometryUpdate();
virtual void activate();
virtual void deactivate();
private:
bool canActivate(const QPoint &cursorPos, const QDateTime &triggerTime);
void handle(const QPoint &cursorPos);
bool handleAction();
bool handleByEffects();
void switchDesktop(const QPoint &cursorPos);
void pushCursorBack(const QPoint &cursorPos);
ScreenEdges *m_edges;
ElectricBorder m_border;
ElectricBorderAction m_action;
int m_reserved;
QRect m_geometry;
QDateTime m_lastTrigger;
QDateTime m_lastReset;
QPoint m_triggeredPoint;
};
class WindowBasedEdge : public Edge
{
Q_OBJECT
public:
explicit WindowBasedEdge(ScreenEdges *parent);
virtual ~WindowBasedEdge();
xcb_window_t window() const;
protected:
virtual void doGeometryUpdate();
virtual void activate();
virtual void deactivate();
private:
void destroyWindow();
void createWindow();
xcb_window_t 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
* desktop or activate other features by moving the mouse pointer to the borders or
* corners of the screen. Technically this is done with input only windows.
* @short Class for controlling screen edges.
*
* The screen edge functionality is split into three parts:
* @li This manager class ScreenEdges
* @li abstract class @link Edge
* @li specific implementation of @link Edge, e.g. @link WindowBasedEdge
*
* @author Arthur Arlt
* @since 4.8
* The ScreenEdges creates an @link Edge for each screen edge which is also an edge in the
* combination of all screens. E.g. if there are two screens, no Edge is created between the screens,
* but at all other edges even if the screens have a different dimension.
*
* In addition at each corner of the overall display geometry an one-pixel large @link Edge is
* created. No matter how many screens there are, there will only be exactly four of these corner
* edges. This is motivated by Fitts's Law which show that it's easy to trigger such a corner, but
* it would be very difficult to trigger a corner between two screens (one pixel target not visually
* outlined).
*
* The ScreenEdges are used for one of the following functionality:
* @li switch virtual desktop (see property @link desktopSwitching)
* @li switch virtual desktop when moving a window (see property @link desktopSwitchingMovingClients)
* @li trigger a pre-defined action (see properties @link actionTop and similar)
* @li trigger an externally configured action (e.g. Effect, Script, see @link reserve, @link unreserve)
*
* An @link Edge is only active if there is at least one of the possible actions "reserved" for this
* edge. The idea is to not block the screen edge if nothing could be triggered there, so that the
* user e.g. can configure nothing on the top edge, which tends to interfere with full screen apps
* having a hidden panel there. On X11 (currently only supported backend) the @link Edge is
* represented by a @link WindowBasedEdge which creates an input only window for the geometry and
* reacts on enter notify events. If the edge gets reserved for the first time a window is created
* and mapped, once the edge gets unreserved again, the window gets destroyed.
*
* When the mouse enters one of the screen edges the following values are used to determine whether
* the action should be triggered or the cursor be pushed back
* @li Time difference between two entering events is not larger than a certain threshold
* @li Time difference between two entering events is larger than @link timeThreshold
* @li Time difference between two activations is larger than @link reActivateThreshold
* @li Distance between two enter events is not larger than a defined pixel distance
* These checks are performed in @link Edge
*
* @todo change way how Effects/Scripts can reserve an edge and are notified.
*/
class ScreenEdge : public QObject {
class ScreenEdges : public QObject
{
Q_OBJECT
Q_PROPERTY(bool desktopSwitching READ isDesktopSwitching)
Q_PROPERTY(bool desktopSwitchingMovingClients READ isDesktopSwitchingMovingClients)
Q_PROPERTY(QSize cursorPushBackDistance READ cursorPushBackDistance)
Q_PROPERTY(int timeThreshold READ timeThreshold)
Q_PROPERTY(int reActivateThreshold READ reActivationThreshold)
Q_PROPERTY(int actionTopLeft READ actionTopLeft)
Q_PROPERTY(int actionTop READ actionTop)
Q_PROPERTY(int actionTopRight READ actionTopRight)
Q_PROPERTY(int actionRight READ actionRight)
Q_PROPERTY(int actionBottomRight READ actionBottomRight)
Q_PROPERTY(int actionBottom READ actionBottom)
Q_PROPERTY(int actionBottomLeft READ actionBottomLeft)
Q_PROPERTY(int actionLeft READ actionLeft)
public:
ScreenEdge();
~ScreenEdge();
explicit ScreenEdges(QObject *parent = 0);
virtual ~ScreenEdges();
/**
* @internal
**/
void setConfig(KSharedConfig::Ptr config);
/**
* Initialize the screen edges.
* @internal
*/
void init();
/**
......@@ -60,29 +194,28 @@ 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
*/
void restoreSize(ElectricBorder border);
/**
* Mark the specified screen edge as reserved in m_screenEdgeReserved
* 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
* @see unreserve
* @todo: add pointer to script/effect
*/
void reserve(ElectricBorder border);
/**
* 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
* @see unreserve
* @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);
/**
* Reserve desktop switching for screen edges, if reserve is true. Unreserve otherwise.