Port Workspace::topClientOnDesktop() to VirtualDesktop

This patch has one behavioral change - raiseOrLowerClient() will not
work if the client is not on the current virtual desktop.

However, raiseOrLowerClient() can be called only in two cases:

* user triggers the raise or lower shortcut for the active client. Since
  the active client is on the current virtual desktop, it's not an issue

* an x11 window restacks itself. It makes no sense if an x11 window
  restacks itself while it's inactive or not on current virtual desktop.
  Also, the Opposite restack mode is rarely used, some window managers
  don't even bother implementing it. So, having such a constraint should
  not be a problem.

The main reason for not allowing raiseOrLowerClient() for windows that
are not on the current virtual desktop is that a window can be on
multiple virtual desktops. If a window is on A and B virtual desktops,
the only logical option is to toggle stacking position if the window is
on the current desktop. It's the only viable option as kwin does not
maintain per virtual desktop stacking order.
This commit is contained in:
Vlad Zahorodnii 2021-08-13 11:41:57 +03:00
parent 76e74d7660
commit b75f089981
6 changed files with 24 additions and 19 deletions

View file

@ -16,6 +16,7 @@
#include "options.h"
#include "screenedge.h"
#include "screens.h"
#include "virtualdesktops.h"
#include "wayland_server.h"
#include "workspace.h"
#include "xcursortheme.h"
@ -756,7 +757,7 @@ void PointerInputTest::testFocusFollowsMouse()
AbstractClient *window2 = workspace()->activeClient();
QVERIFY(window2);
QVERIFY(window1 != window2);
QCOMPARE(workspace()->topClientOnDesktop(1, -1), window2);
QCOMPARE(workspace()->topClientOnDesktop(VirtualDesktopManager::self()->currentDesktop(), -1), window2);
// geometry of the two windows should be overlapping
QVERIFY(window1->frameGeometry().intersects(window2->frameGeometry()));
@ -775,18 +776,18 @@ void PointerInputTest::testFocusFollowsMouse()
Cursors::self()->mouse()->setPos(10, 10);
QVERIFY(stackingOrderChangedSpy.wait());
QCOMPARE(stackingOrderChangedSpy.count(), 1);
QCOMPARE(workspace()->topClientOnDesktop(1, -1), window1);
QCOMPARE(workspace()->topClientOnDesktop(VirtualDesktopManager::self()->currentDesktop(), -1), window1);
QTRY_VERIFY(window1->isActive());
// move on second window, but move away before active window change delay hits
Cursors::self()->mouse()->setPos(810, 810);
QVERIFY(stackingOrderChangedSpy.wait());
QCOMPARE(stackingOrderChangedSpy.count(), 2);
QCOMPARE(workspace()->topClientOnDesktop(1, -1), window2);
QCOMPARE(workspace()->topClientOnDesktop(VirtualDesktopManager::self()->currentDesktop(), -1), window2);
Cursors::self()->mouse()->setPos(10, 10);
QVERIFY(!activeWindowChangedSpy.wait(250));
QVERIFY(window1->isActive());
QCOMPARE(workspace()->topClientOnDesktop(1, -1), window1);
QCOMPARE(workspace()->topClientOnDesktop(VirtualDesktopManager::self()->currentDesktop(), -1), window1);
// as we moved back on window 1 that should been raised in the mean time
QCOMPARE(stackingOrderChangedSpy.count(), 3);
@ -842,7 +843,7 @@ void PointerInputTest::testMouseActionInactiveWindow()
AbstractClient *window2 = workspace()->activeClient();
QVERIFY(window2);
QVERIFY(window1 != window2);
QCOMPARE(workspace()->topClientOnDesktop(1, -1), window2);
QCOMPARE(workspace()->topClientOnDesktop(VirtualDesktopManager::self()->currentDesktop(), -1), window2);
// geometry of the two windows should be overlapping
QVERIFY(window1->frameGeometry().intersects(window2->frameGeometry()));
@ -871,7 +872,7 @@ void PointerInputTest::testMouseActionInactiveWindow()
// should raise window1 and activate it
QCOMPARE(stackingOrderChangedSpy.count(), 1);
QVERIFY(!activeWindowChangedSpy.isEmpty());
QCOMPARE(workspace()->topClientOnDesktop(1, -1), window1);
QCOMPARE(workspace()->topClientOnDesktop(VirtualDesktopManager::self()->currentDesktop(), -1), window1);
QVERIFY(window1->isActive());
QVERIFY(!window2->isActive());
@ -936,12 +937,12 @@ void PointerInputTest::testMouseActionActiveWindow()
QVERIFY(window1 != window2);
QSignalSpy window2DestroyedSpy(window2, &QObject::destroyed);
QVERIFY(window2DestroyedSpy.isValid());
QCOMPARE(workspace()->topClientOnDesktop(1, -1), window2);
QCOMPARE(workspace()->topClientOnDesktop(VirtualDesktopManager::self()->currentDesktop(), -1), window2);
// geometry of the two windows should be overlapping
QVERIFY(window1->frameGeometry().intersects(window2->frameGeometry()));
// lower the currently active window
workspace()->lowerClient(window2);
QCOMPARE(workspace()->topClientOnDesktop(1, -1), window1);
QCOMPARE(workspace()->topClientOnDesktop(VirtualDesktopManager::self()->currentDesktop(), -1), window1);
// signal spy for stacking order spy
QSignalSpy stackingOrderChangedSpy(workspace(), &Workspace::stackingOrderChanged);
@ -959,11 +960,11 @@ void PointerInputTest::testMouseActionActiveWindow()
QVERIFY(buttonSpy.wait());
if (clickRaise) {
QCOMPARE(stackingOrderChangedSpy.count(), 1);
QTRY_COMPARE_WITH_TIMEOUT(workspace()->topClientOnDesktop(1, -1), window2, 200);
QTRY_COMPARE_WITH_TIMEOUT(workspace()->topClientOnDesktop(VirtualDesktopManager::self()->currentDesktop(), -1), window2, 200);
} else {
QCOMPARE(stackingOrderChangedSpy.count(), 0);
QVERIFY(!stackingOrderChangedSpy.wait(100));
QCOMPARE(workspace()->topClientOnDesktop(1, -1), window1);
QCOMPARE(workspace()->topClientOnDesktop(VirtualDesktopManager::self()->currentDesktop(), -1), window1);
}
// release again

