From 45580aa92557caa4f3f5be783573ddb80602e494 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Tue, 24 May 2016 11:15:16 +0200 Subject: QFileSystemWatcher/Win32: Listen for WM_DEVICECHANGE Add a class QWindowsRemovableDriveListener to QWindowsFileSystemWatcherEngine listening to the WM_DEVICECHANGE messages sent to the top level windows to detect insertion and removal of USB drives. In addition, hook into QWindowsFileSystemWatcherEngine::addPaths() when watching on removable drives, registering a notification for a volume-lock-for-removal message on the internal window handle obtained from QEventDispatcherWin32. When a request to lock the volume for removal is received, remove the paths from the watcher, enabling removal. The class instance is set as a dynamic property on the QFileSystemWatcher where it can be retrieved from clients. This is primarily intended for use by QFileInfoGatherer/QFileSystemModel. Task-number: QTBUG-14290 Task-number: QTBUG-18729 Task-number: QTBUG-55459 Change-Id: Ic95b9d9291b1ec6f426c0702bad896bb064b9346 Reviewed-by: Lars Knoll --- src/corelib/io/qfilesystemwatcher.cpp | 53 +++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) (limited to 'src/corelib/io/qfilesystemwatcher.cpp') diff --git a/src/corelib/io/qfilesystemwatcher.cpp b/src/corelib/io/qfilesystemwatcher.cpp index a1d90c76f4..612b3fa57c 100644 --- a/src/corelib/io/qfilesystemwatcher.cpp +++ b/src/corelib/io/qfilesystemwatcher.cpp @@ -64,6 +64,9 @@ # include "qfilesystemwatcher_fsevents_p.h" #endif +#include +#include + QT_BEGIN_NAMESPACE QFileSystemWatcherEngine *QFileSystemWatcherPrivate::createNativeEngine(QObject *parent) @@ -102,6 +105,17 @@ void QFileSystemWatcherPrivate::init() SIGNAL(directoryChanged(QString,bool)), q, SLOT(_q_directoryChanged(QString,bool))); +#if defined(Q_OS_WIN) && !defined(Q_OS_WINRT) + QObject::connect(static_cast(native), + &QWindowsFileSystemWatcherEngine::driveLockForRemoval, + q, [this] (const QString &p) { _q_winDriveLockForRemoval(p); }); + QObject::connect(static_cast(native), + &QWindowsFileSystemWatcherEngine::driveLockForRemovalFailed, + q, [this] (const QString &p) { _q_winDriveLockForRemovalFailed(p); }); + QObject::connect(static_cast(native), + &QWindowsFileSystemWatcherEngine::driveRemoved, + q, [this] (const QString &p) { _q_winDriveRemoved(p); }); +#endif // !Q_OS_WINRT } } @@ -146,7 +160,46 @@ void QFileSystemWatcherPrivate::_q_directoryChanged(const QString &path, bool re emit q->directoryChanged(path, QFileSystemWatcher::QPrivateSignal()); } +#if defined(Q_OS_WIN) && !defined(Q_OS_WINRT) + +void QFileSystemWatcherPrivate::_q_winDriveLockForRemoval(const QString &path) +{ + // Windows: Request to lock a (removable/USB) drive for removal, release + // its paths under watch, temporarily storing them should the lock fail. + Q_Q(QFileSystemWatcher); + QStringList pathsToBeRemoved; + auto pred = [&path] (const QString &f) { return !f.startsWith(path, Qt::CaseInsensitive); }; + std::remove_copy_if(files.cbegin(), files.cend(), + std::back_inserter(pathsToBeRemoved), pred); + std::remove_copy_if(directories.cbegin(), directories.cend(), + std::back_inserter(pathsToBeRemoved), pred); + if (!pathsToBeRemoved.isEmpty()) { + q->removePaths(pathsToBeRemoved); + temporarilyRemovedPaths.insert(path.at(0), pathsToBeRemoved); + } +} + +void QFileSystemWatcherPrivate::_q_winDriveLockForRemovalFailed(const QString &path) +{ + // Windows: Request to lock a (removable/USB) drive failed (blocked by other + // application), restore the watched paths. + Q_Q(QFileSystemWatcher); + if (!path.isEmpty()) { + const auto it = temporarilyRemovedPaths.find(path.at(0)); + if (it != temporarilyRemovedPaths.end()) { + q->addPaths(it.value()); + temporarilyRemovedPaths.erase(it); + } + } +} +void QFileSystemWatcherPrivate::_q_winDriveRemoved(const QString &path) +{ + // Windows: Drive finally removed, clear out paths stored in lock request. + if (!path.isEmpty()) + temporarilyRemovedPaths.remove(path.at(0)); +} +#endif // Q_OS_WIN && !Q_OS_WINRT /*! \class QFileSystemWatcher -- cgit v1.2.3