X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/0f306261b8274121e55b873392d2a5ab3ed30e03..cb04da13bddf9c70028b7adb55ac4efbb92ce4d4:/src/unix/fswatcher_inotify.cpp diff --git a/src/unix/fswatcher_inotify.cpp b/src/unix/fswatcher_inotify.cpp index 2349d4b9fc..f7438727df 100644 --- a/src/unix/fswatcher_inotify.cpp +++ b/src/unix/fswatcher_inotify.cpp @@ -261,16 +261,93 @@ protected: // 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) { @@ -409,10 +486,33 @@ protected: 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) @@ -420,7 +520,7 @@ protected: 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 }, @@ -431,10 +531,10 @@ protected: { 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 } }; @@ -457,8 +557,6 @@ protected: { switch ( flag ) { - case IN_UNMOUNT: - return _("File system containing watched object was unmounted"); case IN_Q_OVERFLOW: return _("Event queue overflowed"); } @@ -535,6 +633,19 @@ bool wxInotifyFileSystemWatcher::Init() 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