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 2025-05-07 19:22:22 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/tail-tray (Old) and /work/SRC/openSUSE:Factory/.tail-tray.new.30101 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "tail-tray" Wed May 7 19:22:22 2025 rev:16 rq:1275319 version:0.2.22 Changes: -------- --- /work/SRC/openSUSE:Factory/tail-tray/tail-tray.changes 2025-04-29 16:42:03.318411053 +0200 +++ /work/SRC/openSUSE:Factory/.tail-tray.new.30101/tail-tray.changes 2025-05-07 19:22:31.894411313 +0200 @@ -1,0 +2,28 @@ +Wed May 07 15:43:17 UTC 2025 - Johannes Kastl <opensuse_buildserv...@ojkastl.de> + +- Update to version 0.2.22: + * What's new in this release + This release has some new Notification handling if you are + building and running it for KDE Plasma 6 or later, using this + feature will give you fancy notification integrations into your + Plasma Desktop. + It also comes with the regular flow of bug fixes, most notable + are fixes around potential segfaults, that hopefully should be + fully resolved now + * Commits + - [Issue #36] - Use KNotification framework for notifications + (#73) (Marcus Grenängen) #73 + - Test to build on kdeneon/plasma:user (Marcus Grenängen) + - Revert "Test to build on kdeneon/plasma:user" (Marcus + Grenängen) + - gh runner (Marcus Grenängen) + - Revert "gh runner" (Marcus Grenängen) + - KNOTIFICATIONS_ENABLED=OFF to have it still build for ubuntu + 24.04 and Debian stable (Marcus Grenängen) + - Fix for potential segfault due to double free + code + readability fix/cleanup (Marcus Grenängen) + - Ignore .cache dir (Marcus Grenängen) + - Fix segfault for Issue #75 (Marcus Grenängen) + - Bump version to 0.2.22 (Marcus Grenängen) + +------------------------------------------------------------------- @@ -5 +33 @@ - * What's new in this release 🎉 + * What's new in this release Old: ---- tail-tray-0.2.21.obscpio New: ---- tail-tray-0.2.22.obscpio ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ tail-tray.spec ++++++ --- /var/tmp/diff_new_pack.v354Ro/_old 2025-05-07 19:22:32.422433362 +0200 +++ /var/tmp/diff_new_pack.v354Ro/_new 2025-05-07 19:22:32.422433362 +0200 @@ -17,7 +17,7 @@ Name: tail-tray -Version: 0.2.21 +Version: 0.2.22 Release: 0 Summary: Tailscale tray menu and UI for the KDE Plasma Desktop License: GPL-3.0-only ++++++ _service ++++++ --- /var/tmp/diff_new_pack.v354Ro/_old 2025-05-07 19:22:32.458434866 +0200 +++ /var/tmp/diff_new_pack.v354Ro/_new 2025-05-07 19:22:32.462435033 +0200 @@ -2,8 +2,8 @@ <service name="obs_scm" mode="manual"> <param name="url">https://github.com/SneWs/tail-tray</param> <param name="scm">git</param> - <param name="revision">refs/tags/v0.2.21</param> - <param name="match-tag">v0.2.21</param> + <param name="revision">refs/tags/v0.2.22</param> + <param name="match-tag">v0.2.22</param> <param name="versionformat">@PARENT_TAG@</param> <param name="versionrewrite-pattern">v(.*)</param> <param name="changesgenerate">enable</param> ++++++ _servicedata ++++++ --- /var/tmp/diff_new_pack.v354Ro/_old 2025-05-07 19:22:32.490436203 +0200 +++ /var/tmp/diff_new_pack.v354Ro/_new 2025-05-07 19:22:32.494436370 +0200 @@ -1,6 +1,6 @@ <servicedata> <service name="tar_scm"> <param name="url">https://github.com/SneWs/tail-tray</param> - <param name="changesrevision">5bf5ad3aab9f6940dab6ec35e7bb5c366ffab9b5</param></service></servicedata> + <param name="changesrevision">124e20bae18e886553d44a2bd85ee60f8e8f0502</param></service></servicedata> (No newline at EOF) ++++++ tail-tray-0.2.21.obscpio -> tail-tray-0.2.22.obscpio ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tail-tray-0.2.21/.github/workflows/cmake-multi-platform.yml new/tail-tray-0.2.22/.github/workflows/cmake-multi-platform.yml --- old/tail-tray-0.2.21/.github/workflows/cmake-multi-platform.yml 2025-04-25 23:50:35.000000000 +0200 +++ new/tail-tray-0.2.22/.github/workflows/cmake-multi-platform.yml 2025-05-07 15:30:19.000000000 +0200 @@ -47,6 +47,7 @@ echo "Running Linux build" cmake -B ${{ steps.strings.outputs.build-output-dir }} \ -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} \ + -DKNOTIFICATIONS_ENABLED=OFF \ -S ${{ github.workspace }} \ -G "Unix Makefiles" # Use Unix Makefiles for Ubuntu shell: bash # This makes sure we use Bash on both platforms. @@ -56,7 +57,7 @@ run: | echo "Running Windows build" echo "Build output directory: ${{ steps.strings.outputs.build-output-dir }}" - cmake -B ${{ steps.strings.outputs.build-output-dir }} -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} -S ${{ github.workspace }} -G "Visual Studio 17 2022" + cmake -B ${{ steps.strings.outputs.build-output-dir }} -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} -DKNOTIFICATIONS_ENABLED=OFF -S ${{ github.workspace }} -G "Visual Studio 17 2022" shell: pwsh - name: Build diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tail-tray-0.2.21/.github/workflows/tagged-releases.yml new/tail-tray-0.2.22/.github/workflows/tagged-releases.yml --- old/tail-tray-0.2.21/.github/workflows/tagged-releases.yml 2025-04-25 23:50:35.000000000 +0200 +++ new/tail-tray-0.2.22/.github/workflows/tagged-releases.yml 2025-05-07 15:30:19.000000000 +0200 @@ -56,6 +56,7 @@ -DCMAKE_CXX_COMPILER=${{ matrix.cpp_compiler }} -DCMAKE_C_COMPILER=${{ matrix.c_compiler }} -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} + -DKNOTIFICATIONS_ENABLED=OFF -S ${{ github.workspace }} - name: Build diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tail-tray-0.2.21/.gitignore new/tail-tray-0.2.22/.gitignore --- old/tail-tray-0.2.21/.gitignore 2025-04-25 23:50:35.000000000 +0200 +++ new/tail-tray-0.2.22/.gitignore 2025-05-07 15:30:19.000000000 +0200 @@ -14,6 +14,7 @@ build/ cmake-build-debug/ cmake-build-release/ +.cache/ packaging/ .flatpak-builder/ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tail-tray-0.2.21/.vscode/launch.json new/tail-tray-0.2.22/.vscode/launch.json --- old/tail-tray-0.2.21/.vscode/launch.json 2025-04-25 23:50:35.000000000 +0200 +++ new/tail-tray-0.2.22/.vscode/launch.json 2025-05-07 15:30:19.000000000 +0200 @@ -5,7 +5,7 @@ "version": "0.2.0", "configurations": [ { - "name": "(Windows) Launch", + "name": "(Debug) Launch", "type": "cppdbg", "request": "launch", "args": [], diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tail-tray-0.2.21/CMakeLists.txt new/tail-tray-0.2.22/CMakeLists.txt --- old/tail-tray-0.2.21/CMakeLists.txt 2025-04-25 23:50:35.000000000 +0200 +++ new/tail-tray-0.2.22/CMakeLists.txt 2025-05-07 15:30:19.000000000 +0200 @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 3.21) -project(tail-tray VERSION 0.2.21 LANGUAGES CXX) +project(tail-tray VERSION 0.2.22 LANGUAGES CXX) set(CMAKE_AUTOUIC ON) set(CMAKE_AUTOMOC ON) @@ -31,56 +31,74 @@ find_package(QT NAMES Qt6 REQUIRED COMPONENTS Widgets Network LinguistTools) find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets Network LinguistTools) +# Use KNotifications +option(KNOTIFICATIONS_ENABLED "Enable KNotifications" OFF) +if (KNOTIFICATIONS_ENABLED) + message("KNotifications has been enabled! This requires Plasma 6") + + find_package(ECM REQUIRED NO_MODULE) + set(CMAKE_MODULE_PATH ${ECM_MODULE_PATH}) + include(KDEInstallDirs) + include(KDECMakeSettings) + + add_definitions(-DKNOTIFICATIONS_ENABLED) + find_package(KF6Notifications) +else () + message("KNotifications has not been enabled!") +endif (KNOTIFICATIONS_ENABLED) + set(PROJECT_SOURCES - src/main.cpp - src/MainWindow.cpp - src/MainWindow.h - src/MainWindow.ui - resources.qrc - src/models/TailAccountInfo.h - src/models/TailDeviceInfo.h - src/models/TailUser.h - src/models/TailNetInfo.h - src/models/TailDriveInfo.h - src/models/TailStatus.h - src/models/TailState.h - src/models/TailDnsStatus.h - src/models/CurrentTailPrefs.h - src/models/JsonHelpers.h - src/models/Models.h - src/models/IpnEvents.h - src/TrayMenuManager.cpp - src/TrayMenuManager.h - src/TailSettings.cpp - src/TailSettings.h - src/AccountsTabUiManager.cpp - src/AccountsTabUiManager.h - src/SysCommand.cpp - src/SysCommand.h - src/KnownValues.h - src/TailFileReceiver.cpp - src/TailFileReceiver.h - src/TailRunner.h - src/TailRunner.cpp - src/TailDriveUiManager.h - src/TailDriveUiManager.cpp - src/ManageDriveWindow.h - src/ManageDriveWindow.cpp - src/ManageDriveWindow.ui - src/NetworkStateMonitor.cpp - src/NetworkStateMonitor.h - src/AdvertiseRoutesDlg.h - src/AdvertiseRoutesDlg.cpp - src/AdvertiseRoutesDlg.ui - src/DnsSettingsDlg.h - src/DnsSettingsDlg.cpp - src/DnsSettingsDlg.ui - src/IpnWatcher.cpp - src/IpnWatcher.h - src/SingleApplicationImpl.h - src/PleaseWaitDlg.h - src/PleaseWaitDlg.cpp - src/PleaseWaitDlg.ui + src/main.cpp + src/MainWindow.cpp + src/MainWindow.h + src/MainWindow.ui + resources.qrc + src/models/TailAccountInfo.h + src/models/TailDeviceInfo.h + src/models/TailUser.h + src/models/TailNetInfo.h + src/models/TailDriveInfo.h + src/models/TailStatus.h + src/models/TailState.h + src/models/TailDnsStatus.h + src/models/CurrentTailPrefs.h + src/models/JsonHelpers.h + src/models/Models.h + src/models/IpnEvents.h + src/TrayMenuManager.cpp + src/TrayMenuManager.h + src/TailSettings.cpp + src/TailSettings.h + src/AccountsTabUiManager.cpp + src/AccountsTabUiManager.h + src/SysCommand.cpp + src/SysCommand.h + src/KnownValues.h + src/TailFileReceiver.cpp + src/TailFileReceiver.h + src/TailRunner.h + src/TailRunner.cpp + src/TailDriveUiManager.h + src/TailDriveUiManager.cpp + src/ManageDriveWindow.h + src/ManageDriveWindow.cpp + src/ManageDriveWindow.ui + src/NetworkStateMonitor.cpp + src/NetworkStateMonitor.h + src/AdvertiseRoutesDlg.h + src/AdvertiseRoutesDlg.cpp + src/AdvertiseRoutesDlg.ui + src/DnsSettingsDlg.h + src/DnsSettingsDlg.cpp + src/DnsSettingsDlg.ui + src/IpnWatcher.cpp + src/IpnWatcher.h + src/SingleApplicationImpl.h + src/PleaseWaitDlg.h + src/PleaseWaitDlg.cpp + src/PleaseWaitDlg.ui + src/NotificationsManager.h + src/NotificationsManager.cpp ) if (APPLE) @@ -128,7 +146,18 @@ ) qt_standard_project_setup(I18N_TRANSLATED_LANGUAGES en_US sv_SE de_DE fr_FR) -target_link_libraries(tail-tray PRIVATE Qt${QT_VERSION_MAJOR}::Widgets Qt${QT_VERSION_MAJOR}::Network) +target_link_libraries( + tail-tray PRIVATE + Qt${QT_VERSION_MAJOR}::Widgets + Qt${QT_VERSION_MAJOR}::Network +) + +if (KNOTIFICATIONS_ENABLED) + target_link_libraries( + tail-tray PRIVATE + KF6::Notifications + ) +endif (KNOTIFICATIONS_ENABLED) configure_file(src/Paths.h.in ${CMAKE_SOURCE_DIR}/src/Paths.h @ONLY) @@ -152,6 +181,10 @@ DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/applications ) +if (KNOTIFICATIONS_ENABLED) + install(FILES "tail-tray.notifyrc" DESTINATION ${KDE_INSTALL_KNOTIFYRCDIR}) +endif (KNOTIFICATIONS_ENABLED) + install(FILES "${CMAKE_BINARY_DIR}/tail_tray_en_US.qm" "${CMAKE_BINARY_DIR}/tail_tray_sv_SE.qm" "${CMAKE_BINARY_DIR}/tail_tray_fr_FR.qm" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tail-tray-0.2.21/debian/changelog new/tail-tray-0.2.22/debian/changelog --- old/tail-tray-0.2.21/debian/changelog 2025-04-25 23:50:35.000000000 +0200 +++ new/tail-tray-0.2.22/debian/changelog 2025-05-07 15:30:19.000000000 +0200 @@ -1,4 +1,4 @@ -tail-tray (0.2.21) UNRELEASED; urgency=medium +tail-tray (0.2.22) UNRELEASED; urgency=medium * New upstream release. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tail-tray-0.2.21/docs/build-from-src.md new/tail-tray-0.2.22/docs/build-from-src.md --- old/tail-tray-0.2.21/docs/build-from-src.md 2025-04-25 23:50:35.000000000 +0200 +++ new/tail-tray-0.2.22/docs/build-from-src.md 2025-05-07 15:30:19.000000000 +0200 @@ -3,17 +3,17 @@ * Git, QT 6, cmake and a c++ compiler, for example: * On Ubuntu and Ubuntu based distros ```bash - sudo apt install git qt6-tools-dev qt6-tools-dev-tools g++ clang cmake davfs2 + sudo apt install git qt6-tools-dev qt6-tools-dev-tools g++ clang cmake davfs2 extra-cmake-modules ``` * On Fedora ```bash - sudo dnf install -y git g++ clang cmake qt6-qtbase-devel qt6-qttools-devel qt6-qtbase-private-devel davfs2 + sudo dnf install -y git g++ clang cmake qt6-qtbase-devel qt6-qttools-devel qt6-qtbase-private-devel davfs2 extra-cmake-modules ``` * On Arch Linux * You can use the AUR package from here https://aur.archlinux.org/packages/tail-tray-git provided by @HeavenVolkoff * or, build it from source yourself: ```bash - sudo pacman -S git clang cmake qt6-base qt6-tools + sudo pacman -S git clang cmake qt6-base qt6-tools extra-cmake-modules ``` ```bash # For davfs2 we need to use the AUR @@ -25,8 +25,10 @@ * If you are running Gnome and not using Ubuntu, make sure to install AppIndicator so you can see your tray icons. See https://extensions.gnome.org/extension/615/appindicator-support/ 2. Clone the repo 3. cd into the repo `cd tail-tray` -4. Run `cmake -B "./build" -DCMAKE_BUILD_TYPE="Release"` - * If you want to disable DAVFS: `cmake -B "./build" -DDAVFS_ENABLED=OFF -DCMAKE_BUILD_TYPE="Release"` + * NOTE: There are several options that can be toggled ON/OFF dep on needs and wants. + * For exampel: `KNOTIFICATIONS_ENABLED` to use rich notifications, this requires KDE Plasma 6 and later with KNotification support +4. Run `cmake -B "./build" -DKNOTIFICATIONS_ENABLED=ON -DCMAKE_BUILD_TYPE="Release"` + * If you want to disable DAVFS: `cmake -B "./build" -DDAVFS_ENABLED=OFF -DKNOTIFICATIONS_ENABLED=ON -DCMAKE_BUILD_TYPE="Release"` 5. Run `cmake --build "./build" --config Release` 6. Run `cd build` 7. Run `sudo make install` diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tail-tray-0.2.21/src/MainWindow.cpp new/tail-tray-0.2.22/src/MainWindow.cpp --- old/tail-tray-0.2.21/src/MainWindow.cpp 2025-04-25 23:50:35.000000000 +0200 +++ new/tail-tray-0.2.22/src/MainWindow.cpp 2025-05-07 15:30:19.000000000 +0200 @@ -1,6 +1,5 @@ #include <QDir> #include <QFile> -#include <QDialog> #include "MainWindow.h" #include "Paths.h" @@ -24,20 +23,18 @@ , pTrayManager(nullptr) , pCurrentExecution(nullptr) , pLoginInProgressDlg(nullptr) - , pTailStatus() , pFileReceiver(nullptr) - , eCurrentState(TailState::NoAccount) , pNetworkStateMonitor(std::make_unique<NetworkStateMonitor>(this)) , pIpnWatcher(std::make_unique<IpnWatcher>(this)) - , pDnsStatus() -#if defined(DAVFS_ENABLED) - , pTailDriveUiManager() -#endif + , eCurrentState(TailState::NoAccount) , settings(this) { ui->setupUi(this); pCurrentExecution = std::make_unique<TailRunner>(settings, this); + accountsTabUi = std::make_unique<AccountsTabUiManager>(ui.get(), pCurrentExecution.get(), this); + pTrayManager = std::make_unique<TrayMenuManager>(settings, pCurrentExecution.get(), this); + pNotificationsManager = std::make_unique<NotificationsManager>(pTrayManager.get(), this); // Remove the tail drive tab by default ui->tabWidget->removeTab(2); @@ -79,8 +76,7 @@ connect(ui->btnAdvertiseRoutes, &QPushButton::clicked, this, &MainWindow::showAdvertiseRoutesDialog); connect(ui->btnTailscaleDnsSettings, &QPushButton::clicked, this, &MainWindow::showDnsSettingsDialog); - accountsTabUi = std::make_unique<AccountsTabUiManager>(ui.get(), pCurrentExecution.get(), this); - pTrayManager = std::make_unique<TrayMenuManager>(settings, pCurrentExecution.get(), this); + connect(pTrayManager.get(), &TrayMenuManager::ipAddressCopiedToClipboard, this, &MainWindow::ipAddressCopiedToClipboard); changeToState(TailState::NotLoggedIn); @@ -365,6 +361,11 @@ pCurrentExecution->bootstrap(); } +void MainWindow::ipAddressCopiedToClipboard(const QString& ipAddress, const QString& hostname) { + pNotificationsManager->showNotification(tr("IP address copied"), + "IP Address " + ipAddress + " for " + hostname + " have been copied to clipboard!"); +} + #if defined(DAVFS_ENABLED) void MainWindow::drivesListed(const QList<TailDriveInfo>& drives, bool error, const QString& errorMsg) { if (error) { @@ -395,7 +396,7 @@ void MainWindow::fileSentToDevice(bool success, const QString& errorMsg, void* userData) const { if (!success) { - pTrayManager->trayIcon()->showMessage(tr("Failed to send file"), errorMsg, QSystemTrayIcon::MessageIcon::Critical, 5000); + pNotificationsManager->showErrorNotification(tr("Failed to send file"), errorMsg); } if (userData == nullptr) { @@ -403,9 +404,10 @@ } auto userDataStr = static_cast<QString*>(userData); - pTrayManager->trayIcon()->showMessage(tr("File sent"), *userDataStr, QSystemTrayIcon::MessageIcon::Information, 5000); + QFileInfo fileInfo(*userDataStr); + pNotificationsManager->showFileNotification(tr("File sent"), + tr("The file %1 has been sent!").arg(*userDataStr), fileInfo); - // We need to delete this here delete userDataStr; } @@ -419,17 +421,15 @@ connect(pFileReceiver.get(), &TailFileReceiver::errorListening, this, [this](const QString& errorMsg) { - pTrayManager->trayIcon()->showMessage(tr("Error"), errorMsg, - QSystemTrayIcon::MessageIcon::Critical, 5000); + pNotificationsManager->showErrorNotification(tr("Error"), errorMsg); }); } void MainWindow::onTailnetFileReceived(QString filePath) const { const QFileInfo file(filePath); - const QString msg("File " + file.fileName() + " was received and saved in " + file.absolutePath()); - - pTrayManager->trayIcon()->showMessage(tr("File received"), msg, - QSystemTrayIcon::MessageIcon::Information, 8000); + pNotificationsManager->showFileNotification(tr("File received"), + tr("File %1 has been saved in %2").arg(file.fileName()).arg(file.absolutePath()), + file); } void MainWindow::onShowTailFileSaveLocationPicker() { @@ -565,7 +565,7 @@ } } - pTrayManager->trayIcon()->showMessage(title, message, QSystemTrayIcon::MessageIcon::Warning, 5000); + pNotificationsManager->showWarningNotification(title, message); } void MainWindow::showErrorMessage(const QString& title, const QString& message, bool timeLimited) { @@ -583,7 +583,7 @@ } } - pTrayManager->trayIcon()->showMessage(title, message, QSystemTrayIcon::MessageIcon::Critical, 5000); + pNotificationsManager->showErrorNotification(title, message); } bool MainWindow::isTailDriveFileAlreadySetup() { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tail-tray-0.2.21/src/MainWindow.h new/tail-tray-0.2.22/src/MainWindow.h --- old/tail-tray-0.2.21/src/MainWindow.h 2025-04-25 23:50:35.000000000 +0200 +++ new/tail-tray-0.2.22/src/MainWindow.h 2025-05-07 15:30:19.000000000 +0200 @@ -17,6 +17,7 @@ #include "IpnWatcher.h" #include "models/TailStatus.h" #include "PleaseWaitDlg.h" +#include "NotificationsManager.h" #if defined(DAVFS_ENABLED) #include "TailDriveUiManager.h" @@ -56,6 +57,7 @@ #if defined(DAVFS_ENABLED) std::unique_ptr<TailDriveUiManager> pTailDriveUiManager; #endif + std::unique_ptr<NotificationsManager> pNotificationsManager; TailState eCurrentState; TailSettings settings; @@ -73,6 +75,7 @@ void loginFlowStarting(const QString& loginUrl); void loginFlowCompleted(bool success = true); void onIpnEvent(const IpnEventData& eventData); + void ipAddressCopiedToClipboard(const QString& ipAddress, const QString& hostname); #if defined(DAVFS_ENABLED) void drivesListed(const QList<TailDriveInfo>& drives, bool error, const QString& errorMsg); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tail-tray-0.2.21/src/NotificationsManager.cpp new/tail-tray-0.2.22/src/NotificationsManager.cpp --- old/tail-tray-0.2.21/src/NotificationsManager.cpp 1970-01-01 01:00:00.000000000 +0100 +++ new/tail-tray-0.2.22/src/NotificationsManager.cpp 2025-05-07 15:30:19.000000000 +0200 @@ -0,0 +1,98 @@ +#include "NotificationsManager.h" + +#include <QDesktopServices> + +NotificationsManager::NotificationsManager(TrayMenuManager const* pTrayMgr, QObject* parent) + : QObject(parent) + , m_pTrayMgr(pTrayMgr) +{ } + +NotificationsManager::~NotificationsManager() = default; + +void NotificationsManager::showNotification(const QString& title, const QString& message, const QString& iconName) { +#if defined(KNOTIFICATIONS_ENABLED) + auto* notification = new KNotification("BasicNotification", KNotification::NotificationFlag::CloseOnTimeout, this); + notification->setTitle(title); + notification->setText(message); + + notification->setUrgency(KNotification::Urgency::DefaultUrgency); + if (!iconName.isEmpty()) { + notification->setIconName(iconName); + } + else { + notification->setIconName("notification-active"); + } + + notification->sendEvent(); +#else + m_pTrayMgr->trayIcon()->showMessage(title, message, + QSystemTrayIcon::MessageIcon::Information, 5000); +#endif +} + +void NotificationsManager::showFileNotification(const QString& title, const QString& message, const QFileInfo& fileInfo, + const QString& iconName) { + +#if defined(KNOTIFICATIONS_ENABLED) + auto* notification = new KNotification("FileTransfer", KNotification::NotificationFlag::CloseOnTimeout, this); + notification->setTitle(title); + notification->setText(message); + + // Setting the file URI will trigger the hamburger menu where one can select to open the file etc + QUrl fileUrl("file://" + fileInfo.absoluteFilePath()); + notification->setUrls(QList{fileUrl}); + + notification->setUrgency(KNotification::Urgency::DefaultUrgency); + if (!iconName.isEmpty()) { + notification->setIconName(iconName); + } + else { + notification->setIconName("edit-image"); + } + + notification->sendEvent(); +#else + m_pTrayMgr->trayIcon()->showMessage(title, message, + QSystemTrayIcon::MessageIcon::Information, 5000); +#endif +} + +void NotificationsManager::showWarningNotification(const QString& title, const QString& message, const QString& iconName) { +#if defined(KNOTIFICATIONS_ENABLED) + auto* notification = new KNotification("BasicNotification", KNotification::NotificationFlag::CloseOnTimeout, this); + notification->setTitle(title); + notification->setText(message); + + notification->setUrgency(KNotification::Urgency::DefaultUrgency); + if (!iconName.isEmpty()) { + notification->setIconName(iconName); + } + else { + notification->setIconName("dialog-warning"); + } + + notification->sendEvent(); +#else + m_pTrayMgr->trayIcon()->showMessage(title, message, QSystemTrayIcon::Warning, 5000); +#endif +} + +void NotificationsManager::showErrorNotification(const QString& title, const QString& message, const QString& iconName) { +#if defined(KNOTIFICATIONS_ENABLED) + auto* notification = new KNotification("BasicNotification", KNotification::NotificationFlag::CloseOnTimeout, this); + notification->setTitle(title); + notification->setText(message); + + notification->setUrgency(KNotification::Urgency::DefaultUrgency); + if (!iconName.isEmpty()) { + notification->setIconName(iconName); + } + else { + notification->setIconName("dialog-error"); + } + + notification->sendEvent(); +#else + m_pTrayMgr->trayIcon()->showMessage(title, message, QSystemTrayIcon::Critical, 5000); +#endif +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tail-tray-0.2.21/src/NotificationsManager.h new/tail-tray-0.2.22/src/NotificationsManager.h --- old/tail-tray-0.2.21/src/NotificationsManager.h 1970-01-01 01:00:00.000000000 +0100 +++ new/tail-tray-0.2.22/src/NotificationsManager.h 2025-05-07 15:30:19.000000000 +0200 @@ -0,0 +1,30 @@ +#ifndef NOTIFICATIONS_MANAGER +#define NOTIFICATIONS_MANAGER + +#include <QFileInfo> + +#if defined(KNOTIFICATIONS_ENABLED) +#include <KNotification> +#endif + +#include "TrayMenuManager.h" + +class NotificationsManager : public QObject +{ + Q_OBJECT +public: + explicit NotificationsManager(TrayMenuManager const* pTrayMgr, QObject* parent = nullptr); + ~NotificationsManager() override; + + void showNotification(const QString &title, const QString& message, const QString& iconName = QString()); + 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")); + +private: + TrayMenuManager const* m_pTrayMgr; +}; + +#endif // NOTIFICATIONS_MANAGER diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tail-tray-0.2.21/src/TailRunner.cpp new/tail-tray-0.2.22/src/TailRunner.cpp --- old/tail-tray-0.2.21/src/TailRunner.cpp 2025-04-25 23:50:35.000000000 +0200 +++ new/tail-tray-0.2.22/src/TailRunner.cpp 2025-05-07 15:30:19.000000000 +0200 @@ -39,37 +39,24 @@ return "Unknown (Not mapped) command (" + QString::number(static_cast<int>(cmd)) + ")"; } + static BufferedProcessWrapper* pActiveLoginFlow = nullptr; } TailRunner::TailRunner(const TailSettings& s, QObject* parent) : QObject(parent) , settings(s) - , processes() , currentPrefs() { } TailRunner::~TailRunner() { - runCompletedCleanup(); } void TailRunner::shutdown() { // Kill off any pending process calls, this is needed in cases such as: // - When the user is in a pending login state, then the process is waiting for user to complete web auth flows - - for (const auto& proc : processes) { - auto* p = proc->process(); - if (!p) - continue; - - if (p->state() == QProcess::Running) { - p->terminate(); - p->close(); - } - } - - runCompletedCleanup(); + cancelLoginFlow(); } void TailRunner::checkIfInstalled() { @@ -199,11 +186,11 @@ } void TailRunner::cancelLoginFlow() { - for (const auto& proc : processes) { - if (proc->command() == Command::Login) { - proc->cancel(); - } + if (pActiveLoginFlow == nullptr) { + return; } + + pActiveLoginFlow->cancel(); } void TailRunner::start(const bool usePkExec) { @@ -262,11 +249,16 @@ } void TailRunner::runCommand(const Command cmdType, const QString& cmd, const QStringList& args, const bool jsonResult, const bool usePkExec, void* userData) { - if (hasPendingCommandOfType(cmdType)) + auto isLoginCmd = cmdType == Command::Login; + if (isLoginCmd && pActiveLoginFlow != nullptr) { + // Already in a login flow... return; + } - auto wrapper = new BufferedProcessWrapper(cmdType, cmdType == Command::Login, this); - processes.emplace_back(wrapper); + auto wrapper = new BufferedProcessWrapper(cmdType, isLoginCmd, this); + if (isLoginCmd) { + pActiveLoginFlow = wrapper; + } connect(wrapper, &BufferedProcessWrapper::processErrorOccurred, this, &TailRunner::onProcessErrorOccurred); @@ -283,7 +275,7 @@ wrapper->start(cmd, args, jsonResult, usePkExec, userData); } -void TailRunner::onProcessCanReadStdOut(const BufferedProcessWrapper* wrapper) { +void TailRunner::onProcessCanReadStdOut(BufferedProcessWrapper* wrapper) { const auto data = wrapper->process()->readAllStandardOutput(); // Parse the status object @@ -372,7 +364,7 @@ } } -void TailRunner::onProcessCanReadStandardError(const BufferedProcessWrapper* wrapper) { +void TailRunner::onProcessCanReadStandardError(BufferedProcessWrapper* wrapper) { const auto commandInfo = wrapper->command(); // NOTE! For whatever reason, the login command output is not captured by the readyReadStandardOutput signal @@ -433,7 +425,7 @@ } } -void TailRunner::onProcessErrorOccurred(const BufferedProcessWrapper* wrapper, QProcess::ProcessError error) { +void TailRunner::onProcessErrorOccurred(BufferedProcessWrapper* wrapper, QProcess::ProcessError error) { const auto commandInfo = wrapper->command(); qDebug() << "Command" << commandToString(commandInfo) << "failed to execute!"; qDebug() << "Command error" << error; @@ -441,14 +433,21 @@ if (commandInfo == Command::CheckIfInstalled) { emit tailscaleIsInstalled(false); } - - runCompletedCleanup(); } -void TailRunner::onProcessFinished(const BufferedProcessWrapper* process, int exitCode, const QProcess::ExitStatus exitStatus) { - //qDebug() << "Process exit code " << exitCode << " - " << exitStatus; +void TailRunner::onProcessFinished(BufferedProcessWrapper* process, int exitCode, const QProcess::ExitStatus exitStatus) { + qDebug() << "Process exit code " << exitCode << " - " << exitStatus; + + //runCompletedCleanup(); + process->deleteLater(); const auto commandInfo = process->command(); + + // Reset login flow tracking ptr + if (commandInfo == Command::Login) { + pActiveLoginFlow = nullptr; + } + if (exitCode != 0) { if (commandInfo == Command::Connect || commandInfo == Command::Disconnect) { // If we failed to connect or disconnect we probably need to invoke pkexec @@ -505,8 +504,6 @@ emit fileSent(true, QString{}, process->userData()); } } - - runCompletedCleanup(); } void TailRunner::parseStatusResponse(const QJsonObject& obj) { @@ -517,31 +514,6 @@ currentPrefs = CurrentTailPrefs::parse(obj); } -bool TailRunner::hasPendingCommandOfType(const Command cmdType) const { - for (const auto* process : processes) { - if (process->command() == cmdType && process->isRunning()) - return true; - } - - return false; -} - -void TailRunner::runCompletedCleanup() { - for (auto it = processes.begin(); it != processes.end();) { - if (!(*it)->isRunning()) { - const auto cmd = commandToString((*it)->command()); - qDebug() << "Cleaning up process " << cmd; - - delete (*it); - it = processes.erase(it); - qDebug() << "Processes active: " << processes.size(); - } - else { - ++it; - } - } -} - //////////////////////////////////////////////////////////////////////////////////////////////////// // ProcessWrapper impl diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tail-tray-0.2.21/src/TailRunner.h new/tail-tray-0.2.22/src/TailRunner.h --- old/tail-tray-0.2.21/src/TailRunner.h 2025-04-25 23:50:35.000000000 +0200 +++ new/tail-tray-0.2.22/src/TailRunner.h 2025-05-07 15:30:19.000000000 +0200 @@ -39,6 +39,7 @@ Q_OBJECT public: explicit BufferedProcessWrapper(Command cmd, bool emitOnActualSignals = false, QObject* parent = nullptr); + ~BufferedProcessWrapper() = default; /// Start the process with the given command and arguments void start(const QString& cmd, QStringList args, bool jsonResult, bool usePkExec, void* userData); @@ -46,7 +47,7 @@ [[nodiscard]] QProcess* process() const { return proc.get();} [[nodiscard]] Command command() const { return eCommand; } [[nodiscard]] void* userData() const { return pUserData; } - [[nodiscard]] bool isRunning() const { return proc != nullptr && proc->state() != QProcess::NotRunning; } + [[nodiscard]] bool isRunning() const { return proc != nullptr && proc->state() == QProcess::Running; } void cancel(bool raiseEvents = true) { if (proc != nullptr) { proc->terminate(); @@ -58,7 +59,7 @@ } signals: - void processErrorOccurred(const BufferedProcessWrapper* wrapper, QProcess::ProcessError error); + void processErrorOccurred(BufferedProcessWrapper* wrapper, QProcess::ProcessError error); void processCanReadStdOut(BufferedProcessWrapper* process); void processCanReadStandardError(BufferedProcessWrapper* process); void processFinished(BufferedProcessWrapper* process, int exitCode, QProcess::ExitStatus exitStatus); @@ -120,7 +121,6 @@ private: const TailSettings& settings; CurrentTailPrefs currentPrefs; - std::vector<BufferedProcessWrapper*> processes; signals: void tailscaleIsInstalled(bool installed); @@ -140,14 +140,11 @@ void parseStatusResponse(const QJsonObject& obj); void parseSettingsResponse(const QJsonObject& obj); - [[nodiscard]] bool hasPendingCommandOfType(Command cmdType) const; - void runCompletedCleanup(); - private slots: - void onProcessErrorOccurred(const BufferedProcessWrapper* wrapper, QProcess::ProcessError error); - void onProcessCanReadStdOut(const BufferedProcessWrapper* wrapper); - void onProcessCanReadStandardError(const BufferedProcessWrapper* wrapper); - void onProcessFinished(const BufferedProcessWrapper* wrapper, int exitCode, QProcess::ExitStatus exitStatus); + void onProcessErrorOccurred(BufferedProcessWrapper* wrapper, QProcess::ProcessError error); + void onProcessCanReadStdOut(BufferedProcessWrapper* wrapper); + void onProcessCanReadStandardError(BufferedProcessWrapper* wrapper); + void onProcessFinished(BufferedProcessWrapper* wrapper, int exitCode, QProcess::ExitStatus exitStatus); }; #endif // TAILRUNNER_H diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tail-tray-0.2.21/src/TrayMenuManager.cpp new/tail-tray-0.2.22/src/TrayMenuManager.cpp --- old/tail-tray-0.2.21/src/TrayMenuManager.cpp 2025-04-25 23:50:35.000000000 +0200 +++ new/tail-tray-0.2.22/src/TrayMenuManager.cpp 2025-05-07 15:30:19.000000000 +0200 @@ -73,7 +73,7 @@ accounts = foundAccounts; } -void TrayMenuManager::stateChangedTo(TailState newState, const TailStatus& pTailStatus) const { +void TrayMenuManager::stateChangedTo(TailState newState, const TailStatus& pTailStatus) { cleanupDisposableActions(); cleanupDisposableMenus(); @@ -143,7 +143,7 @@ buildAccountsMenu(); } -void TrayMenuManager::buildConnectedMenu(const TailStatus& pTailStatus) const { +void TrayMenuManager::buildConnectedMenu(const TailStatus& pTailStatus) { pTrayMenu->clear(); pTrayMenu->addAction(pConnected.get()); pTrayMenu->addAction(pDisconnect.get()); @@ -176,18 +176,13 @@ auto* deviceMenu = netDevs->addMenu(name + ipStr); disposableMenus.push_back(deviceMenu); action = deviceMenu->addAction(tr("Copy IP address")); - connect(action, &QAction::triggered, this, [this, dev, name, ipStr](bool) { + connect(action, &QAction::triggered, this, [this, dev, name](bool) { QClipboard* clipboard = QApplication::clipboard(); const auto& str = dev.tailscaleIPs.first(); qDebug() << str; clipboard->setText(str, QClipboard::Clipboard); - if (clipboard->supportsSelection()) { - clipboard->setText(str, QClipboard::Selection); - } - pSysTray->showMessage(tr("IP address copied"), - "IP Address " + ipStr + " for " + name + " have been copied to clipboard!", - QSystemTrayIcon::Information, 5000); + emit ipAddressCopiedToClipboard(str, name); }); disposableConnectedMenuActions.push_back( @@ -212,7 +207,7 @@ // The user data will be cleaned up when the signal is triggered back to us pTailRunner->sendFile(name, file, - new QString("File " + file + " sent to " + name)); + new QString(file)); }); } disposableConnectedMenuActions.push_back(action); @@ -432,9 +427,6 @@ }); connect(pConnect.get(), &QAction::triggered, this, [this](bool) { - pSysTray->showMessage(tr("Please wait"), tr("Connecting to your Tailscale network"), - QSystemTrayIcon::MessageIcon::Information, 3000); - pTailRunner->start(); }); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tail-tray-0.2.21/src/TrayMenuManager.h new/tail-tray-0.2.22/src/TrayMenuManager.h --- old/tail-tray-0.2.21/src/TrayMenuManager.h 2025-04-25 23:50:35.000000000 +0200 +++ new/tail-tray-0.2.22/src/TrayMenuManager.h 2025-05-07 15:30:19.000000000 +0200 @@ -19,10 +19,13 @@ explicit TrayMenuManager(TailSettings& s, TailRunner* runner, QObject* parent = nullptr); void onAccountsListed(const QList<TailAccountInfo>& foundAccounts); - void stateChangedTo(TailState newState, const TailStatus& pTailStatus) const; + void stateChangedTo(TailState newState, const TailStatus& pTailStatus); [[nodiscard]] QSystemTrayIcon* trayIcon() const { return pSysTray.get(); } +signals: + void ipAddressCopiedToClipboard(const QString& ipAddress, const QString& hostname); + private: QList<TailAccountInfo> accounts; TailSettings& settings; @@ -46,7 +49,7 @@ private: void buildNotLoggedInMenu() const; void buildNotConnectedMenu(const TailStatus& pTailStatus) const; - void buildConnectedMenu(const TailStatus& pTailStatus) const; + void buildConnectedMenu(const TailStatus& pTailStatus); void buildAccountsMenu() const; void setupWellKnownActions() const; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tail-tray-0.2.21/src/main.cpp new/tail-tray-0.2.22/src/main.cpp --- old/tail-tray-0.2.21/src/main.cpp 2025-04-25 23:50:35.000000000 +0200 +++ new/tail-tray-0.2.22/src/main.cpp 2025-05-07 15:30:19.000000000 +0200 @@ -9,7 +9,7 @@ int main(int argc, char** argv) { QCoreApplication::setOrganizationName("grenangen"); QCoreApplication::setOrganizationDomain("grenangen.se"); - QCoreApplication::setApplicationName("Tail Tray"); + QCoreApplication::setApplicationName("tail-tray"); SingleApplicationImpl a(argc, argv); if (!a.claimInstance()) { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tail-tray-0.2.21/tail-tray.notifyrc new/tail-tray-0.2.22/tail-tray.notifyrc --- old/tail-tray-0.2.21/tail-tray.notifyrc 1970-01-01 01:00:00.000000000 +0100 +++ new/tail-tray-0.2.22/tail-tray.notifyrc 2025-05-07 15:30:19.000000000 +0200 @@ -0,0 +1,17 @@ +[Global] + IconName=tailscale + Name=Tail Tray + Comment=A Tailscale Tray Application + DesktopEntry=Tail Tray + +[Event/BasicNotification] + Name=BasicNotification + Comment=Basic notifications without actions + Action=Sound|Popup + Urgency=Normal + +[Event/FileTransfer] + Name=FileTransfer + Comment=A file have been sent or received on this machine over Tailscale/Wireguard + Action=Sound|Popup + Urgency=Normal \ No newline at end of file ++++++ tail-tray.obsinfo ++++++ --- /var/tmp/diff_new_pack.v354Ro/_old 2025-05-07 19:22:32.746446893 +0200 +++ /var/tmp/diff_new_pack.v354Ro/_new 2025-05-07 19:22:32.746446893 +0200 @@ -1,5 +1,5 @@ name: tail-tray -version: 0.2.21 -mtime: 1745617835 -commit: 5bf5ad3aab9f6940dab6ec35e7bb5c366ffab9b5 +version: 0.2.22 +mtime: 1746624619 +commit: 124e20bae18e886553d44a2bd85ee60f8e8f0502