diff options
Diffstat (limited to 'src/gui/Application.cpp')
-rw-r--r-- | src/gui/Application.cpp | 68 |
1 files changed, 68 insertions, 0 deletions
diff --git a/src/gui/Application.cpp b/src/gui/Application.cpp index d982f22ca..26d9d2283 100644 --- a/src/gui/Application.cpp +++ b/src/gui/Application.cpp @@ -17,12 +17,20 @@ */ #include "Application.h" +#include "MainWindow.h" #include <QAbstractNativeEventFilter> #include <QFileOpenEvent> +#include <QSocketNotifier> #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) class XcbEventFilter : public QAbstractNativeEventFilter { @@ -65,12 +73,18 @@ public: Application::Application(int& argc, char** argv) : QApplication(argc, argv) , m_mainWindow(nullptr) +#ifdef Q_OS_UNIX + , m_unixSignalNotifier(nullptr) +#endif { #if defined(Q_OS_UNIX) && !defined(Q_OS_OSX) installNativeEventFilter(new XcbEventFilter()); #elif defined(Q_OS_WIN) installNativeEventFilter(new WinEventFilter()); #endif +#if defined(Q_OS_UNIX) + registerUnixSignals(); +#endif } void Application::setMainWindow(QWidget* mainWindow) @@ -98,3 +112,57 @@ bool Application::event(QEvent* 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 |