From fd4c28ed91c3d095c6ee296b55904b22c3e51759 Mon Sep 17 00:00:00 2001
From: bubnikv <bubnikv@gmail.com>
Date: Mon, 7 Sep 2020 15:55:03 +0200
Subject: [PATCH 01/15] WIP: G-code viewer menu, refactoring of starting a
 background process.

---
 src/slic3r/CMakeLists.txt    |  2 ++
 src/slic3r/GUI/MainFrame.cpp | 25 ++++++-------------------
 src/slic3r/Utils/Thread.hpp  |  6 +++---
 3 files changed, 11 insertions(+), 22 deletions(-)

diff --git a/src/slic3r/CMakeLists.txt b/src/slic3r/CMakeLists.txt
index 5681ed66d..1c3007810 100644
--- a/src/slic3r/CMakeLists.txt
+++ b/src/slic3r/CMakeLists.txt
@@ -195,6 +195,8 @@ set(SLIC3R_GUI_SOURCES
     Utils/Bonjour.hpp
     Utils/PresetUpdater.cpp
     Utils/PresetUpdater.hpp
+    Utils/Process.cpp
+    Utils/Process.hpp
     Utils/Profile.hpp
     Utils/UndoRedo.cpp
     Utils/UndoRedo.hpp
diff --git a/src/slic3r/GUI/MainFrame.cpp b/src/slic3r/GUI/MainFrame.cpp
index f6fd939e2..f4d7f03ec 100644
--- a/src/slic3r/GUI/MainFrame.cpp
+++ b/src/slic3r/GUI/MainFrame.cpp
@@ -9,7 +9,6 @@
 #include <wx/tooltip.h>
 //#include <wx/glcanvas.h>
 #include <wx/filename.h>
-#include <wx/stdpaths.h>
 #include <wx/debug.h>
 
 #include <boost/algorithm/string/predicate.hpp>
@@ -31,6 +30,7 @@
 #include "I18N.hpp"
 #include "GLCanvas3D.hpp"
 #include "Plater.hpp"
+#include "../Utils/Process.hpp"
 
 #include <fstream>
 #include "GUI_App.hpp"
@@ -40,12 +40,6 @@
 #include <shlobj.h>
 #endif // _WIN32
 
-// For starting another PrusaSlicer instance on OSX.
-// Fails to compile on Windows on the build server.
-#ifdef __APPLE__
-    #include <boost/process/spawn.hpp>
-#endif
-
 namespace Slic3r {
 namespace GUI {
 
@@ -1054,8 +1048,8 @@ void MainFrame::init_menubar()
         append_menu_item(fileMenu, wxID_ANY, _L("&Repair STL file") + dots, _L("Automatically repair an STL file"),
             [this](wxCommandEvent&) { repair_stl(); }, "wrench", nullptr,
             [this]() { return true; }, this);
-#if ENABLE_GCODE_VIEWER
         fileMenu->AppendSeparator();
+#if ENABLE_GCODE_VIEWER
         append_menu_item(fileMenu, wxID_ANY, _L("&G-code preview"), _L("Switch to G-code preview mode"),
             [this](wxCommandEvent&) {
                 if (m_plater->model().objects.empty() ||
@@ -1064,6 +1058,8 @@ void MainFrame::init_menubar()
                     set_mode(EMode::GCodeViewer);
             }, "", nullptr);
 #endif // ENABLE_GCODE_VIEWER
+        append_menu_item(fileMenu, wxID_ANY, _L("&G-code preview") + dots, _L("Open G-code viewer"),
+            [this](wxCommandEvent&) { start_new_gcodeviewer_open_file(this); }, "", nullptr);
         fileMenu->AppendSeparator();
         append_menu_item(fileMenu, wxID_EXIT, _L("&Quit"), wxString::Format(_L("Quit %s"), SLIC3R_APP_NAME),
             [this](wxCommandEvent&) { Close(false); });
@@ -1180,20 +1176,11 @@ void MainFrame::init_menubar()
 
         windowMenu->AppendSeparator();
         append_menu_item(windowMenu, wxID_ANY, _L("Print &Host Upload Queue") + "\tCtrl+J", _L("Display the Print Host Upload Queue window"),
-            [this](wxCommandEvent&) { m_printhost_queue_dlg->Show(); }, "upload_queue", nullptr,
-            [this]() {return true; }, this);
+            [this](wxCommandEvent&) { m_printhost_queue_dlg->Show(); }, "upload_queue", nullptr, [this]() {return true; }, this);
         
         windowMenu->AppendSeparator();
         append_menu_item(windowMenu, wxID_ANY, _(L("Open new instance")) + "\tCtrl+I", _(L("Open a new PrusaSlicer instance")),
-                         [this](wxCommandEvent&) {
-                             wxString path = wxStandardPaths::Get().GetExecutablePath();
-#ifdef __APPLE__
-                             boost::process::spawn((const char*)path.c_str());
-#else
-                             wxExecute(wxStandardPaths::Get().GetExecutablePath(), wxEXEC_ASYNC | wxEXEC_HIDE_CONSOLE | wxEXEC_MAKE_GROUP_LEADER);
-#endif
-                         }, "upload_queue", nullptr,
-                         [this]() {return true; }, this);
+			[this](wxCommandEvent&) { start_new_slicer(); }, "", nullptr);
     }
 
     // View menu
diff --git a/src/slic3r/Utils/Thread.hpp b/src/slic3r/Utils/Thread.hpp
index e9c76d2ab..194971c9e 100644
--- a/src/slic3r/Utils/Thread.hpp
+++ b/src/slic3r/Utils/Thread.hpp
@@ -1,5 +1,5 @@
-#ifndef THREAD_HPP
-#define THREAD_HPP
+#ifndef GUI_THREAD_HPP
+#define GUI_THREAD_HPP
 
 #include <utility>
 #include <boost/thread.hpp>
@@ -25,4 +25,4 @@ template<class Fn> inline boost::thread create_thread(Fn &&fn)
 
 }
 
-#endif // THREAD_HPP
+#endif // GUI_THREAD_HPP

