~ubuntu-branches/ubuntu/raring/qtwebkit-source/raring-proposed

« back to all changes in this revision

Viewing changes to Source/WebCore/page/mac/EventHandlerMac.mm

  • Committer: Package Import Robot
  • Author(s): Jonathan Riddell
  • Date: 2013-02-18 14:24:18 UTC
  • Revision ID: package-import@ubuntu.com-20130218142418-eon0jmjg3nj438uy
Tags: upstream-2.3
ImportĀ upstreamĀ versionĀ 2.3

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (C) 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
 
3
 *
 
4
 * Redistribution and use in source and binary forms, with or without
 
5
 * modification, are permitted provided that the following conditions
 
6
 * are met:
 
7
 * 1. Redistributions of source code must retain the above copyright
 
8
 *    notice, this list of conditions and the following disclaimer.
 
9
 * 2. Redistributions in binary form must reproduce the above copyright
 
10
 *    notice, this list of conditions and the following disclaimer in the
 
11
 *    documentation and/or other materials provided with the distribution.
 
12
 *
 
13
 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
 
14
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 
15
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 
16
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
 
17
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 
18
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 
19
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 
20
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
 
21
 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 
22
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 
23
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
 
24
 */
 
25
 
 
26
#include "config.h"
 
27
#include "EventHandler.h"
 
28
 
 
29
#include "AXObjectCache.h"
 
30
#include "BlockExceptions.h"
 
31
#include "Chrome.h"
 
32
#include "ChromeClient.h"
 
33
#include "ClipboardMac.h"
 
34
#include "DragController.h"
 
35
#include "EventNames.h"
 
36
#include "FocusController.h"
 
37
#include "Frame.h"
 
38
#include "FrameLoader.h"
 
39
#include "FrameView.h"
 
40
#include "KeyboardEvent.h"
 
41
#include "MouseEventWithHitTestResults.h"
 
42
#include "NotImplemented.h"
 
43
#include "Page.h"
 
44
#include "Pasteboard.h"
 
45
#include "PlatformEventFactoryMac.h"
 
46
#include "RenderWidget.h"
 
47
#include "RuntimeApplicationChecks.h"
 
48
#include "Scrollbar.h"
 
49
#include "Settings.h"
 
50
#include "WebCoreSystemInterface.h"
 
51
#include <wtf/MainThread.h>
 
52
#include <wtf/ObjcRuntimeExtras.h>
 
53
#include <wtf/StdLibExtras.h>
 
