Make wxFileSystemWatcher watch entries reference-counted.
[wxWidgets.git] / include / wx / fswatcher.h
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: wx/fswatcher.h
3 // Purpose: wxFileSystemWatcherBase
4 // Author: Bartosz Bekier
5 // Created: 2009-05-23
6 // RCS-ID: $Id$
7 // Copyright: (c) 2009 Bartosz Bekier <bartosz.bekier@gmail.com>
8 // Licence: wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
10
11 #ifndef _WX_FSWATCHER_BASE_H_
12 #define _WX_FSWATCHER_BASE_H_
13
14 #include "wx/defs.h"
15
16 #if wxUSE_FSWATCHER
17
18 #include "wx/log.h"
19 #include "wx/event.h"
20 #include "wx/evtloop.h"
21 #include "wx/filename.h"
22 #include "wx/dir.h"
23 #include "wx/hashmap.h"
24
25 #define wxTRACE_FSWATCHER "fswatcher"
26
27 // ----------------------------------------------------------------------------
28 // wxFileSystemWatcherEventType & wxFileSystemWatcherEvent
29 // ----------------------------------------------------------------------------
30
31 /**
32 * Possible types of file system events.
33 * This is a subset that will work fine an all platforms (actually, we will
34 * see how it works on Mac).
35 *
36 * We got 2 types of error events:
37 * - warning: these are not fatal and further events can still be generated
38 * - error: indicates fatal error and causes that no more events will happen
39 */
40 enum
41 {
42 wxFSW_EVENT_CREATE = 0x01,
43 wxFSW_EVENT_DELETE = 0x02,
44 wxFSW_EVENT_RENAME = 0x04,
45 wxFSW_EVENT_MODIFY = 0x08,
46 wxFSW_EVENT_ACCESS = 0x10,
47
48 // error events
49 wxFSW_EVENT_WARNING = 0x20,
50 wxFSW_EVENT_ERROR = 0x40,
51
52 wxFSW_EVENT_ALL = wxFSW_EVENT_CREATE | wxFSW_EVENT_DELETE |
53 wxFSW_EVENT_RENAME | wxFSW_EVENT_MODIFY |
54 wxFSW_EVENT_ACCESS |
55 wxFSW_EVENT_WARNING | wxFSW_EVENT_ERROR
56 };
57
58 // Type of the path watched, used only internally for now.
59 enum wxFSWPathType
60 {
61 wxFSWPath_None, // Invalid value for an initialized watch.
62 wxFSWPath_File, // Plain file.
63 wxFSWPath_Dir, // Watch a directory and the files in it.
64 wxFSWPath_Tree // Watch a directory and all its children recursively.
65 };
66
67
68 /**
69 * Event containing information about file system change.
70 */
71 class WXDLLIMPEXP_FWD_BASE wxFileSystemWatcherEvent;
72 wxDECLARE_EXPORTED_EVENT(WXDLLIMPEXP_BASE, wxEVT_FSWATCHER,
73 wxFileSystemWatcherEvent);
74
75 class WXDLLIMPEXP_BASE wxFileSystemWatcherEvent: public wxEvent
76 {
77 public:
78 wxFileSystemWatcherEvent(int changeType, int watchid = wxID_ANY) :
79 wxEvent(watchid, wxEVT_FSWATCHER),
80 m_changeType(changeType)
81 {
82 }
83
84 wxFileSystemWatcherEvent(int changeType, const wxString& errorMsg,
85 int watchid = wxID_ANY) :
86 wxEvent(watchid, wxEVT_FSWATCHER),
87 m_changeType(changeType), m_errorMsg(errorMsg)
88 {
89 }
90
91 wxFileSystemWatcherEvent(int changeType,
92 const wxFileName& path, const wxFileName& newPath,
93 int watchid = wxID_ANY) :
94 wxEvent(watchid, wxEVT_FSWATCHER),
95 m_changeType(changeType), m_path(path), m_newPath(newPath)
96 {
97 }
98
99 /**
100 * Returns the path at which the event occurred.
101 */
102 const wxFileName& GetPath() const
103 {
104 return m_path;
105 }
106
107 /**
108 * Sets the path at which the event occurred
109 */
110 void SetPath(const wxFileName& path)
111 {
112 m_path = path;
113 }
114
115 /**
116 * In case of rename(move?) events, returns the new path related to the
117 * event. The "new" means newer in the sense of time. In case of other
118 * events it returns the same path as GetPath().
119 */
120 const wxFileName& GetNewPath() const
121 {
122 return m_newPath;
123 }
124
125 /**
126 * Sets the new path related to the event. See above.
127 */
128 void SetNewPath(const wxFileName& path)
129 {
130 m_newPath = path;
131 }
132
133 /**
134 * Returns the type of file system event that occurred.
135 */
136 int GetChangeType() const
137 {
138 return m_changeType;
139 }
140
141 virtual wxEvent* Clone() const
142 {
143 wxFileSystemWatcherEvent* evt = new wxFileSystemWatcherEvent(*this);
144 evt->m_errorMsg = m_errorMsg.Clone();
145 evt->m_path = wxFileName(m_path.GetFullPath().Clone());
146 evt->m_newPath = wxFileName(m_newPath.GetFullPath().Clone());
147 return evt;
148 }
149
150 virtual wxEventCategory GetEventCategory() const
151 {
152 // TODO this has to be merged with "similiar" categories and changed
153 return wxEVT_CATEGORY_UNKNOWN;
154 }
155
156 /**
157 * Returns if this error is an error event
158 */
159 bool IsError() const
160 {
161 return (m_changeType & (wxFSW_EVENT_ERROR | wxFSW_EVENT_WARNING)) != 0;
162 }
163
164 wxString GetErrorDescription() const
165 {
166 return m_errorMsg;
167 }
168
169 /**
170 * Returns a wxString describing an event useful for debugging or testing
171 */
172 wxString ToString() const;
173
174 protected:
175 int m_changeType;
176 wxFileName m_path;
177 wxFileName m_newPath;
178 wxString m_errorMsg;
179 };
180
181 typedef void (wxEvtHandler::*wxFileSystemWatcherEventFunction)
182 (wxFileSystemWatcherEvent&);
183
184 #define wxFileSystemWatcherEventHandler(func) \
185 wxEVENT_HANDLER_CAST(wxFileSystemWatcherEventFunction, func)
186
187 #define EVT_FSWATCHER(winid, func) \
188 wx__DECLARE_EVT1(wxEVT_FSWATCHER, winid, wxFileSystemWatcherEventHandler(func))
189
190 // ----------------------------------------------------------------------------
191 // wxFileSystemWatcherBase: interface for wxFileSystemWatcher
192 // ----------------------------------------------------------------------------
193
194 // Simple container to store information about one watched path.
195 class wxFSWatchInfo
196 {
197 public:
198 wxFSWatchInfo() :
199 m_events(-1), m_type(wxFSWPath_None), m_refcount(-1)
200 {
201 }
202
203 wxFSWatchInfo(const wxString& path,
204 int events,
205 wxFSWPathType type,
206 const wxString& filespec = wxString()) :
207 m_path(path), m_filespec(filespec), m_events(events), m_type(type),
208 m_refcount(1)
209 {
210 }
211
212 const wxString& GetPath() const
213 {
214 return m_path;
215 }
216
217 const wxString& GetFilespec() const { return m_filespec; }
218
219 int GetFlags() const
220 {
221 return m_events;
222 }
223
224 wxFSWPathType GetType() const
225 {
226 return m_type;
227 }
228
229 // Reference counting of watch entries is used to avoid watching the same
230 // file system path multiple times (this can happen even accidentally, e.g.
231 // when you have a recursive watch and then decide to watch some file or
232 // directory under it separately).
233 int IncRef()
234 {
235 return ++m_refcount;
236 }
237
238 int DecRef()
239 {
240 wxASSERT_MSG( m_refcount > 0, wxS("Trying to decrement a zero count") );
241 return --m_refcount;
242 }
243
244 protected:
245 wxString m_path;
246 wxString m_filespec; // For tree watches, holds any filespec to apply
247 int m_events;
248 wxFSWPathType m_type;
249 int m_refcount;
250 };
251
252 WX_DECLARE_STRING_HASH_MAP(wxFSWatchInfo, wxFSWatchInfoMap);
253
254 /**
255 * Encapsulation of platform-specific file system event mechanism
256 */
257 class wxFSWatcherImpl;
258
259 /**
260 * Main entry point for clients interested in file system events.
261 * Defines interface that can be used to receive that kind of events.
262 */
263 class WXDLLIMPEXP_BASE wxFileSystemWatcherBase: public wxEvtHandler
264 {
265 public:
266 wxFileSystemWatcherBase();
267
268 virtual ~wxFileSystemWatcherBase();
269
270 /**
271 * Adds path to currently watched files. Any events concerning this
272 * particular path will be sent to handler. Optionally a filter can be
273 * specified to receive only events of particular type.
274 *
275 * Please note that when adding a dir, immediate children will be watched
276 * as well.
277 */
278 virtual bool Add(const wxFileName& path, int events = wxFSW_EVENT_ALL);
279
280 /**
281 * Like above, but recursively adds every file/dir in the tree rooted in
282 * path. Additionally a file mask can be specified to include only files
283 * of particular type.
284 */
285 virtual bool AddTree(const wxFileName& path, int events = wxFSW_EVENT_ALL,
286 const wxString& filespec = wxEmptyString);
287
288 /**
289 * Removes path from the list of watched paths.
290 */
291 virtual bool Remove(const wxFileName& path);
292
293 /**
294 * Same as above, but also removes every file belonging to the tree rooted
295 * at path.
296 */
297 virtual bool RemoveTree(const wxFileName& path);
298
299 /**
300 * Clears the list of currently watched paths.
301 */
302 virtual bool RemoveAll();
303
304 /**
305 * Returns the number of watched paths
306 */
307 int GetWatchedPathsCount() const;
308
309 /**
310 * Retrevies all watched paths and places them in wxArrayString. Returns
311 * the number of paths.
312 *
313 * TODO think about API here: we need to return more information (like is
314 * the path watched recursively)
315 */
316 int GetWatchedPaths(wxArrayString* paths) const;
317
318 wxEvtHandler* GetOwner() const
319 {
320 return m_owner;
321 }
322
323 void SetOwner(wxEvtHandler* handler)
324 {
325 if (!handler)
326 m_owner = this;
327 else
328 m_owner = handler;
329 }
330
331
332 // This is a semi-private function used by wxWidgets itself only.
333 //
334 // Delegates the real work of adding the path to wxFSWatcherImpl::Add() and
335 // updates m_watches if the new path was successfully added.
336 bool AddAny(const wxFileName& path, int events, wxFSWPathType type,
337 const wxString& filespec = wxString());
338
339 protected:
340
341 static wxString GetCanonicalPath(const wxFileName& path)
342 {
343 wxFileName path_copy = wxFileName(path);
344 if ( !path_copy.Normalize() )
345 {
346 wxFAIL_MSG(wxString::Format("Unable to normalize path '%s'",
347 path.GetFullPath()));
348 return wxEmptyString;
349 }
350
351 return path_copy.GetFullPath();
352 }
353
354
355 wxFSWatchInfoMap m_watches; // path=>wxFSWatchInfo map
356 wxFSWatcherImpl* m_service; // file system events service
357 wxEvtHandler* m_owner; // handler for file system events
358
359 friend class wxFSWatcherImpl;
360 };
361
362 // include the platform specific file defining wxFileSystemWatcher
363 // inheriting from wxFileSystemWatcherBase
364
365 #ifdef wxHAS_INOTIFY
366 #include "wx/unix/fswatcher_inotify.h"
367 #define wxFileSystemWatcher wxInotifyFileSystemWatcher
368 #elif defined(wxHAS_KQUEUE)
369 #include "wx/unix/fswatcher_kqueue.h"
370 #define wxFileSystemWatcher wxKqueueFileSystemWatcher
371 #elif defined(__WINDOWS__)
372 #include "wx/msw/fswatcher.h"
373 #define wxFileSystemWatcher wxMSWFileSystemWatcher
374 #else
375 #include "wx/generic/fswatcher.h"
376 #define wxFileSystemWatcher wxPollingFileSystemWatcher
377 #endif
378
379 #endif // wxUSE_FSWATCHER
380
381 #endif /* _WX_FSWATCHER_BASE_H_ */