From b0bedf33c0d145f2f6494c6e540668a1d49e5e68 Mon Sep 17 00:00:00 2001
From: bubnikv <bubnikv@gmail.com>
Date: Mon, 7 Sep 2020 15:55:03 +0200
Subject: [PATCH 02/15] WIP: G-code viewer menu, refactoring of starting a
 background process.

---
 src/slic3r/CMakeLists.txt    |   2 +
 src/slic3r/GUI/MainFrame.cpp |  25 ++-------
 src/slic3r/Utils/Process.cpp | 105 +++++++++++++++++++++++++++++++++++
 src/slic3r/Utils/Process.hpp |  19 +++++++
 src/slic3r/Utils/Thread.hpp  |   6 +-
 5 files changed, 135 insertions(+), 22 deletions(-)
 create mode 100644 src/slic3r/Utils/Process.cpp
 create mode 100644 src/slic3r/Utils/Process.hpp

diff --git a/src/slic3r/CMakeLists.txt b/src/slic3r/CMakeLists.txt
index 5681ed66d..1c3007810 100644
--- a/src/slic3r/CMakeLists.txt
+++ b/src/slic3r/CMakeLists.txt
@@ -195,6 +195,8 @@ set(SLIC3R_GUI_SOURCES
     Utils/Bonjour.hpp
     Utils/PresetUpdater.cpp
     Utils/PresetUpdater.hpp
+    Utils/Process.cpp
+    Utils/Process.hpp
     Utils/Profile.hpp
     Utils/UndoRedo.cpp
     Utils/UndoRedo.hpp
diff --git a/src/slic3r/GUI/MainFrame.cpp b/src/slic3r/GUI/MainFrame.cpp
index f6fd939e2..f4d7f03ec 100644
--- a/src/slic3r/GUI/MainFrame.cpp
+++ b/src/slic3r/GUI/MainFrame.cpp
@@ -9,7 +9,6 @@
 #include <wx/tooltip.h>
 //#include <wx/glcanvas.h>
 #include <wx/filename.h>
-#include <wx/stdpaths.h>
 #include <wx/debug.h>
 
 #include <boost/algorithm/string/predicate.hpp>
@@ -31,6 +30,7 @@
 #include "I18N.hpp"
 #include "GLCanvas3D.hpp"
 #include "Plater.hpp"
+#include "../Utils/Process.hpp"
 
 #include <fstream>
 #include "GUI_App.hpp"
@@ -40,12 +40,6 @@
 #include <shlobj.h>
 #endif // _WIN32
 
-// For starting another PrusaSlicer instance on OSX.
-// Fails to compile on Windows on the build server.
-#ifdef __APPLE__
-    #include <boost/process/spawn.hpp>
-#endif
-
 namespace Slic3r {
 namespace GUI {
 
@@ -1054,8 +1048,8 @@ void MainFrame::init_menubar()
         append_menu_item(fileMenu, wxID_ANY, _L("&Repair STL file") + dots, _L("Automatically repair an STL file"),
             [this](wxCommandEvent&) { repair_stl(); }, "wrench", nullptr,
             [this]() { return true; }, this);
-#if ENABLE_GCODE_VIEWER
         fileMenu->AppendSeparator();
+#if ENABLE_GCODE_VIEWER
         append_menu_item(fileMenu, wxID_ANY, _L("&G-code preview"), _L("Switch to G-code preview mode"),
             [this](wxCommandEvent&) {
                 if (m_plater->model().objects.empty() ||
@@ -1064,6 +1058,8 @@ void MainFrame::init_menubar()
                     set_mode(EMode::GCodeViewer);
             }, "", nullptr);
 #endif // ENABLE_GCODE_VIEWER
+        append_menu_item(fileMenu, wxID_ANY, _L("&G-code preview") + dots, _L("Open G-code viewer"),
+            [this](wxCommandEvent&) { start_new_gcodeviewer_open_file(this); }, "", nullptr);
         fileMenu->AppendSeparator();
         append_menu_item(fileMenu, wxID_EXIT, _L("&Quit"), wxString::Format(_L("Quit %s"), SLIC3R_APP_NAME),
             [this](wxCommandEvent&) { Close(false); });
@@ -1180,20 +1176,11 @@ void MainFrame::init_menubar()
 
         windowMenu->AppendSeparator();
         append_menu_item(windowMenu, wxID_ANY, _L("Print &Host Upload Queue") + "\tCtrl+J", _L("Display the Print Host Upload Queue window"),
-            [this](wxCommandEvent&) { m_printhost_queue_dlg->Show(); }, "upload_queue", nullptr,
-            [this]() {return true; }, this);
+            [this](wxCommandEvent&) { m_printhost_queue_dlg->Show(); }, "upload_queue", nullptr, [this]() {return true; }, this);
         
         windowMenu->AppendSeparator();
         append_menu_item(windowMenu, wxID_ANY, _(L("Open new instance")) + "\tCtrl+I", _(L("Open a new PrusaSlicer instance")),
-                         [this](wxCommandEvent&) {
-                             wxString path = wxStandardPaths::Get().GetExecutablePath();
-#ifdef __APPLE__
-                             boost::process::spawn((const char*)path.c_str());
-#else
-                             wxExecute(wxStandardPaths::Get().GetExecutablePath(), wxEXEC_ASYNC | wxEXEC_HIDE_CONSOLE | wxEXEC_MAKE_GROUP_LEADER);
-#endif
-                         }, "upload_queue", nullptr,
-                         [this]() {return true; }, this);
+			[this](wxCommandEvent&) { start_new_slicer(); }, "", nullptr);
     }
 
     // View menu
diff --git a/src/slic3r/Utils/Process.cpp b/src/slic3r/Utils/Process.cpp
new file mode 100644
index 000000000..17e3d6fed
--- /dev/null
+++ b/src/slic3r/Utils/Process.cpp
@@ -0,0 +1,105 @@
+#include "Process.hpp"
+
+#include <libslic3r/AppConfig.hpp>
+
+#include "../GUI/GUI.hpp"
+// for file_wildcards()
+#include "../GUI/GUI_App.hpp"
+// localization
+#include "../GUI/I18N.hpp"
+
+// For starting another PrusaSlicer instance on OSX.
+// Fails to compile on Windows on the build server.
+#ifdef __APPLE__
+    #include <boost/process/spawn.hpp>
+#endif
+
+#include <wx/stdpaths.h>
+
+namespace Slic3r {
+namespace GUI {
+
+enum class NewSlicerInstanceType {
+	Slicer,
+	GCodeViewer
+};
+
+// Start a new Slicer process instance either in a Slicer mode or in a G-code mode.
+// Optionally load a 3MF, STL or a G-code on start.
+static void start_new_slicer_or_gcodeviewer(const NewSlicerInstanceType instance_type, const wxString *path_to_open)
+{
+#ifdef _WIN32
+     wxString path;
+     wxFileName::SplitPath(wxStandardPaths::Get().GetExecutablePath(), &path, nullptr, nullptr, wxPATH_NATIVE);
+	 path += "\\";
+	 path += (instance_type == NewSlicerInstanceType::Slicer) ? "prusa-slicer.exe" : "prusa-gcodeviewer.exe";
+     std::vector<const wchar_t*> args;
+     args.reserve(3);
+     args.emplace_back(path.wc_str());
+     if (path_to_open != nullptr)
+     	args.emplace_back(path_to_open->wc_str());
+     args.emplace_back(nullptr);
+     wxExecute(const_cast<wchar_t**>(args.data()), wxEXEC_ASYNC | wxEXEC_HIDE_CONSOLE | wxEXEC_MAKE_GROUP_LEADER);
+#else 
+	// Own executable path.
+    boost::filesystem::path own_path = into_path(wxStandardPaths::Get().GetExecutablePath());
+	#if defined(__APPLE__)
+	{
+		own_path /=	(instance_type == NewSlicerInstanceType::Slicer) ? "PrusaSlicer" : "PrusaGCodeViewer";
+		// On Apple the wxExecute fails, thus we use boost::process instead.
+	    path_to_open ? boost::process::spawn(path.string(), into_u8(*path_to_open)) : boost::process::spawn(path.string());
+	}
+	#else // Linux or Unix
+	{
+		std::vector<const char*> args;
+	    args.reserve(3);
+		#ifdef(__linux)
+		static const char *gcodeviewer_param = "--gcodeviewer";
+	    {
+			// If executed by an AppImage, start the AppImage, not the main process.
+			// see https://docs.appimage.org/packaging-guide/environment-variables.html#id2
+			const char *appimage_binary = std::getenv("APPIMAGE");
+			if (appimage_binary) {
+				args.emplace_back(appimage_binary);
+				if (instance_type == NewSlicerInstanceType::GCodeViewer)
+					args.emplace_back(gcodeviewer_param);
+				if ()
+			}
+		}
+		#endif // __linux
+	    std::string to_open;
+	    if (path_to_open) {
+	    	to_open = into_u8(*path_to_open);
+	    	args.emplace_back(to_open.c_str());
+	    }
+	    args.emplace_back(nullptr);
+	    wxExecute(const_cast<char**>(&args.data()), wxEXEC_ASYNC | wxEXEC_HIDE_CONSOLE | wxEXEC_MAKE_GROUP_LEADER);
+	}
+	#endif // Linux or Unix
+#endif // Win32
+}
+
+void start_new_slicer(const wxString *path_to_open)
+{
+	start_new_slicer_or_gcodeviewer(NewSlicerInstanceType::Slicer, path_to_open);
+}
+
+void start_new_gcodeviewer(const wxString *path_to_open)
+{
+	start_new_slicer_or_gcodeviewer(NewSlicerInstanceType::GCodeViewer, path_to_open);
+}
+
+void start_new_gcodeviewer_open_file(wxWindow *parent)
+{
+    wxFileDialog dialog(parent ? parent : wxGetApp().GetTopWindow(),
+        _L("Open G-code file:"),
+        from_u8(wxGetApp().app_config->get_last_dir()), wxString(),
+        file_wildcards(FT_GCODE), wxFD_OPEN | wxFD_FILE_MUST_EXIST);
+    if (dialog.ShowModal() == wxID_OK) {
+        wxString path = dialog.GetPath();
+		start_new_gcodeviewer(&path);
+    }
+}
+
+} // namespace GUI
+} // namespace Slic3r
diff --git a/src/slic3r/Utils/Process.hpp b/src/slic3r/Utils/Process.hpp
new file mode 100644
index 000000000..c6acaa643
--- /dev/null
+++ b/src/slic3r/Utils/Process.hpp
@@ -0,0 +1,19 @@
+#ifndef GUI_PROCESS_HPP
+#define GUI_PROCESS_HPP
+
+class wxWindow;
+
+namespace Slic3r {
+namespace GUI {
+
+// Start a new slicer instance, optionally with a file to open.
+void start_new_slicer(const wxString *path_to_open = nullptr);
+// Start a new G-code viewer instance, optionally with a file to open.
+void start_new_gcodeviewer(const wxString *path_to_open = nullptr);
+// Open a file dialog, ask the user to select a new G-code to open, start a new G-code viewer.
+void start_new_gcodeviewer_open_file(wxWindow *parent = nullptr);
+
+} // namespace GUI
+} // namespace Slic3r
+
+#endif // GUI_PROCESS_HPP
diff --git a/src/slic3r/Utils/Thread.hpp b/src/slic3r/Utils/Thread.hpp
index e9c76d2ab..194971c9e 100644
--- a/src/slic3r/Utils/Thread.hpp
+++ b/src/slic3r/Utils/Thread.hpp
@@ -1,5 +1,5 @@
-#ifndef THREAD_HPP
-#define THREAD_HPP
+#ifndef GUI_THREAD_HPP
+#define GUI_THREAD_HPP
 
 #include <utility>
 #include <boost/thread.hpp>
@@ -25,4 +25,4 @@ template<class Fn> inline boost::thread create_thread(Fn &&fn)
 
 }
 
