diff --git a/autotests/integration/struts_test.cpp b/autotests/integration/struts_test.cpp index 8f7eef3dc3..a439d1fed0 100644 --- a/autotests/integration/struts_test.cpp +++ b/autotests/integration/struts_test.cpp @@ -13,6 +13,7 @@ #include "deleted.h" #include "screenedge.h" #include "screens.h" +#include "virtualdesktops.h" #include "wayland_server.h" #include "workspace.h" #include @@ -132,6 +133,9 @@ void StrutsTest::testWaylandStruts() { // this test verifies that struts on Wayland panels are handled correctly using namespace KWayland::Client; + + VirtualDesktop *desktop = VirtualDesktopManager::self()->currentDesktop(); + // no, struts yet QVERIFY(waylandServer()->clients().isEmpty()); // first screen @@ -151,7 +155,7 @@ void StrutsTest::testWaylandStruts() // combined QCOMPARE(workspace()->clientArea(WorkArea, 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, windowGeometries); // create the panels @@ -201,7 +205,7 @@ void StrutsTest::testWaylandStruts() QTEST(workspace()->clientArea(PlacementArea, 1, 1), "screen1Maximized"); QTEST(workspace()->clientArea(MaximizeArea, 1, 1), "screen1Maximized"); QTEST(workspace()->clientArea(WorkArea, 0, 1), "workArea"); - QTEST(workspace()->restrictedMoveArea(-1), "restrictedMoveArea"); + QTEST(workspace()->restrictedMoveArea(desktop), "restrictedMoveArea"); // delete all surfaces for (auto it = clients.begin(); it != clients.end(); it++) { @@ -210,7 +214,7 @@ void StrutsTest::testWaylandStruts() delete it.key(); QVERIFY(destroyedSpy.wait()); } - QCOMPARE(workspace()->restrictedMoveArea(-1), QRegion()); + QCOMPARE(workspace()->restrictedMoveArea(desktop), QRegion()); } void StrutsTest::testMoveWaylandPanel() @@ -535,6 +539,8 @@ void StrutsTest::testX11Struts() { // this test verifies that struts are applied correctly for X11 windows + VirtualDesktop *desktop = VirtualDesktopManager::self()->currentDesktop(); + // no, struts yet // first screen QCOMPARE(workspace()->clientArea(PlacementArea, 0, 1), QRect(0, 0, 1280, 1024)); @@ -553,7 +559,7 @@ void StrutsTest::testX11Struts() // combined QCOMPARE(workspace()->clientArea(WorkArea, 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 QScopedPointer c(xcb_connect(nullptr, nullptr)); @@ -636,7 +642,7 @@ void StrutsTest::testX11Struts() QTEST(workspace()->clientArea(PlacementArea, 1, 1), "screen1Maximized"); QTEST(workspace()->clientArea(MaximizeArea, 1, 1), "screen1Maximized"); QTEST(workspace()->clientArea(WorkArea, 0, 1), "workArea"); - QTEST(workspace()->restrictedMoveArea(-1), "restrictedMoveArea"); + QTEST(workspace()->restrictedMoveArea(desktop), "restrictedMoveArea"); // and destroy the window again xcb_unmap_window(c.data(), w); @@ -665,7 +671,7 @@ void StrutsTest::testX11Struts() // combined QCOMPARE(workspace()->clientArea(WorkArea, 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() @@ -863,6 +869,8 @@ void StrutsTest::testWindowMoveWithPanelBetweenScreens() // 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. + VirtualDesktop *desktop = VirtualDesktopManager::self()->currentDesktop(); + // left screen must be smaller than right screen const QVector geometries{QRect(0, 282, 1366, 768), QRect(1366, 0, 1680, 1050)}; 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(MaximizeArea, 1, 1), QRect(1390, 0, 1656, 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 diff --git a/src/abstract_client.cpp b/src/abstract_client.cpp index 0f75df8f14..a455435824 100644 --- a/src/abstract_client.cpp +++ b/src/abstract_client.cpp @@ -19,6 +19,7 @@ #include "effects.h" #include "focuschain.h" #include "outline.h" +#include "platform.h" #include "screens.h" #ifdef KWIN_BUILD_TABBOX #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 // point. We bruteforce this by slowly moving the window back to its previous position 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; int requiredPixels; QRect bTitleRect = titleBarRect(transposed, requiredPixels); @@ -1348,7 +1349,7 @@ void AbstractClient::handleInteractiveMoveResize(int x, int y, int x_root, int y setMoveResizeGeometry(moveResizeGeom); 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 availableArea -= strut; // Strut areas bool transposed = false; @@ -3321,7 +3322,7 @@ void AbstractClient::updateGeometryRestoresForFullscreen(int screen) 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()) { return; @@ -3330,8 +3331,6 @@ void AbstractClient::checkWorkspacePosition(QRect oldGeometry, int oldDesktop, Q const int border[4] = { borderLeft(), borderTop(), borderRight(), borderBottom() }; if( !oldGeometry.isValid()) oldGeometry = moveResizeGeometry(); - if( oldDesktop == -2 ) - oldDesktop = desktop(); if (!oldClientGeometry.isValid()) oldClientGeometry = oldGeometry.adjusted(border[Left], border[Top], -border[Right], -border[Bottom]); if (isFullScreen()) { @@ -3362,6 +3361,11 @@ void AbstractClient::checkWorkspacePosition(QRect oldGeometry, int oldDesktop, Q if (!workspace() || workspace()->initializing()) 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. // 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. @@ -3378,7 +3382,8 @@ void AbstractClient::checkWorkspacePosition(QRect oldGeometry, int oldDesktop, Q } } } 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 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 - for (const QRect &r : workspace()->restrictedMoveArea(desktop(), StrutAreaTop)) { + for (const QRect &r : workspace()->restrictedMoveArea(desktop, StrutAreaTop)) { QRect rect = r & newGeomTall; if (!rect.isEmpty()) 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; if (!rect.isEmpty()) 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; if (!rect.isEmpty()) 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; if (!rect.isEmpty()) leftMax = qMax(leftMax, rect.x() + rect.width()); diff --git a/src/abstract_client.h b/src/abstract_client.h index 2c6377499f..608398265d 100644 --- a/src/abstract_client.h +++ b/src/abstract_client.h @@ -579,7 +579,7 @@ public: * The default implementation returns @c false. */ 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 void updateWindowRules(Rules::Types selection); diff --git a/src/internal_client.cpp b/src/internal_client.cpp index 63c60a082c..948f48c933 100644 --- a/src/internal_client.cpp +++ b/src/internal_client.cpp @@ -316,7 +316,7 @@ void InternalClient::updateDecoration(bool check_workspace_pos, bool force) updateShadow(); if (check_workspace_pos) { - checkWorkspacePosition(oldFrameGeometry, -2, oldClientGeometry); + checkWorkspacePosition(oldFrameGeometry, oldClientGeometry); } } diff --git a/src/workspace.cpp b/src/workspace.cpp index edc70598c4..de923d5b95 100644 --- a/src/workspace.cpp +++ b/src/workspace.cpp @@ -209,7 +209,6 @@ void Workspace::init() KSharedConfigPtr config = kwinApp()->config(); Screens *screens = Screens::self(); // get screen support - connect(screens, &Screens::changed, this, &Workspace::desktopResized); screens->setConfig(config); screens->reconfigure(); connect(options, &Options::configChanged, screens, &Screens::reconfigure); @@ -223,30 +222,25 @@ void Workspace::init() FocusChain *focusChain = FocusChain::create(this); connect(this, &Workspace::clientRemoved, focusChain, &FocusChain::remove); 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]() { focusChain->setCurrentDesktop(VirtualDesktopManager::self()->currentDesktop()); }); connect(options, &Options::separateScreenFocusChanged, focusChain, &FocusChain::setSeparateScreenFocus); focusChain->setSeparateScreenFocus(options->isSeparateScreenFocus()); + Platform *platform = kwinApp()->platform(); + connect(platform, &Platform::outputEnabled, this, &Workspace::slotOutputEnabled); + connect(platform, &Platform::outputDisabled, this, &Workspace::slotOutputDisabled); + + const QVector outputs = platform->enabledOutputs(); + for (AbstractOutput *output : outputs) { + slotOutputEnabled(output); + } + // create VirtualDesktopManager and perform dependency injection VirtualDesktopManager *vds = VirtualDesktopManager::self(); - connect(vds, &VirtualDesktopManager::desktopRemoved, this, [this](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); - } - } - }); - - connect(vds, &VirtualDesktopManager::countChanged, this, &Workspace::slotDesktopCountChanged); + connect(vds, &VirtualDesktopManager::desktopCreated, this, &Workspace::slotDesktopAdded); + connect(vds, &VirtualDesktopManager::desktopRemoved, this, &Workspace::slotDesktopRemoved); connect(vds, &VirtualDesktopManager::currentChanged, this, &Workspace::slotCurrentDesktopChanged); vds->setNavigationWrappingAround(options->isRollOverDesktops()); connect(options, &Options::rollOverDesktopsChanged, vds, &VirtualDesktopManager::setNavigationWrappingAround); @@ -1211,24 +1205,42 @@ void Workspace::updateCurrentActivity(const QString &new_activity) #endif } -void Workspace::slotDesktopCountChanged(uint previousCount, uint newCount) +void Workspace::slotOutputEnabled(AbstractOutput *output) { - Q_UNUSED(previousCount) - Placement::self()->reinitCascading(0); - - resetClientAreas(newCount); + connect(output, &AbstractOutput::geometryChanged, this, &Workspace::desktopResized); + desktopResized(); } -void Workspace::resetClientAreas(uint desktopCount) +void Workspace::slotOutputDisabled(AbstractOutput *output) { - // Make it +1, so that it can be accessed as [1..numberofdesktops] - workarea.clear(); - workarea.resize(desktopCount + 1); - restrictedmovearea.clear(); - restrictedmovearea.resize(desktopCount + 1); - screenarea.clear(); + // TODO: Send clients on the given output to other outputs. + disconnect(output, &AbstractOutput::geometryChanged, this, &Workspace::desktopResized); + desktopResized(); +} - 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() @@ -1277,7 +1289,7 @@ void Workspace::sendClientToDesktop(AbstractClient* c, int desk, bool dont_activ } else raiseClient(c); - c->checkWorkspacePosition( QRect(), old_desktop ); + c->checkWorkspacePosition( QRect(), QRect(), VirtualDesktopManager::self()->desktopForX11Id(old_desktop) ); auto transients_stacking_order = ensureStackingOrder(c->transients()); 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. * - * 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 * which is not taken by windows like panels, the top-of-screen menu * etc). * * @see clientArea() */ -void Workspace::updateClientArea(bool force) +void Workspace::updateClientArea() { - const Screens *s = Screens::self(); - int nscreens = s->count(); - const int numberOfDesktops = VirtualDesktopManager::self()->count(); - QVector< QRect > new_wareas(numberOfDesktops + 1); - QVector< StrutRects > new_rmoveareas(numberOfDesktops + 1); - QVector< QVector< QRect > > new_sareas(numberOfDesktops + 1); - QVector< QRect > screens(nscreens); + const QVector outputs = kwinApp()->platform()->enabledOutputs(); + const QVector desktops = VirtualDesktopManager::self()->desktops(); + + QHash workAreas; + QHash restrictedAreas; + QHash> screenAreas; + QRect desktopArea; - for (int i = 0; i < nscreens; i++) { - desktopArea |= s->geometry(i); + for (const AbstractOutput *output : outputs) { + desktopArea |= output->geometry(); } - for (int iS = 0; - iS < nscreens; - iS ++) { - screens [iS] = s->geometry(iS); - } - for (int i = 1; - 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 (const VirtualDesktop *desktop : desktops) { + workAreas[desktop] = desktopArea; + + for (const AbstractOutput *output : outputs) { + screenAreas[desktop][output] = output->geometry(); + } } + for (AbstractClient *client : qAsConst(m_allClients)) { if (!client->hasStrut()) { continue; @@ -2226,77 +2230,38 @@ void Workspace::updateClientArea(bool force) // or having some content appear offscreen (Relatively rare compared to other). bool hasOffscreenStrut = hasOffscreenXineramaStrut(client); - if (client->isOnAllDesktops()) { - for (int i = 1; - i <= numberOfDesktops; - ++i) { - 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; - } - } + const auto vds = client->isOnAllDesktops() ? desktops : client->desktops(); + for (VirtualDesktop *vd : vds) { + if (!hasOffscreenStrut) { + workAreas[vd] &= r; } - } else { - if (!hasOffscreenStrut) - new_wareas[client->desktop()] = new_wareas[client->desktop()].intersected(r); - 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 ])); + restrictedAreas[vd] += strutRegion; + for (AbstractOutput *output : outputs) { + const auto geo = screenAreas[vd][output].intersected(adjustClientArea(client, output->geometry())); // ignore the geometry if it results in the screen getting removed completely 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(); - for (int i = 1; - !changed && i <= numberOfDesktops; - ++i) { - changed |= workarea[i] != new_wareas[i]; - changed |= restrictedmovearea[i] != new_rmoveareas[i]; - 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 (m_workAreas != workAreas || m_restrictedAreas != restrictedAreas || m_screenAreas != screenAreas) { + m_workAreas = workAreas; + m_screenAreas = screenAreas; + + m_oldRestrictedAreas = m_restrictedAreas; + m_restrictedAreas = restrictedAreas; - if (changed) { - workarea = new_wareas; - oldrestrictedmovearea = restrictedmovearea; - restrictedmovearea = new_rmoveareas; - screenarea = new_sareas; if (rootInfo()) { NETRect r; - for (int i = 1; i <= numberOfDesktops; i++) { - r.pos.x = workarea[ i ].x(); - r.pos.y = workarea[ i ].y(); - r.size.width = workarea[ i ].width(); - r.size.height = workarea[ i ].height(); - rootInfo()->setWorkArea(i, r); + for (VirtualDesktop *desktop : desktops) { + const QRect &workArea = m_workAreas[desktop]; + r.pos.x = workArea.x(); + r.pos.y = workArea.y(); + r.size.width = workArea.width(); + r.size.height = workArea.height(); + rootInfo()->setWorkArea(desktop->x11DesktopNumber(), r); } } @@ -2306,70 +2271,83 @@ void Workspace::updateClientArea(bool force) (*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 * geometry minus windows on the dock. Placement algorithms should * 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(); + 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) { - sarea = (!screenarea.isEmpty() - && screen < screenarea[ desktop ].size()) // screens may be missing during KWin initialization or screen config changes - ? screenarea[ desktop ][ screen_number ] - : screens()->geometry(screen_number); - warea = workarea[ desktop ].isNull() - ? screens()->geometry(screen_number) - : workarea[ desktop ]; + workArea = m_workAreas[desktop]; + if (workArea.isNull()) { + workArea = effectiveOutput->geometry(); + } } else { - sarea = (!screenarea.isEmpty() - && screen < screenarea[ desktop ].size()) // screens may be missing during KWin initialization or screen config changes - ? screenarea[ desktop ][ screen ] - : screens()->geometry(screen); - warea = workarea[ desktop ].isNull() - ? QRect(0, 0, displaySize.width(), displaySize.height()) - : workarea[ desktop ]; + workArea = m_workAreas[desktop]; + if (workArea.isNull()) { + workArea = QRect(0, 0, displaySize.width(), displaySize.height()); + } } switch(opt) { case MaximizeArea: case PlacementArea: - return sarea; + return screenArea; case MaximizeFullArea: case FullScreenArea: case MovementArea: case ScreenArea: - if (is_multihead) - return screens()->geometry(screen_number); - else - return screens()->geometry(screen); + return effectiveOutput->geometry(); case WorkArea: if (is_multihead) - return sarea; + return screenArea; else - return warea; + return workArea; case FullArea: 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 @@ -2402,13 +2380,10 @@ QRect Workspace::clientArea(clientAreaOption opt, const AbstractClient *client, return clientArea(opt, client, screens()->number(pos)); } -static QRegion strutsToRegion(int desktop, StrutAreas areas, const QVector &struts) +static QRegion strutsToRegion(StrutAreas areas, const StrutRects &strut) { - if (desktop == NETWinInfo::OnAllDesktops || desktop == 0) - desktop = VirtualDesktopManager::self()->current(); QRegion region; - const StrutRects &rects = struts[desktop]; - for (const StrutRect &rect : rects) { + for (const StrutRect &rect : strut) { if (areas & rect.area()) { region += rect; } @@ -2416,19 +2391,19 @@ static QRegion strutsToRegion(int desktop, StrutAreas areas, const QVector Workspace::previousScreenSizes() const diff --git a/src/workspace.h b/src/workspace.h index b5b287c668..45a6896efd 100644 --- a/src/workspace.h +++ b/src/workspace.h @@ -140,6 +140,7 @@ public: */ 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 AbstractClient* c) 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, 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; @@ -264,7 +265,7 @@ public: // True when performing Workspace::updateClientArea(). // The calls below are valid only in that case. bool inUpdateClientArea() const; - QRegion previousRestrictedMoveArea(int desktop, StrutAreas areas = StrutAreaAll) const; + QRegion previousRestrictedMoveArea(const VirtualDesktop *desktop, StrutAreas areas = StrutAreaAll) const; QVector< QRect > previousScreenSizes() const; int oldDisplayWidth() const; int oldDisplayHeight() const; @@ -480,8 +481,11 @@ private Q_SLOTS: void slotReloadConfig(); void updateCurrentActivity(const QString &new_activity); // virtual desktop handling - void slotDesktopCountChanged(uint previousCount, uint newCount); void slotCurrentDesktopChanged(uint oldDesktop, uint newDesktop); + void slotDesktopAdded(VirtualDesktop *desktop); + void slotDesktopRemoved(VirtualDesktop *desktop); + void slotOutputEnabled(AbstractOutput *output); + void slotOutputDisabled(AbstractOutput *output); Q_SIGNALS: /** @@ -559,8 +563,6 @@ private: //--------------------------------------------------------------------- void closeActivePopup(); - void updateClientArea(bool force); - void resetClientAreas(uint desktopCount); void updateClientVisibilityOnDesktopChange(VirtualDesktop *newDesktop); void activateClientOnNewDesktop(VirtualDesktop *desktop); AbstractClient *findClientToActivateOnDesktop(VirtualDesktop *desktop); @@ -652,14 +654,13 @@ private: QScopedPointer m_startup; QScopedPointer m_colorMapper; - QVector workarea; // Array of workareas for virtual desktops - // Array of restricted areas that window cannot be moved into - QVector restrictedmovearea; - // Array of the previous restricted areas that window cannot be moved into - QVector oldrestrictedmovearea; - QVector< QVector > screenarea; // Array of workareas per xinerama screen for all virtual desktops + QHash m_workAreas; + QHash m_restrictedAreas; + QHash> m_screenAreas; + QVector< QRect > oldscreensizes; // array of previous sizes of xinerama screens QSize olddisplaysize; // previous sizes od displayWidth()/displayHeight() + QHash m_oldRestrictedAreas; int set_active_client_recursion; int block_stacking_updates; // When > 0, stacking updates are temporarily disabled diff --git a/src/x11client.cpp b/src/x11client.cpp index 59cb711a69..16b900bf3f 100644 --- a/src/x11client.cpp +++ b/src/x11client.cpp @@ -1100,7 +1100,7 @@ void X11Client::updateDecoration(bool check_workspace_pos, bool force) destroyDecoration(); updateShadow(); if (check_workspace_pos) - checkWorkspacePosition(oldgeom, -2, oldClientGeom); + checkWorkspacePosition(oldgeom, oldClientGeom); updateInputWindow(); blockGeometryUpdates(false); updateFrameExtents(); diff --git a/src/xdgshellclient.cpp b/src/xdgshellclient.cpp index f6236ebfa0..9d0f2de01e 100644 --- a/src/xdgshellclient.cpp +++ b/src/xdgshellclient.cpp @@ -638,7 +638,7 @@ void XdgToplevelClient::updateDecoration(bool check_workspace_pos, bool force) if (check_workspace_pos) { const QRect oldGeometryRestore = geometryRestore(); setGeometryRestore(frameGeometry()); - checkWorkspacePosition(oldFrameGeometry, -2, oldClientGeometry); + checkWorkspacePosition(oldFrameGeometry, oldClientGeometry); setGeometryRestore(oldGeometryRestore); } }