~ubuntu-branches/ubuntu/maverick/webkit/maverick

« back to all changes in this revision

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

  • Committer: Bazaar Package Importer
  • Author(s): Mike Hommey
  • Date: 2007-08-19 15:54:12 UTC
  • Revision ID: james.westby@ubuntu.com-20070819155412-uxxg1h9plpghmtbi
Tags: upstream-0~svn25144
ImportĀ upstreamĀ versionĀ 0~svn25144

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (C) 2006 Apple Computer, 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 "BlockExceptions.h"
 
30
#include "ClipboardMac.h"
 
31
#include "Cursor.h"
 
32
#include "Document.h"
 
33
#include "DragController.h"
 
34
#include "EventNames.h"
 
35
#include "FloatPoint.h"
 
36
#include "FocusController.h"
 
37
#include "FoundationExtras.h"
 
38
#include "FrameLoader.h"
 
39
#include "Frame.h"
 
40
#include "FrameTree.h"
 
41
#include "FrameView.h"
 
42
#include "HTMLFrameOwnerElement.h"
 
43
#include "HTMLFrameSetElement.h"
 
44
#include "HitTestRequest.h"
 
45
#include "HitTestResult.h"
 
46
#include "KeyboardEvent.h"
 
47
#include "MouseEventWithHitTestResults.h"
 
48
#include "Page.h"
 
49
#include "PlatformKeyboardEvent.h"
 
50
#include "PlatformScrollBar.h"
 
51
#include "PlatformWheelEvent.h"
 
52
#include "RenderWidget.h"
 
53
#include "WebCoreFrameBridge.h"
 
