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-animatable.h"
52 #include "clutter-binding-pool.h"
53 #include "clutter-color.h"
54 #include "clutter-debug.h"
55 #include "clutter-enum-types.h"
56 #include "clutter-keysyms.h"
57 #include "clutter-main.h"
58 #include "clutter-marshal.h"
59 #include "clutter-private.h" /* includes <cogl-pango/cogl-pango.h> */
60 #include "clutter-profile.h"
61 #include "clutter-property-transition.h"
62 #include "clutter-text-buffer.h"
63 #include "clutter-units.h"
64 #include "clutter-paint-volume-private.h"
65 #include "clutter-scriptable.h"
67 /* cursor width in pixels */
68 #define DEFAULT_CURSOR_SIZE 2
70 /* We need at least three cached layouts to run the allocation without
71 * regenerating a new layout. First the layout will be generated at
72 * full width to get the preferred width, then it will be generated at
73 * the preferred width to get the preferred height and then it might
74 * be regenerated at a different width to get the height for the
75 * actual allocated width
77 * since we might get multiple queries from layout managers doing a
78 * double-pass allocations, like tabular ones, we should use 6 slots
80 #define N_CACHED_LAYOUTS 6
82 #define CLUTTER_TEXT_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), CLUTTER_TYPE_TEXT, ClutterTextPrivate))
84 typedef struct _LayoutCache LayoutCache;
86 static const ClutterColor default_cursor_color = { 0, 0, 0, 255 };
87 static const ClutterColor default_selection_color = { 0, 0, 0, 255 };
88 static const ClutterColor default_text_color = { 0, 0, 0, 255 };
89 static const ClutterColor default_selected_text_color = { 0, 0, 0, 255 };
91 static ClutterAnimatableIface *parent_animatable_iface = NULL;
93 static void clutter_scriptable_iface_init (ClutterScriptableIface *iface);
94 static void clutter_animatable_iface_init (ClutterAnimatableIface *iface);
96 G_DEFINE_TYPE_WITH_CODE (ClutterText,
99 G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_SCRIPTABLE,
100 clutter_scriptable_iface_init)
101 G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_ANIMATABLE,
102 clutter_animatable_iface_init));
106 /* Cached layout. Pango internally caches the computed extents
107 * when they are requested so there is no need to cache that as
112 /* A number representing the age of this cache (so that when a
113 * new layout is needed the last used cache is replaced)
118 struct _ClutterTextPrivate
120 PangoFontDescription *font_desc;
122 /* the displayed text */
123 ClutterTextBuffer *buffer;
129 ClutterColor text_color;
131 LayoutCache cached_layouts[N_CACHED_LAYOUTS];
134 /* These are the attributes set by the attributes property */
135 PangoAttrList *attrs;
136 /* These are the attributes derived from the text when the
137 use-markup property is set */
138 PangoAttrList *markup_attrs;
139 /* This is the combination of the above two lists. It is set to NULL
140 whenever either of them changes and then regenerated by merging
141 the two lists whenever a layout is needed */
142 PangoAttrList *effective_attrs;
143 /* These are the attributes for the preedit string. These are merged
144 with the effective attributes into a temporary list before
146 PangoAttrList *preedit_attrs;
148 /* current cursor position */
151 /* current 'other end of selection' position */
152 gint selection_bound;
154 /* the x position in the PangoLayout, used to
155 * avoid drifting when repeatedly moving up|down
159 /* the x position of the PangoLayout when in
160 * single line mode, to scroll the contents of the
165 /* the y position of the PangoLayout, fixed to 0 by
169 /* Where to draw the cursor */
170 ClutterGeometry cursor_pos;
171 ClutterColor cursor_color;
174 /* Box representing the paint volume. The box is lazily calculated
176 ClutterPaintVolume paint_volume;
178 guint preedit_cursor_pos;
179 gint preedit_n_chars;
181 ClutterColor selection_color;
183 ClutterColor selected_text_color;
185 gunichar password_char;
187 guint password_hint_id;
188 guint password_hint_timeout;
190 /* Signal handler for when the backend changes its font settings */
191 guint settings_changed_id;
193 /* Signal handler for when the :text-direction changes */
194 guint direction_changed_id;
199 guint use_underline : 1;
200 guint use_markup : 1;
202 guint single_line_mode : 1;
206 guint cursor_visible : 1;
207 guint activatable : 1;
208 guint selectable : 1;
209 guint selection_color_set : 1;
210 guint in_select_drag : 1;
211 guint cursor_color_set : 1;
212 guint preedit_set : 1;
213 guint is_default_font : 1;
215 guint selected_text_color_set : 1;
216 guint paint_volume_valid : 1;
217 guint show_password_hint : 1;
218 guint password_hint_visible : 1;
227 PROP_FONT_DESCRIPTION,
238 PROP_SELECTION_BOUND,
239 PROP_SELECTION_COLOR,
240 PROP_SELECTION_COLOR_SET,
243 PROP_CURSOR_COLOR_SET,
250 PROP_SINGLE_LINE_MODE,
251 PROP_SELECTED_TEXT_COLOR,
252 PROP_SELECTED_TEXT_COLOR_SET,
257 static GParamSpec *obj_props[PROP_LAST];
270 static guint text_signals[LAST_SIGNAL] = { 0, };
272 static void clutter_text_settings_changed_cb (ClutterText *text);
273 static void buffer_connect_signals (ClutterText *self);
274 static void buffer_disconnect_signals (ClutterText *self);
275 static ClutterTextBuffer *get_buffer (ClutterText *self);
278 clutter_text_dirty_paint_volume (ClutterText *text)
280 ClutterTextPrivate *priv = text->priv;
282 if (priv->paint_volume_valid)
284 clutter_paint_volume_free (&priv->paint_volume);
285 priv->paint_volume_valid = FALSE;
290 clutter_text_queue_redraw (ClutterActor *self)
292 /* This is a wrapper for clutter_actor_queue_redraw that also
293 dirties the cached paint volume. It would be nice if we could
294 just override the default implementation of the queue redraw
295 signal to do this instead but that doesn't work because the
296 signal isn't immediately emitted when queue_redraw is called.
297 Clutter will however immediately call get_paint_volume when
298 queue_redraw is called so we do need to dirty it immediately. */
300 clutter_text_dirty_paint_volume (CLUTTER_TEXT (self));
302 clutter_actor_queue_redraw (self);
305 #define clutter_actor_queue_redraw \
306 Please_use_clutter_text_queue_redraw_instead
308 #define offset_real(t,p) ((p) == -1 ? g_utf8_strlen ((t), -1) : (p))
311 offset_to_bytes (const gchar *text,
317 return strlen (text);
319 /* Loop over each character in the string until we either reach the
320 end or the requested position */
321 for (ptr = text; *ptr && pos-- > 0; ptr = g_utf8_next_char (ptr));
326 #define bytes_to_offset(t,p) (g_utf8_pointer_to_offset ((t), (t) + (p)))
329 clutter_text_clear_selection (ClutterText *self)
331 ClutterTextPrivate *priv = self->priv;
333 if (priv->selection_bound != priv->position)
335 priv->selection_bound = priv->position;
336 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_SELECTION_BOUND]);
337 clutter_text_queue_redraw (CLUTTER_ACTOR (self));
342 clutter_text_get_display_text (ClutterText *self)
344 ClutterTextPrivate *priv = self->priv;
345 ClutterTextBuffer *buffer;
348 buffer = get_buffer (self);
349 text = clutter_text_buffer_get_text (buffer);
351 /* simple short-circuit to avoid going through GString
352 * with an empty text and a password char set
355 return g_strdup ("");
357 if (G_LIKELY (priv->password_char == 0))
358 return g_strdup (text);
362 gunichar invisible_char;
367 n_chars = clutter_text_buffer_get_length (buffer);
368 str = g_string_sized_new (clutter_text_buffer_get_bytes (buffer));
369 invisible_char = priv->password_char;
371 /* we need to convert the string built of invisible
372 * characters into UTF-8 for it to be fed to the Pango
375 memset (buf, 0, sizeof (buf));
376 char_len = g_unichar_to_utf8 (invisible_char, buf);
378 if (priv->show_password_hint && priv->password_hint_visible)
382 for (i = 0; i < n_chars - 1; i++)
383 g_string_append_len (str, buf, char_len);
385 last_char = g_utf8_offset_to_pointer (text, n_chars - 1);
386 g_string_append (str, last_char);
390 for (i = 0; i < n_chars; i++)
391 g_string_append_len (str, buf, char_len);
394 return g_string_free (str, FALSE);
399 clutter_text_ensure_effective_attributes (ClutterText *self)
401 ClutterTextPrivate *priv = self->priv;
403 /* If we already have the effective attributes then we don't need to
405 if (priv->effective_attrs != NULL)
408 /* same as if we don't have any attribute at all */
409 if (priv->attrs == NULL && priv->markup_attrs == NULL)
412 if (priv->attrs != NULL)
414 /* If there are no markup attributes then we can just use
415 these attributes directly */
416 if (priv->markup_attrs == NULL)
417 priv->effective_attrs = pango_attr_list_ref (priv->attrs);
420 /* Otherwise we need to merge the two lists */
421 PangoAttrIterator *iter;
422 GSList *attributes, *l;
424 priv->effective_attrs = pango_attr_list_copy (priv->markup_attrs);
426 iter = pango_attr_list_get_iterator (priv->attrs);
429 attributes = pango_attr_iterator_get_attrs (iter);
431 for (l = attributes; l != NULL; l = l->next)
433 PangoAttribute *attr = l->data;
435 pango_attr_list_insert (priv->effective_attrs, attr);
438 g_slist_free (attributes);
440 while (pango_attr_iterator_next (iter));
442 pango_attr_iterator_destroy (iter);
445 else if (priv->markup_attrs != NULL)
447 /* We can just use the markup attributes directly */
448 priv->effective_attrs = pango_attr_list_ref (priv->markup_attrs);
453 clutter_text_create_layout_no_cache (ClutterText *text,
456 PangoEllipsizeMode ellipsize)
458 ClutterTextPrivate *priv = text->priv;
463 CLUTTER_STATIC_TIMER (text_layout_timer,
469 CLUTTER_TIMER_START (_clutter_uprof_context, text_layout_timer);
471 layout = clutter_actor_create_pango_layout (CLUTTER_ACTOR (text), NULL);
472 pango_layout_set_font_description (layout, priv->font_desc);
474 contents = clutter_text_get_display_text (text);
475 contents_len = strlen (contents);
477 if (priv->editable && priv->preedit_set)
479 GString *tmp = g_string_new (contents);
480 PangoAttrList *tmp_attrs = pango_attr_list_new ();
483 if (priv->position == 0)
486 cursor_index = offset_to_bytes (contents, priv->position);
488 g_string_insert (tmp, cursor_index, priv->preedit_str);
490 pango_layout_set_text (layout, tmp->str, tmp->len);
492 if (priv->preedit_attrs != NULL)
494 pango_attr_list_splice (tmp_attrs, priv->preedit_attrs,
496 strlen (priv->preedit_str));
498 pango_layout_set_attributes (layout, tmp_attrs);
501 g_string_free (tmp, TRUE);
502 pango_attr_list_unref (tmp_attrs);
505 pango_layout_set_text (layout, contents, contents_len);
509 /* This will merge the markup attributes and the attributes
510 property if needed */
511 clutter_text_ensure_effective_attributes (text);
513 if (priv->effective_attrs != NULL)
514 pango_layout_set_attributes (layout, priv->effective_attrs);
517 pango_layout_set_alignment (layout, priv->alignment);
518 pango_layout_set_single_paragraph_mode (layout, priv->single_line_mode);
519 pango_layout_set_justify (layout, priv->justify);
520 pango_layout_set_wrap (layout, priv->wrap_mode);
522 pango_layout_set_ellipsize (layout, ellipsize);
523 pango_layout_set_width (layout, width);
524 pango_layout_set_height (layout, height);
528 CLUTTER_TIMER_STOP (_clutter_uprof_context, text_layout_timer);
534 clutter_text_dirty_cache (ClutterText *text)
536 ClutterTextPrivate *priv = text->priv;
539 /* Delete the cached layouts so they will be recreated the next time
541 for (i = 0; i < N_CACHED_LAYOUTS; i++)
542 if (priv->cached_layouts[i].layout)
544 g_object_unref (priv->cached_layouts[i].layout);
545 priv->cached_layouts[i].layout = NULL;
548 clutter_text_dirty_paint_volume (text);
552 * clutter_text_set_font_description_internal:
553 * @self: a #ClutterText
554 * @desc: a #PangoFontDescription
556 * Sets @desc as the font description to be used by the #ClutterText
557 * actor. The font description ownership is transferred to @self so
558 * the #PangoFontDescription must not be freed after this function
560 * This function will also set the :font-name field as a side-effect
562 * This function will evict the layout cache, and queue a relayout if
563 * the #ClutterText actor has contents.
566 clutter_text_set_font_description_internal (ClutterText *self,
567 PangoFontDescription *desc)
569 ClutterTextPrivate *priv = self->priv;
571 if (priv->font_desc == desc)
574 if (priv->font_desc != NULL)
575 pango_font_description_free (priv->font_desc);
577 priv->font_desc = desc;
579 /* update the font name string we use */
580 g_free (priv->font_name);
581 priv->font_name = pango_font_description_to_string (priv->font_desc);
583 clutter_text_dirty_cache (self);
585 if (clutter_text_buffer_get_length (get_buffer (self)) != 0)
586 clutter_actor_queue_relayout (CLUTTER_ACTOR (self));
588 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FONT_DESCRIPTION]);
592 clutter_text_settings_changed_cb (ClutterText *text)
594 ClutterTextPrivate *priv = text->priv;
595 guint password_hint_time = 0;
596 ClutterSettings *settings;
598 settings = clutter_settings_get_default ();
600 g_object_get (settings, "password-hint-time", &password_hint_time, NULL);
602 priv->show_password_hint = password_hint_time > 0;
603 priv->password_hint_timeout = password_hint_time;
605 if (priv->is_default_font)
607 PangoFontDescription *font_desc;
608 gchar *font_name = NULL;
610 g_object_get (settings, "font-name", &font_name, NULL);
612 CLUTTER_NOTE (ACTOR, "Text[%p]: default font changed to '%s'",
616 font_desc = pango_font_description_from_string (font_name);
617 clutter_text_set_font_description_internal (text, font_desc);
622 clutter_text_dirty_cache (text);
623 clutter_actor_queue_relayout (CLUTTER_ACTOR (text));
627 clutter_text_direction_changed_cb (GObject *gobject,
630 clutter_text_dirty_cache (CLUTTER_TEXT (gobject));
632 /* no need to queue a relayout: set_text_direction() will do that for us */
636 * clutter_text_create_layout:
637 * @text: a #ClutterText
638 * @allocation_width: the allocation width
639 * @allocation_height: the allocation height
641 * Like clutter_text_create_layout_no_cache(), but will also ensure
642 * the glyphs cache. If a previously cached layout generated using the
643 * same width is available then that will be used instead of
644 * generating a new one.
647 clutter_text_create_layout (ClutterText *text,
648 gfloat allocation_width,
649 gfloat allocation_height)
651 ClutterTextPrivate *priv = text->priv;
652 LayoutCache *oldest_cache = priv->cached_layouts;
653 gboolean found_free_cache = FALSE;
656 PangoEllipsizeMode ellipsize = PANGO_ELLIPSIZE_NONE;
659 CLUTTER_STATIC_COUNTER (text_cache_hit_counter,
660 "Text layout cache hit counter",
661 "Increments for each layout cache hit",
663 CLUTTER_STATIC_COUNTER (text_cache_miss_counter,
664 "Text layout cache miss counter",
665 "Increments for each layout cache miss",
668 /* First determine the width, height, and ellipsize mode that
669 * we need for the layout. The ellipsize mode depends on
670 * allocation_width/allocation_size as follows:
672 * Cases, assuming ellipsize != NONE on actor:
674 * Width request: ellipsization can be set or not on layout,
677 * Height request: ellipsization must never be set on layout
678 * if wrap=true, because we need to measure the wrapped
679 * height. It must always be set if wrap=false.
681 * Allocate: ellipsization must always be set.
683 * See http://bugzilla.gnome.org/show_bug.cgi?id=560931
686 if (priv->ellipsize != PANGO_ELLIPSIZE_NONE)
688 if (allocation_height < 0 && priv->wrap)
689 ; /* must not set ellipsization on wrap=true height request */
693 ellipsize = priv->ellipsize;
697 /* When painting, we always need to set the width, since
698 * we might need to align to the right. When getting the
699 * height, however, there are some cases where we know that
700 * the width won't affect the width.
702 * - editable, single-line text actors, since those can
704 * - non-wrapping, non-ellipsizing actors.
706 if (allocation_width >= 0 &&
707 (allocation_height >= 0 ||
708 !((priv->editable && priv->single_line_mode) ||
709 (priv->ellipsize == PANGO_ELLIPSIZE_NONE && !priv->wrap))))
711 width = allocation_width * 1024 + 0.5f;
714 /* Pango only uses height if ellipsization is enabled, so don't set
715 * height if ellipsize isn't set. Pango implicitly enables wrapping
716 * if height is set, so don't set height if wrapping is disabled.
717 * In other words, only set height if we want to both wrap then
718 * ellipsize and we're not in single line mode.
720 * See http://bugzilla.gnome.org/show_bug.cgi?id=560931 if this
723 if (allocation_height >= 0 &&
725 priv->ellipsize != PANGO_ELLIPSIZE_NONE &&
726 !priv->single_line_mode)
728 height = allocation_height * 1024 + 0.5f;
731 /* Search for a cached layout with the same width and keep
732 * track of the oldest one
734 for (i = 0; i < N_CACHED_LAYOUTS; i++)
736 if (priv->cached_layouts[i].layout == NULL)
738 /* Always prefer free cache spaces */
739 found_free_cache = TRUE;
740 oldest_cache = priv->cached_layouts + i;
744 PangoLayout *cached = priv->cached_layouts[i].layout;
745 gint cached_width = pango_layout_get_width (cached);
746 gint cached_height = pango_layout_get_height (cached);
747 gint cached_ellipsize = pango_layout_get_ellipsize (cached);
749 if (cached_width == width &&
750 cached_height == height &&
751 cached_ellipsize == ellipsize)
753 /* If this cached layout is using the same size then we can
754 * just return that directly
757 "ClutterText: %p: cache hit for size %.2fx%.2f",
762 CLUTTER_COUNTER_INC (_clutter_uprof_context,
763 text_cache_hit_counter);
765 return priv->cached_layouts[i].layout;
768 /* When getting the preferred height for a specific width,
769 * we might be able to reuse the layout from getting the
770 * preferred width. If the width that the layout gives
771 * unconstrained is less than the width that we are using
772 * than the height will be unaffected by that width.
774 if (allocation_height < 0 &&
775 cached_width == -1 &&
776 cached_ellipsize == ellipsize)
778 PangoRectangle logical_rect;
780 pango_layout_get_extents (priv->cached_layouts[i].layout,
784 if (logical_rect.width <= width)
786 /* We've been asked for our height for the width we gave as a result
787 * of a _get_preferred_width call
790 "ClutterText: %p: cache hit for size %.2fx%.2f "
791 "(unwrapped width narrower than given width)",
796 CLUTTER_COUNTER_INC (_clutter_uprof_context,
797 text_cache_hit_counter);
799 return priv->cached_layouts[i].layout;
803 if (!found_free_cache &&
804 (priv->cached_layouts[i].age < oldest_cache->age))
806 oldest_cache = priv->cached_layouts + i;
811 CLUTTER_NOTE (ACTOR, "ClutterText: %p: cache miss for size %.2fx%.2f",
816 CLUTTER_COUNTER_INC (_clutter_uprof_context, text_cache_miss_counter);
818 /* If we make it here then we didn't have a cached version so we
819 need to recreate the layout */
820 if (oldest_cache->layout)
821 g_object_unref (oldest_cache->layout);
823 oldest_cache->layout =
824 clutter_text_create_layout_no_cache (text, width, height, ellipsize);
826 cogl_pango_ensure_glyph_cache_for_layout (oldest_cache->layout);
828 /* Mark the 'time' this cache was created and advance the time */
829 oldest_cache->age = priv->cache_age++;
830 return oldest_cache->layout;
834 * clutter_text_coords_to_position:
835 * @self: a #ClutterText
836 * @x: the X coordinate, relative to the actor
837 * @y: the Y coordinate, relative to the actor
839 * Retrieves the position of the character at the given coordinates.
841 * Return: the position of the character
846 clutter_text_coords_to_position (ClutterText *self,
854 g_return_val_if_fail (CLUTTER_IS_TEXT (self), 0);
856 /* Take any offset due to scrolling into account, and normalize
857 * the coordinates to PangoScale units
859 px = (x - self->priv->text_x) * PANGO_SCALE;
860 py = (y - self->priv->text_y) * PANGO_SCALE;
862 pango_layout_xy_to_index (clutter_text_get_layout (self),
866 return index_ + trailing;
870 * clutter_text_position_to_coords:
871 * @self: a #ClutterText
872 * @position: position in characters
873 * @x: (out): return location for the X coordinate, or %NULL
874 * @y: (out): return location for the Y coordinate, or %NULL
875 * @line_height: (out): return location for the line height, or %NULL
877 * Retrieves the coordinates of the given @position.
879 * Return value: %TRUE if the conversion was successful
884 clutter_text_position_to_coords (ClutterText *self,
890 ClutterTextPrivate *priv;
893 gint password_char_bytes = 1;
897 g_return_val_if_fail (CLUTTER_IS_TEXT (self), FALSE);
901 n_chars = clutter_text_buffer_get_length (get_buffer (self));
902 if (priv->preedit_set)
903 n_chars += priv->preedit_n_chars;
905 if (position < -1 || position > n_chars)
908 if (priv->password_char != 0)
909 password_char_bytes = g_unichar_to_utf8 (priv->password_char, NULL);
913 if (priv->password_char == 0)
915 n_bytes = clutter_text_buffer_get_bytes (get_buffer (self));
916 if (priv->editable && priv->preedit_set)
917 index_ = n_bytes + strlen (priv->preedit_str);
922 index_ = n_chars * password_char_bytes;
924 else if (position == 0)
930 gchar *text = clutter_text_get_display_text (self);
931 GString *tmp = g_string_new (text);
934 cursor_index = offset_to_bytes (text, priv->position);
936 if (priv->preedit_str != NULL)
937 g_string_insert (tmp, cursor_index, priv->preedit_str);
939 if (priv->password_char == 0)
940 index_ = offset_to_bytes (tmp->str, position);
942 index_ = position * password_char_bytes;
945 g_string_free (tmp, TRUE);
948 pango_layout_get_cursor_pos (clutter_text_get_layout (self),
954 *x = (gfloat) rect.x / 1024.0f;
956 /* Take any offset due to scrolling into account */
957 if (priv->single_line_mode)
962 *y = (gfloat) rect.y / 1024.0f;
965 *line_height = (gfloat) rect.height / 1024.0f;
971 clutter_text_ensure_cursor_position (ClutterText *self)
973 ClutterTextPrivate *priv = self->priv;
974 gfloat x, y, cursor_height;
975 ClutterGeometry cursor_pos = { 0, };
976 gboolean x_changed, y_changed;
977 gboolean width_changed, height_changed;
980 position = priv->position;
982 if (priv->editable && priv->preedit_set)
985 position = clutter_text_buffer_get_length (get_buffer (self));
986 position += priv->preedit_cursor_pos;
989 CLUTTER_NOTE (MISC, "Cursor at %d (preedit %s at pos: %d)",
991 priv->preedit_set ? "set" : "unset",
992 priv->preedit_set ? priv->preedit_cursor_pos : 0);
994 x = y = cursor_height = 0;
995 clutter_text_position_to_coords (self, position,
1000 cursor_pos.y = y + 2;
1001 cursor_pos.width = priv->cursor_size;
1002 cursor_pos.height = cursor_height - 4;
1004 x_changed = priv->cursor_pos.x != cursor_pos.x;
1005 y_changed = priv->cursor_pos.y != cursor_pos.y;
1006 width_changed = priv->cursor_pos.width != cursor_pos.width;
1007 height_changed = priv->cursor_pos.height != cursor_pos.height;
1009 if (x_changed || y_changed || width_changed || height_changed)
1011 priv->cursor_pos = cursor_pos;
1013 g_signal_emit (self, text_signals[CURSOR_EVENT], 0, &priv->cursor_pos);
1018 * clutter_text_delete_selection:
1019 * @self: a #ClutterText
1021 * Deletes the currently selected text
1023 * This function is only useful in subclasses of #ClutterText
1025 * Return value: %TRUE if text was deleted or if the text actor
1026 * is empty, and %FALSE otherwise
1031 clutter_text_delete_selection (ClutterText *self)
1033 ClutterTextPrivate *priv;
1036 gint old_position, old_selection;
1039 g_return_val_if_fail (CLUTTER_IS_TEXT (self), FALSE);
1043 n_chars = clutter_text_buffer_get_length (get_buffer (self));
1047 start_index = priv->position == -1 ? n_chars : priv->position;
1048 end_index = priv->selection_bound == -1 ? n_chars : priv->selection_bound;
1050 if (end_index == start_index)
1053 if (end_index < start_index)
1055 gint temp = start_index;
1056 start_index = end_index;
1060 old_position = priv->position;
1061 old_selection = priv->selection_bound;
1063 clutter_text_delete_text (self, start_index, end_index);
1065 priv->position = start_index;
1066 priv->selection_bound = start_index;
1068 /* Not required to be guarded by g_object_freeze/thaw_notify */
1069 if (priv->position != old_position)
1070 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_POSITION]);
1072 if (priv->selection_bound != old_selection)
1073 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_SELECTION_BOUND]);
1079 * Utility function to update both cursor position and selection bound
1083 clutter_text_set_positions (ClutterText *self,
1087 g_object_freeze_notify (G_OBJECT (self));
1088 clutter_text_set_cursor_position (self, new_pos);
1089 clutter_text_set_selection_bound (self, new_bound);
1090 g_object_thaw_notify (G_OBJECT (self));
1094 clutter_text_set_markup_internal (ClutterText *self,
1097 ClutterTextPrivate *priv = self->priv;
1100 PangoAttrList *attrs = NULL;
1103 g_assert (str != NULL);
1106 res = pango_parse_markup (str, -1, 0,
1114 if (G_LIKELY (error != NULL))
1116 g_warning ("Failed to set the markup of the actor '%s': %s",
1117 _clutter_actor_get_debug_name (CLUTTER_ACTOR (self)),
1119 g_error_free (error);
1122 g_warning ("Failed to set the markup of the actor '%s'",
1123 _clutter_actor_get_debug_name (CLUTTER_ACTOR (self)));
1130 clutter_text_buffer_set_text (get_buffer (self), text, -1);
1134 /* Store the new markup attributes */
1135 if (priv->markup_attrs != NULL)
1136 pango_attr_list_unref (priv->markup_attrs);
1138 priv->markup_attrs = attrs;
1140 /* Clear the effective attributes so they will be regenerated when a
1141 layout is created */
1142 if (priv->effective_attrs != NULL)
1144 pango_attr_list_unref (priv->effective_attrs);
1145 priv->effective_attrs = NULL;
1150 clutter_text_set_property (GObject *gobject,
1152 const GValue *value,
1155 ClutterText *self = CLUTTER_TEXT (gobject);
1160 clutter_text_set_buffer (self, g_value_get_object (value));
1165 const char *str = g_value_get_string (value);
1166 if (self->priv->use_markup)
1167 clutter_text_set_markup_internal (self, str ? str : "");
1169 clutter_text_buffer_set_text (get_buffer (self), str ? str : "", -1);
1174 clutter_text_set_color (self, clutter_value_get_color (value));
1177 case PROP_FONT_NAME:
1178 clutter_text_set_font_name (self, g_value_get_string (value));
1181 case PROP_FONT_DESCRIPTION:
1182 clutter_text_set_font_description (self, g_value_get_boxed (value));
1185 case PROP_USE_MARKUP:
1186 clutter_text_set_use_markup (self, g_value_get_boolean (value));
1189 case PROP_ATTRIBUTES:
1190 clutter_text_set_attributes (self, g_value_get_boxed (value));
1193 case PROP_LINE_ALIGNMENT:
1194 clutter_text_set_line_alignment (self, g_value_get_enum (value));
1197 case PROP_LINE_WRAP:
1198 clutter_text_set_line_wrap (self, g_value_get_boolean (value));
1201 case PROP_LINE_WRAP_MODE:
1202 clutter_text_set_line_wrap_mode (self, g_value_get_enum (value));
1206 clutter_text_set_justify (self, g_value_get_boolean (value));
1209 case PROP_ELLIPSIZE:
1210 clutter_text_set_ellipsize (self, g_value_get_enum (value));
1214 clutter_text_set_cursor_position (self, g_value_get_int (value));
1217 case PROP_SELECTION_BOUND:
1218 clutter_text_set_selection_bound (self, g_value_get_int (value));
1221 case PROP_SELECTION_COLOR:
1222 clutter_text_set_selection_color (self, g_value_get_boxed (value));
1225 case PROP_CURSOR_VISIBLE:
1226 clutter_text_set_cursor_visible (self, g_value_get_boolean (value));
1229 case PROP_CURSOR_COLOR:
1230 clutter_text_set_cursor_color (self, g_value_get_boxed (value));
1233 case PROP_CURSOR_SIZE:
1234 clutter_text_set_cursor_size (self, g_value_get_int (value));
1238 clutter_text_set_editable (self, g_value_get_boolean (value));
1241 case PROP_ACTIVATABLE:
1242 clutter_text_set_activatable (self, g_value_get_boolean (value));
1245 case PROP_SELECTABLE:
1246 clutter_text_set_selectable (self, g_value_get_boolean (value));
1249 case PROP_PASSWORD_CHAR:
1250 clutter_text_set_password_char (self, g_value_get_uint (value));
1253 case PROP_MAX_LENGTH:
1254 clutter_text_set_max_length (self, g_value_get_int (value));
1257 case PROP_SINGLE_LINE_MODE:
1258 clutter_text_set_single_line_mode (self, g_value_get_boolean (value));
1261 case PROP_SELECTED_TEXT_COLOR:
1262 clutter_text_set_selected_text_color (self, clutter_value_get_color (value));
1266 G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
1271 clutter_text_get_property (GObject *gobject,
1276 ClutterText *self = CLUTTER_TEXT (gobject);
1277 ClutterTextPrivate *priv = self->priv;
1282 g_value_set_object (value, clutter_text_get_buffer (self));
1286 g_value_set_string (value, clutter_text_buffer_get_text (get_buffer (self)));
1289 case PROP_FONT_NAME:
1290 g_value_set_string (value, priv->font_name);
1293 case PROP_FONT_DESCRIPTION:
1294 g_value_set_boxed (value, priv->font_desc);
1297 case PROP_USE_MARKUP:
1298 g_value_set_boolean (value, priv->use_markup);
1302 clutter_value_set_color (value, &priv->text_color);
1305 case PROP_CURSOR_VISIBLE:
1306 g_value_set_boolean (value, priv->cursor_visible);
1309 case PROP_CURSOR_COLOR:
1310 clutter_value_set_color (value, &priv->cursor_color);
1313 case PROP_CURSOR_COLOR_SET:
1314 g_value_set_boolean (value, priv->cursor_color_set);
1317 case PROP_CURSOR_SIZE:
1318 g_value_set_int (value, priv->cursor_size);
1322 g_value_set_int (value, priv->position);
1325 case PROP_SELECTION_BOUND:
1326 g_value_set_int (value, priv->selection_bound);
1330 g_value_set_boolean (value, priv->editable);
1333 case PROP_SELECTABLE:
1334 g_value_set_boolean (value, priv->selectable);
1337 case PROP_SELECTION_COLOR:
1338 clutter_value_set_color (value, &priv->selection_color);
1341 case PROP_SELECTION_COLOR_SET:
1342 g_value_set_boolean (value, priv->selection_color_set);
1345 case PROP_ACTIVATABLE:
1346 g_value_set_boolean (value, priv->activatable);
1349 case PROP_PASSWORD_CHAR:
1350 g_value_set_uint (value, priv->password_char);
1353 case PROP_MAX_LENGTH:
1354 g_value_set_int (value, clutter_text_buffer_get_max_length (get_buffer (self)));
1357 case PROP_SINGLE_LINE_MODE:
1358 g_value_set_boolean (value, priv->single_line_mode);
1361 case PROP_ELLIPSIZE:
1362 g_value_set_enum (value, priv->ellipsize);
1365 case PROP_LINE_WRAP:
1366 g_value_set_boolean (value, priv->wrap);
1369 case PROP_LINE_WRAP_MODE:
1370 g_value_set_enum (value, priv->wrap_mode);
1373 case PROP_LINE_ALIGNMENT:
1374 g_value_set_enum (value, priv->alignment);
1378 g_value_set_boolean (value, priv->justify);
1381 case PROP_ATTRIBUTES:
1382 g_value_set_boxed (value, priv->attrs);
1385 case PROP_SELECTED_TEXT_COLOR:
1386 clutter_value_set_color (value, &priv->selected_text_color);
1389 case PROP_SELECTED_TEXT_COLOR_SET:
1390 g_value_set_boolean (value, priv->selected_text_color_set);
1394 G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
1399 clutter_text_dispose (GObject *gobject)
1401 ClutterText *self = CLUTTER_TEXT (gobject);
1402 ClutterTextPrivate *priv = self->priv;
1404 /* get rid of the entire cache */
1405 clutter_text_dirty_cache (self);
1407 if (priv->direction_changed_id)
1409 g_signal_handler_disconnect (self, priv->direction_changed_id);
1410 priv->direction_changed_id = 0;
1413 if (priv->settings_changed_id)
1415 g_signal_handler_disconnect (clutter_get_default_backend (),
1416 priv->settings_changed_id);
1417 priv->settings_changed_id = 0;
1420 if (priv->password_hint_id)
1422 g_source_remove (priv->password_hint_id);
1423 priv->password_hint_id = 0;
1426 clutter_text_set_buffer (self, NULL);
1428 G_OBJECT_CLASS (clutter_text_parent_class)->dispose (gobject);
1432 clutter_text_finalize (GObject *gobject)
1434 ClutterText *self = CLUTTER_TEXT (gobject);
1435 ClutterTextPrivate *priv = self->priv;
1437 if (priv->font_desc)
1438 pango_font_description_free (priv->font_desc);
1441 pango_attr_list_unref (priv->attrs);
1442 if (priv->markup_attrs)
1443 pango_attr_list_unref (priv->markup_attrs);
1444 if (priv->effective_attrs)
1445 pango_attr_list_unref (priv->effective_attrs);
1446 if (priv->preedit_attrs)
1447 pango_attr_list_unref (priv->preedit_attrs);
1449 clutter_text_dirty_paint_volume (self);
1451 clutter_text_set_buffer (self, NULL);
1452 g_free (priv->font_name);
1454 G_OBJECT_CLASS (clutter_text_parent_class)->finalize (gobject);
1457 typedef void (* ClutterTextSelectionFunc) (ClutterText *text,
1458 const ClutterActorBox *box,
1459 gpointer user_data);
1462 clutter_text_foreach_selection_rectangle (ClutterText *self,
1463 ClutterTextSelectionFunc func,
1466 ClutterTextPrivate *priv = self->priv;
1467 PangoLayout *layout = clutter_text_get_layout (self);
1468 gchar *utf8 = clutter_text_get_display_text (self);
1474 if (priv->position == 0)
1477 start_index = offset_to_bytes (utf8, priv->position);
1479 if (priv->selection_bound == 0)
1482 end_index = offset_to_bytes (utf8, priv->selection_bound);
1484 if (start_index > end_index)
1486 gint temp = start_index;
1487 start_index = end_index;
1491 lines = pango_layout_get_line_count (layout);
1493 for (line_no = 0; line_no < lines; line_no++)
1495 PangoLayoutLine *line;
1501 ClutterActorBox box;
1504 line = pango_layout_get_line_readonly (layout, line_no);
1505 pango_layout_line_x_to_index (line, G_MAXINT, &maxindex, NULL);
1506 if (maxindex < start_index)
1509 pango_layout_line_get_x_ranges (line, start_index, end_index,
1512 pango_layout_line_x_to_index (line, 0, &index_, NULL);
1514 clutter_text_position_to_coords (self,
1515 bytes_to_offset (utf8, index_),
1519 box.y2 = y + height;
1521 for (i = 0; i < n_ranges; i++)
1526 range_x = ranges[i * 2] / PANGO_SCALE;
1528 /* Account for any scrolling in single line mode */
1529 if (priv->single_line_mode)
1530 range_x += priv->text_x;
1533 range_width = ((gfloat) ranges[i * 2 + 1] - (gfloat) ranges[i * 2])
1537 box.x2 = ceilf (range_x + range_width + .5f);
1539 func (self, &box, user_data);
1549 add_selection_rectangle_to_path (ClutterText *text,
1550 const ClutterActorBox *box,
1553 cogl_path_rectangle (user_data, box->x1, box->y1, box->x2, box->y2);
1556 /* Draws the selected text, its background, and the cursor */
1558 selection_paint (ClutterText *self)
1560 ClutterTextPrivate *priv = self->priv;
1561 ClutterActor *actor = CLUTTER_ACTOR (self);
1562 guint8 paint_opacity = clutter_actor_get_paint_opacity (actor);
1564 if (!priv->has_focus)
1567 if (priv->editable && priv->cursor_visible)
1569 const ClutterColor *color;
1572 position = priv->position;
1574 if (position == priv->selection_bound)
1576 /* No selection, just draw the cursor */
1577 if (priv->cursor_color_set)
1578 color = &priv->cursor_color;
1580 color = &priv->text_color;
1582 cogl_set_source_color4ub (color->red,
1589 cogl_rectangle (priv->cursor_pos.x,
1591 priv->cursor_pos.x + priv->cursor_pos.width,
1592 priv->cursor_pos.y + priv->cursor_pos.height);
1596 /* Paint selection background first */
1597 PangoLayout *layout = clutter_text_get_layout (self);
1598 CoglPath *selection_path = cogl_path_new ();
1599 CoglColor cogl_color = { 0, };
1601 /* Paint selection background */
1602 if (priv->selection_color_set)
1603 color = &priv->selection_color;
1604 else if (priv->cursor_color_set)
1605 color = &priv->cursor_color;
1607 color = &priv->text_color;
1609 cogl_set_source_color4ub (color->red,
1612 paint_opacity * color->alpha / 255);
1614 clutter_text_foreach_selection_rectangle (self,
1615 add_selection_rectangle_to_path,
1618 cogl_path_fill (selection_path);
1620 /* Paint selected text */
1621 cogl_framebuffer_push_path_clip (cogl_get_draw_framebuffer (),
1623 cogl_object_unref (selection_path);
1625 if (priv->selected_text_color_set)
1626 color = &priv->selected_text_color;
1628 color = &priv->text_color;
1630 cogl_color_init_from_4ub (&cogl_color,
1634 paint_opacity * color->alpha / 255);
1636 cogl_pango_render_layout (layout, priv->text_x, 0, &cogl_color, 0);
1644 clutter_text_move_word_backward (ClutterText *self,
1647 gint retval = start;
1649 if (clutter_text_buffer_get_length (get_buffer (self)) > 0 && start > 0)
1651 PangoLayout *layout = clutter_text_get_layout (self);
1652 PangoLogAttr *log_attrs = NULL;
1655 pango_layout_get_log_attrs (layout, &log_attrs, &n_attrs);
1658 while (retval > 0 && !log_attrs[retval].is_word_start)
1668 clutter_text_move_word_forward (ClutterText *self,
1671 gint retval = start;
1674 n_chars = clutter_text_buffer_get_length (get_buffer (self));
1675 if (n_chars > 0 && start < n_chars)
1677 PangoLayout *layout = clutter_text_get_layout (self);
1678 PangoLogAttr *log_attrs = NULL;
1681 pango_layout_get_log_attrs (layout, &log_attrs, &n_attrs);
1684 while (retval < n_chars && !log_attrs[retval].is_word_end)
1694 clutter_text_move_line_start (ClutterText *self,
1697 PangoLayoutLine *layout_line;
1698 PangoLayout *layout;
1704 layout = clutter_text_get_layout (self);
1705 text = clutter_text_buffer_get_text (get_buffer (self));
1710 index_ = offset_to_bytes (text, start);
1712 pango_layout_index_to_line_x (layout, index_,
1716 layout_line = pango_layout_get_line_readonly (layout, line_no);
1720 pango_layout_line_x_to_index (layout_line, 0, &index_, NULL);
1722 position = bytes_to_offset (text, index_);
1728 clutter_text_move_line_end (ClutterText *self,
1731 ClutterTextPrivate *priv = self->priv;
1732 PangoLayoutLine *layout_line;
1733 PangoLayout *layout;
1740 layout = clutter_text_get_layout (self);
1741 text = clutter_text_buffer_get_text (get_buffer (self));
1746 index_ = offset_to_bytes (text, priv->position);
1748 pango_layout_index_to_line_x (layout, index_,
1752 layout_line = pango_layout_get_line_readonly (layout, line_no);
1756 pango_layout_line_x_to_index (layout_line, G_MAXINT, &index_, &trailing);
1759 position = bytes_to_offset (text, index_);
1765 clutter_text_select_word (ClutterText *self)
1767 gint cursor_pos = self->priv->position;
1768 gint start_pos, end_pos;
1770 start_pos = clutter_text_move_word_backward (self, cursor_pos);
1771 end_pos = clutter_text_move_word_forward (self, cursor_pos);
1773 clutter_text_set_selection (self, start_pos, end_pos);
1777 clutter_text_select_line (ClutterText *self)
1779 ClutterTextPrivate *priv = self->priv;
1780 gint cursor_pos = priv->position;
1781 gint start_pos, end_pos;
1783 if (priv->single_line_mode)
1790 start_pos = clutter_text_move_line_start (self, cursor_pos);
1791 end_pos = clutter_text_move_line_end (self, cursor_pos);
1794 clutter_text_set_selection (self, start_pos, end_pos);
1798 clutter_text_button_press (ClutterActor *actor,
1799 ClutterButtonEvent *event)
1801 ClutterText *self = CLUTTER_TEXT (actor);
1802 ClutterTextPrivate *priv = self->priv;
1803 gboolean res = FALSE;
1807 /* we'll steal keyfocus if we need it */
1808 if (priv->editable || priv->selectable)
1809 clutter_actor_grab_key_focus (actor);
1811 return CLUTTER_EVENT_PROPAGATE;
1813 /* if the actor is empty we just reset everything and not
1814 * set up the dragging of the selection since there's nothing
1817 if (clutter_text_buffer_get_length (get_buffer (self)) == 0)
1819 clutter_text_set_positions (self, -1, -1);
1821 return CLUTTER_EVENT_STOP;
1824 res = clutter_actor_transform_stage_point (actor,
1833 index_ = clutter_text_coords_to_position (self, x, y);
1834 text = clutter_text_buffer_get_text (get_buffer (self));
1835 offset = bytes_to_offset (text, index_);
1837 /* what we select depends on the number of button clicks we
1840 * 1: just position the cursor and the selection
1841 * 2: select the current word
1842 * 3: select the contents of the whole actor
1844 if (event->click_count == 1)
1846 clutter_text_set_positions (self, offset, offset);
1848 else if (event->click_count == 2)
1850 clutter_text_select_word (self);
1852 else if (event->click_count == 3)
1854 clutter_text_select_line (self);
1858 /* grab the pointer */
1859 priv->in_select_drag = TRUE;
1860 clutter_grab_pointer (actor);
1862 return CLUTTER_EVENT_STOP;
1866 clutter_text_motion (ClutterActor *actor,
1867 ClutterMotionEvent *mev)
1869 ClutterText *self = CLUTTER_TEXT (actor);
1870 ClutterTextPrivate *priv = self->priv;
1872 gint index_, offset;
1876 if (!priv->in_select_drag)
1877 return CLUTTER_EVENT_PROPAGATE;
1879 res = clutter_actor_transform_stage_point (actor,
1883 return CLUTTER_EVENT_PROPAGATE;
1885 index_ = clutter_text_coords_to_position (self, x, y);
1886 text = clutter_text_buffer_get_text (get_buffer (self));
1887 offset = bytes_to_offset (text, index_);
1889 if (priv->selectable)
1890 clutter_text_set_cursor_position (self, offset);
1892 clutter_text_set_positions (self, offset, offset);
1894 return CLUTTER_EVENT_STOP;
1898 clutter_text_button_release (ClutterActor *actor,
1899 ClutterButtonEvent *bev)
1901 ClutterText *self = CLUTTER_TEXT (actor);
1902 ClutterTextPrivate *priv = self->priv;
1904 if (priv->in_select_drag)
1906 clutter_ungrab_pointer ();
1907 priv->in_select_drag = FALSE;
1909 return CLUTTER_EVENT_STOP;
1912 return CLUTTER_EVENT_PROPAGATE;
1916 clutter_text_remove_password_hint (gpointer data)
1918 ClutterText *self = data;
1920 self->priv->password_hint_visible = FALSE;
1921 self->priv->password_hint_id = 0;
1923 clutter_text_dirty_cache (data);
1924 clutter_text_queue_redraw (data);
1926 return G_SOURCE_REMOVE;
1930 clutter_text_key_press (ClutterActor *actor,
1931 ClutterKeyEvent *event)
1933 ClutterText *self = CLUTTER_TEXT (actor);
1934 ClutterTextPrivate *priv = self->priv;
1935 ClutterBindingPool *pool;
1938 if (!priv->editable)
1939 return CLUTTER_EVENT_PROPAGATE;
1941 /* we need to use the ClutterText type name to find our own
1942 * key bindings; subclasses will override or chain up this
1943 * event handler, so they can do whatever they want there
1945 pool = clutter_binding_pool_find (g_type_name (CLUTTER_TYPE_TEXT));
1946 g_assert (pool != NULL);
1948 /* we allow passing synthetic events that only contain
1949 * the Unicode value and not the key symbol
1951 if (event->keyval == 0 && (event->flags & CLUTTER_EVENT_FLAG_SYNTHETIC))
1954 res = clutter_binding_pool_activate (pool, event->keyval,
1955 event->modifier_state,
1958 /* if the key binding has handled the event we bail out
1959 * as fast as we can; otherwise, we try to insert the
1960 * Unicode character inside the key event into the text
1964 return CLUTTER_EVENT_STOP;
1965 else if ((event->modifier_state & CLUTTER_CONTROL_MASK) == 0)
1967 gunichar key_unichar;
1969 /* Skip keys when control is pressed */
1970 key_unichar = clutter_event_get_key_unicode ((ClutterEvent *) event);
1972 /* return is reported as CR, but we want LF */
1973 if (key_unichar == '\r')
1976 if (key_unichar == '\n' ||
1977 (g_unichar_validate (key_unichar) &&
1978 !g_unichar_iscntrl (key_unichar)))
1980 /* truncate the eventual selection so that the
1981 * Unicode character can replace it
1983 clutter_text_delete_selection (self);
1984 clutter_text_insert_unichar (self, key_unichar);
1986 if (priv->show_password_hint)
1988 if (priv->password_hint_id != 0)
1989 g_source_remove (priv->password_hint_id);
1991 priv->password_hint_visible = TRUE;
1992 priv->password_hint_id =
1993 clutter_threads_add_timeout (priv->password_hint_timeout,
1994 clutter_text_remove_password_hint,
1998 return CLUTTER_EVENT_STOP;
2002 return CLUTTER_EVENT_PROPAGATE;
2005 #define TEXT_PADDING 2
2008 clutter_text_paint (ClutterActor *self)
2010 ClutterText *text = CLUTTER_TEXT (self);
2011 ClutterTextPrivate *priv = text->priv;
2012 PangoLayout *layout;
2013 ClutterActorBox alloc = { 0, };
2014 CoglColor color = { 0, };
2015 guint8 real_opacity;
2016 gint text_x = priv->text_x;
2017 gboolean clip_set = FALSE;
2018 gboolean bg_color_set = FALSE;
2021 /* Note that if anything in this paint method changes it needs to be
2022 reflected in the get_paint_volume implementation which is tightly
2023 tied to the workings of this function */
2025 n_chars = clutter_text_buffer_get_length (get_buffer (text));
2027 /* don't bother painting an empty text actor, unless it's
2028 * editable, in which case we want to paint at least the
2031 if (n_chars == 0 && (!priv->editable || !priv->cursor_visible))
2034 clutter_actor_get_allocation_box (self, &alloc);
2036 g_object_get (self, "background-color-set", &bg_color_set, NULL);
2039 ClutterColor bg_color;
2041 clutter_actor_get_background_color (self, &bg_color);
2042 bg_color.alpha = clutter_actor_get_paint_opacity (self)
2046 cogl_set_source_color4ub (bg_color.red,
2050 cogl_rectangle (0, 0, alloc.x2 - alloc.x1, alloc.y2 - alloc.y1);
2053 if (priv->editable && priv->single_line_mode)
2054 layout = clutter_text_create_layout (text, -1, -1);
2057 /* the only time when we create the PangoLayout using the full
2058 * width and height of the allocation is when we can both wrap
2061 if (priv->wrap && priv->ellipsize)
2063 layout = clutter_text_create_layout (text,
2064 alloc.x2 - alloc.x1,
2065 alloc.y2 - alloc.y1);
2069 /* if we're not wrapping we cannot set the height of the
2070 * layout, otherwise Pango will happily wrap the text to
2071 * fit in the rectangle - thus making the :wrap property
2076 * http://bugzilla.clutter-project.org/show_bug.cgi?id=2339
2078 * in order to fix this, we create a layout that would fit
2079 * in the assigned width, then we clip the actor if the
2080 * logical rectangle overflows the allocation.
2082 layout = clutter_text_create_layout (text,
2083 alloc.x2 - alloc.x1,
2088 if (priv->editable && priv->cursor_visible)
2089 clutter_text_ensure_cursor_position (text);
2091 if (priv->editable && priv->single_line_mode)
2093 PangoRectangle logical_rect = { 0, };
2094 gint actor_width, text_width;
2096 pango_layout_get_extents (layout, NULL, &logical_rect);
2098 cogl_clip_push_rectangle (0, 0,
2099 (alloc.x2 - alloc.x1),
2100 (alloc.y2 - alloc.y1));
2103 actor_width = (alloc.x2 - alloc.x1)
2105 text_width = logical_rect.width / PANGO_SCALE;
2107 if (actor_width < text_width)
2109 gint cursor_x = priv->cursor_pos.x;
2111 if (priv->position == -1)
2113 text_x = actor_width - text_width;
2115 else if (priv->position == 0)
2117 text_x = TEXT_PADDING;
2123 text_x = text_x - cursor_x - TEXT_PADDING;
2125 else if (cursor_x > actor_width)
2127 text_x = text_x + (actor_width - cursor_x) - TEXT_PADDING;
2133 text_x = TEXT_PADDING;
2136 else if (!priv->editable && !(priv->wrap && priv->ellipsize))
2138 PangoRectangle logical_rect = { 0, };
2140 pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
2142 /* don't clip if the layout managed to fit inside our allocation */
2143 if (logical_rect.width > (alloc.x2 - alloc.x1) ||
2144 logical_rect.height > (alloc.y2 - alloc.y1))
2146 cogl_clip_push_rectangle (0, 0,
2147 alloc.x2 - alloc.x1,
2148 alloc.y2 - alloc.y1);
2157 if (priv->text_x != text_x)
2159 priv->text_x = text_x;
2160 clutter_text_ensure_cursor_position (text);
2163 real_opacity = clutter_actor_get_paint_opacity (self)
2164 * priv->text_color.alpha
2167 CLUTTER_NOTE (PAINT, "painting text (text: '%s')",
2168 clutter_text_buffer_get_text (get_buffer (text)));
2170 cogl_color_init_from_4ub (&color,
2171 priv->text_color.red,
2172 priv->text_color.green,
2173 priv->text_color.blue,
2175 cogl_pango_render_layout (layout, text_x, priv->text_y, &color, 0);
2177 selection_paint (text);
2184 add_selection_to_paint_volume (ClutterText *text,
2185 const ClutterActorBox *box,
2188 ClutterPaintVolume *total_volume = user_data;
2189 ClutterPaintVolume rect_volume;
2190 ClutterVertex vertex;
2192 _clutter_paint_volume_init_static (&rect_volume, CLUTTER_ACTOR (text));
2197 clutter_paint_volume_set_origin (&rect_volume, &vertex);
2198 clutter_paint_volume_set_width (&rect_volume, box->x2 - box->x1);
2199 clutter_paint_volume_set_height (&rect_volume, box->y2 - box->y1);
2201 clutter_paint_volume_union (total_volume, &rect_volume);
2203 clutter_paint_volume_free (&rect_volume);
2207 clutter_text_get_paint_volume_for_cursor (ClutterText *text,
2208 ClutterPaintVolume *volume)
2210 ClutterTextPrivate *priv = text->priv;
2211 ClutterVertex origin;
2213 clutter_text_ensure_cursor_position (text);
2215 if (priv->position == priv->selection_bound)
2217 origin.x = priv->cursor_pos.x;
2218 origin.y = priv->cursor_pos.y;
2220 clutter_paint_volume_set_origin (volume, &origin);
2221 clutter_paint_volume_set_width (volume, priv->cursor_pos.width);
2222 clutter_paint_volume_set_height (volume, priv->cursor_pos.height);
2226 clutter_text_foreach_selection_rectangle (text,
2227 add_selection_to_paint_volume,
2233 clutter_text_get_paint_volume (ClutterActor *self,
2234 ClutterPaintVolume *volume)
2236 ClutterText *text = CLUTTER_TEXT (self);
2237 ClutterTextPrivate *priv = text->priv;
2239 /* ClutterText uses the logical layout as the natural size of the
2240 actor. This means that it can sometimes paint outside of its
2241 allocation for example with italic fonts with serifs. Therefore
2242 we should use the ink rectangle of the layout instead */
2244 if (!priv->paint_volume_valid)
2246 PangoLayout *layout;
2247 PangoRectangle ink_rect;
2248 ClutterVertex origin;
2250 /* If the text is single line editable then it gets clipped to
2251 the allocation anyway so we can just use that */
2252 if (priv->editable && priv->single_line_mode)
2253 return _clutter_actor_set_default_paint_volume (self,
2257 if (G_OBJECT_TYPE (self) != CLUTTER_TYPE_TEXT)
2260 if (!clutter_actor_has_allocation (self))
2263 _clutter_paint_volume_init_static (&priv->paint_volume, self);
2265 layout = clutter_text_get_layout (text);
2266 pango_layout_get_extents (layout, &ink_rect, NULL);
2268 origin.x = ink_rect.x / (float) PANGO_SCALE;
2269 origin.y = ink_rect.y / (float) PANGO_SCALE;
2271 clutter_paint_volume_set_origin (&priv->paint_volume, &origin);
2272 clutter_paint_volume_set_width (&priv->paint_volume,
2273 ink_rect.width / (float) PANGO_SCALE);
2274 clutter_paint_volume_set_height (&priv->paint_volume,
2275 ink_rect.height / (float) PANGO_SCALE);
2277 /* If the cursor is visible then that will likely be drawn
2278 outside of the ink rectangle so we should merge that in */
2279 if (priv->editable && priv->cursor_visible && priv->has_focus)
2281 ClutterPaintVolume cursor_paint_volume;
2283 _clutter_paint_volume_init_static (&cursor_paint_volume,
2286 clutter_text_get_paint_volume_for_cursor (text, &cursor_paint_volume);
2288 clutter_paint_volume_union (&priv->paint_volume,
2289 &cursor_paint_volume);
2291 clutter_paint_volume_free (&cursor_paint_volume);
2294 priv->paint_volume_valid = TRUE;
2297 _clutter_paint_volume_copy_static (&priv->paint_volume, volume);
2303 clutter_text_get_preferred_width (ClutterActor *self,
2305 gfloat *min_width_p,
2306 gfloat *natural_width_p)
2308 ClutterText *text = CLUTTER_TEXT (self);
2309 ClutterTextPrivate *priv = text->priv;
2310 PangoRectangle logical_rect = { 0, };
2311 PangoLayout *layout;
2313 gfloat layout_width;
2315 layout = clutter_text_create_layout (text, -1, -1);
2317 pango_layout_get_extents (layout, NULL, &logical_rect);
2319 /* the X coordinate of the logical rectangle might be non-zero
2320 * according to the Pango documentation; hence, we need to offset
2321 * the width accordingly
2323 logical_width = logical_rect.x + logical_rect.width;
2325 layout_width = logical_width > 0
2326 ? ceilf (logical_width / 1024.0f)
2331 if (priv->wrap || priv->ellipsize || priv->editable)
2334 *min_width_p = layout_width;
2337 if (natural_width_p)
2339 if (priv->editable && priv->single_line_mode)
2340 *natural_width_p = layout_width + TEXT_PADDING * 2;
2342 *natural_width_p = layout_width;
2347 clutter_text_get_preferred_height (ClutterActor *self,
2349 gfloat *min_height_p,
2350 gfloat *natural_height_p)
2352 ClutterTextPrivate *priv = CLUTTER_TEXT (self)->priv;
2359 if (natural_height_p)
2360 *natural_height_p = 0;
2364 PangoLayout *layout;
2365 PangoRectangle logical_rect = { 0, };
2366 gint logical_height;
2367 gfloat layout_height;
2369 if (priv->single_line_mode)
2372 layout = clutter_text_create_layout (CLUTTER_TEXT (self),
2375 pango_layout_get_extents (layout, NULL, &logical_rect);
2377 /* the Y coordinate of the logical rectangle might be non-zero
2378 * according to the Pango documentation; hence, we need to offset
2379 * the height accordingly
2381 logical_height = logical_rect.y + logical_rect.height;
2382 layout_height = ceilf (logical_height / 1024.0f);
2386 /* if we wrap and ellipsize then the minimum height is
2387 * going to be at least the size of the first line
2389 if ((priv->ellipsize && priv->wrap) && !priv->single_line_mode)
2391 PangoLayoutLine *line;
2394 line = pango_layout_get_line_readonly (layout, 0);
2395 pango_layout_line_get_extents (line, NULL, &logical_rect);
2397 logical_height = logical_rect.y + logical_rect.height;
2398 line_height = ceilf (logical_height / 1024.0f);
2400 *min_height_p = line_height;
2403 *min_height_p = layout_height;
2406 if (natural_height_p)
2407 *natural_height_p = layout_height;
2412 clutter_text_allocate (ClutterActor *self,
2413 const ClutterActorBox *box,
2414 ClutterAllocationFlags flags)
2416 ClutterText *text = CLUTTER_TEXT (self);
2417 ClutterActorClass *parent_class;
2419 /* Ensure that there is a cached layout with the right width so
2420 * that we don't need to create the text during the paint run
2422 * if the Text is editable and in single line mode we don't want
2423 * to have any limit on the layout size, since the paint will clip
2424 * it to the allocation of the actor
2426 if (text->priv->editable && text->priv->single_line_mode)
2427 clutter_text_create_layout (text, -1, -1);
2429 clutter_text_create_layout (text,
2433 parent_class = CLUTTER_ACTOR_CLASS (clutter_text_parent_class);
2434 parent_class->allocate (self, box, flags);
2438 clutter_text_has_overlaps (ClutterActor *self)
2440 ClutterTextPrivate *priv = CLUTTER_TEXT (self)->priv;
2442 return priv->editable ||
2444 priv->cursor_visible;
2448 clutter_text_key_focus_in (ClutterActor *actor)
2450 ClutterTextPrivate *priv = CLUTTER_TEXT (actor)->priv;
2452 priv->has_focus = TRUE;
2454 clutter_text_queue_redraw (actor);
2458 clutter_text_key_focus_out (ClutterActor *actor)
2460 ClutterTextPrivate *priv = CLUTTER_TEXT (actor)->priv;
2462 priv->has_focus = FALSE;
2464 clutter_text_queue_redraw (actor);
2468 clutter_text_real_move_left (ClutterText *self,
2469 const gchar *action,
2471 ClutterModifierType modifiers)
2473 ClutterTextPrivate *priv = self->priv;
2474 gint pos = priv->position;
2478 len = clutter_text_buffer_get_length (get_buffer (self));
2480 g_object_freeze_notify (G_OBJECT (self));
2482 if (pos != 0 && len != 0)
2484 if (modifiers & CLUTTER_CONTROL_MASK)
2487 new_pos = clutter_text_move_word_backward (self, len);
2489 new_pos = clutter_text_move_word_backward (self, pos);
2499 clutter_text_set_cursor_position (self, new_pos);
2502 if (!(priv->selectable && (modifiers & CLUTTER_SHIFT_MASK)))
2503 clutter_text_clear_selection (self);
2505 g_object_thaw_notify (G_OBJECT (self));
2511 clutter_text_real_move_right (ClutterText *self,
2512 const gchar *action,
2514 ClutterModifierType modifiers)
2516 ClutterTextPrivate *priv = self->priv;
2517 gint pos = priv->position;
2518 gint len = clutter_text_buffer_get_length (get_buffer (self));
2521 g_object_freeze_notify (G_OBJECT (self));
2523 if (pos != -1 && len !=0)
2525 if (modifiers & CLUTTER_CONTROL_MASK)
2528 new_pos = clutter_text_move_word_forward (self, pos);
2536 clutter_text_set_cursor_position (self, new_pos);
2539 if (!(priv->selectable && (modifiers & CLUTTER_SHIFT_MASK)))
2540 clutter_text_clear_selection (self);
2542 g_object_thaw_notify (G_OBJECT (self));
2548 clutter_text_real_move_up (ClutterText *self,
2549 const gchar *action,
2551 ClutterModifierType modifiers)
2553 ClutterTextPrivate *priv = self->priv;
2554 PangoLayoutLine *layout_line;
2555 PangoLayout *layout;
2557 gint index_, trailing;
2562 layout = clutter_text_get_layout (self);
2563 text = clutter_text_buffer_get_text (get_buffer (self));
2565 if (priv->position == 0)
2568 index_ = offset_to_bytes (text, priv->position);
2570 pango_layout_index_to_line_x (layout, index_,
2578 if (priv->x_pos != -1)
2581 layout_line = pango_layout_get_line_readonly (layout, line_no);
2585 pango_layout_line_x_to_index (layout_line, x, &index_, &trailing);
2587 g_object_freeze_notify (G_OBJECT (self));
2589 pos = bytes_to_offset (text, index_);
2590 clutter_text_set_cursor_position (self, pos + trailing);
2592 /* Store the target x position to avoid drifting left and right when
2593 moving the cursor up and down */
2596 if (!(priv->selectable && (modifiers & CLUTTER_SHIFT_MASK)))
2597 clutter_text_clear_selection (self);
2599 g_object_thaw_notify (G_OBJECT (self));
2605 clutter_text_real_move_down (ClutterText *self,
2606 const gchar *action,
2608 ClutterModifierType modifiers)
2610 ClutterTextPrivate *priv = self->priv;
2611 PangoLayoutLine *layout_line;
2612 PangoLayout *layout;
2614 gint index_, trailing;
2619 layout = clutter_text_get_layout (self);
2620 text = clutter_text_buffer_get_text (get_buffer (self));
2622 if (priv->position == 0)
2625 index_ = offset_to_bytes (text, priv->position);
2627 pango_layout_index_to_line_x (layout, index_,
2631 if (priv->x_pos != -1)
2634 layout_line = pango_layout_get_line_readonly (layout, line_no + 1);
2638 pango_layout_line_x_to_index (layout_line, x, &index_, &trailing);
2640 g_object_freeze_notify (G_OBJECT (self));
2642 pos = bytes_to_offset (text, index_);
2643 clutter_text_set_cursor_position (self, pos + trailing);
2645 /* Store the target x position to avoid drifting left and right when
2646 moving the cursor up and down */
2649 if (!(priv->selectable && (modifiers & CLUTTER_SHIFT_MASK)))
2650 clutter_text_clear_selection (self);
2652 g_object_thaw_notify (G_OBJECT (self));
2658 clutter_text_real_line_start (ClutterText *self,
2659 const gchar *action,
2661 ClutterModifierType modifiers)
2663 ClutterTextPrivate *priv = self->priv;
2666 g_object_freeze_notify (G_OBJECT (self));
2668 position = clutter_text_move_line_start (self, priv->position);
2669 clutter_text_set_cursor_position (self, position);
2671 if (!(priv->selectable && (modifiers & CLUTTER_SHIFT_MASK)))
2672 clutter_text_clear_selection (self);
2674 g_object_thaw_notify (G_OBJECT (self));
2680 clutter_text_real_line_end (ClutterText *self,
2681 const gchar *action,
2683 ClutterModifierType modifiers)
2685 ClutterTextPrivate *priv = self->priv;
2688 g_object_freeze_notify (G_OBJECT (self));
2690 position = clutter_text_move_line_end (self, priv->position);
2691 clutter_text_set_cursor_position (self, position);
2693 if (!(priv->selectable && (modifiers & CLUTTER_SHIFT_MASK)))
2694 clutter_text_clear_selection (self);
2696 g_object_thaw_notify (G_OBJECT (self));
2702 clutter_text_real_select_all (ClutterText *self,
2703 const gchar *action,
2705 ClutterModifierType modifiers)
2707 guint n_chars = clutter_text_buffer_get_length (get_buffer (self));
2708 clutter_text_set_positions (self, 0, n_chars);
2714 clutter_text_real_del_next (ClutterText *self,
2715 const gchar *action,
2717 ClutterModifierType modifiers)
2719 ClutterTextPrivate *priv = self->priv;
2723 if (clutter_text_delete_selection (self))
2726 pos = priv->position;
2727 len = clutter_text_buffer_get_length (get_buffer (self));
2729 if (len && pos != -1 && pos < len)
2730 clutter_text_delete_text (self, pos, pos + 1);
2736 clutter_text_real_del_word_next (ClutterText *self,
2737 const gchar *action,
2739 ClutterModifierType modifiers)
2741 ClutterTextPrivate *priv = self->priv;
2745 pos = priv->position;
2746 len = clutter_text_buffer_get_length (get_buffer (self));
2748 if (len && pos != -1 && pos < len)
2752 end = clutter_text_move_word_forward (self, pos);
2753 clutter_text_delete_text (self, pos, end);
2755 if (priv->selection_bound >= end)
2759 new_bound = priv->selection_bound - (end - pos);
2760 clutter_text_set_selection_bound (self, new_bound);
2762 else if (priv->selection_bound > pos)
2764 clutter_text_set_selection_bound (self, pos);
2772 clutter_text_real_del_prev (ClutterText *self,
2773 const gchar *action,
2775 ClutterModifierType modifiers)
2777 ClutterTextPrivate *priv = self->priv;
2781 if (clutter_text_delete_selection (self))
2784 pos = priv->position;
2785 len = clutter_text_buffer_get_length (get_buffer (self));
2787 if (pos != 0 && len != 0)
2791 clutter_text_delete_text (self, len - 1, len);
2793 clutter_text_set_positions (self, -1, -1);
2797 clutter_text_delete_text (self, pos - 1, pos);
2799 clutter_text_set_positions (self, pos - 1, pos - 1);
2807 clutter_text_real_del_word_prev (ClutterText *self,
2808 const gchar *action,
2810 ClutterModifierType modifiers)
2812 ClutterTextPrivate *priv = self->priv;
2816 pos = priv->position;
2817 len = clutter_text_buffer_get_length (get_buffer (self));
2819 if (pos != 0 && len != 0)
2825 new_pos = clutter_text_move_word_backward (self, len);
2826 clutter_text_delete_text (self, new_pos, len);
2828 clutter_text_set_positions (self, -1, -1);
2832 new_pos = clutter_text_move_word_backward (self, pos);
2833 clutter_text_delete_text (self, new_pos, pos);
2835 clutter_text_set_cursor_position (self, new_pos);
2836 if (priv->selection_bound >= pos)
2840 new_bound = priv->selection_bound - (pos - new_pos);
2841 clutter_text_set_selection_bound (self, new_bound);
2843 else if (priv->selection_bound >= new_pos)
2845 clutter_text_set_selection_bound (self, new_pos);
2854 clutter_text_real_activate (ClutterText *self,
2855 const gchar *action,
2857 ClutterModifierType modifiers)
2859 return clutter_text_activate (self);
2863 clutter_text_add_move_binding (ClutterBindingPool *pool,
2864 const gchar *action,
2866 ClutterModifierType additional_modifiers,
2869 clutter_binding_pool_install_action (pool, action,
2874 clutter_binding_pool_install_action (pool, action,
2880 if (additional_modifiers != 0)
2882 clutter_binding_pool_install_action (pool, action,
2884 additional_modifiers,
2887 clutter_binding_pool_install_action (pool, action,
2889 CLUTTER_SHIFT_MASK |
2890 additional_modifiers,
2897 clutter_text_parse_custom_node (ClutterScriptable *scriptable,
2898 ClutterScript *script,
2903 if (strncmp (name, "font-description", 16) == 0)
2905 g_value_init (value, G_TYPE_STRING);
2906 g_value_set_string (value, json_node_get_string (node));
2915 clutter_text_set_color_internal (ClutterText *self,
2917 const ClutterColor *color)
2919 ClutterTextPrivate *priv = CLUTTER_TEXT (self)->priv;
2920 GParamSpec *other = NULL;
2922 switch (pspec->param_id)
2925 priv->text_color = *color;
2928 case PROP_CURSOR_COLOR:
2931 priv->cursor_color = *color;
2932 priv->cursor_color_set = TRUE;
2935 priv->cursor_color_set = FALSE;
2937 other = obj_props[PROP_CURSOR_COLOR_SET];
2940 case PROP_SELECTION_COLOR:
2943 priv->selection_color = *color;
2944 priv->selection_color_set = TRUE;
2947 priv->selection_color_set = FALSE;
2949 other = obj_props[PROP_SELECTION_COLOR_SET];
2952 case PROP_SELECTED_TEXT_COLOR:
2955 priv->selected_text_color = *color;
2956 priv->selected_text_color_set = TRUE;
2959 priv->selected_text_color_set = FALSE;
2961 other = obj_props[PROP_SELECTED_TEXT_COLOR_SET];
2965 g_assert_not_reached ();
2969 clutter_text_queue_redraw (CLUTTER_ACTOR (self));
2970 g_object_notify_by_pspec (G_OBJECT (self), pspec);
2972 g_object_notify_by_pspec (G_OBJECT (self), other);
2976 clutter_text_set_color_animated (ClutterText *self,
2978 const ClutterColor *color)
2980 ClutterActor *actor = CLUTTER_ACTOR (self);
2981 ClutterTextPrivate *priv = self->priv;
2982 const ClutterAnimationInfo *info;
2983 ClutterTransition *transition;
2985 info = _clutter_actor_get_animation_info (actor);
2986 transition = clutter_actor_get_transition (actor, pspec->name);
2988 /* jump to the end if there is no easing state, or if the easing
2989 * state has a duration of 0 msecs
2991 if (info->cur_state == NULL ||
2992 info->cur_state->easing_duration == 0)
2994 /* ensure that we remove any currently running transition */
2995 if (transition != NULL)
2997 clutter_actor_remove_transition (actor, pspec->name);
3001 clutter_text_set_color_internal (self, pspec, color);
3006 if (transition == NULL)
3008 transition = clutter_property_transition_new (pspec->name);
3009 clutter_transition_set_animatable (transition,
3010 CLUTTER_ANIMATABLE (self));
3011 clutter_transition_set_remove_on_complete (transition, TRUE);
3013 /* delay only makes sense if the transition has just been created */
3014 clutter_timeline_set_delay (CLUTTER_TIMELINE (transition),
3015 info->cur_state->easing_delay);
3017 clutter_actor_add_transition (actor, pspec->name, transition);
3019 /* the actor now owns the transition */
3020 g_object_unref (transition);
3023 /* if a transition already exist, update its bounds */
3024 switch (pspec->param_id)
3027 clutter_transition_set_from (transition, CLUTTER_TYPE_COLOR,
3031 case PROP_CURSOR_COLOR:
3032 clutter_transition_set_from (transition, CLUTTER_TYPE_COLOR,
3033 &priv->cursor_color);
3036 case PROP_SELECTION_COLOR:
3037 clutter_transition_set_from (transition, CLUTTER_TYPE_COLOR,
3038 &priv->selection_color);
3041 case PROP_SELECTED_TEXT_COLOR:
3042 clutter_transition_set_from (transition, CLUTTER_TYPE_COLOR,
3043 &priv->selected_text_color);
3047 g_assert_not_reached ();
3050 clutter_transition_set_to (transition, CLUTTER_TYPE_COLOR, color);
3052 /* always use the current easing state */
3053 clutter_timeline_set_duration (CLUTTER_TIMELINE (transition),
3054 info->cur_state->easing_duration);
3055 clutter_timeline_set_progress_mode (CLUTTER_TIMELINE (transition),
3056 info->cur_state->easing_mode);
3058 /* ensure that we start from the beginning */
3059 clutter_timeline_rewind (CLUTTER_TIMELINE (transition));
3060 clutter_timeline_start (CLUTTER_TIMELINE (transition));
3064 clutter_text_set_custom_property (ClutterScriptable *scriptable,
3065 ClutterScript *script,
3067 const GValue *value)
3069 if (strncmp (name, "font-description", 16) == 0)
3071 g_assert (G_VALUE_HOLDS (value, G_TYPE_STRING));
3072 if (g_value_get_string (value) != NULL)
3073 clutter_text_set_font_name (CLUTTER_TEXT (scriptable),
3074 g_value_get_string (value));
3077 g_object_set_property (G_OBJECT (scriptable), name, value);
3081 clutter_scriptable_iface_init (ClutterScriptableIface *iface)
3083 iface->parse_custom_node = clutter_text_parse_custom_node;
3084 iface->set_custom_property = clutter_text_set_custom_property;
3088 clutter_text_set_final_state (ClutterAnimatable *animatable,
3089 const char *property_name,
3090 const GValue *value)
3092 if (strcmp (property_name, "color") == 0)
3094 const ClutterColor *color = clutter_value_get_color (value);
3095 clutter_text_set_color_internal (CLUTTER_TEXT (animatable),
3096 obj_props[PROP_COLOR], color);
3098 else if (strcmp (property_name, "cursor-color") == 0)
3100 const ClutterColor *color = clutter_value_get_color (value);
3101 clutter_text_set_color_internal (CLUTTER_TEXT (animatable),
3102 obj_props[PROP_CURSOR_COLOR],
3105 else if (strcmp (property_name, "selected-text-color") == 0)
3107 const ClutterColor *color = clutter_value_get_color (value);
3108 clutter_text_set_color_internal (CLUTTER_TEXT (animatable),
3109 obj_props[PROP_SELECTED_TEXT_COLOR],
3112 else if (strcmp (property_name, "selection-color") == 0)
3114 const ClutterColor *color = clutter_value_get_color (value);
3115 clutter_text_set_color_internal (CLUTTER_TEXT (animatable),
3116 obj_props[PROP_SELECTION_COLOR],
3120 parent_animatable_iface->set_final_state (animatable, property_name, value);
3124 clutter_animatable_iface_init (ClutterAnimatableIface *iface)
3126 parent_animatable_iface = g_type_interface_peek_parent (iface);
3128 iface->set_final_state = clutter_text_set_final_state;
3132 clutter_text_class_init (ClutterTextClass *klass)
3134 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
3135 ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
3136 ClutterBindingPool *binding_pool;
3139 g_type_class_add_private (klass, sizeof (ClutterTextPrivate));
3141 gobject_class->set_property = clutter_text_set_property;
3142 gobject_class->get_property = clutter_text_get_property;
3143 gobject_class->dispose = clutter_text_dispose;
3144 gobject_class->finalize = clutter_text_finalize;
3146 actor_class->paint = clutter_text_paint;
3147 actor_class->get_paint_volume = clutter_text_get_paint_volume;
3148 actor_class->get_preferred_width = clutter_text_get_preferred_width;
3149 actor_class->get_preferred_height = clutter_text_get_preferred_height;
3150 actor_class->allocate = clutter_text_allocate;
3151 actor_class->key_press_event = clutter_text_key_press;
3152 actor_class->button_press_event = clutter_text_button_press;
3153 actor_class->button_release_event = clutter_text_button_release;
3154 actor_class->motion_event = clutter_text_motion;
3155 actor_class->key_focus_in = clutter_text_key_focus_in;
3156 actor_class->key_focus_out = clutter_text_key_focus_out;
3157 actor_class->has_overlaps = clutter_text_has_overlaps;
3160 * ClutterText:buffer:
3162 * The buffer which stores the text for this #ClutterText.
3164 * If set to %NULL, a default buffer will be created.
3168 pspec = g_param_spec_object ("buffer",
3170 P_("The buffer for the text"),
3171 CLUTTER_TYPE_TEXT_BUFFER,
3172 CLUTTER_PARAM_READWRITE);
3173 obj_props[PROP_BUFFER] = pspec;
3174 g_object_class_install_property (gobject_class, PROP_BUFFER, pspec);
3177 * ClutterText:font-name:
3179 * The font to be used by the #ClutterText, as a string
3180 * that can be parsed by pango_font_description_from_string().
3182 * If set to %NULL, the default system font will be used instead.
3186 pspec = g_param_spec_string ("font-name",
3188 P_("The font to be used by the text"),
3190 CLUTTER_PARAM_READWRITE);
3191 obj_props[PROP_FONT_NAME] = pspec;
3192 g_object_class_install_property (gobject_class, PROP_FONT_NAME, pspec);
3195 * ClutterText:font-description:
3197 * The #PangoFontDescription that should be used by the #ClutterText
3199 * If you have a string describing the font then you should look at
3200 * #ClutterText:font-name instead
3204 pspec = g_param_spec_boxed ("font-description",
3205 P_("Font Description"),
3206 P_("The font description to be used"),
3207 PANGO_TYPE_FONT_DESCRIPTION,
3208 CLUTTER_PARAM_READWRITE);
3209 obj_props[PROP_FONT_DESCRIPTION] = pspec;
3210 g_object_class_install_property (gobject_class,
3211 PROP_FONT_DESCRIPTION,
3217 * The text to render inside the actor.
3221 pspec = g_param_spec_string ("text",
3223 P_("The text to render"),
3225 CLUTTER_PARAM_READWRITE);
3226 obj_props[PROP_TEXT] = pspec;
3227 g_object_class_install_property (gobject_class, PROP_TEXT, pspec);
3230 * ClutterText:color:
3232 * The color used to render the text.
3236 pspec = clutter_param_spec_color ("color",
3238 P_("Color of the font used by the text"),
3239 &default_text_color,
3240 CLUTTER_PARAM_READWRITE |
3241 CLUTTER_PARAM_ANIMATABLE);
3242 obj_props[PROP_COLOR] = pspec;
3243 g_object_class_install_property (gobject_class, PROP_COLOR, pspec);
3246 * ClutterText:editable:
3248 * Whether key events delivered to the actor causes editing.
3252 pspec = g_param_spec_boolean ("editable",
3254 P_("Whether the text is editable"),
3257 obj_props[PROP_EDITABLE] = pspec;
3258 g_object_class_install_property (gobject_class, PROP_EDITABLE, pspec);
3261 * ClutterText:selectable:
3263 * Whether it is possible to select text, either using the pointer
3268 pspec = g_param_spec_boolean ("selectable",
3270 P_("Whether the text is selectable"),
3273 obj_props[PROP_SELECTABLE] = pspec;
3274 g_object_class_install_property (gobject_class, PROP_SELECTABLE, pspec);
3277 * ClutterText:activatable:
3279 * Toggles whether return invokes the activate signal or not.
3283 pspec = g_param_spec_boolean ("activatable",
3285 P_("Whether pressing return causes the activate signal to be emitted"),
3288 obj_props[PROP_ACTIVATABLE] = pspec;
3289 g_object_class_install_property (gobject_class, PROP_ACTIVATABLE, pspec);
3292 * ClutterText:cursor-visible:
3294 * Whether the input cursor is visible or not, it will only be visible
3295 * if both #ClutterText:cursor-visible and #ClutterText:editable are
3300 pspec = g_param_spec_boolean ("cursor-visible",
3301 P_("Cursor Visible"),
3302 P_("Whether the input cursor is visible"),
3304 CLUTTER_PARAM_READWRITE);
3305 obj_props[PROP_CURSOR_VISIBLE] = pspec;
3306 g_object_class_install_property (gobject_class, PROP_CURSOR_VISIBLE, pspec);
3309 * ClutterText:cursor-color:
3311 * The color of the cursor.
3315 pspec = clutter_param_spec_color ("cursor-color",
3318 &default_cursor_color,
3319 CLUTTER_PARAM_READWRITE |
3320 CLUTTER_PARAM_ANIMATABLE);
3321 obj_props[PROP_CURSOR_COLOR] = pspec;
3322 g_object_class_install_property (gobject_class, PROP_CURSOR_COLOR, pspec);
3325 * ClutterText:cursor-color-set:
3327 * Will be set to %TRUE if #ClutterText:cursor-color has been set.
3331 pspec = g_param_spec_boolean ("cursor-color-set",
3332 P_("Cursor Color Set"),
3333 P_("Whether the cursor color has been set"),
3335 CLUTTER_PARAM_READABLE);
3336 obj_props[PROP_CURSOR_COLOR_SET] = pspec;
3337 g_object_class_install_property (gobject_class, PROP_CURSOR_COLOR_SET, pspec);
3340 * ClutterText:cursor-size:
3342 * The size of the cursor, in pixels. If set to -1 the size used will
3343 * be the default cursor size of 2 pixels.
3347 pspec = g_param_spec_int ("cursor-size",
3349 P_("The width of the cursor, in pixels"),
3350 -1, G_MAXINT, DEFAULT_CURSOR_SIZE,
3351 CLUTTER_PARAM_READWRITE);
3352 obj_props[PROP_CURSOR_SIZE] = pspec;
3353 g_object_class_install_property (gobject_class, PROP_CURSOR_SIZE, pspec);
3356 * ClutterText:position:
3358 * The current input cursor position. -1 is taken to be the end of the text
3362 pspec = g_param_spec_int ("position",
3363 P_("Cursor Position"),
3364 P_("The cursor position"),
3367 CLUTTER_PARAM_READWRITE);
3368 obj_props[PROP_POSITION] = pspec;
3369 g_object_class_install_property (gobject_class, PROP_POSITION, pspec);
3372 * ClutterText:selection-bound:
3374 * The current input cursor position. -1 is taken to be the end of the text
3378 pspec = g_param_spec_int ("selection-bound",
3379 P_("Selection-bound"),
3380 P_("The cursor position of the other end of the selection"),
3383 CLUTTER_PARAM_READWRITE);
3384 obj_props[PROP_SELECTION_BOUND] = pspec;
3385 g_object_class_install_property (gobject_class, PROP_SELECTION_BOUND, pspec);
3388 * ClutterText:selection-color:
3390 * The color of the selection.
3394 pspec = clutter_param_spec_color ("selection-color",
3395 P_("Selection Color"),
3396 P_("Selection Color"),
3397 &default_selection_color,
3398 CLUTTER_PARAM_READWRITE |
3399 CLUTTER_PARAM_ANIMATABLE);
3400 obj_props[PROP_SELECTION_COLOR] = pspec;
3401 g_object_class_install_property (gobject_class, PROP_SELECTION_COLOR, pspec);
3404 * ClutterText:selection-color-set:
3406 * Will be set to %TRUE if #ClutterText:selection-color has been set.
3410 pspec = g_param_spec_boolean ("selection-color-set",
3411 P_("Selection Color Set"),
3412 P_("Whether the selection color has been set"),
3414 CLUTTER_PARAM_READABLE);
3415 obj_props[PROP_SELECTION_COLOR_SET] = pspec;
3416 g_object_class_install_property (gobject_class, PROP_SELECTION_COLOR_SET, pspec);
3419 * ClutterText:attributes:
3421 * A list of #PangoStyleAttribute<!-- -->s to be applied to the
3422 * contents of the #ClutterText actor.
3426 pspec = g_param_spec_boxed ("attributes",
3428 P_("A list of style attributes to apply to the contents of the actor"),
3429 PANGO_TYPE_ATTR_LIST,
3430 CLUTTER_PARAM_READWRITE);
3431 obj_props[PROP_ATTRIBUTES] = pspec;
3432 g_object_class_install_property (gobject_class, PROP_ATTRIBUTES, pspec);
3435 * ClutterText:use-markup:
3437 * Whether the text includes Pango markup.
3439 * For more informations about the Pango markup format, see
3440 * pango_layout_set_markup() in the Pango documentation.
3442 * <note>It is not possible to round-trip this property between
3443 * %TRUE and %FALSE. Once a string with markup has been set on
3444 * a #ClutterText actor with :use-markup set to %TRUE, the markup
3445 * is stripped from the string.</note>
3449 pspec = g_param_spec_boolean ("use-markup",
3451 P_("Whether or not the text includes Pango markup"),
3453 CLUTTER_PARAM_READWRITE);
3454 obj_props[PROP_USE_MARKUP] = pspec;
3455 g_object_class_install_property (gobject_class, PROP_USE_MARKUP, pspec);
3458 * ClutterText:line-wrap:
3460 * Whether to wrap the lines of #ClutterText:text if the contents
3461 * exceed the available allocation. The wrapping strategy is
3462 * controlled by the #ClutterText:line-wrap-mode property.
3466 pspec = g_param_spec_boolean ("line-wrap",
3468 P_("If set, wrap the lines if the text becomes too wide"),
3470 CLUTTER_PARAM_READWRITE);
3471 obj_props[PROP_LINE_WRAP] = pspec;
3472 g_object_class_install_property (gobject_class, PROP_LINE_WRAP, pspec);
3475 * ClutterText:line-wrap-mode:
3477 * If #ClutterText:line-wrap is set to %TRUE, this property will
3478 * control how the text is wrapped.
3482 pspec = g_param_spec_enum ("line-wrap-mode",
3483 P_("Line wrap mode"),
3484 P_("Control how line-wrapping is done"),
3485 PANGO_TYPE_WRAP_MODE,
3487 CLUTTER_PARAM_READWRITE);
3488 obj_props[PROP_LINE_WRAP_MODE] = pspec;
3489 g_object_class_install_property (gobject_class, PROP_LINE_WRAP_MODE, pspec);
3492 * ClutterText:ellipsize:
3494 * The preferred place to ellipsize the contents of the #ClutterText actor
3498 pspec = g_param_spec_enum ("ellipsize",
3500 P_("The preferred place to ellipsize the string"),
3501 PANGO_TYPE_ELLIPSIZE_MODE,
3502 PANGO_ELLIPSIZE_NONE,
3503 CLUTTER_PARAM_READWRITE);
3504 obj_props[PROP_ELLIPSIZE] = pspec;
3505 g_object_class_install_property (gobject_class, PROP_ELLIPSIZE, pspec);
3508 * ClutterText:line-alignment:
3510 * The preferred alignment for the text. This property controls
3511 * the alignment of multi-line paragraphs.
3515 pspec = g_param_spec_enum ("line-alignment",
3516 P_("Line Alignment"),
3517 P_("The preferred alignment for the string, for multi-line text"),
3518 PANGO_TYPE_ALIGNMENT,
3520 CLUTTER_PARAM_READWRITE);
3521 obj_props[PROP_LINE_ALIGNMENT] = pspec;
3522 g_object_class_install_property (gobject_class, PROP_LINE_ALIGNMENT, pspec);
3525 * ClutterText:justify:
3527 * Whether the contents of the #ClutterText should be justified
3532 pspec = g_param_spec_boolean ("justify",
3534 P_("Whether the text should be justified"),
3536 CLUTTER_PARAM_READWRITE);
3537 obj_props[PROP_JUSTIFY] = pspec;
3538 g_object_class_install_property (gobject_class, PROP_JUSTIFY, pspec);
3541 * ClutterText:password-char:
3543 * If non-zero, the character that should be used in place of
3544 * the actual text in a password text actor.
3548 pspec = g_param_spec_unichar ("password-char",
3549 P_("Password Character"),
3550 P_("If non-zero, use this character to display the actor's contents"),
3552 CLUTTER_PARAM_READWRITE);
3553 obj_props[PROP_PASSWORD_CHAR] = pspec;
3554 g_object_class_install_property (gobject_class, PROP_PASSWORD_CHAR, pspec);
3557 * ClutterText:max-length:
3559 * The maximum length of the contents of the #ClutterText actor.
3563 pspec = g_param_spec_int ("max-length",
3565 P_("Maximum length of the text inside the actor"),
3567 CLUTTER_PARAM_READWRITE);
3568 obj_props[PROP_MAX_LENGTH] = pspec;
3569 g_object_class_install_property (gobject_class, PROP_MAX_LENGTH, pspec);
3572 * ClutterText:single-line-mode:
3574 * Whether the #ClutterText actor should be in single line mode
3575 * or not. A single line #ClutterText actor will only contain a
3576 * single line of text, scrolling it in case its length is bigger
3577 * than the allocated size.
3579 * Setting this property will also set the #ClutterText:activatable
3580 * property as a side-effect.
3582 * The #ClutterText:single-line-mode property is used only if the
3583 * #ClutterText:editable property is set to %TRUE.
3587 pspec = g_param_spec_boolean ("single-line-mode",
3588 P_("Single Line Mode"),
3589 P_("Whether the text should be a single line"),
3591 CLUTTER_PARAM_READWRITE);
3592 obj_props[PROP_SINGLE_LINE_MODE] = pspec;
3593 g_object_class_install_property (gobject_class, PROP_SINGLE_LINE_MODE, pspec);
3596 * ClutterText:selected-text-color:
3598 * The color of selected text.
3602 pspec = clutter_param_spec_color ("selected-text-color",
3603 P_("Selected Text Color"),
3604 P_("Selected Text Color"),
3605 &default_selected_text_color,
3606 CLUTTER_PARAM_READWRITE |
3607 CLUTTER_PARAM_ANIMATABLE);
3608 obj_props[PROP_SELECTED_TEXT_COLOR] = pspec;
3609 g_object_class_install_property (gobject_class, PROP_SELECTED_TEXT_COLOR, pspec);
3612 * ClutterText:selected-text-color-set:
3614 * Will be set to %TRUE if #ClutterText:selected-text-color has been set.
3618 pspec = g_param_spec_boolean ("selected-text-color-set",
3619 P_("Selected Text Color Set"),
3620 P_("Whether the selected text color has been set"),
3622 CLUTTER_PARAM_READABLE);
3623 obj_props[PROP_SELECTED_TEXT_COLOR_SET] = pspec;
3624 g_object_class_install_property (gobject_class, PROP_SELECTED_TEXT_COLOR_SET, pspec);
3627 * ClutterText::text-changed:
3628 * @self: the #ClutterText that emitted the signal
3630 * The ::text-changed signal is emitted after @actor's text changes
3634 text_signals[TEXT_CHANGED] =
3635 g_signal_new (I_("text-changed"),
3636 G_TYPE_FROM_CLASS (gobject_class),
3638 G_STRUCT_OFFSET (ClutterTextClass, text_changed),
3640 _clutter_marshal_VOID__VOID,
3644 * ClutterText::insert-text:
3645 * @self: the #ClutterText that emitted the signal
3646 * @new_text: the new text to insert
3647 * @new_text_length: the length of the new text, in bytes, or -1 if
3648 * new_text is nul-terminated
3649 * @position: the position, in characters, at which to insert the
3650 * new text. this is an in-out parameter. After the signal
3651 * emission is finished, it should point after the newly
3654 * This signal is emitted when text is inserted into the actor by
3655 * the user. It is emitted before @self text changes.
3659 text_signals[INSERT_TEXT] =
3660 g_signal_new (I_("insert-text"),
3661 G_TYPE_FROM_CLASS (gobject_class),
3662 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
3665 _clutter_marshal_VOID__STRING_INT_POINTER,
3672 * ClutterText::delete-text:
3673 * @self: the #ClutterText that emitted the signal
3674 * @start_pos: the starting position
3675 * @end_pos: the end position
3677 * This signal is emitted when text is deleted from the actor by
3678 * the user. It is emitted before @self text changes.
3682 text_signals[DELETE_TEXT] =
3683 g_signal_new (I_("delete-text"),
3684 G_TYPE_FROM_CLASS (gobject_class),
3685 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
3688 _clutter_marshal_VOID__INT_INT,
3694 * ClutterText::cursor-event:
3695 * @self: the #ClutterText that emitted the signal
3696 * @geometry: the coordinates of the cursor
3698 * The ::cursor-event signal is emitted whenever the cursor position
3699 * changes inside a #ClutterText actor. Inside @geometry it is stored
3700 * the current position and size of the cursor, relative to the actor
3705 text_signals[CURSOR_EVENT] =
3706 g_signal_new (I_("cursor-event"),
3707 G_TYPE_FROM_CLASS (gobject_class),
3709 G_STRUCT_OFFSET (ClutterTextClass, cursor_event),
3711 _clutter_marshal_VOID__BOXED,
3713 CLUTTER_TYPE_GEOMETRY | G_SIGNAL_TYPE_STATIC_SCOPE);
3716 * ClutterText::activate:
3717 * @self: the #ClutterText that emitted the signal
3719 * The ::activate signal is emitted each time the actor is 'activated'
3720 * by the user, normally by pressing the 'Enter' key. The signal is
3721 * emitted only if #ClutterText:activatable is set to %TRUE.
3725 text_signals[ACTIVATE] =
3726 g_signal_new (I_("activate"),
3727 G_TYPE_FROM_CLASS (gobject_class),
3729 G_STRUCT_OFFSET (ClutterTextClass, activate),
3731 _clutter_marshal_VOID__VOID,
3734 binding_pool = clutter_binding_pool_get_for_class (klass);
3736 clutter_text_add_move_binding (binding_pool, "move-left",
3737 CLUTTER_KEY_Left, CLUTTER_CONTROL_MASK,
3738 G_CALLBACK (clutter_text_real_move_left));
3739 clutter_text_add_move_binding (binding_pool, "move-left",
3740 CLUTTER_KEY_KP_Left, CLUTTER_CONTROL_MASK,
3741 G_CALLBACK (clutter_text_real_move_left));
3742 clutter_text_add_move_binding (binding_pool, "move-right",
3743 CLUTTER_KEY_Right, CLUTTER_CONTROL_MASK,
3744 G_CALLBACK (clutter_text_real_move_right));
3745 clutter_text_add_move_binding (binding_pool, "move-right",
3746 CLUTTER_KEY_KP_Right, CLUTTER_CONTROL_MASK,
3747 G_CALLBACK (clutter_text_real_move_right));
3748 clutter_text_add_move_binding (binding_pool, "move-up",
3750 G_CALLBACK (clutter_text_real_move_up));
3751 clutter_text_add_move_binding (binding_pool, "move-up",
3752 CLUTTER_KEY_KP_Up, 0,
3753 G_CALLBACK (clutter_text_real_move_up));
3754 clutter_text_add_move_binding (binding_pool, "move-down",
3755 CLUTTER_KEY_Down, 0,
3756 G_CALLBACK (clutter_text_real_move_down));
3757 clutter_text_add_move_binding (binding_pool, "move-down",
3758 CLUTTER_KEY_KP_Down, 0,
3759 G_CALLBACK (clutter_text_real_move_down));
3761 clutter_text_add_move_binding (binding_pool, "line-start",
3762 CLUTTER_KEY_Home, 0,
3763 G_CALLBACK (clutter_text_real_line_start));
3764 clutter_text_add_move_binding (binding_pool, "line-start",
3765 CLUTTER_KEY_KP_Home, 0,
3766 G_CALLBACK (clutter_text_real_line_start));
3767 clutter_text_add_move_binding (binding_pool, "line-start",
3768 CLUTTER_KEY_Begin, 0,
3769 G_CALLBACK (clutter_text_real_line_start));
3770 clutter_text_add_move_binding (binding_pool, "line-end",
3772 G_CALLBACK (clutter_text_real_line_end));
3773 clutter_text_add_move_binding (binding_pool, "line-end",
3774 CLUTTER_KEY_KP_End, 0,
3775 G_CALLBACK (clutter_text_real_line_end));
3777 clutter_binding_pool_install_action (binding_pool, "select-all",
3778 CLUTTER_KEY_a, CLUTTER_CONTROL_MASK,
3779 G_CALLBACK (clutter_text_real_select_all),
3782 clutter_binding_pool_install_action (binding_pool, "delete-next",
3783 CLUTTER_KEY_Delete, 0,
3784 G_CALLBACK (clutter_text_real_del_next),
3786 clutter_binding_pool_install_action (binding_pool, "delete-next",
3787 CLUTTER_KEY_Delete, CLUTTER_CONTROL_MASK,
3788 G_CALLBACK (clutter_text_real_del_word_next),
3790 clutter_binding_pool_install_action (binding_pool, "delete-next",
3791 CLUTTER_KEY_KP_Delete, 0,
3792 G_CALLBACK (clutter_text_real_del_next),
3794 clutter_binding_pool_install_action (binding_pool, "delete-next",
3795 CLUTTER_KEY_KP_Delete, CLUTTER_CONTROL_MASK,
3796 G_CALLBACK (clutter_text_real_del_word_next),
3798 clutter_binding_pool_install_action (binding_pool, "delete-prev",
3799 CLUTTER_KEY_BackSpace, 0,
3800 G_CALLBACK (clutter_text_real_del_prev),
3802 clutter_binding_pool_install_action (binding_pool, "delete-prev",
3803 CLUTTER_KEY_BackSpace, CLUTTER_SHIFT_MASK,
3804 G_CALLBACK (clutter_text_real_del_prev),
3806 clutter_binding_pool_install_action (binding_pool, "delete-prev",
3807 CLUTTER_KEY_BackSpace, CLUTTER_CONTROL_MASK,
3808 G_CALLBACK (clutter_text_real_del_word_prev),
3811 clutter_binding_pool_install_action (binding_pool, "activate",
3812 CLUTTER_KEY_Return, 0,
3813 G_CALLBACK (clutter_text_real_activate),
3815 clutter_binding_pool_install_action (binding_pool, "activate",
3816 CLUTTER_KEY_KP_Enter, 0,
3817 G_CALLBACK (clutter_text_real_activate),
3819 clutter_binding_pool_install_action (binding_pool, "activate",
3820 CLUTTER_KEY_ISO_Enter, 0,
3821 G_CALLBACK (clutter_text_real_activate),
3826 clutter_text_init (ClutterText *self)
3828 ClutterSettings *settings;
3829 ClutterTextPrivate *priv;
3831 int i, password_hint_time;
3833 self->priv = priv = CLUTTER_TEXT_GET_PRIVATE (self);
3835 priv->alignment = PANGO_ALIGN_LEFT;
3837 priv->wrap_mode = PANGO_WRAP_WORD;
3838 priv->ellipsize = PANGO_ELLIPSIZE_NONE;
3839 priv->use_underline = FALSE;
3840 priv->use_markup = FALSE;
3841 priv->justify = FALSE;
3843 for (i = 0; i < N_CACHED_LAYOUTS; i++)
3844 priv->cached_layouts[i].layout = NULL;
3846 /* default to "" so that clutter_text_get_text() will
3847 * return a valid string and we can safely call strlen()
3850 priv->buffer = NULL;
3852 priv->text_color = default_text_color;
3853 priv->cursor_color = default_cursor_color;
3854 priv->selection_color = default_selection_color;
3855 priv->selected_text_color = default_selected_text_color;
3857 /* get the default font name from the context; we don't use
3858 * set_font_description() here because we are initializing
3859 * the Text and we don't need notifications and sanity checks
3861 settings = clutter_settings_get_default ();
3862 g_object_get (settings,
3863 "font-name", &font_name,
3864 "password-hint-time", &password_hint_time,
3867 priv->font_name = font_name; /* font_name is allocated */
3868 priv->font_desc = pango_font_description_from_string (font_name);
3869 priv->is_default_font = TRUE;
3871 priv->position = -1;
3872 priv->selection_bound = -1;
3875 priv->cursor_visible = TRUE;
3876 priv->editable = FALSE;
3877 priv->selectable = TRUE;
3879 priv->selection_color_set = FALSE;
3880 priv->cursor_color_set = FALSE;
3881 priv->selected_text_color_set = FALSE;
3882 priv->preedit_set = FALSE;
3884 priv->password_char = 0;
3885 priv->show_password_hint = password_hint_time > 0;
3886 priv->password_hint_timeout = password_hint_time;
3890 priv->cursor_size = DEFAULT_CURSOR_SIZE;
3891 memset (&priv->cursor_pos, 0, sizeof (ClutterGeometry));
3893 priv->settings_changed_id =
3894 g_signal_connect_swapped (clutter_get_default_backend (),
3896 G_CALLBACK (clutter_text_settings_changed_cb),
3899 priv->direction_changed_id =
3900 g_signal_connect (self, "notify::text-direction",
3901 G_CALLBACK (clutter_text_direction_changed_cb),
3908 * Creates a new #ClutterText actor. This actor can be used to
3909 * display and edit text.
3911 * Return value: the newly created #ClutterText actor
3916 clutter_text_new (void)
3918 return g_object_new (CLUTTER_TYPE_TEXT, NULL);
3922 * clutter_text_new_full:
3923 * @font_name: a string with a font description
3924 * @text: the contents of the actor
3925 * @color: the color to be used to render @text
3927 * Creates a new #ClutterText actor, using @font_name as the font
3928 * description; @text will be used to set the contents of the actor;
3929 * and @color will be used as the color to render @text.
3931 * This function is equivalent to calling clutter_text_new(),
3932 * clutter_text_set_font_name(), clutter_text_set_text() and
3933 * clutter_text_set_color().
3935 * Return value: the newly created #ClutterText actor
3940 clutter_text_new_full (const gchar *font_name,
3942 const ClutterColor *color)
3944 return g_object_new (CLUTTER_TYPE_TEXT,
3945 "font-name", font_name,
3952 * clutter_text_new_with_text:
3953 * @font_name: (allow-none): a string with a font description
3954 * @text: the contents of the actor
3956 * Creates a new #ClutterText actor, using @font_name as the font
3957 * description; @text will be used to set the contents of the actor.
3959 * This function is equivalent to calling clutter_text_new(),
3960 * clutter_text_set_font_name(), and clutter_text_set_text().
3962 * Return value: the newly created #ClutterText actor
3967 clutter_text_new_with_text (const gchar *font_name,
3970 return g_object_new (CLUTTER_TYPE_TEXT,
3971 "font-name", font_name,
3976 static ClutterTextBuffer*
3977 get_buffer (ClutterText *self)
3979 ClutterTextPrivate *priv = self->priv;
3981 if (priv->buffer == NULL)
3983 ClutterTextBuffer *buffer;
3984 buffer = clutter_text_buffer_new ();
3985 clutter_text_set_buffer (self, buffer);
3986 g_object_unref (buffer);
3989 return priv->buffer;
3992 /* GtkEntryBuffer signal handlers
3995 buffer_inserted_text (ClutterTextBuffer *buffer,
4001 ClutterTextPrivate *priv;
4003 gint new_selection_bound;
4007 if (priv->position >= 0 || priv->selection_bound >= 0)
4009 new_position = priv->position;
4010 new_selection_bound = priv->selection_bound;
4012 if (position <= new_position)
4013 new_position += n_chars;
4014 if (position <= new_selection_bound)
4015 new_selection_bound += n_chars;
4017 if (priv->position != new_position || priv->selection_bound != new_selection_bound)
4018 clutter_text_set_positions (self, new_position, new_selection_bound);
4021 n_bytes = g_utf8_offset_to_pointer (chars, n_chars) - chars;
4022 g_signal_emit (self, text_signals[INSERT_TEXT], 0, chars,
4023 n_bytes, &position);
4025 /* TODO: What are we supposed to with the out value of position? */
4029 buffer_deleted_text (ClutterTextBuffer *buffer,
4034 ClutterTextPrivate *priv;
4036 gint new_selection_bound;
4039 if (priv->position >= 0 || priv->selection_bound >= 0)
4041 new_position = priv->position;
4042 new_selection_bound = priv->selection_bound;
4044 if (position < new_position)
4045 new_position -= n_chars;
4046 if (position < new_selection_bound)
4047 new_selection_bound -= n_chars;
4049 if (priv->position != new_position || priv->selection_bound != new_selection_bound)
4050 clutter_text_set_positions (self, new_position, new_selection_bound);
4053 g_signal_emit (self, text_signals[DELETE_TEXT], 0, position, position + n_chars);
4057 buffer_notify_text (ClutterTextBuffer *buffer,
4061 g_object_freeze_notify (G_OBJECT (self));
4063 clutter_text_dirty_cache (self);
4065 clutter_actor_queue_relayout (CLUTTER_ACTOR (self));
4067 g_signal_emit (self, text_signals[TEXT_CHANGED], 0);
4068 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_TEXT]);
4070 g_object_thaw_notify (G_OBJECT (self));
4074 buffer_notify_max_length (ClutterTextBuffer *buffer,
4078 g_object_notify (G_OBJECT (self), "max-length");
4082 buffer_connect_signals (ClutterText *self)
4084 ClutterTextPrivate *priv = self->priv;
4085 g_signal_connect (priv->buffer, "inserted-text", G_CALLBACK (buffer_inserted_text), self);
4086 g_signal_connect (priv->buffer, "deleted-text", G_CALLBACK (buffer_deleted_text), self);
4087 g_signal_connect (priv->buffer, "notify::text", G_CALLBACK (buffer_notify_text), self);
4088 g_signal_connect (priv->buffer, "notify::max-length", G_CALLBACK (buffer_notify_max_length), self);
4092 buffer_disconnect_signals (ClutterText *self)
4094 ClutterTextPrivate *priv = self->priv;
4095 g_signal_handlers_disconnect_by_func (priv->buffer, buffer_inserted_text, self);
4096 g_signal_handlers_disconnect_by_func (priv->buffer, buffer_deleted_text, self);
4097 g_signal_handlers_disconnect_by_func (priv->buffer, buffer_notify_text, self);
4098 g_signal_handlers_disconnect_by_func (priv->buffer, buffer_notify_max_length, self);
4102 * clutter_text_new_with_buffer:
4103 * @buffer: The buffer to use for the new #ClutterText.
4105 * Creates a new entry with the specified text buffer.
4107 * Return value: a new #ClutterText
4112 clutter_text_new_with_buffer (ClutterTextBuffer *buffer)
4114 g_return_val_if_fail (CLUTTER_IS_TEXT_BUFFER (buffer), NULL);
4115 return g_object_new (CLUTTER_TYPE_TEXT, "buffer", buffer, NULL);
4119 * clutter_text_get_buffer:
4120 * @self: a #ClutterText
4122 * Get the #ClutterTextBuffer object which holds the text for
4125 * Returns: (transfer none): A #GtkEntryBuffer object.
4130 clutter_text_get_buffer (ClutterText *self)
4132 g_return_val_if_fail (CLUTTER_IS_TEXT (self), NULL);
4134 return get_buffer (self);
4138 * clutter_text_set_buffer:
4139 * @self: a #ClutterText
4140 * @buffer: a #ClutterTextBuffer
4142 * Set the #ClutterTextBuffer object which holds the text for
4148 clutter_text_set_buffer (ClutterText *self,
4149 ClutterTextBuffer *buffer)
4151 ClutterTextPrivate *priv;
4154 g_return_if_fail (CLUTTER_IS_TEXT (self));
4160 g_return_if_fail (CLUTTER_IS_TEXT_BUFFER (buffer));
4161 g_object_ref (buffer);
4166 buffer_disconnect_signals (self);
4167 g_object_unref (priv->buffer);
4170 priv->buffer = buffer;
4173 buffer_connect_signals (self);
4175 obj = G_OBJECT (self);
4176 g_object_freeze_notify (obj);
4177 g_object_notify (obj, "buffer");
4178 g_object_notify (obj, "text");
4179 g_object_notify (obj, "max-length");
4180 g_object_thaw_notify (obj);
4184 * clutter_text_set_editable:
4185 * @self: a #ClutterText
4186 * @editable: whether the #ClutterText should be editable
4188 * Sets whether the #ClutterText actor should be editable.
4190 * An editable #ClutterText with key focus set using
4191 * clutter_actor_grab_key_focus() or clutter_stage_set_key_focus()
4192 * will receive key events and will update its contents accordingly.
4197 clutter_text_set_editable (ClutterText *self,
4200 ClutterTextPrivate *priv;
4202 g_return_if_fail (CLUTTER_IS_TEXT (self));
4206 if (priv->editable != editable)
4208 priv->editable = editable;
4210 clutter_text_queue_redraw (CLUTTER_ACTOR (self));
4212 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EDITABLE]);
4217 * clutter_text_get_editable:
4218 * @self: a #ClutterText
4220 * Retrieves whether a #ClutterText is editable or not.
4222 * Return value: %TRUE if the actor is editable
4227 clutter_text_get_editable (ClutterText *self)
4229 g_return_val_if_fail (CLUTTER_IS_TEXT (self), FALSE);
4231 return self->priv->editable;
4235 * clutter_text_set_selectable:
4236 * @self: a #ClutterText
4237 * @selectable: whether the #ClutterText actor should be selectable
4239 * Sets whether a #ClutterText actor should be selectable.
4241 * A selectable #ClutterText will allow selecting its contents using
4242 * the pointer or the keyboard.
4247 clutter_text_set_selectable (ClutterText *self,
4248 gboolean selectable)
4250 ClutterTextPrivate *priv;
4252 g_return_if_fail (CLUTTER_IS_TEXT (self));
4256 if (priv->selectable != selectable)
4258 priv->selectable = selectable;
4260 clutter_text_queue_redraw (CLUTTER_ACTOR (self));
4262 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_SELECTABLE]);
4267 * clutter_text_get_selectable:
4268 * @self: a #ClutterText
4270 * Retrieves whether a #ClutterText is selectable or not.
4272 * Return value: %TRUE if the actor is selectable
4277 clutter_text_get_selectable (ClutterText *self)
4279 g_return_val_if_fail (CLUTTER_IS_TEXT (self), TRUE);
4281 return self->priv->selectable;
4285 * clutter_text_set_activatable:
4286 * @self: a #ClutterText
4287 * @activatable: whether the #ClutterText actor should be activatable
4289 * Sets whether a #ClutterText actor should be activatable.
4291 * An activatable #ClutterText actor will emit the #ClutterText::activate
4292 * signal whenever the 'Enter' (or 'Return') key is pressed; if it is not
4293 * activatable, a new line will be appended to the current content.
4295 * An activatable #ClutterText must also be set as editable using
4296 * clutter_text_set_editable().
4301 clutter_text_set_activatable (ClutterText *self,
4302 gboolean activatable)
4304 ClutterTextPrivate *priv;
4306 g_return_if_fail (CLUTTER_IS_TEXT (self));
4310 if (priv->activatable != activatable)
4312 priv->activatable = activatable;
4314 clutter_text_queue_redraw (CLUTTER_ACTOR (self));
4316 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIVATABLE]);
4321 * clutter_text_get_activatable:
4322 * @self: a #ClutterText
4324 * Retrieves whether a #ClutterText is activatable or not.
4326 * Return value: %TRUE if the actor is activatable
4331 clutter_text_get_activatable (ClutterText *self)
4333 g_return_val_if_fail (CLUTTER_IS_TEXT (self), TRUE);
4335 return self->priv->activatable;
4339 * clutter_text_activate:
4340 * @self: a #ClutterText
4342 * Emits the #ClutterText::activate signal, if @self has been set
4343 * as activatable using clutter_text_set_activatable().
4345 * This function can be used to emit the ::activate signal inside
4346 * a #ClutterActor::captured-event or #ClutterActor::key-press-event
4347 * signal handlers before the default signal handler for the
4348 * #ClutterText is invoked.
4350 * Return value: %TRUE if the ::activate signal has been emitted,
4351 * and %FALSE otherwise
4356 clutter_text_activate (ClutterText *self)
4358 ClutterTextPrivate *priv;
4360 g_return_val_if_fail (CLUTTER_IS_TEXT (self), FALSE);
4364 if (priv->activatable)
4366 g_signal_emit (self, text_signals[ACTIVATE], 0);
4374 * clutter_text_set_cursor_visible:
4375 * @self: a #ClutterText
4376 * @cursor_visible: whether the cursor should be visible
4378 * Sets whether the cursor of a #ClutterText actor should be
4381 * The color of the cursor will be the same as the text color
4382 * unless clutter_text_set_cursor_color() has been called.
4384 * The size of the cursor can be set using clutter_text_set_cursor_size().
4386 * The position of the cursor can be changed programmatically using
4387 * clutter_text_set_cursor_position().
4392 clutter_text_set_cursor_visible (ClutterText *self,
4393 gboolean cursor_visible)
4395 ClutterTextPrivate *priv;
4397 g_return_if_fail (CLUTTER_IS_TEXT (self));
4401 if (priv->cursor_visible != cursor_visible)
4403 priv->cursor_visible = cursor_visible;
4405 clutter_text_queue_redraw (CLUTTER_ACTOR (self));
4407 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CURSOR_VISIBLE]);
4412 * clutter_text_get_cursor_visible:
4413 * @self: a #ClutterText
4415 * Retrieves whether the cursor of a #ClutterText actor is visible.
4417 * Return value: %TRUE if the cursor is visible
4422 clutter_text_get_cursor_visible (ClutterText *self)
4424 g_return_val_if_fail (CLUTTER_IS_TEXT (self), TRUE);
4426 return self->priv->cursor_visible;
4430 * clutter_text_set_cursor_color:
4431 * @self: a #ClutterText
4432 * @color: (allow-none): the color of the cursor, or %NULL to unset it
4434 * Sets the color of the cursor of a #ClutterText actor.
4436 * If @color is %NULL, the cursor color will be the same as the
4442 clutter_text_set_cursor_color (ClutterText *self,
4443 const ClutterColor *color)
4445 g_return_if_fail (CLUTTER_IS_TEXT (self));
4447 clutter_text_set_color_animated (self, obj_props[PROP_CURSOR_COLOR], color);
4451 * clutter_text_get_cursor_color:
4452 * @self: a #ClutterText
4453 * @color: (out): return location for a #ClutterColor
4455 * Retrieves the color of the cursor of a #ClutterText actor.
4460 clutter_text_get_cursor_color (ClutterText *self,
4461 ClutterColor *color)
4463 ClutterTextPrivate *priv;
4465 g_return_if_fail (CLUTTER_IS_TEXT (self));
4466 g_return_if_fail (color != NULL);
4470 *color = priv->cursor_color;
4474 * clutter_text_set_selection:
4475 * @self: a #ClutterText
4476 * @start_pos: start of the selection, in characters
4477 * @end_pos: end of the selection, in characters
4479 * Selects the region of text between @start_pos and @end_pos.
4481 * This function changes the position of the cursor to match
4482 * @start_pos and the selection bound to match @end_pos.
4487 clutter_text_set_selection (ClutterText *self,
4493 g_return_if_fail (CLUTTER_IS_TEXT (self));
4495 n_chars = clutter_text_buffer_get_length (get_buffer (self));
4499 start_pos = MIN (n_chars, start_pos);
4500 end_pos = MIN (n_chars, end_pos);
4502 clutter_text_set_positions (self, start_pos, end_pos);
4506 * clutter_text_get_selection:
4507 * @self: a #ClutterText
4509 * Retrieves the currently selected text.
4511 * Return value: a newly allocated string containing the currently
4512 * selected text, or %NULL. Use g_free() to free the returned
4518 clutter_text_get_selection (ClutterText *self)
4520 ClutterTextPrivate *priv;
4523 gint start_index, end_index;
4524 gint start_offset, end_offset;
4527 g_return_val_if_fail (CLUTTER_IS_TEXT (self), NULL);
4531 start_index = priv->position;
4532 end_index = priv->selection_bound;
4534 if (end_index == start_index)
4535 return g_strdup ("");
4537 if ((end_index != -1 && end_index < start_index) ||
4540 gint temp = start_index;
4541 start_index = end_index;
4545 text = clutter_text_buffer_get_text (get_buffer (self));
4546 start_offset = offset_to_bytes (text, start_index);
4547 end_offset = offset_to_bytes (text, end_index);
4548 len = end_offset - start_offset;
4550 str = g_malloc (len + 1);
4551 g_utf8_strncpy (str, text + start_offset, end_index - start_index);
4557 * clutter_text_set_selection_bound:
4558 * @self: a #ClutterText
4559 * @selection_bound: the position of the end of the selection, in characters
4561 * Sets the other end of the selection, starting from the current
4564 * If @selection_bound is -1, the selection unset.
4569 clutter_text_set_selection_bound (ClutterText *self,
4570 gint selection_bound)
4572 ClutterTextPrivate *priv;
4574 g_return_if_fail (CLUTTER_IS_TEXT (self));
4578 if (priv->selection_bound != selection_bound)
4580 gint len = clutter_text_buffer_get_length (get_buffer (self));;
4582 if (selection_bound < 0 || selection_bound >= len)
4583 priv->selection_bound = -1;
4585 priv->selection_bound = selection_bound;
4587 clutter_text_queue_redraw (CLUTTER_ACTOR (self));
4589 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_SELECTION_BOUND]);
4594 * clutter_text_get_selection_bound:
4595 * @self: a #ClutterText
4597 * Retrieves the other end of the selection of a #ClutterText actor,
4598 * in characters from the current cursor position.
4600 * Return value: the position of the other end of the selection
4605 clutter_text_get_selection_bound (ClutterText *self)
4607 g_return_val_if_fail (CLUTTER_IS_TEXT (self), -1);
4609 return self->priv->selection_bound;
4613 * clutter_text_set_selection_color:
4614 * @self: a #ClutterText
4615 * @color: (allow-none): the color of the selection, or %NULL to unset it
4617 * Sets the color of the selection of a #ClutterText actor.
4619 * If @color is %NULL, the selection color will be the same as the
4620 * cursor color, or if no cursor color is set either then it will be
4621 * the same as the text color.
4626 clutter_text_set_selection_color (ClutterText *self,
4627 const ClutterColor *color)
4629 g_return_if_fail (CLUTTER_IS_TEXT (self));
4631 clutter_text_set_color_animated (self, obj_props[PROP_SELECTION_COLOR],
4636 * clutter_text_get_selection_color:
4637 * @self: a #ClutterText
4638 * @color: (out caller-allocates): return location for a #ClutterColor
4640 * Retrieves the color of the selection of a #ClutterText actor.
4645 clutter_text_get_selection_color (ClutterText *self,
4646 ClutterColor *color)
4648 ClutterTextPrivate *priv;
4650 g_return_if_fail (CLUTTER_IS_TEXT (self));
4651 g_return_if_fail (color != NULL);
4655 *color = priv->selection_color;
4659 * clutter_text_set_selected_text_color:
4660 * @self: a #ClutterText
4661 * @color: (allow-none): the selected text color, or %NULL to unset it
4663 * Sets the selected text color of a #ClutterText actor.
4665 * If @color is %NULL, the selected text color will be the same as the
4666 * selection color, which then falls back to cursor, and then text color.
4671 clutter_text_set_selected_text_color (ClutterText *self,
4672 const ClutterColor *color)
4674 g_return_if_fail (CLUTTER_IS_TEXT (self));
4676 clutter_text_set_color_animated (self, obj_props[PROP_SELECTED_TEXT_COLOR],
4681 * clutter_text_get_selected_text_color:
4682 * @self: a #ClutterText
4683 * @color: (out caller-allocates): return location for a #ClutterColor
4685 * Retrieves the color of selected text of a #ClutterText actor.
4690 clutter_text_get_selected_text_color (ClutterText *self,
4691 ClutterColor *color)
4693 ClutterTextPrivate *priv;
4695 g_return_if_fail (CLUTTER_IS_TEXT (self));
4696 g_return_if_fail (color != NULL);
4700 *color = priv->selected_text_color;
4704 * clutter_text_set_font_description:
4705 * @self: a #ClutterText
4706 * @font_desc: a #PangoFontDescription
4708 * Sets @font_desc as the font description for a #ClutterText
4710 * The #PangoFontDescription is copied by the #ClutterText actor
4711 * so you can safely call pango_font_description_free() on it after
4712 * calling this function.
4717 clutter_text_set_font_description (ClutterText *self,
4718 PangoFontDescription *font_desc)
4720 PangoFontDescription *copy;
4722 g_return_if_fail (CLUTTER_IS_TEXT (self));
4724 copy = pango_font_description_copy (font_desc);
4725 clutter_text_set_font_description_internal (self, copy);
4729 * clutter_text_get_font_description:
4730 * @self: a #ClutterText
4732 * Retrieves the #PangoFontDescription used by @self
4734 * Return value: a #PangoFontDescription. The returned value is owned
4735 * by the #ClutterText actor and it should not be modified or freed
4739 PangoFontDescription *
4740 clutter_text_get_font_description (ClutterText *self)
4742 g_return_val_if_fail (CLUTTER_IS_TEXT (self), NULL);
4744 return self->priv->font_desc;
4748 * clutter_text_get_font_name:
4749 * @self: a #ClutterText
4751 * Retrieves the font name as set by clutter_text_set_font_name().
4753 * Return value: a string containing the font name. The returned
4754 * string is owned by the #ClutterText actor and should not be
4760 clutter_text_get_font_name (ClutterText *text)
4762 g_return_val_if_fail (CLUTTER_IS_TEXT (text), NULL);
4764 return text->priv->font_name;
4768 * clutter_text_set_font_name:
4769 * @self: a #ClutterText
4770 * @font_name: (allow-none): a font name, or %NULL to set the default font name
4772 * Sets the font used by a #ClutterText. The @font_name string
4773 * must either be %NULL, which means that the font name from the
4774 * default #ClutterBackend will be used; or be something that can
4775 * be parsed by the pango_font_description_from_string() function,
4779 * clutter_text_set_font_name (text, "Sans 10pt");
4780 * clutter_text_set_font_name (text, "Serif 16px");
4781 * clutter_text_set_font_name (text, "Helvetica 10");
4787 clutter_text_set_font_name (ClutterText *self,
4788 const gchar *font_name)
4790 ClutterTextPrivate *priv;
4791 PangoFontDescription *desc;
4792 gboolean is_default_font;
4794 g_return_if_fail (CLUTTER_IS_TEXT (self));
4796 /* get the default font name from the backend */
4797 if (font_name == NULL || font_name[0] == '\0')
4799 ClutterSettings *settings = clutter_settings_get_default ();
4800 gchar *default_font_name = NULL;
4802 g_object_get (settings, "font-name", &default_font_name, NULL);
4804 if (default_font_name != NULL)
4805 font_name = default_font_name;
4809 default_font_name = g_strdup ("Sans 12");
4812 is_default_font = TRUE;
4815 is_default_font = FALSE;
4819 if (g_strcmp0 (priv->font_name, font_name) == 0)
4822 desc = pango_font_description_from_string (font_name);
4825 g_warning ("Attempting to create a PangoFontDescription for "
4826 "font name '%s', but failed.",
4831 /* this will set the font_name field as well */
4832 clutter_text_set_font_description_internal (self, desc);
4833 priv->is_default_font = is_default_font;
4835 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FONT_NAME]);
4838 if (is_default_font)
4839 g_free ((gchar *) font_name);
4843 * clutter_text_get_text:
4844 * @self: a #ClutterText
4846 * Retrieves a pointer to the current contents of a #ClutterText
4849 * If you need a copy of the contents for manipulating, either
4850 * use g_strdup() on the returned string, or use:
4853 * copy = clutter_text_get_chars (text, 0, -1);
4856 * Which will return a newly allocated string.
4858 * If the #ClutterText actor is empty, this function will return
4859 * an empty string, and not %NULL.
4861 * Return value: (transfer none): the contents of the actor. The returned
4862 * string is owned by the #ClutterText actor and should never be modified
4868 clutter_text_get_text (ClutterText *self)
4870 g_return_val_if_fail (CLUTTER_IS_TEXT (self), NULL);
4872 return clutter_text_buffer_get_text (get_buffer (self));
4876 clutter_text_set_use_markup_internal (ClutterText *self,
4877 gboolean use_markup)
4879 ClutterTextPrivate *priv = self->priv;
4881 if (priv->use_markup != use_markup)
4883 priv->use_markup = use_markup;
4885 /* reset the attributes lists so that they can be
4888 if (priv->effective_attrs != NULL)
4890 pango_attr_list_unref (priv->effective_attrs);
4891 priv->effective_attrs = NULL;
4894 if (priv->markup_attrs)
4896 pango_attr_list_unref (priv->markup_attrs);
4897 priv->markup_attrs = NULL;
4900 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_USE_MARKUP]);
4905 * clutter_text_set_text:
4906 * @self: a #ClutterText
4907 * @text: (allow-none): the text to set. Passing %NULL is the same
4908 * as passing "" (the empty string)
4910 * Sets the contents of a #ClutterText actor.
4912 * If the #ClutterText:use-markup property was set to %TRUE it
4913 * will be reset to %FALSE as a side effect. If you want to
4914 * maintain the #ClutterText:use-markup you should use the
4915 * clutter_text_set_markup() function instead
4920 clutter_text_set_text (ClutterText *self,
4923 g_return_if_fail (CLUTTER_IS_TEXT (self));
4925 /* if the text is editable (i.e. there is not markup flag to reset) then
4926 * changing the contents will result in selection and cursor changes that
4929 if (self->priv->editable)
4931 if (g_strcmp0 (clutter_text_buffer_get_text (get_buffer (self)), text) == 0)
4935 clutter_text_set_use_markup_internal (self, FALSE);
4936 clutter_text_buffer_set_text (get_buffer (self), text ? text : "", -1);
4940 * clutter_text_set_markup:
4941 * @self: a #ClutterText
4942 * @markup: (allow-none): a string containing Pango markup.
4943 * Passing %NULL is the same as passing "" (the empty string)
4945 * Sets @markup as the contents of a #ClutterText.
4947 * This is a convenience function for setting a string containing
4948 * Pango markup, and it is logically equivalent to:
4951 * /* the order is important */
4952 * clutter_text_set_text (CLUTTER_TEXT (actor), markup);
4953 * clutter_text_set_use_markup (CLUTTER_TEXT (actor), TRUE);
4959 clutter_text_set_markup (ClutterText *self,
4960 const gchar *markup)
4962 g_return_if_fail (CLUTTER_IS_TEXT (self));
4964 clutter_text_set_use_markup_internal (self, TRUE);
4965 if (markup != NULL && *markup != '\0')
4966 clutter_text_set_markup_internal (self, markup);
4968 clutter_text_buffer_set_text (get_buffer (self), "", 0);
4972 * clutter_text_get_layout:
4973 * @self: a #ClutterText
4975 * Retrieves the current #PangoLayout used by a #ClutterText actor.
4977 * Return value: (transfer none): a #PangoLayout. The returned object is owned by
4978 * the #ClutterText actor and should not be modified or freed
4983 clutter_text_get_layout (ClutterText *self)
4985 gfloat width, height;
4987 g_return_val_if_fail (CLUTTER_IS_TEXT (self), NULL);
4989 if (self->priv->editable && self->priv->single_line_mode)
4990 return clutter_text_create_layout (self, -1, -1);
4992 clutter_actor_get_size (CLUTTER_ACTOR (self), &width, &height);
4994 return clutter_text_create_layout (self, width, height);
4998 * clutter_text_set_color:
4999 * @self: a #ClutterText
5000 * @color: a #ClutterColor
5002 * Sets the color of the contents of a #ClutterText actor.
5004 * The overall opacity of the #ClutterText actor will be the
5005 * result of the alpha value of @color and the composited
5006 * opacity of the actor itself on the scenegraph, as returned
5007 * by clutter_actor_get_paint_opacity().
5012 clutter_text_set_color (ClutterText *self,
5013 const ClutterColor *color)
5015 g_return_if_fail (CLUTTER_IS_TEXT (self));
5016 g_return_if_fail (color != NULL);
5018 clutter_text_set_color_animated (self, obj_props[PROP_COLOR], color);
5022 * clutter_text_get_color:
5023 * @self: a #ClutterText
5024 * @color: (out caller-allocates): return location for a #ClutterColor
5026 * Retrieves the text color as set by clutter_text_set_color().
5031 clutter_text_get_color (ClutterText *self,
5032 ClutterColor *color)
5034 ClutterTextPrivate *priv;
5036 g_return_if_fail (CLUTTER_IS_TEXT (self));
5037 g_return_if_fail (color != NULL);
5041 *color = priv->text_color;
5045 * clutter_text_set_ellipsize:
5046 * @self: a #ClutterText
5047 * @mode: a #PangoEllipsizeMode
5049 * Sets the mode used to ellipsize (add an ellipsis: "...") to the
5050 * text if there is not enough space to render the entire contents
5051 * of a #ClutterText actor
5056 clutter_text_set_ellipsize (ClutterText *self,
5057 PangoEllipsizeMode mode)
5059 ClutterTextPrivate *priv;
5061 g_return_if_fail (CLUTTER_IS_TEXT (self));
5062 g_return_if_fail (mode >= PANGO_ELLIPSIZE_NONE &&
5063 mode <= PANGO_ELLIPSIZE_END);
5067 if ((PangoEllipsizeMode) priv->ellipsize != mode)
5069 priv->ellipsize = mode;
5071 clutter_text_dirty_cache (self);
5073 clutter_actor_queue_relayout (CLUTTER_ACTOR (self));
5075 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ELLIPSIZE]);
5080 * clutter_text_get_ellipsize:
5081 * @self: a #ClutterText
5083 * Returns the ellipsizing position of a #ClutterText actor, as
5084 * set by clutter_text_set_ellipsize().
5086 * Return value: #PangoEllipsizeMode
5091 clutter_text_get_ellipsize (ClutterText *self)
5093 g_return_val_if_fail (CLUTTER_IS_TEXT (self), PANGO_ELLIPSIZE_NONE);
5095 return self->priv->ellipsize;
5099 * clutter_text_get_line_wrap:
5100 * @self: a #ClutterText
5102 * Retrieves the value set using clutter_text_set_line_wrap().
5104 * Return value: %TRUE if the #ClutterText actor should wrap
5110 clutter_text_get_line_wrap (ClutterText *self)
5112 g_return_val_if_fail (CLUTTER_IS_TEXT (self), FALSE);
5114 return self->priv->wrap;
5118 * clutter_text_set_line_wrap:
5119 * @self: a #ClutterText
5120 * @line_wrap: whether the contents should wrap
5122 * Sets whether the contents of a #ClutterText actor should wrap,
5123 * if they don't fit the size assigned to the actor.
5128 clutter_text_set_line_wrap (ClutterText *self,
5131 ClutterTextPrivate *priv;
5133 g_return_if_fail (CLUTTER_IS_TEXT (self));
5137 if (priv->wrap != line_wrap)
5139 priv->wrap = line_wrap;
5141 clutter_text_dirty_cache (self);
5143 clutter_actor_queue_relayout (CLUTTER_ACTOR (self));
5145 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LINE_WRAP]);
5150 * clutter_text_set_line_wrap_mode:
5151 * @self: a #ClutterText
5152 * @wrap_mode: the line wrapping mode
5154 * If line wrapping is enabled (see clutter_text_set_line_wrap()) this
5155 * function controls how the line wrapping is performed. The default is
5156 * %PANGO_WRAP_WORD which means wrap on word boundaries.
5161 clutter_text_set_line_wrap_mode (ClutterText *self,
5162 PangoWrapMode wrap_mode)
5164 ClutterTextPrivate *priv;
5166 g_return_if_fail (CLUTTER_IS_TEXT (self));
5170 if (priv->wrap_mode != wrap_mode)
5172 priv->wrap_mode = wrap_mode;
5174 clutter_text_dirty_cache (self);
5176 clutter_actor_queue_relayout (CLUTTER_ACTOR (self));
5178 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LINE_WRAP_MODE]);
5183 * clutter_text_get_line_wrap_mode:
5184 * @self: a #ClutterText
5186 * Retrieves the line wrap mode used by the #ClutterText actor.
5188 * See clutter_text_set_line_wrap_mode ().
5190 * Return value: the wrap mode used by the #ClutterText
5195 clutter_text_get_line_wrap_mode (ClutterText *self)
5197 g_return_val_if_fail (CLUTTER_IS_TEXT (self), PANGO_WRAP_WORD);
5199 return self->priv->wrap_mode;
5203 * clutter_text_set_attributes:
5204 * @self: a #ClutterText
5205 * @attrs: (allow-none): a #PangoAttrList or %NULL to unset the attributes
5207 * Sets the attributes list that are going to be applied to the
5208 * #ClutterText contents.
5210 * The #ClutterText actor will take a reference on the #PangoAttrList
5211 * passed to this function.
5216 clutter_text_set_attributes (ClutterText *self,
5217 PangoAttrList *attrs)
5219 ClutterTextPrivate *priv;
5221 g_return_if_fail (CLUTTER_IS_TEXT (self));
5226 pango_attr_list_ref (attrs);
5229 pango_attr_list_unref (priv->attrs);
5231 priv->attrs = attrs;
5233 /* Clear the effective attributes so they will be regenerated when a
5234 layout is created */
5235 if (priv->effective_attrs)
5237 pango_attr_list_unref (priv->effective_attrs);
5238 priv->effective_attrs = NULL;
5241 clutter_text_dirty_cache (self);
5243 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ATTRIBUTES]);
5245 clutter_actor_queue_relayout (CLUTTER_ACTOR (self));
5249 * clutter_text_get_attributes:
5250 * @self: a #ClutterText
5252 * Gets the attribute list that was set on the #ClutterText actor
5253 * clutter_text_set_attributes(), if any.
5255 * Return value: (transfer none): the attribute list, or %NULL if none was set. The
5256 * returned value is owned by the #ClutterText and should not be unreferenced.
5261 clutter_text_get_attributes (ClutterText *self)
5263 g_return_val_if_fail (CLUTTER_IS_TEXT (self), NULL);
5265 return self->priv->attrs;
5269 * clutter_text_set_line_alignment:
5270 * @self: a #ClutterText
5271 * @alignment: A #PangoAlignment
5273 * Sets the way that the lines of a wrapped label are aligned with
5274 * respect to each other. This does not affect the overall alignment
5275 * of the label within its allocated or specified width.
5277 * To align a #ClutterText actor you should add it to a container
5278 * that supports alignment, or use the anchor point.
5283 clutter_text_set_line_alignment (ClutterText *self,
5284 PangoAlignment alignment)
5286 ClutterTextPrivate *priv;
5288 g_return_if_fail (CLUTTER_IS_TEXT (self));
5292 if (priv->alignment != alignment)
5294 priv->alignment = alignment;
5296 clutter_text_dirty_cache (self);
5298 clutter_actor_queue_relayout (CLUTTER_ACTOR (self));
5300 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LINE_ALIGNMENT]);
5305 * clutter_text_get_line_alignment:
5306 * @self: a #ClutterText
5308 * Retrieves the alignment of a #ClutterText, as set by
5309 * clutter_text_set_line_alignment().
5311 * Return value: a #PangoAlignment
5316 clutter_text_get_line_alignment (ClutterText *self)
5318 g_return_val_if_fail (CLUTTER_IS_TEXT (self), PANGO_ALIGN_LEFT);
5320 return self->priv->alignment;
5324 * clutter_text_set_use_markup:
5325 * @self: a #ClutterText
5326 * @setting: %TRUE if the text should be parsed for markup.
5328 * Sets whether the contents of the #ClutterText actor contains markup
5329 * in <link linkend="PangoMarkupFormat">Pango's text markup language</link>.
5331 * Setting #ClutterText:use-markup on an editable #ClutterText will
5332 * not have any effect except hiding the markup.
5334 * See also #ClutterText:use-markup.
5339 clutter_text_set_use_markup (ClutterText *self,
5344 g_return_if_fail (CLUTTER_IS_TEXT (self));
5346 text = clutter_text_buffer_get_text (get_buffer (self));
5348 clutter_text_set_use_markup_internal (self, setting);
5351 clutter_text_set_markup_internal (self, text);
5353 clutter_text_dirty_cache (self);
5355 clutter_actor_queue_relayout (CLUTTER_ACTOR (self));
5359 * clutter_text_get_use_markup:
5360 * @self: a #ClutterText
5362 * Retrieves whether the contents of the #ClutterText actor should be
5363 * parsed for the Pango text markup.
5365 * Return value: %TRUE if the contents will be parsed for markup
5370 clutter_text_get_use_markup (ClutterText *self)
5372 g_return_val_if_fail (CLUTTER_IS_TEXT (self), FALSE);
5374 return self->priv->use_markup;
5378 * clutter_text_set_justify:
5379 * @self: a #ClutterText
5380 * @justify: whether the text should be justified
5382 * Sets whether the text of the #ClutterText actor should be justified
5383 * on both margins. This setting is ignored if Clutter is compiled
5384 * against Pango < 1.18.
5389 clutter_text_set_justify (ClutterText *self,
5392 ClutterTextPrivate *priv;
5394 g_return_if_fail (CLUTTER_IS_TEXT (self));
5398 if (priv->justify != justify)
5400 priv->justify = justify;
5402 clutter_text_dirty_cache (self);
5404 clutter_actor_queue_relayout (CLUTTER_ACTOR (self));
5406 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_JUSTIFY]);
5411 * clutter_text_get_justify:
5412 * @self: a #ClutterText
5414 * Retrieves whether the #ClutterText actor should justify its contents
5417 * Return value: %TRUE if the text should be justified
5422 clutter_text_get_justify (ClutterText *self)
5424 g_return_val_if_fail (CLUTTER_IS_TEXT (self), FALSE);
5426 return self->priv->justify;
5430 * clutter_text_get_cursor_position:
5431 * @self: a #ClutterText
5433 * Retrieves the cursor position.
5435 * Return value: the cursor position, in characters
5440 clutter_text_get_cursor_position (ClutterText *self)
5442 g_return_val_if_fail (CLUTTER_IS_TEXT (self), -1);
5444 return self->priv->position;
5448 * clutter_text_set_cursor_position:
5449 * @self: a #ClutterText
5450 * @position: the new cursor position, in characters
5452 * Sets the cursor of a #ClutterText actor at @position.
5454 * The position is expressed in characters, not in bytes.
5459 clutter_text_set_cursor_position (ClutterText *self,
5462 ClutterTextPrivate *priv;
5465 g_return_if_fail (CLUTTER_IS_TEXT (self));
5469 if (priv->position == position)
5472 len = clutter_text_buffer_get_length (get_buffer (self));
5474 if (position < 0 || position >= len)
5475 priv->position = -1;
5477 priv->position = position;
5479 /* Forget the target x position so that it will be recalculated next
5480 time the cursor is moved up or down */
5483 clutter_text_queue_redraw (CLUTTER_ACTOR (self));
5485 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_POSITION]);
5489 * clutter_text_set_cursor_size:
5490 * @self: a #ClutterText
5491 * @size: the size of the cursor, in pixels, or -1 to use the
5494 * Sets the size of the cursor of a #ClutterText. The cursor
5495 * will only be visible if the #ClutterText:cursor-visible property
5501 clutter_text_set_cursor_size (ClutterText *self,
5504 ClutterTextPrivate *priv;
5506 g_return_if_fail (CLUTTER_IS_TEXT (self));
5510 if (priv->cursor_size != size)
5513 size = DEFAULT_CURSOR_SIZE;
5515 priv->cursor_size = size;
5517 clutter_text_queue_redraw (CLUTTER_ACTOR (self));
5519 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CURSOR_SIZE]);
5524 * clutter_text_get_cursor_size:
5525 * @self: a #ClutterText
5527 * Retrieves the size of the cursor of a #ClutterText actor.
5529 * Return value: the size of the cursor, in pixels
5534 clutter_text_get_cursor_size (ClutterText *self)
5536 g_return_val_if_fail (CLUTTER_IS_TEXT (self), DEFAULT_CURSOR_SIZE);
5538 return self->priv->cursor_size;
5542 * clutter_text_set_password_char:
5543 * @self: a #ClutterText
5544 * @wc: a Unicode character, or 0 to unset the password character
5546 * Sets the character to use in place of the actual text in a
5547 * password text actor.
5549 * If @wc is 0 the text will be displayed as it is entered in the
5550 * #ClutterText actor.
5555 clutter_text_set_password_char (ClutterText *self,
5558 ClutterTextPrivate *priv;
5560 g_return_if_fail (CLUTTER_IS_TEXT (self));
5564 if (priv->password_char != wc)
5566 priv->password_char = wc;
5568 clutter_text_dirty_cache (self);
5569 clutter_actor_queue_relayout (CLUTTER_ACTOR (self));
5571 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_PASSWORD_CHAR]);
5576 * clutter_text_get_password_char:
5577 * @self: a #ClutterText
5579 * Retrieves the character to use in place of the actual text
5580 * as set by clutter_text_set_password_char().
5582 * Return value: a Unicode character or 0 if the password
5583 * character is not set
5588 clutter_text_get_password_char (ClutterText *self)
5590 g_return_val_if_fail (CLUTTER_IS_TEXT (self), 0);
5592 return self->priv->password_char;
5596 * clutter_text_set_max_length:
5597 * @self: a #ClutterText
5598 * @max: the maximum number of characters allowed in the text actor; 0
5599 * to disable or -1 to set the length of the current string
5601 * Sets the maximum allowed length of the contents of the actor. If the
5602 * current contents are longer than the given length, then they will be
5608 clutter_text_set_max_length (ClutterText *self,
5611 g_return_if_fail (CLUTTER_IS_TEXT (self));
5612 clutter_text_buffer_set_max_length (get_buffer (self), max);
5616 * clutter_text_get_max_length:
5617 * @self: a #ClutterText
5619 * Gets the maximum length of text that can be set into a text actor.
5621 * See clutter_text_set_max_length().
5623 * Return value: the maximum number of characters.
5628 clutter_text_get_max_length (ClutterText *self)
5630 g_return_val_if_fail (CLUTTER_IS_TEXT (self), 0);
5632 return clutter_text_buffer_get_max_length (get_buffer (self));
5636 * clutter_text_insert_unichar:
5637 * @self: a #ClutterText
5638 * @wc: a Unicode character
5640 * Inserts @wc at the current cursor position of a
5641 * #ClutterText actor.
5646 clutter_text_insert_unichar (ClutterText *self,
5649 ClutterTextPrivate *priv;
5654 new = g_string_new ("");
5655 g_string_append_unichar (new, wc);
5657 clutter_text_buffer_insert_text (get_buffer (self), priv->position, new->str, 1);
5659 g_string_free (new, TRUE);
5663 * clutter_text_insert_text:
5664 * @self: a #ClutterText
5665 * @text: the text to be inserted
5666 * @position: the position of the insertion, or -1
5668 * Inserts @text into a #ClutterActor at the given position.
5670 * If @position is a negative number, the text will be appended
5671 * at the end of the current contents of the #ClutterText.
5673 * The position is expressed in characters, not in bytes.
5678 clutter_text_insert_text (ClutterText *self,
5682 g_return_if_fail (CLUTTER_IS_TEXT (self));
5683 g_return_if_fail (text != NULL);
5685 clutter_text_buffer_insert_text (get_buffer (self), position, text,
5686 g_utf8_strlen (text, -1));
5690 * clutter_text_delete_text:
5691 * @self: a #ClutterText
5692 * @start_pos: starting position
5693 * @end_pos: ending position
5695 * Deletes the text inside a #ClutterText actor between @start_pos
5698 * The starting and ending positions are expressed in characters,
5704 clutter_text_delete_text (ClutterText *self,
5708 g_return_if_fail (CLUTTER_IS_TEXT (self));
5710 clutter_text_buffer_delete_text (get_buffer (self), start_pos, end_pos - start_pos);
5714 * clutter_text_delete_chars:
5715 * @self: a #ClutterText
5716 * @n_chars: the number of characters to delete
5718 * Deletes @n_chars inside a #ClutterText actor, starting from the
5719 * current cursor position.
5721 * Somewhat awkwardly, the cursor position is decremented by the same
5722 * number of characters you've deleted.
5727 clutter_text_delete_chars (ClutterText *self,
5730 ClutterTextPrivate *priv;
5732 g_return_if_fail (CLUTTER_IS_TEXT (self));
5736 clutter_text_buffer_delete_text (get_buffer (self), priv->position, n_chars);
5738 if (priv->position > 0)
5739 clutter_text_set_cursor_position (self, priv->position - n_chars);
5743 * clutter_text_get_chars:
5744 * @self: a #ClutterText
5745 * @start_pos: start of text, in characters
5746 * @end_pos: end of text, in characters
5748 * Retrieves the contents of the #ClutterText actor between
5749 * @start_pos and @end_pos, but not including @end_pos.
5751 * The positions are specified in characters, not in bytes.
5753 * Return value: a newly allocated string with the contents of
5754 * the text actor between the specified positions. Use g_free()
5755 * to free the resources when done
5760 clutter_text_get_chars (ClutterText *self,
5764 gint start_index, end_index;
5768 g_return_val_if_fail (CLUTTER_IS_TEXT (self), NULL);
5770 n_chars = clutter_text_buffer_get_length (get_buffer (self));
5771 text = clutter_text_buffer_get_text (get_buffer (self));
5776 start_pos = MIN (n_chars, start_pos);
5777 end_pos = MIN (n_chars, end_pos);
5779 start_index = g_utf8_offset_to_pointer (text, start_pos) - text;
5780 end_index = g_utf8_offset_to_pointer (text, end_pos) - text;
5782 return g_strndup (text + start_index, end_index - start_index);
5786 * clutter_text_set_single_line_mode:
5787 * @self: a #ClutterText
5788 * @single_line: whether to enable single line mode
5790 * Sets whether a #ClutterText actor should be in single line mode
5791 * or not. Only editable #ClutterText<!-- -->s can be in single line
5794 * A text actor in single line mode will not wrap text and will clip
5795 * the visible area to the predefined size. The contents of the
5796 * text actor will scroll to display the end of the text if its length
5797 * is bigger than the allocated width.
5799 * When setting the single line mode the #ClutterText:activatable
5800 * property is also set as a side effect. Instead of entering a new
5801 * line character, the text actor will emit the #ClutterText::activate
5807 clutter_text_set_single_line_mode (ClutterText *self,
5808 gboolean single_line)
5810 ClutterTextPrivate *priv;
5812 g_return_if_fail (CLUTTER_IS_TEXT (self));
5816 if (priv->single_line_mode != single_line)
5818 g_object_freeze_notify (G_OBJECT (self));
5820 priv->single_line_mode = single_line;
5822 if (priv->single_line_mode)
5824 priv->activatable = TRUE;
5826 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIVATABLE]);
5829 clutter_text_dirty_cache (self);
5830 clutter_actor_queue_relayout (CLUTTER_ACTOR (self));
5832 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_SINGLE_LINE_MODE]);
5834 g_object_thaw_notify (G_OBJECT (self));
5839 * clutter_text_get_single_line_mode:
5840 * @self: a #ClutterText
5842 * Retrieves whether the #ClutterText actor is in single line mode.
5844 * Return value: %TRUE if the #ClutterText actor is in single line mode
5849 clutter_text_get_single_line_mode (ClutterText *self)
5851 g_return_val_if_fail (CLUTTER_IS_TEXT (self), FALSE);
5853 return self->priv->single_line_mode;
5857 * clutter_text_set_preedit_string:
5858 * @self: a #ClutterText
5859 * @preedit_str: (allow-none): the pre-edit string, or %NULL to unset it
5860 * @preedit_attrs: (allow-none): the pre-edit string attributes
5861 * @cursor_pos: the cursor position for the pre-edit string
5863 * Sets, or unsets, the pre-edit string. This function is useful
5864 * for input methods to display a string (with eventual specific
5865 * Pango attributes) before it is entered inside the #ClutterText
5868 * The preedit string and attributes are ignored if the #ClutterText
5869 * actor is not editable.
5871 * This function should not be used by applications
5876 clutter_text_set_preedit_string (ClutterText *self,
5877 const gchar *preedit_str,
5878 PangoAttrList *preedit_attrs,
5881 ClutterTextPrivate *priv;
5883 g_return_if_fail (CLUTTER_IS_TEXT (self));
5887 g_free (priv->preedit_str);
5888 priv->preedit_str = NULL;
5890 if (priv->preedit_attrs != NULL)
5892 pango_attr_list_unref (priv->preedit_attrs);
5893 priv->preedit_attrs = NULL;
5896 priv->preedit_n_chars = 0;
5897 priv->preedit_cursor_pos = 0;
5899 if (preedit_str == NULL || *preedit_str == '\0')
5900 priv->preedit_set = FALSE;
5903 priv->preedit_str = g_strdup (preedit_str);
5905 if (priv->preedit_str != NULL)
5906 priv->preedit_n_chars = g_utf8_strlen (priv->preedit_str, -1);
5908 priv->preedit_n_chars = 0;
5910 if (preedit_attrs != NULL)
5911 priv->preedit_attrs = pango_attr_list_ref (preedit_attrs);
5913 priv->preedit_cursor_pos =
5914 CLAMP (cursor_pos, 0, priv->preedit_n_chars);
5916 priv->preedit_set = TRUE;
5919 clutter_text_dirty_cache (self);
5920 clutter_actor_queue_relayout (CLUTTER_ACTOR (self));
5925 * clutter_text_get_layout_offsets:
5926 * @self: a #ClutterText
5927 * @x: (out): location to store X offset of layout, or %NULL
5928 * @y: (out): location to store Y offset of layout, or %NULL
5930 * Obtains the coordinates where the #ClutterText will draw the #PangoLayout
5931 * representing the text.
5936 clutter_text_get_layout_offsets (ClutterText *self,
5940 ClutterTextPrivate *priv;
5942 g_return_if_fail (CLUTTER_IS_TEXT (self));