#import #import #import "atom_application.h" #import "native.h" #import "include/cef_base.h" #import "path_watcher.h" #import static std::string windowState = ""; static NSLock *windowStateLock = [[NSLock alloc] init]; namespace v8_extensions { using namespace std; NSString *stringFromCefV8Value(const CefRefPtr& value); void throwException(const CefRefPtr& global, CefRefPtr exception, NSString *message); Native::Native() : CefV8Handler() { } void Native::CreateContextBinding(CefRefPtr context) { const char* methodNames[] = { "writeToPasteboard", "readFromPasteboard", "quit", "watchPath", "unwatchPath", "getWatchedPaths", "unwatchAllPaths", "moveToTrash", "reload", "setWindowState", "getWindowState", "beep" }; CefRefPtr nativeObject = CefV8Value::CreateObject(NULL); int arrayLength = sizeof(methodNames) / sizeof(const char *); for (int i = 0; i < arrayLength; i++) { const char *functionName = methodNames[i]; CefRefPtr function = CefV8Value::CreateFunction(functionName, this); nativeObject->SetValue(functionName, function, V8_PROPERTY_ATTRIBUTE_NONE); } CefRefPtr global = context->GetGlobal(); global->SetValue("$native", nativeObject, V8_PROPERTY_ATTRIBUTE_NONE); } bool Native::Execute(const CefString& name, CefRefPtr object, const CefV8ValueList& arguments, CefRefPtr& retval, CefString& exception) { @autoreleasepool { if (name == "writeToPasteboard") { NSString *text = stringFromCefV8Value(arguments[0]); NSPasteboard *pb = [NSPasteboard generalPasteboard]; [pb declareTypes:[NSArray arrayWithObjects:NSStringPboardType, nil] owner:nil]; [pb setString:text forType:NSStringPboardType]; return true; } else if (name == "readFromPasteboard") { NSPasteboard *pb = [NSPasteboard generalPasteboard]; NSArray *results = [pb readObjectsForClasses:[NSArray arrayWithObjects:[NSString class], nil] options:nil]; if (results) { retval = CefV8Value::CreateString([[results objectAtIndex:0] UTF8String]); } return true; } else if (name == "quit") { [NSApp terminate:nil]; return true; } else if (name == "watchPath") { NSString *path = stringFromCefV8Value(arguments[0]); CefRefPtr function = arguments[1]; CefRefPtr context = CefV8Context::GetCurrentContext(); WatchCallback callback = ^(NSString *eventType, NSString *path) { context->Enter(); CefV8ValueList args; args.push_back(CefV8Value::CreateString(string([eventType UTF8String], [eventType lengthOfBytesUsingEncoding:NSUTF8StringEncoding]))); args.push_back(CefV8Value::CreateString(string([path UTF8String], [path lengthOfBytesUsingEncoding:NSUTF8StringEncoding]))); function->ExecuteFunction(function, args); context->Exit(); }; PathWatcher *pathWatcher = [PathWatcher pathWatcherForContext:CefV8Context::GetCurrentContext()]; NSString *watchId = [pathWatcher watchPath:path callback:[[callback copy] autorelease]]; if (watchId) { retval = CefV8Value::CreateString([watchId UTF8String]); } else { exception = string("Failed to watch path '") + string([path UTF8String]) + string("' (it may not exist)"); } return true; } else if (name == "unwatchPath") { NSString *path = stringFromCefV8Value(arguments[0]); NSString *callbackId = stringFromCefV8Value(arguments[1]); NSError *error = nil; PathWatcher *pathWatcher = [PathWatcher pathWatcherForContext:CefV8Context::GetCurrentContext()]; [pathWatcher unwatchPath:path callbackId:callbackId error:&error]; if (error) { exception = [[error localizedDescription] UTF8String]; } return true; } else if (name == "getWatchedPaths") { PathWatcher *pathWatcher = [PathWatcher pathWatcherForContext:CefV8Context::GetCurrentContext()]; NSArray *paths = [pathWatcher watchedPaths]; CefRefPtr pathsArray = CefV8Value::CreateArray([paths count]); for (int i = 0; i < [paths count]; i++) { CefRefPtr path = CefV8Value::CreateString([[paths objectAtIndex:i] UTF8String]); pathsArray->SetValue(i, path); } retval = pathsArray; return true; } else if (name == "unwatchAllPaths") { PathWatcher *pathWatcher = [PathWatcher pathWatcherForContext:CefV8Context::GetCurrentContext()]; [pathWatcher unwatchAllPaths]; return true; } else if (name == "moveToTrash") { NSString *sourcePath = stringFromCefV8Value(arguments[0]); bool success = [[NSWorkspace sharedWorkspace] performFileOperation:NSWorkspaceRecycleOperation source:[sourcePath stringByDeletingLastPathComponent] destination:@"" files:[NSArray arrayWithObject:[sourcePath lastPathComponent]] tag:nil]; if (!success) { string exception = "Can not move "; exception += [sourcePath UTF8String]; exception += " to trash."; } return true; } else if (name == "reload") { CefV8Context::GetCurrentContext()->GetBrowser()->ReloadIgnoreCache(); } else if (name == "setWindowState") { [windowStateLock lock]; windowState = arguments[0]->GetStringValue().ToString(); [windowStateLock unlock]; return true; } else if (name == "getWindowState") { [windowStateLock lock]; retval = CefV8Value::CreateString(windowState); [windowStateLock unlock]; return true; } else if (name == "beep") { NSBeep(); } return false; } }; NSString *stringFromCefV8Value(const CefRefPtr& value) { string cc_value = value->GetStringValue().ToString(); return [NSString stringWithUTF8String:cc_value.c_str()]; } void throwException(const CefRefPtr& global, CefRefPtr exception, NSString *message) { CefV8ValueList arguments; message = [message stringByAppendingFormat:@"\n%s", exception->GetMessage().ToString().c_str()]; arguments.push_back(CefV8Value::CreateString(string([message UTF8String], [message lengthOfBytesUsingEncoding:NSUTF8StringEncoding]))); CefRefPtr console = global->GetValue("console"); console->GetValue("error")->ExecuteFunction(console, arguments); } } // namespace v8_extensions