Ticket #514: mac_watchdir.v3.patch​

File mac_watchdir.v3.patch​, 33.5 KB (added by stwf, 11 years ago)
Line 
1Index: libraries/source/fcollada/src/FCollada/FColladaTest/RunFColladaTests/RunFColladaTests.cs
2===================================================================
3--- libraries/source/fcollada/src/FCollada/FColladaTest/RunFColladaTests/RunFColladaTests.cs (revision 13812)
4+++ libraries/source/fcollada/src/FCollada/FColladaTest/RunFColladaTests/RunFColladaTests.cs (working copy)
5@@ -29,7 +29,7 @@
6
7 // test for file existence
8 String fullName = path + exe;
9- FileInfo file = new FileInfo( fullName );
10+ CFileInfo file = new CFileInfo( fullName );
11
12 Assert.IsTrue( file.Exists, "Unable to find executable : " + fullName );
13
14@@ -50,7 +50,7 @@
15 String procErr = proc.StandardError.ReadToEnd();
16 Assert.IsTrue( (procErr.Length == 0), procErr );
17
18- FileInfo outFile = new FileInfo( path + outputName );
19+ CFileInfo outFile = new CFileInfo( path + outputName );
20
21 // test for outFile existence
22 Assert.IsTrue( outFile.Exists, exe + " was unable to create output file." );
23Index: source/graphics/ColladaManager.cpp
24===================================================================
25--- source/graphics/ColladaManager.cpp (revision 13812)
26+++ source/graphics/ColladaManager.cpp (working copy)
27@@ -279,7 +279,7 @@
28 m_skeletonHashes.clear();
29 m_skeletonHashes.resize(paths.size()*2);
30
31- FileInfo fileInfo;
32+ CFileInfo fileInfo;
33 for (VfsPaths::const_iterator it = paths.begin(); it != paths.end(); ++it)
34 {
35 // This will cause an assertion failure if *it doesn't exist,
36Index: source/lib/file/archive/archive.h
37===================================================================
38--- source/lib/file/archive/archive.h (revision 13812)
39+++ source/lib/file/archive/archive.h (working copy)
40@@ -55,7 +55,7 @@
41 * called for each archive entry.
42 * @param pathname full pathname of entry; only valid during the callback.
43 **/
44- typedef void (*ArchiveEntryCallback)(const VfsPath& pathname, const FileInfo& fileInfo, PIArchiveFile archiveFile, uintptr_t cbData);
45+ typedef void (*ArchiveEntryCallback)(const VfsPath& pathname, const CFileInfo& fileInfo, PIArchiveFile archiveFile, uintptr_t cbData);
46 virtual Status ReadEntries(ArchiveEntryCallback cb, uintptr_t cbData) = 0;
47 };
48
49Index: source/lib/file/archive/archive_builder.cpp
50===================================================================
51--- source/lib/file/archive/archive_builder.cpp (revision 13812)
52+++ source/lib/file/archive/archive_builder.cpp (working copy)
53@@ -141,7 +141,7 @@
54 // optimizations like reading from vfs_tree container directly.
55 class FileGatherer
56 {
57- static void EntCb(const char* path, const FileInfo* ent, uintptr_t cbData)
58+ static void EntCb(const char* path, const CFileInfo* ent, uintptr_t cbData)
59 {
60 FileNodes* file_nodes = (FileNodes*)cbData;
61
62@@ -544,7 +544,7 @@
63 archive_ext = path_extension(archive_fn);
64 }
65
66- bool operator()(FileInfo& ent) const
67+ bool operator()(CFileInfo& ent) const
68 {
69 // remove if not file
70 if(ent.IsDirectory)
71Index: source/lib/file/archive/archive_zip.cpp
72===================================================================
73--- source/lib/file/archive/archive_zip.cpp (revision 13812)
74+++ source/lib/file/archive/archive_zip.cpp (working copy)
75@@ -109,7 +109,7 @@
76 class LFH
77 {
78 public:
79- void Init(const FileInfo& fileInfo, off_t csize, ZipMethod method, u32 checksum, const Path& pathname)
80+ void Init(const CFileInfo& fileInfo, off_t csize, ZipMethod method, u32 checksum, const Path& pathname)
81 {
82 const std::string pathnameUTF8 = utf8_from_wstring(pathname.string());
83 const size_t pathnameSize = pathnameUTF8.length();
84@@ -157,7 +157,7 @@
85 class CDFH
86 {
87 public:
88- void Init(const FileInfo& fileInfo, off_t ofs, off_t csize, ZipMethod method, u32 checksum, const Path& pathname, size_t slack)
89+ void Init(const CFileInfo& fileInfo, off_t ofs, off_t csize, ZipMethod method, u32 checksum, const Path& pathname, size_t slack)
90 {
91 const std::string pathnameUTF8 = utf8_from_wstring(pathname.string());
92 const size_t pathnameLength = pathnameUTF8.length();
93@@ -415,7 +415,7 @@
94
95 PFile m_file;
96
97- // all relevant LFH/CDFH fields not covered by FileInfo
98+ // all relevant LFH/CDFH fields not covered by CFileInfo
99 mutable off_t m_ofs;
100 off_t m_csize;
101 u32 m_checksum;
102@@ -434,7 +434,7 @@
103 ArchiveReader_Zip(const OsPath& pathname)
104 : m_file(new File(pathname, O_RDONLY))
105 {
106- FileInfo fileInfo;
107+ CFileInfo fileInfo;
108 GetFileInfo(pathname, &fileInfo);
109 m_fileSize = fileInfo.Size();
110 const size_t minFileSize = sizeof(LFH)+sizeof(CDFH)+sizeof(ECDR);
111@@ -466,7 +466,7 @@
112 if(!relativePathname.IsDirectory())
113 {
114 const OsPath name = relativePathname.Filename();
115- FileInfo fileInfo(name, cdfh->USize(), cdfh->MTime());
116+ CFileInfo fileInfo(name, cdfh->USize(), cdfh->MTime());
117 shared_ptr<ArchiveFile_Zip> archiveFile(new ArchiveFile_Zip(m_file, cdfh->HeaderOffset(), cdfh->CSize(), cdfh->Checksum(), cdfh->Method()));
118 cb(relativePathname, fileInfo, archiveFile, cbData);
119 }
120@@ -612,7 +612,7 @@
121
122 Status AddFile(const OsPath& pathname, const OsPath& pathnameInArchive)
123 {
124- FileInfo fileInfo;
125+ CFileInfo fileInfo;
126 RETURN_STATUS_IF_ERR(GetFileInfo(pathname, &fileInfo));
127
128 PFile file(new File);
129@@ -623,12 +623,12 @@
130
131 Status AddMemory(const u8* data, size_t size, time_t mtime, const OsPath& pathnameInArchive)
132 {
133- FileInfo fileInfo(pathnameInArchive, size, mtime);
134+ CFileInfo fileInfo(pathnameInArchive, size, mtime);
135
136 return AddFileOrMemory(fileInfo, pathnameInArchive, PFile(), data);
137 }
138
139- Status AddFileOrMemory(const FileInfo& fileInfo, const OsPath& pathnameInArchive, const PFile& file, const u8* data)
140+ Status AddFileOrMemory(const CFileInfo& fileInfo, const OsPath& pathnameInArchive, const PFile& file, const u8* data)
141 {
142 ENSURE((file && !data) || (data && !file));
143
144Index: source/lib/file/file_system.cpp
145===================================================================
146--- source/lib/file/file_system.cpp (revision 13812)
147+++ source/lib/file/file_system.cpp (working copy)
148@@ -62,7 +62,7 @@
149 }
150
151
152-Status GetFileInfo(const OsPath& pathname, FileInfo* pfileInfo)
153+Status GetFileInfo(const OsPath& pathname, CFileInfo* pPtrInfo)
154 {
155 errno = 0;
156 struct stat s;
157@@ -70,7 +70,7 @@
158 if(wstat(pathname, &s) != 0)
159 WARN_RETURN(StatusFromErrno());
160
161- *pfileInfo = FileInfo(pathname.Filename(), s.st_size, s.st_mtime);
162+ *pPtrInfo = CFileInfo(pathname.Filename(), s.st_size, s.st_mtime);
163 return INFO::OK;
164 }
165
166@@ -84,7 +84,7 @@
167 }
168 };
169
170-Status GetDirectoryEntries(const OsPath& path, FileInfos* files, DirectoryNames* subdirectoryNames)
171+Status GetDirectoryEntries(const OsPath& path, CFileInfos* files, DirectoryNames* subdirectoryNames)
172 {
173 // open directory
174 errno = 0;
175@@ -123,7 +123,7 @@
176 #endif
177
178 if(files && S_ISREG(s.st_mode))
179- files->push_back(FileInfo(name, s.st_size, s.st_mtime));
180+ files->push_back(CFileInfo(name, s.st_size, s.st_mtime));
181 else if(subdirectoryNames && S_ISDIR(s.st_mode) && name != L"." && name != L"..")
182 subdirectoryNames->push_back(name);
183 }
184@@ -166,7 +166,7 @@
185 // note: we have to recursively empty the directory before it can
186 // be deleted (required by Windows and POSIX rmdir()).
187
188- FileInfos files; DirectoryNames subdirectoryNames;
189+ CFileInfos files; DirectoryNames subdirectoryNames;
190 RETURN_STATUS_IF_ERR(GetDirectoryEntries(path, &files, &subdirectoryNames));
191
192 // delete files
193Index: source/lib/file/file_system.h
194===================================================================
195--- source/lib/file/file_system.h (revision 13812)
196+++ source/lib/file/file_system.h (working copy)
197@@ -38,14 +38,14 @@
198
199
200 // (bundling size and mtime avoids a second expensive call to stat())
201-class FileInfo
202+class CFileInfo
203 {
204 public:
205- FileInfo()
206+ CFileInfo()
207 {
208 }
209
210- FileInfo(const OsPath& name, off_t size, time_t mtime)
211+ CFileInfo(const OsPath& name, off_t size, time_t mtime)
212 : name(name), size(size), mtime(mtime)
213 {
214 }
215@@ -71,12 +71,12 @@
216 time_t mtime;
217 };
218
219-LIB_API Status GetFileInfo(const OsPath& pathname, FileInfo* fileInfo);
220+LIB_API Status GetFileInfo(const OsPath& pathname, CFileInfo* fileInfo);
221
222-typedef std::vector<FileInfo> FileInfos;
223+typedef std::vector<CFileInfo> CFileInfos;
224 typedef std::vector<OsPath> DirectoryNames;
225
226-LIB_API Status GetDirectoryEntries(const OsPath& path, FileInfos* files, DirectoryNames* subdirectoryNames);
227+LIB_API Status GetDirectoryEntries(const OsPath& path, CFileInfos* files, DirectoryNames* subdirectoryNames);
228
229 // same as boost::filesystem::create_directories, except that mkdir is invoked with
230 // <mode> instead of 0755.
231Index: source/lib/file/vfs/vfs.cpp
232===================================================================
233--- source/lib/file/vfs/vfs.cpp (revision 13812)
234+++ source/lib/file/vfs/vfs.cpp (working copy)
235@@ -77,7 +77,7 @@
236 return INFO::OK;
237 }
238
239- virtual Status GetFileInfo(const VfsPath& pathname, FileInfo* pfileInfo) const
240+ virtual Status GetFileInfo(const VfsPath& pathname, CFileInfo* pfileInfo) const
241 {
242 ScopedLock s;
243 VfsDirectory* directory; VfsFile* file;
244@@ -85,7 +85,7 @@
245 if(!pfileInfo) // just indicate if the file exists without raising warnings.
246 return ret;
247 WARN_RETURN_STATUS_IF_ERR(ret);
248- *pfileInfo = FileInfo(file->Name(), file->Size(), file->MTime());
249+ *pfileInfo = CFileInfo(file->Name(), file->Size(), file->MTime());
250 return INFO::OK;
251 }
252
253@@ -98,7 +98,7 @@
254 return INFO::OK;
255 }
256
257- virtual Status GetDirectoryEntries(const VfsPath& path, FileInfos* fileInfos, DirectoryNames* subdirectoryNames) const
258+ virtual Status GetDirectoryEntries(const VfsPath& path, CFileInfos* fileInfos, DirectoryNames* subdirectoryNames) const
259 {
260 ScopedLock s;
261 VfsDirectory* directory;
262@@ -112,7 +112,7 @@
263 for(VfsDirectory::VfsFiles::const_iterator it = files.begin(); it != files.end(); ++it)
264 {
265 const VfsFile& file = it->second;
266- fileInfos->push_back(FileInfo(file.Name(), file.Size(), file.MTime()));
267+ fileInfos->push_back(CFileInfo(file.Name(), file.Size(), file.MTime()));
268 }
269 }
270
271Index: source/lib/file/vfs/vfs.h
272===================================================================
273--- source/lib/file/vfs/vfs.h (revision 13812)
274+++ source/lib/file/vfs/vfs.h (working copy)
275@@ -28,7 +28,7 @@
276 #ifndef INCLUDED_VFS
277 #define INCLUDED_VFS
278
279-#include "lib/file/file_system.h" // FileInfo
280+#include "lib/file/file_system.h" // CFileInfo
281 #include "lib/file/vfs/vfs_path.h"
282
283 namespace ERR
284@@ -109,7 +109,7 @@
285 *
286 * @return Status.
287 **/
288- virtual Status GetFileInfo(const VfsPath& pathname, FileInfo* pfileInfo) const = 0;
289+ virtual Status GetFileInfo(const VfsPath& pathname, CFileInfo* pfileInfo) const = 0;
290
291 /**
292 * Retrieve mount priority for a file.
293@@ -132,7 +132,7 @@
294 * - we cannot efficiently provide routines for returning files and
295 * subdirectories separately due to the underlying POSIX interface.
296 **/
297- virtual Status GetDirectoryEntries(const VfsPath& path, FileInfos* fileInfos, DirectoryNames* subdirectoryNames) const = 0;
298+ virtual Status GetDirectoryEntries(const VfsPath& path, CFileInfos* fileInfos, DirectoryNames* subdirectoryNames) const = 0;
299
300 /**
301 * Create a file with the given contents.
302Index: source/lib/file/vfs/vfs_populate.cpp
303===================================================================
304--- source/lib/file/vfs/vfs_populate.cpp (revision 13812)
305+++ source/lib/file/vfs/vfs_populate.cpp (working copy)
306@@ -41,7 +41,7 @@
307
308 struct CompareFileInfoByName
309 {
310- bool operator()(const FileInfo& a, const FileInfo& b)
311+ bool operator()(const CFileInfo& a, const CFileInfo& b)
312 {
313 return a.Name() < b.Name();
314 }
315@@ -64,7 +64,7 @@
316 s_looseFiles.reserve(10000);
317 #endif
318
319- FileInfos files; files.reserve(500);
320+ CFileInfos files; files.reserve(500);
321 DirectoryNames subdirectoryNames; subdirectoryNames.reserve(50);
322 RETURN_STATUS_IF_ERR(GetDirectoryEntries(m_realDirectory->Path(), &files, &subdirectoryNames));
323
324@@ -82,7 +82,7 @@
325 }
326
327 private:
328- void AddFile(const FileInfo& fileInfo) const
329+ void AddFile(const CFileInfo& fileInfo) const
330 {
331 const VfsPath name = fileInfo.Name();
332 if(name.Extension() == L".DELETED")
333@@ -108,7 +108,7 @@
334 #endif
335 }
336
337- static void AddArchiveFile(const VfsPath& pathname, const FileInfo& fileInfo, PIArchiveFile archiveFile, uintptr_t cbData)
338+ static void AddArchiveFile(const VfsPath& pathname, const CFileInfo& fileInfo, PIArchiveFile archiveFile, uintptr_t cbData)
339 {
340 PopulateHelper* this_ = (PopulateHelper*)cbData;
341
342@@ -133,7 +133,7 @@
343 #endif
344 }
345
346- Status AddFiles(const FileInfos& files) const
347+ Status AddFiles(const CFileInfos& files) const
348 {
349 const OsPath path(m_realDirectory->Path());
350
351Index: source/lib/file/vfs/vfs_tree.h
352===================================================================
353--- source/lib/file/vfs/vfs_tree.h (revision 13812)
354+++ source/lib/file/vfs/vfs_tree.h (working copy)
355@@ -29,7 +29,7 @@
356
357 #include <map>
358
359-#include "lib/file/file_system.h" // FileInfo
360+#include "lib/file/file_system.h" // CFileInfo
361 #include "lib/file/common/file_loader.h" // PIFileLoader
362 #include "lib/file/common/real_directory.h" // PRealDirectory
363 #include "lib/file/vfs/vfs_path.h"
364Index: source/lib/file/vfs/vfs_util.cpp
365===================================================================
366--- source/lib/file/vfs/vfs_util.cpp (revision 13812)
367+++ source/lib/file/vfs/vfs_util.cpp (working copy)
368@@ -39,7 +39,7 @@
369
370 Status GetPathnames(const PIVFS& fs, const VfsPath& path, const wchar_t* filter, VfsPaths& pathnames)
371 {
372- std::vector<FileInfo> files;
373+ std::vector<CFileInfo> files;
374 RETURN_STATUS_IF_ERR(fs->GetDirectoryEntries(path, &files, 0));
375
376 pathnames.clear();
377@@ -58,7 +58,7 @@
378 Status ForEachFile(const PIVFS& fs, const VfsPath& startPath, FileCallback cb, uintptr_t cbData, const wchar_t* pattern, size_t flags)
379 {
380 // (declare here to avoid reallocations)
381- FileInfos files; DirectoryNames subdirectoryNames;
382+ CFileInfos files; DirectoryNames subdirectoryNames;
383
384 // (a FIFO queue is more efficient than recursion because it uses less
385 // stack space and avoids seeks due to breadth-first traversal.)
386@@ -72,11 +72,11 @@
387
388 for(size_t i = 0; i < files.size(); i++)
389 {
390- const FileInfo fileInfo = files[i];
391+ const CFileInfo fileInfo = files[i];
392 if(!match_wildcard(fileInfo.Name().string().c_str(), pattern))
393 continue;
394
395- const VfsPath pathname(path / fileInfo.Name()); // (FileInfo only stores the name)
396+ const VfsPath pathname(path / fileInfo.Name()); // (CFileInfo only stores the name)
397 cb(pathname, fileInfo, cbData);
398 }
399
400@@ -105,7 +105,7 @@
401 const VfsPath path = pathnameFormat.Parent()/"";
402
403 size_t maxNumber = 0;
404- FileInfos files;
405+ CFileInfos files;
406 fs->GetDirectoryEntries(path, &files, 0);
407 for(size_t i = 0; i < files.size(); i++)
408 {
409Index: source/lib/file/vfs/vfs_util.h
410===================================================================
411--- source/lib/file/vfs/vfs_util.h (revision 13812)
412+++ source/lib/file/vfs/vfs_util.h (working copy)
413@@ -37,7 +37,7 @@
414 /**
415 * called for files in a directory.
416 *
417- * @param pathname full pathname (since FileInfo only gives the name).
418+ * @param pathname full pathname (since CFileInfo only gives the name).
419 * @param fileInfo file information
420 * @param cbData user-specified context
421 * @return INFO::CONTINUE on success; any other value will immediately
422@@ -46,7 +46,7 @@
423 * CAVEAT: pathname and fileInfo are only valid until the function
424 * returns!
425 **/
426-typedef Status (*FileCallback)(const VfsPath& pathname, const FileInfo& fileInfo, const uintptr_t cbData);
427+typedef Status (*FileCallback)(const VfsPath& pathname, const CFileInfo& fileInfo, const uintptr_t cbData);
428
429 enum DirFlags
430 {
431Index: source/lib/sysdep/os/osx/dir_watch.cpp
432===================================================================
433--- source/lib/sysdep/os/osx/dir_watch.cpp (revision 13812)
434+++ source/lib/sysdep/os/osx/dir_watch.cpp (working copy)
435@@ -21,16 +21,182 @@
436 */
437
438 #include "precompiled.h"
439+
440 #include "lib/sysdep/dir_watch.h"
441+#include "lib/file/file_system.h"
442+#include "osx_sys_version.h"
443
444-// stub implementations
445+#include "lib/os_path.h"
446+#include "lib/file/file.h"
447+#include "lib/posix/posix_filesystem.h" // mode_t
448
449-Status dir_watch_Add(const OsPath& UNUSED(path), PDirWatch& UNUSED(dirWatch))
450+#include <CoreFoundation/CoreFoundation.h>
451+#include <CoreServices/CoreServices.h>
452+
453+
454+#include "ps/CLogger.h"
455+
456+FSEventStreamRef g_Stream = NULL;
457+
458+struct DirWatch
459 {
460+ OsPath path;
461+ int reqnum;
462+};
463+
464+typedef std::vector<DirWatch> DirWatchMap;
465+static DirWatchMap g_Paths;
466+static DirWatchMap g_RootPaths;
467+static DirWatchNotifications g_QueuedDirs;
468+
469+bool CanRunNotifications()
470+{
471+ int major = 0;
472+ int minor = 0;
473+ int bugfix = 0;
474+
475+ GetSystemVersion( major, minor, bugfix);
476+
477+ if ((major == 10 && minor >= 7) || major >= 11)
478+ return true;
479+
480+ return false;
481+}
482+
483+#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1070
484+#else
485+ #define kFSEventStreamCreateFlagFileEvents 0x00000010
486+ #define kFSEventStreamEventFlagItemIsFile 0x00010000
487+ #define kFSEventStreamEventFlagItemRemoved 0x00000200
488+ #define kFSEventStreamEventFlagItemRenamed 0x00000800
489+ #define kFSEventStreamEventFlagItemCreated 0x00000100
490+ #define kFSEventStreamEventFlagItemModified 0x00001000
491+#endif
492+
493+static void fsevent_callback(
494+ ConstFSEventStreamRef UNUSED(streamRef),
495+ void * UNUSED(clientCallBackInfo),
496+ size_t numEvents,
497+ void *eventPaths,
498+ const FSEventStreamEventFlags eventFlags[],
499+ const FSEventStreamEventId UNUSED(eventIds)[] )
500+{
501+ unsigned long i;
502+ char **paths = (char **)eventPaths;
503+
504+ for (i=0; i<numEvents; i++)
505+ {
506+ bool isWatched = false;
507+ OsPath eventPath = OsPath(paths[i]);
508+ unsigned long eventType = eventFlags[i];
509+
510+ if ( eventPath.Filename().string().c_str()[0] != '.' )
511+ {
512+ for ( DirWatchMap::iterator it = g_Paths.begin() ; it != g_Paths.end(); ++it)
513+ if ( path_is_subpath( it->path.string().c_str(), eventPath.string().c_str() ) )
514+ isWatched = true;
515+ }
516+
517+ if ( ! isWatched )
518+ return;
519+
520+ OsPath filename = Path( eventPath.string().c_str() );
521+
522+ if ( eventType & kFSEventStreamEventFlagItemIsFile)
523+ {
524+ if ( eventType & kFSEventStreamEventFlagItemRemoved )
525+ g_QueuedDirs.push_back(DirWatchNotification( filename.string().c_str(), DirWatchNotification::Deleted ));
526+ else if ( eventType & kFSEventStreamEventFlagItemRenamed )
527+ g_QueuedDirs.push_back(DirWatchNotification( filename.string().c_str(), DirWatchNotification::Deleted ));
528+ else if ( eventType & kFSEventStreamEventFlagItemCreated )
529+ g_QueuedDirs.push_back(DirWatchNotification( filename.string().c_str(), DirWatchNotification::Created ));
530+ else if ( eventType & kFSEventStreamEventFlagItemModified )
531+ g_QueuedDirs.push_back(DirWatchNotification( filename.string().c_str(), DirWatchNotification::Changed ));
532+ }
533+ }
534+
535+}
536+
537+FSEventStreamRef CreateEventStream( DirWatchMap path )
538+{
539+ if ( ( g_Stream == NULL ) && CanRunNotifications() )
540+ {
541+ CFStringRef* pathLists = (CFStringRef*)malloc( sizeof(CFStringRef*) * path.size() );
542+ int index = 0;
543+ for ( DirWatchMap::iterator it = path.begin() ; it != path.end(); ++it)
544+ {
545+ pathLists[index] = CFStringCreateWithFileSystemRepresentation( NULL, OsString(it->path).c_str());
546+ index++;
547+ }
548+ CFArrayRef pathsToWatch = CFArrayCreate(NULL, (const void **)pathLists, index, NULL);
549+
550+ FSEventStreamContext *callbackInfo = NULL;
551+
552+ FSEventStreamRef stream = FSEventStreamCreate(NULL, &fsevent_callback, callbackInfo, pathsToWatch,
553+ kFSEventStreamEventIdSinceNow, 1.0, kFSEventStreamCreateFlagFileEvents );
554+
555+ CFRelease( pathsToWatch );
556+ free( pathLists );
557+
558+ FSEventStreamScheduleWithRunLoop(stream, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
559+ if (!FSEventStreamStart(stream))
560+ debug_warn(L"event_loop FSEventStreamStart failed!");
561+ else
562+ return stream;
563+ }
564+ return NULL;
565+}
566+
567+void DeleteEventStream()
568+{
569+ if ( g_Stream != NULL )
570+ {
571+ FSEventStreamStop(g_Stream);
572+ FSEventStreamInvalidate(g_Stream);
573+ FSEventStreamRelease(g_Stream);
574+
575+ g_Stream = NULL;
576+ }
577+}
578+
579+
580+Status dir_watch_Add(const OsPath& path, PDirWatch& dirWatch)
581+{
582+ PDirWatch tmpDirWatch(new DirWatch);
583+ dirWatch.swap(tmpDirWatch);
584+ dirWatch->path = path;
585+ dirWatch->reqnum = 0;
586+ g_Paths.push_back( *dirWatch );
587+
588+ bool alreadyInsideRootPath = false;
589+ for ( DirWatchMap::iterator it = g_RootPaths.begin() ; it != g_RootPaths.end(); ++it)
590+ {
591+ if ( path_is_subpath( path.string().c_str(), it->path.string().c_str() ) )
592+ alreadyInsideRootPath = true;
593+ }
594+
595+ if ( !alreadyInsideRootPath )
596+ {
597+ DeleteEventStream();
598+ g_RootPaths.push_back( *dirWatch );
599+ }
600+
601 return INFO::OK;
602 }
603
604-Status dir_watch_Poll(DirWatchNotifications& UNUSED(notifications))
605+Status dir_watch_Poll(DirWatchNotifications& notifications)
606 {
607+ if ( g_Stream == NULL )
608+ {
609+ g_Stream = CreateEventStream( g_RootPaths );
610+ }
611+ else
612+ {
613+ for ( DirWatchNotifications::iterator it = g_QueuedDirs.begin() ; it != g_QueuedDirs.end(); ++it)
614+ notifications.push_back(DirWatchNotification( *it ));
615+
616+ g_QueuedDirs.clear();
617+ }
618+
619 return INFO::OK;
620 }
621Index: source/lib/sysdep/os/osx/osx_sys_version.h
622===================================================================
623--- source/lib/sysdep/os/osx/osx_sys_version.h (revision 0)
624+++ source/lib/sysdep/os/osx/osx_sys_version.h (working copy)
625@@ -0,0 +1,25 @@
626+#ifndef OSX_SYS_VERSION_H
627+#define OSX_SYS_VERSION_H
628+
629+
630+
631+
632+
633+
634+
635+
636+void GetSystemVersion( int &major, int &minor, int &bugfix );
637+
638+
639+
640+
641+
642+
643+
644+
645+
646+
647+
648+
649+
650+#endif //OSX_SYS_VERSION_H
651\ No newline at end of file
652Index: source/lib/sysdep/os/osx/osx_sys_version.mm
653===================================================================
654--- source/lib/sysdep/os/osx/osx_sys_version.mm (revision 0)
655+++ source/lib/sysdep/os/osx/osx_sys_version.mm (working copy)
656@@ -0,0 +1,44 @@
657+#import <AvailabilityMacros.h> // MAC_OS_X_VERSION_MIN_REQUIRED
658+#import <Foundation/Foundation.h>
659+#import <string>
660+
661+#import "osx_bundle.h"
662+
663+#define STRINGIZE2(id) # id
664+#define STRINGIZE(id) STRINGIZE2(id)
665+
666+// Pass the bundle identifier string as a build option
667+#ifdef BUNDLE_IDENTIFIER
668+static const char* BUNDLE_ID_STR = STRINGIZE(BUNDLE_IDENTIFIER);
669+#else
670+static const char* BUNDLE_ID_STR = "";
671+#endif
672+
673+
674+void GetSystemVersion( int &major, int &minor, int &bugfix )
675+{
676+ // sensible default
677+ static int mMajor = 10;
678+ static int mMinor = 8;
679+ static int mBugfix = 0;
680+
681+ static dispatch_once_t onceToken;
682+ dispatch_once(&onceToken, ^{
683+ NSString* versionString = [[NSDictionary dictionaryWithContentsOfFile:@"/System/Library/CoreServices/SystemVersion.plist"] objectForKey:@"ProductVersion"];
684+ NSArray* versions = [versionString componentsSeparatedByString:@"."];
685+ check( versions.count >= 2 );
686+ if ( versions.count >= 1 ) {
687+ mMajor = [[versions objectAtIndex:0] integerValue];
688+ }
689+ if ( versions.count >= 2 ) {
690+ mMinor = [[versions objectAtIndex:1] integerValue];
691+ }
692+ if ( versions.count >= 3 ) {
693+ mBugfix = [[versions objectAtIndex:2] integerValue];
694+ }
695+ });
696+
697+ major = mMajor;
698+ minor = mMinor;
699+ bugfix = mBugfix;
700+}
701Index: source/ps/ArchiveBuilder.cpp
702===================================================================
703--- source/ps/ArchiveBuilder.cpp (revision 13812)
704+++ source/ps/ArchiveBuilder.cpp (working copy)
705@@ -173,7 +173,7 @@
706 }
707 }
708
709-Status CArchiveBuilder::CollectFileCB(const VfsPath& pathname, const FileInfo& UNUSED(fileInfo), const uintptr_t cbData)
710+Status CArchiveBuilder::CollectFileCB(const VfsPath& pathname, const CFileInfo& UNUSED(fileInfo), const uintptr_t cbData)
711 {
712 CArchiveBuilder* self = static_cast<CArchiveBuilder*>((void*)cbData);
713 self->m_Files.push_back(pathname);
714Index: source/ps/ArchiveBuilder.h
715===================================================================
716--- source/ps/ArchiveBuilder.h (revision 13812)
717+++ source/ps/ArchiveBuilder.h (working copy)
718@@ -57,7 +57,7 @@
719 void Build(const OsPath& archive, bool compress);
720
721 private:
722- static Status CollectFileCB(const VfsPath& pathname, const FileInfo& fileInfo, const uintptr_t cbData);
723+ static Status CollectFileCB(const VfsPath& pathname, const CFileInfo& fileInfo, const uintptr_t cbData);
724
725 PIVFS m_VFS;
726 std::vector<VfsPath> m_Files;
727Index: source/ps/CacheLoader.cpp
728===================================================================
729--- source/ps/CacheLoader.cpp (revision 13812)
730+++ source/ps/CacheLoader.cpp (working copy)
731@@ -95,7 +95,7 @@
732
733 // If source file is more recent than the archive cache (i.e. the user has edited it),
734 // don't use the old cache
735- FileInfo sourceInfo, archiveCacheInfo;
736+ CFileInfo sourceInfo, archiveCacheInfo;
737 if (m_VFS->GetFileInfo(sourcePath, &sourceInfo) >= 0 &&
738 m_VFS->GetFileInfo(archiveCachePath, &archiveCacheInfo) >= 0)
739 {
740@@ -116,7 +116,7 @@
741
742 VfsPath CCacheLoader::LooseCachePath(const VfsPath& sourcePath, const MD5& initialHash, u32 version)
743 {
744- FileInfo fileInfo;
745+ CFileInfo fileInfo;
746 if (m_VFS->GetFileInfo(sourcePath, &fileInfo) < 0)
747 {
748 debug_warn(L"source file disappeared"); // this should never happen
749Index: source/ps/SavedGame.cpp
750===================================================================
751--- source/ps/SavedGame.cpp (revision 13812)
752+++ source/ps/SavedGame.cpp (working copy)
753@@ -98,7 +98,7 @@
754 archiveWriter.reset(); // close the file
755
756 WriteBuffer buffer;
757- FileInfo tempSaveFile;
758+ CFileInfo tempSaveFile;
759 WARN_RETURN_STATUS_IF_ERR(GetFileInfo(tempSaveFileRealPath, &tempSaveFile));
760 buffer.Reserve(tempSaveFile.Size());
761 WARN_RETURN_STATUS_IF_ERR(io::Load(tempSaveFileRealPath, buffer.Data().get(), buffer.Size()));
762@@ -123,12 +123,12 @@
763 {
764 }
765
766- static void ReadEntryCallback(const VfsPath& pathname, const FileInfo& fileInfo, PIArchiveFile archiveFile, uintptr_t cbData)
767+ static void ReadEntryCallback(const VfsPath& pathname, const CFileInfo& fileInfo, PIArchiveFile archiveFile, uintptr_t cbData)
768 {
769 ((CGameLoader*)cbData)->ReadEntry(pathname, fileInfo, archiveFile);
770 }
771
772- void ReadEntry(const VfsPath& pathname, const FileInfo& fileInfo, PIArchiveFile archiveFile)
773+ void ReadEntry(const VfsPath& pathname, const CFileInfo& fileInfo, PIArchiveFile archiveFile)
774 {
775 if (pathname == L"metadata.json" && m_Metadata)
776 {
777Index: source/ps/scripting/JSInterface_VFS.cpp
778===================================================================
779--- source/ps/scripting/JSInterface_VFS.cpp (revision 13812)
780+++ source/ps/scripting/JSInterface_VFS.cpp (working copy)
781@@ -66,7 +66,7 @@
782 };
783
784 // called for each matching directory entry; add its full pathname to array.
785-static Status BuildDirEntListCB(const VfsPath& pathname, const FileInfo& UNUSED(fileINfo), uintptr_t cbData)
786+static Status BuildDirEntListCB(const VfsPath& pathname, const CFileInfo& UNUSED(fileINfo), uintptr_t cbData)
787 {
788 BuildDirEntListState* s = (BuildDirEntListState*)cbData;
789
790@@ -140,7 +140,7 @@
791 if (!ToPrimitive<CStrW> (cx, JS_ARGV(cx, vp)[0], filename))
792 return JS_FALSE;
793
794- FileInfo fileInfo;
795+ CFileInfo fileInfo;
796 Status err = g_VFS->GetFileInfo(filename, &fileInfo);
797 JS_CHECK_FILE_ERR(err);
798
799@@ -161,7 +161,7 @@
800 if (!ToPrimitive<CStrW> (cx, JS_ARGV(cx, vp)[0], filename))
801 return JS_FALSE;
802
803- FileInfo fileInfo;
804+ CFileInfo fileInfo;
805 Status err = g_VFS->GetFileInfo(filename, &fileInfo);
806 JS_CHECK_FILE_ERR(err);
807
808Index: source/scriptinterface/DebuggingServer.cpp
809===================================================================
810--- source/scriptinterface/DebuggingServer.cpp (revision 13812)
811+++ source/scriptinterface/DebuggingServer.cpp (working copy)
812@@ -176,7 +176,7 @@
813 }
814
815
816-static Status AddFileResponse(const VfsPath& pathname, const FileInfo& UNUSED(fileInfo), const uintptr_t cbData)
817+static Status AddFileResponse(const VfsPath& pathname, const CFileInfo& UNUSED(fileInfo), const uintptr_t cbData)
818 {
819 std::vector<std::string>& templates = *(std::vector<std::string>*)cbData;
820 std::wstring str(pathname.string());
821Index: source/simulation2/components/CCmpTemplateManager.cpp
822===================================================================
823--- source/simulation2/components/CCmpTemplateManager.cpp (revision 13812)
824+++ source/simulation2/components/CCmpTemplateManager.cpp (working copy)
825@@ -429,7 +429,7 @@
826 CParamNode::LoadXMLString(out, xml.c_str(), actorNameW.c_str());
827 }
828
829-static Status AddToTemplates(const VfsPath& pathname, const FileInfo& UNUSED(fileInfo), const uintptr_t cbData)
830+static Status AddToTemplates(const VfsPath& pathname, const CFileInfo& UNUSED(fileInfo), const uintptr_t cbData)
831 {
832 std::vector<std::string>& templates = *(std::vector<std::string>*)cbData;
833
834@@ -446,7 +446,7 @@
835 return INFO::OK;
836 }
837
838-static Status AddActorToTemplates(const VfsPath& pathname, const FileInfo& UNUSED(fileInfo), const uintptr_t cbData)
839+static Status AddActorToTemplates(const VfsPath& pathname, const CFileInfo& UNUSED(fileInfo), const uintptr_t cbData)
840 {
841 std::vector<std::string>& templates = *(std::vector<std::string>*)cbData;
842
843Index: source/simulation2/components/ICmpAIManager.cpp
844===================================================================
845--- source/simulation2/components/ICmpAIManager.cpp (revision 13812)
846+++ source/simulation2/components/ICmpAIManager.cpp (working copy)
847@@ -47,7 +47,7 @@
848 vfs::ForEachFile(g_VFS, L"simulation/ai/", Callback, (uintptr_t)this, L"*.json", vfs::DIR_RECURSIVE);
849 }
850
851- static Status Callback(const VfsPath& pathname, const FileInfo& UNUSED(fileInfo), const uintptr_t cbData)
852+ static Status Callback(const VfsPath& pathname, const CFileInfo& UNUSED(fileInfo), const uintptr_t cbData)
853 {
854 GetAIsHelper* self = (GetAIsHelper*)cbData;
855
856Index: source/simulation2/system/ComponentManager.cpp
857===================================================================
858--- source/simulation2/system/ComponentManager.cpp (revision 13812)
859+++ source/simulation2/system/ComponentManager.cpp (working copy)
860@@ -961,7 +961,7 @@
861 return componentManager->GetScriptInterface().ReadJSONFile(path).get();
862 }
863
864-Status CComponentManager::FindJSONFilesCallback(const VfsPath& pathname, const FileInfo& UNUSED(fileInfo), const uintptr_t cbData)
865+Status CComponentManager::FindJSONFilesCallback(const VfsPath& pathname, const CFileInfo& UNUSED(fileInfo), const uintptr_t cbData)
866 {
867 FindJSONFilesCallbackData* data = (FindJSONFilesCallbackData*)cbData;
868
869Index: source/simulation2/system/ComponentManager.h
870===================================================================
871--- source/simulation2/system/ComponentManager.h (revision 13812)
872+++ source/simulation2/system/ComponentManager.h (working copy)
873@@ -245,7 +245,7 @@
874 static CScriptVal ReadJSONFile(void *cbdata, std::wstring filePath, std::wstring fileName);
875
876 // callback function to handle recursively finding files in a directory
877- static Status FindJSONFilesCallback(const VfsPath&, const FileInfo&, const uintptr_t);
878+ static Status FindJSONFilesCallback(const VfsPath&, const CFileInfo&, const uintptr_t);
879
880 CMessage* ConstructMessage(int mtid, CScriptVal data);
881 void SendGlobalMessage(entity_id_t ent, const CMessage& msg) const;
882Index: source/soundmanager/SoundManager.cpp
883===================================================================
884--- source/soundmanager/SoundManager.cpp (revision 13812)
885+++ source/soundmanager/SoundManager.cpp (working copy)
886@@ -20,6 +20,8 @@
887 #include "ISoundManager.h"
888 #include "SoundManager.h"
889
890+#include "ps/Filesystem.h"
891+
892 #include "soundmanager/data/SoundData.h"
893 #include "soundmanager/items/CSoundItem.h"
894 #include "soundmanager/items/CBufferItem.h"
895@@ -208,7 +210,8 @@
896
897 void ISoundManager::CreateSoundManager()
898 {
899- g_SoundManager = new CSoundManager();
900+ if ( !g_SoundManager )
901+ g_SoundManager = new CSoundManager();
902 }
903
904 void ISoundManager::SetEnabled(bool doEnable)
905@@ -217,7 +220,7 @@
906 {
907 SAFE_DELETE(g_SoundManager);
908 }
909- else if ( ! g_SoundManager && doEnable )
910+ else if ( !g_SoundManager && doEnable )
911 {
912 ISoundManager::CreateSoundManager();
913 }
914@@ -240,6 +243,18 @@
915 al_ReportError(err, caller, line);
916 }
917
918+Status CSoundManager::ReloadChangedFiles(const VfsPath& UNUSED(path))
919+{
920+// LOGERROR(L"GUI file '%ls' changed - reloading page", path.string().c_str());
921+
922+ return INFO::OK;
923+}
924+
925+/*static*/ Status CSoundManager::ReloadChangedFileCB(void* param, const VfsPath& path)
926+{
927+ return static_cast<CSoundManager*>(param)->ReloadChangedFiles(path);
928+}
929+
930 CSoundManager::CSoundManager()
931 {
932 m_CurrentEnvirons = 0;
933@@ -282,10 +297,14 @@
934 m_Worker = new CSoundManagerWorker();
935 m_Worker->SetEnabled( true );
936 }
937+
938+ RegisterFileReloadFunc(ReloadChangedFileCB, this);
939 }
940
941 CSoundManager::~CSoundManager()
942 {
943+ UnregisterFileReloadFunc(ReloadChangedFileCB, this);
944+
945 if (m_Worker )
946 {
947 AL_CHECK
948@@ -649,11 +668,14 @@
949
950 void CSoundManager::SetMusicEnabled (bool isEnabled)
951 {
952+ LOGERROR(L"entering enabled area", isEnabled);
953+
954 if (m_CurrentTune && !isEnabled)
955 {
956 m_CurrentTune->FadeAndDelete(1.00);
957 m_CurrentTune = 0L;
958 }
959+ LOGERROR(L"exiting enabled area", isEnabled);
960 m_MusicEnabled = isEnabled;
961 }
962
963Index: source/soundmanager/SoundManager.h
964===================================================================
965--- source/soundmanager/SoundManager.h (revision 13812)
966+++ source/soundmanager/SoundManager.h (working copy)
967@@ -102,6 +102,8 @@
968 ISoundItem* ItemForData(CSoundData* itemData);
969 ISoundItem* ItemForEntity( entity_id_t source, CSoundData* sndData);
970
971+ Status ReloadChangedFiles(const VfsPath& path);
972+
973 void ClearPlayListItems();
974 void StartPlayList( bool doLoop );
975 void AddPlayListItem( const VfsPath* itemPath);
976@@ -109,6 +111,8 @@
977 static void ScriptingInit();
978 static void CreateSoundManager();
979 static void SetEnabled(bool doEnable);
980+ static Status ReloadChangedFileCB(void* param, const VfsPath& path);
981+
982 static void CloseGame();
983
984 static void al_ReportError(ALenum err, const char* caller, int line);