[wayland] Asyncronously update maximise flags
Summary: A window maximising is an async operation. We work out what size we want the client to be, then request the client to update. The window isn't really maximised until we get that new buffer with the new size. This patch splits the requested, pending and current state, updating as appropriate. Things are a bit complex with things like borders. Technically we shouldn't update them till we get a response, but we also need to have the correct geometry of the full size window in our request. For now they behave as before, updating when we request the change. X code is untouched. This hopefully fixes maximise animations on wayland as now we update the geometry before emitting maximisedChanged. Test Plan: Maximised a window with the button and double clicking title bar. I get only the following events on maximise/restore: 19:51:39.156 KWin::EffectsHandlerImpl::slotGeometryShapeChanged geometry shape changed QRect(47,24 640x509) QRect(0,0 716x573) 19:51:39.157 KWin::EffectsHandlerImpl::slotClientMaximized slot client maximised true true 19:51:40.522 KWin::EffectsHandlerImpl::slotGeometryShapeChanged geometry shape changed QRect(0,0 716x573) QRect(47,24 640x509) 19:51:40.522 KWin::EffectsHandlerImpl::slotClientMaximized slot client maximised false false BUG: 382698 Reviewers: #kwin, romangg Reviewed By: #kwin, romangg Subscribers: romangg, zzag, kwin Tags: #kwin Differential Revision: https://phabricator.kde.org/D15150
This commit is contained in:
parent
65b8ba1770
commit
e327cce4bc
3 changed files with 53 additions and 19 deletions
|
@ -671,6 +671,15 @@ void TestShellClient::testMaximizedToFullscreen()
|
||||||
}
|
}
|
||||||
QVERIFY(sizeChangeRequestedSpy.wait());
|
QVERIFY(sizeChangeRequestedSpy.wait());
|
||||||
QCOMPARE(sizeChangeRequestedSpy.count(), 1);
|
QCOMPARE(sizeChangeRequestedSpy.count(), 1);
|
||||||
|
|
||||||
|
if (xdgShellSurface) {
|
||||||
|
for (const auto &it: configureRequestedSpy) {
|
||||||
|
xdgShellSurface->ackConfigure(it[2].toInt());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Test::render(surface.data(), sizeChangeRequestedSpy.last().first().toSize(), Qt::red);
|
||||||
|
QVERIFY(geometryChangedSpy.wait());
|
||||||
|
|
||||||
QCOMPARE(c->maximizeMode(), MaximizeFull);
|
QCOMPARE(c->maximizeMode(), MaximizeFull);
|
||||||
QCOMPARE(geometryChangedSpy.isEmpty(), false);
|
QCOMPARE(geometryChangedSpy.isEmpty(), false);
|
||||||
geometryChangedSpy.clear();
|
geometryChangedSpy.clear();
|
||||||
|
@ -690,7 +699,6 @@ void TestShellClient::testMaximizedToFullscreen()
|
||||||
QCOMPARE(sizeChangeRequestedSpy.last().first().toSize(), QSize(screens()->size(0)));
|
QCOMPARE(sizeChangeRequestedSpy.last().first().toSize(), QSize(screens()->size(0)));
|
||||||
// TODO: should switch to fullscreen once it's updated
|
// TODO: should switch to fullscreen once it's updated
|
||||||
QVERIFY(c->isFullScreen());
|
QVERIFY(c->isFullScreen());
|
||||||
QCOMPARE(c->clientSize(), QSize(100, 50));
|
|
||||||
QVERIFY(geometryChangedSpy.isEmpty());
|
QVERIFY(geometryChangedSpy.isEmpty());
|
||||||
|
|
||||||
if (xdgShellSurface) {
|
if (xdgShellSurface) {
|
||||||
|
@ -698,7 +706,6 @@ void TestShellClient::testMaximizedToFullscreen()
|
||||||
xdgShellSurface->ackConfigure(it[2].toInt());
|
xdgShellSurface->ackConfigure(it[2].toInt());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// render at the new size
|
// render at the new size
|
||||||
Test::render(surface.data(), sizeChangeRequestedSpy.last().first().toSize(), Qt::red);
|
Test::render(surface.data(), sizeChangeRequestedSpy.last().first().toSize(), Qt::red);
|
||||||
QVERIFY(geometryChangedSpy.wait());
|
QVERIFY(geometryChangedSpy.wait());
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
This file is part of the KDE project.
|
This file is part of the KDE project.
|
||||||
|
|
||||||
Copyright (C) 2015 Martin Gräßlin <mgraesslin@kde.org>
|
Copyright (C) 2015 Martin Gräßlin <mgraesslin@kde.org>
|
||||||
|
Copyright (C) 2018 David Edmundson <davidedmundson@kde.org>
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify
|
This program is free software; you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
||||||
|
@ -606,6 +607,7 @@ void ShellClient::setGeometry(int x, int y, int w, int h, ForceGeometry_t force)
|
||||||
if (QSize(w, h) == geom.size() && !isWaitingForMoveResizeSync()) {
|
if (QSize(w, h) == geom.size() && !isWaitingForMoveResizeSync()) {
|
||||||
// size didn't change, update directly
|
// size didn't change, update directly
|
||||||
doSetGeometry(QRect(x, y, w, h));
|
doSetGeometry(QRect(x, y, w, h));
|
||||||
|
updateMaximizeMode(m_requestedMaximizeMode);
|
||||||
} else {
|
} else {
|
||||||
// size did change, Client needs to provide a new buffer
|
// size did change, Client needs to provide a new buffer
|
||||||
requestGeometry(QRect(x, y, w, h));
|
requestGeometry(QRect(x, y, w, h));
|
||||||
|
@ -826,30 +828,30 @@ void ShellClient::changeMaximize(bool horizontal, bool vertical, bool adjust)
|
||||||
workspace()->clientArea(MaximizeArea, Cursor::pos(), desktop()) :
|
workspace()->clientArea(MaximizeArea, Cursor::pos(), desktop()) :
|
||||||
workspace()->clientArea(MaximizeArea, this);
|
workspace()->clientArea(MaximizeArea, this);
|
||||||
|
|
||||||
MaximizeMode oldMode = m_maximizeMode;
|
MaximizeMode oldMode = m_requestedMaximizeMode;
|
||||||
StackingUpdatesBlocker blocker(workspace());
|
StackingUpdatesBlocker blocker(workspace());
|
||||||
RequestGeometryBlocker geometryBlocker(this);
|
RequestGeometryBlocker geometryBlocker(this);
|
||||||
// 'adjust == true' means to update the size only, e.g. after changing workspace size
|
// 'adjust == true' means to update the size only, e.g. after changing workspace size
|
||||||
if (!adjust) {
|
if (!adjust) {
|
||||||
if (vertical)
|
if (vertical)
|
||||||
m_maximizeMode = MaximizeMode(m_maximizeMode ^ MaximizeVertical);
|
m_requestedMaximizeMode = MaximizeMode(m_requestedMaximizeMode ^ MaximizeVertical);
|
||||||
if (horizontal)
|
if (horizontal)
|
||||||
m_maximizeMode = MaximizeMode(m_maximizeMode ^ MaximizeHorizontal);
|
m_requestedMaximizeMode = MaximizeMode(m_requestedMaximizeMode ^ MaximizeHorizontal);
|
||||||
}
|
}
|
||||||
// TODO: add more checks as in Client
|
// TODO: add more checks as in Client
|
||||||
|
|
||||||
// call into decoration update borders
|
// call into decoration update borders
|
||||||
if (isDecorated() && decoration()->client() && !(options->borderlessMaximizedWindows() && m_maximizeMode == KWin::MaximizeFull)) {
|
if (isDecorated() && decoration()->client() && !(options->borderlessMaximizedWindows() && m_requestedMaximizeMode == KWin::MaximizeFull)) {
|
||||||
changeMaximizeRecursion = true;
|
changeMaximizeRecursion = true;
|
||||||
const auto c = decoration()->client().data();
|
const auto c = decoration()->client().data();
|
||||||
if ((m_maximizeMode & MaximizeVertical) != (oldMode & MaximizeVertical)) {
|
if ((m_requestedMaximizeMode & MaximizeVertical) != (oldMode & MaximizeVertical)) {
|
||||||
emit c->maximizedVerticallyChanged(m_maximizeMode & MaximizeVertical);
|
emit c->maximizedVerticallyChanged(m_requestedMaximizeMode & MaximizeVertical);
|
||||||
}
|
}
|
||||||
if ((m_maximizeMode & MaximizeHorizontal) != (oldMode & MaximizeHorizontal)) {
|
if ((m_requestedMaximizeMode & MaximizeHorizontal) != (oldMode & MaximizeHorizontal)) {
|
||||||
emit c->maximizedHorizontallyChanged(m_maximizeMode & MaximizeHorizontal);
|
emit c->maximizedHorizontallyChanged(m_requestedMaximizeMode & MaximizeHorizontal);
|
||||||
}
|
}
|
||||||
if ((m_maximizeMode == MaximizeFull) != (oldMode == MaximizeFull)) {
|
if ((m_requestedMaximizeMode == MaximizeFull) != (oldMode == MaximizeFull)) {
|
||||||
emit c->maximizedChanged(m_maximizeMode & MaximizeFull);
|
emit c->maximizedChanged(m_requestedMaximizeMode & MaximizeFull);
|
||||||
}
|
}
|
||||||
changeMaximizeRecursion = false;
|
changeMaximizeRecursion = false;
|
||||||
}
|
}
|
||||||
|
@ -858,7 +860,7 @@ void ShellClient::changeMaximize(bool horizontal, bool vertical, bool adjust)
|
||||||
// triggers a maximize change.
|
// triggers a maximize change.
|
||||||
// The next setNoBorder interation will exit since there's no change but the first recursion pullutes the restore geometry
|
// The next setNoBorder interation will exit since there's no change but the first recursion pullutes the restore geometry
|
||||||
changeMaximizeRecursion = true;
|
changeMaximizeRecursion = true;
|
||||||
setNoBorder(rules()->checkNoBorder(m_maximizeMode == MaximizeFull));
|
setNoBorder(rules()->checkNoBorder(m_requestedMaximizeMode == MaximizeFull));
|
||||||
changeMaximizeRecursion = false;
|
changeMaximizeRecursion = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -870,15 +872,15 @@ void ShellClient::changeMaximize(bool horizontal, bool vertical, bool adjust)
|
||||||
// Not restoring on the same screen
|
// Not restoring on the same screen
|
||||||
// TODO: The following doesn't work for some reason
|
// TODO: The following doesn't work for some reason
|
||||||
//quick_tile_mode = QuickTileNone; // And exit quick tile mode manually
|
//quick_tile_mode = QuickTileNone; // And exit quick tile mode manually
|
||||||
} else if ((oldMode == MaximizeVertical && m_maximizeMode == MaximizeRestore) ||
|
} else if ((oldMode == MaximizeVertical && m_requestedMaximizeMode == MaximizeRestore) ||
|
||||||
(oldMode == MaximizeFull && m_maximizeMode == MaximizeHorizontal)) {
|
(oldMode == MaximizeFull && m_requestedMaximizeMode == MaximizeHorizontal)) {
|
||||||
// Modifying geometry of a tiled window
|
// Modifying geometry of a tiled window
|
||||||
updateQuickTileMode(QuickTileFlag::None); // Exit quick tile mode without restoring geometry
|
updateQuickTileMode(QuickTileFlag::None); // Exit quick tile mode without restoring geometry
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: check rules
|
// TODO: check rules
|
||||||
if (m_maximizeMode == MaximizeFull) {
|
if (m_requestedMaximizeMode == MaximizeFull) {
|
||||||
m_geomMaximizeRestore = geometry();
|
m_geomMaximizeRestore = geometry();
|
||||||
// TODO: Client has more checks
|
// TODO: Client has more checks
|
||||||
if (options->electricBorderMaximize()) {
|
if (options->electricBorderMaximize()) {
|
||||||
|
@ -892,7 +894,7 @@ void ShellClient::changeMaximize(bool horizontal, bool vertical, bool adjust)
|
||||||
setGeometry(workspace()->clientArea(MaximizeArea, this));
|
setGeometry(workspace()->clientArea(MaximizeArea, this));
|
||||||
workspace()->raiseClient(this);
|
workspace()->raiseClient(this);
|
||||||
} else {
|
} else {
|
||||||
if (m_maximizeMode == MaximizeRestore) {
|
if (m_requestedMaximizeMode == MaximizeRestore) {
|
||||||
updateQuickTileMode(QuickTileFlag::None);
|
updateQuickTileMode(QuickTileFlag::None);
|
||||||
}
|
}
|
||||||
if (quickTileMode() != oldQuickTileMode) {
|
if (quickTileMode() != oldQuickTileMode) {
|
||||||
|
@ -1174,6 +1176,7 @@ void ShellClient::requestGeometry(const QRect &rect)
|
||||||
}
|
}
|
||||||
PendingConfigureRequest configureRequest;
|
PendingConfigureRequest configureRequest;
|
||||||
configureRequest.positionAfterResize = rect.topLeft();
|
configureRequest.positionAfterResize = rect.topLeft();
|
||||||
|
configureRequest.maximizeMode = m_requestedMaximizeMode;
|
||||||
|
|
||||||
const QSize size = rect.size() - QSize(borderLeft() + borderRight(), borderTop() + borderBottom());
|
const QSize size = rect.size() - QSize(borderLeft() + borderRight(), borderTop() + borderBottom());
|
||||||
if (m_shellSurface) {
|
if (m_shellSurface) {
|
||||||
|
@ -1202,6 +1205,7 @@ void ShellClient::requestGeometry(const QRect &rect)
|
||||||
void ShellClient::updatePendingGeometry()
|
void ShellClient::updatePendingGeometry()
|
||||||
{
|
{
|
||||||
QPoint position = geom.topLeft();
|
QPoint position = geom.topLeft();
|
||||||
|
MaximizeMode maximizeMode = m_maximizeMode;
|
||||||
for (auto it = m_pendingConfigureRequests.begin(); it != m_pendingConfigureRequests.end(); it++) {
|
for (auto it = m_pendingConfigureRequests.begin(); it != m_pendingConfigureRequests.end(); it++) {
|
||||||
if (it->serialId > m_lastAckedConfigureRequest) {
|
if (it->serialId > m_lastAckedConfigureRequest) {
|
||||||
//this serial is not acked yet, therefore we know all future serials are not
|
//this serial is not acked yet, therefore we know all future serials are not
|
||||||
|
@ -1212,6 +1216,7 @@ void ShellClient::updatePendingGeometry()
|
||||||
addLayerRepaint(geometry());
|
addLayerRepaint(geometry());
|
||||||
}
|
}
|
||||||
position = it->positionAfterResize;
|
position = it->positionAfterResize;
|
||||||
|
maximizeMode = it->maximizeMode;
|
||||||
|
|
||||||
m_pendingConfigureRequests.erase(m_pendingConfigureRequests.begin(), ++it);
|
m_pendingConfigureRequests.erase(m_pendingConfigureRequests.begin(), ++it);
|
||||||
break;
|
break;
|
||||||
|
@ -1219,6 +1224,7 @@ void ShellClient::updatePendingGeometry()
|
||||||
//else serialId < m_lastAckedConfigureRequest and the state is now irrelevant and can be ignored
|
//else serialId < m_lastAckedConfigureRequest and the state is now irrelevant and can be ignored
|
||||||
}
|
}
|
||||||
doSetGeometry(QRect(position, m_clientSize + QSize(borderLeft() + borderRight(), borderTop() + borderBottom())));
|
doSetGeometry(QRect(position, m_clientSize + QSize(borderLeft() + borderRight(), borderTop() + borderBottom())));
|
||||||
|
updateMaximizeMode(maximizeMode);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShellClient::clientFullScreenChanged(bool fullScreen)
|
void ShellClient::clientFullScreenChanged(bool fullScreen)
|
||||||
|
@ -1484,6 +1490,20 @@ void ShellClient::updateColorScheme()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ShellClient::updateMaximizeMode(MaximizeMode maximizeMode)
|
||||||
|
{
|
||||||
|
if (maximizeMode == m_maximizeMode) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool horizontalChanged = (maximizeMode & MaximizeHorizontal) != (m_maximizeMode & MaximizeHorizontal);
|
||||||
|
bool verticalChanged = (maximizeMode & MaximizeVertical) != (m_maximizeMode & MaximizeVertical);
|
||||||
|
m_maximizeMode = maximizeMode;
|
||||||
|
|
||||||
|
emit clientMaximizedStateChanged(this, m_maximizeMode);
|
||||||
|
emit clientMaximizedStateChanged(this, horizontalChanged, verticalChanged);
|
||||||
|
}
|
||||||
|
|
||||||
bool ShellClient::hasStrut() const
|
bool ShellClient::hasStrut() const
|
||||||
{
|
{
|
||||||
if (!isShown(true)) {
|
if (!isShown(true)) {
|
||||||
|
@ -1636,7 +1656,7 @@ KWayland::Server::XdgShellSurfaceInterface::States ShellClient::xdgSurfaceStates
|
||||||
if (isFullScreen()) {
|
if (isFullScreen()) {
|
||||||
states |= XdgShellSurfaceInterface::State::Fullscreen;
|
states |= XdgShellSurfaceInterface::State::Fullscreen;
|
||||||
}
|
}
|
||||||
if (maximizeMode() == MaximizeMode::MaximizeFull) {
|
if (m_requestedMaximizeMode == MaximizeMode::MaximizeFull) {
|
||||||
states |= XdgShellSurfaceInterface::State::Maximized;
|
states |= XdgShellSurfaceInterface::State::Maximized;
|
||||||
}
|
}
|
||||||
if (isResize()) {
|
if (isResize()) {
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
This file is part of the KDE project.
|
This file is part of the KDE project.
|
||||||
|
|
||||||
Copyright (C) 2015 Martin Gräßlin <mgraesslin@kde.org>
|
Copyright (C) 2015 Martin Gräßlin <mgraesslin@kde.org>
|
||||||
|
Copyright (C) 2018 David Edmundson <davidedmundson@kde.org>
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify
|
This program is free software; you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
||||||
|
@ -202,6 +203,7 @@ private:
|
||||||
void updateClientOutputs();
|
void updateClientOutputs();
|
||||||
KWayland::Server::XdgShellSurfaceInterface::States xdgSurfaceStates() const;
|
KWayland::Server::XdgShellSurfaceInterface::States xdgSurfaceStates() const;
|
||||||
void updateShowOnScreenEdge();
|
void updateShowOnScreenEdge();
|
||||||
|
void updateMaximizeMode(MaximizeMode maximizeMode);
|
||||||
// called on surface commit and processes all m_pendingConfigureRequests up to m_lastAckedConfigureReqest
|
// called on surface commit and processes all m_pendingConfigureRequests up to m_lastAckedConfigureReqest
|
||||||
void updatePendingGeometry();
|
void updatePendingGeometry();
|
||||||
static void deleteClient(ShellClient *c);
|
static void deleteClient(ShellClient *c);
|
||||||
|
@ -217,17 +219,22 @@ private:
|
||||||
quint32 serialId = 0;
|
quint32 serialId = 0;
|
||||||
// position to apply after a resize operation has been completed
|
// position to apply after a resize operation has been completed
|
||||||
QPoint positionAfterResize;
|
QPoint positionAfterResize;
|
||||||
|
MaximizeMode maximizeMode;
|
||||||
};
|
};
|
||||||
QVector<PendingConfigureRequest> m_pendingConfigureRequests;
|
QVector<PendingConfigureRequest> m_pendingConfigureRequests;
|
||||||
quint32 m_lastAckedConfigureRequest = 0;
|
quint32 m_lastAckedConfigureRequest = 0;
|
||||||
|
|
||||||
|
//mode in use by the current buffer
|
||||||
|
MaximizeMode m_maximizeMode = MaximizeRestore;
|
||||||
|
//mode we currently want to be, could be pending on client updating, could be not sent yet
|
||||||
|
MaximizeMode m_requestedMaximizeMode = MaximizeRestore;
|
||||||
|
|
||||||
QRect m_geomFsRestore; //size and position of the window before it was set to fullscreen
|
QRect m_geomFsRestore; //size and position of the window before it was set to fullscreen
|
||||||
bool m_closing = false;
|
bool m_closing = false;
|
||||||
quint32 m_windowId = 0;
|
quint32 m_windowId = 0;
|
||||||
QWindow *m_internalWindow = nullptr;
|
QWindow *m_internalWindow = nullptr;
|
||||||
Qt::WindowFlags m_internalWindowFlags = Qt::WindowFlags();
|
Qt::WindowFlags m_internalWindowFlags = Qt::WindowFlags();
|
||||||
bool m_unmapped = true;
|
bool m_unmapped = true;
|
||||||
MaximizeMode m_maximizeMode = MaximizeRestore;
|
|
||||||
QRect m_geomMaximizeRestore; // size and position of the window before it was set to maximize
|
QRect m_geomMaximizeRestore; // size and position of the window before it was set to maximize
|
||||||
NET::WindowType m_windowType = NET::Normal;
|
NET::WindowType m_windowType = NET::Normal;
|
||||||
QPointer<KWayland::Server::PlasmaShellSurfaceInterface> m_plasmaShellSurface;
|
QPointer<KWayland::Server::PlasmaShellSurfaceInterface> m_plasmaShellSurface;
|
||||||
|
|
Loading…
Reference in a new issue