-#endif // THREAD_HPP
+#endif // GUI_THREAD_HPP

From 9473ae8fe2fcac9394f85cb3267d8acf62540906 Mon Sep 17 00:00:00 2001
From: Vojtech Bubnik <bubnikv@gmail.com>
Date: Mon, 7 Sep 2020 16:56:22 +0200
Subject: [PATCH 03/15] Fix of previous commit, added symlinks to gcodeviewer
 on Linux & OSX

---
 src/CMakeLists.txt           | 29 ++++++++++++++++++++---------
 src/slic3r/Utils/Process.cpp | 11 ++++++++---
 2 files changed, 28 insertions(+), 12 deletions(-)

diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 0b0b3c0ee..8b9462cb2 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -209,20 +209,31 @@ if (WIN32)
     add_custom_target(PrusaSlicerDllsCopy ALL DEPENDS PrusaSlicer)
     prusaslicer_copy_dlls(PrusaSlicerDllsCopy)
     
-elseif (XCODE)
-    # Because of Debug/Release/etc. configurations (similar to MSVC) the slic3r binary is located in an extra level
-    add_custom_command(TARGET PrusaSlicer POST_BUILD
-        COMMAND ln -sfn "${SLIC3R_RESOURCES_DIR}" "${CMAKE_CURRENT_BINARY_DIR}/resources"
-        COMMENT "Symlinking the resources directory into the build tree"
-        VERBATIM
-    )
 else ()
