diff --git a/CMakeLists.txt b/CMakeLists.txt index 00c7e171f37..23ec0717c56 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -475,6 +475,21 @@ if(OpenVDB_FOUND) slic3r_remap_configs(Blosc::blosc RelWithDebInfo Release) endif() +find_path(SPNAV_INCLUDE_DIR spnav.h) +if (SPNAV_INCLUDE_DIR) + find_library(HAVE_SPNAV spnav) + if (HAVE_SPNAV) + add_definitions(-DHAVE_SPNAV) + add_library(libspnav SHARED IMPORTED) + target_link_libraries(libspnav INTERFACE spnav) + message(STATUS "SPNAV library found") + else() + message(STATUS "SPNAV library NOT found, Spacenavd not supported") + endif() +else() + message(STATUS "SPNAV library NOT found, Spacenavd not supported") +endif() + set(TOP_LEVEL_PROJECT_DIR ${PROJECT_SOURCE_DIR}) function(prusaslicer_copy_dlls target) if ("${CMAKE_SIZEOF_VOID_P}" STREQUAL "8") diff --git a/src/slic3r/CMakeLists.txt b/src/slic3r/CMakeLists.txt index 3beacae6895..4824f854141 100644 --- a/src/slic3r/CMakeLists.txt +++ b/src/slic3r/CMakeLists.txt @@ -283,6 +283,10 @@ if (SLIC3R_PCH AND NOT SLIC3R_SYNTAXONLY) add_precompiled_header(libslic3r_gui pchheader.hpp FORCEINCLUDE) endif () +if (HAVE_SPNAV) + target_link_libraries(libslic3r_gui spnav) +endif() + # We need to implement some hacks for wxWidgets and touch the underlying GTK # layer and sub-libraries. This forces us to use the include locations and # link these libraries. diff --git a/src/slic3r/GUI/Mouse3DController.cpp b/src/slic3r/GUI/Mouse3DController.cpp index fb14d9676bf..8afe4925321 100644 --- a/src/slic3r/GUI/Mouse3DController.cpp +++ b/src/slic3r/GUI/Mouse3DController.cpp @@ -17,7 +17,9 @@ #include //unofficial linux lib -//#include +#ifdef HAVE_SPNAV +#include +#endif // WARN: If updating these lists, please also update resources/udev/90-3dconnexion.rules @@ -709,6 +711,31 @@ void Mouse3DController::shutdown() // Main routine of the worker thread. void Mouse3DController::run() { +#ifdef HAVE_SPNAV + if (spnav_open() == -1) { + // Give up. + BOOST_LOG_TRIVIAL(error) << "Unable to open connection to spacenavd"; + return; + } + m_connected = true; + + for (;;) { + { + std::scoped_lock lock(m_params_ui_mutex); + if (m_stop) + break; + if (m_params_ui_changed) { + m_params = m_params_ui; + m_params_ui_changed = false; + } + } + this->collect_input(); + } + + m_connected = false; + // Finalize the spnav library + spnav_close(); +#else // Initialize the hidapi library int res = hid_init(); if (res != 0) { @@ -753,6 +780,7 @@ void Mouse3DController::run() // Finalize the hidapi library hid_exit(); +#endif } bool Mouse3DController::connect_device() @@ -1042,8 +1070,51 @@ void Mouse3DController::disconnect_device() } } +// Convert a signed 16bit word from a 3DConnexion mouse HID packet into a double coordinate, apply a dead zone. +static double convert_spnav_input(int value) +{ + return (double)value/100; +} + void Mouse3DController::collect_input() { +#ifdef HAVE_SPNAV + // Read packet, block maximum 100 ms. That means when closing the application, closing the application will be delayed by 100 ms. + int fd = spnav_fd(); + + if (fd != -1) { + fd_set fds; + struct timeval tv = {.tv_sec = 0, .tv_usec = 100000}; + + FD_ZERO(&fds); + FD_SET(fd, &fds); + if (select(fd + 1, &fds, NULL, NULL, &tv) == 1) { + spnav_event ev = {}; + switch (spnav_poll_event(&ev)) { + case SPNAV_EVENT_MOTION: { + Vec3d translation(-convert_spnav_input(ev.motion.x), convert_spnav_input(ev.motion.y), -convert_spnav_input(ev.motion.z)); + if (!translation.isApprox(Vec3d::Zero())) { +std::cout << "Motion: X: " << ev.motion.x << ", Y: " << ev.motion.y << ", Z: " << ev.motion.z << std::endl; + m_state.append_translation(translation, m_params.input_queue_max_size); + } + Vec3f rotation(convert_spnav_input(ev.motion.rx), convert_spnav_input(ev.motion.ry), -convert_spnav_input(ev.motion.rz)); + if (!rotation.isApprox(Vec3f::Zero())) { +std::cout << "Motion: rX: " << ev.motion.rx << ", rY: " << ev.motion.ry << ", rZ: " << ev.motion.rz << std::endl; + m_state.append_rotation(rotation, m_params.input_queue_max_size); + } + break; + } + case SPNAV_EVENT_BUTTON: + if (ev.button.press) + m_state.append_button((unsigned int)ev.button.bnum, m_params.input_queue_max_size); + break; + } + wxGetApp().plater()->set_current_canvas_as_dirty(); + // ask for an idle event to update 3D scene + wxWakeUpIdle(); + } + } +#else DataPacketRaw packet = { 0 }; // Read packet, block maximum 100 ms. That means when closing the application, closing the application will be delayed by 100 ms. int res = hid_read_timeout(m_device, packet.data(), packet.size(), 100); @@ -1052,6 +1123,7 @@ void Mouse3DController::collect_input() this->disconnect_device(); } else this->handle_input(packet, res, m_params, m_state); +#endif } #ifdef _WIN32 diff --git a/src/slic3r/GUI/RemovableDriveManager.cpp b/src/slic3r/GUI/RemovableDriveManager.cpp index d226e428882..edb9e807df3 100644 --- a/src/slic3r/GUI/RemovableDriveManager.cpp +++ b/src/slic3r/GUI/RemovableDriveManager.cpp @@ -201,9 +201,7 @@ namespace search_for_drives_internal struct stat buf; stat(path.c_str(), &buf); uid_t uid = buf.st_uid; - std::string username(std::getenv("USER")); - struct passwd *pw = getpwuid(uid); - if (pw != 0 && pw->pw_name == username) + if (getuid() == uid) out.emplace_back(DriveData{ boost::filesystem::basename(boost::filesystem::path(path)), path }); } } @@ -243,7 +241,7 @@ std::vector RemovableDriveManager::search_for_removable_drives() cons search_for_drives_internal::search_path("/media/*", "/media", current_drives); //search_path("/Volumes/*", "/Volumes"); - std::string path(std::getenv("USER")); + std::string path = wxGetUserId().ToUTF8().data(); std::string pp(path); //search /media/USERNAME/* folder