Skip to content

Commit

Permalink
Fix restoring maximized window corner case
Browse files Browse the repository at this point in the history
For issue #553

On Windows it's possible to have normal geometry
in a different screen than the maximized window if
you drag a window across monitors and touch an
aerosnap edge.

While restoring, we need a fake setGeometry()
call to set the normal geometry, since Qt doesn't
provide QWindow::setNormalGeometry(), that resulted
in the window being maximized on the wrong window.

The solution is to patch the normal geometry to be
in the first screen.
  • Loading branch information
iamsergio committed Dec 14, 2024
1 parent 064954c commit a7f4e4f
Show file tree
Hide file tree
Showing 8 changed files with 64 additions and 0 deletions.
1 change: 1 addition & 0 deletions Changelog
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
- Fix case where persistent central widget would detach when dragged
- Allow to build against external KDBindings
- Fix restore layout of nested main windows (#508)
- Fix restore maximized window corner case (#553)

* v2.1.0 (08 May 2024)
- Added standalone layouting example using Slint
Expand Down
12 changes: 12 additions & 0 deletions src/LayoutSaver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -642,6 +642,18 @@ void LayoutSaver::Private::deserializeWindowGeometry(const T &saved, Window::Ptr
// The window will be maximized. We first set its geometry to normal
// Later it's maximized and will remember this value
geometry = saved.normalGeometry;

if (saved.screenIndex != Platform::instance()->screenNumberForPoint(geometry.topLeft())) {
// Workaround bug #553. Window is maximized on screen 2 but its normal
// geometry is on screen 1. Restoring normal geometry would move it to screen 2
// To avoid that, we move its normal geometry to screen 2. Could be fixed
// without workarounds if Qt supported QWindow::setNormalGeometry()
window->setScreen(saved.screenIndex);
if (auto screen = window->screen()) {
// center is as good as any
geometry.moveCenter(screen->geometry().center());
}
}
}

Core::FloatingWindow::ensureRectIsOnScreen(geometry);
Expand Down
4 changes: 4 additions & 0 deletions src/core/Platform.h
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,10 @@ class DOCKS_EXPORT Platform
/// @brief Returns the size of the screen where this view is in
virtual Size screenSizeFor(View *) const = 0;

/// @brief Returns which screen the point is in
/// -1 if not found
virtual int screenNumberForPoint(Point) const = 0;

/// @brief Create an empty view
/// For Qt this would just returns a empty QWidget or QQuickItem
/// other frontends can return something as basic.
Expand Down
5 changes: 5 additions & 0 deletions src/core/Window_p.h
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,11 @@ class DOCKS_EXPORT Window
/// @brief Returns the screen this window is on
virtual Screen::Ptr screen() const = 0;

/// @brief Sets the screen this window belongs to
/// Does not move it
virtual void setScreen(int) = 0;
virtual int screenIndex() const = 0;

/// Deletes the underlying window. Only used during tests.
virtual void destroy() = 0;

Expand Down
11 changes: 11 additions & 0 deletions src/qtcommon/Platform.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,17 @@ int Platform_qt::screenNumberForWindow(std::shared_ptr<Core::Window> window) con
return screenNumberForQWindow(static_cast<Window *>(window.get())->qtWindow());
}

int Platform_qt::screenNumberForPoint(Point pt) const
{
const auto screens = qApp->screens();
for (int i = 0; i < screens.size(); ++i) {
if (screens[i]->geometry().contains(pt))
return i;
}

return -1;
}

int Platform_qt::screenNumberForQWindow(QWindow *window) const
{
if (QScreen *screen = window->screen()) {
Expand Down
1 change: 1 addition & 0 deletions src/qtcommon/Platform.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ class DOCKS_EXPORT Platform_qt : public Core::Platform
QVector<std::shared_ptr<Core::Window>> windows() const override;
virtual std::shared_ptr<Core::Window> windowFromQWindow(QWindow *) const = 0;
int screenNumberForWindow(std::shared_ptr<Core::Window>) const override;
int screenNumberForPoint(Point) const override;

void sendEvent(Core::View *, QEvent *) const override;

Expand Down
27 changes: 27 additions & 0 deletions src/qtcommon/Window.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include <QWindow>
#include <QScreen>
#include <QVariant>
#include <QGuiApplication>

#include <QtGui/private/qhighdpiscaling_p.h>

Expand Down Expand Up @@ -178,3 +179,29 @@ bool Window::isFullScreen() const
{
return m_window->windowStates() & Qt::WindowFullScreen;
}

void Window::setScreen(int index)
{
const auto screens = qApp->screens();
const int numScreens = screens.size();
if (index >= numScreens || index < 0) {
qWarning() << Q_FUNC_INFO << "index out of bounds" << index << numScreens;
return;
}

if (m_window) {
m_window->setScreen(screens[index]);
} else {
qWarning() << Q_FUNC_INFO << "window is nullptr";
}
}

int Window::screenIndex() const
{
if (!m_window) {
qWarning() << Q_FUNC_INFO << "window is nullptr";
return -1;
}

return qApp->screens().indexOf(m_window->screen());
}
3 changes: 3 additions & 0 deletions src/qtcommon/Window_p.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,9 @@ class DOCKS_EXPORT Window : public Core::Window
QPoint mapFromGlobal(QPoint globalPos) const override;
QPoint mapToGlobal(QPoint localPos) const override;
Screen_qt::Ptr screen() const override;
void setScreen(int) override;
int screenIndex() const override;

void destroy() override;
QSize minSize() const override;
QSize maxSize() const override;
Expand Down

0 comments on commit a7f4e4f

Please sign in to comment.