Move handling of Virtual Desktops into a VirtualDesktopManager

The ownership for virtual desktops is moved from Workspace into a new
VirtualDesktopManager. The manager is responsible for providing the count
of virtual desktops and keeping track of the currently used virtual
desktop.

All methods related to moving between desktops are also moved from
Workspace to the new manager, though all methods related to Clients on
Virtual Desktops remain in Workspace for the time being. This is to have
the new manager as independent from KWin core as possible.

An rather important change for the handling of virtual desktops is that
the count and the id of a desktop is now an unsinged integer instead of
an integer. The reason for that is that we cannot have a negative count
of desktops as well as it is not possible to be on a desktop with a
negative identifier.

In that regard it is important to remember that a Client can be on a
desktop with a negative identifier. The special value for a Client being
on all desktops is handled by using -1 as a desktop. For the time being
this is not adjusted but instead of comparing the virtual desktop ids one
should prefer to use the convenient methods like isOnDesktop and
isOnAllDesktops. This would allow in future to internally change the
representation for on all desktops.
icc-effect-5.14.5
Martin Gräßlin 2012-11-16 08:23:47 +01:00
parent 54479225a3
commit 334b4bf622
32 changed files with 2220 additions and 912 deletions

View File

@ -128,8 +128,8 @@ set(kwin_KDEINIT_SRCS
deleted.cpp
effects.cpp
compositingprefs.cpp
desktoplayout.cpp
paintredirector.cpp
virtualdesktops.cpp
)
if(KWIN_BUILD_SCRIPTING)

View File

