+++ /dev/null
-#!/bin/bash
-
-# Configure CMake with custom flags
-# - FEATHER_VERSION_DEBUG_BUILD=ON : Use git describe for version string
-# - CHECK_UPDATES=OFF : Disable built-in update checker
-# - USE_DEVICE_TREZOR=OFF : Disable Trezor hardware wallet support
-# - WITH_SCANNER=OFF : Disable webcam QR scanner support
-
-cmake \
- -DCMAKE_BUILD_TYPE=Debug \
- -DFEATHER_VERSION_DEBUG_BUILD=ON \
- -DCHECK_UPDATES=OFF \
- -DUSE_DEVICE_TREZOR=OFF \
- -DWITH_SCANNER=OFF \
- ..
void MainWindow::showEvent(QShowEvent *event)
{
QMainWindow::showEvent(event);
- qDebug() << "MainWindow::showEvent. WindowHandle:" << this->windowHandle();
- if (auto *window = this->windowHandle()) {
- if (!m_visibilityConnection) {
- m_visibilityConnection = connect(window, &QWindow::visibilityChanged, this, [this](QWindow::Visibility visibility){
- qDebug() << "Visibility changed:" << visibility << " WindowState:" << this->windowHandle()->windowState();
- if (visibility == QWindow::Minimized || this->windowHandle()->windowState() & Qt::WindowMinimized) {
- if (conf()->get(Config::lockOnMinimize).toBool()) {
- this->lockWallet();
- }
-
- bool showTray = conf()->get(Config::showTrayIcon).toBool();
- bool minimizeToTray = conf()->get(Config::minimizeToTray).toBool();
-
- qInfo() << "Visibility: Minimized. Tray=" << showTray << " MinToTray=" << minimizeToTray;
-
- if (showTray && minimizeToTray) {
- this->hide();
- }
- }
- });
- qDebug() << "Connected to visibilityChanged signal:" << (bool)m_visibilityConnection;
- }
- } else {
- qDebug() << "MainWindow::showEvent: No window handle available!";
- }
}
void MainWindow::changeEvent(QEvent* event)
}
}
} else if (event->type() == QEvent::ActivationChange) {
- auto winHandleState = this->windowHandle() ? this->windowHandle()->windowState() : Qt::WindowNoState;
- qInfo() << "changeEvent: ActivationChange. State:" << this->windowState() << " isActive:" << this->isActiveWindow() << " WinHandleState:" << winHandleState;
- if (this->windowHandle() && (this->windowHandle()->windowState() & Qt::WindowMinimized || this->isMinimized())) {
- qInfo() << "changeEvent: ActivationChange -> detected Minimized state";
- if (conf()->get(Config::lockOnMinimize).toBool()) {
- this->lockWallet();
- }
-
- bool showTray = conf()->get(Config::showTrayIcon).toBool();
- bool minimizeToTray = conf()->get(Config::minimizeToTray).toBool();
+ qInfo() << "changeEvent: ActivationChange. Active:" << this->isActiveWindow();
+ QTimer::singleShot(500, this, [this](){
+ auto handle = this->windowHandle();
+ if (handle && !handle->isExposed()) {
+ qInfo() << "ActivationChange (delayed): Window not exposed -> Hiding to tray";
+ if (conf()->get(Config::lockOnMinimize).toBool()) {
+ this->lockWallet();
+ }
- if (showTray && minimizeToTray) {
- this->hide();
+ bool showTray = conf()->get(Config::showTrayIcon).toBool();
+ bool minimizeToTray = conf()->get(Config::minimizeToTray).toBool();
+ if (showTray && minimizeToTray) {
+ this->hide();
+ }
}
- }
+ });
}
}
connect(ui->checkBox_showTrayIcon, &QCheckBox::toggled, [this](bool toggled) {
conf()->set(Config::showTrayIcon, toggled);
ui->checkBox_minimizeToTray->setEnabled(toggled);
+ ui->checkBox_trayLeftClickToggles->setEnabled(toggled);
emit showTrayIcon(toggled);
});
connect(ui->checkBox_minimizeToTray, &QCheckBox::toggled, [this](bool toggled) {
conf()->set(Config::minimizeToTray, toggled);
});
+
+ // [Left click system tray icon to toggle focus]
+ ui->checkBox_trayLeftClickToggles->setEnabled(ui->checkBox_showTrayIcon->isChecked());
+ ui->checkBox_trayLeftClickToggles->setChecked(conf()->get(Config::trayLeftClickToggles).toBool());
+ connect(ui->checkBox_trayLeftClickToggles, &QCheckBox::toggled, [this](bool toggled) {
+ conf()->set(Config::trayLeftClickToggles, toggled);
+ });
}
void Settings::setupMemoryTab() {
</item>
</layout>
</item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_17">
+ <item>
+ <spacer name="horizontalSpacer_3">
+ <property name="orientation">
+ <enum>Qt::Orientation::Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>QSizePolicy::Policy::Fixed</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>30</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="checkBox_trayLeftClickToggles">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>Left click system tray icon to toggle focus</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
</layout>
</item>
<item>
#include <QInputDialog>
#include <QMessageBox>
#include <QWindow>
-#include <QFontMetrics>
#include "Application.h"
#include "constants.h"
this->buildTrayMenu();
m_tray->setVisible(conf()->get(Config::showTrayIcon).toBool());
+ connect(m_tray, &QSystemTrayIcon::activated, [this](QSystemTrayIcon::ActivationReason reason) {
+ if (reason == QSystemTrayIcon::Trigger) {
+ if (conf()->get(Config::trayLeftClickToggles).toBool()) {
+ for (const auto &window : m_windows) {
+ if (window->isVisible()) {
+ window->hide();
+ } else {
+ window->show();
+ window->raise();
+ window->activateWindow();
+ }
+ }
+ } else {
+ m_tray->contextMenu()->popup(QCursor::pos());
+ }
+ }
+ });
+
this->initSkins();
this->patchMacStylesheet();
void WindowManager::close() {
qDebug() << Q_FUNC_INFO << QThread::currentThreadId();
+ if (m_closing) {
+ return;
+ }
+ m_closing = true;
+
+
// Stop all threads before application shutdown to avoid QThreadStorage warnings
if (m_cleanupThread && m_cleanupThread->isRunning()) {
m_cleanupThread->quit();
qDebug() << "WindowManager: cleanup thread stopped in close()";
}
+ // Close all windows first to ensure they cancel their tasks/connections
+ // Iterate over a copy because close() modifies m_windows
+ auto windows = m_windows;
+ for (const auto &window: windows) {
+ window->close();
+ }
+
// Stop Tor manager threads
torManager()->stop();
std::_Exit(1); // Fast exit without cleanup - threads may still hold resources
}
- for (const auto &window: m_windows) {
- window->close();
- }
-
if (m_splashDialog) {
m_splashDialog->deleteLater();
}
for (const auto &window : m_windows) {
QString name = window->walletName();
- QString displayName = name;
- if (name.length() > 20) {
- displayName = name.left(17) + "...";
- }
-
- QMenu *submenu = menu->addMenu(displayName);
- submenu->setToolTip(name);
- submenu->menuAction()->setToolTip(name);
+ QMenu *submenu = menu->addMenu(name);
submenu->addAction("Show/Hide", window, &MainWindow::showOrHide);
submenu->addAction("Close", window, &MainWindow::close);
}
bool m_openWalletTriedOnce = false;
bool m_openingWallet = false;
bool m_initialNetworkConfigured = false;
+ bool m_closing = false;
QThread *m_cleanupThread;
};
return m_daemonBlockChainTargetHeight;
}
-void Wallet::syncStatusUpdated(quint64 height, quint64 target) {
- if (height >= (target - 1)) {
- // TODO: is this needed?
- this->updateBalance();
- }
-
- emit syncStatus(height, target, false);
-}
-
void Wallet::setSyncPaused(bool paused) {
m_syncPaused = paused;
if (paused) {
void connectionStatusChanged(int status) const;
void currentSubaddressAccountChanged() const;
-
void syncStatus(quint64 height, quint64 target, bool daemonSync = false);
void balanceUpdated(quint64 balance, quint64 spendable);
{Config::lockOnMinimize, {QS("lockOnMinimize"), false}},
{Config::showTrayIcon, {QS("showTrayIcon"), true}},
{Config::minimizeToTray, {QS("minimizeToTray"), false}},
+ {Config::trayLeftClickToggles, {QS("trayLeftClickToggles"), false}},
{Config::disableWebsocket, {QS("disableWebsocket"), false}},
{Config::disableAutoRefresh, {QS("disableAutoRefresh"), false}},
{Config::offlineMode, {QS("offlineMode"), false}},
lockOnMinimize,
showTrayIcon,
minimizeToTray,
+ trayLeftClickToggles,
// Transactions
multiBroadcast,