Skip to content

Commit d8fe6df

Browse files
committed
Fix of the fix: avoid direct manipulation of GUI elements by non-GUI threads
1 parent 487f6e5 commit d8fe6df

5 files changed

Lines changed: 32 additions & 37 deletions

File tree

plugins/dataflow_analysis/include/dataflow_analysis/utils/progress_printer.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ namespace hal
3838

3939
void print_progress_to_stderr(float progress, const std::string& message = "");
4040

41-
// GUI calls must not be called from semaphore/mutex protected scope, otherwise threads might block each other
41+
// Safe to call from any thread, any lock state: the registered indicator posts a queued event to the GUI.
4242
void print_progress_to_gui(int percent = -1); // use m_last_percentage if negative
4343

4444
void print_message_to_gui(const std::string& message);

plugins/dataflow_analysis/src/utils/progress_printer.cpp

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,10 +41,7 @@ namespace hal
4141
if (!GuiExtensionDataflow::s_progress_indicator_function) return;
4242
if (percent < 0) percent = m_last_percentage;
4343
if (percent > 99) percent = 99;
44-
{
45-
GuiExtensionDataflow::s_progress_indicator_function(percent, m_gui_message);
46-
}
47-
44+
GuiExtensionDataflow::s_progress_indicator_function(percent, m_gui_message);
4845
}
4946

5047
void ProgressPrinter::print_progress_to_stderr(float progress, const std::string& message)

plugins/gui/include/gui/graph_widget/progress_bar.h

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@
3131
#include <QPushButton>
3232
#include <QImage>
3333
#include <QTimer>
34-
#include <QMutex>
3534

3635
namespace hal {
3736

@@ -65,14 +64,12 @@ namespace hal {
6564
Q_OBJECT
6665
QImage mImage;
6766
double mAngle;
68-
QMutex* mMutex;
6967
public Q_SLOTS:
7068
void handleTimeout();
7169
protected:
7270
void paintEvent(QPaintEvent* event) override;
7371
public:
7472
BusyAnimation(QWidget* parent = nullptr);
75-
~BusyAnimation();
7673
};
7774

7875
class BusyIndicator : public AbstractBusyIndicator
@@ -81,7 +78,6 @@ namespace hal {
8178
QTimer* mTimer;
8279
QLabel* mLabel;
8380
QProgressBar* mProgressBar;
84-
QMutex* mMutex;
8581
public:
8682
BusyIndicator(QWidget* parent = nullptr);
8783
~BusyIndicator();

plugins/gui/src/graph_widget/graph_widget.cpp

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
#include <QInputDialog>
4040
#include <QKeyEvent>
4141
#include <QMessageBox>
42+
#include <QThread>
4243
#include <QTimer>
4344
#include <QToolButton>
4445
#include <QVBoxLayout>
@@ -148,7 +149,10 @@ namespace hal
148149
if (!text.isEmpty())
149150
mProgressBar->setText(text);
150151
mProgressBar->setValue(percent);
151-
qApp->processEvents();
152+
if (QThread::currentThread() == qApp->thread())
153+
{
154+
qApp->processEvents();
155+
}
152156
}
153157

154158
void GraphWidget::showComments(const Node &nd)
@@ -1066,12 +1070,25 @@ namespace hal
10661070

10671071
void GraphWidget::pluginProgressIndicator(int percent, const std::string& msg)
10681072
{
1069-
// qDebug() << "progress" << hex << (quintptr) QThread::currentThread() << (quintptr) gPythonContext->currentThread() << (quintptr) dynamic_cast<PythonThread*>(QThread::currentThread());
1070-
if (!sInstance || gPythonContext->pythonThread()) return;
1071-
if (percent==100)
1072-
sInstance->handleSceneAvailable();
1073+
// Qt widgets must only be touched on the GUI thread. If we're already on it,
1074+
// call showBusy / handleSceneAvailable directly; otherwise post the update to
1075+
// the main event queue.
1076+
QString qmsg = QString::fromStdString(msg);
1077+
auto apply = [percent, qmsg]() {
1078+
if (!sInstance) return;
1079+
if (percent == 100)
1080+
sInstance->handleSceneAvailable();
1081+
else
1082+
sInstance->showBusy(percent, qmsg);
1083+
};
1084+
if (QThread::currentThread() == qApp->thread())
1085+
{
1086+
apply();
1087+
qApp->processEvents();
1088+
}
1089+
10731090
else
1074-
sInstance->showBusy(percent, QString::fromStdString(msg));
1091+
QMetaObject::invokeMethod(qApp, apply, Qt::QueuedConnection);
10751092
}
10761093

10771094
} // namespace hal

plugins/gui/src/graph_widget/progress_bar.cpp

Lines changed: 7 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,6 @@ namespace hal {
4646
BusyIndicator::BusyIndicator(QWidget* parent)
4747
: AbstractBusyIndicator(parent)
4848
{
49-
mMutex = new QMutex;
5049
QVBoxLayout* layout = new QVBoxLayout(this);
5150
layout->setAlignment(Qt::AlignHCenter);
5251
layout->addWidget(mLabel = new QLabel(this));
@@ -61,32 +60,23 @@ namespace hal {
6160
BusyIndicator::~BusyIndicator()
6261
{
6362
mTimer->stop();
64-
delete mMutex;
6563
}
6664

6765
BusyAnimation::BusyAnimation(QWidget* parent)
68-
: QWidget(parent), mImage(QImage(":/icons/hal9000","PNG")), mAngle(0), mMutex(new QMutex)
66+
: QWidget(parent), mImage(QImage(":/icons/hal9000","PNG")), mAngle(0)
6967
{;}
7068

71-
BusyAnimation::~BusyAnimation()
72-
{
73-
delete mMutex;
74-
}
75-
7669
void BusyAnimation::handleTimeout()
7770
{
7871
mAngle += 5;
7972
update();
80-
qApp->processEvents();
8173
}
8274

8375
void BusyAnimation::paintEvent(QPaintEvent* event)
8476
{
8577
Q_UNUSED(event);
86-
if (mMutex->try_lock())
87-
{
88-
QPainter p(this);
89-
p.setRenderHint(QPainter::Antialiasing);
78+
QPainter p(this);
79+
p.setRenderHint(QPainter::Antialiasing);
9080

9181
int rw = rect().width();
9282
int rh = rect().height();
@@ -116,25 +106,20 @@ namespace hal {
116106
}
117107
}
118108

119-
p.drawImage(rimg,img);
120-
mMutex->unlock();
121-
}
109+
p.drawImage(rimg,img);
122110
}
123111

124112
void BusyIndicator::setValue(int percent)
125113
{
126-
if (mProgressBar->value() == percent) return; // nothing to do
127-
QMutexLocker lock(mMutex);
114+
if (mProgressBar->value() == percent) return;
128115
mProgressBar->setValue(percent);
129116
update();
130-
qApp->processEvents();
131117
}
132118

133119
void BusyIndicator::setText(const QString &txt)
134120
{
135-
if (mLabel->text() == txt) return; // nothing to do
136-
QMutexLocker lock(mMutex);
121+
if (mLabel->text() == txt) return;
137122
mLabel->setText(txt);
138-
qApp->processEvents();
123+
update();
139124
}
140125
}

0 commit comments

Comments
 (0)