diff --git a/effects.cpp b/effects.cpp
index 95f87a61d8..a37afc9774 100644
--- a/effects.cpp
+++ b/effects.cpp
@@ -31,6 +31,9 @@ along with this program. If not, see .
#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
diff --git a/events.cpp b/events.cpp
index a39aec07fc..b542f3c5bb 100644
--- a/events.cpp
+++ b/events.cpp
@@ -39,6 +39,9 @@ along with this program. If not, see .
#include "unmanaged.h"
#include "useractions.h"
#include "effects.h"
+#ifdef KWIN_BUILD_SCREENEDGES
+#include "screenedge.h"
+#endif
#include "xcbutils.h"
#include
@@ -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;
diff --git a/geometry.cpp b/geometry.cpp
index ae7ad26f22..b9c0728fde 100644
--- a/geometry.cpp
+++ b/geometry.cpp
@@ -40,6 +40,9 @@ along with this program. If not, see .
#include "geometrytip.h"
#include "rules.h"
#include "effects.h"
+#ifdef KWIN_BUILD_SCREENEDGES
+#include "screenedge.h"
+#endif
#include
#include
#include
@@ -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(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
}
}
diff --git a/layers.cpp b/layers.cpp
index 8d6bf41601..1dab283484 100644
--- a/layers.cpp
+++ b/layers.cpp
@@ -87,6 +87,9 @@ along with this program. If not, see .
#include "effects.h"
#include
#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 it(m_screenEdge.windows());
+ QVectorIterator it(m_screenEdge->windows());
while (it.hasNext()) {
if ((Window)it.next() != None) {
newWindowStack << (Window*)⁢
diff --git a/options.cpp b/options.cpp
index 41dda403ce..798460f2ac 100644
--- a/options.cpp
+++ b/options.cpp
@@ -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) {
diff --git a/options.h b/options.h
index f458637b7f..f910f55b22 100644
--- a/options.h
+++ b/options.h
@@ -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;
diff --git a/screenedge.cpp b/screenedge.cpp
index fb6209c199..9524ec26ab 100644
--- a/screenedge.cpp
+++ b/screenedge.cpp
@@ -3,6 +3,7 @@
This file is part of the KDE project.
Copyright (C) 2011 Arthur Arlt
+Copyright (C) 2013 Martin Gräßlin
Since the functionality provided in this class has been moved from
class Workspace, it is not clear who exactly has written the code.
@@ -32,131 +33,414 @@ along with this program. If not, see .
#include "atoms.h"
#include "client.h"
#include "effects.h"
-#include "options.h"
#include "utils.h"
#include "workspace.h"
#include "virtualdesktops.h"
-
+#include "xcbutils.h"
// Qt
#include
#include
#include
#include
+#include
+#include
namespace KWin {
-ScreenEdge::ScreenEdge()
- : QObject(NULL)
- , m_screenEdgeWindows(ELECTRIC_COUNT, None)
- , m_screenEdgeReserved(ELECTRIC_COUNT, 0)
- , m_virtualDesktopSwitching(Options::ElectricDisabled)
- , m_virtualDesktopLayout(0)
+// Reset timeout
+static const int TRESHOLD_RESET = 250;
+// Mouse should not move more than this many pixels
+static const int DISTANCE_RESET = 30;
+
+Edge::Edge(ScreenEdges *parent)
+ : QObject(parent)
+ , m_edges(parent)
+ , m_border(ElectricNone)
+ , m_action(ElectricActionNone)
+ , m_reserved(0)
{
}
-ScreenEdge::~ScreenEdge()
+Edge::~Edge()
{
}
-void ScreenEdge::init()
+void Edge::reserve()
{
- reserveActions(true);
- update();
-}
-
-void ScreenEdge::update(bool force)
-{
- 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 (m_screenEdgeReserved[pos] == 0) {
- continue;
- }
- if (m_screenEdgeWindows[pos] != None)
- 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);
+ m_reserved++;
+ if (m_reserved == 1) {
+ // got activated
+ activate();
}
}
-void ScreenEdge::restoreSize(ElectricBorder border)
+void Edge::unreserve()
{
- if (m_screenEdgeWindows[border] == None)
+ m_reserved--;
+ if (m_reserved == 0) {
+ // got deactivated
+ deactivate();
+ }
+}
+
+bool Edge::triggersFor(const QPoint &cursorPos) const
+{
+ 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;
- 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 }
+ }
+ // 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 = triggerTime;
+ handle(cursorPos);
+ } else {
+ pushCursorBack(cursorPos);
+ }
+ m_triggeredPoint = cursorPos;
+}
+
+bool Edge::canActivate(const QPoint &cursorPos, const QDateTime &triggerTime)
+{
+ if (m_lastReset.msecsTo(triggerTime) > TRESHOLD_RESET) {
+ 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 desktops 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 (handleAction() || handleByEffects()) {
+ pushCursorBack(cursorPos);
+ return;
+ }
+ if (edges()->isDesktopSwitching() && isCorner()) {
+ // try again desktop switching for the corner
+ switchDesktop(cursorPos);
+ return;
+ }
+ // fallback notify world that edge got activated
+ emit activated(m_border);
+}
+
+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::handleByEffects()
+{
+ if (!effects) {
+ return false;
+ }
+ return static_cast(effects)->borderActivated(m_border);
+}
+
+void Edge::switchDesktop(const QPoint &cursorPos)
+{
+ QPoint pos(cursorPos);
+ VirtualDesktopManager *vds = VirtualDesktopManager::self();
+ uint desktop = vds->current();
+ const uint oldDesktop = vds->current();
+ const int OFFSET = 2;
+ if (isLeft()) {
+ desktop = vds->toLeft(desktop, vds->isNavigationWrappingAround());
+ pos.setX(displayWidth() - 1 - OFFSET);
+ }
+ if (isRight()) {
+ desktop = vds->toRight(desktop, vds->isNavigationWrappingAround());
+ pos.setX(OFFSET);
+ }
+ if (isTop()) {
+ desktop = vds->above(desktop, vds->isNavigationWrappingAround());
+ pos.setY(displayHeight() - 1 - OFFSET);
+ }
+ if (isBottom()) {
+ desktop = vds->below(desktop, vds->isNavigationWrappingAround());
+ 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;
+ }
+ }
+ vds->setCurrent(desktop);
+ if (vds->current() != 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::doGeometryUpdate()
+{
+}
+
+void Edge::activate()
+{
+}
+
+void Edge::deactivate()
+{
+}
+
+/**********************************************************
+ * ScreenEdges
+ *********************************************************/
+WindowBasedEdge::WindowBasedEdge(ScreenEdges *parent)
+ : Edge(parent)
+ , m_window(XCB_WINDOW_NONE)
+{
+}
+
+WindowBasedEdge::~WindowBasedEdge()
+{
+ destroyWindow();
+}
+
+void WindowBasedEdge::activate()
+{
+ createWindow();
+}
+
+void WindowBasedEdge::deactivate()
+{
+ destroyWindow();
+}
+
+void WindowBasedEdge::createWindow()
+{
+ if (m_window != XCB_WINDOW_NONE) {
+ return;
+ }
+ const uint32_t mask = XCB_CW_OVERRIDE_REDIRECT | XCB_CW_EVENT_MASK;
+ const uint32_t values[] = {
+ true,
+ XCB_EVENT_MASK_ENTER_WINDOW | XCB_EVENT_MASK_LEAVE_WINDOW
};
- XMoveResizeWindow(display(), m_screenEdgeWindows[border],
- xywh[border][0], xywh[border][1], xywh[border][2], xywh[border][3]);
+ m_window = Xcb::createInputWindow(geometry(), mask, values);
+ xcb_map_window(connection(), m_window);
+ // Set XdndAware on the windows, so that DND enter events are received (#86998)
+ xcb_atom_t version = 4; // XDND version
+ xcb_change_property(connection(), XCB_PROP_MODE_REPLACE, m_window,
+ atoms->xdnd_aware, XCB_ATOM_ATOM, 32, 1, (unsigned char*)(&version));
}
-void ScreenEdge::reconfigureVirtualDesktopSwitching()
+void WindowBasedEdge::destroyWindow()
{
- const int newMode = options->electricBorders();
- if (m_virtualDesktopSwitching == newMode) {
+ if (m_window != XCB_WINDOW_NONE) {
+ xcb_destroy_window(connection(), m_window);
+ m_window = XCB_WINDOW_NONE;
+ }
+}
+
+void WindowBasedEdge::doGeometryUpdate()
+{
+ Xcb::moveResizeWindow(m_window, geometry());
+}
+
+/**********************************************************
+ * ScreenEdges
+ *********************************************************/
+ScreenEdges::ScreenEdges(QObject *parent)
+ : QObject(parent)
+ , 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_externalReservations.insert(ElectricTopLeft, 0);
+ m_externalReservations.insert(ElectricTop, 0);
+ m_externalReservations.insert(ElectricTopRight, 0);
+ m_externalReservations.insert(ElectricRight, 0);
+ m_externalReservations.insert(ElectricBottomRight, 0);
+ m_externalReservations.insert(ElectricBottom, 0);
+ m_externalReservations.insert(ElectricBottomLeft, 0);
+ m_externalReservations.insert(ElectricLeft, 0);
+}
+
+ScreenEdges::~ScreenEdges()
+{
+}
+
+void ScreenEdges::init()
+{
+ 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 ScreenEdges::reconfigure()
+{
+ if (!m_config) {
return;
}
- if (m_virtualDesktopSwitching == Options::ElectricAlways) {
- reserveDesktopSwitching(false, m_virtualDesktopLayout);
+ // TODO: migrate settings to a group ScreenEdges
+ KConfigGroup windowsConfig = m_config->group("Windows");
+ setTimeThreshold(windowsConfig.readEntry("ElectricBorderDelay", 150));
+ setReActivationThreshold(windowsConfig.readEntry("ElectricBorderCooldown", 350));
+ int desktopSwitching = windowsConfig.readEntry("ElectricBorders", static_cast(ElectricDisabled));
+ if (desktopSwitching == ElectricDisabled) {
+ setDesktopSwitching(false);
+ setDesktopSwitchingMovingClients(false);
+ } else if (desktopSwitching == ElectricMoveOnly) {
+ setDesktopSwitching(false);
+ setDesktopSwitchingMovingClients(true);
+ } else if (desktopSwitching == ElectricAlways) {
+ setDesktopSwitching(true);
+ setDesktopSwitchingMovingClients(true);
}
- m_virtualDesktopSwitching = newMode;
- if (m_virtualDesktopSwitching == Options::ElectricAlways) {
- reserveDesktopSwitching(true, m_virtualDesktopLayout);
- }
- update();
+ 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::reconfigure()
+void ScreenEdges::setActionForBorder(ElectricBorder border, ElectricBorderAction *oldValue, ElectricBorderAction newValue)
{
- reserveActions(true);
- reconfigureVirtualDesktopSwitching();
- updateLayout();
- update();
+ if (*oldValue == newValue) {
+ return;
+ }
+ if (*oldValue == ElectricActionNone) {
+ // have to reserve
+ for (QList::iterator it = m_edges.begin(); it != m_edges.end(); ++it) {
+ if ((*it)->border() == border) {
+ (*it)->reserve();
+ }
+ }
+ }
+ if (newValue == ElectricActionNone) {
+ // have to unreserve
+ for (QList::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::iterator it = m_edges.begin(); it != m_edges.end(); ++it) {
+ if ((*it)->border() == border) {
+ (*it)->setAction(newValue);
+ }
+ }
}
-void ScreenEdge::updateLayout()
+void ScreenEdges::updateLayout()
{
const QSize desktopMatrix = VirtualDesktopManager::self()->grid().size();
Qt::Orientations newLayout = 0;
@@ -169,283 +453,332 @@ void ScreenEdge::updateLayout()
if (newLayout == m_virtualDesktopLayout) {
return;
}
- if (m_virtualDesktopSwitching == Options::ElectricAlways) {
+ if (isDesktopSwitching()) {
reserveDesktopSwitching(false, m_virtualDesktopLayout);
}
m_virtualDesktopLayout = newLayout;
- if (m_virtualDesktopSwitching == Options::ElectricAlways) {
+ if (isDesktopSwitching()) {
reserveDesktopSwitching(true, m_virtualDesktopLayout);
}
}
-void ScreenEdge::reserveActions(bool isToReserve)
+static bool isLeftScreen(const QRect &screen, const QRect &fullArea)
{
- for (int pos = 0; pos < ELECTRIC_COUNT; ++pos)
- if (options->electricBorderAction(static_cast(pos))) {
- if (isToReserve)
- reserve(static_cast(pos));
- else
- unreserve(static_cast(pos));
+ const QDesktopWidget *desktop = QApplication::desktop();
+ if (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; iscreenCount(); ++i) {
+ const QRect otherGeo = desktop->screenGeometry(i);
+ if (otherGeo == screen) {
+ // that's our screen to test
+ continue;
}
+ 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;
}
-void ScreenEdge::reserveDesktopSwitching(bool isToReserve, Qt::Orientations o)
+static bool isRightScreen(const QRect &screen, const QRect &fullArea)
+{
+ const QDesktopWidget *desktop = QApplication::desktop();
+ if (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 with a second screen
+ // more to the right. In that case no screen starts right of this screen
+ for (int i=0; iscreenCount(); ++i) {
+ const QRect otherGeo = desktop->screenGeometry(i);
+ if (otherGeo == screen) {
+ // that's our screen to test
+ continue;
+ }
+ 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;
+}
+
+static bool isTopScreen(const QRect &screen, const QRect &fullArea)
+{
+ const QDesktopWidget *desktop = QApplication::desktop();
+ if (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 coord
+ for (int i=0; iscreenCount(); ++i) {
+ const QRect otherGeo = desktop->screenGeometry(i);
+ if (otherGeo == screen) {
+ // that's our screen to test
+ continue;
+ }
+ if (otherGeo.y() + otherGeo.height() <= screen.y()) {
+ // other screen is completely above
+ return false;
+ }
+ }
+ // did not find a screen above our current screen, so it is the top most
+ return true;
+}
+
+static bool isBottomScreen(const QRect &screen, const QRect &fullArea)
+{
+ const QDesktopWidget *desktop = QApplication::desktop();
+ if (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; iscreenCount(); ++i) {
+ const QRect otherGeo = desktop->screenGeometry(i);
+ if (otherGeo == screen) {
+ // that's our screen to test
+ continue;
+ }
+ 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 ScreenEdges::recreateEdges()
+{
+ qDeleteAll(m_edges);
+ m_edges.clear();
+ const QRect fullArea(0, 0, displayWidth(), displayHeight());
+ const QDesktopWidget *desktop = QApplication::desktop();
+ for (int i=0; iscreenCount(); ++i) {
+ const QRect screen = desktop->screenGeometry(i);
+ if (isLeftScreen(screen, fullArea)) {
+ // left most screen
+ createVerticalEdge(ElectricLeft, screen, fullArea);
+ }
+ if (isRightScreen(screen, fullArea)) {
+ // right most screen
+ createVerticalEdge(ElectricRight, screen, fullArea);
+ }
+ if (isTopScreen(screen, fullArea)) {
+ // top most screen
+ createHorizontalEdge(ElectricTop, screen, fullArea);
+ }
+ if (isBottomScreen(screen, fullArea)) {
+ // bottom most screen
+ createHorizontalEdge(ElectricBottom, screen, fullArea);
+ }
+ }
+}
+
+void ScreenEdges::createVerticalEdge(ElectricBorder border, const QRect &screen, const QRect &fullArea)
+{
+ if (border != ElectricRight && border != KWin::ElectricLeft) {
+ return;
+ }
+ int y = screen.y();
+ int height = screen.height();
+ const int x = (border == ElectricLeft) ? screen.x() : screen.x() + screen.width() -1;
+ if (isTopScreen(screen, fullArea)) {
+ // also top most screen
+ height--;
+ y++;
+ // 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
+ height--;
+ // create bottom left/right edge
+ const ElectricBorder edge = (border == ElectricLeft) ? ElectricBottomLeft : ElectricBottomRight;
+ m_edges << createEdge(edge, x, screen.y() + screen.height() -1, 1, 1);
+ }
+ // create border
+ m_edges << createEdge(border, x, y, 1, height);
+}
+
+void ScreenEdges::createHorizontalEdge(ElectricBorder border, const QRect &screen, const QRect &fullArea)
+{
+ if (border != ElectricTop && border != ElectricBottom) {
+ return;
+ }
+ int x = screen.x();
+ int width = screen.width();
+ if (isLeftScreen(screen, fullArea)) {
+ // also left most - adjust only x and width
+ x++;
+ width--;
+ }
+ if (isRightScreen(screen, fullArea)) {
+ // also right most edge
+ width--;
+ }
+ const int y = (border == ElectricTop) ? screen.y() : screen.y() + screen.height() - 1;
+ m_edges << createEdge(border, x, y, width, 1);
+}
+
+WindowBasedEdge *ScreenEdges::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();
+ }
+ }
+ }
+ QHash::const_iterator it = m_externalReservations.constFind(border);
+ if (it != m_externalReservations.constEnd()) {
+ for (int i=0; ireserve();
+ }
+ }
+ connect(edge, SIGNAL(activated(ElectricBorder)), SIGNAL(activated(ElectricBorder)));
+ return edge;
+}
+
+ElectricBorderAction ScreenEdges::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 ScreenEdges::reserveDesktopSwitching(bool isToReserve, Qt::Orientations o)
{
if (!o)
return;
- if (isToReserve) {
- reserve(ElectricTopLeft);
- reserve(ElectricTopRight);
- reserve(ElectricBottomRight);
- reserve(ElectricBottomLeft);
-
- if (o & Qt::Horizontal) {
- reserve(ElectricLeft);
- reserve(ElectricRight);
- }
- if (o & Qt::Vertical) {
- reserve(ElectricTop);
- reserve(ElectricBottom);
- }
- } else {
- unreserve(ElectricTopLeft);
- unreserve(ElectricTopRight);
- unreserve(ElectricBottomRight);
- unreserve(ElectricBottomLeft);
-
- if (o & Qt::Horizontal) {
- unreserve(ElectricLeft);
- unreserve(ElectricRight);
- }
- if (o & Qt::Vertical) {
- unreserve(ElectricTop);
- unreserve(ElectricBottom);
- }
- }
-}
-
-void ScreenEdge::reserve(ElectricBorder border)
-{
- if (border == ElectricNone)
- return;
- if (m_screenEdgeReserved[border]++ == 0)
- QTimer::singleShot(0, this, SLOT(update()));
-}
-
-void ScreenEdge::unreserve(ElectricBorder border)
-{
- if (border == ElectricNone)
- return;
- assert(m_screenEdgeReserved[border] > 0);
- if (--m_screenEdgeReserved[border] == 0)
- QTimer::singleShot(0, this, SLOT(update()));
-}
-
-void ScreenEdge::check(const QPoint& pos, Time now, bool forceNoPushback)
-{
- if ((pos.x() != m_screenEdgeLeft) &&
- (pos.x() != m_screenEdgeRight) &&
- (pos.y() != m_screenEdgeTop) &&
- (pos.y() != m_screenEdgeBottom))
- return;
-
- bool have_borders = false;
- for (int i = 0; i < ELECTRIC_COUNT; ++i)
- if (m_screenEdgeWindows[i] != None)
- have_borders = true;
- if (!have_borders)
- return;
-
- 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;
-
- 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 (m_virtualDesktopSwitching != Options::ElectricDisabled)
- switchDesktop(border, pos);
- return; // Don't reset cursor position
- } else {
- if (m_virtualDesktopSwitching == 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(effects)->borderActivated(border))
- {} // Handled by effects
- else {
- if (m_virtualDesktopSwitching == Options::ElectricAlways) {
- switchDesktop(border, pos);
- return; // Don't reset cursor position
- }
- emit activated(border);
- }
- }
- }
+ for (QList::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)
+void ScreenEdges::reserve(ElectricBorder border)
{
- QPoint pos = _pos;
- VirtualDesktopManager *vds = VirtualDesktopManager::self();
- int desk = vds->current();
- const int OFFSET = 2;
- if (border == ElectricLeft || border == ElectricTopLeft || border == ElectricBottomLeft) {
- desk = vds->toLeft(desk, options->isRollOverDesktops());
- pos.setX(displayWidth() - 1 - OFFSET);
+ QHash::iterator it = m_externalReservations.find(border);
+ if (it != m_externalReservations.end()) {
+ m_externalReservations.insert(border, it.value() + 1);
}
- if (border == ElectricRight || border == ElectricTopRight || border == ElectricBottomRight) {
- desk = vds->toRight(desk, options->isRollOverDesktops());
- pos.setX(OFFSET);
+ for (QList::iterator it = m_edges.begin(); it != m_edges.end(); ++it) {
+ if ((*it)->border() == border) {
+ (*it)->reserve();
+ }
}
- if (border == ElectricTop || border == ElectricTopLeft || border == ElectricTopRight) {
- desk = vds->above(desk, options->isRollOverDesktops());
- pos.setY(displayHeight() - 1 - OFFSET);
- }
- if (border == ElectricBottom || border == ElectricBottomLeft || border == ElectricBottomRight) {
- desk = vds->below(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
- const uint desk_before = vds->current();
- vds->setCurrent(desk);
- if (vds->current() != desk_before)
- QCursor::setPos(pos);
}
-bool ScreenEdge::isEntered(XEvent* e)
+void ScreenEdges::unreserve(ElectricBorder border)
+{
+ QHash::iterator it = m_externalReservations.find(border);
+ if (it != m_externalReservations.end()) {
+ m_externalReservations.insert(border, it.value() - 1);
+ }
+ for (QList::iterator it = m_edges.begin(); it != m_edges.end(); ++it) {
+ if ((*it)->border() == border) {
+ (*it)->unreserve();
+ }
+ }
+}
+
+void ScreenEdges::check(const QPoint &pos, const QDateTime &now, bool forceNoPushBack)
+{
+ for (QList::iterator it = m_edges.begin(); it != m_edges.end(); ++it) {
+ (*it)->check(pos, now, forceNoPushBack);
+ }
+}
+
+bool ScreenEdges::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);
+ for (QList::iterator it = m_edges.begin(); it != m_edges.end(); ++it) {
+ WindowBasedEdge *edge = *it;
+ if (edge->isReserved() && edge->window() == e->xcrossing.window) {
+ edge->check(QPoint(e->xcrossing.x_root, e->xcrossing.y_root), QDateTime::fromMSecsSinceEpoch(e->xcrossing.time));
return true;
}
+ }
}
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]) {
+ for (QList::iterator it = m_edges.begin(); it != m_edges.end(); ++it) {
+ WindowBasedEdge *edge = *it;
+ if (edge->isReserved() && edge->window() == e->xclient.window) {
updateXTime();
- check(QPoint(e->xclient.data.l[2] >> 16, e->xclient.data.l[2] & 0xffff), xTime(), true);
+ edge->check(QPoint(e->xclient.data.l[2] >> 16, e->xclient.data.l[2] & 0xffff), QDateTime::fromMSecsSinceEpoch(xTime()), true);
return true;
}
+ }
}
}
return false;
}
-void ScreenEdge::ensureOnTop()
+void ScreenEdges::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 ];
- if (!pos) {
- delete [] windows;
- return; // No borders at all
- }
- XRaiseWindow(display(), windows[ 0 ]);
- XRestackWindows(display(), windows, pos);
- delete [] windows;
+ Xcb::restackWindowsWithRaise(windows());
}
/*
@@ -462,45 +795,68 @@ void ScreenEdge::ensureOnTop()
* (which raised our electric borders)
*/
-void ScreenEdge::raisePanelProxies()
+void ScreenEdges::raisePanelProxies()
{
- XWindowAttributes attr;
- Window dummy;
- Window* windows = NULL;
- unsigned int count = 0;
+ QVector ownWindows = windows();
+ Xcb::Tree tree(rootWindow());
+ QVector attributes(tree->children_len);
+ QVector geometries(tree->children_len);
+
+ Xcb::WindowId *windows = tree.children();
QRect screen = QRect(0, 0, displayWidth(), displayHeight());
- QVector proxies;
- XQueryTree(display(), rootWindow(), &dummy, &dummy, &windows, &count);
- for (unsigned int i = 0; i < count; ++i) {
- if (m_screenEdgeWindows.contains(windows[i]))
+ QVector proxies;
+
+ int count = 0;
+ for (unsigned int i = 0; i < tree->children_len; ++i) {
+ if (ownWindows.contains(windows[i])) {
+ // one of our screen edges
continue;
- if (XGetWindowAttributes(display(), windows[i], &attr)) {
- if (attr.map_state == IsUnmapped) // a thousand Qt group leader dummies ...
- continue;
- const QRect geo(attr.x, attr.y, attr.width, attr.height);
- if (geo.width() < 1 || geo.height() < 1)
- continue;
- if (!(geo.width() > 1 || geo.height() > 1))
- continue; // random 1x1 dummy windows, all your corners are belong to us >-)
- if (attr.c_class != InputOnly && (geo.width() > 3 && geo.height() > 3))
- continue;
- if (geo.x() != screen.x() && geo.right() != screen.right() &&
- geo.y() != screen.y() && geo.bottom() != screen.bottom())
- continue;
- proxies << windows[i];
+ }
+ attributes[count] = Xcb::WindowAttributes(windows[i]);
+ geometries[count] = Xcb::WindowGeometry(windows[i]);
+ count++;
+ }
+
+ for (int i=0; imap_state == XCB_MAP_STATE_UNMAPPED) {
+ continue;
+ }
+ Xcb::WindowGeometry geometry(geometries.at(i));
+ if (geometry.isNull()) {
+ continue;
+ }
+ const QRect geo(geometry.rect());
+ if (geo.width() < 1 || geo.height() < 1) {
+ continue;
+ }
+ if (!(geo.width() > 1 || geo.height() > 1)) {
+ continue; // random 1x1 dummy windows, all your corners are belong to us >-)
+ }
+ if (attr->_class != XCB_WINDOW_CLASS_INPUT_ONLY && (geo.width() > 3 && geo.height() > 3)) {
+ continue;
+ }
+ if (geo.x() != screen.x() && geo.right() != screen.right() &&
+ geo.y() != screen.y() && geo.bottom() != screen.bottom()) {
+ continue;
+ }
+ proxies << attr.window();
+ }
+ Xcb::restackWindowsWithRaise(proxies);
+}
+
+QVector< xcb_window_t > ScreenEdges::windows() const
+{
+ QVector wins;
+ for (QList::const_iterator it = m_edges.constBegin();
+ it != m_edges.constEnd();
+ ++it) {
+ xcb_window_t w = (*it)->window();
+ if (w != XCB_WINDOW_NONE) {
+ wins.append(w);
}
}
- if (!proxies.isEmpty()) {
- XRaiseWindow(display(), proxies.data()[ 0 ]);
- XRestackWindows(display(), proxies.data(), proxies.count());
- }
- if (windows)
- XFree(windows);
+ return wins;
}
-const QVector< Window >& ScreenEdge::windows()
-{
- return m_screenEdgeWindows;
-}
} //namespace
-
diff --git a/screenedge.h b/screenedge.h
index 6dd1956332..bd0c69cbfb 100644
--- a/screenedge.h
+++ b/screenedge.h
@@ -3,6 +3,7 @@
This file is part of the KDE project.
Copyright (C) 2011 Arthur Arlt
+Copyright (C) 2013 Martin Gräßlin
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 .
#ifndef KWIN_SCREENEDGE_H
#define KWIN_SCREENEDGE_H
+// KWin
+#include "kwinglobals.h"
+// KDE includes
+#include
+// Qt
#include
#include
-#include "kwinglobals.h"
-
+#include
namespace KWin {
-/**
- * @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.
- *
- * @author Arthur Arlt
- * @since 4.8
- */
-class ScreenEdge : public QObject {
+class ScreenEdges;
+
+class Edge : public QObject
+{
Q_OBJECT
public:
- ScreenEdge();
- ~ScreenEdge();
+ 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 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
+ *
+ * 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 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:
+ 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.
+ * Reserve desktop switching for screen edges, if @p isToReserve is @c true. Unreserve otherwise.
* @param reserve indicated weather desktop switching should be reserved or unreseved
*/
void reserveDesktopSwitching(bool isToReserve, Qt::Orientations o);
@@ -102,30 +235,43 @@ 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< xcb_window_t > 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.
- */
- void update(bool force=false);
- /**
- * Reconfigures the screen edges. That is reserves required borders.
+ * Minimum time between the push back of the cursor and the activation by re-entering the edge.
**/
+ 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();
/**
- * Reconfigures for virtual desktop switching, that is updates m_virtualDesktopSwitching.
- **/
- void reconfigureVirtualDesktopSwitching();
- /**
- * Updates the layout of virtual desktops, that is updates m_virtualDesktopLayout.
+ * 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
@@ -134,35 +280,207 @@ Q_SIGNALS:
**/
void activated(ElectricBorder border);
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;
- /**
- * The virtual desktop switching mode when hitting screen edges. Either:
- * @li never enabled
- * @li enabled when moving windows
- * @li always enabled
- **/
- int m_virtualDesktopSwitching;
- /**
- * Used to know whether desktop switching at top/bottom or left/right borders is supported
- * by the layout of virtual desktops.
- **/
+ enum { ElectricDisabled = 0, ElectricMoveOnly = 1, ElectricAlways = 2 };
+ void setDesktopSwitching(bool enable);
+ void setDesktopSwitchingMovingClients(bool enable);
+ void setCursorPushBackDistance(const QSize &distance);
+ void setTimeThreshold(int threshold);
+ void setReActivationThreshold(int threshold);
+ 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 m_desktopSwitching;
+ bool m_desktopSwitchingMovingClients;
+ QSize m_cursorPushBackDistance;
+ int m_timeThreshold;
+ int m_reactivateThreshold;
Qt::Orientations m_virtualDesktopLayout;
+ QList 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;
+ QHash m_externalReservations;
};
+
+/**********************************************************
+ * 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() const
+{
+ return m_border == ElectricLeft
+ || m_border == ElectricRight
+ || m_border == ElectricTop
+ || 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 ScreenEdges *Edge::edges()
+{
+ return m_edges;
+}
+
+inline const ScreenEdges *Edge::edges() const
+{
+ return m_edges;
+}
+
+inline const QRect &Edge::geometry() const
+{
+ return m_geometry;
+}
+
+inline void Edge::setGeometry(const QRect &geometry)
+{
+ if (m_geometry == geometry) {
+ return;
+ }
+ m_geometry = geometry;
+ doGeometryUpdate();
+}
+
+inline ElectricBorder Edge::border() const
+{
+ return m_border;
+}
+
+/**********************************************************
+ * Inlines WindowBasedEdge
+ *********************************************************/
+
+inline xcb_window_t WindowBasedEdge::window() const
+{
+ return m_window;
+}
+
+/**********************************************************
+ * Inlines ScreenEdges
+ *********************************************************/
+inline void ScreenEdges::setConfig(KSharedConfig::Ptr config)
+{
+ m_config = config;
+}
+
+inline const QSize &ScreenEdges::cursorPushBackDistance() const
+{
+ return m_cursorPushBackDistance;
+}
+
+inline bool ScreenEdges::isDesktopSwitching() const
+{
+ return m_desktopSwitching;
+}
+
+inline bool ScreenEdges::isDesktopSwitchingMovingClients() const
+{
+ return m_desktopSwitchingMovingClients;
+}
+
+inline int ScreenEdges::reActivationThreshold() const
+{
+ return m_reactivateThreshold;
+}
+
+inline int ScreenEdges::timeThreshold() const
+{
+ return m_timeThreshold;
+}
+
+inline void ScreenEdges::setCursorPushBackDistance(const QSize &distance)
+{
+ m_cursorPushBackDistance = distance;
+}
+
+inline void ScreenEdges::setDesktopSwitching(bool enable)
+{
+ if (enable == m_desktopSwitching) {
+ return;
+ }
+ m_desktopSwitching = enable;
+ reserveDesktopSwitching(enable, m_virtualDesktopLayout);
+}
+
+inline void ScreenEdges::setDesktopSwitchingMovingClients(bool enable)
+{
+ m_desktopSwitchingMovingClients = enable;
+}
+
+inline void ScreenEdges::setReActivationThreshold(int threshold)
+{
+ m_reactivateThreshold = threshold;
+}
+
+inline void ScreenEdges::setTimeThreshold(int threshold)
+{
+ m_timeThreshold = threshold;
+}
+
+#define ACTION( name ) \
+inline ElectricBorderAction ScreenEdges::name() const \
+{ \
+ return m_##name; \
+}
+
+ACTION(actionTopLeft)
+ACTION(actionTop)
+ACTION(actionTopRight)
+ACTION(actionRight)
+ACTION(actionBottomRight)
+ACTION(actionBottom)
+ACTION(actionBottomLeft)
+ACTION(actionLeft)
+
+#undef ACTION
+
}
#endif // KWIN_SCREENEDGE_H
diff --git a/scripting/scriptedeffect.cpp b/scripting/scriptedeffect.cpp
index e9c0509108..9ec73bf7bc 100644
--- a/scripting/scriptedeffect.cpp
+++ b/scripting/scriptedeffect.cpp
@@ -22,6 +22,9 @@ along with this program. If not, see .
#include "meta.h"
#include "scriptingutils.h"
#include "workspace_wrapper.h"
+#ifdef KWIN_BUILD_SCREENEDGES
+#include "../screenedge.h"
+#endif
// KDE
#include
#include
diff --git a/scripting/scriptingutils.h b/scripting/scriptingutils.h
index 3ed7845813..b22f846fe8 100644
--- a/scripting/scriptingutils.h
+++ b/scripting/scriptingutils.h
@@ -22,6 +22,9 @@ along with this program. If not, see .
#define KWIN_SCRIPTINGUTILS_H
#include "workspace.h"
+#ifdef KWIN_BUILD_SCREENEDGES
+#include "screenedge.h"
+#endif
#include
#include
diff --git a/workspace.cpp b/workspace.cpp
index 9183fd66da..47e84a8abb 100644
--- a/workspace.cpp
+++ b/workspace.cpp
@@ -66,6 +66,9 @@ along with this program. If not, see .
#include "xcbutils.h"
#include
#include
+#ifdef KWIN_BUILD_SCREENEDGES
+#include "screenedge.h"
+#endif
#ifdef KWIN_BUILD_SCRIPTING
#include "scripting/scripting.h"
#endif
@@ -96,6 +99,9 @@ Workspace* Workspace::_self = 0;
Workspace::Workspace(bool restore)
: QObject(0)
+#ifdef KWIN_BUILD_SCREENEDGES
+ , m_screenEdge(new ScreenEdges(this))
+#endif
, m_compositor(NULL)
// Unsorted
, active_popup(NULL)
@@ -255,10 +261,10 @@ void Workspace::screenChangeTimeout()
void Workspace::init()
{
#ifdef KWIN_BUILD_SCREENEDGES
- m_screenEdge.init();
- connect(options, SIGNAL(configChanged()), &m_screenEdge, SLOT(reconfigure()));
- connect(options, SIGNAL(electricBordersChanged()), &m_screenEdge, SLOT(reconfigureVirtualDesktopSwitching()));
- connect(VirtualDesktopManager::self(), SIGNAL(layoutChanged(int,int)), &m_screenEdge, SLOT(updateLayout()));
+ m_screenEdge->setConfig(KGlobal::config());
+ m_screenEdge->init();
+ connect(options, SIGNAL(configChanged()), m_screenEdge, SLOT(reconfigure()));
+ connect(VirtualDesktopManager::self(), SIGNAL(layoutChanged(int,int)), m_screenEdge, SLOT(updateLayout()));
#endif
supportWindow = new QWidget(NULL, Qt::X11BypassWindowManagerHint);
@@ -992,10 +998,6 @@ void Workspace::slotReconfigure()
kDebug(1212) << "Workspace::slotReconfigure()";
reconfigureTimer.stop();
-#ifdef KWIN_BUILD_SCREENEDGES
- m_screenEdge.reserveActions(false);
-#endif
-
bool borderlessMaximizedWindows = options->borderlessMaximizedWindows();
KGlobal::config()->reparseConfiguration();
@@ -1933,9 +1935,9 @@ Outline* Workspace::outline()
}
#ifdef KWIN_BUILD_SCREENEDGES
-ScreenEdge* Workspace::screenEdge()
+ScreenEdges* Workspace::screenEdge()
{
- return &m_screenEdge;
+ return m_screenEdge;
}
#endif
@@ -1994,6 +1996,18 @@ QString Workspace::supportInformation() const
}
support.append(QLatin1String(property.name()) % ": " % options->property(property.name()).toString() % '\n');
}
+#ifdef KWIN_BUILD_SCREENEDGES
+ support.append("\nScreen Edges\n");
+ support.append( "============\n");
+ const QMetaObject *metaScreenEdges = m_screenEdge->metaObject();
+ for (int i=0; ipropertyCount(); ++i) {
+ const QMetaProperty property = metaScreenEdges->property(i);
+ if (QLatin1String(property.name()) == "objectName") {
+ continue;
+ }
+ support.append(QLatin1String(property.name()) % ": " % m_screenEdge->property(property.name()).toString() % '\n');
+ }
+#endif
support.append("\nScreens\n");
support.append( "=======\n");
support.append("Multi-Head: ");
diff --git a/workspace.h b/workspace.h
index 203dd344c3..4d7a75ce91 100644
--- a/workspace.h
+++ b/workspace.h
@@ -41,9 +41,6 @@ along with this program. If not, see .
#include "plugins.h"
#include "kdecoration.h"
#include "kdecorationfactory.h"
-#ifdef KWIN_BUILD_SCREENEDGES
-#include "screenedge.h"
-#endif
#include "sm.h"
#include
@@ -78,6 +75,7 @@ class Scripting;
class UserActionsMenu;
class WindowRules;
class Compositor;
+class ScreenEdges;
class Workspace : public QObject, public KDecorationDefines
{
@@ -202,7 +200,7 @@ public:
Outline* outline();
#ifdef KWIN_BUILD_SCREENEDGES
- ScreenEdge* screenEdge();
+ ScreenEdges* screenEdge();
#endif
public:
@@ -217,7 +215,7 @@ private:
Outline* m_outline;
#ifdef KWIN_BUILD_SCREENEDGES
- ScreenEdge m_screenEdge;
+ ScreenEdges *m_screenEdge;
#endif
Compositor *m_compositor;