Monday, 19 March 2012
Qt 5.1, aka: when QFileSystemWatcher might not be so useless
With 5.0 now being feature frozen, I thought I'd turn myself towards something I've been meaning to do (and talking about doing) for a very long time. Back before the Qt Project launched, even before Qt Contributors Summit 2011, in fact. I thought I'd make QFileSystemWatcher more useful.
Let's review what QFileSystemWatcher offers: a way to add and remove paths for monitoring directories and files, a directoryChanged(path) and a fileChanged(path) signal. That's it. If you think about this for a moment, you realise just how broken the semantics of the signals are: what _is_ a 'change' anyway? I guess this is one of the reasons that QFileSystemWatcher has been called 'deprecated' (I fixed one of the others, a performance issue, a while back).
So I've been working on making the signals a bit less useless. In the longer run, I plan to call fileChanged and directoryChanged deprecated. They'll still be emitted (of course) to keep existing code working, but in addition, you'll have (subject to review):
pathCreated(path) - emitted when something is created inside a directory you are monitoring, or if something that didn't exist that you were monitoring for is created (more on this later)
pathDeleted(path) - emitted when something is deleted inside a directory you were monitoring, or something that you _were_ monitoring was deleted
fileModified(path) - emitted when a file you were monitoring is modified (attributes or contents)
I also have early plans to introduce a pathMoved(oldLocation, newLocation), but that one has a lot of caveats: it might only work on certain platforms, in certain phases of the moon, and only if you're very lucky - on many platforms, it will likely continue to be synthesised as a pathDeleted(oldPath) and pathCreated(newPath) (if you're watching the new location).
I also have vague ideas about introducing more syntactically friendly API over the top of this, something like:
connect(&pathMonitor, SIGNAL(deleted()), SLOT(watchedPathDeleted()));
... etc ...
but that's a bit farther away in that I haven't really thought it through, yet.
In working on the new signals on Windows, I stumbled across QTBUG-2331, which sort of proves just how useless the existing signals were: deleting a watched directory on Windows essentially never removed the watch, because it didn't notice the deletion. Hopefully, it will be fixed soon, because it's going to block the work on the new signals: otherwise, pathDeleted will never be emitted on a watched path on Windows, and that makes my unit tests sad.
I noted earlier that I have plans to emit pathCreated when you monitor a non-existent path, well, that's correct - I intend to allow just that. None of the native APIs (that I know of) allow for recieving events when you monitor a non-existent path, which is a bit sad, as it means we'll need to fall back to polling on a timer for those cases, but it's certainly much better than nothing.
Oh, and if you're curious, it seems like Linux has the best filesystem monitoring API, in the form of inotify. OS X/BSD comes in second with kqueue (though having to open file descriptors to do the actual monitoring is a bit crap, and not being able to get any sort of real fine-grained notifications on _what_ was added/removed in a directory is also painful). Windows is also incredibly painful due to running into many stupid limitations (like only some ~60 paths being able to be monitored per thread, so the backend spawns loads of threads if you monitor a lot of paths), and not being able to get even remotely useful signals without a lot of extra legwork. Not to mention the above bug, where signals are emitted before deletion.
OS X may get more love in the future, as there is talk about another contributor revisiting the state of the FSEvents backend (which has been disabled for a very long time, and the code removed in Qt 5, due to being massively buggy and unmaintained).
For Windows, ReadDirectoryChangesW might improve the situation, somewhat, but I certainly don't have the time to investigate it for 5.1, and I also lack the motivation, not being a Windows user myself. Contributions welcome?