1 /* GTK - The GIMP Toolkit
2 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free
16 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
21 * file for a list of people on the GTK+ Team. See the ChangeLog
22 * files for a list of changes. These files are distributed with
23 * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
29 #include "gtksignal.h"
30 #include "gtkwindow.h"
31 #include "gdk/gdkkeysyms.h"
32 #include "gtkclipboard.h"
33 #include "gdk/gdki18n.h"
34 #include <pango/pango.h>
36 #include "gtkmenuitem.h"
37 #include "gtknotebook.h"
39 struct _GtkLabelSelectionInfo
42 gint selection_anchor;
61 static void gtk_label_class_init (GtkLabelClass *klass);
62 static void gtk_label_init (GtkLabel *label);
63 static void gtk_label_set_property (GObject *object,
67 static void gtk_label_get_property (GObject *object,
71 static void gtk_label_destroy (GtkObject *object);
72 static void gtk_label_finalize (GObject *object);
73 static void gtk_label_size_request (GtkWidget *widget,
74 GtkRequisition *requisition);
75 static void gtk_label_size_allocate (GtkWidget *widget,
76 GtkAllocation *allocation);
77 static void gtk_label_state_changed (GtkWidget *widget,
79 static void gtk_label_style_set (GtkWidget *widget,
80 GtkStyle *previous_style);
81 static void gtk_label_direction_changed (GtkWidget *widget,
82 GtkTextDirection previous_dir);
83 static gint gtk_label_expose (GtkWidget *widget,
84 GdkEventExpose *event);
86 static void gtk_label_realize (GtkWidget *widget);
87 static void gtk_label_unrealize (GtkWidget *widget);
88 static void gtk_label_map (GtkWidget *widget);
89 static void gtk_label_unmap (GtkWidget *widget);
90 static gint gtk_label_button_press (GtkWidget *widget,
91 GdkEventButton *event);
92 static gint gtk_label_button_release (GtkWidget *widget,
93 GdkEventButton *event);
94 static gint gtk_label_motion (GtkWidget *widget,
95 GdkEventMotion *event);
98 static void gtk_label_set_text_internal (GtkLabel *label,
100 static void gtk_label_set_label_internal (GtkLabel *label,
102 static void gtk_label_set_use_markup_internal (GtkLabel *label,
104 static void gtk_label_set_use_underline_internal (GtkLabel *label,
106 static void gtk_label_set_attributes_internal (GtkLabel *label,
107 PangoAttrList *attrs);
108 static void gtk_label_set_uline_text_internal (GtkLabel *label,
110 static void gtk_label_set_pattern_internal (GtkLabel *label,
111 const gchar *pattern);
112 static void set_markup (GtkLabel *label,
114 gboolean with_uline);
115 static void gtk_label_recalculate (GtkLabel *label);
116 static void gtk_label_hierarchy_changed (GtkWidget *widget);
118 static void gtk_label_create_window (GtkLabel *label);
119 static void gtk_label_destroy_window (GtkLabel *label);
120 static void gtk_label_clear_layout (GtkLabel *label);
121 static void gtk_label_ensure_layout (GtkLabel *label,
124 static void gtk_label_select_region_index (GtkLabel *label,
128 static gboolean gtk_label_mnemonic_activate (GtkWidget *widget,
129 gboolean group_cycling);
130 static void gtk_label_setup_mnemonic (GtkLabel *label,
134 static GtkMiscClass *parent_class = NULL;
138 gtk_label_get_type (void)
140 static GtkType label_type = 0;
144 static const GTypeInfo label_info =
146 sizeof (GtkLabelClass),
147 NULL, /* base_init */
148 NULL, /* base_finalize */
149 (GClassInitFunc) gtk_label_class_init,
150 NULL, /* class_finalize */
151 NULL, /* class_data */
153 32, /* n_preallocs */
154 (GInstanceInitFunc) gtk_label_init,
157 label_type = g_type_register_static (GTK_TYPE_MISC, "GtkLabel", &label_info, 0);
164 gtk_label_class_init (GtkLabelClass *class)
166 GObjectClass *gobject_class = G_OBJECT_CLASS (class);
167 GtkObjectClass *object_class = GTK_OBJECT_CLASS (class);
168 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
170 parent_class = gtk_type_class (GTK_TYPE_MISC);
172 gobject_class->set_property = gtk_label_set_property;
173 gobject_class->get_property = gtk_label_get_property;
174 gobject_class->finalize = gtk_label_finalize;
176 object_class->destroy = gtk_label_destroy;
178 widget_class->size_request = gtk_label_size_request;
179 widget_class->size_allocate = gtk_label_size_allocate;
180 widget_class->state_changed = gtk_label_state_changed;
181 widget_class->style_set = gtk_label_style_set;
182 widget_class->direction_changed = gtk_label_direction_changed;
183 widget_class->expose_event = gtk_label_expose;
184 widget_class->realize = gtk_label_realize;
185 widget_class->unrealize = gtk_label_unrealize;
186 widget_class->map = gtk_label_map;
187 widget_class->unmap = gtk_label_unmap;
188 widget_class->button_press_event = gtk_label_button_press;
189 widget_class->button_release_event = gtk_label_button_release;
190 widget_class->motion_notify_event = gtk_label_motion;
191 widget_class->hierarchy_changed = gtk_label_hierarchy_changed;
192 widget_class->mnemonic_activate = gtk_label_mnemonic_activate;
194 g_object_class_install_property (G_OBJECT_CLASS(object_class),
196 g_param_spec_string ("label",
198 _("The text of the label."),
201 g_object_class_install_property (gobject_class,
203 g_param_spec_boxed ("attributes",
205 _("A list of style attributes to apply to the text of the label."),
206 PANGO_TYPE_ATTR_LIST,
208 g_object_class_install_property (gobject_class,
210 g_param_spec_boolean ("use_markup",
212 _("The text of the label includes XML markup. See pango_parse_markup()."),
215 g_object_class_install_property (gobject_class,
217 g_param_spec_boolean ("use_underline",
219 _("If set, an underline in the text indicates the next character should be used for the mnemonic accelerator key"),
223 g_object_class_install_property (gobject_class,
225 g_param_spec_enum ("justify",
227 _("The alignment of the lines in the text of the label relative to each other. This does NOT affect the alignment of the label within its allocation. See GtkMisc::xalign for that."),
228 GTK_TYPE_JUSTIFICATION,
232 g_object_class_install_property (gobject_class,
234 g_param_spec_string ("pattern",
236 _("A string with _ characters in positions correspond to characters in the text to underline."),
240 g_object_class_install_property (gobject_class,
242 g_param_spec_boolean ("wrap",
244 _("If set, wrap lines if the text becomes too wide."),
247 g_object_class_install_property (gobject_class,
249 g_param_spec_boolean ("selectable",
251 _("Whether the label text can be selected with the mouse."),
254 g_object_class_install_property (gobject_class,
255 PROP_MNEMONIC_KEYVAL,
256 g_param_spec_uint ("mnemonic_keyval",
258 _("The mnemonic accelerator key for this label."),
263 g_object_class_install_property (gobject_class,
264 PROP_MNEMONIC_WIDGET,
265 g_param_spec_object ("mnemonic_widget",
266 _("Mnemonic widget"),
267 _("The widget to be activated when the label's mnemonic "
274 gtk_label_set_property (GObject *object,
282 label = GTK_LABEL (object);
283 last_keyval = label->mnemonic_keyval;
288 gtk_label_set_label_internal (label,
289 g_strdup (g_value_get_string (value)));
290 gtk_label_recalculate (label);
291 if (last_keyval != label->mnemonic_keyval)
292 gtk_label_setup_mnemonic (label, last_keyval);
294 case PROP_ATTRIBUTES:
295 gtk_label_set_attributes (label, g_value_get_boxed (value));
297 case PROP_USE_MARKUP:
298 gtk_label_set_use_markup_internal (label, g_value_get_boolean (value));
299 gtk_label_recalculate (label);
301 case PROP_USE_UNDERLINE:
302 gtk_label_set_use_underline_internal (label, g_value_get_boolean (value));
303 gtk_label_recalculate (label);
304 if (label->use_underline)
305 gtk_label_setup_mnemonic (label, last_keyval);
308 gtk_label_set_justify (label, g_value_get_enum (value));
311 gtk_label_set_pattern (label, g_value_get_string (value));
314 gtk_label_set_line_wrap (label, g_value_get_boolean (value));
316 case PROP_SELECTABLE:
317 gtk_label_set_selectable (label, g_value_get_boolean (value));
319 case PROP_MNEMONIC_WIDGET:
320 gtk_label_set_mnemonic_widget (label, (GtkWidget*) g_value_get_object (value));
323 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
329 gtk_label_get_property (GObject *object,
336 label = GTK_LABEL (object);
341 g_value_set_string (value, label->label);
343 case PROP_ATTRIBUTES:
344 g_value_set_boxed (value, label->attrs);
346 case PROP_USE_MARKUP:
347 g_value_set_boolean (value, label->use_markup);
349 case PROP_USE_UNDERLINE:
350 g_value_set_boolean (value, label->use_underline);
353 g_value_set_enum (value, label->jtype);
356 g_value_set_boolean (value, label->wrap);
358 case PROP_SELECTABLE:
359 g_value_set_boolean (value, gtk_label_get_selectable (label));
361 case PROP_MNEMONIC_KEYVAL:
362 g_value_set_uint (value, label->mnemonic_keyval);
364 case PROP_MNEMONIC_WIDGET:
365 g_value_set_object (value, (GObject*) label->mnemonic_widget);
369 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
375 gtk_label_init (GtkLabel *label)
377 GTK_WIDGET_SET_FLAGS (label, GTK_NO_WINDOW);
381 label->jtype = GTK_JUSTIFY_CENTER;
384 label->use_underline = FALSE;
385 label->use_markup = FALSE;
387 label->mnemonic_keyval = GDK_VoidSymbol;
388 label->layout = NULL;
392 label->mnemonic_widget = NULL;
393 label->mnemonic_window = NULL;
395 gtk_label_set_text (label, "");
400 * @str: The text of the label
401 * @returns: a new #GtkLabel
403 * Creates a new #GtkLabel, containing the text in @str.
406 gtk_label_new (const gchar *str)
410 label = gtk_type_new (GTK_TYPE_LABEL);
413 gtk_label_set_text (label, str);
415 return GTK_WIDGET (label);
419 * gtk_label_new_with_mnemonic:
420 * @str: The text of the label, with an underscore in front of the
422 * @returns: a new #GtkLabel
424 * Creates a new #GtkLabel, containing the text in @str.
426 * If characters in @str are preceded by an underscore, they are underlined
427 * indicating that they represent a keyboard accelerator called a mnemonic.
428 * The mnemonic key can be used to activate another widget, chosen automatically,
429 * or explicitly using gtk_label_set_mnemonic_widget().
432 gtk_label_new_with_mnemonic (const gchar *str)
436 label = gtk_type_new (GTK_TYPE_LABEL);
439 gtk_label_set_text_with_mnemonic (label, str);
441 return GTK_WIDGET (label);
445 gtk_label_mnemonic_activate (GtkWidget *widget,
446 gboolean group_cycling)
450 if (GTK_LABEL (widget)->mnemonic_widget)
451 return gtk_widget_mnemonic_activate (GTK_LABEL (widget)->mnemonic_widget, group_cycling);
453 /* Try to find the widget to activate by traversing the
456 parent = widget->parent;
459 if (GTK_WIDGET_CAN_FOCUS (parent) ||
460 (!group_cycling && GTK_WIDGET_GET_CLASS (parent)->activate_signal) ||
461 (parent->parent && GTK_IS_NOTEBOOK (parent->parent)) ||
462 (GTK_IS_MENU_ITEM (parent)))
463 return gtk_widget_mnemonic_activate (parent, group_cycling);
464 parent = parent->parent;
467 /* barf if there was nothing to activate */
468 g_warning ("Couldn't find a target for a mnemonic activation.");
475 gtk_label_setup_mnemonic (GtkLabel *label,
480 if (last_key != GDK_VoidSymbol && label->mnemonic_window)
482 gtk_window_remove_mnemonic (label->mnemonic_window,
485 label->mnemonic_window = NULL;
488 if (label->mnemonic_keyval == GDK_VoidSymbol)
491 toplevel = gtk_widget_get_toplevel (GTK_WIDGET (label));
493 if (GTK_IS_WINDOW (toplevel))
495 gtk_window_add_mnemonic (GTK_WINDOW (toplevel),
496 label->mnemonic_keyval,
498 label->mnemonic_window = GTK_WINDOW (toplevel);
503 gtk_label_hierarchy_changed (GtkWidget *widget)
505 GtkLabel *label = GTK_LABEL (widget);
507 gtk_label_setup_mnemonic (label, label->mnemonic_keyval);
512 * gtk_label_set_mnemonic_widget:
513 * @label: a #GtkLabel
514 * @widget: the target #GtkWidget
516 * If the label has been set so that it has an mnemonic key (using
517 * i.e. gtk_label_set_markup_with_mnemonic(),
518 * gtk_label_set_text_with_mnemonic(), gtk_label_new_with_mnemonic()
519 * or the "use_underline" property) the label can be associated with a
520 * widget that is the target of the mnemonic. When the label is inside
521 * a widget (like a #GtkButton or a #GtkNotebook tab) it is
522 * automatically associated with the correct widget, but sometimes
523 * (i.e. when the target is a #GtkEntry next to the label) you need to
524 * set it explicitly using this function.
526 * The target widget will be accelerated by emitting "mnemonic_activate" on it.
527 * The default handler for this signal will activate the widget if there are no
528 * mnemonic collisions and toggle focus between the colliding widgets otherwise.
531 gtk_label_set_mnemonic_widget (GtkLabel *label,
534 g_return_if_fail (GTK_IS_LABEL (label));
536 g_return_if_fail (GTK_IS_WIDGET (widget));
538 if (label->mnemonic_widget)
539 gtk_widget_unref (label->mnemonic_widget);
540 label->mnemonic_widget = widget;
541 if (label->mnemonic_widget)
542 gtk_widget_ref (label->mnemonic_widget);
547 * gtk_label_get_mnemonic_keyval:
548 * @label: a #GtkLabel
550 * If the label has been set so that it has an mnemonic key this function
551 * returns the keyval used for the mnemonic accelerator. If there is no
552 * mnemonic set up it returns #GDK_VoidSymbol.
554 * Returns: GDK keyval usable for accelerators, or GDK_VoidSymbol
557 gtk_label_get_mnemonic_keyval (GtkLabel *label)
559 g_return_val_if_fail (GTK_IS_LABEL (label), GDK_VoidSymbol);
561 return label->mnemonic_keyval;
565 gtk_label_set_text_internal (GtkLabel *label,
568 g_free (label->text);
572 gtk_label_select_region_index (label, 0, 0);
576 gtk_label_set_label_internal (GtkLabel *label,
579 g_free (label->label);
583 g_object_notify (G_OBJECT (label), "label");
587 gtk_label_set_use_markup_internal (GtkLabel *label,
591 if (label->use_markup != val)
592 g_object_notify (G_OBJECT (label), "use_markup");
593 label->use_markup = val;
597 gtk_label_set_use_underline_internal (GtkLabel *label,
601 if (label->use_underline != val)
602 g_object_notify (G_OBJECT (label), "use_underline");
603 label->use_underline = val;
607 gtk_label_set_attributes_internal (GtkLabel *label,
608 PangoAttrList *attrs)
611 pango_attr_list_ref (attrs);
614 pango_attr_list_unref (label->attrs);
616 label->attrs = attrs;
617 g_object_notify (G_OBJECT (label), "attributes");
621 /* Calculates text, attrs and mnemonic_keyval from
622 * label, use_underline and use_markup
625 gtk_label_recalculate (GtkLabel *label)
627 if (label->use_markup)
628 set_markup (label, label->label, label->use_underline);
631 if (label->use_underline)
632 gtk_label_set_uline_text_internal (label, label->label);
635 gtk_label_set_text_internal (label, g_strdup (label->label));
636 gtk_label_set_attributes_internal (label, NULL);
640 if (!label->use_underline)
642 guint keyval = label->mnemonic_keyval;
644 label->mnemonic_keyval = GDK_VoidSymbol;
645 gtk_label_setup_mnemonic (label, keyval);
648 gtk_label_clear_layout (label);
649 gtk_widget_queue_resize (GTK_WIDGET (label));
653 * gtk_label_set_text:
654 * @label: a #GtkLabel
657 * Sets the text of the label to @str.
659 * This will also clear any previously set mnemonic accelerators.
662 gtk_label_set_text (GtkLabel *label,
665 g_return_if_fail (GTK_IS_LABEL (label));
667 gtk_label_set_label_internal (label, g_strdup (str ? str : ""));
668 gtk_label_set_use_markup_internal (label, FALSE);
669 gtk_label_set_use_underline_internal (label, FALSE);
671 gtk_label_recalculate (label);
675 * gtk_label_set_attributes:
676 * @label: a #GtkLabel
677 * @attrs: a #PangoAttrList
679 * Sets a #PangoAttrList; the attributes in the list are applied to the
683 gtk_label_set_attributes (GtkLabel *label,
684 PangoAttrList *attrs)
686 g_return_if_fail (GTK_IS_LABEL (label));
688 gtk_label_set_attributes_internal (label, attrs);
690 gtk_label_clear_layout (label);
691 gtk_widget_queue_resize (GTK_WIDGET (label));
695 set_markup (GtkLabel *label,
700 GError *error = NULL;
701 PangoAttrList *attrs = NULL;
702 gunichar accel_char = 0;
704 if (!pango_parse_markup (str,
706 with_uline ? '_' : 0,
709 with_uline ? &accel_char : NULL,
712 g_warning ("Failed to set label from markup due to error parsing markup: %s",
714 g_error_free (error);
719 gtk_label_set_text_internal (label, text);
723 gtk_label_set_attributes_internal (label, attrs);
724 pango_attr_list_unref (attrs);
728 label->mnemonic_keyval = gdk_keyval_to_lower (gdk_unicode_to_keyval (accel_char));
730 label->mnemonic_keyval = GDK_VoidSymbol;
734 * gtk_label_set_markup:
735 * @label: a #GtkLabel
736 * @str: a markup string (see <link linkend="PangoMarkupFormat">Pango markup format</link>)
738 * Parses @str which is marked up with the Pango text markup language,
739 * setting the label's text and attribute list based on the parse results.
742 gtk_label_set_markup (GtkLabel *label,
745 g_return_if_fail (GTK_IS_LABEL (label));
747 gtk_label_set_label_internal (label, g_strdup (str ? str : ""));
748 gtk_label_set_use_markup_internal (label, TRUE);
749 gtk_label_set_use_underline_internal (label, FALSE);
751 gtk_label_recalculate (label);
755 * gtk_label_set_markup_with_mnemonic:
756 * @label: a #GtkLabel
757 * @str: a markup string (see <link linkend="PangoMarkupFormat">Pango markup format</link>)
759 * Parses @str which is marked up with the Pango text markup language,
760 * setting the label's text and attribute list based on the parse results.
761 * If characters in @str are preceded by an underscore, they are underlined
762 * indicating that they represent a keyboard accelerator called a mnemonic.
764 * The mnemonic key can be used to activate another widget, chosen automatically,
765 * or explicitly using gtk_label_set_mnemonic_widget().
768 gtk_label_set_markup_with_mnemonic (GtkLabel *label,
772 g_return_if_fail (GTK_IS_LABEL (label));
774 last_keyval = label->mnemonic_keyval;
775 gtk_label_set_label_internal (label, g_strdup (str ? str : ""));
776 gtk_label_set_use_markup_internal (label, TRUE);
777 gtk_label_set_use_underline_internal (label, TRUE);
779 gtk_label_recalculate (label);
780 gtk_label_setup_mnemonic (label, last_keyval);
784 * gtk_label_get_text:
785 * @label: a #GtkLabel
787 * Fetches the text from a label widget
789 * Return value: the text in the label widget. This is the internal
790 * string used by the label, and must not be modified.
792 G_CONST_RETURN gchar *
793 gtk_label_get_text (GtkLabel *label)
795 g_return_val_if_fail (label != NULL, NULL);
796 g_return_val_if_fail (GTK_IS_LABEL (label), NULL);
801 static PangoAttrList *
802 gtk_label_pattern_to_attrs (GtkLabel *label,
803 const gchar *pattern)
806 const char *p = label->text;
807 const char *q = pattern;
808 PangoAttrList *attrs;
810 attrs = pango_attr_list_new ();
814 while (*p && *q && *q != '_')
816 p = g_utf8_next_char (p);
820 while (*p && *q && *q == '_')
822 p = g_utf8_next_char (p);
828 PangoAttribute *attr = pango_attr_underline_new (PANGO_UNDERLINE_LOW);
829 attr->start_index = start - label->text;
830 attr->end_index = p - label->text;
832 pango_attr_list_insert (attrs, attr);
842 gtk_label_set_pattern_internal (GtkLabel *label,
843 const gchar *pattern)
845 PangoAttrList *attrs;
846 g_return_if_fail (GTK_IS_LABEL (label));
848 attrs = gtk_label_pattern_to_attrs (label, pattern);
850 gtk_label_set_attributes_internal (label, attrs);
854 gtk_label_set_pattern (GtkLabel *label,
855 const gchar *pattern)
857 g_return_if_fail (GTK_IS_LABEL (label));
859 gtk_label_set_pattern_internal (label, pattern);
861 gtk_label_clear_layout (label);
862 gtk_widget_queue_resize (GTK_WIDGET (label));
867 gtk_label_set_justify (GtkLabel *label,
868 GtkJustification jtype)
870 g_return_if_fail (GTK_IS_LABEL (label));
871 g_return_if_fail (jtype >= GTK_JUSTIFY_LEFT && jtype <= GTK_JUSTIFY_FILL);
873 if ((GtkJustification) label->jtype != jtype)
875 label->jtype = jtype;
877 /* No real need to be this drastic, but easier than duplicating the code */
878 gtk_label_clear_layout (label);
880 g_object_notify (G_OBJECT (label), "justify");
881 gtk_widget_queue_resize (GTK_WIDGET (label));
886 gtk_label_set_line_wrap (GtkLabel *label,
889 g_return_if_fail (GTK_IS_LABEL (label));
891 wrap = wrap != FALSE;
893 if (label->wrap != wrap)
896 g_object_notify (G_OBJECT (label), "wrap");
898 gtk_widget_queue_resize (GTK_WIDGET (label));
903 gtk_label_get (GtkLabel *label,
906 g_return_if_fail (label != NULL);
907 g_return_if_fail (GTK_IS_LABEL (label));
908 g_return_if_fail (str != NULL);
914 gtk_label_destroy (GtkObject *object)
916 GtkLabel *label = GTK_LABEL (object);
918 gtk_label_set_mnemonic_widget (label, NULL);
920 GTK_OBJECT_CLASS (parent_class)->destroy (object);
924 gtk_label_finalize (GObject *object)
928 g_return_if_fail (GTK_IS_LABEL (object));
930 label = GTK_LABEL (object);
932 g_free (label->label);
933 g_free (label->text);
936 g_object_unref (G_OBJECT (label->layout));
939 pango_attr_list_unref (label->attrs);
941 g_free (label->select_info);
943 G_OBJECT_CLASS (parent_class)->finalize (object);
947 gtk_label_clear_layout (GtkLabel *label)
951 g_object_unref (G_OBJECT (label->layout));
952 label->layout = NULL;
957 gtk_label_ensure_layout (GtkLabel *label,
962 PangoRectangle logical_rect;
963 gint rwidth, rheight;
965 widget = GTK_WIDGET (label);
968 * There are a number of conditions which will necessitate re-filling
972 * 2. justification changed either from to to GTK_JUSTIFY_FILL.
975 * These have been detected elsewhere, and label->words will be zero,
976 * if one of the above has occured.
978 * Additionally, though, if GTK_JUSTIFY_FILL, we need to re-fill if:
980 * 4. gtk_widget_set_usize has changed the requested width.
981 * 5. gtk_misc_set_padding has changed xpad.
982 * 6. maybe others?...
984 * Too much of a pain to detect all these case, so always re-fill. I
985 * don't think it's really that slow.
988 rwidth = label->misc.xpad * 2;
989 rheight = label->misc.ypad * 2;
993 PangoAlignment align = PANGO_ALIGN_LEFT; /* Quiet gcc */
995 label->layout = gtk_widget_create_pango_layout (widget, label->text);
998 pango_layout_set_attributes (label->layout, label->attrs);
1000 switch (label->jtype)
1002 case GTK_JUSTIFY_LEFT:
1003 align = PANGO_ALIGN_LEFT;
1005 case GTK_JUSTIFY_RIGHT:
1006 align = PANGO_ALIGN_RIGHT;
1008 case GTK_JUSTIFY_CENTER:
1009 align = PANGO_ALIGN_LEFT;
1011 case GTK_JUSTIFY_FILL:
1012 /* FIXME: This just doesn't work to do this */
1013 align = PANGO_ALIGN_LEFT;
1014 pango_layout_set_justify (label->layout, TRUE);
1017 g_assert_not_reached();
1020 pango_layout_set_alignment (label->layout, align);
1025 GtkWidgetAuxInfo *aux_info;
1026 gint longest_paragraph;
1030 aux_info = _gtk_widget_get_aux_info (widget, FALSE);
1031 if (aux_info && aux_info->width > 0)
1033 pango_layout_set_width (label->layout, aux_info->width * PANGO_SCALE);
1034 pango_layout_get_extents (label->layout, NULL, &logical_rect);
1036 rwidth += aux_info->width;
1037 rheight += PANGO_PIXELS (logical_rect.height);
1041 pango_layout_set_width (label->layout, -1);
1042 pango_layout_get_extents (label->layout, NULL, &logical_rect);
1044 width = logical_rect.width;
1045 height = logical_rect.height;
1047 /* Try to guess a reasonable maximum width
1049 longest_paragraph = width;
1052 PANGO_SCALE * gdk_string_width (GTK_WIDGET (label)->style->font,
1053 "This long string gives a good enough length for any line to have."));
1055 PANGO_SCALE * (gdk_screen_width () + 1) / 2);
1057 pango_layout_set_width (label->layout, width);
1058 pango_layout_get_extents (label->layout, NULL, &logical_rect);
1059 real_width = logical_rect.width;
1060 height = logical_rect.height;
1062 /* Unfortunately, the above may leave us with a very unbalanced looking paragraph,
1063 * so we try short search for a narrower width that leaves us with the same height
1065 if (longest_paragraph > 0)
1067 gint nlines, perfect_width;
1069 nlines = pango_layout_get_line_count (label->layout);
1070 perfect_width = (longest_paragraph + nlines - 1) / nlines;
1072 if (perfect_width < width)
1074 pango_layout_set_width (label->layout, perfect_width);
1075 pango_layout_get_extents (label->layout, NULL, &logical_rect);
1077 if (logical_rect.height <= height)
1079 width = perfect_width;
1080 real_width = logical_rect.width;
1081 height = logical_rect.height;
1085 gint mid_width = (perfect_width + width) / 2;
1087 if (mid_width > perfect_width)
1089 pango_layout_set_width (label->layout, mid_width);
1090 pango_layout_get_extents (label->layout, NULL, &logical_rect);
1092 if (logical_rect.height <= height)
1095 real_width = logical_rect.width;
1096 height = logical_rect.height;
1102 pango_layout_set_width (label->layout, width);
1104 rwidth += PANGO_PIXELS (real_width);
1105 rheight += PANGO_PIXELS (height);
1108 else /* !label->wrap */
1110 pango_layout_set_width (label->layout, -1);
1111 pango_layout_get_extents (label->layout, NULL, &logical_rect);
1113 rwidth += PANGO_PIXELS (logical_rect.width);
1114 rheight += PANGO_PIXELS (logical_rect.height);
1125 gtk_label_size_request (GtkWidget *widget,
1126 GtkRequisition *requisition)
1131 g_return_if_fail (GTK_IS_LABEL (widget));
1132 g_return_if_fail (requisition != NULL);
1134 label = GTK_LABEL (widget);
1136 gtk_label_ensure_layout (label, &width, &height);
1138 requisition->width = width;
1139 requisition->height = height;
1143 gtk_label_size_allocate (GtkWidget *widget,
1144 GtkAllocation *allocation)
1148 label = GTK_LABEL (widget);
1150 (* GTK_WIDGET_CLASS (parent_class)->size_allocate) (widget, allocation);
1152 if (label->select_info && label->select_info->window)
1154 gdk_window_move_resize (label->select_info->window,
1158 allocation->height);
1163 gtk_label_state_changed (GtkWidget *widget,
1164 GtkStateType prev_state)
1168 label = GTK_LABEL (widget);
1170 if (label->select_info)
1171 gtk_label_select_region (label, 0, 0);
1173 if (GTK_WIDGET_CLASS (parent_class)->state_changed)
1174 GTK_WIDGET_CLASS (parent_class)->state_changed (widget, prev_state);
1178 gtk_label_style_set (GtkWidget *widget,
1179 GtkStyle *previous_style)
1183 g_return_if_fail (GTK_IS_LABEL (widget));
1185 label = GTK_LABEL (widget);
1187 /* We have to clear the layout, fonts etc. may have changed */
1188 gtk_label_clear_layout (label);
1192 gtk_label_direction_changed (GtkWidget *widget,
1193 GtkTextDirection previous_dir)
1195 GtkLabel *label = GTK_LABEL (widget);
1198 pango_layout_context_changed (label->layout);
1200 GTK_WIDGET_CLASS (parent_class)->direction_changed (widget, previous_dir);
1205 gtk_label_paint_word (GtkLabel *label,
1211 GtkWidget *widget = GTK_WIDGET (label);
1212 GtkLabelULine *uline;
1215 tmp_str = gdk_wcstombs (word->beginning);
1218 gtk_paint_string (widget->style, widget->window, widget->state,
1219 area, widget, "label",
1226 for (uline = word->uline; uline; uline = uline->next)
1227 gtk_paint_hline (widget->style, widget->window,
1228 widget->state, area,
1230 x + uline->x1, x + uline->x2, y + uline->y);
1235 get_layout_location (GtkLabel *label,
1244 misc = GTK_MISC (label);
1245 widget = GTK_WIDGET (label);
1247 if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_LTR)
1248 xalign = misc->xalign;
1250 xalign = 1.0 - misc->xalign;
1252 x = floor (widget->allocation.x + (gint)misc->xpad
1253 + ((widget->allocation.width - widget->requisition.width) * xalign)
1256 y = floor (widget->allocation.y + (gint)misc->ypad
1257 + ((widget->allocation.height - widget->requisition.height) * misc->yalign)
1269 gtk_label_expose (GtkWidget *widget,
1270 GdkEventExpose *event)
1275 g_return_val_if_fail (GTK_IS_LABEL (widget), FALSE);
1276 g_return_val_if_fail (event != NULL, FALSE);
1278 label = GTK_LABEL (widget);
1280 gtk_label_ensure_layout (label, NULL, NULL);
1282 if (GTK_WIDGET_VISIBLE (widget) && GTK_WIDGET_MAPPED (widget) &&
1283 label->text && (*label->text != '\0'))
1285 get_layout_location (label, &x, &y);
1287 gtk_paint_layout (widget->style,
1289 GTK_WIDGET_STATE (widget),
1297 if (label->select_info &&
1298 (label->select_info->selection_anchor !=
1299 label->select_info->selection_end))
1304 range[0] = label->select_info->selection_anchor;
1305 range[1] = label->select_info->selection_end;
1307 if (range[0] > range[1])
1309 gint tmp = range[0];
1310 range[0] = range[1];
1314 clip = gdk_pango_layout_get_clip_region (label->layout,
1319 /* FIXME should use gtk_paint, but it can't use a clip
1323 gdk_gc_set_clip_region (widget->style->white_gc, clip);
1325 gdk_draw_layout_with_colors (widget->window,
1326 widget->style->white_gc,
1329 &widget->style->fg[GTK_STATE_SELECTED],
1330 &widget->style->bg[GTK_STATE_SELECTED]);
1332 gdk_gc_set_clip_region (widget->style->white_gc, NULL);
1333 gdk_region_destroy (clip);
1341 gtk_label_set_uline_text_internal (GtkLabel *label,
1344 guint accel_key = GDK_VoidSymbol;
1349 gchar *dest, *pattern_dest;
1350 gboolean underscore;
1352 g_return_if_fail (GTK_IS_LABEL (label));
1353 g_return_if_fail (str != NULL);
1355 /* Convert text to wide characters */
1357 new_str = g_new (gchar, strlen (str) + 1);
1358 pattern = g_new (gchar, g_utf8_strlen (str, -1) + 1);
1367 pattern_dest = pattern;
1374 c = g_utf8_get_char (src);
1375 if (c == (gunichar)-1)
1377 g_warning ("Invalid input string");
1382 next_src = g_utf8_next_char (src);
1387 *pattern_dest++ = ' ';
1390 *pattern_dest++ = '_';
1391 if (accel_key == GDK_VoidSymbol)
1392 accel_key = gdk_keyval_to_lower (c);
1395 while (src < next_src)
1409 while (src < next_src)
1412 *pattern_dest++ = ' ';
1419 gtk_label_set_text_internal (label, new_str);
1420 gtk_label_set_pattern_internal (label, pattern);
1424 label->mnemonic_keyval = accel_key;
1428 gtk_label_parse_uline (GtkLabel *label,
1434 g_return_val_if_fail (GTK_IS_LABEL (label), GDK_VoidSymbol);
1435 g_return_val_if_fail (str != NULL, GDK_VoidSymbol);
1437 orig_keyval = label->mnemonic_keyval;
1439 gtk_label_set_label_internal (label, g_strdup (str ? str : ""));
1440 gtk_label_set_use_markup_internal (label, FALSE);
1441 gtk_label_set_use_underline_internal (label, TRUE);
1443 gtk_label_recalculate (label);
1445 keyval = label->mnemonic_keyval;
1446 label->mnemonic_keyval = GDK_VoidSymbol;
1448 gtk_label_setup_mnemonic (label, orig_keyval);
1454 * gtk_label_set_text_with_mnemonic:
1455 * @label: a #GtkLabel
1458 * Sets the label's text from the string @str.
1459 * If characters in @str are preceded by an underscore, they are underlined
1460 * indicating that they represent a keyboard accelerator called a mnemonic.
1461 * The mnemonic key can be used to activate another widget, chosen automatically,
1462 * or explicitly using gtk_label_set_mnemonic_widget().
1465 gtk_label_set_text_with_mnemonic (GtkLabel *label,
1470 g_return_if_fail (GTK_IS_LABEL (label));
1471 g_return_if_fail (str != NULL);
1473 last_keyval = label->mnemonic_keyval;
1475 gtk_label_set_label_internal (label, g_strdup (str ? str : ""));
1476 gtk_label_set_use_markup_internal (label, FALSE);
1477 gtk_label_set_use_underline_internal (label, TRUE);
1479 gtk_label_recalculate (label);
1481 gtk_label_setup_mnemonic (label, last_keyval);
1486 gtk_label_realize (GtkWidget *widget)
1490 label = GTK_LABEL (widget);
1492 (* GTK_WIDGET_CLASS (parent_class)->realize) (widget);
1494 if (label->select_info)
1495 gtk_label_create_window (label);
1499 gtk_label_unrealize (GtkWidget *widget)
1503 label = GTK_LABEL (widget);
1505 if (label->select_info)
1506 gtk_label_destroy_window (label);
1508 (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
1512 gtk_label_map (GtkWidget *widget)
1516 label = GTK_LABEL (widget);
1518 (* GTK_WIDGET_CLASS (parent_class)->map) (widget);
1520 if (label->select_info)
1521 gdk_window_show (label->select_info->window);
1525 gtk_label_unmap (GtkWidget *widget)
1529 label = GTK_LABEL (widget);
1531 if (label->select_info)
1532 gdk_window_hide (label->select_info->window);
1534 (* GTK_WIDGET_CLASS (parent_class)->unmap) (widget);
1538 window_to_layout_coords (GtkLabel *label,
1545 widget = GTK_WIDGET (label);
1547 /* get layout location in widget->window coords */
1548 get_layout_location (label, &lx, &ly);
1552 *x += widget->allocation.x; /* go to widget->window */
1553 *x -= lx; /* go to layout */
1558 *y += widget->allocation.y; /* go to widget->window */
1559 *y -= ly; /* go to layout */
1565 layout_to_window_coords (GtkLabel *label,
1572 widget = GTK_WIDGET (label);
1574 /* get layout location in widget->window coords */
1575 get_layout_location (label, &lx, &ly);
1579 *x += lx; /* go to widget->window */
1580 *x -= widget->allocation.x; /* go to selection window */
1585 *y += ly; /* go to widget->window */
1586 *y -= widget->allocation.y; /* go to selection window */
1592 get_layout_index (GtkLabel *label,
1598 const gchar *cluster;
1599 const gchar *cluster_end;
1603 gtk_label_ensure_layout (label, NULL, NULL);
1605 window_to_layout_coords (label, &x, &y);
1610 pango_layout_xy_to_index (label->layout,
1615 cluster = label->text + *index;
1616 cluster_end = cluster;
1619 cluster_end = g_utf8_next_char (cluster_end);
1623 *index += (cluster_end - cluster);
1627 gtk_label_button_press (GtkWidget *widget,
1628 GdkEventButton *event)
1633 label = GTK_LABEL (widget);
1635 if (label->select_info == NULL)
1638 if (event->button != 1)
1641 get_layout_index (label, event->x, event->y, &index);
1643 if ((label->select_info->selection_anchor !=
1644 label->select_info->selection_end) &&
1645 (event->state & GDK_SHIFT_MASK))
1647 /* extend (same as motion) */
1648 if (index < label->select_info->selection_end)
1649 gtk_label_select_region_index (label,
1651 label->select_info->selection_end);
1653 gtk_label_select_region_index (label,
1654 label->select_info->selection_anchor,
1657 /* ensure the anchor is opposite index */
1658 if (index == label->select_info->selection_anchor)
1660 gint tmp = label->select_info->selection_end;
1661 label->select_info->selection_end = label->select_info->selection_anchor;
1662 label->select_info->selection_anchor = tmp;
1667 /* start a replacement */
1668 gtk_label_select_region_index (label, index, index);
1675 gtk_label_button_release (GtkWidget *widget,
1676 GdkEventButton *event)
1681 label = GTK_LABEL (widget);
1683 if (label->select_info == NULL)
1686 if (event->button != 1)
1689 /* The goal here is to return TRUE iff we ate the
1690 * button press to start selecting.
1697 gtk_label_motion (GtkWidget *widget,
1698 GdkEventMotion *event)
1704 label = GTK_LABEL (widget);
1706 if (label->select_info == NULL)
1709 if ((event->state & GDK_BUTTON1_MASK) == 0)
1712 gdk_window_get_pointer (label->select_info->window,
1715 get_layout_index (label, x, y, &index);
1717 gtk_label_select_region_index (label,
1718 label->select_info->selection_anchor,
1725 gtk_label_create_window (GtkLabel *label)
1728 GdkWindowAttr attributes;
1729 gint attributes_mask;
1731 g_assert (label->select_info);
1732 g_assert (GTK_WIDGET_REALIZED (label));
1734 if (label->select_info->window)
1737 widget = GTK_WIDGET (label);
1739 attributes.x = widget->allocation.x;
1740 attributes.y = widget->allocation.y;
1741 attributes.width = widget->allocation.width;
1742 attributes.height = widget->allocation.height;
1743 attributes.window_type = GDK_WINDOW_TEMP;
1744 attributes.wclass = GDK_INPUT_ONLY;
1745 attributes.override_redirect = TRUE;
1746 attributes.event_mask = gtk_widget_get_events (widget) |
1747 GDK_BUTTON_PRESS_MASK |
1748 GDK_BUTTON_RELEASE_MASK |
1749 GDK_BUTTON_MOTION_MASK;
1751 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_NOREDIR;
1753 label->select_info->window = gdk_window_new (widget->window,
1754 &attributes, attributes_mask);
1755 gdk_window_set_user_data (label->select_info->window, widget);
1759 gtk_label_destroy_window (GtkLabel *label)
1761 g_assert (label->select_info);
1763 if (label->select_info->window == NULL)
1766 gdk_window_set_user_data (label->select_info->window, NULL);
1767 gdk_window_destroy (label->select_info->window);
1768 label->select_info->window = NULL;
1772 gtk_label_set_selectable (GtkLabel *label,
1775 gboolean old_setting;
1777 g_return_if_fail (GTK_IS_LABEL (label));
1779 setting = setting != FALSE;
1780 old_setting = label->select_info != NULL;
1784 if (label->select_info == NULL)
1786 label->select_info = g_new (GtkLabelSelectionInfo, 1);
1788 label->select_info->window = NULL;
1789 label->select_info->selection_anchor = 0;
1790 label->select_info->selection_end = 0;
1792 if (GTK_WIDGET_REALIZED (label))
1793 gtk_label_create_window (label);
1795 if (GTK_WIDGET_MAPPED (label))
1796 gdk_window_show (label->select_info->window);
1801 if (label->select_info)
1803 /* unselect, to give up the selection */
1804 gtk_label_select_region (label, 0, 0);
1806 if (label->select_info->window)
1807 gtk_label_destroy_window (label);
1809 g_free (label->select_info);
1811 label->select_info = NULL;
1814 if (setting != old_setting)
1816 g_object_notify (G_OBJECT (label), "selectable");
1817 gtk_widget_queue_draw (GTK_WIDGET (label));
1822 gtk_label_get_selectable (GtkLabel *label)
1824 g_return_val_if_fail (GTK_IS_LABEL (label), FALSE);
1826 return label->select_info != NULL;
1830 get_text_callback (GtkClipboard *clipboard,
1831 GtkSelectionData *selection_data,
1833 gpointer user_data_or_owner)
1838 label = GTK_LABEL (user_data_or_owner);
1840 if ((label->select_info->selection_anchor !=
1841 label->select_info->selection_end) &&
1847 start = MIN (label->select_info->selection_anchor,
1848 label->select_info->selection_end);
1849 end = MAX (label->select_info->selection_anchor,
1850 label->select_info->selection_end);
1852 len = strlen (label->text);
1860 str = g_strndup (label->text + start,
1863 gtk_selection_data_set_text (selection_data,
1871 clear_text_callback (GtkClipboard *clipboard,
1872 gpointer user_data_or_owner)
1876 label = GTK_LABEL (user_data_or_owner);
1878 if (label->select_info)
1880 label->select_info->selection_anchor = 0;
1881 label->select_info->selection_end = 0;
1883 gtk_label_clear_layout (label);
1884 gtk_widget_queue_draw (GTK_WIDGET (label));
1889 gtk_label_select_region_index (GtkLabel *label,
1893 static const GtkTargetEntry targets[] = {
1896 { "COMPOUND_TEXT", 0, 0 },
1897 { "UTF8_STRING", 0, 0 }
1900 g_return_if_fail (GTK_IS_LABEL (label));
1902 if (label->select_info)
1904 GtkClipboard *clipboard;
1906 label->select_info->selection_anchor = anchor_index;
1907 label->select_info->selection_end = end_index;
1909 clipboard = gtk_clipboard_get (GDK_SELECTION_PRIMARY);
1911 if (anchor_index != end_index)
1913 gtk_clipboard_set_with_owner (clipboard,
1915 G_N_ELEMENTS (targets),
1917 clear_text_callback,
1922 if (gtk_clipboard_get_owner (clipboard) == G_OBJECT (label))
1923 gtk_clipboard_clear (clipboard);
1926 gtk_label_clear_layout (label);
1927 gtk_widget_queue_draw (GTK_WIDGET (label));
1932 * gtk_label_select_region:
1933 * @label: a #GtkLabel
1934 * @start_offset: start offset (in characters not bytes)
1935 * @end_offset: end offset (in characters not bytes)
1937 * Selects a range of characters in the label, if the label is selectable.
1938 * See gtk_label_set_selectable(). If the label is not selectable,
1939 * this function has no effect. If @start_offset or
1940 * @end_offset are -1, then the end of the label will be substituted.
1944 gtk_label_select_region (GtkLabel *label,
1948 g_return_if_fail (GTK_IS_LABEL (label));
1950 if (label->text && label->select_info)
1952 if (start_offset < 0)
1953 start_offset = g_utf8_strlen (label->text, -1);
1956 end_offset = g_utf8_strlen (label->text, -1);
1958 gtk_label_select_region_index (label,
1959 g_utf8_offset_to_pointer (label->text, start_offset) - label->text,
1960 g_utf8_offset_to_pointer (label->text, end_offset) - label->text);
1965 * gtk_label_get_selection_bounds:
1966 * @label: a #GtkLabel
1967 * @start: return location for start of selection, as a character offset
1968 * @end: return location for end of selection, as a character offset
1970 * Gets the selected range of characters in the label, returning %TRUE
1971 * if there's a selection.
1973 * Return value: %TRUE if selection is non-empty
1976 gtk_label_get_selection_bounds (GtkLabel *label,
1980 g_return_val_if_fail (GTK_IS_LABEL (label), FALSE);
1982 if (label->select_info == NULL)
1984 /* not a selectable label */
1994 gint start_index, end_index;
1995 gint start_offset, end_offset;
1998 start_index = MIN (label->select_info->selection_anchor,
1999 label->select_info->selection_end);
2000 end_index = MAX (label->select_info->selection_anchor,
2001 label->select_info->selection_end);
2003 len = strlen (label->text);
2005 if (end_index > len)
2008 if (start_index > len)
2011 start_offset = g_utf8_strlen (label->text, start_index);
2012 end_offset = g_utf8_strlen (label->text, end_index);
2014 if (start_offset > end_offset)
2016 gint tmp = start_offset;
2017 start_offset = end_offset;
2022 *start = start_offset;
2027 return start_offset != end_offset;
2032 * gtk_label_get_layout_offsets:
2033 * @label: a #GtkLabel
2034 * @x: location to store X offset of layout, or %NULL
2035 * @y: location to store Y offset of layout, or %NULL
2037 * Obtains the coordinates where the label will draw the #PangoLayout
2038 * representing the text in the label; useful to convert mouse events
2039 * into coordinates inside the #PangoLayout, e.g. to take some action
2040 * if some part of the label is clicked. Of course you will need to
2041 * create a #GtkEventBox to receive the events, and pack the label
2042 * inside it, since labels are a #GTK_NO_WINDOW widget.
2046 gtk_label_get_layout_offsets (GtkLabel *label,
2050 g_return_if_fail (GTK_IS_LABEL (label));
2052 get_layout_location (label, x, y);