From: Kevin Ottens Date: Wed, 20 May 2020 17:36:57 +0000 (+0200) Subject: Move all the position computation on the C++ side X-Git-Tag: archive/raspbian/3.16.7-1_deb13u1+rpi1~1^2~222^2^2~160^2~6 X-Git-Url: https://dgit.raspbian.org/?a=commitdiff_plain;h=6c6dfb15a7d2193b430f55b0deac160e3c4460eb;p=nextcloud-desktop.git Move all the position computation on the C++ side The API is just more convenient there, the rect and point types on the QML side are just pale shadow of their C++ counterparts. Also improved a bit the constness of the Systray class. Signed-off-by: Kevin Ottens --- diff --git a/src/gui/systray.cpp b/src/gui/systray.cpp index 3370a85f7..5db933983 100644 --- a/src/gui/systray.cpp +++ b/src/gui/systray.cpp @@ -61,8 +61,6 @@ Systray::Systray() connect(AccountManager::instance(), &AccountManager::accountAdded, this, &Systray::showWindow); - - qmlRegisterUncreatableType("com.nextcloud.gui", 1, 0, "Systray", "This type is uncreatable, it is exported for its enums"); } void Systray::create() @@ -146,8 +144,22 @@ void Systray::pauseResumeSync() /* Helper functions for cross-platform tray icon position and taskbar orientation detection */ /********************************************************************************************/ +QScreen *Systray::currentScreen() const +{ + const auto screens = QGuiApplication::screens(); + const auto cursorPos = QCursor::pos(); + + for (const auto screen : screens) { + if (screen->geometry().contains(cursorPos)) { + return screen; + } + } + + return nullptr; +} + /// Return the current screen index based on cursor position -int Systray::screenIndex() +int Systray::screenIndex() const { auto qPos = QCursor::pos(); for (int i = 0; i < QGuiApplication::screens().count(); i++) { @@ -158,7 +170,7 @@ int Systray::screenIndex() return 0; } -Systray::TaskBarPosition Systray::taskbarOrientation() +Systray::TaskBarPosition Systray::taskbarOrientation() const { // macOS: Always on top #if defined(Q_OS_MACOS) @@ -208,7 +220,7 @@ Systray::TaskBarPosition Systray::taskbarOrientation() } // TODO: Get real taskbar dimensions Linux as well -QRect Systray::taskbarRect() +QRect Systray::taskbarGeometry() const { #if defined(Q_OS_WIN) QRect tbRect = Utility::getTaskbarDimensions(); @@ -234,15 +246,90 @@ QRect Systray::taskbarRect() #endif } -QPoint Systray::calcTrayIconCenter() +QRect Systray::currentScreenRect() const +{ + const auto screen = currentScreen(); + const auto rect = screen->geometry(); + return rect.translated(screen->virtualGeometry().topLeft()); +} + +QPoint Systray::computeWindowReferencePoint(int width, int height) const +{ + const auto trayIconCenter = calcTrayIconCenter(); + const auto taskbarRect = taskbarGeometry(); + const auto taskbarScreenEdge = taskbarOrientation(); + const auto screenRect = currentScreenRect(); + + switch(taskbarScreenEdge) { + case TaskBarPosition::Bottom: + return { + trayIconCenter.x() - width / 2, + screenRect.bottom() - taskbarRect.height() - height - 4 + }; + case TaskBarPosition::Left: + return { + screenRect.left() + taskbarRect.width() + 4, + trayIconCenter.y() + }; + case TaskBarPosition::Top: + return { + trayIconCenter.x() - width / 2, + screenRect.top() + taskbarRect.height() + 4 + }; + case TaskBarPosition::Right: + return { + screenRect.right() - taskbarRect.width() - width - 4, + trayIconCenter.y() + }; + } + Q_UNREACHABLE(); +} + +QPoint Systray::computeWindowPosition(int width, int height) const +{ + auto referencePoint = computeWindowReferencePoint(width, height); + + const auto taskbarScreenEdge = taskbarOrientation(); + const auto taskbarRect = taskbarGeometry(); + const auto screenRect = currentScreenRect(); + + if (screenRect.right() <= referencePoint.x() + width) { + referencePoint.rx() = screenRect.right() - width - 4; +#if !defined(Q_OS_WIN) && !defined(Q_OS_MACOS) + referencePoint.rx() -= taskbarScreenEdge == TaskBarPosition::Right ? taskbarRect.width() : 0; +#endif + } + + if (referencePoint.x() <= screenRect.left()) { + referencePoint.rx() = screenRect.left() + 4; +#if !defined(Q_OS_WIN) && !defined(Q_OS_MACOS) + referencePoint.rx() += taskbarScreenEdge == TaskBarPosition::Left ? taskbarRect.width() : 0; +#endif + } + + if (referencePoint.y() <= screenRect.top()) { + referencePoint.ry() = screenRect.top() + 4; + +#if !defined(Q_OS_WIN) && !defined(Q_OS_MACOS) + referencePoint.ry() += taskbarScreenEdge == TaskBarPosition::Top ? taskbarRect.height() : 0; +#endif + } + if (screenRect.bottom() <= referencePoint.y() + height) { + referencePoint.ry() = screenRect.bottom() - height - 4; + } + + return referencePoint; +} + +QPoint Systray::calcTrayIconCenter() const { -// QSystemTrayIcon::geometry() is broken for ages on most Linux DEs (invalid geometry returned) -// thus we can use this only for Windows and macOS + // QSystemTrayIcon::geometry() is broken for ages on most Linux DEs (invalid geometry returned) + // thus we can use this only for Windows and macOS #if defined(Q_OS_WIN) || defined(Q_OS_MACOS) auto trayIconCenter = geometry().center(); return trayIconCenter; #else -// On Linux, fall back to mouse position (assuming tray icon is activated by mouse click) + // On Linux, fall back to mouse position (assuming tray icon is activated by mouse click) return QCursor::pos(); #endif } diff --git a/src/gui/systray.h b/src/gui/systray.h index 5dd26ad04..bc1923707 100644 --- a/src/gui/systray.h +++ b/src/gui/systray.h @@ -20,6 +20,7 @@ #include "accountmanager.h" #include "tray/UserModel.h" +class QScreen; class QQmlApplicationEngine; namespace OCC { @@ -57,10 +58,11 @@ public: Q_INVOKABLE bool syncIsPaused(); Q_INVOKABLE void setOpened(); Q_INVOKABLE void setClosed(); - Q_INVOKABLE int screenIndex(); - Q_INVOKABLE QPoint calcTrayIconCenter(); - Q_INVOKABLE TaskBarPosition taskbarOrientation(); - Q_INVOKABLE QRect taskbarRect(); + Q_INVOKABLE int screenIndex() const; + Q_INVOKABLE QPoint calcTrayIconCenter() const; + Q_INVOKABLE TaskBarPosition taskbarOrientation() const; + Q_INVOKABLE QRect taskbarGeometry() const; + Q_INVOKABLE QPoint computeWindowPosition(int width, int height) const; signals: void currentUserChanged(); @@ -80,6 +82,11 @@ public slots: private: static Systray *_instance; Systray(); + + QScreen *currentScreen() const; + QRect currentScreenRect() const; + QPoint computeWindowReferencePoint(int width, int height) const; + bool _isOpen = false; bool _syncIsPaused = false; QQmlApplicationEngine *_trayEngine; diff --git a/src/gui/tray/Window.qml b/src/gui/tray/Window.qml index f0c82986e..505875808 100644 --- a/src/gui/tray/Window.qml +++ b/src/gui/tray/Window.qml @@ -8,97 +8,8 @@ import QtGraphicalEffects 1.0 // Custom qml modules are in /theme (and included by resources.qrc) import Style 1.0 -import com.nextcloud.gui 1.0 Window { - - function setTrayWindowPosition() - { - var trayIconCenter = systrayBackend.calcTrayIconCenter(); - console.debug("Calculated tray icon center:",trayIconCenter); - var currentScreen = systrayBackend.screenIndex(); - console.debug("Tray menu about to show on screen",currentScreen,"."); - trayWindow.screen = Qt.application.screens[currentScreen]; - trayWindow.show(); - trayWindow.raise(); - trayWindow.requestActivate(); - var trayWindowX; - var trayWindowY; - var taskbarOrientation = systrayBackend.taskbarOrientation(); - var taskbarRect = systrayBackend.taskbarRect(); - var screenRect = Qt.rect(0, 0, Screen.width, Screen.height) - if (Qt.platform.os === "linux") { - screenRect.x = Screen.virtualX - screenRect.y = Screen.virtualY - } - - switch(taskbarOrientation) { - // Platform separation here: Windows and macOS draw coordinates have to be given in screen-coordinates - // KDE and most xorg based DEs expect them as virtual coordinates - case Systray.Bottom: - console.debug("Taskbar is on the bottom."); - trayWindowX = trayIconCenter.x - trayWindow.width / 2; - trayWindowY = screenRect.bottom - taskbarRect.height - trayWindow.height - 4; - break; - case Systray.Left: - console.debug("Taskbar is on the left."); - trayWindowX = screenRect.left + taskbarRect.width + 4; - trayWindowY = trayIconCenter.y; - break; - case Systray.Top: - console.debug("Taskbar is on the top."); - trayWindowX = trayIconCenter.x - trayWindow.width / 2; - trayWindowY = screenRect.top + taskbarRect.height + 4; - break; - case Systray.Right: - console.debug("Taskbar is on the right."); - trayWindowX = screenRect.right - taskbarRect.width - trayWindow.width - 4; - trayWindowY = trayIconCenter.y; - break; - } - - console.debug("Screen.height:", Screen.height); - console.debug("Screen.desktopAvailableHeight:", Screen.desktopAvailableHeight); - console.debug("Screen.virtualY:", Screen.virtualY); - console.debug("Screen.width:", Screen.width); - console.debug("Screen.desktopAvailableWidth:", Screen.desktopAvailableWidth); - console.debug("Screen.virtualX:", Screen.virtualX); - console.debug("Taskbar height:", taskbarRect.height); - console.debug("Taskbar width:", taskbarRect.width); - - if (screenRect.right <= trayWindowX + trayWindow.width) { - console.debug("Out-of-screen condition on the right detected. Adjusting window position."); - trayWindowX = screenRect.right - trayWindow.width - 4; - - if (Qt.platform.os === "linux") { - trayWindowX -= taskbarOrientation === Systray.Right ? taskbarRect.width : 0; - } - } - if (trayWindowX <= screenRect.left) { - console.debug("Out-of-screen condition on the left detected. Adjusting window position."); - trayWindowX = screenRect.left + 4; - - if (Qt.platform.os === "linux") { - trayWindowX += taskbarOrientation === Systray.Left ? taskbarRect.width : 0; - } - } - if (trayWindowY <= screenRect.top) { - console.debug("Out-of-screen condition on the top detected. Adjusting window position."); - trayWindowY = screenRect.top + 4; - - if (Qt.platform.os === "linux") { - trayWindowY += taskbarOrientation === Systray.Top ? taskbarRect.height : 0; - } - } - if (screenRect.bottom <= trayWindowY + trayWindow.height) { - console.debug("Out-of-screen condition on the bottom detected. Adjusting window position."); - trayWindowY = screenRect.bottom - trayWindow.height - 4; - } - console.debug("Tray window position: x =",trayWindowX," y =",trayWindowY); - trayWindow.setX(trayWindowX); - trayWindow.setY(trayWindowY); - } - id: trayWindow width: Style.trayWindowWidth @@ -151,7 +62,17 @@ Window { target: systrayBackend onShowWindow: { accountMenu.close(); - setTrayWindowPosition(); + + trayWindow.screen = Qt.application.screens[systrayBackend.screenIndex()]; + + var position = systrayBackend.computeWindowPosition(trayWindow.width, trayWindow.height) + trayWindow.x = position.x + trayWindow.y = position.y + + trayWindow.show(); + trayWindow.raise(); + trayWindow.requestActivate(); + systrayBackend.setOpened(); userModelBackend.fetchCurrentActivityModel(); }