/* This file is part of the GtkHTML library.
*
* Copyright 2002 Ximian, Inc.
*
* Author: Radek Doulik
*
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include
#include "gtkhtml.h"
#include "htmlengine.h"
#include "htmlobject.h"
#include "object.h"
#include "paragraph.h"
#include "utils.h"
#include "text.h"
#include
static void gtk_html_a11y_class_init (GtkHTMLA11YClass *klass);
static void gtk_html_a11y_init (GtkHTMLA11Y *a11y);
static GtkAccessibleClass *parent_class = NULL;
static gint
get_n_actions (AtkAction *action)
{
return 1;
}
static G_CONST_RETURN gchar*
get_description (AtkAction *action, gint i)
{
if (i == 0)
return _("grab focus");
return NULL;
}
static G_CONST_RETURN gchar*
action_get_name (AtkAction *action, gint i)
{
if (i == 0)
return _("grab focus");
return NULL;
}
static gboolean
do_action (AtkAction * action, gint i)
{
GtkWidget *widget;
gboolean return_value = TRUE;
widget = GTK_ACCESSIBLE (action)->widget;
if (widget == NULL) {
/*
* State is defunct
*/
return FALSE;
}
if (!GTK_WIDGET_SENSITIVE (widget) || !GTK_WIDGET_VISIBLE (widget))
return FALSE;
switch (i) {
case 0:
gtk_widget_grab_focus (widget);
default:
return_value = FALSE;
break;
}
return return_value;
}
static void
atk_action_interface_init (AtkActionIface *iface)
{
g_return_if_fail (iface != NULL);
iface->do_action = do_action;
iface->get_n_actions = get_n_actions;
iface->get_description = get_description;
iface->get_name = action_get_name;
}
GType
gtk_html_a11y_get_type (void)
{
static GType type = 0;
if (!type) {
static GTypeInfo tinfo = {
sizeof (GtkHTMLA11YClass),
NULL, /* base init */
NULL, /* base finalize */
(GClassInitFunc) gtk_html_a11y_class_init, /* class init */
NULL, /* class finalize */
NULL, /* class data */
sizeof (GtkHTMLA11Y), /* instance size */
0, /* nb preallocs */
(GInstanceInitFunc) gtk_html_a11y_init, /* instance init */
NULL /* value table */
};
static const GInterfaceInfo atk_action_info = {
(GInterfaceInitFunc) atk_action_interface_init,
(GInterfaceFinalizeFunc) NULL,
NULL
};
/*
* Figure out the size of the class and instance
* we are deriving from
*/
AtkObjectFactory *factory;
GTypeQuery query;
GType derived_atk_type;
factory = atk_registry_get_factory (atk_get_default_registry (), GTK_TYPE_WIDGET);
derived_atk_type = atk_object_factory_get_accessible_type (factory);
g_type_query (derived_atk_type, &query);
tinfo.class_size = query.class_size;
tinfo.instance_size = query.instance_size;
type = g_type_register_static (derived_atk_type, "GtkHTMLA11Y", &tinfo, 0);
g_type_add_interface_static (type, ATK_TYPE_ACTION, &atk_action_info);
}
return type;
}
static void
gtk_html_a11y_finalize (GObject *obj)
{
G_OBJECT_CLASS (parent_class)->finalize (obj);
}
static void
gtk_html_a11y_initialize (AtkObject *obj, gpointer data)
{
/* printf ("gtk_html_a11y_initialize\n"); */
if (ATK_OBJECT_CLASS (parent_class)->initialize)
ATK_OBJECT_CLASS (parent_class)->initialize (obj, data);
g_object_set_data (G_OBJECT (obj), GTK_HTML_ID, data);
}
static gint
gtk_html_a11y_get_n_children (AtkObject *accessible)
{
HTMLObject *clue;
gint n_children = 0;
AtkStateSet *ss;
if (GTK_HTML_A11Y_GTKHTML (accessible)->engine->parsing)
return 0;
ss = atk_object_ref_state_set (accessible);
if (atk_state_set_contains_state (ss, ATK_STATE_DEFUNCT)) {
g_object_unref (ss);
return 0;
}
g_object_unref (ss);
clue = GTK_HTML_A11Y_GTKHTML (accessible)->engine->clue;
if (clue) {
AtkObject *atk_clue = html_utils_get_accessible (clue, NULL);
if (atk_clue) {
AtkStateSet *ss_clue = atk_object_ref_state_set (atk_clue);
if (atk_state_set_contains_state (ss_clue, ATK_STATE_DEFUNCT)) {
g_object_unref (ss_clue);
return 0;
}
g_object_unref (ss_clue);
}
n_children = html_object_get_n_children (GTK_HTML_A11Y_GTKHTML (accessible)->engine->clue);
}
/* printf ("gtk_html_a11y_get_n_children resolves to %d\n", n_children); */
return n_children;
}
static AtkObject *
gtk_html_a11y_ref_child (AtkObject *accessible, gint index)
{
HTMLObject *child;
AtkObject *accessible_child = NULL;
AtkStateSet *ss;
if (GTK_HTML_A11Y_GTKHTML (accessible)->engine->parsing)
return NULL;
ss = atk_object_ref_state_set (accessible);
if (atk_state_set_contains_state (ss, ATK_STATE_DEFUNCT)) {
g_object_unref (ss);
return NULL;
}
g_object_unref (ss);
if (GTK_HTML_A11Y_GTKHTML (accessible)->engine->clue) {
AtkObject *atk_clue = html_utils_get_accessible (GTK_HTML_A11Y_GTKHTML (accessible)->engine->clue, NULL);
if (atk_clue) {
AtkStateSet *ss_clue = atk_object_ref_state_set (atk_clue);
if (atk_state_set_contains_state (ss_clue, ATK_STATE_DEFUNCT)) {
g_object_unref (ss_clue);
return NULL;
}
g_object_unref (ss_clue);
}
child = html_object_get_child (GTK_HTML_A11Y_GTKHTML (accessible)->engine->clue, index);
if (child) {
accessible_child = html_utils_get_accessible (child, accessible);
if (accessible_child)
g_object_ref (accessible_child);
}
}
/* printf ("gtk_html_a11y_ref_child %d resolves to %p\n", index, accessible_child); */
return accessible_child;
}
static G_CONST_RETURN gchar*
gtk_html_a11y_get_name (AtkObject *obj)
{
if (obj->name != NULL) {
return obj->name;
}
return _("Panel containing HTML");
}
static void
gtk_html_a11y_class_init (GtkHTMLA11YClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
AtkObjectClass *atk_class = ATK_OBJECT_CLASS (klass);
parent_class = g_type_class_peek_parent (klass);
atk_class->initialize = gtk_html_a11y_initialize;
atk_class->get_n_children = gtk_html_a11y_get_n_children;
atk_class->ref_child = gtk_html_a11y_ref_child;
atk_class->get_name = gtk_html_a11y_get_name;
gobject_class->finalize = gtk_html_a11y_finalize;
}
static void
gtk_html_a11y_init (GtkHTMLA11Y *a11y)
{
}
static AtkObject *
gtk_html_a11y_get_focus_object (GtkWidget * widget)
{
GtkHTML * html;
HTMLObject * htmlobj = NULL;
AtkObject *obj = NULL;
gint offset;
html = GTK_HTML(widget);
g_return_val_if_fail (html && html->engine, NULL);
if (!html->engine->caret_mode && !gtk_html_get_editable (html))
htmlobj = html_engine_get_focus_object (html->engine, &offset);
else if (html->engine && html->engine->cursor)
htmlobj = html->engine->cursor->object;
if (htmlobj)
obj = html_utils_get_accessible (htmlobj, NULL);
return obj;
}
static void
gtk_html_a11y_grab_focus_cb(GtkWidget * widget)
{
AtkObject *focus_object, *obj, *clue;
focus_object = gtk_html_a11y_get_focus_object (widget);
if (focus_object == NULL)
return;
obj = gtk_widget_get_accessible (widget);
g_object_set_data (G_OBJECT(obj), "gail-focus-object", focus_object);
clue = html_utils_get_accessible(GTK_HTML(widget)->engine->clue, obj);
atk_object_set_parent(clue, obj);
atk_focus_tracker_notify (focus_object);
}
static AtkObject * gtk_html_a11y_focus_object = NULL;
static void
gtk_html_a11y_cursor_changed_cb (GtkWidget *widget)
{
AtkObject *focus_object, *obj;
focus_object = gtk_html_a11y_get_focus_object (widget);
g_return_if_fail (focus_object != NULL);
obj = gtk_widget_get_accessible (widget);
if (gtk_html_a11y_focus_object != focus_object) {
gtk_html_a11y_focus_object = focus_object;
g_object_set_data (G_OBJECT(obj), "gail-focus-object", focus_object);
atk_focus_tracker_notify (focus_object);
} else {
if (G_IS_HTML_A11Y_TEXT(focus_object)) {
gint offset;
offset = (GTK_HTML(widget))->engine->cursor->offset;
g_signal_emit_by_name(focus_object, "text_caret_moved",offset);
}
}
}
static void
gtk_html_a11y_insert_object_cb (GtkWidget * widget, int pos, int len)
{
AtkObject * a11y, *obj;
HTMLCursor *cursor = GTK_HTML (widget)->engine->cursor;
obj = gtk_widget_get_accessible (widget);
a11y = gtk_html_a11y_get_focus_object (widget);
g_return_if_fail (a11y != NULL);
if (gtk_html_a11y_focus_object != a11y) {
gtk_html_a11y_focus_object = a11y;
g_object_set_data (G_OBJECT(obj), "gail-focus-object", a11y);
atk_focus_tracker_notify (a11y);
}
if (G_IS_HTML_A11Y_TEXT(a11y)) {
g_signal_emit_by_name (a11y, "text_changed::insert", cursor->offset - len, len);
}
}
static void
gtk_html_a11y_delete_object_cb (GtkWidget * widget, int pos, int len)
{
AtkObject * a11y, *obj;
HTMLCursor *cursor = GTK_HTML (widget)->engine->cursor;
obj = gtk_widget_get_accessible (widget);
a11y = gtk_html_a11y_get_focus_object (widget);
g_return_if_fail (a11y != NULL);
if (gtk_html_a11y_focus_object != a11y) {
gtk_html_a11y_focus_object = a11y;
g_object_set_data (G_OBJECT(obj), "gail-focus-object", a11y);
atk_focus_tracker_notify (a11y);
}
if (G_IS_HTML_A11Y_TEXT(a11y)) {
g_signal_emit_by_name (a11y, "text_changed::delete", pos, len);
printf ("the cur is %d\n", cursor->offset);
}
}
AtkObject*
gtk_html_a11y_new (GtkWidget *widget)
{
GObject *object;
AtkObject *accessible, *focus_object;
g_return_val_if_fail (GTK_IS_HTML (widget), NULL);
object = g_object_new (G_TYPE_GTK_HTML_A11Y, NULL);
accessible = ATK_OBJECT (object);
atk_object_initialize (accessible, widget);
accessible->role = ATK_ROLE_PANEL;
g_signal_connect (widget, "grab_focus",
G_CALLBACK (gtk_html_a11y_grab_focus_cb),
NULL);
g_signal_connect (widget, "cursor_changed",
G_CALLBACK(gtk_html_a11y_cursor_changed_cb),
NULL);
g_signal_connect_after (widget, "object_inserted",
G_CALLBACK(gtk_html_a11y_insert_object_cb),
NULL);
g_signal_connect_after (widget, "object_delete",
G_CALLBACK(gtk_html_a11y_delete_object_cb),
NULL);
if (GTK_HTML(widget)->engine->clue)
html_utils_get_accessible(GTK_HTML(widget)->engine->clue, accessible);
/* printf ("created new gtkhtml accessible object\n"); */
focus_object = gtk_html_a11y_get_focus_object (widget);
if (focus_object && gtk_html_a11y_focus_object != focus_object) {
gtk_html_a11y_focus_object = focus_object;
g_object_set_data (G_OBJECT (accessible), "gail-focus-object", focus_object);
}
return accessible;
}