Changeset 60478 in webkit


Ignore:
Timestamp:
Jun 1, 2010 7:58:06 AM (14 years ago)
Author:
Martin Robinson
Message:

2010-06-01 Martin Robinson <mrobinson@igalia.com>

Reviewed by Xan Lopez.

[GTK] Double clicks cause three button press events
https://bugs.webkit.org/show_bug.cgi?id=38853

Add rudimentary leapForward support to the GTK+ DRT. leapForward allows a test
to pause for a specified amount of time. It is used in the processing of drag-
-and-drop data as well as to separate distinct mouse double-clicks in some tests.
This patch enables tests that rely on the latter behavior to pass.

  • DumpRenderTree/gtk/DumpRenderTree.cpp: (webViewWindowObjectCleared): Only initialize the EventSender when loading the top frame.
  • DumpRenderTree/gtk/EventSender.cpp: (leapForwardCallback): Add support for adjusting the time offset on leapForward(). (contextClickCallback): Use sendOrQueueEvent. (updateClickCount): Take the time offset into account when counting clicks. (mouseDownCallback): Use sendOrQueueEvent. (getStateFlags): Change down/currentEventButton into buttonCurrentlyDown/lastClickButton. (mouseUpCallback): Use sendOrQueueEvent. (mouseMoveToCallback): Ditto. (mouseWheelToCallback): Ditto. (sendOrQueueEvent): Added. (dispatchEvent): Added. (replaySavedEvents): Pause when an event has a delay and defer to dispatchEvent. (makeEventSender): Only initialize the EventSender when loading the top frame.
  • DumpRenderTree/gtk/EventSender.h: Ditto.
