1 #ifndef slic3r_GUI_RemovableDriveManager_hpp_
2 #define slic3r_GUI_RemovableDriveManager_hpp_
3
4 #include <vector>
5 #include <string>
6
7 #include <boost/thread.hpp>
8 #include <mutex>
9 #include <condition_variable>
10
11 // Custom wxWidget events
12 #include "Event.hpp"
13
14 namespace Slic3r {
15 namespace GUI {
16
17 struct DriveData
18 {
19 std::string name;
20 std::string path;
21
clearSlic3r::GUI::DriveData22 void clear() {
23 name.clear();
24 path.clear();
25 }
emptySlic3r::GUI::DriveData26 bool empty() const {
27 return path.empty();
28 }
29 };
30
operator <(const DriveData & lhs,const DriveData & rhs)31 inline bool operator< (const DriveData &lhs, const DriveData &rhs) { return lhs.path < rhs.path; }
operator >(const DriveData & lhs,const DriveData & rhs)32 inline bool operator> (const DriveData &lhs, const DriveData &rhs) { return lhs.path > rhs.path; }
operator ==(const DriveData & lhs,const DriveData & rhs)33 inline bool operator==(const DriveData &lhs, const DriveData &rhs) { return lhs.path == rhs.path; }
34
35 using RemovableDriveEjectEvent = Event<std::pair<DriveData, bool>>;
36 wxDECLARE_EVENT(EVT_REMOVABLE_DRIVE_EJECTED, RemovableDriveEjectEvent);
37
38 using RemovableDrivesChangedEvent = SimpleEvent;
39 wxDECLARE_EVENT(EVT_REMOVABLE_DRIVES_CHANGED, RemovableDrivesChangedEvent);
40
41 #if __APPLE__
42 // Callbacks on device plug / unplug work reliably on OSX.
43 #define REMOVABLE_DRIVE_MANAGER_OS_CALLBACKS
44 #endif // __APPLE__
45
46 class RemovableDriveManager
47 {
48 public:
49 RemovableDriveManager() = default;
50 RemovableDriveManager(RemovableDriveManager const&) = delete;
51 void operator=(RemovableDriveManager const&) = delete;
~RemovableDriveManager()52 ~RemovableDriveManager() { assert(! m_initialized); }
53
54 // Start the background thread and register this window as a target for update events.
55 // Register for OSX notifications.
56 void init(wxEvtHandler *callback_evt_handler);
57 // Stop the background thread of the removable drive manager, so that no new updates will be sent out.
58 // Deregister OSX notifications.
59 void shutdown();
60
61 // Returns path to a removable media if it exists, prefering the input path.
62 std::string get_removable_drive_path(const std::string &path);
is_path_on_removable_drive(const std::string & path)63 bool is_path_on_removable_drive(const std::string &path) { return this->get_removable_drive_path(path) == path; }
64
65 // Verify whether the path provided is on removable media. If so, save the path for further eject and return true, otherwise return false.
66 bool set_and_verify_last_save_path(const std::string &path);
67 // Eject drive of a file set by set_and_verify_last_save_path().
68 // On Unix / OSX, the function blocks and sends out the EVT_REMOVABLE_DRIVE_EJECTED event on success.
69 // On Windows, the function does not block, and the eject is detected in the background thread.
70 void eject_drive();
71
72 // Status is used to retrieve info for showing UI buttons.
73 // Status is called every time when change of UI buttons is possible therefore should not perform update.
74 struct RemovableDrivesStatus {
75 bool has_removable_drives { false };
76 bool has_eject { false };
77 };
78 RemovableDrivesStatus status();
79
80 // Enumerates current drives and sends out wxWidget events on change or eject.
81 // Called by each public method, by the background thread and from RemovableDriveManagerMM::on_device_unmount OSX notification handler.
82 // Not to be called manually.
83 // Public to be accessible from RemovableDriveManagerMM::on_device_unmount OSX notification handler.
84 // It would be better to make this method private and friend to RemovableDriveManagerMM, but RemovableDriveManagerMM is an ObjectiveC class.
85 void update();
set_exporting_finished(bool b)86 void set_exporting_finished(bool b) { m_exporting_finished = b; }
87 #ifdef _WIN32
88 // Called by Win32 Volume arrived / detached callback.
89 void volumes_changed();
90 #endif // _WIN32
91
92 private:
93 bool m_initialized { false };
94 wxEvtHandler* m_callback_evt_handler { nullptr };
95
96 #ifndef REMOVABLE_DRIVE_MANAGER_OS_CALLBACKS
97 // Worker thread, worker thread synchronization and callbacks to the UI thread.
98 void thread_proc();
99 boost::thread m_thread;
100 std::condition_variable m_thread_stop_condition;
101 mutable std::mutex m_thread_stop_mutex;
102 bool m_stop { false };
103 #ifdef _WIN32
104 std::atomic<bool> m_wakeup { false };
105 #endif /* _WIN32 */
106 #endif // REMOVABLE_DRIVE_MANAGER_OS_CALLBACKS
107
108 // Called from update() to enumerate removable drives.
109 std::vector<DriveData> search_for_removable_drives() const;
110
111 // m_current_drives is guarded by m_drives_mutex
112 // sorted ascending by path
113 std::vector<DriveData> m_current_drives;
114 mutable std::mutex m_drives_mutex;
115 // Locking the update() function to avoid that the function is executed multiple times.
116 mutable std::mutex m_inside_update_mutex;
117
118 // Returns drive path (same as path in DriveData) if exists otherwise empty string.
119 std::string get_removable_drive_from_path(const std::string& path);
120 // Returns iterator to a drive in m_current_drives with path equal to m_last_save_path or end().
121 std::vector<DriveData>::const_iterator find_last_save_path_drive_data() const;
122 // Set with set_and_verify_last_save_path() to a removable drive path to be ejected.
123 std::string m_last_save_path;
124 // Verifies that exporting was finished so drive can be ejected.
125 // Set false by set_and_verify_last_save_path() that is called just before exporting.
126 bool m_exporting_finished;
127 #if __APPLE__
128 void register_window_osx();
129 void unregister_window_osx();
130 void list_devices(std::vector<DriveData> &out) const;
131 // not used as of now
132 void eject_device(const std::string &path);
133 // Opaque pointer to RemovableDriveManagerMM
134 void *m_impl_osx;
135 boost::thread *m_eject_thread { nullptr };
136 void eject_thread_finish();
137 #endif
138 };
139
140 }}
141
142 #endif // slic3r_GUI_RemovableDriveManager_hpp_
143