diff options
author | phajdan.jr@chromium.org <phajdan.jr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-04-30 19:39:15 +0000 |
---|---|---|
committer | phajdan.jr@chromium.org <phajdan.jr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-04-30 19:39:15 +0000 |
commit | e611fd66e64564d17865ed19658dc0b56e1ee746 (patch) | |
tree | 0d607ea22b3aed344707f3af3f8e622fe9fab6cf /base/directory_watcher_mac.cc | |
parent | 022a7edd851ccd3b0e0f5f4e83e44b986085e636 (diff) | |
download | chromium_src-e611fd66e64564d17865ed19658dc0b56e1ee746.zip chromium_src-e611fd66e64564d17865ed19658dc0b56e1ee746.tar.gz chromium_src-e611fd66e64564d17865ed19658dc0b56e1ee746.tar.bz2 |
Add DirectoryWatcher implementation for Mac.
This uses FSEvents and supports both recursive and non-recursive modes.
TEST=Make sure that tests matching DirectoryWatcherTest.* from base_unittests pass on Mac.
http://crbug.com/10967
Review URL: http://codereview.chromium.org/99057
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@14977 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'base/directory_watcher_mac.cc')
-rw-r--r-- | base/directory_watcher_mac.cc | 121 |
1 files changed, 121 insertions, 0 deletions
diff --git a/base/directory_watcher_mac.cc b/base/directory_watcher_mac.cc new file mode 100644 index 0000000..d4b3082 --- /dev/null +++ b/base/directory_watcher_mac.cc @@ -0,0 +1,121 @@ +// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/directory_watcher.h" + +#include <CoreServices/CoreServices.h> + +#include "base/file_path.h" +#include "base/file_util.h" +#include "base/logging.h" +#include "base/message_loop.h" +#include "base/scoped_cftyperef.h" + +namespace { + +const CFAbsoluteTime kEventLatencySeconds = 0.3; + +class DirectoryWatcherImpl : public DirectoryWatcher::PlatformDelegate { + public: + DirectoryWatcherImpl() {} + ~DirectoryWatcherImpl() { + if (!path_.value().empty()) { + FSEventStreamStop(fsevent_stream_); + FSEventStreamInvalidate(fsevent_stream_); + FSEventStreamRelease(fsevent_stream_); + } + } + + virtual bool Watch(const FilePath& path, DirectoryWatcher::Delegate* delegate, + bool recursive); + + void OnFSEventsCallback(const FilePath& event_path) { + DCHECK(!path_.value().empty()); + if (!recursive_) { + FilePath absolute_event_path = event_path; + if (!file_util::AbsolutePath(&absolute_event_path)) + return; + if (absolute_event_path != path_) + return; + } + delegate_->OnDirectoryChanged(path_); + } + + private: + // Delegate to notify upon changes. + DirectoryWatcher::Delegate* delegate_; + + // Path we're watching (passed to delegate). + FilePath path_; + + // Indicates recursive watch. + bool recursive_; + + // Backend stream we receive event callbacks from (strong reference). + FSEventStreamRef fsevent_stream_; + + DISALLOW_COPY_AND_ASSIGN(DirectoryWatcherImpl); +}; + +void FSEventsCallback(ConstFSEventStreamRef stream, + void* event_watcher, size_t num_events, + void* event_paths, const FSEventStreamEventFlags flags[], + const FSEventStreamEventId event_ids[]) { + char** paths = reinterpret_cast<char**>(event_paths); + DirectoryWatcherImpl* watcher = + reinterpret_cast<DirectoryWatcherImpl*> (event_watcher); + for (size_t i = 0; i < num_events; i++) { + watcher->OnFSEventsCallback(FilePath(paths[i])); + } +} + +bool DirectoryWatcherImpl::Watch(const FilePath& path, + DirectoryWatcher::Delegate* delegate, + bool recursive) { + DCHECK(path_.value().empty()); // Can only watch one path. + + DCHECK(MessageLoop::current()->type() == MessageLoop::TYPE_UI); + + if (!file_util::PathExists(path)) + return false; + + path_ = path; + if (!file_util::AbsolutePath(&path_)) { + path_ = FilePath(); // Make sure we're marked as not-in-use. + return false; + } + delegate_ = delegate; + recursive_ = recursive; + + scoped_cftyperef<CFStringRef> cf_path(CFStringCreateWithCString( + NULL, path.value().c_str(), kCFStringEncodingMacHFS)); + CFStringRef path_for_array = cf_path.get(); + scoped_cftyperef<CFArrayRef> watched_paths(CFArrayCreate( + NULL, reinterpret_cast<const void**>(&path_for_array), 1, + &kCFTypeArrayCallBacks)); + + FSEventStreamContext context; + context.version = 0; + context.info = this; + context.retain = NULL; + context.release = NULL; + context.copyDescription = NULL; + + fsevent_stream_ = FSEventStreamCreate(NULL, &FSEventsCallback, &context, + watched_paths, + kFSEventStreamEventIdSinceNow, + kEventLatencySeconds, + kFSEventStreamCreateFlagNone); + FSEventStreamScheduleWithRunLoop(fsevent_stream_, CFRunLoopGetCurrent(), + kCFRunLoopDefaultMode); + FSEventStreamStart(fsevent_stream_); + + return true; +} + +} // namespace + +DirectoryWatcher::DirectoryWatcher() { + impl_ = new DirectoryWatcherImpl(); +} |