From 0b629eb905cbd8e95d2edc86ae797880e01b315d Mon Sep 17 00:00:00 2001
From: Enrico Turri <enricoturri@seznam.cz>
Date: Mon, 2 Mar 2020 10:58:46 +0100
Subject: [PATCH 01/25] GLCanvas3DManager moved from being a static member of
 _3DScene to be a normal member of GUI_App

---
 src/PrusaSlicer.cpp                          |   2 +
 src/libslic3r/Technologies.hpp               |   7 +-
 src/slic3r/GUI/3DBed.cpp                     |   3 +
 src/slic3r/GUI/3DScene.cpp                   |   4 +
 src/slic3r/GUI/3DScene.hpp                   |  10 +
 src/slic3r/GUI/GLCanvas3D.cpp                | 268 ++++++++++++++++++-
 src/slic3r/GUI/GLCanvas3D.hpp                |  25 +-
 src/slic3r/GUI/GLCanvas3DManager.cpp         |  84 +++++-
 src/slic3r/GUI/GLCanvas3DManager.hpp         |  77 +++++-
 src/slic3r/GUI/GLSelectionRectangle.cpp      |  11 +
 src/slic3r/GUI/GLTexture.cpp                 |   3 +
 src/slic3r/GUI/GLToolbar.cpp                 |  31 ++-
 src/slic3r/GUI/GUI_App.cpp                   |  21 +-
 src/slic3r/GUI/GUI_App.hpp                   |  12 +
 src/slic3r/GUI/GUI_Preview.cpp               |  69 ++++-
 src/slic3r/GUI/GUI_Preview.hpp               |  23 +-
 src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp      |  16 ++
 src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp |  19 +-
 src/slic3r/GUI/Gizmos/GLGizmosManager.cpp    |  12 +
 src/slic3r/GUI/MainFrame.cpp                 |   2 +
 src/slic3r/GUI/Plater.cpp                    |  37 ++-
 src/slic3r/GUI/Plater.hpp                    |  12 +-
 src/slic3r/GUI/Selection.cpp                 |   6 +
 src/slic3r/GUI/SysInfoDialog.cpp             |   8 +
 24 files changed, 738 insertions(+), 24 deletions(-)

diff --git a/src/PrusaSlicer.cpp b/src/PrusaSlicer.cpp
index 048aea886..6b6c3de09 100644
--- a/src/PrusaSlicer.cpp
+++ b/src/PrusaSlicer.cpp
@@ -527,8 +527,10 @@ int CLI::run(int argc, char **argv)
                 gui->mainframe->load_config(m_extra_config);
         });
         int result = wxEntry(argc, argv);
+#if !ENABLE_NON_STATIC_CANVAS_MANAGER
         //FIXME this is a workaround for the PrusaSlicer 2.1 release.
 		_3DScene::destroy();
+#endif // !ENABLE_NON_STATIC_CANVAS_MANAGER
         return result;
 #else /* SLIC3R_GUI */
         // No GUI support. Just print out a help.
diff --git a/src/libslic3r/Technologies.hpp b/src/libslic3r/Technologies.hpp
index 8ebfc3472..e7f463ce8 100644
--- a/src/libslic3r/Technologies.hpp
+++ b/src/libslic3r/Technologies.hpp
@@ -43,9 +43,12 @@
 
 
 //==================
-// 2.2.0.beta1 techs
+// 2.2.0.final techs
 //==================
-#define ENABLE_2_2_0_BETA1 1
+#define ENABLE_2_2_0_FINAL 1
+
+// Moves GLCanvas3DManager from being a static member of _3DScene to be a normal member of GUI_App
+#define ENABLE_NON_STATIC_CANVAS_MANAGER (1 && ENABLE_2_2_0_FINAL)
 
 
 #endif // _technologies_h_
diff --git a/src/slic3r/GUI/3DBed.cpp b/src/slic3r/GUI/3DBed.cpp
index 23acd18ef..5ac3899c1 100644
--- a/src/slic3r/GUI/3DBed.cpp
+++ b/src/slic3r/GUI/3DBed.cpp
@@ -10,6 +10,9 @@
 #include "PresetBundle.hpp"
 #include "Gizmos/GLGizmoBase.hpp"
 #include "GLCanvas3D.hpp"
+#if ENABLE_NON_STATIC_CANVAS_MANAGER
+#include "GLCanvas3DManager.hpp"
+#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
 
 #include <GL/glew.h>
 
diff --git a/src/slic3r/GUI/3DScene.cpp b/src/slic3r/GUI/3DScene.cpp
index 9f36ab537..177a448a7 100644
--- a/src/slic3r/GUI/3DScene.cpp
+++ b/src/slic3r/GUI/3DScene.cpp
@@ -1822,7 +1822,9 @@ void _3DScene::point3_to_verts(const Vec3crd& point, double width, double height
     thick_point_to_verts(point, width, height, volume);
 }
 
+#if !ENABLE_NON_STATIC_CANVAS_MANAGER
 GUI::GLCanvas3DManager _3DScene::s_canvas_mgr;
+#endif // !ENABLE_NON_STATIC_CANVAS_MANAGER
 
 GLModel::GLModel()
     : m_filename("")
@@ -2105,6 +2107,7 @@ bool GLBed::on_init_from_file(const std::string& filename)
     return true;
 }
 
+#if !ENABLE_NON_STATIC_CANVAS_MANAGER
 std::string _3DScene::get_gl_info(bool format_as_html, bool extensions)
 {
     return Slic3r::GUI::GLCanvas3DManager::get_gl_info().to_string(format_as_html, extensions);
@@ -2139,5 +2142,6 @@ GUI::GLCanvas3D* _3DScene::get_canvas(wxGLCanvas* canvas)
 {
     return s_canvas_mgr.get_canvas(canvas);
 }
+#endif // !ENABLE_NON_STATIC_CANVAS_MANAGER
 
 } // namespace Slic3r
diff --git a/src/slic3r/GUI/3DScene.hpp b/src/slic3r/GUI/3DScene.hpp
index aed907004..a35b4dca9 100644
--- a/src/slic3r/GUI/3DScene.hpp
+++ b/src/slic3r/GUI/3DScene.hpp
@@ -7,7 +7,9 @@
 #include "libslic3r/TriangleMesh.hpp"
 #include "libslic3r/Utils.hpp"
 #include "libslic3r/Model.hpp"
+#if !ENABLE_NON_STATIC_CANVAS_MANAGER
 #include "slic3r/GUI/GLCanvas3DManager.hpp"
+#endif // !ENABLE_NON_STATIC_CANVAS_MANAGER
 
 #include <functional>
 #include <memory>
@@ -645,10 +647,17 @@ protected:
     bool on_init_from_file(const std::string& filename) override;
 };
 
+#if ENABLE_NON_STATIC_CANVAS_MANAGER
+struct _3DScene
+#else
 class _3DScene
+#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
 {
+#if !ENABLE_NON_STATIC_CANVAS_MANAGER
     static GUI::GLCanvas3DManager s_canvas_mgr;
+#endif // !ENABLE_NON_STATIC_CANVAS_MANAGER
 
+#if !ENABLE_NON_STATIC_CANVAS_MANAGER
 public:
     static std::string get_gl_info(bool format_as_html, bool extensions);
 
@@ -660,6 +669,7 @@ public:
     static void destroy();
 
     static GUI::GLCanvas3D* get_canvas(wxGLCanvas* canvas);
+#endif // !ENABLE_NON_STATIC_CANVAS_MANAGER
 
     static void thick_lines_to_verts(const Lines& lines, const std::vector<double>& widths, const std::vector<double>& heights, bool closed, double top_z, GLVolume& volume);
     static void thick_lines_to_verts(const Lines3& lines, const std::vector<double>& widths, const std::vector<double>& heights, bool closed, GLVolume& volume);
diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp
index adc1e2e44..abca4efa5 100644
--- a/src/slic3r/GUI/GLCanvas3D.cpp
+++ b/src/slic3r/GUI/GLCanvas3D.cpp
@@ -22,6 +22,10 @@
 #include "slic3r/GUI/PresetBundle.hpp"
 #include "slic3r/GUI/Tab.hpp"
 #include "slic3r/GUI/GUI_Preview.hpp"
+#if ENABLE_NON_STATIC_CANVAS_MANAGER
+#include "slic3r/GUI/GLCanvas3DManager.hpp"
+#include "slic3r/GUI/Camera.hpp"
+#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
 
 #include "GUI_App.hpp"
 #include "GUI_ObjectList.hpp"
@@ -357,7 +361,11 @@ Rect GLCanvas3D::LayersEditing::get_bar_rect_viewport(const GLCanvas3D& canvas)
     float half_w = 0.5f * (float)cnv_size.get_width();
     float half_h = 0.5f * (float)cnv_size.get_height();
 
+#if ENABLE_NON_STATIC_CANVAS_MANAGER
+    float inv_zoom = (float)wxGetApp().plater()->get_camera().get_inv_zoom();
+#else
     float inv_zoom = (float)canvas.get_camera().get_inv_zoom();
+#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
 
     return Rect((half_w - thickness_bar_width(canvas)) * inv_zoom, half_h * inv_zoom, half_w * inv_zoom, -half_h * inv_zoom);
 }
@@ -849,7 +857,11 @@ void GLCanvas3D::WarningTexture::render(const GLCanvas3D& canvas) const
     if ((m_id > 0) && (m_original_width > 0) && (m_original_height > 0) && (m_width > 0) && (m_height > 0))
     {
         const Size& cnv_size = canvas.get_canvas_size();
+#if ENABLE_NON_STATIC_CANVAS_MANAGER
+        float inv_zoom = (float)wxGetApp().plater()->get_camera().get_inv_zoom();
+#else
         float inv_zoom = (float)canvas.get_camera().get_inv_zoom();
+#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
         float left = (-0.5f * (float)m_original_width) * inv_zoom;
         float top = (-0.5f * (float)cnv_size.get_height() + (float)m_original_height + 2.0f) * inv_zoom;
         float right = left + (float)m_original_width * inv_zoom;
@@ -1216,7 +1228,11 @@ void GLCanvas3D::LegendTexture::render(const GLCanvas3D& canvas) const
     if ((m_id > 0) && (m_original_width > 0) && (m_original_height > 0) && (m_width > 0) && (m_height > 0))
     {
         const Size& cnv_size = canvas.get_canvas_size();
+#if ENABLE_NON_STATIC_CANVAS_MANAGER
+        float inv_zoom = (float)wxGetApp().plater()->get_camera().get_inv_zoom();
+#else
         float inv_zoom = (float)canvas.get_camera().get_inv_zoom();
+#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
         float left = (-0.5f * (float)cnv_size.get_width()) * inv_zoom;
         float top = (0.5f * (float)cnv_size.get_height()) * inv_zoom;
         float right = left + (float)m_original_width * inv_zoom;
@@ -1242,7 +1258,11 @@ void GLCanvas3D::Labels::render(const std::vector<const ModelInstance*>& sorted_
     if (!m_enabled || !is_shown())
         return;
 
+#if ENABLE_NON_STATIC_CANVAS_MANAGER
+    const Camera& camera = wxGetApp().plater()->get_camera();
+#else
     const Camera& camera = m_canvas.get_camera();
+#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
     const Model* model = m_canvas.get_model();
     if (model == nullptr)
         return;
@@ -1403,16 +1423,22 @@ wxDEFINE_EVENT(EVT_GLCANVAS_RELOAD_FROM_DISK, SimpleEvent);
 const double GLCanvas3D::DefaultCameraZoomToBoxMarginFactor = 1.25;
 #endif // ENABLE_THUMBNAIL_GENERATOR
 
+#if ENABLE_NON_STATIC_CANVAS_MANAGER
+GLCanvas3D::GLCanvas3D(wxGLCanvas* canvas)
+#else
 GLCanvas3D::GLCanvas3D(wxGLCanvas* canvas, Bed3D& bed, Camera& camera, GLToolbar& view_toolbar)
+#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
     : m_canvas(canvas)
     , m_context(nullptr)
 #if ENABLE_RETINA_GL
     , m_retina_helper(nullptr)
 #endif
     , m_in_render(false)
+#if !ENABLE_NON_STATIC_CANVAS_MANAGER
     , m_bed(bed)
     , m_camera(camera)
     , m_view_toolbar(view_toolbar)
+#endif // !ENABLE_NON_STATIC_CANVAS_MANAGER
     , m_main_toolbar(GLToolbar::Normal, "Top")
     , m_undoredo_toolbar(GLToolbar::Normal, "Top")
     , m_gizmos(*this)
@@ -1560,6 +1586,18 @@ void GLCanvas3D::reset_volumes()
     if (!m_initialized)
         return;
 
+#if ENABLE_NON_STATIC_CANVAS_MANAGER
+    if (m_volumes.empty())
+        return;
+
+    _set_current();
+
+    m_selection.clear();
+    m_volumes.clear();
+    m_dirty = true;
+
+    _set_warning_texture(WarningTexture::ObjectOutside, false);
+#else
     _set_current();
 
     if (!m_volumes.empty())
@@ -1570,6 +1608,7 @@ void GLCanvas3D::reset_volumes()
     }
 
     _set_warning_texture(WarningTexture::ObjectOutside, false);
+#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
 }
 
 int GLCanvas3D::check_volumes_outside_state() const
@@ -1651,7 +1690,11 @@ void GLCanvas3D::set_model(Model* model)
 void GLCanvas3D::bed_shape_changed()
 {
     refresh_camera_scene_box();
+#if ENABLE_NON_STATIC_CANVAS_MANAGER
+    wxGetApp().plater()->get_camera().requires_zoom_to_bed = true;
+#else
     m_camera.requires_zoom_to_bed = true;
+#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
     m_dirty = true;
 }
 
@@ -1660,6 +1703,13 @@ void GLCanvas3D::set_color_by(const std::string& value)
     m_color_by = value;
 }
 
