Merge branch 'chrome'
@@ -1,7 +0,0 @@
|
||||
//
|
||||
// Prefix header for all source files of the 'Atom' target in the 'Atom' project
|
||||
//
|
||||
|
||||
#ifdef __OBJC__
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#endif
|
||||
BIN
Atom/Atom.icns
Executable file
@@ -1,17 +0,0 @@
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
@class AtomController, AtomMenuItem;
|
||||
|
||||
@interface AtomApp : NSApplication <NSApplicationDelegate>
|
||||
|
||||
@property (nonatomic, retain) NSMutableArray *controllers;
|
||||
|
||||
- (void)removeController:(AtomController *)controller;
|
||||
- (IBAction)runSpecs:(id)sender;
|
||||
- (void)performActionForMenuItem:(AtomMenuItem *)item;
|
||||
- (void)resetMainMenu;
|
||||
|
||||
- (NSString *)getCachedScript:(NSString *)filePath;
|
||||
- (void)setCachedScript:(NSString *)filePath contents:(NSString *)contents;
|
||||
|
||||
@end
|
||||
@@ -1,144 +0,0 @@
|
||||
#import "AtomApp.h"
|
||||
|
||||
#import "JSCocoa.h"
|
||||
#import <WebKit/WebKit.h>
|
||||
|
||||
#import "AtomController.h"
|
||||
#import "AtomMenuItem.h"
|
||||
|
||||
#define ATOM_USER_PATH ([[NSString stringWithString:@"~/.atom/"] stringByStandardizingPath])
|
||||
#define ATOM_STORAGE_PATH ([ATOM_USER_PATH stringByAppendingPathComponent:@".app-storage"])
|
||||
|
||||
@interface AtomApp () {
|
||||
NSMutableDictionary *_coffeeCache;
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation AtomApp
|
||||
|
||||
@synthesize controllers = _controllers;
|
||||
|
||||
- (void)open:(NSString *)path {
|
||||
AtomController *controller = [[AtomController alloc] initWithURL:path];
|
||||
[self.controllers addObject:controller];
|
||||
}
|
||||
|
||||
- (void)removeController:(AtomController *)controller {
|
||||
[self.controllers removeObject:controller];
|
||||
}
|
||||
|
||||
// Events in the "app:*" namespace are sent to all controllers
|
||||
- (void)triggerGlobalAtomEvent:(NSString *)name data:(id)data {
|
||||
for (AtomController *controller in self.controllers) {
|
||||
[controller triggerAtomEventWithName:name data:data];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark Overrides
|
||||
- (void) sendEvent: (NSEvent *)event {
|
||||
// Default implementation for key down tries key equivalents first
|
||||
// We want to wait until the web view handles the event, then allow key equivalents to be tried
|
||||
if (([event type] != NSKeyDown) || !event.window) {
|
||||
[super sendEvent:event];
|
||||
return;
|
||||
}
|
||||
|
||||
[event.window sendEvent:event];
|
||||
}
|
||||
|
||||
#pragma mark Actions
|
||||
- (IBAction)openNewWindow:(id)sender {
|
||||
[self open:nil];
|
||||
}
|
||||
|
||||
- (IBAction)openPathInNewWindow:(id)sender {
|
||||
NSOpenPanel *panel = [NSOpenPanel openPanel];
|
||||
[panel setCanChooseDirectories:YES];
|
||||
if ([panel runModal] == NSFileHandlingPanelOKButton) {
|
||||
[self open:[panel.URLs.lastObject path]];
|
||||
}
|
||||
}
|
||||
|
||||
- (IBAction)runSpecs:(id)sender {
|
||||
[[AtomController alloc] initForSpecs];
|
||||
}
|
||||
|
||||
- (void)terminate:(id)sender {
|
||||
for (AtomController *controller in self.controllers) {
|
||||
[controller close];
|
||||
}
|
||||
|
||||
[super terminate:sender];
|
||||
}
|
||||
|
||||
#pragma mark NSAppDelegate
|
||||
- (void)applicationWillFinishLaunching:(NSNotification *)aNotification {
|
||||
self.controllers = [NSMutableArray array];
|
||||
|
||||
NSDictionary *defaults = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:YES], @"WebKitDeveloperExtras", nil];
|
||||
[[NSUserDefaults standardUserDefaults] registerDefaults:defaults];
|
||||
}
|
||||
|
||||
- (void)applicationDidFinishLaunching:(NSNotification *)notification {
|
||||
_coffeeCache = [[NSMutableDictionary alloc] init];
|
||||
|
||||
if ([[[NSProcessInfo processInfo] environment] objectForKey:@"AUTO-TEST"]) {
|
||||
[self runSpecs:self];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)performActionForMenuItem:(AtomMenuItem *)item {
|
||||
AtomController *atomController = self.keyWindow.windowController;
|
||||
[atomController performActionForMenuItemPath:item.itemPath];
|
||||
}
|
||||
|
||||
- (void)resetMenu:(NSMenu *)menu {
|
||||
for (AtomMenuItem *item in menu.itemArray) {
|
||||
if (![item isKindOfClass:[AtomMenuItem class]]) continue;
|
||||
|
||||
if (item.submenu) {
|
||||
[self resetMenu:item.submenu];
|
||||
if (item.submenu.numberOfItems == 0) {
|
||||
[menu removeItem:item];
|
||||
}
|
||||
}
|
||||
else if (!item.global) {
|
||||
[menu removeItem:item];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)resetMainMenu {
|
||||
[self resetMenu:self.mainMenu];
|
||||
}
|
||||
|
||||
- (NSString *)getCachedScript:(NSString *)filePath {
|
||||
NSDictionary *cachedObject = [_coffeeCache objectForKey:filePath];
|
||||
if (!cachedObject) return nil;
|
||||
|
||||
NSFileManager *fm = [NSFileManager defaultManager];
|
||||
NSError *error = nil;
|
||||
NSDictionary *attributes = [fm attributesOfItemAtPath:filePath error:&error];
|
||||
if (error) {
|
||||
NSLog(@"Error reading cached scripts: %@", [error localizedDescription]);
|
||||
return nil;
|
||||
}
|
||||
|
||||
NSDate *cachedAt = [cachedObject objectForKey:@"cachedAt"];
|
||||
NSDate *modifedAt = [attributes objectForKey:NSFileModificationDate];
|
||||
if (modifedAt && [modifedAt compare:cachedAt] == NSOrderedAscending) {
|
||||
return [cachedObject objectForKey:@"script"];
|
||||
}
|
||||
else {
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setCachedScript:(NSString *)filePath contents:(NSString *)contents {
|
||||
NSMutableDictionary *cachedObject = [NSMutableDictionary dictionary];
|
||||
[cachedObject setObject:[NSDate date] forKey:@"cachedAt"];
|
||||
[cachedObject setObject:contents forKey:@"script"];
|
||||
[_coffeeCache setObject:cachedObject forKey:filePath];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -1,23 +0,0 @@
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import "JSCocoa.h"
|
||||
|
||||
@class JSCocoa, WebView, FileSystemHelper;
|
||||
|
||||
struct JSGlobalContextRef;
|
||||
|
||||
@interface AtomController : NSWindowController <NSWindowDelegate>
|
||||
|
||||
@property (assign) WebView *webView;
|
||||
@property (nonatomic, retain, readonly) NSString *url;
|
||||
@property (nonatomic, retain, readonly) NSString *bootstrapScript;
|
||||
@property (nonatomic, retain, readonly) FileSystemHelper *fs;
|
||||
|
||||
- (id)initForSpecs;
|
||||
- (id)initWithURL:(NSString *)url;
|
||||
|
||||
- (void)triggerAtomEventWithName:(NSString *)name data:(id)data;
|
||||
- (void)reload;
|
||||
- (JSValueRefAndContextRef)jsWindow;
|
||||
- (void)performActionForMenuItemPath:(NSString *)menuItemPath;
|
||||
|
||||
@end
|
||||
@@ -1,167 +0,0 @@
|
||||
#import "AtomController.h"
|
||||
|
||||
#import "JSCocoa.h"
|
||||
#import <WebKit/WebKit.h>
|
||||
#import <dispatch/dispatch.h>
|
||||
|
||||
#import "AtomApp.h"
|
||||
#import "FileSystemHelper.h"
|
||||
|
||||
@interface AtomController ()
|
||||
@property (nonatomic, retain) JSCocoa *jscocoa;
|
||||
@property (nonatomic, retain, readwrite) NSString *url;
|
||||
@property (nonatomic, retain, readwrite) NSString *bootstrapScript;
|
||||
@property (nonatomic, retain, readwrite) FileSystemHelper *fs;
|
||||
|
||||
- (void)createWebView;
|
||||
- (void)blockUntilWebViewLoads;
|
||||
|
||||
@end
|
||||
|
||||
@interface WebView (Atom)
|
||||
- (id)inspector;
|
||||
- (void)showConsole:(id)sender;
|
||||
- (void)startDebuggingJavaScript:(id)sender;
|
||||
@end
|
||||
|
||||
@implementation AtomController
|
||||
|
||||
@synthesize webView = _webView;
|
||||
@synthesize jscocoa = _jscocoa;
|
||||
@synthesize url = _url;
|
||||
@synthesize bootstrapScript = _bootstrapScript;
|
||||
@synthesize fs = _fs;
|
||||
|
||||
- (void)dealloc {
|
||||
self.webView = nil;
|
||||
self.bootstrapScript = nil;
|
||||
self.url = nil;
|
||||
self.jscocoa = nil;
|
||||
self.fs = nil;
|
||||
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (id)initWithBootstrapScript:(NSString *)bootstrapScript url:(NSString *)url {
|
||||
self = [super initWithWindowNibName:@"AtomWindow"];
|
||||
self.bootstrapScript = bootstrapScript;
|
||||
self.url = url;
|
||||
|
||||
[self.window makeKeyWindow];
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id)initForSpecs {
|
||||
return [self initWithBootstrapScript:@"spec-bootstrap" url:nil];
|
||||
}
|
||||
|
||||
- (id)initWithURL:(NSString *)url {
|
||||
return [self initWithBootstrapScript:@"bootstrap" url:url];
|
||||
}
|
||||
|
||||
- (void)windowDidLoad {
|
||||
[super windowDidLoad];
|
||||
|
||||
[self.window setDelegate:self];
|
||||
[self.window setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary];
|
||||
|
||||
[self setShouldCascadeWindows:YES];
|
||||
[self setWindowFrameAutosaveName:@"atomController"];
|
||||
|
||||
[self createWebView];
|
||||
}
|
||||
|
||||
- (void)triggerAtomEventWithName:(NSString *)name data:(id)data {
|
||||
[self.jscocoa callJSFunctionNamed:@"triggerEvent" withArguments:name, data, false, nil];
|
||||
}
|
||||
|
||||
- (void)createWebView {
|
||||
self.webView = [[WebView alloc] initWithFrame:[self.window.contentView frame]];
|
||||
|
||||
[self.webView setAutoresizingMask:NSViewWidthSizable|NSViewHeightSizable];
|
||||
[self.window.contentView addSubview:self.webView];
|
||||
[self.webView setUIDelegate:self];
|
||||
[self.webView setFrameLoadDelegate:self];
|
||||
|
||||
NSURL *resourceDirURL = [[NSBundle mainBundle] resourceURL];
|
||||
NSURL *indexURL = [resourceDirURL URLByAppendingPathComponent:@"index.html"];
|
||||
|
||||
NSURLRequest *request = [NSURLRequest requestWithURL:indexURL];
|
||||
[[self.webView mainFrame] loadRequest:request];
|
||||
|
||||
[self blockUntilWebViewLoads];
|
||||
}
|
||||
|
||||
- (void)blockUntilWebViewLoads {
|
||||
NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
|
||||
while (self.webView.isLoading) {
|
||||
[runLoop runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)reload {
|
||||
[self.webView reload:self];
|
||||
}
|
||||
|
||||
- (void)close {
|
||||
[(AtomApp *)NSApp removeController:self];
|
||||
[super close];
|
||||
}
|
||||
|
||||
- (NSString *)projectPath {
|
||||
return PROJECT_DIR;
|
||||
}
|
||||
|
||||
- (void)performActionForMenuItemPath:(NSString *)menuItemPath {
|
||||
NSString *jsCode = [NSString stringWithFormat:@"window.performActionForMenuItemPath('%@')", menuItemPath];
|
||||
[self.jscocoa evalJSString:jsCode];
|
||||
}
|
||||
|
||||
- (JSValueRefAndContextRef)jsWindow {
|
||||
JSValueRef window = [self.jscocoa evalJSString:@"window"];
|
||||
JSValueRefAndContextRef windowWithContext = {window, self.jscocoa.ctx};
|
||||
return windowWithContext;
|
||||
}
|
||||
|
||||
- (NSString *)absolute:(NSString *)path {
|
||||
path = [path stringByStandardizingPath];
|
||||
if ([path characterAtIndex:0] == '/') {
|
||||
return path;
|
||||
}
|
||||
|
||||
NSString *resolvedPath = [[NSFileManager defaultManager] currentDirectoryPath];
|
||||
resolvedPath = [[resolvedPath stringByAppendingPathComponent:path] stringByStandardizingPath];
|
||||
|
||||
return resolvedPath;
|
||||
}
|
||||
|
||||
#pragma mark NSWindowDelegate
|
||||
- (BOOL)windowShouldClose:(id)sender {
|
||||
[self close];
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)keyDown:(NSEvent *)event {
|
||||
if ([event modifierFlags] & NSCommandKeyMask && [[event charactersIgnoringModifiers] hasPrefix:@"r"]) {
|
||||
[self reload];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark WebUIDelegate
|
||||
- (NSArray *)webView:(WebView *)sender contextMenuItemsForElement:(NSDictionary *)element defaultMenuItems:(NSArray *)defaultMenuItems {
|
||||
return defaultMenuItems;
|
||||
}
|
||||
|
||||
- (void)webViewClose:(WebView *)sender { // Triggered when closed from javascript
|
||||
[self close];
|
||||
}
|
||||
|
||||
#pragma mark WebFrameLoadDelegate
|
||||
- (void)webView:(WebView *)sender didCommitLoadForFrame:(WebFrame *)frame {
|
||||
self.jscocoa = [[JSCocoa alloc] initWithGlobalContext:[frame globalContext]];
|
||||
[self.jscocoa setObject:self withName:@"$atomController"];
|
||||
[self.jscocoa setObject:self.bootstrapScript withName:@"$bootstrapScript"];
|
||||
self.fs = [[[FileSystemHelper alloc] initWithJSContextRef:(JSContextRef)self.jscocoa.ctx] autorelease];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -1,10 +0,0 @@
|
||||
#import <AppKit/AppKit.h>
|
||||
|
||||
@interface AtomMenuItem : NSMenuItem
|
||||
|
||||
@property BOOL global;
|
||||
@property (nonatomic, retain) NSString *itemPath;
|
||||
|
||||
- initWithTitle:(NSString *)title itemPath:(NSString *)itemPath;
|
||||
|
||||
@end
|
||||
@@ -1,14 +0,0 @@
|
||||
#import "AtomMenuItem.h"
|
||||
|
||||
@implementation AtomMenuItem
|
||||
|
||||
@synthesize global = global_, itemPath = path_;
|
||||
|
||||
- initWithTitle:(NSString *)title itemPath:(NSString *)itemPath {
|
||||
self = [super initWithTitle:title action:@selector(performActionForMenuItem:) keyEquivalent:@""];
|
||||
self.itemPath = itemPath;
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
@end
|
||||
@@ -1,13 +0,0 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <JavaScriptCore/JavaScriptCore.h>
|
||||
#import "JSCocoa.h"
|
||||
|
||||
@interface FileSystemHelper : NSObject {
|
||||
JSContextRef _ctx;
|
||||
}
|
||||
|
||||
- (id)initWithJSContextRef:(JSContextRef)ctx;
|
||||
- (void)listFilesAtPath:(NSString *)path recursive:(BOOL)recursive onComplete:(JSValueRefAndContextRef)jsFunction;
|
||||
- (BOOL)isFile:(NSString *)path;
|
||||
|
||||
@end
|
||||
@@ -1,81 +0,0 @@
|
||||
#import "FileSystemHelper.h"
|
||||
|
||||
@interface FileSystemHelper ()
|
||||
- (NSArray *)listFilesAtPath:(NSString *)path recursive:(BOOL)recursive;
|
||||
- (JSValueRef)convertToJSArrayOfStrings:(NSArray *)nsArray;
|
||||
@end
|
||||
|
||||
@implementation FileSystemHelper
|
||||
|
||||
- (id)initWithJSContextRef:(JSContextRef)ctx {
|
||||
self = [super init];
|
||||
_ctx = ctx;
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)listFilesAtPath:(NSString *)path recursive:(BOOL)recursive onComplete:(JSValueRefAndContextRef)onComplete {
|
||||
dispatch_queue_t backgroundQueue = dispatch_get_global_queue(0, 0);
|
||||
dispatch_queue_t mainQueue = dispatch_get_main_queue();
|
||||
|
||||
JSValueRef onCompleteFn = onComplete.value;
|
||||
|
||||
JSValueProtect(_ctx, onCompleteFn);
|
||||
|
||||
dispatch_async(backgroundQueue, ^{
|
||||
NSArray *paths = [self listFilesAtPath:path recursive:recursive];
|
||||
JSValueRef jsPaths = [self convertToJSArrayOfStrings:paths];
|
||||
|
||||
dispatch_sync(mainQueue, ^{
|
||||
JSValueRef args[] = { jsPaths };
|
||||
JSObjectCallAsFunction(_ctx, JSValueToObject(_ctx, onCompleteFn, NULL), NULL, 1, args, NULL);
|
||||
JSValueUnprotect(_ctx, onCompleteFn);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
- (BOOL)isFile:(NSString *)path {
|
||||
BOOL isDir, exists;
|
||||
exists = [[NSFileManager defaultManager] fileExistsAtPath:path isDirectory:&isDir];
|
||||
return exists && !isDir;
|
||||
}
|
||||
|
||||
- (NSArray *)listFilesAtPath:(NSString *)path recursive:(BOOL)recursive {
|
||||
NSFileManager *fm = [NSFileManager defaultManager];
|
||||
NSMutableArray *paths = [NSMutableArray array];
|
||||
|
||||
if (recursive) {
|
||||
for (NSString *subpath in [fm enumeratorAtPath:path]) {
|
||||
[paths addObject:[path stringByAppendingPathComponent:subpath]];
|
||||
}
|
||||
} else {
|
||||
NSError *error = nil;
|
||||
NSArray *subpaths = [fm contentsOfDirectoryAtPath:path error:&error];
|
||||
if (error) {
|
||||
NSLog(@"ERROR %@", error.localizedDescription);
|
||||
return nil;
|
||||
}
|
||||
for (NSString *subpath in subpaths) {
|
||||
[paths addObject:[path stringByAppendingPathComponent:subpath]];
|
||||
}
|
||||
}
|
||||
|
||||
NSMutableArray *filePaths = [NSMutableArray array];
|
||||
for (NSString *path in paths) {
|
||||
if ([self isFile:path]) [filePaths addObject:path];
|
||||
}
|
||||
return filePaths;
|
||||
}
|
||||
|
||||
- (JSValueRef)convertToJSArrayOfStrings:(NSArray *)nsArray {
|
||||
JSValueRef *cArray = malloc(sizeof(JSValueRef) * nsArray.count);
|
||||
for (int i = 0; i < nsArray.count; i++) {
|
||||
JSStringRef jsString = JSStringCreateWithCFString((CFStringRef)[nsArray objectAtIndex:i]);
|
||||
cArray[i] = JSValueMakeString(_ctx, jsString);
|
||||
JSStringRelease(jsString);
|
||||
}
|
||||
JSValueRef jsArray = (JSValueRef)JSObjectMakeArray(_ctx, nsArray.count, cArray, NULL);
|
||||
free(cArray);
|
||||
return jsArray;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<archive type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="7.10">
|
||||
<data>
|
||||
<int key="IBDocument.SystemTarget">1070</int>
|
||||
<int key="IBDocument.SystemTarget">1060</int>
|
||||
<string key="IBDocument.SystemVersion">11C74</string>
|
||||
<string key="IBDocument.InterfaceBuilderVersion">1938</string>
|
||||
<string key="IBDocument.AppKitVersion">1138.23</string>
|
||||
@@ -35,26 +35,24 @@
|
||||
<object class="NSCustomObject" id="1004">
|
||||
<string key="NSClassName">NSApplication</string>
|
||||
</object>
|
||||
<object class="NSWindowTemplate" id="773759719">
|
||||
<object class="NSWindowTemplate" id="1005">
|
||||
<int key="NSWindowStyleMask">15</int>
|
||||
<int key="NSWindowBacking">2</int>
|
||||
<string key="NSWindowRect">{{288, 20}, {725, 723}}</string>
|
||||
<int key="NSWTFlags">1954021376</int>
|
||||
<string key="NSWindowTitle">untitled</string>
|
||||
<string key="NSWindowRect">{{196, 240}, {637, 578}}</string>
|
||||
<int key="NSWTFlags">544735232</int>
|
||||
<string key="NSWindowTitle">Window</string>
|
||||
<string key="NSWindowClass">NSWindow</string>
|
||||
<nil key="NSViewClass"/>
|
||||
<nil key="NSUserInterfaceItemIdentifier"/>
|
||||
<object class="NSView" key="NSWindowView" id="610964987">
|
||||
<object class="NSView" key="NSWindowView" id="1006">
|
||||
<reference key="NSNextResponder"/>
|
||||
<int key="NSvFlags">256</int>
|
||||
<string key="NSFrameSize">{725, 723}</string>
|
||||
<string key="NSFrameSize">{637, 578}</string>
|
||||
<reference key="NSSuperview"/>
|
||||
<reference key="NSWindow"/>
|
||||
<reference key="NSNextKeyView"/>
|
||||
</object>
|
||||
<string key="NSScreenRect">{{0, 0}, {1440, 878}}</string>
|
||||
<string key="NSScreenRect">{{0, 0}, {2560, 1418}}</string>
|
||||
<string key="NSMaxSize">{10000000000000, 10000000000000}</string>
|
||||
<string key="NSFrameAutosaveName">Atomicity</string>
|
||||
<bool key="NSWindowIsRestorable">YES</bool>
|
||||
</object>
|
||||
</object>
|
||||
@@ -65,9 +63,17 @@
|
||||
<object class="IBOutletConnection" key="connection">
|
||||
<string key="label">window</string>
|
||||
<reference key="source" ref="1001"/>
|
||||
<reference key="destination" ref="773759719"/>
|
||||
<reference key="destination" ref="1005"/>
|
||||
</object>
|
||||
<int key="connectionID">7</int>
|
||||
<int key="connectionID">3</int>
|
||||
</object>
|
||||
<object class="IBConnectionRecord">
|
||||
<object class="IBOutletConnection" key="connection">
|
||||
<string key="label">webView</string>
|
||||
<reference key="source" ref="1001"/>
|
||||
<reference key="destination" ref="1006"/>
|
||||
</object>
|
||||
<int key="connectionID">4</int>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBMutableOrderedSet" key="objectRecords">
|
||||
@@ -75,7 +81,7 @@
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">0</int>
|
||||
<object class="NSArray" key="object" id="0">
|
||||
<object class="NSArray" key="object" id="1002">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
</object>
|
||||
<reference key="children" ref="1000"/>
|
||||
@@ -84,37 +90,34 @@
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">-2</int>
|
||||
<reference key="object" ref="1001"/>
|
||||
<reference key="parent" ref="0"/>
|
||||
<reference key="parent" ref="1002"/>
|
||||
<string key="objectName">File's Owner</string>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">-1</int>
|
||||
<reference key="object" ref="1003"/>
|
||||
<reference key="parent" ref="0"/>
|
||||
<reference key="parent" ref="1002"/>
|
||||
<string key="objectName">First Responder</string>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">-3</int>
|
||||
<reference key="object" ref="1004"/>
|
||||
<reference key="parent" ref="0"/>
|
||||
<reference key="parent" ref="1002"/>
|
||||
<string key="objectName">Application</string>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">3</int>
|
||||
<reference key="object" ref="773759719"/>
|
||||
<int key="objectID">1</int>
|
||||
<reference key="object" ref="1005"/>
|
||||
<object class="NSMutableArray" key="children">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<reference ref="610964987"/>
|
||||
<reference ref="1006"/>
|
||||
</object>
|
||||
<reference key="parent" ref="0"/>
|
||||
<reference key="parent" ref="1002"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">4</int>
|
||||
<reference key="object" ref="610964987"/>
|
||||
<object class="NSMutableArray" key="children">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
</object>
|
||||
<reference key="parent" ref="773759719"/>
|
||||
<int key="objectID">2</int>
|
||||
<reference key="object" ref="1006"/>
|
||||
<reference key="parent" ref="1005"/>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
@@ -125,10 +128,10 @@
|
||||
<string>-1.IBPluginDependency</string>
|
||||
<string>-2.IBPluginDependency</string>
|
||||
<string>-3.IBPluginDependency</string>
|
||||
<string>3.IBPluginDependency</string>
|
||||
<string>3.IBWindowTemplateEditedContentRect</string>
|
||||
<string>3.NSWindowTemplate.visibleAtLaunch</string>
|
||||
<string>4.IBPluginDependency</string>
|
||||
<string>1.IBPluginDependency</string>
|
||||
<string>1.IBWindowTemplateEditedContentRect</string>
|
||||
<string>1.NSWindowTemplate.visibleAtLaunch</string>
|
||||
<string>2.IBPluginDependency</string>
|
||||
</object>
|
||||
<object class="NSMutableArray" key="dict.values">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
@@ -136,24 +139,24 @@
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string>{{324, 121}, {725, 723}}</string>
|
||||
<string>{{357, 418}, {480, 270}}</string>
|
||||
<integer value="1"/>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="NSMutableDictionary" key="unlocalizedProperties">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<reference key="dict.sortedKeys" ref="0"/>
|
||||
<reference key="dict.values" ref="0"/>
|
||||
<reference key="dict.sortedKeys" ref="1002"/>
|
||||
<reference key="dict.values" ref="1002"/>
|
||||
</object>
|
||||
<nil key="activeLocalization"/>
|
||||
<object class="NSMutableDictionary" key="localizations">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<reference key="dict.sortedKeys" ref="0"/>
|
||||
<reference key="dict.values" ref="0"/>
|
||||
<reference key="dict.sortedKeys" ref="1002"/>
|
||||
<reference key="dict.values" ref="1002"/>
|
||||
</object>
|
||||
<nil key="sourceID"/>
|
||||
<int key="maxID">7</int>
|
||||
<int key="maxID">4</int>
|
||||
</object>
|
||||
<object class="IBClassDescriber" key="IBDocument.Classes">
|
||||
<object class="NSMutableArray" key="referencedPartialClassDescriptions">
|
||||
@@ -161,6 +164,17 @@
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">AtomController</string>
|
||||
<string key="superclassName">NSWindowController</string>
|
||||
<object class="NSMutableDictionary" key="outlets">
|
||||
<string key="NS.key.0">webView</string>
|
||||
<string key="NS.object.0">NSView</string>
|
||||
</object>
|
||||
<object class="NSMutableDictionary" key="toOneOutletInfosByName">
|
||||
<string key="NS.key.0">webView</string>
|
||||
<object class="IBToOneOutletInfo" key="NS.object.0">
|
||||
<string key="name">webView</string>
|
||||
<string key="candidateClassName">NSView</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBProjectSource</string>
|
||||
<string key="minorKey">./Classes/AtomController.h</string>
|
||||
@@ -170,6 +184,10 @@
|
||||
</object>
|
||||
<int key="IBDocument.localizationMode">0</int>
|
||||
<string key="IBDocument.TargetRuntimeIdentifier">IBCocoaFramework</string>
|
||||
<object class="NSMutableDictionary" key="IBDocument.PluginDeclaredDependencyDefaults">
|
||||
<string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin.macosx</string>
|
||||
<real value="1060" key="NS.object.0"/>
|
||||
</object>
|
||||
<object class="NSMutableDictionary" key="IBDocument.PluginDeclaredDevelopmentDependencies">
|
||||
<string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin.InterfaceBuilder3</string>
|
||||
<integer value="3000" key="NS.object.0"/>
|
||||
BIN
Atom/Icon.icns
16
Atom/Atom-Info.plist → Atom/Info.plist
Normal file → Executable file
@@ -3,32 +3,26 @@
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>en</string>
|
||||
<string>English</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>${EXECUTABLE_NAME}</string>
|
||||
<key>CFBundleIconFile</key>
|
||||
<string>Icon.icns</string>
|
||||
<string>Atom</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>GitHub.${PRODUCT_NAME:rfc1034identifier}</string>
|
||||
<string>org.cef.cefclient</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>${PRODUCT_NAME}</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
<string>${MACOSX_DEPLOYMENT_TARGET}</string>
|
||||
<key>NSHumanReadableCopyright</key>
|
||||
<string>Copyright © 2011 __MyCompanyName__. All rights reserved.</string>
|
||||
<string>1.0</string>
|
||||
<key>NSMainNibFile</key>
|
||||
<string>MainMenu</string>
|
||||
<key>NSPrincipalClass</key>
|
||||
<string>AtomApp</string>
|
||||
<string>Atom</string>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -1,43 +0,0 @@
|
||||
//
|
||||
// BridgeSupportController.h
|
||||
// JSCocoa
|
||||
//
|
||||
// Created by Patrick Geiller on 08/07/08.
|
||||
// Copyright 2008 __MyCompanyName__. All rights reserved.
|
||||
//
|
||||
|
||||
#if !TARGET_IPHONE_SIMULATOR && !TARGET_OS_IPHONE
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#endif
|
||||
|
||||
@interface BridgeSupportController : NSObject {
|
||||
|
||||
|
||||
NSMutableArray* paths;
|
||||
NSMutableArray* xmlDocuments;
|
||||
|
||||
NSMutableDictionary* hash;
|
||||
NSMutableDictionary* variadicSelectors;
|
||||
NSMutableDictionary* variadicFunctions;
|
||||
}
|
||||
|
||||
+ (id)sharedController;
|
||||
|
||||
- (BOOL)loadBridgeSupport:(NSString*)path;
|
||||
- (BOOL)isBridgeSupportLoaded:(NSString*)path;
|
||||
- (NSUInteger)bridgeSupportIndexForString:(NSString*)string;
|
||||
|
||||
- (NSMutableDictionary*)variadicSelectors;
|
||||
- (NSMutableDictionary*)variadicFunctions;
|
||||
|
||||
/*
|
||||
- (NSString*)query:(NSString*)name withType:(NSString*)type;
|
||||
- (NSString*)query:(NSString*)name withType:(NSString*)type inBridgeSupportFile:(NSString*)file;
|
||||
*/
|
||||
- (NSString*)queryName:(NSString*)name;
|
||||
- (NSString*)queryName:(NSString*)name type:(NSString*)type;
|
||||
|
||||
- (NSArray*)keys;
|
||||
|
||||
|
||||
@end
|
||||
@@ -1,254 +0,0 @@
|
||||
//
|
||||
// BridgeSupportController.m
|
||||
// JSCocoa
|
||||
//
|
||||
// Created by Patrick Geiller on 08/07/08.
|
||||
// Copyright 2008 __MyCompanyName__. All rights reserved.
|
||||
//
|
||||
|
||||
#import "BridgeSupportController.h"
|
||||
|
||||
|
||||
@implementation BridgeSupportController
|
||||
|
||||
|
||||
+ (id)sharedController
|
||||
{
|
||||
static id singleton;
|
||||
@synchronized(self)
|
||||
{
|
||||
if (!singleton)
|
||||
singleton = [[BridgeSupportController alloc] init];
|
||||
return singleton;
|
||||
}
|
||||
return singleton;
|
||||
}
|
||||
|
||||
- (id)init
|
||||
{
|
||||
self = [super init];
|
||||
|
||||
paths = [[NSMutableArray alloc] init];
|
||||
xmlDocuments = [[NSMutableArray alloc] init];
|
||||
hash = [[NSMutableDictionary alloc] init];
|
||||
variadicSelectors = [[NSMutableDictionary alloc] init];
|
||||
variadicFunctions = [[NSMutableDictionary alloc] init];
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[variadicFunctions release];
|
||||
[variadicSelectors release];
|
||||
[hash release];
|
||||
[paths release];
|
||||
[xmlDocuments release];
|
||||
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
//
|
||||
// Load a bridgeSupport file into a hash as { name : xmlTagString }
|
||||
//
|
||||
- (BOOL)loadBridgeSupport:(NSString*)path
|
||||
{
|
||||
NSError* error = nil;
|
||||
/*
|
||||
Adhoc parser
|
||||
NSXMLDocument is too slow
|
||||
loading xml document as string then querying on-demand is too slow
|
||||
can't get CFXMLParserRef to work
|
||||
don't wan't to delve into expat
|
||||
-> ad hoc : load file, build a hash of { name : xmlTagString }
|
||||
*/
|
||||
NSString* xmlDocument = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:&error];
|
||||
if (error) return NSLog(@"loadBridgeSupport : %@", error), NO;
|
||||
|
||||
char* c = (char*)[xmlDocument UTF8String];
|
||||
#ifdef __OBJC_GC__
|
||||
char* originalC = c;
|
||||
[[NSGarbageCollector defaultCollector] disableCollectorForPointer:originalC];
|
||||
#endif
|
||||
|
||||
// double t0 = CFAbsoluteTimeGetCurrent();
|
||||
// Start parsing
|
||||
for (; *c; c++)
|
||||
{
|
||||
if (*c == '<')
|
||||
{
|
||||
char startTagChar = c[1];
|
||||
if (startTagChar == 0) return NO;
|
||||
|
||||
// 'co' constant
|
||||
// 'cl' class
|
||||
// 'e' enum
|
||||
// 'fu' function
|
||||
// 'st' struct
|
||||
if ((c[1] == 'c' && (c[2] == 'o' || c[2] == 'l')) || c[1] == 'e' || (c[1] == 'f' && c[2] == 'u') || (c[1] == 's' && c[2] == 't'))
|
||||
{
|
||||
// Extract name
|
||||
char* tagStart = c;
|
||||
for (; *c && *c != '\''; c++);
|
||||
c++;
|
||||
char* c0 = c;
|
||||
for (; *c && *c != '\''; c++);
|
||||
|
||||
id name = [[NSString alloc] initWithBytes:c0 length:c-c0 encoding:NSUTF8StringEncoding];
|
||||
|
||||
// Move to tag end
|
||||
BOOL foundEndTag = NO;
|
||||
BOOL foundOpenTag = NO;
|
||||
c++;
|
||||
for (; *c && !foundEndTag; c++)
|
||||
{
|
||||
if (*c == '<') foundOpenTag = YES;
|
||||
else
|
||||
if (*c == '/')
|
||||
{
|
||||
if (!foundOpenTag)
|
||||
{
|
||||
if(c[1] == '>') foundEndTag = YES, c++;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (startTagChar == c[1])
|
||||
{
|
||||
foundEndTag = YES;
|
||||
// Skip to end of tag
|
||||
for (; *c && *c != '>'; c++);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
// Variadic parsing
|
||||
if (c[0] == 'v' && c[1] == 'a' && c[2] == 'r')
|
||||
{
|
||||
if (strncmp(c, "variadic", 8) == 0)
|
||||
{
|
||||
// Skip back to tag start
|
||||
c0 = c;
|
||||
for (; *c0 != '<'; c0--);
|
||||
|
||||
// Tag name starts with 'm' : variadic method
|
||||
// <method variadic='true' selector='alertWithMessageText:defaultButton:alternateButton:otherButton:informativeTextWithFormat:' class_method='true'>
|
||||
if (c0[1] == 'm')
|
||||
{
|
||||
c = c0;
|
||||
id variadicMethodName = nil;
|
||||
// Extract selector name
|
||||
for (; *c != '>'; c++)
|
||||
{
|
||||
if (c[0] == ' ' && c[1] == 's' && c[2] == 'e' && c[3] == 'l')
|
||||
{
|
||||
for (; *c && *c != '\''; c++);
|
||||
c++;
|
||||
c0 = c;
|
||||
for (; *c && *c != '\''; c++);
|
||||
variadicMethodName = [[[NSString alloc] initWithBytes:c0 length:c-c0 encoding:NSUTF8StringEncoding] autorelease];
|
||||
}
|
||||
}
|
||||
[variadicSelectors setValue:@"true" forKey:variadicMethodName];
|
||||
// NSLog(@"SELECTOR %@", name);
|
||||
}
|
||||
else
|
||||
// Variadic function
|
||||
// <function name='NSBeginAlertSheet' variadic='true'>
|
||||
{
|
||||
[variadicFunctions setValue:@"true" forKey:name];
|
||||
// NSLog(@"function %@", name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
c0 = tagStart;
|
||||
id value = [[NSString alloc] initWithBytes:c0 length:c-c0 encoding:NSUTF8StringEncoding];
|
||||
|
||||
[hash setValue:value forKey:name];
|
||||
[value release];
|
||||
[name release];
|
||||
}
|
||||
}
|
||||
}
|
||||
// double t1 = CFAbsoluteTimeGetCurrent();
|
||||
// NSLog(@"BridgeSupport %@ parsed in %f", [[path lastPathComponent] stringByDeletingPathExtension], t1-t0);
|
||||
#ifdef __OBJC_GC__
|
||||
[[NSGarbageCollector defaultCollector] enableCollectorForPointer:originalC];
|
||||
#endif
|
||||
[paths addObject:path];
|
||||
[xmlDocuments addObject:xmlDocument];
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
|
||||
- (BOOL)isBridgeSupportLoaded:(NSString*)path
|
||||
{
|
||||
NSUInteger idx = [self bridgeSupportIndexForString:path];
|
||||
return idx == NSNotFound ? NO : YES;
|
||||
}
|
||||
|
||||
//
|
||||
// bridgeSupportIndexForString
|
||||
// given 'AppKit', return index of '/System/Library/Frameworks/AppKit.framework/Versions/C/Resources/BridgeSupport/AppKitFull.bridgesupport'
|
||||
//
|
||||
- (NSUInteger)bridgeSupportIndexForString:(NSString*)string
|
||||
{
|
||||
NSUInteger i, l = [paths count];
|
||||
for (i=0; i<l; i++)
|
||||
{
|
||||
NSString* path = [paths objectAtIndex:i];
|
||||
NSRange range = [path rangeOfString:string];
|
||||
|
||||
if (range.location != NSNotFound) return range.location;
|
||||
}
|
||||
return NSNotFound;
|
||||
}
|
||||
|
||||
- (NSMutableDictionary*)variadicSelectors
|
||||
{
|
||||
return variadicSelectors;
|
||||
}
|
||||
|
||||
- (NSMutableDictionary*)variadicFunctions
|
||||
{
|
||||
return variadicFunctions;
|
||||
}
|
||||
|
||||
- (NSArray*)keys
|
||||
{
|
||||
[hash removeObjectForKey:@"NSProxy"];
|
||||
[hash removeObjectForKey:@"NSProtocolChecker"];
|
||||
[hash removeObjectForKey:@"NSDistantObject"];
|
||||
|
||||
return [hash allKeys];
|
||||
}
|
||||
|
||||
|
||||
- (NSString*)queryName:(NSString*)name
|
||||
{
|
||||
return [hash valueForKey:name];
|
||||
}
|
||||
- (NSString*)queryName:(NSString*)name type:(NSString*)type
|
||||
{
|
||||
id v = [self queryName:name];
|
||||
if (!v) return nil;
|
||||
|
||||
char* c = (char*)[v UTF8String];
|
||||
// Skip tag start
|
||||
c++;
|
||||
char* c0 = c;
|
||||
for (; *c && *c != ' '; c++);
|
||||
id extractedType = [[NSString alloc] initWithBytes:c0 length:c-c0 encoding:NSUTF8StringEncoding];
|
||||
[extractedType autorelease];
|
||||
// NSLog(@"extractedType=%@", extractedType);
|
||||
|
||||
if (![extractedType isEqualToString:type]) return nil;
|
||||
return v;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
//
|
||||
// JSCocoa.h
|
||||
// JSCocoa
|
||||
//
|
||||
// Created by Patrick Geiller on 16/12/08.
|
||||
// Copyright 2008 __MyCompanyName__. All rights reserved.
|
||||
//
|
||||
|
||||
|
||||
#define JSCOCOA
|
||||
#import "JSCocoaController.h"
|
||||
@@ -1,359 +0,0 @@
|
||||
//
|
||||
// JSCocoa.h
|
||||
// JSCocoa
|
||||
//
|
||||
// Created by Patrick Geiller on 09/07/08.
|
||||
// Copyright 2008 __MyCompanyName__. All rights reserved.
|
||||
//
|
||||
#if !TARGET_IPHONE_SIMULATOR && !TARGET_OS_IPHONE
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import <JavaScriptCore/JavaScriptCore.h>
|
||||
#define MACOSX
|
||||
#import <ffi/ffi.h>
|
||||
#endif
|
||||
#import "BridgeSupportController.h"
|
||||
#import "JSCocoaPrivateObject.h"
|
||||
#import "JSCocoaFFIArgument.h"
|
||||
#import "JSCocoaFFIClosure.h"
|
||||
|
||||
|
||||
// JS value container, used by methods wanting a straight JSValue and not a converted JS->ObjC value.
|
||||
struct JSValueRefAndContextRef
|
||||
{
|
||||
JSValueRef value;
|
||||
JSContextRef ctx;
|
||||
};
|
||||
typedef struct JSValueRefAndContextRef JSValueRefAndContextRef;
|
||||
|
||||
#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
|
||||
#import "iPhone/libffi/ffi.h"
|
||||
#import "iPhone/BurksPool.h"
|
||||
#endif
|
||||
|
||||
|
||||
//
|
||||
// JSCocoaController
|
||||
//
|
||||
@interface JSCocoaController : NSObject {
|
||||
|
||||
JSGlobalContextRef ctx;
|
||||
BOOL ownsContext;
|
||||
id _delegate;
|
||||
|
||||
//
|
||||
// Split call
|
||||
// Allows calling multi param ObjC messages with a jQuery-like syntax.
|
||||
//
|
||||
// obj.do({ this : 'hello', andThat : 'world' })
|
||||
// instead of
|
||||
// obj.dothis_andThat_('hello', 'world')
|
||||
//
|
||||
BOOL useSplitCall;
|
||||
|
||||
// JSLint : used for ObjJ syntax, class syntax, return if
|
||||
BOOL useJSLint;
|
||||
|
||||
// Auto call zero arg methods : allow NSWorkspace.sharedWorkspace instead of NSWorkspace.sharedWorkspace()
|
||||
BOOL useAutoCall;
|
||||
// Allow setting javascript values on boxed objects (which are collected after nulling all references to them)
|
||||
BOOL canSetOnBoxedObjects;
|
||||
// Allow calling obj.method(...) instead of obj.method_(...)
|
||||
BOOL callSelectorsMissingTrailingSemicolon;
|
||||
|
||||
// Log all exceptions to NSLog, even if they're caught later by downstream Javascript (in f(g()), log even if f catches after g threw)
|
||||
BOOL logAllExceptions;
|
||||
|
||||
//
|
||||
// Safe dealloc (For ObjC classes written in Javascript)
|
||||
// - (void)dealloc cannot be overloaded as it is called during JS GC, which forbids new JS code execution.
|
||||
// As the js dealloc method cannot be called, safe dealloc allows it to be executed during the next run loop cycle
|
||||
// NOTE : upon destroying a JSCocoaController, safe dealloc is disabled
|
||||
//
|
||||
BOOL useSafeDealloc;
|
||||
|
||||
|
||||
NSMutableDictionary* boxedObjects;
|
||||
|
||||
|
||||
}
|
||||
|
||||
@property (assign) id delegate;
|
||||
@property BOOL useSafeDealloc, useSplitCall, useJSLint, useAutoCall, callSelectorsMissingTrailingSemicolon, canSetOnBoxedObjects, logAllExceptions;
|
||||
|
||||
|
||||
- (id)init;
|
||||
- (id)initWithGlobalContext:(JSGlobalContextRef)ctx;
|
||||
|
||||
+ (id)sharedController;
|
||||
+ (id)controllerFromContext:(JSContextRef)ctx;
|
||||
+ (BOOL)hasSharedController;
|
||||
- (JSGlobalContextRef)ctx;
|
||||
+ (void)hazardReport;
|
||||
+ (NSString*)runningArchitecture;
|
||||
+ (void)updateCustomCallPaths;
|
||||
- (void)accomodateWebKitInspector;
|
||||
|
||||
//
|
||||
// Evaluation
|
||||
//
|
||||
- (id)eval:(NSString*)script;
|
||||
- (id)callFunction:(NSString*)name;
|
||||
- (id)callFunction:(NSString*)name withArguments:(NSArray*)arguments;
|
||||
- (BOOL)hasFunction:(NSString*)name;
|
||||
- (BOOL)isSyntaxValid:(NSString*)script;
|
||||
|
||||
- (BOOL)evalJSFile:(NSString*)path;
|
||||
- (BOOL)evalJSFile:(NSString*)path toJSValueRef:(JSValueRef*)returnValue;
|
||||
- (JSValueRef)evalJSString:(NSString*)script;
|
||||
- (JSValueRef)evalJSString:(NSString*)script withScriptPath:(NSString*)path;
|
||||
- (JSValueRef)callJSFunction:(JSValueRef)function withArguments:(NSArray*)arguments;
|
||||
- (JSValueRef)callJSFunctionNamed:(NSString*)functionName withArguments:arguments, ... NS_REQUIRES_NIL_TERMINATION;
|
||||
- (JSValueRef)callJSFunctionNamed:(NSString*)functionName withArgumentsArray:(NSArray*)arguments;
|
||||
- (JSObjectRef)JSFunctionNamed:(NSString*)functionName;
|
||||
- (BOOL)hasJSFunctionNamed:(NSString*)functionName;
|
||||
- (NSString*)expandJSMacros:(NSString*)script path:(NSString*)path;
|
||||
- (NSString*)expandJSMacros:(NSString*)script path:(NSString*)path errors:(NSMutableArray*)array;
|
||||
- (BOOL)isSyntaxValid:(NSString*)script error:(NSString**)error;
|
||||
- (BOOL)setObject:(id)object withName:(NSString*)name;
|
||||
- (BOOL)setObject:(id)object withName:(NSString*)name attributes:(JSPropertyAttributes)attributes;
|
||||
- (BOOL)setObjectNoRetain:(id)object withName:(NSString*)name attributes:(JSPropertyAttributes)attributes;
|
||||
- (id)objectWithName:(NSString*)name;
|
||||
- (BOOL)removeObjectWithName:(NSString*)name;
|
||||
// Get ObjC and raw values from Javascript
|
||||
- (id)unboxJSValueRef:(JSValueRef)jsValue;
|
||||
- (BOOL)toBool:(JSValueRef)value;
|
||||
- (double)toDouble:(JSValueRef)value;
|
||||
- (int)toInt:(JSValueRef)value;
|
||||
- (NSString*)toString:(JSValueRef)value;
|
||||
// Wrapper for unboxJSValueRef
|
||||
- (id)toObject:(JSValueRef)value;
|
||||
|
||||
|
||||
//
|
||||
// Framework
|
||||
//
|
||||
- (BOOL)loadFrameworkWithName:(NSString*)name;
|
||||
- (BOOL)loadFrameworkWithName:(NSString*)frameworkName inPath:(NSString*)path;
|
||||
|
||||
//
|
||||
// Garbage collection
|
||||
//
|
||||
+ (void)garbageCollect;
|
||||
- (void)garbageCollect;
|
||||
- (void)unlinkAllReferences;
|
||||
+ (void)upJSCocoaPrivateObjectCount;
|
||||
+ (void)downJSCocoaPrivateObjectCount;
|
||||
+ (int)JSCocoaPrivateObjectCount;
|
||||
|
||||
+ (void)upJSValueProtectCount;
|
||||
+ (void)downJSValueProtectCount;
|
||||
+ (int)JSValueProtectCount;
|
||||
|
||||
+ (void)logInstanceStats;
|
||||
- (id)instanceStats;
|
||||
- (void)logBoxedObjects;
|
||||
|
||||
//
|
||||
// Class inspection (shortcuts to JSCocoaLib)
|
||||
//
|
||||
+ (id)rootclasses;
|
||||
+ (id)classes;
|
||||
+ (id)protocols;
|
||||
+ (id)imageNames;
|
||||
+ (id)methods;
|
||||
+ (id)runtimeReport;
|
||||
+ (id)explainMethodEncoding:(id)encoding;
|
||||
|
||||
//
|
||||
// Class handling
|
||||
//
|
||||
+ (BOOL)overloadInstanceMethod:(NSString*)methodName class:(Class)class jsFunction:(JSValueRefAndContextRef)valueAndContext;
|
||||
+ (BOOL)overloadClassMethod:(NSString*)methodName class:(Class)class jsFunction:(JSValueRefAndContextRef)valueAndContext;
|
||||
|
||||
+ (BOOL)addClassMethod:(NSString*)methodName class:(Class)class jsFunction:(JSValueRefAndContextRef)valueAndContext encoding:(char*)encoding;
|
||||
+ (BOOL)addInstanceMethod:(NSString*)methodName class:(Class)class jsFunction:(JSValueRefAndContextRef)valueAndContext encoding:(char*)encoding;
|
||||
|
||||
// Tests
|
||||
- (int)runTests:(NSString*)path;
|
||||
- (int)runTests:(NSString*)path withSelector:(SEL)sel;
|
||||
|
||||
//
|
||||
// Autorelease pool
|
||||
//
|
||||
+ (void)allocAutoreleasePool;
|
||||
+ (void)deallocAutoreleasePool;
|
||||
|
||||
//
|
||||
// Boxing : each object gets only one box, stored in boxedObjects
|
||||
//
|
||||
//+ (JSObjectRef)boxedJSObject:(id)o inContext:(JSContextRef)ctx;
|
||||
- (JSObjectRef)boxObject:(id)o;
|
||||
- (BOOL)isObjectBoxed:(id)o;
|
||||
- (void)deleteBoxOfObject:(id)o;
|
||||
//+ (void)downBoxedJSObjectCount:(id)o;
|
||||
|
||||
|
||||
//
|
||||
// Various internals
|
||||
//
|
||||
//+ (JSObjectRef)jsCocoaPrivateObjectInContext:(JSContextRef)ctx;
|
||||
- (JSObjectRef)newPrivateObject;
|
||||
- (JSObjectRef)newPrivateFunction;
|
||||
+ (NSMutableArray*)parseObjCMethodEncoding:(const char*)typeEncoding;
|
||||
+ (NSMutableArray*)parseCFunctionEncoding:(NSString*)xml functionName:(NSString**)functionNamePlaceHolder;
|
||||
|
||||
//+ (void)ensureJSValueIsObjectAfterInstanceAutocall:(JSValueRef)value inContext:(JSContextRef)ctx;
|
||||
- (NSString*)formatJSException:(JSValueRef)exception;
|
||||
- (id)selectorForJSFunction:(JSObjectRef)function;
|
||||
|
||||
|
||||
- (const char*)typeEncodingOfMethod:(NSString*)methodName class:(NSString*)className;
|
||||
+ (const char*)typeEncodingOfMethod:(NSString*)methodName class:(NSString*)className;
|
||||
|
||||
|
||||
|
||||
@end
|
||||
|
||||
|
||||
//
|
||||
// JSCocoa delegate methods
|
||||
//
|
||||
|
||||
//
|
||||
// Error reporting
|
||||
//
|
||||
@interface NSObject (JSCocoaControllerDelegateMethods)
|
||||
- (void) JSCocoa:(JSCocoaController*)controller hadError:(NSString*)error onLineNumber:(NSInteger)lineNumber atSourceURL:(id)url;
|
||||
- (void) safeDealloc;
|
||||
|
||||
//
|
||||
// Getting
|
||||
//
|
||||
// Check if getting property is allowed
|
||||
- (BOOL) JSCocoa:(JSCocoaController*)controller canGetProperty:(NSString*)propertyName ofObject:(id)object inContext:(JSContextRef)ctx exception:(JSValueRef*)exception;
|
||||
// Custom handler for getting properties
|
||||
// Return a custom JSValueRef to bypass JSCocoa
|
||||
// Return NULL to let JSCocoa handle getProperty
|
||||
// Return JSValueMakeNull() to return a Javascript null
|
||||
- (JSValueRef) JSCocoa:(JSCocoaController*)controller getProperty:(NSString*)propertyName ofObject:(id)object inContext:(JSContextRef)ctx exception:(JSValueRef*)exception;
|
||||
|
||||
//
|
||||
// Setting
|
||||
//
|
||||
// Check if setting property is allowed
|
||||
- (BOOL) JSCocoa:(JSCocoaController*)controller canSetProperty:(NSString*)propertyName ofObject:(id)object toValue:(JSValueRef)value inContext:(JSContextRef)ctx exception:(JSValueRef*)exception;
|
||||
// Custom handler for setting properties
|
||||
// Return YES to indicate you handled setting
|
||||
// Return NO to let JSCocoa handle setProperty
|
||||
- (BOOL) JSCocoa:(JSCocoaController*)controller setProperty:(NSString*)propertyName ofObject:(id)object toValue:(JSValueRef)value inContext:(JSContextRef)ctx exception:(JSValueRef*)exception;
|
||||
|
||||
//
|
||||
// Calling
|
||||
//
|
||||
// Check if calling a C function is allowed
|
||||
- (BOOL) JSCocoa:(JSCocoaController*)controller canCallFunction:(NSString*)functionName argumentCount:(size_t)argumentCount arguments:(JSValueRef*)arguments inContext:(JSContextRef)ctx exception:(JSValueRef*)exception;
|
||||
// Check if calling an ObjC method is allowed
|
||||
- (BOOL) JSCocoa:(JSCocoaController*)controller canCallMethod:(NSString*)methodName ofObject:(id)object argumentCount:(size_t)argumentCount arguments:(JSValueRef*)arguments inContext:(JSContextRef)ctx exception:(JSValueRef*)exception;
|
||||
// Custom handler for calling
|
||||
// Return YES to indicate you handled calling
|
||||
// Return NO to let JSCocoa handle calling
|
||||
- (JSValueRef) JSCocoa:(JSCocoaController*)controller callMethod:(NSString*)methodName ofObject:(id)callee privateObject:(JSCocoaPrivateObject*)thisPrivateObject argumentCount:(size_t)argumentCount arguments:(JSValueRef*)arguments inContext:(JSContextRef)localCtx exception:(JSValueRef*)exception;
|
||||
|
||||
//
|
||||
// Getting global properties (classes, structures, C function names, enums via OSXObject_getProperty)
|
||||
//
|
||||
// Check if getting property is allowed
|
||||
- (BOOL) JSCocoa:(JSCocoaController*)controller canGetGlobalProperty:(NSString*)propertyName inContext:(JSContextRef)ctx exception:(JSValueRef*)exception;
|
||||
// Custom handler for getting properties
|
||||
// Return a custom JSValueRef to bypass JSCocoa
|
||||
// Return NULL to let JSCocoa handle getProperty
|
||||
// Return JSValueMakeNull() to return a Javascript null
|
||||
- (JSValueRef) JSCocoa:(JSCocoaController*)controller getGlobalProperty:(NSString*)propertyName inContext:(JSContextRef)ctx exception:(JSValueRef*)exception;
|
||||
|
||||
//
|
||||
// Returning values to Javascript
|
||||
//
|
||||
// Called before returning any value to Javascript : return a new value or the original one
|
||||
//- (JSValueRef) JSCocoa:(JSCocoaController*)controller willReturnValue:(JSValueRef)value inContext:(JSContextRef)ctx exception:(JSValueRef*)exception;
|
||||
|
||||
//
|
||||
// Evaling
|
||||
//
|
||||
// Check if file can be loaded
|
||||
- (BOOL)JSCocoa:(JSCocoaController*)controller canLoadJSFile:(NSString*)path;
|
||||
// Check if script can be evaluated
|
||||
- (BOOL)JSCocoa:(JSCocoaController*)controller canEvaluateScript:(NSString*)script;
|
||||
// Called before evalJSString, used to modify script about to be evaluated
|
||||
// Return a custom NSString (eg a macro expanded version of the source)
|
||||
// Return NULL to let JSCocoa handle evaluation
|
||||
- (NSString*)JSCocoa:(JSCocoaController*)controller willEvaluateScript:(NSString*)script;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
//
|
||||
// JSCocoa shorthand
|
||||
//
|
||||
@interface JSCocoa : JSCocoaController
|
||||
@end
|
||||
|
||||
//
|
||||
// Boxed object cache : holds one JSObjectRef for each reference to a pointer to an ObjC object
|
||||
//
|
||||
@interface BoxedJSObject : NSObject {
|
||||
JSObjectRef jsObject;
|
||||
}
|
||||
- (void)setJSObject:(JSObjectRef)o;
|
||||
- (JSObjectRef)jsObject;
|
||||
|
||||
@end
|
||||
|
||||
//
|
||||
// Helpers
|
||||
//
|
||||
id NSStringFromJSValue(JSContextRef ctx, JSValueRef value);
|
||||
//void* malloc_autorelease(size_t size);
|
||||
|
||||
// Convert values between contexts (eg user context and webkit page context)
|
||||
JSValueRef valueToExternalContext(JSContextRef ctx, JSValueRef value, JSContextRef externalCtx);
|
||||
|
||||
// valueOf() is called by Javascript on objects, eg someObject + ' someString'
|
||||
JSValueRef valueOfCallback(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef *exception);
|
||||
|
||||
//
|
||||
// From PyObjC : when to call objc_msgSend_stret, for structure return
|
||||
// Depending on structure size & architecture, structures are returned as function first argument (done transparently by ffi) or via registers
|
||||
//
|
||||
|
||||
#if defined(__ppc__)
|
||||
# define SMALL_STRUCT_LIMIT 4
|
||||
#elif defined(__ppc64__)
|
||||
# define SMALL_STRUCT_LIMIT 8
|
||||
#elif defined(__i386__)
|
||||
# define SMALL_STRUCT_LIMIT 8
|
||||
#elif defined(__x86_64__)
|
||||
# define SMALL_STRUCT_LIMIT 16
|
||||
#elif TARGET_OS_IPHONE
|
||||
// TOCHECK
|
||||
# define SMALL_STRUCT_LIMIT 4
|
||||
#else
|
||||
# error "Unsupported MACOSX platform"
|
||||
#endif
|
||||
|
||||
|
||||
// Stored in boxedobjects to access a list of methods, properties, ...
|
||||
#define RuntimeInformationPropertyName "info"
|
||||
|
||||
|
||||
|
||||
/*
|
||||
Some more doc
|
||||
|
||||
__jsHash
|
||||
__jsCocoaController
|
||||
Instance variables set on ObjC classes written in Javascript.
|
||||
These variables enable classes to store Javascript values in them.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
@@ -1,97 +0,0 @@
|
||||
//
|
||||
// JSCocoaFFIArgument.h
|
||||
// JSCocoa
|
||||
//
|
||||
// Created by Patrick Geiller on 14/07/08.
|
||||
// Copyright 2008 __MyCompanyName__. All rights reserved.
|
||||
//
|
||||
|
||||
#if !TARGET_IPHONE_SIMULATOR && !TARGET_OS_IPHONE
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import <JavaScriptCore/JavaScriptCore.h>
|
||||
#define MACOSX
|
||||
#include <ffi/ffi.h>
|
||||
#endif
|
||||
#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
|
||||
#import "iPhone/libffi/ffi.h"
|
||||
#endif
|
||||
|
||||
@interface JSCocoaFFIArgument : NSObject {
|
||||
char typeEncoding;
|
||||
NSString* structureTypeEncoding;
|
||||
NSString* pointerTypeEncoding;
|
||||
|
||||
void* ptr;
|
||||
|
||||
ffi_type structureType;
|
||||
|
||||
id customData;
|
||||
BOOL isReturnValue;
|
||||
BOOL ownsStorage;
|
||||
BOOL isOutArgument;
|
||||
}
|
||||
|
||||
- (NSString*)typeDescription;
|
||||
|
||||
- (BOOL)setTypeEncoding:(char)encoding;
|
||||
- (BOOL)setTypeEncoding:(char)encoding withCustomStorage:(void*)storagePtr;
|
||||
- (void)setStructureTypeEncoding:(NSString*)encoding;
|
||||
- (void)setStructureTypeEncoding:(NSString*)encoding withCustomStorage:(void*)storagePtr;
|
||||
- (void)setPointerTypeEncoding:(NSString*)encoding;
|
||||
|
||||
+ (int)sizeOfTypeEncoding:(char)encoding;
|
||||
+ (int)alignmentOfTypeEncoding:(char)encoding;
|
||||
|
||||
+ (ffi_type*)ffi_typeForTypeEncoding:(char)encoding;
|
||||
|
||||
+ (int)sizeOfStructure:(NSString*)encoding;
|
||||
|
||||
|
||||
+ (NSArray*)typeEncodingsFromStructureTypeEncoding:(NSString*)structureTypeEncoding;
|
||||
+ (NSArray*)typeEncodingsFromStructureTypeEncoding:(NSString*)structureTypeEncoding parsedCount:(NSInteger*)count;
|
||||
|
||||
|
||||
+ (NSString*)structureNameFromStructureTypeEncoding:(NSString*)structureTypeEncoding;
|
||||
+ (NSString*)structureFullTypeEncodingFromStructureTypeEncoding:(NSString*)structureTypeEncoding;
|
||||
+ (NSString*)structureFullTypeEncodingFromStructureName:(NSString*)structureName;
|
||||
+ (NSString*)structureTypeEncodingDescription:(NSString*)structureTypeEncoding;
|
||||
|
||||
+ (BOOL)fromJSValueRef:(JSValueRef)value inContext:(JSContextRef)ctx typeEncoding:(char)typeEncoding fullTypeEncoding:(NSString*)fullTypeEncoding fromStorage:(void*)ptr;
|
||||
|
||||
+ (BOOL)toJSValueRef:(JSValueRef*)value inContext:(JSContextRef)ctx typeEncoding:(char)typeEncoding fullTypeEncoding:(NSString*)fullTypeEncoding fromStorage:(void*)ptr;
|
||||
|
||||
+ (NSInteger)structureToJSValueRef:(JSValueRef*)value inContext:(JSContextRef)ctx fromCString:(char*)c fromStorage:(void**)storage;
|
||||
+ (NSInteger)structureToJSValueRef:(JSValueRef*)value inContext:(JSContextRef)ctx fromCString:(char*)c fromStorage:(void**)ptr initialValues:(JSValueRef*)initialValues initialValueCount:(NSInteger)initialValueCount convertedValueCount:(NSInteger*)convertedValueCount;
|
||||
+ (NSInteger)structureFromJSObjectRef:(JSObjectRef)value inContext:(JSContextRef)ctx inParentJSValueRef:(JSValueRef)parentValue fromCString:(char*)c fromStorage:(void**)ptr;
|
||||
|
||||
+ (void)alignPtr:(void**)ptr accordingToEncoding:(char)encoding;
|
||||
+ (void)advancePtr:(void**)ptr accordingToEncoding:(char)encoding;
|
||||
|
||||
|
||||
- (void*)allocateStorage;
|
||||
- (void*)allocatePointerStorage;
|
||||
- (void**)storage;
|
||||
- (void**)rawStoragePointer;
|
||||
- (char)typeEncoding;
|
||||
- (NSString*)structureTypeEncoding;
|
||||
- (id)pointerTypeEncoding;
|
||||
|
||||
|
||||
- (void)setIsReturnValue:(BOOL)v;
|
||||
- (BOOL)isReturnValue;
|
||||
- (void)setIsOutArgument:(BOOL)v;
|
||||
- (BOOL)isOutArgument;
|
||||
|
||||
- (BOOL)fromJSValueRef:(JSValueRef)value inContext:(JSContextRef)ctx;
|
||||
- (BOOL)toJSValueRef:(JSValueRef*)value inContext:(JSContextRef)ctx;
|
||||
|
||||
|
||||
+ (BOOL)boxObject:(id)o toJSValueRef:(JSValueRef*)value inContext:(JSContextRef)ctx;
|
||||
+ (BOOL)unboxJSValueRef:(JSValueRef)value toObject:(id*)o inContext:(JSContextRef)ctx;
|
||||
+ (BOOL)unboxJSArray:(JSObjectRef)value toObject:(id*)o inContext:(JSContextRef)ctx;
|
||||
+ (BOOL)unboxJSHash:(JSObjectRef)value toObject:(id*)o inContext:(JSContextRef)ctx;
|
||||
|
||||
|
||||
- (ffi_type*)ffi_type;
|
||||
|
||||
@end
|
||||
@@ -1,45 +0,0 @@
|
||||
//
|
||||
// JSCocoaFFIClosure.h
|
||||
// JSCocoa
|
||||
//
|
||||
// Created by Patrick Geiller on 29/07/08.
|
||||
// Copyright 2008 __MyCompanyName__. All rights reserved.
|
||||
//
|
||||
|
||||
#if !TARGET_IPHONE_SIMULATOR && !TARGET_OS_IPHONE
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import <JavaScriptCore/JavaScriptCore.h>
|
||||
#define MACOSX
|
||||
#import <ffi/ffi.h>
|
||||
#endif
|
||||
#import "JSCocoaFFIArgument.h"
|
||||
|
||||
#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
|
||||
#import "iPhone/libffi/ffi.h"
|
||||
#endif
|
||||
|
||||
|
||||
@interface JSCocoaFFIClosure : NSObject {
|
||||
|
||||
JSValueRef jsFunction;
|
||||
// ##UNSURE This might cause a crash if we're registered in a non global context that will have been destroyed when we JSValueUnprotect the function
|
||||
JSContextRef ctx;
|
||||
|
||||
ffi_cif cif;
|
||||
#if !TARGET_OS_IPHONE
|
||||
ffi_closure* closure;
|
||||
#endif
|
||||
ffi_type** argTypes;
|
||||
|
||||
NSMutableArray* encodings;
|
||||
|
||||
JSObjectRef jsThisObject;
|
||||
|
||||
BOOL isObjC;
|
||||
}
|
||||
|
||||
- (IMP)setJSFunction:(JSValueRef)fn inContext:(JSContextRef)ctx argumentEncodings:(NSMutableArray*)argumentEncodings objC:(BOOL)objC;
|
||||
- (void*)functionPointer;
|
||||
- (void)calledByClosureWithArgs:(void**)args returnValue:(void*)returnValue;
|
||||
|
||||
@end
|
||||
@@ -1,215 +0,0 @@
|
||||
//
|
||||
// JSCocoaFFIClosure.m
|
||||
// JSCocoa
|
||||
//
|
||||
// Created by Patrick Geiller on 29/07/08.
|
||||
// Copyright 2008 __MyCompanyName__. All rights reserved.
|
||||
//
|
||||
|
||||
#import "JSCocoaFFIClosure.h"
|
||||
#import "JSCocoaController.h"
|
||||
#include <sys/mman.h> // for mmap()
|
||||
|
||||
void closure_function(ffi_cif* cif, void* resp, void** args, void* userdata);
|
||||
|
||||
@implementation JSCocoaFFIClosure
|
||||
|
||||
|
||||
//
|
||||
// Common closure function, calling back closure object
|
||||
//
|
||||
void closure_function(ffi_cif* cif, void* resp, void** args, void* userdata)
|
||||
{
|
||||
[(id)userdata calledByClosureWithArgs:args returnValue:resp];
|
||||
}
|
||||
|
||||
- (id)init
|
||||
{
|
||||
self = [super init];
|
||||
|
||||
argTypes = NULL;
|
||||
encodings = NULL;
|
||||
jsFunction = NULL;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
//
|
||||
// Cleanup : called by dealloc and finalize
|
||||
//
|
||||
- (void)cleanUp
|
||||
{
|
||||
if (encodings) [encodings release];
|
||||
if (argTypes) free(argTypes);
|
||||
|
||||
if (jsFunction)
|
||||
{
|
||||
JSValueUnprotect(ctx, jsFunction);
|
||||
[JSCocoaController downJSValueProtectCount];
|
||||
}
|
||||
#if !TARGET_OS_IPHONE
|
||||
if (munmap(closure, sizeof(closure)) == -1) NSLog(@"ffi closure munmap failed");
|
||||
#endif
|
||||
}
|
||||
- (void)dealloc
|
||||
{
|
||||
// NSLog(@"deallocing closure %p IMP=%p", self, closure);
|
||||
[self cleanUp];
|
||||
[super dealloc];
|
||||
}
|
||||
- (void)finalize
|
||||
{
|
||||
[self cleanUp];
|
||||
[super finalize];
|
||||
}
|
||||
|
||||
- (void*)functionPointer
|
||||
{
|
||||
#if !TARGET_OS_IPHONE
|
||||
return closure;
|
||||
#else
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
//
|
||||
// Bind a js function to closure. We'll jsValueProtect that function from GC.
|
||||
//
|
||||
- (IMP)setJSFunction:(JSValueRef)fn inContext:(JSContextRef)context argumentEncodings:(NSMutableArray*)argumentEncodings objC:(BOOL)objC
|
||||
{
|
||||
#if !TARGET_OS_IPHONE
|
||||
if ([argumentEncodings count] == 0) return NULL;
|
||||
|
||||
encodings = argumentEncodings;
|
||||
[encodings retain];
|
||||
isObjC = objC;
|
||||
|
||||
unsigned int i, argumentCount = (unsigned int)([argumentEncodings count]-1);
|
||||
argTypes = malloc(sizeof(ffi_type*)*argumentCount);
|
||||
for (i=0; i<argumentCount; i++)
|
||||
{
|
||||
JSCocoaFFIArgument* arg = [argumentEncodings objectAtIndex:i+1];
|
||||
argTypes[i] = [arg ffi_type];
|
||||
}
|
||||
if ((closure = mmap(NULL, sizeof(ffi_closure), PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0)) == (void*)-1)
|
||||
{
|
||||
NSLog(@"ffi closure mmap failed");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
id returnValue = [argumentEncodings objectAtIndex:0];
|
||||
ffi_status prep_status = ffi_prep_cif(&cif, FFI_DEFAULT_ABI, argumentCount, [returnValue ffi_type], argTypes);
|
||||
if (prep_status != FFI_OK)
|
||||
{
|
||||
NSLog(@"ffi_prep_cif failed");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (ffi_prep_closure(closure, &cif, closure_function, (void *)self) != FFI_OK)
|
||||
{
|
||||
NSLog(@"ffi_prep_closure failed");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (mprotect(closure, sizeof(closure), PROT_READ | PROT_EXEC) == -1)
|
||||
{
|
||||
NSLog(@"ffi closure mprotect failed");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
jsFunction = fn;
|
||||
ctx = context;
|
||||
|
||||
// Protect function from GC
|
||||
JSValueProtect(ctx, jsFunction);
|
||||
[JSCocoaController upJSValueProtectCount];
|
||||
|
||||
return (IMP)closure;
|
||||
#else
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
//
|
||||
// Called by ffi
|
||||
//
|
||||
- (void)calledByClosureWithArgs:(void**)closureArgs returnValue:(void*)returnValue
|
||||
{
|
||||
JSObjectRef jsFunctionObject = JSValueToObject(ctx, jsFunction, NULL);
|
||||
JSValueRef exception = NULL;
|
||||
|
||||
// ## Only objC for now. Need to test C function pointers.
|
||||
|
||||
// Argument count is encodings count minus return value
|
||||
NSUInteger i, idx = 0, effectiveArgumentCount = [encodings count]-1;
|
||||
// Skip self and selector
|
||||
if (isObjC)
|
||||
{
|
||||
effectiveArgumentCount -= 2;
|
||||
idx = 2;
|
||||
}
|
||||
// Convert arguments
|
||||
JSValueRef* args = NULL;
|
||||
if (effectiveArgumentCount)
|
||||
{
|
||||
args = malloc(effectiveArgumentCount*sizeof(JSValueRef));
|
||||
for (i=0; i<effectiveArgumentCount; i++, idx++)
|
||||
{
|
||||
// +1 to skip return value
|
||||
id encodingObject = [encodings objectAtIndex:idx+1];
|
||||
|
||||
id arg = [[JSCocoaFFIArgument alloc] init];
|
||||
char encoding = [encodingObject typeEncoding];
|
||||
if (encoding == '{') [arg setStructureTypeEncoding:[encodingObject structureTypeEncoding] withCustomStorage:*(void**)&closureArgs[idx]];
|
||||
else [arg setTypeEncoding:[encodingObject typeEncoding] withCustomStorage:closureArgs[idx]];
|
||||
|
||||
args[i] = NULL;
|
||||
[arg toJSValueRef:&args[i] inContext:ctx];
|
||||
[arg release];
|
||||
}
|
||||
}
|
||||
|
||||
JSObjectRef jsThis = NULL;
|
||||
|
||||
// Create 'this'
|
||||
if (isObjC)
|
||||
jsThis = [[JSCocoa controllerFromContext:ctx] boxObject:*(void**)closureArgs[0]];
|
||||
|
||||
// Call !
|
||||
JSValueRef jsReturnValue = JSObjectCallAsFunction(ctx, jsFunctionObject, jsThis, effectiveArgumentCount, args, &exception);
|
||||
|
||||
// Convert return value if it's not void
|
||||
char encoding = [[encodings objectAtIndex:0] typeEncoding];
|
||||
if (jsReturnValue && encoding != 'v')
|
||||
{
|
||||
[JSCocoaFFIArgument fromJSValueRef:jsReturnValue inContext:ctx typeEncoding:encoding fullTypeEncoding:[[encodings objectAtIndex:0] structureTypeEncoding] fromStorage:returnValue];
|
||||
#ifdef __BIG_ENDIAN__
|
||||
// As ffi always uses a sizeof(long) return value (even for chars and shorts), do some shifting
|
||||
int size = [JSCocoaFFIArgument sizeOfTypeEncoding:encoding];
|
||||
int paddedSize = sizeof(long);
|
||||
long v;
|
||||
if (size > 0 && size < paddedSize && paddedSize == 4)
|
||||
{
|
||||
v = *(long*)returnValue;
|
||||
v = CFSwapInt32(v);
|
||||
*(long*)returnValue = v;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if (effectiveArgumentCount) free(args);
|
||||
if (exception)
|
||||
{
|
||||
@throw [NSException exceptionWithName:@"JSCocoa exception"
|
||||
reason:[[JSCocoaController controllerFromContext:ctx] formatJSException:exception]
|
||||
userInfo:nil];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@end
|
||||
@@ -1,98 +0,0 @@
|
||||
//
|
||||
// JSCocoaLib.h
|
||||
// JSCocoa
|
||||
//
|
||||
// Created by Patrick Geiller on 21/12/08.
|
||||
// Copyright 2008 __MyCompanyName__. All rights reserved.
|
||||
//
|
||||
|
||||
#if !TARGET_IPHONE_SIMULATOR && !TARGET_OS_IPHONE
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#endif
|
||||
#import "JSCocoa.h"
|
||||
|
||||
@class JSCocoaMemoryBuffer;
|
||||
|
||||
@interface JSCocoaOutArgument : NSObject
|
||||
{
|
||||
JSCocoaFFIArgument* arg;
|
||||
JSCocoaMemoryBuffer* buffer;
|
||||
int bufferIndex;
|
||||
}
|
||||
- (BOOL)mateWithJSCocoaFFIArgument:(JSCocoaFFIArgument*)arg;
|
||||
- (JSValueRef)outJSValueRefInContext:(JSContextRef)ctx;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
|
||||
@interface JSCocoaMemoryBuffer : NSObject
|
||||
{
|
||||
void* buffer;
|
||||
int bufferSize;
|
||||
// NSString holding types
|
||||
id typeString;
|
||||
|
||||
// Indicates whether types are aligned.
|
||||
// types not aligned (DEFAULT)
|
||||
// size('fcf') = 4 + 1 + 4 = 9
|
||||
// types aligned
|
||||
// size('fcf') = 4 + 4(align) + 4 = 12
|
||||
BOOL alignTypes;
|
||||
}
|
||||
+ (id)bufferWithTypes:(id)types;
|
||||
- (id)initWithTypes:(id)types;
|
||||
//- (id)initWithTypes:(id)types andValues:(id)values;
|
||||
//- (id)initWithMemoryBuffers:(id)buffers;
|
||||
|
||||
- (void*)pointerForIndex:(NSUInteger)index;
|
||||
- (char)typeAtIndex:(NSUInteger)index;
|
||||
- (JSValueRef)valueAtIndex:(NSUInteger)index inContext:(JSContextRef)ctx;
|
||||
- (BOOL)setValue:(JSValueRef)jsValue atIndex:(NSUInteger)index inContext:(JSContextRef)ctx;
|
||||
- (NSUInteger)typeCount;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@interface JSCocoaLib : NSObject
|
||||
|
||||
+ (id)rootclasses;
|
||||
+ (id)classes;
|
||||
+ (id)protocols;
|
||||
+ (id)imageNames;
|
||||
+ (id)methods;
|
||||
+ (id)runtimeReport;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
|
||||
@interface NSObject(ClassWalker)
|
||||
+ (id)__classImage;
|
||||
- (id)__classImage;
|
||||
+ (id)__derivationPath;
|
||||
- (id)__derivationPath;
|
||||
+ (NSUInteger)__derivationLevel;
|
||||
- (NSUInteger)__derivationLevel;
|
||||
+ (id)__ownMethods;
|
||||
- (id)__ownMethods;
|
||||
+ (id)__methods;
|
||||
- (id)__methods;
|
||||
+ (id)__subclasses;
|
||||
- (id)__subclasses;
|
||||
+ (id)__subclassTree;
|
||||
- (id)__subclassTree;
|
||||
+ (id)__ownIvars;
|
||||
- (id)__ownIvars;
|
||||
+ (id)__ivars;
|
||||
- (id)__ivars;
|
||||
+ (id)__ownProperties;
|
||||
- (id)__ownProperties;
|
||||
+ (id)__properties;
|
||||
- (id)__properties;
|
||||
+ (id)__ownProtocols;
|
||||
- (id)__ownProtocols;
|
||||
+ (id)__protocols;
|
||||
- (id)__protocols;
|
||||
|
||||
@end
|
||||
@@ -1,830 +0,0 @@
|
||||
//
|
||||
// JSCocoaLib.m
|
||||
// JSCocoa
|
||||
//
|
||||
// Created by Patrick Geiller on 21/12/08.
|
||||
// Copyright 2008 __MyCompanyName__. All rights reserved.
|
||||
//
|
||||
|
||||
#import "JSCocoaLib.h"
|
||||
|
||||
|
||||
//
|
||||
// Handles out arguments of functions and methods.
|
||||
// eg NSOpenGLGetVersion(int*, int*) asks for two pointers to int.
|
||||
// JSCocoaOutArgument will alloc the memory through JSCocoaFFIArgument and get the result back to Javascript (check out value in JSCocoaController)
|
||||
//
|
||||
@implementation JSCocoaOutArgument
|
||||
|
||||
- (id)init
|
||||
{
|
||||
self = [super init];
|
||||
|
||||
arg = nil;
|
||||
buffer = nil;
|
||||
return self;
|
||||
}
|
||||
- (void)cleanUp
|
||||
{
|
||||
[arg release];
|
||||
[buffer release];
|
||||
}
|
||||
- (void)dealloc
|
||||
{
|
||||
[self cleanUp];
|
||||
[super dealloc];
|
||||
}
|
||||
- (void)finalize
|
||||
{
|
||||
[self cleanUp];
|
||||
[super finalize];
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// convert the out value to a JSValue
|
||||
//
|
||||
- (JSValueRef)outJSValueRefInContext:(JSContextRef)ctx
|
||||
{
|
||||
JSValueRef jsValue = NULL;
|
||||
[arg toJSValueRef:&jsValue inContext:ctx];
|
||||
return jsValue;
|
||||
}
|
||||
|
||||
// Called from Javascript to extract the resulting value as an object (valueOfCallback returns a string)
|
||||
- (JSValueRefAndContextRef)outValue
|
||||
{
|
||||
JSValueRefAndContextRef r;
|
||||
|
||||
id jsc = nil;
|
||||
object_getInstanceVariable(self, "__jsCocoaController", (void**)&jsc);
|
||||
if (!jsc) return r;
|
||||
|
||||
r.ctx = [jsc ctx];
|
||||
r.value = [self outJSValueRefInContext:r.ctx];
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//
|
||||
// JSCocoaOutArgument holds a JSCocoaFFIArgument around.
|
||||
// it stays alive after ffi_call and can be queried by Javascript for type modifier values.
|
||||
//
|
||||
- (BOOL)mateWithJSCocoaFFIArgument:(JSCocoaFFIArgument*)_arg
|
||||
{
|
||||
// If holding a memory buffer, use its pointer
|
||||
if (buffer)
|
||||
{
|
||||
arg = _arg;
|
||||
[arg retain];
|
||||
void* ptr = [buffer pointerForIndex:bufferIndex];
|
||||
if (!ptr) return NO;
|
||||
[arg setTypeEncoding:[arg typeEncoding] withCustomStorage:ptr];
|
||||
return YES;
|
||||
}
|
||||
|
||||
// Standard pointer
|
||||
void* p = [_arg allocatePointerStorage];
|
||||
if (!p) return NO;
|
||||
|
||||
// Zero out storage
|
||||
*(void**)p = NULL;
|
||||
|
||||
|
||||
arg = _arg;
|
||||
[arg retain];
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (BOOL)mateWithMemoryBuffer:(id)b atIndex:(int)idx
|
||||
{
|
||||
if (!b || ![b isKindOfClass:[JSCocoaMemoryBuffer class]]) return NSLog(@"mateWithMemoryBuffer called without a memory buffer (%@)", b), NO;
|
||||
buffer = b;
|
||||
[buffer retain];
|
||||
bufferIndex = idx;
|
||||
return YES;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
|
||||
//
|
||||
// Instead of malloc(sizeof(float)*4), JSCocoaMemoryBuffer expects 'ffff' as an init string.
|
||||
// The buffer can be manipulated like an array (buffer[2] = 0.5)
|
||||
// * it can be filled, calling methods to copy data in it
|
||||
// - (NSBezierPathElement)elementAtIndex:(NSInteger)index associatedPoints:(NSPointArray)points;
|
||||
// * it can be used as data source, calling methods to copy data from it
|
||||
// - (void)setAssociatedPoints:(NSPointArray)points atIndex:(NSInteger)index;
|
||||
//
|
||||
@implementation JSCocoaMemoryBuffer
|
||||
|
||||
+ (id)bufferWithTypes:(id)types
|
||||
{
|
||||
return [[[JSCocoaMemoryBuffer alloc] initWithTypes:types] autorelease];
|
||||
}
|
||||
|
||||
|
||||
- (id)initWithTypes:(id)_types
|
||||
{
|
||||
self = [super init];
|
||||
buffer = NULL;
|
||||
|
||||
// Copy types string
|
||||
typeString = [NSString stringWithString:_types];
|
||||
[typeString retain];
|
||||
|
||||
// Compute buffer size
|
||||
const char* types = [typeString UTF8String];
|
||||
NSUInteger l = [typeString length];
|
||||
bufferSize = 0;
|
||||
for (int i=0; i<l; i++)
|
||||
{
|
||||
int size = [JSCocoaFFIArgument sizeOfTypeEncoding:types[i]];
|
||||
if (size == -1) return NSLog(@"JSCocoaMemoryBuffer initWithTypes : unknown type %c", types[i]), self;
|
||||
bufferSize += size;
|
||||
}
|
||||
|
||||
if (bufferSize == 0) {
|
||||
NSLog(@"initWithTypes has no types");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Malloc
|
||||
// NSLog(@"mallocing %d bytes for %@", bufferSize, typeString);
|
||||
buffer = malloc(bufferSize);
|
||||
memset(buffer, bufferSize, 1);
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
if (buffer) free(buffer);
|
||||
[typeString release];
|
||||
[super dealloc];
|
||||
}
|
||||
- (void)finalize
|
||||
{
|
||||
if (buffer) free(buffer);
|
||||
[super finalize];
|
||||
}
|
||||
|
||||
//
|
||||
// Returns pointer for index without any padding
|
||||
//
|
||||
- (void*)pointerForIndex:(NSUInteger)idx
|
||||
{
|
||||
const char* types = [typeString UTF8String];
|
||||
if (idx >= [typeString length]) return NULL;
|
||||
void* pointedValue = buffer;
|
||||
for (int i=0; i<idx; i++)
|
||||
{
|
||||
// NSLog(@"advancing %c", types[i]);
|
||||
[JSCocoaFFIArgument advancePtr:&pointedValue accordingToEncoding:types[i]];
|
||||
}
|
||||
return pointedValue;
|
||||
}
|
||||
|
||||
- (char)typeAtIndex:(NSUInteger)idx
|
||||
{
|
||||
if (idx >= [typeString length]) return '\0';
|
||||
return [typeString UTF8String][idx];
|
||||
}
|
||||
|
||||
- (NSUInteger)typeCount
|
||||
{
|
||||
return [typeString length];
|
||||
}
|
||||
|
||||
-(BOOL)referenceObject:(id)o usingPointerAtIndex:(NSUInteger)idx
|
||||
{
|
||||
if ([self typeAtIndex:idx] != '^') return NO;
|
||||
|
||||
void* v = *(void**)[self pointerForIndex:idx];
|
||||
if (!v) return NO;
|
||||
*(id*)v = o;
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (id)dereferenceObjectAtIndex:(NSUInteger)idx
|
||||
{
|
||||
if ([self typeAtIndex:idx] != '^') return nil;
|
||||
void* v = *(void**)[self pointerForIndex:idx];
|
||||
if (!v) return NULL;
|
||||
|
||||
id o = *(id*)v;
|
||||
return o;
|
||||
return *(id*)v;
|
||||
}
|
||||
|
||||
//
|
||||
// Using JSValueRefAndContextRef as input to get the current context in which to create the return value
|
||||
//
|
||||
- (JSValueRef)valueAtIndex:(NSUInteger)idx inContext:(JSContextRef)ctx
|
||||
{
|
||||
char typeEncoding = [self typeAtIndex:idx];
|
||||
void* pointedValue = [self pointerForIndex:idx];
|
||||
if (!pointedValue) return JSValueMakeUndefined(ctx);
|
||||
JSValueRef returnValue;
|
||||
[JSCocoaFFIArgument toJSValueRef:&returnValue inContext:ctx typeEncoding:typeEncoding fullTypeEncoding:nil fromStorage:pointedValue];
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
- (BOOL)setValue:(JSValueRef)jsValue atIndex:(NSUInteger)idx inContext:(JSContextRef)ctx
|
||||
{
|
||||
char typeEncoding = [self typeAtIndex:idx];
|
||||
void* pointedValue = [self pointerForIndex:idx];
|
||||
if (!pointedValue) return NO;
|
||||
[JSCocoaFFIArgument fromJSValueRef:jsValue inContext:ctx typeEncoding:typeEncoding fullTypeEncoding:nil fromStorage:pointedValue];
|
||||
return YES;
|
||||
}
|
||||
|
||||
|
||||
@end
|
||||
|
||||
|
||||
|
||||
@implementation JSCocoaLib
|
||||
|
||||
//
|
||||
// Class list
|
||||
// Some classes are skipped as adding them to an array crashes (Zombie, classes derived from Object or NSProxy)
|
||||
//
|
||||
+ (NSArray*)classes
|
||||
{
|
||||
int classCount = objc_getClassList(nil, 0);
|
||||
Class* classList = malloc(sizeof(Class)*classCount);
|
||||
objc_getClassList(classList, classCount);
|
||||
|
||||
|
||||
NSMutableArray* classArray = [NSMutableArray array];
|
||||
for (int i=0; i<classCount; i++)
|
||||
{
|
||||
id class = classList[i];
|
||||
const char* name= class_getName(class);
|
||||
if (!name) continue;
|
||||
id className = [NSString stringWithUTF8String:name];
|
||||
|
||||
id superclass = class_getSuperclass(class);
|
||||
id superclassName = superclass ? [NSString stringWithUTF8String:class_getName(superclass)] : @"";
|
||||
|
||||
// Check if this class inherits from NSProxy. isKindOfClass crashes, so use raw ObjC api.
|
||||
BOOL isKindOfNSProxy = NO;
|
||||
id c = class;
|
||||
while (c)
|
||||
{
|
||||
if ([[NSString stringWithUTF8String:class_getName(c)] isEqualToString:@"NSProxy"]) isKindOfNSProxy = YES;
|
||||
c = class_getSuperclass(c);
|
||||
}
|
||||
|
||||
// Skip classes crashing when added to an NSArray
|
||||
if ([className hasPrefix:@"_NSZombie_"]
|
||||
|| [className isEqualToString:@"Object"]
|
||||
|| [superclassName isEqualToString:@"Object"]
|
||||
|| [className isEqualToString:@"NSMessageBuilder"]
|
||||
|| [className isEqualToString:@"NSLeafProxy"]
|
||||
|| [className isEqualToString:@"__NSGenericDeallocHandler"]
|
||||
|| isKindOfNSProxy
|
||||
)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
[classArray addObject:class];
|
||||
}
|
||||
|
||||
free(classList);
|
||||
return classArray;
|
||||
}
|
||||
|
||||
+ (NSArray*)rootclasses
|
||||
{
|
||||
id classes = [self classes];
|
||||
NSMutableArray* classArray = [NSMutableArray array];
|
||||
for (id class in classes)
|
||||
{
|
||||
id superclass = class_getSuperclass(class);
|
||||
if (superclass) continue;
|
||||
|
||||
[classArray addObject:class];
|
||||
}
|
||||
return classArray;
|
||||
}
|
||||
|
||||
//
|
||||
// Return an array of { name : imageName, classNames : [className, className, ...] }
|
||||
//
|
||||
+ (id)imageNames
|
||||
{
|
||||
id array = [NSMutableArray array];
|
||||
|
||||
unsigned int imageCount;
|
||||
const char** imageNames = objc_copyImageNames(&imageCount);
|
||||
|
||||
for (int i=0; i<imageCount; i++)
|
||||
{
|
||||
const char* cname = imageNames[i];
|
||||
|
||||
// Gather image class names
|
||||
id array2 = [NSMutableArray array];
|
||||
unsigned int classCount;
|
||||
const char** classNames = objc_copyClassNamesForImage(cname, &classCount);
|
||||
for (int j=0; j<classCount; j++)
|
||||
[array2 addObject:[NSString stringWithUTF8String:classNames[j]]];
|
||||
|
||||
free(classNames);
|
||||
|
||||
// Hash of name and classNames
|
||||
id name = [NSString stringWithUTF8String:cname];
|
||||
id hash = [NSDictionary dictionaryWithObjectsAndKeys:
|
||||
name, @"name",
|
||||
array2, @"classNames",
|
||||
nil];
|
||||
|
||||
[array addObject:hash];
|
||||
}
|
||||
free(imageNames);
|
||||
return array;
|
||||
}
|
||||
|
||||
//
|
||||
// Return protocols and their associated methods
|
||||
//
|
||||
+ (id)protocols
|
||||
{
|
||||
#if NS_BLOCKS_AVAILABLE
|
||||
id array = [NSMutableArray array];
|
||||
unsigned int protocolCount;
|
||||
Protocol** protocols = objc_copyProtocolList(&protocolCount);
|
||||
|
||||
for (int i=0; i<protocolCount; i++)
|
||||
{
|
||||
// array2 is modified by the following block
|
||||
__block id array2 = [NSMutableArray array];
|
||||
Protocol* p = protocols[i];
|
||||
|
||||
// Common block for copying protocol method descriptions
|
||||
void (^b)(BOOL, BOOL) = ^(BOOL isRequiredMethod, BOOL isInstanceMethod) {
|
||||
unsigned int descriptionCount;
|
||||
struct objc_method_description* methodDescriptions = protocol_copyMethodDescriptionList(p, isRequiredMethod, isInstanceMethod, &descriptionCount);
|
||||
for (int j=0; j<descriptionCount; j++)
|
||||
{
|
||||
struct objc_method_description d = methodDescriptions[j];
|
||||
|
||||
id name = NSStringFromSelector(d.name);
|
||||
id encoding = [NSString stringWithUTF8String:d.types];
|
||||
id isRequired = [NSNumber numberWithBool:isRequiredMethod];
|
||||
id type = isInstanceMethod ? @"instance" : @"class";
|
||||
|
||||
id hash = [NSDictionary dictionaryWithObjectsAndKeys:
|
||||
name, @"name",
|
||||
encoding, @"encoding",
|
||||
isRequired, @"isRequired",
|
||||
type, @"type",
|
||||
nil];
|
||||
|
||||
[array2 addObject:hash];
|
||||
}
|
||||
if (methodDescriptions) free(methodDescriptions);
|
||||
};
|
||||
|
||||
// Copy all methods, going through required, non-required, class, instance methods
|
||||
b(YES, YES);
|
||||
b(YES, NO);
|
||||
b(NO, YES);
|
||||
b(NO, NO);
|
||||
|
||||
// Main object : { name : protocolName, methods : [{ name, encoding, isRequired, type }, ...]
|
||||
id name = [NSString stringWithUTF8String:protocol_getName(p)];
|
||||
|
||||
id hash = [NSDictionary dictionaryWithObjectsAndKeys:
|
||||
name, @"name",
|
||||
array2, @"methods",
|
||||
nil];
|
||||
|
||||
[array addObject:hash];
|
||||
}
|
||||
free(protocols);
|
||||
return array;
|
||||
#else
|
||||
return nil;
|
||||
#endif
|
||||
}
|
||||
|
||||
+ (id)methods
|
||||
{
|
||||
id classes = [self classes];
|
||||
id methods = [NSMutableArray array];
|
||||
for (id class in classes)
|
||||
[methods addObjectsFromArray:[class __ownMethods]];
|
||||
return methods;
|
||||
}
|
||||
|
||||
//
|
||||
// Runtime report
|
||||
// Report EVERYTHING
|
||||
// classes
|
||||
// { className : { name
|
||||
// superclassName
|
||||
// derivationPath
|
||||
// subclasses
|
||||
// methods
|
||||
// protocols
|
||||
// ivars
|
||||
// properties
|
||||
// }
|
||||
// protocols
|
||||
// { protocolName : { name
|
||||
// methods
|
||||
// }
|
||||
// imageNames
|
||||
// { imageName : { name
|
||||
// classNames : [className1, className2, ...]
|
||||
// }
|
||||
//
|
||||
+ (id)runtimeReport
|
||||
{
|
||||
/*
|
||||
id classList = [self classes];
|
||||
id protocols = [self protocols];
|
||||
id imageNames = [self imageNames];
|
||||
|
||||
id classes = [NSMutableDictionary dictionary];
|
||||
int classCount = [classList count];
|
||||
// for (id class in classList)
|
||||
for (int i=0; i<classCount; i++)
|
||||
{
|
||||
id class = [classList objectAtIndex:i];
|
||||
id className = [class description];
|
||||
NSLog(@"%d/%d %@", i, (classCount-1), className);
|
||||
|
||||
id superclass = [class superclass];
|
||||
id superclassName = superclass ? [NSString stringWithUTF8String:class_getName(superclass)] : nil;
|
||||
//NSLog(@"%@ (%d/%d)", className, i, classCount-1);
|
||||
id hash = [NSDictionary dictionaryWithObjectsAndKeys:
|
||||
className, @"name",
|
||||
superclassName, @"superclassName",
|
||||
[class __derivationPath], @"derivationPath",
|
||||
[class __methods], @"methods",
|
||||
[class __protocols], @"protocols",
|
||||
[class __ivars], @"ivars",
|
||||
[class __properties], @"properties",
|
||||
nil];
|
||||
[classes setObject:hash forKey:className];
|
||||
}
|
||||
|
||||
id dict = [NSDictionary dictionaryWithObjectsAndKeys:
|
||||
classes, @"classes",
|
||||
protocols, @"protocols",
|
||||
imageNames, @"imageNames",
|
||||
nil];
|
||||
*/
|
||||
// This happens on the ObjC side, NOT in jsc.
|
||||
// There are 2500 classes to dump, this takes a while.
|
||||
// The memory hog is also on the ObjC side, happening during [dict description]
|
||||
return @"Disabled for now, as the resulting hash hangs the app while goring memory";
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
//
|
||||
// Runtime information
|
||||
//
|
||||
@implementation NSObject(ClassWalker)
|
||||
|
||||
//
|
||||
// Class name (description might have been overriden, and classes don't seem to travel well over NSDistantObject)
|
||||
//
|
||||
- (id)__className
|
||||
{
|
||||
return [[self class] description];
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Returns which framework containing the class
|
||||
//
|
||||
+ (id)__classImage
|
||||
{
|
||||
const char* name = class_getImageName(self);
|
||||
if (!name) return nil;
|
||||
return [NSString stringWithUTF8String:name];
|
||||
}
|
||||
- (id)__classImage
|
||||
{
|
||||
return [[self class] __classImage];
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Derivation path
|
||||
// derivationPath(NSButton) = NSObject, NSResponder, NSView, NSControl, NSButton
|
||||
//
|
||||
+ (id)__derivationPath
|
||||
{
|
||||
int level = -1;
|
||||
id class = self;
|
||||
id classes = [NSMutableArray array];
|
||||
while (class)
|
||||
{
|
||||
[classes insertObject:class atIndex:0];
|
||||
level++;
|
||||
class = [class superclass];
|
||||
}
|
||||
return classes;
|
||||
}
|
||||
- (id)__derivationPath
|
||||
{
|
||||
return [[self class] __derivationPath];
|
||||
}
|
||||
|
||||
//
|
||||
// Derivation level
|
||||
//
|
||||
+ (NSUInteger)__derivationLevel
|
||||
{
|
||||
return [[self __derivationPath] count]-1;
|
||||
}
|
||||
- (NSUInteger)__derivationLevel
|
||||
{
|
||||
return [[self class] __derivationLevel];
|
||||
}
|
||||
|
||||
//
|
||||
// Methods
|
||||
//
|
||||
|
||||
// Copy all class or instance (type) methods of a class in an array
|
||||
static id copyMethods(Class class, NSMutableArray* array, NSString* type)
|
||||
{
|
||||
if ([type isEqualToString:@"class"]) class = objc_getMetaClass(class_getName(class));
|
||||
|
||||
unsigned int methodCount;
|
||||
Method* methods = class_copyMethodList(class, &methodCount);
|
||||
|
||||
for (int i=0; i<methodCount; i++)
|
||||
{
|
||||
Method m = methods[i];
|
||||
Dl_info info;
|
||||
dladdr(method_getImplementation(m), &info);
|
||||
|
||||
id name = NSStringFromSelector(method_getName(m));
|
||||
id encoding = [NSString stringWithUTF8String:method_getTypeEncoding(m)];
|
||||
id framework= [NSString stringWithUTF8String:info.dli_fname];
|
||||
|
||||
id hash = [NSDictionary dictionaryWithObjectsAndKeys:
|
||||
name, @"name",
|
||||
encoding, @"encoding",
|
||||
type, @"type",
|
||||
class, @"class",
|
||||
framework, @"framework",
|
||||
nil];
|
||||
|
||||
[array addObject:hash];
|
||||
}
|
||||
free(methods);
|
||||
return array;
|
||||
}
|
||||
+ (id)__ownMethods
|
||||
{
|
||||
id methods = [NSMutableArray array];
|
||||
copyMethods([self class], methods, @"class");
|
||||
copyMethods([self class], methods, @"instance");
|
||||
return methods;
|
||||
}
|
||||
- (id)__ownMethods
|
||||
{
|
||||
return [[self class] __ownMethods];
|
||||
}
|
||||
+ (id)__methods
|
||||
{
|
||||
id classes = [self __derivationPath];
|
||||
id methods = [NSMutableArray array];
|
||||
for (id class in classes)
|
||||
[methods addObjectsFromArray:[class __ownMethods]];
|
||||
return methods;
|
||||
}
|
||||
- (id)__methods
|
||||
{
|
||||
return [[self class] __methods];
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Subclasses
|
||||
//
|
||||
|
||||
// Recursively go breadth first all a class' subclasses
|
||||
static void populateSubclasses(Class class, NSMutableArray* array, NSMutableDictionary* subclassesHash)
|
||||
{
|
||||
// Add ourselves
|
||||
[array addObject:class];
|
||||
|
||||
id className = [NSString stringWithUTF8String:class_getName(class)];
|
||||
id subclasses = [subclassesHash objectForKey:className];
|
||||
for (id subclass in subclasses)
|
||||
{
|
||||
populateSubclasses(subclass, array, subclassesHash);
|
||||
}
|
||||
}
|
||||
// Build a hash of className : [direct subclasses] then walk it down recursively.
|
||||
+ (id)__subclasses
|
||||
{
|
||||
#if NS_BLOCKS_AVAILABLE
|
||||
id classes = [JSCocoaLib classes];
|
||||
id subclasses = [NSMutableArray array];
|
||||
id subclassesHash = [NSMutableDictionary dictionary];
|
||||
|
||||
for (id class in classes)
|
||||
{
|
||||
id superclass = [class superclass];
|
||||
if (!superclass) continue;
|
||||
id superclassName = [NSString stringWithUTF8String:class_getName(superclass)];
|
||||
|
||||
id subclassesArray = [subclassesHash objectForKey:superclassName];
|
||||
if (!subclassesArray)
|
||||
{
|
||||
subclassesArray = [NSMutableArray array];
|
||||
[subclassesHash setObject:subclassesArray forKey:superclassName];
|
||||
}
|
||||
[subclassesArray addObject:class];
|
||||
}
|
||||
|
||||
// (Optional) sort by class name
|
||||
for (id className in subclassesHash)
|
||||
{
|
||||
id subclassesArray = [subclassesHash objectForKey:className];
|
||||
[subclassesArray sortUsingComparator:
|
||||
^(id a, id b)
|
||||
{
|
||||
// Case insensitive compare + remove underscores for sorting (yields [..., NSStatusBarButton, _NSThemeWidget, NSToolbarButton] )
|
||||
return [[[a description] stringByReplacingOccurrencesOfString:@"_" withString:@""]
|
||||
compare:[[b description] stringByReplacingOccurrencesOfString:@"_" withString:@""] options:NSCaseInsensitiveSearch];
|
||||
}];
|
||||
}
|
||||
|
||||
populateSubclasses(self, subclasses, subclassesHash);
|
||||
return subclasses;
|
||||
#else
|
||||
return nil;
|
||||
#endif
|
||||
}
|
||||
- (id)__subclasses
|
||||
{
|
||||
return [[self class] __subclasses];
|
||||
}
|
||||
|
||||
// Returns a string showing subclasses, prefixed with as many spaces as their derivation level
|
||||
+ (id)__subclassTree
|
||||
{
|
||||
id subclasses = [self __subclasses];
|
||||
id str = [NSMutableString string];
|
||||
for (id subclass in subclasses)
|
||||
{
|
||||
NSUInteger level = [subclass __derivationLevel];
|
||||
for (int i=0; i<level; i++)
|
||||
[str appendString:@" "];
|
||||
[str appendString:[NSString stringWithUTF8String:class_getName(subclass)]];
|
||||
[str appendString:@"\n"];
|
||||
}
|
||||
return str;
|
||||
}
|
||||
- (id)__subclassTree
|
||||
{
|
||||
return [[self class] __subclassTree];
|
||||
}
|
||||
|
||||
//
|
||||
// ivars
|
||||
//
|
||||
+ (id)__ownIvars
|
||||
{
|
||||
unsigned int ivarCount;
|
||||
Ivar* ivars = class_copyIvarList(self, &ivarCount);
|
||||
|
||||
id array = [NSMutableArray array];
|
||||
for (int i=0; i<ivarCount; i++)
|
||||
{
|
||||
Ivar ivar = ivars[i];
|
||||
|
||||
id name = [NSString stringWithUTF8String:ivar_getName(ivar)];
|
||||
id encoding = [NSString stringWithUTF8String:ivar_getTypeEncoding(ivar)];
|
||||
id offset = [NSNumber numberWithLong:ivar_getOffset(ivar)];
|
||||
id hash = [NSDictionary dictionaryWithObjectsAndKeys:
|
||||
name, @"name",
|
||||
encoding, @"encoding",
|
||||
offset, @"offset",
|
||||
self, @"class",
|
||||
nil];
|
||||
|
||||
[array addObject:hash];
|
||||
}
|
||||
|
||||
free(ivars);
|
||||
return array;
|
||||
}
|
||||
- (id)__ownIvars
|
||||
{
|
||||
return [[self class] __ownIvars];
|
||||
}
|
||||
+ (id)__ivars
|
||||
{
|
||||
id classes = [self __derivationPath];
|
||||
id ivars = [NSMutableArray array];
|
||||
for (id class in classes)
|
||||
[ivars addObjectsFromArray:[class __ownIvars]];
|
||||
return ivars;
|
||||
}
|
||||
- (id)__ivars
|
||||
{
|
||||
return [[self class] __ivars];
|
||||
}
|
||||
|
||||
//
|
||||
// Properties
|
||||
//
|
||||
+ (id)__ownProperties
|
||||
{
|
||||
unsigned int propertyCount;
|
||||
objc_property_t* properties = class_copyPropertyList(self, &propertyCount);
|
||||
|
||||
id array = [NSMutableArray array];
|
||||
for (int i=0; i<propertyCount; i++)
|
||||
{
|
||||
objc_property_t property = properties[i];
|
||||
|
||||
id name = [NSString stringWithUTF8String:property_getName(property)];
|
||||
id attributes = [NSString stringWithUTF8String:property_getAttributes(property)];
|
||||
id hash = [NSDictionary dictionaryWithObjectsAndKeys:
|
||||
name, @"name",
|
||||
attributes, @"attributes",
|
||||
self, @"class",
|
||||
nil];
|
||||
[array addObject:hash];
|
||||
}
|
||||
|
||||
free(properties);
|
||||
return array;
|
||||
}
|
||||
- (id)__ownProperties
|
||||
{
|
||||
return [[self class] __ownProperties];
|
||||
}
|
||||
+ (id)__properties
|
||||
{
|
||||
id classes = [self __derivationPath];
|
||||
id properties = [NSMutableArray array];
|
||||
for (id class in classes)
|
||||
[properties addObjectsFromArray:[class __ownProperties]];
|
||||
return properties;
|
||||
}
|
||||
- (id)__properties
|
||||
{
|
||||
return [[self class] __properties];
|
||||
}
|
||||
|
||||
//
|
||||
// Protocols
|
||||
//
|
||||
+ (id)__ownProtocols
|
||||
{
|
||||
unsigned int protocolCount;
|
||||
Protocol** protocols = class_copyProtocolList(self, &protocolCount);
|
||||
|
||||
id array = [NSMutableArray array];
|
||||
for (int i=0; i<protocolCount; i++)
|
||||
{
|
||||
id name = [NSString stringWithUTF8String:protocol_getName(protocols[i])];
|
||||
id hash = [NSDictionary dictionaryWithObjectsAndKeys:
|
||||
name, @"name",
|
||||
self, @"class",
|
||||
nil];
|
||||
[array addObject:hash];
|
||||
}
|
||||
|
||||
free(protocols);
|
||||
return array;
|
||||
}
|
||||
- (id)__ownProtocols
|
||||
{
|
||||
return [[self class] __ownProtocols];
|
||||
}
|
||||
|
||||
+ (id)__protocols
|
||||
{
|
||||
id classes = [self __derivationPath];
|
||||
id protocols = [NSMutableArray array];
|
||||
for (id class in classes)
|
||||
[protocols addObjectsFromArray:[class __ownProtocols]];
|
||||
return protocols;
|
||||
}
|
||||
- (id)__protocols
|
||||
{
|
||||
return [[self class] __protocols];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -1,92 +0,0 @@
|
||||
//
|
||||
// JSCocoaPrivateObject.h
|
||||
// JSCocoa
|
||||
//
|
||||
// Created by Patrick Geiller on 09/07/08.
|
||||
// Copyright 2008 __MyCompanyName__. All rights reserved.
|
||||
//
|
||||
|
||||
#if !TARGET_IPHONE_SIMULATOR && !TARGET_OS_IPHONE
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import <JavaScriptCore/JavaScriptCore.h>
|
||||
#endif
|
||||
|
||||
#import <mach-o/dyld.h>
|
||||
#import <dlfcn.h>
|
||||
//#import <objc/objc-class.h>
|
||||
#import <objc/runtime.h>
|
||||
#import <objc/message.h>
|
||||
|
||||
//
|
||||
// Boxing object
|
||||
//
|
||||
// type
|
||||
// @ ObjC object
|
||||
// struct C struct
|
||||
// method ObjC method name
|
||||
// function C function
|
||||
// rawPointer raw C pointer (_C_PTR)
|
||||
// jsFunction Javascript function
|
||||
// jsValueRef raw jsvalue
|
||||
// externalJSValueRef jsvalue coming from an external context (eg, a WebView)
|
||||
//
|
||||
|
||||
@interface JSCocoaPrivateObject : NSObject {
|
||||
|
||||
NSString* type;
|
||||
NSString* xml;
|
||||
NSString* methodName;
|
||||
NSString* structureName;
|
||||
|
||||
NSString* declaredType;
|
||||
void* rawPointer;
|
||||
|
||||
id object;
|
||||
|
||||
Method method;
|
||||
|
||||
JSValueRef jsValue;
|
||||
JSContextRef ctx;
|
||||
unsigned int externalJSValueIndex;
|
||||
// (test) when storing JSValues from a WebView, used to retain the WebView's context.
|
||||
// Disabled for now. Just make sure the WebView has a longer life than the vars it uses.
|
||||
//
|
||||
// Disabled because retaining the context crashes in 32 bits, but works in 64 bit.
|
||||
// May be reenabled someday.
|
||||
// JSContextGroupRef contextGroup;
|
||||
|
||||
BOOL isAutoCall;
|
||||
BOOL retainObject;
|
||||
// Disabled because of a crash on i386. Release globalContext last.
|
||||
// BOOL retainContext;
|
||||
}
|
||||
|
||||
@property (copy) NSString* type;
|
||||
@property (copy) NSString* xml;
|
||||
@property (copy) NSString* methodName;
|
||||
@property (copy) NSString* structureName;
|
||||
@property (copy) NSString* declaredType;
|
||||
@property BOOL isAutoCall;
|
||||
|
||||
//- (void)setPtr:(void*)ptrValue;
|
||||
//- (void*)ptr;
|
||||
|
||||
- (void)setObject:(id)o;
|
||||
- (void)setObjectNoRetain:(id)o;
|
||||
- (BOOL)retainObject;
|
||||
- (id)object;
|
||||
|
||||
- (void)setMethod:(Method)m;
|
||||
- (Method)method;
|
||||
|
||||
- (void)setJSValueRef:(JSValueRef)v ctx:(JSContextRef)ctx;
|
||||
- (JSValueRef)jsValueRef;
|
||||
- (void)setCtx:(JSContextRef)ctx;
|
||||
- (JSContextRef)ctx;
|
||||
- (void)setExternalJSValueRef:(JSValueRef)v ctx:(JSContextRef)ctx;
|
||||
|
||||
- (void*)rawPointer;
|
||||
- (void)setRawPointer:(void*)rp encoding:(id)encoding;
|
||||
- (id)rawPointerEncoding;
|
||||
|
||||
@end
|
||||
@@ -1,236 +0,0 @@
|
||||
//
|
||||
// JSCocoaPrivateObject.m
|
||||
// JSCocoa
|
||||
//
|
||||
// Created by Patrick Geiller on 09/07/08.
|
||||
// Copyright 2008 __MyCompanyName__. All rights reserved.
|
||||
//
|
||||
|
||||
#import "JSCocoaPrivateObject.h"
|
||||
#import "JSCocoaController.h"
|
||||
|
||||
@implementation JSCocoaPrivateObject
|
||||
|
||||
@synthesize type, xml, declaredType, methodName, structureName, isAutoCall;
|
||||
|
||||
|
||||
- (id)init
|
||||
{
|
||||
self = [super init];
|
||||
type = xml = declaredType = methodName = nil;
|
||||
object = nil;
|
||||
isAutoCall = NO;
|
||||
jsValue = NULL;
|
||||
retainObject= YES;
|
||||
rawPointer = NULL;
|
||||
ctx = NULL;
|
||||
// retainContext = NO;
|
||||
externalJSValueIndex = 0;
|
||||
|
||||
|
||||
[JSCocoaController upJSCocoaPrivateObjectCount];
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)cleanUp
|
||||
{
|
||||
[JSCocoaController downJSCocoaPrivateObjectCount];
|
||||
if (object && retainObject)
|
||||
{
|
||||
// NSLog(@"commented downBoxedJSObjectCount");
|
||||
// [JSCocoaController downBoxedJSObjectCount:object];
|
||||
// NSLog(@"releasing %@(%d)", [object class], [object retainCount]);
|
||||
// if ([object isKindOfClass:[JSCocoaController class]])
|
||||
// [object autorelease];
|
||||
// else
|
||||
[object release];
|
||||
}
|
||||
if (jsValue)
|
||||
{
|
||||
if (!externalJSValueIndex) JSValueUnprotect(ctx, jsValue);
|
||||
[JSCocoaController downJSValueProtectCount];
|
||||
|
||||
// If holding a value from an external context, remove it from the GC-safe hash and release context.
|
||||
if (externalJSValueIndex)
|
||||
{
|
||||
JSStringRef scriptJS = JSStringCreateWithUTF8CString("delete __gcprotect[arguments[0]]");
|
||||
JSObjectRef fn = JSObjectMakeFunction(ctx, NULL, 0, NULL, scriptJS, NULL, 1, NULL);
|
||||
JSStringRelease(scriptJS);
|
||||
JSValueRef jsNumber = JSValueMakeNumber(ctx, externalJSValueIndex);
|
||||
JSValueRef exception = NULL;
|
||||
JSObjectCallAsFunction(ctx, fn, NULL, 1, (JSValueRef*)&jsNumber, &exception);
|
||||
// JSGlobalContextRelease((JSGlobalContextRef)ctx);
|
||||
|
||||
if (exception)
|
||||
NSLog(@"Got an exception while trying to release externalJSValueRef %p of context %p", jsValue, ctx);
|
||||
}
|
||||
}
|
||||
/*
|
||||
if (retainContext)
|
||||
{
|
||||
NSLog(@"releasing %p", ctx);
|
||||
JSContextGroupRelease(contextGroup);
|
||||
// JSGlobalContextRelease((JSGlobalContextRef)ctx);
|
||||
}
|
||||
*/
|
||||
// Release properties
|
||||
[type release];
|
||||
[xml release];
|
||||
[methodName release];
|
||||
[structureName release];
|
||||
[declaredType release];
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[self cleanUp];
|
||||
[super dealloc];
|
||||
}
|
||||
- (void)finalize
|
||||
{
|
||||
[self cleanUp];
|
||||
[super finalize];
|
||||
}
|
||||
|
||||
- (void)setObject:(id)o
|
||||
{
|
||||
// if (object && retainObject)
|
||||
// [object release];
|
||||
object = o;
|
||||
if (object && [object retainCount] == -1) return;
|
||||
[object retain];
|
||||
}
|
||||
|
||||
- (void)setObjectNoRetain:(id)o
|
||||
{
|
||||
object = o;
|
||||
retainObject = NO;
|
||||
}
|
||||
|
||||
- (BOOL)retainObject
|
||||
{
|
||||
return retainObject;
|
||||
}
|
||||
|
||||
- (id)object
|
||||
{
|
||||
return object;
|
||||
}
|
||||
|
||||
- (void)setMethod:(Method)m
|
||||
{
|
||||
method = m;
|
||||
}
|
||||
- (Method)method
|
||||
{
|
||||
return method;
|
||||
}
|
||||
|
||||
- (void)setJSValueRef:(JSValueRef)v ctx:(JSContextRef)c
|
||||
{
|
||||
// While autocalling we'll get a NULL value when boxing a void return type - just skip JSValueProtect
|
||||
if (!v)
|
||||
{
|
||||
// NSLog(@"setJSValueRef: NULL value");
|
||||
jsValue = 0;
|
||||
return;
|
||||
}
|
||||
jsValue = v;
|
||||
// ctx = c;
|
||||
// Register global context (this would crash the launcher as JSValueUnprotect was called on a destroyed context)
|
||||
ctx = [[JSCocoaController controllerFromContext:c] ctx];
|
||||
JSValueProtect(ctx, jsValue);
|
||||
[JSCocoaController upJSValueProtectCount];
|
||||
}
|
||||
- (JSValueRef)jsValueRef
|
||||
{
|
||||
return jsValue;
|
||||
}
|
||||
|
||||
- (void)setCtx:(JSContextRef)_ctx {
|
||||
ctx = _ctx;
|
||||
}
|
||||
- (JSContextRef)ctx
|
||||
{
|
||||
return ctx;
|
||||
}
|
||||
|
||||
|
||||
- (void)setExternalJSValueRef:(JSValueRef)v ctx:(JSContextRef)c
|
||||
{
|
||||
if (!v)
|
||||
{
|
||||
jsValue = 0;
|
||||
return;
|
||||
}
|
||||
jsValue = v;
|
||||
ctx = c;
|
||||
|
||||
// Register value in a global hash to protect it from GC. This sucks but JSValueProtect() fails.
|
||||
JSStringRef scriptJS = JSStringCreateWithUTF8CString("if (!('__gcprotect' in this)) { __gcprotect = {}; __gcprotectidx = 1; } __gcprotect[__gcprotectidx] = arguments[0]; return __gcprotectidx++ ");
|
||||
JSObjectRef fn = JSObjectMakeFunction(ctx, NULL, 0, NULL, scriptJS, NULL, 1, NULL);
|
||||
JSStringRelease(scriptJS);
|
||||
|
||||
JSValueRef exception = NULL;
|
||||
JSValueRef result = JSObjectCallAsFunction(ctx, fn, NULL, 1, (JSValueRef*)&jsValue, &exception);
|
||||
if (exception) return;
|
||||
|
||||
// Use hash index as key, will be used to remove value from hash upon deletion.
|
||||
externalJSValueIndex = (unsigned int)JSValueToNumber(ctx, result, &exception);
|
||||
if (exception) return;
|
||||
|
||||
// JSGlobalContextRetain((JSGlobalContextRef)ctx);
|
||||
[JSCocoaController upJSValueProtectCount];
|
||||
}
|
||||
|
||||
|
||||
- (void*)rawPointer
|
||||
{
|
||||
return rawPointer;
|
||||
}
|
||||
- (void)setRawPointer:(void*)rp encoding:(id)encoding
|
||||
{
|
||||
rawPointer = rp;
|
||||
// NSLog(@"RAWPOINTER=%@", encoding);
|
||||
declaredType = encoding;
|
||||
[declaredType retain];
|
||||
}
|
||||
|
||||
- (id)rawPointerEncoding
|
||||
{
|
||||
return declaredType;
|
||||
}
|
||||
|
||||
|
||||
- (id)description {
|
||||
id extra = @"";
|
||||
if ([type isEqualToString:@"rawPointer"])
|
||||
extra = [NSString stringWithFormat:@" rawPointer=%p declaredType=%@", rawPointer, declaredType];
|
||||
return [NSString stringWithFormat:@"<%@: %p holding %@%@>",
|
||||
[self class],
|
||||
self,
|
||||
type,
|
||||
extra
|
||||
];
|
||||
}
|
||||
|
||||
+ (id)description {
|
||||
return @"<JSCocoaPrivateObject class>";
|
||||
}
|
||||
|
||||
- (id)dereferencedObject {
|
||||
if (![type isEqualToString:@"rawPointer"] || !rawPointer)
|
||||
return nil;
|
||||
return *(void**)rawPointer;
|
||||
}
|
||||
|
||||
- (BOOL)referenceObject:(id)o {
|
||||
if (![type isEqualToString:@"rawPointer"])
|
||||
return NO;
|
||||
*(id*)rawPointer = o;
|
||||
return YES;
|
||||
}
|
||||
|
||||
|
||||
@end
|
||||
|
||||
289
Atom/MainMenu.xib
Executable file
@@ -0,0 +1,289 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<archive type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="7.10">
|
||||
<data>
|
||||
<int key="IBDocument.SystemTarget">1050</int>
|
||||
<string key="IBDocument.SystemVersion">11C74</string>
|
||||
<string key="IBDocument.InterfaceBuilderVersion">1938</string>
|
||||
<string key="IBDocument.AppKitVersion">1138.23</string>
|
||||
<string key="IBDocument.HIToolboxVersion">567.00</string>
|
||||
<object class="NSMutableDictionary" key="IBDocument.PluginVersions">
|
||||
<string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string key="NS.object.0">1938</string>
|
||||
</object>
|
||||
<object class="NSArray" key="IBDocument.IntegratedClassDependencies">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<string>NSUserDefaultsController</string>
|
||||
<string>NSMenu</string>
|
||||
<string>NSMenuItem</string>
|
||||
<string>NSCustomObject</string>
|
||||
</object>
|
||||
<object class="NSArray" key="IBDocument.PluginDependencies">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
</object>
|
||||
<object class="NSMutableDictionary" key="IBDocument.Metadata">
|
||||
<string key="NS.key.0">PluginDependencyRecalculationVersion</string>
|
||||
<integer value="1" key="NS.object.0"/>
|
||||
</object>
|
||||
<object class="NSMutableArray" key="IBDocument.RootObjects" id="1048">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="NSCustomObject" id="1021">
|
||||
<string key="NSClassName">ClientApplication</string>
|
||||
</object>
|
||||
<object class="NSCustomObject" id="1014">
|
||||
<string key="NSClassName">FirstResponder</string>
|
||||
</object>
|
||||
<object class="NSCustomObject" id="1050">
|
||||
<string key="NSClassName">Atom</string>
|
||||
</object>
|
||||
<object class="NSMenu" id="649796088">
|
||||
<string key="NSTitle">AMainMenu</string>
|
||||
<object class="NSMutableArray" key="NSMenuItems">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="NSMenuItem" id="694149608">
|
||||
<reference key="NSMenu" ref="649796088"/>
|
||||
<string key="NSTitle">Atom</string>
|
||||
<string key="NSKeyEquiv"/>
|
||||
<int key="NSKeyEquivModMask">1048576</int>
|
||||
<int key="NSMnemonicLoc">2147483647</int>
|
||||
<object class="NSCustomResource" key="NSOnImage" id="293900348">
|
||||
<string key="NSClassName">NSImage</string>
|
||||
<string key="NSResourceName">NSMenuCheckmark</string>
|
||||
</object>
|
||||
<object class="NSCustomResource" key="NSMixedImage" id="169361956">
|
||||
<string key="NSClassName">NSImage</string>
|
||||
<string key="NSResourceName">NSMenuMixedState</string>
|
||||
</object>
|
||||
<string key="NSAction">submenuAction:</string>
|
||||
<object class="NSMenu" key="NSSubmenu" id="110575045">
|
||||
<string key="NSTitle">Atom</string>
|
||||
<object class="NSMutableArray" key="NSMenuItems">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="NSMenuItem" id="238522557">
|
||||
<reference key="NSMenu" ref="110575045"/>
|
||||
<string key="NSTitle">Run Specs</string>
|
||||
<string key="NSKeyEquiv">s</string>
|
||||
<int key="NSKeyEquivModMask">1835008</int>
|
||||
<int key="NSMnemonicLoc">2147483647</int>
|
||||
<reference key="NSOnImage" ref="293900348"/>
|
||||
<reference key="NSMixedImage" ref="169361956"/>
|
||||
</object>
|
||||
<object class="NSMenuItem" id="305640227">
|
||||
<reference key="NSMenu" ref="110575045"/>
|
||||
<string key="NSTitle">Quit</string>
|
||||
<string key="NSKeyEquiv">q</string>
|
||||
<int key="NSKeyEquivModMask">1048576</int>
|
||||
<int key="NSMnemonicLoc">2147483647</int>
|
||||
<reference key="NSOnImage" ref="293900348"/>
|
||||
<reference key="NSMixedImage" ref="169361956"/>
|
||||
</object>
|
||||
</object>
|
||||
<string key="NSName">_NSAppleMenu</string>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
<string key="NSName">_NSMainMenu</string>
|
||||
</object>
|
||||
<object class="NSUserDefaultsController" id="143541711">
|
||||
<bool key="NSSharedInstance">YES</bool>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBObjectContainer" key="IBDocument.Objects">
|
||||
<object class="NSMutableArray" key="connectionRecords">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="IBConnectionRecord">
|
||||
<object class="IBOutletConnection" key="connection">
|
||||
<string key="label">delegate</string>
|
||||
<reference key="source" ref="1050"/>
|
||||
<reference key="destination" ref="1021"/>
|
||||
</object>
|
||||
<int key="connectionID">440</int>
|
||||
</object>
|
||||
<object class="IBConnectionRecord">
|
||||
<object class="IBActionConnection" key="connection">
|
||||
<string key="label">stop:</string>
|
||||
<reference key="source" ref="1050"/>
|
||||
<reference key="destination" ref="305640227"/>
|
||||
</object>
|
||||
<int key="connectionID">447</int>
|
||||
</object>
|
||||
<object class="IBConnectionRecord">
|
||||
<object class="IBActionConnection" key="connection">
|
||||
<string key="label">runSpecs:</string>
|
||||
<reference key="source" ref="1050"/>
|
||||
<reference key="destination" ref="238522557"/>
|
||||
</object>
|
||||
<int key="connectionID">449</int>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBMutableOrderedSet" key="objectRecords">
|
||||
<object class="NSArray" key="orderedObjects">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">0</int>
|
||||
<object class="NSArray" key="object" id="755588897">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
</object>
|
||||
<reference key="children" ref="1048"/>
|
||||
<nil key="parent"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">-2</int>
|
||||
<reference key="object" ref="1021"/>
|
||||
<reference key="parent" ref="755588897"/>
|
||||
<string key="objectName">File's Owner</string>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">-1</int>
|
||||
<reference key="object" ref="1014"/>
|
||||
<reference key="parent" ref="755588897"/>
|
||||
<string key="objectName">First Responder</string>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">-3</int>
|
||||
<reference key="object" ref="1050"/>
|
||||
<reference key="parent" ref="755588897"/>
|
||||
<string key="objectName">Application</string>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">29</int>
|
||||
<reference key="object" ref="649796088"/>
|
||||
<object class="NSMutableArray" key="children">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<reference ref="694149608"/>
|
||||
</object>
|
||||
<reference key="parent" ref="755588897"/>
|
||||
<string key="objectName">MainMenu</string>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">56</int>
|
||||
<reference key="object" ref="694149608"/>
|
||||
<object class="NSMutableArray" key="children">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<reference ref="110575045"/>
|
||||
</object>
|
||||
<reference key="parent" ref="649796088"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">57</int>
|
||||
<reference key="object" ref="110575045"/>
|
||||
<object class="NSMutableArray" key="children">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<reference ref="238522557"/>
|
||||
<reference ref="305640227"/>
|
||||
</object>
|
||||
<reference key="parent" ref="694149608"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">58</int>
|
||||
<reference key="object" ref="238522557"/>
|
||||
<reference key="parent" ref="110575045"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">389</int>
|
||||
<reference key="object" ref="143541711"/>
|
||||
<reference key="parent" ref="755588897"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">441</int>
|
||||
<reference key="object" ref="305640227"/>
|
||||
<reference key="parent" ref="110575045"/>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
<object class="NSMutableDictionary" key="flattenedProperties">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="NSArray" key="dict.sortedKeys">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<string>-1.IBPluginDependency</string>
|
||||
<string>-2.IBPluginDependency</string>
|
||||
<string>-3.IBPluginDependency</string>
|
||||
<string>29.IBPluginDependency</string>
|
||||
<string>389.IBPluginDependency</string>
|
||||
<string>441.IBPluginDependency</string>
|
||||
<string>56.IBPluginDependency</string>
|
||||
<string>57.IBPluginDependency</string>
|
||||
<string>58.IBPluginDependency</string>
|
||||
</object>
|
||||
<object class="NSMutableArray" key="dict.values">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="NSMutableDictionary" key="unlocalizedProperties">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<reference key="dict.sortedKeys" ref="755588897"/>
|
||||
<reference key="dict.values" ref="755588897"/>
|
||||
</object>
|
||||
<nil key="activeLocalization"/>
|
||||
<object class="NSMutableDictionary" key="localizations">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<reference key="dict.sortedKeys" ref="755588897"/>
|
||||
<reference key="dict.values" ref="755588897"/>
|
||||
</object>
|
||||
<nil key="sourceID"/>
|
||||
<int key="maxID">449</int>
|
||||
</object>
|
||||
<object class="IBClassDescriber" key="IBDocument.Classes">
|
||||
<object class="NSMutableArray" key="referencedPartialClassDescriptions">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">Atom</string>
|
||||
<string key="superclassName">NSApplication</string>
|
||||
<object class="NSMutableDictionary" key="actions">
|
||||
<string key="NS.key.0">runSpecs:</string>
|
||||
<string key="NS.object.0">id</string>
|
||||
</object>
|
||||
<object class="NSMutableDictionary" key="actionInfosByName">
|
||||
<string key="NS.key.0">runSpecs:</string>
|
||||
<object class="IBActionInfo" key="NS.object.0">
|
||||
<string key="name">runSpecs:</string>
|
||||
<string key="candidateClassName">id</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBProjectSource</string>
|
||||
<string key="minorKey">./Classes/Atom.h</string>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
<int key="IBDocument.localizationMode">0</int>
|
||||
<string key="IBDocument.TargetRuntimeIdentifier">IBCocoaFramework</string>
|
||||
<object class="NSMutableDictionary" key="IBDocument.PluginDeclaredDependencies">
|
||||
<string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin.macosx</string>
|
||||
<integer value="1050" key="NS.object.0"/>
|
||||
</object>
|
||||
<object class="NSMutableDictionary" key="IBDocument.PluginDeclaredDependencyDefaults">
|
||||
<string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin.macosx</string>
|
||||
<real value="1060" key="NS.object.0"/>
|
||||
</object>
|
||||
<object class="NSMutableDictionary" key="IBDocument.PluginDeclaredDevelopmentDependencies">
|
||||
<string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin.InterfaceBuilder3</string>
|
||||
<integer value="3000" key="NS.object.0"/>
|
||||
</object>
|
||||
<bool key="IBDocument.PluginDeclaredDependenciesTrackSystemTargetVersion">YES</bool>
|
||||
<int key="IBDocument.defaultPropertyAccessControl">3</int>
|
||||
<object class="NSMutableDictionary" key="IBDocument.LastKnownImageSizes">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="NSArray" key="dict.sortedKeys">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<string>NSMenuCheckmark</string>
|
||||
<string>NSMenuMixedState</string>
|
||||
</object>
|
||||
<object class="NSMutableArray" key="dict.values">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<string>{9, 8}</string>
|
||||
<string>{7, 2}</string>
|
||||
</object>
|
||||
</object>
|
||||
</data>
|
||||
</archive>
|
||||
@@ -1,49 +0,0 @@
|
||||
/* =============================================================================
|
||||
FILE: UKFNSubscribeFileWatcher.m
|
||||
PROJECT: Filie
|
||||
|
||||
COPYRIGHT: (c) 2005 M. Uli Kusterer, all rights reserved.
|
||||
|
||||
AUTHORS: M. Uli Kusterer - UK
|
||||
|
||||
LICENSES: MIT License
|
||||
|
||||
REVISIONS:
|
||||
2006-03-13 UK Commented, added singleton.
|
||||
2005-03-02 UK Created.
|
||||
========================================================================== */
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Headers:
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import "UKFileWatcher.h"
|
||||
#import <Carbon/Carbon.h>
|
||||
|
||||
/*
|
||||
NOTE: FNSubscribe has a built-in delay: If your application is in the
|
||||
background while the changes happen, all notifications will be queued up
|
||||
and sent to your app at once the moment it is brought to front again. If
|
||||
your app really needs to do live updates in the background, use a KQueue
|
||||
instead.
|
||||
*/
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Class declaration:
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
@interface UKFNSubscribeFileWatcher : NSObject <UKFileWatcher>
|
||||
{
|
||||
id delegate; // Delegate must respond to UKFileWatcherDelegate protocol.
|
||||
NSMutableDictionary* subscriptions; // List of FNSubscription pointers in NSValues, with the pathnames as their keys.
|
||||
}
|
||||
|
||||
+(id) sharedFileWatcher;
|
||||
|
||||
// UKFileWatcher defines the methods: addPath: removePath: and delegate accessors.
|
||||
|
||||
// Private:
|
||||
-(void) sendDelegateMessage: (FNMessage)message forSubscription: (FNSubscriptionRef)subscription;
|
||||
|
||||
@end
|
||||
@@ -1,201 +0,0 @@
|
||||
/* =============================================================================
|
||||
FILE: UKFNSubscribeFileWatcher.m
|
||||
PROJECT: Filie
|
||||
|
||||
COPYRIGHT: (c) 2005 M. Uli Kusterer, all rights reserved.
|
||||
|
||||
AUTHORS: M. Uli Kusterer - UK
|
||||
|
||||
LICENSES: MIT License
|
||||
|
||||
REVISIONS:
|
||||
2006-03-13 UK Commented, added singleton, added notifications.
|
||||
2005-03-02 UK Created.
|
||||
========================================================================== */
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Headers:
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
#import "UKFNSubscribeFileWatcher.h"
|
||||
#import <Carbon/Carbon.h>
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Prototypes:
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
void UKFileSubscriptionProc(FNMessage message, OptionBits flags, void *refcon, FNSubscriptionRef subscription);
|
||||
|
||||
|
||||
@implementation UKFNSubscribeFileWatcher
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// sharedFileWatcher:
|
||||
// Singleton accessor.
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
+(id) sharedFileWatcher
|
||||
{
|
||||
static UKFNSubscribeFileWatcher* sSharedFileWatcher = nil;
|
||||
|
||||
if( !sSharedFileWatcher )
|
||||
sSharedFileWatcher = [[UKFNSubscribeFileWatcher alloc] init]; // This is a singleton, and thus an intentional "leak".
|
||||
|
||||
return sSharedFileWatcher;
|
||||
}
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// * CONSTRUCTOR:
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
-(id) init
|
||||
{
|
||||
self = [super init];
|
||||
if( !self )
|
||||
return nil;
|
||||
|
||||
subscriptions = [[NSMutableDictionary alloc] init];
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// * DESTRUCTOR:
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
-(void) dealloc
|
||||
{
|
||||
NSEnumerator* enny = [subscriptions objectEnumerator];
|
||||
NSValue* subValue = nil;
|
||||
|
||||
while( (subValue = [enny nextObject]) )
|
||||
{
|
||||
FNSubscriptionRef subscription = [subValue pointerValue];
|
||||
FNUnsubscribe( subscription );
|
||||
}
|
||||
|
||||
[subscriptions release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// addPath:
|
||||
// Start watching the object at the specified path. This only sends write
|
||||
// notifications for all changes, as FNSubscribe doesn't tell what actually
|
||||
// changed about our folder.
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
-(void) addPath: (NSString*)path
|
||||
{
|
||||
OSStatus err = noErr;
|
||||
static FNSubscriptionUPP subscriptionUPP = NULL;
|
||||
FNSubscriptionRef subscription = NULL;
|
||||
|
||||
if( !subscriptionUPP )
|
||||
subscriptionUPP = NewFNSubscriptionUPP( UKFileSubscriptionProc );
|
||||
|
||||
err = FNSubscribeByPath( (UInt8*) [path fileSystemRepresentation], subscriptionUPP, (void*)self,
|
||||
kNilOptions, &subscription );
|
||||
if( err != noErr )
|
||||
{
|
||||
NSLog( @"UKFNSubscribeFileWatcher addPath: %@ failed due to error ID=%d.", path, err );
|
||||
return;
|
||||
}
|
||||
|
||||
[subscriptions setObject: [NSValue valueWithPointer: subscription] forKey: path];
|
||||
}
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// removePath:
|
||||
// Stop watching the object at the specified path.
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
-(void) removePath: (NSString*)path
|
||||
{
|
||||
NSValue* subValue = nil;
|
||||
@synchronized( self )
|
||||
{
|
||||
subValue = [[[subscriptions objectForKey: path] retain] autorelease];
|
||||
[subscriptions removeObjectForKey: path];
|
||||
}
|
||||
|
||||
if( subValue )
|
||||
{
|
||||
FNSubscriptionRef subscription = [subValue pointerValue];
|
||||
|
||||
FNUnsubscribe( subscription );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// sendDelegateMessage:forSubscription:
|
||||
// Bottleneck for change notifications. This is called by our callback
|
||||
// function to actually inform the delegate and send out notifications.
|
||||
//
|
||||
// This *only* sends out write notifications, as FNSubscribe doesn't tell
|
||||
// what changed about our folder.
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
-(void) sendDelegateMessage: (FNMessage)message forSubscription: (FNSubscriptionRef)subscription
|
||||
{
|
||||
NSValue* subValue = [NSValue valueWithPointer: subscription];
|
||||
NSString* path = [[subscriptions allKeysForObject: subValue] objectAtIndex: 0];
|
||||
|
||||
[[[NSWorkspace sharedWorkspace] notificationCenter] postNotificationName: UKFileWatcherWriteNotification
|
||||
object: self
|
||||
userInfo: [NSDictionary dictionaryWithObjectsAndKeys: path, @"path", nil]];
|
||||
|
||||
[delegate watcher: self receivedNotification: UKFileWatcherWriteNotification forPath: path];
|
||||
//NSLog( @"UKFNSubscribeFileWatcher noticed change to %@", path ); // DEBUG ONLY!
|
||||
}
|
||||
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// delegate:
|
||||
// Accessor for file watcher delegate.
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
-(id) delegate
|
||||
{
|
||||
return delegate;
|
||||
}
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// setDelegate:
|
||||
// Mutator for file watcher delegate.
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
-(void) setDelegate: (id)newDelegate
|
||||
{
|
||||
delegate = newDelegate;
|
||||
}
|
||||
|
||||
|
||||
@end
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// UKFileSubscriptionProc:
|
||||
// Callback function we hand to Carbon so it can tell us when something
|
||||
// changed about our watched folders. We set the refcon to a pointer to
|
||||
// our object. This simply extracts the object and hands the info off to
|
||||
// sendDelegateMessage:forSubscription: which does the actual work.
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
void UKFileSubscriptionProc( FNMessage message, OptionBits flags, void *refcon, FNSubscriptionRef subscription )
|
||||
{
|
||||
UKFNSubscribeFileWatcher* obj = (UKFNSubscribeFileWatcher*) refcon;
|
||||
|
||||
if( message == kFNDirectoryModifiedMessage ) // No others exist as of 10.4
|
||||
[obj sendDelegateMessage: message forSubscription: subscription];
|
||||
else
|
||||
NSLog( @"UKFileSubscriptionProc: Unknown message %d", message );
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
/* =============================================================================
|
||||
FILE: UKFileWatcher.h
|
||||
PROJECT: Filie
|
||||
|
||||
COPYRIGHT: (c) 2005 M. Uli Kusterer, all rights reserved.
|
||||
|
||||
AUTHORS: M. Uli Kusterer - UK
|
||||
|
||||
LICENSES: MIT License
|
||||
|
||||
REVISIONS:
|
||||
2006-03-13 UK Moved notification constants to .m file.
|
||||
2005-02-25 UK Created.
|
||||
========================================================================== */
|
||||
|
||||
/*
|
||||
This is a protocol that file change notification classes should adopt.
|
||||
That way, no matter whether you use Carbon's FNNotify/FNSubscribe, BSD's
|
||||
kqueue or whatever, the object being notified can react to change
|
||||
notifications the same way, and you can easily swap one out for the other
|
||||
to cater to different OS versions, target volumes etc.
|
||||
*/
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Protocol:
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
@protocol UKFileWatcher
|
||||
|
||||
// +(id) sharedFileWatcher; // Singleton accessor. Not officially part of the protocol, but use this name if you provide a singleton.
|
||||
|
||||
-(void) addPath: (NSString*)path;
|
||||
-(void) removePath: (NSString*)path;
|
||||
|
||||
-(id) delegate;
|
||||
-(void) setDelegate: (id)newDelegate;
|
||||
|
||||
@end
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Methods delegates need to provide:
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
@interface NSObject (UKFileWatcherDelegate)
|
||||
|
||||
-(void) watcher: (id<UKFileWatcher>)kq receivedNotification: (NSString*)nm forPath: (NSString*)fpath;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
// Notifications this sends:
|
||||
/* object = the file watcher object
|
||||
userInfo.path = file path watched
|
||||
These notifications are sent via the NSWorkspace notification center */
|
||||
extern NSString* UKFileWatcherRenameNotification;
|
||||
extern NSString* UKFileWatcherWriteNotification;
|
||||
extern NSString* UKFileWatcherDeleteNotification;
|
||||
extern NSString* UKFileWatcherAttributeChangeNotification;
|
||||
extern NSString* UKFileWatcherSizeIncreaseNotification;
|
||||
extern NSString* UKFileWatcherLinkCountChangeNotification;
|
||||
extern NSString* UKFileWatcherAccessRevocationNotification;
|
||||
|
||||
@@ -1,38 +0,0 @@
|
||||
/* =============================================================================
|
||||
FILE: UKKQueue.m
|
||||
PROJECT: Filie
|
||||
|
||||
COPYRIGHT: (c) 2005-06 M. Uli Kusterer, all rights reserved.
|
||||
|
||||
AUTHORS: M. Uli Kusterer - UK
|
||||
|
||||
LICENSES: MIT License
|
||||
|
||||
REVISIONS:
|
||||
2006-03-13 UK Created, moved notification constants here as exportable
|
||||
symbols.
|
||||
========================================================================== */
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Headers:
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import "UKFileWatcher.h"
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Constants:
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// Do not rely on the actual contents of these constants. They will eventually
|
||||
// be changed to be more generic and less KQueue-specific.
|
||||
|
||||
NSString* UKFileWatcherRenameNotification = @"UKKQueueFileRenamedNotification";
|
||||
NSString* UKFileWatcherWriteNotification = @"UKKQueueFileWrittenToNotification";
|
||||
NSString* UKFileWatcherDeleteNotification = @"UKKQueueFileDeletedNotification";
|
||||
NSString* UKFileWatcherAttributeChangeNotification = @"UKKQueueFileAttributesChangedNotification";
|
||||
NSString* UKFileWatcherSizeIncreaseNotification = @"UKKQueueFileSizeIncreasedNotification";
|
||||
NSString* UKFileWatcherLinkCountChangeNotification = @"UKKQueueFileLinkCountChangedNotification";
|
||||
NSString* UKFileWatcherAccessRevocationNotification = @"UKKQueueFileAccessRevocationNotification";
|
||||
|
||||
@@ -1,122 +0,0 @@
|
||||
/* =============================================================================
|
||||
FILE: UKKQueue.h
|
||||
PROJECT: Filie
|
||||
|
||||
COPYRIGHT: (c) 2003 M. Uli Kusterer, all rights reserved.
|
||||
|
||||
AUTHORS: M. Uli Kusterer - UK
|
||||
|
||||
LICENSES: MIT License
|
||||
|
||||
REVISIONS:
|
||||
2006-03-13 UK Clarified license, streamlined UKFileWatcher stuff,
|
||||
Changed notifications to be useful and turned off by
|
||||
default some deprecated stuff.
|
||||
2003-12-21 UK Created.
|
||||
========================================================================== */
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Headers:
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/event.h>
|
||||
#import "UKFileWatcher.h"
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Constants:
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// Backwards compatibility constants. Don't rely on code commented out with these constants, because it may be deleted in a future version.
|
||||
#ifndef UKKQUEUE_BACKWARDS_COMPATIBLE
|
||||
#define UKKQUEUE_BACKWARDS_COMPATIBLE 0 // 1 to send old-style kqueue:receivedNotification:forFile: messages to objects that accept them.
|
||||
#endif
|
||||
|
||||
#ifndef UKKQUEUE_SEND_STUPID_NOTIFICATIONS
|
||||
#define UKKQUEUE_SEND_STUPID_NOTIFICATIONS 0 // 1 to send old-style notifications that have the path as the object and no userInfo dictionary.
|
||||
#endif
|
||||
|
||||
#ifndef UKKQUEUE_OLD_SINGLETON_ACCESSOR_NAME
|
||||
#define UKKQUEUE_OLD_SINGLETON_ACCESSOR_NAME 0 // 1 to allow use of sharedQueue instead of sharedFileWatcher.
|
||||
#endif
|
||||
|
||||
#ifndef UKKQUEUE_OLD_NOTIFICATION_NAMES
|
||||
#define UKKQUEUE_OLD_NOTIFICATION_NAMES 0 // 1 to allow use of old KQueue-style notification names instead of the new more generic ones in UKFileWatcher.
|
||||
#endif
|
||||
|
||||
// Flags for notifyingAbout:
|
||||
#define UKKQueueNotifyAboutRename NOTE_RENAME // Item was renamed.
|
||||
#define UKKQueueNotifyAboutWrite NOTE_WRITE // Item contents changed (also folder contents changed).
|
||||
#define UKKQueueNotifyAboutDelete NOTE_DELETE // item was removed.
|
||||
#define UKKQueueNotifyAboutAttributeChange NOTE_ATTRIB // Item attributes changed.
|
||||
#define UKKQueueNotifyAboutSizeIncrease NOTE_EXTEND // Item size increased.
|
||||
#define UKKQueueNotifyAboutLinkCountChanged NOTE_LINK // Item's link count changed.
|
||||
#define UKKQueueNotifyAboutAccessRevocation NOTE_REVOKE // Access to item was revoked.
|
||||
|
||||
// Notifications this sends:
|
||||
// (see UKFileWatcher)
|
||||
// Old names: *deprecated*
|
||||
#if UKKQUEUE_OLD_NOTIFICATION_NAMES
|
||||
#define UKKQueueFileRenamedNotification UKFileWatcherRenameNotification
|
||||
#define UKKQueueFileWrittenToNotification UKFileWatcherWriteNotification
|
||||
#define UKKQueueFileDeletedNotification UKFileWatcherDeleteNotification
|
||||
#define UKKQueueFileAttributesChangedNotification UKFileWatcherAttributeChangeNotification
|
||||
#define UKKQueueFileSizeIncreasedNotification UKFileWatcherSizeIncreaseNotification
|
||||
#define UKKQueueFileLinkCountChangedNotification UKFileWatcherLinkCountChangeNotification
|
||||
#define UKKQueueFileAccessRevocationNotification UKFileWatcherAccessRevocationNotification
|
||||
#endif
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// UKKQueue:
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
@interface UKKQueue : NSObject <UKFileWatcher>
|
||||
{
|
||||
int queueFD; // The actual queue ID (Unix file descriptor).
|
||||
NSMutableArray* watchedPaths; // List of NSStrings containing the paths we're watching.
|
||||
NSMutableArray* watchedFDs; // List of NSNumbers containing the file descriptors we're watching.
|
||||
id delegate; // Gets messages about changes instead of notification center, if specified.
|
||||
id delegateProxy; // Proxy object to which we send messages so they reach delegate on the main thread.
|
||||
BOOL alwaysNotify; // Send notifications even if we have a delegate? Defaults to NO.
|
||||
BOOL keepThreadRunning; // Termination criterion of our thread.
|
||||
}
|
||||
|
||||
+(id) sharedFileWatcher; // Returns a singleton, a shared kqueue object Handy if you're subscribing to the notifications. Use this, or just create separate objects using alloc/init. Whatever floats your boat.
|
||||
|
||||
-(int) queueFD; // I know you unix geeks want this...
|
||||
|
||||
// High-level file watching: (use UKFileWatcher protocol methods instead, where possible!)
|
||||
-(void) addPathToQueue: (NSString*)path;
|
||||
-(void) addPathToQueue: (NSString*)path notifyingAbout: (u_int)fflags;
|
||||
-(void) removePathFromQueue: (NSString*)path;
|
||||
|
||||
-(id) delegate;
|
||||
-(void) setDelegate: (id)newDelegate;
|
||||
|
||||
-(BOOL) alwaysNotify;
|
||||
-(void) setAlwaysNotify: (BOOL)n;
|
||||
|
||||
#if UKKQUEUE_OLD_SINGLETON_ACCESSOR_NAME
|
||||
+(UKKQueue*) sharedQueue;
|
||||
#endif
|
||||
|
||||
// private:
|
||||
-(void) watcherThread: (id)sender;
|
||||
-(void) postNotification: (NSString*)nm forFile: (NSString*)fp; // Message-posting bottleneck.
|
||||
|
||||
@end
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Methods delegates need to provide:
|
||||
// * DEPRECATED * use UKFileWatcher delegate methods instead!
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
@interface NSObject (UKKQueueDelegate)
|
||||
|
||||
-(void) kqueue: (UKKQueue*)kq receivedNotification: (NSString*)nm forFile: (NSString*)fpath;
|
||||
|
||||
@end
|
||||
@@ -1,501 +0,0 @@
|
||||
/* =============================================================================
|
||||
FILE: UKKQueue.m
|
||||
PROJECT: Filie
|
||||
|
||||
COPYRIGHT: (c) 2003 M. Uli Kusterer, all rights reserved.
|
||||
|
||||
AUTHORS: M. Uli Kusterer - UK
|
||||
|
||||
LICENSES: MIT License
|
||||
|
||||
REVISIONS:
|
||||
2006-03-13 UK Clarified license, streamlined UKFileWatcher stuff,
|
||||
Changed notifications to be useful and turned off by
|
||||
default some deprecated stuff.
|
||||
2004-12-28 UK Several threading fixes.
|
||||
2003-12-21 UK Created.
|
||||
========================================================================== */
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Headers:
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
#import "UKKQueue.h"
|
||||
#import "UKMainThreadProxy.h"
|
||||
#import <unistd.h>
|
||||
#import <fcntl.h>
|
||||
#import <sys/param.h>
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Macros:
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// @synchronized isn't available prior to 10.3, so we use a typedef so
|
||||
// this class is thread-safe on Panther but still compiles on older OSs.
|
||||
|
||||
#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_3
|
||||
#define AT_SYNCHRONIZED(n) @synchronized(n)
|
||||
#else
|
||||
#define AT_SYNCHRONIZED(n)
|
||||
#endif
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Globals:
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
static UKKQueue * gUKKQueueSharedQueueSingleton = nil;
|
||||
|
||||
|
||||
@implementation UKKQueue
|
||||
|
||||
// Deprecated:
|
||||
#if UKKQUEUE_OLD_SINGLETON_ACCESSOR_NAME
|
||||
+(UKKQueue*) sharedQueue
|
||||
{
|
||||
return [self sharedFileWatcher];
|
||||
}
|
||||
#endif
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// sharedQueue:
|
||||
// Returns a singleton queue object. In many apps (especially those that
|
||||
// subscribe to the notifications) there will only be one kqueue instance,
|
||||
// and in that case you can use this.
|
||||
//
|
||||
// For all other cases, feel free to create additional instances to use
|
||||
// independently.
|
||||
//
|
||||
// REVISIONS:
|
||||
// 2006-03-13 UK Renamed from sharedQueue.
|
||||
// 2005-07-02 UK Created.
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
+(id) sharedFileWatcher
|
||||
{
|
||||
AT_SYNCHRONIZED( self )
|
||||
{
|
||||
if( !gUKKQueueSharedQueueSingleton )
|
||||
gUKKQueueSharedQueueSingleton = [[UKKQueue alloc] init]; // This is a singleton, and thus an intentional "leak".
|
||||
}
|
||||
|
||||
return gUKKQueueSharedQueueSingleton;
|
||||
}
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// * CONSTRUCTOR:
|
||||
// Creates a new KQueue and starts that thread we use for our
|
||||
// notifications.
|
||||
//
|
||||
// REVISIONS:
|
||||
// 2004-11-12 UK Doesn't pass self as parameter to watcherThread anymore,
|
||||
// because detachNewThreadSelector retains target and args,
|
||||
// which would cause us to never be released.
|
||||
// 2004-03-13 UK Documented.
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
-(id) init
|
||||
{
|
||||
self = [super init];
|
||||
if( self )
|
||||
{
|
||||
queueFD = kqueue();
|
||||
if( queueFD == -1 )
|
||||
{
|
||||
[self release];
|
||||
return nil;
|
||||
}
|
||||
|
||||
watchedPaths = [[NSMutableArray alloc] init];
|
||||
watchedFDs = [[NSMutableArray alloc] init];
|
||||
|
||||
// Start new thread that fetches and processes our events:
|
||||
keepThreadRunning = YES;
|
||||
[NSThread detachNewThreadSelector:@selector(watcherThread:) toTarget:self withObject:nil];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// release:
|
||||
// Since NSThread retains its target, we need this method to terminate the
|
||||
// thread when we reach a retain-count of two. The thread is terminated by
|
||||
// setting keepThreadRunning to NO.
|
||||
//
|
||||
// REVISIONS:
|
||||
// 2004-11-12 UK Created.
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
-(oneway void) release
|
||||
{
|
||||
AT_SYNCHRONIZED(self)
|
||||
{
|
||||
//NSLog(@"%@ (%d)", self, [self retainCount]);
|
||||
if( [self retainCount] == 2 && keepThreadRunning )
|
||||
keepThreadRunning = NO;
|
||||
}
|
||||
|
||||
[super release];
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// * DESTRUCTOR:
|
||||
// Releases the kqueue again.
|
||||
//
|
||||
// REVISIONS:
|
||||
// 2004-03-13 UK Documented.
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
-(void) dealloc
|
||||
{
|
||||
delegate = nil;
|
||||
[delegateProxy release];
|
||||
|
||||
if( keepThreadRunning )
|
||||
keepThreadRunning = NO;
|
||||
|
||||
// Close all our file descriptors so the files can be deleted:
|
||||
NSEnumerator* enny = [watchedFDs objectEnumerator];
|
||||
NSNumber* fdNum;
|
||||
while( (fdNum = [enny nextObject]) )
|
||||
{
|
||||
if( close( [fdNum intValue] ) == -1 )
|
||||
NSLog(@"dealloc: Couldn't close file descriptor (%d)", errno);
|
||||
}
|
||||
|
||||
[watchedPaths release];
|
||||
watchedPaths = nil;
|
||||
[watchedFDs release];
|
||||
watchedFDs = nil;
|
||||
|
||||
[super dealloc];
|
||||
|
||||
//NSLog(@"kqueue released.");
|
||||
}
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// queueFD:
|
||||
// Returns a Unix file descriptor for the KQueue this uses. The descriptor
|
||||
// is owned by this object. Do not close it!
|
||||
//
|
||||
// REVISIONS:
|
||||
// 2004-03-13 UK Documented.
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
-(int) queueFD
|
||||
{
|
||||
return queueFD;
|
||||
}
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// addPathToQueue:
|
||||
// Tell this queue to listen for all interesting notifications sent for
|
||||
// the object at the specified path. If you want more control, use the
|
||||
// addPathToQueue:notifyingAbout: variant instead.
|
||||
//
|
||||
// REVISIONS:
|
||||
// 2004-03-13 UK Documented.
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
-(void) addPathToQueue: (NSString*)path
|
||||
{
|
||||
[self addPath: path];
|
||||
}
|
||||
|
||||
|
||||
-(void) addPath: (NSString*)path
|
||||
{
|
||||
[self addPathToQueue: path notifyingAbout: UKKQueueNotifyAboutRename
|
||||
| UKKQueueNotifyAboutWrite
|
||||
| UKKQueueNotifyAboutDelete
|
||||
| UKKQueueNotifyAboutAttributeChange];
|
||||
}
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// addPathToQueue:notfyingAbout:
|
||||
// Tell this queue to listen for the specified notifications sent for
|
||||
// the object at the specified path.
|
||||
//
|
||||
// REVISIONS:
|
||||
// 2005-06-29 UK Files are now opened using O_EVTONLY instead of O_RDONLY
|
||||
// which allows ejecting or deleting watched files/folders.
|
||||
// Thanks to Phil Hargett for finding this flag in the docs.
|
||||
// 2004-03-13 UK Documented.
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
-(void) addPathToQueue: (NSString*)path notifyingAbout: (u_int)fflags
|
||||
{
|
||||
struct timespec nullts = { 0, 0 };
|
||||
struct kevent ev;
|
||||
int fd = open( [path fileSystemRepresentation], O_EVTONLY, 0 );
|
||||
|
||||
if( fd >= 0 )
|
||||
{
|
||||
EV_SET( &ev, fd, EVFILT_VNODE,
|
||||
EV_ADD | EV_ENABLE | EV_CLEAR,
|
||||
fflags, 0, (void*)path );
|
||||
|
||||
AT_SYNCHRONIZED( self )
|
||||
{
|
||||
[watchedPaths addObject: path];
|
||||
[watchedFDs addObject: [NSNumber numberWithInt: fd]];
|
||||
kevent( queueFD, &ev, 1, NULL, 0, &nullts );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
-(void) removePath: (NSString*)path
|
||||
{
|
||||
[self removePathFromQueue: path];
|
||||
}
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// removePathFromQueue:
|
||||
// Stop listening for changes to the specified path. This removes all
|
||||
// notifications. Use this to balance both addPathToQueue:notfyingAbout:
|
||||
// as well as addPathToQueue:.
|
||||
//
|
||||
// REVISIONS:
|
||||
// 2004-03-13 UK Documented.
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
-(void) removePathFromQueue: (NSString*)path
|
||||
{
|
||||
NSUInteger index = 0;
|
||||
int fd = -1;
|
||||
|
||||
AT_SYNCHRONIZED( self )
|
||||
{
|
||||
index = [watchedPaths indexOfObject: path];
|
||||
|
||||
if( index == NSNotFound )
|
||||
return;
|
||||
|
||||
fd = [[watchedFDs objectAtIndex: index] intValue];
|
||||
|
||||
[watchedFDs removeObjectAtIndex: index];
|
||||
[watchedPaths removeObjectAtIndex: index];
|
||||
}
|
||||
|
||||
if( close( fd ) == -1 )
|
||||
NSLog(@"removePathFromQueue: Couldn't close file descriptor (%d)", errno);
|
||||
}
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// removeAllPathsFromQueue:
|
||||
// Stop listening for changes to all paths. This removes all
|
||||
// notifications.
|
||||
//
|
||||
// REVISIONS:
|
||||
// 2004-12-28 UK Added as suggested by bbum.
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
-(void) removeAllPathsFromQueue;
|
||||
{
|
||||
AT_SYNCHRONIZED( self )
|
||||
{
|
||||
NSEnumerator * fdEnumerator = [watchedFDs objectEnumerator];
|
||||
NSNumber * anFD;
|
||||
|
||||
while( (anFD = [fdEnumerator nextObject]) != nil )
|
||||
close( [anFD intValue] );
|
||||
|
||||
[watchedFDs removeAllObjects];
|
||||
[watchedPaths removeAllObjects];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// watcherThread:
|
||||
// This method is called by our NSThread to loop and poll for any file
|
||||
// changes that our kqueue wants to tell us about. This sends separate
|
||||
// notifications for the different kinds of changes that can happen.
|
||||
// All messages are sent via the postNotification:forFile: main bottleneck.
|
||||
//
|
||||
// This also calls sharedWorkspace's noteFileSystemChanged.
|
||||
//
|
||||
// To terminate this method (and its thread), set keepThreadRunning to NO.
|
||||
//
|
||||
// REVISIONS:
|
||||
// 2005-08-27 UK Changed to use keepThreadRunning instead of kqueueFD
|
||||
// being -1 as termination criterion, and to close the
|
||||
// queue in this thread so the main thread isn't blocked.
|
||||
// 2004-11-12 UK Fixed docs to include termination criterion, added
|
||||
// timeout to make sure the bugger gets disposed.
|
||||
// 2004-03-13 UK Documented.
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
-(void) watcherThread: (id)sender
|
||||
{
|
||||
int n;
|
||||
struct kevent ev;
|
||||
struct timespec timeout = { 5, 0 }; // 5 seconds timeout.
|
||||
int theFD = queueFD; // So we don't have to risk accessing iVars when the thread is terminated.
|
||||
|
||||
while( keepThreadRunning )
|
||||
{
|
||||
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
|
||||
|
||||
NS_DURING
|
||||
n = kevent( queueFD, NULL, 0, &ev, 1, &timeout );
|
||||
if( n > 0 )
|
||||
{
|
||||
if( ev.filter == EVFILT_VNODE )
|
||||
{
|
||||
if( ev.fflags )
|
||||
{
|
||||
NSString* fpath = [[(NSString *)ev.udata retain] autorelease]; // In case one of the notified folks removes the path.
|
||||
//NSLog(@"UKKQueue: Detected file change: %@", fpath);
|
||||
[[NSWorkspace sharedWorkspace] noteFileSystemChanged: fpath];
|
||||
|
||||
//NSLog(@"ev.flags = %u",ev.fflags); // DEBUG ONLY!
|
||||
|
||||
if( (ev.fflags & NOTE_RENAME) == NOTE_RENAME ) {
|
||||
char path[MAXPATHLEN];
|
||||
fcntl((int)ev.ident, F_GETPATH, &path);
|
||||
[self postNotification: UKFileWatcherRenameNotification forFile: [NSString stringWithUTF8String:path]];
|
||||
}
|
||||
if( (ev.fflags & NOTE_WRITE) == NOTE_WRITE ) {
|
||||
[self postNotification: UKFileWatcherWriteNotification forFile: fpath];
|
||||
}
|
||||
if( (ev.fflags & NOTE_DELETE) == NOTE_DELETE ) {
|
||||
[self removePathFromQueue:fpath];
|
||||
int newFD = open( [fpath fileSystemRepresentation], O_EVTONLY, 0 );
|
||||
if (newFD == -1) {
|
||||
// It's really a delete
|
||||
[self postNotification: UKFileWatcherDeleteNotification forFile: fpath];
|
||||
}
|
||||
else {
|
||||
// Probably an atomic write, readd to the queue.
|
||||
close(newFD);
|
||||
[self addPathToQueue:fpath];
|
||||
[self postNotification: UKFileWatcherWriteNotification forFile: fpath];
|
||||
[self postNotification: UKFileWatcherAttributeChangeNotification forFile: fpath];
|
||||
}
|
||||
}
|
||||
if( (ev.fflags & NOTE_ATTRIB) == NOTE_ATTRIB ) {
|
||||
[self postNotification: UKFileWatcherAttributeChangeNotification forFile: fpath];
|
||||
}
|
||||
if( (ev.fflags & NOTE_EXTEND) == NOTE_EXTEND ) {
|
||||
[self postNotification: UKFileWatcherSizeIncreaseNotification forFile: fpath];
|
||||
}
|
||||
if( (ev.fflags & NOTE_LINK) == NOTE_LINK ) {
|
||||
[self postNotification: UKFileWatcherLinkCountChangeNotification forFile: fpath];
|
||||
}
|
||||
if( (ev.fflags & NOTE_REVOKE) == NOTE_REVOKE ) {
|
||||
[self postNotification: UKFileWatcherAccessRevocationNotification forFile: fpath];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
NS_HANDLER
|
||||
NSLog(@"Error in UKKQueue watcherThread: %@",localException);
|
||||
NS_ENDHANDLER
|
||||
|
||||
[pool release];
|
||||
}
|
||||
|
||||
// Close our kqueue's file descriptor:
|
||||
if( close( theFD ) == -1 )
|
||||
NSLog(@"release: Couldn't close main kqueue (%d)", errno);
|
||||
|
||||
//NSLog(@"exiting kqueue watcher thread.");
|
||||
}
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// postNotification:forFile:
|
||||
// This is the main bottleneck for posting notifications. If you don't want
|
||||
// the notifications to go through NSWorkspace, override this method and
|
||||
// send them elsewhere.
|
||||
//
|
||||
// REVISIONS:
|
||||
// 2004-02-27 UK Changed this to send new notification, and the old one
|
||||
// only to objects that respond to it. The old category on
|
||||
// NSObject could cause problems with the proxy itself.
|
||||
// 2004-10-31 UK Helloween fun: Make this use a mainThreadProxy and
|
||||
// allow sending the notification even if we have a
|
||||
// delegate.
|
||||
// 2004-03-13 UK Documented.
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
-(void) postNotification: (NSString*)nm forFile: (NSString*)fp
|
||||
{
|
||||
if( delegateProxy )
|
||||
{
|
||||
#if UKKQUEUE_BACKWARDS_COMPATIBLE
|
||||
if( ![delegateProxy respondsToSelector: @selector(watcher:receivedNotification:forPath:)] )
|
||||
[delegateProxy kqueue: self receivedNotification: nm forFile: fp];
|
||||
else
|
||||
#endif
|
||||
[delegateProxy watcher: self receivedNotification: nm forPath: fp];
|
||||
}
|
||||
|
||||
if( !delegateProxy || alwaysNotify )
|
||||
{
|
||||
#if UKKQUEUE_SEND_STUPID_NOTIFICATIONS
|
||||
[[[NSWorkspace sharedWorkspace] notificationCenter] postNotificationName: nm object: fp];
|
||||
#else
|
||||
[[[NSWorkspace sharedWorkspace] notificationCenter] postNotificationName: nm object: self
|
||||
userInfo: [NSDictionary dictionaryWithObjectsAndKeys: fp, @"path", nil]];
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
-(id) delegate
|
||||
{
|
||||
return delegate;
|
||||
}
|
||||
|
||||
-(void) setDelegate: (id)newDelegate
|
||||
{
|
||||
id oldProxy = delegateProxy;
|
||||
delegate = newDelegate;
|
||||
delegateProxy = [delegate copyMainThreadProxy];
|
||||
[oldProxy release];
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Flag to send a notification even if we have a delegate:
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
-(BOOL) alwaysNotify
|
||||
{
|
||||
return alwaysNotify;
|
||||
}
|
||||
|
||||
|
||||
-(void) setAlwaysNotify: (BOOL)n
|
||||
{
|
||||
alwaysNotify = n;
|
||||
}
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// description:
|
||||
// This method can be used to help in debugging. It provides the value
|
||||
// used by NSLog & co. when you request to print this object using the
|
||||
// %@ format specifier.
|
||||
//
|
||||
// REVISIONS:
|
||||
// 2004-11-12 UK Created.
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
-(NSString*) description
|
||||
{
|
||||
return [NSString stringWithFormat: @"%@ { watchedPaths = %@, alwaysNotify = %@ }", NSStringFromClass([self class]), watchedPaths, (alwaysNotify? @"YES" : @"NO") ];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@@ -1,56 +0,0 @@
|
||||
/* =============================================================================
|
||||
FILE: UKMainThreadProxy.h
|
||||
PROJECT: UKMainThreadProxy
|
||||
|
||||
PURPOSE: Send a message to object theObject to [theObject mainThreadProxy]
|
||||
instead and the message will be received on the main thread by
|
||||
theObject.
|
||||
|
||||
COPYRIGHT: (c) 2004 M. Uli Kusterer, all rights reserved.
|
||||
|
||||
AUTHORS: M. Uli Kusterer - UK
|
||||
|
||||
LICENSES: MIT License
|
||||
|
||||
REVISIONS:
|
||||
2006-03-13 UK Clarified license.
|
||||
2004-10-14 UK Created.
|
||||
========================================================================== */
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Headers:
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Categories:
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
@interface NSObject (UKMainThreadProxy)
|
||||
|
||||
-(id) mainThreadProxy; // You can't init or release this object.
|
||||
-(id) copyMainThreadProxy; // Gives you a retained version.
|
||||
|
||||
@end
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Classes:
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
/*
|
||||
This object is created as a proxy in a second thread for an existing object.
|
||||
All messages you send to this object will automatically be sent to the other
|
||||
object on the main thread, except NSObject methods like retain/release etc.
|
||||
*/
|
||||
|
||||
@interface UKMainThreadProxy : NSObject
|
||||
{
|
||||
IBOutlet id target;
|
||||
}
|
||||
|
||||
-(id) initWithTarget: (id)targ;
|
||||
|
||||
@end
|
||||
@@ -1,151 +0,0 @@
|
||||
/* =============================================================================
|
||||
FILE: UKMainThreadProxy.h
|
||||
PROJECT: UKMainThreadProxy
|
||||
|
||||
PURPOSE: Send a message to object theObject to [theObject mainThreadProxy]
|
||||
instead and the message will be received on the main thread by
|
||||
theObject.
|
||||
|
||||
COPYRIGHT: (c) 2004 M. Uli Kusterer, all rights reserved.
|
||||
|
||||
AUTHORS: M. Uli Kusterer - UK
|
||||
|
||||
LICENSES: MIT Licenseâ
|
||||
|
||||
REVISIONS:
|
||||
2006-03-13 UK Clarified license.
|
||||
2004-10-14 UK Created.
|
||||
========================================================================== */
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Headers:
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
#import "UKMainThreadProxy.h"
|
||||
|
||||
|
||||
@implementation UKMainThreadProxy
|
||||
|
||||
-(id) initWithTarget: (id)targ
|
||||
{
|
||||
self = [super init];
|
||||
if( self )
|
||||
target = targ;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Introspection overrides:
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
-(BOOL) respondsToSelector: (SEL)itemAction
|
||||
{
|
||||
BOOL does = [super respondsToSelector: itemAction];
|
||||
|
||||
return( does || [target respondsToSelector: itemAction] );
|
||||
}
|
||||
|
||||
|
||||
-(id) performSelector: (SEL)itemAction
|
||||
{
|
||||
BOOL does = [super respondsToSelector: itemAction];
|
||||
if( does )
|
||||
return [super performSelector: itemAction];
|
||||
|
||||
if( ![target respondsToSelector: itemAction] )
|
||||
[self doesNotRecognizeSelector: itemAction];
|
||||
|
||||
[target retain];
|
||||
[target performSelectorOnMainThread: itemAction withObject: nil waitUntilDone: YES];
|
||||
[target release];
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
|
||||
-(id) performSelector: (SEL)itemAction withObject: (id)obj
|
||||
{
|
||||
BOOL does = [super respondsToSelector: itemAction];
|
||||
if( does )
|
||||
return [super performSelector: itemAction withObject: obj];
|
||||
|
||||
if( ![target respondsToSelector: itemAction] )
|
||||
[self doesNotRecognizeSelector: itemAction];
|
||||
|
||||
[target retain];
|
||||
[obj retain];
|
||||
[target performSelectorOnMainThread: itemAction withObject: obj waitUntilDone: YES];
|
||||
[obj release];
|
||||
[target release];
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Forwarding unknown methods to the target:
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
-(NSMethodSignature*) methodSignatureForSelector: (SEL)itemAction
|
||||
{
|
||||
NSMethodSignature* sig = [super methodSignatureForSelector: itemAction];
|
||||
|
||||
if( sig )
|
||||
return sig;
|
||||
|
||||
return [target methodSignatureForSelector: itemAction];
|
||||
}
|
||||
|
||||
-(void) forwardInvocation: (NSInvocation*)invocation
|
||||
{
|
||||
SEL itemAction = [invocation selector];
|
||||
|
||||
if( [target respondsToSelector: itemAction] )
|
||||
{
|
||||
[invocation retainArguments];
|
||||
[target retain];
|
||||
[invocation performSelectorOnMainThread: @selector(invokeWithTarget:) withObject: target waitUntilDone: YES];
|
||||
[target release];
|
||||
}
|
||||
else
|
||||
[self doesNotRecognizeSelector: itemAction];
|
||||
}
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Safety net:
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
-(id) mainThreadProxy // Just in case someone accidentally sends this message to a main thread proxy.
|
||||
{
|
||||
return self;
|
||||
}
|
||||
|
||||
-(id) copyMainThreadProxy // Just in case someone accidentally sends this message to a main thread proxy.
|
||||
{
|
||||
return [self retain];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Shorthand notation for getting a main thread proxy:
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
@implementation NSObject (UKMainThreadProxy)
|
||||
|
||||
-(id) mainThreadProxy
|
||||
{
|
||||
return [[[UKMainThreadProxy alloc] initWithTarget: self] autorelease];
|
||||
}
|
||||
|
||||
-(id) copyMainThreadProxy
|
||||
{
|
||||
return [[UKMainThreadProxy alloc] initWithTarget: self];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
/* Localized versions of Info.plist keys */
|
||||
|
||||
@@ -1,380 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<archive type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="8.00">
|
||||
<data>
|
||||
<int key="IBDocument.SystemTarget">1070</int>
|
||||
<string key="IBDocument.SystemVersion">11C74</string>
|
||||
<string key="IBDocument.InterfaceBuilderVersion">1938</string>
|
||||
<string key="IBDocument.AppKitVersion">1138.23</string>
|
||||
<string key="IBDocument.HIToolboxVersion">567.00</string>
|
||||
<object class="NSMutableDictionary" key="IBDocument.PluginVersions">
|
||||
<string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string key="NS.object.0">1938</string>
|
||||
</object>
|
||||
<array key="IBDocument.IntegratedClassDependencies">
|
||||
<string>NSMenu</string>
|
||||
<string>NSMenuItem</string>
|
||||
<string>NSCustomObject</string>
|
||||
</array>
|
||||
<array key="IBDocument.PluginDependencies">
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
</array>
|
||||
<object class="NSMutableDictionary" key="IBDocument.Metadata">
|
||||
<string key="NS.key.0">PluginDependencyRecalculationVersion</string>
|
||||
<integer value="1" key="NS.object.0"/>
|
||||
</object>
|
||||
<array class="NSMutableArray" key="IBDocument.RootObjects" id="1048">
|
||||
<object class="NSCustomObject" id="1021">
|
||||
<string key="NSClassName">AtomApp</string>
|
||||
</object>
|
||||
<object class="NSCustomObject" id="1014">
|
||||
<string key="NSClassName">FirstResponder</string>
|
||||
</object>
|
||||
<object class="NSCustomObject" id="1050">
|
||||
<string key="NSClassName">AtomApp</string>
|
||||
</object>
|
||||
<object class="NSMenu" id="649796088">
|
||||
<string key="NSTitle">AMainMenu</string>
|
||||
<array class="NSMutableArray" key="NSMenuItems">
|
||||
<object class="NSMenuItem" id="694149608">
|
||||
<reference key="NSMenu" ref="649796088"/>
|
||||
<string key="NSTitle">Atom</string>
|
||||
<string key="NSKeyEquiv"/>
|
||||
<int key="NSKeyEquivModMask">1048576</int>
|
||||
<int key="NSMnemonicLoc">2147483647</int>
|
||||
<object class="NSCustomResource" key="NSOnImage" id="35465992">
|
||||
<string key="NSClassName">NSImage</string>
|
||||
<string key="NSResourceName">NSMenuCheckmark</string>
|
||||
</object>
|
||||
<object class="NSCustomResource" key="NSMixedImage" id="502551668">
|
||||
<string key="NSClassName">NSImage</string>
|
||||
<string key="NSResourceName">NSMenuMixedState</string>
|
||||
</object>
|
||||
<string key="NSAction">submenuAction:</string>
|
||||
<object class="NSMenu" key="NSSubmenu" id="110575045">
|
||||
<string key="NSTitle">Atom</string>
|
||||
<array class="NSMutableArray" key="NSMenuItems">
|
||||
<object class="NSMenuItem" id="208934156">
|
||||
<reference key="NSMenu" ref="110575045"/>
|
||||
<string key="NSTitle">Run Specs</string>
|
||||
<string key="NSKeyEquiv">s</string>
|
||||
<int key="NSKeyEquivModMask">1835008</int>
|
||||
<int key="NSMnemonicLoc">2147483647</int>
|
||||
<reference key="NSOnImage" ref="35465992"/>
|
||||
<reference key="NSMixedImage" ref="502551668"/>
|
||||
</object>
|
||||
<object class="NSMenuItem" id="632727374">
|
||||
<reference key="NSMenu" ref="110575045"/>
|
||||
<string key="NSTitle">Quit Atom</string>
|
||||
<string key="NSKeyEquiv">q</string>
|
||||
<int key="NSKeyEquivModMask">1048576</int>
|
||||
<int key="NSMnemonicLoc">2147483647</int>
|
||||
<reference key="NSOnImage" ref="35465992"/>
|
||||
<reference key="NSMixedImage" ref="502551668"/>
|
||||
</object>
|
||||
</array>
|
||||
<string key="NSName">_NSAppleMenu</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="NSMenuItem" id="379814623">
|
||||
<reference key="NSMenu" ref="649796088"/>
|
||||
<string key="NSTitle">File</string>
|
||||
<string key="NSKeyEquiv"/>
|
||||
<int key="NSKeyEquivModMask">1048576</int>
|
||||
<int key="NSMnemonicLoc">2147483647</int>
|
||||
<reference key="NSOnImage" ref="35465992"/>
|
||||
<reference key="NSMixedImage" ref="502551668"/>
|
||||
<string key="NSAction">submenuAction:</string>
|
||||
<object class="NSMenu" key="NSSubmenu" id="720053764">
|
||||
<string key="NSTitle">File</string>
|
||||
<array class="NSMutableArray" key="NSMenuItems">
|
||||
<object class="NSMenuItem" id="705341025">
|
||||
<reference key="NSMenu" ref="720053764"/>
|
||||
<string key="NSTitle">New</string>
|
||||
<string key="NSKeyEquiv">n</string>
|
||||
<int key="NSKeyEquivModMask">1048576</int>
|
||||
<int key="NSMnemonicLoc">2147483647</int>
|
||||
<reference key="NSOnImage" ref="35465992"/>
|
||||
<reference key="NSMixedImage" ref="502551668"/>
|
||||
</object>
|
||||
<object class="NSMenuItem" id="722745758">
|
||||
<reference key="NSMenu" ref="720053764"/>
|
||||
<string key="NSTitle">Open…</string>
|
||||
<string key="NSKeyEquiv">o</string>
|
||||
<int key="NSKeyEquivModMask">1048576</int>
|
||||
<int key="NSMnemonicLoc">2147483647</int>
|
||||
<reference key="NSOnImage" ref="35465992"/>
|
||||
<reference key="NSMixedImage" ref="502551668"/>
|
||||
</object>
|
||||
</array>
|
||||
</object>
|
||||
</object>
|
||||
</array>
|
||||
<string key="NSName">_NSMainMenu</string>
|
||||
</object>
|
||||
<object class="NSCustomObject" id="755631768">
|
||||
<string key="NSClassName">NSFontManager</string>
|
||||
</object>
|
||||
</array>
|
||||
<object class="IBObjectContainer" key="IBDocument.Objects">
|
||||
<array class="NSMutableArray" key="connectionRecords">
|
||||
<object class="IBConnectionRecord">
|
||||
<object class="IBActionConnection" key="connection">
|
||||
<string key="label">terminate:</string>
|
||||
<reference key="source" ref="1050"/>
|
||||
<reference key="destination" ref="632727374"/>
|
||||
</object>
|
||||
<int key="connectionID">449</int>
|
||||
</object>
|
||||
<object class="IBConnectionRecord">
|
||||
<object class="IBOutletConnection" key="connection">
|
||||
<string key="label">delegate</string>
|
||||
<reference key="source" ref="1021"/>
|
||||
<reference key="destination" ref="1050"/>
|
||||
</object>
|
||||
<int key="connectionID">536</int>
|
||||
</object>
|
||||
<object class="IBConnectionRecord">
|
||||
<object class="IBActionConnection" key="connection">
|
||||
<string key="label">runSpecs:</string>
|
||||
<reference key="source" ref="1021"/>
|
||||
<reference key="destination" ref="208934156"/>
|
||||
</object>
|
||||
<int key="connectionID">541</int>
|
||||
</object>
|
||||
<object class="IBConnectionRecord">
|
||||
<object class="IBActionConnection" key="connection">
|
||||
<string key="label">openNewWindow:</string>
|
||||
<reference key="source" ref="1021"/>
|
||||
<reference key="destination" ref="705341025"/>
|
||||
</object>
|
||||
<int key="connectionID">545</int>
|
||||
</object>
|
||||
<object class="IBConnectionRecord">
|
||||
<object class="IBActionConnection" key="connection">
|
||||
<string key="label">openPathInNewWindow:</string>
|
||||
<reference key="source" ref="1021"/>
|
||||
<reference key="destination" ref="722745758"/>
|
||||
</object>
|
||||
<int key="connectionID">547</int>
|
||||
</object>
|
||||
</array>
|
||||
<object class="IBMutableOrderedSet" key="objectRecords">
|
||||
<array key="orderedObjects">
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">0</int>
|
||||
<array key="object" id="0"/>
|
||||
<reference key="children" ref="1048"/>
|
||||
<nil key="parent"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">-2</int>
|
||||
<reference key="object" ref="1021"/>
|
||||
<reference key="parent" ref="0"/>
|
||||
<string key="objectName">File's Owner</string>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">-1</int>
|
||||
<reference key="object" ref="1014"/>
|
||||
<reference key="parent" ref="0"/>
|
||||
<string key="objectName">First Responder</string>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">-3</int>
|
||||
<reference key="object" ref="1050"/>
|
||||
<reference key="parent" ref="0"/>
|
||||
<string key="objectName">Application</string>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">29</int>
|
||||
<reference key="object" ref="649796088"/>
|
||||
<array class="NSMutableArray" key="children">
|
||||
<reference ref="694149608"/>
|
||||
<reference ref="379814623"/>
|
||||
</array>
|
||||
<reference key="parent" ref="0"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">56</int>
|
||||
<reference key="object" ref="694149608"/>
|
||||
<array class="NSMutableArray" key="children">
|
||||
<reference ref="110575045"/>
|
||||
</array>
|
||||
<reference key="parent" ref="649796088"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">83</int>
|
||||
<reference key="object" ref="379814623"/>
|
||||
<array class="NSMutableArray" key="children">
|
||||
<reference ref="720053764"/>
|
||||
</array>
|
||||
<reference key="parent" ref="649796088"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">81</int>
|
||||
<reference key="object" ref="720053764"/>
|
||||
<array class="NSMutableArray" key="children">
|
||||
<reference ref="722745758"/>
|
||||
<reference ref="705341025"/>
|
||||
</array>
|
||||
<reference key="parent" ref="379814623"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">72</int>
|
||||
<reference key="object" ref="722745758"/>
|
||||
<reference key="parent" ref="720053764"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">82</int>
|
||||
<reference key="object" ref="705341025"/>
|
||||
<reference key="parent" ref="720053764"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">57</int>
|
||||
<reference key="object" ref="110575045"/>
|
||||
<array class="NSMutableArray" key="children">
|
||||
<reference ref="632727374"/>
|
||||
<reference ref="208934156"/>
|
||||
</array>
|
||||
<reference key="parent" ref="694149608"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">136</int>
|
||||
<reference key="object" ref="632727374"/>
|
||||
<reference key="parent" ref="110575045"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">420</int>
|
||||
<reference key="object" ref="755631768"/>
|
||||
<reference key="parent" ref="0"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">537</int>
|
||||
<reference key="object" ref="208934156"/>
|
||||
<reference key="parent" ref="110575045"/>
|
||||
</object>
|
||||
</array>
|
||||
</object>
|
||||
<dictionary class="NSMutableDictionary" key="flattenedProperties">
|
||||
<string key="-1.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string key="-2.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string key="-3.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string key="136.CustomClassName">AtomMenuItem</string>
|
||||
<object class="NSMutableDictionary" key="136.IBAttributePlaceholdersKey">
|
||||
<string key="NS.key.0">IBUserDefinedRuntimeAttributesPlaceholderName</string>
|
||||
<object class="IBUserDefinedRuntimeAttributesPlaceholder" key="NS.object.0">
|
||||
<string key="name">IBUserDefinedRuntimeAttributesPlaceholderName</string>
|
||||
<reference key="object" ref="632727374"/>
|
||||
<array key="userDefinedRuntimeAttributes">
|
||||
<object class="IBUserDefinedRuntimeAttribute">
|
||||
<string key="typeIdentifier">com.apple.InterfaceBuilder.userDefinedRuntimeAttributeType.boolean</string>
|
||||
<string key="keyPath">global</string>
|
||||
<boolean value="YES" key="value"/>
|
||||
</object>
|
||||
</array>
|
||||
</object>
|
||||
</object>
|
||||
<string key="136.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string key="29.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string key="420.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string key="537.CustomClassName">AtomMenuItem</string>
|
||||
<object class="NSMutableDictionary" key="537.IBAttributePlaceholdersKey">
|
||||
<string key="NS.key.0">IBUserDefinedRuntimeAttributesPlaceholderName</string>
|
||||
<object class="IBUserDefinedRuntimeAttributesPlaceholder" key="NS.object.0">
|
||||
<string key="name">IBUserDefinedRuntimeAttributesPlaceholderName</string>
|
||||
<reference key="object" ref="208934156"/>
|
||||
<array key="userDefinedRuntimeAttributes">
|
||||
<object class="IBUserDefinedRuntimeAttribute">
|
||||
<string key="typeIdentifier">com.apple.InterfaceBuilder.userDefinedRuntimeAttributeType.boolean</string>
|
||||
<string key="keyPath">global</string>
|
||||
<boolean value="YES" key="value"/>
|
||||
</object>
|
||||
</array>
|
||||
</object>
|
||||
</object>
|
||||
<string key="537.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string key="56.CustomClassName">AtomMenuItem</string>
|
||||
<string key="56.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string key="57.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string key="72.CustomClassName">AtomMenuItem</string>
|
||||
<object class="NSMutableDictionary" key="72.IBAttributePlaceholdersKey">
|
||||
<string key="NS.key.0">IBUserDefinedRuntimeAttributesPlaceholderName</string>
|
||||
<object class="IBUserDefinedRuntimeAttributesPlaceholder" key="NS.object.0">
|
||||
<string key="name">IBUserDefinedRuntimeAttributesPlaceholderName</string>
|
||||
<reference key="object" ref="722745758"/>
|
||||
<array key="userDefinedRuntimeAttributes">
|
||||
<object class="IBUserDefinedRuntimeAttribute">
|
||||
<string key="typeIdentifier">com.apple.InterfaceBuilder.userDefinedRuntimeAttributeType.boolean</string>
|
||||
<string key="keyPath">global</string>
|
||||
<boolean value="YES" key="value"/>
|
||||
</object>
|
||||
</array>
|
||||
</object>
|
||||
</object>
|
||||
<string key="72.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string key="81.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string key="82.CustomClassName">AtomMenuItem</string>
|
||||
<object class="NSMutableDictionary" key="82.IBAttributePlaceholdersKey">
|
||||
<string key="NS.key.0">IBUserDefinedRuntimeAttributesPlaceholderName</string>
|
||||
<object class="IBUserDefinedRuntimeAttributesPlaceholder" key="NS.object.0">
|
||||
<string key="name">IBUserDefinedRuntimeAttributesPlaceholderName</string>
|
||||
<reference key="object" ref="705341025"/>
|
||||
<array key="userDefinedRuntimeAttributes">
|
||||
<object class="IBUserDefinedRuntimeAttribute">
|
||||
<string key="typeIdentifier">com.apple.InterfaceBuilder.userDefinedRuntimeAttributeType.boolean</string>
|
||||
<string key="keyPath">global</string>
|
||||
<boolean value="YES" key="value"/>
|
||||
</object>
|
||||
</array>
|
||||
</object>
|
||||
</object>
|
||||
<string key="82.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string key="83.CustomClassName">AtomMenuItem</string>
|
||||
<string key="83.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
</dictionary>
|
||||
<dictionary class="NSMutableDictionary" key="unlocalizedProperties"/>
|
||||
<nil key="activeLocalization"/>
|
||||
<dictionary class="NSMutableDictionary" key="localizations"/>
|
||||
<nil key="sourceID"/>
|
||||
<int key="maxID">547</int>
|
||||
</object>
|
||||
<object class="IBClassDescriber" key="IBDocument.Classes">
|
||||
<array class="NSMutableArray" key="referencedPartialClassDescriptions">
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">AtomApp</string>
|
||||
<string key="superclassName">NSApplication</string>
|
||||
<object class="NSMutableDictionary" key="actions">
|
||||
<string key="NS.key.0">runSpecs:</string>
|
||||
<string key="NS.object.0">id</string>
|
||||
</object>
|
||||
<object class="NSMutableDictionary" key="actionInfosByName">
|
||||
<string key="NS.key.0">runSpecs:</string>
|
||||
<object class="IBActionInfo" key="NS.object.0">
|
||||
<string key="name">runSpecs:</string>
|
||||
<string key="candidateClassName">id</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBProjectSource</string>
|
||||
<string key="minorKey">./Classes/AtomApp.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">AtomMenuItem</string>
|
||||
<string key="superclassName">NSMenuItem</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBProjectSource</string>
|
||||
<string key="minorKey">./Classes/AtomMenuItem.h</string>
|
||||
</object>
|
||||
</object>
|
||||
</array>
|
||||
</object>
|
||||
<int key="IBDocument.localizationMode">0</int>
|
||||
<string key="IBDocument.TargetRuntimeIdentifier">IBCocoaFramework</string>
|
||||
<bool key="IBDocument.PluginDeclaredDependenciesTrackSystemTargetVersion">YES</bool>
|
||||
<int key="IBDocument.defaultPropertyAccessControl">3</int>
|
||||
<dictionary class="NSMutableDictionary" key="IBDocument.LastKnownImageSizes">
|
||||
<string key="NSMenuCheckmark">{9, 8}</string>
|
||||
<string key="NSMenuMixedState">{7, 2}</string>
|
||||
</dictionary>
|
||||
</data>
|
||||
</archive>
|
||||
14
Atom/main.m
@@ -1,14 +0,0 @@
|
||||
//
|
||||
// main.m
|
||||
// Atom
|
||||
//
|
||||
// Created by Corey Johnson on 10/25/11.
|
||||
// Copyright (c) 2011 __MyCompanyName__. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
return NSApplicationMain(argc, (const char **)argv);
|
||||
}
|
||||
0
frameworks/WebCore.framework/Versions/A/Resources/aliasCursor.png → Atom/resources/aliasCursor.png
Normal file → Executable file
|
Before Width: | Height: | Size: 752 B After Width: | Height: | Size: 752 B |
0
frameworks/WebCore.framework/Versions/A/Resources/cellCursor.png → Atom/resources/cellCursor.png
Normal file → Executable file
|
Before Width: | Height: | Size: 183 B After Width: | Height: | Size: 183 B |
BIN
Atom/resources/chrome.pak
Executable file
0
frameworks/WebCore.framework/Versions/A/Resources/contextMenuCursor.png → Atom/resources/contextMenuCursor.png
Normal file → Executable file
|
Before Width: | Height: | Size: 523 B After Width: | Height: | Size: 523 B |
0
frameworks/WebCore.framework/Versions/A/Resources/copyCursor.png → Atom/resources/copyCursor.png
Normal file → Executable file
|
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.6 KiB |
0
frameworks/WebCore.framework/Versions/A/Resources/deleteButton.png → Atom/resources/deleteButton.png
Normal file → Executable file
|
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 2.2 KiB |
BIN
Atom/resources/deleteButton.tiff
Executable file
0
frameworks/WebCore.framework/Versions/A/Resources/deleteButton@2x.png → Atom/resources/deleteButton@2x.png
Normal file → Executable file
|
Before Width: | Height: | Size: 5.8 KiB After Width: | Height: | Size: 5.8 KiB |
0
frameworks/WebCore.framework/Versions/A/Resources/deleteButtonPressed.png → Atom/resources/deleteButtonPressed.png
Normal file → Executable file
|
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.3 KiB |
BIN
Atom/resources/deleteButtonPressed.tiff
Executable file
0
frameworks/WebCore.framework/Versions/A/Resources/deleteButtonPressed@2x.png → Atom/resources/deleteButtonPressed@2x.png
Normal file → Executable file
|
Before Width: | Height: | Size: 6.0 KiB After Width: | Height: | Size: 6.0 KiB |
0
frameworks/WebCore.framework/Versions/A/Resources/eastResizeCursor.png → Atom/resources/eastResizeCursor.png
Normal file → Executable file
|
Before Width: | Height: | Size: 123 B After Width: | Height: | Size: 123 B |
0
frameworks/WebCore.framework/Versions/A/Resources/eastWestResizeCursor.png → Atom/resources/eastWestResizeCursor.png
Normal file → Executable file
|
Before Width: | Height: | Size: 126 B After Width: | Height: | Size: 126 B |
BIN
Atom/resources/en.lproj/locale.pak
Executable file
0
frameworks/WebCore.framework/Versions/A/Resources/helpCursor.png → Atom/resources/helpCursor.png
Normal file → Executable file
|
Before Width: | Height: | Size: 239 B After Width: | Height: | Size: 239 B |
0
frameworks/WebCore.framework/Versions/A/Resources/inputSpeech.png → Atom/resources/inputSpeech.png
Normal file → Executable file
|
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.6 KiB |
BIN
Atom/resources/inputSpeech.tiff
Executable file
0
frameworks/WebCore.framework/Versions/A/Resources/linkCursor.png → Atom/resources/linkCursor.png
Normal file → Executable file
|
Before Width: | Height: | Size: 341 B After Width: | Height: | Size: 341 B |
0
frameworks/WebCore.framework/Versions/A/Resources/missingImage.png → Atom/resources/missingImage.png
Normal file → Executable file
|
Before Width: | Height: | Size: 411 B After Width: | Height: | Size: 411 B |
BIN
Atom/resources/missingImage.tiff
Executable file
0
frameworks/WebCore.framework/Versions/A/Resources/missingImage@2x.png → Atom/resources/missingImage@2x.png
Normal file → Executable file
|
Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 3.3 KiB |
0
frameworks/WebCore.framework/Versions/A/Resources/moveCursor.png → Atom/resources/moveCursor.png
Normal file → Executable file
|
Before Width: | Height: | Size: 175 B After Width: | Height: | Size: 175 B |
0
frameworks/WebCore.framework/Versions/A/Resources/noDropCursor.png → Atom/resources/noDropCursor.png
Normal file → Executable file
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.4 KiB |
0
frameworks/WebCore.framework/Versions/A/Resources/noneCursor.png → Atom/resources/noneCursor.png
Normal file → Executable file
|
Before Width: | Height: | Size: 90 B After Width: | Height: | Size: 90 B |
0
frameworks/WebCore.framework/Versions/A/Resources/northEastResizeCursor.png → Atom/resources/northEastResizeCursor.png
Normal file → Executable file
|
Before Width: | Height: | Size: 209 B After Width: | Height: | Size: 209 B |
|
Before Width: | Height: | Size: 212 B After Width: | Height: | Size: 212 B |
0
frameworks/WebCore.framework/Versions/A/Resources/northResizeCursor.png → Atom/resources/northResizeCursor.png
Normal file → Executable file
|
Before Width: | Height: | Size: 125 B After Width: | Height: | Size: 125 B |
0
frameworks/WebCore.framework/Versions/A/Resources/northSouthResizeCursor.png → Atom/resources/northSouthResizeCursor.png
Normal file → Executable file
|
Before Width: | Height: | Size: 144 B After Width: | Height: | Size: 144 B |
0
frameworks/WebCore.framework/Versions/A/Resources/northWestResizeCursor.png → Atom/resources/northWestResizeCursor.png
Normal file → Executable file
|
Before Width: | Height: | Size: 174 B After Width: | Height: | Size: 174 B |
|
Before Width: | Height: | Size: 193 B After Width: | Height: | Size: 193 B |
BIN
Atom/resources/nullPlugin.png
Executable file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
Atom/resources/nullPlugin@2x.png
Executable file
|
After Width: | Height: | Size: 7.0 KiB |
BIN
Atom/resources/panIcon.png
Executable file
|
After Width: | Height: | Size: 175 B |
0
frameworks/WebCore.framework/Versions/A/Resources/progressCursor.png → Atom/resources/progressCursor.png
Normal file → Executable file
|
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.7 KiB |
0
frameworks/WebCore.framework/Versions/A/Resources/southEastResizeCursor.png → Atom/resources/southEastResizeCursor.png
Normal file → Executable file
|
Before Width: | Height: | Size: 166 B After Width: | Height: | Size: 166 B |
0
frameworks/WebCore.framework/Versions/A/Resources/southResizeCursor.png → Atom/resources/southResizeCursor.png
Normal file → Executable file
|
Before Width: | Height: | Size: 128 B After Width: | Height: | Size: 128 B |
0
frameworks/WebCore.framework/Versions/A/Resources/southWestResizeCursor.png → Atom/resources/southWestResizeCursor.png
Normal file → Executable file
|
Before Width: | Height: | Size: 177 B After Width: | Height: | Size: 177 B |
0
frameworks/WebCore.framework/Versions/A/Resources/textAreaResizeCorner.png → Atom/resources/textAreaResizeCorner.png
Normal file → Executable file
|
Before Width: | Height: | Size: 146 B After Width: | Height: | Size: 146 B |
BIN
Atom/resources/textAreaResizeCorner.tiff
Executable file
0
frameworks/WebCore.framework/Versions/A/Resources/textAreaResizeCorner@2x.png → Atom/resources/textAreaResizeCorner@2x.png
Normal file → Executable file
|
Before Width: | Height: | Size: 2.8 KiB After Width: | Height: | Size: 2.8 KiB |
BIN
Atom/resources/urlIcon.png
Executable file
|
After Width: | Height: | Size: 819 B |
0
frameworks/WebCore.framework/Versions/A/Resources/verticalTextCursor.png → Atom/resources/verticalTextCursor.png
Normal file → Executable file
|
Before Width: | Height: | Size: 120 B After Width: | Height: | Size: 120 B |
0
frameworks/WebCore.framework/Versions/A/Resources/waitCursor.png → Atom/resources/waitCursor.png
Normal file → Executable file
|
Before Width: | Height: | Size: 125 B After Width: | Height: | Size: 125 B |
0
frameworks/WebCore.framework/Versions/A/Resources/westResizeCursor.png → Atom/resources/westResizeCursor.png
Normal file → Executable file
|
Before Width: | Height: | Size: 122 B After Width: | Height: | Size: 122 B |
0
frameworks/WebCore.framework/Versions/A/Resources/zoomInCursor.png → Atom/resources/zoomInCursor.png
Normal file → Executable file
|
Before Width: | Height: | Size: 199 B After Width: | Height: | Size: 199 B |
0
frameworks/WebCore.framework/Versions/A/Resources/zoomOutCursor.png → Atom/resources/zoomOutCursor.png
Normal file → Executable file
|
Before Width: | Height: | Size: 182 B After Width: | Height: | Size: 182 B |
21
Atom/src/Atom.h
Executable file
@@ -0,0 +1,21 @@
|
||||
#import "BrowserDelegate.h"
|
||||
#import "include/cef.h"
|
||||
#import "include/cef_application_mac.h"
|
||||
|
||||
class ClientHandler;
|
||||
|
||||
@class AtomController;
|
||||
|
||||
@interface Atom : NSApplication<CefAppProtocol, BrowserDelegate> {
|
||||
NSWindow *_hiddenWindow;
|
||||
BOOL handlingSendEvent_;
|
||||
CefRefPtr<ClientHandler> _clientHandler;
|
||||
}
|
||||
|
||||
- (void)open:(NSString *)path;
|
||||
- (IBAction)runSpecs:(id)sender;
|
||||
|
||||
@end
|
||||
|
||||
// Returns the application settings based on command line arguments.
|
||||
void AppGetSettings(CefSettings& settings);
|
||||
120
Atom/src/Atom.mm
Executable file
@@ -0,0 +1,120 @@
|
||||
#import "Atom.h"
|
||||
#import "include/cef.h"
|
||||
#import "AtomController.h"
|
||||
|
||||
#import "native_handler.h"
|
||||
#import "client_handler.h"
|
||||
|
||||
// Provide the CefAppProtocol implementation required by CEF.
|
||||
@implementation Atom
|
||||
|
||||
+ (NSApplication *)sharedApplication {
|
||||
if (!NSApp) {
|
||||
// Populate the settings based on command line arguments.
|
||||
CefSettings settings;
|
||||
AppGetSettings(settings);
|
||||
|
||||
// Initialize CEF.
|
||||
CefRefPtr<CefApp> app;
|
||||
CefInitialize(settings, app);
|
||||
}
|
||||
|
||||
return [super sharedApplication];
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
[_hiddenWindow release];
|
||||
[self dealloc];
|
||||
}
|
||||
|
||||
- (BOOL)isHandlingSendEvent {
|
||||
return handlingSendEvent_;
|
||||
}
|
||||
|
||||
- (void)setHandlingSendEvent:(BOOL)handlingSendEvent {
|
||||
handlingSendEvent_ = handlingSendEvent;
|
||||
}
|
||||
|
||||
- (void)sendEvent:(NSEvent*)event {
|
||||
CefScopedSendingEvent sendingEventScoper;
|
||||
|
||||
if ([[self mainMenu] performKeyEquivalent:event]) return;
|
||||
|
||||
if (_clientHandler && ![self keyWindow] && [event type] == NSKeyDown) {
|
||||
[_hiddenWindow makeKeyAndOrderFront:self];
|
||||
[_hiddenWindow sendEvent:event];
|
||||
}
|
||||
else {
|
||||
[super sendEvent:event];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)createAtomContext {
|
||||
_clientHandler = new ClientHandler(self);
|
||||
|
||||
CefWindowInfo window_info;
|
||||
_hiddenWindow = [[NSWindow alloc] initWithContentRect:NSMakeRect(0, 0, 0, 0) styleMask:nil backing:nil defer:YES];
|
||||
window_info.SetAsChild([_hiddenWindow contentView], 0, 0, 0, 0);
|
||||
|
||||
CefBrowserSettings settings;
|
||||
NSURL *resourceDirURL = [[NSBundle mainBundle] resourceURL];
|
||||
NSString *indexURLString = [[resourceDirURL URLByAppendingPathComponent:@"index.html"] absoluteString];
|
||||
CefBrowser::CreateBrowser(window_info, _clientHandler.get(), [indexURLString UTF8String], settings);
|
||||
}
|
||||
|
||||
- (void)open:(NSString *)path {
|
||||
CefRefPtr<CefV8Context> atomContext = _clientHandler->GetBrowser()->GetMainFrame()->GetV8Context();
|
||||
[[AtomController alloc] initWithPath:path atomContext:atomContext];
|
||||
}
|
||||
|
||||
- (IBAction)runSpecs:(id)sender {
|
||||
CefRefPtr<CefV8Context> atomContext = _clientHandler->GetBrowser()->GetMainFrame()->GetV8Context();
|
||||
[[AtomController alloc] initSpecsWithAtomContext:atomContext];
|
||||
}
|
||||
|
||||
- (void)applicationWillFinishLaunching:(NSNotification *)notification {
|
||||
[self createAtomContext];
|
||||
}
|
||||
|
||||
- (void)applicationWillTerminate:(NSNotification *)aNotification {
|
||||
CefShutdown();
|
||||
}
|
||||
|
||||
#pragma mark BrowserDelegate
|
||||
|
||||
- (void)loadStart {
|
||||
CefRefPtr<CefV8Context> context = _clientHandler->GetBrowser()->GetMainFrame()->GetV8Context();
|
||||
CefRefPtr<CefV8Value> global = context->GetGlobal();
|
||||
|
||||
context->Enter();
|
||||
|
||||
CefRefPtr<CefV8Value> bootstrapScript = CefV8Value::CreateString("atom-bootstrap");
|
||||
global->SetValue("$bootstrapScript", bootstrapScript, V8_PROPERTY_ATTRIBUTE_NONE);
|
||||
|
||||
CefRefPtr<NativeHandler> nativeHandler = new NativeHandler();
|
||||
global->SetValue("$native", nativeHandler->m_object, V8_PROPERTY_ATTRIBUTE_NONE);
|
||||
|
||||
CefRefPtr<CefV8Value> atom = CefV8Value::CreateObject(NULL);
|
||||
global->SetValue("atom", atom, V8_PROPERTY_ATTRIBUTE_NONE);
|
||||
|
||||
CefRefPtr<CefV8Value> loadPath = CefV8Value::CreateString(PROJECT_DIR);
|
||||
atom->SetValue("loadPath", loadPath, V8_PROPERTY_ATTRIBUTE_NONE);
|
||||
|
||||
context->Exit();
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
// Returns the application settings based on command line arguments.
|
||||
void AppGetSettings(CefSettings& settings) {
|
||||
CefString(&settings.cache_path) = "";
|
||||
CefString(&settings.user_agent) = "";
|
||||
CefString(&settings.product_version) = "";
|
||||
CefString(&settings.locale) = "";
|
||||
CefString(&settings.log_file) = "";
|
||||
CefString(&settings.javascript_flags) = "";
|
||||
|
||||
settings.log_severity = LOGSEVERITY_ERROR;
|
||||
settings.local_storage_quota = 0;
|
||||
settings.session_storage_quota = 0;
|
||||
}
|
||||
28
Atom/src/AtomController.h
Normal file
@@ -0,0 +1,28 @@
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
#import "BrowserDelegate.h"
|
||||
#import "include/cef.h"
|
||||
|
||||
class ClientHandler;
|
||||
|
||||
@interface AtomController : NSWindowController <NSWindowDelegate, BrowserDelegate> {
|
||||
NSView *_webView;
|
||||
NSString *_bootstrapScript;
|
||||
NSString *_pathToOpen;
|
||||
|
||||
CefRefPtr<CefV8Context> _atomContext;
|
||||
CefRefPtr<ClientHandler> _clientHandler;
|
||||
}
|
||||
|
||||
- (id)initWithBootstrapScript:(NSString *)bootstrapScript atomContext:(CefRefPtr<CefV8Context>) context;
|
||||
- (id)initWithPath:(NSString *)path atomContext:(CefRefPtr<CefV8Context>)atomContext;
|
||||
- (id)initSpecsWithAtomContext:(CefRefPtr<CefV8Context>)atomContext;
|
||||
|
||||
- (void)createBrowser;
|
||||
|
||||
@property (nonatomic, retain) IBOutlet NSView *webView;
|
||||
|
||||
@end
|
||||
|
||||
// Returns the application browser settings based on command line arguments.
|
||||
void AppGetBrowserSettings(CefBrowserSettings& settings);
|
||||
170
Atom/src/AtomController.mm
Normal file
@@ -0,0 +1,170 @@
|
||||
#import "AtomController.h"
|
||||
|
||||
#import "include/cef.h"
|
||||
#import "client_handler.h"
|
||||
#import "native_handler.h"
|
||||
|
||||
@implementation AtomController
|
||||
|
||||
@synthesize webView=_webView;
|
||||
|
||||
- (void)dealloc {
|
||||
[_bootstrapScript release];
|
||||
[_webView release];
|
||||
[_pathToOpen release];
|
||||
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (id)initWithBootstrapScript:(NSString *)bootstrapScript atomContext:(CefRefPtr<CefV8Context>)atomContext {
|
||||
self = [super initWithWindowNibName:@"ClientWindow"];
|
||||
_bootstrapScript = [bootstrapScript retain];
|
||||
_atomContext = atomContext;
|
||||
|
||||
[self.window makeKeyAndOrderFront:nil];
|
||||
[self createBrowser];
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id)initWithPath:(NSString *)path atomContext:(CefRefPtr<CefV8Context>)atomContext {
|
||||
_pathToOpen = [path retain];
|
||||
return [self initWithBootstrapScript:@"window-bootstrap" atomContext:atomContext];
|
||||
}
|
||||
|
||||
- (id)initSpecsWithAtomContext:(CefRefPtr<CefV8Context>)atomContext {
|
||||
return [self initWithBootstrapScript:@"spec-bootstrap" atomContext:atomContext];
|
||||
}
|
||||
|
||||
- (void)windowDidLoad {
|
||||
[self.window setDelegate:self];
|
||||
[self.window setReleasedWhenClosed:NO];
|
||||
}
|
||||
|
||||
- (void)createBrowser {
|
||||
_clientHandler = new ClientHandler(self);
|
||||
|
||||
CefWindowInfo window_info;
|
||||
CefBrowserSettings settings;
|
||||
|
||||
AppGetBrowserSettings(settings);
|
||||
|
||||
window_info.SetAsChild(self.webView, 0, 0, self.webView.bounds.size.width, self.webView.bounds.size.height);
|
||||
|
||||
NSURL *resourceDirURL = [[NSBundle mainBundle] resourceURL];
|
||||
NSString *indexURLString = [[resourceDirURL URLByAppendingPathComponent:@"index.html"] absoluteString];
|
||||
CefBrowser::CreateBrowser(window_info, _clientHandler.get(), [indexURLString UTF8String], settings);
|
||||
}
|
||||
|
||||
#pragma mark BrowserDelegate
|
||||
|
||||
- (void)loadStart {
|
||||
CefRefPtr<CefV8Context> context = _clientHandler->GetBrowser()->GetMainFrame()->GetV8Context();
|
||||
CefRefPtr<CefV8Value> global = context->GetGlobal();
|
||||
|
||||
context->Enter();
|
||||
|
||||
CefRefPtr<CefV8Value> bootstrapScript = CefV8Value::CreateString([_bootstrapScript UTF8String]);
|
||||
global->SetValue("$bootstrapScript", bootstrapScript, V8_PROPERTY_ATTRIBUTE_NONE);
|
||||
|
||||
CefRefPtr<NativeHandler> nativeHandler = new NativeHandler();
|
||||
global->SetValue("$native", nativeHandler->m_object, V8_PROPERTY_ATTRIBUTE_NONE);
|
||||
|
||||
CefRefPtr<CefV8Value> pathToOpen = _pathToOpen ? CefV8Value::CreateString([_pathToOpen UTF8String]) : CefV8Value::CreateNull();
|
||||
global->SetValue("$pathToOpen", pathToOpen, V8_PROPERTY_ATTRIBUTE_NONE);
|
||||
|
||||
global->SetValue("atom", _atomContext->GetGlobal()->GetValue("atom"), V8_PROPERTY_ATTRIBUTE_NONE);
|
||||
|
||||
context->Exit();
|
||||
}
|
||||
|
||||
- (bool)keyEventOfType:(cef_handler_keyevent_type_t)type
|
||||
code:(int)code
|
||||
modifiers:(int)modifiers
|
||||
isSystemKey:(bool)isSystemKey
|
||||
isAfterJavaScript:(bool)isAfterJavaScript {
|
||||
|
||||
if (isAfterJavaScript && type == KEYEVENT_RAWKEYDOWN && modifiers == KEY_META && code == 'R') {
|
||||
_clientHandler->GetBrowser()->ReloadIgnoreCache();
|
||||
return YES;
|
||||
}
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
#pragma mark NSWindowDelegate
|
||||
|
||||
- (BOOL)windowShouldClose:(id)window {
|
||||
CefRefPtr<CefV8Context> context = _clientHandler->GetBrowser()->GetMainFrame()->GetV8Context();
|
||||
CefRefPtr<CefV8Value> global = context->GetGlobal();
|
||||
|
||||
context->Enter();
|
||||
|
||||
CefRefPtr<CefV8Value> atom = context->GetGlobal()->GetValue("atom");
|
||||
|
||||
CefRefPtr<CefV8Value> retval;
|
||||
CefRefPtr<CefV8Exception> exception;
|
||||
CefV8ValueList arguments;
|
||||
arguments.push_back(global);
|
||||
|
||||
atom->GetValue("windowClosed")->ExecuteFunction(atom, arguments, retval, exception, true);
|
||||
|
||||
context->Exit();
|
||||
|
||||
_clientHandler->GetBrowser()->CloseDevTools();
|
||||
|
||||
_atomContext = NULL;
|
||||
_clientHandler = NULL;
|
||||
|
||||
// Clean ourselves up after clearing the stack of anything that might have the window on it.
|
||||
[self autorelease];
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
// Returns the application browser settings based on command line arguments.
|
||||
void AppGetBrowserSettings(CefBrowserSettings& settings) {
|
||||
CefString(&settings.default_encoding) = "";
|
||||
CefString(&settings.user_style_sheet_location) = "";
|
||||
|
||||
settings.drag_drop_disabled = false;
|
||||
settings.load_drops_disabled = false;
|
||||
settings.history_disabled = false;
|
||||
settings.remote_fonts_disabled = false;
|
||||
settings.encoding_detector_enabled = false;
|
||||
settings.javascript_disabled = false;
|
||||
settings.javascript_open_windows_disallowed = false;
|
||||
settings.javascript_close_windows_disallowed = false;
|
||||
settings.javascript_access_clipboard_disallowed = false;
|
||||
settings.dom_paste_disabled = false;
|
||||
settings.caret_browsing_enabled = false;
|
||||
settings.java_disabled = true;
|
||||
settings.plugins_disabled = true;
|
||||
settings.universal_access_from_file_urls_allowed = true;
|
||||
settings.file_access_from_file_urls_allowed = false;
|
||||
settings.web_security_disabled = true;
|
||||
settings.xss_auditor_enabled = false;
|
||||
settings.image_load_disabled = false;
|
||||
settings.shrink_standalone_images_to_fit = false;
|
||||
settings.site_specific_quirks_disabled = false;
|
||||
settings.text_area_resize_disabled = false;
|
||||
settings.page_cache_disabled = false;
|
||||
settings.tab_to_links_disabled = false;
|
||||
settings.hyperlink_auditing_disabled = false;
|
||||
settings.user_style_sheet_enabled = false;
|
||||
settings.author_and_user_styles_disabled = false;
|
||||
settings.local_storage_disabled = false;
|
||||
settings.databases_disabled = false;
|
||||
settings.application_cache_disabled = false;
|
||||
settings.webgl_disabled = false;
|
||||
settings.accelerated_compositing_enabled = false;
|
||||
settings.threaded_compositing_enabled = false;
|
||||
settings.accelerated_layers_disabled = false;
|
||||
settings.accelerated_video_disabled = false;
|
||||
settings.accelerated_2d_canvas_disabled = false;
|
||||
settings.accelerated_drawing_disabled = false;
|
||||
settings.accelerated_plugins_disabled = false;
|
||||
settings.developer_tools_disabled = false;
|
||||
}
|
||||
11
Atom/src/BrowserDelegate.h
Normal file
@@ -0,0 +1,11 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "include/cef.h"
|
||||
|
||||
@protocol BrowserDelegate <NSObject>
|
||||
|
||||
@optional
|
||||
- (void)afterCreated;
|
||||
- (void)loadStart;
|
||||
- (bool)keyEventOfType:(cef_handler_keyevent_type_t)type code:(int)code modifiers:(int)modifiers isSystemKey:(bool)isSystemKey isAfterJavaScript:(bool)isAfterJavaScript;
|
||||
|
||||
@end
|
||||
128
Atom/src/client_handler.h
Executable file
@@ -0,0 +1,128 @@
|
||||
// Copyright (c) 2011 The Chromium Embedded Framework Authors. All rights
|
||||
// reserved. Use of this source code is governed by a BSD-style license that
|
||||
// can be found in the LICENSE file.
|
||||
|
||||
#ifndef _CLIENT_HANDLER_H
|
||||
#define _CLIENT_HANDLER_H
|
||||
|
||||
#import "include/cef.h"
|
||||
|
||||
@class AtomController;
|
||||
|
||||
// ClientHandler implementation.
|
||||
class ClientHandler : public CefClient,
|
||||
public CefLifeSpanHandler,
|
||||
public CefLoadHandler,
|
||||
public CefRequestHandler,
|
||||
public CefDisplayHandler,
|
||||
public CefFocusHandler,
|
||||
public CefKeyboardHandler,
|
||||
public CefPrintHandler,
|
||||
public CefV8ContextHandler,
|
||||
public CefDragHandler
|
||||
{
|
||||
public:
|
||||
ClientHandler(id delegate);
|
||||
virtual ~ClientHandler();
|
||||
|
||||
// CefClient methods
|
||||
virtual CefRefPtr<CefLifeSpanHandler> GetLifeSpanHandler() OVERRIDE
|
||||
{ return this; }
|
||||
virtual CefRefPtr<CefLoadHandler> GetLoadHandler() OVERRIDE
|
||||
{ return this; }
|
||||
virtual CefRefPtr<CefRequestHandler> GetRequestHandler() OVERRIDE
|
||||
{ return this; }
|
||||
virtual CefRefPtr<CefDisplayHandler> GetDisplayHandler() OVERRIDE
|
||||
{ return this; }
|
||||
virtual CefRefPtr<CefFocusHandler> GetFocusHandler() OVERRIDE
|
||||
{ return this; }
|
||||
virtual CefRefPtr<CefKeyboardHandler> GetKeyboardHandler() OVERRIDE
|
||||
{ return this; }
|
||||
virtual CefRefPtr<CefPrintHandler> GetPrintHandler() OVERRIDE
|
||||
{ return this; }
|
||||
virtual CefRefPtr<CefV8ContextHandler> GetV8ContextHandler() OVERRIDE
|
||||
{ return this; }
|
||||
virtual CefRefPtr<CefDragHandler> GetDragHandler() OVERRIDE
|
||||
{ return this; }
|
||||
|
||||
// CefLifeSpanHandler methods
|
||||
virtual void OnAfterCreated(CefRefPtr<CefBrowser> browser) OVERRIDE;
|
||||
virtual bool DoClose(CefRefPtr<CefBrowser> browser) OVERRIDE;
|
||||
virtual void OnBeforeClose(CefRefPtr<CefBrowser> browser) OVERRIDE;
|
||||
|
||||
// CefLoadHandler methods
|
||||
virtual void OnLoadStart(CefRefPtr<CefBrowser> browser,
|
||||
CefRefPtr<CefFrame> frame) OVERRIDE;
|
||||
virtual void OnLoadEnd(CefRefPtr<CefBrowser> browser,
|
||||
CefRefPtr<CefFrame> frame,
|
||||
int httpStatusCode) OVERRIDE;
|
||||
virtual bool OnLoadError(CefRefPtr<CefBrowser> browser,
|
||||
CefRefPtr<CefFrame> frame,
|
||||
ErrorCode errorCode,
|
||||
const CefString& failedUrl,
|
||||
CefString& errorText) OVERRIDE;
|
||||
|
||||
// CefRequestHandler methods
|
||||
virtual bool OnBeforeResourceLoad(CefRefPtr<CefBrowser> browser,
|
||||
CefRefPtr<CefRequest> request,
|
||||
CefString& redirectUrl,
|
||||
CefRefPtr<CefStreamReader>& resourceStream,
|
||||
CefRefPtr<CefResponse> response,
|
||||
int loadFlags) OVERRIDE;
|
||||
|
||||
|
||||
// CefDisplayHandler methods
|
||||
virtual void OnNavStateChange(CefRefPtr<CefBrowser> browser,
|
||||
bool canGoBack,
|
||||
bool canGoForward) OVERRIDE;
|
||||
virtual void OnTitleChange(CefRefPtr<CefBrowser> browser,
|
||||
const CefString& title) OVERRIDE;
|
||||
|
||||
// CefFocusHandler methods.
|
||||
virtual void OnFocusedNodeChanged(CefRefPtr<CefBrowser> browser,
|
||||
CefRefPtr<CefFrame> frame,
|
||||
CefRefPtr<CefDOMNode> node) OVERRIDE;
|
||||
|
||||
// CefKeyboardHandler methods.
|
||||
virtual bool OnKeyEvent(CefRefPtr<CefBrowser> browser,
|
||||
KeyEventType type,
|
||||
int code,
|
||||
int modifiers,
|
||||
bool isSystemKey,
|
||||
bool isAfterJavaScript) OVERRIDE;
|
||||
|
||||
// CefV8ContextHandler methods
|
||||
virtual void OnContextCreated(CefRefPtr<CefBrowser> browser,
|
||||
CefRefPtr<CefFrame> frame,
|
||||
CefRefPtr<CefV8Context> context) OVERRIDE;
|
||||
|
||||
// CefDragHandler methods.
|
||||
virtual bool OnDragStart(CefRefPtr<CefBrowser> browser,
|
||||
CefRefPtr<CefDragData> dragData,
|
||||
DragOperationsMask mask) OVERRIDE;
|
||||
virtual bool OnDragEnter(CefRefPtr<CefBrowser> browser,
|
||||
CefRefPtr<CefDragData> dragData,
|
||||
DragOperationsMask mask) OVERRIDE;
|
||||
|
||||
CefRefPtr<CefBrowser> GetBrowser() { return m_Browser; }
|
||||
CefWindowHandle GetBrowserHwnd() { return m_BrowserHwnd; }
|
||||
|
||||
protected:
|
||||
// The child browser window
|
||||
CefRefPtr<CefBrowser> m_Browser;
|
||||
|
||||
// The main frame window handle
|
||||
CefWindowHandle m_MainHwnd;
|
||||
|
||||
// The child browser window handle
|
||||
CefWindowHandle m_BrowserHwnd;
|
||||
|
||||
id m_delegate;
|
||||
|
||||
// Include the default reference counting implementation.
|
||||
IMPLEMENT_REFCOUNTING(ClientHandler);
|
||||
// Include the default locking implementation.
|
||||
IMPLEMENT_LOCKING(ClientHandler);
|
||||
};
|
||||
|
||||
#endif // _CLIENT_HANDLER_H
|
||||
199
Atom/src/client_handler.mm
Executable file
@@ -0,0 +1,199 @@
|
||||
#import "include/cef.h"
|
||||
#import "include/cef_wrapper.h"
|
||||
#import "client_handler.h"
|
||||
#import "AtomController.h"
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import <sstream>
|
||||
#import <stdio.h>
|
||||
#import <string>
|
||||
|
||||
#import <assert.h>
|
||||
|
||||
#ifndef NDEBUG
|
||||
#define ASSERT(condition) if(!(condition)) { assert(false); }
|
||||
#else
|
||||
#define ASSERT(condition) ((void)0)
|
||||
#endif
|
||||
|
||||
#define REQUIRE_UI_THREAD() ASSERT(CefCurrentlyOn(TID_UI));
|
||||
#define REQUIRE_IO_THREAD() ASSERT(CefCurrentlyOn(TID_IO));
|
||||
#define REQUIRE_FILE_THREAD() ASSERT(CefCurrentlyOn(TID_FILE));
|
||||
|
||||
ClientHandler::ClientHandler(id delegate)
|
||||
: m_MainHwnd(NULL),
|
||||
m_BrowserHwnd(NULL)
|
||||
{
|
||||
m_delegate = delegate;
|
||||
}
|
||||
|
||||
ClientHandler::~ClientHandler()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void ClientHandler::OnAfterCreated(CefRefPtr<CefBrowser> browser)
|
||||
{
|
||||
REQUIRE_UI_THREAD();
|
||||
|
||||
AutoLock lock_scope(this);
|
||||
if(!m_Browser.get())
|
||||
{
|
||||
// We need to keep the main child window, but not popup windows
|
||||
m_Browser = browser;
|
||||
m_BrowserHwnd = browser->GetWindowHandle();
|
||||
|
||||
if ([m_delegate respondsToSelector:@selector(afterCreated)]) {
|
||||
[m_delegate afterCreated];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool ClientHandler::DoClose(CefRefPtr<CefBrowser> browser)
|
||||
{
|
||||
REQUIRE_UI_THREAD();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void ClientHandler::OnBeforeClose(CefRefPtr<CefBrowser> browser)
|
||||
{
|
||||
REQUIRE_UI_THREAD();
|
||||
|
||||
if(m_BrowserHwnd == browser->GetWindowHandle()) {
|
||||
// Free the browser pointer so that the browser can be destroyed
|
||||
m_Browser = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void ClientHandler::OnLoadStart(CefRefPtr<CefBrowser> browser,
|
||||
CefRefPtr<CefFrame> frame)
|
||||
{
|
||||
REQUIRE_UI_THREAD();
|
||||
|
||||
if ([m_delegate respondsToSelector:@selector(loadStart)]) {
|
||||
[m_delegate loadStart];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void ClientHandler::OnLoadEnd(CefRefPtr<CefBrowser> browser,
|
||||
CefRefPtr<CefFrame> frame,
|
||||
int httpStatusCode)
|
||||
{
|
||||
REQUIRE_UI_THREAD();
|
||||
}
|
||||
|
||||
bool ClientHandler::OnLoadError(CefRefPtr<CefBrowser> browser,
|
||||
CefRefPtr<CefFrame> frame,
|
||||
ErrorCode errorCode,
|
||||
const CefString& failedUrl,
|
||||
CefString& errorText)
|
||||
{
|
||||
REQUIRE_UI_THREAD();
|
||||
|
||||
if(errorCode == ERR_CACHE_MISS) {
|
||||
// Usually caused by navigating to a page with POST data via back or
|
||||
// forward buttons.
|
||||
errorText = "<html><head><title>Expired Form Data</title></head>"
|
||||
"<body><h1>Expired Form Data</h1>"
|
||||
"<h2>Your form request has expired. "
|
||||
"Click reload to re-submit the form data.</h2></body>"
|
||||
"</html>";
|
||||
} else {
|
||||
// All other messages.
|
||||
std::stringstream ss;
|
||||
ss << "<html><head><title>Load Failed</title></head>"
|
||||
"<body><h1>Load Failed</h1>"
|
||||
"<h2>Load of URL " << std::string(failedUrl) <<
|
||||
" failed with error code " << static_cast<int>(errorCode) <<
|
||||
".</h2></body>"
|
||||
"</html>";
|
||||
errorText = ss.str();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void ClientHandler::OnNavStateChange(CefRefPtr<CefBrowser> browser,
|
||||
bool canGoBack,
|
||||
bool canGoForward)
|
||||
{
|
||||
REQUIRE_UI_THREAD();
|
||||
}
|
||||
|
||||
|
||||
void ClientHandler::OnFocusedNodeChanged(CefRefPtr<CefBrowser> browser,
|
||||
CefRefPtr<CefFrame> frame,
|
||||
CefRefPtr<CefDOMNode> node)
|
||||
{
|
||||
REQUIRE_UI_THREAD();
|
||||
|
||||
}
|
||||
|
||||
bool ClientHandler::OnKeyEvent(CefRefPtr<CefBrowser> browser,
|
||||
KeyEventType type,
|
||||
int code,
|
||||
int modifiers,
|
||||
bool isSystemKey,
|
||||
bool isAfterJavaScript)
|
||||
{
|
||||
REQUIRE_UI_THREAD();
|
||||
|
||||
if ([m_delegate respondsToSelector:@selector(keyEventOfType:code:modifiers:isSystemKey:isAfterJavaScript:)]) {
|
||||
return [m_delegate keyEventOfType:type code:code modifiers:modifiers isSystemKey:isSystemKey isAfterJavaScript:isAfterJavaScript];
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void ClientHandler::OnContextCreated(CefRefPtr<CefBrowser> browser,
|
||||
CefRefPtr<CefFrame> frame,
|
||||
CefRefPtr<CefV8Context> context)
|
||||
{
|
||||
REQUIRE_UI_THREAD();
|
||||
}
|
||||
|
||||
bool ClientHandler::OnDragStart(CefRefPtr<CefBrowser> browser,
|
||||
CefRefPtr<CefDragData> dragData,
|
||||
DragOperationsMask mask)
|
||||
{
|
||||
REQUIRE_UI_THREAD();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ClientHandler::OnDragEnter(CefRefPtr<CefBrowser> browser,
|
||||
CefRefPtr<CefDragData> dragData,
|
||||
DragOperationsMask mask)
|
||||
{
|
||||
REQUIRE_UI_THREAD();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ClientHandler::OnBeforeResourceLoad(CefRefPtr<CefBrowser> browser,
|
||||
CefRefPtr<CefRequest> request,
|
||||
CefString& redirectUrl,
|
||||
CefRefPtr<CefStreamReader>& resourceStream,
|
||||
CefRefPtr<CefResponse> response,
|
||||
int loadFlags)
|
||||
{
|
||||
REQUIRE_IO_THREAD();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void ClientHandler::OnTitleChange(CefRefPtr<CefBrowser> browser,
|
||||
const CefString& title)
|
||||
{
|
||||
REQUIRE_UI_THREAD();
|
||||
|
||||
// Set the frame window title bar
|
||||
NSView* view = (NSView*)browser->GetWindowHandle();
|
||||
NSWindow* window = [view window];
|
||||
std::string titleStr(title);
|
||||
NSString* str = [NSString stringWithUTF8String:titleStr.c_str()];
|
||||
[window setTitle:str];
|
||||
}
|
||||
19
Atom/src/main.mm
Normal file
@@ -0,0 +1,19 @@
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
#include "include/cef.h"
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
NSDictionary *infoDictionary = [[NSBundle mainBundle] infoDictionary];
|
||||
Class principalClass = NSClassFromString([infoDictionary objectForKey:@"NSPrincipalClass"]);
|
||||
NSApplication *application = [principalClass sharedApplication];
|
||||
|
||||
NSString *mainNibName = [infoDictionary objectForKey:@"NSMainNibFile"];
|
||||
NSNib *mainNib = [[NSNib alloc] initWithNibNamed:mainNibName bundle:[NSBundle mainBundle]];
|
||||
[mainNib instantiateNibWithOwner:application topLevelObjects:nil];
|
||||
|
||||
// Run the application message loop.
|
||||
CefRunMessageLoop();
|
||||
|
||||
// Don't put anything below this line because it won't be executed.
|
||||
return 0;
|
||||
}
|
||||
18
Atom/src/native_handler.h
Normal file
@@ -0,0 +1,18 @@
|
||||
#import "include/cef.h"
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
class NativeHandler : public CefV8Handler {
|
||||
public:
|
||||
NativeHandler();
|
||||
|
||||
CefRefPtr<CefV8Value> m_object;
|
||||
|
||||
virtual bool Execute(const CefString& name,
|
||||
CefRefPtr<CefV8Value> object,
|
||||
const CefV8ValueList& arguments,
|
||||
CefRefPtr<CefV8Value>& retval,
|
||||
CefString& exception) OVERRIDE;
|
||||
|
||||
// Provide the reference counting implementation for this class.
|
||||
IMPLEMENT_REFCOUNTING(NativeHandler);
|
||||
};
|
||||
258
Atom/src/native_handler.mm
Normal file
@@ -0,0 +1,258 @@
|
||||
#import "native_handler.h"
|
||||
#import "include/cef.h"
|
||||
#import "Atom.h"
|
||||
|
||||
NSString *stringFromCefV8Value(const CefRefPtr<CefV8Value>& value) {
|
||||
std::string cc_value = value->GetStringValue().ToString();
|
||||
return [NSString stringWithUTF8String:cc_value.c_str()];
|
||||
}
|
||||
|
||||
NativeHandler::NativeHandler() : CefV8Handler() {
|
||||
m_object = CefV8Value::CreateObject(NULL);
|
||||
|
||||
const char *functionNames[] = {"exists", "read", "write", "absolute", "list", "isFile", "isDirectory", "remove", "asyncList", "open", "openDialog", "quit", "writeToPasteboard", "readFromPasteboard", "showDevTools", "newWindow", "saveDialog"};
|
||||
NSUInteger arrayLength = sizeof(functionNames) / sizeof(const char *);
|
||||
for (NSUInteger i = 0; i < arrayLength; i++) {
|
||||
const char *functionName = functionNames[i];
|
||||
CefRefPtr<CefV8Value> function = CefV8Value::CreateFunction(functionName, this);
|
||||
m_object->SetValue(functionName, function, V8_PROPERTY_ATTRIBUTE_NONE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool NativeHandler::Execute(const CefString& name,
|
||||
CefRefPtr<CefV8Value> object,
|
||||
const CefV8ValueList& arguments,
|
||||
CefRefPtr<CefV8Value>& retval,
|
||||
CefString& exception) {
|
||||
if (name == "exists") {
|
||||
NSString *path = stringFromCefV8Value(arguments[0]);
|
||||
bool exists = [[NSFileManager defaultManager] fileExistsAtPath:path isDirectory:nil];
|
||||
retval = CefV8Value::CreateBool(exists);
|
||||
|
||||
return true;
|
||||
}
|
||||
else if (name == "read") {
|
||||
NSString *path = stringFromCefV8Value(arguments[0]);
|
||||
|
||||
NSError *error = nil;
|
||||
NSString *contents = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:&error];
|
||||
|
||||
if (error) {
|
||||
exception = [[error localizedDescription] UTF8String];
|
||||
}
|
||||
else {
|
||||
retval = CefV8Value::CreateString([contents UTF8String]);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
else if (name == "write") {
|
||||
NSString *path = stringFromCefV8Value(arguments[0]);
|
||||
NSString *content = stringFromCefV8Value(arguments[1]);
|
||||
|
||||
|
||||
NSError *error = nil;
|
||||
BOOL success = [content writeToFile:path atomically:YES encoding:NSUTF8StringEncoding error:&error];
|
||||
|
||||
if (error) {
|
||||
exception = [[error localizedDescription] UTF8String];
|
||||
}
|
||||
else if (!success) {
|
||||
std::string exception = "Cannot write to '";
|
||||
exception += [path UTF8String];
|
||||
exception += "'";
|
||||
}
|
||||
}
|
||||
else if (name == "absolute") {
|
||||
NSString *path = stringFromCefV8Value(arguments[0]);
|
||||
|
||||
path = [path stringByStandardizingPath];
|
||||
if ([path characterAtIndex:0] == '/') {
|
||||
retval = CefV8Value::CreateString([path UTF8String]);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
else if (name == "list") {
|
||||
NSString *path = stringFromCefV8Value(arguments[0]);
|
||||
bool recursive = arguments[1]->GetBoolValue();
|
||||
|
||||
NSFileManager *fm = [NSFileManager defaultManager];
|
||||
NSArray *relativePaths = [NSArray array];
|
||||
NSError *error = nil;
|
||||
|
||||
if (recursive) {
|
||||
relativePaths = [fm subpathsOfDirectoryAtPath:path error:&error];
|
||||
}
|
||||
else {
|
||||
relativePaths = [fm contentsOfDirectoryAtPath:path error:&error];
|
||||
}
|
||||
|
||||
if (error) {
|
||||
exception = [[error localizedDescription] UTF8String];
|
||||
}
|
||||
else {
|
||||
retval = CefV8Value::CreateArray();
|
||||
for (NSUInteger i = 0; i < relativePaths.count; i++) {
|
||||
NSString *relativePath = [relativePaths objectAtIndex:i];
|
||||
NSString *fullPath = [path stringByAppendingPathComponent:relativePath];
|
||||
retval->SetValue(i, CefV8Value::CreateString([fullPath UTF8String]));
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
else if (name == "isDirectory") {
|
||||
NSString *path = stringFromCefV8Value(arguments[0]);
|
||||
|
||||
BOOL isDir = false;
|
||||
BOOL exists = [[NSFileManager defaultManager] fileExistsAtPath:path isDirectory:&isDir];
|
||||
retval = CefV8Value::CreateBool(exists && isDir);
|
||||
|
||||
return true;
|
||||
}
|
||||
else if (name == "remove") {
|
||||
NSString *path = stringFromCefV8Value(arguments[0]);
|
||||
|
||||
NSError *error = nil;
|
||||
[[NSFileManager defaultManager] removeItemAtPath:path error:&error];
|
||||
|
||||
if (error) {
|
||||
exception = [[error localizedDescription] UTF8String];
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
else if (name == "asyncList") {
|
||||
NSString *path = stringFromCefV8Value(arguments[0]);
|
||||
bool recursive = arguments[1]->GetBoolValue();
|
||||
|
||||
NSFileManager *fm = [NSFileManager defaultManager];
|
||||
NSArray *relativePaths = [NSArray array];
|
||||
NSError *error = nil;
|
||||
|
||||
if (recursive) {
|
||||
relativePaths = [fm subpathsOfDirectoryAtPath:path error:&error];
|
||||
}
|
||||
else {
|
||||
relativePaths = [fm contentsOfDirectoryAtPath:path error:&error];
|
||||
}
|
||||
|
||||
if (error) {
|
||||
exception = [[error localizedDescription] UTF8String];
|
||||
}
|
||||
else {
|
||||
CefRefPtr<CefV8Value> paths = CefV8Value::CreateArray();
|
||||
for (NSUInteger i = 0; i < relativePaths.count; i++) {
|
||||
NSString *relativePath = [relativePaths objectAtIndex:i];
|
||||
NSString *fullPath = [path stringByAppendingPathComponent:relativePath];
|
||||
paths->SetValue(i, CefV8Value::CreateString([fullPath UTF8String]));
|
||||
}
|
||||
|
||||
CefV8ValueList args;
|
||||
args.push_back(paths);
|
||||
CefRefPtr<CefV8Exception> e;
|
||||
arguments[2]->ExecuteFunction(arguments[2], args, retval, e, true);
|
||||
if (e) exception = e->GetMessage();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
else if (name == "alert") {
|
||||
NSString *message = stringFromCefV8Value(arguments[0]);
|
||||
NSString *detailedMessage = stringFromCefV8Value(arguments[1]);
|
||||
CefRefPtr<CefV8Value> buttons = arguments[2];
|
||||
|
||||
NSAlert *alert = [[[NSAlert alloc] init] autorelease];
|
||||
[alert setMessageText:message];
|
||||
[alert setInformativeText:detailedMessage];
|
||||
|
||||
std::vector<CefString> buttonTitles;
|
||||
std::vector<CefString>::iterator iter;
|
||||
NSMutableDictionary *titleForTag = [NSMutableDictionary dictionary];
|
||||
|
||||
buttons->GetKeys(buttonTitles);
|
||||
|
||||
for (iter = buttonTitles.begin(); iter != buttonTitles.end(); iter++) {
|
||||
NSString *buttonTitle = [NSString stringWithUTF8String:(*iter).ToString().c_str()];
|
||||
NSButton *button = [alert addButtonWithTitle:buttonTitle];
|
||||
[titleForTag setObject:buttonTitle forKey:[NSNumber numberWithInt:button.tag]];
|
||||
}
|
||||
|
||||
NSUInteger buttonTag = [alert runModal];
|
||||
const char *buttonTitle = [[titleForTag objectForKey:[NSNumber numberWithInt:buttonTag]] UTF8String];
|
||||
CefRefPtr<CefV8Value> callback = buttons->GetValue(buttonTitle);
|
||||
|
||||
CefV8ValueList args;
|
||||
CefRefPtr<CefV8Exception> e;
|
||||
callback->ExecuteFunction(callback , args, retval, e, true);
|
||||
if (e) exception = e->GetMessage();
|
||||
|
||||
return true;
|
||||
}
|
||||
else 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 == "openDialog") {
|
||||
NSOpenPanel *panel = [NSOpenPanel openPanel];
|
||||
[panel setCanChooseDirectories:YES];
|
||||
if ([panel runModal] == NSFileHandlingPanelOKButton) {
|
||||
NSURL *url = [[panel URLs] lastObject];
|
||||
retval = CefV8Value::CreateString([[url path] UTF8String]);
|
||||
}
|
||||
else {
|
||||
retval = CefV8Value::CreateNull();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
else if (name == "open") {
|
||||
NSString *path = stringFromCefV8Value(arguments[0]);
|
||||
[NSApp open:path];
|
||||
|
||||
return true;
|
||||
}
|
||||
else if (name == "newWindow") {
|
||||
[NSApp open:nil];
|
||||
|
||||
return true;
|
||||
}
|
||||
else if (name == "saveDialog") {
|
||||
NSSavePanel *panel = [NSSavePanel savePanel];
|
||||
if ([panel runModal] == NSFileHandlingPanelOKButton) {
|
||||
NSURL *url = [panel URL];
|
||||
retval = CefV8Value::CreateString([[url path] UTF8String]);
|
||||
}
|
||||
else {
|
||||
return CefV8Value::CreateNull();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
else if (name == "quit") {
|
||||
[NSApp terminate:nil];
|
||||
return true;
|
||||
}
|
||||
else if (name == "showDevTools") {
|
||||
CefV8Context::GetCurrentContext()->GetBrowser()->ShowDevTools();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
5
Rakefile
@@ -8,7 +8,7 @@ task :build do
|
||||
|
||||
dest = File.join(built_dir, contents_dir, "Resources")
|
||||
|
||||
%w(index.html src docs static extensions vendor spec).each do |dir|
|
||||
%w(index.html src static vendor spec).each do |dir|
|
||||
rm_rf File.join(dest, dir)
|
||||
cp_r dir, File.join(dest, dir)
|
||||
end
|
||||
@@ -19,7 +19,8 @@ task :build do
|
||||
"http://coffeescript.org/ - (try `npm i -g coffee-script`)"
|
||||
end
|
||||
|
||||
sh "coffee -c #{dest}/src #{dest}/vendor #{dest}/extensions #{dest}/spec"
|
||||
puts contents_dir
|
||||
sh "coffee -c #{dest}/src #{dest}/vendor #{dest}/spec"
|
||||
end
|
||||
|
||||
desc "Install the app in /Applications"
|
||||
|
||||
3975
cef/include/cef.h
Executable file
120
cef/include/cef_application_mac.h
Executable file
@@ -0,0 +1,120 @@
|
||||
// Copyright (c) 2011 Marshall A. Greenblatt. All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the name Chromium Embedded
|
||||
// Framework nor the names of its contributors may be used to endorse
|
||||
// or promote products derived from this software without specific prior
|
||||
// written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#ifndef _CEF_APPLICATION_MAC_H
|
||||
#define _CEF_APPLICATION_MAC_H
|
||||
#pragma once
|
||||
|
||||
#include "cef.h"
|
||||
|
||||
#if defined(OS_MACOSX) && defined(__OBJC__)
|
||||
|
||||
#ifdef BUILDING_CEF_SHARED
|
||||
|
||||
// Use the existing CrAppProtocol definition.
|
||||
#include "base/message_pump_mac.h"
|
||||
|
||||
// Use the existing empty protocol definitions.
|
||||
#import "base/mac/cocoa_protocols.h"
|
||||
|
||||
#else // BUILDING_CEF_SHARED
|
||||
|
||||
#import <AppKit/AppKit.h>
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
// Copy of CrAppProtocol definition from base/message_pump_mac.h.
|
||||
@protocol CrAppProtocol
|
||||
// Must return true if -[NSApplication sendEvent:] is currently on the stack.
|
||||
- (BOOL)isHandlingSendEvent;
|
||||
@end
|
||||
|
||||
// The Mac OS X 10.6 SDK introduced new protocols used for delegates. These
|
||||
// protocol defintions were not present in earlier releases of the Mac OS X
|
||||
// SDK. In order to support building against the new SDK, which requires
|
||||
// delegates to conform to these protocols, and earlier SDKs, which do not
|
||||
// define these protocols at all, this file will provide empty protocol
|
||||
// definitions when used with earlier SDK versions.
|
||||
|
||||
#if !defined(MAC_OS_X_VERSION_10_6) || \
|
||||
MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_6
|
||||
|
||||
#define DEFINE_EMPTY_PROTOCOL(p) \
|
||||
@protocol p \
|
||||
@end
|
||||
|
||||
DEFINE_EMPTY_PROTOCOL(NSAlertDelegate)
|
||||
DEFINE_EMPTY_PROTOCOL(NSApplicationDelegate)
|
||||
DEFINE_EMPTY_PROTOCOL(NSControlTextEditingDelegate)
|
||||
DEFINE_EMPTY_PROTOCOL(NSMatrixDelegate)
|
||||
DEFINE_EMPTY_PROTOCOL(NSMenuDelegate)
|
||||
DEFINE_EMPTY_PROTOCOL(NSOpenSavePanelDelegate)
|
||||
DEFINE_EMPTY_PROTOCOL(NSOutlineViewDataSource)
|
||||
DEFINE_EMPTY_PROTOCOL(NSOutlineViewDelegate)
|
||||
DEFINE_EMPTY_PROTOCOL(NSSpeechSynthesizerDelegate)
|
||||
DEFINE_EMPTY_PROTOCOL(NSSplitViewDelegate)
|
||||
DEFINE_EMPTY_PROTOCOL(NSTableViewDataSource)
|
||||
DEFINE_EMPTY_PROTOCOL(NSTableViewDelegate)
|
||||
DEFINE_EMPTY_PROTOCOL(NSTextFieldDelegate)
|
||||
DEFINE_EMPTY_PROTOCOL(NSTextViewDelegate)
|
||||
DEFINE_EMPTY_PROTOCOL(NSWindowDelegate)
|
||||
|
||||
#undef DEFINE_EMPTY_PROTOCOL
|
||||
|
||||
#endif
|
||||
|
||||
#endif // BUILDING_CEF_SHARED
|
||||
|
||||
// All CEF client applications must subclass NSApplication and implement this
|
||||
// protocol.
|
||||
@protocol CefAppProtocol<CrAppProtocol>
|
||||
- (void)setHandlingSendEvent:(BOOL)handlingSendEvent;
|
||||
@end
|
||||
|
||||
// Controls the state of |isHandlingSendEvent| in the event loop so that it is
|
||||
// reset properly.
|
||||
class CefScopedSendingEvent {
|
||||
public:
|
||||
CefScopedSendingEvent()
|
||||
: app_(static_cast<NSApplication<CefAppProtocol>*>(
|
||||
[NSApplication sharedApplication])),
|
||||
handling_([app_ isHandlingSendEvent]) {
|
||||
[app_ setHandlingSendEvent:YES];
|
||||
}
|
||||
~CefScopedSendingEvent() {
|
||||
[app_ setHandlingSendEvent:handling_];
|
||||
}
|
||||
|
||||
private:
|
||||
NSApplication<CefAppProtocol>* app_;
|
||||
BOOL handling_;
|
||||
};
|
||||
|
||||
#endif // defined(OS_MACOSX) && defined(__OBJC__)
|
||||
|
||||
#endif // _CEF_APPLICATION_MAC_H
|
||||