4 * An OpenGL based 'interactive canvas' library.
6 * Copyright (C) 2008 Intel Corporation.
8 * Authored By: Øyvind Kolås <pippin@o-hand.com>
9 * Emmanuele Bassi <ebassi@linux.intel.com>
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public
13 * License as published by the Free Software Foundation; either
14 * version 2 of the License, or (at your option) any later version.
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
26 * SECTION:clutter-text
27 * @short_description: An actor for displaying and editing text
29 * #ClutterText is an actor that displays custom text using Pango
30 * as the text rendering engine.
32 * #ClutterText also allows inline editing of the text if the
33 * actor is set editable using clutter_text_set_editable().
35 * Selection using keyboard or pointers can be enabled using
36 * clutter_text_set_selectable().
38 * #ClutterText is available since Clutter 1.0
48 #include "clutter-text.h"
50 #include "clutter-actor-private.h"
51 #include "clutter-binding-pool.h"
52 #include "clutter-color.h"
53 #include "clutter-debug.h"
54 #include "clutter-enum-types.h"
55 #include "clutter-keysyms.h"
56 #include "clutter-main.h"
57 #include "clutter-marshal.h"
58 #include "clutter-private.h" /* includes <cogl-pango/cogl-pango.h> */
59 #include "clutter-profile.h"
60 #include "clutter-text-buffer.h"
61 #include "clutter-units.h"
62 #include "clutter-paint-volume-private.h"
63 #include "clutter-scriptable.h"
65 /* cursor width in pixels */
66 #define DEFAULT_CURSOR_SIZE 2
68 /* We need at least three cached layouts to run the allocation without
69 * regenerating a new layout. First the layout will be generated at
70 * full width to get the preferred width, then it will be generated at
71 * the preferred width to get the preferred height and then it might
72 * be regenerated at a different width to get the height for the
73 * actual allocated width
75 * since we might get multiple queries from layout managers doing a
76 * double-pass allocations, like tabular ones, we should use 6 slots
78 #define N_CACHED_LAYOUTS 6
80 #define CLUTTER_TEXT_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), CLUTTER_TYPE_TEXT, ClutterTextPrivate))
82 typedef struct _LayoutCache LayoutCache;
84 static const ClutterColor default_cursor_color = { 0, 0, 0, 255 };
85 static const ClutterColor default_selection_color = { 0, 0, 0, 255 };
86 static const ClutterColor default_text_color = { 0, 0, 0, 255 };
87 static const ClutterColor default_selected_text_color = { 0, 0, 0, 255 };
89 static void clutter_scriptable_iface_init (ClutterScriptableIface *iface);
91 G_DEFINE_TYPE_WITH_CODE (ClutterText,
94 G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_SCRIPTABLE,
95 clutter_scriptable_iface_init));
99 /* Cached layout. Pango internally caches the computed extents
100 * when they are requested so there is no need to cache that as
105 /* A number representing the age of this cache (so that when a
106 * new layout is needed the last used cache is replaced)
111 struct _ClutterTextPrivate
113 PangoFontDescription *font_desc;
115 /* the displayed text */
116 ClutterTextBuffer *buffer;
122 ClutterColor text_color;
124 LayoutCache cached_layouts[N_CACHED_LAYOUTS];
127 /* These are the attributes set by the attributes property */
128 PangoAttrList *attrs;
129 /* These are the attributes derived from the text when the
130 use-markup property is set */
131 PangoAttrList *markup_attrs;
132 /* This is the combination of the above two lists. It is set to NULL
133 whenever either of them changes and then regenerated by merging
134 the two lists whenever a layout is needed */
135 PangoAttrList *effective_attrs;
136 /* These are the attributes for the preedit string. These are merged
137 with the effective attributes into a temporary list before
139 PangoAttrList *preedit_attrs;
141 /* current cursor position */
144 /* current 'other end of selection' position */
145 gint selection_bound;
147 /* the x position in the PangoLayout, used to
148 * avoid drifting when repeatedly moving up|down
152 /* the x position of the PangoLayout when in
153 * single line mode, to scroll the contents of the
158 /* the y position of the PangoLayout, fixed to 0 by
162 /* Where to draw the cursor */
163 ClutterGeometry cursor_pos;
164 ClutterColor cursor_color;
167 /* Box representing the paint volume. The box is lazily calculated
169 ClutterPaintVolume paint_volume;
171 guint preedit_cursor_pos;
172 gint preedit_n_chars;
174 ClutterColor selection_color;
176 ClutterColor selected_text_color;
178 gunichar password_char;
180 guint password_hint_id;
181 guint password_hint_timeout;
183 /* Signal handler for when the backend changes its font settings */
184 guint settings_changed_id;
186 /* Signal handler for when the :text-direction changes */
187 guint direction_changed_id;
192 guint use_underline : 1;
193 guint use_markup : 1;
195 guint single_line_mode : 1;
199 guint cursor_visible : 1;
200 guint activatable : 1;
201 guint selectable : 1;
202 guint selection_color_set : 1;
203 guint in_select_drag : 1;
204 guint cursor_color_set : 1;
205 guint preedit_set : 1;
206 guint is_default_font : 1;
208 guint selected_text_color_set : 1;
209 guint paint_volume_valid : 1;
210 guint show_password_hint : 1;
211 guint password_hint_visible : 1;
220 PROP_FONT_DESCRIPTION,
231 PROP_SELECTION_BOUND,
232 PROP_SELECTION_COLOR,
233 PROP_SELECTION_COLOR_SET,
236 PROP_CURSOR_COLOR_SET,
243 PROP_SINGLE_LINE_MODE,
244 PROP_SELECTED_TEXT_COLOR,
245 PROP_SELECTED_TEXT_COLOR_SET,
250 static GParamSpec *obj_props[PROP_LAST];
263 static guint text_signals[LAST_SIGNAL] = { 0, };
265 static void clutter_text_settings_changed_cb (ClutterText *text);
266 static void buffer_connect_signals (ClutterText *self);
267 static void buffer_disconnect_signals (ClutterText *self);
268 static ClutterTextBuffer *get_buffer (ClutterText *self);
271 clutter_text_dirty_paint_volume (ClutterText *text)
273 ClutterTextPrivate *priv = text->priv;
275 if (priv->paint_volume_valid)
277 clutter_paint_volume_free (&priv->paint_volume);
278 priv->paint_volume_valid = FALSE;
283 clutter_text_queue_redraw (ClutterActor *self)
285 /* This is a wrapper for clutter_actor_queue_redraw that also
286 dirties the cached paint volume. It would be nice if we could
287 just override the default implementation of the queue redraw
288 signal to do this instead but that doesn't work because the
289 signal isn't immediately emitted when queue_redraw is called.
290 Clutter will however immediately call get_paint_volume when
291 queue_redraw is called so we do need to dirty it immediately. */
293 clutter_text_dirty_paint_volume (CLUTTER_TEXT (self));
295 clutter_actor_queue_redraw (self);
298 #define clutter_actor_queue_redraw \
299 Please_use_clutter_text_queue_redraw_instead
301 #define offset_real(t,p) ((p) == -1 ? g_utf8_strlen ((t), -1) : (p))
304 offset_to_bytes (const gchar *text,
310 return strlen (text);
312 /* Loop over each character in the string until we either reach the
313 end or the requested position */
314 for (ptr = text; *ptr && pos-- > 0; ptr = g_utf8_next_char (ptr));
319 #define bytes_to_offset(t,p) (g_utf8_pointer_to_offset ((t), (t) + (p)))
322 clutter_text_clear_selection (ClutterText *self)
324 ClutterTextPrivate *priv = self->priv;
326 if (priv->selection_bound != priv->position)
328 priv->selection_bound = priv->position;
329 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_SELECTION_BOUND]);
330 clutter_text_queue_redraw (CLUTTER_ACTOR (self));
335 clutter_text_get_display_text (ClutterText *self)
337 ClutterTextPrivate *priv = self->priv;
338 ClutterTextBuffer *buffer;
341 buffer = get_buffer (self);
342 text = clutter_text_buffer_get_text (buffer);
344 /* simple short-circuit to avoid going through GString
345 * with an empty text and a password char set
348 return g_strdup ("");
350 if (G_LIKELY (priv->password_char == 0))
351 return g_strdup (text);
355 gunichar invisible_char;
360 n_chars = clutter_text_buffer_get_length (buffer);
361 str = g_string_sized_new (clutter_text_buffer_get_bytes (buffer));
362 invisible_char = priv->password_char;
364 /* we need to convert the string built of invisible
365 * characters into UTF-8 for it to be fed to the Pango
368 memset (buf, 0, sizeof (buf));
369 char_len = g_unichar_to_utf8 (invisible_char, buf);
371 if (priv->show_password_hint && priv->password_hint_visible)
375 for (i = 0; i < n_chars - 1; i++)
376 g_string_append_len (str, buf, char_len);
378 last_char = g_utf8_offset_to_pointer (text, n_chars - 1);
379 g_string_append (str, last_char);
383 for (i = 0; i < n_chars; i++)
384 g_string_append_len (str, buf, char_len);
387 return g_string_free (str, FALSE);
392 clutter_text_ensure_effective_attributes (ClutterText *self)
394 ClutterTextPrivate *priv = self->priv;
396 /* If we already have the effective attributes then we don't need to
398 if (priv->effective_attrs != NULL)
401 /* same as if we don't have any attribute at all */
402 if (priv->attrs == NULL && priv->markup_attrs == NULL)
405 if (priv->attrs != NULL)
407 /* If there are no markup attributes then we can just use
408 these attributes directly */
409 if (priv->markup_attrs == NULL)
410 priv->effective_attrs = pango_attr_list_ref (priv->attrs);
413 /* Otherwise we need to merge the two lists */
414 PangoAttrIterator *iter;
415 GSList *attributes, *l;
417 priv->effective_attrs = pango_attr_list_copy (priv->markup_attrs);
419 iter = pango_attr_list_get_iterator (priv->attrs);
422 attributes = pango_attr_iterator_get_attrs (iter);
424 for (l = attributes; l != NULL; l = l->next)
426 PangoAttribute *attr = l->data;
428 pango_attr_list_insert (priv->effective_attrs, attr);
431 g_slist_free (attributes);
433 while (pango_attr_iterator_next (iter));
435 pango_attr_iterator_destroy (iter);
438 else if (priv->markup_attrs != NULL)
440 /* We can just use the markup attributes directly */
441 priv->effective_attrs = pango_attr_list_ref (priv->markup_attrs);
446 clutter_text_create_layout_no_cache (ClutterText *text,
449 PangoEllipsizeMode ellipsize)
451 ClutterTextPrivate *priv = text->priv;
456 CLUTTER_STATIC_TIMER (text_layout_timer,
462 CLUTTER_TIMER_START (_clutter_uprof_context, text_layout_timer);
464 layout = clutter_actor_create_pango_layout (CLUTTER_ACTOR (text), NULL);
465 pango_layout_set_font_description (layout, priv->font_desc);
467 contents = clutter_text_get_display_text (text);
468 contents_len = strlen (contents);
470 if (priv->editable && priv->preedit_set)
472 GString *tmp = g_string_new (contents);
473 PangoAttrList *tmp_attrs = pango_attr_list_new ();
476 if (priv->position == 0)
479 cursor_index = offset_to_bytes (contents, priv->position);
481 g_string_insert (tmp, cursor_index, priv->preedit_str);
483 pango_layout_set_text (layout, tmp->str, tmp->len);
485 if (priv->preedit_attrs != NULL)
487 pango_attr_list_splice (tmp_attrs, priv->preedit_attrs,
489 strlen (priv->preedit_str));
491 pango_layout_set_attributes (layout, tmp_attrs);
494 g_string_free (tmp, TRUE);
495 pango_attr_list_unref (tmp_attrs);
498 pango_layout_set_text (layout, contents, contents_len);
502 /* This will merge the markup attributes and the attributes
503 property if needed */
504 clutter_text_ensure_effective_attributes (text);
506 if (priv->effective_attrs != NULL)
507 pango_layout_set_attributes (layout, priv->effective_attrs);
510 pango_layout_set_alignment (layout, priv->alignment);
511 pango_layout_set_single_paragraph_mode (layout, priv->single_line_mode);
512 pango_layout_set_justify (layout, priv->justify);
513 pango_layout_set_wrap (layout, priv->wrap_mode);
515 pango_layout_set_ellipsize (layout, ellipsize);
516 pango_layout_set_width (layout, width);
517 pango_layout_set_height (layout, height);
521 CLUTTER_TIMER_STOP (_clutter_uprof_context, text_layout_timer);
527 clutter_text_dirty_cache (ClutterText *text)
529 ClutterTextPrivate *priv = text->priv;
532 /* Delete the cached layouts so they will be recreated the next time
534 for (i = 0; i < N_CACHED_LAYOUTS; i++)
535 if (priv->cached_layouts[i].layout)
537 g_object_unref (priv->cached_layouts[i].layout);
538 priv->cached_layouts[i].layout = NULL;
541 clutter_text_dirty_paint_volume (text);
545 * clutter_text_set_font_description_internal:
546 * @self: a #ClutterText
547 * @desc: a #PangoFontDescription
549 * Sets @desc as the font description to be used by the #ClutterText
550 * actor. The font description ownership is transferred to @self so
551 * the #PangoFontDescription must not be freed after this function
553 * This function will also set the :font-name field as a side-effect
555 * This function will evict the layout cache, and queue a relayout if
556 * the #ClutterText actor has contents.
559 clutter_text_set_font_description_internal (ClutterText *self,
560 PangoFontDescription *desc)
562 ClutterTextPrivate *priv = self->priv;
564 if (priv->font_desc == desc)
567 if (priv->font_desc != NULL)
568 pango_font_description_free (priv->font_desc);
570 priv->font_desc = desc;
572 /* update the font name string we use */
573 g_free (priv->font_name);
574 priv->font_name = pango_font_description_to_string (priv->font_desc);
576 clutter_text_dirty_cache (self);
578 if (clutter_text_buffer_get_length (get_buffer (self)) != 0)
579 clutter_actor_queue_relayout (CLUTTER_ACTOR (self));
581 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FONT_DESCRIPTION]);
585 clutter_text_settings_changed_cb (ClutterText *text)
587 ClutterTextPrivate *priv = text->priv;
588 guint password_hint_time = 0;
589 ClutterSettings *settings;
591 settings = clutter_settings_get_default ();
593 g_object_get (settings, "password-hint-time", &password_hint_time, NULL);
595 priv->show_password_hint = password_hint_time > 0;
596 priv->password_hint_timeout = password_hint_time;
598 if (priv->is_default_font)
600 PangoFontDescription *font_desc;
601 gchar *font_name = NULL;
603 g_object_get (settings, "font-name", &font_name, NULL);
605 CLUTTER_NOTE (ACTOR, "Text[%p]: default font changed to '%s'",
609 font_desc = pango_font_description_from_string (font_name);
610 clutter_text_set_font_description_internal (text, font_desc);
615 clutter_text_dirty_cache (text);
616 clutter_actor_queue_relayout (CLUTTER_ACTOR (text));
620 clutter_text_direction_changed_cb (GObject *gobject,
623 clutter_text_dirty_cache (CLUTTER_TEXT (gobject));
625 /* no need to queue a relayout: set_text_direction() will do that for us */
629 * clutter_text_create_layout:
630 * @text: a #ClutterText
631 * @allocation_width: the allocation width
632 * @allocation_height: the allocation height
634 * Like clutter_text_create_layout_no_cache(), but will also ensure
635 * the glyphs cache. If a previously cached layout generated using the
636 * same width is available then that will be used instead of
637 * generating a new one.
640 clutter_text_create_layout (ClutterText *text,
641 gfloat allocation_width,
642 gfloat allocation_height)
644 ClutterTextPrivate *priv = text->priv;
645 LayoutCache *oldest_cache = priv->cached_layouts;
646 gboolean found_free_cache = FALSE;
649 PangoEllipsizeMode ellipsize = PANGO_ELLIPSIZE_NONE;
652 CLUTTER_STATIC_COUNTER (text_cache_hit_counter,
653 "Text layout cache hit counter",
654 "Increments for each layout cache hit",
656 CLUTTER_STATIC_COUNTER (text_cache_miss_counter,
657 "Text layout cache miss counter",
658 "Increments for each layout cache miss",
661 /* First determine the width, height, and ellipsize mode that
662 * we need for the layout. The ellipsize mode depends on
663 * allocation_width/allocation_size as follows:
665 * Cases, assuming ellipsize != NONE on actor:
667 * Width request: ellipsization can be set or not on layout,
670 * Height request: ellipsization must never be set on layout
671 * if wrap=true, because we need to measure the wrapped
672 * height. It must always be set if wrap=false.
674 * Allocate: ellipsization must always be set.
676 * See http://bugzilla.gnome.org/show_bug.cgi?id=560931
679 if (priv->ellipsize != PANGO_ELLIPSIZE_NONE)
681 if (allocation_height < 0 && priv->wrap)
682 ; /* must not set ellipsization on wrap=true height request */
686 ellipsize = priv->ellipsize;
690 /* When painting, we always need to set the width, since
691 * we might need to align to the right. When getting the
692 * height, however, there are some cases where we know that
693 * the width won't affect the width.
695 * - editable, single-line text actors, since those can
697 * - non-wrapping, non-ellipsizing actors.
699 if (allocation_width >= 0 &&
700 (allocation_height >= 0 ||
701 !((priv->editable && priv->single_line_mode) ||
702 (priv->ellipsize == PANGO_ELLIPSIZE_NONE && !priv->wrap))))
704 width = allocation_width * 1024 + 0.5f;
707 /* Pango only uses height if ellipsization is enabled, so don't set
708 * height if ellipsize isn't set. Pango implicitly enables wrapping
709 * if height is set, so don't set height if wrapping is disabled.
710 * In other words, only set height if we want to both wrap then
711 * ellipsize and we're not in single line mode.
713 * See http://bugzilla.gnome.org/show_bug.cgi?id=560931 if this
716 if (allocation_height >= 0 &&
718 priv->ellipsize != PANGO_ELLIPSIZE_NONE &&
719 !priv->single_line_mode)
721 height = allocation_height * 1024 + 0.5f;
724 /* Search for a cached layout with the same width and keep
725 * track of the oldest one
727 for (i = 0; i < N_CACHED_LAYOUTS; i++)
729 if (priv->cached_layouts[i].layout == NULL)
731 /* Always prefer free cache spaces */
732 found_free_cache = TRUE;
733 oldest_cache = priv->cached_layouts + i;
737 PangoLayout *cached = priv->cached_layouts[i].layout;
738 gint cached_width = pango_layout_get_width (cached);
739 gint cached_height = pango_layout_get_height (cached);
740 gint cached_ellipsize = pango_layout_get_ellipsize (cached);
742 if (cached_width == width &&
743 cached_height == height &&
744 cached_ellipsize == ellipsize)
746 /* If this cached layout is using the same size then we can
747 * just return that directly
750 "ClutterText: %p: cache hit for size %.2fx%.2f",
755 CLUTTER_COUNTER_INC (_clutter_uprof_context,
756 text_cache_hit_counter);
758 return priv->cached_layouts[i].layout;
761 /* When getting the preferred height for a specific width,
762 * we might be able to reuse the layout from getting the
763 * preferred width. If the width that the layout gives
764 * unconstrained is less than the width that we are using
765 * than the height will be unaffected by that width.
767 if (allocation_height < 0 &&
768 cached_width == -1 &&
769 cached_ellipsize == ellipsize)
771 PangoRectangle logical_rect;
773 pango_layout_get_extents (priv->cached_layouts[i].layout,
777 if (logical_rect.width <= width)
779 /* We've been asked for our height for the width we gave as a result
780 * of a _get_preferred_width call
783 "ClutterText: %p: cache hit for size %.2fx%.2f "
784 "(unwrapped width narrower than given width)",
789 CLUTTER_COUNTER_INC (_clutter_uprof_context,
790 text_cache_hit_counter);
792 return priv->cached_layouts[i].layout;
796 if (!found_free_cache &&
797 (priv->cached_layouts[i].age < oldest_cache->age))
799 oldest_cache = priv->cached_layouts + i;
804 CLUTTER_NOTE (ACTOR, "ClutterText: %p: cache miss for size %.2fx%.2f",
809 CLUTTER_COUNTER_INC (_clutter_uprof_context, text_cache_miss_counter);
811 /* If we make it here then we didn't have a cached version so we
812 need to recreate the layout */
813 if (oldest_cache->layout)
814 g_object_unref (oldest_cache->layout);
816 oldest_cache->layout =
817 clutter_text_create_layout_no_cache (text, width, height, ellipsize);
819 cogl_pango_ensure_glyph_cache_for_layout (oldest_cache->layout);
821 /* Mark the 'time' this cache was created and advance the time */
822 oldest_cache->age = priv->cache_age++;
823 return oldest_cache->layout;
827 * clutter_text_coords_to_position:
828 * @self: a #ClutterText
829 * @x: the X coordinate, relative to the actor
830 * @y: the Y coordinate, relative to the actor
832 * Retrieves the position of the character at the given coordinates.
834 * Return: the position of the character
839 clutter_text_coords_to_position (ClutterText *self,
847 g_return_val_if_fail (CLUTTER_IS_TEXT (self), 0);
849 /* Take any offset due to scrolling into account, and normalize
850 * the coordinates to PangoScale units
852 px = (x - self->priv->text_x) * PANGO_SCALE;
853 py = (y - self->priv->text_y) * PANGO_SCALE;
855 pango_layout_xy_to_index (clutter_text_get_layout (self),
859 return index_ + trailing;
863 * clutter_text_position_to_coords:
864 * @self: a #ClutterText
865 * @position: position in characters
866 * @x: (out): return location for the X coordinate, or %NULL
867 * @y: (out): return location for the Y coordinate, or %NULL
868 * @line_height: (out): return location for the line height, or %NULL
870 * Retrieves the coordinates of the given @position.
872 * Return value: %TRUE if the conversion was successful
877 clutter_text_position_to_coords (ClutterText *self,
883 ClutterTextPrivate *priv;
886 gint password_char_bytes = 1;
890 g_return_val_if_fail (CLUTTER_IS_TEXT (self), FALSE);
894 n_chars = clutter_text_buffer_get_length (get_buffer (self));
895 if (priv->preedit_set)
896 n_chars += priv->preedit_n_chars;
898 if (position < -1 || position > n_chars)
901 if (priv->password_char != 0)
902 password_char_bytes = g_unichar_to_utf8 (priv->password_char, NULL);
906 if (priv->password_char == 0)
908 n_bytes = clutter_text_buffer_get_bytes (get_buffer (self));
909 if (priv->editable && priv->preedit_set)
910 index_ = n_bytes + strlen (priv->preedit_str);
915 index_ = n_chars * password_char_bytes;
917 else if (position == 0)
923 gchar *text = clutter_text_get_display_text (self);
924 GString *tmp = g_string_new (text);
927 cursor_index = offset_to_bytes (text, priv->position);
929 if (priv->preedit_str != NULL)
930 g_string_insert (tmp, cursor_index, priv->preedit_str);
932 if (priv->password_char == 0)
933 index_ = offset_to_bytes (tmp->str, position);
935 index_ = position * password_char_bytes;
938 g_string_free (tmp, TRUE);
941 pango_layout_get_cursor_pos (clutter_text_get_layout (self),
947 *x = (gfloat) rect.x / 1024.0f;
949 /* Take any offset due to scrolling into account */
950 if (priv->single_line_mode)
955 *y = (gfloat) rect.y / 1024.0f;
958 *line_height = (gfloat) rect.height / 1024.0f;
964 clutter_text_ensure_cursor_position (ClutterText *self)
966 ClutterTextPrivate *priv = self->priv;
967 gfloat x, y, cursor_height;
968 ClutterGeometry cursor_pos = { 0, };
969 gboolean x_changed, y_changed;
970 gboolean width_changed, height_changed;
973 position = priv->position;
975 if (priv->editable && priv->preedit_set)
978 position = clutter_text_buffer_get_length (get_buffer (self));
979 position += priv->preedit_cursor_pos;
982 CLUTTER_NOTE (MISC, "Cursor at %d (preedit %s at pos: %d)",
984 priv->preedit_set ? "set" : "unset",
985 priv->preedit_set ? priv->preedit_cursor_pos : 0);
987 x = y = cursor_height = 0;
988 clutter_text_position_to_coords (self, position,
993 cursor_pos.y = y + 2;
994 cursor_pos.width = priv->cursor_size;
995 cursor_pos.height = cursor_height - 4;
997 x_changed = priv->cursor_pos.x != cursor_pos.x;
998 y_changed = priv->cursor_pos.y != cursor_pos.y;
999 width_changed = priv->cursor_pos.width != cursor_pos.width;
1000 height_changed = priv->cursor_pos.height != cursor_pos.height;
1002 if (x_changed || y_changed || width_changed || height_changed)
1004 priv->cursor_pos = cursor_pos;
1006 g_signal_emit (self, text_signals[CURSOR_EVENT], 0, &priv->cursor_pos);
1011 * clutter_text_delete_selection:
1012 * @self: a #ClutterText
1014 * Deletes the currently selected text
1016 * This function is only useful in subclasses of #ClutterText
1018 * Return value: %TRUE if text was deleted or if the text actor
1019 * is empty, and %FALSE otherwise
1024 clutter_text_delete_selection (ClutterText *self)
1026 ClutterTextPrivate *priv;
1029 gint old_position, old_selection;
1032 g_return_val_if_fail (CLUTTER_IS_TEXT (self), FALSE);
1036 n_chars = clutter_text_buffer_get_length (get_buffer (self));
1040 start_index = priv->position == -1 ? n_chars : priv->position;
1041 end_index = priv->selection_bound == -1 ? n_chars : priv->selection_bound;
1043 if (end_index == start_index)
1046 if (end_index < start_index)
1048 gint temp = start_index;
1049 start_index = end_index;
1053 old_position = priv->position;
1054 old_selection = priv->selection_bound;
1056 clutter_text_delete_text (self, start_index, end_index);
1058 priv->position = start_index;
1059 priv->selection_bound = start_index;
1061 /* Not required to be guarded by g_object_freeze/thaw_notify */
1062 if (priv->position != old_position)
1063 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_POSITION]);
1065 if (priv->selection_bound != old_selection)
1066 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_SELECTION_BOUND]);
1072 * Utility function to update both cursor position and selection bound
1076 clutter_text_set_positions (ClutterText *self,
1080 g_object_freeze_notify (G_OBJECT (self));
1081 clutter_text_set_cursor_position (self, new_pos);
1082 clutter_text_set_selection_bound (self, new_bound);
1083 g_object_thaw_notify (G_OBJECT (self));
1087 clutter_text_set_markup_internal (ClutterText *self,
1090 ClutterTextPrivate *priv = self->priv;
1093 PangoAttrList *attrs = NULL;
1096 g_assert (str != NULL);
1099 res = pango_parse_markup (str, -1, 0,
1107 if (G_LIKELY (error != NULL))
1109 g_warning ("Failed to set the markup of the actor '%s': %s",
1110 _clutter_actor_get_debug_name (CLUTTER_ACTOR (self)),
1112 g_error_free (error);
1115 g_warning ("Failed to set the markup of the actor '%s'",
1116 _clutter_actor_get_debug_name (CLUTTER_ACTOR (self)));
1123 clutter_text_buffer_set_text (get_buffer (self), text, -1);
1127 /* Store the new markup attributes */
1128 if (priv->markup_attrs != NULL)
1129 pango_attr_list_unref (priv->markup_attrs);
1131 priv->markup_attrs = attrs;
1133 /* Clear the effective attributes so they will be regenerated when a
1134 layout is created */
1135 if (priv->effective_attrs != NULL)
1137 pango_attr_list_unref (priv->effective_attrs);
1138 priv->effective_attrs = NULL;
1143 clutter_text_set_property (GObject *gobject,
1145 const GValue *value,
1148 ClutterText *self = CLUTTER_TEXT (gobject);
1153 clutter_text_set_buffer (self, g_value_get_object (value));
1158 const char *str = g_value_get_string (value);
1159 if (self->priv->use_markup)
1160 clutter_text_set_markup_internal (self, str ? str : "");
1162 clutter_text_buffer_set_text (get_buffer (self), str ? str : "", -1);
1167 clutter_text_set_color (self, clutter_value_get_color (value));
1170 case PROP_FONT_NAME:
1171 clutter_text_set_font_name (self, g_value_get_string (value));
1174 case PROP_FONT_DESCRIPTION:
1175 clutter_text_set_font_description (self, g_value_get_boxed (value));
1178 case PROP_USE_MARKUP:
1179 clutter_text_set_use_markup (self, g_value_get_boolean (value));
1182 case PROP_ATTRIBUTES:
1183 clutter_text_set_attributes (self, g_value_get_boxed (value));
1186 case PROP_LINE_ALIGNMENT:
1187 clutter_text_set_line_alignment (self, g_value_get_enum (value));
1190 case PROP_LINE_WRAP:
1191 clutter_text_set_line_wrap (self, g_value_get_boolean (value));
1194 case PROP_LINE_WRAP_MODE:
1195 clutter_text_set_line_wrap_mode (self, g_value_get_enum (value));
1199 clutter_text_set_justify (self, g_value_get_boolean (value));
1202 case PROP_ELLIPSIZE:
1203 clutter_text_set_ellipsize (self, g_value_get_enum (value));
1207 clutter_text_set_cursor_position (self, g_value_get_int (value));
1210 case PROP_SELECTION_BOUND:
1211 clutter_text_set_selection_bound (self, g_value_get_int (value));
1214 case PROP_SELECTION_COLOR:
1215 clutter_text_set_selection_color (self, g_value_get_boxed (value));
1218 case PROP_CURSOR_VISIBLE:
1219 clutter_text_set_cursor_visible (self, g_value_get_boolean (value));
1222 case PROP_CURSOR_COLOR:
1223 clutter_text_set_cursor_color (self, g_value_get_boxed (value));
1226 case PROP_CURSOR_SIZE:
1227 clutter_text_set_cursor_size (self, g_value_get_int (value));
1231 clutter_text_set_editable (self, g_value_get_boolean (value));
1234 case PROP_ACTIVATABLE:
1235 clutter_text_set_activatable (self, g_value_get_boolean (value));
1238 case PROP_SELECTABLE:
1239 clutter_text_set_selectable (self, g_value_get_boolean (value));
1242 case PROP_PASSWORD_CHAR:
1243 clutter_text_set_password_char (self, g_value_get_uint (value));
1246 case PROP_MAX_LENGTH:
1247 clutter_text_set_max_length (self, g_value_get_int (value));
1250 case PROP_SINGLE_LINE_MODE:
1251 clutter_text_set_single_line_mode (self, g_value_get_boolean (value));
1254 case PROP_SELECTED_TEXT_COLOR:
1255 clutter_text_set_selected_text_color (self, clutter_value_get_color (value));
1259 G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
1264 clutter_text_get_property (GObject *gobject,
1269 ClutterText *self = CLUTTER_TEXT (gobject);
1270 ClutterTextPrivate *priv = self->priv;
1275 g_value_set_object (value, clutter_text_get_buffer (self));
1279 g_value_set_string (value, clutter_text_buffer_get_text (get_buffer (self)));
1282 case PROP_FONT_NAME:
1283 g_value_set_string (value, priv->font_name);
1286 case PROP_FONT_DESCRIPTION:
1287 g_value_set_boxed (value, priv->font_desc);
1290 case PROP_USE_MARKUP:
1291 g_value_set_boolean (value, priv->use_markup);
1295 clutter_value_set_color (value, &priv->text_color);
1298 case PROP_CURSOR_VISIBLE:
1299 g_value_set_boolean (value, priv->cursor_visible);
1302 case PROP_CURSOR_COLOR:
1303 clutter_value_set_color (value, &priv->cursor_color);
1306 case PROP_CURSOR_COLOR_SET:
1307 g_value_set_boolean (value, priv->cursor_color_set);
1310 case PROP_CURSOR_SIZE:
1311 g_value_set_int (value, priv->cursor_size);
1315 g_value_set_int (value, priv->position);
1318 case PROP_SELECTION_BOUND:
1319 g_value_set_int (value, priv->selection_bound);
1323 g_value_set_boolean (value, priv->editable);
1326 case PROP_SELECTABLE:
1327 g_value_set_boolean (value, priv->selectable);
1330 case PROP_SELECTION_COLOR:
1331 clutter_value_set_color (value, &priv->selection_color);
1334 case PROP_SELECTION_COLOR_SET:
1335 g_value_set_boolean (value, priv->selection_color_set);
1338 case PROP_ACTIVATABLE:
1339 g_value_set_boolean (value, priv->activatable);
1342 case PROP_PASSWORD_CHAR:
1343 g_value_set_uint (value, priv->password_char);
1346 case PROP_MAX_LENGTH:
1347 g_value_set_int (value, clutter_text_buffer_get_max_length (get_buffer (self)));
1350 case PROP_SINGLE_LINE_MODE:
1351 g_value_set_boolean (value, priv->single_line_mode);
1354 case PROP_ELLIPSIZE:
1355 g_value_set_enum (value, priv->ellipsize);
1358 case PROP_LINE_WRAP:
1359 g_value_set_boolean (value, priv->wrap);
1362 case PROP_LINE_WRAP_MODE:
1363 g_value_set_enum (value, priv->wrap_mode);
1366 case PROP_LINE_ALIGNMENT:
1367 g_value_set_enum (value, priv->alignment);
1371 g_value_set_boolean (value, priv->justify);
1374 case PROP_ATTRIBUTES:
1375 g_value_set_boxed (value, priv->attrs);
1378 case PROP_SELECTED_TEXT_COLOR:
1379 clutter_value_set_color (value, &priv->selected_text_color);
1382 case PROP_SELECTED_TEXT_COLOR_SET:
1383 g_value_set_boolean (value, priv->selected_text_color_set);
1387 G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
1392 clutter_text_dispose (GObject *gobject)
1394 ClutterText *self = CLUTTER_TEXT (gobject);
1395 ClutterTextPrivate *priv = self->priv;
1397 /* get rid of the entire cache */
1398 clutter_text_dirty_cache (self);
1400 if (priv->direction_changed_id)
1402 g_signal_handler_disconnect (self, priv->direction_changed_id);
1403 priv->direction_changed_id = 0;
1406 if (priv->settings_changed_id)
1408 g_signal_handler_disconnect (clutter_get_default_backend (),
1409 priv->settings_changed_id);
1410 priv->settings_changed_id = 0;
1413 if (priv->password_hint_id)
1415 g_source_remove (priv->password_hint_id);
1416 priv->password_hint_id = 0;
1419 clutter_text_set_buffer (self, NULL);
1421 G_OBJECT_CLASS (clutter_text_parent_class)->dispose (gobject);
1425 clutter_text_finalize (GObject *gobject)
1427 ClutterText *self = CLUTTER_TEXT (gobject);
1428 ClutterTextPrivate *priv = self->priv;
1430 if (priv->font_desc)
1431 pango_font_description_free (priv->font_desc);
1434 pango_attr_list_unref (priv->attrs);
1435 if (priv->markup_attrs)
1436 pango_attr_list_unref (priv->markup_attrs);
1437 if (priv->effective_attrs)
1438 pango_attr_list_unref (priv->effective_attrs);
1439 if (priv->preedit_attrs)
1440 pango_attr_list_unref (priv->preedit_attrs);
1442 clutter_text_dirty_paint_volume (self);
1444 clutter_text_set_buffer (self, NULL);
1445 g_free (priv->font_name);
1447 G_OBJECT_CLASS (clutter_text_parent_class)->finalize (gobject);
1450 typedef void (* ClutterTextSelectionFunc) (ClutterText *text,
1451 const ClutterActorBox *box,
1452 gpointer user_data);
1455 clutter_text_foreach_selection_rectangle (ClutterText *self,
1456 ClutterTextSelectionFunc func,
1459 ClutterTextPrivate *priv = self->priv;
1460 PangoLayout *layout = clutter_text_get_layout (self);
1461 gchar *utf8 = clutter_text_get_display_text (self);
1467 if (priv->position == 0)
1470 start_index = offset_to_bytes (utf8, priv->position);
1472 if (priv->selection_bound == 0)
1475 end_index = offset_to_bytes (utf8, priv->selection_bound);
1477 if (start_index > end_index)
1479 gint temp = start_index;
1480 start_index = end_index;
1484 lines = pango_layout_get_line_count (layout);
1486 for (line_no = 0; line_no < lines; line_no++)
1488 PangoLayoutLine *line;
1494 ClutterActorBox box;
1497 line = pango_layout_get_line_readonly (layout, line_no);
1498 pango_layout_line_x_to_index (line, G_MAXINT, &maxindex, NULL);
1499 if (maxindex < start_index)
1502 pango_layout_line_get_x_ranges (line, start_index, end_index,
1505 pango_layout_line_x_to_index (line, 0, &index_, NULL);
1507 clutter_text_position_to_coords (self,
1508 bytes_to_offset (utf8, index_),
1512 box.y2 = y + height;
1514 for (i = 0; i < n_ranges; i++)
1519 range_x = ranges[i * 2] / PANGO_SCALE;
1521 /* Account for any scrolling in single line mode */
1522 if (priv->single_line_mode)
1523 range_x += priv->text_x;
1526 range_width = ((gfloat) ranges[i * 2 + 1] - (gfloat) ranges[i * 2])
1530 box.x2 = ceilf (range_x + range_width + .5f);
1532 func (self, &box, user_data);
1542 add_selection_rectangle_to_path (ClutterText *text,
1543 const ClutterActorBox *box,
1546 cogl_path_rectangle (user_data, box->x1, box->y1, box->x2, box->y2);
1549 /* Draws the selected text, its background, and the cursor */
1551 selection_paint (ClutterText *self)
1553 ClutterTextPrivate *priv = self->priv;
1554 ClutterActor *actor = CLUTTER_ACTOR (self);
1555 guint8 paint_opacity = clutter_actor_get_paint_opacity (actor);
1557 if (!priv->has_focus)
1560 if (priv->editable && priv->cursor_visible)
1562 const ClutterColor *color;
1565 position = priv->position;
1567 if (position == priv->selection_bound)
1569 /* No selection, just draw the cursor */
1570 if (priv->cursor_color_set)
1571 color = &priv->cursor_color;
1573 color = &priv->text_color;
1575 cogl_set_source_color4ub (color->red,
1582 cogl_rectangle (priv->cursor_pos.x,
1584 priv->cursor_pos.x + priv->cursor_pos.width,
1585 priv->cursor_pos.y + priv->cursor_pos.height);
1589 /* Paint selection background first */
1590 PangoLayout *layout = clutter_text_get_layout (self);
1591 CoglPath *selection_path = cogl_path_new ();
1592 CoglColor cogl_color = { 0, };
1594 /* Paint selection background */
1595 if (priv->selection_color_set)
1596 color = &priv->selection_color;
1597 else if (priv->cursor_color_set)
1598 color = &priv->cursor_color;
1600 color = &priv->text_color;
1602 cogl_set_source_color4ub (color->red,
1605 paint_opacity * color->alpha / 255);
1607 clutter_text_foreach_selection_rectangle (self,
1608 add_selection_rectangle_to_path,
1611 cogl_path_fill (selection_path);
1613 /* Paint selected text */
1614 cogl_framebuffer_push_path_clip (cogl_get_draw_framebuffer (),
1616 cogl_object_unref (selection_path);
1618 if (priv->selected_text_color_set)
1619 color = &priv->selected_text_color;
1621 color = &priv->text_color;
1623 cogl_color_init_from_4ub (&cogl_color,
1627 paint_opacity * color->alpha / 255);
1629 cogl_pango_render_layout (layout, priv->text_x, 0, &cogl_color, 0);
1637 clutter_text_move_word_backward (ClutterText *self,
1640 gint retval = start;
1642 if (clutter_text_buffer_get_length (get_buffer (self)) > 0 && start > 0)
1644 PangoLayout *layout = clutter_text_get_layout (self);
1645 PangoLogAttr *log_attrs = NULL;
1648 pango_layout_get_log_attrs (layout, &log_attrs, &n_attrs);
1651 while (retval > 0 && !log_attrs[retval].is_word_start)
1661 clutter_text_move_word_forward (ClutterText *self,
1664 gint retval = start;
1667 n_chars = clutter_text_buffer_get_length (get_buffer (self));
1668 if (n_chars > 0 && start < n_chars)
1670 PangoLayout *layout = clutter_text_get_layout (self);
1671 PangoLogAttr *log_attrs = NULL;
1674 pango_layout_get_log_attrs (layout, &log_attrs, &n_attrs);
1677 while (retval < n_chars && !log_attrs[retval].is_word_end)
1687 clutter_text_move_line_start (ClutterText *self,
1690 PangoLayoutLine *layout_line;
1691 PangoLayout *layout;
1697 layout = clutter_text_get_layout (self);
1698 text = clutter_text_buffer_get_text (get_buffer (self));
1703 index_ = offset_to_bytes (text, start);
1705 pango_layout_index_to_line_x (layout, index_,
1709 layout_line = pango_layout_get_line_readonly (layout, line_no);
1713 pango_layout_line_x_to_index (layout_line, 0, &index_, NULL);
1715 position = bytes_to_offset (text, index_);
1721 clutter_text_move_line_end (ClutterText *self,
1724 ClutterTextPrivate *priv = self->priv;
1725 PangoLayoutLine *layout_line;
1726 PangoLayout *layout;
1733 layout = clutter_text_get_layout (self);
1734 text = clutter_text_buffer_get_text (get_buffer (self));
1739 index_ = offset_to_bytes (text, priv->position);
1741 pango_layout_index_to_line_x (layout, index_,
1745 layout_line = pango_layout_get_line_readonly (layout, line_no);
1749 pango_layout_line_x_to_index (layout_line, G_MAXINT, &index_, &trailing);
1752 position = bytes_to_offset (text, index_);
1758 clutter_text_select_word (ClutterText *self)
1760 gint cursor_pos = self->priv->position;
1761 gint start_pos, end_pos;
1763 start_pos = clutter_text_move_word_backward (self, cursor_pos);
1764 end_pos = clutter_text_move_word_forward (self, cursor_pos);
1766 clutter_text_set_selection (self, start_pos, end_pos);
1770 clutter_text_select_line (ClutterText *self)
1772 ClutterTextPrivate *priv = self->priv;
1773 gint cursor_pos = priv->position;
1774 gint start_pos, end_pos;
1776 if (priv->single_line_mode)
1783 start_pos = clutter_text_move_line_start (self, cursor_pos);
1784 end_pos = clutter_text_move_line_end (self, cursor_pos);
1787 clutter_text_set_selection (self, start_pos, end_pos);
1791 clutter_text_button_press (ClutterActor *actor,
1792 ClutterButtonEvent *event)
1794 ClutterText *self = CLUTTER_TEXT (actor);
1795 ClutterTextPrivate *priv = self->priv;
1796 gboolean res = FALSE;
1800 /* we'll steal keyfocus if we need it */
1801 if (priv->editable || priv->selectable)
1802 clutter_actor_grab_key_focus (actor);
1804 return CLUTTER_EVENT_PROPAGATE;
1806 /* if the actor is empty we just reset everything and not
1807 * set up the dragging of the selection since there's nothing
1810 if (clutter_text_buffer_get_length (get_buffer (self)) == 0)
1812 clutter_text_set_positions (self, -1, -1);
1814 return CLUTTER_EVENT_STOP;
1817 res = clutter_actor_transform_stage_point (actor,
1826 index_ = clutter_text_coords_to_position (self, x, y);
1827 text = clutter_text_buffer_get_text (get_buffer (self));
1828 offset = bytes_to_offset (text, index_);
1830 /* what we select depends on the number of button clicks we
1833 * 1: just position the cursor and the selection
1834 * 2: select the current word
1835 * 3: select the contents of the whole actor
1837 if (event->click_count == 1)
1839 clutter_text_set_positions (self, offset, offset);
1841 else if (event->click_count == 2)
1843 clutter_text_select_word (self);
1845 else if (event->click_count == 3)
1847 clutter_text_select_line (self);
1851 /* grab the pointer */
1852 priv->in_select_drag = TRUE;
1853 clutter_grab_pointer (actor);
1855 return CLUTTER_EVENT_STOP;
1859 clutter_text_motion (ClutterActor *actor,
1860 ClutterMotionEvent *mev)
1862 ClutterText *self = CLUTTER_TEXT (actor);
1863 ClutterTextPrivate *priv = self->priv;
1865 gint index_, offset;
1869 if (!priv->in_select_drag)
1870 return CLUTTER_EVENT_PROPAGATE;
1872 res = clutter_actor_transform_stage_point (actor,
1876 return CLUTTER_EVENT_PROPAGATE;
1878 index_ = clutter_text_coords_to_position (self, x, y);
1879 text = clutter_text_buffer_get_text (get_buffer (self));
1880 offset = bytes_to_offset (text, index_);
1882 if (priv->selectable)
1883 clutter_text_set_cursor_position (self, offset);
1885 clutter_text_set_positions (self, offset, offset);
1887 return CLUTTER_EVENT_STOP;
1891 clutter_text_button_release (ClutterActor *actor,
1892 ClutterButtonEvent *bev)
1894 ClutterText *self = CLUTTER_TEXT (actor);
1895 ClutterTextPrivate *priv = self->priv;
1897 if (priv->in_select_drag)
1899 clutter_ungrab_pointer ();
1900 priv->in_select_drag = FALSE;
1902 return CLUTTER_EVENT_STOP;
1905 return CLUTTER_EVENT_PROPAGATE;
1909 clutter_text_remove_password_hint (gpointer data)
1911 ClutterText *self = data;
1913 self->priv->password_hint_visible = FALSE;
1914 self->priv->password_hint_id = 0;
1916 clutter_text_dirty_cache (data);
1917 clutter_text_queue_redraw (data);
1919 return G_SOURCE_REMOVE;
1923 clutter_text_key_press (ClutterActor *actor,
1924 ClutterKeyEvent *event)
1926 ClutterText *self = CLUTTER_TEXT (actor);
1927 ClutterTextPrivate *priv = self->priv;
1928 ClutterBindingPool *pool;
1931 if (!priv->editable)
1932 return CLUTTER_EVENT_PROPAGATE;
1934 /* we need to use the ClutterText type name to find our own
1935 * key bindings; subclasses will override or chain up this
1936 * event handler, so they can do whatever they want there
1938 pool = clutter_binding_pool_find (g_type_name (CLUTTER_TYPE_TEXT));
1939 g_assert (pool != NULL);
1941 /* we allow passing synthetic events that only contain
1942 * the Unicode value and not the key symbol
1944 if (event->keyval == 0 && (event->flags & CLUTTER_EVENT_FLAG_SYNTHETIC))
1947 res = clutter_binding_pool_activate (pool, event->keyval,
1948 event->modifier_state,
1951 /* if the key binding has handled the event we bail out
1952 * as fast as we can; otherwise, we try to insert the
1953 * Unicode character inside the key event into the text
1957 return CLUTTER_EVENT_STOP;
1958 else if ((event->modifier_state & CLUTTER_CONTROL_MASK) == 0)
1960 gunichar key_unichar;
1962 /* Skip keys when control is pressed */
1963 key_unichar = clutter_event_get_key_unicode ((ClutterEvent *) event);
1965 /* return is reported as CR, but we want LF */
1966 if (key_unichar == '\r')
1969 if (key_unichar == '\n' ||
1970 (g_unichar_validate (key_unichar) &&
1971 !g_unichar_iscntrl (key_unichar)))
1973 /* truncate the eventual selection so that the
1974 * Unicode character can replace it
1976 clutter_text_delete_selection (self);
1977 clutter_text_insert_unichar (self, key_unichar);
1979 if (priv->show_password_hint)
1981 if (priv->password_hint_id != 0)
1982 g_source_remove (priv->password_hint_id);
1984 priv->password_hint_visible = TRUE;
1985 priv->password_hint_id =
1986 clutter_threads_add_timeout (priv->password_hint_timeout,
1987 clutter_text_remove_password_hint,
1991 return CLUTTER_EVENT_STOP;
1995 return CLUTTER_EVENT_PROPAGATE;
1998 #define TEXT_PADDING 2
2001 clutter_text_paint (ClutterActor *self)
2003 ClutterText *text = CLUTTER_TEXT (self);
2004 ClutterTextPrivate *priv = text->priv;
2005 PangoLayout *layout;
2006 ClutterActorBox alloc = { 0, };
2007 CoglColor color = { 0, };
2008 guint8 real_opacity;
2009 gint text_x = priv->text_x;
2010 gboolean clip_set = FALSE;
2011 gboolean bg_color_set = FALSE;
2014 /* Note that if anything in this paint method changes it needs to be
2015 reflected in the get_paint_volume implementation which is tightly
2016 tied to the workings of this function */
2018 n_chars = clutter_text_buffer_get_length (get_buffer (text));
2020 /* don't bother painting an empty text actor, unless it's
2021 * editable, in which case we want to paint at least the
2024 if (n_chars == 0 && (!priv->editable || !priv->cursor_visible))
2027 clutter_actor_get_allocation_box (self, &alloc);
2029 g_object_get (self, "background-color-set", &bg_color_set, NULL);
2032 ClutterColor bg_color;
2034 clutter_actor_get_background_color (self, &bg_color);
2035 bg_color.alpha = clutter_actor_get_paint_opacity (self)
2039 cogl_set_source_color4ub (bg_color.red,
2043 cogl_rectangle (0, 0, alloc.x2 - alloc.x1, alloc.y2 - alloc.y1);
2046 if (priv->editable && priv->single_line_mode)
2047 layout = clutter_text_create_layout (text, -1, -1);
2050 /* the only time when we create the PangoLayout using the full
2051 * width and height of the allocation is when we can both wrap
2054 if (priv->wrap && priv->ellipsize)
2056 layout = clutter_text_create_layout (text,
2057 alloc.x2 - alloc.x1,
2058 alloc.y2 - alloc.y1);
2062 /* if we're not wrapping we cannot set the height of the
2063 * layout, otherwise Pango will happily wrap the text to
2064 * fit in the rectangle - thus making the :wrap property
2069 * http://bugzilla.clutter-project.org/show_bug.cgi?id=2339
2071 * in order to fix this, we create a layout that would fit
2072 * in the assigned width, then we clip the actor if the
2073 * logical rectangle overflows the allocation.
2075 layout = clutter_text_create_layout (text,
2076 alloc.x2 - alloc.x1,
2081 if (priv->editable && priv->cursor_visible)
2082 clutter_text_ensure_cursor_position (text);
2084 if (priv->editable && priv->single_line_mode)
2086 PangoRectangle logical_rect = { 0, };
2087 gint actor_width, text_width;
2089 pango_layout_get_extents (layout, NULL, &logical_rect);
2091 cogl_clip_push_rectangle (0, 0,
2092 (alloc.x2 - alloc.x1),
2093 (alloc.y2 - alloc.y1));
2096 actor_width = (alloc.x2 - alloc.x1)
2098 text_width = logical_rect.width / PANGO_SCALE;
2100 if (actor_width < text_width)
2102 gint cursor_x = priv->cursor_pos.x;
2104 if (priv->position == -1)
2106 text_x = actor_width - text_width;
2108 else if (priv->position == 0)
2110 text_x = TEXT_PADDING;
2116 text_x = text_x - cursor_x - TEXT_PADDING;
2118 else if (cursor_x > actor_width)
2120 text_x = text_x + (actor_width - cursor_x) - TEXT_PADDING;
2126 text_x = TEXT_PADDING;
2129 else if (!priv->editable && !(priv->wrap && priv->ellipsize))
2131 PangoRectangle logical_rect = { 0, };
2133 pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
2135 /* don't clip if the layout managed to fit inside our allocation */
2136 if (logical_rect.width > (alloc.x2 - alloc.x1) ||
2137 logical_rect.height > (alloc.y2 - alloc.y1))
2139 cogl_clip_push_rectangle (0, 0,
2140 alloc.x2 - alloc.x1,
2141 alloc.y2 - alloc.y1);
2150 if (priv->text_x != text_x)
2152 priv->text_x = text_x;
2153 clutter_text_ensure_cursor_position (text);
2156 real_opacity = clutter_actor_get_paint_opacity (self)
2157 * priv->text_color.alpha
2160 CLUTTER_NOTE (PAINT, "painting text (text: '%s')",
2161 clutter_text_buffer_get_text (get_buffer (text)));
2163 cogl_color_init_from_4ub (&color,
2164 priv->text_color.red,
2165 priv->text_color.green,
2166 priv->text_color.blue,
2168 cogl_pango_render_layout (layout, text_x, priv->text_y, &color, 0);
2170 selection_paint (text);
2177 add_selection_to_paint_volume (ClutterText *text,
2178 const ClutterActorBox *box,
2181 ClutterPaintVolume *total_volume = user_data;
2182 ClutterPaintVolume rect_volume;
2183 ClutterVertex vertex;
2185 _clutter_paint_volume_init_static (&rect_volume, CLUTTER_ACTOR (text));
2190 clutter_paint_volume_set_origin (&rect_volume, &vertex);
2191 clutter_paint_volume_set_width (&rect_volume, box->x2 - box->x1);
2192 clutter_paint_volume_set_height (&rect_volume, box->y2 - box->y1);
2194 clutter_paint_volume_union (total_volume, &rect_volume);
2196 clutter_paint_volume_free (&rect_volume);
2200 clutter_text_get_paint_volume_for_cursor (ClutterText *text,
2201 ClutterPaintVolume *volume)
2203 ClutterTextPrivate *priv = text->priv;
2204 ClutterVertex origin;
2206 clutter_text_ensure_cursor_position (text);
2208 if (priv->position == priv->selection_bound)
2210 origin.x = priv->cursor_pos.x;
2211 origin.y = priv->cursor_pos.y;
2213 clutter_paint_volume_set_origin (volume, &origin);
2214 clutter_paint_volume_set_width (volume, priv->cursor_pos.width);
2215 clutter_paint_volume_set_height (volume, priv->cursor_pos.height);
2219 clutter_text_foreach_selection_rectangle (text,
2220 add_selection_to_paint_volume,
2226 clutter_text_get_paint_volume (ClutterActor *self,
2227 ClutterPaintVolume *volume)
2229 ClutterText *text = CLUTTER_TEXT (self);
2230 ClutterTextPrivate *priv = text->priv;
2232 /* ClutterText uses the logical layout as the natural size of the
2233 actor. This means that it can sometimes paint outside of its
2234 allocation for example with italic fonts with serifs. Therefore
2235 we should use the ink rectangle of the layout instead */
2237 if (!priv->paint_volume_valid)
2239 PangoLayout *layout;
2240 PangoRectangle ink_rect;
2241 ClutterVertex origin;
2243 /* If the text is single line editable then it gets clipped to
2244 the allocation anyway so we can just use that */
2245 if (priv->editable && priv->single_line_mode)
2246 return _clutter_actor_set_default_paint_volume (self,
2250 if (G_OBJECT_TYPE (self) != CLUTTER_TYPE_TEXT)
2253 if (!clutter_actor_has_allocation (self))
2256 _clutter_paint_volume_init_static (&priv->paint_volume, self);
2258 layout = clutter_text_get_layout (text);
2259 pango_layout_get_extents (layout, &ink_rect, NULL);
2261 origin.x = ink_rect.x / (float) PANGO_SCALE;
2262 origin.y = ink_rect.y / (float) PANGO_SCALE;
2264 clutter_paint_volume_set_origin (&priv->paint_volume, &origin);
2265 clutter_paint_volume_set_width (&priv->paint_volume,
2266 ink_rect.width / (float) PANGO_SCALE);
2267 clutter_paint_volume_set_height (&priv->paint_volume,
2268 ink_rect.height / (float) PANGO_SCALE);
2270 /* If the cursor is visible then that will likely be drawn
2271 outside of the ink rectangle so we should merge that in */
2272 if (priv->editable && priv->cursor_visible && priv->has_focus)
2274 ClutterPaintVolume cursor_paint_volume;
2276 _clutter_paint_volume_init_static (&cursor_paint_volume,
2279 clutter_text_get_paint_volume_for_cursor (text, &cursor_paint_volume);
2281 clutter_paint_volume_union (&priv->paint_volume,
2282 &cursor_paint_volume);
2284 clutter_paint_volume_free (&cursor_paint_volume);
2287 priv->paint_volume_valid = TRUE;
2290 _clutter_paint_volume_copy_static (&priv->paint_volume, volume);
2296 clutter_text_get_preferred_width (ClutterActor *self,
2298 gfloat *min_width_p,
2299 gfloat *natural_width_p)
2301 ClutterText *text = CLUTTER_TEXT (self);
2302 ClutterTextPrivate *priv = text->priv;
2303 PangoRectangle logical_rect = { 0, };
2304 PangoLayout *layout;
2306 gfloat layout_width;
2308 layout = clutter_text_create_layout (text, -1, -1);
2310 pango_layout_get_extents (layout, NULL, &logical_rect);
2312 /* the X coordinate of the logical rectangle might be non-zero
2313 * according to the Pango documentation; hence, we need to offset
2314 * the width accordingly
2316 logical_width = logical_rect.x + logical_rect.width;
2318 layout_width = logical_width > 0
2319 ? ceilf (logical_width / 1024.0f)
2324 if (priv->wrap || priv->ellipsize || priv->editable)
2327 *min_width_p = layout_width;
2330 if (natural_width_p)
2332 if (priv->editable && priv->single_line_mode)
2333 *natural_width_p = layout_width + TEXT_PADDING * 2;
2335 *natural_width_p = layout_width;
2340 clutter_text_get_preferred_height (ClutterActor *self,
2342 gfloat *min_height_p,
2343 gfloat *natural_height_p)
2345 ClutterTextPrivate *priv = CLUTTER_TEXT (self)->priv;
2352 if (natural_height_p)
2353 *natural_height_p = 0;
2357 PangoLayout *layout;
2358 PangoRectangle logical_rect = { 0, };
2359 gint logical_height;
2360 gfloat layout_height;
2362 if (priv->single_line_mode)
2365 layout = clutter_text_create_layout (CLUTTER_TEXT (self),
2368 pango_layout_get_extents (layout, NULL, &logical_rect);
2370 /* the Y coordinate of the logical rectangle might be non-zero
2371 * according to the Pango documentation; hence, we need to offset
2372 * the height accordingly
2374 logical_height = logical_rect.y + logical_rect.height;
2375 layout_height = ceilf (logical_height / 1024.0f);
2379 /* if we wrap and ellipsize then the minimum height is
2380 * going to be at least the size of the first line
2382 if ((priv->ellipsize && priv->wrap) && !priv->single_line_mode)
2384 PangoLayoutLine *line;
2387 line = pango_layout_get_line_readonly (layout, 0);
2388 pango_layout_line_get_extents (line, NULL, &logical_rect);
2390 logical_height = logical_rect.y + logical_rect.height;
2391 line_height = ceilf (logical_height / 1024.0f);
2393 *min_height_p = line_height;
2396 *min_height_p = layout_height;
2399 if (natural_height_p)
2400 *natural_height_p = layout_height;
2405 clutter_text_allocate (ClutterActor *self,
2406 const ClutterActorBox *box,
2407 ClutterAllocationFlags flags)
2409 ClutterText *text = CLUTTER_TEXT (self);
2410 ClutterActorClass *parent_class;
2412 /* Ensure that there is a cached layout with the right width so
2413 * that we don't need to create the text during the paint run
2415 * if the Text is editable and in single line mode we don't want
2416 * to have any limit on the layout size, since the paint will clip
2417 * it to the allocation of the actor
2419 if (text->priv->editable && text->priv->single_line_mode)
2420 clutter_text_create_layout (text, -1, -1);
2422 clutter_text_create_layout (text,
2426 parent_class = CLUTTER_ACTOR_CLASS (clutter_text_parent_class);
2427 parent_class->allocate (self, box, flags);
2431 clutter_text_has_overlaps (ClutterActor *self)
2433 ClutterTextPrivate *priv = CLUTTER_TEXT (self)->priv;
2435 return priv->editable ||
2437 priv->cursor_visible;
2441 clutter_text_key_focus_in (ClutterActor *actor)
2443 ClutterTextPrivate *priv = CLUTTER_TEXT (actor)->priv;
2445 priv->has_focus = TRUE;
2447 clutter_text_queue_redraw (actor);
2451 clutter_text_key_focus_out (ClutterActor *actor)
2453 ClutterTextPrivate *priv = CLUTTER_TEXT (actor)->priv;
2455 priv->has_focus = FALSE;
2457 clutter_text_queue_redraw (actor);
2461 clutter_text_real_move_left (ClutterText *self,
2462 const gchar *action,
2464 ClutterModifierType modifiers)
2466 ClutterTextPrivate *priv = self->priv;
2467 gint pos = priv->position;
2471 len = clutter_text_buffer_get_length (get_buffer (self));
2473 g_object_freeze_notify (G_OBJECT (self));
2475 if (pos != 0 && len != 0)
2477 if (modifiers & CLUTTER_CONTROL_MASK)
2480 new_pos = clutter_text_move_word_backward (self, len);
2482 new_pos = clutter_text_move_word_backward (self, pos);
2492 clutter_text_set_cursor_position (self, new_pos);
2495 if (!(priv->selectable && (modifiers & CLUTTER_SHIFT_MASK)))
2496 clutter_text_clear_selection (self);
2498 g_object_thaw_notify (G_OBJECT (self));
2504 clutter_text_real_move_right (ClutterText *self,
2505 const gchar *action,
2507 ClutterModifierType modifiers)
2509 ClutterTextPrivate *priv = self->priv;
2510 gint pos = priv->position;
2511 gint len = clutter_text_buffer_get_length (get_buffer (self));
2514 g_object_freeze_notify (G_OBJECT (self));
2516 if (pos != -1 && len !=0)
2518 if (modifiers & CLUTTER_CONTROL_MASK)
2521 new_pos = clutter_text_move_word_forward (self, pos);
2529 clutter_text_set_cursor_position (self, new_pos);
2532 if (!(priv->selectable && (modifiers & CLUTTER_SHIFT_MASK)))
2533 clutter_text_clear_selection (self);
2535 g_object_thaw_notify (G_OBJECT (self));
2541 clutter_text_real_move_up (ClutterText *self,
2542 const gchar *action,
2544 ClutterModifierType modifiers)
2546 ClutterTextPrivate *priv = self->priv;
2547 PangoLayoutLine *layout_line;
2548 PangoLayout *layout;
2550 gint index_, trailing;
2555 layout = clutter_text_get_layout (self);
2556 text = clutter_text_buffer_get_text (get_buffer (self));
2558 if (priv->position == 0)
2561 index_ = offset_to_bytes (text, priv->position);
2563 pango_layout_index_to_line_x (layout, index_,
2571 if (priv->x_pos != -1)
2574 layout_line = pango_layout_get_line_readonly (layout, line_no);
2578 pango_layout_line_x_to_index (layout_line, x, &index_, &trailing);
2580 g_object_freeze_notify (G_OBJECT (self));
2582 pos = bytes_to_offset (text, index_);
2583 clutter_text_set_cursor_position (self, pos + trailing);
2585 /* Store the target x position to avoid drifting left and right when
2586 moving the cursor up and down */
2589 if (!(priv->selectable && (modifiers & CLUTTER_SHIFT_MASK)))
2590 clutter_text_clear_selection (self);
2592 g_object_thaw_notify (G_OBJECT (self));
2598 clutter_text_real_move_down (ClutterText *self,
2599 const gchar *action,
2601 ClutterModifierType modifiers)
2603 ClutterTextPrivate *priv = self->priv;
2604 PangoLayoutLine *layout_line;
2605 PangoLayout *layout;
2607 gint index_, trailing;
2612 layout = clutter_text_get_layout (self);
2613 text = clutter_text_buffer_get_text (get_buffer (self));
2615 if (priv->position == 0)
2618 index_ = offset_to_bytes (text, priv->position);
2620 pango_layout_index_to_line_x (layout, index_,
2624 if (priv->x_pos != -1)
2627 layout_line = pango_layout_get_line_readonly (layout, line_no + 1);
2631 pango_layout_line_x_to_index (layout_line, x, &index_, &trailing);
2633 g_object_freeze_notify (G_OBJECT (self));
2635 pos = bytes_to_offset (text, index_);
2636 clutter_text_set_cursor_position (self, pos + trailing);
2638 /* Store the target x position to avoid drifting left and right when
2639 moving the cursor up and down */
2642 if (!(priv->selectable && (modifiers & CLUTTER_SHIFT_MASK)))
2643 clutter_text_clear_selection (self);
2645 g_object_thaw_notify (G_OBJECT (self));
2651 clutter_text_real_line_start (ClutterText *self,
2652 const gchar *action,
2654 ClutterModifierType modifiers)
2656 ClutterTextPrivate *priv = self->priv;
2659 g_object_freeze_notify (G_OBJECT (self));
2661 position = clutter_text_move_line_start (self, priv->position);
2662 clutter_text_set_cursor_position (self, position);
2664 if (!(priv->selectable && (modifiers & CLUTTER_SHIFT_MASK)))
2665 clutter_text_clear_selection (self);
2667 g_object_thaw_notify (G_OBJECT (self));
2673 clutter_text_real_line_end (ClutterText *self,
2674 const gchar *action,
2676 ClutterModifierType modifiers)
2678 ClutterTextPrivate *priv = self->priv;
2681 g_object_freeze_notify (G_OBJECT (self));
2683 position = clutter_text_move_line_end (self, priv->position);
2684 clutter_text_set_cursor_position (self, position);
2686 if (!(priv->selectable && (modifiers & CLUTTER_SHIFT_MASK)))
2687 clutter_text_clear_selection (self);
2689 g_object_thaw_notify (G_OBJECT (self));
2695 clutter_text_real_select_all (ClutterText *self,
2696 const gchar *action,
2698 ClutterModifierType modifiers)
2700 guint n_chars = clutter_text_buffer_get_length (get_buffer (self));
2701 clutter_text_set_positions (self, 0, n_chars);
2707 clutter_text_real_del_next (ClutterText *self,
2708 const gchar *action,
2710 ClutterModifierType modifiers)
2712 ClutterTextPrivate *priv = self->priv;
2716 if (clutter_text_delete_selection (self))
2719 pos = priv->position;
2720 len = clutter_text_buffer_get_length (get_buffer (self));
2722 if (len && pos != -1 && pos < len)
2723 clutter_text_delete_text (self, pos, pos + 1);
2729 clutter_text_real_del_word_next (ClutterText *self,
2730 const gchar *action,
2732 ClutterModifierType modifiers)
2734 ClutterTextPrivate *priv = self->priv;
2738 pos = priv->position;
2739 len = clutter_text_buffer_get_length (get_buffer (self));
2741 if (len && pos != -1 && pos < len)
2745 end = clutter_text_move_word_forward (self, pos);
2746 clutter_text_delete_text (self, pos, end);
2748 if (priv->selection_bound >= end)
2752 new_bound = priv->selection_bound - (end - pos);
2753 clutter_text_set_selection_bound (self, new_bound);
2755 else if (priv->selection_bound > pos)
2757 clutter_text_set_selection_bound (self, pos);
2765 clutter_text_real_del_prev (ClutterText *self,
2766 const gchar *action,
2768 ClutterModifierType modifiers)
2770 ClutterTextPrivate *priv = self->priv;
2774 if (clutter_text_delete_selection (self))
2777 pos = priv->position;
2778 len = clutter_text_buffer_get_length (get_buffer (self));
2780 if (pos != 0 && len != 0)
2784 clutter_text_delete_text (self, len - 1, len);
2786 clutter_text_set_positions (self, -1, -1);
2790 clutter_text_delete_text (self, pos - 1, pos);
2792 clutter_text_set_positions (self, pos - 1, pos - 1);
2800 clutter_text_real_del_word_prev (ClutterText *self,
2801 const gchar *action,
2803 ClutterModifierType modifiers)
2805 ClutterTextPrivate *priv = self->priv;
2809 pos = priv->position;
2810 len = clutter_text_buffer_get_length (get_buffer (self));
2812 if (pos != 0 && len != 0)
2818 new_pos = clutter_text_move_word_backward (self, len);
2819 clutter_text_delete_text (self, new_pos, len);
2821 clutter_text_set_positions (self, -1, -1);
2825 new_pos = clutter_text_move_word_backward (self, pos);
2826 clutter_text_delete_text (self, new_pos, pos);
2828 clutter_text_set_cursor_position (self, new_pos);
2829 if (priv->selection_bound >= pos)
2833 new_bound = priv->selection_bound - (pos - new_pos);
2834 clutter_text_set_selection_bound (self, new_bound);
2836 else if (priv->selection_bound >= new_pos)
2838 clutter_text_set_selection_bound (self, new_pos);
2847 clutter_text_real_activate (ClutterText *self,
2848 const gchar *action,
2850 ClutterModifierType modifiers)
2852 return clutter_text_activate (self);
2856 clutter_text_add_move_binding (ClutterBindingPool *pool,
2857 const gchar *action,
2859 ClutterModifierType additional_modifiers,
2862 clutter_binding_pool_install_action (pool, action,
2867 clutter_binding_pool_install_action (pool, action,
2873 if (additional_modifiers != 0)
2875 clutter_binding_pool_install_action (pool, action,
2877 additional_modifiers,
2880 clutter_binding_pool_install_action (pool, action,
2882 CLUTTER_SHIFT_MASK |
2883 additional_modifiers,
2890 clutter_text_parse_custom_node (ClutterScriptable *scriptable,
2891 ClutterScript *script,
2896 if (strncmp (name, "font-description", 16) == 0)
2898 g_value_init (value, G_TYPE_STRING);
2899 g_value_set_string (value, json_node_get_string (node));
2908 clutter_text_set_custom_property (ClutterScriptable *scriptable,
2909 ClutterScript *script,
2911 const GValue *value)
2913 if (strncmp (name, "font-description", 16) == 0)
2915 g_assert (G_VALUE_HOLDS (value, G_TYPE_STRING));
2916 if (g_value_get_string (value) != NULL)
2917 clutter_text_set_font_name (CLUTTER_TEXT (scriptable),
2918 g_value_get_string (value));
2921 g_object_set_property (G_OBJECT (scriptable), name, value);
2925 clutter_scriptable_iface_init (ClutterScriptableIface *iface)
2927 iface->parse_custom_node = clutter_text_parse_custom_node;
2928 iface->set_custom_property = clutter_text_set_custom_property;
2932 clutter_text_class_init (ClutterTextClass *klass)
2934 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
2935 ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
2936 ClutterBindingPool *binding_pool;
2939 g_type_class_add_private (klass, sizeof (ClutterTextPrivate));
2941 gobject_class->set_property = clutter_text_set_property;
2942 gobject_class->get_property = clutter_text_get_property;
2943 gobject_class->dispose = clutter_text_dispose;
2944 gobject_class->finalize = clutter_text_finalize;
2946 actor_class->paint = clutter_text_paint;
2947 actor_class->get_paint_volume = clutter_text_get_paint_volume;
2948 actor_class->get_preferred_width = clutter_text_get_preferred_width;
2949 actor_class->get_preferred_height = clutter_text_get_preferred_height;
2950 actor_class->allocate = clutter_text_allocate;
2951 actor_class->key_press_event = clutter_text_key_press;
2952 actor_class->button_press_event = clutter_text_button_press;
2953 actor_class->button_release_event = clutter_text_button_release;
2954 actor_class->motion_event = clutter_text_motion;
2955 actor_class->key_focus_in = clutter_text_key_focus_in;
2956 actor_class->key_focus_out = clutter_text_key_focus_out;
2957 actor_class->has_overlaps = clutter_text_has_overlaps;
2960 * ClutterText:buffer:
2962 * The buffer which stores the text for this #ClutterText.
2964 * If set to %NULL, a default buffer will be created.
2968 pspec = g_param_spec_object ("buffer",
2970 P_("The buffer for the text"),
2971 CLUTTER_TYPE_TEXT_BUFFER,
2972 CLUTTER_PARAM_READWRITE);
2973 obj_props[PROP_BUFFER] = pspec;
2974 g_object_class_install_property (gobject_class, PROP_BUFFER, pspec);
2977 * ClutterText:font-name:
2979 * The font to be used by the #ClutterText, as a string
2980 * that can be parsed by pango_font_description_from_string().
2982 * If set to %NULL, the default system font will be used instead.
2986 pspec = g_param_spec_string ("font-name",
2988 P_("The font to be used by the text"),
2990 CLUTTER_PARAM_READWRITE);
2991 obj_props[PROP_FONT_NAME] = pspec;
2992 g_object_class_install_property (gobject_class, PROP_FONT_NAME, pspec);
2995 * ClutterText:font-description:
2997 * The #PangoFontDescription that should be used by the #ClutterText
2999 * If you have a string describing the font then you should look at
3000 * #ClutterText:font-name instead
3004 pspec = g_param_spec_boxed ("font-description",
3005 P_("Font Description"),
3006 P_("The font description to be used"),
3007 PANGO_TYPE_FONT_DESCRIPTION,
3008 CLUTTER_PARAM_READWRITE);
3009 obj_props[PROP_FONT_DESCRIPTION] = pspec;
3010 g_object_class_install_property (gobject_class,
3011 PROP_FONT_DESCRIPTION,
3017 * The text to render inside the actor.
3021 pspec = g_param_spec_string ("text",
3023 P_("The text to render"),
3025 CLUTTER_PARAM_READWRITE);
3026 obj_props[PROP_TEXT] = pspec;
3027 g_object_class_install_property (gobject_class, PROP_TEXT, pspec);
3030 * ClutterText:color:
3032 * The color used to render the text.
3036 pspec = clutter_param_spec_color ("color",
3038 P_("Color of the font used by the text"),
3039 &default_text_color,
3040 CLUTTER_PARAM_READWRITE);
3041 obj_props[PROP_COLOR] = pspec;
3042 g_object_class_install_property (gobject_class, PROP_COLOR, pspec);
3045 * ClutterText:editable:
3047 * Whether key events delivered to the actor causes editing.
3051 pspec = g_param_spec_boolean ("editable",
3053 P_("Whether the text is editable"),
3056 obj_props[PROP_EDITABLE] = pspec;
3057 g_object_class_install_property (gobject_class, PROP_EDITABLE, pspec);
3060 * ClutterText:selectable:
3062 * Whether it is possible to select text, either using the pointer
3067 pspec = g_param_spec_boolean ("selectable",
3069 P_("Whether the text is selectable"),
3072 obj_props[PROP_SELECTABLE] = pspec;
3073 g_object_class_install_property (gobject_class, PROP_SELECTABLE, pspec);
3076 * ClutterText:activatable:
3078 * Toggles whether return invokes the activate signal or not.
3082 pspec = g_param_spec_boolean ("activatable",
3084 P_("Whether pressing return causes the activate signal to be emitted"),
3087 obj_props[PROP_ACTIVATABLE] = pspec;
3088 g_object_class_install_property (gobject_class, PROP_ACTIVATABLE, pspec);
3091 * ClutterText:cursor-visible:
3093 * Whether the input cursor is visible or not, it will only be visible
3094 * if both #ClutterText:cursor-visible and #ClutterText:editable are
3099 pspec = g_param_spec_boolean ("cursor-visible",
3100 P_("Cursor Visible"),
3101 P_("Whether the input cursor is visible"),
3103 CLUTTER_PARAM_READWRITE);
3104 obj_props[PROP_CURSOR_VISIBLE] = pspec;
3105 g_object_class_install_property (gobject_class, PROP_CURSOR_VISIBLE, pspec);
3108 * ClutterText:cursor-color:
3110 * The color of the cursor.
3114 pspec = clutter_param_spec_color ("cursor-color",
3117 &default_cursor_color,
3118 CLUTTER_PARAM_READWRITE);
3119 obj_props[PROP_CURSOR_COLOR] = pspec;
3120 g_object_class_install_property (gobject_class, PROP_CURSOR_COLOR, pspec);
3123 * ClutterText:cursor-color-set:
3125 * Will be set to %TRUE if #ClutterText:cursor-color has been set.
3129 pspec = g_param_spec_boolean ("cursor-color-set",
3130 P_("Cursor Color Set"),
3131 P_("Whether the cursor color has been set"),
3133 CLUTTER_PARAM_READABLE);
3134 obj_props[PROP_CURSOR_COLOR_SET] = pspec;
3135 g_object_class_install_property (gobject_class, PROP_CURSOR_COLOR_SET, pspec);
3138 * ClutterText:cursor-size:
3140 * The size of the cursor, in pixels. If set to -1 the size used will
3141 * be the default cursor size of 2 pixels.
3145 pspec = g_param_spec_int ("cursor-size",
3147 P_("The width of the cursor, in pixels"),
3148 -1, G_MAXINT, DEFAULT_CURSOR_SIZE,
3149 CLUTTER_PARAM_READWRITE);
3150 obj_props[PROP_CURSOR_SIZE] = pspec;
3151 g_object_class_install_property (gobject_class, PROP_CURSOR_SIZE, pspec);
3154 * ClutterText:position:
3156 * The current input cursor position. -1 is taken to be the end of the text
3160 pspec = g_param_spec_int ("position",
3161 P_("Cursor Position"),
3162 P_("The cursor position"),
3165 CLUTTER_PARAM_READWRITE);
3166 obj_props[PROP_POSITION] = pspec;
3167 g_object_class_install_property (gobject_class, PROP_POSITION, pspec);
3170 * ClutterText:selection-bound:
3172 * The current input cursor position. -1 is taken to be the end of the text
3176 pspec = g_param_spec_int ("selection-bound",
3177 P_("Selection-bound"),
3178 P_("The cursor position of the other end of the selection"),
3181 CLUTTER_PARAM_READWRITE);
3182 obj_props[PROP_SELECTION_BOUND] = pspec;
3183 g_object_class_install_property (gobject_class, PROP_SELECTION_BOUND, pspec);
3186 * ClutterText:selection-color:
3188 * The color of the selection.
3192 pspec = clutter_param_spec_color ("selection-color",
3193 P_("Selection Color"),
3194 P_("Selection Color"),
3195 &default_selection_color,
3196 CLUTTER_PARAM_READWRITE);
3197 obj_props[PROP_SELECTION_COLOR] = pspec;
3198 g_object_class_install_property (gobject_class, PROP_SELECTION_COLOR, pspec);
3201 * ClutterText:selection-color-set:
3203 * Will be set to %TRUE if #ClutterText:selection-color has been set.
3207 pspec = g_param_spec_boolean ("selection-color-set",
3208 P_("Selection Color Set"),
3209 P_("Whether the selection color has been set"),
3211 CLUTTER_PARAM_READABLE);
3212 obj_props[PROP_SELECTION_COLOR_SET] = pspec;
3213 g_object_class_install_property (gobject_class, PROP_SELECTION_COLOR_SET, pspec);
3216 * ClutterText:attributes:
3218 * A list of #PangoStyleAttribute<!-- -->s to be applied to the
3219 * contents of the #ClutterText actor.
3223 pspec = g_param_spec_boxed ("attributes",
3225 P_("A list of style attributes to apply to the contents of the actor"),
3226 PANGO_TYPE_ATTR_LIST,
3227 CLUTTER_PARAM_READWRITE);
3228 obj_props[PROP_ATTRIBUTES] = pspec;
3229 g_object_class_install_property (gobject_class, PROP_ATTRIBUTES, pspec);
3232 * ClutterText:use-markup:
3234 * Whether the text includes Pango markup.
3236 * For more informations about the Pango markup format, see
3237 * pango_layout_set_markup() in the Pango documentation.
3239 * <note>It is not possible to round-trip this property between
3240 * %TRUE and %FALSE. Once a string with markup has been set on
3241 * a #ClutterText actor with :use-markup set to %TRUE, the markup
3242 * is stripped from the string.</note>
3246 pspec = g_param_spec_boolean ("use-markup",
3248 P_("Whether or not the text includes Pango markup"),
3250 CLUTTER_PARAM_READWRITE);
3251 obj_props[PROP_USE_MARKUP] = pspec;
3252 g_object_class_install_property (gobject_class, PROP_USE_MARKUP, pspec);
3255 * ClutterText:line-wrap:
3257 * Whether to wrap the lines of #ClutterText:text if the contents
3258 * exceed the available allocation. The wrapping strategy is
3259 * controlled by the #ClutterText:line-wrap-mode property.
3263 pspec = g_param_spec_boolean ("line-wrap",
3265 P_("If set, wrap the lines if the text becomes too wide"),
3267 CLUTTER_PARAM_READWRITE);
3268 obj_props[PROP_LINE_WRAP] = pspec;
3269 g_object_class_install_property (gobject_class, PROP_LINE_WRAP, pspec);
3272 * ClutterText:line-wrap-mode:
3274 * If #ClutterText:line-wrap is set to %TRUE, this property will
3275 * control how the text is wrapped.
3279 pspec = g_param_spec_enum ("line-wrap-mode",
3280 P_("Line wrap mode"),
3281 P_("Control how line-wrapping is done"),
3282 PANGO_TYPE_WRAP_MODE,
3284 CLUTTER_PARAM_READWRITE);
3285 obj_props[PROP_LINE_WRAP_MODE] = pspec;
3286 g_object_class_install_property (gobject_class, PROP_LINE_WRAP_MODE, pspec);
3289 * ClutterText:ellipsize:
3291 * The preferred place to ellipsize the contents of the #ClutterText actor
3295 pspec = g_param_spec_enum ("ellipsize",
3297 P_("The preferred place to ellipsize the string"),
3298 PANGO_TYPE_ELLIPSIZE_MODE,
3299 PANGO_ELLIPSIZE_NONE,
3300 CLUTTER_PARAM_READWRITE);
3301 obj_props[PROP_ELLIPSIZE] = pspec;
3302 g_object_class_install_property (gobject_class, PROP_ELLIPSIZE, pspec);
3305 * ClutterText:line-alignment:
3307 * The preferred alignment for the text. This property controls
3308 * the alignment of multi-line paragraphs.
3312 pspec = g_param_spec_enum ("line-alignment",
3313 P_("Line Alignment"),
3314 P_("The preferred alignment for the string, for multi-line text"),
3315 PANGO_TYPE_ALIGNMENT,
3317 CLUTTER_PARAM_READWRITE);
3318 obj_props[PROP_LINE_ALIGNMENT] = pspec;
3319 g_object_class_install_property (gobject_class, PROP_LINE_ALIGNMENT, pspec);
3322 * ClutterText:justify:
3324 * Whether the contents of the #ClutterText should be justified
3329 pspec = g_param_spec_boolean ("justify",
3331 P_("Whether the text should be justified"),
3333 CLUTTER_PARAM_READWRITE);
3334 obj_props[PROP_JUSTIFY] = pspec;
3335 g_object_class_install_property (gobject_class, PROP_JUSTIFY, pspec);
3338 * ClutterText:password-char:
3340 * If non-zero, the character that should be used in place of
3341 * the actual text in a password text actor.
3345 pspec = g_param_spec_unichar ("password-char",
3346 P_("Password Character"),
3347 P_("If non-zero, use this character to display the actor's contents"),
3349 CLUTTER_PARAM_READWRITE);
3350 obj_props[PROP_PASSWORD_CHAR] = pspec;
3351 g_object_class_install_property (gobject_class, PROP_PASSWORD_CHAR, pspec);
3354 * ClutterText:max-length:
3356 * The maximum length of the contents of the #ClutterText actor.
3360 pspec = g_param_spec_int ("max-length",
3362 P_("Maximum length of the text inside the actor"),
3364 CLUTTER_PARAM_READWRITE);
3365 obj_props[PROP_MAX_LENGTH] = pspec;
3366 g_object_class_install_property (gobject_class, PROP_MAX_LENGTH, pspec);
3369 * ClutterText:single-line-mode:
3371 * Whether the #ClutterText actor should be in single line mode
3372 * or not. A single line #ClutterText actor will only contain a
3373 * single line of text, scrolling it in case its length is bigger
3374 * than the allocated size.
3376 * Setting this property will also set the #ClutterText:activatable
3377 * property as a side-effect.
3379 * The #ClutterText:single-line-mode property is used only if the
3380 * #ClutterText:editable property is set to %TRUE.
3384 pspec = g_param_spec_boolean ("single-line-mode",
3385 P_("Single Line Mode"),
3386 P_("Whether the text should be a single line"),
3388 CLUTTER_PARAM_READWRITE);
3389 obj_props[PROP_SINGLE_LINE_MODE] = pspec;
3390 g_object_class_install_property (gobject_class, PROP_SINGLE_LINE_MODE, pspec);
3393 * ClutterText:selected-text-color:
3395 * The color of selected text.
3399 pspec = clutter_param_spec_color ("selected-text-color",
3400 P_("Selected Text Color"),
3401 P_("Selected Text Color"),
3402 &default_selected_text_color,
3403 CLUTTER_PARAM_READWRITE);
3404 obj_props[PROP_SELECTED_TEXT_COLOR] = pspec;
3405 g_object_class_install_property (gobject_class, PROP_SELECTED_TEXT_COLOR, pspec);
3408 * ClutterText:selected-text-color-set:
3410 * Will be set to %TRUE if #ClutterText:selected-text-color has been set.
3414 pspec = g_param_spec_boolean ("selected-text-color-set",
3415 P_("Selected Text Color Set"),
3416 P_("Whether the selected text color has been set"),
3418 CLUTTER_PARAM_READABLE);
3419 obj_props[PROP_SELECTED_TEXT_COLOR_SET] = pspec;
3420 g_object_class_install_property (gobject_class, PROP_SELECTED_TEXT_COLOR_SET, pspec);
3423 * ClutterText::text-changed:
3424 * @self: the #ClutterText that emitted the signal
3426 * The ::text-changed signal is emitted after @actor's text changes
3430 text_signals[TEXT_CHANGED] =
3431 g_signal_new (I_("text-changed"),
3432 G_TYPE_FROM_CLASS (gobject_class),
3434 G_STRUCT_OFFSET (ClutterTextClass, text_changed),
3436 _clutter_marshal_VOID__VOID,
3440 * ClutterText::insert-text:
3441 * @self: the #ClutterText that emitted the signal
3442 * @new_text: the new text to insert
3443 * @new_text_length: the length of the new text, in bytes, or -1 if
3444 * new_text is nul-terminated
3445 * @position: the position, in characters, at which to insert the
3446 * new text. this is an in-out parameter. After the signal
3447 * emission is finished, it should point after the newly
3450 * This signal is emitted when text is inserted into the actor by
3451 * the user. It is emitted before @self text changes.
3455 text_signals[INSERT_TEXT] =
3456 g_signal_new (I_("insert-text"),
3457 G_TYPE_FROM_CLASS (gobject_class),
3458 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
3461 _clutter_marshal_VOID__STRING_INT_POINTER,
3468 * ClutterText::delete-text:
3469 * @self: the #ClutterText that emitted the signal
3470 * @start_pos: the starting position
3471 * @end_pos: the end position
3473 * This signal is emitted when text is deleted from the actor by
3474 * the user. It is emitted before @self text changes.
3478 text_signals[DELETE_TEXT] =
3479 g_signal_new (I_("delete-text"),
3480 G_TYPE_FROM_CLASS (gobject_class),
3481 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
3484 _clutter_marshal_VOID__INT_INT,
3490 * ClutterText::cursor-event:
3491 * @self: the #ClutterText that emitted the signal
3492 * @geometry: the coordinates of the cursor
3494 * The ::cursor-event signal is emitted whenever the cursor position
3495 * changes inside a #ClutterText actor. Inside @geometry it is stored
3496 * the current position and size of the cursor, relative to the actor
3501 text_signals[CURSOR_EVENT] =
3502 g_signal_new (I_("cursor-event"),
3503 G_TYPE_FROM_CLASS (gobject_class),
3505 G_STRUCT_OFFSET (ClutterTextClass, cursor_event),
3507 _clutter_marshal_VOID__BOXED,
3509 CLUTTER_TYPE_GEOMETRY | G_SIGNAL_TYPE_STATIC_SCOPE);
3512 * ClutterText::activate:
3513 * @self: the #ClutterText that emitted the signal
3515 * The ::activate signal is emitted each time the actor is 'activated'
3516 * by the user, normally by pressing the 'Enter' key. The signal is
3517 * emitted only if #ClutterText:activatable is set to %TRUE.
3521 text_signals[ACTIVATE] =
3522 g_signal_new (I_("activate"),
3523 G_TYPE_FROM_CLASS (gobject_class),
3525 G_STRUCT_OFFSET (ClutterTextClass, activate),
3527 _clutter_marshal_VOID__VOID,
3530 binding_pool = clutter_binding_pool_get_for_class (klass);
3532 clutter_text_add_move_binding (binding_pool, "move-left",
3533 CLUTTER_KEY_Left, CLUTTER_CONTROL_MASK,
3534 G_CALLBACK (clutter_text_real_move_left));
3535 clutter_text_add_move_binding (binding_pool, "move-left",
3536 CLUTTER_KEY_KP_Left, CLUTTER_CONTROL_MASK,
3537 G_CALLBACK (clutter_text_real_move_left));
3538 clutter_text_add_move_binding (binding_pool, "move-right",
3539 CLUTTER_KEY_Right, CLUTTER_CONTROL_MASK,
3540 G_CALLBACK (clutter_text_real_move_right));
3541 clutter_text_add_move_binding (binding_pool, "move-right",
3542 CLUTTER_KEY_KP_Right, CLUTTER_CONTROL_MASK,
3543 G_CALLBACK (clutter_text_real_move_right));
3544 clutter_text_add_move_binding (binding_pool, "move-up",
3546 G_CALLBACK (clutter_text_real_move_up));
3547 clutter_text_add_move_binding (binding_pool, "move-up",
3548 CLUTTER_KEY_KP_Up, 0,
3549 G_CALLBACK (clutter_text_real_move_up));
3550 clutter_text_add_move_binding (binding_pool, "move-down",
3551 CLUTTER_KEY_Down, 0,
3552 G_CALLBACK (clutter_text_real_move_down));
3553 clutter_text_add_move_binding (binding_pool, "move-down",
3554 CLUTTER_KEY_KP_Down, 0,
3555 G_CALLBACK (clutter_text_real_move_down));
3557 clutter_text_add_move_binding (binding_pool, "line-start",
3558 CLUTTER_KEY_Home, 0,
3559 G_CALLBACK (clutter_text_real_line_start));
3560 clutter_text_add_move_binding (binding_pool, "line-start",
3561 CLUTTER_KEY_KP_Home, 0,
3562 G_CALLBACK (clutter_text_real_line_start));
3563 clutter_text_add_move_binding (binding_pool, "line-start",
3564 CLUTTER_KEY_Begin, 0,
3565 G_CALLBACK (clutter_text_real_line_start));
3566 clutter_text_add_move_binding (binding_pool, "line-end",
3568 G_CALLBACK (clutter_text_real_line_end));
3569 clutter_text_add_move_binding (binding_pool, "line-end",
3570 CLUTTER_KEY_KP_End, 0,
3571 G_CALLBACK (clutter_text_real_line_end));
3573 clutter_binding_pool_install_action (binding_pool, "select-all",
3574 CLUTTER_KEY_a, CLUTTER_CONTROL_MASK,
3575 G_CALLBACK (clutter_text_real_select_all),
3578 clutter_binding_pool_install_action (binding_pool, "delete-next",
3579 CLUTTER_KEY_Delete, 0,
3580 G_CALLBACK (clutter_text_real_del_next),
3582 clutter_binding_pool_install_action (binding_pool, "delete-next",
3583 CLUTTER_KEY_Delete, CLUTTER_CONTROL_MASK,
3584 G_CALLBACK (clutter_text_real_del_word_next),
3586 clutter_binding_pool_install_action (binding_pool, "delete-next",
3587 CLUTTER_KEY_KP_Delete, 0,
3588 G_CALLBACK (clutter_text_real_del_next),
3590 clutter_binding_pool_install_action (binding_pool, "delete-next",
3591 CLUTTER_KEY_KP_Delete, CLUTTER_CONTROL_MASK,
3592 G_CALLBACK (clutter_text_real_del_word_next),
3594 clutter_binding_pool_install_action (binding_pool, "delete-prev",
3595 CLUTTER_KEY_BackSpace, 0,
3596 G_CALLBACK (clutter_text_real_del_prev),
3598 clutter_binding_pool_install_action (binding_pool, "delete-prev",
3599 CLUTTER_KEY_BackSpace, CLUTTER_SHIFT_MASK,
3600 G_CALLBACK (clutter_text_real_del_prev),
3602 clutter_binding_pool_install_action (binding_pool, "delete-prev",
3603 CLUTTER_KEY_BackSpace, CLUTTER_CONTROL_MASK,
3604 G_CALLBACK (clutter_text_real_del_word_prev),
3607 clutter_binding_pool_install_action (binding_pool, "activate",
3608 CLUTTER_KEY_Return, 0,
3609 G_CALLBACK (clutter_text_real_activate),
3611 clutter_binding_pool_install_action (binding_pool, "activate",
3612 CLUTTER_KEY_KP_Enter, 0,
3613 G_CALLBACK (clutter_text_real_activate),
3615 clutter_binding_pool_install_action (binding_pool, "activate",
3616 CLUTTER_KEY_ISO_Enter, 0,
3617 G_CALLBACK (clutter_text_real_activate),
3622 clutter_text_init (ClutterText *self)
3624 ClutterSettings *settings;
3625 ClutterTextPrivate *priv;
3627 int i, password_hint_time;
3629 self->priv = priv = CLUTTER_TEXT_GET_PRIVATE (self);
3631 priv->alignment = PANGO_ALIGN_LEFT;
3633 priv->wrap_mode = PANGO_WRAP_WORD;
3634 priv->ellipsize = PANGO_ELLIPSIZE_NONE;
3635 priv->use_underline = FALSE;
3636 priv->use_markup = FALSE;
3637 priv->justify = FALSE;
3639 for (i = 0; i < N_CACHED_LAYOUTS; i++)
3640 priv->cached_layouts[i].layout = NULL;
3642 /* default to "" so that clutter_text_get_text() will
3643 * return a valid string and we can safely call strlen()
3646 priv->buffer = NULL;
3648 priv->text_color = default_text_color;
3649 priv->cursor_color = default_cursor_color;
3650 priv->selection_color = default_selection_color;
3651 priv->selected_text_color = default_selected_text_color;
3653 /* get the default font name from the context; we don't use
3654 * set_font_description() here because we are initializing
3655 * the Text and we don't need notifications and sanity checks
3657 settings = clutter_settings_get_default ();
3658 g_object_get (settings,
3659 "font-name", &font_name,
3660 "password-hint-time", &password_hint_time,
3663 priv->font_name = font_name; /* font_name is allocated */
3664 priv->font_desc = pango_font_description_from_string (font_name);
3665 priv->is_default_font = TRUE;
3667 priv->position = -1;
3668 priv->selection_bound = -1;
3671 priv->cursor_visible = TRUE;
3672 priv->editable = FALSE;
3673 priv->selectable = TRUE;
3675 priv->selection_color_set = FALSE;
3676 priv->cursor_color_set = FALSE;
3677 priv->selected_text_color_set = FALSE;
3678 priv->preedit_set = FALSE;
3680 priv->password_char = 0;
3681 priv->show_password_hint = password_hint_time > 0;
3682 priv->password_hint_timeout = password_hint_time;
3686 priv->cursor_size = DEFAULT_CURSOR_SIZE;
3687 memset (&priv->cursor_pos, 0, sizeof (ClutterGeometry));
3689 priv->settings_changed_id =
3690 g_signal_connect_swapped (clutter_get_default_backend (),
3692 G_CALLBACK (clutter_text_settings_changed_cb),
3695 priv->direction_changed_id =
3696 g_signal_connect (self, "notify::text-direction",
3697 G_CALLBACK (clutter_text_direction_changed_cb),
3704 * Creates a new #ClutterText actor. This actor can be used to
3705 * display and edit text.
3707 * Return value: the newly created #ClutterText actor
3712 clutter_text_new (void)
3714 return g_object_new (CLUTTER_TYPE_TEXT, NULL);
3718 * clutter_text_new_full:
3719 * @font_name: a string with a font description
3720 * @text: the contents of the actor
3721 * @color: the color to be used to render @text
3723 * Creates a new #ClutterText actor, using @font_name as the font
3724 * description; @text will be used to set the contents of the actor;
3725 * and @color will be used as the color to render @text.
3727 * This function is equivalent to calling clutter_text_new(),
3728 * clutter_text_set_font_name(), clutter_text_set_text() and
3729 * clutter_text_set_color().
3731 * Return value: the newly created #ClutterText actor
3736 clutter_text_new_full (const gchar *font_name,
3738 const ClutterColor *color)
3740 return g_object_new (CLUTTER_TYPE_TEXT,
3741 "font-name", font_name,
3748 * clutter_text_new_with_text:
3749 * @font_name: (allow-none): a string with a font description
3750 * @text: the contents of the actor
3752 * Creates a new #ClutterText actor, using @font_name as the font
3753 * description; @text will be used to set the contents of the actor.
3755 * This function is equivalent to calling clutter_text_new(),
3756 * clutter_text_set_font_name(), and clutter_text_set_text().
3758 * Return value: the newly created #ClutterText actor
3763 clutter_text_new_with_text (const gchar *font_name,
3766 return g_object_new (CLUTTER_TYPE_TEXT,
3767 "font-name", font_name,
3772 static ClutterTextBuffer*
3773 get_buffer (ClutterText *self)
3775 ClutterTextPrivate *priv = self->priv;
3777 if (priv->buffer == NULL)
3779 ClutterTextBuffer *buffer;
3780 buffer = clutter_text_buffer_new ();
3781 clutter_text_set_buffer (self, buffer);
3782 g_object_unref (buffer);
3785 return priv->buffer;
3788 /* GtkEntryBuffer signal handlers
3791 buffer_inserted_text (ClutterTextBuffer *buffer,
3797 ClutterTextPrivate *priv;
3799 gint new_selection_bound;
3803 if (priv->position >= 0 || priv->selection_bound >= 0)
3805 new_position = priv->position;
3806 new_selection_bound = priv->selection_bound;
3808 if (position <= new_position)
3809 new_position += n_chars;
3810 if (position <= new_selection_bound)
3811 new_selection_bound += n_chars;
3813 if (priv->position != new_position || priv->selection_bound != new_selection_bound)
3814 clutter_text_set_positions (self, new_position, new_selection_bound);
3817 n_bytes = g_utf8_offset_to_pointer (chars, n_chars) - chars;
3818 g_signal_emit (self, text_signals[INSERT_TEXT], 0, chars,
3819 n_bytes, &position);
3821 /* TODO: What are we supposed to with the out value of position? */
3825 buffer_deleted_text (ClutterTextBuffer *buffer,
3830 ClutterTextPrivate *priv;
3832 gint new_selection_bound;
3835 if (priv->position >= 0 || priv->selection_bound >= 0)
3837 new_position = priv->position;
3838 new_selection_bound = priv->selection_bound;
3840 if (position < new_position)
3841 new_position -= n_chars;
3842 if (position < new_selection_bound)
3843 new_selection_bound -= n_chars;
3845 if (priv->position != new_position || priv->selection_bound != new_selection_bound)
3846 clutter_text_set_positions (self, new_position, new_selection_bound);
3849 g_signal_emit (self, text_signals[DELETE_TEXT], 0, position, position + n_chars);
3853 buffer_notify_text (ClutterTextBuffer *buffer,
3857 g_object_freeze_notify (G_OBJECT (self));
3859 clutter_text_dirty_cache (self);
3861 clutter_actor_queue_relayout (CLUTTER_ACTOR (self));
3863 g_signal_emit (self, text_signals[TEXT_CHANGED], 0);
3864 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_TEXT]);
3866 g_object_thaw_notify (G_OBJECT (self));
3870 buffer_notify_max_length (ClutterTextBuffer *buffer,
3874 g_object_notify (G_OBJECT (self), "max-length");
3878 buffer_connect_signals (ClutterText *self)
3880 ClutterTextPrivate *priv = self->priv;
3881 g_signal_connect (priv->buffer, "inserted-text", G_CALLBACK (buffer_inserted_text), self);
3882 g_signal_connect (priv->buffer, "deleted-text", G_CALLBACK (buffer_deleted_text), self);
3883 g_signal_connect (priv->buffer, "notify::text", G_CALLBACK (buffer_notify_text), self);
3884 g_signal_connect (priv->buffer, "notify::max-length", G_CALLBACK (buffer_notify_max_length), self);
3888 buffer_disconnect_signals (ClutterText *self)
3890 ClutterTextPrivate *priv = self->priv;
3891 g_signal_handlers_disconnect_by_func (priv->buffer, buffer_inserted_text, self);
3892 g_signal_handlers_disconnect_by_func (priv->buffer, buffer_deleted_text, self);
3893 g_signal_handlers_disconnect_by_func (priv->buffer, buffer_notify_text, self);
3894 g_signal_handlers_disconnect_by_func (priv->buffer, buffer_notify_max_length, self);
3898 * clutter_text_new_with_buffer:
3899 * @buffer: The buffer to use for the new #ClutterText.
3901 * Creates a new entry with the specified text buffer.
3903 * Return value: a new #ClutterText
3908 clutter_text_new_with_buffer (ClutterTextBuffer *buffer)
3910 g_return_val_if_fail (CLUTTER_IS_TEXT_BUFFER (buffer), NULL);
3911 return g_object_new (CLUTTER_TYPE_TEXT, "buffer", buffer, NULL);
3915 * clutter_text_get_buffer:
3916 * @self: a #ClutterText
3918 * Get the #ClutterTextBuffer object which holds the text for
3921 * Returns: (transfer none): A #GtkEntryBuffer object.
3926 clutter_text_get_buffer (ClutterText *self)
3928 g_return_val_if_fail (CLUTTER_IS_TEXT (self), NULL);
3930 return get_buffer (self);
3934 * clutter_text_set_buffer:
3935 * @self: a #ClutterText
3936 * @buffer: a #ClutterTextBuffer
3938 * Set the #ClutterTextBuffer object which holds the text for
3944 clutter_text_set_buffer (ClutterText *self,
3945 ClutterTextBuffer *buffer)
3947 ClutterTextPrivate *priv;
3950 g_return_if_fail (CLUTTER_IS_TEXT (self));
3956 g_return_if_fail (CLUTTER_IS_TEXT_BUFFER (buffer));
3957 g_object_ref (buffer);
3962 buffer_disconnect_signals (self);
3963 g_object_unref (priv->buffer);
3966 priv->buffer = buffer;
3969 buffer_connect_signals (self);
3971 obj = G_OBJECT (self);
3972 g_object_freeze_notify (obj);
3973 g_object_notify (obj, "buffer");
3974 g_object_notify (obj, "text");
3975 g_object_notify (obj, "max-length");
3976 g_object_thaw_notify (obj);
3980 * clutter_text_set_editable:
3981 * @self: a #ClutterText
3982 * @editable: whether the #ClutterText should be editable
3984 * Sets whether the #ClutterText actor should be editable.
3986 * An editable #ClutterText with key focus set using
3987 * clutter_actor_grab_key_focus() or clutter_stage_set_key_focus()
3988 * will receive key events and will update its contents accordingly.
3993 clutter_text_set_editable (ClutterText *self,
3996 ClutterTextPrivate *priv;
3998 g_return_if_fail (CLUTTER_IS_TEXT (self));
4002 if (priv->editable != editable)
4004 priv->editable = editable;
4006 clutter_text_queue_redraw (CLUTTER_ACTOR (self));
4008 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EDITABLE]);
4013 * clutter_text_get_editable:
4014 * @self: a #ClutterText
4016 * Retrieves whether a #ClutterText is editable or not.
4018 * Return value: %TRUE if the actor is editable
4023 clutter_text_get_editable (ClutterText *self)
4025 g_return_val_if_fail (CLUTTER_IS_TEXT (self), FALSE);
4027 return self->priv->editable;
4031 * clutter_text_set_selectable:
4032 * @self: a #ClutterText
4033 * @selectable: whether the #ClutterText actor should be selectable
4035 * Sets whether a #ClutterText actor should be selectable.
4037 * A selectable #ClutterText will allow selecting its contents using
4038 * the pointer or the keyboard.
4043 clutter_text_set_selectable (ClutterText *self,
4044 gboolean selectable)
4046 ClutterTextPrivate *priv;
4048 g_return_if_fail (CLUTTER_IS_TEXT (self));
4052 if (priv->selectable != selectable)
4054 priv->selectable = selectable;
4056 clutter_text_queue_redraw (CLUTTER_ACTOR (self));
4058 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_SELECTABLE]);
4063 * clutter_text_get_selectable:
4064 * @self: a #ClutterText
4066 * Retrieves whether a #ClutterText is selectable or not.
4068 * Return value: %TRUE if the actor is selectable
4073 clutter_text_get_selectable (ClutterText *self)
4075 g_return_val_if_fail (CLUTTER_IS_TEXT (self), TRUE);
4077 return self->priv->selectable;
4081 * clutter_text_set_activatable:
4082 * @self: a #ClutterText
4083 * @activatable: whether the #ClutterText actor should be activatable
4085 * Sets whether a #ClutterText actor should be activatable.
4087 * An activatable #ClutterText actor will emit the #ClutterText::activate
4088 * signal whenever the 'Enter' (or 'Return') key is pressed; if it is not
4089 * activatable, a new line will be appended to the current content.
4091 * An activatable #ClutterText must also be set as editable using
4092 * clutter_text_set_editable().
4097 clutter_text_set_activatable (ClutterText *self,
4098 gboolean activatable)
4100 ClutterTextPrivate *priv;
4102 g_return_if_fail (CLUTTER_IS_TEXT (self));
4106 if (priv->activatable != activatable)
4108 priv->activatable = activatable;
4110 clutter_text_queue_redraw (CLUTTER_ACTOR (self));
4112 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIVATABLE]);
4117 * clutter_text_get_activatable:
4118 * @self: a #ClutterText
4120 * Retrieves whether a #ClutterText is activatable or not.
4122 * Return value: %TRUE if the actor is activatable
4127 clutter_text_get_activatable (ClutterText *self)
4129 g_return_val_if_fail (CLUTTER_IS_TEXT (self), TRUE);
4131 return self->priv->activatable;
4135 * clutter_text_activate:
4136 * @self: a #ClutterText
4138 * Emits the #ClutterText::activate signal, if @self has been set
4139 * as activatable using clutter_text_set_activatable().
4141 * This function can be used to emit the ::activate signal inside
4142 * a #ClutterActor::captured-event or #ClutterActor::key-press-event
4143 * signal handlers before the default signal handler for the
4144 * #ClutterText is invoked.
4146 * Return value: %TRUE if the ::activate signal has been emitted,
4147 * and %FALSE otherwise
4152 clutter_text_activate (ClutterText *self)
4154 ClutterTextPrivate *priv;
4156 g_return_val_if_fail (CLUTTER_IS_TEXT (self), FALSE);
4160 if (priv->activatable)
4162 g_signal_emit (self, text_signals[ACTIVATE], 0);
4170 * clutter_text_set_cursor_visible:
4171 * @self: a #ClutterText
4172 * @cursor_visible: whether the cursor should be visible
4174 * Sets whether the cursor of a #ClutterText actor should be
4177 * The color of the cursor will be the same as the text color
4178 * unless clutter_text_set_cursor_color() has been called.
4180 * The size of the cursor can be set using clutter_text_set_cursor_size().
4182 * The position of the cursor can be changed programmatically using
4183 * clutter_text_set_cursor_position().
4188 clutter_text_set_cursor_visible (ClutterText *self,
4189 gboolean cursor_visible)
4191 ClutterTextPrivate *priv;
4193 g_return_if_fail (CLUTTER_IS_TEXT (self));
4197 if (priv->cursor_visible != cursor_visible)
4199 priv->cursor_visible = cursor_visible;
4201 clutter_text_queue_redraw (CLUTTER_ACTOR (self));
4203 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CURSOR_VISIBLE]);
4208 * clutter_text_get_cursor_visible:
4209 * @self: a #ClutterText
4211 * Retrieves whether the cursor of a #ClutterText actor is visible.
4213 * Return value: %TRUE if the cursor is visible
4218 clutter_text_get_cursor_visible (ClutterText *self)
4220 g_return_val_if_fail (CLUTTER_IS_TEXT (self), TRUE);
4222 return self->priv->cursor_visible;
4226 * clutter_text_set_cursor_color:
4227 * @self: a #ClutterText
4228 * @color: the color of the cursor, or %NULL to unset it
4230 * Sets the color of the cursor of a #ClutterText actor.
4232 * If @color is %NULL, the cursor color will be the same as the
4238 clutter_text_set_cursor_color (ClutterText *self,
4239 const ClutterColor *color)
4241 ClutterTextPrivate *priv;
4243 g_return_if_fail (CLUTTER_IS_TEXT (self));
4249 priv->cursor_color = *color;
4250 priv->cursor_color_set = TRUE;
4253 priv->cursor_color_set = FALSE;
4255 clutter_text_queue_redraw (CLUTTER_ACTOR (self));
4257 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CURSOR_COLOR]);
4258 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CURSOR_COLOR_SET]);
4262 * clutter_text_get_cursor_color:
4263 * @self: a #ClutterText
4264 * @color: (out): return location for a #ClutterColor
4266 * Retrieves the color of the cursor of a #ClutterText actor.
4271 clutter_text_get_cursor_color (ClutterText *self,
4272 ClutterColor *color)
4274 ClutterTextPrivate *priv;
4276 g_return_if_fail (CLUTTER_IS_TEXT (self));
4277 g_return_if_fail (color != NULL);
4281 *color = priv->cursor_color;
4285 * clutter_text_set_selection:
4286 * @self: a #ClutterText
4287 * @start_pos: start of the selection, in characters
4288 * @end_pos: end of the selection, in characters
4290 * Selects the region of text between @start_pos and @end_pos.
4292 * This function changes the position of the cursor to match
4293 * @start_pos and the selection bound to match @end_pos.
4298 clutter_text_set_selection (ClutterText *self,
4304 g_return_if_fail (CLUTTER_IS_TEXT (self));
4306 n_chars = clutter_text_buffer_get_length (get_buffer (self));
4310 start_pos = MIN (n_chars, start_pos);
4311 end_pos = MIN (n_chars, end_pos);
4313 clutter_text_set_positions (self, start_pos, end_pos);
4317 * clutter_text_get_selection:
4318 * @self: a #ClutterText
4320 * Retrieves the currently selected text.
4322 * Return value: a newly allocated string containing the currently
4323 * selected text, or %NULL. Use g_free() to free the returned
4329 clutter_text_get_selection (ClutterText *self)
4331 ClutterTextPrivate *priv;
4334 gint start_index, end_index;
4335 gint start_offset, end_offset;
4338 g_return_val_if_fail (CLUTTER_IS_TEXT (self), NULL);
4342 start_index = priv->position;
4343 end_index = priv->selection_bound;
4345 if (end_index == start_index)
4346 return g_strdup ("");
4348 if ((end_index != -1 && end_index < start_index) ||
4351 gint temp = start_index;
4352 start_index = end_index;
4356 text = clutter_text_buffer_get_text (get_buffer (self));
4357 start_offset = offset_to_bytes (text, start_index);
4358 end_offset = offset_to_bytes (text, end_index);
4359 len = end_offset - start_offset;
4361 str = g_malloc (len + 1);
4362 g_utf8_strncpy (str, text + start_offset, end_index - start_index);
4368 * clutter_text_set_selection_bound:
4369 * @self: a #ClutterText
4370 * @selection_bound: the position of the end of the selection, in characters
4372 * Sets the other end of the selection, starting from the current
4375 * If @selection_bound is -1, the selection unset.
4380 clutter_text_set_selection_bound (ClutterText *self,
4381 gint selection_bound)
4383 ClutterTextPrivate *priv;
4385 g_return_if_fail (CLUTTER_IS_TEXT (self));
4389 if (priv->selection_bound != selection_bound)
4391 gint len = clutter_text_buffer_get_length (get_buffer (self));;
4393 if (selection_bound < 0 || selection_bound >= len)
4394 priv->selection_bound = -1;
4396 priv->selection_bound = selection_bound;
4398 clutter_text_queue_redraw (CLUTTER_ACTOR (self));
4400 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_SELECTION_BOUND]);
4405 * clutter_text_get_selection_bound:
4406 * @self: a #ClutterText
4408 * Retrieves the other end of the selection of a #ClutterText actor,
4409 * in characters from the current cursor position.
4411 * Return value: the position of the other end of the selection
4416 clutter_text_get_selection_bound (ClutterText *self)
4418 g_return_val_if_fail (CLUTTER_IS_TEXT (self), -1);
4420 return self->priv->selection_bound;
4424 * clutter_text_set_selection_color:
4425 * @self: a #ClutterText
4426 * @color: the color of the selection, or %NULL to unset it
4428 * Sets the color of the selection of a #ClutterText actor.
4430 * If @color is %NULL, the selection color will be the same as the
4431 * cursor color, or if no cursor color is set either then it will be
4432 * the same as the text color.
4437 clutter_text_set_selection_color (ClutterText *self,
4438 const ClutterColor *color)
4440 ClutterTextPrivate *priv;
4442 g_return_if_fail (CLUTTER_IS_TEXT (self));
4448 priv->selection_color = *color;
4449 priv->selection_color_set = TRUE;
4452 priv->selection_color_set = FALSE;
4454 clutter_text_queue_redraw (CLUTTER_ACTOR (self));
4456 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_SELECTION_COLOR]);
4457 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_SELECTION_COLOR_SET]);
4461 * clutter_text_get_selection_color:
4462 * @self: a #ClutterText
4463 * @color: (out caller-allocates): return location for a #ClutterColor
4465 * Retrieves the color of the selection of a #ClutterText actor.
4470 clutter_text_get_selection_color (ClutterText *self,
4471 ClutterColor *color)
4473 ClutterTextPrivate *priv;
4475 g_return_if_fail (CLUTTER_IS_TEXT (self));
4476 g_return_if_fail (color != NULL);
4480 *color = priv->selection_color;
4484 * clutter_text_set_selected_text_color:
4485 * @self: a #ClutterText
4486 * @color: the selected text color, or %NULL to unset it
4488 * Sets the selected text color of a #ClutterText actor.
4490 * If @color is %NULL, the selected text color will be the same as the
4491 * selection color, which then falls back to cursor, and then text color.
4496 clutter_text_set_selected_text_color (ClutterText *self,
4497 const ClutterColor *color)
4499 ClutterTextPrivate *priv;
4501 g_return_if_fail (CLUTTER_IS_TEXT (self));
4507 priv->selected_text_color = *color;
4508 priv->selected_text_color_set = TRUE;
4511 priv->selected_text_color_set = FALSE;
4513 clutter_text_queue_redraw (CLUTTER_ACTOR (self));
4515 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_SELECTED_TEXT_COLOR]);
4516 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_SELECTED_TEXT_COLOR_SET]);
4520 * clutter_text_get_selected_text_color:
4521 * @self: a #ClutterText
4522 * @color: (out caller-allocates): return location for a #ClutterColor
4524 * Retrieves the color of selected text of a #ClutterText actor.
4529 clutter_text_get_selected_text_color (ClutterText *self,
4530 ClutterColor *color)
4532 ClutterTextPrivate *priv;
4534 g_return_if_fail (CLUTTER_IS_TEXT (self));
4535 g_return_if_fail (color != NULL);
4539 *color = priv->selected_text_color;
4543 * clutter_text_set_font_description:
4544 * @self: a #ClutterText
4545 * @font_desc: a #PangoFontDescription
4547 * Sets @font_desc as the font description for a #ClutterText
4549 * The #PangoFontDescription is copied by the #ClutterText actor
4550 * so you can safely call pango_font_description_free() on it after
4551 * calling this function.
4556 clutter_text_set_font_description (ClutterText *self,
4557 PangoFontDescription *font_desc)
4559 PangoFontDescription *copy;
4561 g_return_if_fail (CLUTTER_IS_TEXT (self));
4563 copy = pango_font_description_copy (font_desc);
4564 clutter_text_set_font_description_internal (self, copy);
4568 * clutter_text_get_font_description:
4569 * @self: a #ClutterText
4571 * Retrieves the #PangoFontDescription used by @self
4573 * Return value: a #PangoFontDescription. The returned value is owned
4574 * by the #ClutterText actor and it should not be modified or freed
4578 PangoFontDescription *
4579 clutter_text_get_font_description (ClutterText *self)
4581 g_return_val_if_fail (CLUTTER_IS_TEXT (self), NULL);
4583 return self->priv->font_desc;
4587 * clutter_text_get_font_name:
4588 * @self: a #ClutterText
4590 * Retrieves the font name as set by clutter_text_set_font_name().
4592 * Return value: a string containing the font name. The returned
4593 * string is owned by the #ClutterText actor and should not be
4599 clutter_text_get_font_name (ClutterText *text)
4601 g_return_val_if_fail (CLUTTER_IS_TEXT (text), NULL);
4603 return text->priv->font_name;
4607 * clutter_text_set_font_name:
4608 * @self: a #ClutterText
4609 * @font_name: (allow-none): a font name, or %NULL to set the default font name
4611 * Sets the font used by a #ClutterText. The @font_name string
4612 * must either be %NULL, which means that the font name from the
4613 * default #ClutterBackend will be used; or be something that can
4614 * be parsed by the pango_font_description_from_string() function,
4618 * clutter_text_set_font_name (text, "Sans 10pt");
4619 * clutter_text_set_font_name (text, "Serif 16px");
4620 * clutter_text_set_font_name (text, "Helvetica 10");
4626 clutter_text_set_font_name (ClutterText *self,
4627 const gchar *font_name)
4629 ClutterTextPrivate *priv;
4630 PangoFontDescription *desc;
4631 gboolean is_default_font;
4633 g_return_if_fail (CLUTTER_IS_TEXT (self));
4635 /* get the default font name from the backend */
4636 if (font_name == NULL || font_name[0] == '\0')
4638 ClutterSettings *settings = clutter_settings_get_default ();
4639 gchar *default_font_name = NULL;
4641 g_object_get (settings, "font-name", &default_font_name, NULL);
4643 if (default_font_name != NULL)
4644 font_name = default_font_name;
4648 default_font_name = g_strdup ("Sans 12");
4651 is_default_font = TRUE;
4654 is_default_font = FALSE;
4658 if (g_strcmp0 (priv->font_name, font_name) == 0)
4661 desc = pango_font_description_from_string (font_name);
4664 g_warning ("Attempting to create a PangoFontDescription for "
4665 "font name '%s', but failed.",
4670 /* this will set the font_name field as well */
4671 clutter_text_set_font_description_internal (self, desc);
4672 priv->is_default_font = is_default_font;
4674 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FONT_NAME]);
4677 if (is_default_font)
4678 g_free ((gchar *) font_name);
4682 * clutter_text_get_text:
4683 * @self: a #ClutterText
4685 * Retrieves a pointer to the current contents of a #ClutterText
4688 * If you need a copy of the contents for manipulating, either
4689 * use g_strdup() on the returned string, or use:
4692 * copy = clutter_text_get_chars (text, 0, -1);
4695 * Which will return a newly allocated string.
4697 * If the #ClutterText actor is empty, this function will return
4698 * an empty string, and not %NULL.
4700 * Return value: (transfer none): the contents of the actor. The returned
4701 * string is owned by the #ClutterText actor and should never be modified
4707 clutter_text_get_text (ClutterText *self)
4709 g_return_val_if_fail (CLUTTER_IS_TEXT (self), NULL);
4711 return clutter_text_buffer_get_text (get_buffer (self));
4715 clutter_text_set_use_markup_internal (ClutterText *self,
4716 gboolean use_markup)
4718 ClutterTextPrivate *priv = self->priv;
4720 if (priv->use_markup != use_markup)
4722 priv->use_markup = use_markup;
4724 /* reset the attributes lists so that they can be
4727 if (priv->effective_attrs != NULL)
4729 pango_attr_list_unref (priv->effective_attrs);
4730 priv->effective_attrs = NULL;
4733 if (priv->markup_attrs)
4735 pango_attr_list_unref (priv->markup_attrs);
4736 priv->markup_attrs = NULL;
4739 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_USE_MARKUP]);
4744 * clutter_text_set_text:
4745 * @self: a #ClutterText
4746 * @text: (allow-none): the text to set. Passing %NULL is the same
4747 * as passing "" (the empty string)
4749 * Sets the contents of a #ClutterText actor.
4751 * If the #ClutterText:use-markup property was set to %TRUE it
4752 * will be reset to %FALSE as a side effect. If you want to
4753 * maintain the #ClutterText:use-markup you should use the
4754 * clutter_text_set_markup() function instead
4759 clutter_text_set_text (ClutterText *self,
4762 g_return_if_fail (CLUTTER_IS_TEXT (self));
4764 /* if the text is editable (i.e. there is not markup flag to reset) then
4765 * changing the contents will result in selection and cursor changes that
4768 if (self->priv->editable)
4770 if (strcmp (clutter_text_buffer_get_text (get_buffer (self)), text) == 0)
4774 clutter_text_set_use_markup_internal (self, FALSE);
4775 clutter_text_buffer_set_text (get_buffer (self), text, -1);
4779 * clutter_text_set_markup:
4780 * @self: a #ClutterText
4781 * @markup: (allow-none): a string containing Pango markup.
4782 * Passing %NULL is the same as passing "" (the empty string)
4784 * Sets @markup as the contents of a #ClutterText.
4786 * This is a convenience function for setting a string containing
4787 * Pango markup, and it is logically equivalent to:
4790 * /* the order is important */
4791 * clutter_text_set_text (CLUTTER_TEXT (actor), markup);
4792 * clutter_text_set_use_markup (CLUTTER_TEXT (actor), TRUE);
4798 clutter_text_set_markup (ClutterText *self,
4799 const gchar *markup)
4801 g_return_if_fail (CLUTTER_IS_TEXT (self));
4803 clutter_text_set_use_markup_internal (self, TRUE);
4804 if (markup != NULL && *markup != '\0')
4805 clutter_text_set_markup_internal (self, markup);
4807 clutter_text_buffer_set_text (get_buffer (self), "", 0);
4811 * clutter_text_get_layout:
4812 * @self: a #ClutterText
4814 * Retrieves the current #PangoLayout used by a #ClutterText actor.
4816 * Return value: (transfer none): a #PangoLayout. The returned object is owned by
4817 * the #ClutterText actor and should not be modified or freed
4822 clutter_text_get_layout (ClutterText *self)
4824 gfloat width, height;
4826 g_return_val_if_fail (CLUTTER_IS_TEXT (self), NULL);
4828 if (self->priv->editable && self->priv->single_line_mode)
4829 return clutter_text_create_layout (self, -1, -1);
4831 clutter_actor_get_size (CLUTTER_ACTOR (self), &width, &height);
4833 return clutter_text_create_layout (self, width, height);
4837 * clutter_text_set_color:
4838 * @self: a #ClutterText
4839 * @color: a #ClutterColor
4841 * Sets the color of the contents of a #ClutterText actor.
4843 * The overall opacity of the #ClutterText actor will be the
4844 * result of the alpha value of @color and the composited
4845 * opacity of the actor itself on the scenegraph, as returned
4846 * by clutter_actor_get_paint_opacity().
4851 clutter_text_set_color (ClutterText *self,
4852 const ClutterColor *color)
4854 ClutterTextPrivate *priv;
4856 g_return_if_fail (CLUTTER_IS_TEXT (self));
4857 g_return_if_fail (color != NULL);
4861 priv->text_color = *color;
4863 clutter_text_queue_redraw (CLUTTER_ACTOR (self));
4865 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_COLOR]);
4869 * clutter_text_get_color:
4870 * @self: a #ClutterText
4871 * @color: (out caller-allocates): return location for a #ClutterColor
4873 * Retrieves the text color as set by clutter_text_set_color().
4878 clutter_text_get_color (ClutterText *self,
4879 ClutterColor *color)
4881 ClutterTextPrivate *priv;
4883 g_return_if_fail (CLUTTER_IS_TEXT (self));
4884 g_return_if_fail (color != NULL);
4888 *color = priv->text_color;
4892 * clutter_text_set_ellipsize:
4893 * @self: a #ClutterText
4894 * @mode: a #PangoEllipsizeMode
4896 * Sets the mode used to ellipsize (add an ellipsis: "...") to the
4897 * text if there is not enough space to render the entire contents
4898 * of a #ClutterText actor
4903 clutter_text_set_ellipsize (ClutterText *self,
4904 PangoEllipsizeMode mode)
4906 ClutterTextPrivate *priv;
4908 g_return_if_fail (CLUTTER_IS_TEXT (self));
4909 g_return_if_fail (mode >= PANGO_ELLIPSIZE_NONE &&
4910 mode <= PANGO_ELLIPSIZE_END);
4914 if ((PangoEllipsizeMode) priv->ellipsize != mode)
4916 priv->ellipsize = mode;
4918 clutter_text_dirty_cache (self);
4920 clutter_actor_queue_relayout (CLUTTER_ACTOR (self));
4922 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ELLIPSIZE]);
4927 * clutter_text_get_ellipsize:
4928 * @self: a #ClutterText
4930 * Returns the ellipsizing position of a #ClutterText actor, as
4931 * set by clutter_text_set_ellipsize().
4933 * Return value: #PangoEllipsizeMode
4938 clutter_text_get_ellipsize (ClutterText *self)
4940 g_return_val_if_fail (CLUTTER_IS_TEXT (self), PANGO_ELLIPSIZE_NONE);
4942 return self->priv->ellipsize;
4946 * clutter_text_get_line_wrap:
4947 * @self: a #ClutterText
4949 * Retrieves the value set using clutter_text_set_line_wrap().
4951 * Return value: %TRUE if the #ClutterText actor should wrap
4957 clutter_text_get_line_wrap (ClutterText *self)
4959 g_return_val_if_fail (CLUTTER_IS_TEXT (self), FALSE);
4961 return self->priv->wrap;
4965 * clutter_text_set_line_wrap:
4966 * @self: a #ClutterText
4967 * @line_wrap: whether the contents should wrap
4969 * Sets whether the contents of a #ClutterText actor should wrap,
4970 * if they don't fit the size assigned to the actor.
4975 clutter_text_set_line_wrap (ClutterText *self,
4978 ClutterTextPrivate *priv;
4980 g_return_if_fail (CLUTTER_IS_TEXT (self));
4984 if (priv->wrap != line_wrap)
4986 priv->wrap = line_wrap;
4988 clutter_text_dirty_cache (self);
4990 clutter_actor_queue_relayout (CLUTTER_ACTOR (self));
4992 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LINE_WRAP]);
4997 * clutter_text_set_line_wrap_mode:
4998 * @self: a #ClutterText
4999 * @wrap_mode: the line wrapping mode
5001 * If line wrapping is enabled (see clutter_text_set_line_wrap()) this
5002 * function controls how the line wrapping is performed. The default is
5003 * %PANGO_WRAP_WORD which means wrap on word boundaries.
5008 clutter_text_set_line_wrap_mode (ClutterText *self,
5009 PangoWrapMode wrap_mode)
5011 ClutterTextPrivate *priv;
5013 g_return_if_fail (CLUTTER_IS_TEXT (self));
5017 if (priv->wrap_mode != wrap_mode)
5019 priv->wrap_mode = wrap_mode;
5021 clutter_text_dirty_cache (self);
5023 clutter_actor_queue_relayout (CLUTTER_ACTOR (self));
5025 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LINE_WRAP_MODE]);
5030 * clutter_text_get_line_wrap_mode:
5031 * @self: a #ClutterText
5033 * Retrieves the line wrap mode used by the #ClutterText actor.
5035 * See clutter_text_set_line_wrap_mode ().
5037 * Return value: the wrap mode used by the #ClutterText
5042 clutter_text_get_line_wrap_mode (ClutterText *self)
5044 g_return_val_if_fail (CLUTTER_IS_TEXT (self), PANGO_WRAP_WORD);
5046 return self->priv->wrap_mode;
5050 * clutter_text_set_attributes:
5051 * @self: a #ClutterText
5052 * @attrs: a #PangoAttrList or %NULL to unset the attributes
5054 * Sets the attributes list that are going to be applied to the
5055 * #ClutterText contents.
5057 * The #ClutterText actor will take a reference on the #PangoAttrList
5058 * passed to this function.
5063 clutter_text_set_attributes (ClutterText *self,
5064 PangoAttrList *attrs)
5066 ClutterTextPrivate *priv;
5068 g_return_if_fail (CLUTTER_IS_TEXT (self));
5073 pango_attr_list_ref (attrs);
5076 pango_attr_list_unref (priv->attrs);
5078 priv->attrs = attrs;
5080 /* Clear the effective attributes so they will be regenerated when a
5081 layout is created */
5082 if (priv->effective_attrs)
5084 pango_attr_list_unref (priv->effective_attrs);
5085 priv->effective_attrs = NULL;
5088 clutter_text_dirty_cache (self);
5090 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ATTRIBUTES]);
5092 clutter_actor_queue_relayout (CLUTTER_ACTOR (self));
5096 * clutter_text_get_attributes:
5097 * @self: a #ClutterText
5099 * Gets the attribute list that was set on the #ClutterText actor
5100 * clutter_text_set_attributes(), if any.
5102 * Return value: (transfer none): the attribute list, or %NULL if none was set. The
5103 * returned value is owned by the #ClutterText and should not be unreferenced.
5108 clutter_text_get_attributes (ClutterText *self)
5110 g_return_val_if_fail (CLUTTER_IS_TEXT (self), NULL);
5112 return self->priv->attrs;
5116 * clutter_text_set_line_alignment:
5117 * @self: a #ClutterText
5118 * @alignment: A #PangoAlignment
5120 * Sets the way that the lines of a wrapped label are aligned with
5121 * respect to each other. This does not affect the overall alignment
5122 * of the label within its allocated or specified width.
5124 * To align a #ClutterText actor you should add it to a container
5125 * that supports alignment, or use the anchor point.
5130 clutter_text_set_line_alignment (ClutterText *self,
5131 PangoAlignment alignment)
5133 ClutterTextPrivate *priv;
5135 g_return_if_fail (CLUTTER_IS_TEXT (self));
5139 if (priv->alignment != alignment)
5141 priv->alignment = alignment;
5143 clutter_text_dirty_cache (self);
5145 clutter_actor_queue_relayout (CLUTTER_ACTOR (self));
5147 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LINE_ALIGNMENT]);
5152 * clutter_text_get_line_alignment:
5153 * @self: a #ClutterText
5155 * Retrieves the alignment of a #ClutterText, as set by
5156 * clutter_text_set_line_alignment().
5158 * Return value: a #PangoAlignment
5163 clutter_text_get_line_alignment (ClutterText *self)
5165 g_return_val_if_fail (CLUTTER_IS_TEXT (self), PANGO_ALIGN_LEFT);
5167 return self->priv->alignment;
5171 * clutter_text_set_use_markup:
5172 * @self: a #ClutterText
5173 * @setting: %TRUE if the text should be parsed for markup.
5175 * Sets whether the contents of the #ClutterText actor contains markup
5176 * in <link linkend="PangoMarkupFormat">Pango's text markup language</link>.
5178 * Setting #ClutterText:use-markup on an editable #ClutterText will
5179 * not have any effect except hiding the markup.
5181 * See also #ClutterText:use-markup.
5186 clutter_text_set_use_markup (ClutterText *self,
5191 g_return_if_fail (CLUTTER_IS_TEXT (self));
5193 text = clutter_text_buffer_get_text (get_buffer (self));
5195 clutter_text_set_use_markup_internal (self, setting);
5198 clutter_text_set_markup_internal (self, text);
5200 clutter_text_dirty_cache (self);
5202 clutter_actor_queue_relayout (CLUTTER_ACTOR (self));
5206 * clutter_text_get_use_markup:
5207 * @self: a #ClutterText
5209 * Retrieves whether the contents of the #ClutterText actor should be
5210 * parsed for the Pango text markup.
5212 * Return value: %TRUE if the contents will be parsed for markup
5217 clutter_text_get_use_markup (ClutterText *self)
5219 g_return_val_if_fail (CLUTTER_IS_TEXT (self), FALSE);
5221 return self->priv->use_markup;
5225 * clutter_text_set_justify:
5226 * @self: a #ClutterText
5227 * @justify: whether the text should be justified
5229 * Sets whether the text of the #ClutterText actor should be justified
5230 * on both margins. This setting is ignored if Clutter is compiled
5231 * against Pango < 1.18.
5236 clutter_text_set_justify (ClutterText *self,
5239 ClutterTextPrivate *priv;
5241 g_return_if_fail (CLUTTER_IS_TEXT (self));
5245 if (priv->justify != justify)
5247 priv->justify = justify;
5249 clutter_text_dirty_cache (self);
5251 clutter_actor_queue_relayout (CLUTTER_ACTOR (self));
5253 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_JUSTIFY]);
5258 * clutter_text_get_justify:
5259 * @self: a #ClutterText
5261 * Retrieves whether the #ClutterText actor should justify its contents
5264 * Return value: %TRUE if the text should be justified
5269 clutter_text_get_justify (ClutterText *self)
5271 g_return_val_if_fail (CLUTTER_IS_TEXT (self), FALSE);
5273 return self->priv->justify;
5277 * clutter_text_get_cursor_position:
5278 * @self: a #ClutterText
5280 * Retrieves the cursor position.
5282 * Return value: the cursor position, in characters
5287 clutter_text_get_cursor_position (ClutterText *self)
5289 g_return_val_if_fail (CLUTTER_IS_TEXT (self), -1);
5291 return self->priv->position;
5295 * clutter_text_set_cursor_position:
5296 * @self: a #ClutterText
5297 * @position: the new cursor position, in characters
5299 * Sets the cursor of a #ClutterText actor at @position.
5301 * The position is expressed in characters, not in bytes.
5306 clutter_text_set_cursor_position (ClutterText *self,
5309 ClutterTextPrivate *priv;
5312 g_return_if_fail (CLUTTER_IS_TEXT (self));
5316 if (priv->position == position)
5319 len = clutter_text_buffer_get_length (get_buffer (self));
5321 if (position < 0 || position >= len)
5322 priv->position = -1;
5324 priv->position = position;
5326 /* Forget the target x position so that it will be recalculated next
5327 time the cursor is moved up or down */
5330 clutter_text_queue_redraw (CLUTTER_ACTOR (self));
5332 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_POSITION]);
5336 * clutter_text_set_cursor_size:
5337 * @self: a #ClutterText
5338 * @size: the size of the cursor, in pixels, or -1 to use the
5341 * Sets the size of the cursor of a #ClutterText. The cursor
5342 * will only be visible if the #ClutterText:cursor-visible property
5348 clutter_text_set_cursor_size (ClutterText *self,
5351 ClutterTextPrivate *priv;
5353 g_return_if_fail (CLUTTER_IS_TEXT (self));
5357 if (priv->cursor_size != size)
5360 size = DEFAULT_CURSOR_SIZE;
5362 priv->cursor_size = size;
5364 clutter_text_queue_redraw (CLUTTER_ACTOR (self));
5366 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CURSOR_SIZE]);
5371 * clutter_text_get_cursor_size:
5372 * @self: a #ClutterText
5374 * Retrieves the size of the cursor of a #ClutterText actor.
5376 * Return value: the size of the cursor, in pixels
5381 clutter_text_get_cursor_size (ClutterText *self)
5383 g_return_val_if_fail (CLUTTER_IS_TEXT (self), DEFAULT_CURSOR_SIZE);
5385 return self->priv->cursor_size;
5389 * clutter_text_set_password_char:
5390 * @self: a #ClutterText
5391 * @wc: a Unicode character, or 0 to unset the password character
5393 * Sets the character to use in place of the actual text in a
5394 * password text actor.
5396 * If @wc is 0 the text will be displayed as it is entered in the
5397 * #ClutterText actor.
5402 clutter_text_set_password_char (ClutterText *self,
5405 ClutterTextPrivate *priv;
5407 g_return_if_fail (CLUTTER_IS_TEXT (self));
5411 if (priv->password_char != wc)
5413 priv->password_char = wc;
5415 clutter_text_dirty_cache (self);
5416 clutter_actor_queue_relayout (CLUTTER_ACTOR (self));
5418 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_PASSWORD_CHAR]);
5423 * clutter_text_get_password_char:
5424 * @self: a #ClutterText
5426 * Retrieves the character to use in place of the actual text
5427 * as set by clutter_text_set_password_char().
5429 * Return value: a Unicode character or 0 if the password
5430 * character is not set
5435 clutter_text_get_password_char (ClutterText *self)
5437 g_return_val_if_fail (CLUTTER_IS_TEXT (self), 0);
5439 return self->priv->password_char;
5443 * clutter_text_set_max_length:
5444 * @self: a #ClutterText
5445 * @max: the maximum number of characters allowed in the text actor; 0
5446 * to disable or -1 to set the length of the current string
5448 * Sets the maximum allowed length of the contents of the actor. If the
5449 * current contents are longer than the given length, then they will be
5455 clutter_text_set_max_length (ClutterText *self,
5458 g_return_if_fail (CLUTTER_IS_TEXT (self));
5459 clutter_text_buffer_set_max_length (get_buffer (self), max);
5463 * clutter_text_get_max_length:
5464 * @self: a #ClutterText
5466 * Gets the maximum length of text that can be set into a text actor.
5468 * See clutter_text_set_max_length().
5470 * Return value: the maximum number of characters.
5475 clutter_text_get_max_length (ClutterText *self)
5477 g_return_val_if_fail (CLUTTER_IS_TEXT (self), 0);
5479 return clutter_text_buffer_get_max_length (get_buffer (self));
5483 * clutter_text_insert_unichar:
5484 * @self: a #ClutterText
5485 * @wc: a Unicode character
5487 * Inserts @wc at the current cursor position of a
5488 * #ClutterText actor.
5493 clutter_text_insert_unichar (ClutterText *self,
5496 ClutterTextPrivate *priv;
5501 new = g_string_new ("");
5502 g_string_append_unichar (new, wc);
5504 clutter_text_buffer_insert_text (get_buffer (self), priv->position, new->str, 1);
5506 g_string_free (new, TRUE);
5510 * clutter_text_insert_text:
5511 * @self: a #ClutterText
5512 * @text: the text to be inserted
5513 * @position: the position of the insertion, or -1
5515 * Inserts @text into a #ClutterActor at the given position.
5517 * If @position is a negative number, the text will be appended
5518 * at the end of the current contents of the #ClutterText.
5520 * The position is expressed in characters, not in bytes.
5525 clutter_text_insert_text (ClutterText *self,
5529 g_return_if_fail (CLUTTER_IS_TEXT (self));
5530 g_return_if_fail (text != NULL);
5532 clutter_text_buffer_insert_text (get_buffer (self), position, text,
5533 g_utf8_strlen (text, -1));
5537 * clutter_text_delete_text:
5538 * @self: a #ClutterText
5539 * @start_pos: starting position
5540 * @end_pos: ending position
5542 * Deletes the text inside a #ClutterText actor between @start_pos
5545 * The starting and ending positions are expressed in characters,
5551 clutter_text_delete_text (ClutterText *self,
5555 g_return_if_fail (CLUTTER_IS_TEXT (self));
5557 clutter_text_buffer_delete_text (get_buffer (self), start_pos, end_pos - start_pos);
5561 * clutter_text_delete_chars:
5562 * @self: a #ClutterText
5563 * @n_chars: the number of characters to delete
5565 * Deletes @n_chars inside a #ClutterText actor, starting from the
5566 * current cursor position.
5568 * Somewhat awkwardly, the cursor position is decremented by the same
5569 * number of characters you've deleted.
5574 clutter_text_delete_chars (ClutterText *self,
5577 ClutterTextPrivate *priv;
5579 g_return_if_fail (CLUTTER_IS_TEXT (self));
5583 clutter_text_buffer_delete_text (get_buffer (self), priv->position, n_chars);
5585 if (priv->position > 0)
5586 clutter_text_set_cursor_position (self, priv->position - n_chars);
5590 * clutter_text_get_chars:
5591 * @self: a #ClutterText
5592 * @start_pos: start of text, in characters
5593 * @end_pos: end of text, in characters
5595 * Retrieves the contents of the #ClutterText actor between
5596 * @start_pos and @end_pos, but not including @end_pos.
5598 * The positions are specified in characters, not in bytes.
5600 * Return value: a newly allocated string with the contents of
5601 * the text actor between the specified positions. Use g_free()
5602 * to free the resources when done
5607 clutter_text_get_chars (ClutterText *self,
5611 gint start_index, end_index;
5615 g_return_val_if_fail (CLUTTER_IS_TEXT (self), NULL);
5617 n_chars = clutter_text_buffer_get_length (get_buffer (self));
5618 text = clutter_text_buffer_get_text (get_buffer (self));
5623 start_pos = MIN (n_chars, start_pos);
5624 end_pos = MIN (n_chars, end_pos);
5626 start_index = g_utf8_offset_to_pointer (text, start_pos) - text;
5627 end_index = g_utf8_offset_to_pointer (text, end_pos) - text;
5629 return g_strndup (text + start_index, end_index - start_index);
5633 * clutter_text_set_single_line_mode:
5634 * @self: a #ClutterText
5635 * @single_line: whether to enable single line mode
5637 * Sets whether a #ClutterText actor should be in single line mode
5638 * or not. Only editable #ClutterText<!-- -->s can be in single line
5641 * A text actor in single line mode will not wrap text and will clip
5642 * the visible area to the predefined size. The contents of the
5643 * text actor will scroll to display the end of the text if its length
5644 * is bigger than the allocated width.
5646 * When setting the single line mode the #ClutterText:activatable
5647 * property is also set as a side effect. Instead of entering a new
5648 * line character, the text actor will emit the #ClutterText::activate
5654 clutter_text_set_single_line_mode (ClutterText *self,
5655 gboolean single_line)
5657 ClutterTextPrivate *priv;
5659 g_return_if_fail (CLUTTER_IS_TEXT (self));
5663 if (priv->single_line_mode != single_line)
5665 g_object_freeze_notify (G_OBJECT (self));
5667 priv->single_line_mode = single_line;
5669 if (priv->single_line_mode)
5671 priv->activatable = TRUE;
5673 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIVATABLE]);
5676 clutter_text_dirty_cache (self);
5677 clutter_actor_queue_relayout (CLUTTER_ACTOR (self));
5679 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_SINGLE_LINE_MODE]);
5681 g_object_thaw_notify (G_OBJECT (self));
5686 * clutter_text_get_single_line_mode:
5687 * @self: a #ClutterText
5689 * Retrieves whether the #ClutterText actor is in single line mode.
5691 * Return value: %TRUE if the #ClutterText actor is in single line mode
5696 clutter_text_get_single_line_mode (ClutterText *self)
5698 g_return_val_if_fail (CLUTTER_IS_TEXT (self), FALSE);
5700 return self->priv->single_line_mode;
5704 * clutter_text_set_preedit_string:
5705 * @self: a #ClutterText
5706 * @preedit_str: (allow-none): the pre-edit string, or %NULL to unset it
5707 * @preedit_attrs: (allow-none): the pre-edit string attributes
5708 * @cursor_pos: the cursor position for the pre-edit string
5710 * Sets, or unsets, the pre-edit string. This function is useful
5711 * for input methods to display a string (with eventual specific
5712 * Pango attributes) before it is entered inside the #ClutterText
5715 * The preedit string and attributes are ignored if the #ClutterText
5716 * actor is not editable.
5718 * This function should not be used by applications
5723 clutter_text_set_preedit_string (ClutterText *self,
5724 const gchar *preedit_str,
5725 PangoAttrList *preedit_attrs,
5728 ClutterTextPrivate *priv;
5730 g_return_if_fail (CLUTTER_IS_TEXT (self));
5734 g_free (priv->preedit_str);
5735 priv->preedit_str = NULL;
5737 if (priv->preedit_attrs != NULL)
5739 pango_attr_list_unref (priv->preedit_attrs);
5740 priv->preedit_attrs = NULL;
5743 priv->preedit_n_chars = 0;
5744 priv->preedit_cursor_pos = 0;
5746 if (preedit_str == NULL || *preedit_str == '\0')
5747 priv->preedit_set = FALSE;
5750 priv->preedit_str = g_strdup (preedit_str);
5752 if (priv->preedit_str != NULL)
5753 priv->preedit_n_chars = g_utf8_strlen (priv->preedit_str, -1);
5755 priv->preedit_n_chars = 0;
5757 if (preedit_attrs != NULL)
5758 priv->preedit_attrs = pango_attr_list_ref (preedit_attrs);
5760 priv->preedit_cursor_pos =
5761 CLAMP (cursor_pos, 0, priv->preedit_n_chars);
5763 priv->preedit_set = TRUE;
5766 clutter_text_dirty_cache (self);
5767 clutter_actor_queue_relayout (CLUTTER_ACTOR (self));
5772 * clutter_text_get_layout_offsets:
5773 * @self: a #ClutterText
5774 * @x: (out): location to store X offset of layout, or %NULL
5775 * @y: (out): location to store Y offset of layout, or %NULL
5777 * Obtains the coordinates where the #ClutterText will draw the #PangoLayout
5778 * representing the text.
5783 clutter_text_get_layout_offsets (ClutterText *self,
5787 ClutterTextPrivate *priv;
5789 g_return_if_fail (CLUTTER_IS_TEXT (self));