Merge "custom eail widget implementation" into tizen
[platform/core/uifw/eail.git] / eail / eail_entry.c
1 /*
2  * Copyright (c) 2013 Samsung Electronics Co., Ltd.
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 License
15  * along with this library; see the file COPYING.LIB.  If not, write to
16  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17  * Boston, MA 02110-1301, USA.
18  */
19
20 /**
21  * @file eail_entry.c
22  * @brief EailEntry implementation
23  */
24
25 #include <Elementary.h>
26
27 #include "eail_entry.h"
28 #include "eail_utils.h"
29 #include "eail_priv.h"
30 #include "eail_clipboard.h"
31
32 static void atk_text_interface_init(AtkTextIface *iface);
33 static void atk_editable_text_interface_init(AtkEditableTextIface *iface);
34
35 /**
36  * @brief Definition of EailEntry as GObject
37  *
38  * EailEntry is extended EAIL_TYPE_TEXT with ATK_TYPE_TEXT and
39  * ATK_TYPE_EDITABLE_TEXT interfaces implemented.
40  *
41  */
42 G_DEFINE_TYPE_WITH_CODE(EailEntry,
43                         eail_entry,
44                         EAIL_TYPE_WIDGET,
45                         G_IMPLEMENT_INTERFACE(ATK_TYPE_TEXT,
46                                               atk_text_interface_init)
47                         G_IMPLEMENT_INTERFACE(ATK_TYPE_EDITABLE_TEXT,
48                                               atk_editable_text_interface_init));
49
50 /**
51  * @brief Handler for event which is raised when entry content has changed
52  *
53  * @param data data passed to callback
54  * @param obj Evas_Object that raised event
55  * @param event_info additional event info
56  */
57 void
58 _eail_entry_handle_changed_event(void *data,
59                                  Evas_Object *obj,
60                                  void *event_info)
61 {
62    eail_emit_atk_signal
63                   (ATK_OBJECT(data), "visible-data-changed", ATK_TYPE_OBJECT);
64 }
65
66 /**
67  * @brief handler for event which is raised when entry content is being pressed
68  *
69  * @param data passed to callback
70  * @param obj object that raised event
71  * @param event_info additional event info
72  */
73 void
74 _eail_entry_handle_pressed_event(void *data,
75                                  Evas_Object *obj,
76                                  void *event_info)
77 {
78    atk_object_notify_state_change(ATK_OBJECT(data), ATK_STATE_PRESSED, TRUE);
79 }
80
81 /**
82  * @brief handler for event which is raised when entry cusror position is being changed
83  *
84  * @param data passed to callback
85  * @param obj object that raised event
86  * @param event_info additional event info
87  */
88 void
89 _eail_entry_handle_cursor_changed_event(void *data,
90                                  Evas_Object *obj,
91                                  void *event_info)
92 {
93    g_signal_emit_by_name (ATK_OBJECT(data), "text_caret_moved",
94                                  elm_entry_cursor_pos_get(obj));
95 }
96
97 /**
98  * @brief Initializer for AtkObject
99  *
100  * @param obj AtkObject instance
101  * @param data initialization data
102  */
103 static void
104 eail_entry_initialize(AtkObject *obj, gpointer data)
105 {
106    Evas_Object *nested_widget = NULL;
107    ATK_OBJECT_CLASS(eail_entry_parent_class)->initialize(obj, data);
108
109    obj->role = ATK_ROLE_ENTRY;
110
111    g_return_if_fail(EAIL_IS_WIDGET(obj));
112    nested_widget = eail_widget_get_widget(EAIL_WIDGET(obj));
113    if (!nested_widget)
114      {
115         ERR("No evas object inside EailWidget was found");
116         return;
117      }
118
119    evas_object_smart_callback_add(nested_widget, "changed",
120                                   _eail_entry_handle_changed_event, obj);
121    evas_object_smart_callback_add(nested_widget, "cursor,changed",
122                                   _eail_entry_handle_cursor_changed_event, obj);
123    evas_object_smart_callback_add(nested_widget, "press",
124                                   _eail_entry_handle_pressed_event, obj);
125 }
126
127 /**
128  * @brief Class destructor
129  *
130  * @param obj GObject instance
131  */
132 static void
133 eail_entry_finalize(GObject *obj)
134 {
135 }
136
137 /**
138  * @brief Gets a reference to the state set of the accessible
139  *
140  * The caller must unreference it when it is no longer needed.
141  *
142  * Implementation of AtkObject->ref_state_set callback.
143  *
144  * @param obj AtkObject instance
145  *
146  * @returns AtkStateSet representing the state set of the
147  * accessible
148  */
149 static AtkStateSet *
150 eail_entry_ref_state_set(AtkObject *obj)
151 {
152    AtkStateSet *state_set;
153    Evas_Object *widget = eail_widget_get_widget(EAIL_WIDGET(obj));
154
155    if (!widget)
156      return NULL;
157
158    state_set = ATK_OBJECT_CLASS(eail_entry_parent_class)->ref_state_set(obj);
159
160    if (elm_entry_editable_get(widget))
161      atk_state_set_add_state(state_set, ATK_STATE_EDITABLE);
162
163    if (elm_entry_single_line_get(widget))
164      atk_state_set_add_state(state_set, ATK_STATE_SINGLE_LINE);
165    else
166      atk_state_set_add_state(state_set, ATK_STATE_MULTI_LINE);
167
168    return state_set;
169 }
170
171 /**
172  * @brief Initializer for EailEntry GObject implementation
173  *
174  * @param entry EailEntry instance
175  */
176 static void
177 eail_entry_init(EailEntry *entry)
178 {
179    entry->selection_start = 0;
180    entry->selection_end = 0;
181 }
182
183 /**
184  * @brief Initializer for EailPopup GObject class
185  *
186  * Defines callbacks for base AtkObject.
187  *
188  * @param klass EailEntryClass instance
189  */
190 static void
191 eail_entry_class_init(EailEntryClass *klass)
192 {
193    AtkObjectClass *atk_class = ATK_OBJECT_CLASS(klass);
194    GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
195
196    atk_class->initialize = eail_entry_initialize;
197    atk_class->ref_state_set = eail_entry_ref_state_set;
198    gobject_class->finalize = eail_entry_finalize;
199 }
200
201 /**
202  * @brief Gets the caret offset
203  *
204  * @param text AtkText instance
205  * @return integer representing the caret offset
206  */
207 static gint
208 eail_entry_get_caret_offset(AtkText *text)
209 {
210    Evas_Object *widget;
211
212    widget = eail_widget_get_widget(EAIL_WIDGET(text));
213    if (!widget)
214      return 0;
215
216    return elm_entry_cursor_pos_get(widget);
217 }
218
219 /**
220  * @brief Sets the caret (cursor) position to the specified offset.
221  *
222  * Implementation of AtkTextIface->set_caret_offset callback.
223  *
224  * @param text AtkText instance
225  * @param offset starting position
226  *
227  * @returns TRUE on success, FALSE otherwise
228  */
229 static gboolean
230 eail_entry_set_caret_offset (AtkText *text,
231                              gint     offset)
232 {
233    Evas_Object *widget;
234
235    widget = eail_widget_get_widget(EAIL_WIDGET(text));
236    if (!widget)
237      return FALSE;
238
239    elm_entry_cursor_pos_set(widget, offset);
240
241    return TRUE;
242 }
243
244 /**
245  * @brief Gets the number of selected text regions
246  *
247  * @param text AtkText instance
248  * @returns integer representing the number of
249  * selected text regions
250  */
251 static gint
252 eail_entry_get_n_selections(AtkText *text)
253 {
254    Evas_Object *widget;
255
256    widget = eail_widget_get_widget(EAIL_WIDGET(text));
257    if (!widget) return 0;
258
259    if (elm_entry_selection_get(widget)) return 1;
260
261    return 0;
262 }
263
264 /**
265  * @brief Gets text selection from entry
266  *
267  * Use g_free() to free the returned string.
268  *
269  * The selected regions are assigned
270  * numbers that correspond to how far the region is from the start of the text.
271  * The selected region closest to the beginning of the text region is assigned
272  * the number 0, etc. Note that adding, moving or deleting a selected region can
273  * change the numbering.
274  *
275  * Implementation of AtkTextIface->get_selection callback.
276  *
277  * @param text AtkText instance
278  * @param selection_num selection number
279  * @param start_offset start position of the selected region
280  * @param end_offset end position of the selected region
281  *
282  * @returns newly allocated string containing the selected text
283  */
284 static gchar *
285 eail_entry_get_selection(AtkText *text,
286                          gint     selection_num,
287                          gint    *start_offset,
288                          gint    *end_offset)
289 {
290    const char* selection;
291    Evas_Object *widget;
292
293    widget = eail_widget_get_widget(EAIL_WIDGET(text));
294    if (!widget)
295      return g_strdup("");
296
297    if (0 != selection_num)
298      return g_strdup("");
299
300    selection = elm_entry_selection_get(widget);
301    if (selection)
302      {
303         *start_offset = EAIL_ENTRY(text)->selection_start;
304         *end_offset = EAIL_ENTRY(text)->selection_end;
305         return g_strdup(selection);
306      }
307
308    return g_strdup("");
309 }
310
311 /**
312  * @brief Adds a selection bounded by the specified offsets
313  *
314  * @param text AtkText instance
315  * @param start_offset start position of the selection
316  * @param end_offset offset of the first character after selection
317  * @returns TRUE on success, FALSE otherwise
318  */
319 static gboolean
320 eail_entry_add_selection(AtkText *text,
321                          gint start_offset,
322                          gint end_offset)
323 {
324    Evas_Object *widget;
325
326    widget = eail_widget_get_widget(EAIL_WIDGET(text));
327    if (!widget) return FALSE;
328
329    elm_entry_cursor_pos_set(widget, start_offset);
330    elm_entry_cursor_selection_begin(widget);
331    elm_entry_cursor_pos_set(widget, end_offset);
332    elm_entry_cursor_selection_end(widget);
333
334    EAIL_ENTRY(text)->selection_start = start_offset;
335    EAIL_ENTRY(text)->selection_end = end_offset;
336
337    return TRUE;
338 }
339
340 /**
341  * @brief Removes text selection
342  *
343  * Only one selection is supported, so
344  * selection number equals 0.
345  *
346  * @param text AtkText instance
347  * @param selection_num selection number
348  * @return TRUE on success, FALSE otherwise
349  */
350 static gboolean
351 eail_entry_remove_selection(AtkText *text,
352                             gint selection_num)
353 {
354    Evas_Object *widget;
355
356    widget = eail_widget_get_widget(EAIL_WIDGET(text));
357    if (!widget) return FALSE;
358
359    if (selection_num != 0 || !elm_entry_selection_get(widget)) return FALSE;
360
361    elm_entry_select_none(widget);
362    EAIL_ENTRY(text)->selection_start = 0;
363    EAIL_ENTRY(text)->selection_end = 0;
364
365    return TRUE;
366 }
367
368 /**
369  * @brief Sets text selection for entry
370  *
371  * The selected regions are assigned
372  * numbers that correspond to how far the region is from the start of the text.
373  * The selected region closest to the beginning of the text region is assigned
374  * the number 0, etc. Note that adding, moving or deleting a selected region can
375  * change the numbering.
376  *
377  * Implementation of AtkTextIface->set_selection callback.
378  *
379  * @param text AtkText instance
380  * @param selection_num selection number
381  * @param start_pos start position of the selected region
382  * @param end_pos end position of the selected region
383  *
384  * @returns TRUE on success, FALSE otherwise
385  */
386 static gboolean
387 eail_entry_set_selection(AtkText *text,
388                          gint     selection_num,
389                          gint     start_pos,
390                          gint     end_pos)
391 {
392    if (0 != selection_num)
393      return FALSE;
394
395    return eail_entry_add_selection(text, start_pos, end_pos);
396 }
397
398 /**
399  * @brief Gets text bounded by start_offset and end_offset
400  *
401  * Use g_free() to free the returned string.
402  *
403  * @param text AtkText instance
404  * @param start_offset start position
405  * @param end_offset end position, -1 for the end of the string
406  * @return string containing text from start_offset up to,
407  * but not including end_offset
408  */
409 static gchar*
410 eail_entry_get_text(AtkText   *text,
411                     gint       start_offset,
412                     gint       end_offset)
413 {
414    const gchar *string = NULL;
415    Evas_Object *widget = eail_widget_get_widget(EAIL_WIDGET(text));
416
417    if (widget)
418      string = elm_entry_entry_get(widget);
419
420    return eail_get_substring(string, start_offset, end_offset);
421 }
422
423
424 /**
425  * @brief Gets the specified text after offset
426  *
427  * Use g_free() to free the returned string.
428  *
429  * @param text AtkText instance
430  * @param offset character offset
431  * @param boundary_type AtkTextBoundary instance
432  * @param [out] start_offset start offset of the returned string
433  * @param [out] end_offset offset of the first character after the returned
434  * substring
435  * @returns newly allocated string containing the text after offset bounded
436  * by the specified boundary_type
437  */
438 static gchar *
439 eail_entry_get_text_after_offset(AtkText *text,
440                                  gint offset,
441                                  AtkTextBoundary boundary_type,
442                                  gint *start_offset,
443                                  gint *end_offset)
444 {
445    Evas_Object *widget;
446    Evas_Object *textblock;
447
448    widget = eail_widget_get_widget(EAIL_WIDGET(text));
449    if (!widget) return NULL;
450
451    textblock = elm_entry_textblock_get(widget);
452
453    return eail_get_text_after(textblock, offset, boundary_type, start_offset,
454                               end_offset);
455
456 }
457
458 /**
459  * @brief Gets the specified text at offset
460  *
461  * Use g_free() to free the returned string.
462  *
463  * @param text AtkText instance
464  * @param offset character offset
465  * @param boundary_type AtkTextBoundary instance
466  * @param [out] start_offset start offset of the returned string
467  * @param [out] end_offset offset of the first character after the returned
468  * substring
469  * @returns newly allocated string containing the text after offset bounded
470  * by the specified boundary_type
471  */
472 static gchar *
473 eail_entry_get_text_at_offset(AtkText *text,
474                               gint offset,
475                               AtkTextBoundary boundary_type,
476                               gint *start_offset,
477                               gint *end_offset)
478 {
479    Evas_Object *widget;
480    Evas_Object *textblock;
481
482    widget = eail_widget_get_widget(EAIL_WIDGET(text));
483    if (!widget) return NULL;
484
485    textblock = elm_entry_textblock_get(widget);
486
487    return eail_get_text_at(textblock, offset, boundary_type, start_offset,
488                            end_offset);
489 }
490
491 /**
492  * @brief Gets the specified text before offset
493  *
494  * Use g_free() to free the returned string.
495  *
496  * @param text AtkText instance
497  * @param offset character offset
498  * @param boundary_type AtkTextBoundary instance
499  * @param [out] start_offset start offset of the returned string
500  * @param [out] end_offset offset of the first character after the returned
501  * substring
502  * @returns newly allocated string containing the text after offset bounded
503  * by the specified boundary_type
504  */
505 static gchar *
506 eail_entry_get_text_before_offset(AtkText *text,
507                                   gint offset,
508                                   AtkTextBoundary boundary_type,
509                                   gint *start_offset,
510                                   gint *end_offset)
511 {
512    Evas_Object *widget;
513    Evas_Object *textblock;
514
515    widget = eail_widget_get_widget(EAIL_WIDGET(text));
516    if (!widget) return NULL;
517
518    textblock = elm_entry_textblock_get(widget);
519
520    return eail_get_text_before(textblock, offset, boundary_type, start_offset,
521                                end_offset);
522 }
523
524 /**
525  * @brief Gets the character at offset
526  *
527  * @param text AtkText instance
528  * @param offset character offset
529  * @return char representing the character at offset
530  */
531 static gunichar
532 eail_entry_get_character_at_offset(AtkText    *text,
533                                    gint        offset)
534 {
535    gunichar character = '\0';
536    Evas_Object *widget = eail_widget_get_widget(EAIL_WIDGET(text));
537
538    if (widget)
539      character = g_utf8_get_char(
540          g_utf8_offset_to_pointer(elm_entry_entry_get(widget), offset));
541
542    return character;
543 }
544
545 /**
546  * @brief Gets the text's length
547  *
548  * @param text AtkText instance
549  * @return integer representing the text length
550  */
551 static gint
552 eail_entry_get_character_count(AtkText *text)
553 {
554    gint count = 0;
555    const gchar *string_text = NULL;
556
557    Evas_Object *widget = eail_widget_get_widget(EAIL_WIDGET(text));
558
559    if (!widget) return count;
560
561    string_text = elm_object_text_get(widget);
562    if (!string_text) return count;
563
564    count = g_utf8_strlen(string_text, -1);
565
566    return count;
567 }
568
569 /**
570  * @brief Creates an AtkAttributeSet which consists of the default values of
571  * attributes for the text
572  *
573  * The returned AtkAttributeSet should be freed by a call to
574  * atk_attribute_set_free().
575  *
576  * @param text AtkText instance
577  *
578  * @returns AtkAttributeSet which contains the default values of attributes
579  * at offset
580  */
581 static AtkAttributeSet *
582 eail_entry_get_default_attributes(AtkText *text)
583 {
584    AtkAttributeSet *at_set = NULL;
585
586    at_set = eail_utils_text_add_attribute
587        (at_set, ATK_TEXT_ATTR_WRAP_MODE,
588         atk_text_attribute_get_value(ATK_TEXT_ATTR_WRAP_MODE, 0));
589
590    at_set = eail_utils_text_add_attribute
591        (at_set, ATK_TEXT_ATTR_EDITABLE,
592         atk_text_attribute_get_value
593          (ATK_TEXT_ATTR_EDITABLE, TRUE));
594
595    return at_set;
596 }
597
598 /**
599  * @brief Creates an AtkAttributeSet which consists of the attributes
600  * explicitly set at the position offset in the text
601  *
602  * start_offset and end_offset are set to the start and end of the range
603  * around offset where the attributes are invariant. Note that end_offset
604  * is the offset of the first character after the range.
605  *
606  * The returned AtkAttributeSet should be freed by a call to
607  * atk_attribute_set_free()
608  *
609  * @param text AtkText instance
610  * @param offset offset at which to get the attributes
611  * @param [out] start_offset start offset of the range
612  * @param [out] end_offset end offset of the range
613  *
614  * @returns AtkAttributeSet which contains the attributes explicitly set at
615  * offset
616  */
617 static AtkAttributeSet *
618 eail_entry_get_run_attributes(AtkText *text,
619                               gint offset,
620                               gint *start_offset,
621                               gint *end_offset)
622 {
623    AtkAttributeSet *at_set = NULL;
624    Evas_Object *widget = eail_widget_get_widget(EAIL_WIDGET(text));
625
626    if (!widget || offset >= eail_entry_get_character_count(text))
627      {
628         *start_offset = -1;
629         *end_offset = -1;
630
631         return NULL;
632      }
633
634    *start_offset = 0;
635    *end_offset = eail_entry_get_character_count(text);
636
637    /* NOTE: Elm_Wrap_Type value is in 100% compatible with ATK wrap modes, so
638     * no additional conversion is needed*/
639    Elm_Wrap_Type wrap_type = elm_entry_line_wrap_get(widget);
640    at_set = eail_utils_text_add_attribute
641        (at_set, ATK_TEXT_ATTR_WRAP_MODE,
642         atk_text_attribute_get_value
643          (ATK_TEXT_ATTR_WRAP_MODE, wrap_type));
644
645    Eina_Bool editable = elm_entry_editable_get(widget);
646    at_set = eail_utils_text_add_attribute
647        (at_set, ATK_TEXT_ATTR_EDITABLE,
648         atk_text_attribute_get_value
649          (ATK_TEXT_ATTR_EDITABLE, editable));
650
651    return at_set;
652 }
653
654 /**
655  * @brief Get the bounding box containing the glyph
656  *  representing the character at a particular text offset.
657  *
658  * @param text AtkText instance
659  * @param offset The offset of the text character for which
660  * bounding information is required.
661  * @param x Pointer for the x cordinate of the bounding box
662  * @param y Pointer for the y cordinate of the bounding box
663  * @param width Pointer for the width of the bounding box
664  * @param height Pointer for the height of the bounding box
665  * @param coords specify whether coordinates are relative to the
666  * screen or widget window
667  *
668  */
669 static void
670 eail_entry_get_character_extents(AtkText *text,
671                                  gint offset,
672                                  gint *x,
673                                  gint *y,
674                                  gint *width,
675                                  gint *height,
676                                  AtkCoordType coords)
677 {
678    int result = -1;
679    Evas_Object *textblock = NULL;
680    Evas_Textblock_Cursor *cur = NULL;
681
682    Evas_Object *widget = eail_widget_get_widget(EAIL_WIDGET(text));
683
684    if (!widget)
685    {
686       return;
687    }
688
689    textblock = elm_entry_textblock_get(widget);
690    cur = evas_object_textblock_cursor_new(textblock);
691    evas_textblock_cursor_pos_set(cur, offset);
692
693    result = evas_textblock_cursor_char_geometry_get(cur, x, y, width, height);
694
695    evas_textblock_cursor_free(cur);
696
697    if (-1 == result) return;
698
699    if (coords == ATK_XY_SCREEN)
700    {
701       int ee_x, ee_y;
702       Ecore_Evas *ee= ecore_evas_ecore_evas_get(evas_object_evas_get(widget));
703
704       ecore_evas_geometry_get(ee, &ee_x, &ee_y, NULL, NULL);
705       *x += ee_x;
706       *y += ee_y;
707     }
708 }
709
710 /*
711  * @brief Gets the offset of the character located at coordinates
712  * x and y. x and y are interpreted as being relative to the
713  *  screen or this widget's window depending on coords.
714  *
715  * @param text AtkText instance
716  * @param x screen x-position of character
717  * @param y screen y-position of character
718  * @param coords specify whether coordinates are relative to the
719  * screen or widget window
720  *
721  * @returns the offset to the character which is located at the
722  * specified x and y coordinates.
723  */
724 static gint
725 eail_entry_get_offset_at_point(AtkText *text,
726                                gint x,
727                                gint y,
728                                AtkCoordType coords)
729 {
730    Eina_Bool result = EINA_FALSE;
731    Evas_Object *textblock = NULL;
732    Evas_Textblock_Cursor *cur = NULL;
733    gint offset = -1;
734
735    Evas_Object *widget = eail_widget_get_widget(EAIL_WIDGET(text));
736
737    if (!widget) return offset;
738
739    if (coords == ATK_XY_SCREEN)
740    {
741       int ee_x, ee_y;
742       Ecore_Evas *ee= ecore_evas_ecore_evas_get(evas_object_evas_get(widget));
743
744       ecore_evas_geometry_get(ee, &ee_x, &ee_y, NULL, NULL);
745       x -= ee_x;
746       y -= ee_y;
747     }
748
749    textblock = elm_entry_textblock_get(widget);
750    if (!textblock) return offset;
751
752    cur = evas_object_textblock_cursor_new(textblock);
753    if (!cur) return offset;
754
755    result = evas_textblock_cursor_char_coord_set(cur, x, y);
756
757    if (result == EINA_FALSE)
758    {
759       evas_textblock_cursor_free(cur);
760       return offset;
761    }
762
763    offset = evas_textblock_cursor_pos_get(cur);
764    evas_textblock_cursor_free(cur);
765
766    return offset;
767 }
768
769 /**
770  * @brief Initializes AtkTextIface interface
771  *
772  * @param iface AtkTextIface instance
773  */
774 static void
775 atk_text_interface_init(AtkTextIface *iface)
776 {
777    iface->get_caret_offset = eail_entry_get_caret_offset;
778    iface->set_caret_offset = eail_entry_set_caret_offset;
779    iface->get_selection    = eail_entry_get_selection;
780    iface->set_selection    = eail_entry_set_selection;
781    iface->get_text         = eail_entry_get_text;
782    iface->get_character_at_offset = eail_entry_get_character_at_offset;
783    iface->get_character_count = eail_entry_get_character_count;
784    iface->remove_selection = eail_entry_remove_selection;
785    iface->get_n_selections = eail_entry_get_n_selections;
786    iface->add_selection = eail_entry_add_selection;
787    iface->get_run_attributes = eail_entry_get_run_attributes;
788    iface->get_default_attributes = eail_entry_get_default_attributes;
789    iface->get_text_after_offset = eail_entry_get_text_after_offset;
790    iface->get_text_at_offset = eail_entry_get_text_at_offset;
791    iface->get_text_before_offset = eail_entry_get_text_before_offset;
792    iface->get_character_extents = eail_entry_get_character_extents;
793    iface->get_offset_at_point = eail_entry_get_offset_at_point;
794 }
795
796 /*
797  * Implementation of the *AtkEditableText* interface
798  */
799
800 /**
801  * @brief Sets text content of entry
802  *
803  * @param text AtkEditableText instance
804  * @param string string to be set as the content of entry
805  */
806 static void
807 eail_entry_set_text_contents(AtkEditableText *text,
808                              const gchar     *string)
809 {
810    Evas_Object *widget;
811
812    widget = eail_widget_get_widget(EAIL_WIDGET(text));
813    if (widget && elm_entry_editable_get(widget))
814      elm_object_text_set(widget, string);
815 }
816
817 /**
818  * @brief Copies text content from entry to clipboard
819  *
820  * @param text AtkEditableText instance
821  * @param start_pos start position of the cursor
822  * @param end_pos end position of the cursor
823  */
824 static void
825 eail_entry_copy_text(AtkEditableText *text,
826                      gint             start_pos,
827                      gint             end_pos)
828 {
829    Evas_Object *widget;
830    const char *entry_text;
831    char *tmp;
832
833    widget = eail_widget_get_widget(EAIL_WIDGET(text));
834    if (!widget) return;
835
836    entry_text = elm_entry_entry_get(widget);
837    tmp = eail_get_substring(entry_text, start_pos, end_pos);
838    eail_clipboard_set_text(tmp);
839    g_free(tmp);
840 }
841
842 /**
843  * @brief Cuts text content from entry to clipboard
844  *
845  * @param text AtkEditableText instance
846  * @param start_pos start position of the cursor
847  * @param end_pos end position of the cursor
848  */
849 static void
850 eail_entry_cut_text(AtkEditableText *text,
851                     gint             start_pos,
852                     gint             end_pos)
853 {
854    Evas_Object *widget;
855    const char *entry_text;
856    char *tmp;
857    GString *s;
858
859    widget = eail_widget_get_widget(EAIL_WIDGET(text));
860    if (!widget || !elm_entry_editable_get(widget))
861      return;
862
863    entry_text = elm_entry_entry_get(widget);
864    tmp = eail_get_substring(entry_text, start_pos, end_pos);
865    eail_clipboard_set_text(tmp);
866    g_free(tmp);
867
868    s = g_string_new(entry_text);
869    s = g_string_erase(s, start_pos, end_pos - start_pos);
870
871    elm_entry_entry_set(widget, s->str);
872    g_string_free(s, TRUE);
873 }
874
875 /**
876  * @brief Pastes text content from clipboard into entry
877  *
878  * @param text AtkEditableText instance
879  * @param position start position of the cursor
880  */
881 static void
882 eail_entry_paste_text(AtkEditableText *text,
883                       gint             position)
884 {
885    Evas_Object *widget;
886    GString *s;
887    const char *clip;
888
889    widget = eail_widget_get_widget(EAIL_WIDGET(text));
890    if (!widget || !elm_entry_editable_get(widget))
891      return;
892
893    clip = eail_clipboard_get_text();
894    if (!clip) return;
895
896    s = g_string_new(elm_entry_entry_get(widget));
897    s = g_string_insert(s, position, clip);
898    elm_entry_entry_set(widget, s->str);
899    g_string_free(s, TRUE);
900 }
901
902 /**
903  * @brief Deletes text between start_pos and end_pos but not
904  * including end_pos
905  *
906  * @param text AtkEditableText instance
907  * @param start_pos start position
908  * @param end_pos end position
909  */
910 static void
911 eail_entry_delete_text(AtkEditableText *text,
912                        gint start_pos,
913                        gint end_pos)
914 {
915    Evas_Object *widget;
916    GString *entry_text;
917
918    widget = eail_widget_get_widget(EAIL_WIDGET(text));
919    if (!widget || !elm_entry_editable_get(widget))
920      return;
921
922    entry_text = g_string_new(elm_entry_entry_get(widget));
923    entry_text = g_string_erase(entry_text, start_pos, end_pos-start_pos);
924
925    elm_entry_entry_set(widget, entry_text->str);
926    g_string_free(entry_text, TRUE);
927 }
928
929 /**
930  * @brief Inserts text at the specified position
931  *
932  * After the call position points to the position after the newly inserted text.
933  *
934  * @param text AtkEditableText instance
935  * @param string string to insert
936  * @param length string's length
937  * @param [out] position position at which text is inserted
938  */
939 static void
940 eail_entry_insert_text(AtkEditableText *text,
941                        const gchar *string,
942                        gint length,
943                        gint *position)
944 {
945    Evas_Object *widget;
946    GString *entry_text;
947
948    widget = eail_widget_get_widget(EAIL_WIDGET(text));
949    if (!widget || !elm_entry_editable_get(widget))
950      return;
951
952    entry_text = g_string_new(elm_entry_entry_get(widget));
953    entry_text = g_string_insert_len(entry_text, *position, string,
954                                     length);
955    elm_entry_entry_set(widget, entry_text->str);
956    *position += length;
957    g_string_free(entry_text, TRUE);
958 }
959
960 /**
961  * @brief Initialization for AtkEditableTextIface interface
962  *
963  * Function called upon instance creation. It initializes AtkText interface
964  * implementation i.e hooks method pointers in the interface structure
965  * to the implementing class's implementation.
966  *
967  * @param iface AtkEditableTextIface instance
968  */
969 static void
970 atk_editable_text_interface_init(AtkEditableTextIface *iface)
971 {
972    iface->set_text_contents = eail_entry_set_text_contents;
973    iface->copy_text = eail_entry_copy_text;
974    iface->cut_text = eail_entry_cut_text;
975    iface->paste_text = eail_entry_paste_text;
976    iface->delete_text = eail_entry_delete_text;
977    iface->insert_text = eail_entry_insert_text;
978 }