diff --git a/ChangeLog b/ChangeLog index 06f7c09b..2475f32c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -5,9 +5,13 @@ 3.5.3git +- correct unregister of headless server and RPP file creation on + SIGINT/SIGTERM, coded by pljones (Tickets #130, #168) + - for CoreAudio and 4 channel input, support mixing channels 1&2 with 3&4 -- added bassoon/oboe/harp instrument icons created by dszgit; congas/bongo created by bspeer (Ticket #131) +- added bassoon/oboe/harp instrument icons created by dszgit; + congas/bongo created by bspeer (Ticket #131) - link to docs from application Help menu (Ticket #90) @@ -17,15 +21,18 @@ - new design for the About dialog (Ticket #189) -- bug fix: for mono capture jack audio interface Jamulus complains it cannot make connections (Ticket #137) +- bug fix: for mono capture jack audio interface Jamulus complains it + cannot make connections (Ticket #137) - bug fix: fixed that Jamulus segfaults when jackd is restarted (Ticket #122, #127) +- bug fix: better handling of disconnect message in the client + + +TODO check if Tickets #130, #168 are really solved by code from pljones TODO WIP support internationalization -TODO improve disconnect message behaviour on client - TODO implement panning for channels (Ticket #52, #145) TODO show mute state of others diff --git a/Jamulus.pro b/Jamulus.pro index 4ba4813a..31e840bb 100755 --- a/Jamulus.pro +++ b/Jamulus.pro @@ -337,7 +337,8 @@ HEADERS += src/audiomixerboard.h \ src/recorder/jamrecorder.h \ src/recorder/creaperproject.h \ src/recorder/cwavestream.h \ - src/historygraph.h + src/historygraph.h \ + src/signalhandler.h HEADERS_OPUS = libs/opus/celt/arch.h \ libs/opus/celt/bands.h \ @@ -451,6 +452,7 @@ SOURCES += src/audiomixerboard.cpp \ src/serverlist.cpp \ src/serverlogging.cpp \ src/settings.cpp \ + src/signalhandler.cpp \ src/socket.cpp \ src/soundbase.cpp \ src/util.cpp \ diff --git a/src/client.cpp b/src/client.cpp index b4a60743..1259e3ee 100755 --- a/src/client.cpp +++ b/src/client.cpp @@ -1207,7 +1207,7 @@ fflush(pFileDelay); // update socket buffer size Channel.UpdateSocketBufferSize(); - Q_UNUSED ( iUnused ); + Q_UNUSED ( iUnused ) } int CClient::EstimatedOverallDelay ( const int iPingTimeMs ) diff --git a/src/client.h b/src/client.h index 76df0702..1b16000c 100755 --- a/src/client.h +++ b/src/client.h @@ -398,7 +398,7 @@ public slots: void OnJittBufSizeChanged ( int iNewJitBufSize ); void OnReqChanInfo() { Channel.SetRemoteInfo ( ChannelInfo ); } void OnNewConnection(); - void OnCLDisconnection ( CHostAddress InetAddr ) { if ( InetAddr == Channel.GetAddress() ) { Stop(); } } + void OnCLDisconnection ( CHostAddress InetAddr ) { if ( InetAddr == Channel.GetAddress() ) { emit Disconnected(); } } void OnCLPingReceived ( CHostAddress InetAddr, int iMs ); diff --git a/src/clientdlg.cpp b/src/clientdlg.cpp index ab178cd4..1f1fe8a2 100755 --- a/src/clientdlg.cpp +++ b/src/clientdlg.cpp @@ -732,16 +732,6 @@ void CClientDlg::OnConnectDisconBut() } } -void CClientDlg::OnDisconnected() -{ - // channel is now disconnected, clear mixer board (remove all faders) and - // reset the delay LED (since this is only updated on an active connection) - MainMixerBoard->HideAll(); - ledDelay->Reset(); - - UpdateDisplay(); -} - void CClientDlg::OnCentralServerAddressTypeChanged() { // if the server list is shown and the server type was changed, update the list diff --git a/src/clientdlg.h b/src/clientdlg.h index b87a925f..d4a7b2b9 100755 --- a/src/clientdlg.h +++ b/src/clientdlg.h @@ -194,7 +194,7 @@ public slots: { MainMixerBoard->SetChannelLevels ( vecLevelList ); } void OnConnectDlgAccepted(); - void OnDisconnected(); + void OnDisconnected() { Disconnect(); } void OnCentralServerAddressTypeChanged(); void OnGUIDesignChanged() diff --git a/src/clientsettingsdlg.cpp b/src/clientsettingsdlg.cpp index 200c1337..0e18604c 100755 --- a/src/clientsettingsdlg.cpp +++ b/src/clientsettingsdlg.cpp @@ -155,7 +155,7 @@ CClientSettingsDlg::CClientSettingsDlg ( CClient* pNCliP, QWidget* parent, "If no buffer size is selected and all settings are disabled, an " "unsupported buffer size is used by the driver. The " ) + APP_NAME + tr ( " software will still work with this setting but with restricted " - "performannce." ) + "
" + tr ( + "performance." ) + "
" + tr ( "The actual buffer delay has influence on the connection status, the " "current upload rate and the overall delay. The lower the buffer size, " "the higher the probability of red light in the status indicator (drop " diff --git a/src/recorder/jamrecorder.cpp b/src/recorder/jamrecorder.cpp index 1055efdc..2c817919 100755 --- a/src/recorder/jamrecorder.cpp +++ b/src/recorder/jamrecorder.cpp @@ -314,22 +314,31 @@ void CJamRecorder::Init( const CServer* server, throw std::runtime_error( (recordBaseDir.absolutePath() + " is a directory but cannot be written to").toStdString() ); } - QObject::connect((const QObject *)server, SIGNAL ( Stopped() ), - this, SLOT( OnEnd() ), - Qt::ConnectionType::QueuedConnection); + QObject::connect( (const QObject *)server, SIGNAL ( Stopped() ), + this, SLOT( OnEnd() ), + Qt::ConnectionType::QueuedConnection ); - QObject::connect((const QObject *)server, SIGNAL ( ClientDisconnected(int) ), - this, SLOT( OnDisconnected(int) ), - Qt::ConnectionType::QueuedConnection); + QObject::connect( (const QObject *)server, SIGNAL ( ClientDisconnected ( int ) ), + this, SLOT( OnDisconnected ( int ) ), + Qt::ConnectionType::QueuedConnection ); qRegisterMetaType>(); - QObject::connect((const QObject *)server, SIGNAL ( AudioFrame(const int, const QString, const CHostAddress, const int, const CVector) ), - this, SLOT( OnFrame(const int, const QString, const CHostAddress, const int, const CVector) ), - Qt::ConnectionType::QueuedConnection); + QObject::connect( (const QObject *)server, SIGNAL ( AudioFrame( const int, const QString, const CHostAddress, const int, const CVector ) ), + this, SLOT( OnFrame (const int, const QString, const CHostAddress, const int, const CVector ) ), + Qt::ConnectionType::QueuedConnection ); + + QObject::connect( QCoreApplication::instance(), + SIGNAL ( aboutToQuit() ), + this, SLOT( OnAboutToQuit() ) ); iServerFrameSizeSamples = _iServerFrameSizeSamples; + + thisThread = new QThread(); + moveToThread ( thisThread ); + thisThread->start(); } + /** * @brief CJamRecorder::OnStart Start up tasks when the first client connects */ @@ -337,7 +346,7 @@ void CJamRecorder::OnStart() { // Ensure any previous cleaning up has been done. OnEnd(); - currentSession = new CJamSession(recordBaseDir); + currentSession = new CJamSession( recordBaseDir ); isRecording = true; } @@ -346,7 +355,7 @@ void CJamRecorder::OnStart() { */ void CJamRecorder::OnEnd() { - if (isRecording) + if ( isRecording ) { isRecording = false; currentSession->End(); @@ -372,6 +381,13 @@ void CJamRecorder::OnEnd() } } +void CJamRecorder::OnAboutToQuit() +{ + OnEnd(); + + thisThread->exit(); +} + /** * @brief CJamRecorder::SessionDirToReaper Replica of CJamRecorder::OnEnd() but using the directory contents to construct the CReaperProject object * @param strSessionDirName @@ -409,11 +425,11 @@ void CJamRecorder::SessionDirToReaper(QString& strSessionDirName, int serverFram */ void CJamRecorder::OnDisconnected(int iChID) { - if (!isRecording) + if ( !isRecording ) { qWarning() << "CJamRecorder::OnDisconnected: channel" << iChID << "disconnected but not recording"; } - if (currentSession == nullptr) + if ( currentSession == nullptr ) { qWarning() << "CJamRecorder::OnDisconnected: channel" << iChID << "disconnected but no currentSession"; return; @@ -434,7 +450,7 @@ void CJamRecorder::OnDisconnected(int iChID) void CJamRecorder::OnFrame(const int iChID, const QString name, const CHostAddress address, const int numAudioChannels, const CVector data) { // Make sure we are ready - if (!isRecording) + if ( !isRecording ) { OnStart(); } diff --git a/src/recorder/jamrecorder.h b/src/recorder/jamrecorder.h index cc49705d..eb5a0581 100755 --- a/src/recorder/jamrecorder.h +++ b/src/recorder/jamrecorder.h @@ -132,13 +132,16 @@ private: QList jamClientConnections; }; -class CJamRecorder : public QThread +class CJamRecorder : public QObject { Q_OBJECT public: - CJamRecorder(const QString recordingDirName) : - recordBaseDir (recordingDirName), isRecording (false) {} + CJamRecorder ( const QString recordingDirName ) : + recordBaseDir ( recordingDirName ), + isRecording ( false ) + { + } void Init( const CServer* server, const int _iServerFrameSizeSamples ); @@ -155,16 +158,21 @@ public slots: */ void OnEnd(); + /** + * @brief Raised when application is stopping + */ + void OnAboutToQuit(); + /** * @brief Raised when an existing client leaves the server. * @param iChID channel number of client */ - void OnDisconnected(int iChID); + void OnDisconnected ( int iChID ); /** - * @brief Raised when a frame of data fis available to process + * @brief Raised when a frame of data is available to process */ - void OnFrame(const int iChID, const QString name, const CHostAddress address, const int numAudioChannels, const CVector data); + void OnFrame ( const int iChID, const QString name, const CHostAddress address, const int numAudioChannels, const CVector data ); private: QDir recordBaseDir; @@ -172,6 +180,8 @@ private: bool isRecording; CJamSession* currentSession; int iServerFrameSizeSamples; + + QThread* thisThread; }; } diff --git a/src/res/translation/translation_de_DE.ts b/src/res/translation/translation_de_DE.ts index 5543ae00..4e38a76f 100644 --- a/src/res/translation/translation_de_DE.ts +++ b/src/res/translation/translation_de_DE.ts @@ -896,7 +896,7 @@ - software will still work with this setting but with restricted performannce. + software will still work with this setting but with restricted performance. Software funktioniert trotzdem aber es könnte eine größere Verzögerung resultieren. diff --git a/src/res/translation/translation_es_ES.ts b/src/res/translation/translation_es_ES.ts index 2d8990f7..f7289637 100644 --- a/src/res/translation/translation_es_ES.ts +++ b/src/res/translation/translation_es_ES.ts @@ -900,7 +900,7 @@ - software will still work with this setting but with restricted performannce. + software will still work with this setting but with restricted performance. seguirá funcionando con esta configuración pero con un rendimiento limitado. diff --git a/src/res/translation/translation_fr_FR.ts b/src/res/translation/translation_fr_FR.ts index cadb8b54..084b6ad9 100644 --- a/src/res/translation/translation_fr_FR.ts +++ b/src/res/translation/translation_fr_FR.ts @@ -908,7 +908,7 @@ - software will still work with this setting but with restricted performannce. + software will still work with this setting but with restricted performance. continuera toujours de fonctionner avec ce réglage, mais avec des performances limitées. @@ -1366,7 +1366,7 @@ server software must be set here. An optional port number can be added after the IP address or URL using a colon as a separator, e.g, example.org: - doit être paramétré ici. Un numéro optionnel de port peut être ajouté après l'adresse IP ou l'URL en utilisant une virgule en tant que séparateur, par exemple, exemple.org : + doit être paramétré ici. Un numéro optionnel de port peut être ajouté après l'adresse IP ou l'URL en utilisant deux points en tant que séparateur, par exemple, exemple.org : diff --git a/src/res/translation/translation_pt_PT.ts b/src/res/translation/translation_pt_PT.ts index 7db7cc2f..a8d45ac7 100644 --- a/src/res/translation/translation_pt_PT.ts +++ b/src/res/translation/translation_pt_PT.ts @@ -908,7 +908,7 @@ - software will still work with this setting but with restricted performannce. + software will still work with this setting but with restricted performance. ainda funcionará com essa configuração, mas com desempenho restrito. diff --git a/src/server.cpp b/src/server.cpp index 7ba26c9f..40e2e63b 100755 --- a/src/server.cpp +++ b/src/server.cpp @@ -251,7 +251,8 @@ CServer::CServer ( const int iNewMaxNumChan, bAutoRunMinimized ( false ), strWelcomeMessage ( strNewWelcomeMessage ), eLicenceType ( eNLicenceType ), - bDisconnectAllClients ( bNDisconnectAllClients ) + bDisconnectAllClients ( bNDisconnectAllClients ), + pSignalHandler ( CSignalHandler::getSingletonP() ) { int iOpusError; int i; @@ -398,11 +399,10 @@ CServer::CServer ( const int iNewMaxNumChan, QString().number( static_cast ( iPortNumber ) ) ); } - // Enable jam recording (if requested) + // Enable jam recording (if requested) - kicks off the thread if ( bEnableRecording ) { JamRecorder.Init ( this, iServerFrameSizeSamples ); - JamRecorder.start(); } // enable all channels (for the server all channel must be enabled the @@ -466,6 +466,14 @@ CServer::CServer ( const int iNewMaxNumChan, SIGNAL ( SvrRegStatusChanged() ), this, SLOT ( OnSvrRegStatusChanged() ) ); + QObject::connect ( QCoreApplication::instance(), + SIGNAL ( aboutToQuit() ), + this, SLOT ( OnAboutToQuit() ) ); + + QObject::connect ( pSignalHandler, + SIGNAL ( ShutdownSignal ( int ) ), + this, SLOT ( OnShutdown ( int ) ) ); + #if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) connectChannelSignalsToServerSlots(); @@ -908,6 +916,23 @@ void CServer::OnCLDisconnection ( CHostAddress InetAddr ) } } +void CServer::OnAboutToQuit() +{ + Stop(); + + // if server was registered at the central server, unregister on shutdown + if ( GetServerListEnabled() ) + { + UnregisterSlaveServer(); + } +} + +void CServer::OnShutdown ( int ) +{ + // This should trigger OnAboutToQuit + QCoreApplication::instance()->exit(); +} + void CServer::Start() { // only start if not already running @@ -1273,7 +1298,7 @@ opus_custom_encoder_ctl ( CurOpusEncoder, Stop(); } - Q_UNUSED ( iUnused ); + Q_UNUSED ( iUnused ) } /// @brief Mix all audio data from all clients together. diff --git a/src/server.h b/src/server.h index d56a42c8..d68cac38 100755 --- a/src/server.h +++ b/src/server.h @@ -36,6 +36,7 @@ #endif #include "global.h" #include "buffer.h" +#include "signalhandler.h" #include "socket.h" #include "channel.h" #include "util.h" @@ -370,6 +371,8 @@ protected: ELicenceType eLicenceType; bool bDisconnectAllClients; + CSignalHandler* pSignalHandler; + signals: void Started(); void Stopped(); @@ -455,6 +458,10 @@ public slots: void OnCLDisconnection ( CHostAddress InetAddr ); + void OnAboutToQuit(); + + void OnShutdown ( int ); + #if QT_VERSION < 0x50000 // MOC does not expand macros in Qt 4, so we cannot use QT_VERSION_CHECK(5, 0, 0) // CODE TAG: MAX_NUM_CHANNELS_TAG // make sure we have MAX_NUM_CHANNELS connections!!! diff --git a/src/serverdlg.cpp b/src/serverdlg.cpp index 7717e023..7df039ed 100755 --- a/src/serverdlg.cpp +++ b/src/serverdlg.cpp @@ -342,18 +342,6 @@ lvwClients->setMinimumHeight ( 140 ); Timer.start ( GUI_CONTRL_UPDATE_TIME ); } -void CServerDlg::closeEvent ( QCloseEvent* Event ) -{ - // if server was registered at the central server, unregister on shutdown - if ( pServer->GetServerListEnabled() ) - { - pServer->UnregisterSlaveServer(); - } - - // default implementation of this event handler routine - Event->accept(); -} - void CServerDlg::OnStartOnOSStartStateChanged ( int value ) { const bool bCurAutoStartMinState = ( value == Qt::Checked ); diff --git a/src/serverdlg.h b/src/serverdlg.h index febb44ef..da06e0c4 100755 --- a/src/serverdlg.h +++ b/src/serverdlg.h @@ -58,7 +58,6 @@ public: protected: virtual void changeEvent ( QEvent* pEvent ); - virtual void closeEvent ( QCloseEvent* Event ); void UpdateGUIDependencies(); void UpdateSystemTrayIcon ( const bool bIsActive ); diff --git a/src/signalhandler.cpp b/src/signalhandler.cpp new file mode 100755 index 00000000..4c37d018 --- /dev/null +++ b/src/signalhandler.cpp @@ -0,0 +1,183 @@ +/******************************************************************************\ + * Copyright (c) 2020 + * + * Author(s): + * Peter L Jones + * + ****************************************************************************** + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + ****************************************************************************** + * + * This code contains some ideas derived from QCtrlSignals + * https://github.com/Skycoder42/QCtrlSignals.git + * - mostly the singleton and emitSignal code, plus some of the structure + * - virtually everything else is common knowledge across SourceForge answers + * + * BSD 3-Clause License + * + * Copyright (c) 2016, Felix Barz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * * Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * +\******************************************************************************/ + +#include "signalhandler.h" + +class CSignalHandlerSingleton : public CSignalHandler { +public: + inline CSignalHandlerSingleton() : CSignalHandler() {} +}; +Q_GLOBAL_STATIC ( CSignalHandlerSingleton, singleton ) + +CSignalHandler::CSignalHandler() : pSignalBase ( CSignalBase::withSignalHandler ( this ) ) {} + +CSignalHandler::~CSignalHandler() = default; + +CSignalHandler* CSignalHandler::getSingletonP() { return singleton; } + +bool CSignalHandler::emitSignal ( int sigNum ) +{ + return QMetaObject::invokeMethod( singleton, "ShutdownSignal", Qt::QueuedConnection, Q_ARG( int, sigNum ) ); +} + +#ifndef _WIN32 +void CSignalHandler::OnSocketNotify( int socket ) +{ + int sigNum; + if ( ::read ( socket, &sigNum, sizeof ( int ) ) == sizeof ( int ) ) + { + emitSignal ( sigNum ); + } +} +#endif + +// ---------------------------------------------------------- + +CSignalBase::CSignalBase ( CSignalHandler* pSignalHandler ) : + pSignalHandler ( pSignalHandler ) +{ +} + +CSignalBase::~CSignalBase() = default; + +CSignalBase* CSignalBase::withSignalHandler ( CSignalHandler* pSignalHandler ) +{ +#ifdef _WIN32 + return new CSignalWin ( pSignalHandler ); +#else + return new CSignalUnix ( pSignalHandler ); +#endif +} + +#ifdef _WIN32 +CSignalWin::CSignalWin ( CSignalHandler* nPSignalHandler ) : + CSignalBase ( nPSignalHandler ), + lock ( QReadWriteLock::Recursive ) +{ + SetConsoleCtrlHandler ( signalHandler, true ); +} + +CSignalWin::~CSignalWin() { + SetConsoleCtrlHandler ( signalHandler, false ); +} + +QReadWriteLock* CSignalWin::getLock() const +{ + return &lock; +} + +BOOL WINAPI CSignalWin::signalHandler ( _In_ DWORD sigNum ) +{ + auto self = getSelf(); + QReadLocker lock ( self->getLock() ); + return self->pSignalHandler->emitSignal ( static_cast( sigNum ) ); +} + +#else +int CSignalUnix::socketPair[2]; + +CSignalUnix::CSignalUnix ( CSignalHandler* nPSignalHandler ) : + CSignalBase ( nPSignalHandler ) +{ + if ( ::socketpair ( AF_UNIX, SOCK_STREAM, 0, socketPair ) == 0 ) + { + socketNotifier = new QSocketNotifier ( socketPair[ 1 ], QSocketNotifier::Read ); + + QObject::connect ( socketNotifier, &QSocketNotifier::activated, nPSignalHandler, &CSignalHandler::OnSocketNotify ); + + socketNotifier->setEnabled ( true ); + + setSignalHandled ( SIGINT, true ); + setSignalHandled ( SIGTERM, true ); + } +} + +CSignalUnix::~CSignalUnix() { + setSignalHandled ( SIGINT, false ); + setSignalHandled ( SIGTERM, false ); +} + +QReadWriteLock* CSignalUnix::getLock() const { return nullptr; } + +bool CSignalUnix::setSignalHandled ( int sigNum, bool state ) +{ + struct sigaction sa; + sigemptyset ( &sa.sa_mask ); + + if ( state ) + { + sa.sa_handler = CSignalUnix::signalHandler; + sa.sa_flags |= SA_RESTART; + } + else + { + sa.sa_handler = SIG_DFL; + } + + return ::sigaction ( sigNum, &sa, nullptr ) == 0; +} + +void CSignalUnix::signalHandler ( int sigNum ) +{ + const auto res = ::write ( socketPair[ 0 ], &sigNum, sizeof ( int ) ); + Q_UNUSED ( res ); +} +#endif diff --git a/src/signalhandler.h b/src/signalhandler.h new file mode 100755 index 00000000..1263ee6a --- /dev/null +++ b/src/signalhandler.h @@ -0,0 +1,177 @@ +/******************************************************************************\ + * Copyright (c) 2020 + * + * Author(s): + * Peter L Jones + * + ****************************************************************************** + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + ****************************************************************************** + * + * This code contains some ideas derived from QCtrlSignals + * https://github.com/Skycoder42/QCtrlSignals.git + * - mostly the singleton and emitSignal code, plus some of the structure + * - virtually everything else is common knowledge across SourceForge answers + * + * BSD 3-Clause License + * + * Copyright (c) 2016, Felix Barz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * * Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * +\******************************************************************************/ + +#pragma once + +#include +#include +#include +#include +#include +#include + +#ifdef _WIN32 +#include +#include +#include +#include +#include +#else +#include +#include +#include +#include +#include +#include +#include +#endif + +class CSignalBase; + +class CSignalHandler : public QObject +{ + Q_OBJECT + + friend class CSignalBase; + friend class CSignalHandlerSingleton; + +public: + static CSignalHandler* getSingletonP(); + + bool emitSignal ( int ); + +#ifndef _WIN32 +public slots: + void OnSocketNotify ( int socket ); +#endif + +signals: + void ShutdownSignal ( int sigNum ); + +private: + QScopedPointer pSignalBase; + + explicit CSignalHandler(); + ~CSignalHandler() override; +}; + +// ---------------------------------------------------------- + +class CSignalBase +{ + Q_DISABLE_COPY ( CSignalBase ) + +public: + static CSignalBase* withSignalHandler ( CSignalHandler* ); + virtual ~CSignalBase(); + + virtual QReadWriteLock* getLock() const = 0; + + QSet sHandledSigNums; + +protected: + CSignalBase ( CSignalHandler* ); + + CSignalHandler* pSignalHandler; + + template + static T *getSelf() + { + return static_cast( CSignalHandler::getSingletonP()->pSignalBase.data() ); + } + +}; + +#ifdef _WIN32 + +class CSignalWin : public CSignalBase +{ +public: + CSignalWin ( CSignalHandler* ); + ~CSignalWin() override; + + virtual QReadWriteLock* getLock() const override; + +private: + mutable QReadWriteLock lock; + + static BOOL WINAPI signalHandler ( _In_ DWORD sigNum ); +}; + +#else + +class CSignalUnix : public CSignalBase +{ +public: + CSignalUnix ( CSignalHandler* ); + ~CSignalUnix() override; + + virtual QReadWriteLock* getLock() const override; + +private: + QSocketNotifier* socketNotifier = nullptr; + bool setSignalHandled ( int sigNum, bool state ); + + static int socketPair[2]; + static void signalHandler ( int sigNum ); +}; + +#endif diff --git a/src/util.cpp b/src/util.cpp index fff72c99..44ceb1fd 100755 --- a/src/util.cpp +++ b/src/util.cpp @@ -388,7 +388,7 @@ CAboutDlg::CAboutDlg ( QWidget* parent ) : QDialog ( parent ) // contributors list txvContributors->setText ( "

Peter L. Jones (pljones)

" - "

Jonathan (gilgongo)

" + "

Jonathan Baker-Bates (gilgongo)

" "

Daniele Masato (doloopuntil)

" "

Simon Tomlinson (sthenos)

" "

Marc jr. Landolt (braindef)

"