]> Pileus Git - ~andy/gtk/blob - modules/other/gail/gailentry.c
Silence unused variable warnings in gail
[~andy/gtk] / modules / other / gail / gailentry.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, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 #include "config.h"
21
22 #include <string.h>
23 #include <gtk/gtk.h>
24 #include <gdk/gdkkeysyms.h>
25 #include "gailentry.h"
26 #include "gailcombobox.h"
27 #include <libgail-util/gailmisc.h>
28
29 static void       gail_entry_class_init            (GailEntryClass       *klass);
30 static void       gail_entry_init                  (GailEntry            *entry);
31 static void       gail_entry_real_initialize       (AtkObject            *obj,
32                                                     gpointer             data);
33 static void       text_setup                       (GailEntry            *entry,
34                                                     GtkEntry             *gtk_entry);
35 static void       gail_entry_real_notify_gtk       (GObject              *obj,
36                                                     GParamSpec           *pspec);
37 static void       gail_entry_finalize              (GObject              *object);
38
39 static gint       gail_entry_get_index_in_parent   (AtkObject            *accessible);
40
41 /* atkobject.h */
42
43 static AtkStateSet* gail_entry_ref_state_set       (AtkObject            *accessible);
44
45 /* atktext.h */
46
47 static void       atk_text_interface_init          (AtkTextIface         *iface);
48
49 static gchar*     gail_entry_get_text              (AtkText              *text,
50                                                     gint                 start_pos,
51                                                     gint                 end_pos);
52 static gunichar   gail_entry_get_character_at_offset
53                                                    (AtkText              *text,
54                                                     gint                 offset);
55 static gchar*     gail_entry_get_text_before_offset(AtkText              *text,
56                                                     gint                 offset,
57                                                     AtkTextBoundary      boundary_type,
58                                                     gint                 *start_offset,
59                                                     gint                 *end_offset);
60 static gchar*     gail_entry_get_text_at_offset    (AtkText              *text,
61                                                     gint                 offset,
62                                                     AtkTextBoundary      boundary_type,
63                                                     gint                 *start_offset,
64                                                     gint                 *end_offset);
65 static gchar*     gail_entry_get_text_after_offset (AtkText              *text,
66                                                     gint                 offset,
67                                                     AtkTextBoundary      boundary_type,
68                                                     gint                 *start_offset,
69                                                     gint                 *end_offset);
70 static gint       gail_entry_get_caret_offset      (AtkText              *text);
71 static gboolean   gail_entry_set_caret_offset      (AtkText              *text,
72                                                     gint                 offset);
73 static gint       gail_entry_get_n_selections      (AtkText              *text);
74 static gchar*     gail_entry_get_selection         (AtkText              *text,
75                                                     gint                 selection_num,
76                                                     gint                 *start_offset,
77                                                     gint                 *end_offset);
78 static gboolean   gail_entry_add_selection         (AtkText              *text,
79                                                     gint                 start_offset,
80                                                     gint                 end_offset);
81 static gboolean   gail_entry_remove_selection      (AtkText              *text,
82                                                     gint                 selection_num);
83 static gboolean   gail_entry_set_selection         (AtkText              *text,
84                                                     gint                 selection_num,
85                                                     gint                 start_offset,
86                                                     gint                 end_offset);
87 static gint       gail_entry_get_character_count   (AtkText              *text);
88 static AtkAttributeSet *  gail_entry_get_run_attributes 
89                                                    (AtkText              *text,
90                                                     gint                 offset,
91                                                     gint                 *start_offset,
92                                                     gint                 *end_offset);
93 static AtkAttributeSet *  gail_entry_get_default_attributes 
94                                                    (AtkText              *text);
95 static void gail_entry_get_character_extents       (AtkText              *text,
96                                                     gint                 offset,
97                                                     gint                 *x,
98                                                     gint                 *y,
99                                                     gint                 *width,
100                                                     gint                 *height,
101                                                     AtkCoordType         coords);
102 static gint gail_entry_get_offset_at_point         (AtkText              *text,
103                                                     gint                 x,
104                                                     gint                 y,
105                                                     AtkCoordType         coords);
106 /* atkeditabletext.h */
107
108 static void       atk_editable_text_interface_init (AtkEditableTextIface *iface);
109 static void       gail_entry_set_text_contents     (AtkEditableText      *text,
110                                                     const gchar          *string);
111 static void       gail_entry_insert_text           (AtkEditableText      *text,
112                                                     const gchar          *string,
113                                                     gint                 length,
114                                                     gint                 *position);
115 static void       gail_entry_copy_text             (AtkEditableText      *text,
116                                                     gint                 start_pos,
117                                                     gint                 end_pos);
118 static void       gail_entry_cut_text              (AtkEditableText      *text,
119                                                     gint                 start_pos,
120                                                     gint                 end_pos);
121 static void       gail_entry_delete_text           (AtkEditableText      *text,
122                                                     gint                 start_pos,
123                                                     gint                 end_pos);
124 static void       gail_entry_paste_text            (AtkEditableText      *text,
125                                                     gint                 position);
126 static void       gail_entry_paste_received        (GtkClipboard *clipboard,
127                                                     const gchar  *text,
128                                                     gpointer     data);
129
130
131 /* Callbacks */
132
133 static gboolean   gail_entry_idle_notify_insert    (gpointer data);
134 static void       gail_entry_notify_insert         (GailEntry            *entry);
135 static void       gail_entry_notify_delete         (GailEntry            *entry);
136 static void       _gail_entry_insert_text_cb       (GtkEntry             *entry,
137                                                     gchar                *arg1,
138                                                     gint                 arg2,
139                                                     gpointer             arg3);
140 static void       _gail_entry_delete_text_cb       (GtkEntry             *entry,
141                                                     gint                 arg1,
142                                                     gint                 arg2);
143 static void       _gail_entry_changed_cb           (GtkEntry             *entry);
144 static gboolean   check_for_selection_change       (GailEntry            *entry,
145                                                     GtkEntry             *gtk_entry);
146
147 static void                  atk_action_interface_init   (AtkActionIface  *iface);
148
149 static gboolean              gail_entry_do_action        (AtkAction       *action,
150                                                           gint            i);
151 static gboolean              idle_do_action              (gpointer        data);
152 static gint                  gail_entry_get_n_actions    (AtkAction       *action);
153 static G_CONST_RETURN gchar* gail_entry_get_description  (AtkAction       *action,
154                                                           gint            i);
155 static G_CONST_RETURN gchar* gail_entry_get_keybinding   (AtkAction       *action,
156                                                           gint            i);
157 static G_CONST_RETURN gchar* gail_entry_action_get_name  (AtkAction       *action,
158                                                           gint            i);
159 static gboolean              gail_entry_set_description  (AtkAction       *action,
160                                                           gint            i,
161                                                           const gchar     *desc);
162
163 typedef struct _GailEntryPaste                  GailEntryPaste;
164
165 struct _GailEntryPaste
166 {
167   GtkEntry* entry;
168   gint position;
169 };
170
171 G_DEFINE_TYPE_WITH_CODE (GailEntry, gail_entry, GAIL_TYPE_WIDGET,
172                          G_IMPLEMENT_INTERFACE (ATK_TYPE_EDITABLE_TEXT, atk_editable_text_interface_init)
173                          G_IMPLEMENT_INTERFACE (ATK_TYPE_TEXT, atk_text_interface_init)
174                          G_IMPLEMENT_INTERFACE (ATK_TYPE_ACTION, atk_action_interface_init))
175
176 static void
177 gail_entry_class_init (GailEntryClass *klass)
178 {
179   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
180   AtkObjectClass  *class = ATK_OBJECT_CLASS (klass);
181   GailWidgetClass *widget_class;
182
183   widget_class = (GailWidgetClass*)klass;
184
185   gobject_class->finalize = gail_entry_finalize;
186
187   class->ref_state_set = gail_entry_ref_state_set;
188   class->get_index_in_parent = gail_entry_get_index_in_parent;
189   class->initialize = gail_entry_real_initialize;
190
191   widget_class->notify_gtk = gail_entry_real_notify_gtk;
192 }
193
194 static void
195 gail_entry_init (GailEntry *entry)
196 {
197   entry->textutil = NULL;
198   entry->signal_name_insert = NULL;
199   entry->signal_name_delete = NULL;
200   entry->cursor_position = 0;
201   entry->selection_bound = 0;
202   entry->activate_description = NULL;
203   entry->activate_keybinding = NULL;
204 }
205
206 static void
207 gail_entry_real_initialize (AtkObject *obj, 
208                             gpointer  data)
209 {
210   GtkEntry *entry;
211   GailEntry *gail_entry;
212   gint start_pos, end_pos;
213
214   ATK_OBJECT_CLASS (gail_entry_parent_class)->initialize (obj, data);
215
216   gail_entry = GAIL_ENTRY (obj);
217   gail_entry->textutil = gail_text_util_new ();
218   
219   g_assert (GTK_IS_ENTRY (data));
220
221   entry = GTK_ENTRY (data);
222   text_setup (gail_entry, entry);
223   gtk_editable_get_selection_bounds (GTK_EDITABLE (entry),
224                                      &start_pos, &end_pos);
225   gail_entry->cursor_position = end_pos;
226   gail_entry->selection_bound = start_pos;
227
228   /* Set up signal callbacks */
229   g_signal_connect (data, "insert-text",
230         G_CALLBACK (_gail_entry_insert_text_cb), NULL);
231   g_signal_connect (data, "delete-text",
232         G_CALLBACK (_gail_entry_delete_text_cb), NULL);
233   g_signal_connect (data, "changed",
234         G_CALLBACK (_gail_entry_changed_cb), NULL);
235
236   if (gtk_entry_get_visibility (entry))
237     obj->role = ATK_ROLE_TEXT;
238   else
239     obj->role = ATK_ROLE_PASSWORD_TEXT;
240 }
241
242 static void
243 gail_entry_real_notify_gtk (GObject             *obj,
244                             GParamSpec          *pspec)
245 {
246   GtkWidget *widget;
247   AtkObject* atk_obj;
248   GtkEntry* gtk_entry;
249   GailEntry* entry;
250
251   widget = GTK_WIDGET (obj);
252   atk_obj = gtk_widget_get_accessible (widget);
253   gtk_entry = GTK_ENTRY (widget);
254   entry = GAIL_ENTRY (atk_obj);
255
256   if (strcmp (pspec->name, "cursor-position") == 0)
257     {
258       if (entry->insert_idle_handler == 0)
259         entry->insert_idle_handler = gdk_threads_add_idle (gail_entry_idle_notify_insert, entry);
260
261       if (check_for_selection_change (entry, gtk_entry))
262         g_signal_emit_by_name (atk_obj, "text_selection_changed");
263       /*
264        * The entry cursor position has moved so generate the signal.
265        */
266       g_signal_emit_by_name (atk_obj, "text_caret_moved", 
267                              entry->cursor_position);
268     }
269   else if (strcmp (pspec->name, "selection-bound") == 0)
270     {
271       if (entry->insert_idle_handler == 0)
272         entry->insert_idle_handler = gdk_threads_add_idle (gail_entry_idle_notify_insert, entry);
273
274       if (check_for_selection_change (entry, gtk_entry))
275         g_signal_emit_by_name (atk_obj, "text_selection_changed");
276     }
277   else if (strcmp (pspec->name, "editable") == 0)
278     {
279       gboolean value;
280
281       g_object_get (obj, "editable", &value, NULL);
282       atk_object_notify_state_change (atk_obj, ATK_STATE_EDITABLE,
283                                                value);
284     }
285   else if (strcmp (pspec->name, "visibility") == 0)
286     {
287       gboolean visibility;
288       AtkRole new_role;
289
290       text_setup (entry, gtk_entry);
291       visibility = gtk_entry_get_visibility (gtk_entry);
292       new_role = visibility ? ATK_ROLE_TEXT : ATK_ROLE_PASSWORD_TEXT;
293       atk_object_set_role (atk_obj, new_role);
294     }
295   else if (strcmp (pspec->name, "invisible-char") == 0)
296     {
297       text_setup (entry, gtk_entry);
298     }
299   else
300     GAIL_WIDGET_CLASS (gail_entry_parent_class)->notify_gtk (obj, pspec);
301 }
302
303 static void
304 text_setup (GailEntry *entry,
305             GtkEntry  *gtk_entry)
306 {
307   if (gtk_entry_get_visibility (gtk_entry))
308     {
309       gail_text_util_text_setup (entry->textutil, gtk_entry_get_text (gtk_entry));
310     }
311   else
312     {
313       gunichar invisible_char;
314       GString *tmp_string = g_string_new (NULL);
315       gint ch_len; 
316       gchar buf[7];
317       guint length;
318       gint i;
319
320       invisible_char = gtk_entry_get_invisible_char (gtk_entry);
321       if (invisible_char == 0)
322         invisible_char = ' ';
323
324       ch_len = g_unichar_to_utf8 (invisible_char, buf);
325       length = gtk_entry_get_text_length (gtk_entry);
326       for (i = 0; i < length; i++)
327         {
328           g_string_append_len (tmp_string, buf, ch_len);
329         }
330
331       gail_text_util_text_setup (entry->textutil, tmp_string->str);
332       g_string_free (tmp_string, TRUE);
333
334     } 
335 }
336
337 static void
338 gail_entry_finalize (GObject            *object)
339 {
340   GailEntry *entry = GAIL_ENTRY (object);
341
342   g_object_unref (entry->textutil);
343   g_free (entry->activate_description);
344   g_free (entry->activate_keybinding);
345   if (entry->action_idle_handler)
346     {
347       g_source_remove (entry->action_idle_handler);
348       entry->action_idle_handler = 0;
349     }
350   if (entry->insert_idle_handler)
351     {
352       g_source_remove (entry->insert_idle_handler);
353       entry->insert_idle_handler = 0;
354     }
355   G_OBJECT_CLASS (gail_entry_parent_class)->finalize (object);
356 }
357
358 static gint
359 gail_entry_get_index_in_parent (AtkObject *accessible)
360 {
361   /*
362    * If the parent widget is a combo box then the index is 1
363    * otherwise do the normal thing.
364    */
365   if (accessible->accessible_parent)
366     if (GAIL_IS_COMBO_BOX (accessible->accessible_parent))
367       return 1;
368
369   return ATK_OBJECT_CLASS (gail_entry_parent_class)->get_index_in_parent (accessible);
370 }
371
372 /* atkobject.h */
373
374 static AtkStateSet*
375 gail_entry_ref_state_set (AtkObject *accessible)
376 {
377   AtkStateSet *state_set;
378   GtkEntry *entry;
379   gboolean value;
380   GtkWidget *widget;
381
382   state_set = ATK_OBJECT_CLASS (gail_entry_parent_class)->ref_state_set (accessible);
383   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (accessible));
384
385   if (widget == NULL)
386     return state_set;
387
388   entry = GTK_ENTRY (widget);
389
390   g_object_get (G_OBJECT (entry), "editable", &value, NULL);
391   if (value)
392     atk_state_set_add_state (state_set, ATK_STATE_EDITABLE);
393   atk_state_set_add_state (state_set, ATK_STATE_SINGLE_LINE);
394
395   return state_set;
396 }
397
398 /* atktext.h */
399
400 static void
401 atk_text_interface_init (AtkTextIface *iface)
402 {
403   iface->get_text = gail_entry_get_text;
404   iface->get_character_at_offset = gail_entry_get_character_at_offset;
405   iface->get_text_before_offset = gail_entry_get_text_before_offset;
406   iface->get_text_at_offset = gail_entry_get_text_at_offset;
407   iface->get_text_after_offset = gail_entry_get_text_after_offset;
408   iface->get_caret_offset = gail_entry_get_caret_offset;
409   iface->set_caret_offset = gail_entry_set_caret_offset;
410   iface->get_character_count = gail_entry_get_character_count;
411   iface->get_n_selections = gail_entry_get_n_selections;
412   iface->get_selection = gail_entry_get_selection;
413   iface->add_selection = gail_entry_add_selection;
414   iface->remove_selection = gail_entry_remove_selection;
415   iface->set_selection = gail_entry_set_selection;
416   iface->get_run_attributes = gail_entry_get_run_attributes;
417   iface->get_default_attributes = gail_entry_get_default_attributes;
418   iface->get_character_extents = gail_entry_get_character_extents;
419   iface->get_offset_at_point = gail_entry_get_offset_at_point;
420 }
421
422 static gchar*
423 gail_entry_get_text (AtkText *text,
424                      gint    start_pos,
425                      gint    end_pos)
426 {
427   GtkWidget *widget;
428
429   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
430   if (widget == NULL)
431     /* State is defunct */
432     return NULL;
433
434   return gail_text_util_get_substring (GAIL_ENTRY (text)->textutil, start_pos, end_pos);
435 }
436
437 static gchar*
438 gail_entry_get_text_before_offset (AtkText          *text,
439                                    gint             offset,
440                                    AtkTextBoundary  boundary_type,
441                                    gint             *start_offset,
442                                    gint             *end_offset)
443 {
444   GtkWidget *widget;
445   GtkEntry *entry;
446
447   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
448   if (widget == NULL)
449     /* State is defunct */
450     return NULL;
451
452   /* Get Entry */
453   entry = GTK_ENTRY (widget);
454
455   return gail_text_util_get_text (GAIL_ENTRY (text)->textutil,
456                           gtk_entry_get_layout (entry), GAIL_BEFORE_OFFSET, 
457                           boundary_type, offset, start_offset, end_offset);
458 }
459
460 static gchar*
461 gail_entry_get_text_at_offset (AtkText          *text,
462                                gint             offset,
463                                AtkTextBoundary  boundary_type,
464                                gint             *start_offset,
465                                gint             *end_offset)
466 {
467   GtkWidget *widget;
468   GtkEntry *entry;
469
470   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
471   if (widget == NULL)
472     /* State is defunct */
473     return NULL;
474
475   /* Get Entry */
476   entry = GTK_ENTRY (widget);
477
478   return gail_text_util_get_text (GAIL_ENTRY (text)->textutil,
479                             gtk_entry_get_layout (entry), GAIL_AT_OFFSET, 
480                             boundary_type, offset, start_offset, end_offset);
481 }
482
483 static gchar*
484 gail_entry_get_text_after_offset  (AtkText          *text,
485                                    gint             offset,
486                                    AtkTextBoundary  boundary_type,
487                                    gint             *start_offset,
488                                    gint             *end_offset)
489 {
490   GtkWidget *widget;
491   GtkEntry *entry;
492
493   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
494   if (widget == NULL)
495     /* State is defunct */
496     return NULL;
497
498   /* Get Entry */
499   entry = GTK_ENTRY (widget);
500
501   return gail_text_util_get_text (GAIL_ENTRY (text)->textutil,
502                            gtk_entry_get_layout (entry), GAIL_AFTER_OFFSET, 
503                            boundary_type, offset, start_offset, end_offset);
504 }
505
506 static gint
507 gail_entry_get_character_count (AtkText *text)
508 {
509   GtkEntry *entry;
510   GtkWidget *widget;
511
512   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
513   if (widget == NULL)
514     /* State is defunct */
515     return 0;
516
517   entry = GTK_ENTRY (widget);
518   return g_utf8_strlen (gtk_entry_get_text (entry), -1);
519 }
520
521 static gint
522 gail_entry_get_caret_offset (AtkText *text)
523 {
524   GtkEntry *entry;
525   GtkWidget *widget;
526
527   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
528   if (widget == NULL)
529     /* State is defunct */
530     return 0;
531
532   entry = GTK_ENTRY (widget);
533
534   return gtk_editable_get_position (GTK_EDITABLE (entry));
535 }
536
537 static gboolean
538 gail_entry_set_caret_offset (AtkText *text, gint offset)
539 {
540   GtkEntry *entry;
541   GtkWidget *widget;
542
543   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
544   if (widget == NULL)
545     /* State is defunct */
546     return FALSE;
547
548   entry = GTK_ENTRY (widget);
549
550   gtk_editable_set_position (GTK_EDITABLE (entry), offset);
551   return TRUE;
552 }
553
554 static AtkAttributeSet*
555 gail_entry_get_run_attributes (AtkText *text,
556                                gint    offset,
557                                gint    *start_offset,
558                                gint    *end_offset)
559 {
560   GtkWidget *widget;
561   GtkEntry *entry;
562   AtkAttributeSet *at_set = NULL;
563   GtkTextDirection dir;
564
565   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
566   if (widget == NULL)
567     /* State is defunct */
568     return NULL;
569
570   entry = GTK_ENTRY (widget);
571  
572   dir = gtk_widget_get_direction (widget);
573   if (dir == GTK_TEXT_DIR_RTL)
574     {
575       at_set = gail_misc_add_attribute (at_set,
576                                         ATK_TEXT_ATTR_DIRECTION,
577        g_strdup (atk_text_attribute_get_value (ATK_TEXT_ATTR_DIRECTION, dir)));
578     }
579
580   at_set = gail_misc_layout_get_run_attributes (at_set,
581                                                 gtk_entry_get_layout (entry),
582                                                 (gchar*)gtk_entry_get_text (entry),
583                                                 offset,
584                                                 start_offset,
585                                                 end_offset);
586   return at_set;
587 }
588
589 static AtkAttributeSet*
590 gail_entry_get_default_attributes (AtkText *text)
591 {
592   GtkWidget *widget;
593   GtkEntry *entry;
594   AtkAttributeSet *at_set = NULL;
595
596   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
597   if (widget == NULL)
598     /* State is defunct */
599     return NULL;
600
601   entry = GTK_ENTRY (widget);
602
603   at_set = gail_misc_get_default_attributes (at_set,
604                                              gtk_entry_get_layout (entry),
605                                              widget);
606   return at_set;
607 }
608   
609 static void
610 gail_entry_get_character_extents (AtkText *text,
611                                   gint    offset,
612                                   gint    *x,
613                                   gint    *y,
614                                   gint    *width,
615                                   gint    *height,
616                                   AtkCoordType coords)
617 {
618   GtkWidget *widget;
619   GtkEntry *entry;
620   PangoRectangle char_rect;
621   gint index, x_layout, y_layout;
622   const gchar *entry_text;
623   gint start_pos, end_pos;
624
625   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
626   if (widget == NULL)
627     /* State is defunct */
628     return;
629
630   entry = GTK_ENTRY (widget);
631
632   gtk_editable_get_selection_bounds (GTK_EDITABLE (entry),
633                                      &start_pos, &end_pos);
634   gtk_entry_get_layout_offsets (entry, &x_layout, &y_layout);
635   entry_text = gtk_entry_get_text (entry);
636
637   index = g_utf8_offset_to_pointer (entry_text, offset) - entry_text;
638
639   /* FIXME: entry->preedit cannot be accessed directly
640   cursor_index = g_utf8_offset_to_pointer (entry_text, end_pos) - entry_text;
641   if (index > cursor_index)
642     index += entry->preedit_length;
643   */
644   pango_layout_index_to_pos (gtk_entry_get_layout(entry), index, &char_rect);
645  
646   gail_misc_get_extents_from_pango_rectangle (widget, &char_rect, 
647                         x_layout, y_layout, x, y, width, height, coords);
648
649
650 static gint 
651 gail_entry_get_offset_at_point (AtkText *text,
652                                 gint x,
653                                 gint y,
654                                 AtkCoordType coords)
655
656   GtkWidget *widget;
657   GtkEntry *entry;
658   gint index, x_layout, y_layout;
659   const gchar *entry_text;
660
661   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
662   if (widget == NULL)
663     /* State is defunct */
664     return -1;
665
666   entry = GTK_ENTRY (widget);
667   
668   gtk_entry_get_layout_offsets (entry, &x_layout, &y_layout);
669   entry_text = gtk_entry_get_text (entry);
670   
671   index = gail_misc_get_index_at_point_in_layout (widget, 
672                gtk_entry_get_layout(entry), x_layout, y_layout, x, y, coords);
673   if (index == -1)
674     {
675       if (coords == ATK_XY_SCREEN || coords == ATK_XY_WINDOW)
676         return g_utf8_strlen (entry_text, -1);
677
678       return index;  
679     }
680   else
681     {
682       gint start_pos, end_pos;
683
684       gtk_editable_get_selection_bounds (GTK_EDITABLE (entry),
685                                          &start_pos, &end_pos);
686       /* FIXME: entry->preedit_length cannot be accessed directly
687       cursor_index = g_utf8_offset_to_pointer (entry_text, end_pos) - entry_text;
688       if (index >= cursor_index && entry->preedit_length)
689         {
690           if (index >= cursor_index + entry->preedit_length)
691             index -= entry->preedit_length;
692           else
693             index = cursor_index;
694         }
695       */
696       return g_utf8_pointer_to_offset (entry_text, entry_text + index);
697     }
698 }
699
700 static gint
701 gail_entry_get_n_selections (AtkText              *text)
702 {
703   GtkEntry *entry;
704   GtkWidget *widget;
705   gint select_start, select_end;
706
707   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
708   if (widget == NULL)
709     /* State is defunct */
710     return -1;
711
712   entry = GTK_ENTRY (widget);
713
714   gtk_editable_get_selection_bounds (GTK_EDITABLE (entry), &select_start, 
715                                      &select_end);
716
717   if (select_start != select_end)
718     return 1;
719   else
720     return 0;
721 }
722
723 static gchar*
724 gail_entry_get_selection (AtkText *text,
725                           gint    selection_num,
726                           gint    *start_pos,
727                           gint    *end_pos)
728 {
729   GtkEntry *entry;
730   GtkWidget *widget;
731
732   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
733   if (widget == NULL)
734     /* State is defunct */
735     return NULL;
736
737  /* Only let the user get the selection if one is set, and if the
738   * selection_num is 0.
739   */
740   if (selection_num != 0)
741      return NULL;
742
743   entry = GTK_ENTRY (widget);
744   gtk_editable_get_selection_bounds (GTK_EDITABLE (entry), start_pos, end_pos);
745
746   if (*start_pos != *end_pos)
747      return gtk_editable_get_chars (GTK_EDITABLE (entry), *start_pos, *end_pos);
748   else
749      return NULL;
750 }
751
752 static gboolean
753 gail_entry_add_selection (AtkText *text,
754                           gint    start_pos,
755                           gint    end_pos)
756 {
757   GtkEntry *entry;
758   GtkWidget *widget;
759   gint select_start, select_end;
760
761   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
762   if (widget == NULL)
763     /* State is defunct */
764     return FALSE;
765
766   entry = GTK_ENTRY (widget);
767
768   gtk_editable_get_selection_bounds (GTK_EDITABLE (entry), &select_start, 
769                                      &select_end);
770
771  /* If there is already a selection, then don't allow another to be added,
772   * since GtkEntry only supports one selected region.
773   */
774   if (select_start == select_end)
775     {
776        gtk_editable_select_region (GTK_EDITABLE (entry), start_pos, end_pos);
777        return TRUE;
778     }
779   else
780    return FALSE;
781 }
782
783 static gboolean
784 gail_entry_remove_selection (AtkText *text,
785                              gint    selection_num)
786 {
787   GtkEntry *entry;
788   GtkWidget *widget;
789   gint select_start, select_end, caret_pos;
790
791   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
792   if (widget == NULL)
793     /* State is defunct */
794     return FALSE;
795
796   if (selection_num != 0)
797      return FALSE;
798
799   entry = GTK_ENTRY (widget);
800   gtk_editable_get_selection_bounds (GTK_EDITABLE (entry), &select_start, 
801                                      &select_end);
802
803   if (select_start != select_end)
804     {
805      /* Setting the start & end of the selected region to the caret position
806       * turns off the selection.
807       */
808       caret_pos = gtk_editable_get_position (GTK_EDITABLE (entry));
809       gtk_editable_select_region (GTK_EDITABLE (entry), caret_pos, caret_pos);
810       return TRUE;
811     }
812   else
813     return FALSE;
814 }
815
816 static gboolean
817 gail_entry_set_selection (AtkText *text,
818                           gint    selection_num,
819                           gint    start_pos,
820                           gint    end_pos)
821 {
822   GtkEntry *entry;
823   GtkWidget *widget;
824   gint select_start, select_end;
825
826   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
827   if (widget == NULL)
828     /* State is defunct */
829     return FALSE;
830
831  /* Only let the user move the selection if one is set, and if the
832   * selection_num is 0
833   */
834   if (selection_num != 0)
835      return FALSE;
836
837   entry = GTK_ENTRY (widget);
838
839   gtk_editable_get_selection_bounds (GTK_EDITABLE (entry), &select_start, 
840                                      &select_end);
841
842   if (select_start != select_end)
843     {
844       gtk_editable_select_region (GTK_EDITABLE (entry), start_pos, end_pos);
845       return TRUE;
846     }
847   else
848     return FALSE;
849 }
850
851 static void
852 atk_editable_text_interface_init (AtkEditableTextIface *iface)
853 {
854   iface->set_text_contents = gail_entry_set_text_contents;
855   iface->insert_text = gail_entry_insert_text;
856   iface->copy_text = gail_entry_copy_text;
857   iface->cut_text = gail_entry_cut_text;
858   iface->delete_text = gail_entry_delete_text;
859   iface->paste_text = gail_entry_paste_text;
860   iface->set_run_attributes = NULL;
861 }
862
863 static void
864 gail_entry_set_text_contents (AtkEditableText *text,
865                               const gchar     *string)
866 {
867   GtkEntry *entry;
868   GtkWidget *widget;
869   GtkEditable *editable;
870
871   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
872   if (widget == NULL)
873     /* State is defunct */
874     return;
875
876   entry = GTK_ENTRY (widget);
877   editable = GTK_EDITABLE (entry);
878   if (!gtk_editable_get_editable (editable))
879     return;
880
881   gtk_entry_set_text (entry, string);
882 }
883
884 static void
885 gail_entry_insert_text (AtkEditableText *text,
886                         const gchar     *string,
887                         gint            length,
888                         gint            *position)
889 {
890   GtkEntry *entry;
891   GtkWidget *widget;
892   GtkEditable *editable;
893
894   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
895   if (widget == NULL)
896     /* State is defunct */
897     return;
898
899   entry = GTK_ENTRY (widget);
900   editable = GTK_EDITABLE (entry);
901   if (!gtk_editable_get_editable (editable))
902     return;
903
904   gtk_editable_insert_text (editable, string, length, position);
905   gtk_editable_set_position (editable, *position);
906 }
907
908 static void
909 gail_entry_copy_text   (AtkEditableText *text,
910                         gint            start_pos,
911                         gint            end_pos)
912 {
913   GtkEntry *entry;
914   GtkWidget *widget;
915   GtkEditable *editable;
916   gchar *str;
917   GtkClipboard *clipboard;
918
919   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
920   if (widget == NULL)
921     /* State is defunct */
922     return;
923
924   entry = GTK_ENTRY (widget);
925   editable = GTK_EDITABLE (entry);
926   str = gtk_editable_get_chars (editable, start_pos, end_pos);
927   clipboard = gtk_clipboard_get_for_display (gtk_widget_get_display (widget),
928                                              GDK_SELECTION_CLIPBOARD);
929   gtk_clipboard_set_text (clipboard, str, -1);
930 }
931
932 static void
933 gail_entry_cut_text (AtkEditableText *text,
934                      gint            start_pos,
935                      gint            end_pos)
936 {
937   GtkEntry *entry;
938   GtkWidget *widget;
939   GtkEditable *editable;
940   gchar *str;
941   GtkClipboard *clipboard;
942
943   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
944   if (widget == NULL)
945     /* State is defunct */
946     return;
947
948   entry = GTK_ENTRY (widget);
949   editable = GTK_EDITABLE (entry);
950   if (!gtk_editable_get_editable (editable))
951     return;
952   str = gtk_editable_get_chars (editable, start_pos, end_pos);
953   clipboard = gtk_clipboard_get_for_display (gtk_widget_get_display (widget),
954                                              GDK_SELECTION_CLIPBOARD);
955   gtk_clipboard_set_text (clipboard, str, -1);
956   gtk_editable_delete_text (editable, start_pos, end_pos);
957 }
958
959 static void
960 gail_entry_delete_text (AtkEditableText *text,
961                         gint            start_pos,
962                         gint            end_pos)
963 {
964   GtkEntry *entry;
965   GtkWidget *widget;
966   GtkEditable *editable;
967
968   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
969   if (widget == NULL)
970     /* State is defunct */
971     return;
972
973   entry = GTK_ENTRY (widget);
974   editable = GTK_EDITABLE (entry);
975   if (!gtk_editable_get_editable (editable))
976     return;
977
978   gtk_editable_delete_text (editable, start_pos, end_pos);
979 }
980
981 static void
982 gail_entry_paste_text (AtkEditableText *text,
983                        gint            position)
984 {
985   GtkWidget *widget;
986   GtkEditable *editable;
987   GailEntryPaste paste_struct;
988   GtkClipboard *clipboard;
989
990   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
991   if (widget == NULL)
992     /* State is defunct */
993     return;
994
995   editable = GTK_EDITABLE (widget);
996   if (!gtk_editable_get_editable (editable))
997     return;
998   paste_struct.entry = GTK_ENTRY (widget);
999   paste_struct.position = position;
1000
1001   g_object_ref (paste_struct.entry);
1002   clipboard = gtk_clipboard_get_for_display (gtk_widget_get_display (widget),
1003                                              GDK_SELECTION_CLIPBOARD);
1004   gtk_clipboard_request_text (clipboard,
1005     gail_entry_paste_received, &paste_struct);
1006 }
1007
1008 static void
1009 gail_entry_paste_received (GtkClipboard *clipboard,
1010                 const gchar  *text,
1011                 gpointer     data)
1012 {
1013   GailEntryPaste* paste_struct = (GailEntryPaste *)data;
1014
1015   if (text)
1016     gtk_editable_insert_text (GTK_EDITABLE (paste_struct->entry), text, -1,
1017        &(paste_struct->position));
1018
1019   g_object_unref (paste_struct->entry);
1020 }
1021
1022 /* Callbacks */
1023
1024 static gboolean
1025 gail_entry_idle_notify_insert (gpointer data)
1026 {
1027   GailEntry *entry;
1028
1029   entry = GAIL_ENTRY (data);
1030   entry->insert_idle_handler = 0;
1031   gail_entry_notify_insert (entry);
1032
1033   return FALSE;
1034 }
1035
1036 static void
1037 gail_entry_notify_insert (GailEntry *entry)
1038 {
1039   GtkWidget *widget;
1040
1041   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (entry));
1042   if (gtk_entry_get_text_length (GTK_ENTRY (widget)) == 0)
1043     return;
1044
1045   if (entry->signal_name_insert)
1046     {
1047       g_signal_emit_by_name (entry, 
1048                              entry->signal_name_insert,
1049                              entry->position_insert,
1050                              entry->length_insert);
1051       entry->signal_name_insert = NULL;
1052     }
1053 }
1054
1055 /* Note arg1 returns the character at the start of the insert.
1056  * arg2 returns the number of characters inserted.
1057  */
1058 static void 
1059 _gail_entry_insert_text_cb (GtkEntry *entry, 
1060                             gchar    *arg1, 
1061                             gint     arg2,
1062                             gpointer arg3)
1063 {
1064   AtkObject *accessible;
1065   GailEntry *gail_entry;
1066   gint *position = (gint *) arg3;
1067
1068   if (arg2 == 0)
1069     return;
1070
1071   accessible = gtk_widget_get_accessible (GTK_WIDGET (entry));
1072   gail_entry = GAIL_ENTRY (accessible);
1073   if (!gail_entry->signal_name_insert)
1074     {
1075       gail_entry->signal_name_insert = "text_changed::insert";
1076       gail_entry->position_insert = *position;
1077       gail_entry->length_insert = g_utf8_strlen(arg1, arg2);
1078     }
1079   /*
1080    * The signal will be emitted when the cursor position is updated.
1081    * or in an idle handler if it not updated.
1082    */
1083    if (gail_entry->insert_idle_handler == 0)
1084      gail_entry->insert_idle_handler = gdk_threads_add_idle (gail_entry_idle_notify_insert, gail_entry);
1085 }
1086
1087 static gunichar 
1088 gail_entry_get_character_at_offset (AtkText *text,
1089                                     gint     offset)
1090 {
1091   GtkWidget *widget;
1092   GailEntry *entry;
1093   gchar *string;
1094   gchar *index;
1095   gunichar unichar;
1096
1097   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
1098   if (widget == NULL)
1099     /* State is defunct */
1100     return '\0';
1101
1102   entry = GAIL_ENTRY (text);
1103   string = gail_text_util_get_substring (entry->textutil, 0, -1);
1104   if (offset >= g_utf8_strlen (string, -1))
1105     {
1106       unichar = '\0';
1107     }
1108   else
1109     {
1110       index = g_utf8_offset_to_pointer (string, offset);
1111
1112       unichar = g_utf8_get_char(index);
1113     }
1114
1115   g_free(string);
1116   return unichar;
1117 }
1118
1119 static void
1120 gail_entry_notify_delete (GailEntry *entry)
1121 {
1122   if (entry->signal_name_delete)
1123     {
1124       g_signal_emit_by_name (entry, 
1125                              entry->signal_name_delete,
1126                              entry->position_delete,
1127                              entry->length_delete);
1128       entry->signal_name_delete = NULL;
1129     }
1130 }
1131
1132 /* Note arg1 returns the start of the delete range, arg2 returns the
1133  * end of the delete range if multiple characters are deleted.  
1134  */
1135 static void 
1136 _gail_entry_delete_text_cb (GtkEntry *entry, 
1137                             gint      arg1, 
1138                             gint      arg2)
1139 {
1140   AtkObject *accessible;
1141   GailEntry *gail_entry;
1142
1143   /*
1144    * Zero length text deleted so ignore
1145    */
1146   if (arg2 - arg1 == 0)
1147     return;
1148
1149   accessible = gtk_widget_get_accessible (GTK_WIDGET (entry));
1150   gail_entry = GAIL_ENTRY (accessible);
1151   if (!gail_entry->signal_name_delete)
1152     {
1153       gail_entry->signal_name_delete = "text_changed::delete";
1154       gail_entry->position_delete = arg1;
1155       gail_entry->length_delete = arg2 - arg1;
1156     }
1157   gail_entry_notify_delete (gail_entry);
1158 }
1159
1160 static void
1161 _gail_entry_changed_cb (GtkEntry *entry)
1162 {
1163   AtkObject *accessible;
1164   GailEntry *gail_entry;
1165
1166   accessible = gtk_widget_get_accessible (GTK_WIDGET (entry));
1167
1168   gail_entry = GAIL_ENTRY (accessible);
1169
1170   text_setup (gail_entry, entry);
1171 }
1172
1173 static gboolean 
1174 check_for_selection_change (GailEntry   *entry,
1175                             GtkEntry    *gtk_entry)
1176 {
1177   gboolean selected, ret_val = FALSE;
1178   gint start_pos, end_pos;
1179
1180   selected = gtk_editable_get_selection_bounds (GTK_EDITABLE (gtk_entry),
1181                                                 &start_pos, &end_pos);
1182   if (selected)
1183     {
1184       if (end_pos != entry->cursor_position ||
1185           start_pos != entry->selection_bound)
1186         /*
1187          * This check is here as this function can be called
1188          * for notification of selection_bound and current_pos.
1189          * The values of current_pos and selection_bound may be the same 
1190          * for both notifications and we only want to generate one
1191          * text_selection_changed signal.
1192          */
1193         ret_val = TRUE;
1194     }
1195   else 
1196     {
1197       /* We had a selection */
1198       ret_val = (entry->cursor_position != entry->selection_bound);
1199     }
1200   entry->cursor_position = end_pos;
1201   entry->selection_bound = start_pos;
1202
1203   return ret_val;
1204 }
1205
1206 static void
1207 atk_action_interface_init (AtkActionIface *iface)
1208 {
1209   iface->do_action = gail_entry_do_action;
1210   iface->get_n_actions = gail_entry_get_n_actions;
1211   iface->get_description = gail_entry_get_description;
1212   iface->get_keybinding = gail_entry_get_keybinding;
1213   iface->get_name = gail_entry_action_get_name;
1214   iface->set_description = gail_entry_set_description;
1215 }
1216
1217 static gboolean
1218 gail_entry_do_action (AtkAction *action,
1219                       gint      i)
1220 {
1221   GailEntry *entry;
1222   GtkWidget *widget;
1223   gboolean return_value = TRUE;
1224
1225   entry = GAIL_ENTRY (action);
1226   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (action));
1227   if (widget == NULL)
1228     /*
1229      * State is defunct
1230      */
1231     return FALSE;
1232
1233   if (!gtk_widget_get_sensitive (widget) || !gtk_widget_get_visible (widget))
1234     return FALSE;
1235
1236   switch (i)
1237     {
1238     case 0:
1239       if (entry->action_idle_handler)
1240         return_value = FALSE;
1241       else
1242         entry->action_idle_handler = gdk_threads_add_idle (idle_do_action, entry);
1243       break;
1244     default:
1245       return_value = FALSE;
1246       break;
1247     }
1248   return return_value; 
1249 }
1250
1251 static gboolean
1252 idle_do_action (gpointer data)
1253 {
1254   GailEntry *entry;
1255   GtkWidget *widget;
1256
1257   entry = GAIL_ENTRY (data);
1258   entry->action_idle_handler = 0;
1259   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (entry));
1260   if (widget == NULL /* State is defunct */ ||
1261       !gtk_widget_get_sensitive (widget) || !gtk_widget_get_visible (widget))
1262     return FALSE;
1263
1264   gtk_widget_activate (widget);
1265
1266   return FALSE;
1267 }
1268
1269 static gint
1270 gail_entry_get_n_actions (AtkAction *action)
1271 {
1272   return 1;
1273 }
1274
1275 static G_CONST_RETURN gchar*
1276 gail_entry_get_description (AtkAction *action,
1277                             gint      i)
1278 {
1279   GailEntry *entry;
1280   G_CONST_RETURN gchar *return_value;
1281
1282   entry = GAIL_ENTRY (action);
1283   switch (i)
1284     {
1285     case 0:
1286       return_value = entry->activate_description;
1287       break;
1288     default:
1289       return_value = NULL;
1290       break;
1291     }
1292   return return_value; 
1293 }
1294
1295 static G_CONST_RETURN gchar*
1296 gail_entry_get_keybinding (AtkAction *action,
1297                            gint      i)
1298 {
1299   GailEntry *entry;
1300   gchar *return_value = NULL;
1301
1302   entry = GAIL_ENTRY (action);
1303   switch (i)
1304     {
1305     case 0:
1306       {
1307         /*
1308          * We look for a mnemonic on the label
1309          */
1310         GtkWidget *widget;
1311         GtkWidget *label;
1312         AtkRelationSet *set;
1313         AtkRelation *relation;
1314         GPtrArray *target;
1315         gpointer target_object;
1316         guint key_val; 
1317
1318         entry = GAIL_ENTRY (action);
1319         widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (entry));
1320         if (widget == NULL)
1321           /*
1322            * State is defunct
1323            */
1324           return NULL;
1325
1326         /* Find labelled-by relation */
1327
1328         set = atk_object_ref_relation_set (ATK_OBJECT (action));
1329         if (!set)
1330           return NULL;
1331         label = NULL;
1332         relation = atk_relation_set_get_relation_by_type (set, ATK_RELATION_LABELLED_BY);
1333         if (relation)
1334           {              
1335             target = atk_relation_get_target (relation);
1336           
1337             target_object = g_ptr_array_index (target, 0);
1338             label = gtk_accessible_get_widget (GTK_ACCESSIBLE (target_object));
1339           }
1340
1341         g_object_unref (set);
1342
1343         if (GTK_IS_LABEL (label))
1344           {
1345             key_val = gtk_label_get_mnemonic_keyval (GTK_LABEL (label)); 
1346             if (key_val != GDK_KEY_VoidSymbol)
1347               return_value = gtk_accelerator_name (key_val, GDK_MOD1_MASK);
1348           }
1349         g_free (entry->activate_keybinding);
1350         entry->activate_keybinding = return_value;
1351         break;
1352       }
1353     default:
1354       break;
1355     }
1356   return return_value; 
1357 }
1358
1359 static G_CONST_RETURN gchar*
1360 gail_entry_action_get_name (AtkAction *action,
1361                             gint      i)
1362 {
1363   G_CONST_RETURN gchar *return_value;
1364
1365   switch (i)
1366     {
1367     case 0:
1368       return_value = "activate";
1369       break;
1370     default:
1371       return_value = NULL;
1372       break;
1373   }
1374   return return_value; 
1375 }
1376
1377 static gboolean
1378 gail_entry_set_description (AtkAction      *action,
1379                             gint           i,
1380                             const gchar    *desc)
1381 {
1382   GailEntry *entry;
1383   gchar **value;
1384
1385   entry = GAIL_ENTRY (action);
1386   switch (i)
1387     {
1388     case 0:
1389       value = &entry->activate_description;
1390       break;
1391     default:
1392       value = NULL;
1393       break;
1394     }
1395
1396   if (value)
1397     {
1398       g_free (*value);
1399       *value = g_strdup (desc);
1400       return TRUE;
1401     }
1402   else
1403     return FALSE;
1404 }