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
This commit is contained in:
Martin Gräßlin 2013-01-21 09:04:06 +01:00
parent 6ade1f3ca5
commit d9aedf620b
12 changed files with 1160 additions and 667 deletions

View file

@ -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

View file

@ -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;

View file

@ -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
}
}

View file

@ -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;

View file

@ -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) {

100
options.h
View file

@ -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;

File diff suppressed because it is too large Load diff

View file

@ -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 {
/**
* @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<WindowBasedEdge*> m_edges;
KSharedConfig::Ptr m_config;
ElectricBorderAction m_actionTopLeft;
ElectricBorderAction m_actionTop;
ElectricBorderAction m_actionTopRight;
ElectricBorderAction m_actionRight;
ElectricBorderAction m_actionBottomRight;
ElectricBorderAction m_actionBottom;
ElectricBorderAction m_actionBottomLeft;
ElectricBorderAction m_actionLeft;
QHash<ElectricBorder, int> 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

View file

@ -22,6 +22,9 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "meta.h"
#include "scriptingutils.h"
#include "workspace_wrapper.h"
#ifdef KWIN_BUILD_SCREENEDGES
#include "../screenedge.h"
#endif
// KDE
#include <KDE/KConfigGroup>
#include <KDE/KDebug>

View file

@ -22,6 +22,9 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#define KWIN_SCRIPTINGUTILS_H
#include "workspace.h"
#ifdef KWIN_BUILD_SCREENEDGES
#include "screenedge.h"
#endif
#include <KDE/KAction>
#include <KDE/KActionCollection>

View file

@ -66,6 +66,9 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "xcbutils.h"
#include <kwinglplatform.h>
#include <kwinglutils.h>
#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; i<metaScreenEdges->propertyCount(); ++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: ");

View file

@ -41,9 +41,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "plugins.h"
#include "kdecoration.h"
#include "kdecorationfactory.h"
#ifdef KWIN_BUILD_SCREENEDGES
#include "screenedge.h"
#endif
#include "sm.h"
#include <X11/Xlib.h>
@ -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;