mirror of
				https://github.com/KevinMidboe/linguist.git
				synced 2025-10-29 17:50:22 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			779 lines
		
	
	
		
			27 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
			
		
		
	
	
			779 lines
		
	
	
		
			27 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
| // grabbed from https://raw.github.com/AOKP/external_webkit/61b2fb934bdd3a5fea253e2de0bcf8a47a552333/Source/WebCore/page/mac/EventHandlerMac.mm
 | |
| 
 | |
| /*
 | |
|  * Copyright (C) 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
 | |
|  *
 | |
|  * 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.
 | |
|  *
 | |
|  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 COMPUTER, INC. OR
 | |
|  * 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.
 | |
|  */
 | |
| 
 | |
| #include "config.h"
 | |
| #include "EventHandler.h"
 | |
| 
 | |
| #include "AXObjectCache.h"
 | |
| #include "BlockExceptions.h"
 | |
| #include "Chrome.h"
 | |
| #include "ChromeClient.h"
 | |
| #include "ClipboardMac.h"
 | |
| #include "DragController.h"
 | |
| #include "EventNames.h"
 | |
| #include "FocusController.h"
 | |
| #include "Frame.h"
 | |
| #include "FrameLoader.h"
 | |
| #include "FrameView.h"
 | |
| #include "KeyboardEvent.h"
 | |
| #include "MouseEventWithHitTestResults.h"
 | |
| #include "NotImplemented.h"
 | |
| #include "Page.h"
 | |
| #include "PlatformKeyboardEvent.h"
 | |
| #include "PlatformWheelEvent.h"
 | |
| #include "RenderWidget.h"
 | |
| #include "RuntimeApplicationChecks.h"
 | |
| #include "Scrollbar.h"
 | |
| #include "Settings.h"
 | |
| #include "WebCoreSystemInterface.h"
 | |
| #include <objc/objc-runtime.h>
 | |
| #include <wtf/StdLibExtras.h>
 | |
| 
 | |
| #if !(defined(OBJC_API_VERSION) && OBJC_API_VERSION > 0)
 | |
| static inline IMP method_setImplementation(Method m, IMP i)
 | |
| {
 | |
|     IMP oi = m->method_imp;
 | |
|     m->method_imp = i;
 | |
|     return oi;
 | |
| }
 | |
| #endif
 | |
| 
 | |