54
 
 
55
namespace WebCore {
 
56
 
 
57
#if ENABLE(DRAG_SUPPORT)
 
58
const double EventHandler::TextDragDelay = 0.15;
 
59
#endif
 
60
 
 
61
static RetainPtr<NSEvent>& currentNSEventSlot()
 
62
{
 
63
    DEFINE_STATIC_LOCAL(RetainPtr<NSEvent>, event, ());
 
64
    return event;
 
65
}
 
66
 
 
67
NSEvent *EventHandler::currentNSEvent()
 
68
{
 
69
    return currentNSEventSlot().get();
 
70
}
 
71
 
 
72
class CurrentEventScope {
 
73
     WTF_MAKE_NONCOPYABLE(CurrentEventScope);
 
74
public:
 
75
    CurrentEventScope(NSEvent *);
 
76
    ~CurrentEventScope();
 
77
 
 
78
private:
 
79
    RetainPtr<NSEvent> m_savedCurrentEvent;
 
80
#ifndef NDEBUG
 
81
    RetainPtr<NSEvent> m_event;
 
82
#endif
 
83
};
 
84
 
 
85
inline CurrentEventScope::CurrentEventScope(NSEvent *event)
 
86
    : m_savedCurrentEvent(currentNSEventSlot())
 
87
#ifndef NDEBUG
 
88
    , m_event(event)
 
89
#endif
 
90
{
 
91
    currentNSEventSlot() = event;
 
92
}
 
93
 
 
94
inline CurrentEventScope::~CurrentEventScope()
 
95
{
 
96
    ASSERT(currentNSEventSlot() == m_event);
 
97
    currentNSEventSlot() = m_savedCurrentEvent;
 
98
}
 
99
 
 
100
bool EventHandler::wheelEvent(NSEvent *event)
 
101
{
 
102
    Page* page = m_frame->page();
 
103
    if (!page)
 
104
        return false;
 
105
 
 
106
    CurrentEventScope scope(event);
 
107
    return handleWheelEvent(PlatformEventFactory::createPlatformWheelEvent(event, page->chrome()->platformPageClient()));
 
108
}
 
109
 
 
110
bool EventHandler::keyEvent(NSEvent *event)
 
111
{
 
112
    BEGIN_BLOCK_OBJC_EXCEPTIONS;
 
113
 
 
114
    ASSERT([event type] == NSKeyDown || [event type] == NSKeyUp);
 
115
 
 
116
    CurrentEventScope scope(event);
 
117
    return keyEvent(PlatformEventFactory::createPlatformKeyboardEvent(event));
 
118
 
 
119
    END_BLOCK_OBJC_EXCEPTIONS;
 
120
 
 
121
    return false;
 
122
}
 
123
 
 
124
void EventHandler::focusDocumentView()
 
125
{
 
126
    Page* page = m_frame->page();
 
127
    if (!page)
 
128
        return;
 
129
 
 
130
    if (FrameView* frameView = m_frame->view()) {
 
131
        if (NSView *documentView = frameView->documentView())
 
132
            page->chrome()->focusNSView(documentView);
 
133
    }
 
134
 
 
135
    page->focusController()->setFocusedFrame(m_frame);
 
136
}
 
137
 
 
138
bool EventHandler::passWidgetMouseDownEventToWidget(const MouseEventWithHitTestResults& event)
 
139
{
 
140
    // Figure out which view to send the event to.
 
141
    RenderObject* target = event.targetNode() ? event.targetNode()->renderer() : 0;
 
142
    if (!target || !target->isWidget())
 
143
        return false;
 
144
    
 
145
    // Double-click events don't exist in Cocoa. Since passWidgetMouseDownEventToWidget will
 
146
    // just pass currentEvent down to the widget, we don't want to call it for events that
 
147
    // don't correspond to Cocoa events.  The mousedown/ups will have already been passed on as
 
148
    // part of the pressed/released handling.
 
149
    return passMouseDownEventToWidget(toRenderWidget(target)->widget());
 
150
}
 
151
 
 
152
bool EventHandler::passWidgetMouseDownEventToWidget(RenderWidget* renderWidget)
 
153
{
 
154
    return passMouseDownEventToWidget(renderWidget->widget());
 
155
}
 
156
 
 
157
static bool lastEventIsMouseUp()
 
158
{
 
159
    // Many AppKit widgets run their own event loops and consume events while the mouse is down.
 
160
    // When they finish, currentEvent is the mouseUp that they exited on. We need to update
 
161
    // the WebCore state with this mouseUp, which we never saw. This method lets us detect
 
162
    // that state. Handling this was critical when we used AppKit widgets for form elements.
 
163
    // It's not clear in what cases this is helpful now -- it's possible it can be removed. 
 
164
 
 
165
    BEGIN_BLOCK_OBJC_EXCEPTIONS;
 
166
    NSEvent *currentEventAfterHandlingMouseDown = [NSApp currentEvent];
 
167
    return EventHandler::currentNSEvent() != currentEventAfterHandlingMouseDown
 
168
        && [currentEventAfterHandlingMouseDown type] == NSLeftMouseUp
 
169
        && [currentEventAfterHandlingMouseDown timestamp] >= [EventHandler::currentNSEvent() timestamp];
 
170
    END_BLOCK_OBJC_EXCEPTIONS;
 
171
 
 
172
    return false;
 
173
}
 
174
 
 
175
bool EventHandler::passMouseDownEventToWidget(Widget* pWidget)
 
176
{
 
177
    // FIXME: This function always returns true. It should be changed either to return
 
178
    // false in some cases or the return value should be removed.
 
179
    
 
180
    RefPtr<Widget> widget = pWidget;
 
181
 
 
182
    if (!widget) {
 
183
        LOG_ERROR("hit a RenderWidget without a corresponding Widget, means a frame is half-constructed");
 
184
        return true;
 
185
    }
 
186
 
 
187
    // In WebKit2 we will never have an NSView. Just return early and let the regular event handler machinery take care of
 
188
    // dispatching the event.
 
189
    if (!widget->platformWidget())
 
190
        return false;
 
191
 
 
192
    BEGIN_BLOCK_OBJC_EXCEPTIONS;
 
193
    
 
194
    NSView *nodeView = widget->platformWidget();
 
195
    ASSERT([nodeView superview]);
 
196
    NSView *view = [nodeView hitTest:[[nodeView superview] convertPoint:[currentNSEvent() locationInWindow] fromView:nil]];
 
197
    if (!view) {
 
198
        // We probably hit the border of a RenderWidget
 
199
        return true;
 
200
    }
 
201
    
 
202
    Page* page = m_frame->page();
 
203
    if (!page)
 
204
        return true;
 
205
 
 
206
    if (page->chrome()->client()->firstResponder() != view) {
 
207
        // Normally [NSWindow sendEvent:] handles setting the first responder.
 
208
        // But in our case, the event was sent to the view representing the entire web page.
 
209
        if ([currentNSEvent() clickCount] <= 1 && [view acceptsFirstResponder] && [view needsPanelToBecomeKey])
 
210
            page->chrome()->client()->makeFirstResponder(view);
 
211
    }
 
212
 
 
213
    // We need to "defer loading" while tracking the mouse, because tearing down the
 
214
    // page while an AppKit control is tracking the mouse can cause a crash.
 
215
    
 
216
    // FIXME: In theory, WebCore now tolerates tear-down while tracking the
 
217
    // mouse. We should confirm that, and then remove the deferrsLoading
 
218
    // hack entirely.
 
219
    
 
220
    bool wasDeferringLoading = page->defersLoading();
 
221
    if (!wasDeferringLoading)
 
222
        page->setDefersLoading(true);
 
223
 
 
224
    ASSERT(!m_sendingEventToSubview);
 
225
    m_sendingEventToSubview = true;
 
226
 
 
227
    {
 
228
        WidgetHierarchyUpdatesSuspensionScope suspendWidgetHierarchyUpdates;
 
229
        [view mouseDown:currentNSEvent()];
 
230
    }
 
231
 
 
232
    m_sendingEventToSubview = false;
 
233
    
 
234
    if (!wasDeferringLoading)
 
235
        page->setDefersLoading(false);
 
236
 
 
237
    // Remember which view we sent the event to, so we can direct the release event properly.
 
238
    m_mouseDownView = view;
 
239
    m_mouseDownWasInSubframe = false;
 
240
    
 
241
    // Many AppKit widgets run their own event loops and consume events while the mouse is down.
 
242
    // When they finish, currentEvent is the mouseUp that they exited on.  We need to update
 
243
    // the EventHandler state with this mouseUp, which we never saw.
 
244
    // If this event isn't a mouseUp, we assume that the mouseUp will be coming later.  There
 
245
    // is a hole here if the widget consumes both the mouseUp and subsequent events.
 
246
    if (lastEventIsMouseUp())
 
247
        m_mousePressed = false;
 
248
 
 
249
    END_BLOCK_OBJC_EXCEPTIONS;
 
250
 
 
251
    return true;
 
252
}
 
253
    
 
254
// Note that this does the same kind of check as [target isDescendantOf:superview].
 
255
// There are two differences: This is a lot slower because it has to walk the whole
 
256
// tree, and this works in cases where the target has already been deallocated.
 
257
static bool findViewInSubviews(NSView *superview, NSView *target)
 
258
{
 
259
    BEGIN_BLOCK_OBJC_EXCEPTIONS;
 
260
    NSEnumerator *e = [[superview subviews] objectEnumerator];
 
261
    NSView *subview;
 
262
    while ((subview = [e nextObject])) {
 
263
        if (subview == target || findViewInSubviews(subview, target)) {
 
264
            return true;
 
265
        }
 
266
    }
 
267
    END_BLOCK_OBJC_EXCEPTIONS;
 
268
    
 
269
    return false;
 
270
}
 
271
 
 
272
NSView *EventHandler::mouseDownViewIfStillGood()
 
273
{
 
274
    // Since we have no way of tracking the lifetime of m_mouseDownView, we have to assume that
 
275
    // it could be deallocated already. We search for it in our subview tree; if we don't find
 
276
    // it, we set it to nil.
 
277
    NSView *mouseDownView = m_mouseDownView;
 
278
    if (!mouseDownView) {
 
279
        return nil;
 
280
    }
 
281
    FrameView* topFrameView = m_frame->view();
 
282
    NSView *topView = topFrameView ? topFrameView->platformWidget() : nil;
 
283
    if (!topView || !findViewInSubviews(topView, mouseDownView)) {
 
284
        m_mouseDownView = nil;
 
285
        return nil;
 
286
    }
 
287
    return mouseDownView;
 
288
}
 
289
 
 
290
#if ENABLE(DRAG_SUPPORT)
 
291
bool EventHandler::eventLoopHandleMouseDragged(const MouseEventWithHitTestResults&)
 
292
{
 
293
    NSView *view = mouseDownViewIfStillGood();
 
294
    
 
295
    if (!view)
 
296
        return false;
 
297
    
 
298
    if (!m_mouseDownWasInSubframe) {
 
299
        ASSERT(!m_sendingEventToSubview);
 
300
        m_sendingEventToSubview = true;
 
301
        BEGIN_BLOCK_OBJC_EXCEPTIONS;
 
302
        [view mouseDragged:currentNSEvent()];
 
303
        END_BLOCK_OBJC_EXCEPTIONS;
 
304
        m_sendingEventToSubview = false;
 
305
    }
 
306
    
 
307
    return true;
 
308
}
 
309
#endif // ENABLE(DRAG_SUPPORT)
 
310
    
 
311
bool EventHandler::eventLoopHandleMouseUp(const MouseEventWithHitTestResults&)
 
312
{
 
313
    NSView *view = mouseDownViewIfStillGood();
 
314
    if (!view)
 
315
        return false;
 
316
    
 
317
    if (!m_mouseDownWasInSubframe) {
 
318
        ASSERT(!m_sendingEventToSubview);
 
319
        m_sendingEventToSubview = true;
 
320
        BEGIN_BLOCK_OBJC_EXCEPTIONS;
 
321
        [view mouseUp:currentNSEvent()];
 
322
        END_BLOCK_OBJC_EXCEPTIONS;
 
323
        m_sendingEventToSubview = false;
 
324
    }
 
325
 
 
326
    return true;
 
327
}
 
328
    
 
329
bool EventHandler::passSubframeEventToSubframe(MouseEventWithHitTestResults& event, Frame* subframe, HitTestResult* hoveredNode)
 
330
{
 
331
    BEGIN_BLOCK_OBJC_EXCEPTIONS;
 
332
 
 
333
    switch ([currentNSEvent() type]) {
 
334
        case NSLeftMouseDragged:
 
335
        case NSOtherMouseDragged:
 
336
        case NSRightMouseDragged:
 
337
            // This check is bogus and results in <rdar://6813830>, but removing it breaks a number of
 
338
            // layout tests.
 
339
            if (!m_mouseDownWasInSubframe)
 
340
                return false;
 
341
#if ENABLE(DRAG_SUPPORT)
 
342
            if (subframe->page()->dragController()->didInitiateDrag())
 
343
                return false;
 
344
#endif
 
345
        case NSMouseMoved:
 
346
            // Since we're passing in currentNSEvent() here, we can call
 
347
            // handleMouseMoveEvent() directly, since the save/restore of
 
348
            // currentNSEvent() that mouseMoved() does would have no effect.
 
349
            ASSERT(!m_sendingEventToSubview);
 
350
            m_sendingEventToSubview = true;
 
351
            subframe->eventHandler()->handleMouseMoveEvent(currentPlatformMouseEvent(), hoveredNode);
 
352
            m_sendingEventToSubview = false;
 
353
            return true;
 
354
        
 
355
        case NSLeftMouseDown: {
 
356
            Node* node = event.targetNode();
 
357
            if (!node)
 
358
                return false;
 
359
            RenderObject* renderer = node->renderer();
 
360
            if (!renderer || !renderer->isWidget())
 
361
                return false;
 
362
            Widget* widget = toRenderWidget(renderer)->widget();
 
363
            if (!widget || !widget->isFrameView())
 
364
                return false;
 
365
            if (!passWidgetMouseDownEventToWidget(toRenderWidget(renderer)))
 
366
                return false;
 
367
            m_mouseDownWasInSubframe = true;
 
368
            return true;
 
369
        }
 
370
        case NSLeftMouseUp: {
 
371
            if (!m_mouseDownWasInSubframe)
 
372
                return false;
 
373
            ASSERT(!m_sendingEventToSubview);
 
374
            m_sendingEventToSubview = true;
 
375
            subframe->eventHandler()->handleMouseReleaseEvent(currentPlatformMouseEvent());
 
376
            m_sendingEventToSubview = false;
 
377
            return true;
 
378
        }
 
379
        default:
 
380
            return false;
 
381
    }
 
382
    END_BLOCK_OBJC_EXCEPTIONS;
 
383
 
 
384
    return false;
 
385
}
 
386
 
 
387
static IMP originalNSScrollViewScrollWheel;
 
388
static bool _nsScrollViewScrollWheelShouldRetainSelf;
 
389
static void selfRetainingNSScrollViewScrollWheel(NSScrollView *, SEL, NSEvent *);
 
390
 
 
391
static bool nsScrollViewScrollWheelShouldRetainSelf()
 
392
{
 
393
    ASSERT(isMainThread());
 
394
 
 
395
    return _nsScrollViewScrollWheelShouldRetainSelf;
 
396
}
 
397
 
 
398
static void setNSScrollViewScrollWheelShouldRetainSelf(bool shouldRetain)
 
399
{
 
400
    ASSERT(isMainThread());
 
401
 
 
402
    if (!originalNSScrollViewScrollWheel) {
 
403
        Method method = class_getInstanceMethod(objc_getRequiredClass("NSScrollView"), @selector(scrollWheel:));
 
404
        originalNSScrollViewScrollWheel = method_setImplementation(method, reinterpret_cast<IMP>(selfRetainingNSScrollViewScrollWheel));
 
405
    }
 
406
 
 
407
    _nsScrollViewScrollWheelShouldRetainSelf = shouldRetain;
 
408
}
 
409
 
 
410
static void selfRetainingNSScrollViewScrollWheel(NSScrollView *self, SEL selector, NSEvent *event)
 
411
{
 
412
    bool shouldRetainSelf = isMainThread() && nsScrollViewScrollWheelShouldRetainSelf();
 
413
 
 
414
    if (shouldRetainSelf)
 
415
        [self retain];
 
416
    wtfCallIMP<void>(originalNSScrollViewScrollWheel, self, selector, event);
 
417
    if (shouldRetainSelf)
 
418
        [self release];
 
419
}
 
420
 
 
421
bool EventHandler::passWheelEventToWidget(const PlatformWheelEvent& wheelEvent, Widget* widget)
 
422
{
 
423
    BEGIN_BLOCK_OBJC_EXCEPTIONS;
 
424
 
 
425
    if (!widget)
 
426
        return false;
 
427
 
 
428
    NSView* nodeView = widget->platformWidget();
 
429
    if (!nodeView) {
 
430
        // WebKit2 code path.
 
431
        if (!widget->isFrameView())
 
432
            return false;
 
433
 
 
434
        return static_cast<FrameView*>(widget)->frame()->eventHandler()->handleWheelEvent(wheelEvent);
 
435
    }
 
436
 
 
437
    if ([currentNSEvent() type] != NSScrollWheel || m_sendingEventToSubview) 
 
438
        return false;
 
439
 
 
440
    ASSERT(nodeView);
 
441
    ASSERT([nodeView superview]);
 
442
    NSView *view = [nodeView hitTest:[[nodeView superview] convertPoint:[currentNSEvent() locationInWindow] fromView:nil]];
 
443
    if (!view)
 
444
        // We probably hit the border of a RenderWidget
 
445
        return false;
 
446
 
 
447
    ASSERT(!m_sendingEventToSubview);
 
448
    m_sendingEventToSubview = true;
 
449
    // Work around <rdar://problem/6806810> which can cause -[NSScrollView scrollWheel:] to
 
450
    // crash if the NSScrollView is released during timer or network callback dispatch
 
451
    // in the nested tracking runloop that -[NSScrollView scrollWheel:] runs.
 
452
    setNSScrollViewScrollWheelShouldRetainSelf(true);
 
453
    [view scrollWheel:currentNSEvent()];
 
454
    setNSScrollViewScrollWheelShouldRetainSelf(false);
 
455
    m_sendingEventToSubview = false;
 
456
    return true;
 
457
            
 
458
    END_BLOCK_OBJC_EXCEPTIONS;
 
459
    return false;
 
460
}
 
461
 
 
462
void EventHandler::mouseDown(NSEvent *event)
 
463
{
 
464
    FrameView* v = m_frame->view();
 
465
    if (!v || m_sendingEventToSubview)
 
466
        return;
 
467
 
 
468
    BEGIN_BLOCK_OBJC_EXCEPTIONS;
 
469
    
 
470
    m_mouseDownView = nil;
 
471
    
 
472
    CurrentEventScope scope(event);
 
473
 
 
474
    handleMousePressEvent(currentPlatformMouseEvent());
 
475
 
 
476
    END_BLOCK_OBJC_EXCEPTIONS;
 
477
}
 
478
 
 
479
void EventHandler::mouseDragged(NSEvent *event)
 
480
{
 
481
    FrameView* v = m_frame->view();
 
482
    if (!v || m_sendingEventToSubview)
 
483
        return;
 
484
 
 
485
    BEGIN_BLOCK_OBJC_EXCEPTIONS;
 
486
 
 
487
    CurrentEventScope scope(event);
 
488
    handleMouseMoveEvent(currentPlatformMouseEvent());
 
489
 
 
490
    END_BLOCK_OBJC_EXCEPTIONS;
 
491
}
 
492
 
 
493
void EventHandler::mouseUp(NSEvent *event)
 
494
{
 
495
    FrameView* v = m_frame->view();
 
496
    if (!v || m_sendingEventToSubview)
 
497
        return;
 
498
 
 
499
    BEGIN_BLOCK_OBJC_EXCEPTIONS;
 
500
 
 
501
    CurrentEventScope scope(event);
 
502
 
 
503
    // Our behavior here is a little different that Qt. Qt always sends
 
504
    // a mouse release event, even for a double click. To correct problems
 
505
    // in khtml's DOM click event handling we do not send a release here
 
506
    // for a double click. Instead we send that event from FrameView's
 
507
    // handleMouseDoubleClickEvent. Note also that the third click of
 
508
    // a triple click is treated as a single click, but the fourth is then
 
509
    // treated as another double click. Hence the "% 2" below.
 
510
    int clickCount = [event clickCount];
 
511
    if (clickCount > 0 && clickCount % 2 == 0)
 
512
        handleMouseDoubleClickEvent(currentPlatformMouseEvent());
 
513
    else
 
514
        handleMouseReleaseEvent(currentPlatformMouseEvent());
 
515
    
 
516
    m_mouseDownView = nil;
 
517
 
 
518
    END_BLOCK_OBJC_EXCEPTIONS;
 
519
}
 
520
 
 
521
/*
 
522
 A hack for the benefit of AK's PopUpButton, which uses the Carbon menu manager, which thus
 
523
 eats all subsequent events after it is starts its modal tracking loop.  After the interaction
 
524
 is done, this routine is used to fix things up.  When a mouse down started us tracking in
 
525
 the widget, we post a fake mouse up to balance the mouse down we started with. When a 
 
526
 key down started us tracking in the widget, we post a fake key up to balance things out.
 
527
 In addition, we post a fake mouseMoved to get the cursor in sync with whatever we happen to 
 
528
 be over after the tracking is done.
 
529
 */
 
530
void EventHandler::sendFakeEventsAfterWidgetTracking(NSEvent *initiatingEvent)
 
531
{
 
532
    FrameView* view = m_frame->view();
 
533
    if (!view)
 
534
        return;
 
535
 
 
536
    BEGIN_BLOCK_OBJC_EXCEPTIONS;
 
537
 
 
538
    m_sendingEventToSubview = false;
 
539
    int eventType = [initiatingEvent type];
 
540
    if (eventType == NSLeftMouseDown || eventType == NSKeyDown) {
 
541
        NSEvent *fakeEvent = nil;
 
542
        if (eventType == NSLeftMouseDown) {
 
543
            fakeEvent = [NSEvent mouseEventWithType:NSLeftMouseUp
 
544
                                           location:[initiatingEvent locationInWindow]
 
545
                                      modifierFlags:[initiatingEvent modifierFlags]
 
546
                                          timestamp:[initiatingEvent timestamp]
 
547
                                       windowNumber:[initiatingEvent windowNumber]
 
548
                                            context:[initiatingEvent context]
 
549
                                        eventNumber:[initiatingEvent eventNumber]
 
550
                                         clickCount:[initiatingEvent clickCount]
 
551
                                           pressure:[initiatingEvent pressure]];
 
552
        
 
553
            [NSApp postEvent:fakeEvent atStart:YES];
 
554
        } else { // eventType == NSKeyDown
 
555
            fakeEvent = [NSEvent keyEventWithType:NSKeyUp
 
556
                                         location:[initiatingEvent locationInWindow]
 
557
                                    modifierFlags:[initiatingEvent modifierFlags]
 
558
                                        timestamp:[initiatingEvent timestamp]
 
559
                                     windowNumber:[initiatingEvent windowNumber]
 
560
                                          context:[initiatingEvent context]
 
561
                                       characters:[initiatingEvent characters] 
 
562
                      charactersIgnoringModifiers:[initiatingEvent charactersIgnoringModifiers] 
 
563
                                        isARepeat:[initiatingEvent isARepeat] 
 
564
                                          keyCode:[initiatingEvent keyCode]];
 
565
            [NSApp postEvent:fakeEvent atStart:YES];
 
566
        }
 
567
        // FIXME: We should really get the current modifierFlags here, but there's no way to poll
 
568
        // them in Cocoa, and because the event stream was stolen by the Carbon menu code we have
 
569
        // no up-to-date cache of them anywhere.
 
570
        fakeEvent = [NSEvent mouseEventWithType:NSMouseMoved
 
571
                                       location:[[view->platformWidget() window] convertScreenToBase:[NSEvent mouseLocation]]
 
572
                                  modifierFlags:[initiatingEvent modifierFlags]
 
573
                                      timestamp:[initiatingEvent timestamp]
 
574
                                   windowNumber:[initiatingEvent windowNumber]
 
575
                                        context:[initiatingEvent context]
 
576
                                    eventNumber:0
 
577
                                     clickCount:0
 
578
                                       pressure:0];
 
579
        [NSApp postEvent:fakeEvent atStart:YES];
 
580
    }
 
581
    
 
582
    END_BLOCK_OBJC_EXCEPTIONS;
 
583
}
 
584
 
 
585
void EventHandler::mouseMoved(NSEvent *event)
 
586
{
 
587
    // Reject a mouse moved if the button is down - screws up tracking during autoscroll
 
588
    // These happen because WebKit sometimes has to fake up moved events.
 
589
    if (!m_frame->view() || m_mousePressed || m_sendingEventToSubview)
 
590
        return;
 
591
    
 
592
    BEGIN_BLOCK_OBJC_EXCEPTIONS;
 
593
    CurrentEventScope scope(event);
 
594
    mouseMoved(currentPlatformMouseEvent());
 
595
    END_BLOCK_OBJC_EXCEPTIONS;
 
596
}
 
597
 
 
598
void EventHandler::passMouseMovedEventToScrollbars(NSEvent *event)
 
599
{
 
600
    // Reject a mouse moved if the button is down - screws up tracking during autoscroll
 
601
    // These happen because WebKit sometimes has to fake up moved events.
 
602
    if (!m_frame->view() || m_mousePressed || m_sendingEventToSubview)
 
603
        return;
 
604
 
 
605
    BEGIN_BLOCK_OBJC_EXCEPTIONS;
 
606
    CurrentEventScope scope(event);
 
607
    passMouseMovedEventToScrollbars(currentPlatformMouseEvent());
 
608
    END_BLOCK_OBJC_EXCEPTIONS;
 
609
}
 
610
 
 
611
static bool frameHasPlatformWidget(Frame* frame)
 
612
{
 
613
    if (FrameView* frameView = frame->view()) {
 
614
        if (frameView->platformWidget())
 
615
            return true;
 
616
    }
 
617
 
 
618
    return false;
 
619
}
 
620
 
 
621
bool EventHandler::passMousePressEventToSubframe(MouseEventWithHitTestResults& mev, Frame* subframe)
 
622
{
 
623
    // WebKit1 code path.
 
624
    if (frameHasPlatformWidget(m_frame))
 
625
        return passSubframeEventToSubframe(mev, subframe);
 
626
 
 
627
    // WebKit2 code path.
 
628
    subframe->eventHandler()->handleMousePressEvent(mev.event());
 
629
    return true;
 
630
}
 
631
 
 
632
bool EventHandler::passMouseMoveEventToSubframe(MouseEventWithHitTestResults& mev, Frame* subframe, HitTestResult* hoveredNode)
 
633
{
 
634
    // WebKit1 code path.
 
635
    if (frameHasPlatformWidget(m_frame))
 
636
        return passSubframeEventToSubframe(mev, subframe, hoveredNode);
 
637
 
 
638
#if ENABLE(DRAG_SUPPORT)
 
639
    // WebKit2 code path.
 
640
    if (m_mouseDownMayStartDrag && !m_mouseDownWasInSubframe)
 
641
        return false;
 
642
#endif
 
643
 
 
644
    subframe->eventHandler()->handleMouseMoveEvent(mev.event(), hoveredNode);
 
645
    return true;
 
646
}
 
647
 
 
648
bool EventHandler::passMouseReleaseEventToSubframe(MouseEventWithHitTestResults& mev, Frame* subframe)
 
649
{
 
650
    // WebKit1 code path.
 
651
    if (frameHasPlatformWidget(m_frame))
 
652
        return passSubframeEventToSubframe(mev, subframe);
 
653
 
 
654
    // WebKit2 code path.
 
655
    subframe->eventHandler()->handleMouseReleaseEvent(mev.event());
 
656
    return true;
 
657
}
 
658
 
 
659
PlatformMouseEvent EventHandler::currentPlatformMouseEvent() const
 
660
{
 
661
    NSView *windowView = nil;
 
662
    if (Page* page = m_frame->page())
 
663
        windowView = page->chrome()->platformPageClient();
 
664
    return PlatformEventFactory::createPlatformMouseEvent(currentNSEvent(), windowView);
 
665
}
 
666
 
 
667
bool EventHandler::eventActivatedView(const PlatformMouseEvent& event) const
 
668
{
 
669
    return m_activationEventNumber == event.eventNumber();
 
670
}
 
671
 
 
672
#if ENABLE(DRAG_SUPPORT)
 
673
 
 
674
PassRefPtr<Clipboard> EventHandler::createDraggingClipboard() const
 
675
{
 
676
    // Must be done before ondragstart adds types and data to the pboard,
 
677
    // also done for security, as it erases data from the last drag
 
678
    Pasteboard pasteboard(NSDragPboard);
 
679
    pasteboard.clear();
 
680
    return ClipboardMac::create(Clipboard::DragAndDrop, String(NSDragPboard), ClipboardWritable, ClipboardMac::DragAndDropData, m_frame);
 
681
}
 
682
 
 
683
#endif
 
684
 
 
685
bool EventHandler::tabsToAllFormControls(KeyboardEvent* event) const
 
686
{
 
687
    Page* page = m_frame->page();
 
688
    if (!page)
 
689
        return false;
 
690
 
 
691
    KeyboardUIMode keyboardUIMode = page->chrome()->client()->keyboardUIMode();
 
692
    bool handlingOptionTab = isKeyboardOptionTab(event);
 
693
 
 
694
    // If tab-to-links is off, option-tab always highlights all controls
 
695
    if ((keyboardUIMode & KeyboardAccessTabsToLinks) == 0 && handlingOptionTab)
 
696
        return true;
 
697
    
 
698
    // If system preferences say to include all controls, we always include all controls
 
699
    if (keyboardUIMode & KeyboardAccessFull)
 
700
        return true;
 
701
    
 
702
    // Otherwise tab-to-links includes all controls, unless the sense is flipped via option-tab.
 
703
    if (keyboardUIMode & KeyboardAccessTabsToLinks)
 
704
        return !handlingOptionTab;
 
705
    
 
706
    return handlingOptionTab;
 
707
}
 
708
 
 
709
bool EventHandler::needsKeyboardEventDisambiguationQuirks() const
 
710
{
 
711
    Settings* settings = m_frame->settings();
 
712
    if (!settings)
 
713
        return false;
 
714
 
 
715
#if ENABLE(DASHBOARD_SUPPORT)
 
716
    if (settings->usesDashboardBackwardCompatibilityMode())
 
717
        return true;
 
718
#endif
 
719
        
 
720
    if (settings->needsKeyboardEventDisambiguationQuirks())
 
721
        return true;
 
722
 
 
723
    return false;
 
724
}
 
725
 
 
726
unsigned EventHandler::accessKeyModifiers()
 
727
{
 
728
    // Control+Option key combinations are usually unused on Mac OS X, but not when VoiceOver is enabled.
 
729
    // So, we use Control in this case, even though it conflicts with Emacs-style key bindings.
 
730
    // See <https://bugs.webkit.org/show_bug.cgi?id=21107> for more detail.
 
731
    if (AXObjectCache::accessibilityEnhancedUserInterfaceEnabled())
 
732
        return PlatformEvent::CtrlKey;
 
733
 
 
734
    return PlatformEvent::CtrlKey | PlatformEvent::AltKey;
 
735
}
 
736
 
 
737
}