Add accessibles for GtkEntry icons

Expose GtkEntry icons as child accessibles of a GtkEntry, and provide
actions to simulate clicking them. Also, refactor the a11y children test
slightly to add a test.

https://bugzilla.gnome.org/show_bug.cgi?id=686347
This commit is contained in:
Mike Gorse 2012-11-11 11:00:49 -06:00
parent 77c0f9d8e6
commit b7743430aa
4 changed files with 676 additions and 18 deletions

View File

@ -17,18 +17,351 @@
#include "config.h"
#include <string.h>
#include <gtk/gtk.h>
#include "gtkpango.h"
#include "gtkentryaccessible.h"
#include "gtkentryprivate.h"
#include "gtkcomboboxaccessible.h"
#define GTK_TYPE_ENTRY_ICON_ACCESSIBLE (_gtk_entry_icon_accessible_get_type ())
#define GTK_ENTRY_ICON_ACCESSIBLE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_ENTRY_ICON_ACCESSIBLE, GtkEntryIconAccessible))
#define GTK_IS_ENTRY_ICON_ACCESSIBLE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_ENTRY_ICON_ACCESSIBLE))
struct _GtkEntryAccessiblePrivate
{
gint cursor_position;
gint selection_bound;
AtkObject *icons[2];
};
typedef struct _GtkEntryIconAccessible GtkEntryIconAccessible;
typedef struct _GtkEntryIconAccessibleClass GtkEntryIconAccessibleClass;
struct _GtkEntryIconAccessible
{
AtkObject parent;
GtkEntryAccessible *entry;
GtkEntryIconPosition pos;
};
struct _GtkEntryIconAccessibleClass
{
AtkObjectClass parent_class;
};
static void atk_action_interface_init (AtkActionIface *iface);
static void icon_atk_action_interface_init (AtkActionIface *iface);
static void icon_atk_component_interface_init (AtkComponentIface *iface);
GType _gtk_entry_icon_accessible_get_type (void);
G_DEFINE_TYPE_WITH_CODE (GtkEntryIconAccessible, _gtk_entry_icon_accessible, ATK_TYPE_OBJECT,
G_IMPLEMENT_INTERFACE (ATK_TYPE_ACTION, icon_atk_action_interface_init)
G_IMPLEMENT_INTERFACE (ATK_TYPE_COMPONENT, icon_atk_component_interface_init))
static void
gtk_entry_icon_accessible_remove_entry (gpointer data, GObject *obj)
{
GtkEntryIconAccessible *icon = data;
if (icon->entry)
{
icon->entry = NULL;
g_object_notify (G_OBJECT (icon), "accessible-parent");
atk_object_notify_state_change (ATK_OBJECT (icon), ATK_STATE_DEFUNCT, TRUE);
}
}
static AtkObject *
gtk_entry_icon_accessible_new (GtkEntryAccessible *entry,
GtkEntryIconPosition pos)
{
GtkEntryIconAccessible *icon;
AtkObject *accessible;
icon = g_object_new (_gtk_entry_icon_accessible_get_type (), NULL);
icon->entry = entry;
g_object_weak_ref (G_OBJECT (entry),
gtk_entry_icon_accessible_remove_entry,
icon);
icon->pos = pos;
accessible = ATK_OBJECT (icon);
atk_object_initialize (accessible, NULL);
return accessible;
}
static void
_gtk_entry_icon_accessible_init (GtkEntryIconAccessible *icon)
{
}
static void
gtk_entry_icon_accessible_initialize (AtkObject *obj,
gpointer data)
{
GtkEntryIconAccessible *icon = GTK_ENTRY_ICON_ACCESSIBLE (obj);
GtkWidget *widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (icon->entry));
GtkEntry *gtk_entry = GTK_ENTRY (widget);
const gchar *name;
gchar *text;
ATK_OBJECT_CLASS (_gtk_entry_icon_accessible_parent_class)->initialize (obj, data);
atk_object_set_role (obj, ATK_ROLE_ICON);
name = gtk_entry_get_icon_name (gtk_entry, icon->pos);
if (name)
atk_object_set_name (obj, name);
text = gtk_entry_get_icon_tooltip_text (gtk_entry, icon->pos);
if (text)
{
atk_object_set_description (obj, text);
g_free (text);
}
atk_object_set_parent (obj, ATK_OBJECT (icon->entry));
}
static AtkObject *
gtk_entry_icon_accessible_get_parent (AtkObject *accessible)
{
GtkEntryIconAccessible *icon = GTK_ENTRY_ICON_ACCESSIBLE (accessible);
return ATK_OBJECT (icon->entry);
}
static AtkStateSet *
gtk_entry_icon_accessible_ref_state_set (AtkObject *accessible)
{
GtkEntryIconAccessible *icon = GTK_ENTRY_ICON_ACCESSIBLE (accessible);
AtkStateSet *set = atk_state_set_new ();
AtkStateSet *entry_set;
GtkWidget *widget;
GtkEntry *gtk_entry;
if (!icon->entry)
{
atk_state_set_add_state (set, ATK_STATE_DEFUNCT);
return set;
}
entry_set = atk_object_ref_state_set (ATK_OBJECT (icon->entry));
if (!entry_set || atk_state_set_contains_state (entry_set, ATK_STATE_DEFUNCT))
{
atk_state_set_add_state (set, ATK_STATE_DEFUNCT);
g_clear_object (&entry_set);
return set;
}
widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (icon->entry));
gtk_entry = GTK_ENTRY (widget);
if (atk_state_set_contains_state (entry_set, ATK_STATE_ENABLED))
atk_state_set_add_state (set, ATK_STATE_ENABLED);
if (atk_state_set_contains_state (entry_set, ATK_STATE_SENSITIVE))
atk_state_set_add_state (set, ATK_STATE_SENSITIVE);
if (atk_state_set_contains_state (entry_set, ATK_STATE_SHOWING))
atk_state_set_add_state (set, ATK_STATE_SHOWING);
if (atk_state_set_contains_state (entry_set, ATK_STATE_VISIBLE))
atk_state_set_add_state (set, ATK_STATE_VISIBLE);
if (!gtk_entry_get_icon_sensitive (gtk_entry, icon->pos))
atk_state_set_remove_state (set, ATK_STATE_SENSITIVE);
if (!gtk_entry_get_icon_activatable (gtk_entry, icon->pos))
atk_state_set_remove_state (set, ATK_STATE_ENABLED);
g_object_unref (entry_set);
return set;
}
static void
gtk_entry_icon_accessible_invalidate (GtkEntryIconAccessible *icon)
{
if (!icon->entry)
return;
g_object_weak_unref (G_OBJECT (icon->entry),
gtk_entry_icon_accessible_remove_entry,
icon);
gtk_entry_icon_accessible_remove_entry (icon, NULL);
}
static void
gtk_entry_icon_accessible_finalize (GObject *object)
{
GtkEntryIconAccessible *icon = GTK_ENTRY_ICON_ACCESSIBLE (object);
gtk_entry_icon_accessible_invalidate (icon);
G_OBJECT_CLASS (_gtk_entry_icon_accessible_parent_class)->finalize (object);
}
static void
_gtk_entry_icon_accessible_class_init (GtkEntryIconAccessibleClass *klass)
{
AtkObjectClass *atk_class = ATK_OBJECT_CLASS (klass);
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
atk_class->initialize = gtk_entry_icon_accessible_initialize;
atk_class->get_parent = gtk_entry_icon_accessible_get_parent;
atk_class->ref_state_set = gtk_entry_icon_accessible_ref_state_set;
gobject_class->finalize = gtk_entry_icon_accessible_finalize;
}
static gboolean
gtk_entry_icon_accessible_do_action (AtkAction *action,
gint i)
{
GtkEntryIconAccessible *icon = (GtkEntryIconAccessible *)action;
GtkWidget *widget;
GtkEntry *gtk_entry;
GdkEvent event;
GdkRectangle icon_area;
widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (icon->entry));
if (widget == NULL)
return FALSE;
if (i != 0)
return FALSE;
if (!gtk_widget_is_sensitive (widget) || !gtk_widget_get_visible (widget))
return FALSE;
gtk_entry = GTK_ENTRY (widget);
if (!gtk_entry_get_icon_sensitive (gtk_entry, icon->pos) ||
!gtk_entry_get_icon_activatable (gtk_entry, icon->pos))
return FALSE;
gtk_entry_get_icon_area (gtk_entry, icon->pos, &icon_area);
memset (&event, 0, sizeof (event));
event.button.type = GDK_BUTTON_PRESS;
event.button.window = gtk_widget_get_window (widget);
event.button.button = 1;
event.button.send_event = TRUE;
event.button.time = GDK_CURRENT_TIME;
event.button.x = icon_area.x;
event.button.y = icon_area.y;
g_signal_emit_by_name (widget, "icon-press", 0, icon->pos, &event);
return TRUE;
}
static gint
gtk_entry_icon_accessible_get_n_actions (AtkAction *action)
{
GtkEntryIconAccessible *icon = GTK_ENTRY_ICON_ACCESSIBLE (action);
GtkWidget *widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (icon->entry));
GtkEntry *gtk_entry = GTK_ENTRY (widget);
return (gtk_entry_get_icon_activatable (gtk_entry, icon->pos) ? 1 : 0);
}
static const gchar *
gtk_entry_icon_accessible_get_name (AtkAction *action,
gint i)
{
GtkEntryIconAccessible *icon = GTK_ENTRY_ICON_ACCESSIBLE (action);
GtkWidget *widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (icon->entry));
GtkEntry *gtk_entry = GTK_ENTRY (widget);
if (i != 0)
return NULL;
if (!gtk_entry_get_icon_activatable (gtk_entry, icon->pos))
return NULL;
return "activate";
}
static void
icon_atk_action_interface_init (AtkActionIface *iface)
{
iface->do_action = gtk_entry_icon_accessible_do_action;
iface->get_n_actions = gtk_entry_icon_accessible_get_n_actions;
iface->get_name = gtk_entry_icon_accessible_get_name;
}
static void
gtk_entry_icon_accessible_get_extents (AtkComponent *component,
gint *x,
gint *y,
gint *width,
gint *height,
AtkCoordType coord_type)
{
GtkEntryIconAccessible *icon = GTK_ENTRY_ICON_ACCESSIBLE (component);
GdkRectangle icon_area;
GtkEntry *gtk_entry;
GtkWidget *widget;
*x = G_MININT;
atk_component_get_extents (ATK_COMPONENT (icon->entry), x, y, width, height,
coord_type);
if (*x == G_MININT)
return;
widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (icon->entry));
gtk_entry = GTK_ENTRY (widget);
gtk_entry_get_icon_area (gtk_entry, icon->pos, &icon_area);
*width = icon_area.width;
*height = icon_area.height;
*x += icon_area.x;
*y += icon_area.y;
}
static void
gtk_entry_icon_accessible_get_position (AtkComponent *component,
gint *x,
gint *y,
AtkCoordType coord_type)
{
GtkEntryIconAccessible *icon = GTK_ENTRY_ICON_ACCESSIBLE (component);
GdkRectangle icon_area;
GtkEntry *gtk_entry;
GtkWidget *widget;
*x = G_MININT;
atk_component_get_position (ATK_COMPONENT (icon->entry), x, y, coord_type);
if (*x == G_MININT)
return;
widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (icon->entry));
gtk_entry = GTK_ENTRY (widget);
gtk_entry_get_icon_area (gtk_entry, icon->pos, &icon_area);
*x += icon_area.x;
*y += icon_area.y;
}
static void
gtk_entry_icon_accessible_get_size (AtkComponent *component,
gint *width,
gint *height)
{
GtkEntryIconAccessible *icon = GTK_ENTRY_ICON_ACCESSIBLE (component);
GdkRectangle icon_area;
GtkEntry *gtk_entry;
GtkWidget *widget;
widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (icon->entry));
gtk_entry = GTK_ENTRY (widget);
gtk_entry_get_icon_area (gtk_entry, icon->pos, &icon_area);
*width = icon_area.width;
*height = icon_area.height;
}
static void
icon_atk_component_interface_init (AtkComponentIface *iface)
{
iface->get_extents = gtk_entry_icon_accessible_get_extents;
iface->get_size = gtk_entry_icon_accessible_get_size;
iface->get_position = gtk_entry_icon_accessible_get_position;
}
/* Callbacks */
static void insert_text_cb (GtkEditable *editable,
@ -137,11 +470,13 @@ gtk_entry_accessible_notify_gtk (GObject *obj,
AtkObject* atk_obj;
GtkEntry* gtk_entry;
GtkEntryAccessible* entry;
GtkEntryAccessiblePrivate *priv;
widget = GTK_WIDGET (obj);
atk_obj = gtk_widget_get_accessible (widget);
gtk_entry = GTK_ENTRY (widget);
entry = GTK_ENTRY_ACCESSIBLE (atk_obj);
priv = entry->priv;
if (g_strcmp0 (pspec->name, "cursor-position") == 0)
{
@ -174,6 +509,119 @@ gtk_entry_accessible_notify_gtk (GObject *obj,
new_role = visibility ? ATK_ROLE_TEXT : ATK_ROLE_PASSWORD_TEXT;
atk_object_set_role (atk_obj, new_role);
}
else if (g_strcmp0 (pspec->name, "primary-icon-storage-type") == 0)
{
if (gtk_entry_get_icon_storage_type (gtk_entry, GTK_ENTRY_ICON_PRIMARY) != GTK_IMAGE_EMPTY && !priv->icons[GTK_ENTRY_ICON_PRIMARY])
{
priv->icons[GTK_ENTRY_ICON_PRIMARY] = gtk_entry_icon_accessible_new (entry, GTK_ENTRY_ICON_PRIMARY);
g_signal_emit_by_name (entry, "children-changed::add", 0,
priv->icons[GTK_ENTRY_ICON_PRIMARY], NULL);
}
else if (gtk_entry_get_icon_storage_type (gtk_entry, GTK_ENTRY_ICON_PRIMARY) == GTK_IMAGE_EMPTY && priv->icons[GTK_ENTRY_ICON_PRIMARY])
{
gtk_entry_icon_accessible_invalidate (GTK_ENTRY_ICON_ACCESSIBLE (priv->icons[GTK_ENTRY_ICON_PRIMARY]));
g_signal_emit_by_name (entry, "children-changed::remove", 0,
priv->icons[GTK_ENTRY_ICON_PRIMARY], NULL);
g_clear_object (&priv->icons[GTK_ENTRY_ICON_PRIMARY]);
}
}
else if (g_strcmp0 (pspec->name, "secondary-icon-storage-type") == 0)
{
gint index = (priv->icons[GTK_ENTRY_ICON_PRIMARY] ? 1 : 0);
if (gtk_entry_get_icon_storage_type (gtk_entry, GTK_ENTRY_ICON_SECONDARY) != GTK_IMAGE_EMPTY && !priv->icons[GTK_ENTRY_ICON_SECONDARY])
{
priv->icons[GTK_ENTRY_ICON_SECONDARY] = gtk_entry_icon_accessible_new (entry, GTK_ENTRY_ICON_SECONDARY);
g_signal_emit_by_name (entry, "children-changed::add", index,
priv->icons[GTK_ENTRY_ICON_SECONDARY], NULL);
}
else if (gtk_entry_get_icon_storage_type (gtk_entry, GTK_ENTRY_ICON_SECONDARY) == GTK_IMAGE_EMPTY && priv->icons[GTK_ENTRY_ICON_SECONDARY])
{
gtk_entry_icon_accessible_invalidate (GTK_ENTRY_ICON_ACCESSIBLE (priv->icons[GTK_ENTRY_ICON_SECONDARY]));
g_signal_emit_by_name (entry, "children-changed::remove", index,
priv->icons[GTK_ENTRY_ICON_SECONDARY], NULL);
g_clear_object (&priv->icons[GTK_ENTRY_ICON_SECONDARY]);
}
}
else if (g_strcmp0 (pspec->name, "primary-icon-name") == 0)
{
if (priv->icons[GTK_ENTRY_ICON_PRIMARY])
{
const gchar *name;
name = gtk_entry_get_icon_name (gtk_entry,
GTK_ENTRY_ICON_PRIMARY);
atk_object_set_name (priv->icons[GTK_ENTRY_ICON_PRIMARY], name);
}
}
else if (g_strcmp0 (pspec->name, "secondary-icon-name") == 0)
{
if (priv->icons[GTK_ENTRY_ICON_SECONDARY])
{
const gchar *name;
name = gtk_entry_get_icon_name (gtk_entry,
GTK_ENTRY_ICON_SECONDARY);
atk_object_set_name (priv->icons[GTK_ENTRY_ICON_SECONDARY], name);
}
}
else if (g_strcmp0 (pspec->name, "primary-icon-tooltip-text") == 0)
{
if (priv->icons[GTK_ENTRY_ICON_PRIMARY])
{
gchar *text;
text = gtk_entry_get_icon_tooltip_text (gtk_entry,
GTK_ENTRY_ICON_PRIMARY);
atk_object_set_description (priv->icons[GTK_ENTRY_ICON_PRIMARY],
text);
g_free (text);
}
}
else if (g_strcmp0 (pspec->name, "secondary-icon-tooltip-text") == 0)
{
if (priv->icons[GTK_ENTRY_ICON_SECONDARY])
{
gchar *text;
text = gtk_entry_get_icon_tooltip_text (gtk_entry,
GTK_ENTRY_ICON_SECONDARY);
atk_object_set_description (priv->icons[GTK_ENTRY_ICON_SECONDARY],
text);
g_free (text);
}
}
else if (g_strcmp0 (pspec->name, "primary-icon-activatable") == 0)
{
if (priv->icons[GTK_ENTRY_ICON_PRIMARY])
{
gboolean on = gtk_entry_get_icon_activatable (gtk_entry, GTK_ENTRY_ICON_PRIMARY);
atk_object_notify_state_change (priv->icons[GTK_ENTRY_ICON_PRIMARY],
ATK_STATE_ENABLED, on);
}
}
else if (g_strcmp0 (pspec->name, "secondary-icon-activatable") == 0)
{
if (priv->icons[GTK_ENTRY_ICON_SECONDARY])
{
gboolean on = gtk_entry_get_icon_activatable (gtk_entry, GTK_ENTRY_ICON_SECONDARY);
atk_object_notify_state_change (priv->icons[GTK_ENTRY_ICON_SECONDARY],
ATK_STATE_ENABLED, on);
}
}
else if (g_strcmp0 (pspec->name, "primary-icon-sensitive") == 0)
{
if (priv->icons[GTK_ENTRY_ICON_PRIMARY])
{
gboolean on = gtk_entry_get_icon_sensitive (gtk_entry, GTK_ENTRY_ICON_PRIMARY);
atk_object_notify_state_change (priv->icons[GTK_ENTRY_ICON_PRIMARY],
ATK_STATE_SENSITIVE, on);
}
}
else if (g_strcmp0 (pspec->name, "secondary-icon-sensitive") == 0)
{
if (priv->icons[GTK_ENTRY_ICON_SECONDARY])
{
gboolean on = gtk_entry_get_icon_sensitive (gtk_entry, GTK_ENTRY_ICON_SECONDARY);
atk_object_notify_state_change (priv->icons[GTK_ENTRY_ICON_SECONDARY],
ATK_STATE_SENSITIVE, on);
}
}
else
GTK_WIDGET_ACCESSIBLE_CLASS (_gtk_entry_accessible_parent_class)->notify_gtk (obj, pspec);
}
@ -192,19 +640,98 @@ gtk_entry_accessible_get_index_in_parent (AtkObject *accessible)
return ATK_OBJECT_CLASS (_gtk_entry_accessible_parent_class)->get_index_in_parent (accessible);
}
static gint
gtk_entry_accessible_get_n_children (AtkObject* obj)
{
GtkWidget *widget;
GtkEntry *entry;
gint count = 0;
widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (obj));
if (widget == NULL)
return 0;
entry = GTK_ENTRY (widget);
if (gtk_entry_get_icon_storage_type (entry, GTK_ENTRY_ICON_PRIMARY) != GTK_IMAGE_EMPTY)
count++;
if (gtk_entry_get_icon_storage_type (entry, GTK_ENTRY_ICON_SECONDARY) != GTK_IMAGE_EMPTY)
count++;
return count;
}
static AtkObject *
gtk_entry_accessible_ref_child (AtkObject *obj,
gint i)
{
GtkEntryAccessible *accessible = GTK_ENTRY_ACCESSIBLE (obj);
GtkEntryAccessiblePrivate *priv = accessible->priv;
GtkWidget *widget;
GtkEntry *entry;
GtkEntryIconPosition pos;
widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (obj));
if (widget == NULL)
return NULL;
entry = GTK_ENTRY (widget);
switch (i)
{
case 0:
if (gtk_entry_get_icon_storage_type (entry, GTK_ENTRY_ICON_PRIMARY) != GTK_IMAGE_EMPTY)
pos = GTK_ENTRY_ICON_PRIMARY;
else if (gtk_entry_get_icon_storage_type (entry, GTK_ENTRY_ICON_SECONDARY) != GTK_IMAGE_EMPTY)
pos = GTK_ENTRY_ICON_SECONDARY;
else
return NULL;
break;
case 1:
if (gtk_entry_get_icon_storage_type (entry, GTK_ENTRY_ICON_PRIMARY) == GTK_IMAGE_EMPTY)
return NULL;
if (gtk_entry_get_icon_storage_type (entry, GTK_ENTRY_ICON_SECONDARY) == GTK_IMAGE_EMPTY)
return NULL;
pos = GTK_ENTRY_ICON_SECONDARY;
break;
default:
return NULL;
}
if (!priv->icons[pos])
priv->icons[pos] = gtk_entry_icon_accessible_new (accessible, pos);
return g_object_ref (priv->icons[pos]);
}
static void
gtk_entry_accessible_finalize (GObject *object)
{
GtkEntryAccessible *entry = GTK_ENTRY_ACCESSIBLE (object);
GtkEntryAccessiblePrivate *priv = entry->priv;
g_clear_object (&priv->icons[GTK_ENTRY_ICON_PRIMARY]);
g_clear_object (&priv->icons[GTK_ENTRY_ICON_SECONDARY]);
G_OBJECT_CLASS (_gtk_entry_accessible_parent_class)->finalize (object);
}
static void
_gtk_entry_accessible_class_init (GtkEntryAccessibleClass *klass)
{
AtkObjectClass *class = ATK_OBJECT_CLASS (klass);
GtkWidgetAccessibleClass *widget_class = (GtkWidgetAccessibleClass*)klass;
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
class->ref_state_set = gtk_entry_accessible_ref_state_set;
class->get_index_in_parent = gtk_entry_accessible_get_index_in_parent;
class->initialize = gtk_entry_accessible_initialize;
class->get_attributes = gtk_entry_accessible_get_attributes;
class->get_n_children = gtk_entry_accessible_get_n_children;
class->ref_child = gtk_entry_accessible_ref_child;
widget_class->notify_gtk = gtk_entry_accessible_notify_gtk;
gobject_class->finalize = gtk_entry_accessible_finalize;
g_type_class_add_private (klass, sizeof (GtkEntryAccessiblePrivate));
}

