OrcaSlicer latest
OrcaSlicer
Loading...
Searching...
No Matches
Slic3r::GUI::RemovableDriveManager Class Reference

#include </home/runner/work/OrcaSlicer/OrcaSlicer/src/slic3r/GUI/RemovableDriveManager.hpp>

Collaboration diagram for Slic3r::GUI::RemovableDriveManager:

Classes

struct  RemovableDrivesStatus

Public Member Functions

 RemovableDriveManager ()=default
 RemovableDriveManager (RemovableDriveManager const &)=delete
void operator= (RemovableDriveManager const &)=delete
 ~RemovableDriveManager ()
void init (wxEvtHandler *callback_evt_handler)
void shutdown ()
std::string get_removable_drive_path (const std::string &path)
bool is_path_on_removable_drive (const std::string &path)
bool set_and_verify_last_save_path (const std::string &path)
void eject_drive ()
RemovableDrivesStatus status ()
void update ()
void set_exporting_finished (bool b)

Private Member Functions

void thread_proc ()
std::vector< DriveData > search_for_removable_drives () const
std::string get_removable_drive_from_path (const std::string &path)
std::vector< DriveData >::const_iterator find_last_save_path_drive_data () const

Private Attributes

bool m_initialized { false }
wxEvtHandler * m_callback_evt_handler { nullptr }
boost::thread m_thread
std::condition_variable m_thread_stop_condition
std::mutex m_thread_stop_mutex
bool m_stop { false }
std::vector< DriveData > m_current_drives
std::mutex m_drives_mutex
std::mutex m_inside_update_mutex
std::string m_last_save_path
bool m_exporting_finished

Detailed Description


Class Documentation

◆ Slic3r::GUI::RemovableDriveManager::RemovableDrivesStatus

struct Slic3r::GUI::RemovableDriveManager::RemovableDrivesStatus
Class Members
bool has_eject { false }
bool has_removable_drives { false }

Constructor & Destructor Documentation

◆ RemovableDriveManager() [1/2]

Slic3r::GUI::RemovableDriveManager::RemovableDriveManager ( )
default

Referenced by RemovableDriveManager(), and operator=().

Here is the caller graph for this function:

◆ RemovableDriveManager() [2/2]

Slic3r::GUI::RemovableDriveManager::RemovableDriveManager ( RemovableDriveManager const & )
delete

References RemovableDriveManager().

Here is the call graph for this function:

◆ ~RemovableDriveManager()

Slic3r::GUI::RemovableDriveManager::~RemovableDriveManager ( )
inline
55{ /*assert(! m_initialized);*/ }

Member Function Documentation

◆ eject_drive()

