Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package tail-tray for openSUSE:Factory 
checked in at 2026-10-05 13:04:28
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/tail-tray (Old)
 and      /work/SRC/openSUSE:Factory/.tail-tray.new.3698736 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "tail-tray"

Mon Oct  5 13:04:28 2026 rev:29 rq:1382371 version:0.2.36

Changes:
--------
--- /work/SRC/openSUSE:Factory/tail-tray/tail-tray.changes      2026-09-29 
17:54:04.593971967 +0200
+++ /work/SRC/openSUSE:Factory/.tail-tray.new.3698736/tail-tray.changes 
2026-10-05 13:04:31.305106915 +0200
@@ -1,0 +2,19 @@
+Sun Oct 04 16:50:19 UTC 2026 - Johannes Kastl 
<[email protected]>
+
+- Update to version 0.2.36:
+  * Bump version to 0.2.36
+  * Align new show window logic when double clicking the tray icon
+    as well
+  * Cancel a login without freezing the window (#139)
+  * Show the main window without asking to un-maximize it (#141)
+  * Log out without root and move on to another account (#140)
+  * Stay on the current tab after a login (#142)
+  * Show "Connecting..." in the tray while Tailscale starts (#143)
+  * Replace Preferences and About in the tray with Show Window /
+    Hide Window (#144)
+  * Use the Tail Tray icon for notifications (#145)
+  * Show the window when tail-tray is launched again (#146)
+  * Refresh the Devices tab on every status update (#132)
+  * Stay on the current tab when the connection comes back (#131)
+
+-------------------------------------------------------------------

Old:
----
  tail-tray-0.2.35.obscpio

New:
----
  tail-tray-0.2.36.obscpio

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ tail-tray.spec ++++++
--- /var/tmp/diff_new_pack.J7KknO/_old  2026-10-05 13:04:32.740167057 +0200
+++ /var/tmp/diff_new_pack.J7KknO/_new  2026-10-05 13:04:32.745167267 +0200
@@ -17,7 +17,7 @@
 
 
 Name:           tail-tray
-Version:        0.2.35
+Version:        0.2.36
 Release:        0
 Summary:        Tailscale tray menu and UI for the KDE Plasma Desktop
 License:        GPL-3.0-only

++++++ _service ++++++
--- /var/tmp/diff_new_pack.J7KknO/_old  2026-10-05 13:04:32.785168943 +0200
+++ /var/tmp/diff_new_pack.J7KknO/_new  2026-10-05 13:04:32.791169195 +0200
@@ -2,8 +2,8 @@
   <service name="obs_scm" mode="manual">
     <param name="url">https://github.com/SneWs/tail-tray.git</param>
     <param name="scm">git</param>
-    <param name="revision">refs/tags/v0.2.35</param>
-    <param name="match-tag">v0.2.35</param>
+    <param name="revision">refs/tags/v0.2.36</param>
+    <param name="match-tag">v0.2.36</param>
     <param name="versionformat">@PARENT_TAG@</param>
     <param name="versionrewrite-pattern">v(.*)</param>
     <param name="changesgenerate">enable</param>

++++++ _servicedata ++++++
--- /var/tmp/diff_new_pack.J7KknO/_old  2026-10-05 13:04:32.831170871 +0200
+++ /var/tmp/diff_new_pack.J7KknO/_new  2026-10-05 13:04:32.844171416 +0200
@@ -3,6 +3,6 @@
                 <param name="url">https://github.com/SneWs/tail-tray</param>
               <param 
name="changesrevision">5089d8a02763a01668fb90c0896fbf25b9b4d16c</param></service><service
 name="tar_scm">
                 <param 
name="url">https://github.com/SneWs/tail-tray.git</param>
-              <param 
name="changesrevision">577bcb0d72dd5ca8a055c05581ab78dc8c0150b4</param></service></servicedata>
+              <param 
name="changesrevision">f46cbe5929582dfdbd505d632a80635d1438e24a</param></service></servicedata>
 (No newline at EOF)
 

++++++ tail-tray-0.2.35.obscpio -> tail-tray-0.2.36.obscpio ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/tail-tray-0.2.35/CMakeLists.txt 
new/tail-tray-0.2.36/CMakeLists.txt
--- old/tail-tray-0.2.35/CMakeLists.txt 2026-09-28 20:16:40.000000000 +0200
+++ new/tail-tray-0.2.36/CMakeLists.txt 2026-10-03 12:27:17.000000000 +0200
@@ -1,6 +1,6 @@
 cmake_minimum_required(VERSION 3.21)
 
-project(tail-tray VERSION 0.2.35 LANGUAGES CXX)
+project(tail-tray VERSION 0.2.36 LANGUAGES CXX)
 
 set(CMAKE_AUTOUIC ON)
 set(CMAKE_AUTOMOC ON)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/tail-tray-0.2.35/debian/changelog 
new/tail-tray-0.2.36/debian/changelog
--- old/tail-tray-0.2.35/debian/changelog       2026-09-28 20:16:40.000000000 
+0200
+++ new/tail-tray-0.2.36/debian/changelog       2026-10-03 12:27:17.000000000 
+0200
@@ -1,5 +1,5 @@
-tail-tray (0.2.35) UNRELEASED; urgency=medium
+tail-tray (0.2.36) UNRELEASED; urgency=medium
 
   * New upstream release.
 
- -- Marcus Grenängen <[email protected]>  Tue, 4 May 2026 17:12:08 +0100
+ -- Marcus Grenängen <[email protected]>  Sat, 2 Oct 2026 12:26:28 +0100
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/tail-tray-0.2.35/src/AccountsTabUiManager.cpp 
new/tail-tray-0.2.36/src/AccountsTabUiManager.cpp
--- old/tail-tray-0.2.35/src/AccountsTabUiManager.cpp   2026-09-28 
20:16:40.000000000 +0200
+++ new/tail-tray-0.2.36/src/AccountsTabUiManager.cpp   2026-10-03 
12:27:17.000000000 +0200
@@ -38,7 +38,15 @@
     );
 
     connect(ui->btnLogout, &QPushButton::clicked, this, [this]() {
-            pTailRunner->logout();
+            // The active account is the one marked with '*'; any other is 
where to go next
+            QString nextAccountId;
+            for (const auto& acc : accounts) {
+                if (!acc.account.endsWith('*')) {
+                    nextAccountId = acc.id;
+                    break;
+                }
+            }
+            pTailRunner->logout(nextAccountId);
             if (ui->lstAccounts->selectedItems().count() > 0) {
                 auto* selectedItem = ui->lstAccounts->selectedItems().first();
                 int row = ui->lstAccounts->row(selectedItem);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/tail-tray-0.2.35/src/MainWindow.cpp 
new/tail-tray-0.2.36/src/MainWindow.cpp
--- old/tail-tray-0.2.35/src/MainWindow.cpp     2026-09-28 20:16:40.000000000 
+0200
+++ new/tail-tray-0.2.36/src/MainWindow.cpp     2026-10-03 12:27:17.000000000 
+0200
@@ -194,28 +194,26 @@
         pCurrentExecution->shutdown();
 }
 
+// Not showNormal(): on a visible window it asks to un-maximize, and 
compositors that treat
+// that request as a toggle (Hyprland) maximize the window instead.
+void MainWindow::showWindow() {
+    setWindowState(windowState() & ~Qt::WindowMinimized);
+    show();
+}
+
 void MainWindow::showSettingsTab() {
     ui->tabWidget->setCurrentIndex(1);
-    showNormal();
+    showWindow();
 }
 
 void MainWindow::showAccountsTab() {
     ui->tabWidget->setCurrentIndex(0);
-    showNormal();
-}
-
-void MainWindow::showAboutTab() {
-    auto tabIndex = 5;
-    if (settings.tailDriveEnabled())
-        tabIndex = 6;
-
-    ui->tabWidget->setCurrentIndex(tabIndex);
-    showNormal();
+    showWindow();
 }
 
 void MainWindow::showNetworkStatusTab() {
     ui->tabWidget->setCurrentIndex(2);
-    showNormal();
+    showWindow();
 }
 
 void MainWindow::tailscaleIsInstalled(bool installed) {
@@ -436,8 +434,8 @@
     pLoginInProgressDlg.reset();
 
     if (success) {
-        // And bring the settings tab front and center
-        showSettingsTab();
+        // Stay on the current tab: the login flow opened the Account tab, 
where the new account shows up
+        show();
 
         pCurrentExecution->start();
     } else {
@@ -807,6 +805,14 @@
 
     // Read settings, and it will be synced to UI once read
     pCurrentExecution->readSettings();
+    pTrayManager->windowVisibilityChanged(isVisible());
+}
+
+void MainWindow::hideEvent(QHideEvent *event) {
+    QMainWindow::hideEvent(event);
+
+    // A minimize also sends a hide event but leaves isVisible() true, as the 
tray item expects
+    pTrayManager->windowVisibilityChanged(isVisible());
 }
 
 void MainWindow::refreshThemebasedItems()
@@ -846,7 +852,6 @@
     if (didChangeState) {
         // If we're not connected, don't allow showing/changing tabs etc
         if (newState == TailState::Connected) {
-            ui->tabWidget->setCurrentIndex(1);
             ui->tabNetworkStatus->setDisabled(false);
             ui->tabSettings->setDisabled(false);
             ui->tabTailDrive->setDisabled(false);
@@ -923,6 +928,8 @@
     }
 
     accountsTabUi->onTailStatusChanged(pTailStatus);
+    if (eCurrentState == TailState::Connected)
+        pDevicesTabManager->syncToUi(pTailStatus);
 #if defined(DAVFS_ENABLED)
     pTailDriveUiManager->stateChangedTo(eCurrentState, pTailStatus);
 #endif
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/tail-tray-0.2.35/src/MainWindow.h 
new/tail-tray-0.2.36/src/MainWindow.h
--- old/tail-tray-0.2.35/src/MainWindow.h       2026-09-28 20:16:40.000000000 
+0200
+++ new/tail-tray-0.2.36/src/MainWindow.h       2026-10-03 12:27:17.000000000 
+0200
@@ -35,9 +35,9 @@
 
     void shutdown() const;
 
+    void showWindow();
     void showSettingsTab();
     void showAccountsTab();
-    void showAboutTab();
     void showNetworkStatusTab();
 
     void syncSettingsToUi() const;
@@ -122,6 +122,7 @@
 
 protected:
     void showEvent(QShowEvent* event) override;
+    void hideEvent(QHideEvent* event) override;
     bool event(QEvent* event) override;
 };
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/tail-tray-0.2.35/src/NotificationsManager.cpp 
new/tail-tray-0.2.36/src/NotificationsManager.cpp
--- old/tail-tray-0.2.35/src/NotificationsManager.cpp   2026-09-28 
20:16:40.000000000 +0200
+++ new/tail-tray-0.2.36/src/NotificationsManager.cpp   2026-10-03 
12:27:17.000000000 +0200
@@ -2,6 +2,11 @@
 
 #include <QDesktopServices>
 
+#if defined(KNOTIFICATIONS_ENABLED)
+// The app icon (as in tail-tray.desktop), so notifications read as Tail Tray's
+static const QString appIconName = QStringLiteral("tail-tray");
+#endif
+
 NotificationsManager::NotificationsManager(TrayMenuManager const* pTrayMgr, 
QObject* parent)
     : QObject(parent)
     , m_pTrayMgr(pTrayMgr)
@@ -16,7 +21,7 @@
     notification->setText(message);
 
     notification->setUrgency(KNotification::Urgency::LowUrgency);
-    notification->setIconName(iconName.isEmpty() ? 
QStringLiteral("notification-active") : iconName);
+    notification->setIconName(iconName.isEmpty() ? appIconName : iconName);
 
     notification->sendEvent();
 #else
@@ -38,12 +43,7 @@
     notification->setUrls(QList{fileUrl});
 
     notification->setUrgency(KNotification::Urgency::DefaultUrgency);
-    if (!iconName.isEmpty()) {
-        notification->setIconName(iconName);
-    }
-    else {
-        notification->setIconName("edit-image");
-    }
+    notification->setIconName(iconName.isEmpty() ? appIconName : iconName);
 
     notification->sendEvent();
 #else
@@ -59,7 +59,7 @@
     notification->setText(message);
 
     notification->setUrgency(KNotification::Urgency::NormalUrgency);
-    notification->setIconName(iconName.isEmpty() ? 
QStringLiteral("dialog-warning") : iconName);
+    notification->setIconName(iconName.isEmpty() ? appIconName : iconName);
 
     notification->sendEvent();
 #else
@@ -74,7 +74,7 @@
     notification->setText(message);
 
     notification->setUrgency(KNotification::Urgency::HighUrgency);
-    notification->setIconName(iconName.isEmpty() ? 
QStringLiteral("dialog-error") : iconName);
+    notification->setIconName(iconName.isEmpty() ? appIconName : iconName);
 
     notification->sendEvent();
 #else
@@ -90,7 +90,7 @@
     notification->setText(message);
 
     notification->setUrgency(KNotification::Urgency::CriticalUrgency);
-    notification->setIconName(iconName.isEmpty() ? 
QStringLiteral("dialog-error") : iconName);
+    notification->setIconName(iconName.isEmpty() ? appIconName : iconName);
 
     notification->sendEvent();
 #else
@@ -106,7 +106,7 @@
     notification->setText(tr("A new device have been discovered on your 
tailnet!\n\nDevice: %1 (%2) - %3")
         .arg(nodeName, ipAddress, os));
 
-    notification->setIconName("online");
+    notification->setIconName(appIconName);
     notification->sendEvent();
 #else
     m_pTrayMgr->trayIcon()->showMessage(tr("Tailnet Devices"),
@@ -123,7 +123,7 @@
     notification->setText(tr("A device have been removed from your 
tailnet!\n\nDevice: %1 (%2) - %3")
         .arg(nodeName, ipAddress, os));
 
-    notification->setIconName("offline");
+    notification->setIconName(appIconName);
     notification->sendEvent();
 #else
     m_pTrayMgr->trayIcon()->showMessage(tr("Tailnet Devices"),
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/tail-tray-0.2.35/src/NotificationsManager.h 
new/tail-tray-0.2.36/src/NotificationsManager.h
--- old/tail-tray-0.2.35/src/NotificationsManager.h     2026-09-28 
20:16:40.000000000 +0200
+++ new/tail-tray-0.2.36/src/NotificationsManager.h     2026-10-03 
12:27:17.000000000 +0200
@@ -28,9 +28,9 @@
     void showFileNotification(const QString& title, const QString& message, 
const QFileInfo& fileInfo,
         const QString& iconName = QString());
 
-    void showWarningNotification(const QString& title, const QString& message, 
const QString& iconName = QString("dialog-warning"));
-    void showErrorNotification(const QString& title, const QString& message, 
const QString& iconName = QString("dialog-error"));
-    void showCriticalNotification(const QString& title, const QString& 
message, const QString& iconName = QString("dialog-error"));
+    void showWarningNotification(const QString& title, const QString& message, 
const QString& iconName = QString());
+    void showErrorNotification(const QString& title, const QString& message, 
const QString& iconName = QString());
+    void showCriticalNotification(const QString& title, const QString& 
message, const QString& iconName = QString());
 
     void showNodeConnectedNotification(const QString& nodeName, const QString& 
ipAddress, const QString& os);
     void showNodeDisconnectedNotification(const QString& nodeName, const 
QString& ipAddress, const QString& os);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/tail-tray-0.2.35/src/SingleApplicationImpl.h 
new/tail-tray-0.2.36/src/SingleApplicationImpl.h
--- old/tail-tray-0.2.35/src/SingleApplicationImpl.h    2026-09-28 
20:16:40.000000000 +0200
+++ new/tail-tray-0.2.36/src/SingleApplicationImpl.h    2026-10-03 
12:27:17.000000000 +0200
@@ -3,6 +3,8 @@
 
 #include <QApplication>
 #include <QDir>
+#include <QLocalServer>
+#include <QLocalSocket>
 #include <QLockFile>
 #include <QStandardPaths>
 
@@ -11,7 +13,7 @@
 public:
     explicit SingleApplicationImpl(int &argc, char **argv)
         : QApplication(argc, argv)
-        , singleGuard(singleInstanceLockFilePath())
+        , singleGuard(runtimeFilePath("tail-tray.grenangen.se.lock"))
     {
         singleGuard.setStaleLockTime(0);
     }
@@ -26,19 +28,45 @@
     }
 
     [[nodiscard]] bool claimInstance() {
-        return singleGuard.tryLock(0);
+        if (!singleGuard.tryLock(0))
+            return false;
+
+        // Later launches connect here to ask this instance to show its 
window. Holding the lock
+        // means an existing socket is a crashed instance's leftover, which 
would fail listen().
+        QLocalServer::removeServer(activationSocketPath());
+        activationServer.listen(activationSocketPath());
+        connect(&activationServer, &QLocalServer::newConnection, this, 
[this]() {
+            activationServer.nextPendingConnection()->deleteLater();
+            emit activationRequested();
+        });
+
+        return true;
+    }
+
+    static void activateRunningInstance() {
+        QLocalSocket socket;
+        socket.connectToServer(activationSocketPath());
+        socket.waitForConnected(1000);
     }
 
+signals:
+    void activationRequested();
+
 private:
-    static QString singleInstanceLockFilePath() {
-        auto lockDir = 
QStandardPaths::writableLocation(QStandardPaths::RuntimeLocation);
-        if (lockDir.isEmpty())
-            lockDir = QDir::tempPath();
+    static QString runtimeFilePath(const QString& fileName) {
+        auto runtimeDir = 
QStandardPaths::writableLocation(QStandardPaths::RuntimeLocation);
+        if (runtimeDir.isEmpty())
+            runtimeDir = QDir::tempPath();
+
+        return QDir(runtimeDir).absoluteFilePath(fileName);
+    }
 
-        return QDir(lockDir).absoluteFilePath("tail-tray.grenangen.se.lock");
+    static QString activationSocketPath() {
+        return runtimeFilePath("tail-tray.grenangen.se.socket");
     }
 
     QLockFile singleGuard;
+    QLocalServer activationServer;
 };
 
 #endif
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/tail-tray-0.2.35/src/TailRunner.cpp 
new/tail-tray-0.2.36/src/TailRunner.cpp
--- old/tail-tray-0.2.35/src/TailRunner.cpp     2026-09-28 20:16:40.000000000 
+0200
+++ new/tail-tray-0.2.36/src/TailRunner.cpp     2026-10-03 12:27:17.000000000 
+0200
@@ -40,6 +40,12 @@
     }
 
     static BufferedProcessWrapper* pActiveLoginFlow = nullptr;
+
+    // `tailscale login` first moves to a new, empty profile; this is where a 
cancel goes back to
+    static QString accountBeforeLogin;
+
+    // Where a finished logout moves on to; empty when no other account is left
+    static QString accountAfterLogout;
 }
 
 TailRunner::TailRunner(const TailSettings& s, QObject* parent)
@@ -179,11 +185,16 @@
     args << "--operator" << qEnvironmentVariable("USER");
 #endif
 
+    if (pActiveLoginFlow == nullptr)
+        accountBeforeLogin = lastKnownStatus.user.loginName;
+
     runCommand(Command::Login, "login", args, false, true);
 }
 
-void TailRunner::logout() {
-    runCommand(Command::Logout, "logout", QStringList(), false, true);
+// Being the account's operator is enough to log out, so no pkexec here
+void TailRunner::logout(const QString& nextAccountId) {
+    accountAfterLogout = nextAccountId;
+    runCommand(Command::Logout, "logout", QStringList());
 }
 
 void TailRunner::cancelLoginFlow() {
@@ -191,7 +202,16 @@
         return;
     }
 
-    pActiveLoginFlow->cancel();
+    // The login runs as root through pkexec, so it can't be killed from here, 
and deleting its
+    // QProcess while it runs blocks the UI for 30s. Going back to the 
previous profile puts
+    // tailscaled in Running again, which ends `tailscale login`; its output 
is ignored from now.
+    auto* flow = pActiveLoginFlow;
+    pActiveLoginFlow = nullptr;
+    disconnect(flow, nullptr, this, nullptr);
+    connect(flow->process(), &QProcess::finished, flow, &QObject::deleteLater);
+
+    if (!accountBeforeLogin.isEmpty())
+        switchAccount(accountBeforeLogin);
 }
 
 void TailRunner::start(const bool usePkExec) {
@@ -503,6 +523,14 @@
         else if (commandInfo == Command::SendFile) {
             emit fileSent(true, QString{}, process->userData());
         }
+        else if (commandInfo == Command::Logout) {
+            // Tailscale is now on a blank account with no operator: only root 
can switch away,
+            // and the account list can't be read until a login sets the 
operator again
+            if (accountAfterLogout.isEmpty())
+                emit accountsListed({});
+            else
+                runCommand(Command::SwitchAccount, "switch", 
QStringList{accountAfterLogout}, false, true);
+        }
     }
 }
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/tail-tray-0.2.35/src/TailRunner.h 
new/tail-tray-0.2.36/src/TailRunner.h
--- old/tail-tray-0.2.35/src/TailRunner.h       2026-09-28 20:16:40.000000000 
+0200
+++ new/tail-tray-0.2.36/src/TailRunner.h       2026-10-03 12:27:17.000000000 
+0200
@@ -49,16 +49,6 @@
     [[nodiscard]] void* userData() const { return pUserData; }
     [[nodiscard]] bool isRunning() const { return proc != nullptr && 
proc->state() == QProcess::Running; }
 
-    void cancel(const bool raiseEvents = true) {
-        if (proc != nullptr) {
-            proc->terminate();
-        }
-
-        if (raiseEvents) {
-            emit processFinished(this, 0, QProcess::NormalExit);
-        }
-    }
-
 signals:
     void processErrorOccurred(BufferedProcessWrapper* wrapper, 
QProcess::ProcessError error);
     void processCanReadStdOut(BufferedProcessWrapper* process);
@@ -102,7 +92,7 @@
     void switchAccount(const QString& accountId);
 
     void login(const QString& customLoginUrl = "");
-    void logout();
+    void logout(const QString& nextAccountId);
     void cancelLoginFlow();
 
     void start(bool usePkExec = false);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/tail-tray-0.2.35/src/TrayMenuManager.cpp 
new/tail-tray-0.2.36/src/TrayMenuManager.cpp
--- old/tail-tray-0.2.35/src/TrayMenuManager.cpp        2026-09-28 
20:16:40.000000000 +0200
+++ new/tail-tray-0.2.36/src/TrayMenuManager.cpp        2026-10-03 
12:27:17.000000000 +0200
@@ -56,11 +56,12 @@
   pQuitAction = std::make_unique<QAction>(tr("Quit"));
   pLoginAction = std::make_unique<QAction>(tr("Login"));
   pLogoutAction = std::make_unique<QAction>(tr("Logout"));
-  pPreferences = std::make_unique<QAction>(tr("Preferences"));
-  pAbout = std::make_unique<QAction>(tr("About..."));
+  pShowHideWindow = std::make_unique<QAction>(tr("Show Window"));
   pConnected = std::make_unique<QAction>(tr("Connected"));
   pConnected->setEnabled(false);
   pConnect = std::make_unique<QAction>(tr("Connect"));
+  pConnecting = std::make_unique<QAction>(tr("Connecting..."));
+  pConnecting->setEnabled(false);
   pDisconnect = std::make_unique<QAction>(tr("Disconnect"));
   pThisDevice = std::make_unique<QAction>(tr("This device"));
   pExitNodeNone = std::make_unique<QAction>(tr("None"));
@@ -74,6 +75,10 @@
   stateChangedTo(TailState::NotLoggedIn, TailStatus{});
 }
 
+void TrayMenuManager::windowVisibilityChanged(bool visible) {
+  pShowHideWindow->setText(visible ? tr("Hide Window") : tr("Show Window"));
+}
+
 void TrayMenuManager::onAccountsListed(
     const QList<TailAccountInfo> &foundAccounts) {
   accounts = foundAccounts;
@@ -110,8 +115,7 @@
   pTrayMenu->clear();
   pTrayMenu->addAction(pLoginAction.get());
   disposableConnectedMenuActions.push_back(pTrayMenu->addSeparator());
-  pTrayMenu->addAction(pPreferences.get());
-  pTrayMenu->addAction(pAbout.get());
+  pTrayMenu->addAction(pShowHideWindow.get());
   disposableConnectedMenuActions.push_back(pTrayMenu->addSeparator());
   pTrayMenu->addAction(pQuitAction.get());
 }
@@ -120,7 +124,9 @@
     const TailStatus &pTailStatus) const {
   pSysTray->setIcon(themeManager.getDisconnectedTrayIcon());
   pTrayMenu->clear();
-  pTrayMenu->addAction(pConnect.get());
+  // Tailscale is already bringing the connection up, so Connect would do 
nothing
+  const bool connecting = pTailStatus.backendState == "Starting" || 
pTailStatus.backendState == "Running";
+  pTrayMenu->addAction(connecting ? pConnecting.get() : pConnect.get());
   disposableConnectedMenuActions.push_back(pTrayMenu->addSeparator());
 
   if (pTailStatus.user.id > 0)
@@ -132,8 +138,7 @@
   actions->addAction(pRestartTailscale.get());
   actions->addAction(pRefreshLocalDns.get());
   disposableConnectedMenuActions.push_back(pTrayMenu->addSeparator());
-  pTrayMenu->addAction(pPreferences.get());
-  pTrayMenu->addAction(pAbout.get());
+  pTrayMenu->addAction(pShowHideWindow.get());
   disposableConnectedMenuActions.push_back(pTrayMenu->addSeparator());
   pTrayMenu->addAction(pQuitAction.get());
 
@@ -489,8 +494,7 @@
           });
 
   disposableConnectedMenuActions.push_back(pTrayMenu->addSeparator());
-  pTrayMenu->addAction(pPreferences.get());
-  pTrayMenu->addAction(pAbout.get());
+  pTrayMenu->addAction(pShowHideWindow.get());
   disposableConnectedMenuActions.push_back(pTrayMenu->addSeparator());
   pTrayMenu->addAction(pQuitAction.get());
 
@@ -535,14 +539,13 @@
   connect(pDisconnect.get(), &QAction::triggered, this,
           [this](bool) { pTailRunner->stop(); });
 
-  connect(pPreferences.get(), &QAction::triggered, this, [this](bool) {
-    auto *wnd = dynamic_cast<MainWindow *>(this->parent());
-    wnd->showSettingsTab();
-  });
-
-  connect(pAbout.get(), &QAction::triggered, this, [this](bool) {
+  // Opens the window on whichever tab it was left on, or hides it when it's 
open
+  connect(pShowHideWindow.get(), &QAction::triggered, this, [this](bool) {
     auto *wnd = dynamic_cast<MainWindow *>(this->parent());
-    wnd->showAboutTab();
+    if (wnd->isVisible())
+      wnd->hide();
+    else
+      wnd->showWindow();
   });
 
   connect(pThisDevice.get(), &QAction::triggered, this, [this](bool) {
@@ -563,7 +566,7 @@
 
   connect(pSysTray.get(), &QSystemTrayIcon::activated, this,
           [this](QSystemTrayIcon::ActivationReason reason) {
-            auto *wnd = dynamic_cast<MainWindow *>(this->parent());
+            auto *wnd = dynamic_cast<MainWindow*>(this->parent());
             if (reason == QSystemTrayIcon::ActivationReason::Trigger) {
               if (wnd->isVisible())
                 wnd->hide();
@@ -571,7 +574,7 @@
                 // NOTE: When settings are read, they will call settings to UI
                 // so will be in sync on show
                 pTailRunner->readSettings();
-                wnd->showSettingsTab();
+                wnd->showWindow();
               }
             }
             else if (reason == QSystemTrayIcon::ActivationReason::MiddleClick) 
{
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/tail-tray-0.2.35/src/TrayMenuManager.h 
new/tail-tray-0.2.36/src/TrayMenuManager.h
--- old/tail-tray-0.2.35/src/TrayMenuManager.h  2026-09-28 20:16:40.000000000 
+0200
+++ new/tail-tray-0.2.36/src/TrayMenuManager.h  2026-10-03 12:27:17.000000000 
+0200
@@ -21,6 +21,7 @@
     explicit TrayMenuManager(TailSettings& s, TailRunner* runner, 
ThemeManager& tm,
                              ScriptManager* scriptManager, QObject* parent = 
nullptr);
 
+    void windowVisibilityChanged(bool visible);
     void onAccountsListed(const QList<TailAccountInfo>& foundAccounts);
     void stateChangedTo(TailState newState, const TailStatus& pTailStatus);
 
@@ -42,9 +43,9 @@
     std::unique_ptr<QAction> pLogoutAction;
     std::unique_ptr<QAction> pConnected;
     std::unique_ptr<QAction> pConnect;
+    std::unique_ptr<QAction> pConnecting;
     std::unique_ptr<QAction> pDisconnect;
-    std::unique_ptr<QAction> pPreferences;
-    std::unique_ptr<QAction> pAbout;
+    std::unique_ptr<QAction> pShowHideWindow;
     std::unique_ptr<QAction> pThisDevice;
     std::unique_ptr<QAction> pExitNodeNone;
     std::unique_ptr<QAction> pRefreshLocalDns;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/tail-tray-0.2.35/src/Version.h 
new/tail-tray-0.2.36/src/Version.h
--- old/tail-tray-0.2.35/src/Version.h  2026-09-28 20:16:40.000000000 +0200
+++ new/tail-tray-0.2.36/src/Version.h  2026-10-03 12:27:17.000000000 +0200
@@ -1,6 +1,6 @@
 #pragma once
 
-#define TAIL_TRAY_VERSION "0.2.35"
+#define TAIL_TRAY_VERSION "0.2.36"
 #define TAIL_TRAY_VERSION_MAJOR 0
 #define TAIL_TRAY_VERSION_MINOR 2
-#define TAIL_TRAY_VERSION_PATCH 35
+#define TAIL_TRAY_VERSION_PATCH 36
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/tail-tray-0.2.35/src/main.cpp 
new/tail-tray-0.2.36/src/main.cpp
--- old/tail-tray-0.2.35/src/main.cpp   2026-09-28 20:16:40.000000000 +0200
+++ new/tail-tray-0.2.36/src/main.cpp   2026-10-03 12:27:17.000000000 +0200
@@ -14,8 +14,12 @@
 
     SingleApplicationImpl a(argc, argv);
     if (!a.claimInstance()) {
-        qDebug() << "Secondary instance not allowed, will quit this instance";
-        return -1;
+        // --background (for autostart) only makes sure tail-tray runs, so the 
window stays put
+        if (!QCoreApplication::arguments().contains("--background")) {
+            qDebug() << "Already running, asking that instance to show its 
window";
+            SingleApplicationImpl::activateRunningInstance();
+        }
+        return 0;
     }
 
     QApplication::setQuitOnLastWindowClosed(false);
@@ -69,6 +73,7 @@
     }
 
     MainWindow w;
+    QObject::connect(&a, &SingleApplicationImpl::activationRequested, &w, 
&MainWindow::showWindow);
 
        // HACK: Workaround to make sure that the tray icon is updated 
correctly when style/theme changes
     {

++++++ tail-tray.obsinfo ++++++
--- /var/tmp/diff_new_pack.J7KknO/_old  2026-10-05 13:04:33.220187174 +0200
+++ /var/tmp/diff_new_pack.J7KknO/_new  2026-10-05 13:04:33.225187384 +0200
@@ -1,5 +1,5 @@
 name: tail-tray
-version: 0.2.35
-mtime: 1790619400
-commit: 577bcb0d72dd5ca8a055c05581ab78dc8c0150b4
+version: 0.2.36
+mtime: 1791023237
+commit: f46cbe5929582dfdbd505d632a80635d1438e24a
 

Reply via email to