mirror of
https://github.com/pulsar-edit/pulsar.git
synced 2025-01-08 16:19:17 +03:00
A new PathWatcher is created for each v8 context. When the associated v8 context is released, the PathWatcher stops watching all its files and deallocs .
This commit is contained in:
parent
4aed73d947
commit
074e2b9b85
@ -83,7 +83,7 @@
|
||||
0487CDA014FEE1DA0045E5E3 /* liblibcef_wrapper.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 0487CC8114FEDF990045E5E3 /* liblibcef_wrapper.a */; };
|
||||
0487D15F14FEE7880045E5E3 /* Resources in Resources */ = {isa = PBXBuildFile; fileRef = 0487D15E14FEE7880045E5E3 /* Resources */; };
|
||||
0487D16014FEE78E0045E5E3 /* Resources in Copy Chrome Resources */ = {isa = PBXBuildFile; fileRef = 0487D15E14FEE7880045E5E3 /* Resources */; };
|
||||
048A2FC7154870DC0051715C /* PathWatcher.m in Sources */ = {isa = PBXBuildFile; fileRef = 048A2FC6154870DC0051715C /* PathWatcher.m */; };
|
||||
048A2FC7154870DC0051715C /* PathWatcher.mm in Sources */ = {isa = PBXBuildFile; fileRef = 048A2FC6154870DC0051715C /* PathWatcher.mm */; };
|
||||
04E1DDDD152A0941001A9D07 /* Sparkle.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 04E1DDDC152A0941001A9D07 /* Sparkle.framework */; };
|
||||
04E1DDDF152A09C3001A9D07 /* Sparkle.framework in Copy Sparkle Framework */ = {isa = PBXBuildFile; fileRef = 04E1DDDC152A0941001A9D07 /* Sparkle.framework */; };
|
||||
/* End PBXBuildFile section */
|
||||
@ -394,7 +394,7 @@
|
||||
0487CD6C14FEE0EC0045E5E3 /* libcef.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libcef.dylib; path = frameworks/libcef.dylib; sourceTree = "<group>"; };
|
||||
0487D15E14FEE7880045E5E3 /* Resources */ = {isa = PBXFileReference; lastKnownFileType = folder; path = Resources; sourceTree = "<group>"; };
|
||||
048A2FC5154870DC0051715C /* PathWatcher.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PathWatcher.h; sourceTree = "<group>"; };
|
||||
048A2FC6154870DC0051715C /* PathWatcher.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PathWatcher.m; sourceTree = "<group>"; };
|
||||
048A2FC6154870DC0051715C /* PathWatcher.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = PathWatcher.mm; sourceTree = "<group>"; };
|
||||
04E1DDDC152A0941001A9D07 /* Sparkle.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Sparkle.framework; path = frameworks/Sparkle.framework; sourceTree = "<group>"; };
|
||||
04F21A2615644AC10083F6D4 /* ResourceConfig.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = ResourceConfig.xcconfig; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
@ -810,7 +810,7 @@
|
||||
0487C93F14FED6090045E5E3 /* AtomController.mm */,
|
||||
042180E614FF080D00DF25EA /* BrowserDelegate.h */,
|
||||
048A2FC5154870DC0051715C /* PathWatcher.h */,
|
||||
048A2FC6154870DC0051715C /* PathWatcher.m */,
|
||||
048A2FC6154870DC0051715C /* PathWatcher.mm */,
|
||||
0487C94014FED6090045E5E3 /* client_handler.h */,
|
||||
0487C94114FED6090045E5E3 /* client_handler.mm */,
|
||||
0487C94314FED6090045E5E3 /* native_handler.h */,
|
||||
@ -963,7 +963,7 @@
|
||||
0487CD9614FEE1360045E5E3 /* client_handler.mm in Sources */,
|
||||
0487CD9714FEE1380045E5E3 /* main.mm in Sources */,
|
||||
0487CD9814FEE13B0045E5E3 /* native_handler.mm in Sources */,
|
||||
048A2FC7154870DC0051715C /* PathWatcher.m in Sources */,
|
||||
048A2FC7154870DC0051715C /* PathWatcher.mm in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
@ -88,8 +88,6 @@
|
||||
|
||||
#pragma mark BrowserDelegate
|
||||
- (void)loadStart {
|
||||
[PathWatcher unwatchAll];
|
||||
|
||||
CefRefPtr<CefV8Context> context = _clientHandler->GetBrowser()->GetMainFrame()->GetV8Context();
|
||||
CefRefPtr<CefV8Value> global = context->GetGlobal();
|
||||
|
||||
|
@ -1,15 +1,24 @@
|
||||
#import "include/cef_base.h"
|
||||
#import "include/cef_v8.h"
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
typedef void (^WatchCallback)(NSArray *);
|
||||
|
||||
@interface PathWatcher : NSObject {
|
||||
int _kq;
|
||||
CefRefPtr<CefV8Context> _context;
|
||||
NSMutableDictionary *_fileDescriptorsByPath;
|
||||
NSMutableDictionary *_callbacksByFileDescriptor;
|
||||
|
||||
bool _keepWatching;
|
||||
}
|
||||
|
||||
+ (NSString *)watchPath:(NSString *)path callback:(WatchCallback)callback;
|
||||
+ (void)unwatchPath:(NSString *)path callbackId:(NSString *)callbackId error:(NSError **)error;
|
||||
+ (void)unwatchAll;
|
||||
+ (PathWatcher *)pathWatcherForContext:(CefRefPtr<CefV8Context>)context;
|
||||
+ (void)removePathWatcherForContext:(CefRefPtr<CefV8Context>)context;
|
||||
|
||||
- (id)initWithContext:(CefRefPtr<CefV8Context>)context;
|
||||
- (NSString *)watchPath:(NSString *)path callback:(WatchCallback)callback;
|
||||
- (void)unwatchPath:(NSString *)path callbackId:(NSString *)callbackId error:(NSError **)error;
|
||||
|
||||
|
||||
@end
|
||||
|
@ -4,33 +4,49 @@
|
||||
#import <sys/time.h>
|
||||
#import <fcntl.h>
|
||||
|
||||
|
||||
static NSMutableArray *gPathWatchers;
|
||||
|
||||
@interface PathWatcher ()
|
||||
- (NSString *)watchPath:(NSString *)path callback:(WatchCallback)callback;
|
||||
- (bool)usesContext:(CefRefPtr<CefV8Context>)context;
|
||||
- (void)watchFileDescriptor:(int)fd;
|
||||
- (void)unwatchPath:(NSString *)path callbackId:(NSString *)callbackId error:(NSError **)error;
|
||||
- (void)unwatchAll;
|
||||
- (void)stopWatching;
|
||||
@end
|
||||
|
||||
@implementation PathWatcher
|
||||
|
||||
+ (id)instance {
|
||||
static PathWatcher *pathWatcher;
|
||||
if (!pathWatcher) pathWatcher = [[PathWatcher alloc] init];
|
||||
+ (PathWatcher *)pathWatcherForContext:(CefRefPtr<CefV8Context>)context {
|
||||
if (!gPathWatchers) gPathWatchers = [[NSMutableArray alloc] init];
|
||||
|
||||
PathWatcher *pathWatcher = nil;
|
||||
for (PathWatcher *p in gPathWatchers) {
|
||||
if ([p usesContext:context]) {
|
||||
pathWatcher = p;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!pathWatcher) {
|
||||
pathWatcher = [[[PathWatcher alloc] initWithContext:context] autorelease];
|
||||
[gPathWatchers addObject:pathWatcher];
|
||||
}
|
||||
|
||||
return pathWatcher;
|
||||
}
|
||||
|
||||
+ (NSString *)watchPath:(NSString *)path callback:(WatchCallback)callback {
|
||||
return [[self instance] watchPath:path callback:callback];
|
||||
}
|
||||
+ (void)removePathWatcherForContext:(CefRefPtr<CefV8Context>)context {
|
||||
PathWatcher *pathWatcher = nil;
|
||||
for (PathWatcher *p in gPathWatchers) {
|
||||
if ([p usesContext:context]) {
|
||||
pathWatcher = p;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (pathWatcher) {
|
||||
[pathWatcher stopWatching];
|
||||
[gPathWatchers removeObject:pathWatcher];
|
||||
}
|
||||
|
||||
+ (void)unwatchPath:(NSString *)path callbackId:(NSString *)callbackId error:(NSError **)error {
|
||||
return [[self instance] unwatchPath:path callbackId:callbackId error:error];
|
||||
}
|
||||
|
||||
+ (void)unwatchAll {
|
||||
return [[self instance] unwatchAll];
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
@ -39,16 +55,18 @@
|
||||
close([fdNumber intValue]);
|
||||
}
|
||||
[_callbacksByFileDescriptor release];
|
||||
|
||||
_context = nil;
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (id)init {
|
||||
- (id)initWithContext:(CefRefPtr<CefV8Context>)context {
|
||||
self = [super init];
|
||||
|
||||
_keepWatching = YES;
|
||||
_callbacksByFileDescriptor = [[NSMutableDictionary alloc] init];
|
||||
_fileDescriptorsByPath = [[NSMutableDictionary alloc] init];
|
||||
_kq = kqueue();
|
||||
_context = context;
|
||||
|
||||
if (_kq == -1) {
|
||||
[NSException raise:@"PathWatcher" format:@"Could not create kqueue"];
|
||||
@ -58,6 +76,15 @@
|
||||
return self;
|
||||
}
|
||||
|
||||
- (bool)usesContext:(CefRefPtr<CefV8Context>)context {
|
||||
return _context->IsSame(context);
|
||||
}
|
||||
|
||||
- (void)stopWatching {
|
||||
[self unwatchAll];
|
||||
_keepWatching = false;
|
||||
}
|
||||
|
||||
- (NSString *)watchPath:(NSString *)path callback:(WatchCallback)callback {
|
||||
path = [path stringByStandardizingPath];
|
||||
NSString *callbackId;
|
||||
@ -131,7 +158,7 @@
|
||||
struct kevent event;
|
||||
int filter = EVFILT_VNODE;
|
||||
int flags = EV_ADD | EV_ENABLE | EV_CLEAR;
|
||||
int filterFlags = NOTE_WRITE;
|
||||
int filterFlags = NOTE_WRITE | NOTE_DELETE | NOTE_ATTRIB | NOTE_EXTEND | NOTE_RENAME | NOTE_REVOKE;
|
||||
EV_SET(&event, fd, filter, flags, filterFlags, 0, 0);
|
||||
kevent(_kq, &event, 1, NULL, 0, &timeout);
|
||||
}
|
||||
@ -141,7 +168,7 @@
|
||||
struct kevent event;
|
||||
struct timespec timeout = { 5, 0 }; // 5 seconds timeout.
|
||||
|
||||
while (true) {
|
||||
while (_keepWatching) {
|
||||
int numberOfEvents = kevent(_kq, NULL, 0, &event, 1, &timeout);
|
||||
|
||||
if (numberOfEvents < 0) {
|
||||
@ -152,8 +179,8 @@
|
||||
}
|
||||
|
||||
NSMutableArray *eventFlags = [NSMutableArray array];
|
||||
|
||||
if (event.fflags & NOTE_WRITE) {
|
||||
|
||||
if (event.fflags & NOTE_WRITE || [self isAtomicWrite:event]) {
|
||||
[eventFlags addObject:@"modified"];
|
||||
}
|
||||
|
||||
@ -169,9 +196,21 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[self release];
|
||||
}
|
||||
}
|
||||
|
||||
- (bool)isAtomicWrite:(struct kevent)event {
|
||||
if (!event.fflags & NOTE_DELETE) return NO;
|
||||
|
||||
NSFileManager *fm = [NSFileManager defaultManager];
|
||||
NSString *path = nil;
|
||||
for (path in [_fileDescriptorsByPath allKeys]) {
|
||||
if ([[_fileDescriptorsByPath objectForKey:path] unsignedLongValue] == event.ident) {
|
||||
return [fm fileExistsAtPath:path];
|
||||
}
|
||||
}
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
@end
|
@ -107,7 +107,9 @@ public:
|
||||
virtual void OnContextCreated(CefRefPtr<CefBrowser> browser,
|
||||
CefRefPtr<CefFrame> frame,
|
||||
CefRefPtr<CefV8Context> context) OVERRIDE;
|
||||
|
||||
virtual void OnContextReleased(CefRefPtr<CefBrowser> browser,
|
||||
CefRefPtr<CefFrame> frame,
|
||||
CefRefPtr<CefV8Context> context) OVERRIDE;
|
||||
// CefDragHandler methods.
|
||||
virtual bool OnDragStart(CefRefPtr<CefBrowser> browser,
|
||||
CefRefPtr<CefDragData> dragData,
|
||||
|
@ -1,6 +1,7 @@
|
||||
#import "include/cef_base.h"
|
||||
#import "client_handler.h"
|
||||
#import "AtomController.h"
|
||||
#import "PathWatcher.h"
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import <iostream>
|
||||
@ -174,6 +175,13 @@ void ClientHandler::OnContextCreated(CefRefPtr<CefBrowser> browser,
|
||||
REQUIRE_UI_THREAD();
|
||||
}
|
||||
|
||||
void ClientHandler::OnContextReleased(CefRefPtr<CefBrowser> browser,
|
||||
CefRefPtr<CefFrame> frame,
|
||||
CefRefPtr<CefV8Context> context) {
|
||||
REQUIRE_UI_THREAD();
|
||||
[PathWatcher removePathWatcherForContext:context];
|
||||
}
|
||||
|
||||
bool ClientHandler::OnDragStart(CefRefPtr<CefBrowser> browser,
|
||||
CefRefPtr<CefDragData> dragData,
|
||||
DragOperationsMask mask)
|
||||
|
@ -319,8 +319,9 @@ bool NativeHandler::Execute(const CefString& name,
|
||||
|
||||
context->Exit();
|
||||
};
|
||||
|
||||
NSString *watchId = [PathWatcher watchPath:path callback:[[callback copy] autorelease]];
|
||||
|
||||
PathWatcher *pathWatcher = [PathWatcher pathWatcherForContext:CefV8Context::GetCurrentContext()];
|
||||
NSString *watchId = [pathWatcher watchPath:path callback:[[callback copy] autorelease]];
|
||||
retval = CefV8Value::CreateString([watchId UTF8String]);
|
||||
|
||||
return true;
|
||||
@ -329,7 +330,8 @@ bool NativeHandler::Execute(const CefString& name,
|
||||
NSString *path = stringFromCefV8Value(arguments[0]);
|
||||
NSString *callbackId = stringFromCefV8Value(arguments[1]);
|
||||
NSError *error = nil;
|
||||
[PathWatcher unwatchPath:path callbackId:callbackId error:&error];
|
||||
PathWatcher *pathWatcher = [PathWatcher pathWatcherForContext:CefV8Context::GetCurrentContext()];
|
||||
[pathWatcher unwatchPath:path callbackId:callbackId error:&error];
|
||||
|
||||
if (error) {
|
||||
exception = [[error localizedDescription] UTF8String];
|
||||
|
Loading…
Reference in New Issue
Block a user