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/.
30 #include "gtkmarshalers.h"
31 #include "gtkwindow.h"
32 #include "gdk/gdkkeysyms.h"
33 #include "gtkclipboard.h"
34 #include <pango/pango.h>
35 #include "gtkimagemenuitem.h"
37 #include "gtkseparatormenuitem.h"
38 #include "gtkmenuitem.h"
39 #include "gtknotebook.h"
41 #include "gtkbindings.h"
43 struct _GtkLabelSelectionInfo
46 gint selection_anchor;
48 GtkWidget *popup_menu;
74 static guint signals[LAST_SIGNAL] = { 0 };
76 static void gtk_label_class_init (GtkLabelClass *klass);
77 static void gtk_label_init (GtkLabel *label);
78 static void gtk_label_set_property (GObject *object,
82 static void gtk_label_get_property (GObject *object,
86 static void gtk_label_destroy (GtkObject *object);
87 static void gtk_label_finalize (GObject *object);
88 static void gtk_label_size_request (GtkWidget *widget,
89 GtkRequisition *requisition);
90 static void gtk_label_size_allocate (GtkWidget *widget,
91 GtkAllocation *allocation);
92 static void gtk_label_state_changed (GtkWidget *widget,
94 static void gtk_label_style_set (GtkWidget *widget,
95 GtkStyle *previous_style);
96 static void gtk_label_direction_changed (GtkWidget *widget,
97 GtkTextDirection previous_dir);
98 static gint gtk_label_expose (GtkWidget *widget,
99 GdkEventExpose *event);
101 static void gtk_label_realize (GtkWidget *widget);
102 static void gtk_label_unrealize (GtkWidget *widget);
103 static void gtk_label_map (GtkWidget *widget);
104 static void gtk_label_unmap (GtkWidget *widget);
105 static gint gtk_label_button_press (GtkWidget *widget,
106 GdkEventButton *event);
107 static gint gtk_label_button_release (GtkWidget *widget,
108 GdkEventButton *event);
109 static gint gtk_label_motion (GtkWidget *widget,
110 GdkEventMotion *event);
113 static void gtk_label_set_text_internal (GtkLabel *label,
115 static void gtk_label_set_label_internal (GtkLabel *label,
117 static void gtk_label_set_use_markup_internal (GtkLabel *label,
119 static void gtk_label_set_use_underline_internal (GtkLabel *label,
121 static void gtk_label_set_attributes_internal (GtkLabel *label,
122 PangoAttrList *attrs);
123 static void gtk_label_set_uline_text_internal (GtkLabel *label,
125 static void gtk_label_set_pattern_internal (GtkLabel *label,
126 const gchar *pattern);
127 static void set_markup (GtkLabel *label,
129 gboolean with_uline);
130 static void gtk_label_recalculate (GtkLabel *label);
131 static void gtk_label_hierarchy_changed (GtkWidget *widget,
132 GtkWidget *old_toplevel);
134 static void gtk_label_create_window (GtkLabel *label);
135 static void gtk_label_destroy_window (GtkLabel *label);
136 static void gtk_label_clear_layout (GtkLabel *label);
137 static void gtk_label_ensure_layout (GtkLabel *label);
138 static void gtk_label_select_region_index (GtkLabel *label,
142 static gboolean gtk_label_mnemonic_activate (GtkWidget *widget,
143 gboolean group_cycling);
144 static void gtk_label_setup_mnemonic (GtkLabel *label,
146 static gboolean gtk_label_focus (GtkWidget *widget,
147 GtkDirectionType direction);
149 /* For selectable lables: */
150 static void gtk_label_move_cursor (GtkLabel *label,
151 GtkMovementStep step,
153 gboolean extend_selection);
154 static void gtk_label_copy_clipboard (GtkLabel *label);
155 static void gtk_label_select_all (GtkLabel *label);
156 static void gtk_label_do_popup (GtkLabel *label,
157 GdkEventButton *event);
159 static gint gtk_label_move_forward_word (GtkLabel *label,
161 static gint gtk_label_move_backward_word (GtkLabel *label,
164 static GtkMiscClass *parent_class = NULL;
168 gtk_label_get_type (void)
170 static GType label_type = 0;
174 static const GTypeInfo label_info =
176 sizeof (GtkLabelClass),
177 NULL, /* base_init */
178 NULL, /* base_finalize */
179 (GClassInitFunc) gtk_label_class_init,
180 NULL, /* class_finalize */
181 NULL, /* class_data */
183 32, /* n_preallocs */
184 (GInstanceInitFunc) gtk_label_init,
187 label_type = g_type_register_static (GTK_TYPE_MISC, "GtkLabel",
195 add_move_binding (GtkBindingSet *binding_set,
198 GtkMovementStep step,
201 g_return_if_fail ((modmask & GDK_SHIFT_MASK) == 0);
203 gtk_binding_entry_add_signal (binding_set, keyval, modmask,
207 G_TYPE_BOOLEAN, FALSE);
209 /* Selection-extending version */
210 gtk_binding_entry_add_signal (binding_set, keyval, modmask | GDK_SHIFT_MASK,
214 G_TYPE_BOOLEAN, TRUE);
218 gtk_label_class_init (GtkLabelClass *class)
220 GObjectClass *gobject_class = G_OBJECT_CLASS (class);
221 GtkObjectClass *object_class = GTK_OBJECT_CLASS (class);
222 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
223 GtkBindingSet *binding_set;
225 parent_class = g_type_class_peek_parent (class);
227 gobject_class->set_property = gtk_label_set_property;
228 gobject_class->get_property = gtk_label_get_property;
229 gobject_class->finalize = gtk_label_finalize;
231 object_class->destroy = gtk_label_destroy;
233 widget_class->size_request = gtk_label_size_request;
234 widget_class->size_allocate = gtk_label_size_allocate;
235 widget_class->state_changed = gtk_label_state_changed;
236 widget_class->style_set = gtk_label_style_set;
237 widget_class->direction_changed = gtk_label_direction_changed;
238 widget_class->expose_event = gtk_label_expose;
239 widget_class->realize = gtk_label_realize;
240 widget_class->unrealize = gtk_label_unrealize;
241 widget_class->map = gtk_label_map;
242 widget_class->unmap = gtk_label_unmap;
243 widget_class->button_press_event = gtk_label_button_press;
244 widget_class->button_release_event = gtk_label_button_release;
245 widget_class->motion_notify_event = gtk_label_motion;
246 widget_class->hierarchy_changed = gtk_label_hierarchy_changed;
247 widget_class->mnemonic_activate = gtk_label_mnemonic_activate;
248 widget_class->focus = gtk_label_focus;
250 class->move_cursor = gtk_label_move_cursor;
251 class->copy_clipboard = gtk_label_copy_clipboard;
253 signals[MOVE_CURSOR] =
254 g_signal_new ("move_cursor",
255 G_OBJECT_CLASS_TYPE (gobject_class),
256 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
257 G_STRUCT_OFFSET (GtkLabelClass, move_cursor),
259 _gtk_marshal_VOID__ENUM_INT_BOOLEAN,
261 GTK_TYPE_MOVEMENT_STEP,
265 signals[COPY_CLIPBOARD] =
266 g_signal_new ("copy_clipboard",
267 G_OBJECT_CLASS_TYPE (gobject_class),
268 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
269 G_STRUCT_OFFSET (GtkLabelClass, copy_clipboard),
271 _gtk_marshal_VOID__VOID,
274 signals[POPULATE_POPUP] =
275 g_signal_new ("populate_popup",
276 G_OBJECT_CLASS_TYPE (gobject_class),
278 G_STRUCT_OFFSET (GtkLabelClass, populate_popup),
280 _gtk_marshal_VOID__OBJECT,
284 g_object_class_install_property (gobject_class,
286 g_param_spec_string ("label",
288 _("The text of the label"),
291 g_object_class_install_property (gobject_class,
293 g_param_spec_boxed ("attributes",
295 _("A list of style attributes to apply to the text of the label"),
296 PANGO_TYPE_ATTR_LIST,
298 g_object_class_install_property (gobject_class,
300 g_param_spec_boolean ("use_markup",
302 _("The text of the label includes XML markup. See pango_parse_markup()"),
305 g_object_class_install_property (gobject_class,
307 g_param_spec_boolean ("use_underline",
309 _("If set, an underline in the text indicates the next character should be used for the mnemonic accelerator key"),
313 g_object_class_install_property (gobject_class,
315 g_param_spec_enum ("justify",
317 _("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"),
318 GTK_TYPE_JUSTIFICATION,
322 g_object_class_install_property (gobject_class,
324 g_param_spec_string ("pattern",
326 _("A string with _ characters in positions correspond to characters in the text to underline"),
330 g_object_class_install_property (gobject_class,
332 g_param_spec_boolean ("wrap",
334 _("If set, wrap lines if the text becomes too wide"),
337 g_object_class_install_property (gobject_class,
339 g_param_spec_boolean ("selectable",
341 _("Whether the label text can be selected with the mouse"),
344 g_object_class_install_property (gobject_class,
345 PROP_MNEMONIC_KEYVAL,
346 g_param_spec_uint ("mnemonic_keyval",
348 _("The mnemonic accelerator key for this label"),
353 g_object_class_install_property (gobject_class,
354 PROP_MNEMONIC_WIDGET,
355 g_param_spec_object ("mnemonic_widget",
356 _("Mnemonic widget"),
357 _("The widget to be activated when the label's mnemonic "
362 g_object_class_install_property (gobject_class,
363 PROP_CURSOR_POSITION,
364 g_param_spec_int ("cursor_position",
365 _("Cursor Position"),
366 _("The current position of the insertion cursor in chars"),
372 g_object_class_install_property (gobject_class,
373 PROP_SELECTION_BOUND,
374 g_param_spec_int ("selection_bound",
375 _("Selection Bound"),
376 _("The position of the opposite end of the selection from the cursor in chars"),
386 binding_set = gtk_binding_set_by_class (class);
388 /* Moving the insertion point */
389 add_move_binding (binding_set, GDK_Right, 0,
390 GTK_MOVEMENT_VISUAL_POSITIONS, 1);
392 add_move_binding (binding_set, GDK_Left, 0,
393 GTK_MOVEMENT_VISUAL_POSITIONS, -1);
395 add_move_binding (binding_set, GDK_KP_Right, 0,
396 GTK_MOVEMENT_VISUAL_POSITIONS, 1);
398 add_move_binding (binding_set, GDK_KP_Left, 0,
399 GTK_MOVEMENT_VISUAL_POSITIONS, -1);
401 add_move_binding (binding_set, GDK_f, GDK_CONTROL_MASK,
402 GTK_MOVEMENT_LOGICAL_POSITIONS, 1);
404 add_move_binding (binding_set, GDK_b, GDK_CONTROL_MASK,
405 GTK_MOVEMENT_LOGICAL_POSITIONS, -1);
407 add_move_binding (binding_set, GDK_Right, GDK_CONTROL_MASK,
408 GTK_MOVEMENT_WORDS, 1);
410 add_move_binding (binding_set, GDK_Left, GDK_CONTROL_MASK,
411 GTK_MOVEMENT_WORDS, -1);
413 add_move_binding (binding_set, GDK_KP_Right, GDK_CONTROL_MASK,
414 GTK_MOVEMENT_WORDS, 1);
416 add_move_binding (binding_set, GDK_KP_Left, GDK_CONTROL_MASK,
417 GTK_MOVEMENT_WORDS, -1);
419 add_move_binding (binding_set, GDK_a, GDK_CONTROL_MASK,
420 GTK_MOVEMENT_PARAGRAPH_ENDS, -1);
422 add_move_binding (binding_set, GDK_e, GDK_CONTROL_MASK,
423 GTK_MOVEMENT_PARAGRAPH_ENDS, 1);
425 add_move_binding (binding_set, GDK_f, GDK_MOD1_MASK,
426 GTK_MOVEMENT_WORDS, 1);
428 add_move_binding (binding_set, GDK_b, GDK_MOD1_MASK,
429 GTK_MOVEMENT_WORDS, -1);
431 add_move_binding (binding_set, GDK_Home, 0,
432 GTK_MOVEMENT_DISPLAY_LINE_ENDS, -1);
434 add_move_binding (binding_set, GDK_End, 0,
435 GTK_MOVEMENT_DISPLAY_LINE_ENDS, 1);
437 add_move_binding (binding_set, GDK_KP_Home, 0,
438 GTK_MOVEMENT_DISPLAY_LINE_ENDS, -1);
440 add_move_binding (binding_set, GDK_KP_End, 0,
441 GTK_MOVEMENT_DISPLAY_LINE_ENDS, 1);
443 add_move_binding (binding_set, GDK_Home, GDK_CONTROL_MASK,
444 GTK_MOVEMENT_BUFFER_ENDS, -1);
446 add_move_binding (binding_set, GDK_End, GDK_CONTROL_MASK,
447 GTK_MOVEMENT_BUFFER_ENDS, 1);
449 add_move_binding (binding_set, GDK_KP_Home, GDK_CONTROL_MASK,
450 GTK_MOVEMENT_BUFFER_ENDS, -1);
452 add_move_binding (binding_set, GDK_KP_End, GDK_CONTROL_MASK,
453 GTK_MOVEMENT_BUFFER_ENDS, 1);
456 gtk_binding_entry_add_signal (binding_set, GDK_c, GDK_CONTROL_MASK,
457 "copy_clipboard", 0);
461 gtk_label_set_property (GObject *object,
469 label = GTK_LABEL (object);
470 last_keyval = label->mnemonic_keyval;
475 gtk_label_set_label (label, g_value_get_string (value));
477 case PROP_ATTRIBUTES:
478 gtk_label_set_attributes (label, g_value_get_boxed (value));
480 case PROP_USE_MARKUP:
481 gtk_label_set_use_markup (label, g_value_get_boolean (value));
483 case PROP_USE_UNDERLINE:
484 gtk_label_set_use_underline (label, g_value_get_boolean (value));
487 gtk_label_set_justify (label, g_value_get_enum (value));
490 gtk_label_set_pattern (label, g_value_get_string (value));
493 gtk_label_set_line_wrap (label, g_value_get_boolean (value));
495 case PROP_SELECTABLE:
496 gtk_label_set_selectable (label, g_value_get_boolean (value));
498 case PROP_MNEMONIC_WIDGET:
499 gtk_label_set_mnemonic_widget (label, (GtkWidget*) g_value_get_object (value));
502 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
508 gtk_label_get_property (GObject *object,
515 label = GTK_LABEL (object);
520 g_value_set_string (value, label->label);
522 case PROP_ATTRIBUTES:
523 g_value_set_boxed (value, label->attrs);
525 case PROP_USE_MARKUP:
526 g_value_set_boolean (value, label->use_markup);
528 case PROP_USE_UNDERLINE:
529 g_value_set_boolean (value, label->use_underline);
532 g_value_set_enum (value, label->jtype);
535 g_value_set_boolean (value, label->wrap);
537 case PROP_SELECTABLE:
538 g_value_set_boolean (value, gtk_label_get_selectable (label));
540 case PROP_MNEMONIC_KEYVAL:
541 g_value_set_uint (value, label->mnemonic_keyval);
543 case PROP_MNEMONIC_WIDGET:
544 g_value_set_object (value, (GObject*) label->mnemonic_widget);
546 case PROP_CURSOR_POSITION:
547 if (label->select_info)
549 gint offset = g_utf8_pointer_to_offset (label->text,
550 label->text + label->select_info->selection_end);
551 g_value_set_int (value, offset);
554 g_value_set_int (value, 0);
556 case PROP_SELECTION_BOUND:
557 if (label->select_info)
559 gint offset = g_utf8_pointer_to_offset (label->text,
560 label->text + label->select_info->selection_anchor);
561 g_value_set_int (value, offset);
564 g_value_set_int (value, 0);
568 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
574 gtk_label_init (GtkLabel *label)
576 GTK_WIDGET_SET_FLAGS (label, GTK_NO_WINDOW);
580 label->jtype = GTK_JUSTIFY_LEFT;
583 label->use_underline = FALSE;
584 label->use_markup = FALSE;
586 label->mnemonic_keyval = GDK_VoidSymbol;
587 label->layout = NULL;
591 label->mnemonic_widget = NULL;
592 label->mnemonic_window = NULL;
594 gtk_label_set_text (label, "");
599 * @str: The text of the label
601 * Creates a new label with the given text inside it. You can
602 * pass %NULL to get an empty label widget.
604 * Return value: the new #GtkLabel
607 gtk_label_new (const gchar *str)
611 label = g_object_new (GTK_TYPE_LABEL, NULL);
614 gtk_label_set_text (label, str);
616 return GTK_WIDGET (label);
620 * gtk_label_new_with_mnemonic:
621 * @str: The text of the label, with an underscore in front of the
624 * Creates a new #GtkLabel, containing the text in @str.
626 * If characters in @str are preceded by an underscore, they are
627 * underlined. If you need a literal underscore character in a label, use
628 * '__' (two underscores). The first underlined character represents a
629 * keyboard accelerator called a mnemonic. The mnemonic key can be used
630 * to activate another widget, chosen automatically, or explicitly using
631 * gtk_label_set_mnemonic_widget().
633 * If gtk_label_set_mnemonic_widget()
634 * is not called, then the first activatable ancestor of the #GtkLabel
635 * will be chosen as the mnemonic widget. For instance, if the
636 * label is inside a button or menu item, the button or menu item will
637 * automatically become the mnemonic widget and be activated by
640 * Return value: the new #GtkLabel
643 gtk_label_new_with_mnemonic (const gchar *str)
647 label = g_object_new (GTK_TYPE_LABEL, NULL);
650 gtk_label_set_text_with_mnemonic (label, str);
652 return GTK_WIDGET (label);
656 gtk_label_mnemonic_activate (GtkWidget *widget,
657 gboolean group_cycling)
661 if (GTK_LABEL (widget)->mnemonic_widget)
662 return gtk_widget_mnemonic_activate (GTK_LABEL (widget)->mnemonic_widget, group_cycling);
664 /* Try to find the widget to activate by traversing the
667 parent = widget->parent;
669 if (parent && GTK_IS_NOTEBOOK (parent))
674 if (GTK_WIDGET_CAN_FOCUS (parent) ||
675 (!group_cycling && GTK_WIDGET_GET_CLASS (parent)->activate_signal) ||
676 (parent->parent && GTK_IS_NOTEBOOK (parent->parent)) ||
677 (GTK_IS_MENU_ITEM (parent)))
678 return gtk_widget_mnemonic_activate (parent, group_cycling);
679 parent = parent->parent;
682 /* barf if there was nothing to activate */
683 g_warning ("Couldn't find a target for a mnemonic activation.");
684 gdk_display_beep (gtk_widget_get_display (widget));
690 gtk_label_setup_mnemonic (GtkLabel *label,
695 if (last_key != GDK_VoidSymbol && label->mnemonic_window)
697 gtk_window_remove_mnemonic (label->mnemonic_window,
700 label->mnemonic_window = NULL;
703 if (label->mnemonic_keyval == GDK_VoidSymbol)
706 toplevel = gtk_widget_get_toplevel (GTK_WIDGET (label));
707 if (GTK_WIDGET_TOPLEVEL (toplevel))
709 gtk_window_add_mnemonic (GTK_WINDOW (toplevel),
710 label->mnemonic_keyval,
712 label->mnemonic_window = GTK_WINDOW (toplevel);
717 gtk_label_hierarchy_changed (GtkWidget *widget,
718 GtkWidget *old_toplevel)
720 GtkLabel *label = GTK_LABEL (widget);
722 /* in case the label has been reparented to another screen */
723 gtk_label_clear_layout (label);
725 gtk_label_setup_mnemonic (label, label->mnemonic_keyval);
729 label_mnemonic_widget_weak_notify (gpointer data,
730 GObject *where_the_object_was)
732 GtkLabel *label = data;
734 label->mnemonic_widget = NULL;
735 g_object_notify (G_OBJECT (label), "mnemonic_widget");
739 * gtk_label_set_mnemonic_widget:
740 * @label: a #GtkLabel
741 * @widget: the target #GtkWidget
743 * If the label has been set so that it has an mnemonic key (using
744 * i.e. gtk_label_set_markup_with_mnemonic(),
745 * gtk_label_set_text_with_mnemonic(), gtk_label_new_with_mnemonic()
746 * or the "use_underline" property) the label can be associated with a
747 * widget that is the target of the mnemonic. When the label is inside
748 * a widget (like a #GtkButton or a #GtkNotebook tab) it is
749 * automatically associated with the correct widget, but sometimes
750 * (i.e. when the target is a #GtkEntry next to the label) you need to
751 * set it explicitly using this function.
753 * The target widget will be accelerated by emitting "mnemonic_activate" on it.
754 * The default handler for this signal will activate the widget if there are no
755 * mnemonic collisions and toggle focus between the colliding widgets otherwise.
758 gtk_label_set_mnemonic_widget (GtkLabel *label,
761 g_return_if_fail (GTK_IS_LABEL (label));
763 g_return_if_fail (GTK_IS_WIDGET (widget));
765 if (label->mnemonic_widget)
766 g_object_weak_unref (G_OBJECT (label->mnemonic_widget),
767 label_mnemonic_widget_weak_notify,
769 label->mnemonic_widget = widget;
770 if (label->mnemonic_widget)
771 g_object_weak_ref (G_OBJECT (label->mnemonic_widget),
772 label_mnemonic_widget_weak_notify,
775 g_object_notify (G_OBJECT (label), "mnemonic_widget");
779 * gtk_label_get_mnemonic_widget:
780 * @label: a #GtkLabel
782 * Retrieves the target of the mnemonic (keyboard shortcut) of this
783 * label. See gtk_label_set_mnemonic_widget ().
785 * Return value: the target of the label's mnemonic, or %NULL if none
786 * has been set and the default algorithm will be used.
789 gtk_label_get_mnemonic_widget (GtkLabel *label)
791 g_return_val_if_fail (GTK_IS_LABEL (label), NULL);
793 return label->mnemonic_widget;
797 * gtk_label_get_mnemonic_keyval:
798 * @label: a #GtkLabel
800 * If the label has been set so that it has an mnemonic key this function
801 * returns the keyval used for the mnemonic accelerator. If there is no
802 * mnemonic set up it returns #GDK_VoidSymbol.
804 * Returns: GDK keyval usable for accelerators, or #GDK_VoidSymbol
807 gtk_label_get_mnemonic_keyval (GtkLabel *label)
809 g_return_val_if_fail (GTK_IS_LABEL (label), GDK_VoidSymbol);
811 return label->mnemonic_keyval;
815 gtk_label_set_text_internal (GtkLabel *label,
818 g_free (label->text);
822 gtk_label_select_region_index (label, 0, 0);
826 gtk_label_set_label_internal (GtkLabel *label,
829 g_free (label->label);
833 g_object_notify (G_OBJECT (label), "label");
837 gtk_label_set_use_markup_internal (GtkLabel *label,
841 if (label->use_markup != val)
843 g_object_notify (G_OBJECT (label), "use_markup");
844 label->use_markup = val;
849 gtk_label_set_use_underline_internal (GtkLabel *label,
853 if (label->use_underline != val)
855 g_object_notify (G_OBJECT (label), "use_underline");
856 label->use_underline = val;
861 gtk_label_set_attributes_internal (GtkLabel *label,
862 PangoAttrList *attrs)
865 pango_attr_list_ref (attrs);
868 pango_attr_list_unref (label->attrs);
870 if (!label->use_markup && !label->use_underline)
872 pango_attr_list_ref (attrs);
873 if (label->effective_attrs)
874 pango_attr_list_unref (label->effective_attrs);
875 label->effective_attrs = attrs;
878 label->attrs = attrs;
879 g_object_notify (G_OBJECT (label), "attributes");
883 /* Calculates text, attrs and mnemonic_keyval from
884 * label, use_underline and use_markup
887 gtk_label_recalculate (GtkLabel *label)
889 if (label->use_markup)
890 set_markup (label, label->label, label->use_underline);
893 if (label->use_underline)
894 gtk_label_set_uline_text_internal (label, label->label);
897 gtk_label_set_text_internal (label, g_strdup (label->label));
899 pango_attr_list_ref (label->attrs);
900 if (label->effective_attrs)
901 pango_attr_list_unref (label->effective_attrs);
902 label->effective_attrs = label->attrs;
906 if (!label->use_underline)
908 guint keyval = label->mnemonic_keyval;
910 label->mnemonic_keyval = GDK_VoidSymbol;
911 gtk_label_setup_mnemonic (label, keyval);
914 gtk_label_clear_layout (label);
915 gtk_widget_queue_resize (GTK_WIDGET (label));
919 * gtk_label_set_text:
920 * @label: a #GtkLabel
921 * @str: The text you want to set.
923 * Sets the text within the #GtkLabel widget. It overwrites any text that
926 * This will also clear any previously set mnemonic accelerators.
929 gtk_label_set_text (GtkLabel *label,
932 g_return_if_fail (GTK_IS_LABEL (label));
934 g_object_freeze_notify (G_OBJECT (label));
936 gtk_label_set_label_internal (label, g_strdup (str ? str : ""));
937 gtk_label_set_use_markup_internal (label, FALSE);
938 gtk_label_set_use_underline_internal (label, FALSE);
940 gtk_label_recalculate (label);
942 g_object_thaw_notify (G_OBJECT (label));
946 * gtk_label_set_attributes:
947 * @label: a #GtkLabel
948 * @attrs: a #PangoAttrList
950 * Sets a #PangoAttrList; the attributes in the list are applied to the
951 * label text. The attributes set with this function will be ignored
952 * if the "use_underline" property or the "use_markup" property
956 gtk_label_set_attributes (GtkLabel *label,
957 PangoAttrList *attrs)
959 g_return_if_fail (GTK_IS_LABEL (label));
961 gtk_label_set_attributes_internal (label, attrs);
963 gtk_label_clear_layout (label);
964 gtk_widget_queue_resize (GTK_WIDGET (label));
968 * gtk_label_get_attributes:
969 * @label: a #GtkLabel
971 * Gets the attribute list that was set on the label using
972 * gtk_label_set_attributes(), if any. This function does
973 * not reflect attributes that come from the labels markup
974 * (see gtk_label_set_markup()). If you want to get the
975 * effective attributes for the label, use
976 * pango_layout_get_attribute (gtk_label_get_layout (label)).
978 * Return value: the attribute list, or %NULL if none was set.
981 gtk_label_get_attributes (GtkLabel *label)
983 g_return_val_if_fail (GTK_IS_LABEL (label), NULL);
989 * gtk_label_set_label:
990 * @label: a #GtkLabel
991 * @str: the new text to set for the label
993 * Sets the text of the label. The label is interpreted as
994 * including embedded underlines and/or Pango markup depending
995 * on the values of label->use_underline and label->use_markup.
998 gtk_label_set_label (GtkLabel *label,
1003 g_return_if_fail (GTK_IS_LABEL (label));
1004 g_return_if_fail (str != NULL);
1006 last_keyval = label->mnemonic_keyval;
1008 gtk_label_set_label_internal (label, g_strdup (str));
1009 gtk_label_recalculate (label);
1010 if (last_keyval != label->mnemonic_keyval)
1011 gtk_label_setup_mnemonic (label, last_keyval);
1015 * gtk_label_get_label:
1016 * @label: a #GtkLabel
1018 * Fetches the text from a label widget including any embedded
1019 * underlines indicating mnemonics and Pango markup. (See
1020 * gtk_label_get_text ()).
1022 * Return value: the text of the label widget. This string is
1023 * owned by the widget and must not be modified or freed.
1025 G_CONST_RETURN gchar *
1026 gtk_label_get_label (GtkLabel *label)
1028 g_return_val_if_fail (GTK_IS_LABEL (label), NULL);
1030 return label->label;
1034 set_markup (GtkLabel *label,
1036 gboolean with_uline)
1039 GError *error = NULL;
1040 PangoAttrList *attrs = NULL;
1041 gunichar accel_char = 0;
1043 if (!pango_parse_markup (str,
1045 with_uline ? '_' : 0,
1048 with_uline ? &accel_char : NULL,
1051 g_warning ("Failed to set label from markup due to error parsing markup: %s",
1053 g_error_free (error);
1058 gtk_label_set_text_internal (label, text);
1062 if (label->effective_attrs)
1063 pango_attr_list_unref (label->effective_attrs);
1064 label->effective_attrs = attrs;
1067 if (accel_char != 0)
1068 label->mnemonic_keyval = gdk_keyval_to_lower (gdk_unicode_to_keyval (accel_char));
1070 label->mnemonic_keyval = GDK_VoidSymbol;
1074 * gtk_label_set_markup:
1075 * @label: a #GtkLabel
1076 * @str: a markup string (see <link linkend="PangoMarkupFormat">Pango markup format</link>)
1078 * Parses @str which is marked up with the <link linkend="PangoMarkupFormat">Pango text markup language</link>,
1079 * setting the label's text and attribute list based on the parse results.
1082 gtk_label_set_markup (GtkLabel *label,
1085 g_return_if_fail (GTK_IS_LABEL (label));
1087 gtk_label_set_label_internal (label, g_strdup (str ? str : ""));
1088 gtk_label_set_use_markup_internal (label, TRUE);
1089 gtk_label_set_use_underline_internal (label, FALSE);
1091 gtk_label_recalculate (label);
1095 * gtk_label_set_markup_with_mnemonic:
1096 * @label: a #GtkLabel
1097 * @str: a markup string (see <link linkend="PangoMarkupFormat">Pango markup format</link>)
1099 * Parses @str which is marked up with the <link linkend="PangoMarkupFormat">Pango text markup language</link>,
1100 * setting the label's text and attribute list based on the parse results.
1101 * If characters in @str are preceded by an underscore, they are underlined
1102 * indicating that they represent a keyboard accelerator called a mnemonic.
1104 * The mnemonic key can be used to activate another widget, chosen automatically,
1105 * or explicitly using gtk_label_set_mnemonic_widget().
1108 gtk_label_set_markup_with_mnemonic (GtkLabel *label,
1112 g_return_if_fail (GTK_IS_LABEL (label));
1114 last_keyval = label->mnemonic_keyval;
1115 gtk_label_set_label_internal (label, g_strdup (str ? str : ""));
1116 gtk_label_set_use_markup_internal (label, TRUE);
1117 gtk_label_set_use_underline_internal (label, TRUE);
1119 gtk_label_recalculate (label);
1120 gtk_label_setup_mnemonic (label, last_keyval);
1124 * gtk_label_get_text:
1125 * @label: a #GtkLabel
1127 * Fetches the text from a label widget, as displayed on the
1128 * screen. This does not include any embedded underlines
1129 * indicating mnemonics or Pango markup. (See gtk_label_get_label())
1131 * Return value: the text in the label widget. This is the internal
1132 * string used by the label, and must not be modified.
1134 G_CONST_RETURN gchar *
1135 gtk_label_get_text (GtkLabel *label)
1137 g_return_val_if_fail (GTK_IS_LABEL (label), NULL);
1142 static PangoAttrList *
1143 gtk_label_pattern_to_attrs (GtkLabel *label,
1144 const gchar *pattern)
1147 const char *p = label->text;
1148 const char *q = pattern;
1149 PangoAttrList *attrs;
1151 attrs = pango_attr_list_new ();
1155 while (*p && *q && *q != '_')
1157 p = g_utf8_next_char (p);
1161 while (*p && *q && *q == '_')
1163 p = g_utf8_next_char (p);
1169 PangoAttribute *attr = pango_attr_underline_new (PANGO_UNDERLINE_LOW);
1170 attr->start_index = start - label->text;
1171 attr->end_index = p - label->text;
1173 pango_attr_list_insert (attrs, attr);
1183 gtk_label_set_pattern_internal (GtkLabel *label,
1184 const gchar *pattern)
1186 PangoAttrList *attrs;
1187 g_return_if_fail (GTK_IS_LABEL (label));
1189 attrs = gtk_label_pattern_to_attrs (label, pattern);
1191 if (label->effective_attrs)
1192 pango_attr_list_unref (label->effective_attrs);
1193 label->effective_attrs = attrs;
1197 gtk_label_set_pattern (GtkLabel *label,
1198 const gchar *pattern)
1200 g_return_if_fail (GTK_IS_LABEL (label));
1202 gtk_label_set_pattern_internal (label, pattern);
1204 gtk_label_clear_layout (label);
1205 gtk_widget_queue_resize (GTK_WIDGET (label));
1210 * gtk_label_set_justify:
1211 * @label: a #GtkLabel
1212 * @jtype: a #GtkJustification
1214 * Sets the alignment of the lines in the text of the label relative to
1215 * each other. %GTK_JUSTIFY_LEFT is the default value when the
1216 * widget is first created with gtk_label_new(). If you instead want
1217 * to set the alignment of the label as a whole, use
1218 * gtk_misc_set_alignment() instead. gtk_label_set_justify() has no
1219 * effect on labels containing only a single line.
1222 gtk_label_set_justify (GtkLabel *label,
1223 GtkJustification jtype)
1225 g_return_if_fail (GTK_IS_LABEL (label));
1226 g_return_if_fail (jtype >= GTK_JUSTIFY_LEFT && jtype <= GTK_JUSTIFY_FILL);
1228 if ((GtkJustification) label->jtype != jtype)
1230 label->jtype = jtype;
1232 /* No real need to be this drastic, but easier than duplicating the code */
1233 gtk_label_clear_layout (label);
1235 g_object_notify (G_OBJECT (label), "justify");
1236 gtk_widget_queue_resize (GTK_WIDGET (label));
1241 * gtk_label_get_justify:
1242 * @label: a #GtkLabel
1244 * Returns the justification of the label. See gtk_label_set_justify ().
1246 * Return value: #GtkJustification
1249 gtk_label_get_justify (GtkLabel *label)
1251 g_return_val_if_fail (GTK_IS_LABEL (label), 0);
1253 return label->jtype;
1257 * gtk_label_set_line_wrap:
1258 * @label: a #GtkLabel
1259 * @wrap: the setting
1261 * Toggles line wrapping within the #GtkLabel widget. %TRUE makes it break
1262 * lines if text exceeds the widget's size. %FALSE lets the text get cut off
1263 * by the edge of the widget if it exceeds the widget size.
1266 gtk_label_set_line_wrap (GtkLabel *label,
1269 g_return_if_fail (GTK_IS_LABEL (label));
1271 wrap = wrap != FALSE;
1273 if (label->wrap != wrap)
1276 g_object_notify (G_OBJECT (label), "wrap");
1278 gtk_widget_queue_resize (GTK_WIDGET (label));
1283 * gtk_label_get_line_wrap:
1284 * @label: a #GtkLabel
1286 * Returns whether lines in the label are automatically wrapped. See gtk_label_set_line_wrap ().
1288 * Return value: %TRUE if the lines of the label are automatically wrapped.
1291 gtk_label_get_line_wrap (GtkLabel *label)
1293 g_return_val_if_fail (GTK_IS_LABEL (label), FALSE);
1299 gtk_label_get (GtkLabel *label,
1302 g_return_if_fail (GTK_IS_LABEL (label));
1303 g_return_if_fail (str != NULL);
1309 gtk_label_destroy (GtkObject *object)
1311 GtkLabel *label = GTK_LABEL (object);
1313 gtk_label_set_mnemonic_widget (label, NULL);
1315 GTK_OBJECT_CLASS (parent_class)->destroy (object);
1319 gtk_label_finalize (GObject *object)
1323 g_return_if_fail (GTK_IS_LABEL (object));
1325 label = GTK_LABEL (object);
1327 g_free (label->label);
1328 g_free (label->text);
1331 g_object_unref (label->layout);
1334 pango_attr_list_unref (label->attrs);
1336 if (label->effective_attrs)
1337 pango_attr_list_unref (label->effective_attrs);
1339 g_free (label->select_info);
1341 G_OBJECT_CLASS (parent_class)->finalize (object);
1345 gtk_label_clear_layout (GtkLabel *label)
1349 g_object_unref (label->layout);
1350 label->layout = NULL;
1354 typedef struct _LabelWrapWidth LabelWrapWidth;
1355 struct _LabelWrapWidth
1358 PangoFontDescription *font_desc;
1362 label_wrap_width_free (gpointer data)
1364 LabelWrapWidth *wrap_width = data;
1365 pango_font_description_free (wrap_width->font_desc);
1366 g_free (wrap_width);
1370 get_label_wrap_width (GtkLabel *label)
1372 PangoLayout *layout;
1373 GtkStyle *style = GTK_WIDGET (label)->style;
1375 LabelWrapWidth *wrap_width = g_object_get_data (G_OBJECT (style), "gtk-label-wrap-width");
1378 wrap_width = g_new0 (LabelWrapWidth, 1);
1379 g_object_set_data_full (G_OBJECT (style), "gtk-label-wrap-width",
1380 wrap_width, label_wrap_width_free);
1383 if (wrap_width->font_desc && pango_font_description_equal (wrap_width->font_desc, style->font_desc))
1384 return wrap_width->width;
1386 if (wrap_width->font_desc)
1387 pango_font_description_free (wrap_width->font_desc);
1389 wrap_width->font_desc = pango_font_description_copy (style->font_desc);
1391 layout = gtk_widget_create_pango_layout (GTK_WIDGET (label),
1392 "This long string gives a good enough length for any line to have.");
1393 pango_layout_get_size (layout, &wrap_width->width, NULL);
1394 g_object_unref (layout);
1396 return wrap_width->width;
1400 gtk_label_ensure_layout (GtkLabel *label)
1403 PangoRectangle logical_rect;
1404 gint rwidth, rheight;
1406 widget = GTK_WIDGET (label);
1408 rwidth = label->misc.xpad * 2;
1409 rheight = label->misc.ypad * 2;
1413 PangoAlignment align = PANGO_ALIGN_LEFT; /* Quiet gcc */
1415 label->layout = gtk_widget_create_pango_layout (widget, label->text);
1417 if (label->effective_attrs)
1418 pango_layout_set_attributes (label->layout, label->effective_attrs);
1420 switch (label->jtype)
1422 case GTK_JUSTIFY_LEFT:
1423 align = PANGO_ALIGN_LEFT;
1425 case GTK_JUSTIFY_RIGHT:
1426 align = PANGO_ALIGN_RIGHT;
1428 case GTK_JUSTIFY_CENTER:
1429 align = PANGO_ALIGN_CENTER;
1431 case GTK_JUSTIFY_FILL:
1432 /* FIXME: This just doesn't work to do this */
1433 align = PANGO_ALIGN_LEFT;
1434 pango_layout_set_justify (label->layout, TRUE);
1437 g_assert_not_reached();
1440 pango_layout_set_alignment (label->layout, align);
1444 GtkWidgetAuxInfo *aux_info;
1445 gint longest_paragraph;
1448 aux_info = _gtk_widget_get_aux_info (widget, FALSE);
1449 if (aux_info && aux_info->width > 0)
1450 pango_layout_set_width (label->layout, aux_info->width * PANGO_SCALE);
1453 GdkScreen *screen = gtk_widget_get_screen (GTK_WIDGET (label));
1456 pango_layout_set_width (label->layout, -1);
1457 pango_layout_get_extents (label->layout, NULL, &logical_rect);
1459 width = logical_rect.width;
1461 /* Try to guess a reasonable maximum width */
1462 longest_paragraph = width;
1464 wrap_width = get_label_wrap_width (label);
1465 width = MIN (width, wrap_width);
1467 PANGO_SCALE * (gdk_screen_get_width (screen) + 1) / 2);
1469 pango_layout_set_width (label->layout, width);
1470 pango_layout_get_extents (label->layout, NULL, &logical_rect);
1471 width = logical_rect.width;
1472 height = logical_rect.height;
1474 /* Unfortunately, the above may leave us with a very unbalanced looking paragraph,
1475 * so we try short search for a narrower width that leaves us with the same height
1477 if (longest_paragraph > 0)
1479 gint nlines, perfect_width;
1481 nlines = pango_layout_get_line_count (label->layout);
1482 perfect_width = (longest_paragraph + nlines - 1) / nlines;
1484 if (perfect_width < width)
1486 pango_layout_set_width (label->layout, perfect_width);
1487 pango_layout_get_extents (label->layout, NULL, &logical_rect);
1489 if (logical_rect.height <= height)
1490 width = logical_rect.width;
1493 gint mid_width = (perfect_width + width) / 2;
1495 if (mid_width > perfect_width)
1497 pango_layout_set_width (label->layout, mid_width);
1498 pango_layout_get_extents (label->layout, NULL, &logical_rect);
1500 if (logical_rect.height <= height)
1501 width = logical_rect.width;
1506 pango_layout_set_width (label->layout, width);
1509 else /* !label->wrap */
1510 pango_layout_set_width (label->layout, -1);
1515 gtk_label_size_request (GtkWidget *widget,
1516 GtkRequisition *requisition)
1520 PangoRectangle logical_rect;
1521 GtkWidgetAuxInfo *aux_info;
1523 g_return_if_fail (GTK_IS_LABEL (widget));
1524 g_return_if_fail (requisition != NULL);
1526 label = GTK_LABEL (widget);
1529 * If word wrapping is on, then the height requisition can depend
1532 * - Any width set on the widget via gtk_widget_set_usize().
1533 * - The padding of the widget (xpad, set by gtk_misc_set_padding)
1535 * Instead of trying to detect changes to these quantities, if we
1536 * are wrapping, we just rewrap for each size request. Since
1537 * size requisitions are cached by the GTK+ core, this is not
1542 gtk_label_clear_layout (label);
1544 gtk_label_ensure_layout (label);
1546 width = label->misc.xpad * 2;
1547 height = label->misc.ypad * 2;
1549 pango_layout_get_extents (label->layout, NULL, &logical_rect);
1551 aux_info = _gtk_widget_get_aux_info (widget, FALSE);
1552 if (label->wrap && aux_info && aux_info->width > 0)
1553 width += aux_info->width;
1555 width += PANGO_PIXELS (logical_rect.width);
1557 height += PANGO_PIXELS (logical_rect.height);
1559 requisition->width = width;
1560 requisition->height = height;
1564 gtk_label_size_allocate (GtkWidget *widget,
1565 GtkAllocation *allocation)
1569 label = GTK_LABEL (widget);
1571 (* GTK_WIDGET_CLASS (parent_class)->size_allocate) (widget, allocation);
1573 if (label->select_info && label->select_info->window)
1575 gdk_window_move_resize (label->select_info->window,
1579 allocation->height);
1584 gtk_label_state_changed (GtkWidget *widget,
1585 GtkStateType prev_state)
1589 label = GTK_LABEL (widget);
1591 if (label->select_info)
1592 gtk_label_select_region (label, 0, 0);
1594 if (GTK_WIDGET_CLASS (parent_class)->state_changed)
1595 GTK_WIDGET_CLASS (parent_class)->state_changed (widget, prev_state);
1599 gtk_label_style_set (GtkWidget *widget,
1600 GtkStyle *previous_style)
1604 g_return_if_fail (GTK_IS_LABEL (widget));
1606 label = GTK_LABEL (widget);
1608 /* We have to clear the layout, fonts etc. may have changed */
1609 gtk_label_clear_layout (label);
1613 gtk_label_direction_changed (GtkWidget *widget,
1614 GtkTextDirection previous_dir)
1616 GtkLabel *label = GTK_LABEL (widget);
1619 pango_layout_context_changed (label->layout);
1621 GTK_WIDGET_CLASS (parent_class)->direction_changed (widget, previous_dir);
1626 gtk_label_paint_word (GtkLabel *label,
1632 GtkWidget *widget = GTK_WIDGET (label);
1633 GtkLabelULine *uline;
1636 tmp_str = gdk_wcstombs (word->beginning);
1639 gtk_paint_string (widget->style, widget->window, widget->state,
1640 area, widget, "label",
1647 for (uline = word->uline; uline; uline = uline->next)
1648 gtk_paint_hline (widget->style, widget->window,
1649 widget->state, area,
1651 x + uline->x1, x + uline->x2, y + uline->y);
1656 get_layout_location (GtkLabel *label,
1665 misc = GTK_MISC (label);
1666 widget = GTK_WIDGET (label);
1668 if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_LTR)
1669 xalign = misc->xalign;
1671 xalign = 1.0 - misc->xalign;
1673 x = floor (widget->allocation.x + (gint)misc->xpad +
1674 xalign * (widget->allocation.width - widget->requisition.width)
1677 if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_LTR)
1678 x = MAX (x, widget->allocation.x + misc->xpad);
1681 widget->allocation.x + widget->allocation.width -
1682 widget->requisition.width - misc->xpad);
1684 y = floor (widget->allocation.y + (gint)misc->ypad
1685 + MAX (((widget->allocation.height - widget->requisition.height) * misc->yalign)
1696 gtk_label_draw_cursor (GtkLabel *label, gint xoffset, gint yoffset)
1698 if (label->select_info == NULL)
1701 if (GTK_WIDGET_DRAWABLE (label))
1703 GtkWidget *widget = GTK_WIDGET (label);
1705 GtkTextDirection keymap_direction;
1706 GtkTextDirection widget_direction;
1707 PangoRectangle strong_pos, weak_pos;
1708 gboolean split_cursor;
1709 PangoRectangle *cursor1 = NULL;
1710 PangoRectangle *cursor2 = NULL;
1711 GdkRectangle cursor_location;
1712 GtkTextDirection dir1 = GTK_TEXT_DIR_NONE;
1713 GtkTextDirection dir2 = GTK_TEXT_DIR_NONE;
1717 (gdk_keymap_get_direction (gdk_keymap_get_for_display (gtk_widget_get_display (widget))) == PANGO_DIRECTION_LTR) ?
1718 GTK_TEXT_DIR_LTR : GTK_TEXT_DIR_RTL;
1720 widget_direction = gtk_widget_get_direction (widget);
1722 gtk_label_ensure_layout (label);
1724 pango_layout_get_cursor_pos (label->layout, label->select_info->selection_end,
1725 &strong_pos, &weak_pos);
1727 g_object_get (gtk_widget_get_settings (widget),
1728 "gtk-split-cursor", &split_cursor,
1731 dir1 = widget_direction;
1735 cursor1 = &strong_pos;
1737 if (strong_pos.x != weak_pos.x ||
1738 strong_pos.y != weak_pos.y)
1740 dir2 = (widget_direction == GTK_TEXT_DIR_LTR) ? GTK_TEXT_DIR_RTL : GTK_TEXT_DIR_LTR;
1741 cursor2 = &weak_pos;
1746 if (keymap_direction == widget_direction)
1747 cursor1 = &strong_pos;
1749 cursor1 = &weak_pos;
1752 cursor_location.x = xoffset + PANGO_PIXELS (cursor1->x);
1753 cursor_location.y = yoffset + PANGO_PIXELS (cursor1->y);
1754 cursor_location.width = 0;
1755 cursor_location.height = PANGO_PIXELS (cursor1->height);
1757 gc = _gtk_get_insertion_cursor_gc (widget, TRUE);
1758 _gtk_draw_insertion_cursor (widget, widget->window, gc,
1759 &cursor_location, dir1,
1760 dir2 != GTK_TEXT_DIR_NONE);
1761 g_object_unref (gc);
1763 if (dir2 != GTK_TEXT_DIR_NONE)
1765 cursor_location.x = xoffset + PANGO_PIXELS (cursor2->x);
1766 cursor_location.y = yoffset + PANGO_PIXELS (cursor2->y);
1767 cursor_location.width = 0;
1768 cursor_location.height = PANGO_PIXELS (cursor2->height);
1770 gc = _gtk_get_insertion_cursor_gc (widget, FALSE);
1771 _gtk_draw_insertion_cursor (widget, widget->window, gc,
1772 &cursor_location, dir2, TRUE);
1773 g_object_unref (gc);
1780 gtk_label_expose (GtkWidget *widget,
1781 GdkEventExpose *event)
1786 g_return_val_if_fail (GTK_IS_LABEL (widget), FALSE);
1787 g_return_val_if_fail (event != NULL, FALSE);
1789 label = GTK_LABEL (widget);
1791 gtk_label_ensure_layout (label);
1793 if (GTK_WIDGET_VISIBLE (widget) && GTK_WIDGET_MAPPED (widget) &&
1794 label->text && (*label->text != '\0'))
1796 get_layout_location (label, &x, &y);
1798 gtk_paint_layout (widget->style,
1800 GTK_WIDGET_STATE (widget),
1808 if (label->select_info &&
1809 (label->select_info->selection_anchor !=
1810 label->select_info->selection_end))
1816 range[0] = label->select_info->selection_anchor;
1817 range[1] = label->select_info->selection_end;
1819 if (range[0] > range[1])
1821 gint tmp = range[0];
1822 range[0] = range[1];
1826 clip = gdk_pango_layout_get_clip_region (label->layout,
1831 /* FIXME should use gtk_paint, but it can't use a clip
1835 gdk_gc_set_clip_region (widget->style->black_gc, clip);
1838 state = GTK_STATE_SELECTED;
1839 if (!GTK_WIDGET_HAS_FOCUS (widget))
1840 state = GTK_STATE_ACTIVE;
1842 gdk_draw_layout_with_colors (widget->window,
1843 widget->style->black_gc,
1846 &widget->style->text[state],
1847 &widget->style->base[state]);
1849 gdk_gc_set_clip_region (widget->style->black_gc, NULL);
1850 gdk_region_destroy (clip);
1852 else if (label->select_info && GTK_WIDGET_HAS_FOCUS (widget))
1853 gtk_label_draw_cursor (label, x, y);
1860 gtk_label_set_uline_text_internal (GtkLabel *label,
1863 guint accel_key = GDK_VoidSymbol;
1868 gchar *dest, *pattern_dest;
1869 gboolean underscore;
1871 g_return_if_fail (GTK_IS_LABEL (label));
1872 g_return_if_fail (str != NULL);
1874 /* Split text into the base text and a separate pattern
1878 new_str = g_new (gchar, strlen (str) + 1);
1879 pattern = g_new (gchar, g_utf8_strlen (str, -1) + 1);
1888 pattern_dest = pattern;
1895 c = g_utf8_get_char (src);
1896 if (c == (gunichar)-1)
1898 g_warning ("Invalid input string");
1903 next_src = g_utf8_next_char (src);
1908 *pattern_dest++ = ' ';
1911 *pattern_dest++ = '_';
1912 if (accel_key == GDK_VoidSymbol)
1913 accel_key = gdk_keyval_to_lower (gdk_unicode_to_keyval (c));
1916 while (src < next_src)
1930 while (src < next_src)
1933 *pattern_dest++ = ' ';
1940 gtk_label_set_text_internal (label, new_str);
1941 gtk_label_set_pattern_internal (label, pattern);
1945 label->mnemonic_keyval = accel_key;
1949 gtk_label_parse_uline (GtkLabel *label,
1955 g_return_val_if_fail (GTK_IS_LABEL (label), GDK_VoidSymbol);
1956 g_return_val_if_fail (str != NULL, GDK_VoidSymbol);
1958 orig_keyval = label->mnemonic_keyval;
1960 g_object_freeze_notify (G_OBJECT (label));
1962 gtk_label_set_label_internal (label, g_strdup (str ? str : ""));
1963 gtk_label_set_use_markup_internal (label, FALSE);
1964 gtk_label_set_use_underline_internal (label, TRUE);
1966 gtk_label_recalculate (label);
1968 keyval = label->mnemonic_keyval;
1969 label->mnemonic_keyval = GDK_VoidSymbol;
1971 gtk_label_setup_mnemonic (label, orig_keyval);
1973 g_object_thaw_notify (G_OBJECT (label));
1979 * gtk_label_set_text_with_mnemonic:
1980 * @label: a #GtkLabel
1983 * Sets the label's text from the string @str.
1984 * If characters in @str are preceded by an underscore, they are underlined
1985 * indicating that they represent a keyboard accelerator called a mnemonic.
1986 * The mnemonic key can be used to activate another widget, chosen automatically,
1987 * or explicitly using gtk_label_set_mnemonic_widget().
1990 gtk_label_set_text_with_mnemonic (GtkLabel *label,
1995 g_return_if_fail (GTK_IS_LABEL (label));
1996 g_return_if_fail (str != NULL);
1998 last_keyval = label->mnemonic_keyval;
2000 g_object_freeze_notify (G_OBJECT (label));
2002 gtk_label_set_label_internal (label, g_strdup (str ? str : ""));
2003 gtk_label_set_use_markup_internal (label, FALSE);
2004 gtk_label_set_use_underline_internal (label, TRUE);
2006 gtk_label_recalculate (label);
2008 gtk_label_setup_mnemonic (label, last_keyval);
2010 g_object_thaw_notify (G_OBJECT (label));
2014 gtk_label_realize (GtkWidget *widget)
2018 label = GTK_LABEL (widget);
2020 (* GTK_WIDGET_CLASS (parent_class)->realize) (widget);
2022 if (label->select_info)
2023 gtk_label_create_window (label);
2027 gtk_label_unrealize (GtkWidget *widget)
2031 label = GTK_LABEL (widget);
2033 if (label->select_info)
2034 gtk_label_destroy_window (label);
2036 (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
2040 gtk_label_map (GtkWidget *widget)
2044 label = GTK_LABEL (widget);
2046 (* GTK_WIDGET_CLASS (parent_class)->map) (widget);
2048 if (label->select_info)
2049 gdk_window_show (label->select_info->window);
2053 gtk_label_unmap (GtkWidget *widget)
2057 label = GTK_LABEL (widget);
2059 if (label->select_info)
2060 gdk_window_hide (label->select_info->window);
2062 (* GTK_WIDGET_CLASS (parent_class)->unmap) (widget);
2066 window_to_layout_coords (GtkLabel *label,
2073 widget = GTK_WIDGET (label);
2075 /* get layout location in widget->window coords */
2076 get_layout_location (label, &lx, &ly);
2080 *x += widget->allocation.x; /* go to widget->window */
2081 *x -= lx; /* go to layout */
2086 *y += widget->allocation.y; /* go to widget->window */
2087 *y -= ly; /* go to layout */
2093 layout_to_window_coords (GtkLabel *label,
2100 widget = GTK_WIDGET (label);
2102 /* get layout location in widget->window coords */
2103 get_layout_location (label, &lx, &ly);
2107 *x += lx; /* go to widget->window */
2108 *x -= widget->allocation.x; /* go to selection window */
2113 *y += ly; /* go to widget->window */
2114 *y -= widget->allocation.y; /* go to selection window */
2120 get_layout_index (GtkLabel *label,
2126 const gchar *cluster;
2127 const gchar *cluster_end;
2131 gtk_label_ensure_layout (label);
2133 window_to_layout_coords (label, &x, &y);
2138 pango_layout_xy_to_index (label->layout,
2143 cluster = label->text + *index;
2144 cluster_end = cluster;
2147 cluster_end = g_utf8_next_char (cluster_end);
2151 *index += (cluster_end - cluster);
2155 gtk_label_select_word (GtkLabel *label)
2159 gint start_index = gtk_label_move_backward_word (label, label->select_info->selection_end);
2160 gint end_index = gtk_label_move_forward_word (label, label->select_info->selection_end);
2162 min = MIN (label->select_info->selection_anchor,
2163 label->select_info->selection_end);
2164 max = MAX (label->select_info->selection_anchor,
2165 label->select_info->selection_end);
2167 min = MIN (min, start_index);
2168 max = MAX (max, end_index);
2170 gtk_label_select_region_index (label, min, max);
2174 gtk_label_button_press (GtkWidget *widget,
2175 GdkEventButton *event)
2180 label = GTK_LABEL (widget);
2182 if (label->select_info == NULL)
2185 if (event->button == 1)
2187 if (!GTK_WIDGET_HAS_FOCUS (widget))
2188 gtk_widget_grab_focus (widget);
2190 if (event->type == GDK_3BUTTON_PRESS)
2192 gtk_label_select_region_index (label, 0, strlen (label->text));
2196 if (event->type == GDK_2BUTTON_PRESS)
2198 gtk_label_select_word (label);
2202 get_layout_index (label, event->x, event->y, &index);
2204 if ((label->select_info->selection_anchor !=
2205 label->select_info->selection_end) &&
2206 (event->state & GDK_SHIFT_MASK))
2210 /* extend (same as motion) */
2211 min = MIN (label->select_info->selection_anchor,
2212 label->select_info->selection_end);
2213 max = MAX (label->select_info->selection_anchor,
2214 label->select_info->selection_end);
2216 min = MIN (min, index);
2217 max = MAX (max, index);
2219 /* ensure the anchor is opposite index */
2227 gtk_label_select_region_index (label, min, max);
2231 if (event->type == GDK_3BUTTON_PRESS)
2232 gtk_label_select_region_index (label, 0, strlen (label->text));
2233 else if (event->type == GDK_2BUTTON_PRESS)
2234 gtk_label_select_word (label);
2236 /* start a replacement */
2237 gtk_label_select_region_index (label, index, index);
2242 else if (event->button == 3 && event->type == GDK_BUTTON_PRESS)
2244 gtk_label_do_popup (label, event);
2253 gtk_label_button_release (GtkWidget *widget,
2254 GdkEventButton *event)
2259 label = GTK_LABEL (widget);
2261 if (label->select_info == NULL)
2264 if (event->button != 1)
2267 /* The goal here is to return TRUE iff we ate the
2268 * button press to start selecting.
2275 gtk_label_motion (GtkWidget *widget,
2276 GdkEventMotion *event)
2282 label = GTK_LABEL (widget);
2284 if (label->select_info == NULL)
2287 if ((event->state & GDK_BUTTON1_MASK) == 0)
2290 gdk_window_get_pointer (label->select_info->window,
2293 get_layout_index (label, x, y, &index);
2295 gtk_label_select_region_index (label,
2296 label->select_info->selection_anchor,
2303 gtk_label_create_window (GtkLabel *label)
2306 GdkWindowAttr attributes;
2307 gint attributes_mask;
2309 g_assert (label->select_info);
2310 g_assert (GTK_WIDGET_REALIZED (label));
2312 if (label->select_info->window)
2315 widget = GTK_WIDGET (label);
2317 attributes.x = widget->allocation.x;
2318 attributes.y = widget->allocation.y;
2319 attributes.width = widget->allocation.width;
2320 attributes.height = widget->allocation.height;
2321 attributes.window_type = GDK_WINDOW_TEMP;
2322 attributes.wclass = GDK_INPUT_ONLY;
2323 attributes.override_redirect = TRUE;
2324 attributes.cursor = gdk_cursor_new_for_display (gtk_widget_get_display (widget),
2326 attributes.event_mask = gtk_widget_get_events (widget) |
2327 GDK_BUTTON_PRESS_MASK |
2328 GDK_BUTTON_RELEASE_MASK |
2329 GDK_BUTTON_MOTION_MASK;
2331 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_NOREDIR | GDK_WA_CURSOR;
2333 label->select_info->window = gdk_window_new (widget->window,
2334 &attributes, attributes_mask);
2335 gdk_window_set_user_data (label->select_info->window, widget);
2337 gdk_cursor_unref (attributes.cursor);
2341 gtk_label_destroy_window (GtkLabel *label)
2343 g_assert (label->select_info);
2345 if (label->select_info->window == NULL)
2348 gdk_window_set_user_data (label->select_info->window, NULL);
2349 gdk_window_destroy (label->select_info->window);
2350 label->select_info->window = NULL;
2354 * gtk_label_set_selectable:
2355 * @label: a #GtkLabel
2356 * @setting: %TRUE to allow selecting text in the label
2358 * Selectable labels allow the user to select text from the label, for
2363 gtk_label_set_selectable (GtkLabel *label,
2366 gboolean old_setting;
2368 g_return_if_fail (GTK_IS_LABEL (label));
2370 setting = setting != FALSE;
2371 old_setting = label->select_info != NULL;
2375 if (label->select_info == NULL)
2377 label->select_info = g_new0 (GtkLabelSelectionInfo, 1);
2379 GTK_WIDGET_SET_FLAGS (label, GTK_CAN_FOCUS);
2381 if (GTK_WIDGET_REALIZED (label))
2382 gtk_label_create_window (label);
2384 if (GTK_WIDGET_MAPPED (label))
2385 gdk_window_show (label->select_info->window);
2390 if (label->select_info)
2392 /* unselect, to give up the selection */
2393 gtk_label_select_region (label, 0, 0);
2395 if (label->select_info->window)
2397 gtk_label_destroy_window (label);
2400 g_free (label->select_info);
2402 label->select_info = NULL;
2404 GTK_WIDGET_UNSET_FLAGS (label, GTK_CAN_FOCUS);
2407 if (setting != old_setting)
2409 g_object_freeze_notify (G_OBJECT (label));
2410 g_object_notify (G_OBJECT (label), "selectable");
2411 g_object_notify (G_OBJECT (label), "cursor_position");
2412 g_object_notify (G_OBJECT (label), "selection_bound");
2413 g_object_thaw_notify (G_OBJECT (label));
2414 gtk_widget_queue_draw (GTK_WIDGET (label));
2419 * gtk_label_get_selectable:
2420 * @label: a #GtkLabel
2422 * Gets the value set by gtk_label_set_selectable().
2424 * Return value: %TRUE if the user can copy text from the label
2427 gtk_label_get_selectable (GtkLabel *label)
2429 g_return_val_if_fail (GTK_IS_LABEL (label), FALSE);
2431 return label->select_info != NULL;
2435 get_text_callback (GtkClipboard *clipboard,
2436 GtkSelectionData *selection_data,
2438 gpointer user_data_or_owner)
2442 label = GTK_LABEL (user_data_or_owner);
2444 if ((label->select_info->selection_anchor !=
2445 label->select_info->selection_end) &&
2451 start = MIN (label->select_info->selection_anchor,
2452 label->select_info->selection_end);
2453 end = MAX (label->select_info->selection_anchor,
2454 label->select_info->selection_end);
2456 len = strlen (label->text);
2464 gtk_selection_data_set_text (selection_data,
2465 label->text + start,
2471 clear_text_callback (GtkClipboard *clipboard,
2472 gpointer user_data_or_owner)
2476 label = GTK_LABEL (user_data_or_owner);
2478 if (label->select_info)
2480 label->select_info->selection_anchor = label->select_info->selection_end;
2482 gtk_widget_queue_draw (GTK_WIDGET (label));
2487 gtk_label_select_region_index (GtkLabel *label,
2491 static const GtkTargetEntry targets[] = {
2494 { "COMPOUND_TEXT", 0, 0 },
2495 { "UTF8_STRING", 0, 0 }
2498 g_return_if_fail (GTK_IS_LABEL (label));
2500 if (label->select_info)
2502 GtkClipboard *clipboard;
2504 if (label->select_info->selection_anchor == anchor_index &&
2505 label->select_info->selection_end == end_index)
2508 label->select_info->selection_anchor = anchor_index;
2509 label->select_info->selection_end = end_index;
2511 clipboard = gtk_widget_get_clipboard (GTK_WIDGET (label),
2512 GDK_SELECTION_PRIMARY);
2514 if (anchor_index != end_index)
2516 gtk_clipboard_set_with_owner (clipboard,
2518 G_N_ELEMENTS (targets),
2520 clear_text_callback,
2525 if (gtk_clipboard_get_owner (clipboard) == G_OBJECT (label))
2526 gtk_clipboard_clear (clipboard);
2529 gtk_widget_queue_draw (GTK_WIDGET (label));
2531 g_object_freeze_notify (G_OBJECT (label));
2532 g_object_notify (G_OBJECT (label), "cursor_position");
2533 g_object_notify (G_OBJECT (label), "selection_bound");
2534 g_object_thaw_notify (G_OBJECT (label));
2539 * gtk_label_select_region:
2540 * @label: a #GtkLabel
2541 * @start_offset: start offset (in characters not bytes)
2542 * @end_offset: end offset (in characters not bytes)
2544 * Selects a range of characters in the label, if the label is selectable.
2545 * See gtk_label_set_selectable(). If the label is not selectable,
2546 * this function has no effect. If @start_offset or
2547 * @end_offset are -1, then the end of the label will be substituted.
2551 gtk_label_select_region (GtkLabel *label,
2555 g_return_if_fail (GTK_IS_LABEL (label));
2557 if (label->text && label->select_info)
2559 if (start_offset < 0)
2560 start_offset = g_utf8_strlen (label->text, -1);
2563 end_offset = g_utf8_strlen (label->text, -1);
2565 gtk_label_select_region_index (label,
2566 g_utf8_offset_to_pointer (label->text, start_offset) - label->text,
2567 g_utf8_offset_to_pointer (label->text, end_offset) - label->text);
2572 * gtk_label_get_selection_bounds:
2573 * @label: a #GtkLabel
2574 * @start: return location for start of selection, as a character offset
2575 * @end: return location for end of selection, as a character offset
2577 * Gets the selected range of characters in the label, returning %TRUE
2578 * if there's a selection.
2580 * Return value: %TRUE if selection is non-empty
2583 gtk_label_get_selection_bounds (GtkLabel *label,
2587 g_return_val_if_fail (GTK_IS_LABEL (label), FALSE);
2589 if (label->select_info == NULL)
2591 /* not a selectable label */
2601 gint start_index, end_index;
2602 gint start_offset, end_offset;
2605 start_index = MIN (label->select_info->selection_anchor,
2606 label->select_info->selection_end);
2607 end_index = MAX (label->select_info->selection_anchor,
2608 label->select_info->selection_end);
2610 len = strlen (label->text);
2612 if (end_index > len)
2615 if (start_index > len)
2618 start_offset = g_utf8_strlen (label->text, start_index);
2619 end_offset = g_utf8_strlen (label->text, end_index);
2621 if (start_offset > end_offset)
2623 gint tmp = start_offset;
2624 start_offset = end_offset;
2629 *start = start_offset;
2634 return start_offset != end_offset;
2640 * gtk_label_get_layout:
2641 * @label: a #GtkLabel
2643 * Gets the #PangoLayout used to display the label.
2644 * The layout is useful to e.g. convert text positions to
2645 * pixel positions, in combination with gtk_label_get_layout_offsets().
2646 * The returned layout is owned by the label so need not be
2647 * freed by the caller.
2649 * Return value: the #PangoLayout for this label
2652 gtk_label_get_layout (GtkLabel *label)
2654 g_return_val_if_fail (GTK_IS_LABEL (label), NULL);
2656 gtk_label_ensure_layout (label);
2658 return label->layout;
2662 * gtk_label_get_layout_offsets:
2663 * @label: a #GtkLabel
2664 * @x: location to store X offset of layout, or %NULL
2665 * @y: location to store Y offset of layout, or %NULL
2667 * Obtains the coordinates where the label will draw the #PangoLayout
2668 * representing the text in the label; useful to convert mouse events
2669 * into coordinates inside the #PangoLayout, e.g. to take some action
2670 * if some part of the label is clicked. Of course you will need to
2671 * create a #GtkEventBox to receive the events, and pack the label
2672 * inside it, since labels are a #GTK_NO_WINDOW widget. Remember
2673 * when using the #PangoLayout functions you need to convert to
2674 * and from pixels using PANGO_PIXELS() or #PANGO_SCALE.
2678 gtk_label_get_layout_offsets (GtkLabel *label,
2682 g_return_if_fail (GTK_IS_LABEL (label));
2684 get_layout_location (label, x, y);
2688 * gtk_label_set_use_markup:
2689 * @label: a #GtkLabel
2690 * @setting: %TRUE if the label's text should be parsed for markup.
2692 * Sets whether the text of the label contains markup in <link
2693 * linkend="PangoMarkupFormat">Pango's text markup
2694 * language</link>. See gtk_label_set_markup().
2697 gtk_label_set_use_markup (GtkLabel *label,
2700 g_return_if_fail (GTK_IS_LABEL (label));
2702 gtk_label_set_use_markup_internal (label, setting);
2703 gtk_label_recalculate (label);
2707 * gtk_label_get_use_markup:
2708 * @label: a #GtkLabel
2710 * Returns whether the label's text is interpreted as marked up with
2711 * the <link linkend="PangoMarkupFormat">Pango text markup
2712 * language</link>. See gtk_label_set_use_markup ().
2714 * Return value: %TRUE if the label's text will be parsed for markup.
2717 gtk_label_get_use_markup (GtkLabel *label)
2719 g_return_val_if_fail (GTK_IS_LABEL (label), FALSE);
2721 return label->use_markup;
2725 * gtk_label_set_use_underline:
2726 * @label: a #GtkLabel
2727 * @setting: %TRUE if underlines in the text indicate mnemonics
2729 * If true, an underline in the text indicates the next character should be
2730 * used for the mnemonic accelerator key.
2733 gtk_label_set_use_underline (GtkLabel *label,
2736 g_return_if_fail (GTK_IS_LABEL (label));
2738 gtk_label_set_use_underline_internal (label, setting);
2739 gtk_label_recalculate (label);
2740 if (label->use_underline)
2741 gtk_label_setup_mnemonic (label, label->mnemonic_keyval);
2745 * gtk_label_get_use_underline:
2746 * @label: a #GtkLabel
2748 * Returns whether an embedded underline in the label indicates a
2749 * mnemonic. See gtk_label_set_use_underline ().
2751 * Return value: %TRUE whether an embedded underline in the label indicates
2752 * the mnemonic accelerator keys.
2755 gtk_label_get_use_underline (GtkLabel *label)
2757 g_return_val_if_fail (GTK_IS_LABEL (label), FALSE);
2759 return label->use_underline;
2763 gtk_label_focus (GtkWidget *widget,
2764 GtkDirectionType direction)
2766 /* We never want to be in the tab chain */
2770 /* Compute the X position for an offset that corresponds to the "more important
2771 * cursor position for that offset. We use this when trying to guess to which
2772 * end of the selection we should go to when the user hits the left or
2776 get_better_cursor (GtkLabel *label,
2781 GdkKeymap *keymap = gdk_keymap_get_for_display (gtk_widget_get_display (GTK_WIDGET (label)));
2782 GtkTextDirection keymap_direction =
2783 (gdk_keymap_get_direction (keymap) == PANGO_DIRECTION_LTR) ?
2784 GTK_TEXT_DIR_LTR : GTK_TEXT_DIR_RTL;
2785 GtkTextDirection widget_direction = gtk_widget_get_direction (GTK_WIDGET (label));
2786 gboolean split_cursor;
2787 PangoRectangle strong_pos, weak_pos;
2789 g_object_get (gtk_widget_get_settings (GTK_WIDGET (label)),
2790 "gtk-split-cursor", &split_cursor,
2793 gtk_label_ensure_layout (label);
2795 pango_layout_get_cursor_pos (label->layout, index,
2796 &strong_pos, &weak_pos);
2800 *x = strong_pos.x / PANGO_SCALE;
2801 *y = strong_pos.y / PANGO_SCALE;
2805 if (keymap_direction == widget_direction)
2807 *x = strong_pos.x / PANGO_SCALE;
2808 *y = strong_pos.y / PANGO_SCALE;
2812 *x = weak_pos.x / PANGO_SCALE;
2813 *y = weak_pos.y / PANGO_SCALE;
2820 gtk_label_move_logically (GtkLabel *label,
2824 gint offset = g_utf8_pointer_to_offset (label->text,
2825 label->text + start);
2829 PangoLogAttr *log_attrs;
2833 gtk_label_ensure_layout (label);
2835 length = g_utf8_strlen (label->text, -1);
2837 pango_layout_get_log_attrs (label->layout, &log_attrs, &n_attrs);
2839 while (count > 0 && offset < length)
2843 while (offset < length && !log_attrs[offset].is_cursor_position);
2847 while (count < 0 && offset > 0)
2851 while (offset > 0 && !log_attrs[offset].is_cursor_position);
2859 return g_utf8_offset_to_pointer (label->text, offset) - label->text;
2863 gtk_label_move_visually (GtkLabel *label,
2873 int new_index, new_trailing;
2874 gboolean split_cursor;
2877 gtk_label_ensure_layout (label);
2879 g_object_get (gtk_widget_get_settings (GTK_WIDGET (label)),
2880 "gtk-split-cursor", &split_cursor,
2887 GdkKeymap *keymap = gdk_keymap_get_for_display (gtk_widget_get_display (GTK_WIDGET (label)));
2888 GtkTextDirection keymap_direction =
2889 (gdk_keymap_get_direction (keymap) == PANGO_DIRECTION_LTR) ?
2890 GTK_TEXT_DIR_LTR : GTK_TEXT_DIR_RTL;
2892 strong = keymap_direction == gtk_widget_get_direction (GTK_WIDGET (label));
2897 pango_layout_move_cursor_visually (label->layout, strong, index, 0, 1, &new_index, &new_trailing);
2902 pango_layout_move_cursor_visually (label->layout, strong, index, 0, -1, &new_index, &new_trailing);
2906 if (new_index < 0 || new_index == G_MAXINT)
2911 while (new_trailing--)
2912 index = g_utf8_next_char (label->text + new_index) - label->text;
2919 gtk_label_move_forward_word (GtkLabel *label,
2922 gint new_pos = g_utf8_pointer_to_offset (label->text,
2923 label->text + start);
2926 length = g_utf8_strlen (label->text, -1);
2927 if (new_pos < length)
2929 PangoLogAttr *log_attrs;
2932 gtk_label_ensure_layout (label);
2934 pango_layout_get_log_attrs (label->layout, &log_attrs, &n_attrs);
2936 /* Find the next word end */
2938 while (new_pos < n_attrs && !log_attrs[new_pos].is_word_end)
2944 return g_utf8_offset_to_pointer (label->text, new_pos) - label->text;
2949 gtk_label_move_backward_word (GtkLabel *label,
2952 gint new_pos = g_utf8_pointer_to_offset (label->text,
2953 label->text + start);
2956 length = g_utf8_strlen (label->text, -1);
2960 PangoLogAttr *log_attrs;
2963 gtk_label_ensure_layout (label);
2965 pango_layout_get_log_attrs (label->layout, &log_attrs, &n_attrs);
2969 /* Find the previous word beginning */
2970 while (new_pos > 0 && !log_attrs[new_pos].is_word_start)
2976 return g_utf8_offset_to_pointer (label->text, new_pos) - label->text;
2980 gtk_label_move_cursor (GtkLabel *label,
2981 GtkMovementStep step,
2983 gboolean extend_selection)
2987 if (label->select_info == NULL)
2990 new_pos = label->select_info->selection_end;
2992 if (label->select_info->selection_end != label->select_info->selection_anchor &&
2995 /* If we have a current selection and aren't extending it, move to the
2996 * start/or end of the selection as appropriate
3000 case GTK_MOVEMENT_VISUAL_POSITIONS:
3003 gint anchor_x, anchor_y;
3004 gboolean end_is_left;
3006 get_better_cursor (label, label->select_info->selection_end, &end_x, &end_y);
3007 get_better_cursor (label, label->select_info->selection_anchor, &anchor_x, &anchor_y);
3009 end_is_left = (end_y < anchor_y) || (end_y == anchor_y && end_x < anchor_x);
3012 new_pos = end_is_left ? label->select_info->selection_end : label->select_info->selection_anchor;
3014 new_pos = !end_is_left ? label->select_info->selection_end : label->select_info->selection_anchor;
3018 case GTK_MOVEMENT_LOGICAL_POSITIONS:
3019 case GTK_MOVEMENT_WORDS:
3021 new_pos = MIN (label->select_info->selection_end, label->select_info->selection_anchor);
3023 new_pos = MAX (label->select_info->selection_end, label->select_info->selection_anchor);
3025 case GTK_MOVEMENT_DISPLAY_LINE_ENDS:
3026 case GTK_MOVEMENT_PARAGRAPH_ENDS:
3027 case GTK_MOVEMENT_BUFFER_ENDS:
3028 /* FIXME: Can do better here */
3029 new_pos = count < 0 ? 0 : strlen (label->text);
3031 case GTK_MOVEMENT_DISPLAY_LINES:
3032 case GTK_MOVEMENT_PARAGRAPHS:
3033 case GTK_MOVEMENT_PAGES:
3041 case GTK_MOVEMENT_LOGICAL_POSITIONS:
3042 new_pos = gtk_label_move_logically (label, new_pos, count);
3044 case GTK_MOVEMENT_VISUAL_POSITIONS:
3045 new_pos = gtk_label_move_visually (label, new_pos, count);
3047 case GTK_MOVEMENT_WORDS:
3050 new_pos = gtk_label_move_forward_word (label, new_pos);
3055 new_pos = gtk_label_move_backward_word (label, new_pos);
3059 case GTK_MOVEMENT_DISPLAY_LINE_ENDS:
3060 case GTK_MOVEMENT_PARAGRAPH_ENDS:
3061 case GTK_MOVEMENT_BUFFER_ENDS:
3062 /* FIXME: Can do better here */
3063 new_pos = count < 0 ? 0 : strlen (label->text);
3065 case GTK_MOVEMENT_DISPLAY_LINES:
3066 case GTK_MOVEMENT_PARAGRAPHS:
3067 case GTK_MOVEMENT_PAGES:
3072 if (extend_selection)
3073 gtk_label_select_region_index (label,
3074 label->select_info->selection_anchor,
3077 gtk_label_select_region_index (label, new_pos, new_pos);
3081 gtk_label_copy_clipboard (GtkLabel *label)
3083 if (label->text && label->select_info)
3088 start = MIN (label->select_info->selection_anchor,
3089 label->select_info->selection_end);
3090 end = MAX (label->select_info->selection_anchor,
3091 label->select_info->selection_end);
3093 len = strlen (label->text);
3102 gtk_clipboard_set_text (gtk_widget_get_clipboard (GTK_WIDGET (label),
3103 GDK_SELECTION_CLIPBOARD),
3104 label->text + start, end - start);
3109 gtk_label_select_all (GtkLabel *label)
3111 gtk_label_select_region_index (label, 0, strlen (label->text));
3114 /* Quick hack of a popup menu
3117 activate_cb (GtkWidget *menuitem,
3120 const gchar *signal = g_object_get_data (G_OBJECT (menuitem), "gtk-signal");
3121 g_signal_emit_by_name (label, signal);
3125 append_action_signal (GtkLabel *label,
3127 const gchar *stock_id,
3128 const gchar *signal,
3131 GtkWidget *menuitem = gtk_image_menu_item_new_from_stock (stock_id, NULL);
3133 g_object_set_data (G_OBJECT (menuitem), "gtk-signal", (char *)signal);
3134 g_signal_connect (menuitem, "activate",
3135 G_CALLBACK (activate_cb), label);
3137 gtk_widget_set_sensitive (menuitem, sensitive);
3139 gtk_widget_show (menuitem);
3140 gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
3144 popup_menu_detach (GtkWidget *attach_widget,
3148 label = GTK_LABEL (attach_widget);
3150 if (label->select_info)
3151 label->select_info->popup_menu = NULL;
3155 popup_position_func (GtkMenu *menu,
3166 label = GTK_LABEL (user_data);
3167 widget = GTK_WIDGET (label);
3169 if (label->select_info == NULL)
3172 g_return_if_fail (GTK_WIDGET_REALIZED (label));
3174 screen = gtk_widget_get_screen (widget);
3175 gdk_window_get_origin (widget->window, x, y);
3177 gtk_widget_size_request (label->select_info->popup_menu, &req);
3179 *x += widget->allocation.width / 2;
3180 *y += widget->allocation.height;
3182 *x = CLAMP (*x, 0, MAX (0, gdk_screen_get_width (screen) - req.width));
3183 *y = CLAMP (*y, 0, MAX (0, gdk_screen_get_height (screen) - req.height));
3188 gtk_label_do_popup (GtkLabel *label,
3189 GdkEventButton *event)
3191 GtkWidget *menuitem;
3192 gboolean have_selection;
3194 if (label->select_info == NULL)
3197 if (label->select_info->popup_menu)
3198 gtk_widget_destroy (label->select_info->popup_menu);
3200 label->select_info->popup_menu = gtk_menu_new ();
3202 gtk_menu_attach_to_widget (GTK_MENU (label->select_info->popup_menu),
3207 label->select_info->selection_anchor != label->select_info->selection_end;
3210 append_action_signal (label, label->select_info->popup_menu, GTK_STOCK_CUT, "cut_clipboard",
3212 append_action_signal (label, label->select_info->popup_menu, GTK_STOCK_COPY, "copy_clipboard",
3214 append_action_signal (label, label->select_info->popup_menu, GTK_STOCK_PASTE, "paste_clipboard",
3217 menuitem = gtk_menu_item_new_with_label (_("Select All"));
3218 g_signal_connect_swapped (menuitem, "activate",
3219 G_CALLBACK (gtk_label_select_all), label);
3220 gtk_widget_show (menuitem);
3221 gtk_menu_shell_append (GTK_MENU_SHELL (label->select_info->popup_menu), menuitem);
3223 menuitem = gtk_separator_menu_item_new ();
3224 gtk_widget_show (menuitem);
3225 gtk_menu_shell_append (GTK_MENU_SHELL (label->select_info->popup_menu), menuitem);
3227 menuitem = gtk_menu_item_new_with_label (_("Input Methods"));
3228 gtk_widget_show (menuitem);
3229 gtk_menu_item_set_submenu (GTK_MENU_ITEM (menuitem), gtk_menu_new ());
3230 gtk_widget_set_sensitive (menuitem, FALSE);
3231 gtk_menu_shell_append (GTK_MENU_SHELL (label->select_info->popup_menu), menuitem);
3233 g_signal_emit (label,
3234 signals[POPULATE_POPUP],
3236 label->select_info->popup_menu);
3239 gtk_menu_popup (GTK_MENU (label->select_info->popup_menu), NULL, NULL,
3241 event->button, event->time);
3243 gtk_menu_popup (GTK_MENU (label->select_info->popup_menu), NULL, NULL,
3244 popup_position_func, label,
3245 0, gtk_get_current_event_time ());