12fc2651226baac27029e38c9d6ef883fa32084dbSteve Block/*
22fc2651226baac27029e38c9d6ef883fa32084dbSteve Block * Copyright (C) 2011 Igalia S.L.
32fc2651226baac27029e38c9d6ef883fa32084dbSteve Block *
42fc2651226baac27029e38c9d6ef883fa32084dbSteve Block * Redistribution and use in source and binary forms, with or without
52fc2651226baac27029e38c9d6ef883fa32084dbSteve Block * modification, are permitted provided that the following conditions
62fc2651226baac27029e38c9d6ef883fa32084dbSteve Block * are met:
72fc2651226baac27029e38c9d6ef883fa32084dbSteve Block *
82fc2651226baac27029e38c9d6ef883fa32084dbSteve Block * 1.  Redistributions of source code must retain the above copyright
92fc2651226baac27029e38c9d6ef883fa32084dbSteve Block *     notice, this list of conditions and the following disclaimer.
102fc2651226baac27029e38c9d6ef883fa32084dbSteve Block * 2.  Redistributions in binary form must reproduce the above copyright
112fc2651226baac27029e38c9d6ef883fa32084dbSteve Block *     notice, this list of conditions and the following disclaimer in the
122fc2651226baac27029e38c9d6ef883fa32084dbSteve Block *     documentation and/or other materials provided with the distribution.
132fc2651226baac27029e38c9d6ef883fa32084dbSteve Block * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
142fc2651226baac27029e38c9d6ef883fa32084dbSteve Block *     its contributors may be used to endorse or promote products derived
152fc2651226baac27029e38c9d6ef883fa32084dbSteve Block *     from this software without specific prior written permission.
162fc2651226baac27029e38c9d6ef883fa32084dbSteve Block *
172fc2651226baac27029e38c9d6ef883fa32084dbSteve Block * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
182fc2651226baac27029e38c9d6ef883fa32084dbSteve Block * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
192fc2651226baac27029e38c9d6ef883fa32084dbSteve Block * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
202fc2651226baac27029e38c9d6ef883fa32084dbSteve Block * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
212fc2651226baac27029e38c9d6ef883fa32084dbSteve Block * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
222fc2651226baac27029e38c9d6ef883fa32084dbSteve Block * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
232fc2651226baac27029e38c9d6ef883fa32084dbSteve Block * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
242fc2651226baac27029e38c9d6ef883fa32084dbSteve Block * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
252fc2651226baac27029e38c9d6ef883fa32084dbSteve Block * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
262fc2651226baac27029e38c9d6ef883fa32084dbSteve Block * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
272fc2651226baac27029e38c9d6ef883fa32084dbSteve Block */
282fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
292fc2651226baac27029e38c9d6ef883fa32084dbSteve Block#include "config.h"
302fc2651226baac27029e38c9d6ef883fa32084dbSteve Block#include "AccessibilityCallbacks.h"
312fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
322fc2651226baac27029e38c9d6ef883fa32084dbSteve Block#include "AccessibilityController.h"
332fc2651226baac27029e38c9d6ef883fa32084dbSteve Block#include "DumpRenderTree.h"
342fc2651226baac27029e38c9d6ef883fa32084dbSteve Block#include "GOwnPtr.h"
352fc2651226baac27029e38c9d6ef883fa32084dbSteve Block#include "WebCoreSupport/DumpRenderTreeSupportGtk.h"
362fc2651226baac27029e38c9d6ef883fa32084dbSteve Block#include <gtk/gtk.h>
372fc2651226baac27029e38c9d6ef883fa32084dbSteve Block#include <webkit/webkit.h>
382fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
392fc2651226baac27029e38c9d6ef883fa32084dbSteve Blockstatic guint stateChangeListenerId = 0;
402fc2651226baac27029e38c9d6ef883fa32084dbSteve Blockstatic guint focusEventListenerId = 0;
412fc2651226baac27029e38c9d6ef883fa32084dbSteve Blockstatic guint activeDescendantChangedListenerId = 0;
422fc2651226baac27029e38c9d6ef883fa32084dbSteve Blockstatic guint childrenChangedListenerId = 0;
432fc2651226baac27029e38c9d6ef883fa32084dbSteve Blockstatic guint propertyChangedListenerId = 0;
442fc2651226baac27029e38c9d6ef883fa32084dbSteve Blockstatic guint visibleDataChangedListenerId = 0;
452fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
462fc2651226baac27029e38c9d6ef883fa32084dbSteve Blockstatic guint loadCompleteListenerId = 0;
472fc2651226baac27029e38c9d6ef883fa32084dbSteve Blockstatic guint loadStoppedListenerId = 0;
482fc2651226baac27029e38c9d6ef883fa32084dbSteve Blockstatic guint reloadListenerId = 0;
492fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
502fc2651226baac27029e38c9d6ef883fa32084dbSteve Blockstatic void printAccessibilityEvent(AtkObject* accessible, const gchar* signalName)
512fc2651226baac27029e38c9d6ef883fa32084dbSteve Block{
522fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    // Sanity check.
532fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    if (!accessible || !ATK_IS_OBJECT(accessible) || !signalName)
542fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        return;
552fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
562fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    const gchar* objectName = atk_object_get_name(accessible);
572fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    guint objectRole = atk_object_get_role(accessible);
582fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
592fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    // Try to always provide a name to be logged for the object.
602fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    if (!objectName || *objectName == '\0')
612fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        objectName = "(No name)";
622fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
632fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    printf("Accessibility object emitted \"%s\" / Name: \"%s\" / Role: %d\n",
642fc2651226baac27029e38c9d6ef883fa32084dbSteve Block           signalName, objectName, objectRole);
652fc2651226baac27029e38c9d6ef883fa32084dbSteve Block}
662fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
672fc2651226baac27029e38c9d6ef883fa32084dbSteve Blockstatic gboolean axObjectEventListener(GSignalInvocationHint *signalHint,
682fc2651226baac27029e38c9d6ef883fa32084dbSteve Block                                      guint numParamValues,
692fc2651226baac27029e38c9d6ef883fa32084dbSteve Block                                      const GValue *paramValues,
702fc2651226baac27029e38c9d6ef883fa32084dbSteve Block                                      gpointer data)
712fc2651226baac27029e38c9d6ef883fa32084dbSteve Block{
722fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    // At least we should receive the instance emitting the signal.
732fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    if (numParamValues < 1)
742fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        return TRUE;
752fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
762fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    AtkObject* accessible = ATK_OBJECT(g_value_get_object(&paramValues[0]));
772fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    if (!accessible || !ATK_IS_OBJECT(accessible))
782fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        return TRUE;
792fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
802fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    GSignalQuery signal_query;
812fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    GOwnPtr<gchar> signalName;
822fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
832fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    g_signal_query(signalHint->signal_id, &signal_query);
842fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
852fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    if (!g_strcmp0(signal_query.signal_name, "state-change")) {
862fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        signalName.set(g_strdup_printf("state-change:%s = %d",
872fc2651226baac27029e38c9d6ef883fa32084dbSteve Block                                       g_value_get_string(&paramValues[1]),
882fc2651226baac27029e38c9d6ef883fa32084dbSteve Block                                       g_value_get_boolean(&paramValues[2])));
892fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    } else if (!g_strcmp0(signal_query.signal_name, "focus-event")) {
902fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        signalName.set(g_strdup_printf("focus-event = %d",
912fc2651226baac27029e38c9d6ef883fa32084dbSteve Block                                       g_value_get_boolean(&paramValues[1])));
922fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    } else if (!g_strcmp0(signal_query.signal_name, "children-changed")) {
932fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        signalName.set(g_strdup_printf("children-changed = %d",
942fc2651226baac27029e38c9d6ef883fa32084dbSteve Block                                       g_value_get_uint(&paramValues[1])));
952bde8e466a4451c7319e3a072d118917957d6554Steve Block    } else if (!g_strcmp0(signal_query.signal_name, "property-change")) {
962bde8e466a4451c7319e3a072d118917957d6554Steve Block        signalName.set(g_strdup_printf("property-change:%s",
972bde8e466a4451c7319e3a072d118917957d6554Steve Block                                       g_quark_to_string(signalHint->detail)));
982fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    } else
992fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        signalName.set(g_strdup(signal_query.signal_name));
1002fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
1012fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    printAccessibilityEvent(accessible, signalName.get());
1022fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
1032fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    return TRUE;
1042fc2651226baac27029e38c9d6ef883fa32084dbSteve Block}
1052fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
1062fc2651226baac27029e38c9d6ef883fa32084dbSteve Blockstatic gboolean axDocumentEventListener(GSignalInvocationHint *signalHint,
1072fc2651226baac27029e38c9d6ef883fa32084dbSteve Block                                        guint numParamValues,
1082fc2651226baac27029e38c9d6ef883fa32084dbSteve Block                                        const GValue *paramValues,
1092fc2651226baac27029e38c9d6ef883fa32084dbSteve Block                                        gpointer data)
1102fc2651226baac27029e38c9d6ef883fa32084dbSteve Block{
1112fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    // At least we should receive the instance emitting the signal.
1122fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    if (numParamValues < 1)
1132fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        return TRUE;
1142fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
1152fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    AtkObject* accessible = ATK_OBJECT(g_value_get_object(&paramValues[0]));
1162fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    if (!accessible || !ATK_IS_DOCUMENT(accessible))
1172fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        return TRUE;
1182fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
1192fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    GSignalQuery signal_query;
1202fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    g_signal_query(signalHint->signal_id, &signal_query);
1212fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
1222fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    printAccessibilityEvent(accessible, signal_query.signal_name);
1232fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
1242fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    return TRUE;
1252fc2651226baac27029e38c9d6ef883fa32084dbSteve Block}
1262fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
1272fc2651226baac27029e38c9d6ef883fa32084dbSteve Blockvoid connectAccessibilityCallbacks()
1282fc2651226baac27029e38c9d6ef883fa32084dbSteve Block{
1292fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    // Ensure no callbacks are connected before.
1302fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    disconnectAccessibilityCallbacks();
1312fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
1322fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    // Ensure that accessibility is initialized for the WebView by querying for
1332fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    // the root accessible object, which will create the full hierarchy.
1342fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    DumpRenderTreeSupportGtk::getRootAccessibleElement(mainFrame);
1352fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
1362fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    // Add global listeners for AtkObject's signals.
1372fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    stateChangeListenerId = atk_add_global_event_listener(axObjectEventListener, "Gtk:AtkObject:state-change");
1382fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    focusEventListenerId = atk_add_global_event_listener(axObjectEventListener, "Gtk:AtkObject:focus-event");
1392fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    activeDescendantChangedListenerId = atk_add_global_event_listener(axObjectEventListener, "Gtk:AtkObject:active-descendant-changed");
1402fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    childrenChangedListenerId = atk_add_global_event_listener(axObjectEventListener, "Gtk:AtkObject:children-changed");
1412fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    propertyChangedListenerId = atk_add_global_event_listener(axObjectEventListener, "Gtk:AtkObject:property-change");
1422fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    visibleDataChangedListenerId = atk_add_global_event_listener(axObjectEventListener, "Gtk:AtkObject:visible-data-changed");
1432fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
1442fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    // Ensure the Atk interface types are registered, otherwise
1452fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    // the AtkDocument signal handlers below won't get registered.
1462fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    GObject* dummyAxObject = G_OBJECT(g_object_new(ATK_TYPE_OBJECT, 0));
1472fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    AtkObject* dummyNoOpAxObject = atk_no_op_object_new(dummyAxObject);
1482fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    g_object_unref(G_OBJECT(dummyNoOpAxObject));
1492fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    g_object_unref(dummyAxObject);
1502fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
1512fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    // Add global listeners for AtkDocument's signals.
1522fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    loadCompleteListenerId = atk_add_global_event_listener(axDocumentEventListener, "Gtk:AtkDocument:load-complete");
1532fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    loadStoppedListenerId = atk_add_global_event_listener(axDocumentEventListener, "Gtk:AtkDocument:load-stopped");
1542fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    reloadListenerId = atk_add_global_event_listener(axDocumentEventListener, "Gtk:AtkDocument:reload");
1552fc2651226baac27029e38c9d6ef883fa32084dbSteve Block}
1562fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
1572fc2651226baac27029e38c9d6ef883fa32084dbSteve Blockvoid disconnectAccessibilityCallbacks()
1582fc2651226baac27029e38c9d6ef883fa32084dbSteve Block{
1592fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    // AtkObject signals.
1602fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    if (stateChangeListenerId) {
1612fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        atk_remove_global_event_listener(stateChangeListenerId);
1622fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        stateChangeListenerId = 0;
1632fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    }
1642fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    if (focusEventListenerId) {
1652fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        atk_remove_global_event_listener(focusEventListenerId);
1662fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        focusEventListenerId = 0;
1672fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    }
1682fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    if (activeDescendantChangedListenerId) {
1692fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        atk_remove_global_event_listener(activeDescendantChangedListenerId);
1702fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        activeDescendantChangedListenerId = 0;
1712fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    }
1722fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    if (childrenChangedListenerId) {
1732fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        atk_remove_global_event_listener(childrenChangedListenerId);
1742fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        childrenChangedListenerId = 0;
1752fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    }
1762fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    if (propertyChangedListenerId) {
1772fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        atk_remove_global_event_listener(propertyChangedListenerId);
1782fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        propertyChangedListenerId = 0;
1792fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    }
1802fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    if (visibleDataChangedListenerId) {
1812fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        atk_remove_global_event_listener(visibleDataChangedListenerId);
1822fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        visibleDataChangedListenerId = 0;
1832fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    }
1842fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
1852fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    // AtkDocument signals.
1862fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    if (loadCompleteListenerId) {
1872fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        atk_remove_global_event_listener(loadCompleteListenerId);
1882fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        loadCompleteListenerId = 0;
1892fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    }
1902fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    if (loadStoppedListenerId) {
1912fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        atk_remove_global_event_listener(loadStoppedListenerId);
1922fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        loadStoppedListenerId = 0;
1932fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    }
1942fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    if (reloadListenerId) {
1952fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        atk_remove_global_event_listener(reloadListenerId);
1962fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        reloadListenerId = 0;
1972fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    }
1982fc2651226baac27029e38c9d6ef883fa32084dbSteve Block}
1992fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
200