diff -r 000000000000 -r 4f2f89ce4247 WebKit/mac/WebView/WebViewEventHandling.mm --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/WebKit/mac/WebView/WebViewEventHandling.mm Fri Sep 17 09:02:29 2010 +0300 @@ -0,0 +1,240 @@ +/* + * Copyright (C) 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. + * Copyright (C) 2006 David Smith (catfish.man@gmail.com) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import "WebViewInternal.h" + +#import "WebFrameInternal.h" +#import "WebHTMLView.h" +#import "WebTextCompletionController.h" +#import "WebViewData.h" +#import + +using namespace WebCore; + +@class NSTextInputContext; + +@interface NSResponder (WebNSResponderDetails) +- (NSTextInputContext *)inputContext; +@end + +#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) +@interface NSObject (NSTextInputContextDetails) +- (BOOL)wantsToHandleMouseEvents; +- (BOOL)handleMouseEvent:(NSEvent *)event; +@end +#endif + +@implementation WebView (WebViewEventHandling) + +static WebView *lastMouseoverView; + +- (void)_closingEventHandling +{ + if (lastMouseoverView == self) + lastMouseoverView = nil; +} + +- (void)_setMouseDownEvent:(NSEvent *)event +{ + ASSERT(!event || [event type] == NSLeftMouseDown || [event type] == NSRightMouseDown || [event type] == NSOtherMouseDown); + + if (event == _private->mouseDownEvent) + return; + + [event retain]; + [_private->mouseDownEvent release]; + _private->mouseDownEvent = event; +} + +- (void)mouseDown:(NSEvent *)event +{ + // FIXME (Viewless): This method should be shared with WebHTMLView, which needs to + // do the same work in the usesDocumentViews case. We don't want to maintain two + // duplicate copies of this method. + + if (_private->usesDocumentViews) { + [super mouseDown:event]; + return; + } + + // There's a chance that responding to this event will run a nested event loop, and + // fetching a new event might release the old one. Retaining and then autoreleasing + // the current event prevents that from causing a problem inside WebKit or AppKit code. + [[event retain] autorelease]; + + RetainPtr protector = self; + if ([[self inputContext] wantsToHandleMouseEvents] && [[self inputContext] handleMouseEvent:event]) + return; + + _private->handlingMouseDownEvent = YES; + + // Record the mouse down position so we can determine drag hysteresis. + [self _setMouseDownEvent:event]; + + NSInputManager *currentInputManager = [NSInputManager currentInputManager]; + if ([currentInputManager wantsToHandleMouseEvents] && [currentInputManager handleMouseEvent:event]) + goto done; + + [_private->completionController endRevertingChange:NO moveLeft:NO]; + + // If the web page handles the context menu event and menuForEvent: returns nil, we'll get control click events here. + // We don't want to pass them along to KHTML a second time. + if (!([event modifierFlags] & NSControlKeyMask)) { + _private->ignoringMouseDraggedEvents = NO; + + // Don't do any mouseover while the mouse is down. + [self _cancelUpdateMouseoverTimer]; + + // Let WebCore get a chance to deal with the event. This will call back to us + // to start the autoscroll timer if appropriate. + if (Frame* frame = [self _mainCoreFrame]) + frame->eventHandler()->mouseDown(event); + } + +done: + _private->handlingMouseDownEvent = NO; +} + +- (void)mouseUp:(NSEvent *)event +{ + // FIXME (Viewless): This method should be shared with WebHTMLView, which needs to + // do the same work in the usesDocumentViews case. We don't want to maintain two + // duplicate copies of this method. + + if (_private->usesDocumentViews) { + [super mouseUp:event]; + return; + } + + // There's a chance that responding to this event will run a nested event loop, and + // fetching a new event might release the old one. Retaining and then autoreleasing + // the current event prevents that from causing a problem inside WebKit or AppKit code. + [[event retain] autorelease]; + + [self _setMouseDownEvent:nil]; + + NSInputManager *currentInputManager = [NSInputManager currentInputManager]; + if ([currentInputManager wantsToHandleMouseEvents] && [currentInputManager handleMouseEvent:event]) + return; + + [self retain]; + + [self _stopAutoscrollTimer]; + if (Frame* frame = [self _mainCoreFrame]) + frame->eventHandler()->mouseUp(event); + [self _updateMouseoverWithFakeEvent]; + + [self release]; +} + ++ (void)_updateMouseoverWithEvent:(NSEvent *)event +{ + WebView *oldView = lastMouseoverView; + + lastMouseoverView = nil; + + NSView *contentView = [[event window] contentView]; + NSPoint locationForHitTest = [[contentView superview] convertPoint:[event locationInWindow] fromView:nil]; + for (NSView *hitView = [contentView hitTest:locationForHitTest]; hitView; hitView = [hitView superview]) { + if ([hitView isKindOfClass:[WebView class]]) { + lastMouseoverView = static_cast(hitView); + break; + } + } + + if (lastMouseoverView && lastMouseoverView->_private->hoverFeedbackSuspended) + lastMouseoverView = nil; + + if (lastMouseoverView != oldView) { + if (Frame* oldCoreFrame = [oldView _mainCoreFrame]) { + NSEvent *oldViewEvent = [NSEvent mouseEventWithType:NSMouseMoved + location:NSMakePoint(-1, -1) + modifierFlags:[[NSApp currentEvent] modifierFlags] + timestamp:[NSDate timeIntervalSinceReferenceDate] + windowNumber:[[oldView window] windowNumber] + context:[[NSApp currentEvent] context] + eventNumber:0 clickCount:0 pressure:0]; + oldCoreFrame->eventHandler()->mouseMoved(oldViewEvent); + } + } + + if (!lastMouseoverView) + return; + + if (Frame* coreFrame = core([lastMouseoverView mainFrame])) + coreFrame->eventHandler()->mouseMoved(event); +} + +- (void)_updateMouseoverWithFakeEvent +{ + [self _cancelUpdateMouseoverTimer]; + + NSEvent *fakeEvent = [NSEvent mouseEventWithType:NSMouseMoved + location:[[self window] convertScreenToBase:[NSEvent mouseLocation]] + modifierFlags:[[NSApp currentEvent] modifierFlags] + timestamp:[NSDate timeIntervalSinceReferenceDate] + windowNumber:[[self window] windowNumber] + context:[[NSApp currentEvent] context] + eventNumber:0 clickCount:0 pressure:0]; + + [[self class] _updateMouseoverWithEvent:fakeEvent]; +} + +- (void)_cancelUpdateMouseoverTimer +{ + if (_private->updateMouseoverTimer) { + CFRunLoopTimerInvalidate(_private->updateMouseoverTimer); + CFRelease(_private->updateMouseoverTimer); + _private->updateMouseoverTimer = NULL; + } +} + +- (void)_stopAutoscrollTimer +{ + NSTimer *timer = _private->autoscrollTimer; + _private->autoscrollTimer = nil; + [_private->autoscrollTriggerEvent release]; + _private->autoscrollTriggerEvent = nil; + [timer invalidate]; + [timer release]; +} + +- (void)_setToolTip:(NSString *)toolTip +{ + if (_private->usesDocumentViews) { + id documentView = [[[self _selectedOrMainFrame] frameView] documentView]; + if ([documentView isKindOfClass:[WebHTMLView class]]) + [documentView _setToolTip:toolTip]; + return; + } + + // FIXME (Viewless): Code to handle tooltips needs to move into WebView. +} + +@end