void Slic3r::GUI::RemovableDriveManager::eject_drive ( )
282{
283 if (m_last_save_path.empty())
284 return;
285
286#ifndef REMOVABLE_DRIVE_MANAGER_OS_CALLBACKS
287 this->update();
288#endif // REMOVABLE_DRIVE_MANAGER_OS_CALLBACKS
289#if __APPLE__
290 // If eject is still pending on the eject thread, wait until it finishes.
291 //FIXME while waiting for the eject thread to finish, the main thread is not pumping Cocoa messages, which may lead
292 // to blocking by the diskutil tool for a couple (up to 10) seconds. This is likely not critical, as the eject normally
293 // finishes quickly.
294 this->eject_thread_finish();
295#endif
296
297 BOOST_LOG_TRIVIAL(info) << "Ejecting started";
298
299 DriveData drive_data;
300 {
301 std::scoped_lock<std::mutex> lock(m_drives_mutex);
302 auto it_drive_data = this->find_last_save_path_drive_data();
303 if (it_drive_data == m_current_drives.end())
304 return;
305 drive_data = *it_drive_data;
306 }
307
308 std::string correct_path(m_last_save_path);
309#if __APPLE__
310 // On Apple, run the eject asynchronously on a worker thread, see the discussion at GH issue #4844.
311 m_eject_thread = new boost::thread([this, correct_path, drive_data]()
312#endif
313 {
314 //std::cout<<"Ejecting "<<(*it).name<<" from "<< correct_path<<"\n";
315 // there is no usable command in c++ so terminal command is used instead
316 // but neither triggers "succesful safe removal messege"
317
318 BOOST_LOG_TRIVIAL(info) << "Ejecting started";
319 boost::process::ipstream istd_err;
320 boost::process::child child(
321#if __APPLE__
322 boost::process::search_path("diskutil"), "eject", correct_path.c_str(), (boost::process::std_out & boost::process::std_err) > istd_err);
323 //Another option how to eject at mac. Currently not working.
324 //used insted of system() command;
325 //this->eject_device(correct_path);
326#else
327 boost::process::search_path("umount"), correct_path.c_str(), (boost::process::std_out & boost::process::std_err) > istd_err);
328#endif
329 std::string line;
330 while (child.running() && std::getline(istd_err, line)) {
331 BOOST_LOG_TRIVIAL(trace) << line;
332 }
333 // wait for command to finnish (blocks ui thread)
334 std::error_code ec;
335 child.wait(ec);
336 bool success = false;
337 if (ec) {
338 // The wait call can fail
339 // It can happen even in cases where the eject is sucessful, but better report it as failed.
340 // We did not find a way to reliably retrieve the exit code of the process.
341 BOOST_LOG_TRIVIAL(error) << "boost::process::child::wait() failed during Ejection. State of Ejection is unknown. Error code: " << ec.value();
342 } else {
343 int err = child.exit_code();
344 if (err) {
345 BOOST_LOG_TRIVIAL(error) << "Ejecting failed. Exit code: " << err;
346 } else {
347 BOOST_LOG_TRIVIAL(info) << "Ejecting finished";
348 success = true;
349 }
350 }
353 wxPostEvent(m_callback_evt_handler, RemovableDriveEjectEvent(EVT_REMOVABLE_DRIVE_EJECTED, std::pair<DriveData, bool>(drive_data, success)));
354 if (success) {
355 // Remove the drive_data from m_current drives, searching by value, not by pointer, as m_current_drives may get modified during
356 // asynchronous execution on m_eject_thread.
357 std::scoped_lock<std::mutex> lock(m_drives_mutex);
358 auto it = std::find(m_current_drives.begin(), m_current_drives.end(), drive_data);
359 if (it != m_current_drives.end())
360 m_current_drives.erase(it);
361 }
362 }
363#if __APPLE__
364 );
365#endif // __APPLE__
366}
std::vector< DriveData > m_current_drives
Definition RemovableDriveManager.hpp:116
void update()
Definition RemovableDriveManager.cpp:491
std::mutex m_drives_mutex
Definition RemovableDriveManager.hpp:117
wxEvtHandler * m_callback_evt_handler
Definition RemovableDriveManager.hpp:97
std::vector< DriveData >::const_iterator find_last_save_path_drive_data() const
Definition RemovableDriveManager.cpp:547
std::string m_last_save_path
Definition RemovableDriveManager.hpp:126
Event< std::pair< DriveData, bool > > RemovableDriveEjectEvent
Definition RemovableDriveManager.hpp:38
void trace(unsigned int level, const char *message)
Definition utils.cpp:247
@ lock
Definition GLGizmoEmboss.cpp:209

References find_last_save_path_drive_data(), m_callback_evt_handler, m_current_drives, m_drives_mutex, m_last_save_path, Slic3r::trace(), and update().

Here is the call graph for this function:

◆ find_last_save_path_drive_data()

std::vector< DriveData >::const_iterator Slic3r::GUI::RemovableDriveManager::find_last_save_path_drive_data ( ) const
private
548{
550 [this](const DriveData &data){ return data.path < m_last_save_path; },
551 [this](const DriveData &data){ return data.path == m_last_save_path; });
552}
ForwardIt binary_find_by_predicate(ForwardIt first, ForwardIt last, LowerThanKeyPredicate lower_thank_key, EqualToKeyPredicate equal_to_key)
Definition libslic3r.h:280

References Slic3r::binary_find_by_predicate(), and m_current_drives.

Referenced by eject_drive(), and status().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ get_removable_drive_from_path()

std::string Slic3r::GUI::RemovableDriveManager::get_removable_drive_from_path ( const std::string & path)
private
385{
386 std::string new_path(path);
387 if (!boost::filesystem::is_directory(path)) {
388 std::size_t found = path.find_last_of("/");
389 if (found != std::string::npos)
390 new_path.erase(found);
391 }
392
393 // check if same filesystem
394 std::scoped_lock<std::mutex> lock(m_drives_mutex);
395 for (const DriveData &drive_data : m_current_drives)
396 if (search_for_drives_internal::compare_filesystem_id(new_path, drive_data.path))
397 return drive_data.path;
398 return std::string();
399}
static bool compare_filesystem_id(const std::string &path_a, const std::string &path_b)
Definition RemovableDriveManager.cpp:188

