Port Workspace::clientArea() to VirtualDesktop

This makes Workspace APIs that take virtual desktops more consistent.
icc-effect-5.26.4
Vlad Zahorodnii 2021-08-21 20:46:51 +03:00
parent 5b3c87f105
commit fddbd57d09
8 changed files with 183 additions and 194 deletions

View File

@ -13,6 +13,7 @@
#include "deleted.h" #include "deleted.h"
#include "screenedge.h" #include "screenedge.h"
#include "screens.h" #include "screens.h"
#include "virtualdesktops.h"
#include "wayland_server.h" #include "wayland_server.h"
#include "workspace.h" #include "workspace.h"
#include <kwineffects.h> #include <kwineffects.h>
@ -132,6 +133,9 @@ void StrutsTest::testWaylandStruts()
{ {
// this test verifies that struts on Wayland panels are handled correctly // this test verifies that struts on Wayland panels are handled correctly
using namespace KWayland::Client; using namespace KWayland::Client;
VirtualDesktop *desktop = VirtualDesktopManager::self()->currentDesktop();
// no, struts yet // no, struts yet
QVERIFY(waylandServer()->clients().isEmpty()); QVERIFY(waylandServer()->clients().isEmpty());
// first screen // first screen
@ -151,7 +155,7 @@ void StrutsTest::testWaylandStruts()
// combined // combined
QCOMPARE(workspace()->clientArea(WorkArea, 0, 1), QRect(0, 0, 2560, 1024)); QCOMPARE(workspace()->clientArea(WorkArea, 0, 1), QRect(0, 0, 2560, 1024));
QCOMPARE(workspace()->clientArea(FullArea, 0, 1), QRect(0, 0, 2560, 1024)); QCOMPARE(workspace()->clientArea(FullArea, 0, 1), QRect(0, 0, 2560, 1024));
QCOMPARE(workspace()->restrictedMoveArea(-1), QRegion()); QCOMPARE(workspace()->restrictedMoveArea(desktop), QRegion());
QFETCH(QVector<QRect>, windowGeometries); QFETCH(QVector<QRect>, windowGeometries);
// create the panels // create the panels
@ -201,7 +205,7 @@ void StrutsTest::testWaylandStruts()
QTEST(workspace()->clientArea(PlacementArea, 1, 1), "screen1Maximized"); QTEST(workspace()->clientArea(PlacementArea, 1, 1), "screen1Maximized");
QTEST(workspace()->clientArea(MaximizeArea, 1, 1), "screen1Maximized"); QTEST(workspace()->clientArea(MaximizeArea, 1, 1), "screen1Maximized");
QTEST(workspace()->clientArea(WorkArea, 0, 1), "workArea"); QTEST(workspace()->clientArea(WorkArea, 0, 1), "workArea");
QTEST(workspace()->restrictedMoveArea(-1), "restrictedMoveArea"); QTEST(workspace()->restrictedMoveArea(desktop), "restrictedMoveArea");
// delete all surfaces // delete all surfaces
for (auto it = clients.begin(); it != clients.end(); it++) { for (auto it = clients.begin(); it != clients.end(); it++) {
@ -210,7 +214,7 @@ void StrutsTest::testWaylandStruts()
delete it.key(); delete it.key();
QVERIFY(destroyedSpy.wait()); QVERIFY(destroyedSpy.wait());
} }
QCOMPARE(workspace()->restrictedMoveArea(-1), QRegion()); QCOMPARE(workspace()->restrictedMoveArea(desktop), QRegion());
} }
void StrutsTest::testMoveWaylandPanel() void StrutsTest::testMoveWaylandPanel()
@ -535,6 +539,8 @@ void StrutsTest::testX11Struts()
{ {
// this test verifies that struts are applied correctly for X11 windows // this test verifies that struts are applied correctly for X11 windows
VirtualDesktop *desktop = VirtualDesktopManager::self()->currentDesktop();
// no, struts yet // no, struts yet
// first screen // first screen
QCOMPARE(workspace()->clientArea(PlacementArea, 0, 1), QRect(0, 0, 1280, 1024)); QCOMPARE(workspace()->clientArea(PlacementArea, 0, 1), QRect(0, 0, 1280, 1024));
@ -553,7 +559,7 @@ void StrutsTest::testX11Struts()
// combined // combined
QCOMPARE(workspace()->clientArea(WorkArea, 0, 1), QRect(0, 0, 2560, 1024)); QCOMPARE(workspace()->clientArea(WorkArea, 0, 1), QRect(0, 0, 2560, 1024));
QCOMPARE(workspace()->clientArea(FullArea, 0, 1), QRect(0, 0, 2560, 1024)); QCOMPARE(workspace()->clientArea(FullArea, 0, 1), QRect(0, 0, 2560, 1024));
QCOMPARE(workspace()->restrictedMoveArea(-1), QRegion()); QCOMPARE(workspace()->restrictedMoveArea(desktop), QRegion());
// create an xcb window // create an xcb window
QScopedPointer<xcb_connection_t, XcbConnectionDeleter> c(xcb_connect(nullptr, nullptr)); QScopedPointer<xcb_connection_t, XcbConnectionDeleter> c(xcb_connect(nullptr, nullptr));
@ -636,7 +642,7 @@ void StrutsTest::testX11Struts()
QTEST(workspace()->clientArea(PlacementArea, 1, 1), "screen1Maximized"); QTEST(workspace()->clientArea(PlacementArea, 1, 1), "screen1Maximized");
QTEST(workspace()->clientArea(MaximizeArea, 1, 1), "screen1Maximized"); QTEST(workspace()->clientArea(MaximizeArea, 1, 1), "screen1Maximized");
QTEST(workspace()->clientArea(WorkArea, 0, 1), "workArea"); QTEST(workspace()->clientArea(WorkArea, 0, 1), "workArea");
QTEST(workspace()->restrictedMoveArea(-1), "restrictedMoveArea"); QTEST(workspace()->restrictedMoveArea(desktop), "restrictedMoveArea");
// and destroy the window again // and destroy the window again
xcb_unmap_window(c.data(), w); xcb_unmap_window(c.data(), w);
@ -665,7 +671,7 @@ void StrutsTest::testX11Struts()
// combined // combined
QCOMPARE(workspace()->clientArea(WorkArea, 0, 1), QRect(0, 0, 2560, 1024)); QCOMPARE(workspace()->clientArea(WorkArea, 0, 1), QRect(0, 0, 2560, 1024));
QCOMPARE(workspace()->clientArea(FullArea, 0, 1), QRect(0, 0, 2560, 1024)); QCOMPARE(workspace()->clientArea(FullArea, 0, 1), QRect(0, 0, 2560, 1024));
QCOMPARE(workspace()->restrictedMoveArea(-1), QRegion()); QCOMPARE(workspace()->restrictedMoveArea(desktop), QRegion());
} }
void StrutsTest::test363804() void StrutsTest::test363804()
@ -863,6 +869,8 @@ void StrutsTest::testWindowMoveWithPanelBetweenScreens()
// when moving a window with decorations in a restricted way it should pass from one screen // when moving a window with decorations in a restricted way it should pass from one screen
// to the other even if there is a panel in between. // to the other even if there is a panel in between.
VirtualDesktop *desktop = VirtualDesktopManager::self()->currentDesktop();
// left screen must be smaller than right screen // left screen must be smaller than right screen
const QVector<QRect> geometries{QRect(0, 282, 1366, 768), QRect(1366, 0, 1680, 1050)}; const QVector<QRect> geometries{QRect(0, 282, 1366, 768), QRect(1366, 0, 1680, 1050)};
QMetaObject::invokeMethod(kwinApp()->platform(), "setVirtualOutputs", QMetaObject::invokeMethod(kwinApp()->platform(), "setVirtualOutputs",
@ -926,7 +934,7 @@ void StrutsTest::testWindowMoveWithPanelBetweenScreens()
QCOMPARE(workspace()->clientArea(PlacementArea, 1, 1), QRect(1390, 0, 1656, 1050)); QCOMPARE(workspace()->clientArea(PlacementArea, 1, 1), QRect(1390, 0, 1656, 1050));
QCOMPARE(workspace()->clientArea(MaximizeArea, 1, 1), QRect(1390, 0, 1656, 1050)); QCOMPARE(workspace()->clientArea(MaximizeArea, 1, 1), QRect(1390, 0, 1656, 1050));
QCOMPARE(workspace()->clientArea(WorkArea, 0, 1), QRect(0, 0, 3046, 1050)); QCOMPARE(workspace()->clientArea(WorkArea, 0, 1), QRect(0, 0, 3046, 1050));
QCOMPARE(workspace()->restrictedMoveArea(-1), QRegion(1366, 0, 24, 1050)); QCOMPARE(workspace()->restrictedMoveArea(desktop), QRegion(1366, 0, 24, 1050));
// create another window and try to move it // create another window and try to move it

View File

@ -19,6 +19,7 @@
#include "effects.h" #include "effects.h"
#include "focuschain.h" #include "focuschain.h"
#include "outline.h" #include "outline.h"
#include "platform.h"
#include "screens.h" #include "screens.h"
#ifdef KWIN_BUILD_TABBOX #ifdef KWIN_BUILD_TABBOX
#include "tabbox.h" #include "tabbox.h"
@ -1222,7 +1223,7 @@ void AbstractClient::handleInteractiveMoveResize(int x, int y, int x_root, int y
// the other directions. If not visible enough, move the window to the closest valid // the other directions. If not visible enough, move the window to the closest valid
// point. We bruteforce this by slowly moving the window back to its previous position // point. We bruteforce this by slowly moving the window back to its previous position
QRegion availableArea(workspace()->clientArea(FullArea, this, -1)); // On the screen QRegion availableArea(workspace()->clientArea(FullArea, this, -1)); // On the screen
availableArea -= workspace()->restrictedMoveArea(desktop()); // Strut areas availableArea -= workspace()->restrictedMoveArea(VirtualDesktopManager::self()->currentDesktop());
bool transposed = false; bool transposed = false;
int requiredPixels; int requiredPixels;
QRect bTitleRect = titleBarRect(transposed, requiredPixels); QRect bTitleRect = titleBarRect(transposed, requiredPixels);
@ -1348,7 +1349,7 @@ void AbstractClient::handleInteractiveMoveResize(int x, int y, int x_root, int y
setMoveResizeGeometry(moveResizeGeom); setMoveResizeGeometry(moveResizeGeom);
if (!isUnrestrictedInteractiveMoveResize()) { if (!isUnrestrictedInteractiveMoveResize()) {
const QRegion strut = workspace()->restrictedMoveArea(desktop()); // Strut areas const QRegion strut = workspace()->restrictedMoveArea(VirtualDesktopManager::self()->currentDesktop());
QRegion availableArea(workspace()->clientArea(FullArea, this, -1)); // On the screen QRegion availableArea(workspace()->clientArea(FullArea, this, -1)); // On the screen
availableArea -= strut; // Strut areas availableArea -= strut; // Strut areas
bool transposed = false; bool transposed = false;
@ -3321,7 +3322,7 @@ void AbstractClient::updateGeometryRestoresForFullscreen(int screen)
setGeometryRestore(newGeometryRestore); setGeometryRestore(newGeometryRestore);
} }
void AbstractClient::checkWorkspacePosition(QRect oldGeometry, int oldDesktop, QRect oldClientGeometry) void AbstractClient::checkWorkspacePosition(QRect oldGeometry, QRect oldClientGeometry, const VirtualDesktop *oldDesktop)
{ {
if (isDock() || isDesktop() || !isPlaceable()) { if (isDock() || isDesktop() || !isPlaceable()) {
return; return;
@ -3330,8 +3331,6 @@ void AbstractClient::checkWorkspacePosition(QRect oldGeometry, int oldDesktop, Q
const int border[4] = { borderLeft(), borderTop(), borderRight(), borderBottom() }; const int border[4] = { borderLeft(), borderTop(), borderRight(), borderBottom() };
if( !oldGeometry.isValid()) if( !oldGeometry.isValid())
oldGeometry = moveResizeGeometry(); oldGeometry = moveResizeGeometry();
if( oldDesktop == -2 )
oldDesktop = desktop();
if (!oldClientGeometry.isValid()) if (!oldClientGeometry.isValid())
oldClientGeometry = oldGeometry.adjusted(border[Left], border[Top], -border[Right], -border[Bottom]); oldClientGeometry = oldGeometry.adjusted(border[Left], border[Top], -border[Right], -border[Bottom]);
if (isFullScreen()) { if (isFullScreen()) {
@ -3362,6 +3361,11 @@ void AbstractClient::checkWorkspacePosition(QRect oldGeometry, int oldDesktop, Q
if (!workspace() || workspace()->initializing()) if (!workspace() || workspace()->initializing())
return; return;
VirtualDesktop *desktop = !isOnCurrentDesktop() ? desktops().constLast() : VirtualDesktopManager::self()->currentDesktop();
if (!oldDesktop) {
oldDesktop = desktop;
}
// If the window was touching an edge before but not now move it so it is again. // If the window was touching an edge before but not now move it so it is again.
// Old and new maximums have different starting values so windows on the screen // Old and new maximums have different starting values so windows on the screen
// edge will move when a new strut is placed on the edge. // edge will move when a new strut is placed on the edge.
@ -3378,7 +3382,8 @@ void AbstractClient::checkWorkspacePosition(QRect oldGeometry, int oldDesktop, Q
} }
} }
} else { } else {
oldScreenArea = workspace()->clientArea(ScreenArea, oldGeometry.center(), oldDesktop); const int oldScreen = screens()->number(oldGeometry.center());
oldScreenArea = workspace()->clientArea(ScreenArea, kwinApp()->platform()->findOutput(oldScreen), oldDesktop);
} }
const QRect oldGeomTall = QRect(oldGeometry.x(), oldScreenArea.y(), oldGeometry.width(), oldScreenArea.height()); // Full screen height const QRect oldGeomTall = QRect(oldGeometry.x(), oldScreenArea.y(), oldGeometry.width(), oldScreenArea.height()); // Full screen height
const QRect oldGeomWide = QRect(oldScreenArea.x(), oldGeometry.y(), oldScreenArea.width(), oldGeometry.height()); // Full screen width const QRect oldGeomWide = QRect(oldScreenArea.x(), oldGeometry.y(), oldScreenArea.width(), oldGeometry.height()); // Full screen width
@ -3425,22 +3430,22 @@ void AbstractClient::checkWorkspacePosition(QRect oldGeometry, int oldDesktop, Q
} }
// These 4 compute new bounds // These 4 compute new bounds
for (const QRect &r : workspace()->restrictedMoveArea(desktop(), StrutAreaTop)) { for (const QRect &r : workspace()->restrictedMoveArea(desktop, StrutAreaTop)) {
QRect rect = r & newGeomTall; QRect rect = r & newGeomTall;
if (!rect.isEmpty()) if (!rect.isEmpty())
topMax = qMax(topMax, rect.y() + rect.height()); topMax = qMax(topMax, rect.y() + rect.height());
} }
for (const QRect &r : workspace()->restrictedMoveArea(desktop(), StrutAreaRight)) { for (const QRect &r : workspace()->restrictedMoveArea(desktop, StrutAreaRight)) {
QRect rect = r & newGeomWide; QRect rect = r & newGeomWide;
if (!rect.isEmpty()) if (!rect.isEmpty())
rightMax = qMin(rightMax, rect.x()); rightMax = qMin(rightMax, rect.x());
} }
for (const QRect &r : workspace()->restrictedMoveArea(desktop(), StrutAreaBottom)) { for (const QRect &r : workspace()->restrictedMoveArea(desktop, StrutAreaBottom)) {
QRect rect = r & newGeomTall; QRect rect = r & newGeomTall;
if (!rect.isEmpty()) if (!rect.isEmpty())
bottomMax = qMin(bottomMax, rect.y()); bottomMax = qMin(bottomMax, rect.y());
} }
for (const QRect &r : workspace()->restrictedMoveArea(desktop(), StrutAreaLeft)) { for (const QRect &r : workspace()->restrictedMoveArea(desktop, StrutAreaLeft)) {
QRect rect = r & newGeomWide; QRect rect = r & newGeomWide;
if (!rect.isEmpty()) if (!rect.isEmpty())
leftMax = qMax(leftMax, rect.x() + rect.width()); leftMax = qMax(leftMax, rect.x() + rect.width());

View File

@ -579,7 +579,7 @@ public:
* The default implementation returns @c false. * The default implementation returns @c false.
*/ */
virtual bool dockWantsInput() const; virtual bool dockWantsInput() const;
void checkWorkspacePosition(QRect oldGeometry = QRect(), int oldDesktop = -2, QRect oldClientGeometry = QRect()); void checkWorkspacePosition(QRect oldGeometry = QRect(), QRect oldClientGeometry = QRect(), const VirtualDesktop *oldDesktop = nullptr);
virtual xcb_timestamp_t userTime() const; virtual xcb_timestamp_t userTime() const;
virtual void updateWindowRules(Rules::Types selection); virtual void updateWindowRules(Rules::Types selection);

View File

@ -316,7 +316,7 @@ void InternalClient::updateDecoration(bool check_workspace_pos, bool force)
updateShadow(); updateShadow();
if (check_workspace_pos) { if (check_workspace_pos) {
checkWorkspacePosition(oldFrameGeometry, -2, oldClientGeometry); checkWorkspacePosition(oldFrameGeometry, oldClientGeometry);
} }
} }

View File

@ -209,7 +209,6 @@ void Workspace::init()
KSharedConfigPtr config = kwinApp()->config(); KSharedConfigPtr config = kwinApp()->config();
Screens *screens = Screens::self(); Screens *screens = Screens::self();
// get screen support // get screen support
connect(screens, &Screens::changed, this, &Workspace::desktopResized);
screens->setConfig(config); screens->setConfig(config);
screens->reconfigure(); screens->reconfigure();
connect(options, &Options::configChanged, screens, &Screens::reconfigure); connect(options, &Options::configChanged, screens, &Screens::reconfigure);
@ -223,30 +222,25 @@ void Workspace::init()
FocusChain *focusChain = FocusChain::create(this); FocusChain *focusChain = FocusChain::create(this);
connect(this, &Workspace::clientRemoved, focusChain, &FocusChain::remove); connect(this, &Workspace::clientRemoved, focusChain, &FocusChain::remove);
connect(this, &Workspace::clientActivated, focusChain, &FocusChain::setActiveClient); connect(this, &Workspace::clientActivated, focusChain, &FocusChain::setActiveClient);
connect(VirtualDesktopManager::self(), &VirtualDesktopManager::desktopCreated, focusChain, &FocusChain::addDesktop);
connect(VirtualDesktopManager::self(), &VirtualDesktopManager::desktopRemoved, focusChain, &FocusChain::removeDesktop);
connect(VirtualDesktopManager::self(), &VirtualDesktopManager::currentChanged, focusChain, [focusChain]() { connect(VirtualDesktopManager::self(), &VirtualDesktopManager::currentChanged, focusChain, [focusChain]() {
focusChain->setCurrentDesktop(VirtualDesktopManager::self()->currentDesktop()); focusChain->setCurrentDesktop(VirtualDesktopManager::self()->currentDesktop());
}); });
connect(options, &Options::separateScreenFocusChanged, focusChain, &FocusChain::setSeparateScreenFocus); connect(options, &Options::separateScreenFocusChanged, focusChain, &FocusChain::setSeparateScreenFocus);
focusChain->setSeparateScreenFocus(options->isSeparateScreenFocus()); focusChain->setSeparateScreenFocus(options->isSeparateScreenFocus());
Platform *platform = kwinApp()->platform();
connect(platform, &Platform::outputEnabled, this, &Workspace::slotOutputEnabled);
connect(platform, &Platform::outputDisabled, this, &Workspace::slotOutputDisabled);
const QVector<AbstractOutput *> outputs = platform->enabledOutputs();
for (AbstractOutput *output : outputs) {
slotOutputEnabled(output);
}
// create VirtualDesktopManager and perform dependency injection // create VirtualDesktopManager and perform dependency injection
VirtualDesktopManager *vds = VirtualDesktopManager::self(); VirtualDesktopManager *vds = VirtualDesktopManager::self();
connect(vds, &VirtualDesktopManager::desktopRemoved, this, [this](VirtualDesktop *desktop) { connect(vds, &VirtualDesktopManager::desktopCreated, this, &Workspace::slotDesktopAdded);
for (auto it = m_allClients.constBegin(); it != m_allClients.constEnd(); ++it) { connect(vds, &VirtualDesktopManager::desktopRemoved, this, &Workspace::slotDesktopRemoved);
if (!(*it)->desktops().contains(desktop)) {
continue;
}
if ((*it)->desktops().count() > 1) {
(*it)->leaveDesktop(desktop);
} else {
sendClientToDesktop(*it, qMin(desktop->x11DesktopNumber(), VirtualDesktopManager::self()->count()), true);
}
}
});
connect(vds, &VirtualDesktopManager::countChanged, this, &Workspace::slotDesktopCountChanged);
connect(vds, &VirtualDesktopManager::currentChanged, this, &Workspace::slotCurrentDesktopChanged); connect(vds, &VirtualDesktopManager::currentChanged, this, &Workspace::slotCurrentDesktopChanged);
vds->setNavigationWrappingAround(options->isRollOverDesktops()); vds->setNavigationWrappingAround(options->isRollOverDesktops());
connect(options, &Options::rollOverDesktopsChanged, vds, &VirtualDesktopManager::setNavigationWrappingAround); connect(options, &Options::rollOverDesktopsChanged, vds, &VirtualDesktopManager::setNavigationWrappingAround);
@ -1211,24 +1205,42 @@ void Workspace::updateCurrentActivity(const QString &new_activity)
#endif #endif
} }
void Workspace::slotDesktopCountChanged(uint previousCount, uint newCount) void Workspace::slotOutputEnabled(AbstractOutput *output)
{ {
Q_UNUSED(previousCount) connect(output, &AbstractOutput::geometryChanged, this, &Workspace::desktopResized);
Placement::self()->reinitCascading(0); desktopResized();
resetClientAreas(newCount);
} }
void Workspace::resetClientAreas(uint desktopCount) void Workspace::slotOutputDisabled(AbstractOutput *output)
{ {
// Make it +1, so that it can be accessed as [1..numberofdesktops] // TODO: Send clients on the given output to other outputs.
workarea.clear(); disconnect(output, &AbstractOutput::geometryChanged, this, &Workspace::desktopResized);
workarea.resize(desktopCount + 1); desktopResized();
restrictedmovearea.clear(); }
restrictedmovearea.resize(desktopCount + 1);
screenarea.clear();
updateClientArea(true); void Workspace::slotDesktopAdded(VirtualDesktop *desktop)
{
FocusChain::self()->addDesktop(desktop);
Placement::self()->reinitCascading(0);
updateClientArea();
}
void Workspace::slotDesktopRemoved(VirtualDesktop *desktop)
{
for (auto it = m_allClients.constBegin(); it != m_allClients.constEnd(); ++it) {
if (!(*it)->desktops().contains(desktop)) {
continue;
}
if ((*it)->desktops().count() > 1) {
(*it)->leaveDesktop(desktop);
} else {
sendClientToDesktop(*it, qMin(desktop->x11DesktopNumber(), VirtualDesktopManager::self()->count()), true);
}
}
updateClientArea();
Placement::self()->reinitCascading(0);
FocusChain::self()->removeDesktop(desktop);
} }
void Workspace::selectWmInputEventMask() void Workspace::selectWmInputEventMask()
@ -1277,7 +1289,7 @@ void Workspace::sendClientToDesktop(AbstractClient* c, int desk, bool dont_activ
} else } else
raiseClient(c); raiseClient(c);
c->checkWorkspacePosition( QRect(), old_desktop ); c->checkWorkspacePosition( QRect(), QRect(), VirtualDesktopManager::self()->desktopForX11Id(old_desktop) );
auto transients_stacking_order = ensureStackingOrder(c->transients()); auto transients_stacking_order = ensureStackingOrder(c->transients());
for (auto it = transients_stacking_order.constBegin(); for (auto it = transients_stacking_order.constBegin();
@ -2156,42 +2168,34 @@ QRect Workspace::adjustClientArea(AbstractClient *client, const QRect &area) con
/** /**
* Updates the current client areas according to the current clients. * Updates the current client areas according to the current clients.
* *
* If the area changes or force is @c true, the new areas are propagated to the world.
*
* The client area is the area that is available for clients (that * The client area is the area that is available for clients (that
* which is not taken by windows like panels, the top-of-screen menu * which is not taken by windows like panels, the top-of-screen menu
* etc). * etc).
* *
* @see clientArea() * @see clientArea()
*/ */
void Workspace::updateClientArea(bool force) void Workspace::updateClientArea()
{ {
const Screens *s = Screens::self(); const QVector<AbstractOutput *> outputs = kwinApp()->platform()->enabledOutputs();
int nscreens = s->count(); const QVector<VirtualDesktop *> desktops = VirtualDesktopManager::self()->desktops();
const int numberOfDesktops = VirtualDesktopManager::self()->count();
QVector< QRect > new_wareas(numberOfDesktops + 1); QHash<const VirtualDesktop *, QRect> workAreas;
QVector< StrutRects > new_rmoveareas(numberOfDesktops + 1); QHash<const VirtualDesktop *, StrutRects> restrictedAreas;
QVector< QVector< QRect > > new_sareas(numberOfDesktops + 1); QHash<const VirtualDesktop *, QHash<const AbstractOutput *, QRect>> screenAreas;
QVector< QRect > screens(nscreens);
QRect desktopArea; QRect desktopArea;
for (int i = 0; i < nscreens; i++) { for (const AbstractOutput *output : outputs) {
desktopArea |= s->geometry(i); desktopArea |= output->geometry();
} }
for (int iS = 0;
iS < nscreens; for (const VirtualDesktop *desktop : desktops) {
iS ++) { workAreas[desktop] = desktopArea;
screens [iS] = s->geometry(iS);
} for (const AbstractOutput *output : outputs) {
for (int i = 1; screenAreas[desktop][output] = output->geometry();
i <= numberOfDesktops; }
++i) {
new_wareas[ i ] = desktopArea;
new_sareas[ i ].resize(nscreens);
for (int iS = 0;
iS < nscreens;
iS ++)
new_sareas[ i ][ iS ] = screens[ iS ];
} }
for (AbstractClient *client : qAsConst(m_allClients)) { for (AbstractClient *client : qAsConst(m_allClients)) {
if (!client->hasStrut()) { if (!client->hasStrut()) {
continue; continue;
@ -2226,77 +2230,38 @@ void Workspace::updateClientArea(bool force)
// or having some content appear offscreen (Relatively rare compared to other). // or having some content appear offscreen (Relatively rare compared to other).
bool hasOffscreenStrut = hasOffscreenXineramaStrut(client); bool hasOffscreenStrut = hasOffscreenXineramaStrut(client);
if (client->isOnAllDesktops()) { const auto vds = client->isOnAllDesktops() ? desktops : client->desktops();
for (int i = 1; for (VirtualDesktop *vd : vds) {
i <= numberOfDesktops; if (!hasOffscreenStrut) {
++i) { workAreas[vd] &= r;
if (!hasOffscreenStrut)
new_wareas[ i ] = new_wareas[ i ].intersected(r);
new_rmoveareas[ i ] += strutRegion;
for (int iS = 0;
iS < nscreens;
iS ++) {
const auto geo = new_sareas[ i ][ iS ].intersected(
adjustClientArea(client, screens[ iS ]));
// ignore the geometry if it results in the screen getting removed completely
if (!geo.isEmpty()) {
new_sareas[ i ][ iS ] = geo;
}
}
} }
} else { restrictedAreas[vd] += strutRegion;
if (!hasOffscreenStrut) for (AbstractOutput *output : outputs) {
new_wareas[client->desktop()] = new_wareas[client->desktop()].intersected(r); const auto geo = screenAreas[vd][output].intersected(adjustClientArea(client, output->geometry()));
new_rmoveareas[client->desktop()] += strutRegion;
for (int iS = 0;
iS < nscreens;
iS ++) {
// qDebug() << "adjusting new_sarea: " << screens[ iS ];
const auto geo = new_sareas[client->desktop()][ iS ].intersected(
adjustClientArea(client, screens[ iS ]));
// ignore the geometry if it results in the screen getting removed completely // ignore the geometry if it results in the screen getting removed completely
if (!geo.isEmpty()) { if (!geo.isEmpty()) {
new_sareas[client->desktop()][ iS ] = geo; screenAreas[vd][output] = geo;
} }
} }
} }
} }
#if 0
for (int i = 1;
i <= numberOfDesktops();
++i) {
for (int iS = 0;
iS < nscreens;
iS ++)
qCDebug(KWIN_CORE) << "new_sarea: " << new_sareas[ i ][ iS ];
}
#endif
bool changed = force || screenarea.isEmpty(); if (m_workAreas != workAreas || m_restrictedAreas != restrictedAreas || m_screenAreas != screenAreas) {
for (int i = 1; m_workAreas = workAreas;
!changed && i <= numberOfDesktops; m_screenAreas = screenAreas;
++i) {
changed |= workarea[i] != new_wareas[i]; m_oldRestrictedAreas = m_restrictedAreas;
changed |= restrictedmovearea[i] != new_rmoveareas[i]; m_restrictedAreas = restrictedAreas;
changed |= screenarea[i].size() != new_sareas[i].size();
for (int iS = 0; !changed && iS < nscreens; iS++) {
changed |= new_sareas[i][iS] != screenarea[i][iS];
}
}
if (changed) {
workarea = new_wareas;
oldrestrictedmovearea = restrictedmovearea;
restrictedmovearea = new_rmoveareas;
screenarea = new_sareas;
if (rootInfo()) { if (rootInfo()) {
NETRect r; NETRect r;
for (int i = 1; i <= numberOfDesktops; i++) { for (VirtualDesktop *desktop : desktops) {
r.pos.x = workarea[ i ].x(); const QRect &workArea = m_workAreas[desktop];
r.pos.y = workarea[ i ].y(); r.pos.x = workArea.x();
r.size.width = workarea[ i ].width(); r.pos.y = workArea.y();
r.size.height = workarea[ i ].height(); r.size.width = workArea.width();
rootInfo()->setWorkArea(i, r); r.size.height = workArea.height();
rootInfo()->setWorkArea(desktop->x11DesktopNumber(), r);
} }
} }
@ -2306,70 +2271,83 @@ void Workspace::updateClientArea(bool force)
(*it)->checkWorkspacePosition(); (*it)->checkWorkspacePosition();
} }
oldrestrictedmovearea.clear(); // reset, no longer valid or needed m_oldRestrictedAreas.clear(); // reset, no longer valid or needed
} }
} }
void Workspace::updateClientArea()
{
updateClientArea(false);
}
/** /**
* Returns the area available for clients. This is the desktop * Returns the area available for clients. This is the desktop
* geometry minus windows on the dock. Placement algorithms should * geometry minus windows on the dock. Placement algorithms should
* refer to this rather than Screens::geometry. * refer to this rather than Screens::geometry.
*/ */
QRect Workspace::clientArea(clientAreaOption opt, int screen, int desktop) const QRect Workspace::clientArea(clientAreaOption opt, const AbstractOutput *output, const VirtualDesktop *desktop) const
{ {
if (desktop == NETWinInfo::OnAllDesktops || desktop == 0)
desktop = VirtualDesktopManager::self()->current();
if (screen == -1)
screen = screens()->current();
const QSize displaySize = screens()->displaySize(); const QSize displaySize = screens()->displaySize();
QRect workArea;
QRect sarea, warea; const AbstractOutput *effectiveOutput = output;
if (is_multihead) {
effectiveOutput = kwinApp()->platform()->findOutput(screen_number);
}
QRect screenArea = m_screenAreas[desktop][effectiveOutput];
if (screenArea.isNull()) { // screens may be missing during KWin initialization or screen config changes
screenArea = effectiveOutput->geometry();
}
if (is_multihead) { if (is_multihead) {
sarea = (!screenarea.isEmpty() workArea = m_workAreas[desktop];
&& screen < screenarea[ desktop ].size()) // screens may be missing during KWin initialization or screen config changes if (workArea.isNull()) {
? screenarea[ desktop ][ screen_number ] workArea = effectiveOutput->geometry();
: screens()->geometry(screen_number); }
warea = workarea[ desktop ].isNull()
? screens()->geometry(screen_number)
: workarea[ desktop ];
} else { } else {
sarea = (!screenarea.isEmpty() workArea = m_workAreas[desktop];
&& screen < screenarea[ desktop ].size()) // screens may be missing during KWin initialization or screen config changes if (workArea.isNull()) {
? screenarea[ desktop ][ screen ] workArea = QRect(0, 0, displaySize.width(), displaySize.height());
: screens()->geometry(screen); }
warea = workarea[ desktop ].isNull()
? QRect(0, 0, displaySize.width(), displaySize.height())
: workarea[ desktop ];
} }
switch(opt) { switch(opt) {
case MaximizeArea: case MaximizeArea:
case PlacementArea: case PlacementArea:
return sarea; return screenArea;
case MaximizeFullArea: case MaximizeFullArea:
case FullScreenArea: case FullScreenArea:
case MovementArea: case MovementArea:
case ScreenArea: case ScreenArea:
if (is_multihead) return effectiveOutput->geometry();
return screens()->geometry(screen_number);
else
return screens()->geometry(screen);
case WorkArea: case WorkArea:
if (is_multihead) if (is_multihead)
return sarea; return screenArea;
else else
return warea; return workArea;
case FullArea: case FullArea:
return QRect(0, 0, displaySize.width(), displaySize.height()); return QRect(0, 0, displaySize.width(), displaySize.height());
default:
Q_UNREACHABLE();
} }
abort(); }
QRect Workspace::clientArea(clientAreaOption opt, int screen, int desktop) const
{
VirtualDesktop *virtualDesktop;
AbstractOutput *output;
if (desktop == NETWinInfo::OnAllDesktops || desktop == 0) {
virtualDesktop = VirtualDesktopManager::self()->currentDesktop();
} else {
virtualDesktop = VirtualDesktopManager::self()->desktopForX11Id(desktop);
Q_ASSERT(virtualDesktop);
}
if (screen == -1) {
screen = screens()->current();
}
output = kwinApp()->platform()->findOutput(screen);
Q_ASSERT(output);
return clientArea(opt, output, virtualDesktop);
} }
QRect Workspace::clientArea(clientAreaOption opt, const AbstractOutput *output, int desktop) const QRect Workspace::clientArea(clientAreaOption opt, const AbstractOutput *output, int desktop) const
@ -2402,13 +2380,10 @@ QRect Workspace::clientArea(clientAreaOption opt, const AbstractClient *client,
return clientArea(opt, client, screens()->number(pos)); return clientArea(opt, client, screens()->number(pos));
} }
static QRegion strutsToRegion(int desktop, StrutAreas areas, const QVector<StrutRects> &struts) static QRegion strutsToRegion(StrutAreas areas, const StrutRects &strut)
{ {
if (desktop == NETWinInfo::OnAllDesktops || desktop == 0)
desktop = VirtualDesktopManager::self()->current();
QRegion region; QRegion region;
const StrutRects &rects = struts[desktop]; for (const StrutRect &rect : strut) {
for (const StrutRect &rect : rects) {
if (areas & rect.area()) { if (areas & rect.area()) {
region += rect; region += rect;
} }
@ -2416,19 +2391,19 @@ static QRegion strutsToRegion(int desktop, StrutAreas areas, const QVector<Strut
return region; return region;
} }
QRegion Workspace::restrictedMoveArea(int desktop, StrutAreas areas) const QRegion Workspace::restrictedMoveArea(const VirtualDesktop *desktop, StrutAreas areas) const
{ {
return strutsToRegion(desktop, areas, restrictedmovearea); return strutsToRegion(areas, m_restrictedAreas[desktop]);
} }
bool Workspace::inUpdateClientArea() const bool Workspace::inUpdateClientArea() const
{ {
return !oldrestrictedmovearea.isEmpty(); return !m_oldRestrictedAreas.isEmpty();
} }
QRegion Workspace::previousRestrictedMoveArea(int desktop, StrutAreas areas) const QRegion Workspace::previousRestrictedMoveArea(const VirtualDesktop *desktop, StrutAreas areas) const
{ {
return strutsToRegion(desktop, areas, oldrestrictedmovearea); return strutsToRegion(areas, m_oldRestrictedAreas[desktop]);
} }
QVector< QRect > Workspace::previousScreenSizes() const QVector< QRect > Workspace::previousScreenSizes() const

View File

@ -140,6 +140,7 @@ public:
*/ */
Toplevel *findInternal(QWindow *w) const; Toplevel *findInternal(QWindow *w) const;
QRect clientArea(clientAreaOption, const AbstractOutput *output, const VirtualDesktop *desktop) const;
QRect clientArea(clientAreaOption, const QPoint& p, int desktop) const; QRect clientArea(clientAreaOption, const QPoint& p, int desktop) const;
QRect clientArea(clientAreaOption, const AbstractClient* c) const; QRect clientArea(clientAreaOption, const AbstractClient* c) const;
QRect clientArea(clientAreaOption, const AbstractClient *client, const AbstractOutput *output) const; QRect clientArea(clientAreaOption, const AbstractClient *client, const AbstractOutput *output) const;
@ -148,7 +149,7 @@ public:
QRect clientArea(clientAreaOption, int screen, int desktop) const; QRect clientArea(clientAreaOption, int screen, int desktop) const;
QRect clientArea(clientAreaOption, const AbstractOutput *output, int desktop) const; QRect clientArea(clientAreaOption, const AbstractOutput *output, int desktop) const;
QRegion restrictedMoveArea(int desktop, StrutAreas areas = StrutAreaAll) const; QRegion restrictedMoveArea(const VirtualDesktop *desktop, StrutAreas areas = StrutAreaAll) const;
bool initializing() const; bool initializing() const;
@ -264,7 +265,7 @@ public:
// True when performing Workspace::updateClientArea(). // True when performing Workspace::updateClientArea().
// The calls below are valid only in that case. // The calls below are valid only in that case.
bool inUpdateClientArea() const; bool inUpdateClientArea() const;
QRegion previousRestrictedMoveArea(int desktop, StrutAreas areas = StrutAreaAll) const; QRegion previousRestrictedMoveArea(const VirtualDesktop *desktop, StrutAreas areas = StrutAreaAll) const;
QVector< QRect > previousScreenSizes() const; QVector< QRect > previousScreenSizes() const;
int oldDisplayWidth() const; int oldDisplayWidth() const;
int oldDisplayHeight() const; int oldDisplayHeight() const;
@ -480,8 +481,11 @@ 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 slotDesktopCountChanged(uint previousCount, uint newCount);
void slotCurrentDesktopChanged(uint oldDesktop, uint newDesktop); void slotCurrentDesktopChanged(uint oldDesktop, uint newDesktop);
void slotDesktopAdded(VirtualDesktop *desktop);
void slotDesktopRemoved(VirtualDesktop *desktop);
void slotOutputEnabled(AbstractOutput *output);
void slotOutputDisabled(AbstractOutput *output);
Q_SIGNALS: Q_SIGNALS:
/** /**
@ -559,8 +563,6 @@ private:
//--------------------------------------------------------------------- //---------------------------------------------------------------------
void closeActivePopup(); void closeActivePopup();
void updateClientArea(bool force);
void resetClientAreas(uint desktopCount);
void updateClientVisibilityOnDesktopChange(VirtualDesktop *newDesktop); void updateClientVisibilityOnDesktopChange(VirtualDesktop *newDesktop);
void activateClientOnNewDesktop(VirtualDesktop *desktop); void activateClientOnNewDesktop(VirtualDesktop *desktop);
AbstractClient *findClientToActivateOnDesktop(VirtualDesktop *desktop); AbstractClient *findClientToActivateOnDesktop(VirtualDesktop *desktop);
@ -652,14 +654,13 @@ private:
QScopedPointer<KStartupInfo> m_startup; QScopedPointer<KStartupInfo> m_startup;
QScopedPointer<ColorMapper> m_colorMapper; QScopedPointer<ColorMapper> m_colorMapper;
QVector<QRect> workarea; // Array of workareas for virtual desktops QHash<const VirtualDesktop *, QRect> m_workAreas;
// Array of restricted areas that window cannot be moved into QHash<const VirtualDesktop *, StrutRects> m_restrictedAreas;
QVector<StrutRects> restrictedmovearea; QHash<const VirtualDesktop *, QHash<const AbstractOutput *, QRect>> m_screenAreas;
// Array of the previous restricted areas that window cannot be moved into
QVector<StrutRects> oldrestrictedmovearea;
QVector< QVector<QRect> > screenarea; // Array of workareas per xinerama screen for all virtual desktops
QVector< QRect > oldscreensizes; // array of previous sizes of xinerama screens QVector< QRect > oldscreensizes; // array of previous sizes of xinerama screens
QSize olddisplaysize; // previous sizes od displayWidth()/displayHeight() QSize olddisplaysize; // previous sizes od displayWidth()/displayHeight()
QHash<const VirtualDesktop *, StrutRects> m_oldRestrictedAreas;
int set_active_client_recursion; int set_active_client_recursion;
int block_stacking_updates; // When > 0, stacking updates are temporarily disabled int block_stacking_updates; // When > 0, stacking updates are temporarily disabled

View File

@ -1100,7 +1100,7 @@ void X11Client::updateDecoration(bool check_workspace_pos, bool force)
destroyDecoration(); destroyDecoration();
updateShadow(); updateShadow();
if (check_workspace_pos) if (check_workspace_pos)
checkWorkspacePosition(oldgeom, -2, oldClientGeom); checkWorkspacePosition(oldgeom, oldClientGeom);
updateInputWindow(); updateInputWindow();
blockGeometryUpdates(false); blockGeometryUpdates(false);
updateFrameExtents(); updateFrameExtents();

View File

@ -638,7 +638,7 @@ void XdgToplevelClient::updateDecoration(bool check_workspace_pos, bool force)
if (check_workspace_pos) { if (check_workspace_pos) {
const QRect oldGeometryRestore = geometryRestore(); const QRect oldGeometryRestore = geometryRestore();
setGeometryRestore(frameGeometry()); setGeometryRestore(frameGeometry());
checkWorkspacePosition(oldFrameGeometry, -2, oldClientGeometry); checkWorkspacePosition(oldFrameGeometry, oldClientGeometry);
setGeometryRestore(oldGeometryRestore); setGeometryRestore(oldGeometryRestore);
} }
} }