Commit 38b9f53c authored by Matthias Clasen's avatar Matthias Clasen Committed by Matthias Clasen
Browse files

Make the icon view accessible by implementing the necesssary ATK

Thu Aug 12 01:35:46 2004  Matthias Clasen  <maclas@gmx.de>

	* gtk/gtkiconview.c: Make the icon view accessible by
	implementing the necesssary ATK interfaces.  (#149728,
	Padraig O'Briain)
parent 001e6299
Thu Aug 12 01:35:46 2004 Matthias Clasen <maclas@gmx.de>
* gtk/gtkiconview.c: Make the icon view accessible by
implementing the necesssary ATK interfaces. (#149728,
Padraig O'Briain)
Thu Aug 12 00:02:29 2004 Matthias Clasen <maclas@gmx.de>
* gtk/gtkaction.c (gtk_action_new): Link to information about
......
Thu Aug 12 01:35:46 2004 Matthias Clasen <maclas@gmx.de>
* gtk/gtkiconview.c: Make the icon view accessible by
implementing the necesssary ATK interfaces. (#149728,
Padraig O'Briain)
Thu Aug 12 00:02:29 2004 Matthias Clasen <maclas@gmx.de>
* gtk/gtkaction.c (gtk_action_new): Link to information about
......
Thu Aug 12 01:35:46 2004 Matthias Clasen <maclas@gmx.de>
* gtk/gtkiconview.c: Make the icon view accessible by
implementing the necesssary ATK interfaces. (#149728,
Padraig O'Briain)
Thu Aug 12 00:02:29 2004 Matthias Clasen <maclas@gmx.de>
* gtk/gtkaction.c (gtk_action_new): Link to information about
......
Thu Aug 12 01:35:46 2004 Matthias Clasen <maclas@gmx.de>
* gtk/gtkiconview.c: Make the icon view accessible by
implementing the necesssary ATK interfaces. (#149728,
Padraig O'Briain)
Thu Aug 12 00:02:29 2004 Matthias Clasen <maclas@gmx.de>
* gtk/gtkaction.c (gtk_action_new): Link to information about
......
......@@ -20,6 +20,8 @@
#include <config.h>
#include <string.h>
#include <atk/atk.h>
#include <gdk/gdkkeysyms.h>
#include "gtkalias.h"
......@@ -30,6 +32,9 @@
#include "gtkmain.h"
#include "gtksignal.h"
#include "gtkintl.h"
#include "gtkaccessible.h"
#include "gtkwindow.h"
#include "gtktextbuffer.h"
#define MINIMUM_ICON_ITEM_WIDTH 100
#define ICON_TEXT_PADDING 3
......@@ -253,8 +258,8 @@ static GtkIconViewItem *gtk_icon_view_get_item_at_pos (GtkIconView *icon_view,
gint y);
/* Accessibility Support */
static AtkObject *gtk_icon_view_get_accessible (GtkWidget *widget);
static GtkContainerClass *parent_class = NULL;
static guint icon_view_signals[LAST_SIGNAL] = { 0 };
......@@ -293,6 +298,7 @@ gtk_icon_view_class_init (GtkIconViewClass *klass)
widget_class->motion_notify_event = gtk_icon_view_motion;
widget_class->button_press_event = gtk_icon_view_button_press;
widget_class->button_release_event = gtk_icon_view_button_release;
widget_class->get_accessible = gtk_icon_view_get_accessible;
klass->set_scroll_adjustments = gtk_icon_view_set_adjustments;
klass->select_all = gtk_icon_view_real_select_all;
......@@ -1952,6 +1958,9 @@ static void
gtk_icon_view_set_cursor_item (GtkIconView *icon_view,
GtkIconViewItem *item)
{
AtkObject *obj;
AtkObject *item_obj;
if (icon_view->priv->cursor_item == item)
return;
......@@ -1960,6 +1969,12 @@ gtk_icon_view_set_cursor_item (GtkIconView *icon_view,
icon_view->priv->cursor_item = item;
gtk_icon_view_queue_draw_item (icon_view, item);
/* Notify that accessible focus object has changed */
obj = gtk_widget_get_accessible (GTK_WIDGET (icon_view));
item_obj = atk_object_ref_accessible_child (obj, item->index);
atk_focus_tracker_notify (item_obj);
g_object_unref (item_obj);
}
......@@ -3448,3 +3463,2246 @@ gtk_icon_view_get_orientation (GtkIconView *icon_view)
return icon_view->priv->orientation;
}
/* Accessibility Support */
static gpointer accessible_parent_class;
static gpointer accessible_item_parent_class;
static GQuark accessible_private_data_quark = 0;
#define GTK_TYPE_ICON_VIEW_ITEM_ACCESSIBLE (gtk_icon_view_item_accessible_get_type ())
#define GTK_ICON_VIEW_ITEM_ACCESSIBLE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_ICON_VIEW_ITEM_ACCESSIBLE, GtkIconViewItemAccessible))
#define GTK_IS_ICON_VIEW_ITEM_ACCESSIBLE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_ICON_VIEW_ITEM_ACCESSIBLE))
static GType gtk_icon_view_item_accessible_get_type (void);
enum {
ACTION_ACTIVATE,
LAST_ACTION
};
typedef struct
{
AtkObject parent;
GtkIconViewItem *item;
GtkWidget *widget;
AtkStateSet *state_set;
gchar *text;
GtkTextBuffer *text_buffer;
gchar *action_descriptions[LAST_ACTION];
gchar *image_description;
guint action_idle_handler;
} GtkIconViewItemAccessible;
static const gchar *gtk_icon_view_item_accessible_action_names[] =
{
"activate",
NULL
};
static const gchar *gtk_icon_view_item_accessible_action_descriptions[] =
{
"Activate item",
NULL
};
typedef struct _GtkIconViewItemAccessibleClass
{
AtkObjectClass parent_class;
} GtkIconViewItemAccessibleClass;
static gboolean gtk_icon_view_item_accessible_is_showing (GtkIconViewItemAccessible *item);
static gboolean
gtk_icon_view_item_accessible_idle_do_action (gpointer data)
{
GtkIconViewItemAccessible *item;
GtkIconView *icon_view;
GtkTreePath *path;
item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (data);
item->action_idle_handler = NULL;
if (item->widget == NULL)
return FALSE;
icon_view = GTK_ICON_VIEW (item->widget);
path = gtk_tree_path_new_from_indices (item->item->index, -1);
gtk_icon_view_item_activated (icon_view, path);
gtk_tree_path_free (path);
return FALSE;
}
static gboolean
gtk_icon_view_item_accessible_action_do_action (AtkAction *action,
gint i)
{
GtkIconViewItemAccessible *item;
GtkIconView *icon_view;
if (i < 0 || i >= LAST_ACTION)
return FALSE;
item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (action);
if (!GTK_IS_ICON_VIEW (item->widget))
return FALSE;
if (atk_state_set_contains_state (item->state_set, ATK_STATE_DEFUNCT))
return FALSE;
icon_view = GTK_ICON_VIEW (item->widget);
switch (i)
{
case ACTION_ACTIVATE:
if (!item->action_idle_handler)
item->action_idle_handler = g_idle_add (gtk_icon_view_item_accessible_idle_do_action, item);
break;
default:
g_assert_not_reached ();
return FALSE;
}
return TRUE;
}
static gint
gtk_icon_view_item_accessible_action_get_n_actions (AtkAction *action)
{
return LAST_ACTION;
}
static const gchar *
gtk_icon_view_item_accessible_action_get_description (AtkAction *action,
gint i)
{
GtkIconViewItemAccessible *item;
if (i < 0 || i >= LAST_ACTION)
return NULL;
item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (action);
if (item->action_descriptions[i])
return item->action_descriptions[i];
else
return gtk_icon_view_item_accessible_action_descriptions[i];
}
static const gchar *
gtk_icon_view_item_accessible_action_get_name (AtkAction *action,
gint i)
{
if (i < 0 || i >= LAST_ACTION)
return NULL;
return gtk_icon_view_item_accessible_action_names[i];
}
static gboolean
gtk_icon_view_item_accessible_action_set_description (AtkAction *action,
gint i,
const gchar *description)
{
GtkIconViewItemAccessible *item;
if (i < 0 || i >= LAST_ACTION)
return FALSE;
item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (action);
if (item->action_descriptions[i])
g_free (item->action_descriptions[i]);
item->action_descriptions[i] = g_strdup (description);
return TRUE;
}
static void
atk_action_item_interface_init (AtkActionIface *iface)
{
iface->do_action = gtk_icon_view_item_accessible_action_do_action;
iface->get_n_actions = gtk_icon_view_item_accessible_action_get_n_actions;
iface->get_description = gtk_icon_view_item_accessible_action_get_description;
iface->get_name = gtk_icon_view_item_accessible_action_get_name;
iface->set_description = gtk_icon_view_item_accessible_action_set_description;
}
static const gchar *
gtk_icon_view_item_accessible_image_get_image_description (AtkImage *image)
{
GtkIconViewItemAccessible *item;
item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (image);
return item->image_description;
}
static gboolean
gtk_icon_view_item_accessible_image_set_image_description (AtkImage *image,
const gchar *description)
{
GtkIconViewItemAccessible *item;
item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (image);
g_free (item->image_description);
item->image_description = g_strdup (item->image_description);
return TRUE;
}
static void
gtk_icon_view_item_accessible_image_get_image_size (AtkImage *image,
gint *width,
gint *height)
{
GtkIconViewItemAccessible *item;
item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (image);
if (!GTK_IS_ICON_VIEW (item->widget))
return;
if (atk_state_set_contains_state (item->state_set, ATK_STATE_DEFUNCT))
return;
*width = item->item->pixbuf_width;
*height = item->item->pixbuf_height;
}
static void
gtk_icon_view_item_accessible_image_get_image_position (AtkImage *image,
gint *x,
gint *y,
AtkCoordType coord_type)
{
GtkIconViewItemAccessible *item;
item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (image);
if (!GTK_IS_ICON_VIEW (item->widget))
return;
if (atk_state_set_contains_state (item->state_set, ATK_STATE_DEFUNCT))
return;
atk_component_get_position (ATK_COMPONENT (image), x, y, coord_type);
*x+= item->item->pixbuf_x - item->item->x;
*y+= item->item->pixbuf_y - item->item->y;
}
static void
atk_image_item_interface_init (AtkImageIface *iface)
{
iface->get_image_description = gtk_icon_view_item_accessible_image_get_image_description;
iface->set_image_description = gtk_icon_view_item_accessible_image_set_image_description;
iface->get_image_size = gtk_icon_view_item_accessible_image_get_image_size;
iface->get_image_position = gtk_icon_view_item_accessible_image_get_image_position;
}
static gchar *
gtk_icon_view_item_accessible_text_get_text (AtkText *text,
gint start_pos,
gint end_pos)
{
GtkIconViewItemAccessible *item;
GtkTextIter start, end;
GtkTextBuffer *buffer;
item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (text);
if (!GTK_IS_ICON_VIEW (item->widget))
return NULL;
if (atk_state_set_contains_state (item->state_set, ATK_STATE_DEFUNCT))
return NULL;
buffer = item->text_buffer;
gtk_text_buffer_get_iter_at_offset (buffer, &start, start_pos);
if (end_pos < 0)
gtk_text_buffer_get_end_iter (buffer, &end);
else
gtk_text_buffer_get_iter_at_offset (buffer, &end, end_pos);
return gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
}
static gunichar
gtk_icon_view_item_accessible_text_get_character_at_offset (AtkText *text,
gint offset)
{
GtkIconViewItemAccessible *item;
GtkTextIter start, end;
GtkTextBuffer *buffer;
gchar *string;
gunichar unichar;
item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (text);
if (!GTK_IS_ICON_VIEW (item->widget))
return '\0';
if (atk_state_set_contains_state (item->state_set, ATK_STATE_DEFUNCT))
return '\0';
buffer = item->text_buffer;
if (offset >= gtk_text_buffer_get_char_count (buffer))
return '\0';
gtk_text_buffer_get_iter_at_offset (buffer, &start, offset);
end = start;
gtk_text_iter_forward_char (&end);
string = gtk_text_buffer_get_slice (buffer, &start, &end, FALSE);
unichar = g_utf8_get_char (string);
g_free(string);
return unichar;
}
static void
get_pango_text_offsets (PangoLayout *layout,
GtkTextBuffer *buffer,
gint function,
AtkTextBoundary boundary_type,
gint offset,
gint *start_offset,
gint *end_offset,
GtkTextIter *start_iter,
GtkTextIter *end_iter)
{
PangoLayoutIter *iter;
PangoLayoutLine *line, *prev_line = NULL, *prev_prev_line = NULL;
gint index, start_index, end_index;
const gchar *text;
gboolean found = FALSE;
text = pango_layout_get_text (layout);
index = g_utf8_offset_to_pointer (text, offset) - text;
iter = pango_layout_get_iter (layout);
do
{
line = pango_layout_iter_get_line (iter);
start_index = line->start_index;
end_index = start_index + line->length;
if (index >= start_index && index <= end_index)
{
/*
* Found line for offset
*/
switch (function)
{
case 0:
/*
* We want the previous line
*/
if (prev_line)
{
switch (boundary_type)
{
case ATK_TEXT_BOUNDARY_LINE_START:
end_index = start_index;
start_index = prev_line->start_index;
break;
case ATK_TEXT_BOUNDARY_LINE_END:
if (prev_prev_line)
start_index = prev_prev_line->start_index +
prev_prev_line->length;
end_index = prev_line->start_index + prev_line->length;
break;
default:
g_assert_not_reached();
}
}
else
start_index = end_index = 0;
break;
case 1:
switch (boundary_type)
{
case ATK_TEXT_BOUNDARY_LINE_START:
if (pango_layout_iter_next_line (iter))
end_index = pango_layout_iter_get_line (iter)->start_index;
break;
case ATK_TEXT_BOUNDARY_LINE_END:
if (prev_line)
start_index = prev_line->start_index +
prev_line->length;
break;
default:
g_assert_not_reached();
}
break;
case 2:
/*
* We want the next line
*/
if (pango_layout_iter_next_line (iter))
{
line = pango_layout_iter_get_line (iter);
switch (boundary_type)
{
case ATK_TEXT_BOUNDARY_LINE_START:
start_index = line->start_index;
if (pango_layout_iter_next_line (iter))
end_index = pango_layout_iter_get_line (iter)->start_index;
else
end_index = start_index + line->length;
break;
case ATK_TEXT_BOUNDARY_LINE_END:
start_index = end_index;
end_index = line->start_index + line->length;
break;
default:
g_assert_not_reached();
}
}
else
start_index = end_index;
break;
}
found = TRUE;
break;
}
prev_prev_line = prev_line;
prev_line = line;
}
while (pango_layout_iter_next_line (iter));
if (!found)
{
start_index = prev_line->start_index + prev_line->length;
end_index = start_index;
}
pango_layout_iter_free (iter);
*start_offset = g_utf8_pointer_to_offset (text, text + start_index);
*end_offset = g_utf8_pointer_to_offset (text, text + end_index);
gtk_text_buffer_get_iter_at_offset (buffer, start_iter, *start_offset);
gtk_text_buffer_get_iter_at_offset (buffer, end_iter, *end_offset);
}
static gchar*
gtk_icon_view_item_accessible_text_get_text_before_offset (AtkText *text,
gint offset,
AtkTextBoundary boundary_type,
gint *start_offset,
gint *end_offset)
{
GtkIconViewItemAccessible *item;
GtkTextIter start, end;
GtkTextBuffer *buffer;
GtkIconView *icon_view;
item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (text);
if (!GTK_IS_ICON_VIEW (item->widget))
return NULL;
if (atk_state_set_contains_state (item->state_set, ATK_STATE_DEFUNCT))
return NULL;
buffer = item->text_buffer;
if (!gtk_text_buffer_get_char_count (buffer))
{
*start_offset = 0;
*end_offset = 0;
return g_strdup ("");
}
gtk_text_buffer_get_iter_at_offset (buffer, &start, offset);
end = start;
switch (boundary_type)
{
case ATK_TEXT_BOUNDARY_CHAR:
gtk_text_iter_backward_char(&start);
break;
case ATK_TEXT_BOUNDARY_WORD_START:
if (!gtk_text_iter_starts_word (&start))
gtk_text_iter_backward_word_start (&start);
end = start;
gtk_text_iter_backward_word_start(&start);
break;
case ATK_TEXT_BOUNDARY_WORD_END:
if (gtk_text_iter_inside_word (&start) &&
!gtk_text_iter_starts_word (&start))
gtk_text_iter_backward_word_start (&start);
while (!gtk_text_iter_ends_word (&start))
{
if (!gtk_text_iter_backward_char (&start))
break;
}
end = start;
gtk_text_iter_backward_word_start(&start);
while (!gtk_text_iter_ends_word (&start))
{
if (!gtk_text_iter_backward_char (&start))
break;
}
break;
case ATK_TEXT_BOUNDARY_SENTENCE_START:
if (!gtk_text_iter_starts_sentence (&start))
gtk_text_iter_backward_sentence_start (&start);
end = start;
gtk_text_iter_backward_sentence_start (&start);
break;
case ATK_TEXT_BOUNDARY_SENTENCE_END:
if (gtk_text_iter_inside_sentence (&start) &&
!gtk_text_iter_starts_sentence (&start))
gtk_text_iter_backward_sentence_start (&start);
while (!gtk_text_iter_ends_sentence (&start))
{
if (!gtk_text_iter_backward_char (&start))
break;
}
end = start;
gtk_text_iter_backward_sentence_start (&start);
while (!gtk_text_iter_ends_sentence (&start))
{
if (!gtk_text_iter_backward_char (&start))
break;
}
break;
case ATK_TEXT_BOUNDARY_LINE_START:
case ATK_TEXT_BOUNDARY_LINE_END:
icon_view = GTK_ICON_VIEW (item->widget);
gtk_icon_view_update_item_text (icon_view, item->item);
get_pango_text_offsets (icon_view->priv->layout,
buffer,
0,
boundary_type,
offset,