References Slic3r::GUI::search_for_drives_internal::compare_filesystem_id(), m_current_drives, and m_drives_mutex.

Referenced by set_and_verify_last_save_path().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ get_removable_drive_path()

std::string Slic3r::GUI::RemovableDriveManager::get_removable_drive_path ( const std::string & path)
369{
370#ifndef REMOVABLE_DRIVE_MANAGER_OS_CALLBACKS
371 this->update();
372#endif // REMOVABLE_DRIVE_MANAGER_OS_CALLBACKS
373
374 std::size_t found = path.find_last_of("/");
375 std::string new_path = found == path.size() - 1 ? path.substr(0, found) : path;
376
377 std::scoped_lock<std::mutex> lock(m_drives_mutex);
378 for (const DriveData &data : m_current_drives)
380 return path;
381 return m_current_drives.empty() ? std::string() : m_current_drives.front().path;
382}

References Slic3r::GUI::search_for_drives_internal::compare_filesystem_id(), m_current_drives, m_drives_mutex, and update().

Referenced by Slic3r::GUI::Plater::export_gcode(), and is_path_on_removable_drive().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ init()

void Slic3r::GUI::RemovableDriveManager::init ( wxEvtHandler * callback_evt_handler)
403{
404 //no need use assert
405 assert(! m_initialized);
406 assert(m_callback_evt_handler == nullptr);
407
408 if (m_initialized)
409 return;
410
411 m_initialized = true;
412 m_callback_evt_handler = callback_evt_handler;
413
414#if __APPLE__
415 this->register_window_osx();
416#endif
417
418#ifdef REMOVABLE_DRIVE_MANAGER_OS_CALLBACKS
419 this->update();
420#else // REMOVABLE_DRIVE_MANAGER_OS_CALLBACKS
421 // Don't call update() manually, as the UI triggered APIs call this->update() anyways.
422 m_thread = boost::thread((boost::bind(&RemovableDriveManager::thread_proc, this)));
423#endif // REMOVABLE_DRIVE_MANAGER_OS_CALLBACKS
424}
void thread_proc()
Definition RemovableDriveManager.cpp:519
bool m_initialized
Definition RemovableDriveManager.hpp:96
boost::thread m_thread
Definition RemovableDriveManager.hpp:102

References m_callback_evt_handler, m_initialized, m_thread, thread_proc(), and update().

Here is the call graph for this function:

◆ is_path_on_removable_drive()

bool Slic3r::GUI::RemovableDriveManager::is_path_on_removable_drive ( const std::string & path)
inline
66{ return this->get_removable_drive_path(path) == path; }
std::string get_removable_drive_path(const std::string &path)
Definition RemovableDriveManager.cpp:368

References get_removable_drive_path().

Referenced by Slic3r::GUI::Plater::export_gcode_3mf().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ operator=()

void Slic3r::GUI::RemovableDriveManager::operator= ( RemovableDriveManager const & )
delete

References RemovableDriveManager().

Here is the call graph for this function:

◆ search_for_removable_drives()

std::vector< DriveData > Slic3r::GUI::RemovableDriveManager::search_for_removable_drives ( ) const
private
242{
243 std::vector<DriveData> current_drives;
244
245#if __APPLE__
246
247 this->list_devices(current_drives);
248
249#else
250
252 // ChromeOS specific: search /mnt/chromeos/removable/* folder
253 search_for_drives_internal::search_path("/mnt/chromeos/removable/*", "/mnt/chromeos/removable", current_drives);
254 } else {
255 //search /media/* folder
256 search_for_drives_internal::search_path("/media/*", "/media", current_drives);
257
258 //search_path("/Volumes/*", "/Volumes");
259 std::string path = wxGetUserId().ToUTF8().data();
260 std::string pp(path);
261
262 //search /media/USERNAME/* folder
263 pp = "/media/"+pp;
264 path = "/media/" + path + "/*";
265 search_for_drives_internal::search_path(path, pp, current_drives);
266
267 //search /run/media/USERNAME/* folder
268 path = "/run" + path;
269 pp = "/run"+pp;
270 search_for_drives_internal::search_path(path, pp, current_drives);
271 }
272
273#endif
274
275 return current_drives;
276}
static void search_path(const std::string &path, const std::string &parent_path, std::vector< DriveData > &out)
Definition RemovableDriveManager.cpp:224
@ LinuxOnChromium
Definition Platform.hpp:24
PlatformFlavor platform_flavor()
Definition Platform.cpp:108

