2019-11-26 13:19:29 +00:00
# include "RemovableDriveManager.hpp"
2020-03-06 14:10:58 +00:00
# include <libslic3r/libslic3r.h>
# include <boost/nowide/convert.hpp>
# include <boost/log/trivial.hpp>
2019-11-26 13:19:29 +00:00
2019-11-26 14:52:18 +00:00
# if _WIN32
# include <windows.h>
# include <tchar.h>
2019-11-27 10:33:36 +00:00
# include <winioctl.h>
2019-11-27 12:30:45 +00:00
# include <shlwapi.h>
2019-12-05 13:07:02 +00:00
2019-12-06 15:51:04 +00:00
# include <Dbt.h>
2019-12-05 13:07:02 +00:00
2019-11-26 14:52:18 +00:00
# else
2020-03-06 14:10:58 +00:00
// unix, linux & OSX includes
2019-11-26 14:52:18 +00:00
# include <errno.h>
# include <sys/mount.h>
# include <sys/stat.h>
# include <glob.h>
2019-11-28 15:35:22 +00:00
# include <pwd.h>
2019-12-19 16:05:23 +00:00
# include <boost/filesystem.hpp>
2020-01-06 10:32:17 +00:00
# include <boost/filesystem/convenience.hpp>
2020-03-10 07:28:27 +00:00
# include <boost/process.hpp>
2019-11-26 14:52:18 +00:00
# endif
2019-11-26 13:19:29 +00:00
namespace Slic3r {
2019-12-03 09:09:53 +00:00
namespace GUI {
2019-11-26 14:52:18 +00:00
2020-03-06 14:10:58 +00:00
wxDEFINE_EVENT ( EVT_REMOVABLE_DRIVE_EJECTED , RemovableDriveEjectEvent ) ;
wxDEFINE_EVENT ( EVT_REMOVABLE_DRIVES_CHANGED , RemovableDrivesChangedEvent ) ;
2019-11-26 14:52:18 +00:00
# if _WIN32
2020-03-06 14:10:58 +00:00
std : : vector < DriveData > RemovableDriveManager : : search_for_removable_drives ( ) const
2019-11-26 13:19:29 +00:00
{
2019-12-13 10:52:08 +00:00
//get logical drives flags by letter in alphabetical order
2020-03-06 14:10:58 +00:00
DWORD drives_mask = : : GetLogicalDrives ( ) ;
// Allocate the buffers before the loop.
std : : wstring volume_name ;
std : : wstring file_system_name ;
// Iterate the Windows drives from 'A' to 'Z'
std : : vector < DriveData > current_drives ;
for ( size_t i = 0 ; i < 26 ; + + i )
if ( drives_mask & ( 1 < < i ) ) {
std : : string path { char ( ' A ' + i ) , ' : ' } ;
UINT drive_type = : : GetDriveTypeA ( path . c_str ( ) ) ;
2019-12-13 10:52:08 +00:00
// DRIVE_REMOVABLE on W are sd cards and usb thumbnails (not usb harddrives)
2020-03-06 14:10:58 +00:00
if ( drive_type = = DRIVE_REMOVABLE ) {
2019-11-26 13:19:29 +00:00
// get name of drive
2020-01-22 16:05:26 +00:00
std : : wstring wpath = boost : : nowide : : widen ( path ) ;
2020-03-07 09:17:58 +00:00
volume_name . resize ( MAX_PATH + 1 ) ;
file_system_name . resize ( MAX_PATH + 1 ) ;
2020-03-06 14:10:58 +00: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 13:30:10 +00:00
ULARGE_INTEGER free_space ;
2020-03-06 14:10:58 +00:00
: : GetDiskFreeSpaceExA ( path . c_str ( ) , & free_space , nullptr , nullptr ) ;
if ( free_space . QuadPart > 0 ) {
2019-12-03 09:55:38 +00:00
path + = " \\ " ;
2020-03-06 14:10:58 +00:00
current_drives . emplace_back ( DriveData { boost : : nowide : : narrow ( volume_name ) , path } ) ;
2019-11-26 13:19:29 +00:00
}
}
}
}
}
2020-03-06 14:10:58 +00:00
return current_drives ;
2019-11-26 13:19:29 +00:00
}
2020-03-06 14:10:58 +00:00
// Called from UI therefore it blocks the UI thread.
// It also blocks updates at the worker thread.
// Win32 implementation.
void RemovableDriveManager : : eject_drive ( )
2019-11-26 13:19:29 +00:00
{
2020-03-06 14:10:58 +00:00
if ( m_last_save_path . empty ( ) )
2019-11-26 13:19:29 +00:00
return ;
2020-03-06 14:10:58 +00:00
# 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 ) ;
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 ) ;
//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 ) {
2019-12-11 16:02:12 +00:00
CloseHandle ( handle ) ;
2020-03-06 14:10:58 +00:00
BOOST_LOG_TRIVIAL ( error ) < < " Ejecting " < < mpath < < " failed " < < deviceControlRetVal < < " " < < GetLastError ( ) < < " \n " ;
return ;
2019-11-26 13:19:29 +00:00
}
2020-03-06 14:10:58 +00:00
CloseHandle ( handle ) ;
2020-03-09 10:47:20 +00:00
assert ( m_callback_evt_handler ) ;
if ( m_callback_evt_handler )
wxPostEvent ( m_callback_evt_handler , RemovableDriveEjectEvent ( EVT_REMOVABLE_DRIVE_EJECTED , std : : move ( * it_drive_data ) ) ) ;
m_current_drives . erase ( it_drive_data ) ;
2019-11-26 13:19:29 +00:00
}
}
2020-03-06 14:10:58 +00:00
std : : string RemovableDriveManager : : get_removable_drive_path ( const std : : string & path )
2019-11-27 13:30:10 +00:00
{
2020-03-06 14:10:58 +00:00
# ifndef REMOVABLE_DRIVE_MANAGER_OS_CALLBACKS
this - > update ( ) ;
# endif // REMOVABLE_DRIVE_MANAGER_OS_CALLBACKS
tbb : : mutex : : scoped_lock lock ( m_drives_mutex ) ;
2019-11-27 13:30:10 +00:00
if ( m_current_drives . empty ( ) )
2020-03-06 14:10:58 +00:00
return std : : string ( ) ;
2019-12-19 10:47:02 +00:00
std : : size_t found = path . find_last_of ( " \\ " ) ;
std : : string new_path = path . substr ( 0 , found ) ;
int letter = PathGetDriveNumberA ( new_path . c_str ( ) ) ;
2020-03-06 14:10:58 +00:00
for ( const DriveData & drive_data : m_current_drives ) {
char drive = drive_data . path [ 0 ] ;
if ( drive = = ' A ' + letter )
return path ;
2019-11-27 13:30:10 +00:00
}
2020-03-06 14:10:58 +00:00
return m_current_drives . front ( ) . path ;
2019-11-27 13:30:10 +00:00
}
2020-03-06 14:10:58 +00:00
std : : string RemovableDriveManager : : get_removable_drive_from_path ( const std : : string & path )
2019-12-05 13:07:02 +00:00
{
2020-03-06 14:10:58 +00:00
tbb : : mutex : : scoped_lock lock ( m_drives_mutex ) ;
2019-12-19 10:47:02 +00:00
std : : size_t found = path . find_last_of ( " \\ " ) ;
std : : string new_path = path . substr ( 0 , found ) ;
2020-03-06 14:10:58 +00:00
int letter = PathGetDriveNumberA ( new_path . c_str ( ) ) ;
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 ( ) ;
}
#if 0
// currently not used, left for possible future use
INT_PTR WINAPI WinProcCallback ( HWND hWnd , UINT message , WPARAM wParam , LPARAM lParam )
{
// here we need to catch messeges about device removal
// problem is that when ejecting usb (how is it implemented above) there is no messege dispached. Only after physical removal of the device.
//uncomment register_window() in init() to register and comment update() in GUI_App.cpp (only for windows!) to stop recieving periodical updates
LRESULT lRet = 1 ;
static HDEVNOTIFY hDeviceNotify ;
static constexpr GUID WceusbshGUID = { 0x25dbce51 , 0x6c8f , 0x4a72 , 0x8a , 0x6d , 0xb5 , 0x4c , 0x2b , 0x4f , 0xc8 , 0x35 } ;
switch ( message )
2019-12-05 13:07:02 +00:00
{
2020-03-06 14:10:58 +00:00
case WM_CREATE :
DEV_BROADCAST_DEVICEINTERFACE NotificationFilter ;
ZeroMemory ( & NotificationFilter , sizeof ( NotificationFilter ) ) ;
NotificationFilter . dbcc_size = sizeof ( DEV_BROADCAST_DEVICEINTERFACE ) ;
NotificationFilter . dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE ;
NotificationFilter . dbcc_classguid = WceusbshGUID ;
hDeviceNotify = RegisterDeviceNotification ( hWnd , & NotificationFilter , DEVICE_NOTIFY_WINDOW_HANDLE ) ;
break ;
case WM_DEVICECHANGE :
{
// here is the important
if ( wParam = = DBT_DEVICEREMOVECOMPLETE )
{
RemovableDriveManager : : get_instance ( ) . update ( 0 , true ) ;
}
}
break ;
default :
// Send all other messages on to the default windows handler.
lRet = DefWindowProc ( hWnd , message , wParam , lParam ) ;
break ;
2019-12-05 13:07:02 +00:00
}
2020-03-06 14:10:58 +00:00
return lRet ;
2019-12-05 13:07:02 +00:00
}
2020-03-06 14:10:58 +00:00
2019-11-28 12:38:08 +00:00
void RemovableDriveManager : : register_window ( )
{
2019-12-12 13:56:30 +00:00
//creates new unvisible window that is recieving callbacks from system
2019-12-13 10:52:08 +00:00
// structure to register
2020-03-06 14:10:58 +00:00
// currently not used, left for possible future use
2019-11-28 12:38:08 +00:00
WNDCLASSEX wndClass ;
wndClass . cbSize = sizeof ( WNDCLASSEX ) ;
wndClass . style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW ;
wndClass . hInstance = reinterpret_cast < HINSTANCE > ( GetModuleHandle ( 0 ) ) ;
2019-12-13 10:52:08 +00:00
wndClass . lpfnWndProc = reinterpret_cast < WNDPROC > ( WinProcCallback ) ; //this is callback
2019-11-28 12:38:08 +00:00
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 ) ;
2019-12-05 13:07:02 +00:00
wndClass . lpszClassName = L " PrusaSlicer_aux_class " ;
2019-11-28 12:38:08 +00:00
wndClass . lpszMenuName = NULL ;
wndClass . hIconSm = wndClass . hIcon ;
2019-12-06 15:51:04 +00:00
if ( ! RegisterClassEx ( & wndClass ) )
{
DWORD err = GetLastError ( ) ;
return ;
}
2019-12-05 13:07:02 +00:00
HWND hWnd = CreateWindowEx (
2019-12-06 15:51:04 +00:00
WS_EX_NOACTIVATE ,
2019-12-05 13:07:02 +00:00
L " PrusaSlicer_aux_class " ,
L " PrusaSlicer_aux_wnd " ,
2019-12-06 15:51:04 +00:00
WS_DISABLED , // style
2019-12-05 13:07:02 +00:00
CW_USEDEFAULT , 0 ,
640 , 480 ,
NULL , NULL ,
2019-12-06 15:51:04 +00:00
GetModuleHandle ( NULL ) ,
2019-12-05 13:07:02 +00:00
NULL ) ;
2019-12-06 15:51:04 +00:00
if ( hWnd = = NULL )
{
DWORD err = GetLastError ( ) ;
}
//ShowWindow(hWnd, SW_SHOWNORMAL);
UpdateWindow ( hWnd ) ;
2019-12-05 13:07:02 +00:00
}
2020-03-06 14:10:58 +00:00
# endif
# else
namespace search_for_drives_internal
2019-12-05 13:07:02 +00:00
{
2020-03-06 14:10:58 +00:00
static bool compare_filesystem_id ( const std : : string & path_a , const std : : string & path_b )
{
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-06 15:51:04 +00:00
2020-03-06 14:10:58 +00:00
void inspect_file ( const std : : string & path , const std : : string & parent_path , std : : vector < DriveData > & out )
2019-12-05 13:07:02 +00:00
{
2020-03-06 14:10:58 +00:00
//confirms if the file is removable drive and adds it to vector
2019-12-05 13:07:02 +00:00
2020-03-06 14:10:58 +00:00
//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 13:07:02 +00:00
2020-03-06 14:10:58 +00:00
static void search_path ( const std : : string & path , const std : : string & parent_path , std : : vector < DriveData > & out )
2019-12-05 13:07:02 +00:00
{
2020-03-06 14:10:58 +00:00
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";
2019-12-05 13:07:02 +00:00
}
2020-03-06 14:10:58 +00:00
globfree ( & globbuf ) ;
2019-12-05 13:07:02 +00:00
}
2019-11-28 12:38:08 +00:00
}
2020-03-06 14:10:58 +00:00
std : : vector < DriveData > RemovableDriveManager : : search_for_removable_drives ( ) const
2019-11-26 14:52:18 +00:00
{
2020-03-06 14:10:58 +00:00
std : : vector < DriveData > current_drives ;
2019-12-09 14:33:10 +00:00
# if __APPLE__
2019-12-11 16:39:34 +00:00
2020-03-06 14:10:58 +00:00
this - > list_devices ( current_drives ) ;
# else
2019-11-26 14:52:18 +00:00
//search /media/* folder
2020-03-06 14:10:58 +00:00
search_for_drives_internal : : search_path ( " /media/* " , " /media " , current_drives ) ;
2019-11-26 14:52:18 +00:00
2020-01-06 10:59:24 +00:00
//search_path("/Volumes/*", "/Volumes");
2019-11-28 15:35:22 +00:00
std : : string path ( std : : getenv ( " USER " ) ) ;
std : : string pp ( path ) ;
2019-11-26 14:52:18 +00:00
2020-03-06 14:10:58 +00:00
//search /media/USERNAME/* folder
pp = " /media/ " + pp ;
path = " /media/ " + path + " /* " ;
search_for_drives_internal : : search_path ( path , pp , current_drives ) ;
2019-11-26 14:52:18 +00:00
2020-03-06 14:10:58 +00: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 13:10:47 +00:00
# endif
2019-12-13 10:52:08 +00:00
2020-03-06 14:10:58 +00:00
return current_drives ;
2019-11-28 15:35:22 +00:00
}
2020-03-06 14:10:58 +00: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-26 14:52:18 +00:00
{
2020-03-06 14:10:58 +00:00
if ( m_last_save_path . empty ( ) )
2019-11-26 14:52:18 +00:00
return ;
2020-03-06 14:10:58 +00:00
# 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 ( ) ) {
std : : string correct_path ( m_last_save_path ) ;
2020-03-10 07:28:27 +00:00
# ifndef __APPLE__
for ( size_t i = 0 ; i < correct_path . size ( ) ; + + i )
2020-03-06 14:10:58 +00:00
if ( correct_path [ i ] = = ' ' ) {
correct_path = correct_path . insert ( i , 1 , ' \\ ' ) ;
+ + i ;
}
2020-03-10 07:28:27 +00:00
# endif
2020-03-06 14:10:58 +00: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 07:28:27 +00:00
BOOST_LOG_TRIVIAL ( info ) < < " Ejecting started " ;
boost : : process : : ipstream istd_err ;
boost : : process : : child child (
2020-03-09 13:25:02 +00:00
# if __APPLE__
2020-03-10 07:28:27 +00:00
boost : : process : : search_path ( " diskutil " ) , " eject " , correct_path . c_str ( ) , ( boost : : process : : std_out & boost : : process : : std_err ) > istd_err ) ;
2020-03-09 13:25:02 +00:00
//Another option how to eject at mac. Currently not working.
//used insted of system() command;
//this->eject_device(correct_path);
2019-12-04 12:30:25 +00:00
# else
2020-03-10 07:28:27 +00:00
boost : : process : : search_path ( " umount " ) , correct_path . c_str ( ) , ( boost : : process : : std_out & boost : : process : : std_err ) > istd_err ) ;
2019-12-04 12:30:25 +00:00
# endif
2020-03-10 07:28:27 +00:00
std : : string line ;
while ( child . running ( ) & & std : : getline ( istd_err , line ) ) {
BOOST_LOG_TRIVIAL ( trace ) < < line ;
2019-11-26 14:52:18 +00:00
}
2020-03-10 07:28:27 +00:00
// wait for command to finnish (blocks ui thread)
child . wait ( ) ;
int err = child . exit_code ( ) ;
if ( err )
{
BOOST_LOG_TRIVIAL ( error ) < < " Ejecting failed " ;
return ;
}
BOOST_LOG_TRIVIAL ( info ) < < " Ejecting finished " ;
2019-11-26 14:52:18 +00:00
2020-03-09 09:56:51 +00:00
assert ( m_callback_evt_handler ) ;
if ( m_callback_evt_handler )
wxPostEvent ( m_callback_evt_handler , RemovableDriveEjectEvent ( EVT_REMOVABLE_DRIVE_EJECTED , std : : move ( * it_drive_data ) ) ) ;
m_current_drives . erase ( it_drive_data ) ;
2019-11-26 14:52:18 +00:00
}
}
2020-03-06 14:10:58 +00:00
std : : string RemovableDriveManager : : get_removable_drive_path ( const std : : string & path )
2019-11-27 13:30:10 +00:00
{
2020-03-06 14:10:58 +00:00
# ifndef REMOVABLE_DRIVE_MANAGER_OS_CALLBACKS
this - > update ( ) ;
# endif // REMOVABLE_DRIVE_MANAGER_OS_CALLBACKS
2019-12-18 14:40:48 +00:00
std : : size_t found = path . find_last_of ( " / " ) ;
2020-01-21 12:06:10 +00:00
std : : string new_path = found = = path . size ( ) - 1 ? path . substr ( 0 , found ) : path ;
2020-03-06 14:10:58 +00: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 13:30:10 +00:00
}
2020-03-06 14:10:58 +00:00
std : : string RemovableDriveManager : : get_removable_drive_from_path ( const std : : string & path )
2019-12-05 13:07:02 +00:00
{
2019-12-19 10:47:02 +00:00
std : : size_t found = path . find_last_of ( " / " ) ;
2020-01-21 12:06:10 +00:00
std : : string new_path = found = = path . size ( ) - 1 ? path . substr ( 0 , found ) : path ;
2020-02-05 15:04:05 +00:00
// trim the filename
found = new_path . find_last_of ( " / " ) ;
new_path = new_path . substr ( 0 , found ) ;
2020-03-06 14:10:58 +00: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 13:07:02 +00:00
}
2019-11-26 14:52:18 +00:00
# endif
2019-12-11 10:00:47 +00:00
2020-03-06 14:10:58 +00:00
void RemovableDriveManager : : init ( wxEvtHandler * callback_evt_handler )
2019-12-16 12:53:12 +00:00
{
2020-03-06 14:10:58 +00:00
assert ( ! m_initialized ) ;
assert ( m_callback_evt_handler = = nullptr ) ;
if ( m_initialized )
return ;
m_initialized = true ;
m_callback_evt_handler = callback_evt_handler ;
2019-11-28 12:38:08 +00:00
# if _WIN32
2020-03-06 14:10:58 +00:00
//this->register_window_msw();
2019-12-10 10:17:12 +00:00
# elif __APPLE__
2020-03-06 14:10:58 +00:00
this - > register_window_osx ( ) ;
2019-11-28 12:38:08 +00:00
# endif
2020-03-06 14:10:58 +00: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-12-06 15:51:04 +00:00
}
2020-03-06 14:10:58 +00:00
void RemovableDriveManager : : shutdown ( )
2019-12-06 15:51:04 +00:00
{
2020-03-06 14:10:58 +00:00
# ifndef REMOVABLE_DRIVE_MANAGER_OS_CALLBACKS
if ( m_thread . joinable ( ) ) {
// Stop the worker thread, if running.
2020-01-21 09:23:50 +00:00
{
2020-03-06 14:10:58 +00:00
// Notify the worker thread to cancel wait on detection polling.
std : : lock_guard < std : : mutex > lck ( m_thread_stop_mutex ) ;
m_stop = true ;
2020-01-21 09:23:50 +00:00
}
2020-03-06 14:10:58 +00:00
m_thread_stop_condition . notify_all ( ) ;
// Wait for the worker thread to stop.
m_thread . join ( ) ;
m_stop = false ;
2019-12-19 13:19:41 +00:00
}
2020-03-06 14:10:58 +00:00
# endif // REMOVABLE_DRIVE_MANAGER_OS_CALLBACKS
# if _WIN32
//this->unregister_window_msw();
# elif __APPLE__
this - > unregister_window_osx ( ) ;
# endif
m_initialized = false ;
2020-03-07 11:24:40 +00:00
m_callback_evt_handler = nullptr ;
2019-11-26 14:52:18 +00:00
}
2020-03-06 14:10:58 +00:00
bool RemovableDriveManager : : set_and_verify_last_save_path ( const std : : string & path )
2019-11-26 14:52:18 +00:00
{
2020-03-06 14:10:58 +00:00
# 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 ) ;
return ! m_last_save_path . empty ( ) ;
2019-11-26 14:52:18 +00:00
}
2020-03-06 14:10:58 +00:00
RemovableDriveManager : : RemovableDrivesStatus RemovableDriveManager : : status ( )
2019-12-11 13:53:28 +00:00
{
2020-03-06 14:10:58 +00:00
# ifndef REMOVABLE_DRIVE_MANAGER_OS_CALLBACKS
this - > update ( ) ;
# endif // REMOVABLE_DRIVE_MANAGER_OS_CALLBACKS
RemovableDriveManager : : RemovableDrivesStatus out ;
2019-12-11 13:53:28 +00:00
{
2020-03-06 14:10:58 +00:00
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 ( ) ;
2019-12-11 13:53:28 +00:00
}
2020-03-06 14:10:58 +00:00
if ( ! out . has_eject )
m_last_save_path . clear ( ) ;
return out ;
2019-11-26 13:19:29 +00:00
}
2020-03-06 14:10:58 +00:00
// Update is called from thread_proc() and from most of the public methods on demand.
void RemovableDriveManager : : update ( )
2019-11-28 12:38:08 +00:00
{
2020-03-06 14:10:58 +00:00
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 ) {
2020-03-09 10:47:20 +00:00
assert ( m_callback_evt_handler ) ;
if ( m_callback_evt_handler )
wxPostEvent ( m_callback_evt_handler , RemovableDrivesChangedEvent ( EVT_REMOVABLE_DRIVES_CHANGED ) ) ;
2019-11-28 12:38:08 +00:00
}
2020-03-06 14:10:58 +00:00
m_current_drives = std : : move ( current_drives ) ;
2019-11-28 12:38:08 +00:00
}
2020-03-06 14:10:58 +00:00
# ifndef REMOVABLE_DRIVE_MANAGER_OS_CALLBACKS
void RemovableDriveManager : : thread_proc ( )
2019-12-13 17:02:25 +00:00
{
2020-03-06 14:10:58 +00:00
for ( ; ; ) {
// Wait for 2 seconds before running the disk enumeration.
// Cancellable.
2019-12-13 17:02:25 +00:00
{
2020-03-06 14:10:58 +00:00
std : : unique_lock < std : : mutex > lck ( m_thread_stop_mutex ) ;
m_thread_stop_condition . wait_for ( lck , std : : chrono : : seconds ( 2 ) , [ this ] { return m_stop ; } ) ;
2019-12-13 17:02:25 +00:00
}
2020-03-06 14:10:58 +00:00
if ( m_stop )
// Stop the worker thread.
break ;
// Update m_current drives and send out update events.
this - > update ( ) ;
2019-12-13 17:02:25 +00:00
}
2020-01-02 15:30:28 +00:00
}
2020-03-06 14:10:58 +00:00
# endif // REMOVABLE_DRIVE_MANAGER_OS_CALLBACKS
std : : vector < DriveData > : : const_iterator RemovableDriveManager : : find_last_save_path_drive_data ( ) const
2020-01-21 09:23:50 +00:00
{
2020-03-06 14:10:58 +00: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 ; } ) ;
2020-01-21 09:23:50 +00:00
}
2020-03-06 14:10:58 +00:00
} } // namespace Slic3r::GUI