diff --git a/sleepyhead/main.cpp b/sleepyhead/main.cpp index 48f0b8c8..1c11a9f8 100644 --- a/sleepyhead/main.cpp +++ b/sleepyhead/main.cpp @@ -25,6 +25,8 @@ #include #include #include +#include + #include "SleepLib/schema.h" #include "mainwindow.h" @@ -50,18 +52,19 @@ MainWindow *mainwin = nullptr; +QMutex mutex; + #if QT_VERSION < QT_VERSION_CHECK(5,0,0) void MyOutputHandler(QtMsgType type, const char *msgtxt) { + #else void MyOutputHandler(QtMsgType type, const QMessageLogContext &context, const QString &msgtxt) { Q_UNUSED(context) #endif - if (!mainwin) { - // qInstallMessageHandler(0); - + if (!logger) { #if QT_VERSION >= QT_VERSION_CHECK(5,0,0) fprintf(stderr, "Pre/Post: %s\n", msgtxt.toLocal8Bit().constData()); #else @@ -96,13 +99,16 @@ void MyOutputHandler(QtMsgType type, const QMessageLogContext &context, const QS #else msg = typestr + msgtxt; #endif - mainwin->Log(msg); + + if (logger && logger->isRunning()) logger->append(msg); + else { + fprintf(stderr, msg.toLocal8Bit().data()); + } if (type == QtFatalMsg) { abort(); } - //loglock.unlock(); } void initialize() @@ -173,6 +179,23 @@ int main(int argc, char *argv[]) } } + logger = new LogThread(); + QThreadPool * threadpool = QThreadPool::globalInstance(); + bool b = threadpool->tryStart(logger); + if (b) { + qWarning() << "Started logging thread"; + } else { + qWarning() << "Logging thread did not start correctly"; + } + +#if QT_VERSION >= QT_VERSION_CHECK(5,0,0) + qInstallMessageHandler(MyOutputHandler); +#else + qInstallMsgHandler(MyOutputHandler); +#endif + + + //////////////////////////////////////////////////////////////////////////////////////////// // Language Selection //////////////////////////////////////////////////////////////////////////////////////////// @@ -430,18 +453,12 @@ retry_directory: qDebug() << "Selected Font" << QApplication::font().family(); -#if QT_VERSION >= QT_VERSION_CHECK(5,0,0) - qInstallMessageHandler(MyOutputHandler); -#else - qInstallMsgHandler(MyOutputHandler); -#endif - // Must be initialized AFTER profile creation MainWindow w; mainwin = &w; - if (check_updates) { mainwin->CheckForUpdates(); } + // if (check_updates) { mainwin->CheckForUpdates(); } w.show(); diff --git a/sleepyhead/mainwindow.cpp b/sleepyhead/mainwindow.cpp index 67706462..8683c44e 100644 --- a/sleepyhead/mainwindow.cpp +++ b/sleepyhead/mainwindow.cpp @@ -33,6 +33,8 @@ #include #include #include +#include + #include "common_gui.h" #include @@ -114,31 +116,47 @@ QString getGraphicsEngine() return gfxEngine; } -void MainWindow::Log(QString s) +LogThread * logger = nullptr; + +void LogThread::append(QString msg) { - - if (!strlock.tryLock()) { - return; - } - - // strlock.lock(); - QString tmp = QString("%1: %2").arg(logtime.elapsed(), 5, 10, QChar('0')).arg(s); - - logbuffer.append(tmp); //QStringList appears not to be threadsafe - strlock.unlock(); - + QString tmp = QString("%1: %2").arg(logtime.elapsed(), 5, 10, QChar('0')).arg(msg); + //QStringList appears not to be threadsafe strlock.lock(); - - // only do this in the main thread? - for (int i = 0; i < logbuffer.size(); i++) { - ui->logText->appendPlainText(logbuffer[i]); - fprintf(stderr, "%s\n", logbuffer[i].toLocal8Bit().constData()); - } - - logbuffer.clear(); + buffer.append(tmp); strlock.unlock(); +} - //loglock.unlock(); +void LogThread::quit() { + qDebug() << "Shutting down logging thread"; + running = false; + strlock.lock(); + while (!buffer.isEmpty()) { + QString msg = buffer.takeFirst(); + fprintf(stderr, "%s\n", msg.toLocal8Bit().constData()); + } + strlock.unlock(); +} + + +void LogThread::run() +{ + running = true; + do { + strlock.lock(); + while (!buffer.isEmpty()) { + QString msg = buffer.takeFirst(); + emit outputLog(msg); + fprintf(stderr, "%s\n", msg.toLocal8Bit().constData()); + } + strlock.unlock(); + QThread::msleep(1000); + } while (running); +} + +void MainWindow::logMessage(QString msg) +{ + ui->logText->appendPlainText(msg); } MainWindow::MainWindow(QWidget *parent) : @@ -147,9 +165,12 @@ MainWindow::MainWindow(QWidget *parent) : { Q_ASSERT(p_profile != nullptr); - logtime.start(); ui->setupUi(this); + if (logger) { + connect(logger, SIGNAL(outputLog(QString)), this, SLOT(logMessage(QString))); + } + QString version = VersionString; #ifdef TEST_BUILD @@ -164,6 +185,14 @@ MainWindow::MainWindow(QWidget *parent) : this->setWindowTitle(STR_TR_SleepyHead + QString(" v%1 (" + tr("Profile") + ": %2)").arg(version).arg(PREF[STR_GEN_Profile].toString())); + + qDebug() << STR_TR_SleepyHeadVersion.toLocal8Bit().data() << "built with Qt" << QT_VERSION_STR << + "on" << __DATE__ << __TIME__; + +#ifdef BROKEN_OPENGL_BUILD + qDebug() << "This build has been created especially for computers with older graphics hardware.\n"; +#endif + //ui->tabWidget->setCurrentIndex(1); #ifdef Q_OS_MAC @@ -315,27 +344,28 @@ MainWindow::MainWindow(QWidget *parent) : void MainWindow::closeEvent(QCloseEvent * event) { + // Shutdown and Save the current User profile + Profiles::Done(); + if (daily) { - daily->close(); + //daily->close(); daily->deleteLater(); } if (overview) { - overview->close(); + //overview->close(); overview->deleteLater(); } if (oximetry) { - oximetry->close(); + //oximetry->close(); oximetry->deleteLater(); } - // Shutdown and Save the current User profile - Profiles::Done(); - // Save current window position QSettings settings(getDeveloperName(), getAppName()); settings.setValue("MainWindow/geometry", saveGeometry()); + QMainWindow::closeEvent(event); } @@ -349,6 +379,12 @@ MainWindow::~MainWindow() // Trash anything allocated by the Graph objects DestroyGraphGlobals(); + logger->quit(); + disconnect(logger, SIGNAL(outputLog(QString)), this, SLOT(logMessage(QString))); + + QThreadPool::globalInstance()->waitForDone(-1); + logger = nullptr; + mainwin = nullptr; delete ui; } @@ -400,13 +436,6 @@ void MainWindow::PopulatePurgeMenu() void MainWindow::Startup() { - qDebug() << STR_TR_SleepyHeadVersion.toLocal8Bit().data() << "built with Qt" << QT_VERSION_STR << - "on" << __DATE__ << __TIME__; - -#ifdef BROKEN_OPENGL_BUILD - qDebug() << "This build has been created especially for computers with older graphics hardware.\n"; -#endif - qstatus->setText(tr("Loading Data")); qprogress->show(); //qstatusbar->showMessage(tr("Loading Data"),0); @@ -1219,11 +1248,14 @@ void MainWindow::on_actionDebug_toggled(bool checked) { PROFILE.general->setShowDebug(checked); + logger->strlock.lock(); if (checked) { ui->logText->show(); } else { ui->logText->hide(); } + // QApplication::processEvents(); + logger->strlock.unlock(); } void MainWindow::on_action_Reset_Graph_Layout_triggered() diff --git a/sleepyhead/mainwindow.h b/sleepyhead/mainwindow.h index 96b440ef..85fb8795 100644 --- a/sleepyhead/mainwindow.h +++ b/sleepyhead/mainwindow.h @@ -17,6 +17,8 @@ #include #include #include +#include +#include #include "version.h" #include "daily.h" @@ -65,6 +67,30 @@ class Daily; class Report; class Overview; +class LogThread:public QObject, public QRunnable +{ + Q_OBJECT +public: + explicit LogThread() { running = false; logtime.start(); } + virtual ~LogThread() {} + + void run(); + void append(QString msg); + bool isRunning() { return running; } + + void quit(); + + QStringList buffer; + QMutex strlock; +signals: + void outputLog(QString); +protected: + volatile bool running; + QTime logtime; +}; +extern LogThread * logger; + + /*! \class MainWindow \author Mark Watkins \brief The Main Application window for SleepyHead @@ -78,9 +104,6 @@ class MainWindow : public QMainWindow explicit MainWindow(QWidget *parent = 0); ~MainWindow(); - //! \brief Log message s to Application Debug log - void Log(QString s); - //! \brief Update the list of Favourites (Bookmarks) in the right sidebar. void updateFavourites(); @@ -314,6 +337,8 @@ class MainWindow : public QMainWindow void on_actionPurgeCurrentDaysOximetry_triggered(); + void logMessage(QString msg); + private: int importCPAP(const QString &path, const QString &message); void importCPAPBackups(); @@ -329,8 +354,6 @@ private: Oximetry *oximetry; bool first_load; PreferencesDialog *prefdialog; - QMutex loglock, strlock; - QStringList logbuffer; QTime logtime; QSystemTrayIcon *systray; QMenu *systraymenu; @@ -343,8 +366,6 @@ private: //! \brief Destroy ALL the CPAP data for the selected machine void purgeMachine(Machine *); - - }; #endif // MAINWINDOW_H