54
 
 
55
namespace WebCore {
 
56
 
 
57
using namespace EventNames;
 
58
 
 
59
static RetainPtr<NSEvent>& currentEvent()
 
60
{
 
61
    static RetainPtr<NSEvent> event;
 
62
    return event;
 
63
}
 
64
 
 
65
NSEvent *EventHandler::currentNSEvent()
 
66
{
 
67
    return currentEvent().get();
 
68
}
 
69
 
 
70
bool EventHandler::wheelEvent(NSEvent *event)
 
71
{
 
72
    RetainPtr<NSEvent> oldCurrentEvent = currentEvent();
 
73
    currentEvent() = event;
 
74
 
 
75
    PlatformWheelEvent wheelEvent(event);
 
76
    handleWheelEvent(wheelEvent);
 
77
 
 
78
    ASSERT(currentEvent() == event);
 
79
    currentEvent() = oldCurrentEvent;
 
80
 
 
81
    return wheelEvent.isAccepted();
 
82
}
 
83
 
 
84
PassRefPtr<KeyboardEvent> EventHandler::currentKeyboardEvent() const
 
85
{
 
86
    NSEvent *event = [NSApp currentEvent];
 
87
    if (!event)
 
88
        return 0;
 
89
    switch ([event type]) {
 
90
        case NSKeyDown:
 
91
        case NSKeyUp:
 
92
            return new KeyboardEvent(event, m_frame->document() ? m_frame->document()->defaultView() : 0);
 
93
        default:
 
94
            return 0;
 
95
    }
 
96
}
 
97
 
 
98
static inline bool isKeyboardOptionTab(KeyboardEvent* event)
 
99
{
 
100
    return event
 
101
    && (event->type() == keydownEvent || event->type() == keypressEvent)
 
102
    && event->altKey()
 
103
    && event->keyIdentifier() == "U+0009";    
 
104
}
 
105
 
 
106
bool EventHandler::invertSenseOfTabsToLinks(KeyboardEvent* event) const
 
107
{
 
108
    return isKeyboardOptionTab(event);
 
109
}
 
110
 
 
111
bool EventHandler::tabsToAllControls(KeyboardEvent* event) const
 
112
{
 
113
    KeyboardUIMode keyboardUIMode = [m_frame->bridge() keyboardUIMode];
 
114
    bool handlingOptionTab = isKeyboardOptionTab(event);
 
115
 
 
116
    // If tab-to-links is off, option-tab always highlights all controls
 
117
    if ((keyboardUIMode & KeyboardAccessTabsToLinks) == 0 && handlingOptionTab)
 
118
        return true;
 
119
    
 
120
    // If system preferences say to include all controls, we always include all controls
 
121
    if (keyboardUIMode & KeyboardAccessFull)
 
122
        return true;
 
123
    
 
124
    // Otherwise tab-to-links includes all controls, unless the sense is flipped via option-tab.
 
125
    if (keyboardUIMode & KeyboardAccessTabsToLinks)
 
126
        return !handlingOptionTab;
 
127
    
 
128
    return handlingOptionTab;
 
129
}
 
130
 
 
131
bool EventHandler::keyEvent(NSEvent *event)
 
132
{
 
133
    bool result;
 
134
    BEGIN_BLOCK_OBJC_EXCEPTIONS;
 
135
 
 
136
    ASSERT([event type] == NSKeyDown || [event type] == NSKeyUp);
 
137
 
 
138
    RetainPtr<NSEvent> oldCurrentEvent = currentEvent();
 
139
    currentEvent() = event;
 
140
 
 
141
    result = keyEvent(PlatformKeyboardEvent(event));
 
142
    
 
143
    ASSERT(currentEvent() == event);
 
144
    currentEvent() = oldCurrentEvent;
 
145
 
 
146
    return result;
 
147
 
 
148
    END_BLOCK_OBJC_EXCEPTIONS;
 
149
 
 
150
    return false;
 
151
}
 
152
 
 
153
void EventHandler::focusDocumentView()
 
154
{
 
155
    Page* page = m_frame->page();
 
156
    if (!page)
 
157
        return;
 
158
 
 
159
    if (FrameView* frameView = m_frame->view())
 
160
        if (NSView *documentView = frameView->getDocumentView())
 
161
            page->chrome()->focusNSView(documentView);
 
162
    
 
163
    page->focusController()->setFocusedFrame(m_frame);
 
164
}
 
165
 
 
166
bool EventHandler::passWidgetMouseDownEventToWidget(const MouseEventWithHitTestResults& event)
 
167
{
 
168
    // Figure out which view to send the event to.
 
169
    RenderObject* target = event.targetNode() ? event.targetNode()->renderer() : 0;
 
170
    if (!target || !target->isWidget())
 
171
        return false;
 
172
    
 
173
    // Double-click events don't exist in Cocoa. Since passWidgetMouseDownEventToWidget will
 
174
    // just pass currentEvent down to the widget, we don't want to call it for events that
 
175
    // don't correspond to Cocoa events.  The mousedown/ups will have already been passed on as
 
176
    // part of the pressed/released handling.
 
177
    return passMouseDownEventToWidget(static_cast<RenderWidget*>(target)->widget());
 
178
}
 
179
 
 
180
bool EventHandler::passWidgetMouseDownEventToWidget(RenderWidget* renderWidget)
 
181
{
 
182
    return passMouseDownEventToWidget(renderWidget->widget());
 
183
}
 
184
 
 
185
static bool lastEventIsMouseUp()
 
186
{
 
187
    // Many AK widgets run their own event loops and consume events while the mouse is down.
 
188
    // When they finish, currentEvent is the mouseUp that they exited on.  We need to update
 
189
    // the khtml state with this mouseUp, which khtml never saw.  This method lets us detect
 
190
    // that state.
 
191
 
 
192
    BEGIN_BLOCK_OBJC_EXCEPTIONS;
 
193
    NSEvent *currentEventAfterHandlingMouseDown = [NSApp currentEvent];
 
194
    if (currentEvent() != currentEventAfterHandlingMouseDown &&
 
195
        [currentEventAfterHandlingMouseDown type] == NSLeftMouseUp &&
 
196
        [currentEventAfterHandlingMouseDown timestamp] >= [currentEvent().get() timestamp])
 
197
            return true;
 
198
    END_BLOCK_OBJC_EXCEPTIONS;
 
199
 
 
200
    return false;
 
201
}
 
202
 
 
203
bool EventHandler::passMouseDownEventToWidget(Widget* widget)
 
204
{
 
205
    // FIXME: this method always returns true
 
206
 
 
207
    if (!widget) {
 
208
        LOG_ERROR("hit a RenderWidget without a corresponding Widget, means a frame is half-constructed");
 
209
        return true;
 
210
    }
 
211
 
 
212
    BEGIN_BLOCK_OBJC_EXCEPTIONS;
 
213
    
 
214
    NSView *nodeView = widget->getView();
 
215
    ASSERT(nodeView);
 
216
    ASSERT([nodeView superview]);
 
217
    NSView *view = [nodeView hitTest:[[nodeView superview] convertPoint:[currentEvent().get() locationInWindow] fromView:nil]];
 
218
    if (!view)
 
219
        // We probably hit the border of a RenderWidget
 
220
        return true;
 
221
    
 
222
    if ([m_frame->bridge() firstResponder] == view) {
 
223
        // In the case where we just became first responder, we should send the mouseDown:
 
224
        // to the NSTextField, not the NSTextField's editor. This code makes sure that happens.
 
225
        // If we don't do this, we see a flash of selected text when clicking in a text field.
 
226
        // FIXME: This is the only caller of textViewWasFirstResponderAtMouseDownTime. When we
 
227
        // eliminate all use of NSTextField/NSTextView in form fields we can eliminate this code,
 
228
        // and textViewWasFirstResponderAtMouseDownTime:, and the instance variable WebHTMLView
 
229
        // keeps solely to support textViewWasFirstResponderAtMouseDownTime:.
 
230
        if ([view isKindOfClass:[NSTextView class]] && ![m_frame->bridge() textViewWasFirstResponderAtMouseDownTime:(NSTextView *)view]) {
 
231
            NSView *superview = view;
 
232
            while (superview != nodeView) {
 
233
                superview = [superview superview];
 
234
                ASSERT(superview);
 
235
                if ([superview isKindOfClass:[NSControl class]]) {
 
236
                    NSControl *control = static_cast<NSControl*>(superview);
 
237
                    if ([control currentEditor] == view)
 
238
                        view = superview;
 
239
                    break;
 
240
                }
 
241
            }
 
242
        }
 
243
    } else {
 
244
        // Normally [NSWindow sendEvent:] handles setting the first responder.
 
245
        // But in our case, the event was sent to the view representing the entire web page.
 
246
        if ([currentEvent().get() clickCount] <= 1 && [view acceptsFirstResponder] && [view needsPanelToBecomeKey]) {
 
247
            [m_frame->bridge() makeFirstResponder:view];
 
248
        }
 
249
    }
 
250
 
 
251
    // We need to "defer loading" while tracking the mouse, because tearing down the
 
252
    // page while an AppKit control is tracking the mouse can cause a crash.
 
253
    
 
254
    // FIXME: In theory, WebCore now tolerates tear-down while tracking the
 
255
    // mouse. We should confirm that, and then remove the deferrsLoading
 
256
    // hack entirely.
 
257
    
 
258
    bool wasDeferringLoading = m_frame->page()->defersLoading();
 
259
    if (!wasDeferringLoading)
 
260
        m_frame->page()->setDefersLoading(true);
 
261
 
 
262
    ASSERT(!m_sendingEventToSubview);
 
263
    m_sendingEventToSubview = true;
 
264
    [view mouseDown:currentEvent().get()];
 
265
    m_sendingEventToSubview = false;
 
266
    
 
267
    if (!wasDeferringLoading)
 
268
        m_frame->page()->setDefersLoading(false);
 
269
 
 
270
    // Remember which view we sent the event to, so we can direct the release event properly.
 
271
    m_mouseDownView = view;
 
272
    m_mouseDownWasInSubframe = false;
 
273
    
 
274
    // Many AppKit widgets run their own event loops and consume events while the mouse is down.
 
275
    // When they finish, currentEvent is the mouseUp that they exited on.  We need to update
 
276
    // the EventHandler state with this mouseUp, which we never saw.
 
277
    // If this event isn't a mouseUp, we assume that the mouseUp will be coming later.  There
 
278
    // is a hole here if the widget consumes both the mouseUp and subsequent events.
 
279
    if (lastEventIsMouseUp())
 
280
        m_mousePressed = false;
 
281
 
 
282
    END_BLOCK_OBJC_EXCEPTIONS;
 
283
 
 
284
    return true;
 
285
}
 
286
    
 
287
// Note that this does the same kind of check as [target isDescendantOf:superview].
 
288
// There are two differences: This is a lot slower because it has to walk the whole
 
289
// tree, and this works in cases where the target has already been deallocated.
 
290
static bool findViewInSubviews(NSView *superview, NSView *target)
 
291
{
 
292
    BEGIN_BLOCK_OBJC_EXCEPTIONS;
 
293
    NSEnumerator *e = [[superview subviews] objectEnumerator];
 
294
    NSView *subview;
 
295
    while ((subview = [e nextObject])) {
 
296
        if (subview == target || findViewInSubviews(subview, target)) {
 
297
            return true;
 
298
        }
 
299
    }
 
300
    END_BLOCK_OBJC_EXCEPTIONS;
 
301
    
 
302
    return false;
 
303
}
 
304
 
 
305
NSView *EventHandler::mouseDownViewIfStillGood()
 
306
{
 
307
    // Since we have no way of tracking the lifetime of m_mouseDownView, we have to assume that
 
308
    // it could be deallocated already. We search for it in our subview tree; if we don't find
 
309
    // it, we set it to nil.
 
310
    NSView *mouseDownView = m_mouseDownView;
 
311
    if (!mouseDownView) {
 
312
        return nil;
 
313
    }
 
314
    FrameView* topFrameView = m_frame->view();
 
315
    NSView *topView = topFrameView ? topFrameView->getView() : nil;
 
316
    if (!topView || !findViewInSubviews(topView, mouseDownView)) {
 
317
        m_mouseDownView = nil;
 
318
        return nil;
 
319
    }
 
320
    return mouseDownView;
 
321
}
 
322
 
 
323
bool EventHandler::eventActivatedView(const PlatformMouseEvent& event) const
 
324
{
 
325
    return m_activationEventNumber == event.eventNumber();
 
326
}
 
327
 
 
328
bool EventHandler::eventLoopHandleMouseDragged(const MouseEventWithHitTestResults&)
 
329
{
 
330
    NSView *view = mouseDownViewIfStillGood();
 
331
    
 
332
    if (!view)
 
333
        return false;
 
334
    
 
335
    if (!m_mouseDownWasInSubframe) {
 
336
        m_sendingEventToSubview = true;
 
337
        BEGIN_BLOCK_OBJC_EXCEPTIONS;
 
338
        [view mouseDragged:currentEvent().get()];
 
339
        END_BLOCK_OBJC_EXCEPTIONS;
 
340
        m_sendingEventToSubview = false;
 
341
    }
 
342
    
 
343
    return true;
 
344
}
 
345
    
 
346
Clipboard* EventHandler::createDraggingClipboard() const 
 
347
{
 
348
    NSPasteboard *pasteboard = [NSPasteboard pasteboardWithName:NSDragPboard];
 
349
    // Must be done before ondragstart adds types and data to the pboard,
 
350
    // also done for security, as it erases data from the last drag
 
351
    [pasteboard declareTypes:[NSArray array] owner:nil];
 
352
    return new ClipboardMac(true, pasteboard, ClipboardWritable, m_frame);
 
353
}
 
354
    
 
355
bool EventHandler::eventLoopHandleMouseUp(const MouseEventWithHitTestResults&)
 
356
{
 
357
    NSView *view = mouseDownViewIfStillGood();
 
358
    if (!view)
 
359
        return false;
 
360
    
 
361
    if (!m_mouseDownWasInSubframe) {
 
362
        m_sendingEventToSubview = true;
 
363
        BEGIN_BLOCK_OBJC_EXCEPTIONS;
 
364
        [view mouseUp:currentEvent().get()];
 
365
        END_BLOCK_OBJC_EXCEPTIONS;
 
366
        m_sendingEventToSubview = false;
 
367
    }
 
368
 
 
369
    return true;
 
370
}
 
371
    
 
372
bool EventHandler::passSubframeEventToSubframe(MouseEventWithHitTestResults& event, Frame* subframe, HitTestResult* hoveredNode)
 
373
{
 
374
    BEGIN_BLOCK_OBJC_EXCEPTIONS;
 
375
 
 
376
    switch ([currentEvent().get() type]) {
 
377
        case NSMouseMoved:
 
378
            // Since we're passing in currentEvent() here, we can call
 
379
            // handleMouseMoveEvent() directly, since the save/restore of
 
380
            // currentEvent() that mouseMoved() does would have no effect.
 
381
            subframe->eventHandler()->handleMouseMoveEvent(currentEvent().get(), hoveredNode);
 
382
            return true;
 
383
        
 
384
        case NSLeftMouseDown: {
 
385
            Node* node = event.targetNode();
 
386
            if (!node)
 
387
                return false;
 
388
            RenderObject* renderer = node->renderer();
 
389
            if (!renderer || !renderer->isWidget())
 
390
                return false;
 
391
            Widget* widget = static_cast<RenderWidget*>(renderer)->widget();
 
392
            if (!widget || !widget->isFrameView())
 
393
                return false;
 
394
            if (!passWidgetMouseDownEventToWidget(static_cast<RenderWidget*>(renderer)))
 
395
                return false;
 
396
            m_mouseDownWasInSubframe = true;
 
397
            return true;
 
398
        }
 
399
        case NSLeftMouseUp: {
 
400
            if (!m_mouseDownWasInSubframe)
 
401
                return false;
 
402
            NSView *view = mouseDownViewIfStillGood();
 
403
            if (!view)
 
404
                return false;
 
405
            ASSERT(!m_sendingEventToSubview);
 
406
            m_sendingEventToSubview = true;
 
407
            [view mouseUp:currentEvent().get()];
 
408
            m_sendingEventToSubview = false;
 
409
            return true;
 
410
        }
 
411
        case NSLeftMouseDragged: {
 
412
            if (!m_mouseDownWasInSubframe)
 
413
                return false;
 
414
            NSView *view = mouseDownViewIfStillGood();
 
415
            if (!view)
 
416
                return false;
 
417
            ASSERT(!m_sendingEventToSubview);
 
418
            m_sendingEventToSubview = true;
 
419
            [view mouseDragged:currentEvent().get()];
 
420
            m_sendingEventToSubview = false;
 
421
            return true;
 
422
        }
 
423
        default:
 
424
            return false;
 
425
    }
 
426
    END_BLOCK_OBJC_EXCEPTIONS;
 
427
 
 
428
    return false;
 
429
}
 
430
 
 
431
bool EventHandler::passWheelEventToWidget(PlatformWheelEvent&, Widget* widget)
 
432
{
 
433
    BEGIN_BLOCK_OBJC_EXCEPTIONS;
 
434
        
 
435
    if ([currentEvent().get() type] != NSScrollWheel || m_sendingEventToSubview || !widget) 
 
436
        return false;
 
437
 
 
438
    NSView *nodeView = widget->getView();
 
439
    ASSERT(nodeView);
 
440
    ASSERT([nodeView superview]);
 
441
    NSView *view = [nodeView hitTest:[[nodeView superview] convertPoint:[currentEvent().get() locationInWindow] fromView:nil]];
 
442
    if (!view)
 
443
        // We probably hit the border of a RenderWidget
 
444
        return false;
 
445
 
 
446
    m_sendingEventToSubview = true;
 
447
    [view scrollWheel:currentEvent().get()];
 
448
    m_sendingEventToSubview = false;
 
449
    return true;
 
450
            
 
451
    END_BLOCK_OBJC_EXCEPTIONS;
 
452
    return false;
 
453
}
 
454
 
 
455
void EventHandler::mouseDown(NSEvent *event)
 
456
{
 
457
    FrameView* v = m_frame->view();
 
458
    if (!v || m_sendingEventToSubview)
 
459
        return;
 
460
 
 
461
    BEGIN_BLOCK_OBJC_EXCEPTIONS;
 
462
    
 
463
    m_frame->loader()->resetMultipleFormSubmissionProtection();
 
464
 
 
465
    m_mouseDownView = nil;
 
466
    dragState().m_dragSrc = 0;
 
467
    
 
468
    RetainPtr<NSEvent> oldCurrentEvent = currentEvent();
 
469
    currentEvent() = event;
 
470
    m_mouseDown = PlatformMouseEvent(event);
 
471
    
 
472
    handleMousePressEvent(event);
 
473
    
 
474
    ASSERT(currentEvent() == event);
 
475
    currentEvent() = oldCurrentEvent;
 
476
 
 
477
    END_BLOCK_OBJC_EXCEPTIONS;
 
478
}
 
479
 
 
480
void EventHandler::mouseDragged(NSEvent *event)
 
481
{
 
482
    FrameView* v = m_frame->view();
 
483
    if (!v || m_sendingEventToSubview)
 
484
        return;
 
485
 
 
486
    BEGIN_BLOCK_OBJC_EXCEPTIONS;
 
487
 
 
488
    RetainPtr<NSEvent> oldCurrentEvent = currentEvent();
 
489
    currentEvent() = event;
 
490
 
 
491
    handleMouseMoveEvent(event);
 
492
    
 
493
    ASSERT(currentEvent() == event);
 
494
    currentEvent() = oldCurrentEvent;
 
495
 
 
496
    END_BLOCK_OBJC_EXCEPTIONS;
 
497
}
 
498
 
 
499
void EventHandler::mouseUp(NSEvent *event)
 
500
{
 
501
    FrameView* v = m_frame->view();
 
502
    if (!v || m_sendingEventToSubview)
 
503
        return;
 
504
 
 
505
    BEGIN_BLOCK_OBJC_EXCEPTIONS;
 
506
 
 
507
    RetainPtr<NSEvent> oldCurrentEvent = currentEvent();
 
508
    currentEvent() = event;
 
509
 
 
510
    // Our behavior here is a little different that Qt. Qt always sends
 
511
    // a mouse release event, even for a double click. To correct problems
 
512
    // in khtml's DOM click event handling we do not send a release here
 
513
    // for a double click. Instead we send that event from FrameView's
 
514
    // handleMouseDoubleClickEvent. Note also that the third click of
 
515
    // a triple click is treated as a single click, but the fourth is then
 
516
    // treated as another double click. Hence the "% 2" below.
 
517
    int clickCount = [event clickCount];
 
518
    if (clickCount > 0 && clickCount % 2 == 0)
 
519
        handleMouseDoubleClickEvent(event);
 
520
    else
 
521
        handleMouseReleaseEvent(event);
 
522
    
 
523
    ASSERT(currentEvent() == event);
 
524
    currentEvent() = oldCurrentEvent;
 
525
    
 
526
    m_mouseDownView = nil;
 
527
 
 
528
    END_BLOCK_OBJC_EXCEPTIONS;
 
529
}
 
530
 
 
531
/*
 
532
 A hack for the benefit of AK's PopUpButton, which uses the Carbon menu manager, which thus
 
533
 eats all subsequent events after it is starts its modal tracking loop.  After the interaction
 
534
 is done, this routine is used to fix things up.  When a mouse down started us tracking in
 
535
 the widget, we post a fake mouse up to balance the mouse down we started with. When a 
 
536
 key down started us tracking in the widget, we post a fake key up to balance things out.
 
537
 In addition, we post a fake mouseMoved to get the cursor in sync with whatever we happen to 
 
538
 be over after the tracking is done.
 
539
 */
 
540
void EventHandler::sendFakeEventsAfterWidgetTracking(NSEvent *initiatingEvent)
 
541
{
 
542
    BEGIN_BLOCK_OBJC_EXCEPTIONS;
 
543
 
 
544
    m_sendingEventToSubview = false;
 
545
    int eventType = [initiatingEvent type];
 
546
    if (eventType == NSLeftMouseDown || eventType == NSKeyDown) {
 
547
        NSEvent *fakeEvent = nil;
 
548
        if (eventType == NSLeftMouseDown) {
 
549
            fakeEvent = [NSEvent mouseEventWithType:NSLeftMouseUp
 
550
                                    location:[initiatingEvent locationInWindow]
 
551
                                modifierFlags:[initiatingEvent modifierFlags]
 
552
                                    timestamp:[initiatingEvent timestamp]
 
553
                                windowNumber:[initiatingEvent windowNumber]
 
554
                                        context:[initiatingEvent context]
 
555
                                    eventNumber:[initiatingEvent eventNumber]
 
556
                                    clickCount:[initiatingEvent clickCount]
 
557
                                    pressure:[initiatingEvent pressure]];
 
558
        
 
559
            [NSApp postEvent:fakeEvent atStart:YES];
 
560
        } else { // eventType == NSKeyDown
 
561
            fakeEvent = [NSEvent keyEventWithType:NSKeyUp
 
562
                                    location:[initiatingEvent locationInWindow]
 
563
                               modifierFlags:[initiatingEvent modifierFlags]
 
564
                                   timestamp:[initiatingEvent timestamp]
 
565
                                windowNumber:[initiatingEvent windowNumber]
 
566
                                     context:[initiatingEvent context]
 
567
                                  characters:[initiatingEvent characters] 
 
568
                 charactersIgnoringModifiers:[initiatingEvent charactersIgnoringModifiers] 
 
569
                                   isARepeat:[initiatingEvent isARepeat] 
 
570
                                     keyCode:[initiatingEvent keyCode]];
 
571
            [NSApp postEvent:fakeEvent atStart:YES];
 
572
        }
 
573
        // FIXME:  We should really get the current modifierFlags here, but there's no way to poll
 
574
        // them in Cocoa, and because the event stream was stolen by the Carbon menu code we have
 
575
        // no up-to-date cache of them anywhere.
 
576
        fakeEvent = [NSEvent mouseEventWithType:NSMouseMoved
 
577
                                       location:[[m_frame->bridge() window] convertScreenToBase:[NSEvent mouseLocation]]
 
578
                                  modifierFlags:[initiatingEvent modifierFlags]
 
579
                                      timestamp:[initiatingEvent timestamp]
 
580
                                   windowNumber:[initiatingEvent windowNumber]
 
581
                                        context:[initiatingEvent context]
 
582
                                    eventNumber:0
 
583
                                     clickCount:0
 
584
                                       pressure:0];
 
585
        [NSApp postEvent:fakeEvent atStart:YES];
 
586
    }
 
587
    
 
588
    END_BLOCK_OBJC_EXCEPTIONS;
 
589
}
 
590
 
 
591
void EventHandler::mouseMoved(NSEvent *event)
 
592
{
 
593
    // Reject a mouse moved if the button is down - screws up tracking during autoscroll
 
594
    // These happen because WebKit sometimes has to fake up moved events.
 
595
    if (!m_frame->view() || m_mousePressed || m_sendingEventToSubview)
 
596
        return;
 
597
    
 
598
    BEGIN_BLOCK_OBJC_EXCEPTIONS;
 
599
 
 
600
    RetainPtr<NSEvent> oldCurrentEvent = currentEvent();
 
601
    currentEvent() = event;
 
602
    
 
603
    mouseMoved(PlatformMouseEvent(event));
 
604
    
 
605
    ASSERT(currentEvent() == event);
 
606
    currentEvent() = oldCurrentEvent;
 
607
 
 
608
    END_BLOCK_OBJC_EXCEPTIONS;
 
609
}
 
610
 
 
611
bool EventHandler::passMousePressEventToSubframe(MouseEventWithHitTestResults& mev, Frame* subframe)
 
612
{
 
613
    return passSubframeEventToSubframe(mev, subframe);
 
614
}
 
615
 
 
616
bool EventHandler::passMouseMoveEventToSubframe(MouseEventWithHitTestResults& mev, Frame* subframe, HitTestResult* hoveredNode)
 
617
{
 
618
    return passSubframeEventToSubframe(mev, subframe, hoveredNode);
 
619
}
 
620
 
 
621
bool EventHandler::passMouseReleaseEventToSubframe(MouseEventWithHitTestResults& mev, Frame* subframe)
 
622
{
 
623
    return passSubframeEventToSubframe(mev, subframe);
 
624
}
 
625
 
 
626
bool EventHandler::passMousePressEventToScrollbar(MouseEventWithHitTestResults&, PlatformScrollbar* scrollbar)
 
627
{
 
628
    return passMouseDownEventToWidget(scrollbar);
 
629
}
 
630
 
 
631
}