| namespace WebCore {
 | |
| 
 | |
| #if ENABLE(DRAG_SUPPORT)
 | |
| const double EventHandler::TextDragDelay = 0.15;
 | |
| #endif
 | |
| 
 | |
| static RetainPtr<NSEvent>& currentNSEventSlot()
 | |
| {
 | |
|     DEFINE_STATIC_LOCAL(RetainPtr<NSEvent>, event, ());
 | |
|     return event;
 | |
| }
 | |
| 
 | |
| NSEvent *EventHandler::currentNSEvent()
 | |
| {
 | |
|     return currentNSEventSlot().get();
 | |
| }
 | |
| 
 | |
| class CurrentEventScope {
 | |
|      WTF_MAKE_NONCOPYABLE(CurrentEventScope);
 | |
| public:
 | |
|     CurrentEventScope(NSEvent *);
 | |
|     ~CurrentEventScope();
 | |
| 
 | |
| private:
 | |
|     RetainPtr<NSEvent> m_savedCurrentEvent;
 | |
| #ifndef NDEBUG
 | |
|     RetainPtr<NSEvent> m_event;
 | |
| #endif
 | |
| };
 | |
| 
 | |
| inline CurrentEventScope::CurrentEventScope(NSEvent *event)
 | |
|     : m_savedCurrentEvent(currentNSEventSlot())
 | |
| #ifndef NDEBUG
 | |
|     , m_event(event)
 | |
| #endif
 | |
| {
 | |
|     currentNSEventSlot() = event;
 | |
| }
 | |
| 
 | |
| inline CurrentEventScope::~CurrentEventScope()
 | |
| {
 | |
|     ASSERT(currentNSEventSlot() == m_event);
 | |
|     currentNSEventSlot() = m_savedCurrentEvent;
 | |
| }
 | |
| 
 | |
| bool EventHandler::wheelEvent(NSEvent *event)
 | |
| {
 | |
|     Page* page = m_frame->page();
 | |
|     if (!page)
 | |
|         return false;
 | |
| 
 | |
|     CurrentEventScope scope(event);
 | |
| 
 | |
|     PlatformWheelEvent wheelEvent(event, page->chrome()->platformPageClient());
 | |
|     handleWheelEvent(wheelEvent);
 | |
| 
 | |
|     return wheelEvent.isAccepted();
 | |
| }
 | |
| 
 | |
| PassRefPtr<KeyboardEvent> EventHandler::currentKeyboardEvent() const
 | |
| {
 | |
|     NSEvent *event = [NSApp currentEvent];
 | |
|     if (!event)
 | |
|         return 0;
 | |
|     switch ([event type]) {
 | |
|         case NSKeyDown: {
 | |
|             PlatformKeyboardEvent platformEvent(event);
 | |
|             platformEvent.disambiguateKeyDownEvent(PlatformKeyboardEvent::RawKeyDown);
 | |
|             return KeyboardEvent::create(platformEvent, m_frame->document()->defaultView());
 | |
|         }
 | |
|         case NSKeyUp:
 | |
|             return KeyboardEvent::create(event, m_frame->document()->defaultView());
 | |
|         default:
 | |
|             return 0;
 | |
|     }
 | |
| }
 | |
| 
 | |
| bool EventHandler::keyEvent(NSEvent *event)
 | |
| {
 | |
|     BEGIN_BLOCK_OBJC_EXCEPTIONS;
 | |
| 
 | |
|     ASSERT([event type] == NSKeyDown || [event type] == NSKeyUp);
 | |
| 
 | |
|     CurrentEventScope scope(event);
 | |
|     return keyEvent(PlatformKeyboardEvent(event));
 | |
| 
 | |
|     END_BLOCK_OBJC_EXCEPTIONS;
 | |
| 
 | |
|     return false;
 | |
| }
 | |
| 
 | |
| void EventHandler::focusDocumentView()
 | |
| {
 | |
|     Page* page = m_frame->page();
 | |
|     if (!page)
 | |
|         return;
 | |
| 
 | |
|     if (FrameView* frameView = m_frame->view()) {
 | |
|         if (NSView *documentView = frameView->documentView())
 | |
|             page->chrome()->focusNSView(documentView);
 | |
|     }
 | |
| 
 | |
|     page->focusController()->setFocusedFrame(m_frame);
 | |
| }
 | |
| 
 | |
| bool EventHandler::passWidgetMouseDownEventToWidget(const MouseEventWithHitTestResults& event)
 | |
| {
 | |
|     // Figure out which view to send the event to.
 | |
|     RenderObject* target = targetNode(event) ? targetNode(event)->renderer() : 0;
 | |
|     if (!target || !target->isWidget())
 | |
|         return false;
 | |
| 
 | |
|     // Double-click events don't exist in Cocoa. Since passWidgetMouseDownEventToWidget will
 | |
|     // just pass currentEvent down to the widget, we don't want to call it for events that
 | |
|     // don't correspond to Cocoa events.  The mousedown/ups will have already been passed on as
 | |
|     // part of the pressed/released handling.
 | |
|     return passMouseDownEventToWidget(toRenderWidget(target)->widget());
 | |
| }
 | |
| 
 | |
| bool EventHandler::passWidgetMouseDownEventToWidget(RenderWidget* renderWidget)
 | |
| {
 | |
|     return passMouseDownEventToWidget(renderWidget->widget());
 | |
| }
 | |
| 
 | |
| static bool lastEventIsMouseUp()
 | |
| {
 | |
|     // Many AppKit widgets run their own event loops and consume events while the mouse is down.
 | |
|     // When they finish, currentEvent is the mouseUp that they exited on. We need to update
 | |
|     // the WebCore state with this mouseUp, which we never saw. This method lets us detect
 | |
|     // that state. Handling this was critical when we used AppKit widgets for form elements.
 | |
|     // It's not clear in what cases this is helpful now -- it's possible it can be removed.
 | |
| 
 | |
|     BEGIN_BLOCK_OBJC_EXCEPTIONS;
 | |
|     NSEvent *currentEventAfterHandlingMouseDown = [NSApp currentEvent];
 | |
|     return EventHandler::currentNSEvent() != currentEventAfterHandlingMouseDown
 | |
|         && [currentEventAfterHandlingMouseDown type] == NSLeftMouseUp
 | |
|         && [currentEventAfterHandlingMouseDown timestamp] >= [EventHandler::currentNSEvent() timestamp];
 | |
|     END_BLOCK_OBJC_EXCEPTIONS;
 | |
| 
 | |
|     return false;
 | |
| }
 | |
| 
 | |
| bool EventHandler::passMouseDownEventToWidget(Widget* pWidget)
 | |
| {
 | |
|     // FIXME: This function always returns true. It should be changed either to return
 | |
|     // false in some cases or the return value should be removed.
 | |
| 
 | |
|     RefPtr<Widget> widget = pWidget;
 | |
| 
 | |
|     if (!widget) {
 | |
|         LOG_ERROR("hit a RenderWidget without a corresponding Widget, means a frame is half-constructed");
 | |
|         return true;
 | |
|     }
 | |
| 
 | |
|     // In WebKit2 we will never have an NSView. Just return early and let the regular event handler machinery take care of
 | |
|     // dispatching the event.
 | |
|     if (!widget->platformWidget())
 | |
|         return false;
 | |
| 
 | |
|     BEGIN_BLOCK_OBJC_EXCEPTIONS;
 | |
| 
 | |
|     NSView *nodeView = widget->platformWidget();
 | |
|     ASSERT([nodeView superview]);
 | |
|     NSView *view = [nodeView hitTest:[[nodeView superview] convertPoint:[currentNSEvent() locationInWindow] fromView:nil]];
 | |
|     if (!view) {
 | |
|         // We probably hit the border of a RenderWidget
 | |
|         return true;
 | |
|     }
 | |
| 
 | |
|     Page* page = m_frame->page();
 | |
|     if (!page)
 | |
|         return true;
 | |
| 
 | |
|     if (page->chrome()->client()->firstResponder() != view) {
 | |
|         // Normally [NSWindow sendEvent:] handles setting the first responder.
 | |
|         // But in our case, the event was sent to the view representing the entire web page.
 | |
|         if ([currentNSEvent() clickCount] <= 1 && [view acceptsFirstResponder] && [view needsPanelToBecomeKey])
 | |
|             page->chrome()->client()->makeFirstResponder(view);
 | |
|     }
 | |
| 
 | |
|     // We need to "defer loading" while tracking the mouse, because tearing down the
 | |
|     // page while an AppKit control is tracking the mouse can cause a crash.
 | |
| 
 | |
|     // FIXME: In theory, WebCore now tolerates tear-down while tracking the
 | |
|     // mouse. We should confirm that, and then remove the deferrsLoading
 | |
|     // hack entirely.
 | |
| 
 | |
|     bool wasDeferringLoading = page->defersLoading();
 | |
|     if (!wasDeferringLoading)
 | |
|         page->setDefersLoading(true);
 | |
| 
 | |
|     ASSERT(!m_sendingEventToSubview);
 | |
|     m_sendingEventToSubview = true;
 | |
|     NSView *outerView = widget->getOuterView();
 | |
|     widget->beforeMouseDown(outerView, widget.get());
 | |
|     [view mouseDown:currentNSEvent()];
 | |
|     widget->afterMouseDown(outerView, widget.get());
 | |
|     m_sendingEventToSubview = false;
 | |
| 
 | |
|     if (!wasDeferringLoading)
 | |
|         page->setDefersLoading(false);
 | |
| 
 | |
|     // Remember which view we sent the event to, so we can direct the release event properly.
 | |
|     m_mouseDownView = view;
 | |
|     m_mouseDownWasInSubframe = false;
 | |
| 
 | |
|     // Many AppKit widgets run their own event loops and consume events while the mouse is down.
 | |
|     // When they finish, currentEvent is the mouseUp that they exited on.  We need to update
 | |
|     // the EventHandler state with this mouseUp, which we never saw.
 | |
|     // If this event isn't a mouseUp, we assume that the mouseUp will be coming later.  There
 | |
|     // is a hole here if the widget consumes both the mouseUp and subsequent events.
 | |
|     if (lastEventIsMouseUp())
 | |
|         m_mousePressed = false;
 | |
| 
 | |
|     END_BLOCK_OBJC_EXCEPTIONS;
 | |
| 
 | |
|     return true;
 | |
| }
 | |
| 
 | |
| // Note that this does the same kind of check as [target isDescendantOf:superview].
 | |
| // There are two differences: This is a lot slower because it has to walk the whole
 | |
| // tree, and this works in cases where the target has already been deallocated.
 | |
| static bool findViewInSubviews(NSView *superview, NSView *target)
 | |
| {
 | |
|     BEGIN_BLOCK_OBJC_EXCEPTIONS;
 | |
|     NSEnumerator *e = [[superview subviews] objectEnumerator];
 | |
|     NSView *subview;
 | |
|     while ((subview = [e nextObject])) {
 | |
|         if (subview == target || findViewInSubviews(subview, target)) {
 | |
|             return true;
 | |
|         }
 | |
|     }
 | |
|     END_BLOCK_OBJC_EXCEPTIONS;
 | |
| 
 | |
|     return false;
 | |
| }
 | |
| 
 | |
| NSView *EventHandler::mouseDownViewIfStillGood()
 | |
| {
 | |
|     // Since we have no way of tracking the lifetime of m_mouseDownView, we have to assume that
 | |
|     // it could be deallocated already. We search for it in our subview tree; if we don't find
 | |
|     // it, we set it to nil.
 | |
|     NSView *mouseDownView = m_mouseDownView;
 | |
|     if (!mouseDownView) {
 | |
|         return nil;
 | |
|     }
 | |
|     FrameView* topFrameView = m_frame->view();
 | |
|     NSView *topView = topFrameView ? topFrameView->platformWidget() : nil;
 | |
|     if (!topView || !findViewInSubviews(topView, mouseDownView)) {
 | |
|         m_mouseDownView = nil;
 | |
|         return nil;
 | |
|     }
 | |
|     return mouseDownView;
 | |
| }
 | |
| 
 | |
| #if ENABLE(DRAG_SUPPORT)
 | |
| bool EventHandler::eventLoopHandleMouseDragged(const MouseEventWithHitTestResults&)
 | |
| {
 | |
|     NSView *view = mouseDownViewIfStillGood();
 | |
| 
 | |
|     if (!view)
 | |
|         return false;
 | |
| 
 | |
|     if (!m_mouseDownWasInSubframe) {
 | |
|         ASSERT(!m_sendingEventToSubview);
 | |
|         m_sendingEventToSubview = true;
 | |
|         BEGIN_BLOCK_OBJC_EXCEPTIONS;
 | |
|         [view mouseDragged:currentNSEvent()];
 | |
|         END_BLOCK_OBJC_EXCEPTIONS;
 | |
|         m_sendingEventToSubview = false;
 | |
|     }
 | |
| 
 | |
|     return true;
 | |
| }
 | |
| #endif // ENABLE(DRAG_SUPPORT)
 | |
| 
 | |
| bool EventHandler::eventLoopHandleMouseUp(const MouseEventWithHitTestResults&)
 | |
| {
 | |
|     NSView *view = mouseDownViewIfStillGood();
 | |
|     if (!view)
 | |
|         return false;
 | |
| 
 | |
|     if (!m_mouseDownWasInSubframe) {
 | |
|         ASSERT(!m_sendingEventToSubview);
 | |
|         m_sendingEventToSubview = true;
 | |
|         BEGIN_BLOCK_OBJC_EXCEPTIONS;
 | |
|         [view mouseUp:currentNSEvent()];
 | |
|         END_BLOCK_OBJC_EXCEPTIONS;
 | |
|         m_sendingEventToSubview = false;
 | |
|     }
 | |
| 
 | |
|     return true;
 | |
| }
 | |
| 
 | |
| bool EventHandler::passSubframeEventToSubframe(MouseEventWithHitTestResults& event, Frame* subframe, HitTestResult* hoveredNode)
 | |
| {
 | |
|     BEGIN_BLOCK_OBJC_EXCEPTIONS;
 | |
| 
 | |
|     switch ([currentNSEvent() type]) {
 | |
|         case NSLeftMouseDragged:
 | |
|         case NSOtherMouseDragged:
 | |
|         case NSRightMouseDragged:
 | |
|             // This check is bogus and results in <rdar://6813830>, but removing it breaks a number of
 | |
|             // layout tests.
 | |
|             if (!m_mouseDownWasInSubframe)
 | |
|                 return false;
 | |
| #if ENABLE(DRAG_SUPPORT)
 | |
|             if (subframe->page()->dragController()->didInitiateDrag())
 | |
|                 return false;
 | |
| #endif
 | |
|         case NSMouseMoved:
 | |
|             // Since we're passing in currentNSEvent() here, we can call
 | |
|             // handleMouseMoveEvent() directly, since the save/restore of
 | |
|             // currentNSEvent() that mouseMoved() does would have no effect.
 | |
|             ASSERT(!m_sendingEventToSubview);
 | |
|             m_sendingEventToSubview = true;
 | |
|             subframe->eventHandler()->handleMouseMoveEvent(currentPlatformMouseEvent(), hoveredNode);
 | |
|             m_sendingEventToSubview = false;
 | |
|             return true;
 | |
| 
 | |
|         case NSLeftMouseDown: {
 | |
|             Node* node = targetNode(event);
 | |
|             if (!node)
 | |
|                 return false;
 | |
|             RenderObject* renderer = node->renderer();
 | |
|             if (!renderer || !renderer->isWidget())
 | |
|                 return false;
 | |
|             Widget* widget = toRenderWidget(renderer)->widget();
 | |
|             if (!widget || !widget->isFrameView())
 | |
|                 return false;
 | |
|             if (!passWidgetMouseDownEventToWidget(toRenderWidget(renderer)))
 | |
|                 return false;
 | |
|             m_mouseDownWasInSubframe = true;
 | |
|             return true;
 | |
|         }
 | |
|         case NSLeftMouseUp: {
 | |
|             if (!m_mouseDownWasInSubframe)
 | |
|                 return false;
 | |
|             ASSERT(!m_sendingEventToSubview);
 | |
|             m_sendingEventToSubview = true;
 | |
|             subframe->eventHandler()->handleMouseReleaseEvent(currentPlatformMouseEvent());
 | |
|             m_sendingEventToSubview = false;
 | |
|             return true;
 | |
|         }
 | |
|         default:
 | |
|             return false;
 | |
|     }
 | |
|     END_BLOCK_OBJC_EXCEPTIONS;
 | |
| 
 | |
|     return false;
 | |
| }
 | |
| 
 | |
| static IMP originalNSScrollViewScrollWheel;
 | |
| static bool _nsScrollViewScrollWheelShouldRetainSelf;
 | |
| static void selfRetainingNSScrollViewScrollWheel(NSScrollView *, SEL, NSEvent *);
 | |
| 
 | |
| static bool nsScrollViewScrollWheelShouldRetainSelf()
 | |
| {
 | |
|     ASSERT(isMainThread());
 | |
| 
 | |
|     return _nsScrollViewScrollWheelShouldRetainSelf;
 | |
| }
 | |
| 
 | |
| static void setNSScrollViewScrollWheelShouldRetainSelf(bool shouldRetain)
 | |
| {
 | |
|     ASSERT(isMainThread());
 | |
| 
 | |
|     if (!originalNSScrollViewScrollWheel) {
 | |
|         Method method = class_getInstanceMethod(objc_getRequiredClass("NSScrollView"), @selector(scrollWheel:));
 | |
|         originalNSScrollViewScrollWheel = method_setImplementation(method, reinterpret_cast<IMP>(selfRetainingNSScrollViewScrollWheel));
 | |
|     }
 | |
| 
 | |
|     _nsScrollViewScrollWheelShouldRetainSelf = shouldRetain;
 | |
| }
 | |
| 
 | |
| static void selfRetainingNSScrollViewScrollWheel(NSScrollView *self, SEL selector, NSEvent *event)
 | |
| {
 | |
|     bool shouldRetainSelf = isMainThread() && nsScrollViewScrollWheelShouldRetainSelf();
 | |
| 
 | |
|     if (shouldRetainSelf)
 | |
|         [self retain];
 | |
|     originalNSScrollViewScrollWheel(self, selector, event);
 | |
|     if (shouldRetainSelf)
 | |
|         [self release];
 | |
| }
 | |
| 
 | |
| bool EventHandler::passWheelEventToWidget(PlatformWheelEvent& wheelEvent, Widget* widget)
 | |
| {
 | |
|     BEGIN_BLOCK_OBJC_EXCEPTIONS;
 | |
| 
 | |
|     if (!widget)
 | |
|         return false;
 | |
| 
 | |
|     NSView* nodeView = widget->platformWidget();
 | |
|     if (!nodeView) {
 | |
|         // WebKit2 code path.
 | |
|         if (!widget->isFrameView())
 | |
|             return false;
 | |
| 
 | |
|         return static_cast<FrameView*>(widget)->frame()->eventHandler()->handleWheelEvent(wheelEvent);
 | |
|     }
 | |
| 
 | |
|     if ([currentNSEvent() type] != NSScrollWheel || m_sendingEventToSubview)
 | |
|         return false;
 | |
| 
 | |
|     ASSERT(nodeView);
 | |
|     ASSERT([nodeView superview]);
 | |
|     NSView *view = [nodeView hitTest:[[nodeView superview] convertPoint:[currentNSEvent() locationInWindow] fromView:nil]];
 | |
|     if (!view)
 | |
|         // We probably hit the border of a RenderWidget
 | |
|         return false;
 | |
| 
 | |
|     ASSERT(!m_sendingEventToSubview);
 | |
|     m_sendingEventToSubview = true;
 | |
|     // Work around <rdar://problem/6806810> which can cause -[NSScrollView scrollWheel:] to
 | |
|     // crash if the NSScrollView is released during timer or network callback dispatch
 | |
|     // in the nested tracking runloop that -[NSScrollView scrollWheel:] runs.
 | |
|     setNSScrollViewScrollWheelShouldRetainSelf(true);
 | |
|     [view scrollWheel:currentNSEvent()];
 | |
|     setNSScrollViewScrollWheelShouldRetainSelf(false);
 | |
|     m_sendingEventToSubview = false;
 | |
|     return true;
 | |
| 
 | |
|     END_BLOCK_OBJC_EXCEPTIONS;
 | |
|     return false;
 | |
| }
 | |
| 
 | |
| void EventHandler::mouseDown(NSEvent *event)
 | |
| {
 | |
|     FrameView* v = m_frame->view();
 | |
|     if (!v || m_sendingEventToSubview)
 | |
|         return;
 | |
| 
 | |
|     BEGIN_BLOCK_OBJC_EXCEPTIONS;
 | |
| 
 | |
|     m_frame->loader()->resetMultipleFormSubmissionProtection();
 | |
| 
 | |
|     m_mouseDownView = nil;
 | |
| 
 | |
|     CurrentEventScope scope(event);
 | |
| 
 | |
|     handleMousePressEvent(currentPlatformMouseEvent());
 | |
| 
 | |
|     END_BLOCK_OBJC_EXCEPTIONS;
 | |
| }
 | |
| 
 | |
| void EventHandler::mouseDragged(NSEvent *event)
 | |
| {
 | |
|     FrameView* v = m_frame->view();
 | |
|     if (!v || m_sendingEventToSubview)
 | |
|         return;
 | |
| 
 | |
|     BEGIN_BLOCK_OBJC_EXCEPTIONS;
 | |
| 
 | |
|     CurrentEventScope scope(event);
 | |
|     handleMouseMoveEvent(currentPlatformMouseEvent());
 | |
| 
 | |
|     END_BLOCK_OBJC_EXCEPTIONS;
 | |
| }
 | |
| 
 | |
| void EventHandler::mouseUp(NSEvent *event)
 | |
| {
 | |
|     FrameView* v = m_frame->view();
 | |
|     if (!v || m_sendingEventToSubview)
 | |
|         return;
 | |
| 
 | |
|     BEGIN_BLOCK_OBJC_EXCEPTIONS;
 | |
| 
 | |
|     CurrentEventScope scope(event);
 | |
| 
 | |
|     // Our behavior here is a little different that Qt. Qt always sends
 | |
|     // a mouse release event, even for a double click. To correct problems
 | |
|     // in khtml's DOM click event handling we do not send a release here
 | |
|     // for a double click. Instead we send that event from FrameView's
 | |
|     // handleMouseDoubleClickEvent. Note also that the third click of
 | |
|     // a triple click is treated as a single click, but the fourth is then
 | |
|     // treated as another double click. Hence the "% 2" below.
 | |
|     int clickCount = [event clickCount];
 | |
|     if (clickCount > 0 && clickCount % 2 == 0)
 | |
|         handleMouseDoubleClickEvent(currentPlatformMouseEvent());
 | |
|     else
 | |
|         handleMouseReleaseEvent(currentPlatformMouseEvent());
 | |
| 
 | |
|     m_mouseDownView = nil;
 | |
| 
 | |
|     END_BLOCK_OBJC_EXCEPTIONS;
 | |
| }
 | |
| 
 | |
| /*
 | |
|  A hack for the benefit of AK's PopUpButton, which uses the Carbon menu manager, which thus
 | |
|  eats all subsequent events after it is starts its modal tracking loop.  After the interaction
 | |
|  is done, this routine is used to fix things up.  When a mouse down started us tracking in
 | |
|  the widget, we post a fake mouse up to balance the mouse down we started with. When a
 | |
|  key down started us tracking in the widget, we post a fake key up to balance things out.
 | |
|  In addition, we post a fake mouseMoved to get the cursor in sync with whatever we happen to
 | |
|  be over after the tracking is done.
 | |
|  */
 | |
| void EventHandler::sendFakeEventsAfterWidgetTracking(NSEvent *initiatingEvent)
 | |
| {
 | |
|     FrameView* view = m_frame->view();
 | |
|     if (!view)
 | |
|         return;
 | |
| 
 | |
|     BEGIN_BLOCK_OBJC_EXCEPTIONS;
 | |
| 
 | |
|     m_sendingEventToSubview = false;
 | |
|     int eventType = [initiatingEvent type];
 | |
|     if (eventType == NSLeftMouseDown || eventType == NSKeyDown) {
 | |
|         NSEvent *fakeEvent = nil;
 | |
|         if (eventType == NSLeftMouseDown) {
 | |
|             fakeEvent = [NSEvent mouseEventWithType:NSLeftMouseUp
 | |
|                                            location:[initiatingEvent locationInWindow]
 | |
|                                       modifierFlags:[initiatingEvent modifierFlags]
 | |
|                                           timestamp:[initiatingEvent timestamp]
 | |
|                                        windowNumber:[initiatingEvent windowNumber]
 | |
|                                             context:[initiatingEvent context]
 | |
|                                         eventNumber:[initiatingEvent eventNumber]
 | |
|                                          clickCount:[initiatingEvent clickCount]
 | |
|                                            pressure:[initiatingEvent pressure]];
 | |
| 
 | |
|             [NSApp postEvent:fakeEvent atStart:YES];
 | |
|         } else { // eventType == NSKeyDown
 | |
|             fakeEvent = [NSEvent keyEventWithType:NSKeyUp
 | |
|                                          location:[initiatingEvent locationInWindow]
 | |
|                                     modifierFlags:[initiatingEvent modifierFlags]
 | |
|                                         timestamp:[initiatingEvent timestamp]
 | |
|                                      windowNumber:[initiatingEvent windowNumber]
 | |
|                                           context:[initiatingEvent context]
 | |
|                                        characters:[initiatingEvent characters]
 | |
|                       charactersIgnoringModifiers:[initiatingEvent charactersIgnoringModifiers]
 | |
|                                         isARepeat:[initiatingEvent isARepeat]
 | |
|                                           keyCode:[initiatingEvent keyCode]];
 | |
|             [NSApp postEvent:fakeEvent atStart:YES];
 | |
|         }
 | |
|         // FIXME: We should really get the current modifierFlags here, but there's no way to poll
 | |
|         // them in Cocoa, and because the event stream was stolen by the Carbon menu code we have
 | |
|         // no up-to-date cache of them anywhere.
 | |
|         fakeEvent = [NSEvent mouseEventWithType:NSMouseMoved
 | |
|                                        location:[[view->platformWidget() window] convertScreenToBase:[NSEvent mouseLocation]]
 | |
|                                   modifierFlags:[initiatingEvent modifierFlags]
 | |
|                                       timestamp:[initiatingEvent timestamp]
 | |
|                                    windowNumber:[initiatingEvent windowNumber]
 | |
|                                         context:[initiatingEvent context]
 | |
|                                     eventNumber:0
 | |
|                                      clickCount:0
 | |
|                                        pressure:0];
 | |
|         [NSApp postEvent:fakeEvent atStart:YES];
 | |
|     }
 | |
| 
 | |
|     END_BLOCK_OBJC_EXCEPTIONS;
 | |
| }
 | |
| 
 | |
| void EventHandler::mouseMoved(NSEvent *event)
 | |
| {
 | |
|     // Reject a mouse moved if the button is down - screws up tracking during autoscroll
 | |
|     // These happen because WebKit sometimes has to fake up moved events.
 | |
|     if (!m_frame->view() || m_mousePressed || m_sendingEventToSubview)
 | |
|         return;
 | |
| 
 | |
|     BEGIN_BLOCK_OBJC_EXCEPTIONS;
 | |
|     CurrentEventScope scope(event);
 | |
|     mouseMoved(currentPlatformMouseEvent());
 | |
|     END_BLOCK_OBJC_EXCEPTIONS;
 | |
| }
 | |
| 
 | |
| static bool frameHasPlatformWidget(Frame* frame)
 | |
| {
 | |
|     if (FrameView* frameView = frame->view()) {
 | |
|         if (frameView->platformWidget())
 | |
|             return true;
 | |
|     }
 | |
| 
 | |
|     return false;
 | |
| }
 | |
| 
 | |
| bool EventHandler::passMousePressEventToSubframe(MouseEventWithHitTestResults& mev, Frame* subframe)
 | |
| {
 | |
|     // WebKit1 code path.
 | |
|     if (frameHasPlatformWidget(m_frame))
 | |
|         return passSubframeEventToSubframe(mev, subframe);
 | |
| 
 | |
|     // WebKit2 code path.
 | |
|     subframe->eventHandler()->handleMousePressEvent(mev.event());
 | |
|     return true;
 | |
| }
 | |
| 
 | |
| bool EventHandler::passMouseMoveEventToSubframe(MouseEventWithHitTestResults& mev, Frame* subframe, HitTestResult* hoveredNode)
 | |
| {
 | |
|     // WebKit1 code path.
 | |
|     if (frameHasPlatformWidget(m_frame))
 | |
|         return passSubframeEventToSubframe(mev, subframe, hoveredNode);
 | |
| 
 | |
|     // WebKit2 code path.
 | |
|     if (m_mouseDownMayStartDrag && !m_mouseDownWasInSubframe)
 | |
|         return false;
 | |
|     subframe->eventHandler()->handleMouseMoveEvent(mev.event(), hoveredNode);
 | |
|     return true;
 | |
| }
 | |
| 
 | |
| bool EventHandler::passMouseReleaseEventToSubframe(MouseEventWithHitTestResults& mev, Frame* subframe)
 | |
| {
 | |
|     // WebKit1 code path.
 | |
|     if (frameHasPlatformWidget(m_frame))
 | |
|         return passSubframeEventToSubframe(mev, subframe);
 | |
| 
 | |
|     // WebKit2 code path.
 | |
|     subframe->eventHandler()->handleMouseReleaseEvent(mev.event());
 | |
|     return true;
 | |
| }
 | |
| 
 | |
| PlatformMouseEvent EventHandler::currentPlatformMouseEvent() const
 | |
| {
 | |
|     NSView *windowView = nil;
 | |
|     if (Page* page = m_frame->page())
 | |
|         windowView = page->chrome()->platformPageClient();
 | |
|     return PlatformMouseEvent(currentNSEvent(), windowView);
 | |
| }
 | |
| 
 | |
| #if ENABLE(CONTEXT_MENUS)
 | |
| bool EventHandler::sendContextMenuEvent(NSEvent *event)
 | |
| {
 | |
|     Page* page = m_frame->page();
 | |
|     if (!page)
 | |
|         return false;
 | |
|     return sendContextMenuEvent(PlatformMouseEvent(event, page->chrome()->platformPageClient()));
 | |
| }
 | |
| #endif // ENABLE(CONTEXT_MENUS)
 | |
| 
 | |
| #if ENABLE(DRAG_SUPPORT)
 | |
| bool EventHandler::eventMayStartDrag(NSEvent *event)
 | |
| {
 | |
|     Page* page = m_frame->page();
 | |
|     if (!page)
 | |
|         return false;
 | |
|     return eventMayStartDrag(PlatformMouseEvent(event, page->chrome()->platformPageClient()));
 | |
| }
 | |
| #endif // ENABLE(DRAG_SUPPORT)
 | |
| 
 | |
| bool EventHandler::eventActivatedView(const PlatformMouseEvent& event) const
 | |
| {
 | |
|     return m_activationEventNumber == event.eventNumber();
 | |
| }
 | |
| 
 | |
| #if ENABLE(DRAG_SUPPORT)
 | |
| 
 | |
| PassRefPtr<Clipboard> EventHandler::createDraggingClipboard() const
 | |
| {
 | |
|     NSPasteboard *pasteboard = [NSPasteboard pasteboardWithName:NSDragPboard];
 | |
|     // Must be done before ondragstart adds types and data to the pboard,
 | |
|     // also done for security, as it erases data from the last drag
 | |
|     [pasteboard declareTypes:[NSArray array] owner:nil];
 | |
|     return ClipboardMac::create(Clipboard::DragAndDrop, pasteboard, ClipboardWritable, m_frame);
 | |
| }
 | |
| 
 | |
| #endif
 | |
| 
 | |
| bool EventHandler::tabsToAllFormControls(KeyboardEvent* event) const
 | |
| {
 | |
|     Page* page = m_frame->page();
 | |
|     if (!page)
 | |
|         return false;
 | |
| 
 | |
|     KeyboardUIMode keyboardUIMode = page->chrome()->client()->keyboardUIMode();
 | |
|     bool handlingOptionTab = isKeyboardOptionTab(event);
 | |
| 
 | |
|     // If tab-to-links is off, option-tab always highlights all controls
 | |
|     if ((keyboardUIMode & KeyboardAccessTabsToLinks) == 0 && handlingOptionTab)
 | |
|         return true;
 | |
| 
 | |
|     // If system preferences say to include all controls, we always include all controls
 | |
|     if (keyboardUIMode & KeyboardAccessFull)
 | |
|         return true;
 | |
| 
 | |
|     // Otherwise tab-to-links includes all controls, unless the sense is flipped via option-tab.
 | |
|     if (keyboardUIMode & KeyboardAccessTabsToLinks)
 | |
|         return !handlingOptionTab;
 | |
| 
 | |
|     return handlingOptionTab;
 | |
| }
 | |
| 
 | |
| bool EventHandler::needsKeyboardEventDisambiguationQuirks() const
 | |
| {
 | |
|     Document* document = m_frame->document();
 | |
| 
 | |
|     // RSS view needs arrow key keypress events.
 | |
|     if (applicationIsSafari() && (document->url().protocolIs("feed") || document->url().protocolIs("feeds")))
 | |
|         return true;
 | |
|     Settings* settings = m_frame->settings();
 | |
|     if (!settings)
 | |
|         return false;
 | |
| 
 | |
| #if ENABLE(DASHBOARD_SUPPORT)
 | |
|     if (settings->usesDashboardBackwardCompatibilityMode())
 | |
|         return true;
 | |
| #endif
 | |
| 
 | |
|     if (settings->needsKeyboardEventDisambiguationQuirks())
 | |
|         return true;
 | |
| 
 | |
|     return false;
 | |
| }
 | |
| 
 | |
| unsigned EventHandler::accessKeyModifiers()
 | |
| {
 | |
|     // Control+Option key combinations are usually unused on Mac OS X, but not when VoiceOver is enabled.
 | |
|     // So, we use Control in this case, even though it conflicts with Emacs-style key bindings.
 | |
|     // See <https://bugs.webkit.org/show_bug.cgi?id=21107> for more detail.
 | |
|     if (AXObjectCache::accessibilityEnhancedUserInterfaceEnabled())
 | |
|         return PlatformKeyboardEvent::CtrlKey;
 | |
| 
 | |
|     return PlatformKeyboardEvent::CtrlKey | PlatformKeyboardEvent::AltKey;
 | |
| }
 | |
| 
 | |
| }
 |