11#include <qloggingcategory.h>
14#if (defined(Q_OS_LINUX) || defined(Q_OS_QNX)) && QT_CONFIG(inotify)
20# include "qfilesystemwatcher_win_p.h"
21#elif defined(USE_INOTIFY)
22# include "qfilesystemwatcher_inotify_p.h"
23#elif defined(Q_OS_FREEBSD) || defined(Q_OS_NETBSD) || defined(Q_OS_OPENBSD) || defined(QT_PLATFORM_UIKIT)
24# include "qfilesystemwatcher_kqueue_p.h"
25#elif defined(Q_OS_MACOS)
26# include "qfilesystemwatcher_fsevents_p.h"
34using namespace Qt::StringLiterals;
41 return new QWindowsFileSystemWatcherEngine(parent);
42#elif defined(USE_INOTIFY)
45 return QInotifyFileSystemWatcherEngine::create(parent);
46#elif defined(Q_OS_FREEBSD) || defined(Q_OS_NETBSD) || defined(Q_OS_OPENBSD) || defined(QT_PLATFORM_UIKIT)
47 return QKqueueFileSystemWatcherEngine::create(parent);
48#elif defined(Q_OS_MACOS)
49 return QFseventsFileSystemWatcherEngine::create(parent);
63 QObjectPrivate::connect(engine, &QFileSystemWatcherEngine::fileChanged,
64 this, &QFileSystemWatcherPrivate::fileChanged);
65 QObjectPrivate::connect(engine, &QFileSystemWatcherEngine::directoryChanged,
66 this, &QFileSystemWatcherPrivate::directoryChanged);
71 Q_Q(QFileSystemWatcher);
72 native = createNativeEngine(q);
76 auto *windowsWatcher =
static_cast<QWindowsFileSystemWatcherEngine *>(native);
77 using WinE = QWindowsFileSystemWatcherEngine;
78 QObjectPrivate::connect(windowsWatcher, &WinE::driveLockForRemoval,
79 this, &QFileSystemWatcherPrivate::winDriveLockForRemoval);
80 QObjectPrivate::connect(windowsWatcher, &WinE::driveLockForRemovalFailed,
81 this, &QFileSystemWatcherPrivate::winDriveLockForRemovalFailed);
82 QObjectPrivate::connect(windowsWatcher, &WinE::driveRemoved,
83 this, &QFileSystemWatcherPrivate::winDriveRemoved);
93 Q_Q(QFileSystemWatcher);
94 poller =
new QPollingFileSystemWatcherEngine(q);
100 Q_Q(QFileSystemWatcher);
101 qCDebug(lcWatcher) <<
"file changed" << path <<
"removed?" << removed <<
"watching?" << files.contains(path);
102 if (!files.contains(path)) {
107 files.removeAll(path);
108 emit q->fileChanged(path, QFileSystemWatcher::QPrivateSignal());
113 Q_Q(QFileSystemWatcher);
114 qCDebug(lcWatcher) <<
"directory changed" << path <<
"removed?" << removed <<
"watching?" << directories.contains(path);
115 if (!directories.contains(path)) {
120 directories.removeAll(path);
121 emit q->directoryChanged(path, QFileSystemWatcher::QPrivateSignal());
126void QFileSystemWatcherPrivate::winDriveLockForRemoval(
const QString &path)
130 Q_Q(QFileSystemWatcher);
131 QStringList pathsToBeRemoved;
132 auto pred = [&path] (
const QString &f) {
return !f.startsWith(path, Qt::CaseInsensitive); };
133 std::remove_copy_if(files.cbegin(), files.cend(),
134 std::back_inserter(pathsToBeRemoved), pred);
135 std::remove_copy_if(directories.cbegin(), directories.cend(),
136 std::back_inserter(pathsToBeRemoved), pred);
137 if (!pathsToBeRemoved.isEmpty()) {
138 q->removePaths(pathsToBeRemoved);
139 temporarilyRemovedPaths.insert(path.at(0), pathsToBeRemoved);
143void QFileSystemWatcherPrivate::winDriveLockForRemovalFailed(
const QString &path)
147 Q_Q(QFileSystemWatcher);
148 if (!path.isEmpty()) {
149 const auto it = temporarilyRemovedPaths.find(path.at(0));
150 if (it != temporarilyRemovedPaths.end()) {
151 q->addPaths(it.value());
152 temporarilyRemovedPaths.erase(it);
157void QFileSystemWatcherPrivate::winDriveRemoved(
const QString &path)
161 temporarilyRemovedPaths.remove(path.at(0));
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
218
219
220QFileSystemWatcher::QFileSystemWatcher(QObject *parent)
221 : QObject(*
new QFileSystemWatcherPrivate, parent)
227
228
229
230QFileSystemWatcher::QFileSystemWatcher(
const QStringList &paths, QObject *parent)
231 : QObject(*
new QFileSystemWatcherPrivate, parent)
238
239
240QFileSystemWatcher::~QFileSystemWatcher()
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266bool QFileSystemWatcher::addPath(
const QString &path)
268 if (path.isEmpty()) {
269 qWarning(
"QFileSystemWatcher::addPath: path is empty");
273 QStringList paths = addPaths(QStringList(path));
274 return paths.isEmpty();
280 p.reserve(paths.size());
281 const auto isEmpty = [](
const QString &s) {
return s.isEmpty(); };
282 std::remove_copy_if(paths.begin(), paths.end(),
283 std::back_inserter(p),
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311QStringList QFileSystemWatcher::addPaths(
const QStringList &paths)
313 Q_D(QFileSystemWatcher);
315 QStringList p = empty_paths_pruned(paths);
318 qWarning(
"QFileSystemWatcher::addPaths: list is empty");
321 qCDebug(lcWatcher) <<
"adding" << paths;
322 const auto selectEngine = [
this, d]() -> QFileSystemWatcherEngine* {
323#ifdef QT_BUILD_INTERNAL
324 const QString on = objectName();
326 if (Q_UNLIKELY(on.startsWith(
"_qt_autotest_force_engine_"_L1))) {
328 const auto forceName = QStringView{on}.mid(26);
329 if (forceName ==
"poller"_L1) {
330 qCDebug(lcWatcher,
"QFileSystemWatcher: skipping native engine, using only polling engine");
331 d_func()->initPollerEngine();
333 }
else if (forceName ==
"native"_L1) {
334 qCDebug(lcWatcher,
"QFileSystemWatcher: skipping polling engine, using only native engine");
344 d_func()->initPollerEngine();
349 if (
auto engine = selectEngine())
350 p = engine->addPaths(p, &d->files, &d->directories);
356
357
358
359
360
361
362
363
364
365bool QFileSystemWatcher::removePath(
const QString &path)
367 if (path.isEmpty()) {
368 qWarning(
"QFileSystemWatcher::removePath: path is empty");
372 QStringList paths = removePaths(QStringList(path));
373 return paths.isEmpty();
377
378
379
380
381
382
383
384
385
386
387QStringList QFileSystemWatcher::removePaths(
const QStringList &paths)
389 Q_D(QFileSystemWatcher);
391 QStringList p = empty_paths_pruned(paths);
394 qWarning(
"QFileSystemWatcher::removePaths: list is empty");
397 qCDebug(lcWatcher) <<
"removing" << paths;
400 p = d->native->removePaths(p, &d->files, &d->directories);
402 p = d->poller->removePaths(p, &d->files, &d->directories);
408
409
410
411
412
413
414
415
416
417
418
419
420
423
424
425
426
427
428
429
430
431
432
433
436
437
438
439
440
441
444
445
446
447
448
449
451QStringList QFileSystemWatcher::directories()
const
453 Q_D(
const QFileSystemWatcher);
454 return d->directories;
457QStringList QFileSystemWatcher::files()
const
459 Q_D(
const QFileSystemWatcher);
465#include "moc_qfilesystemwatcher.cpp"
466#include "moc_qfilesystemwatcher_p.cpp"
void connectEngine(QFileSystemWatcherEngine *e)
void fileChanged(const QString &path, bool removed)
QFileSystemWatcherEngine * native
QFileSystemWatcherEngine * poller
QFileSystemWatcherPrivate()
void directoryChanged(const QString &path, bool removed)
static QStringList empty_paths_pruned(const QStringList &paths)
#define qCDebug(category,...)
#define Q_STATIC_LOGGING_CATEGORY(name,...)