X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/227dee95e0c5b7e060c099329ba3d257281a24e2..a66bf817a6ba833ad47cefc9fa8948ef8045a59d:/src/common/fswatchercmn.cpp diff --git a/src/common/fswatchercmn.cpp b/src/common/fswatchercmn.cpp index 28aeffdcb6..a417a82ee7 100644 --- a/src/common/fswatchercmn.cpp +++ b/src/common/fswatchercmn.cpp @@ -40,6 +40,16 @@ static wxString GetFSWEventChangeTypeName(int type) return "MODIFY"; case wxFSW_EVENT_ACCESS: return "ACCESS"; + case wxFSW_EVENT_ATTRIB: // Currently this is wxGTK-only + return "ATTRIBUTE"; +#ifdef wxHAS_INOTIFY + case wxFSW_EVENT_UNMOUNT: // Currently this is wxGTK-only + return "UNMOUNT"; +#endif + case wxFSW_EVENT_WARNING: + return "WARNING"; + case wxFSW_EVENT_ERROR: + return "ERROR"; } // should never be reached! @@ -52,6 +62,8 @@ static wxString GetFSWEventChangeTypeName(int type) // wxFileSystemWatcherEvent implementation // ============================================================================ +IMPLEMENT_DYNAMIC_CLASS(wxFileSystemWatcherEvent, wxEvent); + wxString wxFileSystemWatcherEvent::ToString() const { return wxString::Format("FSW_EVT type=%d (%s) path='%s'", m_changeType, @@ -90,7 +102,10 @@ bool wxFileSystemWatcherBase::Add(const wxFileName& path, int events) } else { - wxLogError(_("Can't monitor non-existent path \"%s\" for changes."), + // Don't overreact to being passed a non-existent item. It may have + // only just been deleted, in which case doing nothing is correct + wxLogTrace(wxTRACE_FSWATCHER, + "Can't monitor non-existent path \"%s\" for changes.", path.GetFullPath()); return false; } @@ -108,17 +123,28 @@ wxFileSystemWatcherBase::AddAny(const wxFileName& path, if (canonical.IsEmpty()) return false; - wxCHECK_MSG(m_watches.find(canonical) == m_watches.end(), false, - wxString::Format("Path '%s' is already watched", canonical)); - // adding a path in a platform specific way wxFSWatchInfo watch(canonical, events, type, filespec); if ( !m_service->Add(watch) ) return false; - // on success, add path to our 'watch-list' - wxFSWatchInfoMap::value_type val(canonical, watch); - return m_watches.insert(val).second; + // on success, either add path to our 'watch-list' + // or, if already watched, inc the refcount. This may happen if + // a dir is Add()ed, then later AddTree() is called on a parent dir + wxFSWatchInfoMap::iterator it = m_watches.find(canonical); + if ( it == m_watches.end() ) + { + wxFSWatchInfoMap::value_type val(canonical, watch); + m_watches.insert(val); + } + else + { + wxFSWatchInfo& watch = it->second; + int count = watch.IncRef(); + wxLogTrace(wxTRACE_FSWATCHER, + "'%s' is now watched %d times", canonical, count); + } + return true; } bool wxFileSystemWatcherBase::Remove(const wxFileName& path) @@ -132,12 +158,17 @@ bool wxFileSystemWatcherBase::Remove(const wxFileName& path) wxCHECK_MSG(it != m_watches.end(), false, wxString::Format("Path '%s' is not watched", canonical)); - // remove from watch-list - wxFSWatchInfo watch = it->second; - m_watches.erase(it); + // Decrement the watch's refcount and remove from watch-list if 0 + bool ret = true; + wxFSWatchInfo& watch = it->second; + if ( !watch.DecRef() ) + { + // remove in a platform specific way + ret = m_service->Remove(watch); - // remove in a platform specific way - return m_service->Remove(watch); + m_watches.erase(it); + } + return ret; } bool wxFileSystemWatcherBase::AddTree(const wxFileName& path, int events, @@ -157,34 +188,20 @@ bool wxFileSystemWatcherBase::AddTree(const wxFileName& path, int events, { } - // CHECK we choose which files to delegate to Add(), maybe we should pass - // all of them to Add() and let it choose? this is useful when adding a - // file to a dir that is already watched, then not only should we know - // about that, but Add() should also behave well then - virtual wxDirTraverseResult OnFile(const wxString& filename) + virtual wxDirTraverseResult OnFile(const wxString& WXUNUSED(filename)) { - if ( m_watcher->AddAny(wxFileName::FileName(filename), - m_events, wxFSWPath_File) ) - { - wxLogTrace(wxTRACE_FSWATCHER, - "--- AddTree adding file '%s' ---", filename); - } + // There is no need to watch individual files as we watch the + // parent directory which will notify us about any changes in them. return wxDIR_CONTINUE; } virtual wxDirTraverseResult OnDir(const wxString& dirname) { - // We can't currently watch only the files with the given filespec - // in the subdirectories so we only watch subdirectories at all if - // we want to watch everything. - if ( m_filespec.empty() ) + if ( m_watcher->AddAny(wxFileName::DirName(dirname), + m_events, wxFSWPath_Tree, m_filespec) ) { - if ( m_watcher->AddAny(wxFileName::DirName(dirname), - m_events, wxFSWPath_Dir) ) - { - wxLogTrace(wxTRACE_FSWATCHER, - "--- AddTree adding directory '%s' ---", dirname); - } + wxLogTrace(wxTRACE_FSWATCHER, + "--- AddTree adding directory '%s' ---", dirname); } return wxDIR_CONTINUE; } @@ -196,11 +213,17 @@ bool wxFileSystemWatcherBase::AddTree(const wxFileName& path, int events, }; wxDir dir(path.GetFullPath()); + // Prevent asserts or infinite loops in trees containing symlinks + int flags = wxDIR_DIRS; + if ( !path.ShouldFollowLink() ) + { + flags |= wxDIR_NO_FOLLOW; + } AddTraverser traverser(this, events, filespec); - dir.Traverse(traverser, filespec); + dir.Traverse(traverser, filespec, flags); // Add the path itself explicitly as Traverse() doesn't return it. - AddAny(path.GetPathWithSep(), events, wxFSWPath_Dir, filespec); + AddAny(path.GetPathWithSep(), events, wxFSWPath_Tree, filespec); return true; } @@ -221,24 +244,16 @@ bool wxFileSystemWatcherBase::RemoveTree(const wxFileName& path) { } - virtual wxDirTraverseResult OnFile(const wxString& filename) + virtual wxDirTraverseResult OnFile(const wxString& WXUNUSED(filename)) { - m_watcher->Remove(wxFileName(filename)); + // We never watch the individual files when watching the tree, so + // nothing to do here. return wxDIR_CONTINUE; } virtual wxDirTraverseResult OnDir(const wxString& dirname) { - // Currently the subdirectories would have been added only if there - // is no filespec. - // - // Notice that we still need to recurse into them even if we're - // using a filespec because they can contain files matching it. - if ( m_filespec.empty() ) - { - m_watcher->Remove(wxFileName::DirName(dirname)); - } - + m_watcher->Remove(wxFileName::DirName(dirname)); return wxDIR_CONTINUE; } @@ -266,8 +281,17 @@ bool wxFileSystemWatcherBase::RemoveTree(const wxFileName& path) #endif // __WINDOWS__ wxDir dir(path.GetFullPath()); + // AddTree() might have used the wxDIR_NO_FOLLOW to prevent asserts or + // infinite loops in trees containing symlinks. We need to do the same + // or we'll try to remove unwatched items. Let's hope the caller used + // the same ShouldFollowLink() setting as in AddTree()... + int flags = wxDIR_DIRS; + if ( !path.ShouldFollowLink() ) + { + flags |= wxDIR_NO_FOLLOW; + } RemoveTraverser traverser(this, filespec); - dir.Traverse(traverser, filespec); + dir.Traverse(traverser, filespec, flags); // As in AddTree() above, handle the path itself explicitly. Remove(path);