1 /* GTK+ - accessibility implementations
2 * Copyright 2001, 2002, 2003 Sun Microsystems Inc.
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser 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.
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 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
20 #include <glib/gi18n-lib.h>
24 #include "gtkentryaccessible.h"
25 #include "gtkentryprivate.h"
26 #include "gtkcomboboxaccessible.h"
28 #define GTK_TYPE_ENTRY_ICON_ACCESSIBLE (gtk_entry_icon_accessible_get_type ())
29 #define GTK_ENTRY_ICON_ACCESSIBLE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_ENTRY_ICON_ACCESSIBLE, GtkEntryIconAccessible))
30 #define GTK_IS_ENTRY_ICON_ACCESSIBLE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_ENTRY_ICON_ACCESSIBLE))
32 struct _GtkEntryAccessiblePrivate
39 typedef struct _GtkEntryIconAccessible GtkEntryIconAccessible;
40 typedef struct _GtkEntryIconAccessibleClass GtkEntryIconAccessibleClass;
42 struct _GtkEntryIconAccessible
46 GtkEntryAccessible *entry;
47 GtkEntryIconPosition pos;
50 struct _GtkEntryIconAccessibleClass
52 AtkObjectClass parent_class;
55 static void atk_action_interface_init (AtkActionIface *iface);
57 static void icon_atk_action_interface_init (AtkActionIface *iface);
58 static void icon_atk_component_interface_init (AtkComponentIface *iface);
60 GType gtk_entry_icon_accessible_get_type (void);
62 G_DEFINE_TYPE_WITH_CODE (GtkEntryIconAccessible, gtk_entry_icon_accessible, ATK_TYPE_OBJECT,
63 G_IMPLEMENT_INTERFACE (ATK_TYPE_ACTION, icon_atk_action_interface_init)
64 G_IMPLEMENT_INTERFACE (ATK_TYPE_COMPONENT, icon_atk_component_interface_init))
67 gtk_entry_icon_accessible_remove_entry (gpointer data, GObject *obj)
69 GtkEntryIconAccessible *icon = data;
74 g_object_notify (G_OBJECT (icon), "accessible-parent");
75 atk_object_notify_state_change (ATK_OBJECT (icon), ATK_STATE_DEFUNCT, TRUE);
80 gtk_entry_icon_accessible_new (GtkEntryAccessible *entry,
81 GtkEntryIconPosition pos)
83 GtkEntryIconAccessible *icon;
84 AtkObject *accessible;
86 icon = g_object_new (gtk_entry_icon_accessible_get_type (), NULL);
88 g_object_weak_ref (G_OBJECT (entry),
89 gtk_entry_icon_accessible_remove_entry,
93 accessible = ATK_OBJECT (icon);
94 atk_object_initialize (accessible, NULL);
99 gtk_entry_icon_accessible_init (GtkEntryIconAccessible *icon)
104 gtk_entry_icon_accessible_initialize (AtkObject *obj,
107 GtkEntryIconAccessible *icon = GTK_ENTRY_ICON_ACCESSIBLE (obj);
108 GtkWidget *widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (icon->entry));
109 GtkEntry *gtk_entry = GTK_ENTRY (widget);
113 ATK_OBJECT_CLASS (gtk_entry_icon_accessible_parent_class)->initialize (obj, data);
114 atk_object_set_role (obj, ATK_ROLE_ICON);
116 name = gtk_entry_get_icon_name (gtk_entry, icon->pos);
118 atk_object_set_name (obj, name);
120 text = gtk_entry_get_icon_tooltip_text (gtk_entry, icon->pos);
123 atk_object_set_description (obj, text);
127 atk_object_set_parent (obj, ATK_OBJECT (icon->entry));
131 gtk_entry_icon_accessible_get_parent (AtkObject *accessible)
133 GtkEntryIconAccessible *icon = GTK_ENTRY_ICON_ACCESSIBLE (accessible);
135 return ATK_OBJECT (icon->entry);
139 gtk_entry_icon_accessible_ref_state_set (AtkObject *accessible)
141 GtkEntryIconAccessible *icon = GTK_ENTRY_ICON_ACCESSIBLE (accessible);
142 AtkStateSet *set = atk_state_set_new ();
143 AtkStateSet *entry_set;
149 atk_state_set_add_state (set, ATK_STATE_DEFUNCT);
153 entry_set = atk_object_ref_state_set (ATK_OBJECT (icon->entry));
154 if (!entry_set || atk_state_set_contains_state (entry_set, ATK_STATE_DEFUNCT))
156 atk_state_set_add_state (set, ATK_STATE_DEFUNCT);
157 g_clear_object (&entry_set);
161 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (icon->entry));
162 gtk_entry = GTK_ENTRY (widget);
164 if (atk_state_set_contains_state (entry_set, ATK_STATE_ENABLED))
165 atk_state_set_add_state (set, ATK_STATE_ENABLED);
166 if (atk_state_set_contains_state (entry_set, ATK_STATE_SENSITIVE))
167 atk_state_set_add_state (set, ATK_STATE_SENSITIVE);
168 if (atk_state_set_contains_state (entry_set, ATK_STATE_SHOWING))
169 atk_state_set_add_state (set, ATK_STATE_SHOWING);
170 if (atk_state_set_contains_state (entry_set, ATK_STATE_VISIBLE))
171 atk_state_set_add_state (set, ATK_STATE_VISIBLE);
173 if (!gtk_entry_get_icon_sensitive (gtk_entry, icon->pos))
174 atk_state_set_remove_state (set, ATK_STATE_SENSITIVE);
175 if (!gtk_entry_get_icon_activatable (gtk_entry, icon->pos))
176 atk_state_set_remove_state (set, ATK_STATE_ENABLED);
178 g_object_unref (entry_set);
183 gtk_entry_icon_accessible_invalidate (GtkEntryIconAccessible *icon)
187 g_object_weak_unref (G_OBJECT (icon->entry),
188 gtk_entry_icon_accessible_remove_entry,
190 gtk_entry_icon_accessible_remove_entry (icon, NULL);
194 gtk_entry_icon_accessible_finalize (GObject *object)
196 GtkEntryIconAccessible *icon = GTK_ENTRY_ICON_ACCESSIBLE (object);
198 gtk_entry_icon_accessible_invalidate (icon);
200 G_OBJECT_CLASS (gtk_entry_icon_accessible_parent_class)->finalize (object);
204 gtk_entry_icon_accessible_class_init (GtkEntryIconAccessibleClass *klass)
206 AtkObjectClass *atk_class = ATK_OBJECT_CLASS (klass);
207 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
209 atk_class->initialize = gtk_entry_icon_accessible_initialize;
210 atk_class->get_parent = gtk_entry_icon_accessible_get_parent;
211 atk_class->ref_state_set = gtk_entry_icon_accessible_ref_state_set;
213 gobject_class->finalize = gtk_entry_icon_accessible_finalize;
217 gtk_entry_icon_accessible_do_action (AtkAction *action,
220 GtkEntryIconAccessible *icon = (GtkEntryIconAccessible *)action;
224 GdkRectangle icon_area;
226 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (icon->entry));
233 if (!gtk_widget_is_sensitive (widget) || !gtk_widget_get_visible (widget))
236 gtk_entry = GTK_ENTRY (widget);
238 if (!gtk_entry_get_icon_sensitive (gtk_entry, icon->pos) ||
239 !gtk_entry_get_icon_activatable (gtk_entry, icon->pos))
242 gtk_entry_get_icon_area (gtk_entry, icon->pos, &icon_area);
243 memset (&event, 0, sizeof (event));
244 event.button.type = GDK_BUTTON_PRESS;
245 event.button.window = gtk_widget_get_window (widget);
246 event.button.button = 1;
247 event.button.send_event = TRUE;
248 event.button.time = GDK_CURRENT_TIME;
249 event.button.x = icon_area.x;
250 event.button.y = icon_area.y;
252 g_signal_emit_by_name (widget, "icon-press", 0, icon->pos, &event);
257 gtk_entry_icon_accessible_get_n_actions (AtkAction *action)
259 GtkEntryIconAccessible *icon = GTK_ENTRY_ICON_ACCESSIBLE (action);
260 GtkWidget *widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (icon->entry));
261 GtkEntry *gtk_entry = GTK_ENTRY (widget);
263 return (gtk_entry_get_icon_activatable (gtk_entry, icon->pos) ? 1 : 0);
267 gtk_entry_icon_accessible_get_name (AtkAction *action,
270 GtkEntryIconAccessible *icon = GTK_ENTRY_ICON_ACCESSIBLE (action);
271 GtkWidget *widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (icon->entry));
272 GtkEntry *gtk_entry = GTK_ENTRY (widget);
276 if (!gtk_entry_get_icon_activatable (gtk_entry, icon->pos))
283 icon_atk_action_interface_init (AtkActionIface *iface)
285 iface->do_action = gtk_entry_icon_accessible_do_action;
286 iface->get_n_actions = gtk_entry_icon_accessible_get_n_actions;
287 iface->get_name = gtk_entry_icon_accessible_get_name;
291 gtk_entry_icon_accessible_get_extents (AtkComponent *component,
296 AtkCoordType coord_type)
298 GtkEntryIconAccessible *icon = GTK_ENTRY_ICON_ACCESSIBLE (component);
299 GdkRectangle icon_area;
304 atk_component_get_extents (ATK_COMPONENT (icon->entry), x, y, width, height,
309 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (icon->entry));
310 gtk_entry = GTK_ENTRY (widget);
311 gtk_entry_get_icon_area (gtk_entry, icon->pos, &icon_area);
312 *width = icon_area.width;
313 *height = icon_area.height;
319 gtk_entry_icon_accessible_get_position (AtkComponent *component,
322 AtkCoordType coord_type)
324 GtkEntryIconAccessible *icon = GTK_ENTRY_ICON_ACCESSIBLE (component);
325 GdkRectangle icon_area;
330 atk_component_get_position (ATK_COMPONENT (icon->entry), x, y, coord_type);
334 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (icon->entry));
335 gtk_entry = GTK_ENTRY (widget);
336 gtk_entry_get_icon_area (gtk_entry, icon->pos, &icon_area);
342 gtk_entry_icon_accessible_get_size (AtkComponent *component,
346 GtkEntryIconAccessible *icon = GTK_ENTRY_ICON_ACCESSIBLE (component);
347 GdkRectangle icon_area;
351 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (icon->entry));
352 gtk_entry = GTK_ENTRY (widget);
353 gtk_entry_get_icon_area (gtk_entry, icon->pos, &icon_area);
354 *width = icon_area.width;
355 *height = icon_area.height;
359 icon_atk_component_interface_init (AtkComponentIface *iface)
361 iface->get_extents = gtk_entry_icon_accessible_get_extents;
362 iface->get_size = gtk_entry_icon_accessible_get_size;
363 iface->get_position = gtk_entry_icon_accessible_get_position;
368 static void insert_text_cb (GtkEditable *editable,
370 gint new_text_length,
372 static void delete_text_cb (GtkEditable *editable,
376 static gboolean check_for_selection_change (GtkEntryAccessible *entry,
377 GtkEntry *gtk_entry);
380 static void atk_editable_text_interface_init (AtkEditableTextIface *iface);
381 static void atk_text_interface_init (AtkTextIface *iface);
382 static void atk_action_interface_init (AtkActionIface *iface);
385 G_DEFINE_TYPE_WITH_CODE (GtkEntryAccessible, gtk_entry_accessible, GTK_TYPE_WIDGET_ACCESSIBLE,
386 G_IMPLEMENT_INTERFACE (ATK_TYPE_EDITABLE_TEXT, atk_editable_text_interface_init)
387 G_IMPLEMENT_INTERFACE (ATK_TYPE_TEXT, atk_text_interface_init)
388 G_IMPLEMENT_INTERFACE (ATK_TYPE_ACTION, atk_action_interface_init))
392 gtk_entry_accessible_ref_state_set (AtkObject *accessible)
394 AtkStateSet *state_set;
398 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (accessible));
402 state_set = ATK_OBJECT_CLASS (gtk_entry_accessible_parent_class)->ref_state_set (accessible);
404 g_object_get (G_OBJECT (widget), "editable", &value, NULL);
406 atk_state_set_add_state (state_set, ATK_STATE_EDITABLE);
407 atk_state_set_add_state (state_set, ATK_STATE_SINGLE_LINE);
412 static AtkAttributeSet *
413 gtk_entry_accessible_get_attributes (AtkObject *accessible)
416 AtkAttributeSet *attributes;
417 AtkAttribute *placeholder_text;
420 attributes = ATK_OBJECT_CLASS (gtk_entry_accessible_parent_class)->get_attributes (accessible);
422 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (accessible));
426 text = gtk_entry_get_placeholder_text (GTK_ENTRY (widget));
430 placeholder_text = g_malloc (sizeof (AtkAttribute));
431 placeholder_text->name = g_strdup ("placeholder-text");
432 placeholder_text->value = g_strdup (text);
434 attributes = g_slist_append (attributes, placeholder_text);
440 gtk_entry_accessible_initialize (AtkObject *obj,
444 GtkEntryAccessible *gtk_entry_accessible;
445 gint start_pos, end_pos;
447 ATK_OBJECT_CLASS (gtk_entry_accessible_parent_class)->initialize (obj, data);
449 gtk_entry_accessible = GTK_ENTRY_ACCESSIBLE (obj);
451 entry = GTK_ENTRY (data);
452 gtk_editable_get_selection_bounds (GTK_EDITABLE (entry), &start_pos, &end_pos);
453 gtk_entry_accessible->priv->cursor_position = end_pos;
454 gtk_entry_accessible->priv->selection_bound = start_pos;
456 /* Set up signal callbacks */
457 g_signal_connect (entry, "insert-text", G_CALLBACK (insert_text_cb), NULL);
458 g_signal_connect (entry, "delete-text", G_CALLBACK (delete_text_cb), NULL);
460 if (gtk_entry_get_visibility (entry))
461 obj->role = ATK_ROLE_TEXT;
463 obj->role = ATK_ROLE_PASSWORD_TEXT;
467 gtk_entry_accessible_notify_gtk (GObject *obj,
473 GtkEntryAccessible* entry;
474 GtkEntryAccessiblePrivate *priv;
476 widget = GTK_WIDGET (obj);
477 atk_obj = gtk_widget_get_accessible (widget);
478 gtk_entry = GTK_ENTRY (widget);
479 entry = GTK_ENTRY_ACCESSIBLE (atk_obj);
482 if (g_strcmp0 (pspec->name, "cursor-position") == 0)
484 if (check_for_selection_change (entry, gtk_entry))
485 g_signal_emit_by_name (atk_obj, "text-selection-changed");
487 * The entry cursor position has moved so generate the signal.
489 g_signal_emit_by_name (atk_obj, "text-caret-moved",
490 entry->priv->cursor_position);
492 else if (g_strcmp0 (pspec->name, "selection-bound") == 0)
494 if (check_for_selection_change (entry, gtk_entry))
495 g_signal_emit_by_name (atk_obj, "text-selection-changed");
497 else if (g_strcmp0 (pspec->name, "editable") == 0)
501 g_object_get (obj, "editable", &value, NULL);
502 atk_object_notify_state_change (atk_obj, ATK_STATE_EDITABLE, value);
504 else if (g_strcmp0 (pspec->name, "visibility") == 0)
509 visibility = gtk_entry_get_visibility (gtk_entry);
510 new_role = visibility ? ATK_ROLE_TEXT : ATK_ROLE_PASSWORD_TEXT;
511 atk_object_set_role (atk_obj, new_role);
513 else if (g_strcmp0 (pspec->name, "primary-icon-storage-type") == 0)
515 if (gtk_entry_get_icon_storage_type (gtk_entry, GTK_ENTRY_ICON_PRIMARY) != GTK_IMAGE_EMPTY && !priv->icons[GTK_ENTRY_ICON_PRIMARY])
517 priv->icons[GTK_ENTRY_ICON_PRIMARY] = gtk_entry_icon_accessible_new (entry, GTK_ENTRY_ICON_PRIMARY);
518 g_signal_emit_by_name (entry, "children-changed::add", 0,
519 priv->icons[GTK_ENTRY_ICON_PRIMARY], NULL);
521 else if (gtk_entry_get_icon_storage_type (gtk_entry, GTK_ENTRY_ICON_PRIMARY) == GTK_IMAGE_EMPTY && priv->icons[GTK_ENTRY_ICON_PRIMARY])
523 gtk_entry_icon_accessible_invalidate (GTK_ENTRY_ICON_ACCESSIBLE (priv->icons[GTK_ENTRY_ICON_PRIMARY]));
524 g_signal_emit_by_name (entry, "children-changed::remove", 0,
525 priv->icons[GTK_ENTRY_ICON_PRIMARY], NULL);
526 g_clear_object (&priv->icons[GTK_ENTRY_ICON_PRIMARY]);
529 else if (g_strcmp0 (pspec->name, "secondary-icon-storage-type") == 0)
531 gint index = (priv->icons[GTK_ENTRY_ICON_PRIMARY] ? 1 : 0);
532 if (gtk_entry_get_icon_storage_type (gtk_entry, GTK_ENTRY_ICON_SECONDARY) != GTK_IMAGE_EMPTY && !priv->icons[GTK_ENTRY_ICON_SECONDARY])
534 priv->icons[GTK_ENTRY_ICON_SECONDARY] = gtk_entry_icon_accessible_new (entry, GTK_ENTRY_ICON_SECONDARY);
535 g_signal_emit_by_name (entry, "children-changed::add", index,
536 priv->icons[GTK_ENTRY_ICON_SECONDARY], NULL);
538 else if (gtk_entry_get_icon_storage_type (gtk_entry, GTK_ENTRY_ICON_SECONDARY) == GTK_IMAGE_EMPTY && priv->icons[GTK_ENTRY_ICON_SECONDARY])
540 gtk_entry_icon_accessible_invalidate (GTK_ENTRY_ICON_ACCESSIBLE (priv->icons[GTK_ENTRY_ICON_SECONDARY]));
541 g_signal_emit_by_name (entry, "children-changed::remove", index,
542 priv->icons[GTK_ENTRY_ICON_SECONDARY], NULL);
543 g_clear_object (&priv->icons[GTK_ENTRY_ICON_SECONDARY]);
546 else if (g_strcmp0 (pspec->name, "primary-icon-name") == 0)
548 if (priv->icons[GTK_ENTRY_ICON_PRIMARY])
551 name = gtk_entry_get_icon_name (gtk_entry,
552 GTK_ENTRY_ICON_PRIMARY);
554 atk_object_set_name (priv->icons[GTK_ENTRY_ICON_PRIMARY], name);
557 else if (g_strcmp0 (pspec->name, "secondary-icon-name") == 0)
559 if (priv->icons[GTK_ENTRY_ICON_SECONDARY])
562 name = gtk_entry_get_icon_name (gtk_entry,
563 GTK_ENTRY_ICON_SECONDARY);
565 atk_object_set_name (priv->icons[GTK_ENTRY_ICON_SECONDARY], name);
568 else if (g_strcmp0 (pspec->name, "primary-icon-tooltip-text") == 0)
570 if (priv->icons[GTK_ENTRY_ICON_PRIMARY])
573 text = gtk_entry_get_icon_tooltip_text (gtk_entry,
574 GTK_ENTRY_ICON_PRIMARY);
575 atk_object_set_description (priv->icons[GTK_ENTRY_ICON_PRIMARY],
580 else if (g_strcmp0 (pspec->name, "secondary-icon-tooltip-text") == 0)
582 if (priv->icons[GTK_ENTRY_ICON_SECONDARY])
585 text = gtk_entry_get_icon_tooltip_text (gtk_entry,
586 GTK_ENTRY_ICON_SECONDARY);
587 atk_object_set_description (priv->icons[GTK_ENTRY_ICON_SECONDARY],
592 else if (g_strcmp0 (pspec->name, "primary-icon-activatable") == 0)
594 if (priv->icons[GTK_ENTRY_ICON_PRIMARY])
596 gboolean on = gtk_entry_get_icon_activatable (gtk_entry, GTK_ENTRY_ICON_PRIMARY);
597 atk_object_notify_state_change (priv->icons[GTK_ENTRY_ICON_PRIMARY],
598 ATK_STATE_ENABLED, on);
601 else if (g_strcmp0 (pspec->name, "secondary-icon-activatable") == 0)
603 if (priv->icons[GTK_ENTRY_ICON_SECONDARY])
605 gboolean on = gtk_entry_get_icon_activatable (gtk_entry, GTK_ENTRY_ICON_SECONDARY);
606 atk_object_notify_state_change (priv->icons[GTK_ENTRY_ICON_SECONDARY],
607 ATK_STATE_ENABLED, on);
610 else if (g_strcmp0 (pspec->name, "primary-icon-sensitive") == 0)
612 if (priv->icons[GTK_ENTRY_ICON_PRIMARY])
614 gboolean on = gtk_entry_get_icon_sensitive (gtk_entry, GTK_ENTRY_ICON_PRIMARY);
615 atk_object_notify_state_change (priv->icons[GTK_ENTRY_ICON_PRIMARY],
616 ATK_STATE_SENSITIVE, on);
619 else if (g_strcmp0 (pspec->name, "secondary-icon-sensitive") == 0)
621 if (priv->icons[GTK_ENTRY_ICON_SECONDARY])
623 gboolean on = gtk_entry_get_icon_sensitive (gtk_entry, GTK_ENTRY_ICON_SECONDARY);
624 atk_object_notify_state_change (priv->icons[GTK_ENTRY_ICON_SECONDARY],
625 ATK_STATE_SENSITIVE, on);
629 GTK_WIDGET_ACCESSIBLE_CLASS (gtk_entry_accessible_parent_class)->notify_gtk (obj, pspec);
633 gtk_entry_accessible_get_index_in_parent (AtkObject *accessible)
636 * If the parent widget is a combo box then the index is 1
637 * otherwise do the normal thing.
639 if (accessible->accessible_parent)
640 if (GTK_IS_COMBO_BOX_ACCESSIBLE (accessible->accessible_parent))
643 return ATK_OBJECT_CLASS (gtk_entry_accessible_parent_class)->get_index_in_parent (accessible);
647 gtk_entry_accessible_get_n_children (AtkObject* obj)
653 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (obj));
657 entry = GTK_ENTRY (widget);
659 if (gtk_entry_get_icon_storage_type (entry, GTK_ENTRY_ICON_PRIMARY) != GTK_IMAGE_EMPTY)
661 if (gtk_entry_get_icon_storage_type (entry, GTK_ENTRY_ICON_SECONDARY) != GTK_IMAGE_EMPTY)
667 gtk_entry_accessible_ref_child (AtkObject *obj,
670 GtkEntryAccessible *accessible = GTK_ENTRY_ACCESSIBLE (obj);
671 GtkEntryAccessiblePrivate *priv = accessible->priv;
674 GtkEntryIconPosition pos;
676 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (obj));
680 entry = GTK_ENTRY (widget);
685 if (gtk_entry_get_icon_storage_type (entry, GTK_ENTRY_ICON_PRIMARY) != GTK_IMAGE_EMPTY)
686 pos = GTK_ENTRY_ICON_PRIMARY;
687 else if (gtk_entry_get_icon_storage_type (entry, GTK_ENTRY_ICON_SECONDARY) != GTK_IMAGE_EMPTY)
688 pos = GTK_ENTRY_ICON_SECONDARY;
693 if (gtk_entry_get_icon_storage_type (entry, GTK_ENTRY_ICON_PRIMARY) == GTK_IMAGE_EMPTY)
695 if (gtk_entry_get_icon_storage_type (entry, GTK_ENTRY_ICON_SECONDARY) == GTK_IMAGE_EMPTY)
697 pos = GTK_ENTRY_ICON_SECONDARY;
703 if (!priv->icons[pos])
704 priv->icons[pos] = gtk_entry_icon_accessible_new (accessible, pos);
705 return g_object_ref (priv->icons[pos]);
709 gtk_entry_accessible_finalize (GObject *object)
711 GtkEntryAccessible *entry = GTK_ENTRY_ACCESSIBLE (object);
712 GtkEntryAccessiblePrivate *priv = entry->priv;
714 g_clear_object (&priv->icons[GTK_ENTRY_ICON_PRIMARY]);
715 g_clear_object (&priv->icons[GTK_ENTRY_ICON_SECONDARY]);
717 G_OBJECT_CLASS (gtk_entry_accessible_parent_class)->finalize (object);
721 gtk_entry_accessible_class_init (GtkEntryAccessibleClass *klass)
723 AtkObjectClass *class = ATK_OBJECT_CLASS (klass);
724 GtkWidgetAccessibleClass *widget_class = (GtkWidgetAccessibleClass*)klass;
725 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
727 class->ref_state_set = gtk_entry_accessible_ref_state_set;
728 class->get_index_in_parent = gtk_entry_accessible_get_index_in_parent;
729 class->initialize = gtk_entry_accessible_initialize;
730 class->get_attributes = gtk_entry_accessible_get_attributes;
731 class->get_n_children = gtk_entry_accessible_get_n_children;
732 class->ref_child = gtk_entry_accessible_ref_child;
734 widget_class->notify_gtk = gtk_entry_accessible_notify_gtk;
736 gobject_class->finalize = gtk_entry_accessible_finalize;
738 g_type_class_add_private (klass, sizeof (GtkEntryAccessiblePrivate));
742 gtk_entry_accessible_init (GtkEntryAccessible *entry)
744 entry->priv = G_TYPE_INSTANCE_GET_PRIVATE (entry,
745 GTK_TYPE_ENTRY_ACCESSIBLE,
746 GtkEntryAccessiblePrivate);
747 entry->priv->cursor_position = 0;
748 entry->priv->selection_bound = 0;
752 gtk_entry_accessible_get_text (AtkText *atk_text,
758 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (atk_text));
762 return _gtk_entry_get_display_text (GTK_ENTRY (widget), start_pos, end_pos);
766 gtk_entry_accessible_get_text_before_offset (AtkText *text,
768 AtkTextBoundary boundary_type,
774 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
778 return _gtk_pango_get_text_before (gtk_entry_get_layout (GTK_ENTRY (widget)),
779 boundary_type, offset,
780 start_offset, end_offset);
784 gtk_entry_accessible_get_text_at_offset (AtkText *text,
786 AtkTextBoundary boundary_type,
792 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
796 return _gtk_pango_get_text_at (gtk_entry_get_layout (GTK_ENTRY (widget)),
797 boundary_type, offset,
798 start_offset, end_offset);
802 gtk_entry_accessible_get_text_after_offset (AtkText *text,
804 AtkTextBoundary boundary_type,
810 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
814 return _gtk_pango_get_text_after (gtk_entry_get_layout (GTK_ENTRY (widget)),
815 boundary_type, offset,
816 start_offset, end_offset);
820 gtk_entry_accessible_get_character_count (AtkText *atk_text)
826 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (atk_text));
830 text = _gtk_entry_get_display_text (GTK_ENTRY (widget), 0, -1);
835 char_count = g_utf8_strlen (text, -1);
843 gtk_entry_accessible_get_caret_offset (AtkText *text)
847 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
851 return gtk_editable_get_position (GTK_EDITABLE (widget));
855 gtk_entry_accessible_set_caret_offset (AtkText *text,
860 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
864 gtk_editable_set_position (GTK_EDITABLE (widget), offset);
869 static AtkAttributeSet *
870 add_text_attribute (AtkAttributeSet *attributes,
871 AtkTextAttribute attr,
876 at = g_new (AtkAttribute, 1);
877 at->name = g_strdup (atk_text_attribute_get_name (attr));
878 at->value = g_strdup (atk_text_attribute_get_value (attr, i));
880 return g_slist_prepend (attributes, at);
883 static AtkAttributeSet *
884 gtk_entry_accessible_get_run_attributes (AtkText *text,
890 AtkAttributeSet *attributes;
892 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
897 attributes = add_text_attribute (attributes, ATK_TEXT_ATTR_DIRECTION,
898 gtk_widget_get_direction (widget));
899 attributes = _gtk_pango_get_run_attributes (attributes,
900 gtk_entry_get_layout (GTK_ENTRY (widget)),
908 static AtkAttributeSet *
909 gtk_entry_accessible_get_default_attributes (AtkText *text)
912 AtkAttributeSet *attributes;
914 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
919 attributes = add_text_attribute (attributes, ATK_TEXT_ATTR_DIRECTION,
920 gtk_widget_get_direction (widget));
921 attributes = _gtk_pango_get_default_attributes (attributes,
922 gtk_entry_get_layout (GTK_ENTRY (widget)));
923 attributes = _gtk_style_context_get_attributes (attributes,
924 gtk_widget_get_style_context (widget),
925 gtk_widget_get_state_flags (widget));
931 gtk_entry_accessible_get_character_extents (AtkText *text,
941 PangoRectangle char_rect;
943 gint index, x_layout, y_layout;
945 gint x_window, y_window;
947 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
951 entry = GTK_ENTRY (widget);
953 gtk_entry_get_layout_offsets (entry, &x_layout, &y_layout);
954 entry_text = _gtk_entry_get_display_text (entry, 0, -1);
955 index = g_utf8_offset_to_pointer (entry_text, offset) - entry_text;
958 pango_layout_index_to_pos (gtk_entry_get_layout (entry), index, &char_rect);
959 pango_extents_to_pixels (&char_rect, NULL);
961 window = gtk_widget_get_window (widget);
962 gdk_window_get_origin (window, &x_window, &y_window);
964 *x = x_window + x_layout + char_rect.x;
965 *y = y_window + y_layout + char_rect.y;
966 *width = char_rect.width;
967 *height = char_rect.height;
969 if (coords == ATK_XY_WINDOW)
971 window = gdk_window_get_toplevel (window);
972 gdk_window_get_origin (window, &x_window, &y_window);
980 gtk_entry_accessible_get_offset_at_point (AtkText *atk_text,
988 gint index, x_layout, y_layout;
989 gint x_window, y_window;
990 gint x_local, y_local;
994 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (atk_text));
998 entry = GTK_ENTRY (widget);
1000 gtk_entry_get_layout_offsets (entry, &x_layout, &y_layout);
1002 window = gtk_widget_get_window (widget);
1003 gdk_window_get_origin (window, &x_window, &y_window);
1005 x_local = x - x_layout - x_window;
1006 y_local = y - y_layout - y_window;
1008 if (coords == ATK_XY_WINDOW)
1010 window = gdk_window_get_toplevel (window);
1011 gdk_window_get_origin (window, &x_window, &y_window);
1013 x_local += x_window;
1014 y_local += y_window;
1016 if (!pango_layout_xy_to_index (gtk_entry_get_layout (entry),
1017 x_local * PANGO_SCALE,
1018 y_local * PANGO_SCALE,
1021 if (x_local < 0 || y_local < 0)
1030 text = _gtk_entry_get_display_text (entry, 0, -1);
1031 offset = g_utf8_pointer_to_offset (text, text + index);
1039 gtk_entry_accessible_get_n_selections (AtkText *text)
1044 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
1048 if (gtk_editable_get_selection_bounds (GTK_EDITABLE (widget), &start, &end))
1055 gtk_entry_accessible_get_selection (AtkText *text,
1062 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
1066 if (selection_num != 0)
1069 if (gtk_editable_get_selection_bounds (GTK_EDITABLE (widget), start_pos, end_pos))
1070 return gtk_editable_get_chars (GTK_EDITABLE (widget), *start_pos, *end_pos);
1076 gtk_entry_accessible_add_selection (AtkText *text,
1084 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
1088 entry = GTK_ENTRY (widget);
1090 if (!gtk_editable_get_selection_bounds (GTK_EDITABLE (entry), &start, &end))
1092 gtk_editable_select_region (GTK_EDITABLE (entry), start_pos, end_pos);
1100 gtk_entry_accessible_remove_selection (AtkText *text,
1106 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
1110 if (selection_num != 0)
1113 if (gtk_editable_get_selection_bounds (GTK_EDITABLE (widget), &start, &end))
1115 gtk_editable_select_region (GTK_EDITABLE (widget), end, end);
1123 gtk_entry_accessible_set_selection (AtkText *text,
1131 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
1135 if (selection_num != 0)
1138 if (gtk_editable_get_selection_bounds (GTK_EDITABLE (widget), &start, &end))
1140 gtk_editable_select_region (GTK_EDITABLE (widget), start_pos, end_pos);
1148 gtk_entry_accessible_get_character_at_offset (AtkText *atk_text,
1158 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (atk_text));
1162 if (!gtk_entry_get_visibility (GTK_ENTRY (widget)))
1165 text = _gtk_entry_get_display_text (GTK_ENTRY (widget), 0, -1);
1166 if (offset < g_utf8_strlen (text, -1))
1168 index = g_utf8_offset_to_pointer (text, offset);
1169 result = g_utf8_get_char (index);
1177 atk_text_interface_init (AtkTextIface *iface)
1179 iface->get_text = gtk_entry_accessible_get_text;
1180 iface->get_character_at_offset = gtk_entry_accessible_get_character_at_offset;
1181 iface->get_text_before_offset = gtk_entry_accessible_get_text_before_offset;
1182 iface->get_text_at_offset = gtk_entry_accessible_get_text_at_offset;
1183 iface->get_text_after_offset = gtk_entry_accessible_get_text_after_offset;
1184 iface->get_caret_offset = gtk_entry_accessible_get_caret_offset;
1185 iface->set_caret_offset = gtk_entry_accessible_set_caret_offset;
1186 iface->get_character_count = gtk_entry_accessible_get_character_count;
1187 iface->get_n_selections = gtk_entry_accessible_get_n_selections;
1188 iface->get_selection = gtk_entry_accessible_get_selection;
1189 iface->add_selection = gtk_entry_accessible_add_selection;
1190 iface->remove_selection = gtk_entry_accessible_remove_selection;
1191 iface->set_selection = gtk_entry_accessible_set_selection;
1192 iface->get_run_attributes = gtk_entry_accessible_get_run_attributes;
1193 iface->get_default_attributes = gtk_entry_accessible_get_default_attributes;
1194 iface->get_character_extents = gtk_entry_accessible_get_character_extents;
1195 iface->get_offset_at_point = gtk_entry_accessible_get_offset_at_point;
1199 gtk_entry_accessible_set_text_contents (AtkEditableText *text,
1200 const gchar *string)
1204 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
1208 if (!gtk_editable_get_editable (GTK_EDITABLE (widget)))
1211 gtk_entry_set_text (GTK_ENTRY (widget), string);
1215 gtk_entry_accessible_insert_text (AtkEditableText *text,
1216 const gchar *string,
1221 GtkEditable *editable;
1223 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
1227 editable = GTK_EDITABLE (widget);
1228 if (!gtk_editable_get_editable (editable))
1231 gtk_editable_insert_text (editable, string, length, position);
1232 gtk_editable_set_position (editable, *position);
1236 gtk_entry_accessible_copy_text (AtkEditableText *text,
1241 GtkEditable *editable;
1243 GtkClipboard *clipboard;
1245 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
1249 if (!gtk_widget_has_screen (widget))
1252 editable = GTK_EDITABLE (widget);
1253 str = gtk_editable_get_chars (editable, start_pos, end_pos);
1254 clipboard = gtk_widget_get_clipboard (widget, GDK_SELECTION_CLIPBOARD);
1255 gtk_clipboard_set_text (clipboard, str, -1);
1260 gtk_entry_accessible_cut_text (AtkEditableText *text,
1265 GtkEditable *editable;
1267 GtkClipboard *clipboard;
1269 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
1273 if (!gtk_widget_has_screen (widget))
1276 editable = GTK_EDITABLE (widget);
1277 if (!gtk_editable_get_editable (editable))
1280 str = gtk_editable_get_chars (editable, start_pos, end_pos);
1281 clipboard = gtk_widget_get_clipboard (widget, GDK_SELECTION_CLIPBOARD);
1282 gtk_clipboard_set_text (clipboard, str, -1);
1283 gtk_editable_delete_text (editable, start_pos, end_pos);
1287 gtk_entry_accessible_delete_text (AtkEditableText *text,
1292 GtkEditable *editable;
1294 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
1298 editable = GTK_EDITABLE (widget);
1299 if (!gtk_editable_get_editable (editable))
1302 gtk_editable_delete_text (editable, start_pos, end_pos);
1312 paste_received_cb (GtkClipboard *clipboard,
1316 PasteData *paste = data;
1319 gtk_editable_insert_text (GTK_EDITABLE (paste->entry), text, -1,
1322 g_object_unref (paste->entry);
1327 gtk_entry_accessible_paste_text (AtkEditableText *text,
1331 GtkEditable *editable;
1333 GtkClipboard *clipboard;
1335 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
1339 if (!gtk_widget_has_screen (widget))
1342 editable = GTK_EDITABLE (widget);
1343 if (!gtk_editable_get_editable (editable))
1346 paste = g_new0 (PasteData, 1);
1347 paste->entry = GTK_ENTRY (widget);
1348 paste->position = position;
1350 g_object_ref (paste->entry);
1351 clipboard = gtk_widget_get_clipboard (widget, GDK_SELECTION_CLIPBOARD);
1352 gtk_clipboard_request_text (clipboard, paste_received_cb, paste);
1356 atk_editable_text_interface_init (AtkEditableTextIface *iface)
1358 iface->set_text_contents = gtk_entry_accessible_set_text_contents;
1359 iface->insert_text = gtk_entry_accessible_insert_text;
1360 iface->copy_text = gtk_entry_accessible_copy_text;
1361 iface->cut_text = gtk_entry_accessible_cut_text;
1362 iface->delete_text = gtk_entry_accessible_delete_text;
1363 iface->paste_text = gtk_entry_accessible_paste_text;
1364 iface->set_run_attributes = NULL;
1367 /* We connect to GtkEditable::insert-text, since it carries
1368 * the information we need. But we delay emitting our own
1369 * text_changed::insert signal until the entry has update
1370 * all its internal state and emits GtkEntry::changed.
1373 insert_text_cb (GtkEditable *editable,
1375 gint new_text_length,
1378 GtkEntryAccessible *accessible;
1380 if (new_text_length == 0)
1383 accessible = GTK_ENTRY_ACCESSIBLE (gtk_widget_get_accessible (GTK_WIDGET (editable)));
1385 g_signal_emit_by_name (accessible,
1386 "text-changed::insert",
1388 g_utf8_strlen (new_text, new_text_length));
1391 /* We connect to GtkEditable::delete-text, since it carries
1392 * the information we need. But we delay emitting our own
1393 * text_changed::delete signal until the entry has update
1394 * all its internal state and emits GtkEntry::changed.
1397 delete_text_cb (GtkEditable *editable,
1401 GtkEntryAccessible *accessible;
1403 accessible = GTK_ENTRY_ACCESSIBLE (gtk_widget_get_accessible (GTK_WIDGET (editable)));
1409 text = _gtk_entry_get_display_text (GTK_ENTRY (editable), 0, -1);
1410 end = g_utf8_strlen (text, -1);
1417 g_signal_emit_by_name (accessible,
1418 "text-changed::delete",
1424 check_for_selection_change (GtkEntryAccessible *accessible,
1427 gboolean ret_val = FALSE;
1430 if (gtk_editable_get_selection_bounds (GTK_EDITABLE (entry), &start, &end))
1432 if (end != accessible->priv->cursor_position ||
1433 start != accessible->priv->selection_bound)
1435 * This check is here as this function can be called
1436 * for notification of selection_bound and current_pos.
1437 * The values of current_pos and selection_bound may be the same
1438 * for both notifications and we only want to generate one
1439 * text_selection_changed signal.
1445 /* We had a selection */
1446 ret_val = (accessible->priv->cursor_position != accessible->priv->selection_bound);
1449 accessible->priv->cursor_position = end;
1450 accessible->priv->selection_bound = start;
1456 gtk_entry_accessible_do_action (AtkAction *action,
1461 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (action));
1465 if (!gtk_widget_get_sensitive (widget) || !gtk_widget_get_visible (widget))
1471 gtk_widget_activate (widget);
1477 gtk_entry_accessible_get_n_actions (AtkAction *action)
1482 static const gchar *
1483 gtk_entry_accessible_get_keybinding (AtkAction *action,
1488 AtkRelationSet *set;
1489 AtkRelation *relation;
1491 gpointer target_object;
1497 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (action));
1501 set = atk_object_ref_relation_set (ATK_OBJECT (action));
1506 relation = atk_relation_set_get_relation_by_type (set, ATK_RELATION_LABELLED_BY);
1509 target = atk_relation_get_target (relation);
1511 target_object = g_ptr_array_index (target, 0);
1512 label = gtk_accessible_get_widget (GTK_ACCESSIBLE (target_object));
1515 g_object_unref (set);
1517 if (GTK_IS_LABEL (label))
1519 key_val = gtk_label_get_mnemonic_keyval (GTK_LABEL (label));
1520 if (key_val != GDK_KEY_VoidSymbol)
1521 return gtk_accelerator_name (key_val, GDK_MOD1_MASK);
1528 gtk_entry_accessible_action_get_name (AtkAction *action,
1537 gtk_entry_accessible_action_get_localized_name (AtkAction *action,
1541 return C_("Action name", "Activate");
1546 gtk_entry_accessible_action_get_description (AtkAction *action,
1550 return C_("Action description", "Activates the entry");
1555 atk_action_interface_init (AtkActionIface *iface)
1557 iface->do_action = gtk_entry_accessible_do_action;
1558 iface->get_n_actions = gtk_entry_accessible_get_n_actions;
1559 iface->get_keybinding = gtk_entry_accessible_get_keybinding;
1560 iface->get_name = gtk_entry_accessible_action_get_name;
1561 iface->get_localized_name = gtk_entry_accessible_action_get_localized_name;
1562 iface->get_description = gtk_entry_accessible_action_get_description;