mirror of
https://github.com/keepassxreboot/keepassxc.git
synced 2024-12-27 16:29:44 -05:00
Merge pull request #170 from keepassxreboot/feature/169-signal-handlers
Implement clean shutdown after receiving Unix signals, resolves #169
This commit is contained in:
commit
a3f189f452
@ -17,12 +17,20 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "Application.h"
|
#include "Application.h"
|
||||||
|
#include "MainWindow.h"
|
||||||
|
|
||||||
#include <QAbstractNativeEventFilter>
|
#include <QAbstractNativeEventFilter>
|
||||||
#include <QFileOpenEvent>
|
#include <QFileOpenEvent>
|
||||||
|
#include <QSocketNotifier>
|
||||||
|
|
||||||
#include "autotype/AutoType.h"
|
#include "autotype/AutoType.h"
|
||||||
|
|
||||||
|
#if defined(Q_OS_UNIX)
|
||||||
|
#include <signal.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#if defined(Q_OS_UNIX) && !defined(Q_OS_OSX)
|
#if defined(Q_OS_UNIX) && !defined(Q_OS_OSX)
|
||||||
class XcbEventFilter : public QAbstractNativeEventFilter
|
class XcbEventFilter : public QAbstractNativeEventFilter
|
||||||
{
|
{
|
||||||
@ -65,12 +73,18 @@ public:
|
|||||||
Application::Application(int& argc, char** argv)
|
Application::Application(int& argc, char** argv)
|
||||||
: QApplication(argc, argv)
|
: QApplication(argc, argv)
|
||||||
, m_mainWindow(nullptr)
|
, m_mainWindow(nullptr)
|
||||||
|
#ifdef Q_OS_UNIX
|
||||||
|
, m_unixSignalNotifier(nullptr)
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
#if defined(Q_OS_UNIX) && !defined(Q_OS_OSX)
|
#if defined(Q_OS_UNIX) && !defined(Q_OS_OSX)
|
||||||
installNativeEventFilter(new XcbEventFilter());
|
installNativeEventFilter(new XcbEventFilter());
|
||||||
#elif defined(Q_OS_WIN)
|
#elif defined(Q_OS_WIN)
|
||||||
installNativeEventFilter(new WinEventFilter());
|
installNativeEventFilter(new WinEventFilter());
|
||||||
#endif
|
#endif
|
||||||
|
#if defined(Q_OS_UNIX)
|
||||||
|
registerUnixSignals();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::setMainWindow(QWidget* mainWindow)
|
void Application::setMainWindow(QWidget* mainWindow)
|
||||||
@ -98,3 +112,57 @@ bool Application::event(QEvent* event)
|
|||||||
|
|
||||||
return QApplication::event(event);
|
return QApplication::event(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(Q_OS_UNIX)
|
||||||
|
int Application::unixSignalSocket[2];
|
||||||
|
|
||||||
|
void Application::registerUnixSignals()
|
||||||
|
{
|
||||||
|
int result = ::socketpair(AF_UNIX, SOCK_STREAM, 0, unixSignalSocket);
|
||||||
|
Q_ASSERT(0 == result);
|
||||||
|
if (0 != result) {
|
||||||
|
// do not register handles when socket creation failed, otherwise
|
||||||
|
// application will be unresponsive to signals such as SIGINT or SIGTERM
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QVector<int> const handledSignals = { SIGQUIT, SIGINT, SIGTERM, SIGHUP };
|
||||||
|
for (auto s: handledSignals) {
|
||||||
|
struct sigaction sigAction;
|
||||||
|
|
||||||
|
sigAction.sa_handler = handleUnixSignal;
|
||||||
|
sigemptyset(&sigAction.sa_mask);
|
||||||
|
sigAction.sa_flags = 0 | SA_RESTART;
|
||||||
|
sigaction(s, &sigAction, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_unixSignalNotifier = new QSocketNotifier(unixSignalSocket[1], QSocketNotifier::Read, this);
|
||||||
|
connect(m_unixSignalNotifier, SIGNAL(activated(int)), this, SLOT(quitBySignal()));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Application::handleUnixSignal(int sig)
|
||||||
|
{
|
||||||
|
switch (sig) {
|
||||||
|
case SIGQUIT:
|
||||||
|
case SIGINT:
|
||||||
|
case SIGTERM:
|
||||||
|
{
|
||||||
|
char buf = 0;
|
||||||
|
::write(unixSignalSocket[0], &buf, sizeof(buf));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
case SIGHUP:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Application::quitBySignal()
|
||||||
|
{
|
||||||
|
m_unixSignalNotifier->setEnabled(false);
|
||||||
|
char buf;
|
||||||
|
::read(unixSignalSocket[1], &buf, sizeof(buf));
|
||||||
|
|
||||||
|
if (nullptr != m_mainWindow)
|
||||||
|
static_cast<MainWindow*>(m_mainWindow)->appExit();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
@ -21,6 +21,8 @@
|
|||||||
|
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
|
|
||||||
|
class QSocketNotifier;
|
||||||
|
|
||||||
class Application : public QApplication
|
class Application : public QApplication
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
@ -34,8 +36,23 @@ public:
|
|||||||
Q_SIGNALS:
|
Q_SIGNALS:
|
||||||
void openFile(const QString& filename);
|
void openFile(const QString& filename);
|
||||||
|
|
||||||
|
private Q_SLOTS:
|
||||||
|
#if defined(Q_OS_UNIX)
|
||||||
|
void quitBySignal();
|
||||||
|
#endif
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QWidget* m_mainWindow;
|
QWidget* m_mainWindow;
|
||||||
|
|
||||||
|
#if defined(Q_OS_UNIX)
|
||||||
|
/**
|
||||||
|
* Register Unix signals such as SIGINT and SIGTERM for clean shutdown.
|
||||||
|
*/
|
||||||
|
void registerUnixSignals();
|
||||||
|
QSocketNotifier* m_unixSignalNotifier;
|
||||||
|
static void handleUnixSignal(int sig);
|
||||||
|
static int unixSignalSocket[2];
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // KEEPASSX_APPLICATION_H
|
#endif // KEEPASSX_APPLICATION_H
|
||||||
|
@ -42,6 +42,7 @@ public:
|
|||||||
public Q_SLOTS:
|
public Q_SLOTS:
|
||||||
void openDatabase(const QString& fileName, const QString& pw = QString(),
|
void openDatabase(const QString& fileName, const QString& pw = QString(),
|
||||||
const QString& keyFile = QString());
|
const QString& keyFile = QString());
|
||||||
|
void appExit();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void closeEvent(QCloseEvent* event) override;
|
void closeEvent(QCloseEvent* event) override;
|
||||||
@ -68,7 +69,6 @@ private Q_SLOTS:
|
|||||||
void applySettingsChanges();
|
void applySettingsChanges();
|
||||||
void trayIconTriggered(QSystemTrayIcon::ActivationReason reason);
|
void trayIconTriggered(QSystemTrayIcon::ActivationReason reason);
|
||||||
void toggleWindow();
|
void toggleWindow();
|
||||||
void appExit();
|
|
||||||
void lockDatabasesAfterInactivity();
|
void lockDatabasesAfterInactivity();
|
||||||
void repairDatabase();
|
void repairDatabase();
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user