// check out for error/warning condition
if (flags & wxFSW_EVENT_WARNING || flags & wxFSW_EVENT_ERROR)
{
- wxString errMsg = GetErrorDescription(Watcher2NativeFlags(flags));
+ wxString errMsg = GetErrorDescription(nativeFlags);
wxFileSystemWatcherEvent event(flags, errMsg);
SendEvent(event);
}
+ // Now IN_UNMOUNT. We must do so here, as it's not in the watch flags
+ if (nativeFlags & IN_UNMOUNT)
+ {
+ wxFileName path = GetEventPath(watch, inevt);
+ wxFileSystemWatcherEvent event(wxFSW_EVENT_UNMOUNT, path, path);
+ SendEvent(event);
+ }
// filter out ignored events and those not asked for.
// we never filter out warnings or exceptions
else if ((flags == 0) || !(flags & watch.GetFlags()))
{
return;
}
+
+ // Creation
+ // We need do something here only if the original watch was recursive;
+ // we don't watch a child dir itself inside a non-tree watch.
+ // We watch only dirs explicitly, so we don't want file IN_CREATEs.
+ // Distinguish by whether nativeFlags contain IN_ISDIR
+ else if ((nativeFlags & IN_CREATE) &&
+ (watch.GetType() == wxFSWPath_Tree) && (inevt.mask & IN_ISDIR))
+ {
+ wxFileName fn = GetEventPath(watch, inevt);
+ // Though it's a dir, fn treats it as a file. So:
+ fn.AssignDir(fn.GetFullPath());
+
+ if (m_watcher->AddAny(fn, wxFSW_EVENT_ALL,
+ wxFSWPath_Tree, watch.GetFilespec()))
+ {
+ // Tell the owner, in case it's interested
+ // If there's a filespec, assume he's not
+ if (watch.GetFilespec().empty())
+ {
+ wxFileSystemWatcherEvent event(flags, fn, fn);
+ SendEvent(event);
+ }
+ }
+ }
+
+ // Deletion
+ // We watch only dirs explicitly, so we don't want file IN_DELETEs.
+ // We obviously can't check using DirExists() as the object has been
+ // deleted; and nativeFlags here doesn't contain IN_ISDIR, even for
+ // a dir. Fortunately IN_DELETE_SELF doesn't happen for files. We need
+ // to do something here only inside a tree watch, or if it's the parent
+ // dir that's deleted. Otherwise let the parent dir cope
+ else if ((nativeFlags & IN_DELETE_SELF) &&
+ ((watch.GetType() == wxFSWPath_Dir) ||
+ (watch.GetType() == wxFSWPath_Tree)))
+ {
+ // We must remove the deleted directory from the map, so that
+ // DoRemoveInotify() isn't called on it in the future. Don't assert
+ // if the wd isn't found: repeated IN_DELETE_SELFs can occur
+ wxFileName fn = GetEventPath(watch, inevt);
+ wxString path(fn.GetPathWithSep());
+
+ if (m_watchMap.erase(inevt.wd) == 1)
+ {
+ // Delete from wxFileSystemWatcher
+ wxDynamicCast(m_watcher, wxInotifyFileSystemWatcher)->
+ OnDirDeleted(path);
+
+ // Now remove from our local list of watched items
+ wxFSWatchEntries::iterator wit =
+ m_watches.find(path);
+ if (wit != m_watches.end())
+ {
+ m_watches.erase(wit);
+ }
+
+ // Cache the wd in case any events arrive late
+ m_staleDescriptors.Add(inevt.wd);
+ }
+
+ // Tell the owner, in case it's interested
+ // If there's a filespec, assume he's not
+ if (watch.GetFilespec().empty())
+ {
+ wxFileSystemWatcherEvent event(flags, fn, fn);
+ SendEvent(event);
+ }
+ }
+
// renames
else if (nativeFlags & IN_MOVE)
{
return path;
}
- static int Watcher2NativeFlags(int WXUNUSED(flags))
+ static int Watcher2NativeFlags(int flags)
{
- // TODO: it would be nice to subscribe only to the events we really need
- return IN_ALL_EVENTS;
+ // Start with the standard case of wanting all events
+ if (flags == wxFSW_EVENT_ALL)
+ {
+ return IN_ALL_EVENTS;
+ }
+
+ static const int flag_mapping[][2] = {
+ { wxFSW_EVENT_ACCESS, IN_ACCESS },
+ { wxFSW_EVENT_MODIFY, IN_MODIFY },
+ { wxFSW_EVENT_ATTRIB, IN_ATTRIB },
+ { wxFSW_EVENT_RENAME, IN_MOVE },
+ { wxFSW_EVENT_CREATE, IN_CREATE },
+ { wxFSW_EVENT_DELETE, IN_DELETE|IN_DELETE_SELF|IN_MOVE_SELF },
+ { wxFSW_EVENT_UNMOUNT, IN_UNMOUNT }
+ // wxFSW_EVENT_ERROR/WARNING make no sense here
+ };
+
+ int native_flags = 0;
+ for ( unsigned int i=0; i < WXSIZEOF(flag_mapping); ++i)
+ {
+ if (flags & flag_mapping[i][0])
+ native_flags |= flag_mapping[i][1];
+ }
+
+ return native_flags;
}
static int Native2WatcherFlags(int flags)
static const int flag_mapping[][2] = {
{ IN_ACCESS, wxFSW_EVENT_ACCESS }, // generated during read!
{ IN_MODIFY, wxFSW_EVENT_MODIFY },
- { IN_ATTRIB, 0 },
+ { IN_ATTRIB, wxFSW_EVENT_ATTRIB },
{ IN_CLOSE_WRITE, 0 },
{ IN_CLOSE_NOWRITE, 0 },
{ IN_OPEN, 0 },
{ IN_DELETE_SELF, wxFSW_EVENT_DELETE },
{ IN_MOVE_SELF, wxFSW_EVENT_DELETE },
- { IN_UNMOUNT, wxFSW_EVENT_ERROR },
+ { IN_UNMOUNT, wxFSW_EVENT_UNMOUNT},
{ IN_Q_OVERFLOW, wxFSW_EVENT_WARNING},
- // ignored, because this is genereted mainly by watcher::Remove()
+ // ignored, because this is generated mainly by watcher::Remove()
{ IN_IGNORED, 0 }
};
{
switch ( flag )
{
- case IN_UNMOUNT:
- return _("File system containing watched object was unmounted");
case IN_Q_OVERFLOW:
return _("Event queue overflowed");
}
return m_service->Init();
}
+void wxInotifyFileSystemWatcher::OnDirDeleted(const wxString& path)
+{
+ if (!path.empty())
+ {
+ wxFSWatchInfoMap::iterator it = m_watches.find(path);
+ wxCHECK_RET(it != m_watches.end(),
+ wxString::Format("Path '%s' is not watched", path));
+
+ // path has been deleted, so we must forget it whatever its refcount
+ m_watches.erase(it);
+ }
+}
+
#endif // wxHAS_INOTIFY
#endif // wxUSE_FSWATCHER