diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp
index 3ea365b3c..720b9a1fa 100644
--- a/src/libslic3r/GCode.cpp
+++ b/src/libslic3r/GCode.cpp
@@ -3131,6 +3131,10 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description,
             m_last_mm3_per_mm = path.mm3_per_mm;
             sprintf(buf, ";%s%f\n", GCodeAnalyzer::Mm3_Per_Mm_Tag.c_str(), m_last_mm3_per_mm);
             gcode += buf;
+#if ENABLE_GCODE_VIEWER
+            sprintf(buf, ";%s%f\n", GCodeProcessor::Mm3_Per_Mm_Tag.c_str(), m_last_mm3_per_mm);
+            gcode += buf;
+#endif // ENABLE_GCODE_VIEWER
         }
 
         if (last_was_wipe_tower || (m_last_width != path.width))
diff --git a/src/libslic3r/GCode/Analyzer.cpp b/src/libslic3r/GCode/Analyzer.cpp
index b283d70a9..c7b67647f 100644
--- a/src/libslic3r/GCode/Analyzer.cpp
+++ b/src/libslic3r/GCode/Analyzer.cpp
@@ -956,6 +956,8 @@ void GCodeAnalyzer::_store_move(GCodeAnalyzer::GCodeMove::EType type)
         g_debug_output << ", " << std::to_string(_get_feedrate());
         g_debug_output << ", " << std::to_string(_get_width());
         g_debug_output << ", " << std::to_string(_get_height());
+        g_debug_output << ", " << std::to_string(_get_mm3_per_mm());
+        g_debug_output << ", " << std::to_string(_get_fan_speed());
         g_debug_output << "\n";
     }
 #endif // ENABLE_GCODE_VIEWER_DEBUG_OUTPUT
