diff --git a/src/lib/app/RvCommon/RvApplication.cpp b/src/lib/app/RvCommon/RvApplication.cpp index 567b72d11..e52987d38 100644 --- a/src/lib/app/RvCommon/RvApplication.cpp +++ b/src/lib/app/RvCommon/RvApplication.cpp @@ -766,19 +766,50 @@ namespace Rv auto isVirtualDesktop = [&screens, primaryScreen]() -> bool { - // Not a virtual desktop if there is only one screen. - if (screens.size() <= 1) + // Not a virtual desktop if there is only one screen, or if + // we have no primary screen to compare against. + if (screens.size() <= 1 || primaryScreen == nullptr) return false; QRect totalGeometry; for (const auto& screen : screens) { + if (screen == nullptr) + continue; totalGeometry = totalGeometry.united(screen->geometry()); } return totalGeometry != primaryScreen->geometry(); }; + // + // Find the screen index for a given global point. Prefer Qt's + // QGuiApplication::screenAt() which handles edge cases (such as + // monitors whose top edges are not aligned, leaving gaps in the + // virtual desktop bounding box) more robustly than a manual + // QRect::contains() check. + // + auto getScreenFromPoint = [&screens](const QPoint& point) -> int + { + QScreen* s = QGuiApplication::screenAt(point); + if (s != nullptr) + { + const int idx = screens.indexOf(s); + if (idx >= 0) + return idx; + } + + for (int i = 0; i < screens.size(); ++i) + { + if (screens[i] != nullptr && screens[i]->geometry().contains(point)) + { + return i; + } + } + + return -1; + }; + // // Allow command line placement // @@ -787,7 +818,7 @@ namespace Rv { if (opts.screen != -1 && isVirtualDesktop()) { - if (opts.screen < screens.size()) + if (opts.screen >= 0 && opts.screen < screens.size() && screens[opts.screen] != nullptr) { QRect r = screens[opts.screen]->geometry(); opts.x += r.x(); @@ -805,23 +836,19 @@ namespace Rv } } - auto getScreenFromPoint = [&screens](const QPoint& point) -> int - { - for (int i = 0; i < screens.size(); ++i) - { - if (screens[i]->geometry().contains(point)) - { - return i; - } - } - - return -1; - }; - int screen = getScreenFromPoint(QCursor::pos()); if (opts.screen != -1) { - screen = opts.screen; + // + // Honor the user/preference-supplied screen index only when + // it refers to an actual screen. A stale preference (or a + // command-line value larger than the current monitor count) + // must not be propagated as an out-of-bounds index. + // + if (opts.screen >= 0 && opts.screen < screens.size()) + { + screen = opts.screen; + } } int oldX = doc->pos().x(); @@ -829,15 +856,17 @@ namespace Rv int oldScreen = getScreenFromPoint(QPoint(oldX, oldY)); - if (screen != -1 && oldScreen != -1 && isVirtualDesktop() && screen != oldScreen) + if (screen >= 0 && screen < screens.size() && oldScreen >= 0 && oldScreen < screens.size() + && screens[screen] != nullptr && screens[oldScreen] != nullptr && isVirtualDesktop() + && screen != oldScreen) // // The application is going to come up on the wrong screen, so figure // out our our relative position on the current screen, and move to the // same relative position on the correct screen. // { - QRect rnew = QGuiApplication::screens().at(screen)->geometry(); - QRect rold = QGuiApplication::screens().at(oldScreen)->geometry(); + QRect rnew = screens[screen]->geometry(); + QRect rold = screens[oldScreen]->geometry(); int xoff = oldX - rold.x(); int yoff = oldY - rold.y();