mirror of
https://github.com/KevinMidboe/linguist.git
synced 2025-10-28 17:20:22 +00:00
Add Objective-C++ samples
This commit is contained in:
778
samples/Objective-C++/EventHandlerMac.mm
Normal file
778
samples/Objective-C++/EventHandlerMac.mm
Normal file
@@ -0,0 +1,778 @@
|
||||
// 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;
|
||||
}
|
||||
|
||||
}
|
||||
1372
samples/Objective-C++/objsql.mm
Normal file
1372
samples/Objective-C++/objsql.mm
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user