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(¶mValues[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(¶mValues[1]), 882fc2651226baac27029e38c9d6ef883fa32084dbSteve Block g_value_get_boolean(¶mValues[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(¶mValues[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(¶mValues[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(¶mValues[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