From 625baf006121e814612dcbc70a115efd4521cdf5 Mon Sep 17 00:00:00 2001
From: Lukas Holecek <hluk@email.cz>
Date: Wed, 31 Mar 2021 14:50:23 +0200
Subject: [PATCH] Wayland: Fix saving/restoring window size on multiple screens

Getting mouse position on Wayland might be unsupported.
---
 src/common/config.cpp           | 37 +++++++++++++++++++++++++++++----
 src/gui/windowgeometryguard.cpp | 13 ++++++++++++
 src/gui/windowgeometryguard.h   |  4 ++++
 3 files changed, 50 insertions(+), 4 deletions(-)

diff --git a/src/common/config.cpp b/src/common/config.cpp
index 249a05871..4b15d42c1 100644
--- a/src/common/config.cpp
+++ b/src/common/config.cpp
@@ -45,6 +45,16 @@ enum class GeometryAction {
     Restore
 };
 
+QPoint mousePos()
+{
+    // On Wayland, getting mouse position can return
+    // the last known mouse position in an own Qt application window.
+    static const bool supported = !QCursor::pos().isNull();
+    if (supported)
+        return QCursor::pos();
+    return QPoint();
+}
+
 QString toString(const QRect &geometry)
 {
     return QString::fromLatin1("%1x%2,%3,%4")
@@ -56,9 +66,28 @@ QString toString(const QRect &geometry)
 
 int screenNumber(const QWidget &widget, GeometryAction geometryAction)
 {
-    return geometryAction == GeometryAction::Save
-            ? QApplication::desktop()->screenNumber(&widget)
-            : screenNumberAt(QCursor::pos());
+    if (geometryAction == GeometryAction::Restore) {
+        const QPoint pos = mousePos();
+        if ( !pos.isNull() ) {
+            const int n = screenNumberAt(pos);
+            if (n != -1)
+                return n;
+        }
+    }
+
+    QWindow *windowHandle = widget.windowHandle();
+    if (windowHandle) {
+        QScreen *screen = windowHandle->screen();
+        if (screen)
+            return QGuiApplication::screens().indexOf(screen);
+    }
+
+    const int n = QApplication::desktop()->screenNumber(&widget);
+    if (n != -1)
+        return n;
+
+    QScreen *screen = QGuiApplication::primaryScreen();
+    return QGuiApplication::screens().indexOf(screen);
 }
 
 QString geometryOptionName(const QWidget &widget, GeometryAction geometryAction, bool openOnCurrentScreen)
@@ -192,7 +221,7 @@ void restoreWindowGeometry(QWidget *w, bool openOnCurrentScreen)
 
         // If geometry for the screen doesn't exist, move window to the middle of the screen.
         if (geometry.isEmpty()) {
-            const QRect availableGeometry = screenAvailableGeometry(QCursor::pos());
+            const QRect availableGeometry = screenAvailableGeometry(w->pos());
             const QPoint position = availableGeometry.center() - w->rect().center();
             w->move(position);
         }
diff --git a/src/gui/windowgeometryguard.cpp b/src/gui/windowgeometryguard.cpp
index 3abd5503c..eb4f8261a 100644
--- a/src/gui/windowgeometryguard.cpp
+++ b/src/gui/windowgeometryguard.cpp
@@ -27,7 +27,9 @@
 #include <QApplication>
 #include <QEvent>
 #include <QMoveEvent>
+#include <QScreen>
 #include <QVariant>
+#include <QWindow>
 
 namespace {
 
@@ -53,6 +55,11 @@ bool WindowGeometryGuard::eventFilter(QObject *, QEvent *event)
             m_timerSaveGeometry.stop();
             m_timerRestoreGeometry.start();
         }
+        if (!m_screenChangeConnected && m_window->windowHandle()) {
+            m_screenChangeConnected = true;
+            connect(m_window->windowHandle(), &QWindow::screenChanged,
+                    this, &WindowGeometryGuard::onScreenChanged);
+        }
         break;
 
     case QEvent::Move:
@@ -121,3 +128,9 @@ void WindowGeometryGuard::unlockWindowGeometry()
 {
     m_timerUnlockGeometry.stop();
 }
+
+void WindowGeometryGuard::onScreenChanged()
+{
+    m_timerUnlockGeometry.stop();
+    restoreWindowGeometry();
+}
diff --git a/src/gui/windowgeometryguard.h b/src/gui/windowgeometryguard.h
index 8720529e5..bd5137107 100644
--- a/src/gui/windowgeometryguard.h
+++ b/src/gui/windowgeometryguard.h
@@ -41,11 +41,15 @@ private:
     void restoreWindowGeometry();
     void unlockWindowGeometry();
 
+    void onScreenChanged();
+
     QWidget *m_window;
 
     QTimer m_timerSaveGeometry;
     QTimer m_timerRestoreGeometry;
     QTimer m_timerUnlockGeometry;
+
+    bool m_screenChangeConnected = false;
 };
 
 #endif // WINDOWGEOMETRYGUARD_H
-- 
GitLab