Home | History | Annotate | Download | only in qt
      1 /*
      2  * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
      3  * Copyright (C) 2009 Torch Mobile Inc. http://www.torchmobile.com/
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions
      7  * are met:
      8  *
      9  * 1.  Redistributions of source code must retain the above copyright
     10  *     notice, this list of conditions and the following disclaimer.
     11  * 2.  Redistributions in binary form must reproduce the above copyright
     12  *     notice, this list of conditions and the following disclaimer in the
     13  *     documentation and/or other materials provided with the distribution.
     14  * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
     15  *     its contributors may be used to endorse or promote products derived
     16  *     from this software without specific prior written permission.
     17  *
     18  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
     19  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     20  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
     21  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
     22  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
     23  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
     24  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
     25  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     27  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     28  */
     29 #include "config.h"
     30 #include "EventSenderQt.h"
     31 
     32 #include <QGraphicsSceneMouseEvent>
     33 #include <QtTest/QtTest>
     34 
     35 #define KEYCODE_DEL         127
     36 #define KEYCODE_BACKSPACE   8
     37 #define KEYCODE_LEFTARROW   0xf702
     38 #define KEYCODE_RIGHTARROW  0xf703
     39 #define KEYCODE_UPARROW     0xf700
     40 #define KEYCODE_DOWNARROW   0xf701
     41 
     42 // Ports like Gtk and Windows expose a different approach for their zooming
     43 // API if compared to Qt: they have specific methods for zooming in and out,
     44 // as well as a settable zoom factor, while Qt has only a 'setZoomValue' method.
     45 // Hence Qt DRT adopts a fixed zoom-factor (1.2) for compatibility.
     46 #define ZOOM_STEP           1.2
     47 
     48 #define DRT_MESSAGE_DONE (QEvent::User + 1)
     49 
     50 struct DRTEventQueue {
     51     QEvent* m_event;
     52     int m_delay;
     53 };
     54 
     55 static DRTEventQueue eventQueue[1024];
     56 static unsigned endOfQueue;
     57 static unsigned startOfQueue;
     58 
     59 EventSender::EventSender(QWebPage* parent)
     60     : QObject(parent)
     61 {
     62     m_page = parent;
     63     m_mouseButtonPressed = false;
     64     m_drag = false;
     65     memset(eventQueue, 0, sizeof(eventQueue));
     66     endOfQueue = 0;
     67     startOfQueue = 0;
     68     m_eventLoop = 0;
     69     m_currentButton = 0;
     70     resetClickCount();
     71     m_page->view()->installEventFilter(this);
     72     // So that we can match Scrollbar::pixelsPerLineStep() in WheelEventQt.cpp and
     73     // pass fast/events/platform-wheelevent-in-scrolling-div.html
     74     QApplication::setWheelScrollLines(2);
     75 }
     76 
     77 void EventSender::mouseDown(int button)
     78 {
     79     Qt::MouseButton mouseButton;
     80     switch (button) {
     81     case 0:
     82         mouseButton = Qt::LeftButton;
     83         break;
     84     case 1:
     85         mouseButton = Qt::MidButton;
     86         break;
     87     case 2:
     88         mouseButton = Qt::RightButton;
     89         break;
     90     case 3:
     91         // fast/events/mouse-click-events expects the 4th button to be treated as the middle button
     92         mouseButton = Qt::MidButton;
     93         break;
     94     default:
     95         mouseButton = Qt::LeftButton;
     96         break;
     97     }
     98 
     99     // only consider a click to count, an event originated by the
    100     // same previous button and at the same position.
    101     if (m_currentButton == button
    102         && m_mousePos == m_clickPos
    103         && m_clickTimer.isActive())
    104         m_clickCount++;
    105     else
    106         m_clickCount = 1;
    107 
    108     m_currentButton = button;
    109     m_clickPos = m_mousePos;
    110     m_mouseButtons |= mouseButton;
    111 
    112 //     qDebug() << "EventSender::mouseDown" << frame;
    113     QEvent* event;
    114     if (isGraphicsBased()) {
    115         event = createGraphicsSceneMouseEvent((m_clickCount == 2) ?
    116                     QEvent::GraphicsSceneMouseDoubleClick : QEvent::GraphicsSceneMousePress,
    117                     m_mousePos, m_mousePos, mouseButton, m_mouseButtons, Qt::NoModifier);
    118     } else {
    119         event = new QMouseEvent((m_clickCount == 2) ? QEvent::MouseButtonDblClick :
    120                     QEvent::MouseButtonPress, m_mousePos, m_mousePos,
    121                     mouseButton, m_mouseButtons, Qt::NoModifier);
    122     }
    123 
    124     sendOrQueueEvent(event);
    125 
    126     m_clickTimer.start(QApplication::doubleClickInterval(), this);
    127 }
    128 
    129 void EventSender::mouseUp(int button)
    130 {
    131     Qt::MouseButton mouseButton;
    132     switch (button) {
    133     case 0:
    134         mouseButton = Qt::LeftButton;
    135         break;
    136     case 1:
    137         mouseButton = Qt::MidButton;
    138         break;
    139     case 2:
    140         mouseButton = Qt::RightButton;
    141         break;
    142     case 3:
    143         // fast/events/mouse-click-events expects the 4th button to be treated as the middle button
    144         mouseButton = Qt::MidButton;
    145         break;
    146     default:
    147         mouseButton = Qt::LeftButton;
    148         break;
    149     }
    150 
    151     m_mouseButtons &= ~mouseButton;
    152 
    153 //     qDebug() << "EventSender::mouseUp" << frame;
    154     QEvent* event;
    155     if (isGraphicsBased()) {
    156         event = createGraphicsSceneMouseEvent(QEvent::GraphicsSceneMouseRelease,
    157                     m_mousePos, m_mousePos, mouseButton, m_mouseButtons, Qt::NoModifier);
    158     } else {
    159         event = new QMouseEvent(QEvent::MouseButtonRelease,
    160                     m_mousePos, m_mousePos, mouseButton, m_mouseButtons, Qt::NoModifier);
    161     }
    162 
    163     sendOrQueueEvent(event);
    164 }
    165 
    166 void EventSender::mouseMoveTo(int x, int y)
    167 {
    168 //     qDebug() << "EventSender::mouseMoveTo" << x << y;
    169     m_mousePos = QPoint(x, y);
    170 
    171     QEvent* event;
    172     if (isGraphicsBased()) {
    173         event = createGraphicsSceneMouseEvent(QEvent::GraphicsSceneMouseMove,
    174                     m_mousePos, m_mousePos, Qt::NoButton, m_mouseButtons, Qt::NoModifier);
    175     } else {
    176         event = new QMouseEvent(QEvent::MouseMove,
    177                     m_mousePos, m_mousePos, Qt::NoButton, m_mouseButtons, Qt::NoModifier);
    178     }
    179 
    180     sendOrQueueEvent(event);
    181 }
    182 
    183 #ifndef QT_NO_WHEELEVENT
    184 void EventSender::mouseScrollBy(int x, int y)
    185 {
    186     continuousMouseScrollBy((x*120), (y*120));
    187 }
    188 
    189 void EventSender::continuousMouseScrollBy(int x, int y)
    190 {
    191     // continuousMouseScrollBy() mimics devices that send fine-grained scroll events where the 'delta' specified is not the usual
    192     // multiple of 120. See http://doc.qt.nokia.com/4.6/qwheelevent.html#delta for a good explanation of this.
    193     if (x) {
    194         QEvent* event;
    195         if (isGraphicsBased()) {
    196             event = createGraphicsSceneWheelEvent(QEvent::GraphicsSceneWheel,
    197                         m_mousePos, m_mousePos, x, Qt::NoModifier, Qt::Horizontal);
    198         } else
    199             event = new QWheelEvent(m_mousePos, m_mousePos, x, m_mouseButtons, Qt::NoModifier, Qt::Horizontal);
    200 
    201         sendOrQueueEvent(event);
    202     }
    203     if (y) {
    204         QEvent* event;
    205         if (isGraphicsBased()) {
    206             event = createGraphicsSceneWheelEvent(QEvent::GraphicsSceneWheel,
    207                         m_mousePos, m_mousePos, y, Qt::NoModifier, Qt::Vertical);
    208         } else
    209             event = new QWheelEvent(m_mousePos, m_mousePos, y, m_mouseButtons, Qt::NoModifier, Qt::Vertical);
    210 
    211         sendOrQueueEvent(event);
    212     }
    213 }
    214 #endif
    215 
    216 void EventSender::leapForward(int ms)
    217 {
    218     eventQueue[endOfQueue].m_delay = ms;
    219     //qDebug() << "EventSender::leapForward" << ms;
    220 }
    221 
    222 void EventSender::keyDown(const QString& string, const QStringList& modifiers, unsigned int location)
    223 {
    224     QString s = string;
    225     Qt::KeyboardModifiers modifs = 0;
    226     for (int i = 0; i < modifiers.size(); ++i) {
    227         const QString& m = modifiers.at(i);
    228         if (m == "ctrlKey")
    229             modifs |= Qt::ControlModifier;
    230         else if (m == "shiftKey")
    231             modifs |= Qt::ShiftModifier;
    232         else if (m == "altKey")
    233             modifs |= Qt::AltModifier;
    234         else if (m == "metaKey")
    235             modifs |= Qt::MetaModifier;
    236     }
    237     if (location == 3)
    238         modifs |= Qt::KeypadModifier;
    239     int code = 0;
    240     if (string.length() == 1) {
    241         code = string.unicode()->unicode();
    242         //qDebug() << ">>>>>>>>> keyDown" << code << (char)code;
    243         // map special keycodes used by the tests to something that works for Qt/X11
    244         if (code == '\r') {
    245             code = Qt::Key_Return;
    246         } else if (code == '\t') {
    247             code = Qt::Key_Tab;
    248             if (modifs == Qt::ShiftModifier)
    249                 code = Qt::Key_Backtab;
    250             s = QString();
    251         } else if (code == KEYCODE_DEL || code == KEYCODE_BACKSPACE) {
    252             code = Qt::Key_Backspace;
    253             if (modifs == Qt::AltModifier)
    254                 modifs = Qt::ControlModifier;
    255             s = QString();
    256         } else if (code == 'o' && modifs == Qt::ControlModifier) {
    257             // Mimic the emacs ctrl-o binding on Mac by inserting a paragraph
    258             // separator and then putting the cursor back to its original
    259             // position. Allows us to pass emacs-ctrl-o.html
    260             s = QLatin1String("\n");
    261             code = '\n';
    262             modifs = 0;
    263             QKeyEvent event(QEvent::KeyPress, code, modifs, s);
    264             sendEvent(m_page, &event);
    265             QKeyEvent event2(QEvent::KeyRelease, code, modifs, s);
    266             sendEvent(m_page, &event2);
    267             s = QString();
    268             code = Qt::Key_Left;
    269         } else if (code == 'y' && modifs == Qt::ControlModifier) {
    270             s = QLatin1String("c");
    271             code = 'c';
    272         } else if (code == 'k' && modifs == Qt::ControlModifier) {
    273             s = QLatin1String("x");
    274             code = 'x';
    275         } else if (code == 'a' && modifs == Qt::ControlModifier) {
    276             s = QString();
    277             code = Qt::Key_Home;
    278             modifs = 0;
    279         } else if (code == KEYCODE_LEFTARROW) {
    280             s = QString();
    281             code = Qt::Key_Left;
    282             if (modifs & Qt::MetaModifier) {
    283                 code = Qt::Key_Home;
    284                 modifs &= ~Qt::MetaModifier;
    285             }
    286         } else if (code == KEYCODE_RIGHTARROW) {
    287             s = QString();
    288             code = Qt::Key_Right;
    289             if (modifs & Qt::MetaModifier) {
    290                 code = Qt::Key_End;
    291                 modifs &= ~Qt::MetaModifier;
    292             }
    293         } else if (code == KEYCODE_UPARROW) {
    294             s = QString();
    295             code = Qt::Key_Up;
    296             if (modifs & Qt::MetaModifier) {
    297                 code = Qt::Key_PageUp;
    298                 modifs &= ~Qt::MetaModifier;
    299             }
    300         } else if (code == KEYCODE_DOWNARROW) {
    301             s = QString();
    302             code = Qt::Key_Down;
    303             if (modifs & Qt::MetaModifier) {
    304                 code = Qt::Key_PageDown;
    305                 modifs &= ~Qt::MetaModifier;
    306             }
    307         } else if (code == 'a' && modifs == Qt::ControlModifier) {
    308             s = QString();
    309             code = Qt::Key_Home;
    310             modifs = 0;
    311         } else
    312             code = string.unicode()->toUpper().unicode();
    313     } else {
    314         //qDebug() << ">>>>>>>>> keyDown" << string;
    315 
    316         if (string.startsWith(QLatin1Char('F')) && string.count() <= 3) {
    317             s = s.mid(1);
    318             int functionKey = s.toInt();
    319             Q_ASSERT(functionKey >= 1 && functionKey <= 35);
    320             code = Qt::Key_F1 + (functionKey - 1);
    321         // map special keycode strings used by the tests to something that works for Qt/X11
    322         } else if (string == QLatin1String("leftArrow")) {
    323             s = QString();
    324             code = Qt::Key_Left;
    325         } else if (string == QLatin1String("rightArrow")) {
    326             s = QString();
    327             code = Qt::Key_Right;
    328         } else if (string == QLatin1String("upArrow")) {
    329             s = QString();
    330             code = Qt::Key_Up;
    331         } else if (string == QLatin1String("downArrow")) {
    332             s = QString();
    333             code = Qt::Key_Down;
    334         } else if (string == QLatin1String("pageUp")) {
    335             s = QString();
    336             code = Qt::Key_PageUp;
    337         } else if (string == QLatin1String("pageDown")) {
    338             s = QString();
    339             code = Qt::Key_PageDown;
    340         } else if (string == QLatin1String("home")) {
    341             s = QString();
    342             code = Qt::Key_Home;
    343         } else if (string == QLatin1String("end")) {
    344             s = QString();
    345             code = Qt::Key_End;
    346         } else if (string == QLatin1String("insert")) {
    347             s = QString();
    348             code = Qt::Key_Insert;
    349         } else if (string == QLatin1String("delete")) {
    350             s = QString();
    351             code = Qt::Key_Delete;
    352         } else if (string == QLatin1String("printScreen")) {
    353             s = QString();
    354             code = Qt::Key_Print;
    355         } else if (string == QLatin1String("menu")) {
    356             s = QString();
    357             code = Qt::Key_Menu;
    358         }
    359     }
    360     QKeyEvent event(QEvent::KeyPress, code, modifs, s);
    361     sendEvent(m_page, &event);
    362     QKeyEvent event2(QEvent::KeyRelease, code, modifs, s);
    363     sendEvent(m_page, &event2);
    364 }
    365 
    366 QStringList EventSender::contextClick()
    367 {
    368     QMouseEvent event(QEvent::MouseButtonPress, m_mousePos, Qt::RightButton, Qt::RightButton, Qt::NoModifier);
    369     sendEvent(m_page, &event);
    370     QMouseEvent event2(QEvent::MouseButtonRelease, m_mousePos, Qt::RightButton, Qt::RightButton, Qt::NoModifier);
    371     sendEvent(m_page, &event2);
    372 
    373     if (isGraphicsBased()) {
    374         QGraphicsSceneContextMenuEvent ctxEvent(QEvent::GraphicsSceneContextMenu);
    375         ctxEvent.setReason(QGraphicsSceneContextMenuEvent::Mouse);
    376         ctxEvent.setPos(m_mousePos);
    377         WebCore::WebViewGraphicsBased* view = qobject_cast<WebCore::WebViewGraphicsBased*>(m_page->view());
    378         if (view)
    379             sendEvent(view->graphicsView(), &ctxEvent);
    380     } else {
    381         QContextMenuEvent ctxEvent(QContextMenuEvent::Mouse, m_mousePos);
    382         sendEvent(m_page->view(), &ctxEvent);
    383     }
    384     return DumpRenderTreeSupportQt::contextMenu(m_page);
    385 }
    386 
    387 void EventSender::scheduleAsynchronousClick()
    388 {
    389     QMouseEvent* event = new QMouseEvent(QEvent::MouseButtonPress, m_mousePos, Qt::LeftButton, Qt::RightButton, Qt::NoModifier);
    390     postEvent(m_page, event);
    391     QMouseEvent* event2 = new QMouseEvent(QEvent::MouseButtonRelease, m_mousePos, Qt::LeftButton, Qt::RightButton, Qt::NoModifier);
    392     postEvent(m_page, event2);
    393 }
    394 
    395 void EventSender::addTouchPoint(int x, int y)
    396 {
    397     // Use index to refer to the position in the vector that this touch
    398     // is stored. We then create a unique id for the touch that will be
    399     // passed into WebCore.
    400     int index = m_touchPoints.count();
    401     int id = m_touchPoints.isEmpty() ? 0 : m_touchPoints.last().id() + 1;
    402     QTouchEvent::TouchPoint point(id);
    403     m_touchPoints.append(point);
    404     updateTouchPoint(index, x, y);
    405     m_touchPoints[index].setState(Qt::TouchPointPressed);
    406 }
    407 
    408 void EventSender::updateTouchPoint(int index, int x, int y)
    409 {
    410     if (index < 0 || index >= m_touchPoints.count())
    411         return;
    412 
    413     QTouchEvent::TouchPoint &p = m_touchPoints[index];
    414     p.setPos(QPointF(x, y));
    415     p.setState(Qt::TouchPointMoved);
    416 }
    417 
    418 void EventSender::setTouchModifier(const QString &modifier, bool enable)
    419 {
    420     Qt::KeyboardModifier mod = Qt::NoModifier;
    421     if (!modifier.compare(QLatin1String("shift"), Qt::CaseInsensitive))
    422         mod = Qt::ShiftModifier;
    423     else if (!modifier.compare(QLatin1String("alt"), Qt::CaseInsensitive))
    424         mod = Qt::AltModifier;
    425     else if (!modifier.compare(QLatin1String("meta"), Qt::CaseInsensitive))
    426         mod = Qt::MetaModifier;
    427     else if (!modifier.compare(QLatin1String("ctrl"), Qt::CaseInsensitive))
    428         mod = Qt::ControlModifier;
    429 
    430     if (enable)
    431         m_touchModifiers |= mod;
    432     else
    433         m_touchModifiers &= ~mod;
    434 }
    435 
    436 void EventSender::touchStart()
    437 {
    438     if (!m_touchActive) {
    439         sendTouchEvent(QEvent::TouchBegin);
    440         m_touchActive = true;
    441     } else
    442         sendTouchEvent(QEvent::TouchUpdate);
    443 }
    444 
    445 void EventSender::touchMove()
    446 {
    447     sendTouchEvent(QEvent::TouchUpdate);
    448 }
    449 
    450 void EventSender::touchEnd()
    451 {
    452     for (int i = 0; i < m_touchPoints.count(); ++i)
    453         if (m_touchPoints[i].state() != Qt::TouchPointReleased) {
    454             sendTouchEvent(QEvent::TouchUpdate);
    455             return;
    456         }
    457     sendTouchEvent(QEvent::TouchEnd);
    458     m_touchActive = false;
    459 }
    460 
    461 void EventSender::clearTouchPoints()
    462 {
    463     m_touchPoints.clear();
    464     m_touchModifiers = Qt::KeyboardModifiers();
    465     m_touchActive = false;
    466 }
    467 
    468 void EventSender::releaseTouchPoint(int index)
    469 {
    470     if (index < 0 || index >= m_touchPoints.count())
    471         return;
    472 
    473     m_touchPoints[index].setState(Qt::TouchPointReleased);
    474 }
    475 
    476 void EventSender::sendTouchEvent(QEvent::Type type)
    477 {
    478     QTouchEvent event(type, QTouchEvent::TouchScreen, m_touchModifiers);
    479     event.setTouchPoints(m_touchPoints);
    480     sendEvent(m_page, &event);
    481     QList<QTouchEvent::TouchPoint>::Iterator it = m_touchPoints.begin();
    482     while (it != m_touchPoints.end()) {
    483         if (it->state() == Qt::TouchPointReleased)
    484             it = m_touchPoints.erase(it);
    485         else {
    486             it->setState(Qt::TouchPointStationary);
    487             ++it;
    488         }
    489     }
    490 }
    491 
    492 void EventSender::zoomPageIn()
    493 {
    494     if (QWebFrame* frame = m_page->mainFrame())
    495         frame->setZoomFactor(frame->zoomFactor() * ZOOM_STEP);
    496 }
    497 
    498 void EventSender::zoomPageOut()
    499 {
    500     if (QWebFrame* frame = m_page->mainFrame())
    501         frame->setZoomFactor(frame->zoomFactor() / ZOOM_STEP);
    502 }
    503 
    504 void EventSender::textZoomIn()
    505 {
    506     if (QWebFrame* frame = m_page->mainFrame())
    507         frame->setTextSizeMultiplier(frame->textSizeMultiplier() * ZOOM_STEP);
    508 }
    509 
    510 void EventSender::textZoomOut()
    511 {
    512     if (QWebFrame* frame = m_page->mainFrame())
    513         frame->setTextSizeMultiplier(frame->textSizeMultiplier() / ZOOM_STEP);
    514 }
    515 
    516 QWebFrame* EventSender::frameUnderMouse() const
    517 {
    518     QWebFrame* frame = m_page->mainFrame();
    519 
    520 redo:
    521     QList<QWebFrame*> children = frame->childFrames();
    522     for (int i = 0; i < children.size(); ++i) {
    523         if (children.at(i)->geometry().contains(m_mousePos)) {
    524             frame = children.at(i);
    525             goto redo;
    526         }
    527     }
    528     if (frame->geometry().contains(m_mousePos))
    529         return frame;
    530     return 0;
    531 }
    532 
    533 void EventSender::sendOrQueueEvent(QEvent* event)
    534 {
    535     // Mouse move events are queued if
    536     // 1. A previous event was queued.
    537     // 2. A delay was set-up by leapForward().
    538     // 3. A call to mouseMoveTo while the mouse button is pressed could initiate a drag operation, and that does not return until mouseUp is processed.
    539     // To be safe and avoid a deadlock, this event is queued.
    540     if (endOfQueue == startOfQueue && !eventQueue[endOfQueue].m_delay && (!(m_mouseButtonPressed && (m_eventLoop && event->type() == QEvent::MouseButtonRelease)))) {
    541         sendEvent(m_page->view(), event);
    542         delete event;
    543         return;
    544     }
    545     eventQueue[endOfQueue++].m_event = event;
    546     eventQueue[endOfQueue].m_delay = 0;
    547     replaySavedEvents(event->type() != QEvent::MouseMove);
    548 }
    549 
    550 void EventSender::replaySavedEvents(bool flush)
    551 {
    552     if (startOfQueue < endOfQueue) {
    553         // First send all the events that are ready to be sent
    554         while (!eventQueue[startOfQueue].m_delay && startOfQueue < endOfQueue) {
    555             QEvent* ev = eventQueue[startOfQueue++].m_event;
    556             postEvent(m_page->view(), ev);
    557         }
    558         if (startOfQueue == endOfQueue) {
    559             // Reset the queue
    560             startOfQueue = 0;
    561             endOfQueue = 0;
    562         } else {
    563             QTest::qWait(eventQueue[startOfQueue].m_delay);
    564             eventQueue[startOfQueue].m_delay = 0;
    565         }
    566     }
    567     if (!flush)
    568         return;
    569 
    570     // Send a marker event, it will tell us when it is safe to exit the new event loop
    571     QEvent* drtEvent = new QEvent((QEvent::Type)DRT_MESSAGE_DONE);
    572     QApplication::postEvent(m_page->view(), drtEvent);
    573 
    574     // Start an event loop for async handling of Drag & Drop
    575     m_eventLoop = new QEventLoop;
    576     m_eventLoop->exec();
    577     delete m_eventLoop;
    578     m_eventLoop = 0;
    579 }
    580 
    581 bool EventSender::eventFilter(QObject* watched, QEvent* event)
    582 {
    583     if (watched != m_page->view())
    584         return false;
    585     switch (event->type()) {
    586     case QEvent::Leave:
    587         return true;
    588     case QEvent::MouseButtonPress:
    589     case QEvent::GraphicsSceneMousePress:
    590         m_mouseButtonPressed = true;
    591         break;
    592     case QEvent::MouseMove:
    593     case QEvent::GraphicsSceneMouseMove:
    594         if (m_mouseButtonPressed)
    595             m_drag = true;
    596         break;
    597     case QEvent::MouseButtonRelease:
    598     case QEvent::GraphicsSceneMouseRelease:
    599         m_mouseButtonPressed = false;
    600         m_drag = false;
    601         break;
    602     case DRT_MESSAGE_DONE:
    603         m_eventLoop->exit();
    604         return true;
    605     }
    606     return false;
    607 }
    608 
    609 void EventSender::timerEvent(QTimerEvent* ev)
    610 {
    611     m_clickTimer.stop();
    612 }
    613 
    614 QGraphicsSceneMouseEvent* EventSender::createGraphicsSceneMouseEvent(QEvent::Type type, const QPoint& pos, const QPoint& screenPos, Qt::MouseButton button, Qt::MouseButtons buttons, Qt::KeyboardModifiers modifiers)
    615 {
    616     QGraphicsSceneMouseEvent* event;
    617     event = new QGraphicsSceneMouseEvent(type);
    618     event->setPos(pos);
    619     event->setScreenPos(screenPos);
    620     event->setButton(button);
    621     event->setButtons(buttons);
    622     event->setModifiers(modifiers);
    623 
    624     return event;
    625 }
    626 
    627 QGraphicsSceneWheelEvent* EventSender::createGraphicsSceneWheelEvent(QEvent::Type type, const QPoint& pos, const QPoint& screenPos, int delta, Qt::KeyboardModifiers modifiers, Qt::Orientation orientation)
    628 {
    629     QGraphicsSceneWheelEvent* event;
    630     event = new QGraphicsSceneWheelEvent(type);
    631     event->setPos(pos);
    632     event->setScreenPos(screenPos);
    633     event->setDelta(delta);
    634     event->setModifiers(modifiers);
    635     event->setOrientation(orientation);
    636 
    637     return event;
    638 }
    639 
    640 void EventSender::sendEvent(QObject* receiver, QEvent* event)
    641 {
    642     if (WebCore::WebViewGraphicsBased* view = qobject_cast<WebCore::WebViewGraphicsBased*>(receiver))
    643         view->scene()->sendEvent(view->graphicsView(), event);
    644     else
    645         QApplication::sendEvent(receiver, event);
    646 }
    647 
    648 void EventSender::postEvent(QObject* receiver, QEvent* event)
    649 {
    650     // QGraphicsScene does not have a postEvent method, so send the event in this case
    651     // and delete it after that.
    652     if (WebCore::WebViewGraphicsBased* view = qobject_cast<WebCore::WebViewGraphicsBased*>(receiver)) {
    653         view->scene()->sendEvent(view->graphicsView(), event);
    654         delete event;
    655     } else
    656         QApplication::postEvent(receiver, event); // event deleted by the system
    657 }
    658