diff --git a/src/slic3r/CMakeLists.txt b/src/slic3r/CMakeLists.txt index 1973932b9f..9a2b5c66b2 100644 --- a/src/slic3r/CMakeLists.txt +++ b/src/slic3r/CMakeLists.txt @@ -173,7 +173,7 @@ set(SLIC3R_GUI_SOURCES GUI/Jobs/BoostThreadWorker.hpp GUI/Jobs/BoostThreadWorker.cpp GUI/Jobs/BusyCursorJob.hpp - GUI/Jobs/PlaterJob.hpp + GUI/Jobs/PlaterWorker.hpp GUI/Jobs/ArrangeJob.hpp GUI/Jobs/ArrangeJob.cpp GUI/Jobs/RotoptimizeJob.hpp diff --git a/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp b/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp index ac23f754c9..58c5aa9566 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp @@ -11,7 +11,6 @@ #include "libslic3r/PresetBundle.hpp" #include "slic3r/GUI/Jobs/RotoptimizeJob.hpp" -#include "slic3r/GUI/Jobs/PlaterJob.hpp" namespace Slic3r { namespace GUI { diff --git a/src/slic3r/GUI/Jobs/ArrangeJob.cpp b/src/slic3r/GUI/Jobs/ArrangeJob.cpp index 500fc3a10d..3c7dad0a61 100644 --- a/src/slic3r/GUI/Jobs/ArrangeJob.cpp +++ b/src/slic3r/GUI/Jobs/ArrangeJob.cpp @@ -164,10 +164,11 @@ void ArrangeJob::prepare() void ArrangeJob::process(Ctl &ctl) { - ctl.call_on_main_thread([this]{ prepare(); }).wait(); - static const auto arrangestr = _u8L("Arranging"); + ctl.update_status(0, arrangestr); + ctl.call_on_main_thread([this]{ prepare(); }).wait();; + arrangement::ArrangeParams params = get_arrange_params(m_plater); auto count = unsigned(m_selected.size() + m_unprintable.size()); @@ -196,7 +197,7 @@ void ArrangeJob::process(Ctl &ctl) _u8L("Arranging done.")); } -ArrangeJob::ArrangeJob() : m_plater{wxGetApp().plater()} { } +ArrangeJob::ArrangeJob() : m_plater{wxGetApp().plater()} {} static std::string concat_strings(const std::set &strings, const std::string &delim = "\n") diff --git a/src/slic3r/GUI/Jobs/BoostThreadWorker.cpp b/src/slic3r/GUI/Jobs/BoostThreadWorker.cpp index 21455e103a..40729a0e89 100644 --- a/src/slic3r/GUI/Jobs/BoostThreadWorker.cpp +++ b/src/slic3r/GUI/Jobs/BoostThreadWorker.cpp @@ -29,7 +29,7 @@ void BoostThreadWorker::WorkerMessage::deliver(BoostThreadWorker &runner) case MainThreadCall: { MainThreadCallData &calldata = std::get(m_data); calldata.fn(); - calldata.barrier.set_value(); + calldata.promise.set_value(); break; } @@ -69,7 +69,7 @@ void BoostThreadWorker::update_status(int st, const std::string &msg) std::future BoostThreadWorker::call_on_main_thread(std::function fn) { MainThreadCallData cbdata{std::move(fn), {}}; - std::future future = cbdata.barrier.get_future(); + std::future future = cbdata.promise.get_future(); m_output_queue.push(std::move(cbdata)); @@ -77,8 +77,8 @@ std::future BoostThreadWorker::call_on_main_thread(std::function } BoostThreadWorker::BoostThreadWorker(std::shared_ptr pri, - boost::thread::attributes &attribs, - const char * name) + boost::thread::attributes &attribs, + const char * name) : m_progress(std::move(pri)), m_name{name} { if (m_progress) diff --git a/src/slic3r/GUI/Jobs/BoostThreadWorker.hpp b/src/slic3r/GUI/Jobs/BoostThreadWorker.hpp index aeacf39878..31ca9b5910 100644 --- a/src/slic3r/GUI/Jobs/BoostThreadWorker.hpp +++ b/src/slic3r/GUI/Jobs/BoostThreadWorker.hpp @@ -39,7 +39,7 @@ class BoostThreadWorker : public Worker, private Job::Ctl struct MainThreadCallData { std::function fn; - std::promise barrier; + std::promise promise; }; class WorkerMessage @@ -55,6 +55,8 @@ class BoostThreadWorker : public Worker, private Job::Ctl WorkerMessage(JobEntry &&entry) : m_data{std::move(entry)} {} WorkerMessage(MainThreadCallData fn) : m_data{std::move(fn)} {} + int get_type () const { return m_data.index(); } + void deliver(BoostThreadWorker &runner); }; diff --git a/src/slic3r/GUI/Jobs/FillBedJob.cpp b/src/slic3r/GUI/Jobs/FillBedJob.cpp index 979db77cba..c7d69eb500 100644 --- a/src/slic3r/GUI/Jobs/FillBedJob.cpp +++ b/src/slic3r/GUI/Jobs/FillBedJob.cpp @@ -105,7 +105,9 @@ void FillBedJob::prepare() void FillBedJob::process(Ctl &ctl) { - ctl.call_on_main_thread([this]{ prepare(); }).wait(); + auto statustxt = _u8L("Filling bed"); + ctl.call_on_main_thread([this] { prepare(); }).wait(); + ctl.update_status(0, statustxt); if (m_object_idx == -1 || m_selected.empty()) return; @@ -121,10 +123,6 @@ void FillBedJob::process(Ctl &ctl) return ctl.was_canceled() || do_stop; }; - auto statustxt = _u8L("Filling bed"); - - ctl.update_status(0, statustxt); - params.progressind = [this, &ctl, &statustxt](unsigned st) { if (st > 0) ctl.update_status(int(m_status_range - st) * 100 / status_range(), statustxt); diff --git a/src/slic3r/GUI/Jobs/PlaterJob.hpp b/src/slic3r/GUI/Jobs/PlaterWorker.hpp similarity index 59% rename from src/slic3r/GUI/Jobs/PlaterJob.hpp rename to src/slic3r/GUI/Jobs/PlaterWorker.hpp index c20075f0e7..ee64718e65 100644 --- a/src/slic3r/GUI/Jobs/PlaterJob.hpp +++ b/src/slic3r/GUI/Jobs/PlaterWorker.hpp @@ -1,5 +1,5 @@ -#ifndef PLATERJOB_HPP -#define PLATERJOB_HPP +#ifndef PLATERWORKER_HPP +#define PLATERWORKER_HPP #include "BusyCursorJob.hpp" @@ -24,8 +24,32 @@ class PlaterWorker: public Worker { public: void process(Ctl &c) override { - CursorSetterRAII busycursor{c}; - m_job->process(c); + // Ensure that wxWidgets processing wakes up to handle outgoing + // messages in plater's wxIdle handler. Otherwise it might happen + // that the message will only be processed when an event like mouse + // move comes along which might be too late. + struct WakeUpCtl: Ctl { + Ctl &ctl; + WakeUpCtl(Ctl &c) : ctl{c} {} + + void update_status(int st, const std::string &msg = "") override + { + wxWakeUpIdle(); + ctl.update_status(st, msg); + } + + bool was_canceled() const override { return ctl.was_canceled(); } + + std::future call_on_main_thread(std::function fn) override + { + wxWakeUpIdle(); + return ctl.call_on_main_thread(std::move(fn)); + } + + } wctl{c}; + + CursorSetterRAII busycursor{wctl}; + m_job->process(wctl); } void finalize(bool canceled, std::exception_ptr &eptr) override @@ -60,10 +84,18 @@ class PlaterWorker: public Worker { } }; -public: - template - PlaterWorker(WorkerArgs &&...args) : m_w{std::forward(args)...} {} +public: + template + PlaterWorker(Plater *plater, WorkerArgs &&...args) + : m_w{std::forward(args)...} + { + // Ensure that messages from the worker thread to the UI thread are + // processed continuously. + plater->Bind(wxEVT_IDLE, [this](wxIdleEvent &) { + m_w.process_events(); + }); + } // Always package the job argument into a PlaterJob bool start_next(std::unique_ptr job) override @@ -74,7 +106,7 @@ public: bool is_idle() const override { return m_w.is_idle(); } void cancel() override { m_w.cancel(); } void cancel_all() override { m_w.cancel_all(); } - void process_events() override { m_w.process_events(); } + void process_events() override {} }; }} // namespace Slic3r::GUI diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index caaa4a4c89..5cd787882c 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -75,7 +75,7 @@ #include "Jobs/SLAImportJob.hpp" #include "Jobs/SLAImportDialog.hpp" #include "Jobs/NotificationProgressIndicator.hpp" -#include "Jobs/PlaterJob.hpp" +#include "Jobs/PlaterWorker.hpp" #include "Jobs/BoostThreadWorker.hpp" #include "BackgroundSlicingProcess.hpp" #include "PrintHostDialogs.hpp" @@ -1943,7 +1943,7 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame) })) , sidebar(new Sidebar(q)) , notification_manager(std::make_unique(q)) - , m_worker{std::make_unique(notification_manager.get()), "ui_worker"} + , m_worker{q, std::make_unique(notification_manager.get()), "ui_worker"} , m_sla_import_dlg{new SLAImportDialog{q}} , delayed_scene_refresh(false) , view_toolbar(GLToolbar::Radio, "View") @@ -2173,12 +2173,6 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame) bool is_collapsed = wxGetApp().app_config->get("collapsed_sidebar") == "1"; sidebar->collapse(is_collapsed); } - - // Ensure that messages from the worker thread to the UI thread are processed - // continuously. - main_frame->Bind(wxEVT_IDLE, [this](const wxIdleEvent &) { - m_worker.process_events(); - }); } Plater::priv::~priv()