diff --git a/src/libslic3r/GCode/GCodeProcessor.cpp b/src/libslic3r/GCode/GCodeProcessor.cpp
index 01ac11c17..0f42c6796 100644
--- a/src/libslic3r/GCode/GCodeProcessor.cpp
+++ b/src/libslic3r/GCode/GCodeProcessor.cpp
@@ -18,6 +18,7 @@ namespace Slic3r {
 const std::string GCodeProcessor::Extrusion_Role_Tag = "_PROCESSOR_EXTRUSION_ROLE:";
 const std::string GCodeProcessor::Width_Tag          = "_PROCESSOR_WIDTH:";
 const std::string GCodeProcessor::Height_Tag         = "_PROCESSOR_HEIGHT:";
+const std::string GCodeProcessor::Mm3_Per_Mm_Tag     = "_PROCESSOR_MM3_PER_MM:";
 
 void GCodeProcessor::apply_config(const PrintConfig& config)
 {
@@ -48,6 +49,9 @@ void GCodeProcessor::reset()
     m_feedrate = 0.0f;
     m_width = 0.0f;
     m_height = 0.0f;
+    m_mm3_per_mm = 0.0f;
+    m_fan_speed = 0.0f;
+
     m_extrusion_role = erNone;
     m_extruder_id = 0;
 
@@ -79,14 +83,14 @@ void GCodeProcessor::process_gcode_line(const GCodeReader::GCodeLine& line)
             {
                 switch (::atoi(&cmd[1]))
                 {
-                // Move
-                case 1: { process_G1(line); break; }
-                // Set to Absolute Positioning
-                case 90: { processG90(line); break; }
-                // Set to Relative Positioning
-                case 91: { processG91(line); break; }
-                // Set Position
-                case 92: { processG92(line); break; }
+                case 1:  { process_G1(line); break; }  // Move
+                case 10: { process_G10(line); break; } // Retract
+                case 11: { process_G11(line); break; } // Unretract
+                case 22: { process_G22(line); break; } // Firmware controlled retract
+                case 23: { process_G23(line); break; } // Firmware controlled unretract
+                case 90: { process_G90(line); break; } // Set to Absolute Positioning
+                case 91: { process_G91(line); break; } // Set to Relative Positioning
+                case 92: { process_G92(line); break; } // Set Position
                 default: { break; }
                 }
                 break;
@@ -95,16 +99,17 @@ void GCodeProcessor::process_gcode_line(const GCodeReader::GCodeLine& line)
             {
                 switch (::atoi(&cmd[1]))
                 {
-                // Set extruder to absolute mode
-                case 82: { processM82(line); break; }
-                // Set extruder to relative mode
-                case 83: { processM83(line); break; }
+                case 82:  { process_M82(line); break; }  // Set extruder to absolute mode
+                case 83:  { process_M83(line); break; }  // Set extruder to relative mode
+                case 106: { process_M106(line); break; } // Set fan speed
+                case 107: { process_M107(line); break; } // Disable fan
                 default: { break; }
                 }
                 break;
             }
         case 'T':
             {
+                process_T(line); // Select Tool
                 break;
             }
         default: { break; }
@@ -125,12 +130,19 @@ void GCodeProcessor::process_tags(const std::string& comment)
     size_t pos = comment.find(Extrusion_Role_Tag);
     if (pos != comment.npos)
     {
-        int role = std::stoi(comment.substr(pos + Extrusion_Role_Tag.length()));
-        if (is_valid_extrusion_role(role))
-            m_extrusion_role = static_cast<ExtrusionRole>(role);
-        else
+        try
         {
-            // todo: show some error ?
+            int role = std::stoi(comment.substr(pos + Extrusion_Role_Tag.length()));
+            if (is_valid_extrusion_role(role))
+                m_extrusion_role = static_cast<ExtrusionRole>(role);
+            else
+            {
+                // todo: show some error ?
+            }
+        }
+        catch (...)
+        {
+            BOOST_LOG_TRIVIAL(error) << "GCodeProcessor encountered an invalid value for Extrusion Role (" << comment << ").";
         }
 
         return;
@@ -140,7 +152,14 @@ void GCodeProcessor::process_tags(const std::string& comment)
     pos = comment.find(Width_Tag);
     if (pos != comment.npos)
     {
-        m_width = std::stof(comment.substr(pos + Width_Tag.length()));
+        try
+        {
+            m_width = std::stof(comment.substr(pos + Width_Tag.length()));
+        }
+        catch (...)
+        {
+            BOOST_LOG_TRIVIAL(error) << "GCodeProcessor encountered an invalid value for Width (" << comment << ").";
+        }
         return;
     }
 
@@ -148,7 +167,29 @@ void GCodeProcessor::process_tags(const std::string& comment)
     pos = comment.find(Height_Tag);
     if (pos != comment.npos)
     {
-        m_height = std::stof(comment.substr(pos + Height_Tag.length()));
+        try
+        {
+            m_height = std::stof(comment.substr(pos + Height_Tag.length()));
+        }
+        catch (...)
+        {
+            BOOST_LOG_TRIVIAL(error) << "GCodeProcessor encountered an invalid value for Height (" << comment << ").";
+        }
+        return;
+    }
+
+    // mm3 per mm tag
+    pos = comment.find(Mm3_Per_Mm_Tag);
+    if (pos != comment.npos)
+    {
+        try
+        {
+            m_mm3_per_mm = std::stof(comment.substr(pos + Mm3_Per_Mm_Tag.length()));
+        }
+        catch (...)
+        {
+            BOOST_LOG_TRIVIAL(error) << "GCodeProcessor encountered an invalid value for Mm3_Per_Mm (" << comment << ").";
+        }
         return;
     }
 }
@@ -224,17 +265,41 @@ void GCodeProcessor::process_G1(const GCodeReader::GCodeLine& line)
     store_move_vertex(move_type(delta_pos));
 }
 
-void GCodeProcessor::processG90(const GCodeReader::GCodeLine& line)
+void GCodeProcessor::process_G10(const GCodeReader::GCodeLine& line)
+{
+    // stores retract move
+    store_move_vertex(EMoveType::Retract);
+}
+
+void GCodeProcessor::process_G11(const GCodeReader::GCodeLine& line)
+{
+    // stores unretract move
+    store_move_vertex(EMoveType::Unretract);
+}
+
+void GCodeProcessor::process_G22(const GCodeReader::GCodeLine& line)
+{
+    // stores retract move
+    store_move_vertex(EMoveType::Retract);
+}
+
+void GCodeProcessor::process_G23(const GCodeReader::GCodeLine& line)
+{
+    // stores unretract move
+    store_move_vertex(EMoveType::Unretract);
+}
+
+void GCodeProcessor::process_G90(const GCodeReader::GCodeLine& line)
 {
     m_global_positioning_type = EPositioningType::Absolute;
 }
 
-void GCodeProcessor::processG91(const GCodeReader::GCodeLine& line)
+void GCodeProcessor::process_G91(const GCodeReader::GCodeLine& line)
 {
     m_global_positioning_type = EPositioningType::Relative;
 }
 
-void GCodeProcessor::processG92(const GCodeReader::GCodeLine& line)
+void GCodeProcessor::process_G92(const GCodeReader::GCodeLine& line)
 {
     float lengthsScaleFactor = (m_units == EUnits::Inches) ? INCHES_TO_MM : 1.0f;
     bool anyFound = false;
@@ -276,36 +341,61 @@ void GCodeProcessor::processG92(const GCodeReader::GCodeLine& line)
     }
 }
 
-void GCodeProcessor::processM82(const GCodeReader::GCodeLine& line)
+void GCodeProcessor::process_M82(const GCodeReader::GCodeLine& line)
 {
     m_e_local_positioning_type = EPositioningType::Absolute;
 }
 
-void GCodeProcessor::processM83(const GCodeReader::GCodeLine& line)
+void GCodeProcessor::process_M83(const GCodeReader::GCodeLine& line)
 {
     m_e_local_positioning_type = EPositioningType::Relative;
 }
 
-void GCodeProcessor::processT(const GCodeReader::GCodeLine& line)
+void GCodeProcessor::process_M106(const GCodeReader::GCodeLine& line)
+{
+    if (!line.has('P'))
+    {
+        // The absence of P means the print cooling fan, so ignore anything else.
+        float new_fan_speed;
+        if (line.has_value('S', new_fan_speed))
+            m_fan_speed = (100.0f / 255.0f) * new_fan_speed;
+        else
+            m_fan_speed = 100.0f;
+    }
+}
+
+void GCodeProcessor::process_M107(const GCodeReader::GCodeLine& line)
+{
+    m_fan_speed = 0.0f;
+}
+
+void GCodeProcessor::process_T(const GCodeReader::GCodeLine& line)
 {
     const std::string& cmd = line.cmd();
     if (cmd.length() > 1)
     {
-        unsigned int id = (unsigned int)std::stoi(cmd.substr(1));
-        if (m_extruder_id != id)
+        try
         {
-            unsigned int extruders_count = (unsigned int)m_extruder_offsets.size();
-            if (id >= extruders_count)
-                BOOST_LOG_TRIVIAL(error) << "GCodeProcessor encountered an invalid toolchange, maybe from a custom gcode.";
-            else
+            unsigned int id = (unsigned int)std::stoi(cmd.substr(1));
+            if (m_extruder_id != id)
             {
-                m_extruder_id = id;
+                unsigned int extruders_count = (unsigned int)m_extruder_offsets.size();
+                if (id >= extruders_count)
+                    BOOST_LOG_TRIVIAL(error) << "GCodeProcessor encountered an invalid toolchange, maybe from a custom gcode.";
+                else
+                {
+                    m_extruder_id = id;
 //                if (_get_cp_color_id() != INT_MAX) <<<<<<<<<<<<<<<<<<< TODO
 //                    _set_cp_color_id(m_extruder_color[id]);
-            }
+                }
 
-            // store tool change move
-            store_move_vertex(EMoveType::Tool_change);
+                // store tool change move
+                store_move_vertex(EMoveType::Tool_change);
+            }
+        }
+        catch (...)
+        {
+            BOOST_LOG_TRIVIAL(error) << "GCodeProcessor encountered an invalid toolchange (" << cmd << ").";
         }
     }
 }