View File

@ -23,6 +23,12 @@
#include <gtk/gtk.h>
#include <string.h>
typedef struct
{
GtkWidget *widget;
gpointer child[3];
} STATE;
static void
test_scrolled_window_child_count (void)
{
@ -70,16 +76,38 @@ add_child (GtkWidget *container,
}
static void
remove_child (GtkWidget *container,
GtkWidget *child)
remove_child (STATE *state,
gint i)
{
if (GTK_IS_SCROLLED_WINDOW (container))
GtkWidget *child;
if (GTK_IS_ENTRY (state->widget))
{
if (gtk_widget_get_parent (child) != container)
switch (i)
{
case 0:
gtk_entry_set_icon_from_gicon (GTK_ENTRY (state->widget),
GTK_ENTRY_ICON_PRIMARY,
NULL);
return;
case 1:
gtk_entry_set_icon_from_gicon (GTK_ENTRY (state->widget),
GTK_ENTRY_ICON_SECONDARY,
NULL);
return;
default:
return;
}
}
child = state->child [i];
if (GTK_IS_SCROLLED_WINDOW (state->widget))
{
if (gtk_widget_get_parent (child) != state->widget)
child = gtk_widget_get_parent (child);
}
gtk_container_remove (GTK_CONTAINER (container), child);
gtk_container_remove (GTK_CONTAINER (state->widget), child);
}
static void
@ -89,6 +117,34 @@ parent_notify (AtkObject *obj, GParamSpec *pspec, SignalData *data)
data->parent = atk_object_get_parent (obj);
}
gboolean
do_create_child (STATE *state, gint i)
{
if (GTK_IS_ENTRY (state->widget))
{
switch (i)
{
case 0:
gtk_entry_set_icon_from_stock (GTK_ENTRY (state->widget),
GTK_ENTRY_ICON_PRIMARY,
GTK_STOCK_CAPS_LOCK_WARNING);
return TRUE;
case 1:
gtk_entry_set_icon_from_stock (GTK_ENTRY (state->widget),
GTK_ENTRY_ICON_SECONDARY,
GTK_STOCK_CLEAR);
return TRUE;
default:
return FALSE;
}
}
else if (gtk_container_child_type (GTK_CONTAINER (state->widget)) == G_TYPE_NONE)
return FALSE;
state->child[i] = gtk_label_new ("bla");
return TRUE;
}
static void
test_add_remove (GtkWidget *widget)
{
@ -97,10 +153,11 @@ test_add_remove (GtkWidget *widget)
SignalData add_data;
SignalData remove_data;
SignalData parent_data[3];
GtkWidget *child[3];
STATE state;
gint i, j;
gint step_children;
state.widget = widget;
accessible = gtk_widget_get_accessible (widget);
add_data.count = 0;
@ -114,35 +171,44 @@ test_add_remove (GtkWidget *widget)
for (i = 0; i < 3; i++)
{
if (gtk_container_child_type (GTK_CONTAINER (widget)) == G_TYPE_NONE)
if (!do_create_child (&state, i))
break;
child[i] = gtk_label_new ("bla");
parent_data[i].count = 0;
child_accessible = gtk_widget_get_accessible (child[i]);
g_signal_connect (child_accessible, "notify::accessible-parent",
G_CALLBACK (parent_notify), &(parent_data[i]));
add_child (widget, child[i]);
if (!GTK_IS_ENTRY (widget))
{
parent_data[i].count = 0;
child_accessible = gtk_widget_get_accessible (state.child[i]);
g_signal_connect (child_accessible, "notify::accessible-parent",
G_CALLBACK (parent_notify), &(parent_data[i]));
add_child (widget, state.child[i]);
}
else
child_accessible = atk_object_ref_accessible_child (accessible, i);
g_assert_cmpint (add_data.count, ==, i + 1);
g_assert_cmpint (add_data.n_children, ==, step_children + i + 1);
g_assert_cmpint (remove_data.count, ==, 0);
g_assert_cmpint (parent_data[i].count, ==, 1);
if (!GTK_IS_ENTRY (widget))
g_assert_cmpint (parent_data[i].count, ==, 1);
if (GTK_IS_SCROLLED_WINDOW (widget) ||
GTK_IS_NOTEBOOK (widget))
g_assert (atk_object_get_parent (ATK_OBJECT (parent_data[i].parent)) == accessible);
else if (GTK_IS_ENTRY (widget))
g_assert (atk_object_get_parent (child_accessible) == accessible);
else
g_assert (parent_data[i].parent == accessible);
if (GTK_IS_ENTRY (widget))
g_object_unref (child_accessible);
}
for (j = 0 ; j < i; j++)
{
remove_child (widget, child[j]);
remove_child (&state, j);
g_assert_cmpint (add_data.count, ==, i);
g_assert_cmpint (remove_data.count, ==, j + 1);
g_assert_cmpint (remove_data.n_children, ==, step_children + i - j - 1);
if (parent_data[j].count == 2)
g_assert (parent_data[j].parent == NULL);
else
else if (!GTK_IS_ENTRY (widget))
{
AtkStateSet *set;
set = atk_object_ref_state_set (ATK_OBJECT (parent_data[j].parent));
@ -205,6 +271,7 @@ main (int argc, char *argv[])
add_child_tests (gtk_statusbar_new ());
#endif
add_child_tests (gtk_notebook_new ());
add_child_tests (gtk_entry_new ());
return g_test_run ();
}

View File

@ -219,10 +219,66 @@ window1
<AtkAction>
action 0 name: activate
action 0 keybinding: <Alt>p
entry3
"text"
parent: box1
index: 5
state: editable enabled focusable sensitive single-line visible
toolkit: gtk
<AtkComponent>
layer: widget
alpha: 1
<AtkText>
text: icons
character count: 5
caret offset: 0
default attributes: bg-color: <omitted>
bg-full-height: 0
direction: <omitted>
editable: false
family-name: <omitted>
fg-color: <omitted>
indent: 0
invisible: false
justification: left
language: <omitted>
left-margin: 0
pixels-above-lines: 0
pixels-below-lines: 0
pixels-inside-wrap: 0
right-margin: 0
rise: 0
scale: 1
size: <omitted>
stretch: <omitted>
strikethrough: false
style: <omitted>
underline: none
variant: <omitted>
weight: <omitted>
wrap-mode: word
<AtkAction>
action 0 name: activate
unnamed-GtkEntryIconAccessible-0
"icon"
state: enabled sensitive visible
<AtkComponent>
layer: widget
alpha: 1
<AtkAction>
action 0 name: activate
unnamed-GtkEntryIconAccessible-1
"icon"
state: enabled sensitive visible
<AtkComponent>
layer: widget
alpha: 1
<AtkAction>
action 0 name: activate
spinbutton1
"spin button"
parent: box1
index: 5
index: 6
labelled-by: label3
state: editable enabled focusable horizontal sensitive single-line visible
toolkit: gtk

View File

@ -53,6 +53,14 @@
<property name="invisible_char_set">True</property>
</object>
</child>
<child>
<object class="GtkEntry" id="entry3">
<property name="text" translatable="yes">icons</property>
<property name="visible">True</property>
<property name="primary-icon-stock">stock1</property>
<property name="secondary-icon-stock">stock2</property>
</object>
</child>
<child>
<object class="GtkSpinButton" id="spinbutton1">
<property name="adjustment">adjustment1</property>