Location:
trunk/WebKitTools
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/WebKitTools/ChangeLog

    r60471 r60478  
     12010-06-01  Martin Robinson  <mrobinson@igalia.com>
     2
     3        Reviewed by Xan Lopez.
     4
     5        [GTK] Double clicks cause three button press events
     6        https://bugs.webkit.org/show_bug.cgi?id=38853
     7
     8        Add rudimentary leapForward support to the GTK+ DRT. leapForward allows a test
     9        to pause for a specified amount of time. It is used in the processing of drag-
     10        -and-drop data as well as to separate distinct mouse double-clicks in some tests.
     11        This patch enables tests that rely on the latter behavior to pass.
     12
     13        * DumpRenderTree/gtk/DumpRenderTree.cpp:
     14        (webViewWindowObjectCleared): Only initialize the EventSender when loading the top frame.
     15        * DumpRenderTree/gtk/EventSender.cpp:
     16        (leapForwardCallback): Add support for adjusting the time offset on leapForward().
     17        (contextClickCallback): Use sendOrQueueEvent.
     18        (updateClickCount): Take the time offset into account when counting clicks.
     19        (mouseDownCallback): Use sendOrQueueEvent.
     20        (getStateFlags): Change down/currentEventButton into buttonCurrentlyDown/lastClickButton.
     21        (mouseUpCallback): Use sendOrQueueEvent.
     22        (mouseMoveToCallback): Ditto.
     23        (mouseWheelToCallback): Ditto.
     24        (sendOrQueueEvent): Added.
     25        (dispatchEvent): Added.
     26        (replaySavedEvents): Pause when an event has a delay and defer to dispatchEvent.
     27        (makeEventSender): Only initialize the EventSender when loading the top frame.
     28        * DumpRenderTree/gtk/EventSender.h: Ditto.
     29
    1302010-06-01  Martin Robinson  <mrobinson@igalia.com>
    231
  • trunk/WebKitTools/DumpRenderTree/gtk/DumpRenderTree.cpp

    r60471 r60478  
    674674
    675675    JSStringRef eventSenderStr = JSStringCreateWithUTF8CString("eventSender");
    676     JSValueRef eventSender = makeEventSender(context);
     676    JSValueRef eventSender = makeEventSender(context, !webkit_web_frame_get_parent(frame));
    677677    JSObjectSetProperty(context, windowObject, eventSenderStr, eventSender, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete, 0);
    678678    JSStringRelease(eventSenderStr);
  • trunk/WebKitTools/DumpRenderTree/gtk/EventSender.cpp

    r56316 r60478  
    4646#include <string.h>
    4747
    48 // TODO: Currently drag and drop related code is left out and
    49 // should be merged once we have drag and drop support in WebCore.
     48// FIXME: Implement support for synthesizing drop events.
    5049
    5150extern "C" {
     
    5352}
    5453
    55 static bool down = false;
    56 static bool currentEventButton = 1;
    57 static bool dragMode = true;
    58 static bool replayingSavedEvents = false;
     54static bool dragMode;
     55static int timeOffset = 0;
     56
    5957static int lastMousePositionX;
    6058static int lastMousePositionY;
    61 
    6259static int lastClickPositionX;
    6360static int lastClickPositionY;
    64 static int clickCount = 0;
     61static int lastClickTimeOffset;
     62static int lastClickButton;
     63static int buttonCurrentlyDown;
     64static int clickCount;
    6565
    6666struct DelayedMessage {
    6767    GdkEvent event;
    6868    gulong delay;
    69     gboolean isDragEvent;
    7069};
    7170
     
    8584};
    8685
     86static void sendOrQueueEvent(GdkEvent event);
     87static void dispatchEvent(GdkEvent event);
     88static guint getStateFlags();
     89
    8790static JSValueRef getDragModeCallback(JSContextRef context, JSObjectRef object, JSStringRef propertyName, JSValueRef* exception)
    8891{
     
    98101static JSValueRef leapForwardCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
    99102{
    100     // FIXME: Add proper support for forward leaps
     103    if (argumentCount > 0) {
     104        msgQueue[endOfQueue].delay = JSValueToNumber(context, arguments[0], exception);
     105        timeOffset += msgQueue[endOfQueue].delay;
     106        ASSERT(!exception || !*exception);
     107    }
     108
    101109    return JSValueMakeUndefined(context);
    102110}
     
    104112static JSValueRef contextClickCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
    105113{
    106     webkit_web_frame_layout(mainFrame);
    107 
    108114    WebKitWebView* view = webkit_web_frame_get_web_view(mainFrame);
    109115    if (!view)
     
    117123    event.button.window = GTK_WIDGET(view)->window;
    118124
    119     gboolean return_val;
    120     down = true;
    121125    event.type = GDK_BUTTON_PRESS;
    122     g_signal_emit_by_name(view, "button_press_event", &event, &return_val);
    123 
    124     down = false;
     126    sendOrQueueEvent(event);
    125127    event.type = GDK_BUTTON_RELEASE;
    126     g_signal_emit_by_name(view, "button_release_event", &event, &return_val);
     128    sendOrQueueEvent(event);
    127129
    128130    return JSValueMakeUndefined(context);
     
    131133static void updateClickCount(int button)
    132134{
    133     // FIXME: take the last clicked button number and the time of last click into account.
    134     if (lastClickPositionX != lastMousePositionX || lastClickPositionY != lastMousePositionY || currentEventButton != button)
     135    if (lastClickPositionX != lastMousePositionX
     136        || lastClickPositionY != lastMousePositionY
     137        || lastClickButton != button
     138        || timeOffset - lastClickTimeOffset >= 1)
    135139        clickCount = 1;
    136140    else
     
    159163        return JSValueMakeUndefined(context);
    160164
    161     down = true;
    162 
    163165    GdkEvent event;
    164166    memset(&event, 0, sizeof(event));
    165     event.type = GDK_BUTTON_PRESS;
    166167    event.button.button = 1;
    167168
    168169    if (argumentCount == 1) {
    169         event.button.button = (int)JSValueToNumber(context, arguments[0], exception) + 1;
     170        event.button.button = (int)(JSValueToNumber(context, arguments[0], exception)) + 1;
    170171        g_return_val_if_fail((!exception || !*exception), JSValueMakeUndefined(context));
    171172    }
    172 
    173     currentEventButton = event.button.button;
    174173
    175174    event.button.x = lastMousePositionX;
    176175    event.button.y = lastMousePositionY;
    177176    event.button.window = GTK_WIDGET(view)->window;
    178     event.button.time = GDK_CURRENT_TIME;
     177
     178    // Mouse up & down events dispatched via g_signal_emit_by_name must offset
     179    // their time value, so that WebKit can detect where sequences of mouse
     180    // clicks begin and end. This should not interfere with GDK or GTK+ event
     181    // processing, because the event is only seen by the widget.
     182    event.motion.time = GDK_CURRENT_TIME + timeOffset;
    179183    event.button.device = gdk_device_get_core_pointer();
    180184
     
    185189    getRootCoords(GTK_WIDGET(view), &x_root, &y_root);
    186190#endif
    187 
    188191    event.button.x_root = x_root;
    189192    event.button.y_root = y_root;
    190193
     194    event.type = GDK_BUTTON_PRESS;
     195    sendOrQueueEvent(event);
     196
    191197    updateClickCount(event.button.button);
    192 
    193     if (!msgQueue[endOfQueue].delay) {
    194         webkit_web_frame_layout(mainFrame);
    195 
    196         gboolean return_val;
    197         g_signal_emit_by_name(view, "button_press_event", &event, &return_val);
    198         if (clickCount == 2) {
    199             event.type = GDK_2BUTTON_PRESS;
    200             g_signal_emit_by_name(view, "button_press_event", &event, &return_val);
    201         }
    202     } else {
    203         // replaySavedEvents should have the required logic to make leapForward delays work
    204         msgQueue[endOfQueue++].event = event;
    205         replaySavedEvents();
    206     }
    207 
     198    if (clickCount == 2) {
     199        event.type = GDK_2BUTTON_PRESS;
     200        sendOrQueueEvent(event);
     201    }
     202
     203    buttonCurrentlyDown = event.button.button;
    208204    return JSValueMakeUndefined(context);
    209205}
     
    211207static guint getStateFlags()
    212208{
    213     guint state = 0;
    214 
    215     if (down) {
    216         if (currentEventButton == 1)
    217             state = GDK_BUTTON1_MASK;
    218         else if (currentEventButton == 2)
    219             state = GDK_BUTTON2_MASK;
    220         else if (currentEventButton == 3)
    221             state = GDK_BUTTON3_MASK;
    222     } else
    223         state = 0;
    224 
    225     return state;
     209    if (buttonCurrentlyDown == 1)
     210        return GDK_BUTTON1_MASK;
     211    if (buttonCurrentlyDown == 2)
     212        return GDK_BUTTON2_MASK;
     213    if (buttonCurrentlyDown == 3)
     214        return GDK_BUTTON3_MASK;
     215    return 0;
    226216}
    227217
     
    235225    GdkEvent event;
    236226    memset(&event, 0, sizeof(event));
    237     event.type = GDK_BUTTON_RELEASE;
    238227    event.button.button = 1;
    239228
     
    243232    }
    244233
    245     currentEventButton = event.button.button;
    246 
    247234    event.button.x = lastMousePositionX;
    248235    event.button.y = lastMousePositionY;
    249236    event.button.window = GTK_WIDGET(view)->window;
    250     event.button.time = GDK_CURRENT_TIME;
     237
     238    // Mouse up & down events dispatched via g_signal_emit_by_name must offset
     239    // their time value, so that WebKit can detect where sequences of mouse
     240    // clicks begin and end. This should not interfere with GDK or GTK+ event
     241    // processing, because the event is only seen by the widget.
     242    event.button.time = GDK_CURRENT_TIME + timeOffset;
    251243    event.button.device = gdk_device_get_core_pointer();
    252244    event.button.state = getStateFlags();
    253 
    254     down = false;
    255245
    256246    int x_root, y_root;
     
    264254    event.button.y_root = y_root;
    265255
    266     if ((dragMode && !replayingSavedEvents) || msgQueue[endOfQueue].delay) {
    267         msgQueue[endOfQueue].event = event;
    268         msgQueue[endOfQueue++].isDragEvent = true;
    269         replaySavedEvents();
    270     } else {
    271         webkit_web_frame_layout(mainFrame);
    272 
    273         gboolean return_val;
    274         g_signal_emit_by_name(view, "button_release_event", &event, &return_val);
    275     }
    276 
    277256    lastClickPositionX = lastMousePositionX;
    278257    lastClickPositionY = lastMousePositionY;
    279 
     258    lastClickButton = buttonCurrentlyDown;
     259    lastClickTimeOffset = timeOffset;
     260    buttonCurrentlyDown = 0;
     261
     262    event.type = GDK_BUTTON_RELEASE;
     263    sendOrQueueEvent(event);
    280264    return JSValueMakeUndefined(context);
    281265}
     
    300284    event.motion.x = lastMousePositionX;
    301285    event.motion.y = lastMousePositionY;
     286
    302287    event.motion.time = GDK_CURRENT_TIME;
    303288    event.motion.window = GTK_WIDGET(view)->window;
     
    310295    getRootCoords(GTK_WIDGET(view), &x_root, &y_root);
    311296#endif
    312 
    313297    event.motion.x_root = x_root;
    314298    event.motion.y_root = y_root;
    315    
     299
    316300    event.motion.state = getStateFlags();
    317301
    318     if (dragMode && down && !replayingSavedEvents) {
    319         msgQueue[endOfQueue].event = event;
    320         msgQueue[endOfQueue++].isDragEvent = true;
    321     } else {
    322         webkit_web_frame_layout(mainFrame);
    323 
    324         gboolean return_val;
    325         g_signal_emit_by_name(view, "motion_notify_event", &event, &return_val);
    326     }
    327 
     302    sendOrQueueEvent(event);
    328303    return JSValueMakeUndefined(context);
    329304}
     
    364339        g_assert_not_reached();
    365340
    366     if (dragMode && down && !replayingSavedEvents) {
    367         msgQueue[endOfQueue].event = event;
    368         msgQueue[endOfQueue++].isDragEvent = true;
    369     } else {
    370         webkit_web_frame_layout(mainFrame);
     341    sendOrQueueEvent(event);
     342    return JSValueMakeUndefined(context);
     343}
     344
     345static JSValueRef beginDragWithFilesCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
     346{
     347    if (argumentCount < 1)
     348        return JSValueMakeUndefined(context);
     349
     350    // FIXME: Implement this completely once WebCore has complete drag and drop support
     351    return JSValueMakeUndefined(context);
     352}
     353
     354static void sendOrQueueEvent(GdkEvent event)
     355{
     356    // Mouse move events are queued if the previous event was queued or if a
     357    // delay was set up by leapForward().
     358    if (endOfQueue != startOfQueue || msgQueue[endOfQueue].delay) {
     359        msgQueue[endOfQueue++].event = event;
     360        replaySavedEvents();
     361        return;
     362    }
     363
     364    dispatchEvent(event);
     365}
     366
     367static void dispatchEvent(GdkEvent event)
     368{
     369    webkit_web_frame_layout(mainFrame);
     370    WebKitWebView* view = webkit_web_frame_get_web_view(mainFrame);
     371    if (!view)
     372        return;
     373
     374    gboolean returnValue;
     375    if (event.type == GDK_BUTTON_PRESS || event.type == GDK_2BUTTON_PRESS)
     376        g_signal_emit_by_name(view, "button_press_event", &event, &returnValue);
     377    else if (event.type == GDK_BUTTON_RELEASE)
     378        g_signal_emit_by_name(view, "button_release_event", &event, &returnValue);
     379    else if (event.type == GDK_MOTION_NOTIFY)
     380        g_signal_emit_by_name(view, "motion_notify_event", &event, &returnValue);
     381    else if (event.type == GDK_SCROLL)
    371382        gtk_main_do_event(&event);
    372     }
    373 
    374     return JSValueMakeUndefined(context);
    375 }
    376 
    377 static JSValueRef beginDragWithFilesCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
    378 {
    379     if (argumentCount < 1)
    380         return JSValueMakeUndefined(context);
    381 
    382     // FIXME: Implement this completely once WebCore has complete drag and drop support
    383     return JSValueMakeUndefined(context);
    384383}
    385384
    386385void replaySavedEvents()
    387386{
    388     // FIXME: This doesn't deal with forward leaps, but it should.
    389 
    390     WebKitWebView* view = webkit_web_frame_get_web_view(mainFrame);
    391     if (!view)
    392         return;
    393 
    394     replayingSavedEvents = true;
    395 
    396     for (unsigned queuePos = 0; queuePos < endOfQueue; queuePos++) {
    397         GdkEvent event = msgQueue[queuePos].event;
    398         gboolean return_val;
    399 
    400         switch (event.type) {
    401         case GDK_BUTTON_RELEASE:
    402             g_signal_emit_by_name(view, "button_release_event", &event, &return_val);
    403             break;
    404         case GDK_BUTTON_PRESS:
    405             g_signal_emit_by_name(view, "button_press_event", &event, &return_val);
    406             break;
    407         case GDK_MOTION_NOTIFY:
    408             g_signal_emit_by_name(view, "motion_notify_event", &event, &return_val);
    409             break;
    410         default:
    411             continue;
     387    // FIXME: Eventually we may need to have more sophisticated logic to
     388    // track drag-and-drop operations.
     389
     390    // First send all the events that are ready to be sent
     391    while (startOfQueue < endOfQueue) {
     392        if (msgQueue[startOfQueue].delay) {
     393            g_usleep(msgQueue[startOfQueue].delay * 1000);
     394            msgQueue[startOfQueue].delay = 0;
    412395        }
    413396
    414         startOfQueue++;
    415     }
    416 
    417     int numQueuedMessages = endOfQueue - startOfQueue;
    418     if (!numQueuedMessages) {
    419         startOfQueue = 0;
    420         endOfQueue = 0;
    421         replayingSavedEvents = false;
    422         return;
     397        dispatchEvent(msgQueue[startOfQueue++].event);
    423398    }
    424399
    425400    startOfQueue = 0;
    426401    endOfQueue = 0;
    427 
    428     replayingSavedEvents = false;
    429402}
    430403
     
    662635}
    663636
    664 JSObjectRef makeEventSender(JSContextRef context)
    665 {
    666     down = false;
    667     dragMode = true;
    668     lastMousePositionX = lastMousePositionY = 0;
    669     lastClickPositionX = lastClickPositionY = 0;
    670 
    671     if (!replayingSavedEvents) {
    672         // This function can be called in the middle of a test, even
    673         // while replaying saved events. Resetting these while doing that
    674         // can break things.
     637JSObjectRef makeEventSender(JSContextRef context, bool isTopFrame)
     638{
     639    if (isTopFrame) {
     640        dragMode = true;
     641
     642        // Fly forward in time one second when the main frame loads. This will
     643        // ensure that when a test begins clicking in the same location as
     644        // a previous test, those clicks won't be interpreted as continuations
     645        // of the previous test's click sequences.
     646        timeOffset += 1000;
     647
     648        lastMousePositionX = lastMousePositionY = 0;
     649        lastClickPositionX = lastClickPositionY = 0;
     650        lastClickTimeOffset = 0;
     651        lastClickButton = 0;
     652        buttonCurrentlyDown = 0;
     653        clickCount = 0;
     654
    675655        endOfQueue = 0;
    676656        startOfQueue = 0;
  • trunk/WebKitTools/DumpRenderTree/gtk/EventSender.h

    r48228 r60478  
    3434typedef struct OpaqueJSValue* JSObjectRef;
    3535
    36 JSObjectRef makeEventSender(JSContextRef context);
     36JSObjectRef makeEventSender(JSContextRef context, bool isTopFrame);
    3737void replaySavedEvents();
    3838
Note: See TracChangeset for help on using the changeset viewer.