]>
git.saurik.com Git - wxWidgets.git/blob - src/common/fswatchercmn.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/common/fswatchercmn.cpp
3 // Purpose: wxMswFileSystemWatcher
4 // Author: Bartosz Bekier
6 // Copyright: (c) 2009 Bartosz Bekier <bartosz.bekier@gmail.com>
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
10 // For compilers that support precompilation, includes "wx.h".
11 #include "wx/wxprec.h"
19 #include "wx/fswatcher.h"
20 #include "wx/private/fswatcher.h"
22 // ============================================================================
24 // ============================================================================
26 wxDEFINE_EVENT(wxEVT_FSWATCHER
, wxFileSystemWatcherEvent
);
28 static wxString
GetFSWEventChangeTypeName(int type
)
32 case wxFSW_EVENT_CREATE
:
34 case wxFSW_EVENT_DELETE
:
36 case wxFSW_EVENT_RENAME
:
38 case wxFSW_EVENT_MODIFY
:
40 case wxFSW_EVENT_ACCESS
:
42 case wxFSW_EVENT_ATTRIB
: // Currently this is wxGTK-only
45 case wxFSW_EVENT_UNMOUNT
: // Currently this is wxGTK-only
48 case wxFSW_EVENT_WARNING
:
50 case wxFSW_EVENT_ERROR
:
54 // should never be reached!
55 wxFAIL_MSG("Unknown change type");
56 return "INVALID_TYPE";
60 // ============================================================================
61 // wxFileSystemWatcherEvent implementation
62 // ============================================================================
64 IMPLEMENT_DYNAMIC_CLASS(wxFileSystemWatcherEvent
, wxEvent
);
66 wxString
wxFileSystemWatcherEvent::ToString() const
68 return wxString::Format("FSW_EVT type=%d (%s) path='%s'", m_changeType
,
69 GetFSWEventChangeTypeName(m_changeType
), GetPath().GetFullPath());
73 // ============================================================================
74 // wxFileSystemWatcherEvent implementation
75 // ============================================================================
77 wxFileSystemWatcherBase::wxFileSystemWatcherBase() :
78 m_service(0), m_owner(this)
82 wxFileSystemWatcherBase::~wxFileSystemWatcherBase()
91 bool wxFileSystemWatcherBase::Add(const wxFileName
& path
, int events
)
93 wxFSWPathType type
= wxFSWPath_None
;
94 if ( path
.FileExists() )
96 type
= wxFSWPath_File
;
98 else if ( path
.DirExists() )
100 type
= wxFSWPath_Dir
;
104 // Don't overreact to being passed a non-existent item. It may have
105 // only just been deleted, in which case doing nothing is correct
106 wxLogTrace(wxTRACE_FSWATCHER
,
107 "Can't monitor non-existent path \"%s\" for changes.",
112 return AddAny(path
, events
, type
);
116 wxFileSystemWatcherBase::AddAny(const wxFileName
& path
,
119 const wxString
& filespec
)
121 wxString canonical
= GetCanonicalPath(path
);
122 if (canonical
.IsEmpty())
125 // adding a path in a platform specific way
126 wxFSWatchInfo
watch(canonical
, events
, type
, filespec
);
127 if ( !m_service
->Add(watch
) )
130 // on success, either add path to our 'watch-list'
131 // or, if already watched, inc the refcount. This may happen if
132 // a dir is Add()ed, then later AddTree() is called on a parent dir
133 wxFSWatchInfoMap::iterator it
= m_watches
.find(canonical
);
134 if ( it
== m_watches
.end() )
136 wxFSWatchInfoMap::value_type
val(canonical
, watch
);
137 m_watches
.insert(val
);
141 wxFSWatchInfo
& watch
= it
->second
;
142 int count
= watch
.IncRef();
143 wxLogTrace(wxTRACE_FSWATCHER
,
144 "'%s' is now watched %d times", canonical
, count
);
149 bool wxFileSystemWatcherBase::Remove(const wxFileName
& path
)
151 // args validation & consistency checks
152 wxString canonical
= GetCanonicalPath(path
);
153 if (canonical
.IsEmpty())
156 wxFSWatchInfoMap::iterator it
= m_watches
.find(canonical
);
157 wxCHECK_MSG(it
!= m_watches
.end(), false,
158 wxString::Format("Path '%s' is not watched", canonical
));
160 // Decrement the watch's refcount and remove from watch-list if 0
162 wxFSWatchInfo
& watch
= it
->second
;
163 if ( !watch
.DecRef() )
165 // remove in a platform specific way
166 ret
= m_service
->Remove(watch
);
173 bool wxFileSystemWatcherBase::AddTree(const wxFileName
& path
, int events
,
174 const wxString
& filespec
)
176 if (!path
.DirExists())
179 // OPT could be optimised if we stored information about relationships
181 class AddTraverser
: public wxDirTraverser
184 AddTraverser(wxFileSystemWatcherBase
* watcher
, int events
,
185 const wxString
& filespec
) :
186 m_watcher(watcher
), m_events(events
), m_filespec(filespec
)
190 virtual wxDirTraverseResult
OnFile(const wxString
& WXUNUSED(filename
))
192 // There is no need to watch individual files as we watch the
193 // parent directory which will notify us about any changes in them.
194 return wxDIR_CONTINUE
;
197 virtual wxDirTraverseResult
OnDir(const wxString
& dirname
)
199 if ( m_watcher
->AddAny(wxFileName::DirName(dirname
),
200 m_events
, wxFSWPath_Tree
, m_filespec
) )
202 wxLogTrace(wxTRACE_FSWATCHER
,
203 "--- AddTree adding directory '%s' ---", dirname
);
205 return wxDIR_CONTINUE
;
209 wxFileSystemWatcherBase
* m_watcher
;
214 wxDir
dir(path
.GetFullPath());
215 // Prevent asserts or infinite loops in trees containing symlinks
216 int flags
= wxDIR_DIRS
;
217 if ( !path
.ShouldFollowLink() )
219 flags
|= wxDIR_NO_FOLLOW
;
221 AddTraverser
traverser(this, events
, filespec
);
222 dir
.Traverse(traverser
, filespec
, flags
);
224 // Add the path itself explicitly as Traverse() doesn't return it.
225 AddAny(path
.GetPathWithSep(), events
, wxFSWPath_Tree
, filespec
);
230 bool wxFileSystemWatcherBase::RemoveTree(const wxFileName
& path
)
232 if (!path
.DirExists())
235 // OPT could be optimised if we stored information about relationships
237 class RemoveTraverser
: public wxDirTraverser
240 RemoveTraverser(wxFileSystemWatcherBase
* watcher
,
241 const wxString
& filespec
) :
242 m_watcher(watcher
), m_filespec(filespec
)
246 virtual wxDirTraverseResult
OnFile(const wxString
& WXUNUSED(filename
))
248 // We never watch the individual files when watching the tree, so
249 // nothing to do here.
250 return wxDIR_CONTINUE
;
253 virtual wxDirTraverseResult
OnDir(const wxString
& dirname
)
255 m_watcher
->Remove(wxFileName::DirName(dirname
));
256 return wxDIR_CONTINUE
;
260 wxFileSystemWatcherBase
* m_watcher
;
264 // If AddTree() used a filespec, we must use the same one
265 wxString canonical
= GetCanonicalPath(path
);
266 wxFSWatchInfoMap::iterator it
= m_watches
.find(canonical
);
267 wxCHECK_MSG( it
!= m_watches
.end(), false,
268 wxString::Format("Path '%s' is not watched", canonical
) );
269 wxFSWatchInfo watch
= it
->second
;
270 const wxString filespec
= watch
.GetFilespec();
272 #if defined(__WINDOWS__)
273 // When there's no filespec, the wxMSW AddTree() would have set a watch
274 // on only the passed 'path'. We must therefore remove only this
275 if (filespec
.empty())
279 // Otherwise fall through to the generic implementation
280 #endif // __WINDOWS__
282 wxDir
dir(path
.GetFullPath());
283 // AddTree() might have used the wxDIR_NO_FOLLOW to prevent asserts or
284 // infinite loops in trees containing symlinks. We need to do the same
285 // or we'll try to remove unwatched items. Let's hope the caller used
286 // the same ShouldFollowLink() setting as in AddTree()...
287 int flags
= wxDIR_DIRS
;
288 if ( !path
.ShouldFollowLink() )
290 flags
|= wxDIR_NO_FOLLOW
;
292 RemoveTraverser
traverser(this, filespec
);
293 dir
.Traverse(traverser
, filespec
, flags
);
295 // As in AddTree() above, handle the path itself explicitly.
301 bool wxFileSystemWatcherBase::RemoveAll()
303 m_service
->RemoveAll();
308 int wxFileSystemWatcherBase::GetWatchedPathsCount() const
310 return m_watches
.size();
313 int wxFileSystemWatcherBase::GetWatchedPaths(wxArrayString
* paths
) const
315 wxCHECK_MSG( paths
!= NULL
, -1, "Null array passed to retrieve paths");
317 wxFSWatchInfoMap::const_iterator it
= m_watches
.begin();
318 for ( ; it
!= m_watches
.end(); ++it
)
320 paths
->push_back(it
->first
);
323 return m_watches
.size();
326 #endif // wxUSE_FSWATCHER