#ifdef DONATE_BEG
this->donationNag();
#endif
+
+ connect(m_windowManager->eventFilter, &EventFilter::userActivity, this, &MainWindow::userActivity);
+ connect(&m_checkUserActivity, &QTimer::timeout, this, &MainWindow::checkUserActivity);
+ m_checkUserActivity.setInterval(5000);
+ m_checkUserActivity.start();
}
void MainWindow::initStatusBar() {
bool MainWindow::verifyPassword() {
bool ok;
while (true) {
- QString password = QInputDialog::getText(this, "Enter password", "Please enter your password:", QLineEdit::EchoMode::Password, "", &ok);
- if (!ok) { // Dialog cancelled
+ PasswordDialog passwordDialog{this->walletName(), false, this};
+ int ret = passwordDialog.exec();
+ if (ret == QDialog::Rejected) {
return false;
}
- if (password != m_ctx->wallet->getPassword()) {
+ if (passwordDialog.password != m_ctx->wallet->getPassword()) {
QMessageBox::warning(this, "Error", "Incorrect password");
continue;
}
qApp->setStyleSheet(styleSheet);
}
+void MainWindow::userActivity() {
+ m_userLastActive = QDateTime::currentSecsSinceEpoch();
+}
+
+void MainWindow::checkUserActivity() {
+ if (!config()->get(Config::inactivityLockEnabled).toBool()) {
+ return;
+ }
+
+ if (m_constructingTransaction) {
+ return;
+ }
+
+ if ((m_userLastActive + (config()->get(Config::inactivityLockTimeout).toInt()*60)) < QDateTime::currentSecsSinceEpoch()) {
+ m_checkUserActivity.stop();
+ qInfo() << "Locking wallet for inactivity";
+ if (!this->verifyPassword()) {
+ this->setEnabled(false);
+ this->close();
+ // This doesn't close the wallet immediately.
+ do {
+ QApplication::processEvents();
+ // Because running it a single time is apparently not enough.
+ // TODO: Qt bug? Need proper fix for this.
+ } while (QApplication::hasPendingEvents());
+ } else {
+ m_checkUserActivity.start();
+ }
+ }
+}
+
void MainWindow::toggleSearchbar(bool visible) {
config()->set(Config::showSearchbar, visible);
#include "model/CoinsProxyModel.h"
#include "utils/networking.h"
#include "utils/config.h"
+#include "utils/EventFilter.h"
#include "widgets/CCSWidget.h"
#include "widgets/RedditWidget.h"
#include "widgets/TickerWidget.h"
void updateWidgetIcons();
bool verifyPassword();
void patchStylesheetMac();
+ void userActivity();
+ void checkUserActivity();
QIcon hardwareDevicePairedIcon();
QIcon hardwareDeviceUnpairedIcon();
QMap<QString, ToggleTab*> m_tabShowHideMapper;
QTimer m_updateBytes;
+ QTimer m_checkUserActivity;
QString m_statusText;
int m_statusDots;
QTimer m_txTimer;
bool cleanedUp = false;
+
+ EventFilter *m_eventFilter = nullptr;
+ qint64 m_userLastActive = QDateTime::currentSecsSinceEpoch();
};
#endif // FEATHER_MAINWINDOW_H
config()->set(Config::disableLogging, toggled);
WalletManager::instance()->setLogLevel(toggled ? -1 : config()->get(Config::logLevel).toInt());
});
+ connect(ui->checkBox_inactivityLockTimeout, &QCheckBox::toggled, [](bool toggled){
+ config()->set(Config::inactivityLockEnabled, toggled);
+ });
+ connect(ui->spinBox_inactivityLockTimeout, QOverload<int>::of(&QSpinBox::valueChanged), [](int value){
+ config()->set(Config::inactivityLockTimeout, value);
+ });
connect(ui->closeButton, &QDialogButtonBox::accepted, this, &Settings::close);
ui->checkBox_externalLink->setChecked(config()->get(Config::warnOnExternalLink).toBool());
ui->checkBox_hideBalance->setChecked(config()->get(Config::hideBalance).toBool());
ui->checkBox_disableLogging->setChecked(config()->get(Config::disableLogging).toBool());
+ ui->checkBox_inactivityLockTimeout->setChecked(config()->get(Config::inactivityLockEnabled).toBool());
+ ui->spinBox_inactivityLockTimeout->setValue(config()->get(Config::inactivityLockTimeout).toInt());
// setup comboboxes
this->setupSkinCombobox();
<x>0</x>
<y>0</y>
<width>915</width>
- <height>519</height>
+ <height>553</height>
</rect>
</property>
<property name="windowTitle">
</property>
</widget>
</item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_9">
+ <item>
+ <widget class="QCheckBox" name="checkBox_inactivityLockTimeout">
+ <property name="text">
+ <string>Lock wallet on inactivity after</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QSpinBox" name="spinBox_inactivityLockTimeout">
+ <property name="minimum">
+ <number>1</number>
+ </property>
+ <property name="maximum">
+ <number>120</number>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="label_16">
+ <property name="text">
+ <string>minutes</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer_2">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <spacer name="verticalSpacer_3">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>0</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
</layout>
</widget>
<widget class="QWidget" name="tab_node">
#include "utils/TorManager.h"
#include "utils/WebsocketNotifier.h"
-WindowManager::WindowManager() {
+WindowManager::WindowManager(EventFilter *eventFilter)
+ : eventFilter(eventFilter)
+{
m_walletManager = WalletManager::instance();
m_splashDialog = new SplashDialog;
m_cleanupThread = new QThread();
Q_OBJECT
public:
- explicit WindowManager();
+ explicit WindowManager(EventFilter *eventFilter);
~WindowManager() override;
void wizardOpenWallet();
void restartApplication(const QString &binaryFilename);
void raise();
+ EventFilter *eventFilter;
+
signals:
void torSettingsChanged();
#include "config-feather.h"
#include "constants.h"
#include "MainWindow.h"
+#include "utils/EventFilter.h"
#include "WindowManager.h"
#if defined(Q_OS_WIN)
qRegisterMetaType<TxProofResult>("TxProofResult");
qRegisterMetaType<QPair<bool, bool>>();
- WindowManager windowManager;
+ EventFilter filter;
+ app.installEventFilter(&filter);
+
+ WindowManager windowManager(&filter);
QObject::connect(&app, &SingleApplication::instanceStarted, [&windowManager]() {
windowManager.raise();
});
+
+
return QApplication::exec();
}
--- /dev/null
+// SPDX-License-Identifier: BSD-3-Clause
+// SPDX-FileCopyrightText: 2020-2022 The Monero Project
+
+#include "EventFilter.h"
+
+#include <QKeyEvent>
+#include <QDebug>
+
+EventFilter::EventFilter(QObject *parent)
+ : QObject(parent)
+{}
+
+bool EventFilter::eventFilter(QObject *obj, QEvent *ev) {
+ if (ev->type() == QEvent::KeyPress || ev->type() == QEvent::MouseButtonRelease) {
+ emit userActivity();
+ }
+
+ return QObject::eventFilter(obj, ev);
+}
\ No newline at end of file
--- /dev/null
+// SPDX-License-Identifier: BSD-3-Clause
+// SPDX-FileCopyrightText: 2020-2022 The Monero Project
+
+#ifndef FEATHER_EVENTFILTER_H
+#define FEATHER_EVENTFILTER_H
+
+#include <QObject>
+
+class EventFilter : public QObject
+{
+Q_OBJECT
+
+public:
+ explicit EventFilter(QObject *parent = nullptr);
+
+protected:
+ bool eventFilter(QObject *obj, QEvent *ev);
+
+
+signals:
+ void userActivity();
+};
+
+
+#endif //FEATHER_EVENTFILTER_H
{Config::dateFormat, {QS("dateFormat"), "yyyy-MM-dd"}},
{Config::timeFormat, {QS("timeFormat"), "HH:mm"}},
{Config::balanceDisplay, {QS("balanceDisplay"), Config::BalanceDisplay::spendablePlusUnconfirmed}},
+ {Config::inactivityLockEnabled, {QS("inactivityLockEnabled"), false}},
+ {Config::inactivityLockTimeout, {QS("inactivityLockTimeout"), 10}},
{Config::multiBroadcast, {QS("multiBroadcast"), true}},
{Config::warnOnExternalLink,{QS("warnOnExternalLink"), true}},
dateFormat,
timeFormat,
balanceDisplay,
+ inactivityLockEnabled,
+ inactivityLockTimeout,
multiBroadcast,
warnOnExternalLink,