placementtracker: fix restoring of windows in custom tiles
There were two problems preventing it from working: 1. The placement tracker didn't handle them correctly; now it sets the custom tile mode after moving the window to its location 2. The window code used `output()` instead of `moveResizeOutput()`, which means when KWin just moved the window to a different screen and immediately changes the tile mode afterwards, it would tile the window on the wrong output
This commit is contained in:
parent
14c08422ca
commit
33fe211471
3 changed files with 124 additions and 10 deletions
|
@ -10,6 +10,7 @@
|
||||||
#include "core/outputbackend.h"
|
#include "core/outputbackend.h"
|
||||||
#include "core/outputconfiguration.h"
|
#include "core/outputconfiguration.h"
|
||||||
#include "pointer_input.h"
|
#include "pointer_input.h"
|
||||||
|
#include "tiles/tilemanager.h"
|
||||||
#include "wayland_server.h"
|
#include "wayland_server.h"
|
||||||
#include "window.h"
|
#include "window.h"
|
||||||
#include "workspace.h"
|
#include "workspace.h"
|
||||||
|
@ -42,6 +43,8 @@ private Q_SLOTS:
|
||||||
void testMaximizedWindowRestoredAfterEnablingOutput();
|
void testMaximizedWindowRestoredAfterEnablingOutput();
|
||||||
void testFullScreenWindowRestoredAfterEnablingOutput();
|
void testFullScreenWindowRestoredAfterEnablingOutput();
|
||||||
void testQuickTiledWindowRestoredAfterEnablingOutput();
|
void testQuickTiledWindowRestoredAfterEnablingOutput();
|
||||||
|
void testCustomTiledWindowRestoredAfterEnablingOutput_data();
|
||||||
|
void testCustomTiledWindowRestoredAfterEnablingOutput();
|
||||||
void testWindowRestoredAfterChangingScale();
|
void testWindowRestoredAfterChangingScale();
|
||||||
void testMaximizeStateRestoredAfterEnablingOutput_data();
|
void testMaximizeStateRestoredAfterEnablingOutput_data();
|
||||||
void testMaximizeStateRestoredAfterEnablingOutput();
|
void testMaximizeStateRestoredAfterEnablingOutput();
|
||||||
|
@ -526,6 +529,119 @@ void OutputChangesTest::testQuickTiledWindowRestoredAfterEnablingOutput()
|
||||||
QCOMPARE(window->geometryRestore(), QRectF(1280 + 50, 100, 100, 50));
|
QCOMPARE(window->geometryRestore(), QRectF(1280 + 50, 100, 100, 50));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void OutputChangesTest::testCustomTiledWindowRestoredAfterEnablingOutput_data()
|
||||||
|
{
|
||||||
|
const auto outputs = kwinApp()->outputBackend()->outputs();
|
||||||
|
const size_t tileCount = workspace()->tileManager(outputs[1])->rootTile()->childTiles().size();
|
||||||
|
|
||||||
|
QTest::addColumn<size_t>("tileIndex");
|
||||||
|
for (size_t i = 0; i < tileCount; i++) {
|
||||||
|
QTest::addRow("tile %lu", i) << i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void OutputChangesTest::testCustomTiledWindowRestoredAfterEnablingOutput()
|
||||||
|
{
|
||||||
|
// This test verifies that a custom tiled window will be moved to
|
||||||
|
// its original output and tile when the output is re-enabled
|
||||||
|
|
||||||
|
const auto outputs = kwinApp()->outputBackend()->outputs();
|
||||||
|
|
||||||
|
// start with only one output
|
||||||
|
{
|
||||||
|
OutputConfiguration config;
|
||||||
|
auto changeSet = config.changeSet(outputs[1]);
|
||||||
|
changeSet->enabled = false;
|
||||||
|
workspace()->applyOutputConfiguration(config);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a window.
|
||||||
|
std::unique_ptr<KWayland::Client::Surface> surface(Test::createSurface());
|
||||||
|
std::unique_ptr<Test::XdgToplevel> shellSurface(Test::createXdgToplevelSurface(surface.get()));
|
||||||
|
const auto window = Test::renderAndWaitForShown(surface.get(), QSize(100, 50), Qt::blue);
|
||||||
|
QVERIFY(window);
|
||||||
|
|
||||||
|
// kwin will send a configure event with the actived state.
|
||||||
|
QSignalSpy toplevelConfigureRequestedSpy(shellSurface.get(), &Test::XdgToplevel::configureRequested);
|
||||||
|
QSignalSpy surfaceConfigureRequestedSpy(shellSurface->xdgSurface(), &Test::XdgSurface::configureRequested);
|
||||||
|
QVERIFY(surfaceConfigureRequestedSpy.wait());
|
||||||
|
|
||||||
|
const QRectF originalGeometry = window->moveResizeGeometry();
|
||||||
|
|
||||||
|
// Enable the right output
|
||||||
|
{
|
||||||
|
OutputConfiguration config;
|
||||||
|
auto changeSet = config.changeSet(outputs[1]);
|
||||||
|
changeSet->enabled = true;
|
||||||
|
workspace()->applyOutputConfiguration(config);
|
||||||
|
}
|
||||||
|
|
||||||
|
QFETCH(size_t, tileIndex);
|
||||||
|
const QRectF customTileGeom = workspace()->tileManager(outputs[1])->rootTile()->childTiles()[tileIndex]->windowGeometry();
|
||||||
|
|
||||||
|
// Move the window to the right monitor and put it in the middle tile.
|
||||||
|
QSignalSpy frameGeometryChangedSpy(window, &Window::frameGeometryChanged);
|
||||||
|
window->move(customTileGeom.topLeft() + QPointF(50, 50));
|
||||||
|
const auto geomBeforeTiling = window->moveResizeGeometry();
|
||||||
|
window->setQuickTileMode(QuickTileFlag::Custom, true);
|
||||||
|
|
||||||
|
QVERIFY(surfaceConfigureRequestedSpy.wait());
|
||||||
|
QCOMPARE(toplevelConfigureRequestedSpy.last().at(0).value<QSize>(), customTileGeom.size().toSize());
|
||||||
|
shellSurface->xdgSurface()->ack_configure(surfaceConfigureRequestedSpy.last().at(0).value<quint32>());
|
||||||
|
Test::render(surface.get(), customTileGeom.size().toSize(), Qt::blue);
|
||||||
|
QVERIFY(frameGeometryChangedSpy.wait());
|
||||||
|
|
||||||
|
QCOMPARE(window->frameGeometry(), customTileGeom);
|
||||||
|
QCOMPARE(window->moveResizeGeometry(), customTileGeom);
|
||||||
|
QCOMPARE(window->output(), outputs[1]);
|
||||||
|
QCOMPARE(window->quickTileMode(), QuickTileFlag::Custom);
|
||||||
|
QCOMPARE(window->requestedQuickTileMode(), QuickTileFlag::Custom);
|
||||||
|
QCOMPARE(window->geometryRestore(), geomBeforeTiling);
|
||||||
|
|
||||||
|
// Disable the right output.
|
||||||
|
{
|
||||||
|
OutputConfiguration config;
|
||||||
|
auto changeSet = config.changeSet(outputs[1]);
|
||||||
|
changeSet->enabled = false;
|
||||||
|
workspace()->applyOutputConfiguration(config);
|
||||||
|
}
|
||||||
|
|
||||||
|
// The window will be moved to the left monitor, and the original geometry restored
|
||||||
|
QVERIFY(surfaceConfigureRequestedSpy.wait());
|
||||||
|
QCOMPARE(toplevelConfigureRequestedSpy.last().at(0).value<QSize>(), originalGeometry.size().toSize());
|
||||||
|
shellSurface->xdgSurface()->ack_configure(surfaceConfigureRequestedSpy.last().at(0).value<quint32>());
|
||||||
|
Test::render(surface.get(), originalGeometry.size().toSize(), Qt::blue);
|
||||||
|
QVERIFY(frameGeometryChangedSpy.wait());
|
||||||
|
|
||||||
|
QCOMPARE(window->frameGeometry(), originalGeometry);
|
||||||
|
QCOMPARE(window->moveResizeGeometry(), originalGeometry);
|
||||||
|
QCOMPARE(window->output(), outputs[0]);
|
||||||
|
QCOMPARE(window->quickTileMode(), QuickTileFlag::None);
|
||||||
|
QCOMPARE(window->requestedQuickTileMode(), QuickTileFlag::None);
|
||||||
|
|
||||||
|
// Enable the right monitor again
|
||||||
|
{
|
||||||
|
OutputConfiguration config;
|
||||||
|
auto changeSet = config.changeSet(outputs[1]);
|
||||||
|
changeSet->enabled = true;
|
||||||
|
workspace()->applyOutputConfiguration(config);
|
||||||
|
}
|
||||||
|
|
||||||
|
// The window will be moved back to the right monitor, and put in the correct tile
|
||||||
|
QVERIFY(surfaceConfigureRequestedSpy.wait());
|
||||||
|
QCOMPARE(toplevelConfigureRequestedSpy.last().at(0).value<QSize>(), customTileGeom.size().toSize());
|
||||||
|
shellSurface->xdgSurface()->ack_configure(surfaceConfigureRequestedSpy.last().at(0).value<quint32>());
|
||||||
|
Test::render(surface.get(), customTileGeom.size().toSize(), Qt::blue);
|
||||||
|
QVERIFY(frameGeometryChangedSpy.wait());
|
||||||
|
|
||||||
|
QCOMPARE(window->frameGeometry(), customTileGeom);
|
||||||
|
QCOMPARE(window->moveResizeGeometry(), customTileGeom);
|
||||||
|
QCOMPARE(window->output(), outputs[1]);
|
||||||
|
QCOMPARE(window->quickTileMode(), QuickTileFlag::Custom);
|
||||||
|
QCOMPARE(window->requestedQuickTileMode(), QuickTileFlag::Custom);
|
||||||
|
QCOMPARE(window->geometryRestore(), geomBeforeTiling);
|
||||||
|
}
|
||||||
|
|
||||||
void OutputChangesTest::testWindowRestoredAfterChangingScale()
|
void OutputChangesTest::testWindowRestoredAfterChangingScale()
|
||||||
{
|
{
|
||||||
// This test verifies that a window will be moved to its original position after changing the scale of an output
|
// This test verifies that a window will be moved to its original position after changing the scale of an output
|
||||||
|
|
|
@ -119,10 +119,15 @@ void PlacementTracker::restore(const QString &key)
|
||||||
// setting the desired quick tile mode
|
// setting the desired quick tile mode
|
||||||
// TODO fix this more properly
|
// TODO fix this more properly
|
||||||
window->setQuickTileMode(QuickTileFlag::None, true);
|
window->setQuickTileMode(QuickTileFlag::None, true);
|
||||||
window->setQuickTileMode(newData.quickTile, true);
|
if (newData.quickTile != QuickTileFlag::Custom) {
|
||||||
|
window->setQuickTileMode(newData.quickTile, true);
|
||||||
|
}
|
||||||
window->setMaximize(newData.maximize & MaximizeMode::MaximizeVertical, newData.maximize & MaximizeMode::MaximizeHorizontal);
|
window->setMaximize(newData.maximize & MaximizeMode::MaximizeVertical, newData.maximize & MaximizeMode::MaximizeHorizontal);
|
||||||
window->setFullScreen(newData.fullscreen);
|
window->setFullScreen(newData.fullscreen);
|
||||||
window->moveResize(newData.geometry);
|
window->moveResize(newData.geometry);
|
||||||
|
if (newData.quickTile == QuickTileFlag::Custom) {
|
||||||
|
window->setQuickTileMode(QuickTileFlag::Custom, true);
|
||||||
|
}
|
||||||
window->setGeometryRestore(newData.geometryRestore);
|
window->setGeometryRestore(newData.geometryRestore);
|
||||||
window->setFullscreenGeometryRestore(newData.fullscreenGeometryRestore);
|
window->setFullscreenGeometryRestore(newData.fullscreenGeometryRestore);
|
||||||
m_lastRestoreData[window] = dataForWindow(window);
|
m_lastRestoreData[window] = dataForWindow(window);
|
||||||
|
|
|
@ -3559,19 +3559,12 @@ void Window::setQuickTileMode(QuickTileMode mode, bool keyboard)
|
||||||
}
|
}
|
||||||
} else if (mode == QuickTileMode(QuickTileFlag::Custom)) {
|
} else if (mode == QuickTileMode(QuickTileFlag::Custom)) {
|
||||||
// Custom tileMode is the only one that gets immediately assigned without a roundtrip
|
// Custom tileMode is the only one that gets immediately assigned without a roundtrip
|
||||||
Tile *tile = nullptr;
|
|
||||||
if (keyboard) {
|
|
||||||
tile = workspace()->tileManager(output())->bestTileForPosition(moveResizeGeometry().center());
|
|
||||||
} else {
|
|
||||||
Output *output = workspace()->outputAt(Cursors::self()->mouse()->pos());
|
|
||||||
tile = workspace()->tileManager(output)->bestTileForPosition(Cursors::self()->mouse()->pos());
|
|
||||||
}
|
|
||||||
m_requestedQuickTileMode = mode;
|
m_requestedQuickTileMode = mode;
|
||||||
setTile(tile);
|
setTile(workspace()->tileManager(workspace()->outputAt(whichScreen))->bestTileForPosition(whichScreen));
|
||||||
// Don't go into setTileMode as custom tiles don't go trough configure events
|
// Don't go into setTileMode as custom tiles don't go trough configure events
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
Tile *newTile = workspace()->tileManager(output())->quickTile(m_requestedQuickTileMode);
|
Tile *newTile = workspace()->tileManager(moveResizeOutput())->quickTile(m_requestedQuickTileMode);
|
||||||
if (newTile) {
|
if (newTile) {
|
||||||
moveResize(newTile->absoluteGeometry());
|
moveResize(newTile->absoluteGeometry());
|
||||||
} else if (tile()) {
|
} else if (tile()) {
|
||||||
|
|
Loading…
Reference in a new issue