]> Pileus Git - ~andy/gtk/blob - gtk/a11y/gtkentryaccessible.c
Avoid unreachable code
[~andy/gtk] / gtk / a11y / gtkentryaccessible.c
1 /* GAIL - The GNOME Accessibility Implementation Library
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           atk_object_set_name (priv->icons[GTK_ENTRY_ICON_PRIMARY], name);
553         }
554     }
555   else if (g_strcmp0 (pspec->name, "secondary-icon-name") == 0)
556     {
557       if (priv->icons[GTK_ENTRY_ICON_SECONDARY])
558         {
559           const gchar *name;
560           name = gtk_entry_get_icon_name (gtk_entry,
561                                           GTK_ENTRY_ICON_SECONDARY);
562           atk_object_set_name (priv->icons[GTK_ENTRY_ICON_SECONDARY], name);
563         }
564     }
565   else if (g_strcmp0 (pspec->name, "primary-icon-tooltip-text") == 0)
566     {
567       if (priv->icons[GTK_ENTRY_ICON_PRIMARY])
568         {
569           gchar *text;
570           text = gtk_entry_get_icon_tooltip_text (gtk_entry,
571                                                     GTK_ENTRY_ICON_PRIMARY);
572           atk_object_set_description (priv->icons[GTK_ENTRY_ICON_PRIMARY],
573                                       text);
574           g_free (text);
575         }
576     }
577   else if (g_strcmp0 (pspec->name, "secondary-icon-tooltip-text") == 0)
578     {
579       if (priv->icons[GTK_ENTRY_ICON_SECONDARY])
580         {
581           gchar *text;
582           text = gtk_entry_get_icon_tooltip_text (gtk_entry,
583                                                     GTK_ENTRY_ICON_SECONDARY);
584           atk_object_set_description (priv->icons[GTK_ENTRY_ICON_SECONDARY],
585                                       text);
586           g_free (text);
587         }
588     }
589   else if (g_strcmp0 (pspec->name, "primary-icon-activatable") == 0)
590     {
591       if (priv->icons[GTK_ENTRY_ICON_PRIMARY])
592         {
593           gboolean on = gtk_entry_get_icon_activatable (gtk_entry, GTK_ENTRY_ICON_PRIMARY);
594           atk_object_notify_state_change (priv->icons[GTK_ENTRY_ICON_PRIMARY],
595                                           ATK_STATE_ENABLED, on);
596         }
597     }
598   else if (g_strcmp0 (pspec->name, "secondary-icon-activatable") == 0)
599     {
600       if (priv->icons[GTK_ENTRY_ICON_SECONDARY])
601         {
602           gboolean on = gtk_entry_get_icon_activatable (gtk_entry, GTK_ENTRY_ICON_SECONDARY);
603           atk_object_notify_state_change (priv->icons[GTK_ENTRY_ICON_SECONDARY],
604                                           ATK_STATE_ENABLED, on);
605         }
606     }
607   else if (g_strcmp0 (pspec->name, "primary-icon-sensitive") == 0)
608     {
609       if (priv->icons[GTK_ENTRY_ICON_PRIMARY])
610         {
611           gboolean on = gtk_entry_get_icon_sensitive (gtk_entry, GTK_ENTRY_ICON_PRIMARY);
612           atk_object_notify_state_change (priv->icons[GTK_ENTRY_ICON_PRIMARY],
613                                           ATK_STATE_SENSITIVE, on);
614         }
615     }
616   else if (g_strcmp0 (pspec->name, "secondary-icon-sensitive") == 0)
617     {
618       if (priv->icons[GTK_ENTRY_ICON_SECONDARY])
619         {
620           gboolean on = gtk_entry_get_icon_sensitive (gtk_entry, GTK_ENTRY_ICON_SECONDARY);
621           atk_object_notify_state_change (priv->icons[GTK_ENTRY_ICON_SECONDARY],
622                                           ATK_STATE_SENSITIVE, on);
623         }
624     }
625   else
626     GTK_WIDGET_ACCESSIBLE_CLASS (_gtk_entry_accessible_parent_class)->notify_gtk (obj, pspec);
627 }
628
629 static gint
630 gtk_entry_accessible_get_index_in_parent (AtkObject *accessible)
631 {
632   /*
633    * If the parent widget is a combo box then the index is 1
634    * otherwise do the normal thing.
635    */
636   if (accessible->accessible_parent)
637     if (GTK_IS_COMBO_BOX_ACCESSIBLE (accessible->accessible_parent))
638       return 1;
639
640   return ATK_OBJECT_CLASS (_gtk_entry_accessible_parent_class)->get_index_in_parent (accessible);
641 }
642
643 static gint
644 gtk_entry_accessible_get_n_children (AtkObject* obj)
645 {
646   GtkWidget *widget;
647   GtkEntry *entry;
648   gint count = 0;
649
650   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (obj));
651   if (widget == NULL)
652     return 0;
653
654   entry = GTK_ENTRY (widget);
655
656   if (gtk_entry_get_icon_storage_type (entry, GTK_ENTRY_ICON_PRIMARY) != GTK_IMAGE_EMPTY)
657     count++;
658   if (gtk_entry_get_icon_storage_type (entry, GTK_ENTRY_ICON_SECONDARY) != GTK_IMAGE_EMPTY)
659     count++;
660   return count;
661 }
662
663 static AtkObject *
664 gtk_entry_accessible_ref_child (AtkObject *obj,
665                                 gint i)
666 {
667   GtkEntryAccessible *accessible = GTK_ENTRY_ACCESSIBLE (obj);
668   GtkEntryAccessiblePrivate *priv = accessible->priv;
669   GtkWidget *widget;
670   GtkEntry *entry;
671   GtkEntryIconPosition pos;
672
673   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (obj));
674   if (widget == NULL)
675     return NULL;
676
677   entry = GTK_ENTRY (widget);
678
679   switch (i)
680     {
681     case 0:
682       if (gtk_entry_get_icon_storage_type (entry, GTK_ENTRY_ICON_PRIMARY) != GTK_IMAGE_EMPTY)
683         pos = GTK_ENTRY_ICON_PRIMARY;
684       else if (gtk_entry_get_icon_storage_type (entry, GTK_ENTRY_ICON_SECONDARY) != GTK_IMAGE_EMPTY)
685         pos = GTK_ENTRY_ICON_SECONDARY;
686       else
687         return NULL;
688       break;
689     case 1:
690       if (gtk_entry_get_icon_storage_type (entry, GTK_ENTRY_ICON_PRIMARY) == GTK_IMAGE_EMPTY)
691         return NULL;
692       if (gtk_entry_get_icon_storage_type (entry, GTK_ENTRY_ICON_SECONDARY) == GTK_IMAGE_EMPTY)
693         return NULL;
694       pos = GTK_ENTRY_ICON_SECONDARY;
695       break;
696     default:
697       return NULL;
698     }
699
700   if (!priv->icons[pos])
701     priv->icons[pos] = gtk_entry_icon_accessible_new (accessible, pos);
702   return g_object_ref (priv->icons[pos]);
703 }
704
705 static void
706 gtk_entry_accessible_finalize (GObject *object)
707 {
708   GtkEntryAccessible *entry = GTK_ENTRY_ACCESSIBLE (object);
709   GtkEntryAccessiblePrivate *priv = entry->priv;
710
711   g_clear_object (&priv->icons[GTK_ENTRY_ICON_PRIMARY]);
712   g_clear_object (&priv->icons[GTK_ENTRY_ICON_SECONDARY]);
713
714   G_OBJECT_CLASS (_gtk_entry_accessible_parent_class)->finalize (object);
715 }
716
717 static void
718 _gtk_entry_accessible_class_init (GtkEntryAccessibleClass *klass)
719 {
720   AtkObjectClass  *class = ATK_OBJECT_CLASS (klass);
721   GtkWidgetAccessibleClass *widget_class = (GtkWidgetAccessibleClass*)klass;
722   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
723
724   class->ref_state_set = gtk_entry_accessible_ref_state_set;
725   class->get_index_in_parent = gtk_entry_accessible_get_index_in_parent;
726   class->initialize = gtk_entry_accessible_initialize;
727   class->get_attributes = gtk_entry_accessible_get_attributes;
728   class->get_n_children = gtk_entry_accessible_get_n_children;
729   class->ref_child = gtk_entry_accessible_ref_child;
730
731   widget_class->notify_gtk = gtk_entry_accessible_notify_gtk;
732
733   gobject_class->finalize = gtk_entry_accessible_finalize;
734
735   g_type_class_add_private (klass, sizeof (GtkEntryAccessiblePrivate));
736 }
737
738 static void
739 _gtk_entry_accessible_init (GtkEntryAccessible *entry)
740 {
741   entry->priv = G_TYPE_INSTANCE_GET_PRIVATE (entry,
742                                              GTK_TYPE_ENTRY_ACCESSIBLE,
743                                              GtkEntryAccessiblePrivate);
744   entry->priv->cursor_position = 0;
745   entry->priv->selection_bound = 0;
746 }
747
748 static gchar *
749 gtk_entry_accessible_get_text (AtkText *atk_text,
750                                gint     start_pos,
751                                gint     end_pos)
752 {
753   GtkWidget *widget;
754
755   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (atk_text));
756   if (widget == NULL)
757     return NULL;
758
759   return _gtk_entry_get_display_text (GTK_ENTRY (widget), start_pos, end_pos);
760 }
761
762 static gchar *
763 gtk_entry_accessible_get_text_before_offset (AtkText         *text,
764                                              gint             offset,
765                                              AtkTextBoundary  boundary_type,
766                                              gint            *start_offset,
767                                              gint            *end_offset)
768 {
769   GtkWidget *widget;
770
771   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
772   if (widget == NULL)
773     return NULL;
774
775   return _gtk_pango_get_text_before (gtk_entry_get_layout (GTK_ENTRY (widget)),
776                                      boundary_type, offset,
777                                      start_offset, end_offset);
778 }
779
780 static gchar *
781 gtk_entry_accessible_get_text_at_offset (AtkText         *text,
782                                          gint             offset,
783                                          AtkTextBoundary  boundary_type,
784                                          gint            *start_offset,
785                                          gint            *end_offset)
786 {
787   GtkWidget *widget;
788
789   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
790   if (widget == NULL)
791     return NULL;
792
793   return _gtk_pango_get_text_at (gtk_entry_get_layout (GTK_ENTRY (widget)),
794                                  boundary_type, offset,
795                                  start_offset, end_offset);
796 }
797
798 static gchar *
799 gtk_entry_accessible_get_text_after_offset (AtkText         *text,
800                                             gint             offset,
801                                             AtkTextBoundary  boundary_type,
802                                             gint            *start_offset,
803                                             gint            *end_offset)
804 {
805   GtkWidget *widget;
806
807   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
808   if (widget == NULL)
809     return NULL;
810
811   return _gtk_pango_get_text_after (gtk_entry_get_layout (GTK_ENTRY (widget)),
812                                     boundary_type, offset,
813                                     start_offset, end_offset);
814 }
815
816 static gint
817 gtk_entry_accessible_get_character_count (AtkText *atk_text)
818 {
819   GtkWidget *widget;
820   gchar *text;
821   glong char_count;
822
823   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (atk_text));
824   if (widget == NULL)
825     return 0;
826
827   text = _gtk_entry_get_display_text (GTK_ENTRY (widget), 0, -1);
828
829   char_count = 0;
830   if (text)
831     {
832       char_count = g_utf8_strlen (text, -1);
833       g_free (text);
834     }
835
836   return char_count;
837 }
838
839 static gint
840 gtk_entry_accessible_get_caret_offset (AtkText *text)
841 {
842   GtkWidget *widget;
843
844   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
845   if (widget == NULL)
846     return 0;
847
848   return gtk_editable_get_position (GTK_EDITABLE (widget));
849 }
850
851 static gboolean
852 gtk_entry_accessible_set_caret_offset (AtkText *text,
853                                        gint     offset)
854 {
855   GtkWidget *widget;
856
857   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
858   if (widget == NULL)
859     return FALSE;
860
861   gtk_editable_set_position (GTK_EDITABLE (widget), offset);
862
863   return TRUE;
864 }
865
866 static AtkAttributeSet *
867 add_text_attribute (AtkAttributeSet  *attributes,
868                     AtkTextAttribute  attr,
869                     gint              i)
870 {
871   AtkAttribute *at;
872
873   at = g_new (AtkAttribute, 1);
874   at->name = g_strdup (atk_text_attribute_get_name (attr));
875   at->value = g_strdup (atk_text_attribute_get_value (attr, i));
876
877   return g_slist_prepend (attributes, at);
878 }
879
880 static AtkAttributeSet *
881 gtk_entry_accessible_get_run_attributes (AtkText *text,
882                                          gint     offset,
883                                          gint    *start_offset,
884                                          gint    *end_offset)
885 {
886   GtkWidget *widget;
887   AtkAttributeSet *attributes;
888
889   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
890   if (widget == NULL)
891     return NULL;
892
893   attributes = NULL;
894   attributes = add_text_attribute (attributes, ATK_TEXT_ATTR_DIRECTION,
895                                    gtk_widget_get_direction (widget));
896   attributes = _gtk_pango_get_run_attributes (attributes,
897                                               gtk_entry_get_layout (GTK_ENTRY (widget)),
898                                               offset,
899                                               start_offset,
900                                               end_offset);
901
902   return attributes;
903 }
904
905 static AtkAttributeSet *
906 gtk_entry_accessible_get_default_attributes (AtkText *text)
907 {
908   GtkWidget *widget;
909   AtkAttributeSet *attributes;
910
911   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
912   if (widget == NULL)
913     return NULL;
914
915   attributes = NULL;
916   attributes = add_text_attribute (attributes, ATK_TEXT_ATTR_DIRECTION,
917                                    gtk_widget_get_direction (widget));
918   attributes = _gtk_pango_get_default_attributes (attributes,
919                                                   gtk_entry_get_layout (GTK_ENTRY (widget)));
920   attributes = _gtk_style_context_get_attributes (attributes,
921                                                   gtk_widget_get_style_context (widget),
922                                                   gtk_widget_get_state_flags (widget));
923
924   return attributes;
925 }
926
927 static void
928 gtk_entry_accessible_get_character_extents (AtkText      *text,
929                                             gint          offset,
930                                             gint         *x,
931                                             gint         *y,
932                                             gint         *width,
933                                             gint         *height,
934                                             AtkCoordType  coords)
935 {
936   GtkWidget *widget;
937   GtkEntry *entry;
938   PangoRectangle char_rect;
939   gchar *entry_text;
940   gint index, x_layout, y_layout;
941   GdkWindow *window;
942   gint x_window, y_window;
943
944   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
945   if (widget == NULL)
946     return;
947
948   entry = GTK_ENTRY (widget);
949
950   gtk_entry_get_layout_offsets (entry, &x_layout, &y_layout);
951   entry_text = _gtk_entry_get_display_text (entry, 0, -1);
952   index = g_utf8_offset_to_pointer (entry_text, offset) - entry_text;
953   g_free (entry_text);
954
955   pango_layout_index_to_pos (gtk_entry_get_layout (entry), index, &char_rect);
956   pango_extents_to_pixels (&char_rect, NULL);
957
958   window = gtk_widget_get_window (widget);
959   gdk_window_get_origin (window, &x_window, &y_window);
960
961   *x = x_window + x_layout + char_rect.x;
962   *y = y_window + y_layout + char_rect.y;
963   *width = char_rect.width;
964   *height = char_rect.height;
965
966   if (coords == ATK_XY_WINDOW)
967     {
968       window = gdk_window_get_toplevel (window);
969       gdk_window_get_origin (window, &x_window, &y_window);
970
971       *x -= x_window;
972       *y -= y_window;
973     }
974 }
975
976 static gint
977 gtk_entry_accessible_get_offset_at_point (AtkText      *atk_text,
978                                           gint          x,
979                                           gint          y,
980                                           AtkCoordType  coords)
981 {
982   GtkWidget *widget;
983   GtkEntry *entry;
984   gchar *text;
985   gint index, x_layout, y_layout;
986   gint x_window, y_window;
987   gint x_local, y_local;
988   GdkWindow *window;
989   glong offset;
990
991   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (atk_text));
992   if (widget == NULL)
993     return -1;
994
995   entry = GTK_ENTRY (widget);
996
997   gtk_entry_get_layout_offsets (entry, &x_layout, &y_layout);
998
999   window = gtk_widget_get_window (widget);
1000   gdk_window_get_origin (window, &x_window, &y_window);
1001
1002   x_local = x - x_layout - x_window;
1003   y_local = y - y_layout - y_window;
1004
1005   if (coords == ATK_XY_WINDOW)
1006     {
1007       window = gdk_window_get_toplevel (window);
1008       gdk_window_get_origin (window, &x_window, &y_window);
1009
1010       x_local += x_window;
1011       y_local += y_window;
1012     }
1013   if (!pango_layout_xy_to_index (gtk_entry_get_layout (entry),
1014                                  x_local * PANGO_SCALE,
1015                                  y_local * PANGO_SCALE,
1016                                  &index, NULL))
1017     {
1018       if (x_local < 0 || y_local < 0)
1019         index = 0;
1020       else
1021         index = -1;
1022     }
1023
1024   offset = -1;
1025   if (index != -1)
1026     {
1027       text = _gtk_entry_get_display_text (entry, 0, -1);
1028       offset = g_utf8_pointer_to_offset (text, text + index);
1029       g_free (text);
1030     }
1031
1032   return offset;
1033 }
1034
1035 static gint
1036 gtk_entry_accessible_get_n_selections (AtkText *text)
1037 {
1038   GtkWidget *widget;
1039   gint start, end;
1040
1041   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
1042   if (widget == NULL)
1043     return 0;
1044
1045   if (gtk_editable_get_selection_bounds (GTK_EDITABLE (widget), &start, &end))
1046     return 1;
1047
1048   return 0;
1049 }
1050
1051 static gchar *
1052 gtk_entry_accessible_get_selection (AtkText *text,
1053                                     gint     selection_num,
1054                                     gint    *start_pos,
1055                                     gint    *end_pos)
1056 {
1057   GtkWidget *widget;
1058
1059   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
1060   if (widget == NULL)
1061     return NULL;
1062
1063   if (selection_num != 0)
1064      return NULL;
1065
1066   if (gtk_editable_get_selection_bounds (GTK_EDITABLE (widget), start_pos, end_pos))
1067     return gtk_editable_get_chars (GTK_EDITABLE (widget), *start_pos, *end_pos);
1068
1069   return NULL;
1070 }
1071
1072 static gboolean
1073 gtk_entry_accessible_add_selection (AtkText *text,
1074                                     gint     start_pos,
1075                                     gint     end_pos)
1076 {
1077   GtkEntry *entry;
1078   GtkWidget *widget;
1079   gint start, end;
1080
1081   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
1082   if (widget == NULL)
1083     return FALSE;
1084
1085   entry = GTK_ENTRY (widget);
1086
1087   if (!gtk_editable_get_selection_bounds (GTK_EDITABLE (entry), &start, &end))
1088     {
1089       gtk_editable_select_region (GTK_EDITABLE (entry), start_pos, end_pos);
1090       return TRUE;
1091     }
1092   else
1093     return FALSE;
1094 }
1095
1096 static gboolean
1097 gtk_entry_accessible_remove_selection (AtkText *text,
1098                                        gint     selection_num)
1099 {
1100   GtkWidget *widget;
1101   gint start, end;
1102
1103   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
1104   if (widget == NULL)
1105     return FALSE;
1106
1107   if (selection_num != 0)
1108      return FALSE;
1109
1110   if (gtk_editable_get_selection_bounds (GTK_EDITABLE (widget), &start, &end))
1111     {
1112       gtk_editable_select_region (GTK_EDITABLE (widget), end, end);
1113       return TRUE;
1114     }
1115   else
1116     return FALSE;
1117 }
1118
1119 static gboolean
1120 gtk_entry_accessible_set_selection (AtkText *text,
1121                                     gint     selection_num,
1122                                     gint     start_pos,
1123                                     gint     end_pos)
1124 {
1125   GtkWidget *widget;
1126   gint start, end;
1127
1128   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
1129   if (widget == NULL)
1130     return FALSE;
1131
1132   if (selection_num != 0)
1133      return FALSE;
1134
1135   if (gtk_editable_get_selection_bounds (GTK_EDITABLE (widget), &start, &end))
1136     {
1137       gtk_editable_select_region (GTK_EDITABLE (widget), start_pos, end_pos);
1138       return TRUE;
1139     }
1140   else
1141     return FALSE;
1142 }
1143
1144 static gunichar
1145 gtk_entry_accessible_get_character_at_offset (AtkText *atk_text,
1146                                               gint     offset)
1147 {
1148   GtkWidget *widget;
1149   gchar *text;
1150   gchar *index;
1151   gunichar result;
1152
1153   result = '\0';
1154
1155   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (atk_text));
1156   if (widget == NULL)
1157     return result;
1158
1159   if (!gtk_entry_get_visibility (GTK_ENTRY (widget)))
1160     return result;
1161
1162   text = _gtk_entry_get_display_text (GTK_ENTRY (widget), 0, -1);
1163   if (offset < g_utf8_strlen (text, -1))
1164     {
1165       index = g_utf8_offset_to_pointer (text, offset);
1166       result = g_utf8_get_char (index);
1167       g_free (text);
1168     }
1169
1170   return result;
1171 }
1172
1173 static void
1174 atk_text_interface_init (AtkTextIface *iface)
1175 {
1176   iface->get_text = gtk_entry_accessible_get_text;
1177   iface->get_character_at_offset = gtk_entry_accessible_get_character_at_offset;
1178   iface->get_text_before_offset = gtk_entry_accessible_get_text_before_offset;
1179   iface->get_text_at_offset = gtk_entry_accessible_get_text_at_offset;
1180   iface->get_text_after_offset = gtk_entry_accessible_get_text_after_offset;
1181   iface->get_caret_offset = gtk_entry_accessible_get_caret_offset;
1182   iface->set_caret_offset = gtk_entry_accessible_set_caret_offset;
1183   iface->get_character_count = gtk_entry_accessible_get_character_count;
1184   iface->get_n_selections = gtk_entry_accessible_get_n_selections;
1185   iface->get_selection = gtk_entry_accessible_get_selection;
1186   iface->add_selection = gtk_entry_accessible_add_selection;
1187   iface->remove_selection = gtk_entry_accessible_remove_selection;
1188   iface->set_selection = gtk_entry_accessible_set_selection;
1189   iface->get_run_attributes = gtk_entry_accessible_get_run_attributes;
1190   iface->get_default_attributes = gtk_entry_accessible_get_default_attributes;
1191   iface->get_character_extents = gtk_entry_accessible_get_character_extents;
1192   iface->get_offset_at_point = gtk_entry_accessible_get_offset_at_point;
1193 }
1194
1195 static void
1196 gtk_entry_accessible_set_text_contents (AtkEditableText *text,
1197                                         const gchar     *string)
1198 {
1199   GtkWidget *widget;
1200
1201   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
1202   if (widget == NULL)
1203     return;
1204
1205   if (!gtk_editable_get_editable (GTK_EDITABLE (widget)))
1206     return;
1207
1208   gtk_entry_set_text (GTK_ENTRY (widget), string);
1209 }
1210
1211 static void
1212 gtk_entry_accessible_insert_text (AtkEditableText *text,
1213                                   const gchar     *string,
1214                                   gint             length,
1215                                   gint            *position)
1216 {
1217   GtkWidget *widget;
1218   GtkEditable *editable;
1219
1220   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
1221   if (widget == NULL)
1222     return;
1223
1224   editable = GTK_EDITABLE (widget);
1225   if (!gtk_editable_get_editable (editable))
1226     return;
1227
1228   gtk_editable_insert_text (editable, string, length, position);
1229   gtk_editable_set_position (editable, *position);
1230 }
1231
1232 static void
1233 gtk_entry_accessible_copy_text (AtkEditableText *text,
1234                                 gint             start_pos,
1235                                 gint             end_pos)
1236 {
1237   GtkWidget *widget;
1238   GtkEditable *editable;
1239   gchar *str;
1240   GtkClipboard *clipboard;
1241
1242   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
1243   if (widget == NULL)
1244     return;
1245
1246   if (!gtk_widget_has_screen (widget))
1247     return;
1248
1249   editable = GTK_EDITABLE (widget);
1250   str = gtk_editable_get_chars (editable, start_pos, end_pos);
1251   clipboard = gtk_widget_get_clipboard (widget, GDK_SELECTION_CLIPBOARD);
1252   gtk_clipboard_set_text (clipboard, str, -1);
1253   g_free (str);
1254 }
1255
1256 static void
1257 gtk_entry_accessible_cut_text (AtkEditableText *text,
1258                                gint             start_pos,
1259                                gint             end_pos)
1260 {
1261   GtkWidget *widget;
1262   GtkEditable *editable;
1263   gchar *str;
1264   GtkClipboard *clipboard;
1265
1266   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
1267   if (widget == NULL)
1268     return;
1269
1270   if (!gtk_widget_has_screen (widget))
1271     return;
1272
1273   editable = GTK_EDITABLE (widget);
1274   if (!gtk_editable_get_editable (editable))
1275     return;
1276
1277   str = gtk_editable_get_chars (editable, start_pos, end_pos);
1278   clipboard = gtk_widget_get_clipboard (widget, GDK_SELECTION_CLIPBOARD);
1279   gtk_clipboard_set_text (clipboard, str, -1);
1280   gtk_editable_delete_text (editable, start_pos, end_pos);
1281 }
1282
1283 static void
1284 gtk_entry_accessible_delete_text (AtkEditableText *text,
1285                                   gint             start_pos,
1286                                   gint             end_pos)
1287 {
1288   GtkWidget *widget;
1289   GtkEditable *editable;
1290
1291   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
1292   if (widget == NULL)
1293     return;
1294
1295   editable = GTK_EDITABLE (widget);
1296   if (!gtk_editable_get_editable (editable))
1297     return;
1298
1299   gtk_editable_delete_text (editable, start_pos, end_pos);
1300 }
1301
1302 typedef struct
1303 {
1304   GtkEntry* entry;
1305   gint position;
1306 } PasteData;
1307
1308 static void
1309 paste_received_cb (GtkClipboard *clipboard,
1310                    const gchar  *text,
1311                    gpointer      data)
1312 {
1313   PasteData *paste = data;
1314
1315   if (text)
1316     gtk_editable_insert_text (GTK_EDITABLE (paste->entry), text, -1,
1317                               &paste->position);
1318
1319   g_object_unref (paste->entry);
1320   g_free (paste);
1321 }
1322
1323 static void
1324 gtk_entry_accessible_paste_text (AtkEditableText *text,
1325                                  gint             position)
1326 {
1327   GtkWidget *widget;
1328   GtkEditable *editable;
1329   PasteData *paste;
1330   GtkClipboard *clipboard;
1331
1332   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
1333   if (widget == NULL)
1334     return;
1335
1336   if (!gtk_widget_has_screen (widget))
1337     return;
1338
1339   editable = GTK_EDITABLE (widget);
1340   if (!gtk_editable_get_editable (editable))
1341     return;
1342
1343   paste = g_new0 (PasteData, 1);
1344   paste->entry = GTK_ENTRY (widget);
1345   paste->position = position;
1346
1347   g_object_ref (paste->entry);
1348   clipboard = gtk_widget_get_clipboard (widget, GDK_SELECTION_CLIPBOARD);
1349   gtk_clipboard_request_text (clipboard, paste_received_cb, paste);
1350 }
1351
1352 static void
1353 atk_editable_text_interface_init (AtkEditableTextIface *iface)
1354 {
1355   iface->set_text_contents = gtk_entry_accessible_set_text_contents;
1356   iface->insert_text = gtk_entry_accessible_insert_text;
1357   iface->copy_text = gtk_entry_accessible_copy_text;
1358   iface->cut_text = gtk_entry_accessible_cut_text;
1359   iface->delete_text = gtk_entry_accessible_delete_text;
1360   iface->paste_text = gtk_entry_accessible_paste_text;
1361   iface->set_run_attributes = NULL;
1362 }
1363
1364 /* We connect to GtkEditable::insert-text, since it carries
1365  * the information we need. But we delay emitting our own
1366  * text_changed::insert signal until the entry has update
1367  * all its internal state and emits GtkEntry::changed.
1368  */
1369 static void
1370 insert_text_cb (GtkEditable *editable,
1371                 gchar       *new_text,
1372                 gint         new_text_length,
1373                 gint        *position)
1374 {
1375   GtkEntryAccessible *accessible;
1376
1377   if (new_text_length == 0)
1378     return;
1379
1380   accessible = GTK_ENTRY_ACCESSIBLE (gtk_widget_get_accessible (GTK_WIDGET (editable)));
1381
1382   g_signal_emit_by_name (accessible,
1383                          "text-changed::insert",
1384                          *position,
1385                           g_utf8_strlen (new_text, new_text_length));
1386 }
1387
1388 /* We connect to GtkEditable::delete-text, since it carries
1389  * the information we need. But we delay emitting our own
1390  * text_changed::delete signal until the entry has update
1391  * all its internal state and emits GtkEntry::changed.
1392  */
1393 static void
1394 delete_text_cb (GtkEditable *editable,
1395                 gint         start,
1396                 gint         end)
1397 {
1398   GtkEntryAccessible *accessible;
1399
1400   accessible = GTK_ENTRY_ACCESSIBLE (gtk_widget_get_accessible (GTK_WIDGET (editable)));
1401
1402   if (end < 0)
1403     {
1404       gchar *text;
1405
1406       text = _gtk_entry_get_display_text (GTK_ENTRY (editable), 0, -1);
1407       end = g_utf8_strlen (text, -1);
1408       g_free (text);
1409     }
1410
1411   if (end == start)
1412     return;
1413
1414   g_signal_emit_by_name (accessible,
1415                          "text-changed::delete",
1416                          start,
1417                          end);
1418 }
1419
1420 static gboolean
1421 check_for_selection_change (GtkEntryAccessible *accessible,
1422                             GtkEntry           *entry)
1423 {
1424   gboolean ret_val = FALSE;
1425   gint start, end;
1426
1427   if (gtk_editable_get_selection_bounds (GTK_EDITABLE (entry), &start, &end))
1428     {
1429       if (end != accessible->priv->cursor_position ||
1430           start != accessible->priv->selection_bound)
1431         /*
1432          * This check is here as this function can be called
1433          * for notification of selection_bound and current_pos.
1434          * The values of current_pos and selection_bound may be the same
1435          * for both notifications and we only want to generate one
1436          * text_selection_changed signal.
1437          */
1438         ret_val = TRUE;
1439     }
1440   else
1441     {
1442       /* We had a selection */
1443       ret_val = (accessible->priv->cursor_position != accessible->priv->selection_bound);
1444     }
1445
1446   accessible->priv->cursor_position = end;
1447   accessible->priv->selection_bound = start;
1448
1449   return ret_val;
1450 }
1451
1452 static gboolean
1453 gtk_entry_accessible_do_action (AtkAction *action,
1454                                 gint       i)
1455 {
1456   GtkWidget *widget;
1457
1458   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (action));
1459   if (widget == NULL)
1460     return FALSE;
1461
1462   if (!gtk_widget_get_sensitive (widget) || !gtk_widget_get_visible (widget))
1463     return FALSE;
1464
1465   if (i != 0)
1466     return FALSE;
1467
1468   gtk_widget_activate (widget);
1469
1470   return TRUE;
1471 }
1472
1473 static gint
1474 gtk_entry_accessible_get_n_actions (AtkAction *action)
1475 {
1476   return 1;
1477 }
1478
1479 static const gchar *
1480 gtk_entry_accessible_get_keybinding (AtkAction *action,
1481                                      gint       i)
1482 {
1483   GtkWidget *widget;
1484   GtkWidget *label;
1485   AtkRelationSet *set;
1486   AtkRelation *relation;
1487   GPtrArray *target;
1488   gpointer target_object;
1489   guint key_val;
1490
1491   if (i != 0)
1492     return NULL;
1493
1494   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (action));
1495   if (widget == NULL)
1496     return NULL;
1497
1498   set = atk_object_ref_relation_set (ATK_OBJECT (action));
1499   if (!set)
1500     return NULL;
1501
1502   label = NULL;
1503   relation = atk_relation_set_get_relation_by_type (set, ATK_RELATION_LABELLED_BY);
1504   if (relation)
1505     {
1506       target = atk_relation_get_target (relation);
1507
1508       target_object = g_ptr_array_index (target, 0);
1509       label = gtk_accessible_get_widget (GTK_ACCESSIBLE (target_object));
1510     }
1511
1512   g_object_unref (set);
1513
1514   if (GTK_IS_LABEL (label))
1515     {
1516       key_val = gtk_label_get_mnemonic_keyval (GTK_LABEL (label));
1517       if (key_val != GDK_KEY_VoidSymbol)
1518         return gtk_accelerator_name (key_val, GDK_MOD1_MASK);
1519     }
1520
1521   return NULL;
1522 }
1523
1524 static const gchar*
1525 gtk_entry_accessible_action_get_name (AtkAction *action,
1526                                       gint       i)
1527 {
1528   if (i != 0)
1529     return NULL;
1530
1531   return "activate";
1532 }
1533
1534 static void
1535 atk_action_interface_init (AtkActionIface *iface)
1536 {
1537   iface->do_action = gtk_entry_accessible_do_action;
1538   iface->get_n_actions = gtk_entry_accessible_get_n_actions;
1539   iface->get_keybinding = gtk_entry_accessible_get_keybinding;
1540   iface->get_name = gtk_entry_accessible_action_get_name;
1541 }