macVolume.mm 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) 2012 GarageGames, LLC
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to
  6. // deal in the Software without restriction, including without limitation the
  7. // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  8. // sell copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  20. // IN THE SOFTWARE.
  21. //-----------------------------------------------------------------------------
  22. #import <CoreServices/CoreServices.h>
  23. #import "platform/platform.h"
  24. #import "platformMac/macVolume.h"
  25. #import "platform/platformVolume.h"
  26. #import "console/console.h"
  27. struct MacFileSystemChangeNotifier::Event
  28. {
  29. FSEventStreamRef mStream;
  30. Torque::Path mDir;
  31. bool mHasChanged;
  32. };
  33. static void fsNotifyCallback(
  34. ConstFSEventStreamRef stream,
  35. void* callbackInfo,
  36. size_t numEvents,
  37. void* eventPaths,
  38. const FSEventStreamEventFlags eventFlags[],
  39. const FSEventStreamEventId eventIds[] )
  40. {
  41. MacFileSystemChangeNotifier::Event* event =
  42. reinterpret_cast< MacFileSystemChangeNotifier::Event* >( callbackInfo );
  43. // Defer handling this to internalProcessOnce() so we stay in
  44. // line with how the volume system expects notifications to
  45. // be reported.
  46. event->mHasChanged = true;
  47. }
  48. //-----------------------------------------------------------------------------
  49. // Change notifications.
  50. //-----------------------------------------------------------------------------
  51. MacFileSystemChangeNotifier::MacFileSystemChangeNotifier( MacFileSystem* fs )
  52. : Parent( fs )
  53. {
  54. VECTOR_SET_ASSOCIATION( mEvents );
  55. }
  56. MacFileSystemChangeNotifier::~MacFileSystemChangeNotifier()
  57. {
  58. for( U32 i = 0, num = mEvents.size(); i < num; ++ i )
  59. {
  60. FSEventStreamStop( mEvents[ i ]->mStream );
  61. FSEventStreamInvalidate( mEvents[ i ]->mStream );
  62. FSEventStreamRelease( mEvents[ i ]->mStream );
  63. SAFE_DELETE( mEvents[ i ] );
  64. }
  65. }
  66. void MacFileSystemChangeNotifier::internalProcessOnce()
  67. {
  68. for( U32 i = 0; i < mEvents.size(); ++ i )
  69. if( mEvents[ i ]->mHasChanged )
  70. {
  71. // Signal the change.
  72. #ifdef DEBUG_SPEW
  73. Platform::outputDebugString( "[MacFileSystemChangeNotifier] Directory %i changed: '%s'",
  74. i + 1, mEvents[ i ]->mDir.getFullPath().c_str() );
  75. #endif
  76. internalNotifyDirChanged( mEvents[ i ]->mDir );
  77. mEvents[i ]->mHasChanged = false;
  78. }
  79. }
  80. bool MacFileSystemChangeNotifier::internalAddNotification( const Torque::Path& dir )
  81. {
  82. // Map the path.
  83. Torque::Path fullFSPath = mFS->mapTo( dir );
  84. String osPath = PathToOS( fullFSPath );
  85. // Create event stream.
  86. Event* event = new Event;
  87. CFStringRef path = CFStringCreateWithCharacters( NULL, osPath.utf16(), osPath.numChars() );
  88. CFArrayRef paths = CFArrayCreate( NULL, ( const void** ) &path, 1, NULL );
  89. FSEventStreamRef stream;
  90. CFAbsoluteTime latency = 3.f;
  91. FSEventStreamContext context;
  92. dMemset( &context, 0, sizeof( context ) );
  93. context.info = event;
  94. stream = FSEventStreamCreate(
  95. NULL,
  96. &fsNotifyCallback,
  97. &context,
  98. paths,
  99. kFSEventStreamEventIdSinceNow,
  100. latency,
  101. kFSEventStreamCreateFlagNone
  102. );
  103. event->mStream = stream;
  104. event->mDir = dir;
  105. event->mHasChanged = false;
  106. mEvents.push_back( event );
  107. // Put it in the run loop and start the stream.
  108. FSEventStreamScheduleWithRunLoop( stream, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode );
  109. FSEventStreamStart( stream );
  110. CFRelease( path );
  111. CFRelease( paths );
  112. #ifdef DEBUG_SPEW
  113. Platform::outputDebugString( "[MacFileSystemChangeNotifier] Added change notification %i to '%s' (full path: %s)",
  114. mEvents.size(), dir.getFullPath().c_str(), osPath.c_str() );
  115. #endif
  116. return true;
  117. }
  118. bool MacFileSystemChangeNotifier::internalRemoveNotification( const Torque::Path& dir )
  119. {
  120. for( U32 i = 0, num = mEvents.size(); i < num; ++ i )
  121. if( mEvents[ i ]->mDir == dir )
  122. {
  123. #ifdef DEBUG_SPEW
  124. Platform::outputDebugString( "[MacFileSystemChangeNotifier] Removing change notification %i from '%s'",
  125. i + 1, dir.getFullPath().c_str() );
  126. #endif
  127. FSEventStreamStop( mEvents[ i ]->mStream );
  128. FSEventStreamInvalidate( mEvents[ i ]->mStream );
  129. FSEventStreamRelease( mEvents[ i ]->mStream );
  130. SAFE_DELETE( mEvents[ i ] );
  131. mEvents.erase( i );
  132. return true;
  133. }
  134. return false;
  135. }
  136. //-----------------------------------------------------------------------------
  137. // Platform API.
  138. //-----------------------------------------------------------------------------
  139. Torque::FS::FileSystemRef Platform::FS::createNativeFS( const String &volume )
  140. {
  141. return new MacFileSystem( volume );
  142. }