diff options
Diffstat (limited to '')
-rw-r--r-- | src/yuzu/main.cpp | 60 | ||||
-rw-r--r-- | src/yuzu/main.h | 11 |
2 files changed, 71 insertions, 0 deletions
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 84fccab34..ef91ef19c 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -8,6 +8,10 @@ #ifdef __APPLE__ #include <unistd.h> // for chdir #endif +#ifdef __linux__ +#include <csignal> +#include <sys/socket.h> +#endif // VFS includes must be before glad as they will conflict with Windows file api, which uses defines. #include "applets/qt_controller.h" @@ -259,6 +263,10 @@ GMainWindow::GMainWindow(bool has_broken_vulkan) config{std::make_unique<Config>(*system)}, vfs{std::make_shared<FileSys::RealVfsFilesystem>()}, provider{std::make_unique<FileSys::ManualContentProvider>()} { +#ifdef __linux__ + SetupSigInterrupts(); +#endif + Common::Log::Initialize(); LoadTranslation(); @@ -462,7 +470,13 @@ GMainWindow::~GMainWindow() { if (render_window->parent() == nullptr) { delete render_window; } + system->GetRoomNetwork().Shutdown(); + +#ifdef __linux__ + ::close(sig_interrupt_fds[0]); + ::close(sig_interrupt_fds[1]); +#endif } void GMainWindow::RegisterMetaTypes() { @@ -1352,6 +1366,52 @@ static void ReleaseWakeLockLinux(QDBusObjectPath lock) { QString::fromLatin1("org.freedesktop.portal.Request")); unlocker.call(QString::fromLatin1("Close")); } + +std::array<int, 3> GMainWindow::sig_interrupt_fds{0, 0, 0}; + +void GMainWindow::SetupSigInterrupts() { + if (sig_interrupt_fds[2] == 1) { + return; + } + socketpair(AF_UNIX, SOCK_STREAM, 0, sig_interrupt_fds.data()); + sig_interrupt_fds[2] = 1; + + struct sigaction sa; + sa.sa_handler = &GMainWindow::HandleSigInterrupt; + sigemptyset(&sa.sa_mask); + sa.sa_flags = SA_RESETHAND; + sigaction(SIGINT, &sa, nullptr); + sigaction(SIGTERM, &sa, nullptr); + + sig_interrupt_notifier = new QSocketNotifier(sig_interrupt_fds[1], QSocketNotifier::Read, this); + connect(sig_interrupt_notifier, &QSocketNotifier::activated, this, + &GMainWindow::OnSigInterruptNotifierActivated); + connect(this, &GMainWindow::SigInterrupt, this, &GMainWindow::close); +} + +void GMainWindow::HandleSigInterrupt(int sig) { + if (sig == SIGINT) { + exit(1); + } + + // Calling into Qt directly from a signal handler is not safe, + // so wake up a QSocketNotifier with this hacky write call instead. + char a = 1; + int ret = write(sig_interrupt_fds[0], &a, sizeof(a)); + (void)ret; +} + +void GMainWindow::OnSigInterruptNotifierActivated() { + sig_interrupt_notifier->setEnabled(false); + + char a; + int ret = read(sig_interrupt_fds[1], &a, sizeof(a)); + (void)ret; + + sig_interrupt_notifier->setEnabled(true); + + emit SigInterrupt(); +} #endif // __linux__ void GMainWindow::PreventOSSleep() { diff --git a/src/yuzu/main.h b/src/yuzu/main.h index de0d10974..509bb91df 100644 --- a/src/yuzu/main.h +++ b/src/yuzu/main.h @@ -163,6 +163,8 @@ signals: void WebBrowserExtractOfflineRomFS(); void WebBrowserClosed(Service::AM::Applets::WebExitReason exit_reason, std::string last_url); + void SigInterrupt(); + public slots: void OnLoadComplete(); void OnExecuteProgram(std::size_t program_index); @@ -251,6 +253,12 @@ private: void RequestGameResume(); void closeEvent(QCloseEvent* event) override; +#ifdef __linux__ + void SetupSigInterrupts(); + static void HandleSigInterrupt(int); + void OnSigInterruptNotifierActivated(); +#endif + private slots: void OnStartGame(); void OnRestartGame(); @@ -419,6 +427,9 @@ private: bool is_tas_recording_dialog_active{}; #ifdef __linux__ + QSocketNotifier* sig_interrupt_notifier; + static std::array<int, 3> sig_interrupt_fds; + QDBusObjectPath wake_lock{}; #endif |