diff --git a/mainwindow.cpp b/mainwindow.cpp index fb15b0b..a52515e 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -5,6 +5,7 @@ #include "QueryExplainModel.h" #include "sqlhighlighter.h" #include +#include #include #include "json/json.h" #include "explaintreemodelitem.h" @@ -59,6 +60,34 @@ MainWindow::MainWindow(QWidget *parent) : MainWindow::~MainWindow() {} +void MainWindow::QueueTask(callable c) +{ + std::lock_guard lg(m_mutexCallableQueue); + m_callableQueue.emplace_back(std::move(c)); + // Theoretically this needs to be only called if the queue was empty because otherwise it already would + // be busy emptying the queue. For now however I think it is safer to call it just to make sure. + QMetaObject::invokeMethod(this, "processCallableQueue", Qt::QueuedConnection); // queues on main thread +} + +void MainWindow::processCallableQueue() +{ + bool empty; + callable c; + { // narrow scope for lock guard + std::lock_guard lg(m_mutexCallableQueue); + c = m_callableQueue.back(); + m_callableQueue.pop_back(); + empty = m_callableQueue.empty(); + } + + c(); + + if (!empty) { + // This gives other events a chance to be processed to keep the UI snappy. + QTimer::singleShot(0, this, SLOT(processCallableQueue())); + } +} + void MainWindow::startConnect() { if (connection == nullptr) { @@ -125,6 +154,7 @@ void MainWindow::performQuery() QMetaObject::invokeMethod(this, "query_ready", Qt::QueuedConnection); // queues on main thread return res; }); + } void MainWindow::query_ready() diff --git a/mainwindow.h b/mainwindow.h index fadfedb..134e4fb 100644 --- a/mainwindow.h +++ b/mainwindow.h @@ -22,15 +22,36 @@ namespace Pgsql { } +#include +#include + +class TaskQueue { +public: + +private: +}; + class MainWindow : public QMainWindow { Q_OBJECT public: + using callable = std::function; + explicit MainWindow(QWidget *parent = 0); ~MainWindow(); + /* Meant to be called from other threads to pass a code block + * that has to be executed in the context of the thread of the window. + */ + void QueueTask(callable c); + private: + using t_CallableQueue = std::deque; + std::mutex m_mutexCallableQueue; + t_CallableQueue m_callableQueue; + + std::unique_ptr ui; std::unique_ptr highlighter; @@ -65,7 +86,7 @@ private slots: void cancel_query(); void receiveNotice(Pgsql::ErrorDetails notice); - + void processCallableQueue(); }; #endif // MAINWINDOW_H