Updated the command line single-instance processing and help text.

Updated escaping of the command line arguments when passed to the other
instance.
This commit is contained in:
Vojtech Bubnik 2020-10-12 17:06:03 +02:00
parent fa74f50af1
commit 8c0b8f89d0
2 changed files with 40 additions and 37 deletions
src

View file

@ -39,11 +39,6 @@ void PrintConfigDef::init_common_params()
{ {
ConfigOptionDef* def; 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 = this->add("printer_technology", coEnum);
def->label = L("Printer technology"); def->label = L("Printer technology");
def->tooltip = 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->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->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 = this->add("autosave", coString);
def->label = L("Autosave"); def->label = L("Autosave");

View file

@ -15,6 +15,7 @@
#include <unordered_map> #include <unordered_map>
#include <fcntl.h> #include <fcntl.h>
#include <errno.h> #include <errno.h>
#include <optional>
#ifdef _WIN32 #ifdef _WIN32
#include <strsafe.h> #include <strsafe.h>
@ -29,25 +30,29 @@ namespace instance_check_internal
{ {
struct CommandLineAnalysis struct CommandLineAnalysis
{ {
bool should_send; std::optional<bool> should_send;
std::string cl_string; std::string cl_string;
}; };
static CommandLineAnalysis process_command_line(int argc, char** argv) static CommandLineAnalysis process_command_line(int argc, char** argv)
{ {
CommandLineAnalysis ret { false }; CommandLineAnalysis ret { false };
if (argc < 2) if (argc < 2)
return ret; return ret;
ret.cl_string = escape_string_cstyle(argv[0]); std::vector<std::string> arguments { argv[0] };
for (size_t i = 1; i < argc; ++i) { for (size_t i = 1; i < argc; ++i) {
const std::string token = argv[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; ret.should_send = true;
} else { else if (token == "--no-single-instance")
ret.cl_string += " : "; ret.should_send = false;
ret.cl_string += escape_string_cstyle(token); 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; 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); GUI::wxGetApp().set_instance_hash(hashed_path);
BOOST_LOG_TRIVIAL(debug) <<"full path: "<< lock_name; BOOST_LOG_TRIVIAL(debug) <<"full path: "<< lock_name;
instance_check_internal::CommandLineAnalysis cla = instance_check_internal::process_command_line(argc, argv); 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 #ifdef _WIN32
GUI::wxGetApp().init_single_instance_checker(lock_name + ".lock", data_dir() + "/cache/"); 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 #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 #endif
instance_check_internal::send_message(cla.cl_string, lock_name); instance_check_internal::send_message(cla.cl_string, lock_name);
BOOST_LOG_TRIVIAL(info) << "instance check: Another instance found. This instance will terminate."; BOOST_LOG_TRIVIAL(info) << "instance check: Another instance found. This instance will terminate.";
@ -372,32 +379,27 @@ namespace MessageHandlerInternal
} }
} //namespace MessageHandlerInternal } //namespace MessageHandlerInternal
void OtherInstanceMessageHandler::handle_message(const std::string& message) { void OtherInstanceMessageHandler::handle_message(const std::string& message)
std::vector<boost::filesystem::path> paths; {
auto next_space = message.find(" : ");
size_t last_space = 0;
int counter = 0;
BOOST_LOG_TRIVIAL(info) << "message from other instance: " << message; BOOST_LOG_TRIVIAL(info) << "message from other instance: " << message;
while (next_space != std::string::npos) std::vector<std::string> args;
{ bool parsed = unescape_strings_cstyle(message, args);
if (counter != 0) { assert(parsed);
std::string possible_path = message.substr(last_space, next_space - last_space); if (! parsed) {
boost::filesystem::path p = MessageHandlerInternal::get_path(std::move(possible_path)); BOOST_LOG_TRIVIAL(error) << "message from other instance is incorrectly formatted: " << message;
if(!p.string().empty()) return;
paths.emplace_back(p);
}
last_space = next_space + 3;
next_space = message.find(" : ", last_space);
counter++;
} }
if (counter != 0 ) {
boost::filesystem::path p = MessageHandlerInternal::get_path(message.substr(last_space)); std::vector<boost::filesystem::path> paths;
if (!p.string().empty()) // 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); paths.emplace_back(p);
} }
if (!paths.empty()) { if (! paths.empty()) {
//wxEvtHandler* evt_handler = wxGetApp().plater(); //assert here? //wxEvtHandler* evt_handler = wxGetApp().plater(); //assert here?
//if (evt_handler) { //if (evt_handler) {
wxPostEvent(m_callback_evt_handler, LoadFromOtherInstanceEvent(GUI::EVT_LOAD_MODEL_OTHER_INSTANCE, std::vector<boost::filesystem::path>(std::move(paths)))); wxPostEvent(m_callback_evt_handler, LoadFromOtherInstanceEvent(GUI::EVT_LOAD_MODEL_OTHER_INSTANCE, std::vector<boost::filesystem::path>(std::move(paths))));