diff --git a/src/DockWidgetBase.cpp b/src/DockWidgetBase.cpp index e622e886..d50b6258 100644 --- a/src/DockWidgetBase.cpp +++ b/src/DockWidgetBase.cpp @@ -513,6 +513,7 @@ FloatingWindow *DockWidgetBase::Private::morphIntoFloatingWindow() auto frame = Config::self().frameworkWidgetFactory()->createFrame(); frame->addWidget(q); geo.setSize(geo.size().boundedTo(frame->maxSizeHint())); + FloatingWindow::ensureRectIsOnScreen(geo); auto floatingWindow = Config::self().frameworkWidgetFactory()->createFloatingWindow(frame, nullptr, geo); floatingWindow->show(); diff --git a/src/LayoutSaver.cpp b/src/LayoutSaver.cpp index 340495f9..1c2cc3f2 100644 --- a/src/LayoutSaver.cpp +++ b/src/LayoutSaver.cpp @@ -339,10 +339,13 @@ void LayoutSaver::Private::deserializeWindowGeometry(const T &saved, QWidgetOrQu // Not simply calling QWidget::setGeometry() here. // For QtQuick we need to modify the QWindow's geometry. + auto windowGeometry = saved.geometry; + ::FloatingWindow::ensureRectIsOnScreen(windowGeometry); + if (topLevel->isWindow()) { - topLevel->setGeometry(saved.geometry); + topLevel->setGeometry(windowGeometry); } else { - KDDockWidgets::Private::setTopLevelGeometry(saved.geometry, topLevel); + KDDockWidgets::Private::setTopLevelGeometry(windowGeometry, topLevel); } topLevel->setVisible(saved.isVisible); diff --git a/src/private/FloatingWindow.cpp b/src/private/FloatingWindow.cpp index 8396715a..ee5e11be 100644 --- a/src/private/FloatingWindow.cpp +++ b/src/private/FloatingWindow.cpp @@ -261,6 +261,8 @@ void FloatingWindow::setSuggestedGeometry(QRect suggestedRect, SuggestedGeometry suggestedRect.moveCenter(originalCenter); } + ensureRectIsOnScreen(suggestedRect); + setGeometry(suggestedRect); } @@ -635,3 +637,49 @@ void FloatingWindow::updateSizeConstraints() setMaximumSize(maxSizeHint()); }); } + +void FloatingWindow::ensureRectIsOnScreen(QRect &geometry) +{ + const auto screens = qApp->screens(); + if (screens.empty()) + return; + + int nearestDistSq = std::numeric_limits::max(); + int nearestIndex = -1; + + const int screenCount = screens.count(); + for (int i = 0; i < screenCount; i++) { + auto scrGeom = screens[i]->geometry(); + + // Account for virtual coordinates space + scrGeom.moveTopLeft(scrGeom.topLeft() - screens[i]->virtualGeometry().topLeft()); + + // If the rectangle is visible at all, we need do nothing + if (scrGeom.intersects(geometry)) + return; + + // Find the nearest screen, so we can move the geometry onto it + const QPoint dist2D = geometry.center() - scrGeom.center(); + const int distSq = (dist2D.x() * dist2D.x()) + (dist2D.y() * dist2D.y()); + if (distSq < nearestDistSq) { + nearestDistSq = distSq; + nearestIndex = i; + } + } + + // Move the rectangle to the nearest vertical and/or horizontal screen edge + auto scrGeom = screens[nearestIndex]->geometry(); + scrGeom.moveTopLeft(scrGeom.topLeft() - screens[nearestIndex]->virtualGeometry().topLeft()); + + if (geometry.left() < scrGeom.left()) { + geometry.moveLeft(scrGeom.left()); + } else if (geometry.left() > scrGeom.right()) { + geometry.moveRight(scrGeom.right()); + } + + if (geometry.top() < scrGeom.top()) { + geometry.moveTop(scrGeom.top()); + } else if (geometry.top() > scrGeom.bottom()) { + geometry.moveBottom(scrGeom.bottom()); + } +} diff --git a/src/private/FloatingWindow_p.h b/src/private/FloatingWindow_p.h index 5e362b8b..a9e113ca 100644 --- a/src/private/FloatingWindow_p.h +++ b/src/private/FloatingWindow_p.h @@ -62,6 +62,8 @@ public: int userType() const; + static void ensureRectIsOnScreen(QRect &geometry); + #ifdef Q_OS_WIN void setLastHitTest(int hitTest) {