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 01/14] 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 02/14] 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 03/14] 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 04/14] 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 756885fd534ad66720678bd37c6b0bb2a452449f Mon Sep 17 00:00:00 2001 From: Francisco Ryan Tolmasky I Date: Sun, 26 Jul 2009 15:28:41 -0700 Subject: [PATCH 05/14] 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 06/14] 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 07/14] 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 08/14] 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 09/14] 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 10/14] 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 11/14] 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 12/14] 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 13/14] 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 14/14] 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