From 9b99457871fecc86bd500e83b54d7fa82d56e025 Mon Sep 17 00:00:00 2001 From: tlrobinson Date: Mon, 20 Jul 2009 18:16:17 -0700 Subject: [PATCH 01/53] Preliminary typechecking version of objj_msgSend, and preprocessor support. --- Objective-J/preprocess.js | 23 +++++++++-- Objective-J/runtime.js | 81 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 100 insertions(+), 4 deletions(-) diff --git a/Objective-J/preprocess.js b/Objective-J/preprocess.js index 0032ed203..f09af79f1 100644 --- a/Objective-J/preprocess.js +++ b/Objective-J/preprocess.js @@ -578,12 +578,15 @@ objj_preprocessor.prototype.method = function(tokens) var buffer = new objj_stringBuffer(), token, selector = "", - parameters = []; + parameters = [], + types = [null]; while((token = tokens.skip_whitespace()) && token != TOKEN_OPEN_BRACE) { if (token == TOKEN_COLON) { + var type = ""; + // Colons are part of the selector name selector += token; @@ -592,18 +595,30 @@ objj_preprocessor.prototype.method = function(tokens) if (token == TOKEN_OPEN_PARENTHESIS) { // Swallow parameter/return type. Perhaps later we can use this for debugging? - while((token = tokens.skip_whitespace()) && token != TOKEN_CLOSE_PARENTHESIS) ; + while((token = tokens.skip_whitespace()) && token != TOKEN_CLOSE_PARENTHESIS) + type += token; token = tokens.skip_whitespace(); } + // Add the type. If it's empty, add null instead. + types[parameters.length+1] = type || null; + // Since this follows a colon, this must be the parameter name. parameters[parameters.length] = token; } else if (token == TOKEN_OPEN_PARENTHESIS) + { + var type = ""; + // Since :( is handled above, this must be the return type, just swallow it. - while((token = tokens.skip_whitespace()) && token != TOKEN_CLOSE_PARENTHESIS) ; + while((token = tokens.skip_whitespace()) && token != TOKEN_CLOSE_PARENTHESIS) + type += token; + + // types[0] is the return argument + types[0] = type || null; + } // Argument list ", ..." else if (token == TOKEN_COMMA) @@ -640,7 +655,7 @@ objj_preprocessor.prototype.method = function(tokens) CONCAT(buffer, ")\n{ with(self)\n{"); CONCAT(buffer, this.preprocess(tokens, NULL, TOKEN_CLOSE_BRACE, TOKEN_OPEN_BRACE)); - CONCAT(buffer, "}\n})"); + CONCAT(buffer, "}\n},"+types.toSource()+")"); return buffer; } diff --git a/Objective-J/runtime.js b/Objective-J/runtime.js index 365ab725a..fa6fb2273 100644 --- a/Objective-J/runtime.js +++ b/Objective-J/runtime.js @@ -542,3 +542,84 @@ function sel_registerName(aName) { return aName; } + + +// Type checking version of objj_msgSend: + +function objj_msgSendTypeCheck(/*id*/ aReceiver, /*SEL*/ aSelector) +{ + if (aReceiver == nil) + return nil; + + CLASS_GET_METHOD_IMPLEMENTATION(var implementation, aReceiver.isa, aSelector); + + var types = method.types; + + for (var i = 2; i < arguments.length; i++) + { + try + { + runtimeTypeCheck(types[i-1], arguments[i]); + } + catch (e) + { + objj_fprintf(warning_stream, "Type check failure: "+ + "aReceiver="+String(aReceiver).substring(0,100)+", "+ + "aSelector="+String(aSelector).substring(0,100)+", "+ + "argument #"+(i-2)+": " + e); + } + } + + var result = implementation.apply(aReceiver, arguments); + + try + { + runtimeTypeCheck(types[0], result); + } + catch (e) + { + objj_fprintf(warning_stream, "Type check failure: "+ + "aReceiver="+String(aReceiver).substring(0,100)+", "+ + "aSelector="+String(aSelector).substring(0,100)+", "+ + "return value: " + e); + } + + return result; +} + +function runtimeTypeCheck(typeName, actual) +{ + var objjClass; + + if (!typeName) + { + return; + } + if (typeName === "id") + { + return; + } + else if (typeName === "void") + { + if (actual === undefined) + return; + } + else if (objjClass = objj_getClass(typeName)) + { + if (actual && actual.isa) + { + var theClass = actual.isa; + for(; theClass; theClass = theClass.super_class) + if (theClass === objjClass) + return; + } + } + else + { + return; + } + + throw("Expected " + typeName + ", was [" + actual +"]"); +} + +objj_msgSend = objj_msgSendTypeCheck; From d7b679dc786f6942bec01d8420876b1d90172715 Mon Sep 17 00:00:00 2001 From: tlrobinson Date: Mon, 20 Jul 2009 18:39:37 -0700 Subject: [PATCH 02/53] * Move type checking to debug.js. * Use JSON.stringify for serializing types array. * Print Objective-J objects' names instead of descriptions to prevent inf recursion. --- Objective-J/debug.js | 81 +++++++++++++++++++++++++++++++++++++++ Objective-J/preprocess.js | 2 +- Objective-J/runtime.js | 81 --------------------------------------- 3 files changed, 82 insertions(+), 82 deletions(-) diff --git a/Objective-J/debug.js b/Objective-J/debug.js index cbc5fd447..dfaa573b2 100644 --- a/Objective-J/debug.js +++ b/Objective-J/debug.js @@ -171,3 +171,84 @@ function objj_profileEnd() return objj_profile_cleanup(); } + + +// Type checking version of objj_msgSend: + +function objj_msgSendTypeCheck(/*id*/ aReceiver, /*SEL*/ aSelector) +{ + if (aReceiver == nil) + return nil; + + CLASS_GET_METHOD_IMPLEMENTATION(var implementation, aReceiver.isa, aSelector); + + var types = method.types; + + for (var i = 2; i < arguments.length; i++) + { + try + { + runtimeTypeCheck(types[i-1], arguments[i]); + } + catch (e) + { + objj_fprintf(warning_stream, "Type check failure: "+ + "aReceiver="+(aReceiver.isa ? "<"+aReceiver.isa.name+">" : String(aReceiver).substring(0,100))+", "+ + "aSelector="+String(aSelector).substring(0,100)+", "+ + "argument #"+(i-2)+": " + e); + } + } + + var result = implementation.apply(aReceiver, arguments); + + try + { + runtimeTypeCheck(types[0], result); + } + catch (e) + { + objj_fprintf(warning_stream, "Type check failure: "+ + "aReceiver="+(aReceiver.isa ? "<"+aReceiver.isa.name+">" : String(aReceiver).substring(0,100))+", "+ + "aSelector="+String(aSelector).substring(0,100)+", "+ + "return value: " + e); + } + + return result; +} + +function runtimeTypeCheck(typeName, actual) +{ + var objjClass; + + if (!typeName) + { + return; + } + if (typeName === "id") + { + return; + } + else if (typeName === "void") + { + if (actual === undefined) + return; + } + else if (objjClass = objj_getClass(typeName)) + { + if (actual && actual.isa) + { + var theClass = actual.isa; + for(; theClass; theClass = theClass.super_class) + if (theClass === objjClass) + return; + } + } + else + { + return; + } + + throw("Expected " + typeName + ", was [" + ((actual && actual.isa) ? "<"+actual.isa.name+">" : actual) +"]"); +} + +objj_msgSend = objj_msgSendTypeCheck; diff --git a/Objective-J/preprocess.js b/Objective-J/preprocess.js index f09af79f1..473c70f4b 100644 --- a/Objective-J/preprocess.js +++ b/Objective-J/preprocess.js @@ -655,7 +655,7 @@ objj_preprocessor.prototype.method = function(tokens) CONCAT(buffer, ")\n{ with(self)\n{"); CONCAT(buffer, this.preprocess(tokens, NULL, TOKEN_CLOSE_BRACE, TOKEN_OPEN_BRACE)); - CONCAT(buffer, "}\n},"+types.toSource()+")"); + CONCAT(buffer, "}\n},"+JSON.stringify(types)+")"); return buffer; } diff --git a/Objective-J/runtime.js b/Objective-J/runtime.js index fa6fb2273..365ab725a 100644 --- a/Objective-J/runtime.js +++ b/Objective-J/runtime.js @@ -542,84 +542,3 @@ function sel_registerName(aName) { return aName; } - - -// Type checking version of objj_msgSend: - -function objj_msgSendTypeCheck(/*id*/ aReceiver, /*SEL*/ aSelector) -{ - if (aReceiver == nil) - return nil; - - CLASS_GET_METHOD_IMPLEMENTATION(var implementation, aReceiver.isa, aSelector); - - var types = method.types; - - for (var i = 2; i < arguments.length; i++) - { - try - { - runtimeTypeCheck(types[i-1], arguments[i]); - } - catch (e) - { - objj_fprintf(warning_stream, "Type check failure: "+ - "aReceiver="+String(aReceiver).substring(0,100)+", "+ - "aSelector="+String(aSelector).substring(0,100)+", "+ - "argument #"+(i-2)+": " + e); - } - } - - var result = implementation.apply(aReceiver, arguments); - - try - { - runtimeTypeCheck(types[0], result); - } - catch (e) - { - objj_fprintf(warning_stream, "Type check failure: "+ - "aReceiver="+String(aReceiver).substring(0,100)+", "+ - "aSelector="+String(aSelector).substring(0,100)+", "+ - "return value: " + e); - } - - return result; -} - -function runtimeTypeCheck(typeName, actual) -{ - var objjClass; - - if (!typeName) - { - return; - } - if (typeName === "id") - { - return; - } - else if (typeName === "void") - { - if (actual === undefined) - return; - } - else if (objjClass = objj_getClass(typeName)) - { - if (actual && actual.isa) - { - var theClass = actual.isa; - for(; theClass; theClass = theClass.super_class) - if (theClass === objjClass) - return; - } - } - else - { - return; - } - - throw("Expected " + typeName + ", was [" + actual +"]"); -} - -objj_msgSend = objj_msgSendTypeCheck; From 745e24d2f5a9368da0c1b64227fa626c78577d45 Mon Sep 17 00:00:00 2001 From: tlrobinson Date: Mon, 20 Jul 2009 18:42:54 -0700 Subject: [PATCH 03/53] Rename objj_msgSendTypeCheck to objj_msgSend_TypeCheck to match others --- Objective-J/debug.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Objective-J/debug.js b/Objective-J/debug.js index dfaa573b2..59563e4fa 100644 --- a/Objective-J/debug.js +++ b/Objective-J/debug.js @@ -175,7 +175,7 @@ function objj_profileEnd() // Type checking version of objj_msgSend: -function objj_msgSendTypeCheck(/*id*/ aReceiver, /*SEL*/ aSelector) +function objj_msgSend_TypeCheck(/*id*/ aReceiver, /*SEL*/ aSelector) { if (aReceiver == nil) return nil; @@ -251,4 +251,4 @@ function runtimeTypeCheck(typeName, actual) throw("Expected " + typeName + ", was [" + ((actual && actual.isa) ? "<"+actual.isa.name+">" : actual) +"]"); } -objj_msgSend = objj_msgSendTypeCheck; +objj_msgSend = objj_msgSend_TypeCheck; From 3ff945663f1033b31914da29d87a3ee7af4894dc Mon Sep 17 00:00:00 2001 From: Tom Robinson Date: Thu, 23 Jul 2009 13:24:33 -0700 Subject: [PATCH 04/53] Refactored objj_msgSend debug hooks --- Objective-J/debug.js | 344 +++++++++++++++++++++++-------------------- 1 file changed, 185 insertions(+), 159 deletions(-) diff --git a/Objective-J/debug.js b/Objective-J/debug.js index 59563e4fa..e01fbcb7a 100644 --- a/Objective-J/debug.js +++ b/Objective-J/debug.js @@ -1,103 +1,207 @@ -function objj_backtrace_format(aReceiver, aSelector) +// formatting helpers + +function objj_debug_object_format(aReceiver) { - return "[<" + GETMETA(aReceiver).name + " " + (typeof sprintf == "function" ? sprintf("%#08x", aReceiver.__address) : aReceiver.__address.toString(16)) + "> " + aSelector + "]"; + return (aReceiver && aReceiver.isa) ? sprintf("<%s %#08x>", GETMETA(aReceiver).name, aReceiver.__address) : String(aReceiver); } -function objj_msgSend_Backtrace(/*id*/ aReceiver, /*SEL*/ aSelector) +function objj_debug_message_format(aReceiver, aSelector) { - if (aReceiver == nil) - return nil; + return sprintf("[%s %s]", objj_debug_object_format(aReceiver), aSelector); +} - objj_debug_backtrace.push(objj_backtrace_format(aReceiver, aSelector)); - try +// save the original msgSend implementations so we can restore them later +var objj_msgSend_original = objj_msgSend, + objj_msgSendSuper_original = objj_msgSendSuper; + + +// decorator management functions + +// reset to default objj_msgSend* implementations +function objj_msgSend_reset() +{ + objj_msgSend = objj_msgSend_original; + objj_msgSendSuper = objj_msgSendSuper_original; +} + +// decorate both objj_msgSend and objj_msgSendSuper +function objj_msgSend_decorate() +{ + for (var i = 0; i < arguments.length; i++) { - var result = class_getMethodImplementation(aReceiver.isa, aSelector).apply(aReceiver, arguments); + objj_msgSend = arguments[i](objj_msgSend); + objj_msgSendSuper = arguments[i](objj_msgSendSuper); } - catch (anException) - { - CPLog.error("Exception " + anException + " in " + objj_backtrace_format(aReceiver, aSelector)); - objj_debug_print_backtrace(); - } - - objj_debug_backtrace.pop(); - - return result; } -function objj_msgSendSuper_Backtrace(/*id*/ aSuper, /*SEL*/ aSelector) +// reset then decorate both objj_msgSend and objj_msgSendSuper +function objj_msgSend_set_decorators() { - objj_debug_backtrace.push(objj_backtrace_format(aSuper.receiver, aSelector)); - var super_class = aSuper.super_class; - - arguments[0] = aSuper.receiver; - - try - { - var result = class_getMethodImplementation(super_class, aSelector).apply(aSuper.receiver, arguments); - } - catch (anException) - { - CPLog.error("Exception " + anException + " in " + objj_backtrace_format(aSuper.receiver, aSelector)); - objj_debug_print_backtrace(); - } - - objj_debug_backtrace.pop(); - - return result; + objj_msgSend_reset(); + objj_msgSend_decorate.apply(null, arguments); } -function objj_msgSend_Profile(/*id*/ aReceiver, /*SEL*/ aSelector) + +// backtrace decorator + +var objj_backtrace = []; +function objj_backtrace_decorator(msgSend) { - if (aReceiver == nil) - return nil; - - // profiling book keeping - var profileRecord = { - parent : objj_debug_profile, - receiver : GETMETA(aReceiver).name, - selector : aSelector, - calls : [] + return function(aReceiverOrSuper, aSelector) + { + var aReceiver = aReceiverOrSuper && (aReceiverOrSuper.receiver || aReceiverOrSuper); + + // push the receiver and selector onto the backtrace stack + objj_backtrace.push({ receiver: aReceiver, selector : aSelector }); + try + { + return msgSend.apply(null, arguments); + } + catch (anException) + { + // print the exception and backtrace + objj_fprintf(warning_stream, "Exception " + anException + " in " + objj_debug_message_format(aReceiver, aSelector)); + for (var i = 0; i < objj_backtrace.length; i++) + objj_fprintf(warning_stream, objj_debug_message_format(objj_backtrace[i].receiver, objj_backtrace[i].selector)); + } + finally + { + // make sure to always pop + objj_backtrace.pop(); + } } - objj_debug_profile.calls.push(profileRecord); - objj_debug_profile = profileRecord; - profileRecord.start = new Date(); - - var result = class_getMethodImplementation(aReceiver.isa, aSelector).apply(aReceiver, arguments); - - profileRecord.end = new Date(); - objj_debug_profile = profileRecord.parent; - - return result; } -function objj_msgSendSuper_Profile(/*id*/ aSuper, /*SEL*/ aSelector) +// type checking decorator + +var objj_typechecks_reported = {}; +function objj_typecheck_decorator(msgSend) { - // profiling book keeping - var profileRecord = { - parent : objj_debug_profile, - receiver : GETMETA(aReceiver).name, - selector : aSelector, - calls : [] + return function(aReceiverOrSuper, aSelector) + { + var aReceiver = aReceiverOrSuper && (aReceiverOrSuper.receiver || aReceiverOrSuper); + + if (!aReceiver) + return msgSend.apply(null, arguments); + + var types = aReceiver.isa.method_dtable[aSelector].types; + for (var i = 2; i < arguments.length; i++) + { + try + { + objj_debug_typecheck(types[i-1], arguments[i]); + } + catch (e) + { + var key = [GETMETA(aReceiver).name, aSelector, i, e].join(";"); + if (!objj_typechecks_reported[key]) { + objj_typechecks_reported[key] = true; + objj_fprintf(warning_stream, "Type check failed on argument " + (i-2) + " of " + objj_debug_message_format(aReceiver, aSelector) + ": " + e); + } + } + } + + var result = msgSend.apply(null, arguments); + + try + { + objj_debug_typecheck(types[0], result); + } + catch (e) + { + var key = [GETMETA(aReceiver).name, aSelector, "ret", e].join(";"); + if (!objj_typechecks_reported[key]) { + objj_typechecks_reported[key] = true; + objj_fprintf(warning_stream, "Type check failed on return val of " + objj_debug_message_format(aReceiver, aSelector) + ": " + e); + } + } + + return result; } - objj_debug_profile.calls.push(profileRecord); - objj_debug_profile = profileRecord; - profileRecord.start = new Date(); - - var super_class = aSuper.super_class; - - arguments[0] = aSuper.receiver; - - var result = class_getMethodImplementation(super_class, aSelector).apply(aSuper.receiver, arguments); - - profileRecord.end = new Date(); - objj_debug_profile = profileRecord.parent; - - return result; } -var objj_msgSend_Standard = objj_msgSend, - objj_msgSendSuper_Standard = objj_msgSendSuper; +// type checking logic: +function objj_debug_typecheck(expectedType, object) +{ + var objjClass; + + if (!expectedType) + { + return; + } + else if (expectedType === "id") + { + if (object !== undefined) + return; + } + else if (expectedType === "void") + { + if (object === undefined) + return; + } + else if (objjClass = objj_getClass(expectedType)) + { + if (object === nil) + { + return; + } + else if (object.isa) + { + var theClass = object.isa; + for (; theClass; theClass = theClass.super_class) + if (theClass === objjClass) + return; + } + } + else + { + return; + } + + var actualType; + if (object === null) + actualType = "null"; + else if (object === undefined) + actualType = "void"; + else if (object.isa) + actualType = GETMETA(object).name; + else + actualType = typeof object; + + throw ("expected=" + expectedType + ", actual=" + actualType); +} + +// profile decorator +/* +function objj_debug_profile(msgSend) +{ + return function(aReceiverOrSuper, aSelector) + { + var aReceiver = aReceiverOrSuper && (aReceiverOrSuper.receiver || aReceiverOrSuper); + + // profiling book keeping + var profileRecord = { + parent : objj_debug_profile, + receiver : aReceiver && GETMETA(aReceiver).name, + selector : aSelector, + calls : [] + } + objj_debug_profile.calls.push(profileRecord); + objj_debug_profile = profileRecord; + profileRecord.start = new Date(); + + try + { + return msgSend.apply(null, arguments); + } + finally + { + profileRecord.end = new Date(); + objj_debug_profile = profileRecord.parent; + } + } +} // FIXME: This could be much better. var objj_debug_backtrace; @@ -171,84 +275,6 @@ function objj_profileEnd() return objj_profile_cleanup(); } +*/ - -// Type checking version of objj_msgSend: - -function objj_msgSend_TypeCheck(/*id*/ aReceiver, /*SEL*/ aSelector) -{ - if (aReceiver == nil) - return nil; - - CLASS_GET_METHOD_IMPLEMENTATION(var implementation, aReceiver.isa, aSelector); - - var types = method.types; - - for (var i = 2; i < arguments.length; i++) - { - try - { - runtimeTypeCheck(types[i-1], arguments[i]); - } - catch (e) - { - objj_fprintf(warning_stream, "Type check failure: "+ - "aReceiver="+(aReceiver.isa ? "<"+aReceiver.isa.name+">" : String(aReceiver).substring(0,100))+", "+ - "aSelector="+String(aSelector).substring(0,100)+", "+ - "argument #"+(i-2)+": " + e); - } - } - - var result = implementation.apply(aReceiver, arguments); - - try - { - runtimeTypeCheck(types[0], result); - } - catch (e) - { - objj_fprintf(warning_stream, "Type check failure: "+ - "aReceiver="+(aReceiver.isa ? "<"+aReceiver.isa.name+">" : String(aReceiver).substring(0,100))+", "+ - "aSelector="+String(aSelector).substring(0,100)+", "+ - "return value: " + e); - } - - return result; -} - -function runtimeTypeCheck(typeName, actual) -{ - var objjClass; - - if (!typeName) - { - return; - } - if (typeName === "id") - { - return; - } - else if (typeName === "void") - { - if (actual === undefined) - return; - } - else if (objjClass = objj_getClass(typeName)) - { - if (actual && actual.isa) - { - var theClass = actual.isa; - for(; theClass; theClass = theClass.super_class) - if (theClass === objjClass) - return; - } - } - else - { - return; - } - - throw("Expected " + typeName + ", was [" + ((actual && actual.isa) ? "<"+actual.isa.name+">" : actual) +"]"); -} - -objj_msgSend = objj_msgSend_TypeCheck; +objj_msgSend_set_decorators(objj_typecheck_decorator, objj_backtrace_decorator); From 88be473da432591e4b95cf4dde52713e6d874915 Mon Sep 17 00:00:00 2001 From: Tom Robinson Date: Thu, 23 Jul 2009 14:14:34 -0700 Subject: [PATCH 05/53] Fixed bug in type check logic, added ability to print stack traces on type check errors --- Objective-J/debug.js | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/Objective-J/debug.js b/Objective-J/debug.js index e01fbcb7a..fddd7fed7 100644 --- a/Objective-J/debug.js +++ b/Objective-J/debug.js @@ -46,6 +46,12 @@ function objj_msgSend_set_decorators() // backtrace decorator var objj_backtrace = []; + +function objj_backtrace_print(stream) { + for (var i = 0; i < objj_backtrace.length; i++) + objj_fprintf(stream, objj_debug_message_format(objj_backtrace[i].receiver, objj_backtrace[i].selector)); +} + function objj_backtrace_decorator(msgSend) { return function(aReceiverOrSuper, aSelector) @@ -62,8 +68,7 @@ function objj_backtrace_decorator(msgSend) { // print the exception and backtrace objj_fprintf(warning_stream, "Exception " + anException + " in " + objj_debug_message_format(aReceiver, aSelector)); - for (var i = 0; i < objj_backtrace.length; i++) - objj_fprintf(warning_stream, objj_debug_message_format(objj_backtrace[i].receiver, objj_backtrace[i].selector)); + objj_backtrace_print(warning_stream); } finally { @@ -75,7 +80,9 @@ function objj_backtrace_decorator(msgSend) // type checking decorator -var objj_typechecks_reported = {}; +var objj_typechecks_reported = {}, + objj_typecheck_prints_backtrace = false; + function objj_typecheck_decorator(msgSend) { return function(aReceiverOrSuper, aSelector) @@ -98,6 +105,8 @@ function objj_typecheck_decorator(msgSend) if (!objj_typechecks_reported[key]) { objj_typechecks_reported[key] = true; objj_fprintf(warning_stream, "Type check failed on argument " + (i-2) + " of " + objj_debug_message_format(aReceiver, aSelector) + ": " + e); + if (objj_typecheck_prints_backtrace) + objj_backtrace_fprint(warning_stream); } } } @@ -114,6 +123,8 @@ function objj_typecheck_decorator(msgSend) if (!objj_typechecks_reported[key]) { objj_typechecks_reported[key] = true; objj_fprintf(warning_stream, "Type check failed on return val of " + objj_debug_message_format(aReceiver, aSelector) + ": " + e); + if (objj_typecheck_prints_backtrace) + objj_backtrace_fprint(warning_stream); } } @@ -146,7 +157,7 @@ function objj_debug_typecheck(expectedType, object) { return; } - else if (object.isa) + else if (object && object.isa) { var theClass = object.isa; for (; theClass; theClass = theClass.super_class) From 4824f22e3ce0880d526338751e6a1ec0c7402baa Mon Sep 17 00:00:00 2001 From: Francisco Ryan Tolmasky I Date: Fri, 24 Jul 2009 11:22:32 -0700 Subject: [PATCH 06/53] Fix for super not working for class methods. Closes #227. Reviewed by me. --- Objective-J/preprocess.js | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/Objective-J/preprocess.js b/Objective-J/preprocess.js index 0032ed203..47218a9ca 100644 --- a/Objective-J/preprocess.js +++ b/Objective-J/preprocess.js @@ -170,6 +170,7 @@ var objj_preprocessor = function(aString, aSourceFile, aBundle, flags) { this._currentClass = ""; this._currentSuperClass = ""; + this._currentSuperMetaClass = ""; this._file = aSourceFile; this._fragments = []; @@ -177,6 +178,7 @@ var objj_preprocessor = function(aString, aSourceFile, aBundle, flags) this._tokens = new objj_lexer(aString); this._flags = flags; this._bundle = aBundle; + this._classMethod = false; this.preprocess(this._tokens, this._preprocessed); //alert(this._preprocessed + ""); @@ -262,8 +264,7 @@ objj_preprocessor.prototype.brackets = function(/*objj_lexer*/ tokens, /*objj_st if (tuples[0][0].atoms[0] == TOKEN_SUPER) { CONCAT(aStringBuffer, "objj_msgSendSuper("); - CONCAT(aStringBuffer, "{ receiver:self, super_class:" + this._currentSuperClass + " }"); - + CONCAT(aStringBuffer, "{ receiver:self, super_class:" + (this._classMethod ? this._currentSuperMetaClass : this._currentSuperClass ) + " }"); } else { @@ -350,7 +351,7 @@ objj_preprocessor.prototype.implementation = function(tokens, /*objj_stringBuffe category = NO, class_name = tokens.skip_whitespace(), superclass_name = "Nil", - + instance_methods = new objj_stringBuffer(), class_methods = new objj_stringBuffer(); @@ -358,6 +359,7 @@ objj_preprocessor.prototype.implementation = function(tokens, /*objj_stringBuffe objj_exception_throw(new objj_exception(OBJJParseException, "*** Expected class name, found \"" + class_name + "\".")); this._currentSuperClass = NULL; + this._currentSuperMetaClass = NULL; this._currentClass = class_name; // If we reach an open parenthesis, we are declaring a category. @@ -376,12 +378,18 @@ objj_preprocessor.prototype.implementation = function(tokens, /*objj_stringBuffe CONCAT(buffer, "var meta_class = the_class.isa;"); var superclass_name = dictionary_getValue(SUPER_CLASSES, class_name); - + // FIXME: We should have a better solution for this case, although it's actually not much slower than the real case. if (!superclass_name) + { this._currentSuperClass = "objj_getClass(\"" + class_name + "\").super_class"; + this._currentSuperMetaClass = "objj_getMetaClass(\"" + class_name + "\").super_class"; + } else + { this._currentSuperClass = "objj_getClass(\"" + superclass_name + "\")"; + this._currentSuperMetaClass = "objj_getMeraClass(\"" + superclass_name + "\")"; + } } else { @@ -394,7 +402,9 @@ objj_preprocessor.prototype.implementation = function(tokens, /*objj_stringBuffe objj_exception_throw(new objj_exception(OBJJParseException, "*** Expected class name, found \"" + token + "\".")); superclass_name = token; + this._currentSuperClass = "objj_getClass(\"" + superclass_name + "\")"; + this._currentSuperMetaClass = "objj_getMetaClass(\"" + superclass_name + "\")"; dictionary_setValue(SUPER_CLASSES, class_name, superclass_name); @@ -503,6 +513,8 @@ objj_preprocessor.prototype.implementation = function(tokens, /*objj_stringBuffe { if (token == TOKEN_PLUS) { + this._classMethod = true; + if (IS_NOT_EMPTY(class_methods)) CONCAT(class_methods, ", "); @@ -511,6 +523,8 @@ objj_preprocessor.prototype.implementation = function(tokens, /*objj_stringBuffe else if (token == TOKEN_MINUS) { + this._classMethod = false; + if (IS_NOT_EMPTY(instance_methods)) CONCAT(instance_methods, ", "); From 57ee7bcfce4a4a46116c3859671426c93e38503d Mon Sep 17 00:00:00 2001 From: cacaodev Date: Thu, 16 Jul 2009 01:53:04 +0800 Subject: [PATCH 07/53] Fixed bug reported by Paul Tomlin http://groups.google.com/group/objectivej/browse_thread/thread/e4bc41026a8f100f/6b14f3b74189df18 Signed-off-by: Francisco Ryan Tolmasky I --- AppKit/CPSearchField.j | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/AppKit/CPSearchField.j b/AppKit/CPSearchField.j index 8adc431aa..d4c575197 100644 --- a/AppKit/CPSearchField.j +++ b/AppKit/CPSearchField.j @@ -143,8 +143,7 @@ var CPSearchFieldSearchImage = nil, // Managing Buttons /*! Sets the button used to display the search-button image - @param button - @param The search button. + @param button The search button. */ - (void)setSearchButton:(CPButton)button { @@ -567,7 +566,7 @@ var CPSearchFieldSearchImage = nil, - (void)_showMenu:(id)sender { - if(_searchMenu == nil) + if(_searchMenu == nil || ![self isEnabled]) return; [super selectText:nil]; @@ -690,13 +689,15 @@ var CPSearchButtonKey = @"CPSearchButtonKey", self = [super initWithCoder:coder]; _searchButton = [coder decodeObjectForKey:CPSearchButtonKey]; - _searchButton = [coder decodeObjectForKey:CPCancelButtonKey]; + _cancelButton = [coder decodeObjectForKey:CPCancelButtonKey]; _recentsAutosaveName = [coder decodeObjectForKey:CPRecentsAutosaveNameKey]; _sendsWholeSearchString = [coder decodeBoolForKey:CPSendsWholeSearchStringKey]; _sendsSearchStringImmediately = [coder decodeBoolForKey:CPSendsSearchStringImmediatelyKey]; _maximumRecents = [coder decodeIntForKey:CPMaximumRecentsKey]; [self setSearchMenuTemplate:[coder decodeObjectForKey:CPSearchMenuTemplateKey]]; - + [self resetCancelButton]; + [self setDelegate:self]; + return self; } From 5829c8b6820113264fde7b3cb15e61ceb3a12afd Mon Sep 17 00:00:00 2001 From: Ross Boucher Date: Fri, 24 Jul 2009 22:49:18 -0700 Subject: [PATCH 08/53] Fix an issue where removing all items from a CPPopUpButton caused an exception. --- AppKit/CPPopUpButton.j | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/AppKit/CPPopUpButton.j b/AppKit/CPPopUpButton.j index acaecb870..47d7e2176 100644 --- a/AppKit/CPPopUpButton.j +++ b/AppKit/CPPopUpButton.j @@ -204,7 +204,7 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down"); */ - (CPMenuItem)selectedItem { - if (_selectedIndex < 0) + if (_selectedIndex < 0 || _selectedIndex > [self numberOfItems] - 1) return nil; return [_menu itemAtIndex:_selectedIndex]; @@ -550,7 +550,7 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down"); - (void)synchronizeTitleAndSelectedItem { var item = nil; - +debugger; if ([self pullsDown]) { var items = [_menu itemArray]; @@ -628,13 +628,15 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down"); { var numberOfItems = [self numberOfItems]; - if (numberOfItems <= _selectedIndex) + if (numberOfItems <= _selectedIndex && numberOfItems > 0) [self selectItemAtIndex:numberOfItems - 1]; + else + [self synchronizeTitleAndSelectedItem]; } - (void)mouseDown:(CPEvent)anEvent { - if (![self isEnabled]) + if (![self isEnabled] || ![self numberOfItems]) return; [self highlight:YES]; From 82cfc5f994ed2ee645a6068fabdc487e377121a3 Mon Sep 17 00:00:00 2001 From: Geoffrey Grosenbach Date: Sun, 5 Jul 2009 22:26:41 -0700 Subject: [PATCH 09/53] Created initial test for CPSegmentedControl --- Tests/AppKit/CPSegmentedControlTest.j | 33 +++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 Tests/AppKit/CPSegmentedControlTest.j diff --git a/Tests/AppKit/CPSegmentedControlTest.j b/Tests/AppKit/CPSegmentedControlTest.j new file mode 100644 index 000000000..ffd794113 --- /dev/null +++ b/Tests/AppKit/CPSegmentedControlTest.j @@ -0,0 +1,33 @@ +@import + +// TODO: Maybe create one test file for each tracking mode so they can be tested separately without confusion. +@implementation CPSegmentedControlTest : OJTestCase +{ + CPSegmentedControlTest _segmentedControl; +} + +- (void)setUp +{ + _segmentedControl = [[CPSegmentedControl alloc] initWithFrame:CGRectMakeZero()]; + [_segmentedControl setSegmentCount:3]; +} + +- (void)testMakeCPSegmentedControlInstance +{ + [self assertNotNull:_segmentedControl]; +} + +- (void)testDefaultsToSelectOneTrackingMode +{ + [self assert:[_segmentedControl trackingMode] equals:CPSegmentSwitchTrackingSelectOne]; +} + +- (void)testSelectsOneSegmentStartingAtBlankState +{ + [self assert:[_segmentedControl selectedSegment] equals:-1]; + [_segmentedControl setSelectedSegment:1]; + [self assert:[_segmentedControl selectedSegment] equals:1]; +} + +@end + From 8382bb1ae85dc9a1e0828f2169231b7c98d411c8 Mon Sep 17 00:00:00 2001 From: Francisco Ryan Tolmasky I Date: Sat, 25 Jul 2009 16:47:30 -0700 Subject: [PATCH 10/53] Beginnings of Platform reorg. Reviewed by me. --- AppKit/CPApplication.j | 9 +- AppKit/CPMenu.j | 2 +- AppKit/CPStringDrawing.j | 76 +- AppKit/CPWindow/CPWindow.j | 1 + AppKit/Platform/CPPlatform.j | 27 + AppKit/Platform/CPPlatformString.j | 104 +++ AppKit/Platform/CPPlatformWindow.j | 101 +++ AppKit/Platform/DOM/CPDOMWindowBridge.j | 965 +------------------- AppKit/Platform/DOM/_CPBrowserWindow.j | 10 + AppKit/Platform/DOM/_CPDOMWindow.j | 1063 +++++++++++++++++++++++ 10 files changed, 1335 insertions(+), 1023 deletions(-) create mode 100644 AppKit/Platform/CPPlatform.j create mode 100644 AppKit/Platform/CPPlatformString.j create mode 100644 AppKit/Platform/CPPlatformWindow.j create mode 100644 AppKit/Platform/DOM/_CPBrowserWindow.j create mode 100644 AppKit/Platform/DOM/_CPDOMWindow.j diff --git a/AppKit/CPApplication.j b/AppKit/CPApplication.j index f150bb026..f7c9962b8 100644 --- a/AppKit/CPApplication.j +++ b/AppKit/CPApplication.j @@ -29,6 +29,8 @@ @import "CPDocumentController.j" @import "CPThemeBlend.j" @import "CPCibLoading.j" +@import "CPPlatform.j" + var CPMainCibFile = @"CPMainCibFile", CPMainCibFileHumanFriendly = @"Main cib file base name"; @@ -805,7 +807,7 @@ var _CPAppBootstrapperActions = nil; + (void)actions { - return [@selector(loadDefaultTheme), @selector(loadMainCibFile)]; + return [@selector(bootstrapPlatform), @selector(loadDefaultTheme), @selector(loadMainCibFile)]; } + (void)performActions @@ -824,6 +826,11 @@ var _CPAppBootstrapperActions = nil; [CPApp run]; } ++ (BOOL)bootstrapPlatform +{ + return [CPPlatform bootstrap]; +} + + (BOOL)loadDefaultTheme { var blend = [[CPThemeBlend alloc] initWithContentsOfURL:[[CPBundle bundleForClass:[CPApplication class]] pathForResource:@"Aristo.blend"]]; diff --git a/AppKit/CPMenu.j b/AppKit/CPMenu.j index 79ca0e9d2..46e415468 100644 --- a/AppKit/CPMenu.j +++ b/AppKit/CPMenu.j @@ -119,7 +119,7 @@ var _CPMenuBarVisible = NO, // FIXME: There must be a better way to do this. #if PLATFORM(DOM) - [[CPDOMWindowBridge sharedDOMWindowBridge] _bridgeResizeEvent:nil]; + [window.platformWindow resizeEvent:nil]; #endif } diff --git a/AppKit/CPStringDrawing.j b/AppKit/CPStringDrawing.j index 61b4fda70..dec7bde1c 100644 --- a/AppKit/CPStringDrawing.j +++ b/AppKit/CPStringDrawing.j @@ -22,13 +22,9 @@ @import -#include "CoreGraphics/CGGeometry.h" -#include "Platform/Platform.h" +@import "CPPlatformString.j" -var CPStringReferenceElement = nil, - CPStringDefaultFont = nil; - @implementation CPString (CPStringDrawing) /*! @@ -46,75 +42,7 @@ var CPStringReferenceElement = nil, - (CGSize)sizeWithFont:(CPFont)aFont inWidth:(float)aWidth { -#if PLATFORM(DOM) - if (!CPStringReferenceElement) - { - CPStringReferenceElement = document.createElement("span"); - - var style = CPStringReferenceElement.style; - - style.position = "absolute"; - style.whiteSpace = "pre"; - style.visibility = "visible"; - style.padding = "0px"; - style.margin = "0px"; - - style.left = "-100000px"; - style.top = "-100000px"; - style.zIndex = "10000"; - style.background = "red"; - - document.getElementsByTagName("body")[0].appendChild(CPStringReferenceElement); - } - - if (!aFont) - { - if (!CPStringDefaultFont) - CPStringDefaultFont = [CPFont systemFontOfSize:12.0]; - - aFont = CPStringDefaultFont; - } - - var style = CPStringReferenceElement.style; - - if (aWidth === NULL) - { - style.width = ""; - style.whiteSpace = "pre"; - } - - else - { - style.width = ROUND(aWidth) + "px"; - - if (document.attachEvent) - style.wordWrap = "break-word"; - - else - { - style.whiteSpace = "-o-pre-wrap"; - style.whiteSpace = "-pre-wrap"; - style.whiteSpace = "-moz-pre-wrap"; - style.whiteSpace = "pre-wrap"; - } - } - - style.font = [aFont cssString]; - - if (CPFeatureIsCompatible(CPJavascriptInnerTextFeature)) - CPStringReferenceElement.innerText = self; - - else if (CPFeatureIsCompatible(CPJavascriptTextContentFeature)) - CPStringReferenceElement.textContent = self; - - return _CGSizeMake(CPStringReferenceElement.clientWidth, CPStringReferenceElement.clientHeight); -#endif - return _CGSizeMakeZero(); -} - -+ (void)_resetSize -{ - CPStringReferenceElement = nil; + return [CPPlatformString sizeOfString:self withFont:aFont forWidth:aWidth]; } @end diff --git a/AppKit/CPWindow/CPWindow.j b/AppKit/CPWindow/CPWindow.j index 48a9968c6..b3499c575 100644 --- a/AppKit/CPWindow/CPWindow.j +++ b/AppKit/CPWindow/CPWindow.j @@ -27,6 +27,7 @@ @import "CGGeometry.j" @import "CPAnimation.j" @import "CPResponder.j" +@import "CPPlatformWindow.j" #include "../Platform/Platform.h" #include "../Platform/DOM/CPDOMDisplayServer.h" diff --git a/AppKit/Platform/CPPlatform.j b/AppKit/Platform/CPPlatform.j new file mode 100644 index 000000000..e7db6ddb1 --- /dev/null +++ b/AppKit/Platform/CPPlatform.j @@ -0,0 +1,27 @@ + +@import + +#include "Platform.h" + + +@implementation CPPlatform : CPObject +{ +} + ++ (void)bootstrap +{ +#if PLATFORM(DOM) + var body = document.getElementsByTagName("body")[0]; + + body.innerHTML = ""; // Get rid of anything that might be lingering in the body element. + body.style.overflow = "hidden"; + + if (document.documentElement) + document.documentElement.style.overflow = "hidden"; +#endif + + [CPPlatformString bootstrap]; + window.firstWindow = [[CPPlatformWindow alloc] _init]; +} + +@end diff --git a/AppKit/Platform/CPPlatformString.j b/AppKit/Platform/CPPlatformString.j new file mode 100644 index 000000000..24e91d152 --- /dev/null +++ b/AppKit/Platform/CPPlatformString.j @@ -0,0 +1,104 @@ + + +@import + +#include "../CoreGraphics/CGGeometry.h" +#include "Platform.h" + + +#if PLATFORM(DOM) +var DOMIFrameElement = nil, + DOMSpanElement = nil, + DefaultFont = nil; +#endif + +@implementation CPPlatformString : CPObject +{ +} + ++ (void)bootstrap +{ +#if PLATFORM(DOM) + DOMIFrameElement = document.createElement("iframe"); + + DOMIFrameElement.name = name = "iframe_" + FLOOR(RAND() * 10000); + DOMIFrameElement.style.position = "absolute"; + DOMIFrameElement.style.left = "-100px"; + DOMIFrameElement.style.top = "-100px"; + DOMIFrameElement.style.width = "1px"; + DOMIFrameElement.style.height = "1px"; + DOMIFrameElement.style.borderWidth = "0px"; + DOMIFrameElement.style.background = "blue"; + DOMIFrameElement.style.overflow = "hidden"; + DOMIFrameElement.style.zIndex = 100000000000; + + document.getElementsByTagName("body")[0].appendChild(DOMIFrameElement); + + var DOMIFrameDocument = (DOMIFrameElement.contentDocument || DOMIFrameElement.contentWindow.document); + + DOMIFrameDocument.write(""); + DOMIFrameDocument.close(); + + DOMSpanElement = DOMIFrameDocument.createElement("span"); + + DOMSpanElement.style.position = "absolute"; + DOMSpanElement.style.whiteSpace = "pre"; + DOMSpanElement.style.visibility = "visible"; + DOMSpanElement.style.padding = "0px"; + DOMSpanElement.style.margin = "0px"; + DOMSpanElement.style.background = "red"; + + DOMIFrameDocument.getElementsByTagName("body")[0].appendChild(DOMSpanElement); +#endif +} + ++ (CGSize)sizeOfString:(CPString)aString withFont:(CPFont)aFont forWidth:(float)aWidth +{ +#if PLATFORM(DOM) + if (!aFont) + { + if (!DefaultFont) + DefaultFont = [CPFont systemFontOfSize:12.0]; + + aFont = DefaultFont; + } + + var style = DOMSpanElement.style; + + if (aWidth === NULL) + { + style.width = ""; + style.whiteSpace = "pre"; + } + + else + { + style.width = ROUND(aWidth) + "px"; + + if (document.attachEvent) + style.wordWrap = "break-word"; + + else + { + style.whiteSpace = "-o-pre-wrap"; + style.whiteSpace = "-pre-wrap"; + style.whiteSpace = "-moz-pre-wrap"; + style.whiteSpace = "pre-wrap"; + } + } + + style.font = [aFont cssString]; + + if (CPFeatureIsCompatible(CPJavascriptInnerTextFeature)) + DOMSpanElement.innerText = aString; + + else if (CPFeatureIsCompatible(CPJavascriptTextContentFeature)) + DOMSpanElement.textContent = aString; + + return _CGSizeMake(DOMSpanElement.clientWidth, DOMSpanElement.clientHeight); +#else + return _CGSizeMakeZero(); +#endif +} + +@end diff --git a/AppKit/Platform/CPPlatformWindow.j b/AppKit/Platform/CPPlatformWindow.j new file mode 100644 index 000000000..04e35b808 --- /dev/null +++ b/AppKit/Platform/CPPlatformWindow.j @@ -0,0 +1,101 @@ + +@import + +#import "Platform.h" +#import "../CoreGraphics/CGGeometry.h" + + +var PlatformWindowClass = NULL; + +@implementation CPPlatformWindow : CPObject +{ + CGRect _contentRect; +} + ++ (void)_setPlatformWindowClass:(Class)aClass +{ + PlatformWindowClass = aClass; +} + ++ (Class)_platformWindowClass +{ + return PlatformWindowClass; +} + ++ (id)alloc +{ + if (self === [CPPlatformWindow class]) + return [PlatformWindowClass alloc]; + + return [super alloc]; +} + +- (id)initWithContentRect:(CGRect)aRect +{ + self = [super init]; + + if (self) + _contentRect = _CGRectMakeCopy(aRect); + + return self; +} + +- (id)init +{ + return [self initWithContentRect:_CGRectMake(0.0, 0.0, 400.0, 500.0)]; +} + +- (CGRect)contentRect +{ + return _CGRectMakeCopy(_contentRect); +} + +- (void)setContentRect:(CGRect)aRect +{ + if (!aRect || _CGRectEqualToRect(_contentRect, aRect)) + return; + + [self setContentOrigin:aRect.origin]; + [self setContentSize:aRect.size]; +} + +- (void)setContentOrigin:(CGPoint)aPoint +{ + var origin = _contentRect.origin; + + if (!aPoint || _CGPointEqualToPoint(origin, aPoint)) + return; + + origin.x = aPoint.x; + origin.y = aPoint.y; + + [self updateNativeContentOrigin]; +} + +- (void)setContentSize:(CGSize)aSize +{ + var size = _contentRect.size; + + if (!aSize || _CGSizeEqualToSize(size, aSize)) + return; + + var delta = _CGSizeMake(aSize.width - size.width, aSize.height - size.height); + + size.width = aSize.width; + size.height = aSize.height; + + [self updateNativeContentSize]; +} + +- (void)updateFromNativeContentRect +{ + [self setContentRect:[self nativeContentRect]]; +} + +@end + +#if PLATFORM(BROWSER) +@import "_CPBrowserWindow.j" +#else +[CPPlatformWindow _setPlatformWindowClass:[CPPlatformWindow class]]; +#endif diff --git a/AppKit/Platform/DOM/CPDOMWindowBridge.j b/AppKit/Platform/DOM/CPDOMWindowBridge.j index 6b6c57d29..78f6fe640 100644 --- a/AppKit/Platform/DOM/CPDOMWindowBridge.j +++ b/AppKit/Platform/DOM/CPDOMWindowBridge.j @@ -26,7 +26,6 @@ @import "CPEvent.j" @import "CPCompatibility.j" -@import "CPDOMWindowLayer.j" #import "../../CoreGraphics/CGGeometry.h" @@ -42,168 +41,26 @@ var CPDOMWindowGetFrame, @implementation CPDOMWindowBridge : CPObject { - CPArray _orderedWindows; - CPWindow _mouseDownWindow; - - DOMWindow _DOMWindow; - DOMElement _DOMBodyElement; - DOMElement _DOMFocusElement; - - CPArray _windowLevels; - CPDictionary _windowLayers; - - CPRect _frame; - CPRect _contentBounds; - - BOOL _mouseIsDown; - CPTimeInterval _lastMouseUp; - CPTimeInterval _lastMouseDown; - - JSObject _charCodes; - unsigned _keyCode; - - BOOL _DOMEventMode; - - // Native Pasteboard Support - DOMElement _DOMPasteboardElement; - CPEvent _pasteboardKeyDownEvent; - - CPString _overriddenEventType; } /*! - Returns the shared DOMWindowBridge. + Returns the shared DOMWindowBridge. */ + (id)sharedDOMWindowBridge { if (!CPSharedDOMWindowBridge) - CPSharedDOMWindowBridge = [[CPDOMWindowBridge alloc] _initWithDOMWindow:window]; - + CPSharedDOMWindowBridge = [[CPDOMWindowBridge alloc] _init]; + return CPSharedDOMWindowBridge; } -- (id)initWithFrame:(CPRect)aFrame -{ - alert("unimplemented"); -} - /* @ignore */ -- (id)_initWithDOMWindow:(DOMWindow)aDOMWindow +- (id)_init//_initWithDOMWindow:(DOMWindow)aDOMWindow { self = [super init]; - + if (self) { - _DOMWindow = aDOMWindow; - - _windowLevels = []; - _windowLayers = [CPDictionary dictionary]; - - // Do this before getting the frame of the window, because if not it will be wrong in IE. - _DOMBodyElement = document.getElementsByTagName("body")[0]; - _DOMBodyElement.innerHTML = ""; // Get rid of anything that might be lingering in the body element. - _DOMBodyElement.style.overflow = "hidden"; - _DOMBodyElement.style.webkitTouchCallout = "none"; - - [CPString _resetSize]; - - if (document.documentElement) - document.documentElement.style.overflow = "hidden"; - - _frame = CPDOMWindowGetFrame(_DOMWindow); - _contentBounds = CGRectMake(0.0, 0.0, CPRectGetWidth(_frame), CPRectGetHeight(_frame)); - - _DOMFocusElement = document.createElement("input"); - _DOMFocusElement.style.position = "absolute"; - _DOMFocusElement.style.zIndex = "-1000"; - _DOMFocusElement.style.opacity = "0"; - _DOMFocusElement.style.filter = "alpha(opacity=0)"; - _DOMBodyElement.appendChild(_DOMFocusElement); - - // Create Native Pasteboard handler. - _DOMPasteboardElement = document.createElement("input"); - _DOMPasteboardElement.style.position = "absolute"; - _DOMPasteboardElement.style.top = "-10000px"; - _DOMPasteboardElement.style.zIndex = "99"; - - _DOMBodyElement.appendChild(_DOMPasteboardElement); - - // Make sure the pastboard element is blurred. - _DOMPasteboardElement.blur(); - - _charCodes = {}; - - // - var theClass = [self class], - - keyEventSelector = @selector(_bridgeKeyEvent:), - keyEventImplementation = class_getMethodImplementation(theClass, keyEventSelector), - keyEventCallback = function (anEvent) { keyEventImplementation(self, nil, anEvent); }, - - mouseEventSelector = @selector(_bridgeMouseEvent:), - mouseEventImplementation = class_getMethodImplementation(theClass, mouseEventSelector), - mouseEventCallback = function (anEvent) { mouseEventImplementation(self, nil, anEvent); }, - - scrollEventSelector = @selector(_bridgeScrollEvent:), - scrollEventImplementation = class_getMethodImplementation(theClass, scrollEventSelector), - scrollEventCallback = function (anEvent) { scrollEventImplementation(self, nil, anEvent); }, - - resizeEventSelector = @selector(_bridgeResizeEvent:), - resizeEventImplementation = class_getMethodImplementation(theClass, resizeEventSelector), - resizeEventCallback = function (anEvent) { resizeEventImplementation(self, nil, anEvent); }, - - touchEventSelector = @selector(_bridgeTouchEvent:), - touchEventImplementation = class_getMethodImplementation(theClass, touchEventSelector), - touchEventCallback = function (anEvent) { touchEventImplementation(self, nil, anEvent); }, - - theDocument = _DOMWindow.document; - - if (document.addEventListener) - { - _DOMWindow.addEventListener("resize", resizeEventCallback, NO); - - theDocument.addEventListener(CPDOMEventMouseUp, mouseEventCallback, NO); - theDocument.addEventListener(CPDOMEventMouseDown, mouseEventCallback, NO); - theDocument.addEventListener(CPDOMEventMouseMoved, mouseEventCallback, NO); - - theDocument.addEventListener(CPDOMEventKeyUp, keyEventCallback, NO); - theDocument.addEventListener(CPDOMEventKeyDown, keyEventCallback, NO); - theDocument.addEventListener(CPDOMEventKeyPress, keyEventCallback, NO); - - - theDocument.addEventListener(CPDOMEventTouchStart, touchEventCallback, NO); - theDocument.addEventListener(CPDOMEventTouchEnd, touchEventCallback, NO); - theDocument.addEventListener(CPDOMEventTouchMove, touchEventCallback, NO); - theDocument.addEventListener(CPDOMEventTouchCancel, touchEventCallback, NO); - - //FIXME: does firefox really need a different value? - _DOMWindow.addEventListener("DOMMouseScroll", scrollEventCallback, NO); - _DOMWindow.addEventListener(CPDOMEventScrollWheel, scrollEventCallback, NO); - } - else if(document.attachEvent) - { - _DOMWindow.attachEvent("onresize", resizeEventCallback); - - theDocument.attachEvent("on" + CPDOMEventMouseUp, mouseEventCallback); - theDocument.attachEvent("on" + CPDOMEventMouseDown, mouseEventCallback); - theDocument.attachEvent("on" + CPDOMEventMouseMoved, mouseEventCallback); - theDocument.attachEvent("on" + CPDOMEventDoubleClick, mouseEventCallback); - - theDocument.attachEvent("on" + CPDOMEventKeyUp, keyEventCallback); - theDocument.attachEvent("on" + CPDOMEventKeyDown, keyEventCallback); - theDocument.attachEvent("on" + CPDOMEventKeyPress, keyEventCallback); - - _DOMWindow.onmousewheel = scrollEventCallback; - theDocument.onmousewheel = scrollEventCallback; - - theDocument.body.ondrag = function () { return NO; }; - theDocument.body.onselectstart = function () { return window.event.srcElement == _DOMPasteboardElement; }; - } - - ExcludedDOMElements["INPUT"] = YES; - ExcludedDOMElements["SELECT"] = YES; - ExcludedDOMElements["TEXTAREA"] = YES; - ExcludedDOMElements["OPTION"] = YES; } return self; @@ -211,13 +68,13 @@ var CPDOMWindowGetFrame, - (CPRect)frame { - return CGRectMakeCopy(_frame); + return [self contentRect]; } - (CGRect)visibleFrame { - var frame = [self frame]; - + var frame = [self contentBounds]; + frame.origin = CGPointMakeZero(); if ([CPMenu menuBarVisible]) @@ -233,828 +90,42 @@ var CPDOMWindowGetFrame, - (CPRect)contentBounds { - return CPRectCreateCopy(_contentBounds); + var contentBounds = [window.firstWindow contentRect]; + contentBounds.origin = CGPointMake(0,0); + + return contentBounds; } - (CPArray)orderedWindowsAtLevel:(int)aLevel { - var layer = [self layerAtLevel:aLevel create:NO]; - - if (!layer) - return []; - - return [layer orderedWindows]; + return [window.firstWindow orderedWindowsAtLevel:aLevel]; } - (CPDOMWindowLayer)layerAtLevel:(int)aLevel create:(BOOL)aFlag { - var layer = [_windowLayers objectForKey:aLevel]; - - // If the layer doesn't currently exist, and the create flag is true, - // create the layer. - if (!layer && aFlag) - { - layer = [[CPDOMWindowLayer alloc] initWithLevel:aLevel]; - - [_windowLayers setObject:layer forKey:aLevel]; - - // Find the nearest layer. This is similar to a binary search, - // only we know we won't find the value. - var low = 0, - high = _windowLevels.length - 1, - middle; - - while (low <= high) - { - middle = FLOOR((low + high) / 2); - - if (_windowLevels[middle] > aLevel) - high = middle - 1; - else - low = middle + 1; - } - - [_windowLevels insertObject:aLevel atIndex:_windowLevels[middle] > aLevel ? middle : middle + 1]; - layer._DOMElement.style.zIndex = aLevel; - _DOMBodyElement.appendChild(layer._DOMElement); - } - - return layer; + return [window.firstWindow layerAtLevel:aLevel create:aFlag]; } - (void)order:(CPWindowOrderingMode)aPlace window:(CPWindow)aWindow relativeTo:(CPWindow)otherWindow { - // Grab the appropriate level for the layer, and create it if - // necessary (if we are not simply removing the window). - var layer = [self layerAtLevel:[aWindow level] create:aPlace != CPWindowOut]; - - // Ignore otherWindow, simply remove this window from it's level. - // If layer is nil, this will be a no-op. - if (aPlace == CPWindowOut) - return [layer removeWindow:aWindow]; - - // Place the window at the appropriate index. - [layer insertWindow:aWindow atIndex:(otherWindow ? (aPlace == CPWindowAbove ? otherWindow._index + 1 : otherWindow._index) : CPNotFound)]; + return [window.firstWindow order:aPlace window:aWindow relativeTo:otherWindow]; } /* @ignore */ - (id)_dragHitTest:(CPPoint)aPoint pasteboard:(CPPasteboard)aPasteboard { - var levels = _windowLevels, - layers = _windowLayers, - levelCount = levels.length; - - while (levelCount--) - { - // Skip any windows above or at the dragging level. - if (levels[levelCount] >= CPDraggingWindowLevel) - continue; - - var windows = [layers objectForKey:levels[levelCount]]._windows, - windowCount = windows.length; - - while (windowCount--) - { - var theWindow = windows[windowCount]; - - if ([theWindow containsPoint:aPoint]) - return [theWindow _dragHitTest:aPoint pasteboard:aPasteboard]; - } - } - - return nil; + return [window.firstWindow _dragHitTest:aPoint pasteboard:aPasteboard]; } /* @ignore */ - (void)_propagateCurrentDOMEvent:(BOOL)aFlag { - StopDOMEventPropagation = !aFlag; + return [window.firstWindow _propagateCurrentDOMEvent:aFlag]; } - (CPWindow)hitTest:(CPPoint)location { - var levels = _windowLevels, - layers = _windowLayers, - levelCount = levels.length, - theWindow = nil; - - while (levelCount-- && !theWindow) - { - var windows = [layers objectForKey:levels[levelCount]]._windows, - windowCount = windows.length; - - while (windowCount-- && !theWindow) - { - var candidateWindow = windows[windowCount]; - - if (!candidateWindow._ignoresMouseEvents && [candidateWindow containsPoint:location]) - theWindow = candidateWindow; - } - } - - return theWindow; + return [window.firstWindow hitTest:location]; } @end - -var CPDOMWindowGetFrame = function(_DOMWindow) -{ - var frame = nil;//CGRectMakeZero(); - - // We will rarely be able to get all this information, but we do the best we can: - if (_DOMWindow.outerWidth) - frame = CGRectMake(0, 0, _DOMWindow.outerWidth, _DOMWindow.outerHeight); - - else /*if(self.outerWidth)*/ - frame = CGRectMake(0, 0, -1, -1); - - if (window.screenTop) - frame.origin = CGPointMake(_DOMWindow.screenLeft, _DOMWindow.screenTop, 0); - - else if (window.screenX) - frame.origin = CGPointMake(_DOMWindow.screenX, _DOMWindow.screenY, 0); - - // Safari, Mozilla, Firefox, and Opera - if (_DOMWindow.innerWidth) - frame.size = CGSizeMake(_DOMWindow.innerWidth, _DOMWindow.innerHeight); - - // Internet Explorer 6 in Strict Mode - else if (document.documentElement && document.documentElement.clientWidth) - frame.size = CGSizeMake(_DOMWindow.document.documentElement.clientWidth, _DOMWindow.document.documentElement.clientHeight); - - // Internet Explorer X - else - frame.size = CGSizeMake(_DOMWindow.document.body.clientWidth, _DOMWindow.document.body.clientHeight); - - return frame; -} - -//right now we hard code q, w, r and t as keys to propogate -//these aren't normal keycodes, they are with modifier key codes -//might be mac only, we should investigate futher later. -var KeyCodesToPrevent = {}, - CharacterKeysToPrevent = {}, - KeyCodesWithoutKeyPressEvents = { '8':1, '9':1, '16':1, '37':1, '38':1, '39':1, '40':1, '46':1, '33':1, '34':1 }; - -var CTRL_KEY_CODE = 17; - -@implementation CPDOMWindowBridge (Events) - -/*! - When using command (mac) or control (windows), keys are propagated to the browser by default. - To prevent a character key from propagating (to prevent its default action, and instead use it - in your own application), use these methods. These methods are additive -- the list builds until you clear it. - - @param characters a list of characters to stop propagating keypresses to the browser. -*/ -- (void)preventCharacterKeysFromPropagating:(CPArray)characters -{ - for(var i=characters.length; i>0; i--) - CharacterKeysToPrevent[""+characters[i-1].toLowerCase()] = YES; -} - -/*! - @param character a character to stop propagating keypresses to the browser. -*/ -- (void)preventCharacterKeyFromPropagating:(CPString)character -{ - CharacterKeysToPrevent[character.toLowerCase()] = YES; -} - -/*! - Clear the list of characters for which we are not sending keypresses to the browser. -*/ -- (void)clearCharacterKeysToPreventFromPropagating -{ - CharacterKeysToPrevent = {}; -} - -/*! - Prevent these keyCodes from sending their keypresses to the browser. - @param keyCodes an array of keycodes to prevent propagation. -*/ -- (void)preventKeyCodesFromPropagating:(CPArray)keyCodes -{ - for(var i=keyCodes.length; i>0; i--) - KeyCodesToPrevent[keyCodes[i-1]] = YES; -} - -/*! - Prevent this keyCode from sending its key events to the browser. - @param keyCode a keycode to prevent propagation. -*/ -- (void)preventKeyCodeFromPropagating:(CPString)keyCode -{ - KeyCodesToPrevent[keyCode] = YES; -} - -/*! - Clear the list of keyCodes for which we are not sending keypresses to the browser. -*/ -- (void)clearKeyCodesToPreventFromPropagating -{ - KeyCodesToPrevent = {}; -} - -/* @ignore */ -- (void)_bridgeMouseEvent:(DOMEvent)aDOMEvent -{ - var theType = _overriddenEventType || aDOMEvent.type; - - // IE's event order is down, up, up, dblclick, so we have create these events artificially. - if (theType === CPDOMEventDoubleClick) - { - _overriddenEventType = CPDOMEventMouseDown; - [self _bridgeMouseEvent:aDOMEvent]; - - _overriddenEventType = CPDOMEventMouseUp; - [self _bridgeMouseEvent:aDOMEvent]; - - _overriddenEventType = nil; - - return; - } - -#ifndef DEBUG - try - { -#endif - var event, - location = _CGPointMake(aDOMEvent.clientX, aDOMEvent.clientY), - timestamp = aDOMEvent.timeStamp ? aDOMEvent.timeStamp : new Date(), - sourceElement = (aDOMEvent.target || aDOMEvent.srcElement), - windowNumber = 0, - modifierFlags = (aDOMEvent.shiftKey ? CPShiftKeyMask : 0) | - (aDOMEvent.ctrlKey ? CPControlKeyMask : 0) | - (aDOMEvent.altKey ? CPAlternateKeyMask : 0) | - (aDOMEvent.metaKey ? CPCommandKeyMask : 0); - - StopDOMEventPropagation = YES; - - if (_mouseDownWindow) - windowNumber = [_mouseDownWindow windowNumber]; - else - { - var theWindow = [self hitTest:location]; - - if ((aDOMEvent.type === CPDOMEventMouseDown) && theWindow) - _mouseDownWindow = theWindow; - - windowNumber = [theWindow windowNumber]; - } - - if (windowNumber) - { - var windowFrame = CPApp._windows[windowNumber]._frame; - - location.x -= _CGRectGetMinX(windowFrame); - location.y -= _CGRectGetMinY(windowFrame); - } - - switch (theType) - { - case CPDOMEventMouseUp: if(_mouseIsDown) - { - event = _CPEventFromNativeMouseEvent(aDOMEvent, CPLeftMouseUp, location, modifierFlags, timestamp, windowNumber, nil, -1, CPDOMEventGetClickCount(_lastMouseUp, timestamp, location), 0); - - _mouseIsDown = NO; - _lastMouseUp = event; - _mouseDownWindow = nil; - } - - if(_DOMEventMode) - { - _DOMEventMode = NO; - return; - } - - break; - - case CPDOMEventMouseDown: if (ExcludedDOMElements[sourceElement.tagName] && sourceElement != _DOMFocusElement) - { - _DOMEventMode = YES; - _mouseIsDown = YES; - - //fake a down and up event so that event tracking mode will work correctly - [CPApp sendEvent:[CPEvent mouseEventWithType:CPLeftMouseDown location:location modifierFlags:modifierFlags - timestamp:timestamp windowNumber:windowNumber context:nil eventNumber:-1 - clickCount:CPDOMEventGetClickCount(_lastMouseDown, timestamp, location) pressure:0]]; - - [CPApp sendEvent:[CPEvent mouseEventWithType:CPLeftMouseUp location:location modifierFlags:modifierFlags - timestamp:timestamp windowNumber:windowNumber context:nil eventNumber:-1 - clickCount:CPDOMEventGetClickCount(_lastMouseDown, timestamp, location) pressure:0]]; - - return; - } - - event = _CPEventFromNativeMouseEvent(aDOMEvent, CPLeftMouseDown, location, modifierFlags, timestamp, windowNumber, nil, -1, CPDOMEventGetClickCount(_lastMouseDown, timestamp, location), 0); - - _mouseIsDown = YES; - _lastMouseDown = event; - - break; - - case CPDOMEventMouseMoved: if (_DOMEventMode) - return; - - event = _CPEventFromNativeMouseEvent(aDOMEvent, _mouseIsDown ? CPLeftMouseDragged : CPMouseMoved, location, modifierFlags, timestamp, windowNumber, nil, -1, 1, 0); - - break; - } - - if (event) - { - event._DOMEvent = aDOMEvent; - - [CPApp sendEvent:event]; - } - - if (StopDOMEventPropagation) - CPDOMEventStop(aDOMEvent); - - [[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode]; -#ifndef DEBUG - } - catch (anException) - { - objj_exception_report(anException, {path:@"CPDOMWindowBridge.j"}); - } -#endif -} - -/* @ignore */ -- (void)_bridgeKeyEvent:(DOMEvent)aDOMEvent -{ -#ifndef DEBUG - try - { -#endif - var event, - timestamp = aDOMEvent.timeStamp ? aDOMEvent.timeStamp : new Date(), - sourceElement = (aDOMEvent.target || aDOMEvent.srcElement), - windowNumber = [[CPApp keyWindow] windowNumber], - modifierFlags = (aDOMEvent.shiftKey ? CPShiftKeyMask : 0) | - (aDOMEvent.ctrlKey ? CPControlKeyMask : 0) | - (aDOMEvent.altKey ? CPAlternateKeyMask : 0) | - (aDOMEvent.metaKey ? CPCommandKeyMask : 0); - - if (ExcludedDOMElements[sourceElement.tagName] && sourceElement != _DOMFocusElement && sourceElement != _DOMPasteboardElement) - return; - - //We want to stop propagation if this is a command key AND this character or keycode has been added to our blacklist - StopDOMEventPropagation = !(modifierFlags & (CPControlKeyMask | CPCommandKeyMask)) || - CharacterKeysToPrevent[String.fromCharCode(aDOMEvent.keyCode || aDOMEvent.charCode).toLowerCase()] || - KeyCodesToPrevent[aDOMEvent.keyCode]; - - var isNativePasteEvent = NO, - isNativeCopyOrCutEvent = NO; - - switch (aDOMEvent.type) - { - case CPDOMEventKeyDown: // Grab and store the keycode now since it is correct and consistent at this point. - _keyCode = aDOMEvent.keyCode; - - var characters = String.fromCharCode(_keyCode).toLowerCase(); - - // If this could be a native PASTE event, then we need to further examine it before - // sending a CPEvent. Select our element to see if anything gets pasted in it. - if (characters == "v" && (modifierFlags & CPPlatformActionKeyMask)) - { - _DOMPasteboardElement.select(); - _DOMPasteboardElement.value = ""; - - isNativePasteEvent = YES; - } - - // Normally we return now because we let keypress send the actual CPEvent keyDown event, since we don't have - // a complete set of information yet. - - // However, of this could be a native COPY event, we need to let the normal event-process take place so it - // can capture our internal Cappuccino pasteboard. - else if ((characters == "c" || characters == "x") && (modifierFlags & CPPlatformActionKeyMask)) - isNativeCopyOrCutEvent = YES; - - // Also, certain browsers (IE and Safari), have broken keyboard supportwhere they don't send keypresses for certain events. - // So, allow the keypress event to handle the event if we are not a browser with broken (remedial) key support... - else if (!CPFeatureIsCompatible(CPJavascriptRemedialKeySupport)) - return; - - // Or, if this is not one of those special keycodes, and also not a ctrl+event - else if (!KeyCodesWithoutKeyPressEvents[_keyCode] && (_keyCode == CTRL_KEY_CODE || !(modifierFlags & CPControlKeyMask))) - return; - - // If this is in fact our broke state, continue to keypress and send the keydown. - case CPDOMEventKeyPress: - // If the source of this event is our pasteboard element, then simply let it continue - // as normal, so that the paste event can successfully complete. - if ((aDOMEvent.target || aDOMEvent.srcElement) == _DOMPasteboardElement) - return; - - var keyCode = _keyCode, - charCode = aDOMEvent.keyCode || aDOMEvent.charCode, - isARepeat = (_charCodes[keyCode] != nil); - - _charCodes[keyCode] = charCode; - - var characters = String.fromCharCode(charCode), - charactersIgnoringModifiers = characters.toLowerCase(); - - event = [CPEvent keyEventWithType:CPKeyDown location:location modifierFlags:modifierFlags - timestamp:timestamp windowNumber:windowNumber context:nil - characters:characters charactersIgnoringModifiers:charactersIgnoringModifiers isARepeat:isARepeat keyCode:keyCode]; - - if (isNativePasteEvent) - { - _pasteboardKeyDownEvent = event; - - window.setNativeTimeout(function () { [self _checkPasteboardElement] }, 0); - - return; - } - - break; - - case CPDOMEventKeyUp: var keyCode = aDOMEvent.keyCode, - charCode = _charCodes[keyCode]; - - _charCodes[keyCode] = nil; - - var characters = String.fromCharCode(charCode), - charactersIgnoringModifiers = characters.toLowerCase(); - - if (!(modifierFlags & CPShiftKeyMask)) - characters = charactersIgnoringModifiers; - - event = [CPEvent keyEventWithType:CPKeyUp location:location modifierFlags:modifierFlags - timestamp: timestamp windowNumber:windowNumber context:nil - characters:characters charactersIgnoringModifiers:charactersIgnoringModifiers isARepeat:NO keyCode:keyCode]; - break; - } - - if (event) - { - event._DOMEvent = aDOMEvent; - - [CPApp sendEvent:event]; - - if (isNativeCopyOrCutEvent) - { - var pasteboard = [CPPasteboard generalPasteboard], - types = [pasteboard types]; - - // If this is a native copy event, then check if the pasteboard has anything in it. - if (types.length) - { - if ([types indexOfObjectIdenticalTo:CPStringPboardType] != CPNotFound) - _DOMPasteboardElement.value = [pasteboard stringForType:CPStringPboardType]; - else - _DOMPasteboardElement.value = [pasteboard _generateStateUID]; - - _DOMPasteboardElement.select(); - - window.setNativeTimeout(function() { [self _clearPasteboardElement]; }, 0); - } - - return; - } - } - - if (StopDOMEventPropagation) - CPDOMEventStop(aDOMEvent); - - [[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode]; -#ifndef DEBUG - } - catch (anException) - { - objj_exception_report(anException, {path:@"CPDOMWindowBridge.j"}); - } -#endif -} - -/* @ignore */ -- (void)_bridgeScrollEvent:(DOMEvent)aDOMEvent -{ - if(!aDOMEvent) - aDOMEvent = window.event; - -#ifndef DEBUG - try - { -#endif - if (CPFeatureIsCompatible(CPJavaScriptMouseWheelValues_8_15)) - { - var x = 0.0, - y = 0.0, - element = aDOMEvent.target; - - while (element.nodeType !== 1) - element = element.parentNode; - - if (element.offsetParent) - { - do - { - x += element.offsetLeft; - y += element.offsetTop; - - } while (element = element.offsetParent); - } - - var location = _CGPointMake((x + ((aDOMEvent.clientX - 8) / 15)), (y + ((aDOMEvent.clientY - 8) / 15)));} - else - var location = _CGPointMake(aDOMEvent.clientX, aDOMEvent.clientY); - - var deltaX = 0.0, - deltaY = 0.0, - windowNumber = 0, - timestamp = aDOMEvent.timeStamp ? aDOMEvent.timeStamp : new Date(), - modifierFlags = (aDOMEvent.shiftKey ? CPShiftKeyMask : 0) | - (aDOMEvent.ctrlKey ? CPControlKeyMask : 0) | - (aDOMEvent.altKey ? CPAlternateKeyMask : 0) | - (aDOMEvent.metaKey ? CPCommandKeyMask : 0); - - StopDOMEventPropagation = YES; - - windowNumber = [[self hitTest:location] windowNumber]; - - if (!windowNumber) - return; - - var windowFrame = CPApp._windows[windowNumber]._frame; - - location.x -= CGRectGetMinX(windowFrame); - location.y -= CGRectGetMinY(windowFrame); - - if(typeof aDOMEvent.wheelDeltaX != "undefined") - { - deltaX = aDOMEvent.wheelDeltaX / 120.0; - deltaY = aDOMEvent.wheelDeltaY / 120.0; - } - - else if (aDOMEvent.wheelDelta) - deltaY = aDOMEvent.wheelDelta / 120.0; - - else if (aDOMEvent.detail) - deltaY = -aDOMEvent.detail / 3.0; - - else - return; - - if(!CPFeatureIsCompatible(CPJavaScriptNegativeMouseWheelValues)) - { - deltaX = -deltaX; - deltaY = -deltaY; - } - - var event = [CPEvent mouseEventWithType:CPScrollWheel location:location modifierFlags:modifierFlags - timestamp:timestamp windowNumber:windowNumber context:nil eventNumber:-1 clickCount:1 pressure:0 ]; - - event._DOMEvent = aDOMEvent; - event._deltaX = deltaX; - event._deltaY = deltaY; - - [CPApp sendEvent:event]; - - if (StopDOMEventPropagation) - CPDOMEventStop(aDOMEvent); - - [[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode]; -#ifndef DEBUG - } - catch (anException) - { - objj_exception_report(anException, {path:@"CPDOMWindowBridge.j"}); - } -#endif -} - -/* @ignore */ -- (void)_bridgeResizeEvent:(DOMEvent)aDOMEvent -{ -#ifndef DEBUG - try - { -#endif - // FIXME: This is not the right way to do this. - // We should pay attention to mouse down and mouse up in conjunction with this. - //window.liveResize = YES; - - var oldSize = _frame.size; - - // window.liveResize = YES? - _frame = CPDOMWindowGetFrame(_DOMWindow); - _contentBounds.size = CGSizeCreateCopy(_frame.size); - - var levels = _windowLevels, - layers = _windowLayers, - levelCount = levels.length; - - while (levelCount--) - { - var windows = [layers objectForKey:levels[levelCount]]._windows, - windowCount = windows.length; - - while (windowCount--) - [windows[windowCount] resizeWithOldBridgeSize:oldSize]; - } - - //window.liveResize = NO; - - [[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode]; -#ifndef DEBUG - } - catch (anException) - { - objj_exception_report(anException, {path:@"CPDOMWindowBridge.j"}); - } -#endif -} - -// DOM event properties used in mouse bridge code - -// type -// clientX -// clientY -// timestamp -// target/srcElement -// shiftKey,ctrlKey,altKey,metaKey - -/* @ignore */ -- (void)_bridgeTouchEvent:(DOMEvent)aDOMEvent -{ -#ifndef DEBUG - try - { -#endif - if (aDOMEvent.touches && (aDOMEvent.touches.length == 1 || (aDOMEvent.touches.length == 0 && aDOMEvent.changedTouches.length == 1))) - { - var newEvent = {}; - - switch(aDOMEvent.type) - { - case CPDOMEventTouchStart: newEvent.type = CPDOMEventMouseDown; - break; - case CPDOMEventTouchEnd: newEvent.type = CPDOMEventMouseUp; - break; - case CPDOMEventTouchMove: newEvent.type = CPDOMEventMouseMoved; - break; - case CPDOMEventTouchCancel: newEvent.type = CPDOMEventMouseUp; - break; - } - - var touch = aDOMEvent.touches.length ? aDOMEvent.touches[0] : aDOMEvent.changedTouches[0]; - - newEvent.clientX = touch.clientX; - newEvent.clientY = touch.clientY; - - newEvent.timestamp = aDOMEvent.timestamp; - newEvent.target = aDOMEvent.target; - - newEvent.shiftKey = newEvent.ctrlKey = newEvent.altKey = newEvent.metaKey = false; - - newEvent.preventDefault = function(){if(aDOMEvent.preventDefault) aDOMEvent.preventDefault()}; - newEvent.stopPropagation = function(){if(aDOMEvent.stopPropagation) aDOMEvent.stopPropagation()}; - - [self _bridgeMouseEvent:newEvent]; - - return; - } - else - { - if (aDOMEvent.preventDefault) - aDOMEvent.preventDefault(); - - if (aDOMEvent.stopPropagation) - aDOMEvent.stopPropagation(); - } -#ifndef DEBUG - } - catch (anException) - { - objj_exception_report(anException, {path:@"CPDOMWindowBridge.j"}); - } -#endif - // handle touch cases specifically -} - -/* @ignore */ -- (void)_checkPasteboardElement -{ -#ifndef DEBUG - try - { -#endif - var value = _DOMPasteboardElement.value; - - if ([value length]) - { - var pasteboard = [CPPasteboard generalPasteboard]; - - if ([pasteboard _stateUID] != value) - { - [pasteboard declareTypes:[CPStringPboardType] owner:self]; - - [pasteboard setString:value forType:CPStringPboardType]; - } - } - - [self _clearPasteboardElement]; - - [CPApp sendEvent:_pasteboardKeyDownEvent]; - - _pasteboardKeyDownEvent = nil; - - [[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode]; -#ifndef DEBUG - } - catch (anException) - { - objj_exception_report(anException, {path:@"CPDOMWindowBridge.j"}); - } -#endif -} - -/* @ignore */ -- (void)_clearPasteboardElement -{ - _DOMPasteboardElement.value = ""; - _DOMPasteboardElement.blur(); -} - -@end - -var CLICK_SPACE_DELTA = 5.0, - CLICK_TIME_DELTA = (typeof document != "undefined" && document.addEventListener) ? 350.0 : 1000.0; - -var CPDOMEventGetClickCount = function(aComparisonEvent, aTimestamp, aLocation) -{ - if (!aComparisonEvent) - return 1; - - var comparisonLocation = [aComparisonEvent locationInWindow]; - - return (aTimestamp - [aComparisonEvent timestamp] < CLICK_TIME_DELTA && - ABS(comparisonLocation.x - aLocation.x) < CLICK_SPACE_DELTA && - ABS(comparisonLocation.y - aLocation.y) < CLICK_SPACE_DELTA) ? [aComparisonEvent clickCount] + 1 : 1; -} - -var CPDOMEventStop = function(aDOMEvent) -{ - // IE Model - aDOMEvent.cancelBubble = true; - aDOMEvent.returnValue = false; - - // W3C Model - if (aDOMEvent.preventDefault) - aDOMEvent.preventDefault(); - - if (aDOMEvent.stopPropagation) - aDOMEvent.stopPropagation(); - - if (aDOMEvent.type === CPDOMEventMouseDown) - { - CPSharedDOMWindowBridge._DOMFocusElement.focus(); - CPSharedDOMWindowBridge._DOMFocusElement.blur(); - } -} - -function CPWindowObjectList() -{ - var bridge = [CPDOMWindowBridge sharedDOMWindowBridge], - levels = bridge._windowLevels, - layers = bridge._windowLayers, - levelCount = levels.length, - windowObjects = []; - - while (levelCount--) - { - var windows = [layers objectForKey:levels[levelCount]]._windows, - windowCount = windows.length; - - while (windowCount--) - windowObjects.push(windows[windowCount]); - } - - return windowObjects; -} - -function CPWindowList() -{ - var bridge = [CPDOMWindowBridge sharedDOMWindowBridge], - levels = bridge._windowLevels, - layers = bridge._windowLayers, - levelCount = levels.length, - windowNumbers = []; - - while (levelCount--) - { - var windows = [layers objectForKey:levels[levelCount]]._windows, - windowCount = windows.length; - - while (windowCount--) - windowNumbers.push([windows[windowCount] windowNumber]); - } - - return windowNumbers; -} diff --git a/AppKit/Platform/DOM/_CPBrowserWindow.j b/AppKit/Platform/DOM/_CPBrowserWindow.j new file mode 100644 index 000000000..57a97de1c --- /dev/null +++ b/AppKit/Platform/DOM/_CPBrowserWindow.j @@ -0,0 +1,10 @@ + +@import "_CPDOMWindow.j" + + +@implementation _CPBrowserWindow : _CPDOMWindow +{ +} +@end + +[CPPlatformWindow _setPlatformWindowClass:[_CPBrowserWindow class]]; diff --git a/AppKit/Platform/DOM/_CPDOMWindow.j b/AppKit/Platform/DOM/_CPDOMWindow.j new file mode 100644 index 000000000..d8a3b2c0b --- /dev/null +++ b/AppKit/Platform/DOM/_CPDOMWindow.j @@ -0,0 +1,1063 @@ +/* + * _CPDOMWindow.j + * AppKit + * + * Created by Francisco Tolmasky. + * Copyright 2008, 280 North, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +@import +@import + +@import "CPEvent.j" +@import "CPCompatibility.j" + +@import "CPDOMWindowLayer.j" + +@import "CPPlatformWindow.j" + +#import "../../CoreGraphics/CGGeometry.h" + + +var DoubleClick = "dblclick", + MouseDown = "mousedown", + MouseUp = "mouseup", + MouseMove = "mousemove", + MouseDrag = "mousedrag", + KeyUp = "keyup", + KeyDown = "keydown", + KeyPress = "keypress", + Copy = "copy", + Paste = "paste", + Resize = "resize", + ScrollWheel = "mousewheel", + TouchStart = "touchstart", + TouchMove = "touchmove", + TouchEnd = "touchend", + TouchCancel = "touchcancel"; + +var ExcludedDOMElements = []; + +ExcludedDOMElements["INPUT"] = YES; +ExcludedDOMElements["SELECT"] = YES; +ExcludedDOMElements["TEXTAREA"] = YES; +ExcludedDOMElements["OPTION"] = YES; + +// Define up here so compressor knows about em. +var CPDOMEventGetClickCount, + CPDOMEventStop; + +//right now we hard code q, w, r and t as keys to propogate +//these aren't normal keycodes, they are with modifier key codes +//might be mac only, we should investigate futher later. +var KeyCodesToPrevent = {}, + CharacterKeysToPrevent = {}, + KeyCodesWithoutKeyPressEvents = { '8':1, '9':1, '16':1, '37':1, '38':1, '39':1, '40':1, '46':1, '33':1, '34':1 }; + +var CTRL_KEY_CODE = 17; + +@implementation _CPDOMWindow : CPPlatformWindow +{ + DOMWindow _DOMWindow; + + DOMElement _DOMBodyElement; + DOMElement _DOMFocusElement; + + CPArray _windowLevels; + CPDictionary _windowLayers; + + BOOL _mouseIsDown; + CPWindow _mouseDownWindow; + CPTimeInterval _lastMouseUp; + CPTimeInterval _lastMouseDown; + + JSObject _charCodes; + unsigned _keyCode; + + BOOL _DOMEventMode; + + // Native Pasteboard Support + DOMElement _DOMPasteboardElement; + CPEvent _pasteboardKeyDownEvent; + + CPString _overriddenEventType; +} + +- (id)_init +{ + self = [super init]; + + if (self) + { + _DOMWindow = window; + + [self registerDOMWindow]; + [self updateFromNativeContentRect]; + + _charCodes = {}; + + _windowLevels = []; + _windowLayers = [CPDictionary dictionary]; + } + + return self; +} + +- (id)initWithContentRect:(CGRect)aRect +{ + self = [super initWithContentRect:aRect]; + + if (self) + { + _windowLevels = []; + _windowLayers = [CPDictionary dictionary]; + + _charCodes = {}; + } + + return self; +} + +- (CGRect)nativeContentRect +{ + if (!_DOMWindow) + return [self contentRect]; + + var contentRect = _CGRectMakeZero(); + + if (window.screenTop) + contentRect.origin = _CGPointMake(_DOMWindow.screenLeft, _DOMWindow.screenTop); + + else if (window.screenX) + contentRect.origin = _CGPointMake(_DOMWindow.screenX, _DOMWindow.screenY); + + // Safari, Mozilla, Firefox, and Opera + if (_DOMWindow.innerWidth) + contentRect.size = _CGSizeMake(_DOMWindow.innerWidth, _DOMWindow.innerHeight); + + // Internet Explorer 6 in Strict Mode + else if (document.documentElement && document.documentElement.clientWidth) + contentRect.size = _CGSizeMake(_DOMWindow.document.documentElement.clientWidth, _DOMWindow.document.documentElement.clientHeight); + + // Internet Explorer X + else + contentRect.size = _CGSizeMake(_DOMWindow.document.body.clientWidth, _DOMWindow.document.body.clientHeight); + + return contentRect; +} + +- (void)updateNativeContentOrigin +{ + if (!_DOMWindow) + return; + + var origin = [self contentRect].origin, + nativeOrigin = [self nativeContentRect].origin; + + _DOMWindow.moveBy(origin.x - nativeOrigin.x, origin.y - nativeOrigin.y); +} + +- (void)updateNativeContentSize +{ + if (!_DOMWindow) + return; + + var size = [self contentRect].size, + nativeSize = [self nativeContentRect].size; + + _DOMWindow.resizeBy(size.width - nativeSize.width, size.height - nativeSize.height); +} + +- (void)orderBack:(id)aSender +{ + if (_DOMWindow) + _DOMWindow.blur(); +} + +- (void)registerDOMWindow +{ + var theDocument = _DOMWindow.document; + + _DOMBodyElement = theDocument.getElementsByTagName("body")[0]; + + _DOMBodyElement.webkitTouchCallout = "none"; + + _DOMFocusElement = theDocument.createElement("input"); + + _DOMFocusElement.style.position = "absolute"; + _DOMFocusElement.style.zIndex = "-1000"; + _DOMFocusElement.style.opacity = "0"; + _DOMFocusElement.style.filter = "alpha(opacity=0)"; + + _DOMBodyElement.appendChild(_DOMFocusElement); + + // Create Native Pasteboard handler. + _DOMPasteboardElement = theDocument.createElement("input"); + + _DOMPasteboardElement.style.position = "absolute"; + _DOMPasteboardElement.style.top = "-10000px"; + _DOMPasteboardElement.style.zIndex = "99"; + + _DOMBodyElement.appendChild(_DOMPasteboardElement); + + // Make sure the pastboard element is blurred. + _DOMPasteboardElement.blur(); + + var theClass = [self class], + + resizeEventSelector = @selector(resizeEvent:), + resizeEventImplementation = class_getMethodImplementation(theClass, resizeEventSelector), + resizeEventCallback = function (anEvent) { resizeEventImplementation(self, nil, anEvent); }, + + keyEventSelector = @selector(keyEvent:), + keyEventImplementation = class_getMethodImplementation(theClass, keyEventSelector), + keyEventCallback = function (anEvent) { keyEventImplementation(self, nil, anEvent); }, + + mouseEventSelector = @selector(mouseEvent:), + mouseEventImplementation = class_getMethodImplementation(theClass, mouseEventSelector), + mouseEventCallback = function (anEvent) { mouseEventImplementation(self, nil, anEvent); }, + + scrollEventSelector = @selector(scrollEvent:), + scrollEventImplementation = class_getMethodImplementation(theClass, scrollEventSelector), + scrollEventCallback = function (anEvent) { scrollEventImplementation(self, nil, anEvent); }, + + touchEventSelector = @selector(touchEvent:), + touchEventImplementation = class_getMethodImplementation(theClass, touchEventSelector), + touchEventCallback = function (anEvent) { touchEventImplementation(self, nil, anEvent); }; + + if (theDocument.addEventListener) + { + theDocument.addEventListener("mouseup", mouseEventCallback, NO); + theDocument.addEventListener("mousedown", mouseEventCallback, NO); + theDocument.addEventListener("mousemove", mouseEventCallback, NO); + + theDocument.addEventListener("keyup", keyEventCallback, NO); + theDocument.addEventListener("keydown", keyEventCallback, NO); + theDocument.addEventListener("keypress", keyEventCallback, NO); + + theDocument.addEventListener("touchstart", touchEventCallback, NO); + theDocument.addEventListener("touchend", touchEventCallback, NO); + theDocument.addEventListener("touchmove", touchEventCallback, NO); + theDocument.addEventListener("touchcancel", touchEventCallback, NO); + + _DOMWindow.addEventListener("resize", resizeEventCallback, NO); + + _DOMWindow.addEventListener("beforeunload", function() + { + [self updateFromNativeContentRect]; + + theDocument.removeEventListener("mouseup", mouseEventCallback, NO); + theDocument.removeEventListener("mousedown", mouseEventCallback, NO); + theDocument.removeEventListener("mousemove", mouseEventCallback, NO); + + theDocument.removeEventListener("keyup", keyEventCallback, NO); + theDocument.removeEventListener("keydown", keyEventCallback, NO); + theDocument.removeEventListener("keypress", keyEventCallback, NO); + + theDocument.removeEventListener("touchstart", touchEventCallback, NO); + theDocument.removeEventListener("touchend", touchEventCallback, NO); + theDocument.removeEventListener("touchmove", touchEventCallback, NO); + + _DOMWindow.removeEventListener("resize", resizeEventCallback, NO); + + //FIXME: does firefox really need a different value? + _DOMWindow.removeEventListener("DOMMouseScroll", scrollEventCallback, NO); + _DOMWindow.removeEventListener("mousewheel", scrollEventCallback, NO); + + //_DOMWindow.removeEventListener("beforeunload", this, NO); + + self._DOMWindow = nil; + }, NO); + } + else + { + theDocument.attachEvent("onmouseup", mouseEventCallback); + theDocument.attachEvent("onmousedown", mouseEventCallback); + theDocument.attachEvent("onmousemove", mouseEventCallback); + theDocument.attachEvent("ondblclick", mouseEventCallback); + + theDocument.attachEvent("onkeyup", keyEventCallback); + theDocument.attachEvent("onkeydown", keyEventCallback); + theDocument.attachEvent("onkeypress", keyEventCallback); + + _DOMWindow.attachEvent("onresize", resizeEventCallback); + + _DOMWindow.onmousewheel = scrollEventCallback; + theDocument.onmousewheel = scrollEventCallback; + + theDocument.body.ondrag = function () { return NO; }; + theDocument.body.onselectstart = function () { return _DOMWindow.event.srcElement === _DOMPasteboardElement; }; + + _DOMWindow.attachEvent("onbeforeunload", function() + { + [self updateFromNativeContentRect]; + + theDocument.removeEvent("onmouseup", mouseEventCallback); + theDocument.removeEvent("onmousedown", mouseEventCallback); + theDocument.removeEvent("onmousemove", mouseEventCallback); + theDocument.removeEvent("ondblclick", mouseEventCallback); + + theDocument.removeEvent("onkeyup", keyEventCallback); + theDocument.removeEvent("onkeydown", keyEventCallback); + theDocument.removeEvent("onkeypress", keyEventCallback); + + _DOMWindow.removeEvent("onresize", resizeEventCallback); + + _DOMWindow.onmousewheel = NULL; + theDocument.onmousewheel = NULL; + + theDocument.body.ondrag = NULL; + theDocument.body.onselectstart = NULL; + + //_DOMWindow.removeEvent("beforeunload", this); + + self._DOMWindow = nil; + }, NO); + } +} + +- (void)orderFront:(id)aSender +{ + if (_DOMWindow) + return _DOMWindow.focus(); + + _DOMWindow = window.open("", "", "menubar=no,location=no,resizable=yes,scrollbars=no,status=no,left=" + _CGRectGetMinX(_contentRect) + ",top=" + _CGRectGetMinY(_contentRect) + ",width=" + _CGRectGetWidth(_contentRect) + ",height=" + _CGRectGetHeight(_contentRect)); + + [self registerDOMWindow]; +} + +- (void)orderOut:(id)aSender +{ + _DOMWindow.close(); +} + +- (void)keyEvent:(DOMEvent)aDOMEvent +{ + var event, + timestamp = aDOMEvent.timeStamp ? aDOMEvent.timeStamp : new Date(), + sourceElement = (aDOMEvent.target || aDOMEvent.srcElement), + windowNumber = [[CPApp keyWindow] windowNumber], + modifierFlags = (aDOMEvent.shiftKey ? CPShiftKeyMask : 0) | + (aDOMEvent.ctrlKey ? CPControlKeyMask : 0) | + (aDOMEvent.altKey ? CPAlternateKeyMask : 0) | + (aDOMEvent.metaKey ? CPCommandKeyMask : 0); + + if (ExcludedDOMElements[sourceElement.tagName] && sourceElement != _DOMFocusElement && sourceElement != _DOMPasteboardElement) + return; + + //We want to stop propagation if this is a command key AND this character or keycode has been added to our blacklist + StopDOMEventPropagation = !(modifierFlags & (CPControlKeyMask | CPCommandKeyMask)) || + CharacterKeysToPrevent[String.fromCharCode(aDOMEvent.keyCode || aDOMEvent.charCode).toLowerCase()] || + KeyCodesToPrevent[aDOMEvent.keyCode]; + + var isNativePasteEvent = NO, + isNativeCopyOrCutEvent = NO; + + switch (aDOMEvent.type) + { + case "keydown": // Grab and store the keycode now since it is correct and consistent at this point. + _keyCode = aDOMEvent.keyCode; + + var characters = String.fromCharCode(_keyCode).toLowerCase(); + + // If this could be a native PASTE event, then we need to further examine it before + // sending a CPEvent. Select our element to see if anything gets pasted in it. + if (characters == "v" && (modifierFlags & CPPlatformActionKeyMask)) + { + _DOMPasteboardElement.select(); + _DOMPasteboardElement.value = ""; + + isNativePasteEvent = YES; + } + + // Normally we return now because we let keypress send the actual CPEvent keyDown event, since we don't have + // a complete set of information yet. + + // However, of this could be a native COPY event, we need to let the normal event-process take place so it + // can capture our internal Cappuccino pasteboard. + else if ((characters == "c" || characters == "x") && (modifierFlags & CPPlatformActionKeyMask)) + isNativeCopyOrCutEvent = YES; + + // Also, certain browsers (IE and Safari), have broken keyboard supportwhere they don't send keypresses for certain events. + // So, allow the keypress event to handle the event if we are not a browser with broken (remedial) key support... + else if (!CPFeatureIsCompatible(CPJavascriptRemedialKeySupport)) + return; + + // Or, if this is not one of those special keycodes, and also not a ctrl+event + else if (!KeyCodesWithoutKeyPressEvents[_keyCode] && (_keyCode == CTRL_KEY_CODE || !(modifierFlags & CPControlKeyMask))) + return; + + // If this is in fact our broke state, continue to keypress and send the keydown. + case "keypress": // If the source of this event is our pasteboard element, then simply let it continue + // as normal, so that the paste event can successfully complete. + if ((aDOMEvent.target || aDOMEvent.srcElement) == _DOMPasteboardElement) + return; + + var keyCode = _keyCode, + charCode = aDOMEvent.keyCode || aDOMEvent.charCode, + isARepeat = (_charCodes[keyCode] != nil); + + _charCodes[keyCode] = charCode; + + var characters = String.fromCharCode(charCode), + charactersIgnoringModifiers = characters.toLowerCase(); + + event = [CPEvent keyEventWithType:CPKeyDown location:location modifierFlags:modifierFlags + timestamp:timestamp windowNumber:windowNumber context:nil + characters:characters charactersIgnoringModifiers:charactersIgnoringModifiers isARepeat:isARepeat keyCode:keyCode]; + + if (isNativePasteEvent) + { + _pasteboardKeyDownEvent = event; + + window.setNativeTimeout(function () { [self _checkPasteboardElement] }, 0); + + return; + } + + break; + + case "keyup": var keyCode = aDOMEvent.keyCode, + charCode = _charCodes[keyCode]; + + _charCodes[keyCode] = nil; + + var characters = String.fromCharCode(charCode), + charactersIgnoringModifiers = characters.toLowerCase(); + + if (!(modifierFlags & CPShiftKeyMask)) + characters = charactersIgnoringModifiers; + + event = [CPEvent keyEventWithType:CPKeyUp location:location modifierFlags:modifierFlags + timestamp: timestamp windowNumber:windowNumber context:nil + characters:characters charactersIgnoringModifiers:charactersIgnoringModifiers isARepeat:NO keyCode:keyCode]; + break; + } + + if (event) + { + event._DOMEvent = aDOMEvent; + + [CPApp sendEvent:event]; + + if (isNativeCopyOrCutEvent) + { + var pasteboard = [CPPasteboard generalPasteboard], + types = [pasteboard types]; + + // If this is a native copy event, then check if the pasteboard has anything in it. + if (types.length) + { + if ([types indexOfObjectIdenticalTo:CPStringPboardType] != CPNotFound) + _DOMPasteboardElement.value = [pasteboard stringForType:CPStringPboardType]; + else + _DOMPasteboardElement.value = [pasteboard _generateStateUID]; + + _DOMPasteboardElement.select(); + + window.setNativeTimeout(function() { [self _clearPasteboardElement]; }, 0); + } + + return; + } + } + + if (StopDOMEventPropagation) + CPDOMEventStop(aDOMEvent); + + [[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode]; + +} + +- (void)scrollEvent:(DOMEvent)aDOMEvent +{ + if(!aDOMEvent) + aDOMEvent = window.event; + + if (CPFeatureIsCompatible(CPJavaScriptMouseWheelValues_8_15)) + { + var x = 0.0, + y = 0.0, + element = aDOMEvent.target; + + while (element.nodeType !== 1) + element = element.parentNode; + + if (element.offsetParent) + { + do + { + x += element.offsetLeft; + y += element.offsetTop; + + } while (element = element.offsetParent); + } + + var location = _CGPointMake((x + ((aDOMEvent.clientX - 8) / 15)), (y + ((aDOMEvent.clientY - 8) / 15))); + } + else + var location = _CGPointMake(aDOMEvent.clientX, aDOMEvent.clientY); + + var deltaX = 0.0, + deltaY = 0.0, + windowNumber = 0, + timestamp = aDOMEvent.timeStamp ? aDOMEvent.timeStamp : new Date(), + modifierFlags = (aDOMEvent.shiftKey ? CPShiftKeyMask : 0) | + (aDOMEvent.ctrlKey ? CPControlKeyMask : 0) | + (aDOMEvent.altKey ? CPAlternateKeyMask : 0) | + (aDOMEvent.metaKey ? CPCommandKeyMask : 0); + + StopDOMEventPropagation = YES; + + windowNumber = [[self hitTest:location] windowNumber]; + + if (!windowNumber) + return; + + var windowFrame = CPApp._windows[windowNumber]._frame; + + location.x -= CGRectGetMinX(windowFrame); + location.y -= CGRectGetMinY(windowFrame); + + if(typeof aDOMEvent.wheelDeltaX != "undefined") + { + deltaX = aDOMEvent.wheelDeltaX / 120.0; + deltaY = aDOMEvent.wheelDeltaY / 120.0; + } + + else if (aDOMEvent.wheelDelta) + deltaY = aDOMEvent.wheelDelta / 120.0; + + else if (aDOMEvent.detail) + deltaY = -aDOMEvent.detail / 3.0; + + else + return; + + if(!CPFeatureIsCompatible(CPJavaScriptNegativeMouseWheelValues)) + { + deltaX = -deltaX; + deltaY = -deltaY; + } + + var event = [CPEvent mouseEventWithType:CPScrollWheel location:location modifierFlags:modifierFlags + timestamp:timestamp windowNumber:windowNumber context:nil eventNumber:-1 clickCount:1 pressure:0 ]; + + event._DOMEvent = aDOMEvent; + event._deltaX = deltaX; + event._deltaY = deltaY; + + [CPApp sendEvent:event]; + + if (StopDOMEventPropagation) + CPDOMEventStop(aDOMEvent); + + [[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode]; +} + +- (void)resizeEvent:(DOMEvent)aDOMEvent +{ + // FIXME: This is not the right way to do this. + // We should pay attention to mouse down and mouse up in conjunction with this. + //window.liveResize = YES; + + var oldSize = [self contentRect].size; + + [self updateFromNativeContentRect]; + + var levels = _windowLevels, + layers = _windowLayers, + levelCount = levels.length; + + while (levelCount--) + { + var windows = [layers objectForKey:levels[levelCount]]._windows, + windowCount = windows.length; + + while (windowCount--) + [windows[windowCount] resizeWithOldBridgeSize:oldSize]; + } + + //window.liveResize = NO; + + [[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode]; +} + +- (void)touchEvent:(DOMEvent)aDOMEvent +{ + if (aDOMEvent.touches && (aDOMEvent.touches.length == 1 || (aDOMEvent.touches.length == 0 && aDOMEvent.changedTouches.length == 1))) + { + var newEvent = {}; + + switch(aDOMEvent.type) + { + case CPDOMEventTouchStart: newEvent.type = CPDOMEventMouseDown; + break; + case CPDOMEventTouchEnd: newEvent.type = CPDOMEventMouseUp; + break; + case CPDOMEventTouchMove: newEvent.type = CPDOMEventMouseMoved; + break; + case CPDOMEventTouchCancel: newEvent.type = CPDOMEventMouseUp; + break; + } + + var touch = aDOMEvent.touches.length ? aDOMEvent.touches[0] : aDOMEvent.changedTouches[0]; + + newEvent.clientX = touch.clientX; + newEvent.clientY = touch.clientY; + + newEvent.timestamp = aDOMEvent.timestamp; + newEvent.target = aDOMEvent.target; + + newEvent.shiftKey = newEvent.ctrlKey = newEvent.altKey = newEvent.metaKey = false; + + newEvent.preventDefault = function(){if(aDOMEvent.preventDefault) aDOMEvent.preventDefault()}; + newEvent.stopPropagation = function(){if(aDOMEvent.stopPropagation) aDOMEvent.stopPropagation()}; + + [self _bridgeMouseEvent:newEvent]; + + return; + } + else + { + if (aDOMEvent.preventDefault) + aDOMEvent.preventDefault(); + + if (aDOMEvent.stopPropagation) + aDOMEvent.stopPropagation(); + } + // handle touch cases specifically +} + +- (void)mouseEvent:(DOMEvent)aDOMEvent +{ + var type = _overriddenEventType || aDOMEvent.type; + + // IE's event order is down, up, up, dblclick, so we have create these events artificially. + if (type === CPDOMEventDoubleClick) + { + _overriddenEventType = CPDOMEventMouseDown; + [self _bridgeMouseEvent:aDOMEvent]; + + _overriddenEventType = CPDOMEventMouseUp; + [self _bridgeMouseEvent:aDOMEvent]; + + _overriddenEventType = nil; + + return; + } + + var event, + location = _CGPointMake(aDOMEvent.clientX, aDOMEvent.clientY), + timestamp = aDOMEvent.timeStamp ? aDOMEvent.timeStamp : new Date(), + sourceElement = (aDOMEvent.target || aDOMEvent.srcElement), + windowNumber = 0, + modifierFlags = (aDOMEvent.shiftKey ? CPShiftKeyMask : 0) | + (aDOMEvent.ctrlKey ? CPControlKeyMask : 0) | + (aDOMEvent.altKey ? CPAlternateKeyMask : 0) | + (aDOMEvent.metaKey ? CPCommandKeyMask : 0); + + StopDOMEventPropagation = YES; + + if (_mouseDownWindow) + windowNumber = [_mouseDownWindow windowNumber]; + + else + { + var theWindow = [self hitTest:location]; + + if ((aDOMEvent.type === CPDOMEventMouseDown) && theWindow) + _mouseDownWindow = theWindow; + + windowNumber = [theWindow windowNumber]; + } + + if (windowNumber) + { + var windowFrame = CPApp._windows[windowNumber]._frame; + + location.x -= _CGRectGetMinX(windowFrame); + location.y -= _CGRectGetMinY(windowFrame); + } + + if (type === "mouseup") + { + if(_mouseIsDown) + { + event = _CPEventFromNativeMouseEvent(aDOMEvent, CPLeftMouseUp, location, modifierFlags, timestamp, windowNumber, nil, -1, CPDOMEventGetClickCount(_lastMouseUp, timestamp, location), 0); + + _mouseIsDown = NO; + _lastMouseUp = event; + _mouseDownWindow = nil; + } + + if(_DOMEventMode) + { + _DOMEventMode = NO; + return; + } + } + + else if (type === "mousedown") + { + if (ExcludedDOMElements[sourceElement.tagName] && sourceElement != _DOMFocusElement) + { + _DOMEventMode = YES; + _mouseIsDown = YES; + + //fake a down and up event so that event tracking mode will work correctly + [CPApp sendEvent:[CPEvent mouseEventWithType:CPLeftMouseDown location:location modifierFlags:modifierFlags + timestamp:timestamp windowNumber:windowNumber context:nil eventNumber:-1 + clickCount:CPDOMEventGetClickCount(_lastMouseDown, timestamp, location) pressure:0]]; + + [CPApp sendEvent:[CPEvent mouseEventWithType:CPLeftMouseUp location:location modifierFlags:modifierFlags + timestamp:timestamp windowNumber:windowNumber context:nil eventNumber:-1 + clickCount:CPDOMEventGetClickCount(_lastMouseDown, timestamp, location) pressure:0]]; + + return; + } + + event = _CPEventFromNativeMouseEvent(aDOMEvent, CPLeftMouseDown, location, modifierFlags, timestamp, windowNumber, nil, -1, CPDOMEventGetClickCount(_lastMouseDown, timestamp, location), 0); + + _mouseIsDown = YES; + _lastMouseDown = event; + } + + else // if (type === "mousemove") + { + if (_DOMEventMode) + return; + + event = _CPEventFromNativeMouseEvent(aDOMEvent, _mouseIsDown ? CPLeftMouseDragged : CPMouseMoved, location, modifierFlags, timestamp, windowNumber, nil, -1, 1, 0); + } + + if (event) + { + event._DOMEvent = aDOMEvent; + + [CPApp sendEvent:event]; + } + + if (StopDOMEventPropagation) + CPDOMEventStop(aDOMEvent); + + [[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode]; +} + + (CPArray)orderedWindowsAtLevel:(int)aLevel +{ + var layer = [self layerAtLevel:aLevel create:NO]; + + if (!layer) + return []; + + return [layer orderedWindows]; +} + +- (CPDOMWindowLayer)layerAtLevel:(int)aLevel create:(BOOL)aFlag +{ + var layer = [_windowLayers objectForKey:aLevel]; + + // If the layer doesn't currently exist, and the create flag is true, + // create the layer. + if (!layer && aFlag) + { + layer = [[CPDOMWindowLayer alloc] initWithLevel:aLevel]; + + [_windowLayers setObject:layer forKey:aLevel]; + + // Find the nearest layer. This is similar to a binary search, + // only we know we won't find the value. + var low = 0, + high = _windowLevels.length - 1, + middle; + + while (low <= high) + { + middle = FLOOR((low + high) / 2); + + if (_windowLevels[middle] > aLevel) + high = middle - 1; + else + low = middle + 1; + } + + [_windowLevels insertObject:aLevel atIndex:_windowLevels[middle] > aLevel ? middle : middle + 1]; + layer._DOMElement.style.zIndex = aLevel; + _DOMBodyElement.appendChild(layer._DOMElement); + } + + return layer; +} + +- (void)order:(CPWindowOrderingMode)aPlace window:(CPWindow)aWindow relativeTo:(CPWindow)otherWindow +{ + // Grab the appropriate level for the layer, and create it if + // necessary (if we are not simply removing the window). + var layer = [self layerAtLevel:[aWindow level] create:aPlace != CPWindowOut]; + + // Ignore otherWindow, simply remove this window from it's level. + // If layer is nil, this will be a no-op. + if (aPlace == CPWindowOut) + return [layer removeWindow:aWindow]; + + // Place the window at the appropriate index. + [layer insertWindow:aWindow atIndex:(otherWindow ? (aPlace == CPWindowAbove ? otherWindow._index + 1 : otherWindow._index) : CPNotFound)]; +} + +/* @ignore */ +- (id)_dragHitTest:(CPPoint)aPoint pasteboard:(CPPasteboard)aPasteboard +{ + var levels = _windowLevels, + layers = _windowLayers, + levelCount = levels.length; + + while (levelCount--) + { + // Skip any windows above or at the dragging level. + if (levels[levelCount] >= CPDraggingWindowLevel) + continue; + + var windows = [layers objectForKey:levels[levelCount]]._windows, + windowCount = windows.length; + + while (windowCount--) + { + var theWindow = windows[windowCount]; + + if ([theWindow containsPoint:aPoint]) + return [theWindow _dragHitTest:aPoint pasteboard:aPasteboard]; + } + } + + return nil; +} + +/* @ignore */ +- (void)_propagateCurrentDOMEvent:(BOOL)aFlag +{ + StopDOMEventPropagation = !aFlag; +} + +- (CPWindow)hitTest:(CPPoint)location +{ + var levels = _windowLevels, + layers = _windowLayers, + levelCount = levels.length, + theWindow = nil; + + while (levelCount-- && !theWindow) + { + var windows = [layers objectForKey:levels[levelCount]]._windows, + windowCount = windows.length; + + while (windowCount-- && !theWindow) + { + var candidateWindow = windows[windowCount]; + + if (!candidateWindow._ignoresMouseEvents && [candidateWindow containsPoint:location]) + theWindow = candidateWindow; + } + } + + return theWindow; +} + +- (void)_checkPasteboardElement +{ + var value = _DOMPasteboardElement.value; + + if ([value length]) + { + var pasteboard = [CPPasteboard generalPasteboard]; + + if ([pasteboard _stateUID] != value) + { + [pasteboard declareTypes:[CPStringPboardType] owner:self]; + + [pasteboard setString:value forType:CPStringPboardType]; + } + } + + [self _clearPasteboardElement]; + + [CPApp sendEvent:_pasteboardKeyDownEvent]; + + _pasteboardKeyDownEvent = nil; + + [[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode]; +} + +- (void)_clearPasteboardElement +{ + _DOMPasteboardElement.value = ""; + _DOMPasteboardElement.blur(); +} + +/*! + When using command (mac) or control (windows), keys are propagated to the browser by default. + To prevent a character key from propagating (to prevent its default action, and instead use it + in your own application), use these methods. These methods are additive -- the list builds until you clear it. + + @param characters a list of characters to stop propagating keypresses to the browser. +*/ +- (void)preventCharacterKeysFromPropagating:(CPArray)characters +{ + for(var i=characters.length; i>0; i--) + CharacterKeysToPrevent[""+characters[i-1].toLowerCase()] = YES; +} + +/*! + @param character a character to stop propagating keypresses to the browser. +*/ +- (void)preventCharacterKeyFromPropagating:(CPString)character +{ + CharacterKeysToPrevent[character.toLowerCase()] = YES; +} + +/*! + Clear the list of characters for which we are not sending keypresses to the browser. +*/ +- (void)clearCharacterKeysToPreventFromPropagating +{ + CharacterKeysToPrevent = {}; +} + +/*! + Prevent these keyCodes from sending their keypresses to the browser. + @param keyCodes an array of keycodes to prevent propagation. +*/ +- (void)preventKeyCodesFromPropagating:(CPArray)keyCodes +{ + for(var i=keyCodes.length; i>0; i--) + KeyCodesToPrevent[keyCodes[i-1]] = YES; +} + +/*! + Prevent this keyCode from sending its key events to the browser. + @param keyCode a keycode to prevent propagation. +*/ +- (void)preventKeyCodeFromPropagating:(CPString)keyCode +{ + KeyCodesToPrevent[keyCode] = YES; +} + +/*! + Clear the list of keyCodes for which we are not sending keypresses to the browser. +*/ +- (void)clearKeyCodesToPreventFromPropagating +{ + KeyCodesToPrevent = {}; +} + + +@end + +var CPEventClass = [CPEvent class]; + +var _CPEventFromNativeMouseEvent = function(aNativeEvent, anEventType, aPoint, modifierFlags, aTimestamp, aWindowNumber, aGraphicsContext, anEventNumber, aClickCount, aPressure) +{ + aNativeEvent.isa = CPEventClass; + + aNativeEvent._type = anEventType; + aNativeEvent._location = aPoint; + aNativeEvent._modifierFlags = modifierFlags; + aNativeEvent._timestamp = aTimestamp; + aNativeEvent._windowNumber = aWindowNumber; + aNativeEvent._window = nil; + aNativeEvent._context = aGraphicsContext; + aNativeEvent._eventNumber = anEventNumber; + aNativeEvent._clickCount = aClickCount; + aNativeEvent._pressure = aPressure; + + return aNativeEvent; +} + +var CLICK_SPACE_DELTA = 5.0, + CLICK_TIME_DELTA = (typeof document != "undefined" && document.addEventListener) ? 350.0 : 1000.0; + +var CPDOMEventGetClickCount = function(aComparisonEvent, aTimestamp, aLocation) +{ + if (!aComparisonEvent) + return 1; + + var comparisonLocation = [aComparisonEvent locationInWindow]; + + return (aTimestamp - [aComparisonEvent timestamp] < CLICK_TIME_DELTA && + ABS(comparisonLocation.x - aLocation.x) < CLICK_SPACE_DELTA && + ABS(comparisonLocation.y - aLocation.y) < CLICK_SPACE_DELTA) ? [aComparisonEvent clickCount] + 1 : 1; +} + +var CPDOMEventStop = function(aDOMEvent) +{ + // IE Model + aDOMEvent.cancelBubble = true; + aDOMEvent.returnValue = false; + + // W3C Model + if (aDOMEvent.preventDefault) + aDOMEvent.preventDefault(); + + if (aDOMEvent.stopPropagation) + aDOMEvent.stopPropagation(); + + if (aDOMEvent.type === CPDOMEventMouseDown) + { + CPSharedDOMWindowBridge._DOMFocusElement.focus(); + CPSharedDOMWindowBridge._DOMFocusElement.blur(); + } +} + +function CPWindowObjectList() +{ + var bridge = [CPDOMWindowBridge sharedDOMWindowBridge], + levels = bridge._windowLevels, + layers = bridge._windowLayers, + levelCount = levels.length, + windowObjects = []; + + while (levelCount--) + { + var windows = [layers objectForKey:levels[levelCount]]._windows, + windowCount = windows.length; + + while (windowCount--) + windowObjects.push(windows[windowCount]); + } + + return windowObjects; +} + +function CPWindowList() +{ + var bridge = [CPDOMWindowBridge sharedDOMWindowBridge], + levels = bridge._windowLevels, + layers = bridge._windowLayers, + levelCount = levels.length, + windowNumbers = []; + + while (levelCount--) + { + var windows = [layers objectForKey:levels[levelCount]]._windows, + windowCount = windows.length; + + while (windowCount--) + windowNumbers.push([windows[windowCount] windowNumber]); + } + + return windowNumbers; +} From e69d770583c3d0db987717fb110e9fad84f58bd7 Mon Sep 17 00:00:00 2001 From: Francisco Ryan Tolmasky I Date: Sat, 25 Jul 2009 17:10:48 -0700 Subject: [PATCH 11/53] Further deprecation of CPDOMWindowBridge. Reviewed by me. --- AppKit/CPWindow/CPWindow.j | 77 +++++-------------------- AppKit/Platform/CPPlatformWindow.j | 26 +++++++++ AppKit/Platform/DOM/CPDOMWindowBridge.j | 14 +---- AppKit/Platform/DOM/_CPDOMWindow.j | 12 ++-- 4 files changed, 49 insertions(+), 80 deletions(-) diff --git a/AppKit/CPWindow/CPWindow.j b/AppKit/CPWindow/CPWindow.j index b3499c575..3c0134cb5 100644 --- a/AppKit/CPWindow/CPWindow.j +++ b/AppKit/CPWindow/CPWindow.j @@ -236,6 +236,8 @@ var CPWindowSaveImage = nil, */ @implementation CPWindow : CPResponder { + CPPlatformWindow _platformWindow; + int _windowNumber; unsigned _styleMask; CGRect _frame; @@ -290,7 +292,7 @@ var CPWindowSaveImage = nil, #if PLATFORM(DOM) DOMElement _DOMElement; #endif - CPDOMWindowBridge _bridge; + unsigned _autoresizingMask; BOOL _delegateRespondsToWindowWillReturnUndoManagerSelector; @@ -329,37 +331,13 @@ CPTexturedBackgroundWindowMask @return the initialized window */ - (id)initWithContentRect:(CGRect)aContentRect styleMask:(unsigned int)aStyleMask -{ -#if PLATFORM(DOM) - return [self initWithContentRect:aContentRect styleMask:aStyleMask bridge:[CPDOMWindowBridge sharedDOMWindowBridge]]; -#else - return [self initWithContentRect:aContentRect styleMask:aStyleMask bridge:nil]; -#endif -} - -/*! - Initializes the window. The method also takes a style bit mask made up - of any of the following values: -
-CPBorderlessWindowMask
-CPTitledWindowMask
-CPClosableWindowMask
-CPMiniaturizableWindowMask
-CPResizableWindowMask
-CPTexturedBackgroundWindowMask
-
- @param aContentRect the size and location of the window in screen space - @param aStyleMask a style mask - @param aBridge a DOM-Window bridge object - @return the initialized window - @ignore -*/ -- (id)initWithContentRect:(CGRect)aContentRect styleMask:(unsigned int)aStyleMask bridge:(CPDOMWindowBridge)aBridge { self = [super init]; if (self) { + _platformWindow = window.firstWindow; + _isFullBridge = NO; _registeredDraggedTypes = [CPSet set]; _registeredDraggedTypesArray = []; @@ -403,8 +381,6 @@ CPTexturedBackgroundWindowMask CPDOMDisplayServerAppendChild(_DOMElement, _windowView._DOMElement); #endif - [self setBridge:aBridge]; - [self setNextResponder:CPApp]; [self setHasShadow:aStyleMask !== CPBorderlessWindowMask]; @@ -504,7 +480,7 @@ CPTexturedBackgroundWindowMask [self setLevel:CPBackgroundWindowLevel]; [self setHasShadow:NO]; [self setAutoresizingMask:CPWindowWidthSizable | CPWindowHeightSizable]; - [self setFrame:[_bridge visibleFrame]]; + [self setFrame:[_platformWindow usableContentFrame]]; } else { @@ -650,7 +626,7 @@ CPTexturedBackgroundWindowMask */ - (void)orderFront:(id)aSender { - [_bridge order:CPWindowAbove window:self relativeTo:nil]; + [_platformWindow order:CPWindowAbove window:self relativeTo:nil]; } /* @@ -660,7 +636,7 @@ CPTexturedBackgroundWindowMask */ - (void)orderBack:(id)aSender { - //[_bridge order:CPWindowBelow + //[_platformWindow order:CPWindowBelow } /*! @@ -672,7 +648,7 @@ CPTexturedBackgroundWindowMask if ([_delegate respondsToSelector:@selector(windowWillClose:)]) [_delegate windowWillClose:self]; - [_bridge order:CPWindowOut window:self relativeTo:nil]; + [_platformWindow order:CPWindowOut window:self relativeTo:nil]; if ([CPApp keyWindow] == self) { @@ -689,7 +665,7 @@ CPTexturedBackgroundWindowMask */ - (void)orderWindow:(CPWindowOrderingMode)aPlace relativeTo:(int)otherWindowNumber { - [_bridge order:aPlace window:self relativeTo:CPApp._windows[otherWindowNumber]]; + [_platformWindow order:aPlace window:self relativeTo:CPApp._windows[otherWindowNumber]]; } /*! @@ -1154,9 +1130,9 @@ CPTexturedBackgroundWindowMask - (void)center { var size = [self frame].size, - bridgeSize = [_bridge contentBounds].size; + containerSize = [_platformWindow contentBounds].size; - [self setFrameOrigin:CGPointMake((bridgeSize.width - size.width) / 2.0, (bridgeSize.height - size.height) / 2.0)]; + [self setFrameOrigin:CGPointMake((containerSize.width - size.width) / 2.0, (containerSize.height - size.height) / 2.0)]; } /*! @@ -1641,7 +1617,7 @@ CPTexturedBackgroundWindowMask [_windowView noteToolbarChanged]; if (_isFullBridge) - newFrame = [_bridge visibleFrame]; + newFrame = [_platformWindow usableContentFrame]; else { newFrame = CGRectMakeCopy([self frame]); @@ -1708,7 +1684,7 @@ CPTexturedBackgroundWindowMask [self _setAttachedSheetFrameOrigin]; // Place this window above ourselves. - [_bridge order:CPWindowAbove window:aSheet relativeTo:self]; + [_platformWindow order:CPWindowAbove window:aSheet relativeTo:self]; } /*! @@ -1929,39 +1905,18 @@ var keyViewComparator = function(a, b, context) @implementation CPWindow (BridgeSupport) -/* - Sets the DOM-Window bridge for this window. - @ignore -*/ -- (void)setBridge:(CPDOMWindowBridge)aBridge -{ - if (_bridge == aBridge) - return; - - if (_bridge) - { - [self orderOut:self]; - // FIXME: If the bridge changes, then we have to recreate all of our subviews' DOM Elements. - } - - _bridge = aBridge; - - if ([self isFullBridge]) - [self setFrame:[aBridge contentBounds]]; -} - /* @ignore */ - (void)resizeWithOldBridgeSize:(CGSize)aSize { if ([self isFullBridge]) - return [self setFrame:[_bridge visibleFrame]]; + return [self setFrame:[_platformWindow usableContentFrame]]; if (_autoresizingMask == CPWindowNotSizable) return; - var frame = [_bridge contentBounds], + var frame = [_platformWindow contentBounds], newFrame = CGRectMakeCopy(_frame), dX = (CGRectGetWidth(frame) - aSize.width) / (((_autoresizingMask & CPWindowMinXMargin) ? 1 : 0) + (_autoresizingMask & CPWindowWidthSizable ? 1 : 0) + (_autoresizingMask & CPWindowMaxXMargin ? 1 : 0)), diff --git a/AppKit/Platform/CPPlatformWindow.j b/AppKit/Platform/CPPlatformWindow.j index 04e35b808..74fecdb4d 100644 --- a/AppKit/Platform/CPPlatformWindow.j +++ b/AppKit/Platform/CPPlatformWindow.j @@ -50,6 +50,32 @@ var PlatformWindowClass = NULL; return _CGRectMakeCopy(_contentRect); } +- (CGRect)contentBounds +{ + var contentBounds = [self contentRect]; + + contentBounds.origin = _CGPointMakeZero(); + + return contentBounds; +} + +- (void)usableContentFrame +{ + var frame = [self contentBounds]; + + frame.origin = CGPointMakeZero(); + + if ([CPMenu menuBarVisible]) + { + var menuBarHeight = [[CPApp mainMenu] menuBarHeight]; + + frame.origin.y += menuBarHeight; + frame.size.height -= menuBarHeight; + } + + return frame; +} + - (void)setContentRect:(CGRect)aRect { if (!aRect || _CGRectEqualToRect(_contentRect, aRect)) diff --git a/AppKit/Platform/DOM/CPDOMWindowBridge.j b/AppKit/Platform/DOM/CPDOMWindowBridge.j index 78f6fe640..f6afe1168 100644 --- a/AppKit/Platform/DOM/CPDOMWindowBridge.j +++ b/AppKit/Platform/DOM/CPDOMWindowBridge.j @@ -73,19 +73,7 @@ var CPDOMWindowGetFrame, - (CGRect)visibleFrame { - var frame = [self contentBounds]; - - frame.origin = CGPointMakeZero(); - - if ([CPMenu menuBarVisible]) - { - var menuBarHeight = [[CPApp mainMenu] menuBarHeight]; - - frame.origin.y += menuBarHeight; - frame.size.height -= menuBarHeight; - } - - return frame; + return [window.firstWindow usableContentFrame]; } - (CPRect)contentBounds diff --git a/AppKit/Platform/DOM/_CPDOMWindow.j b/AppKit/Platform/DOM/_CPDOMWindow.j index d8a3b2c0b..38b18faa2 100644 --- a/AppKit/Platform/DOM/_CPDOMWindow.j +++ b/AppKit/Platform/DOM/_CPDOMWindow.j @@ -477,7 +477,7 @@ var CTRL_KEY_CODE = 17; } if (StopDOMEventPropagation) - CPDOMEventStop(aDOMEvent); + CPDOMEventStop(aDOMEvent, self); [[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode]; @@ -564,7 +564,7 @@ var CTRL_KEY_CODE = 17; [CPApp sendEvent:event]; if (StopDOMEventPropagation) - CPDOMEventStop(aDOMEvent); + CPDOMEventStop(aDOMEvent, self); [[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode]; } @@ -753,7 +753,7 @@ var CTRL_KEY_CODE = 17; } if (StopDOMEventPropagation) - CPDOMEventStop(aDOMEvent); + CPDOMEventStop(aDOMEvent, self); [[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode]; } @@ -1002,7 +1002,7 @@ var CPDOMEventGetClickCount = function(aComparisonEvent, aTimestamp, aLocation) ABS(comparisonLocation.y - aLocation.y) < CLICK_SPACE_DELTA) ? [aComparisonEvent clickCount] + 1 : 1; } -var CPDOMEventStop = function(aDOMEvent) +var CPDOMEventStop = function(aDOMEvent, aPlatformWindow) { // IE Model aDOMEvent.cancelBubble = true; @@ -1017,8 +1017,8 @@ var CPDOMEventStop = function(aDOMEvent) if (aDOMEvent.type === CPDOMEventMouseDown) { - CPSharedDOMWindowBridge._DOMFocusElement.focus(); - CPSharedDOMWindowBridge._DOMFocusElement.blur(); + aPlatformWindow._DOMFocusElement.focus(); + aPlatformWindow._DOMFocusElement.blur(); } } From ae7fbad2b977607082b65fa15c15a159049a36a0 Mon Sep 17 00:00:00 2001 From: Francisco Ryan Tolmasky I Date: Sun, 26 Jul 2009 01:34:16 -0700 Subject: [PATCH 12/53] Fix for dom layer. Reviewed by me. --- AppKit/Platform/DOM/CPDOMWindowLayer.j | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AppKit/Platform/DOM/CPDOMWindowLayer.j b/AppKit/Platform/DOM/CPDOMWindowLayer.j index bb5c5c882..3d6f3dede 100644 --- a/AppKit/Platform/DOM/CPDOMWindowLayer.j +++ b/AppKit/Platform/DOM/CPDOMWindowLayer.j @@ -115,7 +115,7 @@ aWindow._isVisible = YES; if ([aWindow isFullBridge]) - [aWindow setFrame:[aWindow._bridge visibleFrame]]; + [aWindow setFrame:[aWindow._platformWindow usableContentFrame]]; } } From d53207efd511b7994c08f669d5a97ccebf6942ce Mon Sep 17 00:00:00 2001 From: Francisco Ryan Tolmasky I Date: Sun, 26 Jul 2009 12:52:24 -0700 Subject: [PATCH 13/53] Furhter platform window support. Reviewed by me. --- AppKit/CPWindow/CPWindow.j | 3 +++ AppKit/Platform/CPPlatformWindow.j | 8 ++++++++ 2 files changed, 11 insertions(+) diff --git a/AppKit/CPWindow/CPWindow.j b/AppKit/CPWindow/CPWindow.j index 3c0134cb5..b83b7446e 100644 --- a/AppKit/CPWindow/CPWindow.j +++ b/AppKit/CPWindow/CPWindow.j @@ -626,6 +626,9 @@ CPTexturedBackgroundWindowMask */ - (void)orderFront:(id)aSender { + if (![_platformWindow isVisible]) + [_platformWindow orderFront:self]; + [_platformWindow order:CPWindowAbove window:self relativeTo:nil]; } diff --git a/AppKit/Platform/CPPlatformWindow.j b/AppKit/Platform/CPPlatformWindow.j index 74fecdb4d..d9beb54e6 100644 --- a/AppKit/Platform/CPPlatformWindow.j +++ b/AppKit/Platform/CPPlatformWindow.j @@ -118,6 +118,14 @@ var PlatformWindowClass = NULL; [self setContentRect:[self nativeContentRect]]; } +- (BOOL)isVisible +{ +#if PLATFORM(DOM) + return _DOMWindow !== NULL; +#endif + return NO; +} + @end #if PLATFORM(BROWSER) From 4f4a488762705769be6a608ffb4830567dfa6795 Mon Sep 17 00:00:00 2001 From: Francisco Ryan Tolmasky I Date: Sun, 26 Jul 2009 15:28:41 -0700 Subject: [PATCH 14/53] Remove debugger command in CPPopUpButton that breaks Release builds. Reviewed by me. --- AppKit/CPPopUpButton.j | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AppKit/CPPopUpButton.j b/AppKit/CPPopUpButton.j index 47d7e2176..526a1cb4d 100644 --- a/AppKit/CPPopUpButton.j +++ b/AppKit/CPPopUpButton.j @@ -550,7 +550,7 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down"); - (void)synchronizeTitleAndSelectedItem { var item = nil; -debugger; + if ([self pullsDown]) { var items = [_menu itemArray]; From 5ce96b45bb8ca28f3424bf8ddfb06d8745e08af1 Mon Sep 17 00:00:00 2001 From: Ross Boucher Date: Sun, 26 Jul 2009 22:46:22 -0700 Subject: [PATCH 15/53] Slight performance improvement and memory improvement by moving the storage of KVO proxy objects. --- Foundation/CPKeyValueObserving.j | 32 ++++++++++++++------------------ 1 file changed, 14 insertions(+), 18 deletions(-) diff --git a/Foundation/CPKeyValueObserving.j b/Foundation/CPKeyValueObserving.j index 7a1d575ae..5c57449a2 100644 --- a/Foundation/CPKeyValueObserving.j +++ b/Foundation/CPKeyValueObserving.j @@ -58,7 +58,7 @@ if (!anObserver || !aPath) return; - [[KVOProxyMap objectForKey:[self UID]] _removeObserver:anObserver forKeyPath:aPath]; + [self[KVOProxyKey] _removeObserver:anObserver forKeyPath:aPath]; } + (BOOL)automaticallyNotifiesObserversForKey:(CPString)aKey @@ -98,12 +98,9 @@ CPKeyValueChangeInsertion = 2; CPKeyValueChangeRemoval = 3; CPKeyValueChangeReplacement = 4; -//convenience -var kvoNewAndOld = CPKeyValueObservingOptionNew|CPKeyValueObservingOptionOld; - -// Map of real objects to their KVO proxy -var KVOProxyMap = [CPDictionary dictionary], - DependentKeysMap = [CPDictionary dictionary]; +var kvoNewAndOld = CPKeyValueObservingOptionNew|CPKeyValueObservingOptionOld, + DependentKeysMap = [CPDictionary dictionary], + KVOProxyKey = "$KVOPROXY"; //rule of thumb: _ methods are called on the real proxy object, others are called on the "fake" proxy object (aka the real object) @@ -119,7 +116,7 @@ var KVOProxyMap = [CPDictionary dictionary], + (id)proxyForObject:(CPObject)anObject { - var proxy = [KVOProxyMap objectForKey:[anObject UID]]; + var proxy = anObject[KVOProxyKey]; if (proxy) return proxy; @@ -128,7 +125,7 @@ var KVOProxyMap = [CPDictionary dictionary], [proxy _replaceClass]; - [KVOProxyMap setObject:proxy forKey:[anObject UID]]; + anObject[KVOProxyKey] = proxy; return proxy; } @@ -205,9 +202,10 @@ var KVOProxyMap = [CPDictionary dictionary], } } - var affectingKeys = [[_nativeClass keyPathsForValuesAffectingValueForKey:aKey] allObjects]; + var affectingKeys = [[_nativeClass keyPathsForValuesAffectingValueForKey:aKey] allObjects], + affectingKeysCount = affectingKeys ? affectingKeys.length : 0; - if (![affectingKeys count]) + if (!affectingKeysCount) return; var dependentKeysForClass = [DependentKeysMap objectForKey:[_nativeClass UID]]; @@ -218,11 +216,9 @@ var KVOProxyMap = [CPDictionary dictionary], [DependentKeysMap setObject:dependentKeysForClass forKey:[_nativeClass UID]]; } - var count = [affectingKeys count]; - - while (count--) + while (affectingKeysCount--) { - var affectingKey = affectingKeys[count], + var affectingKey = affectingKeys[affectingKeysCount], affectedKeys = [dependentKeysForClass objectForKey:affectingKey]; if (!affectedKeys) @@ -288,7 +284,7 @@ var KVOProxyMap = [CPDictionary dictionary], if (![_observersForKey count]) { _targetObject.isa = _nativeClass; //restore the original class - [KVOProxyMap removeObjectForKey:[_targetObject UID]]; + delete _targetObject[KVOProxyKey]; } } @@ -360,7 +356,7 @@ var KVOProxyMap = [CPDictionary dictionary], } var observers = [[_observersForKey objectForKey:aKey] allValues], - count = [observers count]; + count = observers ? observers.length : 0; while (count--) { @@ -425,7 +421,7 @@ var KVOProxyMap = [CPDictionary dictionary], - (Class)class { - return [KVOProxyMap objectForKey:[self UID]]._nativeClass; + return self[KVOProxyKey]._nativeClass; } - (Class)superclass From 43706041658e36ef8338c0c0bf515bad1c7d0bba Mon Sep 17 00:00:00 2001 From: Ross Boucher Date: Sun, 26 Jul 2009 23:40:52 -0700 Subject: [PATCH 16/53] Remove several CPDictionaries in favor of Objects, about a 15% performance gain. --- Foundation/CPKeyValueObserving.j | 47 ++++++++++++++++++++------------ 1 file changed, 29 insertions(+), 18 deletions(-) diff --git a/Foundation/CPKeyValueObserving.j b/Foundation/CPKeyValueObserving.j index 5c57449a2..897702537 100644 --- a/Foundation/CPKeyValueObserving.j +++ b/Foundation/CPKeyValueObserving.j @@ -99,7 +99,7 @@ CPKeyValueChangeRemoval = 3; CPKeyValueChangeReplacement = 4; var kvoNewAndOld = CPKeyValueObservingOptionNew|CPKeyValueObservingOptionOld, - DependentKeysMap = [CPDictionary dictionary], + DependentKeysMap = {}, KVOProxyKey = "$KVOPROXY"; //rule of thumb: _ methods are called on the real proxy object, others are called on the "fake" proxy object (aka the real object) @@ -110,7 +110,8 @@ var kvoNewAndOld = CPKeyValueObservingOptionNew|CPKeyValueObservingOptionOld, id _targetObject; Class _nativeClass; CPDictionary _changesForKey; - CPDictionary _observersForKey; + Object _observersForKey; + int _observersForKeyLength; CPSet _replacedKeys; } @@ -136,9 +137,10 @@ var kvoNewAndOld = CPKeyValueObservingOptionNew|CPKeyValueObservingOptionOld, _targetObject = aTarget; _nativeClass = [aTarget class]; - _observersForKey = [CPDictionary dictionary]; - _changesForKey = [CPDictionary dictionary]; _replacedKeys = [CPSet set]; + _observersForKey = {}; + _changesForKey = {}; + _observersForKeyLength = 0; return self; } @@ -208,23 +210,23 @@ var kvoNewAndOld = CPKeyValueObservingOptionNew|CPKeyValueObservingOptionOld, if (!affectingKeysCount) return; - var dependentKeysForClass = [DependentKeysMap objectForKey:[_nativeClass UID]]; + var dependentKeysForClass = DependentKeysMap[[_nativeClass UID]]; if (!dependentKeysForClass) { - dependentKeysForClass = [CPDictionary new]; - [DependentKeysMap setObject:dependentKeysForClass forKey:[_nativeClass UID]]; + dependentKeysForClass = {}; + DependentKeysMap[[_nativeClass UID]] = dependentKeysForClass; } while (affectingKeysCount--) { var affectingKey = affectingKeys[affectingKeysCount], - affectedKeys = [dependentKeysForClass objectForKey:affectingKey]; + affectedKeys = dependentKeysForClass[affectingKey]; if (!affectedKeys) { affectedKeys = [CPSet new]; - [dependentKeysForClass setObject:affectedKeys forKey:affectingKey]; + dependentKeysForClass[affectingKey] = affectedKeys; } [affectedKeys addObject:aKey]; @@ -244,12 +246,13 @@ var kvoNewAndOld = CPKeyValueObservingOptionNew|CPKeyValueObservingOptionOld, else [self _replaceSetterForKey:aPath]; - var observers = [_observersForKey objectForKey:aPath]; + var observers = _observersForKey[aPath]; if (!observers) { observers = [CPDictionary dictionary]; - [_observersForKey setObject:observers forKey:aPath]; + _observersForKey[aPath] = observers; + _observersForKeyLength++; } [observers setObject:_CPKVOInfoMake(anObserver, options, aContext, forwarder) forKey:[anObserver UID]]; @@ -268,7 +271,7 @@ var kvoNewAndOld = CPKeyValueObservingOptionNew|CPKeyValueObservingOptionOld, - (void)_removeObserver:(id)anObserver forKeyPath:(CPString)aPath { - var observers = [_observersForKey objectForKey:aPath]; + var observers = _observersForKey[aPath]; if (aPath.indexOf('.') != CPNotFound) { @@ -279,9 +282,12 @@ var kvoNewAndOld = CPKeyValueObservingOptionNew|CPKeyValueObservingOptionOld, [observers removeObjectForKey:[anObserver UID]]; if (![observers count]) - [_observersForKey removeObjectForKey:aPath]; + { + _observersForKeyLength--; + delete _observersForKey[aPath]; + } - if (![_observersForKey count]) + if (!_observersForKeyLength) { _targetObject.isa = _nativeClass; //restore the original class delete _targetObject[KVOProxyKey]; @@ -292,7 +298,7 @@ var kvoNewAndOld = CPKeyValueObservingOptionNew|CPKeyValueObservingOptionOld, - (void)_sendNotificationsForKey:(CPString)aKey changeOptions:(CPDictionary)changeOptions isBefore:(BOOL)isBefore { - var changes = [_changesForKey objectForKey:aKey]; + var changes = _changesForKey[aKey]; if (isBefore) { @@ -324,7 +330,7 @@ var kvoNewAndOld = CPKeyValueObservingOptionNew|CPKeyValueObservingOptionOld, [changes setObject:1 forKey:CPKeyValueChangeNotificationIsPriorKey]; - [_changesForKey setObject:changes forKey:aKey]; + _changesForKey[aKey] = changes; } else { @@ -355,7 +361,7 @@ var kvoNewAndOld = CPKeyValueObservingOptionNew|CPKeyValueObservingOptionOld, } } - var observers = [[_observersForKey objectForKey:aKey] allValues], + var observers = [_observersForKey[aKey] allValues], count = observers ? observers.length : 0; while (count--) @@ -368,7 +374,12 @@ var kvoNewAndOld = CPKeyValueObservingOptionNew|CPKeyValueObservingOptionOld, [observerInfo.observer observeValueForKeyPath:aKey ofObject:_targetObject change:changes context:observerInfo.context]; } - var keysComposedOfKey = [[[DependentKeysMap objectForKey:[_nativeClass UID]] objectForKey:aKey] allObjects]; + var dependentKeysMap = DependentKeysMap[[_nativeClass UID]]; + + if (!dependentKeysMap) + return; + + var keysComposedOfKey = [dependentKeysMap[aKey] allObjects]; if (!keysComposedOfKey) return; From 0ef4e9bca5901602b9edc7519c54b48eccea3049 Mon Sep 17 00:00:00 2001 From: Ross Boucher Date: Sun, 26 Jul 2009 23:56:18 -0700 Subject: [PATCH 17/53] store dependent keys on the class object itself, rather than in a global map. --- Foundation/CPKeyValueObserving.j | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Foundation/CPKeyValueObserving.j b/Foundation/CPKeyValueObserving.j index 897702537..a2c3fc2d5 100644 --- a/Foundation/CPKeyValueObserving.j +++ b/Foundation/CPKeyValueObserving.j @@ -99,7 +99,7 @@ CPKeyValueChangeRemoval = 3; CPKeyValueChangeReplacement = 4; var kvoNewAndOld = CPKeyValueObservingOptionNew|CPKeyValueObservingOptionOld, - DependentKeysMap = {}, + DependentKeysKey = "$KVODEPENDENT", KVOProxyKey = "$KVOPROXY"; //rule of thumb: _ methods are called on the real proxy object, others are called on the "fake" proxy object (aka the real object) @@ -210,12 +210,12 @@ var kvoNewAndOld = CPKeyValueObservingOptionNew|CPKeyValueObservingOptionOld, if (!affectingKeysCount) return; - var dependentKeysForClass = DependentKeysMap[[_nativeClass UID]]; + var dependentKeysForClass = _nativeClass[DependentKeysKey]; if (!dependentKeysForClass) { dependentKeysForClass = {}; - DependentKeysMap[[_nativeClass UID]] = dependentKeysForClass; + _nativeClass[DependentKeysKey] = dependentKeysForClass; } while (affectingKeysCount--) @@ -374,7 +374,7 @@ var kvoNewAndOld = CPKeyValueObservingOptionNew|CPKeyValueObservingOptionOld, [observerInfo.observer observeValueForKeyPath:aKey ofObject:_targetObject change:changes context:observerInfo.context]; } - var dependentKeysMap = DependentKeysMap[[_nativeClass UID]]; + var dependentKeysMap = _nativeClass[DependentKeysKey]; if (!dependentKeysMap) return; From 756885fd534ad66720678bd37c6b0bb2a452449f Mon Sep 17 00:00:00 2001 From: Francisco Ryan Tolmasky I Date: Sun, 26 Jul 2009 15:28:41 -0700 Subject: [PATCH 18/53] Remove debugger command in CPPopUpButton that breaks Release builds. Reviewed by me. --- AppKit/CPPopUpButton.j | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AppKit/CPPopUpButton.j b/AppKit/CPPopUpButton.j index 47d7e2176..526a1cb4d 100644 --- a/AppKit/CPPopUpButton.j +++ b/AppKit/CPPopUpButton.j @@ -550,7 +550,7 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down"); - (void)synchronizeTitleAndSelectedItem { var item = nil; -debugger; + if ([self pullsDown]) { var items = [_menu itemArray]; From d2b1df88e8a28ea1fc53109609d7427fa96898c7 Mon Sep 17 00:00:00 2001 From: Francisco Ryan Tolmasky I Date: Sun, 26 Jul 2009 15:50:37 -0700 Subject: [PATCH 19/53] FIx for drag and drop without CPDOMWindowBridge. Reviewed by me. --- AppKit/CPDragServer.j | 11 +++++++++-- AppKit/CPWindow/CPWindow.j | 15 ++++++++++++--- AppKit/Platform/DOM/_CPDOMWindow.j | 3 +++ 3 files changed, 24 insertions(+), 5 deletions(-) diff --git a/AppKit/CPDragServer.j b/AppKit/CPDragServer.j index f39524a61..39c4900fb 100644 --- a/AppKit/CPDragServer.j +++ b/AppKit/CPDragServer.j @@ -26,6 +26,7 @@ @import #import "CoreGraphics/CGGeometry.h" +#import "Platform/Platform.h" #define DRAGGING_WINDOW(anObject) ([anObject isKindOfClass:[CPWindow class]] ? anObject : [anObject window]) @@ -241,14 +242,20 @@ var CPDragServerUpdateDragging = function(anEvent) - (void)dragView:(CPView)aView fromWindow:(CPWindow)aWindow at:(CGPoint)viewLocation offset:(CGSize)mouseOffset event:(CPEvent)anEvent pasteboard:(CPPasteboard)aPasteboard source:(id)aSourceObject slideBack:(BOOL)slideBack { var eventLocation = [anEvent locationInWindow]; - + CPDragServerView = aView; CPDragServerSource = aSourceObject; CPDragServerWindow = aWindow; CPDragServerOffset = CPPointMake(eventLocation.x - viewLocation.x, eventLocation.y - viewLocation.y); CPDragServerPasteboard = [CPPasteboard pasteboardWithName:CPDragPboard];//aPasteboard; - [_dragWindow setFrameSize:CGSizeMakeCopy([[CPDOMWindowBridge sharedDOMWindowBridge] frame].size)]; +#if PLATFORM(BROWSER) + var platformWindow = [aWindow platformWindow]; + + [_dragWindow setPlatformWindow:platformWindow]; + [_dragWindow setFrameSize:[platformWindow contentBounds]]; +#endif + [_dragWindow orderFront:self]; [aView setFrameOrigin:viewLocation]; diff --git a/AppKit/CPWindow/CPWindow.j b/AppKit/CPWindow/CPWindow.j index b83b7446e..dcc7fc2c9 100644 --- a/AppKit/CPWindow/CPWindow.j +++ b/AppKit/CPWindow/CPWindow.j @@ -395,6 +395,17 @@ CPTexturedBackgroundWindowMask return self; } +- (CPPlatformWindow)platformWindow +{ + return _platformWindow; +} + +- (void)setPlatformWindow:(CPPlatformWindow)aPlatformWindow +{ + // FIXME: already visible. + _platformWindow = aPlatformWindow; +} + /*! @ignore */ @@ -626,9 +637,7 @@ CPTexturedBackgroundWindowMask */ - (void)orderFront:(id)aSender { - if (![_platformWindow isVisible]) - [_platformWindow orderFront:self]; - + [_platformWindow orderFront:self]; [_platformWindow order:CPWindowAbove window:self relativeTo:nil]; } diff --git a/AppKit/Platform/DOM/_CPDOMWindow.j b/AppKit/Platform/DOM/_CPDOMWindow.j index 38b18faa2..1605ef941 100644 --- a/AppKit/Platform/DOM/_CPDOMWindow.j +++ b/AppKit/Platform/DOM/_CPDOMWindow.j @@ -254,6 +254,9 @@ var CTRL_KEY_CODE = 17; theDocument.addEventListener("touchmove", touchEventCallback, NO); theDocument.addEventListener("touchcancel", touchEventCallback, NO); + _DOMWindow.addEventListener("DOMMouseScroll", scrollEventCallback, NO); + _DOMWindow.addEventListener("mousewheel", scrollEventCallback, NO); + _DOMWindow.addEventListener("resize", resizeEventCallback, NO); _DOMWindow.addEventListener("beforeunload", function() From 4d179b1db70661cf589727016901c444b0a617b5 Mon Sep 17 00:00:00 2001 From: Francisco Ryan Tolmasky I Date: Sun, 26 Jul 2009 16:19:09 -0700 Subject: [PATCH 20/53] Remove global references to first window. Reviewed by me. --- AppKit/CPWindow/CPWindow.j | 2 +- AppKit/Platform/CPPlatform.j | 2 +- AppKit/Platform/CPPlatformWindow.j | 22 +++++++++++++++++++++- AppKit/Platform/DOM/CPDOMWindowBridge.j | 16 ++++++++-------- 4 files changed, 31 insertions(+), 11 deletions(-) diff --git a/AppKit/CPWindow/CPWindow.j b/AppKit/CPWindow/CPWindow.j index dcc7fc2c9..417f2fc9e 100644 --- a/AppKit/CPWindow/CPWindow.j +++ b/AppKit/CPWindow/CPWindow.j @@ -336,7 +336,7 @@ CPTexturedBackgroundWindowMask if (self) { - _platformWindow = window.firstWindow; + [self setPlatformWindow:[CPPlatformWindow primaryPlatformWindow]]; _isFullBridge = NO; _registeredDraggedTypes = [CPSet set]; diff --git a/AppKit/Platform/CPPlatform.j b/AppKit/Platform/CPPlatform.j index e7db6ddb1..8a75b53ab 100644 --- a/AppKit/Platform/CPPlatform.j +++ b/AppKit/Platform/CPPlatform.j @@ -21,7 +21,7 @@ #endif [CPPlatformString bootstrap]; - window.firstWindow = [[CPPlatformWindow alloc] _init]; + [CPPlatformWindow setPrimaryPlatformWindow:[[CPPlatformWindow alloc] _init]]; } @end diff --git a/AppKit/Platform/CPPlatformWindow.j b/AppKit/Platform/CPPlatformWindow.j index d9beb54e6..e0abdf130 100644 --- a/AppKit/Platform/CPPlatformWindow.j +++ b/AppKit/Platform/CPPlatformWindow.j @@ -5,13 +5,33 @@ #import "../CoreGraphics/CGGeometry.h" -var PlatformWindowClass = NULL; +var PlatformWindowClass = NULL, + PrimaryPlatformWindow = NULL; @implementation CPPlatformWindow : CPObject { CGRect _contentRect; } ++ (CPPlatformWindow)primaryPlatformWindow +{ + return PrimaryPlatformWindow; +} + ++ (void)setPrimaryPlatformWindow:(CPPlatformWindow)aPlatformWindow +{ + PrimaryPlatformWindow = aPlatformWindow; +} +/* ++ (BOOL)supportsMultipleWindows +{ +#if PLATFORM(BROWSER) + return YES; +#else + return NO; +#endif +} +*/ + (void)_setPlatformWindowClass:(Class)aClass { PlatformWindowClass = aClass; diff --git a/AppKit/Platform/DOM/CPDOMWindowBridge.j b/AppKit/Platform/DOM/CPDOMWindowBridge.j index f6afe1168..ac3352666 100644 --- a/AppKit/Platform/DOM/CPDOMWindowBridge.j +++ b/AppKit/Platform/DOM/CPDOMWindowBridge.j @@ -73,12 +73,12 @@ var CPDOMWindowGetFrame, - (CGRect)visibleFrame { - return [window.firstWindow usableContentFrame]; + return [[CPPlatformWindow primaryPlatformWindow] usableContentFrame]; } - (CPRect)contentBounds { - var contentBounds = [window.firstWindow contentRect]; + var contentBounds = [[CPPlatformWindow primaryPlatformWindow] contentRect]; contentBounds.origin = CGPointMake(0,0); return contentBounds; @@ -86,34 +86,34 @@ var CPDOMWindowGetFrame, - (CPArray)orderedWindowsAtLevel:(int)aLevel { - return [window.firstWindow orderedWindowsAtLevel:aLevel]; + return [[CPPlatformWindow primaryPlatformWindow] orderedWindowsAtLevel:aLevel]; } - (CPDOMWindowLayer)layerAtLevel:(int)aLevel create:(BOOL)aFlag { - return [window.firstWindow layerAtLevel:aLevel create:aFlag]; + return [[CPPlatformWindow primaryPlatformWindow] layerAtLevel:aLevel create:aFlag]; } - (void)order:(CPWindowOrderingMode)aPlace window:(CPWindow)aWindow relativeTo:(CPWindow)otherWindow { - return [window.firstWindow order:aPlace window:aWindow relativeTo:otherWindow]; + return [[CPPlatformWindow primaryPlatformWindow] order:aPlace window:aWindow relativeTo:otherWindow]; } /* @ignore */ - (id)_dragHitTest:(CPPoint)aPoint pasteboard:(CPPasteboard)aPasteboard { - return [window.firstWindow _dragHitTest:aPoint pasteboard:aPasteboard]; + return [[CPPlatformWindow primaryPlatformWindow] _dragHitTest:aPoint pasteboard:aPasteboard]; } /* @ignore */ - (void)_propagateCurrentDOMEvent:(BOOL)aFlag { - return [window.firstWindow _propagateCurrentDOMEvent:aFlag]; + return [[CPPlatformWindow primaryPlatformWindow] _propagateCurrentDOMEvent:aFlag]; } - (CPWindow)hitTest:(CPPoint)location { - return [window.firstWindow hitTest:location]; + return [[CPPlatformWindow primaryPlatformWindow] hitTest:location]; } @end From fa5352ad40a8352e28c2f376133d801556ebe378 Mon Sep 17 00:00:00 2001 From: Francisco Ryan Tolmasky I Date: Sun, 26 Jul 2009 17:56:25 -0700 Subject: [PATCH 21/53] Fix for drag and drop with platform windows. Reviewed by me. --- AppKit/CPDragServer.j | 3 +- AppKit/CPFlashView.j | 8 +- AppKit/Platform/CPPlatformWindow.j | 85 +++++++++++-------- ...{_CPDOMWindow.j => CPPlatformWindow+DOM.j} | 61 +++---------- AppKit/Platform/DOM/_CPBrowserWindow.j | 10 --- 5 files changed, 68 insertions(+), 99 deletions(-) rename AppKit/Platform/DOM/{_CPDOMWindow.j => CPPlatformWindow+DOM.j} (96%) delete mode 100644 AppKit/Platform/DOM/_CPBrowserWindow.j diff --git a/AppKit/CPDragServer.j b/AppKit/CPDragServer.j index 39c4900fb..337c13a99 100644 --- a/AppKit/CPDragServer.j +++ b/AppKit/CPDragServer.j @@ -252,8 +252,9 @@ var CPDragServerUpdateDragging = function(anEvent) #if PLATFORM(BROWSER) var platformWindow = [aWindow platformWindow]; + // FIXME: We should just have the window be the size of the view and move the window around. [_dragWindow setPlatformWindow:platformWindow]; - [_dragWindow setFrameSize:[platformWindow contentBounds]]; + [_dragWindow setFrameSize:[platformWindow contentBounds].size]; #endif [_dragWindow orderFront:self]; diff --git a/AppKit/CPFlashView.j b/AppKit/CPFlashView.j index 874614b7a..5d3f983a4 100644 --- a/AppKit/CPFlashView.j +++ b/AppKit/CPFlashView.j @@ -20,10 +20,10 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -@import "CPDOMWindowBridge.j" @import "CPFlashMovie.j" @import "CPView.j" + /*! @ingroup appkit */ @@ -96,17 +96,17 @@ - (void)mouseDragged:(CPEvent)anEvent { - [[CPDOMWindowBridge sharedDOMWindowBridge] _propagateCurrentDOMEvent:YES]; + [[[self window] platformWindow] _propagateCurrentDOMEvent:YES]; } - (void)mouseDown:(CPEvent)anEvent { - [[CPDOMWindowBridge sharedDOMWindowBridge] _propagateCurrentDOMEvent:YES]; + [[[self window] platformWindow] _propagateCurrentDOMEvent:YES]; } - (void)mouseUp:(CPEvent)anEvent { - [[CPDOMWindowBridge sharedDOMWindowBridge] _propagateCurrentDOMEvent:YES]; + [[[self window] platformWindow] _propagateCurrentDOMEvent:YES]; } @end diff --git a/AppKit/Platform/CPPlatformWindow.j b/AppKit/Platform/CPPlatformWindow.j index e0abdf130..abc76e29b 100644 --- a/AppKit/Platform/CPPlatformWindow.j +++ b/AppKit/Platform/CPPlatformWindow.j @@ -5,12 +5,37 @@ #import "../CoreGraphics/CGGeometry.h" -var PlatformWindowClass = NULL, - PrimaryPlatformWindow = NULL; +var PrimaryPlatformWindow = NULL; @implementation CPPlatformWindow : CPObject { CGRect _contentRect; + +#if PLATFORM(DOM) + DOMWindow _DOMWindow; + + DOMElement _DOMBodyElement; + DOMElement _DOMFocusElement; + + CPArray _windowLevels; + CPDictionary _windowLayers; + + BOOL _mouseIsDown; + CPWindow _mouseDownWindow; + CPTimeInterval _lastMouseUp; + CPTimeInterval _lastMouseDown; + + Object _charCodes; + unsigned _keyCode; + + BOOL _DOMEventMode; + + // Native Pasteboard Support + DOMElement _DOMPasteboardElement; + CPEvent _pasteboardKeyDownEvent; + + CPString _overriddenEventType; +#endif } + (CPPlatformWindow)primaryPlatformWindow @@ -22,41 +47,23 @@ var PlatformWindowClass = NULL, { PrimaryPlatformWindow = aPlatformWindow; } -/* -+ (BOOL)supportsMultipleWindows -{ -#if PLATFORM(BROWSER) - return YES; -#else - return NO; -#endif -} -*/ -+ (void)_setPlatformWindowClass:(Class)aClass -{ - PlatformWindowClass = aClass; -} - -+ (Class)_platformWindowClass -{ - return PlatformWindowClass; -} - -+ (id)alloc -{ - if (self === [CPPlatformWindow class]) - return [PlatformWindowClass alloc]; - - return [super alloc]; -} - (id)initWithContentRect:(CGRect)aRect { self = [super init]; if (self) + { _contentRect = _CGRectMakeCopy(aRect); +#if PLATFORM(DOM) + _windowLevels = []; + _windowLayers = [CPDictionary dictionary]; + + _charCodes = {}; +#endif + } + return self; } @@ -137,19 +144,25 @@ var PlatformWindowClass = NULL, { [self setContentRect:[self nativeContentRect]]; } - +/* - (BOOL)isVisible { -#if PLATFORM(DOM) - return _DOMWindow !== NULL; -#endif return NO; } +/* ++ (BOOL)supportsMultipleWindows +{ +#if PLATFORM(BROWSER) + return YES; +#else + return NO; +#endif +} +*/ + @end #if PLATFORM(BROWSER) -@import "_CPBrowserWindow.j" -#else -[CPPlatformWindow _setPlatformWindowClass:[CPPlatformWindow class]]; +@import "CPPlatformWindow+DOM.j" #endif diff --git a/AppKit/Platform/DOM/_CPDOMWindow.j b/AppKit/Platform/DOM/CPPlatformWindow+DOM.j similarity index 96% rename from AppKit/Platform/DOM/_CPDOMWindow.j rename to AppKit/Platform/DOM/CPPlatformWindow+DOM.j index 1605ef941..cd948e004 100644 --- a/AppKit/Platform/DOM/_CPDOMWindow.j +++ b/AppKit/Platform/DOM/CPPlatformWindow+DOM.j @@ -70,32 +70,7 @@ var KeyCodesToPrevent = {}, var CTRL_KEY_CODE = 17; -@implementation _CPDOMWindow : CPPlatformWindow -{ - DOMWindow _DOMWindow; - - DOMElement _DOMBodyElement; - DOMElement _DOMFocusElement; - - CPArray _windowLevels; - CPDictionary _windowLayers; - - BOOL _mouseIsDown; - CPWindow _mouseDownWindow; - CPTimeInterval _lastMouseUp; - CPTimeInterval _lastMouseDown; - - JSObject _charCodes; - unsigned _keyCode; - - BOOL _DOMEventMode; - - // Native Pasteboard Support - DOMElement _DOMPasteboardElement; - CPEvent _pasteboardKeyDownEvent; - - CPString _overriddenEventType; -} +@implementation CPPlatformWindow (DOM) - (id)_init { @@ -104,6 +79,7 @@ var CTRL_KEY_CODE = 17; if (self) { _DOMWindow = window; + _contentRect = _CGRectMakeZero(); [self registerDOMWindow]; [self updateFromNativeContentRect]; @@ -117,21 +93,6 @@ var CTRL_KEY_CODE = 17; return self; } -- (id)initWithContentRect:(CGRect)aRect -{ - self = [super initWithContentRect:aRect]; - - if (self) - { - _windowLevels = []; - _windowLayers = [CPDictionary dictionary]; - - _charCodes = {}; - } - - return self; -} - - (CGRect)nativeContentRect { if (!_DOMWindow) @@ -333,6 +294,11 @@ var CTRL_KEY_CODE = 17; } } +- (BOOL)isVisible +{ + return _DOMWindow !== NULL; +} + - (void)orderFront:(id)aSender { if (_DOMWindow) @@ -918,7 +884,7 @@ var CTRL_KEY_CODE = 17; @param characters a list of characters to stop propagating keypresses to the browser. */ -- (void)preventCharacterKeysFromPropagating:(CPArray)characters ++ (void)preventCharacterKeysFromPropagating:(CPArray)characters { for(var i=characters.length; i>0; i--) CharacterKeysToPrevent[""+characters[i-1].toLowerCase()] = YES; @@ -927,7 +893,7 @@ var CTRL_KEY_CODE = 17; /*! @param character a character to stop propagating keypresses to the browser. */ -- (void)preventCharacterKeyFromPropagating:(CPString)character ++ (void)preventCharacterKeyFromPropagating:(CPString)character { CharacterKeysToPrevent[character.toLowerCase()] = YES; } @@ -935,7 +901,7 @@ var CTRL_KEY_CODE = 17; /*! Clear the list of characters for which we are not sending keypresses to the browser. */ -- (void)clearCharacterKeysToPreventFromPropagating ++ (void)clearCharacterKeysToPreventFromPropagating { CharacterKeysToPrevent = {}; } @@ -944,7 +910,7 @@ var CTRL_KEY_CODE = 17; Prevent these keyCodes from sending their keypresses to the browser. @param keyCodes an array of keycodes to prevent propagation. */ -- (void)preventKeyCodesFromPropagating:(CPArray)keyCodes ++ (void)preventKeyCodesFromPropagating:(CPArray)keyCodes { for(var i=keyCodes.length; i>0; i--) KeyCodesToPrevent[keyCodes[i-1]] = YES; @@ -954,7 +920,7 @@ var CTRL_KEY_CODE = 17; Prevent this keyCode from sending its key events to the browser. @param keyCode a keycode to prevent propagation. */ -- (void)preventKeyCodeFromPropagating:(CPString)keyCode ++ (void)preventKeyCodeFromPropagating:(CPString)keyCode { KeyCodesToPrevent[keyCode] = YES; } @@ -962,12 +928,11 @@ var CTRL_KEY_CODE = 17; /*! Clear the list of keyCodes for which we are not sending keypresses to the browser. */ -- (void)clearKeyCodesToPreventFromPropagating ++ (void)clearKeyCodesToPreventFromPropagating { KeyCodesToPrevent = {}; } - @end var CPEventClass = [CPEvent class]; diff --git a/AppKit/Platform/DOM/_CPBrowserWindow.j b/AppKit/Platform/DOM/_CPBrowserWindow.j deleted file mode 100644 index 57a97de1c..000000000 --- a/AppKit/Platform/DOM/_CPBrowserWindow.j +++ /dev/null @@ -1,10 +0,0 @@ - -@import "_CPDOMWindow.j" - - -@implementation _CPBrowserWindow : _CPDOMWindow -{ -} -@end - -[CPPlatformWindow _setPlatformWindowClass:[_CPBrowserWindow class]]; From a34e23fa1cf880677f514f18a1f734d4ccc6c0ab Mon Sep 17 00:00:00 2001 From: Francisco Ryan Tolmasky I Date: Sun, 26 Jul 2009 18:12:50 -0700 Subject: [PATCH 22/53] Removed CPDOMWindowBridge dependency in CPTextField. Reviewed by me. --- AppKit/CPTextField.j | 2 +- AppKit/Platform/CPPlatformWindow.j | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/AppKit/CPTextField.j b/AppKit/CPTextField.j index 24ee21442..c80b975b1 100644 --- a/AppKit/CPTextField.j +++ b/AppKit/CPTextField.j @@ -597,7 +597,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder"); //post CPControlTextDidBeginEditingNotification [self textDidBeginEditing:[CPNotification notificationWithName:CPControlTextDidBeginEditingNotification object:self userInfo:nil]]; - [[CPDOMWindowBridge sharedDOMWindowBridge] _propagateCurrentDOMEvent:YES]; + [[[self window] platformWindow] _propagateCurrentDOMEvent:YES]; CPTextFieldInputIsActive = YES; diff --git a/AppKit/Platform/CPPlatformWindow.j b/AppKit/Platform/CPPlatformWindow.j index abc76e29b..1aec29a90 100644 --- a/AppKit/Platform/CPPlatformWindow.j +++ b/AppKit/Platform/CPPlatformWindow.j @@ -16,24 +16,24 @@ var PrimaryPlatformWindow = NULL; DOMElement _DOMBodyElement; DOMElement _DOMFocusElement; - + CPArray _windowLevels; CPDictionary _windowLayers; - + BOOL _mouseIsDown; CPWindow _mouseDownWindow; CPTimeInterval _lastMouseUp; CPTimeInterval _lastMouseDown; - + Object _charCodes; unsigned _keyCode; - + BOOL _DOMEventMode; - + // Native Pasteboard Support DOMElement _DOMPasteboardElement; CPEvent _pasteboardKeyDownEvent; - + CPString _overriddenEventType; #endif } From 92594a7ef990e6bba55e2079e9d5536b512c4142 Mon Sep 17 00:00:00 2001 From: Francisco Ryan Tolmasky I Date: Sun, 26 Jul 2009 18:26:47 -0700 Subject: [PATCH 23/53] Removed references from CPWindow and CPPlatformWindow to CPDOMWindowBridge. Reviewed by me. --- AppKit/CPWindow/CPWindow.j | 1 - AppKit/Platform/DOM/CPPlatformWindow+DOM.j | 12 ++++++------ 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/AppKit/CPWindow/CPWindow.j b/AppKit/CPWindow/CPWindow.j index 417f2fc9e..86a9f5dff 100644 --- a/AppKit/CPWindow/CPWindow.j +++ b/AppKit/CPWindow/CPWindow.j @@ -2086,5 +2086,4 @@ function _CPWindowFullBridgeSessionMake(aWindowView, aContentRect, hasShadow, aL @import "_CPBorderlessWindowView.j" @import "_CPBorderlessBridgeWindowView.j" @import "CPDragServer.j" -@import "CPDOMWindowBridge.j" @import "CPView.j" diff --git a/AppKit/Platform/DOM/CPPlatformWindow+DOM.j b/AppKit/Platform/DOM/CPPlatformWindow+DOM.j index cd948e004..4630ae210 100644 --- a/AppKit/Platform/DOM/CPPlatformWindow+DOM.j +++ b/AppKit/Platform/DOM/CPPlatformWindow+DOM.j @@ -992,9 +992,9 @@ var CPDOMEventStop = function(aDOMEvent, aPlatformWindow) function CPWindowObjectList() { - var bridge = [CPDOMWindowBridge sharedDOMWindowBridge], - levels = bridge._windowLevels, - layers = bridge._windowLayers, + var platformWindow = [CPPlatformWindow primaryPlatformWindow], + levels = platformWindow._windowLevels, + layers = platformWindow._windowLayers, levelCount = levels.length, windowObjects = []; @@ -1012,9 +1012,9 @@ function CPWindowObjectList() function CPWindowList() { - var bridge = [CPDOMWindowBridge sharedDOMWindowBridge], - levels = bridge._windowLevels, - layers = bridge._windowLayers, + var platformWindow = [CPPlatformWindow primaryPlatformWindow], + levels = platformWindow._windowLevels, + layers = platformWindow._windowLayers, levelCount = levels.length, windowNumbers = []; From 2e37945b4f9680d30c4a3fbba094191a39c9e22a Mon Sep 17 00:00:00 2001 From: Francisco Ryan Tolmasky I Date: Sun, 26 Jul 2009 18:49:41 -0700 Subject: [PATCH 24/53] Removed remaining references to CPDOMWindowBridge. Reviewed by me. --- AppKit/CPDragServer.j | 4 ++-- AppKit/CPMenu.j | 10 +++++----- AppKit/CPView.j | 2 +- AppKit/CPWindow/_CPWindowView.j | 4 ++-- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/AppKit/CPDragServer.j b/AppKit/CPDragServer.j index 337c13a99..60a23f06e 100644 --- a/AppKit/CPDragServer.j +++ b/AppKit/CPDragServer.j @@ -112,7 +112,7 @@ var CPDragServerUpdateDragging = function(anEvent) bridgeLocation = [[anEvent window] convertBaseToBridge:location]; // We have to convert base to bridge since the drag event comes from the source window, not the drag window. - var draggingDestination = [[CPDOMWindowBridge sharedDOMWindowBridge] _dragHitTest:bridgeLocation pasteboard:CPDragServerPasteboard]; + var draggingDestination = [[CPPlatformWindow primaryPlatformWindow] _dragHitTest:bridgeLocation pasteboard:CPDragServerPasteboard]; CPDragServerLocation = [DRAGGING_WINDOW(draggingDestination) convertBridgeToBase:bridgeLocation]; @@ -326,7 +326,7 @@ var CPDragServerUpdateDragging = function(anEvent) return nil; // We don't need to do this because the only place this gets called -// -_dragHitTest: in CPDOMWindowBridge does this already. Perhaps to +// -_dragHitTest: in CPPlatformWindow does this already. Perhaps to // be safe? // if (![self containsPoint:aPoint]) // return nil; diff --git a/AppKit/CPMenu.j b/AppKit/CPMenu.j index 46e415468..8e7ab43e1 100644 --- a/AppKit/CPMenu.j +++ b/AppKit/CPMenu.j @@ -119,7 +119,7 @@ var _CPMenuBarVisible = NO, // FIXME: There must be a better way to do this. #if PLATFORM(DOM) - [window.platformWindow resizeEvent:nil]; + [[CPPlatformWindow primaryPlatformWindow] resizeEvent:nil]; #endif } @@ -1078,7 +1078,7 @@ var STICKY_TIME_INTERVAL = 500, { _unconstrainedFrame = CGRectMakeCopy([self frame]); - var screenBounds = CGRectInset([[CPDOMWindowBridge sharedDOMWindowBridge] contentBounds], 5.0, 5.0), + var screenBounds = CGRectInset([[self platformWindow] contentBounds], 5.0, 5.0), constrainedFrame = CGRectIntersection(_unconstrainedFrame, screenBounds), menuViewOrigin = [self convertBaseToBridge:CGPointMake(LEFT_MARGIN, TOP_MARGIN)]; @@ -1158,7 +1158,7 @@ var STICKY_TIME_INTERVAL = 500, if (type == CPPeriodic) { - var constrainedBounds = CGRectInset([[CPDOMWindowBridge sharedDOMWindowBridge] contentBounds], 5.0, 5.0); + var constrainedBounds = CGRectInset([[self platformWindow] contentBounds], 5.0, 5.0); if (_scrollingState == _CPMenuWindowScrollingStateUp) { @@ -1447,9 +1447,9 @@ var _CPMenuBarWindowBackgroundColor = nil, - (id)init { - var bridgeWidth = CGRectGetWidth([[CPDOMWindowBridge sharedDOMWindowBridge] contentBounds]); + var platformWindowWidth = CGRectGetWidth([[CPPlatformWindow primaryPlatformWindow] contentBounds]); - self = [super initWithContentRect:CGRectMake(0.0, 0.0, bridgeWidth, MENUBAR_HEIGHT) styleMask:CPBorderlessWindowMask]; + self = [super initWithContentRect:CGRectMake(0.0, 0.0, platformWindowWidth, MENUBAR_HEIGHT) styleMask:CPBorderlessWindowMask]; if (self) { diff --git a/AppKit/CPView.j b/AppKit/CPView.j index 0121e9f6b..289e69fe3 100644 --- a/AppKit/CPView.j +++ b/AppKit/CPView.j @@ -970,7 +970,7 @@ var DOMElementPrototype = nil, { _fullScreenModeState = _CPViewFullScreenModeStateMake(self); - var fullScreenWindow = [[CPWindow alloc] initWithContentRect:[[CPDOMWindowBridge sharedDOMWindowBridge] contentBounds] styleMask:CPBorderlessWindowMask]; + var fullScreenWindow = [[CPWindow alloc] initWithContentRect:[[CPPlatformWindow primaryPlatformWindow] contentBounds] styleMask:CPBorderlessWindowMask]; [fullScreenWindow setLevel:CPScreenSaverWindowLevel]; [fullScreenWindow setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable]; diff --git a/AppKit/CPWindow/_CPWindowView.j b/AppKit/CPWindow/_CPWindowView.j index 7bbfaf22b..fe2d1ca4d 100644 --- a/AppKit/CPWindow/_CPWindowView.j +++ b/AppKit/CPWindow/_CPWindowView.j @@ -145,7 +145,7 @@ var _CPWindowViewResizeIndicatorImage = nil; var visibleFrame = _cachedScreenFrame; if (!visibleFrame) - visibleFrame = [[CPDOMWindowBridge sharedDOMWindowBridge] visibleFrame]; + visibleFrame = [[CPPlatformWindow primaryPlatformWindow] usableContentFrame]; var restrictedPoint = CGPointMake(0, 0); @@ -167,7 +167,7 @@ var _CPWindowViewResizeIndicatorImage = nil; else if (type === CPLeftMouseDown) { _mouseDraggedPoint = [[self window] convertBaseToBridge:[anEvent locationInWindow]]; - _cachedScreenFrame = [[CPDOMWindowBridge sharedDOMWindowBridge] visibleFrame]; + _cachedScreenFrame = [[CPPlatformWindow primaryPlatformWindow] usableContentFrame]; } else if (type === CPLeftMouseDragged) { From 865a2b513f4220f1a983b4955c28d6271c745eac Mon Sep 17 00:00:00 2001 From: Ross Boucher Date: Sun, 26 Jul 2009 22:46:22 -0700 Subject: [PATCH 25/53] Slight performance improvement and memory improvement by moving the storage of KVO proxy objects. --- Foundation/CPKeyValueObserving.j | 32 ++++++++++++++------------------ 1 file changed, 14 insertions(+), 18 deletions(-) diff --git a/Foundation/CPKeyValueObserving.j b/Foundation/CPKeyValueObserving.j index 7a1d575ae..5c57449a2 100644 --- a/Foundation/CPKeyValueObserving.j +++ b/Foundation/CPKeyValueObserving.j @@ -58,7 +58,7 @@ if (!anObserver || !aPath) return; - [[KVOProxyMap objectForKey:[self UID]] _removeObserver:anObserver forKeyPath:aPath]; + [self[KVOProxyKey] _removeObserver:anObserver forKeyPath:aPath]; } + (BOOL)automaticallyNotifiesObserversForKey:(CPString)aKey @@ -98,12 +98,9 @@ CPKeyValueChangeInsertion = 2; CPKeyValueChangeRemoval = 3; CPKeyValueChangeReplacement = 4; -//convenience -var kvoNewAndOld = CPKeyValueObservingOptionNew|CPKeyValueObservingOptionOld; - -// Map of real objects to their KVO proxy -var KVOProxyMap = [CPDictionary dictionary], - DependentKeysMap = [CPDictionary dictionary]; +var kvoNewAndOld = CPKeyValueObservingOptionNew|CPKeyValueObservingOptionOld, + DependentKeysMap = [CPDictionary dictionary], + KVOProxyKey = "$KVOPROXY"; //rule of thumb: _ methods are called on the real proxy object, others are called on the "fake" proxy object (aka the real object) @@ -119,7 +116,7 @@ var KVOProxyMap = [CPDictionary dictionary], + (id)proxyForObject:(CPObject)anObject { - var proxy = [KVOProxyMap objectForKey:[anObject UID]]; + var proxy = anObject[KVOProxyKey]; if (proxy) return proxy; @@ -128,7 +125,7 @@ var KVOProxyMap = [CPDictionary dictionary], [proxy _replaceClass]; - [KVOProxyMap setObject:proxy forKey:[anObject UID]]; + anObject[KVOProxyKey] = proxy; return proxy; } @@ -205,9 +202,10 @@ var KVOProxyMap = [CPDictionary dictionary], } } - var affectingKeys = [[_nativeClass keyPathsForValuesAffectingValueForKey:aKey] allObjects]; + var affectingKeys = [[_nativeClass keyPathsForValuesAffectingValueForKey:aKey] allObjects], + affectingKeysCount = affectingKeys ? affectingKeys.length : 0; - if (![affectingKeys count]) + if (!affectingKeysCount) return; var dependentKeysForClass = [DependentKeysMap objectForKey:[_nativeClass UID]]; @@ -218,11 +216,9 @@ var KVOProxyMap = [CPDictionary dictionary], [DependentKeysMap setObject:dependentKeysForClass forKey:[_nativeClass UID]]; } - var count = [affectingKeys count]; - - while (count--) + while (affectingKeysCount--) { - var affectingKey = affectingKeys[count], + var affectingKey = affectingKeys[affectingKeysCount], affectedKeys = [dependentKeysForClass objectForKey:affectingKey]; if (!affectedKeys) @@ -288,7 +284,7 @@ var KVOProxyMap = [CPDictionary dictionary], if (![_observersForKey count]) { _targetObject.isa = _nativeClass; //restore the original class - [KVOProxyMap removeObjectForKey:[_targetObject UID]]; + delete _targetObject[KVOProxyKey]; } } @@ -360,7 +356,7 @@ var KVOProxyMap = [CPDictionary dictionary], } var observers = [[_observersForKey objectForKey:aKey] allValues], - count = [observers count]; + count = observers ? observers.length : 0; while (count--) { @@ -425,7 +421,7 @@ var KVOProxyMap = [CPDictionary dictionary], - (Class)class { - return [KVOProxyMap objectForKey:[self UID]]._nativeClass; + return self[KVOProxyKey]._nativeClass; } - (Class)superclass From 64b81cfcdb932b9768a9ddb5496a3e90d0af1624 Mon Sep 17 00:00:00 2001 From: Ross Boucher Date: Sun, 26 Jul 2009 23:40:52 -0700 Subject: [PATCH 26/53] Remove several CPDictionaries in favor of Objects, about a 15% performance gain. --- Foundation/CPKeyValueObserving.j | 47 ++++++++++++++++++++------------ 1 file changed, 29 insertions(+), 18 deletions(-) diff --git a/Foundation/CPKeyValueObserving.j b/Foundation/CPKeyValueObserving.j index 5c57449a2..897702537 100644 --- a/Foundation/CPKeyValueObserving.j +++ b/Foundation/CPKeyValueObserving.j @@ -99,7 +99,7 @@ CPKeyValueChangeRemoval = 3; CPKeyValueChangeReplacement = 4; var kvoNewAndOld = CPKeyValueObservingOptionNew|CPKeyValueObservingOptionOld, - DependentKeysMap = [CPDictionary dictionary], + DependentKeysMap = {}, KVOProxyKey = "$KVOPROXY"; //rule of thumb: _ methods are called on the real proxy object, others are called on the "fake" proxy object (aka the real object) @@ -110,7 +110,8 @@ var kvoNewAndOld = CPKeyValueObservingOptionNew|CPKeyValueObservingOptionOld, id _targetObject; Class _nativeClass; CPDictionary _changesForKey; - CPDictionary _observersForKey; + Object _observersForKey; + int _observersForKeyLength; CPSet _replacedKeys; } @@ -136,9 +137,10 @@ var kvoNewAndOld = CPKeyValueObservingOptionNew|CPKeyValueObservingOptionOld, _targetObject = aTarget; _nativeClass = [aTarget class]; - _observersForKey = [CPDictionary dictionary]; - _changesForKey = [CPDictionary dictionary]; _replacedKeys = [CPSet set]; + _observersForKey = {}; + _changesForKey = {}; + _observersForKeyLength = 0; return self; } @@ -208,23 +210,23 @@ var kvoNewAndOld = CPKeyValueObservingOptionNew|CPKeyValueObservingOptionOld, if (!affectingKeysCount) return; - var dependentKeysForClass = [DependentKeysMap objectForKey:[_nativeClass UID]]; + var dependentKeysForClass = DependentKeysMap[[_nativeClass UID]]; if (!dependentKeysForClass) { - dependentKeysForClass = [CPDictionary new]; - [DependentKeysMap setObject:dependentKeysForClass forKey:[_nativeClass UID]]; + dependentKeysForClass = {}; + DependentKeysMap[[_nativeClass UID]] = dependentKeysForClass; } while (affectingKeysCount--) { var affectingKey = affectingKeys[affectingKeysCount], - affectedKeys = [dependentKeysForClass objectForKey:affectingKey]; + affectedKeys = dependentKeysForClass[affectingKey]; if (!affectedKeys) { affectedKeys = [CPSet new]; - [dependentKeysForClass setObject:affectedKeys forKey:affectingKey]; + dependentKeysForClass[affectingKey] = affectedKeys; } [affectedKeys addObject:aKey]; @@ -244,12 +246,13 @@ var kvoNewAndOld = CPKeyValueObservingOptionNew|CPKeyValueObservingOptionOld, else [self _replaceSetterForKey:aPath]; - var observers = [_observersForKey objectForKey:aPath]; + var observers = _observersForKey[aPath]; if (!observers) { observers = [CPDictionary dictionary]; - [_observersForKey setObject:observers forKey:aPath]; + _observersForKey[aPath] = observers; + _observersForKeyLength++; } [observers setObject:_CPKVOInfoMake(anObserver, options, aContext, forwarder) forKey:[anObserver UID]]; @@ -268,7 +271,7 @@ var kvoNewAndOld = CPKeyValueObservingOptionNew|CPKeyValueObservingOptionOld, - (void)_removeObserver:(id)anObserver forKeyPath:(CPString)aPath { - var observers = [_observersForKey objectForKey:aPath]; + var observers = _observersForKey[aPath]; if (aPath.indexOf('.') != CPNotFound) { @@ -279,9 +282,12 @@ var kvoNewAndOld = CPKeyValueObservingOptionNew|CPKeyValueObservingOptionOld, [observers removeObjectForKey:[anObserver UID]]; if (![observers count]) - [_observersForKey removeObjectForKey:aPath]; + { + _observersForKeyLength--; + delete _observersForKey[aPath]; + } - if (![_observersForKey count]) + if (!_observersForKeyLength) { _targetObject.isa = _nativeClass; //restore the original class delete _targetObject[KVOProxyKey]; @@ -292,7 +298,7 @@ var kvoNewAndOld = CPKeyValueObservingOptionNew|CPKeyValueObservingOptionOld, - (void)_sendNotificationsForKey:(CPString)aKey changeOptions:(CPDictionary)changeOptions isBefore:(BOOL)isBefore { - var changes = [_changesForKey objectForKey:aKey]; + var changes = _changesForKey[aKey]; if (isBefore) { @@ -324,7 +330,7 @@ var kvoNewAndOld = CPKeyValueObservingOptionNew|CPKeyValueObservingOptionOld, [changes setObject:1 forKey:CPKeyValueChangeNotificationIsPriorKey]; - [_changesForKey setObject:changes forKey:aKey]; + _changesForKey[aKey] = changes; } else { @@ -355,7 +361,7 @@ var kvoNewAndOld = CPKeyValueObservingOptionNew|CPKeyValueObservingOptionOld, } } - var observers = [[_observersForKey objectForKey:aKey] allValues], + var observers = [_observersForKey[aKey] allValues], count = observers ? observers.length : 0; while (count--) @@ -368,7 +374,12 @@ var kvoNewAndOld = CPKeyValueObservingOptionNew|CPKeyValueObservingOptionOld, [observerInfo.observer observeValueForKeyPath:aKey ofObject:_targetObject change:changes context:observerInfo.context]; } - var keysComposedOfKey = [[[DependentKeysMap objectForKey:[_nativeClass UID]] objectForKey:aKey] allObjects]; + var dependentKeysMap = DependentKeysMap[[_nativeClass UID]]; + + if (!dependentKeysMap) + return; + + var keysComposedOfKey = [dependentKeysMap[aKey] allObjects]; if (!keysComposedOfKey) return; From 59bec06e6e295817de069b05c471d41aad1506f5 Mon Sep 17 00:00:00 2001 From: Francisco Ryan Tolmasky I Date: Mon, 27 Jul 2009 12:04:41 -0700 Subject: [PATCH 27/53] Removed CPDOMWindowBridge file. Reviewed by me. --- AppKit/Platform/DOM/CPDOMWindowBridge.j | 119 ------------------------ 1 file changed, 119 deletions(-) delete mode 100644 AppKit/Platform/DOM/CPDOMWindowBridge.j diff --git a/AppKit/Platform/DOM/CPDOMWindowBridge.j b/AppKit/Platform/DOM/CPDOMWindowBridge.j deleted file mode 100644 index ac3352666..000000000 --- a/AppKit/Platform/DOM/CPDOMWindowBridge.j +++ /dev/null @@ -1,119 +0,0 @@ -/* - * CPDOMWindowBridge.j - * AppKit - * - * Created by Francisco Tolmasky. - * Copyright 2008, 280 North, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -@import -@import - -@import "CPEvent.j" -@import "CPCompatibility.j" - - -#import "../../CoreGraphics/CGGeometry.h" - - -CPSharedDOMWindowBridge = nil; - -var ExcludedDOMElements = []; - -// Define up here so compressor knows about em. -var CPDOMWindowGetFrame, - CPDOMEventGetClickCount, - CPDOMEventStop; - -@implementation CPDOMWindowBridge : CPObject -{ -} - -/*! - Returns the shared DOMWindowBridge. -*/ -+ (id)sharedDOMWindowBridge -{ - if (!CPSharedDOMWindowBridge) - CPSharedDOMWindowBridge = [[CPDOMWindowBridge alloc] _init]; - - return CPSharedDOMWindowBridge; -} - -/* @ignore */ -- (id)_init//_initWithDOMWindow:(DOMWindow)aDOMWindow -{ - self = [super init]; - - if (self) - { - } - - return self; -} - -- (CPRect)frame -{ - return [self contentRect]; -} - -- (CGRect)visibleFrame -{ - return [[CPPlatformWindow primaryPlatformWindow] usableContentFrame]; -} - -- (CPRect)contentBounds -{ - var contentBounds = [[CPPlatformWindow primaryPlatformWindow] contentRect]; - contentBounds.origin = CGPointMake(0,0); - - return contentBounds; -} - -- (CPArray)orderedWindowsAtLevel:(int)aLevel -{ - return [[CPPlatformWindow primaryPlatformWindow] orderedWindowsAtLevel:aLevel]; -} - -- (CPDOMWindowLayer)layerAtLevel:(int)aLevel create:(BOOL)aFlag -{ - return [[CPPlatformWindow primaryPlatformWindow] layerAtLevel:aLevel create:aFlag]; -} - -- (void)order:(CPWindowOrderingMode)aPlace window:(CPWindow)aWindow relativeTo:(CPWindow)otherWindow -{ - return [[CPPlatformWindow primaryPlatformWindow] order:aPlace window:aWindow relativeTo:otherWindow]; -} - -/* @ignore */ -- (id)_dragHitTest:(CPPoint)aPoint pasteboard:(CPPasteboard)aPasteboard -{ - return [[CPPlatformWindow primaryPlatformWindow] _dragHitTest:aPoint pasteboard:aPasteboard]; -} - -/* @ignore */ -- (void)_propagateCurrentDOMEvent:(BOOL)aFlag -{ - return [[CPPlatformWindow primaryPlatformWindow] _propagateCurrentDOMEvent:aFlag]; -} - -- (CPWindow)hitTest:(CPPoint)location -{ - return [[CPPlatformWindow primaryPlatformWindow] hitTest:location]; -} - -@end From c0400d636242ddda2ccf6bdb1b2956a9dbfada4d Mon Sep 17 00:00:00 2001 From: Ross Boucher Date: Mon, 27 Jul 2009 13:16:31 -0700 Subject: [PATCH 28/53] Fix a bug where press was clobbering CPApplication arguments. Also changed line endings to Mac/Unix from Windows. --- AppKit/CPApplication.j | 12 +- Tools/press/main.j | 1170 ++++++++++++++++++++-------------------- 2 files changed, 593 insertions(+), 589 deletions(-) diff --git a/AppKit/CPApplication.j b/AppKit/CPApplication.j index f150bb026..dd71a604c 100644 --- a/AppKit/CPApplication.j +++ b/AppKit/CPApplication.j @@ -772,14 +772,18 @@ function CPApplicationMain(args, namedArgs) [principalClass sharedApplication]; //FIXME? - if (!args && !namedArgs) + if (!args) { - var args = [CPApp arguments], - searchParams = window.location.search.substring(1).split("&"); - namedArgs = [CPDictionary dictionary]; + var args = [CPApp arguments]; if([args containsObject:"debug"]) CPLogRegister(CPLogPopup); + } + + if (!namedArgs) + { + var searchParams = window.location.search.substring(1).split("&"); + namedArgs = [CPDictionary dictionary]; for(var i=0; i - -@import "objj-analysis-tools.j" - -var defaultMain = "main.j", - defaultFrameworks = "Frameworks"; - -var usageMessage = -"Usage: press root_directory output_directory [options]\n\ - --main path The relative path (from root_directory) to the main file (default: 'main.j')\n\ - --frameworks path The relative path (from root_directory) to the frameworks directory (default: 'Frameworks')\n\ - --platforms Platform names, colon separated (default: 'browser:objj')\n\ - --png Run pngcrush on all PNGs (pngcrush must be installed!)\n\ - --flatten Flatten all code into a single Application.js file and attempt add script tag to index.html (useful for Adobe AIR and CDN deployment)\n\ - --nostrip Don't strip any files\n\ - --v Verbose"; - -function main() -{ - var rootDirectory = null, - outputDirectory = null, - mainFilename = null, - frameworksDirectory = null, - platforms = ['browser', 'objj'], - optimizePNG = false, - flatten = false, - noStrip = false, - verbose = false; - - var usageError = false; - while (system.args.length && !usageError) - { - var arg = system.args.shift(); - switch(arg) - { - case "--main": - if (system.args.length) - mainFilename = system.args.shift(); - else - usageError = true; - break; - case "--frameworks": - if (system.args.length) - frameworksDirectory = system.args.shift().replace(/\/$/, ""); - else - usageError = true; - break; - case "--platforms": - if (system.args.length) - platforms = system.args.shift().split(":"); - else - usageError = true; - break; - case "--png": - optimizePNG = true; - break; - case "--flatten": - flatten = true; - break; - case "--nostrip": - noStrip = true; - break; - case "--v": - verbose = true; - break; - default: - if (rootDirectory == null) - rootDirectory = arg.replace(/\/$/, ""); - else if (outputDirectory == null) - outputDirectory = arg.replace(/\/$/, ""); - else - usageError = true; - } - } - - if (verbose) - CPLogRegister(CPLogPrint); - else - CPLogRegisterRange(CPLogPrint, "fatal", "info"); - - if (usageError || rootDirectory == null || outputDirectory == null || !platforms.length) - { - print(usageMessage); - return; - } - - rootDirectory = absolutePath(rootDirectory); - - // determine main and frameworks paths - var mainPath = rootDirectory + "/" + (mainFilename || defaultMain), - frameworksPath = rootDirectory + "/" + (frameworksDirectory || defaultFrameworks); - - CPLog.info("Application root: " + rootDirectory); - CPLog.info("Output directory: " + outputDirectory); - CPLog.info("Main file: " + mainPath) - CPLog.info("Frameworks: " + frameworksPath); - - // get a Rhino context - var cx = Packages.org.mozilla.javascript.Context.getCurrentContext(), - scope = makeObjjScope(cx); - - // set OBJJ_INCLUDE_PATHS to include the frameworks path - scope.OBJJ_INCLUDE_PATHS = [frameworksPath]; - scope.OBJJ_PLATFORMS = platforms; - - // flattening bookkeeping. keep track of the bundles and evaled code (in the correct order!) - var bundleArchives = [], - evaledFragments = []; - - scope.objj_search.prototype.didReceiveBundleResponseOriginal = scope.objj_search.prototype.didReceiveBundleResponse; - scope.objj_search.prototype.didReceiveBundleResponse = function(aResponse) { - //CPLog.trace("RESPONSE: " + aResponse); - - var __fakeResponse = { - success : aResponse.success, - filePath : pathRelativeTo(aResponse.filePath, rootDirectory) - }; - - if (aResponse.success) - { - var xmlOutput = new Packages.java.io.ByteArrayOutputStream(); - outputTransformer(xmlOutput, aResponse.xml, "UTF-8"); - //__fakeResponse.xml = String(xmlOutput.toString()); - __fakeResponse.text = CPPropertyListCreate280NorthData(CPPropertyListCreateFromXMLData({ string:String(xmlOutput.toString())})).string; - //CPLog.trace("SERIALIZED: " + __fakeResponse.xml.substring(0,100)); - } - - bundleArchives.push(__fakeResponse); - - this.didReceiveBundleResponseOriginal.apply(this, arguments); - } - - // phase 1: get global defines - CPLog.error("PHASE 1: Loading application..."); - - var globals = findGlobalDefines(cx, scope, mainPath, evaledFragments); - - // coalesce the results - var dependencies = coalesceGlobalDefines(globals); - - // Log - CPLog.trace("Global defines:"); - for (var i in dependencies) - CPLog.trace(" " + i + " => " + dependencies[i]); - - // phase 2: walk the dependency tree (both imports and references) to determine exactly which files need to be included - CPLog.error("PHASE 2: Walk dependency tree..."); - - var requiredFiles = {}; - - if (noStrip) - { - // all files are required. no need for analysis - requiredFiles = scope.objj_files; - } - else - { - if (!scope.objj_files[mainPath]) - { - CPLog.error("Root file not loaded!"); - return; - } - - CPLog.warn("Analyzing dependencies..."); - - var context = { - scope : scope, - dependencies : dependencies, - processedFiles : {}, - ignoreFrameworkImports : true, - importCallback : function(importing, imported) { - requiredFiles[imported] = true; - }, - referenceCallback : function(referencing, referenced) { - requiredFiles[referenced] = true; - } - } - - requiredFiles[mainPath] = true; - traverseDependencies(context, scope.objj_files[mainPath]); - - var count = 0, - total = 0; - for (var path in scope.objj_files) - { - if (requiredFiles[path]) - { - CPLog.debug("Included: " + path); - count++; - } - else - { - CPLog.info("Excluded: " + path); - } - total++; - } - CPLog.warn("Total required files: " + count + " out of " + total); - - // FIXME: sprite images - //for (var i in context.bundleImages) - //{ - // var images = context.bundleImages[i]; - // - // CPLog.debug("Bundle images for " + i); - // for (var j in images) - // CPLog.trace(j + " = " + images[j]); - //} - } - - var outputFiles = {}; - - if (flatten) - { - // phase 3a: build single Application.js file (and modified index.html) - CPLog.error("PHASE 3a: Flattening..."); - - var applicationJS = [], - indexHTML = readFile(rootDirectory + "/index.html"); - - // shim for faking bundle stuff. kind of a giant hack. - var fakeDidReceiveBundleResponse = function(aResponse) - { - var bundle = new objj_bundle(); - - bundle.path = aResponse.filePath; - - if (aResponse.success) - { - var data = new objj_data(); - data.string = aResponse.text; - bundle.info = CPPropertyListCreateFrom280NorthData(data); - //bundle.info = CPPropertyListCreateFromXMLData({ string : aResponse.xml }); - } - else - bundle.info = new objj_dictionary(); - - objj_bundles[aResponse.filePath] = bundle; - } - - // add fake bundle response bookkeeping - applicationJS.push("var __fakeDidReceiveBundleResponse = " + String(fakeDidReceiveBundleResponse)); - applicationJS.push("var __fakeBundleArchives = " + JSON.stringify(bundleArchives) + ";"); - applicationJS.push("for (var i = 0; i < __fakeBundleArchives.length; i++) __fakeDidReceiveBundleResponse(__fakeBundleArchives[i]);") - - // add each fragment, wrapped in a function, along with OBJJ_CURRENT_BUNDLE bookkeeping - for (var i = 0; i < evaledFragments.length; i++) - { - if (requiredFiles[evaledFragments[i].file.path]) - { - applicationJS.push("(function() {"); - applicationJS.push("var OBJJ_CURRENT_BUNDLE = objj_bundles['"+pathRelativeTo(evaledFragments[i].bundle.path, rootDirectory)+"'];"); - applicationJS.push(evaledFragments[i].info); - applicationJS.push("})();"); - } - else - { - CPLog.info("Stripping " + evaledFragments[i].file.path); - } - } - - // call main once the page has loaded - applicationJS.push( - "if (window.addEventListener) \ - window.addEventListener('load', main, false); \ - else if (window.attachEvent) \ - window.attachEvent('onload', main);" - ); - - // comment out any OBJJ_MAIN_FILE defintions or objj_import() calls - indexHTML = indexHTML.replace(/(\bOBJJ_MAIN_FILE\s*=|\bobjj_import\s*\()/g, '//$&'); - - // add a script tag for Application.js at the very end of the block - indexHTML = indexHTML.replace(/([ \t]*)(<\/head>)/, '$1 \n$1$2'); - - // output Application.js and index.html - outputFiles[rootDirectory + "/Application.js"] = applicationJS.join("\n"); - outputFiles[rootDirectory + "/index.html"] = indexHTML; - } - else - { - // phase 3b: rebuild .sj files with correct imports, copy .j files - CPLog.error("PHASE 3b: Rebuild .sj"); - - var bundles = {}; - - for (var path in requiredFiles) - { - var file = scope.objj_files[path], - filename = basename(path), - directory = dirname(path); - - if (file.path != path) - CPLog.warn("Sanity check failed (file path): " + file.path + " vs. " + path); - - if (file.bundle) - { - var bundleDirectory = dirname(file.bundle.path); - - if (!bundles[file.bundle.path]) - bundles[file.bundle.path] = file.bundle; - - if (bundleDirectory != directory) - CPLog.warn("Sanity check failed (directory path): " + directory + " vs. " + bundleDirectory); - - // if it's in a .sj - var dict = file.bundle.info, - replacedFiles = [dict objectForKey:"CPBundleReplacedFiles"]; - if (replacedFiles && [replacedFiles containsObject:filename]) - { - // compute the platform used for this bundle - var platform = "", - bundlePlatforms = [dict objectForKey:"CPBundlePlatforms"]; - - if (bundlePlatforms) - { - platform = [bundlePlatforms firstObjectCommonWithArray:scope.OBJJ_PLATFORMS]; - if (platform) - platform = platform + ".platform/"; - } - - var staticPath = bundleDirectory + "/" + platform + [dict objectForKey:"CPBundleExecutable"]; - if (!outputFiles[staticPath]) - { - outputFiles[staticPath] = []; - outputFiles[staticPath].push("@STATIC;1.0;"); - } - outputFiles[staticPath].push("p;"); - outputFiles[staticPath].push(filename.length+";"); - outputFiles[staticPath].push(filename); - - for (var i = 0; i < file.fragments.length; i++) - { - if (file.fragments[i].type & FRAGMENT_CODE) - { - outputFiles[staticPath].push("c;"); - outputFiles[staticPath].push(file.fragments[i].info.length+";"); - outputFiles[staticPath].push(file.fragments[i].info); - } - else if (file.fragments[i].type & FRAGMENT_FILE) - { - var ignoreFragment = false; - if (file.fragments[i].conditionallyIgnore) - { - var importPath = findImportInObjjFiles(scope, file.fragments[i]); - if (!importPath || !requiredFiles[importPath]) - { - ignoreFragment = true; - } - } - - if (!ignoreFragment) - { - if (file.fragments[i].type & FRAGMENT_LOCAL) - { - var relativePath = pathRelativeTo(file.fragments[i].info, directory) - - outputFiles[staticPath].push("i;"); - outputFiles[staticPath].push(relativePath.length+";"); - outputFiles[staticPath].push(relativePath); - } - else - { - outputFiles[staticPath].push("I;"); - outputFiles[staticPath].push(file.fragments[i].info.length+";"); - outputFiles[staticPath].push(file.fragments[i].info); - } - } - else - CPLog.info("Ignoring import fragment " + file.fragments[i].info + " in " + path); - } - else - CPLog.error("Unknown fragment type"); - } - } - // always output individual .j files - else - { - outputFiles[path] = file.contents; - } - } - else - CPLog.warn("No bundle for " + path) - } - - // phase 3.5: fix bundle plists - CPLog.error("PHASE 3.5: fix bundle plists"); - - for (var path in bundles) - { - var directory = dirname(path), - dict = bundles[path].info, - replacedFiles = [dict objectForKey:"CPBundleReplacedFiles"]; - - CPLog.info("Modifying .sj: " + path); - - if (replacedFiles) - { - var newReplacedFiles = []; - [dict setObject:newReplacedFiles forKey:"CPBundleReplacedFiles"]; - - for (var i = 0; i < replacedFiles.length; i++) - { - var replacedFilePath = directory + "/" + replacedFiles[i] - if (!requiredFiles[replacedFilePath]) - { - CPLog.info("Removing: " + replacedFiles[i]); - } - else - { - //CPLog.info("Keeping: " + replacedFiles[i]); - newReplacedFiles.push(replacedFiles[i]); - } - } - } - outputFiles[path] = CPPropertyListCreateXMLData(dict).string; - } - } - - // phase 4: copy everything and write out the new files - CPLog.error("PHASE 4: copy to output"); - - var rootDirectoryFile = new Packages.java.io.File(rootDirectory), - outputDirectoryFile = new Packages.java.io.File(outputDirectory); - - // FIXME: intelligently copy only what we need (Resources directories?) - copyDirectory(rootDirectoryFile, outputDirectoryFile, optimizePNG); - - for (var path in outputFiles) - { - var file = new java.io.File(outputDirectoryFile, pathRelativeTo(path, rootDirectory)); - - var parent = file.getParentFile(); - if (!parent.exists()) - { - CPLog.warn(parent + " doesn't exist, creating directories."); - parent.mkdirs(); - } - - CPLog.info("Writing out " + file); - - var writer = new java.io.BufferedWriter(new java.io.FileWriter(file)); - - if (typeof outputFiles[path] == "string") - writer.write(outputFiles[path]); - else - writer.write(outputFiles[path].join("")); - - writer.close(); - } -} - -// Helper Utilities - -// TODO: moved elsewhere? - -function copyDirectory(src, dst, optimizePNG) -{ - CPLog.trace("Copying directory " + src); - - dst.mkdirs(); - - var files = src.listFiles(); - for (var i = 0; i < files.length; i++) - { - if (files[i].isFile()) - copyFile(files[i], new Packages.java.io.File(dst, files[i].getName()), optimizePNG); - else if (files[i].isDirectory()) - copyDirectory(files[i], new Packages.java.io.File(dst, files[i].getName()), optimizePNG); - } -} - -function copyFile(src, dst, optimizePNG) -{ - if (optimizePNG && (/.png$/).test(src.getName())) - { - CPLog.warn("Optimizing .png " + src); - exec(["pngcrush", "-rem", "alla", "-reduce", /*"-brute",*/ src.getAbsolutePath(), dst.getAbsolutePath()]); - } - else - { - CPLog.trace("Copying file " + src); - - var input = (new Packages.java.io.FileInputStream(src)).getChannel(), - output = (new Packages.java.io.FileOutputStream(dst)).getChannel(); - - input.transferTo(0, input.size(), output); - - input.close(); - output.close(); - } -} - -function dirname(path) -{ - return path.substring(0, path.lastIndexOf("/")); -} - -function basename(path) -{ - return path.substring(path.lastIndexOf("/") + 1); -} - -function absolutePath(path) -{ - return String((new Packages.java.io.File(path)).getCanonicalPath()); -} - -function pathRelativeTo(target, relativeTo) -{ - var components = [], - targetParts = target.split("/"), - relativeParts = relativeTo ? relativeTo.split("/") : []; - - var i = 0; - while (i < targetParts.length) - { - if (targetParts[i] != relativeParts[i]) - break; - i++; - } - - for (var j = i; j < relativeParts.length; j++) - components.push(".."); - - for (var j = i; j < targetParts.length; j++) - components.push(targetParts[j]); - - var result = components.join("/"); - - return result; -} - -function exec() -{ - var printOutput = false; - - var runtime = Packages.java.lang.Runtime.getRuntime() - var p = runtime.exec.apply(runtime, arguments); - - var stdout = new Packages.java.io.BufferedReader(new Packages.java.io.InputStreamReader(p.getInputStream())), - stdoutString = "", - stderr = new Packages.java.io.BufferedReader(new Packages.java.io.InputStreamReader(p.getErrorStream())), - stderrString = ""; - - var done = false; - while (!done) - { - done = true; - if (s = stdout.readLine()) - { - stdoutString += s; - if (printOutput) - CPLog.info("exec: " + s); - done = false; - } - if (s = stderr.readLine()) - { - stderrString += s; - //if (printOutput) - CPLog.warn("exec: " + s); - done = false; - } - } - - var code = p.waitFor(); - - return { code : code, stdout : stdoutString, stderr : stderrString }; -} - -function outputTransformer(os, document, encoding, standalone) -{ - var domSource = new Packages.javax.xml.transform.dom.DOMSource(document); - var streamResult = new Packages.javax.xml.transform.stream.StreamResult(os); - var tf = Packages.javax.xml.transform.TransformerFactory.newInstance(); - - var serializer = tf.newTransformer(); - serializer.setOutputProperty(Packages.javax.xml.transform.OutputKeys.VERSION, "1.0"); - serializer.setOutputProperty(Packages.javax.xml.transform.OutputKeys.INDENT, "yes"); - if (encoding) - serializer.setOutputProperty(Packages.javax.xml.transform.OutputKeys.ENCODING, encoding); - if (standalone) - serializer.setOutputProperty(Packages.javax.xml.transform.OutputKeys.STANDALONE, (standalone ? "yes" : "no")); - - String(serializer.transform(domSource, streamResult)); -} +@import + +@import "objj-analysis-tools.j" + +var defaultMain = "main.j", + defaultFrameworks = "Frameworks"; + +var usageMessage = +"Usage: press root_directory output_directory [options]\n\ + --main path The relative path (from root_directory) to the main file (default: 'main.j')\n\ + --frameworks path The relative path (from root_directory) to the frameworks directory (default: 'Frameworks')\n\ + --platforms Platform names, colon separated (default: 'browser:objj')\n\ + --png Run pngcrush on all PNGs (pngcrush must be installed!)\n\ + --flatten Flatten all code into a single Application.js file and attempt add script tag to index.html (useful for Adobe AIR and CDN deployment)\n\ + --nostrip Don't strip any files\n\ + --v Verbose"; + +function main() +{ + var rootDirectory = null, + outputDirectory = null, + mainFilename = null, + frameworksDirectory = null, + platforms = ['browser', 'objj'], + optimizePNG = false, + flatten = false, + noStrip = false, + verbose = false; + + var usageError = false; + while (system.args.length && !usageError) + { + var arg = system.args.shift(); + switch(arg) + { + case "--main": + if (system.args.length) + mainFilename = system.args.shift(); + else + usageError = true; + break; + case "--frameworks": + if (system.args.length) + frameworksDirectory = system.args.shift().replace(/\/$/, ""); + else + usageError = true; + break; + case "--platforms": + if (system.args.length) + platforms = system.args.shift().split(":"); + else + usageError = true; + break; + case "--png": + optimizePNG = true; + break; + case "--flatten": + flatten = true; + break; + case "--nostrip": + noStrip = true; + break; + case "--v": + verbose = true; + break; + default: + if (rootDirectory == null) + rootDirectory = arg.replace(/\/$/, ""); + else if (outputDirectory == null) + outputDirectory = arg.replace(/\/$/, ""); + else + usageError = true; + } + } + + if (verbose) + CPLogRegister(CPLogPrint); + else + CPLogRegisterRange(CPLogPrint, "fatal", "info"); + + if (usageError || rootDirectory == null || outputDirectory == null || !platforms.length) + { + print(usageMessage); + return; + } + + rootDirectory = absolutePath(rootDirectory); + + // determine main and frameworks paths + var mainPath = rootDirectory + "/" + (mainFilename || defaultMain), + frameworksPath = rootDirectory + "/" + (frameworksDirectory || defaultFrameworks); + + CPLog.info("Application root: " + rootDirectory); + CPLog.info("Output directory: " + outputDirectory); + CPLog.info("Main file: " + mainPath) + CPLog.info("Frameworks: " + frameworksPath); + + // get a Rhino context + var cx = Packages.org.mozilla.javascript.Context.getCurrentContext(), + scope = makeObjjScope(cx); + + // set OBJJ_INCLUDE_PATHS to include the frameworks path + scope.OBJJ_INCLUDE_PATHS = [frameworksPath]; + scope.OBJJ_PLATFORMS = platforms; + + // flattening bookkeeping. keep track of the bundles and evaled code (in the correct order!) + var bundleArchives = [], + evaledFragments = []; + + scope.objj_search.prototype.didReceiveBundleResponseOriginal = scope.objj_search.prototype.didReceiveBundleResponse; + scope.objj_search.prototype.didReceiveBundleResponse = function(aResponse) { + //CPLog.trace("RESPONSE: " + aResponse); + + var __fakeResponse = { + success : aResponse.success, + filePath : pathRelativeTo(aResponse.filePath, rootDirectory) + }; + + if (aResponse.success) + { + var xmlOutput = new Packages.java.io.ByteArrayOutputStream(); + outputTransformer(xmlOutput, aResponse.xml, "UTF-8"); + //__fakeResponse.xml = String(xmlOutput.toString()); + __fakeResponse.text = CPPropertyListCreate280NorthData(CPPropertyListCreateFromXMLData({ string:String(xmlOutput.toString())})).string; + //CPLog.trace("SERIALIZED: " + __fakeResponse.xml.substring(0,100)); + } + + bundleArchives.push(__fakeResponse); + + this.didReceiveBundleResponseOriginal.apply(this, arguments); + } + + // phase 1: get global defines + CPLog.error("PHASE 1: Loading application..."); + + var globals = findGlobalDefines(cx, scope, mainPath, evaledFragments); + + // coalesce the results + var dependencies = coalesceGlobalDefines(globals); + + // Log + CPLog.trace("Global defines:"); + for (var i in dependencies) + CPLog.trace(" " + i + " => " + dependencies[i]); + + // phase 2: walk the dependency tree (both imports and references) to determine exactly which files need to be included + CPLog.error("PHASE 2: Walk dependency tree..."); + + var requiredFiles = {}; + + if (noStrip) + { + // all files are required. no need for analysis + requiredFiles = scope.objj_files; + } + else + { + if (!scope.objj_files[mainPath]) + { + CPLog.error("Root file not loaded!"); + return; + } + + CPLog.warn("Analyzing dependencies..."); + + var context = { + scope : scope, + dependencies : dependencies, + processedFiles : {}, + ignoreFrameworkImports : true, + importCallback : function(importing, imported) { + requiredFiles[imported] = true; + }, + referenceCallback : function(referencing, referenced) { + requiredFiles[referenced] = true; + } + } + + requiredFiles[mainPath] = true; + traverseDependencies(context, scope.objj_files[mainPath]); + + var count = 0, + total = 0; + for (var path in scope.objj_files) + { + if (requiredFiles[path]) + { + CPLog.debug("Included: " + path); + count++; + } + else + { + CPLog.info("Excluded: " + path); + } + total++; + } + CPLog.warn("Total required files: " + count + " out of " + total); + + // FIXME: sprite images + //for (var i in context.bundleImages) + //{ + // var images = context.bundleImages[i]; + // + // CPLog.debug("Bundle images for " + i); + // for (var j in images) + // CPLog.trace(j + " = " + images[j]); + //} + } + + var outputFiles = {}; + + if (flatten) + { + // phase 3a: build single Application.js file (and modified index.html) + CPLog.error("PHASE 3a: Flattening..."); + + var applicationJS = [], + indexHTML = readFile(rootDirectory + "/index.html"); + + // shim for faking bundle stuff. kind of a giant hack. + var fakeDidReceiveBundleResponse = function(aResponse) + { + var bundle = new objj_bundle(); + + bundle.path = aResponse.filePath; + + if (aResponse.success) + { + var data = new objj_data(); + data.string = aResponse.text; + bundle.info = CPPropertyListCreateFrom280NorthData(data); + //bundle.info = CPPropertyListCreateFromXMLData({ string : aResponse.xml }); + } + else + bundle.info = new objj_dictionary(); + + objj_bundles[aResponse.filePath] = bundle; + } + + // add fake bundle response bookkeeping + applicationJS.push("var __fakeDidReceiveBundleResponse = " + String(fakeDidReceiveBundleResponse)); + applicationJS.push("var __fakeBundleArchives = " + JSON.stringify(bundleArchives) + ";"); + applicationJS.push("for (var i = 0; i < __fakeBundleArchives.length; i++) __fakeDidReceiveBundleResponse(__fakeBundleArchives[i]);") + + // add each fragment, wrapped in a function, along with OBJJ_CURRENT_BUNDLE bookkeeping + for (var i = 0; i < evaledFragments.length; i++) + { + if (requiredFiles[evaledFragments[i].file.path]) + { + applicationJS.push("(function() {"); + applicationJS.push("var OBJJ_CURRENT_BUNDLE = objj_bundles['"+pathRelativeTo(evaledFragments[i].bundle.path, rootDirectory)+"'];"); + applicationJS.push(evaledFragments[i].info); + applicationJS.push("})();"); + } + else + { + CPLog.info("Stripping " + evaledFragments[i].file.path); + } + } + + // call main once the page has loaded + applicationJS.push( + "if (window.addEventListener) \ + window.addEventListener('load', function(){main()}, false); \ + else if (window.attachEvent) \ + window.attachEvent('onload', function(){main()});" + ); + + // comment out any OBJJ_MAIN_FILE defintions or objj_import() calls + indexHTML = indexHTML.replace(/(\bOBJJ_MAIN_FILE\s*=|\bobjj_import\s*\()/g, '//$&'); + + // add a script tag for Application.js at the very end of the block + indexHTML = indexHTML.replace(/([ \t]*)(<\/head>)/, '$1 \n$1$2'); + + // output Application.js and index.html + outputFiles[rootDirectory + "/Application.js"] = applicationJS.join("\n"); + outputFiles[rootDirectory + "/index.html"] = indexHTML; + } + else + { + // phase 3b: rebuild .sj files with correct imports, copy .j files + CPLog.error("PHASE 3b: Rebuild .sj"); + + var bundles = {}; + + for (var path in requiredFiles) + { + var file = scope.objj_files[path], + filename = basename(path), + directory = dirname(path); + + if (file.path != path) + CPLog.warn("Sanity check failed (file path): " + file.path + " vs. " + path); + + if (file.bundle) + { + var bundleDirectory = dirname(file.bundle.path); + + if (!bundles[file.bundle.path]) + bundles[file.bundle.path] = file.bundle; + + if (bundleDirectory != directory) + CPLog.warn("Sanity check failed (directory path): " + directory + " vs. " + bundleDirectory); + + // if it's in a .sj + var dict = file.bundle.info, + replacedFiles = [dict objectForKey:"CPBundleReplacedFiles"]; + if (replacedFiles && [replacedFiles containsObject:filename]) + { + // compute the platform used for this bundle + var platform = "", + bundlePlatforms = [dict objectForKey:"CPBundlePlatforms"]; + + if (bundlePlatforms) + { + platform = [bundlePlatforms firstObjectCommonWithArray:scope.OBJJ_PLATFORMS]; + if (platform) + platform = platform + ".platform/"; + } + + var staticPath = bundleDirectory + "/" + platform + [dict objectForKey:"CPBundleExecutable"]; + if (!outputFiles[staticPath]) + { + outputFiles[staticPath] = []; + outputFiles[staticPath].push("@STATIC;1.0;"); + } + outputFiles[staticPath].push("p;"); + outputFiles[staticPath].push(filename.length+";"); + outputFiles[staticPath].push(filename); + + for (var i = 0; i < file.fragments.length; i++) + { + if (file.fragments[i].type & FRAGMENT_CODE) + { + outputFiles[staticPath].push("c;"); + outputFiles[staticPath].push(file.fragments[i].info.length+";"); + outputFiles[staticPath].push(file.fragments[i].info); + } + else if (file.fragments[i].type & FRAGMENT_FILE) + { + var ignoreFragment = false; + if (file.fragments[i].conditionallyIgnore) + { + var importPath = findImportInObjjFiles(scope, file.fragments[i]); + if (!importPath || !requiredFiles[importPath]) + { + ignoreFragment = true; + } + } + + if (!ignoreFragment) + { + if (file.fragments[i].type & FRAGMENT_LOCAL) + { + var relativePath = pathRelativeTo(file.fragments[i].info, directory) + + outputFiles[staticPath].push("i;"); + outputFiles[staticPath].push(relativePath.length+";"); + outputFiles[staticPath].push(relativePath); + } + else + { + outputFiles[staticPath].push("I;"); + outputFiles[staticPath].push(file.fragments[i].info.length+";"); + outputFiles[staticPath].push(file.fragments[i].info); + } + } + else + CPLog.info("Ignoring import fragment " + file.fragments[i].info + " in " + path); + } + else + CPLog.error("Unknown fragment type"); + } + } + // always output individual .j files + else + { + outputFiles[path] = file.contents; + } + } + else + CPLog.warn("No bundle for " + path) + } + + // phase 3.5: fix bundle plists + CPLog.error("PHASE 3.5: fix bundle plists"); + + for (var path in bundles) + { + var directory = dirname(path), + dict = bundles[path].info, + replacedFiles = [dict objectForKey:"CPBundleReplacedFiles"]; + + CPLog.info("Modifying .sj: " + path); + + if (replacedFiles) + { + var newReplacedFiles = []; + [dict setObject:newReplacedFiles forKey:"CPBundleReplacedFiles"]; + + for (var i = 0; i < replacedFiles.length; i++) + { + var replacedFilePath = directory + "/" + replacedFiles[i] + if (!requiredFiles[replacedFilePath]) + { + CPLog.info("Removing: " + replacedFiles[i]); + } + else + { + //CPLog.info("Keeping: " + replacedFiles[i]); + newReplacedFiles.push(replacedFiles[i]); + } + } + } + outputFiles[path] = CPPropertyListCreateXMLData(dict).string; + } + } + + // phase 4: copy everything and write out the new files + CPLog.error("PHASE 4: copy to output"); + + var rootDirectoryFile = new Packages.java.io.File(rootDirectory), + outputDirectoryFile = new Packages.java.io.File(outputDirectory); + + // FIXME: intelligently copy only what we need (Resources directories?) + copyDirectory(rootDirectoryFile, outputDirectoryFile, optimizePNG); + + for (var path in outputFiles) + { + var file = new java.io.File(outputDirectoryFile, pathRelativeTo(path, rootDirectory)); + + var parent = file.getParentFile(); + if (!parent.exists()) + { + CPLog.warn(parent + " doesn't exist, creating directories."); + parent.mkdirs(); + } + + CPLog.info("Writing out " + file); + + var writer = new java.io.BufferedWriter(new java.io.FileWriter(file)); + + if (typeof outputFiles[path] == "string") + writer.write(outputFiles[path]); + else + writer.write(outputFiles[path].join("")); + + writer.close(); + } +} + +// Helper Utilities + +// TODO: moved elsewhere? + +function copyDirectory(src, dst, optimizePNG) +{ + CPLog.trace("Copying directory " + src); + + dst.mkdirs(); + + var files = src.listFiles(); + for (var i = 0; i < files.length; i++) + { + if (files[i].isFile()) + copyFile(files[i], new Packages.java.io.File(dst, files[i].getName()), optimizePNG); + else if (files[i].isDirectory()) + copyDirectory(files[i], new Packages.java.io.File(dst, files[i].getName()), optimizePNG); + } +} + +function copyFile(src, dst, optimizePNG) +{ + if (optimizePNG && (/.png$/).test(src.getName())) + { + CPLog.warn("Optimizing .png " + src); + exec(["pngcrush", "-rem", "alla", "-reduce", /*"-brute",*/ src.getAbsolutePath(), dst.getAbsolutePath()]); + } + else + { + CPLog.trace("Copying file " + src); + + var input = (new Packages.java.io.FileInputStream(src)).getChannel(), + output = (new Packages.java.io.FileOutputStream(dst)).getChannel(); + + input.transferTo(0, input.size(), output); + + input.close(); + output.close(); + } +} + +function dirname(path) +{ + return path.substring(0, path.lastIndexOf("/")); +} + +function basename(path) +{ + return path.substring(path.lastIndexOf("/") + 1); +} + +function absolutePath(path) +{ + return String((new Packages.java.io.File(path)).getCanonicalPath()); +} + +function pathRelativeTo(target, relativeTo) +{ + var components = [], + targetParts = target.split("/"), + relativeParts = relativeTo ? relativeTo.split("/") : []; + + var i = 0; + while (i < targetParts.length) + { + if (targetParts[i] != relativeParts[i]) + break; + i++; + } + + for (var j = i; j < relativeParts.length; j++) + components.push(".."); + + for (var j = i; j < targetParts.length; j++) + components.push(targetParts[j]); + + var result = components.join("/"); + + return result; +} + +function exec() +{ + var printOutput = false; + + var runtime = Packages.java.lang.Runtime.getRuntime() + var p = runtime.exec.apply(runtime, arguments); + + var stdout = new Packages.java.io.BufferedReader(new Packages.java.io.InputStreamReader(p.getInputStream())), + stdoutString = "", + stderr = new Packages.java.io.BufferedReader(new Packages.java.io.InputStreamReader(p.getErrorStream())), + stderrString = ""; + + var done = false; + while (!done) + { + done = true; + if (s = stdout.readLine()) + { + stdoutString += s; + if (printOutput) + CPLog.info("exec: " + s); + done = false; + } + if (s = stderr.readLine()) + { + stderrString += s; + //if (printOutput) + CPLog.warn("exec: " + s); + done = false; + } + } + + var code = p.waitFor(); + + return { code : code, stdout : stdoutString, stderr : stderrString }; +} + +function outputTransformer(os, document, encoding, standalone) +{ + var domSource = new Packages.javax.xml.transform.dom.DOMSource(document); + var streamResult = new Packages.javax.xml.transform.stream.StreamResult(os); + var tf = Packages.javax.xml.transform.TransformerFactory.newInstance(); + + var serializer = tf.newTransformer(); + serializer.setOutputProperty(Packages.javax.xml.transform.OutputKeys.VERSION, "1.0"); + serializer.setOutputProperty(Packages.javax.xml.transform.OutputKeys.INDENT, "yes"); + if (encoding) + serializer.setOutputProperty(Packages.javax.xml.transform.OutputKeys.ENCODING, encoding); + if (standalone) + serializer.setOutputProperty(Packages.javax.xml.transform.OutputKeys.STANDALONE, (standalone ? "yes" : "no")); + + String(serializer.transform(domSource, streamResult)); +} From 5ccc638bafbf22ca44d237e7965979c6f67c57f2 Mon Sep 17 00:00:00 2001 From: Ross Boucher Date: Mon, 27 Jul 2009 15:55:53 -0700 Subject: [PATCH 29/53] Add resources for CPButton disabled state. Closes #152. --- .gitignore | 2 +- .../Resources/button-bezel-disabled-center.png | Bin 0 -> 148 bytes .../Resources/button-bezel-disabled-left.png | Bin 0 -> 221 bytes .../Resources/button-bezel-disabled-right.png | Bin 0 -> 217 bytes AppKit/Themes/Aristo/ThemeDescriptors.j | 12 ++++++++++++ 5 files changed, 13 insertions(+), 1 deletion(-) create mode 100644 AppKit/Themes/Aristo/Resources/button-bezel-disabled-center.png create mode 100644 AppKit/Themes/Aristo/Resources/button-bezel-disabled-left.png create mode 100644 AppKit/Themes/Aristo/Resources/button-bezel-disabled-right.png diff --git a/.gitignore b/.gitignore index 71e257752..b72055ed9 100644 --- a/.gitignore +++ b/.gitignore @@ -2,5 +2,5 @@ Frameworks Build Demos -Aristo +./Aristo WebSite diff --git a/AppKit/Themes/Aristo/Resources/button-bezel-disabled-center.png b/AppKit/Themes/Aristo/Resources/button-bezel-disabled-center.png new file mode 100644 index 0000000000000000000000000000000000000000..7f143a3de420f9d7c4e33a1f9560c7bf8b328130 GIT binary patch literal 148 zcmeAS@N?(olHy`uVBq!ia0vp^j6f{G!3HF)&rH7sq$EpRBT9nv(@M${i&7aJQ}UBi z6+Ckj(^G>|6H_V+Po~-c6`6UuIEGZ*O1ihZJfHdS_xJauXY8x}eeA%O_xJ7Dmi_<# v-#Iel$o>8G9}5b*7D`q|6H_V+Po~-c71evXIEGZ*O1iVVT;G_Px!G1gn!!;1^#A|=WtT2llCxy# zQpp=PZb-~%U}}5x=n+r-|9`1JzP*)ZKE1#G|Bl8PjBE~35)Kl243k^~9hWhj@Vb?~ zuv78`(*lJ*zkYwuXNzz!WK2D8U;l5;!|Utg6Q(Xuxby$l*X%TfYpkyxFmf0$Bzopr0C0a->Hq)$ literal 0 HcmV?d00001 diff --git a/AppKit/Themes/Aristo/Resources/button-bezel-disabled-right.png b/AppKit/Themes/Aristo/Resources/button-bezel-disabled-right.png new file mode 100644 index 0000000000000000000000000000000000000000..6db8a99ddb64e24a16fa26f4cb11baa95eebc71d GIT binary patch literal 217 zcmeAS@N?(olHy`uVBq!ia0vp^EI=&5!3HGnK8=|Nq$EpRBT9nv(@M${i&7aJQ}UBi z6+Ckj(^G>|6H_V+Po~-c6;*q>IEGZ*O1iVVJfE4F`LMdeK87Rgk!#khk*NFo>*)6{ zFN1fdpPy%FSo`~1@5A@^_wzh@^oZyG|NrJGKfk}1XXatJc}K?~a0f$2@46-(#tBom zTz3*SHeg9${PO&~d;mi&>uQF=xP3L8L4}P^53vTkFs@;IblPDLzrq2AIN5nCV#>O5 QfX-m>boFyt=akR{0OL$m1ONa4 literal 0 HcmV?d00001 diff --git a/AppKit/Themes/Aristo/ThemeDescriptors.j b/AppKit/Themes/Aristo/ThemeDescriptors.j index 72efe57a9..7eeefa96d 100644 --- a/AppKit/Themes/Aristo/ThemeDescriptors.j +++ b/AppKit/Themes/Aristo/ThemeDescriptors.j @@ -53,6 +53,14 @@ [_CPCibCustomResource imageResourceWithName:"default-button-bezel-highlighted-center.png" size:CGSizeMake(1.0, 24.0)], [_CPCibCustomResource imageResourceWithName:"default-button-bezel-highlighted-right.png" size:CGSizeMake(4.0, 24.0)] ] + isVertical:NO]], + + disabledBezelColor = [CPColor colorWithPatternImage:[[CPThreePartImage alloc] initWithImageSlices: + [ + [_CPCibCustomResource imageResourceWithName:"button-bezel-disabled-left.png" size:CGSizeMake(4.0, 24.0)], + [_CPCibCustomResource imageResourceWithName:"button-bezel-disabled-center.png" size:CGSizeMake(1.0, 24.0)], + [_CPCibCustomResource imageResourceWithName:"button-bezel-disabled-right.png" size:CGSizeMake(4.0, 24.0)] + ] isVertical:NO]]; [button setValue:[CPFont boldSystemFontOfSize:12.0] forThemeAttribute:@"font" inState:CPThemeStateBordered]; @@ -65,6 +73,10 @@ [button setValue:highlightedBezelColor forThemeAttribute:@"bezel-color" inState:CPThemeStateBordered|CPThemeStateHighlighted]; [button setValue:CGInsetMake(0.0, 5.0, 0.0, 5.0) forThemeAttribute:@"content-inset" inState:CPThemeStateBordered]; + [button setValue:[CPColor colorWithCalibratedWhite:0.6 alpha:1.0] forThemeAttribute:@"text-color" inState:CPThemeStateDisabled]; + [button setValue:disabledBezelColor forThemeAttribute:@"bezel-color" inState:CPThemeStateDisabled]; + [button setValue:disabledBezelColor forThemeAttribute:@"bezel-color" inState:CPThemeStateDefault|CPThemeStateDisabled]; + [button setValue:defaultBezelColor forThemeAttribute:@"bezel-color" inState:CPThemeStateBordered|CPThemeStateDefault]; [button setValue:defaultHighlightedBezelColor forThemeAttribute:@"bezel-color" inState:CPThemeStateBordered|CPThemeStateHighlighted|CPThemeStateDefault]; [button setValue:[CPColor colorWithCalibratedRed:13.0/255.0 green:51.0/255.0 blue:70.0/255.0 alpha:1.0] forThemeAttribute:@"text-color" inState:CPThemeStateDefault]; From 38e2ca3589dc8145875303ebf95c6460df5e7308 Mon Sep 17 00:00:00 2001 From: Ross Boucher Date: Mon, 27 Jul 2009 16:20:12 -0700 Subject: [PATCH 30/53] Add pushed states to checkboxes. --- .../Resources/check-box-bezel-highlighted.png | Bin 0 -> 289 bytes .../check-box-bezel-selected-highlighted.png | Bin 0 -> 625 bytes AppKit/Themes/Aristo/ThemeDescriptors.j | 12 ++++++++++++ 3 files changed, 12 insertions(+) create mode 100644 AppKit/Themes/Aristo/Resources/check-box-bezel-highlighted.png create mode 100644 AppKit/Themes/Aristo/Resources/check-box-bezel-selected-highlighted.png diff --git a/AppKit/Themes/Aristo/Resources/check-box-bezel-highlighted.png b/AppKit/Themes/Aristo/Resources/check-box-bezel-highlighted.png new file mode 100644 index 0000000000000000000000000000000000000000..51e26047ed49054e9342608b94dbb105acfbef03 GIT binary patch literal 289 zcmV++0p9+JP)7A!xpaaDJ8+SyO@Cp1U%@N!B% nH%+6!7MJQ7!3NyH@g=|j?m@g!*4HD100000NkvXXu0mjfDY$mp literal 0 HcmV?d00001 diff --git a/AppKit/Themes/Aristo/Resources/check-box-bezel-selected-highlighted.png b/AppKit/Themes/Aristo/Resources/check-box-bezel-selected-highlighted.png new file mode 100644 index 0000000000000000000000000000000000000000..dc2a5f089f9e1368b34fabd484f3b0f71ab6f1bc GIT binary patch literal 625 zcmV-%0*?KOP)TX%iFd zBok9>Vqz>Ye%DmcU*bl^wR;z$bkl|Y0Z|GSM8SeVP=cUa10oizAc|N5wMmF=(j>L* z%)JxOooYj=je6mQx#yhcd~nb7-F{lc|D4II7f1T~*{zP?mzm=@8rg1;E|FrrKp{Bd z*;7`%(a@~bmRG_P2g1Q?@kj_>mG!K8_udrN!L&WGgD?UE1`|SD@p&|SF4tjmu`Bpt z_AOq$nMEKP$FON&Y%F(3!bY{x?pg7BwTu^q0tUk|=(>*cXUFlw5(eWm2PN1Qv~3Id z$B&=|4KVKj&YeEtCTOnJp$N_)6G+WW-$A?G+PX^>@-tY23XeaC(Zqg4_nEF;atfz8 zZQH?8Z3$oJOL+3&KCBJy+TImkWBywOddNU1;K$L-5!WsyIf6GUG#bnBnGU>#7ZzYb@EutXr&8FMn?o{@fa7#X;*YB;+pgK%G89GG=FDa@n?VlW0n$p#wrdJ4 z$W*i0hGoePoWDxO$#~+XnQ+9-_G(KbU7)1qKm3&y(nHeqp8^a3j3Yrkr)lZY00000 LNkvXXu0mjfRSFw& literal 0 HcmV?d00001 diff --git a/AppKit/Themes/Aristo/ThemeDescriptors.j b/AppKit/Themes/Aristo/ThemeDescriptors.j index 7eeefa96d..7be96d1cb 100644 --- a/AppKit/Themes/Aristo/ThemeDescriptors.j +++ b/AppKit/Themes/Aristo/ThemeDescriptors.j @@ -386,6 +386,16 @@ [ [_CPCibCustomResource imageResourceWithName:"check-box-bezel-selected.png" size:CGSizeMake(15.0, 16.0)], nil, nil ] + isVertical:NO]), + bezelColorSelectedHighlighted = PatternColor([[CPThreePartImage alloc] initWithImageSlices: + [ + [_CPCibCustomResource imageResourceWithName:"check-box-bezel-selected-highlighted.png" size:CGSizeMake(15.0, 16.0)], nil, nil + ] + isVertical:NO]), + bezelColorHighlighted = PatternColor([[CPThreePartImage alloc] initWithImageSlices: + [ + [_CPCibCustomResource imageResourceWithName:"check-box-bezel-highlighted.png" size:CGSizeMake(15.0, 16.0)], nil, nil + ] isVertical:NO]); [button setValue:CPLeftTextAlignment forThemeAttribute:@"alignment" inState:CPThemeStateBordered]; @@ -393,6 +403,8 @@ [button setValue:CGInsetMake(0.0, 0.0, 0.0, 20.0) forThemeAttribute:@"content-inset" inState:CPThemeStateBordered]; [button setValue:bezelColor forThemeAttribute:@"bezel-color" inState:CPThemeStateBordered]; [button setValue:bezelColorSelected forThemeAttribute:@"bezel-color" inState:CPThemeStateBordered | CPThemeStateSelected]; + [button setValue:bezelColorSelectedHighlighted forThemeAttribute:@"bezel-color" inState:CPThemeStateBordered | CPThemeStateSelected | CPThemeStateHighlighted]; + [button setValue:bezelColorHighlighted forThemeAttribute:@"bezel-color" inState:CPThemeStateBordered | CPThemeStateHighlighted]; [button setValue:CGSizeMake(0.0, 17.0) forThemeAttribute:@"min-size"]; From 241cc2ac0662d16a0c157ca5d80b4a8e0a31b7ed Mon Sep 17 00:00:00 2001 From: Ross Boucher Date: Mon, 27 Jul 2009 16:38:30 -0700 Subject: [PATCH 31/53] Add highlighted states to radio buttons. --- .../Aristo/Resources/radio-bezel-highlighted.png | Bin 0 -> 657 bytes .../radio-bezel-selected-highlighted.png | Bin 0 -> 856 bytes AppKit/Themes/Aristo/ThemeDescriptors.j | 12 ++++++++++++ 3 files changed, 12 insertions(+) create mode 100644 AppKit/Themes/Aristo/Resources/radio-bezel-highlighted.png create mode 100644 AppKit/Themes/Aristo/Resources/radio-bezel-selected-highlighted.png diff --git a/AppKit/Themes/Aristo/Resources/radio-bezel-highlighted.png b/AppKit/Themes/Aristo/Resources/radio-bezel-highlighted.png new file mode 100644 index 0000000000000000000000000000000000000000..6f16d4803dc09c53440bd6bb9daceeb44a075e84 GIT binary patch literal 657 zcmV;C0&e|@P)(64bSYw|=%4W0IJRZ+yzu)h5xm;p8 zor=X`v4LK%-@s%tiB_v68jVJ?QmNdH$KyY#N>7GxIBZfBjw+nZRM6AJJAk1d7 z@cDdRZ1Nm`J>+X0ess}j^a(87TCdk)G#Ux`|1bC+SqZn>eF*hW>4Hl12=Orj6bMde zDFiLhBaB8PNpd7HfZ#TF*~->ZT#vq+>?er~8%|o`4qA)rL8P#sBoadEz>0%jwH7y= z&1T(gChOsFc#Oafn7r1SOeO+-C)*=l;@sak9F7BqrL}n6wOZ{J`#Eez%*drwD)j-w zcGYIHolDT~_XVc*Q!<(4>HLx@2hvth@eRXv56@N{-6ptyq1)|>PN&n#=krJ9a`^|H z$?9cVl}e>fv)TL@3c@Lu#e@)RNM*=5icmFxmw;v7&6Fa?Hc^H?P~ r`zhE{Wl#wu)iR0ZDo%Y*{s=Gt6nP)hJ$xo_Xk&gq;nrz`8g^L-rN_j%vvyyv_x1Ai~}_M^aA!C>rWdA^-xxmJX-Uy!cP zYN|4I=h~TP#0TvqFnc$BgF`j$2H&vPRoU&Sv_XZn1j%+t?7f0x-&RWs7jSmV?&z`J0$=zK9z&na1m#G%?z3T3* z-R~!F#6r~RP;Rxr(TpdA*^%>omt3>>LS%5dJSDX&W}eq4$&b1_lW~N`nx^8YYit$>H&y zU|7b)lTu-f_Jt&gkVwRnZ^j?qOhq^5s3|_>GbPi;Q}-POJM)BIPF|Ui-_!X) idm@w1UNldB3orl)cAzkx4FaeD0000 Date: Mon, 27 Jul 2009 16:51:05 -0700 Subject: [PATCH 32/53] remove opacity from disabled buttons -- otherwise its unusable on dark backgrounds --- .../Resources/button-bezel-disabled-center.png | Bin 148 -> 131 bytes .../Resources/button-bezel-disabled-left.png | Bin 221 -> 211 bytes .../Resources/button-bezel-disabled-right.png | Bin 217 -> 202 bytes 3 files changed, 0 insertions(+), 0 deletions(-) diff --git a/AppKit/Themes/Aristo/Resources/button-bezel-disabled-center.png b/AppKit/Themes/Aristo/Resources/button-bezel-disabled-center.png index 7f143a3de420f9d7c4e33a1f9560c7bf8b328130..2f25f525283ff733a1593882ccea06a1ee43bc02 100644 GIT binary patch delta 77 zcmV-T0J8s-0fPaM83+OZ006YE0F99$C^{ucL_t(|+G4tQ?;gYN-@lna`2YX^1o6Lr j|A0n-7HNq==oL_t(|+RTo-4Fe$%L>F#Dg3IWF)NQ#E+XWr1@JR^~0f^7~ zu!L)1qzUFt^0?OeaL&EF_hgJAu-3jq2$XZCS}P%A>?wqRF~+ahS_2}26`W%iFb#JT zr95Jc@D*SHz=f)|$vyv{01E&B07*qoM6N<$f+2W7 AasU7T delta 156 zcmV;N0Av5t0o?(RNq>JyL_t(|+G5fiwgFckn`xt?>cgQju-0000< KMNUMnLSTZizeukD diff --git a/AppKit/Themes/Aristo/Resources/button-bezel-disabled-right.png b/AppKit/Themes/Aristo/Resources/button-bezel-disabled-right.png index 6db8a99ddb64e24a16fa26f4cb11baa95eebc71d..92127238afebd7d57e158ce012f798af02fd27b4 100644 GIT binary patch delta 137 zcmV;40CxY`0m=c8Nq=lfL_t(|+RTtU4uBvKM2E24SkEExRvZFqLP-J*pB17O7S_7e zzLzN`Bb;+Ar35o?*4kB+Qn9ZEJ#GB rm@o#$7+aI~9!jYRyD?@t1Q-D1v!!ISH+lU400007uL_t(|+G5 Date: Mon, 27 Jul 2009 16:57:16 -0700 Subject: [PATCH 33/53] Add disabled states to CPRadioButton --- .../Aristo/Resources/radio-bezel-disabled.png | Bin 0 -> 640 bytes .../Resources/radio-bezel-selected-disabled.png | Bin 0 -> 799 bytes AppKit/Themes/Aristo/ThemeDescriptors.j | 12 ++++++++++++ 3 files changed, 12 insertions(+) create mode 100644 AppKit/Themes/Aristo/Resources/radio-bezel-disabled.png create mode 100644 AppKit/Themes/Aristo/Resources/radio-bezel-selected-disabled.png diff --git a/AppKit/Themes/Aristo/Resources/radio-bezel-disabled.png b/AppKit/Themes/Aristo/Resources/radio-bezel-disabled.png new file mode 100644 index 0000000000000000000000000000000000000000..76d3c79d7dc05616b0bcedc2fb69a7288347c3dd GIT binary patch literal 640 zcmV-`0)PF9P) z&csR7jb^;bo%`Oq_uO~y-17wCh2(NMvE6QeZ?#wS@Ua#A<-1D6Nml)sEO|4ej zlx6wC@AvPhswxBm0Y@#%a&$VK3iJ8AXxsKtGMTKpIMKZwH-5#ksA<|xG#V9{L=;7W z9Lqh=>1SM}QrUK^lKIJGGTL&vyapL z@%$$?^siwUTPV$QlF4L3DqIpT0%$gy%`+tFj>lt9lL1G_-a9b-oOu2O3y$t!FgO_w zhXw=4h1ZmRsL}8DPl3}*rP9oKJNbMbV^?Be>~1U;`-ydmJYak7=*eQ!G^yoYuXn2J z`VF|%&1SQfLwmGifi!(MuA#??MB*FT+XELq!L2||RMEjC{@_LDB}wWasa~yC?f+ge zo&eeV0k^NihLJ=C*bh4=4KRrZwg5Y11I5>kw`lY)2b=BAPbyamMaH1_OEve~=8}}n2??w{FVj<6}Oxe*CSksvDa((69 zlbM;BxD}(c{$z9OmxX37+Lk%q?bwho4HO+bUPlR`?E2sb{4|`eWt%+mQ&CSiR z?AISt0qD!UT^-}+`ujjPZEyvHT{mis^iS)gC%X@;YgY(Ic#XPiH>WxS!Cnj{yB)($ zzyShV8;>P$9IM#b2?qwGbPh`5c_x#&ip#!AF&G#bd+0dM9nE$cfd74U)H6*7knw=i z(+?5Hb^!U?B@?6jj|Yp;E5QApQ}P zNG*)zumBYVZqk(1PgxA42UbtAF@9P8*rtypL#OgQ;Wcb#EQBS=gZRUQvSD`i08@1Y z)xmcwZF)Gew+OE(ilRyx2T>GRjIm>b?%qD|>jD&9!`$G15=6@;Lg1l9%n47&iDgvZ z<2-11YRbitQRr|IAaPD(YV=Z@o^wtN3xwB@0heL$)^oj-hQVz%nx|5!Hu|khJl6%m z{nvzNNXISjZaoWXl~S!*Z5W;=)k+z7t-Nu#v+fITUfbtBnmcxqk0H|??K(GZiS`7<2Vdn zA?7DuM!!+^`F!3_r_-B&irP+oJCPik<*t1lOY;n--b7Cr#pnP+|Gih-Tf`%LM+V!u zT#o;Bi}4EBaU3U6E@0FLaqK!O0U0Cp3eF331e78%_~%p5d{5{q{H{c^xd~-~f=Dqq d`JVg|U;r{P;N`sT!fOBk002ovPDHLkV1i2qZ6W{w literal 0 HcmV?d00001 diff --git a/AppKit/Themes/Aristo/ThemeDescriptors.j b/AppKit/Themes/Aristo/ThemeDescriptors.j index a047ab9f4..41295e976 100644 --- a/AppKit/Themes/Aristo/ThemeDescriptors.j +++ b/AppKit/Themes/Aristo/ThemeDescriptors.j @@ -364,6 +364,16 @@ [_CPCibCustomResource imageResourceWithName:"radio-bezel-selected-highlighted.png" size:CGSizeMake(17.0, 17.0)], nil, nil ] isVertical:NO]), + bezelColorSelectedDisabled = PatternColor([[CPThreePartImage alloc] initWithImageSlices: + [ + [_CPCibCustomResource imageResourceWithName:"radio-bezel-selected-disabled.png" size:CGSizeMake(17.0, 17.0)], nil, nil + ] + isVertical:NO]), + bezelColorDisabled = PatternColor([[CPThreePartImage alloc] initWithImageSlices: + [ + [_CPCibCustomResource imageResourceWithName:"radio-bezel-disabled.png" size:CGSizeMake(17.0, 17.0)], nil, nil + ] + isVertical:NO]), bezelColorHighlighted = PatternColor([[CPThreePartImage alloc] initWithImageSlices: [ [_CPCibCustomResource imageResourceWithName:"radio-bezel-highlighted.png" size:CGSizeMake(17.0, 17.0)], nil, nil @@ -377,6 +387,8 @@ [button setValue:bezelColorSelected forThemeAttribute:@"bezel-color" inState:CPThemeStateBordered | CPThemeStateSelected]; [button setValue:bezelColorSelectedHighlighted forThemeAttribute:@"bezel-color" inState:CPThemeStateBordered | CPThemeStateSelected | CPThemeStateHighlighted]; [button setValue:bezelColorHighlighted forThemeAttribute:@"bezel-color" inState:CPThemeStateBordered | CPThemeStateHighlighted]; + [button setValue:bezelColorDisabled forThemeAttribute:@"bezel-color" inState:CPThemeStateBordered | CPThemeStateDisabled]; + [button setValue:bezelColorSelectedDisabled forThemeAttribute:@"bezel-color" inState:CPThemeStateBordered | CPThemeStateDisabled | CPThemeStateSelected]; [button setValue:CGSizeMake(0.0, 17.0) forThemeAttribute:@"min-size"]; From a05ecd27593472b66990b8e14e0ccc3bd5763431 Mon Sep 17 00:00:00 2001 From: Ross Boucher Date: Mon, 27 Jul 2009 17:03:34 -0700 Subject: [PATCH 34/53] Add disabled state for check boxes --- .../Aristo/Resources/check-box-bezel-disabled.png | Bin 0 -> 296 bytes .../check-box-bezel-selected-disabled.png | Bin 0 -> 598 bytes AppKit/Themes/Aristo/ThemeDescriptors.j | 12 ++++++++++++ 3 files changed, 12 insertions(+) create mode 100644 AppKit/Themes/Aristo/Resources/check-box-bezel-disabled.png create mode 100644 AppKit/Themes/Aristo/Resources/check-box-bezel-selected-disabled.png diff --git a/AppKit/Themes/Aristo/Resources/check-box-bezel-disabled.png b/AppKit/Themes/Aristo/Resources/check-box-bezel-disabled.png new file mode 100644 index 0000000000000000000000000000000000000000..c1246094f5d3a50c1843b0f42d467975dfccb94a GIT binary patch literal 296 zcmeAS@N?(olHy`uVBq!ia0vp^{6H+g!3HExhN-duDajJoh?3y^w370~qErUQl>DSr z1<%~X^wgl##FWaylc_d9MW;Mn978H@9hqdv*JL2lCjaFiLm+bz(;>ziGQG{x>Yo_m zI;LjqVf4J-CM+P7J44`ut$u@UbN#37vHR+BKh0USiiJUDrDZAi>B_+DSIn&f&vj1g zc}{v#a!+UCV~bbYa836b}oMZyFGK3Phs@YP&kVX2Ex%SJ-uBR6+~CG{TZ8u0$amd~D#~No s4;$zln)lpM=JmdKI;Vst015GR<^TWy literal 0 HcmV?d00001 diff --git a/AppKit/Themes/Aristo/Resources/check-box-bezel-selected-disabled.png b/AppKit/Themes/Aristo/Resources/check-box-bezel-selected-disabled.png new file mode 100644 index 0000000000000000000000000000000000000000..fea5c786c0a9dda267d9068b3efa34b05493286d GIT binary patch literal 598 zcmV-c0;&CpP)f^napN8O?EeG zl8v>&rp1E4!v{g%eG~jy3jPBhMDay@@S$j=2C4-qM$iPMrrk7cn(Zb#AI@$~NbMJ1 zI0JL%o_p?{J42LG_#b=r{N?RlfB&)T6z-C(pMiZ8^C!_bz9*z|E+R@P5riWVa+NWL z(Hjzut*=|4bMqjCpuSW`@+Kw~ zCA{OFHS(^9o69R`cRJV!0tCGtvNqFwW>KpxB1>r+H#>7OQBLe?sf?I&Y;XTg_l9ZW ziXLOZai=k-$g>&C6(4cTvA2H!D@#zVE}S?&K~_qhI`pg8!Q(MXM*si- literal 0 HcmV?d00001 diff --git a/AppKit/Themes/Aristo/ThemeDescriptors.j b/AppKit/Themes/Aristo/ThemeDescriptors.j index 41295e976..bde1704c8 100644 --- a/AppKit/Themes/Aristo/ThemeDescriptors.j +++ b/AppKit/Themes/Aristo/ThemeDescriptors.j @@ -416,6 +416,16 @@ [_CPCibCustomResource imageResourceWithName:"check-box-bezel-selected-highlighted.png" size:CGSizeMake(15.0, 16.0)], nil, nil ] isVertical:NO]), + bezelColorSelectedDisabled = PatternColor([[CPThreePartImage alloc] initWithImageSlices: + [ + [_CPCibCustomResource imageResourceWithName:"check-box-bezel-selected-disabled.png" size:CGSizeMake(15.0, 16.0)], nil, nil + ] + isVertical:NO]), + bezelColorDisabled = PatternColor([[CPThreePartImage alloc] initWithImageSlices: + [ + [_CPCibCustomResource imageResourceWithName:"check-box-bezel-disabled.png" size:CGSizeMake(15.0, 16.0)], nil, nil + ] + isVertical:NO]), bezelColorHighlighted = PatternColor([[CPThreePartImage alloc] initWithImageSlices: [ [_CPCibCustomResource imageResourceWithName:"check-box-bezel-highlighted.png" size:CGSizeMake(15.0, 16.0)], nil, nil @@ -429,6 +439,8 @@ [button setValue:bezelColorSelected forThemeAttribute:@"bezel-color" inState:CPThemeStateBordered | CPThemeStateSelected]; [button setValue:bezelColorSelectedHighlighted forThemeAttribute:@"bezel-color" inState:CPThemeStateBordered | CPThemeStateSelected | CPThemeStateHighlighted]; [button setValue:bezelColorHighlighted forThemeAttribute:@"bezel-color" inState:CPThemeStateBordered | CPThemeStateHighlighted]; + [button setValue:bezelColorDisabled forThemeAttribute:@"bezel-color" inState:CPThemeStateBordered | CPThemeStateDisabled]; + [button setValue:bezelColorSelectedDisabled forThemeAttribute:@"bezel-color" inState:CPThemeStateBordered | CPThemeStateDisabled | CPThemeStateSelected]; [button setValue:CGSizeMake(0.0, 17.0) forThemeAttribute:@"min-size"]; From 41dc660140e4b4d7b6b4f0fe39273816859c950e Mon Sep 17 00:00:00 2001 From: Francisco Ryan Tolmasky I Date: Mon, 27 Jul 2009 18:19:34 -0700 Subject: [PATCH 35/53] Added support for document cibs. Reviewed by me. --- AppKit/CPDocument.j | 17 ++-- AppKit/CPWindowController.j | 161 +++++++++++++++++++++++++++++------- 2 files changed, 139 insertions(+), 39 deletions(-) diff --git a/AppKit/CPDocument.j b/AppKit/CPDocument.j index b39506c37..145d937d5 100644 --- a/AppKit/CPDocument.j +++ b/AppKit/CPDocument.j @@ -90,7 +90,9 @@ var CPDocumentUntitledCount = 0; CPDocuments should be used to represent this. */ @implementation CPDocument : CPResponder -{ +{ + CPWindow _window; // For outlet purposes. + CPURL _fileURL; CPString _fileType; CPArray _windowControllers; @@ -228,9 +230,10 @@ var CPDocumentUntitledCount = 0; */ - (void)makeWindowControllers { - var controller = [[CPWindowController alloc] initWithWindowCibName:nil]; - - [self addWindowController:controller]; + var windowCibName = [self windowCibName]; + + if (windowCibName) + [self addWindowController:[[CPWindowController alloc] initWithWindowCibName:windowCibName owner:self]]; } /*! @@ -250,7 +253,7 @@ var CPDocumentUntitledCount = 0; { [_windowControllers addObject:aWindowController]; - if ([aWindowController document] != self) + if ([aWindowController document] !== self) { [aWindowController setNextResponder:self]; [aWindowController setDocument:self]; @@ -295,7 +298,7 @@ var CPDocumentUntitledCount = 0; Called after aWindowController loads the document's Nib file. @param aWindowController the controller that loaded the Nib file */ -- (void)windowControllerDidLoadNib:(CPWindowController)aWindowController +- (void)windowControllerDidLoadCib:(CPWindowController)aWindowController { } @@ -303,7 +306,7 @@ var CPDocumentUntitledCount = 0; Called before aWindowController will load the document's Nib file. @param aWindowController the controller that will load the Nib file */ -- (void)windowControllerWillLoadNib:(CPWindowController)aWindowController +- (void)windowControllerWillLoadCib:(CPWindowController)aWindowController { } diff --git a/AppKit/CPWindowController.j b/AppKit/CPWindowController.j index 35bc94c90..8ee836374 100644 --- a/AppKit/CPWindowController.j +++ b/AppKit/CPWindowController.j @@ -41,10 +41,22 @@ */ @implementation CPWindowController : CPResponder { - id _owner; CPWindow _window; + CPDocument _document; + BOOL _shouldCloseDocument; + + id _cibOwner; CPString _windowCibName; + CPString _windowCibPath; + + BOOL _isWindowLoading; + BOOL _shouldDisplayWindowWhenLoaded; +} + +- (id)init +{ + return [self initWithWindow:nil]; } /*! @@ -55,14 +67,15 @@ - (id)initWithWindow:(CPWindow)aWindow { self = [super init]; - + if (self) { [self setWindow:aWindow]; - + [self setShouldCloseDocument:NO]; + [self setNextResponder:CPApp]; } - + return self; } @@ -84,37 +97,78 @@ */ - (id)initWithWindowCibName:(CPString)aWindowCibName owner:(id)anOwner { - self = [super init]; - + self = [self initWithWindow:nil]; + if (self) { - _owner = anOwner; + _cibOwner = anOwner; _windowCibName = aWindowCibName; - - [self setNextResponder:CPApp]; } - + + return self; +} + +- (id)initWithWindowCibPath:(CPString)aWindowCibPath owner:(id)anOwner +{ + self = [self initWithWindow:nil]; + + if (self) + { + _cibOwner = anOwner; + _windowCibPath = aWindowCibPath; + } + return self; } /*! Loads the window */ -- (void)loadWindow +- (BOOL)loadWindow { - [self windowWillLoad]; - //FIXME: ACTUALLY LOAD WINDOW!!! - [self setWindow:CPApp._keyWindow = [[CPWindow alloc] initWithContentRect:CPRectMakeZero() styleMask:CPBorderlessBridgeWindowMask|CPTitledWindowMask|CPClosableWindowMask|CPResizableWindowMask]]; - + if ([self isWindowLoaded]) + return YES; + + if (![self isWindowLoading]) + { + _isWindowLoading = YES; + + [self windowWillLoad]; + + [CPBundle loadCibFile:[self windowCibPath] + externalNameTable:[CPDictionary dictionaryWithObject:_cibOwner forKey:CPCibOwner] + loadDelegate:self]; + } + + return NO; +} + +- (void)cibDidFinishLoading:(CPCib)aCib +{ + if (_window === nil && _document !== nil && _cibOwner === _document) + [self setWindow:[_document valueForKey:@"window"]]; + + [self synchronizeWindowTitleWithDocumentName]; + [self windowDidLoad]; + + if (_shouldDisplayWindowWhenLoaded) + [self showWindow:self]; } /*! Shows the window. @param aSender the object requesting the show */ -- (CFAction)showWindow:(id)aSender +- (@action)showWindow:(id)aSender { + if (![self loadWindow]) + { + _shouldDisplayWindowWhenLoaded = YES; + + return; + } + var theWindow = [self window]; if ([theWindow respondsToSelector:@selector(becomesKeyOnlyIfNeeded)] && [theWindow becomesKeyOnlyIfNeeded]) @@ -129,7 +183,12 @@ */ - (BOOL)isWindowLoaded { - return _window; + return _window !== nil; +} + +- (BOOL)isWindowLoading +{ + return _isWindowLoading; } /*! @@ -149,8 +208,10 @@ */ - (void)setWindow:(CPWindow)aWindow { + [_window setWindowController:nil]; + _window = aWindow; - + [_window setWindowController:self]; [_window setNextResponder:self]; } @@ -160,8 +221,8 @@ */ - (void)windowDidLoad { - [_document windowControllerDidLoadNib:self]; - + [_document windowControllerDidLoadCib:self]; + [self synchronizeWindowTitleWithDocumentName]; } @@ -170,7 +231,7 @@ */ - (void)windowWillLoad { - [_document windowControllerWillLoadNib:self]; + [_document windowControllerWillLoadCib:self]; } /*! @@ -179,17 +240,17 @@ */ - (void)setDocument:(CPDocument)aDocument { - if (_document == aDocument) + if (_document === aDocument) return; - + var defaultCenter = [CPNotificationCenter defaultCenter]; - + if (_document) { [defaultCenter removeObserver:self name:CPDocumentWillSaveNotification object:_document]; - + [defaultCenter removeObserver:self name:CPDocumentDidSaveNotification object:_document]; @@ -198,16 +259,16 @@ name:CPDocumentDidFailToSaveNotification object:_document]; } - + _document = aDocument; - + if (_document) { [defaultCenter addObserver:self selector:@selector(_documentWillSave:) name:CPDocumentWillSaveNotification object:_document]; - + [defaultCenter addObserver:self selector:@selector(_documentDidSave:) name:CPDocumentDidSaveNotification @@ -217,10 +278,10 @@ selector:@selector(_documentDidFailToSave:) name:CPDocumentDidFailToSaveNotification object:_document]; - + [self setDocumentEdited:[_document isDocumentEdited]]; - } - + } + [self synchronizeWindowTitleWithDocumentName]; } @@ -259,6 +320,42 @@ [[self window] setDocumentEdited:isEdited]; } +- (void)close +{ + [[self window] close]; +} + +- (void)setShouldCloseDocument:(BOOL)shouldCloseDocument +{ + _shouldCloseDocument = shouldCloseDocument; +} + +- (BOOL)shouldCloseDocument +{ + return _shouldCloseDocument; +} + +- (id)owner +{ + return _cibOwner; +} + +- (CPString)windowCibName +{ + if (_windowCibName) + return _windowCibName; + + return [[_windowCibPath lastPathComponent] stringByDeletingPathExtension]; +} + +- (CPString)windowCibPath +{ + if (_windowCibPath) + return _windowCibPath; + + return [[CPBundle bundleForClass:[_cibOwner class]] pathForResource:_windowCibName + @".cib"]; +} + // Setting and Getting Window Attributes /*! @@ -268,7 +365,7 @@ { if (!_document || !_window) return; - + // [_window setRepresentedFilename:]; [_window setTitle:[self windowTitleForDocumentDisplayName:[_document displayName]]]; } From 5bc92b686b4fae706bc12b8bb96b8ba2a30e1fb8 Mon Sep 17 00:00:00 2001 From: Francisco Ryan Tolmasky I Date: Mon, 27 Jul 2009 18:42:04 -0700 Subject: [PATCH 36/53] Slight fix to new CPWindowController mechanics. Reviewed by me. --- AppKit/CPWindowController.j | 3 +++ 1 file changed, 3 insertions(+) diff --git a/AppKit/CPWindowController.j b/AppKit/CPWindowController.j index 8ee836374..f60abcfe2 100644 --- a/AppKit/CPWindowController.j +++ b/AppKit/CPWindowController.j @@ -74,6 +74,9 @@ [self setShouldCloseDocument:NO]; [self setNextResponder:CPApp]; + + if (aWindow) + [self windowDidLoad]; } return self; From b5e84342ac0c602aa0a500a6e0dd09bab45d79a9 Mon Sep 17 00:00:00 2001 From: Ross Boucher Date: Mon, 27 Jul 2009 18:43:46 -0700 Subject: [PATCH 37/53] Fix for documentation error. Closes #208. --- AppKit/CPImage.j | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/AppKit/CPImage.j b/AppKit/CPImage.j index 4962912bf..94e1eb533 100644 --- a/AppKit/CPImage.j +++ b/AppKit/CPImage.j @@ -187,9 +187,9 @@ function CPImageInBundle(aFilename, aSize, aBundle) } /*! - Returns YES if the image data has already been loaded. + Returns the load status, which will be CPImageLoadStatusCompleted if the image data has already been loaded. */ -- (BOOL)loadStatus +- (unsigned)loadStatus { return _loadStatus; } From b50067e39eff167a8e30accdcfd17c288d5d170b Mon Sep 17 00:00:00 2001 From: Ross Boucher Date: Mon, 27 Jul 2009 22:41:47 -0700 Subject: [PATCH 38/53] Add a trim function to CPString. --- Foundation/CPString.j | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/Foundation/CPString.j b/Foundation/CPString.j index 9f3cb1930..a12dd2236 100644 --- a/Foundation/CPString.j +++ b/Foundation/CPString.j @@ -62,7 +62,8 @@ var CPStringRegexSpecialCharacters = [ '/', '.', '*', '+', '?', '|', '$', '^', '(', ')', '[', ']', '{', '}', '\\' ], - CPStringRegexEscapeExpression = new RegExp("(\\" + CPStringRegexSpecialCharacters.join("|\\") + ")", 'g'); + CPStringRegexEscapeExpression = new RegExp("(\\" + CPStringRegexSpecialCharacters.join("|\\") + ")", 'g'), + CPStringRegexTrimWhitespace = new RegExp("(^\\s+|\\s+$)", 'g'); /*! @class CPString @@ -421,6 +422,13 @@ var CPStringRegexSpecialCharacters = [ return '' + substring(0, range.location) + replacement + substring(range.location + range.length, self.length); } +/*! + Returns a new string with leading and trailing whitespace trimmed +*/ +- (CPString)stringByTrimmingWhitespace +{ + return self.replace(CPStringRegexTrimWhitespace, ""); +} // Identifying and comparing strings From 6a9804939e038ae8b72fe656505dd789c4154e65 Mon Sep 17 00:00:00 2001 From: Francisco Ryan Tolmasky I Date: Mon, 27 Jul 2009 22:43:01 -0700 Subject: [PATCH 39/53] More removal of "bridge". Reviewed by me. --- AppKit/CPWindow/CPWindow.j | 153 ++++++++++++--------- AppKit/Platform/CPPlatformWindow.j | 9 ++ AppKit/Platform/DOM/CPPlatformWindow+DOM.j | 2 +- 3 files changed, 96 insertions(+), 68 deletions(-) diff --git a/AppKit/CPWindow/CPWindow.j b/AppKit/CPWindow/CPWindow.j index 86a9f5dff..c7c7f8f35 100644 --- a/AppKit/CPWindow/CPWindow.j +++ b/AppKit/CPWindow/CPWindow.j @@ -236,69 +236,69 @@ var CPWindowSaveImage = nil, */ @implementation CPWindow : CPResponder { - CPPlatformWindow _platformWindow; + CPPlatformWindow _platformWindow; - int _windowNumber; - unsigned _styleMask; - CGRect _frame; - int _level; - BOOL _isVisible; - BOOL _isAnimating; - BOOL _hasShadow; - BOOL _isMovableByWindowBackground; + int _windowNumber; + unsigned _styleMask; + CGRect _frame; + int _level; + BOOL _isVisible; + BOOL _isAnimating; + BOOL _hasShadow; + BOOL _isMovableByWindowBackground; - BOOL _isDocumentEdited; - BOOL _isDocumentSaving; + BOOL _isDocumentEdited; + BOOL _isDocumentSaving; - CPImageView _shadowView; + CPImageView _shadowView; - CPView _windowView; - CPView _contentView; - CPView _toolbarView; + CPView _windowView; + CPView _contentView; + CPView _toolbarView; - CPArray _mouseEnteredStack; - CPView _leftMouseDownView; - CPView _rightMouseDownView; + CPArray _mouseEnteredStack; + CPView _leftMouseDownView; + CPView _rightMouseDownView; - CPToolbar _toolbar; - CPResponder _firstResponder; - CPResponder _initialFirstResponder; - id _delegate; + CPToolbar _toolbar; + CPResponder _firstResponder; + CPResponder _initialFirstResponder; + id _delegate; - CPString _title; + CPString _title; - BOOL _acceptsMouseMovedEvents; - BOOL _ignoresMouseEvents; + BOOL _acceptsMouseMovedEvents; + BOOL _ignoresMouseEvents; - CPWindowController _windowController; + CPWindowController _windowController; - CGSize _minSize; - CGSize _maxSize; + CGSize _minSize; + CGSize _maxSize; - CPUndoManager _undoManager; - CPURL _representedURL; + CPUndoManager _undoManager; + CPURL _representedURL; - CPSet _registeredDraggedTypes; - CPArray _registeredDraggedTypesArray; - CPCountedSet _inclusiveRegisteredDraggedTypes; + CPSet _registeredDraggedTypes; + CPArray _registeredDraggedTypesArray; + CPCountedSet _inclusiveRegisteredDraggedTypes; - CPButton _defaultButton; - BOOL _defaultButtonEnabled; + CPButton _defaultButton; + BOOL _defaultButtonEnabled; - BOOL _autorecalculatesKeyViewLoop; - BOOL _keyViewLoopIsDirty; + BOOL _autorecalculatesKeyViewLoop; + BOOL _keyViewLoopIsDirty; // Bridge Support #if PLATFORM(DOM) - DOMElement _DOMElement; + DOMElement _DOMElement; #endif - unsigned _autoresizingMask; + unsigned _autoresizingMask; - BOOL _delegateRespondsToWindowWillReturnUndoManagerSelector; + BOOL _delegateRespondsToWindowWillReturnUndoManagerSelector; - BOOL _isFullBridge; - _CPWindowFullBridgeSession _fullBridgeSession; + BOOL _isFullPlatformWindow; + _CPWindowFullPlatformWindowSession _fullPlatformWindowSession; } /* @@ -338,7 +338,7 @@ CPTexturedBackgroundWindowMask { [self setPlatformWindow:[CPPlatformWindow primaryPlatformWindow]]; - _isFullBridge = NO; + _isFullPlatformWindow = NO; _registeredDraggedTypes = [CPSet set]; _registeredDraggedTypesArray = []; @@ -375,7 +375,9 @@ CPTexturedBackgroundWindowMask _DOMElement.style.visibility = "visible"; _DOMElement.style.zIndex = 0; +#if 0 CPDOMDisplayServerSetStyleLeftTop(_DOMElement, NULL, _CGRectGetMinX(_frame), _CGRectGetMinY(_frame)); +#endif CPDOMDisplayServerSetStyleSize(_DOMElement, 1, 1); CPDOMDisplayServerAppendChild(_DOMElement, _windowView._DOMElement); @@ -386,7 +388,7 @@ CPTexturedBackgroundWindowMask [self setHasShadow:aStyleMask !== CPBorderlessWindowMask]; if (aStyleMask & CPBorderlessBridgeWindowMask) - [self setFullBridge:YES]; + [self setFullPlatformWindow:YES]; _defaultButtonEnabled = YES; _keyViewLoopIsDirty = YES; @@ -420,7 +422,7 @@ CPTexturedBackgroundWindowMask return _CPStandardWindowView; } -+ (Class)_windowViewClassForFullBridgeStyleMask:(unsigned)aStyleMask ++ (Class)_windowViewClassForFullPlatformWindowStyleMask:(unsigned)aStyleMask { return _CPBorderlessBridgeWindowView; } @@ -470,21 +472,24 @@ CPTexturedBackgroundWindowMask #endif } -- (void)setFullBridge:(BOOL)shouldBeFullBridge +- (void)setFullPlatformWindow:(BOOL)shouldBeFullPlatformWindow { - shouldBeFullBridge = !!shouldBeFullBridge; - - if (_isFullBridge === shouldBeFullBridge) + if (![_platformWindow supportsFullPlatformWindows]) return; - _isFullBridge = shouldBeFullBridge; + shouldBeFullPlatformWindow = !!shouldBeFullPlatformWindow; - if (_isFullBridge) + if (_isFullPlatformWindow === shouldBeFullPlatformWindow) + return; + + _isFullPlatformWindow = shouldBeFullPlatformWindow; + + if (_isFullPlatformWindow) { - _fullBridgeSession = _CPWindowFullBridgeSessionMake(_windowView, [self contentRectForFrameRect:[self frame]], [self hasShadow], [self level]); + _fullPlatformWindowSession = _CPWindowFullPlatformWindowSessionMake(_windowView, [self contentRectForFrameRect:[self frame]], [self hasShadow], [self level]); - var fullBridgeWindowViewClass = [[self class] _windowViewClassForFullBridgeStyleMask:_styleMask], - windowView = [[fullBridgeWindowViewClass alloc] initWithFrame:CGRectMakeZero() styleMask:_styleMask]; + var fullPlatformWindowViewClass = [[self class] _windowViewClassForFullPlatformWindowStyleMask:_styleMask], + windowView = [[fullPlatformWindowViewClass alloc] initWithFrame:CGRectMakeZero() styleMask:_styleMask]; [self _setWindowView:windowView]; @@ -495,21 +500,21 @@ CPTexturedBackgroundWindowMask } else { - var windowView = _fullBridgeSession.windowView; + var windowView = _fullPlatformWindowSession.windowView; [self _setWindowView:windowView]; - [self setLevel:_fullBridgeSession.level]; - [self setHasShadow:_fullBridgeSession.hasShadow]; + [self setLevel:_fullPlatformWindowSession.level]; + [self setHasShadow:_fullPlatformWindowSession.hasShadow]; [self setAutoresizingMask:CPWindowNotSizable]; - [self setFrame:[windowView frameRectForContentRect:_fullBridgeSession.contentRect]]; + [self setFrame:[windowView frameRectForContentRect:_fullPlatformWindowSession.contentRect]]; } } -- (BOOL)isFullBridge +- (BOOL)isFullPlatformWindow { - return _isFullBridge; + return _isFullPlatformWindow; } /*! @@ -601,7 +606,7 @@ CPTexturedBackgroundWindowMask origin.x = anOrigin.x; origin.y = anOrigin.y; - + #if PLATFORM(DOM) CPDOMDisplayServerSetStyleLeftTop(_DOMElement, NULL, origin.x, origin.y); #endif @@ -621,9 +626,9 @@ CPTexturedBackgroundWindowMask return; _frame.size = aSize; - + [_windowView setFrameSize:aSize]; - + if (_hasShadow) [_shadowView setFrameSize:_CGSizeMake(SHADOW_MARGIN_LEFT + aSize.width + SHADOW_MARGIN_RIGHT, SHADOW_MARGIN_BOTTOM + aSize.height + SHADOW_MARGIN_TOP + SHADOW_DISTANCE)]; @@ -1628,7 +1633,7 @@ CPTexturedBackgroundWindowMask [_windowView noteToolbarChanged]; - if (_isFullBridge) + if (_isFullPlatformWindow) newFrame = [_platformWindow usableContentFrame]; else { @@ -1920,9 +1925,9 @@ var keyViewComparator = function(a, b, context) /* @ignore */ -- (void)resizeWithOldBridgeSize:(CGSize)aSize +- (void)resizeWithOldPlatformWindowSize:(CGSize)aSize { - if ([self isFullBridge]) + if ([self isFullPlatformWindow]) return [self setFrame:[_platformWindow usableContentFrame]]; if (_autoresizingMask == CPWindowNotSizable) @@ -2024,6 +2029,20 @@ var keyViewComparator = function(a, b, context) @end +@implementation CPWindow (Deprecated) + +- (void)setFullBridge:(BOOL)shouldBeFullBridge +{ + [self setFullPlatformWindow:shouldBeFullBridge]; +} + +- (BOOL)isFullBridge +{ + return [self isFullPlatformWindow]; +} + +@end + var interpolate = function(fromValue, toValue, progress) { return fromValue + (toValue - fromValue) * progress; @@ -2075,7 +2094,7 @@ var interpolate = function(fromValue, toValue, progress) @end -function _CPWindowFullBridgeSessionMake(aWindowView, aContentRect, hasShadow, aLevel) +function _CPWindowFullPlatformWindowSessionMake(aWindowView, aContentRect, hasShadow, aLevel) { return { windowView:aWindowView, contentRect:aContentRect, hasShadow:hasShadow, level:aLevel }; } diff --git a/AppKit/Platform/CPPlatformWindow.j b/AppKit/Platform/CPPlatformWindow.j index 1aec29a90..8a6bd2ea5 100644 --- a/AppKit/Platform/CPPlatformWindow.j +++ b/AppKit/Platform/CPPlatformWindow.j @@ -161,6 +161,15 @@ var PrimaryPlatformWindow = NULL; } */ +- (BOOL)supportsFullPlatformWindows +{ +#if PLATFORM(BROWSER) + return YES; +#else + return NO; +#endif +} + @end #if PLATFORM(BROWSER) diff --git a/AppKit/Platform/DOM/CPPlatformWindow+DOM.j b/AppKit/Platform/DOM/CPPlatformWindow+DOM.j index 4630ae210..0730971c4 100644 --- a/AppKit/Platform/DOM/CPPlatformWindow+DOM.j +++ b/AppKit/Platform/DOM/CPPlatformWindow+DOM.j @@ -558,7 +558,7 @@ var CTRL_KEY_CODE = 17; windowCount = windows.length; while (windowCount--) - [windows[windowCount] resizeWithOldBridgeSize:oldSize]; + [windows[windowCount] resizeWithOldPlatformWindowSize:oldSize]; } //window.liveResize = NO; From bbda6e6e77e6d694eaa7c779cb5c8232311d29bc Mon Sep 17 00:00:00 2001 From: Ross Boucher Date: Mon, 27 Jul 2009 23:28:10 -0700 Subject: [PATCH 40/53] Added the images for CPSearchField. Closes #205. --- .../CPSearchField/CPSearchFieldCancel.png | Bin 0 -> 956 bytes .../CPSearchField/CPSearchFieldCancelPressed.png | Bin 0 -> 976 bytes .../Resources/CPSearchField/CPSearchFieldFind.png | Bin 0 -> 958 bytes .../CPSearchField/CPSearchFieldSearch.png | Bin 0 -> 938 bytes 4 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 AppKit/Resources/CPSearchField/CPSearchFieldCancel.png create mode 100644 AppKit/Resources/CPSearchField/CPSearchFieldCancelPressed.png create mode 100644 AppKit/Resources/CPSearchField/CPSearchFieldFind.png create mode 100644 AppKit/Resources/CPSearchField/CPSearchFieldSearch.png diff --git a/AppKit/Resources/CPSearchField/CPSearchFieldCancel.png b/AppKit/Resources/CPSearchField/CPSearchFieldCancel.png new file mode 100644 index 0000000000000000000000000000000000000000..fc32eabb36e7a94ebbf753b53e14a5442009e98f GIT binary patch literal 956 zcmV;t14I0YP)4Tx0C)kdlEF(GK@`TnO%N4}m7<>aAYvi5Yu12XBt~tK<`80vReFiDYZ7qR zWp|AV9{d|T2!&E873rn)Xz3}?OMCDjVr$#~Lcxp3_M08j^w8kN2XFT`-+uFE=FI}h zeA)BX5&#@G^ovh(`irGyz4IqD^x-}R@VG1jZ@N&()6yoczSGS(9hJ4(nA*v`J{JVE z6b=0q#aYQKic69=LocMKDp^#^7I}x9@=L`T@_TY`Me!%eD~i8Lu8WGCdrmf7tL6fU zF7kwB2ZEd>3o8%~`GEY=an@NsNyLcoe9lddkcVVnqzKe6fT=h1@3pk0kHCiK{E~oVz0Ui5Mbh!w0J_K%lMA7w86x|$h?O#CSN^JP` z*vo@x$K3EOV|8X#9XR0`81WtbpH*LCmjS$M0Ne_m?EBPZTzIBOfcr#L$Jyl1=57x?aD=2!hE#U@+!>|B%WVD7J{7S5NNI&v6; zfi%-Z28-&h`4!_6?EM+xTjNXptyKPv(B6uBIJ53;`?X3n)TjBU+bMnC6^~MS+At>Z z2Vfh63TsRr3;+NC32;bRa{vGf6951U69E94oEQKA0fk9KK~y*q?Nm!j#6S>@9|i?c z{OtUJieA72=weL3iAScBOEXFxSsFo0!2tX-e1TzE)@7l{pW3ZZ#-z)G$V-9K zx9guT%EB?BgVhd?SE`O51lVz%IF4V^G`+TM`$mX--@i+e zJa*kK*i126oEP)4Tx0C)kdlFv&UK@`Woo3t3QNR6%MJ&2?b%bGP1FC{;qMeHHO6l-sB@)O*3 z*=(W(5B?1v1VIX=MZAbdi>H8>_TZt2t*!nQ3SLCk@9YrLLqjipFwAG(eCN%3Zw3g* zN{+J}0$|ymTX>b#-!8t>2Yw-p5sV^=nUZKanSA~=C4KDX2Q;~LIw@oI5%qHqySxz4 z;uJioDNajXQe2e0>Ny@Yb;+V$DwEgAakp5=k@v{MHN{^fFDd>ixh-n)>^a%6%MBX{ zMaZdgr76g1vM4u&MgB}qS=I{Uhc3x6;kY~-en1|Vec?=NUjZ*ZP_xWky z&o?p6bd$i*cF%Wx9`s5Zi!`fdA_%7q9Rd%xeE)g@7RndkhNBUW`^7P^cqreGk!VIqkI^^V-dbc%gF zBYf)|w?9hHpXOE8g8t-IocC^{R`>J_e{m(Q&)VX7Tu&Ir4DJEBm3{0~5vi4t#sg&dixi{>d?n zk^Qv-jUf+MKztP}gE_$bCvXd5@CZa3RCp67955@MG>jMc&%n79AD5i)ZGc^1f_~OS zzyj}}*7=xlim$%~rWk9t+lyRv(|pWfF3tK@eP5RfY(mpL7EgRBKVa$UV)!dOt7b9e=^U1ezQk3+RJlar(kA z%)b)ky#ng{1}f{Ple!@Jw_Ifx8+~Y>a2@aoP3+B3KVH=uTv;TzdMDew*Q9gMsL1zczV0000P000&U1^@s6HNQ8u0005cX+uL$Nkc;* zP;zf(X>4Tx0C)kdlFv&UK@`Woo3t3QNR6%MJ&2?b%bGP1FC{;qMeHHO6l-sB@)O*3 z*=(W(5B?1v1VIX=MZAbdi>H8>_TZt2t*!nQ3SLCk@9YrLLqjipFwAG(eCN%3Zw3g* zN{+J}0$|ymTX>b#-!8t>2Yw-p5sV^=nUZKanSA~=C4KDX2Q;~LIw@oI5%qHqySxz4 z;uJioDNajXQe2e0>Ny@Yb;+V$DwEgAakp5=k@v{MHN{^fFDd>ixh-n)>^a%6%MBX{ zMaZdgr76g1vM4u&MgB}qS=I{Uhc3x6;kY~-en1|Vec?=NUjZ*ZP_xWky z&o?p6bd$i*cF%Wx9`s5Zi!`fdA_%7q9Rd%xeE)g@7RndkhNBUW`^7P^cqreGk!VIqkI^^V-dbc%gF zBYf)|w?9hHpXOE8g8t-IocC^{R`>J_e{m(Q&)VX7Tu&Ir4DJEBm3{0?N`=nC;`jZ_f z$Wpa?JZeFAYgav=2cVil7kGGd#f*%)krelmX(@i*XpPVGgEYAz0Tj zw!<+TKu#6McvwX@xMyHbd{_)&zz%jbX6Q4z@*gf~Ss3o7&C{Z-ERL^_yhxB!x&sZs5T}a z61WjpiFO0;!5J8^3QXk3I1klO56!R)_n=NP!^d9(B*_z(Ln(x(e_-wbOfm{JunXhh zD~wfAB|7{5J)zH6u7c6m<$4`j!HTxv2)z>%07*qoM6N<$f_iwhwEzGB literal 0 HcmV?d00001 diff --git a/AppKit/Resources/CPSearchField/CPSearchFieldSearch.png b/AppKit/Resources/CPSearchField/CPSearchFieldSearch.png new file mode 100644 index 0000000000000000000000000000000000000000..77434b8a2085c5acbb0550b101eb53945dc405f3 GIT binary patch literal 938 zcmV;b16BNqP)P000&U1^@s6HNQ8u0005qX+uL$Nkc;* zP;zf(X>4Tx0C)kdlEF(GK@`TnO%N4}m7<>aAYvi5Yu12XBt~tK<`80vReFiDYZ7qR zWp|AV9{d|T2!&E873rn)Xz3}?OMCDjVr$#~Lcxp3_M08j^w8kN2XFT`-+uFE=FI}h zeA)BX5&#@G^ovh(`irGyz4IqD^x-}R@VG1jZ@N&()6yoczSGS(9hJ4(nA*v`J{JVE z6b=0q#aYQKic69=LocMKDp^#^7I}x9@=L`T@_TY`Me!%eD~i8Lu8WGCdrmf7tL6fU zF7kwB2ZEd>3o8%~`GEY=an@NsNyLcoe9lddkcVVnqzKe6fT=h1@3pk0kHCiK{E~oVz0Ui5Mbh!w0J_K%lMA7w86x|$h?O#CSN^JP` z*vo@x$K3EOV|8X#9XR0`81WtbpH*LCmjS$M0Ne_m?EBPZTzIBOfcr#L$Jyl1=57x?aD=2!hE#U@+!>|B%WVD7J{7S5NNI&v6; zfi%-Z28-&h`4!_6?EM+xTjNXptyKPv(B6uBIJ53;`?X3n)TjBU+bMnC6^~MS+At>Z z2Vfh63TsRr3;+NC32;bRa{vGf6951U69E94oEQKA0dq-2K~zW$?UPF@MNt@rk4thd z5;2vc6a&SS!c6%Cet|zCKSuZi2Fj&OOcde_)EUbych8fx>ZrB%KAp&bx1RH@z1FwB zwcc;U>4@U^&L2a=#pVtshjAo6a0J^z!upu<)u8-ePvjKYsgi~i8r%o87yGIZg9?< z??EpN!5AFDBV;P&Bqnw#71gG*QkTbfkLNles{Mg4sJQ{IJf{G3mC z9*03VhYEbFbfv>#n1^=A>k7;D$)YXL2C2V7eN{7d{fL8%vwnH{1A&xA#t!r~1poj5 M07*qoM6N<$g1!c_9RL6T literal 0 HcmV?d00001 From fbf559043e9278bf73074bf1253710424ee319f5 Mon Sep 17 00:00:00 2001 From: Francisco Ryan Tolmasky I Date: Tue, 28 Jul 2009 21:10:16 -0700 Subject: [PATCH 41/53] Fixed accidentally committed #if 0. Reviewed by me. --- AppKit/CPWindow/CPWindow.j | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/AppKit/CPWindow/CPWindow.j b/AppKit/CPWindow/CPWindow.j index c7c7f8f35..65976f471 100644 --- a/AppKit/CPWindow/CPWindow.j +++ b/AppKit/CPWindow/CPWindow.j @@ -374,10 +374,8 @@ CPTexturedBackgroundWindowMask _DOMElement.style.position = "absolute"; _DOMElement.style.visibility = "visible"; _DOMElement.style.zIndex = 0; - -#if 0 + CPDOMDisplayServerSetStyleLeftTop(_DOMElement, NULL, _CGRectGetMinX(_frame), _CGRectGetMinY(_frame)); -#endif CPDOMDisplayServerSetStyleSize(_DOMElement, 1, 1); CPDOMDisplayServerAppendChild(_DOMElement, _windowView._DOMElement); From 856373adecc9f3b02b7b55edbc1309a8f889b6fb Mon Sep 17 00:00:00 2001 From: Tom Robinson Date: Wed, 29 Jul 2009 18:57:18 -0700 Subject: [PATCH 42/53] Added status code checks to abort Rake early. --- AppKit/Rakefile | 1 + Objective-J/Rakefile | 4 +--- Rakefile | 7 +++++++ Tools/Rake/lib/objective-j/bundletask.rb | 3 +++ Tools/capp/Templates/ThemeDescriptor/Rakefile | 1 + common.rb | 5 +++-- 6 files changed, 16 insertions(+), 5 deletions(-) diff --git a/AppKit/Rakefile b/AppKit/Rakefile index f4f3d30cc..a93beb55c 100644 --- a/AppKit/Rakefile +++ b/AppKit/Rakefile @@ -53,6 +53,7 @@ file_d $THEME_PRODUCT => ThemeFiles << $ENVIRONMENT_PRODUCT do puts str end end + rake abort if ($? != 0) end task :build => [:build_subprojects, :AppKit, $ENVIRONMENT_PRODUCT, $THEME_PRODUCT, $ENVIRONMENT_THEME_PRODUCT] diff --git a/Objective-J/Rakefile b/Objective-J/Rakefile index f0f1782ac..dca4d0725 100644 --- a/Objective-J/Rakefile +++ b/Objective-J/Rakefile @@ -55,9 +55,7 @@ def platform_flags(*platforms) end def build_product(path, flags) - IO.popen("gcc #{flags} -E -x c -P -", "w+") do |preprocessor| - Files.select { |name| name.match(/\.js$/) }.each do |fileName| preprocessor.puts IO.read(fileName) end @@ -67,8 +65,8 @@ def build_product(path, flags) File.open(path, "w") do |file| file.write(IO.read("header.txt") + preprocessor.read) end - end + rake abort if ($? != 0) end task :build => [:Products, $ENVIRONMENT_PRODUCT, :build_subprojects] diff --git a/Rakefile b/Rakefile index 4f0a3da62..e06fdf743 100644 --- a/Rakefile +++ b/Rakefile @@ -86,7 +86,9 @@ file_d $STARTER_DOWNLOAD_APPLICATION => [$TOOLS_DOWNLOAD_ENV] do rm_rf($STARTER_DOWNLOAD_APPLICATION) mkdir_p($STARTER_DOWNLOAD) + system %{capp gen #{$STARTER_DOWNLOAD_APPLICATION} -t Application --noconfig } + rake abort if ($? != 0) # No tools means no objective-j gem rm(File.join($STARTER_DOWNLOAD_APPLICATION, 'Rakefile')) @@ -103,7 +105,9 @@ task :install => [:tools_download] do else prefix = '' end + system %{cd #{$TOOLS_DOWNLOAD} && sudo sh ./install-tools #{prefix} } + rake abort if ($? != 0) end task :test => [:build] do @@ -122,6 +126,8 @@ end task :docs do if executable_exists? "doxygen" system %{doxygen #{$DOXYGEN_CONFIG} } + rake abort if ($? != 0) + rm_rf $DOCUMENTATION_BUILD mv "debug.txt", "Documentation" mv "Documentation", $DOCUMENTATION_BUILD @@ -133,6 +139,7 @@ end task :submodules do if executable_exists? "git" system %{git submodule init && git submodule update} + rake abort if ($? != 0) else puts "Git not installed" rake abort diff --git a/Tools/Rake/lib/objective-j/bundletask.rb b/Tools/Rake/lib/objective-j/bundletask.rb index eeee33003..5fe26e939 100644 --- a/Tools/Rake/lib/objective-j/bundletask.rb +++ b/Tools/Rake/lib/objective-j/bundletask.rb @@ -390,6 +390,7 @@ module ObjectiveJ puts str end end + rake abort if ($? != 0) end { 'copy' => include_nibs, 'copied_resources' => [copied_resource] } @@ -424,6 +425,7 @@ module ObjectiveJ puts str end end + rake abort if ($? != 0) end enhance([frameworks_path]) @@ -510,6 +512,7 @@ module ObjectiveJ puts str end end + rake abort if ($? != 0) end BundleTask.compact(build_path) if needs_compact diff --git a/Tools/capp/Templates/ThemeDescriptor/Rakefile b/Tools/capp/Templates/ThemeDescriptor/Rakefile index c88a1aeae..9421af8e1 100644 --- a/Tools/capp/Templates/ThemeDescriptor/Rakefile +++ b/Tools/capp/Templates/ThemeDescriptor/Rakefile @@ -16,6 +16,7 @@ file_d $BLEND_PRODUCT => ['ThemeDescriptors.j'] do puts str end end + rake abort if ($? != 0) end task :default => [$BLEND_PRODUCT] diff --git a/common.rb b/common.rb index 1ae320f40..eeb3ac534 100644 --- a/common.rb +++ b/common.rb @@ -77,8 +77,8 @@ end def subrake(directories, task_name) directories.each do |directory| if (File.directory?(directory) && File.file?(File.join(directory, "Rakefile"))) - ok = system(%{cd #{directory} && #{$serialized_env} #{$0} #{task_name}}) - rake abort unless ok + system(%{cd #{directory} && #{$serialized_env} #{$0} #{task_name}}) + rake abort if ($? != 0) else puts "warning: subrake missing: " + directory +" (this is not necessarily an error, "+directory+" may be optional)" end @@ -147,4 +147,5 @@ task :clobberall => ['clobber-all'] def spawn_rake(task_name) system %{#{$serialized_env} #{$0} #{task_name}} + rake abort if ($? != 0) end From 0876653ae3fe9016ef950fd640bb0a1762bf82c1 Mon Sep 17 00:00:00 2001 From: Francisco Ryan Tolmasky I Date: Wed, 29 Jul 2009 19:06:06 -0700 Subject: [PATCH 43/53] Only include debug.js in DEBUG mode for Objective-J. Reviewed by me. --- Objective-J/Rakefile | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/Objective-J/Rakefile b/Objective-J/Rakefile index f0f1782ac..c57bb8edc 100644 --- a/Objective-J/Rakefile +++ b/Objective-J/Rakefile @@ -17,18 +17,11 @@ $RHINO_FILE = File.join($PRODUCT, 'rhino.platform', 'Objective-J.js' task :Products => [$BROWSER_FILE, $RHINO_FILE, $LICENSE_PRODUCT] -Files = [ 'constants.js', - 'utilities.js', - 'json2.js', - 'runtime.js', - 'dictionary.js', - 'plist.js', - 'file.js', - 'exception.js', - 'preprocess.js', - 'evaluate.js', - 'debug.js', - 'bootstrap.js']; +Files = FileList['constants.js', 'utilities.js', 'json2.js', 'runtime.js', 'dictionary.js', 'plist.js', 'file.js', 'exception.js', 'preprocess.js', 'evaluate.js', 'bootstrap.js'] + +if $CONFIGURATION == 'Debug' + Files.add('debug.js') +end file_d $BROWSER_FILE => Files do |t| build_product(t.name, platform_flags(ObjectiveJ::Platform::Browser, ObjectiveJ::Platform::ObjJ)) From 2bb6da51327d27dd51d1b30c53729cd1e5761ddb Mon Sep 17 00:00:00 2001 From: Tom Robinson Date: Wed, 29 Jul 2009 19:21:17 -0700 Subject: [PATCH 44/53] Undoing this so Ross stops complaining. --- Tools/Rake/lib/objective-j/bundletask.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tools/Rake/lib/objective-j/bundletask.rb b/Tools/Rake/lib/objective-j/bundletask.rb index 5fe26e939..95b77e138 100644 --- a/Tools/Rake/lib/objective-j/bundletask.rb +++ b/Tools/Rake/lib/objective-j/bundletask.rb @@ -390,7 +390,7 @@ module ObjectiveJ puts str end end - rake abort if ($? != 0) + #rake abort if ($? != 0) end { 'copy' => include_nibs, 'copied_resources' => [copied_resource] } From 3b8664e6ff977308ef67769de873f5ab27fa993c Mon Sep 17 00:00:00 2001 From: Tom Robinson Date: Wed, 29 Jul 2009 19:23:32 -0700 Subject: [PATCH 45/53] Disable typechecking by default --- Objective-J/debug.js | 107 -------------------------------------- Objective-J/preprocess.js | 8 ++- 2 files changed, 6 insertions(+), 109 deletions(-) diff --git a/Objective-J/debug.js b/Objective-J/debug.js index fddd7fed7..bd23ab7ae 100644 --- a/Objective-J/debug.js +++ b/Objective-J/debug.js @@ -182,110 +182,3 @@ function objj_debug_typecheck(expectedType, object) throw ("expected=" + expectedType + ", actual=" + actualType); } - -// profile decorator -/* -function objj_debug_profile(msgSend) -{ - return function(aReceiverOrSuper, aSelector) - { - var aReceiver = aReceiverOrSuper && (aReceiverOrSuper.receiver || aReceiverOrSuper); - - // profiling book keeping - var profileRecord = { - parent : objj_debug_profile, - receiver : aReceiver && GETMETA(aReceiver).name, - selector : aSelector, - calls : [] - } - objj_debug_profile.calls.push(profileRecord); - objj_debug_profile = profileRecord; - profileRecord.start = new Date(); - - try - { - return msgSend.apply(null, arguments); - } - finally - { - profileRecord.end = new Date(); - objj_debug_profile = profileRecord.parent; - } - } -} - -// FIXME: This could be much better. -var objj_debug_backtrace; - -function objj_backtrace_set_enabled(enabled) -{ - if (enabled) - { - objj_debug_backtrace = []; - objj_msgSend = objj_msgSend_Backtrace; - objj_msgSendSuper = objj_msgSendSuper_Backtrace; - } - else - { - objj_msgSend = objj_msgSend_Standard; - objj_msgSendSuper = objj_msgSendSuper_Standard; - } -} - -function objj_debug_print_backtrace() -{ - alert(objj_debug_backtrace_string()); -} - -function objj_debug_backtrace_string() -{ - return objj_debug_backtrace ? objj_debug_backtrace.join("\n") : ""; -} - -var objj_debug_profile = null, - objj_currently_profiling = false, - objj_profile_cleanup; - -function objj_profile(title) -{ - if (objj_currently_profiling) - return; - - var objj_msgSend_profile_saved = objj_msgSend, - objj_msgSendSuper_profile_saved = objj_msgSendSuper; - - objj_msgSend = objj_msgSend_Profile; - objj_msgSendSuper = objj_msgSendSuper_Profile; - - var root = { calls: [] }; - objj_debug_profile = root; - - var context = { - start : new Date(), - title : title, - profile : root - }; - - objj_profile_cleanup = function() { - objj_msgSend = objj_msgSend_profile_saved; - objj_msgSendSuper = objj_msgSendSuper_profile_saved; - context.end = new Date(); - return context; - } - - objj_currently_profiling = true; -} - -function objj_profileEnd() -{ - if (!objj_currently_profiling) - return; - - objj_debug_profile = null; - objj_currently_profiling = false; - - return objj_profile_cleanup(); -} -*/ - -objj_msgSend_set_decorators(objj_typecheck_decorator, objj_backtrace_decorator); diff --git a/Objective-J/preprocess.js b/Objective-J/preprocess.js index 0dd3cc93f..07de33827 100644 --- a/Objective-J/preprocess.js +++ b/Objective-J/preprocess.js @@ -20,7 +20,8 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -var OBJJ_PREPROCESSOR_DEBUG_SYMBOLS = 1 << 0; +var OBJJ_PREPROCESSOR_DEBUG_SYMBOLS = 1 << 0, + OBJJ_PREPROCESSOR_TYPE_SIGNATURES = 1 << 1; function objj_preprocess(/*String*/ aString, /*objj_bundle*/ aBundle, /*objj_file*/ aSourceFile, /*unsigned*/ flags) { @@ -669,7 +670,10 @@ objj_preprocessor.prototype.method = function(tokens) CONCAT(buffer, ")\n{ with(self)\n{"); CONCAT(buffer, this.preprocess(tokens, NULL, TOKEN_CLOSE_BRACE, TOKEN_OPEN_BRACE)); - CONCAT(buffer, "}\n},"+JSON.stringify(types)+")"); + CONCAT(buffer, "}\n}"); + if (this._flags & OBJJ_PREPROCESSOR_TYPE_SIGNATURES) + CONCAT(buffer, ","+JSON.stringify(types)); + CONCAT(buffer, ")"); return buffer; } From 0c349a8d7f67b185747290595dbd666fb841408d Mon Sep 17 00:00:00 2001 From: Tom Robinson Date: Wed, 29 Jul 2009 20:23:40 -0700 Subject: [PATCH 46/53] Add option to enable type checking in index-debug.html. --- Objective-J/debug.js | 4 ++-- Objective-J/preprocess.js | 3 ++- .../capp/Templates/Application/index-debug.html | 17 ++++++++++++++++- 3 files changed, 20 insertions(+), 4 deletions(-) diff --git a/Objective-J/debug.js b/Objective-J/debug.js index bd23ab7ae..2c7624464 100644 --- a/Objective-J/debug.js +++ b/Objective-J/debug.js @@ -106,7 +106,7 @@ function objj_typecheck_decorator(msgSend) objj_typechecks_reported[key] = true; objj_fprintf(warning_stream, "Type check failed on argument " + (i-2) + " of " + objj_debug_message_format(aReceiver, aSelector) + ": " + e); if (objj_typecheck_prints_backtrace) - objj_backtrace_fprint(warning_stream); + objj_backtrace_print(warning_stream); } } } @@ -124,7 +124,7 @@ function objj_typecheck_decorator(msgSend) objj_typechecks_reported[key] = true; objj_fprintf(warning_stream, "Type check failed on return val of " + objj_debug_message_format(aReceiver, aSelector) + ": " + e); if (objj_typecheck_prints_backtrace) - objj_backtrace_fprint(warning_stream); + objj_backtrace_print(warning_stream); } } diff --git a/Objective-J/preprocess.js b/Objective-J/preprocess.js index 07de33827..ad96215f9 100644 --- a/Objective-J/preprocess.js +++ b/Objective-J/preprocess.js @@ -671,7 +671,8 @@ objj_preprocessor.prototype.method = function(tokens) CONCAT(buffer, ")\n{ with(self)\n{"); CONCAT(buffer, this.preprocess(tokens, NULL, TOKEN_CLOSE_BRACE, TOKEN_OPEN_BRACE)); CONCAT(buffer, "}\n}"); - if (this._flags & OBJJ_PREPROCESSOR_TYPE_SIGNATURES) + // TODO: actually use OBJJ_PREPROCESSOR_TYPE_SIGNATURES flag instead of tying to OBJJ_PREPROCESSOR_DEBUG_SYMBOLS + if (this._flags & OBJJ_PREPROCESSOR_DEBUG_SYMBOLS) //OBJJ_PREPROCESSOR_TYPE_SIGNATURES) CONCAT(buffer, ","+JSON.stringify(types)); CONCAT(buffer, ")"); diff --git a/Tools/capp/Templates/Application/index-debug.html b/Tools/capp/Templates/Application/index-debug.html index 5ebc00c9a..54b8f7fbe 100644 --- a/Tools/capp/Templates/Application/index-debug.html +++ b/Tools/capp/Templates/Application/index-debug.html @@ -21,7 +21,22 @@ - + + +