WebKit/mac/WebView/WebViewEventHandling.mm
changeset 0 4f2f89ce4247
equal deleted inserted replaced
-1:000000000000 0:4f2f89ce4247
       
     1 /*
       
     2  * Copyright (C) 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
       
     3  * Copyright (C) 2006 David Smith (catfish.man@gmail.com)
       
     4  *
       
     5  * Redistribution and use in source and binary forms, with or without
       
     6  * modification, are permitted provided that the following conditions
       
     7  * are met:
       
     8  *
       
     9  * 1.  Redistributions of source code must retain the above copyright
       
    10  *     notice, this list of conditions and the following disclaimer. 
       
    11  * 2.  Redistributions in binary form must reproduce the above copyright
       
    12  *     notice, this list of conditions and the following disclaimer in the
       
    13  *     documentation and/or other materials provided with the distribution. 
       
    14  * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
       
    15  *     its contributors may be used to endorse or promote products derived
       
    16  *     from this software without specific prior written permission. 
       
    17  *
       
    18  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
       
    19  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
       
    20  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
       
    21  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
       
    22  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
       
    23  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
       
    24  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
       
    25  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
       
    26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
       
    27  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
       
    28  */
       
    29 
       
    30 #import "WebViewInternal.h"
       
    31 
       
    32 #import "WebFrameInternal.h"
       
    33 #import "WebHTMLView.h"
       
    34 #import "WebTextCompletionController.h"
       
    35 #import "WebViewData.h"
       
    36 #import <WebCore/Frame.h>
       
    37 
       
    38 using namespace WebCore;
       
    39 
       
    40 @class NSTextInputContext;
       
    41 
       
    42 @interface NSResponder (WebNSResponderDetails)
       
    43 - (NSTextInputContext *)inputContext;
       
    44 @end
       
    45 
       
    46 #if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
       
    47 @interface NSObject (NSTextInputContextDetails)
       
    48 - (BOOL)wantsToHandleMouseEvents;
       
    49 - (BOOL)handleMouseEvent:(NSEvent *)event;
       
    50 @end
       
    51 #endif
       
    52 
       
    53 @implementation WebView (WebViewEventHandling)
       
    54 
       
    55 static WebView *lastMouseoverView;
       
    56 
       
    57 - (void)_closingEventHandling
       
    58 {
       
    59     if (lastMouseoverView == self)
       
    60         lastMouseoverView = nil;
       
    61 }
       
    62 
       
    63 - (void)_setMouseDownEvent:(NSEvent *)event
       
    64 {
       
    65     ASSERT(!event || [event type] == NSLeftMouseDown || [event type] == NSRightMouseDown || [event type] == NSOtherMouseDown);
       
    66 
       
    67     if (event == _private->mouseDownEvent)
       
    68         return;
       
    69 
       
    70     [event retain];
       
    71     [_private->mouseDownEvent release];
       
    72     _private->mouseDownEvent = event;
       
    73 }
       
    74 
       
    75 - (void)mouseDown:(NSEvent *)event
       
    76 {
       
    77     // FIXME (Viewless): This method should be shared with WebHTMLView, which needs to
       
    78     // do the same work in the usesDocumentViews case. We don't want to maintain two
       
    79     // duplicate copies of this method.
       
    80 
       
    81     if (_private->usesDocumentViews) {
       
    82         [super mouseDown:event];
       
    83         return;
       
    84     }
       
    85     
       
    86     // There's a chance that responding to this event will run a nested event loop, and
       
    87     // fetching a new event might release the old one. Retaining and then autoreleasing
       
    88     // the current event prevents that from causing a problem inside WebKit or AppKit code.
       
    89     [[event retain] autorelease];
       
    90 
       
    91     RetainPtr<WebView> protector = self;
       
    92     if ([[self inputContext] wantsToHandleMouseEvents] && [[self inputContext] handleMouseEvent:event])
       
    93         return;
       
    94 
       
    95     _private->handlingMouseDownEvent = YES;
       
    96 
       
    97     // Record the mouse down position so we can determine drag hysteresis.
       
    98     [self _setMouseDownEvent:event];
       
    99 
       
   100     NSInputManager *currentInputManager = [NSInputManager currentInputManager];
       
   101     if ([currentInputManager wantsToHandleMouseEvents] && [currentInputManager handleMouseEvent:event])
       
   102         goto done;
       
   103 
       
   104     [_private->completionController endRevertingChange:NO moveLeft:NO];
       
   105 
       
   106     // If the web page handles the context menu event and menuForEvent: returns nil, we'll get control click events here.
       
   107     // We don't want to pass them along to KHTML a second time.
       
   108     if (!([event modifierFlags] & NSControlKeyMask)) {
       
   109         _private->ignoringMouseDraggedEvents = NO;
       
   110 
       
   111         // Don't do any mouseover while the mouse is down.
       
   112         [self _cancelUpdateMouseoverTimer];
       
   113 
       
   114         // Let WebCore get a chance to deal with the event. This will call back to us
       
   115         // to start the autoscroll timer if appropriate.
       
   116         if (Frame* frame = [self _mainCoreFrame])
       
   117             frame->eventHandler()->mouseDown(event);
       
   118     }
       
   119 
       
   120 done:
       
   121     _private->handlingMouseDownEvent = NO;
       
   122 }
       
   123 
       
   124 - (void)mouseUp:(NSEvent *)event
       
   125 {
       
   126     // FIXME (Viewless): This method should be shared with WebHTMLView, which needs to
       
   127     // do the same work in the usesDocumentViews case. We don't want to maintain two
       
   128     // duplicate copies of this method.
       
   129 
       
   130     if (_private->usesDocumentViews) {
       
   131         [super mouseUp:event];
       
   132         return;
       
   133     }
       
   134 
       
   135     // There's a chance that responding to this event will run a nested event loop, and
       
   136     // fetching a new event might release the old one. Retaining and then autoreleasing
       
   137     // the current event prevents that from causing a problem inside WebKit or AppKit code.
       
   138     [[event retain] autorelease];
       
   139 
       
   140     [self _setMouseDownEvent:nil];
       
   141 
       
   142     NSInputManager *currentInputManager = [NSInputManager currentInputManager];
       
   143     if ([currentInputManager wantsToHandleMouseEvents] && [currentInputManager handleMouseEvent:event])
       
   144         return;
       
   145 
       
   146     [self retain];
       
   147 
       
   148     [self _stopAutoscrollTimer];
       
   149     if (Frame* frame = [self _mainCoreFrame])
       
   150         frame->eventHandler()->mouseUp(event);
       
   151     [self _updateMouseoverWithFakeEvent];
       
   152 
       
   153     [self release];
       
   154 }
       
   155 
       
   156 + (void)_updateMouseoverWithEvent:(NSEvent *)event
       
   157 {
       
   158     WebView *oldView = lastMouseoverView;
       
   159 
       
   160     lastMouseoverView = nil;
       
   161 
       
   162     NSView *contentView = [[event window] contentView];
       
   163     NSPoint locationForHitTest = [[contentView superview] convertPoint:[event locationInWindow] fromView:nil];
       
   164     for (NSView *hitView = [contentView hitTest:locationForHitTest]; hitView; hitView = [hitView superview]) {
       
   165         if ([hitView isKindOfClass:[WebView class]]) {
       
   166             lastMouseoverView = static_cast<WebView *>(hitView);
       
   167             break;
       
   168         }
       
   169     }
       
   170 
       
   171     if (lastMouseoverView && lastMouseoverView->_private->hoverFeedbackSuspended)
       
   172         lastMouseoverView = nil;
       
   173 
       
   174     if (lastMouseoverView != oldView) {
       
   175         if (Frame* oldCoreFrame = [oldView _mainCoreFrame]) {
       
   176             NSEvent *oldViewEvent = [NSEvent mouseEventWithType:NSMouseMoved
       
   177                 location:NSMakePoint(-1, -1)
       
   178                 modifierFlags:[[NSApp currentEvent] modifierFlags]
       
   179                 timestamp:[NSDate timeIntervalSinceReferenceDate]
       
   180                 windowNumber:[[oldView window] windowNumber]
       
   181                 context:[[NSApp currentEvent] context]
       
   182                 eventNumber:0 clickCount:0 pressure:0];
       
   183             oldCoreFrame->eventHandler()->mouseMoved(oldViewEvent);
       
   184         }
       
   185     }
       
   186 
       
   187     if (!lastMouseoverView)
       
   188         return;
       
   189 
       
   190     if (Frame* coreFrame = core([lastMouseoverView mainFrame]))
       
   191         coreFrame->eventHandler()->mouseMoved(event);
       
   192 }
       
   193 
       
   194 - (void)_updateMouseoverWithFakeEvent
       
   195 {
       
   196     [self _cancelUpdateMouseoverTimer];
       
   197     
       
   198     NSEvent *fakeEvent = [NSEvent mouseEventWithType:NSMouseMoved
       
   199         location:[[self window] convertScreenToBase:[NSEvent mouseLocation]]
       
   200         modifierFlags:[[NSApp currentEvent] modifierFlags]
       
   201         timestamp:[NSDate timeIntervalSinceReferenceDate]
       
   202         windowNumber:[[self window] windowNumber]
       
   203         context:[[NSApp currentEvent] context]
       
   204         eventNumber:0 clickCount:0 pressure:0];
       
   205     
       
   206     [[self class] _updateMouseoverWithEvent:fakeEvent];
       
   207 }
       
   208 
       
   209 - (void)_cancelUpdateMouseoverTimer
       
   210 {
       
   211     if (_private->updateMouseoverTimer) {
       
   212         CFRunLoopTimerInvalidate(_private->updateMouseoverTimer);
       
   213         CFRelease(_private->updateMouseoverTimer);
       
   214         _private->updateMouseoverTimer = NULL;
       
   215     }
       
   216 }
       
   217 
       
   218 - (void)_stopAutoscrollTimer
       
   219 {
       
   220     NSTimer *timer = _private->autoscrollTimer;
       
   221     _private->autoscrollTimer = nil;
       
   222     [_private->autoscrollTriggerEvent release];
       
   223     _private->autoscrollTriggerEvent = nil;
       
   224     [timer invalidate];
       
   225     [timer release];
       
   226 }
       
   227 
       
   228 - (void)_setToolTip:(NSString *)toolTip
       
   229 {
       
   230     if (_private->usesDocumentViews) {
       
   231         id documentView = [[[self _selectedOrMainFrame] frameView] documentView];
       
   232         if ([documentView isKindOfClass:[WebHTMLView class]])
       
   233             [documentView _setToolTip:toolTip];
       
   234         return;
       
   235     }
       
   236 
       
   237     // FIXME (Viewless): Code to handle tooltips needs to move into WebView.
       
   238 }
       
   239 
       
   240 @end