diff --git a/src/slic3r/CMakeLists.txt b/src/slic3r/CMakeLists.txt index 7f06cac29..03413f933 100644 --- a/src/slic3r/CMakeLists.txt +++ b/src/slic3r/CMakeLists.txt @@ -111,6 +111,8 @@ set(SLIC3R_GUI_SOURCES GUI/WipeTowerDialog.hpp GUI/RammingChart.cpp GUI/RammingChart.hpp + GUI/RemovableDriveManager.cpp + GUI/RemovableDriveManager.hpp GUI/BonjourDialog.cpp GUI/BonjourDialog.hpp GUI/ButtonsDescription.cpp diff --git a/src/slic3r/GUI/AppConfig.cpp b/src/slic3r/GUI/AppConfig.cpp index 60f4edf47..16f045966 100644 --- a/src/slic3r/GUI/AppConfig.cpp +++ b/src/slic3r/GUI/AppConfig.cpp @@ -357,6 +357,7 @@ void AppConfig::update_skein_dir(const std::string &dir) std::string AppConfig::get_last_output_dir(const std::string &alt) const { + const auto it = m_storage.find(""); if (it != m_storage.end()) { const auto it2 = it->second.find("last_output_path"); diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index a74c6b0c0..c36c2748d 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -46,6 +46,7 @@ #include "SysInfoDialog.hpp" #include "KBShortcutsDialog.hpp" #include "UpdateDialogs.hpp" +#include "RemovableDriveManager.hpp" #ifdef __WXMSW__ #include @@ -269,6 +270,8 @@ bool GUI_App::on_init_inner() this->obj_manipul()->update_if_dirty(); + RemovableDriveManager::get_instance().update(wxGetLocalTime()); + // Preset updating & Configwizard are done after the above initializations, // and after MainFrame is created & shown. // The extra CallAfter() is needed because of Mac, where this is the only way diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 169cbcb60..5d967cb6c 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -77,6 +77,7 @@ #include "../Utils/FixModelByWin10.hpp" #include "../Utils/UndoRedo.hpp" #include "../Utils/Thread.hpp" +#include "RemovableDriveManager.hpp" #include // Needs to be last because reasons :-/ #include "WipeTowerDialog.hpp" @@ -4555,7 +4556,13 @@ void Plater::export_gcode() } default_output_file = fs::path(Slic3r::fold_utf8_to_ascii(default_output_file.string())); auto start_dir = wxGetApp().app_config->get_last_output_dir(default_output_file.parent_path().string()); - + if (GUI::RemovableDriveManager::get_instance().update()) + { + if (!RemovableDriveManager::get_instance().is_path_on_removable_drive(start_dir)) + { + start_dir = RemovableDriveManager::get_instance().get_last_drive_path(); + } + } wxFileDialog dlg(this, (printer_technology() == ptFFF) ? _(L("Save G-code file as:")) : _(L("Save SL1 file as:")), start_dir, from_path(default_output_file.filename()), diff --git a/src/slic3r/GUI/RemovableDriveManager.cpp b/src/slic3r/GUI/RemovableDriveManager.cpp new file mode 100644 index 000000000..9b3020e79 --- /dev/null +++ b/src/slic3r/GUI/RemovableDriveManager.cpp @@ -0,0 +1,339 @@ +#include "RemovableDriveManager.hpp" +#include +#include "boost/nowide/convert.hpp" + +#if _WIN32 +#include +#include +#include +#include +DEFINE_GUID(GUID_DEVINTERFACE_USB_DEVICE, + 0xA5DCBF10L, 0x6530, 0x11D2, 0x90, 0x1F, 0x00, 0xC0, 0x4F, 0xB9, 0x51, 0xED); +#else +//linux includes +#include +#include +#include +#include +#include +#include +#endif + +namespace Slic3r { +namespace GUI { +//std::vector RemovableDriveManager::m_current_drives; +//std::vector> RemovableDriveManager::m_callbacks; + + +#if _WIN32 +void RemovableDriveManager::search_for_drives() +{ + m_current_drives.clear(); + m_current_drives.reserve(26); + DWORD drives_mask = GetLogicalDrives(); + for (size_t i = 0; i < 26; i++) + { + if(drives_mask & (1 << i)) + { + std::string path (1,(char)('A' + i)); + path+=":"; + UINT drive_type = GetDriveTypeA(path.c_str()); + //std::cout << "found drive" << (char)('A' + i) << ": type:" < 0) + { + path += "\\"; + m_current_drives.push_back(DriveData(boost::nowide::narrow(volume_name), path)); + } + } + } + } + } + } + //std::cout << "found drives:" << m_current_drives.size() << "\n"; +} +void RemovableDriveManager::eject_drive(const std::string &path) +{ + + //if (!update() || !is_drive_mounted(path)) + if(m_current_drives.empty()) + return; + for (auto it = m_current_drives.begin(); it != m_current_drives.end(); ++it) + { + if ((*it).path == path) + { + std::string mpath = "\\\\.\\" + path; + mpath = mpath.substr(0, mpath.size() - 1); + std::cout << "Ejecting " << mpath << "\n"; + HANDLE handle = CreateFileA(mpath.c_str(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, 0, nullptr); + if (handle == INVALID_HANDLE_VALUE) + { + std::cerr << "Ejecting " << mpath << " failed " << GetLastError() << " \n"; + return; + } + DWORD deviceControlRetVal(0); + BOOL error = DeviceIoControl(handle, IOCTL_STORAGE_EJECT_MEDIA, nullptr, 0, nullptr, 0, &deviceControlRetVal, nullptr); + CloseHandle(handle); + if (error == 0) + { + std::cerr << "Ejecting " << mpath << " failed " << deviceControlRetVal << " " << GetLastError() << " \n"; + return; + } + + + m_current_drives.erase(it); + break; + } + } +} +bool RemovableDriveManager::is_path_on_removable_drive(const std::string &path) +{ + if (m_current_drives.empty()) + return false; + int letter = PathGetDriveNumberA(path.c_str()); + for (auto it = m_current_drives.begin(); it != m_current_drives.end(); ++it) + { + char drive = (*it).path[0]; + if (drive == ('A' + letter)) + return true; + } + return false; +} +void RemovableDriveManager::register_window() +{ + /* + WNDCLASSEX wndClass; + + wndClass.cbSize = sizeof(WNDCLASSEX); + wndClass.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW; + wndClass.hInstance = reinterpret_cast(GetModuleHandle(0)); + wndClass.lpfnWndProc = reinterpret_cast(WinProcCallback); + wndClass.cbClsExtra = 0; + wndClass.cbWndExtra = 0; + wndClass.hIcon = LoadIcon(0, IDI_APPLICATION); + wndClass.hbrBackground = CreateSolidBrush(RGB(192, 192, 192)); + wndClass.hCursor = LoadCursor(0, IDC_ARROW); + wndClass.lpszClassName = L"SlicerWindowClass"; + wndClass.lpszMenuName = NULL; + wndClass.hIconSm = wndClass.hIcon; + */ +} +#else +void RemovableDriveManager::search_for_drives() +{ + + m_current_drives.clear(); + m_current_drives.reserve(26); + + //search /media/* folder + search_path("/media/*", "/media"); + + std::string path(std::getenv("USER")); + std::string pp(path); + //std::cout << "user: "<< path << "\n"; + if(path == "root"){ //if program is run with sudo, we have to search for all users + while (true) { + passwd* entry = getpwent(); + if (!entry) { + break; + } + path = entry->pw_name; + pp = path; + //search /media/USERNAME/* folder + pp = "/media/"+pp; + path = "/media/" + path + "/*"; + search_path(path, pp); + + //search /run/media/USERNAME/* folder + path = "/run" + path; + pp = "/run"+pp; + search_path(path, pp); + } + endpwent(); + }else + { + //search /media/USERNAME/* folder + pp = "/media/"+pp; + path = "/media/" + path + "/*"; + search_path(path, pp); + + //search /run/media/USERNAME/* folder + path = "/run" + path; + pp = "/run"+pp; + search_path(path, pp); + + } + + //std::cout << "found drives:" < RemovableDriveManager::get_all_drives() +{ + return m_current_drives; +} +void RemovableDriveManager::check_and_notify() +{ + //std::cout<<"drives count: "< callback) +{ + m_callbacks.push_back(callback); +} +void RemovableDriveManager::print() +{ + std::cout << "notified\n"; +} +}}//namespace Slicer::Gui:: \ No newline at end of file diff --git a/src/slic3r/GUI/RemovableDriveManager.hpp b/src/slic3r/GUI/RemovableDriveManager.hpp new file mode 100644 index 000000000..b465b1c1b --- /dev/null +++ b/src/slic3r/GUI/RemovableDriveManager.hpp @@ -0,0 +1,50 @@ +#ifndef slic3r_GUI_RemovableDriveManager_hpp_ +#define slic3r_GUI_RemovableDriveManager_hpp_ + +#include +#include + +namespace Slic3r { +namespace GUI { +struct DriveData +{ + std::string name; + std::string path; + DriveData(std::string n, std::string p):name(n),path(p){} +}; +class RemovableDriveManager +{ +public: + static RemovableDriveManager& get_instance() + { + static RemovableDriveManager instance; + return instance; + } + RemovableDriveManager(RemovableDriveManager const&) = delete; + void operator=(RemovableDriveManager const&) = delete; + + //update() searches for removable devices, returns false if empty. + bool update(long time = 0); //time = 0 is forced update + bool is_drive_mounted(const std::string &path); + void eject_drive(const std::string &path); + std::string get_last_drive_path(); + std::vector get_all_drives(); + bool is_path_on_removable_drive(const std::string &path); + void add_callback(std::function callback); + void print(); +private: + RemovableDriveManager():m_drives_count(0){} + void search_for_drives(); + void check_and_notify(); + std::vector m_current_drives; + std::vector> m_callbacks; + size_t m_drives_count; +#if _WIN32 + void register_window(); +#else + void search_path(const std::string &path, const std::string &parent_path); + bool compare_filesystem_id(const std::string &path_a, const std::string &path_b); +#endif +}; +}} +#endif \ No newline at end of file