perf: improve animation smoothness on Wayland

This commit is contained in:
dela
2026-06-10 16:12:29 +08:00
parent d56e09914f
commit 012d165b81
8 changed files with 338 additions and 102 deletions
+110 -39
View File
@@ -48,6 +48,36 @@
#include <widgetframe/windowbar.h>
#include <widgetframe/windowbutton.h>
namespace {
bool canAnimateTopLevelWindowPosition()
{
#if defined(Q_OS_LINUX)
return !QGuiApplication::platformName().contains(QStringLiteral("wayland"),
Qt::CaseInsensitive);
#else
return true;
#endif
}
QRect centeredRectWithin(const QRect &sourceGeometry, const QSize &targetSize,
const QRect &bounds)
{
QRect target(QPoint(0, 0), targetSize);
target.moveCenter(sourceGeometry.center());
if (target.left() < bounds.left())
target.moveLeft(bounds.left());
if (target.top() < bounds.top())
target.moveTop(bounds.top());
if (target.right() > bounds.right())
target.moveRight(bounds.right());
if (target.bottom() > bounds.bottom())
target.moveBottom(bounds.bottom());
return target;
}
}
static inline void emulateLeaveEvent(QWidget *widget) {
Q_ASSERT(widget);
if (!widget) return;
@@ -966,6 +996,51 @@ void MainWindow::navigateToHome()
return;
}
if (!canAnimateTopLevelWindowPosition()) {
hide();
setWindowOpacity(0.0);
setMaximumSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX);
setMinimumSize(0, 0);
const QString windowState = ConfigStore::instance()->get<QString>(
ConfigKeys::StartupWindowState, "normal");
const bool shouldMaximize = (windowState == "maximized");
m_loginView->setGraphicsEffect(nullptr);
m_homeView->setGraphicsEffect(nullptr);
m_viewStack->setCurrentWidget(m_homeView);
#if !defined(Q_OS_MACOS) && !defined(Q_OS_MAC)
if (auto* minBtn = findChild<QWidget*>("min-button")) minBtn->show();
if (auto* maxBtn = findChild<QWidget*>("max-button")) maxBtn->show();
#endif
if (shouldMaximize) {
showMaximized();
} else {
resize(1280, 800);
}
setMinimumSize(900, 600);
show();
raise();
activateWindow();
auto *fadeIn = new QPropertyAnimation(this, "windowOpacity", this);
fadeIn->setDuration(180);
fadeIn->setStartValue(0.0);
fadeIn->setEndValue(1.0);
fadeIn->setEasingCurve(QEasingCurve::OutCubic);
connect(fadeIn, &QPropertyAnimation::finished, this, [this]() {
setWindowOpacity(1.0);
m_viewTransitionInProgress = false;
});
QTimer::singleShot(0, fadeIn, [fadeIn]() {
fadeIn->start(QAbstractAnimation::DeleteWhenStopped);
});
return;
}
auto *loginOpacity = new QGraphicsOpacityEffect(m_loginView);
loginOpacity->setOpacity(1.0);
@@ -979,6 +1054,7 @@ void MainWindow::navigateToHome()
connect(fadeOut, &QPropertyAnimation::finished, this, [this]() {
setMaximumSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX);
setMinimumSize(0, 0);
QString windowState = ConfigStore::instance()->get<QString>(
@@ -994,32 +1070,13 @@ void MainWindow::navigateToHome()
int targetWidth = 1280;
int targetHeight = 800;
targetGeo = QRect(
startGeo.x() - (targetWidth - startGeo.width()) / 2,
startGeo.y() - (targetHeight - startGeo.height()) / 2,
targetWidth, targetHeight);
QRect screenGeo = screen()->availableGeometry();
if (targetGeo.left() < screenGeo.left())
targetGeo.moveLeft(screenGeo.left());
if (targetGeo.top() < screenGeo.top())
targetGeo.moveTop(screenGeo.top());
if (targetGeo.right() > screenGeo.right())
targetGeo.moveRight(screenGeo.right());
if (targetGeo.bottom() > screenGeo.bottom())
targetGeo.moveBottom(screenGeo.bottom());
targetGeo = centeredRectWithin(startGeo,
QSize(targetWidth, targetHeight),
screenGeo);
}
auto *geoAnim = new QPropertyAnimation(this, "geometry", this);
geoAnim->setDuration(shouldMaximize ? 500 : 350);
geoAnim->setStartValue(startGeo);
geoAnim->setEndValue(targetGeo);
geoAnim->setEasingCurve(QEasingCurve::InOutCubic);
connect(geoAnim, &QPropertyAnimation::finished, this, [this, shouldMaximize]() {
auto finishWindowTransition = [this, shouldMaximize]() {
setMinimumSize(900, 600);
@@ -1055,7 +1112,16 @@ void MainWindow::navigateToHome()
m_viewTransitionInProgress = false;
});
fadeIn->start(QAbstractAnimation::DeleteWhenStopped);
});
};
auto *geoAnim = new QPropertyAnimation(this, "geometry", this);
geoAnim->setDuration(shouldMaximize ? 500 : 350);
geoAnim->setStartValue(startGeo);
geoAnim->setEndValue(targetGeo);
geoAnim->setEasingCurve(QEasingCurve::InOutCubic);
connect(geoAnim, &QPropertyAnimation::finished, this,
finishWindowTransition);
geoAnim->start(QAbstractAnimation::DeleteWhenStopped);
});
fadeOut->start(QAbstractAnimation::DeleteWhenStopped);
@@ -1132,20 +1198,11 @@ void MainWindow::navigateToLogin() {
QRect startGeo = geometry();
int targetWidth = m_defaultWidth;
int targetHeight = m_defaultHeight;
QRect targetGeo(startGeo.x() + (startGeo.width() - targetWidth) / 2,
startGeo.y() + (startGeo.height() - targetHeight) / 2,
targetWidth, targetHeight);
QRect targetGeo = centeredRectWithin(
startGeo, QSize(targetWidth, targetHeight),
screen()->availableGeometry());
auto *geoAnim = new QPropertyAnimation(this, "geometry", this);
geoAnim->setDuration(startGeo.width() > 1300 ? 500 : 350);
geoAnim->setStartValue(startGeo);
geoAnim->setEndValue(targetGeo);
geoAnim->setEasingCurve(QEasingCurve::InOutCubic);
connect(geoAnim, &QPropertyAnimation::finished, this, [this]() {
auto finishWindowTransition = [this]() {
@@ -1172,8 +1229,22 @@ void MainWindow::navigateToLogin() {
m_viewTransitionInProgress = false;
});
fadeIn->start(QAbstractAnimation::DeleteWhenStopped);
});
geoAnim->start(QAbstractAnimation::DeleteWhenStopped);
};
if (canAnimateTopLevelWindowPosition()) {
auto *geoAnim = new QPropertyAnimation(this, "geometry", this);
geoAnim->setDuration(startGeo.width() > 1300 ? 500 : 350);
geoAnim->setStartValue(startGeo);
geoAnim->setEndValue(targetGeo);
geoAnim->setEasingCurve(QEasingCurve::InOutCubic);
connect(geoAnim, &QPropertyAnimation::finished, this,
finishWindowTransition);
geoAnim->start(QAbstractAnimation::DeleteWhenStopped);
} else {
resize(targetGeo.size());
finishWindowTransition();
}
});
fadeOut->start(QAbstractAnimation::DeleteWhenStopped);
}