View file

@ -389,7 +389,7 @@ void AbstractClient::autoRaise()
bool AbstractClient::isMostRecentlyRaised() const
{
// The last toplevel in the unconstrained stacking order is the most recently raised one.
return workspace()->topClientOnDesktop(VirtualDesktopManager::self()->current(), -1, true, false) == this;
return workspace()->topClientOnDesktop(VirtualDesktopManager::self()->currentDesktop(), -1, true, false) == this;
}
bool AbstractClient::wantsTabFocus() const
@ -2525,7 +2525,7 @@ void AbstractClient::enterEvent(const QPoint &globalPos)
if (options->isAutoRaise() && !isDesktop() &&
!isDock() && workspace()->focusChangeEnabled() &&
globalPos != workspace()->focusMousePosition() &&
workspace()->topClientOnDesktop(VirtualDesktopManager::self()->current(),
workspace()->topClientOnDesktop(VirtualDesktopManager::self()->currentDesktop(),
options->isSeparateScreenFocus() ? screen() : -1) != this) {
startAutoRaise();
}

View file

@ -218,7 +218,7 @@ void Workspace::propagateClients(bool propagate_new_clients)
* doesn't accept focus it's excluded.
*/
// TODO misleading name for this method, too many slightly different ways to use it
AbstractClient* Workspace::topClientOnDesktop(int desktop, int screen, bool unconstrained, bool only_normal) const
AbstractClient *Workspace::topClientOnDesktop(VirtualDesktop *desktop, int screen, bool unconstrained, bool only_normal) const
{
// TODO Q_ASSERT( block_stacking_updates == 0 );
QList<Toplevel *> list;
@ -268,9 +268,12 @@ AbstractClient* Workspace::findDesktop(bool topmost, int desktop) const
void Workspace::raiseOrLowerClient(AbstractClient *c)
{
if (!c) return;
if (!c || !c->isOnCurrentDesktop()) {
return;
}
const AbstractClient *topmost =
topClientOnDesktop(c->isOnAllDesktops() ? VirtualDesktopManager::self()->current() : c->desktop(),
topClientOnDesktop(VirtualDesktopManager::self()->currentDesktop(),
options->isSeparateScreenFocus() ? c->screen() : -1);
if (c == topmost)

View file

@ -1425,7 +1425,7 @@ void Workspace::slotWindowLower()
if (next && next != active_client)
requestFocus(next, false);
} else {
activateClient(topClientOnDesktop(VirtualDesktopManager::self()->current(), -1));
activateClient(topClientOnDesktop(VirtualDesktopManager::self()->currentDesktop(), -1));
}
}
}

View file

@ -432,7 +432,7 @@ void Workspace::initializeX11()
&& activeClient() == nullptr && should_get_focus.count() == 0) {
// No client activated in manage()
if (new_active_client == nullptr)
new_active_client = topClientOnDesktop(VirtualDesktopManager::self()->current(), -1);
new_active_client = topClientOnDesktop(VirtualDesktopManager::self()->currentDesktop(), -1);
if (new_active_client == nullptr)
new_active_client = findDesktop(true, VirtualDesktopManager::self()->current());
}

View file

@ -52,6 +52,7 @@ class ShortcutDialog;
class Toplevel;
class Unmanaged;
class UserActionsMenu;
class VirtualDesktop;
class X11Client;
class X11EventFilter;
enum class Predicate;
@ -274,8 +275,8 @@ public:
QList<X11Client *> ensureStackingOrder(const QList<X11Client *> &clients) const;
QList<AbstractClient*> ensureStackingOrder(const QList<AbstractClient*> &clients) const;
AbstractClient* topClientOnDesktop(int desktop, int screen, bool unconstrained = false,
bool only_normal = true) const;
AbstractClient *topClientOnDesktop(VirtualDesktop *desktop, int screen, bool unconstrained = false,
bool only_normal = true) const;
AbstractClient* findDesktop(bool topmost, int desktop) const;
void sendClientToDesktop(AbstractClient* c, int desktop, bool dont_activate);
void windowToPreviousDesktop(AbstractClient* c);