1/*
2 * Copyright (C) 2012 Igalia S.L.
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12 * Library General Public License for more details.
13 *
14 * You should have received a copy of the GNU Library General Public License
15 * along with this library; see the file COPYING.LIB.  If not, write to
16 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
18 */
19
20#include "config.h"
21#include "WebKitWebViewBaseAccessible.h"
22
23#include "WebKitPrivate.h"
24#include <gtk/gtk.h>
25
26struct _WebKitWebViewBaseAccessiblePrivate {
27    GtkWidget* widget;
28};
29
30WEBKIT_DEFINE_TYPE(WebKitWebViewBaseAccessible, webkit_web_view_base_accessible, ATK_TYPE_SOCKET)
31
32static void webkitWebViewBaseAccessibleWidgetDestroyed(GtkWidget*, WebKitWebViewBaseAccessible* accessible)
33{
34    accessible->priv->widget = 0;
35    atk_object_notify_state_change(ATK_OBJECT(accessible), ATK_STATE_DEFUNCT, TRUE);
36}
37
38static void webkitWebViewBaseAccessibleInitialize(AtkObject* atkObject, gpointer data)
39{
40    if (ATK_OBJECT_CLASS(webkit_web_view_base_accessible_parent_class)->initialize)
41        ATK_OBJECT_CLASS(webkit_web_view_base_accessible_parent_class)->initialize(atkObject, data);
42
43    if (data && GTK_IS_WIDGET(data)) {
44        WebKitWebViewBaseAccessible* accessible = WEBKIT_WEB_VIEW_BASE_ACCESSIBLE(atkObject);
45        accessible->priv->widget = GTK_WIDGET(data);
46
47        g_signal_connect_after(accessible->priv->widget, "destroy",
48                               G_CALLBACK(webkitWebViewBaseAccessibleWidgetDestroyed), atkObject);
49    }
50
51    atk_object_set_role(atkObject, ATK_ROLE_FILLER);
52}
53
54static AtkStateSet* webkitWebViewBaseAccessibleRefStateSet(AtkObject* atkObject)
55{
56    WebKitWebViewBaseAccessible* accessible = WEBKIT_WEB_VIEW_BASE_ACCESSIBLE(atkObject);
57
58    AtkStateSet* stateSet;
59    if (accessible->priv->widget) {
60        // Use the implementation of AtkSocket if the widget is still alive.
61        stateSet = ATK_OBJECT_CLASS(webkit_web_view_base_accessible_parent_class)->ref_state_set(atkObject);
62    } else {
63        // If the widget is no longer alive, save some remote calls
64        // (because of AtkSocket's implementation of ref_state_set())
65        // and just return that this AtkObject is defunct.
66        stateSet = atk_state_set_new();
67        atk_state_set_add_state(stateSet, ATK_STATE_DEFUNCT);
68    }
69
70    return stateSet;
71}
72
73static gint webkitWebViewBaseAccessibleGetIndexInParent(AtkObject* atkObject)
74{
75    AtkObject* atkParent = atk_object_get_parent(atkObject);
76    if (!atkParent)
77        return -1;
78
79    guint count = atk_object_get_n_accessible_children(atkParent);
80    for (guint i = 0; i < count; ++i) {
81        AtkObject* child = atk_object_ref_accessible_child(atkParent, i);
82        bool childIsObject = child == atkObject;
83        g_object_unref(child);
84        if (childIsObject)
85            return i;
86    }
87
88    return -1;
89}
90
91static void webkit_web_view_base_accessible_class_init(WebKitWebViewBaseAccessibleClass* klass)
92{
93    // No need to implement get_n_children() and ref_child() here
94    // since this is a subclass of AtkSocket and all the logic related
95    // to those functions will be implemented by the ATK bridge.
96    AtkObjectClass* atkObjectClass = ATK_OBJECT_CLASS(klass);
97    atkObjectClass->initialize = webkitWebViewBaseAccessibleInitialize;
98    atkObjectClass->ref_state_set = webkitWebViewBaseAccessibleRefStateSet;
99    atkObjectClass->get_index_in_parent = webkitWebViewBaseAccessibleGetIndexInParent;
100}
101
102WebKitWebViewBaseAccessible* webkitWebViewBaseAccessibleNew(GtkWidget* widget)
103{
104    AtkObject* object = ATK_OBJECT(g_object_new(WEBKIT_TYPE_WEB_VIEW_BASE_ACCESSIBLE, NULL));
105    atk_object_initialize(object, widget);
106    return WEBKIT_WEB_VIEW_BASE_ACCESSIBLE(object);
107}
108