+    if (XCODE)
+        add_custom_command(TARGET PrusaSlicer POST_BUILD
+            COMMAND ln -sf "${CMAKE_CURRENT_BINARY_DIR}/PrusaSlicer" "${CMAKE_CURRENT_BINARY_DIR}/prusa-slicer"
+            COMMAND ln -sf "${CMAKE_CURRENT_BINARY_DIR}/PrusaSlicer" "${CMAKE_CURRENT_BINARY_DIR}/prusa-gcodeviewer"
+            COMMAND ln -sf "${CMAKE_CURRENT_BINARY_DIR}/PrusaSlicer" "${CMAKE_CURRENT_BINARY_DIR}/PrusaGCodeViewer"
+            COMMENT "Symlinking the G-code viewer to PrusaSlicer, symlinking to prusa-slicer and prusa-gcodeviewer"
+            VERBATIM
+        )
+        # Because of Debug/Release/etc. configurations (similar to MSVC) the slic3r binary is located in an extra level
+        set(BIN_RESOURCES_DIR "${CMAKE_CURRENT_BINARY_DIR}/resources")
+    else ()
+        add_custom_command(TARGET PrusaSlicer POST_BUILD
+            COMMAND ln -sf "${CMAKE_CURRENT_BINARY_DIR}/prusa-slicer" "${CMAKE_CURRENT_BINARY_DIR}/prusa-gcodeviewer"
+            COMMENT "Symlinking the G-code viewer to PrusaSlicer"
+            VERBATIM
+        )
+        set(BIN_RESOURCES_DIR "${CMAKE_CURRENT_BINARY_DIR}/../resources")
+    endif ()
     add_custom_command(TARGET PrusaSlicer POST_BUILD
-        COMMAND ln -sfn "${SLIC3R_RESOURCES_DIR}" "${CMAKE_CURRENT_BINARY_DIR}/../resources"
+        COMMAND ln -sfn "${SLIC3R_RESOURCES_DIR}" "${BIN_RESOURCES_DIR}"
         COMMENT "Symlinking the resources directory into the build tree"
         VERBATIM
     )
-endif()
+endif ()
 
 # Slic3r binary install target
 if (WIN32)