References Slic3r::LinuxOnChromium, Slic3r::platform_flavor(), and Slic3r::GUI::search_for_drives_internal::search_path().

Referenced by update().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ set_and_verify_last_save_path()

bool Slic3r::GUI::RemovableDriveManager::set_and_verify_last_save_path ( const std::string & path)
456{
457#ifndef REMOVABLE_DRIVE_MANAGER_OS_CALLBACKS
458 this->update();
459#endif // REMOVABLE_DRIVE_MANAGER_OS_CALLBACKS
460
461#ifdef __APPLE__
462 m_last_save_path = path;
463#else
465#endif
466
467
468 m_exporting_finished = false;
469 return ! m_last_save_path.empty();
470}
bool m_exporting_finished
Definition RemovableDriveManager.hpp:129
std::string get_removable_drive_from_path(const std::string &path)
Definition RemovableDriveManager.cpp:384

References get_removable_drive_from_path(), m_exporting_finished, m_last_save_path, and update().

Referenced by Slic3r::GUI::Plater::export_gcode().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ set_exporting_finished()

void Slic3r::GUI::RemovableDriveManager::set_exporting_finished ( bool b)
inline

◆ shutdown()

void Slic3r::GUI::RemovableDriveManager::shutdown ( )
427{
428#if __APPLE__
429 // If eject is still pending on the eject thread, wait until it finishes.
430 //FIXME while waiting for the eject thread to finish, the main thread is not pumping Cocoa messages, which may lead
431 // to blocking by the diskutil tool for a couple (up to 10) seconds. This is likely not critical, as the eject normally
432 // finishes quickly.
433 this->eject_thread_finish();
434#endif
435
436#ifndef REMOVABLE_DRIVE_MANAGER_OS_CALLBACKS
437 if (m_thread.joinable()) {
438 // Stop the worker thread, if running.
439 {
440 // Notify the worker thread to cancel wait on detection polling.
441 std::lock_guard<std::mutex> lck(m_thread_stop_mutex);
442 m_stop = true;
443 }
444 m_thread_stop_condition.notify_all();
445 // Wait for the worker thread to stop.
446 m_thread.join();
447 m_stop = false;
448 }
449#endif // REMOVABLE_DRIVE_MANAGER_OS_CALLBACKS
450
451 m_initialized = false;
452 m_callback_evt_handler = nullptr;
453}
std::condition_variable m_thread_stop_condition
Definition RemovableDriveManager.hpp:103
std::mutex m_thread_stop_mutex
Definition RemovableDriveManager.hpp:104
bool m_stop
Definition RemovableDriveManager.hpp:105

References m_callback_evt_handler, m_initialized, m_stop, m_thread, m_thread_stop_condition, and m_thread_stop_mutex.

Referenced by Slic3r::GUI::GUI_App::shutdown().

Here is the caller graph for this function:

◆ status()

RemovableDriveManager::RemovableDrivesStatus Slic3r::GUI::RemovableDriveManager::status ( )
473{
474
475 RemovableDriveManager::RemovableDrivesStatus out;
476 {
477 std::scoped_lock<std::mutex> lock(m_drives_mutex);
478 out.has_eject =
479 // Cannot control eject on Chromium.
482 out.has_removable_drives = ! m_current_drives.empty();
483 }
484 if (! out.has_eject)
485 m_last_save_path.clear();
486 out.has_eject = out.has_eject && m_exporting_finished;
487 return out;
488}

References find_last_save_path_drive_data(), Slic3r::GUI::RemovableDriveManager::RemovableDrivesStatus::has_eject, Slic3r::GUI::RemovableDriveManager::RemovableDrivesStatus::has_removable_drives, Slic3r::LinuxOnChromium, m_current_drives, m_drives_mutex, m_exporting_finished, m_last_save_path, and Slic3r::platform_flavor().

Here is the call graph for this function:

◆ thread_proc()

