Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/prusa3d/PrusaSlicer.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'src/slic3r/GUI/InstanceCheck.cpp')
-rw-r--r--src/slic3r/GUI/InstanceCheck.cpp623
1 files changed, 623 insertions, 0 deletions
diff --git a/src/slic3r/GUI/InstanceCheck.cpp b/src/slic3r/GUI/InstanceCheck.cpp
new file mode 100644
index 000000000..6cfa879c8
--- /dev/null
+++ b/src/slic3r/GUI/InstanceCheck.cpp
@@ -0,0 +1,623 @@
+#include "GUI_App.hpp"
+#include "InstanceCheck.hpp"
+#include "Plater.hpp"
+
+#ifdef _WIN32
+ #include "MainFrame.hpp"
+#endif
+
+#include "libslic3r/Utils.hpp"
+#include "libslic3r/Config.hpp"
+
+#include "boost/nowide/convert.hpp"
+#include <boost/log/trivial.hpp>
+#include <boost/filesystem/operations.hpp>
+#include <iostream>
+#include <unordered_map>
+#include <fcntl.h>
+#include <errno.h>
+#include <optional>
+#include <cstdint>
+
+#ifdef _WIN32
+#include <strsafe.h>
+#endif //WIN32
+
+#if __linux__
+#include <dbus/dbus.h> /* Pull in all of D-Bus headers. */
+#endif //__linux__
+
+namespace Slic3r {
+namespace instance_check_internal
+{
+ struct CommandLineAnalysis
+ {
+ std::optional<bool> should_send;
+ std::string cl_string;
+ };
+ static CommandLineAnalysis process_command_line(int argc, char** argv)
+ {
+ CommandLineAnalysis ret;
+ //if (argc < 2)
+ // return ret;
+ std::vector<std::string> arguments { argv[0] };
+ for (size_t i = 1; i < argc; ++i) {
+ const std::string token = argv[i];
+ // Processing of boolean command line arguments shall match DynamicConfig::read_cli().
+ if (token == "--single-instance")
+ ret.should_send = true;
+ else if (token == "--no-single-instance")
+ ret.should_send = false;
+ else
+ arguments.emplace_back(token);
+ }
+ ret.cl_string = escape_strings_cstyle(arguments);
+ BOOST_LOG_TRIVIAL(debug) << "single instance: " <<
+ (ret.should_send.has_value() ? (*ret.should_send ? "true" : "false") : "undefined") <<
+ ". other params: " << ret.cl_string;
+ return ret;
+ }
+
+
+
+#ifdef _WIN32
+
+ static HWND l_prusa_slicer_hwnd;
+ static BOOL CALLBACK EnumWindowsProc(_In_ HWND hwnd, _In_ LPARAM lParam)
+ {
+ //checks for other instances of prusaslicer, if found brings it to front and return false to stop enumeration and quit this instance
+ //search is done by classname(wxWindowNR is wxwidgets thing, so probably not unique) and name in window upper panel
+ //other option would be do a mutex and check for its existence
+ //BOOST_LOG_TRIVIAL(error) << "ewp: version: " << l_version_wstring;
+ TCHAR wndText[1000];
+ TCHAR className[1000];
+ int err;
+ err = GetClassName(hwnd, className, 1000);
+ if (err == 0)
+ return true;
+ err = GetWindowText(hwnd, wndText, 1000);
+ if (err == 0)
+ return true;
+ std::wstring classNameString(className);
+ std::wstring wndTextString(wndText);
+ if (wndTextString.find(L"PrusaSlicer") != std::wstring::npos && classNameString == L"wxWindowNR") {
+ //check if other instances has same instance hash
+ //if not it is not same version(binary) as this version
+ HANDLE handle = GetProp(hwnd, L"Instance_Hash_Minor");
+ uint64_t other_instance_hash = PtrToUint(handle);
+ uint64_t other_instance_hash_major;
+ uint64_t my_instance_hash = GUI::wxGetApp().get_instance_hash_int();
+ handle = GetProp(hwnd, L"Instance_Hash_Major");
+ other_instance_hash_major = PtrToUint(handle);
+ other_instance_hash_major = other_instance_hash_major << 32;
+ other_instance_hash += other_instance_hash_major;
+ if(my_instance_hash == other_instance_hash)
+ {
+ BOOST_LOG_TRIVIAL(debug) << "win enum - found correct instance";
+ l_prusa_slicer_hwnd = hwnd;
+ ShowWindow(hwnd, SW_SHOWMAXIMIZED);
+ SetForegroundWindow(hwnd);
+ return false;
+ }
+ BOOST_LOG_TRIVIAL(debug) << "win enum - found wrong instance";
+ }
+ return true;
+ }
+ static bool send_message(const std::string& message, const std::string &version)
+ {
+ if (!EnumWindows(EnumWindowsProc, 0)) {
+ std::wstring wstr = boost::nowide::widen(message);
+ std::unique_ptr<LPWSTR> command_line_args = std::make_unique<LPWSTR>(const_cast<LPWSTR>(wstr.c_str()));
+ /*LPWSTR command_line_args = new wchar_t[wstr.size() + 1];
+ copy(wstr.begin(), wstr.end(), command_line_args);
+ command_line_args[wstr.size()] = 0;*/
+
+ //Create a COPYDATASTRUCT to send the information
+ //cbData represents the size of the information we want to send.
+ //lpData represents the information we want to send.
+ //dwData is an ID defined by us(this is a type of ID different than WM_COPYDATA).
+ COPYDATASTRUCT data_to_send = { 0 };
+ data_to_send.dwData = 1;
+ data_to_send.cbData = sizeof(TCHAR) * (wcslen(*command_line_args.get()) + 1);
+ data_to_send.lpData = *command_line_args.get();
+ SendMessage(l_prusa_slicer_hwnd, WM_COPYDATA, 0, (LPARAM)&data_to_send);
+ return true;
+ }
+ return false;
+ }
+
+#else
+
+ static bool get_lock(const std::string& name, const std::string& path)
+ {
+ std::string dest_dir = path + name;
+ BOOST_LOG_TRIVIAL(debug) <<"full lock path: "<< dest_dir;
+ struct flock fl;
+ int fdlock;
+ fl.l_type = F_WRLCK;
+ fl.l_whence = SEEK_SET;
+ fl.l_start = 0;
+ fl.l_len = 1;
+
+ if (! boost::filesystem::is_directory(path)) {
+ BOOST_LOG_TRIVIAL(debug) << "get_lock(): datadir does not exist yet, creating...";
+ if (! boost::filesystem::create_directories(path))
+ BOOST_LOG_TRIVIAL(debug) << "get_lock(): unable to create datadir !!!";
+ }
+
+ if ((fdlock = open(dest_dir.c_str(), O_WRONLY | O_CREAT, 0666)) == -1)
+ return true;
+
+ if (fcntl(fdlock, F_SETLK, &fl) == -1)
+ return true;
+
+ return false;
+ }
+
+#endif //WIN32
+#if defined(__APPLE__)
+
+ static bool send_message(const std::string &message_text, const std::string &version)
+ {
+ //std::string v(version);
+ //std::replace(v.begin(), v.end(), '.', '-');
+ //if (!instance_check_internal::get_lock(v))
+ {
+ send_message_mac(message_text, version);
+ return true;
+ }
+ return false;
+ }
+
+#elif defined(__linux__)
+
+ static bool send_message(const std::string &message_text, const std::string &version)
+ {
+ /*std::string v(version);
+ std::replace(v.begin(), v.end(), '.', '-');
+ if (!instance_check_internal::get_lock(v))*/
+ /*auto checker = new wxSingleInstanceChecker;
+ if ( !checker->IsAnotherRunning() ) */
+ {
+ DBusMessage* msg;
+ DBusMessageIter args;
+ DBusConnection* conn;
+ DBusError err;
+ dbus_uint32_t serial = 0;
+ const char* sigval = message_text.c_str();
+ //std::string interface_name = "com.prusa3d.prusaslicer.InstanceCheck";
+ std::string interface_name = "com.prusa3d.prusaslicer.InstanceCheck.Object" + version;
+ std::string method_name = "AnotherInstance";
+ //std::string object_name = "/com/prusa3d/prusaslicer/InstanceCheck";
+ std::string object_name = "/com/prusa3d/prusaslicer/InstanceCheck/Object" + version;
+
+
+ // initialise the error value
+ dbus_error_init(&err);
+
+ // connect to bus, and check for errors (use SESSION bus everywhere!)
+ conn = dbus_bus_get(DBUS_BUS_SESSION, &err);
+ if (dbus_error_is_set(&err)) {
+ BOOST_LOG_TRIVIAL(error) << "DBus Connection Error. Message to another instance wont be send.";
+ BOOST_LOG_TRIVIAL(error) << "DBus Connection Error: " << err.message;
+ dbus_error_free(&err);
+ return true;
+ }
+ if (NULL == conn) {
+ BOOST_LOG_TRIVIAL(error) << "DBus Connection is NULL. Message to another instance wont be send.";
+ return true;
+ }
+
+ //some sources do request interface ownership before constructing msg but i think its wrong.
+
+ //create new method call message
+ msg = dbus_message_new_method_call(interface_name.c_str(), object_name.c_str(), interface_name.c_str(), method_name.c_str());
+ if (NULL == msg) {
+ BOOST_LOG_TRIVIAL(error) << "DBus Message is NULL. Message to another instance wont be send.";
+ dbus_connection_unref(conn);
+ return true;
+ }
+ //the AnotherInstance method is not sending reply.
+ dbus_message_set_no_reply(msg, TRUE);
+
+ //append arguments to message
+ if (!dbus_message_append_args(msg, DBUS_TYPE_STRING, &sigval, DBUS_TYPE_INVALID)) {
+ BOOST_LOG_TRIVIAL(error) << "Ran out of memory while constructing args for DBus message. Message to another instance wont be send.";
+ dbus_message_unref(msg);
+ dbus_connection_unref(conn);
+ return true;
+ }
+
+ // send the message and flush the connection
+ if (!dbus_connection_send(conn, msg, &serial)) {
+ BOOST_LOG_TRIVIAL(error) << "Ran out of memory while sending DBus message.";
+ dbus_message_unref(msg);
+ dbus_connection_unref(conn);
+ return true;
+ }
+ dbus_connection_flush(conn);
+
+ BOOST_LOG_TRIVIAL(trace) << "DBus message sent.";
+
+ // free the message and close the connection
+ dbus_message_unref(msg);
+ dbus_connection_unref(conn);
+ return true;
+ }
+ return false;
+ }
+
+#endif //__APPLE__/__linux__
+} //namespace instance_check_internal
+
+bool instance_check(int argc, char** argv, bool app_config_single_instance)
+{
+ std::size_t hashed_path;
+#ifdef _WIN32
+ hashed_path = std::hash<std::string>{}(boost::filesystem::system_complete(argv[0]).string());
+#else
+ boost::system::error_code ec;
+#ifdef __linux__
+ // 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_env = std::getenv("APPIMAGE");
+ bool appimage_env_valid = false;
+ if (appimage_env) {
+ try {
+ auto appimage_path = boost::filesystem::canonical(boost::filesystem::path(appimage_env));
+ if (boost::filesystem::exists(appimage_path)) {
+ hashed_path = std::hash<std::string>{}(appimage_path.string());
+ appimage_env_valid = true;
+ }
+ } catch (std::exception &) {
+ }
+ if (! appimage_env_valid)
+ BOOST_LOG_TRIVIAL(error) << "APPIMAGE environment variable was set, but it does not point to a valid file: " << appimage_env;
+ }
+ if (! appimage_env_valid)
+#endif // __linux__
+ hashed_path = std::hash<std::string>{}(boost::filesystem::canonical(boost::filesystem::system_complete(argv[0]), ec).string());
+ if (ec.value() > 0) { // canonical was not able to find the executable (can happen with appimage on some systems. Does it fail on Fuse file systems?)
+ ec.clear();
+ // Compose path with boost canonical of folder and filename
+ hashed_path = std::hash<std::string>{}(boost::filesystem::canonical(boost::filesystem::system_complete(argv[0]).parent_path(), ec).string() + "/" + boost::filesystem::system_complete(argv[0]).filename().string());
+ if (ec.value() > 0) {
+ // Still not valid, process without canonical
+ hashed_path = std::hash<std::string>{}(boost::filesystem::system_complete(argv[0]).string());
+ }
+ }
+#endif // _WIN32
+
+ std::string lock_name = std::to_string(hashed_path);
+ 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.value() && GUI::wxGetApp().single_instance_checker()->IsAnotherRunning()) {
+#else // mac & linx
+ // get_lock() creates the lockfile therefore *cla.should_send is checked after
+ if (instance_check_internal::get_lock(lock_name + ".lock", data_dir() + "/cache/") && *cla.should_send) {
+#endif
+ instance_check_internal::send_message(cla.cl_string, lock_name);
+ BOOST_LOG_TRIVIAL(info) << "instance check: Another instance found. This instance will terminate.";
+ return true;
+ }
+ BOOST_LOG_TRIVIAL(info) << "instance check: Another instance not found or single-instance not set.";
+ return false;
+}
+
+#ifdef __APPLE__
+bool unlock_lockfile(const std::string& name, const std::string& path)
+{
+ std::string dest_dir = path + name;
+ //BOOST_LOG_TRIVIAL(debug) << "full lock path: " << dest_dir;
+ struct flock fl;
+ int fdlock;
+ fl.l_type = F_UNLCK;
+ fl.l_whence = SEEK_SET;
+ fl.l_start = 0;
+ fl.l_len = 1;
+ if ((fdlock = open(dest_dir.c_str(), O_WRONLY | O_CREAT, 0666)) == -1)
+ return false;
+
+ if (fcntl(fdlock, F_SETLK, &fl) == -1)
+ return false;
+
+ return true;
+}
+#endif //__APPLE__
+namespace GUI {
+
+wxDEFINE_EVENT(EVT_LOAD_MODEL_OTHER_INSTANCE, LoadFromOtherInstanceEvent);
+wxDEFINE_EVENT(EVT_INSTANCE_GO_TO_FRONT, InstanceGoToFrontEvent);
+
+void OtherInstanceMessageHandler::init(wxEvtHandler* callback_evt_handler)
+{
+ assert(!m_initialized);
+ assert(m_callback_evt_handler == nullptr);
+ if (m_initialized)
+ return;
+
+ m_initialized = true;
+ m_callback_evt_handler = callback_evt_handler;
+
+#if defined(__APPLE__)
+ this->register_for_messages(wxGetApp().get_instance_hash_string());
+#endif //__APPLE__
+
+#ifdef BACKGROUND_MESSAGE_LISTENER
+ m_thread = boost::thread((boost::bind(&OtherInstanceMessageHandler::listen, this)));
+#endif //BACKGROUND_MESSAGE_LISTENER
+}
+void OtherInstanceMessageHandler::shutdown(MainFrame* main_frame)
+{
+ BOOST_LOG_TRIVIAL(debug) << "message handler shutdown().";
+ assert(m_initialized);
+ if (m_initialized) {
+#ifdef _WIN32
+ HWND hwnd = main_frame->GetHandle();
+ RemoveProp(hwnd, L"Instance_Hash_Minor");
+ RemoveProp(hwnd, L"Instance_Hash_Major");
+#endif //_WIN32
+#if __APPLE__
+ //delete macos implementation
+ this->unregister_for_messages();
+#endif //__APPLE__
+#ifdef BACKGROUND_MESSAGE_LISTENER
+ if (m_thread.joinable()) {
+ // Stop the worker thread, if running.
+ {
+ // Notify the worker thread to cancel wait on detection polling.
+ std::lock_guard<std::mutex> lck(m_thread_stop_mutex);
+ m_stop = true;
+ }
+ m_thread_stop_condition.notify_all();
+ // Wait for the worker thread to stop.
+ m_thread.join();
+ m_stop = false;
+ }
+#endif //BACKGROUND_MESSAGE_LISTENER
+ m_callback_evt_handler = nullptr;
+ m_initialized = false;
+ }
+}
+
+#ifdef _WIN32
+void OtherInstanceMessageHandler::init_windows_properties(MainFrame* main_frame, size_t instance_hash)
+{
+ size_t minor_hash = instance_hash & 0xFFFFFFFF;
+ size_t major_hash = (instance_hash & 0xFFFFFFFF00000000) >> 32;
+ HWND hwnd = main_frame->GetHandle();
+ HANDLE handle_minor = UIntToPtr(minor_hash);
+ HANDLE handle_major = UIntToPtr(major_hash);
+ SetProp(hwnd, L"Instance_Hash_Minor", handle_minor);
+ SetProp(hwnd, L"Instance_Hash_Major", handle_major);
+ //BOOST_LOG_TRIVIAL(debug) << "window properties initialized " << instance_hash << " (" << minor_hash << " & "<< major_hash;
+}
+
+#if 0
+
+void OtherInstanceMessageHandler::print_window_info(HWND hwnd)
+{
+ std::wstring instance_hash = boost::nowide::widen(wxGetApp().get_instance_hash_string());
+ TCHAR wndText[1000];
+ TCHAR className[1000];
+ GetClassName(hwnd, className, 1000);
+ GetWindowText(hwnd, wndText, 1000);
+ std::wstring classNameString(className);
+ std::wstring wndTextString(wndText);
+ HANDLE handle = GetProp(hwnd, L"Instance_Hash_Minor");
+ size_t result = PtrToUint(handle);
+ handle = GetProp(hwnd, L"Instance_Hash_Major");
+ size_t r2 = PtrToUint(handle);
+ r2 = (r2 << 32);
+ result += r2;
+ BOOST_LOG_TRIVIAL(info) << "window info: " << result;
+}
+#endif //0
+#endif //WIN32
+namespace MessageHandlerInternal
+{
+ // returns ::path to possible model or empty ::path if input string is not existing path
+ static boost::filesystem::path get_path(const std::string& possible_path)
+ {
+ BOOST_LOG_TRIVIAL(debug) << "message part:" << possible_path;
+
+ if (possible_path.empty() || possible_path.size() < 3) {
+ BOOST_LOG_TRIVIAL(debug) << "empty";
+ return boost::filesystem::path();
+ }
+ if (boost::filesystem::exists(possible_path)) {
+ BOOST_LOG_TRIVIAL(debug) << "is path";
+ return boost::filesystem::path(possible_path);
+ } else if (possible_path[0] == '\"') {
+ if(boost::filesystem::exists(possible_path.substr(1, possible_path.size() - 2))) {
+ BOOST_LOG_TRIVIAL(debug) << "is path in quotes";
+ return boost::filesystem::path(possible_path.substr(1, possible_path.size() - 2));
+ }
+ }
+ BOOST_LOG_TRIVIAL(debug) << "is NOT path";
+ return boost::filesystem::path();
+ }
+} //namespace MessageHandlerInternal
+
+void OtherInstanceMessageHandler::handle_message(const std::string& message)
+{
+ BOOST_LOG_TRIVIAL(info) << "message from other instance: " << message;
+
+ std::vector<std::string> 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;
+ }
+
+ std::vector<boost::filesystem::path> 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()) {
+ //wxEvtHandler* evt_handler = wxGetApp().plater(); //assert here?
+ //if (evt_handler) {
+ wxPostEvent(m_callback_evt_handler, LoadFromOtherInstanceEvent(GUI::EVT_LOAD_MODEL_OTHER_INSTANCE, std::vector<boost::filesystem::path>(std::move(paths))));
+ //}
+ }
+}
+
+#ifdef BACKGROUND_MESSAGE_LISTENER
+
+namespace MessageHandlerDBusInternal
+{
+ //reply to introspect makes our DBus object visible for other programs like D-Feet
+ static void respond_to_introspect(DBusConnection *connection, DBusMessage *request)
+ {
+ DBusMessage *reply;
+ const char *introspection_data =
+ " <!DOCTYPE node PUBLIC \"-//freedesktop//DTD D-BUS Object Introspection 1.0//EN\" "
+ "\"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd\">"
+ " <!-- dbus-sharp 0.8.1 -->"
+ " <node>"
+ " <interface name=\"org.freedesktop.DBus.Introspectable\">"
+ " <method name=\"Introspect\">"
+ " <arg name=\"data\" direction=\"out\" type=\"s\" />"
+ " </method>"
+ " </interface>"
+ " <interface name=\"com.prusa3d.prusaslicer.InstanceCheck\">"
+ " <method name=\"AnotherInstance\">"
+ " <arg name=\"data\" direction=\"in\" type=\"s\" />"
+ " </method>"
+ " </interface>"
+ " </node>";
+
+ reply = dbus_message_new_method_return(request);
+ dbus_message_append_args(reply, DBUS_TYPE_STRING, &introspection_data, DBUS_TYPE_INVALID);
+ dbus_connection_send(connection, reply, NULL);
+ dbus_message_unref(reply);
+ }
+ //method AnotherInstance receives message from another PrusaSlicer instance
+ static void handle_method_another_instance(DBusConnection *connection, DBusMessage *request)
+ {
+ DBusError err;
+ char* text = nullptr;
+ wxEvtHandler* evt_handler;
+
+ dbus_error_init(&err);
+ dbus_message_get_args(request, &err, DBUS_TYPE_STRING, &text, DBUS_TYPE_INVALID);
+ if (dbus_error_is_set(&err)) {
+ BOOST_LOG_TRIVIAL(trace) << "Dbus method AnotherInstance received with wrong arguments.";
+ dbus_error_free(&err);
+ return;
+ }
+ wxGetApp().other_instance_message_handler()->handle_message(text);
+
+ evt_handler = wxGetApp().plater();
+ if (evt_handler) {
+ wxPostEvent(evt_handler, InstanceGoToFrontEvent(EVT_INSTANCE_GO_TO_FRONT));
+ }
+ }
+ //every dbus message received comes here
+ static DBusHandlerResult handle_dbus_object_message(DBusConnection *connection, DBusMessage *message, void *user_data)
+ {
+ const char* interface_name = dbus_message_get_interface(message);
+ const char* member_name = dbus_message_get_member(message);
+ std::string our_interface = "com.prusa3d.prusaslicer.InstanceCheck.Object" + wxGetApp().get_instance_hash_string();
+ BOOST_LOG_TRIVIAL(trace) << "DBus message received: interface: " << interface_name << ", member: " << member_name;
+ if (0 == strcmp("org.freedesktop.DBus.Introspectable", interface_name) && 0 == strcmp("Introspect", member_name)) {
+ respond_to_introspect(connection, message);
+ return DBUS_HANDLER_RESULT_HANDLED;
+ } else if (0 == strcmp(our_interface.c_str(), interface_name) && 0 == strcmp("AnotherInstance", member_name)) {
+ handle_method_another_instance(connection, message);
+ return DBUS_HANDLER_RESULT_HANDLED;
+ }
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ }
+} //namespace MessageHandlerDBusInternal
+
+void OtherInstanceMessageHandler::listen()
+{
+ DBusConnection* conn;
+ DBusError err;
+ int name_req_val;
+ DBusObjectPathVTable vtable;
+ std::string instance_hash = wxGetApp().get_instance_hash_string();
+ std::string interface_name = "com.prusa3d.prusaslicer.InstanceCheck.Object" + instance_hash;
+ std::string object_name = "/com/prusa3d/prusaslicer/InstanceCheck/Object" + instance_hash;
+
+ //BOOST_LOG_TRIVIAL(debug) << "init dbus listen " << interface_name << " " << object_name;
+ dbus_error_init(&err);
+
+ // connect to the bus and check for errors (use SESSION bus everywhere!)
+ conn = dbus_bus_get(DBUS_BUS_SESSION, &err);
+ if (dbus_error_is_set(&err)) {
+ BOOST_LOG_TRIVIAL(error) << "DBus Connection Error: "<< err.message;
+ BOOST_LOG_TRIVIAL(error) << "Dbus Messages listening terminating.";
+ dbus_error_free(&err);
+ return;
+ }
+ if (NULL == conn) {
+ BOOST_LOG_TRIVIAL(error) << "DBus Connection is NULL. Dbus Messages listening terminating.";
+ return;
+ }
+
+ // request our name on the bus and check for errors
+ name_req_val = dbus_bus_request_name(conn, interface_name.c_str(), DBUS_NAME_FLAG_REPLACE_EXISTING , &err);
+ if (dbus_error_is_set(&err)) {
+ BOOST_LOG_TRIVIAL(error) << "DBus Request name Error: "<< err.message;
+ BOOST_LOG_TRIVIAL(error) << "Dbus Messages listening terminating.";
+ dbus_error_free(&err);
+ dbus_connection_unref(conn);
+ return;
+ }
+ if (DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER != name_req_val) {
+ BOOST_LOG_TRIVIAL(error) << "Not primary owner of DBus name - probably another PrusaSlicer instance is running.";
+ BOOST_LOG_TRIVIAL(error) << "Dbus Messages listening terminating.";
+ dbus_connection_unref(conn);
+ return;
+ }
+
+ // Set callbacks. Unregister function should not be nessary.
+ vtable.message_function = MessageHandlerDBusInternal::handle_dbus_object_message;
+ vtable.unregister_function = NULL;
+
+ // register new object - this is our access to DBus
+ dbus_connection_try_register_object_path(conn, object_name.c_str(), &vtable, NULL, &err);
+ if ( dbus_error_is_set(&err) ) {
+ BOOST_LOG_TRIVIAL(error) << "DBus Register object Error: "<< err.message;
+ BOOST_LOG_TRIVIAL(error) << "Dbus Messages listening terminating.";
+ dbus_connection_unref(conn);
+ dbus_error_free(&err);
+ return;
+ }
+
+ BOOST_LOG_TRIVIAL(trace) << "Dbus object "<< object_name <<" registered. Starting listening for messages.";
+
+ for (;;) {
+ // Wait for 1 second
+ // Cancellable.
+ {
+ std::unique_lock<std::mutex> lck(m_thread_stop_mutex);
+ m_thread_stop_condition.wait_for(lck, std::chrono::seconds(1), [this] { return m_stop; });
+ }
+ if (m_stop)
+ // Stop the worker thread.
+
+ break;
+ //dispatch should do all the work with incoming messages
+ //second parameter is blocking time that funciton waits for new messages
+ //that is handled here with our own event loop above
+ dbus_connection_read_write_dispatch(conn, 0);
+ }
+
+ dbus_connection_unref(conn);
+}
+#endif //BACKGROUND_MESSAGE_LISTENER
+} // namespace GUI
+} // namespace Slic3r