@ -285,7 +285,7 @@ void Workspace::activateClient(Client* c, bool force)
raiseClient(c);
if (!c->isOnCurrentDesktop()) {
++block_focus;
setCurrentDesktop(c->desktop());
VirtualDesktopManager::self()->setCurrent(c->desktop());
--block_focus;
}
#ifdef KWIN_BUILD_ACTIVITIES
@ -474,6 +474,8 @@ bool Workspace::activateNextClient(Client* c)
}
}
const int desktop = VirtualDesktopManager::self()->current();
if (!get_focus) { // no suitable window under the mouse -> find sth. else
// first try to pass the focus to the (former) active clients leader
if (c && (get_focus = c->transientFor()) && isUsableFocusCandidate(get_focus, c, options->isSeparateScreenFocus())) {
@ -481,8 +483,8 @@ bool Workspace::activateNextClient(Client* c)
} else {
// nope, ask the focus chain for the next candidate
get_focus = NULL; // reset from the inline assignment above
for (int i = focus_chain[ currentDesktop()].size() - 1; i >= 0; --i) {
Client* ci = focus_chain[ currentDesktop()].at(i);
for (int i = focus_chain[desktop].size() - 1; i >= 0; --i) {
Client* ci = focus_chain[desktop].at(i);
if (isUsableFocusCandidate(ci, c, options->isSeparateScreenFocus())) {
get_focus = ci;
break; // we're done
@ -492,7 +494,7 @@ bool Workspace::activateNextClient(Client* c)
}
if (get_focus == NULL) // last chance: focus the desktop
get_focus = findDesktop(true, currentDesktop());
get_focus = findDesktop(true, desktop);
if (get_focus != NULL)
requestFocus(get_focus);
@ -511,10 +513,11 @@ void Workspace::setCurrentScreen(int new_screen)
return;
closeActivePopup();
Client* get_focus = NULL;
for (int i = focus_chain[ currentDesktop()].count() - 1;
const int desktop = VirtualDesktopManager::self()->current();
for (int i = focus_chain[desktop].count() - 1;
i >= 0;
--i) {
Client* ci = focus_chain[ currentDesktop()].at(i);
Client* ci = focus_chain[desktop].at(i);
if (!ci->isShown(false) || !ci->isOnCurrentDesktop() || !ci->isOnCurrentActivity())
continue;
if (ci->screen() == new_screen) {
@ -523,7 +526,7 @@ void Workspace::setCurrentScreen(int new_screen)
}
}
if (get_focus == NULL)
get_focus = findDesktop(true, currentDesktop());
get_focus = findDesktop(true, desktop);
if (get_focus != NULL && get_focus != mostRecentlyActivatedClient())
requestFocus(get_focus);
active_screen = new_screen;
@ -893,7 +896,7 @@ void Client::startupIdChanged()
// If the ASN contains desktop, move it to the desktop, otherwise move it to the current
// desktop (since the new ASN should make the window act like if it's a new application
// launched). However don't affect the window's desktop if it's set to be on all desktops.
int desktop = workspace()->currentDesktop();
int desktop = VirtualDesktopManager::self()->current();
if (asn_data.desktop() != 0)
desktop = asn_data.desktop();
if (!isOnAllDesktops())

View File

@ -172,7 +172,7 @@ void Bridge::setShade(bool set)
int Bridge::currentDesktop() const
{
return c->workspace()->currentDesktop();
return VirtualDesktopManager::self()->current();
}
QWidget* Bridge::initialParentWidget() const

View File

@ -1434,9 +1434,10 @@ void Client::setModal(bool m)
void Client::setDesktop(int desktop)
{
const int numberOfDesktops = VirtualDesktopManager::self()->count();
if (desktop != NET::OnAllDesktops) // Do range check
desktop = qMax(1, qMin(workspace()->numberOfDesktops(), desktop));
desktop = qMin(workspace()->numberOfDesktops(), rules()->checkDesktop(desktop));
desktop = qMax(1, qMin(numberOfDesktops, desktop));
desktop = qMin(numberOfDesktops, rules()->checkDesktop(desktop));
if (desk == desktop)
return;
@ -1582,7 +1583,7 @@ void Client::setOnAllDesktops(bool b)
if (b)
setDesktop(NET::OnAllDesktops);
else
setDesktop(workspace()->currentDesktop());
setDesktop(VirtualDesktopManager::self()->current());
// Update states of all other windows in this group
if (tabGroup())

View File

@ -1184,8 +1184,9 @@ bool Unmanaged::shouldUnredirect() const
)
return false;
// it must cover whole display or one xinerama screen, and be the topmost there
if (geometry() == workspace()->clientArea(FullArea, geometry().center(), workspace()->currentDesktop())
|| geometry() == workspace()->clientArea(ScreenArea, geometry().center(), workspace()->currentDesktop())) {
const int desktop = VirtualDesktopManager::self()->current();
if (geometry() == workspace()->clientArea(FullArea, geometry().center(), desktop)
|| geometry() == workspace()->clientArea(ScreenArea, geometry().center(), desktop)) {
ToplevelList stacking = workspace()->xStackingOrder();
for (int pos = stacking.count() - 1;
pos >= 0;

View File

@ -28,6 +28,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "effects.h"
#include "kwinadaptor.h"
#include "workspace.h"
#include "virtualdesktops.h"
// Qt
#include <QDBusServiceWatcher>
@ -72,16 +73,17 @@ DBusInterface::~DBusInterface()
void DBusInterface::circulateDesktopApplications()
{
Workspace *ws = Workspace::self();
const uint desktop = VirtualDesktopManager::self()->current();
const QList<Client*> &desktops = ws->desktopList();
if (desktops.count() > 1) {
bool change_active = ws->activeClient()->isDesktop();
ws->raiseClient(ws->findDesktop(false, currentDesktop()));
ws->raiseClient(ws->findDesktop(false, desktop));
if (change_active) // if the previously topmost Desktop was active, activate this new one
ws->activateClient(ws->findDesktop(true, currentDesktop()));
ws->activateClient(ws->findDesktop(true, desktop));
}
// if there's no active client, make desktop the active one
if (desktops.count() > 0 && ws->activeClient() == NULL && ws->mostRecentlyActivatedClient() == NULL)
ws->activateClient(ws->findDesktop(true, currentDesktop()));
ws->activateClient(ws->findDesktop(true, desktop));
}
// wrap void methods with no arguments to Workspace
@ -92,8 +94,6 @@ void DBusInterface::name() \
}
WRAP(killWindow)
WRAP(nextDesktop)
WRAP(previousDesktop)
WRAP(reconfigure)
#undef WRAP
@ -116,7 +116,6 @@ rettype DBusInterface::name( ) \
return Workspace::self()->name(); \
}
WRAP(int, currentDesktop)
WRAP(QList<int>, decorationSupportedColors)
WRAP(QString, supportInformation)
WRAP(bool, waitForCompositingSetup)
@ -130,7 +129,6 @@ rettype DBusInterface::name( argtype arg ) \
return Workspace::self()->name(arg); \
}
WRAP(bool, setCurrentDesktop, int)
WRAP(bool, startActivity, const QString &)
WRAP(bool, stopActivity, const QString &)
@ -218,4 +216,24 @@ QString DBusInterface::supportInformationForEffect(const QString &name)
return QString();
}
int DBusInterface::currentDesktop()
{
return VirtualDesktopManager::self()->current();
}
bool DBusInterface::setCurrentDesktop(int desktop)
{
return VirtualDesktopManager::self()->setCurrent(desktop);
}
void DBusInterface::nextDesktop()
{
VirtualDesktopManager::self()->moveTo<DesktopNext>();
}
void DBusInterface::previousDesktop()
{
VirtualDesktopManager::self()->moveTo<DesktopPrevious>();
}
} // namespace

View File

@ -1,191 +0,0 @@
/********************************************************************
KWin - the KDE window manager
This file is part of the KDE project.
Copyright (C) 2009 Lucas Murray <lmurray@undefinedfire.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************/
#include "workspace.h"
#include "options.h"
#include "assert.h"
namespace KWin
{
void Workspace::updateDesktopLayout()
{
#ifdef KWIN_BUILD_SCREENEDGES
if (options->electricBorders() == Options::ElectricAlways) {
m_screenEdge.reserveDesktopSwitching(false, m_screenEdgeOrientation);
}
#endif
// TODO: Is there a sane way to avoid overriding the existing grid?
int width = rootInfo->desktopLayoutColumnsRows().width();
int height = rootInfo->desktopLayoutColumnsRows().height();
if (width == 0 && height == 0) // Not given, set default layout
height = 2;
setNETDesktopLayout(
rootInfo->desktopLayoutOrientation() == NET::OrientationHorizontal ? Qt::Horizontal : Qt::Vertical,
width, height, 0 //rootInfo->desktopLayoutCorner() // Not really worth implementing right now.
);
#ifdef KWIN_BUILD_SCREENEDGES
m_screenEdgeOrientation = 0;
if (width > 1)
m_screenEdgeOrientation |= Qt::Horizontal;
if (height > 1)
m_screenEdgeOrientation |= Qt::Vertical;
if (options->electricBorders() == Options::ElectricAlways) {
m_screenEdge.reserveDesktopSwitching(true, m_screenEdgeOrientation);
}
#endif
}
void Workspace::setNETDesktopLayout(Qt::Orientation orientation, int width, int height,
int startingCorner)
{
Q_UNUSED(startingCorner); // Not really worth implementing right now.
// Calculate valid grid size
assert(width > 0 || height > 0);
if ((width <= 0) && (height > 0))
width = (desktopCount_ + height - 1) / height;
else if ((height <= 0) && (width > 0))
height = (desktopCount_ + width - 1) / width;
while (width * height < desktopCount_) {
if (orientation == Qt::Horizontal)
++width;
else
++height;
}
// Set private variables
delete[] desktopGrid_;
desktopGridSize_ = QSize(width, height);
int size = width * height;
desktopGrid_ = new int[size];
// Populate grid
int desktop = 1;
if (orientation == Qt::Horizontal)
for (int y = 0; y < height; y++)
for (int x = 0; x < width; x++)
desktopGrid_[y * width + x] = (desktop <= desktopCount_ ? desktop++ : 0);
else
for (int x = 0; x < width; x++)
for (int y = 0; y < height; y++)
desktopGrid_[y * width + x] = (desktop <= desktopCount_ ? desktop++ : 0);
}
QPoint Workspace::desktopGridCoords(int id) const
{
for (int y = 0; y < desktopGridSize_.height(); y++)
for (int x = 0; x < desktopGridSize_.width(); x++)
if (desktopGrid_[y * desktopGridSize_.width() + x] == id)
return QPoint(x, y);
return QPoint(-1, -1);
}
QPoint Workspace::desktopCoords(int id) const
{
QPoint coords = desktopGridCoords(id);
if (coords.x() == -1)
return QPoint(-1, -1);
return QPoint(coords.x() * displayWidth(), coords.y() * displayHeight());
}
int Workspace::desktopAbove(int id, bool wrap) const
{
if (id == 0)
id = currentDesktop();
QPoint coords = desktopGridCoords(id);
assert(coords.x() >= 0);
for (;;) {
coords.ry()--;
if (coords.y() < 0) {
if (wrap)
coords.setY(desktopGridSize_.height() - 1);
else
return id; // Already at the top-most desktop
}
int desktop = desktopAtCoords(coords);
if (desktop > 0)
return desktop;
}
}
int Workspace::desktopToRight(int id, bool wrap) const
{
if (id == 0)
id = currentDesktop();
QPoint coords = desktopGridCoords(id);
assert(coords.x() >= 0);
for (;;) {
coords.rx()++;
if (coords.x() >= desktopGridSize_.width()) {
if (wrap)
coords.setX(0);
else
return id; // Already at the right-most desktop
}
int desktop = desktopAtCoords(coords);
if (desktop > 0)
return desktop;
}
}
int Workspace::desktopBelow(int id, bool wrap) const
{
if (id == 0)
id = currentDesktop();
QPoint coords = desktopGridCoords(id);
assert(coords.x() >= 0);
for (;;) {
coords.ry()++;
if (coords.y() >= desktopGridSize_.height()) {
if (wrap)
coords.setY(0);
else
return id; // Already at the bottom-most desktop
}
int desktop = desktopAtCoords(coords);
if (desktop > 0)
return desktop;
}
}
int Workspace::desktopToLeft(int id, bool wrap) const
{
if (id == 0)
id = currentDesktop();
QPoint coords = desktopGridCoords(id);
assert(coords.x() >= 0);
for (;;) {
coords.rx()--;
if (coords.x() < 0) {
if (wrap)
coords.setX(desktopGridSize_.width() - 1);
else
return id; // Already at the left-most desktop
}
int desktop = desktopAtCoords(coords);
if (desktop > 0)
return desktop;
}
}
} // namespace

View File

@ -35,6 +35,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "scripting/scriptedeffect.h"
#endif
#include "thumbnailitem.h"
#include "virtualdesktops.h"
#include "workspace.h"
#include "kwinglutils.h"
@ -116,12 +117,13 @@ EffectsHandlerImpl::EffectsHandlerImpl(Compositor *compositor, Scene *scene)
m_currentBuildQuadsIterator = m_activeEffects.end();
Workspace *ws = Workspace::self();
VirtualDesktopManager *vds = VirtualDesktopManager::self();
connect(ws, SIGNAL(currentDesktopChanged(int, KWin::Client*)), SLOT(slotDesktopChanged(int, KWin::Client*)));
connect(ws, SIGNAL(clientAdded(KWin::Client*)), this, SLOT(slotClientAdded(KWin::Client*)));
connect(ws, SIGNAL(unmanagedAdded(KWin::Unmanaged*)), this, SLOT(slotUnmanagedAdded(KWin::Unmanaged*)));
connect(ws, SIGNAL(clientActivated(KWin::Client*)), this, SLOT(slotClientActivated(KWin::Client*)));
connect(ws, SIGNAL(deletedRemoved(KWin::Deleted*)), this, SLOT(slotDeletedRemoved(KWin::Deleted*)));
connect(ws, SIGNAL(numberDesktopsChanged(int)), SIGNAL(numberDesktopsChanged(int)));
connect(vds, SIGNAL(countChanged(uint,uint)), SIGNAL(numberDesktopsChanged(uint)));
connect(ws, SIGNAL(mouseChanged(QPoint,QPoint,Qt::MouseButtons,Qt::MouseButtons,Qt::KeyboardModifiers,Qt::KeyboardModifiers)),
SIGNAL(mouseChanged(QPoint,QPoint,Qt::MouseButtons,Qt::MouseButtons,Qt::KeyboardModifiers,Qt::KeyboardModifiers)));
connect(ws, SIGNAL(propertyNotify(long)), this, SLOT(slotPropertyNotify(long)));
@ -482,7 +484,7 @@ void EffectsHandlerImpl::slotTabRemoved(EffectWindow *w, EffectWindow* leaderOfF
void EffectsHandlerImpl::slotDesktopChanged(int old, Client *c)
{
const int newDesktop = Workspace::self()->currentDesktop();
const int newDesktop = VirtualDesktopManager::self()->current();
if (old != 0 && newDesktop != old) {
emit desktopChanged(old, newDesktop, c ? c->effectWindow() : 0);
// TODO: remove in 4.10
@ -682,87 +684,90 @@ QString EffectsHandlerImpl::currentActivity() const
int EffectsHandlerImpl::currentDesktop() const
{
return Workspace::self()->currentDesktop();
return VirtualDesktopManager::self()->current();
}
int EffectsHandlerImpl::numberOfDesktops() const
{
return Workspace::self()->numberOfDesktops();
return VirtualDesktopManager::self()->count();
}
void EffectsHandlerImpl::setCurrentDesktop(int desktop)
{
Workspace::self()->setCurrentDesktop(desktop);
VirtualDesktopManager::self()->setCurrent(desktop);
}
void EffectsHandlerImpl::setNumberOfDesktops(int desktops)
{
Workspace::self()->setNumberOfDesktops(desktops);
VirtualDesktopManager::self()->setCount(desktops);
}
QSize EffectsHandlerImpl::desktopGridSize() const
{
return Workspace::self()->desktopGridSize();
return VirtualDesktopManager::self()->grid().size();
}
int EffectsHandlerImpl::desktopGridWidth() const
{
return Workspace::self()->desktopGridWidth();
return desktopGridSize().width();
}
int EffectsHandlerImpl::desktopGridHeight() const
{
return Workspace::self()->desktopGridHeight();
return desktopGridSize().height();
}
int EffectsHandlerImpl::workspaceWidth() const
{
return Workspace::self()->workspaceWidth();
return desktopGridWidth() * displayWidth();
}
int EffectsHandlerImpl::workspaceHeight() const
{
return Workspace::self()->workspaceHeight();
return desktopGridHeight() * displayHeight();
}
int EffectsHandlerImpl::desktopAtCoords(QPoint coords) const
{
return Workspace::self()->desktopAtCoords(coords);
return VirtualDesktopManager::self()->grid().at(coords);
}
QPoint EffectsHandlerImpl::desktopGridCoords(int id) const
{
return Workspace::self()->desktopGridCoords(id);
return VirtualDesktopManager::self()->grid().gridCoords(id);
}
QPoint EffectsHandlerImpl::desktopCoords(int id) const
{
return Workspace::self()->desktopCoords(id);
QPoint coords = VirtualDesktopManager::self()->grid().gridCoords(id);
if (coords.x() == -1)
return QPoint(-1, -1);
return QPoint(coords.x() * displayWidth(), coords.y() * displayHeight());
}
int EffectsHandlerImpl::desktopAbove(int desktop, bool wrap) const
{
return Workspace::self()->desktopAbove(desktop, wrap);
return getDesktop<DesktopAbove>(desktop, wrap);
}
int EffectsHandlerImpl::desktopToRight(int desktop, bool wrap) const
{
return Workspace::self()->desktopToRight(desktop, wrap);
return getDesktop<DesktopRight>(desktop, wrap);
}
int EffectsHandlerImpl::desktopBelow(int desktop, bool wrap) const
{
return Workspace::self()->desktopBelow(desktop, wrap);
return getDesktop<DesktopBelow>(desktop, wrap);
}
int EffectsHandlerImpl::desktopToLeft(int desktop, bool wrap) const
{
return Workspace::self()->desktopToLeft(desktop, wrap);
return getDesktop<DesktopLeft>(desktop, wrap);
}
QString EffectsHandlerImpl::desktopName(int desktop) const
{
return Workspace::self()->desktopName(desktop);
return VirtualDesktopManager::self()->name(desktop);
}
bool EffectsHandlerImpl::optionRollOverDesktops() const
@ -962,7 +967,7 @@ QRect EffectsHandlerImpl::clientArea(clientAreaOption opt, const EffectWindow* c
if (const Client* cl = dynamic_cast< const Client* >(t))
return Workspace::self()->clientArea(opt, cl);
else
return Workspace::self()->clientArea(opt, t->geometry().center(), Workspace::self()->currentDesktop());
return Workspace::self()->clientArea(opt, t->geometry().center(), VirtualDesktopManager::self()->current());
}
QRect EffectsHandlerImpl::clientArea(clientAreaOption opt, const QPoint& p, int desktop) const

View File

@ -79,7 +79,7 @@ DesktopGridEffect::DesktopGridEffect()
connect(effects, SIGNAL(windowAdded(KWin::EffectWindow*)), this, SLOT(slotWindowAdded(KWin::EffectWindow*)));
connect(effects, SIGNAL(windowClosed(KWin::EffectWindow*)), this, SLOT(slotWindowClosed(KWin::EffectWindow*)));
connect(effects, SIGNAL(windowDeleted(KWin::EffectWindow*)), this, SLOT(slotWindowDeleted(KWin::EffectWindow*)));
connect(effects, SIGNAL(numberDesktopsChanged(int)), this, SLOT(slotNumberDesktopsChanged(int)));
connect(effects, SIGNAL(numberDesktopsChanged(uint)), this, SLOT(slotNumberDesktopsChanged(uint)));
connect(effects, SIGNAL(windowGeometryShapeChanged(KWin::EffectWindow*,QRect)), this, SLOT(slotWindowGeometryShapeChanged(KWin::EffectWindow*,QRect)));
// Load all other configuration details
@ -1270,7 +1270,7 @@ void DesktopGridEffect::slotRemoveDesktop()
effects->setNumberOfDesktops(effects->numberOfDesktops() - 1);
}
void DesktopGridEffect::slotNumberDesktopsChanged(int old)
void DesktopGridEffect::slotNumberDesktopsChanged(uint old)
{
if (!activated)
return;

View File

@ -115,7 +115,7 @@ private slots:
void slotWindowAdded(KWin::EffectWindow* w);
void slotWindowClosed(KWin::EffectWindow *w);
void slotWindowDeleted(KWin::EffectWindow *w);
void slotNumberDesktopsChanged(int old);
void slotNumberDesktopsChanged(uint old);
void slotWindowGeometryShapeChanged(KWin::EffectWindow *w, const QRect &old);
private:

View File

@ -129,12 +129,12 @@ RootInfo::RootInfo(Workspace* ws, Display *dpy, Window w, const char *name, unsi
void RootInfo::changeNumberOfDesktops(int n)
{
workspace->setNumberOfDesktops(n);
VirtualDesktopManager::self()->setCount(n);
}
void RootInfo::changeCurrentDesktop(int d)
{
workspace->setCurrentDesktop(d);
VirtualDesktopManager::self()->setCurrent(d);
}
void RootInfo::changeActiveWindow(Window w, NET::RequestSource src, Time timestamp, Window active_window)
@ -232,9 +232,9 @@ bool Workspace::workspaceEvent(XEvent * e)
unsigned long dirty[ NETRootInfo::PROPERTIES_SIZE ];
rootInfo->event(e, dirty, NETRootInfo::PROPERTIES_SIZE);
if (dirty[ NETRootInfo::PROTOCOLS ] & NET::DesktopNames)
saveDesktopSettings();
VirtualDesktopManager::self()->save();
if (dirty[ NETRootInfo::PROTOCOLS2 ] & NET::WM2DesktopLayout)
updateDesktopLayout();
VirtualDesktopManager::self()->updateLayout();
}
// events that should be handled before Clients can get them
@ -889,7 +889,7 @@ void Client::enterNotifyEvent(XCrossingEvent* e)
if (options->isAutoRaise() && !isDesktop() &&
!isDock() && workspace()->focusChangeEnabled() &&
currentPos != workspace()->focusMousePosition() &&
workspace()->topClientOnDesktop(workspace()->currentDesktop(),
workspace()->topClientOnDesktop(VirtualDesktopManager::self()->current(),
options->isSeparateScreenFocus() ? screen() : -1) != this) {
delete autoRaiseTimer;
autoRaiseTimer = new QTimer(this);
@ -1000,7 +1000,7 @@ void Client::updateMouseGrab()
if (workspace()->globalShortcutsDisabled()) {
XUngrabButton(display(), AnyButton, AnyModifier, wrapperId());
// keep grab for the simple click without modifiers if needed (see below)
bool not_obscured = workspace()->topClientOnDesktop(workspace()->currentDesktop(), -1, true, false) == this;
bool not_obscured = workspace()->topClientOnDesktop(VirtualDesktopManager::self()->current(), -1, true, false) == this;
if (!(!options->isClickRaise() || not_obscured))
grabButton(None);
return;
@ -1015,7 +1015,7 @@ void Client::updateMouseGrab()
// is unobscured or if the user doesn't want click raise
// (it is unobscured if it the topmost in the unconstrained stacking order, i.e. it is
// the most recently raised window)
bool not_obscured = workspace()->topClientOnDesktop(workspace()->currentDesktop(), -1, true, false) == this;
bool not_obscured = workspace()->topClientOnDesktop(VirtualDesktopManager::self()->current(), -1, true, false) == this;
if (!options->isClickRaise() || not_obscured)
ungrabButton(None);
else

View File

@ -109,10 +109,11 @@ void Workspace::saveOldScreenSizes()
void Workspace::updateClientArea(bool force)
{
int nscreens = QApplication::desktop()->screenCount();
kDebug(1212) << "screens: " << nscreens << "desktops: " << numberOfDesktops();
QVector< QRect > new_wareas(numberOfDesktops() + 1);
QVector< StrutRects > new_rmoveareas(numberOfDesktops() + 1);
QVector< QVector< QRect > > new_sareas(numberOfDesktops() + 1);
const int numberOfDesktops = VirtualDesktopManager::self()->count();
kDebug(1212) << "screens: " << nscreens << "desktops: " << numberOfDesktops;
QVector< QRect > new_wareas(numberOfDesktops + 1);
QVector< StrutRects > new_rmoveareas(numberOfDesktops + 1);
QVector< QVector< QRect > > new_sareas(numberOfDesktops + 1);
QVector< QRect > screens(nscreens);
QRect desktopArea;
for (int i = 0; i < QApplication::desktop()->screenCount(); i++) {
@ -124,7 +125,7 @@ void Workspace::updateClientArea(bool force)
screens [iS] = QApplication::desktop()->screenGeometry(iS);
}
for (int i = 1;
i <= numberOfDesktops();
i <= numberOfDesktops;
++i) {
new_wareas[ i ] = desktopArea;
new_sareas[ i ].resize(nscreens);
@ -149,7 +150,7 @@ void Workspace::updateClientArea(bool force)
if ((*it)->isOnAllDesktops()) {
for (int i = 1;
i <= numberOfDesktops();
i <= numberOfDesktops;
++i) {
if (!hasOffscreenXineramaStrut)
new_wareas[ i ] = new_wareas[ i ].intersected(r);
@ -192,7 +193,7 @@ void Workspace::updateClientArea(bool force)
changed = true;
for (int i = 1;
!changed && i <= numberOfDesktops();
!changed && i <= numberOfDesktops;
++i) {
if (workarea[ i ] != new_wareas[ i ])
changed = true;
@ -213,7 +214,7 @@ void Workspace::updateClientArea(bool force)
restrictedmovearea = new_rmoveareas;
screenarea = new_sareas;
NETRect r;
for (int i = 1; i <= numberOfDesktops(); i++) {
for (int i = 1; i <= numberOfDesktops; i++) {
r.pos.x = workarea[ i ].x();
r.pos.y = workarea[ i ].y();
r.size.width = workarea[ i ].width();
@ -253,7 +254,7 @@ void Workspace::updateClientArea()
QRect Workspace::clientArea(clientAreaOption opt, int screen, int desktop) const
{
if (desktop == NETWinInfo::OnAllDesktops || desktop == 0)
desktop = currentDesktop();
desktop = VirtualDesktopManager::self()->current();
if (screen == -1)
screen = activeScreen();
@ -315,7 +316,7 @@ QRect Workspace::clientArea(clientAreaOption opt, const Client* c) const
QRegion Workspace::restrictedMoveArea(int desktop, StrutAreas areas) const
{
if (desktop == NETWinInfo::OnAllDesktops || desktop == 0)
desktop = currentDesktop();
desktop = VirtualDesktopManager::self()->current();
QRegion region;
foreach (const StrutRect & rect, restrictedmovearea[desktop])
if (areas & rect.area())
@ -331,7 +332,7 @@ bool Workspace::inUpdateClientArea() const
QRegion Workspace::previousRestrictedMoveArea(int desktop, StrutAreas areas) const
{
if (desktop == NETWinInfo::OnAllDesktops || desktop == 0)
desktop = currentDesktop();
desktop = VirtualDesktopManager::self()->current();
QRegion region;
foreach (const StrutRect & rect, oldrestrictedmovearea.at(desktop))
if (areas & rect.area())
@ -417,7 +418,7 @@ QPoint Workspace::adjustClientPosition(Client* c, QPoint pos, bool unrestricted,
QList<Client *>::ConstIterator l;
for (l = clients.constBegin(); l != clients.constEnd(); ++l) {
if ((((*l)->isOnDesktop(c->desktop()) && !(*l)->isMinimized())
|| (c->isOnDesktop(NET::OnAllDesktops) && (*l)->isOnDesktop(Workspace::currentDesktop())
|| (c->isOnDesktop(NET::OnAllDesktops) && (*l)->isOnDesktop(VirtualDesktopManager::self()->current())
&& !(*l)->isMinimized()))
&& (!(*l)->tabGroup() || (*l) == (*l)->tabGroup()->current())
&& (*l) != c) {
@ -612,7 +613,7 @@ QRect Workspace::adjustClientSize(Client* c, QRect moveResizeGeom, int mode)
deltaY = int(snap);
QList<Client *>::ConstIterator l;
for (l = clients.constBegin(); l != clients.constEnd(); ++l) {
if ((*l)->isOnDesktop(currentDesktop()) &&
if ((*l)->isOnDesktop(VirtualDesktopManager::self()->current()) &&
!(*l)->isMinimized()
&& (*l) != c) {
lx = (*l)->x() - 1;

View File

@ -153,23 +153,6 @@ for (int i = 0; i < 8; ++i) {
DEF(I18N_NOOP("Window to Next Screen"), 0, slotWindowToNextScreen());
DEF(I18N_NOOP("Show Desktop"), 0, slotToggleShowDesktop());
a = actionCollection->addAction("Group:Desktop Switching");
a->setText(i18n("Desktop Switching"));
DEF3("Switch to Desktop %1", Qt::CTRL + Qt::Key_F1, slotSwitchToDesktop(), 1);
DEF3("Switch to Desktop %1", Qt::CTRL + Qt::Key_F2, slotSwitchToDesktop(), 2);
DEF3("Switch to Desktop %1", Qt::CTRL + Qt::Key_F3, slotSwitchToDesktop(), 3);
DEF3("Switch to Desktop %1", Qt::CTRL + Qt::Key_F4, slotSwitchToDesktop(), 4);
for (int i = 5; i < 21; ++i) {
DEF3(I18N_NOOP("Switch to Desktop %1"), 0, slotSwitchToDesktop(), i);
}
DEF(I18N_NOOP("Switch to Next Desktop"), 0, slotSwitchDesktopNext());
DEF(I18N_NOOP("Switch to Previous Desktop"), 0, slotSwitchDesktopPrevious());
DEF(I18N_NOOP("Switch One Desktop to the Right"), 0, slotSwitchDesktopRight());
DEF(I18N_NOOP("Switch One Desktop to the Left"), 0, slotSwitchDesktopLeft());
DEF(I18N_NOOP("Switch One Desktop Up"), 0, slotSwitchDesktopUp());
DEF(I18N_NOOP("Switch One Desktop Down"), 0, slotSwitchDesktopDown());
for (int i = 0; i < 8; ++i) {
DEF3(I18N_NOOP("Switch to Screen %1"), 0, slotSwitchToScreen(), i);
}

View File

@ -282,7 +282,7 @@ void Workspace::raiseOrLowerClient(Client *c)
most_recently_raised->isShown(true) && c->isOnCurrentDesktop())
topmost = most_recently_raised;
else
topmost = topClientOnDesktop(c->isOnAllDesktops() ? currentDesktop() : c->desktop(),
topmost = topClientOnDesktop(c->isOnAllDesktops() ? VirtualDesktopManager::self()->current() : c->desktop(),
options->isSeparateScreenFocus() ? c->screen() : -1);
if (c == topmost)
@ -443,7 +443,7 @@ void Workspace::restack(Client* c, Client* under)
}
assert(unconstrained_stacking_order.contains(c));
for (int desktop = 1; desktop <= numberOfDesktops(); ++desktop) {
for (uint desktop = 1; desktop <= VirtualDesktopManager::self()->count(); ++desktop) {
// do for every virtual desktop to handle the case of onalldesktop windows
if (c->wantsTabFocus() && c->isOnDesktop(desktop) && focus_chain[ desktop ].contains(under)) {
if (Client::belongToSameApplication(under, c)) {
@ -893,7 +893,7 @@ bool Client::isActiveFullScreen() const
// only raise fullscreen above docks if it's the topmost window in unconstrained stacking order,
// i.e. the window set to be topmost by the user (also includes transients of the fullscreen window)
const Client* top = workspace()->topClientOnDesktop(workspace()->currentDesktop(), screen(), true, false);
const Client* top = workspace()->topClientOnDesktop(VirtualDesktopManager::self()->current(), screen(), true, false);
if (!top)
return false;

View File

@ -877,7 +877,7 @@ Q_SIGNALS:
* @see EffectsHandler::numberOfDesktops.
* @since 4.7
*/
void numberDesktopsChanged(int old);
void numberDesktopsChanged(uint old);
/**
* Signal emitted when a new window has been added to the Workspace.
* @param w The added window

View File

@ -183,7 +183,7 @@ bool Client::manage(Window w, bool isMapped)
if (on_all)
desk = NET::OnAllDesktops;
else if (on_current)
desk = workspace()->currentDesktop();
desk = VirtualDesktopManager::self()->current();
else if (maincl != NULL)
desk = maincl->desktop();
@ -207,10 +207,10 @@ bool Client::manage(Window w, bool isMapped)
}
if (desk == 0) // Assume window wants to be visible on the current desktop
desk = isDesktop() ? NET::OnAllDesktops : workspace()->currentDesktop();
desk = isDesktop() ? NET::OnAllDesktops : VirtualDesktopManager::self()->current();
desk = rules()->checkDesktop(desk, !isMapped);
if (desk != NET::OnAllDesktops) // Do range check
desk = qMax(1, qMin(workspace()->numberOfDesktops(), desk));
desk = qBound(1, desk, static_cast<int>(VirtualDesktopManager::self()->count()));
info->setDesktop(desk);
workspace()->updateOnAllDesktopsOfTransients(this); // SELI TODO
//onAllDesktopsChange(); // Decoration doesn't exist here yet
@ -551,7 +551,7 @@ bool Client::manage(Window w, bool isMapped)
} else if (allow) {
// also force if activation is allowed
if (!isOnCurrentDesktop()) {
workspace()->setCurrentDesktop(desktop());
VirtualDesktopManager::self()->setCurrent(desktop());
}
/*if (!isOnCurrentActivity()) {
workspace()->setCurrentActivity( activities().first() );

View File

@ -372,7 +372,7 @@ void Options::setRollOverDesktops(bool rollOverDesktops)
return;
}
m_rollOverDesktops = rollOverDesktops;
emit rollOverDesktopsChanged();
emit rollOverDesktopsChanged(m_rollOverDesktops);
}
void Options::setFocusStealingPreventionLevel(int focusStealingPreventionLevel)

View File

@ -924,7 +924,7 @@ Q_SIGNALS:
void centerSnapZoneChanged();
void snapOnlyWhenOverlappingChanged();
void showDesktopIsMinimizeAllChanged();
void rollOverDesktopsChanged();
void rollOverDesktopsChanged(bool enabled);
void focusStealingPreventionLevelChanged();
void legacyFullscreenSupportChanged();
void operationTitlebarDblClickChanged();

View File

@ -166,7 +166,7 @@ void Placement::placeSmart(Client* c, const QRect& area, Policy /*next*/)
long int overlap, min_overlap = 0;
int x_optimal, y_optimal;
int possible;
int desktop = c->desktop() == 0 || c->isOnAllDesktops() ? m_WorkspacePtr->currentDesktop() : c->desktop();
int desktop = c->desktop() == 0 || c->isOnAllDesktops() ? VirtualDesktopManager::self()->current() : c->desktop();
int cxl, cxr, cyt, cyb; //temp coords
int xl, xr, yt, yb; //temp coords
@ -320,7 +320,7 @@ void Placement::reinitCascading(int desktop)
// desktop == 0 - reinit all
if (desktop == 0) {
cci.clear();
for (int i = 0; i < m_WorkspacePtr->numberOfDesktops(); i++) {
for (uint i = 0; i < VirtualDesktopManager::self()->count(); ++i) {
DesktopCascadingInfo inf;
inf.pos = QPoint(-1, -1);
inf.col = 0;
@ -352,7 +352,7 @@ void Placement::placeCascaded(Client* c, QRect& area, Policy nextPlacement)
//CT how do I get from the 'Client' class the size that NW squarish "handle"
const QPoint delta = m_WorkspacePtr->cascadeOffset(c);
const int dn = c->desktop() == 0 || c->isOnAllDesktops() ? (m_WorkspacePtr->currentDesktop() - 1) : (c->desktop() - 1);
const int dn = c->desktop() == 0 || c->isOnAllDesktops() ? (VirtualDesktopManager::self()->current() - 1) : (c->desktop() - 1);
// get the maximum allowed windows space and desk's origin
QRect maxRect = checkArea(c, area);
@ -547,7 +547,7 @@ void Placement::cascadeDesktop()
{
// TODO XINERAMA this probably is not right for xinerama
Workspace *ws = Workspace::self();
const int desktop = ws->currentDesktop();
const int desktop = VirtualDesktopManager::self()->current();
reinitCascading(desktop);
// TODO: make area const once placeFoo methods are fixed to take a const QRect&
QRect area = ws->clientArea(PlacementArea, QPoint(0, 0), desktop);

View File

@ -35,6 +35,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "options.h"
#include "utils.h"
#include "workspace.h"
#include "virtualdesktops.h"
// Qt
#include <QtCore/QTimer>
@ -332,30 +333,31 @@ void ScreenEdge::check(const QPoint& pos, Time now, bool forceNoPushback)
void ScreenEdge::switchDesktop(ElectricBorder border, const QPoint& _pos)
{
QPoint pos = _pos;
int desk = Workspace::self()->currentDesktop();
VirtualDesktopManager *vds = VirtualDesktopManager::self();
int desk = vds->current();
const int OFFSET = 2;
if (border == ElectricLeft || border == ElectricTopLeft || border == ElectricBottomLeft) {
desk = Workspace::self()->desktopToLeft(desk, options->isRollOverDesktops());
desk = vds->toLeft(desk, options->isRollOverDesktops());
pos.setX(displayWidth() - 1 - OFFSET);
}
if (border == ElectricRight || border == ElectricTopRight || border == ElectricBottomRight) {
desk = Workspace::self()->desktopToRight(desk, options->isRollOverDesktops());
desk = vds->toRight(desk, options->isRollOverDesktops());
pos.setX(OFFSET);
}
if (border == ElectricTop || border == ElectricTopLeft || border == ElectricTopRight) {
desk = Workspace::self()->desktopAbove(desk, options->isRollOverDesktops());
desk = vds->above(desk, options->isRollOverDesktops());
pos.setY(displayHeight() - 1 - OFFSET);
}
if (border == ElectricBottom || border == ElectricBottomLeft || border == ElectricBottomRight) {
desk = Workspace::self()->desktopBelow(desk, options->isRollOverDesktops());
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
int desk_before = Workspace::self()->currentDesktop();
Workspace::self()->setCurrentDesktop(desk);
if (Workspace::self()->currentDesktop() != desk_before)
const uint desk_before = vds->current();
vds->setCurrent(desk);
if (vds->current() != desk_before)
QCursor::setPos(pos);
}

View File

@ -22,6 +22,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "workspace_wrapper.h"
#include "../client.h"
#include "../outline.h"
#include "../virtualdesktops.h"
#include <QtGui/QDesktopWidget>
@ -30,13 +31,14 @@ namespace KWin {
WorkspaceWrapper::WorkspaceWrapper(QObject* parent) : QObject(parent)
{
KWin::Workspace *ws = KWin::Workspace::self();
KWin::VirtualDesktopManager *vds = KWin::VirtualDesktopManager::self();
connect(ws, SIGNAL(desktopPresenceChanged(KWin::Client*,int)), SIGNAL(desktopPresenceChanged(KWin::Client*,int)));
connect(ws, SIGNAL(currentDesktopChanged(int,KWin::Client*)), SIGNAL(currentDesktopChanged(int,KWin::Client*)));
connect(ws, SIGNAL(clientAdded(KWin::Client*)), SIGNAL(clientAdded(KWin::Client*)));
connect(ws, SIGNAL(clientAdded(KWin::Client*)), SLOT(setupClientConnections(KWin::Client*)));
connect(ws, SIGNAL(clientRemoved(KWin::Client*)), SIGNAL(clientRemoved(KWin::Client*)));
connect(ws, SIGNAL(clientActivated(KWin::Client*)), SIGNAL(clientActivated(KWin::Client*)));
connect(ws, SIGNAL(numberDesktopsChanged(int)), SIGNAL(numberDesktopsChanged(int)));
connect(vds, SIGNAL(countChanged(uint,uint)), SIGNAL(numberDesktopsChanged(uint)));
connect(ws, SIGNAL(clientDemandsAttentionChanged(KWin::Client*,bool)), SIGNAL(clientDemandsAttentionChanged(KWin::Client*,bool)));
connect(ws, SIGNAL(currentActivityChanged(QString)), SIGNAL(currentActivityChanged(QString)));
connect(ws, SIGNAL(activityAdded(QString)), SIGNAL(activitiesChanged(QString)));
@ -50,18 +52,25 @@ WorkspaceWrapper::WorkspaceWrapper(QObject* parent) : QObject(parent)
}
}
#define GETTERSETTER( rettype, getterName, setterName ) \
rettype WorkspaceWrapper::getterName( ) const { \
return Workspace::self()->getterName(); \
} \
void WorkspaceWrapper::setterName( rettype val ) { \
Workspace::self()->setterName( val ); \
int WorkspaceWrapper::currentDesktop() const
{
return VirtualDesktopManager::self()->current();
}
GETTERSETTER(int, numberOfDesktops, setNumberOfDesktops)
GETTERSETTER(int, currentDesktop, setCurrentDesktop)
int WorkspaceWrapper::numberOfDesktops() const
{
return VirtualDesktopManager::self()->count();
}
#undef GETTERSETTER
void WorkspaceWrapper::setCurrentDesktop(int desktop)
{
VirtualDesktopManager::self()->setCurrent(desktop);
}
void WorkspaceWrapper::setNumberOfDesktops(int count)
{
VirtualDesktopManager::self()->setCount(count);
}
#define GETTER( rettype, getterName ) \
rettype WorkspaceWrapper::getterName( ) const { \
@ -69,11 +78,6 @@ rettype WorkspaceWrapper::getterName( ) const { \
}
GETTER(KWin::Client*, activeClient)
GETTER(QList< KWin::Client* >, clientList)
GETTER(int, workspaceWidth)
GETTER(int, workspaceHeight)
GETTER(QSize, desktopGridSize)
GETTER(int, desktopGridWidth)
GETTER(int, desktopGridHeight)
GETTER(int, activeScreen)
GETTER(int, numScreens)
GETTER(QString, currentActivity)
@ -86,13 +90,6 @@ void WorkspaceWrapper::name( ) { \
Workspace::self()->name(); \
}
SLOTWRAPPER(slotSwitchDesktopNext)
SLOTWRAPPER(slotSwitchDesktopPrevious)
SLOTWRAPPER(slotSwitchDesktopRight)
SLOTWRAPPER(slotSwitchDesktopLeft)
SLOTWRAPPER(slotSwitchDesktopUp)
SLOTWRAPPER(slotSwitchDesktopDown)
SLOTWRAPPER(slotSwitchToNextScreen)
SLOTWRAPPER(slotWindowToNextScreen)
SLOTWRAPPER(slotToggleShowDesktop)
@ -148,6 +145,20 @@ SLOTWRAPPER(slotWindowToDesktopDown)
#undef SLOTWRAPPER
#define SLOTWRAPPER( name, direction ) \
void WorkspaceWrapper::name( ) { \
VirtualDesktopManager::self()->moveTo<direction>(options->isRollOverDesktops()); \
}
SLOTWRAPPER(slotSwitchDesktopNext, DesktopNext)
SLOTWRAPPER(slotSwitchDesktopPrevious, DesktopPrevious)
SLOTWRAPPER(slotSwitchDesktopRight, DesktopRight)
SLOTWRAPPER(slotSwitchDesktopLeft, DesktopLeft)
SLOTWRAPPER(slotSwitchDesktopUp, DesktopAbove)
SLOTWRAPPER(slotSwitchDesktopDown, DesktopBelow)
#undef SLOTWRAPPER
void WorkspaceWrapper::setActiveClient(KWin::Client* client)
{
KWin::Workspace::self()->activateClient(client);
@ -190,7 +201,7 @@ QRect WorkspaceWrapper::clientArea(ClientAreaOption option, int screen, int desk
QString WorkspaceWrapper::desktopName(int desktop) const
{
return Workspace::self()->desktopName(desktop);
return VirtualDesktopManager::self()->name(desktop);
}
QString WorkspaceWrapper::supportInformation() const
@ -227,4 +238,29 @@ Client *WorkspaceWrapper::getClient(qulonglong windowId)
return Workspace::self()->findClient(WindowMatchPredicate(windowId));
}
QSize WorkspaceWrapper::desktopGridSize() const
{
return VirtualDesktopManager::self()->grid().size();
}
int WorkspaceWrapper::desktopGridWidth() const
{
return desktopGridSize().width();
}
int WorkspaceWrapper::desktopGridHeight() const
{
return desktopGridSize().height();
}
int WorkspaceWrapper::workspaceHeight() const
{
return desktopGridHeight() * displayHeight();
}
int WorkspaceWrapper::workspaceWidth() const
{
return desktopGridWidth() * displayWidth();
}
} // KWin

View File

@ -89,7 +89,7 @@ signals:
* To get the current number of desktops use the property desktops.
* @param oldNumberOfDesktops The previous number of desktops.
**/
void numberDesktopsChanged(int oldNumberOfDesktops);
void numberDesktopsChanged(uint oldNumberOfDesktops);
/**
* The demands attention state for Client @p c changed to @p set.
* @param c The Client for which demands attention changed

4
sm.cpp
View File

@ -104,7 +104,7 @@ void Workspace::storeSession(KConfig* config, SMSavePhase phase)
// but both Qt and KDE treat phase1 and phase2 separately,
// which results in different sessionkey and different config file :(
session_active_client = active_client;
session_desktop = currentDesktop();
session_desktop = VirtualDesktopManager::self()->current();
} else if (phase == SMSavePhase2) {
cg.writeEntry("count", count);
cg.writeEntry("active", session_active_client);
@ -112,7 +112,7 @@ void Workspace::storeSession(KConfig* config, SMSavePhase phase)
} else { // SMSavePhase2Full
cg.writeEntry("count", count);
cg.writeEntry("active", session_active_client);
cg.writeEntry("desktop", currentDesktop());
cg.writeEntry("desktop", VirtualDesktopManager::self()->current());
}
}

View File

@ -30,6 +30,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
// kwin
#include "client.h"
#include "effects.h"
#include "virtualdesktops.h"
#include "workspace.h"
// Qt
#include <QAction>
@ -76,21 +77,21 @@ int TabBoxHandlerImpl::activeScreen() const
int TabBoxHandlerImpl::currentDesktop() const
{
return Workspace::self()->currentDesktop();
return VirtualDesktopManager::self()->current();
}
QString TabBoxHandlerImpl::desktopName(TabBoxClient* client) const
{
if (TabBoxClientImpl* c = static_cast< TabBoxClientImpl* >(client)) {
if (!c->client()->isOnAllDesktops())
return Workspace::self()->desktopName(c->client()->desktop());
return VirtualDesktopManager::self()->name(c->client()->desktop());
}
return Workspace::self()->desktopName(Workspace::self()->currentDesktop());
return VirtualDesktopManager::self()->name(VirtualDesktopManager::self()->current());
}
QString TabBoxHandlerImpl::desktopName(int desktop) const
{
return Workspace::self()->desktopName(desktop);
return VirtualDesktopManager::self()->name(desktop);
}
QWeakPointer<TabBoxClient> TabBoxHandlerImpl::nextClientFocusChain(TabBoxClient* client) const
@ -127,7 +128,7 @@ int TabBoxHandlerImpl::nextDesktopFocusChain(int desktop) const
int TabBoxHandlerImpl::numberOfDesktops() const
{
return Workspace::self()->numberOfDesktops();
return VirtualDesktopManager::self()->count();
}
QWeakPointer<TabBoxClient> TabBoxHandlerImpl::activeClient() const
@ -561,7 +562,7 @@ void TabBox::reset(bool partial_reset)
m_tabBox->createModel();
if (!partial_reset)
setCurrentDesktop(Workspace::self()->currentDesktop());
setCurrentDesktop(VirtualDesktopManager::self()->current());
break;
}
@ -1499,14 +1500,14 @@ void TabBox::keyRelease(const XKeyEvent& ev)
m_tabGrab = old_tab_grab;
if (desktop != -1) {
setCurrentDesktop(desktop);
Workspace::self()->setCurrentDesktop(desktop);
VirtualDesktopManager::self()->setCurrent(desktop);
}
}
}
int TabBox::nextDesktopFocusChain(int iDesktop) const
{
const QVector<int> &desktopFocusChain = Workspace::self()->desktopFocusChain();
const QVector<uint> &desktopFocusChain = Workspace::self()->desktopFocusChain();
int i = desktopFocusChain.indexOf(iDesktop);
if (i >= 0 && i + 1 < desktopFocusChain.size())
return desktopFocusChain[i+1];
@ -1518,30 +1519,26 @@ int TabBox::nextDesktopFocusChain(int iDesktop) const
int TabBox::previousDesktopFocusChain(int iDesktop) const
{
const QVector<int> &desktopFocusChain = Workspace::self()->desktopFocusChain();
const QVector<uint> &desktopFocusChain = Workspace::self()->desktopFocusChain();
int i = desktopFocusChain.indexOf(iDesktop);
if (i - 1 >= 0)
return desktopFocusChain[i-1];
else if (desktopFocusChain.size() > 0)
return desktopFocusChain[desktopFocusChain.size()-1];
else
return Workspace::self()->numberOfDesktops();
return VirtualDesktopManager::self()->count();
}
int TabBox::nextDesktopStatic(int iDesktop) const
{
int i = ++iDesktop;
if (i > Workspace::self()->numberOfDesktops())
i = 1;
return i;
DesktopNext functor;
return functor(iDesktop, true);
}
int TabBox::previousDesktopStatic(int iDesktop) const
{
int i = --iDesktop;
if (i < 1)
i = Workspace::self()->numberOfDesktops();
return i;
DesktopPrevious functor;
return functor(iDesktop, true);
}
/*!

View File

@ -18,3 +18,18 @@ set( testWindowPaintData_SRCS test_window_paint_data.cpp )
kde4_add_unit_test( testWindowPaintData TESTNAME kwin-TestWindowPaintData ${testWindowPaintData_SRCS} )
target_link_libraries( testWindowPaintData kwineffects ${QT_QTCORE_LIBRARY} ${QT_QTGUI_LIBRARY} ${QT_QTTEST_LIBRARY} )
########################################################
# Test VirtualDesktopManager
########################################################
set( testVirtualDesktops_SRCS
test_virtual_desktops.cpp
../virtualdesktops.cpp
)
kde4_add_unit_test( testVirtualDesktops TESTNAME kwin-TestVirtualDesktops ${testVirtualDesktops_SRCS} )
target_link_libraries( testVirtualDesktops
${KDE4_KDEUI_LIBS}
${QT_QTCORE_LIBRARY}
${QT_QTTEST_LIBRARY}
)

View File

@ -0,0 +1,652 @@
/********************************************************************
KWin - the KDE window manager
This file is part of the KDE project.
Copyright (C) 2012 Martin Gräßlin <mgraesslin@kde.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************/
#include "../virtualdesktops.h"
// for mocking
#include "../notifications.h"
// KDE
#include <KDE/KAction>
#include <KDE/KActionCollection>
#include <KDE/KConfigGroup>
#include <QtTest/QtTest>
namespace KWin {
int screen_number = 0;
bool Notify::raise(Event e, const QString& message, Client* c)
{
Q_UNUSED(e)
Q_UNUSED(message)
Q_UNUSED(c)
return false;
}
}
Q_DECLARE_METATYPE(Qt::Orientation)
using namespace KWin;
class TestVirtualDesktops : public QObject
{
Q_OBJECT
private slots:
void init();
void cleanup();
void count_data();
void count();
void navigationWrapsAround_data();
void navigationWrapsAround();
void current_data();
void current();
void currentChangeOnCountChange_data();
void currentChangeOnCountChange();
void next_data();
void next();
void previous_data();
void previous();
void left_data();
void left();
void right_data();
void right();
void above_data();
void above();
void below_data();
void below();
void updateGrid_data();
void updateGrid();
void updateLayout_data();
void updateLayout();
void name_data();
void name();
void switchToShortcuts();
void load();
void save();
private:
void addDirectionColumns();
template<typename T>
void testDirection(const QString &actionName);
};
void TestVirtualDesktops::init()
{
VirtualDesktopManager::create();
screen_number = 0;
}
void TestVirtualDesktops::cleanup()
{
delete VirtualDesktopManager::self();
}
static const uint s_countInitValue = 2;
void TestVirtualDesktops::count_data()
{
QTest::addColumn<uint>("request");
QTest::addColumn<uint>("result");
QTest::addColumn<bool>("signal");
QTest::addColumn<bool>("removedSignal");
QTest::newRow("Minimum") << (uint)1 << (uint)1 << true << true;
QTest::newRow("Below Minimum") << (uint)0 << (uint)1 << true << true;
QTest::newRow("Normal Value") << (uint)10 << (uint)10 << true << false;
QTest::newRow("Maximum") << VirtualDesktopManager::maximum() << VirtualDesktopManager::maximum() << true << false;
QTest::newRow("Above Maximum") << VirtualDesktopManager::maximum() + 1 << VirtualDesktopManager::maximum() << true << false;
QTest::newRow("Unchanged") << s_countInitValue << s_countInitValue << false << false;
}
void TestVirtualDesktops::count()
{
VirtualDesktopManager *vds = VirtualDesktopManager::self();
QCOMPARE(vds->count(), (uint)0);
// start with a useful desktop count
vds->setCount(s_countInitValue);
QSignalSpy spy(vds, SIGNAL(countChanged(uint, uint)));
QSignalSpy desktopsRemoved(vds, SIGNAL(desktopsRemoved(uint)));
QFETCH(uint, request);
QFETCH(uint, result);
QFETCH(bool, signal);
QFETCH(bool, removedSignal);
vds->setCount(request);
QCOMPARE(vds->count(), result);
QCOMPARE(spy.isEmpty(), !signal);
if (!spy.isEmpty()) {
QList<QVariant> arguments = spy.takeFirst();
QCOMPARE(arguments.count(), 2);
QCOMPARE(arguments.at(0).type(), QVariant::UInt);
QCOMPARE(arguments.at(1).type(), QVariant::UInt);
QCOMPARE(arguments.at(0).toUInt(), s_countInitValue);
QCOMPARE(arguments.at(1).toUInt(), result);
}
QCOMPARE(desktopsRemoved.isEmpty(), !removedSignal);
if (!desktopsRemoved.isEmpty()) {
QList<QVariant> arguments = desktopsRemoved.takeFirst();
QCOMPARE(arguments.count(), 1);
QCOMPARE(arguments.at(0).type(), QVariant::UInt);
QCOMPARE(arguments.at(0).toUInt(), s_countInitValue);
}
}
void TestVirtualDesktops::navigationWrapsAround_data()
{
QTest::addColumn<bool>("init");
QTest::addColumn<bool>("request");
QTest::addColumn<bool>("result");
QTest::addColumn<bool>("signal");
QTest::newRow("enable") << false << true << true << true;
QTest::newRow("disable") << true << false << false << true;
QTest::newRow("keep enabled") << true << true << true << false;
QTest::newRow("keep disabled") << false << false << false << false;
}
void TestVirtualDesktops::navigationWrapsAround()
{
VirtualDesktopManager *vds = VirtualDesktopManager::self();
QCOMPARE(vds->isNavigationWrappingAround(), false);
QFETCH(bool, init);
QFETCH(bool, request);
QFETCH(bool, result);
QFETCH(bool, signal);
// set to init value
vds->setNavigationWrappingAround(init);
QCOMPARE(vds->isNavigationWrappingAround(), init);
QSignalSpy spy(vds, SIGNAL(navigationWrappingAroundChanged()));
vds->setNavigationWrappingAround(request);
QCOMPARE(vds->isNavigationWrappingAround(), result);
QCOMPARE(spy.isEmpty(), !signal);
}
void TestVirtualDesktops::current_data()
{
QTest::addColumn<uint>("count");
QTest::addColumn<uint>("init");
QTest::addColumn<uint>("request");
QTest::addColumn<uint>("result");
QTest::addColumn<bool>("signal");
QTest::newRow("lower") << (uint)4 << (uint)3 << (uint)2 << (uint)2 << true;
QTest::newRow("higher") << (uint)4 << (uint)1 << (uint)2 << (uint)2 << true;
QTest::newRow("maximum") << (uint)4 << (uint)1 << (uint)4 << (uint)4 << true;
QTest::newRow("above maximum") << (uint)4 << (uint)1 << (uint)5 << (uint)1 << false;
QTest::newRow("minimum") << (uint)4 << (uint)2 << (uint)1 << (uint)1 << true;
QTest::newRow("below minimum") << (uint)4 << (uint)2 << (uint)0 << (uint)2 << false;
QTest::newRow("unchanged") << (uint)4 << (uint)2 << (uint)2 << (uint)2 << false;
}
void TestVirtualDesktops::current()
{
VirtualDesktopManager *vds = VirtualDesktopManager::self();
QCOMPARE(vds->current(), (uint)0);
QFETCH(uint, count);
vds->setCount(count);
QFETCH(uint, init);
QVERIFY(vds->setCurrent(init));
QCOMPARE(vds->current(), init);
QSignalSpy spy(vds, SIGNAL(currentChanged(uint, uint)));
QFETCH(uint, request);
QFETCH(uint, result);
QFETCH(bool, signal);
QCOMPARE(vds->setCurrent(request), signal);
QCOMPARE(vds->current(), result);
QCOMPARE(spy.isEmpty(), !signal);
if (!spy.isEmpty()) {
QList<QVariant> arguments = spy.takeFirst();
QCOMPARE(arguments.count(), 2);
QCOMPARE(arguments.at(0).type(), QVariant::UInt);
QCOMPARE(arguments.at(1).type(), QVariant::UInt);
QCOMPARE(arguments.at(0).toUInt(), init);
QCOMPARE(arguments.at(1).toUInt(), result);
}
}
void TestVirtualDesktops::currentChangeOnCountChange_data()
{
QTest::addColumn<uint>("initCount");
QTest::addColumn<uint>("initCurrent");
QTest::addColumn<uint>("request");
QTest::addColumn<uint>("current");
QTest::addColumn<bool>("signal");
QTest::newRow("increment") << (uint)4 << (uint)2 << (uint)5 << (uint)2 << false;
QTest::newRow("increment on last") << (uint)4 << (uint)4 << (uint)5 << (uint)4 << false;
QTest::newRow("decrement") << (uint)4 << (uint)2 << (uint)3 << (uint)2 << false;
QTest::newRow("decrement on second last") << (uint)4 << (uint)3 << (uint)3 << (uint)3 << false;
QTest::newRow("decrement on last") << (uint)4 << (uint)4 << (uint)3 << (uint)3 << true;
QTest::newRow("multiple decrement") << (uint)4 << (uint)2 << (uint)1 << (uint)1 << true;
}
void TestVirtualDesktops::currentChangeOnCountChange()
{
VirtualDesktopManager *vds = VirtualDesktopManager::self();
QFETCH(uint, initCount);
QFETCH(uint, initCurrent);
vds->setCount(initCount);
vds->setCurrent(initCurrent);
QSignalSpy spy(vds, SIGNAL(currentChanged(uint, uint)));
QFETCH(uint, request);
QFETCH(uint, current);
QFETCH(bool, signal);
vds->setCount(request);
QCOMPARE(vds->current(), current);
QCOMPARE(spy.isEmpty(), !signal);
}
void TestVirtualDesktops::addDirectionColumns()
{
QTest::addColumn<uint>("initCount");
QTest::addColumn<uint>("initCurrent");
QTest::addColumn<bool>("wrap");
QTest::addColumn<uint>("result");
}
template <typename T>
void TestVirtualDesktops::testDirection(const QString &actionName)
{
VirtualDesktopManager *vds = VirtualDesktopManager::self();
QFETCH(uint, initCount);
QFETCH(uint, initCurrent);
vds->setCount(initCount);
vds->setCurrent(initCurrent);
QFETCH(bool, wrap);
QFETCH(uint, result);
T functor;
QCOMPARE(functor(0, wrap), result);
vds->setNavigationWrappingAround(wrap);
QScopedPointer<KActionCollection> keys(new KActionCollection(this));
vds->initShortcuts(keys.data());
QAction *action = keys->action(actionName);
QVERIFY(action);
action->trigger();
QCOMPARE(vds->current(), result);
QCOMPARE(functor(initCurrent, wrap), result);
}
void TestVirtualDesktops::next_data()
{
addDirectionColumns();
QTest::newRow("one desktop, wrap") << (uint)1 << (uint)1 << true << (uint)1;
QTest::newRow("one desktop, no wrap") << (uint)1 << (uint)1 << false << (uint)1;
QTest::newRow("desktops, wrap") << (uint)4 << (uint)1 << true << (uint)2;
QTest::newRow("desktops, no wrap") << (uint)4 << (uint)1 << false << (uint)2;
QTest::newRow("desktops at end, wrap") << (uint)4 << (uint)4 << true << (uint)1;
QTest::newRow("desktops at end, no wrap") << (uint)4 << (uint)4 << false << (uint)4;
}
void TestVirtualDesktops::next()
{
testDirection<DesktopNext>("Switch to Next Desktop");
}
void TestVirtualDesktops::previous_data()
{
addDirectionColumns();
QTest::newRow("one desktop, wrap") << (uint)1 << (uint)1 << true << (uint)1;
QTest::newRow("one desktop, no wrap") << (uint)1 << (uint)1 << false << (uint)1;
QTest::newRow("desktops, wrap") << (uint)4 << (uint)3 << true << (uint)2;
QTest::newRow("desktops, no wrap") << (uint)4 << (uint)3 << false << (uint)2;
QTest::newRow("desktops at start, wrap") << (uint)4 << (uint)1 << true << (uint)4;
QTest::newRow("desktops at start, no wrap") << (uint)4 << (uint)1 << false << (uint)1;
}
void TestVirtualDesktops::previous()
{
testDirection<DesktopPrevious>("Switch to Previous Desktop");
}
void TestVirtualDesktops::left_data()
{
addDirectionColumns();
QTest::newRow("one desktop, wrap") << (uint)1 << (uint)1 << true << (uint)1;
QTest::newRow("one desktop, no wrap") << (uint)1 << (uint)1 << false << (uint)1;
QTest::newRow("desktops, wrap, 1st row") << (uint)4 << (uint)2 << true << (uint)1;
QTest::newRow("desktops, no wrap, 1st row") << (uint)4 << (uint)2 << false << (uint)1;
QTest::newRow("desktops, wrap, 2nd row") << (uint)4 << (uint)4 << true << (uint)3;
QTest::newRow("desktops, no wrap, 2nd row") << (uint)4 << (uint)4 << false << (uint)3;
QTest::newRow("desktops at start, wrap, 1st row") << (uint)4 << (uint)1 << true << (uint)2;
QTest::newRow("desktops at start, no wrap, 1st row") << (uint)4 << (uint)1 << false << (uint)1;
QTest::newRow("desktops at start, wrap, 2nd row") << (uint)4 << (uint)3 << true << (uint)4;
QTest::newRow("desktops at start, no wrap, 2nd row") << (uint)4 << (uint)3 << false << (uint)3;
QTest::newRow("non symmetric, start") << (uint)5 << (uint)5 << false << (uint)4;
QTest::newRow("non symmetric, end, no wrap") << (uint)5 << (uint)4 << false << (uint)4;
QTest::newRow("non symmetric, end, wrap") << (uint)5 << (uint)4 << true << (uint)5;
}
void TestVirtualDesktops::left()
{
testDirection<DesktopLeft>("Switch One Desktop to the Left");
}
void TestVirtualDesktops::right_data()
{
addDirectionColumns();
QTest::newRow("one desktop, wrap") << (uint)1 << (uint)1 << true << (uint)1;
QTest::newRow("one desktop, no wrap") << (uint)1 << (uint)1 << false << (uint)1;
QTest::newRow("desktops, wrap, 1st row") << (uint)4 << (uint)1 << true << (uint)2;
QTest::newRow("desktops, no wrap, 1st row") << (uint)4 << (uint)1 << false << (uint)2;
QTest::newRow("desktops, wrap, 2nd row") << (uint)4 << (uint)3 << true << (uint)4;
QTest::newRow("desktops, no wrap, 2nd row") << (uint)4 << (uint)3 << false << (uint)4;
QTest::newRow("desktops at start, wrap, 1st row") << (uint)4 << (uint)2 << true << (uint)1;
QTest::newRow("desktops at start, no wrap, 1st row") << (uint)4 << (uint)2 << false << (uint)2;
QTest::newRow("desktops at start, wrap, 2nd row") << (uint)4 << (uint)4 << true << (uint)3;
QTest::newRow("desktops at start, no wrap, 2nd row") << (uint)4 << (uint)4 << false << (uint)4;
QTest::newRow("non symmetric, start") << (uint)5 << (uint)4 << false << (uint)5;
QTest::newRow("non symmetric, end, no wrap") << (uint)5 << (uint)5 << false << (uint)5;
QTest::newRow("non symmetric, end, wrap") << (uint)5 << (uint)5 << true << (uint)4;
}
void TestVirtualDesktops::right()
{
testDirection<DesktopRight>("Switch One Desktop to the Right");
}
void TestVirtualDesktops::above_data()
{
addDirectionColumns();
QTest::newRow("one desktop, wrap") << (uint)1 << (uint)1 << true << (uint)1;
QTest::newRow("one desktop, no wrap") << (uint)1 << (uint)1 << false << (uint)1;
QTest::newRow("desktops, wrap, 1st column") << (uint)4 << (uint)3 << true << (uint)1;
QTest::newRow("desktops, no wrap, 1st column") << (uint)4 << (uint)3 << false << (uint)1;
QTest::newRow("desktops, wrap, 2nd column") << (uint)4 << (uint)4 << true << (uint)2;
QTest::newRow("desktops, no wrap, 2nd column") << (uint)4 << (uint)4 << false << (uint)2;
QTest::newRow("desktops at start, wrap, 1st column") << (uint)4 << (uint)1 << true << (uint)3;
QTest::newRow("desktops at start, no wrap, 1st column") << (uint)4 << (uint)1 << false << (uint)1;
QTest::newRow("desktops at start, wrap, 2nd column") << (uint)4 << (uint)2 << true << (uint)4;
QTest::newRow("desktops at start, no wrap, 2nd column") << (uint)4 << (uint)2 << false << (uint)2;
}
void TestVirtualDesktops::above()
{
testDirection<DesktopAbove>("Switch One Desktop Up");
}
void TestVirtualDesktops::below_data()
{
addDirectionColumns();
QTest::newRow("one desktop, wrap") << (uint)1 << (uint)1 << true << (uint)1;
QTest::newRow("one desktop, no wrap") << (uint)1 << (uint)1 << false << (uint)1;
QTest::newRow("desktops, wrap, 1st column") << (uint)4 << (uint)1 << true << (uint)3;
QTest::newRow("desktops, no wrap, 1st column") << (uint)4 << (uint)1 << false << (uint)3;
QTest::newRow("desktops, wrap, 2nd column") << (uint)4 << (uint)2 << true << (uint)4;
QTest::newRow("desktops, no wrap, 2nd column") << (uint)4 << (uint)2 << false << (uint)4;
QTest::newRow("desktops at start, wrap, 1st column") << (uint)4 << (uint)3 << true << (uint)1;
QTest::newRow("desktops at start, no wrap, 1st column") << (uint)4 << (uint)3 << false << (uint)3;
QTest::newRow("desktops at start, wrap, 2nd column") << (uint)4 << (uint)4 << true << (uint)2;
QTest::newRow("desktops at start, no wrap, 2nd column") << (uint)4 << (uint)4 << false << (uint)4;
}
void TestVirtualDesktops::below()
{
testDirection<DesktopBelow>("Switch One Desktop Down");
}
void TestVirtualDesktops::updateGrid_data()
{
QTest::addColumn<uint>("initCount");
QTest::addColumn<QSize>("size");
QTest::addColumn<Qt::Orientation>("orientation");
QTest::addColumn<QPoint>("coords");
QTest::addColumn<uint>("desktop");
const Qt::Orientation h = Qt::Horizontal;
const Qt::Orientation v = Qt::Vertical;
QTest::newRow("one desktop, h") << (uint)1 << QSize(1, 1) << h << QPoint(0, 0) << (uint)1;
QTest::newRow("one desktop, v") << (uint)1 << QSize(1, 1) << v << QPoint(0, 0) << (uint)1;
QTest::newRow("one desktop, h, 0") << (uint)1 << QSize(1, 1) << h << QPoint(1, 0) << (uint)0;
QTest::newRow("one desktop, v, 0") << (uint)1 << QSize(1, 1) << v << QPoint(0, 1) << (uint)0;
QTest::newRow("two desktops, h, 1") << (uint)2 << QSize(2, 1) << h << QPoint(0, 0) << (uint)1;
QTest::newRow("two desktops, h, 2") << (uint)2 << QSize(2, 1) << h << QPoint(1, 0) << (uint)2;
QTest::newRow("two desktops, h, 3") << (uint)2 << QSize(2, 1) << h << QPoint(0, 1) << (uint)0;
QTest::newRow("two desktops, h, 4") << (uint)2 << QSize(2, 1) << h << QPoint(2, 0) << (uint)0;
QTest::newRow("two desktops, v, 1") << (uint)2 << QSize(2, 1) << v << QPoint(0, 0) << (uint)1;
QTest::newRow("two desktops, v, 2") << (uint)2 << QSize(2, 1) << v << QPoint(1, 0) << (uint)2;
QTest::newRow("two desktops, v, 3") << (uint)2 << QSize(2, 1) << v << QPoint(0, 1) << (uint)0;
QTest::newRow("two desktops, v, 4") << (uint)2 << QSize(2, 1) << v << QPoint(2, 0) << (uint)0;
QTest::newRow("four desktops, h, one row, 1") << (uint)4 << QSize(4, 1) << h << QPoint(0, 0) << (uint)1;
QTest::newRow("four desktops, h, one row, 2") << (uint)4 << QSize(4, 1) << h << QPoint(1, 0) << (uint)2;
QTest::newRow("four desktops, h, one row, 3") << (uint)4 << QSize(4, 1) << h << QPoint(2, 0) << (uint)3;
QTest::newRow("four desktops, h, one row, 4") << (uint)4 << QSize(4, 1) << h << QPoint(3, 0) << (uint)4;
QTest::newRow("four desktops, v, one column, 1") << (uint)4 << QSize(1, 4) << v << QPoint(0, 0) << (uint)1;
QTest::newRow("four desktops, v, one column, 2") << (uint)4 << QSize(1, 4) << v << QPoint(0, 1) << (uint)2;
QTest::newRow("four desktops, v, one column, 3") << (uint)4 << QSize(1, 4) << v << QPoint(0, 2) << (uint)3;
QTest::newRow("four desktops, v, one column, 4") << (uint)4 << QSize(1, 4) << v << QPoint(0, 3) << (uint)4;
QTest::newRow("four desktops, h, grid, 1") << (uint)4 << QSize(2, 2) << h << QPoint(0, 0) << (uint)1;
QTest::newRow("four desktops, h, grid, 2") << (uint)4 << QSize(2, 2) << h << QPoint(1, 0) << (uint)2;
QTest::newRow("four desktops, h, grid, 3") << (uint)4 << QSize(2, 2) << h << QPoint(0, 1) << (uint)3;
QTest::newRow("four desktops, h, grid, 4") << (uint)4 << QSize(2, 2) << h << QPoint(1, 1) << (uint)4;
QTest::newRow("four desktops, h, grid, 0/3") << (uint)4 << QSize(2, 2) << h << QPoint(0, 3) << (uint)0;
QTest::newRow("three desktops, h, grid, 1") << (uint)3 << QSize(2, 2) << h << QPoint(0, 0) << (uint)1;
QTest::newRow("three desktops, h, grid, 2") << (uint)3 << QSize(2, 2) << h << QPoint(1, 0) << (uint)2;
QTest::newRow("three desktops, h, grid, 3") << (uint)3 << QSize(2, 2) << h << QPoint(0, 1) << (uint)3;
QTest::newRow("three desktops, h, grid, 4") << (uint)3 << QSize(2, 2) << h << QPoint(1, 1) << (uint)0;
}
void TestVirtualDesktops::updateGrid()
{
VirtualDesktopManager *vds = VirtualDesktopManager::self();
QFETCH(uint, initCount);
vds->setCount(initCount);
VirtualDesktopGrid grid;
QFETCH(QSize, size);
QFETCH(Qt::Orientation, orientation);
grid.update(size, orientation);
QCOMPARE(grid.size(), size);
QCOMPARE(grid.width(), size.width());
QCOMPARE(grid.height(), size.height());
QFETCH(QPoint, coords);
QFETCH(uint, desktop);
QCOMPARE(grid.at(coords), desktop);
if (desktop != 0) {
QCOMPARE(grid.gridCoords(desktop), coords);
}
}
void TestVirtualDesktops::updateLayout_data()
{
QTest::addColumn<uint>("desktop");
QTest::addColumn<QSize>("result");
QTest::newRow("01") << (uint)1 << QSize(1, 2);
QTest::newRow("02") << (uint)2 << QSize(1, 2);
QTest::newRow("03") << (uint)3 << QSize(2, 2);
QTest::newRow("04") << (uint)4 << QSize(2, 2);
QTest::newRow("05") << (uint)5 << QSize(3, 2);
QTest::newRow("06") << (uint)6 << QSize(3, 2);
QTest::newRow("07") << (uint)7 << QSize(4, 2);
QTest::newRow("08") << (uint)8 << QSize(4, 2);
QTest::newRow("09") << (uint)9 << QSize(5, 2);
QTest::newRow("10") << (uint)10 << QSize(5, 2);
QTest::newRow("11") << (uint)11 << QSize(6, 2);
QTest::newRow("12") << (uint)12 << QSize(6, 2);
QTest::newRow("13") << (uint)13 << QSize(7, 2);
QTest::newRow("14") << (uint)14 << QSize(7, 2);
QTest::newRow("15") << (uint)15 << QSize(8, 2);
QTest::newRow("16") << (uint)16 << QSize(8, 2);
QTest::newRow("17") << (uint)17 << QSize(9, 2);
QTest::newRow("18") << (uint)18 << QSize(9, 2);
QTest::newRow("19") << (uint)19 << QSize(10, 2);
QTest::newRow("20") << (uint)20 << QSize(10, 2);
}
void TestVirtualDesktops::updateLayout()
{
VirtualDesktopManager *vds = VirtualDesktopManager::self();
QSignalSpy spy(vds, SIGNAL(layoutChanged(int, int)));
// call update layout - implicitly through setCount
QFETCH(uint, desktop);
QFETCH(QSize, result);
vds->setCount(desktop);
QCOMPARE(vds->grid().size(), result);
QCOMPARE(spy.count(), 1);
const QVariantList &arguments = spy.at(0);
QCOMPARE(arguments.at(0).toInt(), result.width());
QCOMPARE(arguments.at(1).toInt(), result.height());
// calling update layout again should not change anything
vds->updateLayout();
QCOMPARE(vds->grid().size(), result);
QCOMPARE(spy.count(), 2);
const QVariantList &arguments2 = spy.at(1);
QCOMPARE(arguments2.at(0).toInt(), result.width());
QCOMPARE(arguments2.at(1).toInt(), result.height());
}
void TestVirtualDesktops::name_data()
{
QTest::addColumn<uint>("initCount");
QTest::addColumn<uint>("desktop");
QTest::addColumn<QString>("desktopName");
QTest::newRow("desktop 1") << (uint)4 << (uint)1 << "Desktop 1";
QTest::newRow("desktop 2") << (uint)4 << (uint)2 << "Desktop 2";
QTest::newRow("desktop 3") << (uint)4 << (uint)3 << "Desktop 3";
QTest::newRow("desktop 4") << (uint)4 << (uint)4 << "Desktop 4";
QTest::newRow("desktop 5") << (uint)4 << (uint)5 << "Desktop 5";
}
void TestVirtualDesktops::name()
{
VirtualDesktopManager *vds = VirtualDesktopManager::self();
QFETCH(uint, initCount);
vds->setCount(initCount);
QFETCH(uint, desktop);
QTEST(vds->name(desktop), "desktopName");
}
void TestVirtualDesktops::switchToShortcuts()
{
QScopedPointer<KActionCollection> keys(new KActionCollection(this));
VirtualDesktopManager *vds = VirtualDesktopManager::self();
vds->setCount(vds->maximum());
vds->setCurrent(vds->maximum());
QCOMPARE(vds->current(), vds->maximum());
vds->initShortcuts(keys.data());
const QString toDesktop = "Switch to Desktop %1";
for (uint i=1; i<=vds->maximum(); ++i) {
const QString desktop(toDesktop.arg(i));
QAction *action = keys->action(desktop);
QVERIFY2(action, desktop.toUtf8().constData());
action->trigger();
QCOMPARE(vds->current(), i);
}
// test switchTo with incorrect data in QAction
KAction *action = keys->addAction("wrong", vds, SLOT(slotSwitchTo()));
action->trigger();
// should still be on max
QCOMPARE(vds->current(), vds->maximum());
// invoke switchTo not from a QAction
QMetaObject::invokeMethod(vds, "slotSwitchTo");
// should still be on max
QCOMPARE(vds->current(), vds->maximum());
}
void TestVirtualDesktops::load()
{
VirtualDesktopManager *vds = VirtualDesktopManager::self();
// no config yet, load should not change anything
vds->load();
QCOMPARE(vds->count(), (uint)0);
// empty config should create one desktop
KSharedConfig::Ptr config = KSharedConfig::openConfig(QString(), KConfig::SimpleConfig);
vds->setConfig(config);
vds->load();
QCOMPARE(vds->count(), (uint)1);
// setting a sensible number
config->group("Desktops").writeEntry("Number", 4);
vds->load();
QCOMPARE(vds->count(), (uint)4);
// setting the screen number should reset to one desktop as config value is missing
screen_number = 2;
vds->load();
QCOMPARE(vds->count(), (uint)1);
// creating the respective group should properly load
config->group("Desktops-screen-2").writeEntry("Number", 5);
vds->load();
QCOMPARE(vds->count(), (uint)5);
}
void TestVirtualDesktops::save()
{
VirtualDesktopManager *vds = VirtualDesktopManager::self();
vds->setCount(4);
// no config yet, just to ensure it actually works
vds->save();
KSharedConfig::Ptr config = KSharedConfig::openConfig(QString(), KConfig::SimpleConfig);
vds->setConfig(config);
// now save should create the group "Desktops"
QCOMPARE(config->hasGroup("Desktops"), false);
vds->save();
QCOMPARE(config->hasGroup("Desktops"), true);
KConfigGroup desktops = config->group("Desktops");
QCOMPARE(desktops.readEntry<int>("Number", 1), 4);
QCOMPARE(desktops.hasKey("Name_1"), false);
QCOMPARE(desktops.hasKey("Name_2"), false);
QCOMPARE(desktops.hasKey("Name_3"), false);
QCOMPARE(desktops.hasKey("Name_4"), false);
// change screen number
screen_number = 3;
QCOMPARE(config->hasGroup("Desktops-screen-3"), false);
vds->setCount(3);
vds->save();
QCOMPARE(config->hasGroup("Desktops-screen-3"), true);
// old one should be unchanged
desktops = config->group("Desktops");
QCOMPARE(desktops.readEntry<int>("Number", 1), 4);
desktops = config->group("Desktops-screen-3");
QCOMPARE(desktops.readEntry<int>("Number", 1), 3);
QCOMPARE(desktops.hasKey("Name_1"), false);
QCOMPARE(desktops.hasKey("Name_2"), false);
QCOMPARE(desktops.hasKey("Name_3"), false);
QCOMPARE(desktops.hasKey("Name_4"), false);
}
QTEST_MAIN(TestVirtualDesktops)
#include "test_virtual_desktops.moc"

View File

@ -29,6 +29,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <kdebug.h>
#include "utils.h"
#include "virtualdesktops.h"
#include "workspace.h"
#include <X11/extensions/Xdamage.h>
@ -612,7 +613,7 @@ inline bool Toplevel::isOnActivity(const QString &activity) const
inline bool Toplevel::isOnCurrentDesktop() const
{
return isOnDesktop(workspace()->currentDesktop());
return isOnDesktop(VirtualDesktopManager::self()->current());
}
inline bool Toplevel::isOnCurrentActivity() const

View File

@ -35,6 +35,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "client.h"
#include "workspace.h"
#include "effects.h"
#include "virtualdesktops.h"
#ifdef KWIN_BUILD_SCRIPTING
#include "scripting/scripting.h"
@ -167,7 +168,7 @@ void UserActionsMenu::show(const QRect &pos, const QWeakPointer<Client> &cl)
if (y == pos.top())
m_menu->exec(QPoint(x, y));
else {
QRect area = ws->clientArea(ScreenArea, QPoint(x, y), ws->currentDesktop());
QRect area = ws->clientArea(ScreenArea, QPoint(x, y), VirtualDesktopManager::self()->current());
menuAboutToShow(); // needed for sizeHint() to be correct :-/
int popupHeight = m_menu->sizeHint().height();
if (y + popupHeight < area.height())
@ -409,7 +410,7 @@ void UserActionsMenu::menuAboutToShow()
return;
Workspace *ws = Workspace::self();
if (ws->numberOfDesktops() == 1) {
if (VirtualDesktopManager::self()->count() == 1) {
delete m_desktopMenu;
m_desktopMenu = 0;
} else {
@ -639,7 +640,7 @@ void UserActionsMenu::desktopPopupAboutToShow()
{
if (!m_desktopMenu)
return;
const Workspace *ws = Workspace::self();
const VirtualDesktopManager *vds = VirtualDesktopManager::self();
m_desktopMenu->clear();
QActionGroup *group = new QActionGroup(m_desktopMenu);
@ -652,27 +653,27 @@ void UserActionsMenu::desktopPopupAboutToShow()
action->setChecked(true);
m_desktopMenu->addSeparator();
const int BASE = 10;
for (int i = 1; i <= ws->numberOfDesktops(); ++i) {
const uint BASE = 10;
for (uint i = 1; i <= vds->count(); ++i) {
QString basic_name("%1 %2");
if (i < BASE) {
basic_name.prepend('&');
}
action = m_desktopMenu->addAction(basic_name.arg(i).arg(ws->desktopName(i).replace('&', "&&")));
action = m_desktopMenu->addAction(basic_name.arg(i).arg(vds->name(i).replace('&', "&&")));
action->setData(i);
action->setCheckable(true);
group->addAction(action);
if (!m_client.isNull() &&
!m_client.data()->isOnAllDesktops() && m_client.data()->desktop() == i)
!m_client.data()->isOnAllDesktops() && m_client.data()->isOnDesktop(i))
action->setChecked(true);
}
m_desktopMenu->addSeparator();
action = m_desktopMenu->addAction(i18nc("Create a new desktop and move there the window", "&New Desktop"));
action->setData(ws->numberOfDesktops() + 1);
action->setData(vds->count() + 1);
if (ws->numberOfDesktops() >= Workspace::self()->maxNumberOfDesktops())
if (vds->count() >= vds->maximum())
action->setEnabled(false);
}
@ -758,16 +759,21 @@ void UserActionsMenu::slotWindowOperation(QAction *action)
void UserActionsMenu::slotSendToDesktop(QAction *action)
{
int desk = action->data().toInt();
bool ok = false;
uint desk = action->data().toUInt(&ok);
if (!ok) {
return;
}
if (m_client.isNull())
return;
Workspace *ws = Workspace::self();
VirtualDesktopManager *vds = VirtualDesktopManager::self();
if (desk == 0) {
// the 'on_all_desktops' menu entry
m_client.data()->setOnAllDesktops(!m_client.data()->isOnAllDesktops());
return;
} else if (desk > ws->numberOfDesktops()) {
ws->setNumberOfDesktops(desk);
} else if (desk > vds->count()) {
vds->setCount(desk);
}
ws->sendClientToDesktop(m_client.data(), desk, false);
@ -853,6 +859,7 @@ void Workspace::initShortcuts()
tab_box->initShortcuts(actionCollection);
}
#endif
VirtualDesktopManager::self()->initShortcuts(actionCollection);
m_userActionsMenu->discard(); // so that it's recreated next time
}
@ -1258,67 +1265,10 @@ void Workspace::slotActivateAttentionWindow()
activateClient(attention_chain.first());
}
void Workspace::slotSwitchDesktopNext()
{
int d = currentDesktop() + 1;
if (d > numberOfDesktops()) {
if (options->isRollOverDesktops()) {
d = 1;
} else {
return;
}
}
setCurrentDesktop(d);
}
void Workspace::slotSwitchDesktopPrevious()
{
int d = currentDesktop() - 1;
if (d <= 0) {
if (options->isRollOverDesktops())
d = numberOfDesktops();
else
return;
}
setCurrentDesktop(d);
}
void Workspace::slotSwitchDesktopRight()
{
int desktop = desktopToRight(currentDesktop(), options->isRollOverDesktops());
if (desktop == currentDesktop())
return;
setCurrentDesktop(desktop);
}
void Workspace::slotSwitchDesktopLeft()
{
int desktop = desktopToLeft(currentDesktop(), options->isRollOverDesktops());
if (desktop == currentDesktop())
return;
setCurrentDesktop(desktop);
}
void Workspace::slotSwitchDesktopUp()
{
int desktop = desktopAbove(currentDesktop(), options->isRollOverDesktops());
if (desktop == currentDesktop())
return;
setCurrentDesktop(desktop);
}
void Workspace::slotSwitchDesktopDown()
{
int desktop = desktopBelow(currentDesktop(), options->isRollOverDesktops());
if (desktop == currentDesktop())
return;
setCurrentDesktop(desktop);
}
static int senderValue(QObject *sender)
static uint senderValue(QObject *sender)
{
QAction *act = qobject_cast<QAction*>(sender);
bool ok = false; int i = -1;
bool ok = false; uint i = -1;
if (act)
i = act->data().toUInt(&ok);
if (ok)
@ -1326,23 +1276,16 @@ static int senderValue(QObject *sender)
return -1;
}
void Workspace::slotSwitchToDesktop()
{
const int i = senderValue(sender());
if (i > 0)
setCurrentDesktop(i);
}
#define USABLE_ACTIVE_CLIENT (active_client && !(active_client->isDesktop() || active_client->isDock()))
void Workspace::slotWindowToDesktop()
{
if (USABLE_ACTIVE_CLIENT) {
const int i = senderValue(sender());
const uint i = senderValue(sender());
if (i < 1)
return;
if (i >= 1 && i <= numberOfDesktops())
if (i >= 1 && i <= VirtualDesktopManager::self()->count())
sendClientToDesktop(active_client, i, true);
}
}
@ -1448,7 +1391,7 @@ void Workspace::slotWindowLower()
if (next && next != active_client)
requestFocus(next, false);
} else {
activateClient(topClientOnDesktop(currentDesktop(), -1));
activateClient(topClientOnDesktop(VirtualDesktopManager::self()->current(), -1));
}
}
}
@ -1506,6 +1449,22 @@ void Workspace::slotToggleShowDesktop()
setShowingDesktop(!showingDesktop());
}
template <typename Direction>
void windowToDesktop(Client *c)
{
VirtualDesktopManager *vds = VirtualDesktopManager::self();
Workspace *ws = Workspace::self();
Direction functor;
// TODO: why is options->isRollOverDesktops() not honored?
const int desktop = functor(0, true);
if (c && !c->isDesktop()
&& !c->isDock()) {
ws->setClientIsMoving(c);
vds->setCurrent(desktop);
ws->setClientIsMoving(NULL);
}
}
/*!
Move window to next desktop
*/
@ -1517,15 +1476,7 @@ void Workspace::slotWindowToNextDesktop()
void Workspace::windowToNextDesktop(Client* c)
{
int d = currentDesktop() + 1;
if (d > numberOfDesktops())
d = 1;
if (c && !c->isDesktop()
&& !c->isDock()) {
setClientIsMoving(c);
setCurrentDesktop(d);
setClientIsMoving(NULL);
}
windowToDesktop<DesktopNext>(c);
}
/*!
@ -1539,66 +1490,50 @@ void Workspace::slotWindowToPreviousDesktop()
void Workspace::windowToPreviousDesktop(Client* c)
{
int d = currentDesktop() - 1;
if (d <= 0)
d = numberOfDesktops();
if (c && !c->isDesktop()
&& !c->isDock()) {
setClientIsMoving(c);
setCurrentDesktop(d);
setClientIsMoving(NULL);
windowToDesktop<DesktopPrevious>(c);
}
template <typename Direction>
void activeClientToDesktop()
{
VirtualDesktopManager *vds = VirtualDesktopManager::self();
Workspace *ws = Workspace::self();
const int current = vds->current();
Direction functor;
const int d = functor(current, options->isRollOverDesktops());
if (d == current) {
return;
}
ws->setClientIsMoving(ws->activeClient());
vds->setCurrent(d);
ws->setClientIsMoving(NULL);
}
void Workspace::slotWindowToDesktopRight()
{
if (USABLE_ACTIVE_CLIENT) {
int d = desktopToRight(currentDesktop(), options->isRollOverDesktops());
if (d == currentDesktop())
return;
setClientIsMoving(active_client);
setCurrentDesktop(d);
setClientIsMoving(NULL);
activeClientToDesktop<DesktopRight>();
}
}
void Workspace::slotWindowToDesktopLeft()
{
if (USABLE_ACTIVE_CLIENT) {
int d = desktopToLeft(currentDesktop(), options->isRollOverDesktops());
if (d == currentDesktop())
return;
setClientIsMoving(active_client);
setCurrentDesktop(d);
setClientIsMoving(NULL);
activeClientToDesktop<DesktopLeft>();
}
}
void Workspace::slotWindowToDesktopUp()
{
if (USABLE_ACTIVE_CLIENT) {
int d = desktopAbove(currentDesktop(), options->isRollOverDesktops());
if (d == currentDesktop())
return;
setClientIsMoving(active_client);
setCurrentDesktop(d);
setClientIsMoving(NULL);
activeClientToDesktop<DesktopAbove>();
}
}
void Workspace::slotWindowToDesktopDown()
{
if (USABLE_ACTIVE_CLIENT) {
int d = desktopBelow(currentDesktop(), options->isRollOverDesktops());
if (d == currentDesktop())
return;
setClientIsMoving(active_client);
setCurrentDesktop(d);
setClientIsMoving(NULL);
activeClientToDesktop<DesktopBelow>();
}
}

526
virtualdesktops.cpp Normal file
View File

@ -0,0 +1,526 @@
/********************************************************************
KWin - the KDE window manager
This file is part of the KDE project.
Copyright (C) 2009 Lucas Murray <lmurray@undefinedfire.com>
Copyright (C) 2012 Martin Gräßlin <mgraesslin@kde.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************/
#include "virtualdesktops.h"
// KWin
#include "notifications.h"
// KDE
#include <KDE/KAction>
#include <KDE/KActionCollection>
#include <KDE/KConfigGroup>
#include <KDE/KLocalizedString>
#include <KDE/NETRootInfo>
namespace KWin {
extern int screen_number;
VirtualDesktopGrid::VirtualDesktopGrid()
: m_size(1, 2) // Default to tow rows
, m_grid(new uint[2])
{
// Initializing grid array
m_grid[0] = 0;
m_grid[1] = 0;
}
VirtualDesktopGrid::~VirtualDesktopGrid()
{
delete[] m_grid;
}
void VirtualDesktopGrid::update(const QSize &size, Qt::Orientation orientation)
{
// Set private variables
delete[] m_grid;
m_size = size;
const uint width = size.width();
const uint height = size.height();
const uint length = width * height;
const uint desktopCount = VirtualDesktopManager::self()->count();
m_grid = new uint[length];
// Populate grid
uint desktop = 1;
if (orientation == Qt::Horizontal) {
for (uint y = 0; y < height; ++y) {
for (uint x = 0; x < width; ++x) {
m_grid[y * width + x] = (desktop <= desktopCount ? desktop++ : 0);
}
}
} else {
for (uint x = 0; x < width; ++x) {
for (uint y = 0; y < height; ++y) {
m_grid[y * width + x] = (desktop <= desktopCount ? desktop++ : 0);
}
}
}
}
QPoint VirtualDesktopGrid::gridCoords(uint id) const
{
for (int y = 0; y < m_size.height(); ++y) {
for (int x = 0; x < m_size.width(); ++x) {
if (m_grid[y * m_size.width() + x] == id) {
return QPoint(x, y);
}
}
}
return QPoint(-1, -1);
}
VirtualDesktopManager *VirtualDesktopManager::s_manager = NULL;
VirtualDesktopManager::VirtualDesktopManager(QObject *parent)
: QObject(parent)
, m_current(0)
, m_count(0)
, m_navigationWrapsAround(false)
, m_rootInfo(NULL)
{
}
VirtualDesktopManager::~VirtualDesktopManager()
{
s_manager = NULL;
}
VirtualDesktopManager *VirtualDesktopManager::create(QObject *parent)
{
Q_ASSERT(!s_manager);
s_manager = new VirtualDesktopManager(parent);
return s_manager;
}
QString VirtualDesktopManager::name(uint desktop) const
{
if (!m_rootInfo) {
return defaultName(desktop);
}
return QString::fromUtf8(m_rootInfo->desktopName(desktop));
}
uint VirtualDesktopManager::above(uint id, bool wrap) const
{
if (id == 0) {
id = current();
}
QPoint coords = m_grid.gridCoords(id);
Q_ASSERT(coords.x() >= 0);
while (true) {
coords.ry()--;
if (coords.y() < 0) {
if (wrap) {
coords.setY(m_grid.height() - 1);
} else {
return id; // Already at the top-most desktop
}
}
const uint desktop = m_grid.at(coords);
if (desktop > 0) {
return desktop;
}
}
}
uint VirtualDesktopManager::toRight(uint id, bool wrap) const
{
if (id == 0) {
id = current();
}
QPoint coords = m_grid.gridCoords(id);
Q_ASSERT(coords.x() >= 0);
while (true) {
coords.rx()++;
if (coords.x() >= m_grid.width()) {
if (wrap) {
coords.setX(0);
} else {
return id; // Already at the right-most desktop
}
}
const uint desktop = m_grid.at(coords);
if (desktop > 0) {
return desktop;
}
}
}
uint VirtualDesktopManager::below(uint id, bool wrap) const
{
if (id == 0) {
id = current();
}
QPoint coords = m_grid.gridCoords(id);
Q_ASSERT(coords.x() >= 0);
while (true) {
coords.ry()++;
if (coords.y() >= m_grid.height()) {
if (wrap) {
coords.setY(0);
} else {
// Already at the bottom-most desktop
return id;
}
}
const uint desktop = m_grid.at(coords);
if (desktop > 0) {
return desktop;
}
}
}
uint VirtualDesktopManager::toLeft(uint id, bool wrap) const
{
if (id == 0) {
id = current();
}
QPoint coords = m_grid.gridCoords(id);
Q_ASSERT(coords.x() >= 0);
while (true) {
coords.rx()--;
if (coords.x() < 0) {
if (wrap) {
coords.setX(m_grid.width() - 1);
} else {
return id; // Already at the left-most desktop
}
}
const uint desktop = m_grid.at(coords);
if (desktop > 0) {
return desktop;
}
}
}
uint VirtualDesktopManager::next(uint id, bool wrap) const
{
if (id == 0) {
id = current();
}
const uint desktop = id + 1;
if (desktop > count()) {
if (wrap) {
return 1;
} else {
// are at the last desktop, without wrap return current
return id;
}
}
return desktop;
}
uint VirtualDesktopManager::previous(uint id, bool wrap) const
{
if (id == 0) {
id = current();
}
const uint desktop = id - 1;
if (desktop == 0) {
if (wrap) {
return count();
} else {
// are at the first desktop, without wrap return current
return id;
}
}
return desktop;
}
bool VirtualDesktopManager::setCurrent(uint newDesktop)
{
if (newDesktop < 1 || newDesktop > count() || newDesktop == m_current) {
return false;
}
const uint oldDesktop = m_current;
Notify::raise((Notify::Event)(Notify::DesktopChange + newDesktop));
// change the desktop
m_current = newDesktop;
emit currentChanged(oldDesktop, newDesktop);
return true;
}
void VirtualDesktopManager::setCount(uint count)
{
count = qBound<uint>(1, count, VirtualDesktopManager::maximum());
if (count == m_count) {
// nothing to change
return;
}
const uint oldCount = m_count;
m_count = count;
if (oldCount > m_count) {
handleDesktopsRemoved(oldCount);
}
updateRootInfo();
save();
emit countChanged(oldCount, m_count);
}
void VirtualDesktopManager::handleDesktopsRemoved(uint previousCount)
{
if (current() > count()) {
setCurrent(count());
}
emit desktopsRemoved(previousCount);
}
void VirtualDesktopManager::updateRootInfo()
{
if (!m_rootInfo) {
// Make sure the layout is still valid
updateLayout();
return;
}
const int n = count();
m_rootInfo->setNumberOfDesktops(n);
NETPoint *viewports = new NETPoint[n];
m_rootInfo->setDesktopViewport(n, *viewports);
delete[] viewports;
// Make sure the layout is still valid
updateLayout();
}
void VirtualDesktopManager::updateLayout()
{
int width = 0;
int height = 0;
Qt::Orientation orientation = Qt::Horizontal;
if (m_rootInfo) {
// TODO: Is there a sane way to avoid overriding the existing grid?
width = m_rootInfo->desktopLayoutColumnsRows().width();
height = m_rootInfo->desktopLayoutColumnsRows().height();
orientation = m_rootInfo->desktopLayoutOrientation() == NET::OrientationHorizontal ? Qt::Horizontal : Qt::Vertical;
}
if (width == 0 && height == 0) {
// Not given, set default layout
height = 2;
}
setNETDesktopLayout(orientation,
width, height, 0 //rootInfo->desktopLayoutCorner() // Not really worth implementing right now.
);
}
static bool s_loadingDesktopSettings = false;
void VirtualDesktopManager::load()
{
s_loadingDesktopSettings = true;
if (m_config.isNull()) {
return;
}
QString groupname;
if (screen_number == 0) {
groupname = "Desktops";
} else {
groupname.sprintf("Desktops-screen-%d", screen_number);
}
KConfigGroup group(m_config, groupname);
const int n = group.readEntry("Number", 1);
setCount(n);
if (m_rootInfo) {
for (int i = 1; i <= n; i++) {
QString s = group.readEntry(QString("Name_%1").arg(i), i18n("Desktop %1", i));
m_rootInfo->setDesktopName(i, s.toUtf8().data());
// TODO: update desktop focus chain, why?
// m_desktopFocusChain.value()[i-1] = i;
}
int rows = group.readEntry<int>("Rows", 2);
rows = qBound(1, rows, n);
// avoid weird cases like having 3 rows for 4 desktops, where the last row is unused
int columns = n / rows;
if (n % rows > 0) {
columns++;
}
m_rootInfo->setDesktopLayout(NET::OrientationHorizontal, columns, rows, NET::DesktopLayoutCornerTopLeft);
m_rootInfo->activate();
}
s_loadingDesktopSettings = false;
}
void VirtualDesktopManager::save()
{
if (s_loadingDesktopSettings) {
return;
}
if (m_config.isNull()) {
return;
}
QString groupname;
if (screen_number == 0) {
groupname = "Desktops";
} else {
groupname.sprintf("Desktops-screen-%d", screen_number);
}
KConfigGroup group(m_config, groupname);
group.writeEntry("Number", count());
for (uint i = 1; i <= count(); ++i) {
QString s = name(i);
const QString defaultvalue = defaultName(i);
if (s.isEmpty()) {
s = defaultvalue;
if (m_rootInfo) {
m_rootInfo->setDesktopName(i, s.toUtf8().data());
}
}
if (s != defaultvalue) {
group.writeEntry(QString("Name_%1").arg(i), s);
} else {
QString currentvalue = group.readEntry(QString("Name_%1").arg(i), QString());
if (currentvalue != defaultvalue) {
group.deleteEntry(QString("Name_%1").arg(i));
}
}
}
// Save to disk
group.sync();
}
QString VirtualDesktopManager::defaultName(int desktop) const
{
return i18n("Desktop %1", desktop);
}
void VirtualDesktopManager::setNETDesktopLayout(Qt::Orientation orientation, uint width, uint height, int startingCorner)
{
Q_UNUSED(startingCorner); // Not really worth implementing right now.
// Calculate valid grid size
Q_ASSERT(width > 0 || height > 0);
if ((width <= 0) && (height > 0)) {
width = (m_count + height - 1) / height;
} else if ((height <= 0) && (width > 0)) {
height = (m_count + width - 1) / width;
}
while (width * height < m_count) {
if (orientation == Qt::Horizontal) {
++width;
} else {
++height;
}
}
m_grid.update(QSize(width, height), orientation);
// TODO: why is there no call to m_rootInfo->setDesktopLayout?
emit layoutChanged(width, height);
}
void VirtualDesktopManager::initShortcuts(KActionCollection *keys)
{
KAction *a = keys->addAction("Group:Desktop Switching");
a->setText(i18n("Desktop Switching"));
initSwitchToShortcuts(keys);
addAction(keys, "Switch to Next Desktop", i18n("Switch to Next Desktop"), SLOT(slotNext()));
addAction(keys, "Switch to Previous Desktop", i18n("Switch to Previous Desktop"), SLOT(slotPrevious()));
addAction(keys, "Switch One Desktop to the Right", i18n("Switch One Desktop to the Right"), SLOT(slotRight()));
addAction(keys, "Switch One Desktop to the Left", i18n("Switch One Desktop to the Left"), SLOT(slotLeft()));
addAction(keys, "Switch One Desktop Up", i18n("Switch One Desktop Up"), SLOT(slotUp()));
addAction(keys, "Switch One Desktop Down", i18n("Switch One Desktop Down"), SLOT(slotDown()));
}
void VirtualDesktopManager::initSwitchToShortcuts(KActionCollection *keys)
{
const QString toDesktop = "Switch to Desktop %1";
const KLocalizedString toDesktopLabel = ki18n("Switch to Desktop %1");
addAction(keys, toDesktop, toDesktopLabel, 1, KShortcut(Qt::CTRL + Qt::Key_F1), SLOT(slotSwitchTo()));
addAction(keys, toDesktop, toDesktopLabel, 2, KShortcut(Qt::CTRL + Qt::Key_F2), SLOT(slotSwitchTo()));
addAction(keys, toDesktop, toDesktopLabel, 3, KShortcut(Qt::CTRL + Qt::Key_F3), SLOT(slotSwitchTo()));
addAction(keys, toDesktop, toDesktopLabel, 4, KShortcut(Qt::CTRL + Qt::Key_F4), SLOT(slotSwitchTo()));
for (uint i = 5; i <= maximum(); ++i) {
addAction(keys, toDesktop, toDesktopLabel, i, KShortcut(), SLOT(slotSwitchTo()));
}
}
void VirtualDesktopManager::addAction(KActionCollection *keys, const QString &name, const KLocalizedString &label, uint value, const KShortcut &key, const char *slot)
{
KAction *a = keys->addAction(name.arg(value), this, slot);
a->setText(label.subs(value).toString());
a->setGlobalShortcut(key);
a->setData(value);
}
void VirtualDesktopManager::addAction(KActionCollection *keys, const QString &name, const QString &label, const char *slot)
{
KAction *a = keys->addAction(name, this, slot);
a->setText(label);
}
void VirtualDesktopManager::slotSwitchTo()
{
QAction *act = qobject_cast<QAction*>(sender());
if (!act) {
return;
}
bool ok = false;
const uint i = act->data().toUInt(&ok);
if (!ok) {
return;
}
setCurrent(i);
}
void VirtualDesktopManager::setNavigationWrappingAround(bool enabled)
{
if (enabled == m_navigationWrapsAround) {
return;
}
m_navigationWrapsAround = enabled;
emit navigationWrappingAroundChanged();
}
void VirtualDesktopManager::slotDown()
{
moveTo<DesktopBelow>(isNavigationWrappingAround());
}
void VirtualDesktopManager::slotLeft()
{
moveTo<DesktopLeft>(isNavigationWrappingAround());
}
void VirtualDesktopManager::slotPrevious()
{
moveTo<DesktopPrevious>(isNavigationWrappingAround());
}
void VirtualDesktopManager::slotNext()
{
moveTo<DesktopNext>(isNavigationWrappingAround());
}
void VirtualDesktopManager::slotRight()
{
moveTo<DesktopRight>(isNavigationWrappingAround());
}
void VirtualDesktopManager::slotUp()
{
moveTo<DesktopAbove>(isNavigationWrappingAround());
}
} // KWin

590
virtualdesktops.h Normal file
View File

@ -0,0 +1,590 @@
/********************************************************************
KWin - the KDE window manager
This file is part of the KDE project.
Copyright (C) 2012 Martin Gräßlin <mgraesslin@kde.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************/
#ifndef KWIN_VIRTUAL_DESKTOPS_H
#define KWIN_VIRTUAL_DESKTOPS_H
// Qt includes
#include <QObject>
#include <QPoint>
#include <QSize>
// KDE includes
#include <KDE/KConfig>
class KActionCollection;
class KLocalizedString;
class KShortcut;
class NETRootInfo;
namespace KWin {
/**
* @brief Two dimensional grid containing the ID of the virtual desktop at a specific position
* in the grid.
*
* The VirtualDesktopGrid represents a visual layout of the Virtual Desktops as they are in e.g.
* a Pager. This grid is used for getting a desktop next to a given desktop in any direction by
* making use of the layout information. This allows navigation like move to desktop on left.
**/
class VirtualDesktopGrid
{
public:
VirtualDesktopGrid();
~VirtualDesktopGrid();
void update(const QSize &size, Qt::Orientation orientation);
/**
* @returns The coords of desktop @a id in grid units.
*/
QPoint gridCoords(uint id) const;
/**
* @returns The ID of the desktop at the point @a coords or 0 if no desktop exists at that
* point. @a coords is to be in grid units.
*/
uint at(QPoint coords) const;
int width() const;
int height() const;
const QSize &size() const;
private:
QSize m_size;
uint *m_grid;
};
/**
* @brief Manages the number of available virtual desktops, the layout of those and which virtual
* desktop is the current one.
*
* This manager is responsible for Virtual Desktop handling inside KWin. It has a property for the
* count of available virtual desktops and a property for the currently active virtual desktop. All
* changes to the number of virtual desktops and the current virtual desktop need to go through this
* manager.
*
* On all changes a signal is emitted and interested parties should connect to the signal. The manager
* itself does not interact with other parts of the system. E.g. it does not hide/show windows of
* desktop changes. This is outside the scope of this manager.
*
* Internally the manager organizes the virtual desktops in a grid allowing to navigate over the
* virtual desktops. For this a set of convenient methods are available which allow to get the id
* of an adjacent desktop or to switch to an adjacent desktop. Interested parties should make use of
* these methods and not replicate the logic to switch to the next desktop.
**/
class VirtualDesktopManager : public QObject
{
Q_OBJECT
/**
* The number of virtual desktops currently available.
* The ids of the virtual desktops are in the range [1, VirtualDesktopManager::maximum()].
**/
Q_PROPERTY(uint count READ count WRITE setCount NOTIFY countChanged)
/**
* The id of the virtual desktop which is currently in use.
**/
Q_PROPERTY(uint current READ current WRITE setCurrent NOTIFY currentChanged)
/**
* Whether navigation in the desktop layout wraps around at the borders.
**/
Q_PROPERTY(bool navigationWrappingAround READ isNavigationWrappingAround WRITE setNavigationWrappingAround NOTIFY navigationWrappingAroundChanged)
public:
virtual ~VirtualDesktopManager();
/**
* @internal
**/
void setRootInfo(NETRootInfo *info);
/**
* @internal
**/
void setConfig(KSharedConfig::Ptr config);
/**
* @returns Total number of desktops currently in existence.
* @see setCount
* @see countChanged
*/
uint count() const;
/**
* @returns The ID of the current desktop.
* @see setCurrent
* @see currentChanged
*/
uint current() const;
/**
* Moves to the desktop through the algorithm described by Direction.
* @param wrap If @c true wraps around to the other side of the layout
* @see setCurrent
**/
template <typename Direction>
void moveTo(bool wrap = false);
/**
* @returns The name of the @p desktop
**/
QString name(uint desktop) const;
/**
* @returns @c true if navigation at borders of layout wraps around, @c false otherwise
* @see setNavigationWrappingAround
* @see navigationWrappingAroundChanged
**/
bool isNavigationWrappingAround() const;
/**
* @returns The layout aware virtual desktop grid used by this manager.
**/
const VirtualDesktopGrid &grid() const;
/**
* @returns The ID of the desktop above desktop @a id. Wraps around to the bottom of
* the layout if @a wrap is set. If @a id is not set use the current one.
*/
uint above(uint id = 0, bool wrap = true) const;
/**
* @returns The ID of the desktop to the right of desktop @a id. Wraps around to the
* left of the layout if @a wrap is set. If @a id is not set use the current one.
*/
uint toRight(uint id = 0, bool wrap = true) const;
/**
* @returns The ID of the desktop below desktop @a id. Wraps around to the top of the
* layout if @a wrap is set. If @a id is not set use the current one.
*/
uint below(uint id = 0, bool wrap = true) const;
/**
* @returns The ID of the desktop to the left of desktop @a id. Wraps around to the
* right of the layout if @a wrap is set. If @a id is not set use the current one.
*/
uint toLeft(uint id = 0, bool wrap = true) const;
/**
* @returns The ID of the desktop after the desktop @a id. Wraps around to the first
* desktop if @a wrap is set. If @a id is not set use the current desktop.
**/
uint next(uint id = 0, bool wrap = true) const;
/**
* @returns The ID of the desktop in front of the desktop @a id. Wraps around to the
* last desktop if @a wrap is set. If @a id is not set use the current desktop.
**/
uint previous(uint id = 0, bool wrap = true) const;
void initShortcuts(KActionCollection *keys);
/**
* Singleton getter for this manager.
*
* Does not create a new instance. If the manager has not been created yet a @c null pointer
* is returned.
* @see create
**/
static VirtualDesktopManager *self();
/**
* Factory method to create the VirtualDesktopManager.
* @see self
**/
static VirtualDesktopManager *create(QObject *parent = NULL);
/**
* @returns The maximum number of desktops that KWin supports.
*/
static uint maximum();
public slots:
/**
* Set the number of available desktops to @a count. This function overrides any previous
* grid layout.
* There needs to be at least one virtual desktop and the new value is capped at the maximum
* number of desktops. A caller of this function cannot expect that the change has been applied.
* It is the callers responsibility to either check the @link numberOfDesktops or connect to the
* @link countChanged signal.
*
* In case the @link current desktop is on a desktop higher than the new count, the current desktop
* is changed to be the new desktop with highest id. In that situation the signal @link desktopsRemoved
* is emitted.
* @param count The new number of desktops to use
* @see count
* @see maximum
* @see countChanged
* @see desktopsRemoved
*/
void setCount(uint count);
/**
* Set the current desktop to @a current.
* @returns True on success, false otherwise.
* @see current
* @see currentChanged
* @see moveTo
*/
bool setCurrent(uint current);
/**
* Called from within setCount() to ensure the desktop layout is still valid.
*/
void updateLayout();
/**
* @param enable wrapping around borders for navigation in desktop layout
* @see isNavigationWrappingAround
* @see navigationWrappingAroundChanged
**/
void setNavigationWrappingAround(bool enabled);
/**
* Loads number of desktops and names from configuration file
**/
void load();
/**
* Saves number of desktops and names to configuration file
**/
void save();
Q_SIGNALS:
/**
* Signal emitted whenever the number of virtual desktops changes.
* @param previousCount The number of desktops prior to the change
* @param newCount The new current number of desktops
**/
void countChanged(uint previousCount, uint newCount);
/**
* Signal emitted whenever the number of virtual desktops changes in a way
* that existing desktops are removed.
*
* The signal is emitted after the @c count property has been updated but prior
* to the @link countChanged signal being emitted.
* @param previousCount The number of desktops prior to the change.
* @see countChanged
* @see setCount
* @see count
**/
void desktopsRemoved(uint previousCount);
/**
* Signal emitted whenever the current desktop changes.
* @param previousDesktop The virtual desktop changed from
* @param newDesktop The virtual desktop changed to
**/
void currentChanged(uint previousDesktop, uint newDesktop);
/**
* Signal emitted whenever the desktop layout changes.
* @param columns The new number of columns in the layout
* @param rows The new number of rows in the layout
**/
void layoutChanged(int columns, int rows);
/**
* Signal emitted whenever the navigationWrappingAround property changes.
**/
void navigationWrappingAroundChanged();
private slots:
/**
* Common slot for all "Switch to Desktop n" shortcuts.
* This method uses the sender() method to access some data.
* DO NOT CALL DIRECTLY! ONLY TO BE USED FROM AN ACTION!
**/
void slotSwitchTo();
/**
* Slot for switch to next desktop action.
**/
void slotNext();
/**
* Slot for switch to previous desktop action.
**/
void slotPrevious();
/**
* Slot for switch to right desktop action.
**/
void slotRight();
/**
* Slot for switch to left desktop action.
**/
void slotLeft();
/**
* Slot for switch to desktop above action.
**/
void slotUp();
/**
* Slot for switch to desktop below action.
**/
void slotDown();
private:
explicit VirtualDesktopManager(QObject *parent = 0);
/**
* This method is called when the number of desktops is updated in a way that desktops
* are removed. At the time when this method is invoked the count property is already
* updated but the corresponding signal has not been emitted yet.
*
* Ensures that in case the current desktop is on one of the removed
* desktops the last desktop after the change becomes the new desktop.
* Emits the signal @link desktopsRemoved.
*
* @param previousCount The number of desktops prior to the change.
* @see setCount
* @see desktopsRemoved
**/
void handleDesktopsRemoved(uint previousCount);
/**
* Generate a desktop layout from EWMH _NET_DESKTOP_LAYOUT property parameters.
*/
void setNETDesktopLayout(Qt::Orientation orientation, uint width, uint height, int startingCorner);
/**
* Updates the net root info for new number of desktops
**/
void updateRootInfo();
/**
* @returns A default name for the given @p desktop
**/
QString defaultName(int desktop) const;
/**
* Creates all the global keyboard shortcuts for "Switch To Desktop n" actions.
**/
void initSwitchToShortcuts(KActionCollection *keys);
/**
* Creates an action and connects it to the @p slot in this Manager. This method is
* meant to be used for the case that an additional information needs to be stored in
* the action and the label.
* @param keys The ActionCollection used to create the Action
* @param name The name of the action to be created
* @param label The localized name for the action to be created
* @param value An additional value added to the label and to the created action
* @param key The global shortcut for the action
* @param slot The slot to invoke when the action is triggered
**/
void addAction(KActionCollection *keys, const QString &name, const KLocalizedString &label, uint value, const KShortcut &key, const char *slot);
/**
* Creates an action and connects it to the @p slot in this Manager.
* Overloaded method for the case that no additional value needs to be passed to the action and
* no global shortcut is defined by default.
* @param keys The ActionCollection used to create the Action
* @param name The name of the action to be created
* @param label The localized name for the action to be created
* @param slot The slot to invoke when the action is triggered
**/
void addAction(KActionCollection *keys, const QString &name, const QString &label, const char *slot);
uint m_current;
uint m_count;
bool m_navigationWrapsAround;
VirtualDesktopGrid m_grid;
// TODO: QPointer
NETRootInfo *m_rootInfo;
KSharedConfig::Ptr m_config;
static VirtualDesktopManager *s_manager;
};
/**
* Function object to select the desktop above in the layout.
* Note: does not switch to the desktop!
**/
class DesktopAbove
{
public:
DesktopAbove() {}
/**
* @param desktop The desktop from which the desktop above should be selected. If @c 0 the current desktop is used
* @param wrap Whether to wrap around if already topmost desktop
* @returns Id of the desktop above @p desktop
**/
uint operator() (uint desktop, bool wrap) {
return VirtualDesktopManager::self()->above(desktop, wrap);
}
};
/**
* Function object to select the desktop below in the layout.
* Note: does not switch to the desktop!
**/
class DesktopBelow
{
public:
DesktopBelow() {}
/**
* @param desktop The desktop from which the desktop below should be selected. If @c 0 the current desktop is used
* @param wrap Whether to wrap around if already lowest desktop
* @returns Id of the desktop below @p desktop
**/
uint operator() (uint desktop, bool wrap) {
return VirtualDesktopManager::self()->below(desktop, wrap);
}
};
/**
* Function object to select the desktop to the left in the layout.
* Note: does not switch to the desktop!
**/
class DesktopLeft
{
public:
DesktopLeft() {}
/**
* @param desktop The desktop from which the desktop on the left should be selected. If @c 0 the current desktop is used
* @param wrap Whether to wrap around if already leftmost desktop
* @returns Id of the desktop left of @p desktop
**/
uint operator() (uint desktop, bool wrap) {
return VirtualDesktopManager::self()->toLeft(desktop, wrap);
}
};
/**
* Function object to select the desktop to the right in the layout.
* Note: does not switch to the desktop!
**/
class DesktopRight
{
public:
DesktopRight() {}
/**
* @param desktop The desktop from which the desktop on the right should be selected. If @c 0 the current desktop is used
* @param wrap Whether to wrap around if already rightmost desktop
* @returns Id of the desktop right of @p desktop
**/
uint operator() (uint desktop, bool wrap) {
return VirtualDesktopManager::self()->toRight(desktop, wrap);
}
};
/**
* Function object to select the next desktop in the layout.
* Note: does not switch to the desktop!
**/
class DesktopNext
{
public:
DesktopNext() {}
/**
* @param desktop The desktop from which the next desktop should be selected. If @c 0 the current desktop is used
* @param wrap Whether to wrap around if already last desktop
* @returns Id of the next desktop
**/
uint operator() (uint desktop, bool wrap) {
return VirtualDesktopManager::self()->next(desktop, wrap);
}
};
/**
* Function object to select the previous desktop in the layout.
* Note: does not switch to the desktop!
**/
class DesktopPrevious
{
public:
DesktopPrevious() {}
/**
* @param desktop The desktop from which the previous desktop should be selected. If @c 0 the current desktop is used
* @param wrap Whether to wrap around if already first desktop
* @returns Id of the previous desktop
**/
uint operator() (uint desktop, bool wrap) {
return VirtualDesktopManager::self()->previous(desktop, wrap);
}
};
/**
* Helper function to get the ID of a virtual desktop in the direction from
* the given @p desktop. If @c 0 the current desktop is used as a starting point.
* @param desktop The desktop from which the desktop in given Direction should be selected.
* @param wrap Whether desktop navigation wraps around at the borders of the layout
* @returns The next desktop in specified direction
**/
template <typename Direction>
uint getDesktop(int desktop = 0, bool wrap = true);
template <typename Direction>
uint getDesktop(int d, bool wrap)
{
Direction direction;
return direction(d, wrap);
}
inline
int VirtualDesktopGrid::width() const
{
return m_size.width();
}
inline
int VirtualDesktopGrid::height() const
{
return m_size.height();
}
inline
const QSize &VirtualDesktopGrid::size() const
{
return m_size;
}
inline
uint VirtualDesktopGrid::at(QPoint coords) const
{
const int index = coords.y() * m_size.width() + coords.x();
if (index > m_size.width() * m_size.height() || coords.x() >= width() || coords.y() >= height()) {
return 0;
}
return m_grid[index];
}
inline
VirtualDesktopManager *VirtualDesktopManager::self()
{
Q_ASSERT(s_manager);
return s_manager;
}
inline
uint VirtualDesktopManager::maximum()
{
return 20;
}
inline
uint VirtualDesktopManager::current() const
{
return m_current;
}
inline
uint VirtualDesktopManager::count() const
{
return m_count;
}
inline
bool VirtualDesktopManager::isNavigationWrappingAround() const
{
return m_navigationWrapsAround;
}
inline
void VirtualDesktopManager::setRootInfo(NETRootInfo *info)
{
m_rootInfo = info;
}
inline
void VirtualDesktopManager::setConfig(KSharedConfig::Ptr config)
{
m_config = config;
}
inline
const VirtualDesktopGrid &VirtualDesktopManager::grid() const
{
return m_grid;
}
template <typename Direction>
void VirtualDesktopManager::moveTo(bool wrap)
{
Direction functor;
setCurrent(functor(0, wrap));
}
} // namespace KWin
#endif

View File

@ -61,6 +61,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "effects.h"
#include "overlaywindow.h"
#include "useractions.h"
#include "virtualdesktops.h"
#include <kwinglplatform.h>
#include <kwinglutils.h>
#ifdef KWIN_BUILD_SCRIPTING
@ -81,7 +82,6 @@ namespace KWin
{
extern int screen_number;
static const int KWIN_MAX_NUMBER_DESKTOPS = 20;
#ifdef KWIN_BUILD_KAPPMENU
static const char *KDED_SERVICE = "org.kde.kded";
@ -93,11 +93,6 @@ Workspace* Workspace::_self = 0;
Workspace::Workspace(bool restore)
: QObject(0)
// Desktop layout
, desktopCount_(0) // This is an invalid state
, desktopGridSize_(1, 2) // Default to two rows
, desktopGrid_(new int[2])
, currentDesktop_(0)
#ifdef KWIN_BUILD_SCREENEDGES
, m_screenEdgeOrientation(0)
#endif
@ -154,10 +149,6 @@ Workspace::Workspace(bool restore)
this, SLOT(slotClearMenus()));
#endif
// Initialize desktop grid array
desktopGrid_[0] = 0;
desktopGrid_[1] = 0;
_self = this;
// first initialize the extensions
@ -210,6 +201,10 @@ Workspace::Workspace(bool restore)
new DBusInterface(this);
// VirtualDesktopManager needs to be created prior to init shortcuts
// actual initialization happens in init()
VirtualDesktopManager::create(this);
// Compatibility
long data = 1;
@ -357,13 +352,25 @@ void Workspace::init()
rootInfo = new RootInfo(this, display(), supportWindow->winId(), "KWin", protocols, 5, info.screen());
// Create an entry with empty activity name, it will be used if activities are not supported. Otherwise, it will be removed.
m_desktopFocusChain = m_activitiesDesktopFocusChain.insert(QString(), QVector<int>(numberOfDesktops()));
m_desktopFocusChain = m_activitiesDesktopFocusChain.insert(QString(), QVector<uint>());
// create VirtualDesktopManager and perform dependency injection
VirtualDesktopManager *vds = VirtualDesktopManager::self();
connect(vds, SIGNAL(desktopsRemoved(uint)), SLOT(moveClientsFromRemovedDesktops()));
connect(vds, SIGNAL(countChanged(uint,uint)), SLOT(slotDesktopCountChanged(uint,uint)));
connect(vds, SIGNAL(currentChanged(uint,uint)), SLOT(slotCurrentDesktopChanged(uint,uint)));
vds->setNavigationWrappingAround(options->isRollOverDesktops());
connect(options, SIGNAL(rollOverDesktopsChanged(bool)), vds, SLOT(setNavigationWrappingAround(bool)));
vds->setRootInfo(rootInfo);
vds->setConfig(KGlobal::config());
// Now we know how many desktops we'll have, thus we initialize the positioning object
Placement::create(this);
loadDesktopSettings();
updateDesktopLayout();
// positioning object needs to be created before the virtual desktops are loaded.
vds->load();
vds->updateLayout();
// Extra NETRootInfo instance in Client mode is needed to get the values of the properties
NETRootInfo client_info(display(), NET::ActiveWindow | NET::CurrentDesktop);
int initial_desktop;
@ -373,8 +380,8 @@ void Workspace::init()
KConfigGroup group(kapp->sessionConfig(), "Session");
initial_desktop = group.readEntry("desktop", 1);
}
if (!setCurrentDesktop(initial_desktop))
setCurrentDesktop(1);
if (!VirtualDesktopManager::self()->setCurrent(initial_desktop))
VirtualDesktopManager::self()->setCurrent(1);
#ifdef KWIN_BUILD_ACTIVITIES
updateActivityList(false, true);
#endif
@ -451,8 +458,8 @@ void Workspace::init()
updateClientArea();
// NETWM spec says we have to set it to (0,0) if we don't support it
NETPoint* viewports = new NETPoint[numberOfDesktops()];
rootInfo->setDesktopViewport(numberOfDesktops(), *viewports);
NETPoint* viewports = new NETPoint[VirtualDesktopManager::self()->count()];
rootInfo->setDesktopViewport(VirtualDesktopManager::self()->count(), *viewports);
delete[] viewports;
QRect geom;
for (int i = 0; i < QApplication::desktop()->screenCount(); i++) {
@ -475,9 +482,9 @@ void Workspace::init()
&& activeClient() == NULL && should_get_focus.count() == 0) {
// No client activated in manage()
if (new_active_client == NULL)
new_active_client = topClientOnDesktop(currentDesktop(), -1);
new_active_client = topClientOnDesktop(VirtualDesktopManager::self()->current(), -1);
if (new_active_client == NULL && !desktops.isEmpty())
new_active_client = findDesktop(true, currentDesktop());
new_active_client = findDesktop(true, VirtualDesktopManager::self()->current());
}
if (new_active_client != NULL)
activateClient(new_active_client);
@ -544,8 +551,6 @@ Workspace::~Workspace()
// TODO: ungrabXServer();
delete[] desktopGrid_;
_self = 0;
}
@ -612,7 +617,7 @@ void Workspace::addClient(Client* c, allowed_t)
raiseClient(c);
// If there's no active client, make this desktop the active one
if (activeClient() == NULL && should_get_focus.count() == 0)
activateClient(findDesktop(true, currentDesktop()));
activateClient(findDesktop(true, VirtualDesktopManager::self()->current()));
}
c->checkActiveModal();
checkTransients(c->window()); // SELI TODO: Does this really belong here?
@ -673,7 +678,7 @@ void Workspace::removeClient(Client* c, allowed_t)
clients.removeAll(c);
desktops.removeAll(c);
x_stacking_dirty = true;
for (int i = 1; i <= numberOfDesktops(); ++i)
for (uint i = 1; i <= VirtualDesktopManager::self()->count(); ++i)
focus_chain[i].removeAll(c);
global_focus_chain.removeAll(c);
attention_chain.removeAll(c);
@ -747,16 +752,16 @@ void Workspace::removeDeleted(Deleted* c, allowed_t)
void Workspace::updateFocusChains(Client* c, FocusChainChange change)
{
if (!c->wantsTabFocus()) { // Doesn't want tab focus, remove
for (int i = 1; i <= numberOfDesktops(); ++i)
for (uint i = 1; i <= VirtualDesktopManager::self()->count(); ++i)
focus_chain[i].removeAll(c);
global_focus_chain.removeAll(c);
return;
}
if (c->desktop() == NET::OnAllDesktops) {
// Now on all desktops, add it to focus_chains it is not already in
for (int i = 1; i <= numberOfDesktops(); i++) {
for (uint i = 1; i <= VirtualDesktopManager::self()->count(); i++) {
// Making first/last works only on current desktop, don't affect all desktops
if (i == currentDesktop()
if (i == VirtualDesktopManager::self()->current()
&& (change == FocusChainMakeFirst || change == FocusChainMakeLast)) {
focus_chain[i].removeAll(c);
if (change == FocusChainMakeFirst)
@ -773,8 +778,8 @@ void Workspace::updateFocusChains(Client* c, FocusChainChange change)
}
}
} else { // Now only on desktop, remove it anywhere else
for (int i = 1; i <= numberOfDesktops(); i++) {
if (i == c->desktop()) {
for (uint i = 1; i <= VirtualDesktopManager::self()->count(); i++) {
if (c->isOnDesktop(i)) {
if (change == FocusChainMakeFirst) {
focus_chain[i].removeAll(c);
focus_chain[i].append(c);
@ -1071,71 +1076,6 @@ void Workspace::slotReconfigure()
}
}
static bool _loading_desktop_settings = false;
void Workspace::loadDesktopSettings()
{
_loading_desktop_settings = true;
KSharedConfig::Ptr c = KGlobal::config();
QString groupname;
if (screen_number == 0)
groupname = "Desktops";
else
groupname.sprintf("Desktops-screen-%d", screen_number);
KConfigGroup group(c, groupname);
const int n = group.readEntry("Number", 1);
setNumberOfDesktops(n);
for (int i = 1; i <= n; i++) {
QString s = group.readEntry(QString("Name_%1").arg(i), i18n("Desktop %1", i));
rootInfo->setDesktopName(i, s.toUtf8().data());
m_desktopFocusChain.value()[i-1] = i;
}
int rows = group.readEntry<int>("Rows", 2);
rows = qBound(1, rows, n);
// avoid weird cases like having 3 rows for 4 desktops, where the last row is unused
int columns = n / rows;
if (n % rows > 0) {
columns++;
}
rootInfo->setDesktopLayout(NET::OrientationHorizontal, columns, rows, NET::DesktopLayoutCornerTopLeft);
rootInfo->activate();
_loading_desktop_settings = false;
}
void Workspace::saveDesktopSettings()
{
if (_loading_desktop_settings)
return;
KSharedConfig::Ptr c = KGlobal::config();
QString groupname;
if (screen_number == 0)
groupname = "Desktops";
else
groupname.sprintf("Desktops-screen-%d", screen_number);
KConfigGroup group(c, groupname);
group.writeEntry("Number", numberOfDesktops());
for (int i = 1; i <= numberOfDesktops(); i++) {
QString s = desktopName(i);
QString defaultvalue = i18n("Desktop %1", i);
if (s.isEmpty()) {
s = defaultvalue;
rootInfo->setDesktopName(i, s.toUtf8().data());
}
if (s != defaultvalue) {
group.writeEntry(QString("Name_%1").arg(i), s);
} else {
QString currentvalue = group.readEntry(QString("Name_%1").arg(i), QString());
if (currentvalue != defaultvalue)
group.writeEntry(QString("Name_%1").arg(i), "");
}
}
// Save to disk
group.sync();
}
/**
* Avoids managing a window with title \a title
*/
@ -1223,109 +1163,62 @@ ObscuringWindows::~ObscuringWindows()
}
}
/**
* Sets the current desktop to \a new_desktop
*
* Shows/Hides windows according to the stacking order and finally
* propages the new desktop to the world
*/
bool Workspace::setCurrentDesktop(int new_desktop)
void Workspace::slotCurrentDesktopChanged(uint oldDesktop, uint newDesktop)
{
if (new_desktop < 1 || new_desktop > numberOfDesktops())
return false;
closeActivePopup();
++block_focus;
// TODO: Q_ASSERT( block_stacking_updates == 0 ); // Make sure stacking_order is up to date
StackingUpdatesBlocker blocker(this);
int old_desktop = currentDesktop();
int old_active_screen = activeScreen();
if (new_desktop != currentDesktop()) {
++block_showing_desktop;
// Optimized Desktop switching: unmapping done from back to front
// mapping done from front to back => less exposure events
Notify::raise((Notify::Event)(Notify::DesktopChange + new_desktop));
ObscuringWindows obs_wins;
currentDesktop_ = new_desktop; // Change the desktop (so that Client::updateVisibility() works)
for (ToplevelList::ConstIterator it = stacking_order.constBegin();
it != stacking_order.constEnd();
++it) {
Client *c = qobject_cast<Client*>(*it);
if (!c) {
continue;
}
if (!c->isOnDesktop(new_desktop) && c != movingClient && c->isOnCurrentActivity()) {
if (c->isShown(true) && c->isOnDesktop(old_desktop) && !compositing())
obs_wins.create(c);
(c)->updateVisibility();
}
}
// Now propagate the change, after hiding, before showing
rootInfo->setCurrentDesktop(currentDesktop());
if (movingClient && !movingClient->isOnDesktop(new_desktop)) {
movingClient->setDesktop(new_desktop);
}
for (int i = stacking_order.size() - 1; i >= 0 ; --i) {
Client *c = qobject_cast<Client*>(stacking_order.at(i));
if (!c) {
continue;
}
if (c->isOnDesktop(new_desktop) && c->isOnCurrentActivity())
c->updateVisibility();
}
--block_showing_desktop;
if (showingDesktop()) // Do this only after desktop change to avoid flicker
resetShowingDesktop(false);
}
updateClientVisibilityOnDesktopChange(oldDesktop, newDesktop);
// Restore the focus on this desktop
--block_focus;
Client* c = 0;
if (options->focusPolicyIsReasonable()) {
// Search in focus chain
if (movingClient != NULL && active_client == movingClient &&
focus_chain[currentDesktop()].contains(active_client) &&
active_client->isShown(true) && active_client->isOnCurrentDesktop())
c = active_client; // The requestFocus below will fail, as the client is already active
// from actiavtion.cpp
if (!c && options->isNextFocusPrefersMouse()) {
ToplevelList::const_iterator it = stackingOrder().constEnd();
while (it != stackingOrder().constBegin()) {
Client *client = qobject_cast<Client*>(*(--it));
if (!client) {
continue;
}
activateClientOnNewDesktop(newDesktop);
updateDesktopFocusChain(newDesktop);
emit currentDesktopChanged(oldDesktop, movingClient);
}
if (!(client->isShown(false) && client->isOnDesktop(new_desktop) &&
client->isOnCurrentActivity() && client->isOnScreen(activeScreen())))
continue;
if (client->geometry().contains(QCursor::pos())) {
if (!client->isDesktop())
c = client;
break; // unconditional break - we do not pass the focus to some client below an unusable one
}
}
}
void Workspace::updateClientVisibilityOnDesktopChange(uint oldDesktop, uint newDesktop)
{
++block_showing_desktop;
ObscuringWindows obs_wins;
for (ToplevelList::ConstIterator it = stacking_order.constBegin();
it != stacking_order.constEnd();
++it) {
Client *c = qobject_cast<Client*>(*it);
if (!c) {
for (int i = focus_chain[currentDesktop()].size() - 1; i >= 0; --i) {
Client* tmp = focus_chain[currentDesktop()].at(i);
if (tmp->isShown(false) && tmp->isOnCurrentActivity()
&& ( !options->isSeparateScreenFocus() || tmp->screen() == old_active_screen )) {
c = tmp;
break;
}
}
continue;
}
if (!c->isOnDesktop(newDesktop) && c != movingClient && c->isOnCurrentActivity()) {
if (c->isShown(true) && c->isOnDesktop(oldDesktop) && !compositing())
obs_wins.create(c);
(c)->updateVisibility();
}
}
// Now propagate the change, after hiding, before showing
rootInfo->setCurrentDesktop(VirtualDesktopManager::self()->current());
if (movingClient && !movingClient->isOnDesktop(newDesktop)) {
movingClient->setDesktop(newDesktop);
}
for (int i = stacking_order.size() - 1; i >= 0 ; --i) {
Client *c = qobject_cast<Client*>(stacking_order.at(i));
if (!c) {
continue;
}
if (c->isOnDesktop(newDesktop) && c->isOnCurrentActivity())
c->updateVisibility();
}
--block_showing_desktop;
if (showingDesktop()) // Do this only after desktop change to avoid flicker
resetShowingDesktop(false);
}
void Workspace::activateClientOnNewDesktop(uint desktop)
{
Client* c = NULL;
if (options->focusPolicyIsReasonable()) {
c = findClientToActivateOnDesktop(desktop);
}
// If "unreasonable focus policy" and active_client is on_all_desktops and
// under mouse (Hence == old_active_client), conserve focus.
@ -1334,7 +1227,7 @@ bool Workspace::setCurrentDesktop(int new_desktop)
c = active_client;
if (c == NULL && !desktops.isEmpty())
c = findDesktop(true, currentDesktop());
c = findDesktop(true, desktop);
if (c != active_client)
setActiveClient(NULL, Allowed);
@ -1342,32 +1235,55 @@ bool Workspace::setCurrentDesktop(int new_desktop)
if (c)
requestFocus(c);
else if (!desktops.isEmpty())
requestFocus(findDesktop(true, currentDesktop()));
requestFocus(findDesktop(true, desktop));
else
focusToNull();
// Update focus chain:
// If input: chain = { 1, 2, 3, 4 } and currentDesktop() = 3,
// Output: chain = { 3, 1, 2, 4 }.
//kDebug(1212) << QString("Switching to desktop #%1, at focus_chain index %2\n")
// .arg(currentDesktop()).arg(desktop_focus_chain.find( currentDesktop() ));
QVector<int> &chain = m_desktopFocusChain.value();
for (int i = chain.indexOf(currentDesktop()); i > 0; --i)
chain[i] = chain[i-1];
chain[0] = currentDesktop();
//QString s = "desktop_focus_chain[] = { ";
//for ( uint i = 0; i < desktop_focus_chain.size(); i++ )
// s += QString::number( desktop_focus_chain[i] ) + ", ";
//kDebug( 1212 ) << s << "}\n";
emit currentDesktopChanged(old_desktop, movingClient);
return true;
}
int Workspace::maxNumberOfDesktops() const
Client *Workspace::findClientToActivateOnDesktop(uint desktop)
{
return KWIN_MAX_NUMBER_DESKTOPS;
if (movingClient != NULL && active_client == movingClient &&
focus_chain[desktop].contains(active_client) &&
active_client->isShown(true) && active_client->isOnCurrentDesktop()) {
// A requestFocus call will fail, as the client is already active
return active_client;
}
// from actiavtion.cpp
if (options->isNextFocusPrefersMouse()) {
ToplevelList::const_iterator it = stackingOrder().constEnd();
while (it != stackingOrder().constBegin()) {
Client *client = qobject_cast<Client*>(*(--it));
if (!client) {
continue;
}
if (!(client->isShown(false) && client->isOnDesktop(desktop) &&
client->isOnCurrentActivity() && client->isOnScreen(activeScreen())))
continue;
if (client->geometry().contains(QCursor::pos())) {
if (!client->isDesktop())
return client;
break; // unconditional break - we do not pass the focus to some client below an unusable one
}
}
}
for (int i = focus_chain[desktop].size() - 1; i >= 0; --i) {
Client* tmp = focus_chain[desktop].at(i);
if (tmp->isShown(false) && tmp->isOnCurrentActivity()
&& ( !options->isSeparateScreenFocus() || tmp->screen() == activeScreen() )) {
return tmp;
}
}
return NULL;
}
void Workspace::updateDesktopFocusChain(uint desktop)
{
QVector<uint> &chain = m_desktopFocusChain.value();
for (int i = chain.indexOf(desktop); i > 0; --i)
chain[i] = chain[i-1];
chain[0] = desktop;
}
#ifdef KWIN_BUILD_ACTIVITIES
@ -1515,14 +1431,14 @@ void Workspace::updateCurrentActivity(const QString &new_activity)
if (options->focusPolicyIsReasonable()) {
// Search in focus chain
if (movingClient != NULL && active_client == movingClient &&
focus_chain[currentDesktop()].contains(active_client) &&
focus_chain[VirtualDesktopManager::self()->current()].contains(active_client) &&
active_client->isShown(true) && active_client->isOnCurrentDesktop())
c = active_client; // The requestFocus below will fail, as the client is already active
if (!c) {
for (int i = focus_chain[currentDesktop()].size() - 1; i >= 0; --i) {
if (focus_chain[currentDesktop()].at(i)->isShown(false) &&
focus_chain[currentDesktop()].at(i)->isOnCurrentActivity()) {
c = focus_chain[currentDesktop()].at(i);
for (int i = focus_chain[VirtualDesktopManager::self()->current()].size() - 1; i >= 0; --i) {
if (focus_chain[VirtualDesktopManager::self()->current()].at(i)->isShown(false) &&
focus_chain[VirtualDesktopManager::self()->current()].at(i)->isOnCurrentActivity()) {
c = focus_chain[VirtualDesktopManager::self()->current()].at(i);
break;
}
}
@ -1535,7 +1451,7 @@ void Workspace::updateCurrentActivity(const QString &new_activity)
c = active_client;
if (c == NULL && !desktops.isEmpty())
c = findDesktop(true, currentDesktop());
c = findDesktop(true, VirtualDesktopManager::self()->current());
if (c != active_client)
setActiveClient(NULL, Allowed);
@ -1543,7 +1459,7 @@ void Workspace::updateCurrentActivity(const QString &new_activity)
if (c)
requestFocus(c);
else if (!desktops.isEmpty())
requestFocus(findDesktop(true, currentDesktop()));
requestFocus(findDesktop(true, VirtualDesktopManager::self()->current()));
else
focusToNull();
@ -1551,15 +1467,15 @@ void Workspace::updateCurrentActivity(const QString &new_activity)
#ifdef KWIN_BUILD_ACTIVITIES
// Replace initial dummy with actual activity, preserving the current chain.
if (m_desktopFocusChain.key().isNull()) {
QVector<int> val(m_desktopFocusChain.value());
QVector<uint> val(m_desktopFocusChain.value());
m_activitiesDesktopFocusChain.erase(m_desktopFocusChain);
m_desktopFocusChain = m_activitiesDesktopFocusChain.insert(activity_, val);
} else {
m_desktopFocusChain = m_activitiesDesktopFocusChain.find(activity_);
if (m_desktopFocusChain == m_activitiesDesktopFocusChain.end()) {
m_desktopFocusChain = m_activitiesDesktopFocusChain.insert(activity_, QVector<int>(numberOfDesktops()));
m_desktopFocusChain = m_activitiesDesktopFocusChain.insert(activity_, QVector<uint>(VirtualDesktopManager::self()->count()));
for (int i = 0; i < numberOfDesktops(); ++i) {
for (uint i = 0; i < VirtualDesktopManager::self()->count(); ++i) {
m_desktopFocusChain.value()[i] = i + 1;
}
}
@ -1597,85 +1513,54 @@ void Workspace::slotActivityAdded(const QString &activity)
allActivities_ << activity;
}
/**
* Called only from D-Bus
*/
void Workspace::nextDesktop()
void Workspace::moveClientsFromRemovedDesktops()
{
int desktop = currentDesktop() + 1;
setCurrentDesktop(desktop > numberOfDesktops() ? 1 : desktop);
}
/**
* Called only from D-Bus
*/
void Workspace::previousDesktop()
{
int desktop = currentDesktop() - 1;
setCurrentDesktop(desktop > 0 ? desktop : numberOfDesktops());
}
/**
* Sets the number of virtual desktops to \a n
*/
void Workspace::setNumberOfDesktops(int n)
{
if (n > KWIN_MAX_NUMBER_DESKTOPS)
n = KWIN_MAX_NUMBER_DESKTOPS;
if (n < 1 || n == numberOfDesktops())
return;
int old_number_of_desktops = numberOfDesktops();
desktopCount_ = n;
Placement::self()->reinitCascading(0);
updateDesktopLayout(); // Make sure the layout is still valid
if (currentDesktop() > n)
setCurrentDesktop(n);
// move all windows that would be hidden to the last visible desktop
if (old_number_of_desktops > numberOfDesktops()) {
for (ClientList::ConstIterator it = clients.constBegin(); it != clients.constEnd(); ++it) {
if (!(*it)->isOnAllDesktops() && (*it)->desktop() > numberOfDesktops())
sendClientToDesktop(*it, numberOfDesktops(), true);
// TODO: Tile should have a method allClients, push them into other tiles
}
for (ClientList::ConstIterator it = clients.constBegin(); it != clients.constEnd(); ++it) {
if (!(*it)->isOnAllDesktops() && (*it)->desktop() > static_cast<int>(VirtualDesktopManager::self()->count()))
sendClientToDesktop(*it, VirtualDesktopManager::self()->count(), true);
}
rootInfo->setNumberOfDesktops(n);
NETPoint* viewports = new NETPoint[n];
rootInfo->setDesktopViewport(n, *viewports);
delete[] viewports;
}
void Workspace::slotDesktopCountChanged(uint previousCount, uint newCount)
{
Placement::self()->reinitCascading(0);
// Make it +1, so that it can be accessed as [1..numberofdesktops]
focus_chain.resize(n + 1);
focus_chain.resize(newCount + 1);
workarea.clear();
workarea.resize(n + 1);
restrictedmovearea.clear();
restrictedmovearea.resize(n + 1);
screenarea.clear();
resetClientAreas(newCount);
resizeDesktopFocusChain(previousCount, newCount);
}
updateClientArea(true);
// Resize the desktop focus chain.
void Workspace::resizeDesktopFocusChain(uint previousCount, uint newCount)
{
for (DesktopFocusChains::iterator it = m_activitiesDesktopFocusChain.begin(), end = m_activitiesDesktopFocusChain.end(); it != end; ++it) {
QVector<int> &chain = it.value();
chain.resize(n);
QVector<uint> &chain = it.value();
chain.resize(newCount);
// We do not destroy the chain in case new desktops are added;
if (n >= old_number_of_desktops) {
for (int i = old_number_of_desktops; i < n; ++i)
if (newCount >= previousCount) {
for (uint i = previousCount; i < newCount; ++i)
chain[i] = i + 1;
// But when desktops are removed, we may have to modify the chain a bit,
// otherwise invalid desktops may show up.
} else {
for (int i = 0; i < chain.size(); ++i)
chain[i] = qMin(chain[i], n);
chain[i] = qMin(chain[i], newCount);
}
}
}
saveDesktopSettings();
emit numberDesktopsChanged(old_number_of_desktops);
void Workspace::resetClientAreas(uint desktopCount)
{
// Make it +1, so that it can be accessed as [1..numberofdesktops]
workarea.clear();
workarea.resize(desktopCount + 1);
restrictedmovearea.clear();
restrictedmovearea.resize(desktopCount + 1);
screenarea.clear();
updateClientArea(true);
}
/**
@ -1685,7 +1570,7 @@ void Workspace::setNumberOfDesktops(int n)
*/
void Workspace::sendClientToDesktop(Client* c, int desk, bool dont_activate)
{
if ((desk < 1 && desk != NET::OnAllDesktops) || desk > numberOfDesktops())
if ((desk < 1 && desk != NET::OnAllDesktops) || desk > static_cast<int>(VirtualDesktopManager::self()->count()))
return;
int old_desktop = c->desktop();
bool was_on_desktop = c->isOnDesktop(desk) || c->isOnAllDesktops();
@ -1696,7 +1581,7 @@ void Workspace::sendClientToDesktop(Client* c, int desk, bool dont_activate)
emit desktopPresenceChanged(c, old_desktop);
if (c->isOnDesktop(currentDesktop())) {
if (c->isOnDesktop(VirtualDesktopManager::self()->current())) {
if (c->wantsTabFocus() && options->focusPolicyIsReasonable() &&
!was_on_desktop && // for stickyness changes
!dont_activate)
@ -1920,11 +1805,6 @@ QList<int> Workspace::decorationSupportedColors() const
return ret;
}
QString Workspace::desktopName(int desk) const
{
return QString::fromUtf8(rootInfo->desktopName(desk));
}
bool Workspace::checkStartupNotification(Window w, KStartupInfoId& id, KStartupInfoData& data)
{
return startup->checkStartup(w, id, data) == KStartupInfo::Match;
@ -1965,7 +1845,7 @@ void Workspace::setShowingDesktop(bool showing)
++it)
(*it)->minimize();
--block_focus;
if (Client* desk = findDesktop(true, currentDesktop()))
if (Client* desk = findDesktop(true, VirtualDesktopManager::self()->current()))
requestFocus(desk);
} else {
for (ClientList::ConstIterator it = showing_desktop_clients.constBegin();

View File

@ -205,108 +205,10 @@ public:
ScreenEdge* screenEdge();
#endif
//-------------------------------------------------
// Desktop layout
public:
/**
* @returns Total number of desktops currently in existence.
*/
int numberOfDesktops() const;
/**
* @returns The maximum number of desktops that KWin supports.
*/
int maxNumberOfDesktops() const;
/**
* Set the number of available desktops to @a count. This function overrides any previous
* grid layout.
*/
void setNumberOfDesktops(int count);
/**
* Called from within setNumberOfDesktops() to ensure the desktop layout is still valid.
*/
void updateDesktopLayout();
/**
* @returns The size of desktop layout in grid units.
*/
QSize desktopGridSize() const;
/**
* @returns The width of desktop layout in grid units.
*/
int desktopGridWidth() const;
/**
* @returns The height of desktop layout in grid units.
*/
int desktopGridHeight() const;
/**
* @returns The width of desktop layout in pixels. Equivalent to gridWidth() *
* ::displayWidth().
*/
int workspaceWidth() const;
/**
* @returns The height of desktop layout in pixels. Equivalent to gridHeight() *
* ::displayHeight().
*/
int workspaceHeight() const;
/**
* @returns The ID of the current desktop.
*/
int currentDesktop() const;
/**
* Set the current desktop to @a current.
* @returns True on success, false otherwise.
*/
bool setCurrentDesktop(int current);
/**
* Generate a desktop layout from EWMH _NET_DESKTOP_LAYOUT property parameters.
*/
void setNETDesktopLayout(Qt::Orientation orientation, int width, int height, int startingCorner);
/**
* @returns The ID of the desktop at the point @a coords or 0 if no desktop exists at that
* point. @a coords is to be in grid units.
*/
int desktopAtCoords(QPoint coords) const;
/**
* @returns The coords of desktop @a id in grid units.
*/
QPoint desktopGridCoords(int id) const;
/**
* @returns The coords of the top-left corner of desktop @a id in pixels.
*/
QPoint desktopCoords(int id) const;
/**
* @returns The ID of the desktop above desktop @a id. Wraps around to the bottom of
* the layout if @a wrap is set. If @a id is not set use the current one.
*/
int desktopAbove(int id = 0, bool wrap = true) const;
/**
* @returns The ID of the desktop to the right of desktop @a id. Wraps around to the
* left of the layout if @a wrap is set. If @a id is not set use the current one.
*/
int desktopToRight(int id = 0, bool wrap = true) const;
/**
* @returns The ID of the desktop below desktop @a id. Wraps around to the top of the
* layout if @a wrap is set. If @a id is not set use the current one.
*/
int desktopBelow(int id = 0, bool wrap = true) const;
/**
* @returns The ID of the desktop to the left of desktop @a id. Wraps around to the
* right of the layout if @a wrap is set. If @a id is not set use the current one.
*/
int desktopToLeft(int id = 0, bool wrap = true) const;
QPoint cascadeOffset(const Client *c) const;
private:
int desktopCount_;
QSize desktopGridSize_;
int* desktopGrid_;
int currentDesktop_;
QString activity_;
QStringList allActivities_, openActivities_;
#ifdef KWIN_BUILD_ACTIVITIES
@ -356,7 +258,7 @@ public:
#endif
bool hasTabBox() const;
const QVector<int> &desktopFocusChain() const {
const QVector<uint> &desktopFocusChain() const {
return m_desktopFocusChain.value();
}
const ClientList &globalFocusChain() const {
@ -450,8 +352,6 @@ public:
* @todo: remove KDE5
**/
QList<int> decorationSupportedColors() const;
void nextDesktop();
void previousDesktop();
bool waitForCompositingSetup();
bool stopActivity(const QString &id);
bool startActivity(const QString &id);
@ -459,7 +359,6 @@ public:
void setCurrentScreen(int new_screen);
QString desktopName(int desk) const;
void setShowingDesktop(bool showing);
void resetShowingDesktop(bool keep_hidden);
bool showingDesktop() const;
@ -521,14 +420,6 @@ public:
public slots:
// Keybindings
void slotSwitchDesktopNext();
void slotSwitchDesktopPrevious();
void slotSwitchDesktopRight();
void slotSwitchDesktopLeft();
void slotSwitchDesktopUp();
void slotSwitchDesktopDown();
void slotSwitchToDesktop();
//void slotSwitchToWindow( int );
void slotWindowToDesktop();
@ -631,6 +522,10 @@ private slots:
void slotActivityAdded(const QString &activity);
void reallyStopActivity(const QString &id); //dbus deadlocks suck
void handleActivityReply();
// virtual desktop handling
void moveClientsFromRemovedDesktops();
void slotDesktopCountChanged(uint previousCount, uint newCount);
void slotCurrentDesktopChanged(uint oldDesktop, uint newDesktop);
Q_SIGNALS:
/**
@ -643,7 +538,6 @@ Q_SIGNALS:
signals:
void desktopPresenceChanged(KWin::Client*, int);
void currentDesktopChanged(int, KWin::Client*);
void numberDesktopsChanged(int oldNumberOfDesktops);
void clientAdded(KWin::Client*);
void clientRemoved(KWin::Client*);
void clientActivated(KWin::Client*);
@ -706,16 +600,18 @@ private:
Window findSpecialEventWindow(XEvent* e);
// Desktop names and number of desktops
void loadDesktopSettings();
void saveDesktopSettings();
//---------------------------------------------------------------------
void closeActivePopup();
void updateClientArea(bool force);
void resizeDesktopFocusChain(uint previousCount, uint newCount);
void resetClientAreas(uint desktopCount);
void updateClientVisibilityOnDesktopChange(uint oldDesktop, uint newDesktop);
void activateClientOnNewDesktop(uint desktop);
Client *findClientToActivateOnDesktop(uint desktop);
void updateDesktopFocusChain(uint desktop);
typedef QHash< QString, QVector<int> > DesktopFocusChains;
typedef QHash< QString, QVector<uint> > DesktopFocusChains;
DesktopFocusChains::Iterator m_desktopFocusChain;
DesktopFocusChains m_activitiesDesktopFocusChain;
@ -900,49 +796,6 @@ private:
Workspace* workspace;
};
//---------------------------------------------------------
// Desktop layout
inline int Workspace::numberOfDesktops() const
{
return desktopCount_;
}
inline QSize Workspace::desktopGridSize() const
{
return desktopGridSize_;
}
inline int Workspace::desktopGridWidth() const
{
return desktopGridSize_.width();
}
inline int Workspace::desktopGridHeight() const
{
return desktopGridSize_.height();
}
inline int Workspace::workspaceWidth() const
{
return desktopGridSize_.width() * displayWidth();
}
inline int Workspace::workspaceHeight() const
{
return desktopGridSize_.height() * displayHeight();
}
inline int Workspace::currentDesktop() const
{
return currentDesktop_;
}
inline int Workspace::desktopAtCoords(QPoint coords) const
{
return desktopGrid_[coords.y() * desktopGridSize_.width() + coords.x()];
}
//---------------------------------------------------------
// Unsorted