wayland: Fix windows shrinking when output layout changes
When the output layout changes, the Workspace is going to update the struts and then go through every window and see whether it should be moved or resized. On the other hand, the layer shell windows react to output changes on a timer. Furthermore, it's not synchronized with the workspace rearranging the managed windows. It means that when Workspace::desktopResized() runs, the panel struts can be slightly outdated, i.e. - An output layout change occurs - Workspace::desktopResized() is called but the struts can be wrong - some time later, LayerShellV1Integration::rearrange is called, it fixes layer shell window geometries and struts - after the layer shell integration has finished rearranging the layer shell windows, it calls Workspace::desktopResized(), but the damage had already been caused With the proposed change, the Workspace and the LayerShellV1Integration will rearrange the windows in sync. CCBUG: 482361
This commit is contained in:
parent
9ca738ffec
commit
a489bfa12c
6 changed files with 65 additions and 23 deletions
|
@ -7,6 +7,7 @@
|
|||
#include "kwin_wayland_test.h"
|
||||
|
||||
#include "core/output.h"
|
||||
#include "core/outputconfiguration.h"
|
||||
#include "main.h"
|
||||
#include "pointer_input.h"
|
||||
#include "screenedge.h"
|
||||
|
@ -44,6 +45,7 @@ private Q_SLOTS:
|
|||
void testChangeLayer();
|
||||
void testPlacementArea_data();
|
||||
void testPlacementArea();
|
||||
void testPlacementAreaAfterOutputLayoutChange();
|
||||
void testFill_data();
|
||||
void testFill();
|
||||
void testStack();
|
||||
|
@ -431,6 +433,54 @@ void LayerShellV1WindowTest::testPlacementArea()
|
|||
QVERIFY(Test::waitForWindowClosed(window));
|
||||
}
|
||||
|
||||
void LayerShellV1WindowTest::testPlacementAreaAfterOutputLayoutChange()
|
||||
{
|
||||
// This test verifies that layer shell windows correctly react to output layout changes.
|
||||
|
||||
// The output where the layer surface should be placed.
|
||||
Output *output = workspace()->activeOutput();
|
||||
|
||||
// Create a layer surface with an exclusive zone.
|
||||
std::unique_ptr<KWayland::Client::Surface> surface(Test::createSurface());
|
||||
std::unique_ptr<Test::LayerSurfaceV1> shellSurface(Test::createLayerSurfaceV1(surface.get(), QStringLiteral("dock"), Test::waylandOutput(output->name())));
|
||||
shellSurface->set_layer(Test::LayerShellV1::layer_top);
|
||||
shellSurface->set_anchor(Test::LayerSurfaceV1::anchor_bottom);
|
||||
shellSurface->set_size(100, 50);
|
||||
shellSurface->set_exclusive_edge(Test::LayerSurfaceV1::anchor_bottom);
|
||||
shellSurface->set_exclusive_zone(50);
|
||||
surface->commit(KWayland::Client::Surface::CommitFlag::None);
|
||||
|
||||
// Wait for the compositor to position the layer surface.
|
||||
QSignalSpy configureRequestedSpy(shellSurface.get(), &Test::LayerSurfaceV1::configureRequested);
|
||||
QVERIFY(configureRequestedSpy.wait());
|
||||
shellSurface->ack_configure(configureRequestedSpy.last().at(0).toUInt());
|
||||
Window *window = Test::renderAndWaitForShown(surface.get(), configureRequestedSpy.last().at(1).toSize(), Qt::red);
|
||||
QVERIFY(window);
|
||||
QCOMPARE(workspace()->clientArea(PlacementArea, window), output->geometry().adjusted(0, 0, 0, -50));
|
||||
|
||||
// Move the output 100px down.
|
||||
OutputConfiguration config1;
|
||||
{
|
||||
auto changeSet = config1.changeSet(output);
|
||||
changeSet->pos = output->geometry().topLeft() + QPoint(0, 100);
|
||||
}
|
||||
workspace()->applyOutputConfiguration(config1);
|
||||
QCOMPARE(workspace()->clientArea(PlacementArea, window), output->geometry().adjusted(0, 0, 0, -50));
|
||||
|
||||
// Move the output back to its original position.
|
||||
OutputConfiguration config2;
|
||||
{
|
||||
auto changeSet = config2.changeSet(output);
|
||||
changeSet->pos = output->geometry().topLeft() - QPoint(0, 100);
|
||||
}
|
||||
workspace()->applyOutputConfiguration(config2);
|
||||
QCOMPARE(workspace()->clientArea(PlacementArea, window), output->geometry().adjusted(0, 0, 0, -50));
|
||||
|
||||
// Destroy the window.
|
||||
shellSurface.reset();
|
||||
QVERIFY(Test::waitForWindowClosed(window));
|
||||
}
|
||||
|
||||
void LayerShellV1WindowTest::testFill_data()
|
||||
{
|
||||
QTest::addColumn<int>("anchor");
|
||||
|
|
|
@ -13,8 +13,6 @@
|
|||
#include "wayland_server.h"
|
||||
#include "workspace.h"
|
||||
|
||||
#include <QTimer>
|
||||
|
||||
namespace KWin
|
||||
{
|
||||
|
||||
|
@ -28,9 +26,7 @@ LayerShellV1Integration::LayerShellV1Integration(QObject *parent)
|
|||
connect(shell, &LayerShellV1Interface::surfaceCreated,
|
||||
this, &LayerShellV1Integration::createWindow);
|
||||
|
||||
m_rearrangeTimer = new QTimer(this);
|
||||
m_rearrangeTimer->setSingleShot(true);
|
||||
connect(m_rearrangeTimer, &QTimer::timeout, this, &LayerShellV1Integration::rearrange);
|
||||
connect(workspace(), &Workspace::aboutToUpdateClientArea, this, &LayerShellV1Integration::rearrange);
|
||||
}
|
||||
|
||||
void LayerShellV1Integration::createWindow(LayerSurfaceV1Interface *shellSurface)
|
||||
|
@ -198,21 +194,10 @@ static void rearrangeOutput(Output *output)
|
|||
|
||||
void LayerShellV1Integration::rearrange()
|
||||
{
|
||||
m_rearrangeTimer->stop();
|
||||
|
||||
const QList<Output *> outputs = workspace()->outputs();
|
||||
for (Output *output : outputs) {
|
||||
rearrangeOutput(output);
|
||||
}
|
||||
|
||||
if (workspace()) {
|
||||
workspace()->updateClientArea();
|
||||
}
|
||||
}
|
||||
|
||||
void LayerShellV1Integration::scheduleRearrange()
|
||||
{
|
||||
m_rearrangeTimer->start();
|
||||
}
|
||||
|
||||
} // namespace KWin
|
||||
|
|
|
@ -21,14 +21,10 @@ public:
|
|||
explicit LayerShellV1Integration(QObject *parent = nullptr);
|
||||
|
||||
void rearrange();
|
||||
void scheduleRearrange();
|
||||
|
||||
void createWindow(LayerSurfaceV1Interface *shellSurface);
|
||||
void recreateWindow(LayerSurfaceV1Interface *shellSurface);
|
||||
void destroyWindow(LayerSurfaceV1Interface *shellSurface);
|
||||
|
||||
private:
|
||||
QTimer *m_rearrangeTimer;
|
||||
};
|
||||
|
||||
} // namespace KWin
|
||||
|
|
|
@ -52,8 +52,6 @@ LayerShellV1Window::LayerShellV1Window(LayerSurfaceV1Interface *shellSurface,
|
|||
connect(shellSurface->surface(), &SurfaceInterface::aboutToBeDestroyed,
|
||||
this, &LayerShellV1Window::destroyWindow);
|
||||
|
||||
connect(output, &Output::geometryChanged,
|
||||
this, &LayerShellV1Window::scheduleRearrange);
|
||||
connect(output, &Output::enabledChanged,
|
||||
this, &LayerShellV1Window::handleOutputEnabledChanged);
|
||||
|
||||
|
@ -90,7 +88,7 @@ Output *LayerShellV1Window::desiredOutput() const
|
|||
|
||||
void LayerShellV1Window::scheduleRearrange()
|
||||
{
|
||||
m_integration->scheduleRearrange();
|
||||
workspace()->scheduleUpdateClientArea();
|
||||
}
|
||||
|
||||
WindowType LayerShellV1Window::windowType() const
|
||||
|
|
|
@ -205,9 +205,11 @@ void Workspace::init()
|
|||
vds->setCurrent(m_initialDesktop);
|
||||
|
||||
reconfigureTimer.setSingleShot(true);
|
||||
m_updateClientAreaTimer.setSingleShot(true);
|
||||
updateToolWindowsTimer.setSingleShot(true);
|
||||
|
||||
connect(&reconfigureTimer, &QTimer::timeout, this, &Workspace::slotReconfigure);
|
||||
connect(&m_updateClientAreaTimer, &QTimer::timeout, this, &Workspace::updateClientArea);
|
||||
connect(&updateToolWindowsTimer, &QTimer::timeout, this, &Workspace::slotUpdateToolWindows);
|
||||
|
||||
// TODO: do we really need to reconfigure everything when fonts change?
|
||||
|
@ -2347,6 +2349,11 @@ QRectF Workspace::adjustClientArea(Window *window, const QRectF &area) const
|
|||
return adjustedArea;
|
||||
}
|
||||
|
||||
void Workspace::scheduleUpdateClientArea()
|
||||
{
|
||||
m_updateClientAreaTimer.start(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the current client areas according to the current windows.
|
||||
*
|
||||
|
@ -2358,6 +2365,9 @@ QRectF Workspace::adjustClientArea(Window *window, const QRectF &area) const
|
|||
*/
|
||||
void Workspace::updateClientArea()
|
||||
{
|
||||
Q_EMIT aboutToUpdateClientArea();
|
||||
m_updateClientAreaTimer.stop();
|
||||
|
||||
const QList<VirtualDesktop *> desktops = VirtualDesktopManager::self()->desktops();
|
||||
|
||||
QHash<const VirtualDesktop *, QRectF> workAreas;
|
||||
|
|
|
@ -530,6 +530,7 @@ public Q_SLOTS:
|
|||
void setupWindowShortcutDone(bool);
|
||||
|
||||
void updateClientArea();
|
||||
void scheduleUpdateClientArea();
|
||||
|
||||
private Q_SLOTS:
|
||||
void desktopResized();
|
||||
|
@ -580,6 +581,7 @@ Q_SIGNALS:
|
|||
* or lowered
|
||||
*/
|
||||
void stackingOrderChanged();
|
||||
void aboutToUpdateClientArea();
|
||||
|
||||
private:
|
||||
void init();
|
||||
|
@ -706,6 +708,7 @@ private:
|
|||
|
||||
// Timer to collect requests for 'reconfigure'
|
||||
QTimer reconfigureTimer;
|
||||
QTimer m_updateClientAreaTimer;
|
||||
|
||||
QTimer updateToolWindowsTimer;
|
||||
|
||||
|
|
Loading…
Reference in a new issue