diff --git a/src/slic3r/Utils/Process.cpp b/src/slic3r/Utils/Process.cpp
index 17e3d6fed..ad3730dd8 100644
--- a/src/slic3r/Utils/Process.cpp
+++ b/src/slic3r/Utils/Process.cpp
@@ -53,7 +53,7 @@ static void start_new_slicer_or_gcodeviewer(const NewSlicerInstanceType instance
 	{
 		std::vector<const char*> args;
 	    args.reserve(3);
-		#ifdef(__linux)
+		#ifdef __linux
 		static const char *gcodeviewer_param = "--gcodeviewer";
 	    {
 			// If executed by an AppImage, start the AppImage, not the main process.
@@ -63,17 +63,22 @@ static void start_new_slicer_or_gcodeviewer(const NewSlicerInstanceType instance
 				args.emplace_back(appimage_binary);
 				if (instance_type == NewSlicerInstanceType::GCodeViewer)
 					args.emplace_back(gcodeviewer_param);
-				if ()
 			}
 		}
 		#endif // __linux
+		std::string bin_path;
+		if (args.empty()) {
+			// Binary path was not set to the AppImage in the Linux specific block above, call the application directly.
+			bin_path = (own_path.parent_path() / ((instance_type == NewSlicerInstanceType::Slicer) ? "prusa-slicer" : "prusa-gcodeviewer")).string();
+			args.emplace_back(bin_path.c_str());
+		}
 	    std::string to_open;
 	    if (path_to_open) {
 	    	to_open = into_u8(*path_to_open);
 	    	args.emplace_back(to_open.c_str());
 	    }
 	    args.emplace_back(nullptr);
-	    wxExecute(const_cast<char**>(&args.data()), wxEXEC_ASYNC | wxEXEC_HIDE_CONSOLE | wxEXEC_MAKE_GROUP_LEADER);
+	    wxExecute(const_cast<char**>(args.data()), wxEXEC_ASYNC | wxEXEC_HIDE_CONSOLE | wxEXEC_MAKE_GROUP_LEADER);
 	}
 	#endif // Linux or Unix
 #endif // Win32

From 1221c67d7f9bdb40de5cee3518036511b9f9e8c4 Mon Sep 17 00:00:00 2001
From: Vojtech Bubnik <bubnikv@gmail.com>
Date: Mon, 7 Sep 2020 17:09:27 +0200
Subject: [PATCH 04/15] Fix for OSX

---
 src/slic3r/Utils/Process.cpp | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/src/slic3r/Utils/Process.cpp b/src/slic3r/Utils/Process.cpp
index ad3730dd8..596b73ff8 100644
--- a/src/slic3r/Utils/Process.cpp
+++ b/src/slic3r/Utils/Process.cpp
@@ -42,12 +42,12 @@ static void start_new_slicer_or_gcodeviewer(const NewSlicerInstanceType instance
      wxExecute(const_cast<wchar_t**>(args.data()), wxEXEC_ASYNC | wxEXEC_HIDE_CONSOLE | wxEXEC_MAKE_GROUP_LEADER);
 #else 
 	// Own executable path.
-    boost::filesystem::path own_path = into_path(wxStandardPaths::Get().GetExecutablePath());
+    boost::filesystem::path bin_path = into_path(wxStandardPaths::Get().GetExecutablePath());
 	#if defined(__APPLE__)
 	{
-		own_path /=	(instance_type == NewSlicerInstanceType::Slicer) ? "PrusaSlicer" : "PrusaGCodeViewer";
+		bin_path /=	(instance_type == NewSlicerInstanceType::Slicer) ? "PrusaSlicer" : "PrusaGCodeViewer";
 		// On Apple the wxExecute fails, thus we use boost::process instead.
-	    path_to_open ? boost::process::spawn(path.string(), into_u8(*path_to_open)) : boost::process::spawn(path.string());
+	    path_to_open ? boost::process::spawn(bin_path.string(), into_u8(*path_to_open)) : boost::process::spawn(bin_path.string());
 	}
 	#else // Linux or Unix
 	{

From ae0e576c32b360314a962ddc0eef645c3cc3fe2e Mon Sep 17 00:00:00 2001
From: Vojtech Bubnik <bubnikv@gmail.com>
Date: Mon, 7 Sep 2020 17:41:16 +0200
Subject: [PATCH 05/15] Fixing Linux build

---
 src/slic3r/Utils/Process.cpp | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/src/slic3r/Utils/Process.cpp b/src/slic3r/Utils/Process.cpp
index 596b73ff8..83438390c 100644
--- a/src/slic3r/Utils/Process.cpp
+++ b/src/slic3r/Utils/Process.cpp
@@ -66,11 +66,11 @@ static void start_new_slicer_or_gcodeviewer(const NewSlicerInstanceType instance
 			}
 		}
 		#endif // __linux
-		std::string bin_path;
+		std::string my_path;
 		if (args.empty()) {
 			// Binary path was not set to the AppImage in the Linux specific block above, call the application directly.
-			bin_path = (own_path.parent_path() / ((instance_type == NewSlicerInstanceType::Slicer) ? "prusa-slicer" : "prusa-gcodeviewer")).string();
-			args.emplace_back(bin_path.c_str());
+			my_path = (bin_path.parent_path() / ((instance_type == NewSlicerInstanceType::Slicer) ? "prusa-slicer" : "prusa-gcodeviewer")).string();
+			args.emplace_back(my_path.c_str());
 		}
 	    std::string to_open;
 	    if (path_to_open) {

From 8622437c12d21ca402cc7cd1cf8fb54a603ab62a Mon Sep 17 00:00:00 2001
From: Vojtech Bubnik <bubnikv@gmail.com>
Date: Mon, 7 Sep 2020 18:09:51 +0200
Subject: [PATCH 06/15] fixing symlinks

---
 src/CMakeLists.txt | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 8b9462cb2..e80349f84 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -212,9 +212,10 @@ if (WIN32)
 else ()
     if (XCODE)
         add_custom_command(TARGET PrusaSlicer POST_BUILD
-            COMMAND ln -sf "${CMAKE_CURRENT_BINARY_DIR}/PrusaSlicer" "${CMAKE_CURRENT_BINARY_DIR}/prusa-slicer"
-            COMMAND ln -sf "${CMAKE_CURRENT_BINARY_DIR}/PrusaSlicer" "${CMAKE_CURRENT_BINARY_DIR}/prusa-gcodeviewer"
-            COMMAND ln -sf "${CMAKE_CURRENT_BINARY_DIR}/PrusaSlicer" "${CMAKE_CURRENT_BINARY_DIR}/PrusaGCodeViewer"
+            COMMAND ln -sf PrusaSlicer prusa-slicer
+            COMMAND ln -sf PrusaSlicer prusa-gcodeviewer
+            COMMAND ln -sf PrusaSlicer PrusaGCodeViewer
+            WORKING_DIRECTORY "$<TARGET_FILE_DIR:PrusaSlicer>"
             COMMENT "Symlinking the G-code viewer to PrusaSlicer, symlinking to prusa-slicer and prusa-gcodeviewer"
             VERBATIM
         )
@@ -222,7 +223,8 @@ else ()
         set(BIN_RESOURCES_DIR "${CMAKE_CURRENT_BINARY_DIR}/resources")
     else ()
         add_custom_command(TARGET PrusaSlicer POST_BUILD
-            COMMAND ln -sf "${CMAKE_CURRENT_BINARY_DIR}/prusa-slicer" "${CMAKE_CURRENT_BINARY_DIR}/prusa-gcodeviewer"
+            COMMAND ln -sf prusa-slicer prusa-gcodeviewer
+            WORKING_DIRECTORY "$<TARGET_FILE_DIR:PrusaSlicer>"
             COMMENT "Symlinking the G-code viewer to PrusaSlicer"
             VERBATIM
         )

From 889f05167af523da4f0c8d8028049e970ea91358 Mon Sep 17 00:00:00 2001
From: Vojtech Bubnik <bubnikv@gmail.com>
Date: Mon, 7 Sep 2020 21:36:51 +0200
Subject: [PATCH 07/15] Changing the binary name on OSX to PrusaSlicer.

---
 src/CMakeLists.txt | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index e80349f84..c0137502a 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -106,9 +106,9 @@ if (MINGW)
     set_target_properties(PrusaSlicer PROPERTIES PREFIX "")
 endif (MINGW)
 
-if (NOT WIN32)
-    # Binary name on unix like systems (OSX, Linux)
-   set_target_properties(PrusaSlicer PROPERTIES OUTPUT_NAME "prusa-slicer")
+if (NOT WIN32 AND NOT APPLE)
+    # Binary name on unix like systems (Linux, Unix)
+    set_target_properties(PrusaSlicer PROPERTIES OUTPUT_NAME "prusa-slicer")
 endif ()
 
 target_link_libraries(PrusaSlicer libslic3r cereal)

From 620c85f264f8175552aab041b4ced2d39c132cbb Mon Sep 17 00:00:00 2001
From: test <test@SlicerOSXbot.local>
Date: Mon, 7 Sep 2020 22:00:01 +0200
Subject: [PATCH 08/15] Fix on OSX

---
 src/slic3r/Utils/Process.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/slic3r/Utils/Process.cpp b/src/slic3r/Utils/Process.cpp
index 83438390c..e29160870 100644
--- a/src/slic3r/Utils/Process.cpp
+++ b/src/slic3r/Utils/Process.cpp
@@ -45,7 +45,7 @@ static void start_new_slicer_or_gcodeviewer(const NewSlicerInstanceType instance
     boost::filesystem::path bin_path = into_path(wxStandardPaths::Get().GetExecutablePath());
 	#if defined(__APPLE__)
 	{
-		bin_path /=	(instance_type == NewSlicerInstanceType::Slicer) ? "PrusaSlicer" : "PrusaGCodeViewer";
+		bin_path =	bin_path.parent_path() / ((instance_type == NewSlicerInstanceType::Slicer) ? "PrusaSlicer" : "PrusaGCodeViewer");
 		// On Apple the wxExecute fails, thus we use boost::process instead.
 	    path_to_open ? boost::process::spawn(bin_path.string(), into_u8(*path_to_open)) : boost::process::spawn(bin_path.string());
 	}

From f237b33515b25833bae40e96c11565564f4ee400 Mon Sep 17 00:00:00 2001
From: Vojtech Bubnik <bubnikv@gmail.com>
Date: Mon, 7 Sep 2020 22:26:58 +0200
Subject: [PATCH 09/15] Yet another fix on OSX.

---
 src/CMakeLists.txt | 19 ++++++++++---------
 1 file changed, 10 insertions(+), 9 deletions(-)

diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index c0137502a..ca57ca553 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -210,31 +210,32 @@ if (WIN32)
     prusaslicer_copy_dlls(PrusaSlicerDllsCopy)
     
 else ()
-    if (XCODE)
+    if (APPLE)
+        # On OSX, the name of the binary matches the name of the Application.
         add_custom_command(TARGET PrusaSlicer POST_BUILD
             COMMAND ln -sf PrusaSlicer prusa-slicer
             COMMAND ln -sf PrusaSlicer prusa-gcodeviewer
             COMMAND ln -sf PrusaSlicer PrusaGCodeViewer
             WORKING_DIRECTORY "$<TARGET_FILE_DIR:PrusaSlicer>"
             COMMENT "Symlinking the G-code viewer to PrusaSlicer, symlinking to prusa-slicer and prusa-gcodeviewer"
-            VERBATIM
-        )
-        # Because of Debug/Release/etc. configurations (similar to MSVC) the slic3r binary is located in an extra level
-        set(BIN_RESOURCES_DIR "${CMAKE_CURRENT_BINARY_DIR}/resources")
+            VERBATIM)
     else ()
         add_custom_command(TARGET PrusaSlicer POST_BUILD
             COMMAND ln -sf prusa-slicer prusa-gcodeviewer
             WORKING_DIRECTORY "$<TARGET_FILE_DIR:PrusaSlicer>"
             COMMENT "Symlinking the G-code viewer to PrusaSlicer"
-            VERBATIM
-        )
+            VERBATIM)
+    endif ()
+    if (XCODE)
+        # Because of Debug/Release/etc. configurations (similar to MSVC) the slic3r binary is located in an extra level
+        set(BIN_RESOURCES_DIR "${CMAKE_CURRENT_BINARY_DIR}/resources")
+    else ()
         set(BIN_RESOURCES_DIR "${CMAKE_CURRENT_BINARY_DIR}/../resources")
     endif ()
     add_custom_command(TARGET PrusaSlicer POST_BUILD
         COMMAND ln -sfn "${SLIC3R_RESOURCES_DIR}" "${BIN_RESOURCES_DIR}"
         COMMENT "Symlinking the resources directory into the build tree"
-        VERBATIM
-    )
+        VERBATIM)
 endif ()
 
 # Slic3r binary install target

From d830e1c970f8562ca862759cf3bcb6c4f80c9c54 Mon Sep 17 00:00:00 2001
From: Vojtech Bubnik <bubnikv@gmail.com>
Date: Mon, 7 Sep 2020 22:37:55 +0200
Subject: [PATCH 10/15] Run PrusaSlicer as G-code viewer based on argv[0] name
 on Unix systems.

---
 src/PrusaSlicer.cpp | 11 +++++++++--
 1 file changed, 9 insertions(+), 2 deletions(-)

diff --git a/src/PrusaSlicer.cpp b/src/PrusaSlicer.cpp
index 2962f0cdf..94996dc92 100644
--- a/src/PrusaSlicer.cpp
+++ b/src/PrusaSlicer.cpp
@@ -22,6 +22,7 @@
 #include <cstring>
 #include <iostream>
 #include <math.h>
+#include <boost/algorithm/string/predicate.hpp>
 #include <boost/filesystem.hpp>
 #include <boost/nowide/args.hpp>
 #include <boost/nowide/cenv.hpp>
@@ -101,8 +102,14 @@ int CLI::run(int argc, char **argv)
         std::find(m_transforms.begin(), m_transforms.end(), "cut") == m_transforms.end() &&
         std::find(m_transforms.begin(), m_transforms.end(), "cut_x") == m_transforms.end() &&
         std::find(m_transforms.begin(), m_transforms.end(), "cut_y") == m_transforms.end();
-    bool 							start_as_gcodeviewer = false;
-    
+    bool 							start_as_gcodeviewer =
+#ifdef _WIN32
+            false;
+#else
+            // On Unix systems, the prusa-slicer binary may be symlinked to give the application a different meaning.
+            boost::algorithm::iends_with(boost::filesystem::path(argv[0]).filename().string(), "gcodeviewer");
+#endif // _WIN32
+
     const std::vector<std::string> &load_configs		= m_config.option<ConfigOptionStrings>("load", true)->values;
 
     // load config files supplied via --load

From 663f17a0e3de953dde239ed65dec59eca198a7fc Mon Sep 17 00:00:00 2001
From: Vojtech Bubnik <bubnikv@gmail.com>
Date: Tue, 8 Sep 2020 09:57:17 +0200
Subject: [PATCH 11/15] Improved logging of spawning a subprocess.

---
 src/slic3r/Utils/Process.cpp | 40 ++++++++++++++++++++++++------------
 1 file changed, 27 insertions(+), 13 deletions(-)

diff --git a/src/slic3r/Utils/Process.cpp b/src/slic3r/Utils/Process.cpp
index e29160870..4347f6682 100644
--- a/src/slic3r/Utils/Process.cpp
+++ b/src/slic3r/Utils/Process.cpp
@@ -8,6 +8,11 @@
 // localization
 #include "../GUI/I18N.hpp"
 
+#include <iostream>
+#include <fstream>
+
+#include <boost/log/trivial.hpp>
+
 // For starting another PrusaSlicer instance on OSX.
 // Fails to compile on Windows on the build server.
 #ifdef __APPLE__
@@ -29,17 +34,19 @@ enum class NewSlicerInstanceType {
 static void start_new_slicer_or_gcodeviewer(const NewSlicerInstanceType instance_type, const wxString *path_to_open)
 {
 #ifdef _WIN32
-     wxString path;
-     wxFileName::SplitPath(wxStandardPaths::Get().GetExecutablePath(), &path, nullptr, nullptr, wxPATH_NATIVE);
-	 path += "\\";
-	 path += (instance_type == NewSlicerInstanceType::Slicer) ? "prusa-slicer.exe" : "prusa-gcodeviewer.exe";
-     std::vector<const wchar_t*> args;
-     args.reserve(3);
-     args.emplace_back(path.wc_str());
-     if (path_to_open != nullptr)
-     	args.emplace_back(path_to_open->wc_str());
-     args.emplace_back(nullptr);
-     wxExecute(const_cast<wchar_t**>(args.data()), wxEXEC_ASYNC | wxEXEC_HIDE_CONSOLE | wxEXEC_MAKE_GROUP_LEADER);
+	wxString path;
+	wxFileName::SplitPath(wxStandardPaths::Get().GetExecutablePath(), &path, nullptr, nullptr, wxPATH_NATIVE);
+	path += "\\";
+	path += (instance_type == NewSlicerInstanceType::Slicer) ? "prusa-slicer.exe" : "prusa-gcodeviewer.exe";
+	std::vector<const wchar_t*> args;
+	args.reserve(3);
+	args.emplace_back(path.wc_str());
+	if (path_to_open != nullptr)
+		args.emplace_back(path_to_open->wc_str());
+	args.emplace_back(nullptr);
+	BOOST_LOG_TRIVIAL(info) << "Trying to spawn a new slicer \"" << to_u8(path) << "\"";
+	if (wxExecute(const_cast<wchar_t**>(args.data()), wxEXEC_ASYNC | wxEXEC_HIDE_CONSOLE | wxEXEC_MAKE_GROUP_LEADER) <= 0)
+		BOOST_LOG_TRIVIAL(error) << "Failed to spawn a new slicer \"" << to_u8(path);
 #else 
 	// Own executable path.
     boost::filesystem::path bin_path = into_path(wxStandardPaths::Get().GetExecutablePath());
@@ -47,7 +54,12 @@ static void start_new_slicer_or_gcodeviewer(const NewSlicerInstanceType instance
 	{
 		bin_path =	bin_path.parent_path() / ((instance_type == NewSlicerInstanceType::Slicer) ? "PrusaSlicer" : "PrusaGCodeViewer");
 		// On Apple the wxExecute fails, thus we use boost::process instead.
-	    path_to_open ? boost::process::spawn(bin_path.string(), into_u8(*path_to_open)) : boost::process::spawn(bin_path.string());
+		BOOST_LOG_TRIVIAL(info) << "Trying to spawn a new slicer \"" << bin_path.string() << "\"";
+		try {
+	    	path_to_open ? boost::process::spawn(bin_path.string(), into_u8(*path_to_open)) : boost::process::spawn(bin_path.string());
+	    } catch (const std::exception &ex) {
+			BOOST_LOG_TRIVIAL(error) << "Failed to spawn a new slicer \"" << bin_path.string() << "\": " << ex.what();
+	    }
 	}
 	#else // Linux or Unix
 	{
@@ -78,7 +90,9 @@ static void start_new_slicer_or_gcodeviewer(const NewSlicerInstanceType instance
 	    	args.emplace_back(to_open.c_str());
 	    }
 	    args.emplace_back(nullptr);
-	    wxExecute(const_cast<char**>(args.data()), wxEXEC_ASYNC | wxEXEC_HIDE_CONSOLE | wxEXEC_MAKE_GROUP_LEADER);
+		BOOST_LOG_TRIVIAL(info) << "Trying to spawn a new slicer \"" << args[0] << "\"";
+	    if (wxExecute(const_cast<char**>(args.data()), wxEXEC_ASYNC | wxEXEC_HIDE_CONSOLE | wxEXEC_MAKE_GROUP_LEADER) <= 0)
+	    	BOOST_LOG_TRIVIAL(error) << "Failed to spawn a new slicer \"" << args[0];
 	}
 	#endif // Linux or Unix
 #endif // Win32

From 77ba284a59b782c9898cd6eeb1867ba69cbcf8c3 Mon Sep 17 00:00:00 2001
From: Vojtech Bubnik <bubnikv@gmail.com>
Date: Tue, 8 Sep 2020 11:22:27 +0200
Subject: [PATCH 12/15] Trying to fix spawn on OSX

---
 src/slic3r/Utils/Process.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/slic3r/Utils/Process.cpp b/src/slic3r/Utils/Process.cpp
index 4347f6682..3ee141e80 100644
--- a/src/slic3r/Utils/Process.cpp
+++ b/src/slic3r/Utils/Process.cpp
@@ -56,7 +56,7 @@ static void start_new_slicer_or_gcodeviewer(const NewSlicerInstanceType instance
 		// On Apple the wxExecute fails, thus we use boost::process instead.
 		BOOST_LOG_TRIVIAL(info) << "Trying to spawn a new slicer \"" << bin_path.string() << "\"";
 		try {
-	    	path_to_open ? boost::process::spawn(bin_path.string(), into_u8(*path_to_open)) : boost::process::spawn(bin_path.string());
+	    	path_to_open ? boost::process::spawn(bin_path, into_u8(*path_to_open)) : boost::process::spawn(bin_path, boost::path::args());
 	    } catch (const std::exception &ex) {
 			BOOST_LOG_TRIVIAL(error) << "Failed to spawn a new slicer \"" << bin_path.string() << "\": " << ex.what();
 	    }

From 3c51581e92f7ec88ac82007d5e6ffd2eca8840e5 Mon Sep 17 00:00:00 2001
From: Vojtech Bubnik <bubnikv@gmail.com>
Date: Tue, 8 Sep 2020 11:36:00 +0200
Subject: [PATCH 13/15] Another fix

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

diff --git a/src/slic3r/Utils/Process.cpp b/src/slic3r/Utils/Process.cpp
index 3ee141e80..ab5a9b1e9 100644
--- a/src/slic3r/Utils/Process.cpp
+++ b/src/slic3r/Utils/Process.cpp
@@ -11,6 +11,7 @@
 #include <iostream>
 #include <fstream>
 
+#include <boost/filesystem.hpp>
 #include <boost/log/trivial.hpp>
 
 // For starting another PrusaSlicer instance on OSX.
@@ -56,7 +57,7 @@ static void start_new_slicer_or_gcodeviewer(const NewSlicerInstanceType instance
 		// On Apple the wxExecute fails, thus we use boost::process instead.
 		BOOST_LOG_TRIVIAL(info) << "Trying to spawn a new slicer \"" << bin_path.string() << "\"";
 		try {
-	    	path_to_open ? boost::process::spawn(bin_path, into_u8(*path_to_open)) : boost::process::spawn(bin_path, boost::path::args());
+	    	path_to_open ? boost::process::spawn(bin_path, into_u8(*path_to_open)) : boost::process::spawn(bin_path, boost::filesystem::path::args());
 	    } catch (const std::exception &ex) {
 			BOOST_LOG_TRIVIAL(error) << "Failed to spawn a new slicer \"" << bin_path.string() << "\": " << ex.what();
 	    }

From 0fde670fd654b794c49b462bd140c48f46af6d58 Mon Sep 17 00:00:00 2001
From: Vojtech Bubnik <bubnikv@gmail.com>
Date: Tue, 8 Sep 2020 11:49:02 +0200
Subject: [PATCH 14/15] osx fix

---
 src/slic3r/Utils/Process.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/slic3r/Utils/Process.cpp b/src/slic3r/Utils/Process.cpp
index ab5a9b1e9..2301cd250 100644
--- a/src/slic3r/Utils/Process.cpp
+++ b/src/slic3r/Utils/Process.cpp
@@ -57,7 +57,7 @@ static void start_new_slicer_or_gcodeviewer(const NewSlicerInstanceType instance
 		// On Apple the wxExecute fails, thus we use boost::process instead.
 		BOOST_LOG_TRIVIAL(info) << "Trying to spawn a new slicer \"" << bin_path.string() << "\"";
 		try {
-	    	path_to_open ? boost::process::spawn(bin_path, into_u8(*path_to_open)) : boost::process::spawn(bin_path, boost::filesystem::path::args());
+	    	path_to_open ? boost::process::spawn(bin_path, into_u8(*path_to_open)) : boost::process::spawn(bin_path, boost::process::args());
 	    } catch (const std::exception &ex) {
 			BOOST_LOG_TRIVIAL(error) << "Failed to spawn a new slicer \"" << bin_path.string() << "\": " << ex.what();
 	    }

From 0f64b67ffa9f88055150b59c6314ec7d15377963 Mon Sep 17 00:00:00 2001
From: test <test@SlicerOSXbot.local>
Date: Tue, 8 Sep 2020 12:39:11 +0200
Subject: [PATCH 15/15] osx fix

---
 src/slic3r/Utils/Process.cpp | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/src/slic3r/Utils/Process.cpp b/src/slic3r/Utils/Process.cpp
index 2301cd250..fa5ecb1f0 100644
--- a/src/slic3r/Utils/Process.cpp
+++ b/src/slic3r/Utils/Process.cpp
@@ -18,6 +18,7 @@
 // Fails to compile on Windows on the build server.
 #ifdef __APPLE__
     #include <boost/process/spawn.hpp>
+    #include <boost/process/args.hpp>
 #endif
 
 #include <wx/stdpaths.h>
@@ -57,7 +58,10 @@ static void start_new_slicer_or_gcodeviewer(const NewSlicerInstanceType instance
 		// On Apple the wxExecute fails, thus we use boost::process instead.
 		BOOST_LOG_TRIVIAL(info) << "Trying to spawn a new slicer \"" << bin_path.string() << "\"";
 		try {
-	    	path_to_open ? boost::process::spawn(bin_path, into_u8(*path_to_open)) : boost::process::spawn(bin_path, boost::process::args());
+            std::vector<std::string> args;
+            if (path_to_open)
+                args.emplace_back(into_u8(*path_to_open));
+            boost::process::spawn(bin_path, args);
 	    } catch (const std::exception &ex) {
 			BOOST_LOG_TRIVIAL(error) << "Failed to spawn a new slicer \"" << bin_path.string() << "\": " << ex.what();
 	    }