Close to system tray option on Windows (#1159)

Displays a system tray icon when enabled. Closing the window (clicking the X or Alt+F4) hides the window.

The window can be restored by clicking the icon, or via its context menu. The application can be quit via the context menu or Ctrl+Q.

Default: Disabled

Closes #470
This commit is contained in:
Eric Gregory authored and GitHub committed 2026-02-24 21:07:47 -05:00
1 parent 00c44bc74d
commit 2bc0c4fe8c
4 files changed
+72 -2

No files matched your search

@@ -163,6 +163,12 @@
"default": true,
"platforms": [ "windows" ]
},
{
"value": "enableWindowsTrayIcon",
"display_name": "Enable Windows System Tray",
"default": false,
"platforms": [ "windows" ]
},
{
"value": "enableMPV",
"display_name": "Enable MPV Player",
+11
View File
@@ -21,6 +21,11 @@
///////////////////////////////////////////////////////////////////////////////////////////////////
SettingsComponent::SettingsComponent(QObject *parent) : ComponentBase(parent), m_settingsVersion(-1)
{
connect(this, &SettingsComponent::sectionValueUpdate, this, [this](const QString& section, const QVariantMap& values)
{
if (section == SETTINGS_SECTION_MAIN && values.contains("enableWindowsTrayIcon"))
emit windowsTrayIconChanged();
});
}
/////////////////////////////////////////////////////////////////////////////////////////
@@ -790,6 +795,12 @@ bool SettingsComponent::allowBrowserZoom()
return SettingsComponent::Get().value(SETTINGS_SECTION_MAIN, "allowBrowserZoom").toBool();
}
/////////////////////////////////////////////////////////////////////////////////////////
bool SettingsComponent::enableWindowsTrayIcon()
{
return SettingsComponent::Get().value(SETTINGS_SECTION_MAIN, "enableWindowsTrayIcon").toBool();
}
/////////////////////////////////////////////////////////////////////////////////////////
QString SettingsComponent::detectCertBundlePath()
{
+5
View File
@@ -31,6 +31,7 @@ class SettingsSection;
class SettingsComponent : public ComponentBase
{
Q_OBJECT
Q_PROPERTY(bool windowsTrayIcon READ enableWindowsTrayIcon NOTIFY windowsTrayIconChanged)
DEFINE_SINGLETON(SettingsComponent);
public:
@@ -67,6 +68,7 @@ public:
Q_INVOKABLE bool autodetectCertBundle();
Q_INVOKABLE QString detectCertBundlePath();
Q_INVOKABLE bool allowBrowserZoom();
bool enableWindowsTrayIcon();
// host commands
Q_SLOT Q_INVOKABLE void cycleSettingCommand(const QString& args);
@@ -87,6 +89,9 @@ public:
// part of the map.
Q_SIGNAL void sectionValueUpdate(const QString& section, const QVariantMap& values);
// Windows system tray icon enabled/disabled.
Q_SIGNAL void windowsTrayIconChanged();
// A hack to load a value from the config file at very early init time, before
// the SettingsComponent is created.
//
+50 -2
View File
@@ -4,6 +4,7 @@ import QtWebEngine
import QtWebChannel
import QtQuick.Window
import QtQuick.Controls
import Qt.labs.platform as Labs
Window
{
@@ -24,6 +25,9 @@ Window
property string videoInfo: ""
property string webUrl: ""
property bool showSystemTrayIcon: webDesktopMode && components.system.isWindows &&
components.settings.windowsTrayIcon
signal reloadWebClient()
Component.onCompleted: {
@@ -32,6 +36,14 @@ Window
}
}
onClosing: function(close) {
if (showSystemTrayIcon) {
// Minimize to tray on close.
close.accepted = false
mainWindow.hide()
}
}
function toggleFullscreen() {
visibility = (visibility === Window.FullScreen) ? Window.Windowed : Window.FullScreen
}
@@ -49,6 +61,12 @@ Window
visibility = Window.Minimized
}
function restoreWindow() {
mainWindow.show()
mainWindow.raise()
mainWindow.requestActivate()
}
function runWebAction(action)
{
if (mainWindow.webDesktopMode)
@@ -98,8 +116,8 @@ Window
Action
{
enabled: mainWindow.webDesktopMode
shortcut: StandardKey.Quit
onTriggered: mainWindow.close()
shortcut: components.system.isWindows ? "Ctrl+Q" : StandardKey.Quit
onTriggered: Qt.quit()
}
Action
@@ -400,4 +418,34 @@ Window
}
property QtObject webChannel: web.webChannel
Labs.SystemTrayIcon {
visible: showSystemTrayIcon
icon.source: "qrc:/images/icon.png"
tooltip: "Jellyfin Desktop"
onActivated: function(reason) {
if (reason === Labs.SystemTrayIcon.Context) {
// Right click: open context menu
contextMenu.open()
components.window.setCursorVisibility(true)
} else {
// All other clicks: restore window
restoreWindow()
}
}
menu: Labs.Menu {
id: contextMenu
Labs.MenuItem {
text: qsTr("Restore")
onTriggered: restoreWindow()
}
Labs.MenuSeparator {}
Labs.MenuItem {
text: qsTr("Quit")
onTriggered: Qt.quit()
}
}
}
}