mirror of
https://gitlab.gnome.org/GNOME/gtk.git
synced 2024-09-20 14:00:10 +00:00
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:
parent
77c0f9d8e6
commit
b7743430aa
@ -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));
|
||||
}
|
||||
|
||||
|
@ -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 ();
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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>
|
||||
|
Loading…
Reference in New Issue
Block a user