@@ -319,6 +409,8 @@ void GCodeProcessor::store_move_vertex(EMoveType type)
     vertex.feedrate = m_feedrate;
     vertex.width = m_width;
     vertex.height = m_height;
+    vertex.mm3_per_mm = m_mm3_per_mm;
+    vertex.fan_speed = m_fan_speed;
     vertex.extruder_id = m_extruder_id;
     m_result.moves.emplace_back(vertex);
 }
diff --git a/src/libslic3r/GCode/GCodeProcessor.hpp b/src/libslic3r/GCode/GCodeProcessor.hpp
index 0fa8187fd..66036728d 100644
--- a/src/libslic3r/GCode/GCodeProcessor.hpp
+++ b/src/libslic3r/GCode/GCodeProcessor.hpp
@@ -16,6 +16,7 @@ namespace Slic3r {
         static const std::string Extrusion_Role_Tag;
         static const std::string Width_Tag;
         static const std::string Height_Tag;
+        static const std::string Mm3_Per_Mm_Tag;
 
     private:
         using AxisCoords = std::array<float, 4>;
@@ -52,6 +53,8 @@ namespace Slic3r {
             float feedrate{ 0.0f }; // mm/s
             float width{ 0.0f }; // mm
             float height{ 0.0f }; // mm
+            float mm3_per_mm{ 0.0f };
+            float fan_speed{ 0.0f }; // percentage
             unsigned int extruder_id{ 0 };
 
             std::string to_string() const
@@ -63,6 +66,8 @@ namespace Slic3r {
                 str += ", " + std::to_string(feedrate);
                 str += ", " + std::to_string(width);
                 str += ", " + std::to_string(height);
+                str += ", " + std::to_string(mm3_per_mm);
+                str += ", " + std::to_string(fan_speed);
                 return str;
             }
         };
@@ -85,9 +90,11 @@ namespace Slic3r {
         AxisCoords m_end_position;   // mm
         AxisCoords m_origin;         // mm
 
-        float m_feedrate; // mm/s
-        float m_width;    // mm
-        float m_height;   // mm
+        float m_feedrate;  // mm/s
+        float m_width;     // mm
+        float m_height;    // mm
+        float m_mm3_per_mm;
+        float m_fan_speed; // percentage
         ExtrusionRole m_extrusion_role;
         unsigned int m_extruder_id;
 
@@ -103,7 +110,6 @@ namespace Slic3r {
         Result&& extract_result() { return std::move(m_result); }
 
         // Process the gcode contained in the file with the given filename
-        // Return false if any error occourred
         void process_file(const std::string& filename);
 
     private:
@@ -115,23 +121,41 @@ namespace Slic3r {
         // Move
         void process_G1(const GCodeReader::GCodeLine& line);
 
+        // Retract
+        void process_G10(const GCodeReader::GCodeLine& line);
+
+        // Unretract
+        void process_G11(const GCodeReader::GCodeLine& line);
+
+        // Firmware controlled Retract
+        void process_G22(const GCodeReader::GCodeLine& line);
+
+        // Firmware controlled Unretract
+        void process_G23(const GCodeReader::GCodeLine& line);
+
         // Set to Absolute Positioning
-        void processG90(const GCodeReader::GCodeLine& line);
+        void process_G90(const GCodeReader::GCodeLine& line);
 
         // Set to Relative Positioning
-        void processG91(const GCodeReader::GCodeLine& line);
+        void process_G91(const GCodeReader::GCodeLine& line);
 
         // Set Position
-        void processG92(const GCodeReader::GCodeLine& line);
+        void process_G92(const GCodeReader::GCodeLine& line);
 
         // Set extruder to absolute mode
-        void processM82(const GCodeReader::GCodeLine& line);
+        void process_M82(const GCodeReader::GCodeLine& line);
 
         // Set extruder to relative mode
-        void processM83(const GCodeReader::GCodeLine& line);
+        void process_M83(const GCodeReader::GCodeLine& line);
+
+        // Set fan speed
+        void process_M106(const GCodeReader::GCodeLine& line);
+
+        // Disable fan
+        void process_M107(const GCodeReader::GCodeLine& line);
 
         // Processes T line (Select Tool)
-        void processT(const GCodeReader::GCodeLine& line);
+        void process_T(const GCodeReader::GCodeLine& line);
 
         void store_move_vertex(EMoveType type);
    };
diff --git a/src/libslic3r/GCode/WipeTower.cpp b/src/libslic3r/GCode/WipeTower.cpp
index 339012d0b..d5d060f77 100644
--- a/src/libslic3r/GCode/WipeTower.cpp
+++ b/src/libslic3r/GCode/WipeTower.cpp
@@ -90,6 +90,10 @@ public:
             char buf[64];
             sprintf(buf, ";%s%f\n", GCodeAnalyzer::Mm3_Per_Mm_Tag.c_str(), mm3_per_mm);
             m_gcode += buf;
+#if ENABLE_GCODE_VIEWER
+            sprintf(buf, ";%s%f\n", GCodeProcessor::Mm3_Per_Mm_Tag.c_str(), mm3_per_mm);
+            m_gcode += buf;
+#endif // ENABLE_GCODE_VIEWER
             return *this;
     }