From 8c0b8f89d033832907414a5dae4088e508ec50cc Mon Sep 17 00:00:00 2001 From: Vojtech Bubnik Date: Mon, 12 Oct 2020 17:06:03 +0200 Subject: [PATCH] Updated the command line single-instance processing and help text. Updated escaping of the command line arguments when passed to the other instance. --- src/libslic3r/PrintConfig.cpp | 11 +++--- src/slic3r/GUI/InstanceCheck.cpp | 66 ++++++++++++++++---------------- 2 files changed, 40 insertions(+), 37 deletions(-) diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index 197f467a3..030328321 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -39,11 +39,6 @@ void PrintConfigDef::init_common_params() { ConfigOptionDef* def; - def = this->add("single_instance", coBool); - def->label = L("Single Instance"); - def->mode = comAdvanced; - def->set_default_value(new ConfigOptionBool(false)); - def = this->add("printer_technology", coEnum); def->label = L("Printer technology"); def->tooltip = L("Printer technology"); @@ -3698,6 +3693,12 @@ CLIMiscConfigDef::CLIMiscConfigDef() def->tooltip = L("The file where the output will be written (if not specified, it will be based on the input file)."); def->cli = "output|o"; + def = this->add("single_instance", coBool); + def->label = L("Single Instance"); + def->tooltip = L("If enabled, the command line arguments are sent to an existing instance of GUI PrusaSlicer, " + "or an existing PrusaSlicer window is activated. " + "Overrides the \"single_instance\" configuration value from application preferences."); + /* def = this->add("autosave", coString); def->label = L("Autosave"); diff --git a/src/slic3r/GUI/InstanceCheck.cpp b/src/slic3r/GUI/InstanceCheck.cpp index bbce1ed2c..70000f80e 100644 --- a/src/slic3r/GUI/InstanceCheck.cpp +++ b/src/slic3r/GUI/InstanceCheck.cpp @@ -15,6 +15,7 @@ #include #include #include +#include #ifdef _WIN32 #include @@ -29,25 +30,29 @@ namespace instance_check_internal { struct CommandLineAnalysis { - bool should_send; - std::string cl_string; + std::optional should_send; + std::string cl_string; }; static CommandLineAnalysis process_command_line(int argc, char** argv) { CommandLineAnalysis ret { false }; if (argc < 2) return ret; - ret.cl_string = escape_string_cstyle(argv[0]); + std::vector arguments { argv[0] }; for (size_t i = 1; i < argc; ++i) { const std::string token = argv[i]; - if (token == "--single-instance" || token == "--single-instance=1") { + // Processing of boolean command line arguments shall match DynamicConfig::read_cli(). + if (token == "--single-instance") ret.should_send = true; - } else { - ret.cl_string += " : "; - ret.cl_string += escape_string_cstyle(token); - } + else if (token == "--no-single-instance") + ret.should_send = false; + else + arguments.emplace_back(token); } - BOOST_LOG_TRIVIAL(debug) << "single instance: "<< ret.should_send << ". other params: " << ret.cl_string; + ret.cl_string = escape_strings_cstyle(arguments); + BOOST_LOG_TRIVIAL(debug) << "single instance: " << + (ret.should_send.has_value() ? (ret.should_send.value() ? "true" : "false") : "undefined") << + ". other params: " << ret.cl_string; return ret; } @@ -243,11 +248,13 @@ bool instance_check(int argc, char** argv, bool app_config_single_instance) GUI::wxGetApp().set_instance_hash(hashed_path); BOOST_LOG_TRIVIAL(debug) <<"full path: "<< lock_name; instance_check_internal::CommandLineAnalysis cla = instance_check_internal::process_command_line(argc, argv); + if (! cla.should_send.has_value()) + cla.should_send = app_config_single_instance; #ifdef _WIN32 GUI::wxGetApp().init_single_instance_checker(lock_name + ".lock", data_dir() + "/cache/"); - if ((cla.should_send || app_config_single_instance) && GUI::wxGetApp().single_instance_checker()->IsAnotherRunning()) { + if (cla.should_send.value() && GUI::wxGetApp().single_instance_checker()->IsAnotherRunning()) { #else // mac & linx - if ((cla.should_send || app_config_single_instance) && instance_check_internal::get_lock(lock_name + ".lock", data_dir() + "/cache/")) { + if (cla.should_send.value() && instance_check_internal::get_lock(lock_name + ".lock", data_dir() + "/cache/")) { #endif instance_check_internal::send_message(cla.cl_string, lock_name); BOOST_LOG_TRIVIAL(info) << "instance check: Another instance found. This instance will terminate."; @@ -372,32 +379,27 @@ namespace MessageHandlerInternal } } //namespace MessageHandlerInternal -void OtherInstanceMessageHandler::handle_message(const std::string& message) { - std::vector paths; - auto next_space = message.find(" : "); - size_t last_space = 0; - int counter = 0; - +void OtherInstanceMessageHandler::handle_message(const std::string& message) +{ BOOST_LOG_TRIVIAL(info) << "message from other instance: " << message; - while (next_space != std::string::npos) - { - if (counter != 0) { - std::string possible_path = message.substr(last_space, next_space - last_space); - boost::filesystem::path p = MessageHandlerInternal::get_path(std::move(possible_path)); - if(!p.string().empty()) - paths.emplace_back(p); - } - last_space = next_space + 3; - next_space = message.find(" : ", last_space); - counter++; + std::vector args; + bool parsed = unescape_strings_cstyle(message, args); + assert(parsed); + if (! parsed) { + BOOST_LOG_TRIVIAL(error) << "message from other instance is incorrectly formatted: " << message; + return; } - if (counter != 0 ) { - boost::filesystem::path p = MessageHandlerInternal::get_path(message.substr(last_space)); - if (!p.string().empty()) + + std::vector paths; + // Skip the first argument, it is the path to the slicer executable. + auto it = args.begin(); + for (++ it; it != args.end(); ++ it) { + boost::filesystem::path p = MessageHandlerInternal::get_path(*it); + if (! p.string().empty()) paths.emplace_back(p); } - if (!paths.empty()) { + if (! paths.empty()) { //wxEvtHandler* evt_handler = wxGetApp().plater(); //assert here? //if (evt_handler) { wxPostEvent(m_callback_evt_handler, LoadFromOtherInstanceEvent(GUI::EVT_LOAD_MODEL_OTHER_INSTANCE, std::vector(std::move(paths))));