void Slic3r::GUI::RemovableDriveManager::thread_proc ( )
private
520{
521 // Signal the worker thread to update initially.
522#ifdef _WIN32
523 m_wakeup = true;
524#endif // _WIN32
525
526 for (;;) {
527 // Wait for 2 seconds before running the disk enumeration.
528 // Cancellable.
529 {
530 std::unique_lock<std::mutex> lck(m_thread_stop_mutex);
531#ifdef _WIN32
532 // Reacting to updates by WM_DEVICECHANGE and WM_USER_MEDIACHANGED
533 m_thread_stop_condition.wait(lck, [this]{ return m_stop || m_wakeup; });
534#else
535 m_thread_stop_condition.wait_for(lck, std::chrono::seconds(2), [this]{ return m_stop; });
536#endif
537 }
538 if (m_stop)
539 // Stop the worker thread.
540 break;
541 // Update m_current drives and send out update events.
542 this->update();
543 }
544}

References m_stop, m_thread_stop_condition, m_thread_stop_mutex, and update().

Referenced by init().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ update()

void Slic3r::GUI::RemovableDriveManager::update ( )
492{
493 std::unique_lock<std::mutex> inside_update_lock(m_inside_update_mutex, std::defer_lock);
494#ifdef _WIN32
495 // All wake up calls up to now are now consumed when the drive enumeration starts.
496 m_wakeup = false;
497#endif // _WIN32
498 if (inside_update_lock.try_lock()) {
499 // Got the lock without waiting. That means, the update was not running.
500 // Run the update.
501 std::vector<DriveData> current_drives = this->search_for_removable_drives();
502 // Post update events.
503 std::scoped_lock<std::mutex> lock(m_drives_mutex);
504 std::sort(current_drives.begin(), current_drives.end());
505 if (current_drives != m_current_drives) {
508 wxPostEvent(m_callback_evt_handler, RemovableDrivesChangedEvent(EVT_REMOVABLE_DRIVES_CHANGED));
509 }
510 m_current_drives = std::move(current_drives);
511 } else {
512 // Acquiring the m_iniside_update lock failed, therefore another update is running.
513 // Just block until the other instance of update() finishes.
514 inside_update_lock.lock();
515 }
516}
std::vector< DriveData > search_for_removable_drives() const
Definition RemovableDriveManager.cpp:241
std::mutex m_inside_update_mutex
Definition RemovableDriveManager.hpp:119
SimpleEvent RemovableDrivesChangedEvent
Definition RemovableDriveManager.hpp:41

References m_callback_evt_handler, m_current_drives, m_drives_mutex, m_inside_update_mutex, and search_for_removable_drives().

Referenced by eject_drive(), get_removable_drive_path(), init(), set_and_verify_last_save_path(), and thread_proc().

Here is the call graph for this function:
Here is the caller graph for this function:

Member Data Documentation

◆ m_callback_evt_handler

wxEvtHandler* Slic3r::GUI::RemovableDriveManager::m_callback_evt_handler { nullptr }
private
97{ nullptr };

Referenced by eject_drive(), init(), shutdown(), and update().

◆ m_current_drives

std::vector<DriveData> Slic3r::GUI::RemovableDriveManager::m_current_drives
private

◆ m_drives_mutex

std::mutex Slic3r::GUI::RemovableDriveManager::m_drives_mutex
mutableprivate

◆ m_exporting_finished

bool Slic3r::GUI::RemovableDriveManager::m_exporting_finished
private

◆ m_initialized

bool Slic3r::GUI::RemovableDriveManager::m_initialized { false }
private
96{ false };

Referenced by init(), and shutdown().

◆ m_inside_update_mutex

std::mutex Slic3r::GUI::RemovableDriveManager::m_inside_update_mutex
mutableprivate

Referenced by update().

◆ m_last_save_path

std::string Slic3r::GUI::RemovableDriveManager::m_last_save_path
private

◆ m_stop

bool Slic3r::GUI::RemovableDriveManager::m_stop { false }
private
105{ false };

Referenced by shutdown(), and thread_proc().

◆ m_thread

boost::thread Slic3r::GUI::RemovableDriveManager::m_thread
private

Referenced by init(), and shutdown().

◆ m_thread_stop_condition

std::condition_variable Slic3r::GUI::RemovableDriveManager::m_thread_stop_condition
private

Referenced by shutdown(), and thread_proc().

◆ m_thread_stop_mutex

std::mutex Slic3r::GUI::RemovableDriveManager::m_thread_stop_mutex
mutableprivate

Referenced by shutdown(), and thread_proc().


The documentation for this class was generated from the following files: