connect(AccountManager::instance(), &AccountManager::accountAdded,
this, &Systray::showWindow);
-
- qmlRegisterUncreatableType<Systray>("com.nextcloud.gui", 1, 0, "Systray", "This type is uncreatable, it is exported for its enums");
}
void Systray::create()
/* 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++) {
return 0;
}
-Systray::TaskBarPosition Systray::taskbarOrientation()
+Systray::TaskBarPosition Systray::taskbarOrientation() const
{
// macOS: Always on top
#if defined(Q_OS_MACOS)
}
// TODO: Get real taskbar dimensions Linux as well
-QRect Systray::taskbarRect()
+QRect Systray::taskbarGeometry() const
{
#if defined(Q_OS_WIN)
QRect tbRect = Utility::getTaskbarDimensions();
#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
}
#include "accountmanager.h"
#include "tray/UserModel.h"
+class QScreen;
class QQmlApplicationEngine;
namespace OCC {
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();
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;
\r
// Custom qml modules are in /theme (and included by resources.qrc)\r
import Style 1.0\r
-import com.nextcloud.gui 1.0\r
\r
Window {\r
-\r
- function setTrayWindowPosition()\r
- {\r
- var trayIconCenter = systrayBackend.calcTrayIconCenter();\r
- console.debug("Calculated tray icon center:",trayIconCenter);\r
- var currentScreen = systrayBackend.screenIndex();\r
- console.debug("Tray menu about to show on screen",currentScreen,".");\r
- trayWindow.screen = Qt.application.screens[currentScreen];\r
- trayWindow.show();\r
- trayWindow.raise();\r
- trayWindow.requestActivate();\r
- var trayWindowX;\r
- var trayWindowY;\r
- var taskbarOrientation = systrayBackend.taskbarOrientation();\r
- var taskbarRect = systrayBackend.taskbarRect();\r
- var screenRect = Qt.rect(0, 0, Screen.width, Screen.height)\r
- if (Qt.platform.os === "linux") {\r
- screenRect.x = Screen.virtualX\r
- screenRect.y = Screen.virtualY\r
- }\r
-\r
- switch(taskbarOrientation) {\r
- // Platform separation here: Windows and macOS draw coordinates have to be given in screen-coordinates\r
- // KDE and most xorg based DEs expect them as virtual coordinates\r
- case Systray.Bottom:\r
- console.debug("Taskbar is on the bottom.");\r
- trayWindowX = trayIconCenter.x - trayWindow.width / 2;\r
- trayWindowY = screenRect.bottom - taskbarRect.height - trayWindow.height - 4;\r
- break;\r
- case Systray.Left:\r
- console.debug("Taskbar is on the left.");\r
- trayWindowX = screenRect.left + taskbarRect.width + 4;\r
- trayWindowY = trayIconCenter.y;\r
- break;\r
- case Systray.Top:\r
- console.debug("Taskbar is on the top.");\r
- trayWindowX = trayIconCenter.x - trayWindow.width / 2;\r
- trayWindowY = screenRect.top + taskbarRect.height + 4;\r
- break;\r
- case Systray.Right:\r
- console.debug("Taskbar is on the right.");\r
- trayWindowX = screenRect.right - taskbarRect.width - trayWindow.width - 4;\r
- trayWindowY = trayIconCenter.y;\r
- break;\r
- }\r
-\r
- console.debug("Screen.height:", Screen.height);\r
- console.debug("Screen.desktopAvailableHeight:", Screen.desktopAvailableHeight);\r
- console.debug("Screen.virtualY:", Screen.virtualY);\r
- console.debug("Screen.width:", Screen.width);\r
- console.debug("Screen.desktopAvailableWidth:", Screen.desktopAvailableWidth);\r
- console.debug("Screen.virtualX:", Screen.virtualX);\r
- console.debug("Taskbar height:", taskbarRect.height);\r
- console.debug("Taskbar width:", taskbarRect.width);\r
-\r
- if (screenRect.right <= trayWindowX + trayWindow.width) {\r
- console.debug("Out-of-screen condition on the right detected. Adjusting window position.");\r
- trayWindowX = screenRect.right - trayWindow.width - 4;\r
-\r
- if (Qt.platform.os === "linux") {\r
- trayWindowX -= taskbarOrientation === Systray.Right ? taskbarRect.width : 0;\r
- }\r
- }\r
- if (trayWindowX <= screenRect.left) {\r
- console.debug("Out-of-screen condition on the left detected. Adjusting window position.");\r
- trayWindowX = screenRect.left + 4;\r
-\r
- if (Qt.platform.os === "linux") {\r
- trayWindowX += taskbarOrientation === Systray.Left ? taskbarRect.width : 0;\r
- }\r
- }\r
- if (trayWindowY <= screenRect.top) {\r
- console.debug("Out-of-screen condition on the top detected. Adjusting window position.");\r
- trayWindowY = screenRect.top + 4;\r
-\r
- if (Qt.platform.os === "linux") {\r
- trayWindowY += taskbarOrientation === Systray.Top ? taskbarRect.height : 0;\r
- }\r
- }\r
- if (screenRect.bottom <= trayWindowY + trayWindow.height) {\r
- console.debug("Out-of-screen condition on the bottom detected. Adjusting window position.");\r
- trayWindowY = screenRect.bottom - trayWindow.height - 4;\r
- }\r
- console.debug("Tray window position: x =",trayWindowX," y =",trayWindowY);\r
- trayWindow.setX(trayWindowX);\r
- trayWindow.setY(trayWindowY);\r
- }\r
-\r
id: trayWindow\r
\r
width: Style.trayWindowWidth\r
target: systrayBackend\r
onShowWindow: {\r
accountMenu.close();\r
- setTrayWindowPosition();\r
+\r
+ trayWindow.screen = Qt.application.screens[systrayBackend.screenIndex()];\r
+\r
+ var position = systrayBackend.computeWindowPosition(trayWindow.width, trayWindow.height)\r
+ trayWindow.x = position.x\r
+ trayWindow.y = position.y\r
+\r
+ trayWindow.show();\r
+ trayWindow.raise();\r
+ trayWindow.requestActivate();\r
+\r
systrayBackend.setOpened();\r
userModelBackend.fetchCurrentActivityModel();\r
}\r