From fd4c28ed91c3d095c6ee296b55904b22c3e51759 Mon Sep 17 00:00:00 2001 From: bubnikv Date: Mon, 7 Sep 2020 15:55:03 +0200 Subject: [PATCH 01/16] 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 5681ed66db..1c30078102 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 f6fd939e25..f4d7f03eca 100644 --- a/src/slic3r/GUI/MainFrame.cpp +++ b/src/slic3r/GUI/MainFrame.cpp @@ -9,7 +9,6 @@ #include //#include #include -#include #include #include @@ -31,6 +30,7 @@ #include "I18N.hpp" #include "GLCanvas3D.hpp" #include "Plater.hpp" +#include "../Utils/Process.hpp" #include #include "GUI_App.hpp" @@ -40,12 +40,6 @@ #include #endif // _WIN32 -// For starting another PrusaSlicer instance on OSX. -// Fails to compile on Windows on the build server. -#ifdef __APPLE__ - #include -#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 e9c76d2aba..194971c9eb 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 #include @@ -25,4 +25,4 @@ template 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 Date: Mon, 7 Sep 2020 15:55:03 +0200 Subject: [PATCH 02/16] 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 5681ed66db..1c30078102 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 f6fd939e25..f4d7f03eca 100644 --- a/src/slic3r/GUI/MainFrame.cpp +++ b/src/slic3r/GUI/MainFrame.cpp @@ -9,7 +9,6 @@ #include //#include #include -#include #include #include @@ -31,6 +30,7 @@ #include "I18N.hpp" #include "GLCanvas3D.hpp" #include "Plater.hpp" +#include "../Utils/Process.hpp" #include #include "GUI_App.hpp" @@ -40,12 +40,6 @@ #include #endif // _WIN32 -// For starting another PrusaSlicer instance on OSX. -// Fails to compile on Windows on the build server. -#ifdef __APPLE__ - #include -#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 0000000000..17e3d6fedf --- /dev/null +++ b/src/slic3r/Utils/Process.cpp @@ -0,0 +1,105 @@ +#include "Process.hpp" + +#include + +#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 +#endif + +#include + +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 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(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 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(&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 0000000000..c6acaa643e --- /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 e9c76d2aba..194971c9eb 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 #include @@ -25,4 +25,4 @@ template 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 Date: Mon, 7 Sep 2020 16:56:22 +0200 Subject: [PATCH 03/16] 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 0b0b3c0eef..8b9462cb2a 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 17e3d6fedf..ad3730dd88 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 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(&args.data()), wxEXEC_ASYNC | wxEXEC_HIDE_CONSOLE | wxEXEC_MAKE_GROUP_LEADER); + wxExecute(const_cast(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 Date: Mon, 7 Sep 2020 17:09:27 +0200 Subject: [PATCH 04/16] 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 ad3730dd88..596b73ff81 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(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 Date: Mon, 7 Sep 2020 17:41:16 +0200 Subject: [PATCH 05/16] 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 596b73ff81..83438390c0 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 Date: Mon, 7 Sep 2020 18:09:51 +0200 Subject: [PATCH 06/16] fixing symlinks --- src/CMakeLists.txt | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 8b9462cb2a..e80349f844 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 "$" 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 "$" COMMENT "Symlinking the G-code viewer to PrusaSlicer" VERBATIM ) From 889f05167af523da4f0c8d8028049e970ea91358 Mon Sep 17 00:00:00 2001 From: Vojtech Bubnik Date: Mon, 7 Sep 2020 21:36:51 +0200 Subject: [PATCH 07/16] 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 e80349f844..c0137502a4 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 Date: Mon, 7 Sep 2020 22:00:01 +0200 Subject: [PATCH 08/16] 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 83438390c0..e29160870d 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 Date: Mon, 7 Sep 2020 22:26:58 +0200 Subject: [PATCH 09/16] 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 c0137502a4..ca57ca5531 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 "$" 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 "$" 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 Date: Mon, 7 Sep 2020 22:37:55 +0200 Subject: [PATCH 10/16] 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 2962f0cdfe..94996dc928 100644 --- a/src/PrusaSlicer.cpp +++ b/src/PrusaSlicer.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -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 &load_configs = m_config.option("load", true)->values; // load config files supplied via --load From 663f17a0e3de953dde239ed65dec59eca198a7fc Mon Sep 17 00:00:00 2001 From: Vojtech Bubnik Date: Tue, 8 Sep 2020 09:57:17 +0200 Subject: [PATCH 11/16] 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 e29160870d..4347f66828 100644 --- a/src/slic3r/Utils/Process.cpp +++ b/src/slic3r/Utils/Process.cpp @@ -8,6 +8,11 @@ // localization #include "../GUI/I18N.hpp" +#include +#include + +#include + // 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 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(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 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(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(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(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 Date: Tue, 8 Sep 2020 11:22:27 +0200 Subject: [PATCH 12/16] 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 4347f66828..3ee141e804 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 Date: Tue, 8 Sep 2020 11:36:00 +0200 Subject: [PATCH 13/16] 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 3ee141e804..ab5a9b1e9b 100644 --- a/src/slic3r/Utils/Process.cpp +++ b/src/slic3r/Utils/Process.cpp @@ -11,6 +11,7 @@ #include #include +#include #include // 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 Date: Tue, 8 Sep 2020 11:49:02 +0200 Subject: [PATCH 14/16] 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 ab5a9b1e9b..2301cd2504 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 Date: Tue, 8 Sep 2020 12:39:11 +0200 Subject: [PATCH 15/16] 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 2301cd2504..fa5ecb1f07 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 + #include #endif #include @@ -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 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(); } From 946f51467fec8c90f7b85ae1d943f672f2c3d9bc Mon Sep 17 00:00:00 2001 From: Vojtech Bubnik Date: Tue, 8 Sep 2020 13:33:43 +0200 Subject: [PATCH 16/16] WIP Standalone G-code viewer --- src/CMakeLists.txt | 42 ++++++++---- src/PrusaSlicer.cpp | 11 ++- src/slic3r/CMakeLists.txt | 2 + src/slic3r/GUI/MainFrame.cpp | 25 ++----- src/slic3r/Utils/Process.cpp | 125 +++++++++++++++++++++++++++++++++++ src/slic3r/Utils/Process.hpp | 19 ++++++ src/slic3r/Utils/Thread.hpp | 6 +- 7 files changed, 192 insertions(+), 38 deletions(-) create mode 100644 src/slic3r/Utils/Process.cpp create mode 100644 src/slic3r/Utils/Process.hpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 0b0b3c0eef..ca57ca5531 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) @@ -209,20 +209,34 @@ 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 (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 "$" + COMMENT "Symlinking the G-code viewer to PrusaSlicer, symlinking to prusa-slicer and prusa-gcodeviewer" + VERBATIM) + else () + add_custom_command(TARGET PrusaSlicer POST_BUILD + COMMAND ln -sf prusa-slicer prusa-gcodeviewer + WORKING_DIRECTORY "$" + COMMENT "Symlinking the G-code viewer to PrusaSlicer" + 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}" "${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() + VERBATIM) +endif () # Slic3r binary install target if (WIN32) diff --git a/src/PrusaSlicer.cpp b/src/PrusaSlicer.cpp index 2962f0cdfe..94996dc928 100644 --- a/src/PrusaSlicer.cpp +++ b/src/PrusaSlicer.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -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 &load_configs = m_config.option("load", true)->values; // load config files supplied via --load diff --git a/src/slic3r/CMakeLists.txt b/src/slic3r/CMakeLists.txt index 5681ed66db..1c30078102 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 f6fd939e25..f4d7f03eca 100644 --- a/src/slic3r/GUI/MainFrame.cpp +++ b/src/slic3r/GUI/MainFrame.cpp @@ -9,7 +9,6 @@ #include //#include #include -#include #include #include @@ -31,6 +30,7 @@ #include "I18N.hpp" #include "GLCanvas3D.hpp" #include "Plater.hpp" +#include "../Utils/Process.hpp" #include #include "GUI_App.hpp" @@ -40,12 +40,6 @@ #include #endif // _WIN32 -// For starting another PrusaSlicer instance on OSX. -// Fails to compile on Windows on the build server. -#ifdef __APPLE__ - #include -#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 0000000000..2301cd2504 --- /dev/null +++ b/src/slic3r/Utils/Process.cpp @@ -0,0 +1,125 @@ +#include "Process.hpp" + +#include + +#include "../GUI/GUI.hpp" +// for file_wildcards() +#include "../GUI/GUI_App.hpp" +// localization +#include "../GUI/I18N.hpp" + +#include +#include + +#include +#include + +// For starting another PrusaSlicer instance on OSX. +// Fails to compile on Windows on the build server. +#ifdef __APPLE__ + #include +#endif + +#include + +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 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(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()); + #if defined(__APPLE__) + { + bin_path = bin_path.parent_path() / ((instance_type == NewSlicerInstanceType::Slicer) ? "PrusaSlicer" : "PrusaGCodeViewer"); + // 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()); + } catch (const std::exception &ex) { + BOOST_LOG_TRIVIAL(error) << "Failed to spawn a new slicer \"" << bin_path.string() << "\": " << ex.what(); + } + } + #else // Linux or Unix + { + std::vector 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); + } + } + #endif // __linux + 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. + 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) { + to_open = into_u8(*path_to_open); + args.emplace_back(to_open.c_str()); + } + args.emplace_back(nullptr); + BOOST_LOG_TRIVIAL(info) << "Trying to spawn a new slicer \"" << args[0] << "\""; + if (wxExecute(const_cast(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 +} + +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 0000000000..c6acaa643e --- /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 e9c76d2aba..194971c9eb 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 #include @@ -25,4 +25,4 @@ template inline boost::thread create_thread(Fn &&fn) } -#endif // THREAD_HPP +#endif // GUI_THREAD_HPP