]> Pileus Git - ~andy/gtk/blob - gtk/a11y/gtkentryaccessible.c
GtkBubbleWindow: Use style border color to stroke the bubble shape
[~andy/gtk] / gtk / a11y / gtkentryaccessible.c
1 /* GTK+ - accessibility implementations
2  * Copyright 2001, 2002, 2003 Sun Microsystems Inc.
3  *
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.
8  *
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.
13  *
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/>.
16  */
17
18 #include "config.h"
19
20 #include <glib/gi18n-lib.h>
21 #include <string.h>
22 #include <gtk/gtk.h>
23 #include "gtkpango.h"
24 #include "gtkentryaccessible.h"
25 #include "gtkentryprivate.h"
26 #include "gtkcomboboxaccessible.h"
27
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))
31
32 struct _GtkEntryAccessiblePrivate
33 {
34   gint cursor_position;
35   gint selection_bound;
36   AtkObject *icons[2];
37 };
38
39 typedef struct _GtkEntryIconAccessible GtkEntryIconAccessible;
40 typedef struct _GtkEntryIconAccessibleClass GtkEntryIconAccessibleClass;
41
42 struct _GtkEntryIconAccessible
43 {
44   AtkObject parent;
45
46   GtkEntryAccessible *entry;
47   GtkEntryIconPosition pos;
48 };
49
50 struct _GtkEntryIconAccessibleClass
51 {
52   AtkObjectClass parent_class;
53 };
54
55 static void atk_action_interface_init (AtkActionIface *iface);
56
57 static void icon_atk_action_interface_init (AtkActionIface *iface);
58 static void icon_atk_component_interface_init (AtkComponentIface *iface);
59
60 GType gtk_entry_icon_accessible_get_type (void);
61
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))
65
66 static void
67 gtk_entry_icon_accessible_remove_entry (gpointer data, GObject *obj)
68 {
69   GtkEntryIconAccessible *icon = data;
70
71   if (icon->entry)
72     {
73       icon->entry = NULL;
74       g_object_notify (G_OBJECT (icon), "accessible-parent");
75       atk_object_notify_state_change (ATK_OBJECT (icon), ATK_STATE_DEFUNCT, TRUE);
76     }
77 }
78
79 static AtkObject *
80 gtk_entry_icon_accessible_new (GtkEntryAccessible *entry,
81                                GtkEntryIconPosition pos)
82 {
83   GtkEntryIconAccessible *icon;
84   AtkObject *accessible;
85
86   icon = g_object_new (gtk_entry_icon_accessible_get_type (), NULL);
87   icon->entry = entry;
88   g_object_weak_ref (G_OBJECT (entry),
89                      gtk_entry_icon_accessible_remove_entry,
90                      icon);
91   icon->pos = pos;
92
93   accessible = ATK_OBJECT (icon);
94   atk_object_initialize (accessible, NULL);
95   return accessible;
96 }
97
98 static void
99 gtk_entry_icon_accessible_init (GtkEntryIconAccessible *icon)
100 {
101 }
102
103 static void
104 gtk_entry_icon_accessible_initialize (AtkObject *obj,
105                                       gpointer   data)
106 {
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);
110   const gchar *name;
111   gchar *text;
112
113   ATK_OBJECT_CLASS (gtk_entry_icon_accessible_parent_class)->initialize (obj, data);
114   atk_object_set_role (obj, ATK_ROLE_ICON);
115
116   name = gtk_entry_get_icon_name (gtk_entry, icon->pos);
117   if (name)
118     atk_object_set_name (obj, name);
119
120   text = gtk_entry_get_icon_tooltip_text (gtk_entry, icon->pos);
121   if (text)
122     {
123       atk_object_set_description (obj, text);
124       g_free (text);
125     }
126
127   atk_object_set_parent (obj, ATK_OBJECT (icon->entry));
128 }
129
130 static AtkObject *
131 gtk_entry_icon_accessible_get_parent (AtkObject *accessible)
132 {
133   GtkEntryIconAccessible *icon = GTK_ENTRY_ICON_ACCESSIBLE (accessible);
134
135   return ATK_OBJECT (icon->entry);
136 }
137
138 static AtkStateSet *
139 gtk_entry_icon_accessible_ref_state_set (AtkObject *accessible)
140 {
141   GtkEntryIconAccessible *icon = GTK_ENTRY_ICON_ACCESSIBLE (accessible);
142   AtkStateSet *set = atk_state_set_new ();
143   AtkStateSet *entry_set;
144   GtkWidget *widget;
145   GtkEntry *gtk_entry;
146
147   if (!icon->entry)
148     {
149       atk_state_set_add_state (set, ATK_STATE_DEFUNCT);
150       return set;
151     }
152
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))
155     {
156       atk_state_set_add_state (set, ATK_STATE_DEFUNCT);
157     g_clear_object (&entry_set);
158       return set;
159     }
160
161   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (icon->entry));
162   gtk_entry = GTK_ENTRY (widget);
163
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);
172
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);
177
178   g_object_unref (entry_set);
179   return set;
180 }
181
182 static void
183 gtk_entry_icon_accessible_invalidate (GtkEntryIconAccessible *icon)
184 {
185   if (!icon->entry)
186     return;
187   g_object_weak_unref (G_OBJECT (icon->entry),
188                        gtk_entry_icon_accessible_remove_entry,
189                        icon);
190   gtk_entry_icon_accessible_remove_entry (icon, NULL);
191 }
192
193 static void
194 gtk_entry_icon_accessible_finalize (GObject *object)
195 {
196   GtkEntryIconAccessible *icon = GTK_ENTRY_ICON_ACCESSIBLE (object);
197
198   gtk_entry_icon_accessible_invalidate (icon);
199
200   G_OBJECT_CLASS (gtk_entry_icon_accessible_parent_class)->finalize (object);
201 }
202
203 static void
204 gtk_entry_icon_accessible_class_init (GtkEntryIconAccessibleClass *klass)
205 {
206   AtkObjectClass  *atk_class = ATK_OBJECT_CLASS (klass);
207   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
208
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;
212
213   gobject_class->finalize = gtk_entry_icon_accessible_finalize;
214 }
215
216 static gboolean
217 gtk_entry_icon_accessible_do_action (AtkAction *action,
218                                      gint       i)
219 {
220   GtkEntryIconAccessible *icon = (GtkEntryIconAccessible *)action;
221   GtkWidget *widget;
222   GtkEntry *gtk_entry;
223   GdkEvent event;
224   GdkRectangle icon_area;
225
226   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (icon->entry));
227   if (widget == NULL)
228     return FALSE;
229
230   if (i != 0)
231     return FALSE;
232
233   if (!gtk_widget_is_sensitive (widget) || !gtk_widget_get_visible (widget))
234     return FALSE;
235
236   gtk_entry = GTK_ENTRY (widget);
237
238   if (!gtk_entry_get_icon_sensitive (gtk_entry, icon->pos) ||
239       !gtk_entry_get_icon_activatable (gtk_entry, icon->pos))
240     return FALSE;
241
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;
251
252   g_signal_emit_by_name (widget, "icon-press", 0, icon->pos, &event);
253   return TRUE;
254 }
255
256 static gint
257 gtk_entry_icon_accessible_get_n_actions (AtkAction *action)
258 {
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);
262
263   return (gtk_entry_get_icon_activatable (gtk_entry, icon->pos) ? 1 : 0);
264 }
265
266 static const gchar *
267 gtk_entry_icon_accessible_get_name (AtkAction *action,
268                                     gint       i)
269 {
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);
273
274   if (i != 0)
275     return NULL;
276   if (!gtk_entry_get_icon_activatable (gtk_entry, icon->pos))
277     return NULL;
278
279   return "activate";
280 }
281
282 static void
283 icon_atk_action_interface_init (AtkActionIface *iface)
284 {
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;
288 }
289
290 static void
291 gtk_entry_icon_accessible_get_extents (AtkComponent   *component,
292                                        gint           *x,
293                                        gint           *y,
294                                        gint           *width,
295                                        gint           *height,
296                                        AtkCoordType    coord_type)
297 {
298   GtkEntryIconAccessible *icon = GTK_ENTRY_ICON_ACCESSIBLE (component);
299   GdkRectangle icon_area;
300   GtkEntry *gtk_entry;
301   GtkWidget *widget;
302
303   *x = G_MININT;
304   atk_component_get_extents (ATK_COMPONENT (icon->entry), x, y, width, height,
305                              coord_type);
306   if (*x == G_MININT)
307     return;
308
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;
314   *x += icon_area.x;
315   *y += icon_area.y;
316 }
317
318 static void
319 gtk_entry_icon_accessible_get_position (AtkComponent   *component,
320                                         gint           *x,
321                                         gint           *y,
322                                         AtkCoordType    coord_type)
323 {
324   GtkEntryIconAccessible *icon = GTK_ENTRY_ICON_ACCESSIBLE (component);
325   GdkRectangle icon_area;
326   GtkEntry *gtk_entry;
327   GtkWidget *widget;
328
329   *x = G_MININT;
330   atk_component_get_position (ATK_COMPONENT (icon->entry), x, y, coord_type);
331   if (*x == G_MININT)
332     return;
333
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);
337   *x += icon_area.x;
338   *y += icon_area.y;
339 }
340
341 static void
342 gtk_entry_icon_accessible_get_size (AtkComponent *component,
343                                 gint         *width,
344                                 gint         *height)
345 {
346   GtkEntryIconAccessible *icon = GTK_ENTRY_ICON_ACCESSIBLE (component);
347   GdkRectangle icon_area;
348   GtkEntry *gtk_entry;
349   GtkWidget *widget;
350
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;
356 }
357
358 static void
359 icon_atk_component_interface_init (AtkComponentIface *iface)
360 {
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;
364 }
365
366 /* Callbacks */
367
368 static void     insert_text_cb             (GtkEditable        *editable,
369                                             gchar              *new_text,
370                                             gint                new_text_length,
371                                             gint               *position);
372 static void     delete_text_cb             (GtkEditable        *editable,
373                                             gint                start,
374                                             gint                end);
375
376 static gboolean check_for_selection_change (GtkEntryAccessible *entry,
377                                             GtkEntry           *gtk_entry);
378
379
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);
383
384
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))
389
390
391 static AtkStateSet *
392 gtk_entry_accessible_ref_state_set (AtkObject *accessible)
393 {
394   AtkStateSet *state_set;
395   gboolean value;
396   GtkWidget *widget;
397
398   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (accessible));
399   if (widget == NULL)
400     return NULL;
401
402   state_set = ATK_OBJECT_CLASS (gtk_entry_accessible_parent_class)->ref_state_set (accessible);
403
404   g_object_get (G_OBJECT (widget), "editable", &value, NULL);
405   if (value)
406     atk_state_set_add_state (state_set, ATK_STATE_EDITABLE);
407   atk_state_set_add_state (state_set, ATK_STATE_SINGLE_LINE);
408
409   return state_set;
410 }
411
412 static AtkAttributeSet *
413 gtk_entry_accessible_get_attributes (AtkObject *accessible)
414 {
415   GtkWidget *widget;
416   AtkAttributeSet *attributes;
417   AtkAttribute *placeholder_text;
418   const gchar *text;
419
420   attributes = ATK_OBJECT_CLASS (gtk_entry_accessible_parent_class)->get_attributes (accessible);
421
422   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (accessible));
423   if (widget == NULL)
424     return attributes;
425
426   text = gtk_entry_get_placeholder_text (GTK_ENTRY (widget));
427   if (text == NULL)
428     return attributes;
429
430   placeholder_text = g_malloc (sizeof (AtkAttribute));
431   placeholder_text->name = g_strdup ("placeholder-text");
432   placeholder_text->value = g_strdup (text);
433
434   attributes = g_slist_append (attributes, placeholder_text);
435
436   return attributes;
437 }
438
439 static void
440 gtk_entry_accessible_initialize (AtkObject *obj,
441                                  gpointer   data)
442 {
443   GtkEntry *entry;
444   GtkEntryAccessible *gtk_entry_accessible;
445   gint start_pos, end_pos;
446
447   ATK_OBJECT_CLASS (gtk_entry_accessible_parent_class)->initialize (obj, data);
448
449   gtk_entry_accessible = GTK_ENTRY_ACCESSIBLE (obj);
450
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;
455
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);
459
460   if (gtk_entry_get_visibility (entry))
461     obj->role = ATK_ROLE_TEXT;
462   else
463     obj->role = ATK_ROLE_PASSWORD_TEXT;
464 }
465
466 static void
467 gtk_entry_accessible_notify_gtk (GObject    *obj,
468                                  GParamSpec *pspec)
469 {
470   GtkWidget *widget;
471   AtkObject* atk_obj;
472   GtkEntry* gtk_entry;
473   GtkEntryAccessible* entry;
474   GtkEntryAccessiblePrivate *priv;
475
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);
480   priv = entry->priv;
481
482   if (g_strcmp0 (pspec->name, "cursor-position") == 0)
483     {
484       if (check_for_selection_change (entry, gtk_entry))
485         g_signal_emit_by_name (atk_obj, "text-selection-changed");
486       /*
487        * The entry cursor position has moved so generate the signal.
488        */
489       g_signal_emit_by_name (atk_obj, "text-caret-moved",
490                              entry->priv->cursor_position);
491     }
492   else if (g_strcmp0 (pspec->name, "selection-bound") == 0)
493     {
494       if (check_for_selection_change (entry, gtk_entry))
495         g_signal_emit_by_name (atk_obj, "text-selection-changed");
496     }
497   else if (g_strcmp0 (pspec->name, "editable") == 0)
498     {
499       gboolean value;
500
501       g_object_get (obj, "editable", &value, NULL);
502       atk_object_notify_state_change (atk_obj, ATK_STATE_EDITABLE, value);
503     }
504   else if (g_strcmp0 (pspec->name, "visibility") == 0)
505     {
506       gboolean visibility;
507       AtkRole new_role;
508
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);
512     }
513   else if (g_strcmp0 (pspec->name, "primary-icon-storage-type") == 0)
514     {
515       if (gtk_entry_get_icon_storage_type (gtk_entry, GTK_ENTRY_ICON_PRIMARY) != GTK_IMAGE_EMPTY && !priv->icons[GTK_ENTRY_ICON_PRIMARY])
516         {
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);
520         }
521       else if (gtk_entry_get_icon_storage_type (gtk_entry, GTK_ENTRY_ICON_PRIMARY) == GTK_IMAGE_EMPTY && priv->icons[GTK_ENTRY_ICON_PRIMARY])
522         {
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]);
527         }
528     }
529   else if (g_strcmp0 (pspec->name, "secondary-icon-storage-type") == 0)
530     {
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])
533         {
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);
537         }
538       else if (gtk_entry_get_icon_storage_type (gtk_entry, GTK_ENTRY_ICON_SECONDARY) == GTK_IMAGE_EMPTY && priv->icons[GTK_ENTRY_ICON_SECONDARY])
539         {
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]);
544         }
545     }
546   else if (g_strcmp0 (pspec->name, "primary-icon-name") == 0)
547     {
548       if (priv->icons[GTK_ENTRY_ICON_PRIMARY])
549         {
550           const gchar *name;
551           name = gtk_entry_get_icon_name (gtk_entry,
552                                           GTK_ENTRY_ICON_PRIMARY);
553           if (name)
554             atk_object_set_name (priv->icons[GTK_ENTRY_ICON_PRIMARY], name);
555         }
556     }
557   else if (g_strcmp0 (pspec->name, "secondary-icon-name") == 0)
558     {
559       if (priv->icons[GTK_ENTRY_ICON_SECONDARY])
560         {
561           const gchar *name;
562           name = gtk_entry_get_icon_name (gtk_entry,
563                                           GTK_ENTRY_ICON_SECONDARY);
564           if (name)
565             atk_object_set_name (priv->icons[GTK_ENTRY_ICON_SECONDARY], name);
566         }
567     }
568   else if (g_strcmp0 (pspec->name, "primary-icon-tooltip-text") == 0)
569     {
570       if (priv->icons[GTK_ENTRY_ICON_PRIMARY])
571         {
572           gchar *text;
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],
576                                       text);
577           g_free (text);
578         }
579     }
580   else if (g_strcmp0 (pspec->name, "secondary-icon-tooltip-text") == 0)
581     {
582       if (priv->icons[GTK_ENTRY_ICON_SECONDARY])
583         {
584           gchar *text;
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],
588                                       text);
589           g_free (text);
590         }
591     }
592   else if (g_strcmp0 (pspec->name, "primary-icon-activatable") == 0)
593     {
594       if (priv->icons[GTK_ENTRY_ICON_PRIMARY])
595         {
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);
599         }
600     }
601   else if (g_strcmp0 (pspec->name, "secondary-icon-activatable") == 0)
602     {
603       if (priv->icons[GTK_ENTRY_ICON_SECONDARY])
604         {
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);
608         }
609     }
610   else if (g_strcmp0 (pspec->name, "primary-icon-sensitive") == 0)
611     {
612       if (priv->icons[GTK_ENTRY_ICON_PRIMARY])
613         {
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);
617         }
618     }
619   else if (g_strcmp0 (pspec->name, "secondary-icon-sensitive") == 0)
620     {
621       if (priv->icons[GTK_ENTRY_ICON_SECONDARY])
622         {
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);
626         }
627     }
628   else
629     GTK_WIDGET_ACCESSIBLE_CLASS (gtk_entry_accessible_parent_class)->notify_gtk (obj, pspec);
630 }
631
632 static gint
633 gtk_entry_accessible_get_index_in_parent (AtkObject *accessible)
634 {
635   /*
636    * If the parent widget is a combo box then the index is 1
637    * otherwise do the normal thing.
638    */
639   if (accessible->accessible_parent)
640     if (GTK_IS_COMBO_BOX_ACCESSIBLE (accessible->accessible_parent))
641       return 1;
642
643   return ATK_OBJECT_CLASS (gtk_entry_accessible_parent_class)->get_index_in_parent (accessible);
644 }
645
646 static gint
647 gtk_entry_accessible_get_n_children (AtkObject* obj)
648 {
649   GtkWidget *widget;
650   GtkEntry *entry;
651   gint count = 0;
652
653   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (obj));
654   if (widget == NULL)
655     return 0;
656
657   entry = GTK_ENTRY (widget);
658
659   if (gtk_entry_get_icon_storage_type (entry, GTK_ENTRY_ICON_PRIMARY) != GTK_IMAGE_EMPTY)
660     count++;
661   if (gtk_entry_get_icon_storage_type (entry, GTK_ENTRY_ICON_SECONDARY) != GTK_IMAGE_EMPTY)
662     count++;
663   return count;
664 }
665
666 static AtkObject *
667 gtk_entry_accessible_ref_child (AtkObject *obj,
668                                 gint i)
669 {
670   GtkEntryAccessible *accessible = GTK_ENTRY_ACCESSIBLE (obj);
671   GtkEntryAccessiblePrivate *priv = accessible->priv;
672   GtkWidget *widget;
673   GtkEntry *entry;
674   GtkEntryIconPosition pos;
675
676   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (obj));
677   if (widget == NULL)
678     return NULL;
679
680   entry = GTK_ENTRY (widget);
681
682   switch (i)
683     {
684     case 0:
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;
689       else
690         return NULL;
691       break;
692     case 1:
693       if (gtk_entry_get_icon_storage_type (entry, GTK_ENTRY_ICON_PRIMARY) == GTK_IMAGE_EMPTY)
694         return NULL;
695       if (gtk_entry_get_icon_storage_type (entry, GTK_ENTRY_ICON_SECONDARY) == GTK_IMAGE_EMPTY)
696         return NULL;
697       pos = GTK_ENTRY_ICON_SECONDARY;
698       break;
699     default:
700       return NULL;
701     }
702
703   if (!priv->icons[pos])
704     priv->icons[pos] = gtk_entry_icon_accessible_new (accessible, pos);
705   return g_object_ref (priv->icons[pos]);
706 }
707
708 static void
709 gtk_entry_accessible_finalize (GObject *object)
710 {
711   GtkEntryAccessible *entry = GTK_ENTRY_ACCESSIBLE (object);
712   GtkEntryAccessiblePrivate *priv = entry->priv;
713
714   g_clear_object (&priv->icons[GTK_ENTRY_ICON_PRIMARY]);
715   g_clear_object (&priv->icons[GTK_ENTRY_ICON_SECONDARY]);
716
717   G_OBJECT_CLASS (gtk_entry_accessible_parent_class)->finalize (object);
718 }
719
720 static void
721 gtk_entry_accessible_class_init (GtkEntryAccessibleClass *klass)
722 {
723   AtkObjectClass  *class = ATK_OBJECT_CLASS (klass);
724   GtkWidgetAccessibleClass *widget_class = (GtkWidgetAccessibleClass*)klass;
725   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
726
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;
733
734   widget_class->notify_gtk = gtk_entry_accessible_notify_gtk;
735
736   gobject_class->finalize = gtk_entry_accessible_finalize;
737
738   g_type_class_add_private (klass, sizeof (GtkEntryAccessiblePrivate));
739 }
740
741 static void
742 gtk_entry_accessible_init (GtkEntryAccessible *entry)
743 {
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;
749 }
750
751 static gchar *
752 gtk_entry_accessible_get_text (AtkText *atk_text,
753                                gint     start_pos,
754                                gint     end_pos)
755 {
756   GtkWidget *widget;
757
758   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (atk_text));
759   if (widget == NULL)
760     return NULL;
761
762   return _gtk_entry_get_display_text (GTK_ENTRY (widget), start_pos, end_pos);
763 }
764
765 static gchar *
766 gtk_entry_accessible_get_text_before_offset (AtkText         *text,
767                                              gint             offset,
768                                              AtkTextBoundary  boundary_type,
769                                              gint            *start_offset,
770                                              gint            *end_offset)
771 {
772   GtkWidget *widget;
773
774   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
775   if (widget == NULL)
776     return NULL;
777
778   return _gtk_pango_get_text_before (gtk_entry_get_layout (GTK_ENTRY (widget)),
779                                      boundary_type, offset,
780                                      start_offset, end_offset);
781 }
782
783 static gchar *
784 gtk_entry_accessible_get_text_at_offset (AtkText         *text,
785                                          gint             offset,
786                                          AtkTextBoundary  boundary_type,
787                                          gint            *start_offset,
788                                          gint            *end_offset)
789 {
790   GtkWidget *widget;
791
792   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
793   if (widget == NULL)
794     return NULL;
795
796   return _gtk_pango_get_text_at (gtk_entry_get_layout (GTK_ENTRY (widget)),
797                                  boundary_type, offset,
798                                  start_offset, end_offset);
799 }
800
801 static gchar *
802 gtk_entry_accessible_get_text_after_offset (AtkText         *text,
803                                             gint             offset,
804                                             AtkTextBoundary  boundary_type,
805                                             gint            *start_offset,
806                                             gint            *end_offset)
807 {
808   GtkWidget *widget;
809
810   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
811   if (widget == NULL)
812     return NULL;
813
814   return _gtk_pango_get_text_after (gtk_entry_get_layout (GTK_ENTRY (widget)),
815                                     boundary_type, offset,
816                                     start_offset, end_offset);
817 }
818
819 static gint
820 gtk_entry_accessible_get_character_count (AtkText *atk_text)
821 {
822   GtkWidget *widget;
823   gchar *text;
824   glong char_count;
825
826   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (atk_text));
827   if (widget == NULL)
828     return 0;
829
830   text = _gtk_entry_get_display_text (GTK_ENTRY (widget), 0, -1);
831
832   char_count = 0;
833   if (text)
834     {
835       char_count = g_utf8_strlen (text, -1);
836       g_free (text);
837     }
838
839   return char_count;
840 }
841
842 static gint
843 gtk_entry_accessible_get_caret_offset (AtkText *text)
844 {
845   GtkWidget *widget;
846
847   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
848   if (widget == NULL)
849     return 0;
850
851   return gtk_editable_get_position (GTK_EDITABLE (widget));
852 }
853
854 static gboolean
855 gtk_entry_accessible_set_caret_offset (AtkText *text,
856                                        gint     offset)
857 {
858   GtkWidget *widget;
859
860   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
861   if (widget == NULL)
862     return FALSE;
863
864   gtk_editable_set_position (GTK_EDITABLE (widget), offset);
865
866   return TRUE;
867 }
868
869 static AtkAttributeSet *
870 add_text_attribute (AtkAttributeSet  *attributes,
871                     AtkTextAttribute  attr,
872                     gint              i)
873 {
874   AtkAttribute *at;
875
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));
879
880   return g_slist_prepend (attributes, at);
881 }
882
883 static AtkAttributeSet *
884 gtk_entry_accessible_get_run_attributes (AtkText *text,
885                                          gint     offset,
886                                          gint    *start_offset,
887                                          gint    *end_offset)
888 {
889   GtkWidget *widget;
890   AtkAttributeSet *attributes;
891
892   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
893   if (widget == NULL)
894     return NULL;
895
896   attributes = NULL;
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)),
901                                               offset,
902                                               start_offset,
903                                               end_offset);
904
905   return attributes;
906 }
907
908 static AtkAttributeSet *
909 gtk_entry_accessible_get_default_attributes (AtkText *text)
910 {
911   GtkWidget *widget;
912   AtkAttributeSet *attributes;
913
914   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
915   if (widget == NULL)
916     return NULL;
917
918   attributes = NULL;
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));
926
927   return attributes;
928 }
929
930 static void
931 gtk_entry_accessible_get_character_extents (AtkText      *text,
932                                             gint          offset,
933                                             gint         *x,
934                                             gint         *y,
935                                             gint         *width,
936                                             gint         *height,
937                                             AtkCoordType  coords)
938 {
939   GtkWidget *widget;
940   GtkEntry *entry;
941   PangoRectangle char_rect;
942   gchar *entry_text;
943   gint index, x_layout, y_layout;
944   GdkWindow *window;
945   gint x_window, y_window;
946
947   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
948   if (widget == NULL)
949     return;
950
951   entry = GTK_ENTRY (widget);
952
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;
956   g_free (entry_text);
957
958   pango_layout_index_to_pos (gtk_entry_get_layout (entry), index, &char_rect);
959   pango_extents_to_pixels (&char_rect, NULL);
960
961   window = gtk_widget_get_window (widget);
962   gdk_window_get_origin (window, &x_window, &y_window);
963
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;
968
969   if (coords == ATK_XY_WINDOW)
970     {
971       window = gdk_window_get_toplevel (window);
972       gdk_window_get_origin (window, &x_window, &y_window);
973
974       *x -= x_window;
975       *y -= y_window;
976     }
977 }
978
979 static gint
980 gtk_entry_accessible_get_offset_at_point (AtkText      *atk_text,
981                                           gint          x,
982                                           gint          y,
983                                           AtkCoordType  coords)
984 {
985   GtkWidget *widget;
986   GtkEntry *entry;
987   gchar *text;
988   gint index, x_layout, y_layout;
989   gint x_window, y_window;
990   gint x_local, y_local;
991   GdkWindow *window;
992   glong offset;
993
994   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (atk_text));
995   if (widget == NULL)
996     return -1;
997
998   entry = GTK_ENTRY (widget);
999
1000   gtk_entry_get_layout_offsets (entry, &x_layout, &y_layout);
1001
1002   window = gtk_widget_get_window (widget);
1003   gdk_window_get_origin (window, &x_window, &y_window);
1004
1005   x_local = x - x_layout - x_window;
1006   y_local = y - y_layout - y_window;
1007
1008   if (coords == ATK_XY_WINDOW)
1009     {
1010       window = gdk_window_get_toplevel (window);
1011       gdk_window_get_origin (window, &x_window, &y_window);
1012
1013       x_local += x_window;
1014       y_local += y_window;
1015     }
1016   if (!pango_layout_xy_to_index (gtk_entry_get_layout (entry),
1017                                  x_local * PANGO_SCALE,
1018                                  y_local * PANGO_SCALE,
1019                                  &index, NULL))
1020     {
1021       if (x_local < 0 || y_local < 0)
1022         index = 0;
1023       else
1024         index = -1;
1025     }
1026
1027   offset = -1;
1028   if (index != -1)
1029     {
1030       text = _gtk_entry_get_display_text (entry, 0, -1);
1031       offset = g_utf8_pointer_to_offset (text, text + index);
1032       g_free (text);
1033     }
1034
1035   return offset;
1036 }
1037
1038 static gint
1039 gtk_entry_accessible_get_n_selections (AtkText *text)
1040 {
1041   GtkWidget *widget;
1042   gint start, end;
1043
1044   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
1045   if (widget == NULL)
1046     return 0;
1047
1048   if (gtk_editable_get_selection_bounds (GTK_EDITABLE (widget), &start, &end))
1049     return 1;
1050
1051   return 0;
1052 }
1053
1054 static gchar *
1055 gtk_entry_accessible_get_selection (AtkText *text,
1056                                     gint     selection_num,
1057                                     gint    *start_pos,
1058                                     gint    *end_pos)
1059 {
1060   GtkWidget *widget;
1061
1062   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
1063   if (widget == NULL)
1064     return NULL;
1065
1066   if (selection_num != 0)
1067      return NULL;
1068
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);
1071
1072   return NULL;
1073 }
1074
1075 static gboolean
1076 gtk_entry_accessible_add_selection (AtkText *text,
1077                                     gint     start_pos,
1078                                     gint     end_pos)
1079 {
1080   GtkEntry *entry;
1081   GtkWidget *widget;
1082   gint start, end;
1083
1084   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
1085   if (widget == NULL)
1086     return FALSE;
1087
1088   entry = GTK_ENTRY (widget);
1089
1090   if (!gtk_editable_get_selection_bounds (GTK_EDITABLE (entry), &start, &end))
1091     {
1092       gtk_editable_select_region (GTK_EDITABLE (entry), start_pos, end_pos);
1093       return TRUE;
1094     }
1095   else
1096     return FALSE;
1097 }
1098
1099 static gboolean
1100 gtk_entry_accessible_remove_selection (AtkText *text,
1101                                        gint     selection_num)
1102 {
1103   GtkWidget *widget;
1104   gint start, end;
1105
1106   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
1107   if (widget == NULL)
1108     return FALSE;
1109
1110   if (selection_num != 0)
1111      return FALSE;
1112
1113   if (gtk_editable_get_selection_bounds (GTK_EDITABLE (widget), &start, &end))
1114     {
1115       gtk_editable_select_region (GTK_EDITABLE (widget), end, end);
1116       return TRUE;
1117     }
1118   else
1119     return FALSE;
1120 }
1121
1122 static gboolean
1123 gtk_entry_accessible_set_selection (AtkText *text,
1124                                     gint     selection_num,
1125                                     gint     start_pos,
1126                                     gint     end_pos)
1127 {
1128   GtkWidget *widget;
1129   gint start, end;
1130
1131   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
1132   if (widget == NULL)
1133     return FALSE;
1134
1135   if (selection_num != 0)
1136      return FALSE;
1137
1138   if (gtk_editable_get_selection_bounds (GTK_EDITABLE (widget), &start, &end))
1139     {
1140       gtk_editable_select_region (GTK_EDITABLE (widget), start_pos, end_pos);
1141       return TRUE;
1142     }
1143   else
1144     return FALSE;
1145 }
1146
1147 static gunichar
1148 gtk_entry_accessible_get_character_at_offset (AtkText *atk_text,
1149                                               gint     offset)
1150 {
1151   GtkWidget *widget;
1152   gchar *text;
1153   gchar *index;
1154   gunichar result;
1155
1156   result = '\0';
1157
1158   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (atk_text));
1159   if (widget == NULL)
1160     return result;
1161
1162   if (!gtk_entry_get_visibility (GTK_ENTRY (widget)))
1163     return result;
1164
1165   text = _gtk_entry_get_display_text (GTK_ENTRY (widget), 0, -1);
1166   if (offset < g_utf8_strlen (text, -1))
1167     {
1168       index = g_utf8_offset_to_pointer (text, offset);
1169       result = g_utf8_get_char (index);
1170       g_free (text);
1171     }
1172
1173   return result;
1174 }
1175
1176 static void
1177 atk_text_interface_init (AtkTextIface *iface)
1178 {
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;
1196 }
1197
1198 static void
1199 gtk_entry_accessible_set_text_contents (AtkEditableText *text,
1200                                         const gchar     *string)
1201 {
1202   GtkWidget *widget;
1203
1204   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
1205   if (widget == NULL)
1206     return;
1207
1208   if (!gtk_editable_get_editable (GTK_EDITABLE (widget)))
1209     return;
1210
1211   gtk_entry_set_text (GTK_ENTRY (widget), string);
1212 }
1213
1214 static void
1215 gtk_entry_accessible_insert_text (AtkEditableText *text,
1216                                   const gchar     *string,
1217                                   gint             length,
1218                                   gint            *position)
1219 {
1220   GtkWidget *widget;
1221   GtkEditable *editable;
1222
1223   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
1224   if (widget == NULL)
1225     return;
1226
1227   editable = GTK_EDITABLE (widget);
1228   if (!gtk_editable_get_editable (editable))
1229     return;
1230
1231   gtk_editable_insert_text (editable, string, length, position);
1232   gtk_editable_set_position (editable, *position);
1233 }
1234
1235 static void
1236 gtk_entry_accessible_copy_text (AtkEditableText *text,
1237                                 gint             start_pos,
1238                                 gint             end_pos)
1239 {
1240   GtkWidget *widget;
1241   GtkEditable *editable;
1242   gchar *str;
1243   GtkClipboard *clipboard;
1244
1245   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
1246   if (widget == NULL)
1247     return;
1248
1249   if (!gtk_widget_has_screen (widget))
1250     return;
1251
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);
1256   g_free (str);
1257 }
1258
1259 static void
1260 gtk_entry_accessible_cut_text (AtkEditableText *text,
1261                                gint             start_pos,
1262                                gint             end_pos)
1263 {
1264   GtkWidget *widget;
1265   GtkEditable *editable;
1266   gchar *str;
1267   GtkClipboard *clipboard;
1268
1269   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
1270   if (widget == NULL)
1271     return;
1272
1273   if (!gtk_widget_has_screen (widget))
1274     return;
1275
1276   editable = GTK_EDITABLE (widget);
1277   if (!gtk_editable_get_editable (editable))
1278     return;
1279
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);
1284 }
1285
1286 static void
1287 gtk_entry_accessible_delete_text (AtkEditableText *text,
1288                                   gint             start_pos,
1289                                   gint             end_pos)
1290 {
1291   GtkWidget *widget;
1292   GtkEditable *editable;
1293
1294   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
1295   if (widget == NULL)
1296     return;
1297
1298   editable = GTK_EDITABLE (widget);
1299   if (!gtk_editable_get_editable (editable))
1300     return;
1301
1302   gtk_editable_delete_text (editable, start_pos, end_pos);
1303 }
1304
1305 typedef struct
1306 {
1307   GtkEntry* entry;
1308   gint position;
1309 } PasteData;
1310
1311 static void
1312 paste_received_cb (GtkClipboard *clipboard,
1313                    const gchar  *text,
1314                    gpointer      data)
1315 {
1316   PasteData *paste = data;
1317
1318   if (text)
1319     gtk_editable_insert_text (GTK_EDITABLE (paste->entry), text, -1,
1320                               &paste->position);
1321
1322   g_object_unref (paste->entry);
1323   g_free (paste);
1324 }
1325
1326 static void
1327 gtk_entry_accessible_paste_text (AtkEditableText *text,
1328                                  gint             position)
1329 {
1330   GtkWidget *widget;
1331   GtkEditable *editable;
1332   PasteData *paste;
1333   GtkClipboard *clipboard;
1334
1335   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
1336   if (widget == NULL)
1337     return;
1338
1339   if (!gtk_widget_has_screen (widget))
1340     return;
1341
1342   editable = GTK_EDITABLE (widget);
1343   if (!gtk_editable_get_editable (editable))
1344     return;
1345
1346   paste = g_new0 (PasteData, 1);
1347   paste->entry = GTK_ENTRY (widget);
1348   paste->position = position;
1349
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);
1353 }
1354
1355 static void
1356 atk_editable_text_interface_init (AtkEditableTextIface *iface)
1357 {
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;
1365 }
1366
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.
1371  */
1372 static void
1373 insert_text_cb (GtkEditable *editable,
1374                 gchar       *new_text,
1375                 gint         new_text_length,
1376                 gint        *position)
1377 {
1378   GtkEntryAccessible *accessible;
1379
1380   if (new_text_length == 0)
1381     return;
1382
1383   accessible = GTK_ENTRY_ACCESSIBLE (gtk_widget_get_accessible (GTK_WIDGET (editable)));
1384
1385   g_signal_emit_by_name (accessible,
1386                          "text-changed::insert",
1387                          *position,
1388                           g_utf8_strlen (new_text, new_text_length));
1389 }
1390
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.
1395  */
1396 static void
1397 delete_text_cb (GtkEditable *editable,
1398                 gint         start,
1399                 gint         end)
1400 {
1401   GtkEntryAccessible *accessible;
1402
1403   accessible = GTK_ENTRY_ACCESSIBLE (gtk_widget_get_accessible (GTK_WIDGET (editable)));
1404
1405   if (end < 0)
1406     {
1407       gchar *text;
1408
1409       text = _gtk_entry_get_display_text (GTK_ENTRY (editable), 0, -1);
1410       end = g_utf8_strlen (text, -1);
1411       g_free (text);
1412     }
1413
1414   if (end == start)
1415     return;
1416
1417   g_signal_emit_by_name (accessible,
1418                          "text-changed::delete",
1419                          start,
1420                          end);
1421 }
1422
1423 static gboolean
1424 check_for_selection_change (GtkEntryAccessible *accessible,
1425                             GtkEntry           *entry)
1426 {
1427   gboolean ret_val = FALSE;
1428   gint start, end;
1429
1430   if (gtk_editable_get_selection_bounds (GTK_EDITABLE (entry), &start, &end))
1431     {
1432       if (end != accessible->priv->cursor_position ||
1433           start != accessible->priv->selection_bound)
1434         /*
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.
1440          */
1441         ret_val = TRUE;
1442     }
1443   else
1444     {
1445       /* We had a selection */
1446       ret_val = (accessible->priv->cursor_position != accessible->priv->selection_bound);
1447     }
1448
1449   accessible->priv->cursor_position = end;
1450   accessible->priv->selection_bound = start;
1451
1452   return ret_val;
1453 }
1454
1455 static gboolean
1456 gtk_entry_accessible_do_action (AtkAction *action,
1457                                 gint       i)
1458 {
1459   GtkWidget *widget;
1460
1461   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (action));
1462   if (widget == NULL)
1463     return FALSE;
1464
1465   if (!gtk_widget_get_sensitive (widget) || !gtk_widget_get_visible (widget))
1466     return FALSE;
1467
1468   if (i != 0)
1469     return FALSE;
1470
1471   gtk_widget_activate (widget);
1472
1473   return TRUE;
1474 }
1475
1476 static gint
1477 gtk_entry_accessible_get_n_actions (AtkAction *action)
1478 {
1479   return 1;
1480 }
1481
1482 static const gchar *
1483 gtk_entry_accessible_get_keybinding (AtkAction *action,
1484                                      gint       i)
1485 {
1486   GtkWidget *widget;
1487   GtkWidget *label;
1488   AtkRelationSet *set;
1489   AtkRelation *relation;
1490   GPtrArray *target;
1491   gpointer target_object;
1492   guint key_val;
1493
1494   if (i != 0)
1495     return NULL;
1496
1497   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (action));
1498   if (widget == NULL)
1499     return NULL;
1500
1501   set = atk_object_ref_relation_set (ATK_OBJECT (action));
1502   if (!set)
1503     return NULL;
1504
1505   label = NULL;
1506   relation = atk_relation_set_get_relation_by_type (set, ATK_RELATION_LABELLED_BY);
1507   if (relation)
1508     {
1509       target = atk_relation_get_target (relation);
1510
1511       target_object = g_ptr_array_index (target, 0);
1512       label = gtk_accessible_get_widget (GTK_ACCESSIBLE (target_object));
1513     }
1514
1515   g_object_unref (set);
1516
1517   if (GTK_IS_LABEL (label))
1518     {
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);
1522     }
1523
1524   return NULL;
1525 }
1526
1527 static const gchar*
1528 gtk_entry_accessible_action_get_name (AtkAction *action,
1529                                       gint       i)
1530 {
1531   if (i == 0)
1532     return "activate";
1533   return NULL;
1534 }
1535
1536 static const gchar*
1537 gtk_entry_accessible_action_get_localized_name (AtkAction *action,
1538                                                 gint       i)
1539 {
1540   if (i == 0)
1541     return C_("Action name", "Activate");
1542   return NULL;
1543 }
1544
1545 static const gchar*
1546 gtk_entry_accessible_action_get_description (AtkAction *action,
1547                                              gint       i)
1548 {
1549   if (i == 0)
1550     return C_("Action description", "Activates the entry");
1551   return NULL;
1552 }
1553
1554 static void
1555 atk_action_interface_init (AtkActionIface *iface)
1556 {
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;
1563 }