+#if ENABLE_NON_STATIC_CANVAS_MANAGER
+void GLCanvas3D::refresh_camera_scene_box()
+{
+    wxGetApp().plater()->get_camera().set_scene_box(scene_bounding_box());
+}
+#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
+
 BoundingBoxf3 GLCanvas3D::volumes_bounding_box() const
 {
     BoundingBoxf3 bb;
@@ -1674,7 +1724,11 @@ BoundingBoxf3 GLCanvas3D::volumes_bounding_box() const
 BoundingBoxf3 GLCanvas3D::scene_bounding_box() const
 {
     BoundingBoxf3 bb = volumes_bounding_box();
+#if ENABLE_NON_STATIC_CANVAS_MANAGER
+    bb.merge(wxGetApp().plater()->get_bed().get_bounding_box(true));
+#else
     bb.merge(m_bed.get_bounding_box(true));
+#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
 
     if (m_config != nullptr)
     {
@@ -1787,7 +1841,11 @@ void GLCanvas3D::allow_multisample(bool allow)
 
 void GLCanvas3D::zoom_to_bed()
 {
+#if ENABLE_NON_STATIC_CANVAS_MANAGER
+    _zoom_to_box(wxGetApp().plater()->get_bed().get_bounding_box(false));
+#else
     _zoom_to_box(m_bed.get_bounding_box(false));
+#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
 }
 
 void GLCanvas3D::zoom_to_volumes()
@@ -1805,7 +1863,11 @@ void GLCanvas3D::zoom_to_selection()
 
 void GLCanvas3D::select_view(const std::string& direction)
 {
+#if ENABLE_NON_STATIC_CANVAS_MANAGER
+    wxGetApp().plater()->get_camera().select_view(direction);
+#else
     m_camera.select_view(direction);
+#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
     if (m_canvas != nullptr)
         m_canvas->Refresh();
 }
@@ -1833,14 +1895,26 @@ void GLCanvas3D::render()
         return;
 
     // ensures this canvas is current and initialized
+#if ENABLE_NON_STATIC_CANVAS_MANAGER
+    if (!_is_shown_on_screen() || !_set_current() || !wxGetApp().init_opengl())
+        return;
+
+    if (!is_initialized() && !init())
+        return;
+#else
     if (! _is_shown_on_screen() || !_set_current() || !_3DScene::init(m_canvas))
         return;
+#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
 
 #if ENABLE_RENDER_STATISTICS
     auto start_time = std::chrono::high_resolution_clock::now();
 #endif // ENABLE_RENDER_STATISTICS
 
+#if ENABLE_NON_STATIC_CANVAS_MANAGER
+    if (wxGetApp().plater()->get_bed().get_shape().empty())
+#else
     if (m_bed.get_shape().empty())
+#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
     {
         // this happens at startup when no data is still saved under <>\AppData\Roaming\Slic3rPE
         post_event(SimpleEvent(EVT_GLCANVAS_UPDATE_BED_SHAPE));
@@ -1852,6 +1926,20 @@ void GLCanvas3D::render()
     // to preview, this was called before canvas had its final size. It reported zero width
     // and the viewport was set incorrectly, leading to tripping glAsserts further down
     // the road (in apply_projection). That's why the minimum size is forced to 10.
+#if ENABLE_NON_STATIC_CANVAS_MANAGER
+    Camera& camera = wxGetApp().plater()->get_camera();
+    camera.apply_viewport(0, 0, std::max(10u, (unsigned int)cnv_size.get_width()), std::max(10u, (unsigned int)cnv_size.get_height()));
+
+    if (camera.requires_zoom_to_bed)
+    {
+        zoom_to_bed();
+        _resize((unsigned int)cnv_size.get_width(), (unsigned int)cnv_size.get_height());
+        camera.requires_zoom_to_bed = false;
+    }
+
+    camera.apply_view_matrix();
+    camera.apply_projection(_max_bounding_box(true, true));
+#else
     m_camera.apply_viewport(0, 0, std::max(10u, (unsigned int)cnv_size.get_width()), std::max(10u, (unsigned int)cnv_size.get_height()));
 
     if (m_camera.requires_zoom_to_bed)
@@ -1863,6 +1951,7 @@ void GLCanvas3D::render()
 
     m_camera.apply_view_matrix();
     m_camera.apply_projection(_max_bounding_box(true, true));
+#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
 
     GLfloat position_cam[4] = { 1.0f, 0.0f, 1.0f, 0.0f };
     glsafe(::glLightfv(GL_LIGHT1, GL_POSITION, position_cam));
@@ -1892,7 +1981,11 @@ void GLCanvas3D::render()
     _render_objects();
     _render_sla_slices();
     _render_selection();
+#if ENABLE_NON_STATIC_CANVAS_MANAGER
+    _render_bed(!camera.is_looking_downward(), true);
+#else
     _render_bed(!m_camera.is_looking_downward(), true);
+#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
 
 #if ENABLE_RENDER_SELECTION_CENTER
     _render_selection_center();
@@ -1958,8 +2051,13 @@ void GLCanvas3D::render_thumbnail(ThumbnailData& thumbnail_data, unsigned int w,
 {
     switch (GLCanvas3DManager::get_framebuffers_type())
     {
+#if ENABLE_NON_STATIC_CANVAS_MANAGER
+    case GLCanvas3DManager::EFramebufferType::Arb: { _render_thumbnail_framebuffer(thumbnail_data, w, h, printable_only, parts_only, show_bed, transparent_background); break; }
+    case GLCanvas3DManager::EFramebufferType::Ext: { _render_thumbnail_framebuffer_ext(thumbnail_data, w, h, printable_only, parts_only, show_bed, transparent_background); break; }
+#else
     case GLCanvas3DManager::FB_Arb: { _render_thumbnail_framebuffer(thumbnail_data, w, h, printable_only, parts_only, show_bed, transparent_background); break; }
     case GLCanvas3DManager::FB_Ext: { _render_thumbnail_framebuffer_ext(thumbnail_data, w, h, printable_only, parts_only, show_bed, transparent_background); break; }
+#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
     default: { _render_thumbnail_legacy(thumbnail_data, w, h, printable_only, parts_only, show_bed, transparent_background); break; }
     }
 }
@@ -2065,8 +2163,15 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re
     if ((m_canvas == nullptr) || (m_config == nullptr) || (m_model == nullptr))
         return;
 
+#if ENABLE_NON_STATIC_CANVAS_MANAGER
+    if (!m_initialized)
+        return;
+    
+    _set_current();
+#else
     if (m_initialized)
         _set_current();
+#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
 
     struct ModelVolumeState {
         ModelVolumeState(const GLVolume* volume) :
@@ -2662,8 +2767,13 @@ void GLCanvas3D::on_idle(wxIdleEvent& evt)
 
     m_dirty |= m_main_toolbar.update_items_state();
     m_dirty |= m_undoredo_toolbar.update_items_state();
+#if ENABLE_NON_STATIC_CANVAS_MANAGER
+    m_dirty |= wxGetApp().plater()->get_view_toolbar().update_items_state();
+    bool mouse3d_controller_applied = wxGetApp().plater()->get_mouse3d_controller().apply(wxGetApp().plater()->get_camera());
+#else
     m_dirty |= m_view_toolbar.update_items_state();
     bool mouse3d_controller_applied = wxGetApp().plater()->get_mouse3d_controller().apply(m_camera);
+#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
     m_dirty |= mouse3d_controller_applied;
 
     if (!m_dirty)
@@ -2809,7 +2919,11 @@ void GLCanvas3D::on_char(wxKeyEvent& evt)
         case 'I':
         case 'i': { _update_camera_zoom(1.0); break; }
         case 'K':
+#if ENABLE_NON_STATIC_CANVAS_MANAGER
+        case 'k': { wxGetApp().plater()->get_camera().select_next_type(); m_dirty = true; break; }
+#else
         case 'k': { m_camera.select_next_type(); m_dirty = true; break; }
+#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
         case 'O':
         case 'o': { _update_camera_zoom(-1.0); break; }
 #if ENABLE_RENDER_PICKING_PASS
@@ -2936,7 +3050,11 @@ void GLCanvas3D::on_key(wxKeyEvent& evt)
             Vec3d displacement;
             if (camera_space)
             {
+#if ENABLE_NON_STATIC_CANVAS_MANAGER
+                Eigen::Matrix<double, 3, 3, Eigen::DontAlign> inv_view_3x3 = wxGetApp().plater()->get_camera().get_view_matrix().inverse().matrix().block(0, 0, 3, 3);
+#else
                 Eigen::Matrix<double, 3, 3, Eigen::DontAlign> inv_view_3x3 = m_camera.get_view_matrix().inverse().matrix().block(0, 0, 3, 3);
+#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
                 displacement = multiplier * (inv_view_3x3 * direction);
                 displacement(2) = 0.0;
             }
@@ -3190,6 +3308,11 @@ std::string format_mouse_event_debug_message(const wxMouseEvent &evt)
 
 void GLCanvas3D::on_mouse(wxMouseEvent& evt)
 {
+#if ENABLE_NON_STATIC_CANVAS_MANAGER
+    if (!m_initialized)
+        return;
+#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
+
 #if ENABLE_RETINA_GL
     const float scale = m_retina_helper->get_scale_factor();
     evt.SetX(evt.GetX() * scale);
@@ -3242,7 +3365,11 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
         return;
     }
 
+#if ENABLE_NON_STATIC_CANVAS_MANAGER
+    if (wxGetApp().plater()->get_view_toolbar().on_mouse(evt, *this))
+#else
     if (m_view_toolbar.on_mouse(evt, *this))
+#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
     {
         if (evt.LeftUp() || evt.MiddleUp() || evt.RightUp())
             mouse_up_cleanup();
@@ -3405,7 +3532,12 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
             // we do not want to translate objects if the user just clicked on an object while pressing shift to remove it from the selection and then drag
             if (m_selection.contains_volume(get_first_hover_volume_idx()))
             {
+#if ENABLE_NON_STATIC_CANVAS_MANAGER
+                const Camera& camera = wxGetApp().plater()->get_camera();
+                if (std::abs(camera.get_dir_forward()(2)) < EPSILON)
+#else
                 if (std::abs(m_camera.get_dir_forward()(2)) < EPSILON)
+#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
                 {
                     // side view -> move selected volumes orthogonally to camera view direction
                     Linef3 ray = mouse_ray(pos);
@@ -3418,8 +3550,13 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
                     // vector from the starting position to the found intersection
                     Vec3d inters_vec = inters - m_mouse.drag.start_position_3D;
 
+#if ENABLE_NON_STATIC_CANVAS_MANAGER
+                    Vec3d camera_right = camera.get_dir_right();
+                    Vec3d camera_up = camera.get_dir_up();
+#else
                     Vec3d camera_right = m_camera.get_dir_right();
                     Vec3d camera_up = m_camera.get_dir_up();
+#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
 
                     // finds projection of the vector along the camera axes
                     double projection_x = inters_vec.dot(camera_right);
@@ -3467,10 +3604,17 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
                 const Vec3d& orig = m_mouse.drag.start_position_3D;
                 double x = Geometry::deg2rad(pos(0) - orig(0)) * (double)TRACKBALLSIZE;
                 double y = Geometry::deg2rad(pos(1) - orig(1)) * (double)TRACKBALLSIZE;
+#if ENABLE_NON_STATIC_CANVAS_MANAGER
+                if (wxGetApp().plater()->get_mouse3d_controller().is_running() || (wxGetApp().app_config->get("use_free_camera") == "1"))
+                    wxGetApp().plater()->get_camera().rotate_local_around_target(Vec3d(y, x, 0.0));
+                else
+                    wxGetApp().plater()->get_camera().rotate_on_sphere(x, y, wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() != ptSLA);
+#else
                 if (wxGetApp().plater()->get_mouse3d_controller().is_running() || (wxGetApp().app_config->get("use_free_camera") == "1"))
                     m_camera.rotate_local_around_target(Vec3d(y, x, 0.0));
                 else
                     m_camera.rotate_on_sphere(x, y, wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() != ptSLA);
+#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
 
                 m_dirty = true;
             }
@@ -3485,7 +3629,12 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
                 float z = 0.0f;
                 const Vec3d& cur_pos = _mouse_to_3d(pos, &z);
                 Vec3d orig = _mouse_to_3d(m_mouse.drag.start_position_2D, &z);
+#if ENABLE_NON_STATIC_CANVAS_MANAGER
+                Camera& camera = wxGetApp().plater()->get_camera();
+                camera.set_target(camera.get_target() + orig - cur_pos);
+#else
                 m_camera.set_target(m_camera.get_target() + orig - cur_pos);
+#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
                 m_dirty = true;
             }
             
@@ -3578,7 +3727,11 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
             tooltip = m_undoredo_toolbar.get_tooltip();
 
         if (tooltip.empty())
+#if ENABLE_NON_STATIC_CANVAS_MANAGER
+            tooltip = wxGetApp().plater()->get_view_toolbar().get_tooltip();
+#else
             tooltip = m_view_toolbar.get_tooltip();
+#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
 
         set_tooltip(tooltip);
 
@@ -3932,7 +4085,12 @@ void GLCanvas3D::handle_layers_data_focus_event(const t_layer_height_range range
 
 void GLCanvas3D::update_ui_from_settings()
 {
+#if ENABLE_NON_STATIC_CANVAS_MANAGER
+    Camera& camera = wxGetApp().plater()->get_camera();
+    camera.set_type(wxGetApp().app_config->get("use_perspective_camera"));
+#else
     m_camera.set_type(wxGetApp().app_config->get("use_perspective_camera"));
+#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
     m_dirty = true;
 
 #if ENABLE_RETINA_GL
@@ -3946,7 +4104,11 @@ void GLCanvas3D::update_ui_from_settings()
     if (new_scaling != orig_scaling) {
         BOOST_LOG_TRIVIAL(debug) << "GLCanvas3D: Scaling factor: " << new_scaling;
 
+#if ENABLE_NON_STATIC_CANVAS_MANAGER
+        camera.set_zoom(camera.get_zoom() * new_scaling / orig_scaling);
+#else
         m_camera.set_zoom(m_camera.get_zoom() * new_scaling / orig_scaling);
+#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
         _refresh_if_shown_on_screen();
     }
 #endif
@@ -3981,7 +4143,11 @@ Linef3 GLCanvas3D::mouse_ray(const Point& mouse_pos)
 
 double GLCanvas3D::get_size_proportional_to_max_bed_size(double factor) const
 {
+#if ENABLE_NON_STATIC_CANVAS_MANAGER
+    return factor * wxGetApp().plater()->get_bed().get_bounding_box(false).max_size();
+#else
     return factor * m_bed.get_bounding_box(false).max_size();
+#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
 }
 
 void GLCanvas3D::set_cursor(ECursorType type)
@@ -4042,7 +4208,11 @@ void GLCanvas3D::_render_undo_redo_stack(const bool is_undo, float pos_x) const
 {
     ImGuiWrapper* imgui = wxGetApp().imgui();
 
+#if ENABLE_NON_STATIC_CANVAS_MANAGER
+    const float x = pos_x * (float)wxGetApp().plater()->get_camera().get_zoom() + 0.5f * (float)get_canvas_size().get_width();
+#else
     const float x = pos_x * (float)get_camera().get_zoom() + 0.5f * (float)get_canvas_size().get_width();
+#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
     imgui->set_next_window_pos(x, m_undoredo_toolbar.get_height(), ImGuiCond_Always, 0.5f, 0.0f);
     std::string title = is_undo ? L("Undo History") : L("Redo History");
     imgui->begin(_(title), ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse);
@@ -4138,7 +4308,11 @@ void GLCanvas3D::_render_thumbnail_internal(ThumbnailData& thumbnail_data, bool
         // extends the near and far z of the frustrum to avoid the bed being clipped
 
         // box in eye space
+#if ENABLE_NON_STATIC_CANVAS_MANAGER
+        BoundingBoxf3 t_bed_box = wxGetApp().plater()->get_bed().get_bounding_box(true).transformed(camera.get_view_matrix());
+#else
         BoundingBoxf3 t_bed_box = m_bed.get_bounding_box(true).transformed(camera.get_view_matrix());
+#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
         near_z = -t_bed_box.max(2);
         far_z = -t_bed_box.min(2);
     }
@@ -4415,7 +4589,11 @@ void GLCanvas3D::_render_thumbnail_legacy(ThumbnailData& thumbnail_data, unsigne
 #endif // ENABLE_THUMBNAIL_GENERATOR_DEBUG_OUTPUT
 
     // restore the default framebuffer size to avoid flickering on the 3D scene
+#if ENABLE_NON_STATIC_CANVAS_MANAGER
+    wxGetApp().plater()->get_camera().apply_viewport(0, 0, cnv_size.get_width(), cnv_size.get_height());
+#else
     m_camera.apply_viewport(0, 0, cnv_size.get_width(), cnv_size.get_height());
+#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
 }
 #endif // ENABLE_THUMBNAIL_GENERATOR
 
@@ -4729,14 +4907,22 @@ BoundingBoxf3 GLCanvas3D::_max_bounding_box(bool include_gizmos, bool include_be
         bb.merge(BoundingBoxf3(sel_bb_center - extend_by, sel_bb_center + extend_by));
     }
 
+#if ENABLE_NON_STATIC_CANVAS_MANAGER
+    bb.merge(wxGetApp().plater()->get_bed().get_bounding_box(include_bed_model));
+#else
     bb.merge(m_bed.get_bounding_box(include_bed_model));
+#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
     return bb;
 }
 
 #if ENABLE_THUMBNAIL_GENERATOR
 void GLCanvas3D::_zoom_to_box(const BoundingBoxf3& box, double margin_factor)
 {
+#if ENABLE_NON_STATIC_CANVAS_MANAGER
+    wxGetApp().plater()->get_camera().zoom_to_box(box, margin_factor);
+#else
     m_camera.zoom_to_box(box, margin_factor);
+#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
     m_dirty = true;
 }
 #else
@@ -4750,7 +4936,11 @@ void GLCanvas3D::_zoom_to_box(const BoundingBoxf3& box)
 
 void GLCanvas3D::_update_camera_zoom(double zoom)
 {
+#if ENABLE_NON_STATIC_CANVAS_MANAGER
+    wxGetApp().plater()->get_camera().update_zoom(zoom);
+#else
     m_camera.update_zoom(zoom);
+#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
     m_dirty = true;
 }
 
@@ -4941,7 +5131,11 @@ void GLCanvas3D::_render_bed(float theta, bool show_axes) const
 #if ENABLE_RETINA_GL
     scale_factor = m_retina_helper->get_scale_factor();
 #endif // ENABLE_RETINA_GL
+#if ENABLE_NON_STATIC_CANVAS_MANAGER
+    wxGetApp().plater()->get_bed().render(const_cast<GLCanvas3D&>(*this), theta, scale_factor, show_axes);
+#else
     m_bed.render(const_cast<GLCanvas3D&>(*this), theta, scale_factor, show_axes);
+#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
 }
 
 void GLCanvas3D::_render_objects() const
@@ -4963,7 +5157,11 @@ void GLCanvas3D::_render_objects() const
 
         if (m_config != nullptr)
         {
+#if ENABLE_NON_STATIC_CANVAS_MANAGER
+            const BoundingBoxf3& bed_bb = wxGetApp().plater()->get_bed().get_bounding_box(false);
+#else
             const BoundingBoxf3& bed_bb = m_bed.get_bounding_box(false);
+#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
             m_volumes.set_print_box((float)bed_bb.min(0), (float)bed_bb.min(1), 0.0f, (float)bed_bb.max(0), (float)bed_bb.max(1), (float)m_config->opt_float("max_print_height"));
             m_volumes.check_outside_state(m_config, nullptr);
         }
@@ -4979,19 +5177,37 @@ void GLCanvas3D::_render_objects() const
     m_shader.start_using();
     if (m_picking_enabled && !m_gizmos.is_dragging() && m_layers_editing.is_enabled() && (m_layers_editing.last_object_id != -1) && (m_layers_editing.object_max_z() > 0.0f)) {
         int object_id = m_layers_editing.last_object_id;
+#if ENABLE_NON_STATIC_CANVAS_MANAGER
+        m_volumes.render(GLVolumeCollection::Opaque, false, wxGetApp().plater()->get_camera().get_view_matrix(), [object_id](const GLVolume& volume) {
+            // Which volume to paint without the layer height profile shader?
+            return volume.is_active && (volume.is_modifier || volume.composite_id.object_id != object_id);
+            });
+#else
         m_volumes.render(GLVolumeCollection::Opaque, false, m_camera.get_view_matrix(), [object_id](const GLVolume& volume) {
             // Which volume to paint without the layer height profile shader?
             return volume.is_active && (volume.is_modifier || volume.composite_id.object_id != object_id);
         });
+#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
         // Let LayersEditing handle rendering of the active object using the layer height profile shader.
         m_layers_editing.render_volumes(*this, this->m_volumes);
     } else {
         // do not cull backfaces to show broken geometry, if any
+#if ENABLE_NON_STATIC_CANVAS_MANAGER
+        m_volumes.render(GLVolumeCollection::Opaque, m_picking_enabled, wxGetApp().plater()->get_camera().get_view_matrix(), [this](const GLVolume& volume) {
+            return (m_render_sla_auxiliaries || volume.composite_id.volume_id >= 0);
+            });
+#else
         m_volumes.render(GLVolumeCollection::Opaque, m_picking_enabled, m_camera.get_view_matrix(), [this](const GLVolume& volume) {
             return (m_render_sla_auxiliaries || volume.composite_id.volume_id >= 0);
         });
+#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
     }
+
+#if ENABLE_NON_STATIC_CANVAS_MANAGER
+    m_volumes.render(GLVolumeCollection::Transparent, false, wxGetApp().plater()->get_camera().get_view_matrix());
+#else
     m_volumes.render(GLVolumeCollection::Transparent, false, m_camera.get_view_matrix());
+#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
     m_shader.stop_using();
 
     m_camera_clipping_plane = ClippingPlane::ClipsNothing();
@@ -5024,9 +5240,16 @@ void GLCanvas3D::_render_overlays() const
     glsafe(::glPushMatrix());
     glsafe(::glLoadIdentity());
     // ensure that the textures are renderered inside the frustrum
+#if ENABLE_NON_STATIC_CANVAS_MANAGER
+    const Camera& camera = wxGetApp().plater()->get_camera();
+    glsafe(::glTranslated(0.0, 0.0, -(camera.get_near_z() + 0.005)));
+    // ensure that the overlay fits the frustrum near z plane
+    double gui_scale = camera.get_gui_scale();
+#else
     glsafe(::glTranslated(0.0, 0.0, -(m_camera.get_near_z() + 0.005)));
     // ensure that the overlay fits the frustrum near z plane
     double gui_scale = m_camera.get_gui_scale();
+#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
     glsafe(::glScaled(gui_scale, gui_scale, 1.0));
 
     _render_gizmos_overlay();
@@ -5076,7 +5299,11 @@ void GLCanvas3D::_render_volumes_for_picking() const
     glsafe(::glEnableClientState(GL_VERTEX_ARRAY));
     glsafe(::glEnableClientState(GL_NORMAL_ARRAY));
 
+#if ENABLE_NON_STATIC_CANVAS_MANAGER
+    const Transform3d& view_matrix = wxGetApp().plater()->get_camera().get_view_matrix();
+#else
     const Transform3d& view_matrix = m_camera.get_view_matrix();
+#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
     for (size_t type = 0; type < 2; ++ type) {
 	    GLVolumeWithIdAndZList to_render = volumes_to_render(m_volumes.volumes, (type == 0) ? GLVolumeCollection::Opaque : GLVolumeCollection::Transparent, view_matrix);
 	    for (const GLVolumeWithIdAndZ& volume : to_render)
@@ -5136,7 +5363,11 @@ void GLCanvas3D::_render_main_toolbar() const
 #endif // ENABLE_RETINA_GL
 
     Size cnv_size = get_canvas_size();
+#if ENABLE_NON_STATIC_CANVAS_MANAGER
+    float inv_zoom = (float)wxGetApp().plater()->get_camera().get_inv_zoom();
+#else
     float inv_zoom = (float)m_camera.get_inv_zoom();
+#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
 
     float top = 0.5f * (float)cnv_size.get_height() * inv_zoom;
     float left = -0.5f * (m_main_toolbar.get_width() + m_undoredo_toolbar.get_width()) * inv_zoom;
@@ -5162,7 +5393,11 @@ void GLCanvas3D::_render_undoredo_toolbar() const
 #endif // ENABLE_RETINA_GL
 
     Size cnv_size = get_canvas_size();
+#if ENABLE_NON_STATIC_CANVAS_MANAGER
+    float inv_zoom = (float)wxGetApp().plater()->get_camera().get_inv_zoom();
+#else
     float inv_zoom = (float)m_camera.get_inv_zoom();
+#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
 
     float top = 0.5f * (float)cnv_size.get_height() * inv_zoom;
     float left = (m_main_toolbar.get_width() - 0.5f * (m_main_toolbar.get_width() + m_undoredo_toolbar.get_width())) * inv_zoom;
@@ -5172,25 +5407,50 @@ void GLCanvas3D::_render_undoredo_toolbar() const
 
 void GLCanvas3D::_render_view_toolbar() const
 {
+#if ENABLE_NON_STATIC_CANVAS_MANAGER
+    GLToolbar& view_toolbar = wxGetApp().plater()->get_view_toolbar();
+#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
+
 #if ENABLE_RETINA_GL
 //     m_view_toolbar.set_scale(m_retina_helper->get_scale_factor());
     const float scale = m_retina_helper->get_scale_factor() * wxGetApp().toolbar_icon_scale();
+#if ENABLE_NON_STATIC_CANVAS_MANAGER
+    view_toolbar.set_scale(scale); //! #ys_FIXME_experiment
+#else
     m_view_toolbar.set_scale(scale); //! #ys_FIXME_experiment
+#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
 #else
 //     m_view_toolbar.set_scale(m_canvas->GetContentScaleFactor());
 //     m_view_toolbar.set_scale(wxGetApp().em_unit()*0.1f);
     const float size = int(GLGizmosManager::Default_Icons_Size * wxGetApp().toolbar_icon_scale());
+#if ENABLE_NON_STATIC_CANVAS_MANAGER
+    view_toolbar.set_icons_size(size); //! #ys_FIXME_experiment
+#else
     m_view_toolbar.set_icons_size(size); //! #ys_FIXME_experiment
+#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
 #endif // ENABLE_RETINA_GL
 
     Size cnv_size = get_canvas_size();
+#if ENABLE_NON_STATIC_CANVAS_MANAGER
+    float inv_zoom = (float)wxGetApp().plater()->get_camera().get_inv_zoom();
+#else
     float inv_zoom = (float)m_camera.get_inv_zoom();
+#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
 
     // places the toolbar on the bottom-left corner of the 3d scene
+#if ENABLE_NON_STATIC_CANVAS_MANAGER
+    float top = (-0.5f * (float)cnv_size.get_height() + view_toolbar.get_height()) * inv_zoom;
+#else
     float top = (-0.5f * (float)cnv_size.get_height() + m_view_toolbar.get_height()) * inv_zoom;
+#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
     float left = -0.5f * (float)cnv_size.get_width() * inv_zoom;
+#if ENABLE_NON_STATIC_CANVAS_MANAGER
+    view_toolbar.set_position(top, left);
+    view_toolbar.render(*this);
+#else
     m_view_toolbar.set_position(top, left);
     m_view_toolbar.render(*this);
+#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
 }
 
 #if ENABLE_SHOW_CAMERA_TARGET
@@ -5469,10 +5729,16 @@ Vec3d GLCanvas3D::_mouse_to_3d(const Point& mouse_pos, float* z)
     if (m_canvas == nullptr)
         return Vec3d(DBL_MAX, DBL_MAX, DBL_MAX);
 
-
+#if ENABLE_NON_STATIC_CANVAS_MANAGER
+    const Camera& camera = wxGetApp().plater()->get_camera();
+    const std::array<int, 4>& viewport = camera.get_viewport();
+    const Transform3d& modelview_matrix = camera.get_view_matrix();
+    const Transform3d& projection_matrix = camera.get_projection_matrix();
+#else
     const std::array<int, 4>& viewport = m_camera.get_viewport();
     const Transform3d& modelview_matrix = m_camera.get_view_matrix();
     const Transform3d& projection_matrix = m_camera.get_projection_matrix();
+#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
 
     GLint y = viewport[3] - (GLint)mouse_pos(1);
     GLfloat mouse_z;
diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp
index 9ae127880..0526c874b 100644
--- a/src/slic3r/GUI/GLCanvas3D.hpp
+++ b/src/slic3r/GUI/GLCanvas3D.hpp
@@ -8,7 +8,9 @@
 #include "GLToolbar.hpp"
 #include "Event.hpp"
 #include "3DBed.hpp"
+#if !ENABLE_NON_STATIC_CANVAS_MANAGER
 #include "Camera.hpp"
+#endif // !ENABLE_NON_STATIC_CANVAS_MANAGER
 #include "Selection.hpp"
 #include "Gizmos/GLGizmosManager.hpp"
 #include "GUI_ObjectLayers.hpp"
@@ -26,6 +28,9 @@ class wxMouseEvent;
 class wxTimerEvent;
 class wxPaintEvent;
 class wxGLCanvas;
+#if ENABLE_NON_STATIC_CANVAS_MANAGER
+class wxGLContext;
+#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
 
 // Support for Retina OpenGL on Mac OS
 #define ENABLE_RETINA_GL __APPLE__
@@ -406,9 +411,11 @@ private:
     LegendTexture m_legend_texture;
     WarningTexture m_warning_texture;
     wxTimer m_timer;
+#if !ENABLE_NON_STATIC_CANVAS_MANAGER
     Bed3D& m_bed;
     Camera& m_camera;
     GLToolbar& m_view_toolbar;
+#endif // !ENABLE_NON_STATIC_CANVAS_MANAGER
     LayersEditing m_layers_editing;
     Shader m_shader;
     Mouse m_mouse;
@@ -469,9 +476,17 @@ private:
     Labels m_labels;
 
 public:
+#if ENABLE_NON_STATIC_CANVAS_MANAGER
+    explicit GLCanvas3D(wxGLCanvas* canvas);
+#else
     GLCanvas3D(wxGLCanvas* canvas, Bed3D& bed, Camera& camera, GLToolbar& view_toolbar);
+#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
     ~GLCanvas3D();
 
+#if ENABLE_NON_STATIC_CANVAS_MANAGER
+    bool is_initialized() const { return m_initialized; }
+#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
+
     void set_context(wxGLContext* context) { m_context = context; }
 
     wxGLCanvas* get_wxglcanvas() { return m_canvas; }
@@ -518,9 +533,14 @@ public:
 
     void set_color_by(const std::string& value);
 
+#if ENABLE_NON_STATIC_CANVAS_MANAGER
+    void refresh_camera_scene_box();
+#else
+    void refresh_camera_scene_box() { m_camera.set_scene_box(scene_bounding_box()); }
     const Camera& get_camera() const { return m_camera; }
-    const Shader& get_shader() const { return m_shader; }
     Camera& get_camera() { return m_camera; }
+#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
+    const Shader& get_shader() const { return m_shader; }
 
     BoundingBoxf3 volumes_bounding_box() const;
     BoundingBoxf3 scene_bounding_box() const;
@@ -614,7 +634,9 @@ public:
 
     void update_ui_from_settings();
 
+#if !ENABLE_NON_STATIC_CANVAS_MANAGER
     float get_view_toolbar_height() const { return m_view_toolbar.get_height(); }
+#endif // !ENABLE_NON_STATIC_CANVAS_MANAGER
 
     int get_move_volume_id() const { return m_mouse.drag.move_volume_idx; }
     int get_first_hover_volume_idx() const { return m_hover_volume_idxs.empty() ? -1 : m_hover_volume_idxs.front(); }
@@ -646,7 +668,6 @@ public:
     Linef3 mouse_ray(const Point& mouse_pos);
 
     void set_mouse_as_dragging() { m_mouse.dragging = true; }
-    void refresh_camera_scene_box() { m_camera.set_scene_box(scene_bounding_box()); }
     bool is_mouse_dragging() const { return m_mouse.dragging; }
 
     double get_size_proportional_to_max_bed_size(double factor) const;
diff --git a/src/slic3r/GUI/GLCanvas3DManager.cpp b/src/slic3r/GUI/GLCanvas3DManager.cpp
index a5d75d601..73a82f699 100644
--- a/src/slic3r/GUI/GLCanvas3DManager.cpp
+++ b/src/slic3r/GUI/GLCanvas3DManager.cpp
@@ -1,3 +1,4 @@
+#include "libslic3r/libslic3r.h"
 #include "GLCanvas3DManager.hpp"
 #include "../../slic3r/GUI/GUI.hpp"
 #include "../../slic3r/GUI/AppConfig.hpp"
@@ -23,6 +24,7 @@
 namespace Slic3r {
 namespace GUI {
 
+#if !ENABLE_NON_STATIC_CANVAS_MANAGER
 GLCanvas3DManager::GLInfo::GLInfo()
     : m_detected(false)
     , m_version("")
@@ -33,6 +35,7 @@ GLCanvas3DManager::GLInfo::GLInfo()
     , m_max_anisotropy(0.0f)
 {
 }
+#endif // !ENABLE_NON_STATIC_CANVAS_MANAGER
 
 const std::string& GLCanvas3DManager::GLInfo::get_version() const
 {
@@ -188,22 +191,35 @@ std::string GLCanvas3DManager::GLInfo::to_string(bool format_as_html, bool exten
     return out.str();
 }
 
-GLCanvas3DManager::EMultisampleState GLCanvas3DManager::s_multisample = GLCanvas3DManager::MS_Unknown;
-bool GLCanvas3DManager::s_compressed_textures_supported = false;
-GLCanvas3DManager::EFramebufferType GLCanvas3DManager::s_framebuffers_type = GLCanvas3DManager::FB_None;
 GLCanvas3DManager::GLInfo GLCanvas3DManager::s_gl_info;
+bool GLCanvas3DManager::s_compressed_textures_supported = false;
+#if ENABLE_NON_STATIC_CANVAS_MANAGER
+GLCanvas3DManager::EMultisampleState GLCanvas3DManager::s_multisample = GLCanvas3DManager::EMultisampleState::Unknown;
+GLCanvas3DManager::EFramebufferType GLCanvas3DManager::s_framebuffers_type = GLCanvas3DManager::EFramebufferType::None;
+#else
+GLCanvas3DManager::EMultisampleState GLCanvas3DManager::s_multisample = GLCanvas3DManager::MS_Unknown;
+GLCanvas3DManager::EFramebufferType GLCanvas3DManager::s_framebuffers_type = GLCanvas3DManager::FB_None;
+#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
 
+#if !ENABLE_NON_STATIC_CANVAS_MANAGER
 GLCanvas3DManager::GLCanvas3DManager()
     : m_context(nullptr)
     , m_gl_initialized(false)
 {
 }
+#endif // !ENABLE_NON_STATIC_CANVAS_MANAGER
 
 GLCanvas3DManager::~GLCanvas3DManager()
 {
-	this->destroy();
+#if ENABLE_NON_STATIC_CANVAS_MANAGER
+    if (m_context != nullptr)
+        delete m_context;
+#else
+    this->destroy();
+#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
 }
 
+#if !ENABLE_NON_STATIC_CANVAS_MANAGER
 bool GLCanvas3DManager::add(wxGLCanvas* canvas, Bed3D& bed, Camera& camera, GLToolbar& view_toolbar)
 {
     if (canvas == nullptr)
@@ -255,28 +271,50 @@ void GLCanvas3DManager::remove_all()
     m_canvases.clear();
 }
 
-unsigned int GLCanvas3DManager::count() const
+size_t GLCanvas3DManager::count() const
 {
-    return (unsigned int)m_canvases.size();
+    return m_canvases.size();
 }
+#endif // !ENABLE_NON_STATIC_CANVAS_MANAGER
 
+#if ENABLE_NON_STATIC_CANVAS_MANAGER
+bool GLCanvas3DManager::init_gl()
+#else
 void GLCanvas3DManager::init_gl()
+#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
 {
     if (!m_gl_initialized)
     {
+#if ENABLE_NON_STATIC_CANVAS_MANAGER
+        if (glewInit() != GLEW_OK)
+        {
+            BOOST_LOG_TRIVIAL(error) << "Unable to init glew library";
+            return false;
+        }
+#else
         glewInit();
+#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
         m_gl_initialized = true;
         if (GLEW_EXT_texture_compression_s3tc)
             s_compressed_textures_supported = true;
         else
             s_compressed_textures_supported = false;
 
+#if ENABLE_NON_STATIC_CANVAS_MANAGER
+        if (GLEW_ARB_framebuffer_object)
+            s_framebuffers_type = EFramebufferType::Arb;
+        else if (GLEW_EXT_framebuffer_object)
+            s_framebuffers_type = EFramebufferType::Ext;
+        else
+            s_framebuffers_type = EFramebufferType::None;
+#else
         if (GLEW_ARB_framebuffer_object)
             s_framebuffers_type = FB_Arb;
         else if (GLEW_EXT_framebuffer_object)
             s_framebuffers_type = FB_Ext;
         else
             s_framebuffers_type = FB_None;
+#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
 
         if (! s_gl_info.is_version_greater_or_equal_to(2, 0)) {
         	// Complain about the OpenGL version.
@@ -292,8 +330,21 @@ void GLCanvas3DManager::init_gl()
         	wxMessageBox(message, wxString("PrusaSlicer - ") + _(L("Unsupported OpenGL version")), wxOK | wxICON_ERROR);
         }
     }
+
+#if ENABLE_NON_STATIC_CANVAS_MANAGER
+    return true;
+#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
 }
 
+#if ENABLE_NON_STATIC_CANVAS_MANAGER
+wxGLContext* GLCanvas3DManager::init_glcontext(wxGLCanvas& canvas)
+{
+    if (m_context == nullptr)
+        m_context = new wxGLContext(&canvas);
+
+    return m_context;
+}
+#else
 bool GLCanvas3DManager::init(wxGLCanvas* canvas)
 {
     CanvasesMap::const_iterator it = do_get_canvas(canvas);
@@ -311,14 +362,21 @@ void GLCanvas3DManager::destroy()
         m_context = nullptr;
     }
 }
+#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
 
+#if !ENABLE_NON_STATIC_CANVAS_MANAGER
 GLCanvas3D* GLCanvas3DManager::get_canvas(wxGLCanvas* canvas)
 {
     CanvasesMap::const_iterator it = do_get_canvas(canvas);
     return (it != m_canvases.end()) ? it->second : nullptr;
 }
+#endif // !ENABLE_NON_STATIC_CANVAS_MANAGER
 
+#if ENABLE_NON_STATIC_CANVAS_MANAGER
+wxGLCanvas* GLCanvas3DManager::create_wxglcanvas(wxWindow& parent)
+#else
 wxGLCanvas* GLCanvas3DManager::create_wxglcanvas(wxWindow *parent)
+#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
 {
     int attribList[] = { 
     	WX_GL_RGBA,
@@ -336,7 +394,11 @@ wxGLCanvas* GLCanvas3DManager::create_wxglcanvas(wxWindow *parent)
     	0
     };
 
+#if ENABLE_NON_STATIC_CANVAS_MANAGER
+    if (s_multisample == EMultisampleState::Unknown)
+#else
     if (s_multisample == MS_Unknown)
+#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
     {
         detect_multisample(attribList);
 //        // debug output
@@ -346,9 +408,14 @@ wxGLCanvas* GLCanvas3DManager::create_wxglcanvas(wxWindow *parent)
     if (! can_multisample())
         attribList[12] = 0;
 
+#if ENABLE_NON_STATIC_CANVAS_MANAGER
+    return new wxGLCanvas(&parent, wxID_ANY, attribList, wxDefaultPosition, wxDefaultSize, wxWANTS_CHARS);
+#else
     return new wxGLCanvas(parent, wxID_ANY, attribList, wxDefaultPosition, wxDefaultSize, wxWANTS_CHARS);
+#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
 }
 
+#if !ENABLE_NON_STATIC_CANVAS_MANAGER
 GLCanvas3DManager::CanvasesMap::iterator GLCanvas3DManager::do_get_canvas(wxGLCanvas* canvas)
 {
     return (canvas == nullptr) ? m_canvases.end() : m_canvases.find(canvas);
@@ -366,12 +433,17 @@ bool GLCanvas3DManager::init(GLCanvas3D& canvas)
 
     return canvas.init();
 }
+#endif // !ENABLE_NON_STATIC_CANVAS_MANAGER
 
 void GLCanvas3DManager::detect_multisample(int* attribList)
 {
     int wxVersion = wxMAJOR_VERSION * 10000 + wxMINOR_VERSION * 100 + wxRELEASE_NUMBER;
     bool enable_multisample = wxVersion >= 30003;
+#if ENABLE_NON_STATIC_CANVAS_MANAGER
+    s_multisample = (enable_multisample && wxGLCanvas::IsDisplaySupported(attribList)) ? EMultisampleState::Enabled : EMultisampleState::Disabled;
+#else
     s_multisample = (enable_multisample && wxGLCanvas::IsDisplaySupported(attribList)) ? MS_Enabled : MS_Disabled;
+#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
     // Alternative method: it was working on previous version of wxWidgets but not with the latest, at least on Windows
     // s_multisample = enable_multisample && wxGLCanvas::IsExtensionSupported("WGL_ARB_multisample");
 }
diff --git a/src/slic3r/GUI/GLCanvas3DManager.hpp b/src/slic3r/GUI/GLCanvas3DManager.hpp
index 940e0230a..9b983dbb1 100644
--- a/src/slic3r/GUI/GLCanvas3DManager.hpp
+++ b/src/slic3r/GUI/GLCanvas3DManager.hpp
@@ -23,22 +23,43 @@ class PrintObject;
 namespace GUI {
 
 class GLCanvas3D;
+#if !ENABLE_NON_STATIC_CANVAS_MANAGER
 class Bed3D;
 class GLToolbar;
 struct Camera;
+#endif // !ENABLE_NON_STATIC_CANVAS_MANAGER
 
 class GLCanvas3DManager
 {
 public:
+#if ENABLE_NON_STATIC_CANVAS_MANAGER
+    enum class EFramebufferType : unsigned char
+    {
+        None,
+        Arb,
+        Ext
+    };
+#else
     enum EFramebufferType : unsigned char
     {
         FB_None,
         FB_Arb,
         FB_Ext
     };
+#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
 
     class GLInfo
     {
+#if ENABLE_NON_STATIC_CANVAS_MANAGER
+        mutable bool m_detected{ false };
+        mutable int m_max_tex_size{ 0 };
+        mutable float m_max_anisotropy{ 0.0f };
+
+        mutable std::string m_version;
+        mutable std::string m_glsl_version;
+        mutable std::string m_vendor;
+        mutable std::string m_renderer;
+#else
         mutable bool m_detected;
 
         mutable std::string m_version;
@@ -48,9 +69,14 @@ public:
 
         mutable int m_max_tex_size;
         mutable float m_max_anisotropy;
+#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
 
     public:
+#if ENABLE_NON_STATIC_CANVAS_MANAGER
+        GLInfo() = default;
+#else
         GLInfo();
+#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
 
         const std::string& get_version() const;
         const std::string& get_glsl_version() const;
@@ -69,6 +95,14 @@ public:
     };
 
 private:
+#if ENABLE_NON_STATIC_CANVAS_MANAGER
+    enum class EMultisampleState : unsigned char
+    {
+        Unknown,
+        Enabled,
+        Disabled
+    };
+#else
     enum EMultisampleState : unsigned char
     {
         MS_Unknown,
@@ -77,46 +111,79 @@ private:
     };
 
     typedef std::map<wxGLCanvas*, GLCanvas3D*> CanvasesMap;
+#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
 
-    CanvasesMap m_canvases;
+#if ENABLE_NON_STATIC_CANVAS_MANAGER
+    bool m_gl_initialized{ false };
+    wxGLContext* m_context{ nullptr };
+#else
     wxGLContext* m_context;
-    static GLInfo s_gl_info;
     bool m_gl_initialized;
-    static EMultisampleState s_multisample;
+    CanvasesMap m_canvases;
+#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
+    static GLInfo s_gl_info;
     static bool s_compressed_textures_supported;
+    static EMultisampleState s_multisample;
     static EFramebufferType s_framebuffers_type;
 
 public:
+#if ENABLE_NON_STATIC_CANVAS_MANAGER
+    GLCanvas3DManager() = default;
+#else
     GLCanvas3DManager();
+#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
     ~GLCanvas3DManager();
 
+#if !ENABLE_NON_STATIC_CANVAS_MANAGER
     bool add(wxGLCanvas* canvas, Bed3D& bed, Camera& camera, GLToolbar& view_toolbar);
     bool remove(wxGLCanvas* canvas);
     void remove_all();
 
-    unsigned int count() const;
+    size_t count() const;
+#endif // !ENABLE_NON_STATIC_CANVAS_MANAGER
 
+#if ENABLE_NON_STATIC_CANVAS_MANAGER
+    bool init_gl();
+#else
     void init_gl();
+#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
 
+#if ENABLE_NON_STATIC_CANVAS_MANAGER
+    wxGLContext* init_glcontext(wxGLCanvas& canvas);
+#else
     bool init(wxGLCanvas* canvas);
     void destroy();
+#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
 
+#if !ENABLE_NON_STATIC_CANVAS_MANAGER
     GLCanvas3D* get_canvas(wxGLCanvas* canvas);
+#endif // !ENABLE_NON_STATIC_CANVAS_MANAGER
 
-    static bool can_multisample() { return s_multisample == MS_Enabled; }
     static bool are_compressed_textures_supported() { return s_compressed_textures_supported; }
+#if ENABLE_NON_STATIC_CANVAS_MANAGER
+    static bool can_multisample() { return s_multisample == EMultisampleState::Enabled; }
+    static bool are_framebuffers_supported() { return (s_framebuffers_type != EFramebufferType::None); }
+#else
+    static bool can_multisample() { return s_multisample == MS_Enabled; }
     static bool are_framebuffers_supported() { return (s_framebuffers_type != FB_None); }
+#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
     static EFramebufferType get_framebuffers_type() { return s_framebuffers_type; }
 
+#if ENABLE_NON_STATIC_CANVAS_MANAGER
+    static wxGLCanvas* create_wxglcanvas(wxWindow& parent);
+#else
     static wxGLCanvas* create_wxglcanvas(wxWindow *parent);
+#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
 
     static const GLInfo& get_gl_info() { return s_gl_info; }
 
 private:
+#if !ENABLE_NON_STATIC_CANVAS_MANAGER
     CanvasesMap::iterator do_get_canvas(wxGLCanvas* canvas);
     CanvasesMap::const_iterator do_get_canvas(wxGLCanvas* canvas) const;
 
     bool init(GLCanvas3D& canvas);
+#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
     static void detect_multisample(int* attribList);
 };
 
diff --git a/src/slic3r/GUI/GLSelectionRectangle.cpp b/src/slic3r/GUI/GLSelectionRectangle.cpp
index a8b69d75a..a3103af3a 100644
--- a/src/slic3r/GUI/GLSelectionRectangle.cpp
+++ b/src/slic3r/GUI/GLSelectionRectangle.cpp
@@ -2,6 +2,9 @@
 #include "Camera.hpp"
 #include "3DScene.hpp"
 #include "GLCanvas3D.hpp"
+#if ENABLE_NON_STATIC_CANVAS_MANAGER
+#include "GUI_App.hpp"
+#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
 
 #include <GL/glew.h>
 
@@ -35,7 +38,11 @@ namespace GUI {
 
         m_state = Off;
 
+#if ENABLE_NON_STATIC_CANVAS_MANAGER
+        const Camera& camera = wxGetApp().plater()->get_camera();
+#else
         const Camera& camera = canvas.get_camera();
+#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
         const std::array<int, 4>& viewport = camera.get_viewport();
         const Transform3d& modelview_matrix = camera.get_view_matrix();
         const Transform3d& projection_matrix = camera.get_projection_matrix();
@@ -68,7 +75,11 @@ namespace GUI {
         if (!is_dragging())
             return;
 
+#if ENABLE_NON_STATIC_CANVAS_MANAGER
+        const Camera& camera = wxGetApp().plater()->get_camera();
+#else
         const Camera& camera = canvas.get_camera();
+#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
         float inv_zoom = (float)camera.get_inv_zoom();
 
         Size cnv_size = canvas.get_canvas_size();
diff --git a/src/slic3r/GUI/GLTexture.cpp b/src/slic3r/GUI/GLTexture.cpp
index f178ddc73..545b066bb 100644
--- a/src/slic3r/GUI/GLTexture.cpp
+++ b/src/slic3r/GUI/GLTexture.cpp
@@ -2,6 +2,9 @@
 #include "GLTexture.hpp"
 
 #include "3DScene.hpp"
+#if ENABLE_NON_STATIC_CANVAS_MANAGER
+#include "GLCanvas3DManager.hpp"
+#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
 
 #include <GL/glew.h>
 
diff --git a/src/slic3r/GUI/GLToolbar.cpp b/src/slic3r/GUI/GLToolbar.cpp
index 61dba1c19..1aac1d0b3 100644
--- a/src/slic3r/GUI/GLToolbar.cpp
+++ b/src/slic3r/GUI/GLToolbar.cpp
@@ -3,7 +3,13 @@
 
 #include "GLToolbar.hpp"
 
+#if ENABLE_NON_STATIC_CANVAS_MANAGER
+#include "slic3r/GUI/GLCanvas3D.hpp"
+#include "slic3r/GUI/GUI_App.hpp"
+#include "slic3r/GUI/Camera.hpp"
+#else
 #include "../../slic3r/GUI/GLCanvas3D.hpp"
+#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
 
 #include <GL/glew.h>
 
@@ -16,7 +22,6 @@
 namespace Slic3r {
 namespace GUI {
 
-
 wxDEFINE_EVENT(EVT_GLTOOLBAR_ADD, SimpleEvent);
 wxDEFINE_EVENT(EVT_GLTOOLBAR_DELETE, SimpleEvent);
 wxDEFINE_EVENT(EVT_GLTOOLBAR_DELETE_ALL, SimpleEvent);
@@ -626,7 +631,11 @@ std::string GLToolbar::update_hover_state_horizontal(const Vec2d& mouse_pos, GLC
 {
     // NB: mouse_pos is already scaled appropriately
 
+#if ENABLE_NON_STATIC_CANVAS_MANAGER
+    float inv_zoom = (float)wxGetApp().plater()->get_camera().get_inv_zoom();
+#else
     float inv_zoom = (float)parent.get_camera().get_inv_zoom();
+#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
     float factor = m_layout.scale * inv_zoom;
 
     Size cnv_size = parent.get_canvas_size();
@@ -730,7 +739,11 @@ std::string GLToolbar::update_hover_state_vertical(const Vec2d& mouse_pos, GLCan
 {
     // NB: mouse_pos is already scaled appropriately
 
+#if ENABLE_NON_STATIC_CANVAS_MANAGER
+    float inv_zoom = (float)wxGetApp().plater()->get_camera().get_inv_zoom();
+#else
     float inv_zoom = (float)parent.get_camera().get_inv_zoom();
+#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
     float factor = m_layout.scale * inv_zoom;
 
     Size cnv_size = parent.get_canvas_size();
@@ -846,7 +859,11 @@ int GLToolbar::contains_mouse_horizontal(const Vec2d& mouse_pos, const GLCanvas3
 {
     // NB: mouse_pos is already scaled appropriately
 
+#if ENABLE_NON_STATIC_CANVAS_MANAGER
+    float inv_zoom = (float)wxGetApp().plater()->get_camera().get_inv_zoom();
+#else
     float inv_zoom = (float)parent.get_camera().get_inv_zoom();
+#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
     float factor = m_layout.scale * inv_zoom;
 
     Size cnv_size = parent.get_canvas_size();
@@ -919,7 +936,11 @@ int GLToolbar::contains_mouse_vertical(const Vec2d& mouse_pos, const GLCanvas3D&
 {
     // NB: mouse_pos is already scaled appropriately
 
+#if ENABLE_NON_STATIC_CANVAS_MANAGER
+    float inv_zoom = (float)wxGetApp().plater()->get_camera().get_inv_zoom();
+#else
     float inv_zoom = (float)parent.get_camera().get_inv_zoom();
+#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
     float factor = m_layout.scale * inv_zoom;
 
     Size cnv_size = parent.get_canvas_size();
@@ -1071,7 +1092,11 @@ void GLToolbar::render_horizontal(const GLCanvas3D& parent) const
     int tex_width = m_icons_texture.get_width();
     int tex_height = m_icons_texture.get_height();
 
+#if ENABLE_NON_STATIC_CANVAS_MANAGER
+    float inv_zoom = (float)wxGetApp().plater()->get_camera().get_inv_zoom();
+#else
     float inv_zoom = (float)parent.get_camera().get_inv_zoom();
+#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
     float factor = inv_zoom * m_layout.scale;
 
     float scaled_icons_size = m_layout.icons_size * factor;
@@ -1119,7 +1144,11 @@ void GLToolbar::render_vertical(const GLCanvas3D& parent) const
     int tex_width = m_icons_texture.get_width();
     int tex_height = m_icons_texture.get_height();
 
+#if ENABLE_NON_STATIC_CANVAS_MANAGER
+    float inv_zoom = (float)wxGetApp().plater()->get_camera().get_inv_zoom();
+#else
     float inv_zoom = (float)parent.get_camera().get_inv_zoom();
+#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
     float factor = inv_zoom * m_layout.scale;
 
     float scaled_icons_size = m_layout.icons_size * factor;
diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp
index e1973049f..1d5148194 100644
--- a/src/slic3r/GUI/GUI_App.cpp
+++ b/src/slic3r/GUI/GUI_App.cpp
@@ -169,6 +169,23 @@ GUI_App::~GUI_App()
         delete preset_updater;
 }
 
+#if ENABLE_NON_STATIC_CANVAS_MANAGER
+std::string GUI_App::get_gl_info(bool format_as_html, bool extensions)
+{
+    return GLCanvas3DManager::get_gl_info().to_string(format_as_html, extensions);
+}
+
+wxGLContext* GUI_App::init_glcontext(wxGLCanvas& canvas)
+{
+    return m_canvas_mgr.init_glcontext(canvas);
+}
+
+bool GUI_App::init_opengl()
+{
+    return m_canvas_mgr.init_gl();
+}
+#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
+
 bool GUI_App::OnInit()
 {
     try {
@@ -575,7 +592,9 @@ void GUI_App::import_model(wxWindow *parent, wxArrayString& input_files) const
 bool GUI_App::switch_language()
 {
     if (select_language()) {
+#if !ENABLE_NON_STATIC_CANVAS_MANAGER
         _3DScene::remove_all_canvases();
+#endif // !ENABLE_NON_STATIC_CANVAS_MANAGER
         recreate_GUI();
         return true;
     } else {
@@ -744,7 +763,7 @@ bool GUI_App::load_language(wxString language, bool initial)
     wxTranslations::Get()->SetLanguage(language_dict);
     m_wxLocale->AddCatalog(SLIC3R_APP_KEY);
     m_imgui->set_language(into_u8(language_info->CanonicalName));
-	//FIXME This is a temporary workaround, the correct solution is to switch to "C" locale during file import / export only.
+    //FIXME This is a temporary workaround, the correct solution is to switch to "C" locale during file import / export only.
     wxSetlocale(LC_NUMERIC, "C");
     Preset::update_suffix_modified();
 	return true;
diff --git a/src/slic3r/GUI/GUI_App.hpp b/src/slic3r/GUI/GUI_App.hpp
index 10b09b1da..d7cd0c9b8 100644
--- a/src/slic3r/GUI/GUI_App.hpp
+++ b/src/slic3r/GUI/GUI_App.hpp
@@ -7,6 +7,9 @@
 #include "MainFrame.hpp"
 #include "ImGuiWrapper.hpp"
 #include "ConfigWizard.hpp"
+#if ENABLE_NON_STATIC_CANVAS_MANAGER
+#include "GLCanvas3DManager.hpp"
+#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
 
 #include <wx/app.h>
 #include <wx/colour.h>
@@ -96,6 +99,9 @@ class GUI_App : public wxApp
     // Best translation language, provided by Windows or OSX, owned by wxWidgets.
     const wxLanguageInfo		 *m_language_info_best   = nullptr;
 
+#if ENABLE_NON_STATIC_CANVAS_MANAGER
+    GLCanvas3DManager m_canvas_mgr;
+#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
     std::unique_ptr<ImGuiWrapper> m_imgui;
     std::unique_ptr<PrintHostJobQueue> m_printhost_job_queue;
     ConfigWizard* m_wizard;    // Managed by wxWindow tree
@@ -107,6 +113,12 @@ public:
     GUI_App();
     ~GUI_App() override;
 
+#if ENABLE_NON_STATIC_CANVAS_MANAGER
+    static std::string get_gl_info(bool format_as_html, bool extensions);
+    wxGLContext* init_glcontext(wxGLCanvas& canvas);
+    bool init_opengl();
+#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
+
     static unsigned get_colour_approx_luma(const wxColour &colour);
     static bool     dark_mode();
     void            init_label_colours();
diff --git a/src/slic3r/GUI/GUI_Preview.cpp b/src/slic3r/GUI/GUI_Preview.cpp
index 1ae73a192..4a2550596 100644
--- a/src/slic3r/GUI/GUI_Preview.cpp
+++ b/src/slic3r/GUI/GUI_Preview.cpp
@@ -27,31 +27,64 @@
 namespace Slic3r {
 namespace GUI {
 
+#if ENABLE_NON_STATIC_CANVAS_MANAGER
+View3D::View3D(wxWindow* parent, Model* model, DynamicPrintConfig* config, BackgroundSlicingProcess* process)
+    : m_canvas_widget(nullptr)
+    , m_canvas(nullptr)
+{
+    init(parent, model, config, process);
+}
+#else
 View3D::View3D(wxWindow* parent, Bed3D& bed, Camera& camera, GLToolbar& view_toolbar, Model* model, DynamicPrintConfig* config, BackgroundSlicingProcess* process)
     : m_canvas_widget(nullptr)
     , m_canvas(nullptr)
 {
     init(parent, bed, camera, view_toolbar, model, config, process);
 }
+#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
 
 View3D::~View3D()
 {
+#if ENABLE_NON_STATIC_CANVAS_MANAGER
+    if (m_canvas != nullptr)
+    {
+        m_canvas->unbind_event_handlers();
+        delete m_canvas;
+    }
+#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
+
     if (m_canvas_widget != nullptr)
     {
+#if !ENABLE_NON_STATIC_CANVAS_MANAGER
         _3DScene::remove_canvas(m_canvas_widget);
+#endif // !ENABLE_NON_STATIC_CANVAS_MANAGER
         delete m_canvas_widget;
         m_canvas = nullptr;
     }
 }
 
+#if ENABLE_NON_STATIC_CANVAS_MANAGER
+bool View3D::init(wxWindow* parent, Model* model, DynamicPrintConfig* config, BackgroundSlicingProcess* process)
+#else
 bool View3D::init(wxWindow* parent, Bed3D& bed, Camera& camera, GLToolbar& view_toolbar, Model* model, DynamicPrintConfig* config, BackgroundSlicingProcess* process)
+#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
 {
     if (!Create(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0 /* disable wxTAB_TRAVERSAL */))
         return false;
 
+#if ENABLE_NON_STATIC_CANVAS_MANAGER
+    m_canvas_widget = GLCanvas3DManager::create_wxglcanvas(*this);
+    if (m_canvas_widget == nullptr)
+        return false;
+
+    m_canvas = new GLCanvas3D(m_canvas_widget);
+    m_canvas->set_context(wxGetApp().init_glcontext(*m_canvas_widget));
+    m_canvas->bind_event_handlers();
+#else
     m_canvas_widget = GLCanvas3DManager::create_wxglcanvas(this);
     _3DScene::add_canvas(m_canvas_widget, bed, camera, view_toolbar);
     m_canvas = _3DScene::get_canvas(this->m_canvas_widget);
+#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
 
     m_canvas->allow_multisample(GLCanvas3DManager::can_multisample());
     // XXX: If have OpenGL
@@ -163,9 +196,15 @@ void View3D::render()
         m_canvas->set_as_dirty();
 }
 
+#if ENABLE_NON_STATIC_CANVAS_MANAGER
+Preview::Preview(
+    wxWindow* parent, Model* model, DynamicPrintConfig* config,
+    BackgroundSlicingProcess* process, GCodePreviewData* gcode_preview_data, std::function<void()> schedule_background_process_func)
+#else
 Preview::Preview(
     wxWindow* parent, Bed3D& bed, Camera& camera, GLToolbar& view_toolbar, Model* model, DynamicPrintConfig* config, 
     BackgroundSlicingProcess* process, GCodePreviewData* gcode_preview_data, std::function<void()> schedule_background_process_func)
+#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
     : m_canvas_widget(nullptr)
     , m_canvas(nullptr)
     , m_double_slider_sizer(nullptr)
@@ -190,21 +229,39 @@ Preview::Preview(
     , m_volumes_cleanup_required(false)
 #endif // __linux__
 {
+#if ENABLE_NON_STATIC_CANVAS_MANAGER
+    if (init(parent, model))
+#else
     if (init(parent, bed, camera, view_toolbar, model))
+#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
     {
         show_hide_ui_elements("none");
         load_print();
     }
 }
 
+#if ENABLE_NON_STATIC_CANVAS_MANAGER
+bool Preview::init(wxWindow* parent, Model* model)
+#else
 bool Preview::init(wxWindow* parent, Bed3D& bed, Camera& camera, GLToolbar& view_toolbar, Model* model)
+#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
 {
     if (!Create(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0 /* disable wxTAB_TRAVERSAL */))
         return false;
 
+#if ENABLE_NON_STATIC_CANVAS_MANAGER
+    m_canvas_widget = GLCanvas3DManager::create_wxglcanvas(*this);
+    if (m_canvas_widget == nullptr)
+        return false;
+
+    m_canvas = new GLCanvas3D(m_canvas_widget);
+    m_canvas->set_context(wxGetApp().init_glcontext(*m_canvas_widget));
+    m_canvas->bind_event_handlers();
+#else
     m_canvas_widget = GLCanvas3DManager::create_wxglcanvas(this);
     _3DScene::add_canvas(m_canvas_widget, bed, camera, view_toolbar);
     m_canvas = _3DScene::get_canvas(this->m_canvas_widget);
+#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
     m_canvas->allow_multisample(GLCanvas3DManager::can_multisample());
     m_canvas->set_config(m_config);
     m_canvas->set_model(model);
@@ -313,9 +370,19 @@ Preview::~Preview()
 {
     unbind_event_handlers();
 
+#if ENABLE_NON_STATIC_CANVAS_MANAGER
+    if (m_canvas != nullptr)
+    {
+        m_canvas->unbind_event_handlers();
+        delete m_canvas;
+    }
+#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
+
     if (m_canvas_widget != nullptr)
     {
-		_3DScene::remove_canvas(m_canvas_widget);
+#if !ENABLE_NON_STATIC_CANVAS_MANAGER
+        _3DScene::remove_canvas(m_canvas_widget);
+#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
         delete m_canvas_widget;
         m_canvas = nullptr;
     }
diff --git a/src/slic3r/GUI/GUI_Preview.hpp b/src/slic3r/GUI/GUI_Preview.hpp
index cc8f15325..2fe26ede9 100644
--- a/src/slic3r/GUI/GUI_Preview.hpp
+++ b/src/slic3r/GUI/GUI_Preview.hpp
@@ -34,6 +34,9 @@ class GLCanvas3D;
 class GLToolbar;
 class Bed3D;
 struct Camera;
+#if ENABLE_NON_STATIC_CANVAS_MANAGER
+class Plater;
+#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
 
 class View3D : public wxPanel
 {
@@ -41,7 +44,11 @@ class View3D : public wxPanel
     GLCanvas3D* m_canvas;
 
 public:
+#if ENABLE_NON_STATIC_CANVAS_MANAGER
+    View3D(wxWindow* parent, Model* model, DynamicPrintConfig* config, BackgroundSlicingProcess* process);
+#else
     View3D(wxWindow* parent, Bed3D& bed, Camera& camera, GLToolbar& view_toolbar, Model* model, DynamicPrintConfig* config, BackgroundSlicingProcess* process);
+#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
     virtual ~View3D();
 
     wxGLCanvas* get_wxglcanvas() { return m_canvas_widget; }
@@ -69,7 +76,11 @@ public:
     void render();
 
 private:
+#if ENABLE_NON_STATIC_CANVAS_MANAGER
+    bool init(wxWindow* parent, Model* model, DynamicPrintConfig* config, BackgroundSlicingProcess* process);
+#else
     bool init(wxWindow* parent, Bed3D& bed, Camera& camera, GLToolbar& view_toolbar, Model* model, DynamicPrintConfig* config, BackgroundSlicingProcess* process);
+#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
 };
 
 class Preview : public wxPanel
@@ -109,8 +120,13 @@ class Preview : public wxPanel
     DoubleSlider::Control*       m_slider {nullptr};
 
 public:
-    Preview(wxWindow* parent, Bed3D& bed, Camera& camera, GLToolbar& view_toolbar, Model* model, DynamicPrintConfig* config, 
+#if ENABLE_NON_STATIC_CANVAS_MANAGER
+    Preview(wxWindow* parent, Model* model, DynamicPrintConfig* config,
+        BackgroundSlicingProcess* process, GCodePreviewData* gcode_preview_data, std::function<void()> schedule_background_process = []() {});
+#else
+    Preview(wxWindow* parent, Bed3D& bed, Camera& camera, GLToolbar& view_toolbar, Model* model, DynamicPrintConfig* config,
         BackgroundSlicingProcess* process, GCodePreviewData* gcode_preview_data, std::function<void()> schedule_background_process = [](){});
+#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
     virtual ~Preview();
 
     wxGLCanvas* get_wxglcanvas() { return m_canvas_widget; }
@@ -137,7 +153,11 @@ public:
     bool is_loaded() const { return m_loaded; }
 
 private:
+#if ENABLE_NON_STATIC_CANVAS_MANAGER
+    bool init(wxWindow* parent, Model* model);
+#else
     bool init(wxWindow* parent, Bed3D& bed, Camera& camera, GLToolbar& view_toolbar, Model* model);
+#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
 
     void bind_event_handlers();
     void unbind_event_handlers();
@@ -170,7 +190,6 @@ private:
     void load_print_as_sla();
 
     void on_sliders_scroll_changed(wxCommandEvent& event);
-
 };
 
 } // namespace GUI
diff --git a/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp b/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp
index 43f83d11b..a68219163 100644
--- a/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp
+++ b/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp
@@ -9,6 +9,9 @@
 #include "slic3r/GUI/GUI_ObjectList.hpp"
 #include "slic3r/GUI/MeshUtils.hpp"
 #include "slic3r/GUI/Plater.hpp"
+#if ENABLE_NON_STATIC_CANVAS_MANAGER
+#include "slic3r/GUI/Camera.hpp"
+#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
 #include "slic3r/GUI/PresetBundle.hpp"
 #include "libslic3r/SLAPrint.hpp"
 #include "libslic3r/TriangleMesh.hpp"
@@ -345,7 +348,11 @@ bool GLGizmoHollow::unproject_on_mesh(const Vec2d& mouse_pos, std::pair<Vec3f, V
     // !!! is it really necessary?
     //m_c->update_from_backend(m_parent, m_c->m_model_object);
 
+#if ENABLE_NON_STATIC_CANVAS_MANAGER
+    const Camera& camera = wxGetApp().plater()->get_camera();
+#else
     const Camera& camera = m_parent.get_camera();
+#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
     const Selection& selection = m_parent.get_selection();
     const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin());
     Geometry::Transformation trafo = volume->get_instance_transformation();
@@ -460,7 +467,11 @@ bool GLGizmoHollow::gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_pos
             points_inside.push_back(points[idx].cast<float>());
 
         // Only select/deselect points that are actually visible
+#if ENABLE_NON_STATIC_CANVAS_MANAGER
+        for (size_t idx : m_c->m_mesh_raycaster->get_unobscured_idxs(trafo, wxGetApp().plater()->get_camera(), points_inside, m_c->m_clipping_plane.get()))
+#else
         for (size_t idx :  m_c->m_mesh_raycaster->get_unobscured_idxs(trafo, m_parent.get_camera(), points_inside, m_c->m_clipping_plane.get()))
+#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
         {
             if (rectangle_status == GLSelectionRectangle::Deselect)
                 unselect_point(points_idxs[idx]);
@@ -1137,8 +1148,13 @@ void GLGizmoHollow::update_clipping_plane(bool keep_normal) const
 {
     if (! m_c->m_model_object)
         return;
+#if ENABLE_NON_STATIC_CANVAS_MANAGER
+    Vec3d normal = (keep_normal && m_c->m_clipping_plane->get_normal() != Vec3d::Zero() ?
+        m_c->m_clipping_plane->get_normal() : -wxGetApp().plater()->get_camera().get_dir_forward());
+#else
     Vec3d normal = (keep_normal && m_c->m_clipping_plane->get_normal() != Vec3d::Zero() ?
                         m_c->m_clipping_plane->get_normal() : -m_parent.get_camera().get_dir_forward());
+#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
 
     const Vec3d& center = m_c->m_model_object->instances[m_c->m_active_instance]->get_offset() + Vec3d(0., 0., m_z_shift);
     float dist = normal.dot(center);
diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp
index aa9ce5014..e7764db9c 100644
--- a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp
+++ b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp
@@ -13,6 +13,9 @@
 #include "slic3r/GUI/GUI.hpp"
 #include "slic3r/GUI/GUI_ObjectSettings.hpp"
 #include "slic3r/GUI/GUI_ObjectList.hpp"
+#if ENABLE_NON_STATIC_CANVAS_MANAGER
+#include "slic3r/GUI/Camera.hpp"
+#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
 #include "slic3r/GUI/MeshUtils.hpp"
 #include "slic3r/GUI/Plater.hpp"
 #include "slic3r/GUI/PresetBundle.hpp"
@@ -414,7 +417,11 @@ bool GLGizmoSlaSupports::unproject_on_mesh(const Vec2d& mouse_pos, std::pair<Vec
     if (! m_c->m_mesh_raycaster)
         return false;
 
+#if ENABLE_NON_STATIC_CANVAS_MANAGER
+    const Camera& camera = wxGetApp().plater()->get_camera();
+#else
     const Camera& camera = m_parent.get_camera();
+#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
     const Selection& selection = m_parent.get_selection();
     const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin());
     Geometry::Transformation trafo = volume->get_instance_transformation();
@@ -524,7 +531,11 @@ bool GLGizmoSlaSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mous
                 points_inside.push_back(points[idx].cast<float>());
 
             // Only select/deselect points that are actually visible
+#if ENABLE_NON_STATIC_CANVAS_MANAGER
+            for (size_t idx : m_c->m_mesh_raycaster->get_unobscured_idxs(trafo, wxGetApp().plater()->get_camera(), points_inside, m_c->m_clipping_plane.get()))
+#else
             for (size_t idx :  m_c->m_mesh_raycaster->get_unobscured_idxs(trafo, m_parent.get_camera(), points_inside, m_c->m_clipping_plane.get()))
+#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
             {
                 if (rectangle_status == GLSelectionRectangle::Deselect)
                     unselect_point(points_idxs[idx]);
@@ -1321,8 +1332,14 @@ void GLGizmoSlaSupports::update_clipping_plane(bool keep_normal) const
 {
     if (! m_c->m_model_object)
         return;
+
+#if ENABLE_NON_STATIC_CANVAS_MANAGER
     Vec3d normal = (keep_normal && m_c->m_clipping_plane->get_normal() != Vec3d::Zero() ?
-                        m_c->m_clipping_plane->get_normal() : -m_parent.get_camera().get_dir_forward());
+        m_c->m_clipping_plane->get_normal() : -wxGetApp().plater()->get_camera().get_dir_forward());
+#else
+    Vec3d normal = (keep_normal && m_c->m_clipping_plane->get_normal() != Vec3d::Zero() ?
+        m_c->m_clipping_plane->get_normal() : -m_parent.get_camera().get_dir_forward());
+#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
 
     const Vec3d& center = m_c->m_model_object->instances[m_c->m_active_instance]->get_offset() + Vec3d(0., 0., m_z_shift);
     float dist = normal.dot(center);
diff --git a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp
index 7d747ceff..a9e5e2de6 100644
--- a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp
+++ b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp
@@ -2,6 +2,9 @@
 #include "GLGizmosManager.hpp"
 #include "slic3r/GUI/GLCanvas3D.hpp"
 #include "slic3r/GUI/3DScene.hpp"
+#if ENABLE_NON_STATIC_CANVAS_MANAGER
+#include "slic3r/GUI/Camera.hpp"
+#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
 #include "slic3r/GUI/GUI_App.hpp"
 #include "slic3r/GUI/GUI_ObjectManipulation.hpp"
 #include "slic3r/GUI/PresetBundle.hpp"
@@ -884,8 +887,13 @@ void GLGizmosManager::do_render_overlay() const
 
     float cnv_w = (float)m_parent.get_canvas_size().get_width();
     float cnv_h = (float)m_parent.get_canvas_size().get_height();
+#if ENABLE_NON_STATIC_CANVAS_MANAGER
+    float zoom = (float)wxGetApp().plater()->get_camera().get_zoom();
+    float inv_zoom = (float)wxGetApp().plater()->get_camera().get_inv_zoom();
+#else
     float zoom = (float)m_parent.get_camera().get_zoom();
     float inv_zoom = (float)m_parent.get_camera().get_inv_zoom();
+#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
 
     float height = get_scaled_total_height();
     float width = get_scaled_total_width();
@@ -936,7 +944,11 @@ void GLGizmosManager::do_render_overlay() const
 
         GLTexture::render_sub_texture(icons_texture_id, zoomed_top_x, zoomed_top_x + zoomed_icons_size, zoomed_top_y - zoomed_icons_size, zoomed_top_y, { { u_left, v_bottom }, { u_right, v_bottom }, { u_right, v_top }, { u_left, v_top } });
         if (idx == m_current) {
+#if ENABLE_NON_STATIC_CANVAS_MANAGER
+            float toolbar_top = cnv_h - wxGetApp().plater()->get_view_toolbar().get_height();
+#else
             float toolbar_top = cnv_h - m_parent.get_view_toolbar_height();
+#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
             gizmo->render_input_window(width, 0.5f * cnv_h - zoomed_top_y * zoom, toolbar_top);
         }
         zoomed_top_y -= zoomed_stride_y;
diff --git a/src/slic3r/GUI/MainFrame.cpp b/src/slic3r/GUI/MainFrame.cpp
index 966fb7c8e..550b495ad 100644
--- a/src/slic3r/GUI/MainFrame.cpp
+++ b/src/slic3r/GUI/MainFrame.cpp
@@ -122,7 +122,9 @@ DPIFrame(NULL, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, wxDEFAULT_FRAME_S
         wxGetApp().app_config->save();
 //         if (m_plater)
 //             m_plater->print = undef;
+#if !ENABLE_NON_STATIC_CANVAS_MANAGER
         _3DScene::remove_all_canvases();
+#endif // !ENABLE_NON_STATIC_CANVAS_MANAGER
 //         Slic3r::GUI::deregister_on_request_update_callback();
 
         // set to null tabs and a plater
diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp
index 0f9b21b78..64502bcf9 100644
--- a/src/slic3r/GUI/Plater.cpp
+++ b/src/slic3r/GUI/Plater.cpp
@@ -2031,8 +2031,13 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame)
     sla_print.set_status_callback(statuscb);
     this->q->Bind(EVT_SLICING_UPDATE, &priv::on_slicing_update, this);
 
+#if ENABLE_NON_STATIC_CANVAS_MANAGER
+    view3D = new View3D(q, &model, config, &background_process);
+    preview = new Preview(q, &model, config, &background_process, &gcode_preview_data, [this]() { schedule_background_process(); });
+#else
     view3D = new View3D(q, bed, camera, view_toolbar, &model, config, &background_process);
     preview = new Preview(q, bed, camera, view_toolbar, &model, config, &background_process, &gcode_preview_data, [this](){ schedule_background_process(); });
+#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
 
     panels.push_back(view3D);
     panels.push_back(preview);
@@ -2132,7 +2137,9 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame)
     // Drop target:
     q->SetDropTarget(new PlaterDropTarget(q));   // if my understanding is right, wxWindow takes the owenership
 
+#if !ENABLE_NON_STATIC_CANVAS_MANAGER
     update_ui_from_settings();
+#endif // !ENABLE_NON_STATIC_CANVAS_MANAGER
     q->Layout();
 
     set_current_panel(view3D);
@@ -4530,7 +4537,8 @@ void Sidebar::set_btn_label(const ActionButtonType btn_type, const wxString& lab
 // Plater / Public
 
 Plater::Plater(wxWindow *parent, MainFrame *main_frame)
-    : wxPanel(parent), p(new priv(this, main_frame))
+    : wxPanel(parent)
+    , p(new priv(this, main_frame))
 {
     // Initialization performed in the private c-tor
 }
@@ -5626,6 +5634,33 @@ const Camera& Plater::get_camera() const
     return p->camera;
 }
 
+#if ENABLE_NON_STATIC_CANVAS_MANAGER
+Camera& Plater::get_camera()
+{
+    return p->camera;
+}
+
+const Bed3D& Plater::get_bed() const
+{
+    return p->bed;
+}
+
+Bed3D& Plater::get_bed()
+{
+    return p->bed;
+}
+
+const GLToolbar& Plater::get_view_toolbar() const
+{
+    return p->view_toolbar;
+}
+
+GLToolbar& Plater::get_view_toolbar()
+{
+    return p->view_toolbar;
+}
+#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
+
 const Mouse3DController& Plater::get_mouse3d_controller() const
 {
     return p->mouse3d_controller;
diff --git a/src/slic3r/GUI/Plater.hpp b/src/slic3r/GUI/Plater.hpp
index 2e4f2ca85..1222a5f04 100644
--- a/src/slic3r/GUI/Plater.hpp
+++ b/src/slic3r/GUI/Plater.hpp
@@ -280,12 +280,22 @@ public:
     bool init_view_toolbar();
 
     const Camera& get_camera() const;
+#if ENABLE_NON_STATIC_CANVAS_MANAGER
+    Camera& get_camera();
+
+    const Bed3D& get_bed() const;
+    Bed3D& get_bed();
+
+    const GLToolbar& get_view_toolbar() const;
+    GLToolbar& get_view_toolbar();
+#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
+
     const Mouse3DController& get_mouse3d_controller() const;
     Mouse3DController& get_mouse3d_controller();
 
 	void set_bed_shape() const;
 
-	// ROII wrapper for suppressing the Undo / Redo snapshot to be taken.
+    // ROII wrapper for suppressing the Undo / Redo snapshot to be taken.
 	class SuppressSnapshots
 	{
 	public:
diff --git a/src/slic3r/GUI/Selection.cpp b/src/slic3r/GUI/Selection.cpp
index bb81b56c0..59998a4cc 100644
--- a/src/slic3r/GUI/Selection.cpp
+++ b/src/slic3r/GUI/Selection.cpp
@@ -439,6 +439,12 @@ void Selection::clear()
     update_type();
     this->set_bounding_boxes_dirty();
 
+#if ENABLE_NON_STATIC_CANVAS_MANAGER
+    // this happens while the application is closing
+    if (wxGetApp().obj_manipul() == nullptr)
+        return;
+#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
+
     // resets the cache in the sidebar
     wxGetApp().obj_manipul()->reset_cache();
 
diff --git a/src/slic3r/GUI/SysInfoDialog.cpp b/src/slic3r/GUI/SysInfoDialog.cpp
index a1bae8742..f26fe7033 100644
--- a/src/slic3r/GUI/SysInfoDialog.cpp
+++ b/src/slic3r/GUI/SysInfoDialog.cpp
@@ -145,7 +145,11 @@ SysInfoDialog::SysInfoDialog()
             "</font>"
             "</body>"
             "</html>", bgr_clr_str, text_clr_str, text_clr_str,
+#if ENABLE_NON_STATIC_CANVAS_MANAGER
+            get_mem_info(true) + "<br>" + wxGetApp().get_gl_info(true, true));
+#else
             get_mem_info(true) + "<br>" + _3DScene::get_gl_info(true, true));
+#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
         m_opengl_info_html->SetPage(text);
         main_sizer->Add(m_opengl_info_html, 1, wxEXPAND | wxBOTTOM, 15);
     }
@@ -198,7 +202,11 @@ void SysInfoDialog::on_dpi_changed(const wxRect &suggested_rect)
 void SysInfoDialog::onCopyToClipboard(wxEvent &)
 {
     wxTheClipboard->Open();
+#if ENABLE_NON_STATIC_CANVAS_MANAGER
+    const auto text = get_main_info(false) + "\n" + wxGetApp().get_gl_info(false, true);
+#else
     const auto text = get_main_info(false)+"\n"+_3DScene::get_gl_info(false, true);
+#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
     wxTheClipboard->SetData(new wxTextDataObject(text));
     wxTheClipboard->Close();
 }

From 10d2193645a4cfa70ebccfb482a20ced42e60835 Mon Sep 17 00:00:00 2001
From: Enrico Turri <enricoturri@seznam.cz>
Date: Mon, 2 Mar 2020 11:40:35 +0100
Subject: [PATCH 02/25] Fixed build on MAC

---
 src/slic3r/GUI/GLCanvas3D.cpp        | 4 ++++
 src/slic3r/GUI/GLCanvas3DManager.cpp | 4 +++-
 2 files changed, 7 insertions(+), 1 deletion(-)

diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp
index 173000ab0..02fa09fcb 100644
--- a/src/slic3r/GUI/GLCanvas3D.cpp
+++ b/src/slic3r/GUI/GLCanvas3D.cpp
@@ -1472,7 +1472,11 @@ GLCanvas3D::GLCanvas3D(wxGLCanvas* canvas, Bed3D& bed, Camera& camera, GLToolbar
 #if ENABLE_RETINA_GL
         m_retina_helper.reset(new RetinaHelper(canvas));
         // set default view_toolbar icons size equal to GLGizmosManager::Default_Icons_Size
+#if ENABLE_NON_STATIC_CANVAS_MANAGER
+        wxGetApp().plater()->get_view_toolbar().set_icons_size(GLGizmosManager::Default_Icons_Size);
+#else
         m_view_toolbar.set_icons_size(GLGizmosManager::Default_Icons_Size);
+#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
 #endif
     }
 
diff --git a/src/slic3r/GUI/GLCanvas3DManager.cpp b/src/slic3r/GUI/GLCanvas3DManager.cpp
index 4c9344cd3..1e53db2f1 100644
--- a/src/slic3r/GUI/GLCanvas3DManager.cpp
+++ b/src/slic3r/GUI/GLCanvas3DManager.cpp
@@ -8,7 +8,9 @@
 
 #include <boost/algorithm/string/split.hpp>
 #include <boost/algorithm/string/classification.hpp>
-
+#if ENABLE_NON_STATIC_CANVAS_MANAGER
+#include <boost/log/trivial.hpp>
+#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
 #include <wx/glcanvas.h>
 #include <wx/timer.h>
 #include <wx/msgdlg.h>

From 3f693362043cb66d96ee5d7507efdd1abffe41e2 Mon Sep 17 00:00:00 2001
From: Enrico Turri <enricoturri@seznam.cz>
Date: Mon, 2 Mar 2020 12:13:39 +0100
Subject: [PATCH 03/25] Removed tech ENABLE_HACK_CLOSING_ON_OSX_10_9_5

---
 src/libslic3r/Technologies.hpp       | 16 ++++----
 src/slic3r/GUI/GLCanvas3DManager.cpp | 58 ++++++++++++++++------------
 src/slic3r/GUI/GLCanvas3DManager.hpp | 38 +++++++++---------
 3 files changed, 61 insertions(+), 51 deletions(-)

diff --git a/src/libslic3r/Technologies.hpp b/src/libslic3r/Technologies.hpp
index 51f7275a4..926d51578 100644
--- a/src/libslic3r/Technologies.hpp
+++ b/src/libslic3r/Technologies.hpp
@@ -42,13 +42,15 @@
 #define ENABLE_THUMBNAIL_GENERATOR_DEBUG (0 && ENABLE_THUMBNAIL_GENERATOR)
 
 
-//==================
-// 2.2.0.rc1 techs
-//==================
-#define ENABLE_2_2_0_RC1 1
-
-// Enable hack to remove crash when closing on OSX 10.9.5
-#define ENABLE_HACK_CLOSING_ON_OSX_10_9_5 (1 && ENABLE_2_2_0_RC1)
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+////==================
+//// 2.2.0.rc1 techs
+////==================
+//#define ENABLE_2_2_0_RC1 1
+//
+//// Enable hack to remove crash when closing on OSX 10.9.5
+//#define ENABLE_HACK_CLOSING_ON_OSX_10_9_5 (1 && ENABLE_2_2_0_RC1)
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
 
 
 //==================
diff --git a/src/slic3r/GUI/GLCanvas3DManager.cpp b/src/slic3r/GUI/GLCanvas3DManager.cpp
index 1e53db2f1..a4b45dd66 100644
--- a/src/slic3r/GUI/GLCanvas3DManager.cpp
+++ b/src/slic3r/GUI/GLCanvas3DManager.cpp
@@ -19,10 +19,12 @@
 #include <string>
 #include <iostream>
 
-#if ENABLE_HACK_CLOSING_ON_OSX_10_9_5
-// Part of temporary hack to remove crash when closing on OSX 10.9.5
-#include <wx/platinfo.h>
-#endif // ENABLE_HACK_CLOSING_ON_OSX_10_9_5
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+//#if ENABLE_HACK_CLOSING_ON_OSX_10_9_5
+//// Part of temporary hack to remove crash when closing on OSX 10.9.5
+//#include <wx/platinfo.h>
+//#endif // ENABLE_HACK_CLOSING_ON_OSX_10_9_5
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
 
 #ifdef __APPLE__
 #include "../Utils/MacDarkMode.hpp"
@@ -211,11 +213,13 @@ GLCanvas3DManager::EMultisampleState GLCanvas3DManager::s_multisample = GLCanvas
 GLCanvas3DManager::EFramebufferType GLCanvas3DManager::s_framebuffers_type = GLCanvas3DManager::FB_None;
 #endif // ENABLE_NON_STATIC_CANVAS_MANAGER
 
-#if ENABLE_HACK_CLOSING_ON_OSX_10_9_5
-#ifdef __APPLE__ 
-GLCanvas3DManager::OSInfo GLCanvas3DManager::s_os_info;
-#endif // __APPLE__ 
-#endif // ENABLE_HACK_CLOSING_ON_OSX_10_9_5
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+//#if ENABLE_HACK_CLOSING_ON_OSX_10_9_5
+//#ifdef __APPLE__ 
+//GLCanvas3DManager::OSInfo GLCanvas3DManager::s_os_info;
+//#endif // __APPLE__ 
+//#endif // ENABLE_HACK_CLOSING_ON_OSX_10_9_5
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
 
 #if !ENABLE_NON_STATIC_CANVAS_MANAGER
 GLCanvas3DManager::GLCanvas3DManager()
@@ -256,14 +260,16 @@ bool GLCanvas3DManager::add(wxGLCanvas* canvas, Bed3D& bed, Camera& camera, GLTo
         if (m_context == nullptr)
             return false;
 
-#if ENABLE_HACK_CLOSING_ON_OSX_10_9_5
-#ifdef __APPLE__ 
-        // Part of temporary hack to remove crash when closing on OSX 10.9.5
-        s_os_info.major = wxPlatformInfo::Get().GetOSMajorVersion();
-        s_os_info.minor = wxPlatformInfo::Get().GetOSMinorVersion();
-        s_os_info.micro = wxPlatformInfo::Get().GetOSMicroVersion();
-#endif //__APPLE__
-#endif // ENABLE_HACK_CLOSING_ON_OSX_10_9_5
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+//#if ENABLE_HACK_CLOSING_ON_OSX_10_9_5
+//#ifdef __APPLE__ 
+//        // Part of temporary hack to remove crash when closing on OSX 10.9.5
+//        s_os_info.major = wxPlatformInfo::Get().GetOSMajorVersion();
+//        s_os_info.minor = wxPlatformInfo::Get().GetOSMinorVersion();
+//        s_os_info.micro = wxPlatformInfo::Get().GetOSMicroVersion();
+//#endif //__APPLE__
+//#endif // ENABLE_HACK_CLOSING_ON_OSX_10_9_5
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
     }
 
     canvas3D->set_context(m_context);
@@ -383,14 +389,16 @@ void GLCanvas3DManager::destroy()
 {
     if (m_context != nullptr)
     {
-#if ENABLE_HACK_CLOSING_ON_OSX_10_9_5
-#ifdef __APPLE__ 
-        // this is a temporary ugly hack to solve the crash happening when closing the application on OSX 10.9.5
-        // the crash is inside wxGLContext destructor
-        if (s_os_info.major == 10 && s_os_info.minor == 9 && s_os_info.micro == 5)
-            return;
-#endif //__APPLE__
-#endif // ENABLE_HACK_CLOSING_ON_OSX_10_9_5
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+//#if ENABLE_HACK_CLOSING_ON_OSX_10_9_5
+//#ifdef __APPLE__ 
+//        // this is a temporary ugly hack to solve the crash happening when closing the application on OSX 10.9.5
+//        // the crash is inside wxGLContext destructor
+//        if (s_os_info.major == 10 && s_os_info.minor == 9 && s_os_info.micro == 5)
+//            return;
+//#endif //__APPLE__
+//#endif // ENABLE_HACK_CLOSING_ON_OSX_10_9_5
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
 
         delete m_context;
         m_context = nullptr;
diff --git a/src/slic3r/GUI/GLCanvas3DManager.hpp b/src/slic3r/GUI/GLCanvas3DManager.hpp
index 2efa646d9..ad27f1339 100644
--- a/src/slic3r/GUI/GLCanvas3DManager.hpp
+++ b/src/slic3r/GUI/GLCanvas3DManager.hpp
@@ -94,16 +94,18 @@ public:
         void detect() const;
     };
 
-#if ENABLE_HACK_CLOSING_ON_OSX_10_9_5
-#ifdef __APPLE__ 
-    struct OSInfo
-    {
-        int major{ 0 };
-        int minor{ 0 };
-        int micro{ 0 };
-    };
-#endif //__APPLE__
-#endif // ENABLE_HACK_CLOSING_ON_OSX_10_9_5
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+//#if ENABLE_HACK_CLOSING_ON_OSX_10_9_5
+//#ifdef __APPLE__ 
+//    struct OSInfo
+//    {
+//        int major{ 0 };
+//        int minor{ 0 };
+//        int micro{ 0 };
+//    };
+//#endif //__APPLE__
+//#endif // ENABLE_HACK_CLOSING_ON_OSX_10_9_5
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
 
 private:
 #if ENABLE_NON_STATIC_CANVAS_MANAGER
@@ -129,15 +131,13 @@ private:
     wxGLContext* m_context{ nullptr };
 #else
     wxGLContext* m_context;
-<<<<<<< HEAD
-=======
-    static GLInfo s_gl_info;
-#if ENABLE_HACK_CLOSING_ON_OSX_10_9_5
-#ifdef __APPLE__ 
-    static OSInfo s_os_info;
-#endif //__APPLE__
-#endif // ENABLE_HACK_CLOSING_ON_OSX_10_9_5
->>>>>>> 11bd62a3e6887741701eb908e0fd0cc0b6afb576
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+//#if ENABLE_HACK_CLOSING_ON_OSX_10_9_5
+//#ifdef __APPLE__ 
+//    static OSInfo s_os_info;
+//#endif //__APPLE__
+//#endif // ENABLE_HACK_CLOSING_ON_OSX_10_9_5
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
     bool m_gl_initialized;
     CanvasesMap m_canvases;
 #endif // ENABLE_NON_STATIC_CANVAS_MANAGER

From 595128a90d19d5211e5e89cd426f406073989ae5 Mon Sep 17 00:00:00 2001
From: Enrico Turri <enricoturri@seznam.cz>
Date: Mon, 2 Mar 2020 12:45:04 +0100
Subject: [PATCH 04/25] View toolbar's initialization of icon size moved from
 GLCanvas3D::GLCanvas3D() to Plater::priv::priv() for OSX build

---
 src/slic3r/GUI/GLCanvas3D.cpp |  8 +++-----
 src/slic3r/GUI/Plater.cpp     | 10 ++++++++++
 2 files changed, 13 insertions(+), 5 deletions(-)

diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp
index 02fa09fcb..1cb212f24 100644
--- a/src/slic3r/GUI/GLCanvas3D.cpp
+++ b/src/slic3r/GUI/GLCanvas3D.cpp
@@ -1471,13 +1471,11 @@ GLCanvas3D::GLCanvas3D(wxGLCanvas* canvas, Bed3D& bed, Camera& camera, GLToolbar
         m_timer.SetOwner(m_canvas);
 #if ENABLE_RETINA_GL
         m_retina_helper.reset(new RetinaHelper(canvas));
+#if !ENABLE_NON_STATIC_CANVAS_MANAGER
         // set default view_toolbar icons size equal to GLGizmosManager::Default_Icons_Size
-#if ENABLE_NON_STATIC_CANVAS_MANAGER
-        wxGetApp().plater()->get_view_toolbar().set_icons_size(GLGizmosManager::Default_Icons_Size);
-#else
         m_view_toolbar.set_icons_size(GLGizmosManager::Default_Icons_Size);
-#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
-#endif
+#endif // !ENABLE_NON_STATIC_CANVAS_MANAGER
+#endif // ENABLE_RETINA_GL
     }
 
     m_selection.set_volumes(&m_volumes.volumes);
diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp
index 5d6f72fe5..38ca03656 100644
--- a/src/slic3r/GUI/Plater.cpp
+++ b/src/slic3r/GUI/Plater.cpp
@@ -82,6 +82,11 @@
 #include "../Utils/UndoRedo.hpp"
 #include "../Utils/Thread.hpp"
 #include "RemovableDriveManager.hpp"
+#if ENABLE_NON_STATIC_CANVAS_MANAGER
+#ifdef __APPLE__
+#include "Gizmos/GLGizmosManager.hpp"
+#endif // __APPLE__
+#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
 
 #include <wx/glcanvas.h>    // Needs to be last because reasons :-/
 #include "WipeTowerDialog.hpp"
@@ -2039,6 +2044,11 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame)
 #if ENABLE_NON_STATIC_CANVAS_MANAGER
     view3D = new View3D(q, &model, config, &background_process);
     preview = new Preview(q, &model, config, &background_process, &gcode_preview_data, [this]() { schedule_background_process(); });
+
+#ifdef __APPLE__
+    // set default view_toolbar icons size equal to GLGizmosManager::Default_Icons_Size
+    m_view_toolbar.set_icons_size(GLGizmosManager::Default_Icons_Size);
+#endif // __APPLE__
 #else
     view3D = new View3D(q, bed, camera, view_toolbar, &model, config, &background_process);
     preview = new Preview(q, bed, camera, view_toolbar, &model, config, &background_process, &gcode_preview_data, [this](){ schedule_background_process(); });

From 9e06a5e8d665ffef575285764e81a4493df86f52 Mon Sep 17 00:00:00 2001
From: Enrico Turri <enricoturri@seznam.cz>
Date: Mon, 2 Mar 2020 13:09:12 +0100
Subject: [PATCH 05/25] Fix build on Linux and MAC

---
 src/slic3r/GUI/GLCanvas3DManager.cpp | 4 ++--
 src/slic3r/GUI/GLCanvas3DManager.hpp | 4 ++--
 src/slic3r/GUI/Plater.cpp            | 2 +-
 3 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/src/slic3r/GUI/GLCanvas3DManager.cpp b/src/slic3r/GUI/GLCanvas3DManager.cpp
index a4b45dd66..f27525427 100644
--- a/src/slic3r/GUI/GLCanvas3DManager.cpp
+++ b/src/slic3r/GUI/GLCanvas3DManager.cpp
@@ -207,7 +207,7 @@ GLCanvas3DManager::GLInfo GLCanvas3DManager::s_gl_info;
 bool GLCanvas3DManager::s_compressed_textures_supported = false;
 #if ENABLE_NON_STATIC_CANVAS_MANAGER
 GLCanvas3DManager::EMultisampleState GLCanvas3DManager::s_multisample = GLCanvas3DManager::EMultisampleState::Unknown;
-GLCanvas3DManager::EFramebufferType GLCanvas3DManager::s_framebuffers_type = GLCanvas3DManager::EFramebufferType::None;
+GLCanvas3DManager::EFramebufferType GLCanvas3DManager::s_framebuffers_type = GLCanvas3DManager::EFramebufferType::Unknown;
 #else
 GLCanvas3DManager::EMultisampleState GLCanvas3DManager::s_multisample = GLCanvas3DManager::MS_Unknown;
 GLCanvas3DManager::EFramebufferType GLCanvas3DManager::s_framebuffers_type = GLCanvas3DManager::FB_None;
@@ -337,7 +337,7 @@ void GLCanvas3DManager::init_gl()
         else if (GLEW_EXT_framebuffer_object)
             s_framebuffers_type = EFramebufferType::Ext;
         else
-            s_framebuffers_type = EFramebufferType::None;
+            s_framebuffers_type = EFramebufferType::Unknown;
 #else
         if (GLEW_ARB_framebuffer_object)
             s_framebuffers_type = FB_Arb;
diff --git a/src/slic3r/GUI/GLCanvas3DManager.hpp b/src/slic3r/GUI/GLCanvas3DManager.hpp
index ad27f1339..5f0c76cb7 100644
--- a/src/slic3r/GUI/GLCanvas3DManager.hpp
+++ b/src/slic3r/GUI/GLCanvas3DManager.hpp
@@ -35,7 +35,7 @@ public:
 #if ENABLE_NON_STATIC_CANVAS_MANAGER
     enum class EFramebufferType : unsigned char
     {
-        None,
+        Unknown,
         Arb,
         Ext
     };
@@ -182,7 +182,7 @@ public:
     static bool are_compressed_textures_supported() { return s_compressed_textures_supported; }
 #if ENABLE_NON_STATIC_CANVAS_MANAGER
     static bool can_multisample() { return s_multisample == EMultisampleState::Enabled; }
-    static bool are_framebuffers_supported() { return (s_framebuffers_type != EFramebufferType::None); }
+    static bool are_framebuffers_supported() { return (s_framebuffers_type != EFramebufferType::Unknown); }
 #else
     static bool can_multisample() { return s_multisample == MS_Enabled; }
     static bool are_framebuffers_supported() { return (s_framebuffers_type != FB_None); }
diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp
index 38ca03656..b5a43b7d0 100644
--- a/src/slic3r/GUI/Plater.cpp
+++ b/src/slic3r/GUI/Plater.cpp
@@ -2047,7 +2047,7 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame)
 
 #ifdef __APPLE__
     // set default view_toolbar icons size equal to GLGizmosManager::Default_Icons_Size
-    m_view_toolbar.set_icons_size(GLGizmosManager::Default_Icons_Size);
+    view_toolbar.set_icons_size(GLGizmosManager::Default_Icons_Size);
 #endif // __APPLE__
 #else
     view3D = new View3D(q, bed, camera, view_toolbar, &model, config, &background_process);

From 0a3555f73b04425b485d310b7913d4cddf53d725 Mon Sep 17 00:00:00 2001
From: Enrico Turri <enricoturri@seznam.cz>
Date: Mon, 2 Mar 2020 14:37:01 +0100
Subject: [PATCH 06/25] Reintroduced tech ENABLE_HACK_CLOSING_ON_OSX_10_9_5

---
 src/libslic3r/Technologies.hpp       | 16 +++---
 src/slic3r/GUI/GLCanvas3DManager.cpp | 76 ++++++++++++++++------------
 src/slic3r/GUI/GLCanvas3DManager.hpp | 36 +++++++------
 3 files changed, 67 insertions(+), 61 deletions(-)

diff --git a/src/libslic3r/Technologies.hpp b/src/libslic3r/Technologies.hpp
index 926d51578..90c2525da 100644
--- a/src/libslic3r/Technologies.hpp
+++ b/src/libslic3r/Technologies.hpp
@@ -42,15 +42,13 @@
 #define ENABLE_THUMBNAIL_GENERATOR_DEBUG (0 && ENABLE_THUMBNAIL_GENERATOR)
 
 
-//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
-////==================
-//// 2.2.0.rc1 techs
-////==================
-//#define ENABLE_2_2_0_RC1 1
-//
-//// Enable hack to remove crash when closing on OSX 10.9.5
-//#define ENABLE_HACK_CLOSING_ON_OSX_10_9_5 (1 && ENABLE_2_2_0_RC1)
-//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+//==================
+// 2.2.0.rc1 techs
+//==================
+#define ENABLE_2_2_0_RC1 1
+
+// Enable hack to remove crash when closing the application on OSX 10.9.5 when building against newer wxWidgets
+#define ENABLE_HACK_CLOSING_ON_OSX_10_9_5 (1 && ENABLE_2_2_0_RC1)
 
 
 //==================
diff --git a/src/slic3r/GUI/GLCanvas3DManager.cpp b/src/slic3r/GUI/GLCanvas3DManager.cpp
index f27525427..6430ed8e7 100644
--- a/src/slic3r/GUI/GLCanvas3DManager.cpp
+++ b/src/slic3r/GUI/GLCanvas3DManager.cpp
@@ -19,12 +19,12 @@
 #include <string>
 #include <iostream>
 
-//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
-//#if ENABLE_HACK_CLOSING_ON_OSX_10_9_5
-//// Part of temporary hack to remove crash when closing on OSX 10.9.5
-//#include <wx/platinfo.h>
-//#endif // ENABLE_HACK_CLOSING_ON_OSX_10_9_5
-//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+#if ENABLE_HACK_CLOSING_ON_OSX_10_9_5
+#ifdef __APPLE__
+// Part of hack to remove crash when closing the application on OSX 10.9.5 when building against newer wxWidgets
+#include <wx/platinfo.h>
+#endif // __APPLE__
+#endif // ENABLE_HACK_CLOSING_ON_OSX_10_9_5
 
 #ifdef __APPLE__
 #include "../Utils/MacDarkMode.hpp"
@@ -213,13 +213,12 @@ GLCanvas3DManager::EMultisampleState GLCanvas3DManager::s_multisample = GLCanvas
 GLCanvas3DManager::EFramebufferType GLCanvas3DManager::s_framebuffers_type = GLCanvas3DManager::FB_None;
 #endif // ENABLE_NON_STATIC_CANVAS_MANAGER
 
-//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
-//#if ENABLE_HACK_CLOSING_ON_OSX_10_9_5
-//#ifdef __APPLE__ 
-//GLCanvas3DManager::OSInfo GLCanvas3DManager::s_os_info;
-//#endif // __APPLE__ 
-//#endif // ENABLE_HACK_CLOSING_ON_OSX_10_9_5
-//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+#if ENABLE_HACK_CLOSING_ON_OSX_10_9_5
+#ifdef __APPLE__ 
+// Part of hack to remove crash when closing the application on OSX 10.9.5 when building against newer wxWidgets
+GLCanvas3DManager::OSInfo GLCanvas3DManager::s_os_info;
+#endif // __APPLE__ 
+#endif // ENABLE_HACK_CLOSING_ON_OSX_10_9_5
 
 #if !ENABLE_NON_STATIC_CANVAS_MANAGER
 GLCanvas3DManager::GLCanvas3DManager()
@@ -232,8 +231,23 @@ GLCanvas3DManager::GLCanvas3DManager()
 GLCanvas3DManager::~GLCanvas3DManager()
 {
 #if ENABLE_NON_STATIC_CANVAS_MANAGER
+#if ENABLE_HACK_CLOSING_ON_OSX_10_9_5
+#ifdef __APPLE__ 
+    // This is an ugly hack needed to solve the crash happening when closing the application on OSX 10.9.5 with newer wxWidgets
+    // The crash is triggered inside wxGLContext destructor
+    if (s_os_info.major != 10 || s_os_info.minor != 9 || s_os_info.micro != 5)
+    {
+#endif //__APPLE__
+#endif // ENABLE_HACK_CLOSING_ON_OSX_10_9_5
+
     if (m_context != nullptr)
         delete m_context;
+
+#if ENABLE_HACK_CLOSING_ON_OSX_10_9_5
+#ifdef __APPLE__ 
+    }
+#endif //__APPLE__
+#endif // ENABLE_HACK_CLOSING_ON_OSX_10_9_5
 #else
     this->destroy();
 #endif // ENABLE_NON_STATIC_CANVAS_MANAGER
@@ -260,16 +274,14 @@ bool GLCanvas3DManager::add(wxGLCanvas* canvas, Bed3D& bed, Camera& camera, GLTo
         if (m_context == nullptr)
             return false;
 
-//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
-//#if ENABLE_HACK_CLOSING_ON_OSX_10_9_5
-//#ifdef __APPLE__ 
-//        // Part of temporary hack to remove crash when closing on OSX 10.9.5
-//        s_os_info.major = wxPlatformInfo::Get().GetOSMajorVersion();
-//        s_os_info.minor = wxPlatformInfo::Get().GetOSMinorVersion();
-//        s_os_info.micro = wxPlatformInfo::Get().GetOSMicroVersion();
-//#endif //__APPLE__
-//#endif // ENABLE_HACK_CLOSING_ON_OSX_10_9_5
-//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+#if ENABLE_HACK_CLOSING_ON_OSX_10_9_5
+#ifdef __APPLE__ 
+        // Part of hack to remove crash when closing the application on OSX 10.9.5 when building against newer wxWidgets
+        s_os_info.major = wxPlatformInfo::Get().GetOSMajorVersion();
+        s_os_info.minor = wxPlatformInfo::Get().GetOSMinorVersion();
+        s_os_info.micro = wxPlatformInfo::Get().GetOSMicroVersion();
+#endif //__APPLE__
+#endif // ENABLE_HACK_CLOSING_ON_OSX_10_9_5
     }
 
     canvas3D->set_context(m_context);
@@ -389,16 +401,14 @@ void GLCanvas3DManager::destroy()
 {
     if (m_context != nullptr)
     {
-//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
-//#if ENABLE_HACK_CLOSING_ON_OSX_10_9_5
-//#ifdef __APPLE__ 
-//        // this is a temporary ugly hack to solve the crash happening when closing the application on OSX 10.9.5
-//        // the crash is inside wxGLContext destructor
-//        if (s_os_info.major == 10 && s_os_info.minor == 9 && s_os_info.micro == 5)
-//            return;
-//#endif //__APPLE__
-//#endif // ENABLE_HACK_CLOSING_ON_OSX_10_9_5
-//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+#if ENABLE_HACK_CLOSING_ON_OSX_10_9_5
+#ifdef __APPLE__ 
+        // this is an ugly hack needed to solve the crash happening when closing the application on OSX 10.9.5
+        // the crash is inside wxGLContext destructor
+        if (s_os_info.major == 10 && s_os_info.minor == 9 && s_os_info.micro == 5)
+            return;
+#endif //__APPLE__
+#endif // ENABLE_HACK_CLOSING_ON_OSX_10_9_5
 
         delete m_context;
         m_context = nullptr;
diff --git a/src/slic3r/GUI/GLCanvas3DManager.hpp b/src/slic3r/GUI/GLCanvas3DManager.hpp
index 5f0c76cb7..428ccd96a 100644
--- a/src/slic3r/GUI/GLCanvas3DManager.hpp
+++ b/src/slic3r/GUI/GLCanvas3DManager.hpp
@@ -94,18 +94,17 @@ public:
         void detect() const;
     };
 
-//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
-//#if ENABLE_HACK_CLOSING_ON_OSX_10_9_5
-//#ifdef __APPLE__ 
-//    struct OSInfo
-//    {
-//        int major{ 0 };
-//        int minor{ 0 };
-//        int micro{ 0 };
-//    };
-//#endif //__APPLE__
-//#endif // ENABLE_HACK_CLOSING_ON_OSX_10_9_5
-//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+#if ENABLE_HACK_CLOSING_ON_OSX_10_9_5
+#ifdef __APPLE__ 
+    // Part of hack to remove crash when closing the application on OSX 10.9.5 when building against newer wxWidgets
+    struct OSInfo
+    {
+        int major{ 0 };
+        int minor{ 0 };
+        int micro{ 0 };
+    };
+#endif //__APPLE__
+#endif // ENABLE_HACK_CLOSING_ON_OSX_10_9_5
 
 private:
 #if ENABLE_NON_STATIC_CANVAS_MANAGER
@@ -131,17 +130,16 @@ private:
     wxGLContext* m_context{ nullptr };
 #else
     wxGLContext* m_context;
-//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
-//#if ENABLE_HACK_CLOSING_ON_OSX_10_9_5
-//#ifdef __APPLE__ 
-//    static OSInfo s_os_info;
-//#endif //__APPLE__
-//#endif // ENABLE_HACK_CLOSING_ON_OSX_10_9_5
-//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
     bool m_gl_initialized;
     CanvasesMap m_canvases;
 #endif // ENABLE_NON_STATIC_CANVAS_MANAGER
     static GLInfo s_gl_info;
+#if ENABLE_HACK_CLOSING_ON_OSX_10_9_5
+#ifdef __APPLE__ 
+    // Part of hack to remove crash when closing the application on OSX 10.9.5 when building against newer wxWidgets
+    static OSInfo s_os_info;
+#endif //__APPLE__
+#endif // ENABLE_HACK_CLOSING_ON_OSX_10_9_5
     static bool s_compressed_textures_supported;
     static EMultisampleState s_multisample;
     static EFramebufferType s_framebuffers_type;

From 8b5a08a64a9920f9448f6724e52ac4ee46765028 Mon Sep 17 00:00:00 2001
From: Enrico Turri <enricoturri@seznam.cz>
Date: Mon, 2 Mar 2020 15:22:41 +0100
Subject: [PATCH 07/25] Added temporary debug output

---
 src/slic3r/GUI/GLCanvas3D.cpp        |  4 ++++
 src/slic3r/GUI/GLCanvas3DManager.cpp | 16 ++++++++++++++--
 src/slic3r/GUI/GUI_App.cpp           |  4 ++++
 src/slic3r/GUI/GUI_Preview.cpp       |  8 ++++++++
 src/slic3r/GUI/ImGuiWrapper.cpp      |  4 ++++
 src/slic3r/GUI/MainFrame.hpp         |  8 +++++++-
 src/slic3r/GUI/Plater.cpp            |  7 +++++++
 7 files changed, 48 insertions(+), 3 deletions(-)

diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp
index 1cb212f24..cbcae2f90 100644
--- a/src/slic3r/GUI/GLCanvas3D.cpp
+++ b/src/slic3r/GUI/GLCanvas3D.cpp
@@ -1483,6 +1483,10 @@ GLCanvas3D::GLCanvas3D(wxGLCanvas* canvas, Bed3D& bed, Camera& camera, GLToolbar
 
 GLCanvas3D::~GLCanvas3D()
 {
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+    std::cout << "GLCanvas3D::~GLCanvas3D()\n";
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+
     reset_volumes();
 }
 
diff --git a/src/slic3r/GUI/GLCanvas3DManager.cpp b/src/slic3r/GUI/GLCanvas3DManager.cpp
index 6430ed8e7..39bb482e3 100644
--- a/src/slic3r/GUI/GLCanvas3DManager.cpp
+++ b/src/slic3r/GUI/GLCanvas3DManager.cpp
@@ -230,9 +230,16 @@ GLCanvas3DManager::GLCanvas3DManager()
 
 GLCanvas3DManager::~GLCanvas3DManager()
 {
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+    std::cout << "GLCanvas3DManager::~GLCanvas3DManager()\n";
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+
 #if ENABLE_NON_STATIC_CANVAS_MANAGER
 #if ENABLE_HACK_CLOSING_ON_OSX_10_9_5
 #ifdef __APPLE__ 
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+    std::cout << "OSX version" << s_os_info.major << "." << s_os_info.minor << "." << s_os_info.micro << std::endl;;
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
     // This is an ugly hack needed to solve the crash happening when closing the application on OSX 10.9.5 with newer wxWidgets
     // The crash is triggered inside wxGLContext destructor
     if (s_os_info.major != 10 || s_os_info.minor != 9 || s_os_info.micro != 5)
@@ -240,8 +247,13 @@ GLCanvas3DManager::~GLCanvas3DManager()
 #endif //__APPLE__
 #endif // ENABLE_HACK_CLOSING_ON_OSX_10_9_5
 
-    if (m_context != nullptr)
-        delete m_context;
+        if (m_context != nullptr)
+        {
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+            std::cout << "Destroy wxGLContext\n";
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+            delete m_context;
+        }
 
 #if ENABLE_HACK_CLOSING_ON_OSX_10_9_5
 #ifdef __APPLE__ 
diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp
index 6b92bb21b..dd24d5d85 100644
--- a/src/slic3r/GUI/GUI_App.cpp
+++ b/src/slic3r/GUI/GUI_App.cpp
@@ -159,6 +159,10 @@ GUI_App::GUI_App()
 
 GUI_App::~GUI_App()
 {
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+    std::cout << "GUI_App::~GUI_App()\n";
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+
     if (app_config != nullptr)
         delete app_config;
 
diff --git a/src/slic3r/GUI/GUI_Preview.cpp b/src/slic3r/GUI/GUI_Preview.cpp
index 4a2550596..3d315644d 100644
--- a/src/slic3r/GUI/GUI_Preview.cpp
+++ b/src/slic3r/GUI/GUI_Preview.cpp
@@ -45,6 +45,10 @@ View3D::View3D(wxWindow* parent, Bed3D& bed, Camera& camera, GLToolbar& view_too
 
 View3D::~View3D()
 {
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+    std::cout << "View3D::~View3D()\n";
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+
 #if ENABLE_NON_STATIC_CANVAS_MANAGER
     if (m_canvas != nullptr)
     {
@@ -368,6 +372,10 @@ bool Preview::init(wxWindow* parent, Bed3D& bed, Camera& camera, GLToolbar& view
 
 Preview::~Preview()
 {
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+    std::cout << "Preview::~Preview()\n";
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+
     unbind_event_handlers();
 
 #if ENABLE_NON_STATIC_CANVAS_MANAGER
diff --git a/src/slic3r/GUI/ImGuiWrapper.cpp b/src/slic3r/GUI/ImGuiWrapper.cpp
index 3efa800a9..28c407eee 100644
--- a/src/slic3r/GUI/ImGuiWrapper.cpp
+++ b/src/slic3r/GUI/ImGuiWrapper.cpp
@@ -46,6 +46,10 @@ ImGuiWrapper::ImGuiWrapper()
 
 ImGuiWrapper::~ImGuiWrapper()
 {
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+    std::cout << "ImGuiWrapper::~ImGuiWrapper()\n";
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+
     destroy_font();
     ImGui::DestroyContext();
 }
diff --git a/src/slic3r/GUI/MainFrame.hpp b/src/slic3r/GUI/MainFrame.hpp
index a6d0749ab..b014b929a 100644
--- a/src/slic3r/GUI/MainFrame.hpp
+++ b/src/slic3r/GUI/MainFrame.hpp
@@ -96,7 +96,13 @@ protected:
 
 public:
     MainFrame();
-    ~MainFrame() = default;
+    ~MainFrame()
+    {
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+        std::cout << "MainFrame::~MainFrame()\n";
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+    }
+//    ~MainFrame() = default;
 
     Plater*     plater() { return m_plater; }
 
diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp
index b5a43b7d0..9cc62b163 100644
--- a/src/slic3r/GUI/Plater.cpp
+++ b/src/slic3r/GUI/Plater.cpp
@@ -2173,6 +2173,10 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame)
 
 Plater::priv::~priv()
 {
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+    std::cout << "Plater::priv::~priv()\n";
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+
     mouse3d_controller.shutdown();
 
     if (config != nullptr)
@@ -4560,6 +4564,9 @@ Plater::Plater(wxWindow *parent, MainFrame *main_frame)
 
 Plater::~Plater()
 {
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+    std::cout << "Plater::~Plater()\n";
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
 }
 
 Sidebar&        Plater::sidebar()           { return *p->sidebar; }

From a14fe518be4e4f185c8c714bcca316a4afc9fcb3 Mon Sep 17 00:00:00 2001
From: Enrico Turri <enricoturri@seznam.cz>
Date: Mon, 2 Mar 2020 15:55:36 +0100
Subject: [PATCH 08/25] Fixed detection of OSX version

---
 src/slic3r/GUI/GLCanvas3DManager.cpp | 16 +++++++++++++++-
 1 file changed, 15 insertions(+), 1 deletion(-)

diff --git a/src/slic3r/GUI/GLCanvas3DManager.cpp b/src/slic3r/GUI/GLCanvas3DManager.cpp
index 39bb482e3..54b889a3d 100644
--- a/src/slic3r/GUI/GLCanvas3DManager.cpp
+++ b/src/slic3r/GUI/GLCanvas3DManager.cpp
@@ -238,7 +238,7 @@ GLCanvas3DManager::~GLCanvas3DManager()
 #if ENABLE_HACK_CLOSING_ON_OSX_10_9_5
 #ifdef __APPLE__ 
 //@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
-    std::cout << "OSX version" << s_os_info.major << "." << s_os_info.minor << "." << s_os_info.micro << std::endl;;
+    std::cout << "OSX version: " << s_os_info.major << "." << s_os_info.minor << "." << s_os_info.micro << std::endl;;
 //@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
     // This is an ugly hack needed to solve the crash happening when closing the application on OSX 10.9.5 with newer wxWidgets
     // The crash is triggered inside wxGLContext destructor
@@ -395,8 +395,22 @@ void GLCanvas3DManager::init_gl()
 wxGLContext* GLCanvas3DManager::init_glcontext(wxGLCanvas& canvas)
 {
     if (m_context == nullptr)
+    {
         m_context = new wxGLContext(&canvas);
 
+#if ENABLE_HACK_CLOSING_ON_OSX_10_9_5
+#ifdef __APPLE__ 
+        // Part of hack to remove crash when closing the application on OSX 10.9.5 when building against newer wxWidgets
+        s_os_info.major = wxPlatformInfo::Get().GetOSMajorVersion();
+        s_os_info.minor = wxPlatformInfo::Get().GetOSMinorVersion();
+        s_os_info.micro = wxPlatformInfo::Get().GetOSMicroVersion();
+
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+        std::cout << "GLCanvas3DManager::init_glcontext() -> OSX version: " << s_os_info.major << "." << s_os_info.minor << "." << s_os_info.micro << std::endl;;
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+#endif //__APPLE__
+#endif // ENABLE_HACK_CLOSING_ON_OSX_10_9_5
+    }
     return m_context;
 }
 #else

From d12cc6cb77b7dc597677f4b07c8ecee679f3b7e9 Mon Sep 17 00:00:00 2001
From: Enrico Turri <enricoturri@seznam.cz>
Date: Tue, 3 Mar 2020 08:34:03 +0100
Subject: [PATCH 09/25] Removed temporary debug output

---
 src/slic3r/GUI/GLCanvas3D.cpp        |  4 ----
 src/slic3r/GUI/GLCanvas3DManager.cpp | 16 ----------------
 src/slic3r/GUI/GUI_App.cpp           |  4 ----
 src/slic3r/GUI/GUI_Preview.cpp       |  8 --------
 src/slic3r/GUI/ImGuiWrapper.cpp      |  4 ----
 src/slic3r/GUI/MainFrame.hpp         |  8 +-------
 src/slic3r/GUI/Plater.cpp            |  7 -------
 7 files changed, 1 insertion(+), 50 deletions(-)

diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp
index cbcae2f90..1cb212f24 100644
--- a/src/slic3r/GUI/GLCanvas3D.cpp
+++ b/src/slic3r/GUI/GLCanvas3D.cpp
@@ -1483,10 +1483,6 @@ GLCanvas3D::GLCanvas3D(wxGLCanvas* canvas, Bed3D& bed, Camera& camera, GLToolbar
 
 GLCanvas3D::~GLCanvas3D()
 {
-//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
-    std::cout << "GLCanvas3D::~GLCanvas3D()\n";
-//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
-
     reset_volumes();
 }
 
diff --git a/src/slic3r/GUI/GLCanvas3DManager.cpp b/src/slic3r/GUI/GLCanvas3DManager.cpp
index 54b889a3d..47812db39 100644
--- a/src/slic3r/GUI/GLCanvas3DManager.cpp
+++ b/src/slic3r/GUI/GLCanvas3DManager.cpp
@@ -230,16 +230,9 @@ GLCanvas3DManager::GLCanvas3DManager()
 
 GLCanvas3DManager::~GLCanvas3DManager()
 {
-//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
-    std::cout << "GLCanvas3DManager::~GLCanvas3DManager()\n";
-//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
-
 #if ENABLE_NON_STATIC_CANVAS_MANAGER
 #if ENABLE_HACK_CLOSING_ON_OSX_10_9_5
 #ifdef __APPLE__ 
-//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
-    std::cout << "OSX version: " << s_os_info.major << "." << s_os_info.minor << "." << s_os_info.micro << std::endl;;
-//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
     // This is an ugly hack needed to solve the crash happening when closing the application on OSX 10.9.5 with newer wxWidgets
     // The crash is triggered inside wxGLContext destructor
     if (s_os_info.major != 10 || s_os_info.minor != 9 || s_os_info.micro != 5)
@@ -248,12 +241,7 @@ GLCanvas3DManager::~GLCanvas3DManager()
 #endif // ENABLE_HACK_CLOSING_ON_OSX_10_9_5
 
         if (m_context != nullptr)
-        {
-//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
-            std::cout << "Destroy wxGLContext\n";
-//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
             delete m_context;
-        }
 
 #if ENABLE_HACK_CLOSING_ON_OSX_10_9_5
 #ifdef __APPLE__ 
@@ -404,10 +392,6 @@ wxGLContext* GLCanvas3DManager::init_glcontext(wxGLCanvas& canvas)
         s_os_info.major = wxPlatformInfo::Get().GetOSMajorVersion();
         s_os_info.minor = wxPlatformInfo::Get().GetOSMinorVersion();
         s_os_info.micro = wxPlatformInfo::Get().GetOSMicroVersion();
-
-//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
-        std::cout << "GLCanvas3DManager::init_glcontext() -> OSX version: " << s_os_info.major << "." << s_os_info.minor << "." << s_os_info.micro << std::endl;;
-//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
 #endif //__APPLE__
 #endif // ENABLE_HACK_CLOSING_ON_OSX_10_9_5
     }
diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp
index dd24d5d85..6b92bb21b 100644
--- a/src/slic3r/GUI/GUI_App.cpp
+++ b/src/slic3r/GUI/GUI_App.cpp
@@ -159,10 +159,6 @@ GUI_App::GUI_App()
 
 GUI_App::~GUI_App()
 {
-//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
-    std::cout << "GUI_App::~GUI_App()\n";
-//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
-
     if (app_config != nullptr)
         delete app_config;
 
diff --git a/src/slic3r/GUI/GUI_Preview.cpp b/src/slic3r/GUI/GUI_Preview.cpp
index 3d315644d..4a2550596 100644
--- a/src/slic3r/GUI/GUI_Preview.cpp
+++ b/src/slic3r/GUI/GUI_Preview.cpp
@@ -45,10 +45,6 @@ View3D::View3D(wxWindow* parent, Bed3D& bed, Camera& camera, GLToolbar& view_too
 
 View3D::~View3D()
 {
-//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
-    std::cout << "View3D::~View3D()\n";
-//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
-
 #if ENABLE_NON_STATIC_CANVAS_MANAGER
     if (m_canvas != nullptr)
     {
@@ -372,10 +368,6 @@ bool Preview::init(wxWindow* parent, Bed3D& bed, Camera& camera, GLToolbar& view
 
 Preview::~Preview()
 {
-//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
-    std::cout << "Preview::~Preview()\n";
-//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
-
     unbind_event_handlers();
 
 #if ENABLE_NON_STATIC_CANVAS_MANAGER
diff --git a/src/slic3r/GUI/ImGuiWrapper.cpp b/src/slic3r/GUI/ImGuiWrapper.cpp
index 28c407eee..3efa800a9 100644
--- a/src/slic3r/GUI/ImGuiWrapper.cpp
+++ b/src/slic3r/GUI/ImGuiWrapper.cpp
@@ -46,10 +46,6 @@ ImGuiWrapper::ImGuiWrapper()
 
 ImGuiWrapper::~ImGuiWrapper()
 {
-//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
-    std::cout << "ImGuiWrapper::~ImGuiWrapper()\n";
-//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
-
     destroy_font();
     ImGui::DestroyContext();
 }
diff --git a/src/slic3r/GUI/MainFrame.hpp b/src/slic3r/GUI/MainFrame.hpp
index b014b929a..a6d0749ab 100644
--- a/src/slic3r/GUI/MainFrame.hpp
+++ b/src/slic3r/GUI/MainFrame.hpp
@@ -96,13 +96,7 @@ protected:
 
 public:
     MainFrame();
-    ~MainFrame()
-    {
-//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
-        std::cout << "MainFrame::~MainFrame()\n";
-//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
-    }
-//    ~MainFrame() = default;
+    ~MainFrame() = default;
 
     Plater*     plater() { return m_plater; }
 
diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp
index 9cc62b163..b5a43b7d0 100644
--- a/src/slic3r/GUI/Plater.cpp
+++ b/src/slic3r/GUI/Plater.cpp
@@ -2173,10 +2173,6 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame)
 
 Plater::priv::~priv()
 {
-//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
-    std::cout << "Plater::priv::~priv()\n";
-//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
-
     mouse3d_controller.shutdown();
 
     if (config != nullptr)
@@ -4564,9 +4560,6 @@ Plater::Plater(wxWindow *parent, MainFrame *main_frame)
 
 Plater::~Plater()
 {
-//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
-    std::cout << "Plater::~Plater()\n";
-//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
 }
 
 Sidebar&        Plater::sidebar()           { return *p->sidebar; }

From 1bff1f746075fff053abe5d9dfabaf1f24a09b55 Mon Sep 17 00:00:00 2001
From: Enrico Turri <enricoturri@seznam.cz>
Date: Wed, 4 Mar 2020 14:19:15 +0100
Subject: [PATCH 10/25] Added temporary debug output to investigate crash on
 MAC when closing using Command+Q

---
 src/slic3r/GUI/GLCanvas3D.cpp        | 11 +++++++++++
 src/slic3r/GUI/GLCanvas3DManager.cpp |  3 +++
 src/slic3r/GUI/GUI_App.cpp           |  3 +++
 src/slic3r/GUI/GUI_Preview.cpp       |  6 ++++++
 src/slic3r/GUI/ImGuiWrapper.cpp      |  3 +++
 src/slic3r/GUI/MainFrame.cpp         |  8 ++++++++
 src/slic3r/GUI/MainFrame.hpp         |  8 +++++++-
 src/slic3r/GUI/Plater.cpp            |  6 ++++++
 8 files changed, 47 insertions(+), 1 deletion(-)

diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp
index 1cb212f24..f97bd46e6 100644
--- a/src/slic3r/GUI/GLCanvas3D.cpp
+++ b/src/slic3r/GUI/GLCanvas3D.cpp
@@ -1483,6 +1483,9 @@ GLCanvas3D::GLCanvas3D(wxGLCanvas* canvas, Bed3D& bed, Camera& camera, GLToolbar
 
 GLCanvas3D::~GLCanvas3D()
 {
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+    std::cout << "GLCanvas3D::~GLCanvas3D()\n";
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
     reset_volumes();
 }
 
@@ -2732,6 +2735,10 @@ void GLCanvas3D::bind_event_handlers()
 
 void GLCanvas3D::unbind_event_handlers()
 {
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+    std::cout << "GLCanvas3D::unbind_event_handlers()\n";
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+
     if (m_canvas != nullptr)
     {
         m_canvas->Unbind(wxEVT_SIZE, &GLCanvas3D::on_size, this);
@@ -3315,6 +3322,10 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
         return;
 #endif // ENABLE_NON_STATIC_CANVAS_MANAGER
 
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+    std::cout << "GLCanvas3D::on_mouse()\n";
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+
 #if ENABLE_RETINA_GL
     const float scale = m_retina_helper->get_scale_factor();
     evt.SetX(evt.GetX() * scale);
diff --git a/src/slic3r/GUI/GLCanvas3DManager.cpp b/src/slic3r/GUI/GLCanvas3DManager.cpp
index d4522bb07..631a27e31 100644
--- a/src/slic3r/GUI/GLCanvas3DManager.cpp
+++ b/src/slic3r/GUI/GLCanvas3DManager.cpp
@@ -230,6 +230,9 @@ GLCanvas3DManager::GLCanvas3DManager()
 
 GLCanvas3DManager::~GLCanvas3DManager()
 {
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+    std::cout << "GLCanvas3DManager::~GLCanvas3DManager()\n";
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
 #if ENABLE_NON_STATIC_CANVAS_MANAGER
 #if ENABLE_HACK_CLOSING_ON_OSX_10_9_5
 #ifdef __APPLE__ 
diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp
index 24d9123ba..362ad21a1 100644
--- a/src/slic3r/GUI/GUI_App.cpp
+++ b/src/slic3r/GUI/GUI_App.cpp
@@ -159,6 +159,9 @@ GUI_App::GUI_App()
 
 GUI_App::~GUI_App()
 {
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+    std::cout << "GUI_App::~GUI_App()\n";
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
     if (app_config != nullptr)
         delete app_config;
 
diff --git a/src/slic3r/GUI/GUI_Preview.cpp b/src/slic3r/GUI/GUI_Preview.cpp
index 4a2550596..f4d8adc70 100644
--- a/src/slic3r/GUI/GUI_Preview.cpp
+++ b/src/slic3r/GUI/GUI_Preview.cpp
@@ -45,6 +45,9 @@ View3D::View3D(wxWindow* parent, Bed3D& bed, Camera& camera, GLToolbar& view_too
 
 View3D::~View3D()
 {
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+    std::cout << "View3D::~View3D()\n";
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
 #if ENABLE_NON_STATIC_CANVAS_MANAGER
     if (m_canvas != nullptr)
     {
@@ -368,6 +371,9 @@ bool Preview::init(wxWindow* parent, Bed3D& bed, Camera& camera, GLToolbar& view
 
 Preview::~Preview()
 {
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+    std::cout << "Preview::~Preview()\n";
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
     unbind_event_handlers();
 
 #if ENABLE_NON_STATIC_CANVAS_MANAGER
diff --git a/src/slic3r/GUI/ImGuiWrapper.cpp b/src/slic3r/GUI/ImGuiWrapper.cpp
index 3efa800a9..1abc191c3 100644
--- a/src/slic3r/GUI/ImGuiWrapper.cpp
+++ b/src/slic3r/GUI/ImGuiWrapper.cpp
@@ -46,6 +46,9 @@ ImGuiWrapper::ImGuiWrapper()
 
 ImGuiWrapper::~ImGuiWrapper()
 {
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+    std::cout << "ImGuiWrapper::~ImGuiWrapper()\n";
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
     destroy_font();
     ImGui::DestroyContext();
 }
diff --git a/src/slic3r/GUI/MainFrame.cpp b/src/slic3r/GUI/MainFrame.cpp
index 1b18ef0ae..f06d03ed5 100644
--- a/src/slic3r/GUI/MainFrame.cpp
+++ b/src/slic3r/GUI/MainFrame.cpp
@@ -109,6 +109,10 @@ DPIFrame(NULL, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, wxDEFAULT_FRAME_S
             return;
         }
         
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+        std::cout << "started wxEVT_CLOSE_WINDOW handler\n";
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+
         if(m_plater) m_plater->stop_jobs();
 
         // Weird things happen as the Paint messages are floating around the windows being destructed.
@@ -134,6 +138,10 @@ DPIFrame(NULL, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, wxDEFAULT_FRAME_S
 
         // propagate event
         event.Skip();
+
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+        std::cout << "completed wxEVT_CLOSE_WINDOW handler\n";
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
     });
 
     Bind(wxEVT_ACTIVATE, [this](wxActivateEvent& event) {
diff --git a/src/slic3r/GUI/MainFrame.hpp b/src/slic3r/GUI/MainFrame.hpp
index a6d0749ab..c8a65110e 100644
--- a/src/slic3r/GUI/MainFrame.hpp
+++ b/src/slic3r/GUI/MainFrame.hpp
@@ -96,7 +96,13 @@ protected:
 
 public:
     MainFrame();
-    ~MainFrame() = default;
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+    ~MainFrame()
+    {
+        std::cout << "MainFrame::~MainFrame()\n";
+    }
+//    ~MainFrame() = default;
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
 
     Plater*     plater() { return m_plater; }
 
diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp
index 87f0e1b9c..03b3061d5 100644
--- a/src/slic3r/GUI/Plater.cpp
+++ b/src/slic3r/GUI/Plater.cpp
@@ -2173,6 +2173,9 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame)
 
 Plater::priv::~priv()
 {
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+    std::cout << "Plater::priv::~priv()\n";
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
     mouse3d_controller.shutdown();
 
     if (config != nullptr)
@@ -4560,6 +4563,9 @@ Plater::Plater(wxWindow *parent, MainFrame *main_frame)
 
 Plater::~Plater()
 {
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+    std::cout << "Plater::~Plater()\n";
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
 }
 
 Sidebar&        Plater::sidebar()           { return *p->sidebar; }

From dcf3565426e350f214f9509456c4c109b8617420 Mon Sep 17 00:00:00 2001
From: Enrico Turri <enricoturri@seznam.cz>
Date: Wed, 4 Mar 2020 15:19:48 +0100
Subject: [PATCH 11/25] Attempt to fix crash on MAC when closing using
 Command+Q

---
 src/slic3r/GUI/GUI_Preview.cpp |  8 ++++++--
 src/slic3r/GUI/MainFrame.cpp   |  9 +++++++++
 src/slic3r/GUI/Plater.cpp      | 27 +++++++++++++++++++++++++++
 src/slic3r/GUI/Plater.hpp      |  5 +++++
 4 files changed, 47 insertions(+), 2 deletions(-)

diff --git a/src/slic3r/GUI/GUI_Preview.cpp b/src/slic3r/GUI/GUI_Preview.cpp
index f4d8adc70..7fea1f268 100644
--- a/src/slic3r/GUI/GUI_Preview.cpp
+++ b/src/slic3r/GUI/GUI_Preview.cpp
@@ -51,7 +51,9 @@ View3D::~View3D()
 #if ENABLE_NON_STATIC_CANVAS_MANAGER
     if (m_canvas != nullptr)
     {
-        m_canvas->unbind_event_handlers();
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+//        m_canvas->unbind_event_handlers();
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
         delete m_canvas;
     }
 #endif // ENABLE_NON_STATIC_CANVAS_MANAGER
@@ -379,7 +381,9 @@ Preview::~Preview()
 #if ENABLE_NON_STATIC_CANVAS_MANAGER
     if (m_canvas != nullptr)
     {
-        m_canvas->unbind_event_handlers();
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+//        m_canvas->unbind_event_handlers();
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
         delete m_canvas;
     }
 #endif // ENABLE_NON_STATIC_CANVAS_MANAGER
diff --git a/src/slic3r/GUI/MainFrame.cpp b/src/slic3r/GUI/MainFrame.cpp
index f06d03ed5..d72c201a7 100644
--- a/src/slic3r/GUI/MainFrame.cpp
+++ b/src/slic3r/GUI/MainFrame.cpp
@@ -115,6 +115,15 @@ DPIFrame(NULL, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, wxDEFAULT_FRAME_S
 
         if(m_plater) m_plater->stop_jobs();
 
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+#if ENABLE_NON_STATIC_CANVAS_MANAGER
+        // Unbinding of wxWidgets event handling in canvases needs to be done here because on MAC,
+        // when closing the application using Command+Q, a mouse event is triggered after this lambda is completed,
+        // causing a crash
+        if (m_plater) m_plater->unbind_canvas_event_handlers();
+#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+
         // Weird things happen as the Paint messages are floating around the windows being destructed.
         // Avoid the Paint messages by hiding the main window.
         // Also the application closes much faster without these unnecessary screen refreshes.
diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp
index 03b3061d5..e4cee4e2f 100644
--- a/src/slic3r/GUI/Plater.cpp
+++ b/src/slic3r/GUI/Plater.cpp
@@ -1814,6 +1814,11 @@ struct Plater::priv
 
     void set_current_canvas_as_dirty();
     GLCanvas3D* get_current_canvas3D();
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+#if ENABLE_NON_STATIC_CANVAS_MANAGER
+    void unbind_canvas_event_handlers();
+#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
 
     bool init_view_toolbar();
 
@@ -4089,6 +4094,19 @@ GLCanvas3D* Plater::priv::get_current_canvas3D()
     return (current_panel == view3D) ? view3D->get_canvas3d() : ((current_panel == preview) ? preview->get_canvas3d() : nullptr);
 }
 
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+#if ENABLE_NON_STATIC_CANVAS_MANAGER
+void Plater::priv::unbind_canvas_event_handlers()
+{
+    if (view3D != nullptr)
+        view3D->get_canvas3d()->unbind_event_handlers();
+
+    if (preview != nullptr)
+        preview->get_canvas3d()->unbind_event_handlers();
+}
+#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+
 bool Plater::priv::init_view_toolbar()
 {
     if (view_toolbar.get_items_count() > 0)
@@ -5527,6 +5545,15 @@ void Plater::set_current_canvas_as_dirty()
     p->set_current_canvas_as_dirty();
 }
 
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+#if ENABLE_NON_STATIC_CANVAS_MANAGER
+void Plater::unbind_canvas_event_handlers()
+{
+    p->unbind_canvas_event_handlers();
+}
+#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+
 PrinterTechnology Plater::printer_technology() const
 {
     return p->printer_technology;
diff --git a/src/slic3r/GUI/Plater.hpp b/src/slic3r/GUI/Plater.hpp
index 1ad79978a..872bb0171 100644
--- a/src/slic3r/GUI/Plater.hpp
+++ b/src/slic3r/GUI/Plater.hpp
@@ -253,6 +253,11 @@ public:
     BoundingBoxf bed_shape_bb() const;
 
     void set_current_canvas_as_dirty();
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+#if ENABLE_NON_STATIC_CANVAS_MANAGER
+    void unbind_canvas_event_handlers();
+#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
 
     PrinterTechnology   printer_technology() const;
     void                set_printer_technology(PrinterTechnology printer_technology);

From dc3df3aec7586d485131b4ab04ebcb5863ca2329 Mon Sep 17 00:00:00 2001
From: Enrico Turri <enricoturri@seznam.cz>
Date: Thu, 5 Mar 2020 10:14:12 +0100
Subject: [PATCH 12/25] Removed temporary debug output and clean up

---
 src/slic3r/GUI/GLCanvas3D.cpp        | 11 -----------
 src/slic3r/GUI/GLCanvas3DManager.cpp |  3 ---
 src/slic3r/GUI/GUI_App.cpp           |  3 ---
 src/slic3r/GUI/GUI_Preview.cpp       | 16 ----------------
 src/slic3r/GUI/ImGuiWrapper.cpp      |  3 ---
 src/slic3r/GUI/MainFrame.cpp         | 10 ----------
 src/slic3r/GUI/MainFrame.hpp         |  8 +-------
 src/slic3r/GUI/Plater.cpp            | 12 ------------
 src/slic3r/GUI/Plater.hpp            |  2 --
 9 files changed, 1 insertion(+), 67 deletions(-)

diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp
index f97bd46e6..1cb212f24 100644
--- a/src/slic3r/GUI/GLCanvas3D.cpp
+++ b/src/slic3r/GUI/GLCanvas3D.cpp
@@ -1483,9 +1483,6 @@ GLCanvas3D::GLCanvas3D(wxGLCanvas* canvas, Bed3D& bed, Camera& camera, GLToolbar
 
 GLCanvas3D::~GLCanvas3D()
 {
-//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
-    std::cout << "GLCanvas3D::~GLCanvas3D()\n";
-//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
     reset_volumes();
 }
 
@@ -2735,10 +2732,6 @@ void GLCanvas3D::bind_event_handlers()
 
 void GLCanvas3D::unbind_event_handlers()
 {
-//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
-    std::cout << "GLCanvas3D::unbind_event_handlers()\n";
-//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
-
     if (m_canvas != nullptr)
     {
         m_canvas->Unbind(wxEVT_SIZE, &GLCanvas3D::on_size, this);
@@ -3322,10 +3315,6 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
         return;
 #endif // ENABLE_NON_STATIC_CANVAS_MANAGER
 
-//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
-    std::cout << "GLCanvas3D::on_mouse()\n";
-//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
-
 #if ENABLE_RETINA_GL
     const float scale = m_retina_helper->get_scale_factor();
     evt.SetX(evt.GetX() * scale);
diff --git a/src/slic3r/GUI/GLCanvas3DManager.cpp b/src/slic3r/GUI/GLCanvas3DManager.cpp
index 631a27e31..d4522bb07 100644
--- a/src/slic3r/GUI/GLCanvas3DManager.cpp
+++ b/src/slic3r/GUI/GLCanvas3DManager.cpp
@@ -230,9 +230,6 @@ GLCanvas3DManager::GLCanvas3DManager()
 
 GLCanvas3DManager::~GLCanvas3DManager()
 {
-//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
-    std::cout << "GLCanvas3DManager::~GLCanvas3DManager()\n";
-//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
 #if ENABLE_NON_STATIC_CANVAS_MANAGER
 #if ENABLE_HACK_CLOSING_ON_OSX_10_9_5
 #ifdef __APPLE__ 
diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp
index 362ad21a1..24d9123ba 100644
--- a/src/slic3r/GUI/GUI_App.cpp
+++ b/src/slic3r/GUI/GUI_App.cpp
@@ -159,9 +159,6 @@ GUI_App::GUI_App()
 
 GUI_App::~GUI_App()
 {
-//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
-    std::cout << "GUI_App::~GUI_App()\n";
-//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
     if (app_config != nullptr)
         delete app_config;
 
diff --git a/src/slic3r/GUI/GUI_Preview.cpp b/src/slic3r/GUI/GUI_Preview.cpp
index 7fea1f268..704d1ea95 100644
--- a/src/slic3r/GUI/GUI_Preview.cpp
+++ b/src/slic3r/GUI/GUI_Preview.cpp
@@ -45,17 +45,9 @@ View3D::View3D(wxWindow* parent, Bed3D& bed, Camera& camera, GLToolbar& view_too
 
 View3D::~View3D()
 {
-//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
-    std::cout << "View3D::~View3D()\n";
-//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
 #if ENABLE_NON_STATIC_CANVAS_MANAGER
     if (m_canvas != nullptr)
-    {
-//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
-//        m_canvas->unbind_event_handlers();
-//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
         delete m_canvas;
-    }
 #endif // ENABLE_NON_STATIC_CANVAS_MANAGER
 
     if (m_canvas_widget != nullptr)
@@ -373,19 +365,11 @@ bool Preview::init(wxWindow* parent, Bed3D& bed, Camera& camera, GLToolbar& view
 
 Preview::~Preview()
 {
-//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
-    std::cout << "Preview::~Preview()\n";
-//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
     unbind_event_handlers();
 
 #if ENABLE_NON_STATIC_CANVAS_MANAGER
     if (m_canvas != nullptr)
-    {
-//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
-//        m_canvas->unbind_event_handlers();
-//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
         delete m_canvas;
-    }
 #endif // ENABLE_NON_STATIC_CANVAS_MANAGER
 
     if (m_canvas_widget != nullptr)
diff --git a/src/slic3r/GUI/ImGuiWrapper.cpp b/src/slic3r/GUI/ImGuiWrapper.cpp
index 1abc191c3..3efa800a9 100644
--- a/src/slic3r/GUI/ImGuiWrapper.cpp
+++ b/src/slic3r/GUI/ImGuiWrapper.cpp
@@ -46,9 +46,6 @@ ImGuiWrapper::ImGuiWrapper()
 
 ImGuiWrapper::~ImGuiWrapper()
 {
-//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
-    std::cout << "ImGuiWrapper::~ImGuiWrapper()\n";
-//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
     destroy_font();
     ImGui::DestroyContext();
 }
diff --git a/src/slic3r/GUI/MainFrame.cpp b/src/slic3r/GUI/MainFrame.cpp
index d72c201a7..dd9665205 100644
--- a/src/slic3r/GUI/MainFrame.cpp
+++ b/src/slic3r/GUI/MainFrame.cpp
@@ -109,20 +109,14 @@ DPIFrame(NULL, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, wxDEFAULT_FRAME_S
             return;
         }
         
-//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
-        std::cout << "started wxEVT_CLOSE_WINDOW handler\n";
-//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
-
         if(m_plater) m_plater->stop_jobs();
 
-//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
 #if ENABLE_NON_STATIC_CANVAS_MANAGER
         // Unbinding of wxWidgets event handling in canvases needs to be done here because on MAC,
         // when closing the application using Command+Q, a mouse event is triggered after this lambda is completed,
         // causing a crash
         if (m_plater) m_plater->unbind_canvas_event_handlers();
 #endif // ENABLE_NON_STATIC_CANVAS_MANAGER
-//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
 
         // Weird things happen as the Paint messages are floating around the windows being destructed.
         // Avoid the Paint messages by hiding the main window.
@@ -147,10 +141,6 @@ DPIFrame(NULL, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, wxDEFAULT_FRAME_S
 
         // propagate event
         event.Skip();
-
-//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
-        std::cout << "completed wxEVT_CLOSE_WINDOW handler\n";
-//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
     });
 
     Bind(wxEVT_ACTIVATE, [this](wxActivateEvent& event) {
diff --git a/src/slic3r/GUI/MainFrame.hpp b/src/slic3r/GUI/MainFrame.hpp
index c8a65110e..a6d0749ab 100644
--- a/src/slic3r/GUI/MainFrame.hpp
+++ b/src/slic3r/GUI/MainFrame.hpp
@@ -96,13 +96,7 @@ protected:
 
 public:
     MainFrame();
-//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
-    ~MainFrame()
-    {
-        std::cout << "MainFrame::~MainFrame()\n";
-    }
-//    ~MainFrame() = default;
-//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+    ~MainFrame() = default;
 
     Plater*     plater() { return m_plater; }
 
diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp
index e4cee4e2f..e6cfdb167 100644
--- a/src/slic3r/GUI/Plater.cpp
+++ b/src/slic3r/GUI/Plater.cpp
@@ -1814,11 +1814,9 @@ struct Plater::priv
 
     void set_current_canvas_as_dirty();
     GLCanvas3D* get_current_canvas3D();
-//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
 #if ENABLE_NON_STATIC_CANVAS_MANAGER
     void unbind_canvas_event_handlers();
 #endif // ENABLE_NON_STATIC_CANVAS_MANAGER
-//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
 
     bool init_view_toolbar();
 
@@ -2178,9 +2176,6 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame)
 
 Plater::priv::~priv()
 {
-//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
-    std::cout << "Plater::priv::~priv()\n";
-//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
     mouse3d_controller.shutdown();
 
     if (config != nullptr)
@@ -4094,7 +4089,6 @@ GLCanvas3D* Plater::priv::get_current_canvas3D()
     return (current_panel == view3D) ? view3D->get_canvas3d() : ((current_panel == preview) ? preview->get_canvas3d() : nullptr);
 }
 
-//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
 #if ENABLE_NON_STATIC_CANVAS_MANAGER
 void Plater::priv::unbind_canvas_event_handlers()
 {
@@ -4105,7 +4099,6 @@ void Plater::priv::unbind_canvas_event_handlers()
         preview->get_canvas3d()->unbind_event_handlers();
 }
 #endif // ENABLE_NON_STATIC_CANVAS_MANAGER
-//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
 
 bool Plater::priv::init_view_toolbar()
 {
@@ -4581,9 +4574,6 @@ Plater::Plater(wxWindow *parent, MainFrame *main_frame)
 
 Plater::~Plater()
 {
-//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
-    std::cout << "Plater::~Plater()\n";
-//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
 }
 
 Sidebar&        Plater::sidebar()           { return *p->sidebar; }
@@ -5545,14 +5535,12 @@ void Plater::set_current_canvas_as_dirty()
     p->set_current_canvas_as_dirty();
 }
 
-//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
 #if ENABLE_NON_STATIC_CANVAS_MANAGER
 void Plater::unbind_canvas_event_handlers()
 {
     p->unbind_canvas_event_handlers();
 }
 #endif // ENABLE_NON_STATIC_CANVAS_MANAGER
-//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
 
 PrinterTechnology Plater::printer_technology() const
 {
diff --git a/src/slic3r/GUI/Plater.hpp b/src/slic3r/GUI/Plater.hpp
index 872bb0171..c932c94c7 100644
--- a/src/slic3r/GUI/Plater.hpp
+++ b/src/slic3r/GUI/Plater.hpp
@@ -253,11 +253,9 @@ public:
     BoundingBoxf bed_shape_bb() const;
 
     void set_current_canvas_as_dirty();
-//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
 #if ENABLE_NON_STATIC_CANVAS_MANAGER
     void unbind_canvas_event_handlers();
 #endif // ENABLE_NON_STATIC_CANVAS_MANAGER
-//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
 
     PrinterTechnology   printer_technology() const;
     void                set_printer_technology(PrinterTechnology printer_technology);

From b36051af82f372a9555eb03025d85f7cbd6a07cd Mon Sep 17 00:00:00 2001
From: enricoturri1966 <enricoturri@seznam.cz>
Date: Fri, 13 Mar 2020 15:09:07 +0100
Subject: [PATCH 13/25] New tech ENABLE_SLOPE_RENDERING - 1st installment of
 rendering objects colored by facets slope

---
 resources/shaders/gouraud.fs         | 24 ++++++++-
 resources/shaders/gouraud.vs         | 18 ++++++-
 src/libslic3r/Technologies.hpp       |  9 ++++
 src/slic3r/GUI/3DScene.cpp           | 57 ++++++++++++++++++--
 src/slic3r/GUI/3DScene.hpp           | 42 +++++++++++----
 src/slic3r/GUI/GLCanvas3D.cpp        | 79 ++++++++++++++++++++++++++++
 src/slic3r/GUI/GLCanvas3D.hpp        | 29 ++++++++++
 src/slic3r/GUI/GUI_Preview.cpp       |  3 ++
 src/slic3r/GUI/KBShortcutsDialog.cpp |  3 ++
 src/slic3r/GUI/MainFrame.cpp         | 11 ++++
 src/slic3r/GUI/Plater.cpp            | 14 +++++
 src/slic3r/GUI/Plater.hpp            |  7 +++
 12 files changed, 277 insertions(+), 19 deletions(-)

diff --git a/resources/shaders/gouraud.fs b/resources/shaders/gouraud.fs
index 09003f407..be75b7d9a 100644
--- a/resources/shaders/gouraud.fs
+++ b/resources/shaders/gouraud.fs
@@ -1,6 +1,21 @@
 #version 110
 
 const vec3 ZERO = vec3(0.0, 0.0, 0.0);
+const vec3 GREEN = vec3(0.0, 0.65, 0.0);
+const vec3 YELLOW = vec3(0.5, 0.65, 0.0);
+const vec3 RED = vec3(0.65, 0.0, 0.0);
+const float EPSILON = 0.0001;
+
+struct SlopeDetection
+{
+    bool active;
+	// x = yellow z, y = red z
+	vec2 z_range;
+    mat3 volume_world_normal_matrix;
+};
+
+uniform vec4 uniform_color;
+uniform SlopeDetection slope;
 
 varying vec3 clipping_planes_dots;
 
@@ -10,14 +25,19 @@ varying vec2 intensity;
 varying vec3 delta_box_min;
 varying vec3 delta_box_max;
 
-uniform vec4 uniform_color;
+varying float world_normal_z;
 
+vec3 slope_color()
+{
+    return (world_normal_z > slope.z_range.x - EPSILON) ? GREEN : mix(RED, YELLOW, (world_normal_z - slope.z_range.y) / (slope.z_range.x - slope.z_range.y));
+}
 
 void main()
 {
     if (any(lessThan(clipping_planes_dots, ZERO)))
         discard;
+	vec3 color = slope.active ? slope_color() : uniform_color.rgb;
     // if the fragment is outside the print volume -> use darker color
-    vec3 color = (any(lessThan(delta_box_min, ZERO)) || any(greaterThan(delta_box_max, ZERO))) ? mix(uniform_color.rgb, ZERO, 0.3333) : uniform_color.rgb;
+	color = (any(lessThan(delta_box_min, ZERO)) || any(greaterThan(delta_box_max, ZERO))) ? mix(color, ZERO, 0.3333) : color;
     gl_FragColor = vec4(vec3(intensity.y, intensity.y, intensity.y) + color * intensity.x, uniform_color.a);
 }
diff --git a/resources/shaders/gouraud.vs b/resources/shaders/gouraud.vs
index cc54c1c44..3c06729f8 100644
--- a/resources/shaders/gouraud.vs
+++ b/resources/shaders/gouraud.vs
@@ -20,13 +20,22 @@ const vec3 ZERO = vec3(0.0, 0.0, 0.0);
 
 struct PrintBoxDetection
 {
+    bool active;
     vec3 min;
     vec3 max;
-    bool volume_detection;
     mat4 volume_world_matrix;
 };
 
+struct SlopeDetection
+{
+    bool active;
+	// x = yellow z, y = red z
+	vec2 z_range;
+    mat3 volume_world_normal_matrix;
+};
+
 uniform PrintBoxDetection print_box;
+uniform SlopeDetection slope;
 
 // Clipping plane, x = min z, y = max z. Used by the FFF and SLA previews to clip with a top / bottom plane.
 uniform vec2 z_range;
@@ -41,6 +50,8 @@ varying vec3 delta_box_max;
 
 varying vec3 clipping_planes_dots;
 
+varying float world_normal_z;
+
 void main()
 {
     // First transform the normal into camera space and normalize the result.
@@ -61,7 +72,7 @@ void main()
     intensity.x += NdotL * LIGHT_FRONT_DIFFUSE;
 
     // compute deltas for out of print volume detection (world coordinates)
-    if (print_box.volume_detection)
+    if (print_box.active)
     {
         vec3 v = (print_box.volume_world_matrix * gl_Vertex).xyz;
         delta_box_min = v - print_box.min;
@@ -73,6 +84,9 @@ void main()
         delta_box_max = ZERO;
     }
 
+    // z component of normal vector in world coordinate used for slope shading
+	world_normal_z = slope.active ? (normalize(slope.volume_world_normal_matrix * gl_Normal)).z : 0.0;
+
     gl_Position = ftransform();
     // Point in homogenous coordinates.
     vec4 world_pos = print_box.volume_world_matrix * gl_Vertex;
diff --git a/src/libslic3r/Technologies.hpp b/src/libslic3r/Technologies.hpp
index bd1e6d195..223abe8dd 100644
--- a/src/libslic3r/Technologies.hpp
+++ b/src/libslic3r/Technologies.hpp
@@ -50,4 +50,13 @@
 // Enable hack to remove crash when closing on OSX 10.9.5
 #define ENABLE_HACK_CLOSING_ON_OSX_10_9_5 (1 && ENABLE_2_2_0_RC1)
 
+
+//============
+// 2.2.0 techs
+//============
+#define ENABLE_2_2_0 1
+
+// Enable rendering of objects colored by facets' slope
+#define ENABLE_SLOPE_RENDERING (1 && ENABLE_2_2_0)
+
 #endif // _technologies_h_
diff --git a/src/slic3r/GUI/3DScene.cpp b/src/slic3r/GUI/3DScene.cpp
index 9f36ab537..726bebe11 100644
--- a/src/slic3r/GUI/3DScene.cpp
+++ b/src/slic3r/GUI/3DScene.cpp
@@ -400,6 +400,7 @@ void GLVolume::render() const
         glFrontFace(GL_CCW);
 }
 
+#if !ENABLE_SLOPE_RENDERING
 void GLVolume::render(int color_id, int detection_id, int worldmatrix_id) const
 {
     if (color_id >= 0)
@@ -415,6 +416,7 @@ void GLVolume::render(int color_id, int detection_id, int worldmatrix_id) const
 
     render();
 }
+#endif // !ENABLE_SLOPE_RENDERING
 
 bool GLVolume::is_sla_support() const { return this->composite_id.volume_id == -int(slaposSupportTree); }
 bool GLVolume::is_sla_pad() const { return this->composite_id.volume_id == -int(slaposPad); }
@@ -656,28 +658,64 @@ void GLVolumeCollection::render(GLVolumeCollection::ERenderType type, bool disab
     GLint color_id = (current_program_id > 0) ? ::glGetUniformLocation(current_program_id, "uniform_color") : -1;
     GLint z_range_id = (current_program_id > 0) ? ::glGetUniformLocation(current_program_id, "z_range") : -1;
     GLint clipping_plane_id = (current_program_id > 0) ? ::glGetUniformLocation(current_program_id, "clipping_plane") : -1;
+
     GLint print_box_min_id = (current_program_id > 0) ? ::glGetUniformLocation(current_program_id, "print_box.min") : -1;
     GLint print_box_max_id = (current_program_id > 0) ? ::glGetUniformLocation(current_program_id, "print_box.max") : -1;
-    GLint print_box_detection_id = (current_program_id > 0) ? ::glGetUniformLocation(current_program_id, "print_box.volume_detection") : -1;
+    GLint print_box_active_id = (current_program_id > 0) ? ::glGetUniformLocation(current_program_id, "print_box.active") : -1;
     GLint print_box_worldmatrix_id = (current_program_id > 0) ? ::glGetUniformLocation(current_program_id, "print_box.volume_world_matrix") : -1;
+
+#if ENABLE_SLOPE_RENDERING
+    GLint slope_active_id = (current_program_id > 0) ? ::glGetUniformLocation(current_program_id, "slope.active") : -1;
+    GLint slope_normal_matrix_id = (current_program_id > 0) ? ::glGetUniformLocation(current_program_id, "slope.volume_world_normal_matrix") : -1;
+    GLint slope_z_range_id = (current_program_id > 0) ? ::glGetUniformLocation(current_program_id, "slope.z_range") : -1;
+#endif // ENABLE_SLOPE_RENDERING
     glcheck();
 
     if (print_box_min_id != -1)
-        glsafe(::glUniform3fv(print_box_min_id, 1, (const GLfloat*)print_box_min));
+        glsafe(::glUniform3fv(print_box_min_id, 1, (const GLfloat*)m_print_box_min));
 
     if (print_box_max_id != -1)
-        glsafe(::glUniform3fv(print_box_max_id, 1, (const GLfloat*)print_box_max));
+        glsafe(::glUniform3fv(print_box_max_id, 1, (const GLfloat*)m_print_box_max));
 
     if (z_range_id != -1)
-        glsafe(::glUniform2fv(z_range_id, 1, (const GLfloat*)z_range));
+        glsafe(::glUniform2fv(z_range_id, 1, (const GLfloat*)m_z_range));
 
     if (clipping_plane_id != -1)
-        glsafe(::glUniform4fv(clipping_plane_id, 1, (const GLfloat*)clipping_plane));
+        glsafe(::glUniform4fv(clipping_plane_id, 1, (const GLfloat*)m_clipping_plane));
+
+#if ENABLE_SLOPE_RENDERING
+    if (slope_active_id != -1)
+        glsafe(::glUniform1i(slope_active_id, type == Opaque && m_slope_active ? 1 : 0));
+
+    if (slope_z_range_id != -1)
+        glsafe(::glUniform2fv(slope_z_range_id, 1, (const GLfloat*)m_slope_z_range.data()));
+#endif // ENABLE_SLOPE_RENDERING
 
     GLVolumeWithIdAndZList to_render = volumes_to_render(this->volumes, type, view_matrix, filter_func);
     for (GLVolumeWithIdAndZ& volume : to_render) {
         volume.first->set_render_color();
+#if ENABLE_SLOPE_RENDERING
+        if (color_id >= 0)
+            glsafe(::glUniform4fv(color_id, 1, (const GLfloat*)volume.first->render_color));
+        else
+            glsafe(::glColor4fv(volume.first->render_color));
+
+        if (print_box_active_id != -1)
+            glsafe(::glUniform1i(print_box_active_id, volume.first->shader_outside_printer_detection_enabled ? 1 : 0));
+
+        if (print_box_worldmatrix_id != -1)
+            glsafe(::glUniformMatrix4fv(print_box_worldmatrix_id, 1, GL_FALSE, (const GLfloat*)volume.first->world_matrix().cast<float>().data()));
+
+        if (slope_normal_matrix_id != -1)
+        {
+            Matrix3f normal_matrix = volume.first->world_matrix().matrix().block(0, 0, 3, 3).inverse().transpose().cast<float>();
+            glsafe(::glUniformMatrix3fv(slope_normal_matrix_id, 1, GL_FALSE, (const GLfloat*)normal_matrix.data()));
+        }
+
+        volume.first->render();
+#else
         volume.first->render(color_id, print_box_detection_id, print_box_worldmatrix_id);
+#endif // ENABLE_SLOPE_RENDERING
     }
 
     glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0));
@@ -1891,7 +1929,16 @@ void GLModel::render() const
     GLint color_id = (current_program_id > 0) ? ::glGetUniformLocation(current_program_id, "uniform_color") : -1;
     glcheck();
 
+#if ENABLE_SLOPE_RENDERING
+    if (color_id >= 0)
+        glsafe(::glUniform4fv(color_id, 1, (const GLfloat*)m_volume.render_color));
+    else
+        glsafe(::glColor4fv(m_volume.render_color));
+
+    m_volume.render();
+#else
     m_volume.render(color_id, -1, -1);
+#endif // ENABLE_SLOPE_RENDERING
 
     glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0));
     glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0));
diff --git a/src/slic3r/GUI/3DScene.hpp b/src/slic3r/GUI/3DScene.hpp
index aed907004..2d1fe2bb5 100644
--- a/src/slic3r/GUI/3DScene.hpp
+++ b/src/slic3r/GUI/3DScene.hpp
@@ -449,7 +449,9 @@ public:
     void                set_range(double low, double high);
 
     void                render() const;
+#if !ENABLE_SLOPE_RENDERING
     void                render(int color_id, int detection_id, int worldmatrix_id) const;
+#endif // !ENABLE_SLOPE_RENDERING
 
     void                finalize_geometry(bool opengl_initialized) { this->indexed_vertex_array.finalize_geometry(opengl_initialized); }
     void                release_geometry() { this->indexed_vertex_array.release_geometry(); }
@@ -485,20 +487,31 @@ public:
 
 private:
     // min and max vertex of the print box volume
-    float print_box_min[3];
-    float print_box_max[3];
+    float m_print_box_min[3];
+    float m_print_box_max[3];
 
     // z range for clipping in shaders
-    float z_range[2];
+    float m_z_range[2];
 
     // plane coeffs for clipping in shaders
-    float clipping_plane[4];
+    float m_clipping_plane[4];
+
+#if ENABLE_SLOPE_RENDERING
+    // toggle for slope rendering 
+    bool m_slope_active { false };
+    // [0] = yellow, [1] = red
+    std::array<float, 2> m_slope_z_range;
+#endif // ENABLE_SLOPE_RENDERING
 
 public:
     GLVolumePtrs volumes;
 
-    GLVolumeCollection() {};
-    ~GLVolumeCollection() { clear(); };
+#if ENABLE_SLOPE_RENDERING
+    GLVolumeCollection() { set_default_slope_z_range(); }
+#else
+    GLVolumeCollection() = default;
+#endif // ENABLE_SLOPE_RENDERING
+    ~GLVolumeCollection() { clear(); }
 
     std::vector<int> load_object(
         const ModelObject 		*model_object,
@@ -549,12 +562,21 @@ public:
     void set_range(double low, double high) { for (GLVolume *vol : this->volumes) vol->set_range(low, high); }
 
     void set_print_box(float min_x, float min_y, float min_z, float max_x, float max_y, float max_z) {
-        print_box_min[0] = min_x; print_box_min[1] = min_y; print_box_min[2] = min_z;
-        print_box_max[0] = max_x; print_box_max[1] = max_y; print_box_max[2] = max_z;
+        m_print_box_min[0] = min_x; m_print_box_min[1] = min_y; m_print_box_min[2] = min_z;
+        m_print_box_max[0] = max_x; m_print_box_max[1] = max_y; m_print_box_max[2] = max_z;
     }
 
-    void set_z_range(float min_z, float max_z) { z_range[0] = min_z; z_range[1] = max_z; }
-    void set_clipping_plane(const double* coeffs) { clipping_plane[0] = coeffs[0]; clipping_plane[1] = coeffs[1]; clipping_plane[2] = coeffs[2]; clipping_plane[3] = coeffs[3]; }
+    void set_z_range(float min_z, float max_z) { m_z_range[0] = min_z; m_z_range[1] = max_z; }
+    void set_clipping_plane(const double* coeffs) { m_clipping_plane[0] = coeffs[0]; m_clipping_plane[1] = coeffs[1]; m_clipping_plane[2] = coeffs[2]; m_clipping_plane[3] = coeffs[3]; }
+
+#if ENABLE_SLOPE_RENDERING
+    bool is_slope_active() const { return m_slope_active; }
+    void set_slope_active(bool active) { m_slope_active = active; }
+
+    const std::array<float, 2>& get_slope_z_range() const { return m_slope_z_range; }
+    void set_slope_z_range(const std::array<float, 2>& range) { m_slope_z_range = range; }
+    void set_default_slope_z_range() { m_slope_z_range = { -::cos(Geometry::deg2rad(90.0f - 45.0f)), -::cos(Geometry::deg2rad(90.0f - 70.0f)) }; }
+#endif // ENABLE_SLOPE_RENDERING
 
     // returns true if all the volumes are completely contained in the print volume
     // returns the containment state in the given out_state, if non-null
diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp
index 9a7beddc1..dc3e54bc1 100644
--- a/src/slic3r/GUI/GLCanvas3D.cpp
+++ b/src/slic3r/GUI/GLCanvas3D.cpp
@@ -1370,6 +1370,62 @@ void GLCanvas3D::Labels::render(const std::vector<const ModelInstance*>& sorted_
     }
 }
 
+#if ENABLE_SLOPE_RENDERING
+void GLCanvas3D::Slope::render() const
+{
+    if (is_shown())
+    {
+        const std::array<float, 2>& z_range = m_volumes.get_slope_z_range();
+        std::array<float, 2> angle_range = { Geometry::rad2deg(::acos(z_range[0])) - 90.0f, Geometry::rad2deg(::acos(z_range[1])) - 90.0f };
+        bool modified = false;
+
+        ImGuiWrapper& imgui = *wxGetApp().imgui();
+        const Size& cnv_size = m_canvas.get_canvas_size();
+        imgui.set_next_window_pos((float)cnv_size.get_width(), (float)cnv_size.get_height(), ImGuiCond_Always, 1.0f, 1.0f);
+        imgui.begin(_(L("Slope visualization")), nullptr, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse);
+
+        imgui.text(_(L("Facets' normal angle range (degrees)")) + ":");
+
+        ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4(0.75f, 0.75f, 0.0f, 0.5f));
+        ImGui::PushStyleColor(ImGuiCol_FrameBgHovered, ImVec4(1.0f, 1.0f, 0.0f, 0.5f));
+        ImGui::PushStyleColor(ImGuiCol_FrameBgActive, ImVec4(0.85f, 0.85f, 0.0f, 0.5f));
+        ImGui::PushStyleColor(ImGuiCol_SliderGrab, ImVec4(0.25f, 0.25f, 0.0f, 1.0f));
+        if (ImGui::SliderFloat("##yellow", &angle_range[0], 0.0f, 90.0f, "%.1f"))
+        {
+            modified = true;
+            if (angle_range[1] < angle_range[0])
+                angle_range[1] = angle_range[0];
+        }
+        ImGui::PopStyleColor(4);
+        ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4(0.75f, 0.0f, 0.0f, 0.5f));
+        ImGui::PushStyleColor(ImGuiCol_FrameBgHovered, ImVec4(1.0f, 0.0f, 0.0f, 0.5f));
+        ImGui::PushStyleColor(ImGuiCol_FrameBgActive, ImVec4(0.85f, 0.0f, 0.0f, 0.5f));
+        ImGui::PushStyleColor(ImGuiCol_SliderGrab, ImVec4(0.25f, 0.0f, 0.0f, 1.0f));
+        if (ImGui::SliderFloat("##red", &angle_range[1], 0.0f, 90.0f, "%.1f"))
+        {
+            modified = true;
+            if (angle_range[0] > angle_range[1])
+                angle_range[0] = angle_range[1];
+        }
+        ImGui::PopStyleColor(4);
+
+        ImGui::Separator();
+
+        if (imgui.button(_(L("Default"))))
+            m_volumes.set_default_slope_z_range();
+
+        // to let the dialog immediately showup without waiting for a mouse move
+        if (ImGui::GetWindowContentRegionWidth() + 2.0f * ImGui::GetStyle().WindowPadding.x != ImGui::CalcWindowExpectedSize(ImGui::GetCurrentWindow()).x)
+            m_canvas.request_extra_frame();
+
+        imgui.end();
+
+        if (modified)
+            m_volumes.set_slope_z_range({ -::cos(Geometry::deg2rad(90.0f - angle_range[0])), -::cos(Geometry::deg2rad(90.0f - angle_range[1])) });
+    }
+}
+#endif // ENABLE_SLOPE_RENDERING
+
 wxDEFINE_EVENT(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS, SimpleEvent);
 wxDEFINE_EVENT(EVT_GLCANVAS_OBJECT_SELECT, SimpleEvent);
 wxDEFINE_EVENT(EVT_GLCANVAS_RIGHT_CLICK, RBtnEvent);
@@ -1440,6 +1496,9 @@ GLCanvas3D::GLCanvas3D(wxGLCanvas* canvas, Bed3D& bed, Camera& camera, GLToolbar
 #endif // ENABLE_RENDER_PICKING_PASS
     , m_render_sla_auxiliaries(true)
     , m_labels(*this)
+#if ENABLE_SLOPE_RENDERING
+    , m_slope(*this, m_volumes)
+#endif // ENABLE_SLOPE_RENDERING
 {
     if (m_canvas != nullptr) {
         m_timer.SetOwner(m_canvas);
@@ -1727,6 +1786,11 @@ bool GLCanvas3D::is_reload_delayed() const
 
 void GLCanvas3D::enable_layers_editing(bool enable)
 {
+#if ENABLE_SLOPE_RENDERING
+    if (enable && m_slope.is_shown())
+        m_slope.show(false);
+#endif // ENABLE_SLOPE_RENDERING
+
     m_layers_editing.set_enabled(enable);
     const Selection::IndicesList& idxs = m_selection.get_volume_idxs();
     for (unsigned int idx : idxs)
@@ -2804,6 +2868,17 @@ void GLCanvas3D::on_char(wxKeyEvent& evt)
         case 'a': { post_event(SimpleEvent(EVT_GLCANVAS_ARRANGE)); break; }
         case 'B':
         case 'b': { zoom_to_bed(); break; }
+#if ENABLE_SLOPE_RENDERING
+        case 'D':
+        case 'd': {
+                    if (!is_layers_editing_enabled())
+                    {
+                        m_slope.show(!m_slope.is_shown());
+                        m_dirty = true;
+                    }
+                    break;
+                  }
+#endif // ENABLE_SLOPE_RENDERING
         case 'E':
         case 'e': { m_labels.show(!m_labels.is_shown()); m_dirty = true; break; }
         case 'I':
@@ -5062,6 +5137,10 @@ void GLCanvas3D::_render_overlays() const
     }
     m_labels.render(sorted_instances);
 
+#if ENABLE_SLOPE_RENDERING
+    m_slope.render();
+#endif // ENABLE_SLOPE_RENDERING
+
     glsafe(::glPopMatrix());
 }
 
diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp
index 9ae127880..7373c4cf9 100644
--- a/src/slic3r/GUI/GLCanvas3D.hpp
+++ b/src/slic3r/GUI/GLCanvas3D.hpp
@@ -389,6 +389,24 @@ private:
         void render(const std::vector<const ModelInstance*>& sorted_instances) const;
     };
 
+#if ENABLE_SLOPE_RENDERING
+    class Slope
+    {
+        bool m_enabled{ false };
+        GLCanvas3D& m_canvas;
+        GLVolumeCollection& m_volumes;
+
+    public:
+        Slope(GLCanvas3D& canvas, GLVolumeCollection& volumes) : m_canvas(canvas), m_volumes(volumes) {}
+
+        void enable(bool enable) { m_enabled = enable; }
+        bool is_enabled() const { return m_enabled; }
+        void show(bool show) { m_volumes.set_slope_active(m_enabled ? show : false); }
+        bool is_shown() const { return m_volumes.is_slope_active(); }
+        void render() const;
+    };
+#endif // ENABLE_SLOPE_RENDERING
+
 public:
     enum ECursorType : unsigned char
     {
@@ -467,6 +485,9 @@ private:
     int m_selected_extruder;
 
     Labels m_labels;
+#if ENABLE_SLOPE_RENDERING
+    Slope m_slope;
+#endif // ENABLE_SLOPE_RENDERING
 
 public:
     GLCanvas3D(wxGLCanvas* canvas, Bed3D& bed, Camera& camera, GLToolbar& view_toolbar);
@@ -544,6 +565,9 @@ public:
     void enable_undoredo_toolbar(bool enable);
     void enable_dynamic_background(bool enable);
     void enable_labels(bool enable) { m_labels.enable(enable); }
+#if ENABLE_SLOPE_RENDERING
+    void enable_slope(bool enable) { m_slope.enable(enable); }
+#endif // ENABLE_SLOPE_RENDERING
     void allow_multisample(bool allow);
 
     void zoom_to_bed();
@@ -668,6 +692,11 @@ public:
     bool are_labels_shown() const { return m_labels.is_shown(); }
     void show_labels(bool show) { m_labels.show(show); }
 
+#if ENABLE_SLOPE_RENDERING
+    bool is_slope_shown() const { return m_slope.is_shown(); }
+    void show_slope(bool show) { m_slope.show(show); }
+#endif // ENABLE_SLOPE_RENDERING
+
 private:
     bool _is_shown_on_screen() const;
 
diff --git a/src/slic3r/GUI/GUI_Preview.cpp b/src/slic3r/GUI/GUI_Preview.cpp
index 1ae73a192..3602bd48f 100644
--- a/src/slic3r/GUI/GUI_Preview.cpp
+++ b/src/slic3r/GUI/GUI_Preview.cpp
@@ -66,6 +66,9 @@ bool View3D::init(wxWindow* parent, Bed3D& bed, Camera& camera, GLToolbar& view_
     m_canvas->enable_main_toolbar(true);
     m_canvas->enable_undoredo_toolbar(true);
     m_canvas->enable_labels(true);
+#if ENABLE_SLOPE_RENDERING
+    m_canvas->enable_slope(true);
+#endif // ENABLE_SLOPE_RENDERING
 
     wxBoxSizer* main_sizer = new wxBoxSizer(wxVERTICAL);
     main_sizer->Add(m_canvas_widget, 1, wxALL | wxEXPAND, 0);
diff --git a/src/slic3r/GUI/KBShortcutsDialog.cpp b/src/slic3r/GUI/KBShortcutsDialog.cpp
index b595f1275..d85cd5af4 100644
--- a/src/slic3r/GUI/KBShortcutsDialog.cpp
+++ b/src/slic3r/GUI/KBShortcutsDialog.cpp
@@ -147,6 +147,9 @@ void KBShortcutsDialog::fill_shortcuts()
 #if ENABLE_SHOW_SCENE_LABELS
         { "E", L("Show/Hide object/instance labels") },
 #endif // ENABLE_SHOW_SCENE_LABELS
+#if ENABLE_SLOPE_RENDERING
+        { "D", L("Turn On/Off facets' slope rendering") },
+#endif // ENABLE_SLOPE_RENDERING
         // Configuration
         { ctrl + "P", L("Preferences") },
         // Help
diff --git a/src/slic3r/GUI/MainFrame.cpp b/src/slic3r/GUI/MainFrame.cpp
index defd0b53a..4f01c5797 100644
--- a/src/slic3r/GUI/MainFrame.cpp
+++ b/src/slic3r/GUI/MainFrame.cpp
@@ -720,9 +720,20 @@ void MainFrame::init_menubar()
         append_menu_item(viewMenu, wxID_ANY, _(L("Right")) + sep + "&6", _(L("Right View")), [this](wxCommandEvent&) { select_view("right"); },
             "", nullptr, [this](){return can_change_view(); }, this);
         viewMenu->AppendSeparator();
+#if ENABLE_SLOPE_RENDERING
+        wxMenu* options_menu = new wxMenu();
+        append_menu_check_item(options_menu, wxID_ANY, _(L("Show &labels")) + sep + "E", _(L("Show object/instance labels in 3D scene")),
+            [this](wxCommandEvent&) { m_plater->show_view3D_labels(!m_plater->are_view3D_labels_shown()); }, this,
+            [this]() { return m_plater->is_view3D_shown(); }, [this]() { return m_plater->are_view3D_labels_shown(); }, this);
+        append_menu_check_item(options_menu, wxID_ANY, _(L("Show &slope")) + sep + "D", _(L("Objects coloring using faces' slope")),
+            [this](wxCommandEvent&) { m_plater->show_view3D_slope(!m_plater->is_view3D_slope_shown()); }, this,
+            [this]() { return m_plater->is_view3D_shown() && !m_plater->is_view3D_layers_editing_enabled(); }, [this]() { return m_plater->is_view3D_slope_shown(); }, this);
+        append_submenu(viewMenu, options_menu, wxID_ANY, _(L("&Options")), "");
+#else
         append_menu_check_item(viewMenu, wxID_ANY, _(L("Show &labels")) + sep + "E", _(L("Show object/instance labels in 3D scene")),
             [this](wxCommandEvent&) { m_plater->show_view3D_labels(!m_plater->are_view3D_labels_shown()); }, this,
             [this]() { return m_plater->is_view3D_shown(); }, [this]() { return m_plater->are_view3D_labels_shown(); }, this);
+#endif // ENABLE_SLOPE_RENDERING
     }
 
     // Help menu
diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp
index 224eb42fd..0bd4592ba 100644
--- a/src/slic3r/GUI/Plater.cpp
+++ b/src/slic3r/GUI/Plater.cpp
@@ -1842,6 +1842,13 @@ struct Plater::priv
     bool are_view3D_labels_shown() const { return (current_panel == view3D) && view3D->get_canvas3d()->are_labels_shown(); }
     void show_view3D_labels(bool show) { if (current_panel == view3D) view3D->get_canvas3d()->show_labels(show); }
 
+#if ENABLE_SLOPE_RENDERING
+    bool is_view3D_slope_shown() const { return (current_panel == view3D) && view3D->get_canvas3d()->is_slope_shown(); }
+    void show_view3D_slope(bool show) { if (current_panel == view3D) view3D->get_canvas3d()->show_slope(show); }
+
+    bool is_view3D_layers_editing_enabled() const { return (current_panel == view3D) && view3D->get_canvas3d()->is_layers_editing_enabled(); }
+#endif // ENABLE_SLOPE_RENDERING
+
     void set_current_canvas_as_dirty();
     GLCanvas3D* get_current_canvas3D();
 
@@ -4715,6 +4722,13 @@ bool Plater::is_view3D_shown() const { return p->is_view3D_shown(); }
 bool Plater::are_view3D_labels_shown() const { return p->are_view3D_labels_shown(); }
 void Plater::show_view3D_labels(bool show) { p->show_view3D_labels(show); }
 
+#if ENABLE_SLOPE_RENDERING
+bool Plater::is_view3D_slope_shown() const { return p->is_view3D_slope_shown(); }
+void Plater::show_view3D_slope(bool show) { p->show_view3D_slope(show); }
+
+bool Plater::is_view3D_layers_editing_enabled() const { return p->is_view3D_layers_editing_enabled(); }
+#endif // ENABLE_SLOPE_RENDERING
+
 void Plater::select_all() { p->select_all(); }
 void Plater::deselect_all() { p->deselect_all(); }
 
diff --git a/src/slic3r/GUI/Plater.hpp b/src/slic3r/GUI/Plater.hpp
index 89603f703..529f59a3d 100644
--- a/src/slic3r/GUI/Plater.hpp
+++ b/src/slic3r/GUI/Plater.hpp
@@ -173,6 +173,13 @@ public:
     bool are_view3D_labels_shown() const;
     void show_view3D_labels(bool show);
 
+#if ENABLE_SLOPE_RENDERING
+    bool is_view3D_slope_shown() const;
+    void show_view3D_slope(bool show);
+
+    bool is_view3D_layers_editing_enabled() const;
+#endif // ENABLE_SLOPE_RENDERING
+
     // Called after the Preferences dialog is closed and the program settings are saved.
     // Update the UI based on the current preferences.
     void update_ui_from_settings();

From 5378b18f181e0a2684930c0b831cd88d79e1d6c3 Mon Sep 17 00:00:00 2001
From: enricoturri1966 <enricoturri@seznam.cz>
Date: Mon, 16 Mar 2020 08:35:13 +0100
Subject: [PATCH 14/25] ENABLE_SLOPE_RENDERING - Fixed fragment shader when the
 thresholds are identical

---
 resources/shaders/gouraud.fs | 11 ++++++-----
 resources/shaders/gouraud.vs |  2 +-
 2 files changed, 7 insertions(+), 6 deletions(-)

diff --git a/resources/shaders/gouraud.fs b/resources/shaders/gouraud.fs
index be75b7d9a..dce033d7b 100644
--- a/resources/shaders/gouraud.fs
+++ b/resources/shaders/gouraud.fs
@@ -1,15 +1,15 @@
 #version 110
 
 const vec3 ZERO = vec3(0.0, 0.0, 0.0);
-const vec3 GREEN = vec3(0.0, 0.65, 0.0);
-const vec3 YELLOW = vec3(0.5, 0.65, 0.0);
-const vec3 RED = vec3(0.65, 0.0, 0.0);
+const vec3 GREEN = vec3(0.0, 0.7, 0.0);
+const vec3 YELLOW = vec3(0.5, 0.7, 0.0);
+const vec3 RED = vec3(0.7, 0.0, 0.0);
 const float EPSILON = 0.0001;
 
 struct SlopeDetection
 {
     bool active;
-	// x = yellow z, y = red z
+	// x = yellow, y = red
 	vec2 z_range;
     mat3 volume_world_normal_matrix;
 };
@@ -29,7 +29,8 @@ varying float world_normal_z;
 
 vec3 slope_color()
 {
-    return (world_normal_z > slope.z_range.x - EPSILON) ? GREEN : mix(RED, YELLOW, (world_normal_z - slope.z_range.y) / (slope.z_range.x - slope.z_range.y));
+    float gradient_range = slope.z_range.x - slope.z_range.y;
+    return (world_normal_z > slope.z_range.x - EPSILON) ? GREEN : ((gradient_range == 0.0) ? RED : mix(RED, YELLOW, clamp((world_normal_z - slope.z_range.y) / gradient_range, 0.0, 1.0)));
 }
 
 void main()
diff --git a/resources/shaders/gouraud.vs b/resources/shaders/gouraud.vs
index 3c06729f8..72d6c18b3 100644
--- a/resources/shaders/gouraud.vs
+++ b/resources/shaders/gouraud.vs
@@ -29,7 +29,7 @@ struct PrintBoxDetection
 struct SlopeDetection
 {
     bool active;
-	// x = yellow z, y = red z
+	// x = yellow, y = red
 	vec2 z_range;
     mat3 volume_world_normal_matrix;
 };

From abcd01d64a3b78fdf2fbbffed8bf4dab8d9b327a Mon Sep 17 00:00:00 2001
From: enricoturri1966 <enricoturri@seznam.cz>
Date: Mon, 16 Mar 2020 14:17:19 +0100
Subject: [PATCH 15/25] ENABLE_SLOPE_RENDERING - Do not apply slope shading to
 modifiers and small refactoring

---
 src/slic3r/GUI/3DScene.cpp |  8 ++++----
 src/slic3r/GUI/3DScene.hpp | 23 ++++++++++++++---------
 2 files changed, 18 insertions(+), 13 deletions(-)

diff --git a/src/slic3r/GUI/3DScene.cpp b/src/slic3r/GUI/3DScene.cpp
index 726bebe11..f42ab634a 100644
--- a/src/slic3r/GUI/3DScene.cpp
+++ b/src/slic3r/GUI/3DScene.cpp
@@ -684,11 +684,8 @@ void GLVolumeCollection::render(GLVolumeCollection::ERenderType type, bool disab
         glsafe(::glUniform4fv(clipping_plane_id, 1, (const GLfloat*)m_clipping_plane));
 
 #if ENABLE_SLOPE_RENDERING
-    if (slope_active_id != -1)
-        glsafe(::glUniform1i(slope_active_id, type == Opaque && m_slope_active ? 1 : 0));
-
     if (slope_z_range_id != -1)
-        glsafe(::glUniform2fv(slope_z_range_id, 1, (const GLfloat*)m_slope_z_range.data()));
+        glsafe(::glUniform2fv(slope_z_range_id, 1, (const GLfloat*)m_slope.z_range.data()));
 #endif // ENABLE_SLOPE_RENDERING
 
     GLVolumeWithIdAndZList to_render = volumes_to_render(this->volumes, type, view_matrix, filter_func);
@@ -706,6 +703,9 @@ void GLVolumeCollection::render(GLVolumeCollection::ERenderType type, bool disab
         if (print_box_worldmatrix_id != -1)
             glsafe(::glUniformMatrix4fv(print_box_worldmatrix_id, 1, GL_FALSE, (const GLfloat*)volume.first->world_matrix().cast<float>().data()));
 
+        if (slope_active_id != -1)
+            glsafe(::glUniform1i(slope_active_id, m_slope.active && !volume.first->is_modifier && !volume.first->is_wipe_tower ? 1 : 0));
+
         if (slope_normal_matrix_id != -1)
         {
             Matrix3f normal_matrix = volume.first->world_matrix().matrix().block(0, 0, 3, 3).inverse().transpose().cast<float>();
diff --git a/src/slic3r/GUI/3DScene.hpp b/src/slic3r/GUI/3DScene.hpp
index 2d1fe2bb5..a397f4a1c 100644
--- a/src/slic3r/GUI/3DScene.hpp
+++ b/src/slic3r/GUI/3DScene.hpp
@@ -497,10 +497,15 @@ private:
     float m_clipping_plane[4];
 
 #if ENABLE_SLOPE_RENDERING
-    // toggle for slope rendering 
-    bool m_slope_active { false };
-    // [0] = yellow, [1] = red
-    std::array<float, 2> m_slope_z_range;
+    struct Slope
+    {
+        // toggle for slope rendering 
+        bool active{ false };
+        // [0] = yellow, [1] = red
+        std::array<float, 2> z_range;
+    };
+
+    Slope m_slope;
 #endif // ENABLE_SLOPE_RENDERING
 
 public:
@@ -570,12 +575,12 @@ public:
     void set_clipping_plane(const double* coeffs) { m_clipping_plane[0] = coeffs[0]; m_clipping_plane[1] = coeffs[1]; m_clipping_plane[2] = coeffs[2]; m_clipping_plane[3] = coeffs[3]; }
 
 #if ENABLE_SLOPE_RENDERING
-    bool is_slope_active() const { return m_slope_active; }
-    void set_slope_active(bool active) { m_slope_active = active; }
+    bool is_slope_active() const { return m_slope.active; }
+    void set_slope_active(bool active) { m_slope.active = active; }
 
-    const std::array<float, 2>& get_slope_z_range() const { return m_slope_z_range; }
-    void set_slope_z_range(const std::array<float, 2>& range) { m_slope_z_range = range; }
-    void set_default_slope_z_range() { m_slope_z_range = { -::cos(Geometry::deg2rad(90.0f - 45.0f)), -::cos(Geometry::deg2rad(90.0f - 70.0f)) }; }
+    const std::array<float, 2>& get_slope_z_range() const { return m_slope.z_range; }
+    void set_slope_z_range(const std::array<float, 2>& range) { m_slope.z_range = range; }
+    void set_default_slope_z_range() { m_slope.z_range = { -::cos(Geometry::deg2rad(90.0f - 45.0f)), -::cos(Geometry::deg2rad(90.0f - 70.0f)) }; }
 #endif // ENABLE_SLOPE_RENDERING
 
     // returns true if all the volumes are completely contained in the print volume

From ed0f3b340650a7ecfadee198e0f97ac152b47c12 Mon Sep 17 00:00:00 2001
From: enricoturri1966 <enricoturri@seznam.cz>
Date: Wed, 25 Mar 2020 13:55:17 +0100
Subject: [PATCH 16/25] Small refactoring

---
 src/slic3r/GUI/3DBed.cpp       | 3 ---
 src/slic3r/GUI/GUI_Preview.cpp | 2 ++
 2 files changed, 2 insertions(+), 3 deletions(-)

diff --git a/src/slic3r/GUI/3DBed.cpp b/src/slic3r/GUI/3DBed.cpp
index 5ac3899c1..23acd18ef 100644
--- a/src/slic3r/GUI/3DBed.cpp
+++ b/src/slic3r/GUI/3DBed.cpp
@@ -10,9 +10,6 @@
 #include "PresetBundle.hpp"
 #include "Gizmos/GLGizmoBase.hpp"
 #include "GLCanvas3D.hpp"
-#if ENABLE_NON_STATIC_CANVAS_MANAGER
-#include "GLCanvas3DManager.hpp"
-#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
 
 #include <GL/glew.h>
 
diff --git a/src/slic3r/GUI/GUI_Preview.cpp b/src/slic3r/GUI/GUI_Preview.cpp
index 704d1ea95..d94cba974 100644
--- a/src/slic3r/GUI/GUI_Preview.cpp
+++ b/src/slic3r/GUI/GUI_Preview.cpp
@@ -56,7 +56,9 @@ View3D::~View3D()
         _3DScene::remove_canvas(m_canvas_widget);
 #endif // !ENABLE_NON_STATIC_CANVAS_MANAGER
         delete m_canvas_widget;
+#if !ENABLE_NON_STATIC_CANVAS_MANAGER
         m_canvas = nullptr;
+#endif // !ENABLE_NON_STATIC_CANVAS_MANAGER
     }
 }
 

From bfbcd45209cdcaa0e340780294dfe28efbbf0e96 Mon Sep 17 00:00:00 2001
From: enricoturri1966 <enricoturri@seznam.cz>
Date: Wed, 25 Mar 2020 15:15:20 +0100
Subject: [PATCH 17/25] Fixed build on Mac

---
 src/slic3r/GUI/GLCanvas3D.cpp | 2 +-
 src/slic3r/GUI/GLToolbar.cpp  | 4 ----
 src/slic3r/GUI/Plater.hpp     | 2 --
 3 files changed, 1 insertion(+), 7 deletions(-)

diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp
index c54f2cf9a..ad8579e02 100644
--- a/src/slic3r/GUI/GLCanvas3D.cpp
+++ b/src/slic3r/GUI/GLCanvas3D.cpp
@@ -4229,7 +4229,7 @@ void GLCanvas3D::update_ui_from_settings()
         BOOST_LOG_TRIVIAL(debug) << "GLCanvas3D: Scaling factor: " << new_scaling;
 
 #if ENABLE_NON_STATIC_CANVAS_MANAGER
-        camera.set_zoom(camera.get_zoom() * new_scaling / orig_scaling);
+        wxGetApp().plater()->get_camera().set_zoom(camera.get_zoom() * new_scaling / orig_scaling);
 #else
         m_camera.set_zoom(m_camera.get_zoom() * new_scaling / orig_scaling);
 #endif // ENABLE_NON_STATIC_CANVAS_MANAGER
diff --git a/src/slic3r/GUI/GLToolbar.cpp b/src/slic3r/GUI/GLToolbar.cpp
index 15fd6f0e3..4219fe482 100644
--- a/src/slic3r/GUI/GLToolbar.cpp
+++ b/src/slic3r/GUI/GLToolbar.cpp
@@ -12,10 +12,6 @@
 #include "../../slic3r/GUI/Camera.hpp"
 #endif // ENABLE_NON_STATIC_CANVAS_MANAGER
 
-//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
-//#include <GL/glew.h>
-//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
-
 #include <wx/event.h>
 #include <wx/bitmap.h>
 #include <wx/dcmemory.h>
diff --git a/src/slic3r/GUI/Plater.hpp b/src/slic3r/GUI/Plater.hpp
index d242de8b9..4462d4237 100644
--- a/src/slic3r/GUI/Plater.hpp
+++ b/src/slic3r/GUI/Plater.hpp
@@ -42,12 +42,10 @@ class ObjectList;
 class GLCanvas3D;
 class Mouse3DController;
 struct Camera;
-//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
 #if ENABLE_NON_STATIC_CANVAS_MANAGER
 class Bed3D;
 class GLToolbar;
 #endif // ENABLE_NON_STATIC_CANVAS_MANAGER
-//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
 
 using t_optgroups = std::vector <std::shared_ptr<ConfigOptionsGroup>>;
 

From dd34aef643a9cdd14a4db0ce77f0c3813e25c62c Mon Sep 17 00:00:00 2001
From: enricoturri1966 <enricoturri@seznam.cz>
Date: Wed, 25 Mar 2020 15:30:25 +0100
Subject: [PATCH 18/25] Follow-up of bfbcd45209cdcaa0e340780294dfe28efbbf0e96
 -> completed fix

---
 src/slic3r/GUI/GLCanvas3D.cpp | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp
index ad8579e02..cfd5e1e11 100644
--- a/src/slic3r/GUI/GLCanvas3D.cpp
+++ b/src/slic3r/GUI/GLCanvas3D.cpp
@@ -4229,7 +4229,8 @@ void GLCanvas3D::update_ui_from_settings()
         BOOST_LOG_TRIVIAL(debug) << "GLCanvas3D: Scaling factor: " << new_scaling;
 
 #if ENABLE_NON_STATIC_CANVAS_MANAGER
-        wxGetApp().plater()->get_camera().set_zoom(camera.get_zoom() * new_scaling / orig_scaling);
+        Camera& camera = wxGetApp().plater()->get_camera();
+        camera.set_zoom(camera.get_zoom() * new_scaling / orig_scaling);
 #else
         m_camera.set_zoom(m_camera.get_zoom() * new_scaling / orig_scaling);
 #endif // ENABLE_NON_STATIC_CANVAS_MANAGER

From 8d7f88b381e8e7bb7bbe5b536bc10ea397982895 Mon Sep 17 00:00:00 2001
From: bubnikv <bubnikv@gmail.com>
Date: Wed, 25 Mar 2020 16:03:55 +0100
Subject: [PATCH 19/25] Imported error reporting when loading presets with
 option keys or option values that our poor software does not understand. This
 applies to configs added by some forks of slic3r, for example slic3r++
 PrusaSlicer has encountered an error: Failed loading the preset file: #3909

---
 src/libslic3r/Config.cpp | 2 +-
 src/libslic3r/Config.hpp | 7 +++----
 2 files changed, 4 insertions(+), 5 deletions(-)

diff --git a/src/libslic3r/Config.cpp b/src/libslic3r/Config.cpp
index 6806f4f54..674410388 100644
--- a/src/libslic3r/Config.cpp
+++ b/src/libslic3r/Config.cpp
@@ -464,7 +464,7 @@ bool ConfigBase::set_deserialize_nothrow(const t_config_option_key &opt_key_src,
 void ConfigBase::set_deserialize(const t_config_option_key &opt_key_src, const std::string &value_src, bool append)
 {
 	if (! this->set_deserialize_nothrow(opt_key_src, value_src, append))
-		throw BadOptionTypeException("ConfigBase::set_deserialize() failed");
+		throw BadOptionTypeException((boost::format("ConfigBase::set_deserialize() failed for parameter \"%1%\", value \"%2%\"") % opt_key_src % value_src).str());
 }
 
 void ConfigBase::set_deserialize(std::initializer_list<SetDeserializeItem> items)
diff --git a/src/libslic3r/Config.hpp b/src/libslic3r/Config.hpp
index f02caf226..87e020898 100644
--- a/src/libslic3r/Config.hpp
+++ b/src/libslic3r/Config.hpp
@@ -56,10 +56,9 @@ public:
 class BadOptionTypeException : public std::runtime_error
 {
 public:
-	BadOptionTypeException() :
-		std::runtime_error("Bad option type exception") {}
-	BadOptionTypeException(const char* message) : 
-		std::runtime_error(message) {}
+	BadOptionTypeException() : std::runtime_error("Bad option type exception") {}
+	BadOptionTypeException(const std::string &message) : std::runtime_error(message) {}
+    BadOptionTypeException(const char* message) : std::runtime_error(message) {}
 };
 
 // Type of a configuration value.

From b3cebdb672d23a9949897c63a13feaebe679332e Mon Sep 17 00:00:00 2001
From: bubnikv <bubnikv@gmail.com>
Date: Wed, 25 Mar 2020 17:55:46 +0100
Subject: [PATCH 20/25] Fix after merge

---
 src/libslic3r/Technologies.hpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/libslic3r/Technologies.hpp b/src/libslic3r/Technologies.hpp
index 31f65f7ac..c66cca8ea 100644
--- a/src/libslic3r/Technologies.hpp
+++ b/src/libslic3r/Technologies.hpp
@@ -50,7 +50,7 @@
 #define ENABLE_2_3_0 1
 
 // Enable rendering of objects colored by facets' slope
-#define ENABLE_SLOPE_RENDERING (1 && ENABLE_2_2_0)
+#define ENABLE_SLOPE_RENDERING (1 && ENABLE_2_3_0)
 
 //===================
 // 2.3.0.alpha1 techs

From 0054134ff8e0a5ac5a54359910f7cb536c7492a0 Mon Sep 17 00:00:00 2001
From: Lukas Matena <lukasmatena@seznam.cz>
Date: Wed, 25 Mar 2020 23:52:47 +0100
Subject: [PATCH 21/25] Fix of #3916 (macOS crash when generating
 WarningTexture) Likely the same cause as #3371, hopefully the same solution
 as presented in 4f1f507

---
 src/slic3r/GUI/GLCanvas3D.cpp | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp
index c2713c80d..e422dc238 100644
--- a/src/slic3r/GUI/GLCanvas3D.cpp
+++ b/src/slic3r/GUI/GLCanvas3D.cpp
@@ -781,6 +781,13 @@ bool GLCanvas3D::WarningTexture::generate(const std::string& msg_utf8, const GLC
 #else
     // select default font
     const float scale = canvas.get_canvas_size().get_scale_factor();
+#if ENABLE_RETINA_GL
+    // For non-visible or non-created window getBackingScaleFactor function return 0.0 value.
+    // And using of the zero scale causes a crash, when we trying to draw text to the (0,0) rectangle
+    // https://github.com/prusa3d/PrusaSlicer/issues/3916
+    if (scale <= 0.0f)
+        return false;
+#endif
     wxFont font = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT).Scale(scale);
 #endif
 

From a1aee69c5a501706a5ff3f98e2ed87742224a08b Mon Sep 17 00:00:00 2001
From: bubnikv <bubnikv@gmail.com>
Date: Thu, 26 Mar 2020 14:27:18 +0100
Subject: [PATCH 22/25] Fixed a logical error in substitution of the selected
 language with the system language: System language returned by Windows for
 pt_BR is pt_PT, and this language was then used incorrectly to select the
 dictionary.

Now the selected language is stored into PrusaSlicer.ini and
if a substitution is to be performed to select locales (not the dictionary)
based on the system recommended locales, this substitution is being
done in runtime just before switching the locales.
Fixes PrusaSlicer 2.3.0 - Language Portuguese (Brazilian) dont work #3901

Also hopefully fixed
LANGUAGE environment variable not respected #2970
by calling
wxTranslations::Get()->GetBestTranslation()
on Unix systems as well, which reads the "LANGUAGE" environment.
---
 src/slic3r/GUI/GUI_App.cpp | 28 +++++++++++++++++++---------
 1 file changed, 19 insertions(+), 9 deletions(-)

diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp
index c4014bd4b..dcc0c4417 100644
--- a/src/slic3r/GUI/GUI_App.cpp
+++ b/src/slic3r/GUI/GUI_App.cpp
@@ -684,15 +684,16 @@ bool GUI_App::select_language()
 	// Try to load a new language.
     if (index != -1 && (init_selection == -1 || init_selection != index)) {
     	const wxLanguageInfo *new_language_info = language_infos[index];
-        if (new_language_info == m_language_info_best || new_language_info == m_language_info_system) {
-        	// The newly selected profile matches user's default profile exactly. That's great.
-        } else if (m_language_info_best != nullptr && new_language_info->CanonicalName.BeforeFirst('_') == m_language_info_best->CanonicalName.BeforeFirst('_'))
-    		new_language_info = m_language_info_best;
-    	else if (m_language_info_system != nullptr && new_language_info->CanonicalName.BeforeFirst('_') == m_language_info_system->CanonicalName.BeforeFirst('_'))
-            new_language_info = m_language_info_system;
     	if (this->load_language(new_language_info->CanonicalName, false)) {
 			// Save language at application config.
-			app_config->set("translation_language", m_wxLocale->GetCanonicalName().ToUTF8().data());
+            // Which language to save as the selected dictionary language?
+            // 1) Hopefully the language set to wxTranslations by this->load_language(), but that API is weird and we don't want to rely on its
+            //    stability in the future:
+            //    wxTranslations::Get()->GetBestTranslation(SLIC3R_APP_KEY, wxLANGUAGE_ENGLISH);
+            // 2) Current locale language may not match the dictionary name, see GH issue #3901
+            //    m_wxLocale->GetCanonicalName()
+            // 3) new_language_info->CanonicalName is a safe bet. It points to a valid dictionary name.
+			app_config->set("translation_language", new_language_info->CanonicalName.ToUTF8().data());            
 			app_config->save();
     		return true;
     	}
@@ -721,7 +722,6 @@ bool GUI_App::load_language(wxString language, bool initial)
 	        	BOOST_LOG_TRIVIAL(trace) << boost::format("System language detected (user locales and such): %1%") % m_language_info_system->CanonicalName.ToUTF8().data();
 	        }
 		}
-#if defined(__WXMSW__) || defined(__WXOSX__)
         {
 	    	// Allocating a temporary locale will switch the default wxTranslations to its internal wxTranslations instance.
 	    	wxLocale temp_locale;
@@ -738,7 +738,6 @@ bool GUI_App::load_language(wxString language, bool initial)
 	        	BOOST_LOG_TRIVIAL(trace) << boost::format("Best translation language detected (may be different from user locales): %1%") % m_language_info_best->CanonicalName.ToUTF8().data();
 			}
 		}
-#endif
     }
 
 	const wxLanguageInfo *language_info = language.empty() ? nullptr : wxLocale::FindLanguageInfo(language);
@@ -754,6 +753,7 @@ bool GUI_App::load_language(wxString language, bool initial)
 	}
 
     if (language_info == nullptr) {
+        // PrusaSlicer does not support the Right to Left languages yet.
         if (m_language_info_system != nullptr && m_language_info_system->LayoutDirection != wxLayout_RightToLeft)
             language_info = m_language_info_system;
         if (m_language_info_best != nullptr && m_language_info_best->LayoutDirection != wxLayout_RightToLeft)
@@ -772,6 +772,16 @@ bool GUI_App::load_language(wxString language, bool initial)
 		BOOST_LOG_TRIVIAL(trace) << "Using Czech dictionaries for Slovak language";
     }
 
+    // Select language for locales. This language may be different from the language of the dictionary.
+    if (language_info == m_language_info_best || language_info == m_language_info_system) {
+        // The current language matches user's default profile exactly. That's great.
+    } else if (m_language_info_best != nullptr && language_info->CanonicalName.BeforeFirst('_') == m_language_info_best->CanonicalName.BeforeFirst('_')) {
+        // Use whatever the operating system recommends, if it the language code of the dictionary matches the recommended language.
+        // This allows a Swiss guy to use a German dictionary without forcing him to German locales.
+        language_info = m_language_info_best;
+    } else if (m_language_info_system != nullptr && language_info->CanonicalName.BeforeFirst('_') == m_language_info_system->CanonicalName.BeforeFirst('_'))
+        language_info = m_language_info_system;
+
     if (! wxLocale::IsAvailable(language_info->Language)) {
     	// Loading the language dictionary failed.
     	wxString message = "Switching PrusaSlicer to language " + language_info->CanonicalName + " failed.";

From 3fdd643f4990686cde528024376e46df7042f680 Mon Sep 17 00:00:00 2001
From: bubnikv <bubnikv@gmail.com>
Date: Thu, 26 Mar 2020 19:06:23 +0100
Subject: [PATCH 23/25] Fix of PrusaSlicer trying to access my floppy disk
 (A:\) Some customers seem to posses a floppy drive (sic!) and some floppy
 drives start spinning if accessed just to check whether there is a medium
 plugged in or not.

From now, the A: and B: drives are not checked anymore for removable
media. Now let's pray nobody maps an SD card or flash drive to A: or B:

Fixes
https://forum.prusaprinters.org/forum/prusaslicer/prusaslicer-trying-to-access-my-floppy-disk-a
---
 src/slic3r/GUI/RemovableDriveManager.cpp | 12 +++++++-----
 1 file changed, 7 insertions(+), 5 deletions(-)

diff --git a/src/slic3r/GUI/RemovableDriveManager.cpp b/src/slic3r/GUI/RemovableDriveManager.cpp
index cdb1c1d45..c0efa47fe 100644
--- a/src/slic3r/GUI/RemovableDriveManager.cpp
+++ b/src/slic3r/GUI/RemovableDriveManager.cpp
@@ -33,17 +33,19 @@ wxDEFINE_EVENT(EVT_REMOVABLE_DRIVES_CHANGED, RemovableDrivesChangedEvent);
 #if _WIN32
 std::vector<DriveData> RemovableDriveManager::search_for_removable_drives() const
 {
-	//get logical drives flags by letter in alphabetical order
+	// Get logical drives flags by letter in alphabetical order.
 	DWORD drives_mask = ::GetLogicalDrives();
 
 	// Allocate the buffers before the loop.
 	std::wstring volume_name;
 	std::wstring file_system_name;
-	// Iterate the Windows drives from 'A' to 'Z'
+	// Iterate the Windows drives from 'C' to 'Z'
 	std::vector<DriveData> current_drives;
-	for (size_t i = 0; i < 26; ++ i)
-		if (drives_mask & (1 << i)) {
-			std::string path { char('A' + i), ':' };
+	// Skip A and B drives.
+	drives_mask >>= 2;
+	for (char drive = 'C'; drive <= 'Z'; ++ drive, drives_mask >>= 1)
+		if (drives_mask & 1) {
+			std::string path { drive, ':' };
 			UINT drive_type = ::GetDriveTypeA(path.c_str());
 			// DRIVE_REMOVABLE on W are sd cards and usb thumbnails (not usb harddrives)
 			if (drive_type ==  DRIVE_REMOVABLE) {

From 58192ba6c224298bfa9804e016831e77051c1be7 Mon Sep 17 00:00:00 2001
From: bubnikv <bubnikv@gmail.com>
Date: Fri, 27 Mar 2020 08:10:00 +0100
Subject: [PATCH 24/25] Win32 specific: Using SHChangeNotifyRegister to get
 notifications on removable media insert / eject events. From now on we no
 more poll for removable media on Windows.

Thanks @mjgtp from prusaprinters.org
See the following discussion:
https://forum.prusaprinters.org/forum/prusaslicer/prusaslicer-trying-to-access-my-floppy-disk-a

The final working code sample was taken from Chromium source code,
volume_mount_watcher_win.cc
---
 src/slic3r/GUI/GUI_App.cpp               | 37 +++++++++++++++++++++++-
 src/slic3r/GUI/MainFrame.cpp             | 35 ++++++++++++++++++++--
 src/slic3r/GUI/MainFrame.hpp             |  2 ++
 src/slic3r/GUI/RemovableDriveManager.cpp | 10 ++-----
 4 files changed, 73 insertions(+), 11 deletions(-)

diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp
index dcc0c4417..f5a4a3d92 100644
--- a/src/slic3r/GUI/GUI_App.cpp
+++ b/src/slic3r/GUI/GUI_App.cpp
@@ -50,8 +50,8 @@
 #include "RemovableDriveManager.hpp"
 
 #ifdef __WXMSW__
-#include <Shlobj.h>
 #include <dbt.h>
+#include <shlobj.h>
 #endif // __WXMSW__
 
 #if ENABLE_THUMBNAIL_GENERATOR_DEBUG
@@ -158,6 +158,41 @@ static void register_win32_device_notification_event()
         }
         return true;
     });
+
+    wxWindow::MSWRegisterMessageHandler(MainFrame::WM_USER_MEDIACHANGED, [](wxWindow *win, WXUINT /* nMsg */, WXWPARAM wParam, WXLPARAM lParam) {
+        // Some messages are sent to top level windows by default, some messages are sent to only registered windows, and we explictely register on MainFrame only.
+        auto main_frame = dynamic_cast<MainFrame*>(win);
+        auto plater = (main_frame == nullptr) ? nullptr : main_frame->plater();
+        if (plater == nullptr)
+            // Maybe some other top level window like a dialog or maybe a pop-up menu?
+            return true;
+        wchar_t sPath[MAX_PATH];
+        if (lParam == SHCNE_MEDIAINSERTED || lParam == SHCNE_MEDIAREMOVED) {
+            struct _ITEMIDLIST* pidl = *reinterpret_cast<struct _ITEMIDLIST**>(wParam);
+            if (! SHGetPathFromIDList(pidl, sPath)) {
+                BOOST_LOG_TRIVIAL(error) << "MediaInserted: SHGetPathFromIDList failed";
+                return false;
+            }
+        }
+        switch (lParam) {
+        case SHCNE_MEDIAINSERTED:
+        {
+            //printf("SHCNE_MEDIAINSERTED %S\n", sPath);
+            plater->GetEventHandler()->AddPendingEvent(VolumeAttachedEvent(EVT_VOLUME_ATTACHED));
+            break;
+        }
+        case SHCNE_MEDIAREMOVED:
+        {
+            //printf("SHCNE_MEDIAREMOVED %S\n", sPath);
+            plater->GetEventHandler()->AddPendingEvent(VolumeDetachedEvent(EVT_VOLUME_DETACHED));
+            break;
+        }
+	    default:
+//          printf("Unknown\n");
+            break;
+	    }
+        return true;
+    });
 }
 #endif // WIN32
 
diff --git a/src/slic3r/GUI/MainFrame.cpp b/src/slic3r/GUI/MainFrame.cpp
index 60167bd17..69d20fd9f 100644
--- a/src/slic3r/GUI/MainFrame.cpp
+++ b/src/slic3r/GUI/MainFrame.cpp
@@ -33,6 +33,7 @@
 
 #ifdef _WIN32
 #include <dbt.h>
+#include <shlobj.h>
 #endif // _WIN32
 
 namespace Slic3r {
@@ -127,6 +128,30 @@ DPIFrame(NULL, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, wxDEFAULT_FRAME_S
 //		DEV_BROADCAST_HANDLE NotificationFilter = { 0 };
 //		NotificationFilter.dbch_size = sizeof(DEV_BROADCAST_HANDLE);
 //		NotificationFilter.dbch_devicetype = DBT_DEVTYP_HANDLE;
+
+		// Using Win32 Shell API to register for media insert / removal events.
+		LPITEMIDLIST ppidl;
+		if (SHGetSpecialFolderLocation(this->GetHWND(), CSIDL_DESKTOP, &ppidl) == NOERROR) {
+			SHChangeNotifyEntry shCNE;
+			shCNE.pidl       = ppidl;
+			shCNE.fRecursive = TRUE;
+			// Returns a positive integer registration identifier (ID).
+			// Returns zero if out of memory or in response to invalid parameters.
+			m_ulSHChangeNotifyRegister = SHChangeNotifyRegister(this->GetHWND(),		// Hwnd to receive notification
+				SHCNE_DISKEVENTS,														// Event types of interest (sources)
+				SHCNE_MEDIAINSERTED | SHCNE_MEDIAREMOVED,
+				//SHCNE_UPDATEITEM,														// Events of interest - use SHCNE_ALLEVENTS for all events
+				WM_USER_MEDIACHANGED,													// Notification message to be sent upon the event
+				1,																		// Number of entries in the pfsne array
+				&shCNE);																// Array of SHChangeNotifyEntry structures that 
+																						// contain the notifications. This array should 
+																						// always be set to one when calling SHChnageNotifyRegister
+																						// or SHChangeNotifyDeregister will not work properly.
+			assert(m_ulSHChangeNotifyRegister != 0);    // Shell notification failed
+		} else {
+			// Failed to get desktop location
+			assert(false); 
+		}
 #endif // _WIN32
 
         // propagate event
@@ -161,8 +186,14 @@ DPIFrame(NULL, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, wxDEFAULT_FRAME_S
 void MainFrame::shutdown()
 {
 #ifdef _WIN32
-	::UnregisterDeviceNotification(HDEVNOTIFY(m_hDeviceNotify));
-	m_hDeviceNotify = nullptr;
+	if (m_hDeviceNotify) {
+		::UnregisterDeviceNotification(HDEVNOTIFY(m_hDeviceNotify));
+		m_hDeviceNotify = nullptr;
+	}
+ 	if (m_ulSHChangeNotifyRegister) {
+        SHChangeNotifyDeregister(m_ulSHChangeNotifyRegister);
+        m_ulSHChangeNotifyRegister = 0;
+ 	}
 #endif // _WIN32
 
     if (m_plater)
diff --git a/src/slic3r/GUI/MainFrame.hpp b/src/slic3r/GUI/MainFrame.hpp
index 8c8b98090..6038e6d2f 100644
--- a/src/slic3r/GUI/MainFrame.hpp
+++ b/src/slic3r/GUI/MainFrame.hpp
@@ -144,6 +144,8 @@ public:
 
 #ifdef _WIN32
     void*				m_hDeviceNotify { nullptr };
+    uint32_t  			m_ulSHChangeNotifyRegister { 0 };
+	static constexpr int WM_USER_MEDIACHANGED { 0x7FFF }; // WM_USER from 0x0400 to 0x7FFF, picking the last one to not interfere with wxWidgets allocation
 #endif // _WIN32
 };
 
diff --git a/src/slic3r/GUI/RemovableDriveManager.cpp b/src/slic3r/GUI/RemovableDriveManager.cpp
index c0efa47fe..d67ac4a22 100644
--- a/src/slic3r/GUI/RemovableDriveManager.cpp
+++ b/src/slic3r/GUI/RemovableDriveManager.cpp
@@ -452,14 +452,8 @@ void RemovableDriveManager::thread_proc()
 		{
 			std::unique_lock<std::mutex> lck(m_thread_stop_mutex);
 #ifdef _WIN32
-			// Windows do not send an update on insert / eject of an SD card into an external SD card reader.
-			// Windows also do not send an update on software eject of a FLASH drive.
-			// We can likely use the Windows WMI API, but it will be quite time consuming to implement.
-			// https://www.codeproject.com/Articles/10539/Making-WMI-Queries-In-C
-			// https://docs.microsoft.com/en-us/windows/win32/wmisdk/wmi-start-page
-			// https://docs.microsoft.com/en-us/windows/win32/wmisdk/com-api-for-wmi
-			// https://docs.microsoft.com/en-us/windows/win32/wmisdk/example--receiving-event-notifications-through-wmi-
-			m_thread_stop_condition.wait_for(lck, std::chrono::seconds(2), [this]{ return m_stop || m_wakeup; });
+			// Reacting to updates by WM_DEVICECHANGE and WM_USER_MEDIACHANGED
+			m_thread_stop_condition.wait(lck, [this]{ return m_stop || m_wakeup; });
 #else
 			m_thread_stop_condition.wait_for(lck, std::chrono::seconds(2), [this]{ return m_stop; });
 #endif

From ec86d94f026cd304f2544fcf6990cf360f9db235 Mon Sep 17 00:00:00 2001
From: bubnikv <bubnikv@gmail.com>
Date: Fri, 27 Mar 2020 14:15:09 +0100
Subject: [PATCH 25/25] Workaround for the Prusa3D Fast (layer height 0.35mm)
 profile, which collides with the maximum allowed layer height at the Printer
 Extruder 0.25mm.

Works around "MMU2s and supports on prusaslicer 2.2.0 issue #3919"
---
 src/libslic3r/GCode/ToolOrdering.cpp | 67 +++++++++++++++++++++-------
 src/libslic3r/GCode/ToolOrdering.hpp |  2 +-
 2 files changed, 51 insertions(+), 18 deletions(-)

diff --git a/src/libslic3r/GCode/ToolOrdering.cpp b/src/libslic3r/GCode/ToolOrdering.cpp
index 9bdda3a4c..db398f06c 100644
--- a/src/libslic3r/GCode/ToolOrdering.cpp
+++ b/src/libslic3r/GCode/ToolOrdering.cpp
@@ -94,7 +94,7 @@ ToolOrdering::ToolOrdering(const PrintObject &object, unsigned int first_extrude
     // Reorder the extruders to minimize tool switches.
     this->reorder_extruders(first_extruder);
 
-    this->fill_wipe_tower_partitions(object.print()->config(), object.layers().front()->print_z - object.layers().front()->height);
+    this->fill_wipe_tower_partitions(object.print()->config(), object.layers().front()->print_z - object.layers().front()->height, object.config().layer_height);
 
     this->collect_extruder_statistics(prime_multi_material);
 }
@@ -107,6 +107,7 @@ ToolOrdering::ToolOrdering(const Print &print, unsigned int first_extruder, bool
 
     // Initialize the print layers for all objects and all layers.
     coordf_t object_bottom_z = 0.;
+    coordf_t max_layer_height = 0.;
     {
         std::vector<coordf_t> zs;
         for (auto object : print.objects()) {
@@ -122,6 +123,8 @@ ToolOrdering::ToolOrdering(const Print &print, unsigned int first_extruder, bool
                     object_bottom_z = layer->print_z - layer->height;
                     break;
                 }
+
+            max_layer_height = std::max(max_layer_height, object->config().layer_height.value);
         }
         this->initialize_layers(zs);
     }
@@ -144,7 +147,7 @@ ToolOrdering::ToolOrdering(const Print &print, unsigned int first_extruder, bool
     // Reorder the extruders to minimize tool switches.
     this->reorder_extruders(first_extruder);
 
-    this->fill_wipe_tower_partitions(print.config(), object_bottom_z);
+    this->fill_wipe_tower_partitions(print.config(), object_bottom_z, max_layer_height);
 
     this->collect_extruder_statistics(prime_multi_material);
 }
@@ -318,7 +321,7 @@ void ToolOrdering::reorder_extruders(unsigned int last_extruder_id)
         }    
 }
 
-void ToolOrdering::fill_wipe_tower_partitions(const PrintConfig &config, coordf_t object_bottom_z)
+void ToolOrdering::fill_wipe_tower_partitions(const PrintConfig &config, coordf_t object_bottom_z, coordf_t max_object_layer_height)
 {
     if (m_layer_tools.empty())
         return;
@@ -351,6 +354,10 @@ void ToolOrdering::fill_wipe_tower_partitions(const PrintConfig &config, coordf_
             mlh = 0.75 * config.nozzle_diameter.values[i];
         max_layer_height = std::min(max_layer_height, mlh);
     }
+    // The Prusa3D Fast (0.35mm layer height) print profile sets a higher layer height than what is normally allowed
+    // by the nozzle. This is a hack and it works by increasing extrusion width.
+    max_layer_height = std::max(max_layer_height, max_object_layer_height);
+
     for (size_t i = 0; i + 1 < m_layer_tools.size(); ++ i) {
         const LayerTools &lt      = m_layer_tools[i];
         const LayerTools &lt_next = m_layer_tools[i + 1];
@@ -393,21 +400,47 @@ void ToolOrdering::fill_wipe_tower_partitions(const PrintConfig &config, coordf_
     // and maybe other problems. We will therefore go through layer_tools and detect and fix this.
     // So, if there is a non-object layer starting with different extruder than the last one ended with (or containing more than one extruder),
     // we'll mark it with has_wipe tower.
-    for (unsigned int i=0; i+1<m_layer_tools.size(); ++i) {
-        LayerTools& lt = m_layer_tools[i];
-        LayerTools& lt_next = m_layer_tools[i+1];
-        if (lt.extruders.empty() || lt_next.extruders.empty())
-            break;
-        if (!lt_next.has_wipe_tower && (lt_next.extruders.front() != lt.extruders.back() || lt_next.extruders.size() > 1))
-            lt_next.has_wipe_tower = true;
-        // We should also check that the next wipe tower layer is no further than max_layer_height:
-        unsigned int j = i+1;
-        double last_wipe_tower_print_z = lt_next.print_z;
-        while (++j < m_layer_tools.size()-1 && !m_layer_tools[j].has_wipe_tower)
-            if (m_layer_tools[j+1].print_z - last_wipe_tower_print_z > max_layer_height) {
-                m_layer_tools[j].has_wipe_tower = true;
-                last_wipe_tower_print_z = m_layer_tools[j].print_z;
+    assert(! m_layer_tools.empty() && m_layer_tools.front().has_wipe_tower);
+    if (! m_layer_tools.empty() && m_layer_tools.front().has_wipe_tower) {
+        for (size_t i = 0; i + 1 < m_layer_tools.size();) {
+            const LayerTools &lt = m_layer_tools[i];
+            assert(lt.has_wipe_tower);
+            assert(! lt.extruders.empty());
+            // Find the next layer with wipe tower or mark a layer as such.
+            size_t j = i + 1;
+            for (; j < m_layer_tools.size() && ! m_layer_tools[j].has_wipe_tower; ++ j) {
+                LayerTools &lt_next = m_layer_tools[j];
+                if (lt_next.extruders.empty()) {
+                    //FIXME Vojtech: Lukasi, proc?
+                    j = m_layer_tools.size();
+                    break;
+                }
+                if (lt_next.extruders.front() != lt.extruders.back() || lt_next.extruders.size() > 1) {
+                    // Support only layer, soluble layers? Otherwise the layer should have been already marked as having wipe tower.
+                    assert(lt_next.has_support && ! lt_next.has_object);
+                    lt_next.has_wipe_tower = true;
+                    break;
+                }
             }
+            if (j == m_layer_tools.size())
+                // No wipe tower above layer i, therefore no need to add any wipe tower layer above i.
+                break;
+            // We should also check that the next wipe tower layer is no further than max_layer_height.
+            // This algorith may in theory create very thin wipe layer j if layer closely below j is marked as wipe tower.
+            // This may happen if printing with non-soluble break away supports.
+            // On the other side it should not hurt as there will be no wipe, just perimeter and sparse infill printed
+            // at that particular wipe tower layer without extruder change.
+            double last_wipe_tower_print_z = lt.print_z;
+            assert(m_layer_tools[j].has_wipe_tower);
+            for (size_t k = i + 1; k < j; ++k) {
+                assert(! m_layer_tools[k].has_wipe_tower);
+                if (m_layer_tools[k + 1].print_z - last_wipe_tower_print_z > max_layer_height + EPSILON) {
+                    m_layer_tools[k].has_wipe_tower = true;
+                    last_wipe_tower_print_z = m_layer_tools[k].print_z;
+                }
+            }
+            i = j;
+        }
     }
 
     // Calculate the wipe_tower_layer_height values.
diff --git a/src/libslic3r/GCode/ToolOrdering.hpp b/src/libslic3r/GCode/ToolOrdering.hpp
index a82db2d04..5fe27516d 100644
--- a/src/libslic3r/GCode/ToolOrdering.hpp
+++ b/src/libslic3r/GCode/ToolOrdering.hpp
@@ -166,7 +166,7 @@ private:
     void				initialize_layers(std::vector<coordf_t> &zs);
     void 				collect_extruders(const PrintObject &object, const std::vector<std::pair<double, unsigned int>> &per_layer_extruder_switches);
     void				reorder_extruders(unsigned int last_extruder_id);
-    void 				fill_wipe_tower_partitions(const PrintConfig &config, coordf_t object_bottom_z);
+    void 				fill_wipe_tower_partitions(const PrintConfig &config, coordf_t object_bottom_z, coordf_t max_layer_height);
     void 				collect_extruder_statistics(bool prime_multi_material);
 
     std::vector<LayerTools>    m_layer_tools;