Handle SIGTERM and SIGKILL (#4091)

* Handle sigint and sigterm when KDSingleApplication is used to prevent stale lock files

* fixing windows build

* cleanup after more review
This commit is contained in:
borgmanJeremy
2025-07-27 09:54:21 -05:00
committed by GitHub
parent 4f224d9ad2
commit f78aab5a7a
4 changed files with 134 additions and 5 deletions

View File

@@ -13,6 +13,15 @@ target_sources(flameshot PRIVATE
qguiappcurrentscreen.cpp
)
IF (WIN32)
if (USE_KDSINGLEAPPLICATION)
if (NOT WIN32)
target_sources(flameshot PRIVATE
signaldaemon.h
signaldaemon.cpp
)
endif ()
endif ()
if (WIN32)
target_sources(flameshot PRIVATE globalshortcutfilter.h globalshortcutfilter.cpp)
ENDIF ()
endif ()

62
src/core/signaldaemon.cpp Normal file
View File

@@ -0,0 +1,62 @@
#include "signaldaemon.h"
#include <QApplication>
#include <QSocketNotifier>
#include <csignal>
#include <qdebug.h>
#include <sys/socket.h>
#include <unistd.h>
int SignalDaemon::sigintFd[2];
int SignalDaemon::sigtermFd[2];
SignalDaemon::SignalDaemon(QObject* parent)
: QObject(parent)
{
if (::socketpair(AF_UNIX, SOCK_STREAM, 0, sigintFd))
qFatal("Couldn't create INT socketpair");
if (::socketpair(AF_UNIX, SOCK_STREAM, 0, sigtermFd))
qFatal("Couldn't create TERM socketpair");
snInt = new QSocketNotifier(sigintFd[1], QSocketNotifier::Read, this);
connect(
snInt, SIGNAL(activated(QSocketDescriptor)), this, SLOT(handleSigInt()));
snTerm = new QSocketNotifier(sigtermFd[1], QSocketNotifier::Read, this);
connect(snTerm,
SIGNAL(activated(QSocketDescriptor)),
this,
SLOT(handleSigTerm()));
}
void SignalDaemon::intSignalHandler(int)
{
char msg = 1;
::write(sigintFd[0], &msg, sizeof(msg));
}
void SignalDaemon::termSignalHandler(int)
{
char msg = 1;
::write(sigtermFd[0], &msg, sizeof(msg));
}
void SignalDaemon::handleSigTerm()
{
snTerm->setEnabled(false);
char tmp = 0;
::read(sigtermFd[1], &tmp, sizeof(tmp));
QApplication::quit();
snTerm->setEnabled(true);
}
void SignalDaemon::handleSigInt()
{
snInt->setEnabled(false);
char tmp = 0;
::read(sigintFd[1], &tmp, sizeof(tmp));
QApplication::quit();
snInt->setEnabled(true);
}

27
src/core/signaldaemon.h Normal file
View File

@@ -0,0 +1,27 @@
#include <QObject>
#include <QSocketNotifier>
class SignalDaemon : public QObject
{
Q_OBJECT
public:
SignalDaemon(QObject* parent = 0);
~SignalDaemon() = default;
// Unix signal handlers.
static void intSignalHandler(int unused);
static void termSignalHandler(int unused);
public slots:
// Qt signal handlers.
void handleSigInt();
void handleSigTerm();
private:
static int sigintFd[2];
static int sigtermFd[2];
QSocketNotifier* snInt;
QSocketNotifier* snTerm;
};

View File

@@ -3,6 +3,10 @@
#ifdef USE_KDSINGLEAPPLICATION
#include "kdsingleapplication.h"
#ifdef Q_OS_UNIX
#include "core/signaldaemon.h"
#include "csignal"
#endif
#endif
#include "abstractlogger.h"
@@ -34,6 +38,31 @@
// Required for saving button list QList<CaptureTool::Type>
Q_DECLARE_METATYPE(QList<int>)
#if defined(USE_KDSINGLEAPPLICATION) && defined(Q_OS_UNIX)
static int setup_unix_signal_handlers()
{
struct sigaction sint, term;
sint.sa_handler = SignalDaemon::intSignalHandler;
sigemptyset(&sint.sa_mask);
sint.sa_flags = 0;
sint.sa_flags |= SA_RESTART;
if (sigaction(SIGINT, &sint, 0))
return 1;
term.sa_handler = SignalDaemon::termSignalHandler;
sigemptyset(&term.sa_mask);
term.sa_flags = 0;
term.sa_flags |= SA_RESTART;
if (sigaction(SIGTERM, &term, 0))
return 2;
return 0;
}
#endif
int requestCaptureAndWait(const CaptureRequest& req)
{
Flameshot* flameshot = Flameshot::instance();
@@ -149,11 +178,13 @@ int main(int argc, char* argv[])
QApplication app(argc, argv);
#ifdef USE_KDSINGLEAPPLICATION
KDSingleApplication kdsa(QStringLiteral("flameshot"));
#ifdef Q_OS_UNIX
setup_unix_signal_handlers();
auto signalDaemon = SignalDaemon();
#endif
auto kdsa = KDSingleApplication(QStringLiteral("flameshot"));
if (!kdsa.isPrimaryInstance()) {
// AbstractLogger::warning()
// << QStringLiteral("Closing second Flameshot instance!");
return 0; // Quit
}
#endif