From d942ed415b6857d4e339faa3a9985ac83afb8d1a Mon Sep 17 00:00:00 2001 From: Francisco Ryan Tolmasky I Date: Mon, 5 Jan 2009 23:46:57 -0800 Subject: [PATCH] Fix for Dragging can happen across views. Reviewed by me. --- AppKit/CPDragServer.j | 44 +++++++++---------------- AppKit/CPWindow/CPWindow.j | 33 +++++++++++++++++++ AppKit/Platform/DOM/CPDOMWindowBridge.j | 24 +++++++------- 3 files changed, 62 insertions(+), 39 deletions(-) diff --git a/AppKit/CPDragServer.j b/AppKit/CPDragServer.j index 0c1cdf798..bf3970f23 100644 --- a/AppKit/CPDragServer.j +++ b/AppKit/CPDragServer.j @@ -26,6 +26,8 @@ @import +#define DRAGGING_WINDOW(anObject) ([anObject isKindOfClass:[CPWindow class]] ? anObject : [anObject window]) + var CPSharedDragServer = nil; var CPDragServerView = nil, @@ -55,7 +57,7 @@ var CPDragServerUpdateDragging = function(anEvent) // If this is a mouse up, then complete the drag. if([anEvent type] == CPLeftMouseUp) { - CPDragServerLocation = [[CPDragServerDestination window] convertBridgeToBase:[[anEvent window] convertBaseToBridge:[anEvent locationInWindow]]]; + CPDragServerLocation = [DRAGGING_WINDOW(CPDragServerDestination) convertBridgeToBase:[[anEvent window] convertBaseToBridge:[anEvent locationInWindow]]]; [CPDragServerView removeFromSuperview]; [CPSharedDragServer._dragWindow orderOut:nil]; @@ -89,7 +91,7 @@ var CPDragServerUpdateDragging = function(anEvent) // 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]; - CPDragServerLocation = [[CPDragServerDestination window] convertBridgeToBase:bridgeLocation]; + CPDragServerLocation = [DRAGGING_WINDOW(draggingDestination) convertBridgeToBase:bridgeLocation]; if(draggingDestination != CPDragServerDestination) { @@ -121,20 +123,6 @@ var CPDragServerUpdateDragging = function(anEvent) */ @implementation CPDraggingInfo : CPObject { - CPWindow _window; -} - -/* - Initializes the receiver with the window -*/ -- (id)initWithWindow:(CPWindow)aWindow -{ - self = [super init]; - - if (self) - _window = aWindow; - - return this; } - (id)draggingSource @@ -164,7 +152,7 @@ var CPDragServerUpdateDragging = function(anEvent) - (CGPoint)draggedViewLocation { - return [[CPDragServerDestination window] convertBridgeToBase:[CPDragServerView frame].origin]; + return [DRAGGING_WINDOW(CPDragServerDestination) convertBridgeToBase:[CPDragServerView frame].origin]; } - (CPView)draggedView @@ -298,22 +286,22 @@ var CPDragServerUpdateDragging = function(anEvent) @end -@implementation CPView (CPDraggingAdditions) +@implementation CPWindow (CPDraggingAdditions) /* @ignore */ -- (CPView)_dragHitTest:(CPPoint)aPoint pasteboard:(CPPasteboard)aPasteboard +- (id)_dragHitTest:(CPPoint)aPoint pasteboard:(CPPasteboard)aPasteboard { - if(!CPRectContainsPoint(_frame, aPoint) || self == CPDragServerView) + if (![self containsPoint:aPoint]) return nil; - var view = nil, - i = [_subviews count], - adjustedPoint = CPPointMake(aPoint.x - CPRectGetMinX(_frame), aPoint.y - CPRectGetMinY(_frame)); - - while (i--) - if (view = [_subviews[i] _dragHitTest:adjustedPoint pasteboard:aPasteboard]) - return view; - + var hitView = [_windowView hitTest:aPoint]; + + while (hitView && ![aPasteboard availableTypeFromArray:[hitView registeredDraggedTypes]]) + hitView = [hitView superview]; + + if (hitView) + return hitView; + if ([aPasteboard availableTypeFromArray:_registeredDraggedTypes]) return self; diff --git a/AppKit/CPWindow/CPWindow.j b/AppKit/CPWindow/CPWindow.j index 1b0d3e5eb..bc3cb896e 100644 --- a/AppKit/CPWindow/CPWindow.j +++ b/AppKit/CPWindow/CPWindow.j @@ -273,6 +273,8 @@ var CPWindowSaveImage = nil, CPUndoManager _undoManager; CPURL _representedURL; + CPArray _registeredDraggedTypes; + // Bridge Support #if PLATFORM(DOM) DOMElement _DOMElement; @@ -1210,6 +1212,32 @@ CPTexturedBackgroundWindowMask [[CPDragServer sharedDragServer] dragView:aView fromWindow:self at:[self convertBaseToBridge:imageLocation] offset:mouseOffset event:anEvent pasteboard:aPasteboard source:aSourceObject slideBack:slideBack]; } +/*! + Sets the receiver's list of acceptable data types for a dragging operation. + @param pasteboardTypes an array of CPPasteboards +*/ +- (void)registerForDraggedTypes:(CPArray)pasteboardTypes +{ + _registeredDraggedTypes = [pasteboardTypes copy]; +} + +/*! + Returns an array of all types the receiver accepts for dragging operations. + @return an array of CPPasteBoards +*/ +- (CPArray)registeredDraggedTypes +{ + return _registeredDraggedTypes; +} + +/*! + Resets the array of acceptable data types for a dragging operation. +*/ +- (void)unregisterDraggedTypes +{ + _registeredDraggedTypes = nil; +} + // Accessing Editing Status /*! @@ -1643,6 +1671,11 @@ CPTexturedBackgroundWindowMask [[self undoManager] redo]; } +- (BOOL)containsPoint:(CGPoint)aPoint +{ + return CGRectContainsPoint(_frame, aPoint); +} + @end var interpolate = function(fromValue, toValue, progress) diff --git a/AppKit/Platform/DOM/CPDOMWindowBridge.j b/AppKit/Platform/DOM/CPDOMWindowBridge.j index bfb42b29b..899dd7530 100644 --- a/AppKit/Platform/DOM/CPDOMWindowBridge.j +++ b/AppKit/Platform/DOM/CPDOMWindowBridge.j @@ -285,14 +285,13 @@ var CPDOMWindowGetFrame, } /* @ignore */ -- (CPView)_dragHitTest:(CPPoint)aPoint pasteboard:(CPPasteboard)aPasteboard +- (id)_dragHitTest:(CPPoint)aPoint pasteboard:(CPPasteboard)aPasteboard { - var view = nil, - levels = _windowLevels, + var levels = _windowLevels, layers = _windowLayers, levelCount = levels.length; - while (levelCount-- && !view) + while (levelCount--) { // Skip any windows above or at the dragging level. if (levels[levelCount] >= CPDraggingWindowLevel) @@ -303,18 +302,21 @@ var CPDOMWindowGetFrame, while (windowCount--) { - var theWindow = windows[windowCount], - frame = theWindow._frame; + var theWindow = windows[windowCount]; - if (CPRectContainsPoint(frame, aPoint)) - if (view = [theWindow._windowView _dragHitTest:CGPointMake(aPoint.x - frame.origin.x, aPoint.y - frame.origin.y) pasteboard:aPasteboard]) - return view; + if ([theWindow containsPoint:aPoint]) + { + var object = [theWindow _dragHitTest:aPoint pasteboard:aPasteboard]; + + if (object) + return object; else return nil; + } } } - return view; + return nil; } /* @ignore */ @@ -339,7 +341,7 @@ var CPDOMWindowGetFrame, { var candidateWindow = windows[windowCount]; - if (!candidateWindow._ignoresMouseEvents && CGRectContainsPoint(candidateWindow._frame, location)) + if (!candidateWindow._ignoresMouseEvents && [candidateWindow containsPoint:location]) theWindow = candidateWindow; } }