This commit is contained in:
Jonas Kvinge 2019-07-24 23:29:09 +02:00
parent da0d61f36a
commit 41484f8673
14 changed files with 135 additions and 41 deletions

View File

@ -127,8 +127,10 @@ void SCollection::Exit() {
void SCollection::ExitReceived() {
disconnect(sender(), 0, this, 0);
wait_for_exit_.removeAll(sender());
QObject *obj = static_cast<QObject*>(sender());
disconnect(obj, 0, this, 0);
qLog(Debug) << obj << "successfully exited.";
wait_for_exit_.removeAll(obj);
if (wait_for_exit_.isEmpty()) emit ExitFinished();
}

View File

@ -248,19 +248,27 @@ void Application::MoveToThread(QObject *object, QThread *thread) {
void Application::Exit() {
wait_for_exit_ << collection()
wait_for_exit_ << tag_reader_client()
<< collection()
<< playlist_backend()
<< album_cover_loader()
#ifndef Q_OS_WIN
<< device_manager()
#endif
<< internet_services();
connect(tag_reader_client(), SIGNAL(ExitFinished()), this, SLOT(ExitReceived()));
tag_reader_client()->ExitAsync();
connect(collection(), SIGNAL(ExitFinished()), this, SLOT(ExitReceived()));
collection()->Exit();
connect(playlist_backend(), SIGNAL(ExitFinished()), this, SLOT(ExitReceived()));
playlist_backend()->ExitAsync();
connect(album_cover_loader(), SIGNAL(ExitFinished()), this, SLOT(ExitReceived()));
album_cover_loader()->ExitAsync();
#ifndef Q_OS_WIN
connect(device_manager(), SIGNAL(ExitFinished()), this, SLOT(ExitReceived()));
device_manager()->Exit();
@ -269,16 +277,21 @@ void Application::Exit() {
connect(internet_services(), SIGNAL(ExitFinished()), this, SLOT(ExitReceived()));
internet_services()->Exit();
database()->Close();
}
void Application::ExitReceived() {
disconnect(sender(), 0, this, 0);
QObject *obj = static_cast<QObject*>(sender());
disconnect(obj, 0, this, 0);
wait_for_exit_.removeAll(sender());
if (wait_for_exit_.isEmpty()) emit ExitFinished();
qLog(Debug) << obj << "successfully exited.";
wait_for_exit_.removeAll(obj);
if (wait_for_exit_.isEmpty()) {
database()->Close();
connect(database(), SIGNAL(ExitFinished()), this, SIGNAL(ExitFinished()));
database()->ExitAsync();
}
}

View File

@ -229,7 +229,10 @@ Database::Database(Application *app, QObject *parent, const QString &database_na
mutex_(QMutex::Recursive),
injected_database_name_(database_name),
query_hash_(0),
startup_schema_version_(-1) {
startup_schema_version_(-1),
original_thread_(nullptr) {
original_thread_ = thread();
{
QMutexLocker l(&sNextConnectionIdMutex);
@ -259,6 +262,19 @@ Database::~Database() {
}
void Database::ExitAsync() {
metaObject()->invokeMethod(this, "Exit", Qt::QueuedConnection);
}
void Database::Exit() {
assert(QThread::currentThread() == thread());
Close();
moveToThread(original_thread_);
emit ExitFinished();
}
QSqlDatabase Database::Connect() {
QMutexLocker l(&connect_mutex_);

View File

@ -44,6 +44,7 @@ struct sqlite3_tokenizer_cursor;
struct sqlite3_tokenizer_module;
}
class QThread;
class Application;
class Database : public QObject {
@ -67,6 +68,7 @@ class Database : public QObject {
static const char *kDatabaseFilename;
static const char *kMagicAllSongsTables;
void ExitAsync();
QSqlDatabase Connect();
void Close();
bool CheckErrors(const QSqlQuery &query);
@ -82,9 +84,13 @@ class Database : public QObject {
void AttachDatabaseOnDbConnection(const QString &database_name, const AttachedDatabase &database, QSqlDatabase &db);
void DetachDatabase(const QString &database_name);
signals:
signals:
void ExitFinished();
void Error(const QString &message);
private slots:
void Exit();
public slots:
void DoBackup();
@ -126,6 +132,8 @@ signals:
// This is the schema version of Strawberry's DB from the app's last run.
int startup_schema_version_;
QThread *original_thread_;
// Do static initialisation like loading sqlite functions.
static void StaticInit();

View File

@ -237,7 +237,8 @@ MainWindow::MainWindow(Application *app, SystemTrayIcon *tray_icon, OSD *osd, co
playing_widget_(true),
doubleclick_addmode_(BehaviourSettingsPage::AddBehaviour_Append),
doubleclick_playmode_(BehaviourSettingsPage::PlayBehaviour_Never),
menu_playmode_(BehaviourSettingsPage::PlayBehaviour_Never)
menu_playmode_(BehaviourSettingsPage::PlayBehaviour_Never),
exit_count_(0)
{
qLog(Debug) << "Starting";
@ -985,20 +986,26 @@ void MainWindow::SaveSettings() {
void MainWindow::Exit() {
++exit_count_;
SaveSettings();
if (app_->player()->engine()->is_fadeout_enabled()) {
// To shut down the application when fadeout will be finished
connect(app_->player()->engine(), SIGNAL(FadeoutFinishedSignal()), this, SLOT(DoExit()));
if (app_->player()->GetState() == Engine::Playing) {
app_->player()->Stop();
hide();
if (tray_icon_) tray_icon_->SetVisible(false);
return; // Don't quit the application now: wait for the fadeout finished signal
}
if (exit_count_ > 1) {
qApp->quit();
}
else {
if (app_->player()->engine()->is_fadeout_enabled()) {
// To shut down the application when fadeout will be finished
connect(app_->player()->engine(), SIGNAL(FadeoutFinishedSignal()), this, SLOT(DoExit()));
if (app_->player()->GetState() == Engine::Playing) {
app_->player()->Stop();
hide();
if (tray_icon_) tray_icon_->SetVisible(false);
return; // Don't quit the application now: wait for the fadeout finished signal
}
}
DoExit();
}
DoExit();
}
@ -1323,8 +1330,8 @@ void MainWindow::closeEvent(QCloseEvent *event) {
}
else {
Exit();
QApplication::quit();
}
}
void MainWindow::SetHiddenInTray(bool hidden) {

View File

@ -369,6 +369,7 @@ signals:
Song song_;
Song song_playing_;
QImage image_original_;
int exit_count_;
};

View File

@ -42,6 +42,7 @@ TagReaderClient *TagReaderClient::sInstance = nullptr;
TagReaderClient::TagReaderClient(QObject *parent) : QObject(parent), worker_pool_(new WorkerPool<HandlerType>(this)) {
sInstance = this;
original_thread_ = thread();
worker_pool_->SetExecutableName(kWorkerExecutableName);
worker_pool_->SetWorkerCount(QThread::idealThreadCount());
@ -50,6 +51,18 @@ TagReaderClient::TagReaderClient(QObject *parent) : QObject(parent), worker_pool
void TagReaderClient::Start() { worker_pool_->Start(); }
void TagReaderClient::ExitAsync() {
metaObject()->invokeMethod(this, "Exit", Qt::QueuedConnection);
}
void TagReaderClient::Exit() {
assert(QThread::currentThread() == thread());
moveToThread(original_thread_);
emit ExitFinished();
}
void TagReaderClient::WorkerFailedToStart() {
qLog(Error) << "The" << kWorkerExecutableName << "executable was not found in the current directory or on the PATH. Strawberry will not be able to read music file tags without it.";
}

View File

@ -36,6 +36,7 @@
#include "song.h"
#include "tagreadermessages.pb.h"
class QThread;
class Song;
template <typename HandlerType> class WorkerPool;
@ -51,6 +52,7 @@ class TagReaderClient : public QObject {
static const char *kWorkerExecutableName;
void Start();
void ExitAsync();
ReplyType *ReadFile(const QString &filename);
ReplyType *SaveFile(const QString &filename, const Song &metadata);
@ -67,7 +69,11 @@ class TagReaderClient : public QObject {
// TODO: Make this not a singleton
static TagReaderClient *Instance() { return sInstance; }
signals:
void ExitFinished();
private slots:
void Exit();
void WorkerFailedToStart();
private:
@ -75,6 +81,7 @@ class TagReaderClient : public QObject {
WorkerPool<HandlerType> *worker_pool_;
QList<pb::tagreader::Message> message_queue_;
QThread *original_thread_;
};
typedef TagReaderClient::ReplyType TagReaderReply;

View File

@ -23,12 +23,12 @@
#include <QtGlobal>
#include <QObject>
#include <QDir>
#include <QQueue>
#include <QMutex>
#include <QStandardPaths>
#include <QSize>
#include <QDir>
#include <QThread>
#include <QMutex>
#include <QList>
#include <QQueue>
#include <QSet>
#include <QVariant>
#include <QString>
@ -37,6 +37,7 @@
#include <QImage>
#include <QPixmap>
#include <QPainter>
#include <QSize>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QNetworkRequest>
@ -61,13 +62,30 @@ AlbumCoverLoader::AlbumCoverLoader(QObject *parent)
cover_filename_(CollectionSettingsPage::SaveCover_Hash),
cover_overwrite_(false),
cover_lowercase_(true),
cover_replace_spaces_(true)
cover_replace_spaces_(true),
original_thread_(nullptr)
{
original_thread_ = thread();
ReloadSettings();
}
void AlbumCoverLoader::ExitAsync() {
stop_requested_ = true;
metaObject()->invokeMethod(this, "Exit", Qt::QueuedConnection);
}
void AlbumCoverLoader::Exit() {
assert(QThread::currentThread() == thread());
moveToThread(original_thread_);
emit ExitFinished();
}
void AlbumCoverLoader::ReloadSettings() {
QSettings s;

View File

@ -41,6 +41,7 @@
#include "settings/collectionsettingspage.h"
#include "albumcoverloaderoptions.h"
class QThread;
class Song;
class NetworkAccessManager;
@ -52,6 +53,7 @@ class AlbumCoverLoader : public QObject {
void ReloadSettings();
void ExitAsync();
void Stop() { stop_requested_ = true; }
static QString ImageCacheDir(const Song::Source source);
@ -68,11 +70,13 @@ class AlbumCoverLoader : public QObject {
static QPixmap TryLoadPixmap(const QUrl &automatic, const QUrl &manual, const QUrl &url = QUrl());
static QImage ScaleAndPad(const AlbumCoverLoaderOptions &options, const QImage &image);
signals:
signals:
void ExitFinished();
void ImageLoaded(const quint64 id, const QUrl &cover_url, const QImage &image);
void ImageLoaded(const quint64 id, const QUrl &cover_url, const QImage &scaled, const QImage &original);
protected slots:
void Exit();
void ProcessTasks();
void RemoteFetchFinished(QNetworkReply *reply, const QUrl &cover_url);
@ -128,6 +132,8 @@ signals:
bool cover_lowercase_;
bool cover_replace_spaces_;
QThread *original_thread_;
};
#endif // ALBUMCOVERLOADER_H

View File

@ -86,7 +86,6 @@ void InternetServices::Exit() {
void InternetServices::ExitReceived() {
InternetService *service = qobject_cast<InternetService*>(sender());
wait_for_exit_.removeAll(service);
if (wait_for_exit_.isEmpty()) emit ExitFinished();

View File

@ -180,9 +180,9 @@ QobuzService::~QobuzService() {
stream_url_req->deleteLater();
}
delete artists_collection_backend_;
delete albums_collection_backend_;
delete songs_collection_backend_;
artists_collection_backend_->deleteLater();
albums_collection_backend_->deleteLater();
songs_collection_backend_->deleteLater();
}
@ -202,8 +202,10 @@ void QobuzService::Exit() {
void QobuzService::ExitReceived() {
disconnect(sender(), 0, this, 0);
wait_for_exit_.removeAll(sender());
QObject *obj = static_cast<QObject*>(sender());
disconnect(obj, 0, this, 0);
qLog(Debug) << obj << "successfully exited.";
wait_for_exit_.removeAll(obj);
if (wait_for_exit_.isEmpty()) emit ExitFinished();
}

View File

@ -95,7 +95,7 @@ SubsonicService::SubsonicService(Application *app, QObject *parent)
}
SubsonicService::~SubsonicService() {
delete collection_backend_;
collection_backend_->deleteLater();
}
void SubsonicService::Exit() {

View File

@ -186,9 +186,9 @@ TidalService::~TidalService() {
stream_url_req->deleteLater();
}
delete artists_collection_backend_;
delete albums_collection_backend_;
delete songs_collection_backend_;
artists_collection_backend_->deleteLater();
albums_collection_backend_->deleteLater();
songs_collection_backend_->deleteLater();
}
@ -208,8 +208,10 @@ void TidalService::Exit() {
void TidalService::ExitReceived() {
disconnect(sender(), 0, this, 0);
wait_for_exit_.removeAll(sender());
QObject *obj = static_cast<QObject*>(sender());
disconnect(obj, 0, this, 0);
qLog(Debug) << obj << "successfully exited.";
wait_for_exit_.removeAll(obj);
if (wait_for_exit_.isEmpty()) emit ExitFinished();
}