diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index 560ed434d5..1a1d1bcbff 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -2482,6 +2482,7 @@ void GCode::do_export(Print* print, const char* path, GCodeProcessorResult* resu ctx.name = std::to_string(print->model().id().id); ctx.code = LifecycleEvtCode::Ok; ctx.msg = path; + ctx.cancellation_check = [print]() { return print->canceled(); }; fire_lifecycle_event(LifecycleEvent::GCodeExportStarted, ctx); } @@ -2533,6 +2534,7 @@ void GCode::do_export(Print* print, const char* path, GCodeProcessorResult* resu ctx.name = std::to_string(print->model().id().id); ctx.code = LifecycleEvtCode::Error; ctx.msg = std::string(path) + "\n" + err_msg; + ctx.cancellation_check = [print]() { return print->canceled(); }; fire_lifecycle_event(LifecycleEvent::GCodeExportFinished, ctx); } throw Slic3r::RuntimeError(err_msg); @@ -2556,6 +2558,7 @@ void GCode::do_export(Print* print, const char* path, GCodeProcessorResult* resu ctx.name = std::to_string(print->model().id().id); ctx.code = LifecycleEvtCode::Error; ctx.msg = std::string(path) + "\n" + ex.what(); + ctx.cancellation_check = [print]() { return print->canceled(); }; fire_lifecycle_event(LifecycleEvent::GCodeExportFinished, ctx); } throw; @@ -2668,6 +2671,7 @@ void GCode::do_export(Print* print, const char* path, GCodeProcessorResult* resu ctx.name = std::to_string(print->model().id().id); ctx.code = LifecycleEvtCode::Error; ctx.msg = std::string(path) + "\nFailed to rename the output G-code file: " + ret.message(); + ctx.cancellation_check = [print]() { return print->canceled(); }; fire_lifecycle_event(LifecycleEvent::GCodeExportFinished, ctx); } throw Slic3r::RuntimeError( @@ -2686,6 +2690,7 @@ void GCode::do_export(Print* print, const char* path, GCodeProcessorResult* resu ctx.name = std::to_string(print->model().id().id); ctx.code = LifecycleEvtCode::Ok; ctx.msg = path; + ctx.cancellation_check = [print]() { return print->canceled(); }; fire_lifecycle_event(LifecycleEvent::GCodeExportFinished, ctx); } diff --git a/src/libslic3r/LifecycleEvents.hpp b/src/libslic3r/LifecycleEvents.hpp index 9ceaa99f30..e1abc795c1 100644 --- a/src/libslic3r/LifecycleEvents.hpp +++ b/src/libslic3r/LifecycleEvents.hpp @@ -104,6 +104,11 @@ namespace Slic3r // Aggregate project dirty state for ProjectDirtyChanged. bool dirty = false; + + // Optional host-side cancellation probe. Background slicing and G-code export events set + // this to the originating Print's cancellation state so dispatch can stop before calling + // the next capability. It is intentionally not exposed through the Python payload API. + std::function cancellation_check; }; inline std::string lifecycle_event_to_string(LifecycleEvent event) diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp index 3734318c1a..5df69b7335 100644 --- a/src/libslic3r/Print.cpp +++ b/src/libslic3r/Print.cpp @@ -2699,6 +2699,7 @@ void Print::process(long long *time_cost_with_cache, bool use_cache) LifecycleEventContext ctx; ctx.name = std::to_string(m_model.id().id); ctx.code = LifecycleEvtCode::Ok; + ctx.cancellation_check = [this]() { return canceled(); }; fire_lifecycle_event(LifecycleEvent::SliceStarted, ctx); } @@ -3325,6 +3326,7 @@ void Print::process(long long *time_cost_with_cache, bool use_cache) LifecycleEventContext ctx; ctx.name = std::to_string(m_model.id().id); ctx.code = LifecycleEvtCode::Ok; + ctx.cancellation_check = [this]() { return canceled(); }; fire_lifecycle_event(LifecycleEvent::SliceGeometryFinished, ctx); } } @@ -4931,6 +4933,7 @@ void Print::export_gcode_from_previous_file(const std::string& file, GCodeProces ctx.name = std::to_string(m_model.id().id); ctx.code = LifecycleEvtCode::Ok; ctx.msg = file; + ctx.cancellation_check = [this]() { return canceled(); }; fire_lifecycle_event(LifecycleEvent::GCodeExportStarted, ctx); } @@ -4960,6 +4963,7 @@ void Print::export_gcode_from_previous_file(const std::string& file, GCodeProces ctx.name = std::to_string(m_model.id().id); ctx.code = LifecycleEvtCode::Error; ctx.msg = file + "\n" + ex.what(); + ctx.cancellation_check = [this]() { return canceled(); }; fire_lifecycle_event(LifecycleEvent::GCodeExportFinished, ctx); } throw Slic3r::RuntimeError( @@ -4973,6 +4977,7 @@ void Print::export_gcode_from_previous_file(const std::string& file, GCodeProces ctx.name = std::to_string(m_model.id().id); ctx.code = LifecycleEvtCode::Ok; ctx.msg = file; + ctx.cancellation_check = [this]() { return canceled(); }; fire_lifecycle_event(LifecycleEvent::GCodeExportFinished, ctx); } } diff --git a/src/slic3r/plugin/PluginManager.cpp b/src/slic3r/plugin/PluginManager.cpp index 2b30841172..022f85eb1f 100644 --- a/src/slic3r/plugin/PluginManager.cpp +++ b/src/slic3r/plugin/PluginManager.cpp @@ -2092,8 +2092,17 @@ ExecutionResult PluginManager::run_script_capability(const std::string& plugin_k } void PluginManager::dispatch_lifecycle_event(LifecycleEvent evt, const LifecycleEventContext& ctx) { + const auto is_canceled = [&ctx]() { + return ctx.cancellation_check && ctx.cancellation_check(); + }; + + if (is_canceled()) + return; + for (const auto& cap : get_plugin_capabilities()) { if (!cap || !cap->is_enabled()) continue; + if (is_canceled()) + break; try { cap->on_lifecycle_event(evt, ctx); } catch (const std::exception& ex) {