diff --git a/AppKit/CPApplication.j b/AppKit/CPApplication.j index 04b7032ad..f276ebd74 100644 --- a/AppKit/CPApplication.j +++ b/AppKit/CPApplication.j @@ -379,10 +379,10 @@ CPRunContinuesResponse = -1002; [applicationLabel setStringValue:applicationTitle || ""]; - if (version && applicationVersion) - [versionLabel setStringValue:sprintf(@"Version %@ (%@)", applicationVersion, version)]; + if (applicationVersion && version) + [versionLabel setStringValue:@"Version " + applicationVersion + " (" + version + ")"]; else if (applicationVersion || version) - [versionLabel setStringValue:sprintf(@"Version %@", applicationVersion || version)]; + [versionLabel setStringValue:@"Version " + (applicationVersion || version)]; else [versionLabel setStringValue:@""]; diff --git a/AppKit/CPDocument.j b/AppKit/CPDocument.j index 2994aac92..7e29770da 100644 --- a/AppKit/CPDocument.j +++ b/AppKit/CPDocument.j @@ -888,8 +888,7 @@ var CPDocumentUntitledCount = 0; [_canCloseAlert setDelegate:self]; [_canCloseAlert setAlertStyle:CPWarningAlertStyle]; [_canCloseAlert setTitle:@"Unsaved Document"]; - [_canCloseAlert setMessageText:sprintf(@"Do you want to save the changes you've made to the document \"%@\"?", - [self displayName] || [self fileName])]; + [_canCloseAlert setMessageText:@"Do you want to save the changes you've made to the document \"" + ([self displayName] || [self fileName]) + "\"?"]; [_canCloseAlert addButtonWithTitle:@"Save"]; [_canCloseAlert addButtonWithTitle:@"Cancel"]; diff --git a/AppKit/CPTableHeaderView.j b/AppKit/CPTableHeaderView.j index 4bd2f4de8..76fa81093 100644 --- a/AppKit/CPTableHeaderView.j +++ b/AppKit/CPTableHeaderView.j @@ -371,8 +371,8 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal - (void)viewDidMoveToWindow { - if ([_tableView allowsColumnResizing]) - [[self window] setAcceptsMouseMovedEvents:YES]; + //if ([_tableView allowsColumnResizing]) + // [[self window] setAcceptsMouseMovedEvents:YES]; } - (void)mouseEntered:(CPEvent)theEvent diff --git a/AppKit/CPTableView.j b/AppKit/CPTableView.j index 2f82e6825..31ddd83e6 100644 --- a/AppKit/CPTableView.j +++ b/AppKit/CPTableView.j @@ -2054,6 +2054,7 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; { var row = rowArray[rowIndex], dataView = [self _newDataViewForRow:row tableColumn:tableColumn], + isButton = [dataView isKindOfClass:[CPButton class]], isTextField = [dataView isKindOfClass:[CPTextField class]]; [dataView setFrame:[self frameOfDataViewAtColumn:column row:row]]; @@ -2072,20 +2073,26 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; _dataViewsForTableColumns[tableColumnUID][row] = dataView; - if (_editingCellIndex && _editingCellIndex.x === column && _editingCellIndex.y === row) { - _editingCellIndex = undefined; + if (isButton || (_editingCellIndex && _editingCellIndex.x === column && _editingCellIndex.y === row)) + { + if (!isButton) + _editingCellIndex = undefined; - if (isTextField) { + if (isTextField) + { [dataView setEditable:YES]; [dataView setSendsActionOnEndEditing:YES]; [dataView setSelectable:YES]; [dataView selectText:nil]; // Doesn't seem to actually work (yet?). } + [dataView setTarget:self]; [dataView setAction:@selector(_commitDataViewObjectValue:)]; dataView.tableViewEditedColumnObj = tableColumn; dataView.tableViewEditedRowIndex = row; - } else if (isTextField) { + } + else if (isTextField) + { [dataView setEditable:NO]; [dataView setSelectable:NO]; } @@ -2684,7 +2691,6 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; rowIndex = [self rowAtPoint:aPoint]; if (rowIndex !== -1) { - if (_implementedDelegateMethods & CPTableViewDelegate_tableView_shouldEditTableColumn_row_) shouldEdit = [_delegate tableView:self shouldEditTableColumn:column row:rowIndex]; if (shouldEdit) diff --git a/AppKit/CPToolbar.j b/AppKit/CPToolbar.j index e201f17c1..f78f891b6 100644 --- a/AppKit/CPToolbar.j +++ b/AppKit/CPToolbar.j @@ -350,7 +350,7 @@ var CPToolbarConfigurationsByIdentifier = nil; item = [[_delegate toolbar:self itemForItemIdentifier:identifier willBeInsertedIntoToolbar:toolbar] copy]; if (!item) [CPException raise:CPInvalidArgumentException - reason:sprintf(@"_delegate %s returned nil toolbar item returned for identifier %s", _delegate, identifier)]; + reason:@"Toolbar delegate " + _delegate + " returned nil toolbar item for identifier " + identifier]; } [_identifiedItems setObject:item forKey:identifier]; diff --git a/Foundation/CPAttributedString.j b/Foundation/CPAttributedString.j index 3b8fff5f8..82e7f93a7 100644 --- a/Foundation/CPAttributedString.j +++ b/Foundation/CPAttributedString.j @@ -750,8 +750,8 @@ } //Private methods -- (void)_indexOfRangeEntryForIndex:(unsigned)characterIndex splitOnMaxIndex:(BOOL)split -{ +- (Number)_indexOfRangeEntryForIndex:(unsigned)characterIndex splitOnMaxIndex:(BOOL)split +{ var index = [self _indexOfEntryWithIndex:characterIndex]; if (index < 0) diff --git a/Foundation/CPKeyValueCoding.j b/Foundation/CPKeyValueCoding.j index 8e00497ee..e1a1d872c 100644 --- a/Foundation/CPKeyValueCoding.j +++ b/Foundation/CPKeyValueCoding.j @@ -25,7 +25,6 @@ @import "CPNull.j" @import "CPObject.j" - var CPObjectAccessorsForClass = nil, CPObjectModifiersForClass = nil; @@ -278,4 +277,5 @@ CPUnknownUserInfoKey = @"CPUnknownUserInfoKey"; @end +@import "CPKeyValueObserving.j" @import "CPArray+KVO.j" diff --git a/Foundation/CPURL.j b/Foundation/CPURL.j index bfc2ab507..fc7a52405 100644 --- a/Foundation/CPURL.j +++ b/Foundation/CPURL.j @@ -132,7 +132,7 @@ CPURLCustomIconKey = @"CPURLCustomIconKey"; return URI_RE.test(str) ? (parse(str).domain || nil) : nil; } -- (CPString)port +- (Number)port { var str = [self absoluteString]; if (URI_RE.test(str)) { diff --git a/Jakefile b/Jakefile index 36a6da3eb..36a63e9d5 100644 --- a/Jakefile +++ b/Jakefile @@ -58,7 +58,7 @@ task ("sudo-install", ["CommonJS"], function() if (OS.system(["sudo", "tusk", "install", "--force", $BUILD_CJS_OBJECTIVE_J, $BUILD_CJS_CAPPUCCINO])) { // Attempt a hackish work-around for sudo compiled with the --with-secure-path option - if (OS.system("sudo bash -c 'source `sh shell_config_file.sh`; tusk install --force " + $BUILD_CJS_OBJECTIVE_J + " " + $BUILD_CJS_CAPPUCCINO + "'")) + if (OS.system("sudo bash -c 'source " + getShellConfigFile() + "; tusk install --force " + $BUILD_CJS_OBJECTIVE_J + " " + $BUILD_CJS_CAPPUCCINO + "'")) OS.exit(1); //rake abort if ($? != 0) } }); @@ -255,3 +255,19 @@ function buildCmd(arrayOfCommands) return cmd.map(OS.enquote).join(" "); }).join(" && "); } + +function getShellConfigFile() +{ + var homeDir = SYSTEM.env["HOME"] + "/"; + // use order outlined by http://hayne.net/MacDev/Notes/unixFAQ.html#shellStartup + var possibilities = [homeDir + ".bash_profile", + homeDir + ".bash_login", + homeDir + ".profile", + homeDir + ".bashrc"]; + + for (var i = 0; i < possibilities.length; i++) + { + if (FILE.exists(possibilities[i])) + return possibilities[i]; + } +} diff --git a/Objective-J/Bootstrap.js b/Objective-J/Bootstrap.js index abd530ff7..598867210 100644 --- a/Objective-J/Bootstrap.js +++ b/Objective-J/Bootstrap.js @@ -62,6 +62,8 @@ function resolveCWD() }); } +var documentLoaded = NO; + function afterDocumentLoad(/*Function*/ aFunction) { if (documentLoaded) @@ -74,8 +76,6 @@ function afterDocumentLoad(/*Function*/ aFunction) window.attachEvent("onload", aFunction); } -var documentLoaded = NO; - afterDocumentLoad(function() { documentLoaded = YES; diff --git a/Objective-J/CFBundle.js b/Objective-J/CFBundle.js index 4761d83fc..bb535e2b5 100644 --- a/Objective-J/CFBundle.js +++ b/Objective-J/CFBundle.js @@ -29,7 +29,9 @@ var CFBundleUnloaded = 0, var CFBundlesForPaths = { }, CFBundlesForClasses = { }, - CFCacheBuster = new Date().getTime(); + CFCacheBuster = new Date().getTime(), + CFTotalBytesLoaded = 0, + CPApplicationSizeInBytes = 0; GLOBAL(CFBundle) = function(/*String*/ aPath) { @@ -220,6 +222,9 @@ CFBundle.prototype.load = function(/*BOOL*/ shouldExecute) return; } + if (self === CFBundle.mainBundle() && self.valueForInfoDictionary("CPApplicationSize")) + CPApplicationSizeInBytes = self.valueForInfoDictionary("CPApplicationSize").valueForKey("executable") || 0; + loadExecutableAndResources(self, shouldExecute); } @@ -274,6 +279,12 @@ function loadExecutableAndResources(/*Bundle*/ aBundle, /*BOOL*/ shouldExecute) function success() { + if ((typeof CPApp === "undefined" || !CPApp || !CPApp._finishedLaunching) && + typeof OBJJ_PROGRESS_CALLBACK === "function" && CPApplicationSizeInBytes) + { + OBJJ_PROGRESS_CALLBACK(MAX(MIN(1.0, CFTotalBytesLoaded / CPApplicationSizeInBytes), 0.0), CPApplicationSizeInBytes, aBundle.path()) + } + if (aBundle._loadStatus === CFBundleLoading) aBundle._loadStatus = CFBundleLoaded; else @@ -285,13 +296,13 @@ function loadExecutableAndResources(/*Bundle*/ aBundle, /*BOOL*/ shouldExecute) function complete() { + aBundle._eventDispatcher.dispatchEvent( { type:"load", bundle:aBundle }); } - if (shouldExecute) executeBundle(aBundle, complete); else @@ -310,6 +321,7 @@ function loadExecutableForBundle(/*Bundle*/ aBundle, success, failure) { try { + CFTotalBytesLoaded += anEvent.request.responseText().length; decompileStaticFile(aBundle, anEvent.request.responseText(), aBundle.executablePath()); aBundle._loadStatus &= ~CFBundleLoadingExecutable; success(); @@ -346,6 +358,7 @@ function loadSpritedImagesForBundle(/*Bundle*/ aBundle, success, failure) { try { + CFTotalBytesLoaded += anEvent.request.responseText().length; decompileStaticFile(aBundle, anEvent.request.responseText(), spritedImagesPath); aBundle._loadStatus &= ~CFBundleLoadingSpritedImages; success(); @@ -379,6 +392,29 @@ function CFBundleTestSpriteSupport(/*String*/ MHTMLPath, /*Function*/ aCallback) if (CFBundleSpriteSupportListeners.length > 1) return; + CFBundleSpriteSupportListeners.push(function() + { + var size = 0, + sizeDictionary = CFBundle.mainBundle().valueForInfoDictionary("CPApplicationSize"); + + if (!sizeDictionary) + return; + + switch (CFBundleSupportedSpriteType) + { + case CFBundleDataURLSpriteType: + size = sizeDictionary.valueForKey("data"); + break; + + case CFBundleMHTMLSpriteType: + case CFBundleMHTMLUncachedSpriteType: + size = sizeDictionary.valueForKey("mhtml"); + break; + } + + CPApplicationSizeInBytes += size; + }) + CFBundleTestSpriteTypes([ CFBundleDataURLSpriteType, "data:image/gif;base64,R0lGODlhAQABAIAAAMc9BQAAACH5BAAAAAAALAAAAAABAAEAAAICRAEAOw==", diff --git a/Objective-J/FileExecutable.js b/Objective-J/FileExecutable.js index 8390ebb51..478060f8e 100644 --- a/Objective-J/FileExecutable.js +++ b/Objective-J/FileExecutable.js @@ -22,7 +22,7 @@ var FileExecutablesForURLStrings = { }; -function FileExecutable(/*CFURL*/ aURL) +function FileExecutable(/*CFURL*/ aURL, /*Executable*/ anExecutable) { if (!aURL._path) aURL = new CFURL(aURL); var URLString = aURL.absoluteString(), @@ -37,7 +37,10 @@ if (!aURL._path) aURL = new CFURL(aURL); executable = NULL, extension = aURL.pathExtension(); - if (fileContents.match(/^@STATIC;/)) + if (anExecutable) + executable = anExecutable; + + else if (fileContents.match(/^@STATIC;/)) executable = decompile(fileContents, aURL); else if (extension === "j" || !extension) diff --git a/Objective-J/Includes.js b/Objective-J/Includes.js index 2a86f781e..ec551491d 100644 --- a/Objective-J/Includes.js +++ b/Objective-J/Includes.js @@ -42,7 +42,7 @@ #include "FileExecutable.js" #include "FileExecutableSearch.js" #include "Runtime.js" -#if DEBUG +#if defined(DEBUG) || defined(COMMONJS) #include "Debug.js" #endif #include "Bootstrap.js" diff --git a/Tests/Foundation/CPAttributedStringTest.j b/Tests/Foundation/CPAttributedStringTest.j index bbc2a607d..c5b0e09b3 100644 --- a/Tests/Foundation/CPAttributedStringTest.j +++ b/Tests/Foundation/CPAttributedStringTest.j @@ -31,14 +31,14 @@ var sharedObject = [CPObject new]; return string; } -- (id)testInitWithString +- (void)testInitWithString { var string = [[CPAttributedString alloc] initWithString:@"hi there"]; [self assertTrue:([string string] === @"hi there") message:"testInitWithString: expected:" + @"hi there" + " actual:" + [string string]]; } -- (id)testInitWithAttributedString +- (void)testInitWithAttributedString { var string = [[CPAttributedString alloc] initWithString:@"hi there"], attributedString = [[CPAttributedString alloc] initWithAttributedString:string]; @@ -53,7 +53,7 @@ var sharedObject = [CPObject new]; message:"testInitWithAttributedString: expected:" + [self stringForTesting] + " actual:" + string]; } -- (id)testIinitWithString_attributes +- (void)testIinitWithString_attributes { var string = [[CPAttributedString alloc] initWithString:@"hi there" attributes:[CPDictionary dictionary]]; @@ -70,7 +70,7 @@ var sharedObject = [CPObject new]; } //Retrieving Character Information -- (CPString)testString +- (void)testString { var string = [[CPAttributedString alloc] initWithString:@"hi there"]; @@ -78,7 +78,7 @@ var sharedObject = [CPObject new]; message:"testString: expected:" + @"hi there" + " actual:" + [string string]]; } -- (unsigned)testLength +- (void)testLength { var string = [[CPAttributedString alloc] initWithString:@"hi there"]; @@ -89,7 +89,7 @@ var sharedObject = [CPObject new]; message:"testLength: expected:" + 45 + " actual:" + [[self stringForTesting] length]]; } -- (unsigned)test_indexOfEntryWithIndex +- (void)test_indexOfEntryWithIndex { var string = [self stringForTesting]; @@ -104,7 +104,7 @@ var sharedObject = [CPObject new]; } //Retrieving Attribute Information -- (CPDictionary)testAttributesAtIndexEffectiveRange +- (void)testAttributesAtIndexEffectiveRange { var string = [self stringForTesting], expectedValues = {a:1, b:"bar", c:sharedObject, d:20}; @@ -117,7 +117,7 @@ var sharedObject = [CPObject new]; } //- (CPDictionary)attributesAtIndex:(unsigned)anIndex longestEffectiveRange:(CPRangePointer)aRange inRange:(CPRange)rangeLimit -- (CPDictionary)testAttributesAtIndexLongestEffectiveRangeInRange +- (void)testAttributesAtIndexLongestEffectiveRangeInRange { var string = [self stringForTesting]; @@ -136,7 +136,7 @@ var sharedObject = [CPObject new]; } //- (id)attribute:(CPString)attribute atIndex:(unsigned)index effectiveRange:(CPRangePointer)aRange -- (id)testAttributeAtIndexEffectiveRange +- (void)testAttributeAtIndexEffectiveRange { var string = [self stringForTesting]; @@ -145,7 +145,7 @@ var sharedObject = [CPObject new]; } //- (id)attribute:(CPString)attribute atIndex:(unsigned)index longestEffectiveRange:(CPRangePointer)aRange inRange:(CPRange)rangeLimit -- (id)testAttributeAtIndexLongestEffectiveRangeInRange +- (void)testAttributeAtIndexLongestEffectiveRangeInRange { var string = [self stringForTesting]; @@ -159,14 +159,14 @@ var sharedObject = [CPObject new]; } //Comparing Attributed Strings -- (BOOL)testIsEqualToAttributedString +- (void)testIsEqualToAttributedString { [self assertTrue:[[self stringForTesting] isEqualToAttributedString:[self stringForTesting]] message:"expected stringForTesting to equal itself, but it didn't"]; [self assertFalse:[[self stringForTesting] isEqualToAttributedString:[[CPAttributedString alloc] initWithString:@"HELLO!"]] message:"Expected stringForTesting to not equal 'HELLO!', but it did"]; } -- (BOOL)testIsEqual +- (void)testIsEqual { [self assertTrue:[[self stringForTesting] isEqual:[self stringForTesting]] message:"expected stringForTesting to equal itself, but it didn't"]; @@ -181,7 +181,7 @@ var sharedObject = [CPObject new]; //Extracting a Substring //- (CPAttributedString)attributedSubstringFromRange:(CPRange)aRange -- (CPAttributedString)testAttributedSubstringFromRange +- (void)testAttributedSubstringFromRange { var a = [[self stringForTesting] attributedSubstringFromRange:CPMakeRange(0, 9)], expectedValues = {a:1, b:"bar", c:sharedObject, d:20}; diff --git a/Tests/Manual/LoadTimeTest/AppController.j b/Tests/Manual/LoadTimeTest/AppController.j new file mode 100644 index 000000000..bd1f94618 --- /dev/null +++ b/Tests/Manual/LoadTimeTest/AppController.j @@ -0,0 +1,74 @@ +/* + * AppController.j + * LoadTimeTest + * + * Created by You on February 23, 2010. + * Copyright 2010, Your Company All rights reserved. + */ + +@import + + +@implementation AppController : CPObject +{ +} + +- (void)applicationDidFinishLaunching:(CPNotification)aNotification +{ + var endLaunch = new Date(); + + var data; + if (window.location.search.length > 1) + data = JSON.parse(decodeURIComponent(window.location.search.slice(1))) + else + data = []; + + data.push([endLoad - startLoad, endLaunch - endLoad]); + + if (data.length < 10) + { + // reload with data in the query string + window.location.href = [window.location.protocol, "//", window.location.host, window.location.port, window.location.pathname, "?", encodeURIComponent(JSON.stringify(data))].join(""); + } + else + { + var loadAvg = 0, loadStdev = 0, launchAvg = 0, launchStdev = 0; + for (var i = 0; i < data.length; i++) { + loadAvg += data[i][0]; + launchAvg += data[i][1]; + } + + loadAvg /= data.length; + launchAvg /= data.length; + + for (var i = 0; i < data.length; i++) { + loadStdev += Math.pow(data[i][0] - loadAvg, 2); + launchStdev += Math.pow(data[i][1] - launchAvg, 2); + } + + loadStdev = Math.sqrt(loadStdev / data.length); + launchStdev = Math.sqrt(launchStdev / data.length); + + var theWindow = [[CPWindow alloc] initWithContentRect:CGRectMakeZero() styleMask:CPBorderlessBridgeWindowMask], + contentView = [theWindow contentView]; + + var label = [[CPTextField alloc] initWithFrame:CGRectMakeZero()]; + + [label setStringValue:"load avg="+Math.round(loadAvg)+" (stdev="+Math.round(loadStdev)+"); launch avg="+Math.round(launchAvg)+" (stdev="+Math.round(launchStdev)+")"]; + [label setFont:[CPFont boldSystemFontOfSize:24.0]]; + + [label sizeToFit]; + + [label setAutoresizingMask:CPViewMinXMargin | CPViewMaxXMargin | CPViewMinYMargin | CPViewMaxYMargin]; + [label setCenter:[contentView center]]; + + [contentView addSubview:label]; + + [theWindow orderFront:self]; + + // Uncomment the following line to turn on the standard menu bar. + //[CPMenu setMenuBarVisible:YES]; + } +} + +@end diff --git a/Tests/Manual/LoadTimeTest/Info.plist b/Tests/Manual/LoadTimeTest/Info.plist new file mode 100644 index 000000000..683af34e9 --- /dev/null +++ b/Tests/Manual/LoadTimeTest/Info.plist @@ -0,0 +1,12 @@ + + + + + CPApplicationDelegateClass + AppController + CPBundleName + LoadTimeTest + CPPrincipalClass + CPApplication + + diff --git a/Tests/Manual/LoadTimeTest/Jakefile b/Tests/Manual/LoadTimeTest/Jakefile new file mode 100644 index 000000000..bcb3924ee --- /dev/null +++ b/Tests/Manual/LoadTimeTest/Jakefile @@ -0,0 +1,38 @@ +/* + * Jakefile + * LoadTimeTest + * + * Created by You on February 23, 2010. + * Copyright 2010, Your Company All rights reserved. + */ + +var ENV = require("system").env, + FILE = require("file"), + task = require("jake").task, + FileList = require("jake").FileList, + app = require("cappuccino/jake").app, + configuration = ENV["CONFIG"] || ENV["CONFIGURATION"] || ENV["c"] || "Debug"; + +app ("LoadTimeTest", function(task) +{ + task.setBuildIntermediatesPath(FILE.join("Build", "LoadTimeTest.build", configuration)); + task.setBuildPath(FILE.join("Build", configuration)); + + task.setProductName("LoadTimeTest"); + task.setIdentifier("com.yourcompany.LoadTimeTest"); + task.setVersion("1.0"); + task.setAuthor("Your Company"); + task.setEmail("feedback @nospam@ yourcompany.com"); + task.setSummary("LoadTimeTest"); + task.setSources(new FileList("**/*.j")); + task.setResources(new FileList("Resources/*")); + task.setIndexFilePath("index.html"); + task.setInfoPlistPath("Info.plist"); + + if (configuration === "Debug") + task.setCompilerFlags("-DDEBUG -g"); + else + task.setCompilerFlags("-O"); +}); + +task ("default", ["LoadTimeTest"]); diff --git a/Tests/Manual/LoadTimeTest/Resources/spinner.gif b/Tests/Manual/LoadTimeTest/Resources/spinner.gif new file mode 100644 index 000000000..06dbc2bc2 Binary files /dev/null and b/Tests/Manual/LoadTimeTest/Resources/spinner.gif differ diff --git a/Tests/Manual/LoadTimeTest/index-debug.html b/Tests/Manual/LoadTimeTest/index-debug.html new file mode 100644 index 000000000..32848795f --- /dev/null +++ b/Tests/Manual/LoadTimeTest/index-debug.html @@ -0,0 +1,88 @@ + + + + + + + + + LoadTimeTest + + + + + + + + + + + + + + +
+
+ + + +
+
+ + + diff --git a/Tests/Manual/LoadTimeTest/index.html b/Tests/Manual/LoadTimeTest/index.html new file mode 100644 index 000000000..dcbd4d5db --- /dev/null +++ b/Tests/Manual/LoadTimeTest/index.html @@ -0,0 +1,74 @@ + + + + + + + + + LoadTimeTest + + + + + + + + + + + + +
+
+ + + +
+
+ + + + diff --git a/Tests/Manual/LoadTimeTest/main.j b/Tests/Manual/LoadTimeTest/main.j new file mode 100644 index 000000000..5d26ab57a --- /dev/null +++ b/Tests/Manual/LoadTimeTest/main.j @@ -0,0 +1,19 @@ +/* + * AppController.j + * LoadTimeTest + * + * Created by You on February 23, 2010. + * Copyright 2010, Your Company All rights reserved. + */ + +@import +@import + +@import "AppController.j" + +function main(args, namedArgs) +{ + endLoad = new Date(); + + CPApplicationMain(args, namedArgs); +} diff --git a/Tools/flatten/flatten b/Tools/flatten/flatten index 9854df81a..6889a931d 100755 --- a/Tools/flatten/flatten +++ b/Tools/flatten/flatten @@ -31,7 +31,7 @@ function main(args) var flattener = new ObjectiveJFlattener(rootPath); - flattener.setIncludePaths([rootPath.join("Frameworks/Debug")]); + flattener.setIncludePaths([rootPath.join("Frameworks")]); flattener.setEnvironments(["Browser", "ObjJ"]); flattener.load(rootPath.join("main.j")); @@ -65,6 +65,7 @@ function ObjectiveJFlattener(rootPath) { this.resourceBuffer = []; this.bundleBuffer = []; + this.functionsBuffer = []; this._outputBundles = {}; } @@ -75,6 +76,7 @@ ObjectiveJFlattener.prototype.buildApplicationJS = function(applicationRoot) { print(applicationRoot); this.serializeStaticResources(applicationRoot); + this.serializeStaticFileExecutables(); var buffer = [] @@ -89,14 +91,31 @@ ObjectiveJFlattener.prototype.buildApplicationJS = function(applicationRoot) { buffer.push(this.resourceBuffer.join("\n")); - buffer.push("console.log(ObjectiveJ.StaticResource.root);"); - buffer.push("console.log(applicationRoot);"); - buffer.push("ObjectiveJ.bootstrap();"); buffer.push("})();"); + buffer.push(this.functionsBuffer.join("\n")); + + buffer.push("ObjectiveJ.bootstrap();"); + return buffer.join("\n"); } +ObjectiveJFlattener.prototype.serializeStaticFileExecutables = function() { + this.require("objective-j").FileExecutable.allFileExecutables().forEach(function(aFileExecutable) { + var deps = aFileExecutable.fileDependencies().map(function(dependency) { + return "new ObjectiveJ.FileDependency("+JSON.stringify(dependency.path())+","+JSON.stringify(dependency.isLocal())+")" + }).join(","); + + var func = aFileExecutable._function.toString(); + // HACK + func = func.replace(", require, exports, module, system, print, window", ""); + + this.functionsBuffer.push("var path = ObjectiveJ.StaticResource.cwd + "+JSON.stringify("/"+this.rootPath.relative(aFileExecutable.path()))+";"); + this.functionsBuffer.push("new ObjectiveJ.FileExecutable(path,"+ + "new ObjectiveJ.Executable(null, ["+deps+"], path, "+func+"));"); + }, this); +} + ObjectiveJFlattener.prototype.serializeStaticResources = function(node, depth) { depth = depth || 0; @@ -130,8 +149,10 @@ ObjectiveJFlattener.prototype.serializeStaticResources = function(node, depth) { this.resourceBuffer.push("newNode = applicationRoot;"); } - if (node.contents()) - this.resourceBuffer.push("newNode._contents = " + JSON.stringify(node.contents()) + ";"); + // var contents = node.contents(); + // if (contents) { + // this.resourceBuffer.push("newNode._contents = " + JSON.stringify(contents) + ";"); + // } if (!node.children()) return; diff --git a/Tools/press/main.j b/Tools/press/main.j index 188f9cb17..35047fad3 100644 --- a/Tools/press/main.j +++ b/Tools/press/main.j @@ -81,11 +81,15 @@ function press(rootPath, outputPath, options) { stream.print("Application root: \0green(" + rootPath + "\0)"); stream.print("Output directory: \0green(" + outputPath + "\0)"); - var outputFiles = {}; + var outputFiles = {}, + totalBytes = {executable:0, data:0, mhtml:0}; // analyze and gather files for each environment: options.environments.forEach(function(environment) { - pressEnvironment(rootPath, outputFiles, environment, options); + var returnedBytes = pressEnvironment(rootPath, outputFiles, environment, options); + + for (var i in returnedBytes) + totalBytes[i] += returnedBytes[i]; }); // phase 4: copy everything and write out the new files @@ -110,6 +114,34 @@ function press(rootPath, outputPath, options) { FILE.write(file, outputFiles[path], { charset : "UTF-8" }); } + // phase 4a: update the info.plist to contain meta information about the app + stream.print("\0red(PHASE 4a:\0) Add application size data to Info.plist"); + + var outputInfoPlistPath = FILE.join(outputPath, "Info.plist"), + outputInfoPlistContents = FILE.read(outputInfoPlistPath, { charset:"UTF-8" }), + format = CFPropertyList.sniffedFormatOfString(outputInfoPlistContents), + outputInfoPlist = CFPropertyList.propertyListFromString(outputInfoPlistContents); + + // read in the default theme name, and attempt to get its size + var themeName = outputInfoPlist.valueForKey("CPDefaultTheme") || "Aristo", + themePath = FILE.join(outputPath, options.frameworks, "AppKit", "Resources", themeName+".blend"); + + if (FILE.exists(themePath)) + { + var themeEnvPath = FILE.join(themePath, options.environments[0] + ".environment"), + themeExecutablePath = FILE.join(themeEnvPath, themeName+".blend.sj"), + themeDataPath = FILE.join(themeEnvPath, "dataURLs.txt"), + themeMHTMLPath = FILE.join(themeEnvPath, "MHTMLPaths.txt"); + + totalBytes.executable += FILE.read(themeExecutablePath, {charset : "UTF-8"}).length; + totalBytes.data += FILE.read(themeDataPath, {charset : "UTF-8"}).length; + totalBytes.mhtml += FILE.read(themeMHTMLPath, {charset : "UTF-8"}).length; + } + + outputInfoPlist.setValueForKey("CPApplicationSize", [CPDictionary dictionaryWithJSObject:totalBytes]); + + FILE.write(outputInfoPlistPath, CFPropertyList.stringFromPropertyList(outputInfoPlist, format), { charset:"UTF-8" }); + // strip known unnecessary files // outputPath.glob("**/Frameworks/Debug").forEach(function(debugFramework) { // outputPath.join(debugFramework).rmtree(); @@ -193,7 +225,7 @@ function pressEnvironment(rootPath, outputFiles, environment, options) { }); var included = 0, total = 0; - var includedBytes = 0, totalBytes = 0; + var includedBytes = 0, totalBytes = 0, dataBytes = 0, mhtmlBytes = 0; _OBJJ.FileExecutable.allFileExecutables().forEach(function(aFileExecutable) { var path = aFileExecutable.path(); @@ -224,6 +256,8 @@ function pressEnvironment(rootPath, outputFiles, environment, options) { // phase 3b: rebuild .sj files with correct imports, copy .j files stream.print("\0red(PHASE 3b:\0) Rebuild .sj files"); + var processedBundles = {}; + for (var path in requiredFiles) { var executable = analyzer.executableForImport(path), @@ -289,10 +323,25 @@ function pressEnvironment(rootPath, outputFiles, environment, options) { { stream.print("Passing .j through: \0green(" + rootPath.relative(path) + "\0)"); } + + if (!processedBundles[bundle.path()] && bundle.hasSpritedImages()) + { + processedBundles[bundle.path()] = bundle; + stream.print("Sizing bundle's sprited resources \0green(" + bundle.path() + "\0)"); + + var bundlePath = FILE.join(bundle.path(), environment+".environment"), + bundleDataPath = FILE.join(bundlePath, "dataURLs.txt"), + bundleMHTMLPath = FILE.join(bundlePath, "MHTMLPaths.txt"); + + dataBytes += FILE.read(bundleDataPath, {charset : "UTF-8"}).length; + mhtmlBytes += FILE.read(bundleMHTMLPath, {charset : "UTF-8"}).length; + } } else CPLog.warn("No bundle (or info dictionary for) " + rootPath.relative(path)); } + + return {executable:includedBytes, data:dataBytes, mhtml:mhtmlBytes}; } function pngcrushDirectory(directory) { diff --git a/bootstrap.sh b/bootstrap.sh index c0f47647c..6faf03629 100755 --- a/bootstrap.sh +++ b/bootstrap.sh @@ -45,7 +45,17 @@ function ask_remove_dir () { function ask_append_shell_config () { config_string="$1" - shell_config_file=`sh shell_config_file.sh` + shell_config_file="" + # use order outlined by http://hayne.net/MacDev/Notes/unixFAQ.html#shellStartup + if [ -f "$HOME/.bash_profile" ]; then + shell_config_file="$HOME/.bash_profile" + elif [ -f "$HOME/.bash_login" ]; then + shell_config_file="$HOME/.bash_login" + elif [ -f "$HOME/.profile" ]; then + shell_config_file="$HOME/.profile" + elif [ -f "$HOME/.bashrc" ]; then + shell_config_file="$HOME/.bashrc" + fi echo " \"$config_string\" will be appended to \"$shell_config_file\"." if prompt "no"; then @@ -68,7 +78,12 @@ function check_and_exit () { fi } -default_directory="/usr/local/narwhal" +if [ -w "/usr/local" ]; then + default_directory="/usr/local/narwhal" +else + default_directory="$HOME/narwhal" +fi + install_directory="" tmp_zip="/tmp/narwhal.zip" @@ -103,6 +118,8 @@ github_project="$github_user-narwhal" github_path=$(echo "$github_project" | tr '-' '/') unset NARWHAL_ENGINE +unset SEA +unset SEALVL PATH_SAVED="$PATH" diff --git a/shell_config_file.sh b/shell_config_file.sh deleted file mode 100755 index c52e8bc17..000000000 --- a/shell_config_file.sh +++ /dev/null @@ -1,13 +0,0 @@ -shell_config_file="" -# use order outlined by http://hayne.net/MacDev/Notes/unixFAQ.html#shellStartup -if [ -f "$HOME/.bash_profile" ]; then - shell_config_file="$HOME/.bash_profile" -elif [ -f "$HOME/.bash_login" ]; then - shell_config_file="$HOME/.bash_login" -elif [ -f "$HOME/.profile" ]; then - shell_config_file="$HOME/.profile" -elif [ -f "$HOME/.bashrc" ]; then - shell_config_file="$HOME/.bashrc" -fi - -echo $shell_config_file