2019-11-26 14:19:29 +01:00
#include "RemovableDriveManager.hpp"
2020-03-06 15:10:58 +01:00
#include <libslic3r/libslic3r.h>
#include <boost/nowide/convert.hpp>
#include <boost/log/trivial.hpp>
2019-11-26 14:19:29 +01:00
2019-11-26 15:52:18 +01:00
#if _WIN32
#include <windows.h>
#include <tchar.h>
2019-11-27 11:33:36 +01:00
#include <winioctl.h>
2019-11-27 13:30:45 +01:00
#include <shlwapi.h>
2019-12-05 14:07:02 +01:00
2019-12-06 16:51:04 +01:00
#include <Dbt.h>
2019-12-05 14:07:02 +01:00
2019-11-26 15:52:18 +01:00
#else
2020-03-06 15:10:58 +01:00
// unix, linux & OSX includes
2019-11-26 15:52:18 +01:00
#include <errno.h>
#include <sys/mount.h>
#include <sys/stat.h>
#include <glob.h>
2019-11-28 16:35:22 +01:00
#include <pwd.h>
2019-12-19 17:05:23 +01:00
#include <boost/filesystem.hpp>
2020-01-06 11:32:17 +01:00
#include <boost/filesystem/convenience.hpp>
2020-03-10 08:28:27 +01:00
#include <boost/process.hpp>
2019-11-26 15:52:18 +01:00
#endif
2019-11-26 14:19:29 +01:00
namespace Slic3r {
2019-12-03 10:09:53 +01:00
namespace GUI {
2019-11-26 15:52:18 +01:00
2020-03-06 15:10:58 +01:00
wxDEFINE_EVENT ( EVT_REMOVABLE_DRIVE_EJECTED , RemovableDriveEjectEvent );
wxDEFINE_EVENT ( EVT_REMOVABLE_DRIVES_CHANGED , RemovableDrivesChangedEvent );
2019-11-26 15:52:18 +01:00
#if _WIN32
2020-03-06 15:10:58 +01:00
std :: vector < DriveData > RemovableDriveManager :: search_for_removable_drives () const
2019-11-26 14:19:29 +01:00
{
2020-03-26 19:06:23 +01:00
// Get logical drives flags by letter in alphabetical order.
2020-03-06 15:10:58 +01:00
DWORD drives_mask = :: GetLogicalDrives ();
// Allocate the buffers before the loop.
std :: wstring volume_name ;
std :: wstring file_system_name ;
2020-03-26 19:06:23 +01:00
// Iterate the Windows drives from 'C' to 'Z'
2020-03-06 15:10:58 +01:00
std :: vector < DriveData > current_drives ;
2020-03-26 19:06:23 +01:00
// Skip A and B drives.
drives_mask >>= 2 ;
for ( char drive = 'C' ; drive <= 'Z' ; ++ drive , drives_mask >>= 1 )
if ( drives_mask & 1 ) {
std :: string path { drive , ':' };
2020-03-06 15:10:58 +01:00
UINT drive_type = :: GetDriveTypeA ( path . c_str ());
2019-12-13 11:52:08 +01:00
// DRIVE_REMOVABLE on W are sd cards and usb thumbnails (not usb harddrives)
2020-03-06 15:10:58 +01:00
if ( drive_type == DRIVE_REMOVABLE ) {
2019-11-26 14:19:29 +01:00
// get name of drive
2020-01-22 17:05:26 +01:00
std :: wstring wpath = boost :: nowide :: widen ( path );
2020-03-07 10:17:58 +01:00
volume_name . resize ( MAX_PATH + 1 );
file_system_name . resize ( MAX_PATH + 1 );
2020-03-06 15:10:58 +01:00
BOOL error = :: GetVolumeInformationW ( wpath . c_str (), volume_name . data (), sizeof ( volume_name ), nullptr , nullptr , nullptr , file_system_name . data (), sizeof ( file_system_name ));
if ( error != 0 ) {
volume_name . erase ( volume_name . begin () + wcslen ( volume_name . c_str ()), volume_name . end ());
if ( ! file_system_name . empty ()) {
2019-11-27 14:30:10 +01:00
ULARGE_INTEGER free_space ;
2020-03-13 14:19:02 +01:00
:: GetDiskFreeSpaceExW ( wpath . c_str (), & free_space , nullptr , nullptr );
2020-03-06 15:10:58 +01:00
if ( free_space . QuadPart > 0 ) {
2019-12-03 10:55:38 +01:00
path += " \\ " ;
2020-03-06 15:10:58 +01:00
current_drives . emplace_back ( DriveData { boost :: nowide :: narrow ( volume_name ), path });
2019-11-26 14:19:29 +01:00
}
}
}
}
}
2020-03-06 15:10:58 +01:00
return current_drives ;
}
// Called from UI therefore it blocks the UI thread.
// It also blocks updates at the worker thread.
// Win32 implementation.
void RemovableDriveManager :: eject_drive ()
{
if ( m_last_save_path . empty ())
return ;
#ifndef REMOVABLE_DRIVE_MANAGER_OS_CALLBACKS
this -> update ();
#endif // REMOVABLE_DRIVE_MANAGER_OS_CALLBACKS
tbb :: mutex :: scoped_lock lock ( m_drives_mutex );
auto it_drive_data = this -> find_last_save_path_drive_data ();
if ( it_drive_data != m_current_drives . end ()) {
// get handle to device
std :: string mpath = " \\\\ . \\ " + m_last_save_path ;
mpath = mpath . substr ( 0 , mpath . size () - 1 );
2020-03-13 14:19:02 +01:00
HANDLE handle = CreateFileW ( boost :: nowide :: widen ( mpath ). c_str (), GENERIC_READ | GENERIC_WRITE , FILE_SHARE_READ | FILE_SHARE_WRITE , nullptr , OPEN_EXISTING , 0 , nullptr );
2020-03-06 15:10:58 +01:00
if ( handle == INVALID_HANDLE_VALUE ) {
std :: cerr << "Ejecting " << mpath << " failed " << GetLastError () << " \n " ;
2020-03-12 09:38:46 +01:00
assert ( m_callback_evt_handler );
if ( m_callback_evt_handler )
2020-03-12 12:57:46 +01:00
wxPostEvent ( m_callback_evt_handler , RemovableDriveEjectEvent ( EVT_REMOVABLE_DRIVE_EJECTED , std :: pair < DriveData , bool > ( * it_drive_data , false )));
2020-03-06 15:10:58 +01:00
return ;
}
DWORD deviceControlRetVal ( 0 );
//these 3 commands should eject device safely but they dont, the device does disappear from file explorer but the "device was safely remove" notification doesnt trigger.
//sd cards does trigger WM_DEVICECHANGE messege, usb drives dont
DeviceIoControl ( handle , FSCTL_LOCK_VOLUME , nullptr , 0 , nullptr , 0 , & deviceControlRetVal , nullptr );
DeviceIoControl ( handle , FSCTL_DISMOUNT_VOLUME , nullptr , 0 , nullptr , 0 , & deviceControlRetVal , nullptr );
// some implemenatations also calls IOCTL_STORAGE_MEDIA_REMOVAL here but it returns error to me
BOOL error = DeviceIoControl ( handle , IOCTL_STORAGE_EJECT_MEDIA , nullptr , 0 , nullptr , 0 , & deviceControlRetVal , nullptr );
if ( error == 0 ) {
CloseHandle ( handle );
BOOST_LOG_TRIVIAL ( error ) << "Ejecting " << mpath << " failed " << deviceControlRetVal << " " << GetLastError () << " \n " ;
2020-03-12 09:38:46 +01:00
assert ( m_callback_evt_handler );
if ( m_callback_evt_handler )
2020-03-12 12:57:46 +01:00
wxPostEvent ( m_callback_evt_handler , RemovableDriveEjectEvent ( EVT_REMOVABLE_DRIVE_EJECTED , std :: pair < DriveData , bool > ( * it_drive_data , false )));
2020-03-06 15:10:58 +01:00
return ;
}
CloseHandle ( handle );
2020-03-09 11:47:20 +01:00
assert ( m_callback_evt_handler );
if ( m_callback_evt_handler )
2020-03-12 09:38:46 +01:00
wxPostEvent ( m_callback_evt_handler , RemovableDriveEjectEvent ( EVT_REMOVABLE_DRIVE_EJECTED , std :: pair < DriveData , bool > ( std :: move ( * it_drive_data ), true )));
2020-03-09 11:47:20 +01:00
m_current_drives . erase ( it_drive_data );
2019-11-26 14:19:29 +01:00
}
}
2020-03-06 15:10:58 +01:00
std :: string RemovableDriveManager :: get_removable_drive_path ( const std :: string & path )
2019-11-26 14:19:29 +01:00
{
2020-03-06 15:10:58 +01:00
#ifndef REMOVABLE_DRIVE_MANAGER_OS_CALLBACKS
this -> update ();
#endif // REMOVABLE_DRIVE_MANAGER_OS_CALLBACKS
tbb :: mutex :: scoped_lock lock ( m_drives_mutex );
if ( m_current_drives . empty ())
return std :: string ();
std :: size_t found = path . find_last_of ( " \\ " );
std :: string new_path = path . substr ( 0 , found );
2020-03-13 14:19:02 +01:00
int letter = PathGetDriveNumberW ( boost :: nowide :: widen ( new_path ). c_str ());
2020-03-06 15:10:58 +01:00
for ( const DriveData & drive_data : m_current_drives ) {
char drive = drive_data . path [ 0 ];
if ( drive == 'A' + letter )
return path ;
}
return m_current_drives . front (). path ;
}
std :: string RemovableDriveManager :: get_removable_drive_from_path ( const std :: string & path )
{
tbb :: mutex :: scoped_lock lock ( m_drives_mutex );
std :: size_t found = path . find_last_of ( " \\ " );
std :: string new_path = path . substr ( 0 , found );
2020-03-13 14:19:02 +01:00
int letter = PathGetDriveNumberW ( boost :: nowide :: widen ( new_path ). c_str ());
2020-03-06 15:10:58 +01:00
for ( const DriveData & drive_data : m_current_drives ) {
assert ( ! drive_data . path . empty ());
if ( drive_data . path . front () == 'A' + letter )
return drive_data . path ;
}
return std :: string ();
}
2020-03-13 14:19:02 +01:00
// Called by Win32 Volume arrived / detached callback.
void RemovableDriveManager :: volumes_changed ()
2020-03-06 15:10:58 +01:00
{
2020-03-13 14:19:02 +01:00
if ( m_initialized ) {
// Signal the worker thread to wake up and enumerate removable drives.
m_wakeup = true ;
m_thread_stop_condition . notify_all ();
2019-11-26 14:19:29 +01:00
}
2019-12-05 14:07:02 +01:00
}
2020-03-06 15:10:58 +01:00
#else
namespace search_for_drives_internal
2019-12-05 14:07:02 +01:00
{
2020-03-06 15:10:58 +01:00
static bool compare_filesystem_id ( const std :: string & path_a , const std :: string & path_b )
2019-12-05 14:07:02 +01:00
{
2020-03-06 15:10:58 +01:00
struct stat buf ;
stat ( path_a . c_str () , & buf );
dev_t id_a = buf . st_dev ;
stat ( path_b . c_str () , & buf );
dev_t id_b = buf . st_dev ;
return id_a == id_b ;
}
2019-12-05 14:07:02 +01:00
2020-03-06 15:10:58 +01:00
void inspect_file ( const std :: string & path , const std :: string & parent_path , std :: vector < DriveData > & out )
2019-12-05 14:07:02 +01:00
{
2020-03-06 15:10:58 +01:00
//confirms if the file is removable drive and adds it to vector
//if not same file system - could be removable drive
if ( ! compare_filesystem_id ( path , parent_path )) {
//free space
boost :: filesystem :: space_info si = boost :: filesystem :: space ( path );
if ( si . available != 0 ) {
//user id
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 )
out . emplace_back ( DriveData { boost :: filesystem :: basename ( boost :: filesystem :: path ( path )), path });
}
2019-12-05 14:07:02 +01:00
}
}
2019-12-11 17:39:34 +01:00
2020-03-06 15:10:58 +01:00
static void search_path ( const std :: string & path , const std :: string & parent_path , std :: vector < DriveData > & out )
{
glob_t globbuf ;
globbuf . gl_offs = 2 ;
int error = glob ( path . c_str (), GLOB_TILDE , NULL , & globbuf );
if ( error == 0 ) {
for ( size_t i = 0 ; i < globbuf . gl_pathc ; ++ i )
inspect_file ( globbuf . gl_pathv [ i ], parent_path , out );
} else {
//if error - path probably doesnt exists so function just exits
//std::cout<<"glob error "<< error<< "\n";
}
globfree ( & globbuf );
}
}
std :: vector < DriveData > RemovableDriveManager :: search_for_removable_drives () const
{
std :: vector < DriveData > current_drives ;
#if __APPLE__
this -> list_devices ( current_drives );
#else
2019-11-26 15:52:18 +01:00
//search /media/* folder
2020-03-06 15:10:58 +01:00
search_for_drives_internal :: search_path ( "/media/*" , "/media" , current_drives );
2019-11-26 15:52:18 +01:00
2020-01-06 11:59:24 +01:00
//search_path("/Volumes/*", "/Volumes");
2019-11-28 16:35:22 +01:00
std :: string path ( std :: getenv ( "USER" ));
std :: string pp ( path );
2019-11-26 15:52:18 +01:00
2020-03-06 15:10:58 +01:00
//search /media/USERNAME/* folder
pp = "/media/" + pp ;
path = "/media/" + path + "/*" ;
search_for_drives_internal :: search_path ( path , pp , current_drives );
2019-11-26 15:52:18 +01:00
2020-03-06 15:10:58 +01:00
//search /run/media/USERNAME/* folder
path = "/run" + path ;
pp = "/run" + pp ;
search_for_drives_internal :: search_path ( path , pp , current_drives );
2019-12-10 14:10:47 +01:00
#endif
2019-12-13 11:52:08 +01:00
2020-03-06 15:10:58 +01:00
return current_drives ;
2019-12-10 14:10:47 +01:00
}
2020-03-06 15:10:58 +01:00
// Called from UI therefore it blocks the UI thread.
// It also blocks updates at the worker thread.
// Unix & OSX implementation.
void RemovableDriveManager :: eject_drive ()
2019-11-28 16:35:22 +01:00
{
2020-03-06 15:10:58 +01:00
if ( m_last_save_path . empty ())
2019-11-26 15:52:18 +01:00
return ;
2020-03-06 15:10:58 +01:00
#ifndef REMOVABLE_DRIVE_MANAGER_OS_CALLBACKS
this -> update ();
#endif // REMOVABLE_DRIVE_MANAGER_OS_CALLBACKS
2019-12-17 13:08:17 +01:00
2020-03-06 15:10:58 +01:00
tbb :: mutex :: scoped_lock lock ( m_drives_mutex );
auto it_drive_data = this -> find_last_save_path_drive_data ();
if ( it_drive_data != m_current_drives . end ()) {
std :: string correct_path ( m_last_save_path );
2020-03-10 08:28:27 +01:00
#ifndef __APPLE__
for ( size_t i = 0 ; i < correct_path . size (); ++ i )
2020-03-06 15:10:58 +01:00
if ( correct_path [ i ] == ' ' ) {
correct_path = correct_path . insert ( i , 1 , '\\' );
++ i ;
}
2020-03-10 08:28:27 +01:00
#endif
2020-03-06 15:10:58 +01:00
//std::cout<<"Ejecting "<<(*it).name<<" from "<< correct_path<<"\n";
// there is no usable command in c++ so terminal command is used instead
// but neither triggers "succesful safe removal messege"
2020-03-10 08:28:27 +01:00
BOOST_LOG_TRIVIAL ( info ) << "Ejecting started" ;
boost :: process :: ipstream istd_err ;
boost :: process :: child child (
2020-03-09 14:25:02 +01:00
#if __APPLE__
2020-03-10 08:28:27 +01:00
boost :: process :: search_path ( "diskutil" ), "eject" , correct_path . c_str (), ( boost :: process :: std_out & boost :: process :: std_err ) > istd_err );
2020-03-09 14:25:02 +01:00
//Another option how to eject at mac. Currently not working.
//used insted of system() command;
//this->eject_device(correct_path);
2020-03-06 15:10:58 +01:00
#else
2020-03-10 08:28:27 +01:00
boost :: process :: search_path ( "umount" ), correct_path . c_str (), ( boost :: process :: std_out & boost :: process :: std_err ) > istd_err );
2020-03-06 15:10:58 +01:00
#endif
2020-03-10 08:28:27 +01:00
std :: string line ;
while ( child . running () && std :: getline ( istd_err , line )) {
BOOST_LOG_TRIVIAL ( trace ) << line ;
2019-11-26 15:52:18 +01:00
}
2020-03-10 08:28:27 +01:00
// wait for command to finnish (blocks ui thread)
child . wait ();
int err = child . exit_code ();
2020-03-12 12:57:46 +01:00
if ( err ) {
2020-03-10 08:28:27 +01:00
BOOST_LOG_TRIVIAL ( error ) << "Ejecting failed" ;
2020-03-12 09:38:46 +01:00
assert ( m_callback_evt_handler );
if ( m_callback_evt_handler )
2020-03-12 12:57:46 +01:00
wxPostEvent ( m_callback_evt_handler , RemovableDriveEjectEvent ( EVT_REMOVABLE_DRIVE_EJECTED , std :: pair < DriveData , bool > ( * it_drive_data , false )));
2020-03-10 08:28:27 +01:00
return ;
}
BOOST_LOG_TRIVIAL ( info ) << "Ejecting finished" ;
2019-11-26 15:52:18 +01:00
2020-03-09 10:56:51 +01:00
assert ( m_callback_evt_handler );
if ( m_callback_evt_handler )
2020-03-12 12:57:46 +01:00
wxPostEvent ( m_callback_evt_handler , RemovableDriveEjectEvent ( EVT_REMOVABLE_DRIVE_EJECTED , std :: pair < DriveData , bool > ( std :: move ( * it_drive_data ), true )));
2020-03-09 10:56:51 +01:00
m_current_drives . erase ( it_drive_data );
2019-11-26 15:52:18 +01:00
}
2020-03-06 15:10:58 +01:00
}
2019-11-26 15:52:18 +01:00
2020-03-06 15:10:58 +01:00
std :: string RemovableDriveManager :: get_removable_drive_path ( const std :: string & path )
2019-11-27 14:30:10 +01:00
{
2020-03-06 15:10:58 +01:00
#ifndef REMOVABLE_DRIVE_MANAGER_OS_CALLBACKS
this -> update ();
#endif // REMOVABLE_DRIVE_MANAGER_OS_CALLBACKS
2019-12-18 15:40:48 +01:00
std :: size_t found = path . find_last_of ( "/" );
2020-01-21 13:06:10 +01:00
std :: string new_path = found == path . size () - 1 ? path . substr ( 0 , found ) : path ;
2020-03-06 15:10:58 +01:00
tbb :: mutex :: scoped_lock lock ( m_drives_mutex );
for ( const DriveData & data : m_current_drives )
if ( search_for_drives_internal :: compare_filesystem_id ( new_path , data . path ))
return path ;
return m_current_drives . empty () ? std :: string () : m_current_drives . front (). path ;
2019-11-27 14:30:10 +01:00
}
2020-03-06 15:10:58 +01:00
std :: string RemovableDriveManager :: get_removable_drive_from_path ( const std :: string & path )
2019-12-05 14:07:02 +01:00
{
2019-12-19 11:47:02 +01:00
std :: size_t found = path . find_last_of ( "/" );
2020-01-21 13:06:10 +01:00
std :: string new_path = found == path . size () - 1 ? path . substr ( 0 , found ) : path ;
2020-02-05 16:04:05 +01:00
// trim the filename
found = new_path . find_last_of ( "/" );
new_path = new_path . substr ( 0 , found );
2020-03-06 15:10:58 +01:00
// check if same filesystem
tbb :: mutex :: scoped_lock lock ( m_drives_mutex );
for ( const DriveData & drive_data : m_current_drives )
if ( search_for_drives_internal :: compare_filesystem_id ( new_path , drive_data . path ))
return drive_data . path ;
return std :: string ();
2019-12-05 14:07:02 +01:00
}
2019-11-26 15:52:18 +01:00
#endif
2019-12-11 11:00:47 +01:00
2020-03-06 15:10:58 +01:00
void RemovableDriveManager :: init ( wxEvtHandler * callback_evt_handler )
2019-12-16 13:53:12 +01:00
{
2020-03-06 15:10:58 +01:00
assert ( ! m_initialized );
assert ( m_callback_evt_handler == nullptr );
if ( m_initialized )
return ;
m_initialized = true ;
m_callback_evt_handler = callback_evt_handler ;
2020-03-13 14:19:02 +01:00
#if __APPLE__
2020-03-06 15:10:58 +01:00
this -> register_window_osx ();
2019-12-06 16:51:04 +01:00
#endif
2020-03-06 15:10:58 +01:00
#ifdef REMOVABLE_DRIVE_MANAGER_OS_CALLBACKS
this -> update ();
#else // REMOVABLE_DRIVE_MANAGER_OS_CALLBACKS
// Don't call update() manually, as the UI triggered APIs call this->update() anyways.
m_thread = boost :: thread (( boost :: bind ( & RemovableDriveManager :: thread_proc , this )));
#endif // REMOVABLE_DRIVE_MANAGER_OS_CALLBACKS
2019-11-26 15:52:18 +01:00
}
2020-03-06 15:10:58 +01:00
void RemovableDriveManager :: shutdown ()
2019-11-26 15:52:18 +01:00
{
2020-03-13 14:19:02 +01:00
#if __APPLE__
this -> unregister_window_osx ();
#endif
2020-03-06 15:10:58 +01:00
#ifndef REMOVABLE_DRIVE_MANAGER_OS_CALLBACKS
if ( m_thread . joinable ()) {
// Stop the worker thread, if running.
2019-11-26 15:52:18 +01:00
{
2020-03-06 15:10:58 +01:00
// 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 // REMOVABLE_DRIVE_MANAGER_OS_CALLBACKS
m_initialized = false ;
2020-03-07 12:24:40 +01:00
m_callback_evt_handler = nullptr ;
2020-03-06 15:10:58 +01:00
}
bool RemovableDriveManager :: set_and_verify_last_save_path ( const std :: string & path )
{
#ifndef REMOVABLE_DRIVE_MANAGER_OS_CALLBACKS
this -> update ();
#endif // REMOVABLE_DRIVE_MANAGER_OS_CALLBACKS
m_last_save_path = this -> get_removable_drive_from_path ( path );
2020-06-14 23:14:44 +02:00
m_exporting_finished = false ;
2020-03-06 15:10:58 +01:00
return ! m_last_save_path . empty ();
}
RemovableDriveManager :: RemovableDrivesStatus RemovableDriveManager :: status ()
{
RemovableDriveManager :: RemovableDrivesStatus out ;
{
tbb :: mutex :: scoped_lock lock ( m_drives_mutex );
out . has_eject = this -> find_last_save_path_drive_data () != m_current_drives . end ();
out . has_removable_drives = ! m_current_drives . empty ();
}
if ( ! out . has_eject )
m_last_save_path . clear ();
2020-06-14 23:14:44 +02:00
out . has_eject = out . has_eject && m_exporting_finished ;
2020-03-06 15:10:58 +01:00
return out ;
}
// Update is called from thread_proc() and from most of the public methods on demand.
void RemovableDriveManager :: update ()
{
2020-03-12 11:30:51 +01:00
tbb :: mutex :: scoped_lock inside_update_lock ;
2020-03-13 14:19:02 +01:00
#ifdef _WIN32
// All wake up calls up to now are now consumed when the drive enumeration starts.
m_wakeup = false ;
#endif // _WIN32
2020-03-12 11:30:51 +01:00
if ( inside_update_lock . try_acquire ( m_inside_update_mutex )) {
// Got the lock without waiting. That means, the update was not running.
// Run the update.
std :: vector < DriveData > current_drives = this -> search_for_removable_drives ();
// Post update events.
tbb :: mutex :: scoped_lock lock ( m_drives_mutex );
std :: sort ( current_drives . begin (), current_drives . end ());
if ( current_drives != m_current_drives ) {
assert ( m_callback_evt_handler );
if ( m_callback_evt_handler )
wxPostEvent ( m_callback_evt_handler , RemovableDrivesChangedEvent ( EVT_REMOVABLE_DRIVES_CHANGED ));
}
m_current_drives = std :: move ( current_drives );
} else {
// Acquiring the m_iniside_update lock failed, therefore another update is running.
// Just block until the other instance of update() finishes.
inside_update_lock . acquire ( m_inside_update_mutex );
2019-11-26 15:52:18 +01:00
}
}
2020-03-06 15:10:58 +01:00
#ifndef REMOVABLE_DRIVE_MANAGER_OS_CALLBACKS
void RemovableDriveManager :: thread_proc ()
2019-12-11 14:53:28 +01:00
{
2020-03-13 14:19:02 +01:00
// Signal the worker thread to update initially.
2020-03-13 14:57:45 +01:00
#ifdef _WIN32
2020-03-13 14:19:02 +01:00
m_wakeup = true ;
2020-03-13 14:57:45 +01:00
#endif // _WIN32
2020-03-13 14:19:02 +01:00
2020-03-06 15:10:58 +01:00
for (;;) {
// Wait for 2 seconds before running the disk enumeration.
// Cancellable.
2019-11-28 13:38:08 +01:00
{
2020-03-06 15:10:58 +01:00
std :: unique_lock < std :: mutex > lck ( m_thread_stop_mutex );
2020-03-13 14:19:02 +01:00
#ifdef _WIN32
2020-03-27 08:10:00 +01:00
// Reacting to updates by WM_DEVICECHANGE and WM_USER_MEDIACHANGED
m_thread_stop_condition . wait ( lck , [ this ]{ return m_stop || m_wakeup ; });
2020-03-13 14:19:02 +01:00
#else
2020-03-06 15:10:58 +01:00
m_thread_stop_condition . wait_for ( lck , std :: chrono :: seconds ( 2 ), [ this ]{ return m_stop ; });
2020-03-13 14:19:02 +01:00
#endif
2019-11-28 13:38:08 +01:00
}
2020-03-06 15:10:58 +01:00
if ( m_stop )
// Stop the worker thread.
break ;
// Update m_current drives and send out update events.
this -> update ();
2019-11-28 13:38:08 +01:00
}
}
2020-03-06 15:10:58 +01:00
#endif // REMOVABLE_DRIVE_MANAGER_OS_CALLBACKS
std :: vector < DriveData >:: const_iterator RemovableDriveManager :: find_last_save_path_drive_data () const
2019-11-28 13:38:08 +01:00
{
2020-03-06 15:10:58 +01:00
return Slic3r :: binary_find_by_predicate ( m_current_drives . begin (), m_current_drives . end (),
[ this ]( const DriveData & data ){ return data . path < m_last_save_path ; },
[ this ]( const DriveData & data ){ return data . path == m_last_save_path ; });
2019-11-28 13:38:08 +01:00
}
2020-03-06 15:10:58 +01:00
}} // namespace Slic3r::GUI