[wayland] Use the new plasma virtual desktop protocol
Summary: implement virtual desktop support for Wayland. use the new virtual desktop protocol from D12820 The VirtualDesktopManager class needed some big change in order to accomodate it, which is where most changes are. Other than that, it's mostly connections to wire up VirtualDesktopsManager and VirtualDesktopsManagement(the wayland protocol impl) Depends on D12820 Other notable detail, is the client visibility updated to reflect the presence of the client in the plasmavirtualdesktop. (and the unSetDesktop concept) Test Plan: used a bit a plasma session together with D12820, D13748 and D13746 Reviewers: #plasma, #kwin, graesslin, davidedmundson Reviewed By: #plasma, #kwin, davidedmundson Subscribers: hein, zzag, davidedmundson, kwin Tags: #kwin Maniphest Tasks: T4457 Differential Revision: https://phabricator.kde.org/D13887icc-effect-5.17.5
parent
e0aa3a3049
commit
7e8facc3fd
|
@ -381,6 +381,7 @@ add_subdirectory(helpers)
|
||||||
set(kwin_KDEINIT_SRCS
|
set(kwin_KDEINIT_SRCS
|
||||||
workspace.cpp
|
workspace.cpp
|
||||||
dbusinterface.cpp
|
dbusinterface.cpp
|
||||||
|
virtualdesktopsdbustypes.cpp
|
||||||
abstract_client.cpp
|
abstract_client.cpp
|
||||||
client.cpp
|
client.cpp
|
||||||
client_machine.cpp
|
client_machine.cpp
|
||||||
|
@ -533,6 +534,7 @@ qt5_add_dbus_adaptor( kwin_KDEINIT_SRCS org.kde.kwin.Compositing.xml dbusinterfa
|
||||||
qt5_add_dbus_adaptor( kwin_KDEINIT_SRCS org.kde.kwin.ColorCorrect.xml colorcorrection/colorcorrectdbusinterface.h KWin::ColorCorrect::ColorCorrectDBusInterface )
|
qt5_add_dbus_adaptor( kwin_KDEINIT_SRCS org.kde.kwin.ColorCorrect.xml colorcorrection/colorcorrectdbusinterface.h KWin::ColorCorrect::ColorCorrectDBusInterface )
|
||||||
qt5_add_dbus_adaptor( kwin_KDEINIT_SRCS ${kwin_effects_dbus_xml} effects.h KWin::EffectsHandlerImpl )
|
qt5_add_dbus_adaptor( kwin_KDEINIT_SRCS ${kwin_effects_dbus_xml} effects.h KWin::EffectsHandlerImpl )
|
||||||
qt5_add_dbus_adaptor( kwin_KDEINIT_SRCS org.kde.kwin.OrientationSensor.xml orientation_sensor.h KWin::OrientationSensor)
|
qt5_add_dbus_adaptor( kwin_KDEINIT_SRCS org.kde.kwin.OrientationSensor.xml orientation_sensor.h KWin::OrientationSensor)
|
||||||
|
qt5_add_dbus_adaptor( kwin_KDEINIT_SRCS org.kde.KWin.VirtualDesktopManager.xml dbusinterface.h KWin::VirtualDesktopManagerDBusInterface )
|
||||||
|
|
||||||
qt5_add_dbus_interface( kwin_KDEINIT_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/org.freedesktop.ScreenSaver.xml screenlocker_interface)
|
qt5_add_dbus_interface( kwin_KDEINIT_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/org.freedesktop.ScreenSaver.xml screenlocker_interface)
|
||||||
|
|
||||||
|
@ -671,6 +673,7 @@ install(
|
||||||
org.kde.kwin.Compositing.xml
|
org.kde.kwin.Compositing.xml
|
||||||
org.kde.kwin.ColorCorrect.xml
|
org.kde.kwin.ColorCorrect.xml
|
||||||
org.kde.kwin.Effects.xml
|
org.kde.kwin.Effects.xml
|
||||||
|
org.kde.KWin.VirtualDesktopManager.xml
|
||||||
DESTINATION
|
DESTINATION
|
||||||
${KDE_INSTALL_DBUSINTERFACEDIR}
|
${KDE_INSTALL_DBUSINTERFACEDIR}
|
||||||
)
|
)
|
||||||
|
|
|
@ -489,16 +489,44 @@ void AbstractClient::setDesktop(int desktop)
|
||||||
if (desktop != NET::OnAllDesktops) // Do range check
|
if (desktop != NET::OnAllDesktops) // Do range check
|
||||||
desktop = qMax(1, qMin(numberOfDesktops, desktop));
|
desktop = qMax(1, qMin(numberOfDesktops, desktop));
|
||||||
desktop = qMin(numberOfDesktops, rules()->checkDesktop(desktop));
|
desktop = qMin(numberOfDesktops, rules()->checkDesktop(desktop));
|
||||||
if (m_desktop == desktop)
|
|
||||||
return;
|
|
||||||
|
|
||||||
int was_desk = m_desktop;
|
VirtualDesktop *virtualDesktop = desktop == NET::OnAllDesktops ? nullptr : VirtualDesktopManager::self()->desktopForX11Id(desktop);
|
||||||
const bool wasOnCurrentDesktop = isOnCurrentDesktop();
|
|
||||||
m_desktop = desktop;
|
// Don't do anything if we're already there, if the desktop is already in desktops or if the desktop is NET::OnAllDesktops and m_desktops is already empty.
|
||||||
|
if (m_desktops.contains(virtualDesktop) ||
|
||||||
|
(desktop == NET::OnAllDesktops && m_desktops.isEmpty())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int was_desk = AbstractClient::desktop();
|
||||||
|
const bool wasOnCurrentDesktop = isOnCurrentDesktop() && was_desk >= 0;
|
||||||
|
|
||||||
|
//on x11 we can have only one desktop at a time
|
||||||
|
if (kwinApp()->operationMode() == Application::OperationModeX11) {
|
||||||
|
m_desktops.clear();
|
||||||
|
}
|
||||||
|
if (desktop == NET::OnAllDesktops) {
|
||||||
|
m_desktops.clear();
|
||||||
|
} else {
|
||||||
|
//if would become on all desktops, clear the list, as empty == on all desktops
|
||||||
|
if (m_desktops.count() > 1 && static_cast<uint>(m_desktops.count()) == VirtualDesktopManager::self()->count() - 1) {
|
||||||
|
m_desktops.clear();
|
||||||
|
} else {
|
||||||
|
m_desktops << virtualDesktop;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (windowManagementInterface()) {
|
||||||
|
if (m_desktops.isEmpty()) {
|
||||||
|
windowManagementInterface()->setOnAllDesktops(true);
|
||||||
|
} else {
|
||||||
|
windowManagementInterface()->addPlasmaVirtualDesktop(virtualDesktop->id());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (info) {
|
if (info) {
|
||||||
info->setDesktop(desktop);
|
info->setDesktop(desktop);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((was_desk == NET::OnAllDesktops) != (desktop == NET::OnAllDesktops)) {
|
if ((was_desk == NET::OnAllDesktops) != (desktop == NET::OnAllDesktops)) {
|
||||||
// onAllDesktops changed
|
// onAllDesktops changed
|
||||||
workspace()->updateOnAllDesktopsOfTransients(this);
|
workspace()->updateOnAllDesktopsOfTransients(this);
|
||||||
|
@ -526,6 +554,7 @@ void AbstractClient::setDesktop(int desktop)
|
||||||
emit desktopChanged();
|
emit desktopChanged();
|
||||||
if (wasOnCurrentDesktop != isOnCurrentDesktop())
|
if (wasOnCurrentDesktop != isOnCurrentDesktop())
|
||||||
emit desktopPresenceChanged(this, was_desk);
|
emit desktopPresenceChanged(this, was_desk);
|
||||||
|
emit x11DesktopIdsChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
void AbstractClient::doSetDesktop(int desktop, int was_desk)
|
void AbstractClient::doSetDesktop(int desktop, int was_desk)
|
||||||
|
@ -534,6 +563,34 @@ void AbstractClient::doSetDesktop(int desktop, int was_desk)
|
||||||
Q_UNUSED(was_desk)
|
Q_UNUSED(was_desk)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AbstractClient::unSetDesktop(int desktop)
|
||||||
|
{
|
||||||
|
// Case in which we are on all desktops and gets asked to unset
|
||||||
|
if (desktop == NET::OnAllDesktops) {
|
||||||
|
if (m_desktops.isEmpty()) {
|
||||||
|
setOnAllDesktops(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Out of range
|
||||||
|
if (desktop < 1 || desktop > VirtualDesktopManager::self()->count()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
VirtualDesktop *virtualDesktop = VirtualDesktopManager::self()->desktopForX11Id(desktop);
|
||||||
|
|
||||||
|
m_desktops.removeAll(virtualDesktop);
|
||||||
|
|
||||||
|
if (!windowManagementInterface()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
windowManagementInterface()->removePlasmaVirtualDesktop(virtualDesktop->id());
|
||||||
|
emit x11DesktopIdsChanged();
|
||||||
|
}
|
||||||
|
|
||||||
void AbstractClient::setOnAllDesktops(bool b)
|
void AbstractClient::setOnAllDesktops(bool b)
|
||||||
{
|
{
|
||||||
if ((b && isOnAllDesktops()) ||
|
if ((b && isOnAllDesktops()) ||
|
||||||
|
@ -545,6 +602,20 @@ void AbstractClient::setOnAllDesktops(bool b)
|
||||||
setDesktop(VirtualDesktopManager::self()->current());
|
setDesktop(VirtualDesktopManager::self()->current());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QList<int> AbstractClient::x11DesktopIds() const
|
||||||
|
{
|
||||||
|
const auto desks = desktops();
|
||||||
|
QList<int> x11Ids;
|
||||||
|
x11Ids.reserve(desks.count());
|
||||||
|
std::transform(desks.constBegin(), desks.constEnd(),
|
||||||
|
std::back_inserter(x11Ids),
|
||||||
|
[] (const VirtualDesktop *vd) {
|
||||||
|
return vd->x11DesktopNumber();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
return x11Ids;
|
||||||
|
}
|
||||||
|
|
||||||
bool AbstractClient::isShadeable() const
|
bool AbstractClient::isShadeable() const
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
|
@ -808,16 +879,7 @@ void AbstractClient::setupWindowManagementInterface()
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
connect(this, &AbstractClient::captionChanged, w, [w, this] { w->setTitle(caption()); });
|
connect(this, &AbstractClient::captionChanged, w, [w, this] { w->setTitle(caption()); });
|
||||||
connect(this, &AbstractClient::desktopChanged, w,
|
|
||||||
[w, this] {
|
|
||||||
if (isOnAllDesktops()) {
|
|
||||||
w->setOnAllDesktops(true);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
w->setVirtualDesktop(desktop() - 1);
|
|
||||||
w->setOnAllDesktops(false);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
connect(this, &AbstractClient::activeChanged, w, [w, this] { w->setActive(isActive()); });
|
connect(this, &AbstractClient::activeChanged, w, [w, this] { w->setActive(isActive()); });
|
||||||
connect(this, &AbstractClient::fullScreenChanged, w, [w, this] { w->setFullscreen(isFullScreen()); });
|
connect(this, &AbstractClient::fullScreenChanged, w, [w, this] { w->setFullscreen(isFullScreen()); });
|
||||||
connect(this, &AbstractClient::keepAboveChanged, w, &PlasmaWindowInterface::setKeepAbove);
|
connect(this, &AbstractClient::keepAboveChanged, w, &PlasmaWindowInterface::setKeepAbove);
|
||||||
|
@ -912,6 +974,48 @@ void AbstractClient::setupWindowManagementInterface()
|
||||||
setShade(set);
|
setShade(set);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
for (const auto vd : m_desktops) {
|
||||||
|
w->addPlasmaVirtualDesktop(vd->id());
|
||||||
|
}
|
||||||
|
|
||||||
|
//this is only for the legacy
|
||||||
|
connect(this, &AbstractClient::desktopChanged, w,
|
||||||
|
[w, this] {
|
||||||
|
if (isOnAllDesktops()) {
|
||||||
|
w->setOnAllDesktops(true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
w->setVirtualDesktop(desktop() - 1);
|
||||||
|
w->setOnAllDesktops(false);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
//Plasma Virtual desktop management
|
||||||
|
//show/hide when the window enters/exits from desktop
|
||||||
|
connect(w, &PlasmaWindowInterface::enterPlasmaVirtualDesktopRequested, this,
|
||||||
|
[this] (const QString &desktopId) {
|
||||||
|
VirtualDesktop *vd = VirtualDesktopManager::self()->desktopForId(desktopId.toUtf8());
|
||||||
|
if (vd) {
|
||||||
|
workspace()->sendClientToDesktop(this, vd->x11DesktopNumber(), false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
connect(w, &PlasmaWindowInterface::enterNewPlasmaVirtualDesktopRequested, this,
|
||||||
|
[this] () {
|
||||||
|
VirtualDesktopManager::self()->setCount(VirtualDesktopManager::self()->count() + 1);
|
||||||
|
workspace()->sendClientToDesktop(this, VirtualDesktopManager::self()->count(), false);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
connect(w, &PlasmaWindowInterface::leavePlasmaVirtualDesktopRequested, this,
|
||||||
|
[this] (const QString &desktopId) {
|
||||||
|
VirtualDesktop *vd = VirtualDesktopManager::self()->desktopForId(desktopId.toUtf8());
|
||||||
|
if (vd) {
|
||||||
|
unSetDesktop(vd->x11DesktopNumber());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
m_windowManagementInterface = w;
|
m_windowManagementInterface = w;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -84,12 +84,17 @@ class KWIN_EXPORT AbstractClient : public Toplevel
|
||||||
Q_PROPERTY(bool active READ isActive NOTIFY activeChanged)
|
Q_PROPERTY(bool active READ isActive NOTIFY activeChanged)
|
||||||
/**
|
/**
|
||||||
* The desktop this Client is on. If the Client is on all desktops the property has value -1.
|
* The desktop this Client is on. If the Client is on all desktops the property has value -1.
|
||||||
|
* This is a legacy property, use x11DesktopIds instead
|
||||||
**/
|
**/
|
||||||
Q_PROPERTY(int desktop READ desktop WRITE setDesktop NOTIFY desktopChanged)
|
Q_PROPERTY(int desktop READ desktop WRITE setDesktop NOTIFY desktopChanged)
|
||||||
/**
|
/**
|
||||||
* Whether the Client is on all desktops. That is desktop is -1.
|
* Whether the Client is on all desktops. That is desktop is -1.
|
||||||
**/
|
**/
|
||||||
Q_PROPERTY(bool onAllDesktops READ isOnAllDesktops WRITE setOnAllDesktops NOTIFY desktopChanged)
|
Q_PROPERTY(bool onAllDesktops READ isOnAllDesktops WRITE setOnAllDesktops NOTIFY desktopChanged)
|
||||||
|
/**
|
||||||
|
* The x11 ids for all desktops this client is in. On X11 this list will always have a length of 1
|
||||||
|
**/
|
||||||
|
Q_PROPERTY(QList<int> x11DesktopIds READ x11DesktopIds NOTIFY x11DesktopIdsChanged)
|
||||||
/**
|
/**
|
||||||
* Indicates that the window should not be included on a taskbar.
|
* Indicates that the window should not be included on a taskbar.
|
||||||
**/
|
**/
|
||||||
|
@ -423,9 +428,18 @@ public:
|
||||||
virtual bool performMouseCommand(Options::MouseCommand, const QPoint &globalPos);
|
virtual bool performMouseCommand(Options::MouseCommand, const QPoint &globalPos);
|
||||||
void setOnAllDesktops(bool set);
|
void setOnAllDesktops(bool set);
|
||||||
void setDesktop(int);
|
void setDesktop(int);
|
||||||
|
Q_INVOKABLE virtual void unSetDesktop(int desktop);
|
||||||
int desktop() const override {
|
int desktop() const override {
|
||||||
return m_desktop;
|
return m_desktops.isEmpty() ? (int)NET::OnAllDesktops : m_desktops.last()->x11DesktopNumber();
|
||||||
}
|
}
|
||||||
|
virtual QList<VirtualDesktop *> desktops() const {
|
||||||
|
return m_desktops;
|
||||||
|
}
|
||||||
|
void removeDesktop(VirtualDesktop *desktop) {
|
||||||
|
m_desktops.removeAll(desktop);
|
||||||
|
}
|
||||||
|
QList<int> x11DesktopIds() const;
|
||||||
|
|
||||||
void setMinimized(bool set);
|
void setMinimized(bool set);
|
||||||
/**
|
/**
|
||||||
* Minimizes this client plus its transients
|
* Minimizes this client plus its transients
|
||||||
|
@ -757,6 +771,7 @@ Q_SIGNALS:
|
||||||
void demandsAttentionChanged();
|
void demandsAttentionChanged();
|
||||||
void desktopPresenceChanged(KWin::AbstractClient*, int); // to be forwarded by Workspace
|
void desktopPresenceChanged(KWin::AbstractClient*, int); // to be forwarded by Workspace
|
||||||
void desktopChanged();
|
void desktopChanged();
|
||||||
|
void x11DesktopIdsChanged();
|
||||||
void shadeChanged();
|
void shadeChanged();
|
||||||
void minimizedChanged();
|
void minimizedChanged();
|
||||||
void clientMinimized(KWin::AbstractClient* client, bool animate);
|
void clientMinimized(KWin::AbstractClient* client, bool animate);
|
||||||
|
@ -1107,7 +1122,7 @@ private:
|
||||||
bool m_demandsAttention = false;
|
bool m_demandsAttention = false;
|
||||||
bool m_minimized = false;
|
bool m_minimized = false;
|
||||||
QTimer *m_autoRaiseTimer = nullptr;
|
QTimer *m_autoRaiseTimer = nullptr;
|
||||||
int m_desktop = 0; // 0 means not on any desktop yet
|
QList <VirtualDesktop *> m_desktops;
|
||||||
|
|
||||||
QString m_colorScheme;
|
QString m_colorScheme;
|
||||||
std::shared_ptr<Decoration::DecorationPalette> m_palette;
|
std::shared_ptr<Decoration::DecorationPalette> m_palette;
|
||||||
|
|
|
@ -43,6 +43,7 @@ target_link_libraries( testVirtualDesktops
|
||||||
KF5::GlobalAccel
|
KF5::GlobalAccel
|
||||||
KF5::ConfigCore
|
KF5::ConfigCore
|
||||||
KF5::WindowSystem
|
KF5::WindowSystem
|
||||||
|
KF5::WaylandServer
|
||||||
)
|
)
|
||||||
add_test(NAME kwin-testVirtualDesktops COMMAND testVirtualDesktops)
|
add_test(NAME kwin-testVirtualDesktops COMMAND testVirtualDesktops)
|
||||||
ecm_mark_as_test(testVirtualDesktops)
|
ecm_mark_as_test(testVirtualDesktops)
|
||||||
|
@ -336,6 +337,7 @@ target_link_libraries(testScreenEdges
|
||||||
KF5::GlobalAccel
|
KF5::GlobalAccel
|
||||||
KF5::Notifications
|
KF5::Notifications
|
||||||
KF5::WindowSystem
|
KF5::WindowSystem
|
||||||
|
KF5::WaylandServer
|
||||||
XCB::XCB
|
XCB::XCB
|
||||||
XCB::RANDR
|
XCB::RANDR
|
||||||
XCB::XFIXES
|
XCB::XFIXES
|
||||||
|
|
|
@ -43,6 +43,10 @@ private Q_SLOTS:
|
||||||
void testNetCurrentDesktop();
|
void testNetCurrentDesktop();
|
||||||
void testLastDesktopRemoved_data();
|
void testLastDesktopRemoved_data();
|
||||||
void testLastDesktopRemoved();
|
void testLastDesktopRemoved();
|
||||||
|
void testWindowOnMultipleDesktops_data();
|
||||||
|
void testWindowOnMultipleDesktops();
|
||||||
|
void testRemoveDesktopWithWindow_data();
|
||||||
|
void testRemoveDesktopWithWindow();
|
||||||
};
|
};
|
||||||
|
|
||||||
void VirtualDesktopTest::initTestCase()
|
void VirtualDesktopTest::initTestCase()
|
||||||
|
@ -157,12 +161,154 @@ void VirtualDesktopTest::testLastDesktopRemoved()
|
||||||
QSignalSpy desktopPresenceChangedSpy(client, &ShellClient::desktopPresenceChanged);
|
QSignalSpy desktopPresenceChangedSpy(client, &ShellClient::desktopPresenceChanged);
|
||||||
QVERIFY(desktopPresenceChangedSpy.isValid());
|
QVERIFY(desktopPresenceChangedSpy.isValid());
|
||||||
|
|
||||||
|
QCOMPARE(client->desktops().count(), 1u);
|
||||||
|
QCOMPARE(VirtualDesktopManager::self()->currentDesktop(), client->desktops().first());
|
||||||
|
|
||||||
// and remove last desktop
|
// and remove last desktop
|
||||||
VirtualDesktopManager::self()->setCount(1);
|
VirtualDesktopManager::self()->setCount(1);
|
||||||
QCOMPARE(VirtualDesktopManager::self()->count(), 1u);
|
QCOMPARE(VirtualDesktopManager::self()->count(), 1u);
|
||||||
// now the client should be moved as well
|
// now the client should be moved as well
|
||||||
QTRY_COMPARE(desktopPresenceChangedSpy.count(), 1);
|
QTRY_COMPARE(desktopPresenceChangedSpy.count(), 1);
|
||||||
QCOMPARE(client->desktop(), 1);
|
QCOMPARE(client->desktop(), 1);
|
||||||
|
|
||||||
|
QCOMPARE(client->desktops().count(), 1u);
|
||||||
|
QCOMPARE(VirtualDesktopManager::self()->currentDesktop(), client->desktops().first());
|
||||||
|
}
|
||||||
|
|
||||||
|
void VirtualDesktopTest::testWindowOnMultipleDesktops_data()
|
||||||
|
{
|
||||||
|
QTest::addColumn<Test::ShellSurfaceType>("type");
|
||||||
|
|
||||||
|
QTest::newRow("wlShell") << Test::ShellSurfaceType::WlShell;
|
||||||
|
QTest::newRow("xdgShellV5") << Test::ShellSurfaceType::XdgShellV5;
|
||||||
|
QTest::newRow("xdgShellV6") << Test::ShellSurfaceType::XdgShellV6;
|
||||||
|
}
|
||||||
|
|
||||||
|
void VirtualDesktopTest::testWindowOnMultipleDesktops()
|
||||||
|
{
|
||||||
|
// first create two new desktops
|
||||||
|
QCOMPARE(VirtualDesktopManager::self()->count(), 1u);
|
||||||
|
VirtualDesktopManager::self()->setCount(3);
|
||||||
|
QCOMPARE(VirtualDesktopManager::self()->count(), 3u);
|
||||||
|
|
||||||
|
// switch to last desktop
|
||||||
|
VirtualDesktopManager::self()->setCurrent(VirtualDesktopManager::self()->desktops().last());
|
||||||
|
QCOMPARE(VirtualDesktopManager::self()->current(), 3u);
|
||||||
|
|
||||||
|
// now create a window on this desktop
|
||||||
|
QScopedPointer<Surface> surface(Test::createSurface());
|
||||||
|
QFETCH(Test::ShellSurfaceType, type);
|
||||||
|
QScopedPointer<QObject> shellSurface(Test::createShellSurface(type, surface.data()));
|
||||||
|
auto client = Test::renderAndWaitForShown(surface.data(), QSize(100, 50), Qt::blue);
|
||||||
|
|
||||||
|
QVERIFY(client);
|
||||||
|
QCOMPARE(client->desktop(), 3u);
|
||||||
|
QSignalSpy desktopPresenceChangedSpy(client, &ShellClient::desktopPresenceChanged);
|
||||||
|
QVERIFY(desktopPresenceChangedSpy.isValid());
|
||||||
|
|
||||||
|
QCOMPARE(client->desktops().count(), 1u);
|
||||||
|
QCOMPARE(VirtualDesktopManager::self()->currentDesktop(), client->desktops().first());
|
||||||
|
|
||||||
|
//Set the window on desktop 2 as well
|
||||||
|
client->setDesktop(2u);
|
||||||
|
QCOMPARE(client->desktops().count(), 2u);
|
||||||
|
QCOMPARE(VirtualDesktopManager::self()->desktops()[2], client->desktops()[0]);
|
||||||
|
QCOMPARE(VirtualDesktopManager::self()->desktops()[1], client->desktops()[1]);
|
||||||
|
QVERIFY(client->isOnDesktop(2));
|
||||||
|
QVERIFY(client->isOnDesktop(3));
|
||||||
|
|
||||||
|
//leave desktop 3
|
||||||
|
client->unSetDesktop(3);
|
||||||
|
QCOMPARE(client->desktops().count(), 1u);
|
||||||
|
//leave desktop 2
|
||||||
|
client->unSetDesktop(2);
|
||||||
|
QCOMPARE(client->desktops().count(), 0u);
|
||||||
|
//we should be on all desktops now
|
||||||
|
QVERIFY(client->isOnAllDesktops());
|
||||||
|
//put on desktop 1
|
||||||
|
client->setDesktop(1);
|
||||||
|
QVERIFY(client->isOnDesktop(1));
|
||||||
|
QVERIFY(!client->isOnDesktop(2));
|
||||||
|
QVERIFY(!client->isOnDesktop(3));
|
||||||
|
QCOMPARE(client->desktops().count(), 1u);
|
||||||
|
//put on desktop 2
|
||||||
|
client->setDesktop(2);
|
||||||
|
QVERIFY(client->isOnDesktop(1));
|
||||||
|
QVERIFY(client->isOnDesktop(2));
|
||||||
|
QVERIFY(!client->isOnDesktop(3));
|
||||||
|
QCOMPARE(client->desktops().count(), 2u);
|
||||||
|
//put on desktop 3
|
||||||
|
client->setDesktop(3);
|
||||||
|
QVERIFY(client->isOnDesktop(1));
|
||||||
|
QVERIFY(client->isOnDesktop(2));
|
||||||
|
QVERIFY(client->isOnDesktop(3));
|
||||||
|
QVERIFY(client->isOnAllDesktops());
|
||||||
|
//when it gets on all desktops, it loses all desktops()
|
||||||
|
QCOMPARE(client->desktops().count(), 0u);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VirtualDesktopTest::testRemoveDesktopWithWindow_data()
|
||||||
|
{
|
||||||
|
QTest::addColumn<Test::ShellSurfaceType>("type");
|
||||||
|
|
||||||
|
QTest::newRow("wlShell") << Test::ShellSurfaceType::WlShell;
|
||||||
|
QTest::newRow("xdgShellV5") << Test::ShellSurfaceType::XdgShellV5;
|
||||||
|
QTest::newRow("xdgShellV6") << Test::ShellSurfaceType::XdgShellV6;
|
||||||
|
}
|
||||||
|
|
||||||
|
void VirtualDesktopTest::testRemoveDesktopWithWindow()
|
||||||
|
{
|
||||||
|
// first create two new desktops
|
||||||
|
QCOMPARE(VirtualDesktopManager::self()->count(), 1u);
|
||||||
|
VirtualDesktopManager::self()->setCount(3);
|
||||||
|
QCOMPARE(VirtualDesktopManager::self()->count(), 3u);
|
||||||
|
|
||||||
|
// switch to last desktop
|
||||||
|
VirtualDesktopManager::self()->setCurrent(VirtualDesktopManager::self()->desktops().last());
|
||||||
|
QCOMPARE(VirtualDesktopManager::self()->current(), 3u);
|
||||||
|
|
||||||
|
// now create a window on this desktop
|
||||||
|
QScopedPointer<Surface> surface(Test::createSurface());
|
||||||
|
QFETCH(Test::ShellSurfaceType, type);
|
||||||
|
QScopedPointer<QObject> shellSurface(Test::createShellSurface(type, surface.data()));
|
||||||
|
auto client = Test::renderAndWaitForShown(surface.data(), QSize(100, 50), Qt::blue);
|
||||||
|
|
||||||
|
QVERIFY(client);
|
||||||
|
QCOMPARE(client->desktop(), 3u);
|
||||||
|
QSignalSpy desktopPresenceChangedSpy(client, &ShellClient::desktopPresenceChanged);
|
||||||
|
QVERIFY(desktopPresenceChangedSpy.isValid());
|
||||||
|
|
||||||
|
QCOMPARE(client->desktops().count(), 1u);
|
||||||
|
QCOMPARE(VirtualDesktopManager::self()->currentDesktop(), client->desktops().first());
|
||||||
|
|
||||||
|
//Set the window on desktop 2 as well
|
||||||
|
client->setDesktop(2u);
|
||||||
|
QCOMPARE(client->desktops().count(), 2u);
|
||||||
|
QCOMPARE(VirtualDesktopManager::self()->desktops()[2], client->desktops()[0]);
|
||||||
|
QCOMPARE(VirtualDesktopManager::self()->desktops()[1], client->desktops()[1]);
|
||||||
|
QVERIFY(client->isOnDesktop(2));
|
||||||
|
QVERIFY(client->isOnDesktop(3));
|
||||||
|
|
||||||
|
//remove desktop 3
|
||||||
|
VirtualDesktopManager::self()->setCount(2);
|
||||||
|
QCOMPARE(client->desktops().count(), 1u);
|
||||||
|
//window is only on desktop 2
|
||||||
|
QCOMPARE(VirtualDesktopManager::self()->desktops()[1], client->desktops()[0]);
|
||||||
|
|
||||||
|
//Again 3 desktops
|
||||||
|
VirtualDesktopManager::self()->setCount(3);
|
||||||
|
//move window to be only on desktop 3
|
||||||
|
client->setDesktop(3);
|
||||||
|
client->unSetDesktop(2);
|
||||||
|
QCOMPARE(client->desktops().count(), 1u);
|
||||||
|
//window is only on desktop 3
|
||||||
|
QCOMPARE(VirtualDesktopManager::self()->desktops()[2], client->desktops()[0]);
|
||||||
|
|
||||||
|
//remove desktop 3
|
||||||
|
VirtualDesktopManager::self()->setCount(2);
|
||||||
|
QCOMPARE(client->desktops().count(), 1u);
|
||||||
|
//window is only on desktop 2
|
||||||
|
QCOMPARE(VirtualDesktopManager::self()->desktops()[1], client->desktops()[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
WAYLANDTEST_MAIN(VirtualDesktopTest)
|
WAYLANDTEST_MAIN(VirtualDesktopTest)
|
||||||
|
|
|
@ -132,7 +132,9 @@ void TestVirtualDesktops::count()
|
||||||
vds->setCount(s_countInitValue);
|
vds->setCount(s_countInitValue);
|
||||||
|
|
||||||
QSignalSpy spy(vds, SIGNAL(countChanged(uint,uint)));
|
QSignalSpy spy(vds, SIGNAL(countChanged(uint,uint)));
|
||||||
QSignalSpy desktopsRemoved(vds, SIGNAL(desktopsRemoved(uint)));
|
QSignalSpy desktopsRemoved(vds, SIGNAL(desktopRemoved(KWin::VirtualDesktop *)));
|
||||||
|
|
||||||
|
auto vdToRemove = vds->desktops().last();
|
||||||
|
|
||||||
QFETCH(uint, request);
|
QFETCH(uint, request);
|
||||||
QFETCH(uint, result);
|
QFETCH(uint, result);
|
||||||
|
@ -153,8 +155,7 @@ void TestVirtualDesktops::count()
|
||||||
if (!desktopsRemoved.isEmpty()) {
|
if (!desktopsRemoved.isEmpty()) {
|
||||||
QList<QVariant> arguments = desktopsRemoved.takeFirst();
|
QList<QVariant> arguments = desktopsRemoved.takeFirst();
|
||||||
QCOMPARE(arguments.count(), 1);
|
QCOMPARE(arguments.count(), 1);
|
||||||
QCOMPARE(arguments.at(0).type(), QVariant::UInt);
|
QCOMPARE(arguments.at(0).value<KWin::VirtualDesktop*>(), vdToRemove);
|
||||||
QCOMPARE(arguments.at(0).toUInt(), s_countInitValue);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*********************************************************************/
|
*********************************************************************/
|
||||||
|
|
||||||
#include <kwineffects.h>
|
#include <kwineffects.h>
|
||||||
|
#include "../virtualdesktops.h"
|
||||||
|
|
||||||
#include <QVector2D>
|
#include <QVector2D>
|
||||||
#include <QGraphicsRotation>
|
#include <QGraphicsRotation>
|
||||||
|
@ -72,6 +73,7 @@ public:
|
||||||
virtual void setData(int role, const QVariant &data);
|
virtual void setData(int role, const QVariant &data);
|
||||||
virtual void referencePreviousWindowPixmap() {}
|
virtual void referencePreviousWindowPixmap() {}
|
||||||
virtual void unreferencePreviousWindowPixmap() {}
|
virtual void unreferencePreviousWindowPixmap() {}
|
||||||
|
QList<int> desktops() const { return {};}
|
||||||
};
|
};
|
||||||
|
|
||||||
MockEffectWindow::MockEffectWindow(QObject *parent)
|
MockEffectWindow::MockEffectWindow(QObject *parent)
|
||||||
|
|
|
@ -21,6 +21,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
// own
|
// own
|
||||||
#include "dbusinterface.h"
|
#include "dbusinterface.h"
|
||||||
#include "compositingadaptor.h"
|
#include "compositingadaptor.h"
|
||||||
|
#include "virtualdesktopmanageradaptor.h"
|
||||||
|
|
||||||
// kwin
|
// kwin
|
||||||
#include "abstract_client.h"
|
#include "abstract_client.h"
|
||||||
|
@ -315,4 +316,180 @@ QStringList CompositorDBusInterface::supportedOpenGLPlatformInterfaces() const
|
||||||
return interfaces;
|
return interfaces;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
VirtualDesktopManagerDBusInterface::VirtualDesktopManagerDBusInterface(VirtualDesktopManager *parent)
|
||||||
|
: QObject(parent)
|
||||||
|
, m_manager(parent)
|
||||||
|
{
|
||||||
|
qDBusRegisterMetaType<KWin::DBusDesktopDataStruct>();
|
||||||
|
qDBusRegisterMetaType<KWin::DBusDesktopDataVector>();
|
||||||
|
|
||||||
|
new VirtualDesktopManagerAdaptor(this);
|
||||||
|
QDBusConnection::sessionBus().registerObject(QStringLiteral("/VirtualDesktopManager"),
|
||||||
|
QStringLiteral("org.kde.KWin.VirtualDesktopManager"),
|
||||||
|
this
|
||||||
|
);
|
||||||
|
|
||||||
|
connect(m_manager, &VirtualDesktopManager::currentChanged, this,
|
||||||
|
[this](uint previousDesktop, uint newDesktop) {
|
||||||
|
Q_UNUSED(previousDesktop);
|
||||||
|
Q_UNUSED(newDesktop);
|
||||||
|
emit currentChanged(m_manager->currentDesktop()->id());
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
connect(m_manager, &VirtualDesktopManager::countChanged, this,
|
||||||
|
[this](uint previousCount, uint newCount) {
|
||||||
|
Q_UNUSED(previousCount);
|
||||||
|
emit countChanged(newCount);
|
||||||
|
emit desktopsChanged(desktops());
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
connect(m_manager, &VirtualDesktopManager::navigationWrappingAroundChanged, this,
|
||||||
|
[this]() {
|
||||||
|
emit navigationWrappingAroundChanged(isNavigationWrappingAround());
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
connect(m_manager, &VirtualDesktopManager::rowsChanged, this, &VirtualDesktopManagerDBusInterface::rowsChanged);
|
||||||
|
|
||||||
|
for (auto *vd : m_manager->desktops()) {
|
||||||
|
connect(vd, &VirtualDesktop::x11DesktopNumberChanged, this,
|
||||||
|
[this, vd]() {
|
||||||
|
DBusDesktopDataStruct data{.position = vd->x11DesktopNumber() - 1, .id = vd->id(), .name = vd->name()};
|
||||||
|
emit desktopDataChanged(vd->id(), data);
|
||||||
|
emit desktopsChanged(desktops());
|
||||||
|
}
|
||||||
|
);
|
||||||
|
connect(vd, &VirtualDesktop::nameChanged, this,
|
||||||
|
[this, vd]() {
|
||||||
|
DBusDesktopDataStruct data{.position = vd->x11DesktopNumber() - 1, .id = vd->id(), .name = vd->name()};
|
||||||
|
emit desktopDataChanged(vd->id(), data);
|
||||||
|
emit desktopsChanged(desktops());
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
connect(m_manager, &VirtualDesktopManager::desktopCreated, this,
|
||||||
|
[this](VirtualDesktop *vd) {
|
||||||
|
connect(vd, &VirtualDesktop::x11DesktopNumberChanged, this,
|
||||||
|
[this, vd]() {
|
||||||
|
DBusDesktopDataStruct data{.position = vd->x11DesktopNumber() - 1, .id = vd->id(), .name = vd->name()};
|
||||||
|
emit desktopDataChanged(vd->id(), data);
|
||||||
|
emit desktopsChanged(desktops());
|
||||||
|
}
|
||||||
|
);
|
||||||
|
connect(vd, &VirtualDesktop::nameChanged, this,
|
||||||
|
[this, vd]() {
|
||||||
|
DBusDesktopDataStruct data{.position = vd->x11DesktopNumber() - 1, .id = vd->id(), .name = vd->name()};
|
||||||
|
emit desktopDataChanged(vd->id(), data);
|
||||||
|
emit desktopsChanged(desktops());
|
||||||
|
}
|
||||||
|
);
|
||||||
|
DBusDesktopDataStruct data{.position = vd->x11DesktopNumber() - 1, .id = vd->id(), .name = vd->name()};
|
||||||
|
emit desktopCreated(vd->id(), data);
|
||||||
|
emit desktopsChanged(desktops());
|
||||||
|
}
|
||||||
|
);
|
||||||
|
connect(m_manager, &VirtualDesktopManager::desktopRemoved, this,
|
||||||
|
[this](VirtualDesktop *vd) {
|
||||||
|
emit desktopRemoved(vd->id());
|
||||||
|
emit desktopsChanged(desktops());
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint VirtualDesktopManagerDBusInterface::count() const
|
||||||
|
{
|
||||||
|
return m_manager->count();
|
||||||
|
}
|
||||||
|
|
||||||
|
void VirtualDesktopManagerDBusInterface::setRows(uint rows)
|
||||||
|
{
|
||||||
|
if (static_cast<uint>(m_manager->grid().height()) == rows) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_manager->setRows(rows);
|
||||||
|
m_manager->save();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint VirtualDesktopManagerDBusInterface::rows() const
|
||||||
|
{
|
||||||
|
return m_manager->rows();
|
||||||
|
}
|
||||||
|
|
||||||
|
void VirtualDesktopManagerDBusInterface::setCurrent(const QString &id)
|
||||||
|
{
|
||||||
|
if (m_manager->currentDesktop()->id() == id) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto *vd = m_manager->desktopForId(id.toUtf8());
|
||||||
|
if (vd) {
|
||||||
|
m_manager->setCurrent(vd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QString VirtualDesktopManagerDBusInterface::current() const
|
||||||
|
{
|
||||||
|
return m_manager->currentDesktop()->id();
|
||||||
|
}
|
||||||
|
|
||||||
|
void VirtualDesktopManagerDBusInterface::setNavigationWrappingAround(bool wraps)
|
||||||
|
{
|
||||||
|
if (m_manager->isNavigationWrappingAround() == wraps) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_manager->setNavigationWrappingAround(wraps);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool VirtualDesktopManagerDBusInterface::isNavigationWrappingAround() const
|
||||||
|
{
|
||||||
|
return m_manager->isNavigationWrappingAround();
|
||||||
|
}
|
||||||
|
|
||||||
|
DBusDesktopDataVector VirtualDesktopManagerDBusInterface::desktops() const
|
||||||
|
{
|
||||||
|
const auto desks = m_manager->desktops();
|
||||||
|
DBusDesktopDataVector desktopVect;
|
||||||
|
desktopVect.reserve(m_manager->count());
|
||||||
|
|
||||||
|
std::transform(desks.constBegin(), desks.constEnd(),
|
||||||
|
std::back_inserter(desktopVect),
|
||||||
|
[] (const VirtualDesktop *vd) {
|
||||||
|
return DBusDesktopDataStruct{.position = vd->x11DesktopNumber() - 1, .id = vd->id(), .name = vd->name()};
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
return desktopVect;
|
||||||
|
}
|
||||||
|
|
||||||
|
void VirtualDesktopManagerDBusInterface::createDesktop(uint position, const QString &name)
|
||||||
|
{
|
||||||
|
m_manager->createVirtualDesktop(position + 1, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VirtualDesktopManagerDBusInterface::setDesktopName(const QString &id, const QString &name)
|
||||||
|
{
|
||||||
|
VirtualDesktop *vd = m_manager->desktopForId(id.toUtf8());
|
||||||
|
if (!vd) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (vd->name() == name) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
vd->setName(name);
|
||||||
|
m_manager->save();
|
||||||
|
}
|
||||||
|
|
||||||
|
void VirtualDesktopManagerDBusInterface::removeDesktop(const QString &id)
|
||||||
|
{
|
||||||
|
m_manager->removeVirtualDesktop(id.toUtf8());
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
|
@ -24,10 +24,13 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QtDBus>
|
#include <QtDBus>
|
||||||
|
|
||||||
|
#include "virtualdesktopsdbustypes.h"
|
||||||
|
|
||||||
namespace KWin
|
namespace KWin
|
||||||
{
|
{
|
||||||
|
|
||||||
class Compositor;
|
class Compositor;
|
||||||
|
class VirtualDesktopManager;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief This class is a wrapper for the org.kde.KWin D-Bus interface.
|
* @brief This class is a wrapper for the org.kde.KWin D-Bus interface.
|
||||||
|
@ -169,6 +172,76 @@ private:
|
||||||
Compositor *m_compositor;
|
Compositor *m_compositor;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//TODO: disable all of this in case of kiosk?
|
||||||
|
|
||||||
|
class VirtualDesktopManagerDBusInterface : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
Q_CLASSINFO("D-Bus Interface", "org.kde.KWin.VirtualDesktopManager")
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 NOTIFY countChanged)
|
||||||
|
/**
|
||||||
|
* The number of rows the virtual desktops will be laid out in
|
||||||
|
**/
|
||||||
|
Q_PROPERTY(uint rows READ rows WRITE setRows NOTIFY rowsChanged)
|
||||||
|
/**
|
||||||
|
* The id of the virtual desktop which is currently in use.
|
||||||
|
**/
|
||||||
|
Q_PROPERTY(QString 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)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* list of key/value pairs which every one of them is representing a desktop
|
||||||
|
*/
|
||||||
|
Q_PROPERTY(KWin::DBusDesktopDataVector desktops READ desktops NOTIFY desktopsChanged);
|
||||||
|
|
||||||
|
public:
|
||||||
|
VirtualDesktopManagerDBusInterface(VirtualDesktopManager *parent);
|
||||||
|
~VirtualDesktopManagerDBusInterface() = default;
|
||||||
|
|
||||||
|
uint count() const;
|
||||||
|
|
||||||
|
void setRows(uint rows);
|
||||||
|
uint rows() const;
|
||||||
|
|
||||||
|
void setCurrent(const QString &id);
|
||||||
|
QString current() const;
|
||||||
|
|
||||||
|
void setNavigationWrappingAround(bool wraps);
|
||||||
|
bool isNavigationWrappingAround() const;
|
||||||
|
|
||||||
|
KWin::DBusDesktopDataVector desktops() const;
|
||||||
|
|
||||||
|
Q_SIGNALS:
|
||||||
|
void countChanged(uint count);
|
||||||
|
void rowsChanged(uint rows);
|
||||||
|
void currentChanged(const QString &id);
|
||||||
|
void navigationWrappingAroundChanged(bool wraps);
|
||||||
|
void desktopsChanged(KWin::DBusDesktopDataVector);
|
||||||
|
void desktopDataChanged(const QString &id, KWin::DBusDesktopDataStruct);
|
||||||
|
void desktopCreated(const QString &id, KWin::DBusDesktopDataStruct);
|
||||||
|
void desktopRemoved(const QString &id);
|
||||||
|
|
||||||
|
public Q_SLOTS:
|
||||||
|
/**
|
||||||
|
* Create a desktop with a new name at a given position
|
||||||
|
* note: the position starts from 1
|
||||||
|
*/
|
||||||
|
void createDesktop(uint position, const QString &name);
|
||||||
|
void setDesktopName(const QString &id, const QString &name);
|
||||||
|
void removeDesktop(const QString &id);
|
||||||
|
|
||||||
|
private:
|
||||||
|
VirtualDesktopManager *m_manager;
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
#endif // KWIN_DBUS_INTERFACE_H
|
#endif // KWIN_DBUS_INTERFACE_H
|
||||||
|
|
|
@ -94,6 +94,7 @@ void Deleted::copyToDeleted(Toplevel* c)
|
||||||
assert(dynamic_cast< Deleted* >(c) == NULL);
|
assert(dynamic_cast< Deleted* >(c) == NULL);
|
||||||
Toplevel::copyToDeleted(c);
|
Toplevel::copyToDeleted(c);
|
||||||
desk = c->desktop();
|
desk = c->desktop();
|
||||||
|
m_desktops = c->desktops();
|
||||||
activityList = c->activities();
|
activityList = c->activities();
|
||||||
contentsRect = QRect(c->clientPos(), c->clientSize());
|
contentsRect = QRect(c->clientPos(), c->clientSize());
|
||||||
m_contentPos = c->clientContentPos();
|
m_contentPos = c->clientContentPos();
|
||||||
|
@ -177,6 +178,11 @@ QStringList Deleted::activities() const
|
||||||
return activityList;
|
return activityList;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QList<VirtualDesktop *> Deleted::desktops() const
|
||||||
|
{
|
||||||
|
return m_desktops;
|
||||||
|
}
|
||||||
|
|
||||||
QPoint Deleted::clientPos() const
|
QPoint Deleted::clientPos() const
|
||||||
{
|
{
|
||||||
return contentsRect.topLeft();
|
return contentsRect.topLeft();
|
||||||
|
|
|
@ -52,6 +52,7 @@ public:
|
||||||
void discard();
|
void discard();
|
||||||
virtual int desktop() const;
|
virtual int desktop() const;
|
||||||
virtual QStringList activities() const;
|
virtual QStringList activities() const;
|
||||||
|
virtual QList<VirtualDesktop *> desktops() const;
|
||||||
virtual QPoint clientPos() const;
|
virtual QPoint clientPos() const;
|
||||||
virtual QSize clientSize() const;
|
virtual QSize clientSize() const;
|
||||||
QPoint clientContentPos() const override {
|
QPoint clientContentPos() const override {
|
||||||
|
@ -195,6 +196,7 @@ private:
|
||||||
QPoint m_contentPos;
|
QPoint m_contentPos;
|
||||||
QRect transparent_rect;
|
QRect transparent_rect;
|
||||||
xcb_window_t m_frame;
|
xcb_window_t m_frame;
|
||||||
|
QList <VirtualDesktop *> m_desktops;
|
||||||
|
|
||||||
bool no_border;
|
bool no_border;
|
||||||
QRect decoration_left;
|
QRect decoration_left;
|
||||||
|
|
|
@ -911,8 +911,9 @@ void EffectsHandlerImpl::moveWindow(EffectWindow* w, const QPoint& pos, bool sna
|
||||||
void EffectsHandlerImpl::windowToDesktop(EffectWindow* w, int desktop)
|
void EffectsHandlerImpl::windowToDesktop(EffectWindow* w, int desktop)
|
||||||
{
|
{
|
||||||
AbstractClient* cl = dynamic_cast< AbstractClient* >(static_cast<EffectWindowImpl*>(w)->window());
|
AbstractClient* cl = dynamic_cast< AbstractClient* >(static_cast<EffectWindowImpl*>(w)->window());
|
||||||
if (cl && !cl->isDesktop() && !cl->isDock())
|
if (cl && !cl->isDesktop() && !cl->isDock()) {
|
||||||
Workspace::self()->sendClientToDesktop(cl, desktop, true);
|
Workspace::self()->sendClientToDesktop(cl, desktop, true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void EffectsHandlerImpl::windowToScreen(EffectWindow* w, int screen)
|
void EffectsHandlerImpl::windowToScreen(EffectWindow* w, int screen)
|
||||||
|
|
|
@ -42,6 +42,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
#include <QQmlEngine>
|
#include <QQmlEngine>
|
||||||
#include <QQuickItem>
|
#include <QQuickItem>
|
||||||
|
|
||||||
|
#include <KWayland/Server/surface_interface.h>
|
||||||
|
|
||||||
namespace KWin
|
namespace KWin
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -52,6 +54,7 @@ DesktopGridEffect::DesktopGridEffect()
|
||||||
, timeline()
|
, timeline()
|
||||||
, keyboardGrab(false)
|
, keyboardGrab(false)
|
||||||
, wasWindowMove(false)
|
, wasWindowMove(false)
|
||||||
|
, wasWindowCopy(false)
|
||||||
, wasDesktopMove(false)
|
, wasDesktopMove(false)
|
||||||
, isValidMove(false)
|
, isValidMove(false)
|
||||||
, windowMove(NULL)
|
, windowMove(NULL)
|
||||||
|
@ -297,7 +300,9 @@ void DesktopGridEffect::prePaintWindow(EffectWindow* w, WindowPrePaintData& data
|
||||||
void DesktopGridEffect::paintWindow(EffectWindow* w, int mask, QRegion region, WindowPaintData& data)
|
void DesktopGridEffect::paintWindow(EffectWindow* w, int mask, QRegion region, WindowPaintData& data)
|
||||||
{
|
{
|
||||||
if (timeline.currentValue() != 0 || (isUsingPresentWindows() && isMotionManagerMovingWindows())) {
|
if (timeline.currentValue() != 0 || (isUsingPresentWindows() && isMotionManagerMovingWindows())) {
|
||||||
if (isUsingPresentWindows() && w == windowMove && wasWindowMove) {
|
if (isUsingPresentWindows() && w == windowMove && wasWindowMove &&
|
||||||
|
((!wasWindowCopy && sourceDesktop == paintingDesktop) ||
|
||||||
|
(sourceDesktop != highlightedDesktop && highlightedDesktop == paintingDesktop))) {
|
||||||
return; // will be painted on top of all other windows
|
return; // will be painted on top of all other windows
|
||||||
}
|
}
|
||||||
foreach (DesktopButtonsView *view, m_desktopButtonsViews) {
|
foreach (DesktopButtonsView *view, m_desktopButtonsViews) {
|
||||||
|
@ -487,7 +492,6 @@ void DesktopGridEffect::windowInputMouseEvent(QEvent* e)
|
||||||
if (!wasWindowMove) { // Activate on move
|
if (!wasWindowMove) { // Activate on move
|
||||||
if (isUsingPresentWindows()) {
|
if (isUsingPresentWindows()) {
|
||||||
foreach (const int i, desktopList(windowMove)) {
|
foreach (const int i, desktopList(windowMove)) {
|
||||||
const int sourceDesktop = windowMove->isOnAllDesktops() ? d : windowMove->desktop();
|
|
||||||
WindowMotionManager& manager = m_managers[(i)*(effects->numScreens()) + windowMove->screen()];
|
WindowMotionManager& manager = m_managers[(i)*(effects->numScreens()) + windowMove->screen()];
|
||||||
if ((i + 1) == sourceDesktop) {
|
if ((i + 1) == sourceDesktop) {
|
||||||
const QRectF transformedGeo = manager.transformedGeometry(windowMove);
|
const QRectF transformedGeo = manager.transformedGeometry(windowMove);
|
||||||
|
@ -513,9 +517,18 @@ void DesktopGridEffect::windowInputMouseEvent(QEvent* e)
|
||||||
effects->moveWindow(windowMove, unscalePos(me->pos(), NULL) + windowMoveDiff, true, 1.0 / scale[screen]);
|
effects->moveWindow(windowMove, unscalePos(me->pos(), NULL) + windowMoveDiff, true, 1.0 / scale[screen]);
|
||||||
}
|
}
|
||||||
if (wasWindowMove) {
|
if (wasWindowMove) {
|
||||||
effects->defineCursor(Qt::ClosedHandCursor);
|
if (!effects->waylandDisplay() || (me->modifiers() & Qt::ControlModifier)) {
|
||||||
|
wasWindowCopy = true;
|
||||||
|
effects->defineCursor(Qt::DragCopyCursor);
|
||||||
|
} else {
|
||||||
|
wasWindowCopy = false;
|
||||||
|
effects->defineCursor(Qt::ClosedHandCursor);
|
||||||
|
}
|
||||||
if (d != highlightedDesktop) {
|
if (d != highlightedDesktop) {
|
||||||
effects->windowToDesktop(windowMove, d); // Not true all desktop move
|
effects->windowToDesktop(windowMove, d); // Not true all desktop move
|
||||||
|
if (highlightedDesktop != sourceDesktop || !wasWindowCopy) {
|
||||||
|
effects->removeWindowFromDesktop(windowMove, highlightedDesktop);
|
||||||
|
}
|
||||||
const int screen = effects->screenNumber(me->pos());
|
const int screen = effects->screenNumber(me->pos());
|
||||||
if (screen != windowMove->screen())
|
if (screen != windowMove->screen())
|
||||||
effects->windowToScreen(windowMove, screen);
|
effects->windowToScreen(windowMove, screen);
|
||||||
|
@ -549,6 +562,8 @@ void DesktopGridEffect::windowInputMouseEvent(QEvent* e)
|
||||||
continue;
|
continue;
|
||||||
foreach (EffectWindow *w, stack[i]) {
|
foreach (EffectWindow *w, stack[i]) {
|
||||||
effects->windowToDesktop(w, desks[i+1]);
|
effects->windowToDesktop(w, desks[i+1]);
|
||||||
|
effects->removeWindowFromDesktop(w, desks[i]);
|
||||||
|
|
||||||
if (isUsingPresentWindows()) {
|
if (isUsingPresentWindows()) {
|
||||||
m_managers[(desks[i]-1)*(effects->numScreens()) + w->screen()].unmanage(w);
|
m_managers[(desks[i]-1)*(effects->numScreens()) + w->screen()].unmanage(w);
|
||||||
m_managers[(desks[i+1]-1)*(effects->numScreens()) + w->screen()].manage(w);
|
m_managers[(desks[i+1]-1)*(effects->numScreens()) + w->screen()].manage(w);
|
||||||
|
@ -572,12 +587,15 @@ void DesktopGridEffect::windowInputMouseEvent(QEvent* e)
|
||||||
if (me->buttons() == Qt::LeftButton) {
|
if (me->buttons() == Qt::LeftButton) {
|
||||||
isValidMove = true;
|
isValidMove = true;
|
||||||
dragStartPos = me->pos();
|
dragStartPos = me->pos();
|
||||||
bool isDesktop = (me->modifiers() & Qt::ControlModifier);
|
sourceDesktop = posToDesktop(me->pos());
|
||||||
|
bool isDesktop = (me->modifiers() & Qt::ShiftModifier);
|
||||||
EffectWindow* w = isDesktop ? NULL : windowAt(me->pos());
|
EffectWindow* w = isDesktop ? NULL : windowAt(me->pos());
|
||||||
if (w != NULL)
|
if (w != NULL)
|
||||||
isDesktop = w->isDesktop();
|
isDesktop = w->isDesktop();
|
||||||
if (isDesktop)
|
if (isDesktop)
|
||||||
m_originalMovingDesktop = posToDesktop(me->pos());
|
m_originalMovingDesktop = posToDesktop(me->pos());
|
||||||
|
else
|
||||||
|
m_originalMovingDesktop = 0;
|
||||||
if (w != NULL && !w->isDesktop() && (w->isMovable() || w->isMovableAcrossScreens() || isUsingPresentWindows())) {
|
if (w != NULL && !w->isDesktop() && (w->isMovable() || w->isMovableAcrossScreens() || isUsingPresentWindows())) {
|
||||||
// Prepare it for moving
|
// Prepare it for moving
|
||||||
windowMoveDiff = w->pos() - unscalePos(me->pos(), NULL);
|
windowMoveDiff = w->pos() - unscalePos(me->pos(), NULL);
|
||||||
|
@ -590,12 +608,10 @@ void DesktopGridEffect::windowInputMouseEvent(QEvent* e)
|
||||||
w = nullptr;
|
w = nullptr;
|
||||||
}
|
}
|
||||||
if (w != NULL) {
|
if (w != NULL) {
|
||||||
int desktop = 0;
|
const int desktop = posToDesktop(me->pos());
|
||||||
if (w->isOnAllDesktops()) {
|
if (w->isOnAllDesktops()) {
|
||||||
desktop = posToDesktop(me->pos());
|
|
||||||
effects->windowToDesktop(w, desktop);
|
effects->windowToDesktop(w, desktop);
|
||||||
} else {
|
} else {
|
||||||
desktop = w->desktop();
|
|
||||||
effects->windowToDesktop(w, NET::OnAllDesktops);
|
effects->windowToDesktop(w, NET::OnAllDesktops);
|
||||||
}
|
}
|
||||||
const bool isOnAllDesktops = w->isOnAllDesktops();
|
const bool isOnAllDesktops = w->isOnAllDesktops();
|
||||||
|
@ -630,7 +646,7 @@ void DesktopGridEffect::windowInputMouseEvent(QEvent* e)
|
||||||
}
|
}
|
||||||
if (windowMove) {
|
if (windowMove) {
|
||||||
if (wasWindowMove && isUsingPresentWindows()) {
|
if (wasWindowMove && isUsingPresentWindows()) {
|
||||||
const int targetDesktop = windowMove->isOnAllDesktops() ? posToDesktop(cursorPos()) : windowMove->desktop();
|
const int targetDesktop = posToDesktop(cursorPos());
|
||||||
foreach (const int i, desktopList(windowMove)) {
|
foreach (const int i, desktopList(windowMove)) {
|
||||||
WindowMotionManager& manager = m_managers[(i)*(effects->numScreens()) + windowMove->screen()];
|
WindowMotionManager& manager = m_managers[(i)*(effects->numScreens()) + windowMove->screen()];
|
||||||
manager.manage(windowMove);
|
manager.manage(windowMove);
|
||||||
|
@ -648,6 +664,7 @@ void DesktopGridEffect::windowInputMouseEvent(QEvent* e)
|
||||||
windowMove = NULL;
|
windowMove = NULL;
|
||||||
}
|
}
|
||||||
wasWindowMove = false;
|
wasWindowMove = false;
|
||||||
|
wasWindowCopy = false;
|
||||||
wasDesktopMove = false;
|
wasDesktopMove = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1360,7 +1377,7 @@ void DesktopGridEffect::desktopsRemoved(int old)
|
||||||
// and repaint
|
// and repaint
|
||||||
effects->addRepaintFull();
|
effects->addRepaintFull();
|
||||||
}
|
}
|
||||||
|
//TODO: kill this function? or at least keep a consistent numeration with desktops starting from 1
|
||||||
QVector<int> DesktopGridEffect::desktopList(const EffectWindow *w) const
|
QVector<int> DesktopGridEffect::desktopList(const EffectWindow *w) const
|
||||||
{
|
{
|
||||||
if (w->isOnAllDesktops()) {
|
if (w->isOnAllDesktops()) {
|
||||||
|
@ -1373,16 +1390,13 @@ QVector<int> DesktopGridEffect::desktopList(const EffectWindow *w) const
|
||||||
return allDesktops;
|
return allDesktops;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (w->desktop() > effects->numberOfDesktops() || w->desktop() < 1) { // sic! desktops are [1,n]
|
QVector<int> desks;
|
||||||
static QVector<int> emptyVector;
|
desks.resize(w->desktops().count());
|
||||||
emptyVector.resize(0);
|
int i = 0;
|
||||||
return emptyVector;
|
for (const int desk : w->desktops()) {
|
||||||
|
desks[i++] = desk-1;
|
||||||
}
|
}
|
||||||
|
return desks;
|
||||||
static QVector<int> singleDesktop;
|
|
||||||
singleDesktop.resize(1);
|
|
||||||
singleDesktop[0] = w->desktop() - 1;
|
|
||||||
return singleDesktop;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DesktopGridEffect::isActive() const
|
bool DesktopGridEffect::isActive() const
|
||||||
|
|
|
@ -151,9 +151,10 @@ private:
|
||||||
QTimeLine timeline;
|
QTimeLine timeline;
|
||||||
int paintingDesktop;
|
int paintingDesktop;
|
||||||
int highlightedDesktop;
|
int highlightedDesktop;
|
||||||
|
int sourceDesktop;
|
||||||
int m_originalMovingDesktop;
|
int m_originalMovingDesktop;
|
||||||
bool keyboardGrab;
|
bool keyboardGrab;
|
||||||
bool wasWindowMove, wasDesktopMove, isValidMove;
|
bool wasWindowMove, wasWindowCopy, wasDesktopMove, isValidMove;
|
||||||
EffectWindow* windowMove;
|
EffectWindow* windowMove;
|
||||||
QPoint windowMoveDiff;
|
QPoint windowMoveDiff;
|
||||||
QPoint dragStartPos;
|
QPoint dragStartPos;
|
||||||
|
|
|
@ -762,6 +762,13 @@ bool EffectsHandler::isOpenGLCompositing() const
|
||||||
return compositing_type & OpenGLCompositing;
|
return compositing_type & OpenGLCompositing;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void EffectsHandler::removeWindowFromDesktop(KWin::EffectWindow* w, int desktop)
|
||||||
|
{
|
||||||
|
if (w->parent() && !w->isDesktop() && !w->isDock()) {
|
||||||
|
QMetaObject::invokeMethod(w->parent(), "unSetDesktop", Q_ARG(int, desktop));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
EffectsHandler* effects = nullptr;
|
EffectsHandler* effects = nullptr;
|
||||||
|
|
||||||
|
|
||||||
|
@ -826,7 +833,9 @@ WINDOW_HELPER(int, screen, "screen")
|
||||||
WINDOW_HELPER(QRect, geometry, "geometry")
|
WINDOW_HELPER(QRect, geometry, "geometry")
|
||||||
WINDOW_HELPER(QRect, expandedGeometry, "visibleRect")
|
WINDOW_HELPER(QRect, expandedGeometry, "visibleRect")
|
||||||
WINDOW_HELPER(QRect, rect, "rect")
|
WINDOW_HELPER(QRect, rect, "rect")
|
||||||
|
#ifndef KWIN_NO_DEPRECATED
|
||||||
WINDOW_HELPER(int, desktop, "desktop")
|
WINDOW_HELPER(int, desktop, "desktop")
|
||||||
|
#endif
|
||||||
WINDOW_HELPER(bool, isDesktop, "desktopWindow")
|
WINDOW_HELPER(bool, isDesktop, "desktopWindow")
|
||||||
WINDOW_HELPER(bool, isDock, "dock")
|
WINDOW_HELPER(bool, isDock, "dock")
|
||||||
WINDOW_HELPER(bool, isToolbar, "toolbar")
|
WINDOW_HELPER(bool, isToolbar, "toolbar")
|
||||||
|
@ -849,6 +858,11 @@ WINDOW_HELPER(QStringList, activities, "activities")
|
||||||
WINDOW_HELPER(bool, skipsCloseAnimation, "skipsCloseAnimation")
|
WINDOW_HELPER(bool, skipsCloseAnimation, "skipsCloseAnimation")
|
||||||
WINDOW_HELPER(KWayland::Server::SurfaceInterface *, surface, "surface")
|
WINDOW_HELPER(KWayland::Server::SurfaceInterface *, surface, "surface")
|
||||||
|
|
||||||
|
QList<int> EffectWindow::desktops() const
|
||||||
|
{
|
||||||
|
return parent()->property("x11DesktopIds").value<QList<int> >();
|
||||||
|
}
|
||||||
|
|
||||||
QString EffectWindow::windowClass() const
|
QString EffectWindow::windowClass() const
|
||||||
{
|
{
|
||||||
return parent()->property("resourceName").toString() + QLatin1Char(' ') + parent()->property("resourceClass").toString();
|
return parent()->property("resourceName").toString() + QLatin1Char(' ') + parent()->property("resourceClass").toString();
|
||||||
|
@ -974,12 +988,13 @@ bool EffectWindow::isOnCurrentDesktop() const
|
||||||
|
|
||||||
bool EffectWindow::isOnDesktop(int d) const
|
bool EffectWindow::isOnDesktop(int d) const
|
||||||
{
|
{
|
||||||
return desktop() == d || isOnAllDesktops();
|
const QList<int> ds = desktops();
|
||||||
|
return ds.isEmpty() || ds.contains(d);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool EffectWindow::isOnAllDesktops() const
|
bool EffectWindow::isOnAllDesktops() const
|
||||||
{
|
{
|
||||||
return desktop() == NET::OnAllDesktops;
|
return desktops().isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool EffectWindow::hasDecoration() const
|
bool EffectWindow::hasDecoration() const
|
||||||
|
|
|
@ -944,6 +944,10 @@ public:
|
||||||
virtual KWin::EffectWindow* activeWindow() const = 0 ;
|
virtual KWin::EffectWindow* activeWindow() const = 0 ;
|
||||||
Q_SCRIPTABLE virtual void moveWindow(KWin::EffectWindow* w, const QPoint& pos, bool snap = false, double snapAdjust = 1.0) = 0;
|
Q_SCRIPTABLE virtual void moveWindow(KWin::EffectWindow* w, const QPoint& pos, bool snap = false, double snapAdjust = 1.0) = 0;
|
||||||
Q_SCRIPTABLE virtual void windowToDesktop(KWin::EffectWindow* w, int desktop) = 0;
|
Q_SCRIPTABLE virtual void windowToDesktop(KWin::EffectWindow* w, int desktop) = 0;
|
||||||
|
/**
|
||||||
|
* Removes a window from a desktop on wayland, no-op on X11
|
||||||
|
*/
|
||||||
|
Q_SCRIPTABLE void removeWindowFromDesktop(KWin::EffectWindow* w, int desktop);
|
||||||
Q_SCRIPTABLE virtual void windowToScreen(KWin::EffectWindow* w, int screen) = 0;
|
Q_SCRIPTABLE virtual void windowToScreen(KWin::EffectWindow* w, int screen) = 0;
|
||||||
virtual void setShowingDesktop(bool showing) = 0;
|
virtual void setShowingDesktop(bool showing) = 0;
|
||||||
|
|
||||||
|
@ -2071,7 +2075,23 @@ public:
|
||||||
Q_SCRIPTABLE bool isOnDesktop(int d) const;
|
Q_SCRIPTABLE bool isOnDesktop(int d) const;
|
||||||
bool isOnCurrentDesktop() const;
|
bool isOnCurrentDesktop() const;
|
||||||
bool isOnAllDesktops() const;
|
bool isOnAllDesktops() const;
|
||||||
int desktop() const; // prefer isOnXXX()
|
/**
|
||||||
|
* The desktop this window is in. This mkaes sense only on X11
|
||||||
|
* where desktops are mutually exclusive, on Wayland it's the last
|
||||||
|
* desktop the window has been added to.
|
||||||
|
* use desktops() instead.
|
||||||
|
* @see desktops()
|
||||||
|
* @deprecated
|
||||||
|
*/
|
||||||
|
#ifndef KWIN_NO_DEPRECATED
|
||||||
|
int KWIN_DEPRECATED desktop() const; // prefer isOnXXX()
|
||||||
|
#endif
|
||||||
|
/**
|
||||||
|
* All the desktops by number that the window is in. On X11 this list will always have
|
||||||
|
* a length of 1, on Wayland can be any subset.
|
||||||
|
* If the list is empty it means the window is on all desktops
|
||||||
|
*/
|
||||||
|
QList<int> desktops() const;
|
||||||
|
|
||||||
int x() const;
|
int x() const;
|
||||||
int y() const;
|
int y() const;
|
||||||
|
|
|
@ -0,0 +1,50 @@
|
||||||
|
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
|
||||||
|
<node>
|
||||||
|
<interface name="org.kde.KWin.VirtualDesktopManager">
|
||||||
|
<property name="count" type="u" access="read"/>
|
||||||
|
<property name="current" type="s" access="readwrite"/>
|
||||||
|
<property name="rows" type="u" access="readwrite"/>
|
||||||
|
<property name="navigationWrappingAround" type="b" access="readwrite"/>
|
||||||
|
<property name="desktops" type="a(iss)" access="read">
|
||||||
|
<annotation name="org.qtproject.QtDBus.QtTypeName" value="KWin::DBusDesktopDataVector"/>
|
||||||
|
</property>
|
||||||
|
|
||||||
|
<signal name="countChanged">
|
||||||
|
<arg name="count" type="u" direction="out"/>
|
||||||
|
</signal>
|
||||||
|
<signal name="rowsChanged">
|
||||||
|
<arg name="rows" type="u" direction="out"/>
|
||||||
|
</signal>
|
||||||
|
<signal name="currentChanged">
|
||||||
|
<arg name="id" type="s" direction="out"/>
|
||||||
|
</signal>
|
||||||
|
<signal name="navigationWrappingAroundChanged">
|
||||||
|
<arg name="navigationWrappingAround" type="b" direction="out"/>
|
||||||
|
</signal>
|
||||||
|
<signal name="desktopDataChanged">
|
||||||
|
<arg name="id" type="s" direction="out"/>
|
||||||
|
<annotation name="org.qtproject.QtDBus.QtTypeName.Out1" value="KWin::DBusDesktopDataStruct"/>
|
||||||
|
<arg name="desktopData" type="(iss)" direction="out"/>
|
||||||
|
</signal>
|
||||||
|
<signal name="desktopCreated">
|
||||||
|
<arg name="id" type="s" direction="out"/>
|
||||||
|
<annotation name="org.qtproject.QtDBus.QtTypeName.Out1" value="KWin::DBusDesktopDataStruct"/>
|
||||||
|
<arg name="desktopData" type="(iss)" direction="out"/>
|
||||||
|
</signal>
|
||||||
|
<signal name="desktopRemoved">
|
||||||
|
<arg name="id" type="s" direction="out"/>
|
||||||
|
</signal>
|
||||||
|
|
||||||
|
<method name="createDesktop">
|
||||||
|
<arg name="position" type="u" direction="in"/>
|
||||||
|
<arg name="name" type="s" direction="in"/>
|
||||||
|
</method>
|
||||||
|
<method name="setDesktopName">
|
||||||
|
<arg name="id" type="s" direction="in"/>
|
||||||
|
<arg name="name" type="s" direction="in"/>
|
||||||
|
</method>
|
||||||
|
<method name="removeDesktop">
|
||||||
|
<arg name="id" type="s" direction="in"/>
|
||||||
|
</method>
|
||||||
|
</interface>
|
||||||
|
</node>
|
14
toplevel.h
14
toplevel.h
|
@ -290,6 +290,7 @@ public:
|
||||||
* isOnDesktop() instead.
|
* isOnDesktop() instead.
|
||||||
*/
|
*/
|
||||||
virtual int desktop() const = 0;
|
virtual int desktop() const = 0;
|
||||||
|
virtual QList<VirtualDesktop *> desktops() const = 0;
|
||||||
virtual QStringList activities() const = 0;
|
virtual QStringList activities() const = 0;
|
||||||
bool isOnDesktop(int d) const;
|
bool isOnDesktop(int d) const;
|
||||||
bool isOnActivity(const QString &activity) const;
|
bool isOnActivity(const QString &activity) const;
|
||||||
|
@ -790,7 +791,12 @@ const EffectWindowImpl* Toplevel::effectWindow() const
|
||||||
|
|
||||||
inline bool Toplevel::isOnAllDesktops() const
|
inline bool Toplevel::isOnAllDesktops() const
|
||||||
{
|
{
|
||||||
return desktop() == NET::OnAllDesktops;
|
return kwinApp()->operationMode() == Application::OperationModeWaylandOnly ||
|
||||||
|
kwinApp()->operationMode() == Application::OperationModeXwayland
|
||||||
|
//Wayland
|
||||||
|
? desktops().isEmpty()
|
||||||
|
//X11
|
||||||
|
: desktop() == NET::OnAllDesktops;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool Toplevel::isOnAllActivities() const
|
inline bool Toplevel::isOnAllActivities() const
|
||||||
|
@ -800,7 +806,11 @@ inline bool Toplevel::isOnAllActivities() const
|
||||||
|
|
||||||
inline bool Toplevel::isOnDesktop(int d) const
|
inline bool Toplevel::isOnDesktop(int d) const
|
||||||
{
|
{
|
||||||
return desktop() == d || /*desk == 0 ||*/ isOnAllDesktops();
|
return (kwinApp()->operationMode() == Application::OperationModeWaylandOnly ||
|
||||||
|
kwinApp()->operationMode() == Application::OperationModeXwayland
|
||||||
|
? desktops().contains(VirtualDesktopManager::self()->desktopForX11Id(d))
|
||||||
|
: desktop() == d
|
||||||
|
) || isOnAllDesktops();
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool Toplevel::isOnActivity(const QString &activity) const
|
inline bool Toplevel::isOnActivity(const QString &activity) const
|
||||||
|
|
|
@ -123,6 +123,11 @@ QStringList Unmanaged::activities() const
|
||||||
return QStringList();
|
return QStringList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QList<VirtualDesktop *> Unmanaged::desktops() const
|
||||||
|
{
|
||||||
|
return QList<VirtualDesktop *>();
|
||||||
|
}
|
||||||
|
|
||||||
QPoint Unmanaged::clientPos() const
|
QPoint Unmanaged::clientPos() const
|
||||||
{
|
{
|
||||||
return QPoint(0, 0); // unmanaged windows don't have decorations
|
return QPoint(0, 0); // unmanaged windows don't have decorations
|
||||||
|
|
|
@ -39,6 +39,7 @@ public:
|
||||||
static void deleteUnmanaged(Unmanaged* c);
|
static void deleteUnmanaged(Unmanaged* c);
|
||||||
virtual int desktop() const;
|
virtual int desktop() const;
|
||||||
virtual QStringList activities() const;
|
virtual QStringList activities() const;
|
||||||
|
virtual QList<VirtualDesktop *> desktops() const override;
|
||||||
virtual QPoint clientPos() const;
|
virtual QPoint clientPos() const;
|
||||||
virtual QSize clientSize() const;
|
virtual QSize clientSize() const;
|
||||||
virtual QRect transparentRect() const;
|
virtual QRect transparentRect() const;
|
||||||
|
|
120
useractions.cpp
120
useractions.cpp
|
@ -402,6 +402,7 @@ void UserActionsMenu::discard()
|
||||||
delete m_menu;
|
delete m_menu;
|
||||||
m_menu = NULL;
|
m_menu = NULL;
|
||||||
m_desktopMenu = NULL;
|
m_desktopMenu = NULL;
|
||||||
|
m_multipleDesktopsMenu = nullptr;
|
||||||
m_screenMenu = NULL;
|
m_screenMenu = NULL;
|
||||||
m_activityMenu = NULL;
|
m_activityMenu = NULL;
|
||||||
m_switchToTabMenu = NULL;
|
m_switchToTabMenu = NULL;
|
||||||
|
@ -417,6 +418,8 @@ void UserActionsMenu::menuAboutToShow()
|
||||||
if (VirtualDesktopManager::self()->count() == 1) {
|
if (VirtualDesktopManager::self()->count() == 1) {
|
||||||
delete m_desktopMenu;
|
delete m_desktopMenu;
|
||||||
m_desktopMenu = 0;
|
m_desktopMenu = 0;
|
||||||
|
delete m_multipleDesktopsMenu;
|
||||||
|
m_multipleDesktopsMenu = nullptr;
|
||||||
} else {
|
} else {
|
||||||
initDesktopPopup();
|
initDesktopPopup();
|
||||||
}
|
}
|
||||||
|
@ -604,17 +607,34 @@ void UserActionsMenu::initTabbingPopups()
|
||||||
|
|
||||||
void UserActionsMenu::initDesktopPopup()
|
void UserActionsMenu::initDesktopPopup()
|
||||||
{
|
{
|
||||||
if (m_desktopMenu)
|
if (kwinApp()->operationMode() == Application::OperationModeWaylandOnly ||
|
||||||
return;
|
kwinApp()->operationMode() == Application::OperationModeXwayland) {
|
||||||
|
if (m_multipleDesktopsMenu) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
m_desktopMenu = new QMenu(m_menu);
|
m_multipleDesktopsMenu = new QMenu(m_menu);
|
||||||
connect(m_desktopMenu, &QMenu::triggered, this, &UserActionsMenu::slotSendToDesktop);
|
connect(m_multipleDesktopsMenu, &QMenu::triggered, this, &UserActionsMenu::slotToggleOnVirtualDesktop);
|
||||||
connect(m_desktopMenu, &QMenu::aboutToShow, this, &UserActionsMenu::desktopPopupAboutToShow);
|
connect(m_multipleDesktopsMenu, &QMenu::aboutToShow, this, &UserActionsMenu::multipleDesktopsPopupAboutToShow);
|
||||||
|
|
||||||
QAction *action = m_desktopMenu->menuAction();
|
QAction *action = m_multipleDesktopsMenu->menuAction();
|
||||||
// set it as the first item
|
// set it as the first item
|
||||||
m_menu->insertAction(m_minimizeOperation, action);
|
m_menu->insertAction(m_minimizeOperation, action);
|
||||||
action->setText(i18n("Move To &Desktop"));
|
action->setText(i18n("&Desktops"));
|
||||||
|
|
||||||
|
} else {
|
||||||
|
if (m_desktopMenu)
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_desktopMenu = new QMenu(m_menu);
|
||||||
|
connect(m_desktopMenu, &QMenu::triggered, this, &UserActionsMenu::slotSendToDesktop);
|
||||||
|
connect(m_desktopMenu, &QMenu::aboutToShow, this, &UserActionsMenu::desktopPopupAboutToShow);
|
||||||
|
|
||||||
|
QAction *action = m_desktopMenu->menuAction();
|
||||||
|
// set it as the first item
|
||||||
|
m_menu->insertAction(m_minimizeOperation, action);
|
||||||
|
action->setText(i18n("Move To &Desktop"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void UserActionsMenu::initScreenPopup()
|
void UserActionsMenu::initScreenPopup()
|
||||||
|
@ -667,6 +687,7 @@ void UserActionsMenu::desktopPopupAboutToShow()
|
||||||
m_desktopMenu->addSeparator();
|
m_desktopMenu->addSeparator();
|
||||||
|
|
||||||
const uint BASE = 10;
|
const uint BASE = 10;
|
||||||
|
|
||||||
for (uint i = 1; i <= vds->count(); ++i) {
|
for (uint i = 1; i <= vds->count(); ++i) {
|
||||||
QString basic_name(QStringLiteral("%1 %2"));
|
QString basic_name(QStringLiteral("%1 %2"));
|
||||||
if (i < BASE) {
|
if (i < BASE) {
|
||||||
|
@ -690,6 +711,58 @@ void UserActionsMenu::desktopPopupAboutToShow()
|
||||||
action->setEnabled(false);
|
action->setEnabled(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void UserActionsMenu::multipleDesktopsPopupAboutToShow()
|
||||||
|
{
|
||||||
|
if (!m_multipleDesktopsMenu)
|
||||||
|
return;
|
||||||
|
const VirtualDesktopManager *vds = VirtualDesktopManager::self();
|
||||||
|
|
||||||
|
m_multipleDesktopsMenu->clear();
|
||||||
|
m_multipleDesktopsMenu->setPalette(m_client.data()->palette());
|
||||||
|
QAction *action = m_multipleDesktopsMenu->addAction(i18n("&All Desktops"));
|
||||||
|
action->setData(0);
|
||||||
|
action->setCheckable(true);
|
||||||
|
QActionGroup *allDesktopsGroup = new QActionGroup(m_multipleDesktopsMenu);
|
||||||
|
allDesktopsGroup->addAction(action);
|
||||||
|
|
||||||
|
if (!m_client.isNull() && m_client.data()->isOnAllDesktops()) {
|
||||||
|
action->setChecked(true);
|
||||||
|
}
|
||||||
|
m_multipleDesktopsMenu->addSeparator();
|
||||||
|
|
||||||
|
|
||||||
|
const uint BASE = 10;
|
||||||
|
|
||||||
|
for (uint i = 1; i <= vds->count(); ++i) {
|
||||||
|
QString basic_name(QStringLiteral("%1 %2"));
|
||||||
|
if (i < BASE) {
|
||||||
|
basic_name.prepend(QLatin1Char('&'));
|
||||||
|
}
|
||||||
|
QWidgetAction *action = new QWidgetAction(m_multipleDesktopsMenu);
|
||||||
|
QCheckBox *box = new QCheckBox(basic_name.arg(i).arg(vds->name(i).replace(QLatin1Char('&'), QStringLiteral("&&"))), m_multipleDesktopsMenu);
|
||||||
|
action->setDefaultWidget(box);
|
||||||
|
|
||||||
|
box->setBackgroundRole(m_multipleDesktopsMenu->backgroundRole());
|
||||||
|
box->setForegroundRole(m_multipleDesktopsMenu->foregroundRole());
|
||||||
|
box->setPalette(m_multipleDesktopsMenu->palette());
|
||||||
|
connect(box, &QCheckBox::clicked, action, &QAction::triggered);
|
||||||
|
m_multipleDesktopsMenu->addAction(action);
|
||||||
|
action->setData(i);
|
||||||
|
|
||||||
|
if (!m_client.isNull() &&
|
||||||
|
!m_client.data()->isOnAllDesktops() && m_client.data()->isOnDesktop(i)) {
|
||||||
|
box->setChecked(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_multipleDesktopsMenu->addSeparator();
|
||||||
|
action = m_multipleDesktopsMenu->addAction(i18nc("Create a new desktop and move there the window", "&New Desktop"));
|
||||||
|
action->setData(vds->count() + 1);
|
||||||
|
|
||||||
|
if (vds->count() >= vds->maximum())
|
||||||
|
action->setEnabled(false);
|
||||||
|
}
|
||||||
|
|
||||||
void UserActionsMenu::screenPopupAboutToShow()
|
void UserActionsMenu::screenPopupAboutToShow()
|
||||||
{
|
{
|
||||||
if (!m_screenMenu) {
|
if (!m_screenMenu) {
|
||||||
|
@ -816,6 +889,35 @@ void UserActionsMenu::slotSendToDesktop(QAction *action)
|
||||||
ws->sendClientToDesktop(m_client.data(), desk, false);
|
ws->sendClientToDesktop(m_client.data(), desk, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void UserActionsMenu::slotToggleOnVirtualDesktop(QAction *action)
|
||||||
|
{
|
||||||
|
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 > vds->count()) {
|
||||||
|
vds->setCount(desk);
|
||||||
|
}
|
||||||
|
|
||||||
|
VirtualDesktop *virtualDesktop = VirtualDesktopManager::self()->desktopForX11Id(desk);
|
||||||
|
if (m_client.data()->desktops().contains(virtualDesktop)) {
|
||||||
|
m_client.data()->unSetDesktop(desk);
|
||||||
|
} else {
|
||||||
|
ws->sendClientToDesktop(m_client.data(), desk, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void UserActionsMenu::slotSendToScreen(QAction *action)
|
void UserActionsMenu::slotSendToScreen(QAction *action)
|
||||||
{
|
{
|
||||||
const int screen = action->data().toInt();
|
const int screen = action->data().toInt();
|
||||||
|
|
|
@ -144,6 +144,11 @@ private Q_SLOTS:
|
||||||
* the Client.
|
* the Client.
|
||||||
**/
|
**/
|
||||||
void desktopPopupAboutToShow();
|
void desktopPopupAboutToShow();
|
||||||
|
/**
|
||||||
|
* Adjusts the multipleDesktopsMenu popup to the current values and the location of
|
||||||
|
* the Client, Wayland only.
|
||||||
|
**/
|
||||||
|
void multipleDesktopsPopupAboutToShow();
|
||||||
/**
|
/**
|
||||||
* Adjusts the screen popup to the current values and the location of
|
* Adjusts the screen popup to the current values and the location of
|
||||||
* the Client.
|
* the Client.
|
||||||
|
@ -160,6 +165,12 @@ private Q_SLOTS:
|
||||||
* @param action Invoked Action containing the Desktop as data element
|
* @param action Invoked Action containing the Desktop as data element
|
||||||
**/
|
**/
|
||||||
void slotSendToDesktop(QAction *action);
|
void slotSendToDesktop(QAction *action);
|
||||||
|
/**
|
||||||
|
* Toggle whether the Client is on a desktop (Wayland only)
|
||||||
|
*
|
||||||
|
* @param action Invoked Action containing the Desktop as data element
|
||||||
|
**/
|
||||||
|
void slotToggleOnVirtualDesktop(QAction *action);
|
||||||
/**
|
/**
|
||||||
* Sends the Client to screen \a screen
|
* Sends the Client to screen \a screen
|
||||||
*
|
*
|
||||||
|
@ -217,6 +228,10 @@ private:
|
||||||
* The move to desktop sub menu.
|
* The move to desktop sub menu.
|
||||||
**/
|
**/
|
||||||
QMenu* m_desktopMenu;
|
QMenu* m_desktopMenu;
|
||||||
|
/**
|
||||||
|
* The move to desktop sub menu, with the Wayland protocol.
|
||||||
|
**/
|
||||||
|
QMenu* m_multipleDesktopsMenu;
|
||||||
/**
|
/**
|
||||||
* The move to screen sub menu.
|
* The move to screen sub menu.
|
||||||
**/
|
**/
|
||||||
|
|
|
@ -25,11 +25,14 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
#include <KGlobalAccel>
|
#include <KGlobalAccel>
|
||||||
#include <KLocalizedString>
|
#include <KLocalizedString>
|
||||||
#include <NETWM>
|
#include <NETWM>
|
||||||
|
|
||||||
|
#include <KWayland/Server/plasmavirtualdesktop_interface.h>
|
||||||
// Qt
|
// Qt
|
||||||
#include <QAction>
|
#include <QAction>
|
||||||
|
#include <QUuid>
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <QDebug>
|
||||||
namespace KWin {
|
namespace KWin {
|
||||||
|
|
||||||
extern int screen_number;
|
extern int screen_number;
|
||||||
|
@ -44,6 +47,81 @@ VirtualDesktop::~VirtualDesktop()
|
||||||
emit aboutToBeDestroyed();
|
emit aboutToBeDestroyed();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void VirtualDesktopManager::setVirtualDesktopManagement(KWayland::Server::PlasmaVirtualDesktopManagementInterface *management)
|
||||||
|
{
|
||||||
|
using namespace KWayland::Server;
|
||||||
|
Q_ASSERT(!m_virtualDesktopManagement);
|
||||||
|
m_virtualDesktopManagement = management;
|
||||||
|
|
||||||
|
connect(this, &VirtualDesktopManager::desktopCreated, this,
|
||||||
|
[this](VirtualDesktop *desktop) {
|
||||||
|
using namespace KWayland::Server;
|
||||||
|
PlasmaVirtualDesktopInterface *pvd = m_virtualDesktopManagement->createDesktop(desktop->id(), desktop->x11DesktopNumber() - 1);
|
||||||
|
pvd->setName(desktop->name());
|
||||||
|
pvd->sendDone();
|
||||||
|
connect(desktop, &VirtualDesktop::nameChanged, this,
|
||||||
|
[this, desktop, pvd]() {
|
||||||
|
pvd->setName(desktop->name());
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
//handle removed: from VirtualDesktopManager to the wayland interface
|
||||||
|
connect(this, &VirtualDesktopManager::desktopRemoved, this,
|
||||||
|
[this](VirtualDesktop *desktop) {
|
||||||
|
m_virtualDesktopManagement->removeDesktop(desktop->id());
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
//create a new desktop when the client asks to
|
||||||
|
connect (m_virtualDesktopManagement, &PlasmaVirtualDesktopManagementInterface::desktopCreateRequested, this,
|
||||||
|
[this](const QString &name, quint32 position) {
|
||||||
|
VirtualDesktop *vd = createVirtualDesktop(position);
|
||||||
|
if (vd) {
|
||||||
|
vd->setName(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
//remove when the client asks to
|
||||||
|
connect (m_virtualDesktopManagement, &PlasmaVirtualDesktopManagementInterface::desktopRemoveRequested, this,
|
||||||
|
[this](const QString &id) {
|
||||||
|
//here there can be some nice kauthorized check?
|
||||||
|
//remove only from VirtualDesktopManager, the other connections will remove it from m_virtualDesktopManagement as well
|
||||||
|
removeVirtualDesktop(id.toUtf8());
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
for (quint32 i = 1; i <= count(); ++i) {
|
||||||
|
VirtualDesktop *internalDesktop = desktopForX11Id(i);
|
||||||
|
PlasmaVirtualDesktopInterface *desktop = m_virtualDesktopManagement->createDesktop(internalDesktop->id());
|
||||||
|
|
||||||
|
desktop->setName(desktop->name());
|
||||||
|
desktop->sendDone();
|
||||||
|
|
||||||
|
connect(desktop, &PlasmaVirtualDesktopInterface::activateRequested, this,
|
||||||
|
[this, desktop] () {
|
||||||
|
setCurrent(desktopForId(desktop->id().toUtf8()));
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
//Now we are sure all ids are there
|
||||||
|
save();
|
||||||
|
|
||||||
|
connect(this, &VirtualDesktopManager::currentChanged, this,
|
||||||
|
[this]() {
|
||||||
|
for (auto *deskInt : m_virtualDesktopManagement->desktops()) {
|
||||||
|
if (deskInt->id() == currentDesktop()->id()) {
|
||||||
|
deskInt->setActive(true);
|
||||||
|
} else {
|
||||||
|
deskInt->setActive(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
void VirtualDesktop::setId(const QByteArray &id)
|
void VirtualDesktop::setId(const QByteArray &id)
|
||||||
{
|
{
|
||||||
Q_ASSERT(m_id.isEmpty());
|
Q_ASSERT(m_id.isEmpty());
|
||||||
|
@ -52,8 +130,16 @@ void VirtualDesktop::setId(const QByteArray &id)
|
||||||
|
|
||||||
void VirtualDesktop::setX11DesktopNumber(uint number)
|
void VirtualDesktop::setX11DesktopNumber(uint number)
|
||||||
{
|
{
|
||||||
Q_ASSERT(m_x11DesktopNumber == 0);
|
//x11DesktopNumber can be changed now
|
||||||
|
if (static_cast<uint>(m_x11DesktopNumber) == number) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
m_x11DesktopNumber = number;
|
m_x11DesktopNumber = number;
|
||||||
|
|
||||||
|
if (m_x11DesktopNumber != 0) {
|
||||||
|
emit x11DesktopNumberChanged();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void VirtualDesktop::setName(const QString &name)
|
void VirtualDesktop::setName(const QString &name)
|
||||||
|
@ -325,6 +411,99 @@ VirtualDesktop *VirtualDesktopManager::desktopForX11Id(uint id) const
|
||||||
return m_desktops.at(id - 1);
|
return m_desktops.at(id - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VirtualDesktop *VirtualDesktopManager::desktopForId(const QByteArray &id) const
|
||||||
|
{
|
||||||
|
auto desk = std::find_if(
|
||||||
|
m_desktops.constBegin(),
|
||||||
|
m_desktops.constEnd(),
|
||||||
|
[id] (const VirtualDesktop *desk ) {
|
||||||
|
return desk->id() == id;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
if (desk != m_desktops.constEnd()) {
|
||||||
|
return *desk;
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
VirtualDesktop *VirtualDesktopManager::createVirtualDesktop(uint number, const QString &name)
|
||||||
|
{
|
||||||
|
//too many, can't insert new ones
|
||||||
|
if ((uint)m_desktops.count() == VirtualDesktopManager::maximum()) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint actualNumber = qBound<uint>(0, number, VirtualDesktopManager::maximum());
|
||||||
|
auto *vd = new VirtualDesktop(this);
|
||||||
|
vd->setX11DesktopNumber(actualNumber);
|
||||||
|
//TODO: depend on Qt 5.11, use toString(QUuid::WithoutBraces)
|
||||||
|
vd->setId(QUuid::createUuid().toString().toUtf8());
|
||||||
|
vd->setName(name);
|
||||||
|
if (m_rootInfo) {
|
||||||
|
connect(vd, &VirtualDesktop::nameChanged, this,
|
||||||
|
[this, vd]() {
|
||||||
|
if (m_rootInfo) {
|
||||||
|
m_rootInfo->setDesktopName(vd->x11DesktopNumber(), vd->name().toUtf8().data());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
m_rootInfo->setDesktopName(vd->x11DesktopNumber(), vd->name().toUtf8().data());
|
||||||
|
}
|
||||||
|
|
||||||
|
//update the id of displaced desktops
|
||||||
|
for (uint i = actualNumber; i < (uint)m_desktops.count(); ++i) {
|
||||||
|
m_desktops[i]->setX11DesktopNumber(i + 1);
|
||||||
|
if (m_rootInfo) {
|
||||||
|
m_rootInfo->setDesktopName(i + 1, m_desktops[i]->name().toUtf8().data());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_desktops.insert(actualNumber - 1, vd);
|
||||||
|
save();
|
||||||
|
|
||||||
|
updateRootInfo();
|
||||||
|
emit desktopCreated(vd);
|
||||||
|
emit countChanged(m_desktops.count()-1, m_desktops.count());
|
||||||
|
return vd;
|
||||||
|
}
|
||||||
|
|
||||||
|
void VirtualDesktopManager::removeVirtualDesktop(const QByteArray &id)
|
||||||
|
{
|
||||||
|
//don't end up without any desktop
|
||||||
|
if (m_desktops.count() == 1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto desktop = desktopForId(id);
|
||||||
|
if (!desktop) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint oldCurrent = m_current->x11DesktopNumber();
|
||||||
|
const uint i = desktop->x11DesktopNumber() - 1;
|
||||||
|
m_desktops.remove(i);
|
||||||
|
|
||||||
|
for (uint j = i; j < (uint)m_desktops.count(); ++j) {
|
||||||
|
m_desktops[j]->setX11DesktopNumber(j + 1);
|
||||||
|
if (m_rootInfo) {
|
||||||
|
m_rootInfo->setDesktopName(j + 1, m_desktops[j]->name().toUtf8().data());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint newCurrent = qMin(oldCurrent, (uint)m_desktops.count());
|
||||||
|
m_current = m_desktops.at(newCurrent - 1);
|
||||||
|
if (oldCurrent != newCurrent) {
|
||||||
|
emit currentChanged(oldCurrent, newCurrent);
|
||||||
|
}
|
||||||
|
|
||||||
|
updateRootInfo();
|
||||||
|
emit desktopRemoved(desktop);
|
||||||
|
emit countChanged(m_desktops.count()+1, m_desktops.count());
|
||||||
|
|
||||||
|
desktop->deleteLater();
|
||||||
|
}
|
||||||
|
|
||||||
uint VirtualDesktopManager::current() const
|
uint VirtualDesktopManager::current() const
|
||||||
{
|
{
|
||||||
return m_current ? m_current->x11DesktopNumber() : 0;
|
return m_current ? m_current->x11DesktopNumber() : 0;
|
||||||
|
@ -364,33 +543,79 @@ void VirtualDesktopManager::setCount(uint count)
|
||||||
// nothing to change
|
// nothing to change
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
QList<VirtualDesktop *> newDesktops;
|
||||||
const uint oldCount = m_desktops.count();
|
const uint oldCount = m_desktops.count();
|
||||||
const uint oldCurrent = current();
|
//this explicit check makes it more readable
|
||||||
while (uint(m_desktops.count()) > count) {
|
if ((uint)m_desktops.count() > count) {
|
||||||
delete m_desktops.takeLast();
|
const auto desktopsToRemove = m_desktops.mid(count);
|
||||||
}
|
m_desktops.resize(count);
|
||||||
while (uint(m_desktops.count()) < count) {
|
if (m_current) {
|
||||||
auto vd = new VirtualDesktop(this);
|
uint oldCurrent = current();
|
||||||
vd->setX11DesktopNumber(m_desktops.count() + 1);
|
uint newCurrent = qMin(oldCurrent, count);
|
||||||
m_desktops << vd;
|
m_current = m_desktops.at(newCurrent - 1);
|
||||||
}
|
if (oldCurrent != newCurrent) {
|
||||||
if (oldCount > count) {
|
emit currentChanged(oldCurrent, newCurrent);
|
||||||
handleDesktopsRemoved(oldCount, oldCurrent);
|
}
|
||||||
|
}
|
||||||
|
for (auto desktop : desktopsToRemove) {
|
||||||
|
emit desktopRemoved(desktop);
|
||||||
|
desktop->deleteLater();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
while (uint(m_desktops.count()) < count) {
|
||||||
|
auto vd = new VirtualDesktop(this);
|
||||||
|
vd->setX11DesktopNumber(m_desktops.count() + 1);
|
||||||
|
if (!m_isLoading) {
|
||||||
|
vd->setId(QUuid::createUuid().toString().toUtf8());
|
||||||
|
}
|
||||||
|
m_desktops << vd;
|
||||||
|
newDesktops << vd;
|
||||||
|
if (m_rootInfo) {
|
||||||
|
connect(vd, &VirtualDesktop::nameChanged, this,
|
||||||
|
[this, vd]() {
|
||||||
|
if (m_rootInfo) {
|
||||||
|
m_rootInfo->setDesktopName(vd->x11DesktopNumber(), vd->name().toUtf8().data());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
m_rootInfo->setDesktopName(vd->x11DesktopNumber(), vd->name().toUtf8().data());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
updateRootInfo();
|
updateRootInfo();
|
||||||
|
|
||||||
save();
|
save();
|
||||||
|
for (auto vd : newDesktops) {
|
||||||
|
emit desktopCreated(vd);
|
||||||
|
}
|
||||||
emit countChanged(oldCount, m_desktops.count());
|
emit countChanged(oldCount, m_desktops.count());
|
||||||
}
|
}
|
||||||
|
|
||||||
void VirtualDesktopManager::handleDesktopsRemoved(uint previousCount, uint previousCurrent)
|
|
||||||
|
uint VirtualDesktopManager::rows() const
|
||||||
{
|
{
|
||||||
if (!m_current) {
|
return grid().height();
|
||||||
m_current = m_desktops.last();
|
}
|
||||||
emit currentChanged(previousCurrent, m_current->x11DesktopNumber());
|
|
||||||
|
void VirtualDesktopManager::setRows(uint rows)
|
||||||
|
{
|
||||||
|
if (static_cast<uint>(grid().height()) == rows || rows == 0 || rows > count()) {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
emit desktopsRemoved(previousCount);
|
|
||||||
|
int columns = count() / rows;
|
||||||
|
if (count() % rows > 0) {
|
||||||
|
columns++;
|
||||||
|
}
|
||||||
|
if (m_rootInfo) {
|
||||||
|
m_rootInfo->setDesktopLayout(NET::OrientationHorizontal, columns, rows, NET::DesktopLayoutCornerTopLeft);
|
||||||
|
m_rootInfo->activate();
|
||||||
|
}
|
||||||
|
|
||||||
|
updateLayout();
|
||||||
|
|
||||||
|
//rowsChanged will be emitted by setNETDesktopLayout called by updateLayout
|
||||||
}
|
}
|
||||||
|
|
||||||
void VirtualDesktopManager::updateRootInfo()
|
void VirtualDesktopManager::updateRootInfo()
|
||||||
|
@ -437,6 +662,8 @@ void VirtualDesktopManager::load()
|
||||||
if (!m_config) {
|
if (!m_config) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
//FIXME: how to avoid this?
|
||||||
|
m_isLoading = true;
|
||||||
QString groupname;
|
QString groupname;
|
||||||
if (screen_number == 0) {
|
if (screen_number == 0) {
|
||||||
groupname = QStringLiteral("Desktops");
|
groupname = QStringLiteral("Desktops");
|
||||||
|
@ -446,14 +673,31 @@ void VirtualDesktopManager::load()
|
||||||
KConfigGroup group(m_config, groupname);
|
KConfigGroup group(m_config, groupname);
|
||||||
const int n = group.readEntry("Number", 1);
|
const int n = group.readEntry("Number", 1);
|
||||||
setCount(n);
|
setCount(n);
|
||||||
if (m_rootInfo) {
|
|
||||||
for (int i = 1; i <= n; i++) {
|
for (int i = 1; i <= n; i++) {
|
||||||
QString s = group.readEntry(QStringLiteral("Name_%1").arg(i), i18n("Desktop %1", i));
|
QString s = group.readEntry(QStringLiteral("Name_%1").arg(i), i18n("Desktop %1", i));
|
||||||
|
if (m_rootInfo) {
|
||||||
m_rootInfo->setDesktopName(i, s.toUtf8().data());
|
m_rootInfo->setDesktopName(i, s.toUtf8().data());
|
||||||
// TODO: update desktop focus chain, why?
|
}
|
||||||
// m_desktopFocusChain.value()[i-1] = i;
|
m_desktops[i-1]->setName(s.toUtf8().data());
|
||||||
|
|
||||||
|
QString sId = group.readEntry(QStringLiteral("Id_%1").arg(i), QString());
|
||||||
|
|
||||||
|
//load gets called 2 times, see workspace.cpp line 416 and BUG 385260
|
||||||
|
if (m_desktops[i-1]->id().isEmpty()) {
|
||||||
|
if (sId.isEmpty()) {
|
||||||
|
sId = QUuid::createUuid().toString();
|
||||||
|
}
|
||||||
|
m_desktops[i-1]->setId(sId.toUtf8().data());
|
||||||
|
} else {
|
||||||
|
Q_ASSERT(sId.isEmpty() || m_desktops[i-1]->id() == sId.toUtf8().data());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: update desktop focus chain, why?
|
||||||
|
// m_desktopFocusChain.value()[i-1] = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_rootInfo) {
|
||||||
int rows = group.readEntry<int>("Rows", 2);
|
int rows = group.readEntry<int>("Rows", 2);
|
||||||
rows = qBound(1, rows, n);
|
rows = qBound(1, rows, n);
|
||||||
// avoid weird cases like having 3 rows for 4 desktops, where the last row is unused
|
// avoid weird cases like having 3 rows for 4 desktops, where the last row is unused
|
||||||
|
@ -464,7 +708,9 @@ void VirtualDesktopManager::load()
|
||||||
m_rootInfo->setDesktopLayout(NET::OrientationHorizontal, columns, rows, NET::DesktopLayoutCornerTopLeft);
|
m_rootInfo->setDesktopLayout(NET::OrientationHorizontal, columns, rows, NET::DesktopLayoutCornerTopLeft);
|
||||||
m_rootInfo->activate();
|
m_rootInfo->activate();
|
||||||
}
|
}
|
||||||
|
|
||||||
s_loadingDesktopSettings = false;
|
s_loadingDesktopSettings = false;
|
||||||
|
m_isLoading = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void VirtualDesktopManager::save()
|
void VirtualDesktopManager::save()
|
||||||
|
@ -502,6 +748,7 @@ void VirtualDesktopManager::save()
|
||||||
group.deleteEntry(QStringLiteral("Name_%1").arg(i));
|
group.deleteEntry(QStringLiteral("Name_%1").arg(i));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
group.writeEntry(QStringLiteral("Id_%1").arg(i), m_desktops[i-1]->id());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Save to disk
|
// Save to disk
|
||||||
|
@ -536,6 +783,7 @@ void VirtualDesktopManager::setNETDesktopLayout(Qt::Orientation orientation, uin
|
||||||
m_grid.update(QSize(width, height), orientation, m_desktops);
|
m_grid.update(QSize(width, height), orientation, m_desktops);
|
||||||
// TODO: why is there no call to m_rootInfo->setDesktopLayout?
|
// TODO: why is there no call to m_rootInfo->setDesktopLayout?
|
||||||
emit layoutChanged(width, height);
|
emit layoutChanged(width, height);
|
||||||
|
emit rowsChanged(height);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VirtualDesktopManager::initShortcuts()
|
void VirtualDesktopManager::initShortcuts()
|
||||||
|
|
|
@ -27,6 +27,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
#include <QPoint>
|
#include <QPoint>
|
||||||
#include <QPointer>
|
#include <QPointer>
|
||||||
#include <QSize>
|
#include <QSize>
|
||||||
|
|
||||||
// KDE includes
|
// KDE includes
|
||||||
#include <KConfig>
|
#include <KConfig>
|
||||||
#include <KSharedConfig>
|
#include <KSharedConfig>
|
||||||
|
@ -35,13 +36,21 @@ class KLocalizedString;
|
||||||
class NETRootInfo;
|
class NETRootInfo;
|
||||||
class QAction;
|
class QAction;
|
||||||
|
|
||||||
|
namespace KWayland
|
||||||
|
{
|
||||||
|
namespace Server
|
||||||
|
{
|
||||||
|
class PlasmaVirtualDesktopManagementInterface;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
namespace KWin {
|
namespace KWin {
|
||||||
|
|
||||||
class KWIN_EXPORT VirtualDesktop : public QObject
|
class KWIN_EXPORT VirtualDesktop : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
Q_PROPERTY(QByteArray id READ id CONSTANT)
|
Q_PROPERTY(QByteArray id READ id CONSTANT)
|
||||||
Q_PROPERTY(uint x11DesktopNumber READ x11DesktopNumber CONSTANT)
|
Q_PROPERTY(uint x11DesktopNumber READ x11DesktopNumber NOTIFY x11DesktopNumberChanged)
|
||||||
Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged)
|
Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged)
|
||||||
public:
|
public:
|
||||||
explicit VirtualDesktop(QObject *parent = nullptr);
|
explicit VirtualDesktop(QObject *parent = nullptr);
|
||||||
|
@ -64,6 +73,7 @@ public:
|
||||||
|
|
||||||
Q_SIGNALS:
|
Q_SIGNALS:
|
||||||
void nameChanged();
|
void nameChanged();
|
||||||
|
void x11DesktopNumberChanged();
|
||||||
/**
|
/**
|
||||||
* Emitted just before the desktop gets destroyed.
|
* Emitted just before the desktop gets destroyed.
|
||||||
**/
|
**/
|
||||||
|
@ -148,9 +158,13 @@ class KWIN_EXPORT VirtualDesktopManager : public QObject
|
||||||
public:
|
public:
|
||||||
virtual ~VirtualDesktopManager();
|
virtual ~VirtualDesktopManager();
|
||||||
/**
|
/**
|
||||||
* @internal
|
* @internal, for X11 case
|
||||||
**/
|
**/
|
||||||
void setRootInfo(NETRootInfo *info);
|
void setRootInfo(NETRootInfo *info);
|
||||||
|
/**
|
||||||
|
* @internal, for Wayland case
|
||||||
|
**/
|
||||||
|
void setVirtualDesktopManagement(KWayland::Server::PlasmaVirtualDesktopManagementInterface *management);
|
||||||
/**
|
/**
|
||||||
* @internal
|
* @internal
|
||||||
**/
|
**/
|
||||||
|
@ -161,6 +175,12 @@ public:
|
||||||
* @see countChanged
|
* @see countChanged
|
||||||
*/
|
*/
|
||||||
uint count() const;
|
uint count() const;
|
||||||
|
/**
|
||||||
|
* @returns the number of rows the layout has.
|
||||||
|
* @see setRows
|
||||||
|
* @see rowsChanged
|
||||||
|
*/
|
||||||
|
uint rows() const;
|
||||||
/**
|
/**
|
||||||
* @returns The ID of the current desktop.
|
* @returns The ID of the current desktop.
|
||||||
* @see setCurrent
|
* @see setCurrent
|
||||||
|
@ -263,6 +283,30 @@ public:
|
||||||
**/
|
**/
|
||||||
VirtualDesktop *desktopForX11Id(uint id) const;
|
VirtualDesktop *desktopForX11Id(uint id) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns The VirtualDesktop for the internal desktop string @p id, if no such VirtualDesktop @c null is returned
|
||||||
|
**/
|
||||||
|
VirtualDesktop *desktopForId(const QByteArray &id) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new virtual desktop at the requested position.
|
||||||
|
* The difference with setCount is that setCount always adds new desktops at the end of the chain. The Id is automatically generated.
|
||||||
|
* @param x11DesktopNumber number for the desktop. The desktop created will have an
|
||||||
|
* x11DesktopNumber guaranteed to be between 1 and numberOfDesktops().
|
||||||
|
* Existing desktops will eventually have their x11DesktopNumber increased.
|
||||||
|
* @param name The name for the new desktop, if empty the default name will be used.
|
||||||
|
* @returns the new VirtualDesktop, nullptr if we reached the maximum number of desktops
|
||||||
|
*/
|
||||||
|
VirtualDesktop *createVirtualDesktop(uint x11DesktopNumber, const QString &name = QString());
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the virtual desktop identified by id, if it exists
|
||||||
|
* difference with setCount is that is possible to remove an arbitrary desktop,
|
||||||
|
* not only the last one.
|
||||||
|
* @param id the string id of the desktop to remove
|
||||||
|
*/
|
||||||
|
void removeVirtualDesktop(const QByteArray &id);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates the net root info for new number of desktops
|
* Updates the net root info for new number of desktops
|
||||||
**/
|
**/
|
||||||
|
@ -283,13 +327,14 @@ public Q_SLOTS:
|
||||||
* @link countChanged signal.
|
* @link countChanged signal.
|
||||||
*
|
*
|
||||||
* In case the @link current desktop is on a desktop higher than the new count, the current desktop
|
* 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 changed to be the new desktop with highest id. In that situation the signal @link desktopRemoved
|
||||||
* is emitted.
|
* is emitted.
|
||||||
* @param count The new number of desktops to use
|
* @param count The new number of desktops to use
|
||||||
* @see count
|
* @see count
|
||||||
* @see maximum
|
* @see maximum
|
||||||
* @see countChanged
|
* @see countChanged
|
||||||
* @see desktopsRemoved
|
* @see desktopCreated
|
||||||
|
* @see desktopRemoved
|
||||||
*/
|
*/
|
||||||
void setCount(uint count);
|
void setCount(uint count);
|
||||||
/**
|
/**
|
||||||
|
@ -308,6 +353,10 @@ public Q_SLOTS:
|
||||||
* @see moveTo
|
* @see moveTo
|
||||||
**/
|
**/
|
||||||
bool setCurrent(VirtualDesktop *current);
|
bool setCurrent(VirtualDesktop *current);
|
||||||
|
/**
|
||||||
|
* Updates the layout to a new number of rows. The number of columns will be calculated accordingly
|
||||||
|
*/
|
||||||
|
void setRows(uint rows);
|
||||||
/**
|
/**
|
||||||
* Called from within setCount() to ensure the desktop layout is still valid.
|
* Called from within setCount() to ensure the desktop layout is still valid.
|
||||||
*/
|
*/
|
||||||
|
@ -334,18 +383,27 @@ Q_SIGNALS:
|
||||||
* @param newCount The new current number of desktops
|
* @param newCount The new current number of desktops
|
||||||
**/
|
**/
|
||||||
void countChanged(uint previousCount, uint newCount);
|
void countChanged(uint previousCount, uint newCount);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Signal emitted whenever the number of virtual desktops changes in a way
|
* Signal when the number of rows in the layout changes
|
||||||
* that existing desktops are removed.
|
* @param new number of rows
|
||||||
*
|
*/
|
||||||
* The signal is emitted after the @c count property has been updated but prior
|
void rowsChanged(uint rows);
|
||||||
* to the @link countChanged signal being emitted.
|
|
||||||
* @param previousCount The number of desktops prior to the change.
|
/**
|
||||||
* @see countChanged
|
* A new desktop has been created
|
||||||
* @see setCount
|
* @param desktop the new just crated desktop
|
||||||
* @see count
|
*/
|
||||||
**/
|
void desktopCreated(KWin::VirtualDesktop *desktop);
|
||||||
void desktopsRemoved(uint previousCount);
|
|
||||||
|
/**
|
||||||
|
* A desktop has been removed and is about to be deleted
|
||||||
|
* @param desktop the desktop that has been removed.
|
||||||
|
* It's guaranteed to stil la valid pointer when the signal arrives,
|
||||||
|
* but it's about to be deleted.
|
||||||
|
*/
|
||||||
|
void desktopRemoved(KWin::VirtualDesktop *desktop);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Signal emitted whenever the current desktop changes.
|
* Signal emitted whenever the current desktop changes.
|
||||||
* @param previousDesktop The virtual desktop changed from
|
* @param previousDesktop The virtual desktop changed from
|
||||||
|
@ -396,21 +454,6 @@ private Q_SLOTS:
|
||||||
void slotDown();
|
void slotDown();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/**
|
|
||||||
* 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.
|
|
||||||
* @param previousCurrent The number of the previously current desktop.
|
|
||||||
* @see setCount
|
|
||||||
* @see desktopsRemoved
|
|
||||||
**/
|
|
||||||
void handleDesktopsRemoved(uint previousCount, uint previousCurrent);
|
|
||||||
/**
|
/**
|
||||||
* Generate a desktop layout from EWMH _NET_DESKTOP_LAYOUT property parameters.
|
* Generate a desktop layout from EWMH _NET_DESKTOP_LAYOUT property parameters.
|
||||||
*/
|
*/
|
||||||
|
@ -450,7 +493,9 @@ private:
|
||||||
VirtualDesktopGrid m_grid;
|
VirtualDesktopGrid m_grid;
|
||||||
// TODO: QPointer
|
// TODO: QPointer
|
||||||
NETRootInfo *m_rootInfo;
|
NETRootInfo *m_rootInfo;
|
||||||
|
KWayland::Server::PlasmaVirtualDesktopManagementInterface *m_virtualDesktopManagement = nullptr;
|
||||||
KSharedConfig::Ptr m_config;
|
KSharedConfig::Ptr m_config;
|
||||||
|
bool m_isLoading = false;
|
||||||
|
|
||||||
KWIN_SINGLETON_VARIABLE(VirtualDesktopManager, s_manager)
|
KWIN_SINGLETON_VARIABLE(VirtualDesktopManager, s_manager)
|
||||||
};
|
};
|
||||||
|
|
|
@ -0,0 +1,70 @@
|
||||||
|
/********************************************************************
|
||||||
|
KWin - the KDE window manager
|
||||||
|
This file is part of the KDE project.
|
||||||
|
|
||||||
|
Copyright (C) 2018 Marco Martin <mart@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/>.
|
||||||
|
*********************************************************************/
|
||||||
|
|
||||||
|
// own
|
||||||
|
#include "virtualdesktopsdbustypes.h"
|
||||||
|
|
||||||
|
|
||||||
|
// Marshall the DBusDesktopDataStruct data into a D-BUS argument
|
||||||
|
const QDBusArgument &operator<<(QDBusArgument &argument, const KWin::DBusDesktopDataStruct &desk)
|
||||||
|
{
|
||||||
|
argument.beginStructure();
|
||||||
|
argument << desk.position;
|
||||||
|
argument << desk.id;
|
||||||
|
argument << desk.name;
|
||||||
|
argument.endStructure();
|
||||||
|
return argument;
|
||||||
|
}
|
||||||
|
// Retrieve
|
||||||
|
const QDBusArgument &operator>>(const QDBusArgument &argument, KWin::DBusDesktopDataStruct &desk)
|
||||||
|
{
|
||||||
|
argument.beginStructure();
|
||||||
|
argument >> desk.position;
|
||||||
|
argument >> desk.id;
|
||||||
|
argument >> desk.name;
|
||||||
|
argument.endStructure();
|
||||||
|
return argument;
|
||||||
|
}
|
||||||
|
|
||||||
|
const QDBusArgument &operator<<(QDBusArgument &argument, const KWin::DBusDesktopDataVector &deskVector)
|
||||||
|
{
|
||||||
|
argument.beginArray(qMetaTypeId<KWin::DBusDesktopDataStruct>());
|
||||||
|
for (int i = 0; i < deskVector.size(); ++i) {
|
||||||
|
argument << deskVector[i];
|
||||||
|
}
|
||||||
|
argument.endArray();
|
||||||
|
return argument;
|
||||||
|
}
|
||||||
|
|
||||||
|
const QDBusArgument &operator>>(const QDBusArgument &argument, KWin::DBusDesktopDataVector &deskVector)
|
||||||
|
{
|
||||||
|
argument.beginArray();
|
||||||
|
deskVector.clear();
|
||||||
|
|
||||||
|
while (!argument.atEnd()) {
|
||||||
|
KWin::DBusDesktopDataStruct element;
|
||||||
|
argument >> element;
|
||||||
|
deskVector.append(element);
|
||||||
|
}
|
||||||
|
|
||||||
|
argument.endArray();
|
||||||
|
|
||||||
|
return argument;
|
||||||
|
}
|
|
@ -0,0 +1,47 @@
|
||||||
|
/********************************************************************
|
||||||
|
KWin - the KDE window manager
|
||||||
|
This file is part of the KDE project.
|
||||||
|
|
||||||
|
Copyright (C) 2018 Marco Martin <mart@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_VIRTUALDESKTOPS_DBUS_TYPES_H
|
||||||
|
#define KWIN_VIRTUALDESKTOPS_DBUS_TYPES_H
|
||||||
|
|
||||||
|
#include <QtDBus>
|
||||||
|
|
||||||
|
namespace KWin
|
||||||
|
{
|
||||||
|
|
||||||
|
struct DBusDesktopDataStruct {
|
||||||
|
uint position;
|
||||||
|
QString id;
|
||||||
|
QString name;
|
||||||
|
};
|
||||||
|
typedef QVector<DBusDesktopDataStruct> DBusDesktopDataVector;
|
||||||
|
}
|
||||||
|
|
||||||
|
const QDBusArgument &operator<<(QDBusArgument &argument, const KWin::DBusDesktopDataStruct &desk);
|
||||||
|
const QDBusArgument &operator>>(const QDBusArgument &argument, KWin::DBusDesktopDataStruct &desk);
|
||||||
|
|
||||||
|
Q_DECLARE_METATYPE(KWin::DBusDesktopDataStruct)
|
||||||
|
|
||||||
|
const QDBusArgument &operator<<(QDBusArgument &argument, const KWin::DBusDesktopDataVector &deskVector);
|
||||||
|
const QDBusArgument &operator>>(const QDBusArgument &argument, KWin::DBusDesktopDataVector &deskVector);
|
||||||
|
|
||||||
|
Q_DECLARE_METATYPE(KWin::DBusDesktopDataVector)
|
||||||
|
|
||||||
|
#endif // KWIN_VIRTUALDESKTOPS_DBUS_TYPES_H
|
|
@ -43,6 +43,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
#include <KWayland/Server/idleinhibit_interface.h>
|
#include <KWayland/Server/idleinhibit_interface.h>
|
||||||
#include <KWayland/Server/output_interface.h>
|
#include <KWayland/Server/output_interface.h>
|
||||||
#include <KWayland/Server/plasmashell_interface.h>
|
#include <KWayland/Server/plasmashell_interface.h>
|
||||||
|
#include <KWayland/Server/plasmavirtualdesktop_interface.h>
|
||||||
#include <KWayland/Server/plasmawindowmanagement_interface.h>
|
#include <KWayland/Server/plasmawindowmanagement_interface.h>
|
||||||
#include <KWayland/Server/pointerconstraints_interface.h>
|
#include <KWayland/Server/pointerconstraints_interface.h>
|
||||||
#include <KWayland/Server/pointergestures_interface.h>
|
#include <KWayland/Server/pointergestures_interface.h>
|
||||||
|
@ -333,6 +334,12 @@ bool WaylandServer::init(const QByteArray &socketName, InitalizationFlags flags)
|
||||||
workspace()->setShowingDesktop(set);
|
workspace()->setShowingDesktop(set);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
|
m_virtualDesktopManagement = m_display->createPlasmaVirtualDesktopManagement(m_display);
|
||||||
|
m_virtualDesktopManagement->create();
|
||||||
|
m_windowManagement->setPlasmaVirtualDesktopManagementInterface(m_virtualDesktopManagement);
|
||||||
|
|
||||||
auto shadowManager = m_display->createShadowManager(m_display);
|
auto shadowManager = m_display->createShadowManager(m_display);
|
||||||
shadowManager->create();
|
shadowManager->create();
|
||||||
|
|
||||||
|
@ -390,6 +397,8 @@ void WaylandServer::shellClientShown(Toplevel *t)
|
||||||
|
|
||||||
void WaylandServer::initWorkspace()
|
void WaylandServer::initWorkspace()
|
||||||
{
|
{
|
||||||
|
VirtualDesktopManager::self()->setVirtualDesktopManagement(m_virtualDesktopManagement);
|
||||||
|
|
||||||
if (m_windowManagement) {
|
if (m_windowManagement) {
|
||||||
connect(workspace(), &Workspace::showingDesktopChanged, this,
|
connect(workspace(), &Workspace::showingDesktopChanged, this,
|
||||||
[this] (bool set) {
|
[this] (bool set) {
|
||||||
|
|
|
@ -54,6 +54,7 @@ class SurfaceInterface;
|
||||||
class OutputInterface;
|
class OutputInterface;
|
||||||
class PlasmaShellInterface;
|
class PlasmaShellInterface;
|
||||||
class PlasmaShellSurfaceInterface;
|
class PlasmaShellSurfaceInterface;
|
||||||
|
class PlasmaVirtualDesktopManagementInterface;
|
||||||
class PlasmaWindowManagementInterface;
|
class PlasmaWindowManagementInterface;
|
||||||
class QtSurfaceExtensionInterface;
|
class QtSurfaceExtensionInterface;
|
||||||
class OutputManagementInterface;
|
class OutputManagementInterface;
|
||||||
|
@ -99,6 +100,9 @@ public:
|
||||||
KWayland::Server::ShellInterface *shell() {
|
KWayland::Server::ShellInterface *shell() {
|
||||||
return m_shell;
|
return m_shell;
|
||||||
}
|
}
|
||||||
|
KWayland::Server::PlasmaVirtualDesktopManagementInterface *virtualDesktopManagement() {
|
||||||
|
return m_virtualDesktopManagement;
|
||||||
|
}
|
||||||
KWayland::Server::PlasmaWindowManagementInterface *windowManagement() {
|
KWayland::Server::PlasmaWindowManagementInterface *windowManagement() {
|
||||||
return m_windowManagement;
|
return m_windowManagement;
|
||||||
}
|
}
|
||||||
|
@ -227,6 +231,7 @@ private:
|
||||||
KWayland::Server::XdgShellInterface *m_xdgShell = nullptr;
|
KWayland::Server::XdgShellInterface *m_xdgShell = nullptr;
|
||||||
KWayland::Server::PlasmaShellInterface *m_plasmaShell = nullptr;
|
KWayland::Server::PlasmaShellInterface *m_plasmaShell = nullptr;
|
||||||
KWayland::Server::PlasmaWindowManagementInterface *m_windowManagement = nullptr;
|
KWayland::Server::PlasmaWindowManagementInterface *m_windowManagement = nullptr;
|
||||||
|
KWayland::Server::PlasmaVirtualDesktopManagementInterface *m_virtualDesktopManagement = nullptr;
|
||||||
KWayland::Server::QtSurfaceExtensionInterface *m_qtExtendedSurface = nullptr;
|
KWayland::Server::QtSurfaceExtensionInterface *m_qtExtendedSurface = nullptr;
|
||||||
KWayland::Server::ServerSideDecorationManagerInterface *m_decorationManager = nullptr;
|
KWayland::Server::ServerSideDecorationManagerInterface *m_decorationManager = nullptr;
|
||||||
KWayland::Server::OutputManagementInterface *m_outputManagement = nullptr;
|
KWayland::Server::OutputManagementInterface *m_outputManagement = nullptr;
|
||||||
|
|
|
@ -165,6 +165,8 @@ Workspace::Workspace(const QString &sessionKey)
|
||||||
// and prior to TabBox, due to TabBox connecting to signals
|
// and prior to TabBox, due to TabBox connecting to signals
|
||||||
// actual initialization happens in init()
|
// actual initialization happens in init()
|
||||||
VirtualDesktopManager::create(this);
|
VirtualDesktopManager::create(this);
|
||||||
|
//dbus interface
|
||||||
|
new VirtualDesktopManagerDBusInterface(VirtualDesktopManager::self());
|
||||||
|
|
||||||
#ifdef KWIN_BUILD_TABBOX
|
#ifdef KWIN_BUILD_TABBOX
|
||||||
// need to create the tabbox before compositing scene is setup
|
// need to create the tabbox before compositing scene is setup
|
||||||
|
@ -219,7 +221,30 @@ void Workspace::init()
|
||||||
|
|
||||||
// create VirtualDesktopManager and perform dependency injection
|
// create VirtualDesktopManager and perform dependency injection
|
||||||
VirtualDesktopManager *vds = VirtualDesktopManager::self();
|
VirtualDesktopManager *vds = VirtualDesktopManager::self();
|
||||||
connect(vds, SIGNAL(desktopsRemoved(uint)), SLOT(moveClientsFromRemovedDesktops()));
|
connect(vds, &VirtualDesktopManager::desktopRemoved, this,
|
||||||
|
[this](KWin::VirtualDesktop *desktop) {
|
||||||
|
//Wayland
|
||||||
|
if (kwinApp()->operationMode() == Application::OperationModeWaylandOnly ||
|
||||||
|
kwinApp()->operationMode() == Application::OperationModeXwayland) {
|
||||||
|
for (auto it = m_allClients.constBegin(); it != m_allClients.constEnd(); ++it) {
|
||||||
|
const bool needsMove = (*it)->desktops().count() == 1;
|
||||||
|
(*it)->removeDesktop(desktop);
|
||||||
|
if (needsMove) {
|
||||||
|
const VirtualDesktop *otherDesktop = VirtualDesktopManager::self()->desktops().first();
|
||||||
|
sendClientToDesktop(*it, qMin(desktop->x11DesktopNumber(), VirtualDesktopManager::self()->count()), true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//X11
|
||||||
|
} else {
|
||||||
|
for (auto it = m_allClients.constBegin(); it != m_allClients.constEnd(); ++it) {
|
||||||
|
if (!(*it)->isOnAllDesktops() && ((*it)->desktop() > static_cast<int>(VirtualDesktopManager::self()->count()))) {
|
||||||
|
sendClientToDesktop(*it, VirtualDesktopManager::self()->count(), true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
connect(vds, SIGNAL(countChanged(uint,uint)), SLOT(slotDesktopCountChanged(uint,uint)));
|
connect(vds, SIGNAL(countChanged(uint,uint)), SLOT(slotDesktopCountChanged(uint,uint)));
|
||||||
connect(vds, SIGNAL(currentChanged(uint,uint)), SLOT(slotCurrentDesktopChanged(uint,uint)));
|
connect(vds, SIGNAL(currentChanged(uint,uint)), SLOT(slotCurrentDesktopChanged(uint,uint)));
|
||||||
vds->setNavigationWrappingAround(options->isRollOverDesktops());
|
vds->setNavigationWrappingAround(options->isRollOverDesktops());
|
||||||
|
@ -232,6 +257,9 @@ void Workspace::init()
|
||||||
// positioning object needs to be created before the virtual desktops are loaded.
|
// positioning object needs to be created before the virtual desktops are loaded.
|
||||||
vds->load();
|
vds->load();
|
||||||
vds->updateLayout();
|
vds->updateLayout();
|
||||||
|
//makes sure any autogenerated id is saved, necessary as in case of xwayland, load will be called 2 times
|
||||||
|
// load is needed to be called again when starting xwayalnd to sync to RootInfo, see BUG 385260
|
||||||
|
vds->save();
|
||||||
|
|
||||||
if (!VirtualDesktopManager::self()->setCurrent(m_initialDesktop))
|
if (!VirtualDesktopManager::self()->setCurrent(m_initialDesktop))
|
||||||
VirtualDesktopManager::self()->setCurrent(1);
|
VirtualDesktopManager::self()->setCurrent(1);
|
||||||
|
@ -1074,14 +1102,6 @@ void Workspace::updateCurrentActivity(const QString &new_activity)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void Workspace::moveClientsFromRemovedDesktops()
|
|
||||||
{
|
|
||||||
for (auto it = m_allClients.constBegin(); it != m_allClients.constEnd(); ++it) {
|
|
||||||
if (!(*it)->isOnAllDesktops() && (*it)->desktop() > static_cast<int>(VirtualDesktopManager::self()->count()))
|
|
||||||
sendClientToDesktop(*it, VirtualDesktopManager::self()->count(), true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Workspace::slotDesktopCountChanged(uint previousCount, uint newCount)
|
void Workspace::slotDesktopCountChanged(uint previousCount, uint newCount)
|
||||||
{
|
{
|
||||||
Q_UNUSED(previousCount)
|
Q_UNUSED(previousCount)
|
||||||
|
|
|
@ -457,7 +457,6 @@ private Q_SLOTS:
|
||||||
void slotReloadConfig();
|
void slotReloadConfig();
|
||||||
void updateCurrentActivity(const QString &new_activity);
|
void updateCurrentActivity(const QString &new_activity);
|
||||||
// virtual desktop handling
|
// virtual desktop handling
|
||||||
void moveClientsFromRemovedDesktops();
|
|
||||||
void slotDesktopCountChanged(uint previousCount, uint newCount);
|
void slotDesktopCountChanged(uint previousCount, uint newCount);
|
||||||
void slotCurrentDesktopChanged(uint oldDesktop, uint newDesktop);
|
void slotCurrentDesktopChanged(uint oldDesktop, uint newDesktop);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue