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